/* Janévalla Bandung — mockup v2.
   Tata letaknya bukan kira-kira: koordinat tiap elemen dibaca langsung dari
   XML slide di dalam "Website Mockup Design.pptx" (kanvas 18288000x10287000
   EMU = 16:9) lalu dipakai apa adanya sebagai persen di dalam .stage.
   Karena itu .stage HARUS 16:9 -- persen di kotak beraspek lain akan
   menggeser semuanya. Sisa layar di luar stage diisi tekstur beton yang sama,
   jadi letterbox-nya tidak kelihatan. */

:root {
  --beton:      #FACF04;   /* kuning brand, solid */
  --beton-rgb:  250,207,4; /* komponen rgb-nya, untuk rgba() -- ditulis ulang build_v2 */
  /* Sampul (halaman 1-2, deck Canva hal. 5-6): warna solid, lalu tekstur,
     lalu vektor gedung, lalu isi. Grain-nya dipakai bersama modul tekstur. */
  --sampul: #59384E;
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  --tinta:      #17161a;
  --plum:       #522a44;
  --plum-rgb:   82,42,68;
  /* Aksen terpisah (Site design). Tombol, panah carousel, dan titik navigasi
     dulu satu warna --plum; sekarang masing-masing bisa diisi sendiri, dan
     yang dibiarkan kosong tetap ikut --plum. */
  --tombol-latar: var(--plum);
  --panah:        var(--plum);
  --panah-rgb:    var(--plum-rgb);
  --titik:        var(--plum);
  --titik-rgb:    var(--plum-rgb);
  --gelap-neon: #14082e;
  --font-teks:  "Karla", ui-sans-serif, system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --font-judul: "Monument Extended", "Poppins", var(--font-teks);
  --font-serif: "Karla", Georgia, serif;   /* baris "The Origins of": Karla tebal miring */
  /* 1pt = 1/1440 lebar slide (20 inci pada 72pt/inci). */
  --pt: 0.0694cqw;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
/* Gulir mendatar dipakai untuk menggeser carousel; tanpa ini usapan dua jari
   ke samping di macOS/Chrome memicu "kembali/maju" riwayat peramban. */
html, body { overscroll-behavior-x: none; }
body {
  margin: 0; color: var(--tinta); font: 400 16px/1.6 var(--font-teks);
  overflow-x: hidden; isolation: isolate;
  background: var(--beton);
}
/* Tekstur di atas warna latar: lapisan tetap di z -1 (di bawah semua isi, di
   atas latar body). Pola bawaan adalah mask SVG yang diwarnai --tekstur-warna;
   tekstur unggahan sendiri dipasang sebagai gambar ubin. Dipilih lewat
   <html data-tekstur>, kekuatannya --tekstur-kuat (0..1). */
body::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  opacity: var(--tekstur-kuat, 0); background: var(--tekstur-warna, var(--tinta));
  -webkit-mask: var(--tekstur, none) 0 0 / var(--tekstur-ukuran, 28px) repeat;
  mask: var(--tekstur, none) 0 0 / var(--tekstur-ukuran, 28px) repeat;
}
html:not([data-tekstur]) body::before, html[data-tekstur=""] body::before { display: none; }
html[data-tekstur="titik"]  { --tekstur: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28'%3E%3Ccircle cx='14' cy='14' r='1.7' fill='%23fff'/%3E%3C/svg%3E"); }
html[data-tekstur="garis"]  { --tekstur: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28'%3E%3Cpath d='M-4 32 32-4M-4 4 4-4M24 32l8-8' stroke='%23fff' stroke-width='1.4'/%3E%3C/svg%3E"); }
html[data-tekstur="kisi"]   { --tekstur: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28'%3E%3Cpath d='M0 .5H28M.5 0V28' stroke='%23fff'/%3E%3C/svg%3E"); }
html[data-tekstur="silang"] { --tekstur: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28'%3E%3Cpath d='M-4 32 32-4M-4-4l36 36' stroke='%23fff' stroke-width='1'/%3E%3C/svg%3E"); }
html[data-tekstur="kertas"] { --tekstur-ukuran: 180px; --tekstur: var(--grain); }
html[data-tekstur="beton"]  { --tekstur-ukuran: 240px; --tekstur: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.32' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1.4 -.2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }
html[data-tekstur="gambar"] body::before {
  background: var(--tekstur-gambar) 0 0 / var(--tekstur-ukuran, 320px) repeat;
  -webkit-mask: none; mask: none;
}
img { display: block; max-width: 100%; }
h1, h2, h3 { margin: 0; font-family: var(--font-judul); font-weight: 800; letter-spacing: -.01em; }
p { margin: 0; }
a { color: inherit; text-decoration: none; }

/* ---------- Deck ----------
   Satu scroll = satu section, tidak ada halaman yang menggeser. Section
   ditumpuk di tempat dan ditukar, persis seperti menekan panah di deck Canva.
   Isi yang lebih tinggi dari layar tetap bisa digulir di dalam section-nya
   sendiri; deck baru pindah setelah gulirannya mentok. */
.deck { position: fixed; inset: 0; z-index: 2; overflow: hidden; }
.slide {
  position: absolute; inset: 0; display: grid; place-items: center;
  overflow: hidden; overscroll-behavior: contain;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .7s ease, visibility 0s linear .7s;
}
.slide.aktif {
  opacity: 1; visibility: visible; pointer-events: auto;
  transition: opacity .7s ease, visibility 0s;
}
/* Titik penunjuk posisi di kanan layar. */
.deck-titik {
  position: fixed; right: 18px; top: 50%; translate: 0 -50%; z-index: 40;
  display: flex; flex-direction: column; gap: 10px;
}
.deck-titik button {
  width: 9px; height: 9px; padding: 0; border: 0; border-radius: 999px; cursor: pointer;
  background: rgba(var(--titik-rgb),.32); transition: background-color .3s ease, height .3s ease;
}
.deck-titik button[aria-current="true"] { background: var(--titik); height: 22px; }
/* Dua halaman pertama berlatar plum: titik plum hilang di sana. */
body:has(#top.aktif) .deck-titik button, body:has(#origins.aktif) .deck-titik button { background: rgba(255,255,255,.4); }
body:has(#top.aktif) .deck-titik button[aria-current="true"],
body:has(#origins.aktif) .deck-titik button[aria-current="true"] { background: #fff; }

/* ---------- Menu atas ----------
   Satu bar tetap untuk seluruh deck. Muncul mulai section ke-3 (di deck
   navigasinya memang baru ada dari slide 3). Sorotan menandai section aktif;
   "Book Now" tautan keluar jadi tidak pernah tersorot. */
.topbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 40;
  display: flex; justify-content: flex-end; gap: clamp(14px, 2.6vw, 46px);
  padding: 22px max(18px, 4vw);
  opacity: 0; pointer-events: none; transition: opacity .5s ease;
  /* Kuning tembus pandang yang memudar ke bawah, seperti versi ponsel: kartu
     yang mengintip dari atas (Facilities) dan tulisan tegak lewat di bawah
     menu, dan tanpa ini labelnya tercetak di atas foto. */
  background: linear-gradient(to bottom, rgba(var(--beton-rgb),.94) 55%, rgba(var(--beton-rgb),0));
  padding-bottom: 34px;
}
.topbar.tampil { opacity: 1; pointer-events: auto; }
.topbar-menu { display: contents; }
.topbar a { position: relative; font-size: clamp(15px, 1.35vw, 21px); font-weight: 700; color: var(--tinta); }
.topbar a span { position: relative; }
.topbar a span::after {
  content: ""; position: absolute; left: 50%; right: 50%; bottom: -7px; height: 2px;
  background: var(--plum); transition: left .3s ease, right .3s ease;
}
.topbar a:hover span::after { left: 0; right: 0; }
.topbar a[aria-current="true"] { color: var(--plum); font-weight: 700; }
.topbar a[aria-current="true"] span::after { left: 0; right: 0; }
/* Titik penanda di kiri label yang aktif. */
.topbar a[aria-current="true"] span::before {
  content: ""; position: absolute; left: -12px; top: 50%; translate: 0 -50%;
  width: 6px; height: 6px; border-radius: 999px; background: var(--plum);
}

/* ---------- Slogan yang berpindah ----------
   "Bold with Originality" / "Rich with Character": di kiri-kanan tengah 24 HOUR
   pada slide Origins, lalu meluncur ke pojok bawah slide intro. Lebar
   max-content + translate -100% supaya teksnya bisa rata kanan ke satu jangkar
   tanpa lompatan perataan saat berpindah. */
.slogan-terbang { position: fixed; inset: 0; z-index: 3; display: grid; place-items: center; pointer-events: none;
  opacity: 0; transition: opacity .5s ease; }
.slogan-terbang .stage { background: none; }
.slogan-terbang[data-pos="1"], .slogan-terbang[data-pos="2"] { opacity: 1; }
.slogan-terbang .sudut {
  position: absolute; margin: 0; width: max-content; top: calc(var(--y) * 1%); left: calc(var(--x) * 1%);
  translate: var(--tr, 0) 0;
  transition: left .9s cubic-bezier(.4,0,.2,1), top .9s cubic-bezier(.4,0,.2,1), translate .9s cubic-bezier(.4,0,.2,1);
}
/* Slogan berpusat di garis tengah huruf 24 HOUR (~52.4% tinggi kanvas). */
/* Di halaman sampul slogannya putih; begitu mendarat di intro yang kuning ia
   kembali ke warna aksen. */
.slogan-terbang .sudut { transition-property: left, top, translate, color; }
.slogan-terbang[data-pos="0"] .sudut, .slogan-terbang[data-pos="1"] .sudut { color: var(--origins, #fff); }
/* Slogan statis (dipakai di ponsel) ikut putih: section origins berlatar plum. */
#origins .sudut { color: var(--origins, #fff); }
.slogan-terbang .slogan-1 { --x: 28.8; --y: 50.3; --tr: -100%; }   /* 2% jarak dari huruf 2 */   /* posisi awal = posisi Origins */
.slogan-terbang .slogan-2 { --x: 71.2; --y: 50.3; --tr: 0; }
.slogan-terbang[data-pos="2"] .slogan-1, .slogan-terbang[data-pos="3"] .slogan-1 { --x: 9.77; --y: 89.44; --tr: 0; }
.slogan-terbang[data-pos="2"] .slogan-2, .slogan-terbang[data-pos="3"] .slogan-2 { --x: 88; --y: 89.44; --tr: -100%; }   /* 88, bukan 91.11: menjauh dari tombol WhatsApp */
/* !important: mengalahkan .el.teks { display: flex } yang datang belakangan. */
.hanya-ponsel { display: none !important; }
@media (max-width: 759px), (max-height: 429px) {
  .hanya-desktop { display: none !important; }
  .hanya-ponsel { display: flex !important; }
}

/* ---------- Logo yang berpindah ----------
   Satu lockup (mark + wordmark, sesuai brand guideline tidak boleh terpisah)
   untuk seluruh deck; posisinya berpindah antar section persis seperti di
   Canva (tengah -> atas-tengah -> pojok kiri atas). --x/--w adalah kotak
   MARK-nya; wordmark 3.5x lebar mark, dipusatkan di bawahnya. */
.logo-terbang { position: fixed; inset: 0; z-index: 3; display: grid; place-items: center; pointer-events: none;
  transition: opacity .4s ease; }
/* Di section kontak logonya statis (ikut menggulir bersama isinya); lapisan
   terbang dipadamkan dan lockup salinan di dalam section yang tampil. */
/* Geometrinya tetap seperti pos 3 -- tanpa ini --x/--y/--w kosong di pos 4,
   width-nya jadi auto, dan logonya membesar sekejap sambil memudar. */
.logo-terbang[data-pos="4"] { opacity: 0; }
.logo-terbang[data-pos="4"] .logo-lockup { --x: 5.4; --y: 7.31; --w: 2.3; }
/* Section kontak tidak punya .stage, jadi kotak 16:9 yang dipakai lapisan
   terbang dihitung ulang di sini: lebar min(100vw, 100svh*16/9), dipusatkan.
   Angkanya = posisi 3 (x 5.4 - 2.3*1.25, y 7.31, lebar 2.3*3.5). */
.logo-lockup.logo-statis {   /* spesifisitas > .logo-lockup, yang ditulis sesudahnya */
  --sw: min(100vw, calc(100svh * 16 / 9)); --sh: calc(var(--sw) * 9 / 16);
  --logo: var(--logo-gelap, #fff); z-index: 3; pointer-events: none;
  left: calc((100vw - var(--sw)) / 2 + var(--sw) * .02525);
  top: calc((100svh - var(--sh)) / 2 + var(--sh) * .0731);
  width: calc(var(--sw) * .0805);
}
.logo-terbang .stage { background: none; }
.logo-lockup {
  position: absolute; display: flex; flex-direction: column; align-items: center;
  left: calc((var(--x) - var(--w) * 1.25) * 1%); top: calc(var(--y) * 1%);
  width: calc(var(--w) * 3.5 * 1%);
  transition: left .9s cubic-bezier(.4,0,.2,1), top .9s cubic-bezier(.4,0,.2,1),
              width .9s cubic-bezier(.4,0,.2,1), opacity .5s ease;
}
/* Mark dan wordmark PNG dipakai sebagai mask, warnanya dari --logo: jadi
   bisa diganti dari Site design (gelap di kuning, terang di atas menara).
   <img> di dalamnya transparan, hanya memberi ukuran/rasio. */
.logo-mark, .logo-word {
  display: block; background: var(--logo, #fff); transition: background-color .6s ease;
  -webkit-mask: var(--m) center / contain no-repeat; mask: var(--m) center / contain no-repeat;
}
.logo-mark img, .logo-word img { display: block; width: 100%; height: auto; opacity: 0; }
/* Site design: "pakai warna aslinya". Mask dilepas supaya berkas logo tampil
   apa adanya -- gradien, dua warna, emboss -- bukan silhouette satu warna. */
html[data-logo-asli] .logo-mark, html[data-logo-asli] .logo-word {
  background: none; -webkit-mask: none; mask: none;
}
html[data-logo-asli] .logo-mark img, html[data-logo-asli] .logo-word img { opacity: 1; }
/* Sama untuk vektor gedung: tanpa ini brightness(0) invert(1) memutihkannya,
   jadi panel yang sudah berwarna di berkasnya tetap tampil putih. */
html[data-gedung-asli] .tirai .menara, html[data-gedung-asli] #origins .lineart { filter: none; }
.logo-mark { width: calc(100% / 3.5); margin-bottom: 8%; }
.logo-word { width: 100%; }
/* Logo versi putih di semua section (permintaan 2026-09-17); --logo-gelap dan
   --logo-terang tetap bisa diisi dari Site design kalau mau dibedakan. */
.logo-terbang[data-pos="0"] .logo-lockup { --x: 47.4; --y: 37.0; --w: 5.2; --logo: var(--logo-terang, #fff); }
.logo-terbang[data-pos="1"] .logo-lockup { --x: 48.15; --y:  7.51; --w: 3.7; --logo: var(--logo-gelap, #fff); }
.logo-terbang[data-pos="2"] .logo-lockup { --x:  5.4; --y:  7.31; --w: 2.3; --logo: var(--logo-terang, #fff); }
.logo-terbang[data-pos="3"] .logo-lockup { --x:  5.4; --y:  7.31; --w: 2.3; --logo: var(--logo-gelap, #fff); }

/* ---------- Cincin pemuatan ----------
   Menutup layar sampai aset halaman pertama selesai dimuat dan pop-up
   pengumuman sempat terbuka. Determinate: busurnya terisi dari kosong ke penuh
   mengikuti jumlah berkas yang sudah selesai (app.js menulis --p dan
   aria-valuenow), bukan animasi berputar yang tidak berarti apa-apa. */
.pemuat {
  position: fixed; inset: 0; z-index: 200; display: grid; place-items: center; gap: 14px;
  grid-auto-flow: row; background: var(--sampul); color: #fff;
  transition: opacity .45s ease, visibility 0s linear .45s;
}
.pemuat[data-selesai] { opacity: 0; visibility: hidden; pointer-events: none; }
.pemuat-cincin { width: clamp(76px, 12vmin, 120px); height: auto; transform: rotate(-90deg); }
.pemuat-jalur, .pemuat-isi {
  fill: none; stroke-width: 5; r: 52; cx: 60; cy: 60;
}
.pemuat-jalur { stroke: rgba(255,255,255,.22); }
.pemuat-isi {
  stroke: currentcolor; stroke-linecap: round;
  stroke-dasharray: 326.73;                      /* 2 * pi * 52 */
  stroke-dashoffset: calc(326.73 * (1 - var(--p, 0)));
  transition: stroke-dashoffset .25s ease;
}
.pemuat-angka { margin: 0; font-size: 13px; letter-spacing: .18em; font-variant-numeric: tabular-nums; }
@media (prefers-reduced-motion: reduce) { .pemuat-isi { transition: none; } }

/* ---------- Tirai ----------
   Dua menara neon yang di slide 1 menutup di tengah lalu membuka ke sudut
   di slide 2. Posisi tutup/buka keduanya diambil dari XML slide. */
.tirai { position: fixed; inset: 0; z-index: 1; display: grid; place-items: center; pointer-events: none;
  transition: background-color .9s ease; }
/* Saat tertutup, latar gelap di balik kedua panel: di kanvas potret ponsel
   (asio 0.45-0.5) sambungan diagonalnya menyisakan serpihan di tepi yang
   tidak tertutup gambar menara, dan kuning halaman mengintip di sana. Latar
   ini senada dengan tepi gambar, dan memudar begitu tirainya membuka. */
/* Gambar latar situs (Site design) juga dipakai di halaman 1-2: tanpa ini
   sampul solid menutupinya dan dua halaman pertama tampak tidak ikut setelan. */
.tirai[data-buka="0"], .tirai[data-buka="1"] {
  background: var(--sampul) var(--latar-gambar, none) center/cover no-repeat;
}
/* Lapisan tekstur: anak absolut (bukan item grid), digambar sebelum .stage,
   jadi ia duduk di atas warna solid dan di bawah vektor gedung. */
.tirai::before {
  content: ""; position: absolute; inset: 0; opacity: 0;
  background: #fff; transition: opacity .9s ease;
  -webkit-mask: var(--grain) 0 0 / 180px repeat; mask: var(--grain) 0 0 / 180px repeat;
}
.tirai[data-buka="0"]::before, .tirai[data-buka="1"]::before { opacity: .06; }
.tirai .stage { background: none; }
.tirai .menara {
  /* Vektor gedung dijadikan garis putih tipis apa pun warna berkas aslinya:
     brightness(0) membuatnya hitam pekat, invert(1) membalikkannya jadi putih,
     dan alfa berkas tetap utuh. Jadi aset boleh diganti tanpa menyesuaikan CSS.
     Tidak dicerminkan lagi (--flip 1): kedua salinan di deck memang sama arah. */
  /* Berkas panelnya diekspor dari deck SUDAH dengan transparansi 15%
     (alfa maksimumnya 40/255), jadi di sini tidak diturunkan lagi -- kalau
     dikali .15 sekali lagi, garisnya tinggal 2% dan nyaris tak terlihat.
     Vektor tengah di halaman 2 sebaliknya beralfa penuh, jadi ia yang
     diturunkan ke .15 di aturannya sendiri. */
  opacity: var(--tirai-kuat, 1); filter: brightness(0) invert(1);
  transition: left 1.15s cubic-bezier(.4,0,.2,1), top 1.15s cubic-bezier(.4,0,.2,1), opacity .8s ease;
}
/* Kedua panel memakai gambar yang sama, tapi yang kanan diputar 180 derajat
   dari yang kiri (-135 -> +45). Siluet menara itu asimetris, jadi hanya
   dengan pembalikan ini keduanya saling mengunci seperti kepingan puzzle
   di sepanjang diagonal -- kalau rotasinya sama, keduanya cuma bertumpuk
   sejajar dan menyisakan celah.
   Posisi tutup & buka dua-duanya titik-simetris terhadap pusat layar; angka
   ini memang sudah begitu di slide 1 dan slide 2 deck. */
/* Berkasnya sudah berisi panel yang diputar (ekspor Canva), jadi di sini tidak
   ada rotasi: X/Y = sudut kiri-atas kotak pembatas di deck hal. 5 (kanvas
   1920x1080) -- kiri -1403.3/-1434.2, kanan 688.5/-610.7. Dicocokkan dengan
   PNG ekspor halaman itu: tumpang tindih garisnya 84%.
   Yang terbuka menggeser keduanya keluar ~35% lebar kanvas. */
.tirai .m-kiri  { --x: -73.09; --y: -132.80; }
.tirai .m-kanan { --x:  35.86; --y:  -56.55; }
.tirai[data-buka="1"] .m-kiri  { --x: -108.09; --y: -149.80; }
.tirai[data-buka="1"] .m-kanan { --x:   70.86; --y:  -39.55; }
.tirai[data-buka="2"] .m-kiri  { --x: -108.09; --y: -149.80; opacity: 0; }
.tirai[data-buka="2"] .m-kanan { --x:   70.86; --y:  -39.55; opacity: 0; }
.stage {
  position: relative; width: min(100%, calc(100svh * 16 / 9)); aspect-ratio: 16 / 9;
  container-type: size;
}
.slide .stage { overflow: hidden; }
/* Satu penempat untuk semua: persis kotak dari XML slide. */
.el {
  position: absolute;
  left: calc(var(--x) * 1%); top: calc(var(--y) * 1%);
  width: calc(var(--w) * 1%); height: calc(var(--h) * 1%);
  transform: rotate(var(--rot, 0deg)) scaleX(var(--flip, 1));
}
.el.teks { display: flex; align-items: flex-start; line-height: 1.15; }
.el.tengah { justify-content: center; text-align: center; }
.el img { width: 100%; height: 100%; object-fit: contain; }
.el.isi img { object-fit: cover; }
img.el { object-fit: contain; }

.judul   { font-family: var(--font-judul); color: var(--plum); }
.sudut   { font-size: calc(28 * var(--pt)); font-weight: 700; color: var(--plum); letter-spacing: .01em; white-space: nowrap; }
.sudut.kanan { justify-content: flex-end; text-align: right; }
.sudut.pusat { justify-content: center; text-align: center; }
.nav-tk  { font-size: calc(18 * var(--pt)); color: #000; }
.nav-tk:hover { text-decoration: underline; text-underline-offset: .35em; }

/* ---------- Menara neon ---------- */
.menara { pointer-events: none; }
.menara img { object-fit: fill; }

/* ---------- Slide 1: splash ---------- */
#top .lockup { animation: naikHalus 1.1s cubic-bezier(.2,.7,.2,1); }
@keyframes naikHalus { from { opacity: 0; transform: translateY(3cqh) scale(.9); } }
@keyframes terbangMasuk { from { opacity: 0; transform: translate(-6%, 34%); } }
/* Keterangan kamar/produk/acara yang berganti: muncul naik halus, bukan
   berganti seketika -- di desktop maupun tumpukan ponsel. */
.rdesk:not([hidden]) { animation: naikHalus .55s ease both; }
@keyframes pudarMasuk { from { opacity: 0; } }
/* Secret Corner & Happening: fade-in polos, tanpa geseran (permintaan). */
.sdesk:not([hidden]), #sudut .sjudul, #happening .sjudul { animation: pudarMasuk .6s ease both; }

/* ---------- Slide 2: origins ---------- */
/* Line-art bangunannya tersingkap dari bawah ke atas seperti sedang
   digambar. Sumbernya raster, jadi tidak bisa animasi garis sungguhan --
   clip-path wipe memberi kesan yang sama tanpa perlu SVG path. */
#origins .lineart {
  /* Sama seperti menara: diputihkan lalu diturunkan ke ~20%, seperti di deck. */
  opacity: var(--gedung-kuat, .15); mix-blend-mode: normal; filter: brightness(0) invert(1);
  clip-path: inset(100% 0 0 0);
  transition: clip-path 1.6s cubic-bezier(.35,0,.2,1), opacity .8s ease;
}
.js-v2 #origins.tampil .lineart { clip-path: inset(0 0 0 0); }
#origins .serif {
  font-family: var(--font-serif); font-weight: 700;
  font-size: calc(30 * var(--pt)); letter-spacing: .1em; color: var(--origins, #fff);
}
#origins .h24 { font-size: calc(134 * var(--pt)); line-height: .9; color: var(--origins, #fff); letter-spacing: -.015em; }

/* ---------- Slide 3: intro ---------- */
#intro .isi-teks {
  font-size: calc(24 * var(--pt)); line-height: 1.7; color: var(--plum);
  flex-direction: column; gap: .9em;
}
#intro .isi-teks strong { font-weight: 700; }
/* Menara menyapu masuk dari kiri-atas, seperti transisi slide 3 -> 4 di deck. */
#intro .menara { transition: transform 1.15s cubic-bezier(.2,.7,.2,1), opacity .9s ease; }
.js-v2 #intro .menara { opacity: 0; transform: rotate(-142.8deg) translate(-38%, 0); }
.js-v2 #intro.tampil .menara { opacity: 1; transform: rotate(-142.8deg); }

/* ---------- Slide 4-7: OUR ROOM ---------- */
/* Pembungkus ini transparan di desktop -- kartunya tetap diposisikan
   terhadap stage. Di layar sempit ia jadi wadah carousel tersendiri. */
.rstrip, .fstrip { display: contents; }

.rcard {
  position: absolute; margin: 0; padding: 0; border: 0; background: none; cursor: pointer;
  left: calc(var(--x) * 1%); top: calc(var(--y) * 1%);
  width: calc(var(--w) * 1%); height: calc(var(--h) * 1%);
  transition: left .85s cubic-bezier(.2,.7,.2,1), top .85s cubic-bezier(.2,.7,.2,1),
              width .85s cubic-bezier(.2,.7,.2,1), height .85s cubic-bezier(.2,.7,.2,1),
              opacity .5s ease;
}
.rcard img, .rcard video { width: 100%; height: 100%; object-fit: cover; }
/* Bayangan hanya di kartu tengah supaya ia lepas dari latar; kartu samping polos. */
.rcard[data-p="0"], .fslide[data-p="0"] { box-shadow: var(--bayang-aktif, 0 22px 50px rgba(0,0,0,.38)); }
/* Koordinat langsung dari slide: sisi kiri/kanan separuh keluar kanvas,
   yang aktif membesar ke tengah. */
.rcard[data-p="-1"] { --x: -10.28; --y: 27.49; --w: 38.39; --h: 45.22; opacity: 1; z-index: 1; }
.rcard[data-p="0"]  { --x: 23.74; --y: 19.04; --w: 52.52; --h: 62.13; opacity: 1; z-index: 3; }
.rcard[data-p="1"]  { --x: 71.71; --y: 27.49; --w: 38.16; --h: 45.22; opacity: 1; z-index: 1; }
.rcard[data-p="x"]  { --x: 23.74; --y: 19.04; --w: 52.52; --h: 62.13; opacity: 0; z-index: 0; pointer-events: none; }
/* Judul kamar aktif: 79pt di slide 5-7. Titik y deck-nya 11.01%, tapi pada
   ukuran itu kotak barisnya menyentuh tepi atas gambar; dinaikkan sedikit
   supaya ada jarak antara nama kamar dan fotonya. */
.rjudul {
  position: absolute; left: 0; right: 0; top: 10.8%; z-index: 4;
  text-align: center; font-size: calc(62 * var(--pt)); line-height: 1;
  transition: opacity .45s ease, transform .45s ease;
}
.rjudul[hidden] { display: none; }
/* Nama kamar terbang ke tempatnya, sama seperti judul fasilitas. Bedanya:
   fasilitas punya satu elemen per item yang saling menggantikan, sedangkan
   ini SATU elemen yang isinya berganti -- jadi keadaan awalnya dipasang ulang
   lewat kelas .terbang setiap kali kamarnya berubah. */
.js-v2 .rjudul {
  transition: transform .8s cubic-bezier(.3,.8,.25,1), opacity .55s ease;
  will-change: transform;
}
/* Naik saja, tanpa geser mendatar: kotak judul ini selebar panggung dan
   teksnya rata tengah, jadi geser mendatar tidak terlihat -- yang terjadi
   cuma kotaknya menjorok ke luar layar. */
.js-v2 .rjudul.terbang { transform: translateY(26%); opacity: 0; }
/* Deskripsi tepat di bawah gambar aktif (gambar berakhir di 81.17%). */
.rdesk {
  position: absolute; left: 25%; right: 25%; top: 86%; z-index: 4;
  text-align: center; color: var(--plum);
  font-size: calc(15 * var(--pt)); line-height: 1.55;
}
.rdesk[hidden] { display: none; }
/* Panah di tepi kiri/kanan: bagian bawah sudah terisi wordmark, label
   "OUR ROOM", dan deskripsi. */
.rnav-btn {
  position: absolute; top: 50%; translate: 0 -50%; z-index: 5;
  width: 3.4cqw; height: 3.4cqw; min-width: 36px; min-height: 36px; border-radius: 999px;
  border: .12cqw solid rgba(var(--panah-rgb),.4); background: transparent; color: var(--panah);
  font-size: 1.6cqw; cursor: pointer; line-height: 1;
}
/* Pembungkus ini tidak boleh ikut menata di desktop -- tombolnya menempel
   di tepi kiri/kanan gambar. Di layar sempit baru jadi baris tombol. */
.rnav { display: contents; }
.rnav-prev { left: 1.5%; }
.rnav-next { right: 1.5%; }
.rnav-btn:hover { background: rgba(var(--panah-rgb),.15); }

/* ---------- SECRET CORNER ----------
   Kartunya .rcard yang sama dengan kamar; yang disetel ulang di sini hanya
   posisinya -- dinaikkan supaya nama produk, kalimatnya, dan nama komunitas
   muat di bawah gambar. */
/* Dua bedanya dengan kamar: kartunya POTRET (produknya botol, gantungan
   kunci, pin -- foto tegak), dan kartu sisi tidak menjulur keluar kanvas
   karena kedua tepi sudah dipakai tulisan tegak.
   Panggungnya selalu 16:9, jadi persen lebar dan tinggi tidak sebanding:
   lebar% = tinggi% x 3/4 x 9/16 = tinggi% x 0.421875 untuk potret 3:4. */
/* Kartu 4:5 seperti foto potret Instagram, dan ukurannya SAMA di Secret Corner
   maupun Happening. Di kanvas 16:9, lebar% = 0.45 x tinggi% memberi 4:5 pas:
   (w*16)/(h*9) = 0.8. Tengah 27x60, samping 19.8x44. */
#sudut .rcard[data-p="-1"], #happening .rcard[data-p="-1"] { --x: 15.65; --y: 18; --w: 19.8; --h: 44; }
#sudut .rcard[data-p="0"],  #happening .rcard[data-p="0"]  { --x: 36.50; --y: 10; --w: 27.0; --h: 60; }
#sudut .rcard[data-p="1"],  #happening .rcard[data-p="1"]  { --x: 64.55; --y: 18; --w: 19.8; --h: 44; }
#sudut .rcard[data-p="x"],  #happening .rcard[data-p="x"]  { --x: 36.50; --y: 10; --w: 27.0; --h: 60; }
/* Panah di kiri/kanan gambar seperti Rooms, setinggi tengah kartu (Secret
   Corner 10+60/2 = 40%). Celah antara tulisan tegak dan kartu sisi: 8%-16%. */
#sudut .rnav-btn  { top: 40%; translate: 0 -50%; }
#sudut .rnav-prev { left: 9.5%; }
#sudut .rnav-next { right: 9.5%; }
/* Happening memakai kartu yang sama persis dengan Secret Corner, jadi panah dan
   teksnya duduk di ketinggian yang sama juga. Yang khas Happening hanya judul
   satu baris dan keterangan tiga baris (selengkapnya di pop-up). */
#happening .sjudul { top: 76%; white-space: nowrap; font-size: calc(40 * var(--pt)); }
#happening .sdesk  { top: 82.5%; left: 24%; right: 24%; }
#happening .rnav-btn { top: 40%; bottom: auto; translate: 0 -50%; }
#happening .rnav-prev { left: 9.5%; }
#happening .rnav-next { right: 9.5%; }
#happening .sdesk-kata { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; }
#happening .sdesk-kata p + p { margin-top: .4em; }
.sdesk-tombol { margin-top: 8px; padding: 7px 16px; font-size: calc(12 * var(--pt)); }
/* Nama produk di kartu sisi: kecil, di bawah gambarnya sendiri. Yang tengah
   sudah punya judul besar, jadi labelnya disembunyikan di sana. */
.slabel {
  position: absolute; left: 0; right: 0; top: 100%; padding-top: .5em;
  text-align: center; color: var(--plum); letter-spacing: .12em;
  font-size: calc(13 * var(--pt)); font-weight: 700;
}
.rcard[data-p="0"] .slabel, .rcard[data-p="x"] .slabel { display: none; }
/* Judul terbang seperti nama kamar, tapi di BAWAH gambar. */
.sjudul {
  position: absolute; left: 0; right: 0; top: 76%; z-index: 4;
  text-align: center; font-size: calc(58 * var(--pt)); line-height: 1;
  transition: opacity .45s ease, transform .45s ease;
}
.js-v2 .sjudul {
  transition: transform .8s cubic-bezier(.3,.8,.25,1), opacity .55s ease;
  will-change: transform;
}
.js-v2 .sjudul.terbang { transform: translateY(26%); opacity: 0; }
.sdesk {
  position: absolute; left: 22%; right: 22%; top: 82.5%; z-index: 4;
  text-align: center; color: var(--plum);
}
.sdesk[hidden] { display: none; }
.sdesk-kata  { font-size: calc(16 * var(--pt)); line-height: 1.5; }
.sdesk-mitra { font-size: calc(14 * var(--pt)); letter-spacing: .06em; opacity: .8; margin-top: .4em; }
.sjudul-tegak { font-size: calc(46 * var(--pt)); font-weight: 800; letter-spacing: .12em; }
/* Hampir sebesar judul di kiri. Kalimatnya hampir dua kali lebih panjang, jadi
   spasi hurufnya dirapatkan dan kotaknya (di build_v2.py) dilebarkan --
   nowrap supaya ia patah keluar layar kalau suatu saat kepanjangan, bukan
   melipat diam-diam jadi dua baris di tengah gambar. */
/* Sama persis dengan judul tegak di kiri (atas permintaan): ukuran, bobot, dan
   spasi hurufnya satu paket, supaya kedua sisi terbaca sebagai sepasang. */
.stempat { font-size: calc(46 * var(--pt)); font-weight: 800; letter-spacing: .12em;
  white-space: nowrap; color: var(--plum); }

/* ---------- Slide 8-10: FACILITIES ---------- */
.fslide {
  position: absolute; margin: 0; padding: 0; border: 0; background: none; cursor: pointer;
  left: calc(var(--x) * 1%); top: calc(var(--y) * 1%);
  width: calc(var(--w) * 1%); height: calc(var(--h) * 1%);
  transition: left .85s cubic-bezier(.2,.7,.2,1), top .85s cubic-bezier(.2,.7,.2,1),
              width .85s cubic-bezier(.2,.7,.2,1), height .85s cubic-bezier(.2,.7,.2,1),
              opacity .5s ease;
}
.fslide img, .fslide video { width: 100%; height: 100%; object-fit: cover; }
.fslide[data-p="-1"] { --x: 25.40; --y: -20.97; --w: 38.16; --h: 45.22; opacity: 1; }
.fslide[data-p="0"]  { --x: 30.96; --y: 20.73;  --w: 50.01; --h: 59.27; opacity: 1; z-index: 2; }
.fslide[data-p="1"]  { --x: 25.40; --y: 77.42;  --w: 38.16; --h: 45.22; opacity: 1; }
.fslide[data-p="x"]  { --x: 25.40; --y: 28.31;  --w: 38.16; --h: 45.22; opacity: 0; pointer-events: none; }
/* Label tegak di sisi kartu yang BELUM aktif. Begitu kartunya ke tengah,
   label ini hilang dan yang "berdiri lalu rebah" adalah judul deskripsinya
   (.fjudul di bawah) -- bukan salinan teks di bawah gambar. */
.flabel {
  position: absolute; left: -1.1cqw; bottom: 0; margin: 0; white-space: nowrap;
  transform-origin: left bottom; rotate: -90deg;
  font-size: calc(43 * var(--pt)); color: var(--plum); font-family: var(--font-judul);
  transition: opacity .4s ease;
  /* Tidak lebih panjang dari kartunya: nama acara yang panjang ("ROAD TO
     POCARI SWEAT RUN BDG 2026") kalau dibiarkan menjulur jauh melewati kartu
     dan menimpa kolom keterangan di sebelahnya. --h milik kartu diwarisi. */
  max-width: calc(var(--h) * 1cqh); overflow: hidden; text-overflow: ellipsis;
}
.fslide[data-p="0"] .flabel { opacity: 0; }
/* pointer-events:none supaya lapisan teks ini tidak menghalangi klik pada
   kartu di belakangnya; anak yang memang tombol dikembalikan ke auto. */
/* display:none membuat teksnya kedip mati-hidup dan animasinya terpotong.
   Dipakai opacity+visibility seperti .slide, jadi yang keluar sempat memudar
   sementara yang masuk terbang naik. */
.fteks {
  position: absolute; inset: 0; z-index: 3; pointer-events: none;
  opacity: 0; visibility: hidden;
  transition: opacity .55s ease, visibility 0s linear .55s;
}
.fteks[hidden] { display: block; }
.fteks:not([hidden]) {
  opacity: 1; visibility: visible;
  transition: opacity .55s ease, visibility 0s;
}
/* Titik jangkarnya tetap 7.75/33.99 seperti di slide, tapi tingginya
   mengalir: nama panjang menambah baris ke bawah, bukan menimpa isinya. */
.fteks-in { height: auto; }
.fjudul { font-size: calc(70 * var(--pt)); line-height: .95; color: var(--plum); }
/* Judul berupa ikon/logo: setinggi kira-kira satu baris judul, dibuat hitam
   apa pun warna aslinya supaya seragam dengan teks di sebelahnya. */
.fjudul img { display: block; height: calc(80 * var(--pt)); width: auto; max-width: 100%;
  object-fit: contain; object-position: left; filter: brightness(0); }
/* Kapital dimatikan di Site design: label yang di-uppercase CSS ikut. */
html[data-kapital="0"] .menu-sub, html[data-kapital="0"] .mbagian { text-transform: none; }
/* Judul fasilitas "terbang" ke tempatnya, sama seperti logo Janévalla yang
   berpindah antar section: satu elemen yang digeser dengan transform, bukan
   dua elemen yang saling menggantikan. Transisi, bukan @keyframes -- keyframes
   selalu mulai dari nol dan itu yang membuat gerakannya terasa terpotong saat
   fasilitas diganti sebelum animasinya selesai. */
.js-v2 .fjudul {
  transform: translate(-6%, 34%);
  transition: transform .8s cubic-bezier(.3,.8,.25,1), opacity .55s ease;
  will-change: transform;
}
.js-v2 .fteks:not([hidden]) .fjudul { transform: none; }
.fisi   { font-size: calc(15 * var(--pt)); line-height: 1.6; color: var(--plum); margin-top: 1.6cqh; }
.fisi p + p { margin-top: .7em; }
.fteks button, .fteks a { pointer-events: auto; }
.fnav {
  position: absolute; left: 83%; top: 50%; translate: 0 -50%; z-index: 5;
  display: flex; flex-direction: column; gap: .9cqw;
}
.fnav button {
  width: 3.4cqw; height: 3.4cqw; min-width: 34px; min-height: 34px; border-radius: 999px;
  border: .12cqw solid rgba(var(--panah-rgb),.4); background: transparent; color: var(--panah);
  font-size: 1.6cqw; cursor: pointer; line-height: 1;
}
.fnav button:hover:not(:disabled) { background: rgba(var(--panah-rgb),.12); }
.fnav button:disabled { opacity: .3; cursor: default; }

/* Label bagian: OUR ROOM & FACILITIES sengaja setebal dan sebesar judul
   sekunder, bukan keterangan kecil seperti di deck. */
/* Ajakan di bawah carousel, dikotakkan seperti tombol Book Now. Bukan tombol
   sungguhan -- yang diklik gambarnya, ini cuma penunjuk. */
/* Sekarang tepat di ATAS gambar (bukan di bawah carousel): kotaknya lebih
   kecil supaya muat di sela judul dan gambar. */
.klik-hint { display: flex; justify-content: center; align-items: flex-start; z-index: 4; }
.klik-hint span {
  background: var(--tombol-latar); color: var(--tombol-teks, #fff); font-weight: 700; letter-spacing: .04em;
  font-size: calc(11 * var(--pt)); padding: .45em 1.3em; white-space: nowrap;
}
.label-kanan { font-size: calc(46 * var(--pt)); font-weight: 800; letter-spacing: .02em;
  justify-content: flex-end; text-align: right; }
#fac-h { font-size: calc(58 * var(--pt)); font-weight: 800; letter-spacing: .04em; }
/* Footer hak cipta mendarat di section mana pun yang terakhir, dan ia sudah
   membawa wordmark -- yang di pojok panggung disembunyikan supaya tidak dobel. */
/* ---------- Sisi kanan bar: Book Now + switch bahasa ----------
   "Book Now" dikeluarkan dari daftar nav supaya tidak ikut disorot sebagai
   section dan selalu berdampingan dengan pilihan bahasa. */
.topbar-aksi {
  margin-left: auto; display: flex; align-items: center;
  gap: clamp(10px, 1.6vw, 22px); flex: 0 0 auto;
}
.topbar-pesan {
  background: var(--tombol-latar); color: var(--tombol-teks, #fff) !important; padding: 9px 18px;
  letter-spacing: .04em; white-space: nowrap;
}
.topbar-pesan span::after, .topbar-pesan span::before { display: none; }
.topbar-pesan:hover { background: var(--tinta); }
.topbar-langs { display: flex; align-items: center; gap: 8px; }
.topbar-lang {
  font-weight: 700; letter-spacing: .06em; opacity: .45;
  font-size: clamp(13px, 1.05vw, 16px) !important;
}
.topbar-lang + .topbar-lang::before {
  content: ""; display: inline-block; width: 1px; height: .95em; margin-right: 8px;
  background: currentColor; opacity: .4; vertical-align: -.1em;
}
.topbar-lang:hover { opacity: 1; color: var(--plum); }
.topbar-lang.kini { opacity: 1; color: var(--plum); }

/* ---------- WhatsApp mengambang ---------- */
/* Satu sumber jarak bawah untuk KEDUA tombol mengambang: megafon menumpuk di
   atas WhatsApp dengan menambahkan tinggi WA ke angka yang sama, jadi menaikkan
   satu tanpa satunya akan membuat mereka saling menabrak. */
:root { --apung-bawah: calc(clamp(14px, 2vw, 28px) + 22px); }
/* Ikon saja, bulat seperti megafon; labelnya di tooltip dan aria-label. */
.wa {
  position: fixed; right: clamp(14px, 2vw, 28px); bottom: var(--apung-bawah); z-index: 45;
  width: 52px; height: 52px; border-radius: 999px; display: grid; place-items: center;
  background: #25d366; color: #fff;
  box-shadow: 0 10px 26px rgba(0,0,0,.28);
  transition: transform .22s ease, box-shadow .22s ease;
}
.wa:hover { transform: translateY(-2px); box-shadow: 0 14px 32px rgba(0,0,0,.34); }
@media (max-width: 759px), (max-height: 429px) { .wa { right: 16px; } }

/* ---------- Megafon + pop-up pengumuman ----------
   Megafon duduk tepat di atas tombol WhatsApp; jaraknya dihitung dari tinggi
   .wa + sela, bukan angka tetap, supaya tidak meleset saat label WA
   disembunyikan di layar sempit. */
.megafon {
  position: fixed; right: clamp(14px, 2vw, 28px);
  bottom: calc(var(--apung-bawah) + 52px + 12px);        /* bertumpuk di atas WhatsApp */
  z-index: 45; width: 52px; height: 52px; border: 0; border-radius: 999px; cursor: pointer;
  display: grid; place-items: center; background: var(--tombol-latar); color: var(--tombol-teks, #fff);
  box-shadow: 0 10px 26px rgba(0,0,0,.3);
  transition: transform .22s ease, box-shadow .22s ease;
}
.megafon:hover { transform: translateY(-2px); box-shadow: 0 14px 32px rgba(0,0,0,.38); }

/* Keterangan saat kursor menyentuh, di sebelah KIRI tombol -- keduanya
   menempel di tepi kanan layar, jadi ke arah mana pun yang lain akan keluar
   halaman. Murni CSS: teksnya diambil dari data-tip yang ditulis build. */
.wa[data-tip]::after, .megafon[data-tip]::after {
  content: attr(data-tip);
  position: absolute; right: calc(100% + 12px); top: 50%;
  translate: 8px -50%; opacity: 0; pointer-events: none;
  background: var(--tombol-latar); color: var(--tombol-teks, #fff); white-space: nowrap;
  font-size: 13px; font-weight: 600; letter-spacing: .01em; line-height: 1;
  padding: 10px 14px; border-radius: 999px;
  box-shadow: 0 8px 22px rgba(0,0,0,.28);
  transition: opacity .18s ease, translate .18s ease;
}
.wa:hover::after, .wa:focus-visible::after,
.megafon:hover::after, .megafon:focus-visible::after { opacity: 1; translate: 0 -50%; }
/* Layar sentuh tidak punya hover, dan keterangannya cukup panjang untuk
   menyeberangi layar sempit. */
@media (max-width: 759px), (hover: none) {
  .wa[data-tip]::after, .megafon[data-tip]::after { content: none; }
}

/* Pop-up potret: rasio 9:16 mengikuti sumber videonya, dibatasi tinggi layar
   supaya tidak pernah terpotong di ponsel pendek. */
/* Dibuka dengan showModal(), tapi muncul dengan lembut seperti pop-up menu:
   app.js menambah .tampil di frame berikutnya dan melepasnya sebelum close(). */
.promo { border: 0; padding: 0; background: none; max-width: none; max-height: none;
  opacity: 0; transition: opacity .3s ease; }
.promo.tampil { opacity: 1; }
.promo::backdrop { opacity: 0; transition: opacity .3s ease; }
.promo.tampil::backdrop { opacity: 1; }
.promo::backdrop { background: rgba(23,22,26,.72); backdrop-filter: blur(6px); }
.promo-in {
  position: relative; width: min(86vw, calc(86svh * 9 / 16)); aspect-ratio: 9 / 16;
  overflow: hidden; background: #000; box-shadow: 0 30px 70px rgba(0,0,0,.5);
}
.promo-media { width: 100%; height: 100%; object-fit: cover; display: block; }
.promo-tutup, .promo-suara {
  position: absolute; z-index: 2; width: 40px; height: 40px; border: 0; border-radius: 999px;
  background: rgba(0,0,0,.45); color: #fff; cursor: pointer; display: grid; place-items: center;
  backdrop-filter: blur(4px);
}
.promo-tutup { top: 12px; right: 12px; font-size: 24px; line-height: 1; }
.promo-suara { top: 12px; left: 12px; }
.promo-suara[aria-pressed="true"] { background: var(--plum); }
@media (max-width: 759px), (max-height: 429px) {
  .megafon { right: 16px; bottom: calc(var(--apung-bawah) + 52px + 10px);
    width: 48px; height: 48px; }
}

/* ---------- Petunjuk ketuk di halaman pertama ---------- */
.petunjuk-tap {
  position: absolute; left: 0; right: 0; bottom: clamp(26px, 6vh, 64px); z-index: 9;
  text-align: center; color: #fff; font-size: 13px; letter-spacing: .16em;
  text-transform: uppercase; opacity: .82; pointer-events: none;
  text-shadow: 0 2px 10px rgba(0,0,0,.55);
  animation: kedip 2.4s ease-in-out infinite;
}
@keyframes kedip { 0%, 100% { opacity: .35; } 50% { opacity: .9; } }

/* ---------- Kilau tombol ajakan ----------
   Book Now, WhatsApp, dan megafon: seberkas cahaya menyapu dari kiri ke
   kanan tiap 3,2 detik, seperti tombol Book Now di situs sementara. Dibuat
   dari background-image yang digeser, bukan pseudo-elemen: ::after kedua
   tombol mengambang sudah dipakai keterangan hover, dan overflow:hidden
   akan memotong keterangan itu. Mati di prefers-reduced-motion. */
@keyframes kilau { 0%, 42% { background-position: 100% 0; } 72%, 100% { background-position: 0% 0; } }
.topbar-pesan, .wa, .megafon {
  background-image: linear-gradient(100deg, transparent 42%, var(--kilau) 50%, transparent 58%);
  background-size: 250% 100%; background-repeat: no-repeat; background-position: 100% 0;
  animation: kilau 3.2s ease-in-out infinite;
}
.topbar-pesan { --kilau: rgba(var(--beton-rgb),.55); }
/* Sapuan memakan 30% siklus (0,96 s); jeda 1/3 siklus = tidak pernah dua tombol
   berkilau bersamaan, jadi tetap satu titik fokus. */
.wa { --kilau: rgba(255,255,255,.55); animation-delay: 1.07s; }
.megafon { --kilau: rgba(var(--beton-rgb),.6); animation-delay: 2.13s; }
#top { cursor: pointer; }

/* ---------- FAQ ---------- */
.faq-judul { font-size: calc(70 * var(--pt)); }
.faq-list {
  position: absolute; left: 12%; right: 12%; top: 20%; bottom: 6%;
  overflow-y: auto; overscroll-behavior: contain; padding-right: 6px;
}
.faq {
  border-bottom: 1px solid rgba(var(--plum-rgb),.22);
  font-size: calc(17 * var(--pt));
}
.faq summary {
  cursor: pointer; list-style: none; padding: calc(14 * var(--pt)) 2.2cqw calc(14 * var(--pt)) 0;
  font-weight: 700; color: var(--plum); position: relative;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; position: absolute; right: 0; top: 50%; translate: 0 -50%; font-weight: 400; }
.faq[open] summary::after { content: "\2013"; }
.faq-a { padding: 0 2.2cqw calc(14 * var(--pt)) 0; line-height: 1.65; color: var(--tinta); }

/* ---------- Overlay booking (widget FastBooking) ----------
   Overlay biasa, bukan <dialog>: dialog tertutup itu display:none, dan
   kalender FastBooking menghitung lebar nol lalu tampil rusak saat dibuka. */
.pesan { position: fixed; inset: 0; z-index: 80; display: grid; place-items: center;
  opacity: 0; visibility: hidden; transition: opacity .3s ease, visibility 0s linear .3s; }
.pesan.buka { opacity: 1; visibility: visible; transition: opacity .3s ease, visibility 0s; }
.pesan[hidden] { display: grid; }          /* hidden hanya penanda awal, bukan penyembunyi */
.pesan-tirai { position: absolute; inset: 0; background: rgba(23,22,26,.68); backdrop-filter: blur(5px); }
/* Di dalam pop-up, "kertas" = --popup-latar dan "tinta" = --popup-teks. Tanpa
   ini, situs yang memakai teks putih (aksen putih di Site design) menulis putih
   di atas panel putih dan isinya hilang. */
.pesan-in {
  position: relative; z-index: 1; background: var(--popup-latar, #fff);
  color: var(--popup-teks, var(--tinta));
  padding: 26px 24px 20px; width: min(1000px, 94vw); max-height: 92svh; overflow: auto;
  box-shadow: 0 30px 80px rgba(0,0,0,.4);
}
.pesan-in h2 { font-size: clamp(22px, 2.4vw, 30px); margin-bottom: 14px; color: var(--plum); }
.pesan-tutup {
  position: absolute; top: 10px; right: 12px; width: 40px; height: 40px; z-index: 2;
  border: 0; background: none; font-size: 30px; line-height: 1; cursor: pointer;
  color: var(--popup-teks, var(--tinta));
}
/* Widget punya CSS sendiri dari CDN; di sini hanya diberi ruang. */
#fb-widget-1 { min-height: 420px; }
@media (max-width: 759px) { .pesan-in { padding: 22px 12px 16px; width: 96vw; } }

/* ---------- pop-up galeri kamar & fasilitas ----------
   Carousel mendatar; satu foto = satu panel ber-snap. Sama seperti carousel
   menu, perpindahannya langsung (gulir halus dibatalkan oleh scroll-snap). */
/* Mendatar tetap dikunci (carousel fotonya punya gulir sendiri), tegak boleh
   menggulir: video potret + keterangan + tombol lebih tinggi dari 92svh, dan
   dengan overflow:hidden tombolnya terpotong tanpa jalan untuk mencapainya. */
.galeri-ov .pesan-in { width: min(1000px, 94vw); overflow: hidden auto; overscroll-behavior: contain; }
.galeri-ov h2 { margin-bottom: 14px; }
.gal-kar { position: relative; }
.gal-isi {
  display: flex; gap: 0; overflow-x: auto; overscroll-behavior: contain;
  scroll-snap-type: x mandatory; scrollbar-width: none;
}
.gal-isi::-webkit-scrollbar { display: none; }
.gal-foto {
  flex: 0 0 100%; margin: 0; scroll-snap-align: start; scroll-snap-stop: always;
}
.gal-foto img, .gal-foto video {
  width: 100%; height: min(56svh, 460px); object-fit: cover; display: block;
}
/* Video utuh, bukan dipotong: kontrolnya harus tetap terlihat. */
.gal-foto video { object-fit: contain; background: #000; }
/* Gaya yang sama dengan panah carousel di halaman utama: bulat, transparan,
   bergaris tipis; warnanya ikut tinta pop-up supaya terlihat di panel apa pun. */
.gal-nav {
  position: absolute; top: 50%; translate: 0 -50%; z-index: 2;
  width: 44px; height: 44px; border-radius: 999px; cursor: pointer; line-height: 1;
  border: 1.5px solid currentcolor; background: transparent;
  color: var(--popup-teks, var(--panah)); font-size: 24px;
  transition: background-color .2s ease;
}
.gal-nav:hover { background: rgba(127,127,127,.18); }
.gal-nav[disabled] { opacity: .25; cursor: default; }
.gal-prev { left: 12px; }
.gal-next { right: 12px; }
.gal-hitung {
  position: absolute; right: 12px; bottom: 12px; z-index: 2;
  background: rgba(23,22,26,.6); color: #fff; font-size: 12px; font-weight: 700;
  padding: 4px 9px; letter-spacing: .06em;
}
.gal-tombol { display: block; width: max-content; margin-top: 12px; }
.gal-desk { margin-top: 16px; font-size: 15px; line-height: 1.7; color: var(--popup-teks, var(--plum)); }
.pesan-in .judul, .pesan-in h2, .pesan-in h3 { color: var(--popup-teks, var(--plum)); }
.pesan-in .tombol, .pesan-in .fmenu, .pesan-in .gal-tombol {
  background: var(--popup-teks, var(--plum)); color: var(--popup-latar, #fff);
}
/* Satu overlay dipakai kamar, fasilitas, dan Secret Corner. Yang terakhir
   fotonya tegak, jadi panelnya disempitkan dan fotonya ditinggikan -- kalau
   tidak, foto potret di kotak mendatar terpotong jadi pita di tengahnya. */
.galeri-ov.galeri-potret .pesan-in { width: min(540px, 94vw); }
.galeri-ov.galeri-potret .gal-foto img,
.galeri-ov.galeri-potret .gal-foto video { height: min(68svh, 660px); }
@media (max-width: 759px) {
  .gal-foto img, .gal-foto video { height: min(42svh, 320px); }
  /* Potret: 68svh + judul + keterangan melebihi overlay 92svh, dan
     keterangannya terpotong sebelum sempat bisa digulir. */
  .galeri-ov.galeri-potret .gal-foto img,
  .galeri-ov.galeri-potret .gal-foto video { height: min(56svh, 660px); }
  .gal-nav { width: 36px; height: 36px; font-size: 19px; }
}

/* ---------- e-menu DAK & Saé ----------
   Dua kolom di layar lebar supaya daftar 180 item tidak jadi pita panjang;
   tiap grup dijaga utuh dengan break-inside: avoid. */
/* inline-block: dipakai juga sebagai <a> di Happening, dan margin-top pada
   <a> biasa tidak berlaku -- tombolnya menimpa baris terakhir keterangan. */
.fmenu { display: inline-block; margin-top: 14px; border: 0; cursor: pointer; font: inherit; font-weight: 700;
  text-decoration: none;
  background: var(--tombol-latar); color: var(--tombol-teks, #fff); padding: 10px 20px; letter-spacing: .04em; }
/* Kolom fleksibel: judul, subjudul, baris tombol bagian, lalu carousel yang
   MENGISI SISANYA. Dengan tinggi carousel tetap 72svh, menu yang tombol
   bagiannya melipat jadi dua baris (DAK) melebihi 92svh dan bagian bawahnya
   terpotong tanpa jalan untuk mencapainya. */
.menu-ov .pesan-in { width: min(620px, 94vw); height: min(92svh, 980px); overflow: hidden;
  display: flex; flex-direction: column; }
.menu-ov .pesan-in > * { flex: 0 0 auto; }
.menu-sub { color: var(--plum); font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; font-size: 12px; margin: -8px 0 18px; }
/* Carousel vertikal: satu grup menu = satu panel, digeser dengan panah atau
   gulir; scroll-snap menahan tiap panel tepat di atas.
   Catatan: scroll-snap membatalkan scrollBy({behavior:"smooth"}) tanpa error,
   jadi app.js menggeser scrollTop dari hasil ukur rect, bukan scrollBy. */
/* Tombol bagian menu. Namanya diisi di back office; halaman tanpa nama
   bagian tidak memunculkan tombol. */
.mbagian-baris {
  display: flex; flex-wrap: wrap; gap: 6px; margin: -6px 0 14px;
}
/* Layar pendek: tumpuk tombolnya jadi satu baris yang digulir mendatar, bukan
   dipotong -- baris ketiga yang hilang terbaca sebagai bagian menu yang tidak
   ada. Carousel menunya sendiri sudah menyusut lewat svh. */
@media (max-height: 760px) {
  .mbagian-baris {
    flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
    padding-bottom: 2px;
  }
  .mbagian-baris::-webkit-scrollbar { display: none; }
  .mbagian { flex: none; }
}
.mbagian {
  border: 1px solid currentcolor; background: var(--popup-latar, #fff);
  color: var(--popup-teks, var(--plum));
  font: inherit; font-size: 11px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; padding: 5px 11px; cursor: pointer; border-radius: 999px;
  min-height: 44px;   /* sasaran sentuh */
}
.mbagian:hover, .mbagian.kini { background: var(--popup-teks, var(--plum)); color: var(--popup-latar, #fff); }
/* container-type: size supaya tinggi panel (.mgrup) bisa memakai 100cqh:
   tinggi hasil flex tidak "pasti" bagi persen anak-anaknya, dan height:100%
   di sana tidak mengikuti tinggi carousel yang menyusut. */
.menu-ov .menu-kar { position: relative; flex: 1 1 auto; min-height: 160px; display: flex; flex-direction: column;
  container-type: size; }
.menu-isi {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  /* TANPA scroll-behavior: smooth -- di kontainer scroll-snap mandatory,
     gulir halus (CSS maupun scrollTo) dibatalkan diam-diam dan panahnya
     tampak mati. Perpindahan antar panel langsung saja. */
  scroll-snap-type: y mandatory; scrollbar-width: none; padding-right: 54px;
}
.menu-isi::-webkit-scrollbar { display: none; }
.menu-nav {
  position: absolute; right: 0; top: 50%; translate: 0 -50%;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
}
.menu-nav button {
  width: 40px; height: 40px; border-radius: 999px; cursor: pointer; line-height: 1;
  border: 1px solid rgba(var(--panah-rgb),.35); background: rgba(var(--beton-rgb),.5);
  color: var(--panah); font-size: 17px;
}
.menu-nav button:hover { background: rgba(var(--panah-rgb),.14); }
.menu-nav button[disabled] { opacity: .3; cursor: default; }
.menu-hitung { font-size: 11px; font-weight: 700; color: var(--plum); letter-spacing: .06em; }
.mgrup {
  scroll-snap-align: start; scroll-snap-stop: always;
  height: 100cqh; margin: 0; display: flex; align-items: center; justify-content: center;
}
.mgrup img { max-width: 100%; max-height: 100cqh; width: auto; height: auto; display: block; }
.menu-nb { margin-top: 6px; font-size: 12px; opacity: .6; }
@media (max-width: 759px) {
  .menu-isi { padding-right: 44px; }
  .menu-nav button { width: 34px; height: 34px; font-size: 15px; }
}

.kontak .tombol { border: 0; cursor: pointer; font: inherit; font-weight: 500; }

/* ---------- Contact ----------
   Isinya mengikuti bagian Lokasi di situs newjan: eyebrow, judul, alamat,
   telepon, email, plus peta tertanam. */
.kontak {
  width: min(100%, 1320px); margin: 0 auto;
  padding: clamp(60px, 9svh, 110px) max(20px, 5vw) 0;
  display: grid; gap: clamp(24px, 3.4vw, 48px);
  /* start, bukan center: tiap kolom beda tinggi (peta pendek, embed TikTok
     jauh lebih tinggi), dan rata tengah membuat judul kolom yang paling
     tinggi terdorong ke atas sampai terpotong tepi layar. */
  align-items: start;
}
/* Tiga kolom di layar lebar: alamat+peta, lalu satu kolom per platform.
   Di bawah 1100px embed berdampingan tidak muat (masing-masing minta
   ~300px), jadi turun ke satu kolom. */
@media (min-width: 760px) { .kontak { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1100px) { .kontak { grid-template-columns: 1.15fr 1fr 1fr; } }
/* Tulisan tegak di tepi kiri, seperti HAPPENING/SECRET CORNER. Hanya di
   layar lebar: di bawah 1100px kolomnya sudah memakai seluruh lebar. */
.kontak-tegak {
  display: none; position: absolute; left: 2.4vw; top: 50%; translate: 0 -50%; z-index: 2;
  writing-mode: vertical-rl; rotate: 180deg;      /* dibaca dari bawah ke atas */
  margin: 0; white-space: nowrap; color: var(--plum);
  font-size: clamp(28px, 3.2vw, 62px); font-weight: 800; letter-spacing: .12em;
}
@media (min-width: 1100px) {
  .kontak-tegak { display: block; }
  .kontak { padding-left: max(9vw, 120px); }
}
.kontak .eyebrow {
  font-size: 12px; letter-spacing: .12em; color: var(--plum); margin-bottom: 14px;
}
.kontak h2 { font-size: clamp(28px, 3.4vw, 46px); line-height: 1.1; margin-bottom: 26px; }
.kontak address { font-style: normal; font-size: 17px; line-height: 1.9; }
.kontak-dl { margin: 22px 0 0; display: grid; gap: 4px; }
.kontak-dl dt { font-size: 12px; letter-spacing: .12em; color: var(--plum); margin-top: 14px; }
.kontak-dl dd { margin: 0; font-size: 17px; }
.kontak-dl a { text-decoration: underline; text-underline-offset: 3px; }
.kontak .tombol {
  display: inline-block; margin-top: 30px; padding: 15px 30px;
  background: var(--tombol-latar); color: var(--tombol-teks, #fff); font-weight: 500;
}
.kontak .tombol:hover { background: #3d1f33; }
.sos-h { margin-top: 30px; }
.sos { display: flex; gap: 14px; }
.sos-a {
  width: 42px; height: 42px; display: grid; place-items: center;
  border: 1px solid rgba(var(--plum-rgb),.35); color: var(--plum);
}
.sos-a svg { width: 20px; height: 20px; fill: currentColor; }
.sos-a:hover { background: var(--plum); color: #fff; }
/* Peta duduk di bawah alamat, jadi lebih rendah daripada waktu ia sendirian
   di kolom kanan. */
.kontak-peta { margin-top: 22px; }
.kontak-peta iframe {
  width: 100%; aspect-ratio: 16 / 9; max-height: 30svh; border: 0; display: block;
  background: var(--beton-tua);
}

/* Embed sosial: satu kolom per platform, sejajar dengan kolom alamat.
   .kontak-sos sendiri bukan pembungkus visual -- ia hanya menyalurkan
   anaknya jadi kolom grid induknya (display:contents), supaya Instagram dan
   TikTok benar-benar berdampingan dan bukan bertumpuk di satu kolom. */
.kontak-sos { display: contents; }
.sos-kartu { min-width: 0; }
/* Tinggi kedua kartu DIPAKSA sama. Instagram dan TikTok punya tinggi alami
   yang beda jauh -- TikTok menambah caption dan baris musik di bawah videonya
   -- jadi kalau dibiarkan mengukur diri sendiri, dua kolom ini tidak pernah
   sejajar. Caption TikTok-nya sendiri dimatikan lewat description=0 di URL
   embed; ia di dalam iframe dan tidak bisa disentuh dari luar. */
.sos-kartu-isi {
  background: rgba(var(--plum-rgb), .07); border-radius: 4px;
  height: clamp(420px, 60svh, 620px); overflow: hidden;
}
.sos-kartu-isi iframe { width: 100%; height: 100%; border: 0; display: block; }
/* Satu kolom: embed ditumpuk, jadi beri kolomnya jalan gulir sendiri supaya
   yang kedua tetap bisa dicapai. */
@media (max-width: 1099px) {
  .kontak-sos { display: block; max-height: 74svh; overflow-y: auto;
                overscroll-behavior: contain; }
  .sos-kartu + .sos-kartu { margin-top: 18px; }
}
/* Layar sentuh: iframe IG/TikTok menelan sentuhan, jadi orang yang menggulir
   di atasnya menggulir ISI iframe dan tidak pernah sampai ke section
   berikutnya. Lapisan transparan ini menerima gulirannya (jadi milik halaman
   kita); satu ketukan melepasnya dan embed-nya jadi bisa dimainkan. */
@media (hover: none) {
  .sos-kartu-isi { position: relative; }
  .sos-kartu-isi::after {
    content: attr(data-ketuk); position: absolute; inset: 0; z-index: 1;
    display: flex; align-items: flex-end; justify-content: center; padding-bottom: 14px;
    color: #fff; font-size: 12px; font-weight: 700; letter-spacing: .06em;
    background: linear-gradient(to top, rgba(23,22,26,.55), transparent 28%);
  }
  .sos-kartu-isi.aktif::after { display: none; }
}

/* Kaki halaman kontak: wordmark, hubungi, hak cipta. */
.kontak-kaki {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; align-items: flex-end; gap: clamp(16px, 3vw, 46px);
  flex-wrap: wrap; padding: 12px max(20px, 5vw) 18px;
}
.kaki-hak { margin: 0; font-size: 13px; opacity: .8; margin-left: auto; }
@media (max-width: 759px) {
  /* Rata kiri dengan ruang kanan 128px: dua tombol mengambang duduk di pojok
     kanan bawah, hak cipta yang dipusatkan tertutup olehnya. */
  .kontak-kaki { position: static; flex-direction: column; align-items: flex-start; text-align: left; gap: 10px;
    padding-right: 128px; padding-left: 0; }
  .kaki-hak { margin-left: 0; }
}

/* ---------- Reveal ---------- */
/* px, bukan cqh: di tumpukan ponsel .stage bukan container lagi, dan jarak
   dalam cqh di sana menjadi 0 -- itu yang membuat animasinya seperti hilang. */
.js-v2 .naik { opacity: 0; transform: translateY(14px); }
.js-v2 .tampil .naik, .js-v2 .naik.tampil {
  opacity: 1; transform: none; transition: opacity .8s ease, transform .8s cubic-bezier(.2,.7,.2,1);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation: none !important; transition: none !important; }
  .js-v2 .naik { opacity: 1; transform: none; }
  .js-v2 #intro .menara { opacity: 1; transform: rotate(-142.8deg); }
}

/* ---------- Tata letak tumpukan ----------
   Yang membuat deck tidak terbaca bukan lebar jendela, tapi ukuran stage
   yang tersisa: stage = min(100vw, 100svh x 16/9). Di ponsel potret
   390x844 stage jadi 390x219 dan teks 18pt turun ke ~5px. Tapi jendela
   desktop 900x600 -- meski "sempit" -- masih memberi stage 900x506 dan
   teks ~11px, jadi tidak ada alasan membuang gaya dan animasinya.
   Karena itu ambangnya lebar < 760px ATAU tinggi < 430px, bukan lebar
   < 900px. Jendela kecil tetap dapat deck; ponsel potret yang ditumpuk. Ini memang dua tata letak, dan itu disengaja: memaksa satu
   tata letak akan mengorbankan salah satunya.

   Yang paling gampang terlewat: LAPISAN TETAP (tirai dan logo terbang) juga
   memakai persen stage 16:9. Di layar potret persen itu tidak lagi berarti
   apa-apa -- menara "terbuka" tetap menutupi layar dan logonya mendarat di
   tempat acak. Keduanya diberi posisi tersendiri di bawah ini. */
@media (max-width: 759px), (max-height: 429px) {
  .deck-titik { right: 6px; }
  .deck-titik button { width: 7px; height: 7px; }

  /* Ruang atas harus melewati menu + logo terbang, kalau tidak barisan
     pertama tiap section tertimpa logonya. */
  /* grid-auto-rows: max-content wajib. Dengan baris `auto`, section yang punya
     DUA anak (stage + footer hak cipta) membagi tinggi layar di antara
     keduanya, dan baris stage jadi lebih pendek daripada isinya -- footernya
     lalu digambar menimpa nama produk dan panah. Tinggi penuh section berisi
     satu anak tetap dijaga oleh min-height di .stage, bukan oleh peregangan
     baris. */
  .slide { padding: 108px 6vw 4vh; place-items: start center;
    grid-auto-rows: max-content; align-content: space-between; overflow: hidden auto; }
  .slide .stage { overflow: visible; }
  .stage {
    width: 100%; aspect-ratio: auto; container-type: normal;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 1.6vh; text-align: center;
    min-height: calc(100svh - 108px - 4vh - 52px);   /* 52px = footer hak cipta di bawah stage */
  }
  .el { position: static; width: auto; height: auto; max-width: 100%; transform: none; display: block; }
  .el.teks { display: block; }
  #fac-h { display: block; font-size: 8vw; order: 0; text-align: center; }
  #origins .lineart {
    position: absolute; left: 50%; top: 50%; translate: -50% -50%;
    width: 108vw; height: auto; max-width: none;
    opacity: var(--gedung-kuat, .15); z-index: 0; pointer-events: none;
  }
  #origins .stage > :not(.lineart) { position: relative; left: auto; top: auto; z-index: 1; }

  /* --- menu atas: satu baris rapat, boleh digeser kalau kepanjangan --- */
  .topbar {
    justify-content: flex-start; gap: 16px; padding: 14px 4vw;
    overflow-x: auto; scrollbar-width: none;
    background: linear-gradient(to bottom, rgba(var(--beton-rgb),.96), rgba(var(--beton-rgb),0));
  }
  .topbar::-webkit-scrollbar { display: none; }
  .topbar a { font-size: 14px; white-space: nowrap; }
  .topbar a[aria-current="true"] span::before { display: none; }
  /* Penanda halaman aktif: garis bawah -- titik di kiri label tidak muat di
     baris yang rapat, dan garis ::after milik desktop tidak ikut tampil. */
  .topbar-menu a[aria-current="true"] span {
    text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 6px;
  }
  /* Hanya daftar link yang menggulir; tombol bahasa di luarnya, jadi tidak
     pernah terdorong keluar layar berapa pun panjang menunya. */
  .topbar { overflow: visible; align-items: center; gap: 0; }
  .topbar-menu {
    display: flex; gap: 16px; flex: 1 1 auto; min-width: 0;
    overflow-x: auto; scrollbar-width: none;
  }
  .topbar-menu::-webkit-scrollbar { display: none; }
  .topbar-aksi { flex: 0 0 auto; margin-left: 0; padding-left: 12px; gap: 10px; }
  .topbar-pesan { padding: 7px 12px; font-size: 12px !important; }
  .topbar-lang { font-size: 12px !important; }
  .topbar-langs { gap: 6px; }
  .topbar-lang + .topbar-lang::before { margin-right: 6px; }

  /* --- tirai di layar potret ---
     PENTING: aturan `.el { position: static }` di atas ikut kena lapisan
     tetap ini kalau tidak dikecualikan -- menaranya kehilangan posisi dan
     rotasi lalu menumpuk sebagai dua gambar biasa.
     Rotasi -135/+45 dipertahankan supaya bukaannya tetap miring seperti
     desktop; hanya koordinatnya yang disetel ulang untuk kanvas potret,
     dan panelnya dibesarkan agar tidak menyisakan beton di sudut. */
  .tirai .el, .logo-terbang .el { position: absolute; }
  .tirai .stage { width: 100%; height: 100%; aspect-ratio: auto; }
  /* Ukuran dan posisi dalam vw, bukan persen stage: persen lebar dan persen
     tinggi di kanvas potret menghasilkan kotak berasio 0.27, dan vektornya
     (asio 0.69) teregang jadi serpihan tipis. Dengan vw untuk kedua sisi,
     asio panelnya terjaga seperti di desktop. */
  .tirai .menara {
    max-width: none;
    transform: rotate(var(--rot, 0deg)) scaleX(var(--flip, 1));
    transition: left 1.15s cubic-bezier(.4,0,.2,1), top 1.15s cubic-bezier(.4,0,.2,1), opacity .8s ease;
  }
  /* Di kanvas potret tingginya yang jadi patokan: tiap panel setinggi layar
     penuh (110svh) dengan asionya sendiri (kiri 0.896, kanan 0.858), lalu
     digeser sehingga hanya sisi dalamnya yang terlihat -- persis seperti dua
     panel yang mengapit logo di deck. */
  /* Yang harus pas di layar adalah GAMBARNYA, bukan kotak panelnya: di berkas
     ekspor deck, gambar panel kiri menempati x 6.7-84.6% dan y 20.3-93.3% dari
     kotaknya, yang kanan x 13.6-93.4% dan y 6.8-83.2%. Angka-angka itulah yang
     dipakai di sini supaya tepi dalam gambar mendarat di 45vw dan 55vw dan
     gambarnya setinggi layar, berapa pun rasio ponselnya. Kalau panelnya suatu
     saat diekspor ulang dengan margin kosong yang berbeda, angka ini ikut. */
  .tirai .menara { --t: max(140svh, 150vw); }
  .tirai .m-kiri  { --lebar: calc(var(--t) * .896); height: var(--t); width: var(--lebar);
                    left: calc(45vw - var(--lebar) * .846); top: calc(50svh - var(--t) * .568); }
  .tirai .m-kanan { --lebar: calc(var(--t) * .858); height: var(--t); width: var(--lebar);
                    left: calc(55vw - var(--lebar) * .136); top: calc(50svh - var(--t) * .45); }
  .tirai[data-buka="1"] .m-kiri  { left: calc(15vw - var(--lebar) * .846); }
  .tirai[data-buka="1"] .m-kanan { left: calc(85vw - var(--lebar) * .136); }
  .tirai[data-buka="2"] .m-kiri  { left: calc(15vw - var(--lebar) * .846); opacity: 0; }
  .tirai[data-buka="2"] .m-kanan { left: calc(85vw - var(--lebar) * .136); opacity: 0; }

  /* --- logo terbang: posisi tetap, bukan persen stage --- */
  .logo-terbang .stage { width: 100%; height: 100%; aspect-ratio: auto; }
  .logo-terbang[data-pos="0"] .logo-lockup { left: 50%; top: 50%; translate: -50% -50%; width: 40vw; }
  .logo-terbang[data-pos="1"] .logo-lockup { left: 50%; top: 52px; translate: -50% 0; width: 19vw; --logo: var(--logo-gelap, #fff); }
  .logo-terbang[data-pos="2"] .logo-lockup,
  .logo-terbang[data-pos="3"] .logo-lockup { left: 4vw; top: 54px; translate: none; width: 14vw; --logo: var(--logo-gelap, #fff); }
  .logo-lockup.logo-statis { left: 4vw; top: 54px; width: 14vw; }

  #top { padding: 0; min-height: 100svh; display: grid; place-items: center; }
  #top .stage { display: none; }

  /* --- ukuran teks --- */
  .sudut  { font-size: 25px; font-weight: 800; line-height: 1.1; white-space: normal; order: 6; }
  /* Di desktop slogannya terbang dari samping 24 HOUR ke pojok intro; di ponsel
     lapisan terbang itu mati, jadi versi statisnya yang diberi gerak masuk. */
  .js-v2 #intro.tampil .sudut { animation: naikHalus .8s cubic-bezier(.2,.7,.2,1) both; }
  .js-v2 #intro.tampil .sudut + .sudut { animation-delay: .12s; }
  .sudut.kanan { text-align: center; }
  #origins .serif { font-size: 21px; letter-spacing: .12em; }
  #origins .h24   { font-size: 19vw; }
  /* Slogan kiri-kanan dalam satu baris di bawah 24 HOUR, seperti di desktop. */
  #origins .stage { display: grid; grid-template-columns: 1fr 1fr; column-gap: 12px; align-content: center; }
  #origins .stage > * { grid-column: 1 / -1; }
  #origins .sudut.pusat { grid-column: 1; justify-self: start; text-align: left; font-size: 15px; margin-top: -1vh; }
  #origins .sudut.pusat + .sudut.pusat { grid-column: 2; justify-self: end; text-align: right; }
  #origins img[src*="word"] { width: 190px; order: 5; margin-top: 1vh; }
  #intro .isi-teks { font-size: 19px; line-height: 1.65; }

  /* --- karusel dipertahankan, tidak disembunyikan ---
     Kartu tetangga tetap mengintip di tepi seperti desktop; hanya
     koordinatnya yang disetel ulang. Strip-nya di-clip supaya tetangga yang
     menjulur tidak menambah tinggi guliran section. */
  /* Tinggi strip dijaga supaya satu section muat satu layar tanpa gulir. */
  .rstrip { display: block; position: relative; width: 100%; height: 32vh; overflow: hidden; order: 2; }
  .fstrip { display: block; position: relative; width: 100%; height: 38vh; overflow: hidden; order: 2; }
  .rcard, .fslide { position: absolute; }
  /* Strip di-clip, jadi bayangan berjarak jauh terpotong dan terlihat kotor;
     di ponsel kartu tengah memakai bayangan pendek yang muat di dalam strip. */
  .rcard[data-p="0"], .fslide[data-p="0"] { box-shadow: var(--bayang-ponsel, 0 5px 14px rgba(0,0,0,.28)); }
  .rcard[data-p="-1"] { --x: -60; --y:  8; --w: 72; --h: 84; opacity: 1; }
  .rcard[data-p="0"]  { --x:  14; --y:  3; --w: 72; --h: 94; opacity: 1; }
  .rcard[data-p="1"]  { --x:  88; --y:  8; --w: 72; --h: 84; opacity: 1; }
  .rcard[data-p="x"]  { --x:  14; --y:  3; --w: 72; --h: 94; opacity: 0; }
  .fslide[data-p="-1"] { --x: 10; --y: -42; --w: 80; --h: 52; opacity: 1; }
  .fslide[data-p="0"]  { --x:  2; --y:  14; --w: 96; --h: 72; opacity: 1; }
  .fslide[data-p="1"]  { --x: 10; --y:  90; --w: 80; --h: 52; opacity: 1; }
  .fslide[data-p="x"]  { --x:  2; --y:  14; --w: 96; --h: 72; opacity: 0; }
  .rcard img, .fslide img, .rcard video, .fslide video { aspect-ratio: auto; height: 100%; }
  .flabel { display: none; }
  .rjudul { position: static; font-size: 8.5vw; order: 3; }
  #rooms .label-kanan { order: 0; font-size: 8.5vw; text-align: center; justify-content: center; }
  #rooms .klik-hint { order: 4; }
  .rdesk { order: 5; }
  /* Petunjuk klik: tanpa order ia jatuh ke urutan 0 dan mendarat DI ATAS
     gambar, dan ukurannya ikut --pt yang di sini menyusut jadi ~7px. */
  .klik-hint { order: 2; }
  /* inline-block: kalau kalimatnya patah dua baris, ia tetap SATU kotak.
     Sebagai span biasa tiap barisnya jadi kotak ungu sendiri-sendiri. */
  .klik-hint span { display: inline-block; font-size: 12px; padding: .5em 1.1em;
    white-space: normal; line-height: 1.5; }
  .sstrip { height: 36vh; order: 2; }   /* 3:4 setinggi ini = ~66% lebar ponsel */
  /* Bagian ini punya footer hak cipta SETELAH stage, jadi keduanya dua baris
     grid. min-height stage mengunci tinggi barisnya di layar penuh sementara
     isinya lebih tinggi dari itu -- footernya lalu digambar menimpa panah dan
     tulisan di bawah. Bagian ini tidak butuh tinggi minimum: isinya sudah
     melebihi satu layar. */
  #sudut .stage, #happening .stage { min-height: 0; }
  /* --x/--w ikut ditulis ulang: aturan #sudut di atas menang atas aturan
     .rcard layar sempit karena ber-id, jadi koordinat desktopnya bocor. */
  /* Kartu potret: lebarnya dari tinggi lewat aspect-ratio, bukan persen
     lebar strip -- persen membuatnya gepeng (152 x 438 px di ponsel 375).
     Yang tengah 3:4 setinggi strip, dipusatkan; sisi mengintip 10% di tepi. */
  #sudut .rcard, #happening .rcard { width: auto; aspect-ratio: 4 / 5; }
  #sudut .rcard[data-p="0"],  #happening .rcard[data-p="0"],
  #sudut .rcard[data-p="x"],  #happening .rcard[data-p="x"]  { left: 50%; top: 3%; height: 94%; translate: -50% 0; }
  #sudut .rcard[data-p="-1"], #happening .rcard[data-p="-1"] { left: 10%; top: 9%; height: 82%; translate: -100% 0; }
  #sudut .rcard[data-p="1"],  #happening .rcard[data-p="1"]  { left: 90%; top: 9%; height: 82%; translate: 0 0; }
  #sudut .rnav-btn, #happening .rnav-btn { top: 50%; bottom: auto; translate: 0 -50%; }
  #sudut .rnav-prev, #happening .rnav-prev { left: 6px; right: auto; }
  #sudut .rnav-next, #happening .rnav-next { right: 6px; left: auto; }
  #happening .sjudul { white-space: normal; font-size: 7vw; }
  #happening .sdesk-kata { -webkit-line-clamp: unset; display: block; }
  #happening .sdesk { left: auto; right: auto; }
  .slabel { display: none; }
  .sjudul { position: static; font-size: 7.5vw; order: 3; margin-top: 8px; }
  .sdesk  { position: static; inset: auto; order: 4; margin-top: 4px; }
  .sdesk-kata { font-size: 15px; }
  .sdesk-mitra { font-size: 13px; }
  /* Ditumpuk, jadi dua tulisan tegak itu jadi judul + anak judul di atas
     carousel -- bukan urutan kiri/kanan yang tidak punya arti tanpa rotasi. */
  .sjudul-tegak, .stempat { position: static; rotate: none; font-size: 22px; }
  .sjudul-tegak { order: 0; }
  .stempat { font-size: 18px; letter-spacing: .14em; order: 1; }

  .rdesk { position: static; font-size: 15px; margin-top: 4px; }
  /* 4+5. Panah menempel pada gambarnya: .rnav/.fnav ada DI DALAM strip, yang
     di sini position:relative, jadi tombol absolutnya mengikuti strip --
     kiri/kanan untuk carousel mendatar, atas/bawah untuk yang tegak. */
  .rnav, .fnav { display: contents; }
  .rnav-btn {
    position: absolute; top: 50%; translate: 0 -50%; z-index: 5;
    width: 40px; height: 40px; font-size: 20px; border-width: 1.5px;
    background: transparent;
  }
  .rnav-prev { left: 6px; right: auto; }
  .rnav-next { right: 6px; left: auto; }
  .fnav button {
    position: absolute; left: 50%; translate: -50% 0; z-index: 5;
    width: 40px; height: 40px; font-size: 20px; border-width: 1.5px;
    background: transparent;
  }
  .fnav [data-fprev] { top: 6px; }
  .fnav [data-fnext] { bottom: 6px; }
  .fteks { position: static; inset: auto; pointer-events: auto; order: 3; }
  /* Di desktop teks yang tersembunyi tetap display:block demi pudar-silang --
     aman karena bertumpuk absolut. Di tumpukan ini ia ikut mengalir: lima
     blok tak terlihat menambah ~1300px kosong di bawah yang tampil. */
  .fteks[hidden] { display: none; }
  /* Karena yang tersembunyi display:none, transisi desktop tidak jalan di
     sini (tidak ada keadaan awal). Diganti animasi: elemennya baru tiap kali
     tampil, jadi mulai dari nol memang benar di sini. */
  .fteks:not([hidden]) .fjudul { animation: terbangMasuk .8s cubic-bezier(.3,.8,.25,1) both; }
  .fteks:not([hidden]) .fisi, .fteks:not([hidden]) .fmenu { animation: naikHalus .6s ease both; }
  .fteks-in { width: 100%; }
  .fjudul { font-size: 8vw; text-align: center; }
  .fjudul img { height: 56px; margin: 0 auto; object-position: center; }
  .fisi   { font-size: 15px; text-align: left; margin-top: 10px; }

  /* --- FAQ --- */
  .faq-judul { position: static; font-size: 11vw; order: 0; }
  .faq-list { position: static; left: auto; right: auto; top: auto; bottom: auto;
    width: 100%; max-height: calc(100svh - 250px); order: 1; text-align: left; }
  .faq { font-size: 16px; }
  .faq summary { padding: 14px 26px 14px 0; }
  .faq-a { padding: 0 26px 14px 0; }

  /* --- contact --- */
  .kontak { padding: 0 2vw; }
  .kontak h2 { font-size: 30px; }
  .kontak-peta iframe { aspect-ratio: 1 / 1; }
}



/* Ikon sosial dan pop-upnya diganti embed yang tampil langsung di kolom
   kanan bagian kontak. */
.kontak-wa {
  display: block; margin-top: 2px; font-size: .88em; font-weight: 700;
  color: var(--plum); text-decoration: underline; text-underline-offset: 3px;
}

/* Embed postingan resmi lebih besar daripada kartu profil: Instagram ~540px,
   TikTok ~605px dan tinggi. Beri ruang, lalu biarkan menggulir sendiri. */
.sos-ov .pesan-in { max-width: 660px; }
.sos-bingkai {
  height: min(74svh, 780px); overflow-y: auto; overscroll-behavior: contain;
  border-radius: 10px; background: rgba(var(--plum-rgb), .06); padding: 10px;
}
.sos-bingkai iframe { width: 100%; border: 0; display: block; margin: 0 auto; }
.sos-bingkai blockquote { margin: 0 auto; }
/* TikTok menyesuaikan tinggi iframe-nya lewat postMessage; kalau pesan itu
   tidak sampai, tanpa tinggi minimum kotaknya rata jadi 1px. */
.sos-bingkai .tiktok-embed, .sos-bingkai .tiktok-embed iframe { min-height: 640px; }
