/* nd-hero.css — KARTU HERO POLA NETFLIX di beranda.

   Permintaan pemilik (13 Okt 2026): "slider home nya jangan diblur gitu, ikuti
   persis pola netflix; teks meta data gak boleh bentrok sama gambar poster
   pewarnaannya; poster kita pasti portrait, untuk mode desktop bagi 2 sampai 3
   film per slider sesuai lebar layar user".

   EMPAT keputusan yang membentuk seluruh berkas ini:

   1. TANPA BLUR. Desain lama memuat poster yang SAMA dua kali — satu tajam di
      depan, satu diperbesar + diblur sebagai latar. Sekarang satu kartu = satu
      gambar: karya posternya sendiri yang MENJADI isi kartu, bukan jadi bidang
      warna. Chip tag lama (rgba putih + backdrop-filter blur 6px) juga hilang:
      itu blur kedua, dan kontrasnya ikut warna poster.

   2. KETERBACAAN DIJAMIN GEOMETRI, bukan untung-untungan. Gradien gelap adalah
      BACKGROUND milik .nd-hero-pane, dan titik berhenti .94-nya dipaku ke
      PANJANG YANG SAMA dengan padding-block-start panel (--nd-hero-ramp).
      Akibatnya: setinggi apa pun teks tumbuh — judul 2 baris, sinopsis 2 baris,
      baris fakta yang membungkus, label tombol panjang di bahasa lain, pengguna
      yang membesarkan font peramban — SELURUH teks tetap berdiri di atas alpha
      >= .94, dan ramp selebar 19% LEBAR KARTU selalu ikut naik di atasnya.
      Titik berhenti PERSEN tidak punya jaminan itu: begitu teks bertambah
      tinggi, baris pertamanya melayang ke zona tembus pandang.

   3. SATUAN cqi, BUKAN rem, untuk seluruh komposisi di dalam kartu. Ini yang
      membuat poin 2 tidak bisa dirusak: ramp, padding, ukuran huruf, dan tinggi
      tombol semuanya persen dari LEBAR KARTU, jadi pelat gelap memakan fraksi
      kartu yang SAMA di kartu 271px (HP 320) maupun 475px (desktop 1920) —
      terukur 48-56% tinggi kartu untuk kartu pertama, dan maksimum 66% untuk
      kartu berteks terpanjang (Thai/Tamil) — fraksi yang sama di tiap ukuran.
      Kalau ini ditulis rem, fraksinya ikut berubah tiap breakpoint DAN meledak
      saat pengguna menyetel font peramban ke 20px. Token rem tetap dipakai
      sebagai LANTAI & ATAP clamp() supaya tipografi tidak pernah keluar dari
      skala situs. WebView tua yang
      belum kenal cqi memakai nilai rem di luar blok @supports — satu-satunya
      syaratnya: padding dan titik gradien memakai variabel YANG SAMA, jadi
      jaminan poin 2 tetap utuh di kedua dunia.

   4. PORTRAIT, SELALU — DAN MAKSIMAL 3. Kartu 2/3 dengan lebar DIBATASI
      --nd-hero-cap. Tanpa batas itu, 3 kolom di layar 1920 full-bleed jadi
      kartu 580x870: panel raksasa, bukan kartu, dan hero menelan 80% layar
      pertama. Dengan batas itu, kelebihan ruang di layar sangat lebar jadi
      MARGIN (rel-nya memusat), BUKAN kartu keempat yang mengintip — pemilik
      minta 2 sampai 3 film, bukan 3 setengah. Lihat catatan di .nd-hero-view
      untuk aritmatikanya. */

