/* ═══════════════════════════════════════════════════════════════════════════
   card.css — ENJIN Studio Intro Kad (diden 2026-07-15)

   Satu fail dikongsi SEMUA rekaan studio. Sebelum ni setiap rekaan = satu blade
   dgn CSS inline sendiri (71 blade, 96KB CSS, dihantar semula setiap kali kad
   dibuka, tak boleh cache). Rekaan studio tak bawa CSS langsung — ia cuma
   pancarkan beberapa pemboleh ubah CSS per node. Fail ini yang tahu caranya.

   Prefix `kd-` (kad). BUKAN `ad-` — ad-blocker sorok elemen berawalan itu.

   ⚠️ "token" dlm projek ni = DUIT (Wallet/TokenTransaction). Nilai rupa kad
      dipanggil TEMA / pemboleh ubah CSS. Jangan campur.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── KANVAS ────────────────────────────────────────────────────────────────
   Nisbah TETAP (keputusan diden): koordinat % pereka = koordinat % user, di
   semua telefon. container-type:size membolehkan unit `cqw` — saiz font/elemen
   berskala dgn LEBAR KAD, bukan lebar skrin, jadi rekaan tak pecah dlm editor
   (kad dlm bingkai kecil) mahupun penuh skrin.                              */
.kd-canvas{
    position:relative; width:100%; margin:0 auto;
    aspect-ratio:var(--kd-ar, 420/672);
    container-type:size;
    overflow:hidden; isolation:isolate;
    background:var(--kd-bg, transparent);
}
.kd-canvas.is-full{aspect-ratio:auto; min-height:100dvh}

/* ── MOD MODUL (diden 2026-07-19, mula KU-413) ────────────────────────────
   Kanvas modul TIDAK ikut preset tinggi intro — tinggi DINAMIK ikut kandungan (setiap modul
   beza tinggi, sama spt blade modul asal). Lapisan content masuk ALIRAN dokumen (relative)
   dan MENENTUKAN tinggi kanvas; lapisan lain kekal absolute menutup tinggi itu.
   container-type mesti inline-size: containment saiz penuh kolapskan tinggi auto ke 0;
   cqw (unit lebar) kekal sah dgn inline-size. NOTA: perlukan stack layout ON utk content
   (anak absolute tak beri tinggi) — v1 modul memang stack. */
.kd-canvas.kd-mod{aspect-ratio:auto; container-type:inline-size; min-height:96px; display:grid}
/* wrapper NAV studio (diden 2026-07-21): (1) hiasan design boleh menjulur ATAS bar
   (crest awan, pelangi) — jangan klip; (2) container-type = LAYOUT CONTAINMENT yang
   MEMERANGKAP position:fixed → nav tak lekat bawah skrin (lapor diden: "tak function
   dekat rekabuilder preview") — matikan utk jenis ini. Saiz label cqw selamat: _nav
   set container-type pd .jd-nv sendiri. */
.blk-bnav-st .kd-canvas{overflow:visible;container-type:normal}
/* kd-mod grid min-height 96px MEREGANG nav dlm kanvas EDITOR (nav relative dlm aliran;
   diden 2026-07-21 "ketinggian tak tepat dlm builder") — tinggi nav ikut MENU sendiri.
   Kad tetamu tak terkesan: nav position:fixed, keluar aliran grid. */
.blk-bnav-st .kd-canvas.kd-mod{min-height:0}

/* ── FULL CODE (mode 'code', diden 2026-07-19) — elemen output <jd:slot/> ─────
   .jd-slot = teks (inline; pereka style pembalutnya sendiri). .jd-gfx = grafik arabic
   (saiz asas dari CSS pereka; --gfx-s = slider Saiz USER, corak sama _bismillah). */
.jd-slot{display:inline}
/* flex tengah + max-width:none (fix diden 2026-07-20): dulu max-width:100% MENGUNCI
   --gfx-s > 1 → slider saiz gfx user "tak berkesan" bila membesar (KU-459). Flex →
   limpah melebihi wrapper diagih seimbang kiri/kanan. */
.jd-gfx{display:flex;justify-content:center;line-height:0;margin:0 auto}
.jd-gfx img{display:block;flex:none;width:calc(100% * var(--gfx-s,1));max-width:none;height:auto}
/* gfx BERTINT (colors.gfx design): .kd-tint img{width:100%} (bawah) menang atas formula di atas
   → skala dipindah ke PEMBALUT tint; img dlmnya kekal 100% (kontrak mask). (fix diden 2026-07-20:
   "saiz gfx tak berubah" — KU-459 bertint #c3a054) */
.jd-gfx .kd-tint{width:calc(100% * var(--gfx-s,1));flex:none}
.jd-gfx-txt{display:block;line-height:1.7;direction:rtl;font-family:var(--font-arabic,'Amiri',serif)}
/* <jd:countdown/> — gaya DEFAULT neutral; CSS design bebas override (.jd-cd dll) */
.jd-cd{display:flex;justify-content:center;gap:3cqw;margin:2% 0}
.jd-cd-u{display:flex;flex-direction:column;align-items:center;min-width:11cqw;padding:2cqw 1.5cqw;
  border:1px solid currentColor;border-radius:8px;opacity:.92}
.jd-cd-n{font-size:5cqw;font-weight:600;line-height:1.1;font-variant-numeric:tabular-nums}
.jd-cd-l{font-size:2.2cqw;letter-spacing:.12em;text-transform:uppercase;opacity:.75;margin-top:.6cqw}
/* grid: lapisan content (satu-satunya anak dlm-aliran) REGANG ikut tinggi kanvas — bila
   Ketinggian Modul (mh) dinaikkan, stack center menegak betul, bukan lekat atas */
.kd-mod .kd-l-content{position:relative; inset:auto}

/* ── LAPISAN (urutan z: diden 2026-07-15) ──────────────────────────────────
   1 background · 2 frame · 3 back · 4 content · 5 front
   `back` DI ATAS `frame` — sengaja: ornamen/daun boleh MELIMPAH menyilang garis
   bingkai (rupa kad kahwin klasik). Kalau frame di atas, bingkai memotong daun. */
