/* ==========================================================================
   HeraBox - halaman perkenalan
   Arsitektur: Primitive -> Semantic -> Component
   Lihat DESIGN.md untuk alasan di balik setiap keputusan.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. FONT (self-hosted)
   Display : Cabinet Grotesk  - grotesque dengan terminal tertutup dan
                                lengkung yang tenang. Terasa seperti papan
                                nama bioskop, bukan seperti UI kit.
   Body    : Plus Jakarta Sans - variable 200-800. Dirancang Tokotype untuk
                                identitas kota Jakarta.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Cabinet Grotesk";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("asset/fonts/cabinet-grotesk-700.woff2") format("woff2");
}

@font-face {
  font-family: "Cabinet Grotesk";
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url("asset/fonts/cabinet-grotesk-800.woff2") format("woff2");
}

@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("asset/fonts/plus-jakarta-sans-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("asset/fonts/plus-jakarta-sans-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --------------------------------------------------------------------------
   2. RESET
   -------------------------------------------------------------------------- */

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

/* --------------------------------------------------------------------------
   3. TOKENS
   -------------------------------------------------------------------------- */

:root {
  /* --- Lapis 1: primitif --- */

  /* Permukaan, hue 288. Chroma naik seiring lightness. */
  --c-surface-deepest: #100e1c;
  --c-surface-sunken: #141224;
  --c-surface: #1d1b2f;
  --c-surface-raised: #262342;
  --c-surface-hover: #2f2b52;

  /* Aksen, hue 360. Satu warna, dipakai identik di seluruh halaman. */
  --c-accent: #ee4b8d;
  --c-accent-hover: #f76fa4;
  --c-accent-active: #d63a79;

  /* Teks, di-tint ke hue 288 bukan ke arah hangat. */
  --c-ink: #f2f1f7;
  --c-ink-muted: #c9c5d6;
  --c-ink-faint: #a9a4bd;

  /* Garis. Satu nilai, diturunkan lewat alpha. */
  --c-line-base: 255 255 255;

  /* --- Lapis 2: semantik --- */

  --surface-deepest: var(--c-surface-deepest);
  --surface-sunken: var(--c-surface-sunken);
  --surface: var(--c-surface);
  --surface-raised: var(--c-surface-raised);
  --surface-hover: var(--c-surface-hover);

  --accent: var(--c-accent);
  --accent-hover: var(--c-accent-hover);
  --accent-active: var(--c-accent-active);
  --on-accent: var(--c-surface-sunken);

  --ink: var(--c-ink);
  --ink-muted: var(--c-ink-muted);
  --ink-faint: var(--c-ink-faint);

  --line: rgb(var(--c-line-base) / 0.09);
  --line-strong: rgb(var(--c-line-base) / 0.16);

  --focus-ring: var(--accent);

  /* --- Spasi, skala 4/8 --- */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.25rem;
  --sp-6: 1.5rem;
  --sp-7: 2rem;
  --sp-8: 2.5rem;
  --sp-9: 3rem;
  --sp-10: 4rem;
  --sp-11: 5rem;
  --sp-12: 6rem;

  /* --- Radius, satu sistem dengan aturan --- */
  --r-pill: 999px;
  --r-lg: 16px;
  --r-md: 12px;
  --r-sm: 8px;

  /* --- Gerak --- */
  --dur-fast: 150ms;
  --dur-base: 240ms;
  --dur-slow: 420ms;
  --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
  --ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);

  /* --- Keluarga font --- */
  --font-display: "Cabinet Grotesk", "Plus Jakarta Sans", system-ui, sans-serif;
  --font-body: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI",
    sans-serif;

  /* --- Berat font --- */
  --fw-body: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;
  --fw-display: 800;

  /* --- Tata letak --- */
  --container: 1240px;
  --container-narrow: 820px;
  --gutter: clamp(20px, 5vw, 40px);
  --section-y: clamp(4.5rem, 3.5rem + 5vw, 7rem);
  --nav-h: 68px;

  /* --- Lapisan --- */
  --z-raised: 10;
  --z-sticky: 100;
  --z-drawer: 200;
  --z-grain: 400;

  /* --- Lapis 3: komponen --- */
  --btn-bg: var(--accent);
  --btn-ink: var(--on-accent);
  --btn-bg-hover: var(--accent-hover);
  --btn-bg-active: var(--accent-active);

  --nav-bg: rgb(29 27 47 / 0.72);
  --nav-bg-solid: var(--c-surface);

  --panel-bg: var(--surface-raised);
  --panel-border: var(--line);
}

/* --------------------------------------------------------------------------
   4. DASAR
   -------------------------------------------------------------------------- */

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + var(--sp-6));
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1.0625rem;
  font-weight: var(--fw-body);
  line-height: 1.7;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

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

a {
  color: inherit;
}

/* Judul memakai Cabinet Grotesk. Tracking mengencang seiring ukuran:
   makin besar teksnya, makin rapat optik yang dibutuhkan.
   Batas bawah yang diizinkan -0.04em; nilai di sini masih jauh di atasnya. */
h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  text-wrap: balance;
}

h1 {
  font-size: clamp(2.5rem, 1.6rem + 3.6vw, 4.25rem);
  line-height: 1.08;
  /* Cabinet Grotesk sudah rapat secara bawaan, jadi trackingnya
     dilonggarkan dari nilai sebelumnya supaya tidak terjepit. */
  letter-spacing: -0.022em;
}

h2 {
  font-size: clamp(1.75rem, 1.2rem + 2.2vw, 2.5rem);
  line-height: 1.15;
  letter-spacing: -0.018em;
  max-width: 22ch;
}

h3 {
  font-size: 1.375rem;
  line-height: 1.25;
  letter-spacing: -0.012em;
  /* Cabinet Grotesk hanya punya 700 dan 800. Di ukuran 22px, 800 terlihat
     terlalu tebal, jadi hierarki turun satu tingkat di sini. */
  font-weight: var(--fw-bold);
}

p {
  text-wrap: pretty;
}

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

/* Fokus terlihat di mana saja, tanpa kecuali. */
:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}

/* Grain: hanya pada lapisan tetap, pointer-events none. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: var(--z-grain);
  pointer-events: none;
  opacity: 0.026;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   5. UTILITAS
   -------------------------------------------------------------------------- */

.wrap {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.wrap.narrow {
  max-width: var(--container-narrow);
}

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

/* Section bawah dilewati browser sampai mendekati viewport: hemat layout
   dan paint di HP kelas menengah. Estimasi tinggi hanya untuk scrollbar
   awal; kata kunci auto mengingat ukuran aslinya setelah dirender sekali. */
.section,
.final {
  content-visibility: auto;
  contain-intrinsic-size: auto 900px;
}

/* Garis pemisah antar-section: satu garis cahaya di batas atas. Dasar
   statis terlihat di mana saja; animasi masuknya hanya di desktop supaya
   tangkapan layar penuh HP tidak kehilangan garis. */
.section {
  position: relative;
}

.section::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(
    90deg,
    transparent,
    rgb(238 75 141 / 0.35),
    transparent
  );
  opacity: 0;
  pointer-events: none;
}

@media (max-width: 620px) {
  .section::before {
    opacity: 1;
  }
}

.section.alt {
  background: var(--surface-sunken);
}

.lede {
  margin-top: var(--sp-5);
  font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.25rem);
  color: var(--ink-muted);
  max-width: 60ch;
}

.tiny {
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--ink-faint);
}

.skip-link {
  position: absolute;
  left: var(--sp-4);
  top: var(--sp-4);
  z-index: calc(var(--z-grain) + 1);
  padding: var(--sp-3) var(--sp-5);
  background: var(--accent);
  color: var(--on-accent);
  font-weight: var(--fw-semibold);
  text-decoration: none;
  border-radius: var(--r-sm);
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: translateY(0);
}

/* Reveal: konten terlihat secara default. Kelas .js hanya dipasang
   kalau IntersectionObserver benar-benar ada, jadi kalau JavaScript
   gagal, tidak ada yang tersembunyi.
   Dipakai properti translate, bukan transform, supaya tidak bentrok
   dengan transform yang sudah dipakai elemen lain. */
.js .reveal {
  opacity: 0;
  translate: 0 18px;
  transition: opacity var(--dur-slow) var(--ease-out-quint),
    translate var(--dur-slow) var(--ease-out-quint);
}

.js .reveal.is-in {
  opacity: 1;
  translate: none;
}

/* Elemen yang sudah punya transisi sendiri perlu daftarnya digabung,
   karena aturan reveal lebih spesifik dan akan menimpanya. */
.js details.reveal {
  transition: opacity var(--dur-slow) var(--ease-out-quint),
    translate var(--dur-slow) var(--ease-out-quint),
    border-color var(--dur-fast) var(--ease-out-quart);
}

/* Rak perangkat: masuk berurutan dari kiri.
   Sengaja TIDAK memakai animation-timeline: view(). .shelf punya
   overflow-x: auto, jadi ia sendiri adalah scroll container, dan view()
   di dalamnya akan mengukur sumbu gulir yang salah. Dipakai
   IntersectionObserver pada .shelf-wrap, yang bukan scroll container,
   dengan stagger lewat transition-delay. Ini juga berarti animasinya
   jalan di semua browser, bukan hanya yang mendukung scroll-driven. */
.js .shelf-wrap .device {
  opacity: 0;
  translate: 0 26px;
  transition: opacity var(--dur-slow) var(--ease-out-quint),
    translate var(--dur-slow) var(--ease-out-quint);
}

.js .shelf-wrap.is-in .device {
  opacity: 1;
  translate: none;
}

