/* nd-card.css — desain ulang kartu film & grid.

   ATURAN: NOL rename. Semua nama class lama (.card, .poster-wrap, .poster,
   .poster-fallback, .episode-badge, .poster-tags, .movie-tag, .body, .title,
   .movie-meta-line, .card-link-overlay) DIPERTAHANKAN PERSIS — JS global,
   skrip iklan (resolveNavUrl), dan kontrak SEO (h3.title) membacanya.
   Yang berubah hanya tampilannya.

   Kontrak stacking kartu juga dipertahankan apa adanya:
     .card-link-overlay z1  →  .poster-wrap/.body z2  →  badge & tag z3
   Kalau urutan ini berubah, chip tag berhenti bisa diklik. */

/* ============================================================
   1. KARTU
   ============================================================ */

body.nd-ui .card {
  border-radius: var(--nd-r-3);
  background: var(--nd-s1);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  position: relative;
  isolation: isolate;
  transition: border-color var(--nd-dur-2) var(--nd-ease-out),
              box-shadow var(--nd-dur-2) var(--nd-ease-out);
}

@media (hover: hover) and (pointer: fine) {
  body.nd-ui .card:hover {
    border-color: var(--nd-line);
    box-shadow: var(--nd-e3);
  }
  /* Yang membesar HANYA gambar di dalam bingkai, bukan kotak kartunya.
     Jadi tidak ada reflow, tetangga tidak bergeser, CLS tetap 0. */
  body.nd-ui .card:hover .poster,
  body.nd-ui .card:hover .poster-fallback { transform: scale(1.06); }
}

body.nd-ui .card:focus-within { border-color: var(--nd-accent-400); }

/* ============================================================
   2. POSTER
   ============================================================ */

body.nd-ui .card .poster-wrap {
  position: relative;
  z-index: 2;
  aspect-ratio: 3 / 4;          /* tinggi kartu jadi seragam di satu baris */
  inline-size: 100%;
  overflow: hidden;
  background: var(--nd-s2);
  flex: 0 0 auto;
}

body.nd-ui .card .poster {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--nd-dur-3) var(--nd-ease-out);
  /* Fade-in murni CSS saat gambar selesai dimuat. Sengaja TIDAK memakai
     opacity:0 yang dibuka oleh class dari JS — kalau JS gagal, poster akan
     tak terlihat selamanya. Dengan animation ... both, kondisi akhirnya
     selalu terlihat walau JS mati. */
  animation: nd-card-fade var(--nd-dur-2) var(--nd-ease-out) both;
}

@keyframes nd-card-fade { from { opacity: 0; } to { opacity: 1; } }

/* Placeholder saat film memang tidak punya poster.
   Dulu kotak kosong/putih; sekarang tile bermonogram yang menyatu dengan tema. */
body.nd-ui .card .poster-fallback {
  inline-size: 100%;
  block-size: 100%;
  display: grid;
  place-items: center;
  background:
    radial-gradient(120% 100% at 50% 0%, var(--nd-s3) 0%, var(--nd-s1) 70%);
  color: var(--nd-t3);
  font: 800 clamp(1.5rem, 14%, 3rem) / 1 var(--nd-font-display);
  letter-spacing: .04em;
  transition: transform var(--nd-dur-3) var(--nd-ease-out);
}

/* ============================================================
   3. BADGE & TAG DI ATAS POSTER
   ============================================================ */

body.nd-ui .card .episode-badge {
  position: absolute;
  z-index: 3;
  inset-block-start: var(--nd-sp-2);
  inset-inline-start: var(--nd-sp-2);
  padding: 2px var(--nd-sp-2);
  border-radius: var(--nd-r-1);
  background: var(--nd-scrim-strong);
  color: var(--nd-t-on-accent);
  font: 700 var(--nd-fs-3xs) / 1.4 var(--nd-font-text);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

body.nd-ui .card .poster-tags {
  position: absolute;
  z-index: 3;
  inset-inline: var(--nd-sp-2);
  inset-block-end: var(--nd-sp-2);
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  /* Tag yang tidak muat disembunyikan rapi, bukan dipotong di tengah kata. */
  max-block-size: calc(2 * 1.6em + 4px);
  overflow: hidden;
}

body.nd-ui .card .movie-tag {
  border: 0;
  border-radius: var(--nd-r-1);
  padding: 2px 6px;
  font: 700 var(--nd-fs-3xs) / 1.4 var(--nd-font-text);
  color: var(--nd-t-on-accent);
  /* Scrim di atas poster SELALU gelap, di tema terang maupun gelap:
     teks di atas artwork tidak boleh bergantung tema. */
  background: var(--nd-scrim-strong);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  text-decoration: none;
  white-space: nowrap;
  max-inline-size: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background-color var(--nd-dur-1) var(--nd-ease-out);
}
body.nd-ui .card .movie-tag:hover { background: var(--nd-accent); }

/* ============================================================
   4. BADAN KARTU
   ============================================================ */

body.nd-ui .card .body {
  position: relative;
  z-index: 2;
  padding: var(--nd-sp-3) var(--nd-sp-3) var(--nd-sp-3);
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1 1 auto;
}

body.nd-ui .card .title {
  margin: 0;
  text-align: start;
  font: 700 var(--nd-fs-sm) / var(--nd-lh-snug, 1.3) var(--nd-font-text);
  color: var(--nd-t1);
  /* Tinggi dikunci 2 baris supaya judul pendek & panjang menghasilkan
     kartu setinggi sama — baris kartu jadi rata tanpa JS. */
  min-block-size: calc(2 * var(--nd-lh-snug, 1.3) * 1em);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

body.nd-ui .card .movie-meta-line {
  display: flex;
  flex-wrap: wrap;
  gap: var(--nd-sp-2);
  font: 500 var(--nd-fs-2xs) / 1.3 var(--nd-font-text);
  color: var(--nd-t3);
  margin-block-start: auto;
}

/* ============================================================
   5. GRID
   Tangga kolom 2/3/4/6 — semuanya pembagi 24 (jumlah kartu per halaman),
   sehingga tidak pernah ada baris terakhir yang menyisakan kartu yatim.
   ============================================================ */

body.nd-ui .grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--nd-sp-3);
}
@media (min-width: 560px)  { body.nd-ui .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 900px)  { body.nd-ui .grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 1280px) { body.nd-ui .grid { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--nd-sp-4); } }
@media (min-width: 1920px) { body.nd-ui .grid { grid-template-columns: repeat(8, minmax(0, 1fr)); } }
@media (min-width: 2560px) { body.nd-ui .grid { grid-template-columns: repeat(12, minmax(0, 1fr)); } }

