/*
  Base + komponen, dibangun di atas token di tokens.css. Setiap aturan di sini merujuk ke
  bagian DESIGN.md yang menurunkannya lewat komentar section.
*/

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

html {
  color-scheme: light;
}

/* Dua jalan masuk mode gelap harus sama (DESIGN.md 9): pilihan eksplisit dan sistem. */
:root[data-tema="gelap"] {
  color-scheme: dark;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-tema="terang"]) {
    color-scheme: dark;
  }
}

/* Area akun (/masuk, /dashboard/*, DESIGN.md 9): selalu gelap. Token-nya di tokens.css;
   di sini hanya skema warna kontrol bawaan browser (scrollbar, autofill, date picker). */
:root[data-area="akun"] {
  color-scheme: dark;
}

/* Latar akun dan footer navy nyaris sama (1,00:1), jadi batas footer ditandai garis. */
:root[data-area="akun"] .footer {
  border-top: 1px solid var(--akun-garis);
}

/* Halaman gelap penuh (hanya /ai, DESIGN.md 9): <main> membawa token gelap sendiri
   (tokens.css), jadi latarnya harus dicat ulang di sini, bukan diwarisi dari body. */
[data-tema-lokal="gelap"] {
  color-scheme: dark;
  background: var(--kertas);
  color: var(--tinta);
}

/* Ikon garis Lucide (DESIGN.md 8.8). Ukuran mengikuti teks di sebelahnya. */
.ikon {
  width: 1.25em;
  height: 1.25em;
  flex-shrink: 0;
}

body {
  margin: 0;
  background: var(--kertas);
  color: var(--tinta);
  font-family: var(--font-sans);
  font-size: var(--ukuran-body);
  font-weight: var(--berat-body);
  line-height: var(--tinggi-baris-body);
  scroll-padding-bottom: calc(56px + 16px);
}

/* Kontrol form tidak mewarisi font dari body secara bawaan browser (button jatuh ke Arial
   13,33px). Diwariskan di sini supaya setiap tombol dan field memakai IBM Plex Sans situs;
   ukuran dan berat yang diatur kelas komponen (.tombol, .field input, dst.) tetap menang. */
button,
input,
select,
textarea {
  font: inherit;
}

img {
  max-width: 100%;
  display: block;
}

h1,
h2,
h3 {
  margin: 0;
  font-weight: var(--berat-heading);
  line-height: var(--tinggi-baris-heading);
  text-wrap: balance;
}

h1 {
  font-size: var(--ukuran-h1);
}

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

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

p {
  margin: 0;
}

a {
  color: var(--laut);
}

.lead {
  font-size: var(--ukuran-lead);
  color: var(--tinta-2);
  max-width: var(--lebar-baca-maks);
}

.label {
  font-size: var(--ukuran-label);
  font-weight: var(--berat-label);
  color: var(--tinta-2);
}

.mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

.mt-2 {
  margin-top: var(--ruang-2);
}

.mt-3 {
  margin-top: var(--ruang-3);
}

.mt-4 {
  margin-top: var(--ruang-4);
}

.mt-5 {
  margin-top: var(--ruang-5);
}

.mt-6 {
  margin-top: var(--ruang-6);
}

.mt-7 {
  margin-top: var(--ruang-7);
}

.tanpa-garis-bawah {
  border-bottom: none;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

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

@media (prefers-reduced-motion: no-preference) {
  a,
  button,
  .kartu-tombol,
  input,
  select,
  textarea {
    transition: background-color var(--durasi-mikro) var(--easing-keluar),
      border-color var(--durasi-mikro) var(--easing-keluar),
      color var(--durasi-mikro) var(--easing-keluar),
      opacity var(--durasi-mikro) var(--easing-keluar),
      box-shadow var(--durasi-mikro) var(--easing-keluar);
  }

  .kartu-produk {
    transition: border-color var(--durasi-mikro) var(--easing-keluar),
      box-shadow var(--durasi-mikro) var(--easing-keluar);
  }
}

/* --- Struktur halaman, DESIGN.md bagian 4 dan 5 --- */

.container {
  max-width: var(--lebar-konten-maks);
  margin-inline: auto;
  padding-inline: var(--halaman-px);
}

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

/* Jangkar dropdown "Produk" (#perangkat, #produk-digital, ...) tidak tertutup header lengket,
   dan mendarat di judul section, bukan di padding atasnya: padding section dikurangi dari
   margin, disisakan 24px di bawah header (tahap 6a A3, supaya katalog langsung terlihat). */
.section[id] {
  scroll-margin-top: calc(var(--tinggi-header) - var(--section-py) + var(--ruang-5));
}

/* Section yang difokus ui.js setelah gulir halus (data-gulir-halus) hanya titik awal Tab,
   bukan kontrol: tanpa cincin fokus selebar section. Kontrol di dalamnya tetap bercincin. */
.section[tabindex="-1"]:focus {
  outline: none;
}

.section-head {
  text-align: left;
  max-width: var(--lebar-baca-maks);
  margin-bottom: var(--ruang-6);
}

.section-head p {
  margin-top: var(--ruang-2);
}

/* Subtitle section jasa (tahap 6a B2.8): kalimatnya lebih panjang dari 68ch (--lebar-baca-maks
   di .section-head), jadi "pekerjaan." jatuh sendirian di baris kedua di layar lebar. Lebarkan
   HANYA subtitle ini lewat #layanan (section lain tetap 68ch); di sempit tetap boleh dua baris
   tapi text-wrap mencegah kata yatim juga di sana. */
#layanan .section-head p {
  text-wrap: balance;
  text-wrap: pretty;
}

@media (min-width: 1024px) {
  /* max-width harus lepas dari .section-head sendiri, bukan cuma <p>: .section-head
     membatasi lebar wadahnya ke 68ch juga, jadi <p> di dalamnya tidak pernah bisa lebih
     lebar dari itu walau max-width miliknya sendiri sudah "none". */
  #layanan .section-head {
    max-width: none;
  }
}

/* Judul katalog Beranda + kolom cari (tahap 6a A3). Judul tetap dibatasi lebar baca; kolom
   cari duduk di kanan bawahnya di layar lebar dan turun ke bawah judul di layar sempit. */
.section-head-cari {
  max-width: none;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--ruang-4) var(--ruang-5);
}

.section-head-cari {
  margin-bottom: var(--ruang-5);
}

.section-head-cari > div {
  max-width: var(--lebar-baca-maks);
}

/* Kolom cari minimalis: satu bingkai 4px (radius input, DESIGN.md 6) berisi input dan tombol
   ikon 44px. Batas --garis-kuat supaya lolos 3:1 sebagai kontrol. */
.form-cari {
  display: flex;
  align-items: stretch;
  width: min(100%, 20rem);
  background: var(--permukaan);
  border: 1px solid var(--garis-kuat);
  border-radius: var(--radius-badge);
}

/* Fokus di input: cincin pindah ke bingkai, karena input tanpa batas sendiri. Tombol ikon
   memakai cincinnya sendiri (ke dalam), supaya jelas mana yang sedang difokus. Tanpa :has
   (peramban lama), input tetap memakai cincin bawaan :focus-visible. */
@supports selector(:has(a)) {
  .form-cari:has(input:focus-visible) {
    outline: 2px solid var(--laut);
    outline-offset: 2px;
  }

  .form-cari input:focus-visible {
    outline: none;
  }
}

.form-cari-tombol:focus-visible {
  outline-offset: -4px;
}

.form-cari input {
  flex: 1;
  min-width: 0;
  min-height: 44px;
  padding: 0 var(--ruang-3);
  border: 0;
  background: transparent;
  color: var(--tinta);
  font: inherit;
  font-size: 0.9375rem;
}

.form-cari input::placeholder {
  color: var(--tinta-2);
}

.form-cari-tombol {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  min-height: 44px;
  padding: 0;
  border: 0;
  border-left: 1px solid var(--garis);
  background: transparent;
  color: var(--tinta);
  cursor: pointer;
}

.form-cari-tombol:hover {
  color: var(--laut);
}

.form-cari-tombol .ikon {
  width: 20px;
  height: 20px;
}

.hasil-cari-ringkas {
  margin-bottom: var(--ruang-4);
}

/* Blok split dua kolom, satu per halaman panjang (DESIGN.md 5, patahan #2). Rata atas
   (DESIGN.md 5 "Perataan"): teks pendek di samping kartu tinggi tidak lagi melayang. */
.split {
  display: grid;
  gap: var(--ruang-6);
  align-items: start;
}

@media (min-width: 1024px) {
  .split {
    grid-template-columns: 1fr 1fr;
    gap: var(--ruang-9);
  }
}

/* --- Navbar --- */

/* Header 64px TETAP di semua halaman (tahap 6h, DESIGN.md 8.7): tidak menipis, tidak meloncat.
   Satu-satunya perubahan saat digulir: garis bawah muncul (data-tergulir, dipasang ui.js lewat
   IntersectionObserver pada penanda 8px di puncak dokumen). Header dashboard memakai kelas
   .navbar yang sama dan tidak ikut aturan .navbar-publik di bawah. */
.navbar {
  position: sticky;
  top: env(safe-area-inset-top, 0px);
  z-index: 40;
  height: var(--tinggi-header);
}

.navbar-latar {
  height: 100%;
  background: var(--permukaan);
  border-bottom: 1px solid var(--garis);
  box-shadow: var(--naik);
}

.navbar-penanda {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: var(--ruang-2);
  pointer-events: none;
}

.navbar-row {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ruang-4);
  min-height: var(--tinggi-header);
}

/* Latar header publik: sedikit transparan + blur (satu-satunya elemen kaca di halaman, R-10)
   hanya bila peramban mendukung; tanpa dukungan latarnya padat. Garis bawah transparan di
   puncak halaman, muncul saat digulir. */
.navbar-publik .navbar-latar {
  box-shadow: none;
  border-bottom-color: transparent;
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .navbar-publik .navbar-latar {
    background: color-mix(in srgb, var(--permukaan) 88%, transparent);
    -webkit-backdrop-filter: blur(12px) saturate(1.15);
    backdrop-filter: blur(12px) saturate(1.15);
  }
}

.navbar-publik[data-tergulir] .navbar-latar {
  border-bottom-color: var(--garis);
}

@media (prefers-reduced-motion: no-preference) {
  .navbar-publik .navbar-latar {
    transition: border-color var(--durasi-header) var(--easing-keluar);
  }
}

/* Logo (DESIGN.md 1): turunan Logo-NST (scripts/brand-assets.js) + SITE_NAME. */
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: var(--ruang-2);
  min-height: 44px;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 1.0625rem;
  color: var(--tinta);
  text-decoration: none;
  white-space: nowrap;
}

/* Tinggi 40px = header ringkas 52px dikurangi --ruang-3 (token lama dipertahankan sebagai
   ukuran logo). Logo resmi (tahap 6a B6) rasionya 11:7 (lebar > tinggi); lebar dihitung dari
   rasio itu supaya artworknya tidak pernah diregangkan atau dipotong. */
.logo-brand {
  height: calc(var(--tinggi-header-ringkas) - var(--ruang-3));
  width: calc((var(--tinggi-header-ringkas) - var(--ruang-3)) * 11 / 7);
  flex-shrink: 0;
}

/* Susunan header publik. Mobile/tablet: flex, logo kiri, menu tengah mengisi sisa, kontrol
   kanan. >= 1024px: tiga kolom 1fr auto 1fr supaya menu tengah tepat di tengah halaman. */
.navbar-publik .navbar-row {
  gap: var(--ruang-3);
}

.nav-utama {
  margin-inline: auto;
}

@media (min-width: 1024px) {
  .navbar-publik .navbar-row {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: var(--ruang-4);
  }

  .nav-utama {
    margin-inline: 0;
  }

  .navbar-publik .navbar-kontrol {
    justify-self: end;
  }
}

.nav-links {
  display: flex;
  align-items: center;
  gap: var(--ruang-1);
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav-item {
  position: relative;
  display: flex;
}

/* Pill item aktif: kotak bersudut dengan batas tipis dan garis aksen kecil di tepi bawah.
   Elemen dekoratif TERPISAH dari tautan (aria-hidden); status aktif dibaca dari aria-current
   di tautannya. view-transition-name membuatnya meluncur dari item lama ke item baru saat
   pindah halaman (lihat blok view transition di bawah). */
.nav-pill {
  position: absolute;
  inset: 2px 0;
  border: 1px solid color-mix(in srgb, var(--laut) 38%, transparent);
  border-radius: var(--radius-kartu);
  background: color-mix(in srgb, var(--laut) 8%, transparent);
  transform-origin: left center;
  pointer-events: none;
  view-transition-name: nav-pill;
}

.nav-pill::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -1px;
  width: 16px;
  height: 2px;
  margin-left: -8px;
  border-radius: 2px;
  background: var(--laut);
}

.nav-links > .nav-item > a,
.nav-dropdown-pemicu {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--ruang-1);
  min-height: 44px;
  padding: 0 14px;
  border-radius: var(--radius-kartu);
  color: var(--tinta-2);
  text-decoration: none;
  font-family: var(--font-sans);
  font-size: 0.9375rem;
  font-weight: 500;
}

.nav-links > .nav-item > a:hover,
.nav-dropdown-pemicu:hover {
  color: var(--tinta);
  background: color-mix(in srgb, var(--tinta) 6%, transparent);
}

.nav-links a[aria-current="page"],
.nav-dropdown-pemicu[aria-current] {
  color: var(--laut);
  background: transparent;
}

/* Dropdown "Produk", DESIGN.md 8.7. <button aria-expanded>, dibuka klik/tap/Enter/Spasi. */
.nav-dropdown-pemicu {
  background: none;
  border: 0;
  cursor: pointer;
}

.ikon-chevron {
  width: 1em;
  height: 1em;
}

@media (prefers-reduced-motion: no-preference) {
  .ikon-chevron {
    transition: transform var(--durasi-menu) var(--easing-keluar);
  }
}

.nav-dropdown-pemicu[aria-expanded="true"] .ikon-chevron {
  transform: rotate(180deg);
}

.nav-dropdown {
  list-style: none;
  margin: 0;
  padding: var(--ruang-2);
  position: absolute;
  top: calc(100% + var(--ruang-2));
  left: 0;
  min-width: 15rem;
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-kartu);
  box-shadow: var(--melayang);
  z-index: 45;
}

.nav-dropdown[hidden] {
  display: none;
}

.nav-dropdown a {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--ruang-3);
  border-radius: var(--radius-badge);
  color: var(--tinta);
  text-decoration: none;
  font-size: 0.9375rem;
  /* Label terpanjang ("Jasa AI, n8n & Website") wajib sebaris (tahap 6a B2.5); panel yang
     absolute ikut melebar mengikuti isinya. */
  white-space: nowrap;
}

.nav-dropdown a:hover {
  background: var(--kertas);
  color: var(--laut);
}

/* Dropdown dan panel mobile: fade + geser 4px, 150ms. [hidden] memberi display:none; transisi
   display (allow-discrete) menahannya sampai animasi keluar selesai, dan @starting-style
   memberi keadaan awal saat muncul. Peramban tanpa dukungan: muncul/hilang langsung. */
@media (prefers-reduced-motion: no-preference) {
  .nav-dropdown,
  .nav-links {
    transition:
      opacity 150ms var(--easing-keluar),
      transform 150ms var(--easing-keluar),
      display 150ms allow-discrete;
  }

  .nav-dropdown[hidden] {
    opacity: 0;
    transform: translateY(-4px);
  }

  @starting-style {
    .nav-dropdown {
      opacity: 0;
      transform: translateY(-4px);
    }
  }
}

.navbar-menu {
  display: flex;
  align-items: center;
  gap: var(--ruang-5);
}

.navbar-kontrol {
  display: flex;
  align-items: center;
  gap: var(--ruang-2);
}

/* Keranjang di header, DESIGN.md 8.7: item ikon dengan kotak sentuh 44x44, tanpa batas.
   Hover dan halaman aktif = warna --laut + latar --kertas, sama seperti item dropdown. Dipakai
   juga oleh header dashboard (Cari). */
.nav-ikon {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-kartu);
  color: var(--tinta);
  text-decoration: none;
}

.nav-ikon .ikon {
  width: 24px;
  height: 24px;
}

.nav-ikon:hover,
.nav-ikon[aria-current="page"] {
  background: var(--kertas);
  color: var(--laut);
}