body.nd-ui .nd-hero {
  /* ---- GEOMETRI: satu-satunya tempat angka kolom hidup ---- */
  --nd-hero-cols: 1;
  /* Sisa ruang supaya kartu BERIKUTNYA mengintip di layar 1 kolom. Tanpa ini,
     gutter 16px di HP cuma menyisakan sliver 4px yang terlihat seperti bug
     render, bukan seperti undangan untuk menggeser. Persen, bukan rem. */
  --nd-hero-peek: 6%;
  --nd-hero-gap: var(--nd-sp-3);
  /* Atap lebar kartu. Di 1 kolom atapnya SENGAJA longgar: kartu yang mengisi
     hampir seluruh lebar layar memang bentuk yang pemilik kirimkan di
     screenshot, dan di SEMUA HP nyata (320-430px) yang mengikat adalah rumus
     persen, bukan atap ini — sudah diukur. Atap ini baru bekerja di jendela
     peramban selebar ~450-639px, tempat satu kartu portrait tanpa atap akan
     jadi 552x829 dan menelan 92% layar pertama.
     52vh dipakai, bukan dvh/svh: nilai vh di HP mengacu ke viewport BESAR dan
     tidak berubah saat bilah alamat menyusut, jadi menggulir halaman tidak
     pernah memicu reflow hero DAN atap ini tidak pernah mengecilkan kartu HP. */
  --nd-hero-cap: min(26rem, 52vh);

  position: relative;
  /* Full-bleed: keluar dari gutter induk supaya menyentuh tepi layar. */
  margin-inline: calc(var(--nd-gutter-x, 1rem) * -1);
  margin-block-end: var(--nd-sp-8);
  isolation: isolate;
}

/* DUA kolom. Ambangnya ditentukan ukuran KARTU, bukan nama perangkat: di bawah
   640px kartu kedua jadi lebih sempit dari ~288px, dan di bawah itu dua pil
   bertumpuk + sinopsis 2 baris berhenti terbaca.
   Di sinilah atap tinggi kartu mulai berlaku:
     max(17rem, min(46vh, 28rem + 4vw))
   - 46vh menjaga tinggi kartu (= lebar x 1.5) tidak lebih dari 69vh, supaya 24
     kartu SSR di bawah hero tidak terkubur di luar layar pertama. Itu aset
     pencarian, bukan hiasan.
   - 28rem + 4vw adalah atap kedua untuk layar TINGGI: tanpa itu, 46vh di
     monitor 1440p membuat kartu 662px dan hero 993px.
   - max(17rem, ...) adalah LANTAI untuk layar lebar-tapi-pendek (HP lanskap,
     ultrawide 1080): tanpa lantai, 46vh dari 390px tinggi = kartu 179px dan
     seluruh komposisi di dalam kartu mengecil sampai tak terbaca.
   vh (BUKAN dvh/svh) disengaja: nilainya tidak berubah saat bilah alamat HP
   menyusut, jadi menggulir halaman tidak pernah memicu reflow hero. */
@media (min-width: 640px) {
  body.nd-ui .nd-hero {
    --nd-hero-cols: 2;
    --nd-hero-peek: 0px;
    --nd-hero-cap: max(17rem, min(46vh, 28rem + 4vw));
  }
}
/* TIGA kolom, dan BERHENTI di tiga. Di 1024px tiga kartu pas 306px dan masih
   penuh ke tepi layar; di atas ~1300px yang mengambil alih adalah atap di atas,
   jadi yang bertambah adalah margin kiri-kanan, bukan jumlah kartu. */
@media (min-width: 1024px) {
  body.nd-ui .nd-hero { --nd-hero-cols: 3; }
}

/* ============================================================
   REL
   ============================================================ */

/* ARITMATIKA YANG MENGIKAT BERKAS INI — jangan ubah satu bagian saja.
   max-inline-size di sini = (cols x cap) + (cols-1 x gap) + 2 x gutter,
   dan lebar kartu di bawah = (100% - peek - (cols-1 x gap)) / cols terhadap
   content-box rel (yang sudah dikurangi padding-inline = gutter). Jadi:
     - layar sempit: atap tidak mengikat -> rumus persen menutup TEPAT,
       cols kartu + gap + gutter = lebar layar, nol serpihan kartu berikutnya;
     - layar lebar: atap mengikat -> content-box rel = cols x cap + gap, jadi
       rumus persen menghasilkan tepat cap, nol sisa, dan kelebihan ruang jadi
       margin otomatis (margin-inline: auto) alih-alih kartu keempat.
   Kedua jalur memakai variabel yang sama, jadi tidak mungkin desinkron.
   Pembungkus ini juga yang menjadi jangkar panah kiri/kanan: panah TIDAK BOLEH
   jadi anak .nd-hero-track — anak absolut di dalam area gulir akan ikut
   bergeser bersama isinya. */
