/* 手机 3D 首页 + 带扫描引导的 AR 页。按手机竖屏设计；电脑上打开也能看。
   3D 首页照第二版的样子（用户 10-21 认可的两点：一进来加载状态很明确；放完快门从下面浮上来，一看就知道下一步），但一个字都不写：
   载入是作品缩略图 + 一条进度线，开演是圆环 + ▶，进 AR 是白色快门，手势提示只有手指动画。
   按快门不换页：AR 页是这一页里的隐藏层（iframe），开场时就在后台载好，按下去相机直接在这里打开。AR 页的扫描框、虚影、分享也不写字。 */
:root {
  --m3d-font: -apple-system, "PingFang SC", "HarmonyOS Sans SC", "MiSans", "Microsoft YaHei", system-ui, sans-serif;
  --m3d-ink: #fff;
  --m3d-glass: rgba(14, 16, 28, 0.42);
  --m3d-line: rgba(255, 255, 255, 0.16);
  --m3d-page: #05060d;
  --m3d-sub: rgba(255, 255, 255, 0.62);
  --m3d-shade: rgba(2, 3, 10, 0.86);
  --m3d-c1: #57e1ff;
  --m3d-c2: #9a6bff;
  --m3d-c3: #ff5fd2;
  --m3d-c4: #ffc35a;
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
}
html[data-m3d-theme="color"] { --m3d-shade: rgba(10, 6, 2, 0.8); }
html[data-m3d-theme="white"] { --m3d-ink: #12141c; --m3d-sub: rgba(18, 20, 28, 0.58); --m3d-glass: rgba(255, 255, 255, 0.6); --m3d-line: rgba(18, 20, 28, 0.12); --m3d-page: #eef0f4; --m3d-shade: rgba(244, 245, 248, 0.92); }
.m3d-page { margin: 0; height: 100%; overflow: hidden; background: var(--m3d-page); font-family: var(--m3d-font); color: var(--m3d-ink); -webkit-font-smoothing: antialiased; touch-action: none; -webkit-tap-highlight-color: transparent; user-select: none; -webkit-user-select: none; }
html:has(.m3d-page) { height: 100%; background: var(--m3d-page); }
.m3d-page * { box-sizing: border-box; }
.m3d-page button, .m3d-page a { font: inherit; color: inherit; -webkit-tap-highlight-color: transparent; }
#m3d-view { position: fixed; inset: 0; opacity: 0; transition: opacity 1.2s ease, transform 0.7s cubic-bezier(0.7, 0, 0.84, 0); }
#m3d-view canvas { display: block; width: 100%; height: 100%; touch-action: none; outline: none; }
.m3d-page:not([data-m3d="loading"]) #m3d-view { opacity: 1; }

/* 识别那一刻的柔光（模板自己会调 #flash） */
#flash { position: fixed; inset: 0; z-index: 16; pointer-events: none; opacity: 0; background: radial-gradient(circle at 50% 46%, rgba(255, 250, 236, 0.95), rgba(255, 206, 130, 0.6) 34%, rgba(240, 170, 80, 0) 70%); }
#flash.go { animation: m3d-flash 0.6s ease-out; }
@keyframes m3d-flash { 0% { opacity: 0 } 18% { opacity: 0.85 } 100% { opacity: 0 } }
.m3d-vignette { position: fixed; inset: 0; z-index: 2; pointer-events: none; background: radial-gradient(120% 90% at 50% 42%, transparent 55%, rgba(0, 0, 0, 0.5) 100%); }
html[data-m3d-theme="white"] .m3d-vignette { display: none; }
/* 放完：画面下方压暗一点，让快门立得住（不用卡片） */
.m3d-shade { position: fixed; left: 0; right: 0; bottom: 0; height: 40%; z-index: 3; pointer-events: none; background: linear-gradient(to bottom, transparent, var(--m3d-shade) 82%); opacity: 0; transition: opacity 1.2s ease; }
.m3d-intro-done .m3d-shade { opacity: 1; }

/* ---------- 进 AR：镜头飞回正上方，照片落到扫描框的位置、化成虚影；AR 页一打开就是同一个框，相机在框后面亮起来 ---------- */
.m3d-exit-ui { z-index: 39; }
.m3d-exit-ui::before { content: ""; position: fixed; inset: 0; background: #000; opacity: 0; transition: opacity 0.42s ease; }
.m3d-exit-ui .m3d-frame { transform: translate(-50%, -50%); transition: opacity 0.42s ease; }
.m3d-exit-ui .m3d-ghost { animation: none; opacity: 0.22; }
.m3d-exit-frame .m3d-exit-ui::before, .m3d-exit-frame .m3d-exit-ui .m3d-frame { opacity: 1; }
.m3d-page.m3d-exit-frame #m3d-view { opacity: 0; }
.m3d-exiting :is(.m3d-invite, .m3d-ar-chip, .m3d-again, .m3d-sound, .m3d-gesture, .m3d-shade) { opacity: 0 !important; pointer-events: none !important; transition: opacity 0.35s ease; }
/* AR 层（隐藏的 iframe，开场时就在后台载好、场景建好，只差开相机）：照片落进取景框后淡出来盖住整页，相机在框后面亮起来；按「‹」淡回 3D */
.m3d-arframe { position: fixed; inset: 0; width: 100%; height: 100%; border: 0; z-index: 41; opacity: 0; pointer-events: none; background: transparent; transition: opacity 0.35s ease; }
.m3d-ar-on .m3d-arframe { opacity: 1; pointer-events: auto; }
/* AR 层还没载完（网速慢、刚开场就按）：取景框轻轻呼吸着等，载完马上开相机（AR 层第一帧也是这样呼吸的框，接得上） */
.m3d-exit-ui .m3d-line { display: none; }
.m3d-ar-wait .m3d-exit-ui .m3d-frame { animation: m3d-frame-wait 2.4s ease-in-out infinite; }

/* ---------- 光球：几团彩色的光在玻璃球里慢慢流动，会呼吸 ---------- */
.m3d-orb { --s: 80px; position: relative; display: grid; place-items: center; width: var(--s); height: var(--s); border-radius: 50%; isolation: isolate; color: #fff; text-decoration: none; animation: m3d-breathe 3.4s ease-in-out infinite; }
.m3d-orb-sm { --s: 46px; }
.m3d-orb-lg { --s: 104px; }
.m3d-orb > .o1, .m3d-orb > .o2, .m3d-orb > .o3 { position: absolute; inset: -6%; border-radius: 50%; mix-blend-mode: screen; filter: blur(calc(var(--s) * 0.085)); }
.m3d-orb > .o1 { background: radial-gradient(circle at 32% 34%, var(--m3d-c1) 0, transparent 60%); animation: m3d-swirl 5.6s ease-in-out infinite; }
.m3d-orb > .o2 { background: radial-gradient(circle at 70% 42%, var(--m3d-c2) 0, transparent 60%); animation: m3d-swirl 7.2s ease-in-out infinite reverse; }
.m3d-orb > .o3 { background: radial-gradient(circle at 48% 74%, var(--m3d-c3) 0, transparent 56%), radial-gradient(circle at 34% 62%, var(--m3d-c4) 0, transparent 40%); animation: m3d-swirl 8.8s ease-in-out infinite; }
@keyframes m3d-swirl { 0% { transform: rotate(0deg) scale(1) } 33% { transform: rotate(130deg) scale(1.08) } 66% { transform: rotate(240deg) scale(0.96) } 100% { transform: rotate(360deg) scale(1) } }
/* 玻璃球：左上角的高光 + 一圈亮边 */
.m3d-orb > .core { position: absolute; inset: 12%; border-radius: 50%; background: radial-gradient(circle at 34% 26%, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.16) 30%, rgba(255, 255, 255, 0) 58%); box-shadow: inset 0 0 calc(var(--s) * 0.16) rgba(255, 255, 255, 0.4), 0 0 calc(var(--s) * 0.45) rgba(150, 120, 255, 0.5); }
.m3d-orb::after { content: ""; position: absolute; inset: -12%; border-radius: 50%; border: 1px solid rgba(255, 255, 255, 0.32); animation: m3d-ripple 2.8s ease-out infinite; }
@keyframes m3d-ripple { 0% { transform: scale(0.82); opacity: 0.85 } 100% { transform: scale(1.38); opacity: 0 } }
@keyframes m3d-breathe { 0%, 100% { transform: scale(1) } 50% { transform: scale(1.05) } }
.m3d-orb .glyph { position: relative; z-index: 1; width: 40%; height: 40%; filter: drop-shadow(0 1px 4px rgba(20, 10, 60, 0.55)); }
.m3d-orb-sm::after { display: none; }

/* ---------- 屏幕四周的流光边（AR 页：在找海报时亮着） ---------- */
.m3d-aura { position: fixed; inset: 0; z-index: 13; pointer-events: none; opacity: 0; transition: opacity 1.4s ease; }
.m3d-aura i { position: absolute; background-image: linear-gradient(90deg, var(--m3d-c1), var(--m3d-c2), var(--m3d-c3), var(--m3d-c4), var(--m3d-c1)); background-size: 300% 100%; animation: m3d-flow 7s linear infinite; transition: height 0.7s ease, width 0.7s ease; }
.m3d-aura .t { left: 0; right: 0; top: 0; height: 20px; -webkit-mask: linear-gradient(to bottom, #000, transparent); mask: linear-gradient(to bottom, #000, transparent); }
.m3d-aura .b { left: 0; right: 0; bottom: 0; height: 24px; -webkit-mask: linear-gradient(to top, #000, transparent); mask: linear-gradient(to top, #000, transparent); animation-direction: reverse; }
.m3d-aura .l, .m3d-aura .r { top: 0; bottom: 0; width: 12px; background-image: linear-gradient(180deg, var(--m3d-c1), var(--m3d-c2), var(--m3d-c3), var(--m3d-c4), var(--m3d-c1)); background-size: 100% 300%; animation-name: m3d-flow-v; }
.m3d-aura .l { left: 0; -webkit-mask: linear-gradient(to right, #000, transparent); mask: linear-gradient(to right, #000, transparent); }
.m3d-aura .r { right: 0; -webkit-mask: linear-gradient(to left, #000, transparent); mask: linear-gradient(to left, #000, transparent); animation-direction: reverse; }
@keyframes m3d-flow { to { background-position: 300% 0 } }
@keyframes m3d-flow-v { to { background-position: 0 300% } }

/* ---------- 载入（进场仪式）----------
   底色就是 3D 场景里那片藏青星空（同一套颜色：底下 #05060f、往上 #0e1129，紫、青两团星云，地平线一圈微光，星星在闪），
   进 3D 时颜色接得上（第八版是识别图虚化出来的红黄色，和深色场景前后不搭）。
   仪式：0.15 秒标志浮现（由虚到实、轻轻升起，后面一团柔光），1.3 秒起一道光沿着标志的笔画扫过（以后隔一会儿一次）；
   0.9 秒金线从中间往两边展开；1.1 秒识别图卡片升起来，下面一条和卡片同宽的进度线 */
.m3d-loading { --card-w: min(54vw, 250px, 33vh); position: fixed; inset: 0; z-index: 30; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 22px; overflow: hidden; transition: opacity 0.7s ease; }
.m3d-page:not([data-m3d="loading"]) .m3d-loading { opacity: 0; pointer-events: none; } /* 载完马上离开加载页，进到静止的 3D 画面等访客点 ▶ */
.m3d-sky { position: absolute; inset: 0; background:
  radial-gradient(60% 38% at 20% 26%, rgba(92, 64, 178, 0.22), transparent 70%),
  radial-gradient(52% 34% at 82% 64%, rgba(20, 102, 133, 0.2), transparent 70%),
  radial-gradient(130% 42% at 50% 60%, rgba(41, 48, 107, 0.3), transparent 72%),
  linear-gradient(to bottom, #0e1129 0%, #0a0c21 46%, #05060f 100%); }
.m3d-stars { position: absolute; inset: 0; background-image:
  radial-gradient(1px 1px at 12% 18%, #fff, transparent), radial-gradient(1px 1px at 33% 72%, #dfe6ff, transparent),
  radial-gradient(1.5px 1.5px at 58% 28%, #fff, transparent), radial-gradient(1px 1px at 76% 84%, #cfe2ff, transparent),
  radial-gradient(1px 1px at 88% 12%, #fff, transparent), radial-gradient(1.2px 1.2px at 45% 48%, #e8eeff, transparent),
  radial-gradient(1px 1px at 22% 92%, #fff, transparent), radial-gradient(1px 1px at 66% 58%, #fff, transparent);
  background-size: 220px 260px; opacity: 0.75; animation: m3d-twinkle 4.6s ease-in-out infinite; }
.m3d-stars-b { background-size: 310px 340px; background-position: 70px 40px; opacity: 0.5; animation-duration: 6.4s; animation-delay: -2.2s; }
@keyframes m3d-twinkle { 0%, 100% { opacity: 0.35 } 50% { opacity: 0.85 } }
html[data-m3d-theme="white"] .m3d-sky { background: linear-gradient(to bottom, #ffffff 0%, #f1f2f5 60%, #e2e4ea 100%); }
html[data-m3d-theme="white"] .m3d-stars { display: none; }
.m3d-mark { position: relative; z-index: 1; width: min(68vw, 320px); opacity: 0; }
.m3d-mark.m3d-ready { opacity: 1; animation: m3d-mark-in 1.2s cubic-bezier(0.2, 0.7, 0.2, 1) 0.15s both; } /* 标志图下载完才开始（网慢时不至于动画放完了图才冒出来） */
.m3d-mark::before { content: ""; position: absolute; inset: -60% -18%; z-index: -1; background: radial-gradient(closest-side, rgba(255, 226, 170, 0.22), rgba(140, 160, 255, 0.08) 55%, transparent); animation: m3d-glow 3.6s ease-in-out 1.2s infinite; }
.m3d-mark img { display: block; width: 100%; height: auto; }
.m3d-mark-light { display: none !important; }
html[data-m3d-theme="white"] .m3d-mark-dark { display: none !important; }
html[data-m3d-theme="white"] .m3d-mark-light { display: block !important; }
html[data-m3d-theme="white"] .m3d-mark-shine { display: none; }
.m3d-mark-shine { position: absolute; inset: 0; -webkit-mask-size: 100% 100%; mask-size: 100% 100%; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; background: linear-gradient(105deg, transparent 35%, rgba(255, 246, 214, 0.95) 48%, rgba(255, 255, 255, 0.4) 53%, transparent 64%) 0 0 / 300% 100% no-repeat; opacity: 0; }
.m3d-ready .m3d-mark-shine { opacity: 1; animation: m3d-mark-shine 4.6s ease-in-out 1.3s infinite; }
@keyframes m3d-mark-in { from { opacity: 0; transform: translateY(10px) scale(0.96); filter: blur(8px) } to { opacity: 1; transform: none; filter: none } }
@keyframes m3d-mark-shine { 0% { background-position: 100% 0 } 38%, 100% { background-position: 0 0 } }
@keyframes m3d-glow { 0%, 100% { opacity: 0.7 } 50% { opacity: 1 } }
.m3d-mark-line { position: relative; z-index: 1; display: block; width: min(40vw, 170px); height: 1px; margin: -8px 0 2px; background: linear-gradient(to right, transparent, rgba(232, 200, 132, 0.95), transparent); transform-origin: center; opacity: 0; }
.m3d-mark.m3d-ready + .m3d-mark-line { opacity: 1; animation: m3d-line-in 0.9s cubic-bezier(0.2, 0.7, 0.2, 1) 0.9s both; }
@keyframes m3d-line-in { from { transform: scaleX(0); opacity: 0 } to { transform: none; opacity: 1 } }
.m3d-loading-card { position: relative; z-index: 1; width: var(--card-w); border-radius: 0; overflow: hidden; box-shadow: 0 30px 70px -24px rgba(0, 0, 0, 0.85), 0 0 0 1px rgba(255, 255, 255, 0.14), 0 0 40px -10px rgba(150, 170, 255, 0.25); opacity: 0; }
.m3d-loading-card.m3d-ready { opacity: 1; animation: m3d-card-in 1s cubic-bezier(0.2, 0.7, 0.2, 1) 1.1s both, m3d-float 4.2s ease-in-out 2.1s infinite; } /* 识别图下载完才升起来 */
.m3d-mark:not(.m3d-ready) ~ .m3d-loading-card { opacity: 0 !important; animation: none !important; } /* 有标志时，卡片等标志先出来（顺序不乱） */
@keyframes m3d-card-in { from { opacity: 0; transform: translateY(26px) } to { opacity: 1; transform: none } }
.m3d-loading-poster { display: block; width: 100%; height: auto; }
.m3d-loading-shine { position: absolute; inset: -30% -60%; background: linear-gradient(105deg, transparent 38%, rgba(255, 255, 255, 0.3) 49%, rgba(255, 255, 255, 0.05) 54%, transparent 62%); transform: translateX(-60%); animation: m3d-shine 3.4s cubic-bezier(0.45, 0, 0.25, 1) 2.2s infinite; }
@keyframes m3d-shine { 0% { transform: translateX(-60%) } 55%, 100% { transform: translateX(60%) } }
.m3d-progress { position: relative; z-index: 1; width: var(--card-w); height: 2px; border-radius: 2px; background: rgba(255, 255, 255, 0.16); overflow: hidden; animation: m3d-in 1s ease 1.4s both; }
.m3d-progress i { display: block; height: 100%; width: calc(var(--p, 0.04) * 100%); border-radius: inherit; background: linear-gradient(to right, #e8c884, #fff4d8); box-shadow: 0 0 10px rgba(255, 230, 170, 0.7); transition: width 0.4s ease; }
html[data-m3d-theme="white"] .m3d-progress { background: rgba(18, 20, 28, 0.12); }
html[data-m3d-theme="white"] .m3d-progress i { background: var(--m3d-ink); box-shadow: none; }
@keyframes m3d-in { from { opacity: 0; transform: translateY(6px); filter: blur(4px) } to { opacity: 1; transform: none; filter: none } }
@keyframes m3d-float { 0%, 100% { transform: translateY(0) } 50% { transform: translateY(-5px) } }

/* ---------- 载完的 ▶：3D 画面静止，下面一个圆环 + ▶，点一下带声音开演（第二版还写着「轻触开启」「建议打开声音」，现在不写） ---------- */
.m3d-tap { position: fixed; left: calc(50% - 32px); bottom: calc(34px + var(--safe-b)); z-index: 20; display: none; border: 0; background: none; padding: 0; cursor: pointer; }
.m3d-page[data-m3d="tap"] .m3d-tap { display: block; animation: m3d-in 0.9s ease 0.5s both; } /* 加载页淡出、3D 画面出来以后再浮上来；位置就是放完以后 AR 按钮的位置 */
.m3d-tap-ring { position: relative; display: block; width: 64px; height: 64px; border-radius: 50%; border: 1px solid var(--m3d-line); background: var(--m3d-glass); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); }
html[data-m3d-theme="white"] .m3d-tap-ring { border-color: rgba(18, 20, 28, 0.75); }
.m3d-tap-ring::before { content: ""; position: absolute; left: 50%; top: 50%; margin: -8px 0 0 -4px; border-style: solid; border-width: 8px 0 8px 13px; border-color: transparent transparent transparent var(--m3d-ink); }
.m3d-tap-ring::after { content: ""; position: absolute; inset: -1.5px; border-radius: 50%; border: 1px solid var(--m3d-ink); animation: m3d-pulse 2s ease-out infinite; }
@keyframes m3d-pulse { 0% { transform: scale(1); opacity: 0.6 } 100% { transform: scale(1.55); opacity: 0 } }

/* ---------- 角落的小图标：声音（左上）；开场中途的 AR 入口（右上，取景框图形；第二版是写着「AR」的胶囊）、放完后的重播（右上） ---------- */
.m3d-icon { position: fixed; z-index: 20; top: calc(14px + var(--safe-t)); width: 36px; height: 36px; border-radius: 50%; border: 1px solid var(--m3d-line); background: var(--m3d-glass); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); display: grid; place-items: center; cursor: pointer; padding: 0; color: inherit; text-decoration: none; opacity: 0; pointer-events: none; transition: opacity 0.6s ease; }
.m3d-icon svg { width: 17px; height: 17px; }
.m3d-sound { left: 14px; }
.m3d-page:is([data-m3d="play"], [data-m3d="tap"]) .m3d-sound { opacity: 1; pointer-events: auto; } /* 全程背景音乐一直在：载完就能关 */
.m3d-icon .m3d-off { display: none; }
.m3d-silent .m3d-sound .m3d-on { display: none; }
.m3d-silent .m3d-sound .m3d-off { display: block; }
.m3d-silent .m3d-sound { opacity: 1; pointer-events: auto; animation: m3d-nudge 1.8s ease-in-out infinite; } /* 浏览器不让自动出声：画面照放，碰一下屏幕就有声音 */
@keyframes m3d-nudge { 0%, 100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0) } 50% { box-shadow: 0 0 0 6px rgba(255, 255, 255, 0.14) } }
.m3d-muted .m3d-icon .m3d-on { display: none; }
.m3d-muted .m3d-icon .m3d-off { display: block; }
.m3d-ar-chip, .m3d-again { right: 14px; }
.m3d-playing .m3d-ar-chip { opacity: 1; pointer-events: auto; transition-delay: 3s; }
.m3d-intro-done .m3d-ar-chip { opacity: 0; pointer-events: none; transition-delay: 0s; }
.m3d-intro-done .m3d-again { opacity: 1; pointer-events: auto; transition-delay: 1.6s; }

/* ---------- 手势：一根手指沿弧线来回划（可以转），碰一下屏幕就消失 ---------- */
.m3d-gesture { position: fixed; z-index: 12; left: calc(50% - 40px); bottom: calc(30px + var(--safe-b) + 112px); width: 80px; height: 64px; color: rgba(255, 255, 255, 0.88); pointer-events: none; opacity: 0; transform: translateY(6px); transition: opacity 0.7s ease, transform 0.7s ease; filter: drop-shadow(0 1px 8px rgba(0, 0, 0, 0.45)); }
html[data-m3d-theme="white"] .m3d-gesture { color: rgba(18, 20, 28, 0.7); filter: none; }
.m3d-gesture svg { width: 100%; height: 100%; }
.m3d-gesture .m3d-swipe { animation: m3d-swipe 2.4s ease-in-out infinite; }
.m3d-gesture .m3d-dot { fill: currentColor; stroke: none; opacity: 0.85; }
@keyframes m3d-swipe { 0%, 100% { transform: translateX(-16px) } 50% { transform: translateX(16px) } }
.m3d-hint-gesture .m3d-gesture { opacity: 1; transform: none; }

/* ---------- 放完：AR 按钮从下面浮上来（第二版的位置和浮上来的动作）----------
   10-21 定：所有控件统一成左上角声音按钮那种简约样子——磨砂深色圆钮、1px 细白边、线条图标。AR 按钮只是大一点（60px），
   图标是一个立体方块，外面一圈很淡的光慢慢散开（提示能点）。不要金边、高光、光泽这些。没浮上来之前点不到 */
.m3d-invite { position: fixed; z-index: 14; left: 0; right: 0; bottom: calc(36px + var(--safe-b)); display: flex; justify-content: center; pointer-events: none; opacity: 0; transform: translateY(18px); transition: opacity 1s ease, transform 1.2s cubic-bezier(0.16, 1, 0.3, 1); }
.m3d-intro-done .m3d-invite { opacity: 1; transform: none; }
.m3d-shutter { position: relative; width: 60px; height: 60px; border-radius: 50%; display: grid; place-items: center; pointer-events: none; color: var(--m3d-ink); border: 1px solid var(--m3d-line); background: var(--m3d-glass); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); -webkit-tap-highlight-color: transparent; transition: transform 0.18s ease; }
.m3d-intro-done .m3d-shutter { pointer-events: auto; }
.m3d-shutter::after { content: ""; position: absolute; inset: -1px; border-radius: 50%; border: 1px solid var(--m3d-line); animation: m3d-halo 2.8s ease-out infinite; }
@keyframes m3d-halo { 0% { transform: scale(1); opacity: 1 } 100% { transform: scale(1.5); opacity: 0 } }
.m3d-ar-glyph { width: 26px; height: 26px; }
.m3d-shutter:active, .m3d-exiting .m3d-shutter, .m3d-leaving .m3d-shutter { transform: scale(0.92); }

/* 退回老办法进 AR（包里没有海报预览图，不常见）：从快门的位置推开白光，画面往前一推，然后换页 */
.m3d-portal { position: fixed; inset: 0; z-index: 40; pointer-events: none; background: radial-gradient(circle at var(--px, 50%) var(--py, 88%), #fff 0, rgba(255, 255, 255, 0.85) 18%, #000 60%); clip-path: circle(0 at var(--px, 50%) var(--py, 88%)); transition: clip-path 0.7s cubic-bezier(0.7, 0, 0.3, 1); }
.m3d-leaving .m3d-portal { clip-path: circle(160% at var(--px, 50%) var(--py, 88%)); }
.m3d-leaving #m3d-view { transform: scale(1.16); } /* 不加滤镜：全屏画布上的模糊在低端手机上会掉帧 */

/* 出错（这里必须有字） */
.m3d-error { position: fixed; inset: 0; z-index: 50; display: none; flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 28px; text-align: center; background: #05060d; color: #fff; }
.m3d-page[data-m3d="error"] .m3d-error { display: flex; }
.m3d-error h3 { margin: 0; font-size: 17px; font-weight: 500; letter-spacing: 0.06em; }
.m3d-error p { margin: 0; max-width: 520px; font-size: 13px; line-height: 1.6; color: rgba(255, 255, 255, 0.66); overflow-wrap: anywhere; }
.m3d-error a { margin-top: 8px; padding: 11px 22px; border-radius: 999px; border: 1px solid rgba(255, 255, 255, 0.5); color: #fff; font-size: 13px; letter-spacing: 0.16em; text-decoration: none; }

/* ---------- AR 页：扫描引导（覆盖在原版 AR 画面上；电脑上的桌面预览不出现）。也不写字 ---------- */
.m3d-scan-ui { position: fixed; inset: 0; z-index: 30; pointer-events: none; font-family: var(--m3d-font); color: #fff; }
.m3d-scan-ui > * { transition: opacity 0.5s ease, transform 0.6s cubic-bezier(0.16, 1, 0.3, 1); }
body[data-scan="off"] .m3d-scan-ui, body[data-scan="off"] .m3d-aura { display: none; }
/* 进来时黑场里一个光球在呼吸；相机出画面后，黑场从中间像光圈一样打开 */
.m3d-scan-ui > .m3d-iris { position: fixed; inset: 0; background: #000; clip-path: circle(150% at 50% 44%); transition: clip-path 0.9s cubic-bezier(0.6, 0, 0.2, 1); }
.m3d-iris-open .m3d-scan-ui > .m3d-iris { clip-path: circle(0% at 50% 44%); }
.m3d-cam { position: fixed; left: calc(50% - 40px); top: calc(44% - 40px); opacity: 0; }
body[data-scan="camera"] .m3d-cam, body:not([data-scan]) .m3d-cam { opacity: 1; }
.m3d-frame { position: fixed; left: 50%; top: 44%; width: min(64vw, 290px); aspect-ratio: var(--m3d-aspect, 2 / 3); transform: translate(-50%, -50%) scale(1.06); opacity: 0; }
.m3d-frame i { position: absolute; width: 28px; height: 28px; border: 2.5px solid #fff; border-radius: 3px; filter: drop-shadow(0 0 6px rgba(170, 160, 255, 0.9)); }
.m3d-frame i:nth-of-type(1) { left: 0; top: 0; border-right: 0; border-bottom: 0; }
.m3d-frame i:nth-of-type(2) { right: 0; top: 0; border-left: 0; border-bottom: 0; }
.m3d-frame i:nth-of-type(3) { left: 0; bottom: 0; border-right: 0; border-top: 0; }
.m3d-frame i:nth-of-type(4) { right: 0; bottom: 0; border-left: 0; border-top: 0; }
/* 海报虚影：要对准的是哪一张，一眼就知道 */
.m3d-ghost { position: absolute; inset: 7%; width: 86%; height: 86%; object-fit: cover; border-radius: 3px; opacity: 0.2; filter: saturate(0.6); animation: m3d-ghost 2.6s ease-in-out infinite; }
@keyframes m3d-ghost { 0%, 100% { opacity: 0.12 } 50% { opacity: 0.28 } }
.m3d-frame .m3d-line { position: absolute; left: 5%; right: 5%; height: 2px; top: 0; border-radius: 2px; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.95), transparent); box-shadow: 0 0 12px 2px rgba(200, 214, 255, 0.55); animation: m3d-scanline 2.4s ease-in-out infinite; }
@keyframes m3d-scanline { 0% { top: 6%; opacity: 0 } 15% { opacity: 1 } 85% { opacity: 1 } 100% { top: 94%; opacity: 0 } }
body[data-scan="scan"] .m3d-frame { opacity: 1; transform: translate(-50%, -50%) scale(1); }
body[data-scan="lost"] .m3d-frame { opacity: 0.7; transform: translate(-50%, -50%) scale(1); }
body[data-scan="lost"] .m3d-ghost { display: none; }
body[data-scan="found"] .m3d-frame { opacity: 0; transform: translate(-50%, -50%) scale(1.18); }
/* 流光边：找海报时亮着，认出来那一下闪亮后退掉 */
body[data-scan="scan"] .m3d-aura, body[data-scan="lost"] .m3d-aura { opacity: 0.55; }
body.m3d-found-flash .m3d-aura { animation: m3d-aura-hit 1.3s ease-out; }
@keyframes m3d-aura-hit { 0% { opacity: 1 } 100% { opacity: 0 } }
.m3d-back { pointer-events: auto; position: fixed; z-index: 31; top: calc(14px + var(--safe-t)); left: 14px; width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center; background: var(--m3d-glass); border: 1px solid var(--m3d-line); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); color: #fff; }
.m3d-back svg { width: 18px; height: 18px; }
#error .m3d-back-big { pointer-events: auto; margin-top: 6px; padding: 11px 22px; border-radius: 999px; border: 1px solid rgba(255, 255, 255, 0.5); color: #fff; font-size: 13px; letter-spacing: 0.16em; text-decoration: none; }

/* AR 页一打开：和 3D 页最后一帧同一个框 + 虚影（照片化成的），等相机的时候框轻轻呼吸；相机出画面后光圈从框后面打开 */
body:not([data-scan]) .m3d-has-ghost .m3d-frame, body[data-scan="camera"] .m3d-has-ghost .m3d-frame { opacity: 1; transform: translate(-50%, -50%); animation: m3d-frame-wait 2.4s ease-in-out infinite; }
body:not([data-scan]) .m3d-has-ghost .m3d-ghost, body[data-scan="camera"] .m3d-has-ghost .m3d-ghost { animation: none; opacity: 0.22; }
body:not([data-scan]) .m3d-has-ghost .m3d-line, body[data-scan="camera"] .m3d-has-ghost .m3d-line { display: none; }
body:not([data-scan]) .m3d-has-ghost .m3d-cam, body[data-scan="camera"] .m3d-has-ghost .m3d-cam { opacity: 0; }
@keyframes m3d-frame-wait { 0%, 100% { transform: translate(-50%, -50%) scale(1) } 50% { transform: translate(-50%, -50%) scale(1.015) } }
body[data-scan="scan"] .m3d-has-ghost .m3d-ghost { animation-delay: -0.8s; } /* 从 0.22 附近接着呼吸，不跳 */

/* ---------- 分享：右下角的相机（3D 页）、底部快门（AR 页）、拍照闪白、分享面板 ---------- */
.m3d-cap { position: fixed; z-index: 15; right: 24px; bottom: calc(36px + 30px - 22px + var(--safe-b)); width: 44px; height: 44px; border-radius: 50%; padding: 0; color: var(--m3d-ink); display: grid; place-items: center; cursor: pointer; border: 1px solid var(--m3d-line); background: var(--m3d-glass); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); opacity: 0; pointer-events: none; translate: 0 14px; transition: opacity 0.9s ease 0.5s, translate 1.1s cubic-bezier(0.16, 1, 0.3, 1) 0.5s, transform 0.18s ease; touch-action: none; -webkit-tap-highlight-color: transparent; }
.m3d-exiting .m3d-cap { opacity: 0 !important; pointer-events: none !important; }
.m3d-cap > svg:first-child { width: 19px; height: 19px; }
.m3d-intro-done .m3d-cap { opacity: 1; pointer-events: auto; translate: 0 0; } /* 浮上来用 translate，按下去的缩放用 transform，互不干扰 */
.m3d-cap.m3d-pressing { transform: scale(0.9); }
/* 录像：按钮外面一圈彩色进度，按钮变红点 */
.m3d-cap-ring { position: absolute; inset: -5px; width: calc(100% + 10px); height: calc(100% + 10px); transform: rotate(-90deg); fill: none; opacity: 0; pointer-events: none; }
.m3d-cap-ring circle { stroke: #ff4d6d; stroke-width: 3; stroke-linecap: round; stroke-dasharray: 100; stroke-dashoffset: calc(100 - var(--rec, 0) * 100); }
.m3d-recording .m3d-cap-ring { opacity: 1; }
.m3d-cap.m3d-recording { background: rgba(255, 77, 109, 0.28); }
.m3d-shutter-ar { position: fixed; z-index: 32; left: calc(50% - 36px); bottom: calc(30px + var(--safe-b)); width: 72px; height: 72px; border-radius: 50%; border: 4px solid #fff; background: transparent; padding: 0; display: grid; place-items: center; cursor: pointer; opacity: 0; pointer-events: none; transition: opacity 0.6s ease; touch-action: none; -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent; box-shadow: 0 2px 14px rgba(0, 0, 0, 0.32), inset 0 0 6px rgba(0, 0, 0, 0.12); }
/* 手机相机常见的白色快门（10-21 夜）：白色外圈 + 白色实心圆芯，按下去圆芯缩一点；只拍照，不录像 */
.m3d-shutter-disc { width: 54px; height: 54px; border-radius: 50%; background: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.18); transition: transform 0.15s ease; }
.m3d-shutter-ar.m3d-pressing .m3d-shutter-disc { transform: scale(0.86); }
body.m3d-can-shoot .m3d-shutter-ar { opacity: 1; pointer-events: auto; }
.m3d-snapflash { position: fixed; inset: 0; z-index: 45; pointer-events: none; background: #fff; opacity: 0; }
.m3d-snap .m3d-snapflash { animation: m3d-snap 0.45s ease-out; }
@keyframes m3d-snap { 0% { opacity: 0.85 } 100% { opacity: 0 } }
/* 分享面板（10-21 渔船：圆角和背后的毛玻璃虚化都不要，整个页面没有圆角，糊糊的不好看）：海报直角、背后是干净的深色压暗，不虚化 */
.m3d-share { position: fixed; inset: 0; z-index: 60; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 22px; padding: calc(28px + var(--safe-t)) 24px calc(28px + var(--safe-b)); background: rgba(3, 4, 10, 0.9); opacity: 0; transition: opacity 0.35s ease; pointer-events: none; }
/* 关掉后淡出的那 0.4 秒里不再挡点按（不然紧接着按快门会被它吃掉） */
.m3d-share.show { opacity: 1; pointer-events: auto; }
.m3d-share-stage { position: relative; max-width: min(78vw, 420px); max-height: 72vh; transform: translateY(10px) scale(0.97); transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1); }
.m3d-share.show .m3d-share-stage { transform: none; }
.m3d-share-stage img, .m3d-share-stage video { display: block; max-width: 100%; max-height: 72vh; border-radius: 0; box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.8), 0 0 0 1px rgba(255, 255, 255, 0.12); -webkit-touch-callout: default; user-select: auto; -webkit-user-select: auto; }
/* 微信里：一根手指在海报上「按住」，圈一圈圈扩散——长按保存 / 转发 / 识别二维码 */
.m3d-press { position: absolute; left: 50%; top: 50%; width: 72px; height: 72px; margin: -36px 0 0 -36px; color: #fff; pointer-events: none; filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.6)); animation: m3d-press-out 0.6s ease 3.2s forwards; }
.m3d-press svg { width: 100%; height: 100%; }
.m3d-press .m3d-press-ring { transform-origin: 32px 22px; animation: m3d-press 1.4s ease-out infinite; }
@keyframes m3d-press { 0% { transform: scale(0.4); opacity: 1 } 100% { transform: scale(1.5); opacity: 0 } }
@keyframes m3d-press-out { to { opacity: 0 } }
.m3d-share-bar { display: flex; gap: 18px; }
.m3d-share-btn { width: 48px; height: 48px; border-radius: 50%; border: 1px solid var(--m3d-line); background: var(--m3d-glass); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); color: #fff; display: grid; place-items: center; padding: 0; cursor: pointer; text-decoration: none; }
.m3d-share-btn svg { width: 22px; height: 22px; }