.js .shelf-wrap.is-in .device:nth-child(2) { transition-delay: 55ms; }
.js .shelf-wrap.is-in .device:nth-child(3) { transition-delay: 110ms; }
.js .shelf-wrap.is-in .device:nth-child(4) { transition-delay: 165ms; }
.js .shelf-wrap.is-in .device:nth-child(5) { transition-delay: 220ms; }
.js .shelf-wrap.is-in .device:nth-child(6) { transition-delay: 275ms; }
.js .shelf-wrap.is-in .device:nth-child(7) { transition-delay: 330ms; }

/* --------------------------------------------------------------------------
   6. TOMBOL
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  background: var(--btn-bg);
  color: var(--btn-ink);
  font-size: 1.0625rem;
  font-weight: var(--fw-semibold);
  line-height: 1;
  padding: 0.9rem 1.9rem;
  min-height: 48px;
  border: 0;
  border-radius: var(--r-pill);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out-quart),
    transform var(--dur-fast) var(--ease-out-quart);
}

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

.btn:active {
  background: var(--btn-bg-active);
  transform: scale(0.98);
}

.btn.big {
  font-size: 1.1875rem;
  padding: 1.15rem 2.5rem;
  min-height: 60px;
}

.textlink {
  font-size: 1.0625rem;
  font-weight: var(--fw-medium);
  color: var(--ink-muted);
  text-decoration: none;
  border-bottom: 1px solid var(--line-strong);
  padding-bottom: 2px;
  transition: color var(--dur-fast) var(--ease-out-quart),
    border-color var(--dur-fast) var(--ease-out-quart);
}

.textlink:hover {
  color: var(--ink);
  border-color: var(--accent);
}

/* --------------------------------------------------------------------------
   7. NAVIGASI
   -------------------------------------------------------------------------- */

.nav {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background: var(--nav-bg);
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  border-bottom: 1px solid var(--line);
}

.nav-in {
  display: flex;
  align-items: center;
  gap: var(--sp-6);
  min-height: var(--nav-h);
}

.brand {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: var(--fw-display);
  letter-spacing: -0.018em;
  text-decoration: none;
  flex-shrink: 0;
}

.brand span {
  color: var(--accent);
}

.links {
  display: flex;
  gap: var(--sp-6);
  margin-left: auto;
  font-size: 1rem;
  color: var(--ink-muted);
}

.links a {
  text-decoration: none;
  padding-block: var(--sp-2);
  border-bottom: 1px solid transparent;
  transition: color var(--dur-fast) var(--ease-out-quart),
    border-color var(--dur-fast) var(--ease-out-quart);
}

.links a:hover {
  color: var(--ink);
  border-bottom-color: var(--line-strong);
}

.links a[aria-current="true"] {
  color: var(--ink);
  border-bottom-color: var(--accent);
}

.nav-in > .btn {
  margin-left: 0;
}

/* Ajakan di dalam laci. Hanya tampil saat laci terbuka. */
.drawer-cta {
  display: none;
}

.nav-toggle {
  display: none;
  margin-left: auto;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  color: var(--ink);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out-quart),
    border-color var(--dur-fast) var(--ease-out-quart),
    transform var(--dur-fast) var(--ease-out-quart);
}

.nav-toggle:hover {
  background: var(--surface-raised);
}

.nav-toggle:active {
  transform: scale(0.94);
  background: var(--surface-hover);
}

.nav-toggle svg {
  width: 20px;
  height: 20px;
  stroke: currentColor;
  stroke-width: 1.75;
  fill: none;
  stroke-linecap: round;
  overflow: visible;
}

.nav-toggle path {
  transition: transform var(--dur-base) var(--ease-out-quart),
    opacity var(--dur-fast) var(--ease-out-quart);
  transform-origin: 12px 12px;
}

.nav-toggle[aria-expanded="true"] {
  background: var(--surface-raised);
  border-color: var(--accent);
  color: var(--accent);
}

.nav-toggle[aria-expanded="true"] path:nth-child(1) {
  transform: translateY(6px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] path:nth-child(2) {
  opacity: 0;
  transform: scaleX(0);
}

.nav-toggle[aria-expanded="true"] path:nth-child(3) {
  transform: translateY(-6px) rotate(-45deg);
}

/* --------------------------------------------------------------------------
   8. HERO
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  padding-block: clamp(3.5rem, 2.5rem + 4vw, 5.5rem);
  background: radial-gradient(
      900px 520px at 8% 18%,
      rgb(238 75 141 / 0.13),
      transparent 62%
    ),
    radial-gradient(700px 520px at 96% 88%, rgb(120 90 220 / 0.1), transparent 60%);
  overflow: hidden;
}

.hero-grid {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}

.hero-copy > * {
  animation: rise var(--dur-slow) var(--ease-out-expo) both;
}

.hero-copy > :nth-child(2) {
  animation-delay: 0.07s;
}

.hero-copy > :nth-child(3) {
  animation-delay: 0.14s;
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.hero h1 {
  max-width: 15ch;
}

.hero h1 em {
  font-style: normal;
  color: var(--accent);
}

.sub {
  margin-top: var(--sp-5);
  font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.25rem);
  color: var(--ink-muted);
  max-width: 42ch;
}

.cta-row {
  margin-top: var(--sp-8);
  display: flex;
  align-items: center;
  gap: var(--sp-6);
  flex-wrap: wrap;
}

.hero-shot {
  margin: 0;
  display: grid;
  justify-items: center;
  position: relative;
  /* Animasi masuk murni CSS, bukan lewat JS. Gambar ini elemen LCP,
     jadi hanya transform yang dianimasikan. Opacity tetap 1 sejak awal
     supaya LCP tidak tertunda menunggu fade selesai. */
  animation: rise-shot var(--dur-slow) var(--ease-out-expo) 0.08s both;
}

@keyframes rise-shot {
  from {
    transform: translateY(16px);
  }
  to {
    transform: none;
  }
}

/* Cahaya di belakang perangkat, bukan bayangan di depannya.
   Sengaja tanpa z-index negatif: itu akan jatuh ke belakang latar .hero
   dan warnanya ikut hilang. Dipakai urutan lukis biasa. */
.hero-shot::before {
  content: "";
  position: absolute;
  inset: 6% -14% 10%;
  background: radial-gradient(
    closest-side,
    rgb(238 75 141 / 0.2),
    transparent 72%
  );
  filter: blur(38px);
  pointer-events: none;
}

.hero-shot img {
  position: relative;
  height: clamp(400px, 60vh, 640px);
  width: auto;
  aspect-ratio: 722 / 1566;
  border-radius: 28px;
  border: 1px solid var(--line-strong);
  box-shadow: 0 6px 8px rgb(16 14 28 / 0.5),
    inset 0 1px 0 rgb(255 255 255 / 0.07);
  transform: perspective(1400px) rotateY(-7deg) rotateX(1.5deg);
  transform-origin: center right;
  /* Transisi opacity khusus untuk crossfade spotlight (JS). Properti
     terpisah dari translate/scale milik hero-exit, jadi tidak bentrok. */
  transition: opacity 550ms var(--ease-out-quart);
}

/* Caption teks polos yang duduk dekat perangkat. Hidupnya dari motion
   (masuk telat + ikut mengapung bersama figure), bukan dari dekorasi. */
.hero-shot figcaption {
  margin-top: var(--sp-3);
  font-size: 0.9375rem;
  color: var(--ink-muted);
  text-align: center;
  text-wrap: balance;
  max-width: 34ch;
  animation: chip-in var(--dur-slow) var(--ease-out-expo) 0.5s both;
}

@keyframes chip-in {
  from {
    opacity: 0;
    translate: 0 10px;
  }
}

/* --------------------------------------------------------------------------
   9. BAR FAKTA
   -------------------------------------------------------------------------- */

.factbar {
  border-block: 1px solid var(--line);
  background: var(--surface-sunken);
  padding-block: var(--sp-6);
}

.facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-5) var(--sp-9);
}

.facts > div {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.facts dt {
  font-size: 0.8125rem;
  font-weight: var(--fw-medium);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.facts dd {
  font-size: 1.0625rem;
  font-weight: var(--fw-medium);
  color: var(--ink);
}

/* --------------------------------------------------------------------------
   10. GALERI - RAK + FEATURED VIEWER

   Tujuh tangkapan layar semuanya 722x1566, rasio 0.461. Fakta ini yang
   menentukan bentuk galeri, bukan sebaliknya.

   Ada dua bentuk, dipilih lewat media query, bukan JavaScript:

   1. Perangkat sentuh dan layar kecil: rak yang digeser ke samping.
      Di sana tidak ada hover, jadi rel pilih tidak nyaman dipakai.
      Bentuk rak memakai garis langit: rata bawah, tinggi berbeda-beda.

   2. Desktop dengan kursor sungguhan: featured viewer. Satu screenshot
      tampil utuh di kiri, tujuh baris rel bernomor di kanan memilihnya.
      Tidak ada crop di mana pun, karena screenshot UI yang text-heavy
      hancur informasinya saat disempitkan jadi irisan.

   Keduanya mempertahankan rasio asli. Yang berubah hanya cara memilih
   layar mana yang dilihat penuh.
   -------------------------------------------------------------------------- */

.shelf-wrap {
  position: relative;
  margin-top: var(--sp-9);
}

/* Tepi kanan memudar: petunjuk bahwa masih ada perangkat di sebelahnya. */
.shelf-wrap::after {
  content: "";
  position: absolute;
  inset-block: 0;
  right: calc(var(--gutter) * -1);
  width: var(--gutter);
  background: linear-gradient(to right, transparent, var(--surface-sunken));
  pointer-events: none;
}

.shelf {
  display: flex;
  /* Rata bawah: perangkat berdiri di satu garis dasar. */
  align-items: flex-end;
  gap: var(--sp-5);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  padding-block: var(--sp-2) var(--sp-6);
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  /* Skala tinggi per breakpoint. Satu variabel, tidak perlu menulis
     ulang tujuh selector di setiap media query. */
  --h-scale: 1;
}

.shelf:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 6px;
}

.shelf::-webkit-scrollbar {
  height: 6px;
}

.shelf::-webkit-scrollbar-track {
  background: transparent;
}

.shelf::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border-radius: var(--r-pill);
}

