<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>AI亲子营发布会开场白 — AI机器人·成长营</title>
<style>
/* ============================================================
   AI亲子营发布会 — 专业级动画演示
   子系统: 转场引擎 / 打字机 / 数字滚动 / 交错入场
           粒子v2 / 3D视差 / 辉光脉冲 / 时间线进度条
   ============================================================ */
@import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;600;700;900&family=Noto+Sans+SC:wght@300;400;500;700&display=swap');

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

:root{
  --deep-blue:#1a2a6c;
  --gold:#FFD700;
  --warm-white:#fffcf5;
  --accent-orange:#E67E22;
  --soft-bg:#f0ede4;
  --text-dark:#2c2416;
  --stage-low:#4CAF50;
  --stage-mid:#2196F3;
  --stage-high:#9C27B0;
  --transition-speed:0.75s;
  --stagger-base:0.12s;
}

body{
  font-family:'Noto Sans SC','Noto Serif SC',sans-serif;
  background:#000;
  overflow:hidden;
  width:100vw;height:100vh;
  user-select:none;-webkit-user-select:none;
  cursor:default;
}

#stage{
  position:relative;
  width:100vw;height:100vh;
  background:radial-gradient(ellipse at 50% 40%, #1a3468 0%, #0a1230 55%, #000 100%);
  overflow:hidden;
}

/* ----- Canvas Layers ----- */
#particlesCanvas{
  position:absolute;inset:0;
  pointer-events:none;z-index:1;
}

/* ============================================================
   Timeline Progress Bar
   ============================================================ */
#timeline{
  position:absolute;bottom:0;left:0;right:0;height:4px;
  display:flex;gap:0;z-index:10;
  background:rgba(255,255,255,0.06);
}
#timeline .seg{
  flex:1;height:100%;
  background:rgba(255,255,255,0.12);
  transition:background 0.4s;
  position:relative;
}
#timeline .seg.done{background:rgba(255,215,0,0.5);}
#timeline .seg.current{background:var(--gold);box-shadow:0 0 8px rgba(255,215,0,0.6);}
#timeline .seg .dot-marker{
  position:absolute;top:-4px;right:-5px;
  width:12px;height:12px;border-radius:50%;
  background:rgba(255,255,255,0.2);
  border:2px solid rgba(255,255,255,0.1);
  transition:all 0.4s;
}
#timeline .seg.current .dot-marker,
#timeline .seg.done .dot-marker{
  background:var(--gold);border-color:var(--gold);
  box-shadow:0 0 10px rgba(255,215,0,0.5);
}

/* Auto-play countdown ring */
#countdownRing{
  position:absolute;bottom:16px;left:20px;
  width:32px;height:32px;z-index:10;
  opacity:0;transition:opacity 0.3s;
}
#countdownRing.active{opacity:0.7;}
#countdownRing svg{width:100%;height:100%;transform:rotate(-90deg);}
#countdownRing .bg{fill:none;stroke:rgba(255,255,255,0.15);stroke-width:3;}
#countdownRing .fg{fill:none;stroke:var(--gold);stroke-width:3;stroke-linecap:round;
  stroke-dasharray:75.4;stroke-dashoffset:0;transition:stroke-dashoffset 0.3s linear;}

/* ============================================================
   Scene Container — Multi-mode Transitions
   ============================================================ */
.scene{
  position:absolute;inset:0;
  display:flex;flex-direction:column;
  align-items:center;justify-content:center;
  pointer-events:none;z-index:2;
  padding:40px;
  transition:opacity var(--transition-speed) cubic-bezier(0.4,0,0.2,1),
             transform var(--transition-speed) cubic-bezier(0.4,0,0.2,1);
}
.scene.entering{
  opacity:1;transform:none;
  pointer-events:auto;
}
.scene.exiting{
  pointer-events:none;
}

/* Transition modes */
.scene.mode-fade{opacity:0;transform:scale(0.97);}
.scene.mode-fade.entering{opacity:1;transform:scale(1);}

.scene.mode-slideUp{opacity:0;transform:translateY(60px);}
.scene.mode-slideUp.entering{opacity:1;transform:translateY(0);}

.scene.mode-slideLeft{opacity:0;transform:translateX(80px);}
.scene.mode-slideLeft.entering{opacity:1;transform:translateX(0);}

.scene.mode-zoomIn{opacity:0;transform:scale(0.85);}
.scene.mode-zoomIn.entering{opacity:1;transform:scale(1);}

.scene.mode-slideDown{opacity:0;transform:translateY(-60px);}
.scene.mode-slideDown.entering{opacity:1;transform:translateY(0);}

/* ============================================================
   Stagger children — delayed entry within scenes
   ============================================================ */
.stagger-item{
  opacity:0;
  transform:translateY(30px);
  transition:opacity 0.6s cubic-bezier(0.22,0.61,0.36,1),
             transform 0.6s cubic-bezier(0.22,0.61,0.36,1);
}
.scene.entering .stagger-item{
  opacity:1;transform:translateY(0);
}
.scene.exiting .stagger-item{
  opacity:0;transform:translateY(-20px);
  transition:opacity 0.35s ease-in,transform 0.35s ease-in;
}

/* ============================================================
   Glow Pulse — breathing glow on key elements
   ============================================================ */
@keyframes glowPulse{
  0%,100%{box-shadow:0 0 20px rgba(255,215,0,0.25),0 0 60px rgba(255,215,0,0.1);}
  50%{box-shadow:0 0 35px rgba(255,215,0,0.5),0 0 90px rgba(255,215,0,0.25);}
}
.glow-pulse{
  animation:glowPulse 2.5s ease-in-out infinite;
}

@keyframes glowPulseStrong{
  0%,100%{box-shadow:0 0 30px rgba(255,215,0,0.4),0 0 80px rgba(255,215,0,0.2);}
  50%{box-shadow:0 0 50px rgba(255,215,0,0.7),0 0 120px rgba(255,215,0,0.4);}
}
.glow-pulse-strong{
  animation:glowPulseStrong 2s ease-in-out infinite;
}

/* Ring around logo */
@keyframes ringRotate{
  0%{transform:rotate(0deg);}
  100%{transform:rotate(360deg);}
}
.orbit-ring{
  position:absolute;
  width:180px;height:180px;
  border-radius:50%;
  border:2px solid rgba(255,215,0,0.3);
  animation:ringRotate 8s linear infinite;
  pointer-events:none;
}
.orbit-ring::after{
  content:'';position:absolute;top:-4px;left:50%;
  width:10px;height:10px;border-radius:50%;
  background:var(--gold);
  box-shadow:0 0 15px var(--gold);
}

/* ============================================================
   Typing cursor
   ============================================================ */
@keyframes cursorBlink{
  0%,100%{opacity:1;}
  50%{opacity:0;}
}
.typing-cursor{
  display:inline-block;
  width:2px;height:1.1em;
  background:var(--gold);
  margin-left:2px;
  vertical-align:text-bottom;
  animation:cursorBlink 0.7s step-end infinite;
}
.typing-cursor.done{
  animation:none;
  opacity:0;
  transition:opacity 0.3s;
}

/* ============================================================
   Scene 0: Logo Splash
   ============================================================ */
.splash-wrapper{position:relative;display:flex;flex-direction:column;align-items:center;}
.splash-logo{
  font-size:130px;position:relative;z-index:1;
  filter:drop-shadow(0 0 50px rgba(255,215,0,0.5));
  animation:logoFloat 3.5s ease-in-out infinite;
}
@keyframes logoFloat{
  0%,100%{transform:translateY(0);}
  50%{transform:translateY(-16px);}
}
.splash-title{
  font-family:'Noto Serif SC',serif;
  font-size:54px;font-weight:900;color:#fff;
  text-shadow:0 0 40px rgba(255,215,0,0.55);
  margin-top:18px;letter-spacing:8px;z-index:1;
}
.splash-title em{font-style:normal;color:var(--gold);}
.splash-sub{
  font-size:20px;color:rgba(255,255,255,0.65);
  margin-top:14px;letter-spacing:5px;z-index:1;
}
.splash-hint{
  position:absolute;bottom:50px;
  font-size:15px;color:rgba(255,255,255,0.35);
  animation:blinkHint 2.2s ease-in-out infinite;
  pointer-events:none;
}
@keyframes blinkHint{
  0%,100%{opacity:0.25;}
  50%{opacity:0.9;}
}

/* ============================================================
   Scene 1: Welcome
   ============================================================ */