/* Keranjang ikon saja. Badge menempel di pojok kanan atas glif, hanya saat jumlah > 0. */
.nav-keranjang-hitung {
  position: absolute;
  top: 2px;
  right: 0;
  min-width: 1.25rem;
  padding: 0 var(--ruang-1);
  border-radius: var(--radius-badge);
  background: var(--laut);
  color: var(--teks-di-laut);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.25rem;
  text-align: center;
}

/* Tooltip ikon header ("Keranjang (N item)", "Cari materi"): tampil saat hover dan fokus
   keyboard, disembunyikan Escape (ui.js memasang data-tooltip-tutup). Warna terbalik (--tinta
   di atas, --permukaan teks) supaya terbaca di kedua mode tanpa token baru. Menempel ke kanan
   ikon supaya tidak keluar layar di 390px. */
.nav-tooltip {
  position: absolute;
  top: calc(100% + var(--ruang-1));
  right: 0;
  z-index: 46;
  display: none;
  padding: var(--ruang-1) var(--ruang-2);
  border-radius: var(--radius-badge);
  background: var(--tinta);
  color: var(--permukaan);
  font-size: var(--ukuran-label);
  font-weight: var(--berat-label);
  line-height: 1.4;
  white-space: nowrap;
  box-shadow: var(--melayang);
  pointer-events: none;
}

.nav-ikon:hover .nav-tooltip,
.nav-ikon:focus-visible .nav-tooltip {
  display: block;
}

.nav-ikon[data-tooltip-tutup] .nav-tooltip {
  display: none;
}

/* Tombol keranjang butuh JS (localStorage). Tanpa JS disembunyikan, diganti <noscript>. */
html:not(.js) [data-tambah-keranjang] {
  display: none;
}

.nav-keranjang-hitung[hidden] {
  display: none;
}

/* Angka keranjang baru bertambah (cart.js memasang data-naik): membesar sekali lalu kembali,
   250 ms, supaya mata menangkap bahwa angkanya berubah. Satu kali per penambahan, tidak
   berulang. Mati di prefers-reduced-motion; angka tetap berubah. */
@media (prefers-reduced-motion: no-preference) {
  .nav-keranjang-hitung[data-naik] {
    animation: hitung-naik 250ms var(--easing-keluar);
  }
}

@keyframes hitung-naik {
  40% {
    transform: scale(1.3);
  }
}

/* Toggle tema (tahap 6f, DESIGN.md 8.7): tombol ikon 44x44, glif 24px, bentuk dan hover sama
   dengan .nav-ikon. Dua SVG ditumpuk di tengah; ikon yang tampil dipilih CSS murni dari tema
   yang berlaku, jadi benar di cat pertama tanpa menunggu JS dan tanpa kedip. Terang = bulan
   sabit (aksi: ke gelap), gelap = matahari (aksi: ke terang). Cincin fokus memakai outline
   bawaan global (:focus-visible), tidak dimatikan. */
.tema-toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: var(--radius-kartu);
  color: var(--tinta);
  cursor: pointer;
}

.tema-toggle:hover {
  background: var(--kertas);
  color: var(--laut);
}

.tema-toggle .tema-ikon,
.tema-baris-ikon .tema-ikon {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 24px;
  height: 24px;
}

/* Keadaan awal = tema terang: bulan terlihat, matahari tersembunyi dan terputar. */
.tema-ikon-matahari {
  opacity: 0;
  transform: rotate(-90deg) scale(0.6);
}

.tema-ikon-bulan {
  opacity: 1;
  transform: none;
}

/* Tema gelap: dari pilihan eksplisit, atau dari sistem selama pengunjung belum memilih
   (selektor sama dengan tokens.css supaya ikon dan warna selalu searah). */
:root[data-tema="gelap"] .tema-ikon-bulan {
  opacity: 0;
  transform: rotate(90deg) scale(0.6);
}

:root[data-tema="gelap"] .tema-ikon-matahari {
  opacity: 1;
  transform: none;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-tema="terang"]) .tema-ikon-bulan {
    opacity: 0;
    transform: rotate(90deg) scale(0.6);
  }

  :root:not([data-tema="terang"]) .tema-ikon-matahari {
    opacity: 1;
    transform: none;
  }
}

/* Transisi hanya saat pengunjung mengganti tema (perubahan atribut), bukan di cat pertama.
   Mati total di prefers-reduced-motion: ikon langsung berganti. */
@media (prefers-reduced-motion: no-preference) {
  .tema-toggle .tema-ikon,
  .tema-baris-ikon .tema-ikon {
    transition:
      opacity var(--durasi-menu) var(--easing-keluar),
      transform 240ms var(--easing-keluar);
  }
}

/* Tombol di header publik (tahap 6h): "Masuk"/"Akun" garis tipis dan "Course" emas. Tinggi 44px
   (target sentuh, DESIGN.md 8.9), sudut --radius-kartu seperti kontrol lain, bukan pil. */
.tombol-nav {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ruang-2);
  min-height: 44px;
  padding: 0 var(--ruang-4);
  border-radius: var(--radius-kartu);
  font-family: var(--font-sans);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
}

.tombol-nav .ikon {
  width: 1em;
  height: 1em;
}

.tombol-nav-garis {
  border: 1px solid var(--garis-kuat);
  background: transparent;
  color: var(--tinta);
}

.tombol-nav-garis:hover {
  background: var(--kertas);
  border-color: var(--tinta-2);
}

.tombol-nav-garis[aria-current="page"] {
  border-color: var(--laut);
  color: var(--laut);
}

/* Aksen emas di situs publik (keputusan pemilik tahap 6h): HANYA tombol ini. Token emas yang
   sama dengan area course (tokens.css); teks gelap di atas emas (11,79:1, putih gagal AA). */
.tombol-nav-emas {
  border: 1px solid transparent;
  background: var(--emas-utama);
  color: var(--teks-di-emas);
}

.tombol-nav-emas:hover {
  background: var(--emas-terang);
}

.tombol-nav-emas[aria-current="page"] {
  box-shadow: inset 0 0 0 2px var(--teks-di-emas);
}

/* Umpan balik tekan (tahap 6h): tombol dan tautan di header mengecil ke 0,97 selama ditekan,
   120ms. Hanya saat gerak diizinkan; warna tetap berubah di semua kondisi. */
@media (prefers-reduced-motion: no-preference) {
  .navbar-publik a,
  .navbar-publik button,
  .tombol {
    transition:
      background-color var(--durasi-mikro) var(--easing-keluar),
      border-color var(--durasi-mikro) var(--easing-keluar),
      color var(--durasi-mikro) var(--easing-keluar),
      opacity var(--durasi-mikro) var(--easing-keluar),
      box-shadow var(--durasi-mikro) var(--easing-keluar),
      transform var(--durasi-mikro) var(--easing-keluar);
  }

  .navbar-publik a:active,
  .navbar-publik button:active,
  .tombol:active {
    transform: scale(0.97);
  }
}

/* Hamburger (< 768px): ikon saja, 44x44, nama aksesibel "Menu" (teks sr-only). Garis tiga
   dari CSS, jadi tanpa gambar. */
.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: transparent;
  border: 1px solid var(--garis-kuat);
  border-radius: var(--radius-kartu);
  color: var(--tinta);
  cursor: pointer;
}

.nav-toggle-icon {
  display: block;
  width: 18px;
  height: 12px;
  position: relative;
}

.nav-toggle-icon::before,
.nav-toggle-icon::after,
.nav-toggle-icon span {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 2px;
  background: currentColor;
}

.nav-toggle-icon::before {
  top: 0;
}

.nav-toggle-icon span {
  top: 5px;
}

.nav-toggle-icon::after {
  top: 10px;
}

/* Hanya untuk panel menu mobile: tersembunyi di >= 768px. */
.nav-panel-saja {
  display: none;
}

/* Tablet (768 - 1023px): menu tengah tanpa "Beranda" (logo sudah ke Beranda), jarak diperapat
   supaya logo + menu + kontrol muat satu baris. */
@media (max-width: 899px) {
  /* Di bawah 900px nama brand turun ke dua baris ("Nusantara / Technology"), sama seperti di
     mobile, supaya logo + menu + kontrol muat satu baris tanpa memotong tombol Course. */
  .navbar-publik .wordmark {
    white-space: normal;
    line-height: 1.15;
    font-size: 0.9375rem;
  }

  .navbar-publik .wordmark span {
    max-width: 6.5rem;
  }
}

@media (min-width: 768px) and (max-width: 1023px) {
  .nav-item:first-child {
    display: none;
  }

  .nav-links > .nav-item > a,
  .nav-dropdown-pemicu {
    padding: 0 10px;
  }

  .navbar-publik .navbar-kontrol {
    gap: var(--ruang-1);
  }

  .tombol-nav {
    padding: 0 var(--ruang-3);
  }
}

@media (max-width: 767px) {
  /* Mobile: logo kiri; kanan = keranjang, "Course" kecil, hamburger. Tema dan Masuk/Akun ada di
     panel menu. */
  .kontrol-lebar {
    display: none;
  }

  .nav-toggle {
    display: inline-flex;
  }

  .tombol-nav {
    padding: 0 var(--ruang-3);
    font-size: 0.875rem;
  }

  .navbar-publik .navbar-kontrol {
    gap: var(--ruang-1);
  }

  .nav-utama {
    margin: 0;
  }

  .nav-links {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--permukaan);
    border-bottom: 1px solid var(--garis);
    box-shadow: var(--melayang);
    padding: var(--ruang-2) var(--halaman-px) var(--ruang-4);
    /* Panel lebih tinggi dari layar kecil (landscape): gulir di dalam panel. */
    max-height: calc(100dvh - var(--tinggi-header));
    overflow-y: auto;
  }

  .nav-links[hidden] {
    display: none;
  }

  @media (prefers-reduced-motion: no-preference) {
    .nav-links[hidden] {
      opacity: 0;
      transform: translateY(-6px);
    }

    @starting-style {
      .nav-links {
        opacity: 0;
        transform: translateY(-6px);
      }
    }
  }

  .nav-panel-saja {
    display: block;
  }

  .nav-item,
  .nav-panel-saja {
    flex-direction: column;
    border-bottom: 1px solid var(--garis);
  }

  .nav-links > li:last-child {
    border-bottom: none;
  }

  .nav-links > .nav-item > a,
  .nav-dropdown-pemicu,
  .nav-panel-saja a {
    display: flex;
    width: 100%;
    min-height: 48px;
    padding: 0 var(--ruang-3);
    align-items: center;
    font-family: var(--font-sans);
    font-size: 1rem;
    font-weight: 500;
    color: var(--tinta);
    text-decoration: none;
  }

  .nav-links a[aria-current="page"],
  .nav-dropdown-pemicu[aria-current] {
    color: var(--laut);
  }

  /* Di panel, item aktif = baris dengan latar dan batas pill, tanpa garis aksen bawah. */
  .nav-pill {
    inset: 3px 0;
  }

  .nav-pill::after {
    display: none;
  }

  .nav-dropdown-pemicu {
    justify-content: space-between;
  }

  /* Di panel mobile, dropdown jadi akordeon yang mengalir, bukan panel mengambang. */
  .nav-dropdown {
    position: static;
    min-width: 0;
    padding: 0 0 var(--ruang-2) var(--ruang-3);
    border: none;
    box-shadow: none;
    background: transparent;
  }

  .nav-dropdown a {
    padding: 0 var(--ruang-3);
    min-height: 48px;
  }

  .tema-baris {
    display: flex;
    align-items: center;
    gap: var(--ruang-3);
    width: 100%;
    min-height: 48px;
    padding: 0 var(--ruang-3);
    background: none;
    border: 0;
    color: var(--tinta);
    font-size: 1rem;
    text-align: left;
    cursor: pointer;
  }

  .tema-baris-ikon {
    position: relative;
    flex-shrink: 0;
    width: 24px;
    height: 24px;
  }

  /* Logo + Course + Keranjang + hamburger harus muat satu baris di 390px: wordmark boleh turun
     ke dua baris, tombol di kanan tidak pernah menyusut. */
  .navbar-row > .wordmark {
    min-width: 0;
    white-space: normal;
    line-height: 1.15;
    font-size: 0.9375rem;
  }

  .navbar-publik .navbar-kontrol {
    flex-shrink: 0;
  }
}

/* Pindah halaman: view transition antar dokumen (tahap 6h, DESIGN.md 7). Isi halaman memudar
   160ms; isi header (logo, menu, kontrol) punya nama sendiri dan langsung diganti tanpa
   memudar, jadi header tidak berkedip. Pill menu aktif punya nama sendiri dan meluncur 200ms
   dari item lama ke item baru. Dipasang hanya bila gerak diizinkan; peramban tanpa dukungan
   mengabaikan aturannya dan memakai pill cadangan di scripts/cepat.js. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }

  .navbar-publik .navbar-row {
    view-transition-name: header-situs;
  }

  ::view-transition-group(root) {
    animation-duration: 160ms;
  }

  ::view-transition-group(header-situs) {
    animation: none;
  }

  ::view-transition-old(header-situs) {
    display: none;
  }

  ::view-transition-new(header-situs) {
    animation: none;
  }

  ::view-transition-group(nav-pill) {
    animation-duration: 200ms;
    animation-timing-function: ease-out;
  }
}

/* --- Footer --- */

/* Navy gelap solid di seluruh situs dan di kedua mode (DESIGN.md 2 "Footer", 5 "Footer"):
   satu warna datar --kaki-latar, tanpa gradien. Semua warna di dalamnya dari --kaki-*, jadi
   tidak bergantung pada tema halaman. Footer penuh: padding 32px, dua baris, <= 320px di
   desktop. Varian .footer-tipis (di bawah, DESIGN.md 5 "Footer tipis") memakai warna yang
   sama tapi satu baris saja. */
.footer {
  /* Satu template kolom dipakai baris utama DAN baris bawah di desktop, supaya "Bahasa:
     Indonesia | IDR" jatuh tepat di bawah awal kolom Bantuan. Brand sedikit lebih lebar. */
  --footer-kolom: minmax(15rem, 1.4fr) repeat(3, minmax(0, 1fr));
  background: var(--kaki-latar);
  color: var(--kaki-tinta);
  padding-block: var(--ruang-6);
  color-scheme: dark;
  font-size: 0.9375rem;
}

.footer .wordmark {
  color: var(--kaki-judul);
}

.footer :focus-visible {
  outline-color: var(--kaki-fokus);
}

.footer-utama {
  display: grid;
  gap: var(--ruang-5);
}

/* Di bawah 640px (DESIGN.md 5 "Titik patah", tahap dasar) tiga kolom navigasi membungkus
   sendiri: 2 + 1 di 390px, 3 sejajar mulai ~560px. Brand selalu di atasnya. */
.footer-kolom {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
  gap: var(--ruang-4) var(--ruang-5);
}

/* Sedang ke atas (tahap 6a B5, keputusan pemilik: kolom naik ke baris brand mulai tablet,
   bukan cuma desktop): brand + Produk + Layanan + Bantuan dalam satu baris empat kolom. Pakai
   ambang "sedang" (>= 640px) yang sama dengan tiga-keadaan halaman di DESIGN.md, bukan ambang
   baru, supaya tidak menambah titik patah yang berdiri sendiri. Nav memakai subgrid supaya
   kolomnya sama persis dengan kolom baris bawah. */
@media (min-width: 640px) {
  .footer-utama,
  .footer .footer-bawah {
    display: grid;
    grid-template-columns: var(--footer-kolom);
    column-gap: var(--ruang-5);
  }

  .footer-kolom {
    grid-column: 2 / -1;
    grid-template-columns: subgrid;
  }

  .footer-bawah-bahasa {
    grid-column: 4;
  }
}

.footer-judul {
  margin: 0 0 var(--ruang-1);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--kaki-judul);
}

/* Target 44px (DESIGN.md 8.9): setiap tautan footer dan kontak setinggi 44px, rapat tanpa
   gap tambahan. Karena itu tiap kolom maksimal tiga tautan (Layout.tsx FOOTER_KOLOM). */
.footer-contact,
.daftar-kontak {
  list-style: none;
  margin: var(--ruang-1) 0 0;
  padding: 0;
  display: grid;
}

.footer-contact a,
.daftar-kontak a {
  display: inline-flex;
  align-items: center;
  gap: var(--ruang-2);
  min-height: 44px;
  color: var(--tinta-2);
  text-decoration: underline;
  text-underline-offset: 2px;
  overflow-wrap: anywhere;
}