.device {
  margin: 0;
  flex: 0 0 auto;
  scroll-snap-align: center;
  /* Kolom flex dengan konten didorong ke bawah. Dipakai bersama
     align-items: flex-end pada .shelf, ini yang membuat gambar berdiri
     di satu garis dasar. */
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

/* Lebar mengikuti tinggi lewat rasio asli 722:1566. Tidak ada crop. */
.device img {
  height: calc(var(--h-base) * var(--h-scale));
  width: auto;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface-raised);
  /* Angkat hover 240ms: animasi UI di atas 300ms terasa lemas. */
  transition: transform var(--dur-base) var(--ease-out-quint),
    border-color var(--dur-base) var(--ease-out-quart),
    box-shadow var(--dur-slow) var(--ease-out-quint);
}

/* Hover memakai transform pada gambar, sementara animasi gulir memakai
   translate pada pembungkus. Properti terpisah, jadi tidak saling menimpa.
   Angkatnya digerbangi hover di seksi 22; di sini hanya warna. */
.device:hover img {
  border-color: rgb(238 75 141 / 0.45);
  box-shadow: 0 20px 48px -16px rgb(238 75 141 / 0.32);
}

/* Tinggi caption DIKUNCI, bukan min-height.
   Kalau caption boleh tumbuh, caption yang panjangnya beda akan mendorong
   gambarnya naik, dan garis dasar rak jadi rusak. Dengan tinggi tetap,
   semua gambar duduk rata di garis yang sama.
   Lebar 20ch dipilih supaya ketujuh caption jatuh dalam dua baris. */
.device figcaption {
  margin-top: var(--sp-4);
  height: 2.9em;
  font-size: 0.9375rem;
  line-height: 1.45;
  color: var(--ink-muted);
  max-width: 20ch;
}

/* Garis langit: tidak ada dua tinggi yang berdampingan sama. Dua perangkat
   terluar lebih tinggi sebagai penanda, sisanya mengisi di antaranya. */
.device:nth-child(1) { --h-base: 540px; }
.device:nth-child(2) { --h-base: 428px; }
.device:nth-child(3) { --h-base: 496px; }
.device:nth-child(4) { --h-base: 404px; }
.device:nth-child(5) { --h-base: 472px; }
.device:nth-child(6) { --h-base: 440px; }
.device:nth-child(7) { --h-base: 520px; }

.shelf-nav {
  margin-top: var(--sp-4);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

.shelf-nav button {
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  color: var(--ink-muted);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out-quart),
    color var(--dur-fast) var(--ease-out-quart),
    border-color var(--dur-fast) var(--ease-out-quart);
}

.shelf-nav button:hover {
  background: var(--surface-raised);
  color: var(--ink);
  border-color: var(--accent);
}

.shelf-nav button:active {
  transform: scale(0.96);
}

.shelf-nav button svg {
  width: 18px;
  height: 18px;
  stroke: currentColor;
  stroke-width: 1.75;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.shelf-nav p {
  font-size: 0.9375rem;
  color: var(--ink-faint);
}

/* --------------------------------------------------------------------------
   10b. FEATURED VIEWER

   Hanya di perangkat dengan kursor sungguhan. Satu screenshot tampil utuh
   tanpa crop di viewer kiri, tujuh baris rel di kanan memilihnya. Pola ini
   menggantikan accordion: screenshot UI yang text-heavy hancur informasinya
   saat disempitkan jadi irisan 127px — teks kepotong di tengah kata dan
   tidak ada satu pun panel yang terbaca penuh sebelum di-hover.

   Seluruh aturan di sini digerbangi .js: viewer dibangun oleh JavaScript
   dari figure yang sudah ada (src sama, cache browser dipakai ulang, tidak
   ada unduhan ganda). Tanpa JavaScript ketujuh figure tetap tampil sebagai
   deretan kartu penuh yang bisa digeser, karena aturan rak dasar di atas
   tidak diubah.
   -------------------------------------------------------------------------- */

/* Viewer disembunyikan di mana saja sampai mode desktop memintanya. */
.viewer {
  display: none;
}

@media (hover: hover) and (pointer: fine) and (min-width: 861px) {
  .js .shelf-wrap {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: clamp(2rem, 4vw, 3.5rem);
    align-items: start;
  }

  /* Fade tepi kanan tidak berlaku: tidak ada yang perlu digeser. */
  .shelf-wrap::after,
  .shelf-nav {
    display: none;
  }

  /* Viewer: tinggi dikunci fluid, lebar mengikuti rasio asli 722:1566.
     Tidak ada crop di sini — itu inti perbaikan ini. */
  .js .viewer {
    display: block;
    position: sticky;
    top: calc(var(--nav-h) + var(--sp-8));
    justify-self: center;
    margin: 0;
    height: clamp(460px, 62vh, 620px);
    aspect-ratio: 722 / 1566;
    border-radius: var(--r-lg);
    border: 1px solid var(--line-strong);
    background: var(--surface-raised);
    overflow: hidden;
  }

  .viewer .v-stage {
    position: absolute;
    inset: 0;
  }

  .viewer .v-stage img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border: 0;
    border-radius: 0;
    transition: opacity var(--dur-base) var(--ease-out-quart);
  }

  .viewer .v-stage img.is-hidden {
    opacity: 0;
  }

  .viewer figcaption {
    position: absolute;
    inset-inline: 0;
    bottom: 0;
    margin: 0;
    height: auto;
    max-width: none;
    padding: var(--sp-9) var(--sp-5) var(--sp-5);
    background: linear-gradient(transparent, rgb(16 14 28 / 0.92));
    color: var(--ink);
    font-size: 1rem;
    pointer-events: none;
  }

  /* Penghitung kecil di sudut: posisi terbaca tanpa menutupi konten. */
  .viewer .v-count {
    position: absolute;
    top: var(--sp-4);
    right: var(--sp-4);
    padding: 0.3rem 0.8rem;
    font-size: 0.8125rem;
    font-weight: var(--fw-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--ink);
    background: rgb(16 14 28 / 0.72);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-pill);
    pointer-events: none;
  }

  /* Rel: daftar baris bernomor, satu pola dengan daftar kategori. */
  .js .shelf {
    display: grid;
    gap: var(--sp-2);
    overflow: visible;
    scroll-snap-type: none;
    padding-block: var(--sp-2) var(--sp-6);
    counter-reset: shot;
  }

  .js .device {
    display: grid;
    grid-template-columns: 52px minmax(0, 1fr);
    gap: var(--sp-4);
    align-items: center;
    padding: var(--sp-3) var(--sp-4);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    background: transparent;
    scroll-snap-align: none;
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-out-quart),
      border-color var(--dur-base) var(--ease-out-quart);
  }

  .js .device:hover {
    background: var(--surface-raised);
  }

  .js .device.is-active {
    background: var(--surface-raised);
    border-color: rgb(238 75 141 / 0.45);
  }

  .js .device img {
    height: 76px;
    width: auto;
    border-radius: var(--r-sm);
    transition: transform var(--dur-base) var(--ease-out-quint),
      border-color var(--dur-base) var(--ease-out-quart);
  }

  .js .device:hover img {
    transform: none;
    border-color: var(--line-strong);
    box-shadow: none;
  }

  .js .device.is-active img {
    transform: none;
    border-color: rgb(238 75 141 / 0.55);
    box-shadow: none;
  }

  /* Nomor urut + caption jadi satu baris info yang terbaca penuh. */
  .js .device figcaption {
    margin: 0;
    height: auto;
    max-width: none;
    font-size: 1rem;
    line-height: 1.5;
    color: var(--ink-muted);
  }

  .js .device figcaption::before {
    counter-increment: shot;
    content: "0" counter(shot);
    display: block;
    font-size: 0.8125rem;
    font-weight: var(--fw-semibold);
    letter-spacing: 0.06em;
    color: var(--ink-faint);
    font-variant-numeric: tabular-nums;
  }

  .js .device.is-active figcaption {
    color: var(--ink);
  }

  /* Cincin fokus untuk pengguna keyboard. Barisnya fokusabel, jadi
     pengguna keyboard bisa memilih lewat Tab + panah. */
  .js .device:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 3px;
  }

  /* Viewer ikut reveal bersama rel saat bagian masuk, plus skala halus
     sekali jalan sebagai momen signature bagian ini. */
  .js .viewer {
    opacity: 0;
    translate: 0 26px;
    scale: 0.97;
    transition: opacity var(--dur-slow) var(--ease-out-quint),
      translate var(--dur-slow) var(--ease-out-quint),
      scale var(--dur-slow) var(--ease-out-quint);
  }

  .js .shelf-wrap.is-in .viewer {
    opacity: 1;
    translate: none;
    scale: 1;
  }
}

/* --------------------------------------------------------------------------
   11. LANGKAH
   -------------------------------------------------------------------------- */

.cara-grid {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: clamp(2.5rem, 6vw, 5rem);
  align-items: center;
}

