/* ============================================================
   Lixy Store — lapisan sinematik landing page.
   Pasangan dari markup .cine / .cine-intro / .stage / .lp-band / .pf
   di index.html, dan dari bagian 10-14 landing.js.

   Dimuat SETELAH landing.css, jadi rule di sini menang pada
   specificity yang sama: dipakai untuk mengubah hero dari satu kolom
   terpusat menjadi grid dua kolom (teks + panggung karakter).

   Prinsip:
   - Semua lapisan dekoratif pointer-events:none. Grain/vignette
     menutupi viewport; tanpa itu setiap klik akan tertelan.
   - Idle karakter memakai `animation` pada transform. Parallax dari
     pointer memakai properti individual `translate`/`rotate` yang
     dikomposisikan browser DI ATAS transform, jadi keduanya tidak
     saling menimpa. Browser tanpa dukungan properti individual
     (Safari <14.1) cukup kehilangan parallax-nya.
   - Setiap animasi masuk memakai fill forwards: kalau JS mati, tidak
     ada elemen yang tertinggal menutup layar atau berada di opacity 0.
   ============================================================ */

/* ---------- 1. OVERLAY SINEMATIK ---------- */
/* z-index 55: di atas seluruh isi landing (max 2), di bawah nav (60)
   supaya tombol nav tidak pernah terlihat "berkabut". */
.cine{position:fixed;inset:0;z-index:55;pointer-events:none;overflow:hidden;contain:layout style paint}
.cine>*{position:absolute;pointer-events:none}

/* Flare: satu bloom teal besar yang bergeser sangat pelan, meniru
   pantulan lampu studio. Ukurannya viewport-relative supaya tetap
   proporsional di ultrawide. */
.cine-flare{top:-40vh;right:-30vw;width:95vw;height:95vw;max-width:1400px;max-height:1400px;
  background:radial-gradient(circle,rgba(126,198,183,.09),rgba(84,171,155,.03) 38%,transparent 62%);
  animation:cineFlare 18s var(--in-out) infinite alternate;will-change:transform;contain:strict}
@keyframes cineFlare{from{transform:translate3d(0,0,0) scale(1)}to{transform:translate3d(-9vw,7vh,0) scale(1.12)}}

/* Grain: tekstur feTurbulence digeser dengan steps(). Elemennya dibuat
   150% dan digeser -25% supaya masih ada 25% cadangan di setiap sisi;
   pergeseran animasi (maks 8% dari 150% = 12% viewport) karena itu
   tidak pernah menyingkap tepi yang tidak tertutup. Menggeser layer
   jauh lebih murah daripada melukis ulang noise tiap frame.

   150%, bukan 200%: layer ini punya will-change:transform sehingga
   dipromosikan ke layer compositor sendiri, dan biayanya sebanding
   dengan LUASNYA. 200% = 4x viewport, 150% = 2,25x — hemat 44% area
   yang harus di-composite 60x per detik, dengan cadangan tepi yang
   masih 2x lebih besar dari pergeseran maksimum. */
.cine-grain{top:-25%;left:-25%;width:150%;height:150%;opacity:.045;
  background:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.92' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E") 0 0/220px 220px;
  animation:cineGrain 1.6s steps(6) infinite;will-change:transform;contain:strict}
@keyframes cineGrain{
  0%{transform:translate3d(0,0,0)}16.6%{transform:translate3d(-6%,4%,0)}33.3%{transform:translate3d(3%,-7%,0)}
  50%{transform:translate3d(-8%,-2%,0)}66.6%{transform:translate3d(5%,6%,0)}83.3%{transform:translate3d(-3%,8%,0)}
  100%{transform:translate3d(0,0,0)}}

/* Vignette: menggelapkan sudut supaya mata terpusat ke tengah. */
.cine-vig{inset:0;background:radial-gradient(ellipse 78% 72% at 50% 46%,transparent 52%,rgba(7,9,10,.42) 100%)}

/* Scanline: sangat tipis. Di atas .22 pola ini mulai berkedip
   (moire) pada layar 1x. */
.cine-scan{inset:0;opacity:.09;
  background:repeating-linear-gradient(0deg,rgba(0,0,0,.18) 0 1px,transparent 1px 3px);contain:strict}

/* Letterbox: menemani title card pembuka lalu ditarik pergi.
   Muncul penuh sampai 45% durasi (= saat shutter mulai terbuka). */
