/* London — undangan pernikahan bergaya lukisan cat air: sampul foto penuh layar, lalu tepi Thames saat gerimis dari
   dekat (kotak telepon merah, lampu jalan); pandangan mundur, kabut dan gerimis reda, jembatan dan menara jam muncul,
   lampu menyala, bus tingkat dan perahu melintas, jarum jam berputar ke jam akad, lalu judul sebagai prangko yang
   dicap. Adegannya lapisan gambar (assets/img/*.webp) + hiasan SVG yang digerakkan CSS, tanpa pustaka. */
@font-face { font-family: "Cinzel"; src: url("fonts/cinzel.woff2") format("woff2"); font-weight: 400 700; font-display: swap; }
@font-face { font-family: "Cormorant Garamond"; src: url("fonts/cormorant-garamond.woff2") format("woff2"); font-weight: 300 700; font-display: swap; }
@font-face { font-family: "Cormorant Garamond"; src: url("fonts/cormorant-garamond-italic.woff2") format("woff2"); font-weight: 400; font-style: italic; font-display: swap; }
@font-face { font-family: "Pinyon Script"; src: url("fonts/pinyon-script.woff2") format("woff2"); font-weight: 400; font-display: swap; }

:root {
  --bg: #f6efe9; --bg2: #fbf7f3; --deep: #34446a; --deep2: #26334f; --ink: #2b3350; --soft: #6a6f85; --gold: #b99655; --gold-hi: #e3d0a4;
  --aksen: #9c3b3f; --r1: #f6cfcb; --r2: #e39a98; --r3: #b9484b; --sky1: #f6e7dc; --card: #fffdf9; --line: #e6d9cf;
  --display: "Cinzel", "Cormorant Garamond", Georgia, serif;
  --serif: "Cormorant Garamond", Georgia, serif;
  --script: "Pinyon Script", "Cormorant Garamond", cursive;
}
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; background: var(--bg); }
body { margin: 0; background: var(--bg); color: var(--ink); font: 500 19px/1.55 var(--serif); -webkit-font-smoothing: antialiased; }
img { max-width: 100%; display: block; }
h1, h2, h3, p, ol { margin: 0; }
a { color: var(--deep2); }
:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
.page { position: relative; z-index: 1; max-width: 480px; margin: 0 auto; min-height: 100vh; overflow: hidden; }
@media (min-width: 560px) { .page { box-shadow: 0 30px 80px rgba(30, 36, 60, .28); } }

/* Adegan: lapisan gambar selebar kolom halaman, di belakang isi; hanya bagian pembuka (.hero) yang tembus pandang.
   .stage berbanding 1116:2000 (ukuran lukisan) dan selalu menutup layar; semua lapisan digambar pada bingkai yang
   sama, jadi di skala 1 bertumpuk menjadi lukisan utuh: langit → menara jam → sungai → bus + jembatan → perahu →
   kotak telepon, lampu, pagar. Itu keadaan dasar. Sebelum dibuka (.js:not(.is-open)) pandangan dekat ke kotak telepon
   dan lampu, menara dan jembatan tertutup kabut, langit dingin, dan gerimis turun. */