.steps {
  margin: var(--sp-8) 0 var(--sp-9);
  list-style: none;
  counter-reset: step;
}

.steps li {
  position: relative;
  padding-left: 4.25rem;
  padding-block: var(--sp-4);
}

.steps li::before {
  counter-increment: step;
  content: counter(step);
  position: absolute;
  left: 0;
  top: var(--sp-4);
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  color: var(--accent);
  font-size: 1rem;
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
}

/* Garis penghubung: memperlihatkan bahwa ini urutan, bukan daftar. */
.steps li:not(:last-child)::after {
  content: "";
  position: absolute;
  left: 21px;
  top: calc(var(--sp-4) + 48px);
  bottom: calc(var(--sp-4) * -1);
  width: 1px;
  background: linear-gradient(var(--line-strong), var(--line));
}

.steps h3 {
  font-size: 1.25rem;
}

.steps p {
  margin-top: var(--sp-2);
  font-size: 1rem;
  color: var(--ink-muted);
  max-width: 46ch;
}

.steps a {
  color: var(--ink);
  text-decoration-color: var(--line-strong);
  text-underline-offset: 3px;
}

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

.hero-shot.small img {
  height: clamp(360px, 52vh, 520px);
  transform: none;
}

/* --------------------------------------------------------------------------
   12. KATEGORI + PRATINJAU
   -------------------------------------------------------------------------- */

.cat-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 236px;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
  margin-top: var(--sp-9);
}

.catlist {
  border-top: 1px solid var(--line);
}

.catrow {
  display: flex;
  align-items: center;
  gap: var(--sp-6);
  padding: var(--sp-6) var(--sp-3);
  border-bottom: 1px solid var(--line);
  text-decoration: none;
  transition: background var(--dur-fast) var(--ease-out-quart);
}

.catrow:hover,
.catrow:focus-visible {
  background: var(--surface-raised);
}

.catrow h3 {
  font-size: 1.375rem;
}

.catrow p {
  margin-top: var(--sp-1);
  font-size: 0.9375rem;
  color: var(--ink-muted);
}

.catrow .go {
  margin-left: auto;
  flex-shrink: 0;
  color: var(--accent);
  transition: transform var(--dur-base) var(--ease-out-quart);
}

.catrow .go svg {
  width: 22px;
  height: 22px;
  stroke: currentColor;
  stroke-width: 1.75;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.catrow:focus-visible .go {
  transform: translateX(4px);
}

/* Pratinjau: dekorasi, jadi tidak dibacakan dan tidak wajib. */
.cat-preview {
  position: sticky;
  top: calc(var(--nav-h) + var(--sp-8));
  aspect-ratio: 722 / 1566;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--surface-raised);
}

.cat-preview img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-out-quart),
    transform var(--dur-base) var(--ease-out-quint);
  transform: scale(1.02);
}

.cat-preview img.is-on {
  opacity: 1;
}

/* --------------------------------------------------------------------------
   13. TABEL BANDING
   -------------------------------------------------------------------------- */

.compare {
  margin-top: var(--sp-9);
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 1.0625rem;
  font-variant-numeric: tabular-nums;
}

.compare caption {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.compare th,
.compare td {
  padding: var(--sp-5) var(--sp-6);
  text-align: left;
  vertical-align: baseline;
}

.compare thead th {
  font-size: 0.8125rem;
  font-weight: var(--fw-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  border-bottom: 1px solid var(--line-strong);
}

.compare tbody tr + tr th,
.compare tbody tr + tr td {
  border-top: 1px solid var(--line);
}

.compare tbody th {
  font-weight: var(--fw-medium);
  color: var(--ink-muted);
}

/* Kolom HeraBox ditandai latar, bukan hanya warna teks. */
.compare thead th:nth-child(2),
.compare td:nth-child(2) {
  background: rgb(238 75 141 / 0.07);
}

.compare thead th:nth-child(2) {
  color: var(--accent);
  border-top-left-radius: var(--r-md);
  border-top-right-radius: var(--r-md);
}

.compare tbody tr:last-child td:nth-child(2) {
  border-bottom-left-radius: var(--r-md);
  border-bottom-right-radius: var(--r-md);
}

.compare .yes {
  color: var(--ink);
  font-weight: var(--fw-medium);
}

.compare .no {
  color: var(--ink-faint);
}

/* --------------------------------------------------------------------------
   14. FAQ
   -------------------------------------------------------------------------- */

details {
  margin-top: var(--sp-4);
  background: var(--surface-raised);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--sp-5) var(--sp-6);
  transition: border-color var(--dur-fast) var(--ease-out-quart);
}

details:hover {
  border-color: var(--line-strong);
}

details[open] {
  border-color: var(--line-strong);
}

summary {
  font-size: 1.125rem;
  font-weight: var(--fw-semibold);
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--sp-4);
}

summary::-webkit-details-marker {
  display: none;
}

summary::after {
  content: "";
  margin-left: auto;
  flex-shrink: 0;
  width: 10px;
  height: 10px;
  border-right: 1.75px solid var(--accent);
  border-bottom: 1.75px solid var(--accent);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--dur-base) var(--ease-out-quart);
}

details[open] summary::after {
  transform: rotate(-135deg) translate(-3px, -3px);
}

details p {
  margin-top: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
  font-size: 1rem;
  color: var(--ink-muted);
  max-width: 64ch;
}

details a {
  color: var(--ink);
  text-decoration-color: var(--line-strong);
  text-underline-offset: 3px;
}

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

/* --------------------------------------------------------------------------
   15. AJAKAN AKHIR
   -------------------------------------------------------------------------- */

.final {
  padding-block: clamp(5rem, 4rem + 6vw, 8rem);
  background: radial-gradient(
    760px 420px at 50% 108%,
    rgb(238 75 141 / 0.16),
    transparent 66%
  );
  text-align: center;
}

.final h2 {
  margin-inline: auto;
  max-width: 20ch;
}

.final p {
  margin: var(--sp-5) auto 0;
  font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.25rem);
  color: var(--ink-muted);
  max-width: 48ch;
}

.final .btn {
  margin-top: var(--sp-8);
}

.final .tiny {
  margin-top: var(--sp-5);
}

/* --------------------------------------------------------------------------
   16. FOOTER
   -------------------------------------------------------------------------- */

footer {
  background: var(--surface-deepest);
  border-top: 1px solid var(--line);
  padding-block: var(--sp-10) var(--sp-8);
}

.foot {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-10);
  flex-wrap: wrap;
}

.foot .tiny {
  margin-top: var(--sp-4);
  max-width: 46ch;
}

.foot .tiny a {
  color: var(--ink-muted);
  text-decoration-color: var(--line-strong);
  text-underline-offset: 3px;
}

.foot .tiny a:hover {
  color: var(--ink);
  text-decoration-color: var(--accent);
}

.flinks {
  display: flex;
  gap: var(--sp-6);
  flex-wrap: wrap;
  align-content: flex-start;
}

.flinks a {
  font-size: 1rem;
  color: var(--ink-muted);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-out-quart);
}

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

.base {
  margin-top: var(--sp-10);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--line);
  max-width: none;
}

/* --------------------------------------------------------------------------
   17. RESPONSIF
   -------------------------------------------------------------------------- */

@media (max-width: 1000px) {
  .cat-grid {
    grid-template-columns: minmax(0, 1fr) 200px;
    gap: var(--sp-8);
  }
}

@media (max-width: 860px) {
  /* Navigasi jadi laci, tapi hanya kalau JavaScript tersedia.
     Tanpa JavaScript tautan tetap tampil dan membungkus. */
  .js .links {
    display: none;
    position: absolute;
    top: var(--nav-h);
    left: 0;
    right: 0;
    flex-direction: column;
    gap: 0;
    margin: 0;
    padding: var(--sp-3) var(--gutter) var(--sp-5);
    background: var(--nav-bg-solid);
    border-bottom: 1px solid var(--line-strong);
    box-shadow: 0 8px 8px rgb(16 14 28 / 0.4);
  }

  .js .links.is-open {
    display: flex;
  }

  .js .links a:not(.btn) {
    padding-block: var(--sp-4);
    border-bottom: 1px solid var(--line);
    font-size: 1.125rem;
  }

  /* Ajakan di laci dipisahkan garis rambut dari tautan di atasnya. */
  .js .drawer-cta {
    display: inline-flex;
    align-self: flex-start;
    margin-top: var(--sp-5);
  }

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

  .nav-in {
    gap: var(--sp-4);
  }

  /* Rak: skala tinggi diturunkan, tapi TIDAK sekecil yang bisa dilakukan.
     Perangkat tetap harus cukup besar supaya isi layarnya masih terbaca;
     itu alasan galeri ini ada. */
  .shelf {
    --h-scale: 0.86;
  }

  /* Tanpa JavaScript tautan membungkus. Nav dibiarkan tumbuh
     (min-height, bukan height), jadi tidak ada yang terpotong.
     Ajakan disembunyikan di sini karena baris nav tidak muat,
     tapi tetap terlihat besar di hero. */
  .links {
    flex-wrap: wrap;
    row-gap: 0;
  }

  .nav-in > .btn {
    display: none;
  }

  .hero-grid,
  .cara-grid,
  .cat-grid {
    grid-template-columns: 1fr;
  }

  .hero-shot img {
    transform: none;
    height: clamp(380px, 56vh, 520px);
  }

  .hero-shot::before {
    inset: 10% 12% 12%;
  }

  .hero-copy {
    max-width: 100%;
  }

  .cat-preview {
    display: none;
  }

  .foot {
    flex-direction: column;
    gap: var(--sp-8);
  }
}