.cine-bar{left:0;right:0;height:6vh;background:#07090A;
  animation:cineBar 3s var(--out-expo) forwards}
.cine-bar-t{top:0;transform-origin:top}
.cine-bar-b{bottom:0;transform-origin:bottom}
@keyframes cineBar{0%,45%{transform:scaleY(1)}100%{transform:scaleY(0)}}
/* Kunjungan kedua dalam satu tab: intro dilewati (landing.js menandai
   <html>), jadi letterbox tidak boleh muncul sendirian selama 1,35 s
   tanpa title card yang seharusnya ia dampingi. */
.no-intro .cine-bar{display:none}

/* ---------- 2. TITLE CARD PEMBUKA ---------- */
/* z-index 9000 masih di bawah .auth-ov (10002) dan toast (10010):
   kalau sesi lama masih hidup dan app.js langsung membuka dashboard,
   #landing disembunyikan dan intro ikut lenyap bersamanya. */
.cine-intro{position:fixed;inset:0;z-index:9000;pointer-events:none;overflow:hidden}
/* Dua setengah layar, total 101%: 0,5% tumpang tindih menutup garis
   jahitan sub-pixel yang muncul di tengah pada zoom non-integer. */
.ci-half{position:absolute;left:0;right:0;height:50.5%;background:var(--bg)}
.ci-t{top:0;transform-origin:top;box-shadow:0 1px 0 rgba(84,171,155,.35);
  animation:ciOpenT .9s var(--out-expo) 1.25s forwards}
.ci-b{bottom:0;transform-origin:bottom;
  animation:ciOpenB .9s var(--out-expo) 1.25s forwards}
@keyframes ciOpenT{to{transform:translate3d(0,-101%,0)}}
@keyframes ciOpenB{to{transform:translate3d(0,101%,0)}}

.ci-mid{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  display:flex;flex-direction:column;align-items:center;gap:8px;
  animation:ciMidOut .38s var(--in-out) 1.02s forwards}
@keyframes ciMidOut{to{opacity:0;transform:translate(-50%,-50%) scale(.94)}}
.ci-mark{width:58px;height:58px;color:var(--tx);opacity:0;
  animation:ciMark .72s var(--spring) .05s forwards}
@keyframes ciMark{from{opacity:0;transform:scale(.5) rotate(-24deg)}to{opacity:1;transform:none}}
.ci-wm{font-size:13px;font-weight:800;text-transform:uppercase;color:var(--tx);opacity:0;
  letter-spacing:.6em;margin-top:8px;
  animation:ciWm .8s var(--out-expo) .22s forwards}
@keyframes ciWm{from{opacity:0;letter-spacing:.6em}to{opacity:1;letter-spacing:var(--track)}}
.ci-sub{font-size:9px;font-weight:600;text-transform:uppercase;letter-spacing:var(--track);color:var(--cr);
  opacity:0;animation:ciFade .6s var(--ease) .42s forwards}
@keyframes ciFade{to{opacity:1}}
.ci-line{display:block;width:120px;height:1px;margin-top:10px;background:linear-gradient(90deg,transparent,var(--accent),transparent);
  transform:scaleX(0);animation:ciLine .8s var(--out-expo) .38s forwards}
@keyframes ciLine{to{transform:scaleX(1)}}

/* ---------- 3. HERO DUA KOLOM ---------- */
.lp-hero-grid{position:relative;z-index:2;width:100%;max-width:1140px;margin:0 auto;
  display:grid;grid-template-columns:1fr;gap:28px;align-items:center}
.lp-hero-in{max-width:620px;justify-self:center}

.lp-trust{display:flex;flex-wrap:wrap;justify-content:center;gap:8px 22px;list-style:none;
  margin-top:28px;font-size:11px;color:var(--mu);letter-spacing:.02em}
.lp-trust li{display:flex;align-items:baseline;gap:6px;white-space:nowrap}
.lp-trust b{color:var(--tx);font-weight:800;font-size:13px;font-variant-numeric:tabular-nums}
.lp-trust li+li::before{content:'';width:3px;height:3px;border-radius:50%;background:var(--brd2);align-self:center;margin-right:10px}

@media(min-width:940px){
.lp-hero-grid{grid-template-columns:minmax(0,1.02fr) minmax(0,.98fr);gap:24px}
.lp-hero-in{text-align:left;max-width:560px;justify-self:start}
.lp-hero .lp-sub{margin-left:0;margin-right:0}
/* Di-scope ke .lp-hero-in: .lp-cta juga dipakai section penutup
   (.lp-final) yang tetap harus rata tengah. */
.lp-hero-in .lp-cta,.lp-hero-in .lp-trust{justify-content:flex-start}
}