.scene { position: fixed; top: 0; left: 50%; width: min(100%, 480px); height: 100%; transform: translateX(-50%); z-index: 0; pointer-events: none; overflow: hidden; contain: strict; background: var(--sky1); display: none; }
.js .scene { display: block; }
.scene-off .scene { visibility: hidden; }
.stage { position: absolute; left: 50%; top: 50%; height: max(100%, calc(min(100vw, 480px) * 1.7922)); aspect-ratio: 1116 / 2000; translate: -50% -50%; }
.ly { position: absolute; inset: 0; will-change: transform; transform-origin: 50% 50%; }
.ly > img, .fx { position: absolute; inset: 0; width: 100%; height: 100%; max-width: none; }
.ly-front { transform-origin: 22% 82%; } .ly-roses { transform-origin: 100% 100%; transform: translate(70%, 60%) scale(.8); }
.js .ly { transition: transform 5.2s cubic-bezier(.6, 0, .2, 1) 1.4s, opacity 2.6s ease 3s; }
.js:not(.is-open) .ly-sky { transform: scale(1.12); }
.js:not(.is-open) .ly-tower { transform: translateY(14%) scale(1.12); opacity: 0; }
.js:not(.is-open) .ly-river { transform: translateY(16%) scale(1.3); }
.js:not(.is-open) .ly-bridge { transform: translateY(13%) scale(1.25); opacity: .12; }
.js:not(.is-open) .ly-boat { transform: translateY(16%) scale(1.3); opacity: 0; }
.js:not(.is-open) .ly-front { transform: scale(2.15); }
.js:not(.is-open) .ly-roses { transform: translate(22%, 26%) scale(.8); }
.js.no-anim .ly, .js.no-anim .jj, .js.no-anim .jm, .js.no-anim .lampu, .js.no-anim .dingin, .js.no-anim .kabut, .js.no-anim .hujan { transition: none; }
/* Jarum jam: berhenti di jam akad (--jam/--mnt dipasang london.js); saat dibuka berputar beberapa kali dulu. */
.jarum { fill: none; stroke: #2a2630; stroke-width: 2.2; stroke-linecap: round; } .jarum.tebal { stroke-width: 3.4; } .poros { fill: var(--gold); }
.jj, .jm { transform-origin: 0 0; } .jj { transform: rotate(var(--jam, 305deg)); } .jm { transform: rotate(var(--mnt, 60deg)); }
.js .jj { transition: transform 3.6s cubic-bezier(.3, .8, .3, 1) 5.8s; } .js .jm { transition: transform 3.6s cubic-bezier(.3, .8, .3, 1) 5.8s; }
.js:not(.is-open) .jj { transform: rotate(calc(var(--jam, 305deg) - 180deg)); } .js:not(.is-open) .jm { transform: rotate(calc(var(--mnt, 60deg) - 1440deg)); }
/* Lampu: pendar di kepala tiap lampu jembatan menyala berurutan; lampu depan sudah menyala dan berdenyut. */
.lampu { mix-blend-mode: screen; transition: opacity .5s ease 5s; } .lampu.l2 { transition-delay: 5.25s; } .lampu.l3 { transition-delay: 5.5s; } .lampu.l4 { transition-delay: 5.75s; } .lampu.l5 { transition-delay: 6s; } .lampu.l6 { transition-delay: 6.25s; } .lampu.l7 { transition-delay: 6.5s; }
.js:not(.is-open) .lampu:not(.besar) { opacity: 0; }
.lajur { position: absolute; left: 0; width: 100%; height: 0; transform-origin: 0 0; }
.lajur-bus { top: 47.9%; rotate: 3.1deg; } .bus { position: absolute; bottom: 0; left: 104%; width: 9.8%; height: auto; max-width: none; }
.lajur-perahu { top: 66%; } .perahu { position: absolute; bottom: 0; left: -22%; width: 16%; height: auto; max-width: none; transform-origin: 50% 90%; }
.kilau { position: absolute; inset: 0; } .kilau i { position: absolute; border-radius: 2px; background: #fff; opacity: 0; }
.bw { fill: none; stroke: var(--ink); stroke-width: 3.2; stroke-linecap: round; stroke-linejoin: round; opacity: .55; transform-box: fill-box; transform-origin: 50% 100%; }
.birds { translate: -260px 420px; }
/* Cuaca: lapisan biru-kelabu (langit dingin), dua gumpal kabut, dan garis-garis gerimis; semuanya memudar saat dibuka. */
.dingin { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(92, 108, 140, .62), rgba(120, 130, 150, .42)); mix-blend-mode: multiply; opacity: 0; transition: opacity 4.2s ease 1.8s; }
.kabut { position: absolute; left: -30%; width: 160%; height: 34%; border-radius: 50%; background: radial-gradient(closest-side, rgba(255, 255, 255, .92), rgba(255, 255, 255, 0)); filter: blur(10px); opacity: .18; transition: opacity 4.6s ease 2s; }
.kabut.k1 { top: 30%; } .kabut.k2 { top: 46%; left: -50%; }
.hujan { position: absolute; inset: -20% -20%; background-image: repeating-linear-gradient(100deg, rgba(255, 255, 255, 0) 0 7px, rgba(255, 255, 255, .5) 7px 8px, rgba(255, 255, 255, 0) 8px 23px), repeating-linear-gradient(100deg, rgba(255, 255, 255, 0) 0 31px, rgba(255, 255, 255, .34) 31px 32px, rgba(255, 255, 255, 0) 32px 57px); background-size: 100% 60px, 100% 96px; -webkit-mask-image: repeating-linear-gradient(190deg, #000 0 26px, transparent 26px 64px); mask-image: repeating-linear-gradient(190deg, #000 0 26px, transparent 26px 64px); opacity: 0; transition: opacity 2.4s ease 2.4s; }
.js:not(.is-open) .dingin { opacity: 1; } .js:not(.is-open) .kabut { opacity: 1; } .js:not(.is-open) .hujan { opacity: .85; }
.veil { position: absolute; inset: 0; background: #fff3e2; opacity: 0; }
.terang { position: absolute; inset: 0; background: radial-gradient(circle at 78% 26%, #fff 0, #fff6ea 55%, var(--bg) 100%); opacity: 0; }
.strip { position: relative; width: calc(100% + 56px); margin: -64px -28px 0; -webkit-mask-image: linear-gradient(transparent, #000 12%, #000 78%, transparent); mask-image: linear-gradient(transparent, #000 12%, #000 78%, transparent); }
.strip img { display: block; width: 100%; height: auto; }
.kilau i:nth-child(1) { left: 53%; top: 88.9%; width: 15px; height: 2px; animation-duration: 2.5s; animation-delay: -2.8s; }
.kilau i:nth-child(2) { left: 23%; top: 68.9%; width: 12px; height: 2px; animation-duration: 4.6s; animation-delay: -0.8s; }
.kilau i:nth-child(3) { left: 9%; top: 74.9%; width: 27px; height: 2px; animation-duration: 3.3s; animation-delay: -2s; }
.kilau i:nth-child(4) { left: 57%; top: 64.5%; width: 15px; height: 2px; animation-duration: 2.8s; animation-delay: -0.1s; }
.kilau i:nth-child(5) { left: 72%; top: 73.4%; width: 18px; height: 2px; animation-duration: 4.4s; animation-delay: -1.5s; }
.kilau i:nth-child(6) { left: 90%; top: 69.2%; width: 12px; height: 2px; animation-duration: 4.6s; animation-delay: -0.3s; }
.kilau i:nth-child(7) { left: 54%; top: 65%; width: 24px; height: 2px; animation-duration: 2.3s; animation-delay: -0.9s; }
.kilau i:nth-child(8) { left: 69%; top: 87.3%; width: 12px; height: 2px; animation-duration: 3.4s; animation-delay: -0.8s; }
.kilau i:nth-child(9) { left: 83%; top: 63.8%; width: 15px; height: 2px; animation-duration: 4.5s; animation-delay: -2s; }
.kilau i:nth-child(10) { left: 24%; top: 88.5%; width: 15px; height: 2px; animation-duration: 3.6s; animation-delay: -2.9s; }
.kilau i:nth-child(11) { left: 42%; top: 77.6%; width: 21px; height: 2px; animation-duration: 4.3s; animation-delay: -1.7s; }
.kilau i:nth-child(12) { left: 82%; top: 64.7%; width: 15px; height: 2px; animation-duration: 3.9s; animation-delay: -2.8s; }

.caps { font: 500 13px/1.4 var(--display); letter-spacing: .34em; text-transform: uppercase; }
.script { font: 400 50px/1.05 var(--script); color: var(--deep2); }
.lead { font-size: 18px; line-height: 1.6; color: var(--soft); max-width: 22em; }
.btn { display: inline-flex; align-items: center; justify-content: center; min-height: 46px; padding: 0 26px; border: 1px solid var(--deep2); border-radius: 12px; background: var(--deep2); color: #fff; text-decoration: none; cursor: pointer; font: 600 13px/1 var(--display); letter-spacing: .22em; text-transform: uppercase; }
.btn-line { background: transparent; color: inherit; border-color: currentColor; }
.btn.copied { background: var(--gold); border-color: var(--gold); color: #fff; }

/* Rangkaian bunga lukisan: di bawah foto mempelai, di sampul tanpa foto, dan buket di penutup. */
.spray { position: relative; width: 220px; margin: -58px auto 0; pointer-events: none; }
.cover-buket { position: absolute; left: 50%; bottom: 20%; width: 56%; max-width: none; translate: -50% 0; opacity: .9; pointer-events: none; }
.buket { position: relative; width: 230px; margin: -30px auto 0; pointer-events: none; filter: drop-shadow(0 10px 16px rgba(30, 36, 60, .18)); }

/* ---------- Sampul: foto penuh layar dengan gradasi gelap, nama di atas, tamu dan tombol di bawah ---------- */
.cover { position: relative; min-height: 100vh; min-height: 100svh; padding: 54px 26px 44px; display: flex; flex-direction: column; justify-content: space-between; align-items: center; text-align: center; background: linear-gradient(180deg, var(--bg2), var(--bg) 55%, color-mix(in srgb, var(--deep) 45%, var(--bg))); color: var(--ink); overflow: hidden; }
.cover[hidden] { display: none; }
.cover-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cover.has-photo { color: #fff; }
.cover.has-photo::after { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(20, 10, 12, .55) 0%, rgba(20, 10, 12, .05) 34%, rgba(20, 10, 12, .1) 56%, rgba(20, 10, 12, .78) 100%); }
.cover.has-photo .cover-art { display: none; }
.cover-art { position: absolute; inset: 0; }
.cover-top, .cover-bottom { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.cover .names { font: 500 34px/1.15 var(--display); letter-spacing: .08em; text-transform: uppercase; overflow-wrap: anywhere; }
.names .amp { margin: 0 .25em; font: 400 40px/1 var(--script); text-transform: none; letter-spacing: 0; }
.cover:not(.has-photo) .cover-top { margin-top: 26vh; }
.to { font-size: 16px; line-height: 1.5; opacity: .9; }
.guest-name { font: 600 24px/1.2 var(--serif); overflow-wrap: anywhere; }
.cover .open { margin-top: 10px; min-width: 230px; min-height: 48px; border-color: rgba(255, 255, 255, .55); background: rgba(255, 255, 255, .22); color: inherit; backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
.cover:not(.has-photo) .open { border-color: var(--deep2); background: var(--deep2); color: #fff; }

/* Dengan JS: sampul menutup layar sampai tamu menekan "Buka undangan", lalu memudar dan taman terlihat. */
.js .cover { position: fixed; top: 0; bottom: 0; left: 50%; width: min(100%, 480px); transform: translateX(-50%); z-index: 40; overflow-y: auto; transition: opacity .9s ease; }
.js:not(.is-open) body { overflow: hidden; }
.js.is-open .cover { opacity: 0; pointer-events: none; }
.js.no-anim .cover { transition: none; }
html:not(.js) .cover .open { display: none; }

/* ---------- Pembuka: judul berupa prangko yang dicap (lihat bagian akhir berkas) ---------- */
.hero { position: relative; min-height: 100vh; min-height: 100svh; padding: 44px 20px; display: grid; place-items: center; text-align: center; background: linear-gradient(180deg, var(--sky1), var(--sky2)); }
.js .hero { background: none; }
.frame-art { position: absolute; inset: 0; overflow: hidden; }
.pl-name { font: 500 40px/1.15 var(--display); letter-spacing: .14em; text-transform: uppercase; overflow-wrap: anywhere; }
.pl-name.small { font-size: 22px; margin-top: 10px; }
.pl-and { font: 400 34px/1 var(--script); color: var(--deep2); }
.pl-date { margin-top: 10px; font: 500 15px/1.4 var(--display); letter-spacing: .2em; text-transform: uppercase; }
.mouse { display: block; margin-top: 18px; width: 22px; height: 36px; border: 1.5px solid var(--ink); border-radius: 12px; position: relative; opacity: .7; }
.mouse::after { content: ""; position: absolute; left: 50%; top: 7px; width: 3px; height: 7px; margin-left: -1.5px; border-radius: 2px; background: var(--ink); animation: gulir 1.6s ease-in-out infinite; }

/* ---------- Isi: bagian berlatar krem dan biru navy bergantian ---------- */
main > section:not(.hero) { position: relative; padding: 64px 28px; display: flex; flex-direction: column; align-items: center; gap: 20px; text-align: center; background: var(--bg); }
.verse { background: linear-gradient(180deg, var(--bg2), var(--bg)) !important; }
.quote { font: italic 500 21px/1.6 var(--serif); max-width: 20em; }
.source { font: 600 14px/1.4 var(--display); letter-spacing: .14em; }
.couple { display: flex; flex-direction: column; gap: 44px; width: 100%; margin-top: 8px; }
.person { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.portrait { width: 230px; height: 300px; padding: 7px; border: 1.5px solid var(--gold); border-radius: 10px; background: var(--card); display: flex; }
.portrait > * { flex: 1; width: 100%; height: 100%; border-radius: 5px; object-fit: cover; }
.portrait span { display: flex; align-items: center; justify-content: center; background: var(--bg2); font: 400 90px/1 var(--script); color: var(--deep2); }
.person h3 { font: 400 42px/1.05 var(--script); color: var(--deep2); overflow-wrap: anywhere; }
.parents { font-size: 17px; line-height: 1.45; color: var(--soft); max-width: 16em; }
.ig { font-size: 16px; font-weight: 700; color: var(--deep2); }

main > section.count, main > section.rsvp { background: linear-gradient(180deg, var(--deep), var(--deep2)); color: #fff; }
.count .script, .rsvp .script, .count .lead { color: #fff; }
.countdown { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; width: 100%; }
.countdown div { padding: 14px 0 12px; border: 1.5px solid rgba(255, 255, 255, .75); border-radius: 14px; display: flex; flex-direction: column; gap: 2px; }
.countdown b { font: 500 30px/1.1 var(--display); font-variant-numeric: tabular-nums; }
.countdown span { font-size: 15px; }
html:not(.js) .countdown { display: none; }

.programme { gap: 26px !important; background: linear-gradient(180deg, var(--bg), var(--bg2)) !important; }
.event { width: 100%; padding: 34px 22px 30px; border-radius: 110px 110px 22px 22px; background: var(--card); border: 1.5px solid var(--gold); outline: 1px solid var(--gold-hi); outline-offset: -8px; box-shadow: 0 18px 40px rgba(30, 36, 60, .12); display: flex; flex-direction: column; align-items: center; gap: 12px; }
.when { font: 600 19px/1.5 var(--serif); }
.where { font-size: 17px; line-height: 1.5; color: var(--soft); max-width: 17em; overflow-wrap: anywhere; }
.where b { display: block; font: 600 12px/1.6 var(--display); letter-spacing: .2em; text-transform: uppercase; color: var(--ink); }
.dress { font-size: 17px; font-style: italic; color: var(--soft); }

.chapters { list-style: none; padding: 0; width: 100%; display: flex; flex-direction: column; gap: 18px; text-align: left; }
.chapters li { position: relative; padding: 20px 20px 20px 26px; border-radius: 18px; background: var(--card); border: 1px solid var(--line); }
.chapters li::before { content: ""; position: absolute; left: 0; top: 18px; bottom: 18px; width: 4px; border-radius: 2px; background: var(--r2); }
.chapters h3 { font: 400 34px/1.05 var(--script); color: var(--deep2); margin-bottom: 6px; }
.chapters p { font-size: 17px; line-height: 1.55; color: var(--soft); }

.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; width: 100%; }
.grid img { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; border-radius: 16px; border: 4px solid var(--card); box-shadow: 0 10px 22px rgba(30, 36, 60, .14); }
.grid img:nth-child(3n+1) { grid-column: 1 / -1; aspect-ratio: 4 / 3; }

.gift-list { display: grid; gap: 12px; width: 100%; }
.gift-card { padding: 16px 18px; border-radius: 18px; background: var(--card); border: 1px solid var(--line); display: flex; align-items: center; justify-content: space-between; gap: 12px; text-align: left; }
.bank { font: 600 12px/1.4 var(--display); letter-spacing: .22em; text-transform: uppercase; color: var(--deep2); }
.number { font-size: 22px; font-weight: 700; letter-spacing: .04em; overflow-wrap: anywhere; }
.holder { font-size: 15px; color: var(--soft); }
.gift-card .btn { flex-shrink: 0; min-height: 42px; padding: 0 16px; }
.address { width: 100%; padding: 14px 16px; border-radius: 14px; border: 1px dashed var(--line); font-size: 16px; line-height: 1.5; color: var(--soft); text-align: left; }

.note { width: 100%; padding: 14px 16px; border: 1px dashed rgba(255, 255, 255, .7); border-radius: 14px; font-size: 16px; }
.thanks { width: 100%; padding: 22px 18px; border-radius: 18px; background: rgba(255, 255, 255, .16); display: flex; flex-direction: column; gap: 6px; }
.thanks .big { font: 400 38px/1.1 var(--script); }
.form { width: 100%; display: flex; flex-direction: column; gap: 14px; text-align: left; }
.field { display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 0; border: 0; font-size: 16px; font-weight: 700; }
.field legend { padding: 0 0 6px; }
.field input, .field textarea { width: 100%; min-height: 48px; padding: 0 14px; border: 0; border-radius: 12px; background: #fff; color: var(--ink); font: 500 18px/1.4 var(--serif); }
.field textarea { padding: 12px 14px; min-height: 110px; resize: vertical; }
.field input:focus, .field textarea:focus { outline: 2px solid var(--gold-hi); outline-offset: 1px; }
.opts { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.opt { position: relative; }
.opt input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; margin: 0; cursor: pointer; }
.opt span { display: flex; align-items: center; justify-content: center; min-height: 48px; border: 1.5px solid rgba(255, 255, 255, .8); border-radius: 12px; font: 600 13px/1 var(--display); letter-spacing: .14em; text-transform: uppercase; }
.opt input:checked + span { background: #fff; color: var(--deep2); }
.opt input:focus-visible + span { outline: 2px solid var(--gold-hi); outline-offset: 2px; }
.rsvp .btn { min-height: 50px; background: #fff; border-color: #fff; color: var(--deep2); }

main > section.wishes-box { align-items: stretch; text-align: left; gap: 0; padding-top: 30px; }
.wishes-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.wishes-head h2 { font: 400 36px/1.1 var(--script); color: var(--deep2); }
.wishes-head span { font-size: 15px; color: var(--soft); white-space: nowrap; }
.wishes { list-style: none; margin: 12px 0 0; padding: 0; max-height: 560px; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; }
.wishes li { padding: 14px 16px; border-radius: 16px; background: var(--card); border: 1px solid var(--line); display: flex; flex-direction: column; gap: 4px; }
.wish-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.wish-head b { font-size: 18px; }
.tag { padding: 2px 8px; border-radius: 999px; border: 1px solid var(--gold); font-size: 12px; letter-spacing: .06em; text-transform: uppercase; color: var(--gold); }
.status { font-size: 14px; font-weight: 700; color: var(--deep2); }
.wish-text { font-size: 17px; line-height: 1.5; color: var(--soft); overflow-wrap: anywhere; }
.wish-reply { margin-top: 6px; padding: 8px 12px; border-left: 2px solid var(--r2); font-style: italic; color: var(--soft); }

main > section.closing { padding-top: 90px; background: linear-gradient(180deg, var(--bg), var(--sky2)); }

.merci { font-size: 54px; }
.thanks-line { font-size: 17px; font-style: italic; color: var(--soft); }
footer { position: relative; padding: 18px 16px 26px; text-align: center; font-size: 14px; color: var(--soft); background: var(--sky2); }

.music-toggle { position: fixed; bottom: 16px; right: max(14px, calc(50% - 226px)); z-index: 50; width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; border: 0; border-radius: 50%; background: var(--deep2); color: #fff; cursor: pointer; box-shadow: 0 8px 18px rgba(30, 36, 60, .3); }
.music-toggle svg { width: 18px; height: 18px; }
.music-toggle[aria-pressed="false"]::after { content: ""; position: absolute; width: 24px; height: 1.5px; background: #fff; transform: rotate(-45deg); }
html:not(.js) .music-toggle, .js:not(.is-open) .music-toggle { display: none; }

/* ---------- Animasi ---------- */
/* Isi muncul bertahap saat digulir (kelas .rv dipasang london.js): judul turun, foto membesar, mempelai dari kiri/kanan. */
.rv { opacity: 0; translate: 0 26px; }
.rv.script { translate: 0 -22px; }
.rv.portrait, .grid .rv, .rv.event { translate: 0 0; scale: .86; }
.person:nth-child(odd) .rv { translate: -30px 0; } .person:nth-child(even) .rv { translate: 30px 0; }
.rv.in { opacity: 1; translate: 0 0; scale: 1; transition: opacity .9s cubic-bezier(.2, .7, .2, 1) calc(var(--d, 0) * 1ms), translate .9s cubic-bezier(.2, .7, .2, 1) calc(var(--d, 0) * 1ms), scale .9s cubic-bezier(.2, .7, .2, 1) calc(var(--d, 0) * 1ms); }
@media (prefers-reduced-motion: no-preference) {
  /* Urutan: gerimis & kabut reda sambil pandangan mundur dari kotak telepon (1,4–6,6 dtk) → menara muncul dari kabut →
     lampu jembatan menyala berurutan → jarum jam berputar ke jam akad → prangko jatuh, lalu dicap.
     Berulang terus: bus melintas di jembatan, perahu di sungai, burung, kilau air, denyut lampu. */
  .hujan { animation: gerimis .5s linear infinite; }
  .kabut.k1 { animation: hanyut 22s ease-in-out infinite alternate; } .kabut.k2 { animation: hanyut 30s ease-in-out infinite alternate-reverse; }
  .lampu.besar { animation: nyala 3.2s ease-in-out infinite alternate; }
  .js.is-open .lampu:not(.besar) { animation: nyala 2.8s 8s ease-in-out infinite alternate; }
  .bus { animation: jalan 19s 6.5s linear infinite; } .perahu { animation: layar 30s 4s linear infinite, oleng 3.4s ease-in-out infinite alternate; }
  .kilau i { animation: kilat 3s ease-in-out infinite; }
  .birds { animation: lintas 26s 5s linear infinite; } .bw { animation: sayap .5s ease-in-out infinite alternate; } .bw.b2 { animation-delay: -.2s; } .bw.b3 { animation-delay: -.35s; }
  .ly-roses > img { animation: ayun2 6s ease-in-out infinite alternate; transform-origin: 60% 100%; }
  .ly-sky > img { animation: napas 18s ease-in-out infinite alternate; }
  .js.is-open:not(.no-anim) .veil { animation: silau 3.4s 3.2s ease-in-out both; }
  .js.is-open:not(.no-anim) .prangko { animation: jatuh 1.1s 7s cubic-bezier(.3, 1.3, .5, 1) both; }
  .js.is-open:not(.no-anim) .cap { animation: cap .5s 8.3s cubic-bezier(.2, 1.6, .4, 1) both; }
  .js.is-open:not(.no-anim) .title { animation: getar .3s 8.5s ease-out both; }
  .js.is-open:not(.no-anim) .hero-pin > .mouse { animation: naik 1s 9.3s both; }
  .spray { animation: ayun 6s ease-in-out infinite; transform-origin: 50% 100%; } .buket { animation: ayun 7s ease-in-out infinite; transform-origin: 50% 80%; }
  .cover-top { animation: turun 1.2s .2s both; } .cover-bottom { animation: naik 1.2s .5s both; }
  .cover .open { animation: denyut 2.8s 2s ease-in-out infinite; }
}
@keyframes gugur { from { translate: 0 0; } to { translate: 70px 112vh; } }
@keyframes kibar { from { rotate: -50deg; scale: 1 1; } to { rotate: 190deg; scale: .5 1; } }
@keyframes kelip { 0%, 100% { opacity: 0; translate: 0 0; } 50% { opacity: .75; translate: 6px -26px; } }
@keyframes kepak { from { scale: 1 1; } to { scale: .2 1; } }
@keyframes terbang1 { 0%, 100% { translate: 0 0; rotate: 20deg; } 25% { translate: 70px -60px; rotate: -10deg; } 50% { translate: 150px -20px; rotate: 30deg; } 75% { translate: 60px 30px; rotate: -25deg; } }
@keyframes terbang2 { 0%, 100% { translate: 0 0; rotate: -20deg; } 30% { translate: -90px 40px; rotate: 15deg; } 60% { translate: -150px -10px; rotate: -30deg; } 80% { translate: -50px -40px; rotate: 20deg; } }
@keyframes alir { to { stroke-dashoffset: -14; } }
@keyframes riak { from { scale: .4; opacity: .9; } to { scale: 2.6; opacity: 0; } }
@keyframes apung { from { translate: -2px 1px; } to { translate: 2px -1px; } }
@keyframes apung2 { from { translate: -1px 0; rotate: -.25deg; } to { translate: 1px 0; rotate: .25deg; } }
@keyframes kelip2 { 0%, 100% { scale: .3; opacity: 0; } 50% { scale: 1.1; opacity: .95; } }
@keyframes sinar { from { opacity: .55; } to { opacity: 1; } }
@keyframes napas { from { scale: 1; } to { scale: 1.035; } }
@keyframes silau { 0%, 100% { opacity: 0; } 50% { opacity: .5; } }
@keyframes mekarR { from { opacity: 0; scale: -.3 .3; } to { opacity: 1; scale: -1 1; } }
@keyframes naik2 { from { opacity: 0; translate: 0 50%; } to { opacity: 1; translate: 0 0; } }
@keyframes kabut { from { opacity: .9; } to { opacity: 0; } }
@keyframes toleh { from { rotate: -4deg; } to { rotate: 5deg; } }
@keyframes kibas { from { rotate: -1.2deg; } to { rotate: 1.2deg; } }
@keyframes plakat { from { opacity: 0; translate: 0 26px; scale: .94; } to { opacity: 1; translate: 0 0; scale: 1; } }
@keyframes mekar { from { opacity: 0; scale: .3; } to { opacity: 1; scale: 1; } }
@keyframes turun { from { opacity: 0; translate: 0 -18px; } to { opacity: 1; translate: 0 0; } }
@keyframes naik { from { opacity: 0; translate: 0 18px; } to { opacity: 1; translate: 0 0; } }
@keyframes denyut { 0%, 100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); } 50% { box-shadow: 0 0 0 9px rgba(255, 255, 255, .18); } }
@keyframes ayun { 0%, 100% { rotate: -2deg; } 50% { rotate: 2deg; } }
@keyframes gulir { 0% { translate: 0 0; opacity: 1; } 70% { translate: 0 12px; opacity: 0; } 100% { translate: 0 0; opacity: 0; } }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } .rv { opacity: 1; translate: none; scale: none; } *, *::before, *::after { animation: none !important; } .js .ly, .js .jj, .js .jm, .js .lampu, .js .dingin, .js .kabut, .js .hujan { transition: none; } }
.js body.locked { overflow: visible; }

/* ---------- Pembuka London: judul berupa prangko antik (tepi bergerigi) di langit kiri atas, dengan cap pos yang
   "dijatuhkan" di sudutnya. Lukisan tetap utuh. Selama pembuka digulir (.ready, --p 0→1 dipasang london.js) pandangan
   melaju melewati jembatan menuju menara jam sampai layar memutih. ---------- */
.script, .person h3, .chapters h3, .wishes-head h2 { color: var(--aksen); }
.count .script, .rsvp .script { color: #fff; }
.hero-pin { display: grid; place-items: start; width: 100%; position: relative; }
.js .hero { display: block; padding: 0; }
.js .hero-pin { position: fixed; left: 50%; bottom: 0; width: min(100%, 480px); height: 100vh; height: 100svh; translate: -50% 0; padding: 9vh 22px 0; pointer-events: none; }
.scene-off .hero-pin { visibility: hidden; }
.title-wrap { width: min(68%, 270px); }
.title { position: relative; rotate: -4deg; }
.prangko { padding: 9px; background: #fffdf8; filter: drop-shadow(0 10px 14px rgba(30, 36, 60, .3)); -webkit-mask: radial-gradient(50% 50%, #000 62%, transparent 66%) round 5px 5px / 10px 10px, linear-gradient(#000 0 0) no-repeat 50% / calc(100% - 10px) calc(100% - 10px); mask: radial-gradient(50% 50%, #000 62%, transparent 66%) round 5px 5px / 10px 10px, linear-gradient(#000 0 0) no-repeat 50% / calc(100% - 10px) calc(100% - 10px); }
.prangko-in { padding: 18px 12px 16px; border: 1.5px solid var(--aksen); outline: 1px solid var(--gold); outline-offset: -6px; background: linear-gradient(180deg, #fffdf8, #f8ecdd); text-align: center; color: var(--ink); display: flex; flex-direction: column; align-items: center; gap: 4px; }
.prangko .caps { font-size: 10px; letter-spacing: .28em; color: var(--soft); }
.t-name { font: 400 38px/1.08 var(--script); color: var(--aksen); overflow-wrap: anywhere; }
.t-name .amp { display: block; font-size: .62em; line-height: .9; color: var(--gold); }
.prangko .pl-date { margin-top: 4px; font-size: 11px; letter-spacing: .16em; }
.cap { position: absolute; right: -96px; bottom: -72px; width: 160px; height: auto; rotate: 14deg; opacity: .78; overflow: visible; }
.cap-l { fill: none; stroke: var(--deep); stroke-width: 2.4; } .cap-l.tipis { stroke-width: 1.2; } .cap-g { fill: none; stroke: var(--deep); stroke-width: 2; stroke-linecap: round; }
.cap-t { fill: var(--deep); font: 700 9.5px/1 var(--display); letter-spacing: .16em; text-transform: uppercase; } .cap-h { fill: var(--deep); }
.hero-pin > .mouse { position: absolute; left: 50%; bottom: 5vh; margin: 0 0 0 -11px; border-color: #fff; opacity: .92; filter: drop-shadow(0 1px 3px rgba(30, 36, 60, .6)); } .hero-pin > .mouse::after { background: #fff; }
html:not(.js) .hero-pin { padding: 40px 28px; place-items: center; } html:not(.js) .hero-pin > .mouse { display: none; }
main h2.script::after { content: ""; display: block; width: 240px; max-width: 80vw; height: 34px; margin: 4px auto 0; background: url("img/pembatas.webp") center / contain no-repeat; }
.memuat .cover .open { pointer-events: none; opacity: .55; }
@media (prefers-reduced-motion: no-preference) {
  .js .hero { min-height: 240vh; min-height: 240svh; }
  /* Perjalanan gulir: aktif setelah pembukaan selesai. --p = seberapa jauh pembuka sudah digulir. */
  .ready .ly { transition: none; }
  .ready .ly-sky { transform-origin: 80% 25%; transform: scale(calc(1 + var(--p, 0) * .5)); }
  .ready .ly-tower { transform-origin: 80% 25%; transform: scale(calc(1 + var(--p, 0) * var(--p, 0) * 4.4)); }
  .ready .ly-bridge { transform-origin: 80% 50%; transform: translateY(calc(var(--p, 0) * 22%)) scale(calc(1 + var(--p, 0) * 2.2)); }
  .ready .ly-river, .ready .ly-boat { transform-origin: 80% 50%; transform: translateY(calc(var(--p, 0) * 22%)) scale(calc(1 + var(--p, 0) * 2.2)); } /* sama dengan jembatan supaya air tetap menempel di kakinya */
  .ready .ly-front { transform: translate(calc(var(--p, 0) * -70%), calc(var(--p, 0) * 60%)) scale(calc(1 + var(--p, 0) * .9)); }
  .ready .title-wrap { opacity: calc(1 - var(--p, 0) * 4); translate: 0 calc(var(--p, 0) * -120px); }
  .ready .hero-pin > .mouse { opacity: calc(.92 - var(--p, 0) * 6); }
  .ready .terang { opacity: calc((var(--p, 0) - .6) * 3.2); }
}
@keyframes gerimis { from { background-position: 0 0, 0 0; } to { background-position: -11px 60px, -17px 96px; } }
@keyframes hanyut { from { translate: -6% 0; } to { translate: 12% 0; } }
@keyframes nyala { from { opacity: .55; } to { opacity: 1; } }
@keyframes jalan { from { left: 104%; } to { left: -14%; } }
@keyframes layar { from { left: -22%; } to { left: 108%; } }
@keyframes oleng { from { rotate: -1.6deg; } to { rotate: 1.6deg; } }
@keyframes kilat { 0%, 100% { opacity: 0; scale: .4 1; } 50% { opacity: .8; scale: 1 1; } }
@keyframes lintas { from { translate: -260px 420px; } to { translate: 1300px 240px; } }
@keyframes sayap { from { scale: 1 1; } to { scale: 1 -.6; } }
@keyframes ayun2 { from { rotate: -.6deg; } to { rotate: .6deg; } }
@keyframes jatuh { from { opacity: 0; translate: 0 -60px; rotate: 10deg; scale: 1.25; } to { opacity: 1; translate: 0 0; rotate: 0deg; scale: 1; } }
@keyframes cap { from { opacity: 0; scale: 2.6; } to { opacity: .78; scale: 1; } }
@keyframes getar { 0% { translate: 0 0; } 30% { translate: 2px 3px; } 60% { translate: -1px -1px; } 100% { translate: 0 0; } }

/* Foto tiap kisah cinta (opsional, sub-field stories.photo): polaroid kecil di atas judul, miring bergantian. */
.kisah-foto { margin: 2px 0 14px; padding: 6px 6px 20px; background: #fff; border-radius: 3px; box-shadow: 0 10px 22px rgba(30, 20, 20, .16); rotate: -1.4deg; }
:nth-child(even) > .kisah-foto { rotate: 1.4deg; }
.kisah-foto img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 2px; }

/* Kisah: kartu pos airmail dengan prangko bernomor dan cap pos, dikirim satu per satu lalu ditutup bus merah. */
.chapters { gap: 28px; counter-reset: pos; }
.chapters li { counter-increment: pos; padding: 8px; border: 0; border-radius: 3px; background: repeating-linear-gradient(-45deg, var(--r3) 0 14px, #fff 14px 28px, var(--deep) 28px 42px, #fff 42px 56px); box-shadow: 0 12px 24px rgba(40, 45, 70, .18); rotate: -1deg; }
.chapters li:nth-child(even) { rotate: 1deg; }
.chapters li > * { position: relative; }
.chapters li > h3, .chapters li > p, .chapters li > figure { background: var(--card); }
.chapters li { display: flex; flex-direction: column; }
.chapters li > h3 { padding: 18px 86px 6px 16px; margin: 0; }
.chapters li > p { flex: 1; padding: 0 16px 18px; }
.chapters li > figure { margin: 0; padding: 12px 12px 4px; box-shadow: none; rotate: none; }
.chapters li::before { content: counter(pos); left: auto; right: 18px; top: 16px; bottom: auto; z-index: 2; width: 54px; height: 64px; display: grid; place-items: center; border-radius: 0; background: var(--deep); color: var(--gold-hi); font: 600 24px/1 var(--display); box-shadow: 0 0 0 3px var(--card), 0 0 0 5px var(--deep); outline: 2px dashed var(--gold-hi); outline-offset: -6px; }
.chapters li::after { content: "London"; position: absolute; z-index: 3; right: 58px; top: 40px; width: 56px; height: 56px; display: grid; place-items: center; border: 2px solid rgba(156, 59, 63, .6); border-radius: 50%; color: rgba(156, 59, 63, .7); font: 700 8px/1 var(--display); letter-spacing: .1em; text-transform: uppercase; rotate: -14deg; pointer-events: none; }
.chapters li:has(> figure)::before, .chapters li:has(> figure)::after { top: auto; bottom: 16px; }
.chapters li:has(> figure) > p { padding-right: 16px; padding-bottom: 92px; }
.chapters li:has(> figure) > h3 { padding-right: 16px; }
.story::after { content: ""; width: 120px; aspect-ratio: 300 / 168; background: url("img/bus.webp") center / contain no-repeat; }