body.nd-ui .nd-hero-view {
  position: relative;
  inline-size: 100%;
  max-inline-size: calc(var(--nd-hero-cols) * var(--nd-hero-cap)
                      + (var(--nd-hero-cols) - 1) * var(--nd-hero-gap)
                      + 2 * var(--nd-gutter-x, 1rem));
  margin-inline: auto;
}

/* Gulir NATIVE + scroll-snap, bukan lagi tumpukan slide yang di-fade: begitu
   2-3 kartu terlihat SEKALIGUS, "fade antar slide" kehilangan arti. Imbalannya
   besar — geser jari, roda, dan tombol keyboard jadi gratis dari peramban, dan
   JS tidak perlu lagi berkelahi dengan gerakan jari. */
body.nd-ui .nd-hero-track {
  display: flex;
  gap: var(--nd-hero-gap);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  padding-inline: var(--nd-gutter-x, 1rem);
  /* WAJIB kembar dengan padding-inline: tanpa scroll-padding, kartu yang
     di-snap berhenti menempel tepi layar, tidak sejajar garis gutter halaman. */
  scroll-padding-inline: var(--nd-gutter-x, 1rem);
  /* Ruang napas bayangan kartu — area gulir memotong luapannya. */
  padding-block: var(--nd-sp-1) var(--nd-sp-2);
  scrollbar-width: none;
  -ms-overflow-style: none;
}
body.nd-ui .nd-hero-track::-webkit-scrollbar { display: none; }

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

body.nd-ui .nd-hero-card {
  position: relative;
  flex: 0 0 auto;
  inline-size: min(
      calc((100% - var(--nd-hero-peek) - (var(--nd-hero-cols) - 1) * var(--nd-hero-gap)) / var(--nd-hero-cols)),
      var(--nd-hero-cap));
  /* aspect-ratio + inline-size = tinggi kartu SUDAH PASTI sebelum satu byte
     poster tiba. Itulah yang membuat CLS nol: panel metadata diposisikan
     absolut, jadi judul yang tiba-tiba jadi 2 baris saat webfont bertukar pun
     tidak menggeser apa pun di luar kartu. */
  aspect-ratio: 2 / 3;
  scroll-snap-align: start;
  border-radius: var(--nd-r-4);
  overflow: hidden;
  background: var(--nd-ph-bg);
  box-shadow: var(--nd-e2);
  /* Komposisi di dalam kartu menyetel diri dari lebar KARTU, bukan lebar layar
     (lihat poin 3 di kepala berkas). container-type: inline-size di elemen yang
     sudah position:relative aman — containment tata letak memang menjadikannya
     containing block untuk anak absolut, dan itu persis yang kita mau. */
  container-type: inline-size;
  container-name: ndhero;

  /* Nilai cadangan dalam rem untuk peramban tanpa satuan cqi (WebView tua). */
  --nd-hero-ramp: 4.5rem;
  --nd-hero-pad: var(--nd-sp-4);
  --nd-hero-row: var(--nd-sp-2);
  --nd-hero-fs-title: var(--nd-fs-lg);
  --nd-hero-fs-fact: var(--nd-fs-2xs);
  --nd-hero-fs-desc: var(--nd-fs-xs);
  --nd-hero-fs-btn: var(--nd-fs-sm);
  --nd-hero-btn-h: 2.5rem;
}

/* Versi sebenarnya: semua proporsional terhadap lebar kartu. clamp() memakai
   token situs sebagai lantai & atap supaya tipografi tidak pernah keluar skala
   (dan supaya pengguna yang membesarkan font peramban tetap dapat teks besar). */