/* Tambahan urutan entrance untuk elemen baru. Nilai awal hanya di
   .hero-anim, mengikuti pola landing.css. */
.lp-hero.hero-anim .lp-trust{opacity:0;transform:translateY(18px);
  transition:opacity .72s var(--out-expo) .48s,transform .72s var(--out-expo) .48s}
.lp-hero.hero-anim .stage{opacity:0;transform:translateY(26px) scale(.97);
  transition:opacity 1.1s var(--out-expo) .3s,transform 1.1s var(--out-expo) .3s}
.lp-hero.hero-anim.ready .lp-trust,
.lp-hero.hero-anim.ready .stage{opacity:1;transform:none}

/* ---------- 4. PANGGUNG KARAKTER ---------- */
/* Panggung memakai rasio figur (440/620) sebagai aspect-ratio-nya
   sendiri. Dengan begitu SVG mengisi kotak tepat tanpa sisa: kalau
   kotaknya lebih lebar, preserveAspectRatio bawaan akan me-letterbox
   figur di tengah dan halo + lantai — yang diposisikan relatif ke
   .stage — jadi melebar melampaui figur dan kehilangan jangkarnya.
   Tinggi yang menentukan, lebar mengikuti. */
.stage{--px:0;--py:0;position:relative;height:min(520px,58vh);min-height:340px;
  aspect-ratio:440/620;width:auto;max-width:100%;justify-self:center;isolation:isolate}

/* Satu kolom: blok teks memakan 380-440px dan padding hero 176px, jadi
   tinggi tetap 340-420px untuk panggung membuat hero meluber jauh
   melewati lipatan dan figurnya terpotong di dada. Tingginya karena itu
   dihitung dari ruang yang BENAR-BENAR tersisa: 100vh dikurangi padding
   (176px), perkiraan tinggi teks (28rem — headline 3 baris + sub + CTA
   + strip trust pada lebar tersempit), dan gap.

   min-height dinolkan: nilai 340px dari aturan dasar akan menang atas
   height mana pun dan membuat perhitungan ini tidak berpengaruh. Batas
   bawah dipegang clamp, dan 220px adalah titik di mana visor figur masih
   terbaca. */
@media(max-width:939px){
.stage{min-height:0;height:clamp(220px,calc(100vh - 176px - 28rem),420px)}
}
/* Layar pendek — ponsel lanskap, ponsel lama, jendela kecil: ruang
   jujur di bawah teks + CTA tipis. Figur tetap ditampilkan (animasi
   robot + drone diminta tampil di HP), tapi dikecilkan dan dibiarkan
   meluber ke bawah sebagai siluet — lebih baik terpotong sebagian
   daripada hilang sama sekali. */
@media(max-width:939px) and (max-height:800px){
.stage{min-height:0;height:150px;justify-self:end;opacity:.85}
}

.stage-halo{position:absolute;left:50%;top:42%;width:min(120%,520px);aspect-ratio:1;
  transform:translate(-50%,-50%);pointer-events:none;
  background:radial-gradient(circle,rgba(84,171,155,.20),rgba(84,171,155,.06) 38%,transparent 68%);
  animation:stageHalo 6.5s var(--in-out) infinite alternate;will-change:transform,opacity}
@keyframes stageHalo{from{opacity:.75;transform:translate(-50%,-50%) scale(.96)}to{opacity:1;transform:translate(-50%,-50%) scale(1.06)}}

/* Lantai: grid diproyeksikan dengan rotateX, dipudarkan ke tepi
   dengan mask supaya tidak berakhir sebagai persegi tegas. bottom:10%
   menyamakan horizonnya dengan garis tanah figur (y 556 dari 620). */