@media (max-width: 620px) {
  /* Di HP perangkat justru dibesarkan, bukan dikecilkan. Layar HP sempit,
     jadi cara membuat isi screenshot terbaca adalah menampilkan perangkat
     besar dan membiarkan pengguna menggeser. Ini pola galeri app store. */
  .shelf {
    --h-scale: 0.92;
    gap: var(--sp-5);
  }

  /* Caption diberi ruang tiga baris, karena kolomnya lebih sempit. */
  .device figcaption {
    height: 4.35em;
    font-size: 0.875rem;
  }

  .facts {
    gap: var(--sp-4) var(--sp-7);
  }

  .facts > div {
    flex: 1 1 40%;
  }

  .compare {
    font-size: 0.9375rem;
  }

  .compare th,
  .compare td {
    padding: var(--sp-4);
  }

  .compare tbody th {
    width: 40%;
  }

  .cta-row {
    gap: var(--sp-4);
  }

  .cta-row .btn {
    width: 100%;
  }

  details {
    padding: var(--sp-5);
  }
}

/* --------------------------------------------------------------------------
   18. ANIMASI TERIKAT SCROLL

   Memakai CSS scroll-driven animations (animation-timeline). Ini berjalan
   di compositor, bukan di main thread, jadi tidak ada satu pun JavaScript
   yang jalan saat menggulir. window.addEventListener("scroll") dilarang.

   Semua di dalam @supports. Kalau browser belum mendukung (Firefox saat
   ini), tidak ada satu pun aturan di sini yang aktif dan halaman tampil
   normal tanpa animasi. Tidak ada konten yang disembunyikan.
   -------------------------------------------------------------------------- */

/* Bar kemajuan baca. Disembunyikan sampai terbukti didukung. */
.progress {
  display: none;
}

@supports (animation-timeline: scroll()) {
  .progress {
    display: block;
    position: fixed;
    inset-block-start: 0;
    inset-inline: 0;
    height: 2px;
    z-index: calc(var(--z-sticky) + 1);
    background: var(--accent);
    transform-origin: 0 50%;
    scale: 0 1;
    animation: progress-fill linear both;
    animation-timeline: scroll(root block);
    pointer-events: none;
  }

  @keyframes progress-fill {
    to {
      scale: 1 1;
    }
  }

  /* Navigasi mendapat bayangan begitu halaman mulai bergulir.
     Dipasang sebagai gradient di pseudo-elemen yang menggantung di bawah
     nav, bukan box-shadow. Dua alasan: box-shadow pada elemen seukuran nav
     bocor ke atas dan menutupi isinya, dan menganimasikan box-shadow
     memicu paint ulang setiap frame. Opacity tetap di compositor. */
  .nav::after {
    content: "";
    position: absolute;
    inset-inline: 0;
    top: 100%;
    height: 14px;
    pointer-events: none;
    background: linear-gradient(rgb(16 14 28 / 0.5), transparent);
    opacity: 0;
    animation: nav-lift linear both;
    animation-timeline: scroll(root block);
    animation-range: 0 140px;
  }

  @keyframes nav-lift {
    to {
      opacity: 1;
    }
  }
}

@supports (animation-timeline: view()) {

  /* --- Hero: gambar terangkat dan mengecil saat halaman digulir.
     Terikat posisi gulir, bukan pemicu sekali jalan, jadi pengguna
     bisa menggulir bolak-balik dan gerakannya mengikuti. --- */
  .hero-shot img {
    animation: hero-exit linear both;
    animation-timeline: scroll(root block);
    animation-range: 0 72vh;
  }

  @keyframes hero-exit {
    to {
      translate: 0 -7%;
      scale: 0.93;
    }
  }

  /* --- Bar fakta: enam spesifikasi masuk berurutan. --- */
  .facts > div {
    animation: rise-in linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 46%;
  }

  .facts > div:nth-child(2) { animation-range: entry 4% entry 50%; }
  .facts > div:nth-child(3) { animation-range: entry 8% entry 54%; }
  .facts > div:nth-child(4) { animation-range: entry 12% entry 58%; }
  .facts > div:nth-child(5) { animation-range: entry 16% entry 62%; }
  .facts > div:nth-child(6) { animation-range: entry 20% entry 66%; }

  @keyframes rise-in {
    from {
      opacity: 0;
      translate: 0 22px;
    }
  }

  /* --- Langkah: garis penghubung menggambar mengikuti gulir,
     lalu tiap langkah menyusul. Di sini urutan memang membawa
     informasi, jadi animasinya beralasan. --- */
  .steps li::after {
    transform-origin: 50% 0;
    animation: line-draw linear both;
    animation-timeline: view();
    animation-range: entry 25% entry 85%;
  }

  @keyframes line-draw {
    from {
      scale: 1 0;
    }
  }

  .steps li {
    animation: step-in linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 44%;
  }

  .steps li:nth-child(2) { animation-range: entry 8% entry 52%; }
  .steps li:nth-child(3) { animation-range: entry 16% entry 60%; }

  @keyframes step-in {
    from {
      opacity: 0;
      translate: -18px 0;
    }
  }

  /* --- Kategori: baris masuk dari kiri. --- */
  .catrow {
    animation: row-in linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 40%;
  }

  .catrow:nth-child(2) { animation-range: entry 4% entry 44%; }
  .catrow:nth-child(3) { animation-range: entry 8% entry 48%; }
  .catrow:nth-child(4) { animation-range: entry 12% entry 52%; }
  .catrow:nth-child(5) { animation-range: entry 16% entry 56%; }

  @keyframes row-in {
    from {
      opacity: 0;
      translate: -22px 0;
    }
  }

  /* --- Tabel: baris menyala berurutan. Tanpa offset tambahan,
     karena barisnya memang sudah masuk di posisi gulir yang berbeda. --- */
  .compare tbody tr {
    animation: tr-in linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 36%;
  }

  @keyframes tr-in {
    from {
      opacity: 0;
      translate: 0 14px;
    }
  }

  /* --- Pratinjau kategori: muncul dengan skala halus saat bagian masuk. --- */
  .cat-preview {
    animation: preview-in linear both;
    animation-timeline: view();
    animation-range: entry 10% entry 60%;
  }

  @keyframes preview-in {
    from {
      opacity: 0;
      scale: 0.95;
    }
  }
}

/* --------------------------------------------------------------------------
   19. PENYESUAIAN MOBILE

   Mobile bukan desktop yang diperkecil. Konten utama dipadatkan, target sentuh
   diperbesar, dan animasi scroll-driven yang menahan opacity dimatikan supaya
   halaman tetap terbaca saat dimuat atau diambil sebagai full-page preview.
   -------------------------------------------------------------------------- */