.kd-l{position:absolute; inset:0}
.kd-l-background{z-index:1; background-size:cover; background-position:center; background-repeat:no-repeat}
/* z-index BOLEH DITUKAR (diden 2026-08-03) — lapisan ini ada z-index eksplisit,
   jadi menyusun semula DOM sahaja TIDAK mengubah apa yang nampak di atas: z-index
   sentiasa menang. Kelas `kd-frame-top` pd kanvas menukar kedua-duanya sekali. */
.kd-l-frame     {z-index:2}
.kd-l-back      {z-index:3}
.kd-frame-top .kd-l-frame{z-index:3}
.kd-frame-top .kd-l-back {z-index:2}
/* Front turun BAWAH content — hiasan hadapan di belakang teks. pointer-events
   dikembalikan sebab ia bukan lagi lapisan teratas yang menghalang klik. */
.kd-front-under .kd-l-front  {z-index:4; pointer-events:auto}
.kd-front-under .kd-l-content{z-index:5}
.kd-l-content   {z-index:4}
.kd-l-front     {z-index:5; pointer-events:none}   /* dekorasi hadapan tak boleh halang klik teks */
/* content-stack (auto-rhythm, diden 2026-07-16) — layer content jadi flex-column BERPUSAT; anak FLOW
   (bukan absolute) dgn gap sekata. Frame/latar/front kekal absolute. */
.kd-l-content.kd-stack{ display:flex; flex-direction:column; align-items:var(--sal,center);
    justify-content:center; gap:var(--sgap,4cqw); padding:7% 0; }
.kd-l-content.kd-stack > .kd-n{ position:static; left:auto; top:auto; width:var(--w,auto); max-width:92%;
    transform:rotate(var(--rot,0deg)) rotate(var(--sw,0deg)); }

/* ── NODE ──────────────────────────────────────────────────────────────────
   Kedudukan bebas: x/y = % kanvas, w = % lebar kanvas, rot = putaran.
   --tx/--ty diisi oleh kelas anchor supaya `left/top` merujuk titik yg pereka
   maksudkan (tengah node, bukan sentiasa bucu kiri-atas).                   */
.kd-n{
    position:absolute;
    left:var(--x,0); top:var(--y,0); width:var(--w,auto);
    transform:translate(var(--tx,0), var(--ty,0)) rotate(var(--rot,0deg)) rotate(var(--sw,0deg));
    transform-origin:var(--org, 50% 50%);   /* putaran berpaksi pd TITIK ANCHOR (diden) */
    opacity:var(--o,1);
}
.kd-a-c  {--tx:-50%; --ty:-50%; --org:50% 50%}        /* tengah (default teks) */
.kd-a-tl {--tx:0;    --ty:0;    --org:0 0}
.kd-a-tc {--tx:-50%; --ty:0;    --org:50% 0}
.kd-a-tr {--tx:-100%; --ty:0;    --org:100% 0}
.kd-a-l  {--tx:0;    --ty:-50%; --org:0 50%}
.kd-a-r  {--tx:-100%; --ty:-50%; --org:100% 50%}
.kd-a-bl {--tx:0;    --ty:-100%; --org:0 100%}
.kd-a-bc {--tx:-50%; --ty:-100%; --org:50% 100%}
.kd-a-br {--tx:-100%; --ty:-100%; --org:100% 100%}

/* ── TEKS ──────────────────────────────────────────────────────────────────
   size dlm `cqw` = % lebar kad. Pereka set 7 → teks sentiasa 7% lebar kad.
   Berat 500 default (arahan diden: 700 terlalu tebal utk UI/kad).           */