@supports (inline-size: 1cqi) {
  body.nd-ui .nd-hero-card {
    --nd-hero-ramp: 19cqi;
    --nd-hero-pad: clamp(var(--nd-sp-3), 4.2cqi, var(--nd-sp-5));
    --nd-hero-row: clamp(var(--nd-sp-1), 1.8cqi, var(--nd-sp-3));
    --nd-hero-fs-title: clamp(var(--nd-fs-sm), 6.1cqi, var(--nd-fs-2xl));
    --nd-hero-fs-fact: clamp(var(--nd-fs-3xs), 3.4cqi, var(--nd-fs-sm));
    --nd-hero-fs-desc: clamp(var(--nd-fs-3xs), 3.7cqi, var(--nd-fs-md));
    --nd-hero-fs-btn: clamp(var(--nd-fs-2xs), 4.1cqi, var(--nd-fs-md));
    --nd-hero-btn-h: max(2.5rem, 11.5cqi);
  }
}

body.nd-ui .nd-hero-art-link { position: absolute; inset: 0; display: block; }
body.nd-ui .nd-hero-art {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  /* Poster katalog 3:4 dipotong ~11% di kiri-kanan untuk mengisi kotak 2:3
     (tidak ada potongan vertikal). Titik 20% menaikkan bingkai sedikit: kalau
     ada provider yang posternya lebih jangkung, yang dibuang bagian bawah —
     yang memang tertutup pelat gelap. */
  object-position: center 20%;
}

/* ============================================================
   PANEL METADATA
   ============================================================ */

body.nd-ui .nd-hero-pane {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: var(--nd-hero-row);
  padding: var(--nd-hero-ramp) var(--nd-hero-pad) var(--nd-hero-pad);
  /* Panel tidak menadah klik: seluruh karya poster, TERMASUK di balik teks,
     tetap milik tautan gambar di bawahnya — menyentuh kartu di mana pun membuka
     filmnya, persis perilaku kartu Netflix. Hanya baris tombol yang menadah. */
  pointer-events: none;
  /* Angka warna ditulis LITERAL di sini dan sengaja tidak ikut tema: teks di
     atas artwork tidak boleh pernah bergantung tema terang/gelap — prinsip yang
     sama sudah dipakai --nd-poster-scrim di nd-tokens.css.
     Titik .94 dipaku ke --nd-hero-ramp, PANJANG YANG SAMA dengan
     padding-block-start di atas: itu seluruh jaminan keterbacaannya (poin 2).
     Lima titik di dalam ramp membentuk kurva-S (slope naik lalu turun) supaya
     peralihannya tidak punya "bahu" tajam di tengah seperti ramp 4-titik. */
  background: linear-gradient(to top,
      rgba(5, 6, 8, .97) 0,
      rgba(5, 6, 8, .94) calc(100% - var(--nd-hero-ramp)),
      rgba(5, 6, 8, .76) calc(100% - var(--nd-hero-ramp) * .80),
      rgba(5, 6, 8, .50) calc(100% - var(--nd-hero-ramp) * .60),
      rgba(5, 6, 8, .26) calc(100% - var(--nd-hero-ramp) * .40),
      rgba(5, 6, 8, .09) calc(100% - var(--nd-hero-ramp) * .20),
      rgba(5, 6, 8, 0) 100%);
}

