/* =========================================================
   PARTICLE COSMOS · 手势粒子宇宙
   页面外壳样式（WebGL 画面在 canvas 上，纯手写，无依赖）
   ========================================================= */

*{margin:0;padding:0;box-sizing:border-box}

html,body{
  height:100%;
  overflow:hidden;
  background:#03050d;
  color:#e9f1ff;
  font-family:"PingFang SC","HarmonyOS Sans SC","Hiragino Sans GB","Microsoft YaHei",system-ui,-apple-system,sans-serif;
  -webkit-font-smoothing:antialiased;
  -webkit-tap-highlight-color:transparent;
}

#scene{
  position:fixed;
  inset:0;
  display:block;
  width:100%;
  height:100%;
  cursor:grab;
  touch-action:none;
}
#scene.dragging{cursor:grabbing}
/* 显卡上下文丢失时画布会变成白纸，先藏起来，露出深色底 */
body.gl-lost #scene{opacity:0}

/* ---------- 手部指针 ---------- */
/* 只改 opacity / transform，不碰 layout；两只手的环用不同色调，一眼分得清 */
.hand-layer{
  position:fixed;
  inset:0;
  z-index:3;
  pointer-events:none;
  overflow:hidden;
}
.hand-ring{
  position:absolute;
  left:0;top:0;
  width:74px;height:74px;
  margin:-37px 0 0 -37px;
  border-radius:50%;
  opacity:0;
  will-change:transform;
  transition:opacity .22s ease;
  background:radial-gradient(circle, rgba(127,230,255,.20) 0%, rgba(127,230,255,.06) 46%, rgba(127,230,255,0) 72%);
  box-shadow:
    inset 0 0 0 1px rgba(158,238,255,.62),
    0 0 26px -4px rgba(110,215,255,.55);
}
.hand-ring::after{
  content:"";
  position:absolute;
  left:50%;top:50%;
  width:5px;height:5px;
  margin:-2.5px 0 0 -2.5px;
  border-radius:50%;
  background:#d9f6ff;
  box-shadow:0 0 10px 1px rgba(150,236,255,.9);
}
.hand-ring.is-b{
  box-shadow:
    inset 0 0 0 1px rgba(198,186,255,.6),
    0 0 26px -4px rgba(160,146,255,.5);
  background:radial-gradient(circle, rgba(184,168,255,.2) 0%, rgba(184,168,255,.06) 46%, rgba(184,168,255,0) 72%);
}
.hand-ring.is-b::after{background:#ece7ff;box-shadow:0 0 10px 1px rgba(198,186,255,.9)}

@media (prefers-reduced-motion:reduce){
  .hand-ring{transition:none}
}

/* 暗角，把注意力压到中间 */
.vignette{
  position:fixed;
  inset:0;
  pointer-events:none;
  z-index:2;
  background:
    radial-gradient(120% 90% at 50% 50%, transparent 42%, rgba(2,4,10,.55) 100%),
    linear-gradient(180deg, rgba(2,4,10,.55), transparent 22%, transparent 78%, rgba(2,4,10,.6));
}

/* ---------- HUD ---------- */
.hud{
  position:fixed;
  z-index:6;
  pointer-events:none;
  opacity:1;
  transition:opacity .45s cubic-bezier(.4,0,.2,1), transform .45s cubic-bezier(.4,0,.2,1);
}
body.hud-off .hud,
body.hud-off .cam-panel,
body.hud-off .gesture-cta,
body.hud-off .switcher{opacity:0;pointer-events:none}
/* 隐藏界面时把手部指针一起收掉，留一块干净的画面 */
body.hud-off .hand-layer{opacity:0}

.hud-top{
  top:0;left:0;right:0;
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
  gap:20px;
  padding:clamp(16px,2.4vw,30px) clamp(16px,2.6vw,34px);
}

.brand{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.brand .dot{
  width:6px;height:6px;border-radius:50%;
  background:#7fe6ff;
  box-shadow:0 0 12px rgba(127,230,255,.95);
  animation:blink 2.6s ease-in-out infinite;
}
@keyframes blink{0%,100%{opacity:.35;transform:scale(.9)}50%{opacity:1;transform:scale(1.15)}}
.brand .title{
  font-size:12.5px;
  letter-spacing:.28em;
  font-weight:600;
  color:rgba(238,246,255,.95);
}
.brand .sub{
  font-size:10.5px;
  letter-spacing:.2em;
  color:rgba(150,200,255,.55);
  padding-left:10px;
  border-left:1px solid rgba(150,190,255,.18);
}

.hints{
  display:flex;
  flex-wrap:wrap;
  gap:6px;
  justify-content:flex-end;
  max-width:min(560px,58vw);
}
.hint{
  display:inline-flex;
  align-items:center;
  gap:6px;
  padding:5px 11px;
  font-size:11px;
  letter-spacing:.02em;
  color:rgba(214,232,255,.62);
  background:rgba(12,20,38,.42);
  border:1px solid rgba(150,190,255,.13);
  border-radius:999px;
  backdrop-filter:blur(12px);
  -webkit-backdrop-filter:blur(12px);
}
.hint b{color:rgba(238,246,255,.9);font-weight:500}

/* ---------- 场景切换 ---------- */
.switcher{
  position:fixed;
  z-index:7;
  left:50%;
  bottom:clamp(16px,2.6vw,30px);
  transform:translateX(-50%);
  display:flex;
  gap:6px;
  padding:6px;
  border-radius:999px;
  background:rgba(10,16,32,.5);
  border:1px solid rgba(150,190,255,.14);
  backdrop-filter:blur(18px) saturate(140%);
  -webkit-backdrop-filter:blur(18px) saturate(140%);
  box-shadow:0 20px 50px -30px rgba(0,0,0,.95), inset 0 1px 0 rgba(255,255,255,.08);
  transition:opacity .45s;
}
.sw-btn{
  appearance:none;
  border:0;
  cursor:pointer;
  padding:8px 16px;
  border-radius:999px;
  background:transparent;
  color:rgba(214,232,255,.55);
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:1px;
  transition:background-color .3s, color .3s, box-shadow .3s;
  font-family:inherit;
}
.sw-btn:hover{color:rgba(238,246,255,.95);background:rgba(127,182,255,.10)}
.sw-btn .sw-name{font-size:12.5px;letter-spacing:.04em}
.sw-btn .sw-en{font-size:8.5px;letter-spacing:.22em;opacity:.6;text-transform:uppercase}
.sw-btn.is-active{
  color:#08111f;
  background:linear-gradient(135deg,#cfe6ff,#8ec2ff 55%,#a9a2ff);
  box-shadow:0 10px 26px -12px rgba(127,182,255,.85);
}
.sw-btn.is-active .sw-en{opacity:.75}

.tip{
  position:fixed;
  z-index:6;
  left:50%;
  bottom:clamp(96px,10.5vw,118px);
  transform:translateX(-50%);
  font-size:11px;
  letter-spacing:.04em;
  color:rgba(180,205,235,.42);
  white-space:nowrap;
  pointer-events:none;
  transition:opacity .4s;
}

/* ---------- 手势入口 ---------- */
.gesture-cta{
  position:fixed;
  z-index:7;
  left:50%;
  bottom:clamp(96px,10.5vw,118px);
  transform:translateX(-50%);
  display:flex;
  align-items:center;
  gap:10px;
  padding:8px 13px 8px 10px;
  cursor:pointer;
  font-family:inherit;
  color:inherit;
  border-radius:999px;
  background:rgba(11,18,36,.62);
  border:1px solid rgba(160,212,255,.34);
  backdrop-filter:blur(16px) saturate(140%);
  -webkit-backdrop-filter:blur(16px) saturate(140%);
  box-shadow:0 20px 50px -30px rgba(0,0,0,.95), inset 0 1px 0 rgba(255,255,255,.08);
  transition:opacity .45s, transform .45s, background-color .3s, border-color .3s;
}
.gesture-cta::after{
  content:"";
  position:absolute;
  inset:-1px;
  border-radius:999px;
  pointer-events:none;
  box-shadow:0 0 0 0 rgba(127,205,255,.34);
  animation:ctaPulse 3.6s ease-in-out infinite;
}
@keyframes ctaPulse{
  0%,100%{box-shadow:0 0 0 0 rgba(127,205,255,.28)}
  55%{box-shadow:0 0 0 9px rgba(127,205,255,0)}
}
.gesture-cta:hover{background:rgba(20,32,58,.74);border-color:rgba(170,218,255,.5);transform:translateX(-50%) translateY(-1px)}
.gesture-cta:active{transform:translateX(-50%) scale(.985)}
.gesture-cta:focus-visible{outline:1px solid rgba(170,220,255,.7);outline-offset:3px}
.gesture-cta__icon{
  flex:0 0 auto;
  display:grid;
  place-items:center;
  width:30px;height:30px;
  border-radius:50%;
  color:#c6e9ff;
  background:linear-gradient(145deg,rgba(127,230,255,.24),rgba(142,194,255,.1));
  border:1px solid rgba(160,215,255,.26);
}
.gesture-cta__text{display:flex;flex-direction:column;align-items:flex-start;gap:2px;line-height:1.2}
.gesture-cta__text b{font-size:13px;font-weight:600;letter-spacing:.05em;color:rgba(242,248,255,.98)}
.gesture-cta__text i{font-style:normal;font-size:10px;letter-spacing:.03em;color:rgba(178,203,236,.62)}
.gesture-cta__key{
  flex:0 0 auto;
  margin-left:2px;
  padding:1px 6px;
  border-radius:6px;
  font-family:ui-monospace,Menlo,Consolas,monospace;
  font-size:9.5px;
  color:rgba(190,214,245,.55);
  border:1px solid rgba(150,190,255,.22);
}
/* 手势一开就把入口收起来，把位置还给提示文案 */
body.gesture-on .gesture-cta{opacity:0;transform:translateX(-50%) translateY(8px);pointer-events:none}
body.gesture-on .tip{opacity:1}
body:not(.gesture-on) .tip{opacity:0}

kbd{
  display:inline-block;
  min-width:17px;
  padding:0 4px;
  font-family:ui-monospace,Menlo,Consolas,monospace;
  font-size:10px;
  line-height:1.6;
  text-align:center;
  color:rgba(226,238,255,.8);
  background:rgba(255,255,255,.07);
  border:1px solid rgba(150,190,255,.2);
  border-bottom-width:2px;
  border-radius:4px;
}

/* ---------- 摄像头面板 ---------- */
.cam-panel{
  position:fixed;
  z-index:8;
  right:clamp(14px,2.4vw,30px);
  bottom:clamp(14px,2.4vw,30px);
  width:186px;
  display:flex;
  flex-direction:column;
  gap:8px;
  padding:10px;
  border-radius:14px;
  background:rgba(10,16,32,.5);
  border:1px solid rgba(150,190,255,.14);
  backdrop-filter:blur(18px);
  -webkit-backdrop-filter:blur(18px);
  box-shadow:0 24px 60px -34px rgba(0,0,0,.95), inset 0 1px 0 rgba(255,255,255,.07);
  transition:opacity .45s, transform .45s;
}
body.hud-off .cam-panel{transform:translateY(10px)}

.cam-frame{
  position:relative;
  width:100%;
  aspect-ratio:4/3;
  border-radius:9px;
  overflow:hidden;
  background:#070b16;
  border:1px solid rgba(150,190,255,.12);
}
.cam-frame video{
  width:100%;height:100%;
  object-fit:cover;
  transform:scaleX(-1);
  opacity:0;
  transition:opacity .5s;
}
.cam-frame.on video{opacity:.55}
.cam-frame canvas{
  position:absolute;
  inset:0;
  width:100%;height:100%;
}
.cam-frame::after{
  content:"CAMERA OFF";
  position:absolute;
  inset:0;
  display:grid;
  place-items:center;
  font-size:8.5px;
  letter-spacing:.26em;
  color:rgba(150,190,255,.32);
  transition:opacity .4s;
}
.cam-frame.on::after{opacity:0}
.cam-scan{
  position:absolute;
  left:0;right:0;
  height:22%;
  top:-22%;
  background:linear-gradient(180deg, transparent, rgba(127,230,255,.16), transparent);
  opacity:0;
  transition:opacity .4s;
}
.cam-frame.on .cam-scan{opacity:1;animation:scan 3.4s linear infinite}
@keyframes scan{
  0%{top:-22%}
  100%{top:100%}
}

.cam-meta{display:flex;flex-direction:column;gap:5px}
.cam-status{
  font-size:10.5px;
  line-height:1.45;
  letter-spacing:.06em;
  color:rgba(160,200,255,.72);
  overflow-wrap:break-word;
}
.cam-status.ok{color:#7ef0c0}
.cam-status.err{color:#ff9aa2}
.cam-gesture{
  font-size:16px;
  font-weight:600;
  letter-spacing:.06em;
  color:rgba(238,246,255,.95);
  line-height:1.2;
}
.form-meter{display:flex;align-items:center;gap:6px;font-size:9.5px;color:rgba(160,200,255,.5)}
.fm-track{
  flex:1;
  height:3px;
  border-radius:99px;
  background:rgba(150,190,255,.14);
  overflow:hidden;
}
.fm-track i{
  display:block;
  height:100%;
  width:0;
  border-radius:99px;
  background:linear-gradient(90deg,#6fe6ff,#8ec2ff);
  transition:width .16s linear;
}

/* 指数字提示：1/2/3 指对应三个场景，看得出来“现在能被手势召唤的是哪个” */
.cam-fingers{
  display:flex;
  gap:4px;
  opacity:0;
  transition:opacity .35s;
}
body.gesture-on .cam-fingers{opacity:1}
.cam-fingers span{
  display:grid;
  place-items:center;
  width:17px;height:17px;
  border-radius:5px;
  font-family:ui-monospace,Menlo,Consolas,monospace;
  font-size:9.5px;
  color:rgba(170,200,235,.5);
  background:rgba(150,190,255,.07);
  border:1px solid rgba(150,190,255,.14);
  transition:color .2s, background-color .2s, border-color .2s, box-shadow .2s;
}
.cam-fingers span.is-on{
  color:#08111f;
  background:linear-gradient(135deg,#ffe1b0,#ffc078);
  border-color:rgba(255,210,150,.7);
  box-shadow:0 0 14px -4px rgba(255,196,120,.9);
}

/* 开了手势却迟迟没看到手：把“手该怎么放”直接写在面板里 */
.cam-nudge{
  margin:0;
  max-height:0;
  overflow:hidden;
  opacity:0;
  font-size:9.5px;
  line-height:1.5;
  letter-spacing:.02em;
  color:rgba(255,214,160,.92);
  transition:opacity .35s, max-height .35s, margin-top .35s;
}
.cam-nudge.is-on{opacity:1;max-height:44px;margin-top:1px}

.cam-btn{
  appearance:none;
  cursor:pointer;
  padding:8px 10px;
  font-family:inherit;
  font-size:11.5px;
  letter-spacing:.03em;
  color:rgba(226,238,255,.9);
  background:rgba(127,182,255,.12);
  border:1px solid rgba(150,190,255,.22);
  border-radius:8px;
  transition:background-color .25s, border-color .25s, transform .25s;
}
.cam-btn:hover{background:rgba(127,182,255,.22);border-color:rgba(150,190,255,.4)}
.cam-btn:active{transform:scale(.97)}
/* 还没开过手势时轻微呼吸，提示“这里可以点” */
.cam-btn.is-idle{
  animation:camPulse 3.6s ease-in-out infinite;
  border-color:rgba(150,200,255,.4);
}
@keyframes camPulse{
  0%,100%{box-shadow:0 0 0 0 rgba(127,182,255,.0)}
  50%{box-shadow:0 0 0 4px rgba(127,182,255,.14)}
}
@media (prefers-reduced-motion:reduce){
  .cam-btn.is-idle{animation:none}
}

/* 内嵌预览被策略挡住时的替代入口 */
/* 独立浮层：不放在 .cam-panel 里，否则祖先的 backdrop-filter 会锁住 fixed 定位 */
.cam-help{
  position:fixed;
  left:50%;
  bottom:104px;
  z-index:14;
  display:flex;
  flex-direction:column;
  gap:7px;
  width:min(320px, calc(100vw - 28px));
  padding:12px 13px;
  border-radius:12px;
  background:rgba(28,13,22,.95);
  border:1px solid rgba(255,150,170,.28);
  box-shadow:0 26px 64px -30px rgba(0,0,0,.95), inset 0 1px 0 rgba(255,255,255,.05);
  opacity:0;
  transform:translate(-50%, 14px);
  pointer-events:none;
  transition:opacity .3s ease, transform .3s cubic-bezier(.22,.61,.36,1);
}
.cam-help.is-on{opacity:1;transform:translate(-50%,0);pointer-events:auto}
@media (prefers-reduced-motion:reduce){.cam-help{transition:none}}
.cam-help__note{
  margin:0;
  font-size:11px;
  line-height:1.5;
  font-weight:600;
  letter-spacing:.02em;
  color:rgba(255,198,206,.95);
}
.cam-help__sub{
  margin:-2px 0 0;
  font-size:9.5px;
  line-height:1.6;
  letter-spacing:.02em;
  color:rgba(212,224,246,.56);
}
.cam-help__open{
  padding:8px 8px;
  border-radius:7px;
  text-align:center;
  font-size:11.5px;
  font-weight:600;
  letter-spacing:.03em;
  color:#0a1020;
  background:linear-gradient(100deg,#a9e4ff,#c8b6ff);
  text-decoration:none;
  transition:filter .2s, transform .2s, opacity .25s;
}
.cam-help__open[hidden]{display:none}
.cam-help__open:hover{filter:brightness(1.08)}
.cam-help__open:active{transform:scale(.97)}
.cam-help__open.is-dim{opacity:.32;pointer-events:none}
.cam-help__row{
  display:flex;
  gap:5px;
}
.cam-help__mini{
  appearance:none;
  cursor:pointer;
  flex:1 1 0;
  min-width:0;
  padding:5px 6px;
  font-family:inherit;
  font-size:10px;
  letter-spacing:.02em;
  white-space:nowrap;
  color:rgba(226,238,255,.86);
  background:rgba(127,182,255,.14);
  border:1px solid rgba(150,190,255,.22);
  border-radius:6px;
  transition:background-color .2s, color .2s, border-color .2s, opacity .2s;
}
.cam-help__mini:hover{background:rgba(127,182,255,.24)}
.cam-help__mini.done{color:#7ef0c0;border-color:rgba(126,240,192,.42)}
.cam-help__mini[hidden]{display:none}
.cam-help__mini:disabled{opacity:.5;cursor:default}
.cam-help__retry{
  color:#ffd9a8;
  border-color:rgba(255,205,150,.32);
  background:rgba(255,180,110,.12);
}
.cam-help__retry:hover{background:rgba(255,180,110,.22)}
.cam-help__hint{
  margin:0;
  font-size:9.5px;
  line-height:1.55;
  letter-spacing:.02em;
  color:rgba(180,206,240,.62);
}

/* ---------- 载入 ---------- */
.loader{
  position:fixed;
  inset:0;
  z-index:20;
  display:flex;
  align-items:center;
  justify-content:center;
  gap:12px;
  background:#03050d;
  color:rgba(200,220,245,.65);
  font-size:12px;
  letter-spacing:.14em;
  transition:opacity .6s cubic-bezier(.4,0,.2,1);
}
.loader.done{opacity:0;pointer-events:none}
.spin{
  width:18px;height:18px;
  border-radius:50%;
  border:1.5px solid rgba(150,190,255,.22);
  border-top-color:#7fe6ff;
  animation:spin .9s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg)}}

/* ---------- 提示条 ---------- */
.toast{
  position:fixed;
  left:50%;
  top:76px;
  transform:translate(-50%,-8px);
  z-index:30;
  padding:9px 16px;
  font-size:12px;
  letter-spacing:.03em;
  color:rgba(238,246,255,.94);
  background:rgba(12,20,38,.82);
  border:1px solid rgba(150,190,255,.22);
  border-radius:999px;
  backdrop-filter:blur(14px);
  opacity:0;
  pointer-events:none;
  transition:opacity .35s, transform .35s;
  white-space:nowrap;
}
.toast.show{opacity:1;transform:translate(-50%,0)}

/* 无 WebGL 兜底 */
.fallback{
  position:fixed;
  inset:0;
  z-index:25;
  display:none;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:12px;
  text-align:center;
  padding:30px;
  background:#03050d;
  color:rgba(226,238,255,.8);
  font-size:14px;
  line-height:1.9;
}
.fallback.show{display:flex}
.fallback b{font-size:17px}

@media (max-width:760px){
  .hints{display:none}
  .brand .sub{display:none}
  .cam-panel{
    width:132px;
    right:12px;
    bottom:76px;
    padding:8px;
  }
  /* 窄屏把浮层放到面板上方（面板在右下，宽 132px） */
  .cam-help{bottom:auto;top:calc(50% + 10px);width:min(340px, calc(100vw - 24px))}
  .cam-help__note{font-size:12.5px}
  .cam-help__sub{font-size:10.5px}
  .cam-help__open{font-size:12.5px;padding:9px 10px}
  .cam-help__mini{font-size:10.5px;padding:6px 8px}
  .cam-help__hint{font-size:10px;line-height:1.6}
  .cam-meta{gap:3px}
  .cam-gesture{font-size:13px}
  .form-meter{display:none}
  .cam-fingers span{width:15px;height:15px;font-size:9px}
  .cam-nudge{font-size:9px}
  .hand-ring{width:58px;height:58px;margin:-29px 0 0 -29px}
  .tip{bottom:70px;font-size:10px;white-space:normal;width:78vw;text-align:center}
  /* 小屏上让开右下角的摄像头面板，入口靠左放 */
  .gesture-cta{
    left:12px;
    bottom:82px;
    transform:none;
    gap:8px;
    padding:7px 11px 7px 8px;
    max-width:calc(100vw - 168px);
  }
  .gesture-cta:hover{transform:none}
  .gesture-cta:active{transform:scale(.985)}
  .gesture-cta__icon{width:26px;height:26px}
  .gesture-cta__text b{font-size:11.5px}
  .gesture-cta__text i{display:none}
  .gesture-cta__key{display:none}
  body.gesture-on .gesture-cta{transform:translateY(8px)}
  body:not(.gesture-on) .tip{opacity:0}
  /* 固定元素 left:50% 时可用宽度只剩一半，会挤到换行，这里显式给内容宽度 */
  .switcher{bottom:12px;gap:2px;padding:5px;width:max-content;max-width:calc(100vw - 24px)}
  .sw-btn{padding:7px 11px}
  .sw-btn .sw-name{font-size:11.5px}
  .sw-btn .sw-en{display:none}
}

@media (prefers-reduced-motion:reduce){
  .brand .dot,.cam-scan{animation:none}
}