.daftar-kontak a {
  color: var(--laut);
  font-size: var(--ukuran-lead);
}

.footer-nav {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
}

.footer-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  text-decoration: none;
}

/* Tautan di kolom kontak tetap bergaris bawah (dikenali tanpa warna); tautan navigasi di
   bawah judul kolom sudah jelas sebagai daftar tautan. */
.footer .footer-contact a,
.footer .footer-nav a {
  color: var(--kaki-tautan);
}

.footer .footer-contact a:hover,
.footer .footer-nav a:hover {
  color: var(--kaki-tautan-hover);
}

.footer-nav a:hover {
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Tautan Cart di kolom Bantuan (tahap 6a B5): satu-satunya tautan navigasi footer dengan
   ikon. Ukuran ikon ~1em (bukan 1.25em bawaan .ikon di 46-51) supaya sejajar tinggi huruf,
   bukan lebih besar dari teks di sebelahnya; warnanya ikut currentColor sama seperti tautan
   navigasi lain, tidak menambah warna baru. */
.footer-nav a.footer-nav-ikon {
  gap: var(--ruang-2);
}

.footer-nav a.footer-nav-ikon .ikon {
  width: 1em;
  height: 1em;
}

/* Baris bawah: hak cipta, lalu bahasa dan mata uang. Di bawah 640px keduanya rata kiri dan
   membungkus ke dua baris, bukan terpotong; di atas itu ikut grid di atas (kolom 1 dan 4). */
.footer-bawah {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ruang-1) var(--ruang-5);
  margin-top: var(--ruang-4);
  padding-top: var(--ruang-3);
  border-top: 1px solid var(--kaki-garis);
  font-size: var(--ukuran-label);
  color: var(--kaki-tinta);
}

.footer-bawah p {
  margin: 0;
}

/* Footer tipis (DESIGN.md 5 "Footer tipis", tahap 6a B5): /kontak dan seluruh area akun.
   Satu baris, rata kiri, jauh lebih tipis daripada footer penuh (16px vs 32px) karena isinya
   cuma identitas + hak cipta. flex-wrap supaya di layar sempit hak cipta turun ke baris kedua
   daripada terpotong, tanpa breakpoint tambahan. */
.footer-tipis {
  padding-block: var(--ruang-4);
}

.footer-tipis-baris {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: var(--ruang-5);
  row-gap: var(--ruang-1);
}

.footer-tipis-hak {
  margin: 0;
  color: var(--kaki-tinta);
  font-size: var(--ukuran-label);
}

/* --- Tombol WhatsApp melayang, DESIGN.md 8.3 --- */

.fab-wa {
  position: fixed;
  right: calc(16px + env(safe-area-inset-right, 0px));
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  width: 56px;
  height: 56px;
  border-radius: var(--radius-penuh);
  background: var(--wa);
  border: 2px solid var(--wa-tepi);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--melayang);
  z-index: 50;
  text-decoration: none;
  color: var(--wa-glif);
  /* DESIGN.md 8.3: muncul dan hilang tanpa animasi. */
  transition: none;
}

.fab-wa svg {
  width: 28px;
  height: 28px;
}

/* DESIGN.md 8.3: minggir saat .tombol-utama masuk zonanya ATAU saat form isian terlihat di
   layar (ui.js). Tanpa transisi, sengaja. visibility (bukan opacity) supaya FAB juga keluar
   dari urutan Tab selama tersembunyi. */
.fab-wa[data-minggir] {
  visibility: hidden;
}

/* --- Notifikasi "Ditambahkan ke keranjang", DESIGN.md 8.10 ---
   Menempel di bawah header, rata kanan dengan tombol Keranjang yang angkanya baru naik, jadi
   mata langsung menemukan keduanya. Mengambang di atas isi, karena itu satu-satunya yang
   memakai bayangan --melayang di luar dropdown dan FAB. */

.notif-wadah {
  /* Tepi kiri/kanan = tepi isi kontainer 72rem (sama dengan .container), jadi di layar lebar
     tepi kanan notifikasi segaris dengan tepi kanan tombol Keranjang. */
  --tepi-notif: max(
    var(--halaman-px),
    calc((100% - var(--lebar-konten-maks)) / 2 + var(--halaman-px))
  );
  position: fixed;
  top: calc(64px + var(--ruang-2) + env(safe-area-inset-top, 0px));
  right: calc(var(--tepi-notif) + env(safe-area-inset-right, 0px));
  left: calc(var(--tepi-notif) + env(safe-area-inset-left, 0px));
  z-index: 45;
  display: flex;
  justify-content: flex-end;
  pointer-events: none;
}

.notif {
  pointer-events: auto;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--ruang-2) var(--ruang-4);
  width: 100%;
  max-width: 24rem;
  padding: var(--ruang-2) var(--ruang-2) var(--ruang-2) var(--ruang-4);
  background: var(--permukaan);
  color: var(--tinta);
  border: 1px solid var(--garis-kuat);
  border-radius: var(--radius-kartu);
  box-shadow: var(--melayang);
  font-size: 0.9375rem;
}

.notif-pesan {
  display: flex;
  align-items: center;
  gap: var(--ruang-2);
  flex: 1 1 auto;
  font-weight: var(--berat-label);
}

.notif-pesan svg {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  fill: var(--sukses);
}

.notif a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--ruang-3);
  color: var(--laut);
  font-weight: var(--berat-label);
  text-underline-offset: 2px;
}

@media (prefers-reduced-motion: no-preference) {
  .notif {
    animation: notif-masuk var(--durasi-menu) var(--easing-keluar);
  }
}

@keyframes notif-masuk {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }
}

/* --- Tombol --- */

.tombol {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ruang-2);
  min-height: 44px;
  padding: var(--ruang-3) var(--ruang-5);
  border-radius: var(--radius-kartu);
  font-size: 0.9375rem;
  font-weight: var(--berat-label);
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
}

.tombol-utama {
  background: var(--laut);
  color: var(--teks-di-laut);
}

/* Glow hanya saat hover (DESIGN.md 6, "Glow"). */
.tombol-utama:hover {
  background: var(--laut-hover);
  box-shadow: var(--glow);
}

.tombol-garis {
  background: transparent;
  border-color: var(--garis-kuat);
  color: var(--tinta);
}

.tombol-garis:hover {
  border-color: var(--laut);
  color: var(--laut);
}

.tombol-lebar {
  width: 100%;
}

.tombol:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.tombol-utama:disabled:hover {
  background: var(--laut);
  box-shadow: none;
}

/* Umpan balik tekan tombol utama (DESIGN.md 7): naik 2px + glow saat hover, mengecil ke 0,97
   saat ditekan. Fungsinya menjawab "tombol ini yang akan bereaksi", jadi hanya di
   .tombol-utama. Seluruh gerak ada di dalam no-preference: dengan prefers-reduced-motion
   tidak ada translate/scale sama sekali, bukan sekadar transisi 0 ms yang melompat. */
@media (prefers-reduced-motion: no-preference) {
  .tombol-utama {
    transition: background-color var(--durasi-tombol) var(--easing-keluar),
      border-color var(--durasi-tombol) var(--easing-keluar),
      color var(--durasi-tombol) var(--easing-keluar),
      box-shadow var(--durasi-tombol) var(--easing-keluar),
      transform var(--durasi-tombol) var(--easing-keluar);
  }

  .tombol-utama:hover:not(:disabled) {
    transform: translateY(-2px);
  }

  .tombol-utama:active:not(:disabled) {
    transform: scale(0.97);
  }
}

/* "Masuk keranjang" selama 1,5 detik setelah berhasil (cart.js, DESIGN.md 8.10). Status
   dinyatakan lewat teks dan ikon cek, warna --sukses hanya penguat. Hover tidak mengembalikan
   warna ke --laut dan tanpa glow biru, supaya status tidak tertimpa saat kursor masih di atasnya. */
.tombol-utama[data-berhasil],
.tombol-utama[data-berhasil]:hover {
  background: var(--sukses);
  color: var(--teks-di-sukses);
  box-shadow: none;
}

.tombol-utama[data-berhasil] svg {
  width: 1.25em;
  height: 1.25em;
  flex-shrink: 0;
}

/* --- Grid kartu, DESIGN.md bagian 5 (tahap 6a A3: rapat ala marketplace) ---
   Kolom dihitung dari lebar wadah (.grid-wadah, container query), bukan lebar layar: grid
   yang sama dipakai di kolom penuh dan di separuh blok split. Ambang di rem, jadi zoom
   browser ikut menggeser jumlah kolom. Produk: 2 / 3 / 4 / 5. Artikel: 1 / 2 / 3 / 4. */

.grid-wadah {
  container-type: inline-size;
}

.grid-kartu {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--jarak-kartu-rapat);
}