body.nd-ui .nd-hero-title {
  margin: 0;
  font-weight: 800;
  font-size: var(--nd-hero-fs-title);
  line-height: var(--nd-lh-tight, 1.16);
  font-family: var(--nd-font-display, inherit);
  letter-spacing: var(--nd-ls-display, -.028em);
  color: #FFFFFF;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Baris fakta bertitik, seperti "Komedi - 2021 - 3 Season" di referensi.
   Titiknya pseudo-element pada span KEDUA dan seterusnya, jadi tidak pernah ada
   titik menggantung saat badge episode tidak ada atau tag kosong. */
body.nd-ui .nd-hero-facts {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 var(--nd-sp-2);
  font-weight: 600;
  font-size: var(--nd-hero-fs-fact);
  line-height: var(--nd-lh-snug, 1.3);
  font-family: var(--nd-font-text, inherit);
  color: rgba(255, 255, 255, .94);
}
body.nd-ui .nd-hero-facts span { white-space: nowrap; }
body.nd-ui .nd-hero-facts span + span::before {
  content: "\00B7";
  margin-inline-end: var(--nd-sp-2);
  color: rgba(255, 255, 255, .58);
}

body.nd-ui .nd-hero-desc {
  margin: 0;
  font-weight: 400;
  font-size: var(--nd-hero-fs-desc);
  line-height: var(--nd-lh-base, 1.52);
  font-family: var(--nd-font-text, inherit);
  color: rgba(255, 255, 255, .78);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Dua pil BERTUMPUK lebar penuh — persis referensi, dan tetap bertumpuk di
   SEMUA lebar. Alasannya bukan selera: dua pil berdampingan harus berbagi satu
   baris, sehingga label terpanjang ("Informasi Selengkapnya" di beberapa
   bahasa) memotong label tombol UTAMA jadi "Tonton Se...". Bertumpuk, tiap pil
   dapat seluruh lebar panel dan label apa pun boleh membungkus ke baris kedua —
   panel tumbuh ke atas dan gradiennya ikut naik, jadi tidak ada yang terpotong. */
body.nd-ui .nd-hero-acts {
  margin-block-start: var(--nd-sp-1);
  display: flex;
  flex-direction: column;
  gap: var(--nd-sp-2);
  pointer-events: auto;
}
body.nd-ui .nd-hero-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--nd-sp-2);
  min-block-size: var(--nd-hero-btn-h);
  padding: var(--nd-sp-2) var(--nd-sp-3);
  border-radius: var(--nd-r-full);
  font-weight: 800;
  font-size: var(--nd-hero-fs-btn);
  line-height: var(--nd-lh-tight, 1.16);
  font-family: var(--nd-font-text, inherit);
  text-align: center;
  text-decoration: none;
  transition: background-color var(--nd-dur-1) var(--nd-ease-out),
              transform var(--nd-dur-1) var(--nd-ease-out);
}
body.nd-ui .nd-hero-btn svg { flex: 0 0 auto; }
/* Isian BURAM, bukan tembus pandang: kontras pil jadi ANGKA TETAP (19.6:1) dan
   nol bergantung warna poster di belakangnya. */
