/* ============ bảng màu (B2 rượu vang + champagne) ============ */
:root {
  --paper: #FBF6EC; --paper-2: #F1E6D2; --ink: #3A1219; --ink-muted: #6E4E49; --line: #C9AE83;
  --wine: #5E0B15; --wine-deep: #3D0710; --wine-hi: #8A1A2B; --night: #16040A;
  --champ: #E8D3A9; --cream: #F7EEDD; --gold-dark: #B39566; --gold-ok: #E2B866;
  --world: #3D0710; --world-2: #5E0B15; --world-3: #1E0308; --glow: #FFEBD0; --accent: #E8D3A9;
  --gold: #E8D3A9; --gold-light: #F7EEDD;
  --env-1: #6E0F1C; --env-2: #3D0710; --env-3: #8E2234; --liner: #2A050B; --liner-ink: #E8D3A9;
  --wax-1: #FFF6E2; --wax-2: #D9BE8A; --wax-3: #8E7046;
  --font-script: "Pinyon Script", "Snell Roundhand", cursive;
  --font-display: "Playfair Display", "EB Garamond", Georgia, serif;
  --font-body: "EB Garamond", "Iowan Old Style", Georgia, serif;
  --font-ui: "Be Vietnam Pro", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --grain-dark: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 .22 0 0 0 0 .12 0 0 0 0 .06 0 0 0 .55 -.12'/></filter><rect width='180' height='180' filter='url(%23n)'/></svg>");
  --grain-light: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 .93 0 0 0 0 .84 0 0 0 .5 -.14'/></filter><rect width='180' height='180' filter='url(%23n)'/></svg>");
  --ease: cubic-bezier(.22, .7, .2, 1);
  color-scheme: light;
}
html { background: var(--wine-deep); overflow-x: hidden; -webkit-text-size-adjust: 100%; }
body { margin: 0; background: var(--wine-deep); color: var(--ink); font: 400 17px/1.5 var(--font-body); overflow-x: hidden; -webkit-tap-highlight-color: transparent; }
html:has(#app[data-stage="journey"]), html:has(#app[data-stage="journey"]) body { background: var(--night); }
*, *::before, *::after { box-sizing: border-box; }
button { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--gold-ok); outline-offset: 3px; border-radius: 6px; }
.kicker { margin: 0; font: 600 13.5px/1.3 var(--font-body); letter-spacing: .3em; text-transform: uppercase; color: var(--wine); }
.amp { font-family: var(--font-display); font-style: italic; font-weight: 400; }
.orn { display: block; width: 46%; max-width: 220px; height: auto; color: var(--gold-dark); overflow: visible; }