.welcome-badge{
  display:inline-block;
  background:linear-gradient(135deg,var(--gold),#f0c800);
  color:var(--deep-blue);
  padding:10px 34px;border-radius:40px;
  font-size:17px;font-weight:700;letter-spacing:3px;
  margin-bottom:28px;
}
.welcome-main{
  font-family:'Noto Serif SC',serif;
  font-size:46px;font-weight:900;color:#fff;
  text-align:center;line-height:1.5;
}
.welcome-main .hl{
  background:linear-gradient(135deg,var(--gold),#FFA500);
  -webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;
}
.welcome-desc{
  font-size:19px;color:rgba(255,255,255,0.78);
  margin-top:22px;text-align:center;line-height:1.9;
  max-width:680px;
}

/* ============================================================
   Scene 2: Three Stage Cards (3D Parallax)
   ============================================================ */
.section-label{
  font-size:15px;color:var(--gold);letter-spacing:5px;
  margin-bottom:16px;text-transform:uppercase;
}
.section-title{
  font-family:'Noto Serif SC',serif;
  font-size:42px;font-weight:900;color:#fff;
  margin-bottom:36px;text-align:center;
}
.stages-row{
  display:flex;gap:22px;max-width:1080px;width:100%;
  perspective:1200px;
}
.stage-card{
  flex:1;background:rgba(255,255,255,0.04);
  border:1px solid rgba(255,255,255,0.1);
  border-radius:20px;padding:30px 22px;
  text-align:center;backdrop-filter:blur(12px);
  position:relative;overflow:hidden;
  transition:transform 0.15s ease-out,box-shadow 0.3s;
  transform-style:preserve-3d;
  cursor:default;
  will-change:transform;
}
.stage-card::before{
  content:'';position:absolute;top:0;left:0;right:0;height:4px;
}
.stage-card.low::before{background:var(--stage-low);}
.stage-card.mid::before{background:var(--stage-mid);}
.stage-card.high::before{background:var(--stage-high);}

.stage-card .card-shine{
  position:absolute;inset:0;
  background:radial-gradient(ellipse at var(--mx,50%) var(--my,50%),
    rgba(255,255,255,0.08) 0%,transparent 70%);
  opacity:0;transition:opacity 0.3s;pointer-events:none;
}
.stage-card:hover .card-shine{opacity:1;}

.stage-card .icon{font-size:48px;margin-bottom:14px;position:relative;z-index:1;}
.stage-card h3{font-size:21px;font-weight:700;color:#fff;margin-bottom:6px;position:relative;z-index:1;}
.stage-card .age{font-size:13px;color:rgba(255,255,255,0.45);margin-bottom:10px;position:relative;z-index:1;}
.stage-card p{font-size:13px;color:rgba(255,255,255,0.65);line-height:1.6;position:relative;z-index:1;}
.stage-card .tech-tags{
  display:flex;flex-wrap:wrap;gap:5px;justify-content:center;
  margin-top:12px;position:relative;z-index:1;
}
.stage-card .tech-tags span{
  font-size:11px;padding:3px 10px;border-radius:12px;
  background:rgba(255,255,255,0.07);color:rgba(255,255,255,0.55);
}

/* ============================================================
   Scene 3: Stats Numbers
   ============================================================ */
.highlights-grid{
  display:grid;grid-template-columns:repeat(4,1fr);
  gap:14px;max-width:960px;width:100%;
}
.hl-card{
  background:rgba(255,255,255,0.035);
  border:1px solid rgba(255,255,255,0.08);
  border-radius:16px;padding:26px 18px;text-align:center;
}
.hl-card .num{
  font-family:'Noto Serif SC',serif;
  font-size:44px;font-weight:900;
  background:linear-gradient(135deg,var(--gold),#FFA500);
  -webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;
  display:inline-block;
}
.hl-card .unit{font-size:13px;color:rgba(255,255,255,0.45);}
.hl-card .label{font-size:14px;color:rgba(255,255,255,0.8);margin-top:6px;font-weight:500;}

/* ============================================================
   Scene 4: Demo Cards
   ============================================================ */
.demo-cards{
  display:flex;gap:18px;max-width:1020px;width:100%;
}
.demo-card{
  flex:1;background:rgba(255,255,255,0.04);
  border:1px solid rgba(255,255,255,0.1);
  border-radius:18px;padding:26px 20px;
  backdrop-filter:blur(10px);
  transition:transform 0.3s,box-shadow 0.3s;
}
.demo-card:hover{transform:translateY(-4px);box-shadow:0 12px 40px rgba(0,0,0,0.3);}
.demo-card .d-icon{font-size:42px;margin-bottom:10px;}
.demo-card h4{font-size:19px;font-weight:700;color:#fff;margin-bottom:3px;}
.demo-card .d-age{font-size:12px;color:var(--gold);margin-bottom:8px;}
.demo-card .d-desc{font-size:13px;color:rgba(255,255,255,0.65);line-height:1.6;}
.demo-card .d-time{
  display:inline-block;margin-top:10px;
  font-size:11px;padding:4px 12px;border-radius:12px;
  background:rgba(255,215,0,0.12);color:var(--gold);
}

/* ============================================================
   Scene 5: AI Tools
   ============================================================ */
.ai-tools{
  display:flex;gap:20px;align-items:center;
  max-width:780px;flex-wrap:wrap;justify-content:center;
}
.ai-tool{
  display:flex;flex-direction:column;align-items:center;gap:6px;
  padding:18px 24px;
  background:rgba(255,255,255,0.04);
  border-radius:16px;border:1px solid rgba(255,255,255,0.08);
  transition:transform 0.3s,box-shadow 0.3s;
}
.ai-tool:hover{transform:translateY(-3px);box-shadow:0 8px 30px rgba(0,0,0,0.3);}
.ai-tool .t-icon{font-size:36px;}
.ai-tool .t-name{font-size:15px;color:#fff;font-weight:600;}
.ai-tool .t-use{font-size:11px;color:rgba(255,255,255,0.45);}
.ai-arrow{font-size:22px;color:var(--gold);}

/* ============================================================
   Scene 6: CTA
   ============================================================ */
.cta-box{text-align:center;max-width:620px;}
.cta-box .big-q{
  font-family:'Noto Serif SC',serif;
  font-size:38px;font-weight:900;color:#fff;margin-bottom:18px;
}
.cta-box .big-a{
  font-size:21px;color:var(--gold);font-weight:700;
  margin-bottom:30px;letter-spacing:2px;
}
.cta-btn{
  display:inline-block;
  padding:15px 52px;border-radius:50px;
  background:linear-gradient(135deg,var(--gold),#FFA500);
  color:var(--deep-blue);font-size:21px;font-weight:700;
  letter-spacing:3px;cursor:pointer;text-decoration:none;
  box-shadow:0 8px 40px rgba(255,215,0,0.3);
  transition:all 0.3s ease;
}
.cta-btn:hover{
  transform:translateY(-3px);
  box-shadow:0 12px 55px rgba(255,215,0,0.5);
}
.cta-info{
  margin-top:22px;font-size:14px;color:rgba(255,255,255,0.45);
  line-height:1.8;
}

/* ============================================================
   Scene 7: Final / Thank You
   ============================================================ */
.final-logo{
  font-size:96px;margin-bottom:18px;
  filter:drop-shadow(0 0 45px rgba(255,215,0,0.5));
}
.final-text{
  font-family:'Noto Serif SC',serif;
  font-size:34px;font-weight:900;color:#fff;
  letter-spacing:6px;
}

/* ============================================================
   Narration bar
   ============================================================ */
#narrationBar{
  position:absolute;bottom:60px;left:50%;transform:translateX(-50%);
  max-width:720px;width:90%;text-align:center;
  z-index:5;pointer-events:none;
}
#narrationText{
  font-size:17px;color:rgba(255,255,255,0.88);
  line-height:1.9;font-weight:300;
  text-shadow:0 2px 10px rgba(0,0,0,0.6);
  min-height:2em;
}

/* ============================================================
   Controls hint
   ============================================================ */
#controlsHint{
  position:absolute;top:16px;right:20px;
  font-size:11px;color:rgba(255,255,255,0.25);
  z-index:10;letter-spacing:1px;
  transition:color 0.3s;
}
#controlsHint:hover{color:rgba(255,255,255,0.5);}

/* ============================================================
   Responsive
   ============================================================ */
@media(max-width:900px){
  .stages-row{flex-direction:column;gap:10px;}
  .highlights-grid{grid-template-columns:repeat(2,1fr);gap:8px;}
  .demo-cards{flex-direction:column;gap:10px;}
  .welcome-main{font-size:26px;}
  .section-title{font-size:26px;}
  .splash-title{font-size:30px;}
  .splash-logo{font-size:90px;}
  .cta-box .big-q{font-size:26px;}
  .final-text{font-size:24px;}
  .ai-tools{gap:8px;}
  .ai-tool{padding:12px 16px;}
  .ai-arrow{font-size:16px;}
  .scene{padding:20px;padding-bottom:100px;}
  #narrationBar{bottom:30px;}
  #countdownRing{bottom:8px;left:10px;width:24px;height:24px;}
  .chat-panel{width:100vw;right:-100vw;}
  .chat-panel.open{right:0;}
  .chat-toggle{right:16px;bottom:80px;}
}

/* ============================================================
   Chatbot Widget
   ============================================================ */
.chat-toggle{
  position:fixed;bottom:24px;right:24px;
  width:56px;height:56px;border-radius:50%;
  background:linear-gradient(135deg,var(--gold),#FFA500);
  color:var(--deep-blue);font-size:26px;
  border:none;cursor:pointer;z-index:100;
  box-shadow:0 4px 24px rgba(255,215,0,0.4);
  transition:all 0.3s ease;
  display:flex;align-items:center;justify-content:center;
}
.chat-toggle:hover{transform:scale(1.08);box-shadow:0 6px 32px rgba(255,215,0,0.6);}
.chat-toggle .badge{
  position:absolute;top:-4px;right:-4px;
  width:18px;height:18px;border-radius:50%;
  background:#E74C3C;color:#fff;font-size:10px;
  display:flex;align-items:center;justify-content:center;
  animation:glowPulse 2s ease-in-out infinite;
}
.chat-toggle.hidden{display:none;}

/* Music Toggle Button */
.music-toggle{
  position:fixed;bottom:90px;right:24px;
  width:44px;height:44px;border-radius:50%;
  background:rgba(255,255,255,0.08);
  border:1.5px solid rgba(255,255,255,0.15);
  color:rgba(255,255,255,0.6);font-size:18px;
  cursor:pointer;z-index:100;
  transition:all 0.35s ease;
  display:flex;align-items:center;justify-content:center;
  backdrop-filter:blur(8px);
}
.music-toggle:hover{
  background:rgba(255,255,255,0.14);
  border-color:rgba(255,215,0,0.35);
  color:var(--gold);transform:scale(1.06);
}
.music-toggle.playing{
  background:rgba(255,215,0,0.1);
  border-color:rgba(255,215,0,0.4);
  color:var(--gold);
  animation:musicPulse 2.5s ease-in-out infinite;
}
@keyframes musicPulse{
  0%,100%{box-shadow:0 0 8px rgba(255,215,0,0.2);}
  50%{box-shadow:0 0 20px rgba(255,215,0,0.45);}
}
.music-toggle .note1,.music-toggle .note2{
  position:absolute;font-size:8px;opacity:0;
  transition:all 0.6s ease;
}
.music-toggle.playing .note1{
  opacity:0.7;transform:translate(-8px,-10px);
  animation:floatNote1 2s ease-in-out infinite;
}
.music-toggle.playing .note2{
  opacity:0.5;transform:translate(8px,-8px);
  animation:floatNote2 2.3s ease-in-out infinite 0.4s;
}
@keyframes floatNote1{
  0%,100%{transform:translate(-8px,-10px);opacity:0.7;}
  50%{transform:translate(-10px,-18px);opacity:0.3;}
}
@keyframes floatNote2{
  0%,100%{transform:translate(8px,-8px);opacity:0.5;}
  50%{transform:translate(10px,-16px);opacity:0.2;}
}
@media(max-width:900px){
  .music-toggle{bottom:148px;right:16px;}
}

/* Chat Panel */
.chat-panel{
  position:fixed;top:0;right:-420px;
  width:400px;max-width:100vw;height:100vh;
  background:linear-gradient(180deg,#0d1b3e 0%,#0a1230 100%);
  border-left:1px solid rgba(255,215,0,0.2);
  z-index:99;display:flex;flex-direction:column;
  transition:right 0.4s cubic-bezier(0.4,0,0.2,1);
  box-shadow:-8px 0 40px rgba(0,0,0,0.5);
}
.chat-panel.open{right:0;}

.chat-header{
  padding:18px 20px;
  border-bottom:1px solid rgba(255,255,255,0.1);
  display:flex;align-items:center;gap:12px;
  flex-shrink:0;
}
.chat-header .bot-avatar{
  width:42px;height:42px;border-radius:50%;
  background:linear-gradient(135deg,var(--gold),#FFA500);
  display:flex;align-items:center;justify-content:center;
  font-size:22px;
}
.chat-header .bot-info{flex:1;}
.chat-header .bot-name{font-size:16px;font-weight:700;color:#fff;}
.chat-header .bot-status{font-size:11px;color:rgba(255,255,255,0.5);}
.chat-header .bot-status .dot{
  display:inline-block;width:7px;height:7px;border-radius:50%;
  background:#4CAF50;margin-right:4px;animation:glowPulse 2s ease-in-out infinite;
}
.chat-close{
  width:32px;height:32px;border-radius:50%;
  background:rgba(255,255,255,0.08);color:rgba(255,255,255,0.6);
  border:none;cursor:pointer;font-size:16px;
  transition:all 0.2s;
}
.chat-close:hover{background:rgba(255,255,255,0.15);color:#fff;}

.chat-messages{
  flex:1;overflow-y:auto;padding:16px;
  display:flex;flex-direction:column;gap:12px;
}
.chat-messages::-webkit-scrollbar{width:4px;}
.chat-messages::-webkit-scrollbar-track{background:transparent;}
.chat-messages::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.1);border-radius:2px;}

.msg{
  max-width:88%;padding:10px 14px;border-radius:16px;
  font-size:14px;line-height:1.6;
  animation:msgSlideIn 0.35s cubic-bezier(0.22,0.61,0.36,1);
  word-break:break-word;
}
@keyframes msgSlideIn{
  from{opacity:0;transform:translateY(12px);}
  to{opacity:1;transform:translateY(0);}
}
.msg.bot{
  align-self:flex-start;
  background:rgba(255,255,255,0.06);
  color:rgba(255,255,255,0.9);
  border-bottom-left-radius:4px;
}
.msg.user{
  align-self:flex-end;
  background:linear-gradient(135deg,var(--gold),#f0c800);
  color:var(--deep-blue);
  border-bottom-right-radius:4px;
  font-weight:500;
}
.msg .typing-indicator{
  display:flex;gap:4px;padding:4px 0;
}
.msg .typing-indicator span{
  width:6px;height:6px;border-radius:50%;
  background:rgba(255,255,255,0.4);
  animation:typeBounce 1.2s ease-in-out infinite;
}
.msg .typing-indicator span:nth-child(2){animation-delay:0.2s;}
.msg .typing-indicator span:nth-child(3){animation-delay:0.4s;}
@keyframes typeBounce{
  0%,60%,100%{transform:translateY(0);opacity:0.3;}
  30%{transform:translateY(-6px);opacity:1;}
}

/* Quick questions */
.quick-questions{
  padding:12px 16px;border-top:1px solid rgba(255,255,255,0.08);
  display:flex;flex-wrap:wrap;gap:6px;flex-shrink:0;
}
.quick-q{
  font-size:11px;padding:5px 12px;border-radius:14px;
  background:rgba(255,255,255,0.05);color:rgba(255,255,255,0.65);
  border:1px solid rgba(255,255,255,0.1);cursor:pointer;
  transition:all 0.2s;white-space:nowrap;
}
.quick-q:hover{background:rgba(255,215,0,0.12);color:var(--gold);border-color:rgba(255,215,0,0.25);}

/* Chat input */
.chat-input-area{
  padding:12px 16px;border-top:1px solid rgba(255,255,255,0.1);
  display:flex;gap:8px;flex-shrink:0;
}
.chat-input-area input{
  flex:1;padding:10px 16px;border-radius:22px;
  background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.12);
  color:#fff;font-size:14px;outline:none;
  transition:border-color 0.3s;
}
.chat-input-area input:focus{border-color:var(--gold);}
.chat-input-area input::placeholder{color:rgba(255,255,255,0.3);}
.chat-send{
  width:42px;height:42px;border-radius:50%;
  background:linear-gradient(135deg,var(--gold),#FFA500);
  border:none;cursor:pointer;font-size:18px;color:var(--deep-blue);
  transition:all 0.2s;flex-shrink:0;
}
.chat-send:hover{transform:scale(1.05);}
.chat-send:disabled{opacity:0.4;cursor:not-allowed;transform:none;}
</style>
</head>
<body>

<div id="stage">

  <!-- Particle canvas -->
  <canvas id="particlesCanvas"></canvas>

  <!-- Timeline progress bar -->
  <div id="timeline"></div>

  <!-- Countdown ring -->
  <div id="countdownRing">
    <svg viewBox="0 0 28 28">
      <circle class="bg" cx="14" cy="14" r="12"/>
      <circle class="fg" cx="14" cy="14" r="12"/>
    </svg>
  </div>

  <!-- Controls hint -->
  <div id="controlsHint">← → 切换 · 空格 自动播放 · 点击画面</div>

  <!-- Narration bar -->
  <div id="narrationBar">
    <span id="narrationText"></span><span class="typing-cursor" id="typingCursor"></span>
  </div>

  <!-- ===== Scene 0: Logo Splash ===== -->
  <div class="scene mode-zoomIn entering" data-scene="0" data-transition="zoomIn">
    <div class="splash-wrapper">
      <div class="orbit-ring" style="position:absolute;"></div>
      <span class="splash-logo stagger-item" style="--si:0">🤖</span>
      <span class="splash-title stagger-item" style="--si:1">AI 机器人<em>·成长营</em></span>
      <span class="splash-sub stagger-item" style="--si:2">AI 亲子营 发布会</span>
    </div>
    <div class="splash-hint">— 点击或按空格键开始 —</div>
  </div>

  <!-- ===== Scene 1: Welcome ===== -->
  <div class="scene mode-fade" data-scene="1" data-transition="slideUp">
    <div class="welcome-badge stagger-item glow-pulse" style="--si:0">🎉 发布会开场</div>
    <div class="welcome-main stagger-item" style="--si:1">
      欢迎来到<span class="hl">AI亲子营</span><br/>AI机器人成长营发布会
    </div>
    <div class="welcome-desc stagger-item" style="--si:2">
      当人工智能遇见亲子教育，<br/>
      当机器人走进孩子的成长旅程——<br/>
      一个全新的<span style="color:#FFD700;">AI赋能亲子共学</span>时代，<br/>
      今天，从这里开启。
    </div>
  </div>

  <!-- ===== Scene 2: Three Stages ===== -->
  <div class="scene mode-fade" data-scene="2" data-transition="slideLeft">
    <div class="section-label stagger-item" style="--si:0">✦ 课程体系 ✦</div>
    <div class="section-title stagger-item" style="--si:1">三大成长阶梯，陪伴孩子从启蒙到硬核</div>
    <div class="stages-row">
      <div class="stage-card low stagger-item" style="--si:2" data-parallax>
        <div class="card-shine"></div>
        <div class="icon">🌱</div>
        <h3>启蒙萌芽</h3>
        <div class="age">5-8岁</div>
        <p>感官探索 · 动手建构 · 趣味AI互动<br/>积木式机器人套件、图形化编程、基础传感器</p>
        <div class="tech-tags">
          <span>机器人搭建</span><span>声音传感器</span><span>AI视觉</span><span>机械结构</span>
        </div>
      </div>
      <div class="stage-card mid stagger-item" style="--si:3" data-parallax>
        <div class="card-shine"></div>
        <div class="icon">🌿</div>
        <h3>成长进阶</h3>
        <div class="age">9-12岁</div>
        <p>系统认知 · 编程控制 · AI算法融合<br/>Python、Arduino、AI视觉模块</p>
        <div class="tech-tags">
          <span>Python编程</span><span>仿生机器人</span><span>智能家居</span><span>竞技机器人</span>
        </div>
      </div>
      <div class="stage-card high stagger-item" style="--si:4" data-parallax>
        <div class="card-shine"></div>
        <div class="icon">🚀</div>
        <h3>硬核实训</h3>
        <div class="age">13岁+</div>
        <p>全栈开发 · 算法驱动 · 竞赛实战<br/>ROS、深度学习、Jetson、YOLO</p>
        <div class="tech-tags">
          <span>ROS系统</span><span>SLAM建图</span><span>人形机器人</span><span>无人机</span>
        </div>
      </div>
    </div>
  </div>

  <!-- ===== Scene 3: Stats ===== -->
  <div class="scene mode-fade" data-scene="3" data-transition="slideUp">
    <div class="section-label stagger-item" style="--si:0">✦ 为什么选择我们 ✦</div>
    <div class="section-title stagger-item" style="--si:1">用数据说话</div>
    <div class="highlights-grid">
      <div class="hl-card stagger-item" style="--si:2">
        <div class="num"><span data-countup="12">12</span></div>
        <div class="unit">门</div><div class="label">系统课程</div>
      </div>
      <div class="hl-card stagger-item" style="--si:3">
        <div class="num"><span data-countup="48">48</span></div>
        <div class="unit">节</div><div class="label">互动课件</div>
      </div>
      <div class="hl-card stagger-item" style="--si:4">
        <div class="num"><span data-countup="3">3</span></div>
        <div class="unit">大阶段</div><div class="label">覆盖5-18岁</div>
      </div>
      <div class="hl-card stagger-item" style="--si:5">
        <div class="num"><span data-countup="6">6</span></div>
        <div class="unit">种</div><div class="label">职业导向</div>
      </div>
      <div class="hl-card stagger-item" style="--si:6">
        <div class="num"><span>RIASEC</span></div>
        <div class="unit">模型</div><div class="label">职业兴趣匹配</div>
      </div>
      <div class="hl-card stagger-item" style="--si:7">
        <div class="num"><span>AI+</span></div>
        <div class="unit">驱动</div><div class="label">前沿技术融合</div>
      </div>
      <div class="hl-card stagger-item" style="--si:8">
        <div class="num"><span>PBL</span></div>
        <div class="unit">模式</div><div class="label">项目式学习</div>
      </div>
      <div class="hl-card stagger-item" style="--si:9">
        <div class="num"><span>竞赛</span></div>
        <div class="unit">导向</div><div class="label">FLL/VEX/RoboCup</div>
      </div>
    </div>
  </div>

  <!-- ===== Scene 4: Demo Classes ===== -->
  <div class="scene mode-fade" data-scene="4" data-transition="slideLeft">
    <div class="section-label stagger-item" style="--si:0">✦ 招生展示课 ✦</div>
    <div class="section-title stagger-item" style="--si:1">三堂体验课，让孩子爱上AI</div>
    <div class="demo-cards">
      <div class="demo-card stagger-item" style="--si:2">
        <div class="d-icon">🚗</div>
        <h4>会听话的小车</h4>
        <div class="d-age">5-8岁</div>
        <div class="d-desc">拍拍手，小车就跑；喊停，它就停！<br/>孩子体验声控交互的魔力，<br/>亲自动手搭建人生第一台AI小车。</div>
        <div class="d-time">⏱ 25分钟</div>
      </div>
      <div class="demo-card stagger-item" style="--si:3">
        <div class="d-icon">🚨</div>
        <h4>AI巡逻机器人</h4>
        <div class="d-age">9-12岁</div>
        <div class="d-desc">能自己走路、认识人、还会报警！<br/>现场修改Python代码调整巡逻模式，<br/>即时看到AI效果。</div>
        <div class="d-time">⏱ 25分钟</div>
      </div>
      <div class="demo-card stagger-item" style="--si:4">
        <div class="d-icon">🧭</div>
        <h4>自主导航机器人</h4>
        <div class="d-age">13岁+</div>
        <div class="d-desc">从未见过这个教室，却能自己画出地图、<br/>找到目标——SLAM建图+YOLO检测，<br/>体验真正的自主导航。</div>
        <div class="d-time">⏱ 30分钟</div>
      </div>
    </div>
  </div>

  <!-- ===== Scene 5: AI Tools ===== -->
  <div class="scene mode-fade" data-scene="5" data-transition="slideUp">
    <div class="section-label stagger-item" style="--si:0">✦ AI工具体验 ✦</div>
    <div class="section-title stagger-item" style="--si:1">AI时代的学习新范式</div>
    <div class="ai-tools">
      <div class="ai-tool stagger-item" style="--si:2">
        <div class="t-icon">🤖</div><div class="t-name">Kimi</div>
        <div class="t-use">语音助手·生成自我介绍</div>
      </div>
      <span class="ai-arrow stagger-item" style="--si:2">→</span>
      <div class="ai-tool stagger-item" style="--si:3">
        <div class="t-icon">🧩</div><div class="t-name">Coze</div>
        <div class="t-use">智能体联动·机器人控制</div>
      </div>
      <span class="ai-arrow stagger-item" style="--si:3">→</span>
      <div class="ai-tool stagger-item" style="--si:4">
        <div class="t-icon">💻</div><div class="t-name">Cursor</div>
        <div class="t-use">AI辅助编程·底层代码</div>
      </div>
      <span class="ai-arrow stagger-item" style="--si:4">→</span>
      <div class="ai-tool stagger-item" style="--si:5">
        <div class="t-icon">🔍</div><div class="t-name">DeepSeek</div>
        <div class="t-use">数据分析·传感器解读</div>
      </div>
    </div>
    <p class="stagger-item" style="--si:6;color:rgba(255,255,255,0.6);margin-top:26px;font-size:15px;text-align:center;max-width:650px;line-height:1.8;">
      不只是学机器人——孩子将在课程中<span style="color:#FFD700;font-weight:600;">熟练使用主流AI工具</span>，<br/>
      培养"人+AI协作"的核心素养，为未来10年做好准备。
    </p>
  </div>

  <!-- ===== Scene 6: CTA ===== -->
  <div class="scene mode-fade" data-scene="6" data-transition="zoomIn">
    <div class="cta-box">
      <div class="big-q stagger-item" style="--si:0">准备好让孩子拥抱AI时代了吗？</div>
      <div class="big-a stagger-item" style="--si:1">AI亲子营 · 今日正式发布 🎉</div>
      <a href="http://airobot.zengqi.site/" target="_blank"
         class="cta-btn stagger-item glow-pulse-strong" style="--si:2">
        立即体验 ✨
      </a>
      <div class="cta-info stagger-item" style="--si:3">
        🌐 airobot.zengqi.site<br/>
        📚 12门课程 · 48节互动课件<br/>
        🎯 面向5-13岁+ · 三大成长阶梯
      </div>
    </div>
  </div>

  <!-- ===== Scene 7: Thank You ===== -->
  <div class="scene mode-fade" data-scene="7" data-transition="slideDown">
    <div class="final-logo stagger-item glow-pulse" style="--si:0">🤖</div>
    <div class="final-text stagger-item" style="--si:1">AI 机器人·成长营</div>
    <p class="stagger-item" style="--si:2;color:rgba(255,255,255,0.55);font-size:17px;margin-top:14px;letter-spacing:3px;">
      让每个孩子，都成为AI时代的创造者
    </p>
    <p class="stagger-item" style="--si:3;color:rgba(255,255,255,0.3);font-size:13px;margin-top:28px;">
      感谢观看 · AI亲子营发布会 · 期待您的加入
    </p>
  </div>

</div>

<!-- 静默音频 — 用于触发浏览器自动播放许可 -->
<audio id="silentAudio" autoplay loop style="display:none"
  src="data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQAAAAA=">
</audio>

<!-- ===== AI Chatbot Widget ===== -->
<button class="music-toggle" id="musicToggle" title="背景音乐">
  🎵
  <span class="note1">♪</span>
  <span class="note2">♫</span>
</button>

<button class="chat-toggle" id="chatToggle" title="与AI助手对话">
  🤖
  <span class="badge" id="chatBadge">1</span>
</button>

<div class="chat-panel" id="chatPanel">
  <div class="chat-header">
    <div class="bot-avatar">🤖</div>
    <div class="bot-info">
      <div class="bot-name">小AI · 课程顾问</div>
      <div class="bot-status"><span class="dot"></span>在线 · 随时为你解答</div>
    </div>
    <button class="chat-close" id="chatClose">✕</button>
  </div>

  <div class="chat-messages" id="chatMessages">
    <div class="msg bot">
      👋 你好！我是<strong>小AI</strong>，AI亲子营的智能课程顾问～<br/><br/>
      我可以帮你：<br/>
      🔍 了解适合孩子年龄的课程<br/>
      📚 查看12门AI机器人课程详情<br/>
      🎯 预约招生展示课体验<br/>
      💡 解答AI教育相关问题<br/><br/>
      有什么想了解的吗？😊
    </div>
  </div>

  <div class="quick-questions" id="quickQuestions">
    <button class="quick-q" data-q="5岁孩子适合什么课程？">🎈 5岁孩子适合什么？</button>
    <button class="quick-q" data-q="课程怎么收费？">💰 课程怎么收费？</button>
    <button class="quick-q" data-q="什么是AI机器人成长营？">🤖 什么是AI成长营？</button>
    <button class="quick-q" data-q="12岁孩子学什么？">🧠 12岁孩子学什么？</button>
    <button class="quick-q" data-q="怎么报名展示课？">🎯 怎么报名展示课？</button>
    <button class="quick-q" data-q="学完能参加竞赛吗？">🏆 学完能参加竞赛吗？</button>
  </div>

  <div class="chat-input-area">
    <input type="text" id="chatInput" placeholder="输入你的问题..." maxlength="500" />
    <button class="chat-send" id="chatSend">➤</button>
  </div>
</div>

<script>
// ============================================================
//  AI亲子营发布会 — 专业动画子系统
//  v2: 转场引擎 / 打字机 / 数字滚动 / 交错入场
//      粒子v2 / 3D视差 / 辉光脉冲 / 时间线进度条
// ============================================================

const stage = document.getElementById('stage');
const scenes = Array.from(document.querySelectorAll('.scene'));
const totalScenes = scenes.length;
const narrationText = document.getElementById('narrationText');
const typingCursor = document.getElementById('typingCursor');
const controlsHint = document.getElementById('controlsHint');
const countdownRing = document.getElementById('countdownRing');
const countdownFg = countdownRing.querySelector('.fg');
const timeline = document.getElementById('timeline');

let currentScene = 0;
let autoPlay = false;
let autoPlayTimer = null;
let typingTimer = null;
const SCENE_DURATION = 6500; // ms per scene in auto-play
const COUNTUP_DURATION = 1800; // ms for count-up animation
const TYPE_SPEED = 45; // ms per character

// Transition modes pool — cycles through different modes for variety
const transitionModes = ['slideUp','slideLeft','zoomIn','slideDown','fade'];

// Narration scripts
const narrations = [
  '', // splash — no narration
  '各位家长、各位小朋友，欢迎来到AI亲子营发布会现场！我是曾老师。今天，我们将一起见证一个全新AI教育项目的诞生——AI机器人成长营。',
  '我们的课程分为三大成长阶梯：启蒙萌芽面向5-8岁孩子，以感官探索和动手建构为主；成长进阶面向9-12岁，引入Python编程和AI算法；硬核实训面向13岁以上，深入ROS、深度学习和竞赛实战。',
  '12门系统课程，48节互动课件，覆盖从幼儿园到高中的完整AI机器人学习路径。我们采用RIASEC职业兴趣模型，为每个孩子匹配最适合的学习方向。',
  '我们为三个年龄段精心设计了三堂招生展示课：5到8岁的"会听话的小车"、9到12岁的"AI巡逻机器人"、13岁以上的"自主导航机器人"。每堂课只需25到30分钟，让孩子亲身体验AI机器人的魅力！',
  '在AI机器人成长营，孩子不只是学技术——他们将熟练使用Kimi、Coze、Cursor、DeepSeek等主流AI工具，培养人与AI协作的核心素养。这是未来10年最重要的能力。',
  '准备好让孩子拥抱AI时代了吗？AI亲子营今日正式发布！访问 airobot.zengqi.site 了解更多，我们在这里等你。',
  '让每个孩子，都成为AI时代的创造者。感谢观看，期待在AI机器人成长营与您相见！'
];

// ============================================================
//  1. Timeline Progress Bar
// ============================================================
function buildTimeline(){
  timeline.innerHTML = '';
  for(let i=0;i<totalScenes;i++){
    const seg = document.createElement('div');
    seg.className='seg';
    const dot = document.createElement('div');
    dot.className='dot-marker';
    seg.appendChild(dot);
    timeline.appendChild(seg);
  }
}
buildTimeline();

function updateTimeline(idx){
  const segs = timeline.querySelectorAll('.seg');
  segs.forEach((s,i)=>{
    s.classList.remove('done','current');
    if(i<idx) s.classList.add('done');
    if(i===idx) s.classList.add('current');
  });
}

// ============================================================
//  2. Transition Engine
// ============================================================
function applyTransition(sceneEl, mode){
  // Remove all mode classes
  const modes = ['mode-fade','mode-slideUp','mode-slideLeft','mode-zoomIn','mode-slideDown'];
  modes.forEach(m=>sceneEl.classList.remove(m));
  sceneEl.classList.add('mode-'+mode);
  sceneEl.dataset.transition = mode;
}

function goToScene(index, direction){
  if(index<0||index>=totalScenes||index===currentScene) return;
  direction = direction || (index>currentScene?1:-1);

  const oldScene = scenes[currentScene];
  const newScene = scenes[index];

  // Exit old scene
  oldScene.classList.remove('entering');
  oldScene.classList.add('exiting');

  // Pick transition mode based on direction for variety
  const modeIdx = index % transitionModes.length;
  const mode = transitionModes[modeIdx];

  // Setup new scene
  applyTransition(newScene, mode);
  newScene.classList.remove('exiting');

  // Reset count-up elements in the new scene before entering
  resetCountUps(newScene);

  // Force reflow
  void newScene.offsetWidth;

  // Enter new scene
  requestAnimationFrame(()=>{
    newScene.classList.add('entering');
    currentScene = index;
    updateTimeline(index);
    resetAndStartTyping(index);
    scheduleCountUps(newScene, 400); // slight delay after scene enters
    updateStaggerDelays(newScene);
  });
}

function updateStaggerDelays(sceneEl){
  const items = sceneEl.querySelectorAll('.stagger-item');
  items.forEach(item=>{
    const si = parseInt(item.style.getPropertyValue('--si'))||0;
    item.style.transitionDelay = (si * 0.1) + 's';
  });
}

// ============================================================
//  3. Typewriter Effect
// ============================================================
function resetAndStartTyping(sceneIdx){
  if(typingTimer){clearTimeout(typingTimer);typingTimer=null;}
  const text = narrations[sceneIdx]||'';
  narrationText.textContent = '';
  typingCursor.classList.remove('done');

  if(!text){
    typingCursor.classList.add('done');
    return;
  }

  // Manual switch: show all immediately
  if(!autoPlay){
    narrationText.textContent = text;
    typingCursor.classList.add('done');
    return;
  }

  // Auto-play: type character by character
  let charIdx = 0;
  function typeNext(){
    if(charIdx < text.length){
      narrationText.textContent += text[charIdx];
      charIdx++;
      typingTimer = setTimeout(typeNext, TYPE_SPEED);
    } else {
      typingCursor.classList.add('done');
    }
  }
  typingTimer = setTimeout(typeNext, 200);
}

// ============================================================
//  4. Count-Up Number Animation
// ============================================================
const countUpRegistry = new Map(); // element -> {target, current, animId}

function resetCountUps(sceneEl){
  const els = sceneEl.querySelectorAll('[data-countup]');
  els.forEach(el=>{
    // Cancel any running animation
    const entry = countUpRegistry.get(el);
    if(entry && entry.animId) cancelAnimationFrame(entry.animId);
    countUpRegistry.delete(el);
    // Reset display
    el.textContent = '0';
  });
}

function scheduleCountUps(sceneEl, delay){
  const els = sceneEl.querySelectorAll('[data-countup]');
  els.forEach(el=>{
    const target = parseInt(el.dataset.countup);
    if(isNaN(target)) return;
    setTimeout(()=>animateCountUp(el, target), delay);
  });
}

function animateCountUp(el, target){
  const start = performance.now();
  const initial = 0;

  function step(now){
    const elapsed = now - start;
    const progress = Math.min(elapsed / COUNTUP_DURATION, 1);
    // easeOutCubic
    const eased = 1 - Math.pow(1 - progress, 3);
    const current = Math.round(initial + (target - initial) * eased);
    el.textContent = String(current);

    if(progress < 1){
      const id = requestAnimationFrame(step);
      countUpRegistry.set(el, {target, current, animId: id});
    } else {
      el.textContent = String(target);
      countUpRegistry.delete(el);
    }
  }

  const id = requestAnimationFrame(step);
  countUpRegistry.set(el, {target, initial, animId: id});
}

// ============================================================
//  5. Auto-Play with Countdown Ring
// ============================================================
const CIRCUMFERENCE = 2 * Math.PI * 12; // ~75.4
countdownFg.style.strokeDasharray = CIRCUMFERENCE;
countdownFg.style.strokeDashoffset = '0';

function updateCountdownRing(fraction){
  countdownFg.style.strokeDashoffset = (CIRCUMFERENCE * (1 - fraction));
}

function startAutoPlay(){
  if(autoPlayTimer) clearInterval(autoPlayTimer);

  countdownRing.classList.add('active');
  const startTime = performance.now();
  let frameId;

  function tick(now){
    const elapsed = now - startTime;
    const cycleElapsed = elapsed % SCENE_DURATION;
    const fraction = cycleElapsed / SCENE_DURATION;
    updateCountdownRing(fraction);

    if(autoPlay){
      frameId = requestAnimationFrame(tick);
    }
  }
  frameId = requestAnimationFrame(tick);

  autoPlayTimer = setInterval(()=>{
    const next = (currentScene + 1) % totalScenes;
    if(next === 0){
      // Loop back to scene 1 (skip splash)
      goToScene(1, 1);
    } else {
      goToScene(next, 1);
    }
  }, SCENE_DURATION);

  // Store frameId for cleanup
  countdownRing._frameId = frameId;
}

function stopAutoPlay(){
  if(autoPlayTimer){clearInterval(autoPlayTimer);autoPlayTimer=null;}
  if(countdownRing._frameId){cancelAnimationFrame(countdownRing._frameId);}
  countdownRing.classList.remove('active');
  updateCountdownRing(0);
}

function toggleAutoPlay(){
  autoPlay = !autoPlay;
  if(autoPlay){
    startAutoPlay();
    controlsHint.textContent = '⏸ 自动播放中 (空格键暂停) · ← → 手动切换';
    // If currently showing narration, restart typing
    resetAndStartTyping(currentScene);
  } else {
    stopAutoPlay();
    controlsHint.textContent = '▶ 已暂停 (空格键继续) · ← → 键切换';
    // Show full narration immediately
    if(typingTimer){clearTimeout(typingTimer);typingTimer=null;}
    narrationText.textContent = narrations[currentScene]||'';
    typingCursor.classList.add('done');
  }
}

// ============================================================
//  6. Particle System v2 — Dual-layer + connections + mouse
// ============================================================
const pCanvas = document.getElementById('particlesCanvas');
const pCtx = pCanvas.getContext('2d');

// Determine particle count based on device pixel ratio
const dpr = Math.min(window.devicePixelRatio||1, 2);
const isMobile = /Mobi|Android/i.test(navigator.userAgent);
const PARTICLE_COUNT = isMobile ? 40 : (dpr > 1.5 ? 70 : 50);

let particles = [];
let mouseX = -1000, mouseY = -1000;
let mouseActive = false;

function resizePCanvas(){
  pCanvas.width = window.innerWidth * dpr;
  pCanvas.height = window.innerHeight * dpr;
  pCtx.setTransform(1,0,0,1,0,0);
  pCtx.scale(dpr, dpr);
}
window.addEventListener('resize', resizePCanvas);
resizePCanvas();

// Track mouse
stage.addEventListener('mousemove', e=>{
  mouseX = e.clientX; mouseY = e.clientY; mouseActive = true;
});
stage.addEventListener('mouseleave', ()=>{mouseActive=false;});
stage.addEventListener('touchmove', e=>{
  mouseX = e.touches[0].clientX; mouseY = e.touches[0].clientY; mouseActive = true;
},{passive:true});
stage.addEventListener('touchend', ()=>{mouseActive=false;});

class ParticleV2{
  constructor(layer){
    this.layer = layer; // 'slow' | 'fast'
    this.reset(true);
  }
  reset(init){
    this.x = Math.random() * window.innerWidth;
    this.y = init ? Math.random() * window.innerHeight : window.innerHeight + 20;
    if(this.layer==='slow'){
      this.size = Math.random()*2.8+0.8;
      this.speed = Math.random()*0.4+0.1;
      this.opacity = Math.random()*0.5+0.12;
      this.hue = Math.random()>0.55?45:210;
    } else {
      this.size = Math.random()*1.4+0.3;
      this.speed = Math.random()*1.0+0.3;
      this.opacity = Math.random()*0.7+0.2;
      this.hue = Math.random()>0.6?50:200;
    }
    this.wobble = Math.random()*Math.PI*2;
    this.wobbleSpeed = (Math.random()-0.5)*0.02;
    this.wobbleAmp = Math.random()*0.8+0.2;
  }
  update(){
    this.y -= this.speed;
    this.wobble += this.wobbleSpeed;
    const wx = Math.sin(this.wobble) * this.wobbleAmp;
    this.x += wx;

    // Mouse repulsion
    if(mouseActive){
      const dx = this.x - mouseX;
      const dy = this.y - mouseY;
      const dist = Math.sqrt(dx*dx+dy*dy);
      if(dist < 120){
        const force = (1 - dist/120) * 2.5;
        this.x += (dx/dist) * force;
        this.y += (dy/dist) * force;
      }
    }

    // Fade out near top
    this.opacity -= 0.0002;
    if(this.y < -20 || this.opacity <= 0 || this.x<-20 || this.x>window.innerWidth+20){
      this.reset(false);
    }
  }
  draw(ctx){
    ctx.save();
    ctx.globalAlpha = this.opacity;
    const col = this.hue===45
      ? `hsla(45,100%,65%,${this.opacity})`
      : `hsla(210,60%,75%,${this.opacity})`;
    ctx.fillStyle = col;
    ctx.shadowColor = col;
    ctx.shadowBlur = this.layer==='slow'?6:2;
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.size, 0, Math.PI*2);
    ctx.fill();
    ctx.restore();
  }
}

// Initialize particles
for(let i=0;i<PARTICLE_COUNT;i++){
  particles.push(new ParticleV2(i < PARTICLE_COUNT*0.35 ? 'slow' : 'fast'));
}

// Draw connections between nearby particles
function drawConnections(ctx){
  const threshold = 110;
  for(let i=0;i<particles.length;i++){
    for(let j=i+1;j<particles.length;j++){
      const a=particles[i], b=particles[j];
      const dx=a.x-b.x, dy=a.y-b.y;
      const dist=Math.sqrt(dx*dx+dy*dy);
      if(dist<threshold){
        const alpha = (1-dist/threshold)*0.12;
        ctx.save();
        ctx.globalAlpha = alpha;
        ctx.strokeStyle = a.layer==='slow'&&b.layer==='slow'
          ? 'rgba(255,215,0,0.6)' : 'rgba(180,210,255,0.4)';
        ctx.lineWidth = 0.5;
        ctx.beginPath();
        ctx.moveTo(a.x, a.y);
        ctx.lineTo(b.x, b.y);
        ctx.stroke();
        ctx.restore();
      }
    }
  }
}

function animateParticles(){
  pCtx.clearRect(0, 0, window.innerWidth, window.innerHeight);
  particles.forEach(p=>{p.update();p.draw(pCtx);});
  drawConnections(pCtx);
  requestAnimationFrame(animateParticles);
}
animateParticles();

// ============================================================
//  7. 3D Card Parallax
// ============================================================
function initParallax(){
  const cards = document.querySelectorAll('[data-parallax]');
  cards.forEach(card=>{
    card.addEventListener('mousemove', e=>{
      const rect = card.getBoundingClientRect();
      const x = ((e.clientX - rect.left) / rect.width - 0.5) * 2; // -1..1
      const y = ((e.clientY - rect.top) / rect.height - 0.5) * 2;
      const maxRotate = 8;
      card.style.transform = `perspective(800px) rotateY(${x*maxRotate}deg) rotateX(${-y*maxRotate}deg)`;
      card.style.setProperty('--mx', ((e.clientX-rect.left)/rect.width*100)+'%');
      card.style.setProperty('--my', ((e.clientY-rect.top)/rect.height*100)+'%');
      card.style.boxShadow = `${x*15}px ${y*15}px 30px rgba(0,0,0,0.3)`;
    });
    card.addEventListener('mouseleave', ()=>{
      card.style.transform = 'perspective(800px) rotateY(0deg) rotateX(0deg)';
      card.style.boxShadow = 'none';
      card.style.setProperty('--mx','50%');
      card.style.setProperty('--my','50%');
    });
  });
}
initParallax();

// ============================================================
//  8. Keyboard & Click Navigation
// ============================================================
document.addEventListener('keydown', e=>{
  if(e.key==='ArrowRight'||e.key==='ArrowDown'){
    e.preventDefault();
    const next = currentScene+1;
    if(next<totalScenes) goToScene(next,1);
    else goToScene(1,1); // loop from last to scene 1
  } else if(e.key==='ArrowLeft'||e.key==='ArrowUp'){
    e.preventDefault();
    if(currentScene>0) goToScene(currentScene-1,-1);
  } else if(e.key===' '){
    e.preventDefault();
    if(currentScene===0){
      // Start presentation from splash
      goToScene(1,1);
      autoPlay=true;
      startAutoPlay();
      controlsHint.textContent = '⏸ 自动播放中 (空格键暂停) · ← → 手动切换';
    } else {
      toggleAutoPlay();
    }
  }
});

stage.addEventListener('click', e=>{
  if(e.target.tagName==='A') return;
  if(currentScene===0){
    goToScene(1,1);
    autoPlay=true;
    startAutoPlay();
    controlsHint.textContent = '⏸ 自动播放中 (空格键暂停) · ← → 手动切换';
  }
});

// Touch swipe
let touchStartX=0;
document.addEventListener('touchstart',e=>{touchStartX=e.touches[0].clientX;});
document.addEventListener('touchend',e=>{
  const diff = touchStartX - e.changedTouches[0].clientX;
  if(Math.abs(diff)>50){
    diff>0?goToScene(Math.min(currentScene+1,totalScenes-1),1)
          :goToScene(Math.max(currentScene-1,0),-1);
  }
});

// ============================================================
//  9. Init
// ============================================================
function init(){
  // Scene 0 is the only one active at start
  scenes.forEach((s,i)=>{
    if(i===0){
      s.classList.add('entering');
      s.classList.remove('exiting');
    } else {
      s.classList.remove('entering','exiting');
      // Assign transition mode
      const mode = transitionModes[i % transitionModes.length];
      applyTransition(s, mode);
    }
  });

  updateTimeline(0);
  updateStaggerDelays(scenes[0]);
  resetAndStartTyping(0);

  console.log('🤖 AI亲子营发布会 v2 — 专业动画版');
  console.log('   转场引擎 · 逐字旁白 · 数字滚动 · 交错入场');
  console.log('   双层粒子+连线 · 3D卡片视差 · 辉光脉冲 · 时间线进度');
  console.log('   ← → 切换 · 空格 自动播放 · 点击 开始');
}

init();

// ============================================================
//  AI Chatbot Widget — 小AI课程顾问
// ============================================================
const chatToggle = document.getElementById('chatToggle');
const chatPanel = document.getElementById('chatPanel');
const chatClose = document.getElementById('chatClose');
const chatMessages = document.getElementById('chatMessages');
const chatInput = document.getElementById('chatInput');
const chatSend = document.getElementById('chatSend');
const chatBadge = document.getElementById('chatBadge');
const quickQuestions = document.getElementById('quickQuestions');

let isChatOpen = false;
let isWaiting = false;
let unreadCount = 0;

// Greeting message already in HTML - shown on first open

chatToggle.addEventListener('click', ()=>{
  isChatOpen = !isChatOpen;
  chatPanel.classList.toggle('open', isChatOpen);
  if(isChatOpen){
    unreadCount = 0;
    updateBadge();
    chatInput.focus();
  }
});

chatClose.addEventListener('click', ()=>{
  isChatOpen = false;
  chatPanel.classList.remove('open');
});

function updateBadge(){
  if(unreadCount > 0){
    chatBadge.textContent = unreadCount > 99 ? '99+' : unreadCount;
    chatBadge.style.display = 'flex';
  } else {
    chatBadge.style.display = 'none';
  }
}
updateBadge();

function scrollToBottom(){
  chatMessages.scrollTop = chatMessages.scrollHeight;
}

function addMessage(type, text){
  const div = document.createElement('div');
  div.className = 'msg ' + type;
  div.innerHTML = text;
  chatMessages.appendChild(div);
  scrollToBottom();
  return div;
}

function addTypingIndicator(){
  const div = document.createElement('div');
  div.className = 'msg bot';
  div.innerHTML = '<div class="typing-indicator"><span></span><span></span><span></span></div>';
  div.id = 'typingMsg';
  chatMessages.appendChild(div);
  scrollToBottom();
  return div;
}

function removeTypingIndicator(){
  const el = document.getElementById('typingMsg');
  if(el) el.remove();
}

// Send message to AI
async function sendMessage(text){
  if(isWaiting || !text.trim()) return;
  isWaiting = true;
  chatSend.disabled = true;

  // Display user message
  addMessage('user', escapeHtml(text));
  chatInput.value = '';

  // Show typing indicator
  const typing = addTypingIndicator();

  // Build conversation history — 只取有效非空内容
  const msgElements = chatMessages.querySelectorAll('.msg:not(#typingMsg)');
  const history = [];
  msgElements.forEach(el=>{
    const role = el.classList.contains('user') ? 'user' : 'assistant';
    const content = (el.textContent || '').trim();
    if(content) history.push({role, content});  // 跳过空内容
  });

  // Keep last 20 messages max
  const recentHistory = history.slice(-20);

  // 至少保证有一条用户消息
  if(recentHistory.length === 0){
    recentHistory.push({role:'user', content:text.trim()});
  }

  try{
    // AI亲子营聊天 API — 始终使用同源路径，Nginx 代理到 FastAPI 后端
    const API_URL = '/api/ai/chat';
    const response = await fetch(API_URL, {
      method: 'POST',
      headers: {'Content-Type':'application/json'},
      body: JSON.stringify({messages: recentHistory})
    });

    if(!response.ok){
      removeTypingIndicator();
      // 读取服务器错误详情用于调试
      let errDetail = '';
      try{
        const errText = await response.text();
        errDetail = ' (' + response.status + ': ' + errText.substring(0,100) + ')';
      }catch(e){}
      addMessage('bot', '抱歉😅，AI服务暂时不可用。' + errDetail + ' 请稍后重试或访问 <a href="http://airobot.zengqi.site/" style="color:#FFD700;">官网</a> 了解更多。');
      isWaiting = false;
      chatSend.disabled = false;
      return;
    }

    // Handle SSE stream
    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let botMsgDiv = null;
    let fullText = '';

    while(true){
      const {done, value} = await reader.read();
      if(done) break;
      const chunk = decoder.decode(value);
      const lines = chunk.split('\n');
      for(const line of lines){
        if(line.startsWith('data: ')){
          const jsonStr = line.slice(6);
          if(jsonStr === '[DONE]') continue;
          try{
            const parsed = JSON.parse(jsonStr);
            if(parsed.choices && parsed.choices[0] && parsed.choices[0].delta){
              const content = parsed.choices[0].delta.content;
              if(content){
                fullText += content;
                removeTypingIndicator();
                if(!botMsgDiv){
                  botMsgDiv = addMessage('bot', '');
                }
                // Render with markdown-like formatting
                botMsgDiv.innerHTML = formatBotText(fullText);
                scrollToBottom();
              }
            }
          }catch(e){/* skip malformed lines */}
        }
      }
    }

    if(!botMsgDiv && !fullText){
      removeTypingIndicator();
      addMessage('bot', '抱歉😅，我暂时无法回答这个问题。请换个问题试试，或访问 <a href="http://airobot.zengqi.site/" style="color:#FFD700;">官网</a> 了解更多。');
    }

  }catch(err){
    console.error('Chat error:', err);
    removeTypingIndicator();
    addMessage('bot', '网络连接失败📡，请检查网络后重试。');
  }

  isWaiting = false;
  chatSend.disabled = false;
  chatInput.focus();
}

function formatBotText(text){
  // Simple formatting: bold, emoji preservation, line breaks
  let formatted = escapeHtml(text);
  // Bold: **text**
  formatted = formatted.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
  // Newlines
  formatted = formatted.replace(/\n/g, '<br/>');
  // Links
  formatted = formatted.replace(/(https?:\/\/[^\s<>]+)/g, '<a href="$1" style="color:#FFD700;" target="_blank">$1</a>');
  return formatted;
}

function escapeHtml(str){
  const div = document.createElement('div');
  div.textContent = str;
  return div.innerHTML;
}

// Send button
chatSend.addEventListener('click', ()=>sendMessage(chatInput.value));

// Enter key
chatInput.addEventListener('keydown', e=>{
  if(e.key==='Enter' && !e.shiftKey){
    e.preventDefault();
    sendMessage(chatInput.value);
  }
});

// Quick question buttons
quickQuestions.addEventListener('click', e=>{
  const btn = e.target.closest('.quick-q');
  if(!btn) return;
  const q = btn.dataset.q;
  if(isChatOpen){
    sendMessage(q);
  } else {
    // Open chat first, then send
    isChatOpen = true;
    chatPanel.classList.add('open');
    setTimeout(()=>sendMessage(q), 400);
  }
  chatInput.focus();
});

// If chat is closed and bot sends a message, increment badge
// Watch for new bot messages when panel is closed
const msgObserver = new MutationObserver(()=>{
  if(!isChatOpen){
    const msgs = chatMessages.querySelectorAll('.msg.bot');
    const currentCount = msgs.length;
    if(currentCount > unreadCount + 1){ // +1 for initial greeting
      unreadCount = currentCount - 1;
      updateBadge();
    }
  }
});
msgObserver.observe(chatMessages, {childList:true, subtree:true});

// Show toggle button after first scene transition
const origGoToScene = goToScene;
goToScene = function(index, direction){
  origGoToScene(index, direction);
  if(index >= 1 && chatToggle.classList.contains('hidden')){
    chatToggle.classList.remove('hidden');
    // Auto-show badge hint
    unreadCount = 1;
    updateBadge();
  }
};

console.log('💬 AI聊天机器人已就绪 — 点击右下角🤖开始对话');

// ============================================================
//  Ambient Background Music — Web Audio API 生成
//  大气 · 轻松 · 欢快
//  v3: 最简可靠实现，直接在用户手势中创建 AudioContext
// ============================================================
const musicToggle = document.getElementById('musicToggle');
let audioCtx = null;
let musicPlaying = false;
let musicGain = null;
let masterDryGain = null;
let masterWetGain = null;
let activeOscs = [];
let activeTimers = [];
let musicStartedOnce = false;

const NOTE = {
  C3:130.81,D3:146.83,E3:164.81,F3:174.61,G3:196.00,A3:220.00,B3:246.94,
  C4:261.63,D4:293.66,E4:329.63,F4:349.23,G4:392.00,A4:440.00,B4:493.88,
  C5:523.25,D5:587.33,E5:659.25,F5:698.46,G5:783.99,A5:880.00,B5:987.77
};

const chordProgression = [
  ['C3','E3','G3','C4'],['G2','B3','D4','G4'],
  ['A2','C3','E3','A4'],['F2','A3','C4','F4'],
];

const melodyPhrases = [
  [{n:'C4',d:0.8},{n:'E4',d:0.4},{n:'G4',d:0.8},{n:'C5',d:1.2},{n:'G4',d:0.4},{n:'E4',d:0.8}],
  [{n:'G4',d:0.8},{n:'E4',d:0.4},{n:'D4',d:0.8},{n:'C4',d:1.2},{n:'D4',d:0.4},{n:'E4',d:0.8}],
  [{n:'E4',d:0.4},{n:'G4',d:0.4},{n:'A4',d:0.8},{n:'G4',d:0.4},{n:'E4',d:0.4},{n:'C4',d:0.8},{n:'D4',d:0.4},{n:'E4',d:0.8}],
  [{n:'D4',d:0.6},{n:'C4',d:0.6},{n:'A3',d:0.8},{n:'C4',d:1.2},{n:'F3',d:0.4},{n:'G3',d:0.8}],
];

let currentChord=0, currentPhrase=0;

// 创建混响
function createReverb(ctx,dur=2.5,decay=3){
  const len=ctx.sampleRate*dur;
  const buf=ctx.createBuffer(2,len,ctx.sampleRate);
  for(let ch=0;ch<2;ch++){const d=buf.getChannelData(ch);for(let i=0;i<len;i++)d[i]=(Math.random()*2-1)*Math.pow(1-i/len,decay);}
  const c=ctx.createConvolver();c.buffer=buf;return c;
}

// 播放音符
function playNote(ctx,freq,st,dur,gain=0.15,type='sine'){
  const o=ctx.createOscillator(),g=ctx.createGain();
  o.type=type;o.frequency.setValueAtTime(freq,st);
  g.gain.setValueAtTime(0,st);
  g.gain.linearRampToValueAtTime(gain,st+dur*0.12);
  g.gain.setValueAtTime(gain,st+dur*0.65);
  g.gain.linearRampToValueAtTime(0,st+dur);
  o.connect(g);g.connect(musicGain);
  o.start(st);o.stop(st+dur+0.1);
  activeOscs.push(o);
}

// 和弦层
function scheduleChord(ctx){
  const n=chordProgression[currentChord%4],d=4.5;
  n.forEach((x,i)=>playNote(ctx,NOTE[x],ctx.currentTime+i*0.04,d,0.08));
  const rt=n[0].replace(/[0-9]/,''),bo=parseInt(n[0].match(/\d/)[0])-1;
  if(NOTE[rt+bo]) playNote(ctx,NOTE[rt+bo],ctx.currentTime,d,0.06);
  currentChord++;
}

// 旋律层
function scheduleMelody(ctx){
  const p=melodyPhrases[currentPhrase%4];let t=ctx.currentTime+0.15;
  p.forEach(({n,d})=>{
    const dur=d*1.05,o=ctx.createOscillator(),g=ctx.createGain();
    o.type='triangle';o.frequency.setValueAtTime(NOTE[n],t);
    g.gain.setValueAtTime(0,t);g.gain.linearRampToValueAtTime(0.1,t+0.015);
    g.gain.exponentialRampToValueAtTime(0.06,t+dur*0.4);
    g.gain.linearRampToValueAtTime(0,t+dur);
    o.connect(g);g.connect(musicGain);o.start(t);o.stop(t+dur+0.05);
    activeOscs.push(o);t+=d*0.62;
  });
  currentPhrase++;
  const tid=setTimeout(()=>{if(musicPlaying)scheduleMelody(ctx);},(t-ctx.currentTime+0.8)*1000);
  activeTimers.push(tid);
}

// 节奏层
function scheduleTick(ctx){
  function tick(){
    if(!musicPlaying)return;
    const o=ctx.createOscillator(),g=ctx.createGain();
    o.type='sine';o.frequency.setValueAtTime(1200,ctx.currentTime);
    o.frequency.exponentialRampToValueAtTime(800,ctx.currentTime+0.15);
    g.gain.setValueAtTime(0,ctx.currentTime);g.gain.linearRampToValueAtTime(0.025,ctx.currentTime+0.008);
    g.gain.exponentialRampToValueAtTime(0.001,ctx.currentTime+0.22);
    o.connect(g);g.connect(musicGain);o.start(ctx.currentTime);o.stop(ctx.currentTime+0.28);
    activeOscs.push(o);
    const tid=setTimeout(tick,1800+Math.random()*1200);activeTimers.push(tid);
  }
  const tid=setTimeout(tick,400);activeTimers.push(tid);
}

// 清理所有
function killAllSound(){
  activeTimers.forEach(t=>clearTimeout(t));activeTimers=[];
  activeOscs.forEach(o=>{try{o.stop()}catch(e){}});activeOscs=[];
}

/** 启动音乐 — 必须在用户手势中直接调用 */
function startMusic(){
  if(musicPlaying) return;

  // 在用户手势中创建 AudioContext，保证状态为 running
  if(!audioCtx){
    try{
      audioCtx = new (window.AudioContext||window.webkitAudioContext)();
    }catch(e){
      console.warn('Web Audio API 不可用:',e);
      musicToggle.style.display='none';
      return;
    }
  }

  // 如被挂起则恢复
  if(audioCtx.state==='suspended') audioCtx.resume();

  // 初始化音频路由（仅首次）
  if(!musicGain){
    musicGain=audioCtx.createGain();
    const reverb=createReverb(audioCtx);
    masterDryGain=audioCtx.createGain();masterDryGain.gain.value=0.7;
    masterWetGain=audioCtx.createGain();masterWetGain.gain.value=0.3;
    musicGain.connect(masterDryGain);musicGain.connect(reverb);
    reverb.connect(masterWetGain);
    masterDryGain.connect(audioCtx.destination);
    masterWetGain.connect(audioCtx.destination);
  }

  musicGain.gain.cancelScheduledValues(audioCtx.currentTime);
  musicGain.gain.setValueAtTime(0.35,audioCtx.currentTime);
  currentChord=0;currentPhrase=0;
  musicPlaying=true;musicStartedOnce=true;
  musicToggle.classList.add('playing');
  musicToggle.title='暂停音乐';

  scheduleChord(audioCtx);
  const ctid=setInterval(()=>{if(musicPlaying)scheduleChord(audioCtx);},4500);
  activeTimers.push(ctid);
  scheduleMelody(audioCtx);
  scheduleTick(audioCtx);
  console.log('🎵 音乐已开始 state='+audioCtx.state);
}

/** 停止音乐 */
function stopMusic(){
  if(!musicPlaying)return;
  musicPlaying=false;
  musicToggle.classList.remove('playing');
  musicToggle.title='播放音乐';
  if(musicGain&&audioCtx){
    musicGain.gain.cancelScheduledValues(audioCtx.currentTime);
    musicGain.gain.linearRampToValueAtTime(0,audioCtx.currentTime+0.3);
  }
  killAllSound();
  setTimeout(()=>{killAllSound();if(audioCtx&&audioCtx.state==='running')audioCtx.suspend();},400);
}

/** 按钮切换 */
musicToggle.addEventListener('click',(e)=>{
  e.stopPropagation();
  if(musicPlaying){stopMusic();}else{startMusic();}
});

// ★ 自动启动：先从静默 audio 标签借道，浏览器允许即自动播放
const silentAudio = document.getElementById('silentAudio');

function bootstrapMusic(){
  if(musicStartedOnce) return;
  startMusic();
}

// 方案1: 静默 audio 标签的 play 事件（部分浏览器允许 autoplay 静默音频）
if(silentAudio){
  silentAudio.addEventListener('play', ()=>{
    if(!musicStartedOnce) startMusic();
  });
  // 也尝试程序化播放（会被浏览器拒绝，但 try 无害）
  const playPromise = silentAudio.play();
  if(playPromise){
    playPromise.then(()=>{
      if(!musicStartedOnce) startMusic();
    }).catch(()=>{
      // 浏览器拒绝自动播放，正常 — 等待用户手势
    });
  }
}

// 方案2: splash 页面交互 — 点击时启动
stage.addEventListener('click', function(e){
  if(!musicStartedOnce && currentScene===0 && e.target.tagName!=='A'){
    startMusic();
  }
});

// 方案3: 键盘 — 空格键启动演示时同步启动
document.addEventListener('keydown', function(e){
  if(!musicStartedOnce && currentScene===0 && (e.key===' '||e.key==='Spacebar')){
    startMusic();
  }
});

// 方案4: 页面加载完成后立即尝试（部分浏览器允许在 onload 前创建的 AudioContext）
window.addEventListener('load', ()=>{
  if(!musicStartedOnce) startMusic();
});
// 方案5: 延迟再试（有些浏览器在短暂延迟后放宽限制）
setTimeout(()=>{if(!musicStartedOnce) startMusic();}, 1000);
setTimeout(()=>{if(!musicStartedOnce) startMusic();}, 3000);

console.log('🎵 背景音乐 v4 — 自动播放+静默启动+用户手势 多重策略已就绪');
</script>
</body>
</html>