@media (max-width: 620px) {
  :root {
    --nav-h: 62px;
    --gutter: clamp(16px, 4.5vw, 24px);
    --section-y: clamp(3.5rem, 8vw, 4.75rem);
  }

  html {
    scroll-padding-top: calc(var(--nav-h) + env(safe-area-inset-top, 0px) + 0.75rem);
  }

  body {
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }

  .nav-in {
    min-height: calc(var(--nav-h) + env(safe-area-inset-top, 0px));
    padding-top: env(safe-area-inset-top, 0px);
    padding-inline: max(var(--gutter), env(safe-area-inset-left, 0px))
      max(var(--gutter), env(safe-area-inset-right, 0px));
  }

  .brand {
    font-size: 1.3125rem;
  }

  .nav-toggle {
    width: 44px;
    height: 44px;
  }

  /* Drawer bergerak ringan saat dibuka, tanpa mengubah fallback no-JS. */
  .js .links {
    display: flex;
    visibility: hidden;
    opacity: 0;
    translate: 0 -8px;
    pointer-events: none;
    top: calc(var(--nav-h) + env(safe-area-inset-top, 0px));
    padding-inline: max(var(--gutter), env(safe-area-inset-left, 0px))
      max(var(--gutter), env(safe-area-inset-right, 0px));
    padding-block: var(--sp-2) var(--sp-5);
    background: var(--nav-bg-solid);
    border-bottom: 1px solid var(--line-strong);
    box-shadow: 0 12px 32px -8px rgb(16 14 28 / 0.85);
    transition: opacity var(--dur-base) var(--ease-out-quart),
      translate var(--dur-base) var(--ease-out-quart),
      visibility 0s linear var(--dur-base);
  }

  .js .links.is-open {
    visibility: visible;
    opacity: 1;
    translate: none;
    pointer-events: auto;
    transition-delay: 0s;
  }

  .js .links a:not(.btn) {
    min-height: 50px;
    display: flex;
    align-items: center;
    font-size: 1.0625rem;
    color: var(--ink-muted);
    border-bottom: 1px solid var(--line);
    transition: color var(--dur-fast) var(--ease-out-quart);
  }

  .js .links a:not(.btn):active {
    color: var(--accent);
  }

  .js .drawer-cta {
    width: 100%;
    min-height: 50px;
    justify-content: center;
    margin-top: var(--sp-4);
    border-radius: var(--r-pill);
    box-shadow: 0 4px 16px rgb(238 75 141 / 0.35);
  }

  .hero {
    padding-block: clamp(2.5rem, 6.5vw, 3.25rem) clamp(3rem, 8vw, 4rem);
  }

  .hero-grid {
    gap: 1.75rem;
  }

  .hero h1 {
    max-width: 16ch;
    font-size: clamp(2.125rem, 8.5vw, 2.75rem);
    line-height: 1.12;
    letter-spacing: -0.025em;
  }

  .sub {
    margin-top: var(--sp-3);
    font-size: 1rem;
    line-height: 1.6;
    max-width: 38ch;
  }

  .cta-row {
    margin-top: var(--sp-6);
    align-items: stretch;
    gap: var(--sp-3);
  }

  .cta-row .btn.big {
    width: 100%;
    min-height: 52px;
    font-size: 1.0625rem;
    padding-inline: 1.25rem;
    border-radius: var(--r-pill);
    box-shadow: 0 4px 20px rgb(238 75 141 / 0.35);
  }

  .textlink {
    align-self: center;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    padding: var(--sp-2) var(--sp-4);
    font-size: 0.9375rem;
    letter-spacing: 0.02em;
  }

  .hero-shot::before {
    inset: 8% 14% 12%;
    filter: blur(28px);
    background: radial-gradient(
      closest-side,
      rgb(238 75 141 / 0.28),
      transparent 75%
    );
  }

  .hero-shot img {
    height: clamp(380px, 62vh, 460px);
    border-radius: 24px;
    border: 1px solid var(--line-strong);
    box-shadow: 0 20px 48px -16px rgb(16 14 28 / 0.7);
  }

  .hero-shot figcaption {
    font-size: 0.8125rem;
    margin-top: var(--sp-3);
    color: var(--ink-faint);
  }

  .factbar {
    padding-block: var(--sp-4);
  }

  .facts {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 var(--sp-5);
  }

  .facts > div {
    min-height: 60px;
    padding-block: var(--sp-3);
    border-top: 1px solid var(--line);
    justify-content: center;
  }

  .facts > div:nth-child(-n + 2) {
    border-top: 0;
  }

  .facts dt {
    font-size: 0.6875rem;
    letter-spacing: 0.08em;
    color: var(--ink-faint);
  }

  .facts dd {
    font-size: 1rem;
    line-height: 1.35;
    color: var(--ink);
  }

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

  .section h2 {
    font-size: clamp(1.625rem, 7vw, 2.125rem);
    line-height: 1.18;
    max-width: 20ch;
    letter-spacing: -0.02em;
  }

  .lede {
    margin-top: var(--sp-3);
    font-size: 1rem;
    line-height: 1.6;
    max-width: 36ch;
  }

  .shelf-wrap {
    margin-top: var(--sp-6);
  }

  .shelf {
    gap: 0;
    padding-block: 0 var(--sp-2);
    padding-inline: 0;
    scroll-padding-inline: 0;
    scroll-snap-type: x mandatory;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    touch-action: pan-x;
  }

  .shelf::-webkit-scrollbar {
    display: none;
  }

  .shelf-wrap::after {
    display: none;
  }

  /* Satu slide mengambil seluruh lebar rak di fallback carousel. */
  .device {
    flex: 0 0 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    scroll-snap-align: center;
  }

  .device img {
    height: clamp(380px, 62vh, 460px);
    width: auto;
    aspect-ratio: 722 / 1566;
    max-width: 100%;
    border-radius: 24px;
    border: 1px solid var(--line-strong);
    box-shadow: 0 20px 48px -16px rgb(16 14 28 / 0.65);
  }

  .device:hover img {
    transform: none;
    box-shadow: 0 20px 48px -16px rgb(16 14 28 / 0.65);
  }

  .device figcaption {
    margin-top: var(--sp-3);
    height: auto;
    min-height: 2.75em;
    font-size: 0.9375rem;
    line-height: 1.4;
    max-width: 28ch;
    text-align: center;
    color: var(--ink-muted);
  }

  .shelf-nav {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: nowrap;
    margin-top: var(--sp-3);
    gap: var(--sp-3);
  }

  .shelf-nav button[data-shelf] {
    width: 38px;
    height: 38px;
    border-radius: var(--r-pill);
    background: var(--surface-raised);
    border: 1px solid var(--line-strong);
    color: var(--ink);
    display: grid;
    place-items: center;
    cursor: pointer;
    flex-shrink: 0;
    transition: background var(--dur-fast) var(--ease-out-quart),
      border-color var(--dur-fast) var(--ease-out-quart),
      transform var(--dur-fast) var(--ease-out-quart);
  }

  .shelf-nav button[data-shelf]:active {
    background: var(--surface-hover);
    transform: scale(0.92);
  }

  .shelf-nav button[data-shelf] svg {
    width: 18px;
    height: 18px;
    stroke: currentColor;
    stroke-width: 2;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  .shelf-nav .dots {
    display: flex;
    align-items: center;
    gap: 4px;
    margin: 0;
  }

  .dots button {
    width: 22px;
    height: 36px;
    display: grid;
    place-items: center;
    background: transparent;
    border: 0;
    cursor: pointer;
    padding: 0;
  }

  .dots button::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: var(--r-pill);
    background: var(--line-strong);
    transition: width var(--dur-base) var(--ease-out-expo),
      background var(--dur-fast) var(--ease-out-quart),
      box-shadow var(--dur-fast) var(--ease-out-quart);
  }

  .dots button:active::before {
    transform: scale(1.3);
  }

  .dots button[aria-current="true"]::before {
    width: 18px;
    background: var(--accent);
    box-shadow: 0 0 10px rgb(238 75 141 / 0.5);
  }

  .shelf-nav .count {
    display: block;
    font-size: 0.8125rem;
    font-weight: var(--fw-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--ink-faint);
    background: var(--surface-raised);
    border: 1px solid var(--line);
    padding: 0.25rem 0.65rem;
    border-radius: var(--r-pill);
    margin: 0;
    flex: none;
  }

  .cara-grid {
    gap: var(--sp-7);
  }

  .steps {
    margin-block: var(--sp-6) var(--sp-6);
  }

  .steps li {
    padding-left: 3.5rem;
    padding-block: var(--sp-3);
  }

  .steps li::before {
    top: var(--sp-3);
    width: 40px;
    height: 40px;
    font-size: 0.9375rem;
  }

  .steps li:not(:last-child)::after {
    left: 19.5px;
    top: calc(var(--sp-3) + 40px);
    bottom: calc(var(--sp-3) * -1);
    width: 1px;
    background: linear-gradient(var(--line-strong), var(--line));
  }

  .steps h3 {
    font-size: 1.0625rem;
  }

  .steps p {
    font-size: 0.9375rem;
    line-height: 1.6;
  }

  .hero-shot.small {
    justify-self: center;
  }

  .hero-shot.small img {
    height: clamp(340px, 56vh, 420px);
    border-radius: 24px;
    border: 1px solid var(--line-strong);
    box-shadow: 0 16px 36px -12px rgb(16 14 28 / 0.6);
  }

  .cara-grid > div > .btn.big {
    width: 100%;
    min-height: 52px;
    border-radius: var(--r-pill);
  }

  .cat-grid {
    margin-top: var(--sp-6);
  }

  .catrow {
    min-height: 72px;
    gap: var(--sp-3);
    padding: var(--sp-4) var(--sp-3);
    border-radius: var(--r-md);
    margin-block: 2px;
    transition: background var(--dur-fast) var(--ease-out-quart),
      transform var(--dur-fast) var(--ease-out-quart);
  }

  .catrow:active {
    background: var(--surface-hover);
    transform: scale(0.99);
  }

  .catrow h3 {
    font-size: 1.0625rem;
  }

  .catrow p {
    font-size: 0.875rem;
    line-height: 1.45;
    margin-top: 3px;
  }

  .catrow .go {
    width: 36px;
    height: 36px;
    border-radius: var(--r-pill);
    background: rgb(238 75 141 / 0.08);
    display: grid;
    place-items: center;
    flex-shrink: 0;
    margin-right: 0;
    transition: transform var(--dur-base) var(--ease-out-quart),
      background var(--dur-fast) var(--ease-out-quart);
  }

  .catrow:active .go {
    background: rgb(238 75 141 / 0.18);
    transform: translateX(3px);
  }

  .catrow .go svg {
    width: 18px;
    height: 18px;
  }

  /* Perbandingan berubah menjadi kartu dua kolom per baris agar terbaca tanpa
     memaksa pengguna memperbesar atau menggulir tabel secara horizontal. */
  .compare {
    display: block;
    margin-top: var(--sp-6);
    font-size: 0.9375rem;
  }

  .compare thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .compare tbody {
    display: grid;
    gap: var(--sp-3);
  }

  .compare tbody tr {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-3);
    padding-block: var(--sp-4);
    border-top: 1px solid var(--line);
  }

  .compare tbody tr + tr th,
  .compare tbody tr + tr td {
    border-top: 0;
  }

  .compare tbody th {
    grid-column: 1 / -1;
    width: auto;
    padding: 0 0 var(--sp-1);
    font-size: 0.9375rem;
    font-family: var(--font-display);
    font-weight: var(--fw-semibold);
    color: var(--ink);
  }

  .compare tbody td {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: var(--sp-3) var(--sp-3);
    border-radius: var(--r-md);
  }

  .compare tbody td::before {
    content: attr(data-label);
    font-size: 0.6875rem;
    font-weight: var(--fw-semibold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  .compare tbody td:nth-child(2) {
    background: rgb(238 75 141 / 0.09);
    border: 1px solid rgb(238 75 141 / 0.22);
    border-radius: var(--r-md);
  }

  .compare tbody td:nth-child(2)::before {
    color: var(--accent);
  }

  .compare tbody td:nth-child(3) {
    background: var(--surface-deepest);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
  }

  .compare tbody td:nth-child(3)::before {
    color: var(--ink-faint);
  }

  .compare tbody tr:last-child td:nth-child(2) {
    border-radius: var(--r-md);
  }

  details {
    margin-top: var(--sp-3);
    padding: var(--sp-4) var(--sp-4);
    border-radius: var(--r-md);
    background: var(--surface-raised);
    border: 1px solid var(--line);
    transition: border-color var(--dur-fast) var(--ease-out-quart),
      background var(--dur-fast) var(--ease-out-quart);
  }

  details[open] {
    border-color: rgb(238 75 141 / 0.32);
    background: var(--surface-hover);
  }

  summary {
    min-height: 48px;
    font-size: 1rem;
    transition: color var(--dur-fast) var(--ease-out-quart);
  }

  summary:active {
    opacity: 0.85;
  }

  details p {
    margin-top: var(--sp-3);
    padding-top: var(--sp-3);
    font-size: 0.9375rem;
    line-height: 1.6;
  }

  .final {
    padding-block: clamp(4rem, 12vw, 5.5rem);
  }

  .final h2 {
    font-size: clamp(1.75rem, 8vw, 2.25rem);
  }

  .final p {
    font-size: 1rem;
    line-height: 1.6;
    margin-top: var(--sp-3);
  }

  .final .btn.big {
    width: 100%;
    min-height: 52px;
    font-size: 1.0625rem;
    border-radius: var(--r-pill);
    box-shadow: 0 4px 20px rgb(238 75 141 / 0.35);
  }

  footer {
    padding-block: var(--sp-8) var(--sp-6);
  }

  .foot {
    gap: var(--sp-6);
  }

  .flinks {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 var(--sp-4);
    width: 100%;
  }

  .flinks a {
    min-height: 44px;
    display: flex;
    align-items: center;
    font-size: 0.9375rem;
    color: var(--ink-muted);
    transition: color var(--dur-fast) var(--ease-out-quart);
  }

  .flinks a:active {
    color: var(--ink);
  }

  .base {
    margin-top: var(--sp-6);
    padding-top: var(--sp-4);
    border-top: 1px solid var(--line);
    font-size: 0.8125rem;
    line-height: 1.6;
    color: var(--ink-faint);
  }

  /* Pada layar kecil, hierarchy datang dari posisi dan warna. Semua konten
     tetap terlihat; motion dipertahankan untuk hero, drawer, rak, dan FAQ. */
  .facts > div,
  .steps li,
  .catrow,
  .compare tbody tr {
    animation: none !important;
    opacity: 1 !important;
    translate: none !important;
  }
}


/* --------------------------------------------------------------------------
   20. GALERI SCROLL-DRIVEN DI MOBILE

   Pada browser yang mendukung named view timeline, galeri menjadi satu stage
   vertikal: viewport tetap menempel, track bergerak horizontal mengikuti
   scroll halaman. Browser lain tetap mendapat carousel swipe biasa.
   -------------------------------------------------------------------------- */

@media (max-width: 620px) and (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view(block)) and
    (view-timeline-name: --gallery-scroll) {
    .shelf-wrap {
      height: 470vh;
      height: 560svh;
      view-timeline-name: --gallery-scroll;
      view-timeline-axis: block;
    }

    .shelf-viewport {
      position: sticky;
      top: calc(var(--nav-h) + env(safe-area-inset-top) + var(--sp-4));
      height: min(74svh, 580px);
      overflow: hidden;
      isolation: isolate;
      border-radius: var(--r-lg);
    }

    .shelf {
      position: relative;
      width: 100%;
      max-width: none;
      height: 100%;
      display: block;
      overflow: visible;
      scroll-snap-type: none;
      scrollbar-width: none;
    }

    /* Setiap layar menempati viewport yang sama. Crossfade dan depth motion
       menghindari momen ketika dua screenshot terlihat terpotong bersamaan.
       Caption disembunyikan di mode cinematic agar teks tidak bertumpuk
       selama perpindahan; caption tetap tersedia di fallback carousel. */
    .shelf .device {
      position: absolute;
      inset: 0;
      display: flex;
      flex: none;
      width: 100%;
      min-width: 0;
      height: 100%;
      justify-content: center;
      opacity: 0;
      animation: gallery-card-focus linear both;
      animation-timeline: --gallery-scroll;
    }

    /* Rentang dirapatkan (tumpang tindih 8%, bukan 14%): dua slide tidak
       lagi lama-lama setengah transparan bersamaan, jadi tidak ada momen
       "hantu" dobel di tengah transisi. */
    .shelf .device:nth-child(1) { animation-range: 0% 20%; }
    .shelf .device:nth-child(2) { animation-range: 12% 32%; }
    .shelf .device:nth-child(3) { animation-range: 26% 46%; }
    .shelf .device:nth-child(4) { animation-range: 40% 60%; }
    .shelf .device:nth-child(5) { animation-range: 54% 74%; }
    .shelf .device:nth-child(6) { animation-range: 68% 88%; }
    .shelf .device:nth-child(7) { animation-range: 82% 100%; }

    .shelf .device img {
      height: clamp(400px, 66vh, 480px);
      width: auto;
      aspect-ratio: 722 / 1566;
      border-radius: 24px;
      border: 1px solid var(--line-strong);
      box-shadow: 0 20px 48px -16px rgb(16 14 28 / 0.75);
    }

    .shelf .device figcaption {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      position: absolute;
      bottom: var(--sp-4);
      left: 50%;
      transform: translateX(-50%);
      margin: 0;
      height: auto;
      max-width: calc(100% - 2.5rem);
      padding: 0.45rem 1.15rem;
      background: rgb(16 14 28 / 0.88);
      backdrop-filter: blur(14px) saturate(140%);
      -webkit-backdrop-filter: blur(14px) saturate(140%);
      border: 1px solid var(--line-strong);
      border-radius: var(--r-pill);
      box-shadow: 0 8px 24px rgb(16 14 28 / 0.6);
      color: var(--ink);
      font-size: 0.8125rem;
      font-weight: var(--fw-medium);
      text-align: center;
      white-space: nowrap;
      pointer-events: none;
    }

    .shelf-nav {
      display: none;
    }

    @keyframes gallery-card-focus {
      0% {
        opacity: 0;
        translate: 0 26px;
        scale: 0.94;
      }
      24% {
        opacity: 1;
        translate: 0 0;
        scale: 1;
      }
      76% {
        opacity: 1;
        translate: 0 0;
        scale: 1;
      }
      100% {
        opacity: 0;
        translate: 0 -20px;
        scale: 1.035;
      }
    }
  }
}