/* ============ tầng nào hiện theo màn ============ */
.layer-env { position: fixed; inset: 0; z-index: 30; overflow: hidden; display: none; }
#app[data-stage="env"] .layer-env, #app[data-stage="card"] .layer-env:not([hidden]) { display: block; }
#app[data-stage="card"] .layer-env { pointer-events: none; }
.card-stage { display: none; position: fixed; inset: 0; z-index: 1; background: #1C0306; }
#app[data-stage="card"] .card-stage { display: block; }
.journey { position: fixed; inset: 0; z-index: 10; visibility: hidden; opacity: 0; background: var(--night); overflow: hidden; }
#app[data-stage="journey"] .journey { visibility: visible; opacity: 1; transition: opacity .6s var(--ease); }
.spacer { display: none; }
#app[data-stage="journey"] .spacer { display: block; }
.no-anim *, .no-anim *::before, .no-anim *::after { transition: none !important; }
/* trời sao (sky.js): canvas đục nằm dưới cùng ở màn phong bì và màn thư; phong bì, lá thư được vẽ ngay trong canvas,
   các lớp phía trên trong suốt. Video, ảnh vẫn nằm đúng ô khung trong khung nhìn (iOS ngừng giải mã video bị ẩn hẳn)
   nhưng không hiện, chỉ làm nguồn hình cho canvas. Mất WebGL giữa chừng (sky-on bị gỡ) thì chúng hiện lại. */
.sky { position: fixed; inset: 0; z-index: 0; width: 100%; height: 100%; display: none; }
#app.sky-on[data-stage="env"] .sky, #app.sky-on[data-stage="card"] .sky { display: block; }
#app.sky-on .rv, #app.sky-on .card-stage, #app.sky-on .card-stage .info { background: transparent; }
#app.sky-on .rv::before, #app.sky-on .card-stage .info::before, #app.sky-on .rv-sparks { display: none; }
#app.sky-on .rv-p, #app.sky-on .card-stage .info-img { opacity: 0 !important; }
/* video để 1% (không phải 0): WebKit có thể ngừng giải mã video bị coi là ẩn; 1% của chính hình canvas đang vẽ thì không thấy */
#app.sky-on .rv-v { opacity: .01 !important; }

/* ============ 1 · phong bì A1 ============ */
.a1 { position: absolute; inset: 0; cursor: pointer; }
.a1-bg, .a1-3d { position: absolute; inset: 0; }
.a1-bg { background: radial-gradient(58% 46% at 50% 47%, color-mix(in srgb, var(--world-2) 88%, var(--glow) 8%), transparent 74%), radial-gradient(130% 95% at 50% 42%, var(--world) 25%, var(--world-3) 100%); }
.a1-bg::after { content: ""; position: absolute; inset: 0; background-image: var(--grain-light); opacity: .28; }
.a1-3d { display: grid; place-items: center; perspective: 1700px; perspective-origin: 50% 42%; padding-bottom: 4vh; }
.a1-float { position: relative; width: var(--ew); height: var(--eh); transform-style: preserve-3d; }
.a1-bob { position: absolute; inset: 0; transform-style: preserve-3d; animation: a1bob 6.5s ease-in-out infinite; }
@keyframes a1bob { 0%, 100% { transform: translate3d(0, 0, 0) rotateZ(-.5deg); } 50% { transform: translate3d(0, -8px, 0) rotateZ(.5deg); } }
.a1.opened .a1-bob { animation-play-state: paused; }
.a1-base { position: absolute; inset: 0; transform-style: preserve-3d; }
.a1-env { position: absolute; inset: 0; transform-style: preserve-3d; }
.a1-back, .a1-pocket, .a1-flap { position: absolute; left: 0; top: 0; width: 100%; height: 100%; }
.a1-back svg, .a1-pocket svg, .a1-flap svg { position: absolute; left: 0; top: 0; width: 100%; height: 100%; overflow: visible; }
.a1-back { transform: translateZ(0); }
.a1-pocket { transform: translateZ(2px); pointer-events: none; }
.a1-flap { height: var(--fhb) !important; transform-origin: 50% 0; transform-style: preserve-3d; }
.a1-flap > div { position: absolute; inset: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden; }
.a1-flap .bk { transform: rotateY(180deg); }
.a1-shadow { position: absolute; left: 4%; right: 4%; bottom: -9%; height: 22%; background: radial-gradient(closest-side, rgba(10,0,0,.55), transparent); filter: blur(8px); transform: translateZ(-30px); }
.a1-seal { position: absolute; left: 50%; top: var(--sy); width: var(--sz); height: var(--sz); margin: calc(var(--sz) / -2) 0 0 calc(var(--sz) / -2); transform: translateZ(5px); transform-style: preserve-3d; border-radius: 50%; }
.a1-seal > .half { position: absolute; inset: 0; }
.a1-seal > .half svg { width: 100%; height: 100%; overflow: visible; filter: drop-shadow(0 3px 3px rgba(0,0,0,.35)); }
.a1-seal > .half.l { clip-path: polygon(-20% -20%, 52% -20%, 47% 18%, 55% 34%, 46% 52%, 54% 70%, 48% 86%, 51% 120%, -20% 120%); }
.a1-seal > .half.r { clip-path: polygon(52% -20%, 120% -20%, 120% 120%, 51% 120%, 48% 86%, 54% 70%, 46% 52%, 55% 34%, 47% 18%); }
.a1-crack { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.a1-crack polyline { fill: none; stroke: var(--wax-1); stroke-width: 2.2; stroke-linejoin: round; stroke-dasharray: 1; stroke-dashoffset: 1; filter: drop-shadow(0 0 3px var(--wax-1)); }
.a1-glint { position: absolute; inset: 10%; border-radius: 50%; pointer-events: none; background: radial-gradient(circle at 36% 30%, rgba(255,255,255,.62), rgba(255,255,255,.12) 18%, transparent 34%); }
.a1-ring { position: absolute; inset: -16%; border-radius: 50%; border: 1.5px solid var(--accent); animation: a1ring 2.6s ease-out infinite; pointer-events: none; }
.a1-ring.two { animation-delay: 1.3s; }
.a1.opened .a1-ring, .a1.opened .a1-glint { display: none; }
@keyframes a1ring { 0% { transform: scale(.78); opacity: .85; } 100% { transform: scale(1.45); opacity: 0; } }
.a1-card { position: absolute; left: 50%; top: 50%; width: var(--cw); height: var(--ch); margin: calc(var(--ch) / -2) 0 0 calc(var(--cw) / -2); }
.a1-card .inv { box-shadow: inset 0 0 0 1px rgba(255,255,255,.4), inset 0 0 40px rgba(120,80,30,.12), 0 34px 60px -26px rgba(0,0,0,.6), 0 10px 24px -12px rgba(0,0,0,.4); }
.a1-hint { position: absolute; left: 0; right: 0; bottom: calc(7vh + env(safe-area-inset-bottom)); margin: 0; display: flex; justify-content: center; pointer-events: none; font: italic 400 19px/1.3 var(--font-body); letter-spacing: .03em; color: var(--accent); text-shadow: 0 1px 14px rgba(0,0,0,.35); }
.a1-hint span { display: inline-flex; align-items: center; gap: .6em; animation: hintBreath 2.8s ease-in-out infinite; }
.a1-hint span::before { content: ""; width: .42em; height: .42em; border-radius: 50%; background: currentColor; animation: hintPing 2.8s ease-out infinite; }
@keyframes hintBreath { 50% { opacity: .62; } }
/* phong bì thật (video dựng bằng Blender): khung phủ kín màn khi lá thư vẫn nằm trọn, không thì hai bên là ảnh chờ làm mờ */
.rv { position: absolute; inset: 0; cursor: pointer; overflow: hidden; background: #1C0306; transition: opacity .75s var(--ease); }
.rv::before { content: ""; position: absolute; inset: -8%; background: var(--poster) center / cover; filter: blur(48px) brightness(.38) saturate(1.1); }
/* khung video / ảnh đặt đúng ô fitFrame (--ox --oy --dw --dh, fit.js); có dải trống thì mép khung tan 16px vào nền mờ
   (mask theo toạ độ của chính khung) */
.rv-v, .rv-p, .info-img { position: absolute; left: var(--ox, 0); top: var(--oy, 0); width: var(--dw, 100%); height: var(--dh, 100%); max-width: none; object-fit: fill; }
.rv.wide:not(.packed) .rv-v, .rv.wide:not(.packed) .rv-p, .info.wide:not(.packed) .info-img { -webkit-mask-image: linear-gradient(90deg, transparent, #000 16px, #000 calc(100% - 16px), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 16px, #000 calc(100% - 16px), transparent); }
.rv.tall:not(.packed) .rv-v, .rv.tall:not(.packed) .rv-p, .info.tall:not(.packed) .info-img { -webkit-mask-image: linear-gradient(180deg, transparent, #000 16px, #000 calc(100% - 16px), transparent);
  mask-image: linear-gradient(180deg, transparent, #000 16px, #000 calc(100% - 16px), transparent); }
.rv.wide.tall:not(.packed) .rv-v, .rv.wide.tall:not(.packed) .rv-p, .info.wide.tall:not(.packed) .info-img {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 16px, #000 calc(100% - 16px), transparent), linear-gradient(180deg, transparent, #000 16px, #000 calc(100% - 16px), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 16px, #000 calc(100% - 16px), transparent), linear-gradient(180deg, transparent, #000 16px, #000 calc(100% - 16px), transparent);
  -webkit-mask-composite: source-in; mask-composite: intersect; }
/* tài sản dạng packed (màu nhân sẵn alpha | mặt nạ, rộng 1,5 khung): không có trời sao thì chỉ hiện phần màu trên nền đen */
.rv.packed .rv-v, .rv.packed .rv-p, .info.packed .info-img { width: calc(var(--dw, 100%) * 1.5); clip-path: inset(0 33.3333% 0 0); }
.rv.packed, .info.packed { background: #000; }
.rv.packed::before, .info.packed::before { display: none; }
.rv-cam { position: absolute; inset: 0; transform-origin: 50% 48%; animation: rvBreath 9s ease-in-out infinite alternate; }
/* lúc chạm: envelope-real.js settleCam() gỡ animation ở độ phóng hiện tại rồi trôi về 100% */
@keyframes rvBreath { to { transform: scale(1.018); } }
.rv-p { transition: opacity .2s linear; }
.rv-p.off { opacity: 0; }
/* mở đầu: ảnh chờ ẩn bên dưới cho tới khi video mở đầu chạy hết (khung cuối của nó chính là ảnh chờ) */
.rv.intro .rv-p { visibility: hidden; }
/* hết mở đầu: video tan 0,35 s vào ảnh chờ bên dưới (cùng hình; trình duyệt vẽ video sáng hơn ảnh vài mức nên không đổi cái rụp) */
.rv-in { transition: opacity .35s linear; }
.rv-in.off { opacity: 0; visibility: hidden; transition: opacity .35s linear, visibility 0s linear .35s; }
.rv.intro .a1-hint { opacity: 0; }
/* máy chặn tự phát (iPhone Nguồn điện thấp): nền tối + sao, hiện gợi ý, chạm thì phát mở đầu */
.rv.intro.gate .a1-hint { opacity: 1; }
.a1-hint { transition: opacity .6s var(--ease); }
/* bụi sao vẽ trên trang, nằm trên video, dưới chữ gợi ý */
.rv-sparks { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
/* hạt phim rất nhẹ để khung hình giống video quay thật */
.rv-grain { position: absolute; inset: -40px; background-image: var(--grain-light); opacity: .07; mix-blend-mode: overlay; pointer-events: none; animation: rvGrain .9s steps(5) infinite; transition: opacity 1.2s linear; }
/* video mở thư qua giây 2,2: hạt nhiễu mờ về 0 trước lúc gỡ lớp phong bì (màn thư không có hạt) */
.rv.fx-off .rv-grain { opacity: 0; }
@keyframes rvGrain { 20% { transform: translate(-14px, 9px); } 40% { transform: translate(11px, -16px); } 60% { transform: translate(-7px, -5px); } 80% { transform: translate(16px, 12px); } }
.rv-hit { position: absolute; left: var(--sx); top: var(--sy); width: var(--sd); height: var(--sd); transform: translate(-50%, -50%); border: 0; border-radius: 50%; background: none; padding: 0; cursor: pointer; }
.rv-hit:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.rv.opened .a1-hint { opacity: 0; transition: opacity .35s; }
/* đã chạm nhưng video chưa tải xong: chữ gợi ý đổi thành đang mở */
.rv.opened.wait .a1-hint { opacity: 1; }
.rv.wait .a1-hint span { font-size: 0; }
.rv.wait .a1-hint span::after { content: "Đang mở thiệp…"; font-size: 19px; }
.rv.out { opacity: 0; pointer-events: none; }
@keyframes hintPing { 0% { box-shadow: 0 0 0 0 color-mix(in srgb, currentColor 70%, transparent); } 70%, 100% { box-shadow: 0 0 0 .7em transparent; } }

/* mặt thiệp nhỏ trong phong bì */
.inv { container: inv / size; position: relative; width: 100%; height: 100%; background: var(--paper); color: var(--ink); border-radius: 3px; overflow: hidden; display: grid; place-items: center; text-align: center; }
.inv::before { content: ""; position: absolute; inset: 0; background-image: var(--grain-dark); opacity: .55; pointer-events: none; }
.inv-frame { position: absolute; inset: 3.4cqmin; border: 1px solid var(--line); pointer-events: none; }
.inv-frame::after { content: ""; position: absolute; inset: 1.2cqmin; border: 1px solid color-mix(in srgb, var(--line) 55%, transparent); }
.inv-in { position: relative; display: flex; flex-direction: column; align-items: center; gap: 2.6cqmin; padding: 9cqmin 8cqmin; width: 100%; }
.inv .kicker { font-size: 3.4cqmin; }
.inv-guest { margin: 0; font: italic 400 5cqmin/1.25 var(--font-body); color: var(--ink-muted); }
.inv-guest b { font-weight: 500; color: var(--ink); }
.inv-names { margin: 0; display: flex; flex-direction: column; align-items: center; font: 400 13.5cqmin/1.08 var(--font-script); color: var(--wine); }
.inv-names .amp { font-size: .4em; color: var(--gold-dark); margin: -.05em 0 .1em; }
.inv-date { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 3cqmin; width: 86%; }
.inv-date span { font: 600 2.9cqmin/1 var(--font-body); letter-spacing: .2em; text-transform: uppercase; border-block: 1px solid var(--line); padding: 1.6cqmin 0; }
.inv-date b { font: 400 8.6cqmin/1 var(--font-display); color: var(--wine); }
.inv-lunar { margin: 0; font: italic 400 3.7cqmin/1.3 var(--font-body); color: var(--ink-muted); }
.inv-place { margin: 0; font: 500 3.5cqmin/1.35 var(--font-body); }
.inv .orn { width: 44%; }

/* ============ 2 · thiệp mời ============ */
@keyframes fadeIn { from { opacity: 0; } }

/* nút chung */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 46px; padding: 0 18px; border-radius: 999px; font: 500 15.5px/1.2 var(--font-ui); text-decoration: none; cursor: pointer; transition: background .2s, color .2s, border-color .2s, transform .15s; }
.btn svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; flex: none; }
.btn.ghost { color: var(--wine); background: transparent; border: 1px solid color-mix(in srgb, var(--wine) 45%, transparent); }
.btn.ghost:hover { background: color-mix(in srgb, var(--wine) 7%, transparent); border-color: var(--wine); }
.btn.solid { color: var(--cream); background: var(--wine); border: 1px solid var(--wine); }
.btn.solid:hover { background: var(--wine-hi); }
.btn:active { transform: scale(.98); }

/* màn thư = ảnh khung cuối của video (đặt cùng ô khung với video, xem trên) với lớp thư trong suốt khớp lên ảnh */
.info { position: absolute; inset: 0; overflow: hidden; background: #1C0306; }
.info::before { content: ""; position: absolute; inset: -8%; background: var(--still) center / cover; filter: blur(48px) brightness(.38) saturate(1.1); }
.info > .letter { position: absolute; left: 0; top: 0; }
.info.paper-mode { display: grid; place-items: center; background: radial-gradient(90% 60% at 50% 0%, color-mix(in srgb, var(--wine) 80%, var(--glow) 6%), transparent 70%), var(--wine-deep); }
.info.paper-mode::before, .info.paper-mode .info-img { display: none; }
.info.paper-mode > .letter { position: relative; }
.info-pop { position: fixed; inset: 0; z-index: 60; opacity: 0; transition: opacity .32s var(--ease); }
.info-pop.on { opacity: 1; }
.info-x { position: absolute; z-index: 2; top: calc(10px + env(safe-area-inset-top)); right: calc(10px + env(safe-area-inset-right)); width: 44px; height: 44px; display: grid; place-items: center; padding: 0; border: 0; border-radius: 50%; background: rgba(22,4,9,.5); color: #F3E6CC; cursor: pointer; -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
.info-x svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.info-x:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ============ 3 · hành trình ============ */
.engine { position: absolute; inset: 0; }
.engine canvas { display: block; }
/* khung ngắm máy ảnh ở đầu hành trình. shell.js đặt các biến theo p:
   --dim độ tối trong ô, --hud độ hiện chỉ số, --s độ phóng của ô (viền đen trôi ra ngoài), --af ô lấy nét, --m kim đo sáng */
.vf { --dim: 1; --hud: 0; --s: 1; --af: 1.16; --m: 0; position: absolute; inset: 0; z-index: 2; pointer-events: none; visibility: hidden; }
.vf.on { visibility: visible; }
.vf-win { position: absolute; left: 50%; top: 47%; width: 84vw; height: 60vh; height: 60dvh; max-height: 122vw; border-radius: 3.4vmin;
  transform: translate(-50%, -50%) scale(var(--s)); box-shadow: 0 0 0 150vmax #030001; will-change: transform; }
@media (min-aspect-ratio: 1/1) { .vf-win { width: 66vw; height: 66vh; height: 66dvh; max-height: none; } }
/* vùng tối áp sát mép ô, như nhìn qua thị kính */
.vf-win::before { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit;
  box-shadow: inset 0 0 2.6vmin 1.3vmin #030001, inset 0 0 12vmin 5vmin rgba(3,0,1,.72), inset 0 0 30vmin 3vmin rgba(3,0,1,.32); }
.vf-win::after { content: ""; position: absolute; inset: -1px; z-index: 1; border-radius: inherit; border: 1px solid rgba(255,228,190,.1); }
.vf-dim { position: absolute; inset: 0; border-radius: inherit; background: #030001; opacity: var(--dim); }
/* vệt sáng phản chiếu trên mép kính */
.vf-glow { position: absolute; top: 14%; z-index: 2; width: 24%; height: 72%; border-radius: 50%; mix-blend-mode: screen; filter: blur(5px);
  background: radial-gradient(closest-side, rgba(255,214,150,.4), rgba(255,170,100,.12) 60%, transparent); opacity: calc(var(--hud) * .9); }
.vf-glow.l { left: -12%; }
.vf-glow.r { right: -12%; }
.vf-hud { position: absolute; inset: 0; z-index: 3; opacity: var(--hud); color: #EADBB8;
  font: 500 10.5px/1 "Roboto Mono", ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: .22em; text-shadow: 0 0 6px rgba(234,219,184,.45); }
.vf-hud::before { content: ""; position: absolute; inset: 0; opacity: .1; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.95' numOctaves='2' stitchTiles='stitch'/></filter><rect width='140' height='140' filter='url(%23n)'/></svg>"); }
.vf-k { position: absolute; width: 22px; height: 22px; border: 0 solid currentColor; opacity: .8; }
.vf-k.tl { left: 8%; top: 8%; border-width: 1.5px 0 0 1.5px; }
.vf-k.tr { right: 8%; top: 8%; border-width: 1.5px 1.5px 0 0; }
.vf-k.bl { left: 8%; bottom: 8%; border-width: 0 0 1.5px 1.5px; }
.vf-k.br { right: 8%; bottom: 8%; border-width: 0 1.5px 1.5px 0; }
.vf-tag, .vf-iso { position: absolute; top: calc(8% + 34px); margin: 0; opacity: .82; }
.vf-tag { left: calc(8% + 2px); white-space: pre-line; line-height: 1.75; }
.vf-iso { right: calc(8% + 2px); opacity: .6; }
@media (max-width: 480px) { .vf-iso { display: none; } }
.vf-af { position: absolute; left: 50%; top: 50%; width: 15%; min-width: 46px; height: 19%; transform: translate(-50%, -50%) scale(var(--af)); }
.vf-af i { position: absolute; top: 0; bottom: 0; width: 9px; border: 1.5px solid currentColor; transition: border-color .2s, filter .2s; }
.vf-af i:first-child { left: 0; border-right: 0; }
.vf-af i:last-child { right: 0; border-left: 0; }
.vf.lock .vf-af i { border-color: #E9BE6A; filter: drop-shadow(0 0 5px rgba(233,190,106,.85)); }
.vf-meter { position: absolute; left: 50%; bottom: calc(8% + 32px); width: 40%; height: 8px; transform: translateX(-50%); }
.vf-ticks { position: absolute; inset: 0; opacity: .7; background: linear-gradient(90deg, currentColor 0 1.5px, transparent 1.5px) 0 0 / 6.25% 100% repeat-x; }
.vf-ticks::after { content: ""; position: absolute; left: 50%; top: -4px; width: 1.5px; height: 16px; background: currentColor; }
.vf-needle { position: absolute; top: -4px; left: calc(50% + var(--m) * 44%); width: 2px; height: 16px; margin-left: -1px; background: #E4573D; box-shadow: 0 0 6px rgba(228,87,61,.8); }
.vf-read { position: absolute; left: 0; right: 0; bottom: calc(8% + 10px); margin: 0; display: flex; justify-content: center; gap: 2.2em; }
.vf-pct { min-width: 4ch; text-align: center; font-weight: 500; color: #E4573D; text-shadow: 0 0 6px rgba(228,87,61,.6); }
.vf.lock .vf-pct { color: #E9BE6A; text-shadow: 0 0 6px rgba(233,190,106,.7); }
/* lúc động cơ còn đang nạp: ô tối, ô lấy nét dò liên tục */
.vf.loading { --dim: .9; --hud: 1; }
.vf.loading .vf-af { animation: afhunt 1.4s ease-in-out infinite; }
.vf.loading .vf-needle { animation: needle 1.9s ease-in-out infinite alternate; }
@keyframes afhunt { 0%, 100% { transform: translate(-50%, -50%) scale(1.16); } 50% { transform: translate(-50%, -50%) scale(1.03); } }
@keyframes needle { from { left: 28%; } to { left: 72%; } }
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

.scrim { position: absolute; left: 0; right: 0; bottom: 0; height: 52%; pointer-events: none; opacity: 0; background: linear-gradient(to top, rgba(22,4,10,.9), rgba(22,4,10,.55) 45%, transparent); }
.caption { position: absolute; left: calc(22px + env(safe-area-inset-left)); bottom: calc(70px + env(safe-area-inset-bottom)); right: calc(22px + env(safe-area-inset-right)); max-width: 30rem; opacity: 0; visibility: hidden; pointer-events: none; color: var(--cream); will-change: opacity, transform; }
.cap-k { margin: 0 0 8px; font: 600 12.5px/1.3 var(--font-ui); letter-spacing: .22em; text-transform: uppercase; color: var(--champ); }
.cap-t { margin: 0; font: 400 21px/1.42 var(--font-body); text-shadow: 0 1px 12px rgba(0,0,0,.55); text-wrap: pretty; }
.hint { position: absolute; left: 0; right: 0; bottom: calc(18px + env(safe-area-inset-bottom)); margin: 0; display: flex; flex-direction: column-reverse; align-items: center; gap: 2px; pointer-events: none; color: var(--champ); font: 500 13.5px/1.2 var(--font-ui); letter-spacing: .04em; text-shadow: 0 1px 8px rgba(0,0,0,.6); opacity: 0; transform: translateY(6px); transition: opacity .45s var(--ease), transform .45s var(--ease); }
.hint.on { opacity: .95; transform: none; }
.hint svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; animation: chev 1.6s ease-in-out infinite; }
@keyframes chev { 0%, 100% { transform: translateY(3px); opacity: .55; } 50% { transform: translateY(-3px); opacity: 1; } }

/* khi động cơ còn đang nạp, khung ngắm (.vf.loading) đóng vai màn chờ */
#app.loading .seal-btn { display: none; }
@media (prefers-reduced-motion: reduce) { .vf.loading .vf-af, .vf.loading .vf-needle { animation: none; } }

/* thiệp cuối */
.end { position: absolute; inset: 0; display: grid; place-items: center; padding: calc(24px + env(safe-area-inset-top)) calc(18px + env(safe-area-inset-right)) calc(24px + env(safe-area-inset-bottom)) calc(18px + env(safe-area-inset-left)); opacity: 0; visibility: hidden; transition: opacity .8s var(--ease), visibility 0s linear .8s; background: radial-gradient(70% 55% at 50% 55%, rgba(255,217,160,.12), rgba(22,4,10,.25)); }
.end.on { opacity: 1; visibility: visible; transition: opacity .8s var(--ease), visibility 0s; }
.end .end-card { transform: translateY(14px) scale(.98); transition: transform .9s var(--ease); }
.end.on .end-card { transform: none; }
.paper { position: relative; background: var(--paper); color: var(--ink); border-radius: 4px; isolation: isolate; box-shadow: 0 30px 70px -28px rgba(0,0,0,.75), 0 0 80px rgba(255,217,160,.18); }
.paper::before { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; background-image: var(--grain-dark); opacity: .5; pointer-events: none; }
.paper::after { content: ""; position: absolute; inset: 8px; border: 1px solid var(--gold-dark); outline: 1px solid color-mix(in srgb, var(--gold-dark) 50%, transparent); outline-offset: -5px; pointer-events: none; }
.end-card { width: min(100%, 420px); padding: 36px 26px 30px; text-align: center; }
.end-h { margin: 10px 0 4px; font: 400 clamp(44px, 13vw, 58px)/1.1 var(--font-script); color: var(--wine); }
.end-date { margin: 0; font: 500 21px/1.3 var(--font-display); color: var(--ink); }
.end-lunar { margin: 6px 0 0; font: italic 400 17px/1.4 var(--font-body); color: var(--ink-muted); }
.end-acts { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 24px; position: relative; z-index: 1; }
.end-acts .btn { padding: 0 10px; }
.end-acts .btn:first-child { grid-column: 1 / -1; min-height: 52px; font-weight: 600; }
.end-acts .btn:last-child { grid-column: 1 / -1; }

/* nút con dấu */
.seal-btn { position: fixed; z-index: 40; top: calc(12px + env(safe-area-inset-top)); right: calc(12px + env(safe-area-inset-right)); width: 52px; height: 52px; padding: 0; border: 0; border-radius: 50%; background: transparent; cursor: pointer; filter: drop-shadow(0 4px 8px rgba(0,0,0,.45)); transition: transform .2s; }
.seal-btn svg, .seal-btn img { width: 100%; height: 100%; overflow: visible; display: block; }
.seal-btn:hover { transform: rotate(-6deg) scale(1.04); }
.seal-btn:focus-visible { outline-offset: 2px; border-radius: 50%; }
#app[data-stage="env"] .seal-btn, #app[data-stage="card"] .seal-btn { display: none; }

/* bảng trượt */
html.locked, html.locked body { overflow: hidden; }
.sheet { position: fixed; inset: 0; z-index: 60; }
.sheet-back { position: absolute; inset: 0; background: rgba(16,3,7,.62); opacity: 0; transition: opacity .3s var(--ease); touch-action: none; }
.sheet-panel { position: absolute; left: 0; right: 0; bottom: 0; margin: 0 auto; width: 100%; max-width: 600px; max-height: calc(100% - 40px - env(safe-area-inset-top)); display: flex; flex-direction: column; background: var(--paper); color: var(--ink); border-radius: 18px 18px 0 0; box-shadow: 0 -20px 60px rgba(0,0,0,.45); transform: translateY(102%); transition: transform .34s var(--ease); outline: none; padding-bottom: env(safe-area-inset-bottom); }
.sheet.full .sheet-panel { height: calc(100% - 28px - env(safe-area-inset-top)); }
.sheet.on .sheet-back { opacity: 1; }
.sheet.on .sheet-panel { transform: none; }
.sheet-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 10px 8px 22px; border-bottom: 1px solid color-mix(in srgb, var(--gold-dark) 35%, transparent); }
.sheet-title { margin: 0; font: 500 20px/1.3 var(--font-display); color: var(--wine); }
.sheet-x { width: 46px; height: 46px; display: grid; place-items: center; border: 0; border-radius: 50%; background: transparent; color: var(--wine); cursor: pointer; }
.sheet-x:hover { background: color-mix(in srgb, var(--wine) 8%, transparent); }
.sheet-x svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.sheet-body { overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; padding: 20px 22px 28px; }
.sheet.full .sheet-body { padding: 12px 10px 24px; flex: 1; }
.sheet-p { margin: 0; font-size: 19px; line-height: 1.5; }
.sheet-note { margin: 14px 0 0; padding: 12px 14px; border-radius: 10px; background: color-mix(in srgb, var(--champ) 30%, transparent); font: 400 15.5px/1.5 var(--font-ui); color: var(--ink-muted); }

/* dự phòng */
.fallback { position: relative; z-index: 5; min-height: 100vh; padding: calc(80px + env(safe-area-inset-top)) 16px calc(48px + env(safe-area-inset-bottom)); background: var(--night); color: var(--cream); }
.fb-head { text-align: center; margin-bottom: 28px; }
.fb-head .kicker { color: var(--champ); font-family: var(--font-ui); font-size: 12.5px; }
.fb-names { margin: 8px 0 0; font: 400 clamp(38px, 10.5vw, 56px)/1.15 var(--font-script); color: var(--cream); text-wrap: balance; }
.fb-names .amp { font-size: .5em; color: var(--champ); }
.fb-list { list-style: none; margin: 0 auto; padding: 0; max-width: 440px; display: grid; gap: 40px; }
.fb-item img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 5; object-fit: cover; border-radius: 4px; margin-bottom: 14px; box-shadow: 0 20px 40px -20px rgba(0,0,0,.8); }
.fb-end { margin: 48px auto 0; }

/* ============ máy tính ============ */
@media (min-width: 900px) {
  .caption { left: calc(56px + env(safe-area-inset-left)); bottom: 72px; max-width: 34rem; }
  .cap-t { font-size: 25px; }
  .cap-k { font-size: 13px; }
  .scrim { height: 45%; background: linear-gradient(to top, rgba(22,4,10,.82), rgba(22,4,10,.4) 50%, transparent); }
  .vf-hud { font-size: 11.5px; }
  .vf-k { width: 30px; height: 30px; }
  .sheet-panel { bottom: 24px; border-radius: 18px; max-height: calc(100% - 48px); }
  .sheet.full .sheet-panel { height: calc(100% - 48px); }
  .seal-btn { top: 20px; right: 22px; width: 58px; height: 58px; }
}

@media (prefers-reduced-motion: reduce) {
  .sheet-panel, .sheet-back, .end, .end .end-card, .hint, .info-pop { transition: none !important; }
  .a1-bob, .a1-ring, .hint svg, .a1-hint span, .a1-hint span::before, .rv-grain, .rv-cam { animation: none !important; }
}