/* ============================================================
   6. REDUCED MOTION
   Durasi diambil dari token, dan token durasi sudah di-override jadi 1ms di
   blok prefers-reduced-motion milik nd-tokens.css. Yang perlu dimatikan di
   sini hanyalah transform hover, karena itu gerak, bukan durasi.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  body.nd-ui .card:hover .poster,
  body.nd-ui .card:hover .poster-fallback { transform: none; }
}

/* ============================================================
   7. BADGE PROVIDER DI KARTU
   Dulu pill merah pekat yang menutupi wajah di poster. Sekarang memakai
   WARNA PROVIDER-nya sendiri, lebih ringkas, dan duduk di atas scrim —
   jadi terbaca tanpa merebut perhatian dari artwork.
   ============================================================ */

body.nd-ui .card .provider-badge {
  inset-block-start: var(--nd-sp-2);
  inset-inline-end: var(--nd-sp-2);
  top: auto;
  right: auto;
  border-radius: var(--nd-r-1);
  padding: 2px 6px;
  font: 700 var(--nd-fs-3xs) / 1.4 var(--nd-font-text);
  letter-spacing: 0;
  background: var(--nd-scrim-strong);
  color: var(--pv, var(--nd-t-on-accent));
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  max-inline-size: 60%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ============================================================
   8. TAG DI KARTU SEMPIT
   PENTING: chip tag adalah <a> ke /tag/{slug} — sumber internal link yang
   dihitung Google. Google mengindeks dengan rendering MOBILE-first, jadi
   `display:none` pada chip ke-3 di layar kecil akan MENGHAPUS link itu dari
   indeks. Karena itu semua chip tetap dirender dan tetap terlihat; yang
   disesuaikan hanya kerapatannya supaya muat tanpa terpotong.
   ============================================================ */

@media (max-width: 767.98px) {
  body.nd-ui .card .poster-tags {
    gap: 3px;
    max-block-size: calc(3 * 1.5em + 6px);   /* cukup untuk 3 chip menumpuk */
  }
  body.nd-ui .card .movie-tag {
    padding: 1px 5px;
    font-size: var(--nd-fs-3xs);
    line-height: 1.5;
  }
}

/* ============================================================
   9. HOVER REVEAL — ikon putar di atas poster
   Dibuat murni dari pseudo-element supaya markup kartu TIDAK berubah:
   markup yang sama dipakai SSR Blade dan buildCardHtml() di JS, jadi
   menambah elemen berarti harus mengubah keduanya serentak.
   Tanpa teks → tidak perlu terjemahan untuk 23 bahasa.
   ============================================================ */

body.nd-ui .card .poster-wrap::after {
  content: "";
  position: absolute;
  z-index: 2;
  inset-block-end: var(--nd-sp-2);
  inset-inline-end: var(--nd-sp-2);
  inline-size: 2rem;
  block-size: 2rem;
  border-radius: 50%;
  background: var(--nd-accent) no-repeat center / 44%;
  /* segitiga putar, di-inline sebagai SVG supaya nol request tambahan */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23fff'%3E%3Cpath d='M8 5v14l11-7z'/%3E%3C/svg%3E");
  opacity: 0;
  transform: translateY(6px) scale(.9);
  transition: opacity var(--nd-dur-2) var(--nd-ease-out),
              transform var(--nd-dur-2) var(--nd-ease-spring);
  pointer-events: none;
}

@media (hover: hover) and (pointer: fine) {
  body.nd-ui .card:hover .poster-wrap::after,
  body.nd-ui .card:focus-within .poster-wrap::after {
    opacity: 1;
    transform: none;
  }
}

/* Di perangkat sentuh tidak ada hover: tampilkan terus tapi samar,
   supaya tetap terbaca sebagai "bisa diputar" tanpa menutupi artwork. */
@media (hover: none) {
  body.nd-ui .card .poster-wrap::after { opacity: .85; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  body.nd-ui .card .poster-wrap::after { transform: none; }
}

/* ============================================================
   10. HOVER EXPAND ALA NETFLIX
   Permintaan owner: kartu membesar saat kursor diarahkan.

   Dibuat dengan `transform: scale()` pada KARTU, bukan dengan mengubah
   lebar/tinggi — supaya tidak ada reflow sama sekali (CLS tetap 0) dan
   kartu tetangga tidak bergeser.

   Kartu yang membesar dinaikkan z-index-nya supaya tumbuh DI ATAS
   tetangganya, bukan terpotong di belakangnya.
   ============================================================ */

@media (hover: hover) and (pointer: fine) {
  body.nd-ui .card {
    transform-origin: center center;
    transition: transform var(--nd-dur-2) var(--nd-ease-spring),
                box-shadow var(--nd-dur-2) var(--nd-ease-out);
  }

  body.nd-ui .card:hover,
  body.nd-ui .card:focus-within {
    transform: scale(1.14);
    z-index: 20;
    box-shadow: var(--nd-e4);
  }

  /* Poster TIDAK ikut di-scale lagi saat kartunya sendiri membesar —
     kalau keduanya di-scale, gambar jadi over-zoom dan pecah. */
  body.nd-ui .card:hover .poster,
  body.nd-ui .card:focus-within .poster,
  body.nd-ui .card:hover .poster-fallback { transform: none; }

  /* Kartu di tepi rail: titik tumbuh digeser ke dalam supaya tidak
     tumbuh keluar layar dan memicu scroll horizontal. */
  body.nd-ui .provider-home-rail > .card:first-child { transform-origin: left center; }
  body.nd-ui .provider-home-rail > .card:last-child  { transform-origin: right center; }
  body.nd-ui .grid > .card:nth-child(2n + 1) { transform-origin: left center; }
  body.nd-ui .grid > .card:nth-child(2n)     { transform-origin: right center; }

  /* JEBAKAN — rail provider ADALAH kotak scroll (`overflow-x: auto`), dan begitu
     satu sumbu bukan `visible`, sumbu lainnya TIDAK boleh `visible` lagi: spesifikasi
     memaksanya jadi `auto`. Jadi sumbu vertikal di sini SELALU memotong. Tidak bisa
     diakali dengan `overflow-y: visible` (malah memunculkan scrollbar vertikal) dan
     tidak bisa dengan `overflow-x: clip` (itu mematikan scroll rail berikut tombol
     panahnya). Yang tersisa cuma satu celah: pemotongan terjadi di tepi PADDING-box,
     bukan content-box — jadi padding vertikal = ruang tumbuh yang sah.

     Dulu padding ini sp-3 (12px) dan itu KURANG di hampir semua lebar: kartu yang
     membesar 1,14x menonjol 7% tinggi kartu di atas DAN di bawah, terukur terpotong
     6,7px di 1920 dan 13,1px di 2560 — rata, sudut membulatnya ikut hilang, jadi
     zoom-nya terbaca "kotak dan rusak" (keluhan owner). Tinggi kartu = 4/3 lebar
     kartu dan lebarnya ikut lebar layar, jadi ruangnya diukur dalam vw, BUKAN px
     tetap: 2,2vw selalu melampaui 7% tinggi kartu di seluruh tangga kolom
     (8/7/6/5 kartu) — diperiksa di 1100/1366/1920/2560.

     margin-block negatif mengembalikan tinggi LUAR rail persis seperti sebelum
     patch (padding 12px lama), jadi ritme antar-section tidak bergeser sedikit pun;
     terukur nol beda posisi di semua landmark halaman, CLS tetap 0.
     Dua nilai clamp di bawah WAJIB identik — kalau beda, rail mulai menggeser layout. */
  body.nd-ui .provider-home-rail {
    padding-block: clamp(16px, 2.2vw, 72px);
    margin-block: calc(var(--nd-sp-3) - clamp(16px, 2.2vw, 72px));
  }

  /* Tanpa ini margin negatif di atas "bocor" lewat margin-collapsing dan menyeret
     seluruh pembungkus rail naik (terukur 29px di 1920) — rail adalah anak in-flow
     pertama pembungkusnya. flow-root menutup jalur collapsing itu tanpa mengubah
     apa pun yang lain (tidak memotong, tidak menggeser). */
  body.nd-ui .provider-home-rail-wrap { display: flow-root; }

  /* Kepala section (judul + tombol Prev/Next halaman) duduk TEPAT di atas rail,
     jadi kotak padding rail yang melebar sekarang menindihnya. Kotak scroll menang
     hit-test atas isi non-posisi yang ada di atasnya, dan tombol Prev/Next jadi mati
     total (terbukti: Chrome mengembalikan .provider-home-rail di elementFromPoint
     tepat di tengah tombol). z-index 1 mengangkat kepala section di atas kotak rail,
     dan tetap di BAWAH kartu yang disorot (z-index 20) supaya kartu yang membesar
     tetap menimpa judul, bukan sebaliknya. */
  body.nd-ui .provider-home-section-head { position: relative; z-index: 1; }
}

/* Di bawah 769px jumlah kartu per layar datang dari .env
   (STYLE_HOME_SLICK_ITEM_MOBILE_PROVIDER_FILTER, rentang 1..8; dev & prod = 2,5),
   jadi kartunya jauh lebih besar: di 768px satu kartu setinggi 362px dan butuh 25px
   ruang, dan kalau nilainya diset 1 butuhnya ~66px. 9vw menutupi SELURUH rentang itu;
   kelebihannya tidak berbiaya karena dibatalkan lagi oleh margin negatif. Blok ini
   hanya hidup di perangkat ber-hover — di layar sentuh zoom kartu memang tidak ada. */
@media (hover: hover) and (pointer: fine) and (max-width: 768px) {
  body.nd-ui .provider-home-rail {
    padding-block: clamp(16px, 9vw, 96px);
    margin-block: calc(var(--nd-sp-3) - clamp(16px, 9vw, 96px));
  }
}

/* JEBAKAN — JANGAN kembalikan `background: <warna solid>` untuk .body di sini.
   Aturan lama `body.nd-ui .card:hover .body { background: var(--nd-s2); }` kalah
   urutan tapi MENANG specificity ((0,4,1) lawan (0,3,1) milik scrim di §9), dan
   karena `background` itu shorthand ia sekalian me-reset background-image. Jadi
   saat disorot gradien scrim hilang TOTAL dan yang tersisa pelat abu solid
   dengan garis potong lurus membelah poster — persis keluhan "pelat solid,
   jelek" dari pemilik. Terbukti di computed style: background-image jadi `none`.

   Perlakuan hover sekarang hidup di §9 dan bekerja lewat LAPISAN TERPISAH
   (::before untuk blur, ::after untuk pendar) supaya tidak ada satu properti pun
   yang menimpa scrim. */

@media (prefers-reduced-motion: reduce) {
  body.nd-ui .card:hover,
  body.nd-ui .card:focus-within { transform: none; }
}

/* ============================================================
   FALLBACK POSTER — film tanpa gambar
   Dulu: satu huruf di atas kotak abu kosong, yang di dalam rail terbaca sebagai
   kartu gagal muat. Sekarang: judul penuh di atas latar berwarna yang diturunkan
   dari judul itu sendiri (--nd-fb-h ditempel inline oleh App\Support\NdPoster
   dan oleh ndPosterHue() di sisi JS, dengan rumus yang sama).

   hsl() dipakai, BUKAN oklch()/color-mix(): WebView wrapper lama menganggap dua
   fungsi itu invalid sehingga latarnya akan kosong sama sekali.

   PENTING soal tinggi: `aspect-ratio` hanya menetapkan ukuran yang DIINGINKAN —
   isi yang lebih tinggi tetap bisa mendorongnya melar, karena `min-height` bawaan
   flex/grid adalah `auto`. Itu sebabnya kartu tanpa poster di "You May Like"
   terlihat jauh lebih jangkung daripada tetangganya yang berposter. Dikunci di
   bawah dengan min-block-size:0 + overflow:hidden.
   ============================================================ */

body.nd-ui .poster-fallback,
body.nd-ui .you-may-like-fallback,
body.nd-ui .watch-history-card-fallback,
body.nd-ui .watch-history-thumb-fallback,
body.nd-ui .movie-search-poster-fallback,
body.nd-ui .global-search-thumb-fallback,
body.nd-ui .last-watch-thumb-fallback,
body.nd-ui .nd-img-fallback { /* nd-allow-ns: class SUDAH ADA (penangan gambar gagal global di exoplayer-footer-scripts) — hanya diwarnai ulang */
  --nd-fb-h: 222;
  /* Varian yang markup-nya masih menampilkan satu huruf (bukan .nd-fb-title)
     tetap terbaca: tintanya dipatok putih, bukan diwarisi dari induk. */
  color: #fff;
  font-weight: 800;
  text-shadow: 0 1px 8px rgba(0, 0, 0, .5);
  position: relative;
  display: grid;
  place-items: center;
  min-block-size: 0;
  overflow: hidden;
  isolation: isolate;
  padding: var(--nd-sp-3);
  background:
    radial-gradient(120% 90% at 50% 0%,
                    hsl(calc(var(--nd-fb-h) * 1deg) 55% 32% / .55) 0%,
                    hsl(calc(var(--nd-fb-h) * 1deg) 55% 32% / 0) 62%),
    linear-gradient(155deg,
                    hsl(calc(var(--nd-fb-h) * 1deg) 42% 24%) 0%,
                    hsl(calc((var(--nd-fb-h) + 34) * 1deg) 46% 12%) 100%);
}

:root[data-theme="light"] body.nd-ui .poster-fallback,
:root[data-theme="light"] body.nd-ui .you-may-like-fallback,
:root[data-theme="light"] body.nd-ui .watch-history-card-fallback,
html[data-theme="light"] body.nd-ui .poster-fallback,
html[data-theme="light"] body.nd-ui .you-may-like-fallback,
html[data-theme="light"] body.nd-ui .watch-history-card-fallback,
:root[data-theme="light"] body.nd-ui .watch-history-thumb-fallback,
html[data-theme="light"] body.nd-ui .watch-history-thumb-fallback,
:root[data-theme="light"] body.nd-ui .movie-search-poster-fallback,
html[data-theme="light"] body.nd-ui .movie-search-poster-fallback,
:root[data-theme="light"] body.nd-ui .global-search-thumb-fallback,
html[data-theme="light"] body.nd-ui .global-search-thumb-fallback,
:root[data-theme="light"] body.nd-ui .last-watch-thumb-fallback,
html[data-theme="light"] body.nd-ui .last-watch-thumb-fallback,
:root[data-theme="light"] body.nd-ui .nd-img-fallback, /* nd-allow-ns */
html[data-theme="light"] body.nd-ui .nd-img-fallback { /* nd-allow-ns */
  background:
    radial-gradient(120% 90% at 50% 0%,
                    hsl(calc(var(--nd-fb-h) * 1deg) 70% 72% / .55) 0%,
                    hsl(calc(var(--nd-fb-h) * 1deg) 70% 72% / 0) 62%),
    linear-gradient(155deg,
                    hsl(calc(var(--nd-fb-h) * 1deg) 58% 62%) 0%,
                    hsl(calc((var(--nd-fb-h) + 34) * 1deg) 52% 44%) 100%);
}

/* Kilau diagonal tipis supaya tidak terbaca sebagai bidang datar. */
body.nd-ui .poster-fallback::after,
body.nd-ui .you-may-like-fallback::after,
body.nd-ui .watch-history-card-fallback::after,
body.nd-ui .watch-history-thumb-fallback::after,
body.nd-ui .movie-search-poster-fallback::after,
body.nd-ui .global-search-thumb-fallback::after,
body.nd-ui .last-watch-thumb-fallback::after,
body.nd-ui .nd-img-fallback::after { /* nd-allow-ns */
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(115deg,
              rgba(255, 255, 255, .10) 0%,
              rgba(255, 255, 255, 0) 42%);
}

body.nd-ui .nd-fb-title {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-align: center;
  text-wrap: balance;
  color: #fff;
  font-family: var(--nd-font-display);
  font-weight: 800;
  font-size: clamp(.68rem, 1.1cqw + .5rem, 1rem);
  line-height: 1.25;
  letter-spacing: -.01em;
  text-shadow: 0 1px 10px rgba(0, 0, 0, .55);
}

/* Kartu kecil di rail riwayat hanya muat sedikit baris. */
body.nd-ui .watch-history-card-fallback .nd-fb-title {
  -webkit-line-clamp: 3;
  font-size: var(--nd-fs-3xs);
}

/* Kartu rail SUDAH punya body mengambang yang memuat judul. Jadi judul besar di
   tengah bidang fallback menjadi judul KEDUA pada kartu yang sama — terlihat jelas
   pada kartu tanpa poster di rail "Drama Lainnya": judul di tengah bidang DAN judul
   yang sama lagi di pita bawah, sisanya ruang kosong. Yang dibungkam adalah salinan
   DEKORATIF di dalam bidang fallback; judul asli di body tetap di DOM & terlihat. */
body.nd-ui .watch-history-card .nd-fb-title { display: none; }

/* Bidang fallback lalu diisi tanda putar samar supaya kartu tanpa poster terbaca
   sebagai poster yang memang tak bergambar, bukan kartu yang gagal dimuat. Ditaruh
   sedikit di atas tengah agar tidak tertimpa body mengambang di bawahnya. */
body.nd-ui .watch-history-card-fallback,
body.nd-ui .watch-history-card .nd-img-fallback { /* nd-allow-ns: elemen DIBUAT penangan gambar-gagal global, bukan komponen baru */
  font-size: 0;
}

body.nd-ui .watch-history-card-fallback::before,
body.nd-ui .watch-history-card .nd-img-fallback::before { /* nd-allow-ns */
  content: "";
  inline-size: 34%;
  max-inline-size: 64px;
  aspect-ratio: 1;
  margin-block-end: 20%;
  opacity: .5;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Ccircle cx='24' cy='24' r='21' fill='none' stroke='%23fff' stroke-width='2'/%3E%3Cpath d='M20 16.4 33.2 24 20 31.6Z' fill='%23fff'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* ============================================================
   "YOU MAY LIKE" — tinggi kartu seragam
   Setiap kartu: gambar rasio 3:4 + judul dua baris. Keduanya dikunci supaya
   satu baris grid tidak lagi diregangkan oleh kartu yang kebetulan lebih tinggi.
   ============================================================ */

body.nd-ui .you-may-like-card {
  display: grid;
  grid-template-rows: auto 1fr;
  align-content: start;
  container-type: inline-size;
}

body.nd-ui .you-may-like-img,
body.nd-ui .you-may-like-fallback,
body.nd-ui .you-may-like-card img {
  inline-size: 100%;
  block-size: auto;
  aspect-ratio: 3 / 4;
  min-block-size: 0;
  object-fit: cover;
}

body.nd-ui .watch-history-card-fallback { container-type: inline-size; }

/* ============================================================
   9. KARTU MENGAMBANG — judul & meta DI ATAS poster
   Keputusan owner: ukuran kartu = ukuran poster, dan semua teks (judul, genre,
   meta) mengambang di atas gambar dengan alas gradien gelap transparan + blur,
   supaya warna teks tidak pernah bentrok dengan poster mana pun.

   Dikerjakan murni lewat CSS: markup kartu TIDAK berubah, jadi judul, tag, dan
   tautan tetap berada di DOM persis seperti sebelumnya dan tidak ada satu pun
   sinyal SEO yang hilang.

   Berlaku di semua halaman yang memakai .card (beranda, tag, genre, cari,
   hasil provider).
   ============================================================ */

body.nd-ui .card {
  display: block;
  aspect-ratio: 3 / 4;
  background: var(--nd-s2);
}

/* Poster memenuhi seluruh kartu. */
body.nd-ui .card .poster-wrap {
  position: absolute;
  inset: 0;
  z-index: 1;
  aspect-ratio: auto;
  inline-size: auto;
  block-size: auto;
}

body.nd-ui .card .poster,
body.nd-ui .card .poster-fallback {
  inline-size: 100%;
  block-size: 100%;
}

/* Lapisan tautan menutup kartu, tapi tetap di bawah elemen yang bisa diklik
   sendiri (tag, badge) supaya keduanya tidak saling merebut klik. */
body.nd-ui .card .card-link-overlay { z-index: 4; }

/* ---------- Alas teks ---------- */

body.nd-ui .card .body {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 5;
  pointer-events: none;      /* klik tembus ke lapisan tautan di bawahnya */
  padding: var(--nd-sp-12) var(--nd-sp-3) var(--nd-sp-3);
  gap: var(--nd-sp-1);
  /* Ramp 9-stop yang meniru kurva ease, BUKAN 4-stop linear. Ramp linear punya
     "siku" yang terbaca mata sebagai pelat gelap yang DITEMPEL di atas poster —
     itu setengah dari kesan murahnya. Hitam dasarnya rgba(5, 6, 8) (keluarga
     --nd-scrim), bukan hitam murni: sedikit biru membuatnya menyatu dengan
     poster, bukan melubanginya.

     KONTRAK KONTRAS — jangan diturunkan tanpa menghitung ulang. Blok teks
     digantung di dasar kotak ini, jadi puncak judul jatuh di ~52% tinggi kotak
     saat diam dan ~45% saat disorot. Alpha di titik PALING TIPIS itu .789 dan
     .825; di atas poster PUTIH PENUH (kasus terburuk nyata, bukan rata-rata)
     teks putih dapat 11.3:1 dan 12.9:1 — keduanya lewat lantai .68 / 7.36:1
     yang ditulis di --nd-poster-scrim. Ramp lama di titik yang sama cuma
     memberi ~3.1:1, alias GAGAL AA; jadi ini perbaikan terukur, bukan sekadar
     ganti selera.

     padding-block-start naik ke sp-12 justru UNTUK kontras itu: kotaknya makin
     tinggi → ekornya bisa panjang dan larut, sementara zona teks tetap pekat.
     .body absolut (dan .card dikunci aspect-ratio 3/4), jadi tinggi kartu TIDAK
     bisa tersentuh — CLS tetap 0, diukur 275/275/275 px sebelum-sesudah-saat-hover. */
  background: linear-gradient(to top,
              rgba(5, 6, 8, .93) 0%,
              rgba(5, 6, 8, .90) 20%,
              rgba(5, 6, 8, .86) 38%,
              rgba(5, 6, 8, .78) 54%,
              rgba(5, 6, 8, .62) 68%,
              rgba(5, 6, 8, .38) 80%,
              rgba(5, 6, 8, .18) 90%,
              rgba(5, 6, 8, .06) 96%,
              rgba(5, 6, 8, 0) 100%);
}

/* Blur dipasang di lapisan sendiri dan DIMUDARKAN ke atas lewat mask, supaya
   tidak ada garis potong tajam di tempat kotak teks berakhir. */
body.nd-ui .card .body::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  backdrop-filter: blur(10px) saturate(1.15);
  -webkit-backdrop-filter: blur(10px) saturate(1.15);
  /* Mask dibuat 3-tahap (dulu 2) supaya ujung atas blur benar-benar larut dan
     tidak meninggalkan garis sambungan di tempat kotak teks berakhir.
     Kalau backdrop-filter TIDAK didukung (WebView wrapper lama), lapisan ini
     jadi tak kasat mata dan SELURUH kontras dipikul gradien di atas — itu
     sebabnya lantai alpha hidup di gradien, bukan di blur. */
  mask-image: linear-gradient(to top, #000 0%, #000 30%, rgba(0, 0, 0, .52) 58%, transparent 100%);
  -webkit-mask-image: linear-gradient(to top, #000 0%, #000 30%, rgba(0, 0, 0, .52) 58%, transparent 100%);
  transition: backdrop-filter var(--nd-dur-3) var(--nd-ease-out),
              -webkit-backdrop-filter var(--nd-dur-3) var(--nd-ease-out);
}

/* Pendar aksen di dasar kartu: padam saat diam, menyala saat disorot. Dua
   sumber cahaya (aksen hangat di kiri, biru dingin di kanan) memberi kesan
   "lampu panggung" alih-alih bidang datar.

   Kenapa lapisan sendiri dan bukan ditempel ke `background` .body: jumlah
   lapisan latar jadi berubah antara diam dan hover, dan gradien dengan jumlah
   lapisan berbeda TIDAK bisa di-interpolasi browser → peralihannya "ngejepret".
   Dengan opacity di lapisan terpisah, peralihannya mulus.

   Pendar hanya hidup di zona paling gelap (alpha scrim >= .90) jadi kontras
   teks tidak tergerus: diukur 9.9:1 di poster putih dan 10.9:1 di poster hitam.
   z-index -1 sama dengan ::before, tapi ::after dicat SESUDAHNYA → pendar duduk
   di atas blur dan tetap di bawah teks. */
body.nd-ui .card .body::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0;
  background:
    radial-gradient(142% 96% at 28% 130%,
                    rgba(225, 0, 55, .64) 0%,
                    rgba(225, 0, 55, .22) 38%,
                    rgba(225, 0, 55, 0) 68%),
    radial-gradient(124% 88% at 90% 134%,
                    rgba(89, 182, 255, .34) 0%,
                    rgba(89, 182, 255, 0) 60%);
  transition: opacity var(--nd-dur-3) var(--nd-ease-out);
}

/* ---------- Teks di atas poster ---------- */

body.nd-ui .card .title {
  color: #fff;
  min-block-size: 0;                 /* tinggi kartu kini dari rasio poster */
  -webkit-line-clamp: 2;
  text-shadow: 0 1px 12px rgba(0, 0, 0, .8);
  font-weight: 800;
}

body.nd-ui .card .movie-meta-line,
body.nd-ui .card .provider-search-desc {
  color: rgba(255, 255, 255, .78);
  text-shadow: 0 1px 8px rgba(0, 0, 0, .75);
  margin-block-start: 0;
}

body.nd-ui .card .provider-search-desc {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: var(--nd-fs-2xs);
  line-height: 1.35;
}

/* Tag tetap bisa diklik walau induknya pointer-events:none. */
body.nd-ui .card .body a,
body.nd-ui .card .body .movie-tag { pointer-events: auto; }

body.nd-ui .card .body .movie-tag {
  background: rgba(255, 255, 255, .16);
  color: #fff;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
body.nd-ui .card .body .movie-tag:hover { background: var(--nd-accent); }

/* ---------- Chip genre di kartu buatan JS ----------
   Kartu rail provider dibangun di sisi JS dan memakai .card-genre-chip (markup
   lama, DI DALAM .body). Gaya warisannya dirancang untuk duduk di atas permukaan
   s1: ada garis tepi dan tinta --nd-t3. Sejak kartu jadi mengambang, chip itu
   duduk di atas POSTER, jadi garis tepinya terbaca sebagai kotak abu nyasar dan
   tintanya nyaris hilang. Disamakan dengan .movie-tag di atas: kaca putih, nol
   garis tepi (keputusan owner). Tinta putih di atas kaca ini selalu berada di
   zona scrim >= .90, jadi terbaca di poster putih maupun hitam. */
body.nd-ui .card .body .card-genre-chip {
  border: 0;
  background: rgba(255, 255, 255, .16);
  color: #fff;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  text-shadow: 0 1px 6px rgba(0, 0, 0, .55);
}

/* ---------- Chip tag WAJIB di atas blok judul ----------
   .poster-tags digantung di dasar .poster-wrap — persis di tempat judul & meta
   berada — sehingga judul tercetak MENEMBUS chip (terukur -47px alias tumpang
   tindih penuh), dan chip-nya sendiri diburamkan oleh .body::before. Itu separuh
   sisa dari kesan "berantakan" saat disorot.

   Angkanya DITURUNKAN dari token, bukan ditulis tangan, dan menjumlahkan seluruh
   isi .body dari dasar ke atas:
     var(--nd-sp-3)               padding bawah .body
     1.3 * var(--nd-fs-2xs)       satu baris .movie-meta-line
     var(--nd-sp-1)               gap flex judul & meta
     2 * 1.3 * var(--nd-fs-sm)    judul yang dikunci 2 baris
     var(--nd-sp-2)               jarak aman chip ke judul

   JEBAKAN: baris meta WAJIB ikut dihitung meski di data sekarang hampir selalu
   kosong (display_category terisi cuma untuk segelintir film). Begitu kategori
   terisi, judul terdorong naik setinggi baris itu — dan versi yang memakai angka
   mati 2.275rem menyisakan celah tinggal 0,4px alias chip menempel ke judul.
   Dengan rumus ini celahnya 8px saat kategori terisi dan ~24px saat kosong,
   diukur di 320/390/1280/1920. Semuanya rem, jadi ikut membesar saat :root
   font-size naik di 1920 (17px) dan 2560 (18px).
   .body TIDAK digeser sama sekali, jadi tinggi kartu tetap dan CLS tetap 0. */
body.nd-ui .card .poster-tags {
  inset-block-end: calc(2 * 1.3 * var(--nd-fs-sm) + 1.3 * var(--nd-fs-2xs)
                       + var(--nd-sp-1) + var(--nd-sp-3) + var(--nd-sp-2));
}

/* ---------- Saat disorot: kaca menebal + pendar menyala, BUKAN pelat ---------- */

@media (hover: hover) and (pointer: fine) {
  body.nd-ui .card .body {
    transition: padding-block-start var(--nd-dur-2) var(--nd-ease-out);
  }
  /* Scrim naik lebih tinggi. Karena stop gradiennya dalam PERSEN, seluruh ramp
     ikut meregang mengikuti kotak yang tumbuh — tidak ada satu warna pun yang
     di-swap, jadi tidak ada kedipan dan kontras justru NAIK saat disorot
     (11.3:1 → 12.9:1 di poster putih, diukur di puncak judul). */
  body.nd-ui .card:hover .body,
  body.nd-ui .card:focus-within .body { padding-block-start: var(--nd-sp-16); }

  body.nd-ui .card:hover .body::after,
  body.nd-ui .card:focus-within .body::after { opacity: 1; }

  body.nd-ui .card:hover .body::before,
  body.nd-ui .card:focus-within .body::before {
    backdrop-filter: blur(14px) saturate(1.3);
    -webkit-backdrop-filter: blur(14px) saturate(1.3);
  }
}

/* ---------- Kartu iklan tidak punya poster ---------- */

body.nd-ui .card.card-ad { aspect-ratio: 3 / 4; }
body.nd-ui .card.card-ad .body {
  position: static;
  background: none;
  backdrop-filter: none;
  padding: var(--nd-sp-2) var(--nd-sp-3);
}
body.nd-ui .card.card-ad .body::before { content: none; }
/* Kartu iklan tidak punya poster, jadi tidak ada apa pun untuk disinari —
   pendar aksen dimatikan di sini supaya slot iklan tidak ikut menyala merah. */
body.nd-ui .card.card-ad .body::after { content: none; }
body.nd-ui .card.card-ad .title { color: var(--nd-t2); text-shadow: none; }

@media (prefers-reduced-motion: reduce) {
  /* Tanpa gerak: padding langsung disamakan dengan keadaan diam, jadi scrim tidak
     naik sama sekali. Pendar & blur TETAP menyala — itu umpan balik, bukan gerak —
     dan durasinya sudah dipangkas jadi 1ms lewat token di blok reduced-motion
     nd-tokens.css, jadi tidak ada animasi yang tersisa. */
  body.nd-ui .card:hover .body,
  body.nd-ui .card:focus-within .body { padding-block-start: var(--nd-sp-12); }
}

/* ============================================================
   10. KARTU "HISTORY NONTON" — tema yang SAMA dengan kartu film
   Sebelumnya rail ini memakai bentuk sendiri: thumbnail kecil 72x96 di kiri dan
   teks di kanan, sehingga terlihat seperti komponen dari situs lain ketika
   bersanding dengan grid kartu di bawahnya. Sekarang bentuknya mengikuti .card:
   ukuran kartu = ukuran poster, teks mengambang di atasnya.

   Markup-nya dibangun di sisi JS dan TIDAK diubah — hanya tampilannya.
   ============================================================ */

body.nd-ui .watch-history-card {
  position: relative;
  display: block;
  aspect-ratio: 3 / 4;
  inline-size: 100%;
  border: 0;
  border-radius: var(--nd-r-3);
  overflow: hidden;
  isolation: isolate;
  background: var(--nd-s2);
  text-decoration: none;
  transition: box-shadow var(--nd-dur-2) var(--nd-ease-out);
}

body.nd-ui .watch-history-card-poster,
body.nd-ui .watch-history-card-fallback {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  border-radius: 0;
  object-fit: cover;
  transition: transform var(--nd-dur-3) var(--nd-ease-out);
}

@media (hover: hover) and (pointer: fine) {
  body.nd-ui .watch-history-card:hover { box-shadow: var(--nd-e3); }
  body.nd-ui .watch-history-card:hover .watch-history-card-poster,
  body.nd-ui .watch-history-card:hover .watch-history-card-fallback { transform: scale(1.06); }
}

body.nd-ui .watch-history-card-body {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: var(--nd-sp-8) var(--nd-sp-3) var(--nd-sp-3);
  /* Ramp SAMA PERSIS dengan .card .body di §9. Rail riwayat berdiri tepat di
     sebelah grid kartu di beranda; kalau salah satunya pakai ramp 4-stop lama,
     perbedaan "siku"-nya langsung kelihatan bersisian. Satu bahasa visual. */
  background: linear-gradient(to top,
              rgba(5, 6, 8, .93) 0%,
              rgba(5, 6, 8, .90) 20%,
              rgba(5, 6, 8, .86) 38%,
              rgba(5, 6, 8, .78) 54%,
              rgba(5, 6, 8, .62) 68%,
              rgba(5, 6, 8, .38) 80%,
              rgba(5, 6, 8, .18) 90%,
              rgba(5, 6, 8, .06) 96%,
              rgba(5, 6, 8, 0) 100%);
}

body.nd-ui .watch-history-card-body::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  backdrop-filter: blur(10px) saturate(1.15);
  -webkit-backdrop-filter: blur(10px) saturate(1.15);
  mask-image: linear-gradient(to top, #000 0%, #000 42%, transparent 100%);
  -webkit-mask-image: linear-gradient(to top, #000 0%, #000 42%, transparent 100%);
}

body.nd-ui .watch-history-card-title {
  margin: 0;
  color: #fff;
  font: 800 var(--nd-fs-sm) / var(--nd-lh-snug, 1.3) var(--nd-font-text);
  text-shadow: 0 1px 12px rgba(0, 0, 0, .8);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Judul tidak lagi berjalan (marquee). CSS lama memberinya
   `white-space: nowrap; display: inline-block; min-width: 100%` supaya bisa
   digeser — efeknya sekarang judul panjang terpotong KERAS di tepi kanan tanpa
   elipsis. Ketiganya dinetralkan supaya judul membungkus rapi dua baris. */
body.nd-ui .watch-history-card-title-wrap { overflow: hidden; }
body.nd-ui .watch-history-card-title-wrap .watch-history-card-title,
body.nd-ui .watch-history-card-title {
  animation: none;
  transform: none;
  transition: none;
  white-space: normal;
  min-inline-size: 0;
  inline-size: 100%;
  will-change: auto;
}

body.nd-ui .watch-history-card-time,
body.nd-ui .watch-history-card-meta {
  color: rgba(255, 255, 255, .72);
  font-size: var(--nd-fs-3xs);
  text-shadow: 0 1px 8px rgba(0, 0, 0, .75);
}

body.nd-ui .watch-history-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--nd-sp-2);
}

body.nd-ui .watch-history-card-cta {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: #fff;
  font-size: var(--nd-fs-3xs);
  font-weight: 800;
  background: var(--nd-accent);
  border-radius: var(--nd-r-full);
  padding: 4px var(--nd-sp-2);
  white-space: nowrap;
}

/* Tombol hapus: melayang di pojok kartu, bukan mendorong tata letak. */
body.nd-ui .watch-history-card-wrap { position: relative; }
body.nd-ui .watch-history-card-remove {
  position: absolute;
  z-index: 3;
  inset-block-start: var(--nd-sp-2);
  inset-inline-end: var(--nd-sp-2);
  inline-size: 1.75rem;
  block-size: 1.75rem;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--nd-r-full);
  background: rgba(0, 0, 0, .55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: #fff;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--nd-dur-1) var(--nd-ease-out), background-color var(--nd-dur-1) var(--nd-ease-out);
}
body.nd-ui .watch-history-card-wrap:hover .watch-history-card-remove,
body.nd-ui .watch-history-card-remove:focus-visible { opacity: 1; }
body.nd-ui .watch-history-card-remove:hover { background: var(--nd-danger-solid, var(--nd-danger)); }

/* Di perangkat sentuh tidak ada hover, jadi tombol hapus selalu tampak. */
@media (hover: none) {
  body.nd-ui .watch-history-card-remove { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  body.nd-ui .watch-history-card:hover .watch-history-card-poster,
  body.nd-ui .watch-history-card:hover .watch-history-card-fallback { transform: none; }
}

/* Thumbnail di popup riwayat jauh lebih kecil daripada kartu grid, jadi judul
   fallback-nya dipotong lebih pendek supaya tetap terbaca. */
body.nd-ui .watch-history-thumb-fallback { container-type: inline-size; }
body.nd-ui .watch-history-thumb-fallback .nd-fb-title {
  -webkit-line-clamp: 3;
  font-size: 7px;
  line-height: 1.2;
}

/* ============================================================
   11. "YOU MAY LIKE" — judul ikut mengambang di atas poster
   Permintaan owner berlaku untuk SEMUA halaman yang menampilkan kartu film,
   termasuk kolom saran di halaman detail. Markup tetap: .you-may-like-name
   hanya dipindah posisinya ke atas gambar.
   ============================================================ */

body.nd-ui .you-may-like-card {
  position: relative;
  aspect-ratio: 3 / 4;
  display: block;
  overflow: hidden;
  border-radius: var(--nd-r-3);
  isolation: isolate;
}

body.nd-ui .you-may-like-img,
body.nd-ui .you-may-like-fallback,
body.nd-ui .you-may-like-card img {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  aspect-ratio: auto;
  transition: transform var(--nd-dur-3) var(--nd-ease-out);
}

@media (hover: hover) and (pointer: fine) {
  body.nd-ui .you-may-like-card:hover .you-may-like-img,
  body.nd-ui .you-may-like-card:hover .you-may-like-fallback { transform: scale(1.06); }
}

body.nd-ui .you-may-like-name {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 2;
  min-block-size: 0;
  padding: var(--nd-sp-6) var(--nd-sp-2) var(--nd-sp-2);
  color: #fff;
  text-shadow: 0 1px 12px rgba(0, 0, 0, .8);
  background: linear-gradient(to top,
              rgba(0, 0, 0, .94) 0%,
              rgba(0, 0, 0, .78) 34%,
              rgba(0, 0, 0, .40) 66%,
              rgba(0, 0, 0, 0) 100%);
}

body.nd-ui .you-may-like-name::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  backdrop-filter: blur(10px) saturate(1.15);
  -webkit-backdrop-filter: blur(10px) saturate(1.15);
  mask-image: linear-gradient(to top, #000 0%, #000 42%, transparent 100%);
  -webkit-mask-image: linear-gradient(to top, #000 0%, #000 42%, transparent 100%);
}

@media (prefers-reduced-motion: reduce) {
  body.nd-ui .you-may-like-card:hover .you-may-like-img,
  body.nd-ui .you-may-like-card:hover .you-may-like-fallback { transform: none; }
}