@media (max-width: 620px) and (prefers-reduced-motion: reduce) {
  .shelf-wrap {
    height: auto !important;
  }

  .shelf-viewport {
    position: static;
    height: auto;
    overflow: visible;
  }

  .shelf {
    height: auto;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    animation: none !important;
    translate: none !important;
  }

  .shelf .device {
    flex: 0 0 100%;
    height: auto;
  }

  .shelf-nav {
    display: flex;
  }
}

/* --------------------------------------------------------------------------
   22. FEEL HIDUP — ambient, sheen, reveal bertingkat, delight
   -------------------------------------------------------------------------- */

/* Tombol: kilau lewat sekali saat hover, bukan loop tak berujung. */
.btn {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.btn::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    105deg,
    transparent 40%,
    rgb(255 255 255 / 0.28) 50%,
    transparent 60%
  );
  translate: -120% 0;
  transition: translate 600ms var(--ease-out-expo);
  pointer-events: none;
}

.btn:focus-visible::after {
  translate: 120% 0;
}

/* Tautan nav: garis bawah meluncur, bukan muncul tiba-tiba. */
.links a:not(.btn) {
  position: relative;
  border-bottom-color: transparent;
}

.links a:not(.btn)::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: var(--accent);
  scale: 0 1;
  transform-origin: 0 50%;
  transition: scale var(--dur-base) var(--ease-out-expo);
}

.links a:not(.btn):hover::after,
.links a[aria-current="true"]::after {
  scale: 1 1;
}

/* Reveal bertingkat: tiap kelompok punya jeda sendiri supaya tidak
   jatuh serentak seperti template. */
.js .section h2.reveal,
.js .section .lede.reveal,
.js .cara-grid > div.reveal,
.js .hero-shot.small.reveal,
.js .cat-grid.reveal,
.js .compare.reveal,
.js .final h2.reveal,
.js .final p.reveal,
.js .final .btn.reveal {
  transition-delay: 0s;
}

.js .section .lede.reveal { transition-delay: 70ms; }
.js .hero-shot.small.reveal { transition-delay: 110ms; }
.js .final p.reveal { transition-delay: 70ms; }
.js .final .btn.reveal { transition-delay: 140ms; }

/* Gerak hover hanya di kursor sungguhan: sentuh menembakkan hover palsu
   saat tap, jadi translate/geser dikunci di sini. Warna dan border tetap
   universal sebagai umpan balik tap. Focus-visible keyboard tidak digerbangi. */
@media (hover: hover) and (pointer: fine) {
  .btn:hover {
    transform: translateY(-1px);
  }

  .btn:hover::after {
    translate: 120% 0;
  }

  .device:hover img {
    transform: translateY(-8px);
  }

  .catrow:hover .go {
    transform: translateX(4px);
  }

  .catrow:hover::before {
    scale: 1 1;
  }
}

/* Baris kategori: penanda kiri tumbuh saat disorot. */
.catrow {
  position: relative;
}

.catrow::before {
  content: "";
  position: absolute;
  left: 0;
  top: var(--sp-4);
  bottom: var(--sp-4);
  width: 2px;
  border-radius: var(--r-pill);
  background: var(--accent);
  scale: 1 0;
  transition: scale var(--dur-base) var(--ease-out-expo);
}