@container (min-width: 36rem) {
  .grid-kartu {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@container (min-width: 54rem) {
  .grid-kartu {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@container (min-width: 68rem) {
  .grid-kartu {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
}

/* Section "Produk digital dan layanan AI" Beranda (tahap 6e-A): dikunci 2 kolom di semua
   lebar wadah (di atas dan di dalam semua @container di atas, jadi harus datang SETELAH-nya
   untuk menang lewat urutan yang sama-sama tanpa media/container query di sini - lihat
   komentar variasi di Grid.tsx). Selalu sampai 4 kartu, jadi 2x2 selalu rapi tanpa kartu
   sendirian di baris kedua, beda dari katalog rapat yang jumlah kartunya berubah-ubah. */
@container (min-width: 36rem) {
  .grid-kartu.grid-kartu-beranda-digital {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@container (min-width: 54rem) {
  .grid-kartu.grid-kartu-beranda-digital {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@container (min-width: 68rem) {
  .grid-kartu.grid-kartu-beranda-digital {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Kartu harga course (DESIGN.md 5, patahan #3) tetap lega: isinya daftar keterangan, bukan
   kartu katalog, jadi tidak ikut dirapatkan. */
.grid-harga {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--jarak-kartu);
}

/* --- Kartu produk, DESIGN.md 8.1 --- */

.kartu-produk {
  display: flex;
  flex-direction: column;
  border-radius: var(--radius-kartu);
  overflow: hidden;
  background: var(--permukaan);
  border: 1px solid var(--garis);
}

/* Glow hanya saat hover (DESIGN.md 6): menjawab "ini yang akan saya klik". Diam = datar. */
.kartu-produk:hover {
  border-color: var(--laut);
  box-shadow: var(--glow);
}

.kartu-produk-gambar {
  /* --garis di sini DUA peran: latar kosong permanen (tanpa gambar sama sekali) DAN
     kerangka/"skeleton" sementara saat <img loading="lazy"> belum dimuat - warnanya terlihat
     lewat img yang masih transparan sampai gambar selesai didekode. Statis, tanpa animasi
     berdenyut: DESIGN.md melarang animasi berulang tanpa pemicu. */
  aspect-ratio: 4 / 3;
  background: var(--garis);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.kartu-produk-gambar img,
.kartu-produk-gambar picture {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.kartu-produk-gambar picture[hidden] {
  display: none;
}

/* Detail produk dengan gambar default AI (ProductImage.tsx, varian detail): versi lebar 3:2,
   rasio asli fotonya, karena di halaman detail gambar punya kolom sendiri dan tidak perlu
   disejajarkan dengan kartu lain dalam satu baris grid. */
.kartu-produk-gambar[data-rasio="lebar"] {
  aspect-ratio: 3 / 2;
  border-radius: var(--radius-kartu);
}

.kartu-produk-gambar-kosong {
  padding: var(--ruang-3);
  text-align: center;
  color: var(--tinta-2);
  font-size: var(--ukuran-label);
}

/* --- Galeri foto produk (carousel), DESIGN.md 8.1a, tahap 6a B2.9 --- */
/* Hanya tampil kalau produk punya > 1 foto unggahan (ProductImage.tsx). Memakai wadah
   .kartu-produk-gambar yang sama (rasio 4:3, latar --garis sebagai kerangka), jadi hanya
   properti tata letak yang perlu ditimpa di sini. */

.galeri-produk-wadah {
  position: relative;
}

.galeri-produk {
  display: block;
  position: relative;
}

.galeri-track {
  display: flex;
  width: 100%;
  height: 100%;
  cursor: grab;
  /* Izinkan gulir vertikal halaman lewat sentuhan; geser mendatar ditangani galeri.js lewat
     Pointer Events. */
  touch-action: pan-y;
}

.galeri-track:active {
  cursor: grabbing;
}

/* Dipasang galeri.js selama menyeret: transisi dimatikan supaya jari terasa langsung
   mengikuti geseran, bukan lag di belakang transisi 280ms. */
.galeri-track.galeri-menyeret {
  transition: none !important;
}

.galeri-slide {
  flex: 0 0 100%;
  width: 100%;
  height: 100%;
}

.galeri-slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* draggable="false" di markup menangani sebagian besar peramban; -webkit-user-drag
     menutup celah di Safari. Tanpa ini drag-gambar bawaan peramban membajak urutan
     pointer event JS dan memutusnya lewat pointercancel di tengah geser mouse. */
  -webkit-user-drag: none;
  user-select: none;
}

@media (prefers-reduced-motion: no-preference) {
  .galeri-track {
    transition: transform 280ms var(--easing-keluar);
  }
}

/* Panah: permukaan solid (bukan scrim tembus pandang) supaya kontras ikonnya tidak
   bergantung pada warna foto di baliknya (R-25). Mengambang di atas foto, jadi memakai
   --melayang seperti dropdown dan tombol WA (DESIGN.md 6, "Bayangan"). */
.galeri-panah {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--garis);
  border-radius: var(--radius-kartu);
  background: var(--permukaan);
  color: var(--tinta);
  box-shadow: var(--melayang);
  cursor: pointer;
  padding: 0;
}

.galeri-panah:hover {
  border-color: var(--laut);
  color: var(--laut);
}

.galeri-panah svg {
  width: 20px;
  height: 20px;
}

.galeri-panah-kiri {
  left: var(--ruang-2);
}

.galeri-panah-kanan {
  right: var(--ruang-2);
}

/* Latar solid var(--permukaan), sama seperti panah: foto di baliknya bisa warna apa saja,
   jadi kontras dot tidak boleh bergantung pada scrim tembus pandang di atasnya (R-25). */
.galeri-dots {
  position: absolute;
  bottom: var(--ruang-2);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  max-width: calc(100% - var(--ruang-4));
  gap: var(--ruang-1);
  background: var(--permukaan);
  border: 1px solid var(--garis);
  padding: var(--ruang-1);
  border-radius: var(--radius-badge);
  box-shadow: var(--melayang);
}

/* Tap target 44px meski dot-nya kecil: ::after menggambar bulatan 8px, tombolnya sendiri
   yang mengisi seluruh area sentuh (antislop-layoutmobile, tap target >= 44px). Membungkus
   (flex-wrap) kalau fotonya banyak, supaya baris dots tidak pernah meluber ke luar wadah di
   layar sempit (R-03). Radius dot dibatasi ke --radius-badge (4px), bukan lingkaran penuh:
   DESIGN.md 6 mengunci --radius-penuh (999px) hanya untuk tombol WA melayang dan avatar. */
.galeri-dot {
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
}

.galeri-dot::after {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: var(--radius-badge);
  background: var(--garis-kuat);
}

.galeri-dot[aria-current="true"]::after {
  background: var(--laut);
}

.galeri-thumb {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ruang-2);
  margin-top: var(--ruang-3);
}

.galeri-thumb-item {
  width: 72px;
  height: 54px;
  padding: 0;
  border: 2px solid transparent;
  border-radius: var(--radius-badge);
  overflow: hidden;
  cursor: pointer;
  background: var(--garis);
}

.galeri-thumb-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.galeri-thumb-item[aria-current="true"] {
  border-color: var(--laut);
}

.galeri-thumb-item:hover {
  border-color: var(--garis-kuat);
}

.galeri-thumb-item[aria-current="true"]:hover {
  border-color: var(--laut);
}

.kartu-produk-isi {
  padding: var(--ruang-2) var(--ruang-3) var(--ruang-3);
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 2px;
}

/* Judul kartu rapat: ukuran body kecil, bukan H3 halaman, supaya dua baris muat di kartu
   selebar ~170px (2 kolom di 390px). Tetap 600 supaya nama tetap yang pertama terbaca. */
.kartu-produk-nama {
  font-size: 0.9375rem;
  line-height: 1.35;
}

/* Tautan setinggi minimal 44px (DESIGN.md 8.9); batas 2 baris dipindah ke span di dalamnya
   supaya tautan tidak ikut terpotong. */
.kartu-produk-nama a {
  display: flex;
  align-items: center;
  min-height: 44px;
  color: var(--tinta);
  text-decoration: none;
}

.kartu-produk-nama a span {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.kartu-produk-nama a:hover {
  color: var(--laut);
}

.kartu-produk-keterangan {
  font-size: 0.8125rem;
  color: var(--tinta-2);
}

/* Produk afiliasi (tahap 6i, DESIGN.md 8.1): label kecil, catatan harga, dan "Cek harga" memakai
   --tinta-2 yang sudah lolos kontras di dua tema; tidak ada warna atau badge baru. */
.label-afiliasi {
  font-weight: var(--berat-label);
}

.catatan-harga-afiliasi {
  margin: 0;
  font-size: 0.75rem;
  line-height: 1.3;
  color: var(--tinta-2);
}

.daftar-keunggulan {
  margin: var(--ruang-3) 0 0;
  padding-left: 1.25rem;
  max-width: var(--lebar-baca-maks);
  color: var(--tinta);
}

.daftar-keunggulan li + li {
  margin-top: var(--ruang-1);
}

.harga-cek {
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--tinta);
}

/* Pengganti foto untuk produk afiliasi yang belum punya gambar: ikon kategori di atas nama
   produk, polos, tanpa merek. Hanya cadangan sampai foto asli diunggah. */
.kartu-produk-gambar-kategori {
  flex-direction: column;
  gap: var(--ruang-2);
  width: 100%;
  height: 100%;
}

.kartu-produk-gambar-kategori:not([hidden]) {
  display: flex;
  align-items: center;
  justify-content: center;
}

.kartu-produk-gambar-kategori .ikon {
  width: 2rem;
  height: 2rem;
}

.kartu-produk-gambar-kategori span {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Motif identitas: baris angka. Lihat DESIGN.md "Motif identitas: baris angka". */
.kartu-produk-spacer {
  flex: 1;
}

.blok-angka {
  border-top: 1px solid var(--garis);
  padding-top: var(--ruang-2);
  display: flex;
  align-items: baseline;
  gap: var(--ruang-2);
  flex-wrap: wrap;
}

/* Jasa berharga awal (meta.harga_mulai): label teks biasa di depan angka, bukan harga coret. */
.harga-mulai-label {
  font-size: 0.8125rem;
  color: var(--tinta-2);
}

.harga-coret {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--ukuran-harga-coret);
  color: var(--tinta-2);
  text-decoration: line-through;
}

.harga-jual {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--ukuran-harga-jual);
  font-weight: 600;
  color: var(--tinta);
}

.badge-hemat {
  background: var(--promo);
  color: var(--teks-di-promo);
  border-radius: var(--radius-badge);
  font-size: var(--ukuran-label);
  font-weight: var(--berat-label);
  padding: 2px var(--ruang-2);
}

.promo-berlaku {
  font-size: var(--ukuran-label);
  color: var(--tinta-2);
  width: 100%;
}

.kartu-produk-aksi {
  margin-top: var(--ruang-2);
}

.kartu-produk .kartu-produk-aksi {
  margin-top: var(--ruang-1);
}

/* Di kartu rapat: harga tetap mono tabular (motif baris angka), hanya ukurannya turun ke
   skala kartu. Harga di halaman detail dan kartu harga course tidak terpengaruh. */
.kartu-produk .blok-angka {
  gap: 2px var(--ruang-2);
  line-height: 1.3;
}

/* Gambar kartu rapat 3:2, lebih pendek dari 4:3 di halaman lain, supaya dua baris kartu muat
   di layar laptop (DESIGN.md 5 "Grid kartu"). object-fit: cover tetap dari aturan dasar. */
.kartu-produk > .kartu-produk-gambar {
  aspect-ratio: 3 / 2;
}

.kartu-produk .harga-jual {
  font-size: 1.0625rem;
}

.kartu-produk .harga-coret,
.kartu-produk .badge-hemat,
.kartu-produk .promo-berlaku {
  font-size: 0.75rem;
}

.kartu-produk .badge-hemat {
  padding: 0 var(--ruang-1);
}

/* Tombol kartu rapat: tetap 44px tinggi (DESIGN.md 8.9), padding samping dan huruf dikecilkan
   supaya "Tambah ke keranjang" muat; boleh turun dua baris di kartu tersempit daripada
   terpotong. */
.kartu-produk .tombol {
  padding: var(--ruang-2);
  font-size: 0.875rem;
  line-height: 1.2;
  text-align: center;
  text-wrap: balance;
}

/* --- Kartu harga (course), DESIGN.md 8.2 --- */

.kartu-harga {
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-kartu);
  padding: var(--ruang-5);
  display: flex;
  flex-direction: column;
  gap: var(--ruang-3);
}

/* Badge dari data (meta.badge, mis. "Rekomendasi" - tahap 6e-A), BUKAN badge promo: warna
   emas-utama/teks-di-emas dipakai apa adanya (pasangan yang sudah terukur 11,79:1 di DESIGN.md
   9 "Aksen emas, area course"), jadi kontrasnya tetap lolos AA di kartu harga mana pun kartu
   ini dirender (/course bertema gelap maupun /ai bertema terang) tanpa token baru. Radius 4px
   sama seperti badge promo (DESIGN.md 8.2): bukan pill, bukan dekorasi. */
.kartu-harga-badge {
  align-self: flex-start;
  background: var(--emas-utama);
  color: var(--teks-di-emas);
  border-radius: var(--radius-badge);
  padding: 2px var(--ruang-2);
  font-size: var(--ukuran-label);
  font-weight: 600;
}

/* Garis pemisah label dan harga cukup satu: border-top .blok-angka (DESIGN.md 8.2). */
.kartu-harga-label {
  display: grid;
  gap: var(--ruang-1);
}

.kartu-harga-label h3 a {
  display: flex;
  align-items: center;
  min-height: 44px;
  color: var(--tinta);
  text-decoration: none;
}

.kartu-harga-label h3 a:hover {
  color: var(--laut);
}

/* Catatan cara barang sampai, ikon + teks (DESIGN.md 8.8). */
.catatan-ikon {
  display: flex;
  align-items: flex-start;
  gap: var(--ruang-2);
}

.catatan-ikon .ikon {
  margin-top: 0.15em;
}

.kartu-harga-keterangan {
  color: var(--tinta-2);
  font-size: 0.9375rem;
}

/* --- Kartu jasa di /ai#layanan, DESIGN.md 8.2b (tahap 6a B3) ---
   Bukan komponen baru: tetap ProductCard/.kartu-produk (8.1) dan grid GridProduk/.grid-kartu,
   cuma dikonfigurasi ulang lewat token yang sama supaya gayanya (garis, radius, permukaan)
   otomatis sama dengan kartu harga course tanpa diduplikasi, dan sedikit lebih besar sesuai
   permintaan pemilik. Semua selector dikunci ke #layanan supaya kartu hardware/digital/course
   di halaman lain tidak ikut berubah. */

/* Kolom eksplisit per lebar layar (bukan container query 2/3/4/5 bawaan .grid-kartu):
   section ini cuma berisi beberapa jasa tetap, jadi dikunci 1/2/3 supaya kartu selalu
   mengisi lebar kontainer, tidak ada kolom kosong. Gap "normal" (--jarak-kartu), sama
   dengan grid harga course, bukan gap rapat katalog. */
#layanan .grid-kartu {
  grid-template-columns: 1fr;
  gap: var(--jarak-kartu);
}

@media (min-width: 640px) {
  #layanan .grid-kartu {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

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

/* Gambar 16:10 (bukan 3:2 grid rapat atau 4:3 dasar): sedikit lebih lebar dari rapat,
   sesuai ukuran kartu yang sedikit lebih besar. */
#layanan .kartu-produk > .kartu-produk-gambar {
  aspect-ratio: 16 / 10;
}

/* Padding isi dan judul naik satu tingkat dari ukuran rapat (8px/12px, 0,9375rem) ke
   token normal berikutnya yang sudah ada (--ruang-4, --ukuran-body): "sedikit lebih
   besar, jangan berlebihan" dari pemilik, bukan ukuran kartu harga course yang penuh
   (h3 clamp 1,1875-1,5rem itu untuk kartu tanpa gambar, terlalu besar di sini). */
#layanan .kartu-produk-isi {
  padding: var(--ruang-4);
}

#layanan .kartu-produk-nama {
  font-size: var(--ukuran-body);
}

/* Hover: garis tepi ke --laut seperti bawaan .kartu-produk, tanpa glow besar (beda dari
   kartu katalog rapat, lihat Bagian 6). Kartu harga course diam saat hover; ini satu
   langkah di antaranya, garis saja tanpa bayangan. Transisinya sudah dari .kartu-produk
   di atas (dihormati prefers-reduced-motion di sana), jadi tidak perlu transisi baru. */
#layanan .kartu-produk:hover {
  box-shadow: none;
}

/* Aksi bayar pesanan (TombolBayar.tsx): tombol utama lalu keterangan langkah berikutnya.
   margin 16px karena baris total di atasnya sudah membawa padding 16px: jarak tampak dari
   angka total ke tombol jadi 32px, sama dengan jarak antarblok lain di kartu. Keterangan
   12px di bawah tombol supaya terbaca sebagai milik tombol itu, bukan paragraf lepas. */
.bayar-aksi {
  display: grid;
  justify-items: start;
  gap: var(--ruang-3);
  margin-top: var(--ruang-4);
  max-width: var(--lebar-baca-maks);
}

/* Tombol sekunder di bawah kartu pesanan (halaman sukses): 32px dari kartu, supaya tidak
   terbaca sebagai bagian dari langkah bayar di dalam kartu. */
.hero-aksi.aksi-setelah-kartu {
  margin-top: var(--ruang-6);
}

/* --- Blok harga di halaman, latar berbeda (DESIGN.md 5, patahan #3) --- */

.blok-harga {
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-panel);
  padding: var(--ruang-6);
}

/* --- Artikel --- */

/* Kartu artikel, DESIGN.md 8.12 (tahap 6a A2.5): bingkai 1px --garis, radius 12px, dan satu
   tautan judul yang diregangkan (::after) menutupi seluruh kartu. Naik 2px + bayangan
   --melayang hanya saat hover: kartunya memang satu target klik, jadi elevasi menjawab "ini
   yang akan saya buka". Diam = datar, seperti kartu produk. */
.kartu-artikel {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-panel);
  overflow: hidden;
}

.kartu-artikel:hover {
  box-shadow: var(--melayang);
}

@media (prefers-reduced-motion: no-preference) {
  .kartu-artikel {
    transition: transform var(--durasi-tombol) var(--easing-keluar),
      box-shadow var(--durasi-tombol) var(--easing-keluar);
  }

  .kartu-artikel:hover {
    transform: translateY(-2px);
  }
}

/* Cincin fokus pindah dari teks judul ke seluruh kartu, karena area kliknya seluruh kartu. */
@supports selector(:has(a)) {
  .kartu-artikel:has(h3 a:focus-visible) {
    outline: 2px solid var(--laut);
    outline-offset: 2px;
  }

  .kartu-artikel h3 a:focus-visible {
    outline: none;
  }
}

.kartu-artikel-gambar {
  aspect-ratio: 16 / 9;
  background: var(--garis);
  overflow: hidden;
}

.kartu-artikel-gambar img,
.kartu-artikel-gambar picture,
.artikel-gambar img,
.artikel-gambar picture {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.kartu-artikel-gambar picture[hidden],
.artikel-gambar picture[hidden] {
  display: none;
}

.kartu-artikel-isi {
  display: flex;
  flex-direction: column;
  gap: var(--ruang-1);
  padding: var(--ruang-2) var(--ruang-3) var(--ruang-4);
}

.kartu-artikel h3 {
  font-size: 1rem;
  line-height: 1.35;
}

/* Judul maksimal 2 baris, sama dengan nama produk; batasnya di span supaya tautan tetap 44px. */
.kartu-artikel h3 a span {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.kartu-artikel h3 a {
  display: flex;
  align-items: center;
  min-height: 44px;
  color: var(--tinta);
  text-decoration: none;
}

.kartu-artikel h3 a::after {
  content: "";
  position: absolute;
  inset: 0;
}

.kartu-artikel:hover h3 a {
  color: var(--laut);
}

.kartu-artikel-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ruang-1) var(--ruang-3);
  font-size: var(--ukuran-label);
  color: var(--tinta-2);
}

.kartu-artikel-meta time {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* Deskripsi dipotong di 2 baris supaya kartu dalam satu baris grid tetap sejajar dan rapat. */
.kartu-artikel-ringkas {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: 0.875rem;
  color: var(--tinta-2);
}

/* /artikel: filter kategori sidebar di >= 1024px, disclosure di bawahnya. Grid 1/2/3 kolom. */
.artikel-tata {
  display: grid;
  gap: var(--ruang-5);
}

.filter-sisi {
  display: none;
}

@media (min-width: 1024px) {
  .artikel-tata {
    grid-template-columns: 11rem minmax(0, 1fr);
    gap: var(--ruang-7);
    align-items: start;
  }

  .filter-sisi {
    display: block;
    position: sticky;
    top: calc(64px + var(--ruang-5));
  }

  .filter-dropdown {
    display: none;
  }
}

.filter-judul {
  font-size: var(--ukuran-label);
  font-weight: var(--berat-label);
  color: var(--tinta-2);
  margin-bottom: var(--ruang-2);
}

.filter-kategori {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
}

.filter-kategori a {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--ruang-3);
  border-radius: var(--radius-badge);
  color: var(--tinta);
  text-decoration: none;
}

.filter-kategori a:hover {
  color: var(--laut);
  background: var(--permukaan);
}

.filter-kategori a[aria-current="page"] {
  color: var(--laut);
  background: var(--permukaan);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 4px;
}

.filter-dropdown {
  border: 1px solid var(--garis-kuat);
  border-radius: var(--radius-badge);
  background: var(--permukaan);
}

.filter-dropdown summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ruang-3);
  min-height: 44px;
  padding: 0 var(--ruang-3);
  cursor: pointer;
  list-style: none;
}

.filter-dropdown summary::-webkit-details-marker {
  display: none;
}

.filter-dropdown[open] summary .ikon-chevron {
  transform: rotate(180deg);
}

.filter-dropdown .filter-kategori {
  border-top: 1px solid var(--garis);
  padding: var(--ruang-1);
}

.artikel-kepala {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--ruang-2) var(--ruang-4);
  margin-bottom: var(--ruang-5);
}

.artikel-kepala h2 {
  font-size: var(--ukuran-h3);
}

.grid-artikel {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--jarak-kartu-rapat);
}