.kd-t{
    margin:0;
    /* fallback muktamad = font asas kad (Cormorant, spt blade modul lama): tanpa ini,
       konteks yg TIDAK definisikan --font-body (studio, preview) jatuh ke font UI sans —
       pereka nampak rupa BERBEZA drpd tetamu (laporan diden 2026-07-19). Kad yg set
       --font-body sendiri tetap menang. */
    font-family:var(--f, var(--font-body, 'Cormorant Garamond', Georgia, serif));
    font-size:calc(var(--s, 4cqw) * var(--fit, 1));   /* --fit dikecilkan oleh jd-fit.js utk .kd-fit */
    font-weight:var(--fw, 500);
    color:var(--c, var(--kd-primary, #3d3427));
    letter-spacing:var(--ls, 0);
    line-height:var(--lh, 1.3);
    text-align:var(--ta, center);
    font-style:var(--fs, normal);
    white-space:pre-line;      /* pereka boleh pecah baris dlm teks */
    text-wrap:balance;
    overflow-wrap:anywhere;    /* perkataan panjang tanpa ruang WAJIB break (elak overflow melintang)
                                  walau Height=Auto (tanpa .kd-fit) — fix diden 2026-07-22 */
}
.kd-t:focus{outline:none}
.kd-t[data-field]:focus{background:rgba(124,58,237,.10); border-radius:4px}   /* sama dgn blok lain */
/* Auto-fit teks (diden 2026-07-22): kotak TETAP Width×Height (--w/--h). jd-fit.js kecikkan
   --fit sampai teks muat — nama panjang user tak pecah layout, tak terpotong. overflow:hidden =
   jaring bila JS belum jalan (potong, bukan melimpah). grid+align-content = teks tengah menegak. */
.kd-fit{ height:var(--h); overflow:hidden; overflow-wrap:anywhere; word-break:break-word;
    display:flex; flex-direction:column; justify-content:var(--fit-jc, center); }
/* RULE OF CENTER (diden 2026-07-22): teks center menegak dlm kotak fit, DEFAULT — reusable
   di blok lain (override --fit-jc: flex-start atas / flex-end bawah). break perkataan panjang
   -> overflow jadi menegak. jd-fit ukur guna top-align SEMENTARA (center pecahkan scrollHeight). */

/* ── DEKORASI (imej/SVG) ───────────────────────────────────────────────────
   Sentiasa <img> (bukan background-image): boleh di-cache, ada width/height,
   dan aset boleh ditukar tanpa sentuh CSS.                                  */
.kd-d{display:block; width:100%; height:auto; pointer-events:none; user-select:none}
.kd-d.is-cover{height:100%; object-fit:cover}

/* Latar video — menutup lapisan background sepenuhnya, di BELAKANG segalanya. */
.kd-bgv{position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block}

/* ── GRAFIK BERWARNA (mask) ────────────────────────────────────────────────
   SVG/PNG telus boleh diwarna semula: aset jadi MASK, warna/gradien jadi latar. <img> tak boleh
   diwarna; mask boleh — dan ia mengekalkan bentuk tepat kaligrafi/ornamen.
   Imej dalam (visibility:hidden) yang memberi kotak ini TINGGI mengikut nisbah asli aset —
   tanpa ia, kita tak tahu tinggi aset dan mask jadi kotak leper. */
.kd-tint{
    display:block; width:100%;
    background:var(--fill, currentColor);
    -webkit-mask:var(--m) center/contain no-repeat;
            mask:var(--m) center/contain no-repeat;
}
.kd-tint img{width:100%; height:auto; display:block; visibility:hidden}

/* ── BINGKAI ───────────────────────────────────────────────────────────────
   Dua rupa: garis (CSS, sifar bait aset) atau imej PNG/SVG (bingkai berukir). */
.kd-frame-line{
    position:absolute; inset:var(--inset, 5%);
    border:var(--bw, 1px) var(--bs, solid) var(--bc, var(--kd-frame, #c3a054));
    border-radius:var(--br, 0);
}

/* ── ANIMASI ───────────────────────────────────────────────────────────────
   Pustaka DIKONGSI — ditakrif SEKALI di sini. Rekaan cuma pilih nama.
   Sebelum ni seluruh sistem ada 1 @keyframes; kalau setiap template tulis
   sendiri, pendua merebak dari kosong. Ini menghentikannya sebelum bermula.  */
/* --sw = sudut animasi (swing/sway/spin). DIPISAHKAN dari --rot (putaran statik pereka).
   Didaftar sbg <angle> supaya keyframe interpolate lancar; disuap ke transform .kd-n DALAM
   rantaian yg sama dgn translate anchor → putaran TAK memutar offset kedudukan (sifar hanyut). */
@property --sw { syntax:'<angle>'; inherits:false; initial-value:0deg; }
.kd-anim{ animation:var(--anim, none); animation-play-state:running; }

/* ── CETUSAN OPENER ────────────────────────────────────────────────────────
   Animasi TAK boleh main sebelum tetamu buka sampul kad (opener). Bila opener wujud, <body> dapat
   `.kd-hold` (server) → animasi DIBEKUKAN. jdOpenCard() tambah `.kd-revealed` → animasi MAIN dari
   awal. Tiada opener = tiada .kd-hold → main masa load (selamat tanpa JS). */
.kd-hold:not(.kd-revealed) .kd-anim{ animation-play-state:paused; }

/* ENTRANCE — main sekali, berakhir pd REHAT (opacity 1, translate/scale/rotate 0). */
@keyframes kd-fade      {from{opacity:0}                                to{opacity:1}}
@keyframes kd-reveal-up {from{opacity:0; translate:0 14%}               to{opacity:1; translate:0 0}}
@keyframes kd-reveal-dn {from{opacity:0; translate:0 -14%}              to{opacity:1; translate:0 0}}
@keyframes kd-zoom-in   {from{opacity:0; scale:.88}                     to{opacity:1; scale:1}}
@keyframes kd-zoom-out  {from{opacity:0; scale:1.12}                    to{opacity:1; scale:1}}
@keyframes kd-slide-l   {from{opacity:0; translate:-12% 0}              to{opacity:1; translate:0 0}}
@keyframes kd-slide-r   {from{opacity:0; translate:12% 0}               to{opacity:1; translate:0 0}}
@keyframes kd-unfurl    {from{opacity:0; scale:.6; rotate:-8deg}        to{opacity:1; scale:1; rotate:0deg}}
/* rotate-gentle: ENTRANCE putaran PENUH 360° — sebulat ke KIRI (fade masuk) lalu sebulat ke KANAN,
   mendap ke rehat. Main SEKALI. (diden: putaran penuh 360 dari kiri kemudian kanan slowly) */
@keyframes kd-rotate-gentle {0%{opacity:0; rotate:0deg} 50%{opacity:1; rotate:-360deg} 100%{rotate:0deg}}

/* ── LOOP ──────────────────────────────────────────────────────────────────
   TEKNIK PROTOTYPE diden (swing-gentle.html): 2 keyframe (REHAT → puncak) + `ease-in-out` +
   `alternate` (lihat animCss). alternate = ayun ke satu arah lalu balik; ease-in-out atas 2-keyframe
   = PERLAHAN di setiap hujung (bandul sebenar) → licin, tiada micro-terhenti. `from` = rehat =
   keadaan akhir entrance → sambungan MULUS. (Spin = kes khas: 360 penuh, linear, tiada alternate.) */
@keyframes kd-swing     {from{--sw:0deg} to{--sw:var(--sd,20deg)}}   /* sudut boleh dilaras (Swing angle) — 10 gentle … 360 sweep penuh */
/* Swing "both sides" (R↔L) — pendulum PENUH lalu tengah: mula/akhir di REHAT (0) → sambungan
   entrance kekal mulus; laju di tengah, perlahan di hujung (easing per-stop, animasi = linear). */
@keyframes kd-swing-both {
    0%   {--sw:0deg;                       animation-timing-function:ease-out}
    25%  {--sw:calc(-1 * var(--sd,20deg)); animation-timing-function:ease-in}
    50%  {--sw:0deg;                       animation-timing-function:ease-out}
    75%  {--sw:var(--sd,20deg);            animation-timing-function:ease-in}
    100% {--sw:0deg}
}
@keyframes kd-sway      {from{--sw:0deg} to{--sw:14deg}}
@keyframes kd-sway-soft {from{--sw:0deg} to{--sw:7deg}}
@keyframes kd-sway-wide {from{--sw:0deg} to{--sw:26deg}}
/* Spin (Ease) (diden 2026-07-21): SATU loop — easing per-pusingan dipilih user (animCss),
   arah via --sp (360deg ikut jam / -360deg lawan jam). Ganti Spin 360 + Spin (ease).
   v2: JANGAN henti 0-ke-0 di sempadan pusingan (diden) — slope bezier hujung = slope mula
   dan >0 pd SEMUA gaya, jadi sambungan pusingan sentiasa hidup. Lembut/Denyut = bezier
   simetri luaran (perlahan di sempadan, 36%/10% laju purata). Pecut/Lepas tak simetri →
   keyframes sendiri: titik perlahan DALAM kitaran, sempadan dipadankan pd 0.35x. */
@keyframes kd-spin      {from{--sw:0deg} to{--sw:var(--sp,360deg)}}
/* Wind-up: slow half (50% time, 126°) … faster half — v3 (diden: "tak berapa smooth"):
   derivatif bezier dikira numerik — puncak 1.62x purata (v1: 3.2x), sempadan padan 0.56x,
   junction 0.74x → gelombang lembut, kontras ~3:1. Karakter lebih dramatik = panjangkan
   Loop speed (sampai 20s). */
@keyframes kd-spin-in {
    0%  {--sw:0deg;                            animation-timing-function:cubic-bezier(.35,.28,.7,.68)}
    50% {--sw:calc(var(--sp,360deg) * .35);    animation-timing-function:cubic-bezier(.3,.17,.65,.85)}
    100%{--sw:var(--sp,360deg)}
}
/* Release: faster half first … slow glide — mirror of Wind-up, same softened contrast */
@keyframes kd-spin-out {
    0%  {--sw:0deg;                            animation-timing-function:cubic-bezier(.35,.15,.7,.83)}
    50% {--sw:calc(var(--sp,360deg) * .65);    animation-timing-function:cubic-bezier(.3,.32,.65,.72)}
    100%{--sw:var(--sp,360deg)}
}
/* ── LOOP v2 (diden 2026-07-21): dua-stop from→to kasar diganti MULTI-STOP organik —
     0% = 100% (seamless, linear normal), easing PER-STOP (corak terbukti kd-swing-both),
     transform/opacity shj (GPU compositor). ── */
/* LEGASI: spin-ease digabung ke kd-spin + gaya 'inout' (migrasi client+server); keyframe
   kekal utk render cache lama sahaja — jangan guna utk kerja baru. */
@keyframes kd-spin-ease {0%{--sw:0deg;animation-timing-function:cubic-bezier(.45,.05,.55,.95)} 100%{--sw:360deg}}
/* v2.1 (diden 2026-07-21): --la = KEKUATAN loop (amplitud, default 1 — slider "Kekuatan"
   di studio, corak sama Swing angle). Float/drift ditala semula supaya natural. */
/* Float: sine bob tulen — naik-turun lembut (easeInOutSine kedua-dua hala; x-wobble
   dibuang: pd elemen kecil ia nampak gugup) */
/* TF per-stop DIBUANG 2026-08-03: dlm CSS, animation-timing-function di dlm keyframe
   MENGATASI TF peringkat animasi — jadi pilihan "ease" pereka langsung diabaikan.
   Rentak kini datang dari Scene::LOOP_EASE (lalai `inout` = easeInOutSine, iaitu
   TEPAT nilai yang dibakar dulu → rupa lalai tidak berubah). */
@keyframes kd-float {
    0%  {translate:0 0}
    50% {translate:0 calc(-3% * var(--la,1))}
    100%{translate:0 0}
}
/* Drift: ORBIT elips 12-stop, linear antara stop (laju malar = hanyutan habuk sebenar);
   bermula & berakhir di REHAT (0,0) — pusat orbit dianjak supaya laluan melalui asal */
/* ORBIT: 12 stop, dan setiap stop DIPIN `linear` (2026-08-03). Sebabnya TF animasi
   dikenakan pd SETIAP segmen — bukan sekali atas kitaran. Tanpa pin ini, memilih
   easing bukan-linear menghasilkan 12 kali pecut-nyahpecut satu pusingan = persis
   "stutter" yang dilapor diden. Orbit memang direka laju-malar (hanyutan habuk). */
@keyframes kd-drift {
    0%     {translate:0 0;                                                   animation-timing-function:linear}
    8.33%  {translate:calc(-.2% * var(--la,1))   calc(.53% * var(--la,1));animation-timing-function:linear}
    16.67% {translate:calc(-.75% * var(--la,1))  calc(.91% * var(--la,1));animation-timing-function:linear}
    25%    {translate:calc(-1.5% * var(--la,1))  calc(1.05% * var(--la,1));animation-timing-function:linear}
    33.33% {translate:calc(-2.25% * var(--la,1)) calc(.91% * var(--la,1));animation-timing-function:linear}
    41.67% {translate:calc(-2.8% * var(--la,1))  calc(.53% * var(--la,1));animation-timing-function:linear}
    50%    {translate:calc(-3% * var(--la,1))    0;animation-timing-function:linear}
    58.33% {translate:calc(-2.8% * var(--la,1))  calc(-.53% * var(--la,1));animation-timing-function:linear}
    66.67% {translate:calc(-2.25% * var(--la,1)) calc(-.91% * var(--la,1));animation-timing-function:linear}
    75%    {translate:calc(-1.5% * var(--la,1))  calc(-1.05% * var(--la,1));animation-timing-function:linear}
    83.33% {translate:calc(-.75% * var(--la,1))  calc(-.91% * var(--la,1));animation-timing-function:linear}
    91.67% {translate:calc(-.2% * var(--la,1))   calc(-.53% * var(--la,1));animation-timing-function:linear}
    100%   {translate:0 0}
}
/* Drift (Left & right only): ayunan mendatar harmonik — easeInOutSine dua-dua hala,
   perlahan di hujung laju di tengah (bandul); tiada gerak menegak. (diden 2026-07-21) */
/* GERAK HARMONIK BETUL (diden 2026-08-03: "ada perhentian pula ditengah").
   Laluan ialah pusat->kiri->pusat->kanan->pusat, jadi PUSAT ialah titik LALU,
   bukan titik pusing. Bandul paling LAJU di tengah dan berhenti hanya di hujung.
   Satu easing seragam pd setiap segmen memberi halaju 0 di KEEMPAT-EMPAT titik =
   berhenti di tengah. Jadi easing dibakar BERSELANG dan sengaja:
     keluar (pusat->hujung) = easeOutSine  — mula laju, henti di hujung
     balik  (hujung->pusat) = easeInSine   — mula diam, laju di pusat
   Ini BUKAN citarasa: kedua-duanya betul-betul separuh lengkung sinus, jadi
   hasilnya x = -A*sin(2*pi*t) tepat. Halaju bersambung di setiap simpang
   (termasuk sambungan kitaran 100%->0%), jadi tiada sentakan langsung. */
@keyframes kd-drift-lr {
    0%  {translate:0 0;                        animation-timing-function:cubic-bezier(.61,1,.88,1)}
    25% {translate:calc(-3% * var(--la,1)) 0;  animation-timing-function:cubic-bezier(.12,0,.39,0)}
    50% {translate:0 0;                        animation-timing-function:cubic-bezier(.61,1,.88,1)}
    75% {translate:calc(3% * var(--la,1)) 0;   animation-timing-function:cubic-bezier(.12,0,.39,0)}
    100%{translate:0 0}
}
/* BUAIAN (diden 2026-08-03) — bandul tergantung pd tali, BUKAN sekadar geser
   mendatar. x = -A·sin(2πt) · y = -C·sin²(2πt): paling RENDAH & paling LAJU di
   tengah, paling TINGGI & seketika diam di dua hujung. y berfrekuensi DUA kali x
   (naik sekali setiap hujung). Stop disampel-sinus + linear antaranya, jadi rentak
   betul tanpa easing luaran — sama kaedah dgn orbit. */
@keyframes kd-drift-cradle {
    0%      {translate:0 0;animation-timing-function:linear}
    8.3333% {translate:calc(-1.5% * var(--la,1)) calc(-0.225% * var(--la,1));animation-timing-function:linear}
    16.6667% {translate:calc(-2.598% * var(--la,1)) calc(-0.675% * var(--la,1));animation-timing-function:linear}
    25%     {translate:calc(-3% * var(--la,1)) calc(-0.9% * var(--la,1));animation-timing-function:linear}
    33.3333% {translate:calc(-2.598% * var(--la,1)) calc(-0.675% * var(--la,1));animation-timing-function:linear}
    41.6667% {translate:calc(-1.5% * var(--la,1)) calc(-0.225% * var(--la,1));animation-timing-function:linear}
    50%     {translate:0 0;animation-timing-function:linear}
    58.3333% {translate:calc(1.5% * var(--la,1)) calc(-0.225% * var(--la,1));animation-timing-function:linear}
    66.6667% {translate:calc(2.598% * var(--la,1)) calc(-0.675% * var(--la,1));animation-timing-function:linear}
    75%     {translate:calc(3% * var(--la,1)) calc(-0.9% * var(--la,1));animation-timing-function:linear}
    83.3333% {translate:calc(2.598% * var(--la,1)) calc(-0.675% * var(--la,1));animation-timing-function:linear}
    91.6667% {translate:calc(1.5% * var(--la,1)) calc(-0.225% * var(--la,1));animation-timing-function:linear}
    100%    {translate:0 0}
}

/* ANGKA-8 (∞) — Lissajous 1:2 fasa SINUS: y menyeberang sifar dua kali setiap
   kitaran x, jadi laluannya BERSILANG di tengah. Keluarga sama dgn buaian; bezanya
   cuma fasa y (sin vs sin²) — itu yang menentukan silang lawan lengkung U. */
@keyframes kd-drift-fig8 {
    0%      {translate:0 0;animation-timing-function:linear}
    6.25%   {translate:calc(0.995% * var(--la,1)) calc(0.778% * var(--la,1));animation-timing-function:linear}
    12.5%   {translate:calc(1.838% * var(--la,1)) calc(1.1% * var(--la,1));animation-timing-function:linear}
    18.75%  {translate:calc(2.402% * var(--la,1)) calc(0.778% * var(--la,1));animation-timing-function:linear}
    25%     {translate:calc(2.6% * var(--la,1)) 0;animation-timing-function:linear}
    31.25%  {translate:calc(2.402% * var(--la,1)) calc(-0.778% * var(--la,1));animation-timing-function:linear}
    37.5%   {translate:calc(1.838% * var(--la,1)) calc(-1.1% * var(--la,1));animation-timing-function:linear}
    43.75%  {translate:calc(0.995% * var(--la,1)) calc(-0.778% * var(--la,1));animation-timing-function:linear}
    50%     {translate:0 0;animation-timing-function:linear}
    56.25%  {translate:calc(-0.995% * var(--la,1)) calc(0.778% * var(--la,1));animation-timing-function:linear}
    62.5%   {translate:calc(-1.838% * var(--la,1)) calc(1.1% * var(--la,1));animation-timing-function:linear}
    68.75%  {translate:calc(-2.402% * var(--la,1)) calc(0.778% * var(--la,1));animation-timing-function:linear}
    75%     {translate:calc(-2.6% * var(--la,1)) 0;animation-timing-function:linear}
    81.25%  {translate:calc(-2.402% * var(--la,1)) calc(-0.778% * var(--la,1));animation-timing-function:linear}
    87.5%   {translate:calc(-1.838% * var(--la,1)) calc(-1.1% * var(--la,1));animation-timing-function:linear}
    93.75%  {translate:calc(-0.995% * var(--la,1)) calc(-0.778% * var(--la,1));animation-timing-function:linear}
    100%    {translate:0 0}
}

/* WANDER — hanyutan "ada angin dlm bilik". Dua gelombang berlainan frekuensi
   dijumlahkan, jadi bentuknya senget & mata tak sempat hafal coraknya. Frekuensi
   sengaja INTEGER supaya laluan tertutup rapat di sambungan kitaran, dan seluruh
   laluan DIANJAK supaya ia bermula/berakhir di REHAT (0,0) — kalau tidak elemen
   melompat masuk bila loop bermula (corak sama dgn orbit).
   Guna kekuatan RENDAH + tempoh PANJANG (20-30s) — pd 4s ia nampak gelisah. */
@keyframes kd-drift-wander {
    0%      {translate:0 0;animation-timing-function:linear}
    6.25%   {translate:calc(0.808% * var(--la,1)) calc(0.486% * var(--la,1));animation-timing-function:linear}
    12.5%   {translate:calc(0.689% * var(--la,1)) calc(0.462% * var(--la,1));animation-timing-function:linear}
    18.75%  {translate:calc(0.631% * var(--la,1)) calc(-0.009% * var(--la,1));animation-timing-function:linear}
    25%     {translate:calc(1.27% * var(--la,1)) calc(-0.62% * var(--la,1));animation-timing-function:linear}
    31.25%  {translate:calc(2.015% * var(--la,1)) calc(-1.001% * var(--la,1));animation-timing-function:linear}
    37.5%   {translate:calc(1.747% * var(--la,1)) calc(-0.941% * var(--la,1));animation-timing-function:linear}
    43.75%  {translate:calc(0.235% * var(--la,1)) calc(-0.507% * var(--la,1));animation-timing-function:linear}
    50%     {translate:calc(-1.497% * var(--la,1)) 0;animation-timing-function:linear}
    56.25%  {translate:calc(-2.306% * var(--la,1)) calc(0.225% * var(--la,1));animation-timing-function:linear}
    62.5%   {translate:calc(-2.186% * var(--la,1)) calc(-0.019% * var(--la,1));animation-timing-function:linear}
    68.75%  {translate:calc(-2.128% * var(--la,1)) calc(-0.637% * var(--la,1));animation-timing-function:linear}
    75%     {translate:calc(-2.768% * var(--la,1)) calc(-1.3% * var(--la,1));animation-timing-function:linear}
    81.25%  {translate:calc(-3.512% * var(--la,1)) calc(-1.629% * var(--la,1));animation-timing-function:linear}
    87.5%   {translate:calc(-3.244% * var(--la,1)) calc(-1.422% * var(--la,1));animation-timing-function:linear}
    93.75%  {translate:calc(-1.733% * var(--la,1)) calc(-0.767% * var(--la,1));animation-timing-function:linear}
    100%    {translate:0 0}
}

/* Breathe: tarik nafas → TAHAN sekejap → hembus (bukan zoom robotik) */
@keyframes kd-breathe {
    0%  {scale:1}
    45% {scale:calc(1 + .045 * var(--la,1))}
    58% {scale:calc(1 + .045 * var(--la,1))}   /* tahan — nilai sama, easing tak relevan */
    100%{scale:1}
}
/* Shimmer: kelipan lembut tak sekata (bukan pudar mekanikal 1→.55) */
@keyframes kd-shimmer {
    0%  {opacity:1}
    35% {opacity:calc(1 - .28 * var(--la,1))}
    52% {opacity:calc(1 - .1 * var(--la,1))}
    72% {opacity:calc(1 - .4 * var(--la,1))}
    100%{opacity:1}
}

/* Hormat pilihan pengguna — SEKALI, di satu tempat. Rekaan tak perlu ingat.  */
@media (prefers-reduced-motion: reduce){
    .kd-anim{animation:none !important; opacity:1 !important; translate:none !important; scale:none !important; rotate:none !important}
}

/* Nama pasangan berstruktur — A / & / B (auto-split pada ' & '). & lebih kecil, baris sendiri. */
.kd-couple .kd-cn{display:block}
/* PEMISAH NAMA — saiz (--amp-s), jarak (--amp-g) & jajaran (--amp-a) boleh dilaras
   (diden 2026-08-03). `em` diskalakan supaya pemisah membesar SECARA BERKADAR dgn
   saiz nama; margin diskalakan berasingan supaya membesarkannya tidak menyebabkan
   ia BERTINDIH dgn nama — jarak tumbuh sama. Jajaran guna margin auto, bukan
   text-align, kerana ia elemen blok. */
/* PEMISAH NAMA — SAIZ vs RUANG (diden 2026-08-03).
   `font-size` TIDAK diskala: `em` di dlm elemen merujuk font-size ELEMEN ITU
   SENDIRI, jadi menskala font turut menskala tinggi kotaknya — itulah sebab
   membesarkan & menolak nama. Saiz kini melalui `transform:scale()`, yang
   mengubah RUPA tanpa menyentuh susun atur langsung. Ruang dikawal margin (Gap).
   Jajaran melalui --amp-mi (nilai margin-inline penuh dari node), bukan pemilih
   atribut — pemilih substring pd `style` rapuh dan senyap bila format berubah. */
.kd-couple .kd-amp{display:block;font-size:.52em;line-height:1;
    transform:scale(var(--amp-s,1));transform-origin:var(--amp-o,center);
    opacity:var(--amp-op,1);color:var(--kd-amp-c,inherit);
    margin-block:calc(.9em * var(--amp-g,.2) - .14em);
    width:fit-content;margin-inline:var(--amp-mi,auto)}
.kd-couple .kd-amp-g{width:.8em;height:.8em;transform:rotate(45deg) scale(var(--amp-s,1));
    transform-origin:var(--amp-o,center);opacity:var(--amp-op,1);
    margin-block:calc(.8em * var(--amp-g,.2) - .12em);margin-inline:var(--amp-mi,auto);
    border:.055em solid currentColor;opacity:.75}
.kd-couple .kd-amp-img{display:block;width:fit-content;line-height:0;
    transform:scale(var(--amp-s,1));transform-origin:var(--amp-o,center);opacity:var(--amp-op,1);
    margin-block:calc(.85em * var(--amp-g,.2) - .12em);margin-inline:var(--amp-mi,auto)}
.kd-couple .kd-amp-img>img{width:var(--amp-w,.9em);max-width:none;height:auto;display:block}
/* Jajaran melalui margin-inline: kiri = `0 auto 0 0`, kanan = `0 0 0 auto`.
   --amp-a diberi oleh node (flex-start / flex-end); tiada = kekal tengah. */
.kd-couple{--amp-mi:auto}
.kd-couple:has(.kd-amp,.kd-amp-g,.kd-amp-img){--amp-mi:auto}
.kd-couple .kd-amp-img img{width:100%;height:auto;display:block}
/* hari . tarikh . masa -- satu node, tiga baris. Saiz relatif kpd slot supaya SATU
   slider saiz user melaraskan ketiga-tiganya serentak (itu maksud "group"). */
.kd-dt3{display:flex;flex-direction:var(--dt3-dir,column);align-items:center;
    justify-content:center;gap:var(--dt3-gap,0)}
/* `:not(.st-lockbadge):not(.kd-dt-orn)` — lencana kunci studio ialah <span> yang disuntik ke dlm
   node. Tanpa pengecualian ini ia dilayan sbg LAJUR: mewarisi padding jalur,
   mendapat garis pembahagi sendiri, dan menganjak susun atur (dilapor diden
   2026-08-03). Ia hanya wujud dlm editor, jadi kad tetamu tak pernah terjejas —
   itulah sebab ia terlepas pandang. */
.kd-dt3>span:not(.st-lockbadge):not(.kd-dt-orn){display:block}
.kd-dt3 .kd-dt0{font-size:var(--kd-dt-day,.78em);letter-spacing:var(--kd-dt-day-ls,.16em)}
.kd-dt3 .kd-dt1{font-size:var(--kd-dt-date,1em)}
.kd-dt3 .kd-dt2{font-size:var(--kd-dt-time,.82em);letter-spacing:var(--kd-dt-time-ls,.1em)}
/* STRIP (spec draf F2 trio2, 1:1): 3 lajur sama lebar + pembahagi menegak; lajur tengah
   sedikit lebih lebar dgn NOMBOR HARI besar bertindan atas bulan-tahun. Warna pembahagi
   & font nombor milik REKAAN (--dt3-line / --dt3-num-f) — enjin tiada hardcode. */
.kd-dt3-strip{gap:0;border-top:1px solid var(--dt3-line,color-mix(in srgb,currentColor 32%,transparent));
    border-bottom:1px solid var(--dt3-line,color-mix(in srgb,currentColor 32%,transparent))}
/* Lajur REGANG sama tinggi (atasi align-items:center asas) + kandungan ditengahkan
   DLM lajur — supaya border-left setiap lajur penuh dan BERCANTUM dgn garis atas/bawah.
   Tanpa ini lajur pendek (masa) memberi pembahagi pendek terapung. */
/* Jalur = MENDATAR mengikut takrif — kelas sendiri yang menetapkan arah. Dulu arah
   row datang dari css node rangka F2 (--dt3-dir:row); F2 dibuang 2026-08-01, jadi
   toggle Strip dari inspector cuma menambah kelas ini → tanpa baris ini lajur
   tertindan menegak (nampak rosak). */
.kd-dt3-strip{flex-direction:row;align-items:stretch}
/* text-align ikut NODE (--ta) — dulu dipaku `center`, jadi kawalan Align dlm
   panel langsung tiada kesan bila Group dihidupkan (diden 2026-08-03). */
.kd-dt3-strip>span:not(.st-lockbadge):not(.kd-dt-orn){flex:1;padding:2.4cqw .5cqw;text-align:var(--ta,center);
    display:flex;flex-direction:column;justify-content:center}
/* Pembahagi lajur: dulu `border-left` = sentiasa setinggi lajur. Kini garis
   sendiri yang ditengahkan, jadi TINGGINYA boleh dilaras (--dt3-div, % tinggi
   lajur; 0 = pembahagi dimatikan). */
/* `:not(.kd-dt-orn)` WAJIB: ornamen ialah span selepas span, jadi tanpa pengecualian
   ini `position:relative` di bawah mengatasi `position:absolute`-nya — ia jatuh ke
   dlm aliran dan merampas satu LAJUR penuh (dilapor diden: jalur runtuh bila line
   graphic digunakan). LAJUR sebenar = span yang bukan lencana kunci & bukan ornamen. */
.kd-dt3-strip>span:not(.st-lockbadge):not(.kd-dt-orn)+span:not(.st-lockbadge):not(.kd-dt-orn){position:relative}
.kd-dt3-strip>span:not(.st-lockbadge):not(.kd-dt-orn)+span:not(.st-lockbadge):not(.kd-dt-orn)::before{content:"";position:absolute;left:0;top:50%;
    transform:translateY(-50%);width:1px;height:var(--dt3-div,100%);
    background:var(--dt3-line,color-mix(in srgb,currentColor 32%,transparent))}
.kd-dt3-strip .kd-dt0,.kd-dt3-strip .kd-dt2{font-size:.86em;letter-spacing:.16em;text-transform:uppercase}
/* WARNA DIBUANG 2026-08-03 (diden: "pilih red, hanya beberapa bertukar"). Lajur
   tengah dulu dipaku ke `--kd-primary` tema, jadi ia MENGABAIKAN pemilih warna node
   — hanya lajur hari & masa bertukar. Kini ia mewarisi warna node spt dua lajur lain;
   rekaan yang memang mahu warna tema tinggal set warna node ke `primary`. */
/* Kekhususan mesti >= pemilih lajur ber-:not() di atas, kalau tidak lajur tengah
   kehilangan lebar tambahannya (1.35x) dan ketiga-tiga lajur jadi sama. */
.kd-dt3-strip>.kd-dt1:not(.st-lockbadge):not(.kd-dt-orn){flex:1.35;font-size:.86em;letter-spacing:.06em;text-transform:uppercase}
.kd-dt3-strip .kd-dt1 b{display:block;font-family:var(--dt3-num-f,inherit);
    font-size:var(--dt3-num,2.6em);line-height:1;font-weight:inherit;letter-spacing:-.01em}
/* Garis jalur diganti ORNAMEN library (diden 2026-08-01). Satu var (--dt3-line
   telus) mematikan KETIGA-TIGA garis; ornamen diletak MUTLAK atas/bawah supaya ia
   tidak menjadi lajur flex. Saiz via --dt3-orn-w / --dt3-orn-h (css node). */
/* TIGHT (diden 2026-08-01): lajur peluk kandungan + jarak boleh laras — ganti
   flex:1 yang meregang ikut lebar node. Pembahagi kekal border-left di tepi lajur,
   duduk di tengah jarak kerana padding-inline dibahagi dua ke kiri-kanan.
   MESTI selepas peraturan .kd-dt3-strip: seri kespesifikan diputuskan turutan fail. */
/* Lajur LUAR berkongsi ruang lebihan sama rata (flex:1 1 0), lajur TENGAH ikut
   kandungan -- inilah yg meletakkan lajur tengah tepat di paksi kanvas. Dulu
   ketiga-tiganya `0 1 auto` lalu dipusatkan sbg satu kumpulan: bila teks kiri
   ("TUESDAY") & kanan ("11:00 PAGI") tak sama lebar, titik tengah kumpulan BUKAN
   titik tengah lajur tengah -- nombor tarikh berganjak (diden 2026-08-03; spread
   tak terjejas sbb lajur luarnya memang sama lebar).
   Rupa "peluk" dikekalkan dgn menolak teks lajur luar ke DALAM, jadi jarak visual
   sama spt sebelum ini; pembahagi ::before kekal di tepi dalam lajur. */
.kd-dt3-tight{justify-content:center}
.kd-dt3-tight>span:not(.st-lockbadge):not(.kd-dt-orn){flex:1 1 0;padding-inline:calc(var(--dt3-cgap,3cqw)/2 + .5cqw)}
.kd-dt3-tight>span.kd-dt0:not(.st-lockbadge):not(.kd-dt-orn){text-align:right}
.kd-dt3-tight>span.kd-dt2:not(.st-lockbadge):not(.kd-dt-orn){text-align:left}
.kd-dt3-tight>.kd-dt1:not(.st-lockbadge):not(.kd-dt-orn){flex:0 1 auto}

/* Border dimatikan SECARA EKSPLISIT, bukan via --dt3-line:transparent: rekaan set
   --dt3-line INLINE pd node, dan var inline menang atas kelas — garis akan kekal.
   Ornamen = SATU overlay berpusat atas jalur (diden 2026-08-01: bukan pendua atas/
   bawah); resize via --dt3-orn-w / --dt3-orn-h dlm css node. pointer-events none —
   overlay tidak boleh melindungi pemilihan node. */
.kd-dt3-gfx{border-top:0;border-bottom:0;position:relative}
/* Ornamen tidak lagi memadamkan pembahagi (diden 2026-08-03: "divider hilang bila
   wujud line graphic"). Kini kawalan Divider yang menentukan — set 0 utk mematikannya. */
.kd-dt3-gfx>span+span{border-left:0}
/* --dt3-orn-y: anjakan MENEGAK (% tinggi jalur) — pereka boleh naik/turunkan
   ornamen tanpa menyentuh Custom CSS. --dt3-orn-w boleh `auto` = saiz asal gfx. */
.kd-dt3-gfx .kd-dt-orn{position:absolute;left:50%;top:50%;
    transform:translate(-50%,calc(-50% + var(--dt3-orn-y,0%)));
    width:var(--dt3-orn-w,100%);height:auto;flex:none;padding:0;line-height:0;pointer-events:none}
/* NISBAH ASAL, bukan diregang (diden 2026-08-03: "size dia resize bukan yang sebenar").
   Peraturan SAMA spt .kd-d (deco) dan .kd-amp-img img (pemisah nama): lebar yang
   memandu, tinggi ikut sendiri. `object-fit:fill` lama meregang imej ikut kotak —
   ia satu-satunya tempat dlm enjin yang memesongkan nisbah. Imej SVG ber-viewBox
   tiada width/height intrinsik pun betul di sini: pelayar mengira tinggi dari
   nisbah viewBox. Saiz dilaras melalui SATU kawalan (Size %). */
.kd-dt3-gfx .kd-dt-orn img{width:100%;height:auto;display:block}

/* ── BINGKAI PUSTAKA (diden 2026-08-02) ───────────────────────────────────
   SVG di-INLINE supaya isinya boleh disentuh: warna 3 ton ikut tema (--fr1/2/3),
   ketebalan garis (--frlw, didarab pd setiap stroke oleh FrameLibrary) dan Fill
   shape (siluet dilukis DI BAWAH garis). Penuh-kanvas spt kd-frame-line. */
.kd-fr{position:absolute;inset:0;pointer-events:none}
.kd-fr>svg{width:100%;height:100%;display:block;overflow:visible}
/* Siluet isian: geometri sahaja dari pustaka -> gaya ditetapkan di sini supaya
   satu peraturan mengawal semua bingkai. */
.kd-fr-f>*{fill:var(--frf,#c9a24a);fill-opacity:var(--frfo,.13);stroke:none}