body.nd-ui .nd-hero-btn-play { background: #FFFFFF; color: #0B0C0F; }
body.nd-ui .nd-hero-btn-play:hover { background: #E6E7EA; }
body.nd-ui .nd-hero-btn:active { transform: scale(.98); }

/* Kartu paling sempit (HP 320-330px). Ambang 280px memakai px DENGAN SENGAJA:
   px tidak ikut membesar saat pengguna menyetel font peramban, sama seperti
   lebar kartu yang berasal dari persen lebar layar — jadi keduanya tetap satu
   kerangka. Kalau ambang ini ditulis rem, desktop akan mendapat komposisi HP
   begitu font peramban dinaikkan ke 20px. Lebar kartu nyata terdekat di atas
   ambang ini adalah 288px (2 kolom di 640px), jadi jaraknya aman. */
@container ndhero (max-width: 280px) {
  body.nd-ui .nd-hero-desc { -webkit-line-clamp: 1; }
}

/* ============================================================
   KONTROL
   ============================================================ */

/* Panah HANYA untuk tetikus. Di layar sentuh geser-jari sudah native, jadi
   panah cuma menutupi karya poster. 22% (bukan 50%): panel metadata memakai
   ~57% bagian bawah kartu, jadi titik tengah kartu justru ADA DI DALAM panel. */
body.nd-ui .nd-hero-nav {
  position: absolute;
  z-index: 3;
  inset-block-start: 22%;
  transform: translateY(-50%);
  display: none;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  place-items: center;
  /* <button> bawaan peramban punya `border: 2px outset` dan proyek ini TIDAK
     punya reset tombol global (nd-borderless.css adalah daftar-izin, bukan
     sapuan `*`) — tanpa dua baris ini tombol hero melanggar keputusan "tidak
     ada border di UI" dan ukurannya meleset 4px. */
  border: 0;
  padding: 0;
  border-radius: 50%;
  background: rgba(9, 10, 13, .62);
  color: #FFFFFF;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--nd-dur-2) var(--nd-ease-out),
              background-color var(--nd-dur-1) var(--nd-ease-out);
}
body.nd-ui .nd-hero-prev { inset-inline-start: var(--nd-sp-2); }
body.nd-ui .nd-hero-next { inset-inline-end: var(--nd-sp-2); }
@media (min-width: 1024px) and (hover: hover) {
  body.nd-ui .nd-hero-nav { display: grid; }
  body.nd-ui .nd-hero-view:hover .nd-hero-nav,
  body.nd-ui .nd-hero-nav:focus-visible { opacity: 1; }
  body.nd-ui .nd-hero-nav:hover { background: rgba(9, 10, 13, .88); }
}
/* JS memasang atribut hidden saat semua kartu sudah muat sekaligus (tidak ada
   yang bisa digeser). Aturan ini WAJIB ADA: specificity (0,3,1) di sini menang
   atas display:grid di blok media di atas (0,2,1) — bukan karena urutannya. */
body.nd-ui .nd-hero-nav[hidden] { display: none; }

/* Titik indikator pindah ke BAWAH kartu: di dalam kartu ia akan menindih dua
   pil, dan dengan 2-3 kartu terlihat sekaligus satu titik tidak lagi "milik"
   satu kartu tertentu — satu titik = satu POSISI GESER yang bisa dicapai. */
body.nd-ui .nd-hero-dots {
  display: flex;
  justify-content: center;
  gap: var(--nd-sp-2);
  margin-block-start: var(--nd-sp-2);
  padding-inline: var(--nd-gutter-x, 1rem);
  /* Tinggi baris dicadangkan walau semua titiknya disembunyikan — lihat
     .is-void. */
  min-block-size: 3px;
}
body.nd-ui .nd-hero-dot {
  inline-size: 1.5rem;
  block-size: 3px;
  padding: 0;
  border: 0;                  /* lihat catatan di .nd-hero-nav */
  border-radius: var(--nd-r-full);
  /* Titik berdiri di LATAR HALAMAN, bukan di atas poster — jadi di sini
     warnanya justru HARUS sadar-tema (kebalikan dari teks di dalam kartu).
     --nd-t3 dipilih, BUKAN --nd-line-strong: yang terakhir token garis-rambut
     dan cuma 2.4:1 di tema gelap / 1.8:1 di tema terang, gagal WCAG 1.4.11
     untuk komponen UI. --nd-t3 = 6.4:1 gelap / 5.7:1 terang. */
  background: var(--nd-t3);
  cursor: pointer;
  transition: background-color var(--nd-dur-1) var(--nd-ease-out);
}
body.nd-ui .nd-hero-dot.is-active { background: var(--nd-accent); }
/* Titik yang tidak bisa dicapai (jumlah posisi geser berubah ikut jumlah kolom)
   dibuat INVISIBLE, bukan display:none. Sebabnya CLS: display:none membuat
   baris titik menyusut sesudah JS jalan, dan seluruh halaman di bawah hero
   ikut naik. visibility:hidden mempertahankan kotaknya — nol pergeseran — dan
   tetap mengeluarkan tombolnya dari pohon aksesibilitas maupun dari hit-test. */
body.nd-ui .nd-hero-dot.is-void { visibility: hidden; }

@media (prefers-reduced-motion: reduce) {
  /* Auto-advance dimatikan di JS (lihat initNdShell); di sini gulir halus milik
     tombol panah/titik ikut dimatikan supaya tidak ada gerakan mendadak. */
  body.nd-ui .nd-hero-track { scroll-behavior: auto; }
  body.nd-ui .nd-hero-btn:active { transform: none; }
}