@container (min-width: 34rem) {
  .grid-artikel {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@container (min-width: 50rem) {
  .grid-artikel {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@container (min-width: 68rem) {
  .grid-artikel {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* "Artikel terbaru" di Beranda (tahap 6a B7): begitu wadah cukup lebar untuk lebih dari satu
   kolom (>= 34rem, ambang yang sama dengan .grid-artikel biasa), loncat LANGSUNG ke 3 kolom,
   tidak pernah berhenti di 2. Beranda selalu mengirim tepat 3 artikel (getPublishedArticles
   limit 3): dengan tangga 1/2/3/4 biasa, wadah 768px jatuh di tangga 2 kolom, dan 3 kartu di
   situ menyisakan satu kartu sendirian di baris kedua (persis "baris kedua yang menggantung").
   3 kolom juga dipertahankan di wadah paling lebar (>= 68rem), tidak ikut naik ke 4 seperti
   .grid-artikel biasa, supaya tidak menyisakan satu sel kosong di kanan. Selector gabungan
   (dua kelas) menang atas kedua aturan `.grid-artikel` di atas lewat spesifisitas, tidak
   bergantung urutan berkas. */
@container (min-width: 34rem) {
  .grid-artikel.grid-artikel-beranda {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* Satu kolom (wadah < 34rem, praktis ponsel): kartu jadi baris mendatar, gambar kecil di kiri,
   supaya satu artikel tidak memakan satu layar penuh dengan gambar 16:9 selebar layar. */
@container (max-width: 33.99rem) {
  .kartu-artikel {
    display: grid;
    grid-template-columns: 7.5rem minmax(0, 1fr);
  }

  .kartu-artikel-gambar {
    aspect-ratio: 1 / 1;
  }

  .kartu-artikel-isi {
    padding: var(--ruang-2) var(--ruang-3);
    gap: var(--ruang-1);
  }

  .kartu-artikel-ringkas {
    display: none;
  }
}

.paginasi {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ruang-2);
  margin-top: var(--ruang-6);
}

.paginasi ol {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ruang-2);
  list-style: none;
  margin: 0;
  padding: 0;
}

.paginasi a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 var(--ruang-3);
  border: 1px solid var(--garis-kuat);
  border-radius: var(--radius-kartu);
  color: var(--tinta);
  text-decoration: none;
}

.paginasi a:hover {
  border-color: var(--laut);
  color: var(--laut);
}

.paginasi a[aria-current="page"] {
  background: var(--laut);
  border-color: var(--laut);
  color: var(--teks-di-laut);
}

/* Detail artikel */
.artikel-isi {
  max-width: var(--lebar-baca-maks);
}

.artikel-kategori {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-weight: var(--berat-label);
}

.artikel-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ruang-1) var(--ruang-4);
  font-size: var(--ukuran-label);
  color: var(--tinta-2);
}

.artikel-gambar {
  aspect-ratio: 3 / 2;
  background: var(--garis);
  border-radius: var(--radius-panel);
  overflow: hidden;
}

.artikel-isi h2 {
  margin-top: var(--ruang-7);
  margin-bottom: var(--ruang-3);
}

.artikel-isi h3 {
  margin-top: var(--ruang-5);
  margin-bottom: var(--ruang-2);
}

.artikel-isi p {
  margin-bottom: var(--ruang-4);
}

.artikel-badan ul,
.artikel-badan ol {
  margin: 0 0 var(--ruang-4);
  padding-left: 1.5rem;
}

.artikel-badan li {
  margin-bottom: var(--ruang-2);
}

.artikel-badan li p {
  margin-bottom: var(--ruang-2);
}

.artikel-isi a {
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* "Baca juga" (tahap 6e-A): satu kalimat biru tebal setelah isi artikel, sebelum footer.
   Warna dan garis bawah tautan di dalamnya mewarisi dari sini, jadi seluruh kalimat (bukan
   cuma kata "Baca juga") terbaca sebagai satu ajakan, bukan teks biasa + satu tautan kecil. */
.artikel-baca-juga {
  color: var(--laut);
  font-weight: 600;
}

.artikel-baca-juga a {
  color: inherit;
}

.disclosure-afiliasi {
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-left: 3px solid var(--tinta-2);
  border-radius: var(--radius-badge);
  padding: var(--ruang-3) var(--ruang-4);
  font-size: var(--ukuran-label);
  color: var(--tinta-2);
  margin-bottom: var(--ruang-6);
}

/* --- Form, DESIGN.md 8.4 --- */

.form {
  display: grid;
  gap: var(--jarak-field);
  max-width: 32rem;
}

/* Kelompok field yang dibuka-tutup skrip admin (hidden), tetap berjarak sama dengan .form. */
.grup-field {
  display: grid;
  gap: var(--jarak-field);
}

.grup-field[hidden] {
  display: none;
}

.field {
  display: grid;
  gap: var(--ruang-1);
  /* Item grid default punya min-width: auto, yang di Chrome/Firefox dihitung dari lebar
     konten intrinsik anaknya - untuk <select> itu opsi terpanjangnya. Tanpa ini, satu opsi
     panjang (mis. "Ebook: Menulis Prompt untuk Bisnis (produk digital)") meluberkan seluruh
     kolom grid .form, dan SEMUA field di form ikut overflow horizontal di layar sempit. */
  min-width: 0;
}

.field label {
  font-size: var(--ukuran-label);
  font-weight: var(--berat-label);
  color: var(--tinta);
}

.field .opsional {
  font-weight: 400;
  color: var(--tinta-2);
}

.field input,
.field textarea,
.field select {
  width: 100%;
  min-height: 44px;
  padding: var(--ruang-2) var(--ruang-3);
  border: 1px solid var(--garis-kuat);
  border-radius: var(--radius-badge);
  font-family: var(--font-sans);
  font-size: 1rem;
  background: var(--permukaan);
  color: var(--tinta);
}

.field textarea {
  min-height: 96px;
  resize: vertical;
}

.field input[aria-invalid="true"],
.field textarea[aria-invalid="true"] {
  border-color: var(--galat);
}

.field-galat {
  display: flex;
  align-items: flex-start;
  gap: var(--ruang-1);
  font-size: var(--ukuran-label);
  color: var(--galat);
}

.form-hasil {
  border-radius: var(--radius-badge);
  padding: var(--ruang-4);
  font-size: 0.9375rem;
  display: flex;
  align-items: flex-start;
  gap: var(--ruang-2);
}

.form-hasil svg {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  margin-top: 2px;
}

.form-hasil-sukses {
  background: var(--permukaan);
  color: var(--tinta);
  border: 1px solid var(--garis);
  border-left: 3px solid var(--sukses);
}

.form-hasil-sukses svg {
  fill: var(--sukses);
}

.form-hasil-gagal {
  background: var(--permukaan);
  color: var(--tinta);
  border: 1px solid var(--garis);
  border-left: 3px solid var(--galat);
}

.form-hasil-gagal svg {
  fill: var(--galat);
}

/* Ikon garis (Lucide) di dalam hasil form: tanpa isi, warna dari teks. */
.form-hasil svg.ikon {
  fill: none;
  stroke: currentColor;
}

/* --- Chip status pesanan, DESIGN.md 8.6. Selalu ikon + teks, tidak pernah warna saja. --- */

.chip-status {
  display: inline-flex;
  align-items: center;
  gap: var(--ruang-1);
  border: 1px solid currentColor;
  border-radius: var(--radius-badge);
  padding: 2px var(--ruang-2);
  font-size: var(--ukuran-label);
  font-weight: var(--berat-label);
  white-space: nowrap;
}

.chip-status svg {
  width: 14px;
  height: 14px;
  fill: currentColor;
}

.chip-status-netral {
  color: var(--tinta-2);
}

.chip-status-sukses {
  color: var(--sukses);
}

.chip-status-galat {
  color: var(--galat);
}

/* --- Keranjang & checkout --- */

.baris-keranjang {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--ruang-4);
  padding-block: var(--ruang-4);
  border-bottom: 1px solid var(--garis);
  align-items: start;
}

.baris-keranjang-info h3 {
  font-size: 1rem;
}

.baris-keranjang-info h3 a {
  color: var(--tinta);
  text-decoration: none;
}

.baris-keranjang-aksi {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--ruang-2);
}

/* Halaman /cart (FASE 1, DESIGN.md 8.11). Baris dirender cart.js dari localStorage. */
.keranjang-kepala {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--ruang-4);
  border-bottom: 1px solid var(--garis);
}

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

.baris-keranjang-nama {
  font-size: 1rem;
}

.baris-keranjang-nama a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--tinta);
  text-decoration: none;
}

.baris-keranjang-nama a:hover {
  color: var(--laut);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* < 640px: nama di atas, lalu grid tetap: stepper kiri + subtotal kanan, Hapus di baris
   sendiri. Grid (bukan flex-wrap) supaya setiap baris keranjang pecah di tempat yang sama,
   berapa pun panjang angkanya. >= 640px: nama kiri, aksi kanan dalam satu baris. */
.daftar-keranjang .baris-keranjang {
  grid-template-columns: 1fr;
  gap: var(--ruang-2);
}

.daftar-keranjang .baris-keranjang-aksi {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: var(--ruang-1) var(--ruang-4);
}

.daftar-keranjang .baris-keranjang-aksi .baris-keranjang-subtotal {
  text-align: right;
}

.daftar-keranjang .baris-keranjang-aksi .tombol-teks {
  grid-column: 1 / -1;
  justify-self: start;
  margin-left: calc(-1 * var(--ruang-2));
}

.baris-keranjang-subtotal {
  font-size: var(--ukuran-h3);
}

@media (min-width: 640px) {
  .daftar-keranjang .baris-keranjang {
    grid-template-columns: 1fr auto;
    gap: var(--ruang-5);
    align-items: center;
  }

  .daftar-keranjang .baris-keranjang-aksi {
    display: flex;
    flex-direction: row;
    justify-content: flex-end;
    gap: var(--ruang-4);
  }

  .daftar-keranjang .baris-keranjang-aksi .tombol-teks {
    margin-left: 0;
  }

  /* Lebar tetap untuk angka sampai 11 karakter (Rp99.999.999) supaya stepper qty di setiap
     baris berdiri di kolom yang sama. */
  .baris-keranjang-subtotal {
    min-width: 11rem;
    text-align: right;
  }
}

/* Stepper qty: tombol 44x44 di kiri-kanan input. Batas --garis-kuat (3:1) di kedua mode. */
.qty {
  display: inline-flex;
  align-items: stretch;
}

.qty-tombol,
.qty input[type="number"] {
  min-height: 44px;
  border: 1px solid var(--garis-kuat);
  background: var(--permukaan);
  color: var(--tinta);
  font-family: var(--font-mono);
  font-size: 1rem;
}

.qty-tombol {
  width: 44px;
  cursor: pointer;
}

.qty-tombol:first-child {
  border-radius: var(--radius-badge) 0 0 var(--radius-badge);
}

.qty-tombol:last-child {
  border-radius: 0 var(--radius-badge) var(--radius-badge) 0;
}

.qty-tombol:hover:not(:disabled) {
  color: var(--laut);
  border-color: var(--laut);
}

.qty-tombol:disabled {
  color: var(--tinta-2);
  cursor: not-allowed;
}

.qty input[type="number"] {
  width: 3.5rem;
  border-inline: 0;
  text-align: center;
  -moz-appearance: textfield;
  appearance: textfield;
}

.qty input[type="number"]::-webkit-inner-spin-button,
.qty input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.keranjang-aksi {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ruang-3);
  margin-top: var(--ruang-5);
}

.keranjang-aksi .tombol {
  flex: 1 1 16rem;
}

@media (min-width: 1024px) {
  .keranjang-aksi .tombol {
    flex: 0 0 auto;
  }
}

.keranjang .catatan-ikon {
  max-width: var(--lebar-baca-maks);
}

.tombol-teks {
  background: none;
  border: none;
  color: var(--tinta-2);
  text-decoration: underline;
  text-underline-offset: 2px;
  font-size: var(--ukuran-label);
  cursor: pointer;
  min-height: 44px;
  padding: 0 var(--ruang-2);
}

.tombol-teks:hover {
  color: var(--galat);
}

.ringkasan-total {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding-block: var(--ruang-4);
  border-top: 1px solid var(--garis-kuat);
  margin-top: var(--ruang-2);
}

.ringkasan-total .harga-jual {
  font-size: var(--ukuran-h3);
}

/* --- Tabel admin --- */

.tabel-admin {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9375rem;
}

.tabel-admin th,
.tabel-admin td {
  text-align: left;
  padding: var(--ruang-3) var(--ruang-3);
  border-bottom: 1px solid var(--garis);
  vertical-align: middle;
}

.tabel-admin th {
  color: var(--tinta-2);
  font-weight: var(--berat-label);
  font-size: var(--ukuran-label);
}

.tabel-admin-scroll {
  overflow-x: auto;
}

.form-status-admin {
  display: flex;
  gap: var(--ruang-2);
  align-items: center;
}

.form-status-admin select {
  min-height: 44px;
  padding: var(--ruang-2);
  border: 1px solid var(--garis-kuat);
  border-radius: var(--radius-badge);
  font-family: var(--font-sans);
}

/* --- Keadaan data, DESIGN.md 8.5 --- */

.keadaan-data {
  padding: var(--ruang-6) var(--ruang-4);
  text-align: left;
  color: var(--tinta-2);
  border: 1px dashed var(--garis);
  border-radius: var(--radius-kartu);
  max-width: var(--lebar-baca-maks);
}

.keadaan-data p {
  margin-bottom: var(--ruang-3);
}

.keadaan-data:last-child p {
  margin-bottom: 0;
}

/* --- Hero terang ringkas, halaman transaksi (DESIGN.md 4 dan 5 "Hero gelap") ---
   Ikut lebar kontainer 72rem (rata kiri dengan isi di bawahnya), bukan kolom sempit di
   tengah. Tanpa padding bawah: section berikutnya yang memberi jarak, supaya H1 tidak
   dikelilingi ruang kosong ganda (audit #8). */

.hero {
  padding-top: var(--ruang-6);
  display: grid;
  gap: var(--ruang-4);
}

.hero > * {
  max-width: 44rem;
}

.hero + .section {
  padding-top: var(--ruang-6);
}

.hero:last-child {
  padding-bottom: var(--section-py);
}

@media (min-width: 1024px) {
  .hero {
    padding-top: var(--ruang-7);
  }
}

.hero .lead {
  max-width: var(--lebar-baca-maks);
}

/* Detail produk: split gambar + harga langsung di bawah header. */
.produk-atas {
  padding-top: var(--ruang-6);
}

@media (min-width: 1024px) {
  .produk-atas {
    padding-top: var(--ruang-7);
  }
}

/* Checkout: ringkasan rata atas dengan form, lengket di layar lebar (DESIGN.md 5). */
@media (min-width: 1024px) {
  .ringkasan-checkout {
    position: sticky;
    top: calc(64px + var(--ruang-5));
  }
}

/* --- Hero gelap halaman utama, DESIGN.md 5 "Hero gelap" dan 7 --- */

.hero-gelap {
  position: relative;
  isolation: isolate;
  /* Hanya memotong ilustrasi dekoratif; tinggi pita mengikuti isi, jadi teks tidak pernah
     terpotong walau diperbesar 200%. */
  overflow: hidden;
  background: var(--hero-latar);
  color: var(--hero-tinta);
  border-bottom: 1px solid var(--hero-jejak);
}

/* Ilustrasi = static asset public/images/hero/*.svg lewat <object> (HeroGelap.tsx). Warna,
   animasi, jeda, dan versi diam ada di dalam berkas SVG itu sendiri. */
.hero-ilustrasi {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -2;
  pointer-events: none;
}

/* Scrim. < 1024px chip jatuh di belakang teks, jadi lapisan rata 80% di seluruh ilustrasi.
   Titik terburuk (#CFE4FF di bawah 80%) = #2F3C55, kontrasnya di tabel DESIGN.md 2. */
.hero-gelap::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: color-mix(in srgb, var(--hero-latar) 80%, transparent);
}

/* >= 1024px: pekat (>= 90%) sampai ujung kolom teks 36rem, lalu memudar ke arah chip. Titik
   henti dihitung dari tepi kiri kontainer 72rem, jadi ikut bergeser di layar lebar. */
@media (min-width: 1024px) {
  .hero-gelap::before {
    --tepi-kontainer: max(0px, (100% - var(--lebar-konten-maks)) / 2);
    background: linear-gradient(
      90deg,
      var(--hero-latar) 0,
      color-mix(in srgb, var(--hero-latar) 90%, transparent)
        calc(var(--tepi-kontainer) + var(--halaman-px) + 38rem),
      transparent calc(var(--tepi-kontainer) + var(--halaman-px) + 58rem)
    );
  }
}

.hero-gelap-isi {
  display: grid;
  gap: var(--ruang-4);
  padding-block: var(--ruang-7) 56px;
}

.hero-gelap-isi > * {
  max-width: 36rem;
}

@media (min-width: 640px) {
  .hero-gelap-isi {
    padding-block: var(--ruang-8) 72px;
  }
}

@media (min-width: 1024px) {
  .hero-gelap-isi {
    padding-block: var(--ruang-9);
  }
}

.hero-gelap h1 {
  color: var(--hero-tinta);
}

/* >= 1280px chip bergeser cukup jauh ke kanan (tepi kiri chip ~832px), jadi H1 boleh
   melebar ke 42rem supaya tidak pecah jadi empat baris. Teks kecil tetap 36rem. */
@media (min-width: 1280px) {
  .hero-gelap-isi > h1 {
    max-width: 42rem;
  }
}

.hero-gelap .lead {
  color: var(--hero-tinta-2);
}

.hero-gelap :focus-visible {
  outline-color: var(--hero-pulsa);
}

/* Isi --laut hanya 2,97:1 di ujung --hero-latar-2; tepi --hero-pulsa menjaga batas >= 3:1. */
.hero-gelap .tombol-utama {
  border-color: var(--hero-pulsa);
}

.hero-gelap .tombol-garis {
  color: var(--hero-tinta);
  border-color: var(--hero-garis-kuat);
}