.stage-floor{position:absolute;left:-24%;right:-24%;bottom:10%;height:42%;pointer-events:none;
  background:
    linear-gradient(90deg,rgba(84,171,155,.18) 1px,transparent 1px) 0 0/44px 44px,
    linear-gradient(0deg,rgba(84,171,155,.18) 1px,transparent 1px) 0 0/44px 44px;
  transform:perspective(560px) rotateX(64deg);transform-origin:50% 100%;
  -webkit-mask-image:radial-gradient(ellipse 58% 90% at 50% 100%,#000 26%,transparent 78%);
  mask-image:radial-gradient(ellipse 58% 90% at 50% 100%,#000 26%,transparent 78%);
  animation:stageFloor 6s linear infinite}
@keyframes stageFloor{from{background-position:0 0,0 0}to{background-position:0 0,0 44px}}

/* Robot 3D (robot3d.js) mengisi panggung. Canvas transparan menimpa
   halo + lantai CSS di belakangnya. Ukuran diatur WebGL lewat
   renderer.setSize; di sini cukup memenuhi .stage. */
.ch3d{position:absolute;inset:0;width:100%;height:100%;display:block;z-index:1}

/* ---------- 5. KARTU HOLOGRAFIS ---------- */
/* Latar dinaikkan ke .93 dan backdrop-filter DIHAPUS. Ketiga kartu ini
   melayang tepat di atas canvas robot yang beranimasi; backdrop-filter
   memaksa browser membaca dan mem-blur ulang piksel di belakangnya tiap
   frame — tiga kali, di atas permukaan yang selalu berubah. Di atas
   panggung yang gelap, latar hampir pekat terbaca sama persis dengan
   latar tembus pandang yang di-blur, tanpa biaya itu. */
.holo{position:absolute;z-index:2;display:grid;grid-template-columns:auto 1fr;grid-template-rows:auto auto;
  column-gap:9px;row-gap:2px;align-items:center;padding:9px 12px 9px 11px;
  background:rgba(19,22,25,.93);border:1px solid rgba(84,171,155,.30);border-radius:var(--r2);
  box-shadow:var(--el2),inset 0 0 0 1px rgba(126,198,183,.05);
  text-transform:uppercase;white-space:nowrap;
  transition:translate .7s var(--out-expo)}
/* Garis hologram tipis di atas kartu. */
.holo::after{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;opacity:.35;
  background:repeating-linear-gradient(0deg,rgba(126,198,183,.08) 0 1px,transparent 1px 3px)}
.holo i{grid-row:1/3;width:6px;height:6px;border-radius:50%;background:var(--g);
  box-shadow:0 0 0 3px rgba(87,184,148,.16);animation:pulse 2s ease-in-out infinite}
.holo b{font-size:9px;font-weight:700;letter-spacing:var(--track);color:var(--accent)}
.holo span{grid-column:2;font-size:10px;font-weight:500;letter-spacing:.01em;text-transform:none;color:var(--mu)}
.holo-1{left:-2%;top:13%;animation:holoFloat 3.6s var(--in-out) infinite alternate;
  translate:calc(var(--px)*-18px) calc(var(--py)*-10px)}
.holo-2{right:-4%;top:46%;animation:holoFloat 4.3s var(--in-out) -1.3s infinite alternate;
  translate:calc(var(--px)*-26px) calc(var(--py)*-14px)}
.holo-3{left:0;bottom:15%;animation:holoFloat 3.9s var(--in-out) -2.2s infinite alternate;
  translate:calc(var(--px)*-12px) calc(var(--py)*-8px)}
@keyframes holoFloat{from{transform:translateY(0)}to{transform:translateY(-7px)}}
/* Satu kolom: panggung menyusut ke sisa ruang di bawah teks, dan pada
   lebar itu panggung hanya ~160-300px. Kartu holo selebar 145px akan
   menutupi figurnya hampir seluruhnya. Isinya pun sudah diulang oleh
   strip .lp-trust di atasnya, jadi tidak ada informasi yang hilang. */
@media(max-width:939px){.holo{display:none}}

/* ---------- 6. BAND MARQUEE ---------- */
.lp-band{position:relative;z-index:2;overflow:hidden;padding:16px 0;
  border-top:1px solid var(--brd);border-bottom:1px solid var(--brd);background:rgba(20,23,26,.6);
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent)}
.mq{display:flex;overflow:hidden;white-space:nowrap}
.mq+.mq{margin-top:10px}
/* Setiap track digeser sejauh lebarnya sendiri (-100%). Karena
   landing.js menyalin track sampai total >= 2x viewport, track
   berikutnya tepat mengambil posisi yang ditinggalkan. */
.mq-t{display:flex;align-items:center;gap:28px;padding-right:28px;flex-shrink:0;
  font-size:11px;font-weight:700;letter-spacing:var(--track);text-transform:uppercase;color:var(--tx2);
  animation:mqLeft var(--mq-dur,40s) linear infinite;will-change:transform}
.mq-t i{font-style:normal;font-size:6px;color:var(--cr);line-height:1}
.mq-alt{color:var(--mu)}
.mq-alt i{color:var(--brand)}
.mq[data-mq=right] .mq-t{animation-name:mqRight}
@keyframes mqLeft{from{transform:translate3d(0,0,0)}to{transform:translate3d(-100%,0,0)}}
@keyframes mqRight{from{transform:translate3d(-100%,0,0)}to{transform:translate3d(0,0,0)}}
.lp-band:hover .mq-t{animation-play-state:paused}

/* ---------- 7. PORTOFOLIO ---------- */
.pf{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}
.pf-wide{grid-column:span 2}
.pf-card{--rx:0deg;--ry:0deg;position:relative;display:flex;flex-direction:column;
  background:var(--card);border:1px solid var(--brd);border-radius:var(--r3);overflow:hidden;
  transition:opacity .62s var(--out-expo),transform .55s var(--out-expo),
    border-color var(--t-med) var(--ease),box-shadow var(--t-med) var(--ease)}
/* opacity ikut disebut di atas: rule ini punya specificity yang sama
   dengan [data-reveal] di ui.css tapi dimuat lebih akhir, jadi shorthand
   transition di sini menggantikannya seluruhnya. Tanpa opacity, reveal
   kartu berkedip muncul tanpa fade. */
/* ui.css memakai transform untuk reveal ([data-reveal] -> .in{transform:none}).
   Tilt hanya boleh mengambil alih SETELAH reveal selesai, karena itu
   diikat pada .in dengan specificity lebih tinggi. */
.pf-card[data-reveal].in{transform:perspective(900px) rotateX(var(--rx)) rotateY(var(--ry))}
.pf-card::before{content:'';position:absolute;inset:0;z-index:3;pointer-events:none;opacity:0;
  background:radial-gradient(360px circle at var(--mx,50%) var(--my,50%),rgba(84,171,155,.12),transparent 66%);
  transition:opacity var(--t-med) var(--ease)}
.pf-card:hover{border-color:var(--brd2);box-shadow:var(--el3),0 0 0 1px rgba(84,171,155,.16)}
.pf-card:hover::before{opacity:1}

/* Tinggi art seragam untuk semua kartu. Sebelumnya kartu wide dibuat
   210px dan kartu biasa 190px; karena keduanya berdampingan dalam satu
   baris grid, tag dan judul di bawahnya jadi tidak sebaris dan barisnya
   terbaca miring. */
.pf-art{position:relative;height:200px;overflow:hidden;border-bottom:1px solid var(--brd);
  background:linear-gradient(180deg,#151A1E,#10141A)}
.pf-sheen{position:absolute;inset:0;z-index:2;pointer-events:none;
  background:linear-gradient(112deg,transparent 42%,rgba(236,239,239,.075) 50%,transparent 58%);
  transform:translateX(-100%);transition:transform 1s var(--out-expo)}
.pf-card:hover .pf-sheen{transform:translateX(100%)}

/* 7a. Bar chart Token PLN. --h dari inline style, index dari nth-child.
   left/right 26px menyisakan margin; bottom 0 menempelkan bar ke garis
   pemisah art/body sehingga terbaca sebagai grafik, bukan balok melayang. */
.pf-art-1{background:
  linear-gradient(0deg,rgba(84,171,155,.08) 1px,transparent 1px) 0 0/100% 38px,
  linear-gradient(180deg,#151A1E,#10141A)}
.pf-bars{position:absolute;left:26px;right:26px;bottom:0;height:74%;display:flex;align-items:flex-end;gap:7px}
.pf-bars i{flex:1;height:var(--h,40%);border-radius:3px 3px 0 0;
  background:linear-gradient(180deg,var(--accent),var(--brand) 80%);
  transform-origin:bottom;animation:pfBar 2.8s var(--in-out) infinite alternate;
  box-shadow:0 0 18px -6px rgba(84,171,155,.6)}
/* Fase dibedakan per kolom prima supaya polanya tidak berulang tiap
   beberapa bar dan grafiknya terbaca hidup, bukan bergelombang serempak. */
.pf-bars i:nth-child(2n){animation-duration:3.3s}
.pf-bars i:nth-child(3n){animation-delay:-.9s}
.pf-bars i:nth-child(4n){animation-delay:-1.7s}
.pf-bars i:nth-child(5n){animation-duration:2.4s}
@keyframes pfBar{from{transform:scaleY(.58);opacity:.7}to{transform:scaleY(1);opacity:1}}

/* 7b. Aliran thread Mass Checkout: 8 jalur horizontal, tiap paket
   berjalan dari kiri ke kanan dengan fase berbeda. Jalur diposisikan
   dalam persen, bukan px, supaya tetap terbagi rata pada kartu wide
   (210px) maupun biasa (190px) dan pada breakpoint mobile (170px). */
.pf-art-2{background:
  repeating-linear-gradient(0deg,transparent 0 21px,rgba(84,171,155,.10) 21px 22px) 0 10px/100% 22px,
  linear-gradient(180deg,#151A1E,#10141A)}
.pf-flow{position:absolute;inset:0}
.pf-flow i{position:absolute;left:-14%;width:12%;height:3px;border-radius:2px;
  background:linear-gradient(90deg,transparent,var(--accent));box-shadow:0 0 10px rgba(126,198,183,.5);
  animation:pfFlow 2.6s linear infinite}
.pf-flow i:nth-child(1){top:10%;animation-delay:0s}
.pf-flow i:nth-child(2){top:21%;animation-delay:-1.1s;animation-duration:3.1s}
.pf-flow i:nth-child(3){top:32%;animation-delay:-.4s}
.pf-flow i:nth-child(4){top:43%;animation-delay:-2s;animation-duration:2.2s}
.pf-flow i:nth-child(5){top:55%;animation-delay:-1.6s}
.pf-flow i:nth-child(6){top:66%;animation-delay:-.8s;animation-duration:3.4s}
.pf-flow i:nth-child(7){top:77%;animation-delay:-2.3s}
.pf-flow i:nth-child(8){top:88%;animation-delay:-1.3s;animation-duration:2.4s}
@keyframes pfFlow{from{transform:translateX(0)}to{transform:translateX(950%)}}

/* 7c. Orbit provider OTP: inti + 4 satelit pada dua radius.
   Cincin terluar 160px, di bawah tinggi art terkecil (170px di mobile),
   supaya lingkarannya tidak terpotong jadi busur di sisi atas-bawah. */
.pf-art-3::before,.pf-art-3::after{content:'';position:absolute;left:50%;top:50%;border-radius:50%;
  border:1px solid rgba(84,171,155,.22);transform:translate(-50%,-50%)}
.pf-art-3::before{width:96px;height:96px}
.pf-art-3::after{width:160px;height:160px;border-style:dashed;opacity:.6}
.pf-orbit{position:absolute;left:50%;top:50%;width:0;height:0}
.pf-orbit::before{content:'';position:absolute;left:-9px;top:-9px;width:18px;height:18px;border-radius:50%;
  background:radial-gradient(circle,#EAFFF9,var(--accent) 45%,transparent 72%);
  box-shadow:0 0 24px rgba(126,198,183,.6);animation:chCore 2.2s var(--in-out) infinite alternate}
.pf-orbit i{position:absolute;left:-4px;top:-4px;width:8px;height:8px;border-radius:50%;background:var(--accent);
  box-shadow:0 0 10px rgba(126,198,183,.7);animation:pfOrbit var(--d,6s) linear infinite}
.pf-orbit i:nth-child(1){--r:48px;--d:5.2s}
.pf-orbit i:nth-child(2){--r:48px;--d:5.2s;animation-delay:-2.6s;background:var(--cr)}
.pf-orbit i:nth-child(3){--r:80px;--d:9s;animation-delay:-3s}
.pf-orbit i:nth-child(4){--r:80px;--d:9s;animation-delay:-7.5s;background:var(--tx2);box-shadow:none;width:6px;height:6px}
@keyframes pfOrbit{from{transform:rotate(0) translateX(var(--r))}to{transform:rotate(360deg) translateX(var(--r))}}
@keyframes chCore{from{transform:scale(.9);opacity:.85}to{transform:scale(1.1);opacity:1}}

/* 7d. Kartu QRIS: papan kotak-kotak dengan tiga finder pattern dan
   garis pemindai. Bukan QR asli — cukup untuk terbaca sebagai QR. */
.pf-art-4{background:
  radial-gradient(circle at 50% 50%,rgba(84,171,155,.14),transparent 60%),
  linear-gradient(180deg,#151A1E,#10141A)}
.pf-qr{position:absolute;left:50%;top:50%;width:124px;height:124px;transform:translate(-50%,-50%);
  background:var(--tx);border-radius:8px;box-shadow:var(--el3);overflow:hidden}
/* Modul + tiga finder pattern, semuanya lapisan background pada satu
   pseudo-element. Urutan lapisan = urutan lukis (pertama paling atas):
   inti finder (10px) > cincin putih (18px) > kotak luar (26px) > grid. */
.pf-qr::before{content:'';position:absolute;inset:10px;background:
    linear-gradient(#1A1E22,#1A1E22) 8px 8px/10px 10px no-repeat,
    linear-gradient(#EDEFEF,#EDEFEF) 4px 4px/18px 18px no-repeat,
    linear-gradient(#1A1E22,#1A1E22) 0 0/26px 26px no-repeat,
    linear-gradient(#1A1E22,#1A1E22) calc(100% - 8px) 8px/10px 10px no-repeat,
    linear-gradient(#EDEFEF,#EDEFEF) calc(100% - 4px) 4px/18px 18px no-repeat,
    linear-gradient(#1A1E22,#1A1E22) 100% 0/26px 26px no-repeat,
    linear-gradient(#1A1E22,#1A1E22) 8px calc(100% - 8px)/10px 10px no-repeat,
    linear-gradient(#EDEFEF,#EDEFEF) 4px calc(100% - 4px)/18px 18px no-repeat,
    linear-gradient(#1A1E22,#1A1E22) 0 100%/26px 26px no-repeat,
    repeating-conic-gradient(#1A1E22 0 25%,transparent 0 50%) 0 0/13px 13px,
    repeating-conic-gradient(transparent 0 25%,#1A1E22 0 50%) 6.5px 6.5px/26px 26px}
/* Garis pemindai turun-naik di atas kode. */
.pf-qr::after{content:'';position:absolute;left:0;right:0;top:0;height:3px;
  background:linear-gradient(90deg,transparent,var(--cr),transparent);
  box-shadow:0 0 14px 2px rgba(84,171,155,.6);animation:pfScan 2.6s var(--in-out) infinite alternate}
@keyframes pfScan{to{transform:translateY(121px)}}

/* 7e. Isi kartu */
.pf-body{padding:20px 22px 22px;display:flex;flex-direction:column;gap:8px;flex:1}
.pf-tag{align-self:flex-start;font-size:9px;font-weight:700;letter-spacing:var(--track);text-transform:uppercase;
  color:var(--cr);padding:4px 10px;border-radius:var(--rp);
  background:rgba(84,171,155,.10);border:1px solid rgba(84,171,155,.26)}
.pf-body h3{font-size:16px;font-weight:700;letter-spacing:-.015em;line-height:1.3;color:var(--tx);margin-top:2px}
.pf-body p{font-size:12.5px;line-height:1.62;color:var(--mu)}
.pf-kpi{display:flex;flex-wrap:wrap;gap:12px 28px;margin-top:auto;padding-top:14px;border-top:1px solid var(--brd)}
.pf-kpi b{display:block;font-size:24px;font-weight:800;letter-spacing:-.02em;color:var(--tx);font-variant-numeric:tabular-nums;line-height:1.1}
.pf-kpi span{display:block;margin-top:3px;font-size:9px;font-weight:600;letter-spacing:var(--track);text-transform:uppercase;color:var(--mu)}

@media(max-width:900px){
.pf{grid-template-columns:repeat(2,minmax(0,1fr))}
.pf-wide{grid-column:span 2}
}
@media(max-width:620px){
.pf{grid-template-columns:1fr}
.pf-wide{grid-column:auto}
.pf-art{height:170px}
}

/* ---------- 8. SPLIT TEXT ---------- */
/* landing.js membungkus tiap kata: <span class="sw"><span class="si">kata</span></span>.
   .sw memotong (overflow hidden), .si naik dari bawah. Padding menjaga
   descender (y, g, p) dan sisi huruf tidak terpotong. */
.sw{display:inline-block;overflow:hidden;vertical-align:bottom;padding:.16em .12em .14em;margin:-.16em -.12em -.14em}
.si{display:inline-block;transform:translateY(112%);
  transition:transform .85s var(--out-expo);transition-delay:calc(var(--i,0)*.05s)}
/* Potongan dilepas setelah kata terakhir selesai bergerak. .lp-h1
   memakai text-shadow blur 30px; selama .sw masih memotong, shadow itu
   ikut terpotong dan setiap kata mendapat kotak persegi yang terlihat
   begitu banner 3D di belakangnya sedang terang. landing.js memasang
   .split-done dari transitionend kata terakhir. */
.split-done .sw{overflow:visible}
/* Headline hero: kata-katanya sudah meluncur naik sendiri, jadi
   geseran blok h1 dari landing.css dilepas — dua gerakan bertumpuk
   membuat teks tampak buram saat masuk. Diikat ke .is-split yang hanya
   dipasang landing.js kalau pemecahan kata betul-betul terjadi. */
.lp-hero.hero-anim .lp-h1.is-split{transform:none}
/* background-clip:text pada <em> tidak menembus inline-block di
   dalamnya, jadi gradien dipasang ulang pada tiap kata hasil split. */
.lp-h1 em .si{background:linear-gradient(103deg,var(--accent),var(--cr) 46%,var(--brand));
  -webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent}
/* Pemicu: hero lewat .ready, section lewat [data-reveal].in.
   Elemen [data-split] yang tak punya pemicu manapun diberi class
   split-in oleh landing.js sebagai jaring pengaman. */
.lp-hero.ready .si,[data-reveal].in .si,.split-in .si{transform:none}
/* Kalau .hero-anim tidak dipasang (reduced-motion / JS mati sebelum
   boot), kata-kata tidak boleh tertahan di bawah. */
.lp-hero:not(.hero-anim) .si{transform:none;transition:none}

/* ---------- 8b. DRONE PENDAMPING KELILING ---------- */
/* Drone hero disalin ringan oleh landing.js ke #mascot, lalu melayang
   sepanjang viewport. Lapisan fixed, pointer-events none, di atas konten
   (z-index 2) tapi di bawah nav (60) supaya tidak pernah menghalangi
   klik maupun menutupi tombol nav. --mx/--my diisi JS; properti custom
   dipakai supaya translate+rotate bisa dikomposisikan browser tanpa
   saling menimpa transform idlenya. */
.mascot{position:fixed;inset:0;z-index:40;pointer-events:none;overflow:hidden}
.mascot .m-drone{position:absolute;left:0;top:0;width:150px;height:auto;
  will-change:transform;transform:translate3d(var(--mx,50vw),var(--my,30vh),0);
  transition:transform 1.8s var(--out-expo);
  /* smooth: cubic-bezier sudah, durasi sedikit lebih panjang = less jank */}
@media(prefers-reduced-motion:reduce){.mascot .m-drone{transition:none}}
/* Idle melayang: naik-turun halus + rotasi kecil, memakai properti
   individual translate/rotate supaya tidak menimpa transform posisi. */
.mascot .m-drone .m-body{transform-box:fill-box;transform-origin:50% 50%;
  translate:0 0;animation:mDroneBob 4.2s var(--in-out) infinite alternate}
.mascot .m-drone .m-beam{transform-box:fill-box;transform-origin:50% 0;
  animation:mDroneBeam 2.4s var(--in-out) infinite alternate}
@keyframes mDroneBob{from{translate:0 0;rotate:0deg}to{translate:0 -14px;rotate:2deg}}
@keyframes mDroneBeam{from{opacity:.55;transform:scaleX(.9)}to{opacity:1;transform:scaleX(1.06)}}
/* Ponsel: drone dikecilkan supaya tidak menutupi konten satu kolom. */
@media(max-width:700px){.mascot .m-drone{width:96px}}

/* ---------- 9. GERAK MINIMUM ---------- */
/* Dikunci ke .calm pada <html>, bukan ke media query langsung — lihat
   catatan panjang di app.css. Yang dimatikan hanya gerak berulang
   (loop tanpa akhir) dan gerak besar; sorotan hover, perubahan warna,
   dan fade tetap ada supaya halaman tidak terasa rusak. */
html.calm .cine-intro,html.calm .cine-bar{display:none}
html.calm .cine-flare,html.calm .cine-grain,html.calm .stage-halo,html.calm .stage-floor,
html.calm .mq-t,html.calm .holo,html.calm .holo i,
html.calm .pf-bars i,html.calm .pf-flow i,html.calm .pf-orbit i,
html.calm .pf-orbit::before,html.calm .pf-qr::after{animation:none}
html.calm .pf-flow i{transform:translateX(450%)}
html.calm .mascot{display:none}
html.calm .lp-hero.hero-anim .lp-trust,html.calm .lp-hero.hero-anim .stage{opacity:1;transform:none}
html.calm .pf-card[data-reveal].in{transform:none}
html.calm .si{transform:none;transition:none}
html.calm .pf-sheen{display:none}