.catrow:focus-visible::before {
  scale: 1 1;
}

/* Pratinjau kategori: naik halus + bingkai menyala saat bagian masuk. */
.cat-preview {
  transition: border-color var(--dur-base) var(--ease-out-quart),
    box-shadow var(--dur-slow) var(--ease-out-quint);
}

.cat-grid:hover .cat-preview {
  border-color: rgb(238 75 141 / 0.35);
  box-shadow: 0 8px 8px rgb(16 14 28 / 0.5);
}

.cat-preview img.is-on {
  transform: none;
}

/* Langkah: lingkaran angka menyala saat baris disorot. */
.steps li::before {
  transition: border-color var(--dur-fast) var(--ease-out-quart),
    background var(--dur-fast) var(--ease-out-quart),
    box-shadow var(--dur-base) var(--ease-out-quart);
}

.steps li:hover::before {
  border-color: rgb(238 75 141 / 0.55);
  box-shadow: 0 0 0 4px rgb(238 75 141 / 0.12);
}

/* Tabel: baris terangkat halus, kolom HeraBox tetap jadi jangkar. */
.compare tbody tr {
  transition: background var(--dur-fast) var(--ease-out-quart);
  border-radius: var(--r-sm);
}

.compare tbody tr:hover {
  background: rgb(255 255 255 / 0.025);
}

/* FAQ: isi meluncur masuk saat dibuka, ikon sudah berputar. */
details[open] > p {
  animation: faq-in var(--dur-base) var(--ease-out-quint) both;
}

@keyframes faq-in {
  from {
    opacity: 0;
    translate: 0 -6px;
  }
}

summary {
  transition: color var(--dur-fast) var(--ease-out-quart);
}

summary:hover {
  color: var(--ink);
}

/* Titik galeri + penghitung: hanya hidup di mode rak. */
.dots,
.count {
  display: none;
}

/* CTA menempel: khusus layar kecil, muncul lewat .is-show dari JS. */
.sticky-cta {
  display: none;
}

/* Gerak ambient: hanya tanpa reduced-motion, hanya compositor. */
@media (prefers-reduced-motion: no-preference) {
  /* Cahaya hero bernapas pelan. Area kecil, opacity saja. */
  .hero-shot::before {
    animation: glow-breathe 7s ease-in-out infinite alternate;
  }

  @keyframes glow-breathe {
    from {
      opacity: 0.75;
    }
    to {
      opacity: 1;
    }
  }

  /* Perangkat mengapung setelah masuk. Di pembungkus, bukan di img,
     supaya tidak bentrok dengan hero-exit yang terikat scroll.
     Digabung dengan rise-shot dalam satu shorthand supaya entrance
     tidak tertimpa. */
  .hero-shot {
    animation:
      rise-shot var(--dur-slow) var(--ease-out-expo) 0.08s both,
      float-soft 7s ease-in-out 1.2s infinite;
  }

  @keyframes float-soft {
    0%,
    100% {
      translate: 0 0;
      rotate: 0deg;
    }
    50% {
      translate: 0 -7px;
      rotate: -0.5deg;
    }
  }

  /* Keduanya digabung: masuk dulu, lalu mengapung. rise-shot tetap di img,
     float-soft di figure. Tidak ada konflik properti. */
}

@media (max-width: 860px) {
  .js .links.is-open a:not(.btn) {
    animation: drawer-in var(--dur-base) var(--ease-out-quint) both;
  }

  .js .links.is-open a:not(.btn):nth-child(2) { animation-delay: 45ms; }
  .js .links.is-open a:not(.btn):nth-child(3) { animation-delay: 90ms; }
  .js .links.is-open .drawer-cta { animation: drawer-in var(--dur-base) var(--ease-out-quint) 135ms both; }

  @keyframes drawer-in {
    from {
      opacity: 0;
      translate: 0 -6px;
    }
  }
}

@media (max-width: 620px) {
  /* CTA menempel bawah: kaca tipis + aman notch. */
  .sticky-cta {
    display: block;
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    z-index: var(--z-sticky);
    padding: var(--sp-3) var(--gutter) calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
    background: rgb(20 18 36 / 0.88);
    backdrop-filter: blur(16px) saturate(160%);
    -webkit-backdrop-filter: blur(16px) saturate(160%);
    border-top: 1px solid var(--line-strong);
    box-shadow: 0 -8px 24px rgb(16 14 28 / 0.6);
    translate: 0 110%;
    transition: translate var(--dur-base) var(--ease-out-quint);
    pointer-events: none;
  }

  .sticky-cta.is-show {
    translate: none;
    pointer-events: auto;
  }

  .sticky-cta .btn {
    width: 100%;
    min-height: 50px;
    font-size: 1rem;
    border-radius: var(--r-pill);
    box-shadow: 0 4px 16px rgb(238 75 141 / 0.4);
  }

  body:has(.sticky-cta.is-show) footer {
    padding-bottom: calc(92px + env(safe-area-inset-bottom, 0px));
  }
}

/* Penyesuaian khusus layar ultra-kecil (<= 360px) seperti ponsel lipat & layar kompak */
@media (max-width: 360px) {
  :root {
    --gutter: 14px;
  }

  .hero h1 {
    font-size: 1.875rem;
  }

  .section h2 {
    font-size: 1.4375rem;
  }

  .steps li {
    padding-left: 2.85rem;
  }

  .steps li::before {
    width: 34px;
    height: 34px;
    font-size: 0.8125rem;
  }

  .steps li:not(:last-child)::after {
    left: 16.5px;
    top: calc(var(--sp-3) + 34px);
  }

  .device img {
    height: clamp(320px, 92vw, 360px);
  }

  .compare tbody tr {
    grid-template-columns: 1fr;
    gap: var(--sp-2);
  }
}

/* Rel memakai grid biasa; tidak ada properti layout yang dianimasikan
   di sini, jadi tidak perlu will-change. */
@media (hover: hover) and (pointer: fine) and (min-width: 861px) {
  .js .shelf-wrap {
    contain: layout;
  }
}

@supports (animation-timeline: view()) {
  @media (min-width: 621px) {
    /* Copy melayang turun + memudar sementara gambar terangkat: dua
       kecepatan berlawanan memberi kedalaman tanpa satu pun JavaScript.
       Elemen berbeda dari animasi entrance (hero-copy > *), jadi tidak
       ada konflik properti. */
    .hero-copy {
      animation: hero-copy-drift linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 70vh;
    }

    @keyframes hero-copy-drift {
      to {
        translate: 0 6%;
        opacity: 0.2;
      }
    }

    /* Judul + lede masuk halus di desktop. Di HP dimatikan (aturan mobile
       yang sudah ada) dan diganti reveal IO supaya tangkapan layar penuh
       tidak kosong. */
    .section h2 {
      animation: rise-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 42%;
    }

    .section .lede {
      animation: rise-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 36%;
    }

    .hero-shot.small {
      animation: preview-in linear both;
      animation-timeline: view();
      animation-range: entry 10% entry 55%;
    }

    .final h2 {
      animation: rise-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 50%;
    }

    /* Garis pemisah menyala mengikuti posisi gulir bagian. */
    .section::before {
      opacity: 1;
      animation: divider-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 35%;
    }

    @keyframes divider-in {
      from {
        opacity: 0;
      }
    }
  }

  /* Hero di HP jauh lebih tinggi (copy + perangkat menumpuk vertikal),
     jadi rentang keluarnya diperpanjang mengikuti tinggi aktual. Baris
     vh ditulis dulu sebagai fallback jika svh tidak didukung. */
  @media (max-width: 620px) {
    .hero-shot img {
      animation-range: 0 100vh;
      animation-range: 0 100svh;
    }
  }
}

/* --------------------------------------------------------------------------
   21. GERAK BERKURANG
   -------------------------------------------------------------------------- */

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

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

  .hero-copy > * {
    animation: none;
    opacity: 1;
    transform: none;
  }

  .hero-shot {
    animation: none;
  }

  .hero-shot figcaption {
    animation: none;
  }

  .hero-shot::before,
  details[open] > p,
  .js .links.is-open a {
    animation: none !important;
  }

  .btn::after {
    display: none;
  }

  .sticky-cta {
    translate: none !important;
  }

  .js .reveal {
    opacity: 1;
    translate: none;
  }

  .js .shelf-wrap .device {
    opacity: 1;
    translate: none;
  }

  .js .viewer {
    opacity: 1;
    translate: none;
    scale: none;
  }

  /* Semua animasi terikat scroll dimatikan sepenuhnya, bukan
     dipercepat. Tanpa ini, animation-duration 0.01ms akan memaksa
     semuanya langsung ke keadaan akhir, yang bisa terlihat melompat. */
  .progress,
  .nav::after,
  .hero-shot img,
  .hero-copy,
  .facts > div,
  .steps li,
  .steps li::after,
  .catrow,
  .cat-preview,
  .compare tbody tr,
  .section h2,
  .section .lede,
  .section::before,
  .hero-shot.small,
  .final h2 {
    animation: none !important;
    opacity: 1 !important;
    translate: none !important;
    scale: none !important;
  }

  .progress {
    display: none !important;
  }

  .hero-shot img {
    transform: none;
  }

  .btn:hover,
  .catrow:hover .go,
  .catrow:focus-visible .go {
    transform: none;
  }
}

/* Transparansi dikurangi: kaca diganti warna solid. */
@media (prefers-reduced-transparency: reduce) {
  .nav {
    background: var(--nav-bg-solid);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  .sticky-cta {
    background: var(--nav-bg-solid);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  body::after {
    display: none;
  }
}