.hero-gelap .tombol-garis:hover {
  color: var(--hero-tinta);
  border-color: var(--hero-pulsa);
}

/* Tombol "AI" di hero Beranda (tahap 6a B2.9): ghost seperti .tombol-garis, tapi teks
   memakai warna yang menandai tujuannya, bukan --tinta netral. Padding mendatar dipersempit
   (--ruang-4, bukan --ruang-5) supaya "AI" tidak lebar kosong. */
.tombol-ai {
  background: transparent;
  padding-inline: var(--ruang-4);
  color: var(--laut);
  border-color: var(--garis-kuat);
}

.tombol-ai:hover {
  border-color: var(--laut);
}

/* Tombol "Course" hero Beranda (tahap 6e-A, ganti "Konsultasi Via Whatsapp" - keputusan
   pemilik: sejak ini hero Beranda cuma punya SATU tautan --wa lagi, yaitu FAB melayang,
   lihat DESIGN.md 2). "Kotak nuansa emas", beda dari .tombol-ai yang transparan penuh - di
   sini kotaknya sendiri bertinta emas tipis, bukan cuma teks dan tepinya. Tepi memakai
   --amber-redup yang sudah dipakai border kartu area course (DESIGN.md 9 "Aksen emas, area
   course"), jadi satu keluarga warna dengan identitas course yang sudah ada. */
.tombol-course {
  background: color-mix(in srgb, var(--emas-utama) 14%, transparent);
  color: var(--emas-oranye);
  border-color: var(--amber-redup);
  padding-inline: var(--ruang-4);
  font-weight: 600; /* semi-bold diminta pemilik; --berat-label dasar .tombol cuma 500 */
}

.tombol-course:hover {
  background: color-mix(in srgb, var(--emas-utama) 22%, transparent);
  border-color: var(--emas-utama);
}

/* Isi --laut terang hanya ~3,3:1 di atas --hero-latar dan turun lebih jauh lagi di titik
   ilustrasi paling terang (lihat DESIGN.md 2, "Rasio kontras terverifikasi"), jadi gagal
   4,5:1 sebagai teks. --hero-simpul (varian terang yang sudah ada di keluarga token hero,
   dipakai untuk titik ujung jalur sirkuit) tetap >= 4,5:1 di titik itu. */
.hero-gelap .tombol-ai {
  color: var(--hero-simpul);
  border-color: var(--hero-garis-kuat);
}

.hero-gelap .tombol-ai:hover {
  color: var(--hero-simpul);
  border-color: var(--hero-pulsa);
}

.hero-aksi {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ruang-3);
  margin-top: var(--ruang-2);
}

/* --- Admin: navigasi antar-halaman admin --- */

.admin-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ruang-4);
  margin-top: var(--ruang-2);
}

.admin-nav a {
  color: var(--tinta-2);
  text-decoration: none;
  font-size: var(--ukuran-label);
  font-weight: var(--berat-label);
  /* Target 44px (DESIGN.md 8.9); nav admin kini lima item dan membungkus di 390px. */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.admin-nav a[aria-current="page"] {
  color: var(--tinta);
  border-bottom: 2px solid var(--laut);
}

.admin-nav a:hover {
  color: var(--laut);
}

/* --- Admin: unggah gambar produk (/admin/upload) ---
   Dropzone dan galeri keduanya alat kerja internal, bukan halaman pemasaran, jadi memakai
   warna aksen --laut yang sama dengan tombol utama di situs publik: satu aksen konsisten,
   bukan warna baru (DESIGN.md/antislop R-29). */

.dropzone {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--ruang-2);
  min-height: 120px;
  padding: var(--ruang-5) var(--ruang-4);
  border: 1px dashed var(--garis-kuat);
  border-radius: var(--radius-kartu);
  text-align: center;
  color: var(--tinta-2);
  font-size: var(--ukuran-label);
  cursor: pointer;
}

.dropzone:hover {
  border-color: var(--laut);
  color: var(--laut);
}

.dropzone:focus-within {
  outline: 2px solid var(--laut);
  outline-offset: 2px;
}

.dropzone-aktif {
  border-color: var(--laut);
  background: color-mix(in srgb, var(--laut) 8%, transparent);
  color: var(--laut);
}

.dropzone input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.dropzone-list {
  list-style: none;
  margin: var(--ruang-2) 0 0;
  padding: 0;
  display: grid;
  gap: var(--ruang-1);
  font-size: var(--ukuran-label);
  color: var(--tinta-2);
}

.galeri-admin {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: var(--ruang-3);
}

.galeri-admin-item {
  display: grid;
  gap: var(--ruang-2);
  padding: var(--ruang-2);
  border: 1px solid var(--garis);
  border-radius: var(--radius-badge);
  background: var(--permukaan);
}

.galeri-admin-item img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-badge);
  background: var(--garis);
}

.galeri-admin-item .tombol-teks {
  min-height: 44px;
}

/* --- Area akun: header dashboard (tahap 6d-2, Layout.tsx dashboardShell) ---
   .navbar/.navbar-latar/.navbar-row/.wordmark/.navbar-menu/.navbar-kontrol/.nav-ikon dipakai
   apa adanya dari navbar situs publik (warnanya sudah benar lewat data-area="akun"); di sini
   cuma menu "Course" dan menu akun yang memang beda dari header publik. */
.navbar-dashboard-menu a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--tinta);
  text-decoration: none;
  font-size: 0.9375rem;
  border-bottom: 2px solid transparent;
}

.navbar-dashboard-menu a[aria-current="page"] {
  border-bottom-color: var(--laut);
  color: var(--laut);
}

/* Menu akun: sama pola dengan dropdown "Produk" publik (button aria-expanded + panel absolute),
   cuma ditambatkan ke kanan karena ini item terakhir di header. */
.akun-menu {
  position: relative;
}

.akun-menu-pemicu {
  display: inline-flex;
  align-items: center;
  gap: var(--ruang-2);
  min-height: 44px;
  padding: 0 0 0 var(--ruang-2);
  background: none;
  border: 0;
  color: var(--tinta);
  font: inherit;
  cursor: pointer;
}

.akun-menu-halo {
  font-size: 0.9375rem;
}

.avatar-bulat {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-penuh);
  background: var(--garis);
  color: var(--tinta-2);
}

.avatar-bulat .ikon {
  width: 18px;
  height: 18px;
}

.akun-menu-daftar {
  list-style: none;
  margin: 0;
  padding: var(--ruang-2);
  position: absolute;
  top: calc(100% + var(--ruang-2));
  right: 0;
  min-width: 10rem;
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-kartu);
  box-shadow: var(--melayang);
  z-index: 45;
}

.akun-menu-daftar[hidden] {
  display: none;
}

.akun-menu-daftar button {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 44px;
  padding: 0 var(--ruang-3);
  background: none;
  border: 0;
  border-radius: var(--radius-badge);
  color: var(--tinta);
  font: inherit;
  font-size: 0.9375rem;
  text-align: left;
  cursor: pointer;
}

.akun-menu-daftar button:hover {
  background: var(--kertas);
  color: var(--laut);
}

/* Header ringkas (DESIGN.md "Mobile: header ringkas"): sapaan disembunyikan, avatar + ikon
   cari saja tetap tampil (nama tetap terbaca via aria-label tombol untuk pembaca layar). */
@media (max-width: 639px) {
  .akun-menu-halo {
    display: none;
  }
}

/* --- Area akun: My Courses /dashboard (tahap 6d-2) ---
   Kartu datar berbingkai 1px, tanpa bayangan (DESIGN.md 6). Tiga titik patah eksplisit (bukan
   auto-fit): grid ini butuh jumlah kolom pasti (3/2/1), bukan kolom yang menyusut bebas. */
.grid-my-courses {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--jarak-kartu);
}

@media (min-width: 640px) {
  .grid-my-courses {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .grid-my-courses {
    grid-template-columns: repeat(3, 1fr);
  }
}

.kartu-course-dash {
  display: grid;
  align-content: start;
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-panel);
  overflow: hidden;
}

.kartu-course-dash-isi {
  display: grid;
  justify-items: start;
  gap: var(--ruang-2);
  padding: var(--ruang-5);
}

.kartu-course-dash-isi h2 {
  margin: 0;
  font-size: 1.0625rem;
}

.kartu-course-dash-isi h2 a {
  color: inherit;
  text-decoration: none;
}

.kartu-course-dash-isi h2 a:hover {
  color: var(--laut);
}

/* radius-badge, bukan radius-penuh: DESIGN.md membatasi pill (radius-penuh) hanya untuk tombol
   WA melayang dan avatar, supaya bentuk itu tetap terbaca sebagai obyek melayang, bukan motif
   yang diulang di mana-mana. */
.progress-materi {
  width: 100%;
  height: 6px;
  border-radius: var(--radius-badge);
  background: var(--garis);
  overflow: hidden;
}

.progress-materi-isi {
  height: 100%;
  background: var(--laut);
  border-radius: var(--radius-badge);
}

.progress-materi-teks {
  margin: 0;
  font-size: var(--ukuran-label);
  color: var(--tinta-2);
}

/* --- Area akun: tab Modul/Artikel /dashboard/course/[slug] (tahap 6d-2) --- */
.tab-dashboard {
  display: flex;
  gap: var(--ruang-5);
  border-bottom: 1px solid var(--garis);
}

.tab-dashboard a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--tinta-2);
  text-decoration: none;
  font-weight: var(--berat-label);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}

.tab-dashboard a[aria-current="page"] {
  color: var(--tinta);
  border-bottom-color: var(--laut);
}

/* --- Area akun: grid modul (Jalur Utama + Specialized), tahap 6d-2 --- */
.grid-modul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--jarak-kartu);
}

@media (min-width: 640px) {
  .grid-modul {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .grid-modul {
    grid-template-columns: repeat(3, 1fr);
  }
}

.kartu-modul {
  display: grid;
  align-content: start;
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-panel);
  overflow: hidden;
  color: inherit;
  text-decoration: none;
}

a.kartu-modul:hover h4 {
  color: var(--laut);
}

/* Redupkan hanya sampulnya (bukan opacity di seluruh kartu): teks judul dan keterangan kunci
   harus tetap kontras penuh (WCAG AA) - opacity di seluruh kartu pernah menurunkan label mono
   kecil (--tinta-2 14px) sampai ~3,5:1 terhadap panelnya sendiri, di bawah 4,5:1. */
.kartu-modul-terkunci .kartu-modul-sampul {
  opacity: 0.55;
}

.kartu-modul-sampul {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--garis);
}

.kartu-modul-sampul img,
.sampul-modul {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* radius-badge (bukan radius-penuh): lihat catatan di .progress-materi, sama-sama bukan tombol
   WA atau avatar. */
.kartu-modul-kunci {
  position: absolute;
  top: var(--ruang-2);
  right: var(--ruang-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-badge);
  background: color-mix(in srgb, var(--akun-latar) 70%, transparent);
  color: var(--tinta);
}

.kartu-modul-kunci .ikon {
  width: 16px;
  height: 16px;
}

.kartu-modul-isi {
  display: grid;
  justify-items: start;
  gap: var(--ruang-1);
  padding: var(--ruang-4);
}

.kartu-modul-isi h4 {
  margin: 0;
  font-size: 1rem;
}

/* Deskripsi modul: 2 baris, dipotong (DESIGN.md - kartu tidak boleh melar mengikuti isi). */
.kartu-modul-deskripsi {
  margin: 0;
  color: var(--tinta-2);
  font-size: 0.9375rem;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* --- Area akun: daftar materi dari sudut pandang siswa (tahap 6d-2) ---
   Beda dari .daftar-materi publik (Silabus.tsx, judul saja): baris ini juga bawa ikon tipe,
   durasi, dan status selesai per siswa. */
.daftar-materi-siswa {
  list-style: none;
  margin: 0;
  padding: 0 var(--ruang-5);
  max-width: var(--lebar-baca-maks);
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-panel);
}

.baris-materi-siswa {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--ruang-3);
  padding: var(--ruang-4) 0;
  border-bottom: 1px solid var(--garis);
}

.baris-materi-siswa:last-child {
  border-bottom: none;
}

.baris-materi-siswa-ikon {
  display: inline-flex;
  color: var(--tinta-2);
}

.baris-materi-siswa-judul {
  flex: 1 1 auto;
  min-width: 10rem;
}

.baris-materi-siswa-durasi {
  color: var(--tinta-2);
  font-size: var(--ukuran-label);
}

/* --- Area akun: hasil /dashboard/cari (tahap 6d-2), pola sama dengan daftar-materi --- */
.daftar-hasil-cari-materi {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--ruang-2);
}

.daftar-hasil-cari-materi a {
  display: grid;
  gap: 2px;
  padding: var(--ruang-4);
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-kartu);
  color: var(--tinta);
  text-decoration: none;
}

.daftar-hasil-cari-materi a:hover {
  border-color: var(--laut);
}

.daftar-hasil-cari-materi-judul {
  font-weight: var(--berat-heading);
}

/* Tautan balik ke daftar course: target 44px (DESIGN.md 8.9), tanpa panah hiasan. */
.tautan-kembali {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  justify-self: start;
}

/* --- Aksen emas, area course (tahap 6d-2b), DESIGN.md 9 "Aksen emas, area course" ---
   Tombol utama, progress bar, tab aktif, cincin fokus, hover judul kartu modul, link header,
   dan chip "Selesai" sudah ikut emas otomatis lewat token (tokens.css, blok
   :root[data-shell="dashboard"]). Bagian ini cuma yang butuh selector baru: label nomor
   modul (bukan .label netral biasa), border kartu (motif identitas satu-satunya, bukan
   --garis di semua tempat), dan efek "bohlam" (glow radial, hanya di dua titik ini). */

.label-modul-nomor {
  color: var(--emas-utama);
}

[data-shell="dashboard"] .kartu-course-dash,
[data-shell="dashboard"] .kartu-modul {
  border-color: var(--amber-redup);
}

/* Glow di belakang kartu modul saat hover: umpan balik tindakan (DESIGN.md 7), bukan gerak
   berulang. isolation: isolate supaya .kartu-modul jadi stacking context sendiri - tanpa ini
   latar solid --permukaan kartu ikut lapisan "in-flow" nenek moyang yang sama dengan ::before
   (z-index -1 lolos ke situ juga), jadi latar kartu menimpa glow-nya sendiri dan efeknya tidak
   pernah kelihatan. Dengan isolate, urutan lukis terkunci di dalam kartu ini saja. */
[data-shell="dashboard"] .kartu-modul {
  position: relative;
  isolation: isolate;
}

[data-shell="dashboard"] .kartu-modul::before {
  content: "";
  position: absolute;
  inset: -20px;
  z-index: -1;
  border-radius: var(--radius-panel);
  background: radial-gradient(circle at 50% 35%, var(--glow-emas), transparent 70%);
  opacity: 0;
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  [data-shell="dashboard"] .kartu-modul::before {
    transition: opacity var(--durasi-tombol) var(--easing-keluar);
  }
}

[data-shell="dashboard"] a.kartu-modul:hover::before {
  opacity: 1;
}

/* Glow di belakang judul halaman: dekorasi statis (bukan animasi masuk), jadi tidak melanggar
   MOTION 2 dan tidak butuh penanganan prefers-reduced-motion terpisah - sudah statis sejak
   render pertama. */
[data-shell="dashboard"] h1 {
  position: relative;
}

/* Hanya melebar ke kiri/atas/bawah: pusat ellipse di tepi kiri judul, dan -28px ke KANAN dulu
   (6d-2b) membuat halaman bisa digulir menyamping 12px di 375px karena h1 selebar kontainer. */
[data-shell="dashboard"] h1::before {
  content: "";
  position: absolute;
  inset: -16px 0 -16px -28px;
  z-index: -1;
  background: radial-gradient(ellipse 70% 100% at 0% 50%, var(--glow-emas), transparent 70%);
  pointer-events: none;
}

/* Daftar materi: satu panel, baris dipisah garis 1px; nomor mono dua digit sebagai motif
   baris angka (DESIGN.md 1), bukan lingkaran bernomor. */
.daftar-materi {
  list-style: none;
  margin: 0;
  padding: 0 var(--ruang-5);
  max-width: var(--lebar-baca-maks);
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-panel);
}

.daftar-materi li {
  display: flex;
  align-items: baseline;
  gap: var(--ruang-4);
  padding: var(--ruang-4) 0;
  border-bottom: 1px solid var(--garis);
}

.daftar-materi li:last-child {
  border-bottom: none;
}

.daftar-materi-no {
  flex-shrink: 0;
  color: var(--tinta-2);
}

/* Silabus course (/produk/[slug] dan /dashboard/course): judul track (h3) lalu modul (h4), tiap
   modul satu panel .daftar-materi. h4 hanya dipakai di sini, jadi ukurannya ditaruh di sini:
   ukuran body dengan berat heading, cukup untuk membedakan judul modul dari judul materi. */
.silabus-track + .silabus-track {
  margin-top: var(--ruang-7);
}

.silabus-modul {
  margin-top: var(--ruang-5);
}

.silabus-modul h4 {
  margin: 0;
  font-size: var(--ukuran-body);
  font-weight: var(--berat-heading);
  line-height: var(--tinggi-baris-heading);
  max-width: var(--lebar-baca-maks);
}

/* --- Admin: form produk (tahap 6a B1) --- */

.form-produk {
  max-width: 40rem;
}

.form-produk fieldset {
  display: grid;
  gap: var(--jarak-field);
  margin: 0;
  padding: var(--ruang-4);
  border: 1px solid var(--garis);
  border-radius: var(--radius-kartu);
  min-width: 0;
}

.form-produk fieldset[hidden] {
  display: none;
}

.form-produk legend {
  padding: 0 var(--ruang-2);
  font-weight: var(--berat-heading);
}

.field-bantuan {
  font-size: var(--ukuran-label);
  color: var(--tinta-2);
}

.field-dua {
  display: grid;
  gap: var(--jarak-field);
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
}

/* Kotak centang: label satu baris dengan kotaknya, seluruh baris 44px bisa diklik. */
.field-centang {
  display: flex;
  align-items: center;
  gap: var(--ruang-2);
  min-height: 44px;
  font-weight: var(--berat-label);
}

.field-centang input {
  width: 20px;
  height: 20px;
  accent-color: var(--laut);
}

.aksi-admin {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ruang-3);
}

.field select[aria-invalid="true"] {
  border-color: var(--galat);
}

.admin-lihat-situs {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* --- Admin: materi course (/admin/course, tahap 6d-1) ---
   Daftar berurutan memakai panel yang sama dengan .daftar-materi siswa (garis 1px, baris
   dipisah garis, nomor mono dua digit sebagai motif baris angka DESIGN.md 1), supaya urutan
   yang disusun admin terbaca sama dengan yang nanti dilihat siswa. Tanpa warna baru: aksen
   tetap --laut, tombol hapus memakai --galat yang sudah ada untuk galat. */

.daftar-urut {
  list-style: none;
  margin: 0;
  padding: 0 var(--ruang-4);
  max-width: 52rem;
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-panel);
}

.baris-urut {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ruang-2) var(--ruang-4);
  padding: var(--ruang-3) 0;
  border-bottom: 1px solid var(--garis);
}

.baris-urut:last-child {
  border-bottom: none;
}

.baris-urut:target {
  outline: 2px solid var(--laut);
  outline-offset: 2px;
}

/* Setinggi baris judul (44px) dan menempel ke atas, supaya nomor tetap sejajar judul saat
   tombol aksi membungkus ke baris berikutnya di layar sempit. */
.baris-urut-no {
  flex-shrink: 0;
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--tinta-2);
}

.baris-urut-isi {
  display: grid;
  gap: var(--ruang-1);
  flex: 1 1 14rem;
  min-width: 0;
}

.baris-urut-judul {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-weight: var(--berat-label);
  overflow-wrap: anywhere;
}

.baris-urut-aksi {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ruang-2);
}

.form-geser {
  display: contents;
}

/* Tombol di baris daftar: tetap 44px tinggi (DESIGN.md 8.9), padding samping lebih kecil supaya
   tiga tombol muat satu baris di 390px. */
.tombol-ringkas {
  min-width: 44px;
  padding: var(--ruang-2) var(--ruang-3);
}

.tombol-bahaya {
  color: var(--galat);
}

.tombol-bahaya:hover {
  border-color: var(--galat);
  color: var(--galat);
}

.status-materi {
  color: var(--tinta);
}

.status-materi-draf {
  color: var(--tinta-2);
}

.teks-putus {
  overflow-wrap: anywhere;
}

.zona-hapus {
  max-width: 40rem;
  padding-top: var(--ruang-5);
  border-top: 1px solid var(--garis);
}

.sampul-admin {
  display: grid;
  gap: var(--ruang-2);
  justify-items: start;
}

.sampul-admin img {
  width: 100%;
  max-width: 20rem;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border: 1px solid var(--garis);
  border-radius: var(--radius-badge);
  background: var(--garis);
}

.video-pratinjau {
  aspect-ratio: 16 / 9;
  max-width: 36rem;
  border: 1px solid var(--garis);
  border-radius: var(--radius-kartu);
  background: var(--kertas);
  overflow: hidden;
  display: grid;
  place-items: center;
}

.video-pratinjau iframe {
  width: 100%;
  height: 100%;
  border: 0;
}

.video-kosong {
  padding: var(--ruang-4);
  color: var(--tinta-2);
  font-size: var(--ukuran-label);
  text-align: center;
}

.form-materi {
  max-width: 48rem;
}

.md-editor-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--ruang-2);
}

.md-editor-mode {
  display: inline-flex;
  border: 1px solid var(--garis-kuat);
  border-radius: var(--radius-badge);
  overflow: hidden;
}

.md-editor-mode[hidden] {
  display: none;
}

.tombol-mode {
  min-height: 44px;
  min-width: 44px;
  padding: 0 var(--ruang-4);
  border: none;
  background: transparent;
  color: var(--tinta-2);
  font: inherit;
  font-size: var(--ukuran-label);
  font-weight: var(--berat-label);
  cursor: pointer;
}

.tombol-mode + .tombol-mode {
  border-left: 1px solid var(--garis-kuat);
}

.tombol-mode[aria-pressed="true"] {
  background: var(--laut);
  color: var(--teks-di-laut);
}

.tombol-mode:focus-visible {
  outline: 2px solid var(--laut);
  outline-offset: -4px;
}

.tombol-mode[aria-pressed="true"]:focus-visible {
  outline-color: var(--teks-di-laut);
}

/* Markdown ditulis sebagai kode: mono memudahkan membaca ##, **, dan indentasi daftar. */
.field textarea.mono-md {
  font-family: var(--font-mono);
  font-size: 0.9375rem;
  line-height: 1.6;
}

.md-pratinjau {
  min-height: 12rem;
  max-width: none;
  padding: var(--ruang-4);
  border: 1px solid var(--garis-kuat);
  border-radius: var(--radius-badge);
  background: var(--permukaan);
  overflow-wrap: anywhere;
}

.md-pratinjau > :first-child {
  margin-top: 0;
}

.md-pratinjau img {
  max-width: 100%;
  height: auto;
  border-radius: var(--radius-badge);
}

.md-pratinjau pre {
  overflow-x: auto;
}

.md-pratinjau-info {
  color: var(--tinta-2);
}

.md-pratinjau-galat {
  color: var(--galat);
}

.md-gambar {
  display: grid;
  gap: var(--ruang-3);
  margin-top: var(--ruang-2);
  padding: var(--ruang-4);
  border: 1px dashed var(--garis-kuat);
  border-radius: var(--radius-kartu);
}

.md-gambar[hidden] {
  display: none;
}

.md-gambar-judul {
  font-weight: var(--berat-label);
}

.md-gambar-status {
  font-size: var(--ukuran-label);
  color: var(--tinta-2);
}

/* ===================================================================================
   Dashboard siswa tahap 6d-3: menu lengkap, halaman materi, Artikel, Source, Akun.
   Semua warna dari token area akun + aksen emas (tokens.css, :root[data-shell="dashboard"]);
   tidak ada warna baru. DESIGN.md 9 "Shell dashboard".
   =================================================================================== */

/* --- Menu header (>= 640px) dan bottom nav (< 640px) --- */
.navbar-dashboard-menu {
  display: flex;
  gap: var(--ruang-5);
}

.akun-menu-daftar a {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--ruang-3);
  border-radius: var(--radius-badge);
  color: var(--tinta);
  font-size: 0.9375rem;
  text-decoration: none;
}

.akun-menu-daftar a:hover,
.akun-menu-daftar a[aria-current="page"] {
  background: var(--kertas);
  color: var(--laut);
}

/* Tiga tujuan (Course, Source, Akun; Artikel dicabut di 6e-kecil C), masing-masing ikon + teks
   (bukan ikon saja: artinya tidak ditebak). Tinggi
   64px + safe-area; isi halaman dan FAB WA diberi ruang sebesar itu supaya tidak tertutup. */
.nav-bawah-dashboard {
  display: none;
}

@media (max-width: 639px) {
  .navbar-dashboard-menu {
    display: none;
  }

  .nav-bawah-dashboard {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 40;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    background: var(--permukaan);
    border-top: 1px solid var(--garis);
  }

  .nav-bawah-dashboard a {
    display: grid;
    justify-items: center;
    align-content: center;
    gap: 2px;
    min-height: 64px;
    color: var(--tinta-2);
    font-size: var(--ukuran-label);
    text-decoration: none;
    border-top: 2px solid transparent;
    margin-top: -1px;
  }

  .nav-bawah-dashboard a[aria-current="page"] {
    color: var(--laut);
    border-top-color: var(--laut);
  }

  .nav-bawah-dashboard .ikon {
    width: 22px;
    height: 22px;
  }

  .nav-bawah-dashboard a:focus-visible {
    outline-offset: -4px;
  }

  [data-shell="dashboard"] body {
    padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px));
  }

  [data-shell="dashboard"] .fab-wa {
    bottom: calc(64px + 16px + env(safe-area-inset-bottom, 0px));
  }
}

/* --- Halaman materi /dashboard/course/[slug]/[materi] --- */
.materi-halaman {
  padding-top: var(--ruang-4);
  padding-bottom: var(--section-py);
}

.materi-atas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--ruang-2) var(--ruang-4);
  margin-bottom: var(--ruang-4);
}

/* Tombol laci hanya ada setelah materi.js siap (data-laci-siap), dan hanya < 1024px. Tanpa JS
   daftar materi tampil biasa di bawah konten, jadi tombol ini tidak diperlukan. */
.laci-pemicu {
  display: none;
}

@media (max-width: 1023px) {
  [data-laci-siap] .laci-pemicu {
    display: inline-flex;
  }
}

.materi-pesan {
  display: flex;
  align-items: flex-start;
  gap: var(--ruang-2);
  margin-bottom: var(--ruang-4);
  padding: var(--ruang-3) var(--ruang-4);
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-kartu);
}

.materi-pesan svg {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  color: var(--laut);
}

.materi-tata {
  display: grid;
  gap: var(--ruang-7);
}

/* Dua kolom mulai 1024px: konten + daftar materi 20rem yang menempel saat digulir. */
@media (min-width: 1024px) {
  .materi-tata {
    grid-template-columns: minmax(0, 1fr) 20rem;
    gap: var(--ruang-6);
    align-items: start;
  }

  .materi-samping-slot {
    position: sticky;
    top: calc(var(--tinggi-header) + var(--ruang-4));
    max-height: calc(100dvh - var(--tinggi-header) - var(--ruang-6));
    overflow-y: auto;
  }
}

.materi-utama {
  min-width: 0;
}

/* Video 16:9 selebar kolom konten; di ponsel sampai tepi layar (tanpa radius) supaya video
   tidak mengecil oleh padding halaman. */
.materi-video {
  aspect-ratio: 16 / 9;
  width: 100%;
  background: var(--akun-latar);
  border: 1px solid var(--garis);
  border-radius: var(--radius-panel);
  overflow: hidden;
}

.materi-video iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

@media (max-width: 639px) {
  .materi-video {
    width: auto;
    margin-inline: calc(-1 * var(--halaman-px));
    border-inline: 0;
    border-radius: 0;
  }
}

.materi-video-kosong {
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--ruang-2);
  padding: var(--ruang-4);
  text-align: center;
  border-style: dashed;
  border-color: var(--garis-kuat);
}

.materi-video-kosong .ikon {
  width: 40px;
  height: 40px;
  color: var(--tinta-2);
}

.materi-video-kosong p:first-of-type {
  font-weight: var(--berat-heading);
  font-size: 1.125rem;
}

.materi-judul-baris {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--ruang-3) var(--ruang-5);
  margin-top: var(--ruang-5);
}

.materi-judul-teks {
  display: grid;
  gap: var(--ruang-1);
  min-width: 0;
  flex: 1 1 20rem;
}

/* Judul materi = h1 halaman, tapi ukurannya selevel h3: titik fokus halaman ini video atau
   artikelnya, bukan judul. */
.materi-judul-teks h1 {
  font-size: var(--ukuran-h3);
  overflow-wrap: anywhere;
}

/* Glow bohlam judul (6d-2b) hanya untuk judul halaman besar (My Courses, halaman course, dan
   halaman menu); di judul materi yang kecil pendarnya terpotong jadi balok bertepi keras. */
.materi-judul-teks h1::before {
  content: none;
}

.materi-bagian {
  font-size: var(--ukuran-label);
  color: var(--tinta-2);
}

.materi-bagian span {
  color: var(--tinta);
}

.materi-chip-selesai {
  align-self: center;
}

.materi-akhir-artikel {
  align-items: center;
  padding-top: var(--ruang-5);
  border-top: 1px solid var(--garis);
}

/* Sebelumnya / Berikutnya: dua kolom, Berikutnya rata kanan (arah baca maju). Satu kolom di
   ponsel supaya judul materi panjang tidak terpotong. */
.materi-nav {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--ruang-3);
  margin-top: var(--ruang-5);
}

@media (min-width: 640px) {
  .materi-nav {
    grid-template-columns: 1fr 1fr;
  }

  .materi-nav-berikutnya,
  .materi-nav-terkunci {
    grid-column: 2;
    text-align: right;
  }

  .materi-nav-terkunci .catatan-ikon {
    justify-content: flex-end;
  }
}

.materi-nav-tautan {
  display: grid;
  gap: 2px;
  min-height: 44px;
  padding: var(--ruang-3) var(--ruang-4);
  border: 1px solid var(--garis);
  border-radius: var(--radius-kartu);
  color: var(--tinta);
  text-decoration: none;
}

a.materi-nav-tautan:hover {
  border-color: var(--laut);
}

a.materi-nav-tautan:hover .materi-nav-judul {
  color: var(--laut);
}

.materi-nav-judul {
  font-weight: var(--berat-label);
  overflow-wrap: anywhere;
}

.materi-nav-terkunci {
  border-style: dashed;
}

.materi-nav-terkunci .materi-nav-judul {
  color: var(--tinta-2);
  font-weight: var(--berat-body);
}

.materi-ringkasan {
  margin-top: var(--ruang-7);
}

.materi-ringkasan > h2 {
  font-size: var(--ukuran-h3);
  margin-bottom: var(--ruang-3);
}

/* Isi Markdown materi: kolom baca 68ch dari .artikel-isi, ditambah elemen yang hanya muncul di
   materi (kode, kutipan, tabel, gambar). Heading ber-id tidak tertutup header saat dilompati
   dari daftar isi. */
.materi-artikel {
  margin-top: var(--ruang-5);
}

.materi-utama .artikel-isi [id^="bagian-"] {
  scroll-margin-top: calc(var(--tinggi-header) + var(--ruang-4));
}

.materi-utama .artikel-isi > :first-child {
  margin-top: 0;
}

.materi-utama .artikel-isi img {
  max-width: 100%;
  height: auto;
  border-radius: var(--radius-kartu);
}

.materi-utama .artikel-isi pre {
  margin: 0 0 var(--ruang-4);
  padding: var(--ruang-4);
  overflow-x: auto;
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-kartu);
  font-size: 0.875rem;
}

.materi-utama .artikel-isi code {
  font-family: var(--font-mono);
  font-size: 0.9em;
}

.materi-utama .artikel-isi :not(pre) > code {
  padding: 1px 4px;
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-badge);
  overflow-wrap: anywhere;
}

.materi-utama .artikel-isi blockquote {
  margin: 0 0 var(--ruang-4);
  padding: var(--ruang-2) var(--ruang-4);
  border-left: 3px solid var(--garis-kuat);
  color: var(--tinta-2);
}

.materi-utama .artikel-isi table {
  display: block;
  max-width: 100%;
  overflow-x: auto;
  margin-bottom: var(--ruang-4);
  border-collapse: collapse;
}

.materi-utama .artikel-isi th,
.materi-utama .artikel-isi td {
  padding: var(--ruang-2) var(--ruang-3);
  border: 1px solid var(--garis);
  text-align: left;
}

.daftar-isi {
  max-width: var(--lebar-baca-maks);
  margin-top: var(--ruang-5);
  padding: var(--ruang-3) var(--ruang-4);
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-panel);
}

.daftar-isi-judul {
  font-size: var(--ukuran-label);
  font-weight: var(--berat-label);
  color: var(--tinta-2);
}

.daftar-isi ol {
  list-style: none;
  margin: var(--ruang-1) 0 0;
  padding: 0;
}

.daftar-isi a {
  display: flex;
  align-items: center;
  min-height: 44px;
  text-decoration: none;
}

.daftar-isi a:hover {
  text-decoration: underline;
}

.daftar-isi-sub a {
  padding-left: var(--ruang-4);
  font-size: 0.9375rem;
}

/* --- Tab Resources | About ---
   Tab bersegmen, bukan pill: DESIGN.md 6 membatasi --radius-penuh untuk tombol WA melayang dan
   avatar saja, jadi wadah memakai radius kartu dan tab aktif radius badge. */
.tab-materi {
  margin-top: var(--ruang-7);
}

.tab-materi-daftar {
  display: inline-flex;
  gap: var(--ruang-1);
  padding: var(--ruang-1);
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-kartu);
}

.tab-materi-daftar[hidden] {
  display: none;
}

.tab-materi-daftar [role="tab"] {
  min-height: 44px;
  padding: 0 var(--ruang-5);
  background: none;
  border: 0;
  border-radius: var(--radius-badge);
  color: var(--tinta-2);
  font-weight: var(--berat-label);
  cursor: pointer;
}

.tab-materi-daftar [role="tab"]:hover {
  color: var(--tinta);
}

.tab-materi-daftar [aria-selected="true"],
.tab-materi-daftar [aria-selected="true"]:hover {
  background: var(--laut);
  color: var(--teks-di-laut);
}

.tab-materi-panel {
  margin-top: var(--ruang-5);
}

.tab-materi-panel[hidden] {
  display: none;
}

.tab-materi-panel-judul {
  font-size: var(--ukuran-h3);
  margin-bottom: var(--ruang-4);
}

/* Setelah tab aktif, nama panel sudah dibacakan dari tab-nya; judul h2 tetap ada untuk pembaca
   layar (tanpa JS judul ini yang memisahkan kedua panel). */
.tab-materi[data-tab-aktif] .tab-materi-panel-judul {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

.grid-resource {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--jarak-kartu);
}

@media (min-width: 640px) {
  .grid-resource {
    grid-template-columns: 1fr 1fr;
  }
}

.kartu-resource {
  display: grid;
  align-content: start;
  justify-items: start;
  gap: var(--ruang-3);
  padding: var(--ruang-5);
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-panel);
}

.kartu-resource h3 {
  font-size: 1.0625rem;
}

.kartu-resource p {
  color: var(--tinta-2);
}

/* Tombol WhatsApp isi hijau: --wa adalah warna layanan pihak ketiga (DESIGN.md 2, 8.3), bukan
   aksen. Glif/teks gelap --wa-glif, sama dengan FAB (8,99:1). */
.tombol-wa-isi {
  background: var(--wa);
  border-color: var(--wa);
  color: var(--wa-glif);
}

.tombol-wa-isi:hover {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--wa) 35%, transparent);
}

.tombol-wa-isi svg {
  width: 20px;
  height: 20px;
}

.daftar-aset {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--ruang-1);
  justify-items: start;
}

.tautan-aset {
  display: inline-flex;
  align-items: center;
  gap: var(--ruang-2);
  min-height: 44px;
  overflow-wrap: anywhere;
}

.tautan-aset .ikon {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
}

.tools-kelas-judul {
  font-size: 1.0625rem;
}

.chip-tools {
  list-style: none;
  margin: var(--ruang-3) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--ruang-2);
}

.chip-tools a {
  display: inline-flex;
  align-items: center;
  gap: var(--ruang-2);
  min-height: 44px;
  padding: 0 var(--ruang-4);
  background: var(--permukaan);
  border: 1px solid var(--garis-kuat);
  border-radius: var(--radius-kartu);
  color: var(--tinta);
  text-decoration: none;
}

.chip-tools a:hover {
  border-color: var(--laut);
  color: var(--laut);
}

.chip-tools .ikon {
  width: 16px;
  height: 16px;
  color: var(--tinta-2);
}

/* --- Daftar materi samping (kolom kanan >= 1024px, laci < 1024px) --- */
.materi-samping {
  display: grid;
  gap: var(--ruang-1);
  padding: var(--ruang-4);
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-panel);
}

.materi-samping-judul {
  font-weight: var(--berat-heading);
  margin-bottom: var(--ruang-2);
}

.samping-modul + .samping-modul {
  border-top: 1px solid var(--garis);
}

.samping-modul summary {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 2px var(--ruang-2);
  align-items: center;
  min-height: 44px;
  padding: var(--ruang-3) 0;
  cursor: pointer;
  list-style: none;
}

.samping-modul summary::-webkit-details-marker {
  display: none;
}

/* Baris 1: label modul + hitungan/kunci. Baris 2: judul modul + chevron buka/tutup. */
.samping-modul summary > .label-modul-nomor {
  grid-area: 1 / 1;
}

.samping-modul-hitung {
  grid-area: 1 / 2;
  justify-self: end;
}

.samping-modul-judul {
  grid-area: 2 / 1;
  font-weight: var(--berat-label);
  overflow-wrap: anywhere;
}

.samping-modul-chevron {
  grid-area: 2 / 2;
  display: inline-flex;
  justify-self: end;
  color: var(--tinta-2);
}

@media (prefers-reduced-motion: no-preference) {
  .samping-modul-chevron .ikon {
    transition: transform var(--durasi-menu) var(--easing-keluar);
  }
}

.samping-modul[open] .samping-modul-chevron .ikon {
  transform: rotate(180deg);
}

.samping-materi {
  list-style: none;
  margin: 0 0 var(--ruang-3);
  padding: 0;
  display: grid;
  gap: 2px;
}

.samping-baris {
  display: flex;
  align-items: flex-start;
  gap: var(--ruang-2);
  min-height: 44px;
  padding: var(--ruang-2);
  border-radius: var(--radius-badge);
  color: var(--tinta);
  text-decoration: none;
  font-size: 0.9375rem;
}

a.samping-baris:hover {
  background: var(--kertas);
}

a.samping-baris[aria-current="page"] {
  background: color-mix(in srgb, var(--laut) 14%, var(--permukaan));
  color: var(--laut);
  font-weight: var(--berat-label);
}

.samping-baris-terkunci {
  color: var(--tinta-2);
}

.samping-ikon {
  display: inline-flex;
  flex-shrink: 0;
  margin-top: 2px;
  color: var(--tinta-2);
}

.samping-ikon svg {
  width: 18px;
  height: 18px;
}

.samping-ikon-selesai {
  color: var(--laut);
}

.samping-materi-judul {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* Laci: <dialog> modal menempel di kanan, setinggi layar. Tanpa animasi masuk (MOTION 1,
   DESIGN.md 7). Bayangan --lapis karena ini satu-satunya benda yang melayang di atas halaman. */
.laci-materi {
  margin: 0 0 0 auto;
  padding: 0;
  width: min(24rem, 88vw);
  height: 100dvh;
  max-height: 100dvh;
  max-width: 100vw;
  border: 0;
  border-left: 1px solid var(--garis);
  background: var(--kertas);
  color: var(--tinta);
  box-shadow: var(--lapis);
  overscroll-behavior: contain;
}

.laci-materi::backdrop {
  background: rgb(5 12 24 / 0.6);
}

.laci-materi-kepala {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ruang-3);
  padding: var(--ruang-2) var(--ruang-2) var(--ruang-2) var(--ruang-4);
  background: var(--kertas);
  border-bottom: 1px solid var(--garis);
}

.laci-materi-judul {
  font-weight: var(--berat-heading);
}

.laci-materi-tutup {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  background: none;
  border: 0;
  border-radius: var(--radius-badge);
  color: var(--tinta);
  cursor: pointer;
}

.laci-materi-tutup:hover {
  background: var(--permukaan);
}

.laci-materi .materi-samping {
  border: 0;
  border-radius: 0;
  background: transparent;
}

.laci-materi .materi-samping-judul {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

/* --- /dashboard/artikel: filter --- */
.filter-dashboard {
  display: grid;
  gap: var(--ruang-3);
  padding: var(--ruang-4);
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-panel);
}

@media (min-width: 640px) {
  .filter-dashboard {
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    align-items: end;
  }
}

.filter-dashboard-aksi {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ruang-2);
}

.daftar-hasil-cari-materi .chip-status {
  justify-self: start;
  margin-top: var(--ruang-1);
}

.baris-artikel-terkunci {
  display: grid;
  gap: 2px;
  padding: var(--ruang-4);
  background: var(--permukaan);
  border: 1px dashed var(--garis-kuat);
  border-radius: var(--radius-kartu);
  color: var(--tinta);
}

.baris-artikel-terkunci .catatan-ikon {
  margin-top: var(--ruang-1);
}

/* --- /dashboard/source --- */
.aset-course h3 {
  font-size: var(--ukuran-h3);
}

.daftar-aset-materi {
  list-style: none;
  padding: 0;
  display: grid;
  gap: var(--ruang-3);
}

@media (min-width: 1024px) {
  .daftar-aset-materi {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.aset-materi {
  display: grid;
  align-content: start;
  gap: var(--ruang-2);
  padding: var(--ruang-4);
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-kartu);
}

.aset-materi-judul {
  font-weight: var(--berat-heading);
  color: var(--tinta);
  overflow-wrap: anywhere;
}

a.aset-materi-judul {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  text-decoration: none;
}

a.aset-materi-judul:hover {
  color: var(--laut);
}

/* --- /dashboard/akun --- */
.akun-kotak {
  display: grid;
  justify-items: start;
  gap: var(--ruang-3);
  max-width: 40rem;
  padding: var(--ruang-5);
  background: var(--permukaan);
  border: 1px solid var(--garis);
  border-radius: var(--radius-panel);
}

.akun-email {
  font-size: var(--ukuran-lead);
  font-weight: var(--berat-label);
  overflow-wrap: anywhere;
}

.daftar-pesanan-akun {
  list-style: none;
  padding: 0;
  display: grid;
  gap: var(--ruang-4);
  max-width: 40rem;
}

/* Item grid default min-width: auto (lebar isi); tanpa ini kartu pesanan jebol 7px di 320px. */
.daftar-pesanan-akun > li {
  min-width: 0;
}

.daftar-pesanan-akun .harga-jual {
  overflow-wrap: anywhere;
}

.pesanan-item {
  list-style: none;
  padding: 0;
  display: grid;
  gap: var(--ruang-2);
}

/* --- Halaman /course, tahap 6e-A (landing dua paket course baru) ---
   Halaman dipasang dengan temaHalaman="gelap" (mekanisme "Halaman gelap penuh" yang sama
   dengan /ai, DESIGN.md 9), jadi --kertas dkk. di sini SUDAH navy gelap tanpa kelas baru.
   Aturan di bawah hanya menambah bagian yang /ai tidak punya: hero teks polos (bukan
   HeroGelap - halaman ini tidak ada di daftar hero berilustrasi DESIGN.md 5) dan pendar
   lembut di baliknya. */

.course-hero {
  padding-bottom: var(--ruang-4);
}

.course-hero-isi {
  position: relative;
  max-width: 42rem;
}

/* Pendar lembut ("glow lembut" diminta pemilik): perluasan motif --glow-emas yang sudah ada
   untuk identitas "area course" (DESIGN.md 9, "Aksen emas, area course" - dashboard course),
   dipakai lagi di sini karena halaman ini bagian dari identitas course yang sama, bukan warna
   baru. Statis (tanpa animasi), jadi tidak perlu penanganan prefers-reduced-motion. */
.course-hero-isi::before {
  content: "";
  position: absolute;
  top: -3rem;
  left: -4rem;
  width: 24rem;
  height: 24rem;
  background: radial-gradient(circle, var(--glow-emas), transparent 70%);
  pointer-events: none;
  z-index: -1;
}

.benefit-daftar {
  list-style: none;
  padding: 0;
  display: grid;
  gap: var(--ruang-3);
}

.benefit-daftar li {
  display: flex;
  align-items: flex-start;
  gap: var(--ruang-3);
}

.benefit-daftar svg {
  flex-shrink: 0;
  width: 1.25rem;
  height: 1.25rem;
  margin-top: 2px;
  color: var(--sukses);
}

.faq-daftar {
  display: grid;
  gap: var(--ruang-3);
  max-width: var(--lebar-baca-maks);
}

.faq-item {
  border: 1px solid var(--garis-kuat);
  border-radius: var(--radius-badge);
  background: var(--permukaan);
  padding: 0 var(--ruang-4);
}

.faq-item summary {
  min-height: 44px;
  display: flex;
  align-items: center;
  cursor: pointer;
  font-weight: var(--berat-label);
}

.faq-item p {
  padding-bottom: var(--ruang-4);
  color: var(--tinta-2);
}

.pesanan-item li {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--ruang-1) var(--ruang-4);
}

/* --- Kilau bintang logo, header /dashboard/* (tahap 6d-4, DESIGN.md 7) ---
   Lapisan SVG (KilauLogo.tsx) tepat di atas PNG logo, dicampur "screen" supaya hanya
   menerangi. Diam = opacity 0, jadi logo statis = logo asli (frame akhir animasi juga 0).
   Pemicu: kelas .menyala dipasang ui.js (sekali saat /dashboard dimuat, dan tiap hover/fokus),
   dilepas di animationend. Satu jam 1200ms untuk kedua aktor, pola 20/50/30; easing di dalam
   @keyframes ditulis literal (var() di sana diabaikan Chromium dan jatuh ke linear). */
.logo-kilau-wadah {
  position: relative;
  display: inline-flex;
  flex-shrink: 0;
}

.logo-kilau {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
  mix-blend-mode: screen;
}

.logo-kilau #kilau-pendar,
.logo-kilau #kilau-bintang {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}

.kilau-stop-terang {
  stop-color: var(--emas-terang);
}

.kilau-stop-emas {
  stop-color: var(--emas-utama);
  stop-opacity: 0.8;
}

.kilau-stop-kosong {
  stop-color: var(--emas-utama);
  stop-opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .logo-kilau {
    display: none;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .logo-kilau-wadah.menyala #kilau-pendar {
    animation: kilau-pendar 1200ms both;
  }

  .logo-kilau-wadah.menyala #kilau-bintang {
    animation: kilau-bintang 1200ms both;
  }
}

/* Pendar: muncul dari 0,6x (240ms, ease-out), membesar ke 1,15x di puncak (sampai 840ms),
   lalu meredup kembali ke 0 (360ms, ease-in-out). */
@keyframes kilau-pendar {
  0% {
    opacity: 0;
    transform: scale(0.6);
    animation-timing-function: cubic-bezier(0.33, 0, 0.2, 1); /* ease-out */
  }
  20% {
    opacity: 0.5;
    transform: scale(0.8);
    animation-timing-function: cubic-bezier(0.25, 0.6, 0.3, 1);
  }
  70% {
    opacity: 1;
    transform: scale(1.15);
    animation-timing-function: cubic-bezier(0.45, 0, 0.55, 1); /* ease-in-out */
  }
  100% {
    opacity: 0;
    transform: scale(1);
  }
}

/* Inti bintang: mulai 144ms setelah pendar (tidak serempak), puncak di 660ms lalu masih
   menyala sesaat (follow-through) sebelum ikut meredup. */
@keyframes kilau-bintang {
  0% {
    opacity: 0;
    transform: scale(1);
  }
  12% {
    opacity: 0;
    transform: scale(1);
    animation-timing-function: cubic-bezier(0.33, 0, 0.2, 1); /* ease-out */
  }
  55% {
    opacity: 0.8;
    transform: scale(1.06);
    animation-timing-function: cubic-bezier(0.3, 0, 0.3, 1);
  }
  78% {
    opacity: 0.6;
    transform: scale(1.03);
    animation-timing-function: cubic-bezier(0.45, 0, 0.55, 1); /* ease-in-out */
  }
  100% {
    opacity: 0;
    transform: scale(1);
  }
}
