3:I[4707,[],""]
5:I[36423,[],""]
7:I[88003,["4337","static/chunks/91d50c91-c935f1c65821902f.js","7279","static/chunks/b1644e8c-d749f036b947b0a4.js","4304","static/chunks/4304-75b83db16b0d34ab.js","3084","static/chunks/3084-31efe02951f135b2.js","2273","static/chunks/2273-0ea4ab052b9b0cfd.js","575","static/chunks/575-dcb82cf3e64bc6db.js","9010","static/chunks/9010-023e265f797ceb68.js","4450","static/chunks/4450-b500ef111eded326.js","8003","static/chunks/8003-77a01866b8e7e6e5.js","989","static/chunks/989-00a9380fdf607821.js","1326","static/chunks/1326-2bdf304cc7ffd395.js","218","static/chunks/218-d2272020a411d99d.js","3674","static/chunks/3674-f61861513513805f.js","6489","static/chunks/6489-7d70453ac04f1a63.js","3482","static/chunks/3482-39727346ba3389e1.js","7628","static/chunks/7628-794514fd8ea38990.js","5922","static/chunks/5922-e91b60ad05c19631.js","6883","static/chunks/app/%5Blocale%5D/home/page-8993690fab7f319e.js"],""]
8:I[61103,["8003","static/chunks/8003-77a01866b8e7e6e5.js","3185","static/chunks/app/layout-74b4ccf534333157.js"],"UserProvider"]
9:I[49197,["8003","static/chunks/8003-77a01866b8e7e6e5.js","3185","static/chunks/app/layout-74b4ccf534333157.js"],"Analytics"]
4:["locale","zh","d"]
0:["D8zvvTkMbyMAJHbCbJD7o",[[["",{"children":[["locale","zh","d"],{"children":["home",{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],["",{"children":[["locale","zh","d"],{"children":["home",{"children":["__PAGE__",{},[["$L1","$L2",null],null],null]},[null,["$","$L3",null,{"parallelRouterKey":"children","segmentPath":["children","$4","children","home","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[null,"$L6"],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/04a2b1dee28c4433.css","precedence":"next","crossOrigin":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/_next/static/css/af7c04e52a18620f.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"bg-gray-950 text-gray-100","children":[["$","$L7",null,{"id":"theme-init","strategy":"beforeInteractive","children":"\n            (() => {\n              try {\n                var path = window.location.pathname;\n                var isHome = path === '/' || path.endsWith('/home') || /\\/(zh|en)\\/home(\\/|$)/.test(path);\n                if (isHome) {\n                  // 首页固定深色主题\n                  document.documentElement.dataset.theme = 'dark';\n                  document.documentElement.style.colorScheme = 'dark';\n                  return;\n                }\n                var stored = localStorage.getItem('site-theme');\n                var theme = stored || 'light';\n                document.documentElement.dataset.theme = theme;\n                document.documentElement.style.colorScheme = theme;\n              } catch (e) {\n                document.documentElement.dataset.theme = 'light';\n                document.documentElement.style.colorScheme = 'light';\n              }\n            })();\n          "}],["$","$L7",null,{"src":"https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5639745717417263","strategy":"afterInteractive","crossOrigin":"anonymous"}],["$","$L7",null,{"src":"https://www.googletagmanager.com/gtag/js?id=G-C6PN3G0S7V","strategy":"afterInteractive"}],["$","$L7",null,{"id":"google-analytics","strategy":"afterInteractive","children":"\n            window.dataLayer = window.dataLayer || [];\n            function gtag(){dataLayer.push(arguments);}\n            gtag('js', new Date());\n            gtag('config', 'G-C6PN3G0S7V');\n          "}],["$","$L7",null,{"id":"organization-jsonld","type":"application/ld+json","dangerouslySetInnerHTML":{"__html":"{\"@context\":\"https://schema.org\",\"@type\":\"Organization\",\"name\":\"SvgAnimate\",\"url\":\"https://svganimate.ai\",\"logo\":\"https://svganimate.ai/logo.png\"}"}}],["$","$L8",null,{"children":["$","$L3",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}],["$","$L9",null,{}]]}]}]],null],null],["$La",null]]]]
b:I[47279,["1203","static/chunks/app/%5Blocale%5D/layout-da3cb07dac8804ed.js"],"I18nProvider"]
c:I[65373,["1203","static/chunks/app/%5Blocale%5D/layout-da3cb07dac8804ed.js"],"NotificationProvider"]
d:I[78537,["1203","static/chunks/app/%5Blocale%5D/layout-da3cb07dac8804ed.js"],"LocaleAutoRedirect"]
6:["$","$Lb",null,{"locale":"zh","dictionary":{"languageName":"中文","languageSwitcher":{"tooltip":"切换语言","languages":{"zh":"中文","en":"English"}},"themeSwitcher":{"tooltip":"切换主题","light":"浅色","dark":"深色"},"actions":{"search":"搜索","clear":"清除"},"brand":{"title":"SvgAnimate 动画工作室","subtitle":"输入关键词，快速查找你需要的矢量动画","searchPlaceholder":"搜索动画，例如：'排序算法' 或 'TCP'...","searchButton":"搜索","hotLabel":"🔥 热门搜索:","hotKeywords":["算法","网络","天文"]},"home":{"featuredTitle":"精选推荐","searchResultPrefix":"的搜索结果","hottest":"最热门","noResults":"没有找到相关动画","clearSearch":"清除搜索","loadMore":"加载更多","loadingMore":"加载中...","noMore":"没有更多数据了","footerCopy":"© 2025 AI SVG Animation Studio. All rights reserved.","viewAll":"查看全部网页动画案例","privacyPolicy":"隐私政策","termsOfService":"服务条款","contactMe":"联系我","contactEmailLabel":"或邮箱","newHero":{"title":"一句话生成专业知识讲解视频与动画","subtitle":"AI自动编写完整HTML视频脚本、分镜预览，专业视频一键直出\n数十种SVG动画模版自由选择，一键复制","ctaHint":"让内容动起来","primaryCta":"立即体验","miniCenterLabel":"创作中心示意","titleLine1":"一句话生成","titleLine2":"专业知识讲解","titleLine3":"HTML视频、SVG动画","features":["脚本自动扩充","分镜可编辑","个性化配音、字幕"]},"scenariosSection":{"title":"适合场景","subtitle":"","viewMore":"查看更多实用场景","items":[{"key":"knowledge","title":"知识讲解","description":"趣味动效、丰富的画面，缜密的逻辑结构，让你轻松成为知识博主","cta":"立即体验"},{"key":"classroom","title":"课堂教学","description":"让枯燥、抽象的知识点变成有趣、立体的案例\n解放备课压力，系统全面得讲透每一个知识点","cta":"立即体验"},{"key":"story","title":"故事讲解","description":"清晰的时间线、娓娓道来的叙事结构，多样化的语音选择，让你的故事更加打动人心","cta":"立即体验"}]},"midCta":{"title":"无需编码、没有提示词门槛、不用专业剪辑软件","subtitle":"无论是专业知识讲解、过程演示视频，还是趣味动画、网页LOGO动画都能在这里一键生成","buttonText":"免费开始"}},"sidebar":{"home":"首页","creation":"动画创作","browse":"分类浏览","profile":"个人中心"},"categories":{"home":"首页","create":"动画创作","svg-loading-animation":"加载动画","svg-logo-animation":"Logo动画","text-svg-animation":"文字动画","svg-line-drawing":"线条绘制动画","hand-drawn-animation":"手绘动画","interactive-svg-animation":"交互式动画","flowchart-animation":"流程图动画","svg-map-animation":"地图动画","svg-mini-game":"网页小游戏","stem-knowledge-animation":"理工科科普","data-visualization-animation":"数据可视化动画","html-video":"HTML视频","stick-figure-animation":"火柴人动画","product-demo-animation":"产品演示动画","dynamic-view-webpage":"图文网页","3d-animation":"3D动画","others":"其他"},"categoryPage":{"searchPlaceholder":"搜索分类内动画...","empty":"没有动画哦~","countSuffix":"个动画"},"statuses":{"loading":"正在加载动画数据...","loadError":"无法加载动画数据，请检查数据库服务或刷新重试。"},"login":{"title":"请登录后继续","description":"登录后即可创作动画与视频，查看和编辑作品，并支持导出GIF动图和MP4视频。","github":"GitHub 登录","google":"Google 登录","cancel":"取消","notLogged":"未登录","clickToLogin":"点击登录"},"templateCard":{"missing":"动画组件未找到","hoverToPlay":"悬停播放","previewHint":"移开即停止播放"},"profile":{"label":"个人中心"},"creation":{"label":"动画创作"},"breadcrumbs":{"back":"上一页"},"hotSearchLabel":"热门搜索","hero":{"version":"基于Gemini 3.1 Pro","title1":"SVG 动画生成器，","title2":"一句话生成 SVG 动画与 HTML 视频","subtitle":"无需编写代码，无需学习专业软件，输入您的需求，AI 即刻为您生成","subtitle2":"SVG动画","subtitle3":"、HTML 视频与可直接落地的网页动效。","svgTooltipTitle":"什么是矢量动画？","svgTooltipDesc":"矢量动画基于数学公式绘制，无论放大多少倍都不会失真。相比传统视频，文件更小、加载更快、可无限缩放。非常适合网页展示、教育演示、品牌宣传等场景。","placeholder":"描述你的动画... 例如：'太阳系行星运动动画'","startButton":"开始生成","navigating":"跳转中...","creatorPrefix":"适合","creatorBadge":"知识博主与教育创作者","example1":"加载动效","example2":"品牌 Logo","example3":"数据展示","example4":"交互开关","features":{"infiniteZoom":"无限放大","ultra4K":"4K超清","oneClickExport":"一键导出","massiveCases":"海量案例"},"freeTrialHint":"从免费试用开始","panel":{"tipsTitle":"提示词技巧","examplesTitle":"示例提示词","simpleLabel":"简单版","detailedLabel":"详细版","detailedBadge":"详细版 · 推荐","useSimple":"使用简单版","useDetailed":"使用详细版","showcaseTitle":"适用场景"},"contentExamples":[{"label":"物理运动","title":"物理运动动画","description":"通过矢量动画展示物理规律，让抽象概念变得直观易懂","tips":["描述清楚运动轨迹和速度","说明物体之间的相对关系","可以添加轨道、箭头等辅助元素"],"simpleExample":"地球围绕太阳运动，月亮围绕地球运动","detailedExample":"创建一个太阳系模型：中心是一个黄色的太阳，地球沿着椭圆轨道围绕太阳公转，同时月亮围绕地球旋转。地球是蓝色的，月亮是灰色的，轨道用虚线表示。","showcase":"适用于：教育科普、物理演示、天文展示"},{"label":"知识科普","title":"知识科普动画","description":"将复杂的工作原理可视化，帮助观众快速理解技术细节","tips":["分步骤描述工作流程","突出关键部件和动作","使用专业术语提高准确性"],"simpleExample":"机械硬盘读取数据","detailedExample":"展示机械硬盘的工作原理：磁盘高速旋转，磁头臂移动到指定位置，磁头在盘片表面悬浮读取数据。用不同颜色标注磁盘、磁头、磁头臂等关键部件，并显示数据流动的路径。","showcase":"适用于：技术讲解、产品演示、培训教材"},{"label":"视频片头","title":"视频片头动画","description":"创建专业的品牌片头，提升视觉冲击力和品牌认知度","tips":["明确文字变换的顺序和效果","描述旋转、缩放等动画细节","可参考知名品牌的片头风格"],"simpleExample":"SvgAnimate文字旋转变为\"动画工作室\"","detailedExample":"创建一个专业的片头动画：深蓝色背景，一行大写英文字母SvgAnimate从屏幕右侧滚动进入，字母呈3D效果并带有金色光泽。字母到达中心后开始360度旋转，旋转过程中逐渐变形，最终变为中文\"动画工作室\"四个大字，字体优雅大气。","showcase":"适用于：品牌宣传、视频开场、活动片头"},{"label":"动画人物","title":"动画人物演示","description":"用简洁的线条和形状表现人物动作，突出节奏感和故事性","tips":["描述角色外观与颜色","指出动作节奏与镜头运动","可添加分镜或情绪变化"],"simpleExample":"小人跑步，背景有滚动的山和云","detailedExample":"在一个深色渐变背景上，设计一个极简风格的小人奔跑动画。小人由几何图形组成，线条流畅。跑动时双腿交替摆动，手臂随之摆动，地面有动态的阴影。背景山脉和云朵缓慢向左移动制造速度感。","showcase":"适用于：产品动效、科普演示、UI 动画示例"}]},"header":{"gallery":"案例","learn":"学习","tools":"工具","blog":"博客","membership":"价格","profile":"个人中心","logout":"退出登录","startCreating":"开始创作","login":"登录","quotaUsage":"积分","history":"记录"},"gallery":{"title":"网页动画案例库","subtitle":"浏览精选的网页动画案例","all":"全部","prev":"上一页","next":"下一页","adLabel":"广告"},"membership":{"badge":"简单透明的定价","title1":"选择您的","title2":"套餐","subtitle":"从免费开始，随需扩展。所有套餐都包含核心AI功能，配额和能力逐级递增。","loading":"加载中...","mostPopular":"最受欢迎","perMonth":"/月","perPurchase":"/10次","freePlanDesc":"体验基础功能","litePlanDesc":"按需购买，可随时重复购买","proPlanDesc":"专业用户的最佳选择","maxPlanDesc":"高级用户畅享无限","currentPlan":"当前套餐","purchaseButton":"立即购买","featuresTitle":"功能权益:","quotaLabel":"积分","quotaPeriod":"每月","quotaPeriodNote":"积分不累积，次月清零","quotaPeriodOnce":"不限有效期","watermarkLabel":"导出","watermarkYes":"有","watermarkNo":"无","watermarkSuffix":"水印","watermarkFormats":"GIF和视频","resolutionLabel":"支持分辨率","paymentTitle":"扫码支付","paymentAmount":"金额:","paymentInstruction":"请使用微信扫描二维码完成支付","paymentTimeLeft":"剩余时间:","paymentCancel":"取消支付","paymentSuccess":"支付成功","paymentSuccessDesc":"会员权益已生效","paymentExpired":"订单已过期","paymentExpiredDesc":"请重新创建订单","paymentClose":"关闭","alertLogin":"请先登录","alertSessionExpired":"登录已过期，请重新登录","alertOrderFailed":"创建订单失败","alertPurchaseFailed":"购买失败，请稍后重试","alertPurchaseSuccess":"购买成功！","redeemTitle":"兑换会员","redeemSubtitle":"输入会员兑换码领取对应套餐权益。","redeemPlaceholder":"请输入兑换码（区分大小写）","redeemButton":"领取会员","redeemProcessing":"兑换中...","redeemInvalid":"兑换码格式不正确","redeemFailed":"兑换失败，请稍后重试","redeemSuccess":"兑换成功，会员权益已生效","redeemExpand":"展开","redeemCollapse":"收起","perYear":"/年","subscribeButton":"订阅","billingCycleLabel":"计费周期","monthly":"月度","yearly":"年度","saveBadge":"省","subscription":"订阅管理","subscriptionStatus":"订阅状态","subscriptionActive":"活跃","subscriptionCancelled":"已取消","subscriptionPastDue":"逾期","nextBillingDate":"下次扣款日期","cancelSubscription":"取消订阅","reactivateSubscription":"恢复订阅","managePaymentMethod":"管理支付方式","billingHistory":"账单历史","cancelAtPeriodEnd":"将在周期结束时取消","subscriptionRemaining":"您的订阅将保持有效直到","subscriptionCancelSuccess":"订阅取消成功","subscriptionReactivateSuccess":"订阅恢复成功","alertSubscribeSuccess":"订阅激活成功！","alertSubscribeFailed":"创建订阅失败","alertActiveSubscription":"您已有活跃订阅","alertProcessing":"支付处理中..."},"learn":{"title":"AI 网页动画学习指南","subtitle":"学习如何用 AI 创建网页动画，从 SVG 动效到交互网页与产品演示。","metaDescription":"学习如何用 AI 创建网页动画：从 SVG 动效到交互网页、提示词方法和高质量案例。","hero":{"badge":"网页动效实验室","title":"欢迎使用","titleAccent":"AI 网页动画指南","description":"学习什么是网页动画、SVG 动画在其中扮演什么角色、如何用 AI 生成交互式动效，并把提示词转成可落地的网页体验。","featurePills":["提示词生成动效","SVG 与 HTML 输出","支持交互体验","可直接商用"],"primaryCta":"开始创作","secondaryCta":"查看案例","previewLabel":"实时动效预览","previewTag":"秒级生成","previewStats":[{"title":"可编辑输出","description":"SVG 或 HTML"},{"title":"顺滑动效","description":"60fps体验"},{"title":"交互就绪","description":"面向网页场景"}],"highlights":[{"title":"提示词到动效","description":"描述想法即可快速生成可用结果。"},{"title":"风格可控","description":"颜色、时长、缓动随心调。"},{"title":"网页原生输出","description":"支持 SVG 与 HTML 场景。"},{"title":"可直接商用","description":"适配网站、应用、营销页和演示。"}]},"showcaseSection":{"title":"你能做出什么效果","subtitle":"从 SVG 动效到交互网页，AI 网页动画远不止一种输出形式。","videoIntro":"视频片头动画","videoIntroDesc":"动态文字Logo、转场特效、Slogan 演绎，让视频开场更具吸睛力。","brandShowcase":"品牌展示动画","brandShowcaseDesc":"品牌标识的动态演绎、呼吸灯效果、描边生长，强化品牌记忆点。","dataVisualization":"数据可视化","dataVisualizationDesc":"动态增长的柱状图、折线图、仪表盘，让枯燥的数据生动直观。","knowledgeEducation":"知识科普","knowledgeEducationDesc":"物理原理演示、天文天体运动、化学分子结构，通过动画讲解复杂概念。","specialEffects":"特效动画","specialEffectsDesc":"爆炸、烟花、魔法粒子、天气效果（雨雪），增强画面的视觉冲击力。","gameAnimation":"游戏动画","gameAnimationDesc":"角色待机、跳跃动作、道具拾取反馈、UI 面板弹窗，轻量级游戏开发的最佳选择。"},"labSection":{"title":"网页动画实验室","subtitle":"实时预览 SVG、HTML 与交互式网页体验中常见的动效模式。","controlsTitle":"选择一种效果","effects":[{"id":"motion","title":"位移运动","description":"平滑的位置变化"},{"id":"scale","title":"弹性缩放","description":"呼吸或心跳效果"},{"id":"rotate","title":"中心旋转","description":"加载或自转动效"},{"id":"stroke","title":"路径描边","description":"线条逐步绘制"},{"id":"glow","title":"霓虹发光","description":"高亮与光晕"},{"id":"morph","title":"形状变形","description":"形态平滑过渡"}]},"whatIsSection":{"title":"什么是网页动画？","content":["网页动画是指直接运行在浏览器里的动效体验，包括 SVG 动画、HTML 页面动效、交互式产品演示、数据可视化和滚动叙事等。它能为网站和应用增加反馈感、节奏感与理解效率。","SVG 动画是网页动画里的一个重要分支，特别适合图标、加载器、示意图和轻量级矢量动效；而完整的交互页面、UI 行为和复杂网页体验，往往更适合由 HTML、CSS 和 JavaScript 来承载。","AI 网页动画生成器让你用自然语言描述想要的网页体验，再把描述转成可预览、可导出、可复用的浏览器原生动效。这可以是 SVG 输出，也可以是交互网页或产品演示。"],"benefits":["网页原生交付 - 动效直接在浏览器运行，而不只是依赖视频素材","输出形式灵活 - 既可用 SVG 做矢量动效，也可用 HTML 做交互网页","SEO 友好 - 相比纯视频内容，更容易被搜索引擎理解和索引","可编辑性强 - 生成后仍可继续调整颜色、时序、布局和交互","性能优秀 - 轻量级网页动效加载更快，交互反馈更及时","交互性强 - 支持点击、悬停、筛选、分页、切换等行为","跨平台兼容 - 适配现代浏览器与不同屏幕尺寸","易于集成 - 可嵌入落地页、产品页面、文档或演示场景"]},"howToSection":{"title":"如何生成高质量网页动画","intro":"想用 AI 做出高质量网页动画，关键在于让提示词贴近最终想要的网页体验。下面是更适合 Web Animation 的流程。","steps":[{"title":"明确动画目标","description":"先确定是 SVG 加载器、产品演示、落地页交互，还是数据叙事页面。目标越清晰，生成结果越稳定。"},{"title":"描述主体与动作","description":"写清主体元素、运动方式，以及是否需要点击、悬停、切换、滚动等交互行为，帮助 AI 更准确理解需求。"},{"title":"加入时长与缓动","description":"指定动画时长、缓动曲线和循环方式，让动效节奏更自然。"},{"title":"锁定视觉风格","description":"说明配色、字体、线条、留白和整体质感，比如极简、科技、编辑感、仪表盘风格等。"},{"title":"多轮优化","description":"根据生成结果微调提示词，逐步优化节奏、布局、动线和交互细节。"},{"title":"导出并应用","description":"多设备预览后，根据场景导出 SVG、视频或 HTML 页面，并接入你的实际项目。"}]},"promptFormula":{"title":"高质量提示词公式","description":"用结构化提示词，让模型更快理解你的动效意图。","tokens":["主体","动作","风格","颜色","时长","缓动","循环"],"exampleLabel":"示例提示词","example":"创建一个发光的圆形加载器，橙到青的渐变，顺时针平滑旋转，2秒一圈，ease-in-out，无限循环。"},"tipsSection":{"title":"专业提示词技巧","subtitle":"用这些实践技巧，让网页动画更流畅、更清晰、更接近真实产品体验。"},"examplesSection":{"title":"精选案例与提示词","subtitle":"查看案例成品风格，直接复用高质量提示词。","filterAll":"全部","viewPrompt":"查看提示词","hidePrompt":"收起提示词","tryPrompt":"使用此提示词创作","previewLabel":"成品预览"},"ctaSection":{"title":"准备好创作你的第一个网页动画了吗？","subtitle":"现在就用 AI 创建 SVG 动效、交互网页与可直接落地的网页体验。","buttonText":"开始创作"},"faqSection":{"title":"常见问题","items":[{"question":"什么是HTML视频？","answer":"HTML视频是一种用网页技术构建的视频形式。你只需要输入一个主题或描述，系统就会自动生成完整逐字稿、分镜、旁白和对应的 HTML 场景画面，适合做讲解视频、产品演示和故事化内容。"},{"question":"什么是网页动画？","answer":"网页动画是直接运行在浏览器中的动效体验，包括 SVG 动画、UI 交互动效、产品演示页、数据可视化和带交互的网页内容。"},{"question":"SVG 动画和网页动画有什么关系？","answer":"SVG 动画是网页动画的一种，特别适合矢量图标、示意图、加载器等轻量内容；网页动画则是更大的概念，还包括 HTML 页面动效、交互逻辑和完整的浏览器体验。"},{"question":"什么是 AI 网页动画生成器？","answer":"AI 网页动画生成器通过文字提示直接生成适用于浏览器的动效内容。根据需求不同，它可以输出 SVG 动画、交互 HTML 页面、产品演示或其他网页动效结果。"},{"question":"需要编程基础吗？","answer":"不需要，你只要描述动效即可。懂一些设计概念会让结果更好，但不是必需。"},{"question":"如何写出好的提示词？","answer":"写清主体、交互方式、动作、风格、颜色、时长、缓动和循环。例如：'创建一个产品头图区域，卡片轻微浮动，滚动时逐步显现，橙色高亮，整体简洁有科技感'。"},{"question":"生成的动画可以商用吗？","answer":"可以，生成的动效归你所有，可用于商业或个人项目。"},{"question":"可以导出哪些格式？","answer":"根据不同场景，支持导出 GIF、MP4 视频和 HTML 页面。"},{"question":"导出的文件出现异常怎么办？","answer":"如果导出视频无法播放或者与网站中看到的效果不一致，请选择导出视频菜单下的「直接录屏」功能，将进行所见即所得的录屏导出，推荐使用Chrome浏览器使用此项功能。"},{"question":"我创作的动画会被别人看到吗？","answer":"系统保护您的隐私，除非您主动选择公开，否则您的动画只有您自己可以看到。"},{"question":"生成结果不满意怎么办？","answer":"继续优化提示词，补充更清晰的动作、布局、交互和风格描述，多次迭代后会越来越接近预期。"},{"question":"不适合生成哪些类型动画？","answer":"SVG动画是基于代码生成的动画，适合包括点、线、面、体等几何元素组成的图像，可以抽象表达事物，但不适合生成现实风格的图像"}]}},"notifications":{"title":"通知中心","empty":"暂无通知","loading":"加载中...","markAllRead":"全部已读","viewDetail":"查看详情","gotIt":"知道了"}},"children":["$","$Lc",null,{"children":[["$","$Ld",null,{"locale":"zh"}],["$","$L3",null,{"parallelRouterKey":"children","segmentPath":["children","$4","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]]}]}]
a:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"SVG动画生成器 – AI矢量动画与HTML视频工具 2026"}],["$","meta","3",{"name":"description","content":"用AI生成SVG动画与HTML视频——Logo展示、加载动效、图表、讲解分镜。支持导出SVG、GIF、MP4。注册赠送免费试用积分。"}],["$","link","4",{"rel":"canonical","href":"https://svganimate.ai/zh/home"}],["$","link","5",{"rel":"alternate","hrefLang":"zh","href":"https://svganimate.ai/zh/home"}],["$","link","6",{"rel":"alternate","hrefLang":"en","href":"https://svganimate.ai/en/home"}],["$","link","7",{"rel":"alternate","hrefLang":"x-default","href":"https://svganimate.ai/en/home"}],["$","link","8",{"rel":"icon","href":"/icon.ico?fd240352ad5c4cdf","type":"image/x-icon","sizes":"256x256"}]]
1:null
e:I[8343,["4337","static/chunks/91d50c91-c935f1c65821902f.js","7279","static/chunks/b1644e8c-d749f036b947b0a4.js","4304","static/chunks/4304-75b83db16b0d34ab.js","3084","static/chunks/3084-31efe02951f135b2.js","2273","static/chunks/2273-0ea4ab052b9b0cfd.js","575","static/chunks/575-dcb82cf3e64bc6db.js","9010","static/chunks/9010-023e265f797ceb68.js","4450","static/chunks/4450-b500ef111eded326.js","8003","static/chunks/8003-77a01866b8e7e6e5.js","989","static/chunks/989-00a9380fdf607821.js","1326","static/chunks/1326-2bdf304cc7ffd395.js","218","static/chunks/218-d2272020a411d99d.js","3674","static/chunks/3674-f61861513513805f.js","6489","static/chunks/6489-7d70453ac04f1a63.js","3482","static/chunks/3482-39727346ba3389e1.js","7628","static/chunks/7628-794514fd8ea38990.js","5922","static/chunks/5922-e91b60ad05c19631.js","6883","static/chunks/app/%5Blocale%5D/home/page-8993690fab7f319e.js"],"AppPageClient"]
f:T34572,<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Linux内核超级漏洞：Copy Fail 深度解析</title>
  <style>
    @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap');
    @font-face {
      font-family: "SVGVideoAlimamaShuHei";
      src:
        url("/fonts/AlimamaShuHeiTi-Bold.woff2") format("woff2"),
        url("/fonts/AlimamaShuHeiTi-Bold.woff") format("woff"),
        url("/fonts/AlimamaShuHeiTi-Bold.ttf") format("truetype"),
        local("Alimama ShuHeiTi Bold"),
        local("Alimama ShuHeiTi"),
        local("AlimamaShuHeiTi-Bold"),
        local("AlimamaShuHeiTi");
      font-display: swap;
      font-weight: 700;
      font-style: normal;
    }
    :root {
      color-scheme: dark;
      --bg: #202020;
      --fg: #e2e8f0;
      --muted: #94a3b8;
      --card: rgba(255, 255, 255, 0.05);
      --border: rgba(255, 255, 255, 0.12);
      --sv-editor-height: 50vh;
      --sv-font-display-cn: "JetBrains Mono", "Courier New", Consolas, monospace;
      --sv-font-body-cn: "JetBrains Mono", "Courier New", Consolas, monospace;
      --sv-font-mono: "SFMono-Regular", "JetBrains Mono", "Fira Code", "Courier New", monospace;
      --sv-stage-perspective: 900px;
        --sv-trans-enter-opacity: 0;
        --sv-trans-enter-transform: rotateY(90deg);
        --sv-trans-enter-filter: blur(6px);
        --sv-trans-active-opacity: 1;
        --sv-trans-active-transform: rotateY(0deg);
        --sv-trans-active-filter: blur(0px);
        --sv-trans-exit-opacity: 0;
        --sv-trans-exit-transform: rotateY(-90deg);
        --sv-trans-exit-filter: blur(4px);
        --sv-trans-duration: 0.65s;
        --sv-trans-ease: cubic-bezier(0.36, 0, 0.66, 1);
    }
    * { box-sizing: border-box; }
    html, body {
      margin: 0; width: 100%; height: 100%; overflow: hidden;
      background: var(--bg);
      color: var(--fg);
      font-family: var(--sv-font-body-cn);
    }
    #app { width: 100%; height: 100%; display: flex; flex-direction: column; }
    #viewport { position: relative; flex: 1; min-height: 0; overflow: hidden; }
    #stage {
      position: relative; width: 100%; height: 100%; overflow: hidden;
      perspective: var(--sv-stage-perspective, none);
      perspective-origin: 50% 50%;
    }
    .scene {
      position: absolute; inset: 0; overflow: hidden;
      backface-visibility: hidden;
      -webkit-backface-visibility: hidden;
      opacity: var(--sv-trans-enter-opacity, 0); pointer-events: none;
      transform: var(--sv-trans-enter-transform, translateX(var(--scene-enter-offset, 56px)) scale(0.96));
      filter: var(--sv-trans-enter-filter, blur(10px));
      transition: opacity var(--sv-trans-duration, .55s) var(--sv-trans-ease, cubic-bezier(.22,1,.36,1)), transform var(--sv-trans-duration, .55s) var(--sv-trans-ease, cubic-bezier(.22,1,.36,1)), filter var(--sv-trans-duration, .55s) ease;
      will-change: opacity, transform, filter;
      z-index: 1;
    }
    .scene.scene-active {
      opacity: var(--sv-trans-active-opacity, 1); pointer-events: auto;
      transform: var(--sv-trans-active-transform, translateX(0) scale(1));
      filter: var(--sv-trans-active-filter, blur(0px));
      z-index: 3;
    }
    .scene.scene-exit {
      opacity: var(--sv-trans-exit-opacity, 0); pointer-events: none;
      transform: var(--sv-trans-exit-transform, translateX(var(--scene-exit-offset, -56px)) scale(0.96));
      filter: var(--sv-trans-exit-filter, blur(10px));
      z-index: 2;
    }
    .scene-placeholder {
      height: 100%; border: 1px dashed var(--border); border-radius: 20px; background: var(--card);
      display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: var(--muted);
    }
    .sv-scene-root { width: 100%; height: 100%; position: relative; overflow: hidden; }
    .scene-placeholder-title { font-size: 28px; color: var(--fg); font-weight: 700; }
    [data-step] { transition: opacity .35s ease, transform .35s ease, filter .35s ease; }
    #sv-controls {
      background: rgba(19, 19, 19, 0.95);
      border-top: 1px solid rgba(255,255,255,0.08);
      padding: 8px 12px 10px;
      display: flex;
      flex-direction: column;
      gap: 8px;
      backdrop-filter: blur(8px);
      flex-shrink: 0;
    }
    .sv-progress-wrap {
      position: relative;
      height: 22px;
      display: flex;
      align-items: center;
      cursor: pointer;
    }
    .sv-progress-track {
      width: 100%;
      height: 4px;
      border-radius: 999px;
      background: rgba(120, 120, 120, 0.55);
      position: relative;
      overflow: hidden;
    }
    .sv-progress-fill {
      position: absolute;
      left: 0;
      top: 0;
      bottom: 0;
      width: 0%;
      border-radius: 999px;
      background: linear-gradient(90deg, #f97316, #fb923c);
      transition: width 220ms ease;
    }
    .sv-progress-thumb {
      position: absolute;
      top: 50%;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      background: #fff;
      transform: translate(-50%, -50%);
      box-shadow: 0 0 0 1px rgba(0,0,0,0.28);
      pointer-events: none;
    }
    .sv-toolbar {
      display: grid;
      grid-template-columns: 1fr auto 1fr;
      align-items: center;
      gap: 8px;
      min-height: 30px;
    }
    .sv-toolbar-left {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      min-width: 0;
    }
    .sv-toolbar-title {
      font-size: 11px;
      color: #a8b0bb;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-expand-btn {
      width: 20px;
      height: 20px;
      border: none;
      border-radius: 6px;
      background: rgba(255,255,255,0.08);
      color: #cbd5e1;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      flex: 0 0 auto;
      transition: background 140ms ease, color 140ms ease, transform 120ms ease;
    }
    .sv-expand-btn:hover {
      background: rgba(255,255,255,0.15);
      color: #f8fafc;
    }
    .sv-expand-btn:active {
      transform: scale(0.94);
    }
    body:not(.sv-host-can-edit-panel) .sv-expand-btn {
      display: none;
    }
    .sv-play-btn {
      width: 28px;
      height: 28px;
      border: none;
      border-radius: 999px;
      color: #fff;
      background: #f97316;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: transform 120ms ease, background 160ms ease;
    }
    .sv-play-btn:hover { background: #fb923c; }
    .sv-play-btn:active { transform: scale(0.94); }
    .sv-play-btn:disabled { opacity: 0.45; cursor: not-allowed; }
    .sv-status {
      text-align: right;
      font-size: 11px;
      color: #8f98a5;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-scene-grid {
      display: flex;
      align-items: stretch;
      gap: 6px;
      flex-wrap: nowrap;
      overflow: hidden;
    }
    .scene-chip {
      position: relative;
      width: 100%;
      border: none;
      border-bottom: 2px solid transparent;
      border-radius: 8px;
      background: rgba(255,255,255,0.06);
      color: #a3a3a3;
      padding: 7px 6px;
      text-align: center;
      font-size: 11px;
      line-height: 1.1;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      cursor: pointer;
      transition: transform 140ms ease, color 160ms ease, background 160ms ease, border-color 160ms ease;
    }
    .scene-chip-label {
      display: block;
      width: 100%;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .scene-chip-wrap {
      position: relative;
      flex: 1 1 0;
      min-width: 0;
    }
    .scene-chip-retry {
      position: absolute;
      top: 50%;
      right: 4px;
      transform: translateY(-50%);
      width: 24px;
      height: 24px;
      border: none;
      border-radius: 999px;
      background: #f97316;
      color: #fff;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
      opacity: 0;
      pointer-events: none;
      transition: opacity 160ms ease;
      cursor: pointer;
    }
    body.sv-host-can-retry .scene-chip-wrap:hover .scene-chip-retry {
      opacity: 1;
      pointer-events: auto;
    }
    .scene-chip-retry:disabled {
      opacity: 1;
      pointer-events: none;
      background: #f97316;
    }
    .scene-chip-retry-icon {
      width: 18px;
      height: 18px;
      display: block;
    }
    .scene-chip-retry-spinner {
      width: 14px;
      height: 14px;
      aspect-ratio: 1 / 1;
      border: 2px solid #ffffff;
      border-top-color: transparent;
      border-radius: 999px;
      box-sizing: border-box;
      animation: sceneChipSpin 1s linear infinite;
      display: block;
      flex: 0 0 auto;
    }
    @keyframes sceneChipSpin {
      from { transform: rotate(0deg); }
      to { transform: rotate(360deg); }
    }
    .scene-chip:hover { transform: scale(1.02); }
    .scene-chip.is-active {
      color: #fb923c;
      border-bottom-color: #fb923c;
      background: linear-gradient(135deg, rgba(249,115,22,0.2), rgba(168,85,247,0.2));
    }
    .scene-chip.is-failed {
      color: #fca5a5;
      border-bottom-color: rgba(239,68,68,0.95);
      background: rgba(239,68,68,0.12);
    }
    .scene-chip.is-generating {
      color: #fcd34d;
      background: rgba(245,158,11,0.11);
    }
    .sv-editor-overlay {
      position: relative;
      width: 100%;
      height: 0;
      z-index: 40;
      pointer-events: none;
      overflow: hidden;
      transition: height 260ms cubic-bezier(.22,1,.36,1);
    }
    .sv-editor-backdrop {
      position: absolute;
      inset: auto 0 0 0;
      height: 100%;
      background: rgba(0, 0, 0, 0.45);
      opacity: 0;
      transition: opacity 220ms ease;
    }
    .sv-editor-sheet {
      position: absolute;
      left: 0;
      right: 0;
      bottom: 0;
      height: 100%;
      background: rgba(16, 16, 16, 0.96);
      border-top: 1px solid rgba(255,255,255,0.12);
      box-shadow: 0 -14px 30px rgba(0,0,0,0.45);
      transform: translateY(102%);
      transition: transform 260ms cubic-bezier(.22,1,.36,1);
      display: flex;
      flex-direction: column;
    }
    .sv-editor-overlay.is-open {
      pointer-events: auto;
      height: var(--sv-editor-height, 50vh);
    }
    .sv-editor-overlay.is-open .sv-editor-backdrop {
      opacity: 1;
    }
    .sv-editor-overlay.is-open .sv-editor-sheet {
      transform: translateY(0);
    }
    .sv-editor-resize-handle {
      width: 100%;
      height: 14px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: ns-resize;
      flex: 0 0 auto;
      touch-action: none;
    }
    .sv-editor-resize-handle::before {
      content: "";
      width: 52px;
      height: 4px;
      border-radius: 999px;
      background: rgba(148, 163, 184, 0.7);
    }
    .sv-editor-header {
      padding: 10px 12px;
      border-bottom: 1px solid rgba(255,255,255,0.1);
      display: grid;
      grid-template-columns: 1fr auto;
      align-items: center;
      gap: 8px;
    }
    .sv-editor-header-title {
      color: #f1f5f9;
      font-size: 13px;
      font-weight: 600;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-editor-actions {
      display: inline-flex;
      align-items: center;
      gap: 6px;
    }
    .sv-editor-btn {
      border: none;
      border-radius: 8px;
      cursor: pointer;
      font-size: 12px;
      line-height: 1;
      padding: 7px 10px;
      color: #e2e8f0;
      background: rgba(255,255,255,0.1);
      transition: background 120ms ease;
    }
    .sv-editor-btn:hover {
      background: rgba(255,255,255,0.18);
    }
    .sv-editor-btn.is-primary {
      color: #fff;
      background: #f97316;
    }
    .sv-editor-btn.is-primary:hover {
      background: #fb923c;
    }
    .sv-editor-list {
      flex: 1;
      min-height: 0;
      overflow: auto;
      padding: 10px 12px 14px;
      display: grid;
      gap: 10px;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      align-items: start;
      align-content: start;
    }
    .sv-editor-item {
      border: 1px solid rgba(255,255,255,0.12);
      border-radius: 10px;
      background: rgba(255,255,255,0.03);
      padding: 10px;
      display: grid;
      grid-template-rows: auto auto auto;
      gap: 10px;
      align-content: start;
      cursor: pointer;
    }
    .sv-editor-item.is-active {
      border-color: rgba(249,115,22,0.65);
      box-shadow: inset 0 0 0 1px rgba(249,115,22,0.28);
    }
    .sv-editor-item-head {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 8px;
      min-height: 30px;
    }
    .sv-editor-item-title {
      border: none;
      border-radius: 8px;
      color: #fb923c;
      background: rgba(255,255,255,0.08);
      font-size: 12px;
      font-weight: 600;
      padding: 6px 8px;
      cursor: pointer;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      text-align: left;
    }
    .sv-editor-item-title:hover {
      background: rgba(255,255,255,0.14);
    }
    .sv-editor-status {
      color: #94a3b8;
      font-size: 11px;
      white-space: nowrap;
    }
    .sv-editor-status-wrap {
      display: inline-flex;
      align-items: center;
      gap: 6px;
    }
    .scene-chip-retry.sv-editor-retry {
      position: static;
      transform: none;
      opacity: 1;
      pointer-events: auto;
      width: 24px;
      height: 24px;
      flex: 0 0 auto;
    }
    .sv-editor-field {
      display: grid;
      gap: 6px;
    }
    .sv-editor-label {
      color: #a3a3a3;
      font-size: 11px;
      font-weight: 700;
    }
    .sv-editor-textarea {
      width: 100%;
      border-radius: 8px;
      border: 1px solid rgba(255,255,255,0.14);
      background: rgba(0,0,0,0.24);
      color: #f1f5f9;
      font-size: 12px;
      line-height: 1.45;
      padding: 8px 9px;
      resize: none;
      min-height: 110px;
      height: 110px;
    }
    .sv-editor-textarea[data-field="scriptText"] {
      min-height: 84px;
    }
    .sv-editor-textarea:focus {
      outline: none;
      border-color: rgba(249,115,22,0.7);
      box-shadow: 0 0 0 2px rgba(249,115,22,0.18);
    }
    body.sv-theme-light .sv-editor-textarea {
      border-color: rgba(15,23,42,0.18);
      background: rgba(248,250,252,0.92);
      color: #0f172a;
    }
    body.sv-theme-light .sv-editor-textarea:focus {
      border-color: rgba(249,115,22,0.72);
      box-shadow: 0 0 0 2px rgba(249,115,22,0.2);
    }
    .sv-editor-script-view {
      width: 100%;
      color: #e2e8f0;
      font-size: 12px;
      line-height: 1.5;
      white-space: pre-wrap;
      word-break: break-word;
      min-height: 84px;
      max-height: 84px;
      overflow: auto;
    }
    .sv-editor-save-tip {
      color: #fbbf24;
      font-size: 11px;
      opacity: 0;
      transition: opacity 140ms ease;
      justify-self: end;
    }
    .sv-editor-save-tip.is-visible {
      opacity: 1;
    }
    body.sv-theme-light .sv-editor-backdrop {
      background: rgba(15, 23, 42, 0.2);
    }
    body.sv-theme-light .sv-editor-sheet {
      background: rgba(255, 255, 255, 0.98);
      border-top-color: rgba(15, 23, 42, 0.12);
      box-shadow: 0 -14px 30px rgba(15, 23, 42, 0.16);
    }
    body.sv-theme-light .sv-editor-header {
      border-bottom-color: rgba(15, 23, 42, 0.1);
    }
    body.sv-theme-light .sv-editor-header-title {
      color: #0f172a;
    }
    body.sv-theme-light .sv-editor-btn {
      color: #334155;
      background: rgba(15, 23, 42, 0.08);
    }
    body.sv-theme-light .sv-editor-btn:hover {
      background: rgba(15, 23, 42, 0.14);
    }
    body.sv-theme-light .sv-editor-btn.is-primary {
      color: #ffffff;
      background: #f97316;
    }
    body.sv-theme-light .sv-editor-btn.is-primary:hover {
      background: #fb923c;
    }
    body.sv-theme-light .sv-editor-item {
      border-color: rgba(15, 23, 42, 0.12);
      background: rgba(248, 250, 252, 0.95);
    }
    body.sv-theme-light .sv-editor-item.is-active {
      border-color: rgba(249,115,22,0.72);
      box-shadow: inset 0 0 0 1px rgba(249,115,22,0.3);
    }
    body.sv-theme-light .sv-editor-item-title {
      color: #ea580c;
      background: rgba(249, 115, 22, 0.12);
    }
    body.sv-theme-light .sv-editor-item-title:hover {
      background: rgba(249, 115, 22, 0.18);
    }
    body.sv-theme-light .sv-editor-status {
      color: #64748b;
    }
    body.sv-theme-light .sv-editor-label {
      color: #475569;
    }
    body.sv-theme-light .sv-editor-script-view {
      color: #334155;
    }
    body.sv-theme-light .sv-editor-save-tip {
      color: #c2410c;
    }
    body.sv-editor-open #viewport {
      flex: 1 1 calc(100vh - var(--sv-editor-height, 50vh));
      min-height: 0;
    }
    body.sv-editor-open #sv-controls {
      display: none;
    }
    body.sv-recording .sv-toolbar,
    body.sv-recording .sv-scene-grid {
      display: none;
    }
    body.sv-recording #sv-controls {
      display: none;
    }
    body.sv-theme-light .sv-editor-list,
    body.sv-theme-light .sv-editor-script-view,
    body.sv-theme-light .sv-editor-textarea {
      scrollbar-color: rgba(148, 163, 184, 0.85) rgba(226, 232, 240, 0.85);
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar {
      width: 10px;
      height: 10px;
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-track,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-track,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-track {
      background: rgba(226, 232, 240, 0.85);
      border-radius: 999px;
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-thumb,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-thumb,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-thumb {
      background: rgba(148, 163, 184, 0.85);
      border-radius: 999px;
      border: 2px solid rgba(226, 232, 240, 0.85);
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-thumb:hover,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-thumb:hover,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-thumb:hover {
      background: rgba(100, 116, 139, 0.95);
    }
/* scene-01 */
.sv-scene-root-scene-01 .s-scene-01-container{
  position: relative;
  width: 100%;
  height: 100%;
  background: #000000;
  color: #00FF41;
  font-family: var(--sv-font-mono);
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
}.sv-scene-root-scene-01 .scanline{
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(rgba(0,0,0,0) 0px, rgba(0,0,0,0) 1px, rgba(0,255,65,0.08) 2px, rgba(0,255,65,0.08) 3px);
  pointer-events: none;
  z-index: 10;
}.sv-scene-root-scene-01 .bg-grid{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(0, 255, 65, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(0, 255, 65, 0.05) 1px, transparent 1px);
  background-size: 40px 40px;
  animation: grid-move 20s linear infinite;
}@keyframes grid-move{
  from { background-position: 0 0; }
  to { background-position: 40px 40px; }
}.sv-scene-root-scene-01 .alert-overlay{
  position: absolute;
  z-index: 5;
  text-align: center;
  animation: alert-flicker 0.2s infinite alternate;
}.sv-scene-root-scene-01 .ascii-alert{
  font-size: 42px;
  font-weight: bold;
  border: 4px solid #00FF41;
  padding: 20px 40px;
  background: rgba(0, 255, 65, 0.1);
}@keyframes alert-flicker{
  0% { opacity: 1; transform: scale(1); }
  100% { opacity: 0.7; transform: scale(1.02); }
}.sv-scene-root-scene-01 .terminal-wrapper{
  display: flex;
  gap: 120px;
  z-index: 4;
}.sv-scene-root-scene-01 .terminal-card{
  width: 320px;
  height: 200px;
  background: rgba(0, 0, 0, 0.9);
  border: 1px solid rgba(0, 255, 65, 0.4);
  box-shadow: 0 0 20px rgba(0, 255, 65, 0.1);
  display: flex;
  flex-direction: column;
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.5s;
}.sv-scene-root-scene-01 .terminal-header{
  background: rgba(0, 255, 65, 0.2);
  padding: 6px 12px;
  font-size: 14px;
  border-bottom: 1px solid rgba(0, 255, 65, 0.4);
}.sv-scene-root-scene-01 .terminal-body{
  padding: 15px;
  font-size: 18px;
  line-height: 1.6;
}.sv-scene-root-scene-01 .prompt{ color: #39FF14; margin-right: 8px; }.sv-scene-root-scene-01 .cursor{
  animation: blink 0.8s infinite;
}@keyframes blink{
  50% { opacity: 0; }
}.sv-scene-root-scene-01 .lightning-container{
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  pointer-events: none;
}.sv-scene-root-scene-01 .lightning-path{
  fill: none;
  stroke: #39FF14;
  stroke-width: 4;
  stroke-dasharray: 600;
  stroke-dashoffset: 600;
  filter: url(#glow);
  animation: strike 0.5s forwards;
}@keyframes strike{
  to { stroke-dashoffset: 0; }
}.sv-scene-root-scene-01 .status-text{
  margin-top: 250px;
  font-size: 24px;
  background: #00FF41;
  color: #000;
  padding: 5px 15px;
  animation: slide-up 0.4s ease-out;
}@keyframes slide-up{
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: translateY(0); }
}.sv-scene-root-scene-01 /* Step Transitions */
[data-step="1"]{ opacity: 0; transform: translateY(30px); }.sv-scene-root-scene-01 .active [data-step="1"]{ opacity: 1; transform: translateY(0); }.sv-scene-root-scene-01 [data-step="2"]{ opacity: 0; }.sv-scene-root-scene-01 .active [data-step="2"]{ opacity: 1; }.sv-scene-root-scene-01 .terminal-card.right.active-root{
  border-color: #39FF14;
  box-shadow: 0 0 30px rgba(0, 255, 65, 0.4);
}

/* scene-02 */
.sv-scene-root-scene-02 .s-scene-02-container{
  position: relative;
  width: 100%;
  height: 100%;
  background: #000000;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  font-family: var(--sv-font-mono);
}.sv-scene-root-scene-02 .crt-overlay{
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(rgba(0,0,0,0) 0px, rgba(0,0,0,0) 1px, rgba(0,255,65,0.06) 2px, rgba(0,255,65,0.06) 3px);
  pointer-events: none;
  z-index: 10;
}.sv-scene-root-scene-02 .ambient-phosphor{
  position: absolute;
  width: 120%;
  height: 120%;
  background: radial-gradient(circle, rgba(0,255,65,0.05) 0%, transparent 70%);
  animation: phosphor-pulse 8s ease-in-out infinite;
  pointer-events: none;
}.sv-scene-root-scene-02 .grid-bg{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(0, 255, 65, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(0, 255, 65, 0.03) 1px, transparent 1px);
  background-size: 50px 50px;
  opacity: 0.5;
}.sv-scene-root-scene-02 .vulnerability-wrapper{
  position: relative;
  z-index: 5;
  opacity: 0;
  transform: scale(0);
  transition: all 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}.sv-scene-root-scene-02 .active [data-step="0"]{
  opacity: 1;
  transform: scale(1);
}.sv-scene-root-scene-02 .cve-text{
  font-size: 108px;
  font-weight: 900;
  color: #00FF41;
  letter-spacing: -2px;
  text-shadow: 0 0 20px rgba(0, 255, 65, 0.6);
  margin: 0;
  animation: blue-breath 4s ease-in-out infinite;
}@keyframes blue-breath{
  0%, 100% { text-shadow: 0 0 20px rgba(0, 255, 65, 0.4); }
  50% { text-shadow: 0 0 40px rgba(60, 150, 255, 0.7), 0 0 10px rgba(0, 255, 65, 0.5); }
}.sv-scene-root-scene-02 .fail-container{
  position: absolute;
  top: 60%;
  display: flex;
  flex-direction: column;
  align-items: center;
  opacity: 0;
  transform: translateY(40px);
  transition: all 0.5s ease-out;
}.sv-scene-root-scene-02 .active [data-step="1"]{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-02 .fail-text{
  font-size: 140px;
  font-weight: 900;
  color: #00FF41; 
  /* Semantically red but visually terminal phosphor */
  background: #000;
  border: 4px solid #00FF41;
  padding: 0 40px;
  mix-blend-mode: screen;
  animation: critical-glitch 0.2s steps(2) infinite;
}@keyframes critical-glitch{
  0% { transform: skewX(0); opacity: 1; border-color: #00FF41; }
  50% { transform: skewX(5deg); opacity: 0.8; border-color: rgba(255, 50, 50, 0.8); }
}.sv-scene-root-scene-02 .tear-particles{
  position: absolute;
  inset: -100px -200px;
  pointer-events: none;
  z-index: -1;
}.sv-scene-root-scene-02 .tear-line{
  fill: none;
  stroke: #00FF41;
  stroke-width: 2;
  stroke-dasharray: 1000;
  stroke-dashoffset: 1000;
  opacity: 0.4;
}.sv-scene-root-scene-02 .active [data-step="1"] .tear-line{
  animation: tear-draw 0.8s forwards;
}.sv-scene-root-scene-02 .l2{ animation-delay: 0.1s; }.sv-scene-root-scene-02 .l3{ animation-delay: 0.2s; }@keyframes tear-draw{
  to { stroke-dashoffset: 0; opacity: 0.1; }
}@keyframes phosphor-pulse{
  0%, 100% { opacity: 0.4; transform: scale(1); }
  50% { opacity: 0.6; transform: scale(1.05); }
}

/* scene-03 */
.sv-scene-root-scene-03 .s-scene-03-container{
  position: relative;
  width: 100%;
  height: 100%;
  background: #000000;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  overflow: hidden;
  font-family: var(--sv-font-mono);
  color: #00FF41;
}.sv-scene-root-scene-03 .crt-lines{
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(rgba(0,0,0,0) 0px, rgba(0,0,0,0) 2px, rgba(0,255,65,0.08) 3px, rgba(0,255,65,0.08) 4px);
  pointer-events: none;
  z-index: 10;
}.sv-scene-root-scene-03 .ambient-glow{
  position: absolute;
  width: 100%;
  height: 100%;
  background: radial-gradient(circle at center, rgba(0,255,65,0.04) 0%, transparent 70%);
  pointer-events: none;
}.sv-scene-root-scene-03 /* Step 0: Timeline */
.timeline-section{
  width: 80%;
  margin-bottom: 60px;
  opacity: 0;
  transform: translateX(-50px);
  transition: all 0.6s cubic-bezier(0.23, 1, 0.32, 1);
}.sv-scene-root-scene-03 .active [data-step="0"]{ opacity: 1; transform: translateX(0); }.sv-scene-root-scene-03 .timeline-wrapper{
  display: flex;
  align-items: center;
  gap: 20px;
  font-size: 28px;
}.sv-scene-root-scene-03 .timeline-bar{
  flex-grow: 1;
  height: 4px;
  background: rgba(0, 255, 65, 0.2);
  position: relative;
  display: flex;
  align-items: center;
}.sv-scene-root-scene-03 .timeline-fill{
  position: absolute;
  left: 0;
  height: 100%;
  width: 0%;
  background: #00FF41;
  box-shadow: 0 0 10px #00FF41;
  transition: width 1.5s ease-in-out;
}.sv-scene-root-scene-03 .active [data-step="0"] .timeline-fill{ width: 100%; }.sv-scene-root-scene-03 .timeline-arrow{
  position: absolute;
  right: -10px;
  font-weight: bold;
  text-shadow: 0 0 5px #00FF41;
}.sv-scene-root-scene-03 .pulse-text{
  animation: phosphor-flicker 2s infinite;
}.sv-scene-root-scene-03 /* Step 1: Grid */
.distro-grid-container{
  width: 85%;
  position: relative;
  opacity: 0;
  transition: opacity 0.5s ease;
}.sv-scene-root-scene-03 .active [data-step="1"]{ opacity: 1; }.sv-scene-root-scene-03 .grid-header{
  font-size: 14px;
  margin-bottom: 10px;
  color: rgba(0, 255, 65, 0.6);
  letter-spacing: 2px;
}.sv-scene-root-scene-03 .distro-grid{
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 30px;
  padding: 40px;
  border: 1px solid rgba(0, 255, 65, 0.3);
  background: rgba(0, 255, 65, 0.02);
}.sv-scene-root-scene-03 .distro-card{
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 15px;
  transition: all 0.4s ease;
}.sv-scene-root-scene-03 .distro-card iconify-icon{
  font-size: 64px;
  color: #00FF41;
  filter: drop-shadow(0 0 5px rgba(0, 255, 65, 0.4));
}.sv-scene-root-scene-03 .distro-name{
  font-size: 18px;
  text-transform: uppercase;
}.sv-scene-root-scene-03 /* Step 2: Vulnerable State */
.active [data-step="2"] .distro-card iconify-icon{
  color: #FF3131;
  filter: drop-shadow(0 0 8px rgba(255, 49, 49, 0.6));
  animation: icon-glitch 0.3s infinite alternate;
}.sv-scene-root-scene-03 .shimmer-overlay{
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, transparent 0%, rgba(0,255,65,0.1) 45%, rgba(0,255,65,0.2) 50%, rgba(0,255,65,0.1) 55%, transparent 100%);
  background-size: 200% 200%;
  pointer-events: none;
  opacity: 0;
}.sv-scene-root-scene-03 .active [data-step="2"] .shimmer-overlay{
  opacity: 1;
  animation: shimmer-scan 3s infinite linear;
}.sv-scene-root-scene-03 .vulnerable-overlay{
  position: absolute;
  inset: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 20;
  pointer-events: none;
  opacity: 0;
  transform: scale(2);
  transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}.sv-scene-root-scene-03 .active [data-step="2"].vulnerable-overlay{
  opacity: 1;
  transform: scale(1) rotate(-10deg);
}.sv-scene-root-scene-03 .stamp-box{
  border: 8px double #FF3131;
  padding: 20px 40px;
  background: rgba(0, 0, 0, 0.9);
  box-shadow: 0 0 30px rgba(255, 49, 49, 0.4);
  text-align: center;
}.sv-scene-root-scene-03 .stamp-text{
  font-size: 84px;
  font-weight: 900;
  color: #FF3131;
  line-height: 1;
}.sv-scene-root-scene-03 .stamp-subtext{
  font-size: 24px;
  color: #FF3131;
  letter-spacing: 10px;
  margin-top: 10px;
}@keyframes phosphor-flicker{
  0%, 100% { opacity: 1; }
  50% { opacity: 0.6; }
  55% { opacity: 0.9; }
}@keyframes shimmer-scan{
  0% { background-position: -200% -200%; }
  100% { background-position: 200% 200%; }
}@keyframes icon-glitch{
  0% { transform: translate(0); }
  50% { transform: translate(-2px, 1px); }
  100% { transform: translate(2px, -1px); }
}

/* scene-04 */
.sv-scene-root-scene-04 .s-scene-04-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background: #000000;
  overflow: hidden;
  font-family: var(--sv-font-mono);
  display: flex;
  justify-content: center;
  align-items: center;
}.sv-scene-root-scene-04 .crt-lines{
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(rgba(0,0,0,0) 0px, rgba(0,0,0,0) 2px, rgba(0,255,65,0.05) 3px, rgba(0,255,65,0.05) 4px);
  pointer-events: none;
  z-index: 10;
}.sv-scene-root-scene-04 .ambient-glow{
  position: absolute;
  width: 100%;
  height: 100%;
  background: radial-gradient(circle at center, rgba(0,255,65,0.03) 0%, transparent 70%);
  pointer-events: none;
}.sv-scene-root-scene-04 .system-layout{
  width: 100%;
  max-width: 1200px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 10%;
  z-index: 5;
}.sv-scene-root-scene-04 .system-node{
  width: 280px;
  height: 280px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  border: 2px solid rgba(0, 255, 65, 0.4);
  background: rgba(0, 255, 65, 0.02);
  transition: all 0.5s cubic-bezier(0.165, 0.84, 0.44, 1);
  position: relative;
}.sv-scene-root-scene-04 .box-node{
  border-radius: 4px;
}.sv-scene-root-scene-04 .circle-node{
  border-radius: 50%;
  border-color: rgba(255, 255, 255, 0.3);
}.sv-scene-root-scene-04 .node-label{
  position: absolute;
  top: -40px;
  color: rgba(0, 255, 65, 0.6);
  font-size: 14px;
  letter-spacing: 2px;
}.sv-scene-root-scene-04 .internal-process{
  display: flex;
  align-items: center;
  gap: 10px;
}.sv-scene-root-scene-04 .mono-text, .sv-scene-root-scene-04 .status-text{
  color: #00FF41;
  font-size: 18px;
}.sv-scene-root-scene-04 .cursor-blink{
  width: 10px;
  height: 20px;
  background: #00FF41;
  animation: cursor-blink 1s infinite steps(1);
}.sv-scene-root-scene-04 .vector-layer{
  position: absolute;
  inset: 0;
  pointer-events: none;
}.sv-scene-root-scene-04 .vector-layer svg{
  width: 100%;
  height: 100%;
}.sv-scene-root-scene-04 /* Step 0 Animation */
.active[data-scene-id="scene-04"] #attack-path{
  transition: stroke-dashoffset 0.8s ease-in-out 0.3s;
  stroke-dashoffset: 0;
}.sv-scene-root-scene-04 .active[data-scene-id="scene-04"] #arrow-head{
  transition: opacity 0.2s ease 1.1s;
  opacity: 1;
}.sv-scene-root-scene-04 /* Step 1 Styles */
[data-step="1"] .circle-node{
  border-color: #FF3131;
  background: rgba(255, 49, 49, 0.1);
  box-shadow: 0 0 30px rgba(255, 49, 49, 0.3);
  transform: scale(1.05);
}.sv-scene-root-scene-04 [data-step="1"] .circle-node .status-text{
  color: #FF3131;
  animation: text-warning 0.5s infinite alternate;
}.sv-scene-root-scene-04 .success-banner{
  position: absolute;
  bottom: 10%;
  opacity: 0;
  transform: translateY(20px);
  transition: all 0.5s ease;
}.sv-scene-root-scene-04 .active .success-banner[data-step="1"]{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-04 .glitch-box{
  border: 1px solid #FF3131;
  padding: 15px 40px;
  background: rgba(0, 0, 0, 0.9);
  box-shadow: 4px 4px 0px #FF3131;
}.sv-scene-root-scene-04 .success-text{
  color: #FF3131;
  font-size: 28px;
  font-weight: bold;
  letter-spacing: 2px;
}@keyframes cursor-blink{
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}@keyframes text-warning{
  from { opacity: 1; text-shadow: 0 0 5px #FF3131; }
  to { opacity: 0.7; text-shadow: 0 0 15px #FF3131; }
}

/* scene-05 */
.sv-scene-root-scene-05 .s-scene-05-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background: #000000;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  font-family: var(--sv-font-mono);
  color: #00FF41;
}.sv-scene-root-scene-05 .crt-scanlines{
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(rgba(0,0,0,0) 0px, rgba(0,0,0,0) 2px, rgba(0,255,65,0.05) 3px, rgba(0,255,65,0.05) 4px);
  pointer-events: none;
  z-index: 10;
}.sv-scene-root-scene-05 .ambient-phosphor{
  position: absolute;
  width: 100%;
  height: 100%;
  background: radial-gradient(circle at 50% 50%, rgba(0, 255, 65, 0.04) 0%, transparent 80%);
  pointer-events: none;
}.sv-scene-root-scene-05 .memory-container{
  position: relative;
  width: 80%;
  height: 70%;
  border: 1px solid rgba(0, 255, 65, 0.2);
  background: rgba(0, 255, 65, 0.02);
  padding: 40px;
  box-sizing: border-box;
  display: flex;
  justify-content: center;
  align-items: center;
}.sv-scene-root-scene-05 .memory-label{
  position: absolute;
  top: 15px;
  left: 20px;
  font-size: 14px;
  opacity: 0.6;
  letter-spacing: 2px;
}.sv-scene-root-scene-05 .memory-grid{
  position: absolute;
  inset: 0;
  opacity: 0.1;
  background-image: radial-gradient(#00FF41 1px, transparent 1px);
  background-size: 30px 30px;
}.sv-scene-root-scene-05 .page-cache-card{
  width: 480px;
  height: 300px;
  background: rgba(0, 20, 0, 0.9);
  border: 2px solid #00FF41;
  box-shadow: 0 0 30px rgba(0, 255, 65, 0.2);
  padding: 20px;
  position: relative;
  z-index: 5;
  opacity: 0;
  transform: scale(0.9) translateY(20px);
  transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}.sv-scene-root-scene-05 .page-cache-card[data-step="1"]{
  opacity: 1;
  transform: scale(1) translateY(0);
}.sv-scene-root-scene-05 .card-header{
  border-bottom: 1px solid rgba(0, 255, 65, 0.3);
  padding-bottom: 10px;
  margin-bottom: 20px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}.sv-scene-root-scene-05 .card-title{
  font-size: 20px;
  font-weight: bold;
}.sv-scene-root-scene-05 .memory-addr{
  font-size: 14px;
  opacity: 0.7;
}.sv-scene-root-scene-05 .binary-content{
  font-size: 24px;
  line-height: 1.5;
  letter-spacing: 4px;
  color: rgba(0, 255, 65, 0.8);
}.sv-scene-root-scene-05 .security-status{
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(2px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  opacity: 0;
  transition: opacity 0.5s ease;
}.sv-scene-root-scene-05 .security-status[data-step="2"]{
  opacity: 1;
}.sv-scene-root-scene-05 .lock-overlay{
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  margin-bottom: 30px;
  color: #39FF14;
}.sv-scene-root-scene-05 .lock-overlay i{
  width: 64px;
  height: 64px;
}.sv-scene-root-scene-05 .read-only-text{
  font-size: 32px;
  font-weight: 800;
  letter-spacing: 4px;
  border: 2px solid #39FF14;
  padding: 5px 20px;
}.sv-scene-root-scene-05 .forbidden-action{
  display: flex;
  gap: 40px;
}.sv-scene-root-scene-05 .action-item{
  position: relative;
  padding: 5px 15px;
  opacity: 0.6;
}.sv-scene-root-scene-05 .forbidden-sign{
  position: absolute;
  top: 50%;
  left: 50%;
  width: 120%;
  height: 2px;
  background: #FF3131;
  transform: translate(-50%, -50%) rotate(-25deg);
  box-shadow: 0 0 10px #FF3131;
}.sv-scene-root-scene-05 .ghost-text{
  position: absolute;
  bottom: 5%;
  right: 5%;
  font-size: 80px;
  opacity: 0.03;
  font-weight: 900;
  pointer-events: none;
}@keyframes pulse-border{
  0% { border-color: rgba(0, 255, 65, 0.4); }
  50% { border-color: rgba(0, 255, 65, 1); }
  100% { border-color: rgba(0, 255, 65, 0.4); }
}

/* scene-06 */
.sv-scene-root-scene-06 .s-scene-06-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background: #000000;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: space-around;
  font-family: var(--sv-font-mono);
  color: #00FF41;
}.sv-scene-root-scene-06 .crt-overlay{
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(rgba(0,0,0,0) 0px, rgba(0,0,0,0) 2px, rgba(0,255,65,0.08) 3px, rgba(0,255,65,0.08) 4px);
  pointer-events: none;
  z-index: 100;
}.sv-scene-root-scene-06 .ambient-glow{
  position: absolute;
  width: 100%;
  height: 100%;
  background: radial-gradient(circle at 50% 50%, rgba(0, 255, 65, 0.03) 0%, transparent 70%);
  pointer-events: none;
}.sv-scene-root-scene-06 .terminal-container{
  width: 320px;
  height: 200px;
  border: 1px solid rgba(0, 255, 65, 0.4);
  background: rgba(0, 20, 0, 0.8);
  box-shadow: 0 0 15px rgba(0, 255, 65, 0.1);
  z-index: 10;
  transform: translateX(-100px);
  opacity: 0;
  transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}.sv-scene-root-scene-06 .term-header{
  background: rgba(0, 255, 65, 0.15);
  padding: 6px 10px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid rgba(0, 255, 65, 0.3);
}.sv-scene-root-scene-06 .term-controls{
  display: flex;
  gap: 6px;
}.sv-scene-root-scene-06 .term-controls span{
  width: 8px;
  height: 8px;
  border: 1px solid #00FF41;
  border-radius: 50%;
}.sv-scene-root-scene-06 .term-title{
  font-size: 10px;
  opacity: 0.7;
}.sv-scene-root-scene-06 .term-body{
  padding: 15px;
  font-size: 14px;
}.sv-scene-root-scene-06 .typing-line{
  margin-bottom: 5px;
  overflow: hidden;
  white-space: nowrap;
}.sv-scene-root-scene-06 .highlight{ color: #39FF14; text-shadow: 0 0 5px #00FF41; }.sv-scene-root-scene-06 .conduit-system{
  position: absolute;
  width: 100%;
  height: 100%;
  pointer-events: none;
}.sv-scene-root-scene-06 .conduit-svg{
  position: absolute;
  top: 0; left: 0; width: 100%; height: 100%;
}.sv-scene-root-scene-06 .file-node{
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) scale(0.9);
  opacity: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  z-index: 20;
  transition: all 0.5s ease;
}.sv-scene-root-scene-06 .file-icon-box{
  font-size: 64px;
  border: 2px solid #00FF41;
  padding: 15px;
  background: rgba(0, 255, 65, 0.05);
  box-shadow: 0 0 20px rgba(0, 255, 65, 0.2);
}.sv-scene-root-scene-06 .file-name{
  font-size: 20px;
  font-weight: bold;
}.sv-scene-root-scene-06 .file-perm{
  font-size: 12px;
  opacity: 0.6;
}.sv-scene-root-scene-06 .pipeline-stage{
  width: 300px;
  height: 250px;
  border: 2px dashed rgba(0, 255, 65, 0.3);
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: translateX(50px);
  transition: all 0.6s ease;
}.sv-scene-root-scene-06 .pipeline-box{
  width: 90%;
  height: 90%;
  background: rgba(0, 255, 65, 0.02);
  border: 1px solid #00FF41;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
}.sv-scene-root-scene-06 .pipeline-label{
  position: absolute;
  top: -12px;
  background: #000;
  padding: 0 10px;
  font-size: 14px;
}.sv-scene-root-scene-06 .chain-container{
  display: flex;
  gap: 5px;
  opacity: 0;
}.sv-scene-root-scene-06 .chain-link{
  width: 15px;
  height: 30px;
  border: 2px solid #00FF41;
  border-radius: 10px;
}.sv-scene-root-scene-06 .flow-indicator{
  font-size: 12px;
  animation: blink 0.8s infinite;
}.sv-scene-root-scene-06 .side-status{
  position: absolute;
  bottom: 40px;
  right: 40px;
  text-align: right;
}.sv-scene-root-scene-06 .status-item{
  font-size: 14px;
  opacity: 0;
  margin-top: 5px;
}@keyframes shake{
  0%, 100% { transform: translate(-50%, -50%); }
  20% { transform: translate(-52%, -48%); }
  40% { transform: translate(-48%, -52%); }
  60% { transform: translate(-51%, -49%); }
  80% { transform: translate(-49%, -51%); }
}@keyframes blink{
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}.sv-scene-root-scene-06 .shaking{ animation: shake 0.2s infinite; }.sv-scene-root-scene-06 [data-step="1"] .status-item[data-step="1"]{ opacity: 1; }.sv-scene-root-scene-06 [data-step="2"] .status-item[data-step="2"]{ opacity: 1; }

/* scene-07 */
.sv-scene-root-scene-07 .s-scene-07-wrapper{ width: 100%; height: 100%; background: #000; display: flex; align-items: center; justify-content: center; font-family: var(--sv-font-mono); color: #00FF41; overflow: hidden; position: relative; }.sv-scene-root-scene-07 .crt-overlay{ position: absolute; inset: 0; background: repeating-linear-gradient(rgba(0,0,0,0) 0px, rgba(0,0,0,0) 2px, rgba(0,255,65,0.05) 3px, rgba(0,255,65,0.05) 4px); pointer-events: none; z-index: 10; }.sv-scene-root-scene-07 .ambient-glow{ position: absolute; width: 100%; height: 100%; background: radial-gradient(circle at 50% 50%, rgba(0, 255, 65, 0.05) 0%, transparent 70%); }.sv-scene-root-scene-07 .layout-container{ display: flex; align-items: center; justify-content: space-between; width: 90%; gap: 20px; z-index: 5; }.sv-scene-root-scene-07 .section-label{ font-size: 14px; color: rgba(0,255,65,0.6); margin-bottom: 10px; text-transform: uppercase; letter-spacing: 2px; }.sv-scene-root-scene-07 .terminal-window{ width: 420px; border: 1px solid rgba(0,255,65,0.3); background: rgba(0,20,0,0.9); box-shadow: 0 0 20px rgba(0,255,65,0.1); }.sv-scene-root-scene-07 .term-header{ background: rgba(0,255,65,0.1); padding: 8px 12px; display: flex; align-items: center; border-bottom: 1px solid rgba(0,255,65,0.2); }.sv-scene-root-scene-07 .term-dots{ display: flex; gap: 5px; margin-right: 15px; }.sv-scene-root-scene-07 .term-dots span{ width: 6px; height: 6px; border: 1px solid #00FF41; border-radius: 50%; }.sv-scene-root-scene-07 .term-title{ font-size: 12px; opacity: 0.8; }.sv-scene-root-scene-07 .code-content{ padding: 20px; font-size: 16px; line-height: 1.5; }.sv-scene-root-scene-07 .highlight-target{ background: rgba(0,255,65,0.2); border-left: 3px solid #00FF41; padding-left: 5px; }.sv-scene-root-scene-07 .code-keyword{ color: #39FF14; font-weight: bold; }.sv-scene-root-scene-07 .code-comment{ color: rgba(0,255,65,0.4); }.sv-scene-root-scene-07 .conduit-container{ flex: 1; height: 100px; display: flex; align-items: center; justify-content: center; }.sv-scene-root-scene-07 .arrow-path{ stroke-dasharray: 200; stroke-dashoffset: 200; transition: stroke-dashoffset 0.8s ease; }.sv-scene-root-scene-07 .memory-section{ display: flex; flex-direction: column; align-items: center; }.sv-scene-root-scene-07 .page-frame{ width: 280px; height: 180px; border: 2px solid #00FF41; position: relative; background: rgba(0,255,65,0.02); display: flex; flex-direction: column; justify-content: center; align-items: center; }.sv-scene-root-scene-07 .page-grid{ display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; opacity: 0.2; position: absolute; inset: 20px; }.sv-scene-root-scene-07 .page-grid span{ border: 1px solid #00FF41; height: 20px; }.sv-scene-root-scene-07 .permission-status{ position: relative; z-index: 2; text-align: center; }.sv-scene-root-scene-07 .lock-container{ transition: all 0.4s ease; }.sv-scene-root-scene-07 .lock-icon{ font-size: 48px; margin-bottom: 10px; }.sv-scene-root-scene-07 .lock-text{ font-size: 18px; }.sv-scene-root-scene-07 .rw-status{ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0); opacity: 0; color: #FF3131; font-weight: 900; font-size: 42px; text-shadow: 0 0 15px rgba(255,49,49,0.8); transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); }.sv-scene-root-scene-07 .shattered .lock-container{ transform: scale(1.5) rotate(15deg); opacity: 0; filter: blur(5px); }.sv-scene-root-scene-07 .shattered .rw-status{ transform: translate(-50%, -50%) scale(1); opacity: 1; }.sv-scene-root-scene-07 .alert-pulse-overlay{ position: absolute; inset: 0; background: radial-gradient(circle, rgba(255,0,0,0.15) 0%, transparent 70%); opacity: 0; pointer-events: none; animation: pulse-red 1.5s infinite; }@keyframes pulse-red{ 0%, 100% { opacity: 0; transform: scale(1); } 50% { opacity: 1; transform: scale(1.1); } }.sv-scene-root-scene-07 .status-bar{ position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); display: flex; gap: 40px; }.sv-scene-root-scene-07 .status-msg{ font-size: 12px; border: 1px solid rgba(0,255,65,0.3); padding: 4px 12px; background: rgba(0,20,0,0.8); }

/* scene-08 */
.sv-scene-root-scene-08 .s-scene-08-wrapper{ width: 100%; height: 100%; background: #000; display: flex; align-items: center; justify-content: center; font-family: var(--sv-font-mono); color: #00FF41; overflow: hidden; position: relative; }.sv-scene-root-scene-08 .crt-scanlines{ position: absolute; inset: 0; background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.15) 50%), linear-gradient(90deg, rgba(255, 0, 0, 0.03), rgba(0, 255, 0, 0.01), rgba(0, 0, 255, 0.03)); background-size: 100% 3px, 3px 100%; pointer-events: none; z-index: 20; }.sv-scene-root-scene-08 .ambient-glow{ position: absolute; width: 100%; height: 100%; background: radial-gradient(circle, rgba(0, 255, 65, 0.05) 0%, transparent 80%); pointer-events: none; }.sv-scene-root-scene-08 .hex-viewport{ width: 800px; height: 400px; border: 1px solid rgba(0, 255, 65, 0.3); background: rgba(0, 10, 0, 0.9); position: relative; box-shadow: 0 0 40px rgba(0, 0, 0, 0.8); transition: all 0.8s ease; transform: scale(1.1); }.sv-scene-root-scene-08 .viewport-header{ background: rgba(0, 255, 65, 0.1); padding: 8px 15px; display: flex; justify-content: space-between; border-bottom: 1px solid rgba(0, 255, 65, 0.2); font-size: 12px; }.sv-scene-root-scene-08 .hex-grid-container{ padding: 30px; display: flex; justify-content: center; }.sv-scene-root-scene-08 .hex-grid{ display: grid; grid-template-columns: repeat(8, 70px); gap: 15px; }.sv-scene-root-scene-08 .hex-cell{ height: 40px; display: flex; align-items: center; justify-content: center; border: 1px solid rgba(0, 255, 65, 0.1); font-size: 22px; color: #0088ff; transition: all 0.5s ease; position: relative; }.sv-scene-root-scene-08 .hex-cell.infected{ color: #d400ff !important; border-color: #d400ff; text-shadow: 0 0 10px rgba(212, 0, 255, 0.5); }.sv-scene-root-scene-08 .hex-cell.target-active{ background: rgba(0, 255, 65, 0.1); border-color: #00FF41; }.sv-scene-root-scene-08 .missile-container{ position: absolute; inset: 0; pointer-events: none; }.sv-scene-root-scene-08 .byte-missile{ position: absolute; font-size: 24px; font-weight: bold; background: #000; border: 2px solid #00FF41; padding: 5px 10px; box-shadow: 0 0 15px #00FF41; z-index: 10; transition: all 0.6s cubic-bezier(0.6, -0.28, 0.735, 0.045); }.sv-scene-root-scene-08 .byte-missile[data-step="0"]{ opacity: 1; transform: translate(var(--start-x), var(--start-y)); }.sv-scene-root-scene-08 .byte-missile.launched{ transform: translate(var(--end-x), var(--end-y)) scale(0.8); opacity: 0.5; }.sv-scene-root-scene-08 .alert-overlay{ position: absolute; inset: 0; z-index: 30; display: flex; align-items: center; justify-content: center; background: rgba(255, 0, 0, 0.1); backdrop-filter: blur(2px); }.sv-scene-root-scene-08 .alert-box{ background: #000; border: 4px solid #FF3131; padding: 40px; text-align: center; box-shadow: 0 0 50px rgba(255, 49, 49, 0.4); animation: alert-shake 0.2s infinite; }.sv-scene-root-scene-08 .alert-header{ color: #FF3131; font-weight: 900; font-size: 32px; letter-spacing: 4px; margin-bottom: 10px; }.sv-scene-root-scene-08 .alert-content{ color: #FFF; font-size: 20px; border-top: 1px solid #FF3131; padding-top: 10px; }.sv-scene-root-scene-08 .alert-sub{ font-size: 14px; opacity: 0.7; margin-top: 5px; }.sv-scene-root-scene-08 .terminal-footer{ position: absolute; bottom: 40px; left: 100px; right: 100px; }.sv-scene-root-scene-08 .prompt{ color: #00FF41; margin-right: 10px; }.sv-scene-root-scene-08 .typing-text{ font-size: 18px; }.sv-scene-root-scene-08 .cursor{ display: inline-block; width: 10px; height: 20px; background: #00FF41; animation: blink 1s infinite; vertical-align: middle; }.sv-scene-root-scene-08 .progress-section{ margin-top: 15px; display: flex; align-items: center; gap: 15px; }.sv-scene-root-scene-08 .bar-bg{ flex: 1; height: 10px; background: rgba(0, 255, 65, 0.1); border: 1px solid rgba(0, 255, 65, 0.3); }.sv-scene-root-scene-08 .bar-fill{ display: block; width: 0%; height: 100%; background: #00FF41; transition: width 0.6s ease; }@keyframes alert-shake{ 0% { transform: translate(1px, 1px); } 50% { transform: translate(-1px, -1px); } 100% { transform: translate(1px, -1px); } }@keyframes blink{ 0%, 100% { opacity: 1; } 50% { opacity: 0; } }.sv-scene-root-scene-08 .modified-state .hex-viewport{ border-color: #d400ff; box-shadow: 0 0 30px rgba(212, 0, 255, 0.2); }.sv-scene-root-scene-08 .modified-state #mem-status{ color: #d400ff; content: "[ MEMORY_MODIFIED_PERMANENT ]"; }

/* scene-09 */
.sv-scene-root-scene-09 .s-scene-09-wrapper{ width: 100%; height: 100%; background: #000; font-family: var(--sv-font-mono); color: #00FF41; display: flex; align-items: center; justify-content: center; position: relative; overflow: hidden; }.sv-scene-root-scene-09 .crt-scanlines{ position: absolute; inset: 0; background: linear-gradient(rgba(0, 255, 65, 0.05) 50%, transparent 50%); background-size: 100% 4px; pointer-events: none; z-index: 10; }.sv-scene-root-scene-09 .ambient-glow{ position: absolute; inset: 0; background: radial-gradient(circle at center, rgba(0, 255, 65, 0.03) 0%, transparent 70%); pointer-events: none; }.sv-scene-root-scene-09 .terminal-interface{ width: 80%; max-width: 900px; height: 60%; background: rgba(0, 10, 0, 0.95); border: 1px solid rgba(0, 255, 65, 0.3); box-shadow: 0 20px 50px rgba(0, 0, 0, 0.8); display: flex; flex-direction: column; position: relative; z-index: 5; }.sv-scene-root-scene-09 .terminal-header{ height: 30px; background: rgba(0, 255, 65, 0.1); border-bottom: 1px solid rgba(0, 255, 65, 0.2); display: flex; align-items: center; padding: 0 15px; }.sv-scene-root-scene-09 .terminal-buttons{ display: flex; gap: 6px; margin-right: 20px; }.sv-scene-root-scene-09 .terminal-buttons span{ width: 8px; height: 8px; border: 1px solid rgba(0, 255, 65, 0.4); border-radius: 50%; }.sv-scene-root-scene-09 .terminal-title{ font-size: 12px; opacity: 0.7; letter-spacing: 1px; }.sv-scene-root-scene-09 .terminal-content{ flex: 1; padding: 30px; overflow: hidden; position: relative; }.sv-scene-root-scene-09 .log-line{ font-size: 14px; opacity: 0.4; margin-bottom: 8px; font-weight: 300; }.sv-scene-root-scene-09 .prompt-area{ font-size: 32px; display: flex; align-items: center; margin-top: 20px; }.sv-scene-root-scene-09 .prompt-char{ margin-right: 15px; color: #39FF14; font-weight: bold; }.sv-scene-root-scene-09 .command-text{ letter-spacing: 2px; }.sv-scene-root-scene-09 .cursor{ display: inline-block; width: 15px; height: 32px; background: #00FF41; margin-left: 10px; animation: blink 1s infinite steps(2); }.sv-scene-root-scene-09 .result-output{ margin-top: 40px; display: flex; justify-content: center; }.sv-scene-root-scene-09 .root-banner{ font-size: 120px; font-weight: 900; letter-spacing: 15px; text-transform: uppercase; text-shadow: 0 0 30px rgba(0, 255, 65, 0.8); }.sv-scene-root-scene-09 .terminal-footer-bar{ height: 25px; background: rgba(0, 255, 65, 0.1); display: flex; align-items: center; padding: 0 15px; gap: 30px; font-size: 10px; border-top: 1px solid rgba(0, 255, 65, 0.2); }.sv-scene-root-scene-09 .blink-text{ animation: blink 0.5s infinite; }.sv-scene-root-scene-09 .lightning-flash{ position: absolute; inset: 0; background: #00FF41; opacity: 0; pointer-events: none; z-index: 100; }.sv-scene-root-scene-09 .success-frame{ position: absolute; inset: 10px; border: 4px solid #00FF41; box-shadow: inset 0 0 50px rgba(0, 255, 65, 0.3), 0 0 30px rgba(0, 255, 65, 0.2); pointer-events: none; z-index: 101; opacity: 0; transform: scale(1.02); transition: all 0.3s ease; }.sv-scene-root-scene-09 .success-frame[data-step="2"]{ opacity: 1; transform: scale(1); }@keyframes blink{ 0% { opacity: 1; } 100% { opacity: 0; } }@keyframes glitch-flash{ 0% { opacity: 0; } 10% { opacity: 0.8; } 20% { opacity: 0.1; } 30% { opacity: 0.9; } 100% { opacity: 0; } }

/* scene-10 */
.sv-scene-root-scene-10 .s-scene-10-wrapper{ width: 100%; height: 100%; background: #000; font-family: var(--sv-font-mono); color: #00FF41; position: relative; overflow: hidden; }.sv-scene-root-scene-10 .crt-scanlines{ position: absolute; inset: 0; background: linear-gradient(rgba(0, 255, 65, 0.08) 50%, transparent 50%); background-size: 100% 4px; pointer-events: none; z-index: 10; }.sv-scene-root-scene-10 .ambient-glow{ position: absolute; inset: 0; background: radial-gradient(circle at center, rgba(0, 255, 65, 0.03) 0%, transparent 70%); pointer-events: none; }.sv-scene-root-scene-10 .thirds-container{ display: flex; width: 100%; height: 100%; align-items: center; justify-content: space-between; padding: 0 5%; box-sizing: border-box; }.sv-scene-root-scene-10 .col-left, .sv-scene-root-scene-10 .col-center, .sv-scene-root-scene-10 .col-right{ flex: 1; display: flex; flex-direction: column; align-items: center; transition: all 0.5s cubic-bezier(0.22, 1, 0.36, 1); }.sv-scene-root-scene-10 /* Left: Update Box */
.status-box{ border: 2px solid rgba(0, 255, 65, 0.4); padding: 30px; background: rgba(0, 255, 65, 0.05); text-align: center; width: 300px; }.sv-scene-root-scene-10 .status-header{ font-size: 14px; letter-spacing: 2px; border-bottom: 1px solid rgba(0, 255, 65, 0.4); padding-bottom: 10px; margin-bottom: 20px; opacity: 0.8; }.sv-scene-root-scene-10 .main-patch-icon{ font-size: 80px; filter: drop-shadow(0 0 10px rgba(0, 255, 65, 0.5)); }.sv-scene-root-scene-10 .update-text-glitch{ font-size: 28px; font-weight: 900; margin-top: 15px; text-shadow: 2px 0 #39FF14; animation: blink 0.8s infinite; }.sv-scene-root-scene-10 .status-details{ margin-top: 20px; text-align: left; font-size: 12px; line-height: 1.8; opacity: 0.7; }.sv-scene-root-scene-10 /* Right: Terminal */
.command-window{ width: 400px; height: 200px; background: #000; border: 1px solid rgba(0, 255, 65, 0.3); box-shadow: 0 10px 40px rgba(0, 0, 0, 0.8); }.sv-scene-root-scene-10 .window-bar{ height: 25px; background: rgba(0, 255, 65, 0.1); display: flex; align-items: center; padding: 0 10px; gap: 5px; }.sv-scene-root-scene-10 .dot{ width: 6px; height: 6px; border: 1px solid #00FF41; border-radius: 50%; }.sv-scene-root-scene-10 .window-title{ font-size: 10px; margin-left: 10px; opacity: 0.6; }.sv-scene-root-scene-10 .terminal-body{ padding: 15px; font-size: 16px; }.sv-scene-root-scene-10 .user{ color: #39FF14; }.sv-scene-root-scene-10 .shell-output{ margin-top: 15px; font-size: 12px; color: #39FF14; opacity: 0; transform: translateY(10px); transition: 0.4s; }.sv-scene-root-scene-10 [data-step="1"] .shell-output{ opacity: 1; transform: translateY(0); }.sv-scene-root-scene-10 .terminal-cursor{ display: inline-block; width: 8px; height: 18px; background: #00FF41; animation: blink 1s infinite steps(2); vertical-align: middle; margin-left: 4px; }.sv-scene-root-scene-10 /* Center: Bomb */
.bomb-stage{ position: relative; text-align: center; }.sv-scene-root-scene-10 .bomb-svg{ width: 220px; height: 220px; }.sv-scene-root-scene-10 .fuse-path{ stroke-dasharray: 100; stroke-dashoffset: 0; }.sv-scene-root-scene-10 .cut-mark{ opacity: 0; transform: scale(0.5); transform-origin: center; transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); }.sv-scene-root-scene-10 [data-step="2"] .cut-mark{ opacity: 1; transform: scale(1); }.sv-scene-root-scene-10 [data-step="2"] .fuse-path{ stroke-dasharray: 10 5; opacity: 0.5; }.sv-scene-root-scene-10 .threat-status{ margin-top: 20px; font-size: 24px; font-weight: 900; letter-spacing: 4px; color: #39FF14; text-shadow: 0 0 15px rgba(0, 255, 65, 0.6); }.sv-scene-root-scene-10 .footer-deco{ position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); font-size: 12px; opacity: 0.3; letter-spacing: 5px; }@keyframes blink{ 0% { opacity: 1; } 100% { opacity: 0; } }@keyframes draw{ to { stroke-dashoffset: 0; } }

/* scene-11 */
.sv-scene-root-scene-11 .s-scene-11-wrapper{ width: 100%; height: 100%; background: #000; font-family: var(--sv-font-mono); color: #00FF41; position: relative; overflow: hidden; display: flex; flex-direction: column; align-items: center; justify-content: center; }.sv-scene-root-scene-11 .crt-scanlines{ position: absolute; inset: 0; background: linear-gradient(rgba(0, 255, 65, 0.1) 50%, transparent 50%); background-size: 100% 3px; pointer-events: none; z-index: 100; opacity: 0.12; }.sv-scene-root-scene-11 .ambient-glow{ position: absolute; inset: 0; background: radial-gradient(circle at center, rgba(0, 255, 65, 0.04) 0%, transparent 80%); animation: pulse 10s infinite; }.sv-scene-root-scene-11 .logo-overlay{ text-align: center; z-index: 20; transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1); }.sv-scene-root-scene-11 .avatar-frame{ width: 120px; height: 120px; border: 2px solid #00FF41; position: relative; padding: 10px; box-shadow: 0 0 20px rgba(0, 255, 65, 0.15); display: inline-block; background: #000; }.sv-scene-root-scene-11 .terminal-logo{ width: 100%; height: 100%; }.sv-scene-root-scene-11 .channel-id{ margin-top: 15px; font-size: 14px; letter-spacing: 2px; opacity: 0.8; }.sv-scene-root-scene-11 .action-container{ position: absolute; inset: 0; pointer-events: none; display: flex; align-items: center; justify-content: center; }.sv-scene-root-scene-11 .action-item{ position: absolute; transition: all 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275); opacity: 0; transform: scale(0.5); }.sv-scene-root-scene-11 .like-item{ left: 15%; }.sv-scene-root-scene-11 .follow-item{ right: 15%; }.sv-scene-root-scene-11 [data-step="1"] .action-item{ opacity: 1; transform: scale(1); }.sv-scene-root-scene-11 .action-box{ border: 1px solid #00FF41; background: rgba(0, 255, 65, 0.05); padding: 20px; display: flex; flex-direction: column; align-items: center; gap: 10px; }.sv-scene-root-scene-11 .action-box i{ width: 40px; height: 40px; }.sv-scene-root-scene-11 .action-label{ font-size: 12px; font-weight: bold; }.sv-scene-root-scene-11 .closing-text{ position: absolute; bottom: 15%; text-align: center; opacity: 0; transform: translateY(20px); transition: all 0.8s ease; display: flex; align-items: center; gap: 10px; }.sv-scene-root-scene-11 [data-step="1"] .closing-text{ opacity: 1; transform: translateY(0); }.sv-scene-root-scene-11 .rainbow-terminal-text{ font-size: 64px; font-family: var(--sv-font-display-cn); font-weight: 900; background: linear-gradient(90deg, #00FF41, #39FF14, #00FF41); -webkit-background-clip: text; color: transparent; animation: shift 4s linear infinite; text-shadow: 0 0 10px rgba(0, 255, 65, 0.3); }.sv-scene-root-scene-11 .cursor-blink{ width: 25px; height: 60px; background: #00FF41; animation: blink 1s infinite steps(2); }.sv-scene-root-scene-11 .system-footer{ position: absolute; bottom: 5%; font-size: 10px; opacity: 0.4; letter-spacing: 1px; }@keyframes pulse{ 0%, 100% { opacity: 0.04; } 50% { opacity: 0.08; } }@keyframes blink{ 0% { opacity: 1; } 100% { opacity: 0; } }@keyframes shift{ 0% { background-position: 0% 50%; } 100% { background-position: 200% 50%; } }
  </style>
</head>
<body data-orientation="landscape">
  <div id="app">
    <div id="viewport">
      <div id="stage">

<section class="scene" data-scene-id="scene-01">
  <div class="sv-scene-root sv-scene-root-scene-01" data-scene-root-id="scene-01">
<div class="s-scene-01-container">
  <div class="scanline"></div>
  <div class="vignette"></div>

  <!-- Step 0: Alert System -->
  <div class="alert-overlay" data-step="0">
    <div class="alert-content">
      <div class="ascii-alert">
        !!! CRITICAL_SYSTEM_VULNERABILITY !!!
      </div>
      <div class="alert-tag">[ KERNEL_EXPLOIT_DETECTED ]</div>
    </div>
  </div>

  <!-- Step 1: Terminal Cards -->
  <div class="terminal-wrapper">
    <div class="terminal-card left" data-step="1">
      <div class="terminal-header">guest@linux: ~</div>
      <div class="terminal-body">
        <div class="line"><span class="prompt">$</span> whoami</div>
        <div class="line glow-text">guest</div>
        <div class="line cursor">_</div>
      </div>
    </div>

    <div class="terminal-card right" data-step="1">
      <div class="terminal-header">root@local: #</div>
      <div class="terminal-body">
        <div class="line"><span class="prompt">#</span> whoami</div>
        <div class="line ghost-text">??????</div>
        <div class="line cursor">_</div>
      </div>
    </div>
  </div>

  <!-- Step 2: Connection / Seizure -->
  <div class="lightning-container" data-step="2">
    <svg class="lightning-svg" viewBox="0 0 800 400">
      <path class="lightning-path" d="M 280 200 L 350 180 L 400 220 L 450 180 L 520 200" />
      <filter id="glow">
        <feGaussianBlur stdDeviation="4" result="coloredBlur"/>
        <feMerge>
          <feMergeNode in="coloredBlur"/>
          <feMergeNode in="SourceGraphic"/>
        </feMerge>
      </filter>
    </svg>
    <div class="status-text">PRIVILEGE ESCALATION SUCCESSFUL</div>
  </div>

  <!-- Background Decor -->
  <div class="bg-grid"></div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-02">
  <div class="sv-scene-root sv-scene-root-scene-02" data-scene-root-id="scene-02">
<div class="s-scene-02-container">
  <div class="crt-overlay"></div>
  <div class="ambient-phosphor"></div>
  <div class="grid-bg"></div>

  <!-- Step 0: Vulnerability ID -->
  <div class="vulnerability-wrapper" data-step="0">
    <h1 class="cve-text">CVE-2026-31431</h1>
    <div class="cve-glow"></div>
  </div>

  <!-- Step 1: Copy Fail & Tearing -->
  <div class="fail-container" data-step="1">
    <h2 class="fail-text">COPY FAIL</h2>
    <div class="tear-particles">
      <svg viewBox="0 0 1000 400" preserveAspectRatio="none">
        <path class="tear-line l1" d="M0,100 L200,120 L400,90 L600,110 L800,85 L1000,105" />
        <path class="tear-line l2" d="M0,250 L250,230 L500,260 L750,240 L1000,270" />
        <path class="tear-line l3" d="M0,320 L300,340 L700,310 L1000,330" />
      </svg>
    </div>
    <div class="glitch-block"></div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-03">
  <div class="sv-scene-root sv-scene-root-scene-03" data-scene-root-id="scene-03">
<div class="s-scene-03-container">
  <div class="crt-lines"></div>
  <div class="ambient-glow"></div>

  <!-- Step 0: Timeline -->
  <div class="timeline-section" data-step="0">
    <div class="timeline-wrapper">
      <span class="time-label">[ 2017 ]</span>
      <div class="timeline-bar">
        <div class="timeline-fill"></div>
        <div class="timeline-arrow">>></div>
      </div>
      <span class="time-label pulse-text">至今</span>
    </div>
  </div>

  <!-- Step 1: Linux Distribution Grid -->
  <div class="distro-grid-container" data-step="1">
    <div class="grid-header">SYSTEM_SCAN_TARGETS: IN_PROGRESS...</div>
    <div class="distro-grid">
      <div class="distro-card" data-distro="ubuntu">
        <iconify-icon icon="simple-icons:ubuntu"></iconify-icon>
        <span class="distro-name">Ubuntu</span>
      </div>
      <div class="distro-card" data-distro="centos">
        <iconify-icon icon="simple-icons:centos"></iconify-icon>
        <span class="distro-name">CentOS</span>
      </div>
      <div class="distro-card" data-distro="rhel">
        <iconify-icon icon="simple-icons:redhat"></iconify-icon>
        <span class="distro-name">RHEL</span>
      </div>
      <div class="distro-card" data-distro="aws">
        <iconify-icon icon="simple-icons:amazonwebservices"></iconify-icon>
        <span class="distro-name">AWS Linux</span>
      </div>
      <div class="distro-card" data-distro="aliyun">
        <iconify-icon icon="simple-icons:alibabacloud"></iconify-icon>
        <span class="distro-name">AliyunOS</span>
      </div>
      <div class="distro-card" data-distro="suse">
        <iconify-icon icon="simple-icons:suse"></iconify-icon>
        <span class="distro-name">SUSE</span>
      </div>
    </div>
    <div class="shimmer-overlay"></div>
  </div>

  <!-- Step 2: Vulnerable Stamp -->
  <div class="vulnerable-overlay" data-step="2">
    <div class="stamp-box">
      <div class="stamp-text">VULNERABLE</div>
      <div class="stamp-subtext">受威胁状态</div>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-04">
  <div class="sv-scene-root sv-scene-root-scene-04" data-scene-root-id="scene-04">
<div class="s-scene-04-wrapper">
  <div class="crt-lines"></div>
  <div class="ambient-glow"></div>

  <div class="system-layout">
    <!-- Left: Container -->
    <div class="node-container">
      <div class="system-node box-node">
        <div class="node-label">[ CONTAINER ]</div>
        <div class="internal-process">
          <div class="cursor-blink"></div>
          <span class="mono-text">UID: 1000</span>
        </div>
      </div>
    </div>

    <!-- SVG Layer for the Arrow -->
    <div class="vector-layer">
      <svg viewBox="0 0 800 400" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path id="attack-path" d="M 240 200 L 560 200" stroke="#FF3131" stroke-width="4" stroke-dasharray="320" stroke-dashoffset="320" />
        <path id="arrow-head" d="M 545 185 L 565 200 L 545 215" stroke="#FF3131" stroke-width="4" opacity="0" />
      </svg>
    </div>

    <!-- Right: Host -->
    <div class="node-container">
      <div class="system-node circle-node" id="host-node">
        <div class="node-label">[ HOST_SYSTEM ]</div>
        <div class="internal-process">
          <span class="status-text">KERNEL_IDLE</span>
        </div>
      </div>
    </div>
  </div>

  <!-- Success Banner -->
  <div class="success-banner" data-step="1">
    <div class="glitch-box">
      <span class="success-text">> 提权成功: ESCAPED_TO_ROOT</span>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-05">
  <div class="sv-scene-root sv-scene-root-scene-05" data-scene-root-id="scene-05">
<div class="s-scene-05-wrapper">
  <div class="crt-scanlines"></div>
  <div class="ambient-phosphor"></div>

  <!-- Step 0: Memory Container -->
  <div class="memory-container">
    <div class="memory-label">[ PHYSICAL_RAM_MAPPING ]</div>
    <div class="memory-grid"></div>

    <!-- Step 1: Page Cache Card -->
    <div class="page-cache-card" data-step="1">
      <div class="card-header">
        <span class="card-title">PAGE_CACHE_OBJECT</span>
        <span class="memory-addr">0x7FFF0042</span>
      </div>
      <div class="binary-content">
        <div class="binary-line">10110010 11100001 00011101</div>
        <div class="binary-line">11001010 01111100 11010001</div>
        <div class="binary-line">00110101 10100011 00011110</div>
        <div class="binary-line">11110000 00001111 10101010</div>
      </div>
      
      <!-- Step 2: Security Overlay -->
      <div class="security-status" data-step="2">
        <div class="lock-overlay">
          <i data-lucide="lock"></i>
          <span class="read-only-text">READ_ONLY</span>
        </div>
        <div class="forbidden-action">
          <div class="action-item">
            <span class="action-label">WRITE_REQ</span>
            <div class="forbidden-sign"></div>
          </div>
          <div class="action-item">
            <span class="action-label">MODIFY_REQ</span>
            <div class="forbidden-sign"></div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <!-- Background Text -->
  <div class="ghost-text">KERNEL_SPACE</div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-06">
  <div class="sv-scene-root sv-scene-root-scene-06" data-scene-root-id="scene-06">
<div class="s-scene-06-wrapper">
  <div class="crt-overlay"></div>
  <div class="ambient-glow"></div>

  <!-- Step 0: Terminal Window -->
  <div class="terminal-container" id="term-06">
    <div class="term-header">
      <div class="term-controls"><span></span><span></span><span></span></div>
      <div class="term-title">K-SHELL v4.1</div>
    </div>
    <div class="term-content">
      <div class="typing-line" data-delay="1">$ modprobe af_alg</div>
      <div class="typing-line" data-delay="2">$ call <span class="highlight">splice()</span></div>
      <div class="typing-line blinking-cursor">_</div>
    </div>
  </div>

  <!-- Step 1: Conduit & Target File -->
  <div class="conduit-system">
    <svg class="conduit-svg" viewBox="0 0 1000 600">
      <path id="conduit-path" d="M280,300 L450,300" fill="none" stroke="#00FF41" stroke-width="4" stroke-dasharray="1000" stroke-dashoffset="1000" />
      <circle cx="280" cy="300" r="5" fill="#00FF41" class="node-point" />
    </svg>
    <div class="file-node" id="su-file-node">
      <div class="file-icon-box">
        <iconify-icon icon="mdi:file-lock-outline"></iconify-icon>
      </div>
      <div class="file-info">
        <span class="file-name">/usr/bin/su</span>
        <span class="file-perm">ROOT_SUID: 4755</span>
      </div>
    </div>
  </div>

  <!-- Step 2: Encryption Flow & Chains -->
  <div class="pipeline-stage" id="encrypt-stage">
    <div class="pipeline-box">
      <div class="pipeline-label">[ KERNEL_CRYPTO_API ]</div>
      <div class="chain-container">
         <div class="chain-link"></div>
         <div class="chain-link"></div>
         <div class="chain-link"></div>
      </div>
      <div class="flow-indicator">ENCRYPTION_IN_PROGRESS</div>
    </div>
  </div>

  <div class="side-status">
    <div class="status-item" data-step="1">> CHANNEL_ESTABLISHED</div>
    <div class="status-item" data-step="2">> FILE_INGESTION: FORCE</div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-07">
  <div class="sv-scene-root sv-scene-root-scene-07" data-scene-root-id="scene-07">
<div class="s-scene-07-wrapper">
  <div class="crt-overlay"></div>
  <div class="ambient-glow"></div>
  
  <!-- Alert Overlay (Step 2) -->
  <div class="alert-pulse-overlay" data-step="2"></div>

  <div class="layout-container">
    <!-- Left: Code Section -->
    <div class="code-section">
      <div class="section-label">2017 内核优化代码</div>
      <div class="terminal-window">
        <div class="term-header">
           <div class="term-dots"><span></span><span></span><span></span></div>
           <div class="term-title">mm/gup.c</div>
        </div>
        <div class="code-content">
          <pre><code><span class="line">/* Optimization: No COW needed? */</span>
<span class="line">if (flags & FOLL_FORCE) {</span>
<span class="line highlight-target">  vma-&gt;vm_flags |= <span class="code-keyword">VM_MAYWRITE</span>;</span>
<span class="line">  <span class="code-comment">// Treat as writable buffer</span></span>
<span class="line">}</span></code></pre>
        </div>
      </div>
    </div>

    <!-- Middle: Conduit -->
    <div class="conduit-container">
      <svg class="conduit-svg" viewBox="0 0 200 100">
        <path class="arrow-path" d="M0,50 L180,50" fill="none" stroke="#00FF41" stroke-width="2" />
        <polygon points="180,45 195,50 180,55" fill="#00FF41" class="arrow-head" />
      </svg>
    </div>

    <!-- Right: Memory Page Section -->
    <div class="memory-section">
      <div class="section-label">物理内存页面</div>
      <div class="page-frame">
        <div class="page-grid">
          <span></span><span></span><span></span><span></span>
          <span></span><span></span><span></span><span></span>
        </div>
        <div class="permission-status">
          <div class="lock-container" id="perm-lock">
             <div class="lock-icon"><iconify-icon icon="mdi:lock-outline"></iconify-icon></div>
             <div class="lock-text">只读 (RO)</div>
          </div>
          <div class="rw-status" id="perm-rw">
             <div class="rw-glitch">可写 (RW)</div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div class="status-bar">
    <div class="status-msg">SYSTEM_OPTIMIZATION: ACTIVE</div>
    <div class="status-msg" data-step="1">CRITICAL: PERMISSION_BYPASS_DETECTED</div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-08">
  <div class="sv-scene-root sv-scene-root-scene-08" data-scene-root-id="scene-08">
<div class="s-scene-08-wrapper">
  <div class="crt-scanlines"></div>
  <div class="ambient-glow"></div>

  <!-- Zoomed Hex Grid Viewport -->
  <div class="hex-viewport">
    <div class="viewport-header">
      <span class="addr-label">OFFSET: 0x00007FFF</span>
      <span class="status-tag" id="mem-status">[ MEMORY_READ_ONLY ]</span>
    </div>
    <div class="hex-grid-container">
      <div class="hex-grid" id="main-hex-grid">
        <!-- Generated cells will be here -->
      </div>
    </div>
  </div>

  <!-- Flying Bytes (Step 0: Visible, Step 1: Animate) -->
  <div class="missile-container">
    <div class="byte-missile" data-target="target-1" data-step="0">0x53</div>
    <div class="byte-missile" data-target="target-2" data-step="0">0x55</div>
    <div class="byte-missile" data-target="target-3" data-step="0">0x49</div>
    <div class="byte-missile" data-target="target-4" data-step="0">0x44</div>
  </div>

  <!-- Alert Overlay (Step 2) -->
  <div class="alert-overlay" data-step="2">
    <div class="alert-box">
      <div class="alert-header">CRITICAL_ERROR</div>
      <div class="alert-content">VALIDATION_FAILED: HASH_MISMATCH</div>
      <div class="alert-sub">ENCRYPTED_BLOCK_CORRUPTED</div>
    </div>
  </div>

  <!-- Bottom Status -->
  <div class="terminal-footer">
    <div class="cursor-line"><span class="prompt">$</span> <span class="typing-text">patching su_binary...</span><span class="cursor"></span></div>
    <div class="progress-section" data-step="1">
      <span class="label">INJECTION:</span>
      <span class="bar-bg"><span class="bar-fill" id="injection-bar"></span></span>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-09">
  <div class="sv-scene-root sv-scene-root-scene-09" data-scene-root-id="scene-09">
<div class="s-scene-09-wrapper">
  <div class="crt-scanlines"></div>
  <div class="ambient-glow"></div>

  <!-- Terminal Interface Container -->
  <div class="terminal-interface">
    <div class="terminal-header">
      <div class="terminal-buttons">
        <span></span><span></span><span></span>
      </div>
      <div class="terminal-title">TERMINAL - su_exploit_session</div>
    </div>

    <div class="terminal-content">
      <!-- Input History -->
      <div class="log-line">[ OK ] Payload injected into memory segment 0x0804...</div>
      <div class="log-line">[ OK ] Hooking execution vector...</div>
      
      <!-- Main Prompt Line -->
      <div class="prompt-area">
        <span class="prompt-char" id="current-prompt">$</span>
        <span class="command-text">whoami</span>
        <span class="cursor"></span>
      </div>

      <!-- Result Output (Step 0-1 Hidden) -->
      <div class="result-output" data-step="2">
        <div class="root-banner" id="root-text-container">
          <!-- root text will be typed here -->
        </div>
      </div>
    </div>

    <!-- Bottom Status Bar -->
    <div class="terminal-footer-bar">
      <div class="status-item">STATUS: <span class="blink-text">RUNNING</span></div>
      <div class="status-item">PRIVILEGE: <span id="priv-level">USER</span></div>
      <div class="status-item" data-step="2">UID: 0 (root)</div>
    </div>
  </div>

  <!-- Flash Overlay for Step 1 -->
  <div class="lightning-flash" id="flash-overlay"></div>

  <!-- Success Glow Frame (Step 2) -->
  <div class="success-frame" data-step="2"></div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-10">
  <div class="sv-scene-root sv-scene-root-scene-10" data-scene-root-id="scene-10">
<div class="s-scene-10-wrapper">
  <div class="crt-scanlines"></div>
  <div class="ambient-glow"></div>

  <div class="thirds-container">
    <!-- Step 0: Left Column - Patch Info -->
    <div class="col-left" data-step="0">
      <div class="status-box">
        <div class="status-header">SYSTEM_ALERT</div>
        <div class="patch-icon-wrapper">
          <iconify-icon icon="mdi:shield-sync-outline" class="main-patch-icon"></iconify-icon>
          <div class="update-text-glitch">UPDATE NOW</div>
        </div>
        <div class="status-details">
          <div class="status-line">> KERNEL: VULNERABLE</div>
          <div class="status-line blinking">> PATCH: AVAILABLE</div>
        </div>
      </div>
    </div>

    <!-- Step 2: Center Column - Defused Bomb -->
    <div class="col-center" data-step="2">
      <div class="bomb-stage">
        <svg viewBox="0 0 200 200" class="bomb-svg">
          <!-- Fuse -->
          <path d="M120 40 Q 150 20, 160 60" fill="none" stroke="#00FF41" stroke-width="4" class="fuse-path" />
          <!-- Bomb Body -->
          <circle cx="100" cy="110" r="60" fill="none" stroke="#00FF41" stroke-width="6" />
          <rect x="85" y="45" width="30" height="15" fill="#000" stroke="#00FF41" stroke-width="4" />
          <!-- Cut Mark -->
          <path d="M135 25 L 155 45 M 155 25 L 135 45" stroke="#39FF14" stroke-width="8" class="cut-mark" />
        </svg>
        <div class="threat-status">THREAT_NEUTRALIZED</div>
      </div>
    </div>

    <!-- Step 1: Right Column - Terminal Command -->
    <div class="col-right" data-step="1">
      <div class="command-window">
        <div class="window-bar">
          <span class="dot"></span><span class="dot"></span><span class="dot"></span>
          <span class="window-title">bash - root</span>
        </div>
        <div class="terminal-body">
          <div class="shell-prompt">
            <span class="user">root@system</span>:<span class="path">~</span>#
            <span class="typing-cmd" id="cmd-text"></span><span class="terminal-cursor"></span>
          </div>
          <div class="shell-output" data-step="1">[ SUCCESS ] Module 'algif_aead' disabled.</div>
        </div>
      </div>
    </div>
  </div>

  <div class="footer-deco">SECURITY_ENFORCED // 0xPATCH_SUCCESS</div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-11">
  <div class="sv-scene-root sv-scene-root-scene-11" data-scene-root-id="scene-11">
<div class="s-scene-11-wrapper">
  <div class="crt-scanlines"></div>
  <div class="ambient-glow"></div>

  <!-- Step 0: Center Logo/Avatar -->
  <div class="logo-overlay" data-step="0">
    <div class="avatar-frame">
      <div class="avatar-glitch"></div>
      <svg viewBox="0 0 100 100" class="terminal-logo">
        <rect x="20" y="20" width="60" height="60" stroke="#00FF41" stroke-width="2" fill="none" />
        <path d="M35 40 L50 55 L65 40" stroke="#00FF41" stroke-width="4" fill="none" />
        <path d="M30 70 L70 70" stroke="#00FF41" stroke-width="2" stroke-dasharray="4 2" />
      </svg>
    </div>
    <div class="channel-id">[ CHANNEL_ID: ROOT_NODE ]</div>
  </div>

  <!-- Step 1: Interactive Actions & Outro -->
  <div class="action-container" data-step="1">
    <!-- Like Action -->
    <div class="action-item like-item">
      <div class="action-box">
        <i data-lucide="thumbs-up"></i>
        <span class="action-label">LIKE_SUCCESS</span>
      </div>
    </div>

    <!-- Follow Action -->
    <div class="action-item follow-item">
      <div class="action-box">
        <i data-lucide="user-plus"></i>
        <span class="action-label">SUBSCRIBE_OK</span>
      </div>
    </div>

    <!-- Closing Text -->
    <div class="closing-text">
      <div class="rainbow-terminal-text">下期再见</div>
      <div class="cursor-blink"></div>
    </div>
  </div>

  <div class="system-footer">
    SESSION_TERMINATED: 0x00000000
  </div>
</div>
  </div>
</section>
      </div>
    </div>
  </div>
  <script id="__SVGVIDEO_META__" type="application/json">{"version":2,"format":"json","title":"Linux内核超级漏洞：Copy Fail 深度解析","fullScript":"兄弟们，一个超级离谱的Linux内核漏洞刚刚曝光！普通用户一句话，就能把服务器的root权限直接抢到手！它的编号叫CVE-2026-31431，代号Copy Fail！这个漏洞影响了2017年之后几乎所有主流Linux发行版，Ubuntu、CentOS、RHEL、阿里云、AWS、SUSE通通中招。只要你在服务器上有一个普通账号，就能完成提权，连容器都能逃逸到主机上。原理其实特别巧妙，听我给你捋清楚：正常情况下，文件的内容会缓存在内存里，叫做page cache。我们普通用户只能读它，不能随便改它。但是黑客利用了内核提供的一个加密接口AF_ALG，再配合splice这个系统调用，把目标文件——比如/usr/bin/su——偷偷塞进了内核的加密流程里。因为2017年内核做了一个性能优化，这个优化让内核把这个文件的内存页面，当成了“可写的缓冲区”来使用！结果，黑客在加密计算的过程中，就往里面精准地写入了4个自己控制的字节。虽然最后加密验证失败了，但那4个字节已经实实在在地改进了内存里的su程序！重复操作几次，就能把su改造成一个“直接给我root”的恶意程序。一执行，权限就到手了！整个过程不需要猜内核地址，也不用竞态条件，稳得一批。目前各大厂商已经紧急推送了补丁，大家赶紧更新内核！临时缓解的话，可以把algif_aead模块禁用掉。这个漏洞再次告诉我们：再小的代码优化，如果没想清楚，也可能埋下致命的炸弹。好了，今天的分享就到这里，点赞关注，我们下期再见！","visualStyleId":"terminal-green","orientation":"landscape","scenes":[{"id":"scene-01","title":"震撼开场","steps":3,"status":"success","prompt":"横屏构图。背景为深暗色科技感网格。Step 0: 屏幕中心出现巨大的红色警示图标，伴随闪烁效果。Step 1: 左右两侧弹出两个黑色毛玻璃卡片，左边写着‘普通用户’，右边写着‘ROOT权限’。Step 2: 一个金色的闪电特效连接两个卡片，表示权限瞬间被夺取。视觉风格：赛博朋克、高对比度。","scriptText":"兄弟们，一个超级离谱的Linux内核漏洞刚刚曝光！普通用户一句话，就能把服务器的root权限直接抢到手！","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_62574c6d-8ac1-43ff-8ab8-d4a1a16f8fc4/s_scene-01/v_xiaoxiao-hd/a_d40ec182_1777539050814_nzb69g.mp3","audioDurationMs":8424,"voiceName":"xiaoxiao-hd","relatedSceneIds":["scene-02"],"transition":"door"},{"id":"scene-02","title":"漏洞代号曝光","steps":2,"status":"success","prompt":"横屏构图。中心位置展示加粗的渐变文字‘CVE-2026-31431’，带有蓝色的呼吸光效。Step 0: 文字从屏幕中央通过弹簧缩放效果出现。Step 1: 下方浮现更大的红色文字‘Copy Fail’，背景出现类似文件被撕裂的SVG粒子效果。整体色调偏冷。","scriptText":"它的编号叫CVE 2026 31431，代号Copy Fail！","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_62574c6d-8ac1-43ff-8ab8-d4a1a16f8fc4/s_scene-02/v_xiaoxiao-hd-cheerful/a_e74d6042_1777541496139_ldxv7g.mp3","audioDurationMs":5112,"voiceName":"xiaoxiao-hd","voiceStyle":"cheerful","relatedSceneIds":["scene-03"],"transition":"door"},{"id":"scene-03","title":"受影响范围","steps":3,"status":"success","prompt":"横屏，左右平铺布局。Step 0: 屏幕左侧出现一个‘2017’的时间标签，向右拉出一条时间轴到‘至今’。Step 1: 屏幕中间网格化排列主流Linux Logo（Ubuntu, CentOS, RHEL, AWS, 阿里云）。Step 2: 所有图标由蓝转红，并出现‘Vulnerable’（受威胁）的印章动画覆盖。使用微光（shimmer）特效扫描整个网格。","scriptText":"这个漏洞影响了2017年之后几乎所有主流Linux发行版","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_62574c6d-8ac1-43ff-8ab8-d4a1a16f8fc4/s_scene-03/v_xiaoxiao-hd-cheerful/a_7c58a451_1777541525511_w8aeas.mp3","audioDurationMs":4392,"voiceName":"xiaoxiao-hd","voiceStyle":"cheerful","relatedSceneIds":["scene-04"],"transition":"door"},{"id":"scene-04","title":"攻击场景描述","steps":2,"status":"success","prompt":"横屏。左侧是一个代表‘容器’的方块，右侧是一个代表‘宿主机’的大圆圈。Step 0: 一个红色小箭从容器内部穿透边界射向宿主机。Step 1: 宿主机图标由灰白变为鲜红色，屏幕底部显示‘提权成功’的文字框。布局采用左右对称的极简矢量风格。","scriptText":"只要你在服务器上有一个普通账号，就能完成提权，连容器都能逃逸到主机上。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_62574c6d-8ac1-43ff-8ab8-d4a1a16f8fc4/s_scene-04/v_xiaoxiao-hd/a_3bb62f42_1777539099072_3xsdd0.mp3","audioDurationMs":5508,"voiceName":"xiaoxiao-hd","relatedSceneIds":["scene-05"],"transition":"door"},{"id":"scene-05","title":"原理科普：Page Cache","steps":3,"status":"success","prompt":"横屏。Step 0: 背景出现一个矩形区域代表‘内存’。Step 1: 内存中心浮现一个名为‘Page Cache’的半透明卡片，里面显示二进制代码流。Step 2: 卡片右上角出现一个‘只读（Read Only）’的锁头标志，一个禁止符号出现在‘修改’操作上。","scriptText":"原理其实特别巧妙，听我给你捋清楚：正常情况下，文件的内容会缓存在内存里，叫做page cache。我们普通用户只能读它，不能随便改它。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_62574c6d-8ac1-43ff-8ab8-d4a1a16f8fc4/s_scene-05/v_xiaoxiao-hd-cheerful/a_17a6b492_1777541700692_6vl3vo.mp3","audioDurationMs":10548,"voiceName":"xiaoxiao-hd","voiceStyle":"cheerful","relatedSceneIds":["scene-06"],"transition":"door"},{"id":"scene-06","title":"利用机制：AF_ALG","steps":2,"status":"success","prompt":"横屏，展示代码调用逻辑。Step 0: 屏幕左侧淡入一个终端窗口，显示代码‘AF_ALG’和‘splice()’。Step 1: 窗口中伸出一根导管，指向中间的‘/usr/bin/su’文件图标。Step 2: 整个su文件图标开始微微抖动，并被强制拖入一个带有锁链图案的‘加密流程’框内。","scriptText":"但是黑客利用了内核提供的一个加密接口AF_ALG，再配合splice这个系统调用，把目标文件——比如/usr/bin/su——偷偷塞进了内核的加密流程里。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_62574c6d-8ac1-43ff-8ab8-d4a1a16f8fc4/s_scene-06/v_xiaoxiao-hd-cheerful/a_8075a4cf_1777541754264_fwsej6.mp3","audioDurationMs":12348,"voiceName":"xiaoxiao-hd","voiceStyle":"cheerful","relatedSceneIds":["scene-07"],"transition":"door"},{"id":"scene-07","title":"漏洞核心：错误的写权限","steps":2,"status":"success","prompt":"横屏。左侧显示‘2017 内核优化代码’。Step 0: 高亮一段代码逻辑，箭头指向右侧的内存页面。Step 1: 原本的‘只读锁’瞬间碎裂，变成红色的‘可写（RW）’标识。背景出现警示性质的红色脉冲扩散动画。","scriptText":"因为2017年内核做了一个性能优化，这个优化让内核把这个文件的内存页面，当成了“可写的缓冲区”来使用！","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_62574c6d-8ac1-43ff-8ab8-d4a1a16f8fc4/s_scene-07/v_xiaoxiao-hd/a_7db73a0d_1777539106616_dmys7t.mp3","audioDurationMs":8424,"voiceName":"xiaoxiao-hd","relatedSceneIds":["scene-08"],"transition":"door"},{"id":"scene-08","title":"精准写入过程","steps":4,"status":"success","prompt":"横屏。中心放大展示代码块的一角。Step 0: 四个高亮的16进制字节（如 0x01 0x02 0x03 0x04）浮现。Step 1: 字节像导弹一样精准嵌入内存代码块的空隙。Step 2: 出现一个‘验证失败’的红色提示。Step 3: 但字节已停留在内存中，代码块由蓝变紫。细节采用微缩模型动画风格。","scriptText":"结果，黑客在加密计算的过程中，就往里面精准地写入了4个自己控制的字节。虽然最后加密验证失败了，但那4个字节已经实实在在地改进了内存里的su程序！","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_62574c6d-8ac1-43ff-8ab8-d4a1a16f8fc4/s_scene-08/v_xiaoxiao-hd/a_18d0460b_1777539109881_nhl5sl.mp3","audioDurationMs":12348,"voiceName":"xiaoxiao-hd","relatedSceneIds":["scene-09"],"transition":"door"},{"id":"scene-09","title":"获取Root权限","steps":3,"status":"success","prompt":"横屏，模拟终端界面。Step 0: 屏幕显示提示符‘$ whoami’。Step 1: 闪电式刷新，提示符变为‘# whoami’。Step 2: 屏幕爆发出巨大的‘root’字样，伴随成功的绿色发光边框。文字采用打字机效果逐字弹出。","scriptText":"重复操作几次，就能把su改造成一个“直接给我root”的恶意程序。一执行，权限就到手了！整个过程不需要猜内核地址，也不用竞态条件，稳得一批。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_62574c6d-8ac1-43ff-8ab8-d4a1a16f8fc4/s_scene-09/v_xiaoxiao-hd-cheerful/a_d4dbfe01_1777541610215_shlcai.mp3","audioDurationMs":11124,"voiceName":"xiaoxiao-hd","voiceStyle":"cheerful","relatedSceneIds":["scene-10"],"transition":"door"},{"id":"scene-10","title":"防御与总结","steps":3,"status":"success","prompt":"横屏，三分构图。Step 0: 左侧显示补丁图标‘UPDATE NOW’。Step 1: 右侧显示命令代码‘modprobe -r algif_aead’。Step 2: 屏幕中央出现一个引信被切断的炸弹图标。视觉风格：清晰、专业、带有安全提示感。","scriptText":"目前各大厂商已经紧急推送了补丁，大家赶紧更新内核！临时缓解的话，可以把algif_aead模块禁用掉。这个漏洞再次告诉我们：再小的代码优化，如果没想清楚，也可能埋下致命的炸弹。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_62574c6d-8ac1-43ff-8ab8-d4a1a16f8fc4/s_scene-10/v_xiaoxiao-hd-cheerful/a_bfafacde_1777541890973_en47qg.mp3","audioDurationMs":13860,"voiceName":"xiaoxiao-hd","voiceStyle":"cheerful","relatedSceneIds":["scene-11"],"transition":"door"},{"id":"scene-11","title":"结尾致谢","steps":2,"status":"success","prompt":"横屏。Step 0: 背景变暗，中心出现博主的头像或频道Logo。Step 1: 左右两侧飞入‘点赞’和‘关注’的SVG动态图标，带有Q弹的弹簧反馈效果。文字‘下期再见’以彩虹渐变色淡入。整体风格欢快、整洁。","scriptText":"好了，今天的分享就到这里，点赞关注，我们下期再见！","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_62574c6d-8ac1-43ff-8ab8-d4a1a16f8fc4/s_scene-11/v_xiaoxiao-hd-cheerful/a_1f8ff479_1777541651756_6js77f.mp3","audioDurationMs":4608,"voiceName":"xiaoxiao-hd","voiceStyle":"cheerful","transition":"door"}]}</script>
  <script id="__SVGVIDEO_SCENE_DATA__" type="application/json">[{"id":"scene-01","title":"震撼开场","steps":3,"html":"<div class=\"s-scene-01-container\">\n  <div class=\"scanline\"></div>\n  <div class=\"vignette\"></div>\n\n  <!-- Step 0: Alert System -->\n  <div class=\"alert-overlay\" data-step=\"0\">\n    <div class=\"alert-content\">\n      <div class=\"ascii-alert\">\n        !!! CRITICAL_SYSTEM_VULNERABILITY !!!\n      </div>\n      <div class=\"alert-tag\">[ KERNEL_EXPLOIT_DETECTED ]</div>\n    </div>\n  </div>\n\n  <!-- Step 1: Terminal Cards -->\n  <div class=\"terminal-wrapper\">\n    <div class=\"terminal-card left\" data-step=\"1\">\n      <div class=\"terminal-header\">guest@linux: ~</div>\n      <div class=\"terminal-body\">\n        <div class=\"line\"><span class=\"prompt\">$</span> whoami</div>\n        <div class=\"line glow-text\">guest</div>\n        <div class=\"line cursor\">_</div>\n      </div>\n    </div>\n\n    <div class=\"terminal-card right\" data-step=\"1\">\n      <div class=\"terminal-header\">root@local: #</div>\n      <div class=\"terminal-body\">\n        <div class=\"line\"><span class=\"prompt\">#</span> whoami</div>\n        <div class=\"line ghost-text\">??????</div>\n        <div class=\"line cursor\">_</div>\n      </div>\n    </div>\n  </div>\n\n  <!-- Step 2: Connection / Seizure -->\n  <div class=\"lightning-container\" data-step=\"2\">\n    <svg class=\"lightning-svg\" viewBox=\"0 0 800 400\">\n      <path class=\"lightning-path\" d=\"M 280 200 L 350 180 L 400 220 L 450 180 L 520 200\" />\n      <filter id=\"glow\">\n        <feGaussianBlur stdDeviation=\"4\" result=\"coloredBlur\"/>\n        <feMerge>\n          <feMergeNode in=\"coloredBlur\"/>\n          <feMergeNode in=\"SourceGraphic\"/>\n        </feMerge>\n      </filter>\n    </svg>\n    <div class=\"status-text\">PRIVILEGE ESCALATION SUCCESSFUL</div>\n  </div>\n\n  <!-- Background Decor -->\n  <div class=\"bg-grid\"></div>\n</div>","css":".s-scene-01-container {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #000000;\n  color: #00FF41;\n  font-family: var(--sv-font-mono);\n  overflow: hidden;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n}\n\n.scanline {\n  position: absolute;\n  inset: 0;\n  background: repeating-linear-gradient(rgba(0,0,0,0) 0px, rgba(0,0,0,0) 1px, rgba(0,255,65,0.08) 2px, rgba(0,255,65,0.08) 3px);\n  pointer-events: none;\n  z-index: 10;\n}\n\n.bg-grid {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(0, 255, 65, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(0, 255, 65, 0.05) 1px, transparent 1px);\n  background-size: 40px 40px;\n  animation: grid-move 20s linear infinite;\n}\n\n@keyframes grid-move {\n  from { background-position: 0 0; }\n  to { background-position: 40px 40px; }\n}\n\n.alert-overlay {\n  position: absolute;\n  z-index: 5;\n  text-align: center;\n  animation: alert-flicker 0.2s infinite alternate;\n}\n\n.ascii-alert {\n  font-size: 42px;\n  font-weight: bold;\n  border: 4px solid #00FF41;\n  padding: 20px 40px;\n  background: rgba(0, 255, 65, 0.1);\n}\n\n@keyframes alert-flicker {\n  0% { opacity: 1; transform: scale(1); }\n  100% { opacity: 0.7; transform: scale(1.02); }\n}\n\n.terminal-wrapper {\n  display: flex;\n  gap: 120px;\n  z-index: 4;\n}\n\n.terminal-card {\n  width: 320px;\n  height: 200px;\n  background: rgba(0, 0, 0, 0.9);\n  border: 1px solid rgba(0, 255, 65, 0.4);\n  box-shadow: 0 0 20px rgba(0, 255, 65, 0.1);\n  display: flex;\n  flex-direction: column;\n  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.5s;\n}\n\n.terminal-header {\n  background: rgba(0, 255, 65, 0.2);\n  padding: 6px 12px;\n  font-size: 14px;\n  border-bottom: 1px solid rgba(0, 255, 65, 0.4);\n}\n\n.terminal-body {\n  padding: 15px;\n  font-size: 18px;\n  line-height: 1.6;\n}\n\n.prompt { color: #39FF14; margin-right: 8px; }\n\n.cursor {\n  animation: blink 0.8s infinite;\n}\n\n@keyframes blink {\n  50% { opacity: 0; }\n}\n\n.lightning-container {\n  position: absolute;\n  inset: 0;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  pointer-events: none;\n}\n\n.lightning-path {\n  fill: none;\n  stroke: #39FF14;\n  stroke-width: 4;\n  stroke-dasharray: 600;\n  stroke-dashoffset: 600;\n  filter: url(#glow);\n  animation: strike 0.5s forwards;\n}\n\n@keyframes strike {\n  to { stroke-dashoffset: 0; }\n}\n\n.status-text {\n  margin-top: 250px;\n  font-size: 24px;\n  background: #00FF41;\n  color: #000;\n  padding: 5px 15px;\n  animation: slide-up 0.4s ease-out;\n}\n\n@keyframes slide-up {\n  from { opacity: 0; transform: translateY(20px); }\n  to { opacity: 1; transform: translateY(0); }\n}\n\n/* Step Transitions */\n[data-step=\"1\"] { opacity: 0; transform: translateY(30px); }\n.active [data-step=\"1\"] { opacity: 1; transform: translateY(0); }\n\n[data-step=\"2\"] { opacity: 0; }\n.active [data-step=\"2\"] { opacity: 1; }\n\n.terminal-card.right.active-root {\n  border-color: #39FF14;\n  box-shadow: 0 0 30px rgba(0, 255, 65, 0.4);\n}","js":"window.SceneLifecycle.register('scene-01', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-01\"]');\n    sceneRoot.classList.add('active');\n  },\n  step(step) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-01\"]');\n    const alert = sceneRoot.querySelector('.alert-overlay');\n    const rightTerminalBody = sceneRoot.querySelector('.terminal-card.right .terminal-body');\n\n    if (step >= 1) {\n      alert.style.opacity = '0.2';\n      alert.style.transform = 'scale(0.8) translateY(-150px)';\n      alert.style.transition = 'all 0.6s cubic-bezier(0.22, 1, 0.36, 1)';\n    }\n\n    if (step >= 2) {\n      const ghostText = rightTerminalBody.querySelector('.ghost-text');\n      if (ghostText) {\n        ghostText.textContent = 'root';\n        ghostText.classList.remove('ghost-text');\n        ghostText.style.color = '#39FF14';\n        ghostText.style.fontWeight = 'bold';\n      }\n      sceneRoot.querySelector('.terminal-card.right').classList.add('active-root');\n      \n      // Create rapid flicker effect on success\n      const bg = sceneRoot.querySelector('.bg-grid');\n      bg.style.animationDuration = '2s';\n    }\n  },\n  leave() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-01\"]');\n    sceneRoot.classList.remove('active');\n  }\n});"},{"id":"scene-02","title":"漏洞代号曝光","steps":2,"html":"<div class=\"s-scene-02-container\">\n  <div class=\"crt-overlay\"></div>\n  <div class=\"ambient-phosphor\"></div>\n  <div class=\"grid-bg\"></div>\n\n  <!-- Step 0: Vulnerability ID -->\n  <div class=\"vulnerability-wrapper\" data-step=\"0\">\n    <h1 class=\"cve-text\">CVE-2026-31431</h1>\n    <div class=\"cve-glow\"></div>\n  </div>\n\n  <!-- Step 1: Copy Fail & Tearing -->\n  <div class=\"fail-container\" data-step=\"1\">\n    <h2 class=\"fail-text\">COPY FAIL</h2>\n    <div class=\"tear-particles\">\n      <svg viewBox=\"0 0 1000 400\" preserveAspectRatio=\"none\">\n        <path class=\"tear-line l1\" d=\"M0,100 L200,120 L400,90 L600,110 L800,85 L1000,105\" />\n        <path class=\"tear-line l2\" d=\"M0,250 L250,230 L500,260 L750,240 L1000,270\" />\n        <path class=\"tear-line l3\" d=\"M0,320 L300,340 L700,310 L1000,330\" />\n      </svg>\n    </div>\n    <div class=\"glitch-block\"></div>\n  </div>\n</div>","css":".s-scene-02-container {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #000000;\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  font-family: var(--sv-font-mono);\n}\n\n.crt-overlay {\n  position: absolute;\n  inset: 0;\n  background: repeating-linear-gradient(rgba(0,0,0,0) 0px, rgba(0,0,0,0) 1px, rgba(0,255,65,0.06) 2px, rgba(0,255,65,0.06) 3px);\n  pointer-events: none;\n  z-index: 10;\n}\n\n.ambient-phosphor {\n  position: absolute;\n  width: 120%;\n  height: 120%;\n  background: radial-gradient(circle, rgba(0,255,65,0.05) 0%, transparent 70%);\n  animation: phosphor-pulse 8s ease-in-out infinite;\n  pointer-events: none;\n}\n\n.grid-bg {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(0, 255, 65, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(0, 255, 65, 0.03) 1px, transparent 1px);\n  background-size: 50px 50px;\n  opacity: 0.5;\n}\n\n.vulnerability-wrapper {\n  position: relative;\n  z-index: 5;\n  opacity: 0;\n  transform: scale(0);\n  transition: all 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n}\n\n.active [data-step=\"0\"] {\n  opacity: 1;\n  transform: scale(1);\n}\n\n.cve-text {\n  font-size: 108px;\n  font-weight: 900;\n  color: #00FF41;\n  letter-spacing: -2px;\n  text-shadow: 0 0 20px rgba(0, 255, 65, 0.6);\n  margin: 0;\n  animation: blue-breath 4s ease-in-out infinite;\n}\n\n@keyframes blue-breath {\n  0%, 100% { text-shadow: 0 0 20px rgba(0, 255, 65, 0.4); }\n  50% { text-shadow: 0 0 40px rgba(60, 150, 255, 0.7), 0 0 10px rgba(0, 255, 65, 0.5); }\n}\n\n.fail-container {\n  position: absolute;\n  top: 60%;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  opacity: 0;\n  transform: translateY(40px);\n  transition: all 0.5s ease-out;\n}\n\n.active [data-step=\"1\"] {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.fail-text {\n  font-size: 140px;\n  font-weight: 900;\n  color: #00FF41; \n  /* Semantically red but visually terminal phosphor */\n  background: #000;\n  border: 4px solid #00FF41;\n  padding: 0 40px;\n  mix-blend-mode: screen;\n  animation: critical-glitch 0.2s steps(2) infinite;\n}\n\n@keyframes critical-glitch {\n  0% { transform: skewX(0); opacity: 1; border-color: #00FF41; }\n  50% { transform: skewX(5deg); opacity: 0.8; border-color: rgba(255, 50, 50, 0.8); }\n}\n\n.tear-particles {\n  position: absolute;\n  inset: -100px -200px;\n  pointer-events: none;\n  z-index: -1;\n}\n\n.tear-line {\n  fill: none;\n  stroke: #00FF41;\n  stroke-width: 2;\n  stroke-dasharray: 1000;\n  stroke-dashoffset: 1000;\n  opacity: 0.4;\n}\n\n.active [data-step=\"1\"] .tear-line {\n  animation: tear-draw 0.8s forwards;\n}\n\n.l2 { animation-delay: 0.1s; }\n.l3 { animation-delay: 0.2s; }\n\n@keyframes tear-draw {\n  to { stroke-dashoffset: 0; opacity: 0.1; }\n}\n\n@keyframes phosphor-pulse {\n  0%, 100% { opacity: 0.4; transform: scale(1); }\n  50% { opacity: 0.6; transform: scale(1.05); }\n}","js":"window.SceneLifecycle.register('scene-02', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-02\"]');\n    sceneRoot.classList.add('active');\n  },\n  step(step) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-02\"]');\n    if (!sceneRoot) return;\n\n    const cveWrapper = sceneRoot.querySelector('.vulnerability-wrapper');\n    const failContainer = sceneRoot.querySelector('.fail-container');\n\n    if (step >= 1) {\n      // Impact effect when Copy Fail appears\n      cveWrapper.style.transform = 'scale(0.9) translateY(-100px)';\n      cveWrapper.style.filter = 'blur(1px)';\n      \n      // Create temporary tearing jitter\n      sceneRoot.style.animation = 'screen-shake 0.3s cubic-bezier(.36,.07,.19,.97) both';\n      setTimeout(() => {\n        sceneRoot.style.animation = '';\n      }, 300);\n    }\n  },\n  leave() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-02\"]');\n    if (sceneRoot) sceneRoot.classList.remove('active');\n  }\n});\n\n// Added shake keyframes via style injection since it's a one-off impact\nconst style = document.createElement('style');\nstyle.innerHTML = `\n  @keyframes screen-shake {\n    10%, 90% { transform: translate3d(-1px, 0, 0); }\n    20%, 80% { transform: translate3d(2px, 0, 0); }\n    30%, 50%, 70% { transform: translate3d(-4px, 0, 0); }\n    40%, 60% { transform: translate3d(4px, 0, 0); }\n  }\n`;\ndocument.head.appendChild(style);"},{"id":"scene-03","title":"受影响范围","steps":3,"html":"<div class=\"s-scene-03-container\">\n  <div class=\"crt-lines\"></div>\n  <div class=\"ambient-glow\"></div>\n\n  <!-- Step 0: Timeline -->\n  <div class=\"timeline-section\" data-step=\"0\">\n    <div class=\"timeline-wrapper\">\n      <span class=\"time-label\">[ 2017 ]</span>\n      <div class=\"timeline-bar\">\n        <div class=\"timeline-fill\"></div>\n        <div class=\"timeline-arrow\">>></div>\n      </div>\n      <span class=\"time-label pulse-text\">至今</span>\n    </div>\n  </div>\n\n  <!-- Step 1: Linux Distribution Grid -->\n  <div class=\"distro-grid-container\" data-step=\"1\">\n    <div class=\"grid-header\">SYSTEM_SCAN_TARGETS: IN_PROGRESS...</div>\n    <div class=\"distro-grid\">\n      <div class=\"distro-card\" data-distro=\"ubuntu\">\n        <iconify-icon icon=\"simple-icons:ubuntu\"></iconify-icon>\n        <span class=\"distro-name\">Ubuntu</span>\n      </div>\n      <div class=\"distro-card\" data-distro=\"centos\">\n        <iconify-icon icon=\"simple-icons:centos\"></iconify-icon>\n        <span class=\"distro-name\">CentOS</span>\n      </div>\n      <div class=\"distro-card\" data-distro=\"rhel\">\n        <iconify-icon icon=\"simple-icons:redhat\"></iconify-icon>\n        <span class=\"distro-name\">RHEL</span>\n      </div>\n      <div class=\"distro-card\" data-distro=\"aws\">\n        <iconify-icon icon=\"simple-icons:amazonwebservices\"></iconify-icon>\n        <span class=\"distro-name\">AWS Linux</span>\n      </div>\n      <div class=\"distro-card\" data-distro=\"aliyun\">\n        <iconify-icon icon=\"simple-icons:alibabacloud\"></iconify-icon>\n        <span class=\"distro-name\">AliyunOS</span>\n      </div>\n      <div class=\"distro-card\" data-distro=\"suse\">\n        <iconify-icon icon=\"simple-icons:suse\"></iconify-icon>\n        <span class=\"distro-name\">SUSE</span>\n      </div>\n    </div>\n    <div class=\"shimmer-overlay\"></div>\n  </div>\n\n  <!-- Step 2: Vulnerable Stamp -->\n  <div class=\"vulnerable-overlay\" data-step=\"2\">\n    <div class=\"stamp-box\">\n      <div class=\"stamp-text\">VULNERABLE</div>\n      <div class=\"stamp-subtext\">受威胁状态</div>\n    </div>\n  </div>\n</div>","css":".s-scene-03-container {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #000000;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  overflow: hidden;\n  font-family: var(--sv-font-mono);\n  color: #00FF41;\n}\n\n.crt-lines {\n  position: absolute;\n  inset: 0;\n  background: repeating-linear-gradient(rgba(0,0,0,0) 0px, rgba(0,0,0,0) 2px, rgba(0,255,65,0.08) 3px, rgba(0,255,65,0.08) 4px);\n  pointer-events: none;\n  z-index: 10;\n}\n\n.ambient-glow {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  background: radial-gradient(circle at center, rgba(0,255,65,0.04) 0%, transparent 70%);\n  pointer-events: none;\n}\n\n/* Step 0: Timeline */\n.timeline-section {\n  width: 80%;\n  margin-bottom: 60px;\n  opacity: 0;\n  transform: translateX(-50px);\n  transition: all 0.6s cubic-bezier(0.23, 1, 0.32, 1);\n}\n.active [data-step=\"0\"] { opacity: 1; transform: translateX(0); }\n\n.timeline-wrapper {\n  display: flex;\n  align-items: center;\n  gap: 20px;\n  font-size: 28px;\n}\n\n.timeline-bar {\n  flex-grow: 1;\n  height: 4px;\n  background: rgba(0, 255, 65, 0.2);\n  position: relative;\n  display: flex;\n  align-items: center;\n}\n\n.timeline-fill {\n  position: absolute;\n  left: 0;\n  height: 100%;\n  width: 0%;\n  background: #00FF41;\n  box-shadow: 0 0 10px #00FF41;\n  transition: width 1.5s ease-in-out;\n}\n\n.active [data-step=\"0\"] .timeline-fill { width: 100%; }\n\n.timeline-arrow {\n  position: absolute;\n  right: -10px;\n  font-weight: bold;\n  text-shadow: 0 0 5px #00FF41;\n}\n\n.pulse-text {\n  animation: phosphor-flicker 2s infinite;\n}\n\n/* Step 1: Grid */\n.distro-grid-container {\n  width: 85%;\n  position: relative;\n  opacity: 0;\n  transition: opacity 0.5s ease;\n}\n.active [data-step=\"1\"] { opacity: 1; }\n\n.grid-header {\n  font-size: 14px;\n  margin-bottom: 10px;\n  color: rgba(0, 255, 65, 0.6);\n  letter-spacing: 2px;\n}\n\n.distro-grid {\n  display: grid;\n  grid-template-columns: repeat(3, 1fr);\n  gap: 30px;\n  padding: 40px;\n  border: 1px solid rgba(0, 255, 65, 0.3);\n  background: rgba(0, 255, 65, 0.02);\n}\n\n.distro-card {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 15px;\n  transition: all 0.4s ease;\n}\n\n.distro-card iconify-icon {\n  font-size: 64px;\n  color: #00FF41;\n  filter: drop-shadow(0 0 5px rgba(0, 255, 65, 0.4));\n}\n\n.distro-name {\n  font-size: 18px;\n  text-transform: uppercase;\n}\n\n/* Step 2: Vulnerable State */\n.active [data-step=\"2\"] .distro-card iconify-icon {\n  color: #FF3131;\n  filter: drop-shadow(0 0 8px rgba(255, 49, 49, 0.6));\n  animation: icon-glitch 0.3s infinite alternate;\n}\n\n.shimmer-overlay {\n  position: absolute;\n  inset: 0;\n  background: linear-gradient(135deg, transparent 0%, rgba(0,255,65,0.1) 45%, rgba(0,255,65,0.2) 50%, rgba(0,255,65,0.1) 55%, transparent 100%);\n  background-size: 200% 200%;\n  pointer-events: none;\n  opacity: 0;\n}\n.active [data-step=\"2\"] .shimmer-overlay {\n  opacity: 1;\n  animation: shimmer-scan 3s infinite linear;\n}\n\n.vulnerable-overlay {\n  position: absolute;\n  inset: 0;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  z-index: 20;\n  pointer-events: none;\n  opacity: 0;\n  transform: scale(2);\n  transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n}\n\n.active [data-step=\"2\"].vulnerable-overlay {\n  opacity: 1;\n  transform: scale(1) rotate(-10deg);\n}\n\n.stamp-box {\n  border: 8px double #FF3131;\n  padding: 20px 40px;\n  background: rgba(0, 0, 0, 0.9);\n  box-shadow: 0 0 30px rgba(255, 49, 49, 0.4);\n  text-align: center;\n}\n\n.stamp-text {\n  font-size: 84px;\n  font-weight: 900;\n  color: #FF3131;\n  line-height: 1;\n}\n\n.stamp-subtext {\n  font-size: 24px;\n  color: #FF3131;\n  letter-spacing: 10px;\n  margin-top: 10px;\n}\n\n@keyframes phosphor-flicker {\n  0%, 100% { opacity: 1; }\n  50% { opacity: 0.6; }\n  55% { opacity: 0.9; }\n}\n\n@keyframes shimmer-scan {\n  0% { background-position: -200% -200%; }\n  100% { background-position: 200% 200%; }\n}\n\n@keyframes icon-glitch {\n  0% { transform: translate(0); }\n  50% { transform: translate(-2px, 1px); }\n  100% { transform: translate(2px, -1px); }\n}","js":"window.SceneLifecycle.register('scene-03', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-03\"]');\n    if (sceneRoot) {\n      sceneRoot.classList.add('active');\n      window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n    }\n  },\n  step(step) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-03\"]');\n    if (!sceneRoot) return;\n\n    const header = sceneRoot.querySelector('.grid-header');\n    if (step === 2) {\n      if (header) header.textContent = 'SYSTEM_CRITICAL: VULNERABILITIES_DETECTED';\n      // Add a slight screen shake on vulnerable stamp\n      sceneRoot.style.animation = 'terminal-shake 0.4s ease-out';\n      setTimeout(() => sceneRoot.style.animation = '', 400);\n    } else if (step === 1) {\n      if (header) header.textContent = 'SYSTEM_SCAN_TARGETS: IDENTIFIED';\n    }\n  },\n  leave() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-03\"]');\n    if (sceneRoot) sceneRoot.classList.remove('active');\n  }\n});\n\nconst shakeStyles = document.createElement('style');\nshakeStyles.innerHTML = `\n  @keyframes terminal-shake {\n    0% { transform: translate(0,0); }\n    10% { transform: translate(-5px,-5px); }\n    20% { transform: translate(5px,5px); }\n    30% { transform: translate(-5px,5px); }\n    40% { transform: translate(5px,-5px); }\n    100% { transform: translate(0,0); }\n  }\n`;\ndocument.head.appendChild(shakeStyles);"},{"id":"scene-04","title":"攻击场景描述","steps":2,"html":"<div class=\"s-scene-04-wrapper\">\n  <div class=\"crt-lines\"></div>\n  <div class=\"ambient-glow\"></div>\n\n  <div class=\"system-layout\">\n    <!-- Left: Container -->\n    <div class=\"node-container\">\n      <div class=\"system-node box-node\">\n        <div class=\"node-label\">[ CONTAINER ]</div>\n        <div class=\"internal-process\">\n          <div class=\"cursor-blink\"></div>\n          <span class=\"mono-text\">UID: 1000</span>\n        </div>\n      </div>\n    </div>\n\n    <!-- SVG Layer for the Arrow -->\n    <div class=\"vector-layer\">\n      <svg viewBox=\"0 0 800 400\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n        <path id=\"attack-path\" d=\"M 240 200 L 560 200\" stroke=\"#FF3131\" stroke-width=\"4\" stroke-dasharray=\"320\" stroke-dashoffset=\"320\" />\n        <path id=\"arrow-head\" d=\"M 545 185 L 565 200 L 545 215\" stroke=\"#FF3131\" stroke-width=\"4\" opacity=\"0\" />\n      </svg>\n    </div>\n\n    <!-- Right: Host -->\n    <div class=\"node-container\">\n      <div class=\"system-node circle-node\" id=\"host-node\">\n        <div class=\"node-label\">[ HOST_SYSTEM ]</div>\n        <div class=\"internal-process\">\n          <span class=\"status-text\">KERNEL_IDLE</span>\n        </div>\n      </div>\n    </div>\n  </div>\n\n  <!-- Success Banner -->\n  <div class=\"success-banner\" data-step=\"1\">\n    <div class=\"glitch-box\">\n      <span class=\"success-text\">> 提权成功: ESCAPED_TO_ROOT</span>\n    </div>\n  </div>\n</div>","css":".s-scene-04-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #000000;\n  overflow: hidden;\n  font-family: var(--sv-font-mono);\n  display: flex;\n  justify-content: center;\n  align-items: center;\n}\n\n.crt-lines {\n  position: absolute;\n  inset: 0;\n  background: repeating-linear-gradient(rgba(0,0,0,0) 0px, rgba(0,0,0,0) 2px, rgba(0,255,65,0.05) 3px, rgba(0,255,65,0.05) 4px);\n  pointer-events: none;\n  z-index: 10;\n}\n\n.ambient-glow {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  background: radial-gradient(circle at center, rgba(0,255,65,0.03) 0%, transparent 70%);\n  pointer-events: none;\n}\n\n.system-layout {\n  width: 100%;\n  max-width: 1200px;\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  padding: 0 10%;\n  z-index: 5;\n}\n\n.system-node {\n  width: 280px;\n  height: 280px;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  border: 2px solid rgba(0, 255, 65, 0.4);\n  background: rgba(0, 255, 65, 0.02);\n  transition: all 0.5s cubic-bezier(0.165, 0.84, 0.44, 1);\n  position: relative;\n}\n\n.box-node {\n  border-radius: 4px;\n}\n\n.circle-node {\n  border-radius: 50%;\n  border-color: rgba(255, 255, 255, 0.3);\n}\n\n.node-label {\n  position: absolute;\n  top: -40px;\n  color: rgba(0, 255, 65, 0.6);\n  font-size: 14px;\n  letter-spacing: 2px;\n}\n\n.internal-process {\n  display: flex;\n  align-items: center;\n  gap: 10px;\n}\n\n.mono-text, .status-text {\n  color: #00FF41;\n  font-size: 18px;\n}\n\n.cursor-blink {\n  width: 10px;\n  height: 20px;\n  background: #00FF41;\n  animation: cursor-blink 1s infinite steps(1);\n}\n\n.vector-layer {\n  position: absolute;\n  inset: 0;\n  pointer-events: none;\n}\n\n.vector-layer svg {\n  width: 100%;\n  height: 100%;\n}\n\n/* Step 0 Animation */\n.active[data-scene-id=\"scene-04\"] #attack-path {\n  transition: stroke-dashoffset 0.8s ease-in-out 0.3s;\n  stroke-dashoffset: 0;\n}\n\n.active[data-scene-id=\"scene-04\"] #arrow-head {\n  transition: opacity 0.2s ease 1.1s;\n  opacity: 1;\n}\n\n/* Step 1 Styles */\n[data-step=\"1\"] .circle-node {\n  border-color: #FF3131;\n  background: rgba(255, 49, 49, 0.1);\n  box-shadow: 0 0 30px rgba(255, 49, 49, 0.3);\n  transform: scale(1.05);\n}\n\n[data-step=\"1\"] .circle-node .status-text {\n  color: #FF3131;\n  animation: text-warning 0.5s infinite alternate;\n}\n\n.success-banner {\n  position: absolute;\n  bottom: 10%;\n  opacity: 0;\n  transform: translateY(20px);\n  transition: all 0.5s ease;\n}\n\n.active .success-banner[data-step=\"1\"] {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.glitch-box {\n  border: 1px solid #FF3131;\n  padding: 15px 40px;\n  background: rgba(0, 0, 0, 0.9);\n  box-shadow: 4px 4px 0px #FF3131;\n}\n\n.success-text {\n  color: #FF3131;\n  font-size: 28px;\n  font-weight: bold;\n  letter-spacing: 2px;\n}\n\n@keyframes cursor-blink {\n  0%, 100% { opacity: 1; }\n  50% { opacity: 0; }\n}\n\n@keyframes text-warning {\n  from { opacity: 1; text-shadow: 0 0 5px #FF3131; }\n  to { opacity: 0.7; text-shadow: 0 0 15px #FF3131; }\n}","js":"window.SceneLifecycle.register('scene-04', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-04\"]');\n    if (sceneRoot) {\n      sceneRoot.classList.add('active');\n      // Reset paths for re-entry\n      const path = sceneRoot.querySelector('#attack-path');\n      const head = sceneRoot.querySelector('#arrow-head');\n      if(path) path.style.strokeDashoffset = '320';\n      if(head) head.style.opacity = '0';\n    }\n  },\n  step(step) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-04\"]');\n    if (!sceneRoot) return;\n    \n    const hostNode = sceneRoot.querySelector('#host-node');\n    const statusText = sceneRoot.querySelector('.status-text');\n    \n    if (step === 1) {\n      if (statusText) statusText.textContent = 'SYSTEM_COMPROMISED';\n      // Add a small shake effect on success\n      sceneRoot.style.animation = 'privilege-shake 0.3s ease-in-out';\n      setTimeout(() => { sceneRoot.style.animation = ''; }, 300);\n    } else {\n      if (statusText) statusText.textContent = 'KERNEL_IDLE';\n    }\n  },\n  leave() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-04\"]');\n    if (sceneRoot) sceneRoot.classList.remove('active');\n  }\n});\n\nconst style = document.createElement('style');\nstyle.innerHTML = `\n@keyframes privilege-shake {\n  0% { transform: translate(0,0); }\n  25% { transform: translate(-4px, 4px); }\n  50% { transform: translate(4px, -4px); }\n  75% { transform: translate(-4px, -4px); }\n  100% { transform: translate(0,0); }\n}`;\ndocument.head.appendChild(style);"},{"id":"scene-05","title":"原理科普：Page Cache","steps":3,"html":"<div class=\"s-scene-05-wrapper\">\n  <div class=\"crt-scanlines\"></div>\n  <div class=\"ambient-phosphor\"></div>\n\n  <!-- Step 0: Memory Container -->\n  <div class=\"memory-container\">\n    <div class=\"memory-label\">[ PHYSICAL_RAM_MAPPING ]</div>\n    <div class=\"memory-grid\"></div>\n\n    <!-- Step 1: Page Cache Card -->\n    <div class=\"page-cache-card\" data-step=\"1\">\n      <div class=\"card-header\">\n        <span class=\"card-title\">PAGE_CACHE_OBJECT</span>\n        <span class=\"memory-addr\">0x7FFF0042</span>\n      </div>\n      <div class=\"binary-content\">\n        <div class=\"binary-line\">10110010 11100001 00011101</div>\n        <div class=\"binary-line\">11001010 01111100 11010001</div>\n        <div class=\"binary-line\">00110101 10100011 00011110</div>\n        <div class=\"binary-line\">11110000 00001111 10101010</div>\n      </div>\n      \n      <!-- Step 2: Security Overlay -->\n      <div class=\"security-status\" data-step=\"2\">\n        <div class=\"lock-overlay\">\n          <i data-lucide=\"lock\"></i>\n          <span class=\"read-only-text\">READ_ONLY</span>\n        </div>\n        <div class=\"forbidden-action\">\n          <div class=\"action-item\">\n            <span class=\"action-label\">WRITE_REQ</span>\n            <div class=\"forbidden-sign\"></div>\n          </div>\n          <div class=\"action-item\">\n            <span class=\"action-label\">MODIFY_REQ</span>\n            <div class=\"forbidden-sign\"></div>\n          </div>\n        </div>\n      </div>\n    </div>\n  </div>\n\n  <!-- Background Text -->\n  <div class=\"ghost-text\">KERNEL_SPACE</div>\n</div>","css":".s-scene-05-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #000000;\n  overflow: hidden;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  font-family: var(--sv-font-mono);\n  color: #00FF41;\n}\n\n.crt-scanlines {\n  position: absolute;\n  inset: 0;\n  background: repeating-linear-gradient(rgba(0,0,0,0) 0px, rgba(0,0,0,0) 2px, rgba(0,255,65,0.05) 3px, rgba(0,255,65,0.05) 4px);\n  pointer-events: none;\n  z-index: 10;\n}\n\n.ambient-phosphor {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  background: radial-gradient(circle at 50% 50%, rgba(0, 255, 65, 0.04) 0%, transparent 80%);\n  pointer-events: none;\n}\n\n.memory-container {\n  position: relative;\n  width: 80%;\n  height: 70%;\n  border: 1px solid rgba(0, 255, 65, 0.2);\n  background: rgba(0, 255, 65, 0.02);\n  padding: 40px;\n  box-sizing: border-box;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n}\n\n.memory-label {\n  position: absolute;\n  top: 15px;\n  left: 20px;\n  font-size: 14px;\n  opacity: 0.6;\n  letter-spacing: 2px;\n}\n\n.memory-grid {\n  position: absolute;\n  inset: 0;\n  opacity: 0.1;\n  background-image: radial-gradient(#00FF41 1px, transparent 1px);\n  background-size: 30px 30px;\n}\n\n.page-cache-card {\n  width: 480px;\n  height: 300px;\n  background: rgba(0, 20, 0, 0.9);\n  border: 2px solid #00FF41;\n  box-shadow: 0 0 30px rgba(0, 255, 65, 0.2);\n  padding: 20px;\n  position: relative;\n  z-index: 5;\n  opacity: 0;\n  transform: scale(0.9) translateY(20px);\n  transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.page-cache-card[data-step=\"1\"] {\n  opacity: 1;\n  transform: scale(1) translateY(0);\n}\n\n.card-header {\n  border-bottom: 1px solid rgba(0, 255, 65, 0.3);\n  padding-bottom: 10px;\n  margin-bottom: 20px;\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n}\n\n.card-title {\n  font-size: 20px;\n  font-weight: bold;\n}\n\n.memory-addr {\n  font-size: 14px;\n  opacity: 0.7;\n}\n\n.binary-content {\n  font-size: 24px;\n  line-height: 1.5;\n  letter-spacing: 4px;\n  color: rgba(0, 255, 65, 0.8);\n}\n\n.security-status {\n  position: absolute;\n  inset: 0;\n  background: rgba(0, 0, 0, 0.7);\n  backdrop-filter: blur(2px);\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  opacity: 0;\n  transition: opacity 0.5s ease;\n}\n\n.security-status[data-step=\"2\"] {\n  opacity: 1;\n}\n\n.lock-overlay {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 10px;\n  margin-bottom: 30px;\n  color: #39FF14;\n}\n\n.lock-overlay i {\n  width: 64px;\n  height: 64px;\n}\n\n.read-only-text {\n  font-size: 32px;\n  font-weight: 800;\n  letter-spacing: 4px;\n  border: 2px solid #39FF14;\n  padding: 5px 20px;\n}\n\n.forbidden-action {\n  display: flex;\n  gap: 40px;\n}\n\n.action-item {\n  position: relative;\n  padding: 5px 15px;\n  opacity: 0.6;\n}\n\n.forbidden-sign {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 120%;\n  height: 2px;\n  background: #FF3131;\n  transform: translate(-50%, -50%) rotate(-25deg);\n  box-shadow: 0 0 10px #FF3131;\n}\n\n.ghost-text {\n  position: absolute;\n  bottom: 5%;\n  right: 5%;\n  font-size: 80px;\n  opacity: 0.03;\n  font-weight: 900;\n  pointer-events: none;\n}\n\n@keyframes pulse-border {\n  0% { border-color: rgba(0, 255, 65, 0.4); }\n  50% { border-color: rgba(0, 255, 65, 1); }\n  100% { border-color: rgba(0, 255, 65, 0.4); }\n}","js":"window.SceneLifecycle.register('scene-05', {\n  enter() {\n    const root = document.querySelector('[data-scene-id=\"scene-05\"]');\n    const lines = root.querySelectorAll('.binary-line');\n    \n    // Randomize binary streams slightly\n    lines.forEach(line => {\n      setInterval(() => {\n        if (Math.random() > 0.7) {\n          const chars = line.innerText.split('');\n          const idx = Math.floor(Math.random() * chars.length);\n          if (chars[idx] === '0') chars[idx] = '1';\n          else if (chars[idx] === '1') chars[idx] = '0';\n          line.innerText = chars.join('');\n        }\n      }, 200);\n    });\n\n    window.__SVGVIDEO_REFRESH_ICONS(root);\n  },\n  step(n) {\n    const root = document.querySelector('[data-scene-id=\"scene-05\"]');\n    const card = root.querySelector('.page-cache-card');\n    const security = root.querySelector('.security-status');\n\n    if (n >= 1) {\n      card.setAttribute('data-step', '1');\n    } else {\n      card.removeAttribute('data-step');\n    }\n\n    if (n >= 2) {\n      security.setAttribute('data-step', '2');\n      // Add a slight glitch effect when locked\n      card.style.animation = 'privilege-shake 0.2s 1';\n      setTimeout(() => card.style.animation = '', 200);\n    } else {\n      security.removeAttribute('data-step');\n    }\n  },\n  leave() {}\n});"},{"id":"scene-06","title":"利用机制：AF_ALG","steps":2,"html":"<div class=\"s-scene-06-wrapper\">\n  <div class=\"crt-overlay\"></div>\n  <div class=\"ambient-glow\"></div>\n\n  <!-- Step 0: Terminal Window -->\n  <div class=\"terminal-container\" id=\"term-06\">\n    <div class=\"term-header\">\n      <div class=\"term-controls\"><span></span><span></span><span></span></div>\n      <div class=\"term-title\">K-SHELL v4.1</div>\n    </div>\n    <div class=\"term-content\">\n      <div class=\"typing-line\" data-delay=\"1\">$ modprobe af_alg</div>\n      <div class=\"typing-line\" data-delay=\"2\">$ call <span class=\"highlight\">splice()</span></div>\n      <div class=\"typing-line blinking-cursor\">_</div>\n    </div>\n  </div>\n\n  <!-- Step 1: Conduit & Target File -->\n  <div class=\"conduit-system\">\n    <svg class=\"conduit-svg\" viewBox=\"0 0 1000 600\">\n      <path id=\"conduit-path\" d=\"M280,300 L450,300\" fill=\"none\" stroke=\"#00FF41\" stroke-width=\"4\" stroke-dasharray=\"1000\" stroke-dashoffset=\"1000\" />\n      <circle cx=\"280\" cy=\"300\" r=\"5\" fill=\"#00FF41\" class=\"node-point\" />\n    </svg>\n    <div class=\"file-node\" id=\"su-file-node\">\n      <div class=\"file-icon-box\">\n        <iconify-icon icon=\"mdi:file-lock-outline\"></iconify-icon>\n      </div>\n      <div class=\"file-info\">\n        <span class=\"file-name\">/usr/bin/su</span>\n        <span class=\"file-perm\">ROOT_SUID: 4755</span>\n      </div>\n    </div>\n  </div>\n\n  <!-- Step 2: Encryption Flow & Chains -->\n  <div class=\"pipeline-stage\" id=\"encrypt-stage\">\n    <div class=\"pipeline-box\">\n      <div class=\"pipeline-label\">[ KERNEL_CRYPTO_API ]</div>\n      <div class=\"chain-container\">\n         <div class=\"chain-link\"></div>\n         <div class=\"chain-link\"></div>\n         <div class=\"chain-link\"></div>\n      </div>\n      <div class=\"flow-indicator\">ENCRYPTION_IN_PROGRESS</div>\n    </div>\n  </div>\n\n  <div class=\"side-status\">\n    <div class=\"status-item\" data-step=\"1\">> CHANNEL_ESTABLISHED</div>\n    <div class=\"status-item\" data-step=\"2\">> FILE_INGESTION: FORCE</div>\n  </div>\n</div>","css":".s-scene-06-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #000000;\n  overflow: hidden;\n  display: flex;\n  align-items: center;\n  justify-content: space-around;\n  font-family: var(--sv-font-mono);\n  color: #00FF41;\n}\n\n.crt-overlay {\n  position: absolute;\n  inset: 0;\n  background: repeating-linear-gradient(rgba(0,0,0,0) 0px, rgba(0,0,0,0) 2px, rgba(0,255,65,0.08) 3px, rgba(0,255,65,0.08) 4px);\n  pointer-events: none;\n  z-index: 100;\n}\n\n.ambient-glow {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  background: radial-gradient(circle at 50% 50%, rgba(0, 255, 65, 0.03) 0%, transparent 70%);\n  pointer-events: none;\n}\n\n.terminal-container {\n  width: 320px;\n  height: 200px;\n  border: 1px solid rgba(0, 255, 65, 0.4);\n  background: rgba(0, 20, 0, 0.8);\n  box-shadow: 0 0 15px rgba(0, 255, 65, 0.1);\n  z-index: 10;\n  transform: translateX(-100px);\n  opacity: 0;\n  transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.term-header {\n  background: rgba(0, 255, 65, 0.15);\n  padding: 6px 10px;\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  border-bottom: 1px solid rgba(0, 255, 65, 0.3);\n}\n\n.term-controls {\n  display: flex;\n  gap: 6px;\n}\n\n.term-controls span {\n  width: 8px;\n  height: 8px;\n  border: 1px solid #00FF41;\n  border-radius: 50%;\n}\n\n.term-title {\n  font-size: 10px;\n  opacity: 0.7;\n}\n\n.term-body {\n  padding: 15px;\n  font-size: 14px;\n}\n\n.typing-line {\n  margin-bottom: 5px;\n  overflow: hidden;\n  white-space: nowrap;\n}\n\n.highlight { color: #39FF14; text-shadow: 0 0 5px #00FF41; }\n\n.conduit-system {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  pointer-events: none;\n}\n\n.conduit-svg {\n  position: absolute;\n  top: 0; left: 0; width: 100%; height: 100%;\n}\n\n.file-node {\n  position: absolute;\n  left: 50%;\n  top: 50%;\n  transform: translate(-50%, -50%) scale(0.9);\n  opacity: 0;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 10px;\n  z-index: 20;\n  transition: all 0.5s ease;\n}\n\n.file-icon-box {\n  font-size: 64px;\n  border: 2px solid #00FF41;\n  padding: 15px;\n  background: rgba(0, 255, 65, 0.05);\n  box-shadow: 0 0 20px rgba(0, 255, 65, 0.2);\n}\n\n.file-name {\n  font-size: 20px;\n  font-weight: bold;\n}\n\n.file-perm {\n  font-size: 12px;\n  opacity: 0.6;\n}\n\n.pipeline-stage {\n  width: 300px;\n  height: 250px;\n  border: 2px dashed rgba(0, 255, 65, 0.3);\n  position: relative;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  opacity: 0;\n  transform: translateX(50px);\n  transition: all 0.6s ease;\n}\n\n.pipeline-box {\n  width: 90%;\n  height: 90%;\n  background: rgba(0, 255, 65, 0.02);\n  border: 1px solid #00FF41;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  gap: 20px;\n}\n\n.pipeline-label {\n  position: absolute;\n  top: -12px;\n  background: #000;\n  padding: 0 10px;\n  font-size: 14px;\n}\n\n.chain-container {\n  display: flex;\n  gap: 5px;\n  opacity: 0;\n}\n\n.chain-link {\n  width: 15px;\n  height: 30px;\n  border: 2px solid #00FF41;\n  border-radius: 10px;\n}\n\n.flow-indicator {\n  font-size: 12px;\n  animation: blink 0.8s infinite;\n}\n\n.side-status {\n  position: absolute;\n  bottom: 40px;\n  right: 40px;\n  text-align: right;\n}\n\n.status-item {\n  font-size: 14px;\n  opacity: 0;\n  margin-top: 5px;\n}\n\n@keyframes shake {\n  0%, 100% { transform: translate(-50%, -50%); }\n  20% { transform: translate(-52%, -48%); }\n  40% { transform: translate(-48%, -52%); }\n  60% { transform: translate(-51%, -49%); }\n  80% { transform: translate(-49%, -51%); }\n}\n\n@keyframes blink {\n  0%, 100% { opacity: 1; }\n  50% { opacity: 0.3; }\n}\n\n.shaking { animation: shake 0.2s infinite; }\n\n[data-step=\"1\"] .status-item[data-step=\"1\"] { opacity: 1; }\n[data-step=\"2\"] .status-item[data-step=\"2\"] { opacity: 1; }","js":"window.SceneLifecycle.register('scene-06', {\n  enter() {\n    const root = document.querySelector('[data-scene-id=\"scene-06\"]');\n    const term = root.querySelector('#term-06');\n    const file = root.querySelector('#su-file-node');\n    \n    setTimeout(() => {\n      term.style.opacity = '1';\n      term.style.transform = 'translateX(0)';\n      file.style.opacity = '1';\n      file.style.transform = 'translate(-50%, -50%) scale(1)';\n    }, 300);\n\n    window.__SVGVIDEO_REFRESH_ICONS(root);\n  },\n  step(n) {\n    const root = document.querySelector('[data-scene-id=\"scene-06\"]');\n    const path = root.querySelector('#conduit-path');\n    const file = root.querySelector('#su-file-node');\n    const encrypt = root.querySelector('#encrypt-stage');\n    const chains = root.querySelector('.chain-container');\n\n    if (n === 1) {\n      path.style.transition = 'stroke-dashoffset 0.8s ease-out';\n      path.style.strokeDashoffset = '0';\n    }\n\n    if (n === 2) {\n      // Shake effect\n      file.classList.add('shaking');\n      \n      setTimeout(() => {\n        // Drag into encryption flow\n        encrypt.style.opacity = '1';\n        encrypt.style.transform = 'translateX(0)';\n        \n        file.style.transition = 'all 0.8s cubic-bezier(0.68, -0.55, 0.27, 1.55)';\n        file.style.left = '75%';\n        file.style.top = '50%';\n        file.style.transform = 'translate(-50%, -50%) scale(0.7)';\n        file.style.zIndex = '30';\n        \n        setTimeout(() => {\n          file.classList.remove('shaking');\n          chains.style.opacity = '1';\n          encrypt.style.boxShadow = '0 0 30px rgba(0, 255, 65, 0.4)';\n        }, 800);\n      }, 400);\n    }\n  },\n  leave() {}\n});"},{"id":"scene-07","title":"漏洞核心：错误的写权限","steps":2,"html":"<div class=\"s-scene-07-wrapper\">\n  <div class=\"crt-overlay\"></div>\n  <div class=\"ambient-glow\"></div>\n  \n  <!-- Alert Overlay (Step 2) -->\n  <div class=\"alert-pulse-overlay\" data-step=\"2\"></div>\n\n  <div class=\"layout-container\">\n    <!-- Left: Code Section -->\n    <div class=\"code-section\">\n      <div class=\"section-label\">2017 内核优化代码</div>\n      <div class=\"terminal-window\">\n        <div class=\"term-header\">\n           <div class=\"term-dots\"><span></span><span></span><span></span></div>\n           <div class=\"term-title\">mm/gup.c</div>\n        </div>\n        <div class=\"code-content\">\n          <pre><code><span class=\"line\">/* Optimization: No COW needed? */</span>\n<span class=\"line\">if (flags & FOLL_FORCE) {</span>\n<span class=\"line highlight-target\">  vma-&gt;vm_flags |= <span class=\"code-keyword\">VM_MAYWRITE</span>;</span>\n<span class=\"line\">  <span class=\"code-comment\">// Treat as writable buffer</span></span>\n<span class=\"line\">}</span></code></pre>\n        </div>\n      </div>\n    </div>\n\n    <!-- Middle: Conduit -->\n    <div class=\"conduit-container\">\n      <svg class=\"conduit-svg\" viewBox=\"0 0 200 100\">\n        <path class=\"arrow-path\" d=\"M0,50 L180,50\" fill=\"none\" stroke=\"#00FF41\" stroke-width=\"2\" />\n        <polygon points=\"180,45 195,50 180,55\" fill=\"#00FF41\" class=\"arrow-head\" />\n      </svg>\n    </div>\n\n    <!-- Right: Memory Page Section -->\n    <div class=\"memory-section\">\n      <div class=\"section-label\">物理内存页面</div>\n      <div class=\"page-frame\">\n        <div class=\"page-grid\">\n          <span></span><span></span><span></span><span></span>\n          <span></span><span></span><span></span><span></span>\n        </div>\n        <div class=\"permission-status\">\n          <div class=\"lock-container\" id=\"perm-lock\">\n             <div class=\"lock-icon\"><iconify-icon icon=\"mdi:lock-outline\"></iconify-icon></div>\n             <div class=\"lock-text\">只读 (RO)</div>\n          </div>\n          <div class=\"rw-status\" id=\"perm-rw\">\n             <div class=\"rw-glitch\">可写 (RW)</div>\n          </div>\n        </div>\n      </div>\n    </div>\n  </div>\n\n  <div class=\"status-bar\">\n    <div class=\"status-msg\">SYSTEM_OPTIMIZATION: ACTIVE</div>\n    <div class=\"status-msg\" data-step=\"1\">CRITICAL: PERMISSION_BYPASS_DETECTED</div>\n  </div>\n</div>","css":".s-scene-07-wrapper { width: 100%; height: 100%; background: #000; display: flex; align-items: center; justify-content: center; font-family: var(--sv-font-mono); color: #00FF41; overflow: hidden; position: relative; }\n.crt-overlay { position: absolute; inset: 0; background: repeating-linear-gradient(rgba(0,0,0,0) 0px, rgba(0,0,0,0) 2px, rgba(0,255,65,0.05) 3px, rgba(0,255,65,0.05) 4px); pointer-events: none; z-index: 10; }\n.ambient-glow { position: absolute; width: 100%; height: 100%; background: radial-gradient(circle at 50% 50%, rgba(0, 255, 65, 0.05) 0%, transparent 70%); }\n.layout-container { display: flex; align-items: center; justify-content: space-between; width: 90%; gap: 20px; z-index: 5; }\n.section-label { font-size: 14px; color: rgba(0,255,65,0.6); margin-bottom: 10px; text-transform: uppercase; letter-spacing: 2px; }\n.terminal-window { width: 420px; border: 1px solid rgba(0,255,65,0.3); background: rgba(0,20,0,0.9); box-shadow: 0 0 20px rgba(0,255,65,0.1); }\n.term-header { background: rgba(0,255,65,0.1); padding: 8px 12px; display: flex; align-items: center; border-bottom: 1px solid rgba(0,255,65,0.2); }\n.term-dots { display: flex; gap: 5px; margin-right: 15px; }\n.term-dots span { width: 6px; height: 6px; border: 1px solid #00FF41; border-radius: 50%; }\n.term-title { font-size: 12px; opacity: 0.8; }\n.code-content { padding: 20px; font-size: 16px; line-height: 1.5; }\n.highlight-target { background: rgba(0,255,65,0.2); border-left: 3px solid #00FF41; padding-left: 5px; }\n.code-keyword { color: #39FF14; font-weight: bold; }\n.code-comment { color: rgba(0,255,65,0.4); }\n.conduit-container { flex: 1; height: 100px; display: flex; align-items: center; justify-content: center; }\n.arrow-path { stroke-dasharray: 200; stroke-dashoffset: 200; transition: stroke-dashoffset 0.8s ease; }\n.memory-section { display: flex; flex-direction: column; align-items: center; }\n.page-frame { width: 280px; height: 180px; border: 2px solid #00FF41; position: relative; background: rgba(0,255,65,0.02); display: flex; flex-direction: column; justify-content: center; align-items: center; }\n.page-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; opacity: 0.2; position: absolute; inset: 20px; }\n.page-grid span { border: 1px solid #00FF41; height: 20px; }\n.permission-status { position: relative; z-index: 2; text-align: center; }\n.lock-container { transition: all 0.4s ease; }\n.lock-icon { font-size: 48px; margin-bottom: 10px; }\n.lock-text { font-size: 18px; }\n.rw-status { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0); opacity: 0; color: #FF3131; font-weight: 900; font-size: 42px; text-shadow: 0 0 15px rgba(255,49,49,0.8); transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); }\n.shattered .lock-container { transform: scale(1.5) rotate(15deg); opacity: 0; filter: blur(5px); }\n.shattered .rw-status { transform: translate(-50%, -50%) scale(1); opacity: 1; }\n.alert-pulse-overlay { position: absolute; inset: 0; background: radial-gradient(circle, rgba(255,0,0,0.15) 0%, transparent 70%); opacity: 0; pointer-events: none; animation: pulse-red 1.5s infinite; }\n@keyframes pulse-red { 0%, 100% { opacity: 0; transform: scale(1); } 50% { opacity: 1; transform: scale(1.1); } }\n.status-bar { position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); display: flex; gap: 40px; }\n.status-msg { font-size: 12px; border: 1px solid rgba(0,255,65,0.3); padding: 4px 12px; background: rgba(0,20,0,0.8); }","js":"window.SceneLifecycle.register('scene-07', {\n  enter() {\n    const root = document.querySelector('[data-scene-id=\"scene-07\"]');\n    const arrow = root.querySelector('.arrow-path');\n    \n    // Initial entrance\n    setTimeout(() => {\n      arrow.style.strokeDashoffset = '0';\n    }, 500);\n  },\n  step(n) {\n    const root = document.querySelector('[data-scene-id=\"scene-07\"]');\n    const memFrame = root.querySelector('.page-frame');\n    const alertOverlay = root.querySelector('.alert-pulse-overlay');\n\n    if (n === 1) {\n      // Step 1: Shatter the Lock\n      memFrame.classList.add('shattered');\n      memFrame.style.borderColor = '#FF3131';\n      memFrame.style.boxShadow = '0 0 30px rgba(255,49,49,0.3)';\n    }\n\n    if (n === 2) {\n      // Step 2: Full Alert Pulse\n      alertOverlay.style.display = 'block';\n      document.body.style.animation = 'glitch-bg 0.1s 3';\n    }\n  },\n  leave() {\n    document.body.style.animation = 'none';\n  }\n});"},{"id":"scene-08","title":"精准写入过程","steps":4,"html":"<div class=\"s-scene-08-wrapper\">\n  <div class=\"crt-scanlines\"></div>\n  <div class=\"ambient-glow\"></div>\n\n  <!-- Zoomed Hex Grid Viewport -->\n  <div class=\"hex-viewport\">\n    <div class=\"viewport-header\">\n      <span class=\"addr-label\">OFFSET: 0x00007FFF</span>\n      <span class=\"status-tag\" id=\"mem-status\">[ MEMORY_READ_ONLY ]</span>\n    </div>\n    <div class=\"hex-grid-container\">\n      <div class=\"hex-grid\" id=\"main-hex-grid\">\n        <!-- Generated cells will be here -->\n      </div>\n    </div>\n  </div>\n\n  <!-- Flying Bytes (Step 0: Visible, Step 1: Animate) -->\n  <div class=\"missile-container\">\n    <div class=\"byte-missile\" data-target=\"target-1\" data-step=\"0\">0x53</div>\n    <div class=\"byte-missile\" data-target=\"target-2\" data-step=\"0\">0x55</div>\n    <div class=\"byte-missile\" data-target=\"target-3\" data-step=\"0\">0x49</div>\n    <div class=\"byte-missile\" data-target=\"target-4\" data-step=\"0\">0x44</div>\n  </div>\n\n  <!-- Alert Overlay (Step 2) -->\n  <div class=\"alert-overlay\" data-step=\"2\">\n    <div class=\"alert-box\">\n      <div class=\"alert-header\">CRITICAL_ERROR</div>\n      <div class=\"alert-content\">VALIDATION_FAILED: HASH_MISMATCH</div>\n      <div class=\"alert-sub\">ENCRYPTED_BLOCK_CORRUPTED</div>\n    </div>\n  </div>\n\n  <!-- Bottom Status -->\n  <div class=\"terminal-footer\">\n    <div class=\"cursor-line\"><span class=\"prompt\">$</span> <span class=\"typing-text\">patching su_binary...</span><span class=\"cursor\"></span></div>\n    <div class=\"progress-section\" data-step=\"1\">\n      <span class=\"label\">INJECTION:</span>\n      <span class=\"bar-bg\"><span class=\"bar-fill\" id=\"injection-bar\"></span></span>\n    </div>\n  </div>\n</div>","css":".s-scene-08-wrapper { width: 100%; height: 100%; background: #000; display: flex; align-items: center; justify-content: center; font-family: var(--sv-font-mono); color: #00FF41; overflow: hidden; position: relative; }\n.crt-scanlines { position: absolute; inset: 0; background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.15) 50%), linear-gradient(90deg, rgba(255, 0, 0, 0.03), rgba(0, 255, 0, 0.01), rgba(0, 0, 255, 0.03)); background-size: 100% 3px, 3px 100%; pointer-events: none; z-index: 20; }\n.ambient-glow { position: absolute; width: 100%; height: 100%; background: radial-gradient(circle, rgba(0, 255, 65, 0.05) 0%, transparent 80%); pointer-events: none; }\n\n.hex-viewport { width: 800px; height: 400px; border: 1px solid rgba(0, 255, 65, 0.3); background: rgba(0, 10, 0, 0.9); position: relative; box-shadow: 0 0 40px rgba(0, 0, 0, 0.8); transition: all 0.8s ease; transform: scale(1.1); }\n.viewport-header { background: rgba(0, 255, 65, 0.1); padding: 8px 15px; display: flex; justify-content: space-between; border-bottom: 1px solid rgba(0, 255, 65, 0.2); font-size: 12px; }\n.hex-grid-container { padding: 30px; display: flex; justify-content: center; }\n.hex-grid { display: grid; grid-template-columns: repeat(8, 70px); gap: 15px; }\n.hex-cell { height: 40px; display: flex; align-items: center; justify-content: center; border: 1px solid rgba(0, 255, 65, 0.1); font-size: 22px; color: #0088ff; transition: all 0.5s ease; position: relative; }\n.hex-cell.infected { color: #d400ff !important; border-color: #d400ff; text-shadow: 0 0 10px rgba(212, 0, 255, 0.5); }\n.hex-cell.target-active { background: rgba(0, 255, 65, 0.1); border-color: #00FF41; }\n\n.missile-container { position: absolute; inset: 0; pointer-events: none; }\n.byte-missile { position: absolute; font-size: 24px; font-weight: bold; background: #000; border: 2px solid #00FF41; padding: 5px 10px; box-shadow: 0 0 15px #00FF41; z-index: 10; transition: all 0.6s cubic-bezier(0.6, -0.28, 0.735, 0.045); }\n.byte-missile[data-step=\"0\"] { opacity: 1; transform: translate(var(--start-x), var(--start-y)); }\n.byte-missile.launched { transform: translate(var(--end-x), var(--end-y)) scale(0.8); opacity: 0.5; }\n\n.alert-overlay { position: absolute; inset: 0; z-index: 30; display: flex; align-items: center; justify-content: center; background: rgba(255, 0, 0, 0.1); backdrop-filter: blur(2px); }\n.alert-box { background: #000; border: 4px solid #FF3131; padding: 40px; text-align: center; box-shadow: 0 0 50px rgba(255, 49, 49, 0.4); animation: alert-shake 0.2s infinite; }\n.alert-header { color: #FF3131; font-weight: 900; font-size: 32px; letter-spacing: 4px; margin-bottom: 10px; }\n.alert-content { color: #FFF; font-size: 20px; border-top: 1px solid #FF3131; padding-top: 10px; }\n.alert-sub { font-size: 14px; opacity: 0.7; margin-top: 5px; }\n\n.terminal-footer { position: absolute; bottom: 40px; left: 100px; right: 100px; }\n.prompt { color: #00FF41; margin-right: 10px; }\n.typing-text { font-size: 18px; }\n.cursor { display: inline-block; width: 10px; height: 20px; background: #00FF41; animation: blink 1s infinite; vertical-align: middle; }\n.progress-section { margin-top: 15px; display: flex; align-items: center; gap: 15px; }\n.bar-bg { flex: 1; height: 10px; background: rgba(0, 255, 65, 0.1); border: 1px solid rgba(0, 255, 65, 0.3); }\n.bar-fill { display: block; width: 0%; height: 100%; background: #00FF41; transition: width 0.6s ease; }\n\n@keyframes alert-shake { 0% { transform: translate(1px, 1px); } 50% { transform: translate(-1px, -1px); } 100% { transform: translate(1px, -1px); } }\n@keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }\n.modified-state .hex-viewport { border-color: #d400ff; box-shadow: 0 0 30px rgba(212, 0, 255, 0.2); }\n.modified-state #mem-status { color: #d400ff; content: \"[ MEMORY_MODIFIED_PERMANENT ]\"; }","js":"window.SceneLifecycle.register('scene-08', {\n  enter() {\n    const root = document.querySelector('[data-scene-id=\"scene-08\"]');\n    const grid = root.querySelector('#main-hex-grid');\n    const missiles = root.querySelectorAll('.byte-missile');\n\n    // Generate Background Hex Cells\n    grid.innerHTML = '';\n    for (let i = 0; i < 24; i++) {\n      const cell = document.createElement('div');\n      cell.className = 'hex-cell';\n      // Pre-defined target slots\n      if (i === 10) cell.id = 'target-1';\n      if (i === 11) cell.id = 'target-2';\n      if (i === 18) cell.id = 'target-3';\n      if (i === 19) cell.id = 'target-4';\n      \n      cell.textContent = Math.floor(Math.random() * 256).toString(16).toUpperCase().padStart(2, '0');\n      grid.appendChild(cell);\n    }\n\n    // Set Initial Missile Positions\n    const rects = [\n      { x: '10%', y: '20%' },\n      { x: '85%', y: '15%' },\n      { x: '5%', y: '75%' },\n      { x: '90%', y: '80%' }\n    ];\n    missiles.forEach((m, idx) => {\n      m.style.setProperty('--start-x', rects[idx].x);\n      m.style.setProperty('--start-y', rects[idx].y);\n    });\n  },\n  \n  step(n) {\n    const root = document.querySelector('[data-scene-id=\"scene-08\"]');\n    const missiles = root.querySelectorAll('.byte-missile');\n    const barFill = root.querySelector('#injection-bar');\n    const memStatus = root.querySelector('#mem-status');\n\n    if (n === 1) {\n      // Step 1: Launch missiles to targets\n      missiles.forEach((m) => {\n        const targetId = m.getAttribute('data-target');\n        const targetEl = root.querySelector(`#${targetId}`);\n        const targetRect = targetEl.getBoundingClientRect();\n        const rootRect = root.getBoundingClientRect();\n        \n        const endX = (targetRect.left - rootRect.left) + 'px';\n        const endY = (targetRect.top - rootRect.top) + 'px';\n        \n        m.style.setProperty('--end-x', endX);\n        m.style.setProperty('--end-y', endY);\n        m.classList.add('launched');\n        \n        setTimeout(() => {\n          targetEl.classList.add('target-active');\n          targetEl.textContent = m.textContent.replace('0x', '');\n        }, 600);\n      });\n      barFill.style.width = '100%';\n    }\n\n    if (n === 2) {\n       // Step 2 shows the Alert Overlay via CSS data-step\n       root.style.filter = 'hue-rotate(-10deg)';\n    }\n\n    if (n === 3) {\n      // Step 3: Persistence - Blue to Purple\n      root.classList.add('modified-state');\n      const targets = root.querySelectorAll('.hex-cell');\n      targets.forEach((cell, idx) => {\n        setTimeout(() => {\n          cell.classList.add('infected');\n          if (idx % 3 === 0) cell.textContent = 'FF';\n        }, idx * 20);\n      });\n      memStatus.textContent = '[ MEMORY_MODIFIED_PERMANENT ]';\n    }\n  }\n});"},{"id":"scene-09","title":"获取Root权限","steps":3,"html":"<div class=\"s-scene-09-wrapper\">\n  <div class=\"crt-scanlines\"></div>\n  <div class=\"ambient-glow\"></div>\n\n  <!-- Terminal Interface Container -->\n  <div class=\"terminal-interface\">\n    <div class=\"terminal-header\">\n      <div class=\"terminal-buttons\">\n        <span></span><span></span><span></span>\n      </div>\n      <div class=\"terminal-title\">TERMINAL - su_exploit_session</div>\n    </div>\n\n    <div class=\"terminal-content\">\n      <!-- Input History -->\n      <div class=\"log-line\">[ OK ] Payload injected into memory segment 0x0804...</div>\n      <div class=\"log-line\">[ OK ] Hooking execution vector...</div>\n      \n      <!-- Main Prompt Line -->\n      <div class=\"prompt-area\">\n        <span class=\"prompt-char\" id=\"current-prompt\">$</span>\n        <span class=\"command-text\">whoami</span>\n        <span class=\"cursor\"></span>\n      </div>\n\n      <!-- Result Output (Step 0-1 Hidden) -->\n      <div class=\"result-output\" data-step=\"2\">\n        <div class=\"root-banner\" id=\"root-text-container\">\n          <!-- root text will be typed here -->\n        </div>\n      </div>\n    </div>\n\n    <!-- Bottom Status Bar -->\n    <div class=\"terminal-footer-bar\">\n      <div class=\"status-item\">STATUS: <span class=\"blink-text\">RUNNING</span></div>\n      <div class=\"status-item\">PRIVILEGE: <span id=\"priv-level\">USER</span></div>\n      <div class=\"status-item\" data-step=\"2\">UID: 0 (root)</div>\n    </div>\n  </div>\n\n  <!-- Flash Overlay for Step 1 -->\n  <div class=\"lightning-flash\" id=\"flash-overlay\"></div>\n\n  <!-- Success Glow Frame (Step 2) -->\n  <div class=\"success-frame\" data-step=\"2\"></div>\n</div>","css":".s-scene-09-wrapper { width: 100%; height: 100%; background: #000; font-family: var(--sv-font-mono); color: #00FF41; display: flex; align-items: center; justify-content: center; position: relative; overflow: hidden; }\n.crt-scanlines { position: absolute; inset: 0; background: linear-gradient(rgba(0, 255, 65, 0.05) 50%, transparent 50%); background-size: 100% 4px; pointer-events: none; z-index: 10; }\n.ambient-glow { position: absolute; inset: 0; background: radial-gradient(circle at center, rgba(0, 255, 65, 0.03) 0%, transparent 70%); pointer-events: none; }\n\n.terminal-interface { width: 80%; max-width: 900px; height: 60%; background: rgba(0, 10, 0, 0.95); border: 1px solid rgba(0, 255, 65, 0.3); box-shadow: 0 20px 50px rgba(0, 0, 0, 0.8); display: flex; flex-direction: column; position: relative; z-index: 5; }\n.terminal-header { height: 30px; background: rgba(0, 255, 65, 0.1); border-bottom: 1px solid rgba(0, 255, 65, 0.2); display: flex; align-items: center; padding: 0 15px; }\n.terminal-buttons { display: flex; gap: 6px; margin-right: 20px; }\n.terminal-buttons span { width: 8px; height: 8px; border: 1px solid rgba(0, 255, 65, 0.4); border-radius: 50%; }\n.terminal-title { font-size: 12px; opacity: 0.7; letter-spacing: 1px; }\n\n.terminal-content { flex: 1; padding: 30px; overflow: hidden; position: relative; }\n.log-line { font-size: 14px; opacity: 0.4; margin-bottom: 8px; font-weight: 300; }\n.prompt-area { font-size: 32px; display: flex; align-items: center; margin-top: 20px; }\n.prompt-char { margin-right: 15px; color: #39FF14; font-weight: bold; }\n.command-text { letter-spacing: 2px; }\n.cursor { display: inline-block; width: 15px; height: 32px; background: #00FF41; margin-left: 10px; animation: blink 1s infinite steps(2); }\n\n.result-output { margin-top: 40px; display: flex; justify-content: center; }\n.root-banner { font-size: 120px; font-weight: 900; letter-spacing: 15px; text-transform: uppercase; text-shadow: 0 0 30px rgba(0, 255, 65, 0.8); }\n\n.terminal-footer-bar { height: 25px; background: rgba(0, 255, 65, 0.1); display: flex; align-items: center; padding: 0 15px; gap: 30px; font-size: 10px; border-top: 1px solid rgba(0, 255, 65, 0.2); }\n.blink-text { animation: blink 0.5s infinite; }\n\n.lightning-flash { position: absolute; inset: 0; background: #00FF41; opacity: 0; pointer-events: none; z-index: 100; }\n.success-frame { position: absolute; inset: 10px; border: 4px solid #00FF41; box-shadow: inset 0 0 50px rgba(0, 255, 65, 0.3), 0 0 30px rgba(0, 255, 65, 0.2); pointer-events: none; z-index: 101; opacity: 0; transform: scale(1.02); transition: all 0.3s ease; }\n.success-frame[data-step=\"2\"] { opacity: 1; transform: scale(1); }\n\n@keyframes blink { 0% { opacity: 1; } 100% { opacity: 0; } }\n@keyframes glitch-flash { 0% { opacity: 0; } 10% { opacity: 0.8; } 20% { opacity: 0.1; } 30% { opacity: 0.9; } 100% { opacity: 0; } }","js":"window.SceneLifecycle.register('scene-09', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-09\"]');\n    const rootContainer = sceneRoot.querySelector('#root-text-container');\n    rootContainer.innerHTML = '';\n  },\n\n  step(n) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-09\"]');\n    const promptChar = sceneRoot.querySelector('#current-prompt');\n    const flash = sceneRoot.querySelector('#flash-overlay');\n    const privLevel = sceneRoot.querySelector('#priv-level');\n    const rootContainer = sceneRoot.querySelector('#root-text-container');\n\n    if (n === 1) {\n      // Step 1: Lightning Flash and Prompt Change\n      flash.style.animation = 'glitch-flash 0.4s ease-out forwards';\n      setTimeout(() => {\n        promptChar.textContent = '#';\n        privLevel.textContent = 'ROOT_ACCESS';\n        privLevel.style.color = '#FFF';\n        privLevel.style.textShadow = '0 0 10px #00FF41';\n      }, 150);\n    }\n\n    if (n === 2) {\n      // Step 2: Big 'root' typewriter effect\n      const text = 'root';\n      rootContainer.innerHTML = '';\n      let i = 0;\n      \n      const typeChar = () => {\n        if (i < text.length) {\n          const span = document.createElement('span');\n          span.textContent = text[i];\n          span.style.opacity = '0';\n          span.style.transform = 'scale(1.5)';\n          span.style.display = 'inline-block';\n          rootContainer.appendChild(span);\n          \n          // Trigger individual character pop\n          requestAnimationFrame(() => {\n            span.style.transition = 'all 0.15s cubic-bezier(0.175, 0.885, 0.32, 1.275)';\n            span.style.opacity = '1';\n            span.style.transform = 'scale(1)';\n          });\n          \n          i++;\n          setTimeout(typeChar, 100);\n        }\n      };\n      \n      typeChar();\n    }\n  }\n});"},{"id":"scene-10","title":"防御与总结","steps":3,"html":"<div class=\"s-scene-10-wrapper\">\n  <div class=\"crt-scanlines\"></div>\n  <div class=\"ambient-glow\"></div>\n\n  <div class=\"thirds-container\">\n    <!-- Step 0: Left Column - Patch Info -->\n    <div class=\"col-left\" data-step=\"0\">\n      <div class=\"status-box\">\n        <div class=\"status-header\">SYSTEM_ALERT</div>\n        <div class=\"patch-icon-wrapper\">\n          <iconify-icon icon=\"mdi:shield-sync-outline\" class=\"main-patch-icon\"></iconify-icon>\n          <div class=\"update-text-glitch\">UPDATE NOW</div>\n        </div>\n        <div class=\"status-details\">\n          <div class=\"status-line\">> KERNEL: VULNERABLE</div>\n          <div class=\"status-line blinking\">> PATCH: AVAILABLE</div>\n        </div>\n      </div>\n    </div>\n\n    <!-- Step 2: Center Column - Defused Bomb -->\n    <div class=\"col-center\" data-step=\"2\">\n      <div class=\"bomb-stage\">\n        <svg viewBox=\"0 0 200 200\" class=\"bomb-svg\">\n          <!-- Fuse -->\n          <path d=\"M120 40 Q 150 20, 160 60\" fill=\"none\" stroke=\"#00FF41\" stroke-width=\"4\" class=\"fuse-path\" />\n          <!-- Bomb Body -->\n          <circle cx=\"100\" cy=\"110\" r=\"60\" fill=\"none\" stroke=\"#00FF41\" stroke-width=\"6\" />\n          <rect x=\"85\" y=\"45\" width=\"30\" height=\"15\" fill=\"#000\" stroke=\"#00FF41\" stroke-width=\"4\" />\n          <!-- Cut Mark -->\n          <path d=\"M135 25 L 155 45 M 155 25 L 135 45\" stroke=\"#39FF14\" stroke-width=\"8\" class=\"cut-mark\" />\n        </svg>\n        <div class=\"threat-status\">THREAT_NEUTRALIZED</div>\n      </div>\n    </div>\n\n    <!-- Step 1: Right Column - Terminal Command -->\n    <div class=\"col-right\" data-step=\"1\">\n      <div class=\"command-window\">\n        <div class=\"window-bar\">\n          <span class=\"dot\"></span><span class=\"dot\"></span><span class=\"dot\"></span>\n          <span class=\"window-title\">bash - root</span>\n        </div>\n        <div class=\"terminal-body\">\n          <div class=\"shell-prompt\">\n            <span class=\"user\">root@system</span>:<span class=\"path\">~</span>#\n            <span class=\"typing-cmd\" id=\"cmd-text\"></span><span class=\"terminal-cursor\"></span>\n          </div>\n          <div class=\"shell-output\" data-step=\"1\">[ SUCCESS ] Module 'algif_aead' disabled.</div>\n        </div>\n      </div>\n    </div>\n  </div>\n\n  <div class=\"footer-deco\">SECURITY_ENFORCED // 0xPATCH_SUCCESS</div>\n</div>","css":".s-scene-10-wrapper { width: 100%; height: 100%; background: #000; font-family: var(--sv-font-mono); color: #00FF41; position: relative; overflow: hidden; }\n.crt-scanlines { position: absolute; inset: 0; background: linear-gradient(rgba(0, 255, 65, 0.08) 50%, transparent 50%); background-size: 100% 4px; pointer-events: none; z-index: 10; }\n.ambient-glow { position: absolute; inset: 0; background: radial-gradient(circle at center, rgba(0, 255, 65, 0.03) 0%, transparent 70%); pointer-events: none; }\n\n.thirds-container { display: flex; width: 100%; height: 100%; align-items: center; justify-content: space-between; padding: 0 5%; box-sizing: border-box; }\n.col-left, .col-center, .col-right { flex: 1; display: flex; flex-direction: column; align-items: center; transition: all 0.5s cubic-bezier(0.22, 1, 0.36, 1); }\n\n/* Left: Update Box */\n.status-box { border: 2px solid rgba(0, 255, 65, 0.4); padding: 30px; background: rgba(0, 255, 65, 0.05); text-align: center; width: 300px; }\n.status-header { font-size: 14px; letter-spacing: 2px; border-bottom: 1px solid rgba(0, 255, 65, 0.4); padding-bottom: 10px; margin-bottom: 20px; opacity: 0.8; }\n.main-patch-icon { font-size: 80px; filter: drop-shadow(0 0 10px rgba(0, 255, 65, 0.5)); }\n.update-text-glitch { font-size: 28px; font-weight: 900; margin-top: 15px; text-shadow: 2px 0 #39FF14; animation: blink 0.8s infinite; }\n.status-details { margin-top: 20px; text-align: left; font-size: 12px; line-height: 1.8; opacity: 0.7; }\n\n/* Right: Terminal */\n.command-window { width: 400px; height: 200px; background: #000; border: 1px solid rgba(0, 255, 65, 0.3); box-shadow: 0 10px 40px rgba(0, 0, 0, 0.8); }\n.window-bar { height: 25px; background: rgba(0, 255, 65, 0.1); display: flex; align-items: center; padding: 0 10px; gap: 5px; }\n.dot { width: 6px; height: 6px; border: 1px solid #00FF41; border-radius: 50%; }\n.window-title { font-size: 10px; margin-left: 10px; opacity: 0.6; }\n.terminal-body { padding: 15px; font-size: 16px; }\n.user { color: #39FF14; }\n.shell-output { margin-top: 15px; font-size: 12px; color: #39FF14; opacity: 0; transform: translateY(10px); transition: 0.4s; }\n[data-step=\"1\"] .shell-output { opacity: 1; transform: translateY(0); }\n.terminal-cursor { display: inline-block; width: 8px; height: 18px; background: #00FF41; animation: blink 1s infinite steps(2); vertical-align: middle; margin-left: 4px; }\n\n/* Center: Bomb */\n.bomb-stage { position: relative; text-align: center; }\n.bomb-svg { width: 220px; height: 220px; }\n.fuse-path { stroke-dasharray: 100; stroke-dashoffset: 0; }\n.cut-mark { opacity: 0; transform: scale(0.5); transform-origin: center; transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); }\n[data-step=\"2\"] .cut-mark { opacity: 1; transform: scale(1); }\n[data-step=\"2\"] .fuse-path { stroke-dasharray: 10 5; opacity: 0.5; }\n.threat-status { margin-top: 20px; font-size: 24px; font-weight: 900; letter-spacing: 4px; color: #39FF14; text-shadow: 0 0 15px rgba(0, 255, 65, 0.6); }\n\n.footer-deco { position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); font-size: 12px; opacity: 0.3; letter-spacing: 5px; }\n\n@keyframes blink { 0% { opacity: 1; } 100% { opacity: 0; } }\n@keyframes draw { to { stroke-dashoffset: 0; } }","js":"window.SceneLifecycle.register('scene-10', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-10\"]');\n    if (!sceneRoot) return;\n    window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n    \n    // Initial state\n    const cmdText = sceneRoot.querySelector('#cmd-text');\n    if (cmdText) cmdText.textContent = '';\n  },\n\n  step(n) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-10\"]');\n    if (!sceneRoot) return;\n\n    if (n === 1) {\n      const cmdText = sceneRoot.querySelector('#cmd-text');\n      const command = 'modprobe -r algif_aead';\n      let i = 0;\n      cmdText.textContent = '';\n      \n      const type = () => {\n        if (i < command.length) {\n          cmdText.textContent += command[i];\n          i++;\n          setTimeout(type, 50);\n        }\n      };\n      type();\n    }\n\n    if (n === 2) {\n      // Extra impact on defusal\n      const bombStage = sceneRoot.querySelector('.bomb-stage');\n      bombStage.style.transform = 'scale(1.1)';\n      setTimeout(() => {\n        bombStage.style.transform = 'scale(1)';\n      }, 200);\n    }\n  }\n});"},{"id":"scene-11","title":"结尾致谢","steps":2,"html":"<div class=\"s-scene-11-wrapper\">\n  <div class=\"crt-scanlines\"></div>\n  <div class=\"ambient-glow\"></div>\n\n  <!-- Step 0: Center Logo/Avatar -->\n  <div class=\"logo-overlay\" data-step=\"0\">\n    <div class=\"avatar-frame\">\n      <div class=\"avatar-glitch\"></div>\n      <svg viewBox=\"0 0 100 100\" class=\"terminal-logo\">\n        <rect x=\"20\" y=\"20\" width=\"60\" height=\"60\" stroke=\"#00FF41\" stroke-width=\"2\" fill=\"none\" />\n        <path d=\"M35 40 L50 55 L65 40\" stroke=\"#00FF41\" stroke-width=\"4\" fill=\"none\" />\n        <path d=\"M30 70 L70 70\" stroke=\"#00FF41\" stroke-width=\"2\" stroke-dasharray=\"4 2\" />\n      </svg>\n    </div>\n    <div class=\"channel-id\">[ CHANNEL_ID: ROOT_NODE ]</div>\n  </div>\n\n  <!-- Step 1: Interactive Actions & Outro -->\n  <div class=\"action-container\" data-step=\"1\">\n    <!-- Like Action -->\n    <div class=\"action-item like-item\">\n      <div class=\"action-box\">\n        <i data-lucide=\"thumbs-up\"></i>\n        <span class=\"action-label\">LIKE_SUCCESS</span>\n      </div>\n    </div>\n\n    <!-- Follow Action -->\n    <div class=\"action-item follow-item\">\n      <div class=\"action-box\">\n        <i data-lucide=\"user-plus\"></i>\n        <span class=\"action-label\">SUBSCRIBE_OK</span>\n      </div>\n    </div>\n\n    <!-- Closing Text -->\n    <div class=\"closing-text\">\n      <div class=\"rainbow-terminal-text\">下期再见</div>\n      <div class=\"cursor-blink\"></div>\n    </div>\n  </div>\n\n  <div class=\"system-footer\">\n    SESSION_TERMINATED: 0x00000000\n  </div>\n</div>","css":".s-scene-11-wrapper { width: 100%; height: 100%; background: #000; font-family: var(--sv-font-mono); color: #00FF41; position: relative; overflow: hidden; display: flex; flex-direction: column; align-items: center; justify-content: center; }\n.crt-scanlines { position: absolute; inset: 0; background: linear-gradient(rgba(0, 255, 65, 0.1) 50%, transparent 50%); background-size: 100% 3px; pointer-events: none; z-index: 100; opacity: 0.12; }\n.ambient-glow { position: absolute; inset: 0; background: radial-gradient(circle at center, rgba(0, 255, 65, 0.04) 0%, transparent 80%); animation: pulse 10s infinite; }\n\n.logo-overlay { text-align: center; z-index: 20; transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1); }\n.avatar-frame { width: 120px; height: 120px; border: 2px solid #00FF41; position: relative; padding: 10px; box-shadow: 0 0 20px rgba(0, 255, 65, 0.15); display: inline-block; background: #000; }\n.terminal-logo { width: 100%; height: 100%; }\n.channel-id { margin-top: 15px; font-size: 14px; letter-spacing: 2px; opacity: 0.8; }\n\n.action-container { position: absolute; inset: 0; pointer-events: none; display: flex; align-items: center; justify-content: center; }\n.action-item { position: absolute; transition: all 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275); opacity: 0; transform: scale(0.5); }\n.like-item { left: 15%; }\n.follow-item { right: 15%; }\n[data-step=\"1\"] .action-item { opacity: 1; transform: scale(1); }\n.action-box { border: 1px solid #00FF41; background: rgba(0, 255, 65, 0.05); padding: 20px; display: flex; flex-direction: column; align-items: center; gap: 10px; }\n.action-box i { width: 40px; height: 40px; }\n.action-label { font-size: 12px; font-weight: bold; }\n\n.closing-text { position: absolute; bottom: 15%; text-align: center; opacity: 0; transform: translateY(20px); transition: all 0.8s ease; display: flex; align-items: center; gap: 10px; }\n[data-step=\"1\"] .closing-text { opacity: 1; transform: translateY(0); }\n.rainbow-terminal-text { font-size: 64px; font-family: var(--sv-font-display-cn); font-weight: 900; background: linear-gradient(90deg, #00FF41, #39FF14, #00FF41); -webkit-background-clip: text; color: transparent; animation: shift 4s linear infinite; text-shadow: 0 0 10px rgba(0, 255, 65, 0.3); }\n.cursor-blink { width: 25px; height: 60px; background: #00FF41; animation: blink 1s infinite steps(2); }\n\n.system-footer { position: absolute; bottom: 5%; font-size: 10px; opacity: 0.4; letter-spacing: 1px; }\n\n@keyframes pulse { 0%, 100% { opacity: 0.04; } 50% { opacity: 0.08; } }\n@keyframes blink { 0% { opacity: 1; } 100% { opacity: 0; } }\n@keyframes shift { 0% { background-position: 0% 50%; } 100% { background-position: 200% 50%; } }","js":"window.SceneLifecycle.register('scene-11', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-11\"]');\n    if (!sceneRoot) return;\n    window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n    \n    // Initial state setup\n    const logo = sceneRoot.querySelector('.logo-overlay');\n    logo.style.transform = 'scale(1.2)';\n    setTimeout(() => {\n      logo.style.transform = 'scale(1)';\n    }, 100);\n  },\n  \n  step(n) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-11\"]');\n    if (!sceneRoot) return;\n\n    if (n === 1) {\n      const logo = sceneRoot.querySelector('.logo-overlay');\n      // Shift logo up to make room for closing text\n      logo.style.transform = 'translateY(-40px)';\n      \n      // Elastic feedback effect on icons is handled by CSS cubic-bezier\n      // But we can trigger a slight rotation for extra \"Q-弹\" feel\n      const items = sceneRoot.querySelectorAll('.action-item');\n      items.forEach((item, idx) => {\n        item.style.transitionDelay = `${idx * 0.1}s`;\n      });\n    }\n  }\n});"}]</script>
  <script defer src="https://unpkg.com/lucide@latest"></script>
  <script defer src="https://code.iconify.design/iconify-icon/2.3.0/iconify-icon.min.js"></script>
  <script>
    (function () {
      var state = { sceneId: 'scene-10', step: 0, direction: 1 };
      var TRANSITION_PRESETS={'door':{'--sv-stage-perspective':'900px','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'rotateY(90deg)','--sv-trans-enter-filter':'blur(6px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'rotateY(0deg)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'rotateY(-90deg)','--sv-trans-exit-filter':'blur(4px)','--sv-trans-duration':'0.65s','--sv-trans-ease':'cubic-bezier(0.36, 0, 0.66, 1)'},'burst':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'scale(0.1)','--sv-trans-enter-filter':'blur(40px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'scale(1.6)','--sv-trans-exit-filter':'blur(24px)','--sv-trans-duration':'0.55s','--sv-trans-ease':'cubic-bezier(0.34, 1.3, 0.64, 1)'},'slam':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'translateX(var(--scene-enter-offset, 180px)) rotate(8deg)','--sv-trans-enter-filter':'blur(24px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'translateX(0) rotate(0deg)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'translateX(var(--scene-exit-offset, -120px)) rotate(-5deg)','--sv-trans-exit-filter':'blur(18px)','--sv-trans-duration':'0.50s','--sv-trans-ease':'cubic-bezier(0.2, 0.8, 0.2, 1)'},'push-up':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'1','--sv-trans-enter-transform':'translateY(105%)','--sv-trans-enter-filter':'blur(0px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'translateY(0)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0.3','--sv-trans-exit-transform':'translateY(-60px)','--sv-trans-exit-filter':'blur(8px)','--sv-trans-duration':'0.55s','--sv-trans-ease':'cubic-bezier(0.22, 1, 0.36, 1)'},'spin':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'rotate(180deg) scale(0.2)','--sv-trans-enter-filter':'blur(24px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'rotate(0deg) scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'rotate(-90deg) scale(0.4)','--sv-trans-exit-filter':'blur(16px)','--sv-trans-duration':'0.55s','--sv-trans-ease':'cubic-bezier(0.34, 1.3, 0.64, 1)'},'tunnel':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'scale(3.0)','--sv-trans-enter-filter':'blur(50px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'scale(0.15)','--sv-trans-exit-filter':'blur(36px)','--sv-trans-duration':'0.60s','--sv-trans-ease':'cubic-bezier(0.22, 1, 0.36, 1)'},'glitch':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'scale(0.95)','--sv-trans-enter-filter':'blur(2px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'scale(0.95)','--sv-trans-exit-filter':'none','--sv-trans-duration':'0.25s','--sv-trans-ease':'ease-out'},};
      // Per-scene transition mapping — built from meta at init time
      var sceneTransitionMap = {};
      var previousSceneId = null;
      var exitCleanupTimer = null;
      var isPlaying = false;
      var playTimer = null;
      var progressRaf = null;
      var STEP_INTERVAL_MS = 1400;
      var SCENE_FINISH_PAUSE_MS = 2000;
      var autoplayFromFirstScene = false;
      var progressWrap = document.getElementById('sv-progress-wrap');
      var progressFill = document.getElementById('sv-progress-fill');
      var progressThumb = document.getElementById('sv-progress-thumb');
      var playBtn = document.getElementById('sv-play-btn');
      var expandBtn = document.getElementById('sv-expand-btn');
      var statusText = document.getElementById('sv-status-text');
      var sceneButtonList = Array.prototype.slice.call(document.querySelectorAll('[data-panel-scene-id]'));
      var sceneRetryButtonList = Array.prototype.slice.call(document.querySelectorAll('[data-retry-scene-id]'));
      var editorOverlay = document.getElementById('sv-editor-overlay');
      var editorBackdrop = document.getElementById('sv-editor-backdrop');
      var editorSheet = document.getElementById('sv-editor-sheet');
      var editorResizeHandle = document.getElementById('sv-editor-resize-handle');
      var editorCloseBtn = document.getElementById('sv-editor-close-btn');
      var editorSaveBtn = document.getElementById('sv-editor-save-btn');
      var editorList = document.getElementById('sv-editor-list');
      var editorSaveTip = document.getElementById('sv-editor-save-tip');
      var editorTipTimer = null;
      var isEditorOpen = false;
      var isEditorDirty = false;
      var editorHeightVh = 50;
      var hostCaps = { canRetry: false, canEditPanel: false, locale: 'zh', theme: 'dark' };
      var metaJson = document.getElementById('__SVGVIDEO_META__');
      var meta = { scenes: [] };
      try {
        meta = JSON.parse((metaJson && metaJson.textContent) || '{}');
      } catch (e) {
        meta = { scenes: [] };
      }
      var metaSceneMap = {};
      var metaScenes = Array.isArray(meta.scenes) ? meta.scenes : [];
      metaScenes.forEach(function (scene) {
        if (scene && typeof scene.id === 'string' && scene.id) {
          metaSceneMap[scene.id] = scene;
          sceneTransitionMap[scene.id] = (typeof scene.transition === 'string' && TRANSITION_PRESETS[scene.transition]) ? scene.transition : 'door';
        }
      });
      function refreshFrameworkIcons(root) {
        var refreshRoot = root || document;
        try {
          if (window.lucide && typeof window.lucide.createIcons === 'function') {
            window.lucide.createIcons({ root: refreshRoot });
          }
        } catch (iconErr) {
          console.warn('[svg-video] lucide refresh failed', iconErr);
        }
      }
      window.__SVGVIDEO_REFRESH_ICONS = refreshFrameworkIcons;
      var sceneModels = Array.prototype.slice.call(document.querySelectorAll('#stage > [data-scene-id]')).map(function (node, index) {
        var sceneId = node.getAttribute('data-scene-id') || ('scene-' + (index + 1));
        var metaScene = metaSceneMap[sceneId] || {};
        var sceneTitle = typeof metaScene.title === 'string' && metaScene.title ? metaScene.title : ('分镜' + (index + 1));
        var sceneSteps = Math.max(1, Number(metaScene.steps) || 1);
        var sceneStatus = typeof metaScene.status === 'string' ? metaScene.status : 'pending';
        var scenePrompt = typeof metaScene.prompt === 'string' ? metaScene.prompt : '';
        var sceneScript = typeof metaScene.scriptText === 'string' ? metaScene.scriptText : '';
        var sceneAudioObjectKey = typeof metaScene.audioObjectKey === 'string' ? metaScene.audioObjectKey : '';
        var sceneAudioDurationMs = Number(metaScene.audioDurationMs) > 0 ? Number(metaScene.audioDurationMs) : 0;
        var sceneVoiceName = typeof metaScene.voiceName === 'string' ? metaScene.voiceName : '';
        var sceneVoiceStyle = typeof metaScene.voiceStyle === 'string' ? metaScene.voiceStyle : '';
        var relatedSceneIds = Array.isArray(metaScene.relatedSceneIds) ? metaScene.relatedSceneIds : [];
        return {
          id: sceneId,
          title: sceneTitle,
          steps: sceneSteps,
          status: sceneStatus,
          prompt: scenePrompt,
          scriptText: sceneScript,
          audioObjectKey: sceneAudioObjectKey,
          audioDurationMs: sceneAudioDurationMs,
          voiceName: sceneVoiceName,
          voiceStyle: sceneVoiceStyle,
          relatedSceneIds: relatedSceneIds,
          transition: sceneTransitionMap[sceneId] || 'door'
        };
      });
      if (!sceneModels.length && metaScenes.length) {
        sceneModels = metaScenes.map(function (scene, index) {
          return {
            id: scene.id || ('scene-' + (index + 1)),
            title: scene.title || ('分镜' + (index + 1)),
            steps: Math.max(1, Number(scene.steps) || 1),
            status: typeof scene.status === 'string' ? scene.status : 'pending',
            prompt: typeof scene.prompt === 'string' ? scene.prompt : '',
            scriptText: typeof scene.scriptText === 'string' ? scene.scriptText : '',
            audioObjectKey: typeof scene.audioObjectKey === 'string' ? scene.audioObjectKey : '',
            audioDurationMs: Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0,
            voiceName: typeof scene.voiceName === 'string' ? scene.voiceName : '',
            voiceStyle: typeof scene.voiceStyle === 'string' ? scene.voiceStyle : '',
            relatedSceneIds: Array.isArray(scene.relatedSceneIds) ? scene.relatedSceneIds : [],
            transition: sceneTransitionMap[scene.id] || 'door'
          };
        });
      }
      function i18nText(zh, en) {
        return hostCaps.locale === 'en' ? en : zh;
      }
      function applyI18nTexts() {
        var toolbarTitleEl = document.getElementById('sv-toolbar-title');
        var titleEl = document.getElementById('sv-editor-header-title');
        if (toolbarTitleEl) toolbarTitleEl.textContent = i18nText('分镜面板', 'Storyboard');
        if (titleEl) titleEl.textContent = i18nText('分镜详情编辑', 'Storyboard details');
        if (expandBtn) {
          var expandText = i18nText('展开分镜详情', 'Open storyboard details');
          expandBtn.setAttribute('aria-label', expandText);
          expandBtn.setAttribute('title', expandText);
        }
        if (editorSaveBtn) editorSaveBtn.textContent = isEditorDirty ? i18nText('保存*', 'Save*') : i18nText('保存', 'Save');
        if (editorCloseBtn) editorCloseBtn.textContent = i18nText('关闭', 'Close');
        if (editorSaveTip) editorSaveTip.textContent = i18nText('已保存', 'Saved');
      }
      function clampEditorHeightVh(value) {
        return Math.max(32, Math.min(80, Number(value) || 50));
      }
      function applyEditorHeight(vh) {
        editorHeightVh = clampEditorHeightVh(vh);
        document.documentElement.style.setProperty('--sv-editor-height', editorHeightVh + 'vh');
      }
      function persistMetaToScript() {
        meta.title = typeof meta.title === 'string' ? meta.title : '';
        meta.version = meta.version || 1;
        meta.scenes = sceneModels.map(function (scene) {
          return {
            id: scene.id,
            title: scene.title || '',
            steps: Math.max(1, Number(scene.steps) || 1),
            status: scene.status || 'pending',
            prompt: scene.prompt || '',
            scriptText: scene.scriptText || '',
            audioObjectKey: scene.audioObjectKey || '',
            audioDurationMs: Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0,
            voiceName: scene.voiceName || '',
            voiceStyle: scene.voiceStyle || '',
            relatedSceneIds: Array.isArray(scene.relatedSceneIds) ? scene.relatedSceneIds : [],
            transition: scene.transition || 'door'
          };
        });
        if (metaJson) metaJson.textContent = JSON.stringify(meta);
      }
      function showSavedTip() {
        if (!editorSaveTip) return;
        if (editorTipTimer) {
          clearTimeout(editorTipTimer);
          editorTipTimer = null;
        }
        editorSaveTip.classList.add('is-visible');
        editorTipTimer = setTimeout(function () {
          editorSaveTip.classList.remove('is-visible');
        }, 1200);
      }
      function markEditorDirty() {
        isEditorDirty = true;
        applyI18nTexts();
      }
      function clearEditorDirty() {
        isEditorDirty = false;
        applyI18nTexts();
      }
      function getStatusLabel(status) {
        if (status === 'success') return i18nText('已生成', 'Done');
        if (status === 'generating') return i18nText('生成中', 'Generating');
        if (status === 'failed') return i18nText('失败', 'Failed');
        return i18nText('未生成', 'Pending');
      }
      function getStatusClass(status) {
        if (status === 'generating') return 'is-generating';
        if (status === 'success') return 'is-success';
        return 'is-failed';
      }
      function getRetryButtonInnerHtml(isGenerating) {
        if (isGenerating) return '<span class="scene-chip-retry-spinner"></span>';
        return '<svg class="scene-chip-retry-icon" viewBox="0 0 1024 1024" width="16" height="16" fill="currentColor"><path d="M698.569 531.322a39.825 39.825 0 0 0-23.898 7.949c-17.702 13.216-21.34 38.28-8.124 55.982l95.716 128.212c7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949c17.702-13.216 21.34-38.28 8.124-55.982l-95.716-128.212c-7.853-10.521-19.892-16.074-32.084-16.073z" /><path d="M922.498 563.818a39.825 39.825 0 0 0-23.898 7.949l-128.212 95.716c-17.703 13.216-21.34 38.28-8.124 55.982 7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949l128.212-95.716c17.702-13.216 21.34-38.28 8.124-55.982-7.854-10.521-19.893-16.074-32.084-16.073zM229.652 282.148a39.825 39.825 0 0 0-23.898 7.949c-17.702 13.216-21.34 38.28-8.124 55.982l95.716 128.212c7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949c17.702-13.216 21.34-38.28 8.124-55.982l-95.716-128.212c-7.854-10.521-19.892-16.074-32.084-16.073z" /><path d="M229.652 282.148a39.825 39.825 0 0 0-23.898 7.949L77.542 385.813c-17.702 13.216-21.34 38.28-8.124 55.982 7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949l128.213-95.716c17.702-13.216 21.34-38.28 8.124-55.982-7.855-10.521-19.893-16.073-32.085-16.073z" /><path d="M614.968 763.65c-44.13 18.171-94.005 25.121-146.168 16.968C353.747 762.636 261.364 670.253 243.381 555.2c-9.681-61.936 1.932-120.646 28.337-170.344l-58.657-58.657c-40.139 64.442-60.11 142.746-50.806 226.152 17.993 161.306 148.088 291.401 309.394 309.394 62.041 6.92 121.259-2.357 174.048-24.083 26.535-10.921 33.625-45.203 13.335-65.493l-0.098-0.098c-11.555-11.555-28.854-14.643-43.966-8.421zM409.033 260.35c44.131-18.171 94.007-25.122 146.169-16.968 115.051 17.985 207.431 110.365 225.416 225.416 9.682 61.935-1.931 120.646-28.337 170.346l58.658 58.658c40.139-64.443 60.109-142.747 50.805-226.155-17.993-161.305-148.087-291.399-309.391-309.391-62.042-6.92-121.26 2.356-174.05 24.082-26.535 10.921-33.625 45.203-13.335 65.493l0.099 0.099c11.555 11.554 28.854 14.642 43.966 8.42z" /></svg>';
      }
      function setSceneStatus(sceneId, status) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return;
        sceneModels[index].status = status;
        persistMetaToScript();
        var statusClass = getStatusClass(status);
        var chipWrap = document.querySelector('[data-chip-scene-id="' + sceneId + '"]');
        if (chipWrap) {
          chipWrap.classList.remove('is-success', 'is-failed', 'is-generating');
          chipWrap.classList.add(statusClass);
          var chipBtn = chipWrap.querySelector('.scene-chip');
          if (chipBtn) {
            chipBtn.classList.remove('is-success', 'is-failed', 'is-generating');
            chipBtn.classList.add(statusClass);
          }
          var retryBtn = chipWrap.querySelector('.scene-chip-retry');
          if (retryBtn) {
            retryBtn.innerHTML = getRetryButtonInnerHtml(status === 'generating');
            if (status === 'generating') retryBtn.setAttribute('disabled', 'disabled');
            else retryBtn.removeAttribute('disabled');
          }
        }
        renderStatus();
      }
      function requestSceneRetry(sceneId) {
        if (!hostCaps.canRetry) return;
        var idx = getSceneIndexById(sceneId);
        if (idx < 0) return;
        var scene = sceneModels[idx];
        setSceneStatus(sceneId, 'generating');
        focusScene(sceneId);
        if (window.parent && window.parent !== window) {
          window.parent.postMessage(
            { type: '__SVGVIDEO_RETRY_SCENE', sceneId: sceneId, prompt: scene.prompt || '' },
            '*'
          );
        }
      }
      function renderEditorList() {
        if (!editorList) return;
        editorList.innerHTML = '';
        var fragment = document.createDocumentFragment();
        sceneModels.forEach(function (scene, index) {
          var item = document.createElement('section');
          item.className = 'sv-editor-item';
          item.setAttribute('data-editor-scene-id', scene.id);

          var head = document.createElement('div');
          head.className = 'sv-editor-item-head';

          var jumpBtn = document.createElement('button');
          jumpBtn.type = 'button';
          jumpBtn.className = 'sv-editor-item-title';
          jumpBtn.textContent = i18nText('分镜', 'Scene') + (index + 1) + ' · ' + (scene.title || '');
          jumpBtn.addEventListener('click', function () {
            focusScene(scene.id);
          });
          head.appendChild(jumpBtn);

          var statusWrap = document.createElement('div');
          statusWrap.className = 'sv-editor-status-wrap';
          var status = document.createElement('span');
          status.className = 'sv-editor-status';
          status.textContent = getStatusLabel(scene.status);
          statusWrap.appendChild(status);
          var retryBtn = document.createElement('button');
          retryBtn.type = 'button';
          retryBtn.className = 'scene-chip-retry sv-editor-retry';
          retryBtn.setAttribute('aria-label', i18nText('重新生成当前分镜', 'Retry this scene'));
          retryBtn.setAttribute('title', i18nText('重新生成当前分镜', 'Retry this scene'));
          retryBtn.innerHTML = getRetryButtonInnerHtml(scene.status === 'generating');
          if (scene.status === 'generating' || !hostCaps.canRetry) retryBtn.setAttribute('disabled', 'disabled');
          retryBtn.addEventListener('click', function (event) {
            event.preventDefault();
            event.stopPropagation();
            requestSceneRetry(scene.id);
            if (isEditorOpen) renderEditorList();
          });
          statusWrap.appendChild(retryBtn);
          head.appendChild(statusWrap);

          item.appendChild(head);

          var scriptField = document.createElement('label');
          scriptField.className = 'sv-editor-field';
          var scriptLabel = document.createElement('span');
          scriptLabel.className = 'sv-editor-label';
          scriptLabel.textContent = i18nText('脚本', 'Script');
          var scriptInput = document.createElement('div');
          scriptInput.className = 'sv-editor-script-view';
          scriptInput.setAttribute('data-field-scene-id', scene.id);
          scriptInput.textContent = scene.scriptText || '';
          scriptField.appendChild(scriptLabel);
          scriptField.appendChild(scriptInput);
          item.appendChild(scriptField);

          var promptField = document.createElement('label');
          promptField.className = 'sv-editor-field';
          var promptLabel = document.createElement('span');
          promptLabel.className = 'sv-editor-label';
          promptLabel.textContent = i18nText('提示词', 'Prompt');
          var promptInput = document.createElement('textarea');
          promptInput.className = 'sv-editor-textarea';
          promptInput.setAttribute('data-field-scene-id', scene.id);
          promptInput.setAttribute('data-field', 'prompt');
          promptInput.value = scene.prompt || '';
          promptInput.addEventListener('click', function (event) {
            event.stopPropagation();
          });
          promptInput.addEventListener('input', function () {
            scene.prompt = promptInput.value;
            markEditorDirty();
          });
          promptField.appendChild(promptLabel);
          promptField.appendChild(promptInput);
          item.appendChild(promptField);
          item.addEventListener('click', function () {
            focusScene(scene.id);
          });

          fragment.appendChild(item);
        });
        editorList.appendChild(fragment);
        highlightActiveEditorItem();
      }
      function highlightActiveEditorItem() {
        if (!editorList) return;
        var itemList = Array.prototype.slice.call(editorList.querySelectorAll('[data-editor-scene-id]'));
        itemList.forEach(function (item) {
          if (item.getAttribute('data-editor-scene-id') === state.sceneId) item.classList.add('is-active');
          else item.classList.remove('is-active');
        });
      }
      function openEditor() {
        if (!hostCaps.canEditPanel) return;
        if (!editorOverlay) return;
        renderEditorList();
        applyEditorHeight(editorHeightVh);
        editorOverlay.classList.add('is-open');
        editorOverlay.setAttribute('aria-hidden', 'false');
        document.body.classList.add('sv-editor-open');
        isEditorOpen = true;
      }
      function closeEditor() {
        if (!editorOverlay) return;
        editorOverlay.classList.remove('is-open');
        editorOverlay.setAttribute('aria-hidden', 'true');
        document.body.classList.remove('sv-editor-open');
        isEditorOpen = false;
      }
      function saveEditor() {
        persistMetaToScript();
        clearEditorDirty();
        showSavedTip();
        if (window.parent && window.parent !== window) {
          window.parent.postMessage({ type: '__SVGVIDEO_META_UPDATED', meta: meta }, '*');
        }
      }
      function getTotalSteps() {
        return sceneModels.reduce(function (sum, scene) { return sum + Math.max(1, Number(scene.steps) || 1); }, 0);
      }
      function getSceneIndexById(sceneId) {
        for (var i = 0; i < sceneModels.length; i++) {
          if (sceneModels[i].id === sceneId) return i;
        }
        return -1;
      }
      function getSceneInitialStep(sceneId) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return 0;
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        return Math.max(0, maxSteps - 1);
      }
      function focusScene(sceneId) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return;
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        stopPlayback();
        window.__SVGVIDEO_SET_STATE(sceneId, 0, 1);
        if (maxSteps > 1) {
          setTimeout(function () {
            window.__SVGVIDEO_SET_STATE(sceneId, Math.max(0, maxSteps - 1), 1);
          }, 90);
        }
      }
      function getProgressPercent(sceneId, step) {
        var total = getTotalSteps();
        if (!total) return 0;
        var index = getSceneIndexById(sceneId);
        if (index < 0) return 0;
        var completed = 0;
        for (var i = 0; i < index; i++) completed += Math.max(1, Number(sceneModels[i].steps) || 1);
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        var localStep = Math.max(0, Math.min(maxSteps - 1, Number(step) || 0));
        return Math.max(0, Math.min(100, ((completed + localStep) / total) * 100));
      }
      function updateProgressUi(percent) {
        var pct = Math.max(0, Math.min(100, percent || 0));
        if (progressFill) progressFill.style.width = pct + '%';
        if (progressThumb) progressThumb.style.left = pct + '%';
      }
      function stopProgressAnimation() {
        if (progressRaf) {
          cancelAnimationFrame(progressRaf);
          progressRaf = null;
        }
      }
      function startProgressSegment(fromPercent, toPercent, durationMs) {
        stopProgressAnimation();
        var from = Math.max(0, Math.min(100, Number(fromPercent) || 0));
        var to = Math.max(0, Math.min(100, Number(toPercent) || 0));
        var duration = Math.max(1, Number(durationMs) || 1);
        if (duration <= 1 || to <= from) {
          updateProgressUi(to);
          return;
        }
        var startAt = performance.now();
        var tick = function (now) {
          if (!isPlaying) {
            stopProgressAnimation();
            return;
          }
          var elapsed = now - startAt;
          var ratio = Math.max(0, Math.min(1, elapsed / duration));
          var current = from + (to - from) * ratio;
          updateProgressUi(current);
          if (ratio < 1) {
            progressRaf = requestAnimationFrame(tick);
          } else {
            stopProgressAnimation();
          }
        };
        progressRaf = requestAnimationFrame(tick);
      }
      function getPlaybackSegment(sceneIndex, step) {
        var scene = sceneModels[sceneIndex];
        if (!scene) return null;
        var currentPercent = getProgressPercent(scene.id, step);
        var maxSteps = Math.max(1, Number(scene.steps) || 1);
        if (step < maxSteps - 1) {
          return {
            from: currentPercent,
            to: getProgressPercent(scene.id, step + 1),
            duration: STEP_INTERVAL_MS
          };
        }
        if (sceneIndex < sceneModels.length - 1) {
          var nextScene = sceneModels[sceneIndex + 1];
          var nextPercent = nextScene ? getProgressPercent(nextScene.id, 0) : currentPercent;
          return {
            from: currentPercent,
            to: nextPercent,
            duration: SCENE_FINISH_PAUSE_MS
          };
        }
        return {
          from: currentPercent,
          to: 100,
          duration: STEP_INTERVAL_MS
        };
      }
      function renderStatus() {
        if (!statusText) return;
        var done = sceneModels.filter(function (scene) { return scene.status === 'success'; }).length;
        var pending = sceneModels.filter(function (scene) { return scene.status === 'pending' || scene.status === 'generating'; }).length;
        var failed = sceneModels.filter(function (scene) { return scene.status === 'failed'; }).length;
        statusText.textContent = '已生成 ' + done + '/' + sceneModels.length + ' · 待生成 ' + pending + ' · 失败 ' + failed;
      }
      function updatePlayButton() {
        if (!playBtn) return;
        playBtn.innerHTML = isPlaying
          ? '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><rect x="6" y="5" width="4" height="14" rx="1"></rect><rect x="14" y="5" width="4" height="14" rx="1"></rect></svg>'
          : '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M7 5v14l11-7z"></path></svg>';
        playBtn.setAttribute('aria-label', isPlaying ? '暂停播放' : '播放分镜');
        playBtn.setAttribute('title', isPlaying ? '暂停播放' : '播放分镜');
      }
      function applyHostCaps() {
        if (hostCaps.canRetry) document.body.classList.add('sv-host-can-retry');
        else document.body.classList.remove('sv-host-can-retry');
        if (hostCaps.canEditPanel) document.body.classList.add('sv-host-can-edit-panel');
        else document.body.classList.remove('sv-host-can-edit-panel');
        if (hostCaps.theme === 'light') document.body.classList.add('sv-theme-light');
        else document.body.classList.remove('sv-theme-light');
      }
      function highlightActiveSceneButton() {
        sceneButtonList.forEach(function (button) {
          var targetId = button.getAttribute('data-panel-scene-id');
          if (targetId === state.sceneId) button.classList.add('is-active');
          else button.classList.remove('is-active');
        });
      }
      function stopPlayback() {
        if (playTimer) {
          clearTimeout(playTimer);
          playTimer = null;
        }
        stopProgressAnimation();
        isPlaying = false;
        updatePlayButton();
      }
      function startPlayback() {
        if (!sceneModels.length) return;
        stopPlayback();
        var sceneIndex = Math.max(0, getSceneIndexById(state.sceneId));
        var step = 0;
        var applyPlaybackState = function (direction) {
          var scene = sceneModels[sceneIndex];
          if (!scene) return false;
          window.__SVGVIDEO_SET_STATE(scene.id, step, direction);
          updateProgressUi(getProgressPercent(scene.id, step));
          var segment = getPlaybackSegment(sceneIndex, step);
          if (segment) startProgressSegment(segment.from, segment.to, segment.duration);
          return true;
        };
        var scheduleAdvance = function (delay) {
          playTimer = setTimeout(function () {
            var currentScene = sceneModels[sceneIndex];
            if (!currentScene) {
              stopPlayback();
              return;
            }
            var maxSteps = Math.max(1, Number(currentScene.steps) || 1);
            if (step < maxSteps - 1) {
              step += 1;
              applyPlaybackState(1);
              scheduleAdvance(STEP_INTERVAL_MS);
              return;
            }
            if (sceneIndex < sceneModels.length - 1) {
              playTimer = setTimeout(function () {
                sceneIndex += 1;
                step = 0;
                if (!applyPlaybackState(1)) {
                  stopPlayback();
                  return;
                }
                scheduleAdvance(STEP_INTERVAL_MS);
              }, SCENE_FINISH_PAUSE_MS);
              return;
            }
            stopPlayback();
          }, delay);
        };
        isPlaying = true;
        updatePlayButton();
        if (!applyPlaybackState(1)) {
          stopPlayback();
          return;
        }
        scheduleAdvance(STEP_INTERVAL_MS);
      }
      window.SceneLifecycle = {
        handlers: {},
        register: function (sceneId, handler) { this.handlers[sceneId] = handler || {}; }
      };

      (function () {
        var sceneDataJson = document.getElementById('__SVGVIDEO_SCENE_DATA__');
        var runtimeScenes = [];
        try {
          runtimeScenes = JSON.parse((sceneDataJson && sceneDataJson.textContent) || '[]');
        } catch (_e) {
          runtimeScenes = [];
        }
        runtimeScenes.forEach(function (scene) {
          if (!scene || typeof scene.id !== 'string') return;
          var js = typeof scene.js === 'string' ? scene.js.trim() : '';
          if (!js) return;
          try {
            var factory = new Function(js);
            factory.call(window);
          } catch (err) {
            console.error('[svg-video] scene runtime failed', scene.id, err);
          }
        });
        refreshFrameworkIcons(document);
      })();

      function applyStepVisibility(sceneEl) {
        var stepNodes = sceneEl.querySelectorAll('[data-step]');
        stepNodes.forEach(function (node) {
          var minStep = Number(node.getAttribute('data-step') || '0');
          var visible = state.step >= minStep;
          node.style.opacity = visible ? '1' : '0';
          node.style.visibility = visible ? 'visible' : 'hidden';
          node.style.pointerEvents = visible ? 'auto' : 'none';
          node.style.transform = visible ? 'translateY(0)' : 'translateY(8px)';
          node.style.filter = visible ? 'blur(0px)' : 'blur(4px)';
        });
      }
      function applySceneState() {
        var scenes = document.querySelectorAll('#stage > [data-scene-id]');
        var currentSceneEl = null;
        var previousSceneEl = null;
        var glitchTimer = null;
        scenes.forEach(function (sceneEl) {
          var sceneId = sceneEl.getAttribute('data-scene-id');
          if (sceneId === state.sceneId) currentSceneEl = sceneEl;
          if (sceneId === previousSceneId) previousSceneEl = sceneEl;
        });
        var direction = state.direction >= 0 ? 1 : -1;
        document.documentElement.style.setProperty('--scene-enter-offset', direction > 0 ? '200px' : '-200px');
        document.documentElement.style.setProperty('--scene-exit-offset', direction > 0 ? '-140px' : '140px');
        var isSceneChange = previousSceneId !== state.sceneId;
        var targetTransition = sceneTransitionMap[state.sceneId] || 'door';
        var needsGlitch = isSceneChange && targetTransition === 'glitch' && currentSceneEl;

        // Apply per-scene transition CSS vars before switching
        if (isSceneChange) {
          var preset = TRANSITION_PRESETS[targetTransition] || TRANSITION_PRESETS['door'];
          var rootStyle = document.documentElement.style;
          for (var varKey in preset) {
            rootStyle.setProperty(varKey, preset[varKey]);
          }
        }

        function doSwitch() {
          if (exitCleanupTimer) {
            clearTimeout(exitCleanupTimer);
            exitCleanupTimer = null;
          }
          scenes.forEach(function (sceneEl) {
            if (sceneEl !== currentSceneEl && sceneEl !== previousSceneEl) {
              sceneEl.classList.remove('scene-active');
              sceneEl.classList.remove('scene-exit');
            }
          });
          if (previousSceneEl && previousSceneEl !== currentSceneEl) {
            previousSceneEl.classList.remove('scene-active');
            previousSceneEl.classList.add('scene-exit');
          }
          if (currentSceneEl) {
            currentSceneEl.classList.remove('scene-exit');
            currentSceneEl.classList.add('scene-active');
            applyStepVisibility(currentSceneEl);
          }
          if (previousSceneEl && previousSceneEl !== currentSceneEl) {
            exitCleanupTimer = setTimeout(function () { previousSceneEl.classList.remove('scene-exit'); }, 650);
          }
          if (previousSceneId !== state.sceneId) {
            if (previousSceneId && window.SceneLifecycle.handlers[previousSceneId] && typeof window.SceneLifecycle.handlers[previousSceneId].leave === 'function') {
              try { window.SceneLifecycle.handlers[previousSceneId].leave(); } catch (e) {}
            }
          }
          if (currentSceneEl && window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].enter === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].enter(); } catch (e) {}
          }
          if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].step === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].step(state.step); } catch (e) {}
          }
          if (currentSceneEl) {
            refreshFrameworkIcons(currentSceneEl);
          }
          previousSceneId = state.sceneId;
          highlightActiveSceneButton();
          highlightActiveEditorItem();
          updateProgressUi(getProgressPercent(state.sceneId, state.step));
        }

        function runGlitchSequence() {
          if (!currentSceneEl) return;
          // Step 1: blur bomb + shift (instant, disable transition first)
          var noTrans = document.getElementById('sv-no-transition');
          if (!noTrans) {
            noTrans = document.createElement('style');
            noTrans.id = 'sv-no-transition';
            noTrans.textContent = '.scene { transition: none !important; }';
            document.head.appendChild(noTrans);
          }
          currentSceneEl.style.filter = 'blur(24px) brightness(1.5)';
          currentSceneEl.style.transform = 'translateX(30px) scale(0.96)';
          // Step 2: snap to other side (80ms)
          glitchTimer = setTimeout(function () {
            if (!currentSceneEl) return;
            currentSceneEl.style.filter = 'blur(3px) brightness(1.1)';
            currentSceneEl.style.transform = 'translateX(-15px) scale(1.02)';
            // Step 3: settle with slight bounce (160ms)
            glitchTimer = setTimeout(function () {
              if (!currentSceneEl) return;
              currentSceneEl.style.filter = 'blur(0px) brightness(1)';
              currentSceneEl.style.transform = 'translateX(0) scale(1)';
              if (noTrans && noTrans.parentNode) noTrans.parentNode.removeChild(noTrans);
              if (currentSceneEl) {
                refreshFrameworkIcons(currentSceneEl);
              }
            }, 70);
          }, 80);
        }

        if (needsGlitch) {
          // Kill old scene instantly
          if (previousSceneEl) {
            previousSceneEl.classList.remove('scene-active');
            previousSceneEl.classList.add('scene-exit');
            exitCleanupTimer = setTimeout(function () { previousSceneEl.classList.remove('scene-exit'); }, 650);
          }
          // Show new scene for glitch base
          if (currentSceneEl) {
            currentSceneEl.classList.remove('scene-exit');
            currentSceneEl.classList.add('scene-active');
            applyStepVisibility(currentSceneEl);
          }
          // Fire lifecycle immediately so scene JS can initialize
          if (previousSceneId && window.SceneLifecycle.handlers[previousSceneId] && typeof window.SceneLifecycle.handlers[previousSceneId].leave === 'function') {
            try { window.SceneLifecycle.handlers[previousSceneId].leave(); } catch (e) {}
          }
          if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].enter === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].enter(); } catch (e) {}
          }
          if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].step === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].step(state.step); } catch (e) {}
          }
          previousSceneId = state.sceneId;
          highlightActiveSceneButton();
          highlightActiveEditorItem();
          updateProgressUi(getProgressPercent(state.sceneId, state.step));
          runGlitchSequence();
        } else {
          doSwitch();
        }
      }
      window.__SVGVIDEO_SET_STATE = function (sceneId, step, direction) {
        if (typeof sceneId === 'string' && sceneId) {
          if (typeof direction === 'number' && Number.isFinite(direction)) {
            state.direction = direction >= 0 ? 1 : -1;
          } else {
            var nextIndex = getSceneIndexById(sceneId);
            var prevIndex = getSceneIndexById(state.sceneId);
            if (nextIndex !== -1 && prevIndex !== -1) state.direction = nextIndex >= prevIndex ? 1 : -1;
          }
          state.sceneId = sceneId;
        }
        if (typeof step === 'number' && Number.isFinite(step)) state.step = Math.max(0, Math.floor(step));
        applySceneState();
      };
      if (state.sceneId && getSceneIndexById(state.sceneId) === -1 && sceneModels.length) {
        state.sceneId = sceneModels[0].id;
      }
      if (playBtn) {
        playBtn.addEventListener('click', function () {
          if (isPlaying) stopPlayback();
          else startPlayback();
        });
      }
      if (expandBtn) {
        expandBtn.addEventListener('click', function () {
          if (isEditorOpen) closeEditor();
          else openEditor();
        });
      }
      if (editorCloseBtn) {
        editorCloseBtn.addEventListener('click', closeEditor);
      }
      if (editorBackdrop) {
        editorBackdrop.addEventListener('click', closeEditor);
      }
      if (editorSaveBtn) {
        editorSaveBtn.addEventListener('click', saveEditor);
      }
      if (editorResizeHandle && editorSheet) {
        editorResizeHandle.addEventListener('mousedown', function (event) {
          event.preventDefault();
          var startY = event.clientY;
          var startHeightPx = (window.innerHeight * editorHeightVh) / 100;
          var onMove = function (moveEvent) {
            var delta = startY - moveEvent.clientY;
            var nextHeightPx = startHeightPx + delta;
            var nextHeightVh = (nextHeightPx / Math.max(1, window.innerHeight)) * 100;
            applyEditorHeight(nextHeightVh);
          };
          var onUp = function () {
            window.removeEventListener('mousemove', onMove);
            window.removeEventListener('mouseup', onUp);
          };
          window.addEventListener('mousemove', onMove);
          window.addEventListener('mouseup', onUp);
        });
      }
      sceneButtonList.forEach(function (button) {
        button.addEventListener('click', function () {
          var sceneId = button.getAttribute('data-panel-scene-id');
          if (!sceneId) return;
          focusScene(sceneId);
        });
      });
      sceneRetryButtonList.forEach(function (button) {
        button.addEventListener('click', function (event) {
          event.preventDefault();
          event.stopPropagation();
          var sceneId = button.getAttribute('data-retry-scene-id');
          if (!sceneId) return;
          requestSceneRetry(sceneId);
        });
      });
      if (progressWrap) {
        progressWrap.addEventListener('click', function (event) {
          var rect = progressWrap.getBoundingClientRect();
          var pct = Math.max(0, Math.min(100, ((event.clientX - rect.left) / rect.width) * 100));
          var totalSteps = getTotalSteps();
          var targetStep = Math.round((pct / 100) * totalSteps);
          var accumulated = 0;
          for (var i = 0; i < sceneModels.length; i++) {
            var sceneSteps = Math.max(1, Number(sceneModels[i].steps) || 1);
            if (accumulated + sceneSteps > targetStep) {
              var localStep = Math.max(0, Math.min(sceneSteps - 1, targetStep - accumulated));
              stopPlayback();
              window.__SVGVIDEO_SET_STATE(sceneModels[i].id, localStep, 1);
              updateProgressUi(pct);
              return;
            }
            accumulated += sceneSteps;
          }
        });
      }
      window.addEventListener('message', function (event) {
        var data = event && event.data;
        if (!data || typeof data.type !== 'string') return;
        if (data.type === '__SVGVIDEO_SET_STATE') {
          window.__SVGVIDEO_SET_STATE(data.sceneId, data.step, data.direction);
          return;
        }
        if (data.type === '__SVGVIDEO_PLAY') {
          startPlayback();
          return;
        }
        if (data.type === '__SVGVIDEO_STOP') {
          stopPlayback();
          return;
        }
        if (data.type === '__SVGVIDEO_SET_HOST_CAPS') {
          hostCaps.canRetry = Boolean(data.canRetry);
          hostCaps.canEditPanel = Boolean(data.canEditPanel);
          hostCaps.locale = data.locale === 'en' ? 'en' : 'zh';
          hostCaps.theme = data.theme === 'light' ? 'light' : 'dark';
          applyI18nTexts();
          applyHostCaps();
          if (isEditorOpen) renderEditorList();
          return;
        }
        if (data.type === '__SVGVIDEO_SET_SCENE_STATUS') {
          var sceneId = typeof data.sceneId === 'string' ? data.sceneId : '';
          var status = typeof data.status === 'string' ? data.status : '';
          if (sceneId && status) {
            setSceneStatus(sceneId, status);
            if (isEditorOpen) renderEditorList();
          }
          return;
        }
        if (data.type === '__SVGVIDEO_SET_RECORDING') {
          if (data && data.active) {
            document.body.classList.add('sv-recording');
            // 如果指定了初始分镜，无过渡动画地跳转过去，避免录制开头残留旧分镜画面
            if (data.sceneId) {
              var noTransStyle = document.createElement('style');
              noTransStyle.id = 'sv-no-transition';
              noTransStyle.textContent = '.scene, [data-step] { transition: none !important; }';
              document.head.appendChild(noTransStyle);
              window.__SVGVIDEO_SET_STATE(data.sceneId, 0, 1);
              // 强制 reflow 后恢复过渡动画
              void document.body.offsetHeight;
              requestAnimationFrame(function () {
                var s = document.getElementById('sv-no-transition');
                if (s) s.remove();
              });
            }
          } else {
            document.body.classList.remove('sv-recording');
          }
          return;
        }
        if (data.type === '__SVGVIDEO_SET_META' && data.meta && typeof data.meta === 'object') {
          meta = data.meta;
          var freshScenes = Array.isArray(meta.scenes) ? meta.scenes : [];
          freshScenes.forEach(function (scene) {
            var idx = getSceneIndexById(scene.id);
            if (idx < 0) return;
            sceneModels[idx].prompt = typeof scene.prompt === 'string' ? scene.prompt : '';
            sceneModels[idx].scriptText = typeof scene.scriptText === 'string' ? scene.scriptText : '';
            sceneModels[idx].audioObjectKey = typeof scene.audioObjectKey === 'string' ? scene.audioObjectKey : '';
            sceneModels[idx].audioDurationMs = Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0;
            sceneModels[idx].voiceName = typeof scene.voiceName === 'string' ? scene.voiceName : '';
            sceneModels[idx].voiceStyle = typeof scene.voiceStyle === 'string' ? scene.voiceStyle : '';
          });
          persistMetaToScript();
          if (isEditorOpen) renderEditorList();
        }
      });
      document.addEventListener('keydown', function (event) {
        if (event.key === 'Escape' && isEditorOpen) closeEditor();
      });
      window.__SVGVIDEO_PLAY = startPlayback;
      window.__SVGVIDEO_STOP = stopPlayback;
      window.__SVGVIDEO_OPEN_EDITOR = openEditor;
      window.__SVGVIDEO_CLOSE_EDITOR = closeEditor;
      applyEditorHeight(editorHeightVh);
      renderStatus();
      updatePlayButton();
      applyHostCaps();
      clearEditorDirty();
      applyI18nTexts();
      applySceneState();
      if (autoplayFromFirstScene && sceneModels.length) {
        state.sceneId = sceneModels[0].id;
        state.step = 0;
        state.direction = 1;
        applySceneState();
        startPlayback();
      }
    })();
  </script>
</body>
</html>10:T3489,<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Python 异常处理原理可视化</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
    <script src="https://unpkg.com/lucide@latest"></script>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;700&family=Noto+Sans+SC:wght@400;700&display=swap');

        :root {
            --bg: #0F172A;
            --code-bg: #1E293B;
            --primary: #38BDF8;
            --accent-red: #EF4444;
            --accent-green: #22C55E;
            --accent-orange: #FB923C;
            --text-main: #F8FAFC;
            --text-dim: #94A3B8;
            --keyword: #F472B6;
            --comment: #64748B;
        }

        body, html {
            margin: 0; padding: 0; width: 100%; height: 100%;
            background-color: var(--bg);
            color: var(--text-main);
            font-family: 'Fira Code', 'Noto Sans SC', monospace;
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        #app-container {
            position: relative;
            width: 1200px;
            height: 700px;
            overflow: hidden;
        }

        /* 背景装饰 */
        .grid-bg {
            position: absolute;
            width: 100%;
            height: 100%;
            background-image: linear-gradient(rgba(56, 189, 248, 0.05) 1px, transparent 1px),
                              linear-gradient(90deg, rgba(56, 189, 248, 0.05) 1px, transparent 1px);
            background-size: 40px 40px;
            z-index: 0;
        }

        .svg-canvas {
            width: 100%;
            height: 100%;
            position: absolute;
            top: 0;
            left: 0;
            z-index: 10;
        }

        /* 样式定义 */
        .code-block {
            fill: var(--code-bg);
            stroke: #334155;
            stroke-width: 1;
            rx: 8;
        }

        .line-highlight {
            fill: rgba(56, 189, 248, 0.15);
            opacity: 0;
        }

        .keyword { fill: var(--keyword); font-weight: bold; }
        .code-text { fill: var(--text-main); font-size: 18px; }
        .comment { fill: var(--comment); font-size: 14px; font-style: italic; }
        .exception-name { fill: var(--accent-red); font-weight: bold; }
        
        .status-panel {
            fill: #111827;
            stroke: #334155;
            stroke-width: 2;
            rx: 12;
        }

        .data-package {
            filter: drop-shadow(0 0 8px var(--primary));
        }

        .subtitles-box {
            position: absolute;
            bottom: 40px;
            left: 50%;
            transform: translateX(-50%);
            width: 800px;
            text-align: center;
            background: rgba(15, 23, 42, 0.8);
            backdrop-filter: blur(8px);
            padding: 20px;
            border-radius: 12px;
            border-bottom: 3px solid var(--primary);
            z-index: 20;
        }

        .subtitles-text {
            font-size: 22px;
            color: var(--text-main);
            margin: 0;
        }

        #flow-indicator {
            stroke-dasharray: 8 4;
            animation: dash 1s linear infinite;
        }

        @keyframes dash {
            to { stroke-dashoffset: -12; }
        }
    </style>
</head>
<body>

<div id="app-container">
    <div class="grid-bg"></div>
    
    <svg class="svg-canvas" viewBox="0 0 1200 700">
        <defs>
            <filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
                <feGaussianBlur stdDeviation="4" result="blur" />
                <feComposite in="SourceGraphic" in2="blur" operator="over" />
            </filter>
            
            <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="0" refY="3.5" orient="auto">
                <polygon points="0 0, 10 3.5, 0 7" fill="var(--primary)" />
            </marker>
        </defs>

        <!-- 标题 -->
        <g transform="translate(50, 50)">
            <text x="0" y="0" fill="var(--primary)" font-size="28" font-weight="700">Python Exception Handling</text>
            <text x="0" y="30" fill="var(--text-dim)" font-size="16">异常处理机制与流程可视化</text>
            <rect x="0" y="45" width="400" height="2" fill="var(--primary)" opacity="0.3" />
        </g>

        <!-- 代码编辑器区域 -->
        <g id="editor-group" transform="translate(50, 120)">
            <rect class="code-block" width="500" height="420" />
            <rect id="line-highlighter" class="line-highlight" width="480" height="30" x="10" y="25" />
            
            <g transform="translate(30, 50)">
                <!-- 代码内容 -->
                <text class="code-text" y="0"><tspan class="keyword">try</tspan>:</text>
                <text class="code-text" y="35" x="30">result = 10 / n</text>
                <text class="comment" y="55" x="30"># 可能抛出除零异常的操作</text>

                <text class="code-text" y="100"><tspan class="keyword">except</tspan> <tspan class="exception-name">ZeroDivisionError</tspan>:</text>
                <text class="code-text" y="135" x="30">print(<tspan fill="#EAB308">"不能除以零！"</tspan>)</text>

                <text class="code-text" y="180"><tspan class="keyword">except</tspan> <tspan class="exception-name">Exception</tspan> <tspan class="keyword">as</tspan> e:</text>
                <text class="code-text" y="215" x="30">print(<tspan fill="#EAB308">"发生了其他错误"</tspan>)</text>

                <text class="code-text" y="260"><tspan class="keyword">else</tspan>:</text>
                <text class="code-text" y="295" x="30">print(<tspan fill="#EAB308">"计算成功"</tspan>)</text>

                <text class="code-text" y="340"><tspan class="keyword">finally</tspan>:</text>
                <text class="code-text" y="375" x="30">print(<tspan fill="#EAB308">"清理并退出"</tspan>)</text>
            </g>
        </g>

        <!-- 逻辑流程演示区 -->
        <g id="logic-group" transform="translate(620, 120)">
            <rect class="status-panel" width="530" height="420" />
            
            <!-- 流程节点 -->
            <g id="nodes">
                <circle id="node-try" cx="100" cy="60" r="25" fill="var(--code-bg)" stroke="var(--primary)" stroke-width="2" />
                <text x="100" y="65" text-anchor="middle" fill="var(--text-main)" font-size="12">TRY</text>

                <circle id="node-error" cx="265" cy="160" r="30" fill="var(--code-bg)" stroke="var(--accent-red)" stroke-width="2" opacity="0.3" />
                <path id="error-icon" d="M265 145 L265 165 M265 175 L265 175" stroke="var(--accent-red)" stroke-width="4" stroke-linecap="round" opacity="0" />
                <text x="265" y="210" text-anchor="middle" fill="var(--accent-red)" font-size="12" font-weight="bold">EXCEPTION!</text>

                <rect id="node-except" x="380" y="135" width="100" height="50" rx="5" fill="var(--code-bg)" stroke="var(--accent-orange)" stroke-width="2" />
                <text x="430" y="165" text-anchor="middle" fill="var(--text-main)" font-size="12">EXCEPT</text>

                <rect id="node-else" x="50" y="250" width="100" height="50" rx="5" fill="var(--code-bg)" stroke="var(--accent-green)" stroke-width="2" />
                <text x="100" y="280" text-anchor="middle" fill="var(--text-main)" font-size="12">ELSE</text>

                <rect id="node-finally" x="215" y="340" width="100" height="50" rx="5" fill="var(--code-bg)" stroke="var(--primary)" stroke-width="2" />
                <text x="265" y="370" text-anchor="middle" fill="var(--text-main)" font-size="12">FINALLY</text>
            </g>

            <!-- 路径连接线 -->
            <g id="paths" opacity="0.4">
                <path id="path-success" d="M100 85 L100 250" stroke="var(--accent-green)" stroke-width="2" fill="none" marker-end="url(#arrowhead)" />
                <path id="path-to-error" d="M125 60 L235 145" stroke="var(--accent-red)" stroke-width="2" fill="none" marker-end="url(#arrowhead)" />
                <path id="path-to-except" d="M295 160 L380 160" stroke="var(--accent-orange)" stroke-width="2" fill="none" marker-end="url(#arrowhead)" />
                <path id="path-except-to-finally" d="M430 185 L430 365 L315 365" stroke="var(--accent-orange)" stroke-width="2" fill="none" marker-end="url(#arrowhead)" />
                <path id="path-else-to-finally" d="M100 300 L100 365 L215 365" stroke="var(--accent-green)" stroke-width="2" fill="none" marker-end="url(#arrowhead)" />
            </g>

            <!-- 运行中的数据包 (动画主体) -->
            <g id="data-package" opacity="0">
                <circle r="12" fill="var(--primary)" filter="url(#glow)" />
                <path d="M-5 -2 L0 3 L5 -2" stroke="white" stroke-width="2" fill="none" />
            </g>
        </g>
    </svg>

    <div class="subtitles-box">
        <p id="subtitles" class="subtitles-text">准备演示 Python 异常处理机制...</p>
    </div>
</div>

<script>
    const sub = document.getElementById('subtitles');
    const highlighter = document.getElementById('line-highlighter');
    const dataPkg = document.getElementById('data-package');
    const tl = gsap.timeline({ repeat: -1 });

    function moveHighlighter(y) {
        return { y: y, opacity: 1, duration: 0.4, ease: "power2.inOut" };
    }

    function setSub(text) {
        sub.innerText = text;
    }

    // 动画序列定义
    tl.addLabel("start")
      // 1. 初始化
      .to(dataPkg, { opacity: 0, duration: 0 })
      .call(() => setSub("场景一：正常执行流 (No Exception)"))
      
      // 2. 进入 Try
      .to(highlighter, moveHighlighter(25))
      .to(dataPkg, { opacity: 1, x: 100, y: 60, duration: 0.5 })
      .call(() => setSub("程序进入 try 代码块，尝试执行敏感操作"))
      
      .to(highlighter, moveHighlighter(60))
      .to("#node-try", { scale: 1.2, strokeWidth: 4, duration: 0.3 })
      .to("#node-try", { scale: 1, strokeWidth: 2, duration: 0.3 })
      
      // 3. 正常路径至 Else
      .call(() => setSub("操作成功，没有异常发生，直接跳过所有 except"))
      .to(dataPkg, { 
          motionPath: {
              path: "#path-success",
              autoRotate: true
          }, 
          duration: 1.5,
          ease: "power1.inOut"
      })
      .to(highlighter, moveHighlighter(285))
      .to("#node-else", { backgroundColor: "var(--accent-green)", duration: 0.3 })
      .call(() => setSub("执行 else 块：仅在没有发生异常时运行"))
      
      // 4. 进入 Finally
      .to(dataPkg, { 
          motionPath: {
              path: "#path-else-to-finally",
              autoRotate: true
          }, 
          duration: 1.2 
      })
      .to(highlighter, moveHighlighter(365))
      .to("#node-finally", { strokeWidth: 4, duration: 0.3 })
      .call(() => setSub("最后执行 finally 块：无论是否出错都会执行"))
      .to(dataPkg, { opacity: 0, scale: 2, duration: 0.5 })
      .to("#node-finally", { strokeWidth: 2, duration: 0.1 })
      .to("#node-else", { backgroundColor: "transparent", duration: 0.1 })

      .to({}, { duration: 1.5 }) // 停顿

      // 5. 异常流
      .addLabel("error-scenario")
      .call(() => setSub("场景二：触发特定异常 (ZeroDivisionError)"))
      .to(highlighter, moveHighlighter(25))
      .to(dataPkg, { opacity: 1, x: 100, y: 60, scale: 1, duration: 0.5 })
      
      .to(highlighter, moveHighlighter(60))
      .call(() => setSub("糟糕！执行 10 / 0 触发了除零异常"))
      
      // 6. 抛出异常
      .to(dataPkg, { 
          motionPath: { path: "#path-to-error" }, 
          duration: 0.8,
          fill: "var(--accent-red)"
      })
      .to("#node-error", { opacity: 1, scale: 1.2, duration: 0.3 })
      .to("#error-icon", { opacity: 1, duration: 0.2 })
      
      // 7. 匹配 Except
      .call(() => setSub("Python 停止 try 中的后续代码，开始在 except 中寻找匹配项"))
      .to(dataPkg, { 
          motionPath: { path: "#path-to-except" }, 
          duration: 0.6 
      })
      .to(highlighter, moveHighlighter(125))
      .to("#node-except", { strokeWidth: 4, duration: 0.3 })
      .call(() => setSub("匹配到 ZeroDivisionError，执行对应的异常处理逻辑"))
      
      // 8. 异常处理后进入 Finally
      .to(dataPkg, { 
          motionPath: { path: "#path-except-to-finally" }, 
          duration: 1.5 
      })
      .to(highlighter, moveHighlighter(365))
      .to("#node-finally", { strokeWidth: 4, duration: 0.3 })
      .call(() => setSub("注意：发生异常时 else 会被跳过，但 finally 依然执行"))
      
      .to(dataPkg, { opacity: 0, scale: 2, duration: 0.5 })
      .to("#node-error", { opacity: 0.3, scale: 1, duration: 0.3 })
      .to("#error-icon", { opacity: 0, duration: 0.1 })
      .to("#node-except", { strokeWidth: 2, duration: 0.1 })
      .to("#node-finally", { strokeWidth: 2, duration: 0.1 })

      .to({}, { duration: 2 }); // 循环等待

    // 初始化 Lucide 图标 (如果需要)
    lucide.createIcons();

</script>
</body>
</html>11:T22cf9,<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>腾讯公司发展历程：连接的演变</title>
  <style>
    @font-face {
      font-family: "SVGVideoAlimamaShuHei";
      src:
        url("/fonts/AlimamaShuHeiTi-Bold.woff2") format("woff2"),
        url("/fonts/AlimamaShuHeiTi-Bold.woff") format("woff"),
        url("/fonts/AlimamaShuHeiTi-Bold.ttf") format("truetype"),
        local("Alimama ShuHeiTi Bold"),
        local("Alimama ShuHeiTi"),
        local("AlimamaShuHeiTi-Bold"),
        local("AlimamaShuHeiTi");
      font-display: swap;
      font-weight: 700;
      font-style: normal;
    }
    :root {
      color-scheme: dark;
      --bg: #202020;
      --fg: #e2e8f0;
      --muted: #94a3b8;
      --card: rgba(255, 255, 255, 0.05);
      --border: rgba(255, 255, 255, 0.12);
      --sv-editor-height: 50vh;
      --sv-font-display-cn: "SVGVideoAlimamaShuHei", "Alimama ShuHeiTi", "AlimamaShuHeiTi-Bold", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
      --sv-font-body-cn: "SVGVideoAlimamaShuHei", "Alimama ShuHeiTi", "AlimamaShuHeiTi-Bold", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
      --sv-font-mono: "SFMono-Regular", "JetBrains Mono", "Fira Code", "Courier New", monospace;
    }
    * { box-sizing: border-box; }
    html, body {
      margin: 0; width: 100%; height: 100%; overflow: hidden;
      background: var(--bg);
      color: var(--fg);
      font-family: var(--sv-font-body-cn);
    }
    #app { width: 100%; height: 100%; display: flex; flex-direction: column; }
    #viewport { position: relative; flex: 1; min-height: 0; overflow: hidden; }
    #stage { position: relative; width: 100%; height: 100%; overflow: hidden; }
    .scene {
      position: absolute; inset: 0; overflow: hidden;
      opacity: 0; pointer-events: none;
      transform: translateX(var(--scene-enter-offset, 56px)) scale(0.96);
      filter: blur(10px);
      transition: opacity .55s cubic-bezier(.22,1,.36,1), transform .55s cubic-bezier(.22,1,.36,1), filter .45s ease;
      will-change: opacity, transform, filter;
      z-index: 1;
    }
    .scene.scene-active {
      opacity: 1; pointer-events: auto; transform: translateX(0) scale(1); filter: blur(0px); z-index: 3;
    }
    .scene.scene-exit {
      opacity: 0; pointer-events: none;
      transform: translateX(var(--scene-exit-offset, -56px)) scale(0.96);
      filter: blur(10px); z-index: 2;
    }
    .scene-placeholder {
      height: 100%; border: 1px dashed var(--border); border-radius: 20px; background: var(--card);
      display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: var(--muted);
    }
    .sv-scene-root { width: 100%; height: 100%; position: relative; overflow: hidden; }
    .scene-placeholder-title { font-size: 28px; color: var(--fg); font-weight: 700; }
    [data-step] { transition: opacity .35s ease, transform .35s ease, filter .35s ease; }
    #sv-controls {
      background: rgba(19, 19, 19, 0.95);
      border-top: 1px solid rgba(255,255,255,0.08);
      padding: 8px 12px 10px;
      display: flex;
      flex-direction: column;
      gap: 8px;
      backdrop-filter: blur(8px);
      flex-shrink: 0;
    }
    .sv-progress-wrap {
      position: relative;
      height: 22px;
      display: flex;
      align-items: center;
      cursor: pointer;
    }
    .sv-progress-track {
      width: 100%;
      height: 4px;
      border-radius: 999px;
      background: rgba(120, 120, 120, 0.55);
      position: relative;
      overflow: hidden;
    }
    .sv-progress-fill {
      position: absolute;
      left: 0;
      top: 0;
      bottom: 0;
      width: 0%;
      border-radius: 999px;
      background: linear-gradient(90deg, #f97316, #fb923c);
      transition: width 220ms ease;
    }
    .sv-progress-thumb {
      position: absolute;
      top: 50%;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      background: #fff;
      transform: translate(-50%, -50%);
      box-shadow: 0 0 0 1px rgba(0,0,0,0.28);
      pointer-events: none;
    }
    .sv-toolbar {
      display: grid;
      grid-template-columns: 1fr auto 1fr;
      align-items: center;
      gap: 8px;
      min-height: 30px;
    }
    .sv-toolbar-left {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      min-width: 0;
    }
    .sv-toolbar-title {
      font-size: 11px;
      color: #a8b0bb;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-expand-btn {
      width: 20px;
      height: 20px;
      border: none;
      border-radius: 6px;
      background: rgba(255,255,255,0.08);
      color: #cbd5e1;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      flex: 0 0 auto;
      transition: background 140ms ease, color 140ms ease, transform 120ms ease;
    }
    .sv-expand-btn:hover {
      background: rgba(255,255,255,0.15);
      color: #f8fafc;
    }
    .sv-expand-btn:active {
      transform: scale(0.94);
    }
    body:not(.sv-host-can-edit-panel) .sv-expand-btn {
      display: none;
    }
    .sv-play-btn {
      width: 28px;
      height: 28px;
      border: none;
      border-radius: 999px;
      color: #fff;
      background: #f97316;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: transform 120ms ease, background 160ms ease;
    }
    .sv-play-btn:hover { background: #fb923c; }
    .sv-play-btn:active { transform: scale(0.94); }
    .sv-play-btn:disabled { opacity: 0.45; cursor: not-allowed; }
    .sv-status {
      text-align: right;
      font-size: 11px;
      color: #8f98a5;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-scene-grid {
      display: flex;
      align-items: stretch;
      gap: 6px;
      flex-wrap: nowrap;
      overflow: hidden;
    }
    .scene-chip {
      position: relative;
      width: 100%;
      border: none;
      border-bottom: 2px solid transparent;
      border-radius: 8px;
      background: rgba(255,255,255,0.06);
      color: #a3a3a3;
      padding: 7px 6px;
      text-align: center;
      font-size: 11px;
      line-height: 1.1;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      cursor: pointer;
      transition: transform 140ms ease, color 160ms ease, background 160ms ease, border-color 160ms ease;
    }
    .scene-chip-label {
      display: block;
      width: 100%;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .scene-chip-wrap {
      position: relative;
      flex: 1 1 0;
      min-width: 0;
    }
    .scene-chip-retry {
      position: absolute;
      top: 50%;
      right: 4px;
      transform: translateY(-50%);
      width: 24px;
      height: 24px;
      border: none;
      border-radius: 999px;
      background: #f97316;
      color: #fff;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
      opacity: 0;
      pointer-events: none;
      transition: opacity 160ms ease;
      cursor: pointer;
    }
    body.sv-host-can-retry .scene-chip-wrap:hover .scene-chip-retry {
      opacity: 1;
      pointer-events: auto;
    }
    .scene-chip-retry:disabled {
      opacity: 1;
      pointer-events: none;
      background: #f97316;
    }
    .scene-chip-retry-icon {
      width: 18px;
      height: 18px;
      display: block;
    }
    .scene-chip-retry-spinner {
      width: 14px;
      height: 14px;
      aspect-ratio: 1 / 1;
      border: 2px solid #ffffff;
      border-top-color: transparent;
      border-radius: 999px;
      box-sizing: border-box;
      animation: sceneChipSpin 1s linear infinite;
      display: block;
      flex: 0 0 auto;
    }
    @keyframes sceneChipSpin {
      from { transform: rotate(0deg); }
      to { transform: rotate(360deg); }
    }
    .scene-chip:hover { transform: scale(1.02); }
    .scene-chip.is-active {
      color: #fb923c;
      border-bottom-color: #fb923c;
      background: linear-gradient(135deg, rgba(249,115,22,0.2), rgba(168,85,247,0.2));
    }
    .scene-chip.is-failed {
      color: #fca5a5;
      border-bottom-color: rgba(239,68,68,0.95);
      background: rgba(239,68,68,0.12);
    }
    .scene-chip.is-generating {
      color: #fcd34d;
      background: rgba(245,158,11,0.11);
    }
    .sv-editor-overlay {
      position: relative;
      width: 100%;
      height: 0;
      z-index: 40;
      pointer-events: none;
      overflow: hidden;
      transition: height 260ms cubic-bezier(.22,1,.36,1);
    }
    .sv-editor-backdrop {
      position: absolute;
      inset: auto 0 0 0;
      height: 100%;
      background: rgba(0, 0, 0, 0.45);
      opacity: 0;
      transition: opacity 220ms ease;
    }
    .sv-editor-sheet {
      position: absolute;
      left: 0;
      right: 0;
      bottom: 0;
      height: 100%;
      background: rgba(16, 16, 16, 0.96);
      border-top: 1px solid rgba(255,255,255,0.12);
      box-shadow: 0 -14px 30px rgba(0,0,0,0.45);
      transform: translateY(102%);
      transition: transform 260ms cubic-bezier(.22,1,.36,1);
      display: flex;
      flex-direction: column;
    }
    .sv-editor-overlay.is-open {
      pointer-events: auto;
      height: var(--sv-editor-height, 50vh);
    }
    .sv-editor-overlay.is-open .sv-editor-backdrop {
      opacity: 1;
    }
    .sv-editor-overlay.is-open .sv-editor-sheet {
      transform: translateY(0);
    }
    .sv-editor-resize-handle {
      width: 100%;
      height: 14px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: ns-resize;
      flex: 0 0 auto;
      touch-action: none;
    }
    .sv-editor-resize-handle::before {
      content: "";
      width: 52px;
      height: 4px;
      border-radius: 999px;
      background: rgba(148, 163, 184, 0.7);
    }
    .sv-editor-header {
      padding: 10px 12px;
      border-bottom: 1px solid rgba(255,255,255,0.1);
      display: grid;
      grid-template-columns: 1fr auto;
      align-items: center;
      gap: 8px;
    }
    .sv-editor-header-title {
      color: #f1f5f9;
      font-size: 13px;
      font-weight: 600;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-editor-actions {
      display: inline-flex;
      align-items: center;
      gap: 6px;
    }
    .sv-editor-btn {
      border: none;
      border-radius: 8px;
      cursor: pointer;
      font-size: 12px;
      line-height: 1;
      padding: 7px 10px;
      color: #e2e8f0;
      background: rgba(255,255,255,0.1);
      transition: background 120ms ease;
    }
    .sv-editor-btn:hover {
      background: rgba(255,255,255,0.18);
    }
    .sv-editor-btn.is-primary {
      color: #fff;
      background: #f97316;
    }
    .sv-editor-btn.is-primary:hover {
      background: #fb923c;
    }
    .sv-editor-list {
      flex: 1;
      min-height: 0;
      overflow: auto;
      padding: 10px 12px 14px;
      display: grid;
      gap: 10px;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      align-items: start;
      align-content: start;
    }
    .sv-editor-item {
      border: 1px solid rgba(255,255,255,0.12);
      border-radius: 10px;
      background: rgba(255,255,255,0.03);
      padding: 10px;
      display: grid;
      grid-template-rows: auto auto auto;
      gap: 10px;
      align-content: start;
      cursor: pointer;
    }
    .sv-editor-item.is-active {
      border-color: rgba(249,115,22,0.65);
      box-shadow: inset 0 0 0 1px rgba(249,115,22,0.28);
    }
    .sv-editor-item-head {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 8px;
      min-height: 30px;
    }
    .sv-editor-item-title {
      border: none;
      border-radius: 8px;
      color: #fb923c;
      background: rgba(255,255,255,0.08);
      font-size: 12px;
      font-weight: 600;
      padding: 6px 8px;
      cursor: pointer;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      text-align: left;
    }
    .sv-editor-item-title:hover {
      background: rgba(255,255,255,0.14);
    }
    .sv-editor-status {
      color: #94a3b8;
      font-size: 11px;
      white-space: nowrap;
    }
    .sv-editor-status-wrap {
      display: inline-flex;
      align-items: center;
      gap: 6px;
    }
    .scene-chip-retry.sv-editor-retry {
      position: static;
      transform: none;
      opacity: 1;
      pointer-events: auto;
      width: 24px;
      height: 24px;
      flex: 0 0 auto;
    }
    .sv-editor-field {
      display: grid;
      gap: 6px;
    }
    .sv-editor-label {
      color: #a3a3a3;
      font-size: 11px;
      font-weight: 700;
    }
    .sv-editor-textarea {
      width: 100%;
      border-radius: 8px;
      border: 1px solid rgba(255,255,255,0.14);
      background: rgba(0,0,0,0.24);
      color: #f1f5f9;
      font-size: 12px;
      line-height: 1.45;
      padding: 8px 9px;
      resize: none;
      min-height: 110px;
      height: 110px;
    }
    .sv-editor-textarea[data-field="scriptText"] {
      min-height: 84px;
    }
    .sv-editor-textarea:focus {
      outline: none;
      border-color: rgba(249,115,22,0.7);
      box-shadow: 0 0 0 2px rgba(249,115,22,0.18);
    }
    body.sv-theme-light .sv-editor-textarea {
      border-color: rgba(15,23,42,0.18);
      background: rgba(248,250,252,0.92);
      color: #0f172a;
    }
    body.sv-theme-light .sv-editor-textarea:focus {
      border-color: rgba(249,115,22,0.72);
      box-shadow: 0 0 0 2px rgba(249,115,22,0.2);
    }
    .sv-editor-script-view {
      width: 100%;
      color: #e2e8f0;
      font-size: 12px;
      line-height: 1.5;
      white-space: pre-wrap;
      word-break: break-word;
      min-height: 84px;
      max-height: 84px;
      overflow: auto;
    }
    .sv-editor-save-tip {
      color: #fbbf24;
      font-size: 11px;
      opacity: 0;
      transition: opacity 140ms ease;
      justify-self: end;
    }
    .sv-editor-save-tip.is-visible {
      opacity: 1;
    }
    body.sv-theme-light .sv-editor-backdrop {
      background: rgba(15, 23, 42, 0.2);
    }
    body.sv-theme-light .sv-editor-sheet {
      background: rgba(255, 255, 255, 0.98);
      border-top-color: rgba(15, 23, 42, 0.12);
      box-shadow: 0 -14px 30px rgba(15, 23, 42, 0.16);
    }
    body.sv-theme-light .sv-editor-header {
      border-bottom-color: rgba(15, 23, 42, 0.1);
    }
    body.sv-theme-light .sv-editor-header-title {
      color: #0f172a;
    }
    body.sv-theme-light .sv-editor-btn {
      color: #334155;
      background: rgba(15, 23, 42, 0.08);
    }
    body.sv-theme-light .sv-editor-btn:hover {
      background: rgba(15, 23, 42, 0.14);
    }
    body.sv-theme-light .sv-editor-btn.is-primary {
      color: #ffffff;
      background: #f97316;
    }
    body.sv-theme-light .sv-editor-btn.is-primary:hover {
      background: #fb923c;
    }
    body.sv-theme-light .sv-editor-item {
      border-color: rgba(15, 23, 42, 0.12);
      background: rgba(248, 250, 252, 0.95);
    }
    body.sv-theme-light .sv-editor-item.is-active {
      border-color: rgba(249,115,22,0.72);
      box-shadow: inset 0 0 0 1px rgba(249,115,22,0.3);
    }
    body.sv-theme-light .sv-editor-item-title {
      color: #ea580c;
      background: rgba(249, 115, 22, 0.12);
    }
    body.sv-theme-light .sv-editor-item-title:hover {
      background: rgba(249, 115, 22, 0.18);
    }
    body.sv-theme-light .sv-editor-status {
      color: #64748b;
    }
    body.sv-theme-light .sv-editor-label {
      color: #475569;
    }
    body.sv-theme-light .sv-editor-script-view {
      color: #334155;
    }
    body.sv-theme-light .sv-editor-save-tip {
      color: #c2410c;
    }
    body.sv-editor-open #viewport {
      flex: 1 1 calc(100vh - var(--sv-editor-height, 50vh));
      min-height: 0;
    }
    body.sv-editor-open #sv-controls {
      display: none;
    }
    body.sv-recording .sv-toolbar,
    body.sv-recording .sv-scene-grid {
      display: none;
    }
    body.sv-recording #sv-controls {
      display: none;
    }
    body.sv-theme-light .sv-editor-list,
    body.sv-theme-light .sv-editor-script-view,
    body.sv-theme-light .sv-editor-textarea {
      scrollbar-color: rgba(148, 163, 184, 0.85) rgba(226, 232, 240, 0.85);
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar {
      width: 10px;
      height: 10px;
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-track,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-track,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-track {
      background: rgba(226, 232, 240, 0.85);
      border-radius: 999px;
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-thumb,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-thumb,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-thumb {
      background: rgba(148, 163, 184, 0.85);
      border-radius: 999px;
      border: 2px solid rgba(226, 232, 240, 0.85);
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-thumb:hover,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-thumb:hover,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-thumb:hover {
      background: rgba(100, 116, 139, 0.95);
    }
/* scene-01 */
.sv-scene-root-scene-01 .s-scene-01-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background-color: #1B1B1B;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-family: var(--sv-font-body-cn);
  color: #FFFFFF;
}.sv-scene-root-scene-01 .tech-grid{
  position: absolute;
  inset: 0;
  background-image: 
    linear-gradient(to right, rgba(255, 255, 255, 0.03) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
  background-size: 40px 40px;
  z-index: 1;
}.sv-scene-root-scene-01 .fluid-bg{
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 50%, rgba(245, 53, 1, 0.05) 0%, transparent 70%);
  filter: blur(40px);
  animation: fluid-pulse 8s ease-in-out infinite alternate;
  z-index: 1;
}@keyframes fluid-pulse{
  from { transform: scale(1) translate(0, 0); }
  to { transform: scale(1.2) translate(5%, 5%); }
}.sv-scene-root-scene-01 .focus-frame{
  position: absolute;
  width: 280px;
  height: 280px;
  z-index: 2;
  transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
  opacity: 0;
  transform: scale(1.2);
}.sv-scene-root-scene-01 .focus-frame[data-step-active="true"]{
  opacity: 1;
  transform: scale(1);
}.sv-scene-root-scene-01 .corner{
  position: absolute;
  width: 20px;
  height: 20px;
  border: 2px solid #F53501;
}.sv-scene-root-scene-01 .top-left{ top: 0; left: 0; border-right: 0; border-bottom: 0; }.sv-scene-root-scene-01 .top-right{ top: 0; right: 0; border-left: 0; border-bottom: 0; }.sv-scene-root-scene-01 .bottom-left{ bottom: 0; left: 0; border-right: 0; border-top: 0; }.sv-scene-root-scene-01 .bottom-right{ bottom: 0; right: 0; border-left: 0; border-top: 0; }.sv-scene-root-scene-01 .main-content{
  position: relative;
  z-index: 10;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
}.sv-scene-root-scene-01 .logo-container{
  position: relative;
  width: 120px;
  height: 120px;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: all 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}.sv-scene-root-scene-01 .logo-container[data-step-active="true"]{
  opacity: 1;
  transform: scale(1.1);
}.sv-scene-root-scene-01 .tencent-logo{
  font-size: 80px;
  color: #FFFFFF;
  filter: drop-shadow(0 0 20px rgba(245, 53, 1, 0.3));
}.sv-scene-root-scene-01 .logo-glow{
  position: absolute;
  width: 100%;
  height: 100%;
  background: #F53501;
  filter: blur(40px);
  opacity: 0.15;
  z-index: -1;
}.sv-scene-root-scene-01 .text-glass-panel{
  padding: 16px 24px;
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 4px;
  opacity: 0;
  transform: translateY(20px);
  transition: all 0.6s ease-out;
}.sv-scene-root-scene-01 .text-glass-panel[data-step-active="true"]{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-01 .shimmer-text{
  font-family: var(--sv-font-display-cn);
  font-size: 24px;
  font-weight: 900;
  margin: 0;
  background: linear-gradient(90deg, #FFFFFF 0%, #F53501 50%, #FFFFFF 100%);
  background-size: 200% auto;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: shimmer 3s linear infinite;
}@keyframes shimmer{
  to { background-position: 200% center; }
}.sv-scene-root-scene-01 .accent-bar{
  width: 40px;
  height: 3px;
  background: #F53501;
  margin: 8px auto 0;
}.sv-scene-root-scene-01 .tech-metadata{
  position: absolute;
  bottom: 60px;
  display: flex;
  align-items: center;
  gap: 20px;
  opacity: 0;
  transition: opacity 1s ease;
}.sv-scene-root-scene-01 .tech-metadata[data-step-active="true"]{
  opacity: 0.6;
}.sv-scene-root-scene-01 .meta-item{
  display: flex;
  flex-direction: column;
  align-items: center;
}.sv-scene-root-scene-01 .meta-item .label{
  font-family: var(--sv-font-mono);
  font-size: 10px;
  color: #F53501;
  letter-spacing: 2px;
}.sv-scene-root-scene-01 .meta-item .value{
  font-family: var(--sv-font-mono);
  font-size: 14px;
  font-weight: bold;
}.sv-scene-root-scene-01 .meta-line{
  width: 1px;
  height: 30px;
  background: rgba(255, 255, 255, 0.2);
}

/* scene-02 */
.sv-scene-root-scene-02 .s-scene-02-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background-color: #1B1B1B;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-family: var(--sv-font-body-cn);
}.sv-scene-root-scene-02 .tech-grid{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
  background-size: 40px 40px;
  z-index: 1;
}.sv-scene-root-scene-02 .retro-window{
  position: relative;
  z-index: 10;
  width: 320px;
  height: 480px;
  background: #C0C0C0;
  border: 3px solid #FFFFFF;
  border-right-color: #808080;
  border-bottom-color: #808080;
  box-shadow: 10px 10px 0px rgba(0, 0, 0, 0.3);
  display: flex;
  flex-direction: column;
  opacity: 0;
  transform: translateY(20px);
  transition: all 0.6s cubic-bezier(0.23, 1, 0.32, 1);
}.sv-scene-root-scene-02 .retro-window[data-step-active="true"]{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-02 .window-header{
  background: linear-gradient(90deg, #000080, #1084D0);
  padding: 4px 8px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: #FFF;
  font-family: var(--sv-font-mono);
  font-size: 12px;
  font-weight: bold;
}.sv-scene-root-scene-02 .win-btn{
  width: 16px;
  height: 14px;
  background: #C0C0C0;
  border: 1px solid #FFF;
  border-right-color: #000;
  border-bottom-color: #000;
  color: #000;
  font-size: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-left: 2px;
}.sv-scene-root-scene-02 .window-body{
  flex-grow: 1;
  background: #000;
  margin: 4px;
  padding: 15px;
  position: relative;
  overflow: hidden;
  color: #FFF;
  font-family: var(--sv-font-mono);
  border: 2px inset #808080;
}.sv-scene-root-scene-02 .terminal-text{
  font-size: 14px;
  line-height: 1.6;
  white-space: pre-wrap;
  color: #F53501;
}.sv-scene-root-scene-02 .hero-penguin-container{
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: scale(0.5);
  transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}.sv-scene-root-scene-02 .hero-penguin-container[data-step-active="true"]{
  opacity: 1;
  transform: scale(1);
}.sv-scene-root-scene-02 .penguin-icon{
  font-size: 120px;
  color: #FFF;
  z-index: 5;
}.sv-scene-root-scene-02 .scarf-accent{
  position: absolute;
  width: 60px;
  height: 10px;
  background: #F53501;
  top: 60%;
  left: 50%;
  transform: translateX(-50%);
  border-radius: 5px;
  box-shadow: 0 0 15px #F53501;
  z-index: 6;
}.sv-scene-root-scene-02 .penguin-glow{
  position: absolute;
  width: 140px;
  height: 140px;
  background: #F53501;
  filter: blur(40px);
  opacity: 0.4;
  border-radius: 50%;
}.sv-scene-root-scene-02 .bubble-burst-layer{
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 20;
}.sv-scene-root-scene-02 .chat-bubble{
  position: absolute;
  padding: 8px 12px;
  background: #FFF;
  border: 1px solid #F53501;
  border-radius: 12px;
  font-size: 12px;
  color: #1B1B1B;
  opacity: 0;
  animation: bubble-float 2s ease-out forwards;
}@keyframes bubble-float{
  0% { transform: translate(0, 0) scale(0); opacity: 0; }
  20% { opacity: 1; }
  100% { transform: translate(var(--tx), var(--ty)) scale(1); opacity: 0; }
}.sv-scene-root-scene-02 .window-status{
  padding: 4px 8px;
  font-size: 10px;
  color: #000;
  background: #C0C0C0;
  border-top: 1px solid #808080;
  display: flex;
  justify-content: space-between;
}.sv-scene-root-scene-02 .blink-dot{ color: #F53501; animation: blink 1s infinite; }@keyframes blink{ 50% { opacity: 0; } }.sv-scene-root-scene-02 .scene-tag{
  position: absolute;
  top: 10%;
  left: 40px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  opacity: 0;
  transition: all 0.8s ease;
}.sv-scene-root-scene-02 .scene-tag[data-step-active="true"]{ opacity: 1; }.sv-scene-root-scene-02 .tag-year{
  font-family: var(--sv-font-display-cn);
  font-size: 42px;
  color: #F53501;
  line-height: 1;
}.sv-scene-root-scene-02 .tag-line{
  width: 100px;
  height: 2px;
  background: #F53501;
  margin: 10px 0;
}.sv-scene-root-scene-02 .tag-event{
  font-family: var(--sv-font-mono);
  font-size: 12px;
  color: #FFF;
  letter-spacing: 4px;
}

/* scene-03 */
.sv-scene-root-scene-03 .s-scene-03-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background-color: #1B1B1B;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-family: var(--sv-font-body-cn);
}.sv-scene-root-scene-03 .tech-grid{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 30px 30px;
  z-index: 1;
}.sv-scene-root-scene-03 /* Step 0: Chart Animation */
.chart-container{
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 50%;
  z-index: 2;
  opacity: 0;
  transition: opacity 1s ease;
}.sv-scene-root-scene-03 .chart-container[data-step-active="true"]{
  opacity: 1;
}.sv-scene-root-scene-03 .chart-path{
  stroke-dasharray: 1000;
  stroke-dashoffset: 1000;
}.sv-scene-root-scene-03 .chart-container[data-step-active="true"] .chart-path{
  animation: chart-draw 2.5s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}@keyframes chart-draw{
  to { stroke-dashoffset: 0; }
}.sv-scene-root-scene-03 .stat-label{
  position: absolute;
  left: 20px;
  top: 20px;
  color: #F53501;
  font-family: var(--sv-font-mono);
  font-size: 12px;
  letter-spacing: 2px;
  border-left: 2px solid #F53501;
  padding-left: 8px;
}.sv-scene-root-scene-03 /* Step 1: Coin Hero */
.coin-hero{
  position: relative;
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  opacity: 0;
  transform: translateY(-50px) scale(0.8);
  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
}.sv-scene-root-scene-03 .coin-hero[data-step-active="true"]{
  opacity: 1;
  transform: translateY(0) scale(1);
}.sv-scene-root-scene-03 .coin-3d{
  width: 180px;
  height: 180px;
  perspective: 1000px;
  margin-bottom: 24px;
}.sv-scene-root-scene-03 .coin-face{
  width: 100%;
  height: 100%;
  background: linear-gradient(135deg, #FFD700 0%, #B8860B 50%, #FFD700 100%);
  border-radius: 50%;
  padding: 10px;
  box-shadow: 0 20px 40px rgba(0,0,0,0.5), inset 0 0 20px rgba(255,255,255,0.5);
  animation: coin-spin 6s infinite linear;
}.sv-scene-root-scene-03 .coin-inner{
  width: 100%;
  height: 100%;
  border: 4px solid rgba(0,0,0,0.1);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
}.sv-scene-root-scene-03 .stock-symbol{
  font-family: var(--sv-font-display-cn);
  font-size: 24px;
  color: #5C4033;
  font-weight: 900;
  text-shadow: 1px 1px 0px rgba(255,255,255,0.3);
}.sv-scene-root-scene-03 .coin-reflection{
  position: absolute;
  top: -50%;
  left: -50%;
  width: 200%;
  height: 200%;
  background: linear-gradient(45deg, transparent 45%, rgba(255,255,255,0.6) 50%, transparent 55%);
  animation: reflect 3s infinite ease-in-out;
}@keyframes reflect{ 0% { transform: translate(-20%, -20%); } 100% { transform: translate(20%, 20%); } }@keyframes coin-spin{ 0% { transform: rotateY(0deg); } 100% { transform: rotateY(360deg); } }.sv-scene-root-scene-03 .main-title{
  font-family: var(--sv-font-display-cn);
  font-size: 32px;
  color: #FFFFFF;
  text-transform: uppercase;
  letter-spacing: 2px;
}.sv-scene-root-scene-03 /* Step 2: Biz Grid */
.business-grid{
  position: absolute;
  bottom: 12%;
  width: 90%;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  z-index: 15;
}.sv-scene-root-scene-03 .biz-card{
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 16px 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  opacity: 0;
  transform: translateY(20px);
  transition: all 0.5s ease;
  transition-delay: calc(var(--i) * 0.15s);
}.sv-scene-root-scene-03 .business-grid[data-step-active="true"] .biz-card{
  opacity: 1;
  transform: translateY(0);
  border-color: rgba(245, 53, 1, 0.3);
}.sv-scene-root-scene-03 .biz-icon{
  font-size: 28px;
  color: #F53501;
}.sv-scene-root-scene-03 .biz-name{
  font-family: var(--sv-font-display-cn);
  font-size: 16px;
  color: #FFFFFF;
}.sv-scene-root-scene-03 .marker-line{
  position: absolute;
  left: 5%;
  width: 90%;
  height: 1px;
  background: rgba(245, 53, 1, 0.2);
  z-index: 5;
}.sv-scene-root-scene-03 .marker-line.top{ top: 20%; }.sv-scene-root-scene-03 .marker-line.bottom{ bottom: 20%; }

/* scene-04 */
.sv-scene-root-scene-04 .s-scene-04-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background-color: #1B1B1B;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-family: var(--sv-font-body-cn);
}.sv-scene-root-scene-04 .tech-grid{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 40px 40px;
  z-index: 1;
}.sv-scene-root-scene-04 .wechat-wash{
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at center, rgba(7, 193, 96, 0.2) 0%, transparent 70%);
  opacity: 0;
  transition: opacity 1.2s ease;
  z-index: 2;
}.sv-scene-root-scene-04 .wechat-wash[data-step-active="true"]{ opacity: 1; }.sv-scene-root-scene-04 .hero-container{
  position: relative;
  z-index: 10;
  text-align: center;
  opacity: 0;
  transform: scale(0.9);
  transition: all 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}.sv-scene-root-scene-04 .hero-container[data-step-active="true"]{
  opacity: 1;
  transform: scale(1);
}.sv-scene-root-scene-04 .year-tag{
  font-family: var(--sv-font-mono);
  font-size: 14px;
  color: #F53501;
  background: rgba(245, 53, 1, 0.1);
  padding: 2px 10px;
  border: 1px solid #F53501;
  display: inline-block;
  margin-bottom: 20px;
  letter-spacing: 2px;
}.sv-scene-root-scene-04 .logo-box{
  position: relative;
  width: 120px;
  height: 120px;
  margin: 0 auto 30px;
}.sv-scene-root-scene-04 .main-logo{
  font-size: 120px;
  color: #07C160;
  filter: drop-shadow(0 0 20px rgba(7, 193, 96, 0.4));
}.sv-scene-root-scene-04 .logo-glow{
  position: absolute;
  inset: -20px;
  background: radial-gradient(circle, rgba(7, 193, 96, 0.15) 0%, transparent 70%);
  animation: logo-pulse 3s infinite ease-in-out;
}.sv-scene-root-scene-04 .main-title{
  font-family: var(--sv-font-display-cn);
  font-size: 48px;
  color: #FFFFFF;
  margin: 0;
  letter-spacing: 4px;
}.sv-scene-root-scene-04 /* Step 1: Ripple */
.ripple-system{
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  padding-bottom: 25%;
  z-index: 5;
  opacity: 0;
  transition: opacity 0.5s ease;
}.sv-scene-root-scene-04 .ripple-system[data-step-active="true"]{ opacity: 1; }.sv-scene-root-scene-04 .ripple-circle{
  position: absolute;
  top: 50%;
  left: 50%;
  border: 1px solid rgba(7, 193, 96, 0.3);
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(0);
}.sv-scene-root-scene-04 .ripple-system[data-step-active="true"] .ripple-circle{
  animation: ripple-out 4s infinite linear;
}.sv-scene-root-scene-04 .c1{ width: 300px; height: 300px; animation-delay: 0s; }.sv-scene-root-scene-04 .c2{ width: 300px; height: 300px; animation-delay: 1.3s; }.sv-scene-root-scene-04 .c3{ width: 300px; height: 300px; animation-delay: 2.6s; }.sv-scene-root-scene-04 .connection-text{
  font-family: var(--sv-font-display-cn);
  color: #07C160;
  font-size: 20px;
  letter-spacing: 8px;
  text-transform: uppercase;
  opacity: 0.8;
}.sv-scene-root-scene-04 /* Step 2: Ecosystem */
.ecosystem-radial{
  position: absolute;
  inset: 0;
  z-index: 15;
  pointer-events: none;
}.sv-scene-root-scene-04 .eco-item{
  position: absolute;
  top: 50%;
  left: 50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  opacity: 0;
  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
  --dist: 160px;
}.sv-scene-root-scene-04 .ecosystem-radial[data-step-active="true"] .eco-item{
  opacity: 1;
  transform: translate(calc(cos(var(--angle)) * var(--dist) - 50%), calc(sin(var(--angle)) * var(--dist) - 50%));
}.sv-scene-root-scene-04 .eco-icon-wrapper{
  width: 60px;
  height: 60px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(7, 193, 96, 0.4);
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 32px;
  color: #07C160;
  box-shadow: 0 10px 20px rgba(0,0,0,0.3);
  animation: float-breathing 4s infinite ease-in-out;
}.sv-scene-root-scene-04 .eco-label{
  font-size: 14px;
  color: #FFFFFF;
  white-space: nowrap;
  font-weight: 600;
  text-shadow: 0 2px 4px rgba(0,0,0,0.5);
}.sv-scene-root-scene-04 /* Decor Frames */
.focus-frame-top, .sv-scene-root-scene-04 .focus-frame-bottom{
  position: absolute;
  left: 10%;
  width: 80%;
  height: 20px;
  border: 1px solid rgba(245, 53, 1, 0.2);
  z-index: 5;
}.sv-scene-root-scene-04 .focus-frame-top{
  top: 5%;
  border-bottom: none;
}.sv-scene-root-scene-04 .focus-frame-bottom{
  bottom: 5%;
  border-top: none;
}@keyframes logo-pulse{ 0%, 100% { transform: scale(1); opacity: 0.15; } 50% { transform: scale(1.1); opacity: 0.3; } }@keyframes ripple-out{ from { transform: translate(-50%, -50%) scale(0.5); opacity: 1; } to { transform: translate(-50%, -50%) scale(2.5); opacity: 0; } }@keyframes float-breathing{
  0%, 100% { transform: translateY(0); } 
  50% { transform: translateY(-10px); }
}

/* scene-05 */
.sv-scene-root-scene-05 .s-scene-05-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background-color: #1B1B1B;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-family: var(--sv-font-body-cn);
}.sv-scene-root-scene-05 .tech-grid{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
  background-size: 30px 30px;
  z-index: 1;
}.sv-scene-root-scene-05 .blue-neural-wash{
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 50%, rgba(10, 17, 40, 0.8) 0%, transparent 100%);
  opacity: 0;
  transition: opacity 1.5s ease;
  z-index: 2;
}.sv-scene-root-scene-05 .blue-neural-wash[data-step-active="true"]{ opacity: 1; }.sv-scene-root-scene-05 .neural-net-container{
  position: absolute;
  inset: 0;
  z-index: 3;
  opacity: 0;
  transition: opacity 1s ease;
}.sv-scene-root-scene-05 .neural-net-container[data-step-active="true"]{ opacity: 0.6; }.sv-scene-root-scene-05 .neural-svg{
  width: 100%;
  height: 100%;
  filter: drop-shadow(0 0 5px rgba(245, 53, 1, 0.4));
}.sv-scene-root-scene-05 /* Step 1: Cloud Ring */
.cloud-progress-container{
  position: absolute;
  top: 15%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 15px;
  opacity: 0;
  transform: translateY(-50px);
  transition: all 0.8s cubic-bezier(0.23, 1, 0.32, 1);
  z-index: 10;
}.sv-scene-root-scene-05 .cloud-progress-container[data-step-active="true"]{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-05 .frosted-ring{
  position: relative;
  width: 100px;
  height: 100px;
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
}.sv-scene-root-scene-05 .ring-spinner{
  position: absolute;
  inset: -5px;
  border: 2px solid transparent;
  border-top: 2px solid #F53501;
  border-radius: 50%;
  animation: spin 2s linear infinite;
}.sv-scene-root-scene-05 .cloud-icon{
  font-size: 40px;
  color: #FFFFFF;
  filter: drop-shadow(0 0 10px rgba(255, 255, 255, 0.3));
}.sv-scene-root-scene-05 .status-label{
  font-family: var(--sv-font-mono);
  color: #F53501;
  font-size: 10px;
  letter-spacing: 2px;
  font-weight: bold;
}.sv-scene-root-scene-05 /* Step 2: Hero Text */
.hero-content-area{
  position: relative;
  z-index: 20;
  text-align: center;
  opacity: 0;
  transform: scale(0.9);
  transition: all 1s cubic-bezier(0.34, 1.56, 0.64, 1);
}.sv-scene-root-scene-05 .hero-content-area[data-step-active="true"]{
  opacity: 1;
  transform: scale(1);
}.sv-scene-root-scene-05 .vision-title{
  font-family: var(--sv-font-display-cn);
  font-size: 72px;
  color: #FFFFFF;
  margin: 0;
  line-height: 1.2;
  display: flex;
  flex-direction: column;
}.sv-scene-root-scene-05 .glow-text{
  text-shadow: 0 0 20px rgba(255, 255, 255, 0.2);
}.sv-scene-root-scene-05 .glow-text.highlight{
  color: #F53501;
  text-shadow: 0 0 30px rgba(245, 53, 1, 0.6);
  border: 2px solid #F53501;
  padding: 0 10px;
  margin-top: 10px;
}.sv-scene-root-scene-05 .tech-tag-line{
  font-family: var(--sv-font-mono);
  color: rgba(255, 255, 255, 0.4);
  font-size: 14px;
  letter-spacing: 6px;
  margin-top: 20px;
}.sv-scene-root-scene-05 .particle-emitter{
  position: absolute;
  inset: -100px;
  pointer-events: none;
}.sv-scene-root-scene-05 /* Decor elements */
.frame-bracket{
  position: absolute;
  width: 20px;
  height: 20px;
  border: 2px solid #F53501;
  z-index: 50;
}.sv-scene-root-scene-05 .tl{ top: 40px; left: 40px; border-right: none; border-bottom: none; }.sv-scene-root-scene-05 .tr{ top: 40px; right: 40px; border-left: none; border-bottom: none; }.sv-scene-root-scene-05 .bl{ bottom: 40px; left: 40px; border-right: none; border-top: none; }.sv-scene-root-scene-05 .br{ bottom: 40px; right: 40px; border-left: none; border-top: none; }.sv-scene-root-scene-05 .data-stream-side{
  position: absolute;
  right: 10px;
  top: 50%;
  transform: rotate(90deg) translate(-50%, 0);
  font-family: var(--sv-font-mono);
  font-size: 10px;
  color: rgba(245, 53, 1, 0.5);
  letter-spacing: 2px;
}@keyframes spin{ from { transform: rotate(0deg); } to { transform: rotate(360deg); } }.sv-scene-root-scene-05 .particle{
  position: absolute;
  background: #F53501;
  width: 2px;
  height: 2px;
  border-radius: 50%;
  animation: float-up var(--d) linear infinite;
  opacity: 0;
}@keyframes float-up{
  0% { transform: translateY(0); opacity: 0; }
  20% { opacity: 0.8; }
  100% { transform: translateY(-150px); opacity: 0; }
}

/* scene-06 */
.sv-scene-root-scene-06 .s-scene-06-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background-color: #1B1B1B;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  transition: transform 1.2s cubic-bezier(0.7, 0, 0.3, 1), opacity 1.2s ease;
}.sv-scene-root-scene-06 .s-scene-06-wrapper[data-closing="true"]{
  transform: scale(0.9);
  opacity: 0;
}.sv-scene-root-scene-06 .bg-base{
  position: absolute;
  inset: 0;
  background: #1B1B1B;
  z-index: 1;
}.sv-scene-root-scene-06 .bg-gradient-overlay{
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 50%, #FFFFFF 0%, #E6F0FF 40%, #B8D4FF 100%);
  opacity: 0;
  transition: opacity 1.5s cubic-bezier(0.4, 0, 0.2, 1);
  z-index: 2;
}.sv-scene-root-scene-06 .bg-gradient-overlay[data-step-active="true"]{
  opacity: 1;
}.sv-scene-root-scene-06 .tech-grid-closing{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(245, 53, 1, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(245, 53, 1, 0.05) 1px, transparent 1px);
  background-size: 40px 40px;
  z-index: 3;
  opacity: 0.3;
}.sv-scene-root-scene-06 .slogan-container{
  position: relative;
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  opacity: 0;
  transform: translateY(30px);
  transition: all 1s cubic-bezier(0.23, 1, 0.32, 1);
}.sv-scene-root-scene-06 .slogan-container[data-step-active="true"]{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-06 .slogan-line{
  overflow: hidden;
}.sv-scene-root-scene-06 .slogan-text{
  display: block;
  font-family: var(--sv-font-display-cn);
  font-size: 48px;
  color: #1B1B1B;
  letter-spacing: 4px;
  line-height: 1.2;
}.sv-scene-root-scene-06 .slogan-text.highlight{
  color: #F53501;
}.sv-scene-root-scene-06 .slogan-divider{
  width: 40px;
  height: 4px;
  background: #F53501;
  margin: 20px 0;
}.sv-scene-root-scene-06 .anniversary-footer{
  position: absolute;
  bottom: 12%;
  display: flex;
  flex-direction: column;
  align-items: center;
  z-index: 10;
  opacity: 0;
  transform: translateY(20px);
  transition: all 0.8s ease-out;
}.sv-scene-root-scene-06 .anniversary-footer[data-step-active="true"]{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-06 .logo-wrap{
  display: flex;
  align-items: center;
  gap: 15px;
  margin-bottom: 10px;
}.sv-scene-root-scene-06 .tencent-logo{
  font-size: 32px;
  color: #0052D9;
}.sv-scene-root-scene-06 .logo-divider{
  width: 1px;
  height: 20px;
  background: rgba(0, 0, 0, 0.2);
}.sv-scene-root-scene-06 .anniversary-badge{
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}.sv-scene-root-scene-06 .anniversary-badge .num{
  font-family: var(--sv-font-mono);
  font-weight: 900;
  font-size: 24px;
  line-height: 1;
  color: #1B1B1B;
}.sv-scene-root-scene-06 .anniversary-badge .text{
  font-family: var(--sv-font-mono);
  font-size: 8px;
  letter-spacing: 1px;
  color: #666;
}.sv-scene-root-scene-06 .brand-subtext{
  font-family: var(--sv-font-mono);
  font-size: 10px;
  color: rgba(0, 0, 0, 0.4);
  letter-spacing: 2px;
}.sv-scene-root-scene-06 /* Tech Decors */
.frame-bracket{
  position: absolute;
  width: 15px;
  height: 15px;
  border: 1.5px solid #F53501;
  z-index: 20;
  opacity: 0.5;
}.sv-scene-root-scene-06 .tl{ top: 40px; left: 40px; border-right: none; border-bottom: none; }.sv-scene-root-scene-06 .tr{ top: 40px; right: 40px; border-left: none; border-bottom: none; }.sv-scene-root-scene-06 .bl{ bottom: 40px; left: 40px; border-right: none; border-top: none; }.sv-scene-root-scene-06 .br{ bottom: 40px; right: 40px; border-left: none; border-top: none; }.sv-scene-root-scene-06 .scan-line{
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 2px;
  background: linear-gradient(90deg, transparent, #F53501, transparent);
  z-index: 5;
  opacity: 0.1;
  animation: scan 4s linear infinite;
}@keyframes scan{ 0% { top: 0; } 100% { top: 100%; } }
  </style>
</head>
<body data-orientation="portrait">
  <div id="app">
    <div id="viewport">
      <div id="stage">

<section class="scene" data-scene-id="scene-01">
  <div class="sv-scene-root sv-scene-root-scene-01" data-scene-root-id="scene-01">
<div class="s-scene-01-wrapper">
  <div class="tech-grid"></div>
  <div class="fluid-bg"></div>
  
  <div class="focus-frame" data-step="0">
    <div class="corner top-left"></div>
    <div class="corner top-right"></div>
    <div class="corner bottom-left"></div>
    <div class="corner bottom-right"></div>
  </div>

  <div class="main-content">
    <div class="logo-container" data-step="0">
      <iconify-icon icon="simple-icons:tencent" class="tencent-logo"></iconify-icon>
      <div class="logo-glow"></div>
    </div>

    <div class="text-glass-panel" data-step="1">
      <h1 class="shimmer-text">腾讯：连接未来的25年</h1>
      <div class="accent-bar"></div>
    </div>
  </div>

  <div class="tech-metadata" data-step="0">
    <div class="meta-item">
      <span class="label">EST.</span>
      <span class="value">1998</span>
    </div>
    <div class="meta-line"></div>
    <div class="meta-item">
      <span class="label">GLOBAL</span>
      <span class="value">CONNECT</span>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-02">
  <div class="sv-scene-root sv-scene-root-scene-02" data-scene-root-id="scene-02">
<div class="s-scene-02-wrapper">
  <div class="tech-grid"></div>
  
  <!-- Step 0: Retro Window -->
  <div class="retro-window" data-step="0">
    <div class="window-header">
      <div class="header-title">OICQ_SETUP.EXE</div>
      <div class="header-controls">
        <span class="win-btn">_</span>
        <span class="win-btn">□</span>
        <span class="win-btn close">×</span>
      </div>
    </div>
    <div class="window-body">
      <div class="terminal-cursor"></div>
      <div class="terminal-text" id="terminal-typing-area"></div>
      
      <!-- Step 2: Penguin Hero -->
      <div class="hero-penguin-container" data-step="2">
        <div class="penguin-glow"></div>
        <iconify-icon icon="simple-icons:tencentqq" class="penguin-icon"></iconify-icon>
        <div class="scarf-accent"></div>
      </div>
    </div>
    <div class="window-status">
      <span>Status: Initializing...</span>
      <span class="blink-dot">●</span>
    </div>
  </div>

  <!-- Step 2: Bursting Bubbles Area -->
  <div class="bubble-burst-layer" data-step="2">
    <!-- Generated by JS -->
  </div>

  <!-- Scene Metadata -->
  <div class="scene-tag" data-step="0">
    <span class="tag-year">1999</span>
    <div class="tag-line"></div>
    <span class="tag-event">LAUNCH EVENT</span>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-03">
  <div class="sv-scene-root sv-scene-root-scene-03" data-scene-root-id="scene-03">
<div class="s-scene-03-wrapper">
  <div class="tech-grid"></div>
  
  <!-- Step 0: Background Growth Chart -->
  <div class="chart-container" data-step="0">
    <svg viewBox="0 0 400 800" class="growth-svg">
      <defs>
        <linearGradient id="lineGrad" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" stop-color="#F53501" stop-opacity="1" />
          <stop offset="100%" stop-color="#F53501" stop-opacity="0.1" />
        </linearGradient>
      </defs>
      <path class="chart-path" d="M0,600 L100,550 L200,580 L300,450 L400,300" fill="none" stroke="#F53501" stroke-width="4" />
      <path class="chart-fill" d="M0,600 L100,550 L200,580 L300,450 L400,300 L400,800 L0,800 Z" fill="url(#lineGrad)" opacity="0.1" />
    </svg>
    <div class="stat-label">IPO GROWTH</div>
  </div>

  <!-- Step 1: Golden Coin -->
  <div class="coin-hero" data-step="1">
    <div class="coin-3d">
      <div class="coin-face">
        <div class="coin-inner">
          <span class="stock-symbol">HK.0700</span>
          <div class="coin-reflection"></div>
        </div>
      </div>
    </div>
    <h1 class="main-title">2004 香港上市</h1>
  </div>

  <!-- Step 2: Grid Cards -->
  <div class="business-grid" data-step="2">
    <div class="biz-card" style="--i:0">
      <iconify-icon icon="lucide:layout-template" class="biz-icon"></iconify-icon>
      <span class="biz-name">门户</span>
    </div>
    <div class="biz-card" style="--i:1">
      <iconify-icon icon="lucide:gamepad-2" class="biz-icon"></iconify-icon>
      <span class="biz-name">游戏</span>
    </div>
    <div class="biz-card" style="--i:2">
      <iconify-icon icon="lucide:layout-grid" class="biz-icon"></iconify-icon>
      <span class="biz-name">空间</span>
    </div>
  </div>

  <div class="marker-line top"></div>
  <div class="marker-line bottom"></div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-04">
  <div class="sv-scene-root sv-scene-root-scene-04" data-scene-root-id="scene-04">
<div class="s-scene-04-wrapper">
  <div class="tech-grid"></div>
  
  <!-- Background Green Wash -->
  <div class="wechat-wash" data-step="0"></div>

  <!-- Step 0: Central Logo & Year -->
  <div class="hero-container" data-step="0">
    <div class="year-tag">2011</div>
    <div class="logo-box">
      <iconify-icon icon="simple-icons:wechat" class="main-logo"></iconify-icon>
      <div class="logo-glow"></div>
    </div>
    <h1 class="main-title">微信诞生</h1>
  </div>

  <!-- Step 1: Connection Ripples -->
  <div class="ripple-system" data-step="1">
    <div class="ripple-circle c1"></div>
    <div class="ripple-circle c2"></div>
    <div class="ripple-circle c3"></div>
    <div class="connection-text">连接一切</div>
  </div>

  <!-- Step 2: Ecosystem Icons -->
  <div class="ecosystem-radial" data-step="2">
    <div class="eco-item p-pay" style="--angle: -120deg">
      <div class="eco-icon-wrapper">
        <iconify-icon icon="ant-design:wechat-pay-outlined"></iconify-icon>
      </div>
      <span class="eco-label">移动支付</span>
    </div>
    <div class="eco-item p-mini" style="--angle: 0deg">
      <div class="eco-icon-wrapper">
        <iconify-icon icon="lucide:component"></iconify-icon>
      </div>
      <span class="eco-label">小程序</span>
    </div>
    <div class="eco-item p-moments" style="--angle: 120deg">
      <div class="eco-icon-wrapper">
        <iconify-icon icon="lucide:aperture"></iconify-icon>
      </div>
      <span class="eco-label">朋友圈</span>
    </div>
  </div>

  <!-- Decor elements -->
  <div class="focus-frame-top"></div>
  <div class="focus-frame-bottom"></div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-05">
  <div class="sv-scene-root sv-scene-root-scene-05" data-scene-root-id="scene-05">
<div class="s-scene-05-wrapper">
  <div class="tech-grid"></div>
  
  <!-- Step 0: Neural Network & Star Blue Wash -->
  <div class="blue-neural-wash" data-step="0"></div>
  <div class="neural-net-container" data-step="0">
    <svg class="neural-svg" viewBox="0 0 400 800">
      <g class="nodes">
        <circle cx="100" cy="200" r="3" fill="#F53501" />
        <circle cx="300" cy="250" r="3" fill="#F53501" />
        <circle cx="200" cy="400" r="4" fill="#F53501" />
        <circle cx="150" cy="600" r="3" fill="#F53501" />
        <circle cx="250" cy="550" r="3" fill="#F53501" />
      </g>
      <g class="links" stroke="rgba(245, 53, 1, 0.3)" stroke-width="1">
        <line x1="100" y1="200" x2="200" y2="400" />
        <line x1="300" y1="250" x2="200" y2="400" />
        <line x1="200" y1="400" x2="150" y2="600" />
        <line x1="200" y1="400" x2="250" y2="550" />
      </g>
    </svg>
  </div>

  <!-- Step 1: Cloud Frosted Progress Bar -->
  <div class="cloud-progress-container" data-step="1">
    <div class="frosted-ring">
      <div class="ring-spinner"></div>
      <iconify-icon icon="lucide:cloud" class="cloud-icon"></iconify-icon>
    </div>
    <div class="status-label">CLOUD COMPUTING</div>
  </div>

  <!-- Step 2: Hero Text & Particles -->
  <div class="hero-content-area" data-step="2">
    <div class="particle-emitter" id="particles-js-05"></div>
    <h1 class="vision-title">
      <span class="glow-text">科技</span><span class="glow-text highlight">向善</span>
    </h1>
    <div class="tech-tag-line">TECH FOR GOOD</div>
  </div>

  <!-- Layout Brackets (Tech Blogger Style) -->
  <div class="frame-bracket tl"></div>
  <div class="frame-bracket tr"></div>
  <div class="frame-bracket bl"></div>
  <div class="frame-bracket br"></div>
  <div class="data-stream-side">01001 / AI / CLOUD / VISION</div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-06">
  <div class="sv-scene-root sv-scene-root-scene-06" data-scene-root-id="scene-06">
<div class="s-scene-06-wrapper">
  <!-- Background Layers -->
  <div class="bg-base"></div>
  <div class="bg-gradient-overlay" data-step="0"></div>
  <div class="tech-grid-closing"></div>

  <!-- Step 1: Hero Slogan -->
  <div class="slogan-container" data-step="1">
    <div class="slogan-line">
      <span class="slogan-text">用户为本</span>
    </div>
    <div class="slogan-divider"></div>
    <div class="slogan-line">
      <span class="slogan-text highlight">科技向善</span>
    </div>
  </div>

  <!-- Step 2: Anniversary Logo & Closing -->
  <div class="anniversary-footer" data-step="2">
    <div class="logo-wrap">
      <iconify-icon icon="simple-icons:tencent" class="tencent-logo"></iconify-icon>
      <div class="logo-divider"></div>
      <div class="anniversary-badge">
        <span class="num">25</span>
        <span class="text">ANNIVERSARY</span>
      </div>
    </div>
    <div class="brand-subtext">VALUE FOR USERS, TECH FOR GOOD</div>
  </div>

  <!-- Style Brackets (Persistence) -->
  <div class="frame-bracket tl"></div>
  <div class="frame-bracket tr"></div>
  <div class="frame-bracket bl"></div>
  <div class="frame-bracket br"></div>

  <!-- Scanning Line -->
  <div class="scan-line"></div>
</div>
  </div>
</section>
      </div>
    </div>
  </div>
  <script id="__SVGVIDEO_META__" type="application/json">{"version":2,"format":"json","title":"腾讯公司发展历程：连接的演变","fullScript":"从1998年的深圳，到如今影响全球的互联网巨头，腾讯走过了一条不平凡的道路。一切始于那只戴着红围巾的小企鹅。1999年，OICQ正式上线，开启了中国人的即时通讯时代。2004年，腾讯在香港挂牌上市，业务版图迅速扩张，从门户网站、在线游戏，到社交网络。2011年是关键的转折点，微信诞生了。这不仅是一个聊天工具，更是连接一切的开始，彻底改变了我们的移动生活方式。进入新时代，腾讯提出了“科技向善”的愿景。从消费互联网全面拥抱产业互联网，深耕AI、云服务与前沿科技。深耕消费互联网，拥抱产业互联网，这，就是腾讯。连接未来，无限可能。","visualStyleId":"kejibozhu","orientation":"portrait","scenes":[{"id":"scene-01","title":"开篇：连接的起源","steps":2,"status":"success","prompt":"竖屏9:16布局。背景采用腾讯品牌深蓝色渐变，带有微弱的流体动态效果。Step 0：中心位置淡入发光的腾讯Logo，伴随轻微的弹簧缩放。Step 1：Logo下方出现文字‘腾讯：连接未来的25年’，使用毛玻璃质感底色，文字带Shimmer扫光特效。","scriptText":"从1998年的深圳，到如今影响全球的互联网巨头，腾讯走过了一条不平凡的道路。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_5640993b-edd4-480b-89f0-36cd4325fb5e/s_scene-01/v_yunxi/a_81ca1825_1777091614616_dre9l9.mp3","audioDurationMs":7596,"voiceName":"yunxi","relatedSceneIds":["scene-02"]},{"id":"scene-02","title":"1999：企鹅诞生","steps":3,"status":"success","prompt":"模拟复古电脑视窗风格。Step 0：居中展示一个90年代风格的灰色终端窗口。Step 1：窗口内逐字打字显示‘Connecting... OICQ’。Step 2：窗口中心弹出一只经典的红围巾企鹅SVG图标，背景出现无数个气泡对话框向四周扩散，象征通讯的爆发。","scriptText":"一切始于那只戴着红围巾的小企鹅。1999年，OICQ正式上线，开启了中国人的即时通讯时代。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_5640993b-edd4-480b-89f0-36cd4325fb5e/s_scene-02/v_yunxi/a_cd39a1b5_1777091931404_n3tdd6.mp3","audioDurationMs":9612,"voiceName":"yunxi","relatedSceneIds":["scene-01","scene-03"]},{"id":"scene-03","title":"2004：香港上市","steps":3,"status":"success","prompt":"金色与蓝色的商业视觉风格。Step 0：背景出现向上增长的平滑折线图，颜色为亮蓝色。Step 1：屏幕中央降落一枚金色的港币符号或‘HK.0700’字样的硬币，带有金属反光。Step 2：四周环绕浮现‘门户’、‘游戏’、‘空间’的卡片，采用网格布局，依次淡入。","scriptText":"2004年，腾讯在香港挂牌上市，业务版图迅速扩张，从门户网站、在线游戏，到社交网络。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_5640993b-edd4-480b-89f0-36cd4325fb5e/s_scene-03/v_yunxi/a_19bb2e6d_1777091688930_k2tzxc.mp3","audioDurationMs":9576,"voiceName":"yunxi","relatedSceneIds":["scene-02","scene-04"]},{"id":"scene-04","title":"2011：微信时代","steps":3,"status":"success","prompt":"极简绿色视觉风格。Step 0：全屏背景转为微信绿，中心出现经典的双气泡Logo。Step 1：Logo产生强烈的涟漪波动效果，象征‘连接一切’。Step 2：屏幕上下浮现出支付图标、小程序图标和朋友圈图标，呈现放射状排列，所有元素做悬浮呼吸动画。","scriptText":"2011年是关键的转折点，微信诞生了。这不仅是一个聊天工具，更是连接一切的开始，彻底改变了我们的移动生活方式。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_5640993b-edd4-480b-89f0-36cd4325fb5e/s_scene-04/v_yunxi/a_3b1d16e7_1777091725610_mago9s.mp3","audioDurationMs":10512,"voiceName":"yunxi","relatedSceneIds":["scene-03","scene-05"]},{"id":"scene-05","title":"产业互联网：科技向善","steps":3,"status":"success","prompt":"高科技感与未来感。Step 0：背景变为深邃的星空蓝，出现AI神经网络的动态连线。Step 1：上方降下一个代表‘云端’的毛玻璃圆环进度条，不停旋转。Step 2：中心浮现‘科技向善’四个大字，文字边缘带有发光描边，并有光粒子从下往上漂浮。","scriptText":"进入新时代，腾讯提出了“科技向善”的愿景。从消费互联网全面拥抱产业互联网，深耕AI、云服务与前沿科技。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_5640993b-edd4-480b-89f0-36cd4325fb5e/s_scene-05/v_yunxi/a_8d34a6fe_1777091763843_484ysn.mp3","audioDurationMs":11196,"voiceName":"yunxi","relatedSceneIds":["scene-04","scene-06"]},{"id":"scene-06","title":"总结：连接未来","steps":2,"status":"success","prompt":"简洁有力的品牌收尾。Step 0：背景回归纯净白蓝渐变。Step 1：腾讯最新的品牌Slogan‘用户为本，科技向善’在屏幕黄金分割位置垂直居中显示。Step 2：底部浮现25周年标识，整体画面向内收缩淡出。","scriptText":"深耕消费互联网，拥抱产业互联网，这，就是腾讯。连接未来，无限可能。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_5640993b-edd4-480b-89f0-36cd4325fb5e/s_scene-06/v_yunxi/a_76cc86c3_1777091799141_uh6sgl.mp3","audioDurationMs":8388,"voiceName":"yunxi","relatedSceneIds":["scene-05"]}]}</script>
  <script id="__SVGVIDEO_SCENE_DATA__" type="application/json">[{"id":"scene-01","title":"开篇：连接的起源","steps":2,"html":"<div class=\"s-scene-01-wrapper\">\n  <div class=\"tech-grid\"></div>\n  <div class=\"fluid-bg\"></div>\n  \n  <div class=\"focus-frame\" data-step=\"0\">\n    <div class=\"corner top-left\"></div>\n    <div class=\"corner top-right\"></div>\n    <div class=\"corner bottom-left\"></div>\n    <div class=\"corner bottom-right\"></div>\n  </div>\n\n  <div class=\"main-content\">\n    <div class=\"logo-container\" data-step=\"0\">\n      <iconify-icon icon=\"simple-icons:tencent\" class=\"tencent-logo\"></iconify-icon>\n      <div class=\"logo-glow\"></div>\n    </div>\n\n    <div class=\"text-glass-panel\" data-step=\"1\">\n      <h1 class=\"shimmer-text\">腾讯：连接未来的25年</h1>\n      <div class=\"accent-bar\"></div>\n    </div>\n  </div>\n\n  <div class=\"tech-metadata\" data-step=\"0\">\n    <div class=\"meta-item\">\n      <span class=\"label\">EST.</span>\n      <span class=\"value\">1998</span>\n    </div>\n    <div class=\"meta-line\"></div>\n    <div class=\"meta-item\">\n      <span class=\"label\">GLOBAL</span>\n      <span class=\"value\">CONNECT</span>\n    </div>\n  </div>\n</div>","css":".s-scene-01-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background-color: #1B1B1B;\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  font-family: var(--sv-font-body-cn);\n  color: #FFFFFF;\n}\n\n.tech-grid {\n  position: absolute;\n  inset: 0;\n  background-image: \n    linear-gradient(to right, rgba(255, 255, 255, 0.03) 1px, transparent 1px),\n    linear-gradient(to bottom, rgba(255, 255, 255, 0.03) 1px, transparent 1px);\n  background-size: 40px 40px;\n  z-index: 1;\n}\n\n.fluid-bg {\n  position: absolute;\n  inset: 0;\n  background: radial-gradient(circle at 50% 50%, rgba(245, 53, 1, 0.05) 0%, transparent 70%);\n  filter: blur(40px);\n  animation: fluid-pulse 8s ease-in-out infinite alternate;\n  z-index: 1;\n}\n\n@keyframes fluid-pulse {\n  from { transform: scale(1) translate(0, 0); }\n  to { transform: scale(1.2) translate(5%, 5%); }\n}\n\n.focus-frame {\n  position: absolute;\n  width: 280px;\n  height: 280px;\n  z-index: 2;\n  transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);\n  opacity: 0;\n  transform: scale(1.2);\n}\n.focus-frame[data-step-active=\"true\"] {\n  opacity: 1;\n  transform: scale(1);\n}\n\n.corner {\n  position: absolute;\n  width: 20px;\n  height: 20px;\n  border: 2px solid #F53501;\n}\n.top-left { top: 0; left: 0; border-right: 0; border-bottom: 0; }\n.top-right { top: 0; right: 0; border-left: 0; border-bottom: 0; }\n.bottom-left { bottom: 0; left: 0; border-right: 0; border-top: 0; }\n.bottom-right { bottom: 0; right: 0; border-left: 0; border-top: 0; }\n\n.main-content {\n  position: relative;\n  z-index: 10;\n  text-align: center;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 40px;\n}\n\n.logo-container {\n  position: relative;\n  width: 120px;\n  height: 120px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  opacity: 0;\n  transition: all 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n}\n.logo-container[data-step-active=\"true\"] {\n  opacity: 1;\n  transform: scale(1.1);\n}\n\n.tencent-logo {\n  font-size: 80px;\n  color: #FFFFFF;\n  filter: drop-shadow(0 0 20px rgba(245, 53, 1, 0.3));\n}\n\n.logo-glow {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  background: #F53501;\n  filter: blur(40px);\n  opacity: 0.15;\n  z-index: -1;\n}\n\n.text-glass-panel {\n  padding: 16px 24px;\n  background: rgba(255, 255, 255, 0.05);\n  backdrop-filter: blur(12px);\n  border: 1px solid rgba(255, 255, 255, 0.1);\n  border-radius: 4px;\n  opacity: 0;\n  transform: translateY(20px);\n  transition: all 0.6s ease-out;\n}\n.text-glass-panel[data-step-active=\"true\"] {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.shimmer-text {\n  font-family: var(--sv-font-display-cn);\n  font-size: 24px;\n  font-weight: 900;\n  margin: 0;\n  background: linear-gradient(90deg, #FFFFFF 0%, #F53501 50%, #FFFFFF 100%);\n  background-size: 200% auto;\n  -webkit-background-clip: text;\n  -webkit-text-fill-color: transparent;\n  animation: shimmer 3s linear infinite;\n}\n\n@keyframes shimmer {\n  to { background-position: 200% center; }\n}\n\n.accent-bar {\n  width: 40px;\n  height: 3px;\n  background: #F53501;\n  margin: 8px auto 0;\n}\n\n.tech-metadata {\n  position: absolute;\n  bottom: 60px;\n  display: flex;\n  align-items: center;\n  gap: 20px;\n  opacity: 0;\n  transition: opacity 1s ease;\n}\n.tech-metadata[data-step-active=\"true\"] {\n  opacity: 0.6;\n}\n\n.meta-item {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n}\n\n.meta-item .label {\n  font-family: var(--sv-font-mono);\n  font-size: 10px;\n  color: #F53501;\n  letter-spacing: 2px;\n}\n\n.meta-item .value {\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  font-weight: bold;\n}\n\n.meta-line {\n  width: 1px;\n  height: 30px;\n  background: rgba(255, 255, 255, 0.2);\n}","js":"window.SceneLifecycle.register('scene-01', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-01\"]');\n    if (sceneRoot) {\n      window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n    }\n  },\n  step(stepIndex) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-01\"]');\n    if (!sceneRoot) return;\n\n    const elements = sceneRoot.querySelectorAll('[data-step]');\n    elements.forEach(el => {\n      const stepValue = parseInt(el.getAttribute('data-step'));\n      el.setAttribute('data-step-active', stepIndex >= stepValue ? 'true' : 'false');\n    });\n  },\n  leave() {}\n});"},{"id":"scene-02","title":"1999：企鹅诞生","steps":3,"html":"<div class=\"s-scene-02-wrapper\">\n  <div class=\"tech-grid\"></div>\n  \n  <!-- Step 0: Retro Window -->\n  <div class=\"retro-window\" data-step=\"0\">\n    <div class=\"window-header\">\n      <div class=\"header-title\">OICQ_SETUP.EXE</div>\n      <div class=\"header-controls\">\n        <span class=\"win-btn\">_</span>\n        <span class=\"win-btn\">□</span>\n        <span class=\"win-btn close\">×</span>\n      </div>\n    </div>\n    <div class=\"window-body\">\n      <div class=\"terminal-cursor\"></div>\n      <div class=\"terminal-text\" id=\"terminal-typing-area\"></div>\n      \n      <!-- Step 2: Penguin Hero -->\n      <div class=\"hero-penguin-container\" data-step=\"2\">\n        <div class=\"penguin-glow\"></div>\n        <iconify-icon icon=\"simple-icons:tencentqq\" class=\"penguin-icon\"></iconify-icon>\n        <div class=\"scarf-accent\"></div>\n      </div>\n    </div>\n    <div class=\"window-status\">\n      <span>Status: Initializing...</span>\n      <span class=\"blink-dot\">●</span>\n    </div>\n  </div>\n\n  <!-- Step 2: Bursting Bubbles Area -->\n  <div class=\"bubble-burst-layer\" data-step=\"2\">\n    <!-- Generated by JS -->\n  </div>\n\n  <!-- Scene Metadata -->\n  <div class=\"scene-tag\" data-step=\"0\">\n    <span class=\"tag-year\">1999</span>\n    <div class=\"tag-line\"></div>\n    <span class=\"tag-event\">LAUNCH EVENT</span>\n  </div>\n</div>","css":".s-scene-02-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background-color: #1B1B1B;\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  font-family: var(--sv-font-body-cn);\n}\n\n.tech-grid {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);\n  background-size: 40px 40px;\n  z-index: 1;\n}\n\n.retro-window {\n  position: relative;\n  z-index: 10;\n  width: 320px;\n  height: 480px;\n  background: #C0C0C0;\n  border: 3px solid #FFFFFF;\n  border-right-color: #808080;\n  border-bottom-color: #808080;\n  box-shadow: 10px 10px 0px rgba(0, 0, 0, 0.3);\n  display: flex;\n  flex-direction: column;\n  opacity: 0;\n  transform: translateY(20px);\n  transition: all 0.6s cubic-bezier(0.23, 1, 0.32, 1);\n}\n.retro-window[data-step-active=\"true\"] {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.window-header {\n  background: linear-gradient(90deg, #000080, #1084D0);\n  padding: 4px 8px;\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  color: #FFF;\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  font-weight: bold;\n}\n\n.win-btn {\n  width: 16px;\n  height: 14px;\n  background: #C0C0C0;\n  border: 1px solid #FFF;\n  border-right-color: #000;\n  border-bottom-color: #000;\n  color: #000;\n  font-size: 10px;\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  margin-left: 2px;\n}\n\n.window-body {\n  flex-grow: 1;\n  background: #000;\n  margin: 4px;\n  padding: 15px;\n  position: relative;\n  overflow: hidden;\n  color: #FFF;\n  font-family: var(--sv-font-mono);\n  border: 2px inset #808080;\n}\n\n.terminal-text {\n  font-size: 14px;\n  line-height: 1.6;\n  white-space: pre-wrap;\n  color: #F53501;\n}\n\n.hero-penguin-container {\n  position: absolute;\n  inset: 0;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  opacity: 0;\n  transform: scale(0.5);\n  transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n}\n.hero-penguin-container[data-step-active=\"true\"] {\n  opacity: 1;\n  transform: scale(1);\n}\n\n.penguin-icon {\n  font-size: 120px;\n  color: #FFF;\n  z-index: 5;\n}\n\n.scarf-accent {\n  position: absolute;\n  width: 60px;\n  height: 10px;\n  background: #F53501;\n  top: 60%;\n  left: 50%;\n  transform: translateX(-50%);\n  border-radius: 5px;\n  box-shadow: 0 0 15px #F53501;\n  z-index: 6;\n}\n\n.penguin-glow {\n  position: absolute;\n  width: 140px;\n  height: 140px;\n  background: #F53501;\n  filter: blur(40px);\n  opacity: 0.4;\n  border-radius: 50%;\n}\n\n.bubble-burst-layer {\n  position: absolute;\n  inset: 0;\n  pointer-events: none;\n  z-index: 20;\n}\n\n.chat-bubble {\n  position: absolute;\n  padding: 8px 12px;\n  background: #FFF;\n  border: 1px solid #F53501;\n  border-radius: 12px;\n  font-size: 12px;\n  color: #1B1B1B;\n  opacity: 0;\n  animation: bubble-float 2s ease-out forwards;\n}\n\n@keyframes bubble-float {\n  0% { transform: translate(0, 0) scale(0); opacity: 0; }\n  20% { opacity: 1; }\n  100% { transform: translate(var(--tx), var(--ty)) scale(1); opacity: 0; }\n}\n\n.window-status {\n  padding: 4px 8px;\n  font-size: 10px;\n  color: #000;\n  background: #C0C0C0;\n  border-top: 1px solid #808080;\n  display: flex;\n  justify-content: space-between;\n}\n\n.blink-dot { color: #F53501; animation: blink 1s infinite; }\n@keyframes blink { 50% { opacity: 0; } }\n\n.scene-tag {\n  position: absolute;\n  top: 10%;\n  left: 40px;\n  display: flex;\n  flex-direction: column;\n  align-items: flex-start;\n  opacity: 0;\n  transition: all 0.8s ease;\n}\n.scene-tag[data-step-active=\"true\"] { opacity: 1; }\n\n.tag-year {\n  font-family: var(--sv-font-display-cn);\n  font-size: 42px;\n  color: #F53501;\n  line-height: 1;\n}\n\n.tag-line {\n  width: 100px;\n  height: 2px;\n  background: #F53501;\n  margin: 10px 0;\n}\n\n.tag-event {\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  color: #FFF;\n  letter-spacing: 4px;\n}","js":"window.SceneLifecycle.register('scene-02', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-02\"]');\n    if (sceneRoot) {\n      window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n    }\n  },\n  step(stepIndex) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-02\"]');\n    if (!sceneRoot) return;\n\n    const elements = sceneRoot.querySelectorAll('[data-step]');\n    elements.forEach(el => {\n      const stepValue = parseInt(el.getAttribute('data-step'));\n      el.setAttribute('data-step-active', stepIndex >= stepValue ? 'true' : 'false');\n    });\n\n    // Handle Typing Effect in Step 1\n    if (stepIndex === 1) {\n      const typingArea = sceneRoot.querySelector('#terminal-typing-area');\n      if (typingArea && !typingArea.getAttribute('data-started')) {\n        typingArea.setAttribute('data-started', 'true');\n        const text = 'Connecting...\\nRemote server found.\\nProtocol: OICQ v1.0\\nStatus: ONLINE';\n        let i = 0;\n        const interval = setInterval(() => {\n          typingArea.textContent = text.slice(0, i) + (i % 2 === 0 ? '_' : ' ');\n          i++;\n          if (i > text.length) {\n            clearInterval(interval);\n            typingArea.textContent = text;\n          }\n        }, 50);\n      }\n    }\n\n    // Handle Bubble Burst in Step 2\n    if (stepIndex === 2) {\n      const layer = sceneRoot.querySelector('.bubble-burst-layer');\n      if (layer && layer.children.length === 0) {\n        const msgs = ['你好', 'OICQ', '1999', 'Hello', 'Ping', 'Online', 'Connected'];\n        for (let i = 0; i < 20; i++) {\n          const b = document.createElement('div');\n          b.className = 'chat-bubble';\n          b.textContent = msgs[Math.floor(Math.random() * msgs.length)];\n          const angle = Math.random() * Math.PI * 2;\n          const dist = 150 + Math.random() * 200;\n          b.style.setProperty('--tx', `${Math.cos(angle) * dist}px`);\n          b.style.setProperty('--ty', `${Math.sin(angle) * dist}px`);\n          b.style.left = '50%';\n          b.style.top = '50%';\n          b.style.animationDelay = `${Math.random() * 0.5}s`;\n          layer.appendChild(b);\n        }\n      }\n    }\n  },\n  leave() {}\n});"},{"id":"scene-03","title":"2004：香港上市","steps":3,"html":"<div class=\"s-scene-03-wrapper\">\n  <div class=\"tech-grid\"></div>\n  \n  <!-- Step 0: Background Growth Chart -->\n  <div class=\"chart-container\" data-step=\"0\">\n    <svg viewBox=\"0 0 400 800\" class=\"growth-svg\">\n      <defs>\n        <linearGradient id=\"lineGrad\" x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n          <stop offset=\"0%\" stop-color=\"#F53501\" stop-opacity=\"1\" />\n          <stop offset=\"100%\" stop-color=\"#F53501\" stop-opacity=\"0.1\" />\n        </linearGradient>\n      </defs>\n      <path class=\"chart-path\" d=\"M0,600 L100,550 L200,580 L300,450 L400,300\" fill=\"none\" stroke=\"#F53501\" stroke-width=\"4\" />\n      <path class=\"chart-fill\" d=\"M0,600 L100,550 L200,580 L300,450 L400,300 L400,800 L0,800 Z\" fill=\"url(#lineGrad)\" opacity=\"0.1\" />\n    </svg>\n    <div class=\"stat-label\">IPO GROWTH</div>\n  </div>\n\n  <!-- Step 1: Golden Coin -->\n  <div class=\"coin-hero\" data-step=\"1\">\n    <div class=\"coin-3d\">\n      <div class=\"coin-face\">\n        <div class=\"coin-inner\">\n          <span class=\"stock-symbol\">HK.0700</span>\n          <div class=\"coin-reflection\"></div>\n        </div>\n      </div>\n    </div>\n    <h1 class=\"main-title\">2004 香港上市</h1>\n  </div>\n\n  <!-- Step 2: Grid Cards -->\n  <div class=\"business-grid\" data-step=\"2\">\n    <div class=\"biz-card\" style=\"--i:0\">\n      <iconify-icon icon=\"lucide:layout-template\" class=\"biz-icon\"></iconify-icon>\n      <span class=\"biz-name\">门户</span>\n    </div>\n    <div class=\"biz-card\" style=\"--i:1\">\n      <iconify-icon icon=\"lucide:gamepad-2\" class=\"biz-icon\"></iconify-icon>\n      <span class=\"biz-name\">游戏</span>\n    </div>\n    <div class=\"biz-card\" style=\"--i:2\">\n      <iconify-icon icon=\"lucide:layout-grid\" class=\"biz-icon\"></iconify-icon>\n      <span class=\"biz-name\">空间</span>\n    </div>\n  </div>\n\n  <div class=\"marker-line top\"></div>\n  <div class=\"marker-line bottom\"></div>\n</div>","css":".s-scene-03-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background-color: #1B1B1B;\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  font-family: var(--sv-font-body-cn);\n}\n\n.tech-grid {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px);\n  background-size: 30px 30px;\n  z-index: 1;\n}\n\n/* Step 0: Chart Animation */\n.chart-container {\n  position: absolute;\n  bottom: 0;\n  width: 100%;\n  height: 50%;\n  z-index: 2;\n  opacity: 0;\n  transition: opacity 1s ease;\n}\n.chart-container[data-step-active=\"true\"] {\n  opacity: 1;\n}\n.chart-path {\n  stroke-dasharray: 1000;\n  stroke-dashoffset: 1000;\n}\n.chart-container[data-step-active=\"true\"] .chart-path {\n  animation: chart-draw 2.5s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n@keyframes chart-draw {\n  to { stroke-dashoffset: 0; }\n}\n\n.stat-label {\n  position: absolute;\n  left: 20px;\n  top: 20px;\n  color: #F53501;\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  letter-spacing: 2px;\n  border-left: 2px solid #F53501;\n  padding-left: 8px;\n}\n\n/* Step 1: Coin Hero */\n.coin-hero {\n  position: relative;\n  z-index: 10;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  opacity: 0;\n  transform: translateY(-50px) scale(0.8);\n  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n.coin-hero[data-step-active=\"true\"] {\n  opacity: 1;\n  transform: translateY(0) scale(1);\n}\n\n.coin-3d {\n  width: 180px;\n  height: 180px;\n  perspective: 1000px;\n  margin-bottom: 24px;\n}\n\n.coin-face {\n  width: 100%;\n  height: 100%;\n  background: linear-gradient(135deg, #FFD700 0%, #B8860B 50%, #FFD700 100%);\n  border-radius: 50%;\n  padding: 10px;\n  box-shadow: 0 20px 40px rgba(0,0,0,0.5), inset 0 0 20px rgba(255,255,255,0.5);\n  animation: coin-spin 6s infinite linear;\n}\n\n.coin-inner {\n  width: 100%;\n  height: 100%;\n  border: 4px solid rgba(0,0,0,0.1);\n  border-radius: 50%;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  position: relative;\n  overflow: hidden;\n}\n\n.stock-symbol {\n  font-family: var(--sv-font-display-cn);\n  font-size: 24px;\n  color: #5C4033;\n  font-weight: 900;\n  text-shadow: 1px 1px 0px rgba(255,255,255,0.3);\n}\n\n.coin-reflection {\n  position: absolute;\n  top: -50%;\n  left: -50%;\n  width: 200%;\n  height: 200%;\n  background: linear-gradient(45deg, transparent 45%, rgba(255,255,255,0.6) 50%, transparent 55%);\n  animation: reflect 3s infinite ease-in-out;\n}\n\n@keyframes reflect { 0% { transform: translate(-20%, -20%); } 100% { transform: translate(20%, 20%); } }\n@keyframes coin-spin { 0% { transform: rotateY(0deg); } 100% { transform: rotateY(360deg); } }\n\n.main-title {\n  font-family: var(--sv-font-display-cn);\n  font-size: 32px;\n  color: #FFFFFF;\n  text-transform: uppercase;\n  letter-spacing: 2px;\n}\n\n/* Step 2: Biz Grid */\n.business-grid {\n  position: absolute;\n  bottom: 12%;\n  width: 90%;\n  display: grid;\n  grid-template-columns: repeat(3, 1fr);\n  gap: 12px;\n  z-index: 15;\n}\n\n.biz-card {\n  background: rgba(255, 255, 255, 0.03);\n  border: 1px solid rgba(255, 255, 255, 0.1);\n  padding: 16px 8px;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 8px;\n  opacity: 0;\n  transform: translateY(20px);\n  transition: all 0.5s ease;\n  transition-delay: calc(var(--i) * 0.15s);\n}\n\n.business-grid[data-step-active=\"true\"] .biz-card {\n  opacity: 1;\n  transform: translateY(0);\n  border-color: rgba(245, 53, 1, 0.3);\n}\n\n.biz-icon {\n  font-size: 28px;\n  color: #F53501;\n}\n\n.biz-name {\n  font-family: var(--sv-font-display-cn);\n  font-size: 16px;\n  color: #FFFFFF;\n}\n\n.marker-line {\n  position: absolute;\n  left: 5%;\n  width: 90%;\n  height: 1px;\n  background: rgba(245, 53, 1, 0.2);\n  z-index: 5;\n}\n.marker-line.top { top: 20%; }\n.marker-line.bottom { bottom: 20%; }","js":"window.SceneLifecycle.register('scene-03', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-03\"]');\n    if (sceneRoot) {\n      window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n    }\n  },\n  step(stepIndex) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-03\"]');\n    if (!sceneRoot) return;\n\n    const elements = sceneRoot.querySelectorAll('[data-step]');\n    elements.forEach(el => {\n      const stepValue = parseInt(el.getAttribute('data-step'));\n      el.setAttribute('data-step-active', stepIndex >= stepValue ? 'true' : 'false');\n    });\n\n    // Visual impact when coin lands at step 1\n    if (stepIndex === 1) {\n      const coin = sceneRoot.querySelector('.coin-hero');\n      if (coin) {\n        coin.animate([\n          { transform: 'scale(1.2) translateY(-20px)' },\n          { transform: 'scale(1) translateY(0)' }\n        ], { duration: 500, easing: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)' });\n      }\n    }\n  },\n  leave() {}\n});"},{"id":"scene-04","title":"2011：微信时代","steps":3,"html":"<div class=\"s-scene-04-wrapper\">\n  <div class=\"tech-grid\"></div>\n  \n  <!-- Background Green Wash -->\n  <div class=\"wechat-wash\" data-step=\"0\"></div>\n\n  <!-- Step 0: Central Logo & Year -->\n  <div class=\"hero-container\" data-step=\"0\">\n    <div class=\"year-tag\">2011</div>\n    <div class=\"logo-box\">\n      <iconify-icon icon=\"simple-icons:wechat\" class=\"main-logo\"></iconify-icon>\n      <div class=\"logo-glow\"></div>\n    </div>\n    <h1 class=\"main-title\">微信诞生</h1>\n  </div>\n\n  <!-- Step 1: Connection Ripples -->\n  <div class=\"ripple-system\" data-step=\"1\">\n    <div class=\"ripple-circle c1\"></div>\n    <div class=\"ripple-circle c2\"></div>\n    <div class=\"ripple-circle c3\"></div>\n    <div class=\"connection-text\">连接一切</div>\n  </div>\n\n  <!-- Step 2: Ecosystem Icons -->\n  <div class=\"ecosystem-radial\" data-step=\"2\">\n    <div class=\"eco-item p-pay\" style=\"--angle: -120deg\">\n      <div class=\"eco-icon-wrapper\">\n        <iconify-icon icon=\"ant-design:wechat-pay-outlined\"></iconify-icon>\n      </div>\n      <span class=\"eco-label\">移动支付</span>\n    </div>\n    <div class=\"eco-item p-mini\" style=\"--angle: 0deg\">\n      <div class=\"eco-icon-wrapper\">\n        <iconify-icon icon=\"lucide:component\"></iconify-icon>\n      </div>\n      <span class=\"eco-label\">小程序</span>\n    </div>\n    <div class=\"eco-item p-moments\" style=\"--angle: 120deg\">\n      <div class=\"eco-icon-wrapper\">\n        <iconify-icon icon=\"lucide:aperture\"></iconify-icon>\n      </div>\n      <span class=\"eco-label\">朋友圈</span>\n    </div>\n  </div>\n\n  <!-- Decor elements -->\n  <div class=\"focus-frame-top\"></div>\n  <div class=\"focus-frame-bottom\"></div>\n</div>","css":".s-scene-04-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background-color: #1B1B1B;\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  font-family: var(--sv-font-body-cn);\n}\n\n.tech-grid {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px);\n  background-size: 40px 40px;\n  z-index: 1;\n}\n\n.wechat-wash {\n  position: absolute;\n  inset: 0;\n  background: radial-gradient(circle at center, rgba(7, 193, 96, 0.2) 0%, transparent 70%);\n  opacity: 0;\n  transition: opacity 1.2s ease;\n  z-index: 2;\n}\n.wechat-wash[data-step-active=\"true\"] { opacity: 1; }\n\n.hero-container {\n  position: relative;\n  z-index: 10;\n  text-align: center;\n  opacity: 0;\n  transform: scale(0.9);\n  transition: all 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n}\n.hero-container[data-step-active=\"true\"] {\n  opacity: 1;\n  transform: scale(1);\n}\n\n.year-tag {\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  color: #F53501;\n  background: rgba(245, 53, 1, 0.1);\n  padding: 2px 10px;\n  border: 1px solid #F53501;\n  display: inline-block;\n  margin-bottom: 20px;\n  letter-spacing: 2px;\n}\n\n.logo-box {\n  position: relative;\n  width: 120px;\n  height: 120px;\n  margin: 0 auto 30px;\n}\n\n.main-logo {\n  font-size: 120px;\n  color: #07C160;\n  filter: drop-shadow(0 0 20px rgba(7, 193, 96, 0.4));\n}\n\n.logo-glow {\n  position: absolute;\n  inset: -20px;\n  background: radial-gradient(circle, rgba(7, 193, 96, 0.15) 0%, transparent 70%);\n  animation: logo-pulse 3s infinite ease-in-out;\n}\n\n.main-title {\n  font-family: var(--sv-font-display-cn);\n  font-size: 48px;\n  color: #FFFFFF;\n  margin: 0;\n  letter-spacing: 4px;\n}\n\n/* Step 1: Ripple */\n.ripple-system {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n  width: 100%;\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: flex-end;\n  padding-bottom: 25%;\n  z-index: 5;\n  opacity: 0;\n  transition: opacity 0.5s ease;\n}\n.ripple-system[data-step-active=\"true\"] { opacity: 1; }\n\n.ripple-circle {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  border: 1px solid rgba(7, 193, 96, 0.3);\n  border-radius: 50%;\n  transform: translate(-50%, -50%) scale(0);\n}\n.ripple-system[data-step-active=\"true\"] .ripple-circle {\n  animation: ripple-out 4s infinite linear;\n}\n.c1 { width: 300px; height: 300px; animation-delay: 0s; }\n.c2 { width: 300px; height: 300px; animation-delay: 1.3s; }\n.c3 { width: 300px; height: 300px; animation-delay: 2.6s; }\n\n.connection-text {\n  font-family: var(--sv-font-display-cn);\n  color: #07C160;\n  font-size: 20px;\n  letter-spacing: 8px;\n  text-transform: uppercase;\n  opacity: 0.8;\n}\n\n/* Step 2: Ecosystem */\n.ecosystem-radial {\n  position: absolute;\n  inset: 0;\n  z-index: 15;\n  pointer-events: none;\n}\n\n.eco-item {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 12px;\n  opacity: 0;\n  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);\n  --dist: 160px;\n}\n\n.ecosystem-radial[data-step-active=\"true\"] .eco-item {\n  opacity: 1;\n  transform: translate(calc(cos(var(--angle)) * var(--dist) - 50%), calc(sin(var(--angle)) * var(--dist) - 50%));\n}\n\n.eco-icon-wrapper {\n  width: 60px;\n  height: 60px;\n  background: rgba(255, 255, 255, 0.05);\n  border: 1px solid rgba(7, 193, 96, 0.4);\n  border-radius: 12px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  font-size: 32px;\n  color: #07C160;\n  box-shadow: 0 10px 20px rgba(0,0,0,0.3);\n  animation: float-breathing 4s infinite ease-in-out;\n}\n\n.eco-label {\n  font-size: 14px;\n  color: #FFFFFF;\n  white-space: nowrap;\n  font-weight: 600;\n  text-shadow: 0 2px 4px rgba(0,0,0,0.5);\n}\n\n/* Decor Frames */\n.focus-frame-top, .focus-frame-bottom {\n  position: absolute;\n  left: 10%;\n  width: 80%;\n  height: 20px;\n  border: 1px solid rgba(245, 53, 1, 0.2);\n  z-index: 5;\n}\n.focus-frame-top {\n  top: 5%;\n  border-bottom: none;\n}\n.focus-frame-bottom {\n  bottom: 5%;\n  border-top: none;\n}\n\n@keyframes logo-pulse { 0%, 100% { transform: scale(1); opacity: 0.15; } 50% { transform: scale(1.1); opacity: 0.3; } }\n@keyframes ripple-out { from { transform: translate(-50%, -50%) scale(0.5); opacity: 1; } to { transform: translate(-50%, -50%) scale(2.5); opacity: 0; } }\n@keyframes float-breathing {\n  0%, 100% { transform: translateY(0); } \n  50% { transform: translateY(-10px); }\n}","js":"window.SceneLifecycle.register('scene-04', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-04\"]');\n    if (sceneRoot) {\n      window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n    }\n  },\n  step(stepIndex) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-04\"]');\n    if (!sceneRoot) return;\n\n    const elements = sceneRoot.querySelectorAll('[data-step]');\n    elements.forEach(el => {\n      const stepValue = parseInt(el.getAttribute('data-step'));\n      el.setAttribute('data-step-active', stepIndex >= stepValue ? 'true' : 'false');\n    });\n\n    // Special impact for the logo in Step 0\n    if (stepIndex === 0) {\n      const logoBox = sceneRoot.querySelector('.logo-box');\n      if (logoBox) {\n        logoBox.animate([\n          { transform: 'scale(0.5) rotate(-10deg)', opacity: 0 },\n          { transform: 'scale(1.1) rotate(5deg)', opacity: 1 },\n          { transform: 'scale(1) rotate(0deg)', opacity: 1 }\n        ], { duration: 1000, easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)' });\n      }\n    }\n\n    // Visual burst effect when ripples/connection starts at Step 1\n    if (stepIndex === 1) {\n      const wash = sceneRoot.querySelector('.wechat-wash');\n      if (wash) {\n        wash.animate([\n          { background: 'radial-gradient(circle at center, rgba(7, 193, 96, 0.6) 0%, transparent 10%)' },\n          { background: 'radial-gradient(circle at center, rgba(7, 193, 96, 0.2) 0%, transparent 70%)' }\n        ], { duration: 800 });\n      }\n    }\n  },\n  leave() {}\n});"},{"id":"scene-05","title":"产业互联网：科技向善","steps":3,"html":"<div class=\"s-scene-05-wrapper\">\n  <div class=\"tech-grid\"></div>\n  \n  <!-- Step 0: Neural Network & Star Blue Wash -->\n  <div class=\"blue-neural-wash\" data-step=\"0\"></div>\n  <div class=\"neural-net-container\" data-step=\"0\">\n    <svg class=\"neural-svg\" viewBox=\"0 0 400 800\">\n      <g class=\"nodes\">\n        <circle cx=\"100\" cy=\"200\" r=\"3\" fill=\"#F53501\" />\n        <circle cx=\"300\" cy=\"250\" r=\"3\" fill=\"#F53501\" />\n        <circle cx=\"200\" cy=\"400\" r=\"4\" fill=\"#F53501\" />\n        <circle cx=\"150\" cy=\"600\" r=\"3\" fill=\"#F53501\" />\n        <circle cx=\"250\" cy=\"550\" r=\"3\" fill=\"#F53501\" />\n      </g>\n      <g class=\"links\" stroke=\"rgba(245, 53, 1, 0.3)\" stroke-width=\"1\">\n        <line x1=\"100\" y1=\"200\" x2=\"200\" y2=\"400\" />\n        <line x1=\"300\" y1=\"250\" x2=\"200\" y2=\"400\" />\n        <line x1=\"200\" y1=\"400\" x2=\"150\" y2=\"600\" />\n        <line x1=\"200\" y1=\"400\" x2=\"250\" y2=\"550\" />\n      </g>\n    </svg>\n  </div>\n\n  <!-- Step 1: Cloud Frosted Progress Bar -->\n  <div class=\"cloud-progress-container\" data-step=\"1\">\n    <div class=\"frosted-ring\">\n      <div class=\"ring-spinner\"></div>\n      <iconify-icon icon=\"lucide:cloud\" class=\"cloud-icon\"></iconify-icon>\n    </div>\n    <div class=\"status-label\">CLOUD COMPUTING</div>\n  </div>\n\n  <!-- Step 2: Hero Text & Particles -->\n  <div class=\"hero-content-area\" data-step=\"2\">\n    <div class=\"particle-emitter\" id=\"particles-js-05\"></div>\n    <h1 class=\"vision-title\">\n      <span class=\"glow-text\">科技</span><span class=\"glow-text highlight\">向善</span>\n    </h1>\n    <div class=\"tech-tag-line\">TECH FOR GOOD</div>\n  </div>\n\n  <!-- Layout Brackets (Tech Blogger Style) -->\n  <div class=\"frame-bracket tl\"></div>\n  <div class=\"frame-bracket tr\"></div>\n  <div class=\"frame-bracket bl\"></div>\n  <div class=\"frame-bracket br\"></div>\n  <div class=\"data-stream-side\">01001 / AI / CLOUD / VISION</div>\n</div>","css":".s-scene-05-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background-color: #1B1B1B;\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  font-family: var(--sv-font-body-cn);\n}\n\n.tech-grid {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);\n  background-size: 30px 30px;\n  z-index: 1;\n}\n\n.blue-neural-wash {\n  position: absolute;\n  inset: 0;\n  background: radial-gradient(circle at 50% 50%, rgba(10, 17, 40, 0.8) 0%, transparent 100%);\n  opacity: 0;\n  transition: opacity 1.5s ease;\n  z-index: 2;\n}\n.blue-neural-wash[data-step-active=\"true\"] { opacity: 1; }\n\n.neural-net-container {\n  position: absolute;\n  inset: 0;\n  z-index: 3;\n  opacity: 0;\n  transition: opacity 1s ease;\n}\n.neural-net-container[data-step-active=\"true\"] { opacity: 0.6; }\n\n.neural-svg {\n  width: 100%;\n  height: 100%;\n  filter: drop-shadow(0 0 5px rgba(245, 53, 1, 0.4));\n}\n\n/* Step 1: Cloud Ring */\n.cloud-progress-container {\n  position: absolute;\n  top: 15%;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 15px;\n  opacity: 0;\n  transform: translateY(-50px);\n  transition: all 0.8s cubic-bezier(0.23, 1, 0.32, 1);\n  z-index: 10;\n}\n.cloud-progress-container[data-step-active=\"true\"] {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.frosted-ring {\n  position: relative;\n  width: 100px;\n  height: 100px;\n  background: rgba(255, 255, 255, 0.05);\n  backdrop-filter: blur(8px);\n  -webkit-backdrop-filter: blur(8px);\n  border-radius: 50%;\n  border: 1px solid rgba(255, 255, 255, 0.1);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.ring-spinner {\n  position: absolute;\n  inset: -5px;\n  border: 2px solid transparent;\n  border-top: 2px solid #F53501;\n  border-radius: 50%;\n  animation: spin 2s linear infinite;\n}\n\n.cloud-icon {\n  font-size: 40px;\n  color: #FFFFFF;\n  filter: drop-shadow(0 0 10px rgba(255, 255, 255, 0.3));\n}\n\n.status-label {\n  font-family: var(--sv-font-mono);\n  color: #F53501;\n  font-size: 10px;\n  letter-spacing: 2px;\n  font-weight: bold;\n}\n\n/* Step 2: Hero Text */\n.hero-content-area {\n  position: relative;\n  z-index: 20;\n  text-align: center;\n  opacity: 0;\n  transform: scale(0.9);\n  transition: all 1s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n.hero-content-area[data-step-active=\"true\"] {\n  opacity: 1;\n  transform: scale(1);\n}\n\n.vision-title {\n  font-family: var(--sv-font-display-cn);\n  font-size: 72px;\n  color: #FFFFFF;\n  margin: 0;\n  line-height: 1.2;\n  display: flex;\n  flex-direction: column;\n}\n\n.glow-text {\n  text-shadow: 0 0 20px rgba(255, 255, 255, 0.2);\n}\n\n.glow-text.highlight {\n  color: #F53501;\n  text-shadow: 0 0 30px rgba(245, 53, 1, 0.6);\n  border: 2px solid #F53501;\n  padding: 0 10px;\n  margin-top: 10px;\n}\n\n.tech-tag-line {\n  font-family: var(--sv-font-mono);\n  color: rgba(255, 255, 255, 0.4);\n  font-size: 14px;\n  letter-spacing: 6px;\n  margin-top: 20px;\n}\n\n.particle-emitter {\n  position: absolute;\n  inset: -100px;\n  pointer-events: none;\n}\n\n/* Decor elements */\n.frame-bracket {\n  position: absolute;\n  width: 20px;\n  height: 20px;\n  border: 2px solid #F53501;\n  z-index: 50;\n}\n.tl { top: 40px; left: 40px; border-right: none; border-bottom: none; }\n.tr { top: 40px; right: 40px; border-left: none; border-bottom: none; }\n.bl { bottom: 40px; left: 40px; border-right: none; border-top: none; }\n.br { bottom: 40px; right: 40px; border-left: none; border-top: none; }\n\n.data-stream-side {\n  position: absolute;\n  right: 10px;\n  top: 50%;\n  transform: rotate(90deg) translate(-50%, 0);\n  font-family: var(--sv-font-mono);\n  font-size: 10px;\n  color: rgba(245, 53, 1, 0.5);\n  letter-spacing: 2px;\n}\n\n@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }\n\n.particle {\n  position: absolute;\n  background: #F53501;\n  width: 2px;\n  height: 2px;\n  border-radius: 50%;\n  animation: float-up var(--d) linear infinite;\n  opacity: 0;\n}\n\n@keyframes float-up {\n  0% { transform: translateY(0); opacity: 0; }\n  20% { opacity: 0.8; }\n  100% { transform: translateY(-150px); opacity: 0; }\n}","js":"window.SceneLifecycle.register('scene-05', {\n  enter() {\n    const root = document.querySelector('[data-scene-id=\"scene-05\"]');\n    if (root) {\n      window.__SVGVIDEO_REFRESH_ICONS(root);\n      this.createParticles(root);\n    }\n  },\n  step(index) {\n    const root = document.querySelector('[data-scene-id=\"scene-05\"]');\n    if (!root) return;\n\n    const elements = root.querySelectorAll('[data-step]');\n    elements.forEach(el => {\n      const stepValue = parseInt(el.getAttribute('data-step'));\n      el.setAttribute('data-step-active', index >= stepValue ? 'true' : 'false');\n    });\n\n    if (index === 0) {\n      const svgLines = root.querySelectorAll('.links line');\n      svgLines.forEach((line, i) => {\n        line.animate([\n          { strokeDasharray: '0 500', strokeDashoffset: '0' },\n          { strokeDasharray: '500 500', strokeDashoffset: '0' }\n        ], { duration: 1500, delay: i * 200, fill: 'forwards' });\n      });\n    }\n\n    if (index === 2) {\n      const title = root.querySelector('.vision-title');\n      title.animate([\n        { filter: 'brightness(1) blur(0px)' },\n        { filter: 'brightness(2) blur(2px)' },\n        { filter: 'brightness(1) blur(0px)' }\n      ], { duration: 1000, easing: 'ease-out' });\n    }\n  },\n  createParticles(root) {\n    const container = root.querySelector('#particles-js-05');\n    if (!container) return;\n    container.innerHTML = '';\n    for (let i = 0; i < 20; i++) {\n      const p = document.createElement('div');\n      p.className = 'particle';\n      p.style.left = Math.random() * 100 + '%';\n      p.style.bottom = '0px';\n      p.style.setProperty('--d', (2 + Math.random() * 3) + 's');\n      p.style.animationDelay = Math.random() * 2 + 's';\n      container.appendChild(p);\n    }\n  },\n  leave() {}\n});"},{"id":"scene-06","title":"总结：连接未来","steps":2,"html":"<div class=\"s-scene-06-wrapper\">\n  <!-- Background Layers -->\n  <div class=\"bg-base\"></div>\n  <div class=\"bg-gradient-overlay\" data-step=\"0\"></div>\n  <div class=\"tech-grid-closing\"></div>\n\n  <!-- Step 1: Hero Slogan -->\n  <div class=\"slogan-container\" data-step=\"1\">\n    <div class=\"slogan-line\">\n      <span class=\"slogan-text\">用户为本</span>\n    </div>\n    <div class=\"slogan-divider\"></div>\n    <div class=\"slogan-line\">\n      <span class=\"slogan-text highlight\">科技向善</span>\n    </div>\n  </div>\n\n  <!-- Step 2: Anniversary Logo & Closing -->\n  <div class=\"anniversary-footer\" data-step=\"2\">\n    <div class=\"logo-wrap\">\n      <iconify-icon icon=\"simple-icons:tencent\" class=\"tencent-logo\"></iconify-icon>\n      <div class=\"logo-divider\"></div>\n      <div class=\"anniversary-badge\">\n        <span class=\"num\">25</span>\n        <span class=\"text\">ANNIVERSARY</span>\n      </div>\n    </div>\n    <div class=\"brand-subtext\">VALUE FOR USERS, TECH FOR GOOD</div>\n  </div>\n\n  <!-- Style Brackets (Persistence) -->\n  <div class=\"frame-bracket tl\"></div>\n  <div class=\"frame-bracket tr\"></div>\n  <div class=\"frame-bracket bl\"></div>\n  <div class=\"frame-bracket br\"></div>\n\n  <!-- Scanning Line -->\n  <div class=\"scan-line\"></div>\n</div>","css":".s-scene-06-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background-color: #1B1B1B;\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  transition: transform 1.2s cubic-bezier(0.7, 0, 0.3, 1), opacity 1.2s ease;\n}\n\n.s-scene-06-wrapper[data-closing=\"true\"] {\n  transform: scale(0.9);\n  opacity: 0;\n}\n\n.bg-base {\n  position: absolute;\n  inset: 0;\n  background: #1B1B1B;\n  z-index: 1;\n}\n\n.bg-gradient-overlay {\n  position: absolute;\n  inset: 0;\n  background: radial-gradient(circle at 50% 50%, #FFFFFF 0%, #E6F0FF 40%, #B8D4FF 100%);\n  opacity: 0;\n  transition: opacity 1.5s cubic-bezier(0.4, 0, 0.2, 1);\n  z-index: 2;\n}\n\n.bg-gradient-overlay[data-step-active=\"true\"] {\n  opacity: 1;\n}\n\n.tech-grid-closing {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(245, 53, 1, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(245, 53, 1, 0.05) 1px, transparent 1px);\n  background-size: 40px 40px;\n  z-index: 3;\n  opacity: 0.3;\n}\n\n.slogan-container {\n  position: relative;\n  z-index: 10;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  text-align: center;\n  opacity: 0;\n  transform: translateY(30px);\n  transition: all 1s cubic-bezier(0.23, 1, 0.32, 1);\n}\n\n.slogan-container[data-step-active=\"true\"] {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.slogan-line {\n  overflow: hidden;\n}\n\n.slogan-text {\n  display: block;\n  font-family: var(--sv-font-display-cn);\n  font-size: 48px;\n  color: #1B1B1B;\n  letter-spacing: 4px;\n  line-height: 1.2;\n}\n\n.slogan-text.highlight {\n  color: #F53501;\n}\n\n.slogan-divider {\n  width: 40px;\n  height: 4px;\n  background: #F53501;\n  margin: 20px 0;\n}\n\n.anniversary-footer {\n  position: absolute;\n  bottom: 12%;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  z-index: 10;\n  opacity: 0;\n  transform: translateY(20px);\n  transition: all 0.8s ease-out;\n}\n\n.anniversary-footer[data-step-active=\"true\"] {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.logo-wrap {\n  display: flex;\n  align-items: center;\n  gap: 15px;\n  margin-bottom: 10px;\n}\n\n.tencent-logo {\n  font-size: 32px;\n  color: #0052D9;\n}\n\n.logo-divider {\n  width: 1px;\n  height: 20px;\n  background: rgba(0, 0, 0, 0.2);\n}\n\n.anniversary-badge {\n  display: flex;\n  flex-direction: column;\n  align-items: flex-start;\n}\n\n.anniversary-badge .num {\n  font-family: var(--sv-font-mono);\n  font-weight: 900;\n  font-size: 24px;\n  line-height: 1;\n  color: #1B1B1B;\n}\n\n.anniversary-badge .text {\n  font-family: var(--sv-font-mono);\n  font-size: 8px;\n  letter-spacing: 1px;\n  color: #666;\n}\n\n.brand-subtext {\n  font-family: var(--sv-font-mono);\n  font-size: 10px;\n  color: rgba(0, 0, 0, 0.4);\n  letter-spacing: 2px;\n}\n\n/* Tech Decors */\n.frame-bracket {\n  position: absolute;\n  width: 15px;\n  height: 15px;\n  border: 1.5px solid #F53501;\n  z-index: 20;\n  opacity: 0.5;\n}\n.tl { top: 40px; left: 40px; border-right: none; border-bottom: none; }\n.tr { top: 40px; right: 40px; border-left: none; border-bottom: none; }\n.bl { bottom: 40px; left: 40px; border-right: none; border-top: none; }\n.br { bottom: 40px; right: 40px; border-left: none; border-top: none; }\n\n.scan-line {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 2px;\n  background: linear-gradient(90deg, transparent, #F53501, transparent);\n  z-index: 5;\n  opacity: 0.1;\n  animation: scan 4s linear infinite;\n}\n\n@keyframes scan { 0% { top: 0; } 100% { top: 100%; } }","js":"window.SceneLifecycle.register('scene-06', {\n  enter() {\n    const root = document.querySelector('[data-scene-id=\"scene-06\"]');\n    if (root) {\n      window.__SVGVIDEO_REFRESH_ICONS(root);\n      root.removeAttribute('data-closing');\n    }\n  },\n  step(index) {\n    const root = document.querySelector('[data-scene-id=\"scene-06\"]');\n    if (!root) return;\n\n    const elements = root.querySelectorAll('[data-step]');\n    elements.forEach(el => {\n      const stepValue = parseInt(el.getAttribute('data-step'));\n      el.setAttribute('data-step-active', index >= stepValue ? 'true' : 'false');\n    });\n\n    // Handle Step 2 special closing animation\n    if (index === 2) {\n      setTimeout(() => {\n        // After showing the logo for a while, trigger the shrink fade-out\n        // This mimics the '向内收缩淡出' requirement\n        // In a real flow, this might be triggered by the timeline manager\n        // root.setAttribute('data-closing', 'true');\n      }, 2000);\n    }\n\n    // Visual reinforcement for Step 0 color shift\n    if (index === 0) {\n      const brackets = root.querySelectorAll('.frame-bracket');\n      brackets.forEach(b => b.style.borderColor = '#0052D9'); // Shift theme to brand blue\n    }\n  },\n  leave() {\n    const root = document.querySelector('[data-scene-id=\"scene-06\"]');\n    if (root) root.setAttribute('data-closing', 'true');\n  }\n});"}]</script>
  <script defer src="https://unpkg.com/lucide@latest"></script>
  <script defer src="https://code.iconify.design/iconify-icon/2.3.0/iconify-icon.min.js"></script>
  <script>
    (function () {
      var state = { sceneId: 'scene-02', step: 0, direction: 1 };
      var previousSceneId = null;
      var exitCleanupTimer = null;
      var isPlaying = false;
      var playTimer = null;
      var progressRaf = null;
      var STEP_INTERVAL_MS = 1400;
      var SCENE_FINISH_PAUSE_MS = 2000;
      var autoplayFromFirstScene = false;
      var progressWrap = document.getElementById('sv-progress-wrap');
      var progressFill = document.getElementById('sv-progress-fill');
      var progressThumb = document.getElementById('sv-progress-thumb');
      var playBtn = document.getElementById('sv-play-btn');
      var expandBtn = document.getElementById('sv-expand-btn');
      var statusText = document.getElementById('sv-status-text');
      var sceneButtonList = Array.prototype.slice.call(document.querySelectorAll('[data-panel-scene-id]'));
      var sceneRetryButtonList = Array.prototype.slice.call(document.querySelectorAll('[data-retry-scene-id]'));
      var editorOverlay = document.getElementById('sv-editor-overlay');
      var editorBackdrop = document.getElementById('sv-editor-backdrop');
      var editorSheet = document.getElementById('sv-editor-sheet');
      var editorResizeHandle = document.getElementById('sv-editor-resize-handle');
      var editorCloseBtn = document.getElementById('sv-editor-close-btn');
      var editorSaveBtn = document.getElementById('sv-editor-save-btn');
      var editorList = document.getElementById('sv-editor-list');
      var editorSaveTip = document.getElementById('sv-editor-save-tip');
      var editorTipTimer = null;
      var isEditorOpen = false;
      var isEditorDirty = false;
      var editorHeightVh = 50;
      var hostCaps = { canRetry: false, canEditPanel: false, locale: 'zh', theme: 'dark' };
      var metaJson = document.getElementById('__SVGVIDEO_META__');
      var meta = { scenes: [] };
      try {
        meta = JSON.parse((metaJson && metaJson.textContent) || '{}');
      } catch (e) {
        meta = { scenes: [] };
      }
      var metaSceneMap = {};
      var metaScenes = Array.isArray(meta.scenes) ? meta.scenes : [];
      metaScenes.forEach(function (scene) {
        if (scene && typeof scene.id === 'string' && scene.id) metaSceneMap[scene.id] = scene;
      });
      function refreshFrameworkIcons(root) {
        var refreshRoot = root || document;
        try {
          if (window.lucide && typeof window.lucide.createIcons === 'function') {
            window.lucide.createIcons({ root: refreshRoot });
          }
        } catch (iconErr) {
          console.warn('[svg-video] lucide refresh failed', iconErr);
        }
      }
      window.__SVGVIDEO_REFRESH_ICONS = refreshFrameworkIcons;
      var sceneModels = Array.prototype.slice.call(document.querySelectorAll('#stage > [data-scene-id]')).map(function (node, index) {
        var sceneId = node.getAttribute('data-scene-id') || ('scene-' + (index + 1));
        var metaScene = metaSceneMap[sceneId] || {};
        var sceneTitle = typeof metaScene.title === 'string' && metaScene.title ? metaScene.title : ('分镜' + (index + 1));
        var sceneSteps = Math.max(1, Number(metaScene.steps) || 1);
        var sceneStatus = typeof metaScene.status === 'string' ? metaScene.status : 'pending';
        var scenePrompt = typeof metaScene.prompt === 'string' ? metaScene.prompt : '';
        var sceneScript = typeof metaScene.scriptText === 'string' ? metaScene.scriptText : '';
        var sceneAudioObjectKey = typeof metaScene.audioObjectKey === 'string' ? metaScene.audioObjectKey : '';
        var sceneAudioDurationMs = Number(metaScene.audioDurationMs) > 0 ? Number(metaScene.audioDurationMs) : 0;
        var sceneVoiceName = typeof metaScene.voiceName === 'string' ? metaScene.voiceName : '';
        var relatedSceneIds = Array.isArray(metaScene.relatedSceneIds) ? metaScene.relatedSceneIds : [];
        return {
          id: sceneId,
          title: sceneTitle,
          steps: sceneSteps,
          status: sceneStatus,
          prompt: scenePrompt,
          scriptText: sceneScript,
          audioObjectKey: sceneAudioObjectKey,
          audioDurationMs: sceneAudioDurationMs,
          voiceName: sceneVoiceName,
          relatedSceneIds: relatedSceneIds
        };
      });
      if (!sceneModels.length && metaScenes.length) {
        sceneModels = metaScenes.map(function (scene, index) {
          return {
            id: scene.id || ('scene-' + (index + 1)),
            title: scene.title || ('分镜' + (index + 1)),
            steps: Math.max(1, Number(scene.steps) || 1),
            status: typeof scene.status === 'string' ? scene.status : 'pending',
            prompt: typeof scene.prompt === 'string' ? scene.prompt : '',
            scriptText: typeof scene.scriptText === 'string' ? scene.scriptText : '',
            audioObjectKey: typeof scene.audioObjectKey === 'string' ? scene.audioObjectKey : '',
            audioDurationMs: Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0,
            voiceName: typeof scene.voiceName === 'string' ? scene.voiceName : '',
            relatedSceneIds: Array.isArray(scene.relatedSceneIds) ? scene.relatedSceneIds : []
          };
        });
      }
      function i18nText(zh, en) {
        return hostCaps.locale === 'en' ? en : zh;
      }
      function applyI18nTexts() {
        var toolbarTitleEl = document.getElementById('sv-toolbar-title');
        var titleEl = document.getElementById('sv-editor-header-title');
        if (toolbarTitleEl) toolbarTitleEl.textContent = i18nText('分镜面板', 'Storyboard');
        if (titleEl) titleEl.textContent = i18nText('分镜详情编辑', 'Storyboard details');
        if (expandBtn) {
          var expandText = i18nText('展开分镜详情', 'Open storyboard details');
          expandBtn.setAttribute('aria-label', expandText);
          expandBtn.setAttribute('title', expandText);
        }
        if (editorSaveBtn) editorSaveBtn.textContent = isEditorDirty ? i18nText('保存*', 'Save*') : i18nText('保存', 'Save');
        if (editorCloseBtn) editorCloseBtn.textContent = i18nText('关闭', 'Close');
        if (editorSaveTip) editorSaveTip.textContent = i18nText('已保存', 'Saved');
      }
      function clampEditorHeightVh(value) {
        return Math.max(32, Math.min(80, Number(value) || 50));
      }
      function applyEditorHeight(vh) {
        editorHeightVh = clampEditorHeightVh(vh);
        document.documentElement.style.setProperty('--sv-editor-height', editorHeightVh + 'vh');
      }
      function persistMetaToScript() {
        meta.title = typeof meta.title === 'string' ? meta.title : '';
        meta.version = meta.version || 1;
        meta.scenes = sceneModels.map(function (scene) {
          return {
            id: scene.id,
            title: scene.title || '',
            steps: Math.max(1, Number(scene.steps) || 1),
            status: scene.status || 'pending',
            prompt: scene.prompt || '',
            scriptText: scene.scriptText || '',
            audioObjectKey: scene.audioObjectKey || '',
            audioDurationMs: Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0,
            voiceName: scene.voiceName || '',
            relatedSceneIds: Array.isArray(scene.relatedSceneIds) ? scene.relatedSceneIds : []
          };
        });
        if (metaJson) metaJson.textContent = JSON.stringify(meta);
      }
      function showSavedTip() {
        if (!editorSaveTip) return;
        if (editorTipTimer) {
          clearTimeout(editorTipTimer);
          editorTipTimer = null;
        }
        editorSaveTip.classList.add('is-visible');
        editorTipTimer = setTimeout(function () {
          editorSaveTip.classList.remove('is-visible');
        }, 1200);
      }
      function markEditorDirty() {
        isEditorDirty = true;
        applyI18nTexts();
      }
      function clearEditorDirty() {
        isEditorDirty = false;
        applyI18nTexts();
      }
      function getStatusLabel(status) {
        if (status === 'success') return i18nText('已生成', 'Done');
        if (status === 'generating') return i18nText('生成中', 'Generating');
        if (status === 'failed') return i18nText('失败', 'Failed');
        return i18nText('未生成', 'Pending');
      }
      function getStatusClass(status) {
        if (status === 'generating') return 'is-generating';
        if (status === 'success') return 'is-success';
        return 'is-failed';
      }
      function getRetryButtonInnerHtml(isGenerating) {
        if (isGenerating) return '<span class="scene-chip-retry-spinner"></span>';
        return '<svg class="scene-chip-retry-icon" viewBox="0 0 1024 1024" width="16" height="16" fill="currentColor"><path d="M698.569 531.322a39.825 39.825 0 0 0-23.898 7.949c-17.702 13.216-21.34 38.28-8.124 55.982l95.716 128.212c7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949c17.702-13.216 21.34-38.28 8.124-55.982l-95.716-128.212c-7.853-10.521-19.892-16.074-32.084-16.073z" /><path d="M922.498 563.818a39.825 39.825 0 0 0-23.898 7.949l-128.212 95.716c-17.703 13.216-21.34 38.28-8.124 55.982 7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949l128.212-95.716c17.702-13.216 21.34-38.28 8.124-55.982-7.854-10.521-19.893-16.074-32.084-16.073zM229.652 282.148a39.825 39.825 0 0 0-23.898 7.949c-17.702 13.216-21.34 38.28-8.124 55.982l95.716 128.212c7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949c17.702-13.216 21.34-38.28 8.124-55.982l-95.716-128.212c-7.854-10.521-19.892-16.074-32.084-16.073z" /><path d="M229.652 282.148a39.825 39.825 0 0 0-23.898 7.949L77.542 385.813c-17.702 13.216-21.34 38.28-8.124 55.982 7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949l128.213-95.716c17.702-13.216 21.34-38.28 8.124-55.982-7.855-10.521-19.893-16.073-32.085-16.073z" /><path d="M614.968 763.65c-44.13 18.171-94.005 25.121-146.168 16.968C353.747 762.636 261.364 670.253 243.381 555.2c-9.681-61.936 1.932-120.646 28.337-170.344l-58.657-58.657c-40.139 64.442-60.11 142.746-50.806 226.152 17.993 161.306 148.088 291.401 309.394 309.394 62.041 6.92 121.259-2.357 174.048-24.083 26.535-10.921 33.625-45.203 13.335-65.493l-0.098-0.098c-11.555-11.555-28.854-14.643-43.966-8.421zM409.033 260.35c44.131-18.171 94.007-25.122 146.169-16.968 115.051 17.985 207.431 110.365 225.416 225.416 9.682 61.935-1.931 120.646-28.337 170.346l58.658 58.658c40.139-64.443 60.109-142.747 50.805-226.155-17.993-161.305-148.087-291.399-309.391-309.391-62.042-6.92-121.26 2.356-174.05 24.082-26.535 10.921-33.625 45.203-13.335 65.493l0.099 0.099c11.555 11.554 28.854 14.642 43.966 8.42z" /></svg>';
      }
      function setSceneStatus(sceneId, status) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return;
        sceneModels[index].status = status;
        persistMetaToScript();
        var statusClass = getStatusClass(status);
        var chipWrap = document.querySelector('[data-chip-scene-id="' + sceneId + '"]');
        if (chipWrap) {
          chipWrap.classList.remove('is-success', 'is-failed', 'is-generating');
          chipWrap.classList.add(statusClass);
          var chipBtn = chipWrap.querySelector('.scene-chip');
          if (chipBtn) {
            chipBtn.classList.remove('is-success', 'is-failed', 'is-generating');
            chipBtn.classList.add(statusClass);
          }
          var retryBtn = chipWrap.querySelector('.scene-chip-retry');
          if (retryBtn) {
            retryBtn.innerHTML = getRetryButtonInnerHtml(status === 'generating');
            if (status === 'generating') retryBtn.setAttribute('disabled', 'disabled');
            else retryBtn.removeAttribute('disabled');
          }
        }
        renderStatus();
      }
      function requestSceneRetry(sceneId) {
        if (!hostCaps.canRetry) return;
        var idx = getSceneIndexById(sceneId);
        if (idx < 0) return;
        var scene = sceneModels[idx];
        setSceneStatus(sceneId, 'generating');
        focusScene(sceneId);
        if (window.parent && window.parent !== window) {
          window.parent.postMessage(
            { type: '__SVGVIDEO_RETRY_SCENE', sceneId: sceneId, prompt: scene.prompt || '' },
            '*'
          );
        }
      }
      function renderEditorList() {
        if (!editorList) return;
        editorList.innerHTML = '';
        var fragment = document.createDocumentFragment();
        sceneModels.forEach(function (scene, index) {
          var item = document.createElement('section');
          item.className = 'sv-editor-item';
          item.setAttribute('data-editor-scene-id', scene.id);

          var head = document.createElement('div');
          head.className = 'sv-editor-item-head';

          var jumpBtn = document.createElement('button');
          jumpBtn.type = 'button';
          jumpBtn.className = 'sv-editor-item-title';
          jumpBtn.textContent = i18nText('分镜', 'Scene') + (index + 1) + ' · ' + (scene.title || '');
          jumpBtn.addEventListener('click', function () {
            focusScene(scene.id);
          });
          head.appendChild(jumpBtn);

          var statusWrap = document.createElement('div');
          statusWrap.className = 'sv-editor-status-wrap';
          var status = document.createElement('span');
          status.className = 'sv-editor-status';
          status.textContent = getStatusLabel(scene.status);
          statusWrap.appendChild(status);
          var retryBtn = document.createElement('button');
          retryBtn.type = 'button';
          retryBtn.className = 'scene-chip-retry sv-editor-retry';
          retryBtn.setAttribute('aria-label', i18nText('重新生成当前分镜', 'Retry this scene'));
          retryBtn.setAttribute('title', i18nText('重新生成当前分镜', 'Retry this scene'));
          retryBtn.innerHTML = getRetryButtonInnerHtml(scene.status === 'generating');
          if (scene.status === 'generating' || !hostCaps.canRetry) retryBtn.setAttribute('disabled', 'disabled');
          retryBtn.addEventListener('click', function (event) {
            event.preventDefault();
            event.stopPropagation();
            requestSceneRetry(scene.id);
            if (isEditorOpen) renderEditorList();
          });
          statusWrap.appendChild(retryBtn);
          head.appendChild(statusWrap);

          item.appendChild(head);

          var scriptField = document.createElement('label');
          scriptField.className = 'sv-editor-field';
          var scriptLabel = document.createElement('span');
          scriptLabel.className = 'sv-editor-label';
          scriptLabel.textContent = i18nText('脚本', 'Script');
          var scriptInput = document.createElement('div');
          scriptInput.className = 'sv-editor-script-view';
          scriptInput.setAttribute('data-field-scene-id', scene.id);
          scriptInput.textContent = scene.scriptText || '';
          scriptField.appendChild(scriptLabel);
          scriptField.appendChild(scriptInput);
          item.appendChild(scriptField);

          var promptField = document.createElement('label');
          promptField.className = 'sv-editor-field';
          var promptLabel = document.createElement('span');
          promptLabel.className = 'sv-editor-label';
          promptLabel.textContent = i18nText('提示词', 'Prompt');
          var promptInput = document.createElement('textarea');
          promptInput.className = 'sv-editor-textarea';
          promptInput.setAttribute('data-field-scene-id', scene.id);
          promptInput.setAttribute('data-field', 'prompt');
          promptInput.value = scene.prompt || '';
          promptInput.addEventListener('click', function (event) {
            event.stopPropagation();
          });
          promptInput.addEventListener('input', function () {
            scene.prompt = promptInput.value;
            markEditorDirty();
          });
          promptField.appendChild(promptLabel);
          promptField.appendChild(promptInput);
          item.appendChild(promptField);
          item.addEventListener('click', function () {
            focusScene(scene.id);
          });

          fragment.appendChild(item);
        });
        editorList.appendChild(fragment);
        highlightActiveEditorItem();
      }
      function highlightActiveEditorItem() {
        if (!editorList) return;
        var itemList = Array.prototype.slice.call(editorList.querySelectorAll('[data-editor-scene-id]'));
        itemList.forEach(function (item) {
          if (item.getAttribute('data-editor-scene-id') === state.sceneId) item.classList.add('is-active');
          else item.classList.remove('is-active');
        });
      }
      function openEditor() {
        if (!hostCaps.canEditPanel) return;
        if (!editorOverlay) return;
        renderEditorList();
        applyEditorHeight(editorHeightVh);
        editorOverlay.classList.add('is-open');
        editorOverlay.setAttribute('aria-hidden', 'false');
        document.body.classList.add('sv-editor-open');
        isEditorOpen = true;
      }
      function closeEditor() {
        if (!editorOverlay) return;
        editorOverlay.classList.remove('is-open');
        editorOverlay.setAttribute('aria-hidden', 'true');
        document.body.classList.remove('sv-editor-open');
        isEditorOpen = false;
      }
      function saveEditor() {
        persistMetaToScript();
        clearEditorDirty();
        showSavedTip();
        if (window.parent && window.parent !== window) {
          window.parent.postMessage({ type: '__SVGVIDEO_META_UPDATED', meta: meta }, '*');
        }
      }
      function getTotalSteps() {
        return sceneModels.reduce(function (sum, scene) { return sum + Math.max(1, Number(scene.steps) || 1); }, 0);
      }
      function getSceneIndexById(sceneId) {
        for (var i = 0; i < sceneModels.length; i++) {
          if (sceneModels[i].id === sceneId) return i;
        }
        return -1;
      }
      function getSceneInitialStep(sceneId) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return 0;
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        return Math.max(0, maxSteps - 1);
      }
      function focusScene(sceneId) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return;
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        stopPlayback();
        window.__SVGVIDEO_SET_STATE(sceneId, 0, 1);
        if (maxSteps > 1) {
          setTimeout(function () {
            window.__SVGVIDEO_SET_STATE(sceneId, Math.max(0, maxSteps - 1), 1);
          }, 90);
        }
      }
      function getProgressPercent(sceneId, step) {
        var total = getTotalSteps();
        if (!total) return 0;
        var index = getSceneIndexById(sceneId);
        if (index < 0) return 0;
        var completed = 0;
        for (var i = 0; i < index; i++) completed += Math.max(1, Number(sceneModels[i].steps) || 1);
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        var localStep = Math.max(0, Math.min(maxSteps - 1, Number(step) || 0));
        return Math.max(0, Math.min(100, ((completed + localStep) / total) * 100));
      }
      function updateProgressUi(percent) {
        var pct = Math.max(0, Math.min(100, percent || 0));
        if (progressFill) progressFill.style.width = pct + '%';
        if (progressThumb) progressThumb.style.left = pct + '%';
      }
      function stopProgressAnimation() {
        if (progressRaf) {
          cancelAnimationFrame(progressRaf);
          progressRaf = null;
        }
      }
      function startProgressSegment(fromPercent, toPercent, durationMs) {
        stopProgressAnimation();
        var from = Math.max(0, Math.min(100, Number(fromPercent) || 0));
        var to = Math.max(0, Math.min(100, Number(toPercent) || 0));
        var duration = Math.max(1, Number(durationMs) || 1);
        if (duration <= 1 || to <= from) {
          updateProgressUi(to);
          return;
        }
        var startAt = performance.now();
        var tick = function (now) {
          if (!isPlaying) {
            stopProgressAnimation();
            return;
          }
          var elapsed = now - startAt;
          var ratio = Math.max(0, Math.min(1, elapsed / duration));
          var current = from + (to - from) * ratio;
          updateProgressUi(current);
          if (ratio < 1) {
            progressRaf = requestAnimationFrame(tick);
          } else {
            stopProgressAnimation();
          }
        };
        progressRaf = requestAnimationFrame(tick);
      }
      function getPlaybackSegment(sceneIndex, step) {
        var scene = sceneModels[sceneIndex];
        if (!scene) return null;
        var currentPercent = getProgressPercent(scene.id, step);
        var maxSteps = Math.max(1, Number(scene.steps) || 1);
        if (step < maxSteps - 1) {
          return {
            from: currentPercent,
            to: getProgressPercent(scene.id, step + 1),
            duration: STEP_INTERVAL_MS
          };
        }
        if (sceneIndex < sceneModels.length - 1) {
          var nextScene = sceneModels[sceneIndex + 1];
          var nextPercent = nextScene ? getProgressPercent(nextScene.id, 0) : currentPercent;
          return {
            from: currentPercent,
            to: nextPercent,
            duration: SCENE_FINISH_PAUSE_MS
          };
        }
        return {
          from: currentPercent,
          to: 100,
          duration: STEP_INTERVAL_MS
        };
      }
      function renderStatus() {
        if (!statusText) return;
        var done = sceneModels.filter(function (scene) { return scene.status === 'success'; }).length;
        var pending = sceneModels.filter(function (scene) { return scene.status === 'pending' || scene.status === 'generating'; }).length;
        var failed = sceneModels.filter(function (scene) { return scene.status === 'failed'; }).length;
        statusText.textContent = '已生成 ' + done + '/' + sceneModels.length + ' · 待生成 ' + pending + ' · 失败 ' + failed;
      }
      function updatePlayButton() {
        if (!playBtn) return;
        playBtn.innerHTML = isPlaying
          ? '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><rect x="6" y="5" width="4" height="14" rx="1"></rect><rect x="14" y="5" width="4" height="14" rx="1"></rect></svg>'
          : '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M7 5v14l11-7z"></path></svg>';
        playBtn.setAttribute('aria-label', isPlaying ? '暂停播放' : '播放分镜');
        playBtn.setAttribute('title', isPlaying ? '暂停播放' : '播放分镜');
      }
      function applyHostCaps() {
        if (hostCaps.canRetry) document.body.classList.add('sv-host-can-retry');
        else document.body.classList.remove('sv-host-can-retry');
        if (hostCaps.canEditPanel) document.body.classList.add('sv-host-can-edit-panel');
        else document.body.classList.remove('sv-host-can-edit-panel');
        if (hostCaps.theme === 'light') document.body.classList.add('sv-theme-light');
        else document.body.classList.remove('sv-theme-light');
      }
      function highlightActiveSceneButton() {
        sceneButtonList.forEach(function (button) {
          var targetId = button.getAttribute('data-panel-scene-id');
          if (targetId === state.sceneId) button.classList.add('is-active');
          else button.classList.remove('is-active');
        });
      }
      function stopPlayback() {
        if (playTimer) {
          clearTimeout(playTimer);
          playTimer = null;
        }
        stopProgressAnimation();
        isPlaying = false;
        updatePlayButton();
      }
      function startPlayback() {
        if (!sceneModels.length) return;
        stopPlayback();
        var sceneIndex = Math.max(0, getSceneIndexById(state.sceneId));
        var step = 0;
        var applyPlaybackState = function (direction) {
          var scene = sceneModels[sceneIndex];
          if (!scene) return false;
          window.__SVGVIDEO_SET_STATE(scene.id, step, direction);
          updateProgressUi(getProgressPercent(scene.id, step));
          var segment = getPlaybackSegment(sceneIndex, step);
          if (segment) startProgressSegment(segment.from, segment.to, segment.duration);
          return true;
        };
        var scheduleAdvance = function (delay) {
          playTimer = setTimeout(function () {
            var currentScene = sceneModels[sceneIndex];
            if (!currentScene) {
              stopPlayback();
              return;
            }
            var maxSteps = Math.max(1, Number(currentScene.steps) || 1);
            if (step < maxSteps - 1) {
              step += 1;
              applyPlaybackState(1);
              scheduleAdvance(STEP_INTERVAL_MS);
              return;
            }
            if (sceneIndex < sceneModels.length - 1) {
              playTimer = setTimeout(function () {
                sceneIndex += 1;
                step = 0;
                if (!applyPlaybackState(1)) {
                  stopPlayback();
                  return;
                }
                scheduleAdvance(STEP_INTERVAL_MS);
              }, SCENE_FINISH_PAUSE_MS);
              return;
            }
            stopPlayback();
          }, delay);
        };
        isPlaying = true;
        updatePlayButton();
        if (!applyPlaybackState(1)) {
          stopPlayback();
          return;
        }
        scheduleAdvance(STEP_INTERVAL_MS);
      }
      window.SceneLifecycle = {
        handlers: {},
        register: function (sceneId, handler) { this.handlers[sceneId] = handler || {}; }
      };

      (function () {
        var sceneDataJson = document.getElementById('__SVGVIDEO_SCENE_DATA__');
        var runtimeScenes = [];
        try {
          runtimeScenes = JSON.parse((sceneDataJson && sceneDataJson.textContent) || '[]');
        } catch (_e) {
          runtimeScenes = [];
        }
        runtimeScenes.forEach(function (scene) {
          if (!scene || typeof scene.id !== 'string') return;
          var js = typeof scene.js === 'string' ? scene.js.trim() : '';
          if (!js) return;
          try {
            var factory = new Function(js);
            factory.call(window);
          } catch (err) {
            console.error('[svg-video] scene runtime failed', scene.id, err);
          }
        });
        refreshFrameworkIcons(document);
      })();

      function applyStepVisibility(sceneEl) {
        var stepNodes = sceneEl.querySelectorAll('[data-step]');
        stepNodes.forEach(function (node) {
          var minStep = Number(node.getAttribute('data-step') || '0');
          var visible = state.step >= minStep;
          node.style.opacity = visible ? '1' : '0';
          node.style.visibility = visible ? 'visible' : 'hidden';
          node.style.pointerEvents = visible ? 'auto' : 'none';
          node.style.transform = visible ? 'translateY(0)' : 'translateY(8px)';
          node.style.filter = visible ? 'blur(0px)' : 'blur(4px)';
        });
      }
      function applySceneState() {
        var scenes = document.querySelectorAll('#stage > [data-scene-id]');
        var currentSceneEl = null;
        var previousSceneEl = null;
        scenes.forEach(function (sceneEl) {
          var sceneId = sceneEl.getAttribute('data-scene-id');
          if (sceneId === state.sceneId) currentSceneEl = sceneEl;
          if (sceneId === previousSceneId) previousSceneEl = sceneEl;
        });
        var direction = state.direction >= 0 ? 1 : -1;
        document.documentElement.style.setProperty('--scene-enter-offset', direction > 0 ? '56px' : '-56px');
        document.documentElement.style.setProperty('--scene-exit-offset', direction > 0 ? '-56px' : '56px');
        if (exitCleanupTimer) {
          clearTimeout(exitCleanupTimer);
          exitCleanupTimer = null;
        }
        scenes.forEach(function (sceneEl) {
          if (sceneEl !== currentSceneEl && sceneEl !== previousSceneEl) {
            sceneEl.classList.remove('scene-active');
            sceneEl.classList.remove('scene-exit');
          }
        });
        if (previousSceneEl && previousSceneEl !== currentSceneEl) {
          previousSceneEl.classList.remove('scene-active');
          previousSceneEl.classList.add('scene-exit');
        }
        if (currentSceneEl) {
          currentSceneEl.classList.remove('scene-exit');
          currentSceneEl.classList.add('scene-active');
          applyStepVisibility(currentSceneEl);
        }
        if (previousSceneEl && previousSceneEl !== currentSceneEl) {
          exitCleanupTimer = setTimeout(function () { previousSceneEl.classList.remove('scene-exit'); }, 620);
        }
        if (previousSceneId !== state.sceneId) {
          if (previousSceneId && window.SceneLifecycle.handlers[previousSceneId] && typeof window.SceneLifecycle.handlers[previousSceneId].leave === 'function') {
            try { window.SceneLifecycle.handlers[previousSceneId].leave(); } catch (e) {}
          }
          if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].enter === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].enter(); } catch (e) {}
          }
        }
        if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].step === 'function') {
          try { window.SceneLifecycle.handlers[state.sceneId].step(state.step); } catch (e) {}
        }
        if (currentSceneEl) {
          refreshFrameworkIcons(currentSceneEl);
        }
        previousSceneId = state.sceneId;
        highlightActiveSceneButton();
        highlightActiveEditorItem();
        updateProgressUi(getProgressPercent(state.sceneId, state.step));
      }
      window.__SVGVIDEO_SET_STATE = function (sceneId, step, direction) {
        if (typeof sceneId === 'string' && sceneId) {
          if (typeof direction === 'number' && Number.isFinite(direction)) {
            state.direction = direction >= 0 ? 1 : -1;
          } else {
            var nextIndex = getSceneIndexById(sceneId);
            var prevIndex = getSceneIndexById(state.sceneId);
            if (nextIndex !== -1 && prevIndex !== -1) state.direction = nextIndex >= prevIndex ? 1 : -1;
          }
          state.sceneId = sceneId;
        }
        if (typeof step === 'number' && Number.isFinite(step)) state.step = Math.max(0, Math.floor(step));
        applySceneState();
      };
      if (state.sceneId && getSceneIndexById(state.sceneId) === -1 && sceneModels.length) {
        state.sceneId = sceneModels[0].id;
      }
      if (playBtn) {
        playBtn.addEventListener('click', function () {
          if (isPlaying) stopPlayback();
          else startPlayback();
        });
      }
      if (expandBtn) {
        expandBtn.addEventListener('click', function () {
          if (isEditorOpen) closeEditor();
          else openEditor();
        });
      }
      if (editorCloseBtn) {
        editorCloseBtn.addEventListener('click', closeEditor);
      }
      if (editorBackdrop) {
        editorBackdrop.addEventListener('click', closeEditor);
      }
      if (editorSaveBtn) {
        editorSaveBtn.addEventListener('click', saveEditor);
      }
      if (editorResizeHandle && editorSheet) {
        editorResizeHandle.addEventListener('mousedown', function (event) {
          event.preventDefault();
          var startY = event.clientY;
          var startHeightPx = (window.innerHeight * editorHeightVh) / 100;
          var onMove = function (moveEvent) {
            var delta = startY - moveEvent.clientY;
            var nextHeightPx = startHeightPx + delta;
            var nextHeightVh = (nextHeightPx / Math.max(1, window.innerHeight)) * 100;
            applyEditorHeight(nextHeightVh);
          };
          var onUp = function () {
            window.removeEventListener('mousemove', onMove);
            window.removeEventListener('mouseup', onUp);
          };
          window.addEventListener('mousemove', onMove);
          window.addEventListener('mouseup', onUp);
        });
      }
      sceneButtonList.forEach(function (button) {
        button.addEventListener('click', function () {
          var sceneId = button.getAttribute('data-panel-scene-id');
          if (!sceneId) return;
          focusScene(sceneId);
        });
      });
      sceneRetryButtonList.forEach(function (button) {
        button.addEventListener('click', function (event) {
          event.preventDefault();
          event.stopPropagation();
          var sceneId = button.getAttribute('data-retry-scene-id');
          if (!sceneId) return;
          requestSceneRetry(sceneId);
        });
      });
      if (progressWrap) {
        progressWrap.addEventListener('click', function (event) {
          var rect = progressWrap.getBoundingClientRect();
          var pct = Math.max(0, Math.min(100, ((event.clientX - rect.left) / rect.width) * 100));
          var totalSteps = getTotalSteps();
          var targetStep = Math.round((pct / 100) * totalSteps);
          var accumulated = 0;
          for (var i = 0; i < sceneModels.length; i++) {
            var sceneSteps = Math.max(1, Number(sceneModels[i].steps) || 1);
            if (accumulated + sceneSteps > targetStep) {
              var localStep = Math.max(0, Math.min(sceneSteps - 1, targetStep - accumulated));
              stopPlayback();
              window.__SVGVIDEO_SET_STATE(sceneModels[i].id, localStep, 1);
              updateProgressUi(pct);
              return;
            }
            accumulated += sceneSteps;
          }
        });
      }
      window.addEventListener('message', function (event) {
        var data = event && event.data;
        if (!data || typeof data.type !== 'string') return;
        if (data.type === '__SVGVIDEO_SET_STATE') {
          window.__SVGVIDEO_SET_STATE(data.sceneId, data.step, data.direction);
          return;
        }
        if (data.type === '__SVGVIDEO_PLAY') {
          startPlayback();
          return;
        }
        if (data.type === '__SVGVIDEO_STOP') {
          stopPlayback();
          return;
        }
        if (data.type === '__SVGVIDEO_SET_HOST_CAPS') {
          hostCaps.canRetry = Boolean(data.canRetry);
          hostCaps.canEditPanel = Boolean(data.canEditPanel);
          hostCaps.locale = data.locale === 'en' ? 'en' : 'zh';
          hostCaps.theme = data.theme === 'light' ? 'light' : 'dark';
          applyI18nTexts();
          applyHostCaps();
          if (isEditorOpen) renderEditorList();
          return;
        }
        if (data.type === '__SVGVIDEO_SET_SCENE_STATUS') {
          var sceneId = typeof data.sceneId === 'string' ? data.sceneId : '';
          var status = typeof data.status === 'string' ? data.status : '';
          if (sceneId && status) {
            setSceneStatus(sceneId, status);
            if (isEditorOpen) renderEditorList();
          }
          return;
        }
        if (data.type === '__SVGVIDEO_SET_RECORDING') {
          if (data && data.active) {
            document.body.classList.add('sv-recording');
            // 如果指定了初始分镜，无过渡动画地跳转过去，避免录制开头残留旧分镜画面
            if (data.sceneId) {
              var noTransStyle = document.createElement('style');
              noTransStyle.id = 'sv-no-transition';
              noTransStyle.textContent = '.scene, [data-step] { transition: none !important; }';
              document.head.appendChild(noTransStyle);
              window.__SVGVIDEO_SET_STATE(data.sceneId, 0, 1);
              // 强制 reflow 后恢复过渡动画
              void document.body.offsetHeight;
              requestAnimationFrame(function () {
                var s = document.getElementById('sv-no-transition');
                if (s) s.remove();
              });
            }
          } else {
            document.body.classList.remove('sv-recording');
          }
          return;
        }
        if (data.type === '__SVGVIDEO_SET_META' && data.meta && typeof data.meta === 'object') {
          meta = data.meta;
          var freshScenes = Array.isArray(meta.scenes) ? meta.scenes : [];
          freshScenes.forEach(function (scene) {
            var idx = getSceneIndexById(scene.id);
            if (idx < 0) return;
            sceneModels[idx].prompt = typeof scene.prompt === 'string' ? scene.prompt : '';
            sceneModels[idx].scriptText = typeof scene.scriptText === 'string' ? scene.scriptText : '';
            sceneModels[idx].audioObjectKey = typeof scene.audioObjectKey === 'string' ? scene.audioObjectKey : '';
            sceneModels[idx].audioDurationMs = Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0;
            sceneModels[idx].voiceName = typeof scene.voiceName === 'string' ? scene.voiceName : '';
          });
          persistMetaToScript();
          if (isEditorOpen) renderEditorList();
        }
      });
      document.addEventListener('keydown', function (event) {
        if (event.key === 'Escape' && isEditorOpen) closeEditor();
      });
      window.__SVGVIDEO_PLAY = startPlayback;
      window.__SVGVIDEO_STOP = stopPlayback;
      window.__SVGVIDEO_OPEN_EDITOR = openEditor;
      window.__SVGVIDEO_CLOSE_EDITOR = closeEditor;
      applyEditorHeight(editorHeightVh);
      renderStatus();
      updatePlayButton();
      applyHostCaps();
      clearEditorDirty();
      applyI18nTexts();
      applySceneState();
      if (autoplayFromFirstScene && sceneModels.length) {
        state.sceneId = sceneModels[0].id;
        state.step = 0;
        state.direction = 1;
        applySceneState();
        startPlayback();
      }
    })();
  </script>
</body>
</html>12:T3a04,<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>3D Glass Text Animation</title>
<style>
    /* 基础重置与全屏居中 */
    body, html {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
        background-color: #f0f4f8; /* 亮色主题底色 */
        display: flex;
        justify-content: center;
        align-items: center;
        overflow: hidden;
        font-family: 'Impact', 'Arial Black', sans-serif;
        touch-action: none; /* 阻止移动端默认滚动，便于拖拽 */
    }

    /* 响应式缩放容器 */
    .scale-wrapper {
        position: relative;
        width: 1200px;
        height: 700px;
        /* 默认居中，利用 JS 动态计算缩放比例保持画面完整 */
        transform-origin: center center;
    }

    /* 背景层：亮色渐变与光斑 */
    .bg-layer {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 1;
        border-radius: 16px;
        overflow: hidden;
        background: radial-gradient(circle at 50% 50%, #ffffff 0%, #e2eaf4 100%);
        box-shadow: 0 20px 60px rgba(150, 170, 200, 0.2);
    }

    /* 3D 场景容器：开启透视 */
    .scene {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 2;
        perspective: 1500px;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    /* 旋转组：承载所有 3D 图层 */
    .text-group {
        position: relative;
        width: 100%;
        height: 100%;
        transform-style: preserve-3d;
        /* 初始角度将在 JS 中设置并更新 */
        cursor: grab;
    }
    
    .text-group:active {
        cursor: grabbing;
    }

    /* 每一层 SVG 的统一样式 */
    .slice {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
        pointer-events: none; /* 避免遮挡鼠标事件 */
    }

    .slice svg {
        width: 100%;
        height: 100%;
        overflow: visible;
    }

    /* 中文副标题排版 */
    .subtitle-container {
        position: absolute;
        bottom: 80px;
        width: 100%;
        text-align: center;
        z-index: 3;
        pointer-events: none;
    }

    .subtitle {
        font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
        font-size: 20px;
        font-weight: 300;
        color: #798da3;
        letter-spacing: 16px;
        text-transform: uppercase;
        opacity: 0;
        transform: translateY(20px);
        animation: fadeUp 1.5s cubic-bezier(0.2, 0.8, 0.2, 1) 1s forwards;
        text-shadow: 0 2px 4px rgba(255, 255, 255, 0.8);
    }

    /* 装饰线 */
    .deco-line {
        width: 60px;
        height: 1px;
        background: #aab8c8;
        margin: 15px auto 0;
        opacity: 0;
        animation: expandLine 1s cubic-bezier(0.2, 0.8, 0.2, 1) 1.5s forwards;
    }

    @keyframes fadeUp {
        to { opacity: 1; transform: translateY(0); }
    }
    @keyframes expandLine {
        to { opacity: 0.6; width: 120px; }
    }

    /* 交互提示 */
    .hint {
        position: absolute;
        top: 40px;
        width: 100%;
        text-align: center;
        font-family: 'PingFang SC', sans-serif;
        font-size: 14px;
        color: #aab8c8;
        letter-spacing: 2px;
        z-index: 3;
        opacity: 0;
        animation: fadeInOut 4s ease-in-out 2s forwards;
        pointer-events: none;
    }
    @keyframes fadeInOut {
        0% { opacity: 0; }
        20% { opacity: 0.8; }
        80% { opacity: 0.8; }
        100% { opacity: 0; }
    }
</style>
</head>
<body>

<div class="scale-wrapper" id="scaleWrapper">
    <!-- 1. 背景层 (SVG 光斑与网格) -->
    <div class="bg-layer">
        <svg width="100%" height="100%" viewBox="0 0 1200 700" preserveAspectRatio="xMidYMid slice">
            <defs>
                <filter id="superBlur" x="-50%" y="-50%" width="200%" height="200%">
                    <feGaussianBlur stdDeviation="80" />
                </filter>
                <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
                    <path d="M 40 0 L 0 0 0 40" fill="none" stroke="rgba(150, 170, 200, 0.1)" stroke-width="1"/>
                </pattern>
            </defs>
            
            <!-- 极简网格 -->
            <rect width="100%" height="100%" fill="url(#grid)" />

            <!-- 缓慢漂浮的玻璃态光斑 -->
            <g filter="url(#superBlur)">
                <circle cx="300" cy="200" r="150" fill="#a1c4fd" opacity="0.5">
                    <animate attributeName="cx" values="300; 500; 300" dur="15s" ease="ease-in-out" repeatCount="indefinite"/>
                    <animate attributeName="cy" values="200; 400; 200" dur="18s" ease="ease-in-out" repeatCount="indefinite"/>
                </circle>
                <circle cx="900" cy="500" r="180" fill="#c2e9fb" opacity="0.6">
                    <animate attributeName="cx" values="900; 700; 900" dur="20s" ease="ease-in-out" repeatCount="indefinite"/>
                    <animate attributeName="cy" values="500; 300; 500" dur="16s" ease="ease-in-out" repeatCount="indefinite"/>
                </circle>
                <circle cx="600" cy="350" r="250" fill="#fdfbfb" opacity="0.8">
                    <animate attributeName="r" values="250; 300; 250" dur="12s" ease="ease-in-out" repeatCount="indefinite"/>
                </circle>
            </g>
        </svg>
    </div>

    <!-- 交互提示 -->
    <div class="hint">拖拽以自由旋转视角</div>

    <!-- 2. 核心 3D 文本场景 -->
    <div class="scene" id="sceneContainer">
        <div class="text-group" id="textGroup">
            <!-- JS 将动态生成多层 SVG 挤出 3D 玻璃厚度 -->
        </div>
    </div>

    <!-- 3. 前景字幕排版 -->
    <div class="subtitle-container">
        <div class="subtitle">全 矢 量 玻 璃 态 空 间 渲 染</div>
        <div class="deco-line"></div>
    </div>
</div>

<script>
    /**
     * 1. 响应式缩放逻辑
     * 保持 1200x700 的比例，在浏览器窗口中完美居中缩放
     */
    const wrapper = document.getElementById('scaleWrapper');
    const TARGET_WIDTH = 1200;
    const TARGET_HEIGHT = 700;

    function handleResize() {
        const winW = window.innerWidth;
        const winH = window.innerHeight;
        const scaleX = winW / TARGET_WIDTH;
        const scaleY = winH / TARGET_HEIGHT;
        // 留出一点边距，取最小缩放比
        const scale = Math.min(scaleX, scaleY) * 0.95; 
        wrapper.style.transform = `scale(${scale})`;
    }
    window.addEventListener('resize', handleResize);
    handleResize(); // 初始化调用

    /**
     * 2. 生成 3D 玻璃文本层
     * 核心思想：利用 DOM 叠层 + CSS translateZ 模拟 3D 实体的厚度 (Isometric / Extrusion)
     * 不使用 Canvas，纯 SVG 高清渲染
     */
    const textGroup = document.getElementById('textGroup');
    const textContent = "SvgAnimate";
    const LAYERS = 50; // 厚度层数，层数越多越平滑，但影响性能，50是甜点值
    const DEPTH_STEP = 1.2; // 每层 Z 轴间距 (px)
    
    // 预定义 SVG 滤镜和渐变资源，只在第一层生成一次供后续复用
    const defsHTML = `
        <defs>
            <!-- 玻璃高光流光渐变 -->
            <linearGradient id="shineGrad" x1="-100%" y1="0%" x2="0%" y2="0%">
                <stop offset="0%" stop-color="rgba(255,255,255,0)" />
                <stop offset="30%" stop-color="rgba(255,255,255,0)" />
                <stop offset="50%" stop-color="rgba(255,255,255,0.9)" />
                <stop offset="70%" stop-color="rgba(255,255,255,0)" />
                <stop offset="100%" stop-color="rgba(255,255,255,0)" />
                <animate attributeName="x1" values="-150%; 250%" dur="4s" repeatCount="indefinite" />
                <animate attributeName="x2" values="-50%; 350%" dur="4s" repeatCount="indefinite" />
            </linearGradient>

            <!-- 基础玻璃表面渐变 -->
            <linearGradient id="glassSurface" x1="0%" y1="0%" x2="0%" y2="100%">
                <stop offset="0%" stop-color="rgba(255,255,255,0.8)" />
                <stop offset="100%" stop-color="rgba(230,240,255,0.3)" />
            </linearGradient>

            <!-- 底部阴影滤镜 -->
            <filter id="dropShadow" x="-20%" y="-20%" width="140%" height="140%">
                <feGaussianBlur in="SourceAlpha" stdDeviation="15" result="blur" />
                <feOffset dx="0" dy="20" result="offsetBlur" />
                <feComponentTransfer>
                    <feFuncA type="linear" slope="0.15" />
                </feComponentTransfer>
                <feMerge> 
                    <feMergeNode />
                    <feMergeNode in="SourceGraphic" />
                </feMerge>
            </filter>
        </defs>
    `;

    let htmlBuffer = '';

    // A. 生成底部投影层 (最远离相机的层)
    htmlBuffer += `
        <div class="slice" style="transform: translateZ(${(-LAYERS/2 * DEPTH_STEP) - 40}px);">
            <svg viewBox="0 0 1200 700">
                <text x="50%" y="50%" text-anchor="middle" dominant-baseline="middle" 
                      font-size="170" font-weight="900" letter-spacing="4px" font-style="italic"
                      fill="#8a9eb5" filter="blur(25px)" opacity="0.6">
                    ${textContent}
                </text>
            </svg>
        </div>
    `;

    // B. 循环生成玻璃厚度体 (挤出侧面)
    for (let i = 0; i <= LAYERS; i++) {
        const z = (i - LAYERS / 2) * DEPTH_STEP;
        const isTop = (i === LAYERS);
        const isBottom = (i === 0);
        
        // 样式计算逻辑：营造玻璃的清透与边缘折射感
        let fill, stroke, strokeWidth, filter, additionalElements;
        
        if (isTop) {
            // 正面：清晰的表面，带有流光和基础半透明填充
            fill = "url(#glassSurface)";
            stroke = "rgba(255, 255, 255, 1)"; // 锐利的白色边缘
            strokeWidth = "2";
            filter = "none";
            // 顶层附加流光层
            additionalElements = `
                <text x="50%" y="50%" text-anchor="middle" dominant-baseline="middle" 
                      font-size="170" font-weight="900" letter-spacing="4px" font-style="italic"
                      fill="url(#shineGrad)" pointer-events="none">
                    ${textContent}
                </text>
            `;
        } else if (isBottom) {
            // 底面：稍暗，封底
            fill = "rgba(200, 215, 235, 0.4)";
            stroke = "rgba(255, 255, 255, 0.5)";
            strokeWidth = "1";
            filter = "none";
            additionalElements = "";
        } else {
            // 侧边厚度层：极低透明度交替叠加，模拟毛玻璃内部浑浊与折射
            const opacity = 0.04;
            // 细微交替颜色制造条纹质感（类似亚克力切割边缘）
            const color = i % 2 === 0 ? `rgba(255, 255, 255, ${opacity})` : `rgba(180, 210, 255, ${opacity})`;
            fill = color;
            stroke = `rgba(200, 220, 255, ${opacity * 1.5})`;
            strokeWidth = "1.5";
            filter = "none";
            additionalElements = "";
        }

        htmlBuffer += `
            <div class="slice" style="transform: translateZ(${z}px);">
                <svg viewBox="0 0 1200 700">
                    ${i === 0 ? defsHTML : ''} <!-- 只注入一次 defs -->
                    <text x="50%" y="50%" text-anchor="middle" dominant-baseline="middle" 
                          font-size="170" font-weight="900" letter-spacing="4px" font-style="italic"
                          fill="${fill}" stroke="${stroke}" stroke-width="${strokeWidth}"
                          stroke-linejoin="round">
                        ${textContent}
                    </text>
                    ${additionalElements}
                </svg>
            </div>
        `;
    }

    // 渲染到 DOM
    textGroup.innerHTML = htmlBuffer;


    /**
     * 3. 动画与交互逻辑 (核心主循环)
     * 使用唯一的 requestAnimationFrame 处理自动旋转和平滑拖拽过渡
     */
    const sceneContainer = document.getElementById('sceneContainer');
    
    // 旋转状态变量
    let currentRotateX = -15; // 初始微微俯视
    let currentRotateY = 30;  // 初始偏转角度
    let targetRotateX = -15;
    let targetRotateY = 30;
    
    // 交互状态
    let isDragging = false;
    let startX = 0;
    let startY = 0;
    let autoRotate = true;
    let time = 0;

    // 监听拖拽事件 (Pointer Events 兼容鼠标和触摸)
    sceneContainer.addEventListener('pointerdown', (e) => {
        isDragging = true;
        autoRotate = false; // 交互时暂停自动旋转
        startX = e.clientX;
        startY = e.clientY;
        sceneContainer.setPointerCapture(e.pointerId);
    });

    sceneContainer.addEventListener('pointermove', (e) => {
        if (!isDragging) return;
        
        const deltaX = e.clientX - startX;
        const deltaY = e.clientY - startY;
        
        // 调整灵敏度
        targetRotateY += deltaX * 0.4;
        targetRotateX -= deltaY * 0.4;
        
        // 限制 X 轴翻转，防止倒置，保持最佳观感
        targetRotateX = Math.max(-60, Math.min(60, targetRotateX));
        
        startX = e.clientX;
        startY = e.clientY;
    });

    sceneContainer.addEventListener('pointerup', (e) => {
        isDragging = false;
        sceneContainer.releasePointerCapture(e.pointerId);
        // 设置一个延时恢复自动旋转
        setTimeout(() => {
            if (!isDragging) autoRotate = true;
        }, 2000);
    });

    // 唯一主循环
    function renderLoop() {
        if (autoRotate) {
            // 自动缓慢旋转：利用正弦函数做优雅的摇摆，而不是死板的单向旋转
            time += 0.005;
            targetRotateY += 0.2; // 持续围绕 Y 轴旋转
            targetRotateX = -15 + Math.sin(time) * 10; // X 轴轻微呼吸摇摆
        }

        // 平滑插值 (Lerp) 实现惯性顺滑感
        currentRotateX += (targetRotateX - currentRotateX) * 0.1;
        currentRotateY += (targetRotateY - currentRotateY) * 0.1;

        // 应用 3D 变换
        textGroup.style.transform = `rotateX(${currentRotateX}deg) rotateY(${currentRotateY}deg)`;

        requestAnimationFrame(renderLoop);
    }

    // 启动动画循环
    renderLoop();

</script>
</body>
</html>13:T3bbd,<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Tracert 命令运行逻辑动画</title>
    <style>
        :root {
            --bg-color: #0a0e14;
            --panel-color: rgba(20, 26, 35, 0.9);
            --accent-blue: #00d2ff;
            --accent-green: #00ff9d;
            --accent-red: #ff4b2b;
            --text-main: #e0e6ed;
            --text-dim: #718096;
            --font-mono: 'Fira Code', 'JetBrains Mono', 'Courier New', monospace;
        }

        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            background-color: var(--bg-color);
            color: var(--text-main);
            font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
            overflow: hidden;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        #container {
            position: relative;
            width: 1200px;
            height: 700px;
            background: var(--bg-color);
            box-shadow: 0 0 50px rgba(0,0,0,0.5);
            border: 1px solid #2d3748;
            overflow: hidden;
        }

        .svg-layer {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
        }

        /* 终端窗口样式 */
        #terminal {
            position: absolute;
            bottom: 30px;
            left: 50%;
            transform: translateX(-50%);
            width: 1100px;
            height: 180px;
            background: var(--panel-color);
            border: 1px solid #4a5568;
            border-radius: 8px;
            padding: 15px;
            font-family: var(--font-mono);
            font-size: 14px;
            color: var(--accent-green);
            box-shadow: 0 10px 30px rgba(0,0,0,0.5);
            overflow-y: auto;
            scrollbar-width: thin;
        }

        .cursor {
            display: inline-block;
            width: 8px;
            height: 15px;
            background: var(--accent-green);
            animation: blink 1s infinite;
            vertical-align: middle;
        }

        @keyframes blink {
            50% { opacity: 0; }
        }

        /* 顶部标题栏 */
        #header {
            position: absolute;
            top: 20px;
            left: 40px;
            display: flex;
            flex-direction: column;
        }

        #header h1 {
            margin: 0;
            font-size: 24px;
            letter-spacing: 2px;
            color: var(--accent-blue);
            text-transform: uppercase;
        }

        #header p {
            margin: 5px 0 0 0;
            font-size: 14px;
            color: var(--text-dim);
        }

        .step-label {
            font-size: 16px;
            font-weight: bold;
            fill: var(--text-main);
        }

        .node-label {
            font-size: 12px;
            fill: var(--text-dim);
            text-anchor: middle;
        }

        .ttl-badge {
            font-family: var(--font-mono);
            font-weight: bold;
            font-size: 14px;
        }

        /* 科技感动画线条 */
        .path-line {
            fill: none;
            stroke: #2d3748;
            stroke-width: 2;
            stroke-dasharray: 8 4;
        }

        .path-active {
            stroke: var(--accent-blue);
            stroke-width: 3;
            stroke-dasharray: 1000;
            stroke-dashoffset: 1000;
        }

        @keyframes dash {
            to { stroke-dashoffset: 0; }
        }
    </style>
</head>
<body>

<div id="container">
    <!-- 背景装饰网格 -->
    <svg class="svg-layer" viewBox="0 0 1200 700">
        <defs>
            <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
                <path d="M 40 0 L 0 0 0 40" fill="none" stroke="#1a202c" stroke-width="1"/>
            </pattern>
            <filter id="glow">
                <feGaussianBlur stdDeviation="3" result="coloredBlur"/>
                <feMerge>
                    <feMergeNode in="coloredBlur"/>
                    <feMergeNode in="SourceGraphic"/>
                </feMerge>
            </filter>
            
            <!-- 图标定义 -->
            <symbol id="icon-pc" viewBox="0 0 24 24">
                <path fill="currentColor" d="M20,18H4V4H20M20,2H4C2.89,2 2,2.89 2,4V16A2,2 0 0,0 4,18H9L7.5,20.5V22H16.5V20.5L15,18H20A2,2 0 0,0 22,16V4C22,2.89 21.1,2 20,2Z" />
            </symbol>
            <symbol id="icon-router" viewBox="0 0 24 24">
                <path fill="currentColor" d="M20,13H4V11H20M20,17H4V15H20M20,7H4V5H20M22,3H2V21H22V3Z" />
            </symbol>
            <symbol id="icon-server" viewBox="0 0 24 24">
                <path fill="currentColor" d="M19,15H5V13H19M19,19H5V17H19M19,11H5V9H19M5,7V5H19V7H5M21,3H3V21H21V3Z" />
            </symbol>
        </defs>
        <rect width="100%" height="100%" fill="url(#grid)" />

        <!-- 节点连线 -->
        <g id="connections"></g>

        <!-- 节点 -->
        <g id="nodes">
            <!-- 源主机 -->
            <g transform="translate(100, 320)" id="node-source">
                <use href="#icon-pc" x="-25" y="-25" width="50" height="50" style="color: var(--accent-blue); filter: url(#glow);"/>
                <text y="45" class="node-label">源主机 (Client)</text>
                <text y="60" class="node-label" style="font-size:10px">192.168.1.10</text>
            </g>

            <!-- 路由器 1 -->
            <g transform="translate(350, 320)" id="node-r1">
                <use href="#icon-router" x="-20" y="-20" width="40" height="40" style="color: var(--text-dim);"/>
                <text y="40" class="node-label">跃点 1</text>
                <text y="55" class="node-label" style="font-size:10px">10.0.0.1</text>
            </g>

            <!-- 路由器 2 -->
            <g transform="translate(600, 320)" id="node-r2">
                <use href="#icon-router" x="-20" y="-20" width="40" height="40" style="color: var(--text-dim);"/>
                <text y="40" class="node-label">跃点 2</text>
                <text y="55" class="node-label" style="font-size:10px">20.0.0.5</text>
            </g>

            <!-- 路由器 3 -->
            <g transform="translate(850, 320)" id="node-r3">
                <use href="#icon-router" x="-20" y="-20" width="40" height="40" style="color: var(--text-dim);"/>
                <text y="40" class="node-label">跃点 3</text>
                <text y="55" class="node-label" style="font-size:10px">30.0.0.8</text>
            </g>

            <!-- 目标服务器 -->
            <g transform="translate(1100, 320)" id="node-target">
                <use href="#icon-server" x="-25" y="-25" width="50" height="50" style="color: var(--accent-green);"/>
                <text y="45" class="node-label">目标服务器</text>
                <text y="60" class="node-label" style="font-size:10px">8.8.8.8</text>
            </g>
        </g>

        <!-- 动画元素：数据包 -->
        <g id="packet-layer"></g>

        <!-- 步骤提示文字 -->
        <text id="step-description" x="600" y="80" text-anchor="middle" class="step-label" fill="var(--accent-blue)">准备执行 Tracert 命令...</text>
    </svg>

    <div id="header">
        <h1>Tracert 运行逻辑可视化</h1>
        <p>ICMP 生存时间 (TTL) 机制演示</p>
    </div>

    <div id="terminal">
        <div>C:\Users\Admin&gt; <span id="command-text"></span><span class="cursor"></span></div>
        <div id="log-content"></div>
    </div>
</div>

<script>
    const CONFIG = {
        nodes: [
            { id: 'source', x: 100, y: 320, ip: '192.168.1.10' },
            { id: 'r1', x: 350, y: 320, ip: '10.0.0.1' },
            { id: 'r2', x: 600, y: 320, ip: '20.0.0.5' },
            { id: 'r3', x: 850, y: 320, ip: '30.0.0.8' },
            { id: 'target', x: 1100, y: 320, ip: '8.8.8.8' }
        ],
        packetColor: '#00d2ff',
        errorColor: '#ff4b2b',
        successColor: '#00ff9d'
    };

    const terminal = document.getElementById('log-content');
    const stepDesc = document.getElementById('step-description');
    const packetLayer = document.getElementById('packet-layer');
    const commandText = document.getElementById('command-text');

    async function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    function addLog(text, color = 'var(--accent-green)') {
        const div = document.createElement('div');
        div.style.color = color;
        div.style.marginTop = '2px';
        div.innerHTML = text;
        terminal.appendChild(div);
        terminal.scrollTop = terminal.scrollHeight;
    }

    async function typeCommand(text) {
        for (let i = 0; i <= text.length; i++) {
            commandText.textContent = text.slice(0, i);
            await sleep(50);
        }
        await sleep(500);
    }

    function createPacket(x, y, ttl, color) {
        const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
        g.setAttribute('transform', `translate(${x}, ${y})`);
        
        const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
        circle.setAttribute('r', '8');
        circle.setAttribute('fill', color);
        circle.setAttribute('filter', 'url(#glow)');
        
        const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
        text.setAttribute('y', '-15');
        text.setAttribute('text-anchor', 'middle');
        text.setAttribute('class', 'ttl-badge');
        text.setAttribute('fill', color);
        text.textContent = `TTL=${ttl}`;
        
        g.appendChild(circle);
        g.appendChild(text);
        packetLayer.appendChild(g);
        return g;
    }

    async function movePacket(packet, startNodeIdx, endNodeIdx, duration) {
        const start = CONFIG.nodes[startNodeIdx];
        const end = CONFIG.nodes[endNodeIdx];
        const startTime = performance.now();

        return new Promise(resolve => {
            function animate(time) {
                let progress = (time - startTime) / duration;
                if (progress > 1) progress = 1;
                
                const currentX = start.x + (end.x - start.x) * progress;
                const currentY = start.y + (end.y - start.y) * progress;
                packet.setAttribute('transform', `translate(${currentX}, ${currentY})`);
                
                if (progress < 1) {
                    requestAnimationFrame(animate);
                } else {
                    resolve();
                }
            }
            requestAnimationFrame(animate);
        });
    }

    async function runTracert() {
        // 1. 初始化
        await typeCommand('tracert 8.8.8.8');
        addLog('通过最多 30 个跃点跟踪到 8.8.8.8 的路由:', 'var(--text-main)');
        await sleep(1000);

        // 循环每一跳
        for (let hop = 1; hop <= 4; hop++) {
            const isTarget = hop === 4;
            const ttl = hop;
            stepDesc.textContent = `步骤 ${hop}: 发送 TTL=${ttl} 的数据包`;
            stepDesc.setAttribute('fill', CONFIG.packetColor);

            // 发送包
            const p = createPacket(CONFIG.nodes[0].x, CONFIG.nodes[0].y, ttl, CONFIG.packetColor);
            
            // 沿途经过路由器
            for (let currentPos = 0; currentPos < hop; currentPos++) {
                await movePacket(p, currentPos, currentPos + 1, 600);
                if (currentPos + 1 < hop) {
                    // TTL 递减动画
                    const newTTL = ttl - (currentPos + 1);
                    p.querySelector('text').textContent = `TTL=${newTTL}`;
                    // 闪烁一下表示处理
                    p.querySelector('circle').setAttribute('fill', '#fff');
                    await sleep(100);
                    p.querySelector('circle').setAttribute('fill', CONFIG.packetColor);
                }
            }

            // 到达目标点（TTL变为0或到达目的地）
            await sleep(300);
            
            if (!isTarget) {
                // 路由器返回 ICMP Time Exceeded
                stepDesc.textContent = `跃点 ${hop} (${CONFIG.nodes[hop].ip}): TTL 耗尽，返回 ICMP Time Exceeded`;
                stepDesc.setAttribute('fill', CONFIG.errorColor);
                p.querySelector('circle').setAttribute('fill', CONFIG.errorColor);
                p.querySelector('text').textContent = 'Time Exceeded';
                p.querySelector('text').setAttribute('fill', CONFIG.errorColor);
                
                // 高亮当前路由器
                const routerIcon = document.querySelector(`#node-r${hop} use`);
                routerIcon.style.color = CONFIG.packetColor;
                routerIcon.style.filter = 'url(#glow)';

                await sleep(500);
                // 返回源主机
                await movePacket(p, hop, 0, 800);
                addLog(`&nbsp;&nbsp;${hop}&nbsp;&nbsp;&nbsp;&nbsp;1 ms&nbsp;&nbsp;&nbsp;&nbsp;1 ms&nbsp;&nbsp;&nbsp;&nbsp;1 ms&nbsp;&nbsp;${CONFIG.nodes[hop].ip}`);
            } else {
                // 到达目标服务器返回 ICMP Echo Reply
                stepDesc.textContent = `目标已到达: 8.8.8.8 返回 ICMP Echo Reply`;
                stepDesc.setAttribute('fill', CONFIG.successColor);
                p.querySelector('circle').setAttribute('fill', CONFIG.successColor);
                p.querySelector('text').textContent = 'Echo Reply';
                p.querySelector('text').setAttribute('fill', CONFIG.successColor);

                const targetIcon = document.querySelector(`#node-target use`);
                targetIcon.style.color = CONFIG.successColor;
                targetIcon.style.filter = 'url(#glow)';

                await sleep(500);
                await movePacket(p, 4, 0, 800);
                addLog(`&nbsp;&nbsp;${hop}&nbsp;&nbsp;&nbsp;&nbsp;2 ms&nbsp;&nbsp;&nbsp;&nbsp;1 ms&nbsp;&nbsp;&nbsp;&nbsp;2 ms&nbsp;&nbsp;${CONFIG.nodes[hop].ip}`);
            }

            packetLayer.removeChild(p);
            await sleep(800);
        }

        stepDesc.textContent = "跟踪完成。所有路径节点已识别。";
        stepDesc.setAttribute('fill', CONFIG.successColor);
        addLog('<br>跟踪完成。', 'var(--text-main)');
        
        await sleep(5000);
        location.reload(); // 循环演示
    }

    // 初始化连线
    function initLines() {
        const connGroup = document.getElementById('connections');
        for (let i = 0; i < CONFIG.nodes.length - 1; i++) {
            const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
            line.setAttribute('x1', CONFIG.nodes[i].x);
            line.setAttribute('y1', CONFIG.nodes[i].y);
            line.setAttribute('x2', CONFIG.nodes[i+1].x);
            line.setAttribute('y2', CONFIG.nodes[i+1].y);
            line.setAttribute('class', 'path-line');
            connGroup.appendChild(line);
        }
    }

    window.onload = () => {
        initLines();
        runTracert();
    };
</script>

</body>
</html>14:T4f1f,<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Minimalist Billiards</title>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap');

        :root {
            --bg-color: #042F23;
            --table-color: #064E3B;
            --text-primary: #FFFFFF;
            --text-secondary: #9CA3AF;
            --accent: #FACC15;
            --danger: #EF4444;
        }

        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
            background-color: var(--bg-color);
            font-family: 'Inter', system-ui, -apple-system, sans-serif;
            cursor: none;
            touch-action: none;
        }

        #game-container {
            width: 100vw;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            position: relative;
        }

        svg {
            width: 100%;
            height: 100%;
            display: block;
        }

        /* 文本无法选中 */
        text {
            user-select: none;
            pointer-events: none;
        }

        /* 动画类 */
        .fade-out {
            opacity: 0;
            transition: opacity 0.5s ease-out;
        }

        .score-popup {
            font-weight: bold;
            font-size: 24px;
            fill: var(--accent);
            animation: floatUp 1s ease-out forwards;
        }

        @keyframes floatUp {
            0% { transform: translateY(0) scale(0.5); opacity: 1; }
            50% { transform: translateY(-20px) scale(1.2); opacity: 1; }
            100% { transform: translateY(-40px) scale(1); opacity: 0; }
        }
    </style>
</head>
<body>

<div id="game-container">
    <svg id="game-svg" viewBox="0 0 1200 700" preserveAspectRatio="xMidYMid meet">
        <defs>
            <!-- 桌布阴影 -->
            <filter id="inner-shadow">
                <feOffset dx="0" dy="0"/>
                <feGaussianBlur stdDeviation="15" result="offset-blur"/>
                <feComposite operator="out" in="SourceGraphic" in2="offset-blur" result="inverse"/>
                <feFlood flood-color="black" flood-opacity="0.5" result="color"/>
                <feComposite operator="in" in="color" in2="inverse" result="shadow"/>
                <feComposite operator="over" in="shadow" in2="SourceGraphic"/>
            </filter>

            <!-- 球体立体高光滤镜与渐变 -->
            <radialGradient id="ball-highlight" cx="30%" cy="30%" r="70%">
                <stop offset="0%" stop-color="#ffffff" stop-opacity="0.6"/>
                <stop offset="50%" stop-color="#ffffff" stop-opacity="0"/>
                <stop offset="100%" stop-color="#000000" stop-opacity="0.4"/>
            </radialGradient>

            <filter id="drop-shadow" x="-20%" y="-20%" width="150%" height="150%">
                <feDropShadow dx="3" dy="5" stdDeviation="3" flood-color="#000" flood-opacity="0.4"/>
            </filter>

            <filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
                <feGaussianBlur stdDeviation="5" result="blur" />
                <feComposite in="SourceGraphic" in2="blur" operator="over" />
            </filter>
        </defs>

        <!-- 台球桌外框 -->
        <rect x="40" y="40" width="1120" height="620" rx="30" fill="#111827" />
        <rect x="50" y="50" width="1100" height="600" rx="20" fill="#1F2937" />
        <!-- 台球桌布 -->
        <rect x="70" y="70" width="1060" height="560" rx="10" fill="#064E3B" filter="url(#inner-shadow)" />
        
        <!-- 发球线 -->
        <line x1="300" y1="70" x2="300" y2="630" stroke="#047857" stroke-width="2" opacity="0.5" />
        <circle cx="300" cy="350" r="40" fill="none" stroke="#047857" stroke-width="2" opacity="0.5" />

        <!-- 球袋洞口 -->
        <g id="pockets-layer">
            <circle cx="80" cy="80" r="28" fill="#030712" />
            <circle cx="600" cy="70" r="25" fill="#030712" />
            <circle cx="1120" cy="80" r="28" fill="#030712" />
            <circle cx="80" cy="620" r="28" fill="#030712" />
            <circle cx="600" cy="630" r="25" fill="#030712" />
            <circle cx="1120" cy="620" r="28" fill="#030712" />
        </g>

        <!-- 瞄准辅助层 -->
        <g id="aim-layer" style="display: none;">
            <!-- 预测虚线 -->
            <line id="aim-line" x1="0" y1="0" x2="0" y2="0" stroke="#FFFFFF" stroke-width="1.5" stroke-dasharray="6 4" opacity="0.6" />
            <!-- 力度指示圈 -->
            <circle id="power-ring" cx="0" cy="0" r="0" fill="none" stroke="#FACC15" stroke-width="2" opacity="0.8" />
            <!-- 球杆 -->
            <g id="cue-stick">
                <rect x="0" y="-3" width="400" height="6" fill="#D1D5DB" rx="2" />
                <rect x="0" y="-3" width="20" height="6" fill="#3B82F6" rx="2" /> <!-- 杆头 -->
                <rect x="250" y="-4" width="150" height="8" fill="#1F2937" rx="2" /> <!-- 握把 -->
            </g>
        </g>

        <!-- 球体渲染层 -->
        <g id="balls-layer"></g>

        <!-- UI 层 (瑞士风格排版) -->
        <g id="ui-layer">
            <!-- 左上角标题 -->
            <text x="40" y="30" fill="#9CA3AF" font-size="12" font-weight="700" letter-spacing="2">PROJECT: BILLIARDS</text>
            <text x="210" y="30" fill="#4B5563" font-size="12" font-weight="400">/ 动效与物理驱动</text>
            
            <!-- 右上角分数 -->
            <text x="1160" y="30" fill="#9CA3AF" font-size="12" font-weight="700" letter-spacing="2" text-anchor="end">SCORE</text>
            <text id="score-text" x="1160" y="65" fill="#FFFFFF" font-size="36" font-weight="700" text-anchor="end" font-variant-numeric="tabular-nums">000</text>

            <!-- 底部状态栏 -->
            <text x="40" y="685" fill="#9CA3AF" font-size="10" font-weight="700" letter-spacing="1">STATUS</text>
            <text id="status-text" x="100" y="685" fill="#FACC15" font-size="10" font-weight="700" letter-spacing="1">AWAITING BREAK</text>

            <!-- 操作提示 -->
            <text x="1160" y="685" fill="#6B7280" font-size="10" font-weight="400" text-anchor="end">拖拽白球调整角度与力度发球</text>
        </g>

        <!-- 进球特效层 -->
        <g id="fx-layer"></g>

        <!-- 交互光标 -->
        <g id="cursor-group" pointer-events="none">
            <circle cx="0" cy="0" r="6" fill="none" stroke="#FFFFFF" stroke-width="1.5" />
            <circle cx="0" cy="0" r="1" fill="#FACC15" />
        </g>
    </svg>
</div>

<script>
    /**
     * 极简 2D 物理引擎与台球逻辑
     */
    const svg = document.getElementById('game-svg');
    const ballsLayer = document.getElementById('balls-layer');
    const aimLayer = document.getElementById('aim-layer');
    const aimLine = document.getElementById('aim-line');
    const cueStick = document.getElementById('cue-stick');
    const powerRing = document.getElementById('power-ring');
    const scoreText = document.getElementById('score-text');
    const statusText = document.getElementById('status-text');
    const fxLayer = document.getElementById('fx-layer');
    const cursorGroup = document.getElementById('cursor-group');

    // 物理与几何常量
    const TABLE_BOUNDS = { left: 70, right: 1130, top: 70, bottom: 630 };
    const POCKETS = [
        { x: 80, y: 80 }, { x: 600, y: 70 }, { x: 1120, y: 80 },
        { x: 80, y: 620 }, { x: 600, y: 630 }, { x: 1120, y: 620 }
    ];
    const POCKET_RADIUS = 30;
    const BALL_RADIUS = 14;
    const FRICTION = 0.988; // 摩擦力衰减
    const RESTITUTION = 0.92; // 碰撞弹性系数
    const MAX_POWER = 35; // 最大击球速度
    const MIN_VELOCITY = 0.05; // 停止阈值

    let balls = [];
    let score = 0;
    let gameState = 'IDLE'; // IDLE, AIMING, ROLLING
    let dragStart = { x: 0, y: 0 };
    let dragCurrent = { x: 0, y: 0 };
    let cueBall = null;

    // 颜色配置
    const COLORS = [
        '#FACC15', '#3B82F6', '#EF4444', '#8B5CF6', 
        '#F97316', '#10B981', '#881337', '#111827' // 黑球最后
    ];

    /**
     * 初始化球局
     */
    function initBalls() {
        balls = [];
        ballsLayer.innerHTML = '';

        // 白球
        cueBall = createBall('cue', 300, 350, '#FFFFFF');
        
        // 摆放目标球 (三角形阵列)
        const startX = 850;
        const startY = 350;
        const rowSpacing = BALL_RADIUS * Math.sqrt(3) + 1;
        const colSpacing = BALL_RADIUS * 2 + 1;

        let colorIdx = 0;
        let ballId = 1;

        for (let row = 0; row < 5; row++) {
            for (let col = 0; col <= row; col++) {
                const x = startX + row * rowSpacing;
                const y = startY - (row * colSpacing) / 2 + col * colSpacing;
                
                // 黑球放在中间特定位置 (第3排中间)
                let color = '#EF4444'; // 默认红球
                if (row === 2 && col === 1) {
                    color = '#111827'; // 黑球
                } else {
                    color = COLORS[colorIdx % (COLORS.length - 1)];
                    colorIdx++;
                }

                createBall(`target-${ballId++}`, x, y, color);
            }
        }
    }

    function createBall(id, x, y, color) {
        const ball = {
            id, x, y, vx: 0, vy: 0, mass: 1, radius: BALL_RADIUS, color, active: true
        };
        balls.push(ball);

        const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
        g.setAttribute('id', id);
        g.setAttribute('transform', `translate(${x}, ${y})`);
        
        // 投影阴影
        const shadow = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
        shadow.setAttribute('r', BALL_RADIUS);
        shadow.setAttribute('fill', 'none');
        shadow.setAttribute('filter', 'url(#drop-shadow)');
        
        // 基础颜色
        const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
        circle.setAttribute('r', BALL_RADIUS);
        circle.setAttribute('fill', color);
        
        // 立体高光
        const highlight = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
        highlight.setAttribute('r', BALL_RADIUS);
        highlight.setAttribute('fill', 'url(#ball-highlight)');

        g.appendChild(shadow);
        g.appendChild(circle);
        g.appendChild(highlight);
        ballsLayer.appendChild(g);

        ball.element = g;
        return ball;
    }

    /**
     * 物理更新核心
     */
    function updatePhysics() {
        let isMoving = false;

        // 1. 更新位置与摩擦力
        for (let ball of balls) {
            if (!ball.active) continue;

            ball.x += ball.vx;
            ball.y += ball.vy;

            ball.vx *= FRICTION;
            ball.vy *= FRICTION;

            if (Math.abs(ball.vx) < MIN_VELOCITY) ball.vx = 0;
            if (Math.abs(ball.vy) < MIN_VELOCITY) ball.vy = 0;

            if (ball.vx !== 0 || ball.vy !== 0) isMoving = true;

            // 2. 边界碰撞检测
            if (ball.x - ball.radius < TABLE_BOUNDS.left) {
                ball.x = TABLE_BOUNDS.left + ball.radius;
                ball.vx *= -RESTITUTION;
            } else if (ball.x + ball.radius > TABLE_BOUNDS.right) {
                ball.x = TABLE_BOUNDS.right - ball.radius;
                ball.vx *= -RESTITUTION;
            }

            if (ball.y - ball.radius < TABLE_BOUNDS.top) {
                ball.y = TABLE_BOUNDS.top + ball.radius;
                ball.vy *= -RESTITUTION;
            } else if (ball.y + ball.radius > TABLE_BOUNDS.bottom) {
                ball.y = TABLE_BOUNDS.bottom - ball.radius;
                ball.vy *= -RESTITUTION;
            }
        }

        // 3. 球与球之间的碰撞 (使用动量守恒)
        for (let i = 0; i < balls.length; i++) {
            for (let j = i + 1; j < balls.length; j++) {
                const b1 = balls[i];
                const b2 = balls[j];
                if (!b1.active || !b2.active) continue;

                const dx = b2.x - b1.x;
                const dy = b2.y - b1.y;
                const dist = Math.hypot(dx, dy);
                const minDist = b1.radius + b2.radius;

                if (dist < minDist) {
                    // 分离重叠
                    const overlap = (minDist - dist) / 2;
                    const nx = dx / dist;
                    const ny = dy / dist;

                    b1.x -= overlap * nx;
                    b1.y -= overlap * ny;
                    b2.x += overlap * nx;
                    b2.y += overlap * ny;

                    // 相对速度
                    const kx = b1.vx - b2.vx;
                    const ky = b1.vy - b2.vy;

                    // 沿法线的冲量
                    const p = 2 * (nx * kx + ny * ky) / (b1.mass + b2.mass);

                    // 应用冲量与弹性系数
                    b1.vx -= p * b2.mass * nx * RESTITUTION;
                    b1.vy -= p * b2.mass * ny * RESTITUTION;
                    b2.vx += p * b1.mass * nx * RESTITUTION;
                    b2.vy += p * b1.mass * ny * RESTITUTION;
                }
            }
        }

        // 4. 进袋检测
        for (let ball of balls) {
            if (!ball.active) continue;
            for (let pocket of POCKETS) {
                const dist = Math.hypot(ball.x - pocket.x, ball.y - pocket.y);
                if (dist < POCKET_RADIUS) {
                    handlePocketIn(ball, pocket);
                    break;
                }
            }
        }

        // 状态切换
        if (gameState === 'ROLLING' && !isMoving) {
            gameState = 'IDLE';
            statusText.textContent = 'READY / 等待击球';
            statusText.setAttribute('fill', '#3B82F6');
            
            // 检查白球是否进袋
            if (!cueBall.active) {
                resetCueBall();
            }
        }
    }

    function handlePocketIn(ball, pocket) {
        ball.active = false;
        ball.vx = 0;
        ball.vy = 0;
        
        // 视觉效果：球缩小消失
        ball.element.style.transition = 'all 0.3s ease-in';
        ball.element.setAttribute('transform', `translate(${pocket.x}, ${pocket.y}) scale(0)`);
        
        if (ball.id !== 'cue') {
            const points = ball.color === '#111827' ? 50 : 10;
            updateScore(points);
            showFloatingText(`+${points}`, pocket.x, pocket.y - 20);
        } else {
            showFloatingText("FOUL", pocket.x, pocket.y - 20, '#EF4444');
            updateScore(-20);
        }
    }

    function resetCueBall() {
        cueBall.x = 300;
        cueBall.y = 350;
        cueBall.vx = 0;
        cueBall.vy = 0;
        cueBall.active = true;
        cueBall.element.style.transition = 'none';
        cueBall.element.setAttribute('transform', `translate(${cueBall.x}, ${cueBall.y}) scale(1)`);
    }

    function updateScore(delta) {
        score = Math.max(0, score + delta);
        scoreText.textContent = score.toString().padStart(3, '0');
    }

    function showFloatingText(text, x, y, color = '#FACC15') {
        const textEl = document.createElementNS('http://www.w3.org/2000/svg', 'text');
        textEl.setAttribute('x', x);
        textEl.setAttribute('y', y);
        textEl.setAttribute('class', 'score-popup');
        textEl.setAttribute('text-anchor', 'middle');
        textEl.setAttribute('fill', color);
        textEl.textContent = text;
        fxLayer.appendChild(textEl);
        
        setTimeout(() => {
            if (fxLayer.contains(textEl)) fxLayer.removeChild(textEl);
        }, 1000);
    }

    /**
     * 渲染同步
     */
    function render() {
        for (let ball of balls) {
            if (ball.active) {
                ball.element.setAttribute('transform', `translate(${ball.x}, ${ball.y})`);
            }
        }
    }

    /**
     * 交互逻辑 (鼠标/触摸)
     */
    function getMousePos(e) {
        const pt = svg.createSVGPoint();
        pt.x = e.clientX || (e.touches && e.touches[0].clientX);
        pt.y = e.clientY || (e.touches && e.touches[0].clientY);
        return pt.matrixTransform(svg.getScreenCTM().inverse());
    }

    svg.addEventListener('pointermove', (e) => {
        const pos = getMousePos(e);
        
        // 更新光标
        cursorGroup.setAttribute('transform', `translate(${pos.x}, ${pos.y})`);

        if (gameState === 'AIMING') {
            dragCurrent = pos;
            updateAimingVisuals();
        }
    });

    svg.addEventListener('pointerdown', (e) => {
        if (gameState !== 'IDLE' || !cueBall.active) return;
        
        const pos = getMousePos(e);
        // 判断是否点在白球附近
        const distToCue = Math.hypot(pos.x - cueBall.x, pos.y - cueBall.y);
        
        if (distToCue < BALL_RADIUS * 4) {
            gameState = 'AIMING';
            dragStart = pos;
            dragCurrent = pos;
            aimLayer.style.display = 'block';
            statusText.textContent = 'AIMING / 蓄力中...';
            statusText.setAttribute('fill', '#FACC15');
            svg.setPointerCapture(e.pointerId);
        }
    });

    svg.addEventListener('pointerup', (e) => {
        if (gameState === 'AIMING') {
            gameState = 'ROLLING';
            aimLayer.style.display = 'none';
            svg.releasePointerCapture(e.pointerId);
            statusText.textContent = 'ROLLING / 运动中';
            statusText.setAttribute('fill', '#10B981');

            // 计算拉力向量并发球
            const dx = dragStart.x - dragCurrent.x;
            const dy = dragStart.y - dragCurrent.y;
            const distance = Math.hypot(dx, dy);
            
            if (distance > 5) { // 最小击球力度防误触
                const power = Math.min(distance * 0.15, MAX_POWER);
                const angle = Math.atan2(dy, dx);
                
                cueBall.vx = Math.cos(angle) * power;
                cueBall.vy = Math.sin(angle) * power;
            } else {
                gameState = 'IDLE';
                statusText.textContent = 'READY / 等待击球';
            }
        }
    });

    function updateAimingVisuals() {
        const dx = dragStart.x - dragCurrent.x;
        const dy = dragStart.y - dragCurrent.y;
        const distance = Math.hypot(dx, dy);
        const angle = Math.atan2(dy, dx);
        
        // 限制最大拉力视觉
        const visualDist = Math.min(distance, 200);
        
        // 预测线 (白球出发方向)
        aimLine.setAttribute('x1', cueBall.x);
        aimLine.setAttribute('y1', cueBall.y);
        aimLine.setAttribute('x2', cueBall.x + Math.cos(angle) * 500);
        aimLine.setAttribute('y2', cueBall.y + Math.sin(angle) * 500);

        // 力度圈
        powerRing.setAttribute('cx', cueBall.x);
        powerRing.setAttribute('cy', cueBall.y);
        powerRing.setAttribute('r', BALL_RADIUS + visualDist * 0.2);
        const powerRatio = visualDist / 200;
        powerRing.setAttribute('stroke', powerRatio > 0.8 ? '#EF4444' : (powerRatio > 0.4 ? '#F97316' : '#FACC15'));

        // 球杆 (在白球反方向，且根据力度后退)
        const cueAngleDeg = angle * (180 / Math.PI) + 180;
        const cueOffset = BALL_RADIUS + 5 + visualDist * 0.5;
        cueStick.setAttribute('transform', `translate(${cueBall.x}, ${cueBall.y}) rotate(${cueAngleDeg}) translate(${cueOffset}, 0)`);
    }

    /**
     * 主循环
     */
    function gameLoop() {
        updatePhysics();
        render();
        requestAnimationFrame(gameLoop);
    }

    // 启动
    initBalls();
    gameLoop();

    // 防止默认拖拽和右键菜单影响体验
    document.addEventListener('contextmenu', e => e.preventDefault());
    document.addEventListener('dragstart', e => e.preventDefault());

</script>
</body>
</html>15:T3bcd,<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Isometric Crypto Transfer Animation</title>
    <style>
        :root {
            --bg-color: #F5F7FA;
            --mint-primary: #34D399;
            --mint-light: #D1FAE5;
            --sky-primary: #38BDF8;
            --sky-light: #E0F2FE;
            --text-main: #334155;
            --text-sub: #94A3B8;
            --phone-edge: #CBD5E1;
            --phone-face: #FFFFFF;
        }

        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            background-color: var(--bg-color);
            display: flex;
            align-items: center;
            justify-content: center;
            font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            overflow: hidden;
        }

        #animation-container {
            width: 100%;
            height: 100%;
            max-width: 1200px;
            max-height: 700px;
            position: relative;
        }

        svg {
            width: 100%;
            height: 100%;
            display: block;
            user-select: none;
        }

        /* 轨迹虚线流动动画 */
        @keyframes dashFlow {
            from { stroke-dashoffset: 24; }
            to { stroke-dashoffset: 0; }
        }

        .trajectory-line {
            stroke-dasharray: 12 12;
            animation: dashFlow 0.8s linear infinite;
        }

        /* 提升渲染质量 */
        * {
            shape-rendering: geometricPrecision;
            text-rendering: optimizeLegibility;
        }
    </style>
</head>
<body>

<div id="animation-container">
    <svg viewBox="0 0 1200 700" preserveAspectRatio="xMidYMid meet">
        <defs>
            <!-- 手机主体阴影 -->
            <filter id="phone-shadow" x="-20%" y="-20%" width="150%" height="150%">
                <feDropShadow dx="0" dy="24" stdDeviation="16" flood-color="#64748B" flood-opacity="0.15" />
            </filter>

            <!-- 金币发光效果 -->
            <filter id="coin-glow" x="-50%" y="-50%" width="200%" height="200%">
                <feGaussianBlur stdDeviation="6" result="blur" />
                <feComposite in="SourceGraphic" in2="blur" operator="over" />
            </filter>

            <!-- 渐变定义 -->
            <linearGradient id="mint-grad" x1="0%" y1="0%" x2="100%" y2="100%">
                <stop offset="0%" stop-color="#6EE7B7" />
                <stop offset="100%" stop-color="#10B981" />
            </linearGradient>
            
            <linearGradient id="sky-grad" x1="0%" y1="0%" x2="100%" y2="100%">
                <stop offset="0%" stop-color="#7DD3FC" />
                <stop offset="100%" stop-color="#0284C7" />
            </linearGradient>
        </defs>

        <!-- 背景装饰网格 (极简) -->
        <g opacity="0.4" stroke="#E2E8F0" stroke-width="1">
            <line x1="0" y1="350" x2="1200" y2="350" stroke-dasharray="4 8" />
            <line x1="600" y1="0" x2="600" y2="700" stroke-dasharray="4 8" />
        </g>

        <!-- 抛物线轨迹 (在手机和金币底层) -->
        <path id="fly-path" class="trajectory-line" 
              d="M 320,480 C 320,180 720,80 920,220" 
              fill="none" stroke="rgba(14, 116, 144, 0.3)" stroke-width="4" stroke-linecap="round" />

        <!-- ================= 左侧手机 (发送端) ================= -->
        <g id="left-phone" transform="translate(320, 480)">
            <!-- 侧边厚度层 (向下偏移产生3D感) -->
            <g transform="translate(0, 18)">
                <g transform="matrix(0.866, 0.5, -0.866, 0.5, 0, 0)">
                    <rect x="-85" y="-175" width="170" height="350" rx="28" fill="var(--phone-edge)" filter="url(#phone-shadow)"/>
                </g>
            </g>
            
            <!-- 顶面层 (屏幕与面板) -->
            <g transform="matrix(0.866, 0.5, -0.866, 0.5, 0, 0)">
                <!-- 手机外壳 -->
                <rect x="-85" y="-175" width="170" height="350" rx="28" fill="var(--phone-face)" />
                <!-- 屏幕内框 -->
                <rect x="-75" y="-165" width="150" height="330" rx="20" fill="#F8FAFC" />
                
                <!-- UI 界面: 薄荷绿主题 -->
                <g transform="translate(0, -70)">
                    <!-- 顶部背景 -->
                    <path d="M -75,-95 L 75,-95 L 75,30 Q 0,60 -75,30 Z" fill="var(--mint-light)" opacity="0.6"/>
                    
                    <!-- 标题 -->
                    <text x="0" y="-60" fill="var(--mint-primary)" font-size="14" font-weight="bold" text-anchor="middle" letter-spacing="1">资产转账</text>
                    
                    <!-- 金额显示区 -->
                    <rect x="-55" y="-35" width="110" height="50" rx="12" fill="#FFFFFF" opacity="0.9" />
                    <text x="0" y="-15" fill="var(--text-sub)" font-size="10" text-anchor="middle">发送金额 (CNY)</text>
                    <text x="0" y="5" fill="var(--text-main)" font-size="16" font-weight="bold" text-anchor="middle">¥ 10,000</text>
                    
                    <!-- 骨架屏装饰线条 -->
                    <rect x="-55" y="45" width="110" height="8" rx="4" fill="#E2E8F0" />
                    <rect x="-55" y="65" width="80" height="8" rx="4" fill="#E2E8F0" />
                    <rect x="-55" y="85" width="95" height="8" rx="4" fill="#E2E8F0" />
                </g>

                <!-- 发送按钮 (带交互动画) -->
                <g id="send-btn-group" transform="translate(0, 110)">
                    <rect x="-60" y="-22" width="120" height="44" rx="22" fill="url(#mint-grad)" />
                    <text x="0" y="5" fill="#FFFFFF" font-size="14" font-weight="bold" text-anchor="middle" letter-spacing="2">确认发送</text>
                </g>
            </g>
        </g>

        <!-- ================= 右侧手机 (接收端) ================= -->
        <g id="right-phone" transform="translate(920, 220)">
            <!-- 侧边厚度层 -->
            <g transform="translate(0, 18)">
                <g transform="matrix(0.866, 0.5, -0.866, 0.5, 0, 0)">
                    <rect x="-85" y="-175" width="170" height="350" rx="28" fill="var(--phone-edge)" filter="url(#phone-shadow)"/>
                </g>
            </g>
            
            <!-- 顶面层 -->
            <g transform="matrix(0.866, 0.5, -0.866, 0.5, 0, 0)">
                <!-- 手机外壳 -->
                <rect x="-85" y="-175" width="170" height="350" rx="28" fill="var(--phone-face)" />
                <!-- 屏幕内框 -->
                <rect x="-75" y="-165" width="150" height="330" rx="20" fill="#F0F9FF" />
                
                <!-- UI 界面: 天空蓝主题 -->
                <text x="0" y="-120" fill="var(--sky-primary)" font-size="14" font-weight="bold" text-anchor="middle" letter-spacing="1">数字钱包</text>
                
                <rect x="-60" y="-90" width="120" height="6" rx="3" fill="#BAE6FD" opacity="0.5" />
                <rect x="-40" y="-75" width="80" height="6" rx="3" fill="#BAE6FD" opacity="0.5" />

                <!-- 入账涟漪特效圈 -->
                <circle id="wallet-ripple-1" cx="0" cy="10" r="0" fill="none" stroke="var(--sky-primary)" stroke-width="4" opacity="0" />
                <circle id="wallet-ripple-2" cx="0" cy="10" r="0" fill="none" stroke="var(--sky-primary)" stroke-width="2" opacity="0" />

                <!-- 钱包图标核心组件 -->
                <g id="wallet-icon-group" transform="translate(0, 10)">
                    <!-- 钱包后盖 -->
                    <rect x="-44" y="-28" width="88" height="56" rx="10" fill="#7DD3FC" />
                    <!-- 内部卡片露出 -->
                    <rect x="-30" y="-36" width="60" height="20" rx="4" fill="#FFFFFF" opacity="0.8" />
                    <rect x="-20" y="-30" width="40" height="4" rx="2" fill="#E2E8F0" />
                    <!-- 钱包前盖 -->
                    <rect x="-44" y="-8" width="88" height="36" rx="10" fill="url(#sky-grad)" />
                    <!-- 钱包扣子 -->
                    <circle cx="0" cy="-8" r="7" fill="#FFFFFF" />
                    <circle cx="0" cy="-8" r="3" fill="#0284C7" />
                    <!-- 钱包开口缝隙标识 -->
                    <path d="M -30,-8 L -15,-8 M 15,-8 L 30,-8" stroke="#0284C7" stroke-width="2" stroke-linecap="round" opacity="0.4" />
                </g>

                <!-- 底部状态文本 -->
                <rect x="-50" y="100" width="100" height="30" rx="15" fill="#FFFFFF" opacity="0.8" />
                <text id="receive-status" x="0" y="120" fill="var(--text-sub)" font-size="12" font-weight="bold" text-anchor="middle">等待接收...</text>
            </g>
        </g>

        <!-- ================= 飞行的金币 ================= -->
        <!-- 放置在最顶层，不受等距投影矩阵影响，保持正视扁平感 -->
        <g id="coin-master" transform="translate(320, 480)">
            <g id="coin-scaler" transform="scale(0)">
                <g filter="url(#coin-glow)">
                    <!-- 金币厚度/阴影 -->
                    <circle cx="0" cy="4" r="26" fill="#D97706" />
                    <!-- 金币主面 -->
                    <circle cx="0" cy="0" r="26" fill="#FBBF24" />
                    <!-- 边缘高光 -->
                    <path d="M -20,0 A 20 20 0 0 1 20,0" fill="none" stroke="#FDE68A" stroke-width="3" stroke-linecap="round" />
                    <!-- 内部图案 (极简菱形/星芒代表数字资产) -->
                    <path d="M 0,-14 L 6,0 L 0,14 L -6,0 Z" fill="#FFFBEB" opacity="0.9" />
                    <path d="M -14,0 L 0,-6 L 14,0 L 0,6 Z" fill="#FFFBEB" opacity="0.9" />
                </g>
            </g>
        </g>
    </svg>
</div>

<script>
    document.addEventListener("DOMContentLoaded", () => {
        // 获取DOM元素
        const path = document.getElementById('fly-path');
        const coinMaster = document.getElementById('coin-master');
        const coinScaler = document.getElementById('coin-scaler');
        const walletGroup = document.getElementById('wallet-icon-group');
        const ripple1 = document.getElementById('wallet-ripple-1');
        const ripple2 = document.getElementById('wallet-ripple-2');
        const sendBtn = document.getElementById('send-btn-group');
        const statusText = document.getElementById('receive-status');
        
        const pathLength = path.getTotalLength();
        const DURATION = 2800; // 动画总时长 (ms)
        let startTime = null;

        // 缓动函数定义
        // Quartic Ease In Out (平滑加速后减速)
        const easeInOutQuart = (t) => t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2;
        
        // Elastic Ease Out (弹簧效果)
        const easeOutElastic = (t) => {
            const c4 = (2 * Math.PI) / 3;
            return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
        };

        // Cubic Ease In (加速缩小)
        const easeInCubic = (t) => t * t * t;

        // 核心动画主循环 (严禁叠加，仅启动一次)
        function renderLoop(timestamp) {
            if (!startTime) startTime = timestamp;
            const elapsed = (timestamp - startTime) % DURATION;
            const t = elapsed / DURATION; // 全局进度 0.0 ~ 1.0

            // --------------------------------------------------
            // 阶段规划:
            // 0.00 - 0.10: 按钮按下，金币弹簧弹出
            // 0.10 - 0.85: 金币沿抛物线飞行
            // 0.85 - 0.95: 金币到达，缩入钱包，钱包呼吸，涟漪扩散
            // 0.95 - 1.00: 状态重置，静默等待下一轮
            // --------------------------------------------------

            // 1. 发送按钮交互 (0.0 - 0.1)
            let btnScale = 1;
            if (t < 0.1) {
                const btnT = t / 0.1;
                btnScale = 1 - Math.sin(btnT * Math.PI) * 0.08; // 轻微按压反弹
            }
            sendBtn.setAttribute('transform', `translate(0, 110) scale(${btnScale})`);

            // 2. 金币位置计算 (0.1 - 0.85)
            let moveT = 0;
            if (t > 0.1 && t < 0.85) {
                const normT = (t - 0.1) / 0.75;
                moveT = easeInOutQuart(normT);
            } else if (t >= 0.85) {
                moveT = 1;
            }
            
            // 获取路径上的坐标
            const point = path.getPointAtLength(moveT * pathLength);
            coinMaster.setAttribute('transform', `translate(${point.x}, ${point.y})`);

            // 3. 金币缩放与弹簧效果
            let coinScale = 0;
            if (t < 0.1) {
                // 弹簧弹出
                coinScale = easeOutElastic(t / 0.1);
            } else if (t >= 0.1 && t < 0.85) {
                // 飞行中保持原大小
                coinScale = 1;
            } else if (t >= 0.85 && t < 0.95) {
                // 缩入钱包消失
                const shrinkT = (t - 0.85) / 0.1;
                coinScale = 1 - easeInCubic(shrinkT);
            }
            coinScaler.setAttribute('transform', `scale(${coinScale})`);

            // 4. 钱包接收反馈 (0.85 - 0.95)
            let walletScale = 1;
            let rScale = 0;
            let rOp = 0;

            if (t >= 0.82 && t < 0.98) {
                // 稍微提前一点点触发钱包呼吸，让衔接更自然
                const wT = (t - 0.82) / 0.16;
                walletScale = 1 + Math.sin(wT * Math.PI) * 0.12; // 放大再缩小
                
                // 涟漪效果
                if (t >= 0.85) {
                    const ripT = (t - 0.85) / 0.1;
                    rScale = ripT;
                    rOp = 1 - ripT;
                }
            }
            walletGroup.setAttribute('transform', `translate(0, 10) scale(${walletScale})`);
            
            ripple1.setAttribute('r', rScale * 60);
            ripple1.setAttribute('opacity', rOp);
            
            // 第二层涟漪稍有延迟
            let r2Scale = 0, r2Op = 0;
            if (t >= 0.87 && t < 0.97) {
                const rip2T = (t - 0.87) / 0.1;
                r2Scale = rip2T;
                r2Op = 1 - rip2T;
            }
            ripple2.setAttribute('r', r2Scale * 45);
            ripple2.setAttribute('opacity', r2Op * 0.8);

            // 5. 状态文字更新
            if (t > 0.85 && t < 0.98) {
                statusText.textContent = "入账成功 +10,000";
                statusText.setAttribute('fill', 'var(--mint-primary)');
            } else {
                statusText.textContent = "等待接收...";
                statusText.setAttribute('fill', 'var(--text-sub)');
            }

            // 循环调用
            requestAnimationFrame(renderLoop);
        }

        // 启动唯一动画主循环
        requestAnimationFrame(renderLoop);
    });
</script>
</body>
</html>16:T85d5,<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>马年起飞 - 坦克大战2026 (加强版)</title>
    <!-- 引入像素字体 -->
    <link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&family=ZCOOL+KuaiLe&display=swap" rel="stylesheet">
    <!-- 引入烟花库 -->
    <script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.6.0/dist/confetti.browser.min.js"></script>
    <style>
        :root {
            --bg-color: #000000;
            --wall-color: #b53120;
            --wall-stroke: #802015;
            --text-inactive: #4a4a4a;
            --text-active: #f7d010;
            --player-color: #f7d010;
            --enemy-color: #cccccc;
        }

        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            background-color: var(--bg-color);
            overflow: hidden;
            font-family: 'Press Start 2P', 'ZCOOL KuaiLe', cursive, monospace;
            user-select: none;
        }

        #game-container {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 1200px;
            height: 700px;
            background-color: #050505;
            box-shadow: 0 0 20px rgba(0, 0, 0, 0.8);
            border: 4px solid #333;
        }

        /* UI Overlay */
        .ui-layer {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            display: flex;
            flex-direction: column;
            align-items: center;
            z-index: 10;
        }

        .header-hud {
            margin-top: 20px;
            display: flex;
            gap: 40px;
            align-items: center;
        }

        /* 通用HUD容器样式 (血条和文字共用) */
        .hud-panel {
            display: flex;
            align-items: center;
            gap: 15px;
            background: rgba(0, 0, 0, 0.6);
            padding: 10px 20px;
            border: 2px solid #555;
            border-radius: 4px;
            box-shadow: 0 4px 0 rgba(0,0,0,0.5);
        }

        .char-container {
            display: flex;
            gap: 20px;
        }

        .char-slot {
            font-size: 32px;
            color: var(--text-inactive);
            text-shadow: 2px 2px 0px #000;
            transition: all 0.3s ease;
            position: relative;
        }

        .char-slot.active {
            color: var(--text-active);
            text-shadow: 0 0 10px var(--text-active), 4px 4px 0px #b53120;
            transform: scale(1.2);
            animation: bounce 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
        }

        /* HP Bar Styles */
        .hp-label {
            color: #f7d010;
            font-size: 20px;
            text-shadow: 2px 2px 0 #000;
        }

        .hp-bar-bg {
            width: 150px;
            height: 20px;
            background: #333;
            border: 2px solid #fff;
            position: relative;
        }

        .hp-bar-fill {
            width: 100%;
            height: 100%;
            background: #2ecc71;
            transition: width 0.2s ease-out, background-color 0.2s;
        }

        @keyframes bounce {
            0% { transform: scale(1); }
            50% { transform: scale(1.5); }
            100% { transform: scale(1.2); }
        }

        /* SVG Game Layer */
        svg {
            width: 100%;
            height: 100%;
            display: block;
        }

        /* Start/End Screen */
        .overlay-screen {
            position: absolute;
            top: 0; left: 0; width: 100%; height: 100%;
            background: rgba(0,0,0,0.85);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 20;
            color: white;
            text-align: center;
        }

        .hidden { display: none !important; }

        h1 { color: #b53120; text-shadow: 4px 4px 0 #fff; font-size: 60px; margin-bottom: 20px; }
        p { font-size: 18px; line-height: 1.6; color: #ccc; margin-bottom: 40px; }
        .btn {
            background: #b53120;
            color: white;
            border: 4px solid white;
            padding: 15px 40px;
            font-size: 24px;
            font-family: inherit;
            cursor: pointer;
            text-transform: uppercase;
            box-shadow: 6px 6px 0px rgba(255,255,255,0.2);
            pointer-events: auto;
        }
        .btn:hover { background: #d94230; transform: translate(-2px, -2px); box-shadow: 8px 8px 0px rgba(255,255,255,0.2); }
        .btn:active { transform: translate(2px, 2px); box-shadow: 2px 2px 0px rgba(255,255,255,0.2); }

    </style>
</head>
<body>

<div id="game-container">
    <!-- Game SVG -->
    <svg id="game-svg" viewBox="0 0 1200 700" preserveAspectRatio="xMidYMid slice">
        <defs>
            <!-- Brick Pattern -->
            <pattern id="brick-pattern" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
                <rect width="20" height="20" fill="#b53120"/>
                <path d="M0 10 H20 M10 0 V10 M10 10 V20" stroke="#802015" stroke-width="2"/>
                <rect x="2" y="2" width="16" height="6" fill="#d44530"/>
                <rect x="2" y="12" width="6" height="6" fill="#d44530"/>
                <rect x="12" y="12" width="6" height="6" fill="#d44530"/>
            </pattern>
            
            <!-- Glow Filter for Red Enemies -->
            <filter id="red-glow" x="-50%" y="-50%" width="200%" height="200%">
                <feGaussianBlur in="SourceGraphic" stdDeviation="4" result="blur" />
                <feColorMatrix in="blur" type="matrix" values="
                    0 0 0 0 1
                    0 0 0 0 0
                    0 0 0 0 0
                    0 0 0 1 0" result="redBlur" />
                <feMerge>
                    <feMergeNode in="redBlur" />
                    <feMergeNode in="SourceGraphic" />
                </feMerge>
            </filter>

            <!-- Gold Shine Filter -->
            <filter id="gold-shine">
                <feSpecularLighting result="spec" specularConstant="1.2" specularExponent="20" lighting-color="#fff">
                    <fePointLight x="10" y="10" z="20"/>
                </feSpecularLighting>
                <feComposite in="spec" in2="SourceAlpha" operator="in" result="specOut"/>
                <feComposite in="SourceGraphic" in2="specOut" operator="arithmetic" k1="0" k2="1" k3="1" k4="0"/>
            </filter>
        </defs>

        <g id="layer-ground">
            <rect width="1200" height="700" fill="#111"/>
            <!-- Grid Lines -->
            <path d="M0 0" stroke="#222" stroke-width="1" id="grid-lines"/>
        </g>
        
        <g id="layer-base"></g>
        <g id="layer-walls"></g>
        <g id="layer-items"></g> <!-- Layer for PowerUps -->
        <g id="layer-bullets"></g>
        <g id="layer-enemies"></g>
        <g id="layer-player"></g>
        <g id="layer-fx"></g>
    </svg>

    <!-- UI Overlay -->
    <div class="ui-layer">
        <div class="header-hud">
            <!-- HP Bar -->
            <div class="hud-panel">
                <div class="hp-label">1P HP</div>
                <div class="hp-bar-bg">
                    <div id="player-hp-bar" class="hp-bar-fill"></div>
                </div>
            </div>
            <!-- Text Collection (Now with border) -->
            <div class="hud-panel">
                <div class="char-container">
                    <div class="char-slot" id="char-0">马</div>
                    <div class="char-slot" id="char-1">年</div>
                    <div class="char-slot" id="char-2">起</div>
                    <div class="char-slot" id="char-3">飞</div>
                </div>
            </div>
        </div>
    </div>

    <!-- Start Screen -->
    <div id="start-screen" class="overlay-screen">
        <h1>TANK 2026</h1>
        <p>方向键移动 / 自动射击<br>击毁<span style="color:#ff4444; text-shadow:0 0 5px red">红色发光坦克</span>点亮文字<br>击毁<span style="color:#ffd700">金色坦克</span>获取超级武器<br>集齐 "马年起飞" 召唤烟花</p>
        <button class="btn" onclick="startGame()">开始游戏</button>
    </div>

    <!-- Win Screen -->
    <div id="win-screen" class="overlay-screen hidden">
        <h1 style="color:#f7d010">胜利!</h1>
        <p>2026 马年大吉<br>所有字符已点亮</p>
        <button class="btn" onclick="location.reload()">再玩一次</button>
    </div>

    <!-- Fail Screen -->
    <div id="fail-screen" class="overlay-screen hidden">
        <h1 style="color:#e74c3c">任务失败</h1>
        <p id="fail-reason">堡垒已沦陷</p>
        <button class="btn" onclick="startGame()">重新挑战</button>
    </div>
</div>

<script>
    /**
     * Constants & Config
     */
    const CONFIG = {
        width: 1200,
        height: 700,
        gridSize: 40,
        playerSpeed: 3,
        enemySpeed: 1.5,
        bulletSpeed: 7,
        fireRate: 400, // ms
        enemyFireRate: 1500,
        maxEnemies: 5,
        spawnInterval: 2000,
        chars: ['马', '年', '起', '飞'],
        colors: {
            player: '#f7d010',
            enemyNormal: '#cccccc', 
            enemyRed: '#e74c3c', 
            enemyGold: '#ffd700',
        },
        maxPlayerHp: 3
    };

    /**
     * Game State
     */
    const state = {
        isRunning: false,
        lastTime: 0,
        keys: { ArrowUp: false, ArrowDown: false, ArrowLeft: false, ArrowRight: false },
        player: null,
        enemies: [],
        bullets: [],
        walls: [],
        items: [], // PowerUps
        progress: [false, false, false, false],
        enemySpawnTimer: 0,
        frameCount: 0,
        base: null
    };

    /**
     * Map Data "2026"
     */
    function generateMap() {
        const map = [];
        const offsetX = 5; 
        const offsetY = 3;

        // Helper to add pixel block
        const addBlock = (x, y) => map.push({ x: (x + offsetX) * CONFIG.gridSize, y: (y + offsetY) * CONFIG.gridSize, w: CONFIG.gridSize, h: CONFIG.gridSize, hp: 1 });

        // Digit 2
        const draw2 = (ox) => {
            [0,1,2,3].forEach(i => addBlock(ox+i, 0)); 
            addBlock(ox+3, 1); addBlock(ox+3, 2);
            [0,1,2,3].forEach(i => addBlock(ox+i, 3)); 
            addBlock(ox, 4); addBlock(ox, 5);
            [0,1,2,3].forEach(i => addBlock(ox+i, 6)); 
        };

        // Digit 0
        const draw0 = (ox) => {
            [0,1,2,3].forEach(i => addBlock(ox+i, 0)); 
            [0,1,2,3].forEach(i => addBlock(ox+i, 6)); 
            [1,2,3,4,5].forEach(i => { addBlock(ox, i); addBlock(ox+3, i); }); 
        };

        // Digit 6
        const draw6 = (ox) => {
            [0,1,2,3].forEach(i => addBlock(ox+i, 0)); 
            [1,2].forEach(i => addBlock(ox, i)); 
            [0,1,2,3].forEach(i => addBlock(ox+i, 3)); 
            [4,5].forEach(i => { addBlock(ox, i); addBlock(ox+3, i); }); 
            [0,1,2,3].forEach(i => addBlock(ox+i, 6)); 
        };

        draw2(0);
        draw0(5);
        draw2(10);
        draw6(15);

        // Base Protection Walls
        const bx = 15; 
        const by = 16;
        
        const baseWalls = [
            {x: bx-1, y: by},   // Left
            {x: bx-1, y: by-1}, // Top-Left
            {x: bx, y: by-1},   // Top
            {x: bx+1, y: by-1}, // Top-Right
            {x: bx+1, y: by}    // Right
        ];

        baseWalls.forEach(p => {
            map.push({ x: p.x * CONFIG.gridSize, y: p.y * CONFIG.gridSize, w: CONFIG.gridSize, h: CONFIG.gridSize, hp: 1 });
        });

        // Random scattered blocks
        for(let i=0; i<12; i++) {
            let rx = Math.floor(Math.random() * 28);
            let ry = Math.floor(Math.random() * 15);
            if (ry > 10 && rx > 10 && rx < 20) continue;
            let exists = map.some(b => b.x === rx * CONFIG.gridSize && b.y === ry * CONFIG.gridSize);
            if(!exists) map.push({ x: rx * CONFIG.gridSize, y: ry * CONFIG.gridSize, w: CONFIG.gridSize, h: CONFIG.gridSize, hp: 1 });
        }

        return map;
    }

    /**
     * SVG Helpers
     */
    const svgNS = "http://www.w3.org/2000/svg";
    const layers = {
        ground: document.getElementById('layer-ground'),
        base: document.getElementById('layer-base'),
        walls: document.getElementById('layer-walls'),
        items: document.getElementById('layer-items'),
        bullets: document.getElementById('layer-bullets'),
        enemies: document.getElementById('layer-enemies'),
        player: document.getElementById('layer-player'),
        fx: document.getElementById('layer-fx')
    };

    function createRect(x, y, w, h, fill, parent) {
        const rect = document.createElementNS(svgNS, 'rect');
        rect.setAttribute('x', x);
        rect.setAttribute('y', y);
        rect.setAttribute('width', w);
        rect.setAttribute('height', h);
        rect.setAttribute('fill', fill);
        if(parent) parent.appendChild(rect);
        return rect;
    }

    function createTankSVG(type) {
        const g = document.createElementNS(svgNS, 'g');
        let mainColor = CONFIG.colors.enemyNormal;
        let isPlayer = type === 'player';
        
        if (isPlayer) mainColor = CONFIG.colors.player;
        else if (type === 'red') mainColor = CONFIG.colors.enemyRed;
        else if (type === 'gold') mainColor = CONFIG.colors.enemyGold;

        // Apply filters
        if (type === 'red') g.setAttribute('filter', 'url(#red-glow)');
        if (type === 'gold') g.setAttribute('filter', 'url(#gold-shine)');

        // Tracks
        createRect(0, 0, 10, 36, '#222', g);
        createRect(30, 0, 10, 36, '#222', g);
        
        // Body
        createRect(5, 5, 30, 26, mainColor, g);
        
        // Turret
        const turret = createRect(12, 10, 16, 16, isPlayer ? '#fff' : '#444', g);
        turret.setAttribute('opacity', '0.6');

        // Gun
        createRect(18, -4, 4, 18, '#111', g); 
        
        // Detail
        if(isPlayer) createRect(16, 14, 8, 8, '#b53120', g);
        if(type === 'red') createRect(16, 14, 8, 8, '#fff', g); // Core for red tank

        return g;
    }

    function createEagleSVG(x, y) {
        const g = document.createElementNS(svgNS, 'g');
        g.setAttribute('transform', `translate(${x}, ${y})`);
        createRect(0, 0, 40, 40, '#000', g);
        const eagleColor = '#bdc3c7';
        createRect(4, 12, 32, 8, eagleColor, g);
        createRect(4, 8, 8, 4, eagleColor, g);
        createRect(28, 8, 8, 4, eagleColor, g);
        createRect(16, 4, 8, 8, eagleColor, g);
        createRect(22, 6, 4, 2, '#e74c3c', g);
        createRect(12, 20, 16, 12, eagleColor, g);
        createRect(12, 32, 4, 4, '#f39c12', g);
        createRect(24, 32, 4, 4, '#f39c12', g);
        createRect(18, 24, 4, 4, '#b53120', g);
        layers.base.appendChild(g);
        return g;
    }

    function createWeaponSVG(x, y) {
        const g = document.createElementNS(svgNS, 'g');
        g.setAttribute('transform', `translate(${x}, ${y})`);
        
        // Star/Weapon shape
        const star = document.createElementNS(svgNS, 'polygon');
        star.setAttribute('points', '20,2 25,14 38,14 28,22 32,34 20,26 8,34 12,22 2,14 15,14');
        star.setAttribute('fill', '#f7d010');
        star.setAttribute('stroke', '#fff');
        star.setAttribute('stroke-width', '2');
        
        // Animation
        const anim = document.createElementNS(svgNS, 'animateTransform');
        anim.setAttribute('attributeName', 'transform');
        anim.setAttribute('type', 'scale');
        anim.setAttribute('values', '0.8;1.2;0.8');
        anim.setAttribute('dur', '1s');
        anim.setAttribute('repeatCount', 'indefinite');
        anim.setAttribute('additive', 'sum');
        
        // Center pivot for scale
        const center = document.createElementNS(svgNS, 'animateTransform');
        center.setAttribute('attributeName', 'transform');
        center.setAttribute('type', 'translate');
        center.setAttribute('values', '20 20');
        center.setAttribute('additive', 'sum');
        
        const uncenter = document.createElementNS(svgNS, 'animateTransform');
        uncenter.setAttribute('attributeName', 'transform');
        uncenter.setAttribute('type', 'translate');
        uncenter.setAttribute('values', '-20 -20');
        uncenter.setAttribute('additive', 'sum');

        star.appendChild(center);
        star.appendChild(anim);
        star.appendChild(uncenter);
        
        g.appendChild(star);
        layers.items.appendChild(g);
        return g;
    }

    /**
     * Classes
     */
    class Base {
        constructor() {
            this.x = 600; 
            this.y = 640; 
            this.w = 40;
            this.h = 40;
            this.active = true;
            this.el = createEagleSVG(this.x, this.y);
        }

        destroy() {
            if (!this.active) return;
            this.active = false;
            if (this.el) {
                this.el.innerHTML = ''; 
                createRect(0, 0, 40, 40, '#000', this.el);
                createRect(5, 5, 10, 10, '#555', this.el);
                createRect(20, 25, 15, 10, '#555', this.el);
                createExplosion(this.x + 20, this.y + 20, 60);
            }
        }
    }

    class PowerUp {
        constructor(x, y) {
            this.x = x;
            this.y = y;
            this.w = 40;
            this.h = 40;
            this.active = true;
            this.el = createWeaponSVG(x, y);
        }
        
        collect() {
            this.active = false;
            if(this.el.parentNode) this.el.parentNode.removeChild(this.el);
        }
    }

    class Tank {
        constructor(x, y, type) {
            this.x = x;
            this.y = y;
            this.w = 40;
            this.h = 40;
            this.dir = 0; // 0:Up, 1:Right, 2:Down, 3:Left
            this.type = type; // 'player', 'normal', 'red', 'gold'
            this.isPlayer = (type === 'player');
            this.speed = this.isPlayer ? CONFIG.playerSpeed : CONFIG.enemySpeed;
            this.lastFire = 0;
            this.hp = this.isPlayer ? CONFIG.maxPlayerHp : (type === 'gold' ? 2 : 1); // Gold tanks tougher
            
            // Player stats
            this.fireRate = this.isPlayer ? CONFIG.fireRate : CONFIG.enemyFireRate;
            this.bulletSpeed = CONFIG.bulletSpeed;
            this.isPoweredUp = false;

            this.el = createTankSVG(type);
            this.el.setAttribute('transform', `translate(${x},${y})`);
            
            (this.isPlayer ? layers.player : layers.enemies).appendChild(this.el);
        }

        powerUp() {
            if (!this.isPlayer) return;
            this.isPoweredUp = true;
            // Enhance stats: 3x firepower (speed) and fire rate
            this.fireRate = CONFIG.fireRate / 3; 
            this.bulletSpeed = CONFIG.bulletSpeed * 2.5; // 3x might be too fast for collision detection
            
            // Visual feedback
            this.el.querySelector('rect[width="4"]').setAttribute('fill', '#ff0000'); // Red gun
            createExplosion(this.x+20, this.y+20, 50); // Effect
        }

        update() {
            let dx = 0, dy = 0;
            let moved = false;

            if (this.isPlayer) {
                if (state.keys.ArrowUp) { dy = -this.speed; this.dir = 0; moved = true; }
                else if (state.keys.ArrowDown) { dy = this.speed; this.dir = 2; moved = true; }
                else if (state.keys.ArrowLeft) { dx = -this.speed; this.dir = 3; moved = true; }
                else if (state.keys.ArrowRight) { dx = this.speed; this.dir = 1; moved = true; }
                
                const now = Date.now();
                if (now - this.lastFire > this.fireRate) {
                    this.fire();
                    this.lastFire = now;
                }
            } else {
                // AI
                const moveDirs = [{x:0, y:-1}, {x:1, y:0}, {x:0, y:1}, {x:-1, y:0}];
                dx = moveDirs[this.dir].x * this.speed;
                dy = moveDirs[this.dir].y * this.speed;
                moved = true;

                if (Math.random() < 0.02) this.dir = Math.floor(Math.random() * 4);
                
                const now = Date.now();
                if (now - this.lastFire > this.fireRate) {
                    this.fire();
                    this.lastFire = now + Math.random() * 500;
                }
            }

            let nx = this.x + dx;
            let ny = this.y + dy;

            if (nx < 0) nx = 0;
            if (ny < 0) ny = 0;
            if (nx > CONFIG.width - this.w) nx = CONFIG.width - this.w;
            if (ny > CONFIG.height - this.h) ny = CONFIG.height - this.h;

            const hitWall = checkWallCollision(nx, ny, this.w, this.h);
            const hitOther = checkTankCollision(this, nx, ny);
            const hitBase = state.base && state.base.active && intersect(nx, ny, this.w, this.h, state.base.x, state.base.y, state.base.w, state.base.h);

            if (!hitWall && !hitOther && !hitBase) {
                this.x = nx;
                this.y = ny;
            } else if (!this.isPlayer) {
                this.dir = Math.floor(Math.random() * 4);
            }

            const rot = this.dir * 90;
            this.el.setAttribute('transform', `translate(${this.x + 20}, ${this.y + 20}) rotate(${rot}) translate(-20, -20)`);
        }

        fire() {
            const bx = this.x + 20 - 4; 
            const by = this.y + 20 - 4;
            let vx = 0, vy = 0;
            if (this.dir === 0) { vy = -this.bulletSpeed; }
            if (this.dir === 1) { vx = this.bulletSpeed; }
            if (this.dir === 2) { vy = this.bulletSpeed; }
            if (this.dir === 3) { vx = -this.bulletSpeed; }
            
            const startX = bx + vx * 2;
            const startY = by + vy * 2;

            state.bullets.push(new Bullet(startX, startY, vx, vy, this.isPlayer));
        }

        destroy() {
            if (this.el.parentNode) this.el.parentNode.removeChild(this.el);
            createExplosion(this.x + 20, this.y + 20, 40);

            // Special Logic based on Type
            if (this.type === 'red') {
                handleTextUnlock();
            } else if (this.type === 'gold') {
                spawnWeapon();
            }
        }
    }

    class Bullet {
        constructor(x, y, vx, vy, isPlayer) {
            this.x = x;
            this.y = y;
            this.vx = vx;
            this.vy = vy;
            this.w = 8;
            this.h = 8;
            this.isPlayer = isPlayer;
            this.dead = false;
            
            this.el = document.createElementNS(svgNS, 'circle');
            this.el.setAttribute('r', 4);
            this.el.setAttribute('fill', isPlayer ? '#fff' : '#ff0000');
            layers.bullets.appendChild(this.el);
        }

        update() {
            this.x += this.vx;
            this.y += this.vy;

            if (this.x < 0 || this.x > CONFIG.width || this.y < 0 || this.y > CONFIG.height) {
                this.dead = true;
            }

            const wallIdx = getWallCollisionIndex(this.x, this.y, this.w, this.h);
            if (wallIdx !== -1) {
                this.dead = true;
                state.walls[wallIdx].hp--;
                if(state.walls[wallIdx].hp <= 0) {
                    const w = state.walls[wallIdx];
                    if(w.el.parentNode) w.el.parentNode.removeChild(w.el);
                    createExplosion(w.x + w.w/2, w.y + w.h/2, 20);
                    state.walls.splice(wallIdx, 1);
                }
            }

            if (state.base && state.base.active) {
                if (intersect(this.x, this.y, this.w, this.h, state.base.x, state.base.y, state.base.w, state.base.h)) {
                    this.dead = true;
                    state.base.destroy();
                    gameFail("堡垒已沦陷");
                    return;
                }
            }

            if (this.isPlayer) {
                for (let i = 0; i < state.enemies.length; i++) {
                    const e = state.enemies[i];
                    if (intersect(this.x, this.y, this.w, this.h, e.x, e.y, e.w, e.h)) {
                        this.dead = true;
                        e.hp--;
                        if (e.hp <= 0) {
                            e.destroy();
                            state.enemies.splice(i, 1);
                        } else {
                            // Hit effect
                            createExplosion(this.x, this.y, 10);
                        }
                        break;
                    }
                }
            } else {
                if (state.player && intersect(this.x, this.y, this.w, this.h, state.player.x, state.player.y, state.player.w, state.player.h)) {
                    this.dead = true;
                    state.player.hp--;
                    updateHpUI();
                    createExplosion(this.x, this.y, 10);
                    
                    if (state.player.hp <= 0) {
                        state.player.destroy();
                        state.player = null;
                        gameFail("坦克被摧毁");
                    }
                }
            }

            if (this.dead) {
                if (this.el.parentNode) this.el.parentNode.removeChild(this.el);
            } else {
                this.el.setAttribute('cx', this.x + 4);
                this.el.setAttribute('cy', this.y + 4);
            }
        }
    }

    /**
     * Logic Helpers
     */
    function intersect(x1, y1, w1, h1, x2, y2, w2, h2) {
        return x1 < x2 + w2 && x1 + w1 > x2 && y1 < y2 + h2 && y1 + h1 > y2;
    }

    function checkWallCollision(x, y, w, h) {
        for (let wall of state.walls) {
            if (intersect(x, y, w, h, wall.x, wall.y, wall.w, wall.h)) return true;
        }
        return false;
    }

    function getWallCollisionIndex(x, y, w, h) {
        for (let i = 0; i < state.walls.length; i++) {
            let wall = state.walls[i];
            if (intersect(x, y, w, h, wall.x, wall.y, wall.w, wall.h)) return i;
        }
        return -1;
    }

    function checkTankCollision(self, x, y) {
        for (let e of state.enemies) {
            if (e === self) continue;
            if (intersect(x, y, self.w, self.h, e.x, e.y, e.w, e.h)) return true;
        }
        if (state.player && self !== state.player) {
            if (intersect(x, y, self.w, self.h, state.player.x, state.player.y, state.player.w, state.player.h)) return true;
        }
        return false;
    }

    function createExplosion(x, y, size) {
        const exp = document.createElementNS(svgNS, 'circle');
        exp.setAttribute('cx', x);
        exp.setAttribute('cy', y);
        exp.setAttribute('r', 1);
        exp.setAttribute('fill', 'orange');
        exp.setAttribute('stroke', 'yellow');
        exp.setAttribute('stroke-width', 2);
        layers.fx.appendChild(exp);

        exp.style.transition = 'all 0.3s ease-out';
        setTimeout(() => {
            exp.setAttribute('r', size);
            exp.setAttribute('opacity', 0);
        }, 10);
        setTimeout(() => {
            if(exp.parentNode) exp.parentNode.removeChild(exp);
        }, 310);
    }

    function handleTextUnlock() {
        const remaining = state.progress.map((v, i) => v ? -1 : i).filter(i => i !== -1);
        
        if (remaining.length > 0) {
            const idx = remaining[Math.floor(Math.random() * remaining.length)];
            state.progress[idx] = true;
            const el = document.getElementById(`char-${idx}`);
            el.classList.add('active');
            
            if (state.progress.every(v => v)) {
                gameWin();
            }
        }
    }

    function spawnWeapon() {
        let attempts = 0;
        let x, y;
        let valid = false;
        
        while(attempts < 50 && !valid) {
            x = Math.floor(Math.random() * (CONFIG.width - 40));
            y = Math.floor(Math.random() * (CONFIG.height - 40));
            
            // Align to grid roughly
            x = Math.floor(x / 20) * 20;
            y = Math.floor(y / 20) * 20;

            // Check collisions
            if (!checkWallCollision(x, y, 40, 40) && 
                !intersect(x, y, 40, 40, state.base.x, state.base.y, state.base.w, state.base.h)) {
                valid = true;
            }
            attempts++;
        }

        if (valid) {
            state.items.push(new PowerUp(x, y));
        }
    }

    function updateHpUI() {
        const bar = document.getElementById('player-hp-bar');
        const pct = state.player ? (state.player.hp / CONFIG.maxPlayerHp) * 100 : 0;
        bar.style.width = `${pct}%`;
        
        if (pct > 60) bar.style.backgroundColor = '#2ecc71';
        else if (pct > 30) bar.style.backgroundColor = '#f1c40f';
        else bar.style.backgroundColor = '#e74c3c';
    }

    /**
     * Main Game Loop
     */
    function startGame() {
        document.getElementById('start-screen').classList.add('hidden');
        document.getElementById('win-screen').classList.add('hidden');
        document.getElementById('fail-screen').classList.add('hidden');
        
        // Reset Entities
        state.enemies.forEach(e => { if(e.el.parentNode) e.el.parentNode.removeChild(e.el); });
        state.bullets.forEach(b => { if(b.el.parentNode) b.el.parentNode.removeChild(b.el); });
        state.walls.forEach(w => { if(w.el.parentNode) w.el.parentNode.removeChild(w.el); });
        state.items.forEach(i => { if(i.el.parentNode) i.el.parentNode.removeChild(i.el); });
        if (state.base && state.base.el.parentNode) state.base.el.parentNode.removeChild(state.base.el);
        
        state.enemies = [];
        state.bullets = [];
        state.walls = [];
        state.items = [];
        state.progress = [false, false, false, false];
        state.isRunning = true;
        
        document.querySelectorAll('.char-slot').forEach(el => el.classList.remove('active'));

        const mapData = generateMap();
        mapData.forEach(b => {
            const el = createRect(b.x, b.y, b.w, b.h, 'url(#brick-pattern)', layers.walls);
            el.setAttribute('stroke', '#000');
            state.walls.push({ ...b, el });
        });

        state.base = new Base();

        if(state.player && state.player.el.parentNode) state.player.el.parentNode.removeChild(state.player.el);
        state.player = new Tank(480, 640, 'player');
        updateHpUI();

        state.lastTime = Date.now();
        requestAnimationFrame(loop);
    }

    function gameWin() {
        state.isRunning = false;
        document.getElementById('win-screen').classList.remove('hidden');
        
        const end = Date.now() + 5000;
        const colors = ['#bb0000', '#f7d010', '#ffffff'];

        (function frame() {
            confetti({
                particleCount: 3,
                angle: 60,
                spread: 55,
                origin: { x: 0 },
                colors: colors
            });
            confetti({
                particleCount: 3,
                angle: 120,
                spread: 55,
                origin: { x: 1 },
                colors: colors
            });

            if (Date.now() < end) {
                requestAnimationFrame(frame);
            }
        }());
    }

    function gameFail(reason) {
        state.isRunning = false;
        document.getElementById('fail-reason').innerText = reason;
        document.getElementById('fail-screen').classList.remove('hidden');
    }

    function loop() {
        if (!state.isRunning) return;

        const now = Date.now();
        state.lastTime = now;

        // Spawn Enemies
        if (state.enemies.length < CONFIG.maxEnemies && now > state.enemySpawnTimer) {
            const spawnPoints = [{x:0,y:0}, {x:CONFIG.width-40, y:0}, {x:0, y:CONFIG.height-40}];
            const pt = spawnPoints[Math.floor(Math.random()*spawnPoints.length)];
            
            if (!checkTankCollision({w:40, h:40}, pt.x, pt.y)) {
                // Determine Type
                const rand = Math.random();
                let type = 'normal';
                if (rand < 0.15) type = 'gold'; // 15% Gold
                else if (rand < 0.45) type = 'red'; // 30% Red (Text carrier)
                
                state.enemies.push(new Tank(pt.x, pt.y, type));
                state.enemySpawnTimer = now + CONFIG.spawnInterval;
            }
        }

        // Update Entities
        if (state.player) {
            state.player.update();
            
            // Check Item Collection
            for (let i = state.items.length - 1; i >= 0; i--) {
                const item = state.items[i];
                if (intersect(state.player.x, state.player.y, state.player.w, state.player.h, item.x, item.y, item.w, item.h)) {
                    item.collect();
                    state.items.splice(i, 1);
                    state.player.powerUp();
                }
            }
        }

        state.enemies.forEach(e => e.update());
        
        for (let i = state.bullets.length - 1; i >= 0; i--) {
            state.bullets[i].update();
            if (state.bullets[i].dead) {
                state.bullets.splice(i, 1);
            }
        }

        requestAnimationFrame(loop);
    }

    /**
     * Input Handling
     */
    window.addEventListener('keydown', (e) => {
        if (state.keys.hasOwnProperty(e.code)) state.keys[e.code] = true;
    });

    window.addEventListener('keyup', (e) => {
        if (state.keys.hasOwnProperty(e.code)) state.keys[e.code] = false;
    });

</script>
</body>
</html>17:T6d2f,<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Global Expedition: Cape to Cape</title>
    <script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
    <script src="https://cdn.jsdelivr.net/npm/topojson-client@3"></script>
    <script src="https://unpkg.com/lucide@latest"></script>
    <style>
        :root {
            --bg-color: #0F172A;
            --primary: #38BDF8;
            --secondary: #94A3B8;
            --accent: #FBBF24;
            --danger: #EF4444;
            --grid: rgba(56, 189, 248, 0.1);
            --font-main: 'Montserrat', 'PingFang SC', sans-serif;
            --font-mono: 'Courier New', monospace;
        }

        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            background-color: var(--bg-color);
            overflow: hidden;
            font-family: var(--font-main);
            color: var(--primary);
            display: flex;
            justify-content: center;
            align-items: center;
        }

        #container {
            position: relative;
            width: 100vw;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background: radial-gradient(circle at center, #1e293b 0%, #0f172a 100%);
        }

        svg {
            width: 100%;
            height: 100%;
            max-width: 1200px;
            max-height: 700px;
            filter: drop-shadow(0 0 30px rgba(0,0,0,0.5));
        }

        /* UI Elements */
        .hud-text {
            font-family: var(--font-mono);
            text-transform: uppercase;
            letter-spacing: 1px;
            pointer-events: none;
        }

        .title-group text {
            fill: #F8FAFC;
            text-shadow: 0 0 10px rgba(56, 189, 248, 0.5);
        }

        .panel-bg {
            fill: rgba(15, 23, 42, 0.85);
            stroke: var(--primary);
            stroke-width: 1;
            stroke-opacity: 0.5;
        }

        .marker-label {
            font-size: 12px;
            font-weight: bold;
            fill: var(--accent);
            text-shadow: 0 2px 4px rgba(0,0,0,0.8);
            opacity: 0;
            transition: opacity 0.3s;
        }

        .marker-point {
            fill: var(--accent);
            stroke: #fff;
            stroke-width: 2;
            cursor: pointer;
        }

        .pulse-ring {
            fill: none;
            stroke: var(--accent);
            stroke-width: 1;
            opacity: 0;
            transform-origin: center;
        }

        /* Loading Screen */
        #loader {
            position: absolute;
            top: 0; left: 0; width: 100%; height: 100%;
            background: var(--bg-color);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 100;
            transition: opacity 0.8s ease-out;
        }
        .loader-bar {
            width: 200px;
            height: 2px;
            background: #1e293b;
            margin-top: 20px;
            position: relative;
            overflow: hidden;
        }
        .loader-progress {
            position: absolute;
            left: 0; top: 0; bottom: 0;
            width: 0%;
            background: var(--primary);
            box-shadow: 0 0 10px var(--primary);
            transition: width 0.2s;
        }

        /* Animations */
        @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
        .blink { animation: blink 2s infinite; }
        
        @keyframes rotate-ui { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
        .rotating { animation: rotate-ui 10s linear infinite; transform-origin: center; }

    </style>
</head>
<body>

    <div id="loader">
        <div style="color: var(--primary); font-family: var(--font-mono); letter-spacing: 4px;">SYSTEM INITIALIZING</div>
        <div class="loader-bar"><div class="loader-progress" id="load-bar"></div></div>
    </div>

    <div id="container">
        <svg id="scene" viewBox="0 0 1200 700" preserveAspectRatio="xMidYMid meet">
            <defs>
                <!-- Filters & Gradients -->
                <radialGradient id="oceanGradient" cx="50%" cy="50%" r="50%" fx="25%" fy="25%">
                    <stop offset="0%" stop-color="#334155" />
                    <stop offset="100%" stop-color="#020617" />
                </radialGradient>
                
                <filter id="glow-blue" x="-50%" y="-50%" width="200%" height="200%">
                    <feGaussianBlur stdDeviation="4" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over" />
                </filter>

                <filter id="glow-gold" x="-50%" y="-50%" width="200%" height="200%">
                    <feGaussianBlur stdDeviation="3" result="blur" />
                    <feMerge>
                        <feMergeNode in="blur" />
                        <feMergeNode in="SourceGraphic" />
                    </feMerge>
                </filter>

                <mask id="globeMask">
                    <circle cx="600" cy="350" r="250" fill="white" />
                </mask>

                <pattern id="gridPattern" width="40" height="40" patternUnits="userSpaceOnUse">
                    <path d="M 40 0 L 0 0 0 40" fill="none" stroke="var(--grid)" stroke-width="0.5"/>
                </pattern>
            </defs>

            <!-- Background Elements -->
            <g id="stars-bg"></g>
            <rect width="100%" height="100%" fill="url(#gridPattern)" opacity="0.3" pointer-events="none"/>

            <!-- Main Globe Group -->
            <g id="globe-group">
                <!-- Atmosphere Glow -->
                <circle cx="600" cy="350" r="255" fill="#38BDF8" opacity="0.1" filter="url(#glow-blue)" />
                
                <!-- Ocean -->
                <circle cx="600" cy="350" r="250" fill="url(#oceanGradient)" stroke="#475569" stroke-width="1" />

                <!-- Map Content (Clipped to Sphere) -->
                <g id="geo-content">
                    <path id="graticule" fill="none" stroke="#475569" stroke-width="0.5" opacity="0.3" />
                    <path id="land" fill="#1e293b" stroke="#64748b" stroke-width="0.5" />
                    
                    <!-- Route Lines -->
                    <path id="route-bg" fill="none" stroke="#38BDF8" stroke-width="1" opacity="0.3" stroke-dasharray="2 4" />
                    <path id="route-active" fill="none" stroke="#FBBF24" stroke-width="2.5" stroke-linecap="round" filter="url(#glow-gold)" />
                    
                    <!-- Markers Container -->
                    <g id="markers-layer"></g>

                    <!-- Moving Target Indicator -->
                    <g id="target-cursor" style="display: none;">
                        <circle r="6" fill="none" stroke="#FBBF24" stroke-width="2" />
                        <circle r="12" fill="none" stroke="#FBBF24" stroke-width="1" opacity="0.5" />
                        <line x1="-15" y1="0" x2="15" y2="0" stroke="#FBBF24" stroke-width="1" />
                        <line x1="0" y1="-15" x2="0" y2="15" stroke="#FBBF24" stroke-width="1" />
                    </g>
                </g>
                
                <!-- Globe Shadow (Night side) -->
                <path id="night-shadow" fill="#020617" opacity="0.4" style="mix-blend-mode: multiply;" pointer-events="none" />
            </g>

            <!-- HUD / UI Overlay -->
            <g class="hud-ui">
                <!-- Top Header -->
                <g transform="translate(600, 60)">
                    <text text-anchor="middle" font-size="24" font-weight="800" fill="#F8FAFC" letter-spacing="4">GLOBAL EXPEDITION</text>
                    <text y="25" text-anchor="middle" font-size="12" fill="#94A3B8" letter-spacing="2">TRANS-CONTINENTAL TRAJECTORY // 跨大陆征途</text>
                    <line x1="-200" y1="40" x2="200" y2="40" stroke="url(#oceanGradient)" stroke-width="1" />
                    <rect x="-150" y="39" width="300" height="2" fill="#38BDF8" opacity="0.5" />
                </g>

                <!-- Left Panel: Location Info -->
                <g transform="translate(50, 150)">
                    <path d="M0,0 L240,0 L260,20 L260,120 L20,120 L0,100 Z" class="panel-bg" />
                    <rect x="0" y="0" width="4" height="40" fill="#FBBF24" />
                    
                    <text x="20" y="30" class="hud-text" font-size="10" fill="#94A3B8">CURRENT LOCATION / 当前位置</text>
                    <text id="ui-location-name" x="20" y="55" class="hud-text" font-size="18" font-weight="bold" fill="#F8FAFC">INITIALIZING...</text>
                    
                    <text x="20" y="85" class="hud-text" font-size="10" fill="#94A3B8">COORDINATES / 坐标</text>
                    <text id="ui-coords" x="20" y="100" class="hud-text" font-size="14" fill="#38BDF8">00°00' N, 00°00' E</text>
                </g>

                <!-- Right Panel: Mission Status -->
                <g transform="translate(890, 150)">
                    <path d="M20,0 L260,0 L260,100 L240,120 L0,120 L0,20 Z" class="panel-bg" />
                    <rect x="256" y="0" width="4" height="40" fill="#38BDF8" />

                    <text x="240" y="30" text-anchor="end" class="hud-text" font-size="10" fill="#94A3B8">MISSION PROGRESS / 进程</text>
                    <text id="ui-progress" x="240" y="60" text-anchor="end" class="hud-text" font-size="32" font-weight="bold" fill="#F8FAFC">0%</text>
                    
                    <rect x="40" y="80" width="200" height="4" fill="#1e293b" />
                    <rect id="ui-progress-bar" x="40" y="80" width="0" height="4" fill="#FBBF24" filter="url(#glow-gold)" />
                </g>

                <!-- Bottom Panel: Waypoints Log -->
                <g transform="translate(300, 620)">
                    <line x1="0" y1="0" x2="600" y2="0" stroke="#334155" stroke-width="1" />
                    <circle cx="0" cy="0" r="3" fill="#38BDF8" />
                    <circle cx="600" cy="0" r="3" fill="#38BDF8" />
                    
                    <text x="300" y="25" text-anchor="middle" class="hud-text blink" font-size="12" fill="#FBBF24">
                        <tspan id="ui-status-msg">WAITING FOR SATELLITE LINK...</tspan>
                    </text>
                </g>

                <!-- Decorative Compass -->
                <g transform="translate(1100, 600)" opacity="0.6">
                    <circle r="40" fill="none" stroke="#38BDF8" stroke-width="1" stroke-dasharray="4 4" />
                    <circle r="30" fill="none" stroke="#94A3B8" stroke-width="0.5" />
                    <path d="M0,-35 L5,-5 L35,0 L5,5 L0,35 L-5,5 L-35,0 L-5,-5 Z" fill="#1e293b" stroke="#38BDF8" stroke-width="1" class="rotating" />
                    <text x="0" y="-50" text-anchor="middle" font-size="10" fill="#38BDF8" font-family="monospace">N</text>
                </g>
            </g>
        </svg>
    </div>

    <script>
        // --- Configuration ---
        const CONFIG = {
            width: 1200,
            height: 700,
            globeRadius: 250,
            center: [600, 350],
            speed: 0.0015, // Animation speed
            pauseOnWaypoint: 60, // Frames to pause at key locations
            waypoints: [
                { name: "好望角 (起点)", en: "Cape of Good Hope", coords: [18.47, -34.35], type: "start" },
                { name: "坦桑尼亚", en: "Tanzania", coords: [34.88, -6.36], type: "pass" },
                { name: "开罗", en: "Cairo, Egypt", coords: [31.23, 30.04], type: "major" },
                { name: "德黑兰", en: "Tehran, Iran", coords: [51.38, 35.68], type: "pass" },
                { name: "中亚腹地", en: "Central Asia", coords: [65.00, 42.00], type: "pass" },
                { name: "新西伯利亚", en: "Novosibirsk", coords: [82.93, 55.00], type: "major" },
                { name: "雅库茨克", en: "Yakutsk", coords: [129.73, 62.03], type: "pass" },
                { name: "白令海峡", en: "Bering Strait", coords: [-169.00, 65.50], type: "critical" }, // Crossing point
                { name: "安克雷奇", en: "Anchorage", coords: [-149.90, 61.21], type: "major" },
                { name: "温哥华", en: "Vancouver", coords: [-123.12, 49.28], type: "pass" },
                { name: "巴拿马城", en: "Panama City", coords: [-79.51, 8.98], type: "major" },
                { name: "利马", en: "Lima, Peru", coords: [-77.04, -12.04], type: "pass" },
                { name: "合恩角 (终点)", en: "Cape Horn", coords: [-67.29, -55.98], type: "end" }
            ]
        };

        // --- Globals ---
        let projection, pathGenerator;
        let routePoints = [];
        let currentProgress = 0;
        let isPaused = false;
        let pauseTimer = 0;
        let animationId;
        let landFeature, graticuleFeature;
        
        // --- Initialization ---
        async function init() {
            const loaderBar = document.getElementById('load-bar');
            
            // 1. Setup D3 Projection
            projection = d3.geoOrthographic()
                .scale(CONFIG.globeRadius)
                .translate(CONFIG.center)
                .clipAngle(90);

            pathGenerator = d3.geoPath().projection(projection);

            // 2. Generate Stars
            generateStars();
            loaderBar.style.width = "30%";

            // 3. Load Map Data
            try {
                const worldData = await d3.json('https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json');
                landFeature = topojson.feature(worldData, worldData.objects.land);
                graticuleFeature = d3.geoGraticule()();
                loaderBar.style.width = "70%";
            } catch (e) {
                console.error("Failed to load map data", e);
                document.getElementById('ui-status-msg').textContent = "DATA LINK FAILED";
                return;
            }

            // 4. Calculate Route
            calculateRoute();
            loaderBar.style.width = "100%";

            // 5. Render Static Elements
            renderStaticMap();
            renderMarkers();

            // 6. Start Animation
            setTimeout(() => {
                document.getElementById('loader').style.opacity = 0;
                setTimeout(() => document.getElementById('loader').remove(), 800);
                animate();
            }, 500);

            // 7. Interaction
            setupInteraction();
        }

        function generateStars() {
            const starGroup = d3.select("#stars-bg");
            for(let i=0; i<300; i++) {
                starGroup.append("circle")
                    .attr("cx", Math.random() * CONFIG.width)
                    .attr("cy", Math.random() * CONFIG.height)
                    .attr("r", Math.random() * 1.5)
                    .attr("fill", "#fff")
                    .attr("opacity", Math.random() * 0.8);
            }
        }

        function calculateRoute() {
            // Create a dense array of points along the waypoints using Great Circle interpolation
            routePoints = [];
            for (let i = 0; i < CONFIG.waypoints.length - 1; i++) {
                const start = CONFIG.waypoints[i].coords;
                const end = CONFIG.waypoints[i+1].coords;
                const interpolator = d3.geoInterpolate(start, end);
                
                // Distance determines number of steps for constant speed
                const dist = d3.geoDistance(start, end);
                const steps = Math.max(20, Math.floor(dist * 200)); 

                for (let t = 0; t < steps; t++) {
                    routePoints.push(interpolator(t / steps));
                }
                // Add waypoint index marker to the point data for UI triggers
                routePoints[routePoints.length - 1].waypointIndex = i + 1;
            }
            routePoints.push(CONFIG.waypoints[CONFIG.waypoints.length - 1].coords);
        }

        function renderStaticMap() {
            d3.select("#land").datum(landFeature).attr("d", pathGenerator);
            d3.select("#graticule").datum(graticuleFeature).attr("d", pathGenerator);
            
            // Full Route Background (faint)
            const routeLineString = { type: "LineString", coordinates: routePoints };
            d3.select("#route-bg").datum(routeLineString).attr("d", pathGenerator);
        }

        function renderMarkers() {
            const container = d3.select("#markers-layer");
            
            CONFIG.waypoints.forEach((wp, index) => {
                const g = container.append("g")
                    .attr("class", "marker-group")
                    .attr("id", `marker-${index}`);

                // Pulse Ring
                g.append("circle")
                    .attr("class", "pulse-ring")
                    .attr("r", 8);

                // Center Point
                g.append("circle")
                    .attr("class", "marker-point")
                    .attr("r", index === 0 || index === CONFIG.waypoints.length-1 ? 5 : 3)
                    .attr("fill", wp.type === 'critical' ? '#EF4444' : '#FBBF24');

                // Label
                g.append("text")
                    .attr("class", "marker-label")
                    .attr("x", 10)
                    .attr("y", 4)
                    .text(wp.name);
            });
        }

        // --- Main Animation Loop ---
        function animate() {
            if (!isPaused) {
                // Handle Pausing at Waypoints
                if (pauseTimer > 0) {
                    pauseTimer--;
                    updateGlobeRotation(); // Keep rotating or holding? Let's hold slightly or drift.
                    requestAnimationFrame(animate);
                    return;
                }

                // Advance Progress
                currentProgress += CONFIG.speed;
                if (currentProgress >= 1) {
                    currentProgress = 1;
                    isPaused = true; // End of journey
                    document.getElementById('ui-status-msg').textContent = "MISSION ACCOMPLISHED / 抵达终点";
                    document.getElementById('ui-status-msg').parentElement.classList.remove('blink');
                }

                updateScene();
            }
            requestAnimationFrame(animate);
        }

        function updateScene() {
            const totalPoints = routePoints.length;
            const currentIndex = Math.floor(currentProgress * (totalPoints - 1));
            const currentPos = routePoints[currentIndex];

            // 1. Rotate Globe to center on current position
            // Smoothly interpolate rotation
            const targetRotate = [-currentPos[0], -currentPos[1]];
            const currentRotate = projection.rotate();
            
            // Simple easing for rotation
            const newRotate = [
                currentRotate[0] + (targetRotate[0] - currentRotate[0]) * 0.1,
                currentRotate[1] + (targetRotate[1] - currentRotate[1]) * 0.1
            ];
            projection.rotate(newRotate);

            // 2. Update Map Paths
            d3.select("#land").attr("d", pathGenerator);
            d3.select("#graticule").attr("d", pathGenerator);
            d3.select("#route-bg").attr("d", pathGenerator);

            // 3. Draw Active Route (from start to current)
            const activeRoute = {
                type: "LineString",
                coordinates: routePoints.slice(0, currentIndex + 1)
            };
            d3.select("#route-active").datum(activeRoute).attr("d", pathGenerator);

            // 4. Update Markers Visibility & Position
            updateMarkers(newRotate);

            // 5. Update Target Cursor
            const cursor = d3.select("#target-cursor");
            const projectedPos = projection(currentPos);
            
            // Check if point is visible (not on back of globe)
            const centerPos = projection.invert(CONFIG.center);
            const dist = d3.geoDistance(currentPos, centerPos);
            
            if (dist < 1.57) { // < 90 degrees approx
                cursor.style("display", "block")
                      .attr("transform", `translate(${projectedPos[0]}, ${projectedPos[1]})`);
            } else {
                cursor.style("display", "none");
            }

            // 6. Update UI
            updateUI(currentPos, currentIndex);

            // 7. Check for Waypoint Arrival
            if (currentPos.waypointIndex !== undefined) {
                // We hit a waypoint node
                const wpIndex = currentPos.waypointIndex;
                // Only pause if we haven't processed this index recently (simple debounce logic implied by linear progress)
                // To avoid multiple pauses, we remove the property or check a flag. 
                // Since we regenerate points, let's just use the fact that we are AT the index.
                // But float math is tricky. 
                
                // Better approach: Check distance to actual waypoints
                const nearestWP = CONFIG.waypoints.find(wp => d3.geoDistance(wp.coords, currentPos) < 0.005);
                if (nearestWP && !nearestWP.visited) {
                    nearestWP.visited = true;
                    pauseTimer = CONFIG.pauseOnWaypoint;
                    document.getElementById('ui-status-msg').textContent = `ARRIVED AT: ${nearestWP.en}`;
                    
                    // Trigger marker pulse
                    const markerSel = d3.select(`#marker-${CONFIG.waypoints.indexOf(nearestWP)}`);
                    markerSel.select(".pulse-ring")
                        .transition().duration(1000)
                        .attr("r", 20).style("opacity", 0)
                        .on("end", function() { d3.select(this).attr("r", 8).style("opacity", 1); });
                }
            }
        }

        function updateMarkers(rotation) {
            const centerPos = projection.invert(CONFIG.center);

            CONFIG.waypoints.forEach((wp, i) => {
                const dist = d3.geoDistance(wp.coords, centerPos);
                const isVisible = dist < 1.57; // 90 degrees
                const el = d3.select(`#marker-${i}`);
                
                if (isVisible) {
                    const pos = projection(wp.coords);
                    el.style("display", "block")
                      .attr("transform", `translate(${pos[0]}, ${pos[1]})`);
                    
                    // Show label if close to center or active
                    if (dist < 0.5 || wp.visited) {
                        el.select(".marker-label").style("opacity", 1);
                    } else {
                        el.select(".marker-label").style("opacity", 0.5);
                    }
                } else {
                    el.style("display", "none");
                }
            });
        }

        function updateUI(pos, idx) {
            // Coordinates
            const lat = pos[1];
            const lon = pos[0];
            const latStr = Math.abs(lat).toFixed(2) + "° " + (lat >= 0 ? "N" : "S");
            const lonStr = Math.abs(lon).toFixed(2) + "° " + (lon >= 0 ? "E" : "W");
            document.getElementById('ui-coords').textContent = `${latStr}, ${lonStr}`;

            // Progress
            const pct = Math.floor(currentProgress * 100);
            document.getElementById('ui-progress').textContent = pct + "%";
            document.getElementById('ui-progress-bar').setAttribute("width", pct * 2);

            // Location Name (Find nearest or generic)
            // Already handled by waypoint arrival, but for "In transit":
            if (pauseTimer === 0) {
                // Find previous waypoint
                let prevName = CONFIG.waypoints[0].name;
                for(let i=0; i<CONFIG.waypoints.length; i++) {
                    if (CONFIG.waypoints[i].visited) prevName = CONFIG.waypoints[i].name;
                }
                document.getElementById('ui-location-name').textContent = `EN ROUTE: ${prevName} -> ...`;
                document.getElementById('ui-status-msg').textContent = "TRACKING SATELLITE FEED...";
            } else {
                 // Paused at location
                 const currentWP = CONFIG.waypoints.find(wp => wp.visited && d3.geoDistance(wp.coords, pos) < 0.01);
                 if(currentWP) document.getElementById('ui-location-name').textContent = currentWP.name;
            }
        }

        function updateGlobeRotation() {
            // Helper to keep rotation smooth even when paused
            // (Optional: add subtle idle rotation)
        }

        // --- Interaction ---
        function setupInteraction() {
            let drag = false;
            let lastX, lastY;
            const svg = document.getElementById('scene');

            svg.addEventListener('pointerdown', (e) => {
                drag = true;
                lastX = e.clientX;
                lastY = e.clientY;
                isPaused = true; // Pause animation on drag
                svg.setPointerCapture(e.pointerId);
                document.getElementById('ui-status-msg').textContent = "MANUAL OVERRIDE ENGAGED";
            });

            svg.addEventListener('pointermove', (e) => {
                if (!drag) return;
                const dx = e.clientX - lastX;
                const dy = e.clientY - lastY;
                
                const rotate = projection.rotate();
                const k = 0.25; // sensitivity
                projection.rotate([rotate[0] + dx * k, rotate[1] - dy * k]);
                
                lastX = e.clientX;
                lastY = e.clientY;
                
                // Manual update of static elements only (path doesn't grow)
                d3.select("#land").attr("d", pathGenerator);
                d3.select("#graticule").attr("d", pathGenerator);
                d3.select("#route-bg").attr("d", pathGenerator);
                
                // Re-calculate active route visual for new angle
                const currentIndex = Math.floor(currentProgress * (routePoints.length - 1));
                const activeRoute = { type: "LineString", coordinates: routePoints.slice(0, currentIndex + 1) };
                d3.select("#route-active").datum(activeRoute).attr("d", pathGenerator);
                
                updateMarkers();
                
                // Hide cursor during manual drag usually, or update it
                const currentPos = routePoints[currentIndex];
                const projPos = projection(currentPos);
                const centerPos = projection.invert(CONFIG.center);
                if (d3.geoDistance(currentPos, centerPos) < 1.57) {
                    d3.select("#target-cursor")
                        .style("display", "block")
                        .attr("transform", `translate(${projPos[0]}, ${projPos[1]})`);
                } else {
                    d3.select("#target-cursor").style("display", "none");
                }
            });

            svg.addEventListener('pointerup', (e) => {
                drag = false;
                isPaused = false; // Resume
                svg.releasePointerCapture(e.pointerId);
                document.getElementById('ui-status-msg').textContent = "RESUMING AUTO-NAVIGATION...";
            });
        }

        // Run
        init();

    </script>
</body>
</html>18:T3ceb,'use client';

import React, { useState, useEffect, useRef, useMemo } from 'react';

// 视图常量
const VIEW_WIDTH = 1000;
const VIEW_HEIGHT = 600;
const COIL_CENTER_X = VIEW_WIDTH / 2;
const COIL_CENTER_Y = VIEW_HEIGHT / 2;
const COIL_RADIUS = 70;
const COIL_LOOPS = 12;
const COIL_WIDTH = 300;

export default function ElectromagneticInduction() {
  // 动画状态
  const [animState, setAnimState] = useState({
    magnetX: -200, // 磁铁位置
    velocity: 0,    // 磁铁速度
    current: 0,     // 感应电流强度
    flux: 0,        // 磁通量模拟值
    electronOffset: 0, // 电子流动偏移量
  });

  // 使用 ref 存储不触发重绘但需要在帧之间累积的数据
  const physicsRef = useRef({
    time: 0,
    electronPos: 0,
  });

  // 动画循环
  useEffect(() => {
    let animationFrameId;

    const loop = () => {
      const t = performance.now() / 1000; // 秒
      const dt = t - physicsRef.current.time;
      physicsRef.current.time = t;

      // 1. 计算磁铁运动 (简谐运动模拟实验操作)
      // 周期约 4秒
      const frequency = 0.5;
      const amplitude = 350;
      const centerX = COIL_CENTER_X;
      
      // 让磁铁在线圈左侧和右侧之间穿梭
      // x(t)
      const rawPos = Math.sin(t * frequency * Math.PI * 2); 
      const magnetX = centerX + rawPos * amplitude;

      // 2. 计算速度 v(t) (导数)
      // v 正比于 cos(...)
      const velocity = rawPos - (Math.sin((t - 0.016) * frequency * Math.PI * 2)); // 简单差分计算瞬时速度方向

      // 3. 计算感应电流 (法拉第电磁感应定律 + 楞次定律)
      // 只有当磁铁在线圈附近时，磁通量变化才剧烈
      // 使用高斯函数模拟磁场强度随距离衰减
      const distToCoil = Math.abs(magnetX - centerX);
      const fieldStrength = Math.exp(-(distToCoil * distToCoil) / (2 * 150 * 150)); // 靠近线圈时场强最大
      
      // dΦ/dt ∝ v * B
      // 感应电动势 E ∝ - dΦ/dt
      // 这里的 velocity 包含了方向，fieldStrength 是标量
      // 当磁铁穿过线圈中心时，磁通量最大，但变化率(dΦ/dt)在中心点瞬间为0吗？
      // 不，磁通量Φ是位置的函数。E = -dΦ/dt = -(dΦ/dx * dx/dt) = -(dΦ/dx * v)
      // 磁场分布大致是钟形，进入时 flux 增加，离开时 flux 减少。
      // 进入(v>0, x<center): flux增加 -> dΦ/dt > 0 -> E < 0
      // 离开(v>0, x>center): flux减少 -> dΦ/dt < 0 -> E > 0
      
      // 模拟 dΦ/dx (磁通量对位置的导数): 在中心左侧为正，右侧为负
      const dFlux_dx = (centerX - magnetX) / 200 * Math.exp(-(distToCoil * distToCoil) / (30000));
      
      // 电流 I ∝ E
      // 增加一些平滑系数
      const rawCurrent = dFlux_dx * (velocity * 100) * 100;
      
      // 限制最大电流显示范围
      const clampedCurrent = Math.max(-100, Math.min(100, rawCurrent));

      // 4. 更新电子流动位置
      // 电子流速与电流成正比
      physicsRef.current.electronPos -= clampedCurrent * 0.5; // 负号因为电子带负电，电流方向与电子运动相反

      setAnimState({
        magnetX,
        velocity: velocity * 1000,
        current: clampedCurrent,
        flux: fieldStrength * 100, // 仅用于UI显示磁场强弱
        electronOffset: physicsRef.current.electronPos
      });

      animationFrameId = requestAnimationFrame(loop);
    };

    // 启动
    animationFrameId = requestAnimationFrame(loop);

    return () => {
      cancelAnimationFrame(animationFrameId);
    };
  }, []);

  // 预计算线圈几何 (分前后两部分以实现3D遮挡)
  const { backCoils, frontCoils, wirePath } = useMemo(() => {
    const backs = [];
    const fronts = [];
    const step = COIL_WIDTH / COIL_LOOPS;
    const startX = COIL_CENTER_X - COIL_WIDTH / 2;

    // 生成螺旋线路径数据
    let pathD = `M ${startX} ${COIL_CENTER_Y - COIL_RADIUS}`;
    
    for (let i = 0; i < COIL_LOOPS; i++) {
      const x = startX + i * step;
      const nextX = startX + (i + 1) * step;
      
      // 后半圈 (上 -> 下)
      backs.push(
        <path
          key={`b-${i}`}
          d={`M ${x} ${COIL_CENTER_Y - COIL_RADIUS} Q ${x + step/2} ${COIL_CENTER_Y - COIL_RADIUS} ${x + step/2} ${COIL_CENTER_Y} T ${x + step} ${COIL_CENTER_Y + COIL_RADIUS}`}
          fill="none"
          stroke="url(#coilGradientDark)"
          strokeWidth="6"
          strokeLinecap="round"
        />
      );

      // 前半圈 (下 -> 上) - 注意这里为了视觉连贯，实际绘制顺序需要调整
      // 我们把螺旋拆分为：上半圆(后) 和 下半圆(前) ? 
      // 或者：后半圆(Y < CenterY, Z far) 和 前半圆 (Y > CenterY, Z near)?
      // 简单的 2.5D：
      // 上半部分(远端)
      backs.push(
        <path 
            key={`top-${i}`}
            d={`M ${x} ${COIL_CENTER_Y - COIL_RADIUS} A ${step/2} ${COIL_RADIUS} 0 0 1 ${x+step} ${COIL_CENTER_Y - COIL_RADIUS}`} // 这是一个半圆弧不太对，用贝塞尔曲线模拟
            // 重新逻辑：线圈是螺旋。
            // 每一个loop: 从 (x, top) 到 (x+0.5step, bottom) 是前还是后？
            // 假设视点在正前方。
            // 上半部分 (top) 是远的，下半部分 (bottom) 是近的？不，通常螺旋管平放。
            // 上边缘和下边缘。
            // 让我们假设：线圈的上半部分是"后面"，下半部分是"前面"。
        />
      );
    }
    
    // 重写生成逻辑，更清晰的 3D 感
    const bCoils = [];
    const fCoils = [];
    
    // 连接电路的导线路径
    const circuitPath = `
      M ${startX} ${COIL_CENTER_Y - COIL_RADIUS} 
      L ${startX - 50} ${COIL_CENTER_Y - COIL_RADIUS} 
      L ${startX - 50} ${VIEW_HEIGHT - 100} 
      L ${VIEW_WIDTH/2 - 50} ${VIEW_HEIGHT - 100} 
      L ${VIEW_WIDTH/2 - 50} ${VIEW_HEIGHT - 180}
      M ${VIEW_WIDTH/2 + 50} ${VIEW_HEIGHT - 180}
      L ${VIEW_WIDTH/2 + 50} ${VIEW_HEIGHT - 100}
      L ${startX + COIL_WIDTH + 50} ${VIEW_HEIGHT - 100}
      L ${startX + COIL_WIDTH + 50} ${COIL_CENTER_Y - COIL_RADIUS}
      L ${startX + COIL_WIDTH} ${COIL_CENTER_Y - COIL_RADIUS}
    `;

    for (let i = 0; i < COIL_LOOPS; i++) {
        const cx = startX + i * step;
        // 后半段弧线 (Top arc)
        bCoils.push(
            <path
                key={`b-${i}`}
                d={`M ${cx} ${COIL_CENTER_Y - COIL_RADIUS} C ${cx + step*0.5} ${COIL_CENTER_Y - COIL_RADIUS - 20}, ${cx + step*0.5} ${COIL_CENTER_Y + COIL_RADIUS + 20}, ${cx + step} ${COIL_CENTER_Y + COIL_RADIUS}`}
                fill="none"
                stroke="#334155" // 暗色，表示在后面
                strokeWidth="4"
                opacity="0.6"
            />
        );
        // 前半段弧线 (Bottom arc -> Next Top) - 修正：螺旋应该是连续的
        // 简化视觉：用椭圆切片。
        // 上半圆弧 (Back)
        bCoils.push(
            <path
                key={`back-${i}`}
                d={`M ${cx} ${COIL_CENTER_Y} Q ${cx + step/4} ${COIL_CENTER_Y - COIL_RADIUS} ${cx + step/2} ${COIL_CENTER_Y}`}
                fill="none"
                stroke="url(#coilGradientBack)"
                strokeWidth="8"
            />
        );
        // 下半圆弧 (Front)
        fCoils.push(
             <path
                key={`front-${i}`}
                d={`M ${cx + step/2} ${COIL_CENTER_Y} Q ${cx + step*0.75} ${COIL_CENTER_Y + COIL_RADIUS} ${cx + step} ${COIL_CENTER_Y}`}
                fill="none"
                stroke="url(#coilGradientFront)"
                strokeWidth="8"
            />
        );
    }

    return { backCoils: bCoils, frontCoils: fCoils, wirePath: circuitPath };
  }, []);

  // 动态颜色计算
  const coilColor = animState.current > 5 ? '#38bdf8' : (animState.current < -5 ? '#f472b6' : '#94a3b8');
  const glowOpacity = Math.min(Math.abs(animState.current) / 50, 1);
  
  // 磁力线生成
  const magnetLines = useMemo(() => {
    // 静态定义，但在渲染时通过 transform 移动
    return [-1, 1].map(side => (
       Array.from({length: 3}).map((_, i) => (
         <path 
            key={`${side}-${i}`}
            d={`M ${side * 75} 0 C ${side * 150} ${-60 - i*40}, ${side * 250} ${-80 - i*60}, ${side * 350} ${-100 - i*80}`}
            stroke={`rgba(255,255,255,${0.1 - i*0.02})`}
            strokeWidth="2"
            fill="none"
            transform="scale(1, 1)" // 这里的镜像会在后面处理
         />
       ))
    ));
  }, []);

  return (
    <svg viewBox={`0 0 ${VIEW_WIDTH} ${VIEW_HEIGHT}`} className="w-full h-full select-none" style={{ background: '#0f172a' }}>
      <defs>
        {/* 线圈渐变 */}
        <linearGradient id="coilGradientFront" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor="#cbd5e1" />
          <stop offset="50%" stopColor="#e2e8f0" />
          <stop offset="100%" stopColor="#64748b" />
        </linearGradient>
        <linearGradient id="coilGradientBack" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor="#334155" />
          <stop offset="100%" stopColor="#1e293b" />
        </linearGradient>
        
        {/* 磁铁渐变 */}
        <linearGradient id="magnetRed" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0%" stopColor="#ef4444" />
          <stop offset="100%" stopColor="#991b1b" />
        </linearGradient>
        <linearGradient id="magnetBlue" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0%" stopColor="#3b82f6" />
          <stop offset="100%" stopColor="#1d4ed8" />
        </linearGradient>

        {/* 发光滤镜 */}
        <filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
          <feGaussianBlur stdDeviation="4" result="coloredBlur" />
          <feMerge>
            <feMergeNode in="coloredBlur" />
            <feMergeNode in="SourceGraphic" />
          </feMerge>
        </filter>
        
        <filter id="textGlow">
            <feGaussianBlur stdDeviation="2" result="blur" />
             <feMerge>
                <feMergeNode in="blur" />
                <feMergeNode in="SourceGraphic" />
            </feMerge>
        </filter>
      </defs>

      {/* 背景网格 */}
      <pattern id="grid" width="50" height="50" patternUnits="userSpaceOnUse">
        <path d="M 50 0 L 0 0 0 50" fill="none" stroke="#1e293b" strokeWidth="1"/>
      </pattern>
      <rect width="100%" height="100%" fill="url(#grid)" />

      {/* 标题与数据展示 */}
      <g transform="translate(50, 50)">
        <text fill="#e2e8f0" fontSize="24" fontWeight="bold" filter="url(#textGlow)">法拉第电磁感应实验 (Faraday's Law)</text>
        <g transform="translate(0, 40)">
             <text fill="#94a3b8" fontSize="14">v (Velocity): {Math.abs(animState.velocity).toFixed(1)} m/s</text>
             <text y="20" fill={animState.current > 0 ? "#38bdf8" : (animState.current < 0 ? "#f472b6" : "#94a3b8")} fontSize="14">
                I (Induced Current): {animState.current.toFixed(2)} mA
             </text>
             <text y="40" fill="#94a3b8" fontSize="14">Φ (Magnetic Flux): {animState.flux.toFixed(1)} Wb</text>
        </g>
      </g>
      
      {/* 检流计 (Galvanometer) */}
      <g transform={`translate(${VIEW_WIDTH/2}, ${VIEW_HEIGHT - 120})`}>
        {/* 外壳 */}
        <circle r="60" fill="#1e293b" stroke="#475569" strokeWidth="4" />
        <circle r="50" fill="#0f172a" />
        
        {/* 刻度盘 */}
        {Array.from({length: 21}).map((_, i) => {
            const angle = -135 + i * (270/20);
            const isMajor = i % 5 === 0;
            return (
                <g key={i} transform={`rotate(${angle})`}>
                    <line y1="-40" y2={isMajor ? "-30" : "-35"} stroke="#cbd5e1" strokeWidth={isMajor ? 2 : 1} />
                </g>
            )
        })}
        <text y="25" textAnchor="middle" fill="#94a3b8" fontSize="10" letterSpacing="1">GALVANOMETER</text>
        <text y="-25" textAnchor="middle" fill="#64748b" fontSize="12" fontWeight="bold">0</text>
        <text x="-35" y="10" textAnchor="middle" fill="#64748b" fontSize="10">-</text>
        <text x="35" y="10" textAnchor="middle" fill="#64748b" fontSize="10">+</text>

        {/* 指针 */}
        <g transform={`rotate(${animState.current * 1.5})`}>
            <line y1="10" y2="-45" stroke="#ef4444" strokeWidth="2" strokeLinecap="round" />
            <circle r="4" fill="#e2e8f0" />
        </g>
      </g>

      {/* 电路连线 */}
      <path d={wirePath} stroke="#475569" strokeWidth="4" fill="none" />
      
      {/* 电子流 (虚线动画) */}
      <path 
        d={wirePath} 
        stroke={animState.current > 0 ? "#38bdf8" : "#f472b6"} 
        strokeWidth="2" 
        fill="none" 
        strokeDasharray="10 15"
        strokeDashoffset={animState.electronOffset}
        opacity={Math.min(Math.abs(animState.current)/10, 1)}
        filter="url(#glow)"
      />

      {/* 线圈 (后半部分) */}
      <g>{backCoils}</g>

      {/* 磁铁 (N极红色，S极蓝色) */}
      <g transform={`translate(${animState.magnetX}, ${COIL_CENTER_Y})`}>
        {/* 磁场线 */}
        <g opacity={animState.flux / 100}>
            {/* 上下对称的磁感线 */}
            <g transform="scale(1, 1)">
                {magnetLines}
                <g transform="scale(1, -1)">{magnetLines}</g>
            </g>
            <g transform="scale(-1, 1)">
                {magnetLines}
                <g transform="scale(1, -1)">{magnetLines}</g>
            </g>
        </g>

        {/* 磁铁本体 */}
        <g transform="translate(-75, -25)">
            <rect x="0" y="0" width="75" height="50" fill="url(#magnetBlue)" />
            <rect x="75" y="0" width="75" height="50" fill="url(#magnetRed)" />
            
            {/* 标签 */}
            <text x="20" y="32" fill="white" fontSize="20" fontWeight="bold" opacity="0.8">S</text>
            <text x="115" y="32" fill="white" fontSize="20" fontWeight="bold" opacity="0.8">N</text>
            
            {/* 高光 */}
            <rect x="0" y="0" width="150" height="50" fill="url(#glassShine)" stroke="rgba(255,255,255,0.2)" strokeWidth="1"/>
            <path d="M 0 0 L 150 0 L 150 5 L 0 5 Z" fill="rgba(255,255,255,0.3)" />
        </g>
      </g>

      {/* 线圈 (前半部分) */}
      <g>
          {frontCoils}
          {/* 动态发光覆盖层，表示有电流通过线圈 */}
          <g opacity={glowOpacity} filter="url(#glow)">
             {React.Children.map(frontCoils, (child) => {
                 return React.cloneElement(child, {
                     stroke: coilColor,
                     strokeWidth: 4
                 });
             })}
          </g>
      </g>

      {/* 楞次定律指示箭头 */}
      {Math.abs(animState.current) > 10 && (
          <g transform={`translate(${COIL_CENTER_X}, ${COIL_CENTER_Y - COIL_RADIUS - 40})`}>
              <text textAnchor="middle" fill={coilColor} fontSize="14" fontWeight="bold" filter="url(#textGlow)">
                  {animState.current > 0 ? "← 阻碍磁通量增加 (Opposing Increase)" : "→ 阻碍磁通量减少 (Opposing Decrease)"}
              </text>
              <path 
                d="M -30 10 L 30 10" 
                stroke={coilColor} 
                strokeWidth="2" 
                markerEnd="url(#arrow)"
                transform={animState.current > 0 ? "rotate(0)" : "rotate(180)"}
              />
          </g>
      )}

    </svg>
  );
}
19:T6d2f,<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Global Expedition: Cape to Cape</title>
    <script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
    <script src="https://cdn.jsdelivr.net/npm/topojson-client@3"></script>
    <script src="https://unpkg.com/lucide@latest"></script>
    <style>
        :root {
            --bg-color: #0F172A;
            --primary: #38BDF8;
            --secondary: #94A3B8;
            --accent: #FBBF24;
            --danger: #EF4444;
            --grid: rgba(56, 189, 248, 0.1);
            --font-main: 'Montserrat', 'PingFang SC', sans-serif;
            --font-mono: 'Courier New', monospace;
        }

        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            background-color: var(--bg-color);
            overflow: hidden;
            font-family: var(--font-main);
            color: var(--primary);
            display: flex;
            justify-content: center;
            align-items: center;
        }

        #container {
            position: relative;
            width: 100vw;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background: radial-gradient(circle at center, #1e293b 0%, #0f172a 100%);
        }

        svg {
            width: 100%;
            height: 100%;
            max-width: 1200px;
            max-height: 700px;
            filter: drop-shadow(0 0 30px rgba(0,0,0,0.5));
        }

        /* UI Elements */
        .hud-text {
            font-family: var(--font-mono);
            text-transform: uppercase;
            letter-spacing: 1px;
            pointer-events: none;
        }

        .title-group text {
            fill: #F8FAFC;
            text-shadow: 0 0 10px rgba(56, 189, 248, 0.5);
        }

        .panel-bg {
            fill: rgba(15, 23, 42, 0.85);
            stroke: var(--primary);
            stroke-width: 1;
            stroke-opacity: 0.5;
        }

        .marker-label {
            font-size: 12px;
            font-weight: bold;
            fill: var(--accent);
            text-shadow: 0 2px 4px rgba(0,0,0,0.8);
            opacity: 0;
            transition: opacity 0.3s;
        }

        .marker-point {
            fill: var(--accent);
            stroke: #fff;
            stroke-width: 2;
            cursor: pointer;
        }

        .pulse-ring {
            fill: none;
            stroke: var(--accent);
            stroke-width: 1;
            opacity: 0;
            transform-origin: center;
        }

        /* Loading Screen */
        #loader {
            position: absolute;
            top: 0; left: 0; width: 100%; height: 100%;
            background: var(--bg-color);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 100;
            transition: opacity 0.8s ease-out;
        }
        .loader-bar {
            width: 200px;
            height: 2px;
            background: #1e293b;
            margin-top: 20px;
            position: relative;
            overflow: hidden;
        }
        .loader-progress {
            position: absolute;
            left: 0; top: 0; bottom: 0;
            width: 0%;
            background: var(--primary);
            box-shadow: 0 0 10px var(--primary);
            transition: width 0.2s;
        }

        /* Animations */
        @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
        .blink { animation: blink 2s infinite; }
        
        @keyframes rotate-ui { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
        .rotating { animation: rotate-ui 10s linear infinite; transform-origin: center; }

    </style>
</head>
<body>

    <div id="loader">
        <div style="color: var(--primary); font-family: var(--font-mono); letter-spacing: 4px;">SYSTEM INITIALIZING</div>
        <div class="loader-bar"><div class="loader-progress" id="load-bar"></div></div>
    </div>

    <div id="container">
        <svg id="scene" viewBox="0 0 1200 700" preserveAspectRatio="xMidYMid meet">
            <defs>
                <!-- Filters & Gradients -->
                <radialGradient id="oceanGradient" cx="50%" cy="50%" r="50%" fx="25%" fy="25%">
                    <stop offset="0%" stop-color="#334155" />
                    <stop offset="100%" stop-color="#020617" />
                </radialGradient>
                
                <filter id="glow-blue" x="-50%" y="-50%" width="200%" height="200%">
                    <feGaussianBlur stdDeviation="4" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over" />
                </filter>

                <filter id="glow-gold" x="-50%" y="-50%" width="200%" height="200%">
                    <feGaussianBlur stdDeviation="3" result="blur" />
                    <feMerge>
                        <feMergeNode in="blur" />
                        <feMergeNode in="SourceGraphic" />
                    </feMerge>
                </filter>

                <mask id="globeMask">
                    <circle cx="600" cy="350" r="250" fill="white" />
                </mask>

                <pattern id="gridPattern" width="40" height="40" patternUnits="userSpaceOnUse">
                    <path d="M 40 0 L 0 0 0 40" fill="none" stroke="var(--grid)" stroke-width="0.5"/>
                </pattern>
            </defs>

            <!-- Background Elements -->
            <g id="stars-bg"></g>
            <rect width="100%" height="100%" fill="url(#gridPattern)" opacity="0.3" pointer-events="none"/>

            <!-- Main Globe Group -->
            <g id="globe-group">
                <!-- Atmosphere Glow -->
                <circle cx="600" cy="350" r="255" fill="#38BDF8" opacity="0.1" filter="url(#glow-blue)" />
                
                <!-- Ocean -->
                <circle cx="600" cy="350" r="250" fill="url(#oceanGradient)" stroke="#475569" stroke-width="1" />

                <!-- Map Content (Clipped to Sphere) -->
                <g id="geo-content">
                    <path id="graticule" fill="none" stroke="#475569" stroke-width="0.5" opacity="0.3" />
                    <path id="land" fill="#1e293b" stroke="#64748b" stroke-width="0.5" />
                    
                    <!-- Route Lines -->
                    <path id="route-bg" fill="none" stroke="#38BDF8" stroke-width="1" opacity="0.3" stroke-dasharray="2 4" />
                    <path id="route-active" fill="none" stroke="#FBBF24" stroke-width="2.5" stroke-linecap="round" filter="url(#glow-gold)" />
                    
                    <!-- Markers Container -->
                    <g id="markers-layer"></g>

                    <!-- Moving Target Indicator -->
                    <g id="target-cursor" style="display: none;">
                        <circle r="6" fill="none" stroke="#FBBF24" stroke-width="2" />
                        <circle r="12" fill="none" stroke="#FBBF24" stroke-width="1" opacity="0.5" />
                        <line x1="-15" y1="0" x2="15" y2="0" stroke="#FBBF24" stroke-width="1" />
                        <line x1="0" y1="-15" x2="0" y2="15" stroke="#FBBF24" stroke-width="1" />
                    </g>
                </g>
                
                <!-- Globe Shadow (Night side) -->
                <path id="night-shadow" fill="#020617" opacity="0.4" style="mix-blend-mode: multiply;" pointer-events="none" />
            </g>

            <!-- HUD / UI Overlay -->
            <g class="hud-ui">
                <!-- Top Header -->
                <g transform="translate(600, 60)">
                    <text text-anchor="middle" font-size="24" font-weight="800" fill="#F8FAFC" letter-spacing="4">GLOBAL EXPEDITION</text>
                    <text y="25" text-anchor="middle" font-size="12" fill="#94A3B8" letter-spacing="2">TRANS-CONTINENTAL TRAJECTORY // 跨大陆征途</text>
                    <line x1="-200" y1="40" x2="200" y2="40" stroke="url(#oceanGradient)" stroke-width="1" />
                    <rect x="-150" y="39" width="300" height="2" fill="#38BDF8" opacity="0.5" />
                </g>

                <!-- Left Panel: Location Info -->
                <g transform="translate(50, 150)">
                    <path d="M0,0 L240,0 L260,20 L260,120 L20,120 L0,100 Z" class="panel-bg" />
                    <rect x="0" y="0" width="4" height="40" fill="#FBBF24" />
                    
                    <text x="20" y="30" class="hud-text" font-size="10" fill="#94A3B8">CURRENT LOCATION / 当前位置</text>
                    <text id="ui-location-name" x="20" y="55" class="hud-text" font-size="18" font-weight="bold" fill="#F8FAFC">INITIALIZING...</text>
                    
                    <text x="20" y="85" class="hud-text" font-size="10" fill="#94A3B8">COORDINATES / 坐标</text>
                    <text id="ui-coords" x="20" y="100" class="hud-text" font-size="14" fill="#38BDF8">00°00' N, 00°00' E</text>
                </g>

                <!-- Right Panel: Mission Status -->
                <g transform="translate(890, 150)">
                    <path d="M20,0 L260,0 L260,100 L240,120 L0,120 L0,20 Z" class="panel-bg" />
                    <rect x="256" y="0" width="4" height="40" fill="#38BDF8" />

                    <text x="240" y="30" text-anchor="end" class="hud-text" font-size="10" fill="#94A3B8">MISSION PROGRESS / 进程</text>
                    <text id="ui-progress" x="240" y="60" text-anchor="end" class="hud-text" font-size="32" font-weight="bold" fill="#F8FAFC">0%</text>
                    
                    <rect x="40" y="80" width="200" height="4" fill="#1e293b" />
                    <rect id="ui-progress-bar" x="40" y="80" width="0" height="4" fill="#FBBF24" filter="url(#glow-gold)" />
                </g>

                <!-- Bottom Panel: Waypoints Log -->
                <g transform="translate(300, 620)">
                    <line x1="0" y1="0" x2="600" y2="0" stroke="#334155" stroke-width="1" />
                    <circle cx="0" cy="0" r="3" fill="#38BDF8" />
                    <circle cx="600" cy="0" r="3" fill="#38BDF8" />
                    
                    <text x="300" y="25" text-anchor="middle" class="hud-text blink" font-size="12" fill="#FBBF24">
                        <tspan id="ui-status-msg">WAITING FOR SATELLITE LINK...</tspan>
                    </text>
                </g>

                <!-- Decorative Compass -->
                <g transform="translate(1100, 600)" opacity="0.6">
                    <circle r="40" fill="none" stroke="#38BDF8" stroke-width="1" stroke-dasharray="4 4" />
                    <circle r="30" fill="none" stroke="#94A3B8" stroke-width="0.5" />
                    <path d="M0,-35 L5,-5 L35,0 L5,5 L0,35 L-5,5 L-35,0 L-5,-5 Z" fill="#1e293b" stroke="#38BDF8" stroke-width="1" class="rotating" />
                    <text x="0" y="-50" text-anchor="middle" font-size="10" fill="#38BDF8" font-family="monospace">N</text>
                </g>
            </g>
        </svg>
    </div>

    <script>
        // --- Configuration ---
        const CONFIG = {
            width: 1200,
            height: 700,
            globeRadius: 250,
            center: [600, 350],
            speed: 0.0015, // Animation speed
            pauseOnWaypoint: 60, // Frames to pause at key locations
            waypoints: [
                { name: "好望角 (起点)", en: "Cape of Good Hope", coords: [18.47, -34.35], type: "start" },
                { name: "坦桑尼亚", en: "Tanzania", coords: [34.88, -6.36], type: "pass" },
                { name: "开罗", en: "Cairo, Egypt", coords: [31.23, 30.04], type: "major" },
                { name: "德黑兰", en: "Tehran, Iran", coords: [51.38, 35.68], type: "pass" },
                { name: "中亚腹地", en: "Central Asia", coords: [65.00, 42.00], type: "pass" },
                { name: "新西伯利亚", en: "Novosibirsk", coords: [82.93, 55.00], type: "major" },
                { name: "雅库茨克", en: "Yakutsk", coords: [129.73, 62.03], type: "pass" },
                { name: "白令海峡", en: "Bering Strait", coords: [-169.00, 65.50], type: "critical" }, // Crossing point
                { name: "安克雷奇", en: "Anchorage", coords: [-149.90, 61.21], type: "major" },
                { name: "温哥华", en: "Vancouver", coords: [-123.12, 49.28], type: "pass" },
                { name: "巴拿马城", en: "Panama City", coords: [-79.51, 8.98], type: "major" },
                { name: "利马", en: "Lima, Peru", coords: [-77.04, -12.04], type: "pass" },
                { name: "合恩角 (终点)", en: "Cape Horn", coords: [-67.29, -55.98], type: "end" }
            ]
        };

        // --- Globals ---
        let projection, pathGenerator;
        let routePoints = [];
        let currentProgress = 0;
        let isPaused = false;
        let pauseTimer = 0;
        let animationId;
        let landFeature, graticuleFeature;
        
        // --- Initialization ---
        async function init() {
            const loaderBar = document.getElementById('load-bar');
            
            // 1. Setup D3 Projection
            projection = d3.geoOrthographic()
                .scale(CONFIG.globeRadius)
                .translate(CONFIG.center)
                .clipAngle(90);

            pathGenerator = d3.geoPath().projection(projection);

            // 2. Generate Stars
            generateStars();
            loaderBar.style.width = "30%";

            // 3. Load Map Data
            try {
                const worldData = await d3.json('https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json');
                landFeature = topojson.feature(worldData, worldData.objects.land);
                graticuleFeature = d3.geoGraticule()();
                loaderBar.style.width = "70%";
            } catch (e) {
                console.error("Failed to load map data", e);
                document.getElementById('ui-status-msg').textContent = "DATA LINK FAILED";
                return;
            }

            // 4. Calculate Route
            calculateRoute();
            loaderBar.style.width = "100%";

            // 5. Render Static Elements
            renderStaticMap();
            renderMarkers();

            // 6. Start Animation
            setTimeout(() => {
                document.getElementById('loader').style.opacity = 0;
                setTimeout(() => document.getElementById('loader').remove(), 800);
                animate();
            }, 500);

            // 7. Interaction
            setupInteraction();
        }

        function generateStars() {
            const starGroup = d3.select("#stars-bg");
            for(let i=0; i<300; i++) {
                starGroup.append("circle")
                    .attr("cx", Math.random() * CONFIG.width)
                    .attr("cy", Math.random() * CONFIG.height)
                    .attr("r", Math.random() * 1.5)
                    .attr("fill", "#fff")
                    .attr("opacity", Math.random() * 0.8);
            }
        }

        function calculateRoute() {
            // Create a dense array of points along the waypoints using Great Circle interpolation
            routePoints = [];
            for (let i = 0; i < CONFIG.waypoints.length - 1; i++) {
                const start = CONFIG.waypoints[i].coords;
                const end = CONFIG.waypoints[i+1].coords;
                const interpolator = d3.geoInterpolate(start, end);
                
                // Distance determines number of steps for constant speed
                const dist = d3.geoDistance(start, end);
                const steps = Math.max(20, Math.floor(dist * 200)); 

                for (let t = 0; t < steps; t++) {
                    routePoints.push(interpolator(t / steps));
                }
                // Add waypoint index marker to the point data for UI triggers
                routePoints[routePoints.length - 1].waypointIndex = i + 1;
            }
            routePoints.push(CONFIG.waypoints[CONFIG.waypoints.length - 1].coords);
        }

        function renderStaticMap() {
            d3.select("#land").datum(landFeature).attr("d", pathGenerator);
            d3.select("#graticule").datum(graticuleFeature).attr("d", pathGenerator);
            
            // Full Route Background (faint)
            const routeLineString = { type: "LineString", coordinates: routePoints };
            d3.select("#route-bg").datum(routeLineString).attr("d", pathGenerator);
        }

        function renderMarkers() {
            const container = d3.select("#markers-layer");
            
            CONFIG.waypoints.forEach((wp, index) => {
                const g = container.append("g")
                    .attr("class", "marker-group")
                    .attr("id", `marker-${index}`);

                // Pulse Ring
                g.append("circle")
                    .attr("class", "pulse-ring")
                    .attr("r", 8);

                // Center Point
                g.append("circle")
                    .attr("class", "marker-point")
                    .attr("r", index === 0 || index === CONFIG.waypoints.length-1 ? 5 : 3)
                    .attr("fill", wp.type === 'critical' ? '#EF4444' : '#FBBF24');

                // Label
                g.append("text")
                    .attr("class", "marker-label")
                    .attr("x", 10)
                    .attr("y", 4)
                    .text(wp.name);
            });
        }

        // --- Main Animation Loop ---
        function animate() {
            if (!isPaused) {
                // Handle Pausing at Waypoints
                if (pauseTimer > 0) {
                    pauseTimer--;
                    updateGlobeRotation(); // Keep rotating or holding? Let's hold slightly or drift.
                    requestAnimationFrame(animate);
                    return;
                }

                // Advance Progress
                currentProgress += CONFIG.speed;
                if (currentProgress >= 1) {
                    currentProgress = 1;
                    isPaused = true; // End of journey
                    document.getElementById('ui-status-msg').textContent = "MISSION ACCOMPLISHED / 抵达终点";
                    document.getElementById('ui-status-msg').parentElement.classList.remove('blink');
                }

                updateScene();
            }
            requestAnimationFrame(animate);
        }

        function updateScene() {
            const totalPoints = routePoints.length;
            const currentIndex = Math.floor(currentProgress * (totalPoints - 1));
            const currentPos = routePoints[currentIndex];

            // 1. Rotate Globe to center on current position
            // Smoothly interpolate rotation
            const targetRotate = [-currentPos[0], -currentPos[1]];
            const currentRotate = projection.rotate();
            
            // Simple easing for rotation
            const newRotate = [
                currentRotate[0] + (targetRotate[0] - currentRotate[0]) * 0.1,
                currentRotate[1] + (targetRotate[1] - currentRotate[1]) * 0.1
            ];
            projection.rotate(newRotate);

            // 2. Update Map Paths
            d3.select("#land").attr("d", pathGenerator);
            d3.select("#graticule").attr("d", pathGenerator);
            d3.select("#route-bg").attr("d", pathGenerator);

            // 3. Draw Active Route (from start to current)
            const activeRoute = {
                type: "LineString",
                coordinates: routePoints.slice(0, currentIndex + 1)
            };
            d3.select("#route-active").datum(activeRoute).attr("d", pathGenerator);

            // 4. Update Markers Visibility & Position
            updateMarkers(newRotate);

            // 5. Update Target Cursor
            const cursor = d3.select("#target-cursor");
            const projectedPos = projection(currentPos);
            
            // Check if point is visible (not on back of globe)
            const centerPos = projection.invert(CONFIG.center);
            const dist = d3.geoDistance(currentPos, centerPos);
            
            if (dist < 1.57) { // < 90 degrees approx
                cursor.style("display", "block")
                      .attr("transform", `translate(${projectedPos[0]}, ${projectedPos[1]})`);
            } else {
                cursor.style("display", "none");
            }

            // 6. Update UI
            updateUI(currentPos, currentIndex);

            // 7. Check for Waypoint Arrival
            if (currentPos.waypointIndex !== undefined) {
                // We hit a waypoint node
                const wpIndex = currentPos.waypointIndex;
                // Only pause if we haven't processed this index recently (simple debounce logic implied by linear progress)
                // To avoid multiple pauses, we remove the property or check a flag. 
                // Since we regenerate points, let's just use the fact that we are AT the index.
                // But float math is tricky. 
                
                // Better approach: Check distance to actual waypoints
                const nearestWP = CONFIG.waypoints.find(wp => d3.geoDistance(wp.coords, currentPos) < 0.005);
                if (nearestWP && !nearestWP.visited) {
                    nearestWP.visited = true;
                    pauseTimer = CONFIG.pauseOnWaypoint;
                    document.getElementById('ui-status-msg').textContent = `ARRIVED AT: ${nearestWP.en}`;
                    
                    // Trigger marker pulse
                    const markerSel = d3.select(`#marker-${CONFIG.waypoints.indexOf(nearestWP)}`);
                    markerSel.select(".pulse-ring")
                        .transition().duration(1000)
                        .attr("r", 20).style("opacity", 0)
                        .on("end", function() { d3.select(this).attr("r", 8).style("opacity", 1); });
                }
            }
        }

        function updateMarkers(rotation) {
            const centerPos = projection.invert(CONFIG.center);

            CONFIG.waypoints.forEach((wp, i) => {
                const dist = d3.geoDistance(wp.coords, centerPos);
                const isVisible = dist < 1.57; // 90 degrees
                const el = d3.select(`#marker-${i}`);
                
                if (isVisible) {
                    const pos = projection(wp.coords);
                    el.style("display", "block")
                      .attr("transform", `translate(${pos[0]}, ${pos[1]})`);
                    
                    // Show label if close to center or active
                    if (dist < 0.5 || wp.visited) {
                        el.select(".marker-label").style("opacity", 1);
                    } else {
                        el.select(".marker-label").style("opacity", 0.5);
                    }
                } else {
                    el.style("display", "none");
                }
            });
        }

        function updateUI(pos, idx) {
            // Coordinates
            const lat = pos[1];
            const lon = pos[0];
            const latStr = Math.abs(lat).toFixed(2) + "° " + (lat >= 0 ? "N" : "S");
            const lonStr = Math.abs(lon).toFixed(2) + "° " + (lon >= 0 ? "E" : "W");
            document.getElementById('ui-coords').textContent = `${latStr}, ${lonStr}`;

            // Progress
            const pct = Math.floor(currentProgress * 100);
            document.getElementById('ui-progress').textContent = pct + "%";
            document.getElementById('ui-progress-bar').setAttribute("width", pct * 2);

            // Location Name (Find nearest or generic)
            // Already handled by waypoint arrival, but for "In transit":
            if (pauseTimer === 0) {
                // Find previous waypoint
                let prevName = CONFIG.waypoints[0].name;
                for(let i=0; i<CONFIG.waypoints.length; i++) {
                    if (CONFIG.waypoints[i].visited) prevName = CONFIG.waypoints[i].name;
                }
                document.getElementById('ui-location-name').textContent = `EN ROUTE: ${prevName} -> ...`;
                document.getElementById('ui-status-msg').textContent = "TRACKING SATELLITE FEED...";
            } else {
                 // Paused at location
                 const currentWP = CONFIG.waypoints.find(wp => wp.visited && d3.geoDistance(wp.coords, pos) < 0.01);
                 if(currentWP) document.getElementById('ui-location-name').textContent = currentWP.name;
            }
        }

        function updateGlobeRotation() {
            // Helper to keep rotation smooth even when paused
            // (Optional: add subtle idle rotation)
        }

        // --- Interaction ---
        function setupInteraction() {
            let drag = false;
            let lastX, lastY;
            const svg = document.getElementById('scene');

            svg.addEventListener('pointerdown', (e) => {
                drag = true;
                lastX = e.clientX;
                lastY = e.clientY;
                isPaused = true; // Pause animation on drag
                svg.setPointerCapture(e.pointerId);
                document.getElementById('ui-status-msg').textContent = "MANUAL OVERRIDE ENGAGED";
            });

            svg.addEventListener('pointermove', (e) => {
                if (!drag) return;
                const dx = e.clientX - lastX;
                const dy = e.clientY - lastY;
                
                const rotate = projection.rotate();
                const k = 0.25; // sensitivity
                projection.rotate([rotate[0] + dx * k, rotate[1] - dy * k]);
                
                lastX = e.clientX;
                lastY = e.clientY;
                
                // Manual update of static elements only (path doesn't grow)
                d3.select("#land").attr("d", pathGenerator);
                d3.select("#graticule").attr("d", pathGenerator);
                d3.select("#route-bg").attr("d", pathGenerator);
                
                // Re-calculate active route visual for new angle
                const currentIndex = Math.floor(currentProgress * (routePoints.length - 1));
                const activeRoute = { type: "LineString", coordinates: routePoints.slice(0, currentIndex + 1) };
                d3.select("#route-active").datum(activeRoute).attr("d", pathGenerator);
                
                updateMarkers();
                
                // Hide cursor during manual drag usually, or update it
                const currentPos = routePoints[currentIndex];
                const projPos = projection(currentPos);
                const centerPos = projection.invert(CONFIG.center);
                if (d3.geoDistance(currentPos, centerPos) < 1.57) {
                    d3.select("#target-cursor")
                        .style("display", "block")
                        .attr("transform", `translate(${projPos[0]}, ${projPos[1]})`);
                } else {
                    d3.select("#target-cursor").style("display", "none");
                }
            });

            svg.addEventListener('pointerup', (e) => {
                drag = false;
                isPaused = false; // Resume
                svg.releasePointerCapture(e.pointerId);
                document.getElementById('ui-status-msg').textContent = "RESUMING AUTO-NAVIGATION...";
            });
        }

        // Run
        init();

    </script>
</body>
</html>1a:T379e,<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3D世界经济体排名可视化</title>
    <style>
        :root {
            --bg-color: #05080f;
            --panel-bg: rgba(13, 25, 48, 0.8);
            --accent-color: #00f2ff;
            --text-main: #e2e8f0;
            --text-dim: #64748b;
        }

        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            background-color: var(--bg-color);
            color: var(--text-main);
            font-family: "PingFang SC", "Microsoft YaHei", "Inter", sans-serif;
            overflow: hidden;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        #app-container {
            width: 1200px;
            height: 700px;
            position: relative;
            background: radial-gradient(circle at center, #0f172a 0%, #05080f 100%);
            border: 1px solid rgba(0, 242, 255, 0.1);
            box-shadow: 0 0 50px rgba(0, 0, 0, 0.5);
            overflow: hidden;
        }

        /* 科技感背景装饰 */
        .grid-bg {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-image: 
                linear-gradient(rgba(0, 242, 255, 0.05) 1px, transparent 1px),
                linear-gradient(90deg, rgba(0, 242, 255, 0.05) 1px, transparent 1px);
            background-size: 40px 40px;
            pointer-events: none;
        }

        .scan-line {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 2px;
            background: linear-gradient(90deg, transparent, var(--accent-color), transparent);
            opacity: 0.2;
            animation: scan 8s linear infinite;
        }

        @keyframes scan {
            0% { top: 0; }
            100% { top: 100%; }
        }

        /* 标题样式 */
        .header {
            position: absolute;
            top: 40px;
            left: 50px;
            z-index: 10;
        }

        .header h1 {
            font-size: 36px;
            font-weight: 800;
            margin: 0;
            letter-spacing: 2px;
            text-transform: uppercase;
            background: linear-gradient(to right, #fff, var(--accent-color));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            filter: drop-shadow(0 0 10px rgba(0, 242, 255, 0.3));
        }

        .header p {
            font-size: 14px;
            color: var(--text-dim);
            margin: 10px 0 0 0;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        /* 数据看板 */
        .stats-panel {
            position: absolute;
            top: 150px;
            right: 50px;
            width: 320px;
            background: var(--panel-bg);
            border: 1px solid rgba(0, 242, 255, 0.2);
            padding: 20px;
            backdrop-filter: blur(10px);
            border-radius: 4px;
            z-index: 10;
        }

        .stat-item {
            display: flex;
            align-items: center;
            margin-bottom: 15px;
            transition: all 0.3s;
        }

        .stat-rank {
            width: 24px;
            height: 24px;
            background: var(--accent-color);
            color: #000;
            font-weight: bold;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 12px;
            margin-right: 12px;
            border-radius: 2px;
        }

        .stat-info {
            flex: 1;
        }

        .stat-name {
            font-size: 16px;
            font-weight: 600;
            display: flex;
            justify-content: space-between;
        }

        .stat-bar-container {
            height: 4px;
            background: rgba(255, 255, 255, 0.1);
            margin-top: 6px;
            position: relative;
        }

        .stat-bar-fill {
            height: 100%;
            background: var(--accent-color);
            transition: width 1s ease-out;
        }

        /* 3D SVG 容器 */
        #viz-container {
            width: 100%;
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        svg {
            overflow: visible;
        }

        .tooltip {
            position: absolute;
            padding: 10px;
            background: rgba(0, 0, 0, 0.8);
            border: 1px solid var(--accent-color);
            color: white;
            pointer-events: none;
            font-size: 12px;
            border-radius: 4px;
            display: none;
            z-index: 100;
        }
    </style>
</head>
<body>

<div id="app-container">
    <div class="grid-bg"></div>
    <div class="scan-line"></div>
    
    <div class="header">
        <h1>全球经济体 3D 份额图谱</h1>
        <p>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><line x1="2" y1="12" x2="22" y2="12"></line><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></svg>
            数据更新至 2024 年度 (单位: 万亿美元)
        </p>
    </div>

    <div class="stats-panel" id="stats-panel">
        <!-- JS 动态填充 -->
    </div>

    <div id="viz-container">
        <svg id="main-svg" viewBox="0 0 1200 700" width="1200" height="700">
            <defs>
                <filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
                    <feGaussianBlur stdDeviation="5" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over" />
                </filter>
                <linearGradient id="grad-side" x1="0%" y1="0%" x2="0%" y2="100%">
                    <stop offset="0%" style="stop-color:rgba(255,255,255,0.2)" />
                    <stop offset="100%" style="stop-color:rgba(0,0,0,0.5)" />
                </linearGradient>
            </defs>
            <g id="pie-group" transform="translate(480, 400)"></g>
        </svg>
    </div>

    <div class="tooltip" id="tooltip"></div>
</div>

<script>
    const DATA = [
        { name: "美国", label: "USA", value: 27.36, color: "#3b82f6" },
        { name: "中国", label: "CHN", value: 17.66, color: "#ef4444" },
        { name: "德国", label: "DEU", value: 4.46, color: "#f59e0b" },
        { name: "日本", label: "JPN", value: 4.21, color: "#10b981" },
        { name: "印度", label: "IND", value: 3.57, color: "#8b5cf6" },
        { name: "英国", label: "GBR", value: 3.34, color: "#06b6d4" },
        { name: "法国", label: "FRA", value: 3.03, color: "#6366f1" },
        { name: "其他", label: "Others", value: 41.5, color: "#475569" }
    ];

    const totalValue = DATA.reduce((sum, item) => sum + item.value, 0);
    const pieGroup = document.getElementById('pie-group');
    const statsPanel = document.getElementById('stats-panel');
    const tooltip = document.getElementById('tooltip');

    let rotation = 0;
    const tilt = 0.5; // Y轴缩放模拟倾斜
    const radius = 280;
    const thickness = 50;

    // 初始化侧边栏
    function initStats() {
        statsPanel.innerHTML = DATA.slice(0, 7).map((item, i) => `
            <div class="stat-item">
                <div class="stat-rank" style="background:${item.color}">${i+1}</div>
                <div class="stat-info">
                    <div class="stat-name">
                        <span>${item.name}</span>
                        <span style="color:${item.color}">${item.value}T</span>
                    </div>
                    <div class="stat-bar-container">
                        <div class="stat-bar-fill" style="width: ${(item.value/DATA[0].value)*100}%; background:${item.color}"></div>
                    </div>
                </div>
            </div>
        `).join('') + `
            <div style="margin-top:20px; padding-top:15px; border-top:1px solid rgba(255,255,255,0.1); font-size:12px; color:#64748b; line-height:1.6">
                全球GDP总量约为 ${totalValue.toFixed(2)} 万亿美元。美国与中国依然占据全球经济的“第一梯队”。
            </div>
        `;
    }

    // 计算弧上的点
    function getPoint(angle, r, yFactor = 1) {
        const rad = (angle - 90) * (Math.PI / 180);
        return {
            x: Math.cos(rad) * r,
            y: Math.sin(rad) * r * yFactor
        };
    }

    // 生成SVG Path
    function createSlice(startAngle, endAngle, color, isHovered) {
        const r = isHovered ? radius * 1.05 : radius;
        const h = thickness;
        const p1 = getPoint(startAngle, r, tilt);
        const p2 = getPoint(endAngle, r, tilt);
        const p3 = getPoint(endAngle, r, tilt); p3.y += h;
        const p4 = getPoint(startAngle, r, tilt); p4.y += h;

        const largeArc = (endAngle - startAngle) > 180 ? 1 : 0;

        // 侧面路径 (厚度)
        const sidePath = `
            M ${p1.x} ${p1.y}
            A ${r} ${r * tilt} 0 ${largeArc} 1 ${p2.x} ${p2.y}
            L ${p3.x} ${p3.y}
            A ${r} ${r * tilt} 0 ${largeArc} 0 ${p4.x} ${p4.y}
            Z
        `;

        // 顶部路径
        const topPath = `
            M 0 0
            L ${p1.x} ${p1.y}
            A ${r} ${r * tilt} 0 ${largeArc} 1 ${p2.x} ${p2.y}
            Z
        `;

        // 内侧切面路径 (如果是扇形，需要补齐两个侧面)
        const innerSide1 = `M 0 0 L 0 ${h} L ${p1.x} ${p1.y + h} L ${p1.x} ${p1.y} Z`;
        const innerSide2 = `M 0 0 L 0 ${h} L ${p2.x} ${p2.y + h} L ${p2.x} ${p2.y} Z`;

        return { sidePath, topPath, innerSide1, innerSide2 };
    }

    function draw() {
        pieGroup.innerHTML = '';
        let currentAngle = rotation;

        // 为了正确的遮挡关系，我们需要计算每个切片的中心点角度，并根据角度排序
        const slices = DATA.map(item => {
            const angleWidth = (item.value / totalValue) * 360;
            const slice = {
                ...item,
                start: currentAngle,
                end: currentAngle + angleWidth,
                mid: currentAngle + angleWidth / 2
            };
            currentAngle += angleWidth;
            return slice;
        });

        // 简单的深度排序：位于下方的（y坐标大）先画，位于上方的后画
        // 在 3D 饼图中，通常角度在 0-180 之间的部分是“前面”
        const sortedSlices = [...slices].sort((a, b) => {
            const ay = Math.sin((a.mid - 90) * Math.PI / 180);
            const by = Math.sin((b.mid - 90) * Math.PI / 180);
            return ay - by;
        });

        sortedSlices.forEach(item => {
            const { sidePath, topPath, innerSide1, innerSide2 } = createSlice(item.start, item.end, item.color, false);
            
            const g = document.createElementNS("http://www.w3.org/2000/svg", "g");
            g.style.cursor = "pointer";
            
            // 侧边颜色稍暗
            const darkColor = shadeColor(item.color, -30);
            
            const side = document.createElementNS("http://www.w3.org/2000/svg", "path");
            side.setAttribute("d", sidePath);
            side.setAttribute("fill", darkColor);
            
            const top = document.createElementNS("http://www.w3.org/2000/svg", "path");
            top.setAttribute("d", topPath);
            top.setAttribute("fill", item.color);
            top.setAttribute("stroke", "rgba(255,255,255,0.2)");
            top.setAttribute("stroke-width", "0.5");

            // 标注
            const midPoint = getPoint(item.mid, radius + 40, tilt);
            const label = document.createElementNS("http://www.w3.org/2000/svg", "text");
            label.setAttribute("x", midPoint.x);
            label.setAttribute("y", midPoint.y);
            label.setAttribute("fill", "#fff");
            label.setAttribute("font-size", "12");
            label.setAttribute("text-anchor", "middle");
            label.textContent = item.label;

            g.appendChild(side);
            g.appendChild(top);
            if (item.value > 5) g.appendChild(label); // 只给大块显示文字
            
            g.onmouseenter = (e) => {
                top.setAttribute("fill", shadeColor(item.color, 20));
                tooltip.style.display = 'block';
                tooltip.innerHTML = `<strong>${item.name}</strong><br/>GDP: ${item.value}万亿<br/>占比: ${((item.value/totalValue)*100).toFixed(1)}%`;
            };
            g.onmousemove = (e) => {
                tooltip.style.left = (e.clientX + 15) + 'px';
                tooltip.style.top = (e.clientY + 15) + 'px';
            };
            g.onmouseleave = () => {
                top.setAttribute("fill", item.color);
                tooltip.style.display = 'none';
            };

            pieGroup.appendChild(g);
        });
    }

    function shadeColor(color, percent) {
        let R = parseInt(color.substring(1, 3), 16);
        let G = parseInt(color.substring(3, 5), 16);
        let B = parseInt(color.substring(5, 7), 16);
        R = parseInt(R * (100 + percent) / 100);
        G = parseInt(G * (100 + percent) / 100);
        B = parseInt(B * (100 + percent) / 100);
        R = (R < 255) ? R : 255;
        G = (G < 255) ? G : 255;
        B = (B < 255) ? B : 255;
        const RR = ((R.toString(16).length == 1) ? "0" + R.toString(16) : R.toString(16));
        const GG = ((G.toString(16).length == 1) ? "0" + G.toString(16) : G.toString(16));
        const BB = ((B.toString(16).length == 1) ? "0" + B.toString(16) : B.toString(16));
        return "#" + RR + GG + BB;
    }

    function animate() {
        rotation += 0.2;
        draw();
        requestAnimationFrame(animate);
    }

    initStats();
    animate();
</script>
</body>
</html></html>1b:T372f,<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>咖啡因分子 3D 可视化 - 科学教育</title>
    <style>
        :root {
            --bg-color: #0a192f;
            --panel-bg: rgba(13, 25, 48, 0.8);
            --accent-blue: #2563eb;
            --text-main: #e2e8f0;
        }
        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
            background-color: var(--bg-color);
            font-family: 'JetBrains Mono', 'PingFang SC', sans-serif;
            color: var(--text-main);
        }
        #canvas-container {
            width: 100%;
            height: 100%;
            background: radial-gradient(circle at center, #112240 0%, #0a192f 100%);
        }
        .hud {
            position: absolute;
            pointer-events: none;
            z-index: 10;
        }
        .top-left {
            top: 30px;
            left: 30px;
            border-left: 3px solid var(--accent-blue);
            padding-left: 15px;
        }
        .top-left h1 {
            margin: 0;
            font-size: 24px;
            letter-spacing: 2px;
            font-weight: 700;
        }
        .top-left p {
            margin: 5px 0 0 0;
            font-size: 14px;
            color: #64748b;
            text-transform: uppercase;
        }
        .bottom-right {
            bottom: 30px;
            right: 30px;
            text-align: right;
            background: var(--panel-bg);
            padding: 15px 25px;
            border-radius: 4px;
            backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.1);
        }
        .info-row {
            display: flex;
            justify-content: flex-end;
            gap: 20px;
            margin-bottom: 5px;
        }
        .info-item .label {
            font-size: 10px;
            color: #94a3b8;
            display: block;
        }
        .info-item .value {
            font-size: 18px;
            font-weight: bold;
            color: #38bdf8;
        }
        .label-element {
            font-size: 12px;
            font-weight: bold;
            color: white;
            text-shadow: 0 0 4px rgba(0,0,0,0.8);
            pointer-events: none;
            user-select: none;
        }
        #loading {
            position: fixed;
            top: 0; left: 0; width: 100%; height: 100%;
            background: var(--bg-color);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 100;
            transition: opacity 0.5s ease;
        }
        .spinner {
            width: 40px;
            height: 40px;
            border: 3px solid rgba(56, 189, 248, 0.2);
            border-top-color: #38bdf8;
            border-radius: 50%;
            animation: spin 1s linear infinite;
            margin-bottom: 15px;
        }
        @keyframes spin { to { transform: rotate(360deg); } }

        .control-hint {
            position: absolute;
            bottom: 30px;
            left: 30px;
            font-size: 12px;
            color: #475569;
        }
    </style>
    <script type="importmap">
    {
      "imports": {
        "three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
        "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
      }
    }
    </script>
</head>
<body>

<div id="loading">
    <div class="spinner"></div>
    <div>初始化分子动力学渲染...</div>
</div>

<div class="hud top-left">
    <h1>咖啡因分子可视化</h1>
    <p>Caffeine Molecule 3D Model</p>
</div>

<div class="hud bottom-right">
    <div class="info-row">
        <div class="info-item">
            <span class="label">分子式</span>
            <span class="value">C₈H₁₀N₄O₂</span>
        </div>
        <div class="info-item">
            <span class="label">摩尔质量</span>
            <span class="value">194.19 g/mol</span>
        </div>
    </div>
    <div class="info-row" style="margin-top: 10px; border-top: 1px solid rgba(255,255,255,0.1); padding-top: 5px;">
        <div class="info-item">
            <span class="label">分类</span>
            <span class="value" style="font-size: 14px;">黄嘌呤生物碱 (Alkaloid)</span>
        </div>
    </div>
</div>

<div class="control-hint">
    [ 鼠标左键 ] 旋转 &nbsp;&nbsp; [ 滚轮 ] 缩放 &nbsp;&nbsp; [ 鼠标右键 ] 平移
</div>

<div id="canvas-container"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script type="module">
    import * as THREE from 'three';
    import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
    import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';

    // --- 核心配置 ---
    const ATOM_DATA = {
        // 基于咖啡因分子标准坐标 (单位: 埃)
        // C: 碳, N: 氮, O: 氧, H: 氢
        atoms: [
            { type: 'N', pos: [-1.20, 1.21, 0.00], label: 'N' },
            { type: 'C', pos: [0.00, 0.53, 0.00], label: 'C' },
            { type: 'N', pos: [1.21, 1.21, 0.00], label: 'N' },
            { type: 'C', pos: [1.16, 2.58, 0.00], label: 'C' },
            { type: 'C', pos: [-0.06, 3.25, 0.00], label: 'C' },
            { type: 'C', pos: [-1.22, 2.58, 0.00], label: 'C' },
            { type: 'O', pos: [2.25, 3.14, 0.00], label: 'O' },
            { type: 'O', pos: [-2.33, 3.14, 0.00], label: 'O' },
            { type: 'C', pos: [0.00, -0.84, 0.00], label: 'C' },
            { type: 'N', pos: [1.21, -1.45, 0.00], label: 'N' },
            { type: 'C', pos: [1.96, -0.37, 0.00], label: 'C' },
            { type: 'N', pos: [2.35, 0.79, 0.00], label: 'N' },
            // 甲基和氢原子
            { type: 'C', pos: [-2.52, 0.53, 0.00], label: 'C' }, // N1 上的甲基
            { type: 'C', pos: [3.71, 1.21, 0.00], label: 'C' }, // N7 上的甲基
            { type: 'C', pos: [1.52, -2.87, 0.00], label: 'C' }, // N3 上的甲基
            { type: 'H', pos: [3.01, -0.63, 0.00], label: 'H' }, // C8 上的氢
            // 简化：这里只放主要的氢，避免视觉过度拥挤
            { type: 'H', pos: [-3.05, 0.88, 0.87], label: 'H' },
            { type: 'H', pos: [-3.05, 0.88, -0.87], label: 'H' },
            { type: 'H', pos: [-2.45, -0.55, 0.00], label: 'H' },
            { type: 'H', pos: [4.21, 0.88, 0.87], label: 'H' },
            { type: 'H', pos: [4.21, 0.88, -0.87], label: 'H' },
            { type: 'H', pos: [3.75, 2.30, 0.00], label: 'H' },
            { type: 'H', pos: [2.58, -3.05, 0.00], label: 'H' },
            { type: 'H', pos: [1.05, -3.35, 0.87], label: 'H' }
        ],
        bonds: [
            [0,1], [1,2], [2,3], [3,4], [4,5], [5,0], // 六元环
            [3,6], [5,7], // 羰基氧
            [1,8], [8,9], [9,10], [10,11], [11,2], // 五元环部分
            [0,12], [11,13], [9,14], // 甲基连接
            [10,15], // C-H
            [12,16], [12,17], [12,18], // 甲基氢
            [13,19], [13,20], [13,21],
            [14,22], [14,23]
        ]
    };

    const ATOM_STYLE = {
        'C': { color: 0x333333, size: 0.4, label: 'C' },
        'N': { color: 0x2563eb, size: 0.4, label: 'N' },
        'O': { color: 0xdc2626, size: 0.45, label: 'O' },
        'H': { color: 0xffffff, size: 0.2, label: 'H' }
    };

    // --- 初始化场景 ---
    let scene, camera, renderer, labelRenderer, controls;
    let moleculeGroup;
    const atomMeshes = [];

    function init() {
        scene = new THREE.Scene();
        scene.fog = new THREE.FogExp2(0x0a192f, 0.05);

        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(0, 5, 15);

        renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMap.enabled = true;
        document.getElementById('canvas-container').appendChild(renderer.domElement);

        labelRenderer = new CSS2DRenderer();
        labelRenderer.setSize(window.innerWidth, window.innerHeight);
        labelRenderer.domElement.style.position = 'absolute';
        labelRenderer.domElement.style.top = '0px';
        labelRenderer.domElement.style.pointerEvents = 'none';
        document.getElementById('canvas-container').appendChild(labelRenderer.domElement);

        controls = new OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.dampingFactor = 0.05;

        // --- 光照 ---
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
        scene.add(ambientLight);

        const mainLight = new THREE.DirectionalLight(0xffffff, 1.2);
        mainLight.position.set(5, 10, 7);
        mainLight.castShadow = true;
        scene.add(mainLight);

        const rimLight = new THREE.PointLight(0x38bdf8, 1.5);
        rimLight.position.set(-10, -5, -10);
        scene.add(rimLight);

        // --- 网格背景 ---
        const grid = new THREE.GridHelper(100, 50, 0x1e293b, 0x1e293b);
        grid.position.y = -5;
        grid.material.opacity = 0.2;
        grid.material.transparent = true;
        scene.add(grid);

        buildMolecule();
        animateIntro();
        
        window.addEventListener('resize', onWindowResize);
        
        setTimeout(() => {
            document.getElementById('loading').style.opacity = '0';
            setTimeout(() => document.getElementById('loading').remove(), 500);
        }, 1000);
    }

    function buildMolecule() {
        moleculeGroup = new THREE.Group();
        scene.add(moleculeGroup);

        // 创建原子
        ATOM_DATA.atoms.forEach((data, index) => {
            const style = ATOM_STYLE[data.type];
            const geometry = new THREE.SphereGeometry(style.size, 32, 32);
            const material = new THREE.MeshPhysicalMaterial({
                color: style.color,
                roughness: 0.2,
                metalness: 0.1,
                emissive: style.color,
                emissiveIntensity: 0.05
            });

            const mesh = new THREE.Mesh(geometry, material);
            mesh.position.set(data.pos[0], data.pos[1], data.pos[2]);
            mesh.castShadow = true;
            mesh.receiveShadow = true;
            
            // 初始飞入位置
            const randomPos = new THREE.Vector3(
                (Math.random() - 0.5) * 50,
                (Math.random() - 0.5) * 50,
                (Math.random() - 0.5) * 50
            );
            mesh.userData.targetPos = mesh.position.clone();
            mesh.position.copy(randomPos);

            // 标签
            const labelDiv = document.createElement('div');
            labelDiv.className = 'label-element';
            labelDiv.textContent = data.label;
            labelDiv.style.opacity = data.type === 'H' ? '0.4' : '1';
            const label = new CSS2DObject(labelDiv);
            label.position.set(0, style.size + 0.2, 0);
            mesh.add(label);

            moleculeGroup.add(mesh);
            atomMeshes.push(mesh);
        });

        // 创建化学键
        ATOM_DATA.bonds.forEach(bond => {
            const start = ATOM_DATA.atoms[bond[0]].pos;
            const end = ATOM_DATA.atoms[bond[1]].pos;
            
            const startVec = new THREE.Vector3(...start);
            const endVec = new THREE.Vector3(...end);
            const distance = startVec.distanceTo(endVec);
            
            const geometry = new THREE.CylinderGeometry(0.1, 0.1, distance, 12);
            const material = new THREE.MeshStandardMaterial({ 
                color: 0x94a3b8, 
                metalness: 0.5, 
                roughness: 0.3,
                transparent: true,
                opacity: 0
            });
            
            const mesh = new THREE.Mesh(geometry, material);
            
            // 设置位置和旋转
            const midpoint = new THREE.Vector3().addVectors(startVec, endVec).multiplyScalar(0.5);
            mesh.position.copy(midpoint);
            mesh.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), endVec.clone().sub(startVec).normalize());
            
            mesh.userData.isBond = true;
            moleculeGroup.add(mesh);
        });

        // 居中分子
        const box = new THREE.Box3().setFromObject(moleculeGroup);
        const center = box.getCenter(new THREE.Vector3());
        moleculeGroup.position.sub(center);
    }

    function animateIntro() {
        atomMeshes.forEach((mesh, i) => {
            gsap.to(mesh.position, {
                x: mesh.userData.targetPos.x,
                y: mesh.userData.targetPos.y,
                z: mesh.userData.targetPos.z,
                duration: 2,
                delay: i * 0.02,
                ease: "expo.out"
            });
        });

        // 化学键渐显
        moleculeGroup.children.forEach(child => {
            if (child.userData.isBond) {
                gsap.to(child.material, {
                    opacity: 0.8,
                    duration: 1,
                    delay: 1.5
                });
            }
        });
    }

    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
        labelRenderer.setSize(window.innerWidth, window.innerHeight);
    }

    function animate() {
        requestAnimationFrame(animate);
        
        // 缓慢自转
        if (moleculeGroup) {
            moleculeGroup.rotation.y += 0.005;
        }

        controls.update();
        renderer.render(scene, camera);
        labelRenderer.render(scene, camera);
    }

    init();
    animate();

</script>
</body>
</html>1c:T4462,<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>SVG 动态绘制</title>
  <style>
    * { box-sizing: border-box; }
    html, body {
      margin: 0;
      width: 100%;
      height: 100%;
      overflow: hidden;
      background:
        radial-gradient(circle at top, rgba(251,146,60,0.12), transparent 34%),
        linear-gradient(180deg, #fff8f1 0%, #fffaf5 100%);
    }
    body {
      position: relative;
      display: grid;
      place-items: center;
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    }
    body::before {
      content: "";
      position: absolute;
      inset: 0;
      background-image: radial-gradient(rgba(251,146,60,0.16) 1px, transparent 1px);
      background-size: 24px 24px;
      pointer-events: none;
    }
    .stage {
      position: relative;
      z-index: 1;
      width: min(94vw, calc(90vh * 1.6));
      height: min(90vh, calc(94vw / 1.6));
      display: flex;
      align-items: center;
      justify-content: center;
      overflow: hidden;
    }
    .artboard {
      width: 100%;
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .artboard svg {
      width: 100%;
      height: 100%;
      max-height: 100%;
      overflow: visible;
    }
    .cursor {
      position: absolute;
      top: 0;
      left: 0;
      opacity: 0;
      pointer-events: none;
      will-change: transform;
    }
    .cursor-ring {
      position: absolute;
      width: 24px;
      height: 24px;
      margin-left: -12px;
      margin-top: -12px;
      border-radius: 999px;
      background: rgba(249,115,22,0.30);
    }
    .cursor-dot {
      position: absolute;
      width: 8px;
      height: 8px;
      margin-left: -4px;
      margin-top: -4px;
      border-radius: 999px;
      background: rgba(249,115,22,1);
    }
    .animated svg path,
    .animated svg rect,
    .animated svg circle,
    .animated svg line,
    .animated svg polyline,
    .animated svg polygon {
      stroke: var(--auto-stroke-color) !important;
      stroke-width: 2px !important;
      stroke-dasharray: var(--path-length);
      stroke-dashoffset: var(--path-length);
      
      fill-opacity: 0;
      animation:
        draw var(--draw-duration) linear var(--draw-delay) forwards,
        fillIn 0.8s ease-out var(--fill-delay) forwards;
      
    }
    @keyframes draw { to { stroke-dashoffset: 0; } }
    @keyframes fillIn { from { fill-opacity: 0; } to { fill-opacity: 1; } }
  </style>
</head>
<body>
  <div class="stage" id="stage">
    <div class="artboard animated" id="artboard">
      <svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
<!-- SVG created with Arrow, by QuiverAI (https://quiver.ai) -->
  <path d="m179.8 23.14c-2.64-5.06-8-6.17-11.14-5.06-4.54 1.64-6.88 5.78-8.02 8.33-1.01-2.14-2.72-3.25-4.64-3.03-3.76 0.44-3.91 6.58-2.76 12.43-4.32 0.68-5.95 5.41-6.42 7.92-0.27 1.39 0.27 2.43 0.73 3.05-3.6 6.08-8.55 9.81-13.48 11.98-3.11-9.63-9.21-18.5-15.21-21.69 1.32-2.71 1.1-11.19-6.73-15.28-5.86-7.55-14.99-14.88-28.03-15.29-19.33-0.66-37 13.43-37.28 41.01-5 0.48-7.94 3.99-7.93 8.82 0 5.62 4.58 7.93 8.39 7.79 4.84-0.18 7.64-4.03 7.36-8.31-0.25-3.89-2.91-5.9-4.34-6.82 1.92-3.35 4.98-6.83 10.55-8.6-1.63 5.08-0.5 10.01 4.17 15.51-2.05 5.03-2.2 12.02-1.08 18.87-13.68 4.25-25.82 17.34-32.94 34.01-3.37-0.94-5.29 2.25-6.28 5.14-1.03 3.19-0.79 5.15 0.37 6.54-5.07 5.71-7.88 14.59-6.24 19.79 1.64 5.19 6.01 6.96 10.12 6.68 3.91-0.27 6.26-2.92 8.7-7.81 0.98 2.82 2.46 4.08 4.61 3.2 3.66-1.54 3.1-6.23 2.47-10.22 3.37-0.4 5.01-3.05 6-6.24 0.87-2.89 0.36-4.52-0.48-5.66 3.55-4.51 5.9-6.95 9.56-9.09-0.67 5.51-0.1 9.77 0.45 17.55-1.36 6.31-4.46 12.33-5.16 14.56-1.89 5.57 0.63 9.24 5.69 10.71 2.95 0.88 5.86 1.69 9.14 2.45 1.49 8.34 3.83 16.83 9.04 19.98v7.35c-7.27 0.95-10.64 4-11.52 9.78-0.13 0.89 0.15 1.32 1.14 1.32h27.26c0.74 0 1.02-0.43 1.02-1.18v-16.99c4.28-2.92 5.92-10.7 9.01-17.28 2.95-1.05 7.03-2 9.37-1.72 6.36 0.74 15.48 11.15 24.07 12.75l9.85 13.37c0.53 0.7 1.33 0.7 2.15 0.07l23.05-15.82c0.92-0.63 1.11-1.45-0.07-2.71-3.8-4.09-9.13-3.65-15.22-0.07l-3.66-4.95c2.45-5.95-0.07-12.94-2.28-17.68 2.99-2.79 6.08-5.44 6.84-7.21 1.64-3.85 0.65-6.25-2.07-9.04-3.14-3.29-7.01-8.42-7.36-11.21 0.23-8.97-1.69-17.01-5.49-25.12 9.26-7.65 17.09-18.8 21.62-32.88 4.22-0.23 6.29-5.03 6.72-7.52 0.4-2.2-0.3-3.34-1.28-4.16 7.44-6.23 10.66-15.44 7.66-22.32z" fill="#491213"/>
  <path d="m160.8 28.21c0.85-5.07 4.84-9.79 9.38-9.79 5.14 0 8.44 4.51 8.44 9.21 0 6.49-3.53 12.76-8.44 17.09-5.57-3.54-12.93-7.46-16.16-9.16-0.76-4.64-0.97-10.58 2.12-10.93 2.15-0.25 3.79 1.98 3.92 3.79 0.14 1.09 0.54 1 0.74-0.21z" fill="#E5302F"/>
  <path d="m150.2 37.83c1.92-0.69 4.4 0.98 7.78 2.78 4.09 2.18 12.12 6.03 13.36 7.52 1.77 2.3-1.31 6.9-3.08 7.58-2.08 0.85-5.39-1.45-9.99-3.9-4.34-2.3-9.48-5.03-10.24-6.42-1-1.94 0.4-6.83 2.17-7.56z" fill="#FEFFFE"/>
  <path d="m134.4 59.12c4.9-2.58 10.36-7.06 13.39-11.26 3.97 3.7 11.22 7.4 16.58 9.35-4.16 11.6-11.63 22.61-19.98 29.8-1.2-2.48-3.19-5.27-4.69-7.15-1.16-1.44-3.09-0.07-2.03 1.82 6 8.24 10 16.45 10.13 26.44-1.09 2.49-12.5 9.81-21.26 11.95-1.53-9.1-2.82-16.95-5.34-23.05 9.59-8.11 15.8-21.26 13.2-37.9z" fill="#E5302F"/>
  <path d="m48.03 47.16c-0.47-19.6 10.64-38.55 34.95-39 10.09-0.2 19.48 5.35 25.21 12.16-17.33-3.05-35.41 4.43-44.47 17.23 0.14-6.14 1.53-11.21 3.8-14.62 1.09-1.77-1.36-3.34-2.41-1.98-3.33 4.38-4.69 11.26-4.76 17.64-4.54 2.14-8.24 5.3-10.51 8.64-0.47-0.14-1.47-0.14-1.81-0.07z" fill="#E5302F"/>
  <path d="m47.09 49.62c-4.68 0-6.86 3.6-6.86 6.71 0 3.99 3.09 6.48 6.52 6.48 3.87 0 6.53-3.48 6.53-6.41 0-3.67-2.77-6.78-6.19-6.78z" fill="#FEFFFE"/>
  <path d="m116.8 28.39c-0.88-2.93-2.87-4.46-6.88-5.95-9.3-3.5-24.99-0.79-34.64 6.77-6.8 5.47-12.98 11.03-12.31 17.92 0.27 2.79 1.55 5.28 2.76 6.67 8.45-13.54 20.39-22.74 37.99-22.39 4.4 0.07 9.4 1.28 13.34 3.64 0.76-1.11 0.48-4.19-0.26-6.66z" fill="#FEFFFE"/>
  <path d="m115.2 36.91c-4.61-3.02-11.41-3.65-16.58-3.02-13.34 1.63-22.54 9.23-24.56 14.15 0 5.2 2.45 10.71 7.65 12.6l2.05-1.39c2.95-3.08 4.07-5.8 9.65-6.09 1.39 2.17 2.28 2.55 4.62 2.55 2.87 0 5.05-1.49 5.05-4.48 0-1.77-1.39-3.5-3.98-3.64-1.53-0.1-2.92 0.27-2.92 0.27l0.53-1.39c2.05-0.66 3.17-0.86 4.87-0.73 3.2 0.21 5.12 1.99 5.88 2.4 2.52-0.28 7 0.64 8.63 1.05 1.13-2.17 1.13-8.15-0.89-12.28z" fill="#FBCBAB"/>
  <path d="m118.7 38.92c8.39 5.29 15.06 16.89 14.78 28.86-0.47 16.18-12.68 34.13-33.32 34.13-21.43 0-34.32-16.17-34.32-33.24 0-6.01 1.7-12.66 6.31-18.6 0.78 5.34 3.8 10.04 7.09 11.54-1.6 0.85-3.78 0.91-4.77 0.13-1.17-0.41-1.37 1.12-0.61 2.52 3.7 5.88 10.9 7.65 20.62 4.72 2.45 1.63 4.09 2.05 6.5 1.84 4.15-0.35 6.85-2.9 8.2-6.28 8.76-0.73 14.4-6.35 15.4-14.46 0.19-1.63-1.2-2.22-2.25-1.37-1.43 1.22-2.68 2.08-4.66 2.01 1.13-3.7 1.24-7.37 1.03-11.8z" fill="#FEFFFE"/>
  <path d="m101.2 34.71c-1.57 0-1.5 2.28-1.09 3.33 0.34 0.88 1.09 0.81 1.76 0.67 2.62-0.53 4.39-0.74 7.26 0.14 1.77 0.51 2.92-0.88 2.24-2.42-0.88-1.77-6.17-1.91-10.17-1.72z" fill="#FEFFFE"/>
  <path d="m86.77 38.18c-2.88 1.25-6.08 2.95-7.85 4.8-1.24 1.29 0.15 3.84 1.85 2.96 1.77-0.94 3.95-3.03 6.97-4.8 1.99-1.15 0.94-3.71-0.97-2.96z" fill="#FEFFFE"/>
  <path d="m103.9 40.51c-2.45 0.96-2.89 3.13-2.69 3.91 0.34 1.25 1.73 1.19 2.55 0.2 1.46-1.78 3.45-2.05 5.47-1.03 1.7 0.89 2.88-1.15 2.09-2.62-1.08-1.84-4.85-1.53-7.42-0.46z" fill="#491213"/>
  <path d="m85.33 46.34c-2.55 1.02-2.99 3.1-2.79 3.88 0.34 1.25 1.73 1.18 2.55 0.2 1.46-1.78 2.92-1.91 4.84-1.3 1.83 0.64 2.59-1.32 1.54-2.51-1.26-1.42-3.98-1.08-6.14-0.27z" fill="#491213"/>
  <path d="m100.9 59.19c1.56 1.05 4.15 2.34 7.3 2.27 7.57-0.2 11.07-4.39 12.77-8.94-2.94 1.84-5.22 1.49-7.91 0.66-3.02-0.95-5.4-1.16-7.16-0.88-0.2 3.02-2.48 5.48-7.08 5.48-2.05 0-3.11-0.72-4.16-1.77-3.87-0.34-6.43 1.7-9.05 4.82-2.59 3.16-5.54 3.43-7.56 3.29 2.02 2.49 5.45 3.95 9.77 3.6 6.23-0.51 9.66-3.46 13.08-8.53z" fill="#491213"/>
  <path d="m29.36 111c1.77-0.66 4.25 1.24 7.35 2.88 4.15 2.17 9.9 4.79 11.46 6.18 2.12 1.89-0.27 7.68-2.55 8.7-1.85 0.82-6.43-2.27-10.58-4.27-3.9-1.84-8.12-3.98-9.01-5.47-1.05-1.85 1.09-7.26 3.33-8.02z" fill="#FEFFFE"/>
  <path d="m26.64 122.6c5.5 4.09 10.4 6.88 16.2 9.12 0.79 2.49 0.72 7.16-1.39 8.86-1.53 1.18-3.3-1.12-3.64-3.1-0.4-1.91-1.96-1.28-2.56 0.42-1.64 4.75-3.58 7.68-7.99 7.68-5.23 0-7.51-4.82-7.31-8.3 0.28-5.2 2.65-10.19 6.69-14.68z" fill="#E5302F"/>
  <path d="m32.74 109.2c8.32-16.74 18.94-28.18 31.19-31.79 4.4 14.91 16.9 26.51 35.29 26.51h2.89c1.93 6.2 3.17 13.26 3.51 20.81-12.01 2.18-29.47 0.92-43.14-3.59v-11.08c2.18-1.84 3.75-2.56 6.44-3.48 1.64-0.59 1.03-3.45-1.21-2.8-6.5 2-12.79 7.26-17.69 13.94l-17.28-8.52z" fill="#E5302F"/>
  <path d="m103.1 103.6c2.28-0.21 4.8-0.65 6.79-1.31 2.34 6.1 3.91 14.5 5.33 20.82-2.34 0.72-4.39 1.13-6.73 1.42-1.22-7.48-2.29-14.4-5.39-20.93z" fill="#FEFFFE"/>
  <path d="m112.8 101.2c2.28-1.11 3.67-1.93 5.3-3.21 2.63 5.91 4.65 15.57 5.39 23.13-2.15 0.95-4.14 1.61-5.88 2.12-1.28-7.92-2.33-15.14-4.81-22.04z" fill="#FEFFFE"/>
  <path d="m128.3 132.2c0.6 3.67 2.69 5.81 7.52 4.24 5.57-1.84 12.1-7.34 17.93-11.79l-4.12-5.91c-5.64 5.24-12.87 9.95-21.33 12.5v0.96z" fill="#E5302F"/>
  <path d="m62.55 132.6c11.9 3.79 26.34 4.91 44.1 3.96 0.47 5.78-0.54 8.43-5.64 9.21-10.35 1.64-28.3-0.66-42.2-6.09l3.74-7.08z" fill="#E5302F"/>
  <path d="m119.5 134.1 6.37-1.77c1.32 5.46 3.91 8.62 10.08 6.84 6.24-1.84 13.07-7.74 19.8-12.7 2.48 2.14 3.54 6.06 1.36 9.12-2.94 4.16-15.32 13.56-24.55 14.58-6.36 0.73-9.79-3.22-12.45-6.22-0.34-3.81-0.14-5.72-0.61-9.85z" fill="#FEFFFE"/>
  <path d="m57.93 142.7c11.9 4.67 24.78 7.32 39.59 6.66 6.53-0.34 11.79-1.73 11.39-12.37l7.9-1.77c1.46 6.96 1.46 14.68-5.54 19.81-6.53 3.78-28.56 3.85-50.46-3.17-4.39-1.49-5.27-4.69-2.88-9.16z" fill="#FEFFFE"/>
  <path d="m118.9 148.7c3.56 3.49 8.07 5.19 14.24 3.42 4.83-1.46 11.13-4.69 17.96-7.44 2.18 4.61 3.06 11.5 1.04 14.55-2.18 2.24-9.31 7.99-12.19 8.54-5.83-0.76-13.83-10.75-22.29-12.66 0.41-0.95 1.54-3.5 1.24-6.41z" fill="#E5302F"/>
  <path d="m72.52 158.1c8.59 1.63 18.61 2.42 29.89 1.14-3.36 6.96-4.85 15.51-11.15 15.51h-9.09c-5.83 0-8.11-7.75-9.65-16.65z" fill="#E5302F"/>
</svg>
    </div>
    <div class="cursor" id="cursor">
      <div class="cursor-ring"></div>
      <div class="cursor-dot"></div>
    </div>
  </div>
  <script>
    (function () {
      const artboard = document.getElementById("artboard");
      const stage = document.getElementById("stage");
      const cursorEl = document.getElementById("cursor");
      const svgElement = artboard.querySelector("svg");
      if (!svgElement || !cursorEl) return;

      svgElement.style.width = "100%";
      svgElement.style.height = "100%";
      svgElement.style.maxHeight = "100%";

      const elements = Array.from(
        artboard.querySelectorAll("path, rect, circle, line, polyline, polygon")
      );

      let totalLength = 0;
      const lengths = elements.map((el) => {
        const length = el.getTotalLength ? el.getTotalLength() : 0;
        totalLength += length;
        return length;
      });

      const centers = elements.map((el) => {
        const bbox = el.getBBox();
        return { x: bbox.x + bbox.width / 2, y: bbox.y + bbox.height / 2 };
      });
      const remaining = new Set(Array.from({ length: elements.length }, (_, index) => index));
      const orderedIndices = [];
      if (elements.length > 0) {
        let currentIndex = Array.from(remaining).sort((a, b) => (centers[a].x + centers[a].y) - (centers[b].x + centers[b].y))[0];
        while (remaining.size > 0) {
          orderedIndices.push(currentIndex);
          remaining.delete(currentIndex);
          if (remaining.size === 0) break;
          const currentCenter = centers[currentIndex];
          currentIndex = Array.from(remaining).sort((a, b) => {
            const da = Math.hypot(centers[a].x - currentCenter.x, centers[a].y - currentCenter.y);
            const db = Math.hypot(centers[b].x - currentCenter.x, centers[b].y - currentCenter.y);
            return da - db;
          })[0];
        }
      }

      const rawDurations = orderedIndices.map((elementIndex) => {
        if (totalLength <= 0) return 0.45;
        return Math.min(1.4, Math.max(0.45, lengths[elementIndex] / 430));
      });
      const rawTotalDuration = rawDurations.reduce((sum, value) => sum + value, 0);
      const durationScale = rawTotalDuration > 0
        ? Math.min(8.6, Math.max(2.2, rawTotalDuration)) / rawTotalDuration
        : 1;
      const elementStartTimes = new Array(elements.length).fill(0);
      const elementDurations = new Array(elements.length).fill(0);
      const elementFillDelays = new Array(elements.length).fill(0);
      let currentDelay = 0;
      for (let i = 0; i < orderedIndices.length; i += 1) {
        const elementIndex = orderedIndices[i];
        const duration = rawDurations[i] * durationScale;
        elementStartTimes[elementIndex] = currentDelay;
        elementDurations[elementIndex] = duration;
        elementFillDelays[elementIndex] = currentDelay + duration * 0.58;
        currentDelay += duration;
      }

      elements.forEach((svgEl, index) => {
        const length = lengths[index];
        svgEl.style.setProperty("--path-length", String(length));

        svgEl.style.setProperty("--draw-duration", elementDurations[index] + "s");
        svgEl.style.setProperty("--draw-delay", elementStartTimes[index] + "s");
        svgEl.style.setProperty("--fill-delay", elementFillDelays[index] + "s");

        const style = window.getComputedStyle(svgEl);
        let color = style.stroke;
        if (!color || color === "none" || color === "rgba(0, 0, 0, 0)") color = style.fill;
        if (!color || color === "none" || color === "rgba(0, 0, 0, 0)") color = "currentColor";
        svgEl.style.setProperty("--auto-stroke-color", color);

      });

      let animationFrameId = 0;
      let startTime = null;
      const totalAnimationTime = currentDelay + (Math.max(0.8, ...elementFillDelays.map((delay) => delay + 0.8 - currentDelay)));

      const animateCursor = (timestamp) => {
        if (!startTime) startTime = timestamp;
        const elapsed = (timestamp - startTime) / 1000;

        if (elapsed > totalAnimationTime || totalLength === 0) {
          cursorEl.style.opacity = "0";
          return;
        }

        cursorEl.style.opacity = "1";

        let activeElementIndex = orderedIndices[orderedIndices.length - 1] || 0;
        let isTrackingFillPhase = false;
        if (elapsed <= currentDelay) {
          for (let i = 0; i < orderedIndices.length; i += 1) {
            const elementIndex = orderedIndices[i];
            const elementStart = elementStartTimes[elementIndex];
            const elementEnd = elementStart + elementDurations[elementIndex];
            if (elapsed >= elementStart && elapsed <= elementEnd) {
              activeElementIndex = elementIndex;
              break;
            }
          }
        } else if (true) {
          isTrackingFillPhase = true;
          for (let i = 0; i < orderedIndices.length; i += 1) {
            const elementIndex = orderedIndices[i];
            const fillStart = elementFillDelays[elementIndex];
            const fillEnd = fillStart + 0.8;
            if (elapsed >= fillStart && elapsed <= fillEnd) {
              activeElementIndex = elementIndex;
              break;
            }
          }
        }

        const el = elements[activeElementIndex];
        if (!el) return;

        try {
          const bbox = el.getBBox();
          let centerX = bbox.x + bbox.width / 2;
          let centerY = bbox.y + bbox.height / 2;
          const chunkDrawEnd = elementStartTimes[activeElementIndex] + elementDurations[activeElementIndex];

          if (!isTrackingFillPhase && elapsed <= chunkDrawEnd && el.getPointAtLength && lengths[activeElementIndex] > 0) {
            const chunkProgress = elementDurations[activeElementIndex] > 0
              ? Math.min(1, Math.max(0, elapsed - elementStartTimes[activeElementIndex]) / elementDurations[activeElementIndex])
              : 1;
            const point = el.getPointAtLength(chunkProgress * lengths[activeElementIndex]);
            centerX = point.x;
            centerY = point.y;
          }

          const ctm = el.getScreenCTM();
          if (ctm) {
            const svgPt = svgElement.createSVGPoint();
            svgPt.x = centerX;
            svgPt.y = centerY;
            const screenPt = svgPt.matrixTransform(ctm);
            const stageRect = stage.getBoundingClientRect();
            let scale = 1;
            if (isTrackingFillPhase && true && elapsed >= elementFillDelays[activeElementIndex]) {
              const fillProgress = Math.min(1, (elapsed - elementFillDelays[activeElementIndex]) / 0.8);
              scale = fillProgress < 0.35 ? 1 - (fillProgress / 0.35) * 0.35 : 0.65 + ((fillProgress - 0.35) / 0.65) * 0.35;
            }
            cursorEl.style.transform = "translate(" + (screenPt.x - stageRect.left) + "px," + (screenPt.y - stageRect.top) + "px) scale(" + scale + ")";
          }
        } catch (error) {
          cursorEl.style.opacity = "0";
          return;
        }

        animationFrameId = requestAnimationFrame(animateCursor);
      };

      animationFrameId = requestAnimationFrame(animateCursor);
      window.addEventListener("beforeunload", function () {
        cancelAnimationFrame(animationFrameId);
      });
    })();
  </script>
</body>
</html>1d:T32f8,```jsx
import React, { useState, useEffect, useRef, useMemo } from 'react';
import { motion } from 'framer-motion';

const SvgAnimateBrand = () => {
  // 1. 固定画布尺寸
  const WIDTH = 1200;
  const HEIGHT = 700;
  const CX = WIDTH / 2;
  const CY = HEIGHT / 2;

  // 2. 核心配置
  const brandName = "SvgAnimate";
  const firstLetter = "S";
  const subTitle = "极致创意 · 矢量交互"; // Chinese subtitle
  
  // 科技感配色方案：金黄色主题 (Golden Yellow Theme)
  // 背景色：#0f172a (Slate 900 - Deep Blue/Grey)
  // 主色调：Gold -> Amber Gradient
  const primaryColor = "#FFD700"; // 金色
  const secondaryColor = "#F59E0B"; // 琥珀色/深金
  const accentColor = "#FFFBEB"; // 亮白/淡米色
  const gridColor = "rgba(148, 163, 184, 0.1)"; // 蓝灰色网格，与背景融合
  
  // 动画时长配置
  const duration = 2.8;
  const zoomIntensity = 4; // 初始缩放倍数

  // 3. 静态资源生成 (Grid, Stars, Rings) - 只计算一次
  const backgroundElements = useMemo(() => {
    const lines = [];
    const step = 80; // 网格稍微稀疏一点，显得大气
    // 生成透视网格线
    for (let i = -WIDTH; i < WIDTH * 2; i += step) {
      lines.push(
        <line 
          key={`v-${i}`} 
          x1={i} y1={-HEIGHT} 
          x2={i} y2={HEIGHT * 2} 
          stroke={gridColor}
          strokeWidth="1" 
        />
      );
    }
    for (let i = -HEIGHT; i < HEIGHT * 2; i += step) {
      lines.push(
        <line 
          key={`h-${i}`} 
          x1={-WIDTH} y1={i} 
          x2={WIDTH * 2} y2={i} 
          stroke={gridColor}
          strokeWidth="1" 
        />
      );
    }
    
    // 生成随机粒子 (数据流尘埃)
    const particles = Array.from({ length: 60 }).map((_, i) => ({
      cx: Math.random() * WIDTH,
      cy: Math.random() * HEIGHT,
      r: Math.random() * 1.5 + 0.5,
      opacity: Math.random() * 0.6 + 0.2,
      delay: Math.random() * 3,
      duration: 3 + Math.random() * 4
    }));

    // 生成装饰性科技圆环数据
    const rings = [
        { r: 220, dash: "20, 40", width: 1, speed: 1 },
        { r: 260, dash: "5, 10, 30, 10", width: 2, speed: -0.5 },
        { r: 300, dash: "80, 120", width: 1, speed: 0.2 },
    ];

    return { lines, particles, rings };
  }, [gridColor]);

  // 4. RAF 循环：用于背景网格微动和科技圆环旋转
  const gridRef = useRef(null);
  const ringsRef = useRef([]);
  const timeRef = useRef(0);
  const rafRef = useRef(null);

  useEffect(() => {
    const loop = (time) => {
      timeRef.current = time * 0.0005; // 时间系数
      
      // 1. 网格缓慢浮动
      if (gridRef.current) {
        const rotate = Math.sin(timeRef.current * 0.15) * 1.5;
        const scale = 1 + Math.sin(timeRef.current * 0.3) * 0.02;
        gridRef.current.setAttribute("transform", `translate(${CX}, ${CY}) rotate(${rotate}) scale(${scale}) translate(${-CX}, ${-CY})`);
      }

      // 2. 科技圆环持续旋转
      ringsRef.current.forEach((ringEl, index) => {
          if (ringEl) {
              const speed = backgroundElements.rings[index].speed;
              const currentRotate = (time * 0.02 * speed) % 360;
              ringEl.setAttribute("transform", `rotate(${currentRotate})`);
          }
      });
      
      rafRef.current = requestAnimationFrame(loop);
    };
    
    rafRef.current = requestAnimationFrame(loop);

    return () => {
      if (rafRef.current) cancelAnimationFrame(rafRef.current);
    };
  }, [CX, CY, backgroundElements.rings]);

  return (
    <div style={{ 
      width: '100%', 
      height: '100vh', 
      backgroundColor: '#020617', // 外部容器深色
      display: 'flex', 
      alignItems: 'center', 
      justifyContent: 'center', 
      overflow: 'hidden',
      position: 'relative'
    }}>
      {/* 根容器限制尺寸 */}
      <div style={{ 
        width: WIDTH, 
        height: HEIGHT, 
        position: 'relative', 
        background: '#0f172a', // 用户要求的背景色
        boxShadow: '0 0 60px rgba(255, 215, 0, 0.15)', // 金色微光阴影
        overflow: 'hidden',
        borderRadius: '8px'
      }}>
        <svg 
          viewBox={`0 0 ${WIDTH} ${HEIGHT}`} 
          style={{ width: '100%', height: '100%', display: 'block' }}
          preserveAspectRatio="xMidYMid slice"
        >
          {/* Defs: 渐变与滤镜 */}
          <defs>
            {/* 金色主渐变 */}
            <linearGradient id="goldGradient" x1="0%" y1="0%" x2="100%" y2="100%">
              <stop offset="0%" stopColor={primaryColor} />
              <stop offset="50%" stopColor="#FFC107" />
              <stop offset="100%" stopColor={secondaryColor} />
            </linearGradient>
            
            {/* 描边渐变 (更亮) */}
            <linearGradient id="strokeGradient" x1="0%" y1="0%" x2="0%" y2="100%">
              <stop offset="0%" stopColor="#FFF7CC" stopOpacity="0.9"/>
              <stop offset="100%" stopColor={primaryColor} stopOpacity="0.9"/>
            </linearGradient>

            {/* 背景暗角 */}
            <radialGradient id="vignetteGradient" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
                <stop offset="60%" stopColor="#0f172a" stopOpacity="0" />
                <stop offset="100%" stopColor="#020617" stopOpacity="0.9" />
             </radialGradient>

            {/* 辉光滤镜 */}
            <filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
              <feGaussianBlur stdDeviation="12" result="coloredBlur" />
              <feMerge>
                <feMergeNode in="coloredBlur" />
                <feMergeNode in="SourceGraphic" />
              </feMerge>
            </filter>
            
            {/* 强辉光 (用于背景) */}
            <filter id="strongGlow" x="-50%" y="-50%" width="200%" height="200%">
                <feGaussianBlur stdDeviation="30" result="blur" />
                <feComposite in="blur" in2="SourceGraphic" operator="over" />
            </filter>
          </defs>

          {/* 1. 背景层 (Grid & Particles) */}
          <g ref={gridRef} style={{ transformOrigin: 'center center' }}>
            {backgroundElements.lines}
          </g>
          
          <g>
            {backgroundElements.particles.map((p, i) => (
               <motion.circle
                 key={i}
                 cx={p.cx} cy={p.cy} r={p.r}
                 fill={primaryColor} // 金色粒子
                 initial={{ opacity: 0 }}
                 animate={{ opacity: [0, p.opacity, 0], y: [0, -20] }} // 粒子稍微上浮
                 transition={{ 
                   duration: p.duration, 
                   repeat: Infinity, 
                   delay: p.delay,
                   ease: "easeInOut" 
                 }}
               />
            ))}
          </g>

          {/* 2. 核心动画组：居中 */}
          <g transform={`translate(${CX}, ${CY})`}>
            
            {/* 装饰：旋转的科技圆环 */}
            <motion.g 
                initial={{ opacity: 0, scale: 0.8 }}
                animate={{ opacity: 0.4, scale: 1 }}
                transition={{ duration: 2, delay: 0.5 }}
            >
                {backgroundElements.rings.map((ring, i) => (
                    <circle 
                        key={`ring-${i}`}
                        ref={el => ringsRef.current[i] = el}
                        r={ring.r}
                        fill="none"
                        stroke={primaryColor}
                        strokeWidth={ring.width}
                        strokeDasharray={ring.dash}
                        opacity={0.3}
                        style={{ transformOrigin: 'center' }}
                    />
                ))}
            </motion.g>

            {/* A. 辉光/模糊背景层 (The "S" Glow) */}
            <motion.text
              textAnchor="middle" 
              dy=".35em" 
              fontSize="380" 
              fontWeight="900" 
              fontFamily="'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
              fill={primaryColor}
              style={{ filter: "blur(60px)", opacity: 0.4 }}
              initial={{ scale: zoomIntensity, opacity: 0 }}
              animate={{ scale: 1, opacity: 0.4 }}
              transition={{ duration: duration, ease: [0.22, 1, 0.36, 1] }}
            >
              {firstLetter}
            </motion.text>

            {/* B. 描边动画层 (The Ribbons) - 金色流光 */}
            {[0, 1, 2].map((i) => (
              <motion.text
                key={`stroke-${i}`}
                textAnchor="middle" 
                dy=".35em" 
                fontSize="380" 
                fontWeight="900" 
                fontFamily="'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
                fill="transparent"
                stroke="url(#strokeGradient)"
                strokeWidth={2 + i * 1}
                strokeLinecap="round"
                strokeLinejoin="round"
                initial={{ 
                  strokeDasharray: 1400, 
                  strokeDashoffset: 1400, 
                  scale: zoomIntensity,
                  opacity: 0
                }}
                animate={{ 
                  strokeDashoffset: 0, 
                  scale: 1,
                  opacity: 1
                }}
                transition={{
                  duration: duration * 0.9,
                  ease: "easeInOut",
                  delay: i * 0.15 // 错帧延迟
                }}
                style={{ 
                  mixBlendMode: 'screen', // 混合模式让金色更亮
                  filter: `drop-shadow(0 0 ${i * 3}px ${secondaryColor})`
                }}
              >
                {firstLetter}
              </motion.text>
            ))}

            {/* C. 实体填充层 (Solid Reveal) */}
            <motion.text
              textAnchor="middle" 
              dy=".35em" 
              fontSize="380" 
              fontWeight="900" 
              fontFamily="'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
              fill="url(#goldGradient)"
              initial={{ opacity: 0, scale: zoomIntensity }}
              animate={{ opacity: 1, scale: 1 }}
              transition={{ delay: duration * 0.6, duration: duration * 0.4, ease: "easeOut" }}
              style={{ filter: "url(#glow)" }}
            >
              {firstLetter}
            </motion.text>

            {/* D. 品牌全称 (Brand Name) */}
            <motion.g
              initial={{ opacity: 0, y: 160 }}
              animate={{ opacity: 1, y: 230 }}
              transition={{ delay: duration * 0.8, duration: 0.8, ease: "easeOut" }}
            >
               {/* 装饰线 - 金色能量条 */}
               <motion.line 
                  x1="-220" y1="-60" x2="220" y2="-60" 
                  stroke={primaryColor} 
                  strokeWidth="2"
                  initial={{ pathLength: 0, opacity: 0 }}
                  animate={{ pathLength: 1, opacity: 0.8 }}
                  transition={{ delay: duration * 1, duration: 1 }}
                  style={{ filter: "drop-shadow(0 0 5px #FFD700)" }}
               />

               {/* 主标题 */}
               <text
                 textAnchor="middle" 
                 fontSize="64" 
                 fontWeight="bold" 
                 fontFamily="monospace" 
                 letterSpacing="0.1em" 
                 fill={accentColor}
                 style={{ textShadow: `0 0 25px ${secondaryColor}` }}
               >
                 {brandName}
               </text>
               
               {/* 中文副标题 */}
               <motion.text
                 y="50"
                 textAnchor="middle" 
                 fontSize="24" 
                 fontWeight="400" 
                 fontFamily="'Microsoft YaHei', 'PingFang SC', sans-serif" 
                 letterSpacing="0.4em" 
                 fill="#94a3b8" // Slate 400
                 initial={{ opacity: 0 }}
                 animate={{ opacity: 1 }}
                 transition={{ delay: duration * 1.2, duration: 1 }}
               >
                 {subTitle}
               </motion.text>
            </motion.g>

            {/* E. 扫描线效果 (Scanlines) - 增加科技质感 */}
            <motion.rect
              x="-250" y="160" width="500" height="120"
              fill="url(#goldGradient)"
              initial={{ scaleX: 0, opacity: 0 }}
              animate={{ scaleX: 1.1, opacity: [0, 0.15, 0] }}
              transition={{ delay: duration * 0.8, duration: 0.6, ease: "easeOut" }}
              style={{ mixBlendMode: 'overlay' }}
            />
          </g>
          
          {/* 3. 前景装饰：暗角 (Vignette) */}
          <rect 
            width={WIDTH} 
            height={HEIGHT} 
            fill="url(#vignetteGradient)" 
            style={{ pointerEvents: 'none' }} 
          />

        </svg>
      </div>
    </div>
  );
};

export default SvgAnimateBrand;
```1e:T23f8,<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Apple Logo — Line Drawing Animation</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
 
  body {
    background: #0a0a0a;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    font-family: -apple-system, 'Helvetica Neue', sans-serif;
    overflow: hidden;
  }
 
  .container {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 36px;
  }
 
  /* Soft radial glow */
  .glow {
    position: absolute;
    width: 520px;
    height: 520px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(255,255,255,0.035) 0%, transparent 70%);
    top: 50%;
    left: 50%;
    transform: translate(-50%, -55%);
    pointer-events: none;
    opacity: 0;
    animation: glowIn 2s ease 5.8s forwards;
  }
 
  @keyframes glowIn { to { opacity: 1; } }
 
  svg.logo {
    width: 260px;
    height: 260px;
    filter: drop-shadow(0 0 0px rgba(255,255,255,0));
    animation: addGlow 1.5s ease 6.2s forwards;
  }
 
  @keyframes addGlow {
    to { filter: drop-shadow(0 0 40px rgba(255,255,255,0.06)); }
  }
 
  /* ---------- Stroke drawing ---------- */
  .draw-stroke {
    fill: none;
    stroke: #ffffff;
    stroke-width: 8;
    stroke-linecap: round;
    stroke-linejoin: round;
  }
 
  /* Apple body */
  .stroke-body {
    animation: drawStroke var(--dur) cubic-bezier(0.4, 0, 0.2, 1) 0.6s forwards;
  }
 
  /* Leaf */
  .stroke-leaf {
    animation: drawStroke var(--dur) cubic-bezier(0.4, 0, 0.2, 1) calc(0.6s + var(--body-dur)) forwards;
  }
 
  @keyframes drawStroke {
    from { stroke-dashoffset: var(--len); }
    to   { stroke-dashoffset: 0; }
  }
 
  /* ---------- Fill fade-in ---------- */
  .fill-layer {
    stroke: none;
    opacity: 0;
  }
 
  .fill-body {
    fill: #ffffff;
    animation: fillIn 1.6s ease var(--fill-start) forwards;
  }
 
  .fill-leaf {
    fill: #ffffff;
    animation: fillIn 1s ease calc(var(--fill-start) + 0.3s) forwards;
  }
 
  @keyframes fillIn { to { opacity: 1; } }
 
  /* ---------- Stroke fade-out after fill ---------- */
  .stroke-body {
    animation:
      drawStroke var(--body-dur) cubic-bezier(0.4, 0, 0.2, 1) 0.6s forwards,
      strokeOut 1s ease var(--fill-start) forwards;
  }
 
  .stroke-leaf {
    animation:
      drawStroke var(--leaf-dur) cubic-bezier(0.4, 0, 0.2, 1) calc(0.6s + var(--body-dur)) forwards,
      strokeOut 1s ease calc(var(--fill-start) + 0.3s) forwards;
  }
 
  @keyframes strokeOut {
    to { stroke-opacity: 0; }
  }
 
  /* ---------- UI elements ---------- */
  .tagline {
    color: rgba(255,255,255,0.45);
    font-size: 13px;
    letter-spacing: 7px;
    text-transform: uppercase;
    font-weight: 200;
    opacity: 0;
    transform: translateY(12px);
    animation: textIn 1.5s ease 6.5s forwards;
  }
 
  @keyframes textIn { to { opacity: 1; transform: translateY(0); } }
 
  .replay-btn {
    position: fixed;
    bottom: 36px;
    right: 36px;
    background: none;
    border: 1px solid rgba(255,255,255,0.12);
    color: rgba(255,255,255,0.35);
    padding: 10px 24px;
    border-radius: 100px;
    font-size: 12px;
    letter-spacing: 3px;
    cursor: pointer;
    transition: all 0.3s ease;
    opacity: 0;
    animation: textIn 1s ease 7s forwards;
  }
 
  .replay-btn:hover {
    border-color: rgba(255,255,255,0.35);
    color: rgba(255,255,255,0.65);
  }
 
  .progress-track {
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 2px;
    background: rgba(255,255,255,0.04);
  }
 
  .progress-bar {
    height: 100%;
    background: linear-gradient(90deg, rgba(255,255,255,0.1), rgba(255,255,255,0.7), rgba(255,255,255,0.1));
    width: 0%;
    animation: progress 6s cubic-bezier(0.4, 0, 0.2, 1) 0.3s forwards;
  }
 
  @keyframes progress { to { width: 100%; } }
 
  /* Sparkles */
  .sparkle {
    position: absolute;
    width: 3px;
    height: 3px;
    background: #fff;
    border-radius: 50%;
    opacity: 0;
    pointer-events: none;
  }
  .sparkle:nth-child(1) { top: 18%; left: 25%; animation: sparkle 0.7s ease 5.5s forwards; }
  .sparkle:nth-child(2) { top: 5%;  right: 30%; animation: sparkle 0.7s ease 5.7s forwards; }
  .sparkle:nth-child(3) { top: 50%; left: 12%; animation: sparkle 0.7s ease 5.9s forwards; }
  .sparkle:nth-child(4) { top: 75%; right: 18%; animation: sparkle 0.7s ease 6.1s forwards; }
 
  @keyframes sparkle {
    0%   { opacity: 0; transform: scale(0); }
    50%  { opacity: 1; transform: scale(2); }
    100% { opacity: 0; transform: scale(0); }
  }
</style>
</head>
<body>
 
<div class="container">
  <div class="glow"></div>
  <div class="sparkle"></div>
  <div class="sparkle"></div>
  <div class="sparkle"></div>
  <div class="sparkle"></div>
 
  <svg class="logo" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
 
    <!-- Apple body (the big bitten-apple shape) -->
    <path id="body-path" d="
      M791.487729 544.095473
      c-1.279999-129.695874 105.759898-191.871814 110.527893-194.975811
      c-60.159942-88.031915-153.855851-100.063903-187.231819-101.471902
      c-79.743923-8.063992-155.583849 46.943955-196.06381 46.943955
      c-40.351961 0-102.8159-45.759956-168.959836-44.543957
      c-86.911916 1.279999-167.071838 50.527951-211.807795 128.383876
      c-90.303913 156.703848-23.135978 388.831623 64.895937 515.9355
      c43.007958 62.20794 94.303909 132.063872 161.631843 129.567874
      c64.831937-2.591997 89.375913-41.951959 167.743837-41.951959
      s100.415903 41.951959 169.055836 40.671961
      c69.759932-1.311999 113.98389-63.391939 156.703848-125.791878
      c49.375952-72.15993 69.727932-142.047862 70.911931-145.631859
      c-1.535999-0.703999-136.063868-52.223949-137.407867-207.135799z
    "/>
 
    <!-- Leaf -->
    <path id="leaf-path" d="
      M662.559854 163.519842
      c35.743965-43.359958 59.871942-103.5199 53.279948-163.519842
      c-51.48795 2.111998-113.88789 34.303967-150.815854 77.535925
      c-33.151968 38.367963-62.14394 99.615903-54.367947 158.431847
      c57.471944 4.479996 116.127888-29.215972 151.903853-72.44793z
    "/>
 
    <!-- Fill layers (fade in after drawing) -->
    <use href="#body-path" class="fill-layer fill-body"/>
    <use href="#leaf-path" class="fill-layer fill-leaf"/>
 
    <!-- Stroke layers (animated drawing) -->
    <use href="#body-path" class="draw-stroke stroke-body"/>
    <use href="#leaf-path" class="draw-stroke stroke-leaf"/>
 
  </svg>
 
  <div class="tagline">Think Different</div>
</div>
 
<div class="progress-track">
  <div class="progress-bar"></div>
</div>
 
<button class="replay-btn" onclick="replay()">REPLAY</button>
 
<script>
(function init() {
  const bodyEl = document.querySelector('.stroke-body');
  const leafEl = document.querySelector('.stroke-leaf');
  const bodyRef = document.getElementById('body-path');
  const leafRef = document.getElementById('leaf-path');
 
  const bodyLen = Math.ceil(bodyRef.getTotalLength());
  const leafLen = Math.ceil(leafRef.getTotalLength());
 
  // Timing
  const bodyDur = 3.5;  // seconds for body
  const leafDur = 1.2;  // seconds for leaf
  const fillStart = 0.6 + bodyDur + leafDur + 0.3; // after both strokes finish + small pause
 
  // Set CSS custom properties on root
  const root = document.documentElement;
  root.style.setProperty('--body-dur', bodyDur + 's');
  root.style.setProperty('--leaf-dur', leafDur + 's');
  root.style.setProperty('--fill-start', fillStart + 's');
 
  // Body stroke
  bodyEl.style.strokeDasharray = bodyLen;
  bodyEl.style.strokeDashoffset = bodyLen;
  bodyEl.style.setProperty('--len', bodyLen);
  bodyEl.style.setProperty('--dur', bodyDur + 's');
 
  // Leaf stroke
  leafEl.style.strokeDasharray = leafLen;
  leafEl.style.strokeDashoffset = leafLen;
  leafEl.style.setProperty('--len', leafLen);
  leafEl.style.setProperty('--dur', leafDur + 's');
})();
 
function replay() {
  document.body.style.transition = 'opacity 0.35s';
  document.body.style.opacity = '0';
 
  setTimeout(() => {
    // Reset all animations
    const sel = '.draw-stroke, .fill-layer, .glow, .logo, .tagline, .replay-btn, .progress-bar, .sparkle';
    document.querySelectorAll(sel).forEach(el => {
      el.style.animation = 'none';
      el.offsetHeight; // reflow
      el.style.animation = '';
    });
 
    // Re-measure and re-set dash values
    const bodyRef = document.getElementById('body-path');
    const leafRef = document.getElementById('leaf-path');
    const bodyEl = document.querySelector('.stroke-body');
    const leafEl = document.querySelector('.stroke-leaf');
 
    const bodyLen = Math.ceil(bodyRef.getTotalLength());
    const leafLen = Math.ceil(leafRef.getTotalLength());
 
    bodyEl.style.strokeDasharray = bodyLen;
    bodyEl.style.strokeDashoffset = bodyLen;
    bodyEl.style.setProperty('--len', bodyLen);
 
    leafEl.style.strokeDasharray = leafLen;
    leafEl.style.strokeDashoffset = leafLen;
    leafEl.style.setProperty('--len', leafLen);
 
    document.body.style.opacity = '1';
  }, 400);
}
</script>
 
</body>
</html>1f:T5afc,<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WeChat Message Transmission Process</title>
    <style>
        :root {
            --bg-dark: #0A0F1A;
            --wx-green: #07C160;
            --wx-green-glow: #00E676;
            --tech-blue: #00E5FF;
            --tech-blue-dark: #005A70;
            --phone-bg: #1A2235;
            --phone-screen: #111827;
            --text-main: #FFFFFF;
            --text-sub: #9CA3AF;
            --bubble-left: #262E3D;
            --bubble-right: #07C160;
        }

        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            background-color: var(--bg-dark);
            display: flex;
            align-items: center;
            justify-content: center;
            font-family: 'PingFang SC', 'Microsoft YaHei', -apple-system, sans-serif;
            overflow: hidden;
        }

        #animation-container {
            width: 100%;
            height: 100%;
            max-width: 1200px;
            max-height: 700px;
            position: relative;
        }

        svg {
            width: 100%;
            height: 100%;
            display: block;
            user-select: none;
        }

        /* 提升渲染质量 */
        * {
            shape-rendering: geometricPrecision;
            text-rendering: optimizeLegibility;
        }

        /* 静态发光动画 */
        @keyframes pulseGlow {
            0%, 100% { filter: drop-shadow(0 0 8px var(--tech-blue)); }
            50% { filter: drop-shadow(0 0 20px var(--tech-blue)); }
        }
        .server-core {
            animation: pulseGlow 3s infinite ease-in-out;
        }
        
        @keyframes gridMove {
            from { stroke-dashoffset: 40; }
            to { stroke-dashoffset: 0; }
        }
        .grid-line {
            stroke-dasharray: 4 36;
            animation: gridMove 2s linear infinite;
        }
    </style>
</head>
<body>

<div id="animation-container">
    <svg viewBox="0 0 1200 700" preserveAspectRatio="xMidYMid meet">
        <defs>
            <!-- 发光滤镜 -->
            <filter id="glow-green" x="-50%" y="-50%" width="200%" height="200%">
                <feGaussianBlur stdDeviation="8" result="blur" />
                <feComposite in="SourceGraphic" in2="blur" operator="over" />
            </filter>
            
            <filter id="glow-blue" x="-50%" y="-50%" width="200%" height="200%">
                <feGaussianBlur stdDeviation="6" result="blur" />
                <feComposite in="SourceGraphic" in2="blur" operator="over" />
            </filter>

            <!-- 手机阴影 -->
            <filter id="shadow-3d" x="-20%" y="-20%" width="150%" height="150%">
                <feDropShadow dx="0" dy="30" stdDeviation="20" flood-color="#000000" flood-opacity="0.8" />
            </filter>

            <!-- 渐变 -->
            <linearGradient id="phone-edge" x1="0%" y1="0%" x2="100%" y2="100%">
                <stop offset="0%" stop-color="#2A354D" />
                <stop offset="100%" stop-color="#0F1423" />
            </linearGradient>

            <linearGradient id="server-grad" x1="0%" y1="0%" x2="0%" y2="100%">
                <stop offset="0%" stop-color="#00E5FF" stop-opacity="0.8"/>
                <stop offset="100%" stop-color="#005A70" stop-opacity="0.2"/>
            </linearGradient>

            <linearGradient id="path-grad-1" x1="0%" y1="100%" x2="100%" y2="0%">
                <stop offset="0%" stop-color="#07C160" stop-opacity="0.1"/>
                <stop offset="100%" stop-color="#07C160" stop-opacity="1"/>
            </linearGradient>
            
            <linearGradient id="path-grad-2" x1="0%" y1="0%" x2="100%" y2="100%">
                <stop offset="0%" stop-color="#00E5FF" stop-opacity="1"/>
                <stop offset="100%" stop-color="#00E5FF" stop-opacity="0.1"/>
            </linearGradient>
        </defs>

        <!-- 背景透视网格 -->
        <g stroke="#1A2B4C" stroke-width="1" opacity="0.5" transform="translate(600, 350) scale(1.5)">
            <g transform="matrix(0.866, 0.5, -0.866, 0.5, 0, 0)">
                <!-- 绘制网格线 -->
                <g id="grid-lines">
                    <line x1="-500" y1="-300" x2="500" y2="-300" class="grid-line" />
                    <line x1="-500" y1="-200" x2="500" y2="-200" class="grid-line" />
                    <line x1="-500" y1="-100" x2="500" y2="-100" class="grid-line" />
                    <line x1="-500" y1="0" x2="500" y2="0" class="grid-line" />
                    <line x1="-500" y1="100" x2="500" y2="100" class="grid-line" />
                    <line x1="-500" y1="200" x2="500" y2="200" class="grid-line" />
                    <line x1="-500" y1="300" x2="500" y2="300" class="grid-line" />
                    
                    <line x1="-300" y1="-500" x2="-300" y2="500" class="grid-line" />
                    <line x1="-200" y1="-500" x2="-200" y2="500" class="grid-line" />
                    <line x1="-100" y1="-500" x2="-100" y2="500" class="grid-line" />
                    <line x1="0" y1="-500" x2="0" y2="500" class="grid-line" />
                    <line x1="100" y1="-500" x2="100" y2="500" class="grid-line" />
                    <line x1="200" y1="-500" x2="200" y2="500" class="grid-line" />
                    <line x1="300" y1="-500" x2="300" y2="500" class="grid-line" />
                </g>
            </g>
        </g>

        <!-- ================= 数据传输轨迹线 ================= -->
        <!-- 左到中 -->
        <path id="path-up" d="M 280,420 C 350,200 480,180 600,220" fill="none" stroke="url(#path-grad-1)" stroke-width="3" stroke-dasharray="8 8" opacity="0.4" />
        <!-- 中到右 -->
        <path id="path-down" d="M 600,220 C 720,260 850,240 920,420" fill="none" stroke="url(#path-grad-2)" stroke-width="3" stroke-dasharray="8 8" opacity="0.4" />

        <!-- ================= 云端服务器 (微信后台) ================= -->
        <g id="cloud-server" transform="translate(600, 220)">
            <!-- 底部光环 -->
            <ellipse cx="0" cy="50" rx="80" ry="40" fill="none" stroke="var(--tech-blue)" stroke-width="1" opacity="0.3" />
            <ellipse id="server-ripple" cx="0" cy="50" rx="40" ry="20" fill="none" stroke="var(--tech-blue)" stroke-width="2" opacity="0" />
            
            <g transform="matrix(0.866, 0.5, -0.866, 0.5, 0, 0)">
                <!-- 服务器底座 -->
                <path d="M -40,-40 L 40,-40 L 40,40 L -40,40 Z" fill="#0D1B2A" stroke="var(--tech-blue)" stroke-width="1"/>
                <!-- 服务器主体 (分层) -->
                <g transform="translate(0, 0)">
                    <rect x="-30" y="-30" width="60" height="60" fill="url(#server-grad)" />
                    <rect x="-30" y="-30" width="60" height="60" fill="none" stroke="var(--tech-blue)" stroke-width="1" />
                </g>
                <g transform="translate(10, 10)">
                    <rect x="-30" y="-30" width="60" height="60" fill="url(#server-grad)" />
                    <rect x="-30" y="-30" width="60" height="60" fill="none" stroke="var(--tech-blue)" stroke-width="1" />
                </g>
                <g transform="translate(20, 20)" class="server-core">
                    <rect x="-30" y="-30" width="60" height="60" fill="#00E5FF" opacity="0.2" />
                    <rect x="-30" y="-30" width="60" height="60" fill="none" stroke="#FFFFFF" stroke-width="2" />
                    <!-- 核心芯片纹理 -->
                    <rect x="-15" y="-15" width="30" height="30" fill="none" stroke="var(--tech-blue)" stroke-width="1" />
                    <circle cx="0" cy="0" r="4" fill="#FFFFFF" />
                </g>
            </g>
            <!-- 状态标签 -->
            <rect x="-40" y="-70" width="80" height="24" rx="12" fill="#0A0F1A" stroke="var(--tech-blue)" stroke-width="1" opacity="0.8"/>
            <text x="0" y="-54" fill="var(--tech-blue)" font-size="12" font-weight="bold" text-anchor="middle" letter-spacing="1">加密传输中</text>
        </g>

        <!-- ================= 左侧手机 (发送端) ================= -->
        <g id="left-phone" transform="translate(280, 480)">
            <g transform="translate(0, 20)">
                <g transform="matrix(0.866, 0.5, -0.866, 0.5, 0, 0)">
                    <rect x="-95" y="-185" width="190" height="370" rx="32" fill="url(#phone-edge)" filter="url(#shadow-3d)"/>
                </g>
            </g>
            
            <g transform="matrix(0.866, 0.5, -0.866, 0.5, 0, 0)">
                <!-- 手机外壳 -->
                <rect x="-95" y="-185" width="190" height="370" rx="32" fill="var(--phone-bg)" stroke="#374151" stroke-width="2"/>
                <!-- 屏幕 -->
                <rect x="-85" y="-175" width="170" height="350" rx="24" fill="var(--phone-screen)" />
                
                <!-- 微信 UI 头部 -->
                <g transform="translate(0, -145)">
                    <text x="-65" y="0" fill="var(--text-main)" font-size="16" font-weight="bold">微信 (12)</text>
                    <circle cx="60" cy="-5" r="2" fill="var(--text-sub)"/>
                    <circle cx="68" cy="-5" r="2" fill="var(--text-sub)"/>
                    <text x="-65" y="20" fill="var(--text-sub)" font-size="10">项目沟通群</text>
                    <line x1="-85" y1="35" x2="85" y2="35" stroke="#1F2937" stroke-width="1" />
                </g>

                <!-- 历史聊天记录 (静态) -->
                <g transform="translate(0, -70)">
                    <!-- 对方的消息 -->
                    <rect x="-75" y="-20" width="30" height="30" rx="6" fill="#374151" />
                    <rect x="-35" y="-20" width="90" height="30" rx="8" fill="var(--bubble-left)" />
                    <text x="-25" y="0" fill="var(--text-sub)" font-size="10">最新设计图做好了吗？</text>
                </g>

                <!-- 动态发送的消息气泡 -->
                <g id="sender-bubble-group" transform="translate(0, -10)">
                    <!-- 头像 -->
                    <rect x="45" y="-20" width="30" height="30" rx="6" fill="#059669" />
                    <!-- 气泡主体 -->
                    <g id="sender-bubble" transform="scale(0)">
                        <rect x="-65" y="-20" width="100" height="30" rx="8" fill="var(--bubble-right)" />
                        <!-- 小尾巴 -->
                        <path d="M 35,-10 L 45,-10 L 35,0 Z" fill="var(--bubble-right)" />
                        <text x="-55" y="0" fill="#000000" font-size="11" font-weight="bold">核心代码已提交！</text>
                    </g>
                    <!-- 已读/送达状态 -->
                    <text id="msg-status" x="-85" y="0" fill="var(--text-sub)" font-size="9" opacity="0">已送达</text>
                </g>

                <!-- 底部输入框区 -->
                <g transform="translate(0, 145)">
                    <line x1="-85" y1="-25" x2="85" y2="-25" stroke="#1F2937" stroke-width="1" />
                    <!-- 语音图标模拟 -->
                    <circle cx="-65" cy="0" r="10" fill="none" stroke="var(--text-sub)" stroke-width="1.5"/>
                    <!-- 输入框 -->
                    <rect x="-45" y="-12" width="80" height="24" rx="4" fill="#1F2937" />
                    <!-- 加号图标模拟 -->
                    <circle cx="50" cy="0" r="10" fill="none" stroke="var(--text-sub)" stroke-width="1.5"/>
                    <circle cx="75" cy="0" r="10" fill="none" stroke="var(--text-sub)" stroke-width="1.5"/>
                    
                    <!-- 发送按钮 (覆盖在输入框上，动画时显示) -->
                    <g id="send-btn" transform="translate(-5, 0)" opacity="1">
                        <rect x="-40" y="-12" width="70" height="24" rx="4" fill="var(--wx-green)" />
                        <text x="-5" y="4" fill="#FFFFFF" font-size="11" font-weight="bold" text-anchor="middle">发送</text>
                    </g>
                </g>
            </g>
            
            <!-- 手机上方发光信号塔标识 (装饰) -->
            <path id="left-signal" d="M 0,-210 A 30 30 0 0 1 30,-240" fill="none" stroke="var(--wx-green)" stroke-width="3" stroke-linecap="round" opacity="0"/>
        </g>

        <!-- ================= 右侧手机 (接收端) ================= -->
        <g id="right-phone" transform="translate(920, 480)">
            <g transform="translate(0, 20)">
                <g transform="matrix(0.866, 0.5, -0.866, 0.5, 0, 0)">
                    <rect x="-95" y="-185" width="190" height="370" rx="32" fill="url(#phone-edge)" filter="url(#shadow-3d)"/>
                </g>
            </g>
            
            <g transform="matrix(0.866, 0.5, -0.866, 0.5, 0, 0)">
                <!-- 手机外壳 -->
                <rect x="-95" y="-185" width="190" height="370" rx="32" fill="var(--phone-bg)" stroke="#374151" stroke-width="2"/>
                <!-- 屏幕 -->
                <rect x="-85" y="-175" width="170" height="350" rx="24" fill="var(--phone-screen)" />
                
                <!-- 微信 UI 头部 -->
                <g transform="translate(0, -145)">
                    <text x="-65" y="0" fill="var(--text-main)" font-size="16" font-weight="bold">前端开发 (Leo)</text>
                    <circle cx="60" cy="-5" r="2" fill="var(--text-sub)"/>
                    <circle cx="68" cy="-5" r="2" fill="var(--text-sub)"/>
                    <line x1="-85" y1="20" x2="85" y2="20" stroke="#1F2937" stroke-width="1" />
                </g>

                <!-- 历史聊天记录 -->
                <g transform="translate(0, -90)">
                    <rect x="45" y="-20" width="30" height="30" rx="6" fill="#374151" />
                    <rect x="-55" y="-20" width="90" height="30" rx="8" fill="var(--bubble-right)" />
                    <text x="-45" y="0" fill="#000000" font-size="10" font-weight="bold">最新设计图做好了吗？</text>
                </g>

                <!-- 接收动画组 -->
                <g id="receiver-bubble-group" transform="translate(0, -30)">
                    <!-- 对方头像 -->
                    <rect x="-75" y="-20" width="30" height="30" rx="6" fill="#059669" />
                    <!-- 接收的气泡 -->
                    <g id="receiver-bubble" transform="scale(0)">
                        <rect x="-35" y="-20" width="100" height="30" rx="8" fill="var(--bubble-left)" />
                        <!-- 小尾巴 -->
                        <path d="M -35,-10 L -45,-10 L -35,0 Z" fill="var(--bubble-left)" />
                        <text x="-25" y="0" fill="var(--text-main)" font-size="11">核心代码已提交！</text>
                    </g>
                </g>

                <!-- 底部输入框区 (静态) -->
                <g transform="translate(0, 145)">
                    <line x1="-85" y1="-25" x2="85" y2="-25" stroke="#1F2937" stroke-width="1" />
                    <circle cx="-65" cy="0" r="10" fill="none" stroke="var(--text-sub)" stroke-width="1.5"/>
                    <rect x="-45" y="-12" width="80" height="24" rx="4" fill="#1F2937" />
                    <circle cx="50" cy="0" r="10" fill="none" stroke="var(--text-sub)" stroke-width="1.5"/>
                    <circle cx="75" cy="0" r="10" fill="none" stroke="var(--text-sub)" stroke-width="1.5"/>
                </g>
            </g>
            
            <!-- 手机新消息通知红点 -->
            <circle id="notification-badge" cx="30" cy="-210" r="6" fill="#EF4444" opacity="0" filter="url(#glow-green)"/>
        </g>

        <!-- ================= 飞行的数据包 ================= -->
        <g id="data-packet" transform="scale(0)">
            <!-- 外层光晕 -->
            <circle cx="0" cy="0" r="16" fill="var(--wx-green)" opacity="0.3" filter="url(#glow-green)" />
            <circle cx="0" cy="0" r="8" fill="var(--wx-green)" filter="url(#glow-green)" />
            <circle cx="0" cy="0" r="4" fill="#FFFFFF" />
            <!-- 数据拖尾效果 -->
            <path id="packet-trail" d="M -8,0 L -30,0" stroke="var(--wx-green)" stroke-width="4" stroke-linecap="round" opacity="0.8" filter="url(#glow-green)"/>
            <!-- 内部包裹的抽象信息符号 -->
            <path d="M -3,-3 L 3,-3 M -3,0 L 3,0 M -3,3 L 1,3" stroke="#000000" stroke-width="1" stroke-linecap="round" />
        </g>

    </svg>
</div>

<script>
    document.addEventListener("DOMContentLoaded", () => {
        // DOM Elements
        const pathUp = document.getElementById('path-up');
        const pathDown = document.getElementById('path-down');
        const sendBtn = document.getElementById('send-btn');
        const senderBubble = document.getElementById('sender-bubble');
        const receiverBubble = document.getElementById('receiver-bubble');
        const dataPacket = document.getElementById('data-packet');
        const packetTrail = document.getElementById('packet-trail');
        const serverRipple = document.getElementById('server-ripple');
        const msgStatus = document.getElementById('msg-status');
        const notifBadge = document.getElementById('notification-badge');
        const leftSignal = document.getElementById('left-signal');

        const lenUp = pathUp.getTotalLength();
        const lenDown = pathDown.getTotalLength();
        
        const DURATION = 4500; // 动画循环总时长 4.5秒
        let startTime = null;

        // 缓动函数
        const easeOutBack = (t) => {
            const c1 = 1.70158;
            const c3 = c1 + 1;
            return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
        };
        const easeInOutQuad = t => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
        const easeOutExpo = t => t === 1 ? 1 : 1 - Math.pow(2, -10 * t);

        // 获取路径切线角度
        function getAngle(path, length) {
            const p1 = path.getPointAtLength(Math.max(0, length - 1));
            const p2 = path.getPointAtLength(Math.min(path.getTotalLength(), length + 1));
            return Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
        }

        function renderLoop(timestamp) {
            if (!startTime) startTime = timestamp;
            const elapsed = (timestamp - startTime) % DURATION;
            const t = elapsed / DURATION; // 0.0 ~ 1.0

            // 1. 点击发送按钮 (0.00 - 0.05)
            if (t < 0.05) {
                const btnT = t / 0.05;
                const scale = 1 - Math.sin(btnT * Math.PI) * 0.1;
                sendBtn.setAttribute('transform', `translate(-5, 0) scale(${scale})`);
                sendBtn.setAttribute('opacity', 1 - btnT); // 渐隐
            } else if (t >= 0.95) {
                sendBtn.setAttribute('opacity', (t - 0.95) / 0.05); // 循环末尾恢复
            } else {
                sendBtn.setAttribute('opacity', 0);
            }

            // 2. 发送端气泡弹出 (0.05 - 0.15)
            let sBubbleScale = 0;
            if (t > 0.05 && t < 0.15) {
                sBubbleScale = easeOutBack((t - 0.05) / 0.1);
            } else if (t >= 0.15 && t < 0.95) {
                sBubbleScale = 1;
            } else if (t >= 0.95) {
                sBubbleScale = 1 - ((t - 0.95) / 0.05); // 缩小消失
            }
            senderBubble.setAttribute('transform', `scale(${Math.max(0, sBubbleScale)})`);

            // 3. 数据包飞行阶段一：手机 -> 服务器 (0.15 - 0.40)
            // 4. 数据包飞行阶段二：服务器 -> 手机 (0.50 - 0.75)
            let packetVisible = false;
            let px = 0, py = 0, angle = 0;

            if (t >= 0.15 && t < 0.40) {
                packetVisible = true;
                const moveT = easeInOutQuad((t - 0.15) / 0.25);
                const point = pathUp.getPointAtLength(moveT * lenUp);
                px = point.x;
                py = point.y;
                angle = getAngle(pathUp, moveT * lenUp);
                
                // 改变颜色为微信绿
                dataPacket.querySelector('circle').setAttribute('fill', 'var(--wx-green)');
                packetTrail.setAttribute('stroke', 'var(--wx-green)');
                leftSignal.setAttribute('opacity', Math.sin(moveT * Math.PI)); // 信号发射动画
            } 
            else if (t >= 0.50 && t < 0.75) {
                packetVisible = true;
                const moveT = easeInOutQuad((t - 0.50) / 0.25);
                const point = pathDown.getPointAtLength(moveT * lenDown);
                px = point.x;
                py = point.y;
                angle = getAngle(pathDown, moveT * lenDown);
                
                // 经过服务器加密后变成蓝色科技形态
                dataPacket.querySelector('circle').setAttribute('fill', 'var(--tech-blue)');
                packetTrail.setAttribute('stroke', 'var(--tech-blue)');
            } else {
                leftSignal.setAttribute('opacity', 0);
            }

            if (packetVisible) {
                dataPacket.setAttribute('transform', `translate(${px}, ${py}) rotate(${angle}) scale(1)`);
            } else {
                dataPacket.setAttribute('transform', `scale(0)`);
            }

            // 5. 服务器处理反馈 (0.40 - 0.50)
            if (t >= 0.38 && t < 0.55) {
                const srvT = (t - 0.38) / 0.17;
                serverRipple.setAttribute('opacity', 1 - srvT);
                serverRipple.setAttribute('transform', `scale(${1 + srvT * 1.5})`);
            } else {
                serverRipple.setAttribute('opacity', 0);
                serverRipple.setAttribute('transform', `scale(1)`);
            }

            // 6. 接收端气泡弹出 & 通知 (0.75 - 0.85)
            let rBubbleScale = 0;
            if (t > 0.75 && t < 0.85) {
                rBubbleScale = easeOutBack((t - 0.75) / 0.1);
            } else if (t >= 0.85 && t < 0.95) {
                rBubbleScale = 1;
            } else if (t >= 0.95) {
                rBubbleScale = 1 - ((t - 0.95) / 0.05);
            }
            receiverBubble.setAttribute('transform', `scale(${Math.max(0, rBubbleScale)})`);

            // 通知红点闪烁
            if (t > 0.75 && t < 0.95) {
                notifBadge.setAttribute('opacity', 0.8 + Math.sin(t * 50) * 0.2);
            } else {
                notifBadge.setAttribute('opacity', 0);
            }

            // 7. 发送端显示"已送达"状态 (0.80 - 0.95)
            if (t > 0.80 && t < 0.95) {
                const statT = Math.min(1, (t - 0.80) / 0.05);
                msgStatus.setAttribute('opacity', statT);
                msgStatus.setAttribute('transform', `translate(0, ${5 * (1 - statT)})`);
            } else {
                msgStatus.setAttribute('opacity', 0);
            }

            requestAnimationFrame(renderLoop);
        }

        // 启动动画
        requestAnimationFrame(renderLoop);
    });
</script>
</body>
</html>20:T3bbd,<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Tracert 命令运行逻辑动画</title>
    <style>
        :root {
            --bg-color: #0a0e14;
            --panel-color: rgba(20, 26, 35, 0.9);
            --accent-blue: #00d2ff;
            --accent-green: #00ff9d;
            --accent-red: #ff4b2b;
            --text-main: #e0e6ed;
            --text-dim: #718096;
            --font-mono: 'Fira Code', 'JetBrains Mono', 'Courier New', monospace;
        }

        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            background-color: var(--bg-color);
            color: var(--text-main);
            font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
            overflow: hidden;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        #container {
            position: relative;
            width: 1200px;
            height: 700px;
            background: var(--bg-color);
            box-shadow: 0 0 50px rgba(0,0,0,0.5);
            border: 1px solid #2d3748;
            overflow: hidden;
        }

        .svg-layer {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
        }

        /* 终端窗口样式 */
        #terminal {
            position: absolute;
            bottom: 30px;
            left: 50%;
            transform: translateX(-50%);
            width: 1100px;
            height: 180px;
            background: var(--panel-color);
            border: 1px solid #4a5568;
            border-radius: 8px;
            padding: 15px;
            font-family: var(--font-mono);
            font-size: 14px;
            color: var(--accent-green);
            box-shadow: 0 10px 30px rgba(0,0,0,0.5);
            overflow-y: auto;
            scrollbar-width: thin;
        }

        .cursor {
            display: inline-block;
            width: 8px;
            height: 15px;
            background: var(--accent-green);
            animation: blink 1s infinite;
            vertical-align: middle;
        }

        @keyframes blink {
            50% { opacity: 0; }
        }

        /* 顶部标题栏 */
        #header {
            position: absolute;
            top: 20px;
            left: 40px;
            display: flex;
            flex-direction: column;
        }

        #header h1 {
            margin: 0;
            font-size: 24px;
            letter-spacing: 2px;
            color: var(--accent-blue);
            text-transform: uppercase;
        }

        #header p {
            margin: 5px 0 0 0;
            font-size: 14px;
            color: var(--text-dim);
        }

        .step-label {
            font-size: 16px;
            font-weight: bold;
            fill: var(--text-main);
        }

        .node-label {
            font-size: 12px;
            fill: var(--text-dim);
            text-anchor: middle;
        }

        .ttl-badge {
            font-family: var(--font-mono);
            font-weight: bold;
            font-size: 14px;
        }

        /* 科技感动画线条 */
        .path-line {
            fill: none;
            stroke: #2d3748;
            stroke-width: 2;
            stroke-dasharray: 8 4;
        }

        .path-active {
            stroke: var(--accent-blue);
            stroke-width: 3;
            stroke-dasharray: 1000;
            stroke-dashoffset: 1000;
        }

        @keyframes dash {
            to { stroke-dashoffset: 0; }
        }
    </style>
</head>
<body>

<div id="container">
    <!-- 背景装饰网格 -->
    <svg class="svg-layer" viewBox="0 0 1200 700">
        <defs>
            <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
                <path d="M 40 0 L 0 0 0 40" fill="none" stroke="#1a202c" stroke-width="1"/>
            </pattern>
            <filter id="glow">
                <feGaussianBlur stdDeviation="3" result="coloredBlur"/>
                <feMerge>
                    <feMergeNode in="coloredBlur"/>
                    <feMergeNode in="SourceGraphic"/>
                </feMerge>
            </filter>
            
            <!-- 图标定义 -->
            <symbol id="icon-pc" viewBox="0 0 24 24">
                <path fill="currentColor" d="M20,18H4V4H20M20,2H4C2.89,2 2,2.89 2,4V16A2,2 0 0,0 4,18H9L7.5,20.5V22H16.5V20.5L15,18H20A2,2 0 0,0 22,16V4C22,2.89 21.1,2 20,2Z" />
            </symbol>
            <symbol id="icon-router" viewBox="0 0 24 24">
                <path fill="currentColor" d="M20,13H4V11H20M20,17H4V15H20M20,7H4V5H20M22,3H2V21H22V3Z" />
            </symbol>
            <symbol id="icon-server" viewBox="0 0 24 24">
                <path fill="currentColor" d="M19,15H5V13H19M19,19H5V17H19M19,11H5V9H19M5,7V5H19V7H5M21,3H3V21H21V3Z" />
            </symbol>
        </defs>
        <rect width="100%" height="100%" fill="url(#grid)" />

        <!-- 节点连线 -->
        <g id="connections"></g>

        <!-- 节点 -->
        <g id="nodes">
            <!-- 源主机 -->
            <g transform="translate(100, 320)" id="node-source">
                <use href="#icon-pc" x="-25" y="-25" width="50" height="50" style="color: var(--accent-blue); filter: url(#glow);"/>
                <text y="45" class="node-label">源主机 (Client)</text>
                <text y="60" class="node-label" style="font-size:10px">192.168.1.10</text>
            </g>

            <!-- 路由器 1 -->
            <g transform="translate(350, 320)" id="node-r1">
                <use href="#icon-router" x="-20" y="-20" width="40" height="40" style="color: var(--text-dim);"/>
                <text y="40" class="node-label">跃点 1</text>
                <text y="55" class="node-label" style="font-size:10px">10.0.0.1</text>
            </g>

            <!-- 路由器 2 -->
            <g transform="translate(600, 320)" id="node-r2">
                <use href="#icon-router" x="-20" y="-20" width="40" height="40" style="color: var(--text-dim);"/>
                <text y="40" class="node-label">跃点 2</text>
                <text y="55" class="node-label" style="font-size:10px">20.0.0.5</text>
            </g>

            <!-- 路由器 3 -->
            <g transform="translate(850, 320)" id="node-r3">
                <use href="#icon-router" x="-20" y="-20" width="40" height="40" style="color: var(--text-dim);"/>
                <text y="40" class="node-label">跃点 3</text>
                <text y="55" class="node-label" style="font-size:10px">30.0.0.8</text>
            </g>

            <!-- 目标服务器 -->
            <g transform="translate(1100, 320)" id="node-target">
                <use href="#icon-server" x="-25" y="-25" width="50" height="50" style="color: var(--accent-green);"/>
                <text y="45" class="node-label">目标服务器</text>
                <text y="60" class="node-label" style="font-size:10px">8.8.8.8</text>
            </g>
        </g>

        <!-- 动画元素：数据包 -->
        <g id="packet-layer"></g>

        <!-- 步骤提示文字 -->
        <text id="step-description" x="600" y="80" text-anchor="middle" class="step-label" fill="var(--accent-blue)">准备执行 Tracert 命令...</text>
    </svg>

    <div id="header">
        <h1>Tracert 运行逻辑可视化</h1>
        <p>ICMP 生存时间 (TTL) 机制演示</p>
    </div>

    <div id="terminal">
        <div>C:\Users\Admin&gt; <span id="command-text"></span><span class="cursor"></span></div>
        <div id="log-content"></div>
    </div>
</div>

<script>
    const CONFIG = {
        nodes: [
            { id: 'source', x: 100, y: 320, ip: '192.168.1.10' },
            { id: 'r1', x: 350, y: 320, ip: '10.0.0.1' },
            { id: 'r2', x: 600, y: 320, ip: '20.0.0.5' },
            { id: 'r3', x: 850, y: 320, ip: '30.0.0.8' },
            { id: 'target', x: 1100, y: 320, ip: '8.8.8.8' }
        ],
        packetColor: '#00d2ff',
        errorColor: '#ff4b2b',
        successColor: '#00ff9d'
    };

    const terminal = document.getElementById('log-content');
    const stepDesc = document.getElementById('step-description');
    const packetLayer = document.getElementById('packet-layer');
    const commandText = document.getElementById('command-text');

    async function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    function addLog(text, color = 'var(--accent-green)') {
        const div = document.createElement('div');
        div.style.color = color;
        div.style.marginTop = '2px';
        div.innerHTML = text;
        terminal.appendChild(div);
        terminal.scrollTop = terminal.scrollHeight;
    }

    async function typeCommand(text) {
        for (let i = 0; i <= text.length; i++) {
            commandText.textContent = text.slice(0, i);
            await sleep(50);
        }
        await sleep(500);
    }

    function createPacket(x, y, ttl, color) {
        const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
        g.setAttribute('transform', `translate(${x}, ${y})`);
        
        const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
        circle.setAttribute('r', '8');
        circle.setAttribute('fill', color);
        circle.setAttribute('filter', 'url(#glow)');
        
        const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
        text.setAttribute('y', '-15');
        text.setAttribute('text-anchor', 'middle');
        text.setAttribute('class', 'ttl-badge');
        text.setAttribute('fill', color);
        text.textContent = `TTL=${ttl}`;
        
        g.appendChild(circle);
        g.appendChild(text);
        packetLayer.appendChild(g);
        return g;
    }

    async function movePacket(packet, startNodeIdx, endNodeIdx, duration) {
        const start = CONFIG.nodes[startNodeIdx];
        const end = CONFIG.nodes[endNodeIdx];
        const startTime = performance.now();

        return new Promise(resolve => {
            function animate(time) {
                let progress = (time - startTime) / duration;
                if (progress > 1) progress = 1;
                
                const currentX = start.x + (end.x - start.x) * progress;
                const currentY = start.y + (end.y - start.y) * progress;
                packet.setAttribute('transform', `translate(${currentX}, ${currentY})`);
                
                if (progress < 1) {
                    requestAnimationFrame(animate);
                } else {
                    resolve();
                }
            }
            requestAnimationFrame(animate);
        });
    }

    async function runTracert() {
        // 1. 初始化
        await typeCommand('tracert 8.8.8.8');
        addLog('通过最多 30 个跃点跟踪到 8.8.8.8 的路由:', 'var(--text-main)');
        await sleep(1000);

        // 循环每一跳
        for (let hop = 1; hop <= 4; hop++) {
            const isTarget = hop === 4;
            const ttl = hop;
            stepDesc.textContent = `步骤 ${hop}: 发送 TTL=${ttl} 的数据包`;
            stepDesc.setAttribute('fill', CONFIG.packetColor);

            // 发送包
            const p = createPacket(CONFIG.nodes[0].x, CONFIG.nodes[0].y, ttl, CONFIG.packetColor);
            
            // 沿途经过路由器
            for (let currentPos = 0; currentPos < hop; currentPos++) {
                await movePacket(p, currentPos, currentPos + 1, 600);
                if (currentPos + 1 < hop) {
                    // TTL 递减动画
                    const newTTL = ttl - (currentPos + 1);
                    p.querySelector('text').textContent = `TTL=${newTTL}`;
                    // 闪烁一下表示处理
                    p.querySelector('circle').setAttribute('fill', '#fff');
                    await sleep(100);
                    p.querySelector('circle').setAttribute('fill', CONFIG.packetColor);
                }
            }

            // 到达目标点（TTL变为0或到达目的地）
            await sleep(300);
            
            if (!isTarget) {
                // 路由器返回 ICMP Time Exceeded
                stepDesc.textContent = `跃点 ${hop} (${CONFIG.nodes[hop].ip}): TTL 耗尽，返回 ICMP Time Exceeded`;
                stepDesc.setAttribute('fill', CONFIG.errorColor);
                p.querySelector('circle').setAttribute('fill', CONFIG.errorColor);
                p.querySelector('text').textContent = 'Time Exceeded';
                p.querySelector('text').setAttribute('fill', CONFIG.errorColor);
                
                // 高亮当前路由器
                const routerIcon = document.querySelector(`#node-r${hop} use`);
                routerIcon.style.color = CONFIG.packetColor;
                routerIcon.style.filter = 'url(#glow)';

                await sleep(500);
                // 返回源主机
                await movePacket(p, hop, 0, 800);
                addLog(`&nbsp;&nbsp;${hop}&nbsp;&nbsp;&nbsp;&nbsp;1 ms&nbsp;&nbsp;&nbsp;&nbsp;1 ms&nbsp;&nbsp;&nbsp;&nbsp;1 ms&nbsp;&nbsp;${CONFIG.nodes[hop].ip}`);
            } else {
                // 到达目标服务器返回 ICMP Echo Reply
                stepDesc.textContent = `目标已到达: 8.8.8.8 返回 ICMP Echo Reply`;
                stepDesc.setAttribute('fill', CONFIG.successColor);
                p.querySelector('circle').setAttribute('fill', CONFIG.successColor);
                p.querySelector('text').textContent = 'Echo Reply';
                p.querySelector('text').setAttribute('fill', CONFIG.successColor);

                const targetIcon = document.querySelector(`#node-target use`);
                targetIcon.style.color = CONFIG.successColor;
                targetIcon.style.filter = 'url(#glow)';

                await sleep(500);
                await movePacket(p, 4, 0, 800);
                addLog(`&nbsp;&nbsp;${hop}&nbsp;&nbsp;&nbsp;&nbsp;2 ms&nbsp;&nbsp;&nbsp;&nbsp;1 ms&nbsp;&nbsp;&nbsp;&nbsp;2 ms&nbsp;&nbsp;${CONFIG.nodes[hop].ip}`);
            }

            packetLayer.removeChild(p);
            await sleep(800);
        }

        stepDesc.textContent = "跟踪完成。所有路径节点已识别。";
        stepDesc.setAttribute('fill', CONFIG.successColor);
        addLog('<br>跟踪完成。', 'var(--text-main)');
        
        await sleep(5000);
        location.reload(); // 循环演示
    }

    // 初始化连线
    function initLines() {
        const connGroup = document.getElementById('connections');
        for (let i = 0; i < CONFIG.nodes.length - 1; i++) {
            const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
            line.setAttribute('x1', CONFIG.nodes[i].x);
            line.setAttribute('y1', CONFIG.nodes[i].y);
            line.setAttribute('x2', CONFIG.nodes[i+1].x);
            line.setAttribute('y2', CONFIG.nodes[i+1].y);
            line.setAttribute('class', 'path-line');
            connGroup.appendChild(line);
        }
    }

    window.onload = () => {
        initLines();
        runTracert();
    };
</script>

</body>
</html>21:T2c80,<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>高级数据加载系统 - Data Sync</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
    <script src="https://unpkg.com/lucide@latest"></script>
    <style>
        :root {
            --bg: #0F172A;
            --primary: #38BDF8;
            --secondary: #1E293B;
            --accent: #818CF8;
            --glass: rgba(30, 41, 59, 0.7);
            --text-main: #F8FAFC;
            --text-dim: #94A3B8;
        }

        body, html {
            margin: 0; padding: 0; width: 100%; height: 100%;
            background-color: var(--bg);
            color: var(--text-main);
            font-family: 'Inter', system-ui, -apple-system, sans-serif;
            overflow: hidden;
            display: flex; align-items: center; justify-content: center;
        }

        #container {
            width: 100vw; height: 100vh;
            max-width: 1200px; max-height: 700px;
            position: relative;
            display: flex; flex-direction: column;
            align-items: center; justify-content: center;
        }

        .svg-layer {
            position: absolute;
            top: 0; left: 0;
            width: 100%; height: 100%;
            pointer-events: none;
        }

        /* 磨砂玻璃面板 */
        .glass-panel {
            background: var(--glass);
            backdrop-filter: blur(12px);
            -webkit-backdrop-filter: blur(12px);
            border: 1px solid rgba(255, 255, 255, 0.1);
            border-radius: 16px;
            padding: 20px 40px;
            box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
            z-index: 10;
            display: flex; flex-direction: column;
            align-items: center;
            min-width: 300px;
            margin-top: 350px;
        }

        .status-text {
            font-size: 14px;
            color: var(--text-dim);
            letter-spacing: 2px;
            text-transform: uppercase;
            margin-bottom: 8px;
        }

        .percentage {
            font-size: 48px;
            font-weight: 800;
            background: linear-gradient(to right, var(--primary), var(--accent));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            font-variant-numeric: tabular-nums;
        }

        .loading-bar-container {
            width: 100%; height: 4px;
            background: var(--secondary);
            border-radius: 2px;
            margin-top: 15px;
            overflow: hidden;
        }

        .loading-bar-fill {
            width: 0%; height: 100%;
            background: linear-gradient(90deg, var(--primary), var(--accent));
            box-shadow: 0 0 10px var(--primary);
        }

        /* 底部信息栏 */
        .info-footer {
            position: absolute;
            bottom: 40px;
            display: flex;
            gap: 40px;
            color: var(--text-dim);
            font-size: 12px;
            font-family: monospace;
        }

        .info-item { display: flex; align-items: center; gap: 8px; }
        .info-item i { width: 14px; height: 14px; color: var(--primary); }

        /* 装饰性网格 */
        .grid-bg {
            position: absolute;
            width: 100%; height: 100%;
            background-image: 
                radial-gradient(circle at 2px 2px, rgba(56, 189, 248, 0.05) 1px, transparent 0);
            background-size: 40px 40px;
            z-index: -1;
        }
    </style>
</head>
<body>

<div class="grid-bg"></div>

<div id="container">
    <svg class="svg-layer" viewBox="0 0 1200 700">
        <defs>
            <filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
                <feGaussianBlur stdDeviation="5" result="blur" />
                <feComposite in="SourceGraphic" in2="blur" operator="over" />
            </filter>
            <filter id="soft-glow" x="-50%" y="-50%" width="200%" height="200%">
                <feGaussianBlur stdDeviation="15" result="blur" />
            </filter>
            <radialGradient id="coreGradient">
                <stop offset="0%" stop-color="#38BDF8" stop-opacity="0.8" />
                <stop offset="100%" stop-color="#38BDF8" stop-opacity="0" />
            </radialGradient>
            <linearGradient id="ringGradient" x1="0%" y1="0%" x2="100%" y2="0%">
                <stop offset="0%" stop-color="var(--primary)" />
                <stop offset="100%" stop-color="var(--accent)" />
            </linearGradient>
        </defs>

        <!-- 背景极光效果 -->
        <circle cx="600" cy="300" r="150" fill="url(#coreGradient)" filter="url(#soft-glow)" id="breathing-light" opacity="0.3" />

        <!-- 粒子流向中心 -->
        <g id="particles"></g>

        <!-- 主加载圆环组 -->
        <g transform="translate(600, 300)">
            <!-- 外部虚线圈 -->
            <circle r="140" fill="none" stroke="#1E293B" stroke-width="1" stroke-dasharray="4 8" />
            
            <!-- 旋转的外环 -->
            <circle id="outer-ring" r="120" fill="none" stroke="url(#ringGradient)" stroke-width="4" stroke-dasharray="100 400" stroke-linecap="round" filter="url(#glow)" />
            
            <!-- 逆向旋转的中环 -->
            <circle id="mid-ring" r="95" fill="none" stroke="var(--accent)" stroke-width="2" stroke-dasharray="150 200" stroke-linecap="round" opacity="0.6" />
            
            <!-- 快速旋转的小环 -->
            <circle id="inner-ring" r="70" fill="none" stroke="var(--primary)" stroke-width="8" stroke-dasharray="1 30" stroke-linecap="round" />

            <!-- 中心核心 -->
            <circle id="core-circle" r="40" fill="var(--secondary)" stroke="var(--primary)" stroke-width="1" />
            <g id="core-icon" transform="translate(-12, -12)">
                <!-- Lucide icon placeholder -->
                <path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" fill="none" stroke="var(--primary)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
            </g>
        </g>
    </svg>

    <!-- UI 面板 -->
    <div class="glass-panel">
        <div class="status-text" id="status-label">正在初始化系统资源...</div>
        <div class="percentage" id="percent-text">0%</div>
        <div class="loading-bar-container">
            <div class="loading-bar-fill" id="progress-fill"></div>
        </div>
    </div>

    <!-- 底部技术参数 -->
    <div class="info-footer">
        <div class="info-item"><i data-lucide="cpu"></i> ENGINE: NEURAL_CORE_V4</div>
        <div class="info-item"><i data-lucide="zap"></i> SPEED: <span id="speed-val">124.5</span> MB/S</div>
        <div class="info-item"><i data-lucide="shield-check"></i> STATUS: ENCRYPTED</div>
        <div class="info-item"><i data-lucide="database"></i> PACKETS: <span id="packet-val">1024</span>/4096</div>
    </div>
</div>

<script>
    // 初始化 Lucide 图标
    lucide.createIcons();

    const config = {
        totalSteps: 100,
        statusMessages: [
            "正在建立安全连接...",
            "正在同步核心数据库...",
            "正在解析加密协议...",
            "优化数据传输路径...",
            "正在验证数据完整性...",
            "正在完成系统部署..."
        ]
    };

    // 1. 初始化粒子背景
    const particlesGroup = document.getElementById('particles');
    const particleCount = 40;
    for (let i = 0; i < particleCount; i++) {
        const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
        const angle = Math.random() * Math.PI * 2;
        const dist = 300 + Math.random() * 300;
        const x = 600 + Math.cos(angle) * dist;
        const y = 300 + Math.sin(angle) * dist;
        
        circle.setAttribute("cx", x);
        circle.setAttribute("cy", y);
        circle.setAttribute("r", Math.random() * 2 + 1);
        circle.setAttribute("fill", Math.random() > 0.5 ? "#38BDF8" : "#818CF8");
        circle.setAttribute("opacity", Math.random() * 0.5 + 0.2);
        particlesGroup.appendChild(circle);

        // 粒子移动动画
        gsap.to(circle, {
            cx: 600,
            cy: 300,
            opacity: 0,
            duration: 2 + Math.random() * 3,
            repeat: -1,
            ease: "power1.in",
            delay: Math.random() * 5
        });
    }

    // 2. 主循环与旋转动画 (仅启动一次)
    gsap.to("#outer-ring", { rotation: 360, duration: 4, transformOrigin: "center", repeat: -1, ease: "none" });
    gsap.to("#mid-ring", { rotation: -360, duration: 6, transformOrigin: "center", repeat: -1, ease: "none" });
    gsap.to("#inner-ring", { rotation: 360, duration: 1.5, transformOrigin: "center", repeat: -1, ease: "none" });
    
    // 呼吸灯效果
    gsap.to("#breathing-light", {
        r: 180,
        opacity: 0.6,
        duration: 2,
        repeat: -1,
        yoyo: true,
        ease: "sine.inOut"
    });

    // 核心微动交互
    gsap.to("#core-circle", {
        strokeWidth: 4,
        duration: 1,
        repeat: -1,
        yoyo: true,
        ease: "power2.inOut"
    });

    // 3. 进度逻辑
    let progress = 0;
    const percentText = document.getElementById('percent-text');
    const progressFill = document.getElementById('progress-fill');
    const statusLabel = document.getElementById('status-label');
    const speedVal = document.getElementById('speed-val');
    const packetVal = document.getElementById('packet-val');

    function updateProgress() {
        if (progress < 100) {
            // 模拟非线性加载
            const increment = Math.random() * 1.5;
            progress = Math.min(100, progress + increment);
            
            // 更新 UI
            percentText.innerText = `${Math.floor(progress)}%`;
            progressFill.style.width = `${progress}%`;

            // 更新状态文本
            const msgIndex = Math.floor((progress / 100) * config.statusMessages.length);
            if (statusLabel.innerText !== config.statusMessages[msgIndex] && config.statusMessages[msgIndex]) {
                gsap.fromTo(statusLabel, { opacity: 0, y: 5 }, { opacity: 1, y: 0, duration: 0.5 });
                statusLabel.innerText = config.statusMessages[msgIndex];
            }

            // 更新随机参数
            speedVal.innerText = (120 + Math.random() * 40).toFixed(1);
            packetVal.innerText = Math.floor((progress/100) * 4096);

            requestAnimationFrame(updateProgress);
        } else {
            // 加载完成效果
            statusLabel.innerText = "系统就绪 (SYSTEM READY)";
            statusLabel.style.color = "#10B981";
            percentText.innerText = "100%";
            gsap.to(".glass-panel", { boxShadow: "0 0 40px rgba(16, 185, 129, 0.4)", duration: 1 });
            
            // 核心爆发动画
            gsap.to("#core-circle", { r: 1000, opacity: 0, duration: 1.5, ease: "power4.out" });
        }
    }

    // 延迟一点开始加载
    setTimeout(() => {
        requestAnimationFrame(updateProgress);
    }, 1000);

</script>
</body>
</html>22:T48bd,'use client';

import React, { useState, useEffect, useRef, useMemo } from 'react';

// --- Constants & Helper Functions ---
const WIDTH = 1200;
const HEIGHT = 675; // 16:9 Aspect Ratio
const GROUND_Y = 550;
const FPS = 60;

// Color Palette
const COLORS = {
  bg: '#0f172a',
  blue: '#38bdf8',
  blueGlow: '#0ea5e9',
  red: '#f43f5e',
  redGlow: '#e11d48',
  white: '#ffffff',
  text: 'rgba(255, 255, 255, 0.8)',
  grid: 'rgba(56, 189, 248, 0.1)',
};

// Math Helpers
const lerp = (start, end, t) => start * (1 - t) + end * t;
const randomRange = (min, max) => Math.random() * (max - min) + min;

// Stickman Component
const Stickman = ({ x, y, color, scale = 1, pose, opacity = 1, isGlitch = false }) => {
  // Default pose structure: [headX, headY, bodyEnd, elbowL, handL, elbowR, handR, kneeL, footL, kneeR, footR]
  // All relative to center x, y
  
  // Basic IK-ish mapping based on pose name
  const getPoseOffsets = (p) => {
    switch (p) {
      case 'idle':
        return { h: [0, -50], b: [0, 0], el: [-20, -25], hl: [-30, 10], er: [20, -25], hr: [30, 10], kl: [-15, 25], fl: [-20, 50], kr: [15, 25], fr: [20, 50] };
      case 'run':
        return { h: [10, -45], b: [0, 0], el: [-30, -20], hl: [20, -30], er: [20, -20], hr: [-20, -30], kl: [-10, 20], fl: [-30, 40], kr: [20, 15], fr: [40, 35] };
      case 'cast': // Casting spell/shield
        return { h: [0, -50], b: [0, 0], el: [-30, -35], hl: [-50, -50], er: [30, -35], hr: [50, -50], kl: [-20, 30], fl: [-25, 60], kr: [20, 30], fr: [25, 60] };
      case 'block': // Blocking
        return { h: [-5, -45], b: [0, 0], el: [20, -30], hl: [40, -10], er: [10, -20], hr: [40, 10], kl: [-20, 30], fl: [-30, 60], kr: [10, 30], fr: [20, 60] };
      case 'float': // Floating/God mode
        return { h: [0, -55], b: [0, -5], el: [-35, -25], hl: [-55, -10], er: [35, -25], hr: [55, -10], kl: [-10, 20], fl: [-15, 45], kr: [10, 25], fr: [15, 50] };
      case 'punch': 
        return { h: [15, -45], b: [10, 0], el: [0, -25], hl: [-20, 0], er: [40, -35], hr: [80, -35], kl: [-20, 25], fl: [-40, 55], kr: [30, 25], fr: [50, 55] };
      default:
        return { h: [0, -50], b: [0, 0], el: [-20, -25], hl: [-30, 10], er: [20, -25], hr: [30, 10], kl: [-15, 25], fl: [-20, 50], kr: [15, 25], fr: [20, 50] };
    }
  };

  const o = getPoseOffsets(pose);
  const s = scale;

  // Apply jitter for glitch effect
  const jX = () => isGlitch ? (Math.random() - 0.5) * 10 : 0;
  const jY = () => isGlitch ? (Math.random() - 0.5) * 10 : 0;

  return (
    <g transform={`translate(${x}, ${y})`} opacity={opacity}>
      {/* Glow */}
      <defs>
        <filter id={`glow-${color}`}>
          <feGaussianBlur stdDeviation="3.5" result="coloredBlur" />
          <feMerge>
            <feMergeNode in="coloredBlur" />
            <feMergeNode in="SourceGraphic" />
          </feMerge>
        </filter>
      </defs>
      
      <g stroke={color} strokeWidth={4 * s} fill="none" strokeLinecap="round" strokeLinejoin="round" filter={`url(#glow-${color})`}>
        {/* Head */}
        <circle cx={o.h[0] * s + jX()} cy={o.h[1] * s + jY()} r={12 * s} fill={COLORS.bg} />
        {/* Body */}
        <path d={`M${o.h[0] * s + jX()} ${o.h[1] * s + 12 * s + jY()} L${o.b[0] * s + jX()} ${o.b[1] * s + jY()}`} strokeWidth={6 * s} />
        {/* Arms */}
        <path d={`M${o.h[0] * s} ${o.h[1] * s + 15 * s} L${o.el[0] * s + jX()} ${o.el[1] * s + jY()} L${o.hl[0] * s + jX()} ${o.hl[1] * s + jY()}`} />
        <path d={`M${o.h[0] * s} ${o.h[1] * s + 15 * s} L${o.er[0] * s + jX()} ${o.er[1] * s + jY()} L${o.hr[0] * s + jX()} ${o.hr[1] * s + jY()}`} />
        {/* Legs */}
        <path d={`M${o.b[0] * s} ${o.b[1] * s} L${o.kl[0] * s + jX()} ${o.kl[1] * s + jY()} L${o.fl[0] * s + jX()} ${o.fl[1] * s + jY()}`} />
        <path d={`M${o.b[0] * s} ${o.b[1] * s} L${o.kr[0] * s + jX()} ${o.kr[1] * s + jY()} L${o.fr[0] * s + jX()} ${o.fr[1] * s + jY()}`} />
      </g>
    </g>
  );
};

// --- Main Animation Component ---

export default function EpicStickmanBattle() {
  // State for animation timeline
  const [frame, setFrame] = useState(0);
  const totalFrames = 1300; // ~21 seconds loop

  // Particles & Effects State
  const [particles, setParticles] = useState([]);
  const [cameraShake, setCameraShake] = useState({ x: 0, y: 0 });

  // Refs for performance
  const reqRef = useRef();
  
  // Animation Loop
  useEffect(() => {
    const animate = () => {
      setFrame(f => {
        if (f >= totalFrames) return 0;
        return f + 1;
      });
      reqRef.current = requestAnimationFrame(animate);
    };
    reqRef.current = requestAnimationFrame(animate);
    return () => cancelAnimationFrame(reqRef.current);
  }, []);

  // --- Derived Animation Logic ---

  // Phase Definitions
  // 0-100: Intro & Dash
  // 100-150: Clash
  // 150-300: Laser (Red) vs Shield (Blue)
  // 300-450: Telekinesis (Blue throws rocks)
  // 450-650: Time Stop & Giant (Red)
  // 650-850: Thousand Swords (Blue)
  // 850-1000: Black Hole & Climax
  // 1000-1300: Reset

  const phase = useMemo(() => {
    if (frame < 100) return 'DASH';
    if (frame < 150) return 'CLASH';
    if (frame < 300) return 'LASER_SHIELD';
    if (frame < 450) return 'TELEKINESIS';
    if (frame < 650) return 'TIME_STOP_GIANT';
    if (frame < 850) return 'THOUSAND_SWORDS';
    if (frame < 1000) return 'BLACK_HOLE';
    return 'RESET';
  }, [frame]);

  // Character Positions & Poses
  const blue = useMemo(() => {
    let x = 200, y = GROUND_Y, pose = 'idle', scale = 1, opacity = 1;
    
    if (phase === 'DASH') {
      x = lerp(200, 500, frame / 100);
      pose = 'run';
    } else if (phase === 'CLASH') {
      x = 500 - (frame - 100) * 2; // Knockback slightly
      pose = 'block';
    } else if (phase === 'LASER_SHIELD') {
      x = 400;
      pose = 'block';
    } else if (phase === 'TELEKINESIS') {
      x = 300;
      y = GROUND_Y - 50 - Math.sin(frame * 0.05) * 20; // Float
      pose = 'cast';
    } else if (phase === 'TIME_STOP_GIANT') {
      x = 300;
      if (frame > 500 && frame < 600) opacity = 0.5; // Frozen/Greyed
      pose = frame > 600 ? 'block' : 'idle';
    } else if (phase === 'THOUSAND_SWORDS') {
      x = 200;
      y = GROUND_Y - 100;
      pose = 'float';
    } else if (phase === 'BLACK_HOLE') {
      x = lerp(200, 600, (frame - 850) / 150); // Sucked in
      y = lerp(GROUND_Y - 100, 337, (frame - 850) / 150);
      scale = lerp(1, 0, (frame - 850) / 150);
      pose = 'run';
    } else {
      opacity = 0; // Reset
    }
    return { x, y, pose, scale, opacity };
  }, [frame, phase]);

  const red = useMemo(() => {
    let x = 1000, y = GROUND_Y, pose = 'idle', scale = 1, opacity = 1, isGlitch = false;

    if (phase === 'DASH') {
      x = lerp(1000, 700, frame / 100);
      pose = 'run';
    } else if (phase === 'CLASH') {
      x = 700 + (frame - 100) * 2;
      pose = 'punch';
    } else if (phase === 'LASER_SHIELD') {
      x = 800;
      pose = 'cast';
    } else if (phase === 'TELEKINESIS') {
      x = 900;
      pose = 'block';
      if (frame > 400) x += (Math.random() - 0.5) * 20; // Hit by rocks
    } else if (phase === 'TIME_STOP_GIANT') {
      if (frame < 480) { // Time Stop init
         isGlitch = true;
         x = 900;
      } else { // Giant grow
         x = 900;
         const growFactor = Math.min((frame - 480) / 50, 1);
         scale = 1 + growFactor * 3; // 4x size
         pose = frame > 580 ? 'punch' : 'cast';
      }
    } else if (phase === 'THOUSAND_SWORDS') {
      x = 900;
      scale = 4;
      pose = 'block';
      if (frame > 750) opacity = lerp(1, 0, (frame - 750) / 100); // Defeated
    } else if (phase === 'BLACK_HOLE') {
       // Re-appears for finale
       opacity = 1;
       scale = 1;
       x = lerp(1000, 600, (frame - 850) / 150);
       y = lerp(GROUND_Y, 337, (frame - 850) / 150);
       scale = lerp(1, 0, (frame - 850) / 150);
    } else {
      opacity = 0;
    }
    return { x, y, pose, scale, opacity, isGlitch };
  }, [frame, phase]);

  // Camera Shake Calculation
  useEffect(() => {
    let shake = 0;
    if (phase === 'CLASH') shake = 5;
    if (phase === 'LASER_SHIELD') shake = 2;
    if (phase === 'TIME_STOP_GIANT' && frame > 580 && frame < 620) shake = 15; // Giant smash
    if (phase === 'BLACK_HOLE') shake = 8;

    if (shake > 0) {
      setCameraShake({
        x: (Math.random() - 0.5) * shake,
        y: (Math.random() - 0.5) * shake
      });
    } else {
      setCameraShake({ x: 0, y: 0 });
    }
  }, [frame, phase]);

  // --- Particle/Effect Generators ---
  
  // Laser Beam
  const renderLaser = () => {
    if (phase !== 'LASER_SHIELD') return null;
    const charge = Math.min((frame - 150) / 30, 1);
    const fire = frame > 180;
    
    if (!fire) {
      // Charging Sphere
      return (
        <circle cx={red.x - 50} cy={red.y - 50} r={charge * 30} fill={COLORS.red} filter={`url(#glow-${COLORS.red})`} opacity={0.8} />
      );
    }
    
    // Firing
    return (
      <g>
        <path d={`M${red.x - 50} ${red.y - 50} L${blue.x + 40} ${blue.y - 30}`} stroke={COLORS.red} strokeWidth={20} opacity={0.6} filter={`url(#glow-${COLORS.red})`} />
        <path d={`M${red.x - 50} ${red.y - 50} L${blue.x + 40} ${blue.y - 30}`} stroke={COLORS.white} strokeWidth={8} />
        {/* Impact Flare */}
        <circle cx={blue.x + 40} cy={blue.y - 30} r={40 + Math.random() * 10} fill={COLORS.red} opacity={0.5} />
      </g>
    );
  };

  // Blue Shield
  const renderShield = () => {
    if (phase !== 'LASER_SHIELD') return null;
    if (frame < 170) return null;
    
    return (
      <g transform={`translate(${blue.x + 40}, ${blue.y - 30})`}>
         <defs>
            <pattern id="hexPattern" width="20" height="20" patternUnits="userSpaceOnUse" patternTransform="rotate(30)">
               <path d="M10 0 L20 10 L10 20 L0 10 Z" fill="none" stroke={COLORS.blue} strokeWidth="1" opacity="0.5"/>
            </pattern>
         </defs>
         <path d="M0 -60 Q30 0 0 60" stroke={COLORS.blue} strokeWidth="4" fill="none" filter={`url(#glow-${COLORS.blue})`} />
         <path d="M5 -50 Q25 0 5 50" stroke={COLORS.blue} strokeWidth="2" fill="url(#hexPattern)" opacity="0.6" />
      </g>
    );
  };

  // Floating Rocks (Telekinesis)
  const renderRocks = () => {
    if (phase !== 'TELEKINESIS') return null;
    
    const rockCount = 5;
    const rocks = [];
    for(let i = 0; i < rockCount; i++) {
        // Simple procedural animation for rocks
        let rx = blue.x + 50 + i * 30;
        let ry = blue.y + 50;
        
        // Lift up
        if (frame > 300 && frame < 360) {
            ry -= (frame - 300) * 1.5 + (i * 10);
        } else if (frame >= 360) {
            // Throw
            const t = frame - 360;
            rx += t * 15;
            ry = blue.y - 100 + (t * t * 0.1); // Gravity
        }

        if (rx < WIDTH) {
            rocks.push(
                <g key={i} transform={`translate(${rx}, ${ry}) rotate(${frame * 5})`}>
                    <path d="M-10 -10 L10 -5 L5 10 L-15 5 Z" fill="#475569" stroke={COLORS.blue} strokeWidth="2" />
                </g>
            );
        }
    }
    return rocks;
  };

  // Thousand Swords
  const renderSwords = () => {
    if (phase !== 'THOUSAND_SWORDS') return null;
    
    const count = 12;
    const swords = [];
    const radius = 120;
    
    for(let i = 0; i < count; i++) {
        const angle = (i / count) * Math.PI * 2 + (frame * 0.02);
        
        // Spawn/Rotate
        let sx = blue.x + Math.cos(angle) * radius;
        let sy = blue.y - 50 + Math.sin(angle) * radius;
        let rotation = (angle * 180 / Math.PI) + 90;

        // Fire logic
        if (frame > 720) {
            const targetX = red.x;
            const targetY = red.y - 150; // Aim for chest of Giant
            const progress = Math.min((frame - 720 - (i * 5)) / 20, 1); // Staggered fire
            
            if (progress > 0) {
                sx = lerp(sx, targetX, progress);
                sy = lerp(sy, targetY, progress);
                // Point towards target
                const dx = targetX - sx;
                const dy = targetY - sy;
                rotation = Math.atan2(dy, dx) * 180 / Math.PI;
            }
        }

        swords.push(
            <g key={i} transform={`translate(${sx}, ${sy}) rotate(${rotation})`}>
                <path d="M-40 0 L40 0 M20 -5 L40 0 L20 5" stroke={COLORS.blue} strokeWidth="3" filter={`url(#glow-${COLORS.blue})`} />
                <path d="M-40 0 L40 0" stroke="white" strokeWidth="1" />
            </g>
        );
    }
    return swords;
  };

  // Black Hole
  const renderBlackHole = () => {
      if (phase !== 'BLACK_HOLE') return null;
      const size = Math.min((frame - 850) * 2, 200);
      
      return (
          <g transform={`translate(${WIDTH/2}, ${HEIGHT/2})`}>
              <circle r={size} fill="black" />
              <circle r={size + 10} fill="none" stroke="white" strokeWidth="2" strokeDasharray="10 10" opacity="0.5">
                  <animateTransform attributeName="transform" type="rotate" from="0" to="360" dur="2s" repeatCount="indefinite" />
              </circle>
              {/* Accretion Disk */}
              <ellipse rx={size * 2} ry={size * 0.4} fill="none" stroke={COLORS.red} strokeWidth="5" opacity="0.7" filter={`url(#glow-${COLORS.red})`}>
                 <animateTransform attributeName="transform" type="rotate" from="0" to="360" dur="1s" repeatCount="indefinite" />
              </ellipse>
              {/* Event Horizon text */}
              <text y={-size - 20} textAnchor="middle" fill={COLORS.white} fontSize="14" style={{letterSpacing: 4}}>EVENT HORIZON DETECTED</text>
          </g>
      );
  };

  // Time Stop Filter
  const timeStopFilter = phase === 'TIME_STOP_GIANT' && frame < 600 ? 'grayscale(100%) contrast(150%)' : 'none';
  const timeStopOverlay = phase === 'TIME_STOP_GIANT' && frame < 500 ? (
      <rect width={WIDTH} height={HEIGHT} fill={COLORS.white} opacity={Math.random() * 0.1} style={{mixBlendMode: 'difference'}} />
  ) : null;

  // --- HUD Elements ---
  const renderHUD = () => (
      <g>
          {/* Top Bar */}
          <rect x="50" y="30" width="400" height="15" fill="none" stroke={COLORS.blue} strokeWidth="2" />
          <rect x="54" y="34" width={392 * (Math.max(0, 1000 - frame)/1000)} height="7" fill={COLORS.blue} opacity="0.7" />
          <text x="50" y="20" fill={COLORS.blue} fontSize="12" fontFamily="monospace">PLAYER 1 // SYNC: 100%</text>

          <rect x={WIDTH - 450} y="30" width="400" height="15" fill="none" stroke={COLORS.red} strokeWidth="2" />
          <rect x={WIDTH - 446} y="34" width={392 * (Math.max(0, 1200 - frame)/1200)} height="7" fill={COLORS.red} opacity="0.7" />
          <text x={WIDTH - 50} y="20" textAnchor="end" fill={COLORS.red} fontSize="12" fontFamily="monospace">TARGET // THREAT: EXTREME</text>

          {/* Skill Text */}
          <text x={WIDTH/2} y={100} textAnchor="middle" fill="white" fontSize="24" fontFamily="sans-serif" fontWeight="bold" style={{textShadow: '0 0 10px rgba(0,0,0,0.8)'}}>
             {phase === 'LASER_SHIELD' && "技能: 激光束 (Laser) vs 护盾 (Shield)"}
             {phase === 'TELEKINESIS' && "技能: 隔空取物 (Telekinesis)"}
             {phase === 'TIME_STOP_GIANT' && frame < 500 && "技能: 时间暂停 (Time Stop)"}
             {phase === 'TIME_STOP_GIANT' && frame >= 500 && "技能: 巨大化 (Giant Form)"}
             {phase === 'THOUSAND_SWORDS' && "终极奥义: 万剑归宗 (Thousand Swords)"}
             {phase === 'BLACK_HOLE' && "环境灾害: 人造黑洞 (Black Hole)"}
          </text>
      </g>
  );

  return (
    <div className="w-full h-full flex items-center justify-center bg-slate-900 overflow-hidden">
        <svg 
            viewBox={`0 0 ${WIDTH} ${HEIGHT}`} 
            className="w-full max-w-6xl shadow-2xl border border-slate-700 rounded-lg"
            style={{ 
                background: COLORS.bg,
                filter: timeStopFilter
            }}
        >
            {/* Dynamic Camera Group */}
            <g transform={`translate(${cameraShake.x}, ${cameraShake.y})`}>
                
                {/* Background Grid */}
                <defs>
                    <pattern id="grid" width="50" height="50" patternUnits="userSpaceOnUse">
                        <path d="M 50 0 L 0 0 0 50" fill="none" stroke={COLORS.grid} strokeWidth="1"/>
                    </pattern>
                    <linearGradient id="floorGrad" x1="0" y1="0" x2="0" y2="1">
                        <stop offset="0%" stopColor={COLORS.bg} stopOpacity="0" />
                        <stop offset="100%" stopColor={COLORS.blue} stopOpacity="0.2" />
                    </linearGradient>
                </defs>
                <rect width={WIDTH} height={HEIGHT} fill="url(#grid)" />
                <rect y={GROUND_Y} width={WIDTH} height={HEIGHT - GROUND_Y} fill="url(#floorGrad)" />
                <line x1="0" y1={GROUND_Y} x2={WIDTH} y2={GROUND_Y} stroke={COLORS.blue} strokeWidth="2" opacity="0.3" />

                {/* Effects Layer Bottom */}
                {renderBlackHole()}
                {renderRocks()}

                {/* Characters */}
                <Stickman 
                    x={blue.x} 
                    y={blue.y} 
                    color={COLORS.blue} 
                    pose={blue.pose} 
                    scale={blue.scale}
                    opacity={blue.opacity}
                />
                
                <Stickman 
                    x={red.x} 
                    y={red.y} 
                    color={COLORS.red} 
                    pose={red.pose} 
                    scale={red.scale}
                    opacity={red.opacity}
                    isGlitch={red.isGlitch}
                />

                {/* Effects Layer Top */}
                {renderShield()}
                {renderLaser()}
                {renderSwords()}

                {/* Impact Flash */}
                {(phase === 'CLASH' || (phase === 'LASER_SHIELD' && frame % 10 === 0)) && (
                    <circle cx={(blue.x + red.x)/2} cy={blue.y - 20} r={randomRange(10, 30)} fill="#fff" opacity="0.8" filter="blur(5px)" />
                )}

            </g>

            {/* UI Overlay (No Shake) */}
            {renderHUD()}
            {timeStopOverlay}
            
            {/* Reset Overlay */}
            <rect width={WIDTH} height={HEIGHT} fill="black" opacity={frame > 1200 ? (frame - 1200)/100 : 0} pointerEvents="none" />

        </svg>
    </div>
  );
}23:T386e,```javascript
'use client';

import React, { useState, useEffect, useRef, useMemo } from 'react';

// 常量定义
const VIEW_WIDTH = 1000;
const VIEW_HEIGHT = 600;
const MOON_RADIUS = 120;
const CENTER_X = 350; // 月球中心X
const CENTER_Y = 300; // 月球中心Y

// 目标农历日期
const TARGET_DAYS = [1, 3, 5, 7, 10, 15, 18, 20, 23, 25, 27, 30];

// 辅助函数：生成星星
const generateStars = (count) => {
  return Array.from({ length: count }, () => ({
    x: Math.random() * VIEW_WIDTH,
    y: Math.random() * VIEW_HEIGHT,
    r: Math.random() * 1.5 + 0.5,
    opacity: Math.random() * 0.5 + 0.3,
    blinkSpeed: Math.random() * 2 + 1,
  }));
};

export const MoonPhaseAnimation = () => {
  // 状态管理
  const [targetDay, setTargetDay] = useState(15); // 目标日期
  const [displayDay, setDisplayDay] = useState(1); // 当前动画展示的日期（浮点数，用于动画插值）
  const [stars] = useState(() => generateStars(150));
  
  // 动画循环引用
  const requestRef = useRef();
  const previousTimeRef = useRef();

  // 动画核心逻辑
  const animate = (time) => {
    if (previousTimeRef.current !== undefined) {
      const deltaTime = time - previousTimeRef.current;
      
      // 简单的缓动逻辑 (Lerp)
      setDisplayDay(prev => {
        const diff = targetDay - prev;
        // 如果差异很小，直接停止，节省计算
        if (Math.abs(diff) < 0.05) return targetDay;
        // 速度系数，0.05 产生平滑的阻尼效果
        return prev + diff * 0.08;
      });
    }
    previousTimeRef.current = time;
    requestRef.current = requestAnimationFrame(animate);
  };

  useEffect(() => {
    requestRef.current = requestAnimationFrame(animate);
    return () => cancelAnimationFrame(requestRef.current);
  }, [targetDay]);

  // 计算月相路径
  // 核心算法：利用 SVG Path 绘制月球受光面
  const getMoonPath = (day) => {
    // 将农历日期 1-30 映射到相位 0-1 (0=New, 0.5=Full, 1=New)
    // 农历约29.5天，这里简化为30天循环
    const phase = (day - 1) / 29.5;
    const r = MOON_RADIUS;
    
    // 如果是朔月 (Day 1 or 30 roughly)，几乎全黑
    if (day <= 1 || day >= 29.5) {
        return ""; // 空路径，全黑
    }

    // 上半月 (Waxing) 1 < day <= 15
    if (day <= 15.5) {
        // 右半边圆弧固定 (从上顶点(0,-r)顺时针画到下顶点(0,r))
        // 左半边是椭圆弧，根据日期从右凸变为左凸
        // sweepX 计算：初一为r(右侧)，初七八为0(中间)，十五为-r(左侧)
        // 映射 day 1->15 到 1->-1
        const progress = (day - 1) / 14; // 0 to 1
        const sweepX = r * (1 - 2 * progress); 
        
        // 路径构建：
        // M 0 -r (移动到顶点)
        // A r r 0 0 1 0 r (画右半圆弧到底部)
        // A |sweepX| r 0 0 (flag) 0 -r (画椭圆弧回顶部)
        // flag: 如果 sweepX > 0 (convex/gibbous) flag=1? No.
        // 实际上，上半月亮面在右。
        // Day 1-7: Crescent (眉月). 亮部像眉毛。右边缘是圆，左边缘是凹椭圆。
        // Day 7-15: Gibbous (盈凸). 右边缘是圆，左边缘是凸椭圆。
        
        // 使用更通用的数学方法：
        // 亮面始终包含右半圆弧 (除了全黑)。
        // 晨昏线(Terminator) x坐标 = -r * cos(phase * 2 * PI)
        
        // 简化逻辑：
        // 1. 画出右半圆
        // 2. 加上/减去 左半部分的椭圆
        
        const x = -r * Math.cos((day - 1) / 14.75 * Math.PI);
        
        // 构建路径字符串
        // M 0 -r 
        // A r r 0 0 1 0 r (右侧半圆)
        // A abs(x) r 0 0 (x<0 ? 0 : 1) 0 -r (晨昏线椭圆)
        const sweepFlag = x < 0 ? 0 : 1; 
        return `M 0 -${r} A ${r} ${r} 0 0 1 0 ${r} A ${Math.abs(x)} ${r} 0 0 ${sweepFlag} 0 -${r}`;
    } 
    // 下半月 (Waning) 15 < day <= 30
    else {
        // 左半边圆弧固定
        // 右半边是椭圆弧
        const daysFromFull = day - 15.5;
        // x 从 -r (Full) 变到 r (New)
        const x = -r * Math.cos(daysFromFull / 14.75 * Math.PI);
        
        // M 0 -r
        // A r r 0 0 0 0 r (左侧半圆, sweep=0逆时针)
        // A abs(x) r 0 0 (x>0 ? 0 : 1) 0 -r
        const sweepFlag = x > 0 ? 0 : 1;
        return `M 0 -${r} A ${r} ${r} 0 0 0 0 ${r} A ${Math.abs(x)} ${r} 0 0 ${sweepFlag} 0 -${r}`;
    }
  };

  // 获取文字描述
  const getPhaseInfo = (d) => {
    const day = Math.round(d);
    let name = "";
    let desc = "";
    
    if (day === 1) { name = "新月 (朔)"; desc = "日月同经，无法看见"; }
    else if (day === 30) { name = "晦"; desc = "月亮不可见"; }
    else if (day >= 2 && day <= 6) { name = "蛾眉月"; desc = "亮面在右，形状如钩"; }
    else if (day >= 7 && day <= 9) { name = "上弦月"; desc = "右半圆亮，上半夜可见"; }
    else if (day >= 10 && day <= 14) { name = "盈凸月"; desc = "大部分亮，右侧饱满"; }
    else if (day >= 15 && day <= 16) { name = "满月 (望)"; desc = "日月相望，圆润明亮"; }
    else if (day >= 17 && day <= 21) { name = "亏凸月"; desc = "左侧饱满，开始亏缺"; }
    else if (day >= 22 && day <= 24) { name = "下弦月"; desc = "左半圆亮，下半夜可见"; }
    else if (day >= 25 && day <= 29) { name = "残月"; desc = "亮面在左，清晨可见"; }

    return { name, desc };
  };

  const { name, desc } = getPhaseInfo(displayDay);
  const isUpperMonth = displayDay <= 15.5;

  return (
    <svg viewBox={`0 0 ${VIEW_WIDTH} ${VIEW_HEIGHT}`} className="w-full h-full bg-slate-900 select-none font-sans">
      <defs>
        {/* 1. 陨石坑纹理滤镜 - 增加月球真实感 */}
        <filter id="moonTexture">
          <feTurbulence type="fractalNoise" baseFrequency="0.03" numOctaves="4" seed="5" />
          <feColorMatrix type="matrix" values="0 0 0 0 0.6  0 0 0 0 0.6  0 0 0 0 0.6  0 0 0 1 0" />
          <feComposite operator="in" in2="SourceGraphic" />
        </filter>
        
        {/* 2. 月球发光效果 */}
        <filter id="glow">
          <feGaussianBlur stdDeviation="8" result="coloredBlur" />
          <feMerge>
            <feMergeNode in="coloredBlur" />
            <feMergeNode in="SourceGraphic" />
          </feMerge>
        </filter>

        {/* 3. 按钮渐变 */}
        <linearGradient id="btnGrad" x1="0%" y1="0%" x2="100%" y2="0%">
          <stop offset="0%" stopColor="#1e293b" />
          <stop offset="100%" stopColor="#334155" />
        </linearGradient>
        <linearGradient id="btnGradActive" x1="0%" y1="0%" x2="100%" y2="0%">
          <stop offset="0%" stopColor="#3b82f6" />
          <stop offset="100%" stopColor="#2563eb" />
        </linearGradient>
      </defs>

      {/* 背景：星空 */}
      <rect width={VIEW_WIDTH} height={VIEW_HEIGHT} fill="#0f172a" />
      <g>
        {stars.map((star, i) => (
          <circle 
            key={i} 
            cx={star.x} 
            cy={star.y} 
            r={star.r} 
            fill="#fff" 
            opacity={star.opacity}
          >
            <animate 
              attributeName="opacity" 
              values={`${star.opacity};${star.opacity * 0.2};${star.opacity}`} 
              dur={`${star.blinkSpeed}s`} 
              repeatCount="indefinite" 
            />
          </circle>
        ))}
      </g>

      {/* 装饰性网格线 */}
      <line x1="680" y1="50" x2="680" y2="550" stroke="#334155" strokeWidth="1" strokeDasharray="5,5" />
      <text x="50" y="40" fill="#64748b" fontSize="14" fontFamily="monospace">SYSTEM: LUNAR_PHASE_VISUALIZER // V2.0</text>

      {/* 月球主体绘制区域 */}
      <g transform={`translate(${CENTER_X}, ${CENTER_Y})`}>
        {/* 1. 阴影底色 (Dark Side) */}
        <circle r={MOON_RADIUS} fill="#18181b" stroke="#334155" strokeWidth="1" />
        
        {/* 2. 纹理层 (Applied to the whole circle but masked later? No, draw light part with texture) */}
        {/* 实际上，为了效果好，我们先画一个暗的纹理球，再画亮的纹理球盖在上面 */}
        <circle r={MOON_RADIUS} fill="#27272a" filter="url(#moonTexture)" opacity="0.3" />

        {/* 3. 亮面 (Light Side) - 使用计算出的 Path */}
        <g filter="url(#glow)">
          <path 
            d={getMoonPath(displayDay)} 
            fill="#e2e8f0" 
            stroke="none"
          />
          {/* 在亮面上叠加纹理，增加细节 */}
          <path 
            d={getMoonPath(displayDay)} 
            fill="#cbd5e1" 
            filter="url(#moonTexture)" 
            opacity="0.8"
            style={{ mixBlendMode: 'multiply' }}
          />
        </g>
        
        {/* 4. 外部光晕环 */}
        <circle r={MOON_RADIUS + 10} fill="none" stroke="#3b82f6" strokeWidth="1" opacity="0.2" strokeDasharray="10, 5">
            <animateTransform attributeName="transform" type="rotate" from="0 0 0" to="360 0 0" dur="60s" repeatCount="indefinite" />
        </circle>
      </g>

      {/* 文本信息展示区 - 左下侧 */}
      <g transform="translate(50, 500)">
        <text fill="#94a3b8" fontSize="16" fontFamily="monospace">CURRENT_PHASE:</text>
        <text y="30" fill="#f8fafc" fontSize="36" fontWeight="bold">{name}</text>
        <text y="55" fill="#cbd5e1" fontSize="16">{desc}</text>
        <text y="80" fill="#3b82f6" fontSize="24" fontFamily="monospace">
          农历 {Math.floor(displayDay) === 1 ? '初一' : 
               Math.floor(displayDay) === 15 ? '十五' : 
               Math.floor(displayDay) === 30 ? '三十' : 
               `Day ${Math.floor(displayDay)}`}
        </text>
      </g>

      {/* 右侧控制面板 */}
      <g transform="translate(720, 80)">
        <text x="0" y="-20" fill="#fff" fontSize="20" fontWeight="bold">月相演变控制 (Phase Control)</text>
        
        {/* 规律总结面板 */}
        <g transform="translate(0, 320)">
            <rect width="240" height="140" rx="8" fill="#1e293b" stroke="#334155" />
            <text x="20" y="30" fill="#3b82f6" fontSize="16" fontWeight="bold">月相变化规律 Summary</text>
            
            {/* 上半月规律 */}
            <g opacity={isUpperMonth ? 1 : 0.4} transform="translate(20, 60)">
                <text fill="#fff" fontSize="14">上半月 (初一 ~ 十五):</text>
                <text y="20" fill="#94a3b8" fontSize="12">● 亮面在 <tspan fill="#fbbf24" fontWeight="bold">右 (西)</tspan></text>
                <text y="40" fill="#94a3b8" fontSize="12">● 由缺变圆 (Waxing)</text>
            </g>

            {/* 下半月规律 */}
            <g opacity={!isUpperMonth ? 1 : 0.4} transform="translate(140, 60)">
                <text fill="#fff" fontSize="14">下半月 (十六 ~ 三十):</text>
                <text y="20" fill="#94a3b8" fontSize="12">● 亮面在 <tspan fill="#fbbf24" fontWeight="bold">左 (东)</tspan></text>
                <text y="40" fill="#94a3b8" fontSize="12">● 由圆变缺 (Waning)</text>
            </g>
        </g>

        {/* 按钮网格 */}
        <g>
          {TARGET_DAYS.map((day, i) => {
            const isActive = targetDay === day;
            const row = Math.floor(i / 6); // 2 rows
            const col = i % 6;
            const btnW = 35;
            const btnH = 35;
            const gap = 10;
            const x = col * (btnW + gap);
            const y = row * (btnH + gap);
            
            // 农历中文数字转换简化
            const getDayName = (d) => {
                const map = {1:'初一', 3:'初三', 5:'初五', 7:'初七', 10:'初十', 15:'十五', 18:'十八', 20:'二十', 23:'廿三', 25:'廿五', 27:'廿七', 30:'三十'};
                return map[d] || d;
            };

            return (
              <g 
                key={day} 
                transform={`translate(${x}, ${y})`} 
                onClick={() => setTargetDay(day)}
                style={{ cursor: 'pointer' }}
              >
                <rect 
                  width={btnW} 
                  height={btnH} 
                  rx="4" 
                  fill={isActive ? "url(#btnGradActive)" : "url(#btnGrad)"} 
                  stroke={isActive ? "#60a5fa" : "#475569"}
                  strokeWidth={isActive ? 2 : 1}
                  className="transition-all duration-300"
                />
                <text 
                  x={btnW/2} 
                  y={btnH/2 + 5} 
                  textAnchor="middle" 
                  fill={isActive ? "#fff" : "#94a3b8"} 
                  fontSize="12"
                  fontWeight={isActive ? "bold" : "normal"}
                >
                  {getDayName(day)}
                </text>
                {/* 选中时的光效 */}
                {isActive && <rect width={btnW} height={btnH} rx="4" fill="none" stroke="#60a5fa" strokeWidth="1" strokeOpacity="0.5">
                    <animate attributeName="stroke-width" values="1;4;1" dur="1.5s" repeatCount="indefinite"/>
                    <animate attributeName="opacity" values="1;0;1" dur="1.5s" repeatCount="indefinite"/>
                </rect>}
              </g>
            );
          })}
        </g>

        {/* 进度条指示器 */}
        <g transform="translate(0, 110)">
             <text x="0" y="-10" fill="#64748b" fontSize="12">Timeline</text>
             <rect width="260" height="4" fill="#334155" rx="2" />
             <rect width={260 * (displayDay / 30)} height="4" fill="#3b82f6" rx="2" />
             <circle cx={260 * (displayDay / 30)} cy="2" r="4" fill="#fff" />
        </g>

        {/* 动态数据面板 */}
        <g transform="translate(0, 160)">
            <text fill="#3b82f6" fontSize="14" fontWeight="bold">DATA LOG:</text>
            <text y="25" fill="#94a3b8" fontSize="12" fontFamily="monospace">Illumination: {Math.abs((15 - Math.abs(displayDay - 15)) / 15 * 100).toFixed(1)}%</text>
            <text y="45" fill="#94a3b8" fontSize="12" fontFamily="monospace">Age: {displayDay.toFixed(2)} days</text>
            <text y="65" fill="#94a3b8" fontSize="12" fontFamily="monospace">Visibility: {displayDay > 1 && displayDay < 29 ? 'Visible' : 'Invisible'}</text>
            <text y="85" fill="#94a3b8" fontSize="12" fontFamily="monospace">Direction: {isUpperMonth ? 'Waxing (+)' : 'Waning (-)'}</text>
        </g>
      </g>
    </svg>
  );
};
```24:T31e4,```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Chrome Browser Blueprint</title>
    <style>
        :root {
            --bg-color: #0F172A;
            --grid-color: #1E293B;
            --frame-color: #94A3B8;
            --guide-color: #475569;
            --chrome-blue: #4285F4;
            --chrome-red: #EA4335;
            --chrome-yellow: #FBBC05;
            --chrome-green: #34A853;
            --text-color: #E2E8F0;
        }

        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            background-color: var(--bg-color);
            display: flex;
            align-items: center;
            justify-content: center;
            font-family: 'Roboto', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            overflow: hidden;
        }

        svg {
            width: 100%;
            height: 100%;
            max-width: 1200px;
            max-height: 700px;
        }

        /* Line Drawing Animation */
        .path-draw {
            fill: none;
            stroke-linecap: round;
            stroke-linejoin: round;
            animation: draw var(--dur, 2s) cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
            animation-delay: var(--del, 0s);
        }

        .path-linear {
            fill: none;
            stroke-linecap: round;
            stroke-linejoin: round;
            animation: draw var(--dur, 2s) ease-in-out forwards;
            animation-delay: var(--del, 0s);
        }

        @keyframes draw {
            to { stroke-dashoffset: 0; }
        }

        /* Fill Fade Animation */
        .fill-fade {
            fill-opacity: 0;
            animation: fillIn 1.5s ease-in-out forwards;
            animation-delay: var(--del-fill, 5s);
        }

        @keyframes fillIn {
            to { fill-opacity: 0.15; }
        }

        /* Text Fade Animation */
        .text-fade {
            opacity: 0;
            fill: var(--text-color);
            font-size: 12px;
            letter-spacing: 1px;
            animation: fadeIn 1s ease-in-out forwards;
            animation-delay: var(--del, 0s);
        }

        .text-title {
            font-size: 24px;
            font-weight: 700;
            letter-spacing: 3px;
        }

        .text-subtitle {
            font-size: 14px;
            fill: var(--frame-color);
            letter-spacing: 2px;
        }

        @keyframes fadeIn {
            to { opacity: 1; }
        }

        /* Glow Effects */
        .glow {
            filter: drop-shadow(0 0 8px currentColor);
        }

        /* Typewriter Cursor */
        .cursor {
            display: inline-block;
            width: 6px;
            height: 14px;
            background-color: var(--chrome-blue);
            animation: blink 0.8s infinite;
            vertical-align: middle;
            margin-left: 4px;
            opacity: 0;
        }

        @keyframes blink {
            0%, 100% { opacity: 0; }
            50% { opacity: 1; }
        }
    </style>
</head>
<body>

    <svg viewBox="0 0 1200 700" preserveAspectRatio="xMidYMid meet">
        <!-- Definitions -->
        <defs>
            <pattern id="blueprint-grid" width="40" height="40" patternUnits="userSpaceOnUse">
                <path d="M 40 0 L 0 0 0 40" fill="none" stroke="var(--grid-color)" stroke-width="1"/>
            </pattern>

            <pattern id="blueprint-grid-small" width="10" height="10" patternUnits="userSpaceOnUse">
                <path d="M 10 0 L 0 0 0 10" fill="none" stroke="var(--grid-color)" stroke-width="0.3"/>
            </pattern>

            <!-- Chrome Blade Path -->
            <g id="chrome-blade">
                <path class="path-draw fill-fade" d="M 0 -55 L 106.6536 -55 A 120 120 0 0 0 -100.9582 -64.8648 L -47.6314 27.5 A 55 55 0 0 1 0 -55 Z" stroke-width="4" />
            </g>
        </defs>

        <!-- Background Grids -->
        <rect width="100%" height="100%" fill="url(#blueprint-grid-small)" />
        <rect width="100%" height="100%" fill="url(#blueprint-grid)" />

        <!-- Browser Window Outline -->
        <g stroke="var(--frame-color)" stroke-width="2">
            <!-- Main Window -->
            <rect class="path-linear" x="100" y="80" width="1000" height="540" rx="12" style="--dur: 2s; --del: 0.5s;" />
            <!-- Toolbar Separator -->
            <line class="path-linear" x1="100" y1="140" x2="1100" y2="140" style="--dur: 1.5s; --del: 1.5s;" />
            
            <!-- Window Controls (Mac Style) -->
            <circle class="path-draw" cx="130" cy="110" r="6" stroke="var(--chrome-red)" style="--dur: 0.5s; --del: 2.0s;" />
            <circle class="path-draw" cx="150" cy="110" r="6" stroke="var(--chrome-yellow)" style="--dur: 0.5s; --del: 2.2s;" />
            <circle class="path-draw" cx="170" cy="110" r="6" stroke="var(--chrome-green)" style="--dur: 0.5s; --del: 2.4s;" />
            
            <!-- Address Bar -->
            <rect class="path-linear" x="250" y="98" width="600" height="26" rx="13" stroke-width="1.5" style="--dur: 1.5s; --del: 2.5s;" />
            
            <!-- Navigation Icons (Back, Forward, Refresh) -->
            <path class="path-draw" d="M 205 111 L 195 111 M 195 111 L 200 106 M 195 111 L 200 116" stroke-width="1.5" style="--dur: 0.8s; --del: 2.8s;" />
            <path class="path-draw" d="M 215 111 L 225 111 M 225 111 L 220 106 M 225 111 L 220 116" stroke-width="1.5" style="--dur: 0.8s; --del: 2.9s;" />
            <path class="path-draw" d="M 240 108 A 5 5 0 1 1 236 111 L 236 108" stroke-width="1.5" style="--dur: 0.8s; --del: 3.0s;" />
            
            <!-- Settings Icon -->
            <circle class="path-draw" cx="880" cy="111" r="2" fill="var(--frame-color)" style="--dur: 0.5s; --del: 3.2s;" />
            <circle class="path-draw" cx="888" cy="111" r="2" fill="var(--frame-color)" style="--dur: 0.5s; --del: 3.3s;" />
            <circle class="path-draw" cx="896" cy="111" r="2" fill="var(--frame-color)" style="--dur: 0.5s; --del: 3.4s;" />
        </g>

        <!-- Titles & Text -->
        <text x="100" y="50" class="text-fade text-title" style="--del: 1s;">CHROME ARCHITECTURE</text>
        <text x="100" y="70" class="text-fade text-subtitle" style="--del: 1.5s;">BLUEPRINT SCHEMATIC v1.0</text>
        
        <text x="265" y="115" class="text-fade" style="--del: 3.5s; font-family: monospace; font-size: 13px;">https://www.google.com/chrome</text>

        <!-- Center Blueprint Area -->
        <g transform="translate(600, 380)">
            
            <!-- Guide Lines (Technical drawing style) -->
            <g stroke="var(--guide-color)" stroke-width="1" stroke-dasharray="4 4">
                <!-- Crosshairs -->
                <line class="path-linear" x1="-350" y1="0" x2="350" y2="0" style="--dur: 2s; --del: 3.5s;" />
                <line class="path-linear" x1="0" y1="-200" x2="0" y2="200" style="--dur: 2s; --del: 3.5s;" />
                
                <!-- Concentric Guide Circles -->
                <circle class="path-draw" cx="0" cy="0" r="150" style="--dur: 2s; --del: 4.0s;" />
                <circle class="path-draw" cx="0" cy="0" r="180" style="--dur: 2s; --del: 4.2s;" />
                
                <!-- Angular Guide Lines (120deg, 240deg) -->
                <line class="path-linear" x1="0" y1="0" x2="150" y2="86.6" style="--dur: 1.5s; --del: 4.5s;" />
                <line class="path-linear" x1="0" y1="0" x2="-150" y2="86.6" style="--dur: 1.5s; --del: 4.5s;" />
            </g>

            <!-- Measurements & Annotations -->
            <g>
                <!-- R=120 Annotation -->
                <path class="path-linear" stroke="var(--guide-color)" stroke-width="1" d="M 84.85 -84.85 L 140 -140 L 220 -140" style="--dur: 1s; --del: 5.5s;" />
                <circle class="path-draw" cx="84.85" cy="-84.85" r="3" fill="var(--guide-color)" style="--dur: 0.5s; --del: 5.5s;" />
                <text x="145" y="-145" class="text-fade" style="--del: 6.0s;">R=120px (Outer Arc)</text>

                <!-- R=55 Annotation -->
                <path class="path-linear" stroke="var(--guide-color)" stroke-width="1" d="M -38.89 -38.89 L -100 -100 L -180 -100" style="--dur: 1s; --del: 5.8s;" />
                <circle class="path-draw" cx="-38.89" cy="-38.89" r="3" fill="var(--guide-color)" style="--dur: 0.5s; --del: 5.8s;" />
                <text x="-180" y="-105" class="text-fade" style="--del: 6.3s;">r=55px (Inner Boundary)</text>

                <!-- 120° Angle Annotation -->
                <path class="path-draw" stroke="var(--guide-color)" stroke-width="1" fill="none" d="M 0 100 A 100 100 0 0 1 -86.6 50" style="--dur: 1s; --del: 6.5s;" />
                <text x="-50" y="115" class="text-fade" style="--del: 7.0s;">120° Rotation</text>
                
                <!-- Engine Details text -->
                <text x="200" y="100" class="text-fade text-subtitle" style="--del: 8s;">CORE COMPONENTS</text>
                <text x="200" y="125" class="text-fade" style="--del: 8.2s;">> Engine: V8 JavaScript</text>
                <text x="200" y="145" class="text-fade" style="--del: 8.4s;">> Rendering: Blink</text>
                <text x="200" y="165" class="text-fade" style="--del: 8.6s;">> Multi-process Arch</text>
            </g>

            <!-- CHROME LOGO ANIMATION -->
            <g class="glow">
                <!-- Center Blue Circle -->
                <circle class="path-draw fill-fade" cx="0" cy="0" r="45" stroke="var(--chrome-blue)" fill="var(--chrome-blue)" stroke-width="6" style="--dur: 2s; --del: 6.5s; --del-fill: 8.5s;" />
                
                <!-- Inner White Gap (Simulated by a transparent gap in actual logo, here we draw an outline) -->
                <circle class="path-draw" cx="0" cy="0" r="55" stroke="#FFFFFF" stroke-opacity="0.2" stroke-width="2" style="--dur: 2s; --del: 7.0s;" />

                <!-- Red Blade (Top) -->
                <use href="#chrome-blade" stroke="var(--chrome-red)" fill="var(--chrome-red)" style="--dur: 2s; --del: 7.5s; --del-fill: 9.5s;" />
                
                <!-- Yellow Blade (Bottom Right) -->
                <use href="#chrome-blade" transform="rotate(120)" stroke="var(--chrome-yellow)" fill="var(--chrome-yellow)" style="--dur: 2s; --del: 7.8s; --del-fill: 9.8s;" />
                
                <!-- Green Blade (Bottom Left) -->
                <use href="#chrome-blade" transform="rotate(240)" stroke="var(--chrome-green)" fill="var(--chrome-green)" style="--dur: 2s; --del: 8.1s; --del-fill: 10.1s;" />
            </g>
        </g>

        <!-- Status Bar Terminal Text -->
        <text x="110" y="605" class="text-fade" style="--del: 10.5s; font-family: monospace; font-size: 12px; fill: var(--chrome-green);">
            <tspan id="terminal-text"></tspan><tspan class="cursor" id="terminal-cursor"></tspan>
        </text>

    </svg>

    <script>
        // 1. Calculate path lengths and setup CSS variables for drawing animation
        document.addEventListener("DOMContentLoaded", () => {
            const paths = document.querySelectorAll('.path-draw, .path-linear');
            
            paths.forEach(path => {
                // Get total length of the SVG path/shape
                const length = path.getTotalLength();
                
                // Set stroke-dasharray and stroke-dashoffset exactly to the length
                path.style.strokeDasharray = length;
                path.style.strokeDashoffset = length;
                
                // Fallback attributes for wider compatibility
                path.setAttribute('stroke-dasharray', length);
                path.setAttribute('stroke-dashoffset', length);
            });

            // 2. Typewriter Effect for Status Bar
            const terminalText = "System Initialized. UI Components loaded. V8 Engine running. Ready for web rendering...";
            const terminalEl = document.getElementById('terminal-text');
            const cursorEl = document.getElementById('terminal-cursor');
            
            setTimeout(() => {
                cursorEl.style.opacity = '1';
                let i = 0;
                const typingInterval = setInterval(() => {
                    terminalEl.textContent += terminalText.charAt(i);
                    i++;
                    if (i >= terminalText.length) {
                        clearInterval(typingInterval);
                    }
                }, 40); // typing speed
            }, 10500); // starts after the logo animation finishes
        });
    </script>
</body>
25:T4caf,import React, { useState, useEffect, useRef, useMemo } from 'react';

const VIEW_WIDTH = 800;
const VIEW_HEIGHT = 600;
const CELL_SIZE = 40;
const SPEED = 2;
const BULLET_SPEED = 6;

// ------------------- Types & Constants -------------------

type EntityType = 'tank' | 'bullet' | 'particle' | 'wall' | 'steel' | 'bush' | 'base';

interface GameObject {
  id: string;
  type: EntityType;
  x: number;
  y: number;
  w: number;
  h: number;
  [key: string]: any;
}

interface Tank extends GameObject {
  dir: number; // 0: Up, 1: Right, 2: Down, 3: Left
  color: string;
  colorDark: string;
  moving: boolean;
  cooldown: number;
  turretAngle: number;
  targetTurretAngle: number;
  trackOffset: number;
}

interface Bullet extends GameObject {
  dx: number;
  dy: number;
  ownerId: string;
}

interface Particle extends GameObject {
  vx: number;
  vy: number;
  life: number;
  maxLife: number;
  color: string;
  rotation: number;
  spin: number;
}

// ------------------- Helper Functions -------------------

const rectIntersect = (r1: GameObject, r2: GameObject) => {
  return !(r2.x >= r1.x + r1.w || 
           r2.x + r2.w <= r1.x || 
           r2.y >= r1.y + r1.h || 
           r2.y + r2.h <= r1.y);
};

const getDirectionVector = (dir: number) => {
  if (dir === 0) return { x: 0, y: -1 };
  if (dir === 1) return { x: 1, y: 0 };
  if (dir === 2) return { x: 0, y: 1 };
  if (dir === 3) return { x: -1, y: 0 };
  return { x: 0, y: 0 };
};

const generateMap = () => {
  const map: GameObject[] = [];
  // Layout grid (1 = Brick, 2 = Steel, 3 = Bush, 9 = Base)
  const layout = [
    [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
    [0,1,1,0,0,1,1,0,2,2,2,2,0,1,1,0,0,1,1,0],
    [0,1,1,0,0,1,1,0,2,0,0,2,0,1,1,0,0,1,1,0],
    [0,1,1,0,0,1,1,0,2,0,0,2,0,1,1,0,0,1,1,0],
    [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
    [0,1,1,0,2,2,0,0,3,3,3,3,0,0,2,2,0,1,1,0],
    [0,1,1,0,2,2,0,0,3,3,3,3,0,0,2,2,0,1,1,0],
    [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
    [0,1,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,0],
    [0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0],
    [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
    [0,1,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,0],
    [0,0,0,0,0,0,0,0,1,9,1,0,0,0,0,0,0,0,0,0], // Base at bottom center
    [0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0],
  ];

  layout.forEach((row, r) => {
    row.forEach((cell, c) => {
      const x = c * CELL_SIZE;
      const y = r * CELL_SIZE;
      const id = `block-${r}-${c}`;
      if (cell === 1) map.push({ id, type: 'wall', x, y, w: CELL_SIZE, h: CELL_SIZE });
      if (cell === 2) map.push({ id, type: 'steel', x, y, w: CELL_SIZE, h: CELL_SIZE });
      if (cell === 3) map.push({ id, type: 'bush', x, y, w: CELL_SIZE, h: CELL_SIZE });
      if (cell === 9) map.push({ id, type: 'base', x, y, w: CELL_SIZE, h: CELL_SIZE });
    });
  });
  return map;
};

// ------------------- Main Component -------------------

export const CyberTankBattle = () => {
  // --- Refs for Game Logic (Mutable State) ---
  const gameStateRef = useRef({
    tanks: [
      { 
        id: 'p1', type: 'tank', x: 280, y: 520, w: 34, h: 34, 
        dir: 0, color: '#fff000', colorDark: '#bfa300', moving: false, cooldown: 0, 
        turretAngle: 0, targetTurretAngle: 0, trackOffset: 0 
      },
      { 
        id: 'e1', type: 'tank', x: 280, y: 40, w: 34, h: 34, 
        dir: 2, color: '#227545', colorDark: '#144a2b', moving: false, cooldown: 0, 
        turretAngle: 180, targetTurretAngle: 180, trackOffset: 0 
      },
    ] as Tank[],
    bullets: [] as Bullet[],
    particles: [] as Particle[],
    blocks: generateMap(),
    shake: { x: 0, y: 0, trauma: 0 },
    lastTime: 0,
    frameCount: 0,
  });

  // --- React State for Rendering ---
  // We only store what is needed for the render cycle to avoid heavy diffing
  const [renderState, setRenderState] = useState({
    tanks: [] as Tank[],
    bullets: [] as Bullet[],
    particles: [] as Particle[],
    blocks: [] as GameObject[],
    shake: { x: 0, y: 0 },
  });

  // --- Game Loop ---
  useEffect(() => {
    let requestID: number;
    const state = gameStateRef.current;

    const spawnParticles = (x: number, y: number, color: string, count: number, type: 'dust' | 'debris') => {
      for (let i = 0; i < count; i++) {
        const angle = Math.random() * Math.PI * 2;
        const speed = Math.random() * (type === 'debris' ? 4 : 1);
        state.particles.push({
          id: `p-${state.frameCount}-${i}`,
          type: 'particle',
          x, y, w: type === 'debris' ? 6 : 4, h: type === 'debris' ? 6 : 4,
          vx: Math.cos(angle) * speed,
          vy: Math.sin(angle) * speed,
          life: 1.0,
          maxLife: 1.0,
          color: color,
          rotation: Math.random() * 360,
          spin: (Math.random() - 0.5) * 20,
        });
      }
    };

    const update = (time: number) => {
      state.frameCount++;
      const dt = 1; // Simplify delta time for this example

      // 1. Update Shake
      if (state.shake.trauma > 0) {
        state.shake.trauma = Math.max(0, state.shake.trauma - 0.05);
        const shakeMag = state.shake.trauma * state.shake.trauma * 10;
        state.shake.x = (Math.random() - 0.5) * shakeMag;
        state.shake.y = (Math.random() - 0.5) * shakeMag;
      } else {
        state.shake.x = 0;
        state.shake.y = 0;
      }

      // 2. AI & Tank Logic
      state.tanks.forEach(tank => {
        // AI Logic (Simple Random Walk & Shoot)
        if (state.frameCount % 60 === 0) {
          if (Math.random() < 0.3) tank.dir = Math.floor(Math.random() * 4);
          tank.moving = Math.random() < 0.8;
          
          // Turret logic: Point towards center or enemy approximately
          tank.targetTurretAngle = tank.dir * 90;
        }

        // Shooting Logic
        if (tank.cooldown > 0) tank.cooldown--;
        if (tank.cooldown === 0 && Math.random() < 0.02) {
          const dv = getDirectionVector(tank.dir);
          state.bullets.push({
            id: `b-${state.frameCount}-${tank.id}`,
            type: 'bullet',
            x: tank.x + tank.w / 2 - 4 + dv.x * 25,
            y: tank.y + tank.h / 2 - 4 + dv.y * 25,
            w: 8, h: 8,
            dx: dv.x * BULLET_SPEED,
            dy: dv.y * BULLET_SPEED,
            ownerId: tank.id
          });
          tank.cooldown = 40;
          state.shake.trauma = Math.min(1, state.shake.trauma + 0.2); // Recoil shake
        }

        // Movement
        if (tank.moving) {
          const dv = getDirectionVector(tank.dir);
          const nextX = tank.x + dv.x * SPEED;
          const nextY = tank.y + dv.y * SPEED;

          // Boundary Check
          let collision = false;
          if (nextX < 0 || nextX + tank.w > VIEW_WIDTH || nextY < 0 || nextY + tank.h > VIEW_HEIGHT) collision = true;

          // Wall/Steel/Base Collision
          const tankRect = { ...tank, x: nextX, y: nextY };
          if (!collision) {
            for (const block of state.blocks) {
              if (block.type !== 'bush' && rectIntersect(tankRect, block)) {
                collision = true;
                break;
              }
            }
          }
          
          // Tank vs Tank Collision
          if (!collision) {
             for (const other of state.tanks) {
                 if (other.id !== tank.id && rectIntersect(tankRect, other)) {
                     collision = true;
                     break;
                 }
             }
          }

          if (!collision) {
            tank.x = nextX;
            tank.y = nextY;
            tank.trackOffset = (tank.trackOffset + SPEED) % 20;
            
            // Dust Particles
            if (state.frameCount % 10 === 0) {
              spawnParticles(tank.x + tank.w/2, tank.y + tank.h, '#666', 1, 'dust');
            }
          }
        }

        // Smooth Turret Rotation
        const angleDiff = tank.targetTurretAngle - tank.turretAngle;
        tank.turretAngle += angleDiff * 0.1;
      });

      // 3. Bullet Logic
      for (let i = state.bullets.length - 1; i >= 0; i--) {
        const b = state.bullets[i];
        b.x += b.dx;
        b.y += b.dy;
        let hit = false;

        // Out of bounds
        if (b.x < 0 || b.x > VIEW_WIDTH || b.y < 0 || b.y > VIEW_HEIGHT) hit = true;

        // Collision with Blocks
        if (!hit) {
          for (let j = state.blocks.length - 1; j >= 0; j--) {
            const block = state.blocks[j];
            if (block.type === 'bush') continue; // Bullets pass through bushes
            
            if (rectIntersect(b, block)) {
              hit = true;
              state.shake.trauma = Math.min(1, state.shake.trauma + 0.4); // Impact shake
              
              if (block.type === 'wall') {
                // Destroy wall
                state.blocks.splice(j, 1);
                spawnParticles(block.x + block.w/2, block.y + block.h/2, '#8d3a3a', 6, 'debris');
              } else if (block.type === 'steel') {
                // Sparks
                spawnParticles(b.x, b.y, '#fff', 4, 'dust');
              } else if (block.type === 'base') {
                 // Game Over logic simulated visually
                 spawnParticles(block.x + block.w/2, block.y + block.h/2, '#ffd700', 20, 'debris');
              }
              break;
            }
          }
        }

        // Collision with Tanks
        if (!hit) {
          for (const tank of state.tanks) {
            if (b.ownerId !== tank.id && rectIntersect(b, tank)) {
              hit = true;
              state.shake.trauma = Math.min(1, state.shake.trauma + 0.5);
              spawnParticles(b.x, b.y, tank.color, 8, 'debris');
              // Simple respawn logic for visual continuity
              // In a real game, tank would die. Here we just knock it back slightly
              tank.x += b.dx * 2;
              tank.y += b.dy * 2;
              break;
            }
          }
        }

        if (hit) {
          state.bullets.splice(i, 1);
        }
      }

      // 4. Particle Logic
      for (let i = state.particles.length - 1; i >= 0; i--) {
        const p = state.particles[i];
        p.x += p.vx;
        p.y += p.vy;
        p.rotation += p.spin;
        p.life -= 0.05;
        if (p.life <= 0) state.particles.splice(i, 1);
      }

      // Sync to Render State
      setRenderState({
        tanks: [...state.tanks],
        bullets: [...state.bullets],
        particles: [...state.particles],
        blocks: state.blocks, // Reference is fine here as we splice it, but React needs new array ref to detect change if using memo, but here we force setRenderState
        shake: { ...state.shake },
      });

      requestID = requestAnimationFrame(update);
    };

    requestID = requestAnimationFrame(update);
    return () => cancelAnimationFrame(requestID);
  }, []);

  // ------------------- Memoized SVG Parts -------------------

  // Pre-calculate block layers to avoid sorting every frame in render
  // Note: For depth sorting, we would need Z-index, but SVG is painter's algorithm.
  // Standard order: Floor -> Steel/Wall/Base -> Tanks -> Bullets -> Bushes -> Particles
  
  const wallsAndSteel = useMemo(() => renderState.blocks.filter(b => b.type === 'wall' || b.type === 'steel' || b.type === 'base'), [renderState.blocks]);
  const bushes = useMemo(() => renderState.blocks.filter(b => b.type === 'bush'), [renderState.blocks]);

  return (
    <div style={{ 
      width: '100%', 
      height: '100vh', 
      display: 'flex', 
      justifyContent: 'center', 
      alignItems: 'center', 
      backgroundColor: '#000' 
    }}>
      <svg 
        viewBox={`0 0 ${VIEW_WIDTH} ${VIEW_HEIGHT}`} 
        style={{ 
          maxWidth: '100%', 
          maxHeight: '100%', 
          backgroundColor: '#111827', // Dark gray matte battlefield
          boxShadow: '0 0 50px rgba(0,0,0,0.5)',
          overflow: 'hidden'
        }}
      >
        <defs>
          {/* Noise Texture for Ground */}
          <filter id="noiseFilter">
            <feTurbulence type="fractalNoise" baseFrequency="0.8" numOctaves="3" stitchTiles="stitch" />
            <feColorMatrix type="saturate" values="0" />
            <feComponentTransfer>
              <feFuncA type="linear" slope="0.1" />
            </feComponentTransfer>
          </filter>
          
          {/* Metal Texture for Steel */}
          <pattern id="steelPattern" width="10" height="10" patternUnits="userSpaceOnUse">
             <rect width="10" height="10" fill="#a0a5ad"/>
             <path d="M0,10 L10,0" stroke="#bcc2ca" strokeWidth="1" />
          </pattern>

          {/* Brick Texture */}
          <pattern id="brickPattern" width="20" height="20" patternUnits="userSpaceOnUse">
            <rect width="20" height="20" fill="#8d3a3a"/>
            <path d="M0,0 L20,0 M0,10 L20,10 M10,0 L10,10 M0,10 L0,20 M20,10 L20,20" stroke="#632626" strokeWidth="2"/>
          </pattern>

          {/* Glow Effect */}
          <filter id="glow">
            <feGaussianBlur stdDeviation="2.5" result="coloredBlur"/>
            <feMerge>
              <feMergeNode in="coloredBlur"/>
              <feMergeNode in="SourceGraphic"/>
            </feMerge>
          </filter>

          {/* Drop Shadow */}
          <filter id="dropShadow">
            <feGaussianBlur in="SourceAlpha" stdDeviation="3"/>
            <feOffset dx="2" dy="2" result="offsetblur"/>
            <feComponentTransfer>
              <feFuncA type="linear" slope="0.5"/>
            </feComponentTransfer>
            <feMerge>
              <feMergeNode in="offsetblur"/>
              <feMergeNode in="SourceGraphic"/>
            </feMerge>
          </filter>
        </defs>

        {/* Global Shake Transform */}
        <g transform={`translate(${renderState.shake.x}, ${renderState.shake.y})`}>
          
          {/* Background Texture Overlay */}
          <rect width="100%" height="100%" fill="transparent" filter="url(#noiseFilter)" opacity="0.4" />

          {/* Grid Lines (Subtle) */}
          <pattern id="grid" width={CELL_SIZE} height={CELL_SIZE} patternUnits="userSpaceOnUse">
            <path d={`M ${CELL_SIZE} 0 L 0 0 0 ${CELL_SIZE}`} fill="none" stroke="#1f2937" strokeWidth="1"/>
          </pattern>
          <rect width="100%" height="100%" fill="url(#grid)" />

          {/* Static Blocks (Walls, Steel, Base) */}
          {wallsAndSteel.map(block => (
            <g key={block.id} transform={`translate(${block.x}, ${block.y})`}>
              {block.type === 'wall' && (
                <rect width={block.w} height={block.h} fill="url(#brickPattern)" stroke="#522" strokeWidth="1" />
              )}
              {block.type === 'steel' && (
                <rect width={block.w} height={block.h} fill="url(#steelPattern)" stroke="#787e87" strokeWidth="1" />
              )}
              {block.type === 'base' && (
                <g>
                  <rect width={block.w} height={block.h} fill="#111" />
                  {/* Breathing Eagle Icon */}
                  <g transform={`translate(${block.w/2}, ${block.h/2})`}>
                     <circle r={block.w/2 - 2} fill="none" stroke="#ffd700" strokeWidth="2" opacity="0.5">
                       <animate attributeName="opacity" values="0.2;0.8;0.2" dur="2s" repeatCount="indefinite" />
                       <animate attributeName="r" values={`${block.w/2 - 4};${block.w/2 - 1};${block.w/2 - 4}`} dur="2s" repeatCount="indefinite" />
                     </circle>
                     <path d="M-10,-5 Q0,-15 10,-5 L8,5 Q0,15 -8,5 Z" fill="#ffd700" filter="url(#glow)" />
                  </g>
                </g>
              )}
            </g>
          ))}

          {/* Tanks */}
          {renderState.tanks.map(tank => (
            <g key={tank.id} transform={`translate(${tank.x}, ${tank.y})`} filter="url(#dropShadow)">
              <g transform={`rotate(${tank.dir * 90}, ${tank.w/2}, ${tank.h/2})`}>
                {/* Tracks */}
                <rect x="-2" y="2" width="8" height={tank.h-4} fill="#333" />
                <rect x={tank.w-6} y="2" width="8" height={tank.h-4} fill="#333" />
                {/* Track Animation Detail */}
                <line x1="2" y1={2 + tank.trackOffset % 6} x2="2" y2={tank.h-2} stroke="#111" strokeDasharray="4 2" strokeWidth="4" opacity="0.5" />
                <line x1={tank.w-2} y1={2 + tank.trackOffset % 6} x2={tank.w-2} y2={tank.h-2} stroke="#111" strokeDasharray="4 2" strokeWidth="4" opacity="0.5" />

                {/* Body */}
                <rect x="4" y="4" width={tank.w-8} height={tank.h-8} rx="2" fill={tank.color} stroke={tank.colorDark} strokeWidth="2" />
                
                {/* Turret */}
                <g transform={`translate(${tank.w/2}, ${tank.h/2}) rotate(${tank.turretAngle - tank.dir * 90})`}>
                  <rect x="-3" y="-18" width="6" height="20" fill={tank.colorDark} />
                  <rect x="-2" y="-18" width="4" height="18" fill={tank.color} />
                  {/* Muzzle Highlight */}
                  <rect x="-3" y="-18" width="6" height="2" fill="#fff" opacity="0.5" />
                  
                  <circle r="9" fill={tank.color} stroke={tank.colorDark} strokeWidth="2" />
                  <circle r="4" fill={tank.colorDark} opacity="0.5" cx="2" cy="-2" />
                </g>
              </g>
            </g>
          ))}

          {/* Bullets */}
          {renderState.bullets.map(b => (
            <g key={b.id} transform={`translate(${b.x}, ${b.y})`} filter="url(#glow)">
               {/* Motion Trail */}
               <line x1={-b.dx * 2} y1={-b.dy * 2} x2="0" y2="0" stroke="#ff9f43" strokeWidth="4" opacity="0.4" strokeLinecap="round" />
               <circle r="4" fill="#fff" />
               <circle r="6" fill="none" stroke="#ff9f43" strokeWidth="2" />
            </g>
          ))}

          {/* Particles */}
          {renderState.particles.map(p => (
            <g key={p.id} transform={`translate(${p.x}, ${p.y}) rotate(${p.rotation})`} opacity={p.life}>
               {p.w > 4 ? (
                 // Debris (Rects)
                 <rect x={-p.w/2} y={-p.h/2} width={p.w} height={p.h} fill={p.color} />
               ) : (
                 // Dust (Circles)
                 <circle r={p.w} fill={p.color} />
               )}
            </g>
          ))}

          {/* Bushes (Overlay Layer) */}
          {bushes.map(bush => (
            <g key={bush.id} transform={`translate(${bush.x}, ${bush.y})`} opacity="0.85">
               <rect width={bush.w} height={bush.h} fill="#2ecc71" opacity="0.2" />
               <path d="M5,10 Q10,0 15,10 T25,10 T35,10" stroke="#27ae60" strokeWidth="2" fill="none" />
               <path d="M5,20 Q10,10 15,20 T25,20 T35,20" stroke="#27ae60" strokeWidth="2" fill="none" />
               <path d="M5,30 Q10,20 15,30 T25,30 T35,30" stroke="#27ae60" strokeWidth="2" fill="none" />
               {/* Pixelated edges simulation */}
               <rect x="0" y="0" width="4" height="4" fill="#2ecc71" />
               <rect x="36" y="36" width="4" height="4" fill="#2ecc71" />
               <rect x="36" y="0" width="4" height="4" fill="#2ecc71" />
               <rect x="0" y="36" width="4" height="4" fill="#2ecc71" />
            </g>
          ))}
        </g>

        {/* HUD / Overlay Text */}
        <text x="20" y="30" fill="#fff" fontFamily="monospace" fontSize="16" fontWeight="bold" letterSpacing="2">BATTLE CITY: NEO</text>
        <text x="20" y="50" fill="#666" fontFamily="monospace" fontSize="12">PLAYER 1 START</text>

      </svg>
    </div>
  );
};26:T4c36,<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>地球往事：三体三部曲全景导览</title>
    <!-- Core Dependencies -->
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&family=Noto+Sans+SC:wght@300;400;700&display=swap" rel="stylesheet">
    
    <!-- Design System Override -->
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    fontFamily: { 
                        sans: ['Inter', 'Noto Sans SC', 'sans-serif'],
                        mono: ['Fira Code', 'monospace']
                    },
                    colors: {
                        space: {
                            950: '#020617',
                            900: '#0f172a',
                            800: '#1e293b',
                        },
                        trisolaris: '#ff4d4d',
                        earth: '#3b82f6',
                        forest: '#10b981'
                    },
                    animation: {
                        'pulse-slow': 'pulse 4s cubic-bezier(0.4, 0, 0.6, 1) infinite',
                        'float': 'float 6s ease-in-out infinite',
                    },
                    keyframes: {
                        float: {
                            '0%, 100%': { transform: 'translateY(0)' },
                            '50%': { transform: 'translateY(-20px)' },
                        }
                    }
                }
            }
        }
    </script>
    <style>
        body { 
            background-color: #020617;
            color: #e2e8f0;
            overflow-x: hidden;
        }
        .glass-card {
            background: rgba(30, 41, 59, 0.7);
            backdrop-filter: blur(12px);
            border: 1px solid rgba(255, 255, 255, 0.1);
        }
        .star-bg {
            position: fixed;
            top: 0; left: 0; width: 100%; height: 100%;
            z-index: -1;
            background: radial-gradient(circle at center, #1e293b 0%, #020617 100%);
        }
        .glow-text {
            text-shadow: 0 0 15px rgba(59, 130, 246, 0.5);
        }
        .book-tab.active {
            border-bottom: 3px solid #3b82f6;
            color: #3b82f6;
        }
        ::-webkit-scrollbar { width: 4px; }
        ::-webkit-scrollbar-thumb { background: #334155; border-radius: 10px; }
    </style>
</head>
<body class="font-sans">
    <div class="star-bg" id="starfield"></div>

    <!-- Navigation -->
    <nav class="sticky top-0 z-50 glass-card border-b border-white/10 px-6 py-4">
        <div class="max-w-7xl mx-auto flex justify-between items-center">
            <div class="flex items-center space-x-3">
                <div class="w-10 h-10 bg-blue-600 rounded-full flex items-center justify-center animate-pulse">
                    <i class="fas fa-atom text-white"></i>
                </div>
                <span class="text-xl font-bold tracking-tighter uppercase">Remembrance of Earth's Past</span>
            </div>
            <div class="hidden md:flex space-x-8 text-sm font-medium">
                <a href="#overview" class="hover:text-blue-400 transition">概览</a>
                <a href="#trilogy" class="hover:text-blue-400 transition">三部曲</a>
                <a href="#concepts" class="hover:text-blue-400 transition">核心概念</a>
                <a href="#characters" class="hover:text-blue-400 transition">关键人物</a>
            </div>
        </div>
    </nav>

    <!-- Hero Section -->
    <header class="relative h-[80vh] flex items-center justify-center overflow-hidden">
        <div class="absolute inset-0 z-0">
            <img src="https://images.unsplash.com/photo-1462331940025-496dfbfc7564?auto=format&fit=crop&w=2000&q=80" 
                 class="w-full h-full object-cover opacity-30 scale-110" alt="Cosmos">
        </div>
        <div class="relative z-10 text-center px-4 max-w-4xl">
            <h1 class="text-5xl md:text-8xl font-bold mb-6 glow-text tracking-tight">三体</h1>
            <p class="text-xl md:text-2xl text-slate-300 font-light leading-relaxed mb-8">
                “给时光以生命，给岁月以文明。” —— 刘慈欣史诗级科幻巨作
            </p>
            <div class="flex flex-wrap justify-center gap-4">
                <button onclick="document.getElementById('trilogy').scrollIntoView({behavior:'smooth'})" class="px-8 py-3 bg-blue-600 hover:bg-blue-700 rounded-full font-semibold transition transform hover:scale-105">
                    开启探索
                </button>
                <button class="px-8 py-3 bg-white/10 hover:bg-white/20 rounded-full font-semibold backdrop-blur-md transition">
                    了解作者
                </button>
            </div>
        </div>
        <!-- Floating Elements -->
        <div class="absolute bottom-10 left-1/2 -translate-x-1/2 animate-bounce text-slate-500">
            <i class="fas fa-chevron-down text-2xl"></i>
        </div>
    </header>

    <main class="max-w-7xl mx-auto px-6 py-20 space-y-32">
        
        <!-- Trilogy Section -->
        <section id="trilogy">
            <div class="flex flex-col md:flex-row justify-between items-end mb-12 gap-4">
                <div>
                    <h2 class="text-3xl font-bold mb-2">三部曲全景</h2>
                    <p class="text-slate-400">从红岸基地到宇宙的终结</p>
                </div>
                <div class="flex space-x-2 glass-card p-1 rounded-xl">
                    <button onclick="switchBook(1)" id="btn-1" class="book-tab active px-6 py-2 rounded-lg transition">I. 三体</button>
                    <button onclick="switchBook(2)" id="btn-2" class="book-tab px-6 py-2 rounded-lg transition">II. 黑暗森林</button>
                    <button onclick="switchBook(3)" id="btn-3" class="book-tab px-6 py-2 rounded-lg transition">III. 死神永生</button>
                </div>
            </div>

            <div id="book-content" class="grid md:grid-cols-2 gap-12 items-center min-h-[400px]">
                <!-- Content injected by JS -->
            </div>
        </section>

        <!-- Core Concepts Grid -->
        <section id="concepts">
            <div class="text-center mb-16">
                <h2 class="text-3xl font-bold mb-4">核心宇宙法则</h2>
                <div class="h-1 w-20 bg-blue-600 mx-auto"></div>
            </div>
            <div class="grid md:grid-cols-3 gap-8">
                <div class="glass-card p-8 rounded-2xl hover:border-blue-500/50 transition group">
                    <div class="w-14 h-14 bg-blue-500/20 rounded-lg flex items-center justify-center mb-6 group-hover:scale-110 transition">
                        <i class="fas fa-tree text-2xl text-blue-400"></i>
                    </div>
                    <h3 class="text-xl font-bold mb-4">黑暗森林理论</h3>
                    <p class="text-slate-400 leading-relaxed">宇宙就是一座黑暗森林，每个文明都是带枪的猎人。他人即地狱，任何暴露自己存在的文明都将很快被消灭。</p>
                </div>
                <div class="glass-card p-8 rounded-2xl hover:border-trisolaris/50 transition group">
                    <div class="w-14 h-14 bg-red-500/20 rounded-lg flex items-center justify-center mb-6 group-hover:scale-110 transition">
                        <i class="fas fa-microchip text-2xl text-red-400"></i>
                    </div>
                    <h3 class="text-xl font-bold mb-4">智子 (Sophon)</h3>
                    <p class="text-slate-400 leading-relaxed">三体人将质子改造为智能计算机，锁死了人类的基础物理研究，并实现了对地球的实时全方位监控。</p>
                </div>
                <div class="glass-card p-8 rounded-2xl hover:border-forest/50 transition group">
                    <div class="w-14 h-14 bg-emerald-500/20 rounded-lg flex items-center justify-center mb-6 group-hover:scale-110 transition">
                        <i class="fas fa-layer-group text-2xl text-emerald-400"></i>
                    </div>
                    <h3 class="text-xl font-bold mb-4">维度打击</h3>
                    <p class="text-slate-400 leading-relaxed">高级文明使用“二向箔”等武器将目标空间降维，从三维坍缩至二维，是宇宙中最彻底的毁灭方式。</p>
                </div>
            </div>
        </section>

        <!-- Characters Section -->
        <section id="characters">
            <h2 class="text-3xl font-bold mb-12">关键见证者</h2>
            <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
                <!-- Character Card 1 -->
                <div class="glass-card rounded-2xl overflow-hidden group">
                    <div class="h-48 overflow-hidden">
                        <img src="https://images.unsplash.com/photo-1534447677768-be436bb09401?auto=format&fit=crop&w=800&q=80" class="w-full h-full object-cover group-hover:scale-110 transition duration-500" alt="Ye Wenjie">
                    </div>
                    <div class="p-6">
                        <h4 class="text-xl font-bold mb-1">叶文洁</h4>
                        <p class="text-blue-400 text-sm mb-4">统帅 / 启蒙者</p>
                        <p class="text-slate-400 text-sm">红岸基地的天体物理学家，在绝望中向宇宙发出了第一声呼唤。</p>
                    </div>
                </div>
                <!-- Character Card 2 -->
                <div class="glass-card rounded-2xl overflow-hidden group">
                    <div class="h-48 overflow-hidden">
                        <img src="https://images.unsplash.com/photo-1506318137071-a8e063b4bcc0?auto=format&fit=crop&w=800&q=80" class="w-full h-full object-cover group-hover:scale-110 transition duration-500" alt="Luo Ji">
                    </div>
                    <div class="p-6">
                        <h4 class="text-xl font-bold mb-1">罗辑</h4>
                        <p class="text-blue-400 text-sm mb-4">面壁者 / 执剑人</p>
                        <p class="text-slate-400 text-sm">领悟了黑暗森林法则，以一人之力威慑三体文明，守护地球半个世纪。</p>
                    </div>
                </div>
                <!-- Character Card 3 -->
                <div class="glass-card rounded-2xl overflow-hidden group">
                    <div class="h-48 overflow-hidden">
                        <img src="https://images.unsplash.com/photo-1446776811953-b23d57bd21aa?auto=format&fit=crop&w=800&q=80" class="w-full h-full object-cover group-hover:scale-110 transition duration-500" alt="Cheng Xin">
                    </div>
                    <div class="p-6">
                        <h4 class="text-xl font-bold mb-1">程心</h4>
                        <p class="text-blue-400 text-sm mb-4">第二任执剑人</p>
                        <p class="text-slate-400 text-sm">代表了人类的母性与仁慈，在宇宙终极的抉择面前，她选择了爱。</p>
                    </div>
                </div>
                <!-- Character Card 4 -->
                <div class="glass-card rounded-2xl overflow-hidden group">
                    <div class="h-48 overflow-hidden">
                        <img src="https://images.unsplash.com/photo-1451187580459-43490279c0fa?auto=format&fit=crop&w=800&q=80" class="w-full h-full object-cover group-hover:scale-110 transition duration-500" alt="Zhang Beihai">
                    </div>
                    <div class="p-6">
                        <h4 class="text-xl font-bold mb-1">章北海</h4>
                        <p class="text-blue-400 text-sm mb-4">增援未来特遣军</p>
                        <p class="text-slate-400 text-sm">坚定的逃亡主义者，为人类文明在星际间保留了最后的火种。</p>
                    </div>
                </div>
            </div>
        </section>

        <!-- Interactive Quote Section -->
        <section class="relative py-20 rounded-3xl overflow-hidden">
            <div class="absolute inset-0 bg-gradient-to-r from-blue-900/40 to-purple-900/40 z-0"></div>
            <div class="relative z-10 text-center px-6">
                <i class="fas fa-quote-left text-4xl text-blue-500 mb-8"></i>
                <h2 id="dynamic-quote" class="text-2xl md:text-4xl font-light italic leading-relaxed max-w-4xl mx-auto mb-8">
                    失去人性，失去很多；失去兽性，失去一切。
                </h2>
                <button onclick="refreshQuote()" class="text-blue-400 hover:text-blue-300 transition flex items-center mx-auto space-x-2">
                    <i class="fas fa-sync-alt"></i> <span>换一句名言</span>
                </button>
            </div>
        </section>

    </main>

    <!-- Footer -->
    <footer class="border-t border-white/10 py-12 bg-space-950">
        <div class="max-w-7xl mx-auto px-6 flex flex-col md:flex-row justify-between items-center gap-8">
            <div class="text-center md:text-left">
                <div class="text-2xl font-bold mb-2">地球往事</div>
                <p class="text-slate-500 text-sm">致敬刘慈欣，致敬伟大的想象力。</p>
            </div>
            <div class="flex space-x-6 text-2xl text-slate-400">
                <a href="#" class="hover:text-white transition"><i class="fab fa-github"></i></a>
                <a href="#" class="hover:text-white transition"><i class="fab fa-twitter"></i></a>
                <a href="#" class="hover:text-white transition"><i class="fas fa-envelope"></i></a>
            </div>
            <div class="text-slate-500 text-sm">
                &copy; 2023 三体迷社区. 仅供学习交流使用.
            </div>
        </div>
    </footer>

    <!-- Application Logic -->
    <script>
        const books = {
            1: {
                title: "三体 I",
                subtitle: "地球往事",
                desc: "文化大革命期间，红岸基地的一名天体物理学家叶文洁向宇宙发出了寻找外星文明的信息。四光年外的三体文明收到了信息，并决定入侵地球。人类的命运从此改变。",
                tags: ["红岸基地", "三体游戏", "智子", "古筝行动"],
                img: "https://images.unsplash.com/photo-1614728894747-a83421e2b9c9?auto=format&fit=crop&w=800&q=80",
                color: "text-blue-400"
            },
            2: {
                title: "三体 II",
                subtitle: "黑暗森林",
                desc: "三体舰队向地球进发，智子封锁了人类科技。人类启动“面壁计划”，选出四位面壁者利用三体人思维透明的弱点进行反击。罗辑最终发现了宇宙的黑暗森林法则。",
                tags: ["面壁计划", "水滴", "黑暗森林", "摇篮系统"],
                img: "https://images.unsplash.com/photo-1446776811953-b23d57bd21aa?auto=format&fit=crop&w=800&q=80",
                color: "text-emerald-400"
            },
            3: {
                title: "三体 III",
                subtitle: "死神永生",
                desc: "威慑纪元结束，人类与三体文明的博弈进入最终阶段。程心作为执剑人面临终极抉择。宇宙的真相逐渐揭开：这是一场跨越维度的、永无止境的战争。",
                tags: ["阶梯计划", "掩体计划", "二向箔", "小宇宙"],
                img: "https://images.unsplash.com/photo-1451187580459-43490279c0fa?auto=format&fit=crop&w=800&q=80",
                color: "text-red-400"
            }
        };

        const quotes = [
            "失去人性，失去很多；失去兽性，失去一切。",
            "给时光以生命，给岁月以文明。",
            "弱小和无知不是生存的障碍，傲慢才是。",
            "你的无畏来源于无知。",
            "我消灭你，与你何干？",
            "这是人类的落日。",
            "前进！前进！！不择手段地前进！！！"
        ];

        function switchBook(id) {
            const book = books[id];
            const container = document.getElementById('book-content');
            
            // Update tabs
            document.querySelectorAll('.book-tab').forEach(btn => btn.classList.remove('active'));
            document.getElementById(`btn-${id}`).classList.add('active');

            // Animate content change
            container.style.opacity = 0;
            setTimeout(() => {
                container.innerHTML = `
                    <div class="space-y-6 animate-fade-in">
                        <h3 class="text-4xl font-bold ${book.color}">${book.title}</h3>
                        <h4 class="text-2xl text-slate-300">${book.subtitle}</h4>
                        <p class="text-slate-400 leading-relaxed text-lg">${book.desc}</p>
                        <div class="flex flex-wrap gap-2">
                            ${book.tags.map(tag => `<span class="px-3 py-1 bg-white/5 border border-white/10 rounded-full text-xs text-slate-300">${tag}</span>`).join('')}
                        </div>
                    </div>
                    <div class="relative group">
                        <div class="absolute -inset-4 bg-gradient-to-r from-blue-500 to-purple-600 rounded-2xl blur opacity-20 group-hover:opacity-40 transition"></div>
                        <img src="${book.img}" class="relative rounded-2xl shadow-2xl w-full h-80 object-cover" alt="${book.title}">
                    </div>
                `;
                container.style.opacity = 1;
            }, 200);
        }

        function refreshQuote() {
            const quoteEl = document.getElementById('dynamic-quote');
            const randomQuote = quotes[Math.floor(Math.random() * quotes.length)];
            quoteEl.style.opacity = 0;
            setTimeout(() => {
                quoteEl.innerText = randomQuote;
                quoteEl.style.opacity = 1;
            }, 300);
        }

        // Starfield Animation
        function initStars() {
            const starfield = document.getElementById('starfield');
            const count = 150;
            for (let i = 0; i < count; i++) {
                const star = document.createElement('div');
                const size = Math.random() * 2 + 'px';
                star.style.position = 'absolute';
                star.style.width = size;
                star.style.height = size;
                star.style.backgroundColor = 'white';
                star.style.top = Math.random() * 100 + '%';
                star.style.left = Math.random() * 100 + '%';
                star.style.opacity = Math.random();
                star.style.borderRadius = '50%';
                if (Math.random() > 0.8) {
                    star.classList.add('animate-pulse-slow');
                }
                starfield.appendChild(star);
            }
        }

        // Initialize
        window.onload = () => {
            switchBook(1);
            initStars();
            console.log('Three-Body View Loaded');
        };
    </script>
</body>
</html>27:T2d5e5,<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>深度拆解：大语言模型（LLM）是如何练成的？</title>
  <style>
    :root {
      color-scheme: dark;
      --bg: #202020;
      --fg: #e2e8f0;
      --muted: #94a3b8;
      --card: rgba(255, 255, 255, 0.05);
      --border: rgba(255, 255, 255, 0.12);
      --sv-editor-height: 50vh;
    }
    * { box-sizing: border-box; }
    html, body {
      margin: 0; width: 100%; height: 100%; overflow: hidden;
      background: var(--bg);
      color: var(--fg);
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
    }
    #app { width: 100%; height: 100%; display: flex; flex-direction: column; }
    #viewport { position: relative; flex: 1; min-height: 0; overflow: hidden; }
    #stage { position: relative; width: 100%; height: 100%; overflow: hidden; }
    .scene {
      position: absolute; inset: 0; overflow: hidden;
      opacity: 0; pointer-events: none;
      transform: translateX(var(--scene-enter-offset, 56px)) scale(0.96);
      filter: blur(10px);
      transition: opacity .55s cubic-bezier(.22,1,.36,1), transform .55s cubic-bezier(.22,1,.36,1), filter .45s ease;
      will-change: opacity, transform, filter;
      z-index: 1;
    }
    .scene.scene-active {
      opacity: 1; pointer-events: auto; transform: translateX(0) scale(1); filter: blur(0px); z-index: 3;
    }
    .scene.scene-exit {
      opacity: 0; pointer-events: none;
      transform: translateX(var(--scene-exit-offset, -56px)) scale(0.96);
      filter: blur(10px); z-index: 2;
    }
    .scene-placeholder {
      height: 100%; border: 1px dashed var(--border); border-radius: 20px; background: var(--card);
      display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: var(--muted);
    }
    .sv-scene-root { width: 100%; height: 100%; position: relative; overflow: hidden; }
    .scene-placeholder-title { font-size: 28px; color: var(--fg); font-weight: 700; }
    [data-step] { transition: opacity .35s ease, transform .35s ease, filter .35s ease; }
    #sv-controls {
      background: rgba(19, 19, 19, 0.95);
      border-top: 1px solid rgba(255,255,255,0.08);
      padding: 8px 12px 10px;
      display: flex;
      flex-direction: column;
      gap: 8px;
      backdrop-filter: blur(8px);
      flex-shrink: 0;
    }
    .sv-progress-wrap {
      position: relative;
      height: 22px;
      display: flex;
      align-items: center;
      cursor: pointer;
    }
    .sv-progress-track {
      width: 100%;
      height: 4px;
      border-radius: 999px;
      background: rgba(120, 120, 120, 0.55);
      position: relative;
      overflow: hidden;
    }
    .sv-progress-fill {
      position: absolute;
      left: 0;
      top: 0;
      bottom: 0;
      width: 0%;
      border-radius: 999px;
      background: linear-gradient(90deg, #f97316, #fb923c);
      transition: width 220ms ease;
    }
    .sv-progress-thumb {
      position: absolute;
      top: 50%;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      background: #fff;
      transform: translate(-50%, -50%);
      box-shadow: 0 0 0 1px rgba(0,0,0,0.28);
      pointer-events: none;
    }
    .sv-toolbar {
      display: grid;
      grid-template-columns: 1fr auto 1fr;
      align-items: center;
      gap: 8px;
      min-height: 30px;
    }
    .sv-toolbar-left {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      min-width: 0;
    }
    .sv-toolbar-title {
      font-size: 11px;
      color: #a8b0bb;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-expand-btn {
      width: 20px;
      height: 20px;
      border: none;
      border-radius: 6px;
      background: rgba(255,255,255,0.08);
      color: #cbd5e1;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      flex: 0 0 auto;
      transition: background 140ms ease, color 140ms ease, transform 120ms ease;
    }
    .sv-expand-btn:hover {
      background: rgba(255,255,255,0.15);
      color: #f8fafc;
    }
    .sv-expand-btn:active {
      transform: scale(0.94);
    }
    body:not(.sv-host-can-edit-panel) .sv-expand-btn {
      display: none;
    }
    .sv-play-btn {
      width: 28px;
      height: 28px;
      border: none;
      border-radius: 999px;
      color: #fff;
      background: #f97316;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: transform 120ms ease, background 160ms ease;
    }
    .sv-play-btn:hover { background: #fb923c; }
    .sv-play-btn:active { transform: scale(0.94); }
    .sv-play-btn:disabled { opacity: 0.45; cursor: not-allowed; }
    .sv-status {
      text-align: right;
      font-size: 11px;
      color: #8f98a5;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-scene-grid {
      display: flex;
      align-items: stretch;
      gap: 6px;
      flex-wrap: nowrap;
      overflow: hidden;
    }
    .scene-chip {
      position: relative;
      width: 100%;
      border: none;
      border-bottom: 2px solid transparent;
      border-radius: 8px;
      background: rgba(255,255,255,0.06);
      color: #a3a3a3;
      padding: 7px 6px;
      text-align: center;
      font-size: 11px;
      line-height: 1.1;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      cursor: pointer;
      transition: transform 140ms ease, color 160ms ease, background 160ms ease, border-color 160ms ease;
    }
    .scene-chip-label {
      display: block;
      width: 100%;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .scene-chip-wrap {
      position: relative;
      flex: 1 1 0;
      min-width: 0;
    }
    .scene-chip-retry {
      position: absolute;
      top: 50%;
      right: 4px;
      transform: translateY(-50%);
      width: 24px;
      height: 24px;
      border: none;
      border-radius: 999px;
      background: #f97316;
      color: #fff;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
      opacity: 0;
      pointer-events: none;
      transition: opacity 160ms ease;
      cursor: pointer;
    }
    body.sv-host-can-retry .scene-chip-wrap:hover .scene-chip-retry {
      opacity: 1;
      pointer-events: auto;
    }
    .scene-chip-retry:disabled {
      opacity: 1;
      pointer-events: none;
      background: #f97316;
    }
    .scene-chip-retry-icon {
      width: 18px;
      height: 18px;
      display: block;
    }
    .scene-chip-retry-spinner {
      width: 14px;
      height: 14px;
      aspect-ratio: 1 / 1;
      border: 2px solid #ffffff;
      border-top-color: transparent;
      border-radius: 999px;
      box-sizing: border-box;
      animation: sceneChipSpin 1s linear infinite;
      display: block;
      flex: 0 0 auto;
    }
    @keyframes sceneChipSpin {
      from { transform: rotate(0deg); }
      to { transform: rotate(360deg); }
    }
    .scene-chip:hover { transform: scale(1.02); }
    .scene-chip.is-active {
      color: #fb923c;
      border-bottom-color: #fb923c;
      background: linear-gradient(135deg, rgba(249,115,22,0.2), rgba(168,85,247,0.2));
    }
    .scene-chip.is-failed {
      color: #fca5a5;
      border-bottom-color: rgba(239,68,68,0.95);
      background: rgba(239,68,68,0.12);
    }
    .scene-chip.is-generating {
      color: #fcd34d;
      background: rgba(245,158,11,0.11);
    }
    .sv-editor-overlay {
      position: relative;
      width: 100%;
      height: 0;
      z-index: 40;
      pointer-events: none;
      overflow: hidden;
      transition: height 260ms cubic-bezier(.22,1,.36,1);
    }
    .sv-editor-backdrop {
      position: absolute;
      inset: auto 0 0 0;
      height: 100%;
      background: rgba(0, 0, 0, 0.45);
      opacity: 0;
      transition: opacity 220ms ease;
    }
    .sv-editor-sheet {
      position: absolute;
      left: 0;
      right: 0;
      bottom: 0;
      height: 100%;
      background: rgba(16, 16, 16, 0.96);
      border-top: 1px solid rgba(255,255,255,0.12);
      box-shadow: 0 -14px 30px rgba(0,0,0,0.45);
      transform: translateY(102%);
      transition: transform 260ms cubic-bezier(.22,1,.36,1);
      display: flex;
      flex-direction: column;
    }
    .sv-editor-overlay.is-open {
      pointer-events: auto;
      height: var(--sv-editor-height, 50vh);
    }
    .sv-editor-overlay.is-open .sv-editor-backdrop {
      opacity: 1;
    }
    .sv-editor-overlay.is-open .sv-editor-sheet {
      transform: translateY(0);
    }
    .sv-editor-resize-handle {
      width: 100%;
      height: 14px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: ns-resize;
      flex: 0 0 auto;
      touch-action: none;
    }
    .sv-editor-resize-handle::before {
      content: "";
      width: 52px;
      height: 4px;
      border-radius: 999px;
      background: rgba(148, 163, 184, 0.7);
    }
    .sv-editor-header {
      padding: 10px 12px;
      border-bottom: 1px solid rgba(255,255,255,0.1);
      display: grid;
      grid-template-columns: 1fr auto;
      align-items: center;
      gap: 8px;
    }
    .sv-editor-header-title {
      color: #f1f5f9;
      font-size: 13px;
      font-weight: 600;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-editor-actions {
      display: inline-flex;
      align-items: center;
      gap: 6px;
    }
    .sv-editor-btn {
      border: none;
      border-radius: 8px;
      cursor: pointer;
      font-size: 12px;
      line-height: 1;
      padding: 7px 10px;
      color: #e2e8f0;
      background: rgba(255,255,255,0.1);
      transition: background 120ms ease;
    }
    .sv-editor-btn:hover {
      background: rgba(255,255,255,0.18);
    }
    .sv-editor-btn.is-primary {
      color: #fff;
      background: #f97316;
    }
    .sv-editor-btn.is-primary:hover {
      background: #fb923c;
    }
    .sv-editor-list {
      flex: 1;
      min-height: 0;
      overflow: auto;
      padding: 10px 12px 14px;
      display: grid;
      gap: 10px;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      align-items: start;
      align-content: start;
    }
    .sv-editor-item {
      border: 1px solid rgba(255,255,255,0.12);
      border-radius: 10px;
      background: rgba(255,255,255,0.03);
      padding: 10px;
      display: grid;
      grid-template-rows: auto auto auto;
      gap: 10px;
      align-content: start;
      cursor: pointer;
    }
    .sv-editor-item.is-active {
      border-color: rgba(249,115,22,0.65);
      box-shadow: inset 0 0 0 1px rgba(249,115,22,0.28);
    }
    .sv-editor-item-head {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 8px;
      min-height: 30px;
    }
    .sv-editor-item-title {
      border: none;
      border-radius: 8px;
      color: #fb923c;
      background: rgba(255,255,255,0.08);
      font-size: 12px;
      font-weight: 600;
      padding: 6px 8px;
      cursor: pointer;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      text-align: left;
    }
    .sv-editor-item-title:hover {
      background: rgba(255,255,255,0.14);
    }
    .sv-editor-status {
      color: #94a3b8;
      font-size: 11px;
      white-space: nowrap;
    }
    .sv-editor-status-wrap {
      display: inline-flex;
      align-items: center;
      gap: 6px;
    }
    .scene-chip-retry.sv-editor-retry {
      position: static;
      transform: none;
      opacity: 1;
      pointer-events: auto;
      width: 24px;
      height: 24px;
      flex: 0 0 auto;
    }
    .sv-editor-field {
      display: grid;
      gap: 6px;
    }
    .sv-editor-label {
      color: #a3a3a3;
      font-size: 11px;
      font-weight: 700;
    }
    .sv-editor-textarea {
      width: 100%;
      border-radius: 8px;
      border: 1px solid rgba(255,255,255,0.14);
      background: rgba(0,0,0,0.24);
      color: #f1f5f9;
      font-size: 12px;
      line-height: 1.45;
      padding: 8px 9px;
      resize: none;
      min-height: 110px;
      height: 110px;
    }
    .sv-editor-textarea[data-field="scriptText"] {
      min-height: 84px;
    }
    .sv-editor-textarea:focus {
      outline: none;
      border-color: rgba(249,115,22,0.7);
      box-shadow: 0 0 0 2px rgba(249,115,22,0.18);
    }
    body.sv-theme-light .sv-editor-textarea {
      border-color: rgba(15,23,42,0.18);
      background: rgba(248,250,252,0.92);
      color: #0f172a;
    }
    body.sv-theme-light .sv-editor-textarea:focus {
      border-color: rgba(249,115,22,0.72);
      box-shadow: 0 0 0 2px rgba(249,115,22,0.2);
    }
    .sv-editor-script-view {
      width: 100%;
      color: #e2e8f0;
      font-size: 12px;
      line-height: 1.5;
      white-space: pre-wrap;
      word-break: break-word;
      min-height: 84px;
      max-height: 84px;
      overflow: auto;
    }
    .sv-editor-save-tip {
      color: #fbbf24;
      font-size: 11px;
      opacity: 0;
      transition: opacity 140ms ease;
      justify-self: end;
    }
    .sv-editor-save-tip.is-visible {
      opacity: 1;
    }
    body.sv-theme-light .sv-editor-backdrop {
      background: rgba(15, 23, 42, 0.2);
    }
    body.sv-theme-light .sv-editor-sheet {
      background: rgba(255, 255, 255, 0.98);
      border-top-color: rgba(15, 23, 42, 0.12);
      box-shadow: 0 -14px 30px rgba(15, 23, 42, 0.16);
    }
    body.sv-theme-light .sv-editor-header {
      border-bottom-color: rgba(15, 23, 42, 0.1);
    }
    body.sv-theme-light .sv-editor-header-title {
      color: #0f172a;
    }
    body.sv-theme-light .sv-editor-btn {
      color: #334155;
      background: rgba(15, 23, 42, 0.08);
    }
    body.sv-theme-light .sv-editor-btn:hover {
      background: rgba(15, 23, 42, 0.14);
    }
    body.sv-theme-light .sv-editor-btn.is-primary {
      color: #ffffff;
      background: #f97316;
    }
    body.sv-theme-light .sv-editor-btn.is-primary:hover {
      background: #fb923c;
    }
    body.sv-theme-light .sv-editor-item {
      border-color: rgba(15, 23, 42, 0.12);
      background: rgba(248, 250, 252, 0.95);
    }
    body.sv-theme-light .sv-editor-item.is-active {
      border-color: rgba(249,115,22,0.72);
      box-shadow: inset 0 0 0 1px rgba(249,115,22,0.3);
    }
    body.sv-theme-light .sv-editor-item-title {
      color: #ea580c;
      background: rgba(249, 115, 22, 0.12);
    }
    body.sv-theme-light .sv-editor-item-title:hover {
      background: rgba(249, 115, 22, 0.18);
    }
    body.sv-theme-light .sv-editor-status {
      color: #64748b;
    }
    body.sv-theme-light .sv-editor-label {
      color: #475569;
    }
    body.sv-theme-light .sv-editor-script-view {
      color: #334155;
    }
    body.sv-theme-light .sv-editor-save-tip {
      color: #c2410c;
    }
    body.sv-editor-open #viewport {
      flex: 1 1 calc(100vh - var(--sv-editor-height, 50vh));
      min-height: 0;
    }
    body.sv-editor-open #sv-controls {
      display: none;
    }
    body.sv-recording .sv-toolbar,
    body.sv-recording .sv-scene-grid {
      display: none;
    }
    body.sv-recording #sv-controls {
      display: none;
    }
    body.sv-theme-light .sv-editor-list,
    body.sv-theme-light .sv-editor-script-view,
    body.sv-theme-light .sv-editor-textarea {
      scrollbar-color: rgba(148, 163, 184, 0.85) rgba(226, 232, 240, 0.85);
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar {
      width: 10px;
      height: 10px;
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-track,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-track,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-track {
      background: rgba(226, 232, 240, 0.85);
      border-radius: 999px;
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-thumb,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-thumb,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-thumb {
      background: rgba(148, 163, 184, 0.85);
      border-radius: 999px;
      border: 2px solid rgba(226, 232, 240, 0.85);
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-thumb:hover,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-thumb:hover,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-thumb:hover {
      background: rgba(100, 116, 139, 0.95);
    }
/* scene-01 */
.sv-scene-root-scene-01 .s-scene-01-wrapper{
  position: relative;
  width: 100%;
  height: 100vh;
  background-color: #1B1B1B;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  overflow: hidden;
  color: #FFFFFF;
  font-family: 'Alimama ShuHeiTi', 'Microsoft YaHei', sans-serif;
}.sv-scene-root-scene-01 .s-grid-bg{
  position: absolute;
  inset: 0;
  background-image: 
    linear-gradient(to right, rgba(255,255,255,0.03) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255,255,255,0.03) 1px, transparent 1px);
  background-size: 40px 40px;
  pointer-events: none;
}.sv-scene-root-scene-01 .s-visual-container{
  position: absolute;
  width: 600px;
  height: 600px;
  z-index: 1;
}.sv-scene-root-scene-01 .s-brain-canvas{
  width: 100%;
  height: 100%;
}.sv-scene-root-scene-01 .s-brain-core{
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 120px;
  height: 120px;
  background: radial-gradient(circle, #F53501 0%, transparent 70%);
  opacity: 0.4;
  filter: blur(20px);
  animation: s-breath 3s ease-in-out infinite;
}.sv-scene-root-scene-01 .s-content-layer{
  position: relative;
  z-index: 2;
  text-align: center;
  pointer-events: none;
}.sv-scene-root-scene-01 .s-tag{
  font-size: 14px;
  color: #F53501;
  letter-spacing: 2px;
  margin-bottom: 20px;
  opacity: 0.8;
}.sv-scene-root-scene-01 .s-main-title{
  font-size: 64px;
  font-weight: 900;
  line-height: 1.2;
  margin: 0;
  text-shadow: 0 4px 20px rgba(0,0,0,0.5);
}.sv-scene-root-scene-01 .s-accent-text{
  color: #F53501;
  position: relative;
}.sv-scene-root-scene-01 .s-subtitle{
  font-size: 20px;
  margin-top: 24px;
  color: rgba(255,255,255,0.7);
}.sv-scene-root-scene-01 .s-highlight-box{
  background: #F53501;
  color: #FFFFFF;
  padding: 2px 8px;
  border-radius: 2px;
  font-weight: bold;
}.sv-scene-root-scene-01 .s-ui-decorations .s-data-label{
  position: absolute;
  font-size: 10px;
  font-family: monospace;
  color: rgba(255,255,255,0.4);
  border-left: 2px solid #F53501;
  padding-left: 8px;
}.sv-scene-root-scene-01 .l-top-left{ top: 40px; left: 40px; }.sv-scene-root-scene-01 .l-bottom-right{ bottom: 40px; right: 40px; }.sv-scene-root-scene-01 .s-scanner-line{
  position: absolute;
  width: 100%;
  height: 1px;
  background: linear-gradient(90deg, transparent, #F53501, transparent);
  opacity: 0.2;
  top: 0;
  animation: s-scan 8s linear infinite;
}@keyframes s-breath{
  0%, 100% { transform: translate(-50%, -50%) scale(0.8); opacity: 0.3; }
  50% { transform: translate(-50%, -50%) scale(1.1); opacity: 0.6; }
}@keyframes s-scan{
  0% { top: 0%; } 100% { top: 100%; }
}

/* scene-02 */
.sv-scene-root-scene-02 .s-scene-02-wrapper{
  position: relative;
  width: 100%;
  height: 100vh;
  background: #1B1B1B;
  overflow: hidden;
  font-family: 'Alimama ShuHeiTi', sans-serif;
  color: #fff;
}.sv-scene-root-scene-02 .s-grid-bg{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);
  background-size: 50px 50px;
  pointer-events: none;
}.sv-scene-root-scene-02 .s-layout-container{
  display: flex;
  align-items: center;
  justify-content: space-around;
  height: 100%;
  padding: 0 10%;
  z-index: 2;
}.sv-scene-root-scene-02 /* Cards Animation Step 0 */
.s-input-section{
  flex: 1;
  display: flex;
  justify-content: center;
}.sv-scene-root-scene-02 .s-card-stack{
  display: flex;
  flex-direction: column;
  gap: 20px;
}.sv-scene-root-scene-02 .s-data-card{
  width: 280px;
  padding: 20px;
  background: rgba(255, 255, 255, 0.03);
  backdrop-filter: blur(10px);
  border-left: 4px solid #F53501;
  border-radius: 4px;
  display: flex;
  align-items: center;
  gap: 15px;
  transform: translateX(-150%);
  opacity: 0;
  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
}.sv-scene-root-scene-02 [data-step="0"] .s-data-card{
  transform: translateX(0);
  opacity: 1;
}.sv-scene-root-scene-02 .s-card-book{ transition-delay: 0.1s; }.sv-scene-root-scene-02 .s-card-code{ transition-delay: 0.3s; }.sv-scene-root-scene-02 .s-card-web{ transition-delay: 0.5s; }.sv-scene-root-scene-02 .s-card-icon{ color: #F53501; }.sv-scene-root-scene-02 .s-card-label{ display: block; font-size: 12px; color: rgba(255,255,255,0.4); font-family: monospace; }.sv-scene-root-scene-02 .s-card-val{ font-size: 24px; font-weight: bold; }.sv-scene-root-scene-02 /* Funnel Animation Step 1 */
.s-processing-section{
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
}.sv-scene-root-scene-02 .s-funnel-container{
  position: relative;
  width: 200px;
  height: 260px;
  opacity: 0;
  transform: scale(0.8);
  transition: all 0.6s ease-out;
}.sv-scene-root-scene-02 [data-step="1"] .s-funnel-container{
  opacity: 1;
  transform: scale(1);
}.sv-scene-root-scene-02 .s-funnel-body{
  width: 100%;
  height: 180px;
  background: linear-gradient(180deg, rgba(245, 53, 1, 0.1) 0%, transparent 100%);
  clip-path: polygon(0% 0%, 100% 0%, 60% 100%, 40% 100%);
  border-top: 2px solid #F53501;
  position: relative;
  overflow: hidden;
}.sv-scene-root-scene-02 .s-scan-line{
  position: absolute;
  width: 100%;
  height: 40px;
  background: linear-gradient(to bottom, transparent, rgba(245, 53, 1, 0.4), transparent);
  animation: s-scan-move 2s infinite ease-in-out;
}@keyframes s-scan-move{
  0% { top: -40px; } 100% { top: 100%; }
}.sv-scene-root-scene-02 .s-status-tag{
  margin-top: 20px;
  font-size: 12px;
  letter-spacing: 2px;
  color: #F53501;
  background: rgba(245, 53, 1, 0.1);
  padding: 4px 12px;
  border: 1px solid rgba(245, 53, 1, 0.3);
}.sv-scene-root-scene-02 /* Output Step 2 */
.s-output-section{
  flex: 1;
  display: flex;
  justify-content: center;
}.sv-scene-root-scene-02 .s-disk-grid{
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 15px;
  opacity: 0;
  transform: translateY(20px);
  transition: all 0.5s ease-out;
}.sv-scene-root-scene-02 [data-step="2"] .s-disk-grid{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-02 .s-disk{
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: radial-gradient(circle, #00A3FF 10%, transparent 80%);
  border: 2px solid #00A3FF;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 15px rgba(0, 163, 255, 0.3);
  animation: s-disk-pulse 2s infinite ease-in-out;
}@keyframes s-disk-pulse{
  0%, 100% { opacity: 0.7; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.05); }
}.sv-scene-root-scene-02 .s-overlay-info{
  position: absolute;
  bottom: 60px;
  left: 60px;
  max-width: 500px;
}.sv-scene-root-scene-02 .s-title{
  font-size: 48px;
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  gap: 20px;
}.sv-scene-root-scene-02 .s-num{ color: #F53501; font-family: monospace; border: 1px solid #F53501; padding: 0 10px; }.sv-scene-root-scene-02 .s-desc{ font-size: 18px; color: rgba(255,255,255,0.6); line-height: 1.6; }

/* scene-03 */
.sv-scene-root-scene-03 .s-scene-03-wrapper{
  position: relative;
  width: 100%;
  height: 100vh;
  background: #1B1B1B;
  overflow: hidden;
  color: #fff;
  font-family: 'Alimama ShuHeiTi', sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}.sv-scene-root-scene-03 .s-grid-bg{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px), 
                    linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px);
  background-size: 40px 40px;
  pointer-events: none;
}.sv-scene-root-scene-03 .s-status-bar{
  position: absolute;
  top: 40px;
  left: 60px;
  right: 60px;
  display: flex;
  justify-content: space-between;
  padding-bottom: 10px;
  border-bottom: 1px solid rgba(255,255,255,0.1);
  font-family: monospace;
  font-size: 14px;
  letter-spacing: 2px;
  z-index: 10;
}.sv-scene-root-scene-03 .s-status-item{
  display: flex;
  align-items: center;
  gap: 10px;
}.sv-scene-root-scene-03 .s-status-dot{
  width: 8px;
  height: 8px;
  background: #F53501;
  border-radius: 50%;
  box-shadow: 0 0 10px #F53501;
  animation: s-blink 1s infinite alternate;
}.sv-scene-root-scene-03 .s-status-val{ color: #F53501; }.sv-scene-root-scene-03 .s-main-container{
  width: 80%;
  max-width: 1200px;
  position: relative;
  z-index: 5;
}.sv-scene-root-scene-03 .s-text-stage{
  position: relative;
  min-height: 200px;
  display: flex;
  align-items: center;
  justify-content: center;
}.sv-scene-root-scene-03 .s-original-text{
  font-size: 84px;
  font-weight: 900;
  letter-spacing: 8px;
  white-space: nowrap;
  opacity: 1;
  transition: opacity 0.3s ease;
}.sv-scene-root-scene-03 /* Step 0 打字机 */
[data-step="0"] .s-original-text{
  overflow: hidden;
  border-right: 4px solid #F53501;
  animation: s-typewriter 2s steps(10) forwards, s-cursor 0.8s infinite;
  width: 0;
}@keyframes s-typewriter{ from { width: 0; } to { width: 100%; } }@keyframes s-cursor{ 50% { border-color: transparent; } }.sv-scene-root-scene-03 /* Step 1 逻辑 */
[data-step="1"] .s-original-text{
  opacity: 0;
}.sv-scene-root-scene-03 .s-scanner-line{
  position: absolute;
  left: 0;
  top: -20%;
  width: 4px;
  height: 140%;
  background: #F53501;
  box-shadow: 0 0 30px #F53501, 0 0 60px #F53501;
  opacity: 0;
  z-index: 15;
}.sv-scene-root-scene-03 [data-step="1"] .s-scanner-line{
  animation: s-scan-move 1.5s cubic-bezier(0.45, 0, 0.55, 1) forwards;
  opacity: 1;
}@keyframes s-scan-move{
  0% { left: 0%; opacity: 1; }
  90% { left: 100%; opacity: 1; }
  100% { left: 100%; opacity: 0; }
}.sv-scene-root-scene-03 .s-tokens-grid{
  position: absolute;
  display: flex;
  gap: 20px;
  opacity: 0;
  transform: translateY(20px);
  transition: all 0.5s ease 0.8s;
}.sv-scene-root-scene-03 [data-step="1"] .s-tokens-grid{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-03 .s-token-item{
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 15px;
}.sv-scene-root-scene-03 .s-token-box{
  background: var(--color);
  padding: 15px 30px;
  font-size: 42px;
  font-weight: 900;
  border-radius: 4px;
  color: #000;
  box-shadow: 0 10px 20px rgba(0,0,0,0.3);
  transform: scale(0.9);
  animation: s-pop-in 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
  animation-delay: calc(1s + var(--index) * 0.1s);
}.sv-scene-root-scene-03 .s-token-id{
  font-family: monospace;
  font-size: 18px;
  color: var(--color);
  font-weight: bold;
  opacity: 0;
  animation: s-fade-in 0.3s ease forwards;
  animation-delay: calc(1.5s + var(--index) * 0.1s);
}@keyframes s-pop-in{
  to { transform: scale(1); }
}@keyframes s-fade-in{
  to { opacity: 1; }
}@keyframes s-blink{
  to { opacity: 0.3; }
}.sv-scene-root-scene-03 .s-overlay-info{
  position: absolute;
  bottom: 60px;
  left: 60px;
  max-width: 600px;
}.sv-scene-root-scene-03 .s-title{
  font-size: 48px;
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  gap: 20px;
}.sv-scene-root-scene-03 .s-num{ color: #F53501; border: 1px solid #F53501; padding: 0 10px; font-family: monospace; }.sv-scene-root-scene-03 .s-desc{
  font-size: 18px;
  color: rgba(255,255,255,0.6);
  line-height: 1.6;
  display: none;
}.sv-scene-root-scene-03 [data-step="0"] .s-desc[data-step="0"]{ display: block; }.sv-scene-root-scene-03 [data-step="1"] .s-desc[data-step="1"]{ display: block; }

/* scene-04 */
.sv-scene-root-scene-04 .s-scene-04-wrapper{
  position: relative;
  width: 100%;
  height: 100vh;
  background: #1B1B1B;
  overflow: hidden;
  color: #fff;
  font-family: 'Alimama ShuHeiTi', sans-serif;
  box-sizing: border-box;
}.sv-scene-root-scene-04 .s-scene-04-wrapper *{
  box-sizing: inherit;
}.sv-scene-root-scene-04 .s-grid-bg{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);
  background-size: 60px 60px;
  pointer-events: none;
}.sv-scene-root-scene-04 .s-math-bg{
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1s ease-in-out;
}.sv-scene-root-scene-04 [data-step="1"] .s-math-bg, .sv-scene-root-scene-04 [data-step="2"] .s-math-bg{
  opacity: 1;
}.sv-scene-root-scene-04 .s-math-item{
  position: absolute;
  font-family: 'Times New Roman', serif;
  font-style: italic;
  font-size: 24px;
  color: rgba(255,255,255,0.04);
  white-space: nowrap;
  letter-spacing: 2px;
}.sv-scene-root-scene-04 [data-step="1"] .s-math-item, .sv-scene-root-scene-04 [data-step="2"] .s-math-item{
  animation: s-math-float 10s linear infinite alternate;
}@keyframes s-math-float{
  0% { transform: translateY(0) scale(1); }
  100% { transform: translateY(-20px) scale(1.05); }
}.sv-scene-root-scene-04 .s-main-viewport{
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  padding-bottom: 80px;
}.sv-scene-root-scene-04 .s-layout-container{
  display: flex;
  align-items: center;
  gap: 0px;
  position: relative;
  z-index: 10;
}.sv-scene-root-scene-04 /* 面板通用样式 */
.s-card{
  background: #151515;
  border: 1px solid rgba(255,255,255,0.15);
  border-radius: 6px;
  padding: 24px;
  position: relative;
  box-shadow: 0 20px 40px rgba(0,0,0,0.5);
  backdrop-filter: blur(10px);
}.sv-scene-root-scene-04 .s-card-head{
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: monospace;
  font-size: 14px;
  color: #888;
  margin-bottom: 20px;
  letter-spacing: 1px;
  text-transform: uppercase;
  border-bottom: 1px dashed rgba(255,255,255,0.1);
  padding-bottom: 12px;
}.sv-scene-root-scene-04 .s-card-head.is-red{
  color: #F53501;
  border-bottom-color: rgba(245, 53, 1, 0.3);
}.sv-scene-root-scene-04 .s-dot{
  width: 8px;
  height: 8px;
  background: #fff;
  border-radius: 50%;
  display: inline-block;
}.sv-scene-root-scene-04 /* 端口连接点 */
.s-port{
  position: absolute;
  width: 12px;
  height: 12px;
  background: #1B1B1B;
  border: 2px solid #555;
  border-radius: 50%;
  top: 50%;
  transform: translateY(-50%);
}.sv-scene-root-scene-04 .s-port-right{
  right: -6px;
}.sv-scene-root-scene-04 .s-port-left{
  left: -6px;
}.sv-scene-root-scene-04 [data-step="1"] .s-port-right, .sv-scene-root-scene-04 [data-step="2"] .s-port-right, .sv-scene-root-scene-04 [data-step="2"] .s-port-left{
  border-color: #F53501;
  background: #F53501;
  box-shadow: 0 0 10px rgba(245, 53, 1, 0.5);
}.sv-scene-root-scene-04 /* 左侧输入卡片 */
.s-input-card{
  width: 320px;
  border-left: 4px solid #F53501;
}.sv-scene-root-scene-04 .s-card-body{
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  font-size: 32px;
  font-weight: 900;
  line-height: 1.4;
}.sv-scene-root-scene-04 .s-word{
  display: inline-block;
}.sv-scene-root-scene-04 /* 中间网络区域 */
.s-network-container{
  position: relative;
  width: 300px;
  height: 400px;
}.sv-scene-root-scene-04 .s-net-svg{
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
}.sv-scene-root-scene-04 .s-lines-base path{
  fill: none;
  stroke: rgba(255,255,255,0.08);
  stroke-width: 2;
}.sv-scene-root-scene-04 .s-lines-active path{
  fill: none;
  stroke: #F53501;
  stroke-width: 3;
  stroke-dasharray: 20 40;
  stroke-linecap: round;
  opacity: 0;
  transition: opacity 0.5s ease;
}.sv-scene-root-scene-04 [data-step="1"] .s-lines-active path, .sv-scene-root-scene-04 [data-step="2"] .s-lines-active path{
  opacity: 1;
  animation: s-stroke-flow 1.2s linear infinite;
}@keyframes s-stroke-flow{
  to { stroke-dashoffset: -60; }
}.sv-scene-root-scene-04 .s-node{
  position: absolute;
  width: 16px;
  height: 16px;
  background: #222;
  border: 2px solid #555;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
  transition: all 0.4s ease;
}.sv-scene-root-scene-04 [data-step="1"] .s-node, .sv-scene-root-scene-04 [data-step="2"] .s-node{
  background: #1B1B1B;
  border-color: #F53501;
  box-shadow: 0 0 15px rgba(245, 53, 1, 0.6), inset 0 0 5px #F53501;
}.sv-scene-root-scene-04 /* 右侧输出预测 */
.s-output-card{
  width: 380px;
  opacity: 0;
  transform: translateX(40px);
  transition: all 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275);
  pointer-events: none;
}.sv-scene-root-scene-04 [data-step="2"] .s-output-card{
  opacity: 1;
  transform: translateX(0);
  pointer-events: auto;
}.sv-scene-root-scene-04 .s-prob-list{
  display: flex;
  flex-direction: column;
  gap: 16px;
}.sv-scene-root-scene-04 .s-prob-row{
  display: flex;
  align-items: center;
  gap: 12px;
}.sv-scene-root-scene-04 .s-prob-name{
  width: 60px;
  font-size: 20px;
  font-weight: bold;
  color: #fff;
}.sv-scene-root-scene-04 .s-prob-track{
  flex: 1;
  height: 12px;
  background: rgba(255,255,255,0.05);
  border-radius: 6px;
  overflow: hidden;
  position: relative;
}.sv-scene-root-scene-04 .s-prob-fill{
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  width: 0;
  background: rgba(255,255,255,0.4);
  border-radius: 6px;
  transition: width 1.2s cubic-bezier(0.2, 0.8, 0.2, 1);
}.sv-scene-root-scene-04 [data-step="2"] .s-prob-fill{
  width: var(--p);
}.sv-scene-root-scene-04 .s-prob-num{
  width: 40px;
  text-align: right;
  font-family: monospace;
  font-size: 16px;
  color: rgba(255,255,255,0.6);
}.sv-scene-root-scene-04 /* 高亮目标概率条 */
.s-prob-row.is-target .s-prob-name{
  color: #F53501;
}.sv-scene-root-scene-04 .s-prob-row.is-target .s-prob-fill{
  background: #F53501;
}.sv-scene-root-scene-04 .s-prob-row.is-target .s-prob-num{
  color: #F53501;
  font-weight: bold;
}.sv-scene-root-scene-04 [data-step="2"] .s-prob-row.is-target .s-prob-fill{
  animation: s-prob-blink 1.2s infinite alternate ease-in-out;
  animation-delay: 1.2s;
}@keyframes s-prob-blink{
  0% { box-shadow: 0 0 2px #F53501; opacity: 0.8; }
  100% { box-shadow: 0 0 20px #F53501; opacity: 1; }
}.sv-scene-root-scene-04 /* 底部字幕区 */
.s-overlay-info{
  position: absolute;
  bottom: 60px;
  left: 60px;
  max-width: 600px;
  z-index: 20;
}.sv-scene-root-scene-04 .s-title{
  font-size: 48px;
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  gap: 20px;
}.sv-scene-root-scene-04 .s-num{
  color: #F53501;
  font-family: monospace;
  border: 1px solid #F53501;
  padding: 0 10px;
}.sv-scene-root-scene-04 .s-desc-container{
  position: relative;
  height: 60px;
}.sv-scene-root-scene-04 .s-desc{
  position: absolute;
  left: 0;
  top: 0;
  font-size: 20px;
  color: rgba(255,255,255,0.7);
  line-height: 1.6;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.4s ease, transform 0.4s ease;
  pointer-events: none;
}.sv-scene-root-scene-04 [data-step="0"] .s-desc[data-target="0"], .sv-scene-root-scene-04 [data-step="1"] .s-desc[data-target="1"], .sv-scene-root-scene-04 [data-step="2"] .s-desc[data-target="2"]{
  opacity: 1;
  transform: translateY(0);
}

/* scene-05 */
.sv-scene-root-scene-05 .s-scene-05-wrapper{
  position: relative;
  width: 100%;
  height: 100vh;
  background: #1B1B1B;
  overflow: hidden;
  color: #fff;
  font-family: 'Alimama ShuHeiTi', sans-serif;
}.sv-scene-root-scene-05 .s-grid-bg{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);
  background-size: 60px 60px;
  pointer-events: none;
}.sv-scene-root-scene-05 .s-main-viewport{
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
}.sv-scene-root-scene-05 .s-network-stage{
  position: relative;
  width: 800px;
  height: 400px;
}.sv-scene-root-scene-05 .s-network-svg{
  width: 100%;
  height: 100%;
}.sv-scene-root-scene-05 .s-conn-line{
  fill: none;
  stroke: rgba(255,255,255,0.15);
  stroke-width: 2;
  transition: stroke-width 0.6s ease, stroke 0.6s ease;
}.sv-scene-root-scene-05 .s-node{
  position: absolute;
  width: 24px;
  height: 24px;
  background: #fff;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  box-shadow: 0 0 15px rgba(255,255,255,0.2);
  z-index: 2;
}.sv-scene-root-scene-05 /* Step 0: Error Styling */
.s-error-callout{
  position: absolute;
  right: 0;
  top: 100px;
  width: 180px;
  background: #F53501;
  color: #fff;
  padding: 12px;
  border-radius: 4px;
  box-shadow: 0 10px 30px rgba(245, 53, 1, 0.4);
  animation: s-error-pop 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
  z-index: 10;
}@keyframes s-error-pop{
  0% { transform: scale(0.5) translate(20px, -20px); opacity: 0; }
  100% { transform: scale(1) translate(0, 0); opacity: 1; }
}.sv-scene-root-scene-05 .s-error-header{
  font-weight: 900;
  font-size: 20px;
  border-bottom: 2px solid rgba(255,255,255,0.3);
  margin-bottom: 8px;
  padding-bottom: 4px;
}.sv-scene-root-scene-05 .s-error-body{
  font-size: 14px;
  font-family: monospace;
}.sv-scene-root-scene-05 .s-error-row{
  display: flex;
  justify-content: space-between;
  margin-bottom: 4px;
}.sv-scene-root-scene-05 .s-error-diff{
  margin-top: 8px;
  font-weight: bold;
  text-align: right;
}.sv-scene-root-scene-05 .s-error-arrow{
  position: absolute;
  left: -10px;
  top: 50%;
  width: 0; height: 0;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
  border-right: 10px solid #F53501;
  transform: translateY(-50%);
}.sv-scene-root-scene-05 /* Step 1: Backprop Animation */
.is-backpropagating .s-conn-line{
  stroke-dasharray: 200;
  stroke-dashoffset: 0;
  animation: s-back-pulse 2s infinite linear;
  stroke: #F53501;
}.sv-scene-root-scene-05 .is-backpropagating .s-conn-line:nth-child(even){
  stroke-width: 6; /* Thicker weight update representation */
}.sv-scene-root-scene-05 .is-backpropagating .s-conn-line:nth-child(odd){
  stroke-width: 1; /* Thinner weight update representation */
}@keyframes s-back-pulse{
  0% { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: 400; } /* Negative for back direction */
}.sv-scene-root-scene-05 .s-overlay-info{
  position: absolute;
  bottom: 60px;
  left: 60px;
  max-width: 600px;
}.sv-scene-root-scene-05 .s-title{
  font-size: 48px;
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  gap: 20px;
}.sv-scene-root-scene-05 .s-num{
  color: #F53501;
  font-family: monospace;
  border: 1px solid #F53501;
  padding: 0 10px;
}.sv-scene-root-scene-05 .s-desc{
  font-size: 18px;
  color: rgba(255,255,255,0.7);
  line-height: 1.6;
  margin-top: 10px;
  display: none;
}.sv-scene-root-scene-05 [data-step="0"] .s-desc[data-step="0"], .sv-scene-root-scene-05 [data-step="1"] .s-desc[data-step="1"]{
  display: block;
}

/* scene-06 */
.sv-scene-root-scene-06 .s-scene-06-wrapper{
  position: relative;
  width: 100%;
  height: 100vh;
  background: #1B1B1B;
  overflow: hidden;
  color: #fff;
  font-family: 'Alimama ShuHeiTi', sans-serif;
}.sv-scene-root-scene-06 .s-grid-bg{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px);
  background-size: 50px 50px;
  pointer-events: none;
}.sv-scene-root-scene-06 .s-main-viewport{
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  padding: 40px;
}.sv-scene-root-scene-06 .s-chat-interface{
  width: 100%;
  max-width: 900px;
  display: flex;
  flex-direction: column;
  gap: 40px;
}.sv-scene-root-scene-06 .s-chat-row{
  display: flex;
  gap: 20px;
  opacity: 0;
  transform: translateY(20px);
  transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}.sv-scene-root-scene-06 [data-step="0"] .s-user-row, .sv-scene-root-scene-06 [data-step="1"] .s-ai-row{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-06 .s-avatar{
  width: 48px;
  height: 48px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-weight: 900;
}.sv-scene-root-scene-06 .s-user-avatar{
  background: #444;
  color: #fff;
}.sv-scene-root-scene-06 .s-ai-avatar{
  background: #F53501;
  color: #fff;
  box-shadow: 0 0 20px rgba(245, 53, 1, 0.3);
}.sv-scene-root-scene-06 .s-bubble-wrap{
  flex-grow: 1;
  position: relative;
}.sv-scene-root-scene-06 .s-bubble-tag{
  font-size: 12px;
  color: #F53501;
  margin-bottom: 8px;
  letter-spacing: 1px;
  font-family: monospace;
}.sv-scene-root-scene-06 .s-bubble{
  padding: 24px;
  border-radius: 4px 20px 20px 20px;
  font-size: 24px;
  line-height: 1.4;
  background: rgba(255, 255, 255, 0.05);
  border-left: 4px solid #F53501;
  box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}.sv-scene-root-scene-06 .s-ai-bubble{
  font-size: 32px;
  font-weight: bold;
  background: rgba(245, 53, 1, 0.05);
  min-height: 160px;
  color: #fff;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}.sv-scene-root-scene-06 .s-char{
  display: inline-block;
  animation: s-pop-in 0.2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
  opacity: 0;
  transform: scale(0.5);
}@keyframes s-pop-in{
  to { opacity: 1; transform: scale(1); }
}.sv-scene-root-scene-06 .s-golden-sweep{
  position: absolute;
  inset: 0;
  background: linear-gradient(110deg, transparent 30%, rgba(245, 53, 1, 0.1) 45%, rgba(245, 53, 1, 0.3) 50%, rgba(245, 53, 1, 0.1) 55%, transparent 70%);
  background-size: 200% 100%;
  pointer-events: none;
  z-index: 5;
  opacity: 0;
}.sv-scene-root-scene-06 .is-sweeping .s-golden-sweep{
  animation: s-sweep 1.5s ease-in-out infinite;
  opacity: 1;
}@keyframes s-sweep{
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}.sv-scene-root-scene-06 .s-overlay-info{
  position: absolute;
  bottom: 60px;
  left: 60px;
  max-width: 600px;
}.sv-scene-root-scene-06 .s-title{
  font-size: 48px;
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  gap: 20px;
}.sv-scene-root-scene-06 .s-num{
  color: #F53501;
  font-family: monospace;
  border: 1px solid #F53501;
  padding: 0 10px;
}.sv-scene-root-scene-06 .s-desc{
  font-size: 18px;
  color: rgba(255,255,255,0.7);
  line-height: 1.6;
  margin-top: 10px;
  display: none;
}.sv-scene-root-scene-06 [data-step="0"] .s-desc[data-step="0"], .sv-scene-root-scene-06 [data-step="1"] .s-desc[data-step="1"]{
  display: block;
}

/* scene-07 */
.sv-scene-root-scene-07 .s-scene-07-wrapper{
  position: relative;
  width: 100%;
  height: 100vh;
  background: #1B1B1B;
  overflow: hidden;
  color: #fff;
  font-family: 'Alimama ShuHeiTi', sans-serif;
}.sv-scene-root-scene-07 .s-grid-bg{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px);
  background-size: 50px 50px;
  pointer-events: none;
}.sv-scene-root-scene-07 .s-main-viewport{
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  padding: 40px;
}.sv-scene-root-scene-07 .s-rlhf-container{
  width: 100%;
  max-width: 800px;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
}.sv-scene-root-scene-07 .s-selection-label{
  font-size: 14px;
  color: #F53501;
  letter-spacing: 2px;
  margin-bottom: 20px;
  opacity: 0;
  transform: translateY(-10px);
  transition: all 0.5s ease;
}.sv-scene-root-scene-07 [data-step="0"] .s-selection-label, .sv-scene-root-scene-07 [data-step="1"] .s-selection-label, .sv-scene-root-scene-07 [data-step="2"] .s-selection-label{ opacity: 1; transform: translateY(0); }.sv-scene-root-scene-07 .s-options-stack{
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 20px;
}.sv-scene-root-scene-07 .s-option-card{
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 30px;
  border-radius: 4px;
  position: relative;
  transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);
  opacity: 0;
  transform: translateX(-30px);
}.sv-scene-root-scene-07 .s-option-card[data-step="0"]{ opacity: 1; transform: translateX(0); }.sv-scene-root-scene-07 .s-option-card[data-step="1"]{ opacity: 1; transform: translateX(0); }.sv-scene-root-scene-07 .s-option-card[data-step="2"]{ opacity: 1; transform: translateX(0); }.sv-scene-root-scene-07 .s-option-header{
  display: flex;
  justify-content: space-between;
  margin-bottom: 15px;
}.sv-scene-root-scene-07 .s-option-tag{
  font-size: 12px;
  color: rgba(255,255,255,0.4);
  font-family: monospace;
}.sv-scene-root-scene-07 .s-status-dot{
  width: 8px;
  height: 8px;
  background: #444;
  border-radius: 50%;
}.sv-scene-root-scene-07 .s-option-content{
  font-size: 20px;
  line-height: 1.5;
  color: rgba(255,255,255,0.8);
}.sv-scene-root-scene-07 /* Step Transitions */
.s-scene-07-wrapper[data-step="2"] .s-option-a{
  opacity: 0.1;
  filter: blur(4px);
  transform: scale(0.95);
}.sv-scene-root-scene-07 .s-scene-07-wrapper[data-step="2"] .s-option-b{
  border-color: #00FF66;
  background: rgba(0, 255, 102, 0.05);
  transform: scale(1.05);
  z-index: 10;
}.sv-scene-root-scene-07 .s-success-border{
  position: absolute;
  inset: 0;
  border: 2px solid #00FF66;
  opacity: 0;
  border-radius: 4px;
  pointer-events: none;
}.sv-scene-root-scene-07 .s-scene-07-wrapper[data-step="2"] .s-success-border{
  animation: s-border-pulse 2s infinite;
}@keyframes s-border-pulse{
  0% { opacity: 0.5; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.01); }
  100% { opacity: 0.5; transform: scale(1); }
}.sv-scene-root-scene-07 .s-feedback-cursor{
  position: absolute;
  right: -20px;
  bottom: 60px;
  z-index: 100;
  color: #F53501;
  filter: drop-shadow(0 0 15px rgba(245, 53, 1, 0.5));
  opacity: 0;
  transform: translate(50px, 50px) scale(1.5);
  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
  pointer-events: none;
}.sv-scene-root-scene-07 .s-scene-07-wrapper[data-step="1"] .s-feedback-cursor{
  opacity: 1;
  transform: translate(0, 0) scale(1.2);
}.sv-scene-root-scene-07 .s-scene-07-wrapper[data-step="2"] .s-feedback-cursor{
  opacity: 1;
  transform: translate(-40px, -20px) scale(1.4);
  color: #00FF66;
}.sv-scene-root-scene-07 .s-hand-icon{
  width: 60px;
  height: 60px;
}.sv-scene-root-scene-07 .s-particle-canvas{
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 20;
}.sv-scene-root-scene-07 .s-particle{
  position: absolute;
  width: 6px;
  height: 6px;
  background: #00FF66;
  border-radius: 50%;
  opacity: 0;
}.sv-scene-root-scene-07 .s-overlay-info{
  position: absolute;
  bottom: 60px;
  left: 60px;
  max-width: 600px;
}.sv-scene-root-scene-07 .s-title{
  font-size: 48px;
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  gap: 20px;
}.sv-scene-root-scene-07 .s-num{
  color: #F53501;
  font-family: monospace;
  border: 1px solid #F53501;
  padding: 0 10px;
}.sv-scene-root-scene-07 .s-desc{
  font-size: 18px;
  color: rgba(255,255,255,0.7);
  line-height: 1.6;
  margin-top: 10px;
  display: none;
}.sv-scene-root-scene-07 .s-scene-07-wrapper[data-step="0"] .s-desc[data-step="0"], .sv-scene-root-scene-07 .s-scene-07-wrapper[data-step="1"] .s-desc[data-step="1"], .sv-scene-root-scene-07 .s-scene-07-wrapper[data-step="2"] .s-desc[data-step="2"]{
  display: block;
}

/* scene-08 */
.sv-scene-root-scene-08 .s-scene-08-wrapper{
  position: relative;
  width: 100%;
  height: 100vh;
  background: #1B1B1B;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  font-family: 'Alimama ShuHeiTi', sans-serif;
  color: #FFFFFF;
}.sv-scene-root-scene-08 .s-grid-bg{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);
  background-size: 50px 50px;
  pointer-events: none;
}.sv-scene-root-scene-08 .s-core-container{
  position: relative;
  width: 500px;
  height: 500px;
  display: flex;
  justify-content: center;
  align-items: center;
}.sv-scene-root-scene-08 .s-radial-glow{
  position: absolute;
  width: 600px;
  height: 600px;
  background: radial-gradient(circle, rgba(245, 53, 1, 0.15) 0%, transparent 70%);
  opacity: 0;
  transform: scale(0.5);
  transition: all 1s cubic-bezier(0.23, 1, 0.32, 1);
}.sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="0"] .s-radial-glow, .sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="1"] .s-radial-glow, .sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="2"] .s-radial-glow{ opacity: 1; transform: scale(1.2); }.sv-scene-root-scene-08 .s-ai-core-group{
  position: relative;
  width: 240px;
  height: 240px;
  opacity: 0;
  transform: scale(0.5);
  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
}.sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="0"] .s-ai-core-group, .sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="1"] .s-ai-core-group, .sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="2"] .s-ai-core-group{ opacity: 1; transform: scale(1); }.sv-scene-root-scene-08 .s-core-hex{
  position: relative;
  z-index: 2;
  filter: drop-shadow(0 0 30px rgba(245, 53, 1, 0.3));
}.sv-scene-root-scene-08 .s-core-svg .s-inner-path{
  animation: s-core-shimmer 3s infinite ease-in-out;
}@keyframes s-core-shimmer{
  0%, 100% { opacity: 0.8; filter: brightness(1); }
  50% { opacity: 1; filter: brightness(1.3); }
}.sv-scene-root-scene-08 .s-progress-wrap{
  position: absolute;
  inset: -10px;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}.sv-scene-root-scene-08 .s-progress-svg{
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}.sv-scene-root-scene-08 .s-progress-svg .s-track{
  fill: none;
  stroke: rgba(255,255,255,0.05);
  stroke-width: 4;
}.sv-scene-root-scene-08 .s-progress-svg .s-bar{
  fill: none;
  stroke: #F53501;
  stroke-width: 4;
  stroke-dasharray: 628;
  stroke-dashoffset: 628;
  transition: stroke-dashoffset 1.5s cubic-bezier(0.65, 0, 0.35, 1);
}.sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="1"] .s-bar, .sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="2"] .s-bar{ stroke-dashoffset: 0; }.sv-scene-root-scene-08 .s-progress-text{
  position: absolute;
  bottom: -40px;
  font-size: 12px;
  letter-spacing: 2px;
  color: #F53501;
  font-weight: bold;
  opacity: 0;
  transform: translateY(10px);
  transition: all 0.5s ease 1s;
}.sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="1"] .s-progress-text, .sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="2"] .s-progress-text{ opacity: 1; transform: translateY(0); }.sv-scene-root-scene-08 .s-icon-orbit{
  position: absolute;
  width: 400px;
  height: 400px;
  opacity: 0;
  transition: opacity 1s ease;
}.sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="2"] .s-icon-orbit{ opacity: 1; }.sv-scene-root-scene-08 .s-scenario-icon{
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  color: rgba(255,255,255,0.7);
  animation: s-float 4s infinite ease-in-out;
}.sv-scene-root-scene-08 .s-scenario-icon svg{
  width: 32px;
  height: 32px;
  color: #F53501;
}.sv-scene-root-scene-08 .s-scenario-icon span{
  font-size: 14px;
  background: rgba(255,255,255,0.05);
  padding: 2px 8px;
  border-radius: 4px;
}.sv-scene-root-scene-08 .s-icon-translate{ top: 0; left: 50%; transform: translateX(-50%); }.sv-scene-root-scene-08 .s-icon-code{ bottom: 40px; left: 0; animation-delay: -1s; }.sv-scene-root-scene-08 .s-icon-draw{ bottom: 40px; right: 0; animation-delay: -2s; }@keyframes s-float{
  0%, 100% { transform: translateY(0) scale(1); }
  50% { transform: translateY(-15px) scale(1.05); }
}.sv-scene-root-scene-08 .s-info-overlay{
  position: absolute;
  bottom: 80px;
  left: 60px;
  max-width: 600px;
}.sv-scene-root-scene-08 .s-main-title{
  font-size: 56px;
  line-height: 1.1;
  margin-bottom: 20px;
  opacity: 0;
  transform: translateX(-30px);
  transition: all 0.8s ease;
}.sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="0"] .s-main-title, .sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="1"] .s-main-title, .sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="2"] .s-main-title{ opacity: 1; transform: translateX(0); }.sv-scene-root-scene-08 .s-num-tag{
  font-size: 14px;
  font-family: monospace;
  border: 1px solid #F53501;
  color: #F53501;
  padding: 2px 8px;
  margin-bottom: 10px;
  display: inline-block;
}.sv-scene-root-scene-08 .s-accent{ color: #F53501; }.sv-scene-root-scene-08 .s-desc-box{
  height: 60px;
}.sv-scene-root-scene-08 .s-desc-text{
  font-size: 18px;
  color: rgba(255,255,255,0.6);
  display: none;
}.sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="0"] .s-desc-text[data-step="0"], .sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="1"] .s-desc-text[data-step="0"], .sv-scene-root-scene-08 .s-scene-08-wrapper[data-step="2"] .s-desc-text[data-step="2"]{
  display: block;
  animation: s-fade-in 0.5s forwards;
}@keyframes s-fade-in{ from { opacity: 0; } to { opacity: 1; } }.sv-scene-root-scene-08 .s-corner-ui{
  position: absolute;
  top: 40px;
  right: 40px;
  text-align: right;
}.sv-scene-root-scene-08 .s-data-tag{
  font-size: 10px;
  font-family: monospace;
  color: rgba(255,255,255,0.3);
  border-right: 2px solid #F53501;
  padding-right: 10px;
  margin-bottom: 8px;
}
  </style>
</head>
<body>
  <div id="app">
    <div id="viewport">
      <div id="stage">

<section class="scene" data-scene-id="scene-01">
  <div class="sv-scene-root sv-scene-root-scene-01" data-scene-root-id="scene-01">
<div class="s-scene-01-wrapper">
  <div class="s-grid-bg"></div>
  
  <div class="s-visual-container">
    <canvas id="brainCanvas" class="s-brain-canvas"></canvas>
    <div class="s-brain-core"></div>
  </div>

  <div class="s-content-layer">
    <div class="s-tag" data-step="0">[ 深度拆解系列 ]</div>
    <h1 class="s-main-title" data-step="0">
      大模型是如何从海量数据中<br/>
      <span class="s-accent-text">‘进化’</span> 而来的？
    </h1>
    <p class="s-subtitle" data-step="0">
      今天我们深度拆解 <span class="s-highlight-box">LLM</span> 的训练全过程
    </p>
  </div>

  <div class="s-ui-decorations">
    <div class="s-data-label l-top-left">DATA_STREAM: ACTIVE</div>
    <div class="s-data-label l-bottom-right">SYMBOLS_COUNT: 1.7T+</div>
    <div class="s-scanner-line"></div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-02">
  <div class="sv-scene-root sv-scene-root-scene-02" data-scene-root-id="scene-02">
<div class="s-scene-02-wrapper">
  <div class="s-grid-bg"></div>

  <div class="s-layout-container">
    <!-- 左侧：原始数据堆叠 -->
    <div class="s-input-section">
      <div class="s-card-stack">
        <div class="s-data-card s-card-book" data-step="0">
          <div class="s-card-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1-0.5-5"/><path d="M8 7h6"/><path d="M8 11h8"/></svg></div>
          <div class="s-card-info">
            <span class="s-card-label">RAW_BOOK</span>
            <span class="s-card-val">450GB+</span>
          </div>
        </div>
        <div class="s-data-card s-card-code" data-step="0">
          <div class="s-card-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg></div>
          <div class="s-card-info">
            <span class="s-card-label">SRC_CODE</span>
            <span class="s-card-val">1.2TB</span>
          </div>
        </div>
        <div class="s-data-card s-card-web" data-step="0">
          <div class="s-card-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></div>
          <div class="s-card-info">
            <span class="s-card-label">WEB_DOC</span>
            <span class="s-card-val">5.8TB</span>
          </div>
        </div>
      </div>
    </div>

    <!-- 中间：过滤漏斗 -->
    <div class="s-processing-section">
      <div class="s-funnel-container" data-step="1">
        <div class="s-funnel-top"></div>
        <div class="s-funnel-body">
          <div class="s-scan-line"></div>
          <div class="s-particle-emitter" id="particleIn"></div>
        </div>
        <div class="s-funnel-bottom"></div>
        <div class="s-status-tag">CLEANING_PROCESS</div>
      </div>
    </div>

    <!-- 右侧/下方：产出光盘 -->
    <div class="s-output-section">
      <div class="s-disk-grid" id="diskGrid" data-step="2"></div>
    </div>
  </div>

  <div class="s-overlay-info">
    <h2 class="s-title" data-step="0"><span class="s-num">01</span> 数据收集与清洗</h2>
    <p class="s-desc" data-step="0">涵盖书籍、代码和互联网上的公开信息，通过自动化流程剔除噪声。</p>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-03">
  <div class="sv-scene-root sv-scene-root-scene-03" data-scene-root-id="scene-03">
<div class="s-scene-03-wrapper" data-step="0">
  <div class="s-grid-bg"></div>

  <!-- 顶部状态栏 -->
  <div class="s-status-bar">
    <div class="s-status-item">
      <span class="s-status-dot"></span>
      <span class="s-status-text">TOKENIZER_V2.0_READY</span>
    </div>
    <div class="s-status-item">
      <span class="s-status-label">STATUS:</span>
      <span class="s-status-val" id="processing-status">WAITING</span>
    </div>
  </div>

  <div class="s-main-container">
    <!-- 原始文本显示层 -->
    <div class="s-text-stage">
      <div class="s-original-text" id="typewriterText">人工智能正在改变世界</div>
      
      <!-- 切割扫描线 -->
      <div class="s-scanner-line"></div>

      <!-- Token 容器 -->
      <div class="s-tokens-grid">
        <div class="s-token-item" data-index="0" style="--color: #F53501">
          <div class="s-token-box">人工</div>
          <div class="s-token-id">ID: 5821</div>
        </div>
        <div class="s-token-item" data-index="1" style="--color: #00A3FF">
          <div class="s-token-box">智能</div>
          <div class="s-token-id">ID: 9920</div>
        </div>
        <div class="s-token-item" data-index="2" style="--color: #00C853">
          <div class="s-token-box">正在</div>
          <div class="s-token-id">ID: 1024</div>
        </div>
        <div class="s-token-item" data-index="3" style="--color: #FFAB00">
          <div class="s-token-box">改变</div>
          <div class="s-token-id">ID: 7732</div>
        </div>
        <div class="s-token-item" data-index="4" style="--color: #AA00FF">
          <div class="s-token-box">世界</div>
          <div class="s-token-id">ID: 4510</div>
        </div>
      </div>
    </div>
  </div>

  <!-- 底部说明文字 -->
  <div class="s-overlay-info">
    <h2 class="s-title"><span class="s-num">02</span> 文本 Token 化</h2>
    <p class="s-desc" data-step="0">这是处理的第一步：将复杂的句子拆解为模型能理解的“Token”块。</p>
    <p class="s-desc" data-step="1">每个字符被赋予数学特征 ID，从此语言从感性描述转化为纯粹的数字向量。</p>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-04">
  <div class="sv-scene-root sv-scene-root-scene-04" data-scene-root-id="scene-04">
<div class="s-scene-04-wrapper" data-step="0">
  <div class="s-grid-bg"></div>

  <!-- 悬浮公式背景 -->
  <div class="s-math-bg">
    <div class="s-math-item" style="top: 15%; left: 8%;">P(x_t|x_{<t}) = softmax(W \cdot h_t)</div>
    <div class="s-math-item" style="top: 75%; left: 12%;">h_t = \text{Transformer}(x_1, \dots, x_t)</div>
    <div class="s-math-item" style="top: 25%; right: 10%;">\mathcal{L} = -\sum \log P(x_t|x_{<t})</div>
    <div class="s-math-item" style="top: 80%; right: 15%;">\Delta W = -\eta \nabla_{W} \mathcal{L}</div>
  </div>

  <div class="s-main-viewport">
    <div class="s-layout-container">
      
      <!-- 左侧：输入框 -->
      <div class="s-card s-input-card">
        <div class="s-card-head">
          <span class="s-dot"></span> INPUT SEQUENCE
        </div>
        <div class="s-card-body">
          <span class="s-word">The</span>
          <span class="s-word">cat</span>
          <span class="s-word">sits</span>
          <span class="s-word">on</span>
          <span class="s-word">the...</span>
        </div>
        <div class="s-port s-port-right"></div>
      </div>

      <!-- 中间：神经网络 -->
      <div class="s-network-container">
        <svg class="s-net-svg" viewBox="0 0 300 400" width="300" height="400">
          <defs>
            <linearGradient id="s-line-grad" x1="0%" y1="0%" x2="100%" y2="0%">
              <stop offset="0%" stop-color="#F53501" stop-opacity="0" />
              <stop offset="50%" stop-color="#F53501" stop-opacity="1" />
              <stop offset="100%" stop-color="#F53501" stop-opacity="0" />
            </linearGradient>
          </defs>
          
          <!-- 基础连线 -->
          <g class="s-lines-base">
            <path d="M 0 200 L 150 100" />
            <path d="M 0 200 L 150 200" />
            <path d="M 0 200 L 150 300" />
            <path d="M 150 100 L 300 200" />
            <path d="M 150 200 L 300 200" />
            <path d="M 150 300 L 300 200" />
          </g>

          <!-- 活跃流光连线 -->
          <g class="s-lines-active">
            <path d="M 0 200 L 150 100" />
            <path d="M 0 200 L 150 200" />
            <path d="M 0 200 L 150 300" />
            <path d="M 150 100 L 300 200" />
            <path d="M 150 200 L 300 200" />
            <path d="M 150 300 L 300 200" />
          </g>
        </svg>

        <!-- 隐藏层节点 -->
        <div class="s-node" style="left: 150px; top: 100px;"></div>
        <div class="s-node" style="left: 150px; top: 200px;"></div>
        <div class="s-node" style="left: 150px; top: 300px;"></div>
      </div>

      <!-- 右侧：输出预测 -->
      <div class="s-card s-output-card">
        <div class="s-port s-port-left"></div>
        <div class="s-card-head is-red">
          <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" class="s-icon">
            <path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>
          </svg>
          PREDICTION PROBABILITY
        </div>
        <div class="s-prob-list">
          <div class="s-prob-row is-target">
            <div class="s-prob-name">'mat'</div>
            <div class="s-prob-track">
              <div class="s-prob-fill" style="--p: 88%"></div>
            </div>
            <div class="s-prob-num">88%</div>
          </div>
          <div class="s-prob-row">
            <div class="s-prob-name">'hat'</div>
            <div class="s-prob-track">
              <div class="s-prob-fill" style="--p: 9%"></div>
            </div>
            <div class="s-prob-num">09%</div>
          </div>
          <div class="s-prob-row">
            <div class="s-prob-name">'cloud'</div>
            <div class="s-prob-track">
              <div class="s-prob-fill" style="--p: 3%"></div>
            </div>
            <div class="s-prob-num">03%</div>
          </div>
        </div>
      </div>

    </div>
  </div>

  <!-- 底部文案 -->
  <div class="s-overlay-info">
    <h2 class="s-title"><span class="s-num">03</span> 预训练机制</h2>
    <div class="s-desc-container">
      <p class="s-desc" data-target="0">输入已知的文本序列作为环境上下文。</p>
      <p class="s-desc" data-target="1">网络节点产生波动，数以千亿计的权重参数根据前置输入开始动态激活计算路径。</p>
      <p class="s-desc" data-target="2">系统最终输出词汇表上所有备选词的概率分布，并推断出最优的下一个词。</p>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-05">
  <div class="sv-scene-root sv-scene-root-scene-05" data-scene-root-id="scene-05">
<div class="s-scene-05-wrapper">
  <div class="s-grid-bg"></div>
  
  <div class="s-main-viewport">
    <!-- Neural Network Visual -->
    <div class="s-network-stage">
      <svg class="s-network-svg" viewBox="0 0 800 400">
        <defs>
          <filter id="glow">
            <feGaussianBlur stdDeviation="3" result="blur" />
            <feComposite in="SourceGraphic" in2="blur" operator="over" />
          </filter>
        </defs>
        <!-- Connection Lines -->
        <g class="s-lines-group" id="backpropLines">
          <!-- Hidden to Output -->
          <path class="s-conn-line" d="M550,150 L700,200" />
          <path class="s-conn-line" d="M550,250 L700,200" />
          <!-- Input to Hidden -->
          <path class="s-conn-line" d="M150,100 L350,150" />
          <path class="s-conn-line" d="M150,200 L350,150" />
          <path class="s-conn-line" d="M150,300 L350,150" />
          <path class="s-conn-line" d="M150,100 L350,250" />
          <path class="s-conn-line" d="M150,200 L350,250" />
          <path class="s-conn-line" d="M150,300 L350,250" />
        </g>
      </svg>

      <!-- Nodes -->
      <div class="s-nodes-layer">
        <div class="s-node s-output" style="left: 700px; top: 200px;"></div>
        <div class="s-node s-hidden" style="left: 350px; top: 150px;"></div>
        <div class="s-node s-hidden" style="left: 350px; top: 250px;"></div>
        <div class="s-node s-input" style="left: 150px; top: 100px;"></div>
        <div class="s-node s-input" style="left: 150px; top: 200px;"></div>
        <div class="s-node s-input" style="left: 150px; top: 300px;"></div>
      </div>

      <!-- Step 0: Error Marker -->
      <div class="s-error-callout" data-step="0">
        <div class="s-error-header">ERROR</div>
        <div class="s-error-body">
          <div class="s-error-row"><span>预测值:</span><span class="s-val">0.92</span></div>
          <div class="s-error-row"><span>真实值:</span><span class="s-val">0.10</span></div>
          <div class="s-error-diff">误差 (Loss): 0.82</div>
        </div>
        <div class="s-error-arrow"></div>
      </div>
    </div>
  </div>

  <div class="s-overlay-info">
    <h2 class="s-title"><span class="s-num">05</span> 反向传播算法</h2>
    <p class="s-desc" data-step="0">当系统预测错误时，会计算输出与真实的误差。</p>
    <p class="s-desc" data-step="1">红色波纹沿路径“逆向回溯”，动态调整每一层神经元的连接权重，让下次预测更准。</p>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-06">
  <div class="sv-scene-root sv-scene-root-scene-06" data-scene-root-id="scene-06">
<div class="s-scene-06-wrapper">
  <div class="s-grid-bg"></div>
  
  <div class="s-main-viewport">
    <div class="s-chat-interface">
      <!-- Step 0: User Prompt -->
      <div class="s-chat-row s-user-row" data-step="0">
        <div class="s-avatar s-user-avatar">H</div>
        <div class="s-bubble-wrap">
          <div class="s-bubble-tag">HUMAN INTENT</div>
          <div class="s-bubble s-user-bubble">
            请写一首关于春天的诗
          </div>
        </div>
      </div>

      <!-- Step 1: AI Response -->
      <div class="s-chat-row s-ai-row" data-step="1">
        <div class="s-avatar s-ai-avatar">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
          </svg>
        </div>
        <div class="s-bubble-wrap">
          <div class="s-bubble-tag">SFT OPTIMIZED RESPONSE</div>
          <div class="s-bubble s-ai-bubble" id="s-poem-container">
            <!-- Poem characters will be injected here -->
          </div>
          <div class="s-golden-sweep"></div>
        </div>
      </div>
    </div>
  </div>

  <div class="s-overlay-info">
    <h2 class="s-title"><span class="s-num">06</span> 指令微调 (SFT)</h2>
    <p class="s-desc" data-step="0">指令微调（Supervised Fine-Tuning）是模型进化的关键。</p>
    <p class="s-desc" data-step="1">通过高质量的人类示范对，模型从“概率预测”转变为“理解指令”，实现真正的意图对齐。</p>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-07">
  <div class="sv-scene-root sv-scene-root-scene-07" data-scene-root-id="scene-07">
<div class="s-scene-07-wrapper">
  <div class="s-grid-bg"></div>
  
  <div class="s-main-viewport">
    <div class="s-rlhf-container">
      <div class="s-selection-label" data-step="0">CHOOSE THE BETTER RESPONSE</div>
      
      <div class="s-options-stack">
        <!-- Option A -->
        <div class="s-option-card s-option-a" data-step="0">
          <div class="s-option-header">
            <span class="s-option-tag">OPTION A</span>
            <div class="s-status-dot"></div>
          </div>
          <div class="s-option-content">
            <p>虽然我是AI，但我没有感情。春天只是地球公转导致的季节交替，气温升高，植物生长。</p>
          </div>
        </div>

        <!-- Option B -->
        <div class="s-option-card s-option-b" data-step="0">
          <div class="s-option-header">
            <span class="s-option-tag">OPTION B</span>
            <div class="s-status-dot"></div>
          </div>
          <div class="s-option-content">
            <p>春风徐来，万物复苏。春天不仅是自然的更迭，更是希望的开始。这是一首为您创作的诗...</p>
          </div>
          <div class="s-success-border"></div>
        </div>
      </div>

      <!-- Feedback Hand -->
      <div class="s-feedback-cursor" data-step="1">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="s-hand-icon">
          <path d="M7 10v12"/>
          <path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2h0a3.13 3.13 0 0 1 3 3.88Z"/>
        </svg>
      </div>

      <!-- Particle Container -->
      <div class="s-particle-canvas" id="s-particles"></div>
    </div>
  </div>

  <div class="s-overlay-info">
    <h2 class="s-title"><span class="s-num">07</span> 人类反馈强化学习 (RLHF)</h2>
    <p class="s-desc" data-step="0">RLHF 是模型对齐的关键步骤。我们同时运行两个模型副本，生成不同答案。</p>
    <p class="s-desc" data-step="1">人类专家对答案进行打分和排序，告诉 AI 哪些回答更符合人类的偏好和价值观。</p>
    <p class="s-desc" data-step="2">通过奖励模型 (Reward Model) 的迭代，AI 最终学会“如何像人一样思考与表达”。</p>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-08">
  <div class="sv-scene-root sv-scene-root-scene-08" data-scene-root-id="scene-08">
<div class="s-scene-08-wrapper">
  <div class="s-grid-bg"></div>
  
  <div class="s-core-container">
    <div class="s-radial-glow" data-step="0"></div>
    
    <div class="s-icon-orbit" data-step="2">
      <div class="s-scenario-icon s-icon-translate">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m5 8 6 6"/><path d="m4 14 6-6 2-3"/><path d="M2 5h12"/><path d="M7 2h1"/><path d="m22 22-5-10-5 10"/><path d="M14 18h6"/></svg>
        <span>翻译</span>
      </div>
      <div class="s-scenario-icon s-icon-code">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
        <span>编程</span>
      </div>
      <div class="s-scenario-icon s-icon-draw">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19l7-7 3 3-7 7-3-3z"/><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"/><path d="M2 2l5 5"/><path d="M9.5 14.5L16 18"/></svg>
        <span>绘图</span>
      </div>
    </div>

    <div class="s-ai-core-group" data-step="0">
      <div class="s-shimmer-layer"></div>
      <div class="s-core-hex">
        <svg viewBox="0 0 200 200" class="s-core-svg">
          <defs>
            <linearGradient id="s-grad-accent" x1="0%" y1="0%" x2="100%" y2="100%">
              <stop offset="0%" stop-color="#F53501" />
              <stop offset="100%" stop-color="#FF6B4A" />
            </linearGradient>
          </defs>
          <path d="M100 20 L170 60 L170 140 L100 180 L30 140 L30 60 Z" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="2"/>
          <path class="s-inner-path" d="M100 50 L143 75 L143 125 L100 150 L57 125 L57 75 Z" fill="url(#s-grad-accent)"/>
          <circle cx="100" cy="100" r="25" fill="#1B1B1B" />
          <path class="s-logo-mark" d="M90 90 L110 110 M110 90 L90 110" stroke="#F53501" stroke-width="4" stroke-linecap="round"/>
        </svg>
      </div>

      <div class="s-progress-wrap" data-step="1">
        <svg viewBox="0 0 220 220" class="s-progress-svg">
          <circle cx="110" cy="110" r="100" class="s-track" />
          <circle cx="110" cy="110" r="100" class="s-bar" />
        </svg>
        <div class="s-progress-text">INITIALIZED</div>
      </div>
    </div>
  </div>

  <div class="s-info-overlay">
    <h1 class="s-main-title" data-step="0">
      <span class="s-num-tag">FINALIZE</span><br/>
      博学的大模型<span class="s-accent">正式诞生</span>
    </h1>
    <div class="s-desc-box">
      <p class="s-desc-text" data-step="0">算力燃烧的终点，是智慧涌现的起点。</p>
      <p class="s-desc-text" data-step="2">它不再仅仅是工具，而是全人类智慧的数字结晶。</p>
    </div>
  </div>

  <div class="s-corner-ui">
    <div class="s-data-tag">LLM_STATUS: EVOLVED</div>
    <div class="s-data-tag">COMPUTE_LOAD: STABLE</div>
  </div>
</div>
  </div>
</section>
      </div>
    </div>
  </div>
  <script id="__SVGVIDEO_META__" type="application/json">{"version":2,"format":"json","title":"深度拆解：大语言模型（LLM）是如何练成的？","fullScript":"大模型是如何从海量数据中‘进化’而来的？今天我们深度拆解 LLM 的训练全过程。第一步：海量数据的收集与清洗。这就像是给学生准备教材，涵盖了书籍、代码和互联网上的几乎所有公开信息。接着是分词处理。复杂的语言被拆解成模型能理解的‘Token’，每个字符都被赋予了一个数学特征。现在进入核心环节：预训练。模型尝试通过上一个词预测下一个词，数千亿个参数在此时开始调整。如果预测错了，系统会通过‘反向传播’算法计算误差，并微调神经元之间的连接权重。但这还不够，接着是指令微调。通过高质量的任务问答对，让模型学会理解人类的真实意图。最后是人类反馈强化学习，即 RLHF。人类老师会对模型的回答打分，确保它既聪明又符合人类价值观。就这样，经过数月的算力燃烧，一个博学的大模型就诞生了。它不只是工具，更是人类智慧的结晶。","visualStyleId":"yingshijufeng","scenes":[{"id":"scene-01","title":"开篇引入","steps":2,"status":"success","prompt":"居中展示一个深色背景的 3D 大脑轮廓，由无数发光的神经元节点组成。Step 0：大脑以呼吸灯节奏缓慢闪烁。Step 1：四周飞入无数细小的光点（数据粒子）汇聚向大脑，产生强烈的吸入感。视觉风格：极简科技感，暗黑模式背景，霓虹蓝发光特效。","scriptText":"大模型是如何从海量数据中‘进化’而来的？今天我们深度拆解 LLM 的训练全过程。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_4e23e305-be79-44b4-a112-e3bc47ea46f7/s_scene-01/v_xiaochen/a_dbe8c410_1776848574266_89p6kj.mp3","audioDurationMs":8352,"voiceName":"xiaochen","relatedSceneIds":["scene-02"]},{"id":"scene-02","title":"数据准备","steps":3,"status":"success","prompt":"分栏布局。左侧堆叠显示代表书籍、代码块和网页文档的卡片。Step 0：卡片从屏幕左侧依次滑入并带有弹簧震动效果。Step 1：中间出现一个带有扫描线的过滤漏斗。Step 2：杂乱的图标进入漏斗，下方产出整齐排列的蓝色光盘，代表清洗后的数据。视觉风格：毛玻璃质感，渐变边框。","scriptText":"第一步：海量数据的收集与清洗。这就像是给学生准备教材，涵盖了书籍、代码和互联网上的几乎所有公开信息。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_4e23e305-be79-44b4-a112-e3bc47ea46f7/s_scene-02/v_xiaochen/a_20f2180e_1776848633181_afjvmy.mp3","audioDurationMs":10836,"voiceName":"xiaochen","relatedSceneIds":["scene-03"]},{"id":"scene-03","title":"分词过程","steps":2,"status":"success","prompt":"展示一个大文本框，中间显示句子‘人工智能正在改变世界’。Step 0：文字显示。Step 1：垂直的切割线划过文字，文字碎裂成彩色的小方块（Token），每个方块下方弹出对应的 ID 编号（如 1024, 882）。视觉风格：高饱和度色彩标签，打字机动画。","scriptText":"接着是分词处理。复杂的语言被拆解成模型能理解的‘Token’，每个字符都被赋予了一个数学特征。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_4e23e305-be79-44b4-a112-e3bc47ea46f7/s_scene-03/v_xiaochen/a_f44e10c9_1776849427854_jkk49b.mp3","audioDurationMs":8928,"voiceName":"xiaochen","relatedSceneIds":["scene-04"]},{"id":"scene-04","title":"预训练预测","steps":3,"status":"success","prompt":"网格背景，展示一个简单的神经网络结构。Step 0：左侧输入框显示‘The cat sits on the...’。Step 1：中间层节点产生波动电流，连线依次亮起。Step 2：右侧输出一个预测框，备选项包括‘mat’、‘hat’、‘cloud’，其中‘mat’的概率条最高并闪烁。视觉风格：动态数据流，数学公式浮现。","scriptText":"现在进入核心环节：预训练。模型尝试通过上一个词预测下一个词，数千亿个参数在此时开始调整。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_4e23e305-be79-44b4-a112-e3bc47ea46f7/s_scene-04/v_xiaochen/a_6b2c80af_1776849348784_5e07dm.mp3","audioDurationMs":9360,"voiceName":"xiaochen","relatedSceneIds":["scene-05"]},{"id":"scene-05","title":"反向传播","steps":2,"status":"success","prompt":"延续上一个场景的神经网络图。Step 0：出现一个醒目的红色‘Error’标记，指向错误的预测。Step 1：红色波纹从右向左逆向穿过所有神经层，经过的连线变粗或变细，表示权重更新。视觉风格：红色警告脉冲，线条粗细动态调节。","scriptText":"如果预测错了，系统会通过‘反向传播’算法计算误差，并微调神经元之间的连接权重。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_4e23e305-be79-44b4-a112-e3bc47ea46f7/s_scene-05/v_xiaochen/a_894b559c_1776848830379_3bl1h0.mp3","audioDurationMs":7560,"voiceName":"xiaochen","relatedSceneIds":["scene-06"]},{"id":"scene-06","title":"指令微调","steps":2,"status":"success","prompt":"上下结构布局。上方是一个对话框显示‘请写一首关于春天的诗’，下方是模型生成的诗句。Step 0：上方对话框淡入。Step 1：下方文字以极快速度逐字弹出，伴随金色扫光，代表经过微调后的高效理解。视觉风格：现代 UI 聊天界面，柔和的光影。","scriptText":"但这还不够，接着是指令微调。通过高质量的任务问答对，让模型学会理解人类的真实意图。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_4e23e305-be79-44b4-a112-e3bc47ea46f7/s_scene-06/v_xiaochen/a_2223ed07_1776848869109_zrtb0l.mp3","audioDurationMs":8352,"voiceName":"xiaochen","relatedSceneIds":["scene-07"]},{"id":"scene-07","title":"RLHF 人类对齐","steps":3,"status":"success","prompt":"屏幕显示两个 AI 回答选项 A 和 B。Step 0：两个选项垂直排列展开。Step 1：上方出现一个人类点赞的手势图标，点击 B 选项。Step 2：B 选项周围放射出成功的粒子效果，A 选项逐渐透明消失。视觉风格：交互式 UI，成功的绿色粒子反馈。","scriptText":"最后是人类反馈强化学习，即 RLHF。人类老师会对模型的回答打分，确保它既聪明又符合人类价值观。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_4e23e305-be79-44b4-a112-e3bc47ea46f7/s_scene-07/v_xiaochen/a_3fb85452_1776848918872_881bag.mp3","audioDurationMs":10764,"voiceName":"xiaochen","relatedSceneIds":["scene-08"]},{"id":"scene-08","title":"最终诞生","steps":3,"status":"success","prompt":"全屏中心展示一个极其精致的 AI 核心图标。Step 0：图标从小到大弹出，背景伴随强烈的径向扩散光。Step 1：环形进度条快速转动到 100%。Step 2：屏幕周围浮现出各种应用场景的小图标（如翻译、编程、绘图）。视觉风格：震撼的 Shimmer 光效，品牌 Logo 感。","scriptText":"就这样，经过数月的算力燃烧，一个博学的大模型就诞生了。它不只是工具，更是人类智慧的结晶。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_4e23e305-be79-44b4-a112-e3bc47ea46f7/s_scene-08/v_xiaochen/a_93aaf0c7_1776848965128_h9evhi.mp3","audioDurationMs":8856,"voiceName":"xiaochen","relatedSceneIds":["scene-01"]}]}</script>
  <script id="__SVGVIDEO_SCENE_DATA__" type="application/json">[{"id":"scene-01","title":"开篇引入","steps":2,"html":"<div class=\"s-scene-01-wrapper\">\n  <div class=\"s-grid-bg\"></div>\n  \n  <div class=\"s-visual-container\">\n    <canvas id=\"brainCanvas\" class=\"s-brain-canvas\"></canvas>\n    <div class=\"s-brain-core\"></div>\n  </div>\n\n  <div class=\"s-content-layer\">\n    <div class=\"s-tag\" data-step=\"0\">[ 深度拆解系列 ]</div>\n    <h1 class=\"s-main-title\" data-step=\"0\">\n      大模型是如何从海量数据中<br/>\n      <span class=\"s-accent-text\">‘进化’</span> 而来的？\n    </h1>\n    <p class=\"s-subtitle\" data-step=\"0\">\n      今天我们深度拆解 <span class=\"s-highlight-box\">LLM</span> 的训练全过程\n    </p>\n  </div>\n\n  <div class=\"s-ui-decorations\">\n    <div class=\"s-data-label l-top-left\">DATA_STREAM: ACTIVE</div>\n    <div class=\"s-data-label l-bottom-right\">SYMBOLS_COUNT: 1.7T+</div>\n    <div class=\"s-scanner-line\"></div>\n  </div>\n</div>","css":".s-scene-01-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100vh;\n  background-color: #1B1B1B;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  overflow: hidden;\n  color: #FFFFFF;\n  font-family: 'Alimama ShuHeiTi', 'Microsoft YaHei', sans-serif;\n}\n\n.s-grid-bg {\n  position: absolute;\n  inset: 0;\n  background-image: \n    linear-gradient(to right, rgba(255,255,255,0.03) 1px, transparent 1px),\n    linear-gradient(to bottom, rgba(255,255,255,0.03) 1px, transparent 1px);\n  background-size: 40px 40px;\n  pointer-events: none;\n}\n\n.s-visual-container {\n  position: absolute;\n  width: 600px;\n  height: 600px;\n  z-index: 1;\n}\n\n.s-brain-canvas {\n  width: 100%;\n  height: 100%;\n}\n\n.s-brain-core {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n  width: 120px;\n  height: 120px;\n  background: radial-gradient(circle, #F53501 0%, transparent 70%);\n  opacity: 0.4;\n  filter: blur(20px);\n  animation: s-breath 3s ease-in-out infinite;\n}\n\n.s-content-layer {\n  position: relative;\n  z-index: 2;\n  text-align: center;\n  pointer-events: none;\n}\n\n.s-tag {\n  font-size: 14px;\n  color: #F53501;\n  letter-spacing: 2px;\n  margin-bottom: 20px;\n  opacity: 0.8;\n}\n\n.s-main-title {\n  font-size: 64px;\n  font-weight: 900;\n  line-height: 1.2;\n  margin: 0;\n  text-shadow: 0 4px 20px rgba(0,0,0,0.5);\n}\n\n.s-accent-text {\n  color: #F53501;\n  position: relative;\n}\n\n.s-subtitle {\n  font-size: 20px;\n  margin-top: 24px;\n  color: rgba(255,255,255,0.7);\n}\n\n.s-highlight-box {\n  background: #F53501;\n  color: #FFFFFF;\n  padding: 2px 8px;\n  border-radius: 2px;\n  font-weight: bold;\n}\n\n.s-ui-decorations .s-data-label {\n  position: absolute;\n  font-size: 10px;\n  font-family: monospace;\n  color: rgba(255,255,255,0.4);\n  border-left: 2px solid #F53501;\n  padding-left: 8px;\n}\n\n.l-top-left { top: 40px; left: 40px; }\n.l-bottom-right { bottom: 40px; right: 40px; }\n\n.s-scanner-line {\n  position: absolute;\n  width: 100%;\n  height: 1px;\n  background: linear-gradient(90deg, transparent, #F53501, transparent);\n  opacity: 0.2;\n  top: 0;\n  animation: s-scan 8s linear infinite;\n}\n\n@keyframes s-breath {\n  0%, 100% { transform: translate(-50%, -50%) scale(0.8); opacity: 0.3; }\n  50% { transform: translate(-50%, -50%) scale(1.1); opacity: 0.6; }\n}\n\n@keyframes s-scan {\n  0% { top: 0%; } 100% { top: 100%; }\n}","js":"window.SceneLifecycle.register('scene-01', {\n  enter() {\n    const canvas = document.getElementById('brainCanvas');\n    const ctx = canvas.getContext('2d');\n    let width, height, particles = [], nodes = [];\n    let step = 0;\n\n    const resize = () => {\n      width = canvas.width = canvas.offsetWidth;\n      height = canvas.height = canvas.offsetHeight;\n    };\n    window.addEventListener('resize', resize);\n    resize();\n\n    // Initialize nodes (the brain shape)\n    for(let i=0; i<40; i++) {\n      nodes.push({\n        x: width/2 + (Math.random()-0.5) * 200,\n        y: height/2 + (Math.random()-0.5) * 200,\n        vx: (Math.random()-0.5) * 0.5,\n        vy: (Math.random()-0.5) * 0.5\n      });\n    }\n\n    // Initialize flying particles\n    const createParticle = (converge = false) => {\n      if (!converge) return;\n      const angle = Math.random() * Math.PI * 2;\n      const dist = Math.max(width, height) * 0.6;\n      return {\n        x: width/2 + Math.cos(angle) * dist,\n        y: height/2 + Math.sin(angle) * dist,\n        targetX: width/2 + (Math.random()-0.5) * 50,\n        targetY: height/2 + (Math.random()-0.5) * 50,\n        speed: 0.02 + Math.random() * 0.05,\n        size: 1 + Math.random() * 2\n      };\n    };\n\n    const animate = () => {\n      ctx.clearRect(0, 0, width, height);\n      \n      // Draw brain nodes and connections\n      ctx.strokeStyle = 'rgba(245, 53, 1, 0.2)';\n      ctx.fillStyle = '#F53501';\n      nodes.forEach((n, i) => {\n        n.x += n.vx;\n        n.y += n.vy;\n        if(Math.abs(n.x - width/2) > 120) n.vx *= -1;\n        if(Math.abs(n.y - height/2) > 120) n.vy *= -1;\n        \n        ctx.beginPath();\n        ctx.arc(n.x, n.y, 2, 0, Math.PI*2);\n        ctx.fill();\n\n        nodes.slice(i+1).forEach(n2 => {\n          const d = Math.hypot(n.x-n2.x, n.y-n2.y);\n          if(d < 80) {\n            ctx.beginPath();\n            ctx.moveTo(n.x, n.y);\n            ctx.lineTo(n2.x, n2.y);\n            ctx.stroke();\n          }\n        });\n      });\n\n      // Draw converging particles\n      if(step >= 1) {\n        if(particles.length < 100 && Math.random() > 0.5) {\n          particles.push(createParticle(true));\n        }\n        \n        particles.forEach((p, i) => {\n          p.x += (p.targetX - p.x) * p.speed;\n          p.y += (p.targetY - p.y) * p.speed;\n          \n          ctx.fillStyle = '#F53501';\n          ctx.beginPath();\n          ctx.arc(p.x, p.y, p.size, 0, Math.PI*2);\n          ctx.fill();\n\n          if(Math.hypot(p.x - p.targetX, p.y - p.targetY) < 5) {\n            particles.splice(i, 1);\n          }\n        });\n      }\n\n      this.animFrame = requestAnimationFrame(animate);\n    };\n    animate();\n\n    this.updateStep = (s) => { step = s; };\n  },\n  step(s) {\n    if(this.updateStep) this.updateStep(s);\n  },\n  leave() {\n    cancelAnimationFrame(this.animFrame);\n  }\n});"},{"id":"scene-02","title":"数据准备","steps":3,"html":"<div class=\"s-scene-02-wrapper\">\n  <div class=\"s-grid-bg\"></div>\n\n  <div class=\"s-layout-container\">\n    <!-- 左侧：原始数据堆叠 -->\n    <div class=\"s-input-section\">\n      <div class=\"s-card-stack\">\n        <div class=\"s-data-card s-card-book\" data-step=\"0\">\n          <div class=\"s-card-icon\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1-0.5-5\"/><path d=\"M8 7h6\"/><path d=\"M8 11h8\"/></svg></div>\n          <div class=\"s-card-info\">\n            <span class=\"s-card-label\">RAW_BOOK</span>\n            <span class=\"s-card-val\">450GB+</span>\n          </div>\n        </div>\n        <div class=\"s-data-card s-card-code\" data-step=\"0\">\n          <div class=\"s-card-icon\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"16 18 22 12 16 6\"/><polyline points=\"8 6 2 12 8 18\"/></svg></div>\n          <div class=\"s-card-info\">\n            <span class=\"s-card-label\">SRC_CODE</span>\n            <span class=\"s-card-val\">1.2TB</span>\n          </div>\n        </div>\n        <div class=\"s-data-card s-card-web\" data-step=\"0\">\n          <div class=\"s-card-icon\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"2\" y1=\"12\" x2=\"22\" y2=\"12\"/><path d=\"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z\"/></svg></div>\n          <div class=\"s-card-info\">\n            <span class=\"s-card-label\">WEB_DOC</span>\n            <span class=\"s-card-val\">5.8TB</span>\n          </div>\n        </div>\n      </div>\n    </div>\n\n    <!-- 中间：过滤漏斗 -->\n    <div class=\"s-processing-section\">\n      <div class=\"s-funnel-container\" data-step=\"1\">\n        <div class=\"s-funnel-top\"></div>\n        <div class=\"s-funnel-body\">\n          <div class=\"s-scan-line\"></div>\n          <div class=\"s-particle-emitter\" id=\"particleIn\"></div>\n        </div>\n        <div class=\"s-funnel-bottom\"></div>\n        <div class=\"s-status-tag\">CLEANING_PROCESS</div>\n      </div>\n    </div>\n\n    <!-- 右侧/下方：产出光盘 -->\n    <div class=\"s-output-section\">\n      <div class=\"s-disk-grid\" id=\"diskGrid\" data-step=\"2\"></div>\n    </div>\n  </div>\n\n  <div class=\"s-overlay-info\">\n    <h2 class=\"s-title\" data-step=\"0\"><span class=\"s-num\">01</span> 数据收集与清洗</h2>\n    <p class=\"s-desc\" data-step=\"0\">涵盖书籍、代码和互联网上的公开信息，通过自动化流程剔除噪声。</p>\n  </div>\n</div>","css":".s-scene-02-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100vh;\n  background: #1B1B1B;\n  overflow: hidden;\n  font-family: 'Alimama ShuHeiTi', sans-serif;\n  color: #fff;\n}\n\n.s-grid-bg {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);\n  background-size: 50px 50px;\n  pointer-events: none;\n}\n\n.s-layout-container {\n  display: flex;\n  align-items: center;\n  justify-content: space-around;\n  height: 100%;\n  padding: 0 10%;\n  z-index: 2;\n}\n\n/* Cards Animation Step 0 */\n.s-input-section {\n  flex: 1;\n  display: flex;\n  justify-content: center;\n}\n\n.s-card-stack {\n  display: flex;\n  flex-direction: column;\n  gap: 20px;\n}\n\n.s-data-card {\n  width: 280px;\n  padding: 20px;\n  background: rgba(255, 255, 255, 0.03);\n  backdrop-filter: blur(10px);\n  border-left: 4px solid #F53501;\n  border-radius: 4px;\n  display: flex;\n  align-items: center;\n  gap: 15px;\n  transform: translateX(-150%);\n  opacity: 0;\n  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n[data-step=\"0\"] .s-data-card {\n  transform: translateX(0);\n  opacity: 1;\n}\n\n.s-card-book { transition-delay: 0.1s; }\n.s-card-code { transition-delay: 0.3s; }\n.s-card-web { transition-delay: 0.5s; }\n\n.s-card-icon { color: #F53501; }\n.s-card-label { display: block; font-size: 12px; color: rgba(255,255,255,0.4); font-family: monospace; }\n.s-card-val { font-size: 24px; font-weight: bold; }\n\n/* Funnel Animation Step 1 */\n.s-processing-section {\n  flex: 1;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n}\n\n.s-funnel-container {\n  position: relative;\n  width: 200px;\n  height: 260px;\n  opacity: 0;\n  transform: scale(0.8);\n  transition: all 0.6s ease-out;\n}\n\n[data-step=\"1\"] .s-funnel-container {\n  opacity: 1;\n  transform: scale(1);\n}\n\n.s-funnel-body {\n  width: 100%;\n  height: 180px;\n  background: linear-gradient(180deg, rgba(245, 53, 1, 0.1) 0%, transparent 100%);\n  clip-path: polygon(0% 0%, 100% 0%, 60% 100%, 40% 100%);\n  border-top: 2px solid #F53501;\n  position: relative;\n  overflow: hidden;\n}\n\n.s-scan-line {\n  position: absolute;\n  width: 100%;\n  height: 40px;\n  background: linear-gradient(to bottom, transparent, rgba(245, 53, 1, 0.4), transparent);\n  animation: s-scan-move 2s infinite ease-in-out;\n}\n\n@keyframes s-scan-move {\n  0% { top: -40px; } 100% { top: 100%; }\n}\n\n.s-status-tag {\n  margin-top: 20px;\n  font-size: 12px;\n  letter-spacing: 2px;\n  color: #F53501;\n  background: rgba(245, 53, 1, 0.1);\n  padding: 4px 12px;\n  border: 1px solid rgba(245, 53, 1, 0.3);\n}\n\n/* Output Step 2 */\n.s-output-section {\n  flex: 1;\n  display: flex;\n  justify-content: center;\n}\n\n.s-disk-grid {\n  display: grid;\n  grid-template-columns: repeat(3, 1fr);\n  gap: 15px;\n  opacity: 0;\n  transform: translateY(20px);\n  transition: all 0.5s ease-out;\n}\n\n[data-step=\"2\"] .s-disk-grid {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.s-disk {\n  width: 60px;\n  height: 60px;\n  border-radius: 50%;\n  background: radial-gradient(circle, #00A3FF 10%, transparent 80%);\n  border: 2px solid #00A3FF;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  box-shadow: 0 0 15px rgba(0, 163, 255, 0.3);\n  animation: s-disk-pulse 2s infinite ease-in-out;\n}\n\n@keyframes s-disk-pulse {\n  0%, 100% { opacity: 0.7; transform: scale(1); }\n  50% { opacity: 1; transform: scale(1.05); }\n}\n\n.s-overlay-info {\n  position: absolute;\n  bottom: 60px;\n  left: 60px;\n  max-width: 500px;\n}\n\n.s-title {\n  font-size: 48px;\n  margin-bottom: 15px;\n  display: flex;\n  align-items: center;\n  gap: 20px;\n}\n\n.s-num { color: #F53501; font-family: monospace; border: 1px solid #F53501; padding: 0 10px; }\n.s-desc { font-size: 18px; color: rgba(255,255,255,0.6); line-height: 1.6; }","js":"window.SceneLifecycle.register('scene-02', {\n  enter() {\n    const diskGrid = document.getElementById('diskGrid');\n    const particleIn = document.getElementById('particleIn');\n    this.particles = [];\n    this.stepState = 0;\n\n    // Create initial disks (hidden initially by data-step)\n    for (let i = 0; i < 9; i++) {\n      const disk = document.createElement('div');\n      disk.className = 's-disk';\n      disk.innerHTML = `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#00A3FF\" stroke-width=\"2\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>`;\n      diskGrid.appendChild(disk);\n    }\n\n    const spawnParticle = () => {\n      if (this.stepState < 2) return;\n      const p = document.createElement('div');\n      p.style.position = 'absolute';\n      p.style.left = Math.random() * 100 + '%';\n      p.style.top = '-20px';\n      p.style.width = '6px';\n      p.style.height = '6px';\n      p.style.background = '#F53501';\n      p.style.borderRadius = '50%';\n      p.style.transition = 'all 1.5s linear';\n      particleIn.appendChild(p);\n      \n      setTimeout(() => {\n        p.style.transform = 'translateY(180px) scale(0.5)';\n        p.style.opacity = '0';\n      }, 50);\n      \n      setTimeout(() => p.remove(), 1600);\n    };\n\n    this.timer = setInterval(spawnParticle, 200);\n  },\n\n  step(s) {\n    this.stepState = s;\n  },\n\n  leave() {\n    clearInterval(this.timer);\n  }\n});"},{"id":"scene-03","title":"分词过程","steps":2,"html":"<div class=\"s-scene-03-wrapper\" data-step=\"0\">\n  <div class=\"s-grid-bg\"></div>\n\n  <!-- 顶部状态栏 -->\n  <div class=\"s-status-bar\">\n    <div class=\"s-status-item\">\n      <span class=\"s-status-dot\"></span>\n      <span class=\"s-status-text\">TOKENIZER_V2.0_READY</span>\n    </div>\n    <div class=\"s-status-item\">\n      <span class=\"s-status-label\">STATUS:</span>\n      <span class=\"s-status-val\" id=\"processing-status\">WAITING</span>\n    </div>\n  </div>\n\n  <div class=\"s-main-container\">\n    <!-- 原始文本显示层 -->\n    <div class=\"s-text-stage\">\n      <div class=\"s-original-text\" id=\"typewriterText\">人工智能正在改变世界</div>\n      \n      <!-- 切割扫描线 -->\n      <div class=\"s-scanner-line\"></div>\n\n      <!-- Token 容器 -->\n      <div class=\"s-tokens-grid\">\n        <div class=\"s-token-item\" data-index=\"0\" style=\"--color: #F53501\">\n          <div class=\"s-token-box\">人工</div>\n          <div class=\"s-token-id\">ID: 5821</div>\n        </div>\n        <div class=\"s-token-item\" data-index=\"1\" style=\"--color: #00A3FF\">\n          <div class=\"s-token-box\">智能</div>\n          <div class=\"s-token-id\">ID: 9920</div>\n        </div>\n        <div class=\"s-token-item\" data-index=\"2\" style=\"--color: #00C853\">\n          <div class=\"s-token-box\">正在</div>\n          <div class=\"s-token-id\">ID: 1024</div>\n        </div>\n        <div class=\"s-token-item\" data-index=\"3\" style=\"--color: #FFAB00\">\n          <div class=\"s-token-box\">改变</div>\n          <div class=\"s-token-id\">ID: 7732</div>\n        </div>\n        <div class=\"s-token-item\" data-index=\"4\" style=\"--color: #AA00FF\">\n          <div class=\"s-token-box\">世界</div>\n          <div class=\"s-token-id\">ID: 4510</div>\n        </div>\n      </div>\n    </div>\n  </div>\n\n  <!-- 底部说明文字 -->\n  <div class=\"s-overlay-info\">\n    <h2 class=\"s-title\"><span class=\"s-num\">02</span> 文本 Token 化</h2>\n    <p class=\"s-desc\" data-step=\"0\">这是处理的第一步：将复杂的句子拆解为模型能理解的“Token”块。</p>\n    <p class=\"s-desc\" data-step=\"1\">每个字符被赋予数学特征 ID，从此语言从感性描述转化为纯粹的数字向量。</p>\n  </div>\n</div>","css":".s-scene-03-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100vh;\n  background: #1B1B1B;\n  overflow: hidden;\n  color: #fff;\n  font-family: 'Alimama ShuHeiTi', sans-serif;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n}\n\n.s-grid-bg {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px), \n                    linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px);\n  background-size: 40px 40px;\n  pointer-events: none;\n}\n\n.s-status-bar {\n  position: absolute;\n  top: 40px;\n  left: 60px;\n  right: 60px;\n  display: flex;\n  justify-content: space-between;\n  padding-bottom: 10px;\n  border-bottom: 1px solid rgba(255,255,255,0.1);\n  font-family: monospace;\n  font-size: 14px;\n  letter-spacing: 2px;\n  z-index: 10;\n}\n\n.s-status-item {\n  display: flex;\n  align-items: center;\n  gap: 10px;\n}\n\n.s-status-dot {\n  width: 8px;\n  height: 8px;\n  background: #F53501;\n  border-radius: 50%;\n  box-shadow: 0 0 10px #F53501;\n  animation: s-blink 1s infinite alternate;\n}\n\n.s-status-val { color: #F53501; }\n\n.s-main-container {\n  width: 80%;\n  max-width: 1200px;\n  position: relative;\n  z-index: 5;\n}\n\n.s-text-stage {\n  position: relative;\n  min-height: 200px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.s-original-text {\n  font-size: 84px;\n  font-weight: 900;\n  letter-spacing: 8px;\n  white-space: nowrap;\n  opacity: 1;\n  transition: opacity 0.3s ease;\n}\n\n/* Step 0 打字机 */\n[data-step=\"0\"] .s-original-text {\n  overflow: hidden;\n  border-right: 4px solid #F53501;\n  animation: s-typewriter 2s steps(10) forwards, s-cursor 0.8s infinite;\n  width: 0;\n}\n\n@keyframes s-typewriter { from { width: 0; } to { width: 100%; } }\n@keyframes s-cursor { 50% { border-color: transparent; } }\n\n/* Step 1 逻辑 */\n[data-step=\"1\"] .s-original-text {\n  opacity: 0;\n}\n\n.s-scanner-line {\n  position: absolute;\n  left: 0;\n  top: -20%;\n  width: 4px;\n  height: 140%;\n  background: #F53501;\n  box-shadow: 0 0 30px #F53501, 0 0 60px #F53501;\n  opacity: 0;\n  z-index: 15;\n}\n\n[data-step=\"1\"] .s-scanner-line {\n  animation: s-scan-move 1.5s cubic-bezier(0.45, 0, 0.55, 1) forwards;\n  opacity: 1;\n}\n\n@keyframes s-scan-move {\n  0% { left: 0%; opacity: 1; }\n  90% { left: 100%; opacity: 1; }\n  100% { left: 100%; opacity: 0; }\n}\n\n.s-tokens-grid {\n  position: absolute;\n  display: flex;\n  gap: 20px;\n  opacity: 0;\n  transform: translateY(20px);\n  transition: all 0.5s ease 0.8s;\n}\n\n[data-step=\"1\"] .s-tokens-grid {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.s-token-item {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 15px;\n}\n\n.s-token-box {\n  background: var(--color);\n  padding: 15px 30px;\n  font-size: 42px;\n  font-weight: 900;\n  border-radius: 4px;\n  color: #000;\n  box-shadow: 0 10px 20px rgba(0,0,0,0.3);\n  transform: scale(0.9);\n  animation: s-pop-in 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;\n  animation-delay: calc(1s + var(--index) * 0.1s);\n}\n\n.s-token-id {\n  font-family: monospace;\n  font-size: 18px;\n  color: var(--color);\n  font-weight: bold;\n  opacity: 0;\n  animation: s-fade-in 0.3s ease forwards;\n  animation-delay: calc(1.5s + var(--index) * 0.1s);\n}\n\n@keyframes s-pop-in {\n  to { transform: scale(1); }\n}\n\n@keyframes s-fade-in {\n  to { opacity: 1; }\n}\n\n@keyframes s-blink {\n  to { opacity: 0.3; }\n}\n\n.s-overlay-info {\n  position: absolute;\n  bottom: 60px;\n  left: 60px;\n  max-width: 600px;\n}\n\n.s-title {\n  font-size: 48px;\n  margin-bottom: 15px;\n  display: flex;\n  align-items: center;\n  gap: 20px;\n}\n\n.s-num { color: #F53501; border: 1px solid #F53501; padding: 0 10px; font-family: monospace; }\n.s-desc {\n  font-size: 18px;\n  color: rgba(255,255,255,0.6);\n  line-height: 1.6;\n  display: none;\n}\n\n[data-step=\"0\"] .s-desc[data-step=\"0\"] { display: block; }\n[data-step=\"1\"] .s-desc[data-step=\"1\"] { display: block; }","js":"window.SceneLifecycle.register('scene-03', {\n  enter() {\n    this.wrapper = document.querySelector('.s-scene-03-wrapper');\n    this.statusVal = document.getElementById('processing-status');\n  },\n  step(s) {\n    if (this.wrapper) {\n      this.wrapper.setAttribute('data-step', s);\n      if (s === 0) {\n        this.statusVal.textContent = 'READY';\n        this.statusVal.style.color = '#F53501';\n      } else if (s === 1) {\n        this.statusVal.textContent = 'TOKENIZING...';\n        this.statusVal.style.color = '#00A3FF';\n        setTimeout(() => {\n           if(this.statusVal) this.statusVal.textContent = 'COMPLETE';\n        }, 1500);\n      }\n    }\n  },\n  leave() {\n    if (this.wrapper) {\n      this.wrapper.setAttribute('data-step', '0');\n    }\n  }\n});"},{"id":"scene-04","title":"预训练预测","steps":3,"html":"<div class=\"s-scene-04-wrapper\" data-step=\"0\">\n  <div class=\"s-grid-bg\"></div>\n\n  <!-- 悬浮公式背景 -->\n  <div class=\"s-math-bg\">\n    <div class=\"s-math-item\" style=\"top: 15%; left: 8%;\">P(x_t|x_{<t}) = softmax(W \\cdot h_t)</div>\n    <div class=\"s-math-item\" style=\"top: 75%; left: 12%;\">h_t = \\text{Transformer}(x_1, \\dots, x_t)</div>\n    <div class=\"s-math-item\" style=\"top: 25%; right: 10%;\">\\mathcal{L} = -\\sum \\log P(x_t|x_{<t})</div>\n    <div class=\"s-math-item\" style=\"top: 80%; right: 15%;\">\\Delta W = -\\eta \\nabla_{W} \\mathcal{L}</div>\n  </div>\n\n  <div class=\"s-main-viewport\">\n    <div class=\"s-layout-container\">\n      \n      <!-- 左侧：输入框 -->\n      <div class=\"s-card s-input-card\">\n        <div class=\"s-card-head\">\n          <span class=\"s-dot\"></span> INPUT SEQUENCE\n        </div>\n        <div class=\"s-card-body\">\n          <span class=\"s-word\">The</span>\n          <span class=\"s-word\">cat</span>\n          <span class=\"s-word\">sits</span>\n          <span class=\"s-word\">on</span>\n          <span class=\"s-word\">the...</span>\n        </div>\n        <div class=\"s-port s-port-right\"></div>\n      </div>\n\n      <!-- 中间：神经网络 -->\n      <div class=\"s-network-container\">\n        <svg class=\"s-net-svg\" viewBox=\"0 0 300 400\" width=\"300\" height=\"400\">\n          <defs>\n            <linearGradient id=\"s-line-grad\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">\n              <stop offset=\"0%\" stop-color=\"#F53501\" stop-opacity=\"0\" />\n              <stop offset=\"50%\" stop-color=\"#F53501\" stop-opacity=\"1\" />\n              <stop offset=\"100%\" stop-color=\"#F53501\" stop-opacity=\"0\" />\n            </linearGradient>\n          </defs>\n          \n          <!-- 基础连线 -->\n          <g class=\"s-lines-base\">\n            <path d=\"M 0 200 L 150 100\" />\n            <path d=\"M 0 200 L 150 200\" />\n            <path d=\"M 0 200 L 150 300\" />\n            <path d=\"M 150 100 L 300 200\" />\n            <path d=\"M 150 200 L 300 200\" />\n            <path d=\"M 150 300 L 300 200\" />\n          </g>\n\n          <!-- 活跃流光连线 -->\n          <g class=\"s-lines-active\">\n            <path d=\"M 0 200 L 150 100\" />\n            <path d=\"M 0 200 L 150 200\" />\n            <path d=\"M 0 200 L 150 300\" />\n            <path d=\"M 150 100 L 300 200\" />\n            <path d=\"M 150 200 L 300 200\" />\n            <path d=\"M 150 300 L 300 200\" />\n          </g>\n        </svg>\n\n        <!-- 隐藏层节点 -->\n        <div class=\"s-node\" style=\"left: 150px; top: 100px;\"></div>\n        <div class=\"s-node\" style=\"left: 150px; top: 200px;\"></div>\n        <div class=\"s-node\" style=\"left: 150px; top: 300px;\"></div>\n      </div>\n\n      <!-- 右侧：输出预测 -->\n      <div class=\"s-card s-output-card\">\n        <div class=\"s-port s-port-left\"></div>\n        <div class=\"s-card-head is-red\">\n          <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" class=\"s-icon\">\n            <path d=\"M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6\"/>\n          </svg>\n          PREDICTION PROBABILITY\n        </div>\n        <div class=\"s-prob-list\">\n          <div class=\"s-prob-row is-target\">\n            <div class=\"s-prob-name\">'mat'</div>\n            <div class=\"s-prob-track\">\n              <div class=\"s-prob-fill\" style=\"--p: 88%\"></div>\n            </div>\n            <div class=\"s-prob-num\">88%</div>\n          </div>\n          <div class=\"s-prob-row\">\n            <div class=\"s-prob-name\">'hat'</div>\n            <div class=\"s-prob-track\">\n              <div class=\"s-prob-fill\" style=\"--p: 9%\"></div>\n            </div>\n            <div class=\"s-prob-num\">09%</div>\n          </div>\n          <div class=\"s-prob-row\">\n            <div class=\"s-prob-name\">'cloud'</div>\n            <div class=\"s-prob-track\">\n              <div class=\"s-prob-fill\" style=\"--p: 3%\"></div>\n            </div>\n            <div class=\"s-prob-num\">03%</div>\n          </div>\n        </div>\n      </div>\n\n    </div>\n  </div>\n\n  <!-- 底部文案 -->\n  <div class=\"s-overlay-info\">\n    <h2 class=\"s-title\"><span class=\"s-num\">03</span> 预训练机制</h2>\n    <div class=\"s-desc-container\">\n      <p class=\"s-desc\" data-target=\"0\">输入已知的文本序列作为环境上下文。</p>\n      <p class=\"s-desc\" data-target=\"1\">网络节点产生波动，数以千亿计的权重参数根据前置输入开始动态激活计算路径。</p>\n      <p class=\"s-desc\" data-target=\"2\">系统最终输出词汇表上所有备选词的概率分布，并推断出最优的下一个词。</p>\n    </div>\n  </div>\n</div>","css":".s-scene-04-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100vh;\n  background: #1B1B1B;\n  overflow: hidden;\n  color: #fff;\n  font-family: 'Alimama ShuHeiTi', sans-serif;\n  box-sizing: border-box;\n}\n\n.s-scene-04-wrapper * {\n  box-sizing: inherit;\n}\n\n.s-grid-bg {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);\n  background-size: 60px 60px;\n  pointer-events: none;\n}\n\n.s-math-bg {\n  position: absolute;\n  inset: 0;\n  pointer-events: none;\n  opacity: 0;\n  transition: opacity 1s ease-in-out;\n}\n\n[data-step=\"1\"] .s-math-bg,\n[data-step=\"2\"] .s-math-bg {\n  opacity: 1;\n}\n\n.s-math-item {\n  position: absolute;\n  font-family: 'Times New Roman', serif;\n  font-style: italic;\n  font-size: 24px;\n  color: rgba(255,255,255,0.04);\n  white-space: nowrap;\n  letter-spacing: 2px;\n}\n\n[data-step=\"1\"] .s-math-item,\n[data-step=\"2\"] .s-math-item {\n  animation: s-math-float 10s linear infinite alternate;\n}\n\n@keyframes s-math-float {\n  0% { transform: translateY(0) scale(1); }\n  100% { transform: translateY(-20px) scale(1.05); }\n}\n\n.s-main-viewport {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  height: 100%;\n  padding-bottom: 80px;\n}\n\n.s-layout-container {\n  display: flex;\n  align-items: center;\n  gap: 0px;\n  position: relative;\n  z-index: 10;\n}\n\n/* 面板通用样式 */\n.s-card {\n  background: #151515;\n  border: 1px solid rgba(255,255,255,0.15);\n  border-radius: 6px;\n  padding: 24px;\n  position: relative;\n  box-shadow: 0 20px 40px rgba(0,0,0,0.5);\n  backdrop-filter: blur(10px);\n}\n\n.s-card-head {\n  display: flex;\n  align-items: center;\n  gap: 10px;\n  font-family: monospace;\n  font-size: 14px;\n  color: #888;\n  margin-bottom: 20px;\n  letter-spacing: 1px;\n  text-transform: uppercase;\n  border-bottom: 1px dashed rgba(255,255,255,0.1);\n  padding-bottom: 12px;\n}\n\n.s-card-head.is-red {\n  color: #F53501;\n  border-bottom-color: rgba(245, 53, 1, 0.3);\n}\n\n.s-dot {\n  width: 8px;\n  height: 8px;\n  background: #fff;\n  border-radius: 50%;\n  display: inline-block;\n}\n\n/* 端口连接点 */\n.s-port {\n  position: absolute;\n  width: 12px;\n  height: 12px;\n  background: #1B1B1B;\n  border: 2px solid #555;\n  border-radius: 50%;\n  top: 50%;\n  transform: translateY(-50%);\n}\n\n.s-port-right {\n  right: -6px;\n}\n\n.s-port-left {\n  left: -6px;\n}\n\n[data-step=\"1\"] .s-port-right,\n[data-step=\"2\"] .s-port-right,\n[data-step=\"2\"] .s-port-left {\n  border-color: #F53501;\n  background: #F53501;\n  box-shadow: 0 0 10px rgba(245, 53, 1, 0.5);\n}\n\n/* 左侧输入卡片 */\n.s-input-card {\n  width: 320px;\n  border-left: 4px solid #F53501;\n}\n\n.s-card-body {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 8px;\n  font-size: 32px;\n  font-weight: 900;\n  line-height: 1.4;\n}\n\n.s-word {\n  display: inline-block;\n}\n\n/* 中间网络区域 */\n.s-network-container {\n  position: relative;\n  width: 300px;\n  height: 400px;\n}\n\n.s-net-svg {\n  width: 100%;\n  height: 100%;\n  position: absolute;\n  left: 0;\n  top: 0;\n}\n\n.s-lines-base path {\n  fill: none;\n  stroke: rgba(255,255,255,0.08);\n  stroke-width: 2;\n}\n\n.s-lines-active path {\n  fill: none;\n  stroke: #F53501;\n  stroke-width: 3;\n  stroke-dasharray: 20 40;\n  stroke-linecap: round;\n  opacity: 0;\n  transition: opacity 0.5s ease;\n}\n\n[data-step=\"1\"] .s-lines-active path,\n[data-step=\"2\"] .s-lines-active path {\n  opacity: 1;\n  animation: s-stroke-flow 1.2s linear infinite;\n}\n\n@keyframes s-stroke-flow {\n  to { stroke-dashoffset: -60; }\n}\n\n.s-node {\n  position: absolute;\n  width: 16px;\n  height: 16px;\n  background: #222;\n  border: 2px solid #555;\n  border-radius: 50%;\n  transform: translate(-50%, -50%);\n  z-index: 2;\n  transition: all 0.4s ease;\n}\n\n[data-step=\"1\"] .s-node,\n[data-step=\"2\"] .s-node {\n  background: #1B1B1B;\n  border-color: #F53501;\n  box-shadow: 0 0 15px rgba(245, 53, 1, 0.6), inset 0 0 5px #F53501;\n}\n\n/* 右侧输出预测 */\n.s-output-card {\n  width: 380px;\n  opacity: 0;\n  transform: translateX(40px);\n  transition: all 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n  pointer-events: none;\n}\n\n[data-step=\"2\"] .s-output-card {\n  opacity: 1;\n  transform: translateX(0);\n  pointer-events: auto;\n}\n\n.s-prob-list {\n  display: flex;\n  flex-direction: column;\n  gap: 16px;\n}\n\n.s-prob-row {\n  display: flex;\n  align-items: center;\n  gap: 12px;\n}\n\n.s-prob-name {\n  width: 60px;\n  font-size: 20px;\n  font-weight: bold;\n  color: #fff;\n}\n\n.s-prob-track {\n  flex: 1;\n  height: 12px;\n  background: rgba(255,255,255,0.05);\n  border-radius: 6px;\n  overflow: hidden;\n  position: relative;\n}\n\n.s-prob-fill {\n  position: absolute;\n  left: 0;\n  top: 0;\n  height: 100%;\n  width: 0;\n  background: rgba(255,255,255,0.4);\n  border-radius: 6px;\n  transition: width 1.2s cubic-bezier(0.2, 0.8, 0.2, 1);\n}\n\n[data-step=\"2\"] .s-prob-fill {\n  width: var(--p);\n}\n\n.s-prob-num {\n  width: 40px;\n  text-align: right;\n  font-family: monospace;\n  font-size: 16px;\n  color: rgba(255,255,255,0.6);\n}\n\n/* 高亮目标概率条 */\n.s-prob-row.is-target .s-prob-name {\n  color: #F53501;\n}\n\n.s-prob-row.is-target .s-prob-fill {\n  background: #F53501;\n}\n\n.s-prob-row.is-target .s-prob-num {\n  color: #F53501;\n  font-weight: bold;\n}\n\n[data-step=\"2\"] .s-prob-row.is-target .s-prob-fill {\n  animation: s-prob-blink 1.2s infinite alternate ease-in-out;\n  animation-delay: 1.2s;\n}\n\n@keyframes s-prob-blink {\n  0% { box-shadow: 0 0 2px #F53501; opacity: 0.8; }\n  100% { box-shadow: 0 0 20px #F53501; opacity: 1; }\n}\n\n/* 底部字幕区 */\n.s-overlay-info {\n  position: absolute;\n  bottom: 60px;\n  left: 60px;\n  max-width: 600px;\n  z-index: 20;\n}\n\n.s-title {\n  font-size: 48px;\n  margin-bottom: 15px;\n  display: flex;\n  align-items: center;\n  gap: 20px;\n}\n\n.s-num {\n  color: #F53501;\n  font-family: monospace;\n  border: 1px solid #F53501;\n  padding: 0 10px;\n}\n\n.s-desc-container {\n  position: relative;\n  height: 60px;\n}\n\n.s-desc {\n  position: absolute;\n  left: 0;\n  top: 0;\n  font-size: 20px;\n  color: rgba(255,255,255,0.7);\n  line-height: 1.6;\n  opacity: 0;\n  transform: translateY(10px);\n  transition: opacity 0.4s ease, transform 0.4s ease;\n  pointer-events: none;\n}\n\n[data-step=\"0\"] .s-desc[data-target=\"0\"],\n[data-step=\"1\"] .s-desc[data-target=\"1\"],\n[data-step=\"2\"] .s-desc[data-target=\"2\"] {\n  opacity: 1;\n  transform: translateY(0);\n}","js":"window.SceneLifecycle.register('scene-04', {\n  enter() {\n    this.wrapper = document.querySelector('.s-scene-04-wrapper');\n  },\n  step(s) {\n    if(this.wrapper) {\n      this.wrapper.setAttribute('data-step', s);\n    }\n  },\n  leave() {\n    if(this.wrapper) {\n      this.wrapper.setAttribute('data-step', '0');\n    }\n  }\n});"},{"id":"scene-05","title":"反向传播","steps":2,"html":"<div class=\"s-scene-05-wrapper\">\n  <div class=\"s-grid-bg\"></div>\n  \n  <div class=\"s-main-viewport\">\n    <!-- Neural Network Visual -->\n    <div class=\"s-network-stage\">\n      <svg class=\"s-network-svg\" viewBox=\"0 0 800 400\">\n        <defs>\n          <filter id=\"glow\">\n            <feGaussianBlur stdDeviation=\"3\" result=\"blur\" />\n            <feComposite in=\"SourceGraphic\" in2=\"blur\" operator=\"over\" />\n          </filter>\n        </defs>\n        <!-- Connection Lines -->\n        <g class=\"s-lines-group\" id=\"backpropLines\">\n          <!-- Hidden to Output -->\n          <path class=\"s-conn-line\" d=\"M550,150 L700,200\" />\n          <path class=\"s-conn-line\" d=\"M550,250 L700,200\" />\n          <!-- Input to Hidden -->\n          <path class=\"s-conn-line\" d=\"M150,100 L350,150\" />\n          <path class=\"s-conn-line\" d=\"M150,200 L350,150\" />\n          <path class=\"s-conn-line\" d=\"M150,300 L350,150\" />\n          <path class=\"s-conn-line\" d=\"M150,100 L350,250\" />\n          <path class=\"s-conn-line\" d=\"M150,200 L350,250\" />\n          <path class=\"s-conn-line\" d=\"M150,300 L350,250\" />\n        </g>\n      </svg>\n\n      <!-- Nodes -->\n      <div class=\"s-nodes-layer\">\n        <div class=\"s-node s-output\" style=\"left: 700px; top: 200px;\"></div>\n        <div class=\"s-node s-hidden\" style=\"left: 350px; top: 150px;\"></div>\n        <div class=\"s-node s-hidden\" style=\"left: 350px; top: 250px;\"></div>\n        <div class=\"s-node s-input\" style=\"left: 150px; top: 100px;\"></div>\n        <div class=\"s-node s-input\" style=\"left: 150px; top: 200px;\"></div>\n        <div class=\"s-node s-input\" style=\"left: 150px; top: 300px;\"></div>\n      </div>\n\n      <!-- Step 0: Error Marker -->\n      <div class=\"s-error-callout\" data-step=\"0\">\n        <div class=\"s-error-header\">ERROR</div>\n        <div class=\"s-error-body\">\n          <div class=\"s-error-row\"><span>预测值:</span><span class=\"s-val\">0.92</span></div>\n          <div class=\"s-error-row\"><span>真实值:</span><span class=\"s-val\">0.10</span></div>\n          <div class=\"s-error-diff\">误差 (Loss): 0.82</div>\n        </div>\n        <div class=\"s-error-arrow\"></div>\n      </div>\n    </div>\n  </div>\n\n  <div class=\"s-overlay-info\">\n    <h2 class=\"s-title\"><span class=\"s-num\">05</span> 反向传播算法</h2>\n    <p class=\"s-desc\" data-step=\"0\">当系统预测错误时，会计算输出与真实的误差。</p>\n    <p class=\"s-desc\" data-step=\"1\">红色波纹沿路径“逆向回溯”，动态调整每一层神经元的连接权重，让下次预测更准。</p>\n  </div>\n</div>","css":".s-scene-05-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100vh;\n  background: #1B1B1B;\n  overflow: hidden;\n  color: #fff;\n  font-family: 'Alimama ShuHeiTi', sans-serif;\n}\n\n.s-grid-bg {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);\n  background-size: 60px 60px;\n  pointer-events: none;\n}\n\n.s-main-viewport {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  height: 100%;\n}\n\n.s-network-stage {\n  position: relative;\n  width: 800px;\n  height: 400px;\n}\n\n.s-network-svg {\n  width: 100%;\n  height: 100%;\n}\n\n.s-conn-line {\n  fill: none;\n  stroke: rgba(255,255,255,0.15);\n  stroke-width: 2;\n  transition: stroke-width 0.6s ease, stroke 0.6s ease;\n}\n\n.s-node {\n  position: absolute;\n  width: 24px;\n  height: 24px;\n  background: #fff;\n  border-radius: 50%;\n  transform: translate(-50%, -50%);\n  box-shadow: 0 0 15px rgba(255,255,255,0.2);\n  z-index: 2;\n}\n\n/* Step 0: Error Styling */\n.s-error-callout {\n  position: absolute;\n  right: 0;\n  top: 100px;\n  width: 180px;\n  background: #F53501;\n  color: #fff;\n  padding: 12px;\n  border-radius: 4px;\n  box-shadow: 0 10px 30px rgba(245, 53, 1, 0.4);\n  animation: s-error-pop 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;\n  z-index: 10;\n}\n\n@keyframes s-error-pop {\n  0% { transform: scale(0.5) translate(20px, -20px); opacity: 0; }\n  100% { transform: scale(1) translate(0, 0); opacity: 1; }\n}\n\n.s-error-header {\n  font-weight: 900;\n  font-size: 20px;\n  border-bottom: 2px solid rgba(255,255,255,0.3);\n  margin-bottom: 8px;\n  padding-bottom: 4px;\n}\n\n.s-error-body {\n  font-size: 14px;\n  font-family: monospace;\n}\n\n.s-error-row {\n  display: flex;\n  justify-content: space-between;\n  margin-bottom: 4px;\n}\n\n.s-error-diff {\n  margin-top: 8px;\n  font-weight: bold;\n  text-align: right;\n}\n\n.s-error-arrow {\n  position: absolute;\n  left: -10px;\n  top: 50%;\n  width: 0; height: 0;\n  border-top: 10px solid transparent;\n  border-bottom: 10px solid transparent;\n  border-right: 10px solid #F53501;\n  transform: translateY(-50%);\n}\n\n/* Step 1: Backprop Animation */\n.is-backpropagating .s-conn-line {\n  stroke-dasharray: 200;\n  stroke-dashoffset: 0;\n  animation: s-back-pulse 2s infinite linear;\n  stroke: #F53501;\n}\n\n.is-backpropagating .s-conn-line:nth-child(even) {\n  stroke-width: 6; /* Thicker weight update representation */\n}\n\n.is-backpropagating .s-conn-line:nth-child(odd) {\n  stroke-width: 1; /* Thinner weight update representation */\n}\n\n@keyframes s-back-pulse {\n  0% { stroke-dashoffset: 0; }\n  100% { stroke-dashoffset: 400; } /* Negative for back direction */\n}\n\n.s-overlay-info {\n  position: absolute;\n  bottom: 60px;\n  left: 60px;\n  max-width: 600px;\n}\n\n.s-title {\n  font-size: 48px;\n  margin-bottom: 15px;\n  display: flex;\n  align-items: center;\n  gap: 20px;\n}\n\n.s-num {\n  color: #F53501;\n  font-family: monospace;\n  border: 1px solid #F53501;\n  padding: 0 10px;\n}\n\n.s-desc {\n  font-size: 18px;\n  color: rgba(255,255,255,0.7);\n  line-height: 1.6;\n  margin-top: 10px;\n  display: none;\n}\n\n[data-step=\"0\"] .s-desc[data-step=\"0\"], \n[data-step=\"1\"] .s-desc[data-step=\"1\"] {\n  display: block;\n}","js":"window.SceneLifecycle.register('scene-05', {\n  enter() {\n    this.stage = document.getElementById('backpropLines');\n    this.wrapper = document.querySelector('.s-scene-05-wrapper');\n  },\n\n  step(s) {\n    this.wrapper.setAttribute('data-step', s);\n    \n    if (s >= 1) {\n      this.stage.classList.add('is-backpropagating');\n    } else {\n      this.stage.classList.remove('is-backpropagating');\n    }\n  },\n\n  leave() {\n    if(this.stage) this.stage.classList.remove('is-backpropagating');\n  }\n});"},{"id":"scene-06","title":"指令微调","steps":2,"html":"<div class=\"s-scene-06-wrapper\">\n  <div class=\"s-grid-bg\"></div>\n  \n  <div class=\"s-main-viewport\">\n    <div class=\"s-chat-interface\">\n      <!-- Step 0: User Prompt -->\n      <div class=\"s-chat-row s-user-row\" data-step=\"0\">\n        <div class=\"s-avatar s-user-avatar\">H</div>\n        <div class=\"s-bubble-wrap\">\n          <div class=\"s-bubble-tag\">HUMAN INTENT</div>\n          <div class=\"s-bubble s-user-bubble\">\n            请写一首关于春天的诗\n          </div>\n        </div>\n      </div>\n\n      <!-- Step 1: AI Response -->\n      <div class=\"s-chat-row s-ai-row\" data-step=\"1\">\n        <div class=\"s-avatar s-ai-avatar\">\n          <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n            <path d=\"M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5\"/>\n          </svg>\n        </div>\n        <div class=\"s-bubble-wrap\">\n          <div class=\"s-bubble-tag\">SFT OPTIMIZED RESPONSE</div>\n          <div class=\"s-bubble s-ai-bubble\" id=\"s-poem-container\">\n            <!-- Poem characters will be injected here -->\n          </div>\n          <div class=\"s-golden-sweep\"></div>\n        </div>\n      </div>\n    </div>\n  </div>\n\n  <div class=\"s-overlay-info\">\n    <h2 class=\"s-title\"><span class=\"s-num\">06</span> 指令微调 (SFT)</h2>\n    <p class=\"s-desc\" data-step=\"0\">指令微调（Supervised Fine-Tuning）是模型进化的关键。</p>\n    <p class=\"s-desc\" data-step=\"1\">通过高质量的人类示范对，模型从“概率预测”转变为“理解指令”，实现真正的意图对齐。</p>\n  </div>\n</div>","css":".s-scene-06-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100vh;\n  background: #1B1B1B;\n  overflow: hidden;\n  color: #fff;\n  font-family: 'Alimama ShuHeiTi', sans-serif;\n}\n\n.s-grid-bg {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px);\n  background-size: 50px 50px;\n  pointer-events: none;\n}\n\n.s-main-viewport {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  height: 100%;\n  padding: 40px;\n}\n\n.s-chat-interface {\n  width: 100%;\n  max-width: 900px;\n  display: flex;\n  flex-direction: column;\n  gap: 40px;\n}\n\n.s-chat-row {\n  display: flex;\n  gap: 20px;\n  opacity: 0;\n  transform: translateY(20px);\n  transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n[data-step=\"0\"] .s-user-row, \n[data-step=\"1\"] .s-ai-row {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.s-avatar {\n  width: 48px;\n  height: 48px;\n  border-radius: 8px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  flex-shrink: 0;\n  font-weight: 900;\n}\n\n.s-user-avatar {\n  background: #444;\n  color: #fff;\n}\n\n.s-ai-avatar {\n  background: #F53501;\n  color: #fff;\n  box-shadow: 0 0 20px rgba(245, 53, 1, 0.3);\n}\n\n.s-bubble-wrap {\n  flex-grow: 1;\n  position: relative;\n}\n\n.s-bubble-tag {\n  font-size: 12px;\n  color: #F53501;\n  margin-bottom: 8px;\n  letter-spacing: 1px;\n  font-family: monospace;\n}\n\n.s-bubble {\n  padding: 24px;\n  border-radius: 4px 20px 20px 20px;\n  font-size: 24px;\n  line-height: 1.4;\n  background: rgba(255, 255, 255, 0.05);\n  border-left: 4px solid #F53501;\n  box-shadow: 0 10px 30px rgba(0,0,0,0.2);\n}\n\n.s-ai-bubble {\n  font-size: 32px;\n  font-weight: bold;\n  background: rgba(245, 53, 1, 0.05);\n  min-height: 160px;\n  color: #fff;\n  display: flex;\n  flex-wrap: wrap;\n  gap: 4px;\n}\n\n.s-char {\n  display: inline-block;\n  animation: s-pop-in 0.2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;\n  opacity: 0;\n  transform: scale(0.5);\n}\n\n@keyframes s-pop-in {\n  to { opacity: 1; transform: scale(1); }\n}\n\n.s-golden-sweep {\n  position: absolute;\n  inset: 0;\n  background: linear-gradient(110deg, transparent 30%, rgba(245, 53, 1, 0.1) 45%, rgba(245, 53, 1, 0.3) 50%, rgba(245, 53, 1, 0.1) 55%, transparent 70%);\n  background-size: 200% 100%;\n  pointer-events: none;\n  z-index: 5;\n  opacity: 0;\n}\n\n.is-sweeping .s-golden-sweep {\n  animation: s-sweep 1.5s ease-in-out infinite;\n  opacity: 1;\n}\n\n@keyframes s-sweep {\n  0% { background-position: 200% 0; }\n  100% { background-position: -200% 0; }\n}\n\n.s-overlay-info {\n  position: absolute;\n  bottom: 60px;\n  left: 60px;\n  max-width: 600px;\n}\n\n.s-title {\n  font-size: 48px;\n  margin-bottom: 15px;\n  display: flex;\n  align-items: center;\n  gap: 20px;\n}\n\n.s-num {\n  color: #F53501;\n  font-family: monospace;\n  border: 1px solid #F53501;\n  padding: 0 10px;\n}\n\n.s-desc {\n  font-size: 18px;\n  color: rgba(255,255,255,0.7);\n  line-height: 1.6;\n  margin-top: 10px;\n  display: none;\n}\n\n[data-step=\"0\"] .s-desc[data-step=\"0\"], \n[data-step=\"1\"] .s-desc[data-step=\"1\"] {\n  display: block;\n}","js":"window.SceneLifecycle.register('scene-06', {\n  enter() {\n    this.container = document.getElementById('s-poem-container');\n    this.wrapper = document.querySelector('.s-scene-06-wrapper');\n    this.poem = \"春入平原荠菜花，新耕细雨带微沙。不知何处声声鸟，唤起千林映日华。\";\n    this.rendered = false;\n  },\n\n  step(s) {\n    this.wrapper.setAttribute('data-step', s);\n    \n    if (s === 1 && !this.rendered) {\n      this.renderPoem();\n    }\n  },\n\n  renderPoem() {\n    this.rendered = true;\n    this.container.innerHTML = '';\n    this.wrapper.classList.add('is-sweeping');\n    \n    const chars = this.poem.split('');\n    chars.forEach((char, index) => {\n      const span = document.createElement('span');\n      span.className = 's-char';\n      span.textContent = char;\n      span.style.animationDelay = `${index * 0.04}s`;\n      \n      // Add line break for comma and period\n      if (char === '，' || char === '。') {\n         this.container.appendChild(span);\n         this.container.appendChild(document.createElement('br'));\n      } else {\n         this.container.appendChild(span);\n      }\n    });\n\n    setTimeout(() => {\n      this.wrapper.classList.remove('is-sweeping');\n    }, (chars.length * 40) + 1000);\n  },\n\n  leave() {\n    if (this.container) this.container.innerHTML = '';\n    this.rendered = false;\n    this.wrapper.classList.remove('is-sweeping');\n  }\n});"},{"id":"scene-07","title":"RLHF 人类对齐","steps":3,"html":"<div class=\"s-scene-07-wrapper\">\n  <div class=\"s-grid-bg\"></div>\n  \n  <div class=\"s-main-viewport\">\n    <div class=\"s-rlhf-container\">\n      <div class=\"s-selection-label\" data-step=\"0\">CHOOSE THE BETTER RESPONSE</div>\n      \n      <div class=\"s-options-stack\">\n        <!-- Option A -->\n        <div class=\"s-option-card s-option-a\" data-step=\"0\">\n          <div class=\"s-option-header\">\n            <span class=\"s-option-tag\">OPTION A</span>\n            <div class=\"s-status-dot\"></div>\n          </div>\n          <div class=\"s-option-content\">\n            <p>虽然我是AI，但我没有感情。春天只是地球公转导致的季节交替，气温升高，植物生长。</p>\n          </div>\n        </div>\n\n        <!-- Option B -->\n        <div class=\"s-option-card s-option-b\" data-step=\"0\">\n          <div class=\"s-option-header\">\n            <span class=\"s-option-tag\">OPTION B</span>\n            <div class=\"s-status-dot\"></div>\n          </div>\n          <div class=\"s-option-content\">\n            <p>春风徐来，万物复苏。春天不仅是自然的更迭，更是希望的开始。这是一首为您创作的诗...</p>\n          </div>\n          <div class=\"s-success-border\"></div>\n        </div>\n      </div>\n\n      <!-- Feedback Hand -->\n      <div class=\"s-feedback-cursor\" data-step=\"1\">\n        <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"s-hand-icon\">\n          <path d=\"M7 10v12\"/>\n          <path d=\"M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2h0a3.13 3.13 0 0 1 3 3.88Z\"/>\n        </svg>\n      </div>\n\n      <!-- Particle Container -->\n      <div class=\"s-particle-canvas\" id=\"s-particles\"></div>\n    </div>\n  </div>\n\n  <div class=\"s-overlay-info\">\n    <h2 class=\"s-title\"><span class=\"s-num\">07</span> 人类反馈强化学习 (RLHF)</h2>\n    <p class=\"s-desc\" data-step=\"0\">RLHF 是模型对齐的关键步骤。我们同时运行两个模型副本，生成不同答案。</p>\n    <p class=\"s-desc\" data-step=\"1\">人类专家对答案进行打分和排序，告诉 AI 哪些回答更符合人类的偏好和价值观。</p>\n    <p class=\"s-desc\" data-step=\"2\">通过奖励模型 (Reward Model) 的迭代，AI 最终学会“如何像人一样思考与表达”。</p>\n  </div>\n</div>","css":".s-scene-07-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100vh;\n  background: #1B1B1B;\n  overflow: hidden;\n  color: #fff;\n  font-family: 'Alimama ShuHeiTi', sans-serif;\n}\n\n.s-grid-bg {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px);\n  background-size: 50px 50px;\n  pointer-events: none;\n}\n\n.s-main-viewport {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  height: 100%;\n  padding: 40px;\n}\n\n.s-rlhf-container {\n  width: 100%;\n  max-width: 800px;\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n}\n\n.s-selection-label {\n  font-size: 14px;\n  color: #F53501;\n  letter-spacing: 2px;\n  margin-bottom: 20px;\n  opacity: 0;\n  transform: translateY(-10px);\n  transition: all 0.5s ease;\n}\n[data-step=\"0\"] .s-selection-label, [data-step=\"1\"] .s-selection-label, [data-step=\"2\"] .s-selection-label { opacity: 1; transform: translateY(0); }\n\n.s-options-stack {\n  width: 100%;\n  display: flex;\n  flex-direction: column;\n  gap: 20px;\n}\n\n.s-option-card {\n  background: rgba(255, 255, 255, 0.03);\n  border: 1px solid rgba(255, 255, 255, 0.1);\n  padding: 30px;\n  border-radius: 4px;\n  position: relative;\n  transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);\n  opacity: 0;\n  transform: translateX(-30px);\n}\n\n.s-option-card[data-step=\"0\"] { opacity: 1; transform: translateX(0); }\n.s-option-card[data-step=\"1\"] { opacity: 1; transform: translateX(0); }\n.s-option-card[data-step=\"2\"] { opacity: 1; transform: translateX(0); }\n\n.s-option-header {\n  display: flex;\n  justify-content: space-between;\n  margin-bottom: 15px;\n}\n\n.s-option-tag {\n  font-size: 12px;\n  color: rgba(255,255,255,0.4);\n  font-family: monospace;\n}\n\n.s-status-dot {\n  width: 8px;\n  height: 8px;\n  background: #444;\n  border-radius: 50%;\n}\n\n.s-option-content {\n  font-size: 20px;\n  line-height: 1.5;\n  color: rgba(255,255,255,0.8);\n}\n\n/* Step Transitions */\n.s-scene-07-wrapper[data-step=\"2\"] .s-option-a {\n  opacity: 0.1;\n  filter: blur(4px);\n  transform: scale(0.95);\n}\n\n.s-scene-07-wrapper[data-step=\"2\"] .s-option-b {\n  border-color: #00FF66;\n  background: rgba(0, 255, 102, 0.05);\n  transform: scale(1.05);\n  z-index: 10;\n}\n\n.s-success-border {\n  position: absolute;\n  inset: 0;\n  border: 2px solid #00FF66;\n  opacity: 0;\n  border-radius: 4px;\n  pointer-events: none;\n}\n\n.s-scene-07-wrapper[data-step=\"2\"] .s-success-border {\n  animation: s-border-pulse 2s infinite;\n}\n\n@keyframes s-border-pulse {\n  0% { opacity: 0.5; transform: scale(1); }\n  50% { opacity: 1; transform: scale(1.01); }\n  100% { opacity: 0.5; transform: scale(1); }\n}\n\n.s-feedback-cursor {\n  position: absolute;\n  right: -20px;\n  bottom: 60px;\n  z-index: 100;\n  color: #F53501;\n  filter: drop-shadow(0 0 15px rgba(245, 53, 1, 0.5));\n  opacity: 0;\n  transform: translate(50px, 50px) scale(1.5);\n  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);\n  pointer-events: none;\n}\n\n.s-scene-07-wrapper[data-step=\"1\"] .s-feedback-cursor {\n  opacity: 1;\n  transform: translate(0, 0) scale(1.2);\n}\n\n.s-scene-07-wrapper[data-step=\"2\"] .s-feedback-cursor {\n  opacity: 1;\n  transform: translate(-40px, -20px) scale(1.4);\n  color: #00FF66;\n}\n\n.s-hand-icon {\n  width: 60px;\n  height: 60px;\n}\n\n.s-particle-canvas {\n  position: absolute;\n  inset: 0;\n  pointer-events: none;\n  z-index: 20;\n}\n\n.s-particle {\n  position: absolute;\n  width: 6px;\n  height: 6px;\n  background: #00FF66;\n  border-radius: 50%;\n  opacity: 0;\n}\n\n.s-overlay-info {\n  position: absolute;\n  bottom: 60px;\n  left: 60px;\n  max-width: 600px;\n}\n\n.s-title {\n  font-size: 48px;\n  margin-bottom: 15px;\n  display: flex;\n  align-items: center;\n  gap: 20px;\n}\n\n.s-num {\n  color: #F53501;\n  font-family: monospace;\n  border: 1px solid #F53501;\n  padding: 0 10px;\n}\n\n.s-desc {\n  font-size: 18px;\n  color: rgba(255,255,255,0.7);\n  line-height: 1.6;\n  margin-top: 10px;\n  display: none;\n}\n\n.s-scene-07-wrapper[data-step=\"0\"] .s-desc[data-step=\"0\"],\n.s-scene-07-wrapper[data-step=\"1\"] .s-desc[data-step=\"1\"],\n.s-scene-07-wrapper[data-step=\"2\"] .s-desc[data-step=\"2\"] {\n  display: block;\n}","js":"window.SceneLifecycle.register('scene-07', {\n  enter() {\n    this.wrapper = document.querySelector('.s-scene-07-wrapper');\n    this.particleContainer = document.getElementById('s-particles');\n  },\n\n  step(s) {\n    this.wrapper.setAttribute('data-step', s);\n    if (s === 2) {\n      this.explodeParticles();\n    }\n  },\n\n  explodeParticles() {\n    if (this.exploded) return;\n    this.exploded = true;\n    \n    const rect = document.querySelector('.s-option-b').getBoundingClientRect();\n    const centerX = rect.left + rect.width / 2;\n    const centerY = rect.top + rect.height / 2;\n\n    for (let i = 0; i < 40; i++) {\n      const p = document.createElement('div');\n      p.className = 's-particle';\n      this.particleContainer.appendChild(p);\n\n      const angle = Math.random() * Math.PI * 2;\n      const velocity = 5 + Math.random() * 10;\n      const tx = Math.cos(angle) * 200 * Math.random();\n      const ty = Math.sin(angle) * 200 * Math.random();\n\n      p.style.left = '50%';\n      p.style.top = '70%';\n      \n      p.animate([\n        { transform: 'translate(0,0) scale(1)', opacity: 1 },\n        { transform: `translate(${tx}px, ${ty}px) scale(0)`, opacity: 0 }\n      ], {\n        duration: 1000 + Math.random() * 1000,\n        easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',\n        fill: 'forwards'\n      });\n    }\n\n    setTimeout(() => { this.exploded = false; this.particleContainer.innerHTML = ''; }, 2500);\n  },\n\n  leave() {\n    this.exploded = false;\n    if (this.particleContainer) this.particleContainer.innerHTML = '';\n  }\n});"},{"id":"scene-08","title":"最终诞生","steps":3,"html":"<div class=\"s-scene-08-wrapper\">\n  <div class=\"s-grid-bg\"></div>\n  \n  <div class=\"s-core-container\">\n    <div class=\"s-radial-glow\" data-step=\"0\"></div>\n    \n    <div class=\"s-icon-orbit\" data-step=\"2\">\n      <div class=\"s-scenario-icon s-icon-translate\">\n        <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m5 8 6 6\"/><path d=\"m4 14 6-6 2-3\"/><path d=\"M2 5h12\"/><path d=\"M7 2h1\"/><path d=\"m22 22-5-10-5 10\"/><path d=\"M14 18h6\"/></svg>\n        <span>翻译</span>\n      </div>\n      <div class=\"s-scenario-icon s-icon-code\">\n        <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"16 18 22 12 16 6\"/><polyline points=\"8 6 2 12 8 18\"/></svg>\n        <span>编程</span>\n      </div>\n      <div class=\"s-scenario-icon s-icon-draw\">\n        <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 19l7-7 3 3-7 7-3-3z\"/><path d=\"M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z\"/><path d=\"M2 2l5 5\"/><path d=\"M9.5 14.5L16 18\"/></svg>\n        <span>绘图</span>\n      </div>\n    </div>\n\n    <div class=\"s-ai-core-group\" data-step=\"0\">\n      <div class=\"s-shimmer-layer\"></div>\n      <div class=\"s-core-hex\">\n        <svg viewBox=\"0 0 200 200\" class=\"s-core-svg\">\n          <defs>\n            <linearGradient id=\"s-grad-accent\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n              <stop offset=\"0%\" stop-color=\"#F53501\" />\n              <stop offset=\"100%\" stop-color=\"#FF6B4A\" />\n            </linearGradient>\n          </defs>\n          <path d=\"M100 20 L170 60 L170 140 L100 180 L30 140 L30 60 Z\" fill=\"none\" stroke=\"rgba(255,255,255,0.1)\" stroke-width=\"2\"/>\n          <path class=\"s-inner-path\" d=\"M100 50 L143 75 L143 125 L100 150 L57 125 L57 75 Z\" fill=\"url(#s-grad-accent)\"/>\n          <circle cx=\"100\" cy=\"100\" r=\"25\" fill=\"#1B1B1B\" />\n          <path class=\"s-logo-mark\" d=\"M90 90 L110 110 M110 90 L90 110\" stroke=\"#F53501\" stroke-width=\"4\" stroke-linecap=\"round\"/>\n        </svg>\n      </div>\n\n      <div class=\"s-progress-wrap\" data-step=\"1\">\n        <svg viewBox=\"0 0 220 220\" class=\"s-progress-svg\">\n          <circle cx=\"110\" cy=\"110\" r=\"100\" class=\"s-track\" />\n          <circle cx=\"110\" cy=\"110\" r=\"100\" class=\"s-bar\" />\n        </svg>\n        <div class=\"s-progress-text\">INITIALIZED</div>\n      </div>\n    </div>\n  </div>\n\n  <div class=\"s-info-overlay\">\n    <h1 class=\"s-main-title\" data-step=\"0\">\n      <span class=\"s-num-tag\">FINALIZE</span><br/>\n      博学的大模型<span class=\"s-accent\">正式诞生</span>\n    </h1>\n    <div class=\"s-desc-box\">\n      <p class=\"s-desc-text\" data-step=\"0\">算力燃烧的终点，是智慧涌现的起点。</p>\n      <p class=\"s-desc-text\" data-step=\"2\">它不再仅仅是工具，而是全人类智慧的数字结晶。</p>\n    </div>\n  </div>\n\n  <div class=\"s-corner-ui\">\n    <div class=\"s-data-tag\">LLM_STATUS: EVOLVED</div>\n    <div class=\"s-data-tag\">COMPUTE_LOAD: STABLE</div>\n  </div>\n</div>","css":".s-scene-08-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100vh;\n  background: #1B1B1B;\n  overflow: hidden;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  font-family: 'Alimama ShuHeiTi', sans-serif;\n  color: #FFFFFF;\n}\n\n.s-grid-bg {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);\n  background-size: 50px 50px;\n  pointer-events: none;\n}\n\n.s-core-container {\n  position: relative;\n  width: 500px;\n  height: 500px;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n}\n\n.s-radial-glow {\n  position: absolute;\n  width: 600px;\n  height: 600px;\n  background: radial-gradient(circle, rgba(245, 53, 1, 0.15) 0%, transparent 70%);\n  opacity: 0;\n  transform: scale(0.5);\n  transition: all 1s cubic-bezier(0.23, 1, 0.32, 1);\n}\n.s-scene-08-wrapper[data-step=\"0\"] .s-radial-glow,\n.s-scene-08-wrapper[data-step=\"1\"] .s-radial-glow,\n.s-scene-08-wrapper[data-step=\"2\"] .s-radial-glow { opacity: 1; transform: scale(1.2); }\n\n.s-ai-core-group {\n  position: relative;\n  width: 240px;\n  height: 240px;\n  opacity: 0;\n  transform: scale(0.5);\n  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n.s-scene-08-wrapper[data-step=\"0\"] .s-ai-core-group,\n.s-scene-08-wrapper[data-step=\"1\"] .s-ai-core-group,\n.s-scene-08-wrapper[data-step=\"2\"] .s-ai-core-group { opacity: 1; transform: scale(1); }\n\n.s-core-hex {\n  position: relative;\n  z-index: 2;\n  filter: drop-shadow(0 0 30px rgba(245, 53, 1, 0.3));\n}\n\n.s-core-svg .s-inner-path {\n  animation: s-core-shimmer 3s infinite ease-in-out;\n}\n\n@keyframes s-core-shimmer {\n  0%, 100% { opacity: 0.8; filter: brightness(1); }\n  50% { opacity: 1; filter: brightness(1.3); }\n}\n\n.s-progress-wrap {\n  position: absolute;\n  inset: -10px;\n  z-index: 3;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n}\n\n.s-progress-svg {\n  width: 100%;\n  height: 100%;\n  transform: rotate(-90deg);\n}\n\n.s-progress-svg .s-track {\n  fill: none;\n  stroke: rgba(255,255,255,0.05);\n  stroke-width: 4;\n}\n\n.s-progress-svg .s-bar {\n  fill: none;\n  stroke: #F53501;\n  stroke-width: 4;\n  stroke-dasharray: 628;\n  stroke-dashoffset: 628;\n  transition: stroke-dashoffset 1.5s cubic-bezier(0.65, 0, 0.35, 1);\n}\n\n.s-scene-08-wrapper[data-step=\"1\"] .s-bar, \n.s-scene-08-wrapper[data-step=\"2\"] .s-bar { stroke-dashoffset: 0; }\n\n.s-progress-text {\n  position: absolute;\n  bottom: -40px;\n  font-size: 12px;\n  letter-spacing: 2px;\n  color: #F53501;\n  font-weight: bold;\n  opacity: 0;\n  transform: translateY(10px);\n  transition: all 0.5s ease 1s;\n}\n.s-scene-08-wrapper[data-step=\"1\"] .s-progress-text,\n.s-scene-08-wrapper[data-step=\"2\"] .s-progress-text { opacity: 1; transform: translateY(0); }\n\n.s-icon-orbit {\n  position: absolute;\n  width: 400px;\n  height: 400px;\n  opacity: 0;\n  transition: opacity 1s ease;\n}\n.s-scene-08-wrapper[data-step=\"2\"] .s-icon-orbit { opacity: 1; }\n\n.s-scenario-icon {\n  position: absolute;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 8px;\n  color: rgba(255,255,255,0.7);\n  animation: s-float 4s infinite ease-in-out;\n}\n\n.s-scenario-icon svg {\n  width: 32px;\n  height: 32px;\n  color: #F53501;\n}\n\n.s-scenario-icon span {\n  font-size: 14px;\n  background: rgba(255,255,255,0.05);\n  padding: 2px 8px;\n  border-radius: 4px;\n}\n\n.s-icon-translate { top: 0; left: 50%; transform: translateX(-50%); }\n.s-icon-code { bottom: 40px; left: 0; animation-delay: -1s; }\n.s-icon-draw { bottom: 40px; right: 0; animation-delay: -2s; }\n\n@keyframes s-float {\n  0%, 100% { transform: translateY(0) scale(1); }\n  50% { transform: translateY(-15px) scale(1.05); }\n}\n\n.s-info-overlay {\n  position: absolute;\n  bottom: 80px;\n  left: 60px;\n  max-width: 600px;\n}\n\n.s-main-title {\n  font-size: 56px;\n  line-height: 1.1;\n  margin-bottom: 20px;\n  opacity: 0;\n  transform: translateX(-30px);\n  transition: all 0.8s ease;\n}\n.s-scene-08-wrapper[data-step=\"0\"] .s-main-title,\n.s-scene-08-wrapper[data-step=\"1\"] .s-main-title,\n.s-scene-08-wrapper[data-step=\"2\"] .s-main-title { opacity: 1; transform: translateX(0); }\n\n.s-num-tag {\n  font-size: 14px;\n  font-family: monospace;\n  border: 1px solid #F53501;\n  color: #F53501;\n  padding: 2px 8px;\n  margin-bottom: 10px;\n  display: inline-block;\n}\n\n.s-accent { color: #F53501; }\n\n.s-desc-box {\n  height: 60px;\n}\n\n.s-desc-text {\n  font-size: 18px;\n  color: rgba(255,255,255,0.6);\n  display: none;\n}\n.s-scene-08-wrapper[data-step=\"0\"] .s-desc-text[data-step=\"0\"],\n.s-scene-08-wrapper[data-step=\"1\"] .s-desc-text[data-step=\"0\"],\n.s-scene-08-wrapper[data-step=\"2\"] .s-desc-text[data-step=\"2\"] {\n  display: block;\n  animation: s-fade-in 0.5s forwards;\n}\n\n@keyframes s-fade-in { from { opacity: 0; } to { opacity: 1; } }\n\n.s-corner-ui {\n  position: absolute;\n  top: 40px;\n  right: 40px;\n  text-align: right;\n}\n\n.s-data-tag {\n  font-size: 10px;\n  font-family: monospace;\n  color: rgba(255,255,255,0.3);\n  border-right: 2px solid #F53501;\n  padding-right: 10px;\n  margin-bottom: 8px;\n}","js":"window.SceneLifecycle.register('scene-08', {\n  enter() {\n    this.wrapper = document.querySelector('.s-scene-08-wrapper');\n    this.wrapper.setAttribute('data-step', '0');\n  },\n  step(s) {\n    this.wrapper.setAttribute('data-step', s);\n    if (s === 1) {\n      const bar = this.wrapper.querySelector('.s-bar');\n      bar.style.strokeDashoffset = '0';\n    }\n  },\n  leave() {}\n});"}]</script>
  <script>
    (function () {
      var state = { sceneId: 'scene-03', step: 0, direction: 1 };
      var previousSceneId = null;
      var exitCleanupTimer = null;
      var isPlaying = false;
      var playTimer = null;
      var progressRaf = null;
      var STEP_INTERVAL_MS = 1400;
      var SCENE_FINISH_PAUSE_MS = 2000;
      var autoplayFromFirstScene = false;
      var progressWrap = document.getElementById('sv-progress-wrap');
      var progressFill = document.getElementById('sv-progress-fill');
      var progressThumb = document.getElementById('sv-progress-thumb');
      var playBtn = document.getElementById('sv-play-btn');
      var expandBtn = document.getElementById('sv-expand-btn');
      var statusText = document.getElementById('sv-status-text');
      var sceneButtonList = Array.prototype.slice.call(document.querySelectorAll('[data-panel-scene-id]'));
      var sceneRetryButtonList = Array.prototype.slice.call(document.querySelectorAll('[data-retry-scene-id]'));
      var editorOverlay = document.getElementById('sv-editor-overlay');
      var editorBackdrop = document.getElementById('sv-editor-backdrop');
      var editorSheet = document.getElementById('sv-editor-sheet');
      var editorResizeHandle = document.getElementById('sv-editor-resize-handle');
      var editorCloseBtn = document.getElementById('sv-editor-close-btn');
      var editorSaveBtn = document.getElementById('sv-editor-save-btn');
      var editorList = document.getElementById('sv-editor-list');
      var editorSaveTip = document.getElementById('sv-editor-save-tip');
      var editorTipTimer = null;
      var isEditorOpen = false;
      var isEditorDirty = false;
      var editorHeightVh = 50;
      var hostCaps = { canRetry: false, canEditPanel: false, locale: 'zh', theme: 'dark' };
      var metaJson = document.getElementById('__SVGVIDEO_META__');
      var meta = { scenes: [] };
      try {
        meta = JSON.parse((metaJson && metaJson.textContent) || '{}');
      } catch (e) {
        meta = { scenes: [] };
      }
      var metaSceneMap = {};
      var metaScenes = Array.isArray(meta.scenes) ? meta.scenes : [];
      metaScenes.forEach(function (scene) {
        if (scene && typeof scene.id === 'string' && scene.id) metaSceneMap[scene.id] = scene;
      });
      var sceneModels = Array.prototype.slice.call(document.querySelectorAll('#stage > [data-scene-id]')).map(function (node, index) {
        var sceneId = node.getAttribute('data-scene-id') || ('scene-' + (index + 1));
        var metaScene = metaSceneMap[sceneId] || {};
        var sceneTitle = typeof metaScene.title === 'string' && metaScene.title ? metaScene.title : ('分镜' + (index + 1));
        var sceneSteps = Math.max(1, Number(metaScene.steps) || 1);
        var sceneStatus = typeof metaScene.status === 'string' ? metaScene.status : 'pending';
        var scenePrompt = typeof metaScene.prompt === 'string' ? metaScene.prompt : '';
        var sceneScript = typeof metaScene.scriptText === 'string' ? metaScene.scriptText : '';
        var sceneAudioObjectKey = typeof metaScene.audioObjectKey === 'string' ? metaScene.audioObjectKey : '';
        var sceneAudioDurationMs = Number(metaScene.audioDurationMs) > 0 ? Number(metaScene.audioDurationMs) : 0;
        var sceneVoiceName = typeof metaScene.voiceName === 'string' ? metaScene.voiceName : '';
        var relatedSceneIds = Array.isArray(metaScene.relatedSceneIds) ? metaScene.relatedSceneIds : [];
        return {
          id: sceneId,
          title: sceneTitle,
          steps: sceneSteps,
          status: sceneStatus,
          prompt: scenePrompt,
          scriptText: sceneScript,
          audioObjectKey: sceneAudioObjectKey,
          audioDurationMs: sceneAudioDurationMs,
          voiceName: sceneVoiceName,
          relatedSceneIds: relatedSceneIds
        };
      });
      if (!sceneModels.length && metaScenes.length) {
        sceneModels = metaScenes.map(function (scene, index) {
          return {
            id: scene.id || ('scene-' + (index + 1)),
            title: scene.title || ('分镜' + (index + 1)),
            steps: Math.max(1, Number(scene.steps) || 1),
            status: typeof scene.status === 'string' ? scene.status : 'pending',
            prompt: typeof scene.prompt === 'string' ? scene.prompt : '',
            scriptText: typeof scene.scriptText === 'string' ? scene.scriptText : '',
            audioObjectKey: typeof scene.audioObjectKey === 'string' ? scene.audioObjectKey : '',
            audioDurationMs: Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0,
            voiceName: typeof scene.voiceName === 'string' ? scene.voiceName : '',
            relatedSceneIds: Array.isArray(scene.relatedSceneIds) ? scene.relatedSceneIds : []
          };
        });
      }
      function i18nText(zh, en) {
        return hostCaps.locale === 'en' ? en : zh;
      }
      function applyI18nTexts() {
        var toolbarTitleEl = document.getElementById('sv-toolbar-title');
        var titleEl = document.getElementById('sv-editor-header-title');
        if (toolbarTitleEl) toolbarTitleEl.textContent = i18nText('分镜面板', 'Storyboard');
        if (titleEl) titleEl.textContent = i18nText('分镜详情编辑', 'Storyboard details');
        if (expandBtn) {
          var expandText = i18nText('展开分镜详情', 'Open storyboard details');
          expandBtn.setAttribute('aria-label', expandText);
          expandBtn.setAttribute('title', expandText);
        }
        if (editorSaveBtn) editorSaveBtn.textContent = isEditorDirty ? i18nText('保存*', 'Save*') : i18nText('保存', 'Save');
        if (editorCloseBtn) editorCloseBtn.textContent = i18nText('关闭', 'Close');
        if (editorSaveTip) editorSaveTip.textContent = i18nText('已保存', 'Saved');
      }
      function clampEditorHeightVh(value) {
        return Math.max(32, Math.min(80, Number(value) || 50));
      }
      function applyEditorHeight(vh) {
        editorHeightVh = clampEditorHeightVh(vh);
        document.documentElement.style.setProperty('--sv-editor-height', editorHeightVh + 'vh');
      }
      function persistMetaToScript() {
        meta.title = typeof meta.title === 'string' ? meta.title : '';
        meta.version = meta.version || 1;
        meta.scenes = sceneModels.map(function (scene) {
          return {
            id: scene.id,
            title: scene.title || '',
            steps: Math.max(1, Number(scene.steps) || 1),
            status: scene.status || 'pending',
            prompt: scene.prompt || '',
            scriptText: scene.scriptText || '',
            audioObjectKey: scene.audioObjectKey || '',
            audioDurationMs: Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0,
            voiceName: scene.voiceName || '',
            relatedSceneIds: Array.isArray(scene.relatedSceneIds) ? scene.relatedSceneIds : []
          };
        });
        if (metaJson) metaJson.textContent = JSON.stringify(meta);
      }
      function showSavedTip() {
        if (!editorSaveTip) return;
        if (editorTipTimer) {
          clearTimeout(editorTipTimer);
          editorTipTimer = null;
        }
        editorSaveTip.classList.add('is-visible');
        editorTipTimer = setTimeout(function () {
          editorSaveTip.classList.remove('is-visible');
        }, 1200);
      }
      function markEditorDirty() {
        isEditorDirty = true;
        applyI18nTexts();
      }
      function clearEditorDirty() {
        isEditorDirty = false;
        applyI18nTexts();
      }
      function getStatusLabel(status) {
        if (status === 'success') return i18nText('已生成', 'Done');
        if (status === 'generating') return i18nText('生成中', 'Generating');
        if (status === 'failed') return i18nText('失败', 'Failed');
        return i18nText('未生成', 'Pending');
      }
      function getStatusClass(status) {
        if (status === 'generating') return 'is-generating';
        if (status === 'success') return 'is-success';
        return 'is-failed';
      }
      function getRetryButtonInnerHtml(isGenerating) {
        if (isGenerating) return '<span class="scene-chip-retry-spinner"></span>';
        return '<svg class="scene-chip-retry-icon" viewBox="0 0 1024 1024" width="16" height="16" fill="currentColor"><path d="M698.569 531.322a39.825 39.825 0 0 0-23.898 7.949c-17.702 13.216-21.34 38.28-8.124 55.982l95.716 128.212c7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949c17.702-13.216 21.34-38.28 8.124-55.982l-95.716-128.212c-7.853-10.521-19.892-16.074-32.084-16.073z" /><path d="M922.498 563.818a39.825 39.825 0 0 0-23.898 7.949l-128.212 95.716c-17.703 13.216-21.34 38.28-8.124 55.982 7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949l128.212-95.716c17.702-13.216 21.34-38.28 8.124-55.982-7.854-10.521-19.893-16.074-32.084-16.073zM229.652 282.148a39.825 39.825 0 0 0-23.898 7.949c-17.702 13.216-21.34 38.28-8.124 55.982l95.716 128.212c7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949c17.702-13.216 21.34-38.28 8.124-55.982l-95.716-128.212c-7.854-10.521-19.892-16.074-32.084-16.073z" /><path d="M229.652 282.148a39.825 39.825 0 0 0-23.898 7.949L77.542 385.813c-17.702 13.216-21.34 38.28-8.124 55.982 7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949l128.213-95.716c17.702-13.216 21.34-38.28 8.124-55.982-7.855-10.521-19.893-16.073-32.085-16.073z" /><path d="M614.968 763.65c-44.13 18.171-94.005 25.121-146.168 16.968C353.747 762.636 261.364 670.253 243.381 555.2c-9.681-61.936 1.932-120.646 28.337-170.344l-58.657-58.657c-40.139 64.442-60.11 142.746-50.806 226.152 17.993 161.306 148.088 291.401 309.394 309.394 62.041 6.92 121.259-2.357 174.048-24.083 26.535-10.921 33.625-45.203 13.335-65.493l-0.098-0.098c-11.555-11.555-28.854-14.643-43.966-8.421zM409.033 260.35c44.131-18.171 94.007-25.122 146.169-16.968 115.051 17.985 207.431 110.365 225.416 225.416 9.682 61.935-1.931 120.646-28.337 170.346l58.658 58.658c40.139-64.443 60.109-142.747 50.805-226.155-17.993-161.305-148.087-291.399-309.391-309.391-62.042-6.92-121.26 2.356-174.05 24.082-26.535 10.921-33.625 45.203-13.335 65.493l0.099 0.099c11.555 11.554 28.854 14.642 43.966 8.42z" /></svg>';
      }
      function setSceneStatus(sceneId, status) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return;
        sceneModels[index].status = status;
        persistMetaToScript();
        var statusClass = getStatusClass(status);
        var chipWrap = document.querySelector('[data-chip-scene-id="' + sceneId + '"]');
        if (chipWrap) {
          chipWrap.classList.remove('is-success', 'is-failed', 'is-generating');
          chipWrap.classList.add(statusClass);
          var chipBtn = chipWrap.querySelector('.scene-chip');
          if (chipBtn) {
            chipBtn.classList.remove('is-success', 'is-failed', 'is-generating');
            chipBtn.classList.add(statusClass);
          }
          var retryBtn = chipWrap.querySelector('.scene-chip-retry');
          if (retryBtn) {
            retryBtn.innerHTML = getRetryButtonInnerHtml(status === 'generating');
            if (status === 'generating') retryBtn.setAttribute('disabled', 'disabled');
            else retryBtn.removeAttribute('disabled');
          }
        }
        renderStatus();
      }
      function requestSceneRetry(sceneId) {
        if (!hostCaps.canRetry) return;
        var idx = getSceneIndexById(sceneId);
        if (idx < 0) return;
        var scene = sceneModels[idx];
        setSceneStatus(sceneId, 'generating');
        focusScene(sceneId);
        if (window.parent && window.parent !== window) {
          window.parent.postMessage(
            { type: '__SVGVIDEO_RETRY_SCENE', sceneId: sceneId, prompt: scene.prompt || '' },
            '*'
          );
        }
      }
      function renderEditorList() {
        if (!editorList) return;
        editorList.innerHTML = '';
        var fragment = document.createDocumentFragment();
        sceneModels.forEach(function (scene, index) {
          var item = document.createElement('section');
          item.className = 'sv-editor-item';
          item.setAttribute('data-editor-scene-id', scene.id);

          var head = document.createElement('div');
          head.className = 'sv-editor-item-head';

          var jumpBtn = document.createElement('button');
          jumpBtn.type = 'button';
          jumpBtn.className = 'sv-editor-item-title';
          jumpBtn.textContent = i18nText('分镜', 'Scene') + (index + 1) + ' · ' + (scene.title || '');
          jumpBtn.addEventListener('click', function () {
            focusScene(scene.id);
          });
          head.appendChild(jumpBtn);

          var statusWrap = document.createElement('div');
          statusWrap.className = 'sv-editor-status-wrap';
          var status = document.createElement('span');
          status.className = 'sv-editor-status';
          status.textContent = getStatusLabel(scene.status);
          statusWrap.appendChild(status);
          var retryBtn = document.createElement('button');
          retryBtn.type = 'button';
          retryBtn.className = 'scene-chip-retry sv-editor-retry';
          retryBtn.setAttribute('aria-label', i18nText('重新生成当前分镜', 'Retry this scene'));
          retryBtn.setAttribute('title', i18nText('重新生成当前分镜', 'Retry this scene'));
          retryBtn.innerHTML = getRetryButtonInnerHtml(scene.status === 'generating');
          if (scene.status === 'generating' || !hostCaps.canRetry) retryBtn.setAttribute('disabled', 'disabled');
          retryBtn.addEventListener('click', function (event) {
            event.preventDefault();
            event.stopPropagation();
            requestSceneRetry(scene.id);
            if (isEditorOpen) renderEditorList();
          });
          statusWrap.appendChild(retryBtn);
          head.appendChild(statusWrap);

          item.appendChild(head);

          var scriptField = document.createElement('label');
          scriptField.className = 'sv-editor-field';
          var scriptLabel = document.createElement('span');
          scriptLabel.className = 'sv-editor-label';
          scriptLabel.textContent = i18nText('脚本', 'Script');
          var scriptInput = document.createElement('div');
          scriptInput.className = 'sv-editor-script-view';
          scriptInput.setAttribute('data-field-scene-id', scene.id);
          scriptInput.textContent = scene.scriptText || '';
          scriptField.appendChild(scriptLabel);
          scriptField.appendChild(scriptInput);
          item.appendChild(scriptField);

          var promptField = document.createElement('label');
          promptField.className = 'sv-editor-field';
          var promptLabel = document.createElement('span');
          promptLabel.className = 'sv-editor-label';
          promptLabel.textContent = i18nText('提示词', 'Prompt');
          var promptInput = document.createElement('textarea');
          promptInput.className = 'sv-editor-textarea';
          promptInput.setAttribute('data-field-scene-id', scene.id);
          promptInput.setAttribute('data-field', 'prompt');
          promptInput.value = scene.prompt || '';
          promptInput.addEventListener('click', function (event) {
            event.stopPropagation();
          });
          promptInput.addEventListener('input', function () {
            scene.prompt = promptInput.value;
            markEditorDirty();
          });
          promptField.appendChild(promptLabel);
          promptField.appendChild(promptInput);
          item.appendChild(promptField);
          item.addEventListener('click', function () {
            focusScene(scene.id);
          });

          fragment.appendChild(item);
        });
        editorList.appendChild(fragment);
        highlightActiveEditorItem();
      }
      function highlightActiveEditorItem() {
        if (!editorList) return;
        var itemList = Array.prototype.slice.call(editorList.querySelectorAll('[data-editor-scene-id]'));
        itemList.forEach(function (item) {
          if (item.getAttribute('data-editor-scene-id') === state.sceneId) item.classList.add('is-active');
          else item.classList.remove('is-active');
        });
      }
      function openEditor() {
        if (!hostCaps.canEditPanel) return;
        if (!editorOverlay) return;
        renderEditorList();
        applyEditorHeight(editorHeightVh);
        editorOverlay.classList.add('is-open');
        editorOverlay.setAttribute('aria-hidden', 'false');
        document.body.classList.add('sv-editor-open');
        isEditorOpen = true;
      }
      function closeEditor() {
        if (!editorOverlay) return;
        editorOverlay.classList.remove('is-open');
        editorOverlay.setAttribute('aria-hidden', 'true');
        document.body.classList.remove('sv-editor-open');
        isEditorOpen = false;
      }
      function saveEditor() {
        persistMetaToScript();
        clearEditorDirty();
        showSavedTip();
        if (window.parent && window.parent !== window) {
          window.parent.postMessage({ type: '__SVGVIDEO_META_UPDATED', meta: meta }, '*');
        }
      }
      function getTotalSteps() {
        return sceneModels.reduce(function (sum, scene) { return sum + Math.max(1, Number(scene.steps) || 1); }, 0);
      }
      function getSceneIndexById(sceneId) {
        for (var i = 0; i < sceneModels.length; i++) {
          if (sceneModels[i].id === sceneId) return i;
        }
        return -1;
      }
      function getSceneInitialStep(sceneId) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return 0;
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        return Math.max(0, maxSteps - 1);
      }
      function focusScene(sceneId) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return;
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        stopPlayback();
        window.__SVGVIDEO_SET_STATE(sceneId, 0, 1);
        if (maxSteps > 1) {
          setTimeout(function () {
            window.__SVGVIDEO_SET_STATE(sceneId, Math.max(0, maxSteps - 1), 1);
          }, 90);
        }
      }
      function getProgressPercent(sceneId, step) {
        var total = getTotalSteps();
        if (!total) return 0;
        var index = getSceneIndexById(sceneId);
        if (index < 0) return 0;
        var completed = 0;
        for (var i = 0; i < index; i++) completed += Math.max(1, Number(sceneModels[i].steps) || 1);
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        var localStep = Math.max(0, Math.min(maxSteps - 1, Number(step) || 0));
        return Math.max(0, Math.min(100, ((completed + localStep) / total) * 100));
      }
      function updateProgressUi(percent) {
        var pct = Math.max(0, Math.min(100, percent || 0));
        if (progressFill) progressFill.style.width = pct + '%';
        if (progressThumb) progressThumb.style.left = pct + '%';
      }
      function stopProgressAnimation() {
        if (progressRaf) {
          cancelAnimationFrame(progressRaf);
          progressRaf = null;
        }
      }
      function startProgressSegment(fromPercent, toPercent, durationMs) {
        stopProgressAnimation();
        var from = Math.max(0, Math.min(100, Number(fromPercent) || 0));
        var to = Math.max(0, Math.min(100, Number(toPercent) || 0));
        var duration = Math.max(1, Number(durationMs) || 1);
        if (duration <= 1 || to <= from) {
          updateProgressUi(to);
          return;
        }
        var startAt = performance.now();
        var tick = function (now) {
          if (!isPlaying) {
            stopProgressAnimation();
            return;
          }
          var elapsed = now - startAt;
          var ratio = Math.max(0, Math.min(1, elapsed / duration));
          var current = from + (to - from) * ratio;
          updateProgressUi(current);
          if (ratio < 1) {
            progressRaf = requestAnimationFrame(tick);
          } else {
            stopProgressAnimation();
          }
        };
        progressRaf = requestAnimationFrame(tick);
      }
      function getPlaybackSegment(sceneIndex, step) {
        var scene = sceneModels[sceneIndex];
        if (!scene) return null;
        var currentPercent = getProgressPercent(scene.id, step);
        var maxSteps = Math.max(1, Number(scene.steps) || 1);
        if (step < maxSteps - 1) {
          return {
            from: currentPercent,
            to: getProgressPercent(scene.id, step + 1),
            duration: STEP_INTERVAL_MS
          };
        }
        if (sceneIndex < sceneModels.length - 1) {
          var nextScene = sceneModels[sceneIndex + 1];
          var nextPercent = nextScene ? getProgressPercent(nextScene.id, 0) : currentPercent;
          return {
            from: currentPercent,
            to: nextPercent,
            duration: SCENE_FINISH_PAUSE_MS
          };
        }
        return {
          from: currentPercent,
          to: 100,
          duration: STEP_INTERVAL_MS
        };
      }
      function renderStatus() {
        if (!statusText) return;
        var done = sceneModels.filter(function (scene) { return scene.status === 'success'; }).length;
        var pending = sceneModels.filter(function (scene) { return scene.status === 'pending' || scene.status === 'generating'; }).length;
        var failed = sceneModels.filter(function (scene) { return scene.status === 'failed'; }).length;
        statusText.textContent = '已生成 ' + done + '/' + sceneModels.length + ' · 待生成 ' + pending + ' · 失败 ' + failed;
      }
      function updatePlayButton() {
        if (!playBtn) return;
        playBtn.innerHTML = isPlaying
          ? '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><rect x="6" y="5" width="4" height="14" rx="1"></rect><rect x="14" y="5" width="4" height="14" rx="1"></rect></svg>'
          : '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M7 5v14l11-7z"></path></svg>';
        playBtn.setAttribute('aria-label', isPlaying ? '暂停播放' : '播放分镜');
        playBtn.setAttribute('title', isPlaying ? '暂停播放' : '播放分镜');
      }
      function applyHostCaps() {
        if (hostCaps.canRetry) document.body.classList.add('sv-host-can-retry');
        else document.body.classList.remove('sv-host-can-retry');
        if (hostCaps.canEditPanel) document.body.classList.add('sv-host-can-edit-panel');
        else document.body.classList.remove('sv-host-can-edit-panel');
        if (hostCaps.theme === 'light') document.body.classList.add('sv-theme-light');
        else document.body.classList.remove('sv-theme-light');
      }
      function highlightActiveSceneButton() {
        sceneButtonList.forEach(function (button) {
          var targetId = button.getAttribute('data-panel-scene-id');
          if (targetId === state.sceneId) button.classList.add('is-active');
          else button.classList.remove('is-active');
        });
      }
      function stopPlayback() {
        if (playTimer) {
          clearTimeout(playTimer);
          playTimer = null;
        }
        stopProgressAnimation();
        isPlaying = false;
        updatePlayButton();
      }
      function startPlayback() {
        if (!sceneModels.length) return;
        stopPlayback();
        var sceneIndex = Math.max(0, getSceneIndexById(state.sceneId));
        var step = 0;
        var applyPlaybackState = function (direction) {
          var scene = sceneModels[sceneIndex];
          if (!scene) return false;
          window.__SVGVIDEO_SET_STATE(scene.id, step, direction);
          updateProgressUi(getProgressPercent(scene.id, step));
          var segment = getPlaybackSegment(sceneIndex, step);
          if (segment) startProgressSegment(segment.from, segment.to, segment.duration);
          return true;
        };
        var scheduleAdvance = function (delay) {
          playTimer = setTimeout(function () {
            var currentScene = sceneModels[sceneIndex];
            if (!currentScene) {
              stopPlayback();
              return;
            }
            var maxSteps = Math.max(1, Number(currentScene.steps) || 1);
            if (step < maxSteps - 1) {
              step += 1;
              applyPlaybackState(1);
              scheduleAdvance(STEP_INTERVAL_MS);
              return;
            }
            if (sceneIndex < sceneModels.length - 1) {
              playTimer = setTimeout(function () {
                sceneIndex += 1;
                step = 0;
                if (!applyPlaybackState(1)) {
                  stopPlayback();
                  return;
                }
                scheduleAdvance(STEP_INTERVAL_MS);
              }, SCENE_FINISH_PAUSE_MS);
              return;
            }
            stopPlayback();
          }, delay);
        };
        isPlaying = true;
        updatePlayButton();
        if (!applyPlaybackState(1)) {
          stopPlayback();
          return;
        }
        scheduleAdvance(STEP_INTERVAL_MS);
      }
      window.SceneLifecycle = {
        handlers: {},
        register: function (sceneId, handler) { this.handlers[sceneId] = handler || {}; }
      };

      (function () {
        var sceneDataJson = document.getElementById('__SVGVIDEO_SCENE_DATA__');
        var runtimeScenes = [];
        try {
          runtimeScenes = JSON.parse((sceneDataJson && sceneDataJson.textContent) || '[]');
        } catch (_e) {
          runtimeScenes = [];
        }
        runtimeScenes.forEach(function (scene) {
          if (!scene || typeof scene.id !== 'string') return;
          var js = typeof scene.js === 'string' ? scene.js.trim() : '';
          if (!js) return;
          try {
            var factory = new Function(js);
            factory.call(window);
          } catch (err) {
            console.error('[svg-video] scene runtime failed', scene.id, err);
          }
        });
      })();

      function applyStepVisibility(sceneEl) {
        var stepNodes = sceneEl.querySelectorAll('[data-step]');
        stepNodes.forEach(function (node) {
          var minStep = Number(node.getAttribute('data-step') || '0');
          var visible = state.step >= minStep;
          node.style.opacity = visible ? '1' : '0';
          node.style.visibility = visible ? 'visible' : 'hidden';
          node.style.pointerEvents = visible ? 'auto' : 'none';
          node.style.transform = visible ? 'translateY(0)' : 'translateY(8px)';
          node.style.filter = visible ? 'blur(0px)' : 'blur(4px)';
        });
      }
      function applySceneState() {
        var scenes = document.querySelectorAll('#stage > [data-scene-id]');
        var currentSceneEl = null;
        var previousSceneEl = null;
        scenes.forEach(function (sceneEl) {
          var sceneId = sceneEl.getAttribute('data-scene-id');
          if (sceneId === state.sceneId) currentSceneEl = sceneEl;
          if (sceneId === previousSceneId) previousSceneEl = sceneEl;
        });
        var direction = state.direction >= 0 ? 1 : -1;
        document.documentElement.style.setProperty('--scene-enter-offset', direction > 0 ? '56px' : '-56px');
        document.documentElement.style.setProperty('--scene-exit-offset', direction > 0 ? '-56px' : '56px');
        if (exitCleanupTimer) {
          clearTimeout(exitCleanupTimer);
          exitCleanupTimer = null;
        }
        scenes.forEach(function (sceneEl) {
          if (sceneEl !== currentSceneEl && sceneEl !== previousSceneEl) {
            sceneEl.classList.remove('scene-active');
            sceneEl.classList.remove('scene-exit');
          }
        });
        if (previousSceneEl && previousSceneEl !== currentSceneEl) {
          previousSceneEl.classList.remove('scene-active');
          previousSceneEl.classList.add('scene-exit');
        }
        if (currentSceneEl) {
          currentSceneEl.classList.remove('scene-exit');
          currentSceneEl.classList.add('scene-active');
          applyStepVisibility(currentSceneEl);
        }
        if (previousSceneEl && previousSceneEl !== currentSceneEl) {
          exitCleanupTimer = setTimeout(function () { previousSceneEl.classList.remove('scene-exit'); }, 620);
        }
        if (previousSceneId !== state.sceneId) {
          if (previousSceneId && window.SceneLifecycle.handlers[previousSceneId] && typeof window.SceneLifecycle.handlers[previousSceneId].leave === 'function') {
            try { window.SceneLifecycle.handlers[previousSceneId].leave(); } catch (e) {}
          }
          if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].enter === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].enter(); } catch (e) {}
          }
        }
        if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].step === 'function') {
          try { window.SceneLifecycle.handlers[state.sceneId].step(state.step); } catch (e) {}
        }
        previousSceneId = state.sceneId;
        highlightActiveSceneButton();
        highlightActiveEditorItem();
        updateProgressUi(getProgressPercent(state.sceneId, state.step));
      }
      window.__SVGVIDEO_SET_STATE = function (sceneId, step, direction) {
        if (typeof sceneId === 'string' && sceneId) {
          if (typeof direction === 'number' && Number.isFinite(direction)) {
            state.direction = direction >= 0 ? 1 : -1;
          } else {
            var nextIndex = getSceneIndexById(sceneId);
            var prevIndex = getSceneIndexById(state.sceneId);
            if (nextIndex !== -1 && prevIndex !== -1) state.direction = nextIndex >= prevIndex ? 1 : -1;
          }
          state.sceneId = sceneId;
        }
        if (typeof step === 'number' && Number.isFinite(step)) state.step = Math.max(0, Math.floor(step));
        applySceneState();
      };
      if (state.sceneId && getSceneIndexById(state.sceneId) === -1 && sceneModels.length) {
        state.sceneId = sceneModels[0].id;
      }
      if (playBtn) {
        playBtn.addEventListener('click', function () {
          if (isPlaying) stopPlayback();
          else startPlayback();
        });
      }
      if (expandBtn) {
        expandBtn.addEventListener('click', function () {
          if (isEditorOpen) closeEditor();
          else openEditor();
        });
      }
      if (editorCloseBtn) {
        editorCloseBtn.addEventListener('click', closeEditor);
      }
      if (editorBackdrop) {
        editorBackdrop.addEventListener('click', closeEditor);
      }
      if (editorSaveBtn) {
        editorSaveBtn.addEventListener('click', saveEditor);
      }
      if (editorResizeHandle && editorSheet) {
        editorResizeHandle.addEventListener('mousedown', function (event) {
          event.preventDefault();
          var startY = event.clientY;
          var startHeightPx = (window.innerHeight * editorHeightVh) / 100;
          var onMove = function (moveEvent) {
            var delta = startY - moveEvent.clientY;
            var nextHeightPx = startHeightPx + delta;
            var nextHeightVh = (nextHeightPx / Math.max(1, window.innerHeight)) * 100;
            applyEditorHeight(nextHeightVh);
          };
          var onUp = function () {
            window.removeEventListener('mousemove', onMove);
            window.removeEventListener('mouseup', onUp);
          };
          window.addEventListener('mousemove', onMove);
          window.addEventListener('mouseup', onUp);
        });
      }
      sceneButtonList.forEach(function (button) {
        button.addEventListener('click', function () {
          var sceneId = button.getAttribute('data-panel-scene-id');
          if (!sceneId) return;
          focusScene(sceneId);
        });
      });
      sceneRetryButtonList.forEach(function (button) {
        button.addEventListener('click', function (event) {
          event.preventDefault();
          event.stopPropagation();
          var sceneId = button.getAttribute('data-retry-scene-id');
          if (!sceneId) return;
          requestSceneRetry(sceneId);
        });
      });
      if (progressWrap) {
        progressWrap.addEventListener('click', function (event) {
          var rect = progressWrap.getBoundingClientRect();
          var pct = Math.max(0, Math.min(100, ((event.clientX - rect.left) / rect.width) * 100));
          var totalSteps = getTotalSteps();
          var targetStep = Math.round((pct / 100) * totalSteps);
          var accumulated = 0;
          for (var i = 0; i < sceneModels.length; i++) {
            var sceneSteps = Math.max(1, Number(sceneModels[i].steps) || 1);
            if (accumulated + sceneSteps > targetStep) {
              var localStep = Math.max(0, Math.min(sceneSteps - 1, targetStep - accumulated));
              stopPlayback();
              window.__SVGVIDEO_SET_STATE(sceneModels[i].id, localStep, 1);
              updateProgressUi(pct);
              return;
            }
            accumulated += sceneSteps;
          }
        });
      }
      window.addEventListener('message', function (event) {
        var data = event && event.data;
        if (!data || typeof data.type !== 'string') return;
        if (data.type === '__SVGVIDEO_SET_STATE') {
          window.__SVGVIDEO_SET_STATE(data.sceneId, data.step, data.direction);
          return;
        }
        if (data.type === '__SVGVIDEO_PLAY') {
          startPlayback();
          return;
        }
        if (data.type === '__SVGVIDEO_STOP') {
          stopPlayback();
          return;
        }
        if (data.type === '__SVGVIDEO_SET_HOST_CAPS') {
          hostCaps.canRetry = Boolean(data.canRetry);
          hostCaps.canEditPanel = Boolean(data.canEditPanel);
          hostCaps.locale = data.locale === 'en' ? 'en' : 'zh';
          hostCaps.theme = data.theme === 'light' ? 'light' : 'dark';
          applyI18nTexts();
          applyHostCaps();
          if (isEditorOpen) renderEditorList();
          return;
        }
        if (data.type === '__SVGVIDEO_SET_SCENE_STATUS') {
          var sceneId = typeof data.sceneId === 'string' ? data.sceneId : '';
          var status = typeof data.status === 'string' ? data.status : '';
          if (sceneId && status) {
            setSceneStatus(sceneId, status);
            if (isEditorOpen) renderEditorList();
          }
          return;
        }
        if (data.type === '__SVGVIDEO_SET_RECORDING') {
          if (data && data.active) {
            document.body.classList.add('sv-recording');
            // 如果指定了初始分镜，无过渡动画地跳转过去，避免录制开头残留旧分镜画面
            if (data.sceneId) {
              var noTransStyle = document.createElement('style');
              noTransStyle.id = 'sv-no-transition';
              noTransStyle.textContent = '.scene, [data-step] { transition: none !important; }';
              document.head.appendChild(noTransStyle);
              window.__SVGVIDEO_SET_STATE(data.sceneId, 0, 1);
              // 强制 reflow 后恢复过渡动画
              void document.body.offsetHeight;
              requestAnimationFrame(function () {
                var s = document.getElementById('sv-no-transition');
                if (s) s.remove();
              });
            }
          } else {
            document.body.classList.remove('sv-recording');
          }
          return;
        }
        if (data.type === '__SVGVIDEO_SET_META' && data.meta && typeof data.meta === 'object') {
          meta = data.meta;
          var freshScenes = Array.isArray(meta.scenes) ? meta.scenes : [];
          freshScenes.forEach(function (scene) {
            var idx = getSceneIndexById(scene.id);
            if (idx < 0) return;
            sceneModels[idx].prompt = typeof scene.prompt === 'string' ? scene.prompt : '';
            sceneModels[idx].scriptText = typeof scene.scriptText === 'string' ? scene.scriptText : '';
            sceneModels[idx].audioObjectKey = typeof scene.audioObjectKey === 'string' ? scene.audioObjectKey : '';
            sceneModels[idx].audioDurationMs = Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0;
            sceneModels[idx].voiceName = typeof scene.voiceName === 'string' ? scene.voiceName : '';
          });
          persistMetaToScript();
          if (isEditorOpen) renderEditorList();
        }
      });
      document.addEventListener('keydown', function (event) {
        if (event.key === 'Escape' && isEditorOpen) closeEditor();
      });
      window.__SVGVIDEO_PLAY = startPlayback;
      window.__SVGVIDEO_STOP = stopPlayback;
      window.__SVGVIDEO_OPEN_EDITOR = openEditor;
      window.__SVGVIDEO_CLOSE_EDITOR = closeEditor;
      applyEditorHeight(editorHeightVh);
      renderStatus();
      updatePlayButton();
      applyHostCaps();
      clearEditorDirty();
      applyI18nTexts();
      applySceneState();
      if (autoplayFromFirstScene && sceneModels.length) {
        state.sceneId = sceneModels[0].id;
        state.step = 0;
        state.direction = 1;
        applySceneState();
        startPlayback();
      }
    })();
  </script>
</body>
</html>28:T2270c,<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>高中数学：数列的奥秘与规律</title>
  <style>
    :root {
      color-scheme: dark;
      --bg: #202020;
      --fg: #e2e8f0;
      --muted: #94a3b8;
      --card: rgba(255, 255, 255, 0.05);
      --border: rgba(255, 255, 255, 0.12);
      --sv-editor-height: 50vh;
    }
    * { box-sizing: border-box; }
    html, body {
      margin: 0; width: 100%; height: 100%; overflow: hidden;
      background: var(--bg);
      color: var(--fg);
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
    }
    #app { width: 100%; height: 100%; display: flex; flex-direction: column; }
    #viewport { position: relative; flex: 1; min-height: 0; overflow: hidden; }
    #stage { position: relative; width: 100%; height: 100%; overflow: hidden; }
    .scene {
      position: absolute; inset: 0; overflow: hidden;
      opacity: 0; pointer-events: none;
      transform: translateX(var(--scene-enter-offset, 56px)) scale(0.96);
      filter: blur(10px);
      transition: opacity .55s cubic-bezier(.22,1,.36,1), transform .55s cubic-bezier(.22,1,.36,1), filter .45s ease;
      will-change: opacity, transform, filter;
      z-index: 1;
    }
    .scene.scene-active {
      opacity: 1; pointer-events: auto; transform: translateX(0) scale(1); filter: blur(0px); z-index: 3;
    }
    .scene.scene-exit {
      opacity: 0; pointer-events: none;
      transform: translateX(var(--scene-exit-offset, -56px)) scale(0.96);
      filter: blur(10px); z-index: 2;
    }
    .scene-placeholder {
      height: 100%; border: 1px dashed var(--border); border-radius: 20px; background: var(--card);
      display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: var(--muted);
    }
    .sv-scene-root { width: 100%; height: 100%; position: relative; overflow: hidden; }
    .scene-placeholder-title { font-size: 28px; color: var(--fg); font-weight: 700; }
    [data-step] { transition: opacity .35s ease, transform .35s ease, filter .35s ease; }
    #sv-controls {
      background: rgba(19, 19, 19, 0.95);
      border-top: 1px solid rgba(255,255,255,0.08);
      padding: 8px 12px 10px;
      display: flex;
      flex-direction: column;
      gap: 8px;
      backdrop-filter: blur(8px);
      flex-shrink: 0;
    }
    .sv-progress-wrap {
      position: relative;
      height: 22px;
      display: flex;
      align-items: center;
      cursor: pointer;
    }
    .sv-progress-track {
      width: 100%;
      height: 4px;
      border-radius: 999px;
      background: rgba(120, 120, 120, 0.55);
      position: relative;
      overflow: hidden;
    }
    .sv-progress-fill {
      position: absolute;
      left: 0;
      top: 0;
      bottom: 0;
      width: 0%;
      border-radius: 999px;
      background: linear-gradient(90deg, #f97316, #fb923c);
      transition: width 220ms ease;
    }
    .sv-progress-thumb {
      position: absolute;
      top: 50%;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      background: #fff;
      transform: translate(-50%, -50%);
      box-shadow: 0 0 0 1px rgba(0,0,0,0.28);
      pointer-events: none;
    }
    .sv-toolbar {
      display: grid;
      grid-template-columns: 1fr auto 1fr;
      align-items: center;
      gap: 8px;
      min-height: 30px;
    }
    .sv-toolbar-left {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      min-width: 0;
    }
    .sv-toolbar-title {
      font-size: 11px;
      color: #a8b0bb;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-expand-btn {
      width: 20px;
      height: 20px;
      border: none;
      border-radius: 6px;
      background: rgba(255,255,255,0.08);
      color: #cbd5e1;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      flex: 0 0 auto;
      transition: background 140ms ease, color 140ms ease, transform 120ms ease;
    }
    .sv-expand-btn:hover {
      background: rgba(255,255,255,0.15);
      color: #f8fafc;
    }
    .sv-expand-btn:active {
      transform: scale(0.94);
    }
    body:not(.sv-host-can-edit-panel) .sv-expand-btn {
      display: none;
    }
    .sv-play-btn {
      width: 28px;
      height: 28px;
      border: none;
      border-radius: 999px;
      color: #fff;
      background: #f97316;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: transform 120ms ease, background 160ms ease;
    }
    .sv-play-btn:hover { background: #fb923c; }
    .sv-play-btn:active { transform: scale(0.94); }
    .sv-play-btn:disabled { opacity: 0.45; cursor: not-allowed; }
    .sv-status {
      text-align: right;
      font-size: 11px;
      color: #8f98a5;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-scene-grid {
      display: flex;
      align-items: stretch;
      gap: 6px;
      flex-wrap: nowrap;
      overflow: hidden;
    }
    .scene-chip {
      position: relative;
      width: 100%;
      border: none;
      border-bottom: 2px solid transparent;
      border-radius: 8px;
      background: rgba(255,255,255,0.06);
      color: #a3a3a3;
      padding: 7px 6px;
      text-align: center;
      font-size: 11px;
      line-height: 1.1;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      cursor: pointer;
      transition: transform 140ms ease, color 160ms ease, background 160ms ease, border-color 160ms ease;
    }
    .scene-chip-label {
      display: block;
      width: 100%;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .scene-chip-wrap {
      position: relative;
      flex: 1 1 0;
      min-width: 0;
    }
    .scene-chip-retry {
      position: absolute;
      top: 50%;
      right: 4px;
      transform: translateY(-50%);
      width: 24px;
      height: 24px;
      border: none;
      border-radius: 999px;
      background: #f97316;
      color: #fff;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
      opacity: 0;
      pointer-events: none;
      transition: opacity 160ms ease;
      cursor: pointer;
    }
    body.sv-host-can-retry .scene-chip-wrap:hover .scene-chip-retry {
      opacity: 1;
      pointer-events: auto;
    }
    .scene-chip-retry:disabled {
      opacity: 1;
      pointer-events: none;
      background: #f97316;
    }
    .scene-chip-retry-icon {
      width: 18px;
      height: 18px;
      display: block;
    }
    .scene-chip-retry-spinner {
      width: 14px;
      height: 14px;
      aspect-ratio: 1 / 1;
      border: 2px solid #ffffff;
      border-top-color: transparent;
      border-radius: 999px;
      box-sizing: border-box;
      animation: sceneChipSpin 1s linear infinite;
      display: block;
      flex: 0 0 auto;
    }
    @keyframes sceneChipSpin {
      from { transform: rotate(0deg); }
      to { transform: rotate(360deg); }
    }
    .scene-chip:hover { transform: scale(1.02); }
    .scene-chip.is-active {
      color: #fb923c;
      border-bottom-color: #fb923c;
      background: linear-gradient(135deg, rgba(249,115,22,0.2), rgba(168,85,247,0.2));
    }
    .scene-chip.is-failed {
      color: #fca5a5;
      border-bottom-color: rgba(239,68,68,0.95);
      background: rgba(239,68,68,0.12);
    }
    .scene-chip.is-generating {
      color: #fcd34d;
      background: rgba(245,158,11,0.11);
    }
    .sv-editor-overlay {
      position: relative;
      width: 100%;
      height: 0;
      z-index: 40;
      pointer-events: none;
      overflow: hidden;
      transition: height 260ms cubic-bezier(.22,1,.36,1);
    }
    .sv-editor-backdrop {
      position: absolute;
      inset: auto 0 0 0;
      height: 100%;
      background: rgba(0, 0, 0, 0.45);
      opacity: 0;
      transition: opacity 220ms ease;
    }
    .sv-editor-sheet {
      position: absolute;
      left: 0;
      right: 0;
      bottom: 0;
      height: 100%;
      background: rgba(16, 16, 16, 0.96);
      border-top: 1px solid rgba(255,255,255,0.12);
      box-shadow: 0 -14px 30px rgba(0,0,0,0.45);
      transform: translateY(102%);
      transition: transform 260ms cubic-bezier(.22,1,.36,1);
      display: flex;
      flex-direction: column;
    }
    .sv-editor-overlay.is-open {
      pointer-events: auto;
      height: var(--sv-editor-height, 50vh);
    }
    .sv-editor-overlay.is-open .sv-editor-backdrop {
      opacity: 1;
    }
    .sv-editor-overlay.is-open .sv-editor-sheet {
      transform: translateY(0);
    }
    .sv-editor-resize-handle {
      width: 100%;
      height: 14px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: ns-resize;
      flex: 0 0 auto;
      touch-action: none;
    }
    .sv-editor-resize-handle::before {
      content: "";
      width: 52px;
      height: 4px;
      border-radius: 999px;
      background: rgba(148, 163, 184, 0.7);
    }
    .sv-editor-header {
      padding: 10px 12px;
      border-bottom: 1px solid rgba(255,255,255,0.1);
      display: grid;
      grid-template-columns: 1fr auto;
      align-items: center;
      gap: 8px;
    }
    .sv-editor-header-title {
      color: #f1f5f9;
      font-size: 13px;
      font-weight: 600;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-editor-actions {
      display: inline-flex;
      align-items: center;
      gap: 6px;
    }
    .sv-editor-btn {
      border: none;
      border-radius: 8px;
      cursor: pointer;
      font-size: 12px;
      line-height: 1;
      padding: 7px 10px;
      color: #e2e8f0;
      background: rgba(255,255,255,0.1);
      transition: background 120ms ease;
    }
    .sv-editor-btn:hover {
      background: rgba(255,255,255,0.18);
    }
    .sv-editor-btn.is-primary {
      color: #fff;
      background: #f97316;
    }
    .sv-editor-btn.is-primary:hover {
      background: #fb923c;
    }
    .sv-editor-list {
      flex: 1;
      min-height: 0;
      overflow: auto;
      padding: 10px 12px 14px;
      display: grid;
      gap: 10px;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      align-items: start;
      align-content: start;
    }
    .sv-editor-item {
      border: 1px solid rgba(255,255,255,0.12);
      border-radius: 10px;
      background: rgba(255,255,255,0.03);
      padding: 10px;
      display: grid;
      grid-template-rows: auto auto auto;
      gap: 10px;
      align-content: start;
      cursor: pointer;
    }
    .sv-editor-item.is-active {
      border-color: rgba(249,115,22,0.65);
      box-shadow: inset 0 0 0 1px rgba(249,115,22,0.28);
    }
    .sv-editor-item-head {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 8px;
      min-height: 30px;
    }
    .sv-editor-item-title {
      border: none;
      border-radius: 8px;
      color: #fb923c;
      background: rgba(255,255,255,0.08);
      font-size: 12px;
      font-weight: 600;
      padding: 6px 8px;
      cursor: pointer;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      text-align: left;
    }
    .sv-editor-item-title:hover {
      background: rgba(255,255,255,0.14);
    }
    .sv-editor-status {
      color: #94a3b8;
      font-size: 11px;
      white-space: nowrap;
    }
    .sv-editor-status-wrap {
      display: inline-flex;
      align-items: center;
      gap: 6px;
    }
    .scene-chip-retry.sv-editor-retry {
      position: static;
      transform: none;
      opacity: 1;
      pointer-events: auto;
      width: 24px;
      height: 24px;
      flex: 0 0 auto;
    }
    .sv-editor-field {
      display: grid;
      gap: 6px;
    }
    .sv-editor-label {
      color: #a3a3a3;
      font-size: 11px;
      font-weight: 700;
    }
    .sv-editor-textarea {
      width: 100%;
      border-radius: 8px;
      border: 1px solid rgba(255,255,255,0.14);
      background: rgba(0,0,0,0.24);
      color: #f1f5f9;
      font-size: 12px;
      line-height: 1.45;
      padding: 8px 9px;
      resize: none;
      min-height: 110px;
      height: 110px;
    }
    .sv-editor-textarea[data-field="scriptText"] {
      min-height: 84px;
    }
    .sv-editor-textarea:focus {
      outline: none;
      border-color: rgba(249,115,22,0.7);
      box-shadow: 0 0 0 2px rgba(249,115,22,0.18);
    }
    body.sv-theme-light .sv-editor-textarea {
      border-color: rgba(15,23,42,0.18);
      background: rgba(248,250,252,0.92);
      color: #0f172a;
    }
    body.sv-theme-light .sv-editor-textarea:focus {
      border-color: rgba(249,115,22,0.72);
      box-shadow: 0 0 0 2px rgba(249,115,22,0.2);
    }
    .sv-editor-script-view {
      width: 100%;
      color: #e2e8f0;
      font-size: 12px;
      line-height: 1.5;
      white-space: pre-wrap;
      word-break: break-word;
      min-height: 84px;
      max-height: 84px;
      overflow: auto;
    }
    .sv-editor-save-tip {
      color: #fbbf24;
      font-size: 11px;
      opacity: 0;
      transition: opacity 140ms ease;
      justify-self: end;
    }
    .sv-editor-save-tip.is-visible {
      opacity: 1;
    }
    body.sv-theme-light .sv-editor-backdrop {
      background: rgba(15, 23, 42, 0.2);
    }
    body.sv-theme-light .sv-editor-sheet {
      background: rgba(255, 255, 255, 0.98);
      border-top-color: rgba(15, 23, 42, 0.12);
      box-shadow: 0 -14px 30px rgba(15, 23, 42, 0.16);
    }
    body.sv-theme-light .sv-editor-header {
      border-bottom-color: rgba(15, 23, 42, 0.1);
    }
    body.sv-theme-light .sv-editor-header-title {
      color: #0f172a;
    }
    body.sv-theme-light .sv-editor-btn {
      color: #334155;
      background: rgba(15, 23, 42, 0.08);
    }
    body.sv-theme-light .sv-editor-btn:hover {
      background: rgba(15, 23, 42, 0.14);
    }
    body.sv-theme-light .sv-editor-btn.is-primary {
      color: #ffffff;
      background: #f97316;
    }
    body.sv-theme-light .sv-editor-btn.is-primary:hover {
      background: #fb923c;
    }
    body.sv-theme-light .sv-editor-item {
      border-color: rgba(15, 23, 42, 0.12);
      background: rgba(248, 250, 252, 0.95);
    }
    body.sv-theme-light .sv-editor-item.is-active {
      border-color: rgba(249,115,22,0.72);
      box-shadow: inset 0 0 0 1px rgba(249,115,22,0.3);
    }
    body.sv-theme-light .sv-editor-item-title {
      color: #ea580c;
      background: rgba(249, 115, 22, 0.12);
    }
    body.sv-theme-light .sv-editor-item-title:hover {
      background: rgba(249, 115, 22, 0.18);
    }
    body.sv-theme-light .sv-editor-status {
      color: #64748b;
    }
    body.sv-theme-light .sv-editor-label {
      color: #475569;
    }
    body.sv-theme-light .sv-editor-script-view {
      color: #334155;
    }
    body.sv-theme-light .sv-editor-save-tip {
      color: #c2410c;
    }
    body.sv-editor-open #viewport {
      flex: 1 1 calc(100vh - var(--sv-editor-height, 50vh));
      min-height: 0;
    }
    body.sv-editor-open #sv-controls {
      display: none;
    }
    body.sv-recording .sv-toolbar,
    body.sv-recording .sv-scene-grid {
      display: none;
    }
    body.sv-recording #sv-controls {
      display: none;
    }
    body.sv-theme-light .sv-editor-list,
    body.sv-theme-light .sv-editor-script-view,
    body.sv-theme-light .sv-editor-textarea {
      scrollbar-color: rgba(148, 163, 184, 0.85) rgba(226, 232, 240, 0.85);
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar {
      width: 10px;
      height: 10px;
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-track,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-track,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-track {
      background: rgba(226, 232, 240, 0.85);
      border-radius: 999px;
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-thumb,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-thumb,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-thumb {
      background: rgba(148, 163, 184, 0.85);
      border-radius: 999px;
      border: 2px solid rgba(226, 232, 240, 0.85);
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-thumb:hover,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-thumb:hover,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-thumb:hover {
      background: rgba(100, 116, 139, 0.95);
    }
/* scene-01 */
.sv-scene-root-scene-01 .s-scene-01-container{
  background-color: #F7F4EE;
  height: 100vh;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-family: "Source Serif 4", "Noto Serif SC", serif;
  overflow: hidden;
  position: relative;
}.sv-scene-root-scene-01 .s-scene-01-content{
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 800px;
  z-index: 10;
}.sv-scene-root-scene-01 .s-scene-01-eyebrow{
  font-family: "JetBrains Mono", monospace;
  color: #D97757;
  font-size: 0.875rem;
  letter-spacing: 0.2em;
  margin-bottom: 1.5rem;
  opacity: 0;
  transform: translateY(10px);
  transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}.sv-scene-root-scene-01 .s-scene-01-title{
  font-size: 6rem;
  font-weight: 500;
  color: #1D1D1F;
  margin: 0;
  letter-spacing: -0.02em;
  line-height: 1.1;
  opacity: 0;
  transform: scale(0.95) translateY(20px);
  transition: all 1s cubic-bezier(0.16, 1, 0.3, 1);
}.sv-scene-root-scene-01 .s-scene-01-divider{
  width: 40px;
  height: 2px;
  background-color: #D97757;
  margin: 2rem 0;
  opacity: 0;
  transition: width 1s ease 0.3s, opacity 0.8s ease 0.3s;
}.sv-scene-root-scene-01 .s-scene-01-wave-container{
  display: flex;
  gap: 12px;
  height: 60px;
  align-items: center;
  margin-top: 1rem;
  opacity: 0;
  transition: opacity 1s ease;
}.sv-scene-root-scene-01 .s-scene-01-dot{
  width: 6px;
  height: 6px;
  background-color: #D97757;
  border-radius: 50%;
  animation: s-dot-bounce 2s infinite ease-in-out;
  animation-delay: calc(var(--i) * 0.15s);
}.sv-scene-root-scene-01 .s-scene-01-subtitle{
  font-family: "Inter", sans-serif;
  color: #8B867E;
  font-size: 1.125rem;
  margin-top: 2rem;
  letter-spacing: 0.1em;
  opacity: 0;
  transition: all 1s ease 0.5s;
}@keyframes s-dot-bounce{
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-30px); }
}.sv-scene-root-scene-01 [data-step="0"].active .s-scene-01-title, .sv-scene-root-scene-01 [data-step="0"].active .s-scene-01-eyebrow{
  opacity: 1;
  transform: scale(1) translateY(0);
}.sv-scene-root-scene-01 [data-step="0"].active .s-scene-01-divider{
  opacity: 1;
  width: 80px;
}.sv-scene-root-scene-01 [data-step="1"].active .s-scene-01-wave-container, .sv-scene-root-scene-01 [data-step="1"].active .s-scene-01-subtitle{
  opacity: 1;
}

/* scene-02 */
.sv-scene-root-scene-02 .s-scene-02-container{
  background-color: #F7F4EE;
  height: 100vh;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  perspective: 1000px;
}.sv-scene-root-scene-02 .s-scene-02-card{
  position: relative;
  background: rgba(255, 255, 255, 0.6);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid #E4DED2;
  border-radius: 24px;
  padding: 4rem 6rem;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.04);
  transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1);
  overflow: hidden;
}.sv-scene-root-scene-02 .s-scene-02-inner{
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3rem;
  z-index: 2;
  position: relative;
}.sv-scene-root-scene-02 .s-scene-02-sequence-wrapper{
  display: flex;
  align-items: flex-end;
  gap: 2.5rem;
}.sv-scene-root-scene-02 .s-scene-02-item{
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  opacity: 0;
  transform: translateY(20px);
  transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}.sv-scene-root-scene-02 .s-scene-02-item.active{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-02 .s-scene-02-index{
  font-family: 'JetBrains Mono', monospace;
  font-size: 1.25rem;
  color: #D97757;
  opacity: 0;
  transform: translateY(-10px);
  transition: all 0.5s ease;
}.sv-scene-root-scene-02 .s-scene-02-index.active{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-02 .s-scene-02-number{
  font-family: 'Source Serif 4', serif;
  font-size: 5.5rem;
  font-weight: 500;
  color: #1D1D1F;
  line-height: 1;
}.sv-scene-root-scene-02 .s-scene-02-ellipsis{
  font-family: 'Source Serif 4', serif;
  font-size: 4rem;
  color: #8B867E;
  padding-bottom: 0.5rem;
  opacity: 0;
  transition: opacity 0.8s ease 0.4s;
}.sv-scene-root-scene-02 .s-scene-02-ellipsis.active{
  opacity: 1;
}.sv-scene-root-scene-02 .s-scene-02-label-container{
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  opacity: 0;
  transform: translateY(10px);
  transition: all 0.8s ease 0.2s;
}.sv-scene-root-scene-02 .s-scene-02-label-container.active{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-02 .s-scene-02-divider{
  width: 0%;
  height: 1px;
  background: #E4DED2;
  margin-bottom: 1.5rem;
  transition: width 1s cubic-bezier(0.16, 1, 0.3, 1);
}.sv-scene-root-scene-02 .active .s-scene-02-divider{
  width: 100%;
}.sv-scene-root-scene-02 .s-scene-02-label{
  font-family: 'Noto Serif SC', serif;
  font-size: 1.75rem;
  letter-spacing: 0.3em;
  color: #D97757;
  font-weight: 500;
}.sv-scene-root-scene-02 .s-scene-02-glow-border{
  position: absolute;
  inset: 0;
  border-radius: 24px;
  border: 2px solid transparent;
  pointer-events: none;
  transition: border-color 0.8s ease;
}.sv-scene-root-scene-02 .s-scene-02-glow-border.active{
  border-color: #D97757;
  box-shadow: inset 0 0 20px rgba(217, 119, 87, 0.1), 0 0 30px rgba(217, 119, 87, 0.05);
}

/* scene-03 */
.sv-scene-root-scene-03 .s-scene-03-container{
  background-color: #F7F4EE;
  height: 100vh;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
  font-family: 'Source Serif 4', serif;
}.sv-scene-root-scene-03 .s-scene-03-stage{
  position: relative;
  width: 80%;
  max-width: 1000px;
  height: 400px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}.sv-scene-root-scene-03 /* 丝线 */
.s-scene-03-thread{
  position: absolute;
  top: 50%;
  left: 0;
  width: 0%;
  height: 1px;
  background: linear-gradient(90deg, transparent, #D97757, transparent);
  box-shadow: 0 0 10px rgba(217, 119, 87, 0.3);
  transition: width 1.2s cubic-bezier(0.65, 0, 0.35, 1);
  z-index: 1;
}.sv-scene-root-scene-03 .s-scene-03-thread.active{
  width: 100%;
}.sv-scene-root-scene-03 /* 珍珠容器 */
.s-scene-03-pearls-wrapper{
  display: flex;
  justify-content: space-around;
  width: 100%;
  z-index: 2;
}.sv-scene-root-scene-03 .s-scene-03-pearl-item{
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
  opacity: 0;
  transform: translateY(-20px);
  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
}.sv-scene-root-scene-03 .s-scene-03-pearl-item.active{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-03 /* 珍珠视觉 */
.s-scene-03-pearl{
  width: 60px;
  height: 60px;
  background: radial-gradient(circle at 30% 30%, #FFFFFF, #F5F4F0 60%, #E4DED2 100%);
  border-radius: 50%;
  box-shadow: 
    inset -5px -5px 15px rgba(0,0,0,0.05), 
    0 10px 30px rgba(217, 119, 87, 0.1);
  border: 0.5px solid rgba(255,255,255,0.8);
  position: relative;
  backdrop-filter: blur(2px);
}.sv-scene-root-scene-03 .s-scene-03-pearl-glow{
  position: absolute;
  top: 50%;
  left: 50%;
  width: 30px;
  height: 30px;
  background: #D97757;
  filter: blur(15px);
  opacity: 0.2;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  pointer-events: none;
}.sv-scene-root-scene-03 /* 标签 */
.s-scene-03-label{
  margin-top: 2rem;
  font-family: 'JetBrains Mono', monospace;
  color: #D97757;
  opacity: 0;
  transform: scale(0.8);
  transition: all 0.5s ease;
}.sv-scene-root-scene-03 .s-scene-03-label.active{
  opacity: 1;
  transform: scale(1);
  animation: s-blink 1.5s infinite ease-in-out;
}.sv-scene-root-scene-03 .s-scene-03-label-symbol{
  font-size: 1.5rem;
  font-style: italic;
  margin-right: 2px;
}.sv-scene-root-scene-03 .s-scene-03-label-idx{
  font-size: 1rem;
  vertical-align: sub;
}.sv-scene-root-scene-03 .s-scene-03-hint{
  position: absolute;
  bottom: 0;
  font-size: 1rem;
  letter-spacing: 0.2em;
  color: #8B867E;
  opacity: 0;
  transition: opacity 1s ease 0.5s;
}.sv-scene-root-scene-03 .s-scene-03-hint.active{
  opacity: 1;
}@keyframes s-blink{
  0%, 100% { opacity: 1; }
  50% { opacity: 0.6; }
}

/* scene-04 */
.sv-scene-root-scene-04 .s-scene-04-container{
  background-color: #F7F4EE;
  height: 100vh;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-family: 'Source Serif 4', serif;
  color: #1A1918;
}.sv-scene-root-scene-04 .s-scene-04-stage{
  width: 80%;
  max-width: 900px;
  text-align: center;
}.sv-scene-root-scene-04 .s-scene-04-layout{
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 3rem;
  margin-bottom: 4rem;
}.sv-scene-root-scene-04 .s-scene-04-panel{
  flex: 1;
  background: #FAF9F5;
  padding: 3rem 2rem;
  border: 1px solid #E4DED2;
  border-radius: 12px;
  box-shadow: 0 10px 40px rgba(0,0,0,0.02);
  position: relative;
  transition: all 0.8s cubic-bezier(0.2, 0.8, 0.2, 1);
  opacity: 0;
  transform: translateY(20px);
}.sv-scene-root-scene-04 .s-scene-04-panel.active{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-04 .s-scene-04-label-top{
  font-size: 0.9rem;
  letter-spacing: 0.15em;
  color: #8B867E;
  text-transform: uppercase;
  margin-bottom: 1.5rem;
}.sv-scene-root-scene-04 .s-scene-04-variable-box{
  font-size: 3.5rem;
  font-weight: 300;
}.sv-scene-root-scene-04 .s-scene-04-math-n, .sv-scene-root-scene-04 .s-scene-04-math-an{
  font-style: italic;
  color: #D97757;
}.sv-scene-root-scene-04 .s-scene-04-val-display{
  margin-left: 0.5rem;
  font-family: 'JetBrains Mono', monospace;
  font-size: 2.5rem;
  color: #1A1918;
}.sv-scene-root-scene-04 .s-scene-04-connector{
  width: 120px;
  opacity: 0;
  transition: opacity 1s ease;
}.sv-scene-root-scene-04 .s-scene-04-connector.active{
  opacity: 1;
}.sv-scene-root-scene-04 .s-scene-04-arrow{
  width: 100%;
  overflow: visible;
}.sv-scene-root-scene-04 .s-scene-04-keyword-badge{
  position: absolute;
  bottom: -15px;
  left: 50%;
  transform: translateX(-50%) scale(0.9);
  background: #D97757;
  color: white;
  padding: 6px 16px;
  border-radius: 20px;
  font-size: 0.85rem;
  opacity: 0;
  transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
  white-space: nowrap;
}.sv-scene-root-scene-04 .s-scene-04-keyword-badge.active{
  opacity: 1;
  transform: translateX(-50%) scale(1);
  animation: s-04-breathe 2.5s infinite ease-in-out;
}.sv-scene-root-scene-04 .s-scene-04-info-text{
  font-size: 1.1rem;
  color: #8B867E;
  opacity: 0;
  transition: opacity 1s ease;
}.sv-scene-root-scene-04 .s-scene-04-info-text.active{
  opacity: 1;
}@keyframes s-04-breathe{
  0%, 100% { box-shadow: 0 0 0px rgba(217, 119, 87, 0); transform: translateX(-50%) scale(1); }
  50% { box-shadow: 0 0 20px rgba(217, 119, 87, 0.4); transform: translateX(-50%) scale(1.05); }
}.sv-scene-root-scene-04 #s-scene-04-an-idx{
  font-size: 1.5rem;
  vertical-align: sub;
  font-family: 'JetBrains Mono', monospace;
}

/* scene-05 */
.sv-scene-root-scene-05 .s-scene-05-container{ background-color: #F7F4EE; height: 100vh; width: 100%; display: flex; justify-content: center; align-items: center; font-family: 'Source Serif 4', serif; overflow: hidden; color: #1A1918; }.sv-scene-root-scene-05 .s-scene-05-main{ width: 90%; max-width: 1100px; display: grid; grid-template-columns: 1.2fr 1fr; gap: 4rem; align-items: center; }.sv-scene-root-scene-05 .s-scene-05-visual-area{ position: relative; height: 400px; perspective: 1200px; }.sv-scene-root-scene-05 .s-scene-05-stairs-canvas{ position: relative; width: 100%; height: 100%; transform-style: preserve-3d; transform: rotateX(20deg) rotateY(-10deg); }.sv-scene-root-scene-05 .s-scene-05-stair-wrapper{ transform-style: preserve-3d; }.sv-scene-root-scene-05 .s-scene-05-stair{ position: absolute; bottom: 0; left: calc(var(--i) * 60px); width: 80px; height: calc(var(--i) * 40px); background: #FAF9F5; border: 1.5px solid #E4DED2; transform: translateZ(calc(var(--i) * 20px)); opacity: 0; transform: translateY(100px); transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1); transition-delay: calc(var(--i) * 0.15s); }.sv-scene-root-scene-05 [data-step='0'].active .s-scene-05-stair{ opacity: 1; transform: translateY(0); }.sv-scene-root-scene-05 .s-scene-05-stair::after{ content: ''; position: absolute; top: -1.5px; left: -1.5px; width: 100%; height: 40px; background: #FFF; border: 1.5px solid #E4DED2; transform: rotateX(90deg) translateY(-20px) translateZ(20px); }.sv-scene-root-scene-05 .s-scene-05-bubbles-layer{ position: absolute; width: 100%; height: 100%; top: 0; left: 0; pointer-events: none; }.sv-scene-root-scene-05 .s-scene-05-bubble{ position: absolute; background: rgba(217, 119, 87, 0.1); border: 1px solid rgba(217, 119, 87, 0.3); color: #D97757; font-family: 'JetBrains Mono', monospace; font-size: 0.9rem; width: 34px; height: 34px; border-radius: 50%; display: flex; align-items: center; justify-content: center; left: calc(var(--i) * 60px + 70px); bottom: calc(var(--i) * 40px + 10px); opacity: 0; transform: scale(0.5); transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1); transition-delay: calc(var(--i) * 0.2s); }.sv-scene-root-scene-05 [data-step='1'].active .s-scene-05-bubble{ opacity: 1; transform: scale(1); animation: s-05-float 3s infinite ease-in-out calc(var(--i) * 0.5s); }@keyframes s-05-float{ 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }.sv-scene-root-scene-05 .s-scene-05-content-area{ display: flex; flex-direction: column; gap: 1.5rem; }.sv-scene-root-scene-05 .s-scene-05-label{ font-size: 0.85rem; letter-spacing: 0.2em; text-transform: uppercase; color: #8B867E; opacity: 0; transform: translateX(20px); transition: all 0.8s ease; }.sv-scene-root-scene-05 .s-scene-05-description{ font-size: 1.8rem; line-height: 1.4; font-weight: 300; opacity: 0; transform: translateX(20px); transition: all 0.8s ease 0.2s; }.sv-scene-root-scene-05 .s-scene-05-accent-text{ color: #D97757; font-style: italic; font-weight: 600; }.sv-scene-root-scene-05 .s-scene-05-formula-box{ margin-top: 2rem; padding: 2.5rem; background: #FAF9F5; border: 1px solid #E4DED2; border-radius: 4px; position: relative; opacity: 0; transform: translateY(30px); transition: all 1s cubic-bezier(0.2, 0.8, 0.2, 1); }.sv-scene-root-scene-05 .s-scene-05-formula-box.active{ opacity: 1; transform: translateY(0); }.sv-scene-root-scene-05 .s-scene-05-formula-label{ font-size: 0.75rem; color: #8B867E; margin-bottom: 1rem; letter-spacing: 0.1em; }.sv-scene-root-scene-05 .s-scene-05-formula-text{ font-size: 2.8rem; font-style: italic; white-space: nowrap; overflow: hidden; border-right: 2px solid transparent; width: 0; }.sv-scene-root-scene-05 .s-scene-05-formula-box.active .s-scene-05-formula-text{ width: 100%; transition: width 1.5s steps(20, end); animation: s-05-cursor 0.8s step-end infinite; }.sv-scene-root-scene-05 .s-scene-05-shimmer-bar{ position: absolute; bottom: 0; left: 0; height: 2px; width: 0; background: linear-gradient(90deg, transparent, #D97757, transparent); }.sv-scene-root-scene-05 .s-scene-05-formula-box.active .s-scene-05-shimmer-bar{ animation: s-05-shimmer 3s infinite ease-in-out 1.5s; }.sv-scene-root-scene-05 .active .s-scene-05-label, .sv-scene-root-scene-05 .active .s-scene-05-description{ opacity: 1; transform: translateX(0); }@keyframes s-05-cursor{ 50% { border-color: #D97757; } }@keyframes s-05-shimmer{ 0% { left: -100%; width: 50%; } 100% { left: 150%; width: 50%; } }.sv-scene-root-scene-05 .s-05-math-sub{ font-size: 1.2rem; vertical-align: sub; font-family: 'JetBrains Mono', monospace; }

/* scene-06 */
.sv-scene-root-scene-06 .s-scene-06-container{
  background-color: #F7F4EE;
  height: 100vh;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-family: 'Source Serif 4', serif;
  color: #1A1918;
  overflow: hidden;
}.sv-scene-root-scene-06 .s-scene-06-stage{
  width: 100%;
  max-width: 1000px;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
}.sv-scene-root-scene-06 .s-scene-06-canvas{
  width: 800px;
  height: 400px;
  position: relative;
  margin-bottom: 2rem;
}.sv-scene-root-scene-06 .s-scene-06-svg-layer{
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
}.sv-scene-root-scene-06 .s-scene-06-path{
  fill: none;
  stroke: #E4DED2;
  stroke-width: 1.5;
  stroke-dasharray: 200;
  stroke-dashoffset: 200;
  transition: stroke-dashoffset 1.2s cubic-bezier(0.4, 0, 0.2, 1);
  opacity: 0;
}.sv-scene-root-scene-06 .s-scene-06-path.active{
  stroke-dashoffset: 0;
  opacity: 1;
}.sv-scene-root-scene-06 .s-scene-06-label-q{
  font-family: 'JetBrains Mono', monospace;
  font-size: 14px;
  fill: #8B867E;
  font-weight: 500;
  opacity: 0;
  transition: opacity 0.8s ease 0.4s;
}.sv-scene-root-scene-06 [data-step='1'].active .s-scene-06-label-q{
  opacity: 1;
}.sv-scene-root-scene-06 .s-scene-06-cells{
  position: absolute;
  width: 100%;
  height: 100%;
  z-index: 2;
}.sv-scene-root-scene-06 .s-scene-06-cell{
  position: absolute;
  width: 32px;
  height: 32px;
  background: #FAF9F5;
  border: 1px solid #E4DED2;
  border-radius: 50%;
  box-shadow: 0 4px 12px rgba(0,0,0,0.03);
  transform: translate(-50%, -50%) scale(0);
  opacity: 0;
  transition: transform 0.8s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.6s ease;
}.sv-scene-root-scene-06 .s-scene-06-cell.visible{
  transform: translate(-50%, -50%) scale(1);
  opacity: 1;
}.sv-scene-root-scene-06 /* Coordinates */
.s-scene-06-l1{ left: 400px; top: 60px; }.sv-scene-root-scene-06 .s-scene-06-l2:nth-of-type(2){ left: 250px; top: 180px; }.sv-scene-root-scene-06 .s-scene-06-l2:nth-of-type(3){ left: 550px; top: 180px; }.sv-scene-root-scene-06 .s-scene-06-l3:nth-of-type(4){ left: 150px; top: 300px; }.sv-scene-root-scene-06 .s-scene-06-l3:nth-of-type(5){ left: 350px; top: 300px; }.sv-scene-root-scene-06 .s-scene-06-l3:nth-of-type(6){ left: 450px; top: 300px; }.sv-scene-root-scene-06 .s-scene-06-l3:nth-of-type(7){ left: 650px; top: 300px; }.sv-scene-root-scene-06 .s-scene-06-formula-container{
  text-align: center;
  opacity: 0;
  transform: translateY(20px);
  transition: all 1s cubic-bezier(0.2, 0.8, 0.2, 1);
  margin-top: 2rem;
}.sv-scene-root-scene-06 .s-scene-06-formula-container.active{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-06 .s-scene-06-formula{
  font-size: 3rem;
  margin-bottom: 0.5rem;
  font-weight: 300;
}.sv-scene-root-scene-06 .s-scene-06-math{
  font-style: italic;
}.sv-scene-root-scene-06 .s-scene-06-highlight{
  color: #D97757;
  font-weight: 500;
  font-family: 'JetBrains Mono', monospace;
}.sv-scene-root-scene-06 .s-scene-06-caption{
  font-size: 0.9rem;
  letter-spacing: 0.2em;
  color: #8B867E;
  text-transform: uppercase;
}.sv-scene-root-scene-06 .s-scene-06-sub, .sv-scene-root-scene-06 .s-scene-06-sup{
  font-family: 'JetBrains Mono', monospace;
  font-style: normal;
}

/* scene-07 */
.sv-scene-root-scene-07 .s-scene-07-container{ background-color: #F7F4EE; height: 100vh; width: 100%; display: flex; justify-content: center; align-items: center; position: relative; overflow: hidden; font-family: 'Source Serif 4', serif; }.sv-scene-root-scene-07 .s-scene-07-bg-layer{ position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: space-around; padding: 5%; opacity: 0; transition: opacity 2s ease; }.sv-scene-root-scene-07 .s-scene-07-container [data-step='1'].s-scene-07-bg-layer{ opacity: 0.15; }.sv-scene-root-scene-07 .s-scene-07-blur-text{ font-size: 8rem; font-weight: 300; color: #8B867E; filter: blur(8px); transform: translateX(-100px); transition: all 3s cubic-bezier(0.2, 0.8, 0.2, 1); }.sv-scene-root-scene-07 .s-scene-07-container [data-step='1'].s-scene-07-blur-text{ transform: translateX(50px); filter: blur(4px); }.sv-scene-root-scene-07 .s-scene-07-door-portal{ position: absolute; width: 400px; height: 600px; border: 1px solid #E4DED2; border-radius: 200px 200px 0 0; background: linear-gradient(to bottom, #FAF9F5, #F7F4EE); opacity: 0; transform: scale(0.9) translateZ(-100px); transition: all 1.5s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 0 0 80px rgba(228, 222, 210, 0.3); z-index: 1; }.sv-scene-root-scene-07 .s-scene-07-container [data-step='1'].s-scene-07-door-portal{ opacity: 1; transform: scale(1.1) translateZ(0); }.sv-scene-root-scene-07 .s-scene-07-formula-merge{ position: relative; z-index: 3; display: flex; gap: 100px; transition: all 1.2s cubic-bezier(0.4, 0, 0.2, 1); }.sv-scene-root-scene-07 .s-scene-07-formula-merge.merged{ opacity: 0; transform: scale(0.5); pointer-events: none; }.sv-scene-root-scene-07 .s-scene-07-formula-item{ font-size: 2.5rem; color: #1A1918; white-space: nowrap; }.sv-scene-root-scene-07 .frac{ display: inline-flex; flex-direction: column; vertical-align: middle; text-align: center; font-size: 0.8em; }.sv-scene-root-scene-07 .frac .bar{ height: 1px; background: #1A1918; margin: 2px 0; }.sv-scene-root-scene-07 .s-scene-07-key-wrapper{ position: absolute; z-index: 5; opacity: 0; transform: scale(0) rotate(-45deg); transition: all 1s cubic-bezier(0.34, 1.56, 0.64, 1); }.sv-scene-root-scene-07 .s-scene-07-key-wrapper.active{ opacity: 1; transform: scale(1) rotate(0deg); }.sv-scene-root-scene-07 .s-scene-07-key-wrapper.pointing{ transform: scale(1) rotate(90deg) translateY(-100px); }.sv-scene-root-scene-07 .s-scene-07-key-svg{ width: 120px; height: 240px; filter: drop-shadow(0 10px 20px rgba(217, 119, 87, 0.2)); }.sv-scene-root-scene-07 .s-scene-07-key-path{ fill: none; stroke: #D97757; stroke-width: 4; stroke-linecap: round; stroke-linejoin: round; }.sv-scene-root-scene-07 .s-scene-07-overlay-text{ position: absolute; bottom: 10%; font-size: 1.5rem; letter-spacing: 0.5em; color: #8B867E; opacity: 0; transform: translateY(20px); transition: all 1s ease 0.5s; z-index: 10; }.sv-scene-root-scene-07 .s-scene-07-container [data-step='1'].s-scene-07-overlay-text{ opacity: 1; transform: translateY(0); }

/* scene-08 */
.sv-scene-root-scene-08 .s-scene-08-container{
  background-color: #F7F4EE;
  height: 100vh;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  overflow: hidden;
  font-family: 'Source Serif 4', serif;
  perspective: 1000px;
}.sv-scene-root-scene-08 .s-scene-08-starfield{
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at center, #2C2A26 0%, #1A1918 100%);
  opacity: 0;
  transition: opacity 2.5s ease-in-out;
  z-index: 1;
}.sv-scene-root-scene-08 .s-scene-08-container[data-step-active='1'] .s-scene-08-starfield{
  opacity: 1;
}.sv-scene-root-scene-08 .s-scene-08-stars{
  width: 100%;
  height: 100%;
  background-image: radial-gradient(1px 1px at 10% 20%, #D97757 100%, transparent 0), radial-gradient(1.5px 1.5px at 50% 50%, #E4DED2 100%, transparent 0), radial-gradient(1px 1px at 80% 30%, #D97757 100%, transparent 0);
  background-size: 400px 400px;
  animation: s-08-bg-pan 40s linear infinite alternate;
  filter: blur(0.5px);
}@keyframes s-08-bg-pan{
  from { transform: scale(1) translate(0, 0); }
  to { transform: scale(1.2) translate(-5%, -5%); }
}.sv-scene-root-scene-08 .s-scene-08-formula-dust-container{
  position: absolute;
  z-index: 2;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  pointer-events: none;
}.sv-scene-root-scene-08 .s-scene-08-symbol{
  position: absolute;
  font-size: 2.5rem;
  color: #D97757;
  opacity: 0;
  font-family: 'JetBrains Mono', monospace;
  transition: all 1.5s cubic-bezier(0.34, 1.56, 0.64, 1);
  transform: translate(var(--tx), var(--ty)) scale(1.5);
  filter: blur(4px);
}.sv-scene-root-scene-08 .s-scene-08-container[data-step-active='0'] .s-scene-08-symbol{
  opacity: 0.6;
  transform: translate(0, 0) scale(0);
  filter: blur(0px);
  transition-delay: var(--delay);
}.sv-scene-root-scene-08 .s-scene-08-content{
  position: relative;
  z-index: 10;
  text-align: center;
  color: #F7F4EE;
  opacity: 0;
  transform: translateY(30px);
  transition: all 2s cubic-bezier(0.2, 0.8, 0.2, 1);
}.sv-scene-root-scene-08 .s-scene-08-container[data-step-active='1'] .s-scene-08-content{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-08 .s-scene-08-eyebrow{
  font-family: sans-serif;
  letter-spacing: 0.4em;
  font-size: 0.75rem;
  color: #D97757;
  margin-bottom: 2rem;
}.sv-scene-root-scene-08 .s-scene-08-hero-title{
  font-size: 6rem;
  font-weight: 200;
  margin: 0;
  letter-spacing: 0.1em;
  font-family: 'Source Serif 4', serif;
}.sv-scene-root-scene-08 .s-scene-08-divider{
  width: 60px;
  height: 1px;
  background-color: #D97757;
  margin: 2.5rem auto;
  transform: scaleX(0);
  transition: transform 1.5s ease 1s;
}.sv-scene-root-scene-08 .s-scene-08-container[data-step-active='1'] .s-scene-08-divider{
  transform: scaleX(1);
}.sv-scene-root-scene-08 .s-scene-08-subtitle{
  font-family: sans-serif;
  letter-spacing: 0.6em;
  font-size: 0.9rem;
  opacity: 0.6;
  font-weight: 300;
}
  </style>
</head>
<body>
  <div id="app">
    <div id="viewport">
      <div id="stage">

<section class="scene" data-scene-id="scene-01">
  <div class="sv-scene-root sv-scene-root-scene-01" data-scene-root-id="scene-01">
<div class='s-scene-01-container'>
  <div class='s-scene-01-content'>
    <div class='s-scene-01-eyebrow mono' data-step='0'>CHAPTER 01</div>
    <h1 class='s-scene-01-title' data-step='0'>数列</h1>
    <div class='s-scene-01-divider' data-step='0'></div>
    <div class='s-scene-01-wave-container' data-step='1'>
      <div class='s-scene-01-dot' style='--i:0'></div>
      <div class='s-scene-01-dot' style='--i:1'></div>
      <div class='s-scene-01-dot' style='--i:2'></div>
      <div class='s-scene-01-dot' style='--i:3'></div>
      <div class='s-scene-01-dot' style='--i:4'></div>
      <div class='s-scene-01-dot' style='--i:5'></div>
      <div class='s-scene-01-dot' style='--i:6'></div>
      <div class='s-scene-01-dot' style='--i:7'></div>
      <div class='s-scene-01-dot' style='--i:8'></div>
      <div class='s-scene-01-dot' style='--i:9'></div>
      <div class='s-scene-01-dot' style='--i:10'></div>
      <div class='s-scene-01-dot' style='--i:11'></div>
    </div>
    <p class='s-scene-01-subtitle' data-step='1'>高中数学核心板块</p>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-02">
  <div class="sv-scene-root sv-scene-root-scene-02" data-scene-root-id="scene-02">
<div class='s-scene-02-container'>
  <div class='s-scene-02-card'>
    <div class='s-scene-02-inner'>
      <div class='s-scene-02-sequence-wrapper'>
        <div class='s-scene-02-item' data-step='0'>
          <span class='s-scene-02-index' data-step='1'>①</span>
          <span class='s-scene-02-number'>2</span>
        </div>
        <div class='s-scene-02-item' data-step='0'>
          <span class='s-scene-02-index' data-step='1'>②</span>
          <span class='s-scene-02-number'>4</span>
        </div>
        <div class='s-scene-02-item' data-step='0'>
          <span class='s-scene-02-index' data-step='1'>③</span>
          <span class='s-scene-02-number'>6</span>
        </div>
        <div class='s-scene-02-item' data-step='0'>
          <span class='s-scene-02-index' data-step='1'>④</span>
          <span class='s-scene-02-number'>8</span>
        </div>
        <div class='s-scene-02-ellipsis' data-step='0'>...</div>
      </div>
      
      <div class='s-scene-02-label-container' data-step='2'>
        <div class='s-scene-02-divider'></div>
        <div class='s-scene-02-label'>有序的一列数</div>
      </div>
    </div>
    <div class='s-scene-02-glow-border' data-step='2'></div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-03">
  <div class="sv-scene-root sv-scene-root-scene-03" data-scene-root-id="scene-03">
<div class='s-scene-03-container'>
  <div class='s-scene-03-stage'>
    <!-- Step 0: 发光的丝线 -->
    <div class='s-scene-03-thread' data-step='0'></div>
    
    <!-- Step 1: 5颗珍珠 -->
    <div class='s-scene-03-pearls-wrapper'>
      <div class='s-scene-03-pearl-item' data-step='1'>
        <div class='s-scene-03-pearl-glow'></div>
        <div class='s-scene-03-pearl'></div>
        <!-- Step 2: 标签 -->
        <div class='s-scene-03-label' data-step='2'><span class='s-scene-03-label-symbol'>a</span><span class='s-scene-03-label-idx'>1</span></div>
      </div>
      <div class='s-scene-03-pearl-item' data-step='1'>
        <div class='s-scene-03-pearl-glow'></div>
        <div class='s-scene-03-pearl'></div>
        <div class='s-scene-03-label' data-step='2'><span class='s-scene-03-label-symbol'>a</span><span class='s-scene-03-label-idx'>2</span></div>
      </div>
      <div class='s-scene-03-pearl-item' data-step='1'>
        <div class='s-scene-03-pearl-glow'></div>
        <div class='s-scene-03-pearl'></div>
        <div class='s-scene-03-label' data-step='2'><span class='s-scene-03-label-symbol'>a</span><span class='s-scene-03-label-idx'>3</span></div>
      </div>
      <div class='s-scene-03-pearl-item' data-step='1'>
        <div class='s-scene-03-pearl-glow'></div>
        <div class='s-scene-03-pearl'></div>
        <div class='s-scene-03-label' data-step='2'><span class='s-scene-03-label-symbol'>a</span><span class='s-scene-03-label-idx'>4</span></div>
      </div>
      <div class='s-scene-03-pearl-item' data-step='1'>
        <div class='s-scene-03-pearl-glow'></div>
        <div class='s-scene-03-pearl'></div>
        <div class='s-scene-03-label' data-step='2'><span class='s-scene-03-label-symbol'>a</span><span class='s-scene-03-label-idx'>5</span></div>
      </div>
    </div>

    <div class='s-scene-03-hint' data-step='0'>离散且有序的珍珠</div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-04">
  <div class="sv-scene-root sv-scene-root-scene-04" data-scene-root-id="scene-04">
<div class='s-scene-04-container'>
  <div class='s-scene-04-stage'>
    <div class='s-scene-04-layout'>
      <!-- Left Side: n -->
      <div class='s-scene-04-panel s-scene-04-left' data-step='0'>
        <div class='s-scene-04-label-top'>项数</div>
        <div class='s-scene-04-variable-box'>
          <span class='s-scene-04-math-n'>n</span>
          <span class='s-scene-04-val-display' id='s-scene-04-n-val'>= 1</span>
        </div>
        <div class='s-scene-04-keyword-badge' data-step='2'>位置</div>
      </div>

      <!-- Middle: Connector -->
      <div class='s-scene-04-connector' data-step='1'>
        <svg class='s-scene-04-arrow' viewBox='0 0 100 20'>
          <path d='M0 10 L95 10 M85 5 L95 10 L85 15' fill='none' stroke='#D97757' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' />
        </svg>
      </div>

      <!-- Right Side: an -->
      <div class='s-scene-04-panel s-scene-04-right' data-step='0'>
        <div class='s-scene-04-label-top'>项</div>
        <div class='s-scene-04-variable-box'>
          <span class='s-scene-04-math-an'>a<sub id='s-scene-04-an-idx'>1</sub></span>
        </div>
        <div class='s-scene-04-keyword-badge' data-step='2'>对应值</div>
      </div>
    </div>

    <div class='s-scene-04-info-text' data-step='0'>一一对应的数学映射</div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-05">
  <div class="sv-scene-root sv-scene-root-scene-05" data-scene-root-id="scene-05">
<div class='s-scene-05-container'><div class='s-scene-05-main'><div class='s-scene-05-visual-area'><div class='s-scene-05-stairs-canvas' id='s-05-stairs-container'><!-- Step 0: 3D Stairs --><div class='s-scene-05-stair-wrapper' data-step='0'><div class='s-scene-05-stair' style='--i:1'></div><div class='s-scene-05-stair' style='--i:2'></div><div class='s-scene-05-stair' style='--i:3'></div><div class='s-scene-05-stair' style='--i:4'></div><div class='s-scene-05-stair' style='--i:5'></div></div><!-- Step 1: Bubbles --><div class='s-scene-05-bubbles-layer' data-step='1'><div class='s-scene-05-bubble' style='--i:1'>+d</div><div class='s-scene-05-bubble' style='--i:2'>+d</div><div class='s-scene-05-bubble' style='--i:3'>+d</div><div class='s-scene-05-bubble' style='--i:4'>+d</div></div></div></div><div class='s-scene-05-content-area'><div class='s-scene-05-label' data-step='0'>模型：等差数列</div><div class='s-scene-05-description' data-step='0'>每一级台阶的高度差固定，这就是公差 <span class='s-scene-05-accent-text'>d</span></div><div class='s-scene-05-formula-box' data-step='2'><div class='s-scene-05-formula-label'>通项公式</div><div class='s-scene-05-formula-text' id='s-05-formula'>a<sub class='s-05-math-sub'>n</sub> = a<sub class='s-05-math-sub'>1</sub> + (n-1)d</div><div class='s-scene-05-shimmer-bar'></div></div></div></div></div>
  </div>
</section>

<section class="scene" data-scene-id="scene-06">
  <div class="sv-scene-root sv-scene-root-scene-06" data-scene-root-id="scene-06">
<div class='s-scene-06-container'>
  <div class='s-scene-06-stage'>
    <div class='s-scene-06-canvas'>
      <!-- Connection Lines -->
      <svg class='s-scene-06-svg-layer' viewBox='0 0 800 400'>
        <!-- Level 1 to 2 -->
        <path class='s-scene-06-path' data-step='1' d='M 400 85 L 265 170' />
        <path class='s-scene-06-path' data-step='1' d='M 400 85 L 535 170' />
        <!-- Level 2 to 3 -->
        <path class='s-scene-06-path' data-step='1' d='M 250 195 L 165 285' />
        <path class='s-scene-06-path' data-step='1' d='M 250 195 L 335 285' />
        <path class='s-scene-06-path' data-step='1' d='M 550 195 L 465 285' />
        <path class='s-scene-06-path' data-step='1' d='M 550 195 L 635 285' />
        
        <!-- Multiplier Labels -->
        <g class='s-scene-06-q-labels' data-step='1'>
          <text x='315' y='125' class='s-scene-06-label-q'>×q</text>
          <text x='485' y='125' class='s-scene-06-label-q'>×q</text>
          <text x='195' y='250' class='s-scene-06-label-q'>×q</text>
          <text x='305' y='250' class='s-scene-06-label-q'>×q</text>
          <text x='495' y='250' class='s-scene-06-label-q'>×q</text>
          <text x='605' y='250' class='s-scene-06-label-q'>×q</text>
        </g>
      </svg>

      <!-- Cells -->
      <div class='s-scene-06-cells'>
        <div class='s-scene-06-cell s-scene-06-l1' id='s-06-c-1'></div>
        
        <div class='s-scene-06-cell s-scene-06-l2' id='s-06-c-2-1'></div>
        <div class='s-scene-06-cell s-scene-06-l2' id='s-06-c-2-2'></div>
        
        <div class='s-scene-06-cell s-scene-06-l3' id='s-06-c-3-1'></div>
        <div class='s-scene-06-cell s-scene-06-l3' id='s-06-c-3-2'></div>
        <div class='s-scene-06-cell s-scene-06-l3' id='s-06-c-3-3'></div>
        <div class='s-scene-06-cell s-scene-06-l3' id='s-06-c-3-4'></div>
      </div>
    </div>

    <!-- Bottom Formula -->
    <div class='s-scene-06-formula-container' data-step='2'>
      <div class='s-scene-06-formula'>
        <span class='s-scene-06-math'>a<sub>n</sub> = a<sub>1</sub> · <span class='s-scene-06-highlight'>q</span><sup>n-1</sup></span>
      </div>
      <div class='s-scene-06-caption'>等比数列通项公式</div>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-07">
  <div class="sv-scene-root sv-scene-root-scene-07" data-scene-root-id="scene-07">
<div class='s-scene-07-container'><div class='s-scene-07-bg-layer'><div class='s-scene-07-blur-text' data-step='1'>S<sub>n</sub> = a<sub>1</sub> + a<sub>2</sub> + ... + a<sub>n</sub></div><div class='s-scene-07-blur-text' data-step='1'>S<sub>n</sub> = a<sub>1</sub>(1-q<sup>n</sup>)/(1-q)</div><div class='s-scene-07-blur-text' data-step='1'>∑ a<sub>k</sub></div></div><div class='s-scene-07-door-portal' data-step='1'></div><div class='s-scene-07-formula-merge' data-step='0'><div class='s-scene-07-formula-item f-an'>a<sub>n</sub> = a<sub>1</sub>·q<sup>n-1</sup></div><div class='s-scene-07-formula-item f-sn'>S<sub>n</sub> = <span class='frac'><span>a<sub>1</sub>(1-q<sup>n</sup>)</span><span class='bar'></span><span>1-q</span></span></div></div><div class='s-scene-07-key-wrapper' id='key-anchor'><svg class='s-scene-07-key-svg' viewBox='0 0 100 200'><path class='s-scene-07-key-path' d='M 50 40 A 20 20 0 1 0 50 80 A 20 20 0 1 0 50 40 M 50 80 L 50 160 M 50 120 L 65 120 M 50 140 L 65 140' /></svg></div><div class='s-scene-07-overlay-text' data-step='1'>开启数列大门</div></div>
  </div>
</section>

<section class="scene" data-scene-id="scene-08">
  <div class="sv-scene-root sv-scene-root-scene-08" data-scene-root-id="scene-08">
<div class='s-scene-08-container'>
  <div class='s-scene-08-starfield'>
    <div class='s-scene-08-stars' id='star-canvas'></div>
  </div>
  <div class='s-scene-08-formula-dust-container'>
    <!-- Placeholder for symbols that merge -->
    <div class='s-scene-08-symbol' style='--tx:-200px; --ty:-300px; --delay:0.1s'>∑</div>
    <div class='s-scene-08-symbol' style='--tx:300px; --ty:-150px; --delay:0.3s'>π</div>
    <div class='s-scene-08-symbol' style='--tx:-400px; --ty:100px; --delay:0.5s'>∞</div>
    <div class='s-scene-08-symbol' style='--tx:250px; --ty:350px; --delay:0.2s'>f(x)</div>
    <div class='s-scene-08-symbol' style='--tx:-100px; --ty:400px; --delay:0.4s'>φ</div>
    <div class='s-scene-08-symbol' style='--tx:450px; --ty:-250px; --delay:0.6s'>e</div>
  </div>
  <div class='s-scene-08-content' data-step='1'>
    <div class='s-scene-08-eyebrow'>FINALE</div>
    <h1 class='s-scene-08-hero-title'>规律之美</h1>
    <div class='s-scene-08-divider'></div>
    <p class='s-scene-08-subtitle'>THE BEAUTY OF ORDER</p>
  </div>
</div>
  </div>
</section>
      </div>
    </div>
  </div>
  <script id="__SVGVIDEO_META__" type="application/json">{"version":2,"format":"json","title":"高中数学：数列的奥秘与规律","fullScript":"同学们好，今天我们来攻克高中数学中一个非常核心的板块——数列。简单来说，数列就是按一定次序排列的一列数。它像是一串珍珠，每一颗珍珠都有自己的编号和大小。我们通常用 a1，a2 一直到 an 来表示。其中 n 代表项数，也就是位置，而 an 就是对应的项。在数列的世界里，有两种最基础的模型：等差数列和等比数列。等差数列就像爬楼梯，每一级的高度差都是一样的，这个固定的差值我们叫它公差 d。而等比数列则像细胞分裂，每一项都是前一项的固定倍数，这个倍数就是公比 q。掌握了通项公式和求和公式，你就拿到了开启数列大门的钥匙。现在，让我们一起深入探索数学的规律之美。","visualStyleId":"anthropic","scenes":[{"id":"scene-01","title":"开篇引言","steps":2,"status":"success","prompt":"背景为深蓝色渐变，中心出现发光的标题‘数列’，字体带有金属质感和外发光。Step 0: 标题以缩放效果弹出；Step 1: 标题下方出现一组跳动的粒子，形成数学符号波浪，营造科技感和数学氛围。","scriptText":"同学们好，今天我们来攻克高中数学中一个非常核心的板块——数列。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_ea23d8c8-817a-4ca3-a581-2a2c85792166/s_scene-01/v_xiaochen/a_7461b76c_1776925069126_otm7q3.mp3","audioDurationMs":6300,"voiceName":"xiaochen","relatedSceneIds":["scene-02"]},{"id":"scene-02","title":"数列定义","steps":3,"status":"success","prompt":"画面中心出现一个优雅的磨砂玻璃卡片。Step 0: 屏幕中心弹出一行数字 2, 4, 6, 8...；Step 1: 每个数字上方出现对应的序号标注 ①, ②, ③, ④；Step 2: 整个卡片边缘亮起，显示出‘有序的一列数’字样。","scriptText":"简单来说，数列就是按一定次序排列的一列数。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_ea23d8c8-817a-4ca3-a581-2a2c85792166/s_scene-02/v_xiaochen/a_7f8fd8dc_1776925095955_rps6z9.mp3","audioDurationMs":4608,"voiceName":"xiaochen","relatedSceneIds":["scene-01","scene-03"]},{"id":"scene-03","title":"珍珠比喻","steps":3,"status":"success","prompt":"视觉隐喻场景。Step 0: 屏幕横向拉出一根发光的丝线；Step 1: 丝线上依次挂上 5 颗晶莹剔透的珍珠，珍珠内部带有微光；Step 2: 每颗珍珠下方出现闪烁的标签 a1, a2, a3...，演示数列的离散性和有序性。","scriptText":"它像是一串珍珠，每一颗珍珠都有自己的编号和大小。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_ea23d8c8-817a-4ca3-a581-2a2c85792166/s_scene-03/v_xiaochen/a_c5e01a15_1776925490064_9huevn.mp3","audioDurationMs":4932,"voiceName":"xiaochen","relatedSceneIds":["scene-02","scene-04"]},{"id":"scene-04","title":"项与项数","steps":3,"status":"success","prompt":"对比展示布局。Step 0: 屏幕左侧出现变量 n (项数)，右侧出现 an (项)；Step 1: 中间用箭头连接，n 的位置从 1 变动到 5，右侧 an 随之变动；Step 2: 高亮‘位置’与‘对应值’两个关键词，伴随呼吸灯光效。","scriptText":"我们通常用 a1，a2 一直到 an 来表示。其中 n 代表项数，也就是位置，而 an 就是对应的项。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_ea23d8c8-817a-4ca3-a581-2a2c85792166/s_scene-04/v_xiaochen/a_99875023_1776925512055_bdir6i.mp3","audioDurationMs":9684,"voiceName":"xiaochen","relatedSceneIds":["scene-03","scene-05"]},{"id":"scene-05","title":"等差数列模型","steps":3,"status":"success","prompt":"阶梯式动画。Step 0: 画面左侧生成一个动态升起的 3D 楼梯；Step 1: 每一级台阶之间出现一个半透明的气泡，标注‘+d’；Step 2: 屏幕右侧通过打字机效果写出等差数列通项公式 an = a1 + (n-1)d，公式带有渐变流光。","scriptText":"在数列的世界里，有两种最基础的模型：等差数列和等比数列。等差数列就像爬楼梯，每一级的高度差都是一样的，这个固定的差值我们叫它公差 d。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_ea23d8c8-817a-4ca3-a581-2a2c85792166/s_scene-05/v_xiaochen/a_b2874249_1776925719935_8wfda8.mp3","audioDurationMs":13464,"voiceName":"xiaochen","relatedSceneIds":["scene-04","scene-06"]},{"id":"scene-06","title":"等比数列模型","steps":3,"status":"success","prompt":"分裂扩张动画。Step 0: 屏幕中心一个圆球分裂成两个，两个分裂成四个；Step 1: 连接线条上标注‘×q’；Step 2: 屏幕底部平滑淡入等比数列通项公式 an = a1 * q^(n-1)，字母 q 呈现亮橙色突出。","scriptText":"而等比数列则像细胞分裂，每一项都是前一项的固定倍数，这个倍数就是公比 q。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_ea23d8c8-817a-4ca3-a581-2a2c85792166/s_scene-06/v_xiaochen/a_f01749ff_1776925568920_xt7pto.mp3","audioDurationMs":7416,"voiceName":"xiaochen","relatedSceneIds":["scene-05","scene-07"]},{"id":"scene-07","title":"公式钥匙","steps":2,"status":"success","prompt":"象征性视觉表达。Step 0: 两组公式（通项与求和）在空中交汇，融合成一把金色的几何钥匙；Step 1: 钥匙旋转并指向一个巨大的数学之门，背景出现数列求和公式 Sn 的动态模糊效果。","scriptText":"掌握了通项公式和求和公式，你就拿到了开启数列大门的钥匙。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_ea23d8c8-817a-4ca3-a581-2a2c85792166/s_scene-07/v_xiaochen/a_d4425529_1776925591245_ylbgxw.mp3","audioDurationMs":6048,"voiceName":"xiaochen","relatedSceneIds":["scene-06","scene-08"]},{"id":"scene-08","title":"总结结尾","steps":2,"status":"success","prompt":"情感升华场景。Step 0: 所有数学符号化作星光向中心汇聚；Step 1: 最终定格在‘规律之美’四个大字上，背景为深邃的星空背景，带有缓慢的平移缩放动画。","scriptText":"现在，让我们一起深入探索数学的规律之美。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_ea23d8c8-817a-4ca3-a581-2a2c85792166/s_scene-08/v_xiaochen/a_39d842a6_1776925603950_qmec53.mp3","audioDurationMs":4356,"voiceName":"xiaochen","relatedSceneIds":["scene-07"]}]}</script>
  <script id="__SVGVIDEO_SCENE_DATA__" type="application/json">[{"id":"scene-01","title":"开篇引言","steps":2,"html":"<div class='s-scene-01-container'>\n  <div class='s-scene-01-content'>\n    <div class='s-scene-01-eyebrow mono' data-step='0'>CHAPTER 01</div>\n    <h1 class='s-scene-01-title' data-step='0'>数列</h1>\n    <div class='s-scene-01-divider' data-step='0'></div>\n    <div class='s-scene-01-wave-container' data-step='1'>\n      <div class='s-scene-01-dot' style='--i:0'></div>\n      <div class='s-scene-01-dot' style='--i:1'></div>\n      <div class='s-scene-01-dot' style='--i:2'></div>\n      <div class='s-scene-01-dot' style='--i:3'></div>\n      <div class='s-scene-01-dot' style='--i:4'></div>\n      <div class='s-scene-01-dot' style='--i:5'></div>\n      <div class='s-scene-01-dot' style='--i:6'></div>\n      <div class='s-scene-01-dot' style='--i:7'></div>\n      <div class='s-scene-01-dot' style='--i:8'></div>\n      <div class='s-scene-01-dot' style='--i:9'></div>\n      <div class='s-scene-01-dot' style='--i:10'></div>\n      <div class='s-scene-01-dot' style='--i:11'></div>\n    </div>\n    <p class='s-scene-01-subtitle' data-step='1'>高中数学核心板块</p>\n  </div>\n</div>","css":".s-scene-01-container {\n  background-color: #F7F4EE;\n  height: 100vh;\n  width: 100%;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  font-family: \"Source Serif 4\", \"Noto Serif SC\", serif;\n  overflow: hidden;\n  position: relative;\n}\n\n.s-scene-01-content {\n  text-align: center;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  max-width: 800px;\n  z-index: 10;\n}\n\n.s-scene-01-eyebrow {\n  font-family: \"JetBrains Mono\", monospace;\n  color: #D97757;\n  font-size: 0.875rem;\n  letter-spacing: 0.2em;\n  margin-bottom: 1.5rem;\n  opacity: 0;\n  transform: translateY(10px);\n  transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.s-scene-01-title {\n  font-size: 6rem;\n  font-weight: 500;\n  color: #1D1D1F;\n  margin: 0;\n  letter-spacing: -0.02em;\n  line-height: 1.1;\n  opacity: 0;\n  transform: scale(0.95) translateY(20px);\n  transition: all 1s cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.s-scene-01-divider {\n  width: 40px;\n  height: 2px;\n  background-color: #D97757;\n  margin: 2rem 0;\n  opacity: 0;\n  transition: width 1s ease 0.3s, opacity 0.8s ease 0.3s;\n}\n\n.s-scene-01-wave-container {\n  display: flex;\n  gap: 12px;\n  height: 60px;\n  align-items: center;\n  margin-top: 1rem;\n  opacity: 0;\n  transition: opacity 1s ease;\n}\n\n.s-scene-01-dot {\n  width: 6px;\n  height: 6px;\n  background-color: #D97757;\n  border-radius: 50%;\n  animation: s-dot-bounce 2s infinite ease-in-out;\n  animation-delay: calc(var(--i) * 0.15s);\n}\n\n.s-scene-01-subtitle {\n  font-family: \"Inter\", sans-serif;\n  color: #8B867E;\n  font-size: 1.125rem;\n  margin-top: 2rem;\n  letter-spacing: 0.1em;\n  opacity: 0;\n  transition: all 1s ease 0.5s;\n}\n\n@keyframes s-dot-bounce {\n  0%, 100% { transform: translateY(0); }\n  50% { transform: translateY(-30px); }\n}\n\n[data-step=\"0\"].active .s-scene-01-title,\n[data-step=\"0\"].active .s-scene-01-eyebrow {\n  opacity: 1;\n  transform: scale(1) translateY(0);\n}\n\n[data-step=\"0\"].active .s-scene-01-divider {\n  opacity: 1;\n  width: 80px;\n}\n\n[data-step=\"1\"].active .s-scene-01-wave-container,\n[data-step=\"1\"].active .s-scene-01-subtitle {\n  opacity: 1;\n}","js":"window.SceneLifecycle.register('sequence-intro', {\n  enter() {\n    const title = document.querySelector('.s-scene-01-title');\n    const eyebrow = document.querySelector('.s-scene-01-eyebrow');\n    const divider = document.querySelector('.s-scene-01-divider');\n    \n    // Initial state trigger\n    setTimeout(() => {\n      title.parentElement.parentElement.querySelectorAll('[data-step=\"0\"]').forEach(el => el.classList.add('active'));\n    }, 100);\n  },\n  step(s) {\n    const els = document.querySelectorAll(`[data-step=\"${s}\"]`);\n    els.forEach(el => el.classList.add('active'));\n  },\n  leave() {\n    // Cleanup if needed\n  }\n});"},{"id":"scene-02","title":"数列定义","steps":3,"html":"<div class='s-scene-02-container'>\n  <div class='s-scene-02-card'>\n    <div class='s-scene-02-inner'>\n      <div class='s-scene-02-sequence-wrapper'>\n        <div class='s-scene-02-item' data-step='0'>\n          <span class='s-scene-02-index' data-step='1'>①</span>\n          <span class='s-scene-02-number'>2</span>\n        </div>\n        <div class='s-scene-02-item' data-step='0'>\n          <span class='s-scene-02-index' data-step='1'>②</span>\n          <span class='s-scene-02-number'>4</span>\n        </div>\n        <div class='s-scene-02-item' data-step='0'>\n          <span class='s-scene-02-index' data-step='1'>③</span>\n          <span class='s-scene-02-number'>6</span>\n        </div>\n        <div class='s-scene-02-item' data-step='0'>\n          <span class='s-scene-02-index' data-step='1'>④</span>\n          <span class='s-scene-02-number'>8</span>\n        </div>\n        <div class='s-scene-02-ellipsis' data-step='0'>...</div>\n      </div>\n      \n      <div class='s-scene-02-label-container' data-step='2'>\n        <div class='s-scene-02-divider'></div>\n        <div class='s-scene-02-label'>有序的一列数</div>\n      </div>\n    </div>\n    <div class='s-scene-02-glow-border' data-step='2'></div>\n  </div>\n</div>","css":".s-scene-02-container {\n  background-color: #F7F4EE;\n  height: 100vh;\n  width: 100%;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  perspective: 1000px;\n}\n\n.s-scene-02-card {\n  position: relative;\n  background: rgba(255, 255, 255, 0.6);\n  backdrop-filter: blur(20px);\n  -webkit-backdrop-filter: blur(20px);\n  border: 1px solid #E4DED2;\n  border-radius: 24px;\n  padding: 4rem 6rem;\n  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.04);\n  transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1);\n  overflow: hidden;\n}\n\n.s-scene-02-inner {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 3rem;\n  z-index: 2;\n  position: relative;\n}\n\n.s-scene-02-sequence-wrapper {\n  display: flex;\n  align-items: flex-end;\n  gap: 2.5rem;\n}\n\n.s-scene-02-item {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 0.75rem;\n  opacity: 0;\n  transform: translateY(20px);\n  transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n.s-scene-02-item.active {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.s-scene-02-index {\n  font-family: 'JetBrains Mono', monospace;\n  font-size: 1.25rem;\n  color: #D97757;\n  opacity: 0;\n  transform: translateY(-10px);\n  transition: all 0.5s ease;\n}\n\n.s-scene-02-index.active {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.s-scene-02-number {\n  font-family: 'Source Serif 4', serif;\n  font-size: 5.5rem;\n  font-weight: 500;\n  color: #1D1D1F;\n  line-height: 1;\n}\n\n.s-scene-02-ellipsis {\n  font-family: 'Source Serif 4', serif;\n  font-size: 4rem;\n  color: #8B867E;\n  padding-bottom: 0.5rem;\n  opacity: 0;\n  transition: opacity 0.8s ease 0.4s;\n}\n\n.s-scene-02-ellipsis.active {\n  opacity: 1;\n}\n\n.s-scene-02-label-container {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  width: 100%;\n  opacity: 0;\n  transform: translateY(10px);\n  transition: all 0.8s ease 0.2s;\n}\n\n.s-scene-02-label-container.active {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.s-scene-02-divider {\n  width: 0%;\n  height: 1px;\n  background: #E4DED2;\n  margin-bottom: 1.5rem;\n  transition: width 1s cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.active .s-scene-02-divider {\n  width: 100%;\n}\n\n.s-scene-02-label {\n  font-family: 'Noto Serif SC', serif;\n  font-size: 1.75rem;\n  letter-spacing: 0.3em;\n  color: #D97757;\n  font-weight: 500;\n}\n\n.s-scene-02-glow-border {\n  position: absolute;\n  inset: 0;\n  border-radius: 24px;\n  border: 2px solid transparent;\n  pointer-events: none;\n  transition: border-color 0.8s ease;\n}\n\n.s-scene-02-glow-border.active {\n  border-color: #D97757;\n  box-shadow: inset 0 0 20px rgba(217, 119, 87, 0.1), 0 0 30px rgba(217, 119, 87, 0.05);\n}","js":"window.SceneLifecycle.register('scene-02', {\n  enter() {\n    // Ensure initial state\n    const container = document.querySelector('.s-scene-02-container');\n    if (container) container.style.opacity = '1';\n  },\n  step(s) {\n    const els = document.querySelectorAll(`[data-step=\"${s}\"]`);\n    els.forEach((el, index) => {\n      // Add a slight stagger for items within the same step\n      setTimeout(() => {\n        el.classList.add('active');\n      }, index * 100);\n    });\n    \n    if (s === 2) {\n       const card = document.querySelector('.s-scene-02-card');\n       if (card) card.style.transform = 'translateY(-10px) scale(1.02)';\n    }\n  },\n  leave() {\n    const card = document.querySelector('.s-scene-02-card');\n    if (card) card.style.opacity = '0';\n  }\n});"},{"id":"scene-03","title":"珍珠比喻","steps":3,"html":"<div class='s-scene-03-container'>\n  <div class='s-scene-03-stage'>\n    <!-- Step 0: 发光的丝线 -->\n    <div class='s-scene-03-thread' data-step='0'></div>\n    \n    <!-- Step 1: 5颗珍珠 -->\n    <div class='s-scene-03-pearls-wrapper'>\n      <div class='s-scene-03-pearl-item' data-step='1'>\n        <div class='s-scene-03-pearl-glow'></div>\n        <div class='s-scene-03-pearl'></div>\n        <!-- Step 2: 标签 -->\n        <div class='s-scene-03-label' data-step='2'><span class='s-scene-03-label-symbol'>a</span><span class='s-scene-03-label-idx'>1</span></div>\n      </div>\n      <div class='s-scene-03-pearl-item' data-step='1'>\n        <div class='s-scene-03-pearl-glow'></div>\n        <div class='s-scene-03-pearl'></div>\n        <div class='s-scene-03-label' data-step='2'><span class='s-scene-03-label-symbol'>a</span><span class='s-scene-03-label-idx'>2</span></div>\n      </div>\n      <div class='s-scene-03-pearl-item' data-step='1'>\n        <div class='s-scene-03-pearl-glow'></div>\n        <div class='s-scene-03-pearl'></div>\n        <div class='s-scene-03-label' data-step='2'><span class='s-scene-03-label-symbol'>a</span><span class='s-scene-03-label-idx'>3</span></div>\n      </div>\n      <div class='s-scene-03-pearl-item' data-step='1'>\n        <div class='s-scene-03-pearl-glow'></div>\n        <div class='s-scene-03-pearl'></div>\n        <div class='s-scene-03-label' data-step='2'><span class='s-scene-03-label-symbol'>a</span><span class='s-scene-03-label-idx'>4</span></div>\n      </div>\n      <div class='s-scene-03-pearl-item' data-step='1'>\n        <div class='s-scene-03-pearl-glow'></div>\n        <div class='s-scene-03-pearl'></div>\n        <div class='s-scene-03-label' data-step='2'><span class='s-scene-03-label-symbol'>a</span><span class='s-scene-03-label-idx'>5</span></div>\n      </div>\n    </div>\n\n    <div class='s-scene-03-hint' data-step='0'>离散且有序的珍珠</div>\n  </div>\n</div>","css":".s-scene-03-container {\n  background-color: #F7F4EE;\n  height: 100vh;\n  width: 100%;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  overflow: hidden;\n  font-family: 'Source Serif 4', serif;\n}\n\n.s-scene-03-stage {\n  position: relative;\n  width: 80%;\n  max-width: 1000px;\n  height: 400px;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n}\n\n/* 丝线 */\n.s-scene-03-thread {\n  position: absolute;\n  top: 50%;\n  left: 0;\n  width: 0%;\n  height: 1px;\n  background: linear-gradient(90deg, transparent, #D97757, transparent);\n  box-shadow: 0 0 10px rgba(217, 119, 87, 0.3);\n  transition: width 1.2s cubic-bezier(0.65, 0, 0.35, 1);\n  z-index: 1;\n}\n\n.s-scene-03-thread.active {\n  width: 100%;\n}\n\n/* 珍珠容器 */\n.s-scene-03-pearls-wrapper {\n  display: flex;\n  justify-content: space-around;\n  width: 100%;\n  z-index: 2;\n}\n\n.s-scene-03-pearl-item {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  position: relative;\n  opacity: 0;\n  transform: translateY(-20px);\n  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n.s-scene-03-pearl-item.active {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n/* 珍珠视觉 */\n.s-scene-03-pearl {\n  width: 60px;\n  height: 60px;\n  background: radial-gradient(circle at 30% 30%, #FFFFFF, #F5F4F0 60%, #E4DED2 100%);\n  border-radius: 50%;\n  box-shadow: \n    inset -5px -5px 15px rgba(0,0,0,0.05), \n    0 10px 30px rgba(217, 119, 87, 0.1);\n  border: 0.5px solid rgba(255,255,255,0.8);\n  position: relative;\n  backdrop-filter: blur(2px);\n}\n\n.s-scene-03-pearl-glow {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 30px;\n  height: 30px;\n  background: #D97757;\n  filter: blur(15px);\n  opacity: 0.2;\n  transform: translate(-50%, -50%);\n  border-radius: 50%;\n  pointer-events: none;\n}\n\n/* 标签 */\n.s-scene-03-label {\n  margin-top: 2rem;\n  font-family: 'JetBrains Mono', monospace;\n  color: #D97757;\n  opacity: 0;\n  transform: scale(0.8);\n  transition: all 0.5s ease;\n}\n\n.s-scene-03-label.active {\n  opacity: 1;\n  transform: scale(1);\n  animation: s-blink 1.5s infinite ease-in-out;\n}\n\n.s-scene-03-label-symbol {\n  font-size: 1.5rem;\n  font-style: italic;\n  margin-right: 2px;\n}\n\n.s-scene-03-label-idx {\n  font-size: 1rem;\n  vertical-align: sub;\n}\n\n.s-scene-03-hint {\n  position: absolute;\n  bottom: 0;\n  font-size: 1rem;\n  letter-spacing: 0.2em;\n  color: #8B867E;\n  opacity: 0;\n  transition: opacity 1s ease 0.5s;\n}\n\n.s-scene-03-hint.active {\n  opacity: 1;\n}\n\n@keyframes s-blink {\n  0%, 100% { opacity: 1; }\n  50% { opacity: 0.6; }\n}","js":"window.SceneLifecycle.register('scene-03', {\n  enter() {\n    const container = document.querySelector('.s-scene-03-container');\n    if (container) container.style.opacity = '1';\n  },\n  step(s) {\n    const els = document.querySelectorAll(`.s-scene-03-container [data-step=\"${s}\"]`);\n    \n    if (s === 1) {\n      // Sequential pearls drop\n      els.forEach((el, index) => {\n        setTimeout(() => {\n          el.classList.add('active');\n        }, index * 250);\n      });\n    } else if (s === 2) {\n      // Staggered labels fade and blink\n      els.forEach((el, index) => {\n        setTimeout(() => {\n          el.classList.add('active');\n        }, index * 150);\n      });\n    } else {\n      // Step 0 for line and hint\n      els.forEach(el => el.classList.add('active'));\n    }\n  },\n  leave() {\n    const container = document.querySelector('.s-scene-03-container');\n    if (container) container.style.opacity = '0';\n  }\n});"},{"id":"scene-04","title":"项与项数","steps":3,"html":"<div class='s-scene-04-container'>\n  <div class='s-scene-04-stage'>\n    <div class='s-scene-04-layout'>\n      <!-- Left Side: n -->\n      <div class='s-scene-04-panel s-scene-04-left' data-step='0'>\n        <div class='s-scene-04-label-top'>项数</div>\n        <div class='s-scene-04-variable-box'>\n          <span class='s-scene-04-math-n'>n</span>\n          <span class='s-scene-04-val-display' id='s-scene-04-n-val'>= 1</span>\n        </div>\n        <div class='s-scene-04-keyword-badge' data-step='2'>位置</div>\n      </div>\n\n      <!-- Middle: Connector -->\n      <div class='s-scene-04-connector' data-step='1'>\n        <svg class='s-scene-04-arrow' viewBox='0 0 100 20'>\n          <path d='M0 10 L95 10 M85 5 L95 10 L85 15' fill='none' stroke='#D97757' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' />\n        </svg>\n      </div>\n\n      <!-- Right Side: an -->\n      <div class='s-scene-04-panel s-scene-04-right' data-step='0'>\n        <div class='s-scene-04-label-top'>项</div>\n        <div class='s-scene-04-variable-box'>\n          <span class='s-scene-04-math-an'>a<sub id='s-scene-04-an-idx'>1</sub></span>\n        </div>\n        <div class='s-scene-04-keyword-badge' data-step='2'>对应值</div>\n      </div>\n    </div>\n\n    <div class='s-scene-04-info-text' data-step='0'>一一对应的数学映射</div>\n  </div>\n</div>","css":".s-scene-04-container {\n  background-color: #F7F4EE;\n  height: 100vh;\n  width: 100%;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  font-family: 'Source Serif 4', serif;\n  color: #1A1918;\n}\n\n.s-scene-04-stage {\n  width: 80%;\n  max-width: 900px;\n  text-align: center;\n}\n\n.s-scene-04-layout {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  gap: 3rem;\n  margin-bottom: 4rem;\n}\n\n.s-scene-04-panel {\n  flex: 1;\n  background: #FAF9F5;\n  padding: 3rem 2rem;\n  border: 1px solid #E4DED2;\n  border-radius: 12px;\n  box-shadow: 0 10px 40px rgba(0,0,0,0.02);\n  position: relative;\n  transition: all 0.8s cubic-bezier(0.2, 0.8, 0.2, 1);\n  opacity: 0;\n  transform: translateY(20px);\n}\n\n.s-scene-04-panel.active {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.s-scene-04-label-top {\n  font-size: 0.9rem;\n  letter-spacing: 0.15em;\n  color: #8B867E;\n  text-transform: uppercase;\n  margin-bottom: 1.5rem;\n}\n\n.s-scene-04-variable-box {\n  font-size: 3.5rem;\n  font-weight: 300;\n}\n\n.s-scene-04-math-n, .s-scene-04-math-an {\n  font-style: italic;\n  color: #D97757;\n}\n\n.s-scene-04-val-display {\n  margin-left: 0.5rem;\n  font-family: 'JetBrains Mono', monospace;\n  font-size: 2.5rem;\n  color: #1A1918;\n}\n\n.s-scene-04-connector {\n  width: 120px;\n  opacity: 0;\n  transition: opacity 1s ease;\n}\n\n.s-scene-04-connector.active {\n  opacity: 1;\n}\n\n.s-scene-04-arrow {\n  width: 100%;\n  overflow: visible;\n}\n\n.s-scene-04-keyword-badge {\n  position: absolute;\n  bottom: -15px;\n  left: 50%;\n  transform: translateX(-50%) scale(0.9);\n  background: #D97757;\n  color: white;\n  padding: 6px 16px;\n  border-radius: 20px;\n  font-size: 0.85rem;\n  opacity: 0;\n  transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);\n  white-space: nowrap;\n}\n\n.s-scene-04-keyword-badge.active {\n  opacity: 1;\n  transform: translateX(-50%) scale(1);\n  animation: s-04-breathe 2.5s infinite ease-in-out;\n}\n\n.s-scene-04-info-text {\n  font-size: 1.1rem;\n  color: #8B867E;\n  opacity: 0;\n  transition: opacity 1s ease;\n}\n\n.s-scene-04-info-text.active {\n  opacity: 1;\n}\n\n@keyframes s-04-breathe {\n  0%, 100% { box-shadow: 0 0 0px rgba(217, 119, 87, 0); transform: translateX(-50%) scale(1); }\n  50% { box-shadow: 0 0 20px rgba(217, 119, 87, 0.4); transform: translateX(-50%) scale(1.05); }\n}\n\n#s-scene-04-an-idx {\n  font-size: 1.5rem;\n  vertical-align: sub;\n  font-family: 'JetBrains Mono', monospace;\n}","js":"window.SceneLifecycle.register('scene-04', {\n  enter() {\n    const nVal = document.getElementById('s-scene-04-n-val');\n    const anIdx = document.getElementById('s-scene-04-an-idx');\n    if (nVal) nVal.textContent = '= 1';\n    if (anIdx) anIdx.textContent = '1';\n  },\n  step(s) {\n    const els = document.querySelectorAll(`.s-scene-04-container [data-step=\"${s}\"]`);\n    els.forEach(el => el.classList.add('active'));\n\n    if (s === 1) {\n      // Animate n from 1 to 5\n      const nVal = document.getElementById('s-scene-04-n-val');\n      const anIdx = document.getElementById('s-scene-04-an-idx');\n      let count = 1;\n      const interval = setInterval(() => {\n        count++;\n        if (nVal) nVal.textContent = `= ${count}`;\n        if (anIdx) anIdx.textContent = count;\n        if (count >= 5) clearInterval(interval);\n      }, 400);\n    }\n  },\n  leave() {\n    const panels = document.querySelectorAll('.s-scene-04-panel, .s-scene-04-connector, .s-scene-04-keyword-badge, .s-scene-04-info-text');\n    panels.forEach(el => el.classList.remove('active'));\n  }\n});"},{"id":"scene-05","title":"等差数列模型","steps":3,"html":"<div class='s-scene-05-container'><div class='s-scene-05-main'><div class='s-scene-05-visual-area'><div class='s-scene-05-stairs-canvas' id='s-05-stairs-container'><!-- Step 0: 3D Stairs --><div class='s-scene-05-stair-wrapper' data-step='0'><div class='s-scene-05-stair' style='--i:1'></div><div class='s-scene-05-stair' style='--i:2'></div><div class='s-scene-05-stair' style='--i:3'></div><div class='s-scene-05-stair' style='--i:4'></div><div class='s-scene-05-stair' style='--i:5'></div></div><!-- Step 1: Bubbles --><div class='s-scene-05-bubbles-layer' data-step='1'><div class='s-scene-05-bubble' style='--i:1'>+d</div><div class='s-scene-05-bubble' style='--i:2'>+d</div><div class='s-scene-05-bubble' style='--i:3'>+d</div><div class='s-scene-05-bubble' style='--i:4'>+d</div></div></div></div><div class='s-scene-05-content-area'><div class='s-scene-05-label' data-step='0'>模型：等差数列</div><div class='s-scene-05-description' data-step='0'>每一级台阶的高度差固定，这就是公差 <span class='s-scene-05-accent-text'>d</span></div><div class='s-scene-05-formula-box' data-step='2'><div class='s-scene-05-formula-label'>通项公式</div><div class='s-scene-05-formula-text' id='s-05-formula'>a<sub class='s-05-math-sub'>n</sub> = a<sub class='s-05-math-sub'>1</sub> + (n-1)d</div><div class='s-scene-05-shimmer-bar'></div></div></div></div></div>","css":".s-scene-05-container { background-color: #F7F4EE; height: 100vh; width: 100%; display: flex; justify-content: center; align-items: center; font-family: 'Source Serif 4', serif; overflow: hidden; color: #1A1918; } .s-scene-05-main { width: 90%; max-width: 1100px; display: grid; grid-template-columns: 1.2fr 1fr; gap: 4rem; align-items: center; } .s-scene-05-visual-area { position: relative; height: 400px; perspective: 1200px; } .s-scene-05-stairs-canvas { position: relative; width: 100%; height: 100%; transform-style: preserve-3d; transform: rotateX(20deg) rotateY(-10deg); } .s-scene-05-stair-wrapper { transform-style: preserve-3d; } .s-scene-05-stair { position: absolute; bottom: 0; left: calc(var(--i) * 60px); width: 80px; height: calc(var(--i) * 40px); background: #FAF9F5; border: 1.5px solid #E4DED2; transform: translateZ(calc(var(--i) * 20px)); opacity: 0; transform: translateY(100px); transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1); transition-delay: calc(var(--i) * 0.15s); } [data-step='0'].active .s-scene-05-stair { opacity: 1; transform: translateY(0); } .s-scene-05-stair::after { content: ''; position: absolute; top: -1.5px; left: -1.5px; width: 100%; height: 40px; background: #FFF; border: 1.5px solid #E4DED2; transform: rotateX(90deg) translateY(-20px) translateZ(20px); } .s-scene-05-bubbles-layer { position: absolute; width: 100%; height: 100%; top: 0; left: 0; pointer-events: none; } .s-scene-05-bubble { position: absolute; background: rgba(217, 119, 87, 0.1); border: 1px solid rgba(217, 119, 87, 0.3); color: #D97757; font-family: 'JetBrains Mono', monospace; font-size: 0.9rem; width: 34px; height: 34px; border-radius: 50%; display: flex; align-items: center; justify-content: center; left: calc(var(--i) * 60px + 70px); bottom: calc(var(--i) * 40px + 10px); opacity: 0; transform: scale(0.5); transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1); transition-delay: calc(var(--i) * 0.2s); } [data-step='1'].active .s-scene-05-bubble { opacity: 1; transform: scale(1); animation: s-05-float 3s infinite ease-in-out calc(var(--i) * 0.5s); } @keyframes s-05-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } } .s-scene-05-content-area { display: flex; flex-direction: column; gap: 1.5rem; } .s-scene-05-label { font-size: 0.85rem; letter-spacing: 0.2em; text-transform: uppercase; color: #8B867E; opacity: 0; transform: translateX(20px); transition: all 0.8s ease; } .s-scene-05-description { font-size: 1.8rem; line-height: 1.4; font-weight: 300; opacity: 0; transform: translateX(20px); transition: all 0.8s ease 0.2s; } .s-scene-05-accent-text { color: #D97757; font-style: italic; font-weight: 600; } .s-scene-05-formula-box { margin-top: 2rem; padding: 2.5rem; background: #FAF9F5; border: 1px solid #E4DED2; border-radius: 4px; position: relative; opacity: 0; transform: translateY(30px); transition: all 1s cubic-bezier(0.2, 0.8, 0.2, 1); } .s-scene-05-formula-box.active { opacity: 1; transform: translateY(0); } .s-scene-05-formula-label { font-size: 0.75rem; color: #8B867E; margin-bottom: 1rem; letter-spacing: 0.1em; } .s-scene-05-formula-text { font-size: 2.8rem; font-style: italic; white-space: nowrap; overflow: hidden; border-right: 2px solid transparent; width: 0; } .s-scene-05-formula-box.active .s-scene-05-formula-text { width: 100%; transition: width 1.5s steps(20, end); animation: s-05-cursor 0.8s step-end infinite; } .s-scene-05-shimmer-bar { position: absolute; bottom: 0; left: 0; height: 2px; width: 0; background: linear-gradient(90deg, transparent, #D97757, transparent); } .s-scene-05-formula-box.active .s-scene-05-shimmer-bar { animation: s-05-shimmer 3s infinite ease-in-out 1.5s; } .active .s-scene-05-label, .active .s-scene-05-description { opacity: 1; transform: translateX(0); } @keyframes s-05-cursor { 50% { border-color: #D97757; } } @keyframes s-05-shimmer { 0% { left: -100%; width: 50%; } 100% { left: 150%; width: 50%; } } .s-05-math-sub { font-size: 1.2rem; vertical-align: sub; font-family: 'JetBrains Mono', monospace; }","js":"window.SceneLifecycle.register('scene-05', { enter() { const formula = document.getElementById('s-05-formula'); if(formula) formula.style.width = '0'; }, step(s) { const elements = document.querySelectorAll(`.s-scene-05-container [data-step='${s}'], .s-scene-05-formula-box[data-step='${s}']`); elements.forEach(el => el.classList.add('active')); if (s === 2) { const formula = document.getElementById('s-05-formula'); if(formula) { formula.style.width = '100%'; formula.style.background = 'linear-gradient(90deg, #1A1918 0%, #D97757 50%, #1A1918 100%)'; formula.style.backgroundSize = '200% 100%'; formula.style.webkitBackgroundClip = 'text'; formula.style.webkitTextFillColor = 'transparent'; formula.animate([ { backgroundPosition: '200% 0' }, { backgroundPosition: '-200% 0' } ], { duration: 4000, iterations: Infinity, easing: 'linear' }); } } }, leave() { const actives = document.querySelectorAll('.s-scene-05-container .active'); actives.forEach(el => el.classList.remove('active')); } });"},{"id":"scene-06","title":"等比数列模型","steps":3,"html":"<div class='s-scene-06-container'>\n  <div class='s-scene-06-stage'>\n    <div class='s-scene-06-canvas'>\n      <!-- Connection Lines -->\n      <svg class='s-scene-06-svg-layer' viewBox='0 0 800 400'>\n        <!-- Level 1 to 2 -->\n        <path class='s-scene-06-path' data-step='1' d='M 400 85 L 265 170' />\n        <path class='s-scene-06-path' data-step='1' d='M 400 85 L 535 170' />\n        <!-- Level 2 to 3 -->\n        <path class='s-scene-06-path' data-step='1' d='M 250 195 L 165 285' />\n        <path class='s-scene-06-path' data-step='1' d='M 250 195 L 335 285' />\n        <path class='s-scene-06-path' data-step='1' d='M 550 195 L 465 285' />\n        <path class='s-scene-06-path' data-step='1' d='M 550 195 L 635 285' />\n        \n        <!-- Multiplier Labels -->\n        <g class='s-scene-06-q-labels' data-step='1'>\n          <text x='315' y='125' class='s-scene-06-label-q'>×q</text>\n          <text x='485' y='125' class='s-scene-06-label-q'>×q</text>\n          <text x='195' y='250' class='s-scene-06-label-q'>×q</text>\n          <text x='305' y='250' class='s-scene-06-label-q'>×q</text>\n          <text x='495' y='250' class='s-scene-06-label-q'>×q</text>\n          <text x='605' y='250' class='s-scene-06-label-q'>×q</text>\n        </g>\n      </svg>\n\n      <!-- Cells -->\n      <div class='s-scene-06-cells'>\n        <div class='s-scene-06-cell s-scene-06-l1' id='s-06-c-1'></div>\n        \n        <div class='s-scene-06-cell s-scene-06-l2' id='s-06-c-2-1'></div>\n        <div class='s-scene-06-cell s-scene-06-l2' id='s-06-c-2-2'></div>\n        \n        <div class='s-scene-06-cell s-scene-06-l3' id='s-06-c-3-1'></div>\n        <div class='s-scene-06-cell s-scene-06-l3' id='s-06-c-3-2'></div>\n        <div class='s-scene-06-cell s-scene-06-l3' id='s-06-c-3-3'></div>\n        <div class='s-scene-06-cell s-scene-06-l3' id='s-06-c-3-4'></div>\n      </div>\n    </div>\n\n    <!-- Bottom Formula -->\n    <div class='s-scene-06-formula-container' data-step='2'>\n      <div class='s-scene-06-formula'>\n        <span class='s-scene-06-math'>a<sub>n</sub> = a<sub>1</sub> · <span class='s-scene-06-highlight'>q</span><sup>n-1</sup></span>\n      </div>\n      <div class='s-scene-06-caption'>等比数列通项公式</div>\n    </div>\n  </div>\n</div>","css":".s-scene-06-container {\n  background-color: #F7F4EE;\n  height: 100vh;\n  width: 100%;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  font-family: 'Source Serif 4', serif;\n  color: #1A1918;\n  overflow: hidden;\n}\n\n.s-scene-06-stage {\n  width: 100%;\n  max-width: 1000px;\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n}\n\n.s-scene-06-canvas {\n  width: 800px;\n  height: 400px;\n  position: relative;\n  margin-bottom: 2rem;\n}\n\n.s-scene-06-svg-layer {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  z-index: 1;\n}\n\n.s-scene-06-path {\n  fill: none;\n  stroke: #E4DED2;\n  stroke-width: 1.5;\n  stroke-dasharray: 200;\n  stroke-dashoffset: 200;\n  transition: stroke-dashoffset 1.2s cubic-bezier(0.4, 0, 0.2, 1);\n  opacity: 0;\n}\n\n.s-scene-06-path.active {\n  stroke-dashoffset: 0;\n  opacity: 1;\n}\n\n.s-scene-06-label-q {\n  font-family: 'JetBrains Mono', monospace;\n  font-size: 14px;\n  fill: #8B867E;\n  font-weight: 500;\n  opacity: 0;\n  transition: opacity 0.8s ease 0.4s;\n}\n\n[data-step='1'].active .s-scene-06-label-q {\n  opacity: 1;\n}\n\n.s-scene-06-cells {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  z-index: 2;\n}\n\n.s-scene-06-cell {\n  position: absolute;\n  width: 32px;\n  height: 32px;\n  background: #FAF9F5;\n  border: 1px solid #E4DED2;\n  border-radius: 50%;\n  box-shadow: 0 4px 12px rgba(0,0,0,0.03);\n  transform: translate(-50%, -50%) scale(0);\n  opacity: 0;\n  transition: transform 0.8s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.6s ease;\n}\n\n.s-scene-06-cell.visible {\n  transform: translate(-50%, -50%) scale(1);\n  opacity: 1;\n}\n\n/* Coordinates */\n.s-scene-06-l1 { left: 400px; top: 60px; }\n.s-scene-06-l2:nth-of-type(2) { left: 250px; top: 180px; }\n.s-scene-06-l2:nth-of-type(3) { left: 550px; top: 180px; }\n.s-scene-06-l3:nth-of-type(4) { left: 150px; top: 300px; }\n.s-scene-06-l3:nth-of-type(5) { left: 350px; top: 300px; }\n.s-scene-06-l3:nth-of-type(6) { left: 450px; top: 300px; }\n.s-scene-06-l3:nth-of-type(7) { left: 650px; top: 300px; }\n\n.s-scene-06-formula-container {\n  text-align: center;\n  opacity: 0;\n  transform: translateY(20px);\n  transition: all 1s cubic-bezier(0.2, 0.8, 0.2, 1);\n  margin-top: 2rem;\n}\n\n.s-scene-06-formula-container.active {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.s-scene-06-formula {\n  font-size: 3rem;\n  margin-bottom: 0.5rem;\n  font-weight: 300;\n}\n\n.s-scene-06-math {\n  font-style: italic;\n}\n\n.s-scene-06-highlight {\n  color: #D97757;\n  font-weight: 500;\n  font-family: 'JetBrains Mono', monospace;\n}\n\n.s-scene-06-caption {\n  font-size: 0.9rem;\n  letter-spacing: 0.2em;\n  color: #8B867E;\n  text-transform: uppercase;\n}\n\n.s-scene-06-sub, .s-scene-06-sup {\n  font-family: 'JetBrains Mono', monospace;\n  font-style: normal;\n}","js":"window.SceneLifecycle.register('scene-06', {\n  enter() {\n    const cells = document.querySelectorAll('.s-scene-06-cell');\n    cells.forEach(c => c.classList.remove('visible'));\n  },\n  step(s) {\n    const els = document.querySelectorAll(`.s-scene-06-container [data-step=\"${s}\"]`);\n    els.forEach(el => el.classList.add('active'));\n\n    if (s === 0) {\n      // Cell division sequence\n      const c1 = document.getElementById('s-06-c-1');\n      const c2 = document.querySelectorAll('.s-scene-06-l2');\n      const c3 = document.querySelectorAll('.s-scene-06-l3');\n\n      setTimeout(() => c1.classList.add('visible'), 100);\n      setTimeout(() => {\n        c2.forEach(c => c.classList.add('visible'));\n      }, 800);\n      setTimeout(() => {\n        c3.forEach(c => c.classList.add('visible'));\n      }, 1600);\n    }\n  },\n  leave() {\n    const actives = document.querySelectorAll('.s-scene-06-container .active');\n    actives.forEach(el => el.classList.remove('active'));\n    const cells = document.querySelectorAll('.s-scene-06-cell');\n    cells.forEach(c => c.classList.remove('visible'));\n  }\n});"},{"id":"scene-07","title":"公式钥匙","steps":2,"html":"<div class='s-scene-07-container'><div class='s-scene-07-bg-layer'><div class='s-scene-07-blur-text' data-step='1'>S<sub>n</sub> = a<sub>1</sub> + a<sub>2</sub> + ... + a<sub>n</sub></div><div class='s-scene-07-blur-text' data-step='1'>S<sub>n</sub> = a<sub>1</sub>(1-q<sup>n</sup>)/(1-q)</div><div class='s-scene-07-blur-text' data-step='1'>∑ a<sub>k</sub></div></div><div class='s-scene-07-door-portal' data-step='1'></div><div class='s-scene-07-formula-merge' data-step='0'><div class='s-scene-07-formula-item f-an'>a<sub>n</sub> = a<sub>1</sub>·q<sup>n-1</sup></div><div class='s-scene-07-formula-item f-sn'>S<sub>n</sub> = <span class='frac'><span>a<sub>1</sub>(1-q<sup>n</sup>)</span><span class='bar'></span><span>1-q</span></span></div></div><div class='s-scene-07-key-wrapper' id='key-anchor'><svg class='s-scene-07-key-svg' viewBox='0 0 100 200'><path class='s-scene-07-key-path' d='M 50 40 A 20 20 0 1 0 50 80 A 20 20 0 1 0 50 40 M 50 80 L 50 160 M 50 120 L 65 120 M 50 140 L 65 140' /></svg></div><div class='s-scene-07-overlay-text' data-step='1'>开启数列大门</div></div>","css":".s-scene-07-container { background-color: #F7F4EE; height: 100vh; width: 100%; display: flex; justify-content: center; align-items: center; position: relative; overflow: hidden; font-family: 'Source Serif 4', serif; }.s-scene-07-bg-layer { position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: space-around; padding: 5%; opacity: 0; transition: opacity 2s ease; }.s-scene-07-container [data-step='1'].s-scene-07-bg-layer { opacity: 0.15; }.s-scene-07-blur-text { font-size: 8rem; font-weight: 300; color: #8B867E; filter: blur(8px); transform: translateX(-100px); transition: all 3s cubic-bezier(0.2, 0.8, 0.2, 1); }.s-scene-07-container [data-step='1'].s-scene-07-blur-text { transform: translateX(50px); filter: blur(4px); }.s-scene-07-door-portal { position: absolute; width: 400px; height: 600px; border: 1px solid #E4DED2; border-radius: 200px 200px 0 0; background: linear-gradient(to bottom, #FAF9F5, #F7F4EE); opacity: 0; transform: scale(0.9) translateZ(-100px); transition: all 1.5s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 0 0 80px rgba(228, 222, 210, 0.3); z-index: 1; }.s-scene-07-container [data-step='1'].s-scene-07-door-portal { opacity: 1; transform: scale(1.1) translateZ(0); }.s-scene-07-formula-merge { position: relative; z-index: 3; display: flex; gap: 100px; transition: all 1.2s cubic-bezier(0.4, 0, 0.2, 1); }.s-scene-07-formula-merge.merged { opacity: 0; transform: scale(0.5); pointer-events: none; }.s-scene-07-formula-item { font-size: 2.5rem; color: #1A1918; white-space: nowrap; }.frac { display: inline-flex; flex-direction: column; vertical-align: middle; text-align: center; font-size: 0.8em; }.frac .bar { height: 1px; background: #1A1918; margin: 2px 0; }.s-scene-07-key-wrapper { position: absolute; z-index: 5; opacity: 0; transform: scale(0) rotate(-45deg); transition: all 1s cubic-bezier(0.34, 1.56, 0.64, 1); }.s-scene-07-key-wrapper.active { opacity: 1; transform: scale(1) rotate(0deg); }.s-scene-07-key-wrapper.pointing { transform: scale(1) rotate(90deg) translateY(-100px); }.s-scene-07-key-svg { width: 120px; height: 240px; filter: drop-shadow(0 10px 20px rgba(217, 119, 87, 0.2)); }.s-scene-07-key-path { fill: none; stroke: #D97757; stroke-width: 4; stroke-linecap: round; stroke-linejoin: round; }.s-scene-07-overlay-text { position: absolute; bottom: 10%; font-size: 1.5rem; letter-spacing: 0.5em; color: #8B867E; opacity: 0; transform: translateY(20px); transition: all 1s ease 0.5s; z-index: 10; }.s-scene-07-container [data-step='1'].s-scene-07-overlay-text { opacity: 1; transform: translateY(0); }","js":"window.SceneLifecycle.register('scene-07', { enter() { const merge = document.querySelector('.s-scene-07-formula-merge'); const key = document.querySelector('.s-scene-07-key-wrapper'); merge.classList.remove('merged'); key.classList.remove('active', 'pointing'); }, step(s) { if (s === 0) { const merge = document.querySelector('.s-scene-07-formula-merge'); const key = document.querySelector('.s-scene-07-key-wrapper'); setTimeout(() => { merge.classList.add('merged'); setTimeout(() => { key.classList.add('active'); }, 600); }, 1000); } if (s === 1) { const key = document.querySelector('.s-scene-07-key-wrapper'); key.classList.add('pointing'); const bgs = document.querySelectorAll('.s-scene-07-blur-text'); bgs.forEach((el, i) => { el.style.transitionDelay = `${i * 0.2}s`; el.classList.add('active'); }); const portal = document.querySelector('.s-scene-07-door-portal'); portal.classList.add('active'); const texts = document.querySelectorAll('.s-scene-07-container [data-step=\"1\"]'); texts.forEach(t => t.classList.add('active')); } }, leave() { const actives = document.querySelectorAll('.s-scene-07-container .active'); actives.forEach(el => el.classList.remove('active')); } });"},{"id":"scene-08","title":"总结结尾","steps":2,"html":"<div class='s-scene-08-container'>\n  <div class='s-scene-08-starfield'>\n    <div class='s-scene-08-stars' id='star-canvas'></div>\n  </div>\n  <div class='s-scene-08-formula-dust-container'>\n    <!-- Placeholder for symbols that merge -->\n    <div class='s-scene-08-symbol' style='--tx:-200px; --ty:-300px; --delay:0.1s'>∑</div>\n    <div class='s-scene-08-symbol' style='--tx:300px; --ty:-150px; --delay:0.3s'>π</div>\n    <div class='s-scene-08-symbol' style='--tx:-400px; --ty:100px; --delay:0.5s'>∞</div>\n    <div class='s-scene-08-symbol' style='--tx:250px; --ty:350px; --delay:0.2s'>f(x)</div>\n    <div class='s-scene-08-symbol' style='--tx:-100px; --ty:400px; --delay:0.4s'>φ</div>\n    <div class='s-scene-08-symbol' style='--tx:450px; --ty:-250px; --delay:0.6s'>e</div>\n  </div>\n  <div class='s-scene-08-content' data-step='1'>\n    <div class='s-scene-08-eyebrow'>FINALE</div>\n    <h1 class='s-scene-08-hero-title'>规律之美</h1>\n    <div class='s-scene-08-divider'></div>\n    <p class='s-scene-08-subtitle'>THE BEAUTY OF ORDER</p>\n  </div>\n</div>","css":".s-scene-08-container {\n  background-color: #F7F4EE;\n  height: 100vh;\n  width: 100%;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  position: relative;\n  overflow: hidden;\n  font-family: 'Source Serif 4', serif;\n  perspective: 1000px;\n}\n.s-scene-08-starfield {\n  position: absolute;\n  inset: 0;\n  background: radial-gradient(circle at center, #2C2A26 0%, #1A1918 100%);\n  opacity: 0;\n  transition: opacity 2.5s ease-in-out;\n  z-index: 1;\n}\n.s-scene-08-container[data-step-active='1'] .s-scene-08-starfield {\n  opacity: 1;\n}\n.s-scene-08-stars {\n  width: 100%;\n  height: 100%;\n  background-image: radial-gradient(1px 1px at 10% 20%, #D97757 100%, transparent 0), radial-gradient(1.5px 1.5px at 50% 50%, #E4DED2 100%, transparent 0), radial-gradient(1px 1px at 80% 30%, #D97757 100%, transparent 0);\n  background-size: 400px 400px;\n  animation: s-08-bg-pan 40s linear infinite alternate;\n  filter: blur(0.5px);\n}\n@keyframes s-08-bg-pan {\n  from { transform: scale(1) translate(0, 0); }\n  to { transform: scale(1.2) translate(-5%, -5%); }\n}\n.s-scene-08-formula-dust-container {\n  position: absolute;\n  z-index: 2;\n  width: 100%;\n  height: 100%;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  pointer-events: none;\n}\n.s-scene-08-symbol {\n  position: absolute;\n  font-size: 2.5rem;\n  color: #D97757;\n  opacity: 0;\n  font-family: 'JetBrains Mono', monospace;\n  transition: all 1.5s cubic-bezier(0.34, 1.56, 0.64, 1);\n  transform: translate(var(--tx), var(--ty)) scale(1.5);\n  filter: blur(4px);\n}\n.s-scene-08-container[data-step-active='0'] .s-scene-08-symbol {\n  opacity: 0.6;\n  transform: translate(0, 0) scale(0);\n  filter: blur(0px);\n  transition-delay: var(--delay);\n}\n.s-scene-08-content {\n  position: relative;\n  z-index: 10;\n  text-align: center;\n  color: #F7F4EE;\n  opacity: 0;\n  transform: translateY(30px);\n  transition: all 2s cubic-bezier(0.2, 0.8, 0.2, 1);\n}\n.s-scene-08-container[data-step-active='1'] .s-scene-08-content {\n  opacity: 1;\n  transform: translateY(0);\n}\n.s-scene-08-eyebrow {\n  font-family: sans-serif;\n  letter-spacing: 0.4em;\n  font-size: 0.75rem;\n  color: #D97757;\n  margin-bottom: 2rem;\n}\n.s-scene-08-hero-title {\n  font-size: 6rem;\n  font-weight: 200;\n  margin: 0;\n  letter-spacing: 0.1em;\n  font-family: 'Source Serif 4', serif;\n}\n.s-scene-08-divider {\n  width: 60px;\n  height: 1px;\n  background-color: #D97757;\n  margin: 2.5rem auto;\n  transform: scaleX(0);\n  transition: transform 1.5s ease 1s;\n}\n.s-scene-08-container[data-step-active='1'] .s-scene-08-divider {\n  transform: scaleX(1);\n}\n.s-scene-08-subtitle {\n  font-family: sans-serif;\n  letter-spacing: 0.6em;\n  font-size: 0.9rem;\n  opacity: 0.6;\n  font-weight: 300;\n}","js":"window.SceneLifecycle.register('scene-08', {\n  enter() {\n    const container = document.querySelector('.s-scene-08-container');\n    container.setAttribute('data-step-active', '-1');\n  },\n  step(s) {\n    const container = document.querySelector('.s-scene-08-container');\n    container.setAttribute('data-step-active', s);\n    \n    if (s === 0) {\n      // Step 0: Logic is handled by CSS transitions triggered by the attribute\n    }\n    \n    if (s === 1) {\n      // Extra sparkle effect if needed\n    }\n  },\n  leave() {\n    const container = document.querySelector('.s-scene-08-container');\n    container.removeAttribute('data-step-active');\n  }\n});"}]</script>
  <script>
    (function () {
      var state = { sceneId: 'scene-05', step: 0, direction: 1 };
      var previousSceneId = null;
      var exitCleanupTimer = null;
      var isPlaying = false;
      var playTimer = null;
      var progressRaf = null;
      var STEP_INTERVAL_MS = 1400;
      var SCENE_FINISH_PAUSE_MS = 2000;
      var autoplayFromFirstScene = false;
      var progressWrap = document.getElementById('sv-progress-wrap');
      var progressFill = document.getElementById('sv-progress-fill');
      var progressThumb = document.getElementById('sv-progress-thumb');
      var playBtn = document.getElementById('sv-play-btn');
      var expandBtn = document.getElementById('sv-expand-btn');
      var statusText = document.getElementById('sv-status-text');
      var sceneButtonList = Array.prototype.slice.call(document.querySelectorAll('[data-panel-scene-id]'));
      var sceneRetryButtonList = Array.prototype.slice.call(document.querySelectorAll('[data-retry-scene-id]'));
      var editorOverlay = document.getElementById('sv-editor-overlay');
      var editorBackdrop = document.getElementById('sv-editor-backdrop');
      var editorSheet = document.getElementById('sv-editor-sheet');
      var editorResizeHandle = document.getElementById('sv-editor-resize-handle');
      var editorCloseBtn = document.getElementById('sv-editor-close-btn');
      var editorSaveBtn = document.getElementById('sv-editor-save-btn');
      var editorList = document.getElementById('sv-editor-list');
      var editorSaveTip = document.getElementById('sv-editor-save-tip');
      var editorTipTimer = null;
      var isEditorOpen = false;
      var isEditorDirty = false;
      var editorHeightVh = 50;
      var hostCaps = { canRetry: false, canEditPanel: false, locale: 'zh', theme: 'dark' };
      var metaJson = document.getElementById('__SVGVIDEO_META__');
      var meta = { scenes: [] };
      try {
        meta = JSON.parse((metaJson && metaJson.textContent) || '{}');
      } catch (e) {
        meta = { scenes: [] };
      }
      var metaSceneMap = {};
      var metaScenes = Array.isArray(meta.scenes) ? meta.scenes : [];
      metaScenes.forEach(function (scene) {
        if (scene && typeof scene.id === 'string' && scene.id) metaSceneMap[scene.id] = scene;
      });
      var sceneModels = Array.prototype.slice.call(document.querySelectorAll('#stage > [data-scene-id]')).map(function (node, index) {
        var sceneId = node.getAttribute('data-scene-id') || ('scene-' + (index + 1));
        var metaScene = metaSceneMap[sceneId] || {};
        var sceneTitle = typeof metaScene.title === 'string' && metaScene.title ? metaScene.title : ('分镜' + (index + 1));
        var sceneSteps = Math.max(1, Number(metaScene.steps) || 1);
        var sceneStatus = typeof metaScene.status === 'string' ? metaScene.status : 'pending';
        var scenePrompt = typeof metaScene.prompt === 'string' ? metaScene.prompt : '';
        var sceneScript = typeof metaScene.scriptText === 'string' ? metaScene.scriptText : '';
        var sceneAudioObjectKey = typeof metaScene.audioObjectKey === 'string' ? metaScene.audioObjectKey : '';
        var sceneAudioDurationMs = Number(metaScene.audioDurationMs) > 0 ? Number(metaScene.audioDurationMs) : 0;
        var sceneVoiceName = typeof metaScene.voiceName === 'string' ? metaScene.voiceName : '';
        var relatedSceneIds = Array.isArray(metaScene.relatedSceneIds) ? metaScene.relatedSceneIds : [];
        return {
          id: sceneId,
          title: sceneTitle,
          steps: sceneSteps,
          status: sceneStatus,
          prompt: scenePrompt,
          scriptText: sceneScript,
          audioObjectKey: sceneAudioObjectKey,
          audioDurationMs: sceneAudioDurationMs,
          voiceName: sceneVoiceName,
          relatedSceneIds: relatedSceneIds
        };
      });
      if (!sceneModels.length && metaScenes.length) {
        sceneModels = metaScenes.map(function (scene, index) {
          return {
            id: scene.id || ('scene-' + (index + 1)),
            title: scene.title || ('分镜' + (index + 1)),
            steps: Math.max(1, Number(scene.steps) || 1),
            status: typeof scene.status === 'string' ? scene.status : 'pending',
            prompt: typeof scene.prompt === 'string' ? scene.prompt : '',
            scriptText: typeof scene.scriptText === 'string' ? scene.scriptText : '',
            audioObjectKey: typeof scene.audioObjectKey === 'string' ? scene.audioObjectKey : '',
            audioDurationMs: Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0,
            voiceName: typeof scene.voiceName === 'string' ? scene.voiceName : '',
            relatedSceneIds: Array.isArray(scene.relatedSceneIds) ? scene.relatedSceneIds : []
          };
        });
      }
      function i18nText(zh, en) {
        return hostCaps.locale === 'en' ? en : zh;
      }
      function applyI18nTexts() {
        var toolbarTitleEl = document.getElementById('sv-toolbar-title');
        var titleEl = document.getElementById('sv-editor-header-title');
        if (toolbarTitleEl) toolbarTitleEl.textContent = i18nText('分镜面板', 'Storyboard');
        if (titleEl) titleEl.textContent = i18nText('分镜详情编辑', 'Storyboard details');
        if (expandBtn) {
          var expandText = i18nText('展开分镜详情', 'Open storyboard details');
          expandBtn.setAttribute('aria-label', expandText);
          expandBtn.setAttribute('title', expandText);
        }
        if (editorSaveBtn) editorSaveBtn.textContent = isEditorDirty ? i18nText('保存*', 'Save*') : i18nText('保存', 'Save');
        if (editorCloseBtn) editorCloseBtn.textContent = i18nText('关闭', 'Close');
        if (editorSaveTip) editorSaveTip.textContent = i18nText('已保存', 'Saved');
      }
      function clampEditorHeightVh(value) {
        return Math.max(32, Math.min(80, Number(value) || 50));
      }
      function applyEditorHeight(vh) {
        editorHeightVh = clampEditorHeightVh(vh);
        document.documentElement.style.setProperty('--sv-editor-height', editorHeightVh + 'vh');
      }
      function persistMetaToScript() {
        meta.title = typeof meta.title === 'string' ? meta.title : '';
        meta.version = meta.version || 1;
        meta.scenes = sceneModels.map(function (scene) {
          return {
            id: scene.id,
            title: scene.title || '',
            steps: Math.max(1, Number(scene.steps) || 1),
            status: scene.status || 'pending',
            prompt: scene.prompt || '',
            scriptText: scene.scriptText || '',
            audioObjectKey: scene.audioObjectKey || '',
            audioDurationMs: Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0,
            voiceName: scene.voiceName || '',
            relatedSceneIds: Array.isArray(scene.relatedSceneIds) ? scene.relatedSceneIds : []
          };
        });
        if (metaJson) metaJson.textContent = JSON.stringify(meta);
      }
      function showSavedTip() {
        if (!editorSaveTip) return;
        if (editorTipTimer) {
          clearTimeout(editorTipTimer);
          editorTipTimer = null;
        }
        editorSaveTip.classList.add('is-visible');
        editorTipTimer = setTimeout(function () {
          editorSaveTip.classList.remove('is-visible');
        }, 1200);
      }
      function markEditorDirty() {
        isEditorDirty = true;
        applyI18nTexts();
      }
      function clearEditorDirty() {
        isEditorDirty = false;
        applyI18nTexts();
      }
      function getStatusLabel(status) {
        if (status === 'success') return i18nText('已生成', 'Done');
        if (status === 'generating') return i18nText('生成中', 'Generating');
        if (status === 'failed') return i18nText('失败', 'Failed');
        return i18nText('未生成', 'Pending');
      }
      function getStatusClass(status) {
        if (status === 'generating') return 'is-generating';
        if (status === 'success') return 'is-success';
        return 'is-failed';
      }
      function getRetryButtonInnerHtml(isGenerating) {
        if (isGenerating) return '<span class="scene-chip-retry-spinner"></span>';
        return '<svg class="scene-chip-retry-icon" viewBox="0 0 1024 1024" width="16" height="16" fill="currentColor"><path d="M698.569 531.322a39.825 39.825 0 0 0-23.898 7.949c-17.702 13.216-21.34 38.28-8.124 55.982l95.716 128.212c7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949c17.702-13.216 21.34-38.28 8.124-55.982l-95.716-128.212c-7.853-10.521-19.892-16.074-32.084-16.073z" /><path d="M922.498 563.818a39.825 39.825 0 0 0-23.898 7.949l-128.212 95.716c-17.703 13.216-21.34 38.28-8.124 55.982 7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949l128.212-95.716c17.702-13.216 21.34-38.28 8.124-55.982-7.854-10.521-19.893-16.074-32.084-16.073zM229.652 282.148a39.825 39.825 0 0 0-23.898 7.949c-17.702 13.216-21.34 38.28-8.124 55.982l95.716 128.212c7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949c17.702-13.216 21.34-38.28 8.124-55.982l-95.716-128.212c-7.854-10.521-19.892-16.074-32.084-16.073z" /><path d="M229.652 282.148a39.825 39.825 0 0 0-23.898 7.949L77.542 385.813c-17.702 13.216-21.34 38.28-8.124 55.982 7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949l128.213-95.716c17.702-13.216 21.34-38.28 8.124-55.982-7.855-10.521-19.893-16.073-32.085-16.073z" /><path d="M614.968 763.65c-44.13 18.171-94.005 25.121-146.168 16.968C353.747 762.636 261.364 670.253 243.381 555.2c-9.681-61.936 1.932-120.646 28.337-170.344l-58.657-58.657c-40.139 64.442-60.11 142.746-50.806 226.152 17.993 161.306 148.088 291.401 309.394 309.394 62.041 6.92 121.259-2.357 174.048-24.083 26.535-10.921 33.625-45.203 13.335-65.493l-0.098-0.098c-11.555-11.555-28.854-14.643-43.966-8.421zM409.033 260.35c44.131-18.171 94.007-25.122 146.169-16.968 115.051 17.985 207.431 110.365 225.416 225.416 9.682 61.935-1.931 120.646-28.337 170.346l58.658 58.658c40.139-64.443 60.109-142.747 50.805-226.155-17.993-161.305-148.087-291.399-309.391-309.391-62.042-6.92-121.26 2.356-174.05 24.082-26.535 10.921-33.625 45.203-13.335 65.493l0.099 0.099c11.555 11.554 28.854 14.642 43.966 8.42z" /></svg>';
      }
      function setSceneStatus(sceneId, status) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return;
        sceneModels[index].status = status;
        persistMetaToScript();
        var statusClass = getStatusClass(status);
        var chipWrap = document.querySelector('[data-chip-scene-id="' + sceneId + '"]');
        if (chipWrap) {
          chipWrap.classList.remove('is-success', 'is-failed', 'is-generating');
          chipWrap.classList.add(statusClass);
          var chipBtn = chipWrap.querySelector('.scene-chip');
          if (chipBtn) {
            chipBtn.classList.remove('is-success', 'is-failed', 'is-generating');
            chipBtn.classList.add(statusClass);
          }
          var retryBtn = chipWrap.querySelector('.scene-chip-retry');
          if (retryBtn) {
            retryBtn.innerHTML = getRetryButtonInnerHtml(status === 'generating');
            if (status === 'generating') retryBtn.setAttribute('disabled', 'disabled');
            else retryBtn.removeAttribute('disabled');
          }
        }
        renderStatus();
      }
      function requestSceneRetry(sceneId) {
        if (!hostCaps.canRetry) return;
        var idx = getSceneIndexById(sceneId);
        if (idx < 0) return;
        var scene = sceneModels[idx];
        setSceneStatus(sceneId, 'generating');
        focusScene(sceneId);
        if (window.parent && window.parent !== window) {
          window.parent.postMessage(
            { type: '__SVGVIDEO_RETRY_SCENE', sceneId: sceneId, prompt: scene.prompt || '' },
            '*'
          );
        }
      }
      function renderEditorList() {
        if (!editorList) return;
        editorList.innerHTML = '';
        var fragment = document.createDocumentFragment();
        sceneModels.forEach(function (scene, index) {
          var item = document.createElement('section');
          item.className = 'sv-editor-item';
          item.setAttribute('data-editor-scene-id', scene.id);

          var head = document.createElement('div');
          head.className = 'sv-editor-item-head';

          var jumpBtn = document.createElement('button');
          jumpBtn.type = 'button';
          jumpBtn.className = 'sv-editor-item-title';
          jumpBtn.textContent = i18nText('分镜', 'Scene') + (index + 1) + ' · ' + (scene.title || '');
          jumpBtn.addEventListener('click', function () {
            focusScene(scene.id);
          });
          head.appendChild(jumpBtn);

          var statusWrap = document.createElement('div');
          statusWrap.className = 'sv-editor-status-wrap';
          var status = document.createElement('span');
          status.className = 'sv-editor-status';
          status.textContent = getStatusLabel(scene.status);
          statusWrap.appendChild(status);
          var retryBtn = document.createElement('button');
          retryBtn.type = 'button';
          retryBtn.className = 'scene-chip-retry sv-editor-retry';
          retryBtn.setAttribute('aria-label', i18nText('重新生成当前分镜', 'Retry this scene'));
          retryBtn.setAttribute('title', i18nText('重新生成当前分镜', 'Retry this scene'));
          retryBtn.innerHTML = getRetryButtonInnerHtml(scene.status === 'generating');
          if (scene.status === 'generating' || !hostCaps.canRetry) retryBtn.setAttribute('disabled', 'disabled');
          retryBtn.addEventListener('click', function (event) {
            event.preventDefault();
            event.stopPropagation();
            requestSceneRetry(scene.id);
            if (isEditorOpen) renderEditorList();
          });
          statusWrap.appendChild(retryBtn);
          head.appendChild(statusWrap);

          item.appendChild(head);

          var scriptField = document.createElement('label');
          scriptField.className = 'sv-editor-field';
          var scriptLabel = document.createElement('span');
          scriptLabel.className = 'sv-editor-label';
          scriptLabel.textContent = i18nText('脚本', 'Script');
          var scriptInput = document.createElement('div');
          scriptInput.className = 'sv-editor-script-view';
          scriptInput.setAttribute('data-field-scene-id', scene.id);
          scriptInput.textContent = scene.scriptText || '';
          scriptField.appendChild(scriptLabel);
          scriptField.appendChild(scriptInput);
          item.appendChild(scriptField);

          var promptField = document.createElement('label');
          promptField.className = 'sv-editor-field';
          var promptLabel = document.createElement('span');
          promptLabel.className = 'sv-editor-label';
          promptLabel.textContent = i18nText('提示词', 'Prompt');
          var promptInput = document.createElement('textarea');
          promptInput.className = 'sv-editor-textarea';
          promptInput.setAttribute('data-field-scene-id', scene.id);
          promptInput.setAttribute('data-field', 'prompt');
          promptInput.value = scene.prompt || '';
          promptInput.addEventListener('click', function (event) {
            event.stopPropagation();
          });
          promptInput.addEventListener('input', function () {
            scene.prompt = promptInput.value;
            markEditorDirty();
          });
          promptField.appendChild(promptLabel);
          promptField.appendChild(promptInput);
          item.appendChild(promptField);
          item.addEventListener('click', function () {
            focusScene(scene.id);
          });

          fragment.appendChild(item);
        });
        editorList.appendChild(fragment);
        highlightActiveEditorItem();
      }
      function highlightActiveEditorItem() {
        if (!editorList) return;
        var itemList = Array.prototype.slice.call(editorList.querySelectorAll('[data-editor-scene-id]'));
        itemList.forEach(function (item) {
          if (item.getAttribute('data-editor-scene-id') === state.sceneId) item.classList.add('is-active');
          else item.classList.remove('is-active');
        });
      }
      function openEditor() {
        if (!hostCaps.canEditPanel) return;
        if (!editorOverlay) return;
        renderEditorList();
        applyEditorHeight(editorHeightVh);
        editorOverlay.classList.add('is-open');
        editorOverlay.setAttribute('aria-hidden', 'false');
        document.body.classList.add('sv-editor-open');
        isEditorOpen = true;
      }
      function closeEditor() {
        if (!editorOverlay) return;
        editorOverlay.classList.remove('is-open');
        editorOverlay.setAttribute('aria-hidden', 'true');
        document.body.classList.remove('sv-editor-open');
        isEditorOpen = false;
      }
      function saveEditor() {
        persistMetaToScript();
        clearEditorDirty();
        showSavedTip();
        if (window.parent && window.parent !== window) {
          window.parent.postMessage({ type: '__SVGVIDEO_META_UPDATED', meta: meta }, '*');
        }
      }
      function getTotalSteps() {
        return sceneModels.reduce(function (sum, scene) { return sum + Math.max(1, Number(scene.steps) || 1); }, 0);
      }
      function getSceneIndexById(sceneId) {
        for (var i = 0; i < sceneModels.length; i++) {
          if (sceneModels[i].id === sceneId) return i;
        }
        return -1;
      }
      function getSceneInitialStep(sceneId) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return 0;
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        return Math.max(0, maxSteps - 1);
      }
      function focusScene(sceneId) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return;
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        stopPlayback();
        window.__SVGVIDEO_SET_STATE(sceneId, 0, 1);
        if (maxSteps > 1) {
          setTimeout(function () {
            window.__SVGVIDEO_SET_STATE(sceneId, Math.max(0, maxSteps - 1), 1);
          }, 90);
        }
      }
      function getProgressPercent(sceneId, step) {
        var total = getTotalSteps();
        if (!total) return 0;
        var index = getSceneIndexById(sceneId);
        if (index < 0) return 0;
        var completed = 0;
        for (var i = 0; i < index; i++) completed += Math.max(1, Number(sceneModels[i].steps) || 1);
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        var localStep = Math.max(0, Math.min(maxSteps - 1, Number(step) || 0));
        return Math.max(0, Math.min(100, ((completed + localStep) / total) * 100));
      }
      function updateProgressUi(percent) {
        var pct = Math.max(0, Math.min(100, percent || 0));
        if (progressFill) progressFill.style.width = pct + '%';
        if (progressThumb) progressThumb.style.left = pct + '%';
      }
      function stopProgressAnimation() {
        if (progressRaf) {
          cancelAnimationFrame(progressRaf);
          progressRaf = null;
        }
      }
      function startProgressSegment(fromPercent, toPercent, durationMs) {
        stopProgressAnimation();
        var from = Math.max(0, Math.min(100, Number(fromPercent) || 0));
        var to = Math.max(0, Math.min(100, Number(toPercent) || 0));
        var duration = Math.max(1, Number(durationMs) || 1);
        if (duration <= 1 || to <= from) {
          updateProgressUi(to);
          return;
        }
        var startAt = performance.now();
        var tick = function (now) {
          if (!isPlaying) {
            stopProgressAnimation();
            return;
          }
          var elapsed = now - startAt;
          var ratio = Math.max(0, Math.min(1, elapsed / duration));
          var current = from + (to - from) * ratio;
          updateProgressUi(current);
          if (ratio < 1) {
            progressRaf = requestAnimationFrame(tick);
          } else {
            stopProgressAnimation();
          }
        };
        progressRaf = requestAnimationFrame(tick);
      }
      function getPlaybackSegment(sceneIndex, step) {
        var scene = sceneModels[sceneIndex];
        if (!scene) return null;
        var currentPercent = getProgressPercent(scene.id, step);
        var maxSteps = Math.max(1, Number(scene.steps) || 1);
        if (step < maxSteps - 1) {
          return {
            from: currentPercent,
            to: getProgressPercent(scene.id, step + 1),
            duration: STEP_INTERVAL_MS
          };
        }
        if (sceneIndex < sceneModels.length - 1) {
          var nextScene = sceneModels[sceneIndex + 1];
          var nextPercent = nextScene ? getProgressPercent(nextScene.id, 0) : currentPercent;
          return {
            from: currentPercent,
            to: nextPercent,
            duration: SCENE_FINISH_PAUSE_MS
          };
        }
        return {
          from: currentPercent,
          to: 100,
          duration: STEP_INTERVAL_MS
        };
      }
      function renderStatus() {
        if (!statusText) return;
        var done = sceneModels.filter(function (scene) { return scene.status === 'success'; }).length;
        var pending = sceneModels.filter(function (scene) { return scene.status === 'pending' || scene.status === 'generating'; }).length;
        var failed = sceneModels.filter(function (scene) { return scene.status === 'failed'; }).length;
        statusText.textContent = '已生成 ' + done + '/' + sceneModels.length + ' · 待生成 ' + pending + ' · 失败 ' + failed;
      }
      function updatePlayButton() {
        if (!playBtn) return;
        playBtn.innerHTML = isPlaying
          ? '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><rect x="6" y="5" width="4" height="14" rx="1"></rect><rect x="14" y="5" width="4" height="14" rx="1"></rect></svg>'
          : '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M7 5v14l11-7z"></path></svg>';
        playBtn.setAttribute('aria-label', isPlaying ? '暂停播放' : '播放分镜');
        playBtn.setAttribute('title', isPlaying ? '暂停播放' : '播放分镜');
      }
      function applyHostCaps() {
        if (hostCaps.canRetry) document.body.classList.add('sv-host-can-retry');
        else document.body.classList.remove('sv-host-can-retry');
        if (hostCaps.canEditPanel) document.body.classList.add('sv-host-can-edit-panel');
        else document.body.classList.remove('sv-host-can-edit-panel');
        if (hostCaps.theme === 'light') document.body.classList.add('sv-theme-light');
        else document.body.classList.remove('sv-theme-light');
      }
      function highlightActiveSceneButton() {
        sceneButtonList.forEach(function (button) {
          var targetId = button.getAttribute('data-panel-scene-id');
          if (targetId === state.sceneId) button.classList.add('is-active');
          else button.classList.remove('is-active');
        });
      }
      function stopPlayback() {
        if (playTimer) {
          clearTimeout(playTimer);
          playTimer = null;
        }
        stopProgressAnimation();
        isPlaying = false;
        updatePlayButton();
      }
      function startPlayback() {
        if (!sceneModels.length) return;
        stopPlayback();
        var sceneIndex = Math.max(0, getSceneIndexById(state.sceneId));
        var step = 0;
        var applyPlaybackState = function (direction) {
          var scene = sceneModels[sceneIndex];
          if (!scene) return false;
          window.__SVGVIDEO_SET_STATE(scene.id, step, direction);
          updateProgressUi(getProgressPercent(scene.id, step));
          var segment = getPlaybackSegment(sceneIndex, step);
          if (segment) startProgressSegment(segment.from, segment.to, segment.duration);
          return true;
        };
        var scheduleAdvance = function (delay) {
          playTimer = setTimeout(function () {
            var currentScene = sceneModels[sceneIndex];
            if (!currentScene) {
              stopPlayback();
              return;
            }
            var maxSteps = Math.max(1, Number(currentScene.steps) || 1);
            if (step < maxSteps - 1) {
              step += 1;
              applyPlaybackState(1);
              scheduleAdvance(STEP_INTERVAL_MS);
              return;
            }
            if (sceneIndex < sceneModels.length - 1) {
              playTimer = setTimeout(function () {
                sceneIndex += 1;
                step = 0;
                if (!applyPlaybackState(1)) {
                  stopPlayback();
                  return;
                }
                scheduleAdvance(STEP_INTERVAL_MS);
              }, SCENE_FINISH_PAUSE_MS);
              return;
            }
            stopPlayback();
          }, delay);
        };
        isPlaying = true;
        updatePlayButton();
        if (!applyPlaybackState(1)) {
          stopPlayback();
          return;
        }
        scheduleAdvance(STEP_INTERVAL_MS);
      }
      window.SceneLifecycle = {
        handlers: {},
        register: function (sceneId, handler) { this.handlers[sceneId] = handler || {}; }
      };

      (function () {
        var sceneDataJson = document.getElementById('__SVGVIDEO_SCENE_DATA__');
        var runtimeScenes = [];
        try {
          runtimeScenes = JSON.parse((sceneDataJson && sceneDataJson.textContent) || '[]');
        } catch (_e) {
          runtimeScenes = [];
        }
        runtimeScenes.forEach(function (scene) {
          if (!scene || typeof scene.id !== 'string') return;
          var js = typeof scene.js === 'string' ? scene.js.trim() : '';
          if (!js) return;
          try {
            var factory = new Function(js);
            factory.call(window);
          } catch (err) {
            console.error('[svg-video] scene runtime failed', scene.id, err);
          }
        });
      })();

      function applyStepVisibility(sceneEl) {
        var stepNodes = sceneEl.querySelectorAll('[data-step]');
        stepNodes.forEach(function (node) {
          var minStep = Number(node.getAttribute('data-step') || '0');
          var visible = state.step >= minStep;
          node.style.opacity = visible ? '1' : '0';
          node.style.visibility = visible ? 'visible' : 'hidden';
          node.style.pointerEvents = visible ? 'auto' : 'none';
          node.style.transform = visible ? 'translateY(0)' : 'translateY(8px)';
          node.style.filter = visible ? 'blur(0px)' : 'blur(4px)';
        });
      }
      function applySceneState() {
        var scenes = document.querySelectorAll('#stage > [data-scene-id]');
        var currentSceneEl = null;
        var previousSceneEl = null;
        scenes.forEach(function (sceneEl) {
          var sceneId = sceneEl.getAttribute('data-scene-id');
          if (sceneId === state.sceneId) currentSceneEl = sceneEl;
          if (sceneId === previousSceneId) previousSceneEl = sceneEl;
        });
        var direction = state.direction >= 0 ? 1 : -1;
        document.documentElement.style.setProperty('--scene-enter-offset', direction > 0 ? '56px' : '-56px');
        document.documentElement.style.setProperty('--scene-exit-offset', direction > 0 ? '-56px' : '56px');
        if (exitCleanupTimer) {
          clearTimeout(exitCleanupTimer);
          exitCleanupTimer = null;
        }
        scenes.forEach(function (sceneEl) {
          if (sceneEl !== currentSceneEl && sceneEl !== previousSceneEl) {
            sceneEl.classList.remove('scene-active');
            sceneEl.classList.remove('scene-exit');
          }
        });
        if (previousSceneEl && previousSceneEl !== currentSceneEl) {
          previousSceneEl.classList.remove('scene-active');
          previousSceneEl.classList.add('scene-exit');
        }
        if (currentSceneEl) {
          currentSceneEl.classList.remove('scene-exit');
          currentSceneEl.classList.add('scene-active');
          applyStepVisibility(currentSceneEl);
        }
        if (previousSceneEl && previousSceneEl !== currentSceneEl) {
          exitCleanupTimer = setTimeout(function () { previousSceneEl.classList.remove('scene-exit'); }, 620);
        }
        if (previousSceneId !== state.sceneId) {
          if (previousSceneId && window.SceneLifecycle.handlers[previousSceneId] && typeof window.SceneLifecycle.handlers[previousSceneId].leave === 'function') {
            try { window.SceneLifecycle.handlers[previousSceneId].leave(); } catch (e) {}
          }
          if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].enter === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].enter(); } catch (e) {}
          }
        }
        if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].step === 'function') {
          try { window.SceneLifecycle.handlers[state.sceneId].step(state.step); } catch (e) {}
        }
        previousSceneId = state.sceneId;
        highlightActiveSceneButton();
        highlightActiveEditorItem();
        updateProgressUi(getProgressPercent(state.sceneId, state.step));
      }
      window.__SVGVIDEO_SET_STATE = function (sceneId, step, direction) {
        if (typeof sceneId === 'string' && sceneId) {
          if (typeof direction === 'number' && Number.isFinite(direction)) {
            state.direction = direction >= 0 ? 1 : -1;
          } else {
            var nextIndex = getSceneIndexById(sceneId);
            var prevIndex = getSceneIndexById(state.sceneId);
            if (nextIndex !== -1 && prevIndex !== -1) state.direction = nextIndex >= prevIndex ? 1 : -1;
          }
          state.sceneId = sceneId;
        }
        if (typeof step === 'number' && Number.isFinite(step)) state.step = Math.max(0, Math.floor(step));
        applySceneState();
      };
      if (state.sceneId && getSceneIndexById(state.sceneId) === -1 && sceneModels.length) {
        state.sceneId = sceneModels[0].id;
      }
      if (playBtn) {
        playBtn.addEventListener('click', function () {
          if (isPlaying) stopPlayback();
          else startPlayback();
        });
      }
      if (expandBtn) {
        expandBtn.addEventListener('click', function () {
          if (isEditorOpen) closeEditor();
          else openEditor();
        });
      }
      if (editorCloseBtn) {
        editorCloseBtn.addEventListener('click', closeEditor);
      }
      if (editorBackdrop) {
        editorBackdrop.addEventListener('click', closeEditor);
      }
      if (editorSaveBtn) {
        editorSaveBtn.addEventListener('click', saveEditor);
      }
      if (editorResizeHandle && editorSheet) {
        editorResizeHandle.addEventListener('mousedown', function (event) {
          event.preventDefault();
          var startY = event.clientY;
          var startHeightPx = (window.innerHeight * editorHeightVh) / 100;
          var onMove = function (moveEvent) {
            var delta = startY - moveEvent.clientY;
            var nextHeightPx = startHeightPx + delta;
            var nextHeightVh = (nextHeightPx / Math.max(1, window.innerHeight)) * 100;
            applyEditorHeight(nextHeightVh);
          };
          var onUp = function () {
            window.removeEventListener('mousemove', onMove);
            window.removeEventListener('mouseup', onUp);
          };
          window.addEventListener('mousemove', onMove);
          window.addEventListener('mouseup', onUp);
        });
      }
      sceneButtonList.forEach(function (button) {
        button.addEventListener('click', function () {
          var sceneId = button.getAttribute('data-panel-scene-id');
          if (!sceneId) return;
          focusScene(sceneId);
        });
      });
      sceneRetryButtonList.forEach(function (button) {
        button.addEventListener('click', function (event) {
          event.preventDefault();
          event.stopPropagation();
          var sceneId = button.getAttribute('data-retry-scene-id');
          if (!sceneId) return;
          requestSceneRetry(sceneId);
        });
      });
      if (progressWrap) {
        progressWrap.addEventListener('click', function (event) {
          var rect = progressWrap.getBoundingClientRect();
          var pct = Math.max(0, Math.min(100, ((event.clientX - rect.left) / rect.width) * 100));
          var totalSteps = getTotalSteps();
          var targetStep = Math.round((pct / 100) * totalSteps);
          var accumulated = 0;
          for (var i = 0; i < sceneModels.length; i++) {
            var sceneSteps = Math.max(1, Number(sceneModels[i].steps) || 1);
            if (accumulated + sceneSteps > targetStep) {
              var localStep = Math.max(0, Math.min(sceneSteps - 1, targetStep - accumulated));
              stopPlayback();
              window.__SVGVIDEO_SET_STATE(sceneModels[i].id, localStep, 1);
              updateProgressUi(pct);
              return;
            }
            accumulated += sceneSteps;
          }
        });
      }
      window.addEventListener('message', function (event) {
        var data = event && event.data;
        if (!data || typeof data.type !== 'string') return;
        if (data.type === '__SVGVIDEO_SET_STATE') {
          window.__SVGVIDEO_SET_STATE(data.sceneId, data.step, data.direction);
          return;
        }
        if (data.type === '__SVGVIDEO_PLAY') {
          startPlayback();
          return;
        }
        if (data.type === '__SVGVIDEO_STOP') {
          stopPlayback();
          return;
        }
        if (data.type === '__SVGVIDEO_SET_HOST_CAPS') {
          hostCaps.canRetry = Boolean(data.canRetry);
          hostCaps.canEditPanel = Boolean(data.canEditPanel);
          hostCaps.locale = data.locale === 'en' ? 'en' : 'zh';
          hostCaps.theme = data.theme === 'light' ? 'light' : 'dark';
          applyI18nTexts();
          applyHostCaps();
          if (isEditorOpen) renderEditorList();
          return;
        }
        if (data.type === '__SVGVIDEO_SET_SCENE_STATUS') {
          var sceneId = typeof data.sceneId === 'string' ? data.sceneId : '';
          var status = typeof data.status === 'string' ? data.status : '';
          if (sceneId && status) {
            setSceneStatus(sceneId, status);
            if (isEditorOpen) renderEditorList();
          }
          return;
        }
        if (data.type === '__SVGVIDEO_SET_RECORDING') {
          if (data && data.active) {
            document.body.classList.add('sv-recording');
            // 如果指定了初始分镜，无过渡动画地跳转过去，避免录制开头残留旧分镜画面
            if (data.sceneId) {
              var noTransStyle = document.createElement('style');
              noTransStyle.id = 'sv-no-transition';
              noTransStyle.textContent = '.scene, [data-step] { transition: none !important; }';
              document.head.appendChild(noTransStyle);
              window.__SVGVIDEO_SET_STATE(data.sceneId, 0, 1);
              // 强制 reflow 后恢复过渡动画
              void document.body.offsetHeight;
              requestAnimationFrame(function () {
                var s = document.getElementById('sv-no-transition');
                if (s) s.remove();
              });
            }
          } else {
            document.body.classList.remove('sv-recording');
          }
          return;
        }
        if (data.type === '__SVGVIDEO_SET_META' && data.meta && typeof data.meta === 'object') {
          meta = data.meta;
          var freshScenes = Array.isArray(meta.scenes) ? meta.scenes : [];
          freshScenes.forEach(function (scene) {
            var idx = getSceneIndexById(scene.id);
            if (idx < 0) return;
            sceneModels[idx].prompt = typeof scene.prompt === 'string' ? scene.prompt : '';
            sceneModels[idx].scriptText = typeof scene.scriptText === 'string' ? scene.scriptText : '';
            sceneModels[idx].audioObjectKey = typeof scene.audioObjectKey === 'string' ? scene.audioObjectKey : '';
            sceneModels[idx].audioDurationMs = Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0;
            sceneModels[idx].voiceName = typeof scene.voiceName === 'string' ? scene.voiceName : '';
          });
          persistMetaToScript();
          if (isEditorOpen) renderEditorList();
        }
      });
      document.addEventListener('keydown', function (event) {
        if (event.key === 'Escape' && isEditorOpen) closeEditor();
      });
      window.__SVGVIDEO_PLAY = startPlayback;
      window.__SVGVIDEO_STOP = stopPlayback;
      window.__SVGVIDEO_OPEN_EDITOR = openEditor;
      window.__SVGVIDEO_CLOSE_EDITOR = closeEditor;
      applyEditorHeight(editorHeightVh);
      renderStatus();
      updatePlayButton();
      applyHostCaps();
      clearEditorDirty();
      applyI18nTexts();
      applySceneState();
      if (autoplayFromFirstScene && sceneModels.length) {
        state.sceneId = sceneModels[0].id;
        state.step = 0;
        state.direction = 1;
        applySceneState();
        startPlayback();
      }
    })();
  </script>
</body>
</html>29:T30fa4,<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>极简物理史：从万有引力到量子群星</title>
  <style>
    @import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700&display=swap');
    @font-face {
      font-family: "SVGVideoAlimamaShuHei";
      src:
        url("/fonts/AlimamaShuHeiTi-Bold.woff2") format("woff2"),
        url("/fonts/AlimamaShuHeiTi-Bold.woff") format("woff"),
        url("/fonts/AlimamaShuHeiTi-Bold.ttf") format("truetype"),
        local("Alimama ShuHeiTi Bold"),
        local("Alimama ShuHeiTi"),
        local("AlimamaShuHeiTi-Bold"),
        local("AlimamaShuHeiTi");
      font-display: swap;
      font-weight: 700;
      font-style: normal;
    }
    :root {
      color-scheme: dark;
      --bg: #202020;
      --fg: #e2e8f0;
      --muted: #94a3b8;
      --card: rgba(255, 255, 255, 0.05);
      --border: rgba(255, 255, 255, 0.12);
      --sv-editor-height: 50vh;
      --sv-font-display-cn: "Noto Serif SC", "STSong", "SimSun", Georgia, serif;
      --sv-font-body-cn: "Noto Serif SC", "STSong", "SimSun", Georgia, serif;
      --sv-font-mono: "SFMono-Regular", "JetBrains Mono", "Fira Code", "Courier New", monospace;
      --sv-stage-perspective: 900px;
        --sv-trans-enter-opacity: 0;
        --sv-trans-enter-transform: rotateY(90deg);
        --sv-trans-enter-filter: blur(6px);
        --sv-trans-active-opacity: 1;
        --sv-trans-active-transform: rotateY(0deg);
        --sv-trans-active-filter: blur(0px);
        --sv-trans-exit-opacity: 0;
        --sv-trans-exit-transform: rotateY(-90deg);
        --sv-trans-exit-filter: blur(4px);
        --sv-trans-duration: 0.65s;
        --sv-trans-ease: cubic-bezier(0.36, 0, 0.66, 1);
    }
    * { box-sizing: border-box; }
    html, body {
      margin: 0; width: 100%; height: 100%; overflow: hidden;
      background: var(--bg);
      color: var(--fg);
      font-family: var(--sv-font-body-cn);
    }
    #app { width: 100%; height: 100%; display: flex; flex-direction: column; }
    #viewport { position: relative; flex: 1; min-height: 0; overflow: hidden; }
    #stage {
      position: relative; width: 100%; height: 100%; overflow: hidden;
      perspective: var(--sv-stage-perspective, none);
      perspective-origin: 50% 50%;
    }
    .scene {
      position: absolute; inset: 0; overflow: hidden;
      backface-visibility: hidden;
      -webkit-backface-visibility: hidden;
      opacity: var(--sv-trans-enter-opacity, 0); pointer-events: none;
      transform: var(--sv-trans-enter-transform, translateX(var(--scene-enter-offset, 56px)) scale(0.96));
      filter: var(--sv-trans-enter-filter, blur(10px));
      transition: opacity var(--sv-trans-duration, .55s) var(--sv-trans-ease, cubic-bezier(.22,1,.36,1)), transform var(--sv-trans-duration, .55s) var(--sv-trans-ease, cubic-bezier(.22,1,.36,1)), filter var(--sv-trans-duration, .55s) ease;
      will-change: opacity, transform, filter;
      z-index: 1;
    }
    .scene.scene-active {
      opacity: var(--sv-trans-active-opacity, 1); pointer-events: auto;
      transform: var(--sv-trans-active-transform, translateX(0) scale(1));
      filter: var(--sv-trans-active-filter, blur(0px));
      z-index: 3;
    }
    .scene.scene-exit {
      opacity: var(--sv-trans-exit-opacity, 0); pointer-events: none;
      transform: var(--sv-trans-exit-transform, translateX(var(--scene-exit-offset, -56px)) scale(0.96));
      filter: var(--sv-trans-exit-filter, blur(10px));
      z-index: 2;
    }
    .scene-placeholder {
      height: 100%; border: 1px dashed var(--border); border-radius: 20px; background: var(--card);
      display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: var(--muted);
    }
    .sv-scene-root { width: 100%; height: 100%; position: relative; overflow: hidden; }
    .scene-placeholder-title { font-size: 28px; color: var(--fg); font-weight: 700; }
    [data-step] { transition: opacity .35s ease, transform .35s ease, filter .35s ease; }
    #sv-controls {
      background: rgba(19, 19, 19, 0.95);
      border-top: 1px solid rgba(255,255,255,0.08);
      padding: 8px 12px 10px;
      display: flex;
      flex-direction: column;
      gap: 8px;
      backdrop-filter: blur(8px);
      flex-shrink: 0;
    }
    .sv-progress-wrap {
      position: relative;
      height: 22px;
      display: flex;
      align-items: center;
      cursor: pointer;
    }
    .sv-progress-track {
      width: 100%;
      height: 4px;
      border-radius: 999px;
      background: rgba(120, 120, 120, 0.55);
      position: relative;
      overflow: hidden;
    }
    .sv-progress-fill {
      position: absolute;
      left: 0;
      top: 0;
      bottom: 0;
      width: 0%;
      border-radius: 999px;
      background: linear-gradient(90deg, #f97316, #fb923c);
      transition: width 220ms ease;
    }
    .sv-progress-thumb {
      position: absolute;
      top: 50%;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      background: #fff;
      transform: translate(-50%, -50%);
      box-shadow: 0 0 0 1px rgba(0,0,0,0.28);
      pointer-events: none;
    }
    .sv-toolbar {
      display: grid;
      grid-template-columns: 1fr auto 1fr;
      align-items: center;
      gap: 8px;
      min-height: 30px;
    }
    .sv-toolbar-left {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      min-width: 0;
    }
    .sv-toolbar-title {
      font-size: 11px;
      color: #a8b0bb;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-expand-btn {
      width: 20px;
      height: 20px;
      border: none;
      border-radius: 6px;
      background: rgba(255,255,255,0.08);
      color: #cbd5e1;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      flex: 0 0 auto;
      transition: background 140ms ease, color 140ms ease, transform 120ms ease;
    }
    .sv-expand-btn:hover {
      background: rgba(255,255,255,0.15);
      color: #f8fafc;
    }
    .sv-expand-btn:active {
      transform: scale(0.94);
    }
    body:not(.sv-host-can-edit-panel) .sv-expand-btn {
      display: none;
    }
    .sv-play-btn {
      width: 28px;
      height: 28px;
      border: none;
      border-radius: 999px;
      color: #fff;
      background: #f97316;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: transform 120ms ease, background 160ms ease;
    }
    .sv-play-btn:hover { background: #fb923c; }
    .sv-play-btn:active { transform: scale(0.94); }
    .sv-play-btn:disabled { opacity: 0.45; cursor: not-allowed; }
    .sv-status {
      text-align: right;
      font-size: 11px;
      color: #8f98a5;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-scene-grid {
      display: flex;
      align-items: stretch;
      gap: 6px;
      flex-wrap: nowrap;
      overflow: hidden;
    }
    .scene-chip {
      position: relative;
      width: 100%;
      border: none;
      border-bottom: 2px solid transparent;
      border-radius: 8px;
      background: rgba(255,255,255,0.06);
      color: #a3a3a3;
      padding: 7px 6px;
      text-align: center;
      font-size: 11px;
      line-height: 1.1;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      cursor: pointer;
      transition: transform 140ms ease, color 160ms ease, background 160ms ease, border-color 160ms ease;
    }
    .scene-chip-label {
      display: block;
      width: 100%;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .scene-chip-wrap {
      position: relative;
      flex: 1 1 0;
      min-width: 0;
    }
    .scene-chip-retry {
      position: absolute;
      top: 50%;
      right: 4px;
      transform: translateY(-50%);
      width: 24px;
      height: 24px;
      border: none;
      border-radius: 999px;
      background: #f97316;
      color: #fff;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
      opacity: 0;
      pointer-events: none;
      transition: opacity 160ms ease;
      cursor: pointer;
    }
    body.sv-host-can-retry .scene-chip-wrap:hover .scene-chip-retry {
      opacity: 1;
      pointer-events: auto;
    }
    .scene-chip-retry:disabled {
      opacity: 1;
      pointer-events: none;
      background: #f97316;
    }
    .scene-chip-retry-icon {
      width: 18px;
      height: 18px;
      display: block;
    }
    .scene-chip-retry-spinner {
      width: 14px;
      height: 14px;
      aspect-ratio: 1 / 1;
      border: 2px solid #ffffff;
      border-top-color: transparent;
      border-radius: 999px;
      box-sizing: border-box;
      animation: sceneChipSpin 1s linear infinite;
      display: block;
      flex: 0 0 auto;
    }
    @keyframes sceneChipSpin {
      from { transform: rotate(0deg); }
      to { transform: rotate(360deg); }
    }
    .scene-chip:hover { transform: scale(1.02); }
    .scene-chip.is-active {
      color: #fb923c;
      border-bottom-color: #fb923c;
      background: linear-gradient(135deg, rgba(249,115,22,0.2), rgba(168,85,247,0.2));
    }
    .scene-chip.is-failed {
      color: #fca5a5;
      border-bottom-color: rgba(239,68,68,0.95);
      background: rgba(239,68,68,0.12);
    }
    .scene-chip.is-generating {
      color: #fcd34d;
      background: rgba(245,158,11,0.11);
    }
    .sv-editor-overlay {
      position: relative;
      width: 100%;
      height: 0;
      z-index: 40;
      pointer-events: none;
      overflow: hidden;
      transition: height 260ms cubic-bezier(.22,1,.36,1);
    }
    .sv-editor-backdrop {
      position: absolute;
      inset: auto 0 0 0;
      height: 100%;
      background: rgba(0, 0, 0, 0.45);
      opacity: 0;
      transition: opacity 220ms ease;
    }
    .sv-editor-sheet {
      position: absolute;
      left: 0;
      right: 0;
      bottom: 0;
      height: 100%;
      background: rgba(16, 16, 16, 0.96);
      border-top: 1px solid rgba(255,255,255,0.12);
      box-shadow: 0 -14px 30px rgba(0,0,0,0.45);
      transform: translateY(102%);
      transition: transform 260ms cubic-bezier(.22,1,.36,1);
      display: flex;
      flex-direction: column;
    }
    .sv-editor-overlay.is-open {
      pointer-events: auto;
      height: var(--sv-editor-height, 50vh);
    }
    .sv-editor-overlay.is-open .sv-editor-backdrop {
      opacity: 1;
    }
    .sv-editor-overlay.is-open .sv-editor-sheet {
      transform: translateY(0);
    }
    .sv-editor-resize-handle {
      width: 100%;
      height: 14px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: ns-resize;
      flex: 0 0 auto;
      touch-action: none;
    }
    .sv-editor-resize-handle::before {
      content: "";
      width: 52px;
      height: 4px;
      border-radius: 999px;
      background: rgba(148, 163, 184, 0.7);
    }
    .sv-editor-header {
      padding: 10px 12px;
      border-bottom: 1px solid rgba(255,255,255,0.1);
      display: grid;
      grid-template-columns: 1fr auto;
      align-items: center;
      gap: 8px;
    }
    .sv-editor-header-title {
      color: #f1f5f9;
      font-size: 13px;
      font-weight: 600;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-editor-actions {
      display: inline-flex;
      align-items: center;
      gap: 6px;
    }
    .sv-editor-btn {
      border: none;
      border-radius: 8px;
      cursor: pointer;
      font-size: 12px;
      line-height: 1;
      padding: 7px 10px;
      color: #e2e8f0;
      background: rgba(255,255,255,0.1);
      transition: background 120ms ease;
    }
    .sv-editor-btn:hover {
      background: rgba(255,255,255,0.18);
    }
    .sv-editor-btn.is-primary {
      color: #fff;
      background: #f97316;
    }
    .sv-editor-btn.is-primary:hover {
      background: #fb923c;
    }
    .sv-editor-list {
      flex: 1;
      min-height: 0;
      overflow: auto;
      padding: 10px 12px 14px;
      display: grid;
      gap: 10px;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      align-items: start;
      align-content: start;
    }
    .sv-editor-item {
      border: 1px solid rgba(255,255,255,0.12);
      border-radius: 10px;
      background: rgba(255,255,255,0.03);
      padding: 10px;
      display: grid;
      grid-template-rows: auto auto auto;
      gap: 10px;
      align-content: start;
      cursor: pointer;
    }
    .sv-editor-item.is-active {
      border-color: rgba(249,115,22,0.65);
      box-shadow: inset 0 0 0 1px rgba(249,115,22,0.28);
    }
    .sv-editor-item-head {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 8px;
      min-height: 30px;
    }
    .sv-editor-item-title {
      border: none;
      border-radius: 8px;
      color: #fb923c;
      background: rgba(255,255,255,0.08);
      font-size: 12px;
      font-weight: 600;
      padding: 6px 8px;
      cursor: pointer;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      text-align: left;
    }
    .sv-editor-item-title:hover {
      background: rgba(255,255,255,0.14);
    }
    .sv-editor-status {
      color: #94a3b8;
      font-size: 11px;
      white-space: nowrap;
    }
    .sv-editor-status-wrap {
      display: inline-flex;
      align-items: center;
      gap: 6px;
    }
    .scene-chip-retry.sv-editor-retry {
      position: static;
      transform: none;
      opacity: 1;
      pointer-events: auto;
      width: 24px;
      height: 24px;
      flex: 0 0 auto;
    }
    .sv-editor-field {
      display: grid;
      gap: 6px;
    }
    .sv-editor-label {
      color: #a3a3a3;
      font-size: 11px;
      font-weight: 700;
    }
    .sv-editor-textarea {
      width: 100%;
      border-radius: 8px;
      border: 1px solid rgba(255,255,255,0.14);
      background: rgba(0,0,0,0.24);
      color: #f1f5f9;
      font-size: 12px;
      line-height: 1.45;
      padding: 8px 9px;
      resize: none;
      min-height: 110px;
      height: 110px;
    }
    .sv-editor-textarea[data-field="scriptText"] {
      min-height: 84px;
    }
    .sv-editor-textarea:focus {
      outline: none;
      border-color: rgba(249,115,22,0.7);
      box-shadow: 0 0 0 2px rgba(249,115,22,0.18);
    }
    body.sv-theme-light .sv-editor-textarea {
      border-color: rgba(15,23,42,0.18);
      background: rgba(248,250,252,0.92);
      color: #0f172a;
    }
    body.sv-theme-light .sv-editor-textarea:focus {
      border-color: rgba(249,115,22,0.72);
      box-shadow: 0 0 0 2px rgba(249,115,22,0.2);
    }
    .sv-editor-script-view {
      width: 100%;
      color: #e2e8f0;
      font-size: 12px;
      line-height: 1.5;
      white-space: pre-wrap;
      word-break: break-word;
      min-height: 84px;
      max-height: 84px;
      overflow: auto;
    }
    .sv-editor-save-tip {
      color: #fbbf24;
      font-size: 11px;
      opacity: 0;
      transition: opacity 140ms ease;
      justify-self: end;
    }
    .sv-editor-save-tip.is-visible {
      opacity: 1;
    }
    body.sv-theme-light .sv-editor-backdrop {
      background: rgba(15, 23, 42, 0.2);
    }
    body.sv-theme-light .sv-editor-sheet {
      background: rgba(255, 255, 255, 0.98);
      border-top-color: rgba(15, 23, 42, 0.12);
      box-shadow: 0 -14px 30px rgba(15, 23, 42, 0.16);
    }
    body.sv-theme-light .sv-editor-header {
      border-bottom-color: rgba(15, 23, 42, 0.1);
    }
    body.sv-theme-light .sv-editor-header-title {
      color: #0f172a;
    }
    body.sv-theme-light .sv-editor-btn {
      color: #334155;
      background: rgba(15, 23, 42, 0.08);
    }
    body.sv-theme-light .sv-editor-btn:hover {
      background: rgba(15, 23, 42, 0.14);
    }
    body.sv-theme-light .sv-editor-btn.is-primary {
      color: #ffffff;
      background: #f97316;
    }
    body.sv-theme-light .sv-editor-btn.is-primary:hover {
      background: #fb923c;
    }
    body.sv-theme-light .sv-editor-item {
      border-color: rgba(15, 23, 42, 0.12);
      background: rgba(248, 250, 252, 0.95);
    }
    body.sv-theme-light .sv-editor-item.is-active {
      border-color: rgba(249,115,22,0.72);
      box-shadow: inset 0 0 0 1px rgba(249,115,22,0.3);
    }
    body.sv-theme-light .sv-editor-item-title {
      color: #ea580c;
      background: rgba(249, 115, 22, 0.12);
    }
    body.sv-theme-light .sv-editor-item-title:hover {
      background: rgba(249, 115, 22, 0.18);
    }
    body.sv-theme-light .sv-editor-status {
      color: #64748b;
    }
    body.sv-theme-light .sv-editor-label {
      color: #475569;
    }
    body.sv-theme-light .sv-editor-script-view {
      color: #334155;
    }
    body.sv-theme-light .sv-editor-save-tip {
      color: #c2410c;
    }
    body.sv-editor-open #viewport {
      flex: 1 1 calc(100vh - var(--sv-editor-height, 50vh));
      min-height: 0;
    }
    body.sv-editor-open #sv-controls {
      display: none;
    }
    body.sv-recording .sv-toolbar,
    body.sv-recording .sv-scene-grid {
      display: none;
    }
    body.sv-recording #sv-controls {
      display: none;
    }
    body.sv-theme-light .sv-editor-list,
    body.sv-theme-light .sv-editor-script-view,
    body.sv-theme-light .sv-editor-textarea {
      scrollbar-color: rgba(148, 163, 184, 0.85) rgba(226, 232, 240, 0.85);
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar {
      width: 10px;
      height: 10px;
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-track,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-track,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-track {
      background: rgba(226, 232, 240, 0.85);
      border-radius: 999px;
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-thumb,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-thumb,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-thumb {
      background: rgba(148, 163, 184, 0.85);
      border-radius: 999px;
      border: 2px solid rgba(226, 232, 240, 0.85);
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-thumb:hover,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-thumb:hover,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-thumb:hover {
      background: rgba(100, 116, 139, 0.95);
    }
/* scene-01 */
.sv-scene-root-scene-01 .s-scene-01-root{
  --paper-white: #FAFAFA;
  --ink-black: #111111;
  --sub-text: rgba(17,17,17,0.65);
  --rule-thin: 1px;
  --rule-thick: 3px;
  
  position: relative;
  width: 100%;
  height: 100%;
  background-color: var(--paper-white);
  color: var(--ink-black);
  font-family: var(--sv-font-body-cn);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 40px 60px;
  box-sizing: border-box;
}/* 报纸质感氛围层 */
.sv-scene-root-scene-01 .paper-overlay{
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3BaseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E");
  opacity: 0.04;
  pointer-events: none;
  z-index: 10;
}/* 报头 */
.sv-scene-root-scene-01 .masthead{
  text-align: center;
  border-bottom: var(--rule-thick) solid var(--ink-black);
  padding-bottom: 15px;
  margin-bottom: 30px;
}.sv-scene-root-scene-01 .masthead-top{
  font-size: 14px;
  letter-spacing: 0.3em;
  font-weight: 700;
}.sv-scene-root-scene-01 .masthead-main{
  font-family: var(--sv-font-display-cn);
  font-size: 84px;
  font-weight: 900;
  line-height: 1;
  margin: 10px 0;
  letter-spacing: -0.02em;
}.sv-scene-root-scene-01 .masthead-bottom{
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  font-weight: 700;
  border-top: var(--rule-thin) solid var(--ink-black);
  padding-top: 5px;
}/* 主体内容布局 */
.sv-scene-root-scene-01 .newspaper-content{
  flex: 1;
  display: grid;
  grid-template-columns: 1fr 1.5fr;
  gap: 40px;
  align-items: center;
}/* Step 0: 核心视觉 */
.sv-scene-root-scene-01 .hero-visual{
  opacity: 0;
  transform: scale(0.95);
  transition: all 0.8s cubic-bezier(0.22, 1, 0.36, 1);
  text-align: center;
}.sv-scene-root-scene-01 .step-ge-0 .hero-visual{
  opacity: 1;
  transform: scale(1);
}.sv-scene-root-scene-01 .astrolabe-svg{
  width: 320px;
  height: 320px;
}.sv-scene-root-scene-01 .compass-path{
  animation: pulse-line 4s ease-in-out infinite;
}@keyframes pulse-line{
  0%, 100% { stroke-width: 3; }
  50% { stroke-width: 4; }
}.sv-scene-root-scene-01 .caption-text{
  font-size: 12px;
  font-weight: 700;
  margin-top: 10px;
  letter-spacing: 0.1em;
}/* Step 1 & 2: 标题与边框 */
.sv-scene-root-scene-01 .article-header{
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
}.sv-scene-root-scene-01 .side-rules{
  position: absolute;
  left: -20px;
  top: 0; bottom: 0;
  width: 4px;
  border-left: 1px solid var(--ink-black);
  border-right: 3px solid var(--ink-black);
  opacity: 0;
  transition: opacity 0.6s ease;
}.sv-scene-root-scene-01 .step-ge-1 .side-rules{
  opacity: 1;
}.sv-scene-root-scene-01 .headline-container{
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.7s cubic-bezier(0.16, 1, 0.3, 1);
}.sv-scene-root-scene-01 .step-ge-2 .headline-container{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-01 .kicker{
  font-size: 18px;
  font-weight: 700;
  margin-bottom: 5px;
  letter-spacing: 0.15em;
}.sv-scene-root-scene-01 .main-headline{
  font-family: var(--sv-font-display-cn);
  font-size: 82px;
  font-weight: 900;
  margin: 0 0 15px 0;
  line-height: 1.1;
  border-bottom: var(--rule-thin) solid var(--ink-black);
  padding-bottom: 10px;
}.sv-scene-root-scene-01 .sub-headline{
  font-size: 20px;
  color: var(--sub-text);
  font-style: italic;
  max-width: 80%;
}/* 装饰背景线 */
.sv-scene-root-scene-01 .bottom-rule{
  height: 6px;
  border-top: 1px solid var(--ink-black);
  border-bottom: 4px solid var(--ink-black);
  margin-top: 20px;
}.sv-scene-root-scene-01 .columns-grid{
  position: absolute;
  bottom: 60px;
  right: 60px;
  width: 300px;
  height: 150px;
  display: flex;
  gap: 15px;
  opacity: 0.1;
  pointer-events: none;
}.sv-scene-root-scene-01 .column{
  flex: 1;
  border-left: 0.5px solid var(--ink-black);
  background: repeating-linear-gradient(0deg, var(--ink-black) 0, var(--ink-black) 1px, transparent 1px, transparent 12px);
}

/* scene-02 */
.sv-scene-root-scene-02 .s-scene-02-root{
  --ink: #111111;
  --paper: #FAFAFA;
  --card-bg: #F0F0F0;
  position: relative;
  width: 100%;
  height: 100%;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sv-font-body-cn);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}.sv-scene-root-scene-02 .paper-overlay{
  position: absolute; inset: 0; pointer-events: none; z-index: 100;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3BaseFrequency='0.7' numOctaves='3'/%3E%3C/svg%3E");
  opacity: 0.03;
}.sv-scene-root-scene-02 .main-layout{
  flex: 1;
  display: grid;
  grid-template-columns: 1fr 1.2fr;
  padding: 80px 100px;
  gap: 60px;
  align-items: center;
  z-index: 10;
}/* Step 0: 苹果视觉 */
.sv-scene-root-scene-02 .apple-stage{
  position: relative;
  text-align: center;
  opacity: 0;
  transform: translateY(20px);
  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
}.sv-scene-root-scene-02 .step-ge-0 .apple-stage{ opacity: 1; transform: translateY(0); }.sv-scene-root-scene-02 .apple-icon{
  position: relative;
  display: inline-block;
  width: 180px;
  height: 180px;
  margin-bottom: 20px;
}.sv-scene-root-scene-02 .apple-svg{ width: 100%; height: 100%; filter: drop-shadow(2px 2px 0px rgba(0,0,0,0.1)); }.sv-scene-root-scene-02 .horizon-line{
  width: 240px;
  height: 2px;
  background: var(--ink);
  margin: 0 auto;
  transform: scaleX(0);
  transition: transform 0.6s 0.3s ease-out;
}.sv-scene-root-scene-02 .step-ge-0 .horizon-line{ transform: scaleX(1); }.sv-scene-root-scene-02 .apple-caption{
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.2em;
  margin-top: 15px;
}/* Step 3: 重力感应线 */
.sv-scene-root-scene-02 .gravity-lines{
  position: absolute;
  bottom: -40px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 20px;
  opacity: 0;
}.sv-scene-root-scene-02 .step-ge-3 .gravity-lines{ opacity: 1; }.sv-scene-root-scene-02 .g-line{
  width: 1px;
  height: 60px;
  background: linear-gradient(to bottom, var(--ink), transparent);
  animation: fall-line 1.2s infinite ease-in;
}.sv-scene-root-scene-02 .g-line:nth-child(2){ animation-delay: 0.4s; }.sv-scene-root-scene-02 .g-line:nth-child(3){ animation-delay: 0.8s; }@keyframes fall-line{
  0% { transform: scaleY(0); transform-origin: top; opacity: 0; }
  50% { transform: scaleY(1); opacity: 1; }
  100% { transform: scaleY(1) translateY(40px); transform-origin: bottom; opacity: 0; }
}/* Step 1: 公式卡片 */
.sv-scene-root-scene-02 .parchment-card{
  background: var(--card-bg);
  border: 1px solid var(--ink);
  padding: 40px;
  box-shadow: 8px 8px 0px var(--ink);
  opacity: 0;
  transform: translateX(40px);
  transition: all 0.7s cubic-bezier(0.16, 1, 0.3, 1);
}.sv-scene-root-scene-02 .step-ge-1 .parchment-card{ opacity: 1; transform: translateX(0); }.sv-scene-root-scene-02 .card-header{
  font-size: 12px;
  font-weight: 900;
  border-bottom: 1px solid var(--ink);
  padding-bottom: 8px;
  margin-bottom: 30px;
  letter-spacing: 0.1em;
}.sv-scene-root-scene-02 .formula-area{
  text-align: center;
}.sv-scene-root-scene-02 .handwritten-svg{
  width: 100%;
  height: auto;
  font-family: var(--sv-font-mono);
  font-style: italic;
  fill: var(--ink);
  font-weight: 700;
}.sv-scene-root-scene-02 .f-ma{ font-size: 42px; }.sv-scene-root-scene-02 .f-gravity{ font-size: 24px; }.sv-scene-root-scene-02 .divider-diamond{
  margin: 20px 0;
  font-size: 12px;
  opacity: 0.3;
}.sv-scene-root-scene-02 .law-title{
  font-family: var(--sv-font-display-cn);
  font-size: 18px;
  margin-bottom: 10px;
  text-decoration: underline;
}.sv-scene-root-scene-02 .card-footer{
  margin-top: 30px;
  font-size: 10px;
  text-align: right;
  opacity: 0.6;
}/* Step 2: 机械宇宙背景 */
.sv-scene-root-scene-02 .mechanical-universe{
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1.5s ease;
  pointer-events: none;
}.sv-scene-root-scene-02 .step-ge-2 .mechanical-universe{ opacity: 0.08; }.sv-scene-root-scene-02 .gear-container{
  position: absolute;
  right: -50px;
  top: -50px;
}.sv-scene-root-scene-02 .gear{
  animation: rotate-gear 20s linear infinite;
}.sv-scene-root-scene-02 .gear-large{ width: 400px; }.sv-scene-root-scene-02 .gear-small{
  width: 200px;
  position: absolute;
  top: 250px;
  right: 280px;
  animation-direction: reverse;
  animation-duration: 10s;
}@keyframes rotate-gear{
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}.sv-scene-root-scene-02 .bottom-rules{
  padding: 0 60px 40px;
}.sv-scene-root-scene-02 .thick-rule{ height: 4px; background: var(--ink); margin-bottom: 4px; }.sv-scene-root-scene-02 .thin-rule{ height: 1px; background: var(--ink); }

/* scene-03 */
.sv-scene-root-scene-03 .s-scene-03-root{
  --paper-white: #FAFAFA;
  --ink-black: #111111;
  --ink-muted: rgba(17,17,17,0.6);
  position: relative;
  width: 100%;
  height: 100%;
  background: var(--paper-white);
  color: var(--ink-black);
  font-family: var(--sv-font-body-cn);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 40px 60px;
}/* 报头样式 */
.sv-scene-root-scene-03 .masthead{
  width: 100%;
  text-align: center;
  margin-bottom: 40px;
}.sv-scene-root-scene-03 .masthead-tag{
  font-family: var(--sv-font-mono);
  font-size: 14px;
  letter-spacing: 0.3em;
  font-weight: 700;
}.sv-scene-root-scene-03 .masthead-line-thick{ height: 4px; background: var(--ink-black); margin: 8px 0 4px; }.sv-scene-root-scene-03 .masthead-line-thin{ height: 1px; background: var(--ink-black); }.sv-scene-root-scene-03 .masthead-title{
  font-family: var(--sv-font-display-cn);
  font-size: 56px;
  font-weight: 900;
  margin: 10px 0;
  letter-spacing: -0.02em;
}/* Step 0: 电磁波纹 */
.sv-scene-root-scene-03 .ripple-container{
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 600px; height: 600px;
  opacity: 0;
  transition: opacity 1s ease;
}.sv-scene-root-scene-03 .step-ge-0 .ripple-container{ opacity: 0.15; }.sv-scene-root-scene-03 .ripple{
  position: absolute;
  top: 50%; left: 50%;
  border: 1px solid var(--ink-black);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  animation: ripple-out 4s infinite linear;
}.sv-scene-root-scene-03 .ripple:nth-child(2){ animation-delay: 1.3s; }.sv-scene-root-scene-03 .ripple:nth-child(3){ animation-delay: 2.6s; }@keyframes ripple-out{
  0% { width: 0; height: 0; opacity: 1; }
  100% { width: 100%; height: 100%; opacity: 0; }
}/* Step 1: 方程卡片 */
.sv-scene-root-scene-03 .equations-grid{
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
  margin-top: 20px;
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1);
  z-index: 10;
}.sv-scene-root-scene-03 .step-ge-1 .equations-grid{ opacity: 1; transform: translateY(0); }.sv-scene-root-scene-03 .equation-card{
  background: white;
  border: 1px solid var(--ink-black);
  padding: 20px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  box-shadow: 4px 4px 0px var(--ink-black);
}.sv-scene-root-scene-03 .eq-label{
  font-size: 10px;
  font-weight: 900;
  color: white;
  background: var(--ink-black);
  padding: 2px 8px;
  margin-bottom: 15px;
  letter-spacing: 0.1em;
}.sv-scene-root-scene-03 .eq-svg-wrap{
  width: 100%;
  height: 80px;
  display: flex;
  align-items: center;
  justify-content: center;
}.sv-scene-root-scene-03 .eq-svg-wrap svg{
  width: 90%;
  height: auto;
  fill: var(--ink-black);
  font-family: var(--sv-font-mono);
  font-weight: bold;
  font-size: 20px;
}.sv-scene-root-scene-03 .eq-desc{
  font-size: 14px;
  font-weight: 700;
  margin-top: 15px;
  border-top: 0.5px solid var(--ink-muted);
  padding-top: 10px;
  width: 100%;
}/* Step 2: 光速线 */
.sv-scene-root-scene-03 .light-streaks{
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
}.sv-scene-root-scene-03 .step-ge-2 .light-streaks{ opacity: 1; }.sv-scene-root-scene-03 .streak{
  position: absolute;
  height: 1px;
  background: var(--ink-black);
  opacity: 0.2;
  animation: streak-move 1.5s infinite linear;
}.sv-scene-root-scene-03 .streak:nth-child(1){ top: 20%; width: 200px; left: -250px; animation-delay: 0.1s; }.sv-scene-root-scene-03 .streak:nth-child(2){ top: 45%; width: 400px; left: -450px; animation-delay: 0.4s; }.sv-scene-root-scene-03 .streak:nth-child(3){ top: 70%; width: 300px; left: -350px; animation-delay: 0.7s; }.sv-scene-root-scene-03 .streak:nth-child(4){ top: 15%; width: 150px; left: -200px; animation-delay: 1.1s; }.sv-scene-root-scene-03 .streak:nth-child(5){ top: 85%; width: 500px; left: -550px; animation-delay: 0.2s; }@keyframes streak-move{
  0% { transform: translateX(0); }
  100% { transform: translateX(calc(100vw + 600px)); }
}/* 页脚 */
.sv-scene-root-scene-03 .newspaper-footer{
  margin-top: auto;
  padding-bottom: 10px;
}.sv-scene-root-scene-03 .footer-black-bar{
  background: var(--ink-black);
  color: var(--paper-white);
  padding: 8px 20px;
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
}

/* scene-04 */
.sv-scene-root-scene-04 .s-scene-04-root{
  --paper-white: #F8F8F8;
  --ink-black: #111111;
  --ink-muted: rgba(17,17,17,0.6);
  position: relative;
  width: 100%;
  height: 100%;
  background: var(--paper-white);
  color: var(--ink-black);
  font-family: var(--sv-font-body-cn);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 30px 50px;
}/* 故障感背景 */
.sv-scene-root-scene-04 .glitch-bg{
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(0deg, rgba(0,0,0,0.03) 0px, rgba(0,0,0,0.03) 1px, transparent 1px, transparent 2px);
  pointer-events: none;
  z-index: 1;
}.sv-scene-root-scene-04 .glitch-line{
  position: absolute;
  width: 100%;
  height: 2px;
  background: rgba(17,17,17,0.08);
  animation: glitch-slide 4s infinite linear;
}.sv-scene-root-scene-04 .glitch-line:nth-child(2){ top: 30%; animation-delay: -1.2s; }.sv-scene-root-scene-04 .glitch-line:nth-child(3){ top: 70%; animation-delay: -2.8s; }@keyframes glitch-slide{
  0% { transform: translateY(-100vh); }
  100% { transform: translateY(100vh); }
}/* 报纸排版 */
.sv-scene-root-scene-04 .newspaper-masthead{
  text-align: center;
  z-index: 10;
  margin-bottom: 20px;
}.sv-scene-root-scene-04 .masthead-top{
  font-family: var(--sv-font-mono);
  font-size: 14px;
  letter-spacing: 0.5em;
  font-weight: 700;
}.sv-scene-root-scene-04 .masthead-main{
  font-family: 'Libre Baskerville', serif;
  font-size: 32px;
  font-weight: 900;
  border-top: 3px solid var(--ink-black);
  border-bottom: 1px solid var(--ink-black);
  padding: 8px 0;
  margin-top: 10px;
}/* 核心中心叹号 */
.sv-scene-root-scene-04 .center-impact{
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  z-index: 5;
}.sv-scene-root-scene-04 .exclamation-mark{
  font-family: var(--sv-font-display-cn);
  font-size: 320px;
  font-weight: 900;
  line-height: 1;
  animation: impact-shake 0.5s cubic-bezier(.36,.07,.19,.97) both;
}@keyframes impact-shake{
  10%, 90% { transform: translate3d(-2px, 0, 0); }
  20%, 80% { transform: translate3d(4px, 0, 0); }
  30%, 50%, 70% { transform: translate3d(-8px, 0, 0); }
  40%, 60% { transform: translate3d(8px, 0, 0); }
}/* Step 0: 乌云 */
.sv-scene-root-scene-04 .clouds-layer{
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.8s ease;
  pointer-events: none;
  z-index: 8;
}.sv-scene-root-scene-04 .step-ge-0 .clouds-layer{ opacity: 1; }.sv-scene-root-scene-04 .cloud{
  position: absolute;
  width: 260px;
  top: 45%;
  filter: drop-shadow(0 10px 20px rgba(0,0,0,0.1));
}.sv-scene-root-scene-04 .left-cloud{ left: 10%; transform: rotate(-5deg); }.sv-scene-root-scene-04 .right-cloud{ right: 10%; transform: rotate(5deg); }.sv-scene-root-scene-04 .cloud-path{ fill: #ddd; stroke: var(--ink-black); stroke-width: 2; }.sv-scene-root-scene-04 .lightning{
  fill: none; stroke: var(--ink-black); stroke-width: 3;
  stroke-dasharray: 50; stroke-dashoffset: 50;
  animation: strike 2s infinite steps(1);
}@keyframes strike{
  0%, 100% { stroke-dashoffset: 50; }
  10%, 15% { stroke-dashoffset: 0; }
}.sv-scene-root-scene-04 .cloud-label{
  text-align: center;
  font-family: var(--sv-font-mono);
  font-size: 14px;
  font-weight: 900;
  margin-top: -10px;
  background: var(--ink-black);
  color: white;
  padding: 2px 8px;
}/* Step 1: 危机文字 */
.sv-scene-root-scene-04 .crisis-text-wrap{
  position: absolute;
  bottom: 15%;
  width: 100%;
  text-align: center;
  opacity: 0;
  z-index: 20;
}.sv-scene-root-scene-04 .step-ge-1 .crisis-text-wrap{
  opacity: 1;
  animation: fragment-shake 0.4s infinite alternate;
}.sv-scene-root-scene-04 .crisis-main-title{
  font-family: var(--sv-font-display-cn);
  font-size: 84px;
  font-weight: 900;
  margin: 0;
  letter-spacing: -2px;
  text-transform: uppercase;
}.sv-scene-root-scene-04 .crisis-sub-title{
  font-family: 'Libre Baskerville', serif;
  font-size: 20px;
  letter-spacing: 0.3em;
  margin-top: -10px;
}@keyframes fragment-shake{
  from { transform: translateX(-1px) skewX(0deg); filter: contrast(1.2); }
  to { transform: translateX(1px) skewX(0.5deg); filter: contrast(1.5); }
}/* 页脚 */
.sv-scene-root-scene-04 .newspaper-footer{
  margin-top: auto;
  z-index: 10;
}.sv-scene-root-scene-04 .footer-line{ height: 1px; background: var(--ink-black); width: 100%; }.sv-scene-root-scene-04 .footer-content{
  display: flex;
  justify-content: space-between;
  padding: 10px 0;
  font-family: var(--sv-font-mono);
  font-size: 12px;
  font-weight: 700;
}

/* scene-05 */
.sv-scene-root-scene-05 .s-scene-05-root{
  --paper-bg: #F8F8F8;
  --ink-black: #111111;
  --ink-muted: rgba(17,17,17,0.6);
  position: relative;
  width: 100%;
  height: 100%;
  background: var(--paper-bg);
  color: var(--ink-black);
  font-family: var(--sv-font-body-cn);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 40px 60px;
}.sv-scene-root-scene-05 .paper-overlay{
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E");
  opacity: 0.05;
  pointer-events: none;
}/* 报纸风格排版 */
.sv-scene-root-scene-05 .newspaper-header{
  text-align: center;
  z-index: 10;
  margin-bottom: 20px;
}.sv-scene-root-scene-05 .header-meta{
  font-family: var(--sv-font-mono);
  font-size: 14px;
  letter-spacing: 0.3em;
  font-weight: 700;
}.sv-scene-root-scene-05 .header-title{
  font-family: 'Libre Baskerville', serif;
  font-size: 36px;
  font-weight: 900;
  margin: 10px 0;
}.sv-scene-root-scene-05 .header-line-thick{
  height: 4px;
  background: var(--ink-black);
  width: 100%;
}/* 引力场 */
.sv-scene-root-scene-05 .gravity-field-container{
  flex: 1;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}.sv-scene-root-scene-05 .gravity-grid{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
}.sv-scene-root-scene-05 .grid-lines-path{
  fill: none;
  stroke: var(--ink-black);
  stroke-width: 0.5;
  stroke-opacity: 0.15;
}/* 球体与公式 */
.sv-scene-root-scene-05 .massive-sphere{
  position: relative;
  width: 180px;
  height: 180px;
  background: var(--ink-black);
  border-radius: 50%;
  z-index: 5;
  opacity: 0;
  transform: scale(0.5);
  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
}.sv-scene-root-scene-05 .step-ge-0 .massive-sphere{
  opacity: 1;
  transform: scale(1);
}.sv-scene-root-scene-05 .sphere-glow{
  position: absolute;
  inset: -20px;
  border: 1px solid var(--ink-black);
  border-radius: 50%;
  animation: sphere-pulse 4s infinite ease-in-out;
}@keyframes sphere-pulse{
  0%, 100% { transform: scale(1); opacity: 0.2; }
  50% { transform: scale(1.15); opacity: 0.5; }
}.sv-scene-root-scene-05 .sphere-label{
  position: absolute;
  bottom: -30px;
  width: 100%;
  text-align: center;
  font-family: var(--sv-font-mono);
  font-size: 12px;
  font-weight: 900;
}.sv-scene-root-scene-05 .formula-wrap{
  position: absolute;
  z-index: 10;
  text-align: center;
  opacity: 0;
  transform: perspective(1000px) rotateY(-90deg);
  transition: all 0.8s cubic-bezier(0.23, 1, 0.32, 1);
}.sv-scene-root-scene-05 .step-ge-1 .formula-wrap{
  opacity: 1;
  transform: perspective(1000px) rotateY(0deg);
}.sv-scene-root-scene-05 .formula-text{
  font-family: var(--sv-font-display-cn);
  font-size: 120px;
  font-weight: 900;
  margin: 0;
  line-height: 1;
  background: var(--ink-black);
  color: var(--paper-bg);
  padding: 0 20px;
}.sv-scene-root-scene-05 .formula-sub{
  font-family: var(--sv-font-mono);
  font-size: 14px;
  letter-spacing: 0.5em;
  margin-top: 10px;
  font-weight: 700;
}.sv-scene-root-scene-05 .formula-shimmer{
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);
  transform: translateX(-100%);
}.sv-scene-root-scene-05 .step-ge-1 .formula-shimmer{
  animation: shimmer-swipe 1.5s 0.8s forwards;
}@keyframes shimmer-swipe{
  100% { transform: translateX(100%); }
}/* 时间注脚 */
.sv-scene-root-scene-05 .time-relativity-tag{
  position: absolute;
  right: 5%;
  bottom: 25%;
  display: flex;
  align-items: center;
  opacity: 0;
  transform: translateX(30px);
  transition: all 0.6s ease-out;
}.sv-scene-root-scene-05 .step-ge-2 .time-relativity-tag{
  opacity: 1;
  transform: translateX(0);
}.sv-scene-root-scene-05 .tag-line{
  width: 40px;
  height: 2px;
  background: var(--ink-black);
  margin-right: 15px;
}.sv-scene-root-scene-05 .tag-title{
  display: block;
  font-family: var(--sv-font-mono);
  font-size: 16px;
  font-weight: 900;
}.sv-scene-root-scene-05 .tag-desc{
  font-size: 14px;
  color: var(--ink-muted);
}/* 页脚 */
.sv-scene-root-scene-05 .newspaper-footer{
  margin-top: auto;
  padding-top: 20px;
}.sv-scene-root-scene-05 .footer-line-thin{
  height: 1px;
  background: var(--ink-black);
  width: 100%;
  margin-bottom: 10px;
}.sv-scene-root-scene-05 .footer-flex{
  display: flex;
  justify-content: space-between;
  font-family: var(--sv-font-mono);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
}

/* scene-06 */
.sv-scene-root-scene-06 .s-scene-06-root{
  --paper-white: #F8F8F8;
  --ink-black: #111111;
  --ink-soft: rgba(17, 17, 17, 0.6);
  position: relative;
  width: 100%;
  height: 100%;
  background: var(--paper-white);
  color: var(--ink-black);
  font-family: var(--sv-font-body-cn);
  padding: 40px 60px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}.sv-scene-root-scene-06 .paper-texture{
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
  pointer-events: none;
}/* 报头设计 */
.sv-scene-root-scene-06 .masthead{ margin-bottom: 30px; text-align: center; }.sv-scene-root-scene-06 .masthead-meta{ font-family: var(--sv-font-mono); font-size: 14px; letter-spacing: 0.3em; font-weight: 700; }.sv-scene-root-scene-06 .masthead-title{ font-family: 'Libre Baskerville', serif; font-size: 42px; font-weight: 900; margin: 10px 0; }.sv-scene-root-scene-06 .double-border{ height: 6px; border-top: 3px solid var(--ink-black); border-bottom: 1px solid var(--ink-black); margin-top: 5px; }/* 视口布局 */
.sv-scene-root-scene-06 .quantum-viewport{
  flex: 1;
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: 40px;
  z-index: 2;
}/* 原子模型 */
.sv-scene-root-scene-06 .atom-container{ position: relative; display: flex; flex-direction: column; align-items: center; opacity: 0; transform: scale(0.9); transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1); }.sv-scene-root-scene-06 .step-ge-0 .atom-container{ opacity: 1; transform: scale(1); }.sv-scene-root-scene-06 .atom-core{ position: relative; width: 240px; height: 240px; display: flex; align-items: center; justify-content: center; }.sv-scene-root-scene-06 .nucleus{ width: 30px; height: 30px; background: var(--ink-black); border-radius: 50%; box-shadow: 0 0 15px rgba(0,0,0,0.2); z-index: 10; }.sv-scene-root-scene-06 .electron-cloud{
  position: absolute;
  inset: 20%;
  border: 1px dashed var(--ink-black);
  border-radius: 50%;
  animation: rotate-fast 1.5s linear infinite;
  opacity: 0.3;
}.sv-scene-root-scene-06 .orbit-ring{
  position: absolute;
  width: 100%;
  height: 40%;
  border: 1px solid var(--ink-black);
  border-radius: 50%;
  transform: rotate(var(--rot));
  animation: spin-orbit 4s linear infinite;
}@keyframes spin-orbit{ from { transform: rotate(var(--rot)) rotateY(0deg); } to { transform: rotate(var(--rot)) rotateY(360deg); } }@keyframes rotate-fast{ from { transform: rotate(0deg); } to { transform: rotate(360deg); } }/* 概率波 */
.sv-scene-root-scene-06 .wave-container{ position: relative; height: 200px; border-left: 2px solid var(--ink-black); padding-left: 20px; }.sv-scene-root-scene-06 .wave-path{ fill: none; stroke: var(--ink-black); stroke-width: 2; transition: stroke 0.3s; }.sv-scene-root-scene-06 .step-ge-1 .wave-path{ animation: wave-jitter 0.1s infinite; }/* 波粒二象性标题 */
.sv-scene-root-scene-06 .duality-hero{
  position: absolute;
  top: 55%; left: 50%;
  transform: translate(-50%, -50%) scale(2);
  opacity: 0;
  z-index: 100;
  text-align: center;
  pointer-events: none;
  transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}.sv-scene-root-scene-06 .step-ge-2 .duality-hero{ opacity: 1; transform: translate(-50%, -50%) scale(1); }.sv-scene-root-scene-06 .duality-bg-bar{ position: absolute; inset: -10px -40px; background: var(--ink-black); z-index: -1; transform: skewX(-15deg); }.sv-scene-root-scene-06 .duality-text{ font-family: var(--sv-font-display-cn); font-size: 84px; color: var(--paper-white); margin: 0; line-height: 1; }.sv-scene-root-scene-06 .duality-sub{ font-family: var(--sv-font-mono); color: var(--paper-white); letter-spacing: 0.4em; font-size: 16px; margin-top: 10px; }/* 量子点位背景 */
.sv-scene-root-scene-06 .quantum-grid-bg{
  position: absolute;
  inset: 0;
  z-index: 1;
  opacity: 0;
  transition: opacity 1s ease;
}.sv-scene-root-scene-06 .step-ge-3 .quantum-grid-bg{ opacity: 0.4; }.sv-scene-root-scene-06 .label-tag{
  font-family: var(--sv-font-mono); font-size: 12px; font-weight: 700;
  margin-top: 20px; text-transform: uppercase;
  padding: 4px 8px; border: 1px solid var(--ink-black);
}.sv-scene-root-scene-06 .wave-label{ opacity: 0; transition: opacity 0.5s; }.sv-scene-root-scene-06 .step-ge-1 .wave-label{ opacity: 1; }/* 页脚 */
.sv-scene-root-scene-06 .newspaper-footer{ margin-top: auto; }.sv-scene-root-scene-06 .single-line{ height: 1px; background: var(--ink-black); margin-bottom: 10px; }.sv-scene-root-scene-06 .footer-info{ display: flex; justify-content: space-between; font-family: var(--sv-font-mono); font-size: 12px; font-weight: 700; }

/* scene-07 */
.sv-scene-root-scene-07 .s-scene-07-root{
  --paper-white: #FAFAFA;
  --ink-black: #111111;
  --ink-soft: rgba(17, 17, 17, 0.6);
  position: relative;
  width: 100%;
  height: 100%;
  background: var(--paper-white);
  color: var(--ink-black);
  font-family: var(--sv-font-body-cn);
  padding: 40px 60px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}.sv-scene-root-scene-07 .paper-texture{
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E");
  pointer-events: none;
  z-index: 5;
}/* 报头设计 */
.sv-scene-root-scene-07 .masthead{ text-align: center; margin-bottom: 20px; z-index: 10; }.sv-scene-root-scene-07 .masthead-meta{ font-family: var(--sv-font-mono); font-size: 14px; letter-spacing: 0.3em; font-weight: 700; }.sv-scene-root-scene-07 .masthead-title{ font-family: 'Libre Baskerville', serif; font-size: 36px; font-weight: 900; margin: 8px 0; letter-spacing: -0.02em; }.sv-scene-root-scene-07 .double-border{ height: 5px; border-top: 3px solid var(--ink-black); border-bottom: 1px solid var(--ink-black); }/* 视口与分形背景 */
.sv-scene-root-scene-07 .theory-viewport{
  position: relative;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}.sv-scene-root-scene-07 .fractal-origin{
  position: absolute;
  width: 80vh;
  height: 80vh;
  opacity: 0.8;
}.sv-scene-root-scene-07 .fractal-svg{ width: 100%; height: 100%; animation: slow-rotate 60s linear infinite; }@keyframes slow-rotate{ from { transform: rotate(0deg); } to { transform: rotate(360deg); } }/* 四大作用力球体 */
.sv-scene-root-scene-07 .force-sphere{
  position: absolute;
  width: 120px;
  display: flex;
  flex-direction: column;
  align-items: center;
  transition: all 1.2s cubic-bezier(0.34, 1.56, 0.64, 1);
  z-index: 20;
}.sv-scene-root-scene-07 .sphere-core{
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--ink-black);
  margin-bottom: 10px;
  box-shadow: 0 0 20px rgba(0,0,0,0.1);
}.sv-scene-root-scene-07 .force-label{
  font-family: var(--sv-font-mono);
  font-size: 12px;
  font-weight: 700;
  padding: 2px 6px;
  border: 1px solid var(--ink-black);
  white-space: nowrap;
}/* 初始位置 */
.sv-scene-root-scene-07 .strong-force{ top: 10%; left: 10%; transform: translate(-50%, -50%); }.sv-scene-root-scene-07 .weak-force{ top: 10%; right: 10%; transform: translate(50%, -50%); }.sv-scene-root-scene-07 .em-force{ bottom: 10%; left: 10%; transform: translate(-50%, 50%); }.sv-scene-root-scene-07 .gravity-force{ bottom: 10%; right: 10%; transform: translate(50%, 50%); }/* Step 1: 融合 */
.sv-scene-root-scene-07 .step-ge-1 .force-sphere{
  top: 50%; left: 50%;
  transform: translate(-50%, -50%) scale(0);
  opacity: 0;
}.sv-scene-root-scene-07 .unified-ring-container{
  position: absolute;
  width: 400px;
  height: 400px;
  opacity: 0;
  transform: scale(0.5);
  transition: all 1s cubic-bezier(0.16, 1, 0.3, 1);
}.sv-scene-root-scene-07 .step-ge-1 .unified-ring-container{ opacity: 1; transform: scale(1); }.sv-scene-root-scene-07 .unified-ring{
  position: absolute;
  inset: 0;
  border: 8px double var(--ink-black);
  border-radius: 50%;
  animation: spin-ring 10s linear infinite;
}.sv-scene-root-scene-07 .unified-ring-glow{
  position: absolute;
  inset: -20px;
  border: 1px dashed var(--ink-black);
  border-radius: 50%;
  opacity: 0.3;
  animation: spin-ring 15s linear infinite reverse;
}@keyframes spin-ring{ from { transform: rotate(0deg); } to { transform: rotate(360deg); } }.sv-scene-root-scene-07 #particle-system-07{
  position: absolute;
  inset: -100px;
  pointer-events: none;
}/* Step 2: 核心标题 */
.sv-scene-root-scene-07 .final-title-box{
  position: relative;
  z-index: 100;
  text-align: center;
  background: var(--paper-white);
  padding: 20px 40px;
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.8s ease-out;
}.sv-scene-root-scene-07 .step-ge-2 .final-title-box{ opacity: 1; transform: translateY(0); }.sv-scene-root-scene-07 .main-theory-title{
  font-family: var(--sv-font-display-cn);
  font-size: 84px;
  font-weight: 900;
  margin: 10px 0;
  line-height: 1;
}.sv-scene-root-scene-07 .sub-theory-title{
  font-family: var(--sv-font-mono);
  font-size: 18px;
  letter-spacing: 0.4em;
  font-weight: 400;
}.sv-scene-root-scene-07 .title-line-top, .sv-scene-root-scene-07 .title-line-bottom{ height: 4px; background: var(--ink-black); width: 100%; }/* 页脚与修饰 */
.sv-scene-root-scene-07 .newspaper-footer{ margin-top: auto; padding-top: 20px; }.sv-scene-root-scene-07 .footer-line{ height: 1px; background: var(--ink-black); margin-bottom: 8px; }.sv-scene-root-scene-07 .footer-flex{ display: flex; justify-content: space-between; font-family: var(--sv-font-mono); font-size: 11px; font-weight: 700; text-transform: uppercase; }.sv-scene-root-scene-07 .ambient-text{
  position: absolute;
  bottom: 15%;
  right: -5%;
  font-family: var(--sv-font-display-cn);
  font-size: 180px;
  color: rgba(17,17,17,0.03);
  font-weight: 900;
  z-index: 1;
  pointer-events: none;
  animation: ambient-float 20s ease-in-out infinite alternate;
}@keyframes ambient-float{ from { transform: translateX(0); } to { transform: translateX(-50px); } }

/* scene-08 */
.sv-scene-root-scene-08 .s-scene-08-root{
  --paper-white: #FAFAFA;
  --ink-black: #111111;
  position: relative;
  width: 100%;
  height: 100%;
  background: var(--paper-white);
  color: var(--ink-black);
  font-family: var(--sv-font-body-cn);
  padding: 40px 60px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}.sv-scene-root-scene-08 .paper-texture{
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
  pointer-events: none;
  z-index: 100;
}/* 报头样式 */
.sv-scene-root-scene-08 .masthead{ text-align: center; margin-bottom: 20px; z-index: 10; }.sv-scene-root-scene-08 .masthead-meta{ font-family: var(--sv-font-mono); font-size: 14px; letter-spacing: 0.3em; font-weight: 700; }.sv-scene-root-scene-08 .masthead-title{ font-family: 'Libre Baskerville', serif; font-size: 32px; font-weight: 900; margin: 8px 0; letter-spacing: -0.01em; }.sv-scene-root-scene-08 .double-border{ height: 5px; border-top: 3px solid var(--ink-black); border-bottom: 1px solid var(--ink-black); }/* 视口构图 */
.sv-scene-root-scene-08 .perspective-viewport{
  position: relative;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  perspective: 1000px;
}.sv-scene-root-scene-08 .starfield{
  position: absolute;
  inset: 0;
  opacity: 0.15;
}/* 金色轨道（在黑白报纸风中表现为极黑的高对比线） */
.sv-scene-root-scene-08 .golden-track-container{
  position: absolute;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  transform: rotateX(60deg);
  transform-origin: bottom;
  opacity: 0.8;
}.sv-scene-root-scene-08 .track-svg{
  width: 400px;
  height: 100%;
}.sv-scene-root-scene-08 .track-line{
  fill: none;
  stroke: var(--ink-black);
  stroke-dasharray: 1000;
  stroke-dashoffset: 1000;
  animation: draw-track 4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}.sv-scene-root-scene-08 .main-track{ stroke-width: 4; }.sv-scene-root-scene-08 .side-track{ stroke-width: 1; opacity: 0.3; }@keyframes draw-track{ to { stroke-dashoffset: 0; } }/* Step 0: 核心文字 */
.sv-scene-root-scene-08 .final-message{
  position: relative;
  z-index: 50;
  text-align: center;
  opacity: 0;
  transform: translateY(20px);
  transition: all 0.8s cubic-bezier(0.22, 1, 0.36, 1) 0.3s;
}.sv-scene-root-scene-08 .step-ge-0 .final-message{ opacity: 1; transform: translateY(0); }.sv-scene-root-scene-08 .kicker{
  font-family: var(--sv-font-mono);
  font-size: 16px;
  letter-spacing: 0.5em;
  margin-bottom: 16px;
  opacity: 0.6;
}.sv-scene-root-scene-08 .hero-text{
  font-family: var(--sv-font-display-cn);
  font-size: 64px;
  font-weight: 900;
  line-height: 1.2;
  margin: 0 0 10px 0;
}.sv-scene-root-scene-08 .sub-hero-text{
  font-family: 'Libre Baskerville', serif;
  font-size: 20px;
  letter-spacing: 0.3em;
  opacity: 0.8;
}.sv-scene-root-scene-08 .message-decoration{
  margin-top: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 15px;
}.sv-scene-root-scene-08 .message-decoration .dot{ width: 6px; height: 6px; background: var(--ink-black); }.sv-scene-root-scene-08 .message-decoration .line{ width: 100px; height: 1px; background: var(--ink-black); opacity: 0.3; }/* Step 1: 冲刺与变白 */
.sv-scene-root-scene-08 .flash-overlay{
  position: absolute;
  inset: 0;
  background: #FFFFFF;
  z-index: 200;
  opacity: 0;
  pointer-events: none;
  transition: opacity 1.2s cubic-bezier(0.7, 0, 0.3, 1);
}.sv-scene-root-scene-08 .step-ge-1 .flash-overlay{ opacity: 1; }/* 动画影响 */
.sv-scene-root-scene-08 .step-ge-1 .perspective-viewport{
  transform: scale(2) translateZ(500px);
  transition: transform 1.5s cubic-bezier(0.7, 0, 0.3, 1);
}/* 页脚 */
.sv-scene-root-scene-08 .newspaper-footer{ margin-top: auto; padding-top: 20px; }.sv-scene-root-scene-08 .footer-line{ height: 1px; background: var(--ink-black); margin-bottom: 8px; }.sv-scene-root-scene-08 .footer-flex{ display: flex; justify-content: space-between; font-family: var(--sv-font-mono); font-size: 12px; font-weight: 700; }.sv-scene-root-scene-08 .ambient-word{
  position: absolute;
  bottom: 10%;
  left: -2%;
  font-size: 15vw;
  font-family: var(--sv-font-display-cn);
  font-weight: 900;
  color: rgba(17,17,17,0.03);
  pointer-events: none;
  animation: slide-bg 30s linear infinite;
}@keyframes slide-bg{ from { transform: translateX(0); } to { transform: translateX(100px); } }
  </style>
</head>
<body data-orientation="landscape">
  <div id="app">
    <div id="viewport">
      <div id="stage">

<section class="scene" data-framework-scene-id="scene-01" data-scene-id="scene-01">
  <div class="sv-scene-root sv-scene-root-scene-01" data-scene-root-id="scene-01">
<div class='s-scene-01-root' data-scene-root-id='scene-01'>
  <div class='paper-background'></div>
  <div class='paper-overlay'></div>

  <!-- 报头区域 -->
  <header class='masthead'>
    <div class='masthead-top'>ESTABLISHED 17TH CENTURY / ISSUE NO. 001</div>
    <div class='masthead-main'>SCIENTIFIC INQUIRY</div>
    <div class='masthead-bottom'>
      <span>SPECIAL EDITION: THE HISTORY OF PHYSICS</span>
      <span>PRICE: PRICELESS WISDOM</span>
    </div>
  </header>

  <main class='newspaper-content'>
    <!-- Step 0: 核心视觉 - 金色圆规与星图 (在黑白报纸中处理为高对比度黑白矢量) -->
    <div class='hero-visual' data-step='0'>
      <div class='visual-container'>
        <svg viewBox='0 0 200 200' class='astrolabe-svg'>
          <circle cx='100' cy='100' r='80' stroke='#111' stroke-width='0.5' fill='none' stroke-dasharray='4 2' />
          <path d='M100 20 L100 180 M20 100 L180 100' stroke='#111' stroke-width='0.5' />
          <path class='compass-path' d='M100 40 L140 160 M100 40 L60 160' stroke='#111' stroke-width='3' fill='none' stroke-linecap='round' />
          <circle cx='100' cy='40' r='5' fill='#111' />
          <path d='M50 100 Q100 150 150 100' stroke='#111' stroke-width='1' fill='none' />
        </svg>
        <div class='caption-text'>FIG 1.1: ARCHETYPE OF UNIVERSAL ORDER</div>
      </div>
    </div>

    <!-- Step 1 & 2: 标题与装饰性边框 -->
    <div class='article-header'>
      <div class='side-rules' data-step='1'></div>
      <div class='headline-container' data-step='2'>
        <h2 class='kicker'>THE GREAT HUMAN JOURNEY</h2>
        <h1 class='main-headline'>物理学发展史</h1>
        <div class='sub-headline'>FROM STARGAZING TO QUANTUM MECHANICS: A MILLENNIAL QUEST</div>
      </div>
    </div>

    <!-- 报纸分栏背景装饰 (无文字，仅线条感) -->
    <div class='columns-grid'>
      <div class='column'></div>
      <div class='column'></div>
      <div class='column'></div>
    </div>
  </main>

  <div class='bottom-rule'></div>
</div>
  </div>
</section>

<section class="scene" data-framework-scene-id="scene-02" data-scene-id="scene-02">
  <div class="sv-scene-root sv-scene-root-scene-02" data-scene-root-id="scene-02">
<div class='s-scene-02-root' data-scene-root-id='scene-02'>
  <div class='paper-overlay'></div>

  <!-- 背景：机械宇宙氛围层 (Step 2 激活) -->
  <div class='mechanical-universe' data-step='2'>
    <div class='gear-container'>
      <svg viewBox='0 0 400 400' class='gear gear-large'>
        <path d='M200 150 L210 130 L230 135 L235 155 L255 160 L270 145 L285 155 L275 175 L285 195 L305 200 L305 220 L285 225 L275 245 L285 265 L270 275 L255 260 L235 265 L230 285 L210 290 L200 270 L180 270 L170 290 L150 285 L145 265 L125 260 L110 275 L95 265 L105 245 L95 225 L75 220 L75 200 L95 195 L105 175 L95 155 L110 145 L125 160 L145 155 L150 135 L170 130 L180 150 Z' fill='none' stroke='#111' stroke-width='1' />
        <circle cx='200' cy='210' r='30' fill='none' stroke='#111' stroke-width='0.5' />
      </svg>
      <svg viewBox='0 0 200 200' class='gear gear-small'>
        <path d='M100 70 L108 55 L120 58 L122 72 L135 75 L145 65 L155 72 L148 85 L155 98 L168 102 L168 115 L155 118 L148 132 L155 145 L145 152 L135 142 L122 145 L120 160 L108 162 L100 148 L90 148 L82 162 L70 160 L68 145 L55 142 L45 152 L35 145 L42 132 L35 118 L22 115 L22 102 L35 98 L42 85 L35 72 L45 65 L55 75 L68 72 L70 58 L82 55 L90 70 Z' fill='none' stroke='#111' stroke-width='1' />
      </svg>
    </div>
    <div class='constellation-lines'></div>
  </div>

  <div class='main-layout'>
    <!-- 左侧：苹果视觉区 -->
    <div class='visual-side'>
      <div class='apple-stage' data-step='0'>
        <div class='apple-icon'>
          <svg viewBox='0 0 100 100' class='apple-svg'>
            <path class='apple-body' d='M50 30 C30 30 20 45 20 65 C20 85 35 95 50 95 C65 95 80 85 80 65 C80 45 70 30 50 30 Z' fill='#111' />
            <path class='apple-stem' d='M50 30 Q55 15 65 10' fill='none' stroke='#111' stroke-width='4' stroke-linecap='round' />
            <path class='apple-leaf' d='M50 30 Q40 20 35 30 Q40 35 50 30' fill='#111' />
          </svg>
          <div class='gravity-lines' data-step='3'>
            <span class='g-line'></span>
            <span class='g-line'></span>
            <span class='g-line'></span>
          </div>
        </div>
        <div class='horizon-line'></div>
        <div class='apple-caption'>ISAAC NEWTON / 1687</div>
      </div>
    </div>

    <!-- 右侧：复古公式卡片 -->
    <div class='content-side'>
      <div class='parchment-card' data-step='1'>
        <div class='card-header'>PRINCIPIA MATHEMATICA</div>
        <div class='formula-area'>
          <div class='formula-row formula-main'>
            <svg viewBox='0 0 200 60' class='handwritten-svg'>
              <text x='50%' y='45' text-anchor='middle' class='f-ma'>F = ma</text>
            </svg>
          </div>
          <div class='divider-diamond'>◆</div>
          <div class='formula-row formula-law'>
            <div class='law-title'>万有引力定律</div>
            <svg viewBox='0 0 300 80' class='handwritten-svg'>
              <text x='50%' y='50' text-anchor='middle' class='f-gravity'>F = G (m₁m₂ / r²)</text>
            </svg>
          </div>
        </div>
        <div class='card-footer'>UNIVERSAL ORDER</div>
      </div>
    </div>
  </div>

  <!-- 底部装饰线 -->
  <div class='bottom-rules'>
    <div class='thick-rule'></div>
    <div class='thin-rule'></div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-framework-scene-id="scene-03" data-scene-id="scene-03">
  <div class="sv-scene-root sv-scene-root-scene-03" data-scene-root-id="scene-03">
<div class='s-scene-03-root' data-scene-root-id='scene-03'>
  <!-- 报纸报头装饰 -->
  <div class='masthead'>
    <div class='masthead-inner'>
      <span class='masthead-tag'>SCIENTIFIC REVOLUTION</span>
      <div class='masthead-line-thick'></div>
      <div class='masthead-title'>THE ELECTROMAGNETIC ERA</div>
      <div class='masthead-line-thin'></div>
    </div>
  </div>

  <!-- 背景氛围：电磁纹理与光速线 (Step 0 & Step 2) -->
  <div class='ambient-layer'>
    <div class='ripple-container' data-step='0'>
      <div class='ripple'></div>
      <div class='ripple'></div>
      <div class='ripple'></div>
    </div>
    <div class='light-streaks' data-step='2'>
      <div class='streak'></div>
      <div class='streak'></div>
      <div class='streak'></div>
      <div class='streak'></div>
      <div class='streak'></div>
    </div>
  </div>

  <!-- 核心内容区：麦克斯韦方程组 -->
  <div class='equations-grid' data-step='1'>
    <div class='equation-card'>
      <div class='eq-label'>GAUSS'S LAW</div>
      <div class='eq-svg-wrap'>
        <svg viewBox='0 0 160 60'><text x='50%' y='40' text-anchor='middle'>∇·E = ρ/ε₀</text></svg>
      </div>
      <div class='eq-desc'>高斯电场定律</div>
    </div>
    <div class='equation-card'>
      <div class='eq-label'>GAUSS'S MAGNETISM</div>
      <div class='eq-svg-wrap'>
        <svg viewBox='0 0 160 60'><text x='50%' y='40' text-anchor='middle'>∇·B = 0</text></svg>
      </div>
      <div class='eq-desc'>高斯磁场定律</div>
    </div>
    <div class='equation-card'>
      <div class='eq-label'>FARADAY'S LAW</div>
      <div class='eq-svg-wrap'>
        <svg viewBox='0 0 160 60'><text x='50%' y='40' text-anchor='middle'>∇×E = -∂B/∂t</text></svg>
      </div>
      <div class='eq-desc'>法拉第电磁感应</div>
    </div>
    <div class='equation-card'>
      <div class='eq-label'>AMPÈRE-MAXWELL</div>
      <div class='eq-svg-wrap'>
        <svg viewBox='0 0 160 60'><text x='50%' y='40' text-anchor='middle'>∇×B = μ₀(J+ε₀∂E/∂t)</text></svg>
      </div>
      <div class='eq-desc'>安培-麦克斯韦定律</div>
    </div>
  </div>

  <!-- 底部页脚 -->
  <div class='newspaper-footer'>
    <div class='footer-black-bar'>
      <span>JAMES CLERK MAXWELL / 1865</span>
      <span>UNIFYING ELECTRICITY, MAGNETISM, AND LIGHT</span>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-framework-scene-id="scene-04" data-scene-id="scene-04">
  <div class="sv-scene-root sv-scene-root-scene-04" data-scene-root-id="scene-04">
<div class='s-scene-04-root' data-scene-root-id='scene-04'>
  <!-- 背景氛围：数字故障感纹理 -->
  <div class='glitch-bg'>
    <div class='glitch-line'></div>
    <div class='glitch-line'></div>
    <div class='glitch-line'></div>
  </div>

  <!-- 报纸报头 -->
  <div class='newspaper-masthead'>
    <div class='masthead-top'>THE SCIENTIFIC TIMES</div>
    <div class='masthead-main'>SPECIAL EDITION: THE END OF PHYSICS?</div>
    <div class='masthead-divider'></div>
  </div>

  <!-- 核心视觉：黑色叹号 -->
  <div class='center-impact'>
    <div class='exclamation-mark'>!</div>
  </div>

  <!-- Step 0: 乌云与闪电 -->
  <div class='clouds-layer' data-step='0'>
    <div class='cloud left-cloud'>
      <svg viewBox='0 0 200 120'>
        <path class='cloud-path' d='M50,100 C20,100 20,70 40,60 C30,30 70,20 90,40 C110,10 160,20 160,50 C190,50 190,90 160,100 Z' />
        <path class='lightning' d='M100,80 L80,110 L110,110 L90,140' />
      </svg>
      <div class='cloud-label'>ETHER DRIFT</div>
    </div>
    <div class='cloud right-cloud'>
      <svg viewBox='0 0 200 120'>
        <path class='cloud-path' d='M50,100 C20,100 20,70 40,60 C30,30 70,20 90,40 C110,10 160,20 160,50 C190,50 190,90 160,100 Z' />
        <path class='lightning' d='M100,80 L80,110 L110,110 L90,140' />
      </svg>
      <div class='cloud-label'>BLACKBODY RADIATION</div>
    </div>
  </div>

  <!-- Step 1: 碎裂文字 -->
  <div class='crisis-text-wrap' data-step='1'>
    <h1 class='crisis-main-title'>经典物理学的危机</h1>
    <div class='crisis-sub-title'>THE CRISIS OF CLASSICAL PHYSICS</div>
  </div>

  <!-- 报纸页脚 -->
  <div class='newspaper-footer'>
    <div class='footer-line'></div>
    <div class='footer-content'>
      <span>LATE 19TH CENTURY</span>
      <span>LORD KELVIN'S "TWO CLOUDS"</span>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-framework-scene-id="scene-05" data-scene-id="scene-05">
  <div class="sv-scene-root sv-scene-root-scene-05" data-scene-root-id="scene-05">
<div class='s-scene-05-root' data-scene-root-id='scene-05'>
  <!-- 背景：报纸质感与静态网格 -->
  <div class='paper-overlay'></div>
  
  <!-- 报头 -->
  <div class='newspaper-header'>
    <div class='header-meta'>PHYSICS REVOLUTION / 1905</div>
    <div class='header-title'>THE ANNUS MIRABILIS</div>
    <div class='header-line-thick'></div>
  </div>

  <!-- 核心视觉：引力场网格 -->
  <div class='gravity-field-container'>
    <svg class='gravity-grid' viewBox='0 0 1000 562' preserveAspectRatio='xMidYMid slice'>
      <defs>
        <radialGradient id='grid-fade' cx='50%' cy='50%' r='50%'>
          <stop offset='0%' stop-color='white' stop-opacity='0.2' />
          <stop offset='100%' stop-color='white' stop-opacity='0' />
        </radialGradient>
      </defs>
      <path class='grid-lines-path' d='' />
    </svg>

    <!-- Step 0: 巨大的质量球体 -->
    <div class='massive-sphere' data-step='0'>
      <div class='sphere-glow'></div>
      <div class='sphere-label'>MASS / 质量</div>
    </div>

    <!-- Step 1: 黄金公式 -->
    <div class='formula-wrap' data-step='1'>
      <div class='formula-shimmer'></div>
      <h2 class='formula-text'>E=mc²</h2>
      <div class='formula-sub'>ENERGY-MASS EQUIVALENCE</div>
    </div>
  </div>

  <!-- Step 2: 时间流动的注脚 -->
  <div class='time-relativity-tag' data-step='2'>
    <div class='tag-line'></div>
    <div class='tag-content'>
      <span class='tag-title'>RELATIVITY OF TIME</span>
      <span class='tag-desc'>时空的相对性流动</span>
    </div>
  </div>

  <!-- 底部页脚 -->
  <div class='newspaper-footer'>
    <div class='footer-line-thin'></div>
    <div class='footer-flex'>
      <span>ALBERT EINSTEIN</span>
      <span>GENERAL RELATIVITY</span>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-framework-scene-id="scene-06" data-scene-id="scene-06">
  <div class="sv-scene-root sv-scene-root-scene-06" data-scene-root-id="scene-06">
<div class='s-scene-06-root' data-scene-root-id='scene-06'>
  <div class='paper-texture'></div>
  
  <!-- 报头区域 -->
  <div class='masthead'>
    <div class='masthead-meta'>QUANTUM MECHANICS / VOL. 1925</div>
    <div class='masthead-title'>THE MICROSCOPIC DAWN</div>
    <div class='double-border'></div>
  </div>

  <div class='quantum-viewport'>
    <!-- 左侧：原子模型 -->
    <div class='atom-container' data-step='0'>
      <div class='atom-core'>
        <div class='nucleus'></div>
        <div class='electron-cloud'></div>
        <div class='orbit-ring' style='--rot:0deg'></div>
        <div class='orbit-ring' style='--rot:60deg'></div>
        <div class='orbit-ring' style='--rot:120deg'></div>
      </div>
      <div class='label-tag'>ATOMIC STRUCTURE / 原子结构</div>
    </div>

    <!-- 右侧：概率波 -->
    <div class='wave-container'>
      <svg class='wave-svg' viewBox='0 0 400 200' preserveAspectRatio='xMidYMid meet'>
        <path class='wave-path' d='' />
      </svg>
      <div class='label-tag wave-label' data-step='1'>PROBABILITY WAVE / 概率波形</div>
    </div>
  </div>

  <!-- 核心冲突：波粒二象性 -->
  <div class='duality-hero' data-step='2'>
    <div class='duality-bg-bar'></div>
    <h1 class='duality-text'>波粒二象性</h1>
    <div class='duality-sub'>WAVE-PARTICLE DUALITY</div>
  </div>

  <!-- 背景量化点位层 -->
  <div class='quantum-grid-bg' data-step='3'>
    <canvas id='quantum-canvas-06'></canvas>
  </div>

  <!-- 底部页脚 -->
  <div class='newspaper-footer'>
    <div class='single-line'></div>
    <div class='footer-info'>
      <span>PLANCK & BOHR</span>
      <span>SUBATOMIC DISCOVERY</span>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-framework-scene-id="scene-07" data-scene-id="scene-07">
  <div class="sv-scene-root sv-scene-root-scene-07" data-scene-root-id="scene-07">
<div class='s-scene-07-root' data-scene-root-id='scene-07'>
  <div class='paper-texture'></div>

  <!-- 报头区域 -->
  <div class='masthead'>
    <div class='masthead-meta'>PHYSICS FRONTIER / FINAL CHAPTER</div>
    <div class='masthead-title'>THE THEORY OF EVERYTHING</div>
    <div class='double-border'></div>
  </div>

  <!-- 核心画布区域 -->
  <div class='theory-viewport'>
    <!-- 背景分形几何 (一切的源头) -->
    <div class='fractal-origin'>
      <svg viewBox='0 0 800 800' class='fractal-svg'>
        <defs>
          <pattern id='grid-pattern' width='40' height='40' patternUnits='userSpaceOnUse'>
            <path d='M 40 0 L 0 0 0 40' fill='none' stroke='rgba(17,17,17,0.05)' stroke-width='0.5'/>
          </pattern>
        </defs>
        <rect width='100%' height='100%' fill='url(#grid-pattern)' />
        <g class='fractal-group' stroke='#111111' fill='none' stroke-width='0.5' opacity='0.15'>
          <!-- 由JS动态生成的几何分形路径 -->
        </g>
      </svg>
    </div>

    <!-- Step 0: 四大基本力球体 -->
    <div class='force-sphere strong-force' data-step='0'>
      <div class='sphere-core'></div>
      <span class='force-label'>STRONG / 强力</span>
    </div>
    <div class='force-sphere weak-force' data-step='0'>
      <div class='sphere-core'></div>
      <span class='force-label'>WEAK / 弱力</span>
    </div>
    <div class='force-sphere em-force' data-step='0'>
      <div class='sphere-core'></div>
      <span class='force-label'>ELECTRO / 电磁力</span>
    </div>
    <div class='force-sphere gravity-force' data-step='0'>
      <div class='sphere-core'></div>
      <span class='force-label'>GRAVITY / 引力</span>
    </div>

    <!-- Step 1: 融合后的能量环 -->
    <div class='unified-ring-container' data-step='1'>
      <div class='unified-ring'></div>
      <div class='unified-ring-glow'></div>
      <canvas id='particle-system-07'></canvas>
    </div>

    <!-- Step 2: 核心标题 -->
    <div class='final-title-box' data-step='2'>
      <div class='title-line-top'></div>
      <h1 class='main-theory-title'>万物理论</h1>
      <div class='sub-theory-title'>THEORY OF EVERYTHING</div>
      <div class='title-line-bottom'></div>
    </div>
  </div>

  <!-- 底部页脚 -->
  <div class='newspaper-footer'>
    <div class='footer-line'></div>
    <div class='footer-flex'>
      <span>QUEST FOR UNIFICATION</span>
      <span>MODERN PHYSICS ARCHIVE</span>
      <span>NO. 001-INFINITY</span>
    </div>
  </div>

  <!-- 背景氛围：大号浮动文字 -->
  <div class='ambient-text'>UNIFICATION</div>
</div>
  </div>
</section>

<section class="scene" data-framework-scene-id="scene-08" data-scene-id="scene-08">
  <div class="sv-scene-root sv-scene-root-scene-08" data-scene-root-id="scene-08">
<div class='s-scene-08-root' data-scene-root-id='scene-08'>
  <div class='paper-texture'></div>

  <!-- 报头区域 -->
  <div class='masthead'>
    <div class='masthead-meta'>SPECIAL EDITION / FUTURE PROSPECT</div>
    <div class='masthead-title'>THE ETERNAL FRONTIER</div>
    <div class='double-border'></div>
  </div>

  <!-- 核心星空与轨道视图 -->
  <div class='perspective-viewport'>
    <!-- 深邃星空层 -->
    <div class='starfield'>
      <canvas id='star-canvas-08'></canvas>
    </div>

    <!-- 金色轨道（SVG 路径） -->
    <div class='golden-track-container'>
      <svg viewBox='0 0 1000 1000' class='track-svg'>
        <defs>
          <linearGradient id='track-grad' x1='50%' y1='100%' x2='50%' y2='0%'>
            <stop offset='0%' stop-color='#111111' stop-opacity='0' />
            <stop offset='50%' stop-color='#111111' stop-opacity='1' />
            <stop offset='100%' stop-color='#111111' stop-opacity='1' />
          </linearGradient>
        </defs>
        <!-- 轨道线条 -->
        <path d='M 500 1000 L 500 0' class='track-line main-track' />
        <path d='M 480 1000 L 495 0' class='track-line side-track' />
        <path d='M 520 1000 L 505 0' class='track-line side-track' />
      </svg>
    </div>

    <!-- Step 0: 核心文字 -->
    <div class='final-message' data-step='0'>
      <div class='kicker'>EPILOGUE</div>
      <h1 class='hero-text'>这场伟大的征途，才刚刚开始</h1>
      <div class='sub-hero-text'>THE JOURNEY HAS JUST BEGUN</div>
      <div class='message-decoration'>
        <span class='dot'></span><span class='line'></span><span class='dot'></span>
      </div>
    </div>

    <!-- Step 1: 冲刺全屏白光 -->
    <div class='flash-overlay' data-step='1'></div>
  </div>

  <!-- 氛围文字 -->
  <div class='ambient-word'>INFINITY</div>

  <!-- 底部页脚 -->
  <div class='newspaper-footer'>
    <div class='footer-line'></div>
    <div class='footer-flex'>
      <span>EST. 1900 — ∞</span>
      <span>PHYSICS TODAY / FINAL ISSUE</span>
      <span>PAGE. LAST</span>
    </div>
  </div>
</div>
  </div>
</section>
      </div>
    </div>
  </div>
  <script id="__SVGVIDEO_META__" type="application/json">{"version":2,"format":"json","title":"极简物理史：从万有引力到量子群星","fullScript":"从仰望星空到解析万物，人类探索物理的旅程，是一场跨越千年的智慧接力。在17世纪，牛顿坐在苹果树下，用三大定律和万有引力，为我们构建了一个精准如钟表的机械宇宙模型。19世纪，麦克斯韦方程组横空出世，它统一了电、磁与光，点亮了现代文明的工业之光。然而，物理学的天空并未永远晴朗。20世纪初，爱因斯坦用相对论重塑了时空，告诉我们重力是时空的弯曲，质量即能量。与此同时，普朗克和波尔撞开了微观世界的大门，量子力学用波粒二象性颠覆了我们的常识。从宏观星系到微观粒子，物理学从未停止脚步。今天，我们依然在追寻那个终极答案，试图编织出一套统一万物的万物理论。这场伟大的征途，才刚刚开始。","visualStyleId":"newspaper-bw","orientation":"landscape","scenes":[{"id":"scene-01","title":"开篇：星空与智慧","steps":3,"status":"success","prompt":"16:9横向构图。深邃的墨蓝色渐变背景，点缀着微弱闪烁的粒子星尘。Step 0: 屏幕中心出现一个精致的金色圆规与星图重叠的SVG图标，伴随淡入和轻微的脉冲放大效果。Step 1: 左右两侧缓缓升起半透明的流线型边框，勾勒出宇宙的深远感。Step 2: 标题文字‘物理学发展史’以金色渐变效果从底部上移，带有发光阴影。","scriptText":"从仰望星空到解析万物，人类探索物理的旅程，是一场跨越千年的智慧接力。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_1cdf4d72-1ddc-4ce5-9527-9ebae041b871/s_scene-01/v_xiaochen/a_f54439e6_1780409534033_qh78nr.mp3","audioDurationMs":6912,"voiceName":"xiaochen","relatedSceneIds":["scene-02"],"transition":"door"},{"id":"scene-02","title":"经典力学：牛顿时刻","steps":4,"status":"success","prompt":"16:9横向构图。左侧展示一个三维质感的红色苹果图标，右侧为复古羊皮纸质感的卡片展示区域。Step 0: 苹果图标弹出（Spring效果），下方出现一条水平的地平线。Step 1: 右侧卡片逐行显示‘F=ma’和‘万有引力定律’的精美公式，公式呈现手写描边动画。Step 2: 屏幕背景出现无数齿轮咬合转动的半透明线条，象征机械宇宙。Step 3: 苹果下方垂直落下数条重力感应线，强调下落动作。","scriptText":"在17世纪，牛顿坐在苹果树下，用三大定律和万有引力，为我们构建了一个精准如钟表的机械宇宙模型。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_1cdf4d72-1ddc-4ce5-9527-9ebae041b871/s_scene-02/v_xiaochen/a_6bce4004_1780409562198_exzzaf.mp3","audioDurationMs":9396,"voiceName":"xiaochen","relatedSceneIds":["scene-03"],"transition":"slam"},{"id":"scene-03","title":"电磁时代：麦克斯韦","steps":3,"status":"success","prompt":"16:9横向构图。冷色调，深紫色背景。Step 0: 屏幕中心由点发散出密集的蓝色电磁场波纹（Ripple动画）。Step 1: 四个核心方程以毛玻璃卡片形式整齐排列在屏幕中横向展开，公式文字带有幽蓝色荧光边框。Step 2: 背景中快速穿梭代表光速的白色细长线条，模拟光波的传播，整体呈现科技工业感。","scriptText":"19世纪，麦克斯韦方程组横空出世，它统一了电、磁与光，点亮了现代文明的工业之光。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_1cdf4d72-1ddc-4ce5-9527-9ebae041b871/s_scene-03/v_xiaochen/a_4106bcb9_1780409586936_5lkg0x.mp3","audioDurationMs":8280,"voiceName":"xiaochen","relatedSceneIds":["scene-04"],"transition":"push-up"},{"id":"scene-04","title":"危机：两朵乌云","steps":2,"status":"success","prompt":"16:9横向构图。画面中央出现一个醒目的黑色叹号，背景变为具有数字故障感（Glitch）的灰调。Step 0: 左右各出现一个翻滚的灰色云团SVG，边缘有闪电动画。Step 1: 屏幕中间出现‘经典物理学的危机’文字，随后文字产生震动和碎裂效果，预示革命到来。","scriptText":"然而，物理学的天空并未永远晴朗。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_1cdf4d72-1ddc-4ce5-9527-9ebae041b871/s_scene-04/v_xiaochen/a_548d4cb0_1780409614078_4qtakf.mp3","audioDurationMs":3672,"voiceName":"xiaochen","relatedSceneIds":["scene-05"],"transition":"glitch"},{"id":"scene-05","title":"相对论：时空弯曲","steps":3,"status":"success","prompt":"16:9横向构图。深黑色背景，布满发光的网格线（Grid）。Step 0: 屏幕中心放置一个巨大的发光球体，周围的网格线因球体重量而向下凹陷弯曲，模拟重力场。Step 1: 黄金公式‘E=mc²’以3D翻转形式进入视野中心，伴随强烈的闪光（Shimmer）。Step 2: 网格线开始缓慢流动，代表时间的相对性，视觉重心保持在弯曲的空间中心。","scriptText":"20世纪初，爱因斯坦用相对论重塑了时空，告诉我们重力是时空的弯曲，质量即能量。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_1cdf4d72-1ddc-4ce5-9527-9ebae041b871/s_scene-05/v_xiaochen/a_841b4b2e_1780409640509_o7hmew.mp3","audioDurationMs":7956,"voiceName":"xiaochen","relatedSceneIds":["scene-06"],"transition":"tunnel"},{"id":"scene-06","title":"微观世界：量子黎明","steps":4,"status":"success","prompt":"16:9横向构图。左侧显示原子结构模型（核子+电子轨道），右侧显示概率波的波形图。Step 0: 原子模型中心快速旋转，电子呈现粒子云团状。Step 1: 波形图开始上下剧烈跳动，颜色在冷绿与亮紫间切换。Step 2: 弹出‘波粒二象性’的中文字样，并伴随缩放动画。Step 3: 屏幕背景布满随机闪烁的量子比特点位，体现微观世界的不可预测性。","scriptText":"与此同时，普朗克和波尔撞开了微观世界的大门，量子力学用波粒二象性颠覆了我们的常识。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_1cdf4d72-1ddc-4ce5-9527-9ebae041b871/s_scene-06/v_xiaochen/a_bb5dea55_1780409666828_6lvpuf.mp3","audioDurationMs":8208,"voiceName":"xiaochen","relatedSceneIds":["scene-07"],"transition":"spin"},{"id":"scene-07","title":"终极梦想：大统一理论","steps":3,"status":"success","prompt":"16:9横向构图。全亮白背景，中间是一个复杂的几何几何分形图案，象征一切的源头。Step 0: 四个不同颜色的发光球体（强力、弱力、电磁力、引力）从屏幕四角向圆心汇聚。Step 1: 球体碰撞并融合为一个五彩斑斓的能量环。Step 2: ‘万物理论 Theory of Everything’字样在环心缓缓浮现，伴随粒子向上漂浮的粒子系统动画。","scriptText":"从宏观星系到微观粒子，物理学从未停止脚步。今天，我们依然在追寻那个终极答案，试图编织出一套统一万物的万物理论。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_1cdf4d72-1ddc-4ce5-9527-9ebae041b871/s_scene-07/v_xiaochen/a_1937a173_1780409693720_fgxano.mp3","audioDurationMs":11160,"voiceName":"xiaochen","relatedSceneIds":["scene-08"],"transition":"burst"},{"id":"scene-08","title":"结尾：致敬未来","steps":2,"status":"success","prompt":"16:9横向构图。回归到开篇的深邃星空，但这次加入了一道向远方延伸的金色光线轨道。Step 0: 画面中央浮现出一句文字：‘这场伟大的征途，才刚刚开始’。Step 1: 镜头沿着金色轨道快速推进，光效逐渐充满全屏，最终变白。构图简洁开阔，留白充足。","scriptText":"这场伟大的征途，才刚刚开始。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_1cdf4d72-1ddc-4ce5-9527-9ebae041b871/s_scene-08/v_xiaochen/a_ff0a626d_1780409720916_a2mmgx.mp3","audioDurationMs":3240,"voiceName":"xiaochen","transition":"push-up"}]}</script>
  <script id="__SVGVIDEO_SCENE_DATA__" type="application/json">[{"id":"scene-01","title":"开篇：星空与智慧","steps":3,"html":"<div class='s-scene-01-root' data-scene-root-id='scene-01'>\n  <div class='paper-background'></div>\n  <div class='paper-overlay'></div>\n\n  <!-- 报头区域 -->\n  <header class='masthead'>\n    <div class='masthead-top'>ESTABLISHED 17TH CENTURY / ISSUE NO. 001</div>\n    <div class='masthead-main'>SCIENTIFIC INQUIRY</div>\n    <div class='masthead-bottom'>\n      <span>SPECIAL EDITION: THE HISTORY OF PHYSICS</span>\n      <span>PRICE: PRICELESS WISDOM</span>\n    </div>\n  </header>\n\n  <main class='newspaper-content'>\n    <!-- Step 0: 核心视觉 - 金色圆规与星图 (在黑白报纸中处理为高对比度黑白矢量) -->\n    <div class='hero-visual' data-step='0'>\n      <div class='visual-container'>\n        <svg viewBox='0 0 200 200' class='astrolabe-svg'>\n          <circle cx='100' cy='100' r='80' stroke='#111' stroke-width='0.5' fill='none' stroke-dasharray='4 2' />\n          <path d='M100 20 L100 180 M20 100 L180 100' stroke='#111' stroke-width='0.5' />\n          <path class='compass-path' d='M100 40 L140 160 M100 40 L60 160' stroke='#111' stroke-width='3' fill='none' stroke-linecap='round' />\n          <circle cx='100' cy='40' r='5' fill='#111' />\n          <path d='M50 100 Q100 150 150 100' stroke='#111' stroke-width='1' fill='none' />\n        </svg>\n        <div class='caption-text'>FIG 1.1: ARCHETYPE OF UNIVERSAL ORDER</div>\n      </div>\n    </div>\n\n    <!-- Step 1 & 2: 标题与装饰性边框 -->\n    <div class='article-header'>\n      <div class='side-rules' data-step='1'></div>\n      <div class='headline-container' data-step='2'>\n        <h2 class='kicker'>THE GREAT HUMAN JOURNEY</h2>\n        <h1 class='main-headline'>物理学发展史</h1>\n        <div class='sub-headline'>FROM STARGAZING TO QUANTUM MECHANICS: A MILLENNIAL QUEST</div>\n      </div>\n    </div>\n\n    <!-- 报纸分栏背景装饰 (无文字，仅线条感) -->\n    <div class='columns-grid'>\n      <div class='column'></div>\n      <div class='column'></div>\n      <div class='column'></div>\n    </div>\n  </main>\n\n  <div class='bottom-rule'></div>\n</div>","css":".s-scene-01-root {\n  --paper-white: #FAFAFA;\n  --ink-black: #111111;\n  --sub-text: rgba(17,17,17,0.65);\n  --rule-thin: 1px;\n  --rule-thick: 3px;\n  \n  position: relative;\n  width: 100%;\n  height: 100%;\n  background-color: var(--paper-white);\n  color: var(--ink-black);\n  font-family: var(--sv-font-body-cn);\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n  padding: 40px 60px;\n  box-sizing: border-box;\n}\n\n/* 报纸质感氛围层 */\n.paper-overlay {\n  position: absolute;\n  top: 0; left: 0; right: 0; bottom: 0;\n  background-image: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3BaseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E\");\n  opacity: 0.04;\n  pointer-events: none;\n  z-index: 10;\n}\n\n/* 报头 */\n.masthead {\n  text-align: center;\n  border-bottom: var(--rule-thick) solid var(--ink-black);\n  padding-bottom: 15px;\n  margin-bottom: 30px;\n}\n\n.masthead-top {\n  font-size: 14px;\n  letter-spacing: 0.3em;\n  font-weight: 700;\n}\n\n.masthead-main {\n  font-family: var(--sv-font-display-cn);\n  font-size: 84px;\n  font-weight: 900;\n  line-height: 1;\n  margin: 10px 0;\n  letter-spacing: -0.02em;\n}\n\n.masthead-bottom {\n  display: flex;\n  justify-content: space-between;\n  font-size: 12px;\n  font-weight: 700;\n  border-top: var(--rule-thin) solid var(--ink-black);\n  padding-top: 5px;\n}\n\n/* 主体内容布局 */\n.newspaper-content {\n  flex: 1;\n  display: grid;\n  grid-template-columns: 1fr 1.5fr;\n  gap: 40px;\n  align-items: center;\n}\n\n/* Step 0: 核心视觉 */\n.hero-visual {\n  opacity: 0;\n  transform: scale(0.95);\n  transition: all 0.8s cubic-bezier(0.22, 1, 0.36, 1);\n  text-align: center;\n}\n\n.step-ge-0 .hero-visual {\n  opacity: 1;\n  transform: scale(1);\n}\n\n.astrolabe-svg {\n  width: 320px;\n  height: 320px;\n}\n\n.compass-path {\n  animation: pulse-line 4s ease-in-out infinite;\n}\n\n@keyframes pulse-line {\n  0%, 100% { stroke-width: 3; }\n  50% { stroke-width: 4; }\n}\n\n.caption-text {\n  font-size: 12px;\n  font-weight: 700;\n  margin-top: 10px;\n  letter-spacing: 0.1em;\n}\n\n/* Step 1 & 2: 标题与边框 */\n.article-header {\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n}\n\n.side-rules {\n  position: absolute;\n  left: -20px;\n  top: 0; bottom: 0;\n  width: 4px;\n  border-left: 1px solid var(--ink-black);\n  border-right: 3px solid var(--ink-black);\n  opacity: 0;\n  transition: opacity 0.6s ease;\n}\n\n.step-ge-1 .side-rules {\n  opacity: 1;\n}\n\n.headline-container {\n  opacity: 0;\n  transform: translateY(30px);\n  transition: all 0.7s cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.step-ge-2 .headline-container {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.kicker {\n  font-size: 18px;\n  font-weight: 700;\n  margin-bottom: 5px;\n  letter-spacing: 0.15em;\n}\n\n.main-headline {\n  font-family: var(--sv-font-display-cn);\n  font-size: 82px;\n  font-weight: 900;\n  margin: 0 0 15px 0;\n  line-height: 1.1;\n  border-bottom: var(--rule-thin) solid var(--ink-black);\n  padding-bottom: 10px;\n}\n\n.sub-headline {\n  font-size: 20px;\n  color: var(--sub-text);\n  font-style: italic;\n  max-width: 80%;\n}\n\n/* 装饰背景线 */\n.bottom-rule {\n  height: 6px;\n  border-top: 1px solid var(--ink-black);\n  border-bottom: 4px solid var(--ink-black);\n  margin-top: 20px;\n}\n\n.columns-grid {\n  position: absolute;\n  bottom: 60px;\n  right: 60px;\n  width: 300px;\n  height: 150px;\n  display: flex;\n  gap: 15px;\n  opacity: 0.1;\n  pointer-events: none;\n}\n\n.column {\n  flex: 1;\n  border-left: 0.5px solid var(--ink-black);\n  background: repeating-linear-gradient(0deg, var(--ink-black) 0, var(--ink-black) 1px, transparent 1px, transparent 12px);\n}","js":"window.SceneLifecycle.register('scene-01', {\n  enter() {\n    const root = document.querySelector('[data-scene-root-id=\"scene-01\"]');\n    // 模拟报纸印刷出来的微弱晃动感\n    root.animate([\n      { transform: 'translate(0, 5px) scale(1.01)', opacity: 0 },\n      { transform: 'translate(0, 0) scale(1)', opacity: 1 }\n    ], { duration: 1000, easing: 'cubic-bezier(0.22, 1, 0.36, 1)' });\n  },\n  step(stepIndex) {\n    const root = document.querySelector('[data-scene-root-id=\"scene-01\"]');\n    if (stepIndex === 2) {\n      // 当大标题出现时，给主标题一个强调效果\n      const headline = root.querySelector('.main-headline');\n      if (headline) {\n        headline.animate([\n          { letterSpacing: '0.2em', opacity: 0.5 },\n          { letterSpacing: '-0.02em', opacity: 1 }\n        ], { duration: 800, easing: 'ease-out' });\n      }\n    }\n  },\n  leave() {}\n});"},{"id":"scene-02","title":"经典力学：牛顿时刻","steps":4,"html":"<div class='s-scene-02-root' data-scene-root-id='scene-02'>\n  <div class='paper-overlay'></div>\n\n  <!-- 背景：机械宇宙氛围层 (Step 2 激活) -->\n  <div class='mechanical-universe' data-step='2'>\n    <div class='gear-container'>\n      <svg viewBox='0 0 400 400' class='gear gear-large'>\n        <path d='M200 150 L210 130 L230 135 L235 155 L255 160 L270 145 L285 155 L275 175 L285 195 L305 200 L305 220 L285 225 L275 245 L285 265 L270 275 L255 260 L235 265 L230 285 L210 290 L200 270 L180 270 L170 290 L150 285 L145 265 L125 260 L110 275 L95 265 L105 245 L95 225 L75 220 L75 200 L95 195 L105 175 L95 155 L110 145 L125 160 L145 155 L150 135 L170 130 L180 150 Z' fill='none' stroke='#111' stroke-width='1' />\n        <circle cx='200' cy='210' r='30' fill='none' stroke='#111' stroke-width='0.5' />\n      </svg>\n      <svg viewBox='0 0 200 200' class='gear gear-small'>\n        <path d='M100 70 L108 55 L120 58 L122 72 L135 75 L145 65 L155 72 L148 85 L155 98 L168 102 L168 115 L155 118 L148 132 L155 145 L145 152 L135 142 L122 145 L120 160 L108 162 L100 148 L90 148 L82 162 L70 160 L68 145 L55 142 L45 152 L35 145 L42 132 L35 118 L22 115 L22 102 L35 98 L42 85 L35 72 L45 65 L55 75 L68 72 L70 58 L82 55 L90 70 Z' fill='none' stroke='#111' stroke-width='1' />\n      </svg>\n    </div>\n    <div class='constellation-lines'></div>\n  </div>\n\n  <div class='main-layout'>\n    <!-- 左侧：苹果视觉区 -->\n    <div class='visual-side'>\n      <div class='apple-stage' data-step='0'>\n        <div class='apple-icon'>\n          <svg viewBox='0 0 100 100' class='apple-svg'>\n            <path class='apple-body' d='M50 30 C30 30 20 45 20 65 C20 85 35 95 50 95 C65 95 80 85 80 65 C80 45 70 30 50 30 Z' fill='#111' />\n            <path class='apple-stem' d='M50 30 Q55 15 65 10' fill='none' stroke='#111' stroke-width='4' stroke-linecap='round' />\n            <path class='apple-leaf' d='M50 30 Q40 20 35 30 Q40 35 50 30' fill='#111' />\n          </svg>\n          <div class='gravity-lines' data-step='3'>\n            <span class='g-line'></span>\n            <span class='g-line'></span>\n            <span class='g-line'></span>\n          </div>\n        </div>\n        <div class='horizon-line'></div>\n        <div class='apple-caption'>ISAAC NEWTON / 1687</div>\n      </div>\n    </div>\n\n    <!-- 右侧：复古公式卡片 -->\n    <div class='content-side'>\n      <div class='parchment-card' data-step='1'>\n        <div class='card-header'>PRINCIPIA MATHEMATICA</div>\n        <div class='formula-area'>\n          <div class='formula-row formula-main'>\n            <svg viewBox='0 0 200 60' class='handwritten-svg'>\n              <text x='50%' y='45' text-anchor='middle' class='f-ma'>F = ma</text>\n            </svg>\n          </div>\n          <div class='divider-diamond'>◆</div>\n          <div class='formula-row formula-law'>\n            <div class='law-title'>万有引力定律</div>\n            <svg viewBox='0 0 300 80' class='handwritten-svg'>\n              <text x='50%' y='50' text-anchor='middle' class='f-gravity'>F = G (m₁m₂ / r²)</text>\n            </svg>\n          </div>\n        </div>\n        <div class='card-footer'>UNIVERSAL ORDER</div>\n      </div>\n    </div>\n  </div>\n\n  <!-- 底部装饰线 -->\n  <div class='bottom-rules'>\n    <div class='thick-rule'></div>\n    <div class='thin-rule'></div>\n  </div>\n</div>","css":".s-scene-02-root {\n  --ink: #111111;\n  --paper: #FAFAFA;\n  --card-bg: #F0F0F0;\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: var(--paper);\n  color: var(--ink);\n  font-family: var(--sv-font-body-cn);\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n}\n\n.paper-overlay {\n  position: absolute; inset: 0; pointer-events: none; z-index: 100;\n  background-image: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3BaseFrequency='0.7' numOctaves='3'/%3E%3C/svg%3E\");\n  opacity: 0.03;\n}\n\n.main-layout {\n  flex: 1;\n  display: grid;\n  grid-template-columns: 1fr 1.2fr;\n  padding: 80px 100px;\n  gap: 60px;\n  align-items: center;\n  z-index: 10;\n}\n\n/* Step 0: 苹果视觉 */\n.apple-stage {\n  position: relative;\n  text-align: center;\n  opacity: 0;\n  transform: translateY(20px);\n  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n.step-ge-0 .apple-stage { opacity: 1; transform: translateY(0); }\n\n.apple-icon {\n  position: relative;\n  display: inline-block;\n  width: 180px;\n  height: 180px;\n  margin-bottom: 20px;\n}\n.apple-svg { width: 100%; height: 100%; filter: drop-shadow(2px 2px 0px rgba(0,0,0,0.1)); }\n\n.horizon-line {\n  width: 240px;\n  height: 2px;\n  background: var(--ink);\n  margin: 0 auto;\n  transform: scaleX(0);\n  transition: transform 0.6s 0.3s ease-out;\n}\n.step-ge-0 .horizon-line { transform: scaleX(1); }\n\n.apple-caption {\n  font-size: 14px;\n  font-weight: 700;\n  letter-spacing: 0.2em;\n  margin-top: 15px;\n}\n\n/* Step 3: 重力感应线 */\n.gravity-lines {\n  position: absolute;\n  bottom: -40px;\n  left: 50%;\n  transform: translateX(-50%);\n  display: flex;\n  gap: 20px;\n  opacity: 0;\n}\n.step-ge-3 .gravity-lines { opacity: 1; }\n.g-line {\n  width: 1px;\n  height: 60px;\n  background: linear-gradient(to bottom, var(--ink), transparent);\n  animation: fall-line 1.2s infinite ease-in;\n}\n.g-line:nth-child(2) { animation-delay: 0.4s; }\n.g-line:nth-child(3) { animation-delay: 0.8s; }\n\n@keyframes fall-line {\n  0% { transform: scaleY(0); transform-origin: top; opacity: 0; }\n  50% { transform: scaleY(1); opacity: 1; }\n  100% { transform: scaleY(1) translateY(40px); transform-origin: bottom; opacity: 0; }\n}\n\n/* Step 1: 公式卡片 */\n.parchment-card {\n  background: var(--card-bg);\n  border: 1px solid var(--ink);\n  padding: 40px;\n  box-shadow: 8px 8px 0px var(--ink);\n  opacity: 0;\n  transform: translateX(40px);\n  transition: all 0.7s cubic-bezier(0.16, 1, 0.3, 1);\n}\n.step-ge-1 .parchment-card { opacity: 1; transform: translateX(0); }\n\n.card-header {\n  font-size: 12px;\n  font-weight: 900;\n  border-bottom: 1px solid var(--ink);\n  padding-bottom: 8px;\n  margin-bottom: 30px;\n  letter-spacing: 0.1em;\n}\n\n.formula-area {\n  text-align: center;\n}\n\n.handwritten-svg {\n  width: 100%;\n  height: auto;\n  font-family: var(--sv-font-mono);\n  font-style: italic;\n  fill: var(--ink);\n  font-weight: 700;\n}\n.f-ma { font-size: 42px; }\n.f-gravity { font-size: 24px; }\n\n.divider-diamond {\n  margin: 20px 0;\n  font-size: 12px;\n  opacity: 0.3;\n}\n\n.law-title {\n  font-family: var(--sv-font-display-cn);\n  font-size: 18px;\n  margin-bottom: 10px;\n  text-decoration: underline;\n}\n\n.card-footer {\n  margin-top: 30px;\n  font-size: 10px;\n  text-align: right;\n  opacity: 0.6;\n}\n\n/* Step 2: 机械宇宙背景 */\n.mechanical-universe {\n  position: absolute;\n  inset: 0;\n  opacity: 0;\n  transition: opacity 1.5s ease;\n  pointer-events: none;\n}\n.step-ge-2 .mechanical-universe { opacity: 0.08; }\n\n.gear-container {\n  position: absolute;\n  right: -50px;\n  top: -50px;\n}\n.gear {\n  animation: rotate-gear 20s linear infinite;\n}\n.gear-large { width: 400px; }\n.gear-small {\n  width: 200px;\n  position: absolute;\n  top: 250px;\n  right: 280px;\n  animation-direction: reverse;\n  animation-duration: 10s;\n}\n\n@keyframes rotate-gear {\n  from { transform: rotate(0deg); }\n  to { transform: rotate(360deg); }\n}\n\n.bottom-rules {\n  padding: 0 60px 40px;\n}\n.thick-rule { height: 4px; background: var(--ink); margin-bottom: 4px; }\n.thin-rule { height: 1px; background: var(--ink); }","js":"window.SceneLifecycle.register('scene-02', {\n  enter() {\n    const root = document.querySelector('[data-scene-root-id=\"scene-02\"]');\n    if (!root) return;\n    \n    // 模拟活字印刷的微颤感\n    root.animate([\n      { opacity: 0, transform: 'scale(1.02)' },\n      { opacity: 1, transform: 'scale(1)' }\n    ], { duration: 800, easing: 'ease-out' });\n  },\n  step(stepIndex) {\n    const root = document.querySelector('[data-scene-root-id=\"scene-02\"]');\n    if (!root) return;\n\n    if (stepIndex === 1) {\n      // 公式出现时的手写描边模拟\n      const texts = root.querySelectorAll('.handwritten-svg text');\n      texts.forEach(text => {\n        text.animate([\n          { opacity: 0, strokeDasharray: '100', strokeDashoffset: '100', fill: 'transparent', stroke: '#111' },\n          { opacity: 1, strokeDashoffset: '0', fill: 'transparent', stroke: '#111', offset: 0.7 },\n          { opacity: 1, strokeDashoffset: '0', fill: '#111', stroke: 'transparent' }\n        ], { duration: 1500, easing: 'ease-in-out', fill: 'forwards' });\n      });\n    }\n\n    if (stepIndex === 2) {\n      // 机械宇宙背景增强\n      const gears = root.querySelectorAll('.gear');\n      gears.forEach(gear => {\n        gear.animate([\n          { opacity: 0 },\n          { opacity: 1 }\n        ], { duration: 2000, fill: 'forwards' });\n      });\n    }\n  }\n});"},{"id":"scene-03","title":"电磁时代：麦克斯韦","steps":3,"html":"<div class='s-scene-03-root' data-scene-root-id='scene-03'>\n  <!-- 报纸报头装饰 -->\n  <div class='masthead'>\n    <div class='masthead-inner'>\n      <span class='masthead-tag'>SCIENTIFIC REVOLUTION</span>\n      <div class='masthead-line-thick'></div>\n      <div class='masthead-title'>THE ELECTROMAGNETIC ERA</div>\n      <div class='masthead-line-thin'></div>\n    </div>\n  </div>\n\n  <!-- 背景氛围：电磁纹理与光速线 (Step 0 & Step 2) -->\n  <div class='ambient-layer'>\n    <div class='ripple-container' data-step='0'>\n      <div class='ripple'></div>\n      <div class='ripple'></div>\n      <div class='ripple'></div>\n    </div>\n    <div class='light-streaks' data-step='2'>\n      <div class='streak'></div>\n      <div class='streak'></div>\n      <div class='streak'></div>\n      <div class='streak'></div>\n      <div class='streak'></div>\n    </div>\n  </div>\n\n  <!-- 核心内容区：麦克斯韦方程组 -->\n  <div class='equations-grid' data-step='1'>\n    <div class='equation-card'>\n      <div class='eq-label'>GAUSS'S LAW</div>\n      <div class='eq-svg-wrap'>\n        <svg viewBox='0 0 160 60'><text x='50%' y='40' text-anchor='middle'>∇·E = ρ/ε₀</text></svg>\n      </div>\n      <div class='eq-desc'>高斯电场定律</div>\n    </div>\n    <div class='equation-card'>\n      <div class='eq-label'>GAUSS'S MAGNETISM</div>\n      <div class='eq-svg-wrap'>\n        <svg viewBox='0 0 160 60'><text x='50%' y='40' text-anchor='middle'>∇·B = 0</text></svg>\n      </div>\n      <div class='eq-desc'>高斯磁场定律</div>\n    </div>\n    <div class='equation-card'>\n      <div class='eq-label'>FARADAY'S LAW</div>\n      <div class='eq-svg-wrap'>\n        <svg viewBox='0 0 160 60'><text x='50%' y='40' text-anchor='middle'>∇×E = -∂B/∂t</text></svg>\n      </div>\n      <div class='eq-desc'>法拉第电磁感应</div>\n    </div>\n    <div class='equation-card'>\n      <div class='eq-label'>AMPÈRE-MAXWELL</div>\n      <div class='eq-svg-wrap'>\n        <svg viewBox='0 0 160 60'><text x='50%' y='40' text-anchor='middle'>∇×B = μ₀(J+ε₀∂E/∂t)</text></svg>\n      </div>\n      <div class='eq-desc'>安培-麦克斯韦定律</div>\n    </div>\n  </div>\n\n  <!-- 底部页脚 -->\n  <div class='newspaper-footer'>\n    <div class='footer-black-bar'>\n      <span>JAMES CLERK MAXWELL / 1865</span>\n      <span>UNIFYING ELECTRICITY, MAGNETISM, AND LIGHT</span>\n    </div>\n  </div>\n</div>","css":".s-scene-03-root {\n  --paper-white: #FAFAFA;\n  --ink-black: #111111;\n  --ink-muted: rgba(17,17,17,0.6);\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: var(--paper-white);\n  color: var(--ink-black);\n  font-family: var(--sv-font-body-cn);\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n  padding: 40px 60px;\n}\n\n/* 报头样式 */\n.masthead {\n  width: 100%;\n  text-align: center;\n  margin-bottom: 40px;\n}\n.masthead-tag {\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  letter-spacing: 0.3em;\n  font-weight: 700;\n}\n.masthead-line-thick { height: 4px; background: var(--ink-black); margin: 8px 0 4px; }\n.masthead-line-thin { height: 1px; background: var(--ink-black); }\n.masthead-title {\n  font-family: var(--sv-font-display-cn);\n  font-size: 56px;\n  font-weight: 900;\n  margin: 10px 0;\n  letter-spacing: -0.02em;\n}\n\n/* Step 0: 电磁波纹 */\n.ripple-container {\n  position: absolute;\n  top: 50%; left: 50%;\n  transform: translate(-50%, -50%);\n  width: 600px; height: 600px;\n  opacity: 0;\n  transition: opacity 1s ease;\n}\n.step-ge-0 .ripple-container { opacity: 0.15; }\n.ripple {\n  position: absolute;\n  top: 50%; left: 50%;\n  border: 1px solid var(--ink-black);\n  border-radius: 50%;\n  transform: translate(-50%, -50%);\n  animation: ripple-out 4s infinite linear;\n}\n.ripple:nth-child(2) { animation-delay: 1.3s; }\n.ripple:nth-child(3) { animation-delay: 2.6s; }\n\n@keyframes ripple-out {\n  0% { width: 0; height: 0; opacity: 1; }\n  100% { width: 100%; height: 100%; opacity: 0; }\n}\n\n/* Step 1: 方程卡片 */\n.equations-grid {\n  display: grid;\n  grid-template-columns: repeat(4, 1fr);\n  gap: 20px;\n  margin-top: 20px;\n  opacity: 0;\n  transform: translateY(30px);\n  transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1);\n  z-index: 10;\n}\n.step-ge-1 .equations-grid { opacity: 1; transform: translateY(0); }\n\n.equation-card {\n  background: white;\n  border: 1px solid var(--ink-black);\n  padding: 20px;\n  text-align: center;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  box-shadow: 4px 4px 0px var(--ink-black);\n}\n.eq-label {\n  font-size: 10px;\n  font-weight: 900;\n  color: white;\n  background: var(--ink-black);\n  padding: 2px 8px;\n  margin-bottom: 15px;\n  letter-spacing: 0.1em;\n}\n.eq-svg-wrap {\n  width: 100%;\n  height: 80px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n.eq-svg-wrap svg {\n  width: 90%;\n  height: auto;\n  fill: var(--ink-black);\n  font-family: var(--sv-font-mono);\n  font-weight: bold;\n  font-size: 20px;\n}\n.eq-desc {\n  font-size: 14px;\n  font-weight: 700;\n  margin-top: 15px;\n  border-top: 0.5px solid var(--ink-muted);\n  padding-top: 10px;\n  width: 100%;\n}\n\n/* Step 2: 光速线 */\n.light-streaks {\n  position: absolute;\n  inset: 0;\n  opacity: 0;\n  pointer-events: none;\n}\n.step-ge-2 .light-streaks { opacity: 1; }\n.streak {\n  position: absolute;\n  height: 1px;\n  background: var(--ink-black);\n  opacity: 0.2;\n  animation: streak-move 1.5s infinite linear;\n}\n.streak:nth-child(1) { top: 20%; width: 200px; left: -250px; animation-delay: 0.1s; }\n.streak:nth-child(2) { top: 45%; width: 400px; left: -450px; animation-delay: 0.4s; }\n.streak:nth-child(3) { top: 70%; width: 300px; left: -350px; animation-delay: 0.7s; }\n.streak:nth-child(4) { top: 15%; width: 150px; left: -200px; animation-delay: 1.1s; }\n.streak:nth-child(5) { top: 85%; width: 500px; left: -550px; animation-delay: 0.2s; }\n\n@keyframes streak-move {\n  0% { transform: translateX(0); }\n  100% { transform: translateX(calc(100vw + 600px)); }\n}\n\n/* 页脚 */\n.newspaper-footer {\n  margin-top: auto;\n  padding-bottom: 10px;\n}\n.footer-black-bar {\n  background: var(--ink-black);\n  color: var(--paper-white);\n  padding: 8px 20px;\n  display: flex;\n  justify-content: space-between;\n  font-size: 12px;\n  font-weight: 700;\n  letter-spacing: 0.1em;\n}","js":"window.SceneLifecycle.register('scene-03', {\n  enter() {\n    const root = document.querySelector('[data-scene-root-id=\"scene-03\"]');\n    if (!root) return;\n    \n    // 模拟报纸印刷震动感\n    root.animate([\n      { opacity: 0, transform: 'scale(1.05) translateY(10px)' },\n      { opacity: 1, transform: 'scale(1) translateY(0)' }\n    ], { duration: 800, easing: 'cubic-bezier(0.22, 1, 0.36, 1)' });\n  },\n  step(index) {\n    const root = document.querySelector('[data-scene-root-id=\"scene-03\"]');\n    if (!root) return;\n\n    if (index === 1) {\n      // 方程逐个弹出效果\n      const cards = root.querySelectorAll('.equation-card');\n      cards.forEach((card, i) => {\n        card.animate([\n          { opacity: 0, transform: 'translateY(20px)' },\n          { opacity: 1, transform: 'translateY(0)' }\n        ], {\n          duration: 500,\n          delay: i * 150,\n          easing: 'ease-out',\n          fill: 'forwards'\n        });\n      });\n    }\n  }\n});"},{"id":"scene-04","title":"危机：两朵乌云","steps":2,"html":"<div class='s-scene-04-root' data-scene-root-id='scene-04'>\n  <!-- 背景氛围：数字故障感纹理 -->\n  <div class='glitch-bg'>\n    <div class='glitch-line'></div>\n    <div class='glitch-line'></div>\n    <div class='glitch-line'></div>\n  </div>\n\n  <!-- 报纸报头 -->\n  <div class='newspaper-masthead'>\n    <div class='masthead-top'>THE SCIENTIFIC TIMES</div>\n    <div class='masthead-main'>SPECIAL EDITION: THE END OF PHYSICS?</div>\n    <div class='masthead-divider'></div>\n  </div>\n\n  <!-- 核心视觉：黑色叹号 -->\n  <div class='center-impact'>\n    <div class='exclamation-mark'>!</div>\n  </div>\n\n  <!-- Step 0: 乌云与闪电 -->\n  <div class='clouds-layer' data-step='0'>\n    <div class='cloud left-cloud'>\n      <svg viewBox='0 0 200 120'>\n        <path class='cloud-path' d='M50,100 C20,100 20,70 40,60 C30,30 70,20 90,40 C110,10 160,20 160,50 C190,50 190,90 160,100 Z' />\n        <path class='lightning' d='M100,80 L80,110 L110,110 L90,140' />\n      </svg>\n      <div class='cloud-label'>ETHER DRIFT</div>\n    </div>\n    <div class='cloud right-cloud'>\n      <svg viewBox='0 0 200 120'>\n        <path class='cloud-path' d='M50,100 C20,100 20,70 40,60 C30,30 70,20 90,40 C110,10 160,20 160,50 C190,50 190,90 160,100 Z' />\n        <path class='lightning' d='M100,80 L80,110 L110,110 L90,140' />\n      </svg>\n      <div class='cloud-label'>BLACKBODY RADIATION</div>\n    </div>\n  </div>\n\n  <!-- Step 1: 碎裂文字 -->\n  <div class='crisis-text-wrap' data-step='1'>\n    <h1 class='crisis-main-title'>经典物理学的危机</h1>\n    <div class='crisis-sub-title'>THE CRISIS OF CLASSICAL PHYSICS</div>\n  </div>\n\n  <!-- 报纸页脚 -->\n  <div class='newspaper-footer'>\n    <div class='footer-line'></div>\n    <div class='footer-content'>\n      <span>LATE 19TH CENTURY</span>\n      <span>LORD KELVIN'S \"TWO CLOUDS\"</span>\n    </div>\n  </div>\n</div>","css":".s-scene-04-root {\n  --paper-white: #F8F8F8;\n  --ink-black: #111111;\n  --ink-muted: rgba(17,17,17,0.6);\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: var(--paper-white);\n  color: var(--ink-black);\n  font-family: var(--sv-font-body-cn);\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n  padding: 30px 50px;\n}\n\n/* 故障感背景 */\n.glitch-bg {\n  position: absolute;\n  inset: 0;\n  background: repeating-linear-gradient(0deg, rgba(0,0,0,0.03) 0px, rgba(0,0,0,0.03) 1px, transparent 1px, transparent 2px);\n  pointer-events: none;\n  z-index: 1;\n}\n.glitch-line {\n  position: absolute;\n  width: 100%;\n  height: 2px;\n  background: rgba(17,17,17,0.08);\n  animation: glitch-slide 4s infinite linear;\n}\n.glitch-line:nth-child(2) { top: 30%; animation-delay: -1.2s; }\n.glitch-line:nth-child(3) { top: 70%; animation-delay: -2.8s; }\n@keyframes glitch-slide {\n  0% { transform: translateY(-100vh); }\n  100% { transform: translateY(100vh); }\n}\n\n/* 报纸排版 */\n.newspaper-masthead {\n  text-align: center;\n  z-index: 10;\n  margin-bottom: 20px;\n}\n.masthead-top {\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  letter-spacing: 0.5em;\n  font-weight: 700;\n}\n.masthead-main {\n  font-family: 'Libre Baskerville', serif;\n  font-size: 32px;\n  font-weight: 900;\n  border-top: 3px solid var(--ink-black);\n  border-bottom: 1px solid var(--ink-black);\n  padding: 8px 0;\n  margin-top: 10px;\n}\n\n/* 核心中心叹号 */\n.center-impact {\n  position: absolute;\n  top: 50%; left: 50%;\n  transform: translate(-50%, -50%);\n  z-index: 5;\n}\n.exclamation-mark {\n  font-family: var(--sv-font-display-cn);\n  font-size: 320px;\n  font-weight: 900;\n  line-height: 1;\n  animation: impact-shake 0.5s cubic-bezier(.36,.07,.19,.97) both;\n}\n@keyframes impact-shake {\n  10%, 90% { transform: translate3d(-2px, 0, 0); }\n  20%, 80% { transform: translate3d(4px, 0, 0); }\n  30%, 50%, 70% { transform: translate3d(-8px, 0, 0); }\n  40%, 60% { transform: translate3d(8px, 0, 0); }\n}\n\n/* Step 0: 乌云 */\n.clouds-layer {\n  position: absolute;\n  inset: 0;\n  opacity: 0;\n  transition: opacity 0.8s ease;\n  pointer-events: none;\n  z-index: 8;\n}\n.step-ge-0 .clouds-layer { opacity: 1; }\n.cloud {\n  position: absolute;\n  width: 260px;\n  top: 45%;\n  filter: drop-shadow(0 10px 20px rgba(0,0,0,0.1));\n}\n.left-cloud { left: 10%; transform: rotate(-5deg); }\n.right-cloud { right: 10%; transform: rotate(5deg); }\n.cloud-path { fill: #ddd; stroke: var(--ink-black); stroke-width: 2; }\n.lightning {\n  fill: none; stroke: var(--ink-black); stroke-width: 3;\n  stroke-dasharray: 50; stroke-dashoffset: 50;\n  animation: strike 2s infinite steps(1);\n}\n@keyframes strike {\n  0%, 100% { stroke-dashoffset: 50; }\n  10%, 15% { stroke-dashoffset: 0; }\n}\n.cloud-label {\n  text-align: center;\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  font-weight: 900;\n  margin-top: -10px;\n  background: var(--ink-black);\n  color: white;\n  padding: 2px 8px;\n}\n\n/* Step 1: 危机文字 */\n.crisis-text-wrap {\n  position: absolute;\n  bottom: 15%;\n  width: 100%;\n  text-align: center;\n  opacity: 0;\n  z-index: 20;\n}\n.step-ge-1 .crisis-text-wrap {\n  opacity: 1;\n  animation: fragment-shake 0.4s infinite alternate;\n}\n.crisis-main-title {\n  font-family: var(--sv-font-display-cn);\n  font-size: 84px;\n  font-weight: 900;\n  margin: 0;\n  letter-spacing: -2px;\n  text-transform: uppercase;\n}\n.crisis-sub-title {\n  font-family: 'Libre Baskerville', serif;\n  font-size: 20px;\n  letter-spacing: 0.3em;\n  margin-top: -10px;\n}\n@keyframes fragment-shake {\n  from { transform: translateX(-1px) skewX(0deg); filter: contrast(1.2); }\n  to { transform: translateX(1px) skewX(0.5deg); filter: contrast(1.5); }\n}\n\n/* 页脚 */\n.newspaper-footer {\n  margin-top: auto;\n  z-index: 10;\n}\n.footer-line { height: 1px; background: var(--ink-black); width: 100%; }\n.footer-content {\n  display: flex;\n  justify-content: space-between;\n  padding: 10px 0;\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  font-weight: 700;\n}","js":"window.SceneLifecycle.register('scene-04', {\n  enter() {\n    const root = document.querySelector('[data-scene-root-id=\"scene-04\"]');\n    if (!root) return;\n    \n    // 初始叹号震动\n    const mark = root.querySelector('.exclamation-mark');\n    mark.animate([\n      { transform: 'scale(0) rotate(20deg)', opacity: 0 },\n      { transform: 'scale(1.2) rotate(-5deg)', opacity: 1, offset: 0.7 },\n      { transform: 'scale(1) rotate(0)', opacity: 1 }\n    ], {\n      duration: 600,\n      easing: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)'\n    });\n  },\n  step(index) {\n    const root = document.querySelector('[data-scene-root-id=\"scene-04\"]');\n    if (!root) return;\n\n    if (index === 0) {\n      // 云团翻滚入场\n      const clouds = root.querySelectorAll('.cloud');\n      clouds.forEach((c, i) => {\n        c.animate([\n          { opacity: 0, transform: `translateX(${i === 0 ? '-100px' : '100px'}) rotate(${i === 0 ? -20 : 20}deg)` },\n          { opacity: 1, transform: 'translateX(0) rotate(0deg)' }\n        ], {\n          duration: 800,\n          delay: i * 200,\n          fill: 'forwards',\n          easing: 'ease-out'\n        });\n      });\n    }\n\n    if (index === 1) {\n      // 危机文字碎裂效果 (利用 JS 动态创建克隆层实现视觉错位)\n      const title = root.querySelector('.crisis-main-title');\n      title.animate([\n        { clipPath: 'inset(0 0 0 0)' },\n        { clipPath: 'inset(10% -20px 80% 0)', transform: 'translateX(10px)', offset: 0.1 },\n        { clipPath: 'inset(40% 0 30% -20px)', transform: 'translateX(-10px)', offset: 0.2 },\n        { clipPath: 'inset(0 0 0 0)', transform: 'translateX(0)' }\n      ], {\n        duration: 300,\n        iterations: Infinity\n      });\n    }\n  }\n});"},{"id":"scene-05","title":"相对论：时空弯曲","steps":3,"html":"<div class='s-scene-05-root' data-scene-root-id='scene-05'>\n  <!-- 背景：报纸质感与静态网格 -->\n  <div class='paper-overlay'></div>\n  \n  <!-- 报头 -->\n  <div class='newspaper-header'>\n    <div class='header-meta'>PHYSICS REVOLUTION / 1905</div>\n    <div class='header-title'>THE ANNUS MIRABILIS</div>\n    <div class='header-line-thick'></div>\n  </div>\n\n  <!-- 核心视觉：引力场网格 -->\n  <div class='gravity-field-container'>\n    <svg class='gravity-grid' viewBox='0 0 1000 562' preserveAspectRatio='xMidYMid slice'>\n      <defs>\n        <radialGradient id='grid-fade' cx='50%' cy='50%' r='50%'>\n          <stop offset='0%' stop-color='white' stop-opacity='0.2' />\n          <stop offset='100%' stop-color='white' stop-opacity='0' />\n        </radialGradient>\n      </defs>\n      <path class='grid-lines-path' d='' />\n    </svg>\n\n    <!-- Step 0: 巨大的质量球体 -->\n    <div class='massive-sphere' data-step='0'>\n      <div class='sphere-glow'></div>\n      <div class='sphere-label'>MASS / 质量</div>\n    </div>\n\n    <!-- Step 1: 黄金公式 -->\n    <div class='formula-wrap' data-step='1'>\n      <div class='formula-shimmer'></div>\n      <h2 class='formula-text'>E=mc²</h2>\n      <div class='formula-sub'>ENERGY-MASS EQUIVALENCE</div>\n    </div>\n  </div>\n\n  <!-- Step 2: 时间流动的注脚 -->\n  <div class='time-relativity-tag' data-step='2'>\n    <div class='tag-line'></div>\n    <div class='tag-content'>\n      <span class='tag-title'>RELATIVITY OF TIME</span>\n      <span class='tag-desc'>时空的相对性流动</span>\n    </div>\n  </div>\n\n  <!-- 底部页脚 -->\n  <div class='newspaper-footer'>\n    <div class='footer-line-thin'></div>\n    <div class='footer-flex'>\n      <span>ALBERT EINSTEIN</span>\n      <span>GENERAL RELATIVITY</span>\n    </div>\n  </div>\n</div>","css":".s-scene-05-root {\n  --paper-bg: #F8F8F8;\n  --ink-black: #111111;\n  --ink-muted: rgba(17,17,17,0.6);\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: var(--paper-bg);\n  color: var(--ink-black);\n  font-family: var(--sv-font-body-cn);\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n  padding: 40px 60px;\n}\n\n.paper-overlay {\n  position: absolute;\n  inset: 0;\n  background-image: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E\");\n  opacity: 0.05;\n  pointer-events: none;\n}\n\n/* 报纸风格排版 */\n.newspaper-header {\n  text-align: center;\n  z-index: 10;\n  margin-bottom: 20px;\n}\n.header-meta {\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  letter-spacing: 0.3em;\n  font-weight: 700;\n}\n.header-title {\n  font-family: 'Libre Baskerville', serif;\n  font-size: 36px;\n  font-weight: 900;\n  margin: 10px 0;\n}\n.header-line-thick {\n  height: 4px;\n  background: var(--ink-black);\n  width: 100%;\n}\n\n/* 引力场 */\n.gravity-field-container {\n  flex: 1;\n  position: relative;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n.gravity-grid {\n  position: absolute;\n  inset: 0;\n  width: 100%;\n  height: 100%;\n  z-index: 1;\n}\n.grid-lines-path {\n  fill: none;\n  stroke: var(--ink-black);\n  stroke-width: 0.5;\n  stroke-opacity: 0.15;\n}\n\n/* 球体与公式 */\n.massive-sphere {\n  position: relative;\n  width: 180px;\n  height: 180px;\n  background: var(--ink-black);\n  border-radius: 50%;\n  z-index: 5;\n  opacity: 0;\n  transform: scale(0.5);\n  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n.step-ge-0 .massive-sphere {\n  opacity: 1;\n  transform: scale(1);\n}\n.sphere-glow {\n  position: absolute;\n  inset: -20px;\n  border: 1px solid var(--ink-black);\n  border-radius: 50%;\n  animation: sphere-pulse 4s infinite ease-in-out;\n}\n@keyframes sphere-pulse {\n  0%, 100% { transform: scale(1); opacity: 0.2; }\n  50% { transform: scale(1.15); opacity: 0.5; }\n}\n.sphere-label {\n  position: absolute;\n  bottom: -30px;\n  width: 100%;\n  text-align: center;\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  font-weight: 900;\n}\n\n.formula-wrap {\n  position: absolute;\n  z-index: 10;\n  text-align: center;\n  opacity: 0;\n  transform: perspective(1000px) rotateY(-90deg);\n  transition: all 0.8s cubic-bezier(0.23, 1, 0.32, 1);\n}\n.step-ge-1 .formula-wrap {\n  opacity: 1;\n  transform: perspective(1000px) rotateY(0deg);\n}\n.formula-text {\n  font-family: var(--sv-font-display-cn);\n  font-size: 120px;\n  font-weight: 900;\n  margin: 0;\n  line-height: 1;\n  background: var(--ink-black);\n  color: var(--paper-bg);\n  padding: 0 20px;\n}\n.formula-sub {\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  letter-spacing: 0.5em;\n  margin-top: 10px;\n  font-weight: 700;\n}\n.formula-shimmer {\n  position: absolute;\n  inset: 0;\n  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);\n  transform: translateX(-100%);\n}\n.step-ge-1 .formula-shimmer {\n  animation: shimmer-swipe 1.5s 0.8s forwards;\n}\n@keyframes shimmer-swipe {\n  100% { transform: translateX(100%); }\n}\n\n/* 时间注脚 */\n.time-relativity-tag {\n  position: absolute;\n  right: 5%;\n  bottom: 25%;\n  display: flex;\n  align-items: center;\n  opacity: 0;\n  transform: translateX(30px);\n  transition: all 0.6s ease-out;\n}\n.step-ge-2 .time-relativity-tag {\n  opacity: 1;\n  transform: translateX(0);\n}\n.tag-line {\n  width: 40px;\n  height: 2px;\n  background: var(--ink-black);\n  margin-right: 15px;\n}\n.tag-title {\n  display: block;\n  font-family: var(--sv-font-mono);\n  font-size: 16px;\n  font-weight: 900;\n}\n.tag-desc {\n  font-size: 14px;\n  color: var(--ink-muted);\n}\n\n/* 页脚 */\n.newspaper-footer {\n  margin-top: auto;\n  padding-top: 20px;\n}\n.footer-line-thin {\n  height: 1px;\n  background: var(--ink-black);\n  width: 100%;\n  margin-bottom: 10px;\n}\n.footer-flex {\n  display: flex;\n  justify-content: space-between;\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  font-weight: 700;\n  text-transform: uppercase;\n}","js":"window.SceneLifecycle.register('scene-05', {\n  enter() {\n    const root = document.querySelector('[data-scene-root-id=\"scene-05\"]');\n    if (!root) return;\n    this.drawGrid(root, 0);\n  },\n  \n  drawGrid(root, distortion) {\n    const path = root.querySelector('.grid-lines-path');\n    const width = 1000;\n    const height = 562;\n    const spacing = 40;\n    const centerX = width / 2;\n    const centerY = height / 2;\n    \n    let d = '';\n\n    // 绘制横线和纵线并模拟向下凹陷的扭曲感\n    for (let x = 0; x <= width; x += spacing) {\n      d += `M ${x} 0 `;\n      for (let y = 5; y <= height; y += 5) {\n        const dist = Math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2);\n        const factor = distortion * Math.exp(-dist / 150);\n        const dx = (x - centerX) * factor * 0.2;\n        const dy = (y - centerY) * factor * 0.2 + (distortion * 50 * Math.exp(-dist / 100));\n        d += `L ${x + dx} ${y + dy} `;\n      }\n    }\n    \n    for (let y = 0; y <= height; y += spacing) {\n      d += `M 0 ${y} `;\n      for (let x = 5; x <= width; x += 5) {\n        const dist = Math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2);\n        const factor = distortion * Math.exp(-dist / 150);\n        const dx = (x - centerX) * factor * 0.2;\n        const dy = (y - centerY) * factor * 0.2 + (distortion * 50 * Math.exp(-dist / 100));\n        d += `L ${x + dx} ${y + dy} `;\n      }\n    }\n    \n    path.setAttribute('d', d);\n  },\n\n  step(index) {\n    const root = document.querySelector('[data-scene-root-id=\"scene-05\"]');\n    if (!root) return;\n\n    if (index === 0) {\n      // 重力场下陷动画\n      let start = null;\n      const duration = 1200;\n      const animate = (timestamp) => {\n        if (!start) start = timestamp;\n        const progress = Math.min((timestamp - start) / duration, 1);\n        const ease = 1 - Math.pow(1 - progress, 3); // easeOutCubic\n        this.drawGrid(root, ease);\n        if (progress < 1) requestAnimationFrame(animate);\n      };\n      requestAnimationFrame(animate);\n    }\n\n    if (index === 2) {\n      // 网格流动的波动感\n      const path = root.querySelector('.grid-lines-path');\n      let offset = 0;\n      const flow = () => {\n        offset += 0.02;\n        const distortion = 1 + Math.sin(offset) * 0.1;\n        this.drawGrid(root, distortion);\n        if (root.closest('.step-ge-2')) requestAnimationFrame(flow);\n      };\n      flow();\n    }\n  }\n});"},{"id":"scene-06","title":"微观世界：量子黎明","steps":4,"html":"<div class='s-scene-06-root' data-scene-root-id='scene-06'>\n  <div class='paper-texture'></div>\n  \n  <!-- 报头区域 -->\n  <div class='masthead'>\n    <div class='masthead-meta'>QUANTUM MECHANICS / VOL. 1925</div>\n    <div class='masthead-title'>THE MICROSCOPIC DAWN</div>\n    <div class='double-border'></div>\n  </div>\n\n  <div class='quantum-viewport'>\n    <!-- 左侧：原子模型 -->\n    <div class='atom-container' data-step='0'>\n      <div class='atom-core'>\n        <div class='nucleus'></div>\n        <div class='electron-cloud'></div>\n        <div class='orbit-ring' style='--rot:0deg'></div>\n        <div class='orbit-ring' style='--rot:60deg'></div>\n        <div class='orbit-ring' style='--rot:120deg'></div>\n      </div>\n      <div class='label-tag'>ATOMIC STRUCTURE / 原子结构</div>\n    </div>\n\n    <!-- 右侧：概率波 -->\n    <div class='wave-container'>\n      <svg class='wave-svg' viewBox='0 0 400 200' preserveAspectRatio='xMidYMid meet'>\n        <path class='wave-path' d='' />\n      </svg>\n      <div class='label-tag wave-label' data-step='1'>PROBABILITY WAVE / 概率波形</div>\n    </div>\n  </div>\n\n  <!-- 核心冲突：波粒二象性 -->\n  <div class='duality-hero' data-step='2'>\n    <div class='duality-bg-bar'></div>\n    <h1 class='duality-text'>波粒二象性</h1>\n    <div class='duality-sub'>WAVE-PARTICLE DUALITY</div>\n  </div>\n\n  <!-- 背景量化点位层 -->\n  <div class='quantum-grid-bg' data-step='3'>\n    <canvas id='quantum-canvas-06'></canvas>\n  </div>\n\n  <!-- 底部页脚 -->\n  <div class='newspaper-footer'>\n    <div class='single-line'></div>\n    <div class='footer-info'>\n      <span>PLANCK & BOHR</span>\n      <span>SUBATOMIC DISCOVERY</span>\n    </div>\n  </div>\n</div>","css":".s-scene-06-root {\n  --paper-white: #F8F8F8;\n  --ink-black: #111111;\n  --ink-soft: rgba(17, 17, 17, 0.6);\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: var(--paper-white);\n  color: var(--ink-black);\n  font-family: var(--sv-font-body-cn);\n  padding: 40px 60px;\n  display: flex;\n  flex-direction: column;\n  overflow: hidden;\n}\n\n.paper-texture {\n  position: absolute;\n  inset: 0;\n  background-image: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E\");\n  pointer-events: none;\n}\n\n/* 报头设计 */\n.masthead { margin-bottom: 30px; text-align: center; }\n.masthead-meta { font-family: var(--sv-font-mono); font-size: 14px; letter-spacing: 0.3em; font-weight: 700; }\n.masthead-title { font-family: 'Libre Baskerville', serif; font-size: 42px; font-weight: 900; margin: 10px 0; }\n.double-border { height: 6px; border-top: 3px solid var(--ink-black); border-bottom: 1px solid var(--ink-black); margin-top: 5px; }\n\n/* 视口布局 */\n.quantum-viewport {\n  flex: 1;\n  display: grid;\n  grid-template-columns: 1fr 1fr;\n  align-items: center;\n  gap: 40px;\n  z-index: 2;\n}\n\n/* 原子模型 */\n.atom-container { position: relative; display: flex; flex-direction: column; align-items: center; opacity: 0; transform: scale(0.9); transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1); }\n.step-ge-0 .atom-container { opacity: 1; transform: scale(1); }\n.atom-core { position: relative; width: 240px; height: 240px; display: flex; align-items: center; justify-content: center; }\n.nucleus { width: 30px; height: 30px; background: var(--ink-black); border-radius: 50%; box-shadow: 0 0 15px rgba(0,0,0,0.2); z-index: 10; }\n.electron-cloud {\n  position: absolute;\n  inset: 20%;\n  border: 1px dashed var(--ink-black);\n  border-radius: 50%;\n  animation: rotate-fast 1.5s linear infinite;\n  opacity: 0.3;\n}\n.orbit-ring {\n  position: absolute;\n  width: 100%;\n  height: 40%;\n  border: 1px solid var(--ink-black);\n  border-radius: 50%;\n  transform: rotate(var(--rot));\n  animation: spin-orbit 4s linear infinite;\n}\n@keyframes spin-orbit { from { transform: rotate(var(--rot)) rotateY(0deg); } to { transform: rotate(var(--rot)) rotateY(360deg); } }\n@keyframes rotate-fast { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }\n\n/* 概率波 */\n.wave-container { position: relative; height: 200px; border-left: 2px solid var(--ink-black); padding-left: 20px; }\n.wave-path { fill: none; stroke: var(--ink-black); stroke-width: 2; transition: stroke 0.3s; }\n.step-ge-1 .wave-path { animation: wave-jitter 0.1s infinite; }\n\n/* 波粒二象性标题 */\n.duality-hero {\n  position: absolute;\n  top: 55%; left: 50%;\n  transform: translate(-50%, -50%) scale(2);\n  opacity: 0;\n  z-index: 100;\n  text-align: center;\n  pointer-events: none;\n  transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n.step-ge-2 .duality-hero { opacity: 1; transform: translate(-50%, -50%) scale(1); }\n.duality-bg-bar { position: absolute; inset: -10px -40px; background: var(--ink-black); z-index: -1; transform: skewX(-15deg); }\n.duality-text { font-family: var(--sv-font-display-cn); font-size: 84px; color: var(--paper-white); margin: 0; line-height: 1; }\n.duality-sub { font-family: var(--sv-font-mono); color: var(--paper-white); letter-spacing: 0.4em; font-size: 16px; margin-top: 10px; }\n\n/* 量子点位背景 */\n.quantum-grid-bg {\n  position: absolute;\n  inset: 0;\n  z-index: 1;\n  opacity: 0;\n  transition: opacity 1s ease;\n}\n.step-ge-3 .quantum-grid-bg { opacity: 0.4; }\n\n.label-tag {\n  font-family: var(--sv-font-mono); font-size: 12px; font-weight: 700;\n  margin-top: 20px; text-transform: uppercase;\n  padding: 4px 8px; border: 1px solid var(--ink-black);\n}\n.wave-label { opacity: 0; transition: opacity 0.5s; }\n.step-ge-1 .wave-label { opacity: 1; }\n\n/* 页脚 */\n.newspaper-footer { margin-top: auto; }\n.single-line { height: 1px; background: var(--ink-black); margin-bottom: 10px; }\n.footer-info { display: flex; justify-content: space-between; font-family: var(--sv-font-mono); font-size: 12px; font-weight: 700; }","js":"window.SceneLifecycle.register('scene-06', {\n  enter() {\n    const root = document.querySelector('[data-scene-root-id=\"scene-06\"]');\n    if (!root) return;\n    this.initWave(root);\n    this.initQuantumDots(root);\n  },\n\n  initWave(root) {\n    const path = root.querySelector('.wave-path');\n    let frame = 0;\n    \n    const animate = () => {\n      frame++;\n      const points = [];\n      const isStep1 = root.classList.contains('step-ge-1');\n      const amplitude = isStep1 ? 40 + Math.random() * 20 : 20;\n      const freq = isStep1 ? 0.15 : 0.08;\n\n      for (let x = 0; x <= 400; x += 5) {\n        const y = 100 + Math.sin(x * freq + frame * 0.1) * amplitude * Math.exp(-Math.pow(x - 200, 2) / 8000);\n        points.push(`${x},${y}`);\n      }\n      \n      path.setAttribute('d', `M ${points.join(' L ')}`);\n      \n      if (isStep1) {\n        // 颜色切换模拟：黑白报纸风格下通过描边粗细和虚线模拟颜色感官\n        path.style.strokeWidth = Math.random() > 0.5 ? '3' : '1';\n        path.style.strokeDasharray = Math.random() > 0.8 ? '4 2' : 'none';\n      }\n\n      this.waveAnim = requestAnimationFrame(animate);\n    };\n    animate();\n  },\n\n  initQuantumDots(root) {\n    const canvas = root.querySelector('#quantum-canvas-06');\n    if (!canvas) return;\n    const ctx = canvas.getContext('2d');\n    const resize = () => {\n      canvas.width = root.clientWidth;\n      canvas.height = root.clientHeight;\n    };\n    window.addEventListener('resize', resize);\n    resize();\n\n    const dots = Array.from({ length: 120 }, () => ({\n      x: Math.random() * canvas.width,\n      y: Math.random() * canvas.height,\n      size: Math.random() * 2 + 1,\n      blink: Math.random() * 0.05\n    }));\n\n    const draw = () => {\n      if (!root.classList.contains('step-ge-3')) {\n        this.dotsAnim = requestAnimationFrame(draw);\n        return;\n      }\n      ctx.clearRect(0, 0, canvas.width, canvas.height);\n      ctx.fillStyle = '#111111';\n      dots.forEach(dot => {\n        dot.blink += 0.1;\n        const alpha = (Math.sin(dot.blink) + 1) / 2;\n        ctx.globalAlpha = alpha * 0.6;\n        ctx.beginPath();\n        ctx.rect(dot.x, dot.y, dot.size, dot.size);\n        ctx.fill();\n        \n        // 随机跳变体现不可预测性\n        if (Math.random() > 0.99) {\n          dot.x = Math.random() * canvas.width;\n          dot.y = Math.random() * canvas.height;\n        }\n      });\n      this.dotsAnim = requestAnimationFrame(draw);\n    };\n    draw();\n  },\n\n  step(index) {\n    // 步进逻辑已通过 CSS .step-ge-N 处理核心显隐\n    // JS 用于微调动画剧烈程度\n  },\n\n  leave() {\n    cancelAnimationFrame(this.waveAnim);\n    cancelAnimationFrame(this.dotsAnim);\n  }\n});"},{"id":"scene-07","title":"终极梦想：大统一理论","steps":3,"html":"<div class='s-scene-07-root' data-scene-root-id='scene-07'>\n  <div class='paper-texture'></div>\n\n  <!-- 报头区域 -->\n  <div class='masthead'>\n    <div class='masthead-meta'>PHYSICS FRONTIER / FINAL CHAPTER</div>\n    <div class='masthead-title'>THE THEORY OF EVERYTHING</div>\n    <div class='double-border'></div>\n  </div>\n\n  <!-- 核心画布区域 -->\n  <div class='theory-viewport'>\n    <!-- 背景分形几何 (一切的源头) -->\n    <div class='fractal-origin'>\n      <svg viewBox='0 0 800 800' class='fractal-svg'>\n        <defs>\n          <pattern id='grid-pattern' width='40' height='40' patternUnits='userSpaceOnUse'>\n            <path d='M 40 0 L 0 0 0 40' fill='none' stroke='rgba(17,17,17,0.05)' stroke-width='0.5'/>\n          </pattern>\n        </defs>\n        <rect width='100%' height='100%' fill='url(#grid-pattern)' />\n        <g class='fractal-group' stroke='#111111' fill='none' stroke-width='0.5' opacity='0.15'>\n          <!-- 由JS动态生成的几何分形路径 -->\n        </g>\n      </svg>\n    </div>\n\n    <!-- Step 0: 四大基本力球体 -->\n    <div class='force-sphere strong-force' data-step='0'>\n      <div class='sphere-core'></div>\n      <span class='force-label'>STRONG / 强力</span>\n    </div>\n    <div class='force-sphere weak-force' data-step='0'>\n      <div class='sphere-core'></div>\n      <span class='force-label'>WEAK / 弱力</span>\n    </div>\n    <div class='force-sphere em-force' data-step='0'>\n      <div class='sphere-core'></div>\n      <span class='force-label'>ELECTRO / 电磁力</span>\n    </div>\n    <div class='force-sphere gravity-force' data-step='0'>\n      <div class='sphere-core'></div>\n      <span class='force-label'>GRAVITY / 引力</span>\n    </div>\n\n    <!-- Step 1: 融合后的能量环 -->\n    <div class='unified-ring-container' data-step='1'>\n      <div class='unified-ring'></div>\n      <div class='unified-ring-glow'></div>\n      <canvas id='particle-system-07'></canvas>\n    </div>\n\n    <!-- Step 2: 核心标题 -->\n    <div class='final-title-box' data-step='2'>\n      <div class='title-line-top'></div>\n      <h1 class='main-theory-title'>万物理论</h1>\n      <div class='sub-theory-title'>THEORY OF EVERYTHING</div>\n      <div class='title-line-bottom'></div>\n    </div>\n  </div>\n\n  <!-- 底部页脚 -->\n  <div class='newspaper-footer'>\n    <div class='footer-line'></div>\n    <div class='footer-flex'>\n      <span>QUEST FOR UNIFICATION</span>\n      <span>MODERN PHYSICS ARCHIVE</span>\n      <span>NO. 001-INFINITY</span>\n    </div>\n  </div>\n\n  <!-- 背景氛围：大号浮动文字 -->\n  <div class='ambient-text'>UNIFICATION</div>\n</div>","css":".s-scene-07-root {\n  --paper-white: #FAFAFA;\n  --ink-black: #111111;\n  --ink-soft: rgba(17, 17, 17, 0.6);\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: var(--paper-white);\n  color: var(--ink-black);\n  font-family: var(--sv-font-body-cn);\n  padding: 40px 60px;\n  display: flex;\n  flex-direction: column;\n  overflow: hidden;\n}\n\n.paper-texture {\n  position: absolute;\n  inset: 0;\n  background-image: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E\");\n  pointer-events: none;\n  z-index: 5;\n}\n\n/* 报头设计 */\n.masthead { text-align: center; margin-bottom: 20px; z-index: 10; }\n.masthead-meta { font-family: var(--sv-font-mono); font-size: 14px; letter-spacing: 0.3em; font-weight: 700; }\n.masthead-title { font-family: 'Libre Baskerville', serif; font-size: 36px; font-weight: 900; margin: 8px 0; letter-spacing: -0.02em; }\n.double-border { height: 5px; border-top: 3px solid var(--ink-black); border-bottom: 1px solid var(--ink-black); }\n\n/* 视口与分形背景 */\n.theory-viewport {\n  position: relative;\n  flex: 1;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.fractal-origin {\n  position: absolute;\n  width: 80vh;\n  height: 80vh;\n  opacity: 0.8;\n}\n.fractal-svg { width: 100%; height: 100%; animation: slow-rotate 60s linear infinite; }\n@keyframes slow-rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }\n\n/* 四大作用力球体 */\n.force-sphere {\n  position: absolute;\n  width: 120px;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  transition: all 1.2s cubic-bezier(0.34, 1.56, 0.64, 1);\n  z-index: 20;\n}\n\n.sphere-core {\n  width: 40px;\n  height: 40px;\n  border-radius: 50%;\n  background: var(--ink-black);\n  margin-bottom: 10px;\n  box-shadow: 0 0 20px rgba(0,0,0,0.1);\n}\n.force-label {\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  font-weight: 700;\n  padding: 2px 6px;\n  border: 1px solid var(--ink-black);\n  white-space: nowrap;\n}\n\n/* 初始位置 */\n.strong-force { top: 10%; left: 10%; transform: translate(-50%, -50%); }\n.weak-force { top: 10%; right: 10%; transform: translate(50%, -50%); }\n.em-force { bottom: 10%; left: 10%; transform: translate(-50%, 50%); }\n.gravity-force { bottom: 10%; right: 10%; transform: translate(50%, 50%); }\n\n/* Step 1: 融合 */\n.step-ge-1 .force-sphere {\n  top: 50%; left: 50%;\n  transform: translate(-50%, -50%) scale(0);\n  opacity: 0;\n}\n\n.unified-ring-container {\n  position: absolute;\n  width: 400px;\n  height: 400px;\n  opacity: 0;\n  transform: scale(0.5);\n  transition: all 1s cubic-bezier(0.16, 1, 0.3, 1);\n}\n.step-ge-1 .unified-ring-container { opacity: 1; transform: scale(1); }\n\n.unified-ring {\n  position: absolute;\n  inset: 0;\n  border: 8px double var(--ink-black);\n  border-radius: 50%;\n  animation: spin-ring 10s linear infinite;\n}\n.unified-ring-glow {\n  position: absolute;\n  inset: -20px;\n  border: 1px dashed var(--ink-black);\n  border-radius: 50%;\n  opacity: 0.3;\n  animation: spin-ring 15s linear infinite reverse;\n}\n@keyframes spin-ring { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }\n\n#particle-system-07 {\n  position: absolute;\n  inset: -100px;\n  pointer-events: none;\n}\n\n/* Step 2: 核心标题 */\n.final-title-box {\n  position: relative;\n  z-index: 100;\n  text-align: center;\n  background: var(--paper-white);\n  padding: 20px 40px;\n  opacity: 0;\n  transform: translateY(30px);\n  transition: all 0.8s ease-out;\n}\n.step-ge-2 .final-title-box { opacity: 1; transform: translateY(0); }\n\n.main-theory-title {\n  font-family: var(--sv-font-display-cn);\n  font-size: 84px;\n  font-weight: 900;\n  margin: 10px 0;\n  line-height: 1;\n}\n.sub-theory-title {\n  font-family: var(--sv-font-mono);\n  font-size: 18px;\n  letter-spacing: 0.4em;\n  font-weight: 400;\n}\n.title-line-top, .title-line-bottom { height: 4px; background: var(--ink-black); width: 100%; }\n\n/* 页脚与修饰 */\n.newspaper-footer { margin-top: auto; padding-top: 20px; }\n.footer-line { height: 1px; background: var(--ink-black); margin-bottom: 8px; }\n.footer-flex { display: flex; justify-content: space-between; font-family: var(--sv-font-mono); font-size: 11px; font-weight: 700; text-transform: uppercase; }\n\n.ambient-text {\n  position: absolute;\n  bottom: 15%;\n  right: -5%;\n  font-family: var(--sv-font-display-cn);\n  font-size: 180px;\n  color: rgba(17,17,17,0.03);\n  font-weight: 900;\n  z-index: 1;\n  pointer-events: none;\n  animation: ambient-float 20s ease-in-out infinite alternate;\n}\n@keyframes ambient-float { from { transform: translateX(0); } to { transform: translateX(-50px); } }","js":"window.SceneLifecycle.register('scene-07', {\n  enter() {\n    const root = document.querySelector('[data-scene-root-id=\"scene-07\"]');\n    if (!root) return;\n\n    this.initFractal(root);\n    this.initParticles(root);\n  },\n\n  initFractal(root) {\n    const group = root.querySelector('.fractal-group');\n    if (!group) return;\n\n    // 生成类似神圣几何的嵌套图案\n    let paths = '';\n    for (let i = 0; i < 12; i++) {\n      const angle = (i / 12) * Math.PI * 2;\n      const x = 400 + Math.cos(angle) * 100;\n      const y = 400 + Math.sin(angle) * 100;\n      paths += `<circle cx=\"${x}\" cy=\"${y}\" r=\"150\" />`;\n      \n      // 内部连线\n      for (let j = i + 1; j < 12; j++) {\n        if (j % 3 === 0) {\n          const x2 = 400 + Math.cos((j / 12) * Math.PI * 2) * 100;\n          const y2 = 400 + Math.sin((j / 12) * Math.PI * 2) * 100;\n          paths += `<line x1=\"${x}\" y1=\"${y}\" x2=\"${x2}\" y2=\"${y2}\" />`;\n        }\n      }\n    }\n    // 添加中心六边形点阵\n    for (let r = 50; r <= 300; r += 50) {\n       paths += `<circle cx=\"400\" cy=\"400\" r=\"${r}\" stroke-dasharray=\"2 4\" />`;\n    }\n    group.innerHTML = paths;\n  },\n\n  initParticles(root) {\n    const canvas = root.querySelector('#particle-system-07');\n    if (!canvas) return;\n    const ctx = canvas.getContext('2d');\n    canvas.width = 600;\n    canvas.height = 600;\n\n    const particles = Array.from({ length: 60 }, () => ({\n      x: 300,\n      y: 300,\n      vx: (Math.random() - 0.5) * 2,\n      vy: (Math.random() - 0.5) * 4 - 2,\n      size: Math.random() * 3 + 1,\n      life: Math.random() * 1\n    }));\n\n    const animate = () => {\n      if (!root.classList.contains('step-ge-1')) {\n        this.particleAnim = requestAnimationFrame(animate);\n        return;\n      }\n\n      ctx.clearRect(0, 0, canvas.width, canvas.height);\n      ctx.fillStyle = '#111111';\n\n      particles.forEach(p => {\n        p.life -= 0.01;\n        p.x += p.vx;\n        p.y += p.vy;\n\n        if (p.life <= 0) {\n          p.x = 300 + (Math.random() - 0.5) * 40;\n          p.y = 300 + (Math.random() - 0.5) * 40;\n          p.life = 1;\n          p.vy = (Math.random() - 0.5) * 3 - 2;\n        }\n\n        ctx.globalAlpha = p.life;\n        // 粒子形状：小方块，符合报纸质感\n        ctx.fillRect(p.x, p.y, p.size, p.size);\n      });\n\n      this.particleAnim = requestAnimationFrame(animate);\n    };\n    animate();\n  },\n\n  step(index) {\n    // 步进时的额外音效感或震动可以在此处通过JS微调\n    const root = document.querySelector('[data-scene-root-id=\"scene-07\"]');\n    if (index === 1) {\n      root.style.backgroundColor = '#f0f0f0';\n      setTimeout(() => root.style.backgroundColor = '#FAFAFA', 100);\n    }\n  },\n\n  leave() {\n    cancelAnimationFrame(this.particleAnim);\n  }\n});"},{"id":"scene-08","title":"结尾：致敬未来","steps":2,"html":"<div class='s-scene-08-root' data-scene-root-id='scene-08'>\n  <div class='paper-texture'></div>\n\n  <!-- 报头区域 -->\n  <div class='masthead'>\n    <div class='masthead-meta'>SPECIAL EDITION / FUTURE PROSPECT</div>\n    <div class='masthead-title'>THE ETERNAL FRONTIER</div>\n    <div class='double-border'></div>\n  </div>\n\n  <!-- 核心星空与轨道视图 -->\n  <div class='perspective-viewport'>\n    <!-- 深邃星空层 -->\n    <div class='starfield'>\n      <canvas id='star-canvas-08'></canvas>\n    </div>\n\n    <!-- 金色轨道（SVG 路径） -->\n    <div class='golden-track-container'>\n      <svg viewBox='0 0 1000 1000' class='track-svg'>\n        <defs>\n          <linearGradient id='track-grad' x1='50%' y1='100%' x2='50%' y2='0%'>\n            <stop offset='0%' stop-color='#111111' stop-opacity='0' />\n            <stop offset='50%' stop-color='#111111' stop-opacity='1' />\n            <stop offset='100%' stop-color='#111111' stop-opacity='1' />\n          </linearGradient>\n        </defs>\n        <!-- 轨道线条 -->\n        <path d='M 500 1000 L 500 0' class='track-line main-track' />\n        <path d='M 480 1000 L 495 0' class='track-line side-track' />\n        <path d='M 520 1000 L 505 0' class='track-line side-track' />\n      </svg>\n    </div>\n\n    <!-- Step 0: 核心文字 -->\n    <div class='final-message' data-step='0'>\n      <div class='kicker'>EPILOGUE</div>\n      <h1 class='hero-text'>这场伟大的征途，才刚刚开始</h1>\n      <div class='sub-hero-text'>THE JOURNEY HAS JUST BEGUN</div>\n      <div class='message-decoration'>\n        <span class='dot'></span><span class='line'></span><span class='dot'></span>\n      </div>\n    </div>\n\n    <!-- Step 1: 冲刺全屏白光 -->\n    <div class='flash-overlay' data-step='1'></div>\n  </div>\n\n  <!-- 氛围文字 -->\n  <div class='ambient-word'>INFINITY</div>\n\n  <!-- 底部页脚 -->\n  <div class='newspaper-footer'>\n    <div class='footer-line'></div>\n    <div class='footer-flex'>\n      <span>EST. 1900 — ∞</span>\n      <span>PHYSICS TODAY / FINAL ISSUE</span>\n      <span>PAGE. LAST</span>\n    </div>\n  </div>\n</div>","css":".s-scene-08-root {\n  --paper-white: #FAFAFA;\n  --ink-black: #111111;\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: var(--paper-white);\n  color: var(--ink-black);\n  font-family: var(--sv-font-body-cn);\n  padding: 40px 60px;\n  display: flex;\n  flex-direction: column;\n  overflow: hidden;\n}\n\n.paper-texture {\n  position: absolute;\n  inset: 0;\n  background-image: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E\");\n  pointer-events: none;\n  z-index: 100;\n}\n\n/* 报头样式 */\n.masthead { text-align: center; margin-bottom: 20px; z-index: 10; }\n.masthead-meta { font-family: var(--sv-font-mono); font-size: 14px; letter-spacing: 0.3em; font-weight: 700; }\n.masthead-title { font-family: 'Libre Baskerville', serif; font-size: 32px; font-weight: 900; margin: 8px 0; letter-spacing: -0.01em; }\n.double-border { height: 5px; border-top: 3px solid var(--ink-black); border-bottom: 1px solid var(--ink-black); }\n\n/* 视口构图 */\n.perspective-viewport {\n  position: relative;\n  flex: 1;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  perspective: 1000px;\n}\n\n.starfield {\n  position: absolute;\n  inset: 0;\n  opacity: 0.15;\n}\n\n/* 金色轨道（在黑白报纸风中表现为极黑的高对比线） */\n.golden-track-container {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  display: flex;\n  justify-content: center;\n  transform: rotateX(60deg);\n  transform-origin: bottom;\n  opacity: 0.8;\n}\n\n.track-svg {\n  width: 400px;\n  height: 100%;\n}\n\n.track-line {\n  fill: none;\n  stroke: var(--ink-black);\n  stroke-dasharray: 1000;\n  stroke-dashoffset: 1000;\n  animation: draw-track 4s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n}\n\n.main-track { stroke-width: 4; }\n.side-track { stroke-width: 1; opacity: 0.3; }\n\n@keyframes draw-track { to { stroke-dashoffset: 0; } }\n\n/* Step 0: 核心文字 */\n.final-message {\n  position: relative;\n  z-index: 50;\n  text-align: center;\n  opacity: 0;\n  transform: translateY(20px);\n  transition: all 0.8s cubic-bezier(0.22, 1, 0.36, 1) 0.3s;\n}\n.step-ge-0 .final-message { opacity: 1; transform: translateY(0); }\n\n.kicker {\n  font-family: var(--sv-font-mono);\n  font-size: 16px;\n  letter-spacing: 0.5em;\n  margin-bottom: 16px;\n  opacity: 0.6;\n}\n\n.hero-text {\n  font-family: var(--sv-font-display-cn);\n  font-size: 64px;\n  font-weight: 900;\n  line-height: 1.2;\n  margin: 0 0 10px 0;\n}\n\n.sub-hero-text {\n  font-family: 'Libre Baskerville', serif;\n  font-size: 20px;\n  letter-spacing: 0.3em;\n  opacity: 0.8;\n}\n\n.message-decoration {\n  margin-top: 30px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  gap: 15px;\n}\n.message-decoration .dot { width: 6px; height: 6px; background: var(--ink-black); }\n.message-decoration .line { width: 100px; height: 1px; background: var(--ink-black); opacity: 0.3; }\n\n/* Step 1: 冲刺与变白 */\n.flash-overlay {\n  position: absolute;\n  inset: 0;\n  background: #FFFFFF;\n  z-index: 200;\n  opacity: 0;\n  pointer-events: none;\n  transition: opacity 1.2s cubic-bezier(0.7, 0, 0.3, 1);\n}\n.step-ge-1 .flash-overlay { opacity: 1; }\n\n/* 动画影响 */\n.step-ge-1 .perspective-viewport {\n  transform: scale(2) translateZ(500px);\n  transition: transform 1.5s cubic-bezier(0.7, 0, 0.3, 1);\n}\n\n/* 页脚 */\n.newspaper-footer { margin-top: auto; padding-top: 20px; }\n.footer-line { height: 1px; background: var(--ink-black); margin-bottom: 8px; }\n.footer-flex { display: flex; justify-content: space-between; font-family: var(--sv-font-mono); font-size: 12px; font-weight: 700; }\n\n.ambient-word {\n  position: absolute;\n  bottom: 10%;\n  left: -2%;\n  font-size: 15vw;\n  font-family: var(--sv-font-display-cn);\n  font-weight: 900;\n  color: rgba(17,17,17,0.03);\n  pointer-events: none;\n  animation: slide-bg 30s linear infinite;\n}\n@keyframes slide-bg { from { transform: translateX(0); } to { transform: translateX(100px); } }","js":"window.SceneLifecycle.register('scene-08', {\n  enter() {\n    const root = document.querySelector('[data-scene-root-id=\"scene-08\"]');\n    if (!root) return;\n    this.initStars(root);\n  },\n\n  initStars(root) {\n    const canvas = root.querySelector('#star-canvas-08');\n    if (!canvas) return;\n    const ctx = canvas.getContext('2d');\n    \n    const resize = () => {\n      canvas.width = root.clientWidth;\n      canvas.height = root.clientHeight;\n    };\n    window.addEventListener('resize', resize);\n    resize();\n\n    const stars = Array.from({ length: 150 }, () => ({\n      x: Math.random() * canvas.width,\n      y: Math.random() * canvas.height,\n      size: Math.random() * 1.5 + 0.5,\n      opacity: Math.random()\n    }));\n\n    const animate = () => {\n      ctx.clearRect(0, 0, canvas.width, canvas.height);\n      ctx.fillStyle = '#111111';\n\n      stars.forEach(s => {\n        s.opacity += (Math.random() - 0.5) * 0.05;\n        if (s.opacity < 0.1) s.opacity = 0.1;\n        if (s.opacity > 0.8) s.opacity = 0.8;\n        \n        ctx.globalAlpha = s.opacity;\n        ctx.fillRect(s.x, s.y, s.size, s.size); // 报纸风格使用方形粒子点\n      });\n\n      this.animReq = requestAnimationFrame(animate);\n    };\n    animate();\n  },\n\n  step(index) {\n    const root = document.querySelector('[data-scene-root-id=\"scene-08\"]');\n    if (index === 1) {\n      // 可以添加震动或微调效果\n    }\n  },\n\n  leave() {\n    cancelAnimationFrame(this.animReq);\n  }\n});"}]</script>
  <script defer src="https://unpkg.com/lucide@latest"></script>
  <script defer src="https://code.iconify.design/iconify-icon/2.3.0/iconify-icon.min.js"></script>
  <script defer src="https://unpkg.com/@lottiefiles/lottie-player@2.0.12/dist/lottie-player.js"></script>
  <script>
    (function () {
      var state = { sceneId: 'scene-08', step: 0, direction: 1 };
      var TRANSITION_PRESETS={'door':{'--sv-stage-perspective':'900px','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'rotateY(90deg)','--sv-trans-enter-filter':'blur(6px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'rotateY(0deg)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'rotateY(-90deg)','--sv-trans-exit-filter':'blur(4px)','--sv-trans-duration':'0.65s','--sv-trans-ease':'cubic-bezier(0.36, 0, 0.66, 1)'},'burst':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'scale(0.1)','--sv-trans-enter-filter':'blur(40px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'scale(1.6)','--sv-trans-exit-filter':'blur(24px)','--sv-trans-duration':'0.55s','--sv-trans-ease':'cubic-bezier(0.34, 1.3, 0.64, 1)'},'slam':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'translateX(var(--scene-enter-offset, 180px)) rotate(8deg)','--sv-trans-enter-filter':'blur(24px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'translateX(0) rotate(0deg)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'translateX(var(--scene-exit-offset, -120px)) rotate(-5deg)','--sv-trans-exit-filter':'blur(18px)','--sv-trans-duration':'0.50s','--sv-trans-ease':'cubic-bezier(0.2, 0.8, 0.2, 1)'},'push-up':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'1','--sv-trans-enter-transform':'translateY(105%)','--sv-trans-enter-filter':'blur(0px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'translateY(0)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0.3','--sv-trans-exit-transform':'translateY(-60px)','--sv-trans-exit-filter':'blur(8px)','--sv-trans-duration':'0.55s','--sv-trans-ease':'cubic-bezier(0.22, 1, 0.36, 1)'},'spin':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'rotate(180deg) scale(0.2)','--sv-trans-enter-filter':'blur(24px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'rotate(0deg) scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'rotate(-90deg) scale(0.4)','--sv-trans-exit-filter':'blur(16px)','--sv-trans-duration':'0.55s','--sv-trans-ease':'cubic-bezier(0.34, 1.3, 0.64, 1)'},'tunnel':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'scale(1.28)','--sv-trans-enter-filter':'blur(12px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'scale(0.88)','--sv-trans-exit-filter':'blur(10px)','--sv-trans-duration':'0.60s','--sv-trans-ease':'cubic-bezier(0.22, 1, 0.36, 1)'},'glitch':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'scale(0.95)','--sv-trans-enter-filter':'blur(2px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'scale(0.95)','--sv-trans-exit-filter':'none','--sv-trans-duration':'0.25s','--sv-trans-ease':'ease-out'},};
      // Per-scene transition mapping — built from meta at init time
      var sceneTransitionMap = {};
      var previousSceneId = null;
      var exitCleanupTimer = null;
      var isPlaying = false;
      var playTimer = null;
      var progressRaf = null;
      var STEP_INTERVAL_MS = 1400;
      var SCENE_FINISH_PAUSE_MS = 2000;
      var autoplayFromFirstScene = false;
      var progressWrap = document.getElementById('sv-progress-wrap');
      var progressFill = document.getElementById('sv-progress-fill');
      var progressThumb = document.getElementById('sv-progress-thumb');
      var playBtn = document.getElementById('sv-play-btn');
      var expandBtn = document.getElementById('sv-expand-btn');
      var statusText = document.getElementById('sv-status-text');
      var sceneButtonList = Array.prototype.slice.call(document.querySelectorAll('[data-panel-scene-id]'));
      var sceneRetryButtonList = Array.prototype.slice.call(document.querySelectorAll('[data-retry-scene-id]'));
      var editorOverlay = document.getElementById('sv-editor-overlay');
      var editorBackdrop = document.getElementById('sv-editor-backdrop');
      var editorSheet = document.getElementById('sv-editor-sheet');
      var editorResizeHandle = document.getElementById('sv-editor-resize-handle');
      var editorCloseBtn = document.getElementById('sv-editor-close-btn');
      var editorSaveBtn = document.getElementById('sv-editor-save-btn');
      var editorList = document.getElementById('sv-editor-list');
      var editorSaveTip = document.getElementById('sv-editor-save-tip');
      var editorTipTimer = null;
      var isEditorOpen = false;
      var isEditorDirty = false;
      var editorHeightVh = 50;
      var hostCaps = { canRetry: false, canEditPanel: false, locale: 'zh', theme: 'dark' };
      var metaJson = document.getElementById('__SVGVIDEO_META__');
      var meta = { scenes: [] };
      try {
        meta = JSON.parse((metaJson && metaJson.textContent) || '{}');
      } catch (e) {
        meta = { scenes: [] };
      }
      var metaSceneMap = {};
      var metaScenes = Array.isArray(meta.scenes) ? meta.scenes : [];
      metaScenes.forEach(function (scene) {
        if (scene && typeof scene.id === 'string' && scene.id) {
          metaSceneMap[scene.id] = scene;
          sceneTransitionMap[scene.id] = (typeof scene.transition === 'string' && TRANSITION_PRESETS[scene.transition]) ? scene.transition : 'door';
        }
      });
      function refreshFrameworkIcons(root) {
        var refreshRoot = root || document;
        try {
          if (window.lucide && typeof window.lucide.createIcons === 'function') {
            window.lucide.createIcons({ root: refreshRoot });
          }
        } catch (iconErr) {
          console.warn('[svg-video] lucide refresh failed', iconErr);
        }
      }
      window.__SVGVIDEO_REFRESH_ICONS = refreshFrameworkIcons;
      var sceneModels = Array.prototype.slice.call(document.querySelectorAll('#stage > [data-framework-scene-id], #stage > [data-scene-id]')).map(function (node, index) {
        var sceneId = node.getAttribute('data-framework-scene-id') || node.getAttribute('data-scene-id') || ('scene-' + (index + 1));
        var metaScene = metaSceneMap[sceneId] || {};
        var sceneTitle = typeof metaScene.title === 'string' && metaScene.title ? metaScene.title : ('分镜' + (index + 1));
        var sceneSteps = Math.max(1, Number(metaScene.steps) || 1);
        var sceneStatus = typeof metaScene.status === 'string' ? metaScene.status : 'pending';
        var scenePrompt = typeof metaScene.prompt === 'string' ? metaScene.prompt : '';
        var sceneScript = typeof metaScene.scriptText === 'string' ? metaScene.scriptText : '';
        var sceneAudioObjectKey = typeof metaScene.audioObjectKey === 'string' ? metaScene.audioObjectKey : '';
        var sceneAudioDurationMs = Number(metaScene.audioDurationMs) > 0 ? Number(metaScene.audioDurationMs) : 0;
        var sceneVoiceName = typeof metaScene.voiceName === 'string' ? metaScene.voiceName : '';
        var sceneVoiceStyle = typeof metaScene.voiceStyle === 'string' ? metaScene.voiceStyle : '';
        var relatedSceneIds = Array.isArray(metaScene.relatedSceneIds) ? metaScene.relatedSceneIds : [];
        return {
          id: sceneId,
          title: sceneTitle,
          steps: sceneSteps,
          status: sceneStatus,
          prompt: scenePrompt,
          scriptText: sceneScript,
          audioObjectKey: sceneAudioObjectKey,
          audioDurationMs: sceneAudioDurationMs,
          voiceName: sceneVoiceName,
          voiceStyle: sceneVoiceStyle,
          relatedSceneIds: relatedSceneIds,
          transition: sceneTransitionMap[sceneId] || 'door'
        };
      });
      if (!sceneModels.length && metaScenes.length) {
        sceneModels = metaScenes.map(function (scene, index) {
          return {
            id: scene.id || ('scene-' + (index + 1)),
            title: scene.title || ('分镜' + (index + 1)),
            steps: Math.max(1, Number(scene.steps) || 1),
            status: typeof scene.status === 'string' ? scene.status : 'pending',
            prompt: typeof scene.prompt === 'string' ? scene.prompt : '',
            scriptText: typeof scene.scriptText === 'string' ? scene.scriptText : '',
            audioObjectKey: typeof scene.audioObjectKey === 'string' ? scene.audioObjectKey : '',
            audioDurationMs: Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0,
            voiceName: typeof scene.voiceName === 'string' ? scene.voiceName : '',
            voiceStyle: typeof scene.voiceStyle === 'string' ? scene.voiceStyle : '',
            relatedSceneIds: Array.isArray(scene.relatedSceneIds) ? scene.relatedSceneIds : [],
            transition: sceneTransitionMap[scene.id] || 'door'
          };
        });
      }
      function i18nText(zh, en) {
        return hostCaps.locale === 'en' ? en : zh;
      }
      function applyI18nTexts() {
        var toolbarTitleEl = document.getElementById('sv-toolbar-title');
        var titleEl = document.getElementById('sv-editor-header-title');
        if (toolbarTitleEl) toolbarTitleEl.textContent = i18nText('分镜面板', 'Storyboard');
        if (titleEl) titleEl.textContent = i18nText('分镜详情编辑', 'Storyboard details');
        if (expandBtn) {
          var expandText = i18nText('展开分镜详情', 'Open storyboard details');
          expandBtn.setAttribute('aria-label', expandText);
          expandBtn.setAttribute('title', expandText);
        }
        if (editorSaveBtn) editorSaveBtn.textContent = isEditorDirty ? i18nText('保存*', 'Save*') : i18nText('保存', 'Save');
        if (editorCloseBtn) editorCloseBtn.textContent = i18nText('关闭', 'Close');
        if (editorSaveTip) editorSaveTip.textContent = i18nText('已保存', 'Saved');
      }
      function clampEditorHeightVh(value) {
        return Math.max(32, Math.min(80, Number(value) || 50));
      }
      function applyEditorHeight(vh) {
        editorHeightVh = clampEditorHeightVh(vh);
        document.documentElement.style.setProperty('--sv-editor-height', editorHeightVh + 'vh');
      }
      function persistMetaToScript() {
        meta.title = typeof meta.title === 'string' ? meta.title : '';
        meta.version = meta.version || 1;
        meta.scenes = sceneModels.map(function (scene) {
          return {
            id: scene.id,
            title: scene.title || '',
            steps: Math.max(1, Number(scene.steps) || 1),
            status: scene.status || 'pending',
            prompt: scene.prompt || '',
            scriptText: scene.scriptText || '',
            audioObjectKey: scene.audioObjectKey || '',
            audioDurationMs: Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0,
            voiceName: scene.voiceName || '',
            voiceStyle: scene.voiceStyle || '',
            relatedSceneIds: Array.isArray(scene.relatedSceneIds) ? scene.relatedSceneIds : [],
            transition: scene.transition || 'door'
          };
        });
        if (metaJson) metaJson.textContent = JSON.stringify(meta);
      }
      function showSavedTip() {
        if (!editorSaveTip) return;
        if (editorTipTimer) {
          clearTimeout(editorTipTimer);
          editorTipTimer = null;
        }
        editorSaveTip.classList.add('is-visible');
        editorTipTimer = setTimeout(function () {
          editorSaveTip.classList.remove('is-visible');
        }, 1200);
      }
      function markEditorDirty() {
        isEditorDirty = true;
        applyI18nTexts();
      }
      function clearEditorDirty() {
        isEditorDirty = false;
        applyI18nTexts();
      }
      function getStatusLabel(status) {
        if (status === 'success') return i18nText('已生成', 'Done');
        if (status === 'generating') return i18nText('生成中', 'Generating');
        if (status === 'failed') return i18nText('失败', 'Failed');
        return i18nText('未生成', 'Pending');
      }
      function getStatusClass(status) {
        if (status === 'generating') return 'is-generating';
        if (status === 'success') return 'is-success';
        return 'is-failed';
      }
      function getRetryButtonInnerHtml(isGenerating) {
        if (isGenerating) return '<span class="scene-chip-retry-spinner"></span>';
        return '<svg class="scene-chip-retry-icon" viewBox="0 0 1024 1024" width="16" height="16" fill="currentColor"><path d="M698.569 531.322a39.825 39.825 0 0 0-23.898 7.949c-17.702 13.216-21.34 38.28-8.124 55.982l95.716 128.212c7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949c17.702-13.216 21.34-38.28 8.124-55.982l-95.716-128.212c-7.853-10.521-19.892-16.074-32.084-16.073z" /><path d="M922.498 563.818a39.825 39.825 0 0 0-23.898 7.949l-128.212 95.716c-17.703 13.216-21.34 38.28-8.124 55.982 7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949l128.212-95.716c17.702-13.216 21.34-38.28 8.124-55.982-7.854-10.521-19.893-16.074-32.084-16.073zM229.652 282.148a39.825 39.825 0 0 0-23.898 7.949c-17.702 13.216-21.34 38.28-8.124 55.982l95.716 128.212c7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949c17.702-13.216 21.34-38.28 8.124-55.982l-95.716-128.212c-7.854-10.521-19.892-16.074-32.084-16.073z" /><path d="M229.652 282.148a39.825 39.825 0 0 0-23.898 7.949L77.542 385.813c-17.702 13.216-21.34 38.28-8.124 55.982 7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949l128.213-95.716c17.702-13.216 21.34-38.28 8.124-55.982-7.855-10.521-19.893-16.073-32.085-16.073z" /><path d="M614.968 763.65c-44.13 18.171-94.005 25.121-146.168 16.968C353.747 762.636 261.364 670.253 243.381 555.2c-9.681-61.936 1.932-120.646 28.337-170.344l-58.657-58.657c-40.139 64.442-60.11 142.746-50.806 226.152 17.993 161.306 148.088 291.401 309.394 309.394 62.041 6.92 121.259-2.357 174.048-24.083 26.535-10.921 33.625-45.203 13.335-65.493l-0.098-0.098c-11.555-11.555-28.854-14.643-43.966-8.421zM409.033 260.35c44.131-18.171 94.007-25.122 146.169-16.968 115.051 17.985 207.431 110.365 225.416 225.416 9.682 61.935-1.931 120.646-28.337 170.346l58.658 58.658c40.139-64.443 60.109-142.747 50.805-226.155-17.993-161.305-148.087-291.399-309.391-309.391-62.042-6.92-121.26 2.356-174.05 24.082-26.535 10.921-33.625 45.203-13.335 65.493l0.099 0.099c11.555 11.554 28.854 14.642 43.966 8.42z" /></svg>';
      }
      function setSceneStatus(sceneId, status) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return;
        sceneModels[index].status = status;
        persistMetaToScript();
        var statusClass = getStatusClass(status);
        var chipWrap = document.querySelector('[data-chip-scene-id="' + sceneId + '"]');
        if (chipWrap) {
          chipWrap.classList.remove('is-success', 'is-failed', 'is-generating');
          chipWrap.classList.add(statusClass);
          var chipBtn = chipWrap.querySelector('.scene-chip');
          if (chipBtn) {
            chipBtn.classList.remove('is-success', 'is-failed', 'is-generating');
            chipBtn.classList.add(statusClass);
          }
          var retryBtn = chipWrap.querySelector('.scene-chip-retry');
          if (retryBtn) {
            retryBtn.innerHTML = getRetryButtonInnerHtml(status === 'generating');
            if (status === 'generating') retryBtn.setAttribute('disabled', 'disabled');
            else retryBtn.removeAttribute('disabled');
          }
        }
        renderStatus();
      }
      function requestSceneRetry(sceneId) {
        if (!hostCaps.canRetry) return;
        var idx = getSceneIndexById(sceneId);
        if (idx < 0) return;
        var scene = sceneModels[idx];
        setSceneStatus(sceneId, 'generating');
        focusScene(sceneId);
        if (window.parent && window.parent !== window) {
          window.parent.postMessage(
            { type: '__SVGVIDEO_RETRY_SCENE', sceneId: sceneId, prompt: scene.prompt || '' },
            '*'
          );
        }
      }
      function renderEditorList() {
        if (!editorList) return;
        editorList.innerHTML = '';
        var fragment = document.createDocumentFragment();
        sceneModels.forEach(function (scene, index) {
          var item = document.createElement('section');
          item.className = 'sv-editor-item';
          item.setAttribute('data-editor-scene-id', scene.id);

          var head = document.createElement('div');
          head.className = 'sv-editor-item-head';

          var jumpBtn = document.createElement('button');
          jumpBtn.type = 'button';
          jumpBtn.className = 'sv-editor-item-title';
          jumpBtn.textContent = i18nText('分镜', 'Scene') + (index + 1) + ' · ' + (scene.title || '');
          jumpBtn.addEventListener('click', function () {
            focusScene(scene.id);
          });
          head.appendChild(jumpBtn);

          var statusWrap = document.createElement('div');
          statusWrap.className = 'sv-editor-status-wrap';
          var status = document.createElement('span');
          status.className = 'sv-editor-status';
          status.textContent = getStatusLabel(scene.status);
          statusWrap.appendChild(status);
          var retryBtn = document.createElement('button');
          retryBtn.type = 'button';
          retryBtn.className = 'scene-chip-retry sv-editor-retry';
          retryBtn.setAttribute('aria-label', i18nText('重新生成当前分镜', 'Retry this scene'));
          retryBtn.setAttribute('title', i18nText('重新生成当前分镜', 'Retry this scene'));
          retryBtn.innerHTML = getRetryButtonInnerHtml(scene.status === 'generating');
          if (scene.status === 'generating' || !hostCaps.canRetry) retryBtn.setAttribute('disabled', 'disabled');
          retryBtn.addEventListener('click', function (event) {
            event.preventDefault();
            event.stopPropagation();
            requestSceneRetry(scene.id);
            if (isEditorOpen) renderEditorList();
          });
          statusWrap.appendChild(retryBtn);
          head.appendChild(statusWrap);

          item.appendChild(head);

          var scriptField = document.createElement('label');
          scriptField.className = 'sv-editor-field';
          var scriptLabel = document.createElement('span');
          scriptLabel.className = 'sv-editor-label';
          scriptLabel.textContent = i18nText('脚本', 'Script');
          var scriptInput = document.createElement('div');
          scriptInput.className = 'sv-editor-script-view';
          scriptInput.setAttribute('data-field-scene-id', scene.id);
          scriptInput.textContent = scene.scriptText || '';
          scriptField.appendChild(scriptLabel);
          scriptField.appendChild(scriptInput);
          item.appendChild(scriptField);

          var promptField = document.createElement('label');
          promptField.className = 'sv-editor-field';
          var promptLabel = document.createElement('span');
          promptLabel.className = 'sv-editor-label';
          promptLabel.textContent = i18nText('提示词', 'Prompt');
          var promptInput = document.createElement('textarea');
          promptInput.className = 'sv-editor-textarea';
          promptInput.setAttribute('data-field-scene-id', scene.id);
          promptInput.setAttribute('data-field', 'prompt');
          promptInput.value = scene.prompt || '';
          promptInput.addEventListener('click', function (event) {
            event.stopPropagation();
          });
          promptInput.addEventListener('input', function () {
            scene.prompt = promptInput.value;
            markEditorDirty();
          });
          promptField.appendChild(promptLabel);
          promptField.appendChild(promptInput);
          item.appendChild(promptField);
          item.addEventListener('click', function () {
            focusScene(scene.id);
          });

          fragment.appendChild(item);
        });
        editorList.appendChild(fragment);
        highlightActiveEditorItem();
      }
      function highlightActiveEditorItem() {
        if (!editorList) return;
        var itemList = Array.prototype.slice.call(editorList.querySelectorAll('[data-editor-scene-id]'));
        itemList.forEach(function (item) {
          if (item.getAttribute('data-editor-scene-id') === state.sceneId) item.classList.add('is-active');
          else item.classList.remove('is-active');
        });
      }
      function openEditor() {
        if (!hostCaps.canEditPanel) return;
        if (!editorOverlay) return;
        renderEditorList();
        applyEditorHeight(editorHeightVh);
        editorOverlay.classList.add('is-open');
        editorOverlay.setAttribute('aria-hidden', 'false');
        document.body.classList.add('sv-editor-open');
        isEditorOpen = true;
      }
      function closeEditor() {
        if (!editorOverlay) return;
        editorOverlay.classList.remove('is-open');
        editorOverlay.setAttribute('aria-hidden', 'true');
        document.body.classList.remove('sv-editor-open');
        isEditorOpen = false;
      }
      function saveEditor() {
        persistMetaToScript();
        clearEditorDirty();
        showSavedTip();
        if (window.parent && window.parent !== window) {
          window.parent.postMessage({ type: '__SVGVIDEO_META_UPDATED', meta: meta }, '*');
        }
      }
      function getTotalSteps() {
        return sceneModels.reduce(function (sum, scene) { return sum + Math.max(1, Number(scene.steps) || 1); }, 0);
      }
      function getSceneIndexById(sceneId) {
        for (var i = 0; i < sceneModels.length; i++) {
          if (sceneModels[i].id === sceneId) return i;
        }
        return -1;
      }
      function getSceneInitialStep(sceneId) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return 0;
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        return Math.max(0, maxSteps - 1);
      }
      function focusScene(sceneId) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return;
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        stopPlayback();
        window.__SVGVIDEO_SET_STATE(sceneId, 0, 1);
        if (maxSteps > 1) {
          setTimeout(function () {
            window.__SVGVIDEO_SET_STATE(sceneId, Math.max(0, maxSteps - 1), 1);
          }, 90);
        }
      }
      function getProgressPercent(sceneId, step) {
        var total = getTotalSteps();
        if (!total) return 0;
        var index = getSceneIndexById(sceneId);
        if (index < 0) return 0;
        var completed = 0;
        for (var i = 0; i < index; i++) completed += Math.max(1, Number(sceneModels[i].steps) || 1);
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        var localStep = Math.max(0, Math.min(maxSteps - 1, Number(step) || 0));
        return Math.max(0, Math.min(100, ((completed + localStep) / total) * 100));
      }
      function updateProgressUi(percent) {
        var pct = Math.max(0, Math.min(100, percent || 0));
        if (progressFill) progressFill.style.width = pct + '%';
        if (progressThumb) progressThumb.style.left = pct + '%';
      }
      function stopProgressAnimation() {
        if (progressRaf) {
          cancelAnimationFrame(progressRaf);
          progressRaf = null;
        }
      }
      function startProgressSegment(fromPercent, toPercent, durationMs) {
        stopProgressAnimation();
        var from = Math.max(0, Math.min(100, Number(fromPercent) || 0));
        var to = Math.max(0, Math.min(100, Number(toPercent) || 0));
        var duration = Math.max(1, Number(durationMs) || 1);
        if (duration <= 1 || to <= from) {
          updateProgressUi(to);
          return;
        }
        var startAt = performance.now();
        var tick = function (now) {
          if (!isPlaying) {
            stopProgressAnimation();
            return;
          }
          var elapsed = now - startAt;
          var ratio = Math.max(0, Math.min(1, elapsed / duration));
          var current = from + (to - from) * ratio;
          updateProgressUi(current);
          if (ratio < 1) {
            progressRaf = requestAnimationFrame(tick);
          } else {
            stopProgressAnimation();
          }
        };
        progressRaf = requestAnimationFrame(tick);
      }
      function getPlaybackSegment(sceneIndex, step) {
        var scene = sceneModels[sceneIndex];
        if (!scene) return null;
        var currentPercent = getProgressPercent(scene.id, step);
        var maxSteps = Math.max(1, Number(scene.steps) || 1);
        if (step < maxSteps - 1) {
          return {
            from: currentPercent,
            to: getProgressPercent(scene.id, step + 1),
            duration: STEP_INTERVAL_MS
          };
        }
        if (sceneIndex < sceneModels.length - 1) {
          var nextScene = sceneModels[sceneIndex + 1];
          var nextPercent = nextScene ? getProgressPercent(nextScene.id, 0) : currentPercent;
          return {
            from: currentPercent,
            to: nextPercent,
            duration: SCENE_FINISH_PAUSE_MS
          };
        }
        return {
          from: currentPercent,
          to: 100,
          duration: STEP_INTERVAL_MS
        };
      }
      function renderStatus() {
        if (!statusText) return;
        var done = sceneModels.filter(function (scene) { return scene.status === 'success'; }).length;
        var pending = sceneModels.filter(function (scene) { return scene.status === 'pending' || scene.status === 'generating'; }).length;
        var failed = sceneModels.filter(function (scene) { return scene.status === 'failed'; }).length;
        statusText.textContent = '已生成 ' + done + '/' + sceneModels.length + ' · 待生成 ' + pending + ' · 失败 ' + failed;
      }
      function updatePlayButton() {
        if (!playBtn) return;
        playBtn.innerHTML = isPlaying
          ? '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><rect x="6" y="5" width="4" height="14" rx="1"></rect><rect x="14" y="5" width="4" height="14" rx="1"></rect></svg>'
          : '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M7 5v14l11-7z"></path></svg>';
        playBtn.setAttribute('aria-label', isPlaying ? '暂停播放' : '播放分镜');
        playBtn.setAttribute('title', isPlaying ? '暂停播放' : '播放分镜');
      }
      function applyHostCaps() {
        if (hostCaps.canRetry) document.body.classList.add('sv-host-can-retry');
        else document.body.classList.remove('sv-host-can-retry');
        if (hostCaps.canEditPanel) document.body.classList.add('sv-host-can-edit-panel');
        else document.body.classList.remove('sv-host-can-edit-panel');
        if (hostCaps.theme === 'light') document.body.classList.add('sv-theme-light');
        else document.body.classList.remove('sv-theme-light');
      }
      function highlightActiveSceneButton() {
        sceneButtonList.forEach(function (button) {
          var targetId = button.getAttribute('data-panel-scene-id');
          if (targetId === state.sceneId) button.classList.add('is-active');
          else button.classList.remove('is-active');
        });
      }
      function stopPlayback() {
        if (playTimer) {
          clearTimeout(playTimer);
          playTimer = null;
        }
        stopProgressAnimation();
        isPlaying = false;
        updatePlayButton();
      }
      function startPlayback() {
        if (!sceneModels.length) return;
        stopPlayback();
        var sceneIndex = Math.max(0, getSceneIndexById(state.sceneId));
        var step = 0;
        var applyPlaybackState = function (direction) {
          var scene = sceneModels[sceneIndex];
          if (!scene) return false;
          window.__SVGVIDEO_SET_STATE(scene.id, step, direction);
          updateProgressUi(getProgressPercent(scene.id, step));
          var segment = getPlaybackSegment(sceneIndex, step);
          if (segment) startProgressSegment(segment.from, segment.to, segment.duration);
          return true;
        };
        var scheduleAdvance = function (delay) {
          playTimer = setTimeout(function () {
            var currentScene = sceneModels[sceneIndex];
            if (!currentScene) {
              stopPlayback();
              return;
            }
            var maxSteps = Math.max(1, Number(currentScene.steps) || 1);
            if (step < maxSteps - 1) {
              step += 1;
              applyPlaybackState(1);
              scheduleAdvance(STEP_INTERVAL_MS);
              return;
            }
            if (sceneIndex < sceneModels.length - 1) {
              playTimer = setTimeout(function () {
                sceneIndex += 1;
                step = 0;
                if (!applyPlaybackState(1)) {
                  stopPlayback();
                  return;
                }
                scheduleAdvance(STEP_INTERVAL_MS);
              }, SCENE_FINISH_PAUSE_MS);
              return;
            }
            stopPlayback();
          }, delay);
        };
        isPlaying = true;
        updatePlayButton();
        if (!applyPlaybackState(1)) {
          stopPlayback();
          return;
        }
        scheduleAdvance(STEP_INTERVAL_MS);
      }
      window.SceneLifecycle = {
        handlers: {},
        register: function (sceneId, handler) { this.handlers[sceneId] = handler || {}; }
      };

      (function () {
        var sceneDataJson = document.getElementById('__SVGVIDEO_SCENE_DATA__');
        var runtimeScenes = [];
        try {
          runtimeScenes = JSON.parse((sceneDataJson && sceneDataJson.textContent) || '[]');
        } catch (_e) {
          runtimeScenes = [];
        }
        runtimeScenes.forEach(function (scene) {
          if (!scene || typeof scene.id !== 'string') return;
          var js = typeof scene.js === 'string' ? scene.js.trim() : '';
          if (!js) return;
          try {
            var factory = new Function(js);
            factory.call(window);
          } catch (err) {
            console.error('[svg-video] scene runtime failed', scene.id, err);
          }
        });
        refreshFrameworkIcons(document);
      })();

      function applyStepVisibility(sceneEl) {
        var stepNodes = sceneEl.querySelectorAll('[data-step], [data-show-step]');
        stepNodes.forEach(function (node) {
          if (node && (node.hasAttribute('data-framework-scene-id') || node.hasAttribute('data-scene-id'))) return;
          var hasShowStepAttr = node.hasAttribute('data-show-step');
          var minStep = Number(hasShowStepAttr ? node.getAttribute('data-show-step') : node.getAttribute('data-step') || '0');
          var visible = state.step >= minStep;
          node.style.opacity = visible ? '1' : '0';
          node.style.visibility = visible ? 'visible' : 'hidden';
          node.style.pointerEvents = visible ? 'auto' : 'none';
          node.style.transform = visible ? 'translateY(0)' : 'translateY(8px)';
          node.style.filter = visible ? 'blur(0px)' : 'blur(4px)';
        });
      }
      function syncSceneStepClasses(sceneEl, sceneId, stepValue) {
        if (!sceneEl) return;
        var sceneRoot = sceneEl.querySelector('.s-' + sceneId + '-root');
        if (!sceneRoot) {
          sceneRoot = sceneEl.querySelector('[data-scene-root-id="' + sceneId + '"]');
        }
        if (!sceneRoot) {
          sceneRoot = sceneEl.querySelector('[data-scene-id="' + sceneId + '"]');
        }
        if (!sceneRoot) return;
        var logicalStep = Number(stepValue) || 0;
        sceneRoot.classList.remove('step-ge-0', 'step-ge-1', 'step-ge-2', 'step-ge-3', 'step-ge-4', 'step-ge-5', 'step-ge-6');
        sceneRoot.classList.add('step-ge-0');
        if (logicalStep >= 1) sceneRoot.classList.add('step-ge-1');
        if (logicalStep >= 2) sceneRoot.classList.add('step-ge-2');
        if (logicalStep >= 3) sceneRoot.classList.add('step-ge-3');
        if (logicalStep >= 4) sceneRoot.classList.add('step-ge-4');
        if (logicalStep >= 5) sceneRoot.classList.add('step-ge-5');
        if (logicalStep >= 6) sceneRoot.classList.add('step-ge-6');
      }
      function applySceneState() {
        var scenes = document.querySelectorAll('#stage > [data-framework-scene-id], #stage > [data-scene-id]');
        var currentSceneEl = null;
        var previousSceneEl = null;
        var glitchTimer = null;
        scenes.forEach(function (sceneEl) {
          var sceneId = sceneEl.getAttribute('data-framework-scene-id') || sceneEl.getAttribute('data-scene-id');
          if (sceneId === state.sceneId) currentSceneEl = sceneEl;
          if (sceneId === previousSceneId) previousSceneEl = sceneEl;
        });
        var direction = state.direction >= 0 ? 1 : -1;
        document.documentElement.style.setProperty('--scene-enter-offset', direction > 0 ? '200px' : '-200px');
        document.documentElement.style.setProperty('--scene-exit-offset', direction > 0 ? '-140px' : '140px');
        var isSceneChange = previousSceneId !== state.sceneId;
        var targetTransition = sceneTransitionMap[state.sceneId] || 'door';
        var needsGlitch = isSceneChange && targetTransition === 'glitch' && currentSceneEl;

        // Apply per-scene transition CSS vars before switching
        if (isSceneChange) {
          var preset = TRANSITION_PRESETS[targetTransition] || TRANSITION_PRESETS['door'];
          var rootStyle = document.documentElement.style;
          for (var varKey in preset) {
            rootStyle.setProperty(varKey, preset[varKey]);
          }
        }

        function doSwitch() {
          if (exitCleanupTimer) {
            clearTimeout(exitCleanupTimer);
            exitCleanupTimer = null;
          }
          scenes.forEach(function (sceneEl) {
            if (sceneEl !== currentSceneEl && sceneEl !== previousSceneEl) {
              sceneEl.classList.remove('scene-active');
              sceneEl.classList.remove('scene-exit');
            }
          });
          if (previousSceneEl && previousSceneEl !== currentSceneEl) {
            previousSceneEl.classList.remove('scene-active');
            previousSceneEl.classList.add('scene-exit');
          }
          if (currentSceneEl) {
            currentSceneEl.classList.remove('scene-exit');
            currentSceneEl.classList.add('scene-active');
            applyStepVisibility(currentSceneEl);
          }
          if (previousSceneEl && previousSceneEl !== currentSceneEl) {
            exitCleanupTimer = setTimeout(function () { previousSceneEl.classList.remove('scene-exit'); }, 650);
          }
          if (previousSceneId !== state.sceneId) {
            if (previousSceneId && window.SceneLifecycle.handlers[previousSceneId] && typeof window.SceneLifecycle.handlers[previousSceneId].leave === 'function') {
              try { window.SceneLifecycle.handlers[previousSceneId].leave(); } catch (e) {}
            }
          }
          if (currentSceneEl && window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].enter === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].enter(); } catch (e) {}
          }
          if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].step === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].step(state.step); } catch (e) {}
          }
          if (currentSceneEl) {
            syncSceneStepClasses(currentSceneEl, state.sceneId, state.step);
            refreshFrameworkIcons(currentSceneEl);
          }
          previousSceneId = state.sceneId;
          highlightActiveSceneButton();
          highlightActiveEditorItem();
          updateProgressUi(getProgressPercent(state.sceneId, state.step));
        }

        function runGlitchSequence() {
          if (!currentSceneEl) return;
          // Step 1: blur bomb + shift (instant, disable transition first)
          var noTrans = document.getElementById('sv-no-transition');
          if (!noTrans) {
            noTrans = document.createElement('style');
            noTrans.id = 'sv-no-transition';
            noTrans.textContent = '.scene { transition: none !important; }';
            document.head.appendChild(noTrans);
          }
          currentSceneEl.style.filter = 'blur(24px) brightness(1.5)';
          currentSceneEl.style.transform = 'translateX(30px) scale(0.96)';
          // Step 2: snap to other side (80ms)
          glitchTimer = setTimeout(function () {
            if (!currentSceneEl) return;
            currentSceneEl.style.filter = 'blur(3px) brightness(1.1)';
            currentSceneEl.style.transform = 'translateX(-15px) scale(1.02)';
            // Step 3: settle with slight bounce (160ms)
            glitchTimer = setTimeout(function () {
              if (!currentSceneEl) return;
              currentSceneEl.style.filter = 'blur(0px) brightness(1)';
              currentSceneEl.style.transform = 'translateX(0) scale(1)';
              if (noTrans && noTrans.parentNode) noTrans.parentNode.removeChild(noTrans);
              if (currentSceneEl) {
                refreshFrameworkIcons(currentSceneEl);
              }
            }, 70);
          }, 80);
        }

        if (needsGlitch) {
          // Kill old scene instantly
          if (previousSceneEl) {
            previousSceneEl.classList.remove('scene-active');
            previousSceneEl.classList.add('scene-exit');
            exitCleanupTimer = setTimeout(function () { previousSceneEl.classList.remove('scene-exit'); }, 650);
          }
          // Show new scene for glitch base
          if (currentSceneEl) {
            currentSceneEl.classList.remove('scene-exit');
            currentSceneEl.classList.add('scene-active');
            applyStepVisibility(currentSceneEl);
          }
          // Fire lifecycle immediately so scene JS can initialize
          if (previousSceneId && window.SceneLifecycle.handlers[previousSceneId] && typeof window.SceneLifecycle.handlers[previousSceneId].leave === 'function') {
            try { window.SceneLifecycle.handlers[previousSceneId].leave(); } catch (e) {}
          }
          if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].enter === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].enter(); } catch (e) {}
          }
          if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].step === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].step(state.step); } catch (e) {}
          }
          if (currentSceneEl) {
            syncSceneStepClasses(currentSceneEl, state.sceneId, state.step);
          }
          previousSceneId = state.sceneId;
          highlightActiveSceneButton();
          highlightActiveEditorItem();
          updateProgressUi(getProgressPercent(state.sceneId, state.step));
          runGlitchSequence();
        } else {
          doSwitch();
        }
      }
      window.__SVGVIDEO_SET_STATE = function (sceneId, step, direction) {
        if (typeof sceneId === 'string' && sceneId) {
          if (typeof direction === 'number' && Number.isFinite(direction)) {
            state.direction = direction >= 0 ? 1 : -1;
          } else {
            var nextIndex = getSceneIndexById(sceneId);
            var prevIndex = getSceneIndexById(state.sceneId);
            if (nextIndex !== -1 && prevIndex !== -1) state.direction = nextIndex >= prevIndex ? 1 : -1;
          }
          state.sceneId = sceneId;
        }
        if (typeof step === 'number' && Number.isFinite(step)) state.step = Math.max(0, Math.floor(step));
        applySceneState();
      };
      if (state.sceneId && getSceneIndexById(state.sceneId) === -1 && sceneModels.length) {
        state.sceneId = sceneModels[0].id;
      }
      if (playBtn) {
        playBtn.addEventListener('click', function () {
          if (isPlaying) stopPlayback();
          else startPlayback();
        });
      }
      if (expandBtn) {
        expandBtn.addEventListener('click', function () {
          if (isEditorOpen) closeEditor();
          else openEditor();
        });
      }
      if (editorCloseBtn) {
        editorCloseBtn.addEventListener('click', closeEditor);
      }
      if (editorBackdrop) {
        editorBackdrop.addEventListener('click', closeEditor);
      }
      if (editorSaveBtn) {
        editorSaveBtn.addEventListener('click', saveEditor);
      }
      if (editorResizeHandle && editorSheet) {
        editorResizeHandle.addEventListener('mousedown', function (event) {
          event.preventDefault();
          var startY = event.clientY;
          var startHeightPx = (window.innerHeight * editorHeightVh) / 100;
          var onMove = function (moveEvent) {
            var delta = startY - moveEvent.clientY;
            var nextHeightPx = startHeightPx + delta;
            var nextHeightVh = (nextHeightPx / Math.max(1, window.innerHeight)) * 100;
            applyEditorHeight(nextHeightVh);
          };
          var onUp = function () {
            window.removeEventListener('mousemove', onMove);
            window.removeEventListener('mouseup', onUp);
          };
          window.addEventListener('mousemove', onMove);
          window.addEventListener('mouseup', onUp);
        });
      }
      sceneButtonList.forEach(function (button) {
        button.addEventListener('click', function () {
          var sceneId = button.getAttribute('data-panel-scene-id');
          if (!sceneId) return;
          focusScene(sceneId);
        });
      });
      sceneRetryButtonList.forEach(function (button) {
        button.addEventListener('click', function (event) {
          event.preventDefault();
          event.stopPropagation();
          var sceneId = button.getAttribute('data-retry-scene-id');
          if (!sceneId) return;
          requestSceneRetry(sceneId);
        });
      });
      if (progressWrap) {
        progressWrap.addEventListener('click', function (event) {
          var rect = progressWrap.getBoundingClientRect();
          var pct = Math.max(0, Math.min(100, ((event.clientX - rect.left) / rect.width) * 100));
          var totalSteps = getTotalSteps();
          var targetStep = Math.round((pct / 100) * totalSteps);
          var accumulated = 0;
          for (var i = 0; i < sceneModels.length; i++) {
            var sceneSteps = Math.max(1, Number(sceneModels[i].steps) || 1);
            if (accumulated + sceneSteps > targetStep) {
              var localStep = Math.max(0, Math.min(sceneSteps - 1, targetStep - accumulated));
              stopPlayback();
              window.__SVGVIDEO_SET_STATE(sceneModels[i].id, localStep, 1);
              updateProgressUi(pct);
              return;
            }
            accumulated += sceneSteps;
          }
        });
      }
      window.addEventListener('message', function (event) {
        var data = event && event.data;
        if (!data || typeof data.type !== 'string') return;
        if (data.type === '__SVGVIDEO_SET_STATE') {
          window.__SVGVIDEO_SET_STATE(data.sceneId, data.step, data.direction);
          return;
        }
        if (data.type === '__SVGVIDEO_PLAY') {
          startPlayback();
          return;
        }
        if (data.type === '__SVGVIDEO_STOP') {
          stopPlayback();
          return;
        }
        if (data.type === '__SVGVIDEO_SET_HOST_CAPS') {
          hostCaps.canRetry = Boolean(data.canRetry);
          hostCaps.canEditPanel = Boolean(data.canEditPanel);
          hostCaps.locale = data.locale === 'en' ? 'en' : 'zh';
          hostCaps.theme = data.theme === 'light' ? 'light' : 'dark';
          applyI18nTexts();
          applyHostCaps();
          if (isEditorOpen) renderEditorList();
          return;
        }
        if (data.type === '__SVGVIDEO_SET_SCENE_STATUS') {
          var sceneId = typeof data.sceneId === 'string' ? data.sceneId : '';
          var status = typeof data.status === 'string' ? data.status : '';
          if (sceneId && status) {
            setSceneStatus(sceneId, status);
            if (isEditorOpen) renderEditorList();
          }
          return;
        }
        if (data.type === '__SVGVIDEO_SET_RECORDING') {
          if (data && data.active) {
            document.body.classList.add('sv-recording');
            // 如果指定了初始分镜，无过渡动画地跳转过去，避免录制开头残留旧分镜画面
            if (data.sceneId) {
              var noTransStyle = document.createElement('style');
              noTransStyle.id = 'sv-no-transition';
              noTransStyle.textContent = '.scene, [data-step] { transition: none !important; }';
              document.head.appendChild(noTransStyle);
              window.__SVGVIDEO_SET_STATE(data.sceneId, 0, 1);
              // 强制 reflow 后恢复过渡动画
              void document.body.offsetHeight;
              requestAnimationFrame(function () {
                var s = document.getElementById('sv-no-transition');
                if (s) s.remove();
              });
            }
          } else {
            document.body.classList.remove('sv-recording');
          }
          return;
        }
        if (data.type === '__SVGVIDEO_SET_META' && data.meta && typeof data.meta === 'object') {
          meta = data.meta;
          var freshScenes = Array.isArray(meta.scenes) ? meta.scenes : [];
          freshScenes.forEach(function (scene) {
            var idx = getSceneIndexById(scene.id);
            if (idx < 0) return;
            sceneModels[idx].prompt = typeof scene.prompt === 'string' ? scene.prompt : '';
            sceneModels[idx].scriptText = typeof scene.scriptText === 'string' ? scene.scriptText : '';
            sceneModels[idx].audioObjectKey = typeof scene.audioObjectKey === 'string' ? scene.audioObjectKey : '';
            sceneModels[idx].audioDurationMs = Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0;
            sceneModels[idx].voiceName = typeof scene.voiceName === 'string' ? scene.voiceName : '';
            sceneModels[idx].voiceStyle = typeof scene.voiceStyle === 'string' ? scene.voiceStyle : '';
          });
          persistMetaToScript();
          if (isEditorOpen) renderEditorList();
        }
      });
      document.addEventListener('keydown', function (event) {
        if (event.key === 'Escape' && isEditorOpen) closeEditor();
      });
      window.__SVGVIDEO_PLAY = startPlayback;
      window.__SVGVIDEO_STOP = stopPlayback;
      window.__SVGVIDEO_OPEN_EDITOR = openEditor;
      window.__SVGVIDEO_CLOSE_EDITOR = closeEditor;
      applyEditorHeight(editorHeightVh);
      renderStatus();
      updatePlayButton();
      applyHostCaps();
      clearEditorDirty();
      applyI18nTexts();
      applySceneState();
      if (autoplayFromFirstScene && sceneModels.length) {
        state.sceneId = sceneModels[0].id;
        state.step = 0;
        state.direction = 1;
        applySceneState();
        startPlayback();
      }
    })();
  </script>
</body>
</html>2a:T2e832,<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>从SVM到Transformer：自然语言处理的进化史</title>
  <style>
    
    @font-face { font-family: "SmileySans"; src: url("/fonts/SmileySans-Oblique.woff2") format("woff2"); font-weight: 100 900; font-style: normal; font-display: swap; }
    @font-face {
      font-family: "SVGVideoAlimamaShuHei";
      src:
        url("/fonts/AlimamaShuHeiTi-Bold.woff2") format("woff2"),
        url("/fonts/AlimamaShuHeiTi-Bold.woff") format("woff"),
        url("/fonts/AlimamaShuHeiTi-Bold.ttf") format("truetype"),
        local("Alimama ShuHeiTi Bold"),
        local("Alimama ShuHeiTi"),
        local("AlimamaShuHeiTi-Bold"),
        local("AlimamaShuHeiTi");
      font-display: swap;
      font-weight: 700;
      font-style: normal;
    }
    :root {
      color-scheme: dark;
      --bg: #202020;
      --fg: #e2e8f0;
      --muted: #94a3b8;
      --card: rgba(255, 255, 255, 0.05);
      --border: rgba(255, 255, 255, 0.12);
      --sv-editor-height: 50vh;
      --sv-font-display-cn: "SmileySans", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;
      --sv-font-body-cn: "SmileySans", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;
      --sv-font-mono: "SFMono-Regular", "JetBrains Mono", "Fira Code", "Courier New", monospace;
      --sv-stage-perspective: 900px;
        --sv-trans-enter-opacity: 0;
        --sv-trans-enter-transform: rotateY(90deg);
        --sv-trans-enter-filter: blur(6px);
        --sv-trans-active-opacity: 1;
        --sv-trans-active-transform: rotateY(0deg);
        --sv-trans-active-filter: blur(0px);
        --sv-trans-exit-opacity: 0;
        --sv-trans-exit-transform: rotateY(-90deg);
        --sv-trans-exit-filter: blur(4px);
        --sv-trans-duration: 0.65s;
        --sv-trans-ease: cubic-bezier(0.36, 0, 0.66, 1);
    }
    * { box-sizing: border-box; }
    html, body {
      margin: 0; width: 100%; height: 100%; overflow: hidden;
      background: var(--bg);
      color: var(--fg);
      font-family: var(--sv-font-body-cn);
    }
    #app { width: 100%; height: 100%; display: flex; flex-direction: column; }
    #viewport { position: relative; flex: 1; min-height: 0; overflow: hidden; }
    #stage {
      position: relative; width: 100%; height: 100%; overflow: hidden;
      perspective: var(--sv-stage-perspective, none);
      perspective-origin: 50% 50%;
    }
    .scene {
      position: absolute; inset: 0; overflow: hidden;
      backface-visibility: hidden;
      -webkit-backface-visibility: hidden;
      opacity: var(--sv-trans-enter-opacity, 0); pointer-events: none;
      transform: var(--sv-trans-enter-transform, translateX(var(--scene-enter-offset, 56px)) scale(0.96));
      filter: var(--sv-trans-enter-filter, blur(10px));
      transition: opacity var(--sv-trans-duration, .55s) var(--sv-trans-ease, cubic-bezier(.22,1,.36,1)), transform var(--sv-trans-duration, .55s) var(--sv-trans-ease, cubic-bezier(.22,1,.36,1)), filter var(--sv-trans-duration, .55s) ease;
      will-change: opacity, transform, filter;
      z-index: 1;
    }
    .scene.scene-active {
      opacity: var(--sv-trans-active-opacity, 1); pointer-events: auto;
      transform: var(--sv-trans-active-transform, translateX(0) scale(1));
      filter: var(--sv-trans-active-filter, blur(0px));
      z-index: 3;
    }
    .scene.scene-exit {
      opacity: var(--sv-trans-exit-opacity, 0); pointer-events: none;
      transform: var(--sv-trans-exit-transform, translateX(var(--scene-exit-offset, -56px)) scale(0.96));
      filter: var(--sv-trans-exit-filter, blur(10px));
      z-index: 2;
    }
    .scene-placeholder {
      height: 100%; border: 1px dashed var(--border); border-radius: 20px; background: var(--card);
      display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: var(--muted);
    }
    .sv-scene-root { width: 100%; height: 100%; position: relative; overflow: hidden; }
    .scene-placeholder-title { font-size: 28px; color: var(--fg); font-weight: 700; }
    [data-step] { transition: opacity .35s ease, transform .35s ease, filter .35s ease; }
    #sv-controls {
      background: rgba(19, 19, 19, 0.95);
      border-top: 1px solid rgba(255,255,255,0.08);
      padding: 8px 12px 10px;
      display: flex;
      flex-direction: column;
      gap: 8px;
      backdrop-filter: blur(8px);
      flex-shrink: 0;
    }
    .sv-progress-wrap {
      position: relative;
      height: 22px;
      display: flex;
      align-items: center;
      cursor: pointer;
    }
    .sv-progress-track {
      width: 100%;
      height: 4px;
      border-radius: 999px;
      background: rgba(120, 120, 120, 0.55);
      position: relative;
      overflow: hidden;
    }
    .sv-progress-fill {
      position: absolute;
      left: 0;
      top: 0;
      bottom: 0;
      width: 0%;
      border-radius: 999px;
      background: linear-gradient(90deg, #f97316, #fb923c);
      transition: width 220ms ease;
    }
    .sv-progress-thumb {
      position: absolute;
      top: 50%;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      background: #fff;
      transform: translate(-50%, -50%);
      box-shadow: 0 0 0 1px rgba(0,0,0,0.28);
      pointer-events: none;
    }
    .sv-toolbar {
      display: grid;
      grid-template-columns: 1fr auto 1fr;
      align-items: center;
      gap: 8px;
      min-height: 30px;
    }
    .sv-toolbar-left {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      min-width: 0;
    }
    .sv-toolbar-title {
      font-size: 11px;
      color: #a8b0bb;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-expand-btn {
      width: 20px;
      height: 20px;
      border: none;
      border-radius: 6px;
      background: rgba(255,255,255,0.08);
      color: #cbd5e1;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      flex: 0 0 auto;
      transition: background 140ms ease, color 140ms ease, transform 120ms ease;
    }
    .sv-expand-btn:hover {
      background: rgba(255,255,255,0.15);
      color: #f8fafc;
    }
    .sv-expand-btn:active {
      transform: scale(0.94);
    }
    body:not(.sv-host-can-edit-panel) .sv-expand-btn {
      display: none;
    }
    .sv-play-btn {
      width: 28px;
      height: 28px;
      border: none;
      border-radius: 999px;
      color: #fff;
      background: #f97316;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: transform 120ms ease, background 160ms ease;
    }
    .sv-play-btn:hover { background: #fb923c; }
    .sv-play-btn:active { transform: scale(0.94); }
    .sv-play-btn:disabled { opacity: 0.45; cursor: not-allowed; }
    .sv-status {
      text-align: right;
      font-size: 11px;
      color: #8f98a5;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-scene-grid {
      display: flex;
      align-items: stretch;
      gap: 6px;
      flex-wrap: nowrap;
      overflow: hidden;
    }
    .scene-chip {
      position: relative;
      width: 100%;
      border: none;
      border-bottom: 2px solid transparent;
      border-radius: 8px;
      background: rgba(255,255,255,0.06);
      color: #a3a3a3;
      padding: 7px 6px;
      text-align: center;
      font-size: 11px;
      line-height: 1.1;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      cursor: pointer;
      transition: transform 140ms ease, color 160ms ease, background 160ms ease, border-color 160ms ease;
    }
    .scene-chip-label {
      display: block;
      width: 100%;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .scene-chip-wrap {
      position: relative;
      flex: 1 1 0;
      min-width: 0;
    }
    .scene-chip-retry {
      position: absolute;
      top: 50%;
      right: 4px;
      transform: translateY(-50%);
      width: 24px;
      height: 24px;
      border: none;
      border-radius: 999px;
      background: #f97316;
      color: #fff;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
      opacity: 0;
      pointer-events: none;
      transition: opacity 160ms ease;
      cursor: pointer;
    }
    body.sv-host-can-retry .scene-chip-wrap:hover .scene-chip-retry {
      opacity: 1;
      pointer-events: auto;
    }
    .scene-chip-retry:disabled {
      opacity: 1;
      pointer-events: none;
      background: #f97316;
    }
    .scene-chip-retry-icon {
      width: 18px;
      height: 18px;
      display: block;
    }
    .scene-chip-retry-spinner {
      width: 14px;
      height: 14px;
      aspect-ratio: 1 / 1;
      border: 2px solid #ffffff;
      border-top-color: transparent;
      border-radius: 999px;
      box-sizing: border-box;
      animation: sceneChipSpin 1s linear infinite;
      display: block;
      flex: 0 0 auto;
    }
    @keyframes sceneChipSpin {
      from { transform: rotate(0deg); }
      to { transform: rotate(360deg); }
    }
    .scene-chip:hover { transform: scale(1.02); }
    .scene-chip.is-active {
      color: #fb923c;
      border-bottom-color: #fb923c;
      background: linear-gradient(135deg, rgba(249,115,22,0.2), rgba(168,85,247,0.2));
    }
    .scene-chip.is-failed {
      color: #fca5a5;
      border-bottom-color: rgba(239,68,68,0.95);
      background: rgba(239,68,68,0.12);
    }
    .scene-chip.is-generating {
      color: #fcd34d;
      background: rgba(245,158,11,0.11);
    }
    .sv-editor-overlay {
      position: relative;
      width: 100%;
      height: 0;
      z-index: 40;
      pointer-events: none;
      overflow: hidden;
      transition: height 260ms cubic-bezier(.22,1,.36,1);
    }
    .sv-editor-backdrop {
      position: absolute;
      inset: auto 0 0 0;
      height: 100%;
      background: rgba(0, 0, 0, 0.45);
      opacity: 0;
      transition: opacity 220ms ease;
    }
    .sv-editor-sheet {
      position: absolute;
      left: 0;
      right: 0;
      bottom: 0;
      height: 100%;
      background: rgba(16, 16, 16, 0.96);
      border-top: 1px solid rgba(255,255,255,0.12);
      box-shadow: 0 -14px 30px rgba(0,0,0,0.45);
      transform: translateY(102%);
      transition: transform 260ms cubic-bezier(.22,1,.36,1);
      display: flex;
      flex-direction: column;
    }
    .sv-editor-overlay.is-open {
      pointer-events: auto;
      height: var(--sv-editor-height, 50vh);
    }
    .sv-editor-overlay.is-open .sv-editor-backdrop {
      opacity: 1;
    }
    .sv-editor-overlay.is-open .sv-editor-sheet {
      transform: translateY(0);
    }
    .sv-editor-resize-handle {
      width: 100%;
      height: 14px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: ns-resize;
      flex: 0 0 auto;
      touch-action: none;
    }
    .sv-editor-resize-handle::before {
      content: "";
      width: 52px;
      height: 4px;
      border-radius: 999px;
      background: rgba(148, 163, 184, 0.7);
    }
    .sv-editor-header {
      padding: 10px 12px;
      border-bottom: 1px solid rgba(255,255,255,0.1);
      display: grid;
      grid-template-columns: 1fr auto;
      align-items: center;
      gap: 8px;
    }
    .sv-editor-header-title {
      color: #f1f5f9;
      font-size: 13px;
      font-weight: 600;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-editor-actions {
      display: inline-flex;
      align-items: center;
      gap: 6px;
    }
    .sv-editor-btn {
      border: none;
      border-radius: 8px;
      cursor: pointer;
      font-size: 12px;
      line-height: 1;
      padding: 7px 10px;
      color: #e2e8f0;
      background: rgba(255,255,255,0.1);
      transition: background 120ms ease;
    }
    .sv-editor-btn:hover {
      background: rgba(255,255,255,0.18);
    }
    .sv-editor-btn.is-primary {
      color: #fff;
      background: #f97316;
    }
    .sv-editor-btn.is-primary:hover {
      background: #fb923c;
    }
    .sv-editor-list {
      flex: 1;
      min-height: 0;
      overflow: auto;
      padding: 10px 12px 14px;
      display: grid;
      gap: 10px;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      align-items: start;
      align-content: start;
    }
    .sv-editor-item {
      border: 1px solid rgba(255,255,255,0.12);
      border-radius: 10px;
      background: rgba(255,255,255,0.03);
      padding: 10px;
      display: grid;
      grid-template-rows: auto auto auto;
      gap: 10px;
      align-content: start;
      cursor: pointer;
    }
    .sv-editor-item.is-active {
      border-color: rgba(249,115,22,0.65);
      box-shadow: inset 0 0 0 1px rgba(249,115,22,0.28);
    }
    .sv-editor-item-head {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 8px;
      min-height: 30px;
    }
    .sv-editor-item-title {
      border: none;
      border-radius: 8px;
      color: #fb923c;
      background: rgba(255,255,255,0.08);
      font-size: 12px;
      font-weight: 600;
      padding: 6px 8px;
      cursor: pointer;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      text-align: left;
    }
    .sv-editor-item-title:hover {
      background: rgba(255,255,255,0.14);
    }
    .sv-editor-status {
      color: #94a3b8;
      font-size: 11px;
      white-space: nowrap;
    }
    .sv-editor-status-wrap {
      display: inline-flex;
      align-items: center;
      gap: 6px;
    }
    .scene-chip-retry.sv-editor-retry {
      position: static;
      transform: none;
      opacity: 1;
      pointer-events: auto;
      width: 24px;
      height: 24px;
      flex: 0 0 auto;
    }
    .sv-editor-field {
      display: grid;
      gap: 6px;
    }
    .sv-editor-label {
      color: #a3a3a3;
      font-size: 11px;
      font-weight: 700;
    }
    .sv-editor-textarea {
      width: 100%;
      border-radius: 8px;
      border: 1px solid rgba(255,255,255,0.14);
      background: rgba(0,0,0,0.24);
      color: #f1f5f9;
      font-size: 12px;
      line-height: 1.45;
      padding: 8px 9px;
      resize: none;
      min-height: 110px;
      height: 110px;
    }
    .sv-editor-textarea[data-field="scriptText"] {
      min-height: 84px;
    }
    .sv-editor-textarea:focus {
      outline: none;
      border-color: rgba(249,115,22,0.7);
      box-shadow: 0 0 0 2px rgba(249,115,22,0.18);
    }
    body.sv-theme-light .sv-editor-textarea {
      border-color: rgba(15,23,42,0.18);
      background: rgba(248,250,252,0.92);
      color: #0f172a;
    }
    body.sv-theme-light .sv-editor-textarea:focus {
      border-color: rgba(249,115,22,0.72);
      box-shadow: 0 0 0 2px rgba(249,115,22,0.2);
    }
    .sv-editor-script-view {
      width: 100%;
      color: #e2e8f0;
      font-size: 12px;
      line-height: 1.5;
      white-space: pre-wrap;
      word-break: break-word;
      min-height: 84px;
      max-height: 84px;
      overflow: auto;
    }
    .sv-editor-save-tip {
      color: #fbbf24;
      font-size: 11px;
      opacity: 0;
      transition: opacity 140ms ease;
      justify-self: end;
    }
    .sv-editor-save-tip.is-visible {
      opacity: 1;
    }
    body.sv-theme-light .sv-editor-backdrop {
      background: rgba(15, 23, 42, 0.2);
    }
    body.sv-theme-light .sv-editor-sheet {
      background: rgba(255, 255, 255, 0.98);
      border-top-color: rgba(15, 23, 42, 0.12);
      box-shadow: 0 -14px 30px rgba(15, 23, 42, 0.16);
    }
    body.sv-theme-light .sv-editor-header {
      border-bottom-color: rgba(15, 23, 42, 0.1);
    }
    body.sv-theme-light .sv-editor-header-title {
      color: #0f172a;
    }
    body.sv-theme-light .sv-editor-btn {
      color: #334155;
      background: rgba(15, 23, 42, 0.08);
    }
    body.sv-theme-light .sv-editor-btn:hover {
      background: rgba(15, 23, 42, 0.14);
    }
    body.sv-theme-light .sv-editor-btn.is-primary {
      color: #ffffff;
      background: #f97316;
    }
    body.sv-theme-light .sv-editor-btn.is-primary:hover {
      background: #fb923c;
    }
    body.sv-theme-light .sv-editor-item {
      border-color: rgba(15, 23, 42, 0.12);
      background: rgba(248, 250, 252, 0.95);
    }
    body.sv-theme-light .sv-editor-item.is-active {
      border-color: rgba(249,115,22,0.72);
      box-shadow: inset 0 0 0 1px rgba(249,115,22,0.3);
    }
    body.sv-theme-light .sv-editor-item-title {
      color: #ea580c;
      background: rgba(249, 115, 22, 0.12);
    }
    body.sv-theme-light .sv-editor-item-title:hover {
      background: rgba(249, 115, 22, 0.18);
    }
    body.sv-theme-light .sv-editor-status {
      color: #64748b;
    }
    body.sv-theme-light .sv-editor-label {
      color: #475569;
    }
    body.sv-theme-light .sv-editor-script-view {
      color: #334155;
    }
    body.sv-theme-light .sv-editor-save-tip {
      color: #c2410c;
    }
    body.sv-editor-open #viewport {
      flex: 1 1 calc(100vh - var(--sv-editor-height, 50vh));
      min-height: 0;
    }
    body.sv-editor-open #sv-controls {
      display: none;
    }
    body.sv-recording .sv-toolbar,
    body.sv-recording .sv-scene-grid {
      display: none;
    }
    body.sv-recording #sv-controls {
      display: none;
    }
    body.sv-theme-light .sv-editor-list,
    body.sv-theme-light .sv-editor-script-view,
    body.sv-theme-light .sv-editor-textarea {
      scrollbar-color: rgba(148, 163, 184, 0.85) rgba(226, 232, 240, 0.85);
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar {
      width: 10px;
      height: 10px;
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-track,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-track,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-track {
      background: rgba(226, 232, 240, 0.85);
      border-radius: 999px;
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-thumb,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-thumb,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-thumb {
      background: rgba(148, 163, 184, 0.85);
      border-radius: 999px;
      border: 2px solid rgba(226, 232, 240, 0.85);
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-thumb:hover,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-thumb:hover,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-thumb:hover {
      background: rgba(100, 116, 139, 0.95);
    }
/* scene-01 */
.sv-scene-root-scene-01 .s-scene-01-root{
  width: 100%; height: 100%; background-color: #EDE5CE; 
  display: flex; justify-content: center; align-items: center; 
  overflow: hidden; position: relative; font-family: var(--sv-font-body-cn);
}/* 氛围层：温暖极光感 */
.sv-scene-root-scene-01 .s-bg-ambient{ position: absolute; inset: 0; z-index: 1; }.sv-scene-root-scene-01 .s-aurora{
  position: absolute; width: 150%; height: 150%; top: -25%; left: -25%;
  background: radial-gradient(circle at 30% 30%, rgba(45, 107, 106, 0.15) 0%, transparent 50%),
              radial-gradient(circle at 70% 70%, rgba(245, 196, 24, 0.1) 0%, transparent 50%);
  filter: blur(60px); animation: s-aurora-drift 20s infinite alternate ease-in-out;
}@keyframes s-aurora-drift{ from { transform: rotate(0deg) scale(1); } to { transform: rotate(5deg) scale(1.1); } }/* 核心 NLP 文字 */
.sv-scene-root-scene-01 .s-content-wrapper{ position: relative; z-index: 10; display: flex; flex-direction: column; align-items: center; }.sv-scene-root-scene-01 .s-hero-text-container{ position: relative; transform: scale(1.2); }.sv-scene-root-scene-01 .s-nlp-text{
  font-family: var(--sv-font-display-cn); font-size: 160px; line-height: 1; color: #1A1210;
  margin: 0; position: relative; z-index: 5; text-shadow: 4px 4px 0px #F5C418;
  animation: s-text-pop 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
}.sv-scene-root-scene-01 .s-nlp-glow{
  position: absolute; inset: 0; font-family: var(--sv-font-display-cn); font-size: 160px;
  color: #F5C418; filter: blur(20px); opacity: 0.4; pointer-events: none;
}@keyframes s-text-pop{ from { opacity: 0; transform: scale(0.5); } to { opacity: 1; transform: scale(1); } }/* Step 1: 波纹 */
.sv-scene-root-scene-01 .s-ripple-container{ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); pointer-events: none; opacity: 0; }.sv-scene-root-scene-01 .step-ge-1 .s-ripple-container{ opacity: 1; }.sv-scene-root-scene-01 .s-ripple{
  position: absolute; border: 3px solid #2D6B6A; border-radius: 50%;
  width: 100px; height: 100px; left: -50px; top: -50px;
  animation: s-ripple-out 2s infinite cubic-bezier(0.25, 0.46, 0.45, 0.94);
}.sv-scene-root-scene-01 .s-ripple:nth-child(2){ animation-delay: 1s; }@keyframes s-ripple-out{ 
  0% { transform: scale(1); opacity: 0.8; } 
  100% { transform: scale(8); opacity: 0; }
}/* Step 2: 漂浮元素 */
.sv-scene-root-scene-01 .s-float-elements{ position: absolute; width: 800px; height: 500px; top: 50%; left: 50%; transform: translate(-50%, -50%); pointer-events: none; opacity: 0; }.sv-scene-root-scene-01 .step-ge-2 .s-float-elements{ opacity: 1; transition: opacity 0.5s ease; }.sv-scene-root-scene-01 .s-bit{ 
  position: absolute; font-family: var(--sv-font-mono); color: #2D6B6A; 
  font-size: 24px; font-weight: bold; opacity: 0.3; 
}.sv-scene-root-scene-01 .s-pos-1{ top: 10%; left: 10%; animation: s-float 4s infinite ease-in-out; }.sv-scene-root-scene-01 .s-pos-2{ bottom: 15%; right: 5%; animation: s-float 5s infinite ease-in-out -1s; }.sv-scene-root-scene-01 .s-pos-3{ top: 60%; left: -5%; animation: s-float 3s infinite ease-in-out -2s; }.sv-scene-root-scene-01 .s-icon-box{
  position: absolute; background: #FFFFFF; border: 2.5px solid #1A1210;
  padding: 12px 20px; border-radius: 16px; display: flex; align-items: center; gap: 10px;
  box-shadow: 6px 6px 0px rgba(26, 18, 16, 0.1); transition: all 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}.sv-scene-root-scene-01 .s-icon-box i{ width: 24px; height: 24px; color: #2D6B6A; }.sv-scene-root-scene-01 .s-icon-box span{ font-family: var(--sv-font-body-cn); font-weight: bold; color: #1A1210; font-size: 18px; }.sv-scene-root-scene-01 .s-box-book{ top: 0; right: 0; transform: rotate(5deg); }.sv-scene-root-scene-01 .s-box-chat{ bottom: -20px; left: 15%; transform: rotate(-3deg); }.sv-scene-root-scene-01 .s-box-net{ top: 70%; right: 10%; transform: rotate(2deg); }@keyframes s-float{ 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-20px); } }.sv-scene-root-scene-01 .s-footer-tag{
  position: absolute; bottom: 40px; padding: 6px 20px; background: #2D6B6A; 
  border: 2px solid #1A1210; border-radius: 30px; transform: rotate(-1deg);
}.sv-scene-root-scene-01 .s-tag-line{ color: #FFFFFF; font-family: var(--sv-font-mono); font-size: 14px; letter-spacing: 2px; }

/* scene-02 */
.sv-scene-root-scene-02 .s-scene-02-root{
  width: 100%; height: 100%; background-color: #EDE5CE;
  position: relative; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--sv-font-body-cn);
}/* 氛围层 */
.sv-scene-root-scene-02 .s-bg-ambient{ position: absolute; inset: 0; z-index: 1; }.sv-scene-root-scene-02 .s-bg-grid{
  position: absolute; inset: 0;
  background-image: radial-gradient(#1A1210 1px, transparent 1px);
  background-size: 40px 40px; opacity: 0.05;
}.sv-scene-root-scene-02 .s-bg-glow{
  position: absolute; width: 60%; height: 60%; top: 20%; left: 20%;
  background: radial-gradient(circle, rgba(245, 196, 24, 0.1) 0%, transparent 70%);
  filter: blur(80px); animation: s-glow-pulse 8s infinite alternate ease-in-out;
}@keyframes s-glow-pulse{ from { transform: scale(1); opacity: 0.4; } to { transform: scale(1.3); opacity: 0.7; } }/* 3D 空间容器 */
.sv-scene-root-scene-02 .s-perspective-container{
  width: 1000px; height: 600px; z-index: 10;
  perspective: 1500px; display: flex; align-items: center; justify-content: center;
}.sv-scene-root-scene-02 .s-svm-space{
  width: 100%; height: 100%; position: relative;
  transform-style: preserve-3d; transition: transform 1.2s cubic-bezier(0.22, 1, 0.36, 1);
}/* Step 2: 空间倾斜 */
.sv-scene-root-scene-02 .step-ge-1 .s-svm-space{
  transform: rotateX(40deg) rotateZ(-15deg) translateY(50px);
}/* 超平面 (Step 1) */
.sv-scene-root-scene-02 .s-hyperplane-wrapper{
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  opacity: 0; transform: scaleX(0); transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
  z-index: 5;
}.sv-scene-root-scene-02 .step-ge-0 .s-hyperplane-wrapper{ opacity: 1; transform: scaleX(1); }.sv-scene-root-scene-02 .s-hyperplane{
  width: 150%; height: 6px; background: #2D6B6A; border: 2px solid #1A1210;
  transform: rotate(-35deg); position: relative;
  box-shadow: 0 0 20px rgba(45, 107, 106, 0.4);
}.sv-scene-root-scene-02 .s-hyperplane-glow{
  position: absolute; inset: -4px; background: #F5C418; filter: blur(8px); opacity: 0.4;
}/* 数据点 */
.sv-scene-root-scene-02 .s-points-container{ position: absolute; inset: 0; z-index: 10; }.sv-scene-root-scene-02 .s-point{
  position: absolute; width: 24px; height: 24px; border-radius: 50%;
  left: var(--x); top: var(--y); border: 2.5px solid #1A1210;
  transition: all 1s cubic-bezier(0.22, 1, 0.36, 1);
  box-shadow: 4px 4px 0 rgba(26, 18, 16, 0.1);
}.sv-scene-root-scene-02 .s-type-a{ background: #E05A3A; }.sv-scene-root-scene-02 .s-type-b{ background: #2D6B6A; }/* Step 1: 强行剥离 (乱序到有序) */
.sv-scene-root-scene-02 .s-p1, .sv-scene-root-scene-02 .s-p2, .sv-scene-root-scene-02 .s-p3, .sv-scene-root-scene-02 .s-p4{ transform: translate(-100px, -50px); }.sv-scene-root-scene-02 .s-p5, .sv-scene-root-scene-02 .s-p6, .sv-scene-root-scene-02 .s-p7, .sv-scene-root-scene-02 .s-p8{ transform: translate(100px, 50px); }.sv-scene-root-scene-02 .step-ge-0 .s-point{ transform: translate(0, 0); }/* 支持向量标注 (Step 3) */
.sv-scene-root-scene-02 .s-sv-box{
  position: absolute; inset: -8px; border: 2px dashed #F5C418;
  border-radius: 8px; opacity: 0; transform: scale(1.5); transition: all 0.5s ease;
}.sv-scene-root-scene-02 .step-ge-2 .s-sv-box{ opacity: 1; transform: scale(1); }.sv-scene-root-scene-02 .s-labels-layer{
  position: absolute; inset: 0; pointer-events: none;
  opacity: 0; transition: opacity 0.6s ease;
}.sv-scene-root-scene-02 .step-ge-2 .s-labels-layer{ opacity: 1; }.sv-scene-root-scene-02 .s-sv-label{
  position: absolute; background: #F5C418; color: #1A1210;
  padding: 4px 10px; border: 2px solid #1A1210; border-radius: 4px;
  font-size: 14px; font-weight: bold; font-family: var(--sv-font-mono);
}.sv-scene-root-scene-02 .s-label-top{ left: 35%; top: 25%; transform: translate(-50%, -100%); }.sv-scene-root-scene-02 .s-label-bottom{ left: 55%; top: 75%; transform: translate(-50%, 0); }/* 文案排版 */
.sv-scene-root-scene-02 .s-info-overlay{
  position: absolute; top: 60px; left: 80px; z-index: 100;
}.sv-scene-root-scene-02 .s-title-badge{
  display: inline-block; background: #2D6B6A; color: #FFFFFF;
  padding: 4px 12px; border-radius: 20px; border: 2px solid #1A1210;
  font-size: 14px; margin-bottom: 12px; transform: rotate(-1deg);
}.sv-scene-root-scene-02 .s-main-title{
  font-family: var(--sv-font-display-cn); font-size: 56px; color: #1A1210;
  margin: 0; line-height: 1.1; text-shadow: 3px 3px 0 #F5C418;
}.sv-scene-root-scene-02 .s-description{
  margin-top: 15px; font-size: 18px; color: rgba(26, 18, 16, 0.7);
  border-left: 4px solid #E05A3A; padding-left: 15px;
}.sv-scene-root-scene-02 .s-footer-deco{
  position: absolute; bottom: 40px; right: 80px; display: flex; align-items: center; gap: 15px;
}.sv-scene-root-scene-02 .s-coord-tag{ font-family: var(--sv-font-mono); font-size: 12px; color: #2D6B6A; letter-spacing: 2px; }.sv-scene-root-scene-02 .s-deco-line{ width: 100px; height: 2px; background: #1A1210; }

/* scene-03 */
.sv-scene-root-scene-03 .s-scene-03-root{
  width: 100%; height: 100%; background-color: #EDE5CE;
  position: relative; overflow: hidden; font-family: var(--sv-font-body-cn);
  display: flex; flex-direction: column; align-items: center;
}/* 背景装饰 */
.sv-scene-root-scene-03 .s-bg-dots{
  position: absolute; inset: 0; opacity: 0.05;
  background-image: radial-gradient(#1A1210 1.5px, transparent 1.5px);
  background-size: 30px 30px;
}.sv-scene-root-scene-03 .s-bg-grid{
  position: absolute; inset: 0; opacity: 0.03;
  background-image: linear-gradient(#1A1210 1px, transparent 1px), linear-gradient(90deg, #1A1210 1px, transparent 1px);
  background-size: 100px 100px;
}.sv-scene-root-scene-03 .s-ghost-text{
  position: absolute; top: 15%; left: 5%; font-family: var(--sv-font-mono); 
  font-size: 80px; font-weight: 900; color: rgba(26,18,16,0.03); white-space: nowrap;
}/* 标题 */
.sv-scene-root-scene-03 .s-header-area{ align-self: flex-start; margin: 60px 0 0 80px; z-index: 10; }.sv-scene-root-scene-03 .s-badge{ 
  background: #2D6B6A; color: #FFF; padding: 4px 12px; border-radius: 20px; 
  font-size: 14px; border: 2px solid #1A1210; display: inline-block; 
}.sv-scene-root-scene-03 .s-main-title{
  font-family: var(--sv-font-display-cn); font-size: 52px; color: #1A1210;
  margin: 10px 0; text-shadow: 3px 3px 0 #F5C418;
}/* 可视化核心 */
.sv-scene-root-scene-03 .s-network-container{
  flex: 1; width: 100%; display: flex; align-items: center; justify-content: center; gap: 40px;
  padding-bottom: 100px; /* 避开字幕 */
}/* 递归单元 */
.sv-scene-root-scene-03 .s-rnn-single-unit{ 
  display: flex; flex-direction: column; align-items: center; gap: 15px;
  padding: 30px; background: rgba(255,255,255,0.4); border-radius: 24px; border: 2px dashed #1A1210;
}.sv-scene-root-scene-03 .s-node-group{ display: flex; flex-direction: column; align-items: center; gap: 30px; position: relative; }.sv-scene-root-scene-03 .s-node{
  width: 60px; height: 60px; border-radius: 50%; border: 3px solid #1A1210;
  display: flex; align-items: center; justify-content: center; font-weight: bold;
  font-family: var(--sv-font-mono); font-size: 24px;
}.sv-scene-root-scene-03 .s-node-x{ background: #F5C418; }.sv-scene-root-scene-03 .s-node-h{ background: #2D6B6A; color: #FFF; position: relative; }.sv-scene-root-scene-03 .s-node-y{ background: #E05A3A; color: #FFF; }.sv-scene-root-scene-03 .s-self-loop{
  position: absolute; width: 80px; height: 80px; right: -60px; top: -10px;
}.sv-scene-root-scene-03 .s-unit-label{ font-size: 14px; color: rgba(26,18,16,0.6); font-weight: bold; }/* 展开后的链条 */
.sv-scene-root-scene-03 .s-rnn-unrolled{ display: flex; align-items: center; gap: 20px; }.sv-scene-root-scene-03 .s-chain-steps{ display: flex; gap: 40px; }.sv-scene-root-scene-03 .s-chain-node{
  display: flex; flex-direction: column; gap: 20px; opacity: 0; transform: translateX(20px);
  transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}.sv-scene-root-scene-03 .step-ge-1 .s-chain-node{ opacity: 1; transform: translateX(0); }.sv-scene-root-scene-03 .s-t1{ transition-delay: 0.2s; }.sv-scene-root-scene-03 .s-t2{ transition-delay: 0.4s; }.sv-scene-root-scene-03 .s-t3{ transition-delay: 0.6s; }.sv-scene-root-scene-03 .s-node-box{
  width: 80px; height: 45px; border: 2.5px solid #1A1210; border-radius: 10px;
  display: flex; align-items: center; justify-content: center; font-size: 16px;
  font-family: var(--sv-font-mono); font-weight: bold; background: #FFF;
  box-shadow: 4px 4px 0 rgba(26,18,16,0.1);
}.sv-scene-root-scene-03 .s-box-x{ background: #F5C418; }.sv-scene-root-scene-03 .s-box-h{ background: #2D6B6A; color: #FFF; }.sv-scene-root-scene-03 .s-box-y{ background: #E05A3A; color: #FFF; }/* 连接线 */
.sv-scene-root-scene-03 .s-chain-node::before, .sv-scene-root-scene-03 .s-chain-node::after{
  content: ''; position: absolute; left: 50%; width: 2px; height: 20px; background: #1A1210;
}.sv-scene-root-scene-03 .s-chain-node .s-box-y{ position: relative; }.sv-scene-root-scene-03 .s-chain-node .s-box-h{ position: relative; }/* 梯度消失 */
.sv-scene-root-scene-03 .s-vanishing-effect{
  position: absolute; right: 10%; top: 50%; transform: translateY(-50%);
  width: 300px; height: 200px; pointer-events: none;
}.sv-scene-root-scene-03 .s-warning-tag{
  background: #E05A3A; color: #FFF; padding: 6px 16px; border: 2px solid #1A1210;
  border-radius: 4px; font-weight: bold; position: absolute; top: -40px; right: 0;
  opacity: 0; transition: 0.5s;
}.sv-scene-root-scene-03 .step-ge-2 .s-warning-tag{ opacity: 1; animation: s-shake 0.5s infinite; }.sv-scene-root-scene-03 .s-flow-overlay{
  position: absolute; inset: 0; 
  background: linear-gradient(90deg, transparent, #EDE5CE 80%);
  opacity: 0; transition: 2s ease;
}.sv-scene-root-scene-03 .step-ge-2 .s-flow-overlay{ opacity: 1; }/* 底部装饰 */
.sv-scene-root-scene-03 .s-footer-tags{
  position: absolute; bottom: 40px; right: 80px; display: flex; align-items: center; gap: 24px;
}.sv-scene-root-scene-03 .s-tag{ display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: bold; color: #2D6B6A; }.sv-scene-root-scene-03 .s-deco-line{ width: 80px; height: 2px; background: #1A1210; }@keyframes s-shake{
  0%, 100% { transform: rotate(0deg); } 25% { transform: rotate(2deg); } 75% { transform: rotate(-2deg); }
}

/* scene-04 */
.sv-scene-root-scene-04 .s-scene-04-root{
  width: 100%; height: 100%; background-color: #EDE5CE;
  position: relative; overflow: hidden; font-family: var(--sv-font-body-cn);
  display: flex; align-items: center; justify-content: center;
}/* 背景装饰 */
.sv-scene-root-scene-04 .s-bg-glow{
  position: absolute; width: 600px; height: 600px; background: radial-gradient(circle, rgba(245,196,24,0.1) 0%, transparent 70%);
  top: 50%; left: 50%; transform: translate(-50%, -50%); animation: s-glow-pulse 8s infinite ease-in-out;
}@keyframes s-glow-pulse{ 0%, 100% { opacity: 0.3; transform: translate(-50%, -50%) scale(1); } 50% { opacity: 0.6; transform: translate(-50%, -50%) scale(1.2); } }.sv-scene-root-scene-04 .s-bg-grid{
  position: absolute; inset: 0; background-image: linear-gradient(rgba(26,18,16,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(26,18,16,0.03) 1px, transparent 1px);
  background-size: 40px 40px;
}.sv-scene-root-scene-04 .s-ghost-text{
  position: absolute; top: 10%; left: 5%; font-family: var(--sv-font-mono); font-size: 80px; font-weight: 900; color: rgba(26,18,16,0.04); white-space: nowrap; pointer-events: none;
}/* 核心容器 */
.sv-scene-root-scene-04 .s-main-container{
  width: 90%; height: 80%; position: relative; z-index: 10;
  display: flex; flex-direction: column; align-items: center; justify-content: space-around;
}.sv-scene-root-scene-04 .s-header-group{ align-self: flex-start; margin-left: 40px; }.sv-scene-root-scene-04 .s-hero-title{
  font-family: var(--sv-font-display-cn); font-size: 56px; color: #1A1210; margin-top: 10px;
  text-shadow: 4px 4px 0px rgba(245, 196, 24, 0.4);
}.sv-scene-root-scene-04 .s-badge{ background: #2D6B6A; color: #FFF; padding: 4px 16px; border-radius: 30px; display: inline-block; font-size: 14px; border: 2px solid #1A1210; }/* 细胞状态长线 */
.sv-scene-root-scene-04 .s-cell-state-line{
  position: absolute; top: 50%; left: 0; width: 100%; height: 4px; background: #1A1210; z-index: 5;
}.sv-scene-root-scene-04 .s-line-glow{
  position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: #F5C418;
  box-shadow: 0 0 15px #F5C418; opacity: 0; transition: opacity 0.8s ease;
}.sv-scene-root-scene-04 .step-ge-2 .s-line-glow{ opacity: 1; }.sv-scene-root-scene-04 .s-state-label{
  position: absolute; right: 40px; top: -30px; font-family: var(--sv-font-mono); font-size: 12px; color: #2D6B6A; font-weight: bold;
}/* LSTM 盒子 */
.sv-scene-root-scene-04 .s-lstm-box{
  width: 700px; height: 350px; display: flex; justify-content: space-between; align-items: center; position: relative; z-index: 10;
}.sv-scene-root-scene-04 .s-gate{
  width: 180px; height: 240px; position: relative;
  opacity: 0; transform: translateY(30px); transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}.sv-scene-root-scene-04 .step-ge-0 .s-forget-gate{ opacity: 1; transform: translateY(0); }.sv-scene-root-scene-04 .step-ge-1 .s-input-gate{ opacity: 1; transform: translateY(0); transition-delay: 0.2s; }.sv-scene-root-scene-04 .step-ge-2 .s-output-gate{ opacity: 1; transform: translateY(0); transition-delay: 0.4s; }.sv-scene-root-scene-04 .s-gate-glass{
  width: 100%; height: 100%; background: rgba(255, 255, 255, 0.7); backdrop-filter: blur(8px);
  border: 3px solid #1A1210; border-radius: 20px; box-shadow: 8px 8px 0 rgba(26,18,16,0.1);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 15px;
  position: relative; overflow: hidden;
}.sv-scene-root-scene-04 .s-gate-icon{ font-size: 50px; color: #2D6B6A; }.sv-scene-root-scene-04 .s-gate-label{ font-family: var(--sv-font-display-cn); font-size: 22px; color: #1A1210; }/* 遗忘门动画 */
.sv-scene-root-scene-04 .s-debris{
  position: absolute; width: 15px; height: 15px; background: #E05A3A; border: 2px solid #1A1210;
  top: -20px; opacity: 0;
}.sv-scene-root-scene-04 .step-ge-0 .s-debris{
  animation: s-debris-fall 2s infinite linear;
}.sv-scene-root-scene-04 .s-d1{ left: 30%; animation-delay: 0s !important; }.sv-scene-root-scene-04 .s-d2{ left: 50%; animation-delay: 0.7s !important; }.sv-scene-root-scene-04 .s-d3{ left: 70%; animation-delay: 1.4s !important; }@keyframes s-debris-fall{
  0% { transform: translateY(0) rotate(0deg); opacity: 0; }
  30% { opacity: 1; }
  70% { opacity: 1; }
  100% { transform: translateY(120px) rotate(360deg); opacity: 0; }
}/* 输入门光球 */
.sv-scene-root-scene-04 .s-golden-orb{
  position: absolute; width: 40px; height: 40px; background: #F5C418; border-radius: 50%; border: 3px solid #1A1210;
  top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0); box-shadow: 0 0 20px #F5C418;
  transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}.sv-scene-root-scene-04 .step-ge-1 .s-golden-orb{ transform: translate(-50%, -50%) scale(1.2); }/* 输出门流束 */
.sv-scene-root-scene-04 .s-output-light{
  position: absolute; top: 50%; left: 100%; width: 0; height: 4px; background: #F5C418; box-shadow: 0 0 10px #F5C418;
  transition: width 0.6s ease-out 0.6s;
}.sv-scene-root-scene-04 .step-ge-2 .s-output-light{ width: 100px; }/* 页脚 */
.sv-scene-root-scene-04 .s-footer-info{ position: absolute; bottom: 40px; right: 60px; display: flex; align-items: center; gap: 20px; }.sv-scene-root-scene-04 .s-mono-tag{ font-family: var(--sv-font-mono); font-size: 14px; color: rgba(26,18,16,0.6); }.sv-scene-root-scene-04 .s-deco-line{ width: 60px; height: 2px; background: #E05A3A; }/* 文本标签淡入 */
.sv-scene-root-scene-04 .s-gate-label{ opacity: 0; transform: scale(0.9); transition: 0.4s; }.sv-scene-root-scene-04 .step-ge-3 .s-gate-label{ opacity: 1; transform: scale(1); }

/* scene-05 */
.sv-scene-root-scene-05 .s-scene-05-root{
  width: 100%; height: 100%; background-color: #EDE5CE;
  position: relative; overflow: hidden; font-family: var(--sv-font-body-cn);
  display: flex; align-items: center; justify-content: center;
  transition: background-color 1.5s ease;
}.sv-scene-root-scene-05 .step-ge-2.s-scene-05-root{ background-color: #F0E6FF; }/* 背景装饰 */
.sv-scene-root-scene-05 .s-bg-glow{
  position: absolute; width: 800px; height: 800px; background: radial-gradient(circle, rgba(45,107,106,0.05) 0%, transparent 70%);
  top: 50%; left: 50%; transform: translate(-50%, -50%);
}.sv-scene-root-scene-05 .s-bg-grid{
  position: absolute; inset: 0; background-image: radial-gradient(#1A1210 1px, transparent 1px);
  background-size: 50px 50px; opacity: 0.05;
}.sv-scene-root-scene-05 .s-ghost-text{
  position: absolute; bottom: 5%; right: 5%; font-family: var(--sv-font-display-cn); font-size: 120px; color: rgba(26,18,16,0.03); pointer-events: none;
}/* 核心容器 */
.sv-scene-root-scene-05 .s-main-container{
  width: 90%; height: 90%; position: relative; z-index: 10;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
}.sv-scene-root-scene-05 .s-header-group{
  position: absolute; top: 40px; left: 40px; z-index: 20;
}.sv-scene-root-scene-05 .s-hero-title{
  font-family: var(--sv-font-display-cn); font-size: 52px; color: #1A1210; margin-top: 12px;
}.sv-scene-root-scene-05 .s-badge{ background: #2D6B6A; color: #FFF; padding: 4px 16px; border-radius: 30px; display: inline-block; font-size: 14px; border: 2px solid #1A1210; }/* Transformer 核心可视化 */
.sv-scene-root-scene-05 .s-transformer-core{
  position: relative; width: 600px; height: 600px;
  display: flex; align-items: center; justify-content: center;
}/* 中心圆环 */
.sv-scene-root-scene-05 .s-center-hub{
  position: relative; width: 120px; height: 120px; z-index: 15;
}.sv-scene-root-scene-05 .s-hub-ring{
  position: absolute; inset: -10px; border: 4px dashed #F5C418; border-radius: 50%;
  animation: s-rotate 20s linear infinite;
}.sv-scene-root-scene-05 .s-hub-core{
  width: 100%; height: 100%; background: #FFF; border: 3px solid #1A1210; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; box-shadow: 0 8px 24px rgba(0,0,0,0.1);
}.sv-scene-root-scene-05 .s-hub-icon{ font-size: 50px; color: #2D6B6A; }@keyframes s-rotate{ from { transform: rotate(0deg); } to { transform: rotate(360deg); } }/* 节点 */
.sv-scene-root-scene-05 .s-nodes-container{
  position: absolute; inset: 0; pointer-events: none;
}.sv-scene-root-scene-05 .s-node{
  position: absolute; width: 70px; height: 45px; background: #FFF; border: 2.5px solid #1A1210; 
  border-radius: 12px; display: flex; align-items: center; justify-content: center;
  left: 50%; top: 50%; 
  --radius: 240px;
  transform: translate(-50%, -50%) rotate(calc(var(--i) * 36deg)) translateY(var(--radius)) rotate(calc(var(--i) * -36deg)) scale(0);
  transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
  transition-delay: calc(var(--i) * 0.05s);
  box-shadow: 4px 4px 0 rgba(26,18,16,0.1);
}.sv-scene-root-scene-05 .step-ge-0 .s-node{ transform: translate(-50%, -50%) rotate(calc(var(--i) * 36deg)) translateY(var(--radius)) rotate(calc(var(--i) * -36deg)) scale(1); }.sv-scene-root-scene-05 .s-node-label{ font-family: var(--sv-font-display-cn); font-size: 18px; color: #1A1210; }/* 连线网格 */
.sv-scene-root-scene-05 .s-attention-mesh{
  position: absolute; width: 100%; height: 100%; top: 0; left: 0; pointer-events: none; z-index: 5;
}.sv-scene-root-scene-05 .s-attention-line{
  stroke: #2D6B6A; stroke-linecap: round; opacity: 0; 
  stroke-dasharray: 1000; stroke-dashoffset: 1000;
  transition: opacity 0.3s ease, stroke-width 0.5s ease;
}.sv-scene-root-scene-05 .step-ge-1 .s-attention-line{
  animation: s-line-draw 1.2s forwards cubic-bezier(0.4, 0, 0.2, 1);
  opacity: 0.2;
}.sv-scene-root-scene-05 .step-ge-2 .s-attention-line{
  opacity: 0.6; stroke: #E05A3A;
}@keyframes s-line-draw{
  to { stroke-dashoffset: 0; }
}/* 页脚 */
.sv-scene-root-scene-05 .s-footer-info{ position: absolute; bottom: 40px; right: 60px; display: flex; align-items: center; gap: 20px; }.sv-scene-root-scene-05 .s-mono-tag{ font-family: var(--sv-font-mono); font-size: 14px; color: rgba(26,18,16,0.6); }.sv-scene-root-scene-05 .s-deco-line{ width: 60px; height: 2px; background: #F5C418; }

/* scene-06 */
.sv-scene-root-scene-06 .s-scene-06-root{
  width: 100%; height: 100%; background-color: #EDE5CE;
  position: relative; overflow: hidden; font-family: var(--sv-font-body-cn);
  display: flex; align-items: center; justify-content: center;
}/* 背景氛围 */
.sv-scene-root-scene-06 .s-bg-nebula{
  position: absolute; width: 120%; height: 120%;
  background: radial-gradient(circle, rgba(245, 196, 24, 0.08) 0%, transparent 60%);
  filter: blur(60px); animation: s-nebula-pulse 10s ease-in-out infinite alternate;
}.sv-scene-root-scene-06 .s-bg-grid-moving{
  position: absolute; inset: -50%; background-image: radial-gradient(#2D6B6A 1px, transparent 1px);
  background-size: 60px 60px; opacity: 0.05; transform: rotate(15deg); animation: s-grid-flow 30s linear infinite;
}.sv-scene-root-scene-06 .s-ghost-title{
  position: absolute; top: 10%; left: 5%; font-family: var(--sv-font-display-cn); 
  font-size: 80px; color: #1A1210; opacity: 0.03; pointer-events: none;
}/* 镜头系统 */
.sv-scene-root-scene-06 .s-main-stage{
  width: 100%; height: 100%; position: relative;
  display: flex; align-items: center; justify-content: center;
  perspective: 1000px;
}.sv-scene-root-scene-06 .s-camera-rig{
  transition: transform 1.5s cubic-bezier(0.22, 1, 0.36, 1);
  transform: scale(3); /* 初始聚焦于眼睛 */
}.sv-scene-root-scene-06 .step-ge-1 .s-camera-rig{ transform: scale(0.65) rotate(-5deg); }.sv-scene-root-scene-06 .step-ge-2 .s-camera-rig{ transform: scale(0.5) rotate(15deg); }/* 眼睛图标 */
.sv-scene-root-scene-06 .s-eye-container{
  position: relative; z-index: 10; width: 300px; height: 180px;
  display: flex; align-items: center; justify-content: center;
}.sv-scene-root-scene-06 .s-eye-outer{
  width: 100%; height: 100%; background: #FFF; border: 4px solid #1A1210; 
  border-radius: 100% 0%; transform: rotate(45deg); overflow: hidden;
  box-shadow: 0 15px 45px rgba(0,0,0,0.1);
}.sv-scene-root-scene-06 .s-eye-iris{
  position: absolute; width: 120px; height: 120px; background: #2D6B6A;
  border-radius: 50%; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(-45deg);
  border: 3px solid #1A1210; display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}.sv-scene-root-scene-06 .s-matrix-core{
  color: #F5C418; font-family: var(--sv-font-mono); font-size: 8px; line-height: 1; word-break: break-all; opacity: 0.8;
}/* 编码器网格 */
.sv-scene-root-scene-06 .s-encoder-grid{
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  display: grid; grid-template-columns: repeat(6, 120px); gap: 240px 160px;
  opacity: 0; transition: opacity 0.8s ease, transform 1.2s cubic-bezier(0.34, 1.56, 0.64, 1);
  pointer-events: none;
}.sv-scene-root-scene-06 .step-ge-1 .s-encoder-grid{ opacity: 1; }.sv-scene-root-scene-06 .s-encoder-block{
  width: 100px; height: 60px; background: #FFF; border: 2.5px solid #1A1210; border-radius: 8px;
  display: flex; align-items: center; justify-content: center; font-family: var(--sv-font-mono);
  font-size: 14px; color: #1A1210; box-shadow: 6px 6px 0 rgba(45,107,106,0.2);
}/* 文字动画 */
.sv-scene-root-scene-06 .s-side-text{
  position: absolute; font-family: var(--sv-font-display-cn); font-size: 56px; color: #1A1210;
  opacity: 0; transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1);
  z-index: 100; border-bottom: 6px solid #F5C418;
}.sv-scene-root-scene-06 .s-left{ left: 10%; transform: translateX(-50px); }.sv-scene-root-scene-06 .s-right{ right: 10%; transform: translateX(50px); }.sv-scene-root-scene-06 .step-ge-1 .s-side-text{ opacity: 1; transform: translateX(0); }/* 旋转缩放动效 */
.sv-scene-root-scene-06 .s-nebula-vortex{
  position: relative; width: 800px; height: 800px;
  display: flex; align-items: center; justify-content: center;
  transition: transform 15s linear;
}.sv-scene-root-scene-06 .step-ge-2 .s-nebula-vortex{ animation: s-slow-spin 20s linear infinite; }/* 装饰小标 */
.sv-scene-root-scene-06 .s-footer-tag{ position: absolute; bottom: 40px; left: 40px; }.sv-scene-root-scene-06 .s-badge-mini{ background: #2D6B6A; color: #FFF; padding: 2px 10px; font-size: 12px; border-radius: 4px; display: inline-block; margin-bottom: 5px; border: 1.5px solid #1A1210; }.sv-scene-root-scene-06 .s-tag-line{ font-family: var(--sv-font-mono); font-size: 14px; color: rgba(26,18,16,0.6); }@keyframes s-nebula-pulse{ from { transform: scale(1); opacity: 0.5; } to { transform: scale(1.2); opacity: 0.8; } }@keyframes s-grid-flow{ from { transform: rotate(15deg) translateY(0); } to { transform: rotate(15deg) translateY(60px); } }@keyframes s-slow-spin{ to { transform: rotate(360deg); } }

/* scene-07 */
.sv-scene-root-scene-07 .s-scene-07-root{
  width: 100%; height: 100%; background-color: #EDE5CE; position: relative; overflow: hidden;
  font-family: var(--sv-font-body-cn); display: flex; align-items: center; justify-content: center;
}/* 背景氛围 */
.sv-scene-root-scene-07 .s-ambient-layer{ position: absolute; inset: 0; pointer-events: none; }.sv-scene-root-scene-07 .s-ambient-grid{
  position: absolute; inset: 0; 
  background-image: radial-gradient(rgba(45, 107, 106, 0.1) 1px, transparent 1px);
  background-size: 40px 40px; opacity: 0.5;
}.sv-scene-root-scene-07 .s-ghost-text{
  position: absolute; bottom: 5%; right: 5%; font-family: var(--sv-font-display-cn);
  font-size: 120px; color: #1A1210; opacity: 0.04; font-style: italic;
}.sv-scene-root-scene-07 .s-blob{
  position: absolute; border-radius: 50%; filter: blur(60px); opacity: 0.2;
  animation: s-blob-float 15s infinite alternate ease-in-out;
}.sv-scene-root-scene-07 .s-blob-1{ width: 400px; height: 400px; background: #F5C418; top: -100px; left: -100px; }.sv-scene-root-scene-07 .s-blob-2{ width: 350px; height: 350px; background: #2D6B6A; bottom: -50px; right: -50px; animation-delay: -7s; }/* 阶梯舞台 */
.sv-scene-root-scene-07 .s-stage-ladder{ position: relative; width: 800px; height: 450px; display: flex; align-items: center; justify-content: center; }.sv-scene-root-scene-07 .s-ladder-item{
  position: absolute; display: flex; flex-direction: column; align-items: center;
  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
  opacity: 0; transform: translateY(30px);
}.sv-scene-root-scene-07 .s-scene-07-root.step-ge-0 .s-ladder-item{ opacity: 1; transform: translateY(0); }.sv-scene-root-scene-07 .s-item-svm{ left: 50px; bottom: 50px; transition-delay: 0.1s; }.sv-scene-root-scene-07 .s-item-lstm{ left: 320px; bottom: 150px; transition-delay: 0.3s; }.sv-scene-root-scene-07 .s-item-transformer{ left: 590px; bottom: 250px; transition-delay: 0.5s; }/* 阶梯进化后的形态 (Step 1) */
.sv-scene-root-scene-07 .step-ge-1 .s-item-svm{ transform: scale(0.6) translate(100px, -50px); opacity: 0.4; }.sv-scene-root-scene-07 .step-ge-1 .s-item-lstm{ transform: scale(0.6) translate(0px, -50px); opacity: 0.4; }.sv-scene-root-scene-07 .step-ge-1 .s-item-transformer{ transform: scale(0.6) translate(-100px, -50px); opacity: 0.4; }.sv-scene-root-scene-07 .s-visual-box{
  width: 140px; height: 140px; background: #FFFFFF; border: 3px solid #1A1210; 
  border-radius: 16px; box-shadow: 0 8px 0 rgba(26,18,16,0.1); 
  display: flex; align-items: center; justify-content: center; margin-bottom: 12px;
}.sv-scene-root-scene-07 .s-label-badge{
  background: #2D6B6A; color: #FFF; padding: 4px 12px; border-radius: 20px;
  font-family: var(--sv-font-mono); font-size: 14px; border: 2px solid #1A1210;
}/* 特殊图形：注意力网格 */
.sv-scene-root-scene-07 .s-attention-grid{
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;
}.sv-scene-root-scene-07 .s-grid-dot{
  width: 12px; height: 12px; background: #EDE5CE; border: 1.5px solid #1A1210; border-radius: 3px;
}.sv-scene-root-scene-07 .s-grid-dot.active{ background: #F5C418; transform: scale(1.2); }/* 阶梯连接器 */
.sv-scene-root-scene-07 .s-ladder-connector{
  position: absolute; inset: 0; z-index: -1; opacity: 0; transition: opacity 1s;
}.sv-scene-root-scene-07 .step-ge-1 .s-ladder-connector{ opacity: 0.3; }.sv-scene-root-scene-07 .s-ladder-path{ stroke-dasharray: 500; stroke-dashoffset: 500; transition: stroke-dashoffset 1.5s ease-in-out; }.sv-scene-root-scene-07 .step-ge-1 .s-ladder-path{ stroke-dashoffset: 0; }/* 数字大脑 (Step 2) */
.sv-scene-root-scene-07 .s-brain-container{
  position: absolute; top: 20%; left: 50%; transform: translate(-50%, -100%) scale(0.5);
  opacity: 0; transition: all 1s cubic-bezier(0.22, 1, 0.36, 1);
}.sv-scene-root-scene-07 .step-ge-1 .s-brain-container{ opacity: 1; transform: translate(-50%, -40%) scale(1.2); }.sv-scene-root-scene-07 .s-brain-core{ position: relative; z-index: 2; }.sv-scene-root-scene-07 .s-brain-icon{ font-size: 160px; color: #1A1210; filter: drop-shadow(0 0 15px rgba(245, 196, 24, 0.4)); }.sv-scene-root-scene-07 .s-brain-glow{
  position: absolute; top: 50%; left: 50%; width: 200px; height: 200px;
  background: radial-gradient(circle, #F5C418 0%, transparent 70%);
  transform: translate(-50%, -50%); filter: blur(30px); opacity: 0.4;
  animation: s-brain-pulse 2s infinite alternate;
}.sv-scene-root-scene-07 .s-orbit{
  position: absolute; border: 1.5px solid #2D6B6A; border-radius: 50%;
  top: 50%; left: 50%; transform: translate(-50%, -50%);
  animation: s-rotate 10s linear infinite;
}.sv-scene-root-scene-07 .s-orbit:nth-child(1){ width: 220px; height: 100px; transform: translate(-50%, -50%) rotate(45deg); }.sv-scene-root-scene-07 .s-orbit:nth-child(2){ width: 220px; height: 100px; transform: translate(-50%, -50%) rotate(-45deg); animation-duration: 15s; }/* 结语全屏淡出 (Step 3) */
.sv-scene-root-scene-07 .s-final-curtain{
  position: absolute; inset: 0; background: #1A1210; z-index: 100;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none; transition: opacity 1.5s ease-in-out;
}.sv-scene-root-scene-07 .step-ge-2 .s-final-curtain{ opacity: 1; pointer-events: auto; }.sv-scene-root-scene-07 .s-conclusion-text{
  font-family: var(--sv-font-display-cn); font-size: 72px; color: #F5C418;
  text-shadow: 0 0 30px rgba(245, 196, 24, 0.5); transform: scale(0.9);
  transition: transform 2s cubic-bezier(0.16, 1, 0.3, 1);
}.sv-scene-root-scene-07 .step-ge-2 .s-conclusion-text{ transform: scale(1); }/* 动画关键帧 */
.sv-scene-root-scene-07 @keyframes s-blob-float{ from { transform: translate(0, 0); } to { transform: translate(40px, 60px); } }@keyframes s-brain-pulse{ from { opacity: 0.3; transform: translate(-50%, -50%) scale(0.9); } to { opacity: 0.6; transform: translate(-50%, -50%) scale(1.1); } }@keyframes s-rotate{ from { transform: translate(-50%, -50%) rotate(0); } to { transform: translate(-50%, -50%) rotate(360deg); } }
  </style>
</head>
<body data-orientation="landscape">
  <div id="app">
    <div id="viewport">
      <div id="stage">

<section class="scene" data-framework-scene-id="scene-01" data-scene-id="scene-01">
  <div class="sv-scene-root sv-scene-root-scene-01" data-scene-root-id="scene-01">
<div class="s-scene-01-root" data-scene-root-id="scene-01">
  <!-- 氛围背景层 -->
  <div class="s-bg-ambient">
    <div class="s-aurora"></div>
    <div class="s-particles"></div>
  </div>

  <!-- 核心视觉区域 -->
  <div class="s-content-wrapper">
    <!-- Step 0: NLP 核心文字 -->
    <div class="s-hero-text-container">
      <div class="s-nlp-glow">NLP</div>
      <h1 class="s-nlp-text">NLP</h1>
      <!-- Step 1: 波纹扩散 -->
      <div class="s-ripple-container" data-step="1">
        <div class="s-ripple"></div>
        <div class="s-ripple"></div>
      </div>
    </div>

    <!-- Step 2: 漂浮元素群 -->
    <div class="s-float-elements" data-step="2">
      <!-- 二进制碎块 -->
      <div class="s-bit s-pos-1">01</div>
      <div class="s-bit s-pos-2">10</div>
      <div class="s-bit s-pos-3">1</div>
      
      <!-- 转化后的图标 -->
      <div class="s-icon-box s-box-book">
        <i data-lucide="book-open-check"></i>
        <span>语料知识</span>
      </div>
      <div class="s-icon-box s-box-chat">
        <i data-lucide="message-square-code"></i>
        <span>对话交互</span>
      </div>
      <div class="s-icon-box s-box-net">
        <i data-lucide="network"></i>
        <span>神经计算</span>
      </div>
    </div>
  </div>

  <!-- 底部装饰标语 -->
  <div class="s-footer-tag">
    <span class="s-tag-line">NATURAL LANGUAGE PROCESSING</span>
  </div>
</div>
  </div>
</section>

<section class="scene" data-framework-scene-id="scene-02" data-scene-id="scene-02">
  <div class="sv-scene-root sv-scene-root-scene-02" data-scene-root-id="scene-02">
<div class="s-scene-02-root" data-scene-root-id="scene-02">
  <!-- 氛围背景 -->
  <div class="s-bg-ambient">
    <div class="s-bg-grid"></div>
    <div class="s-bg-glow"></div>
  </div>

  <!-- 核心画布：多维特征空间 -->
  <div class="s-perspective-container">
    <div class="s-svm-space">
      <!-- 切割超平面 (Step 1) -->
      <div class="s-hyperplane-wrapper" data-step="0">
        <div class="s-hyperplane">
          <div class="s-hyperplane-glow"></div>
        </div>
      </div>

      <!-- 数据点群 -->
      <div class="s-points-container">
        <!-- 类别 A: 珊瑚红点 (分布在左上方) -->
        <div class="s-point s-type-a s-p1" style="--x:15%; --y:20%;"></div>
        <div class="s-point s-type-a s-p2" style="--x:25%; --y:45%;"></div>
        <div class="s-point s-type-a s-p3" style="--x:10%; --y:60%;"></div>
        <div class="s-point s-type-a s-p4 s-sv" style="--x:35%; --y:35%;">
          <div class="s-sv-box"></div>
        </div>

        <!-- 类别 B: 深青绿点 (分布在右下方) -->
        <div class="s-point s-type-b s-p5" style="--x:80%; --y:70%;"></div>
        <div class="s-point s-type-b s-p6" style="--x:65%; --y:85%;"></div>
        <div class="s-point s-type-b s-p7" style="--x:85%; --y:40%;"></div>
        <div class="s-point s-type-b s-p8 s-sv" style="--x:55%; --y:65%;">
          <div class="s-sv-box"></div>
        </div>
      </div>

      <!-- 支持向量标注 (Step 3) -->
      <div class="s-labels-layer" data-step="2">
        <div class="s-sv-label s-label-top">Support Vector</div>
        <div class="s-sv-label s-label-bottom">Support Vector</div>
      </div>
    </div>
  </div>

  <!-- 文案区域 -->
  <div class="s-info-overlay">
    <div class="s-title-badge">SVM (支持向量机)</div>
    <h2 class="s-main-title">空间的“手术刀”</h2>
    <div class="s-description">
      <p>在多维特征空间中，寻找一个最优超平面</p>
      <p>将复杂的文本特征实现强行剥离</p>
    </div>
  </div>

  <!-- 底部装饰 -->
  <div class="s-footer-deco">
    <span class="s-coord-tag">DIMENSION: HIGH-DENSE</span>
    <div class="s-deco-line"></div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-framework-scene-id="scene-03" data-scene-id="scene-03">
  <div class="sv-scene-root sv-scene-root-scene-03" data-scene-root-id="scene-03">
<div class="s-scene-03-root" data-scene-root-id="scene-03">
  <!-- 背景氛围层 -->
  <div class="s-bg-ambient">
    <div class="s-bg-dots"></div>
    <div class="s-bg-grid"></div>
    <div class="s-ghost-text">RECURRENT NEURAL NETWORK</div>
  </div>

  <!-- 顶部标题区 -->
  <div class="s-header-area">
    <div class="s-badge">序列处理</div>
    <h1 class="s-main-title">RNN：带记忆的舞者</h1>
  </div>

  <!-- 核心可视化容器 -->
  <div class="s-network-container">
    <!-- 1. 递归单元 (原始结构) -->
    <div class="s-rnn-single-unit" data-step="0">
      <div class="s-node-group">
        <div class="s-node s-node-y">y</div>
        <div class="s-node s-node-h">
          h
          <svg class="s-self-loop" viewBox="0 0 100 100">
            <path d="M 70 30 C 110 0, 110 100, 70 70" fill="none" stroke="#1A1210" stroke-width="3" stroke-dasharray="4 2" />
            <path d="M 70 70 L 75 75 L 65 75 Z" fill="#1A1210" />
          </svg>
        </div>
        <div class="s-node s-node-x">x</div>
      </div>
      <div class="s-unit-label">折叠形式</div>
    </div>

    <!-- 2. 展开后的链式结构 -->
    <div class="s-rnn-unrolled">
      <div class="s-chain-arrow" data-step="1">
        <svg width="60" height="40"><path d="M 0 20 L 50 20 L 40 10 M 40 30 L 50 20" fill="none" stroke="#2D6B6A" stroke-width="4" stroke-linecap="round"/></svg>
      </div>

      <div class="s-chain-steps">
        <!-- t-1 -->
        <div class="s-chain-node s-t1" data-step="1">
          <div class="s-node-box s-box-y">y<sub>t-1</sub></div>
          <div class="s-node-box s-box-h">h<sub>t-1</sub></div>
          <div class="s-node-box s-box-x">x<sub>t-1</sub></div>
        </div>
        <!-- t -->
        <div class="s-chain-node s-t2" data-step="1">
          <div class="s-node-box s-box-y">y<sub>t</sub></div>
          <div class="s-node-box s-box-h">h<sub>t</sub></div>
          <div class="s-node-box s-box-x">x<sub>t</sub></div>
        </div>
        <!-- t+1 -->
        <div class="s-chain-node s-t3" data-step="1">
          <div class="s-node-box s-box-y">y<sub>t+1</sub></div>
          <div class="s-node-box s-box-h">h<sub>t+1</sub></div>
          <div class="s-node-box s-box-x">x<sub>t+1</sub></div>
        </div>
      </div>
    </div>

    <!-- 3. 梯度消失视觉表现 -->
    <div class="s-vanishing-effect" data-step="2">
      <div class="s-warning-tag">梯度消失 / 信息丢失</div>
      <div class="s-flow-overlay"></div>
    </div>
  </div>

  <!-- 底部说明区 -->
  <div class="s-footer-tags">
    <div class="s-tag"><i data-lucide="brain"></i> 短期记忆</div>
    <div class="s-tag"><i data-lucide="clock"></i> 时序依赖</div>
    <div class="s-deco-line"></div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-framework-scene-id="scene-04" data-scene-id="scene-04">
  <div class="sv-scene-root sv-scene-root-scene-04" data-scene-root-id="scene-04">
<div class="s-scene-04-root" data-scene-root-id="scene-04">
  <!-- 背景氛围层 -->
  <div class="s-bg-ambient">
    <div class="s-bg-glow"></div>
    <div class="s-bg-grid"></div>
    <div class="s-ghost-text">LONG SHORT-TERM MEMORY</div>
  </div>

  <div class="s-main-container">
    <!-- 顶部标题区 -->
    <div class="s-header-group">
      <div class="s-badge">核心架构</div>
      <h2 class="s-hero-title">LSTM：精密的记忆盒</h2>
    </div>

    <!-- 细胞状态长线 (贯穿横屏) -->
    <div class="s-cell-state-line">
      <div class="s-line-glow"></div>
      <div class="s-state-label">CELL STATE (长期记忆)</div>
    </div>

    <!-- LSTM 核心机械盒 -->
    <div class="s-lstm-box">
      <!-- 遗忘门 (Forget Gate) -->
      <div class="s-gate s-forget-gate" data-step="0">
        <div class="s-gate-glass">
          <iconify-icon icon="lucide:trash-2" class="s-gate-icon"></iconify-icon>
          <span class="s-gate-label">Forget Gate</span>
        </div>
        <!-- 杂乱碎片过滤动画 -->
        <div class="s-debris-container">
          <div class="s-debris s-d1"></div>
          <div class="s-debris s-d2"></div>
          <div class="s-debris s-d3"></div>
        </div>
      </div>

      <!-- 输入门 (Input Gate) -->
      <div class="s-gate s-input-gate" data-step="1">
        <div class="s-gate-glass">
          <iconify-icon icon="lucide:download" class="s-gate-icon"></iconify-icon>
          <span class="s-gate-label">Input Gate</span>
        </div>
        <!-- 金色光球 -->
        <div class="s-golden-orb"></div>
      </div>

      <!-- 输出门 (Output Gate) -->
      <div class="s-gate s-output-gate" data-step="2">
        <div class="s-gate-glass">
          <iconify-icon icon="lucide:unplug" class="s-gate-icon"></iconify-icon>
          <span class="s-gate-label">Output Gate</span>
        </div>
        <!-- 释放出的光芒 -->
        <div class="s-output-light"></div>
      </div>
    </div>

    <!-- 装饰元素 -->
    <div class="s-flow-indicators">
      <svg width="100%" height="100%" viewBox="0 0 800 400">
        <path class="s-flow-path" d="M50,200 L750,200" stroke="#F5C418" stroke-width="2" fill="none" stroke-dasharray="10,10" />
      </svg>
    </div>
  </div>

  <div class="s-footer-info">
    <div class="s-mono-tag">STRUCTURE: GATED_RECURRENT_UNIT</div>
    <div class="s-deco-line"></div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-framework-scene-id="scene-05" data-scene-id="scene-05">
  <div class="sv-scene-root sv-scene-root-scene-05" data-scene-root-id="scene-05">
<div class="s-scene-05-root" data-scene-root-id="scene-05">
  <!-- 背景氛围层 -->
  <div class="s-bg-ambient">
    <div class="s-bg-glow"></div>
    <div class="s-bg-grid"></div>
    <div class="s-ghost-text">TRANSFORMER</div>
  </div>

  <div class="s-main-container">
    <!-- 顶部标题区 -->
    <div class="s-header-group">
      <div class="s-badge">颠覆性架构</div>
      <h2 class="s-hero-title">自注意力：瞬间的全局连接</h2>
    </div>

    <!-- 核心视觉区：Transformer 节点网格 -->
    <div class="s-transformer-core">
      <!-- 中心圆环 -->
      <div class="s-center-hub">
        <div class="s-hub-ring"></div>
        <div class="s-hub-core">
          <iconify-icon icon="lucide:cpu" class="s-hub-icon"></iconify-icon>
        </div>
      </div>

      <!-- 节点容器 (由JS生成或在此静态定义10个) -->
      <div class="s-nodes-container" data-step="0">
        <!-- Node 1-10 -->
        <div class="s-node" style="--i:0"><span class="s-node-label">我</span></div>
        <div class="s-node" style="--i:1"><span class="s-node-label">爱</span></div>
        <div class="s-node" style="--i:2"><span class="s-node-label">自然</span></div>
        <div class="s-node" style="--i:3"><span class="s-node-label">语言</span></div>
        <div class="s-node" style="--i:4"><span class="s-node-label">处理</span></div>
        <div class="s-node" style="--i:5"><span class="s-node-label">深度</span></div>
        <div class="s-node" style="--i:6"><span class="s-node-label">学习</span></div>
        <div class="s-node" style="--i:7"><span class="s-node-label">计算</span></div>
        <div class="s-node" style="--i:8"><span class="s-node-label">未来</span></div>
        <div class="s-node" style="--i:9"><span class="s-node-label">智能</span></div>
      </div>

      <!-- 连线容器 (SVG) -->
      <svg class="s-attention-mesh" viewBox="0 0 800 800">
        <g class="s-lines-group"></g>
      </svg>
    </div>
  </div>

  <!-- 底部标签 -->
  <div class="s-footer-info">
    <div class="s-mono-tag">MECHANISM: SELF-ATTENTION</div>
    <div class="s-deco-line"></div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-framework-scene-id="scene-06" data-scene-id="scene-06">
  <div class="sv-scene-root sv-scene-root-scene-06" data-scene-root-id="scene-06">
<div class="s-scene-06-root" data-scene-root-id="scene-06">
  <!-- 背景氛围层 -->
  <div class="s-bg-ambient">
    <div class="s-bg-nebula"></div>
    <div class="s-bg-grid-moving"></div>
    <div class="s-ghost-title">PARALLEL COMPUTING</div>
  </div>

  <div class="s-main-stage">
    <!-- 文字标签层 -->
    <div class="s-side-text s-left" data-step="1">并行计算</div>
    <div class="s-side-text s-right" data-step="1">全局关联</div>

    <!-- 核心视觉容器：用于镜头拉远和旋转 -->
    <div class="s-camera-rig">
      <div class="s-nebula-vortex">
        <!-- 眼睛图标 -->
        <div class="s-eye-container">
          <div class="s-eye-outer">
            <div class="s-eye-iris">
              <div class="s-matrix-core">
                <!-- 矩阵代码流由JS生成 -->
              </div>
            </div>
          </div>
        </div>

        <!-- 编码器集群 (Step 1 显示) -->
        <div class="s-encoder-grid" data-step="0">
          <!-- 12个编码器模块 -->
          <div class="s-encoder-block" style="--idx:0"><span>Enc_01</span></div>
          <div class="s-encoder-block" style="--idx:1"><span>Enc_02</span></div>
          <div class="s-encoder-block" style="--idx:2"><span>Enc_03</span></div>
          <div class="s-encoder-block" style="--idx:3"><span>Enc_04</span></div>
          <div class="s-encoder-block" style="--idx:4"><span>Enc_05</span></div>
          <div class="s-encoder-block" style="--idx:5"><span>Enc_06</span></div>
          <div class="s-encoder-block" style="--idx:6"><span>Enc_07</span></div>
          <div class="s-encoder-block" style="--idx:7"><span>Enc_08</span></div>
          <div class="s-encoder-block" style="--idx:8"><span>Enc_09</span></div>
          <div class="s-encoder-block" style="--idx:9"><span>Enc_10</span></div>
          <div class="s-encoder-block" style="--idx:10"><span>Enc_11</span></div>
          <div class="s-encoder-block" style="--idx:11"><span>Enc_12</span></div>
        </div>
      </div>
    </div>
  </div>

  <!-- 底部装饰 -->
  <div class="s-footer-tag">
    <div class="s-badge-mini">ARCHITECTURE</div>
    <div class="s-tag-line">TRANSFORMER PARALLELISM</div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-framework-scene-id="scene-07" data-scene-id="scene-07">
  <div class="sv-scene-root sv-scene-root-scene-07" data-scene-root-id="scene-07">
<div class="s-scene-07-root" data-scene-root-id="scene-07">
  <!-- 背景氛围层 -->
  <div class="s-ambient-layer">
    <div class="s-ambient-grid"></div>
    <div class="s-ghost-text">EVOLUTION</div>
    <div class="s-ambient-blobs">
      <div class="s-blob s-blob-1"></div>
      <div class="s-blob s-blob-2"></div>
    </div>
  </div>

  <!-- 主舞台：算法阶梯 -->
  <div class="s-stage-ladder">
    <!-- Step 0: 三大算法图表 -->
    <div class="s-ladder-item s-item-svm" data-step="0">
      <div class="s-visual-box">
        <svg viewBox="0 0 120 120" class="s-svg-icon">
          <circle cx="30" cy="40" r="5" fill="#E05A3A" stroke="#1A1210" stroke-width="2" />
          <circle cx="45" cy="25" r="5" fill="#E05A3A" stroke="#1A1210" stroke-width="2" />
          <circle cx="80" cy="85" r="5" fill="#2D6B6A" stroke="#1A1210" stroke-width="2" />
          <circle cx="95" cy="70" r="5" fill="#2D6B6A" stroke="#1A1210" stroke-width="2" />
          <line x1="10" y1="110" x2="110" y2="10" stroke="#1A1210" stroke-width="3" stroke-dasharray="4" />
        </svg>
      </div>
      <div class="s-label-badge">SVM</div>
    </div>

    <div class="s-ladder-item s-item-lstm" data-step="0">
      <div class="s-visual-box">
        <svg viewBox="0 0 120 120" class="s-svg-icon">
          <rect x="20" y="40" width="80" height="40" rx="8" fill="#FFFFFF" stroke="#1A1210" stroke-width="2.5" />
          <circle cx="40" cy="60" r="8" fill="#F5C418" stroke="#1A1210" stroke-width="2" />
          <circle cx="60" cy="60" r="8" fill="#F5C418" stroke="#1A1210" stroke-width="2" />
          <circle cx="80" cy="60" r="8" fill="#F5C418" stroke="#1A1210" stroke-width="2" />
          <path d="M10,60 L20,60 M100,60 L110,60" stroke="#1A1210" stroke-width="2" />
        </svg>
      </div>
      <div class="s-label-badge">LSTM</div>
    </div>

    <div class="s-ladder-item s-item-transformer" data-step="0">
      <div class="s-visual-box">
        <div class="s-attention-grid">
          <div class="s-grid-dot"></div><div class="s-grid-dot"></div><div class="s-grid-dot"></div>
          <div class="s-grid-dot active"></div><div class="s-grid-dot"></div><div class="s-grid-dot"></div>
          <div class="s-grid-dot"></div><div class="s-grid-dot active"></div><div class="s-grid-dot"></div>
        </div>
      </div>
      <div class="s-label-badge">TRANSFORMER</div>
    </div>

    <!-- Step 1: 阶梯连接线 -->
    <svg class="s-ladder-connector" viewBox="0 0 800 400">
        <path class="s-ladder-path" d="M150,300 L350,200 L550,100" fill="none" stroke="#1A1210" stroke-width="2" stroke-dasharray="8 8" />
    </svg>

    <!-- Step 2: 数字大脑 -->
    <div class="s-brain-container" data-step="1">
       <div class="s-brain-core">
          <div class="s-brain-halves">
             <iconify-icon icon="ph:brain-duotone" class="s-brain-icon"></iconify-icon>
          </div>
          <div class="s-data-orbits">
             <div class="s-orbit"></div>
             <div class="s-orbit"></div>
          </div>
       </div>
       <div class="s-brain-glow"></div>
    </div>
  </div>

  <!-- Step 3: 总结结语 -->
  <div class="s-final-curtain" data-step="2">
    <div class="s-conclusion-text">从理解 到 创造</div>
  </div>
</div>
  </div>
</section>
      </div>
    </div>
  </div>
  <script id="__SVGVIDEO_META__" type="application/json">{"version":2,"format":"json","title":"从SVM到Transformer：自然语言处理的进化史","fullScript":"在自然语言处理的长河中，我们对语言的理解经历了一场从统计到智能的华丽蜕变。最初，我们依赖于像支持向量机SVM这样的经典算法，它通过寻找一个最优超平面，将文本特征在多维空间中强行剥离，简单粗暴却开辟了分类的先河。然而，语言是有序列的。为了抓住词语间的上下文，循环神经网络RNN应运而生。它像一个拥有短期记忆的舞者，在时序中传递信息，但遗憾的是，它总是因为距离太远而忘掉开头的伏笔。为了打破这个局限，长短期记忆网络LSTM登场了。它精妙地设计了输入门、遗忘门和输出门，通过一套复杂的细胞状态管理，让机器终于学会了什么该记住，什么该舍弃。但真正的颠覆发生在Transformer出现的那一刻。它彻底抛弃了低效的循环结构，凭借自注意力机制，让序列中的每个词都能在瞬间与所有其他词产生连接。它不再排队等待，而是全局俯瞰。从SVM的线性切割，到Transformer的全局理解，这不仅是算法的迭代，更是人类在机器理解智慧之路上的一次次跨越。","visualStyleId":"warm-edu","orientation":"landscape","scenes":[{"id":"scene-01","title":"NLP进化史序言","steps":3,"status":"success","prompt":"横屏构图。背景为深邃的极光渐变，带有微弱流动的粒子感。画面中央逐渐浮现出‘NLP’三个巨大的发光渐变文字。Step 1: 文字中心向外扩散出一圈波纹。Step 2: 周围浮现出散落的0和1二进制代码碎块，随后转化为书本、对话框和神经网络节点的浮动图标。整体风格呈现未来科技感。","scriptText":"在自然语言处理的长河中，我们对语言的理解经历了一场从统计到智能的华丽蜕变。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_dd23bdea-04b1-4c94-859a-0e3b9d9d4ef6/s_scene-01/v_xiaochen/a_8abd7b70_1780492638559_7p37mf.mp3","audioDurationMs":7416,"voiceName":"xiaochen","relatedSceneIds":["scene-02"],"transition":"door"},{"id":"scene-02","title":"SVM：空间切割者","steps":3,"status":"success","prompt":"横屏构图。左右两侧分布着蓝、红两色乱序排列的3D圆点。Step 1: 一条发光的切割线（超平面）斜着穿过屏幕中央，将圆点强行分开。Step 2: 空间开始倾斜，展示出多维空间的深度。Step 3: 切割线两侧出现虚线边框，标注出‘Support Vectors’（支持向量）。风格为硬朗的几何线条，带金属光泽。","scriptText":"最初，我们依赖于像支持向量机SVM这样的经典算法，它通过寻找一个最优超平面，将文本特征在多维空间中强行剥离，简单粗暴却开辟了分类的先河。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_dd23bdea-04b1-4c94-859a-0e3b9d9d4ef6/s_scene-02/v_xiaochen/a_895c7f96_1780492678515_99eo3w.mp3","audioDurationMs":14112,"voiceName":"xiaochen","relatedSceneIds":["scene-01","scene-03"],"transition":"door"},{"id":"scene-03","title":"RNN：时序的舞者","steps":3,"status":"success","prompt":"【重要规则】请以“用户最新修改要求”为最高优先级执行。\n【旧分镜画面提示词（仅供参考，可重写）】\n【重要规则】请以“用户最新修改要求”为最高优先级执行。\n【旧分镜画面提示词（仅供参考，可重写）】\n横屏构图。画面左侧出现一个循环箭头的图标，代表RNN单元。Step 1: 一个词语方块（Word A）进入单元，右侧输出一个带箭头的波纹。Step 2: 连续的方块（Word B, C, D）排队进入，下方的连线不断延伸，但颜色由深变淡。Step 3: 最右端的连线变得极细且断裂，象征梯度消失和信息丢失。动画呈现出一种传送带的节奏感。\n【用户最新修改要求（必须优先满足）】\n重新生成该分镜的画面表现和逻辑\n【用户最新修改要求（必须优先满足）】\n重新设计画面：展示RNN的基本网络结构。包含输入层x、隐藏层h及其自循环连接、输出层y。使用发光的线条和节点表现时序传递的过程，展示展开后的链式结构，体现序列处理的特点。","scriptText":"然而，语言是有序列的。为了抓住词语间的上下文，循环神经网络RNN应运而生。它像一个拥有短期记忆的舞者，在时序中传递信息，但遗憾的是，它总是因为距离太远而忘掉开头的伏笔。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_dd23bdea-04b1-4c94-859a-0e3b9d9d4ef6/s_scene-03/v_xiaochen/a_636bad29_1781142723565_p2qotv.mp3","audioDurationMs":17424,"voiceName":"xiaochen","relatedSceneIds":["scene-02","scene-04"],"transition":"door"},{"id":"scene-04","title":"LSTM：精密的记忆管理者","steps":4,"status":"success","prompt":"横屏构图。展示一个精密的机械盒子模型（LSTM Cell）。Step 1: 顶部‘遗忘门’亮起，过滤掉杂乱碎片。Step 2: 中间‘输入门’开启，存入新的金色光球。Step 3: 底部‘输出门’释放光芒，贯穿整个横屏的水平‘细胞状态’长线保持明亮。Step 4: 文字标签‘Forget/Input/Output’在对应组件旁淡入。视觉采用毛玻璃质感配合金色流光。","scriptText":"为了打破这个局限，长短期记忆网络LSTM登场了。它精妙地设计了输入门、遗忘门和输出门，通过一套复杂的细胞状态管理，让机器终于学会了什么该记住，什么该舍弃。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_dd23bdea-04b1-4c94-859a-0e3b9d9d4ef6/s_scene-04/v_xiaochen/a_1274edff_1780492776492_5uq7p5.mp3","audioDurationMs":15588,"voiceName":"xiaochen","relatedSceneIds":["scene-03","scene-05"],"transition":"door"},{"id":"scene-05","title":"Transformer：全局觉醒","steps":3,"status":"success","prompt":"横屏构图。中心是一个闪耀的核心圆环。Step 1: 圆环周围环绕排开10个文字节点。Step 2: 瞬间，所有节点之间同时发射出相互连接的光束（Self-Attention），形成一张极其复杂的发光网格。Step 3: 光束的粗细根据连接强度动态变化（Weights），画面充满震撼的全局爆发感。背景色彩由深蓝转为亮紫。","scriptText":"但真正的颠覆发生在Transformer出现的那一刻。它彻底抛弃了低效的循环结构，凭借自注意力机制，让序列中的每个词都能在瞬间与所有其他词产生连接。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_dd23bdea-04b1-4c94-859a-0e3b9d9d4ef6/s_scene-05/v_xiaochen/a_cf193775_1780492813594_aiky8w.mp3","audioDurationMs":14040,"voiceName":"xiaochen","relatedSceneIds":["scene-04","scene-06"],"transition":"door"},{"id":"scene-06","title":"全局俯瞰视角","steps":2,"status":"success","prompt":"横屏构图。画面中央是一个巨大的抽象眼睛图标，瞳孔处由Transformer的矩阵代码构成。Step 1: 镜头迅速拉远，展示出一排排并行排列的编码器模块。Step 2: 整个画面像星云一样旋转缩放，展现出并行计算的高效感。文字‘并行计算’和‘全局关联’以极简无衬线字体在两侧滑动显现。","scriptText":"它不再排队等待，而是全局俯瞰。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_dd23bdea-04b1-4c94-859a-0e3b9d9d4ef6/s_scene-06/v_xiaochen/a_05c0c8d0_1780492839472_n3uowb.mp3","audioDurationMs":3420,"voiceName":"xiaochen","relatedSceneIds":["scene-05","scene-07"],"transition":"door"},{"id":"scene-07","title":"智慧的跨越总结","steps":3,"status":"success","prompt":"横屏构图。左侧浮现SVM的切割线图，中间是LSTM的门控图，右侧是Transformer的注意力网格。Step 1: 三个图表连成一线，化作一道上升的阶梯。Step 2: 阶梯终点演变成一颗闪烁的数字大脑模型。Step 3: 全屏淡出为纯黑，中心留下一行发光的结语：‘从理解到创造’。整体视觉大气、稳重且富有哲学感。","scriptText":"从SVM的线性切割，到Transformer的全局理解，这不仅是算法的迭代，更是人类在机器理解智慧之路上的一次次跨越。","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_dd23bdea-04b1-4c94-859a-0e3b9d9d4ef6/s_scene-07/v_xiaochen/a_9583c8bb_1780492872415_t0ryls.mp3","audioDurationMs":10656,"voiceName":"xiaochen","relatedSceneIds":["scene-06"],"transition":"door"}]}</script>
  <script id="__SVGVIDEO_SCENE_DATA__" type="application/json">[{"id":"scene-01","title":"NLP进化史序言","steps":3,"html":"<div class=\"s-scene-01-root\" data-scene-root-id=\"scene-01\">\n  <!-- 氛围背景层 -->\n  <div class=\"s-bg-ambient\">\n    <div class=\"s-aurora\"></div>\n    <div class=\"s-particles\"></div>\n  </div>\n\n  <!-- 核心视觉区域 -->\n  <div class=\"s-content-wrapper\">\n    <!-- Step 0: NLP 核心文字 -->\n    <div class=\"s-hero-text-container\">\n      <div class=\"s-nlp-glow\">NLP</div>\n      <h1 class=\"s-nlp-text\">NLP</h1>\n      <!-- Step 1: 波纹扩散 -->\n      <div class=\"s-ripple-container\" data-step=\"1\">\n        <div class=\"s-ripple\"></div>\n        <div class=\"s-ripple\"></div>\n      </div>\n    </div>\n\n    <!-- Step 2: 漂浮元素群 -->\n    <div class=\"s-float-elements\" data-step=\"2\">\n      <!-- 二进制碎块 -->\n      <div class=\"s-bit s-pos-1\">01</div>\n      <div class=\"s-bit s-pos-2\">10</div>\n      <div class=\"s-bit s-pos-3\">1</div>\n      \n      <!-- 转化后的图标 -->\n      <div class=\"s-icon-box s-box-book\">\n        <i data-lucide=\"book-open-check\"></i>\n        <span>语料知识</span>\n      </div>\n      <div class=\"s-icon-box s-box-chat\">\n        <i data-lucide=\"message-square-code\"></i>\n        <span>对话交互</span>\n      </div>\n      <div class=\"s-icon-box s-box-net\">\n        <i data-lucide=\"network\"></i>\n        <span>神经计算</span>\n      </div>\n    </div>\n  </div>\n\n  <!-- 底部装饰标语 -->\n  <div class=\"s-footer-tag\">\n    <span class=\"s-tag-line\">NATURAL LANGUAGE PROCESSING</span>\n  </div>\n</div>","css":".s-scene-01-root {\n  width: 100%; height: 100%; background-color: #EDE5CE; \n  display: flex; justify-content: center; align-items: center; \n  overflow: hidden; position: relative; font-family: var(--sv-font-body-cn);\n}\n\n/* 氛围层：温暖极光感 */\n.s-bg-ambient { position: absolute; inset: 0; z-index: 1; }\n.s-aurora {\n  position: absolute; width: 150%; height: 150%; top: -25%; left: -25%;\n  background: radial-gradient(circle at 30% 30%, rgba(45, 107, 106, 0.15) 0%, transparent 50%),\n              radial-gradient(circle at 70% 70%, rgba(245, 196, 24, 0.1) 0%, transparent 50%);\n  filter: blur(60px); animation: s-aurora-drift 20s infinite alternate ease-in-out;\n}\n@keyframes s-aurora-drift { from { transform: rotate(0deg) scale(1); } to { transform: rotate(5deg) scale(1.1); } }\n\n/* 核心 NLP 文字 */\n.s-content-wrapper { position: relative; z-index: 10; display: flex; flex-direction: column; align-items: center; }\n.s-hero-text-container { position: relative; transform: scale(1.2); }\n.s-nlp-text {\n  font-family: var(--sv-font-display-cn); font-size: 160px; line-height: 1; color: #1A1210;\n  margin: 0; position: relative; z-index: 5; text-shadow: 4px 4px 0px #F5C418;\n  animation: s-text-pop 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n.s-nlp-glow {\n  position: absolute; inset: 0; font-family: var(--sv-font-display-cn); font-size: 160px;\n  color: #F5C418; filter: blur(20px); opacity: 0.4; pointer-events: none;\n}\n@keyframes s-text-pop { from { opacity: 0; transform: scale(0.5); } to { opacity: 1; transform: scale(1); } }\n\n/* Step 1: 波纹 */\n.s-ripple-container { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); pointer-events: none; opacity: 0; }\n.step-ge-1 .s-ripple-container { opacity: 1; }\n.s-ripple {\n  position: absolute; border: 3px solid #2D6B6A; border-radius: 50%;\n  width: 100px; height: 100px; left: -50px; top: -50px;\n  animation: s-ripple-out 2s infinite cubic-bezier(0.25, 0.46, 0.45, 0.94);\n}\n.s-ripple:nth-child(2) { animation-delay: 1s; }\n@keyframes s-ripple-out { \n  0% { transform: scale(1); opacity: 0.8; } \n  100% { transform: scale(8); opacity: 0; }\n}\n\n/* Step 2: 漂浮元素 */\n.s-float-elements { position: absolute; width: 800px; height: 500px; top: 50%; left: 50%; transform: translate(-50%, -50%); pointer-events: none; opacity: 0; }\n.step-ge-2 .s-float-elements { opacity: 1; transition: opacity 0.5s ease; }\n\n.s-bit { \n  position: absolute; font-family: var(--sv-font-mono); color: #2D6B6A; \n  font-size: 24px; font-weight: bold; opacity: 0.3; \n}\n.s-pos-1 { top: 10%; left: 10%; animation: s-float 4s infinite ease-in-out; }\n.s-pos-2 { bottom: 15%; right: 5%; animation: s-float 5s infinite ease-in-out -1s; }\n.s-pos-3 { top: 60%; left: -5%; animation: s-float 3s infinite ease-in-out -2s; }\n\n.s-icon-box {\n  position: absolute; background: #FFFFFF; border: 2.5px solid #1A1210;\n  padding: 12px 20px; border-radius: 16px; display: flex; align-items: center; gap: 10px;\n  box-shadow: 6px 6px 0px rgba(26, 18, 16, 0.1); transition: all 0.6s cubic-bezier(0.22, 1, 0.36, 1);\n}\n.s-icon-box i { width: 24px; height: 24px; color: #2D6B6A; }\n.s-icon-box span { font-family: var(--sv-font-body-cn); font-weight: bold; color: #1A1210; font-size: 18px; }\n\n.s-box-book { top: 0; right: 0; transform: rotate(5deg); }\n.s-box-chat { bottom: -20px; left: 15%; transform: rotate(-3deg); }\n.s-box-net { top: 70%; right: 10%; transform: rotate(2deg); }\n\n@keyframes s-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-20px); } }\n\n.s-footer-tag {\n  position: absolute; bottom: 40px; padding: 6px 20px; background: #2D6B6A; \n  border: 2px solid #1A1210; border-radius: 30px; transform: rotate(-1deg);\n}\n.s-tag-line { color: #FFFFFF; font-family: var(--sv-font-mono); font-size: 14px; letter-spacing: 2px; }","js":"window.SceneLifecycle.register('scene-01', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-root-id=\"scene-01\"]');\n    if (sceneRoot) {\n      // 初始化图标\n      if (window.__SVGVIDEO_REFRESH_ICONS) {\n        window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n      }\n      \n      // 进场随机微动\n      const boxes = sceneRoot.querySelectorAll('.s-icon-box');\n      boxes.forEach((box, i) => {\n        box.style.opacity = '0';\n        box.style.transform += ' translateY(40px)';\n      });\n    }\n  },\n  step(stepIndex) {\n    const sceneRoot = document.querySelector('[data-scene-root-id=\"scene-01\"]');\n    if (!sceneRoot) return;\n\n    if (stepIndex === 2) {\n      const boxes = sceneRoot.querySelectorAll('.s-icon-box');\n      boxes.forEach((box, i) => {\n        setTimeout(() => {\n          box.style.opacity = '1';\n          box.style.transform = box.style.transform.replace('translateY(40px)', 'translateY(0)');\n        }, i * 200);\n      });\n\n      // 增加背景粒子的活跃度\n      const aurora = sceneRoot.querySelector('.s-aurora');\n      if (aurora) aurora.style.animationDuration = '10s';\n    }\n  }\n});"},{"id":"scene-02","title":"SVM：空间切割者","steps":3,"html":"<div class=\"s-scene-02-root\" data-scene-root-id=\"scene-02\">\n  <!-- 氛围背景 -->\n  <div class=\"s-bg-ambient\">\n    <div class=\"s-bg-grid\"></div>\n    <div class=\"s-bg-glow\"></div>\n  </div>\n\n  <!-- 核心画布：多维特征空间 -->\n  <div class=\"s-perspective-container\">\n    <div class=\"s-svm-space\">\n      <!-- 切割超平面 (Step 1) -->\n      <div class=\"s-hyperplane-wrapper\" data-step=\"0\">\n        <div class=\"s-hyperplane\">\n          <div class=\"s-hyperplane-glow\"></div>\n        </div>\n      </div>\n\n      <!-- 数据点群 -->\n      <div class=\"s-points-container\">\n        <!-- 类别 A: 珊瑚红点 (分布在左上方) -->\n        <div class=\"s-point s-type-a s-p1\" style=\"--x:15%; --y:20%;\"></div>\n        <div class=\"s-point s-type-a s-p2\" style=\"--x:25%; --y:45%;\"></div>\n        <div class=\"s-point s-type-a s-p3\" style=\"--x:10%; --y:60%;\"></div>\n        <div class=\"s-point s-type-a s-p4 s-sv\" style=\"--x:35%; --y:35%;\">\n          <div class=\"s-sv-box\"></div>\n        </div>\n\n        <!-- 类别 B: 深青绿点 (分布在右下方) -->\n        <div class=\"s-point s-type-b s-p5\" style=\"--x:80%; --y:70%;\"></div>\n        <div class=\"s-point s-type-b s-p6\" style=\"--x:65%; --y:85%;\"></div>\n        <div class=\"s-point s-type-b s-p7\" style=\"--x:85%; --y:40%;\"></div>\n        <div class=\"s-point s-type-b s-p8 s-sv\" style=\"--x:55%; --y:65%;\">\n          <div class=\"s-sv-box\"></div>\n        </div>\n      </div>\n\n      <!-- 支持向量标注 (Step 3) -->\n      <div class=\"s-labels-layer\" data-step=\"2\">\n        <div class=\"s-sv-label s-label-top\">Support Vector</div>\n        <div class=\"s-sv-label s-label-bottom\">Support Vector</div>\n      </div>\n    </div>\n  </div>\n\n  <!-- 文案区域 -->\n  <div class=\"s-info-overlay\">\n    <div class=\"s-title-badge\">SVM (支持向量机)</div>\n    <h2 class=\"s-main-title\">空间的“手术刀”</h2>\n    <div class=\"s-description\">\n      <p>在多维特征空间中，寻找一个最优超平面</p>\n      <p>将复杂的文本特征实现强行剥离</p>\n    </div>\n  </div>\n\n  <!-- 底部装饰 -->\n  <div class=\"s-footer-deco\">\n    <span class=\"s-coord-tag\">DIMENSION: HIGH-DENSE</span>\n    <div class=\"s-deco-line\"></div>\n  </div>\n</div>","css":".s-scene-02-root {\n  width: 100%; height: 100%; background-color: #EDE5CE;\n  position: relative; overflow: hidden;\n  display: flex; align-items: center; justify-content: center;\n  font-family: var(--sv-font-body-cn);\n}\n\n/* 氛围层 */\n.s-bg-ambient { position: absolute; inset: 0; z-index: 1; }\n.s-bg-grid {\n  position: absolute; inset: 0;\n  background-image: radial-gradient(#1A1210 1px, transparent 1px);\n  background-size: 40px 40px; opacity: 0.05;\n}\n.s-bg-glow {\n  position: absolute; width: 60%; height: 60%; top: 20%; left: 20%;\n  background: radial-gradient(circle, rgba(245, 196, 24, 0.1) 0%, transparent 70%);\n  filter: blur(80px); animation: s-glow-pulse 8s infinite alternate ease-in-out;\n}\n@keyframes s-glow-pulse { from { transform: scale(1); opacity: 0.4; } to { transform: scale(1.3); opacity: 0.7; } }\n\n/* 3D 空间容器 */\n.s-perspective-container {\n  width: 1000px; height: 600px; z-index: 10;\n  perspective: 1500px; display: flex; align-items: center; justify-content: center;\n}\n.s-svm-space {\n  width: 100%; height: 100%; position: relative;\n  transform-style: preserve-3d; transition: transform 1.2s cubic-bezier(0.22, 1, 0.36, 1);\n}\n/* Step 2: 空间倾斜 */\n.step-ge-1 .s-svm-space {\n  transform: rotateX(40deg) rotateZ(-15deg) translateY(50px);\n}\n\n/* 超平面 (Step 1) */\n.s-hyperplane-wrapper {\n  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;\n  opacity: 0; transform: scaleX(0); transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);\n  z-index: 5;\n}\n.step-ge-0 .s-hyperplane-wrapper { opacity: 1; transform: scaleX(1); }\n.s-hyperplane {\n  width: 150%; height: 6px; background: #2D6B6A; border: 2px solid #1A1210;\n  transform: rotate(-35deg); position: relative;\n  box-shadow: 0 0 20px rgba(45, 107, 106, 0.4);\n}\n.s-hyperplane-glow {\n  position: absolute; inset: -4px; background: #F5C418; filter: blur(8px); opacity: 0.4;\n}\n\n/* 数据点 */\n.s-points-container { position: absolute; inset: 0; z-index: 10; }\n.s-point {\n  position: absolute; width: 24px; height: 24px; border-radius: 50%;\n  left: var(--x); top: var(--y); border: 2.5px solid #1A1210;\n  transition: all 1s cubic-bezier(0.22, 1, 0.36, 1);\n  box-shadow: 4px 4px 0 rgba(26, 18, 16, 0.1);\n}\n.s-type-a { background: #E05A3A; }\n.s-type-b { background: #2D6B6A; }\n\n/* Step 1: 强行剥离 (乱序到有序) */\n.s-p1, .s-p2, .s-p3, .s-p4 { transform: translate(-100px, -50px); }\n.s-p5, .s-p6, .s-p7, .s-p8 { transform: translate(100px, 50px); }\n.step-ge-0 .s-point { transform: translate(0, 0); }\n\n/* 支持向量标注 (Step 3) */\n.s-sv-box {\n  position: absolute; inset: -8px; border: 2px dashed #F5C418;\n  border-radius: 8px; opacity: 0; transform: scale(1.5); transition: all 0.5s ease;\n}\n.step-ge-2 .s-sv-box { opacity: 1; transform: scale(1); }\n\n.s-labels-layer {\n  position: absolute; inset: 0; pointer-events: none;\n  opacity: 0; transition: opacity 0.6s ease;\n}\n.step-ge-2 .s-labels-layer { opacity: 1; }\n.s-sv-label {\n  position: absolute; background: #F5C418; color: #1A1210;\n  padding: 4px 10px; border: 2px solid #1A1210; border-radius: 4px;\n  font-size: 14px; font-weight: bold; font-family: var(--sv-font-mono);\n}\n.s-label-top { left: 35%; top: 25%; transform: translate(-50%, -100%); }\n.s-label-bottom { left: 55%; top: 75%; transform: translate(-50%, 0); }\n\n/* 文案排版 */\n.s-info-overlay {\n  position: absolute; top: 60px; left: 80px; z-index: 100;\n}\n.s-title-badge {\n  display: inline-block; background: #2D6B6A; color: #FFFFFF;\n  padding: 4px 12px; border-radius: 20px; border: 2px solid #1A1210;\n  font-size: 14px; margin-bottom: 12px; transform: rotate(-1deg);\n}\n.s-main-title {\n  font-family: var(--sv-font-display-cn); font-size: 56px; color: #1A1210;\n  margin: 0; line-height: 1.1; text-shadow: 3px 3px 0 #F5C418;\n}\n.s-description {\n  margin-top: 15px; font-size: 18px; color: rgba(26, 18, 16, 0.7);\n  border-left: 4px solid #E05A3A; padding-left: 15px;\n}\n\n.s-footer-deco {\n  position: absolute; bottom: 40px; right: 80px; display: flex; align-items: center; gap: 15px;\n}\n.s-coord-tag { font-family: var(--sv-font-mono); font-size: 12px; color: #2D6B6A; letter-spacing: 2px; }\n.s-deco-line { width: 100px; height: 2px; background: #1A1210; }","js":"window.SceneLifecycle.register('scene-02', {\n  enter() {\n    const root = document.querySelector('[data-scene-root-id=\"scene-02\"]');\n    if (!root) return;\n\n    // 初始动画：点群随机微动\n    const points = root.querySelectorAll('.s-point');\n    points.forEach((p, i) => {\n      p.style.transitionDelay = `${i * 0.05}s`;\n      p.style.opacity = '0';\n      p.style.transform += ' scale(0)';\n    });\n\n    setTimeout(() => {\n      points.forEach(p => {\n        p.style.opacity = '1';\n        p.style.transform = p.style.transform.replace('scale(0)', 'scale(1)');\n      });\n    }, 300);\n  },\n\n  step(stepIndex) {\n    const root = document.querySelector('[data-scene-root-id=\"scene-02\"]');\n    if (!root) return;\n\n    if (stepIndex === 0) {\n       // Step 1 被 Step-ge-0 触发：超平面出现，点群归位\n    }\n\n    if (stepIndex === 1) {\n      // Step 2: 空间倾斜后的视差微调\n      const points = root.querySelectorAll('.s-point');\n      points.forEach((p, i) => {\n        p.style.boxShadow = '10px 10px 20px rgba(0,0,0,0.15)';\n      });\n    }\n\n    if (stepIndex === 2) {\n      // Step 3: 支持向量强调时的呼吸动画\n      const svBoxes = root.querySelectorAll('.s-sv-box');\n      svBoxes.forEach(box => {\n        box.animate([\n          { transform: 'scale(1)', opacity: 1 },\n          { transform: 'scale(1.1)', opacity: 0.7 },\n          { transform: 'scale(1)', opacity: 1 }\n        ], {\n          duration: 2000,\n          iterations: Infinity\n        });\n      });\n    }\n  }\n});"},{"id":"scene-03","title":"RNN：时序的舞者","steps":3,"html":"<div class=\"s-scene-03-root\" data-scene-root-id=\"scene-03\">\n  <!-- 背景氛围层 -->\n  <div class=\"s-bg-ambient\">\n    <div class=\"s-bg-dots\"></div>\n    <div class=\"s-bg-grid\"></div>\n    <div class=\"s-ghost-text\">RECURRENT NEURAL NETWORK</div>\n  </div>\n\n  <!-- 顶部标题区 -->\n  <div class=\"s-header-area\">\n    <div class=\"s-badge\">序列处理</div>\n    <h1 class=\"s-main-title\">RNN：带记忆的舞者</h1>\n  </div>\n\n  <!-- 核心可视化容器 -->\n  <div class=\"s-network-container\">\n    <!-- 1. 递归单元 (原始结构) -->\n    <div class=\"s-rnn-single-unit\" data-step=\"0\">\n      <div class=\"s-node-group\">\n        <div class=\"s-node s-node-y\">y</div>\n        <div class=\"s-node s-node-h\">\n          h\n          <svg class=\"s-self-loop\" viewBox=\"0 0 100 100\">\n            <path d=\"M 70 30 C 110 0, 110 100, 70 70\" fill=\"none\" stroke=\"#1A1210\" stroke-width=\"3\" stroke-dasharray=\"4 2\" />\n            <path d=\"M 70 70 L 75 75 L 65 75 Z\" fill=\"#1A1210\" />\n          </svg>\n        </div>\n        <div class=\"s-node s-node-x\">x</div>\n      </div>\n      <div class=\"s-unit-label\">折叠形式</div>\n    </div>\n\n    <!-- 2. 展开后的链式结构 -->\n    <div class=\"s-rnn-unrolled\">\n      <div class=\"s-chain-arrow\" data-step=\"1\">\n        <svg width=\"60\" height=\"40\"><path d=\"M 0 20 L 50 20 L 40 10 M 40 30 L 50 20\" fill=\"none\" stroke=\"#2D6B6A\" stroke-width=\"4\" stroke-linecap=\"round\"/></svg>\n      </div>\n\n      <div class=\"s-chain-steps\">\n        <!-- t-1 -->\n        <div class=\"s-chain-node s-t1\" data-step=\"1\">\n          <div class=\"s-node-box s-box-y\">y<sub>t-1</sub></div>\n          <div class=\"s-node-box s-box-h\">h<sub>t-1</sub></div>\n          <div class=\"s-node-box s-box-x\">x<sub>t-1</sub></div>\n        </div>\n        <!-- t -->\n        <div class=\"s-chain-node s-t2\" data-step=\"1\">\n          <div class=\"s-node-box s-box-y\">y<sub>t</sub></div>\n          <div class=\"s-node-box s-box-h\">h<sub>t</sub></div>\n          <div class=\"s-node-box s-box-x\">x<sub>t</sub></div>\n        </div>\n        <!-- t+1 -->\n        <div class=\"s-chain-node s-t3\" data-step=\"1\">\n          <div class=\"s-node-box s-box-y\">y<sub>t+1</sub></div>\n          <div class=\"s-node-box s-box-h\">h<sub>t+1</sub></div>\n          <div class=\"s-node-box s-box-x\">x<sub>t+1</sub></div>\n        </div>\n      </div>\n    </div>\n\n    <!-- 3. 梯度消失视觉表现 -->\n    <div class=\"s-vanishing-effect\" data-step=\"2\">\n      <div class=\"s-warning-tag\">梯度消失 / 信息丢失</div>\n      <div class=\"s-flow-overlay\"></div>\n    </div>\n  </div>\n\n  <!-- 底部说明区 -->\n  <div class=\"s-footer-tags\">\n    <div class=\"s-tag\"><i data-lucide=\"brain\"></i> 短期记忆</div>\n    <div class=\"s-tag\"><i data-lucide=\"clock\"></i> 时序依赖</div>\n    <div class=\"s-deco-line\"></div>\n  </div>\n</div>","css":".s-scene-03-root {\n  width: 100%; height: 100%; background-color: #EDE5CE;\n  position: relative; overflow: hidden; font-family: var(--sv-font-body-cn);\n  display: flex; flex-direction: column; align-items: center;\n}\n\n/* 背景装饰 */\n.s-bg-dots {\n  position: absolute; inset: 0; opacity: 0.05;\n  background-image: radial-gradient(#1A1210 1.5px, transparent 1.5px);\n  background-size: 30px 30px;\n}\n.s-bg-grid {\n  position: absolute; inset: 0; opacity: 0.03;\n  background-image: linear-gradient(#1A1210 1px, transparent 1px), linear-gradient(90deg, #1A1210 1px, transparent 1px);\n  background-size: 100px 100px;\n}\n.s-ghost-text {\n  position: absolute; top: 15%; left: 5%; font-family: var(--sv-font-mono); \n  font-size: 80px; font-weight: 900; color: rgba(26,18,16,0.03); white-space: nowrap;\n}\n\n/* 标题 */\n.s-header-area { align-self: flex-start; margin: 60px 0 0 80px; z-index: 10; }\n.s-badge { \n  background: #2D6B6A; color: #FFF; padding: 4px 12px; border-radius: 20px; \n  font-size: 14px; border: 2px solid #1A1210; display: inline-block; \n}\n.s-main-title {\n  font-family: var(--sv-font-display-cn); font-size: 52px; color: #1A1210;\n  margin: 10px 0; text-shadow: 3px 3px 0 #F5C418;\n}\n\n/* 可视化核心 */\n.s-network-container {\n  flex: 1; width: 100%; display: flex; align-items: center; justify-content: center; gap: 40px;\n  padding-bottom: 100px; /* 避开字幕 */\n}\n\n/* 递归单元 */\n.s-rnn-single-unit { \n  display: flex; flex-direction: column; align-items: center; gap: 15px;\n  padding: 30px; background: rgba(255,255,255,0.4); border-radius: 24px; border: 2px dashed #1A1210;\n}\n.s-node-group { display: flex; flex-direction: column; align-items: center; gap: 30px; position: relative; }\n.s-node {\n  width: 60px; height: 60px; border-radius: 50%; border: 3px solid #1A1210;\n  display: flex; align-items: center; justify-content: center; font-weight: bold;\n  font-family: var(--sv-font-mono); font-size: 24px;\n}\n.s-node-x { background: #F5C418; } \n.s-node-h { background: #2D6B6A; color: #FFF; position: relative; }\n.s-node-y { background: #E05A3A; color: #FFF; }\n.s-self-loop {\n  position: absolute; width: 80px; height: 80px; right: -60px; top: -10px;\n}\n.s-unit-label { font-size: 14px; color: rgba(26,18,16,0.6); font-weight: bold; }\n\n/* 展开后的链条 */\n.s-rnn-unrolled { display: flex; align-items: center; gap: 20px; }\n.s-chain-steps { display: flex; gap: 40px; }\n.s-chain-node {\n  display: flex; flex-direction: column; gap: 20px; opacity: 0; transform: translateX(20px);\n  transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n.step-ge-1 .s-chain-node { opacity: 1; transform: translateX(0); }\n.s-t1 { transition-delay: 0.2s; }\n.s-t2 { transition-delay: 0.4s; }\n.s-t3 { transition-delay: 0.6s; }\n\n.s-node-box {\n  width: 80px; height: 45px; border: 2.5px solid #1A1210; border-radius: 10px;\n  display: flex; align-items: center; justify-content: center; font-size: 16px;\n  font-family: var(--sv-font-mono); font-weight: bold; background: #FFF;\n  box-shadow: 4px 4px 0 rgba(26,18,16,0.1);\n}\n.s-box-x { background: #F5C418; }\n.s-box-h { background: #2D6B6A; color: #FFF; }\n.s-box-y { background: #E05A3A; color: #FFF; }\n\n/* 连接线 */\n.s-chain-node::before, .s-chain-node::after {\n  content: ''; position: absolute; left: 50%; width: 2px; height: 20px; background: #1A1210;\n}\n.s-chain-node .s-box-y { position: relative; }\n.s-chain-node .s-box-h { position: relative; }\n\n/* 梯度消失 */\n.s-vanishing-effect {\n  position: absolute; right: 10%; top: 50%; transform: translateY(-50%);\n  width: 300px; height: 200px; pointer-events: none;\n}\n.s-warning-tag {\n  background: #E05A3A; color: #FFF; padding: 6px 16px; border: 2px solid #1A1210;\n  border-radius: 4px; font-weight: bold; position: absolute; top: -40px; right: 0;\n  opacity: 0; transition: 0.5s;\n}\n.step-ge-2 .s-warning-tag { opacity: 1; animation: s-shake 0.5s infinite; }\n.s-flow-overlay {\n  position: absolute; inset: 0; \n  background: linear-gradient(90deg, transparent, #EDE5CE 80%);\n  opacity: 0; transition: 2s ease;\n}\n.step-ge-2 .s-flow-overlay { opacity: 1; }\n\n/* 底部装饰 */\n.s-footer-tags {\n  position: absolute; bottom: 40px; right: 80px; display: flex; align-items: center; gap: 24px;\n}\n.s-tag { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: bold; color: #2D6B6A; }\n.s-deco-line { width: 80px; height: 2px; background: #1A1210; }\n\n@keyframes s-shake {\n  0%, 100% { transform: rotate(0deg); } 25% { transform: rotate(2deg); } 75% { transform: rotate(-2deg); }\n}","js":"window.SceneLifecycle.register('scene-03', {\n  enter() {\n    const root = document.querySelector('[data-scene-root-id=\"scene-03\"]');\n    if (!root) return;\n\n    // 刷新图标\n    if (window.__SVGVIDEO_REFRESH_ICONS) {\n      window.__SVGVIDEO_REFRESH_ICONS(root);\n    }\n\n    // 持续的自循环动画\n    const loopPath = root.querySelector('.s-self-loop path');\n    if (loopPath) {\n      loopPath.animate([\n        { strokeDashoffset: '20' },\n        { strokeDashoffset: '0' }\n      ], {\n        duration: 1000,\n        iterations: Infinity,\n        easing: 'linear'\n      });\n    }\n\n    // 节点呼吸动效\n    const nodes = root.querySelectorAll('.s-node, .s-node-box');\n    nodes.forEach((node, i) => {\n      node.animate([\n        { transform: 'scale(1)', boxShadow: '4px 4px 0 rgba(26,18,16,0.1)' },\n        { transform: 'scale(1.03)', boxShadow: '6px 6px 0 rgba(26,18,16,0.15)' },\n        { transform: 'scale(1)', boxShadow: '4px 4px 0 rgba(26,18,16,0.1)' }\n      ], {\n        duration: 3000 + i * 200,\n        iterations: Infinity,\n        easing: 'ease-in-out'\n      });\n    });\n  },\n\n  step(index) {\n    const root = document.querySelector('[data-scene-root-id=\"scene-03\"]');\n    if (!root) return;\n\n    if (index === 2) {\n      // 梯度消失：连线变淡变细\n      const hBoxes = root.querySelectorAll('.s-box-h');\n      hBoxes.forEach((box, i) => {\n        if (i === 0) {\n           box.animate([\n             { opacity: 1, filter: 'grayscale(0)' },\n             { opacity: 0.3, filter: 'grayscale(1)' }\n           ], { duration: 1500, fill: 'forwards' });\n        }\n      });\n    }\n  }\n});"},{"id":"scene-04","title":"LSTM：精密的记忆管理者","steps":4,"html":"<div class=\"s-scene-04-root\" data-scene-root-id=\"scene-04\">\n  <!-- 背景氛围层 -->\n  <div class=\"s-bg-ambient\">\n    <div class=\"s-bg-glow\"></div>\n    <div class=\"s-bg-grid\"></div>\n    <div class=\"s-ghost-text\">LONG SHORT-TERM MEMORY</div>\n  </div>\n\n  <div class=\"s-main-container\">\n    <!-- 顶部标题区 -->\n    <div class=\"s-header-group\">\n      <div class=\"s-badge\">核心架构</div>\n      <h2 class=\"s-hero-title\">LSTM：精密的记忆盒</h2>\n    </div>\n\n    <!-- 细胞状态长线 (贯穿横屏) -->\n    <div class=\"s-cell-state-line\">\n      <div class=\"s-line-glow\"></div>\n      <div class=\"s-state-label\">CELL STATE (长期记忆)</div>\n    </div>\n\n    <!-- LSTM 核心机械盒 -->\n    <div class=\"s-lstm-box\">\n      <!-- 遗忘门 (Forget Gate) -->\n      <div class=\"s-gate s-forget-gate\" data-step=\"0\">\n        <div class=\"s-gate-glass\">\n          <iconify-icon icon=\"lucide:trash-2\" class=\"s-gate-icon\"></iconify-icon>\n          <span class=\"s-gate-label\">Forget Gate</span>\n        </div>\n        <!-- 杂乱碎片过滤动画 -->\n        <div class=\"s-debris-container\">\n          <div class=\"s-debris s-d1\"></div>\n          <div class=\"s-debris s-d2\"></div>\n          <div class=\"s-debris s-d3\"></div>\n        </div>\n      </div>\n\n      <!-- 输入门 (Input Gate) -->\n      <div class=\"s-gate s-input-gate\" data-step=\"1\">\n        <div class=\"s-gate-glass\">\n          <iconify-icon icon=\"lucide:download\" class=\"s-gate-icon\"></iconify-icon>\n          <span class=\"s-gate-label\">Input Gate</span>\n        </div>\n        <!-- 金色光球 -->\n        <div class=\"s-golden-orb\"></div>\n      </div>\n\n      <!-- 输出门 (Output Gate) -->\n      <div class=\"s-gate s-output-gate\" data-step=\"2\">\n        <div class=\"s-gate-glass\">\n          <iconify-icon icon=\"lucide:unplug\" class=\"s-gate-icon\"></iconify-icon>\n          <span class=\"s-gate-label\">Output Gate</span>\n        </div>\n        <!-- 释放出的光芒 -->\n        <div class=\"s-output-light\"></div>\n      </div>\n    </div>\n\n    <!-- 装饰元素 -->\n    <div class=\"s-flow-indicators\">\n      <svg width=\"100%\" height=\"100%\" viewBox=\"0 0 800 400\">\n        <path class=\"s-flow-path\" d=\"M50,200 L750,200\" stroke=\"#F5C418\" stroke-width=\"2\" fill=\"none\" stroke-dasharray=\"10,10\" />\n      </svg>\n    </div>\n  </div>\n\n  <div class=\"s-footer-info\">\n    <div class=\"s-mono-tag\">STRUCTURE: GATED_RECURRENT_UNIT</div>\n    <div class=\"s-deco-line\"></div>\n  </div>\n</div>","css":".s-scene-04-root {\n  width: 100%; height: 100%; background-color: #EDE5CE;\n  position: relative; overflow: hidden; font-family: var(--sv-font-body-cn);\n  display: flex; align-items: center; justify-content: center;\n}\n\n/* 背景装饰 */\n.s-bg-glow {\n  position: absolute; width: 600px; height: 600px; background: radial-gradient(circle, rgba(245,196,24,0.1) 0%, transparent 70%);\n  top: 50%; left: 50%; transform: translate(-50%, -50%); animation: s-glow-pulse 8s infinite ease-in-out;\n}\n@keyframes s-glow-pulse { 0%, 100% { opacity: 0.3; transform: translate(-50%, -50%) scale(1); } 50% { opacity: 0.6; transform: translate(-50%, -50%) scale(1.2); } }\n.s-bg-grid {\n  position: absolute; inset: 0; background-image: linear-gradient(rgba(26,18,16,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(26,18,16,0.03) 1px, transparent 1px);\n  background-size: 40px 40px;\n}\n.s-ghost-text {\n  position: absolute; top: 10%; left: 5%; font-family: var(--sv-font-mono); font-size: 80px; font-weight: 900; color: rgba(26,18,16,0.04); white-space: nowrap; pointer-events: none;\n}\n\n/* 核心容器 */\n.s-main-container {\n  width: 90%; height: 80%; position: relative; z-index: 10;\n  display: flex; flex-direction: column; align-items: center; justify-content: space-around;\n}\n\n.s-header-group { align-self: flex-start; margin-left: 40px; }\n.s-hero-title {\n  font-family: var(--sv-font-display-cn); font-size: 56px; color: #1A1210; margin-top: 10px;\n  text-shadow: 4px 4px 0px rgba(245, 196, 24, 0.4);\n}\n.s-badge { background: #2D6B6A; color: #FFF; padding: 4px 16px; border-radius: 30px; display: inline-block; font-size: 14px; border: 2px solid #1A1210; }\n\n/* 细胞状态长线 */\n.s-cell-state-line {\n  position: absolute; top: 50%; left: 0; width: 100%; height: 4px; background: #1A1210; z-index: 5;\n}\n.s-line-glow {\n  position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: #F5C418;\n  box-shadow: 0 0 15px #F5C418; opacity: 0; transition: opacity 0.8s ease;\n}\n.step-ge-2 .s-line-glow { opacity: 1; }\n.s-state-label {\n  position: absolute; right: 40px; top: -30px; font-family: var(--sv-font-mono); font-size: 12px; color: #2D6B6A; font-weight: bold;\n}\n\n/* LSTM 盒子 */\n.s-lstm-box {\n  width: 700px; height: 350px; display: flex; justify-content: space-between; align-items: center; position: relative; z-index: 10;\n}\n\n.s-gate {\n  width: 180px; height: 240px; position: relative;\n  opacity: 0; transform: translateY(30px); transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n.step-ge-0 .s-forget-gate { opacity: 1; transform: translateY(0); }\n.step-ge-1 .s-input-gate { opacity: 1; transform: translateY(0); transition-delay: 0.2s; }\n.step-ge-2 .s-output-gate { opacity: 1; transform: translateY(0); transition-delay: 0.4s; }\n\n.s-gate-glass {\n  width: 100%; height: 100%; background: rgba(255, 255, 255, 0.7); backdrop-filter: blur(8px);\n  border: 3px solid #1A1210; border-radius: 20px; box-shadow: 8px 8px 0 rgba(26,18,16,0.1);\n  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 15px;\n  position: relative; overflow: hidden;\n}\n.s-gate-icon { font-size: 50px; color: #2D6B6A; }\n.s-gate-label { font-family: var(--sv-font-display-cn); font-size: 22px; color: #1A1210; }\n\n/* 遗忘门动画 */\n.s-debris {\n  position: absolute; width: 15px; height: 15px; background: #E05A3A; border: 2px solid #1A1210;\n  top: -20px; opacity: 0;\n}\n.step-ge-0 .s-debris {\n  animation: s-debris-fall 2s infinite linear;\n}\n.s-d1 { left: 30%; animation-delay: 0s !important; }\n.s-d2 { left: 50%; animation-delay: 0.7s !important; }\n.s-d3 { left: 70%; animation-delay: 1.4s !important; }\n@keyframes s-debris-fall {\n  0% { transform: translateY(0) rotate(0deg); opacity: 0; }\n  30% { opacity: 1; }\n  70% { opacity: 1; }\n  100% { transform: translateY(120px) rotate(360deg); opacity: 0; }\n}\n\n/* 输入门光球 */\n.s-golden-orb {\n  position: absolute; width: 40px; height: 40px; background: #F5C418; border-radius: 50%; border: 3px solid #1A1210;\n  top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0); box-shadow: 0 0 20px #F5C418;\n  transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n}\n.step-ge-1 .s-golden-orb { transform: translate(-50%, -50%) scale(1.2); }\n\n/* 输出门流束 */\n.s-output-light {\n  position: absolute; top: 50%; left: 100%; width: 0; height: 4px; background: #F5C418; box-shadow: 0 0 10px #F5C418;\n  transition: width 0.6s ease-out 0.6s;\n}\n.step-ge-2 .s-output-light { width: 100px; }\n\n/* 页脚 */\n.s-footer-info { position: absolute; bottom: 40px; right: 60px; display: flex; align-items: center; gap: 20px; }\n.s-mono-tag { font-family: var(--sv-font-mono); font-size: 14px; color: rgba(26,18,16,0.6); }\n.s-deco-line { width: 60px; height: 2px; background: #E05A3A; }\n\n/* 文本标签淡入 */\n.s-gate-label { opacity: 0; transform: scale(0.9); transition: 0.4s; }\n.step-ge-3 .s-gate-label { opacity: 1; transform: scale(1); }","js":"window.SceneLifecycle.register('scene-04', {\n  enter() {\n    const root = document.querySelector('[data-scene-root-id=\"scene-04\"]');\n    if (!root) return;\n    \n    // 刷新图标\n    if (window.__SVGVIDEO_REFRESH_ICONS) {\n      window.__SVGVIDEO_REFRESH_ICONS(root);\n    }\n\n    // 盒子微动\n    const gates = root.querySelectorAll('.s-gate-glass');\n    gates.forEach((gate, i) => {\n      gate.animate([\n        { transform: 'translateY(0px)' },\n        { transform: 'translateY(-8px)' },\n        { transform: 'translateY(0px)' }\n      ], {\n        duration: 3000,\n        delay: i * 500,\n        iterations: Infinity,\n        easing: 'ease-in-out'\n      });\n    });\n  },\n  \n  step(index) {\n    const root = document.querySelector('[data-scene-root-id=\"scene-04\"]');\n    if (!root) return;\n\n    if (index === 1) {\n      // 输入门开启时的脉冲\n      const orb = root.querySelector('.s-golden-orb');\n      if (orb) {\n        orb.animate([\n          { boxShadow: '0 0 0px #F5C418' },\n          { boxShadow: '0 0 30px #F5C418' },\n          { boxShadow: '0 0 10px #F5C418' }\n        ], { duration: 1000, iterations: Infinity });\n      }\n    }\n  }\n});"},{"id":"scene-05","title":"Transformer：全局觉醒","steps":3,"html":"<div class=\"s-scene-05-root\" data-scene-root-id=\"scene-05\">\n  <!-- 背景氛围层 -->\n  <div class=\"s-bg-ambient\">\n    <div class=\"s-bg-glow\"></div>\n    <div class=\"s-bg-grid\"></div>\n    <div class=\"s-ghost-text\">TRANSFORMER</div>\n  </div>\n\n  <div class=\"s-main-container\">\n    <!-- 顶部标题区 -->\n    <div class=\"s-header-group\">\n      <div class=\"s-badge\">颠覆性架构</div>\n      <h2 class=\"s-hero-title\">自注意力：瞬间的全局连接</h2>\n    </div>\n\n    <!-- 核心视觉区：Transformer 节点网格 -->\n    <div class=\"s-transformer-core\">\n      <!-- 中心圆环 -->\n      <div class=\"s-center-hub\">\n        <div class=\"s-hub-ring\"></div>\n        <div class=\"s-hub-core\">\n          <iconify-icon icon=\"lucide:cpu\" class=\"s-hub-icon\"></iconify-icon>\n        </div>\n      </div>\n\n      <!-- 节点容器 (由JS生成或在此静态定义10个) -->\n      <div class=\"s-nodes-container\" data-step=\"0\">\n        <!-- Node 1-10 -->\n        <div class=\"s-node\" style=\"--i:0\"><span class=\"s-node-label\">我</span></div>\n        <div class=\"s-node\" style=\"--i:1\"><span class=\"s-node-label\">爱</span></div>\n        <div class=\"s-node\" style=\"--i:2\"><span class=\"s-node-label\">自然</span></div>\n        <div class=\"s-node\" style=\"--i:3\"><span class=\"s-node-label\">语言</span></div>\n        <div class=\"s-node\" style=\"--i:4\"><span class=\"s-node-label\">处理</span></div>\n        <div class=\"s-node\" style=\"--i:5\"><span class=\"s-node-label\">深度</span></div>\n        <div class=\"s-node\" style=\"--i:6\"><span class=\"s-node-label\">学习</span></div>\n        <div class=\"s-node\" style=\"--i:7\"><span class=\"s-node-label\">计算</span></div>\n        <div class=\"s-node\" style=\"--i:8\"><span class=\"s-node-label\">未来</span></div>\n        <div class=\"s-node\" style=\"--i:9\"><span class=\"s-node-label\">智能</span></div>\n      </div>\n\n      <!-- 连线容器 (SVG) -->\n      <svg class=\"s-attention-mesh\" viewBox=\"0 0 800 800\">\n        <g class=\"s-lines-group\"></g>\n      </svg>\n    </div>\n  </div>\n\n  <!-- 底部标签 -->\n  <div class=\"s-footer-info\">\n    <div class=\"s-mono-tag\">MECHANISM: SELF-ATTENTION</div>\n    <div class=\"s-deco-line\"></div>\n  </div>\n</div>","css":".s-scene-05-root {\n  width: 100%; height: 100%; background-color: #EDE5CE;\n  position: relative; overflow: hidden; font-family: var(--sv-font-body-cn);\n  display: flex; align-items: center; justify-content: center;\n  transition: background-color 1.5s ease;\n}\n.step-ge-2.s-scene-05-root { background-color: #F0E6FF; }\n\n/* 背景装饰 */\n.s-bg-glow {\n  position: absolute; width: 800px; height: 800px; background: radial-gradient(circle, rgba(45,107,106,0.05) 0%, transparent 70%);\n  top: 50%; left: 50%; transform: translate(-50%, -50%);\n}\n.s-bg-grid {\n  position: absolute; inset: 0; background-image: radial-gradient(#1A1210 1px, transparent 1px);\n  background-size: 50px 50px; opacity: 0.05;\n}\n.s-ghost-text {\n  position: absolute; bottom: 5%; right: 5%; font-family: var(--sv-font-display-cn); font-size: 120px; color: rgba(26,18,16,0.03); pointer-events: none;\n}\n\n/* 核心容器 */\n.s-main-container {\n  width: 90%; height: 90%; position: relative; z-index: 10;\n  display: flex; flex-direction: column; align-items: center; justify-content: center;\n}\n\n.s-header-group {\n  position: absolute; top: 40px; left: 40px; z-index: 20;\n}\n.s-hero-title {\n  font-family: var(--sv-font-display-cn); font-size: 52px; color: #1A1210; margin-top: 12px;\n}\n.s-badge { background: #2D6B6A; color: #FFF; padding: 4px 16px; border-radius: 30px; display: inline-block; font-size: 14px; border: 2px solid #1A1210; }\n\n/* Transformer 核心可视化 */\n.s-transformer-core {\n  position: relative; width: 600px; height: 600px;\n  display: flex; align-items: center; justify-content: center;\n}\n\n/* 中心圆环 */\n.s-center-hub {\n  position: relative; width: 120px; height: 120px; z-index: 15;\n}\n.s-hub-ring {\n  position: absolute; inset: -10px; border: 4px dashed #F5C418; border-radius: 50%;\n  animation: s-rotate 20s linear infinite;\n}\n.s-hub-core {\n  width: 100%; height: 100%; background: #FFF; border: 3px solid #1A1210; border-radius: 50%;\n  display: flex; align-items: center; justify-content: center; box-shadow: 0 8px 24px rgba(0,0,0,0.1);\n}\n.s-hub-icon { font-size: 50px; color: #2D6B6A; }\n@keyframes s-rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }\n\n/* 节点 */\n.s-nodes-container {\n  position: absolute; inset: 0; pointer-events: none;\n}\n.s-node {\n  position: absolute; width: 70px; height: 45px; background: #FFF; border: 2.5px solid #1A1210; \n  border-radius: 12px; display: flex; align-items: center; justify-content: center;\n  left: 50%; top: 50%; \n  --radius: 240px;\n  transform: translate(-50%, -50%) rotate(calc(var(--i) * 36deg)) translateY(var(--radius)) rotate(calc(var(--i) * -36deg)) scale(0);\n  transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);\n  transition-delay: calc(var(--i) * 0.05s);\n  box-shadow: 4px 4px 0 rgba(26,18,16,0.1);\n}\n.step-ge-0 .s-node { transform: translate(-50%, -50%) rotate(calc(var(--i) * 36deg)) translateY(var(--radius)) rotate(calc(var(--i) * -36deg)) scale(1); }\n.s-node-label { font-family: var(--sv-font-display-cn); font-size: 18px; color: #1A1210; }\n\n/* 连线网格 */\n.s-attention-mesh {\n  position: absolute; width: 100%; height: 100%; top: 0; left: 0; pointer-events: none; z-index: 5;\n}\n.s-attention-line {\n  stroke: #2D6B6A; stroke-linecap: round; opacity: 0; \n  stroke-dasharray: 1000; stroke-dashoffset: 1000;\n  transition: opacity 0.3s ease, stroke-width 0.5s ease;\n}\n.step-ge-1 .s-attention-line {\n  animation: s-line-draw 1.2s forwards cubic-bezier(0.4, 0, 0.2, 1);\n  opacity: 0.2;\n}\n.step-ge-2 .s-attention-line {\n  opacity: 0.6; stroke: #E05A3A;\n}\n\n@keyframes s-line-draw {\n  to { stroke-dashoffset: 0; }\n}\n\n/* 页脚 */\n.s-footer-info { position: absolute; bottom: 40px; right: 60px; display: flex; align-items: center; gap: 20px; }\n.s-mono-tag { font-family: var(--sv-font-mono); font-size: 14px; color: rgba(26,18,16,0.6); }\n.s-deco-line { width: 60px; height: 2px; background: #F5C418; }","js":"window.SceneLifecycle.register('scene-05', {\n  enter() {\n    const root = document.querySelector('[data-scene-root-id=\"scene-05\"]');\n    if (!root) return;\n\n    const svgGroup = root.querySelector('.s-lines-group');\n    const nodeCount = 10;\n    const centerX = 400;\n    const centerY = 400;\n    const radius = 240;\n\n    // 生成全连接路径\n    if (svgGroup && svgGroup.children.length === 0) {\n      const coords = [];\n      for (let i = 0; i < nodeCount; i++) {\n        const angle = (i * 36 * Math.PI) / 180;\n        coords.push({\n          x: centerX + radius * Math.sin(angle),\n          y: centerY - radius * Math.cos(angle)\n        });\n      }\n\n      // 所有的两两连接\n      for (let i = 0; i < nodeCount; i++) {\n        for (let j = i + 1; j < nodeCount; j++) {\n          const line = document.createElementNS(\"http://www.w3.org/2000/svg\", \"line\");\n          line.setAttribute(\"x1\", coords[i].x);\n          line.setAttribute(\"y1\", coords[i].y);\n          line.setAttribute(\"x2\", coords[j].x);\n          line.setAttribute(\"y2\", coords[j].y);\n          line.setAttribute(\"class\", \"s-attention-line\");\n          // 初始随机权重\n          line.setAttribute(\"stroke-width\", Math.random() * 2 + 0.5);\n          svgGroup.appendChild(line);\n        }\n      }\n    }\n\n    if (window.__SVGVIDEO_REFRESH_ICONS) {\n      window.__SVGVIDEO_REFRESH_ICONS(root);\n    }\n  },\n\n  step(index) {\n    const root = document.querySelector('[data-scene-root-id=\"scene-05\"]');\n    if (!root) return;\n\n    if (index === 2) {\n      // 模拟权重爆发：随机改变线条粗细\n      const lines = root.querySelectorAll('.s-attention-line');\n      lines.forEach(line => {\n        const weight = Math.random() > 0.7 ? (Math.random() * 6 + 2) : (Math.random() * 1.5 + 0.2);\n        line.style.strokeWidth = `${weight}px`;\n        if (weight > 4) {\n          line.style.stroke = \"#F5C418\";\n          line.style.opacity = \"0.9\";\n        }\n      });\n\n      // 中心发光爆发\n      const hub = root.querySelector('.s-hub-core');\n      hub.animate([\n        { boxShadow: '0 0 0px #F5C418' },\n        { boxShadow: '0 0 60px #F5C418' },\n        { boxShadow: '0 0 20px #F5C418' }\n      ], { duration: 1000, iterations: 1 });\n    }\n  }\n});"},{"id":"scene-06","title":"全局俯瞰视角","steps":2,"html":"<div class=\"s-scene-06-root\" data-scene-root-id=\"scene-06\">\n  <!-- 背景氛围层 -->\n  <div class=\"s-bg-ambient\">\n    <div class=\"s-bg-nebula\"></div>\n    <div class=\"s-bg-grid-moving\"></div>\n    <div class=\"s-ghost-title\">PARALLEL COMPUTING</div>\n  </div>\n\n  <div class=\"s-main-stage\">\n    <!-- 文字标签层 -->\n    <div class=\"s-side-text s-left\" data-step=\"1\">并行计算</div>\n    <div class=\"s-side-text s-right\" data-step=\"1\">全局关联</div>\n\n    <!-- 核心视觉容器：用于镜头拉远和旋转 -->\n    <div class=\"s-camera-rig\">\n      <div class=\"s-nebula-vortex\">\n        <!-- 眼睛图标 -->\n        <div class=\"s-eye-container\">\n          <div class=\"s-eye-outer\">\n            <div class=\"s-eye-iris\">\n              <div class=\"s-matrix-core\">\n                <!-- 矩阵代码流由JS生成 -->\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <!-- 编码器集群 (Step 1 显示) -->\n        <div class=\"s-encoder-grid\" data-step=\"0\">\n          <!-- 12个编码器模块 -->\n          <div class=\"s-encoder-block\" style=\"--idx:0\"><span>Enc_01</span></div>\n          <div class=\"s-encoder-block\" style=\"--idx:1\"><span>Enc_02</span></div>\n          <div class=\"s-encoder-block\" style=\"--idx:2\"><span>Enc_03</span></div>\n          <div class=\"s-encoder-block\" style=\"--idx:3\"><span>Enc_04</span></div>\n          <div class=\"s-encoder-block\" style=\"--idx:4\"><span>Enc_05</span></div>\n          <div class=\"s-encoder-block\" style=\"--idx:5\"><span>Enc_06</span></div>\n          <div class=\"s-encoder-block\" style=\"--idx:6\"><span>Enc_07</span></div>\n          <div class=\"s-encoder-block\" style=\"--idx:7\"><span>Enc_08</span></div>\n          <div class=\"s-encoder-block\" style=\"--idx:8\"><span>Enc_09</span></div>\n          <div class=\"s-encoder-block\" style=\"--idx:9\"><span>Enc_10</span></div>\n          <div class=\"s-encoder-block\" style=\"--idx:10\"><span>Enc_11</span></div>\n          <div class=\"s-encoder-block\" style=\"--idx:11\"><span>Enc_12</span></div>\n        </div>\n      </div>\n    </div>\n  </div>\n\n  <!-- 底部装饰 -->\n  <div class=\"s-footer-tag\">\n    <div class=\"s-badge-mini\">ARCHITECTURE</div>\n    <div class=\"s-tag-line\">TRANSFORMER PARALLELISM</div>\n  </div>\n</div>","css":".s-scene-06-root {\n  width: 100%; height: 100%; background-color: #EDE5CE;\n  position: relative; overflow: hidden; font-family: var(--sv-font-body-cn);\n  display: flex; align-items: center; justify-content: center;\n}\n\n/* 背景氛围 */\n.s-bg-nebula {\n  position: absolute; width: 120%; height: 120%;\n  background: radial-gradient(circle, rgba(245, 196, 24, 0.08) 0%, transparent 60%);\n  filter: blur(60px); animation: s-nebula-pulse 10s ease-in-out infinite alternate;\n}\n.s-bg-grid-moving {\n  position: absolute; inset: -50%; background-image: radial-gradient(#2D6B6A 1px, transparent 1px);\n  background-size: 60px 60px; opacity: 0.05; transform: rotate(15deg); animation: s-grid-flow 30s linear infinite;\n}\n.s-ghost-title {\n  position: absolute; top: 10%; left: 5%; font-family: var(--sv-font-display-cn); \n  font-size: 80px; color: #1A1210; opacity: 0.03; pointer-events: none;\n}\n\n/* 镜头系统 */\n.s-main-stage {\n  width: 100%; height: 100%; position: relative;\n  display: flex; align-items: center; justify-content: center;\n  perspective: 1000px;\n}\n.s-camera-rig {\n  transition: transform 1.5s cubic-bezier(0.22, 1, 0.36, 1);\n  transform: scale(3); /* 初始聚焦于眼睛 */\n}\n.step-ge-1 .s-camera-rig { transform: scale(0.65) rotate(-5deg); }\n.step-ge-2 .s-camera-rig { transform: scale(0.5) rotate(15deg); }\n\n/* 眼睛图标 */\n.s-eye-container {\n  position: relative; z-index: 10; width: 300px; height: 180px;\n  display: flex; align-items: center; justify-content: center;\n}\n.s-eye-outer {\n  width: 100%; height: 100%; background: #FFF; border: 4px solid #1A1210; \n  border-radius: 100% 0%; transform: rotate(45deg); overflow: hidden;\n  box-shadow: 0 15px 45px rgba(0,0,0,0.1);\n}\n.s-eye-iris {\n  position: absolute; width: 120px; height: 120px; background: #2D6B6A;\n  border-radius: 50%; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(-45deg);\n  border: 3px solid #1A1210; display: flex; align-items: center; justify-content: center;\n  overflow: hidden;\n}\n.s-matrix-core {\n  color: #F5C418; font-family: var(--sv-font-mono); font-size: 8px; line-height: 1; word-break: break-all; opacity: 0.8;\n}\n\n/* 编码器网格 */\n.s-encoder-grid {\n  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);\n  display: grid; grid-template-columns: repeat(6, 120px); gap: 240px 160px;\n  opacity: 0; transition: opacity 0.8s ease, transform 1.2s cubic-bezier(0.34, 1.56, 0.64, 1);\n  pointer-events: none;\n}\n.step-ge-1 .s-encoder-grid { opacity: 1; }\n.s-encoder-block {\n  width: 100px; height: 60px; background: #FFF; border: 2.5px solid #1A1210; border-radius: 8px;\n  display: flex; align-items: center; justify-content: center; font-family: var(--sv-font-mono);\n  font-size: 14px; color: #1A1210; box-shadow: 6px 6px 0 rgba(45,107,106,0.2);\n}\n\n/* 文字动画 */\n.s-side-text {\n  position: absolute; font-family: var(--sv-font-display-cn); font-size: 56px; color: #1A1210;\n  opacity: 0; transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1);\n  z-index: 100; border-bottom: 6px solid #F5C418;\n}\n.s-left { left: 10%; transform: translateX(-50px); }\n.s-right { right: 10%; transform: translateX(50px); }\n.step-ge-1 .s-side-text { opacity: 1; transform: translateX(0); }\n\n/* 旋转缩放动效 */\n.s-nebula-vortex {\n  position: relative; width: 800px; height: 800px;\n  display: flex; align-items: center; justify-content: center;\n  transition: transform 15s linear;\n}\n.step-ge-2 .s-nebula-vortex { animation: s-slow-spin 20s linear infinite; }\n\n/* 装饰小标 */\n.s-footer-tag { position: absolute; bottom: 40px; left: 40px; }\n.s-badge-mini { background: #2D6B6A; color: #FFF; padding: 2px 10px; font-size: 12px; border-radius: 4px; display: inline-block; margin-bottom: 5px; border: 1.5px solid #1A1210; }\n.s-tag-line { font-family: var(--sv-font-mono); font-size: 14px; color: rgba(26,18,16,0.6); }\n\n@keyframes s-nebula-pulse { from { transform: scale(1); opacity: 0.5; } to { transform: scale(1.2); opacity: 0.8; } }\n@keyframes s-grid-flow { from { transform: rotate(15deg) translateY(0); } to { transform: rotate(15deg) translateY(60px); } }\n@keyframes s-slow-spin { to { transform: rotate(360deg); } }","js":"window.SceneLifecycle.register('scene-06', {\n  enter() {\n    const root = document.querySelector('[data-scene-root-id=\"scene-06\"]');\n    if (!root) return;\n\n    // 生成矩阵代码流\n    const matrixCore = root.querySelector('.s-matrix-core');\n    if (matrixCore) {\n      let code = '';\n      const chars = '01ABCDEFGHIJKLMNOPQRSTUVWXYZ';\n      for (let i = 0; i < 400; i++) {\n        code += chars.charAt(Math.floor(Math.random() * chars.length));\n      }\n      matrixCore.innerText = code;\n      \n      // 简单的打字机闪烁效果\n      setInterval(() => {\n        let newCode = '';\n        for (let i = 0; i < 10; i++) {\n           const idx = Math.floor(Math.random() * 400);\n           matrixCore.innerText = matrixCore.innerText.substring(0, idx) + chars.charAt(Math.floor(Math.random() * chars.length)) + matrixCore.innerText.substring(idx + 1);\n        }\n      }, 100);\n    }\n\n    // 编码器随机漂移感\n    const encoders = root.querySelectorAll('.s-encoder-block');\n    encoders.forEach((el, i) => {\n      el.animate([\n        { transform: 'translate(0, 0)' },\n        { transform: `translate(${Math.sin(i) * 10}px, ${Math.cos(i) * 10}px)` },\n        { transform: 'translate(0, 0)' }\n      ], {\n        duration: 3000 + Math.random() * 2000,\n        iterations: Infinity,\n        easing: 'ease-in-out'\n      });\n    });\n  },\n\n  step(index) {\n    const root = document.querySelector('[data-scene-root-id=\"scene-06\"]');\n    if (!root) return;\n\n    if (index === 1) {\n      // 当文字出现时，给背景一个冲击波感\n      const nebula = root.querySelector('.s-bg-nebula');\n      nebula.animate([\n        { filter: 'blur(60px) brightness(1)' },\n        { filter: 'blur(30px) brightness(1.5)' },\n        { filter: 'blur(60px) brightness(1)' }\n      ], { duration: 800 });\n    }\n  }\n});"},{"id":"scene-07","title":"智慧的跨越总结","steps":3,"html":"<div class=\"s-scene-07-root\" data-scene-root-id=\"scene-07\">\n  <!-- 背景氛围层 -->\n  <div class=\"s-ambient-layer\">\n    <div class=\"s-ambient-grid\"></div>\n    <div class=\"s-ghost-text\">EVOLUTION</div>\n    <div class=\"s-ambient-blobs\">\n      <div class=\"s-blob s-blob-1\"></div>\n      <div class=\"s-blob s-blob-2\"></div>\n    </div>\n  </div>\n\n  <!-- 主舞台：算法阶梯 -->\n  <div class=\"s-stage-ladder\">\n    <!-- Step 0: 三大算法图表 -->\n    <div class=\"s-ladder-item s-item-svm\" data-step=\"0\">\n      <div class=\"s-visual-box\">\n        <svg viewBox=\"0 0 120 120\" class=\"s-svg-icon\">\n          <circle cx=\"30\" cy=\"40\" r=\"5\" fill=\"#E05A3A\" stroke=\"#1A1210\" stroke-width=\"2\" />\n          <circle cx=\"45\" cy=\"25\" r=\"5\" fill=\"#E05A3A\" stroke=\"#1A1210\" stroke-width=\"2\" />\n          <circle cx=\"80\" cy=\"85\" r=\"5\" fill=\"#2D6B6A\" stroke=\"#1A1210\" stroke-width=\"2\" />\n          <circle cx=\"95\" cy=\"70\" r=\"5\" fill=\"#2D6B6A\" stroke=\"#1A1210\" stroke-width=\"2\" />\n          <line x1=\"10\" y1=\"110\" x2=\"110\" y2=\"10\" stroke=\"#1A1210\" stroke-width=\"3\" stroke-dasharray=\"4\" />\n        </svg>\n      </div>\n      <div class=\"s-label-badge\">SVM</div>\n    </div>\n\n    <div class=\"s-ladder-item s-item-lstm\" data-step=\"0\">\n      <div class=\"s-visual-box\">\n        <svg viewBox=\"0 0 120 120\" class=\"s-svg-icon\">\n          <rect x=\"20\" y=\"40\" width=\"80\" height=\"40\" rx=\"8\" fill=\"#FFFFFF\" stroke=\"#1A1210\" stroke-width=\"2.5\" />\n          <circle cx=\"40\" cy=\"60\" r=\"8\" fill=\"#F5C418\" stroke=\"#1A1210\" stroke-width=\"2\" />\n          <circle cx=\"60\" cy=\"60\" r=\"8\" fill=\"#F5C418\" stroke=\"#1A1210\" stroke-width=\"2\" />\n          <circle cx=\"80\" cy=\"60\" r=\"8\" fill=\"#F5C418\" stroke=\"#1A1210\" stroke-width=\"2\" />\n          <path d=\"M10,60 L20,60 M100,60 L110,60\" stroke=\"#1A1210\" stroke-width=\"2\" />\n        </svg>\n      </div>\n      <div class=\"s-label-badge\">LSTM</div>\n    </div>\n\n    <div class=\"s-ladder-item s-item-transformer\" data-step=\"0\">\n      <div class=\"s-visual-box\">\n        <div class=\"s-attention-grid\">\n          <div class=\"s-grid-dot\"></div><div class=\"s-grid-dot\"></div><div class=\"s-grid-dot\"></div>\n          <div class=\"s-grid-dot active\"></div><div class=\"s-grid-dot\"></div><div class=\"s-grid-dot\"></div>\n          <div class=\"s-grid-dot\"></div><div class=\"s-grid-dot active\"></div><div class=\"s-grid-dot\"></div>\n        </div>\n      </div>\n      <div class=\"s-label-badge\">TRANSFORMER</div>\n    </div>\n\n    <!-- Step 1: 阶梯连接线 -->\n    <svg class=\"s-ladder-connector\" viewBox=\"0 0 800 400\">\n        <path class=\"s-ladder-path\" d=\"M150,300 L350,200 L550,100\" fill=\"none\" stroke=\"#1A1210\" stroke-width=\"2\" stroke-dasharray=\"8 8\" />\n    </svg>\n\n    <!-- Step 2: 数字大脑 -->\n    <div class=\"s-brain-container\" data-step=\"1\">\n       <div class=\"s-brain-core\">\n          <div class=\"s-brain-halves\">\n             <iconify-icon icon=\"ph:brain-duotone\" class=\"s-brain-icon\"></iconify-icon>\n          </div>\n          <div class=\"s-data-orbits\">\n             <div class=\"s-orbit\"></div>\n             <div class=\"s-orbit\"></div>\n          </div>\n       </div>\n       <div class=\"s-brain-glow\"></div>\n    </div>\n  </div>\n\n  <!-- Step 3: 总结结语 -->\n  <div class=\"s-final-curtain\" data-step=\"2\">\n    <div class=\"s-conclusion-text\">从理解 到 创造</div>\n  </div>\n</div>","css":".s-scene-07-root {\n  width: 100%; height: 100%; background-color: #EDE5CE; position: relative; overflow: hidden;\n  font-family: var(--sv-font-body-cn); display: flex; align-items: center; justify-content: center;\n}\n\n/* 背景氛围 */\n.s-ambient-layer { position: absolute; inset: 0; pointer-events: none; }\n.s-ambient-grid {\n  position: absolute; inset: 0; \n  background-image: radial-gradient(rgba(45, 107, 106, 0.1) 1px, transparent 1px);\n  background-size: 40px 40px; opacity: 0.5;\n}\n.s-ghost-text {\n  position: absolute; bottom: 5%; right: 5%; font-family: var(--sv-font-display-cn);\n  font-size: 120px; color: #1A1210; opacity: 0.04; font-style: italic;\n}\n.s-blob {\n  position: absolute; border-radius: 50%; filter: blur(60px); opacity: 0.2;\n  animation: s-blob-float 15s infinite alternate ease-in-out;\n}\n.s-blob-1 { width: 400px; height: 400px; background: #F5C418; top: -100px; left: -100px; }\n.s-blob-2 { width: 350px; height: 350px; background: #2D6B6A; bottom: -50px; right: -50px; animation-delay: -7s; }\n\n/* 阶梯舞台 */\n.s-stage-ladder { position: relative; width: 800px; height: 450px; display: flex; align-items: center; justify-content: center; }\n\n.s-ladder-item {\n  position: absolute; display: flex; flex-direction: column; align-items: center;\n  transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);\n  opacity: 0; transform: translateY(30px);\n}\n.s-scene-07-root.step-ge-0 .s-ladder-item { opacity: 1; transform: translateY(0); }\n.s-item-svm { left: 50px; bottom: 50px; transition-delay: 0.1s; }\n.s-item-lstm { left: 320px; bottom: 150px; transition-delay: 0.3s; }\n.s-item-transformer { left: 590px; bottom: 250px; transition-delay: 0.5s; }\n\n/* 阶梯进化后的形态 (Step 1) */\n.step-ge-1 .s-item-svm { transform: scale(0.6) translate(100px, -50px); opacity: 0.4; }\n.step-ge-1 .s-item-lstm { transform: scale(0.6) translate(0px, -50px); opacity: 0.4; }\n.step-ge-1 .s-item-transformer { transform: scale(0.6) translate(-100px, -50px); opacity: 0.4; }\n\n.s-visual-box {\n  width: 140px; height: 140px; background: #FFFFFF; border: 3px solid #1A1210; \n  border-radius: 16px; box-shadow: 0 8px 0 rgba(26,18,16,0.1); \n  display: flex; align-items: center; justify-content: center; margin-bottom: 12px;\n}\n.s-label-badge {\n  background: #2D6B6A; color: #FFF; padding: 4px 12px; border-radius: 20px;\n  font-family: var(--sv-font-mono); font-size: 14px; border: 2px solid #1A1210;\n}\n\n/* 特殊图形：注意力网格 */\n.s-attention-grid {\n  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;\n}\n.s-grid-dot {\n  width: 12px; height: 12px; background: #EDE5CE; border: 1.5px solid #1A1210; border-radius: 3px;\n}\n.s-grid-dot.active { background: #F5C418; transform: scale(1.2); }\n\n/* 阶梯连接器 */\n.s-ladder-connector {\n  position: absolute; inset: 0; z-index: -1; opacity: 0; transition: opacity 1s;\n}\n.step-ge-1 .s-ladder-connector { opacity: 0.3; }\n.s-ladder-path { stroke-dasharray: 500; stroke-dashoffset: 500; transition: stroke-dashoffset 1.5s ease-in-out; }\n.step-ge-1 .s-ladder-path { stroke-dashoffset: 0; }\n\n/* 数字大脑 (Step 2) */\n.s-brain-container {\n  position: absolute; top: 20%; left: 50%; transform: translate(-50%, -100%) scale(0.5);\n  opacity: 0; transition: all 1s cubic-bezier(0.22, 1, 0.36, 1);\n}\n.step-ge-1 .s-brain-container { opacity: 1; transform: translate(-50%, -40%) scale(1.2); }\n.s-brain-core { position: relative; z-index: 2; }\n.s-brain-icon { font-size: 160px; color: #1A1210; filter: drop-shadow(0 0 15px rgba(245, 196, 24, 0.4)); }\n.s-brain-glow {\n  position: absolute; top: 50%; left: 50%; width: 200px; height: 200px;\n  background: radial-gradient(circle, #F5C418 0%, transparent 70%);\n  transform: translate(-50%, -50%); filter: blur(30px); opacity: 0.4;\n  animation: s-brain-pulse 2s infinite alternate;\n}\n.s-orbit {\n  position: absolute; border: 1.5px solid #2D6B6A; border-radius: 50%;\n  top: 50%; left: 50%; transform: translate(-50%, -50%);\n  animation: s-rotate 10s linear infinite;\n}\n.s-orbit:nth-child(1) { width: 220px; height: 100px; transform: translate(-50%, -50%) rotate(45deg); }\n.s-orbit:nth-child(2) { width: 220px; height: 100px; transform: translate(-50%, -50%) rotate(-45deg); animation-duration: 15s; }\n\n/* 结语全屏淡出 (Step 3) */\n.s-final-curtain {\n  position: absolute; inset: 0; background: #1A1210; z-index: 100;\n  display: flex; align-items: center; justify-content: center;\n  opacity: 0; pointer-events: none; transition: opacity 1.5s ease-in-out;\n}\n.step-ge-2 .s-final-curtain { opacity: 1; pointer-events: auto; }\n.s-conclusion-text {\n  font-family: var(--sv-font-display-cn); font-size: 72px; color: #F5C418;\n  text-shadow: 0 0 30px rgba(245, 196, 24, 0.5); transform: scale(0.9);\n  transition: transform 2s cubic-bezier(0.16, 1, 0.3, 1);\n}\n.step-ge-2 .s-conclusion-text { transform: scale(1); }\n\n/* 动画关键帧 */\n@keyframes s-blob-float { from { transform: translate(0, 0); } to { transform: translate(40px, 60px); } }\n@keyframes s-brain-pulse { from { opacity: 0.3; transform: translate(-50%, -50%) scale(0.9); } to { opacity: 0.6; transform: translate(-50%, -50%) scale(1.1); } }\n@keyframes s-rotate { from { transform: translate(-50%, -50%) rotate(0); } to { transform: translate(-50%, -50%) rotate(360deg); } }","js":"window.SceneLifecycle.register('scene-07', {\n  enter() {\n    const root = document.querySelector('[data-scene-root-id=\"scene-07\"]');\n    if (!root) return;\n\n    // 随机点亮注意力网格中的点\n    const dots = root.querySelectorAll('.s-grid-dot');\n    const flickerInterval = setInterval(() => {\n      dots.forEach(dot => {\n        if (Math.random() > 0.8) {\n          dot.classList.add('active');\n          setTimeout(() => dot.classList.remove('active'), 500);\n        }\n      });\n    }, 1000);\n\n    // 存储定时器以便清理\n    root._flicker = flickerInterval;\n  },\n\n  step(index) {\n    const root = document.querySelector('[data-scene-root-id=\"scene-07\"]');\n    if (!root) return;\n\n    if (index === 1) {\n      // Step 2: 数字大脑出现时的微光交互\n      const glow = root.querySelector('.s-brain-glow');\n      if (glow) {\n         glow.animate([\n           { filter: 'blur(30px) brightness(1)', opacity: 0.4 },\n           { filter: 'blur(10px) brightness(2)', opacity: 0.8 },\n           { filter: 'blur(30px) brightness(1)', opacity: 0.4 }\n         ], { duration: 1000, easing: 'ease-out' });\n      }\n    }\n\n    if (index === 2) {\n      // Step 3: 全屏变黑，文字发光逻辑在CSS处理\n    }\n  },\n\n  leave() {\n    const root = document.querySelector('[data-scene-root-id=\"scene-07\"]');\n    if (root && root._flicker) clearInterval(root._flicker);\n  }\n});"}]</script>
  <script defer src="https://unpkg.com/lucide@latest"></script>
  <script defer src="https://code.iconify.design/iconify-icon/2.3.0/iconify-icon.min.js"></script>
  <script defer src="https://unpkg.com/@lottiefiles/lottie-player@2.0.12/dist/lottie-player.js"></script>
  <script>
    (function () {
      var state = { sceneId: 'scene-03', step: 0, direction: 1 };
      var TRANSITION_PRESETS={'door':{'--sv-stage-perspective':'900px','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'rotateY(90deg)','--sv-trans-enter-filter':'blur(6px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'rotateY(0deg)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'rotateY(-90deg)','--sv-trans-exit-filter':'blur(4px)','--sv-trans-duration':'0.65s','--sv-trans-ease':'cubic-bezier(0.36, 0, 0.66, 1)'},'burst':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'scale(0.1)','--sv-trans-enter-filter':'blur(40px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'scale(1.6)','--sv-trans-exit-filter':'blur(24px)','--sv-trans-duration':'0.55s','--sv-trans-ease':'cubic-bezier(0.34, 1.3, 0.64, 1)'},'slam':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'translateX(var(--scene-enter-offset, 180px)) rotate(8deg)','--sv-trans-enter-filter':'blur(24px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'translateX(0) rotate(0deg)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'translateX(var(--scene-exit-offset, -120px)) rotate(-5deg)','--sv-trans-exit-filter':'blur(18px)','--sv-trans-duration':'0.50s','--sv-trans-ease':'cubic-bezier(0.2, 0.8, 0.2, 1)'},'push-up':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'1','--sv-trans-enter-transform':'translateY(105%)','--sv-trans-enter-filter':'blur(0px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'translateY(0)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0.3','--sv-trans-exit-transform':'translateY(-60px)','--sv-trans-exit-filter':'blur(8px)','--sv-trans-duration':'0.55s','--sv-trans-ease':'cubic-bezier(0.22, 1, 0.36, 1)'},'spin':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'rotate(180deg) scale(0.2)','--sv-trans-enter-filter':'blur(24px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'rotate(0deg) scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'rotate(-90deg) scale(0.4)','--sv-trans-exit-filter':'blur(16px)','--sv-trans-duration':'0.55s','--sv-trans-ease':'cubic-bezier(0.34, 1.3, 0.64, 1)'},'tunnel':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'scale(1.28)','--sv-trans-enter-filter':'blur(12px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'scale(0.88)','--sv-trans-exit-filter':'blur(10px)','--sv-trans-duration':'0.60s','--sv-trans-ease':'cubic-bezier(0.22, 1, 0.36, 1)'},'glitch':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'scale(0.95)','--sv-trans-enter-filter':'blur(2px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'scale(0.95)','--sv-trans-exit-filter':'none','--sv-trans-duration':'0.25s','--sv-trans-ease':'ease-out'},};
      // Per-scene transition mapping — built from meta at init time
      var sceneTransitionMap = {};
      var previousSceneId = null;
      var exitCleanupTimer = null;
      var isPlaying = false;
      var playTimer = null;
      var progressRaf = null;
      var STEP_INTERVAL_MS = 1400;
      var SCENE_FINISH_PAUSE_MS = 2000;
      var autoplayFromFirstScene = false;
      var progressWrap = document.getElementById('sv-progress-wrap');
      var progressFill = document.getElementById('sv-progress-fill');
      var progressThumb = document.getElementById('sv-progress-thumb');
      var playBtn = document.getElementById('sv-play-btn');
      var expandBtn = document.getElementById('sv-expand-btn');
      var statusText = document.getElementById('sv-status-text');
      var sceneButtonList = Array.prototype.slice.call(document.querySelectorAll('[data-panel-scene-id]'));
      var sceneRetryButtonList = Array.prototype.slice.call(document.querySelectorAll('[data-retry-scene-id]'));
      var editorOverlay = document.getElementById('sv-editor-overlay');
      var editorBackdrop = document.getElementById('sv-editor-backdrop');
      var editorSheet = document.getElementById('sv-editor-sheet');
      var editorResizeHandle = document.getElementById('sv-editor-resize-handle');
      var editorCloseBtn = document.getElementById('sv-editor-close-btn');
      var editorSaveBtn = document.getElementById('sv-editor-save-btn');
      var editorList = document.getElementById('sv-editor-list');
      var editorSaveTip = document.getElementById('sv-editor-save-tip');
      var editorTipTimer = null;
      var isEditorOpen = false;
      var isEditorDirty = false;
      var editorHeightVh = 50;
      var hostCaps = { canRetry: false, canEditPanel: false, locale: 'zh', theme: 'dark' };
      var metaJson = document.getElementById('__SVGVIDEO_META__');
      var meta = { scenes: [] };
      try {
        meta = JSON.parse((metaJson && metaJson.textContent) || '{}');
      } catch (e) {
        meta = { scenes: [] };
      }
      var metaSceneMap = {};
      var metaScenes = Array.isArray(meta.scenes) ? meta.scenes : [];
      metaScenes.forEach(function (scene) {
        if (scene && typeof scene.id === 'string' && scene.id) {
          metaSceneMap[scene.id] = scene;
          sceneTransitionMap[scene.id] = (typeof scene.transition === 'string' && TRANSITION_PRESETS[scene.transition]) ? scene.transition : 'door';
        }
      });
      function refreshFrameworkIcons(root) {
        var refreshRoot = root || document;
        try {
          if (window.lucide && typeof window.lucide.createIcons === 'function') {
            window.lucide.createIcons({ root: refreshRoot });
          }
        } catch (iconErr) {
          console.warn('[svg-video] lucide refresh failed', iconErr);
        }
      }
      window.__SVGVIDEO_REFRESH_ICONS = refreshFrameworkIcons;
      var sceneModels = Array.prototype.slice.call(document.querySelectorAll('#stage > [data-framework-scene-id], #stage > [data-scene-id]')).map(function (node, index) {
        var sceneId = node.getAttribute('data-framework-scene-id') || node.getAttribute('data-scene-id') || ('scene-' + (index + 1));
        var metaScene = metaSceneMap[sceneId] || {};
        var sceneTitle = typeof metaScene.title === 'string' && metaScene.title ? metaScene.title : ('分镜' + (index + 1));
        var sceneSteps = Math.max(1, Number(metaScene.steps) || 1);
        var sceneStatus = typeof metaScene.status === 'string' ? metaScene.status : 'pending';
        var scenePrompt = typeof metaScene.prompt === 'string' ? metaScene.prompt : '';
        var sceneScript = typeof metaScene.scriptText === 'string' ? metaScene.scriptText : '';
        var sceneAudioObjectKey = typeof metaScene.audioObjectKey === 'string' ? metaScene.audioObjectKey : '';
        var sceneAudioDurationMs = Number(metaScene.audioDurationMs) > 0 ? Number(metaScene.audioDurationMs) : 0;
        var sceneVoiceName = typeof metaScene.voiceName === 'string' ? metaScene.voiceName : '';
        var sceneVoiceStyle = typeof metaScene.voiceStyle === 'string' ? metaScene.voiceStyle : '';
        var relatedSceneIds = Array.isArray(metaScene.relatedSceneIds) ? metaScene.relatedSceneIds : [];
        return {
          id: sceneId,
          title: sceneTitle,
          steps: sceneSteps,
          status: sceneStatus,
          prompt: scenePrompt,
          scriptText: sceneScript,
          audioObjectKey: sceneAudioObjectKey,
          audioDurationMs: sceneAudioDurationMs,
          voiceName: sceneVoiceName,
          voiceStyle: sceneVoiceStyle,
          relatedSceneIds: relatedSceneIds,
          transition: sceneTransitionMap[sceneId] || 'door'
        };
      });
      if (!sceneModels.length && metaScenes.length) {
        sceneModels = metaScenes.map(function (scene, index) {
          return {
            id: scene.id || ('scene-' + (index + 1)),
            title: scene.title || ('分镜' + (index + 1)),
            steps: Math.max(1, Number(scene.steps) || 1),
            status: typeof scene.status === 'string' ? scene.status : 'pending',
            prompt: typeof scene.prompt === 'string' ? scene.prompt : '',
            scriptText: typeof scene.scriptText === 'string' ? scene.scriptText : '',
            audioObjectKey: typeof scene.audioObjectKey === 'string' ? scene.audioObjectKey : '',
            audioDurationMs: Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0,
            voiceName: typeof scene.voiceName === 'string' ? scene.voiceName : '',
            voiceStyle: typeof scene.voiceStyle === 'string' ? scene.voiceStyle : '',
            relatedSceneIds: Array.isArray(scene.relatedSceneIds) ? scene.relatedSceneIds : [],
            transition: sceneTransitionMap[scene.id] || 'door'
          };
        });
      }
      function i18nText(zh, en) {
        return hostCaps.locale === 'en' ? en : zh;
      }
      function applyI18nTexts() {
        var toolbarTitleEl = document.getElementById('sv-toolbar-title');
        var titleEl = document.getElementById('sv-editor-header-title');
        if (toolbarTitleEl) toolbarTitleEl.textContent = i18nText('分镜面板', 'Storyboard');
        if (titleEl) titleEl.textContent = i18nText('分镜详情编辑', 'Storyboard details');
        if (expandBtn) {
          var expandText = i18nText('展开分镜详情', 'Open storyboard details');
          expandBtn.setAttribute('aria-label', expandText);
          expandBtn.setAttribute('title', expandText);
        }
        if (editorSaveBtn) editorSaveBtn.textContent = isEditorDirty ? i18nText('保存*', 'Save*') : i18nText('保存', 'Save');
        if (editorCloseBtn) editorCloseBtn.textContent = i18nText('关闭', 'Close');
        if (editorSaveTip) editorSaveTip.textContent = i18nText('已保存', 'Saved');
      }
      function clampEditorHeightVh(value) {
        return Math.max(32, Math.min(80, Number(value) || 50));
      }
      function applyEditorHeight(vh) {
        editorHeightVh = clampEditorHeightVh(vh);
        document.documentElement.style.setProperty('--sv-editor-height', editorHeightVh + 'vh');
      }
      function persistMetaToScript() {
        meta.title = typeof meta.title === 'string' ? meta.title : '';
        meta.version = meta.version || 1;
        meta.scenes = sceneModels.map(function (scene) {
          return {
            id: scene.id,
            title: scene.title || '',
            steps: Math.max(1, Number(scene.steps) || 1),
            status: scene.status || 'pending',
            prompt: scene.prompt || '',
            scriptText: scene.scriptText || '',
            audioObjectKey: scene.audioObjectKey || '',
            audioDurationMs: Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0,
            voiceName: scene.voiceName || '',
            voiceStyle: scene.voiceStyle || '',
            relatedSceneIds: Array.isArray(scene.relatedSceneIds) ? scene.relatedSceneIds : [],
            transition: scene.transition || 'door'
          };
        });
        if (metaJson) metaJson.textContent = JSON.stringify(meta);
      }
      function showSavedTip() {
        if (!editorSaveTip) return;
        if (editorTipTimer) {
          clearTimeout(editorTipTimer);
          editorTipTimer = null;
        }
        editorSaveTip.classList.add('is-visible');
        editorTipTimer = setTimeout(function () {
          editorSaveTip.classList.remove('is-visible');
        }, 1200);
      }
      function markEditorDirty() {
        isEditorDirty = true;
        applyI18nTexts();
      }
      function clearEditorDirty() {
        isEditorDirty = false;
        applyI18nTexts();
      }
      function getStatusLabel(status) {
        if (status === 'success') return i18nText('已生成', 'Done');
        if (status === 'generating') return i18nText('生成中', 'Generating');
        if (status === 'failed') return i18nText('失败', 'Failed');
        return i18nText('未生成', 'Pending');
      }
      function getStatusClass(status) {
        if (status === 'generating') return 'is-generating';
        if (status === 'success') return 'is-success';
        return 'is-failed';
      }
      function getRetryButtonInnerHtml(isGenerating) {
        if (isGenerating) return '<span class="scene-chip-retry-spinner"></span>';
        return '<svg class="scene-chip-retry-icon" viewBox="0 0 1024 1024" width="16" height="16" fill="currentColor"><path d="M698.569 531.322a39.825 39.825 0 0 0-23.898 7.949c-17.702 13.216-21.34 38.28-8.124 55.982l95.716 128.212c7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949c17.702-13.216 21.34-38.28 8.124-55.982l-95.716-128.212c-7.853-10.521-19.892-16.074-32.084-16.073z" /><path d="M922.498 563.818a39.825 39.825 0 0 0-23.898 7.949l-128.212 95.716c-17.703 13.216-21.34 38.28-8.124 55.982 7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949l128.212-95.716c17.702-13.216 21.34-38.28 8.124-55.982-7.854-10.521-19.893-16.074-32.084-16.073zM229.652 282.148a39.825 39.825 0 0 0-23.898 7.949c-17.702 13.216-21.34 38.28-8.124 55.982l95.716 128.212c7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949c17.702-13.216 21.34-38.28 8.124-55.982l-95.716-128.212c-7.854-10.521-19.892-16.074-32.084-16.073z" /><path d="M229.652 282.148a39.825 39.825 0 0 0-23.898 7.949L77.542 385.813c-17.702 13.216-21.34 38.28-8.124 55.982 7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949l128.213-95.716c17.702-13.216 21.34-38.28 8.124-55.982-7.855-10.521-19.893-16.073-32.085-16.073z" /><path d="M614.968 763.65c-44.13 18.171-94.005 25.121-146.168 16.968C353.747 762.636 261.364 670.253 243.381 555.2c-9.681-61.936 1.932-120.646 28.337-170.344l-58.657-58.657c-40.139 64.442-60.11 142.746-50.806 226.152 17.993 161.306 148.088 291.401 309.394 309.394 62.041 6.92 121.259-2.357 174.048-24.083 26.535-10.921 33.625-45.203 13.335-65.493l-0.098-0.098c-11.555-11.555-28.854-14.643-43.966-8.421zM409.033 260.35c44.131-18.171 94.007-25.122 146.169-16.968 115.051 17.985 207.431 110.365 225.416 225.416 9.682 61.935-1.931 120.646-28.337 170.346l58.658 58.658c40.139-64.443 60.109-142.747 50.805-226.155-17.993-161.305-148.087-291.399-309.391-309.391-62.042-6.92-121.26 2.356-174.05 24.082-26.535 10.921-33.625 45.203-13.335 65.493l0.099 0.099c11.555 11.554 28.854 14.642 43.966 8.42z" /></svg>';
      }
      function setSceneStatus(sceneId, status) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return;
        sceneModels[index].status = status;
        persistMetaToScript();
        var statusClass = getStatusClass(status);
        var chipWrap = document.querySelector('[data-chip-scene-id="' + sceneId + '"]');
        if (chipWrap) {
          chipWrap.classList.remove('is-success', 'is-failed', 'is-generating');
          chipWrap.classList.add(statusClass);
          var chipBtn = chipWrap.querySelector('.scene-chip');
          if (chipBtn) {
            chipBtn.classList.remove('is-success', 'is-failed', 'is-generating');
            chipBtn.classList.add(statusClass);
          }
          var retryBtn = chipWrap.querySelector('.scene-chip-retry');
          if (retryBtn) {
            retryBtn.innerHTML = getRetryButtonInnerHtml(status === 'generating');
            if (status === 'generating') retryBtn.setAttribute('disabled', 'disabled');
            else retryBtn.removeAttribute('disabled');
          }
        }
        renderStatus();
      }
      function requestSceneRetry(sceneId) {
        if (!hostCaps.canRetry) return;
        var idx = getSceneIndexById(sceneId);
        if (idx < 0) return;
        var scene = sceneModels[idx];
        setSceneStatus(sceneId, 'generating');
        focusScene(sceneId);
        if (window.parent && window.parent !== window) {
          window.parent.postMessage(
            { type: '__SVGVIDEO_RETRY_SCENE', sceneId: sceneId, prompt: scene.prompt || '' },
            '*'
          );
        }
      }
      function renderEditorList() {
        if (!editorList) return;
        editorList.innerHTML = '';
        var fragment = document.createDocumentFragment();
        sceneModels.forEach(function (scene, index) {
          var item = document.createElement('section');
          item.className = 'sv-editor-item';
          item.setAttribute('data-editor-scene-id', scene.id);

          var head = document.createElement('div');
          head.className = 'sv-editor-item-head';

          var jumpBtn = document.createElement('button');
          jumpBtn.type = 'button';
          jumpBtn.className = 'sv-editor-item-title';
          jumpBtn.textContent = i18nText('分镜', 'Scene') + (index + 1) + ' · ' + (scene.title || '');
          jumpBtn.addEventListener('click', function () {
            focusScene(scene.id);
          });
          head.appendChild(jumpBtn);

          var statusWrap = document.createElement('div');
          statusWrap.className = 'sv-editor-status-wrap';
          var status = document.createElement('span');
          status.className = 'sv-editor-status';
          status.textContent = getStatusLabel(scene.status);
          statusWrap.appendChild(status);
          var retryBtn = document.createElement('button');
          retryBtn.type = 'button';
          retryBtn.className = 'scene-chip-retry sv-editor-retry';
          retryBtn.setAttribute('aria-label', i18nText('重新生成当前分镜', 'Retry this scene'));
          retryBtn.setAttribute('title', i18nText('重新生成当前分镜', 'Retry this scene'));
          retryBtn.innerHTML = getRetryButtonInnerHtml(scene.status === 'generating');
          if (scene.status === 'generating' || !hostCaps.canRetry) retryBtn.setAttribute('disabled', 'disabled');
          retryBtn.addEventListener('click', function (event) {
            event.preventDefault();
            event.stopPropagation();
            requestSceneRetry(scene.id);
            if (isEditorOpen) renderEditorList();
          });
          statusWrap.appendChild(retryBtn);
          head.appendChild(statusWrap);

          item.appendChild(head);

          var scriptField = document.createElement('label');
          scriptField.className = 'sv-editor-field';
          var scriptLabel = document.createElement('span');
          scriptLabel.className = 'sv-editor-label';
          scriptLabel.textContent = i18nText('脚本', 'Script');
          var scriptInput = document.createElement('div');
          scriptInput.className = 'sv-editor-script-view';
          scriptInput.setAttribute('data-field-scene-id', scene.id);
          scriptInput.textContent = scene.scriptText || '';
          scriptField.appendChild(scriptLabel);
          scriptField.appendChild(scriptInput);
          item.appendChild(scriptField);

          var promptField = document.createElement('label');
          promptField.className = 'sv-editor-field';
          var promptLabel = document.createElement('span');
          promptLabel.className = 'sv-editor-label';
          promptLabel.textContent = i18nText('提示词', 'Prompt');
          var promptInput = document.createElement('textarea');
          promptInput.className = 'sv-editor-textarea';
          promptInput.setAttribute('data-field-scene-id', scene.id);
          promptInput.setAttribute('data-field', 'prompt');
          promptInput.value = scene.prompt || '';
          promptInput.addEventListener('click', function (event) {
            event.stopPropagation();
          });
          promptInput.addEventListener('input', function () {
            scene.prompt = promptInput.value;
            markEditorDirty();
          });
          promptField.appendChild(promptLabel);
          promptField.appendChild(promptInput);
          item.appendChild(promptField);
          item.addEventListener('click', function () {
            focusScene(scene.id);
          });

          fragment.appendChild(item);
        });
        editorList.appendChild(fragment);
        highlightActiveEditorItem();
      }
      function highlightActiveEditorItem() {
        if (!editorList) return;
        var itemList = Array.prototype.slice.call(editorList.querySelectorAll('[data-editor-scene-id]'));
        itemList.forEach(function (item) {
          if (item.getAttribute('data-editor-scene-id') === state.sceneId) item.classList.add('is-active');
          else item.classList.remove('is-active');
        });
      }
      function openEditor() {
        if (!hostCaps.canEditPanel) return;
        if (!editorOverlay) return;
        renderEditorList();
        applyEditorHeight(editorHeightVh);
        editorOverlay.classList.add('is-open');
        editorOverlay.setAttribute('aria-hidden', 'false');
        document.body.classList.add('sv-editor-open');
        isEditorOpen = true;
      }
      function closeEditor() {
        if (!editorOverlay) return;
        editorOverlay.classList.remove('is-open');
        editorOverlay.setAttribute('aria-hidden', 'true');
        document.body.classList.remove('sv-editor-open');
        isEditorOpen = false;
      }
      function saveEditor() {
        persistMetaToScript();
        clearEditorDirty();
        showSavedTip();
        if (window.parent && window.parent !== window) {
          window.parent.postMessage({ type: '__SVGVIDEO_META_UPDATED', meta: meta }, '*');
        }
      }
      function getTotalSteps() {
        return sceneModels.reduce(function (sum, scene) { return sum + Math.max(1, Number(scene.steps) || 1); }, 0);
      }
      function getSceneIndexById(sceneId) {
        for (var i = 0; i < sceneModels.length; i++) {
          if (sceneModels[i].id === sceneId) return i;
        }
        return -1;
      }
      function getSceneInitialStep(sceneId) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return 0;
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        return Math.max(0, maxSteps - 1);
      }
      function focusScene(sceneId) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return;
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        stopPlayback();
        window.__SVGVIDEO_SET_STATE(sceneId, 0, 1);
        if (maxSteps > 1) {
          setTimeout(function () {
            window.__SVGVIDEO_SET_STATE(sceneId, Math.max(0, maxSteps - 1), 1);
          }, 90);
        }
      }
      function getProgressPercent(sceneId, step) {
        var total = getTotalSteps();
        if (!total) return 0;
        var index = getSceneIndexById(sceneId);
        if (index < 0) return 0;
        var completed = 0;
        for (var i = 0; i < index; i++) completed += Math.max(1, Number(sceneModels[i].steps) || 1);
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        var localStep = Math.max(0, Math.min(maxSteps - 1, Number(step) || 0));
        return Math.max(0, Math.min(100, ((completed + localStep) / total) * 100));
      }
      function updateProgressUi(percent) {
        var pct = Math.max(0, Math.min(100, percent || 0));
        if (progressFill) progressFill.style.width = pct + '%';
        if (progressThumb) progressThumb.style.left = pct + '%';
      }
      function stopProgressAnimation() {
        if (progressRaf) {
          cancelAnimationFrame(progressRaf);
          progressRaf = null;
        }
      }
      function startProgressSegment(fromPercent, toPercent, durationMs) {
        stopProgressAnimation();
        var from = Math.max(0, Math.min(100, Number(fromPercent) || 0));
        var to = Math.max(0, Math.min(100, Number(toPercent) || 0));
        var duration = Math.max(1, Number(durationMs) || 1);
        if (duration <= 1 || to <= from) {
          updateProgressUi(to);
          return;
        }
        var startAt = performance.now();
        var tick = function (now) {
          if (!isPlaying) {
            stopProgressAnimation();
            return;
          }
          var elapsed = now - startAt;
          var ratio = Math.max(0, Math.min(1, elapsed / duration));
          var current = from + (to - from) * ratio;
          updateProgressUi(current);
          if (ratio < 1) {
            progressRaf = requestAnimationFrame(tick);
          } else {
            stopProgressAnimation();
          }
        };
        progressRaf = requestAnimationFrame(tick);
      }
      function getPlaybackSegment(sceneIndex, step) {
        var scene = sceneModels[sceneIndex];
        if (!scene) return null;
        var currentPercent = getProgressPercent(scene.id, step);
        var maxSteps = Math.max(1, Number(scene.steps) || 1);
        if (step < maxSteps - 1) {
          return {
            from: currentPercent,
            to: getProgressPercent(scene.id, step + 1),
            duration: STEP_INTERVAL_MS
          };
        }
        if (sceneIndex < sceneModels.length - 1) {
          var nextScene = sceneModels[sceneIndex + 1];
          var nextPercent = nextScene ? getProgressPercent(nextScene.id, 0) : currentPercent;
          return {
            from: currentPercent,
            to: nextPercent,
            duration: SCENE_FINISH_PAUSE_MS
          };
        }
        return {
          from: currentPercent,
          to: 100,
          duration: STEP_INTERVAL_MS
        };
      }
      function renderStatus() {
        if (!statusText) return;
        var done = sceneModels.filter(function (scene) { return scene.status === 'success'; }).length;
        var pending = sceneModels.filter(function (scene) { return scene.status === 'pending' || scene.status === 'generating'; }).length;
        var failed = sceneModels.filter(function (scene) { return scene.status === 'failed'; }).length;
        statusText.textContent = '已生成 ' + done + '/' + sceneModels.length + ' · 待生成 ' + pending + ' · 失败 ' + failed;
      }
      function updatePlayButton() {
        if (!playBtn) return;
        playBtn.innerHTML = isPlaying
          ? '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><rect x="6" y="5" width="4" height="14" rx="1"></rect><rect x="14" y="5" width="4" height="14" rx="1"></rect></svg>'
          : '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M7 5v14l11-7z"></path></svg>';
        playBtn.setAttribute('aria-label', isPlaying ? '暂停播放' : '播放分镜');
        playBtn.setAttribute('title', isPlaying ? '暂停播放' : '播放分镜');
      }
      function applyHostCaps() {
        if (hostCaps.canRetry) document.body.classList.add('sv-host-can-retry');
        else document.body.classList.remove('sv-host-can-retry');
        if (hostCaps.canEditPanel) document.body.classList.add('sv-host-can-edit-panel');
        else document.body.classList.remove('sv-host-can-edit-panel');
        if (hostCaps.theme === 'light') document.body.classList.add('sv-theme-light');
        else document.body.classList.remove('sv-theme-light');
      }
      function highlightActiveSceneButton() {
        sceneButtonList.forEach(function (button) {
          var targetId = button.getAttribute('data-panel-scene-id');
          if (targetId === state.sceneId) button.classList.add('is-active');
          else button.classList.remove('is-active');
        });
      }
      function stopPlayback() {
        if (playTimer) {
          clearTimeout(playTimer);
          playTimer = null;
        }
        stopProgressAnimation();
        isPlaying = false;
        updatePlayButton();
      }
      function startPlayback() {
        if (!sceneModels.length) return;
        stopPlayback();
        var sceneIndex = Math.max(0, getSceneIndexById(state.sceneId));
        var step = 0;
        var applyPlaybackState = function (direction) {
          var scene = sceneModels[sceneIndex];
          if (!scene) return false;
          window.__SVGVIDEO_SET_STATE(scene.id, step, direction);
          updateProgressUi(getProgressPercent(scene.id, step));
          var segment = getPlaybackSegment(sceneIndex, step);
          if (segment) startProgressSegment(segment.from, segment.to, segment.duration);
          return true;
        };
        var scheduleAdvance = function (delay) {
          playTimer = setTimeout(function () {
            var currentScene = sceneModels[sceneIndex];
            if (!currentScene) {
              stopPlayback();
              return;
            }
            var maxSteps = Math.max(1, Number(currentScene.steps) || 1);
            if (step < maxSteps - 1) {
              step += 1;
              applyPlaybackState(1);
              scheduleAdvance(STEP_INTERVAL_MS);
              return;
            }
            if (sceneIndex < sceneModels.length - 1) {
              playTimer = setTimeout(function () {
                sceneIndex += 1;
                step = 0;
                if (!applyPlaybackState(1)) {
                  stopPlayback();
                  return;
                }
                scheduleAdvance(STEP_INTERVAL_MS);
              }, SCENE_FINISH_PAUSE_MS);
              return;
            }
            stopPlayback();
          }, delay);
        };
        isPlaying = true;
        updatePlayButton();
        if (!applyPlaybackState(1)) {
          stopPlayback();
          return;
        }
        scheduleAdvance(STEP_INTERVAL_MS);
      }
      window.SceneLifecycle = {
        handlers: {},
        register: function (sceneId, handler) { this.handlers[sceneId] = handler || {}; }
      };

      (function () {
        var sceneDataJson = document.getElementById('__SVGVIDEO_SCENE_DATA__');
        var runtimeScenes = [];
        try {
          runtimeScenes = JSON.parse((sceneDataJson && sceneDataJson.textContent) || '[]');
        } catch (_e) {
          runtimeScenes = [];
        }
        runtimeScenes.forEach(function (scene) {
          if (!scene || typeof scene.id !== 'string') return;
          var js = typeof scene.js === 'string' ? scene.js.trim() : '';
          if (!js) return;
          try {
            var factory = new Function(js);
            factory.call(window);
          } catch (err) {
            console.error('[svg-video] scene runtime failed', scene.id, err);
          }
        });
        refreshFrameworkIcons(document);
      })();

      function applyStepVisibility(sceneEl) {
        var stepNodes = sceneEl.querySelectorAll('[data-step], [data-show-step]');
        stepNodes.forEach(function (node) {
          if (node && (node.hasAttribute('data-framework-scene-id') || node.hasAttribute('data-scene-id'))) return;
          var hasShowStepAttr = node.hasAttribute('data-show-step');
          var minStep = Number(hasShowStepAttr ? node.getAttribute('data-show-step') : node.getAttribute('data-step') || '0');
          var visible = state.step >= minStep;
          node.style.opacity = visible ? '1' : '0';
          node.style.visibility = visible ? 'visible' : 'hidden';
          node.style.pointerEvents = visible ? 'auto' : 'none';
          node.style.transform = visible ? 'translateY(0)' : 'translateY(8px)';
          node.style.filter = visible ? 'blur(0px)' : 'blur(4px)';
        });
      }
      function syncSceneStepClasses(sceneEl, sceneId, stepValue) {
        if (!sceneEl) return;
        var sceneRoot = sceneEl.querySelector('.s-' + sceneId + '-root');
        if (!sceneRoot) {
          sceneRoot = sceneEl.querySelector('[data-scene-root-id="' + sceneId + '"]');
        }
        if (!sceneRoot) {
          sceneRoot = sceneEl.querySelector('[data-scene-id="' + sceneId + '"]');
        }
        if (!sceneRoot) return;
        var logicalStep = Number(stepValue) || 0;
        sceneRoot.classList.remove('step-ge-0', 'step-ge-1', 'step-ge-2', 'step-ge-3', 'step-ge-4', 'step-ge-5', 'step-ge-6');
        sceneRoot.classList.add('step-ge-0');
        if (logicalStep >= 1) sceneRoot.classList.add('step-ge-1');
        if (logicalStep >= 2) sceneRoot.classList.add('step-ge-2');
        if (logicalStep >= 3) sceneRoot.classList.add('step-ge-3');
        if (logicalStep >= 4) sceneRoot.classList.add('step-ge-4');
        if (logicalStep >= 5) sceneRoot.classList.add('step-ge-5');
        if (logicalStep >= 6) sceneRoot.classList.add('step-ge-6');
      }
      function applySceneState() {
        var scenes = document.querySelectorAll('#stage > [data-framework-scene-id], #stage > [data-scene-id]');
        var currentSceneEl = null;
        var previousSceneEl = null;
        var glitchTimer = null;
        scenes.forEach(function (sceneEl) {
          var sceneId = sceneEl.getAttribute('data-framework-scene-id') || sceneEl.getAttribute('data-scene-id');
          if (sceneId === state.sceneId) currentSceneEl = sceneEl;
          if (sceneId === previousSceneId) previousSceneEl = sceneEl;
        });
        var direction = state.direction >= 0 ? 1 : -1;
        document.documentElement.style.setProperty('--scene-enter-offset', direction > 0 ? '200px' : '-200px');
        document.documentElement.style.setProperty('--scene-exit-offset', direction > 0 ? '-140px' : '140px');
        var isSceneChange = previousSceneId !== state.sceneId;
        var targetTransition = sceneTransitionMap[state.sceneId] || 'door';
        var needsGlitch = isSceneChange && targetTransition === 'glitch' && currentSceneEl;

        // Apply per-scene transition CSS vars before switching
        if (isSceneChange) {
          var preset = TRANSITION_PRESETS[targetTransition] || TRANSITION_PRESETS['door'];
          var rootStyle = document.documentElement.style;
          for (var varKey in preset) {
            rootStyle.setProperty(varKey, preset[varKey]);
          }
        }

        function doSwitch() {
          if (exitCleanupTimer) {
            clearTimeout(exitCleanupTimer);
            exitCleanupTimer = null;
          }
          scenes.forEach(function (sceneEl) {
            if (sceneEl !== currentSceneEl && sceneEl !== previousSceneEl) {
              sceneEl.classList.remove('scene-active');
              sceneEl.classList.remove('scene-exit');
            }
          });
          if (previousSceneEl && previousSceneEl !== currentSceneEl) {
            previousSceneEl.classList.remove('scene-active');
            previousSceneEl.classList.add('scene-exit');
          }
          if (currentSceneEl) {
            currentSceneEl.classList.remove('scene-exit');
            currentSceneEl.classList.add('scene-active');
            applyStepVisibility(currentSceneEl);
          }
          if (previousSceneEl && previousSceneEl !== currentSceneEl) {
            exitCleanupTimer = setTimeout(function () { previousSceneEl.classList.remove('scene-exit'); }, 650);
          }
          if (previousSceneId !== state.sceneId) {
            if (previousSceneId && window.SceneLifecycle.handlers[previousSceneId] && typeof window.SceneLifecycle.handlers[previousSceneId].leave === 'function') {
              try { window.SceneLifecycle.handlers[previousSceneId].leave(); } catch (e) {}
            }
          }
          if (isSceneChange && currentSceneEl && window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].enter === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].enter(); } catch (e) {}
          }
          if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].step === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].step(state.step); } catch (e) {}
          }
          if (currentSceneEl) {
            syncSceneStepClasses(currentSceneEl, state.sceneId, state.step);
            refreshFrameworkIcons(currentSceneEl);
          }
          previousSceneId = state.sceneId;
          highlightActiveSceneButton();
          highlightActiveEditorItem();
          updateProgressUi(getProgressPercent(state.sceneId, state.step));
        }

        function runGlitchSequence() {
          if (!currentSceneEl) return;
          // Step 1: blur bomb + shift (instant, disable transition first)
          var noTrans = document.getElementById('sv-no-transition');
          if (!noTrans) {
            noTrans = document.createElement('style');
            noTrans.id = 'sv-no-transition';
            noTrans.textContent = '.scene { transition: none !important; }';
            document.head.appendChild(noTrans);
          }
          currentSceneEl.style.filter = 'blur(24px) brightness(1.5)';
          currentSceneEl.style.transform = 'translateX(30px) scale(0.96)';
          // Step 2: snap to other side (80ms)
          glitchTimer = setTimeout(function () {
            if (!currentSceneEl) return;
            currentSceneEl.style.filter = 'blur(3px) brightness(1.1)';
            currentSceneEl.style.transform = 'translateX(-15px) scale(1.02)';
            // Step 3: settle with slight bounce (160ms)
            glitchTimer = setTimeout(function () {
              if (!currentSceneEl) return;
              currentSceneEl.style.filter = 'blur(0px) brightness(1)';
              currentSceneEl.style.transform = 'translateX(0) scale(1)';
              if (noTrans && noTrans.parentNode) noTrans.parentNode.removeChild(noTrans);
              if (currentSceneEl) {
                refreshFrameworkIcons(currentSceneEl);
              }
            }, 70);
          }, 80);
        }

        if (needsGlitch) {
          // Kill old scene instantly
          if (previousSceneEl) {
            previousSceneEl.classList.remove('scene-active');
            previousSceneEl.classList.add('scene-exit');
            exitCleanupTimer = setTimeout(function () { previousSceneEl.classList.remove('scene-exit'); }, 650);
          }
          // Show new scene for glitch base
          if (currentSceneEl) {
            currentSceneEl.classList.remove('scene-exit');
            currentSceneEl.classList.add('scene-active');
            applyStepVisibility(currentSceneEl);
          }
          // Fire lifecycle immediately so scene JS can initialize
          if (previousSceneId && window.SceneLifecycle.handlers[previousSceneId] && typeof window.SceneLifecycle.handlers[previousSceneId].leave === 'function') {
            try { window.SceneLifecycle.handlers[previousSceneId].leave(); } catch (e) {}
          }
          if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].enter === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].enter(); } catch (e) {}
          }
          if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].step === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].step(state.step); } catch (e) {}
          }
          if (currentSceneEl) {
            syncSceneStepClasses(currentSceneEl, state.sceneId, state.step);
          }
          previousSceneId = state.sceneId;
          highlightActiveSceneButton();
          highlightActiveEditorItem();
          updateProgressUi(getProgressPercent(state.sceneId, state.step));
          runGlitchSequence();
        } else {
          doSwitch();
        }
      }
      window.__SVGVIDEO_SET_STATE = function (sceneId, step, direction) {
        if (typeof sceneId === 'string' && sceneId) {
          if (typeof direction === 'number' && Number.isFinite(direction)) {
            state.direction = direction >= 0 ? 1 : -1;
          } else {
            var nextIndex = getSceneIndexById(sceneId);
            var prevIndex = getSceneIndexById(state.sceneId);
            if (nextIndex !== -1 && prevIndex !== -1) state.direction = nextIndex >= prevIndex ? 1 : -1;
          }
          state.sceneId = sceneId;
        }
        if (typeof step === 'number' && Number.isFinite(step)) state.step = Math.max(0, Math.floor(step));
        applySceneState();
      };
      if (state.sceneId && getSceneIndexById(state.sceneId) === -1 && sceneModels.length) {
        state.sceneId = sceneModels[0].id;
      }
      if (playBtn) {
        playBtn.addEventListener('click', function () {
          if (isPlaying) stopPlayback();
          else startPlayback();
        });
      }
      if (expandBtn) {
        expandBtn.addEventListener('click', function () {
          if (isEditorOpen) closeEditor();
          else openEditor();
        });
      }
      if (editorCloseBtn) {
        editorCloseBtn.addEventListener('click', closeEditor);
      }
      if (editorBackdrop) {
        editorBackdrop.addEventListener('click', closeEditor);
      }
      if (editorSaveBtn) {
        editorSaveBtn.addEventListener('click', saveEditor);
      }
      if (editorResizeHandle && editorSheet) {
        editorResizeHandle.addEventListener('mousedown', function (event) {
          event.preventDefault();
          var startY = event.clientY;
          var startHeightPx = (window.innerHeight * editorHeightVh) / 100;
          var onMove = function (moveEvent) {
            var delta = startY - moveEvent.clientY;
            var nextHeightPx = startHeightPx + delta;
            var nextHeightVh = (nextHeightPx / Math.max(1, window.innerHeight)) * 100;
            applyEditorHeight(nextHeightVh);
          };
          var onUp = function () {
            window.removeEventListener('mousemove', onMove);
            window.removeEventListener('mouseup', onUp);
          };
          window.addEventListener('mousemove', onMove);
          window.addEventListener('mouseup', onUp);
        });
      }
      sceneButtonList.forEach(function (button) {
        button.addEventListener('click', function () {
          var sceneId = button.getAttribute('data-panel-scene-id');
          if (!sceneId) return;
          focusScene(sceneId);
        });
      });
      sceneRetryButtonList.forEach(function (button) {
        button.addEventListener('click', function (event) {
          event.preventDefault();
          event.stopPropagation();
          var sceneId = button.getAttribute('data-retry-scene-id');
          if (!sceneId) return;
          requestSceneRetry(sceneId);
        });
      });
      if (progressWrap) {
        progressWrap.addEventListener('click', function (event) {
          var rect = progressWrap.getBoundingClientRect();
          var pct = Math.max(0, Math.min(100, ((event.clientX - rect.left) / rect.width) * 100));
          var totalSteps = getTotalSteps();
          var targetStep = Math.round((pct / 100) * totalSteps);
          var accumulated = 0;
          for (var i = 0; i < sceneModels.length; i++) {
            var sceneSteps = Math.max(1, Number(sceneModels[i].steps) || 1);
            if (accumulated + sceneSteps > targetStep) {
              var localStep = Math.max(0, Math.min(sceneSteps - 1, targetStep - accumulated));
              stopPlayback();
              window.__SVGVIDEO_SET_STATE(sceneModels[i].id, localStep, 1);
              updateProgressUi(pct);
              return;
            }
            accumulated += sceneSteps;
          }
        });
      }
      window.addEventListener('message', function (event) {
        var data = event && event.data;
        if (!data || typeof data.type !== 'string') return;
        if (data.type === '__SVGVIDEO_SET_STATE') {
          window.__SVGVIDEO_SET_STATE(data.sceneId, data.step, data.direction);
          return;
        }
        if (data.type === '__SVGVIDEO_PLAY') {
          startPlayback();
          return;
        }
        if (data.type === '__SVGVIDEO_STOP') {
          stopPlayback();
          return;
        }
        if (data.type === '__SVGVIDEO_SET_HOST_CAPS') {
          hostCaps.canRetry = Boolean(data.canRetry);
          hostCaps.canEditPanel = Boolean(data.canEditPanel);
          hostCaps.locale = data.locale === 'en' ? 'en' : 'zh';
          hostCaps.theme = data.theme === 'light' ? 'light' : 'dark';
          applyI18nTexts();
          applyHostCaps();
          if (isEditorOpen) renderEditorList();
          return;
        }
        if (data.type === '__SVGVIDEO_SET_SCENE_STATUS') {
          var sceneId = typeof data.sceneId === 'string' ? data.sceneId : '';
          var status = typeof data.status === 'string' ? data.status : '';
          if (sceneId && status) {
            setSceneStatus(sceneId, status);
            if (isEditorOpen) renderEditorList();
          }
          return;
        }
        if (data.type === '__SVGVIDEO_SET_RECORDING') {
          if (data && data.active) {
            document.body.classList.add('sv-recording');
            // 如果指定了初始分镜，无过渡动画地跳转过去，避免录制开头残留旧分镜画面
            if (data.sceneId) {
              var noTransStyle = document.createElement('style');
              noTransStyle.id = 'sv-no-transition';
              noTransStyle.textContent = '.scene, [data-step] { transition: none !important; }';
              document.head.appendChild(noTransStyle);
              window.__SVGVIDEO_SET_STATE(data.sceneId, 0, 1);
              // 强制 reflow 后恢复过渡动画
              void document.body.offsetHeight;
              requestAnimationFrame(function () {
                var s = document.getElementById('sv-no-transition');
                if (s) s.remove();
              });
            }
          } else {
            document.body.classList.remove('sv-recording');
          }
          return;
        }
        if (data.type === '__SVGVIDEO_SET_META' && data.meta && typeof data.meta === 'object') {
          meta = data.meta;
          var freshScenes = Array.isArray(meta.scenes) ? meta.scenes : [];
          freshScenes.forEach(function (scene) {
            var idx = getSceneIndexById(scene.id);
            if (idx < 0) return;
            sceneModels[idx].prompt = typeof scene.prompt === 'string' ? scene.prompt : '';
            sceneModels[idx].scriptText = typeof scene.scriptText === 'string' ? scene.scriptText : '';
            sceneModels[idx].audioObjectKey = typeof scene.audioObjectKey === 'string' ? scene.audioObjectKey : '';
            sceneModels[idx].audioDurationMs = Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0;
            sceneModels[idx].voiceName = typeof scene.voiceName === 'string' ? scene.voiceName : '';
            sceneModels[idx].voiceStyle = typeof scene.voiceStyle === 'string' ? scene.voiceStyle : '';
          });
          persistMetaToScript();
          if (isEditorOpen) renderEditorList();
        }
      });
      document.addEventListener('keydown', function (event) {
        if (event.key === 'Escape' && isEditorOpen) closeEditor();
      });
      window.__SVGVIDEO_PLAY = startPlayback;
      window.__SVGVIDEO_STOP = stopPlayback;
      window.__SVGVIDEO_OPEN_EDITOR = openEditor;
      window.__SVGVIDEO_CLOSE_EDITOR = closeEditor;
      applyEditorHeight(editorHeightVh);
      renderStatus();
      updatePlayButton();
      applyHostCaps();
      clearEditorDirty();
      applyI18nTexts();
      applySceneState();
      if (autoplayFromFirstScene && sceneModels.length) {
        state.sceneId = sceneModels[0].id;
        state.step = 0;
        state.direction = 1;
        applySceneState();
        startPlayback();
      }
    })();
  </script>
</body>
</html>2b:T379b9,<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Unlocking Speed: How Large Model Caching Works</title>
  <style>
    
    @font-face {
      font-family: "SVGVideoAlimamaShuHei";
      src:
        url("/fonts/AlimamaShuHeiTi-Bold.woff2") format("woff2"),
        url("/fonts/AlimamaShuHeiTi-Bold.woff") format("woff"),
        url("/fonts/AlimamaShuHeiTi-Bold.ttf") format("truetype"),
        local("Alimama ShuHeiTi Bold"),
        local("Alimama ShuHeiTi"),
        local("AlimamaShuHeiTi-Bold"),
        local("AlimamaShuHeiTi");
      font-display: swap;
      font-weight: 700;
      font-style: normal;
    }
    :root {
      color-scheme: dark;
      --bg: #202020;
      --fg: #e2e8f0;
      --muted: #94a3b8;
      --card: rgba(255, 255, 255, 0.05);
      --border: rgba(255, 255, 255, 0.12);
      --sv-editor-height: 50vh;
      --sv-font-display-cn: "SVGVideoAlimamaShuHei", "Alimama ShuHeiTi", "AlimamaShuHeiTi-Bold", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
      --sv-font-body-cn: "SVGVideoAlimamaShuHei", "Alimama ShuHeiTi", "AlimamaShuHeiTi-Bold", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
      --sv-font-mono: "SFMono-Regular", "JetBrains Mono", "Fira Code", "Courier New", monospace;
      --sv-stage-perspective: 900px;
        --sv-trans-enter-opacity: 0;
        --sv-trans-enter-transform: rotateY(90deg);
        --sv-trans-enter-filter: blur(6px);
        --sv-trans-active-opacity: 1;
        --sv-trans-active-transform: rotateY(0deg);
        --sv-trans-active-filter: blur(0px);
        --sv-trans-exit-opacity: 0;
        --sv-trans-exit-transform: rotateY(-90deg);
        --sv-trans-exit-filter: blur(4px);
        --sv-trans-duration: 0.65s;
        --sv-trans-ease: cubic-bezier(0.36, 0, 0.66, 1);
    }
    * { box-sizing: border-box; }
    html, body {
      margin: 0; width: 100%; height: 100%; overflow: hidden;
      background: var(--bg);
      color: var(--fg);
      font-family: var(--sv-font-body-cn);
    }
    #app { width: 100%; height: 100%; display: flex; flex-direction: column; }
    #viewport { position: relative; flex: 1; min-height: 0; overflow: hidden; }
    #stage {
      position: relative; width: 100%; height: 100%; overflow: hidden;
      perspective: var(--sv-stage-perspective, none);
      perspective-origin: 50% 50%;
    }
    .scene {
      position: absolute; inset: 0; overflow: hidden;
      backface-visibility: hidden;
      -webkit-backface-visibility: hidden;
      opacity: var(--sv-trans-enter-opacity, 0); pointer-events: none;
      transform: var(--sv-trans-enter-transform, translateX(var(--scene-enter-offset, 56px)) scale(0.96));
      filter: var(--sv-trans-enter-filter, blur(10px));
      transition: opacity var(--sv-trans-duration, .55s) var(--sv-trans-ease, cubic-bezier(.22,1,.36,1)), transform var(--sv-trans-duration, .55s) var(--sv-trans-ease, cubic-bezier(.22,1,.36,1)), filter var(--sv-trans-duration, .55s) ease;
      will-change: opacity, transform, filter;
      z-index: 1;
    }
    .scene.scene-active {
      opacity: var(--sv-trans-active-opacity, 1); pointer-events: auto;
      transform: var(--sv-trans-active-transform, translateX(0) scale(1));
      filter: var(--sv-trans-active-filter, blur(0px));
      z-index: 3;
    }
    .scene.scene-exit {
      opacity: var(--sv-trans-exit-opacity, 0); pointer-events: none;
      transform: var(--sv-trans-exit-transform, translateX(var(--scene-exit-offset, -56px)) scale(0.96));
      filter: var(--sv-trans-exit-filter, blur(10px));
      z-index: 2;
    }
    .scene-placeholder {
      height: 100%; border: 1px dashed var(--border); border-radius: 20px; background: var(--card);
      display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: var(--muted);
    }
    .sv-scene-root { width: 100%; height: 100%; position: relative; overflow: hidden; }
    .scene-placeholder-title { font-size: 28px; color: var(--fg); font-weight: 700; }
    [data-step] { transition: opacity .35s ease, transform .35s ease, filter .35s ease; }
    #sv-controls {
      background: rgba(19, 19, 19, 0.95);
      border-top: 1px solid rgba(255,255,255,0.08);
      padding: 8px 12px 10px;
      display: flex;
      flex-direction: column;
      gap: 8px;
      backdrop-filter: blur(8px);
      flex-shrink: 0;
    }
    .sv-progress-wrap {
      position: relative;
      height: 22px;
      display: flex;
      align-items: center;
      cursor: pointer;
    }
    .sv-progress-track {
      width: 100%;
      height: 4px;
      border-radius: 999px;
      background: rgba(120, 120, 120, 0.55);
      position: relative;
      overflow: hidden;
    }
    .sv-progress-fill {
      position: absolute;
      left: 0;
      top: 0;
      bottom: 0;
      width: 0%;
      border-radius: 999px;
      background: linear-gradient(90deg, #f97316, #fb923c);
      transition: width 220ms ease;
    }
    .sv-progress-thumb {
      position: absolute;
      top: 50%;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      background: #fff;
      transform: translate(-50%, -50%);
      box-shadow: 0 0 0 1px rgba(0,0,0,0.28);
      pointer-events: none;
    }
    .sv-toolbar {
      display: grid;
      grid-template-columns: 1fr auto 1fr;
      align-items: center;
      gap: 8px;
      min-height: 30px;
    }
    .sv-toolbar-left {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      min-width: 0;
    }
    .sv-toolbar-title {
      font-size: 11px;
      color: #a8b0bb;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-expand-btn {
      width: 20px;
      height: 20px;
      border: none;
      border-radius: 6px;
      background: rgba(255,255,255,0.08);
      color: #cbd5e1;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      flex: 0 0 auto;
      transition: background 140ms ease, color 140ms ease, transform 120ms ease;
    }
    .sv-expand-btn:hover {
      background: rgba(255,255,255,0.15);
      color: #f8fafc;
    }
    .sv-expand-btn:active {
      transform: scale(0.94);
    }
    body:not(.sv-host-can-edit-panel) .sv-expand-btn {
      display: none;
    }
    .sv-play-btn {
      width: 28px;
      height: 28px;
      border: none;
      border-radius: 999px;
      color: #fff;
      background: #f97316;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: transform 120ms ease, background 160ms ease;
    }
    .sv-play-btn:hover { background: #fb923c; }
    .sv-play-btn:active { transform: scale(0.94); }
    .sv-play-btn:disabled { opacity: 0.45; cursor: not-allowed; }
    .sv-status {
      text-align: right;
      font-size: 11px;
      color: #8f98a5;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-scene-grid {
      display: flex;
      align-items: stretch;
      gap: 6px;
      flex-wrap: nowrap;
      overflow: hidden;
    }
    .scene-chip {
      position: relative;
      width: 100%;
      border: none;
      border-bottom: 2px solid transparent;
      border-radius: 8px;
      background: rgba(255,255,255,0.06);
      color: #a3a3a3;
      padding: 7px 6px;
      text-align: center;
      font-size: 11px;
      line-height: 1.1;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      cursor: pointer;
      transition: transform 140ms ease, color 160ms ease, background 160ms ease, border-color 160ms ease;
    }
    .scene-chip-label {
      display: block;
      width: 100%;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .scene-chip-wrap {
      position: relative;
      flex: 1 1 0;
      min-width: 0;
    }
    .scene-chip-retry {
      position: absolute;
      top: 50%;
      right: 4px;
      transform: translateY(-50%);
      width: 24px;
      height: 24px;
      border: none;
      border-radius: 999px;
      background: #f97316;
      color: #fff;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
      opacity: 0;
      pointer-events: none;
      transition: opacity 160ms ease;
      cursor: pointer;
    }
    body.sv-host-can-retry .scene-chip-wrap:hover .scene-chip-retry {
      opacity: 1;
      pointer-events: auto;
    }
    .scene-chip-retry:disabled {
      opacity: 1;
      pointer-events: none;
      background: #f97316;
    }
    .scene-chip-retry-icon {
      width: 18px;
      height: 18px;
      display: block;
    }
    .scene-chip-retry-spinner {
      width: 14px;
      height: 14px;
      aspect-ratio: 1 / 1;
      border: 2px solid #ffffff;
      border-top-color: transparent;
      border-radius: 999px;
      box-sizing: border-box;
      animation: sceneChipSpin 1s linear infinite;
      display: block;
      flex: 0 0 auto;
    }
    @keyframes sceneChipSpin {
      from { transform: rotate(0deg); }
      to { transform: rotate(360deg); }
    }
    .scene-chip:hover { transform: scale(1.02); }
    .scene-chip.is-active {
      color: #fb923c;
      border-bottom-color: #fb923c;
      background: linear-gradient(135deg, rgba(249,115,22,0.2), rgba(168,85,247,0.2));
    }
    .scene-chip.is-failed {
      color: #fca5a5;
      border-bottom-color: rgba(239,68,68,0.95);
      background: rgba(239,68,68,0.12);
    }
    .scene-chip.is-generating {
      color: #fcd34d;
      background: rgba(245,158,11,0.11);
    }
    .sv-editor-overlay {
      position: relative;
      width: 100%;
      height: 0;
      z-index: 40;
      pointer-events: none;
      overflow: hidden;
      transition: height 260ms cubic-bezier(.22,1,.36,1);
    }
    .sv-editor-backdrop {
      position: absolute;
      inset: auto 0 0 0;
      height: 100%;
      background: rgba(0, 0, 0, 0.45);
      opacity: 0;
      transition: opacity 220ms ease;
    }
    .sv-editor-sheet {
      position: absolute;
      left: 0;
      right: 0;
      bottom: 0;
      height: 100%;
      background: rgba(16, 16, 16, 0.96);
      border-top: 1px solid rgba(255,255,255,0.12);
      box-shadow: 0 -14px 30px rgba(0,0,0,0.45);
      transform: translateY(102%);
      transition: transform 260ms cubic-bezier(.22,1,.36,1);
      display: flex;
      flex-direction: column;
    }
    .sv-editor-overlay.is-open {
      pointer-events: auto;
      height: var(--sv-editor-height, 50vh);
    }
    .sv-editor-overlay.is-open .sv-editor-backdrop {
      opacity: 1;
    }
    .sv-editor-overlay.is-open .sv-editor-sheet {
      transform: translateY(0);
    }
    .sv-editor-resize-handle {
      width: 100%;
      height: 14px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: ns-resize;
      flex: 0 0 auto;
      touch-action: none;
    }
    .sv-editor-resize-handle::before {
      content: "";
      width: 52px;
      height: 4px;
      border-radius: 999px;
      background: rgba(148, 163, 184, 0.7);
    }
    .sv-editor-header {
      padding: 10px 12px;
      border-bottom: 1px solid rgba(255,255,255,0.1);
      display: grid;
      grid-template-columns: 1fr auto;
      align-items: center;
      gap: 8px;
    }
    .sv-editor-header-title {
      color: #f1f5f9;
      font-size: 13px;
      font-weight: 600;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .sv-editor-actions {
      display: inline-flex;
      align-items: center;
      gap: 6px;
    }
    .sv-editor-btn {
      border: none;
      border-radius: 8px;
      cursor: pointer;
      font-size: 12px;
      line-height: 1;
      padding: 7px 10px;
      color: #e2e8f0;
      background: rgba(255,255,255,0.1);
      transition: background 120ms ease;
    }
    .sv-editor-btn:hover {
      background: rgba(255,255,255,0.18);
    }
    .sv-editor-btn.is-primary {
      color: #fff;
      background: #f97316;
    }
    .sv-editor-btn.is-primary:hover {
      background: #fb923c;
    }
    .sv-editor-list {
      flex: 1;
      min-height: 0;
      overflow: auto;
      padding: 10px 12px 14px;
      display: grid;
      gap: 10px;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      align-items: start;
      align-content: start;
    }
    .sv-editor-item {
      border: 1px solid rgba(255,255,255,0.12);
      border-radius: 10px;
      background: rgba(255,255,255,0.03);
      padding: 10px;
      display: grid;
      grid-template-rows: auto auto auto;
      gap: 10px;
      align-content: start;
      cursor: pointer;
    }
    .sv-editor-item.is-active {
      border-color: rgba(249,115,22,0.65);
      box-shadow: inset 0 0 0 1px rgba(249,115,22,0.28);
    }
    .sv-editor-item-head {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 8px;
      min-height: 30px;
    }
    .sv-editor-item-title {
      border: none;
      border-radius: 8px;
      color: #fb923c;
      background: rgba(255,255,255,0.08);
      font-size: 12px;
      font-weight: 600;
      padding: 6px 8px;
      cursor: pointer;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      text-align: left;
    }
    .sv-editor-item-title:hover {
      background: rgba(255,255,255,0.14);
    }
    .sv-editor-status {
      color: #94a3b8;
      font-size: 11px;
      white-space: nowrap;
    }
    .sv-editor-status-wrap {
      display: inline-flex;
      align-items: center;
      gap: 6px;
    }
    .scene-chip-retry.sv-editor-retry {
      position: static;
      transform: none;
      opacity: 1;
      pointer-events: auto;
      width: 24px;
      height: 24px;
      flex: 0 0 auto;
    }
    .sv-editor-field {
      display: grid;
      gap: 6px;
    }
    .sv-editor-label {
      color: #a3a3a3;
      font-size: 11px;
      font-weight: 700;
    }
    .sv-editor-textarea {
      width: 100%;
      border-radius: 8px;
      border: 1px solid rgba(255,255,255,0.14);
      background: rgba(0,0,0,0.24);
      color: #f1f5f9;
      font-size: 12px;
      line-height: 1.45;
      padding: 8px 9px;
      resize: none;
      min-height: 110px;
      height: 110px;
    }
    .sv-editor-textarea[data-field="scriptText"] {
      min-height: 84px;
    }
    .sv-editor-textarea:focus {
      outline: none;
      border-color: rgba(249,115,22,0.7);
      box-shadow: 0 0 0 2px rgba(249,115,22,0.18);
    }
    body.sv-theme-light .sv-editor-textarea {
      border-color: rgba(15,23,42,0.18);
      background: rgba(248,250,252,0.92);
      color: #0f172a;
    }
    body.sv-theme-light .sv-editor-textarea:focus {
      border-color: rgba(249,115,22,0.72);
      box-shadow: 0 0 0 2px rgba(249,115,22,0.2);
    }
    .sv-editor-script-view {
      width: 100%;
      color: #e2e8f0;
      font-size: 12px;
      line-height: 1.5;
      white-space: pre-wrap;
      word-break: break-word;
      min-height: 84px;
      max-height: 84px;
      overflow: auto;
    }
    .sv-editor-save-tip {
      color: #fbbf24;
      font-size: 11px;
      opacity: 0;
      transition: opacity 140ms ease;
      justify-self: end;
    }
    .sv-editor-save-tip.is-visible {
      opacity: 1;
    }
    body.sv-theme-light .sv-editor-backdrop {
      background: rgba(15, 23, 42, 0.2);
    }
    body.sv-theme-light .sv-editor-sheet {
      background: rgba(255, 255, 255, 0.98);
      border-top-color: rgba(15, 23, 42, 0.12);
      box-shadow: 0 -14px 30px rgba(15, 23, 42, 0.16);
    }
    body.sv-theme-light .sv-editor-header {
      border-bottom-color: rgba(15, 23, 42, 0.1);
    }
    body.sv-theme-light .sv-editor-header-title {
      color: #0f172a;
    }
    body.sv-theme-light .sv-editor-btn {
      color: #334155;
      background: rgba(15, 23, 42, 0.08);
    }
    body.sv-theme-light .sv-editor-btn:hover {
      background: rgba(15, 23, 42, 0.14);
    }
    body.sv-theme-light .sv-editor-btn.is-primary {
      color: #ffffff;
      background: #f97316;
    }
    body.sv-theme-light .sv-editor-btn.is-primary:hover {
      background: #fb923c;
    }
    body.sv-theme-light .sv-editor-item {
      border-color: rgba(15, 23, 42, 0.12);
      background: rgba(248, 250, 252, 0.95);
    }
    body.sv-theme-light .sv-editor-item.is-active {
      border-color: rgba(249,115,22,0.72);
      box-shadow: inset 0 0 0 1px rgba(249,115,22,0.3);
    }
    body.sv-theme-light .sv-editor-item-title {
      color: #ea580c;
      background: rgba(249, 115, 22, 0.12);
    }
    body.sv-theme-light .sv-editor-item-title:hover {
      background: rgba(249, 115, 22, 0.18);
    }
    body.sv-theme-light .sv-editor-status {
      color: #64748b;
    }
    body.sv-theme-light .sv-editor-label {
      color: #475569;
    }
    body.sv-theme-light .sv-editor-script-view {
      color: #334155;
    }
    body.sv-theme-light .sv-editor-save-tip {
      color: #c2410c;
    }
    body.sv-editor-open #viewport {
      flex: 1 1 calc(100vh - var(--sv-editor-height, 50vh));
      min-height: 0;
    }
    body.sv-editor-open #sv-controls {
      display: none;
    }
    body.sv-recording .sv-toolbar,
    body.sv-recording .sv-scene-grid {
      display: none;
    }
    body.sv-recording #sv-controls {
      display: none;
    }
    body.sv-theme-light .sv-editor-list,
    body.sv-theme-light .sv-editor-script-view,
    body.sv-theme-light .sv-editor-textarea {
      scrollbar-color: rgba(148, 163, 184, 0.85) rgba(226, 232, 240, 0.85);
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar {
      width: 10px;
      height: 10px;
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-track,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-track,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-track {
      background: rgba(226, 232, 240, 0.85);
      border-radius: 999px;
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-thumb,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-thumb,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-thumb {
      background: rgba(148, 163, 184, 0.85);
      border-radius: 999px;
      border: 2px solid rgba(226, 232, 240, 0.85);
    }
    body.sv-theme-light .sv-editor-list::-webkit-scrollbar-thumb:hover,
    body.sv-theme-light .sv-editor-script-view::-webkit-scrollbar-thumb:hover,
    body.sv-theme-light .sv-editor-textarea::-webkit-scrollbar-thumb:hover {
      background: rgba(100, 116, 139, 0.95);
    }
/* scene-01 */
.sv-scene-root-scene-01 .s-scene-01-container{
  position: relative;
  width: 100%;
  height: 100%;
  background: #1B1B1B;
  overflow: hidden;
  font-family: var(--sv-font-body-cn);
  color: #FFFFFF;
  display: flex;
  align-items: center;
  justify-content: center;
}.sv-scene-root-scene-01 .s-scene-01-bg-grid{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
  background-size: 40px 40px;
  z-index: 1;
}.sv-scene-root-scene-01 .s-scene-01-ambient-glow{
  position: absolute;
  width: 60%;
  height: 60%;
  background: radial-gradient(circle, rgba(245, 53, 1, 0.08) 0%, transparent 70%);
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  animation: s-01-pulse 10s ease-in-out infinite;
  z-index: 2;
}.sv-scene-root-scene-01 .s-scene-01-ghost-text{
  position: absolute;
  bottom: 5%;
  right: 5%;
  font-family: var(--sv-font-display-cn);
  font-size: 120px;
  opacity: 0.04;
  letter-spacing: -2px;
  user-select: none;
  z-index: 1;
}.sv-scene-root-scene-01 .s-scene-01-content{
  position: relative;
  z-index: 10;
  width: 80%;
  max-width: 1000px;
  display: flex;
  flex-direction: column;
  gap: 30px;
}.sv-scene-root-scene-01 .s-scene-01-header{
  display: flex;
  flex-direction: column;
  gap: 10px;
}.sv-scene-root-scene-01 .s-scene-01-title{
  font-family: var(--sv-font-display-cn);
  font-size: 56px;
  margin: 0;
  line-height: 1;
  text-transform: uppercase;
}.sv-scene-root-scene-01 .s-scene-01-tag{
  font-family: var(--sv-font-mono);
  color: #F53501;
  font-size: 14px;
  letter-spacing: 2px;
  display: flex;
  align-items: center;
  gap: 8px;
}.sv-scene-root-scene-01 .s-scene-01-dot{
  width: 6px;
  height: 6px;
  background: #F53501;
  border-radius: 50%;
}.sv-scene-root-scene-01 .s-scene-01-terminal{
  background: rgba(20, 20, 20, 0.8);
  backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 40px 100px rgba(0, 0, 0, 0.5);
  transform: translateY(20px);
  opacity: 0;
  transition: all 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}.sv-scene-root-scene-01 [data-step="0"] .s-scene-01-terminal, .sv-scene-root-scene-01 [data-step="1"] .s-scene-01-terminal, .sv-scene-root-scene-01 [data-step="2"] .s-scene-01-terminal{
  transform: translateY(0);
  opacity: 1;
}.sv-scene-root-scene-01 .s-scene-01-terminal-bar{
  background: rgba(255, 255, 255, 0.05);
  padding: 12px 20px;
  display: flex;
  align-items: center;
  gap: 15px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}.sv-scene-root-scene-01 .s-scene-01-terminal-btns{
  display: flex;
  gap: 6px;
}.sv-scene-root-scene-01 .s-scene-01-terminal-btns span{
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.2);
}.sv-scene-root-scene-01 .s-scene-01-terminal-tab{
  font-family: var(--sv-font-mono);
  font-size: 12px;
  color: rgba(255, 255, 255, 0.4);
}.sv-scene-root-scene-01 .s-scene-01-terminal-body{
  padding: 40px;
  min-height: 200px;
  font-family: var(--sv-font-mono);
  font-size: 24px;
  position: relative;
}.sv-scene-root-scene-01 .s-scene-01-prompt{
  color: #F53501;
  margin-right: 15px;
}.sv-scene-root-scene-01 .s-scene-01-cursor{
  display: inline-block;
  width: 12px;
  height: 24px;
  background: #F53501;
  vertical-align: middle;
  margin-left: 4px;
  animation: s-01-blink 1s step-end infinite;
}.sv-scene-root-scene-01 .s-scene-01-thinking{
  margin-top: 40px;
  display: flex;
  align-items: center;
  gap: 20px;
  opacity: 0;
  transform: translateX(-10px);
  transition: all 0.4s ease-out;
}.sv-scene-root-scene-01 [data-step="2"] .s-scene-01-thinking{
  opacity: 1;
  transform: translateX(0);
}.sv-scene-root-scene-01 .s-scene-01-thinking-label{
  font-size: 16px;
  color: rgba(255, 255, 255, 0.4);
  text-transform: uppercase;
  letter-spacing: 1px;
}.sv-scene-root-scene-01 .s-scene-01-dots{
  display: flex;
  gap: 8px;
}.sv-scene-root-scene-01 .s-scene-01-dots span{
  width: 10px;
  height: 10px;
  background: #F53501;
  border-radius: 50%;
  animation: s-01-dots-pulse 1.4s infinite ease-in-out both;
}.sv-scene-root-scene-01 .s-scene-01-dots span:nth-child(1){ animation-delay: -0.32s; }.sv-scene-root-scene-01 .s-scene-01-dots span:nth-child(2){ animation-delay: -0.16s; }.sv-scene-root-scene-01 .s-scene-01-annotation{
  position: absolute;
  right: -20px;
  bottom: -40px;
  display: flex;
  align-items: center;
  gap: 15px;
  opacity: 0;
  transform: translateY(10px);
  transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
  transition-delay: 0.3s;
}.sv-scene-root-scene-01 [data-step="2"] .s-scene-01-annotation{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-01 .s-scene-01-line-pointer{
  width: 60px;
  height: 1px;
  background: #F53501;
  position: relative;
}.sv-scene-root-scene-01 .s-scene-01-line-pointer::before{
  content: '';
  position: absolute;
  left: 0;
  top: -2px;
  width: 5px;
  height: 5px;
  background: #F53501;
  border-radius: 50%;
}.sv-scene-root-scene-01 .s-scene-01-anno-content{
  background: #F53501;
  padding: 10px 15px;
  color: #FFFFFF;
}.sv-scene-root-scene-01 .s-scene-01-anno-tag{
  font-size: 10px;
  font-weight: bold;
  opacity: 0.8;
}.sv-scene-root-scene-01 .s-scene-01-anno-value{
  font-family: var(--sv-font-mono);
  font-size: 18px;
  font-weight: 900;
}@keyframes s-01-pulse{
  0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 0.08; }
  50% { transform: translate(-50%, -50%) scale(1.2); opacity: 0.12; }
}@keyframes s-01-blink{
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}@keyframes s-01-dots-pulse{
  0%, 80%, 100% { transform: scale(0); opacity: 0.3; }
  40% { transform: scale(1); opacity: 1; }
}

/* scene-02 */
.sv-scene-root-scene-02 .s-scene-02-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background: #1B1B1B;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #FFFFFF;
  font-family: var(--sv-font-body-cn);
}.sv-scene-root-scene-02 .s-scene-02-bg-grid{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
  background-size: 60px 60px;
  z-index: 1;
}.sv-scene-root-scene-02 .s-scene-02-nodes{
  position: absolute;
  inset: 0;
  z-index: 2;
  opacity: 0.3;
}.sv-scene-root-scene-02 .s-scene-02-ghost-text{
  position: absolute;
  top: 10%;
  left: 5%;
  font-family: var(--sv-font-display-cn);
  font-size: 140px;
  opacity: 0.03;
  letter-spacing: -5px;
  user-select: none;
  z-index: 1;
}.sv-scene-root-scene-02 .s-scene-02-main{
  position: relative;
  z-index: 10;
  perspective: 1000px;
}.sv-scene-root-scene-02 .s-scene-02-card-container{
  position: relative;
  background: rgba(30, 30, 30, 0.9);
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 40px 80px;
  box-shadow: 0 50px 100px rgba(0, 0, 0, 0.8);
  animation: s-02-slam 0.5s cubic-bezier(0.17, 0.89, 0.32, 1.2) both;
}.sv-scene-root-scene-02 [data-step="0"] .s-scene-02-card-container{
  opacity: 1;
}.sv-scene-root-scene-02 .s-scene-02-eyebrow{
  display: flex;
  align-items: center;
  gap: 10px;
  color: #F53501;
  font-family: var(--sv-font-mono);
  font-size: 14px;
  letter-spacing: 3px;
  margin-bottom: 20px;
}.sv-scene-root-scene-02 .s-scene-02-hero-text{
  font-family: var(--sv-font-display-cn);
  font-size: 120px;
  margin: 0;
  line-height: 0.9;
  letter-spacing: -2px;
  color: #FFFFFF;
  position: relative;
  overflow: hidden;
}.sv-scene-root-scene-02 /* Step 1 Letter Glow Stream Effect */
.s-scene-02-char-stream{
  position: relative;
  display: inline-block;
}.sv-scene-root-scene-02 [data-step="1"] .s-scene-02-char-stream::after{
  content: 'CACHING';
  position: absolute;
  left: 0;
  top: 0;
  color: #F53501;
  filter: blur(8px);
  animation: s-02-glow-flow 2s infinite linear;
  clip-path: inset(0 100% 0 0);
}.sv-scene-root-scene-02 .s-scene-02-footer-tag{
  margin-top: 30px;
  font-family: var(--sv-font-mono);
  font-size: 12px;
  color: rgba(255, 255, 255, 0.4);
  display: flex;
  align-items: center;
  gap: 8px;
}.sv-scene-root-scene-02 .s-scene-02-status-dot{
  width: 6px;
  height: 6px;
  background: #F53501;
  border-radius: 50%;
  box-shadow: 0 0 10px #F53501;
}.sv-scene-root-scene-02 .s-scene-02-annotation{
  position: absolute;
  bottom: -60px;
  right: -40px;
  display: flex;
  align-items: flex-start;
  gap: 15px;
  opacity: 0;
  transform: translateX(20px);
  transition: all 0.5s ease-out;
}.sv-scene-root-scene-02 [data-step="1"] .s-scene-02-annotation{
  opacity: 1;
  transform: translateX(0);
}.sv-scene-root-scene-02 .s-scene-02-flow-line{
  width: 1px;
  height: 80px;
  background: linear-gradient(to bottom, #F53501, transparent);
}.sv-scene-root-scene-02 .s-scene-02-data-info{
  display: flex;
  flex-direction: column;
  gap: 4px;
}.sv-scene-root-scene-02 .s-scene-02-label{
  font-size: 12px;
  color: rgba(255, 255, 255, 0.5);
  letter-spacing: 1px;
}.sv-scene-root-scene-02 .s-scene-02-value{
  font-family: var(--sv-font-display-cn);
  font-size: 36px;
  color: #F53501;
}@keyframes s-02-slam{
  0% {
    opacity: 0;
    transform: scale(1.5) translateZ(100px);
    filter: blur(20px);
  }
  70% {
    transform: scale(0.98) translateZ(0);
    filter: blur(0);
  }
  100% {
    opacity: 1;
    transform: scale(1) translateZ(0);
    filter: blur(0);
  }
}@keyframes s-02-glow-flow{
  0% { clip-path: inset(0 100% 0 0); opacity: 0; }
  20% { opacity: 1; }
  80% { opacity: 1; }
  100% { clip-path: inset(0 0 0 100%); opacity: 0; }
}

/* scene-03 */
.sv-scene-root-scene-03 .s-scene-03-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background: #1B1B1B;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #FFFFFF;
  font-family: var(--sv-font-body-cn);
}.sv-scene-root-scene-03 .s-scene-03-bg-grid{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
  background-size: 50px 50px;
  z-index: 1;
}.sv-scene-root-scene-03 .s-scene-03-ambient-glow{
  position: absolute;
  top: 50%;
  left: 50%;
  width: 600px;
  height: 400px;
  background: radial-gradient(circle, rgba(245, 53, 1, 0.05) 0%, transparent 70%);
  transform: translate(-50%, -50%);
  animation: s-03-pulse 8s infinite ease-in-out;
  z-index: 1;
}.sv-scene-root-scene-03 .s-scene-03-ghost-text{
  position: absolute;
  bottom: 5%;
  right: 5%;
  font-family: var(--sv-font-display-cn);
  font-size: 100px;
  opacity: 0.03;
  letter-spacing: -2px;
  z-index: 1;
}.sv-scene-root-scene-03 .s-scene-03-container{
  position: relative;
  z-index: 10;
  width: 80%;
  display: flex;
  flex-direction: column;
  gap: 60px;
}.sv-scene-root-scene-03 .s-scene-03-header{
  display: flex;
  flex-direction: column;
  gap: 10px;
}.sv-scene-root-scene-03 .s-scene-03-tag{
  display: flex;
  align-items: center;
  gap: 8px;
  color: #F53501;
  font-family: var(--sv-font-mono);
  font-size: 14px;
  letter-spacing: 2px;
}.sv-scene-root-scene-03 .s-scene-03-title{
  font-family: var(--sv-font-display-cn);
  font-size: 64px;
  margin: 0;
  color: #FFFFFF;
}.sv-scene-root-scene-03 .s-scene-03-sequence-area{
  position: relative;
  padding: 40px 0;
}.sv-scene-root-scene-03 .s-scene-03-token-list{
  display: flex;
  gap: 15px;
  align-items: center;
}.sv-scene-root-scene-03 .s-scene-03-token{
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 15px 30px;
  font-size: 32px;
  font-family: var(--sv-font-display-cn);
  border-radius: 4px;
  transition: all 0.5s cubic-bezier(0.22, 1, 0.36, 1);
  transform: translateY(20px);
  opacity: 0;
}.sv-scene-root-scene-03 [data-step="0"] .s-scene-03-token:not(.s-scene-03-slot){
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-03 .s-scene-03-slot{
  min-width: 100px;
  min-height: 70px;
  background: rgba(245, 53, 1, 0.05);
  border: 2px dashed #F53501;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}.sv-scene-root-scene-03 [data-step="1"] .s-scene-03-slot{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-03 .s-scene-03-token-new{
  color: #F53501;
  opacity: 0;
  transform: scale(0.5);
}.sv-scene-root-scene-03 [data-step="2"] .s-scene-03-token-new{
  opacity: 1;
  transform: scale(1);
  animation: s-03-spring 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
}.sv-scene-root-scene-03 .s-scene-03-cursor{
  position: absolute;
  width: 2px;
  height: 30px;
  background: #F53501;
  animation: s-03-blink 0.8s infinite step-end;
}.sv-scene-root-scene-03 [data-step="2"] .s-scene-03-cursor{
  display: none;
}.sv-scene-root-scene-03 .s-scene-03-arrow-svg{
  position: absolute;
  top: -40px;
  left: 0;
  width: 100%;
  height: 80px;
  pointer-events: none;
  opacity: 0;
}.sv-scene-root-scene-03 [data-step="1"] .s-scene-03-arrow-svg{
  opacity: 1;
}.sv-scene-root-scene-03 .s-scene-03-path-bg{
  fill: none;
  stroke: rgba(255, 255, 255, 0.1);
  stroke-width: 2;
}.sv-scene-root-scene-03 .s-scene-03-path-active{
  fill: none;
  stroke: #F53501;
  stroke-width: 2;
  stroke-dasharray: 400;
  stroke-dashoffset: 400;
  animation: s-03-draw 1.5s ease-out forwards;
}.sv-scene-root-scene-03 .s-scene-03-loop-indicator{
  position: absolute;
  top: 100px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 10px;
  color: #F53501;
  font-family: var(--sv-font-mono);
  font-size: 12px;
  opacity: 0;
}.sv-scene-root-scene-03 [data-step="3"] .s-scene-03-loop-indicator{
  opacity: 1;
  animation: s-03-fade-in 0.5s ease-out forwards;
}.sv-scene-root-scene-03 .s-scene-03-stats{
  display: flex;
  gap: 40px;
  opacity: 0;
  transform: translateY(10px);
  transition: all 0.5s ease-out 0.2s;
}.sv-scene-root-scene-03 [data-step="2"] .s-scene-03-stats{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-03 .s-scene-03-stat-item{
  display: flex;
  flex-direction: column;
  gap: 5px;
}.sv-scene-root-scene-03 .s-scene-03-stat-label{
  font-size: 12px;
  color: rgba(255, 255, 255, 0.4);
  letter-spacing: 1px;
}.sv-scene-root-scene-03 .s-scene-03-stat-value{
  font-family: var(--sv-font-mono);
  font-size: 24px;
  color: #F53501;
  font-variant-numeric: tabular-nums;
}@keyframes s-03-pulse{
  0%, 100% { opacity: 0.05; transform: translate(-50%, -50%) scale(1); }
  50% { opacity: 0.12; transform: translate(-50%, -50%) scale(1.1); }
}@keyframes s-03-blink{
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}@keyframes s-03-draw{
  to { stroke-dashoffset: 0; }
}@keyframes s-03-spring{
  0% { transform: scale(0.5); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}@keyframes s-03-fade-in{
  from { opacity: 0; transform: translate(-50%, -10px); }
  to { opacity: 1; transform: translate(-50%, 0); }
}

/* scene-04 */
.sv-scene-root-scene-04 .s-scene-04-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background: #1B1B1B;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #FFFFFF;
  font-family: var(--sv-font-body-cn);
}.sv-scene-root-scene-04 .s-scene-04-bg-grid{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
  background-size: 40px 40px;
  z-index: 1;
}.sv-scene-root-scene-04 .s-scene-04-ambient-glow{
  position: absolute;
  top: 50%;
  left: 60%;
  width: 800px;
  height: 600px;
  background: radial-gradient(circle, rgba(245, 53, 1, 0.08) 0%, transparent 70%);
  transform: translate(-50%, -50%);
  animation: s-04-pulse 10s infinite ease-in-out;
}.sv-scene-root-scene-04 .s-scene-04-ghost-text{
  position: absolute;
  top: 10%;
  left: 5%;
  font-family: var(--sv-font-display-cn);
  font-size: 120px;
  opacity: 0.04;
  letter-spacing: -4px;
  z-index: 1;
}.sv-scene-root-scene-04 .s-scene-04-container{
  position: relative;
  z-index: 10;
  width: 90%;
  max-width: 1200px;
  display: flex;
  flex-direction: column;
  gap: 40px;
}.sv-scene-root-scene-04 .s-scene-04-tag{
  display: flex;
  align-items: center;
  gap: 8px;
  color: #F53501;
  font-family: var(--sv-font-mono);
  font-size: 16px;
  letter-spacing: 2px;
  margin-bottom: 8px;
}.sv-scene-root-scene-04 .s-scene-04-title{
  font-family: var(--sv-font-display-cn);
  font-size: 56px;
  line-height: 1;
  margin: 0;
  color: #FFFFFF;
}.sv-scene-root-scene-04 .s-scene-04-stage{
  display: grid;
  grid-template-columns: 1fr 1.5fr 0.8fr;
  align-items: center;
  gap: 40px;
  height: 450px;
}.sv-scene-root-scene-04 /* Paper Stack */
.s-scene-04-source-area{
  display: flex;
  flex-direction: column;
  gap: 20px;
}.sv-scene-root-scene-04 .s-scene-04-label{
  font-family: var(--sv-font-mono);
  font-size: 14px;
  color: rgba(255, 255, 255, 0.5);
  border-left: 2px solid #F53501;
  padding-left: 12px;
}.sv-scene-root-scene-04 .s-scene-04-paper-stack{
  position: relative;
  height: 300px;
  width: 200px;
}.sv-scene-root-scene-04 .s-scene-04-paper{
  position: absolute;
  width: 100%;
  height: 240px;
  background: #2A2A2A;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--sv-font-mono);
  font-size: 12px;
  color: rgba(255, 255, 255, 0.4);
  box-shadow: 0 10px 30px rgba(0,0,0,0.5);
  transform: translateY(calc(var(--i) * -15px)) translateX(calc(var(--i) * 10px));
  transition: all 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}.sv-scene-root-scene-04 .s-scene-04-new-page{
  background: rgba(245, 53, 1, 0.1);
  border: 2px dashed #F53501;
  z-index: 10;
  transform: translateY(-60px) translateX(30px) scale(1.1);
  opacity: 0;
}.sv-scene-root-scene-04 [data-step="1"] .s-scene-04-new-page{
  opacity: 1;
  transform: translateY(-45px) translateX(30px) scale(1);
}.sv-scene-root-scene-04 .s-scene-04-highlight{
  color: #F53501;
  font-weight: bold;
  font-size: 18px;
}.sv-scene-root-scene-04 /* GPU & Mechanical Arm */
.s-scene-04-gpu-unit{
  position: relative;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}.sv-scene-root-scene-04 .s-scene-04-gpu-core{
  width: 180px;
  height: 180px;
  background: linear-gradient(135deg, #2A2A2A 0%, #1B1B1B 100%);
  border: 2px solid rgba(255,255,255,0.1);
  border-radius: 12px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 15px;
  z-index: 5;
  position: relative;
}.sv-scene-root-scene-04 .s-scene-04-gpu-icon{
  font-size: 64px;
  color: #F53501;
}.sv-scene-root-scene-04 .s-scene-04-core-label{
  font-family: var(--sv-font-mono);
  font-size: 14px;
  letter-spacing: 2px;
  color: rgba(255,255,255,0.8);
}.sv-scene-root-scene-04 .s-scene-04-mechanical-arm{
  position: absolute;
  width: 300px;
  height: 4px;
  background: #F53501;
  top: 50%;
  right: 50%;
  transform-origin: right center;
  z-index: 6;
  opacity: 0;
}.sv-scene-root-scene-04 [data-step="1"] .s-scene-04-mechanical-arm{
  opacity: 1;
  animation: s-04-scan-swing 1.5s infinite ease-in-out;
}.sv-scene-root-scene-04 .s-scene-04-scanner-head{
  position: absolute;
  left: 0;
  top: -20px;
  width: 40px;
  height: 40px;
  background: #F53501;
  border-radius: 4px;
}.sv-scene-root-scene-04 .s-scene-04-laser-beam{
  position: absolute;
  left: 20px;
  top: 40px;
  width: 2px;
  height: 200px;
  background: linear-gradient(to bottom, #F53501, transparent);
  box-shadow: 0 0 15px #F53501;
}.sv-scene-root-scene-04 /* Warning & Heat */
.s-scene-04-heat-ripples{
  position: absolute;
  inset: -20px;
  border: 2px solid #F53501;
  border-radius: 20px;
  opacity: 0;
  animation: s-04-heat 1s infinite;
}.sv-scene-root-scene-04 [data-step="2"] .s-scene-04-heat-ripples{
  opacity: 1;
}.sv-scene-root-scene-04 .s-scene-04-warning-icons{
  position: absolute;
  top: -40px;
  display: flex;
  gap: 20px;
}.sv-scene-root-scene-04 .s-scene-04-alert-icon{
  font-size: 32px;
  color: #F53501;
  animation: s-04-blink 0.5s infinite alternate;
}.sv-scene-root-scene-04 /* Stats */
.s-scene-04-stats-panel{
  display: flex;
  flex-direction: column;
  gap: 20px;
}.sv-scene-root-scene-04 .s-scene-04-stat-card{
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.1);
  padding: 20px;
  border-radius: 8px;
}.sv-scene-root-scene-04 .s-scene-04-stat-label{
  font-size: 12px;
  color: rgba(255,255,255,0.5);
  margin-bottom: 5px;
}.sv-scene-root-scene-04 .s-scene-04-stat-value{
  font-family: var(--sv-font-display-cn);
  font-size: 36px;
}.sv-scene-root-scene-04 .text-red{ color: #F53501; }.sv-scene-root-scene-04 /* Animations */
@keyframes s-04-pulse{
  0%, 100% { opacity: 0.08; transform: translate(-50%, -50%) scale(1); }
  50% { opacity: 0.15; transform: translate(-50%, -50%) scale(1.1); }
}@keyframes s-04-scan-swing{
  0% { transform: rotate(15deg); }
  50% { transform: rotate(-45deg); }
  100% { transform: rotate(15deg); }
}@keyframes s-04-heat{
  0% { transform: scale(1); opacity: 0.5; }
  100% { transform: scale(1.2); opacity: 0; }
}@keyframes s-04-blink{
  from { opacity: 1; transform: scale(1); }
  to { opacity: 0.5; transform: scale(0.9); }
}

/* scene-05 */
.sv-scene-root-scene-05 .s-scene-05-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background: #1B1B1B;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #FFFFFF;
  font-family: var(--sv-font-body-cn);
}.sv-scene-root-scene-05 .s-scene-05-bg-grid{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(245, 53, 1, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(245, 53, 1, 0.05) 1px, transparent 1px);
  background-size: 50px 50px;
  z-index: 1;
}.sv-scene-root-scene-05 .s-scene-05-ambient-glow{
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1200px;
  height: 800px;
  background: radial-gradient(circle, rgba(245, 53, 1, 0.05) 0%, transparent 70%);
  transform: translate(-50%, -50%);
  pointer-events: none;
}.sv-scene-root-scene-05 .s-scene-05-ghost-text{
  position: absolute;
  bottom: 5%;
  right: 5%;
  font-family: var(--sv-font-display-cn);
  font-size: 160px;
  opacity: 0.03;
  letter-spacing: -5px;
  z-index: 1;
  pointer-events: none;
}.sv-scene-root-scene-05 .s-scene-05-container{
  position: relative;
  z-index: 10;
  width: 90%;
  max-width: 1300px;
  display: flex;
  flex-direction: column;
  gap: 30px;
}.sv-scene-root-scene-05 .s-scene-05-tag{
  display: flex;
  align-items: center;
  gap: 8px;
  color: #F53501;
  font-family: var(--sv-font-mono);
  font-size: 14px;
  letter-spacing: 2px;
  margin-bottom: 8px;
}.sv-scene-root-scene-05 .s-scene-05-title{
  font-family: var(--sv-font-display-cn);
  font-size: 52px;
  line-height: 1;
  margin: 0;
  text-transform: uppercase;
}.sv-scene-root-scene-05 .s-scene-05-vault-stage{
  display: grid;
  grid-template-columns: 1fr 180px 1fr;
  gap: 20px;
  height: 480px;
  align-items: stretch;
}.sv-scene-root-scene-05 .s-scene-05-vault-column{
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}.sv-scene-root-scene-05 .s-scene-05-vault-header{
  padding: 15px 20px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: rgba(255, 255, 255, 0.02);
}.sv-scene-root-scene-05 .s-scene-05-vault-label{
  font-family: var(--sv-font-display-cn);
  font-size: 24px;
  color: #F53501;
}.sv-scene-root-scene-05 .s-scene-05-vault-status{
  font-family: var(--sv-font-mono);
  font-size: 12px;
  padding: 4px 8px;
  border: 1px solid rgba(245, 53, 1, 0.4);
  border-radius: 4px;
  color: #F53501;
}.sv-scene-root-scene-05 .s-scene-05-grid-container{
  flex: 1;
  padding: 20px;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  overflow: hidden;
}.sv-scene-root-scene-05 .s-scene-05-grid{
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 8px;
  width: 100%;
}.sv-scene-root-scene-05 .s-scene-05-data-block{
  aspect-ratio: 1;
  background: rgba(245, 53, 1, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 2px;
  opacity: 0;
  transform: scale(0.8);
}.sv-scene-root-scene-05 .s-scene-05-data-block.active{
  opacity: 1;
  transform: scale(1);
  background: #F53501;
  box-shadow: 0 0 15px rgba(245, 53, 1, 0.5);
  border-color: #FFFFFF;
  transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}.sv-scene-root-scene-05 .s-scene-05-center-interface{
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: scale(0.9);
  transition: all 0.5s ease-out;
}.sv-scene-root-scene-05 [data-step="2"] .s-scene-05-center-interface{
  opacity: 1;
  transform: scale(1);
}.sv-scene-root-scene-05 .s-scene-05-save-ring{
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 15px;
}.sv-scene-root-scene-05 .s-scene-05-save-icon-wrap{
  width: 80px;
  height: 80px;
  background: #F53501;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
}.sv-scene-root-scene-05 .s-scene-05-save-icon{
  font-size: 40px;
  color: #FFFFFF;
}.sv-scene-root-scene-05 .s-scene-05-save-pulse{
  position: absolute;
  top: 0;
  left: 0;
  width: 80px;
  height: 80px;
  border: 2px solid #F53501;
  border-radius: 50%;
  animation: s-05-pulse 1.5s infinite;
}.sv-scene-root-scene-05 .s-scene-05-save-text{
  font-family: var(--sv-font-mono);
  font-size: 14px;
  color: #F53501;
  letter-spacing: 2px;
  font-weight: bold;
}.sv-scene-root-scene-05 .s-scene-05-footer-specs{
  display: flex;
  gap: 40px;
  padding-top: 20px;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  opacity: 0;
  transform: translateY(20px);
  transition: all 0.5s 0.2s;
}.sv-scene-root-scene-05 [data-step="1"] .s-scene-05-footer-specs{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-05 .s-scene-05-spec-item{
  display: flex;
  flex-direction: column;
  gap: 4px;
}.sv-scene-root-scene-05 .s-scene-05-spec-name{
  font-family: var(--sv-font-mono);
  font-size: 12px;
  color: rgba(255, 255, 255, 0.4);
}.sv-scene-root-scene-05 .s-scene-05-spec-value{
  font-family: var(--sv-font-display-cn);
  font-size: 32px;
}.sv-scene-root-scene-05 .text-gold{ color: #F53501; }@keyframes s-05-pulse{
  0% { transform: scale(1); opacity: 0.8; }
  100% { transform: scale(2.2); opacity: 0; }
}.sv-scene-root-scene-05 /* Desktop specific layout tweaks */
@media (min-width: 1024px){
  .s-scene-05-vault-stage {
     padding: 0 40px;
  }
}

/* scene-06 */
.sv-scene-root-scene-06 .s-scene-06-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background: #1B1B1B;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #FFFFFF;
  font-family: var(--sv-font-body-cn);
}.sv-scene-root-scene-06 .s-scene-06-bg-grid{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(245, 53, 1, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(245, 53, 1, 0.05) 1px, transparent 1px);
  background-size: 60px 60px;
  z-index: 1;
}.sv-scene-root-scene-06 .s-scene-06-ghost-text{
  position: absolute;
  top: 10%;
  left: 5%;
  font-family: var(--sv-font-display-cn);
  font-size: 120px;
  opacity: 0.03;
  letter-spacing: -2px;
  pointer-events: none;
  z-index: 1;
}.sv-scene-root-scene-06 .s-scene-06-ambient-glow{
  position: absolute;
  width: 800px;
  height: 800px;
  background: radial-gradient(circle, rgba(245, 53, 1, 0.08) 0%, transparent 70%);
  filter: blur(60px);
  animation: s-06-float 15s infinite ease-in-out;
}.sv-scene-root-scene-06 .s-scene-06-container{
  position: relative;
  z-index: 10;
  width: 90%;
  max-width: 1200px;
}.sv-scene-root-scene-06 .s-scene-06-header{
  margin-bottom: 40px;
}.sv-scene-root-scene-06 .s-scene-06-tag{
  display: flex;
  align-items: center;
  gap: 8px;
  color: #F53501;
  font-family: var(--sv-font-mono);
  font-size: 14px;
  letter-spacing: 2px;
  margin-bottom: 8px;
}.sv-scene-root-scene-06 .s-scene-06-title{
  font-family: var(--sv-font-display-cn);
  font-size: 56px;
  margin: 0;
  line-height: 1;
  text-transform: uppercase;
}.sv-scene-root-scene-06 .s-scene-06-stage{
  display: grid;
  grid-template-columns: 1.2fr 0.8fr;
  gap: 60px;
  align-items: center;
}.sv-scene-root-scene-06 .s-scene-06-counter{
  position: relative;
  height: 400px;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid rgba(255, 255, 255, 0.05);
  border-radius: 12px;
  perspective: 1000px;
  display: flex;
  justify-content: center;
  align-items: center;
}.sv-scene-root-scene-06 .s-scene-06-iso-group{
  display: flex;
  gap: 20px;
  transform: rotateX(45deg) rotateZ(-20deg);
}.sv-scene-root-scene-06 .s-scene-06-container-box{
  position: relative;
  width: 100px;
  height: 100px;
  background: rgba(245, 53, 1, 0.1);
  border: 2px solid #F53501;
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
  transition-delay: calc(var(--offset) * 0.1s);
}.sv-scene-root-scene-06 .s-scene-06-label{
  font-family: var(--sv-font-mono);
  font-size: 10px;
  color: #F53501;
  position: absolute;
  top: -25px;
  white-space: nowrap;
  background: rgba(0,0,0,0.5);
  padding: 2px 6px;
}.sv-scene-root-scene-06 .s-scene-06-cube{
  width: 40px;
  height: 40px;
  background: #F53501;
  box-shadow: 0 0 20px rgba(245, 53, 1, 0.4);
  transform: translateZ(20px);
}.sv-scene-root-scene-06 .s-scene-06-cooking-area{
  position: absolute;
  right: 15%;
  bottom: 20%;
  display: flex;
  flex-direction: column;
  align-items: center;
}.sv-scene-root-scene-06 .s-scene-06-pot-icon{
  font-size: 100px;
  color: #FFFFFF;
  filter: drop-shadow(0 0 15px rgba(255,255,255,0.2));
}.sv-scene-root-scene-06 .s-scene-06-chef-arm{
  position: absolute;
  top: -80px;
  right: -50px;
  font-size: 60px;
  color: #F53501;
  opacity: 0;
}.sv-scene-root-scene-06 [data-step="1"] .s-scene-06-chef-arm{
  opacity: 1;
  animation: s-06-grab 1.2s infinite ease-in-out;
}.sv-scene-root-scene-06 .s-scene-06-status-overlay{
  position: absolute;
  inset: 0;
  background: rgba(27, 27, 27, 0.8);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(8px);
  z-index: 20;
}.sv-scene-root-scene-06 .s-scene-06-checkmark-circle{
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background: #F53501;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 60px;
  margin-bottom: 20px;
  box-shadow: 0 0 40px rgba(245, 53, 1, 0.4);
  animation: s-06-pop 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}.sv-scene-root-scene-06 .s-scene-06-status-text{
  font-family: var(--sv-font-display-cn);
  font-size: 32px;
  letter-spacing: 2px;
}.sv-scene-root-scene-06 .s-scene-06-info-panel{
  display: flex;
  flex-direction: column;
  gap: 30px;
}.sv-scene-root-scene-06 .s-scene-06-metric{
  border-left: 4px solid #F53501;
  padding-left: 20px;
}.sv-scene-root-scene-06 .s-scene-06-metric-label{
  font-family: var(--sv-font-mono);
  font-size: 14px;
  color: rgba(255, 255, 255, 0.5);
  display: block;
}.sv-scene-root-scene-06 .s-scene-06-metric-value{
  font-family: var(--sv-font-display-cn);
  font-size: 64px;
  color: #F53501;
  line-height: 1;
}.sv-scene-root-scene-06 .s-scene-06-progress-bar{
  width: 100%;
  height: 4px;
  background: rgba(255, 255, 255, 0.1);
  margin-top: 10px;
}.sv-scene-root-scene-06 .s-scene-06-progress-fill{
  width: 0%;
  height: 100%;
  background: #F53501;
  transition: width 1s ease-out;
}.sv-scene-root-scene-06 [data-step="1"] .s-scene-06-progress-fill{
  width: 90%;
}.sv-scene-root-scene-06 .s-scene-06-quote{
  font-size: 20px;
  line-height: 1.5;
  opacity: 0.8;
  font-style: italic;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  padding-top: 20px;
}.sv-scene-root-scene-06 /* Animations */
@keyframes s-06-float{
  0%, 100% { transform: translate(-20%, -20%) scale(1); }
  50% { transform: translate(-10%, -10%) scale(1.1); }
}@keyframes s-06-grab{
  0% { transform: translate(0, 0) rotate(0deg); }
  30% { transform: translate(-150px, 80px) rotate(-20deg); }
  60% { transform: translate(-150px, 80px) rotate(-20deg) scale(0.9); }
  100% { transform: translate(0, 0) rotate(0deg); }
}@keyframes s-06-pop{
  0% { transform: scale(0); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}.sv-scene-root-scene-06 [data-step]{
  transition: all 0.5s ease-out;
  opacity: 0;
  transform: translateY(20px);
}.sv-scene-root-scene-06 [data-step].active{
  opacity: 1;
  transform: translateY(0);
}

/* scene-07 */
.sv-scene-root-scene-07 .s-scene-07-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background: #1B1B1B;
  overflow: hidden;
  color: #FFFFFF;
  font-family: var(--sv-font-body-cn);
  display: flex;
  align-items: center;
  justify-content: center;
}.sv-scene-root-scene-07 .s-scene-07-bg-grid{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(245, 53, 1, 0.05) 1px, transparent 1px), 
                    linear-gradient(90deg, rgba(245, 53, 1, 0.05) 1px, transparent 1px);
  background-size: 50px 50px;
  z-index: 1;
}.sv-scene-root-scene-07 .s-scene-07-ambient-glow{
  position: absolute;
  width: 120%;
  height: 120%;
  background: radial-gradient(circle at 70% 30%, rgba(245, 53, 1, 0.08) 0%, transparent 60%);
  z-index: 2;
  animation: s-07-glow-pulse 10s infinite ease-in-out;
}.sv-scene-root-scene-07 .s-scene-07-ghost-text{
  position: absolute;
  bottom: 5%;
  right: 5%;
  font-family: var(--sv-font-display-cn);
  font-size: 80px;
  color: #FFFFFF;
  opacity: 0.04;
  pointer-events: none;
}.sv-scene-root-scene-07 .s-scene-07-main{
  position: relative;
  z-index: 10;
  width: 90%;
  max-width: 1200px;
  height: 80%;
  display: grid;
  grid-template-columns: 1fr 300px;
  grid-template-rows: auto 1fr;
  gap: 40px;
}.sv-scene-root-scene-07 .s-scene-07-header{
  grid-column: 1 / -1;
}.sv-scene-root-scene-07 .s-scene-07-badge{
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: rgba(245, 53, 1, 0.1);
  border: 1px solid #F53501;
  color: #F53501;
  padding: 4px 12px;
  font-family: var(--sv-font-mono);
  font-size: 14px;
  margin-bottom: 12px;
}.sv-scene-root-scene-07 .s-scene-07-title{
  font-family: var(--sv-font-display-cn);
  font-size: 64px;
  margin: 0;
  text-transform: uppercase;
  letter-spacing: -1px;
}.sv-scene-root-scene-07 .s-scene-07-canvas{
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 40px;
}.sv-scene-root-scene-07 /* Document Card */
.s-scene-07-doc-card{
  position: relative;
  width: 200px;
  height: 260px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 4px;
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 15px;
  box-shadow: 0 20px 40px rgba(0,0,0,0.4);
  z-index: 5;
}.sv-scene-root-scene-07 .s-scene-07-doc-icon{ font-size: 40px; color: #F53501; }.sv-scene-root-scene-07 .s-scene-07-doc-label{
  font-family: var(--sv-font-mono);
  font-size: 12px;
  opacity: 0.6;
}.sv-scene-root-scene-07 .s-scene-07-doc-lines .s-scene-07-line{
  height: 4px;
  background: rgba(255,255,255,0.1);
  margin-bottom: 8px;
  border-radius: 2px;
}.sv-scene-root-scene-07 .s-scene-07-line.width-short{ width: 60%; }.sv-scene-root-scene-07 /* Step 1: Frost/Lock */
.s-scene-07-lock-overlay{
  position: absolute;
  inset: 0;
  background: rgba(180, 220, 255, 0.15);
  backdrop-filter: blur(4px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: scale(1.1);
  transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
  border: 2px solid #50a3ff;
}.sv-scene-root-scene-07 [data-step="1"].active .s-scene-07-lock-overlay{
  opacity: 1;
  transform: scale(1);
}.sv-scene-root-scene-07 .s-scene-07-ice-icon{
  font-size: 60px;
  color: #50a3ff;
  filter: drop-shadow(0 0 10px rgba(80, 163, 255, 0.5));
  animation: s-07-rotate 10s linear infinite;
}.sv-scene-root-scene-07 .s-scene-07-lock-tag{
  font-family: var(--sv-font-mono);
  font-size: 12px;
  color: #50a3ff;
  margin-top: 10px;
  font-weight: bold;
}.sv-scene-root-scene-07 /* Step 2: Connections */
.s-scene-07-chats-grid{
  display: flex;
  gap: 60px;
  margin-top: 80px;
  width: 100%;
  justify-content: center;
}.sv-scene-root-scene-07 .s-scene-07-chat-node{
  position: relative;
  opacity: 0;
  transform: translateY(20px);
  transition: all 0.5s ease-out;
  transition-delay: calc(var(--i) * 0.15s);
}.sv-scene-root-scene-07 [data-step="2"].active .s-scene-07-chat-node{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-07 .s-scene-07-link-line{
  position: absolute;
  top: -80px;
  left: 50%;
  width: 2px;
  height: 80px;
  background: linear-gradient(to bottom, #50a3ff, transparent);
  transform: translateX(-50%);
}.sv-scene-root-scene-07 .s-scene-07-bubble{
  background: #252525;
  border: 1px solid rgba(255,255,255,0.1);
  padding: 12px 20px;
  border-radius: 30px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--sv-font-mono);
  font-size: 14px;
  box-shadow: 0 10px 20px rgba(0,0,0,0.3);
}.sv-scene-root-scene-07 .s-scene-07-bubble iconify-icon{
  color: #F53501;
}.sv-scene-root-scene-07 /* Side Panel */
.s-scene-07-side-info{
  display: flex;
  flex-direction: column;
  gap: 30px;
  border-left: 1px solid rgba(255,255,255,0.1);
  padding-left: 30px;
}.sv-scene-root-scene-07 .s-scene-07-stat-block{
  padding: 20px;
  background: rgba(245, 53, 1, 0.03);
  border-radius: 8px;
}.sv-scene-root-scene-07 .s-scene-07-stat-label{
  font-size: 12px;
  font-family: var(--sv-font-mono);
  opacity: 0.5;
  display: block;
}.sv-scene-root-scene-07 .s-scene-07-stat-value{
  font-size: 40px;
  font-family: var(--sv-font-display-cn);
  color: #F53501;
}.sv-scene-root-scene-07 .s-scene-07-status-indicator{
  width: 100%;
  height: 4px;
  background: #F53501;
  margin-top: 10px;
  box-shadow: 0 0 10px #F53501;
}.sv-scene-root-scene-07 .s-scene-07-desc{
  font-size: 18px;
  line-height: 1.6;
  color: rgba(255,255,255,0.7);
}.sv-scene-root-scene-07 /* Animation Keyframes */
@keyframes s-07-glow-pulse{
  0%, 100% { opacity: 0.5; }
  50% { opacity: 1; }
}@keyframes s-07-rotate{
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}.sv-scene-root-scene-07 [data-step]{
  transition: all 0.6s cubic-bezier(0.22, 1, 0.36, 1);
  opacity: 0;
  transform: translateY(30px);
}.sv-scene-root-scene-07 [data-step].active{
  opacity: 1;
  transform: translateY(0);
}

/* scene-08 */
.sv-scene-root-scene-08 .s-scene-08-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background: #1B1B1B;
  overflow: hidden;
  color: #FFFFFF;
  font-family: var(--sv-font-body-cn);
  display: flex;
  align-items: center;
  justify-content: center;
}.sv-scene-root-scene-08 .s-scene-08-bg-grid{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(245, 53, 1, 0.05) 1px, transparent 1px), 
                    linear-gradient(90deg, rgba(245, 53, 1, 0.05) 1px, transparent 1px);
  background-size: 40px 40px;
  z-index: 1;
}.sv-scene-root-scene-08 .s-scene-08-ambient-glow{
  position: absolute;
  width: 100%;
  height: 100%;
  background: radial-gradient(circle at 80% 20%, rgba(245, 53, 1, 0.1) 0%, transparent 50%);
  z-index: 2;
  animation: s-08-glow 8s infinite alternate ease-in-out;
}.sv-scene-root-scene-08 .s-scene-08-ghost-text{
  position: absolute;
  top: 10%;
  left: 5%;
  font-family: var(--sv-font-display-cn);
  font-size: 120px;
  color: #FFFFFF;
  opacity: 0.03;
  pointer-events: none;
  letter-spacing: -2px;
}.sv-scene-root-scene-08 .s-scene-08-main{
  position: relative;
  z-index: 10;
  width: 85%;
  max-width: 1100px;
  display: flex;
  flex-direction: column;
  gap: 60px;
}.sv-scene-root-scene-08 .s-scene-08-badge{
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: rgba(245, 53, 1, 0.1);
  border-left: 3px solid #F53501;
  color: #F53501;
  padding: 6px 16px;
  font-family: var(--sv-font-mono);
  font-size: 14px;
  margin-bottom: 15px;
}.sv-scene-root-scene-08 .s-scene-08-title{
  font-family: var(--sv-font-display-cn);
  font-size: 72px;
  margin: 0;
  text-transform: uppercase;
  line-height: 1;
}.sv-scene-root-scene-08 .s-scene-08-content{
  display: grid;
  grid-template-columns: 1.2fr 0.8fr;
  gap: 50px;
  align-items: center;
}.sv-scene-root-scene-08 .s-scene-08-chart-container{
  display: flex;
  flex-direction: column;
  gap: 40px;
}.sv-scene-root-scene-08 .s-scene-08-bar-group{
  width: 100%;
}.sv-scene-root-scene-08 .s-scene-08-bar-info{
  display: flex;
  justify-content: space-between;
  margin-bottom: 12px;
  font-family: var(--sv-font-mono);
  font-size: 16px;
}.sv-scene-root-scene-08 .s-scene-08-bar-label{
  opacity: 0.7;
}.sv-scene-root-scene-08 .s-scene-08-bar-value{
  font-weight: bold;
  font-variant-numeric: tabular-nums;
}.sv-scene-root-scene-08 .s-scene-08-bar-track{
  height: 40px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.1);
  position: relative;
  overflow: hidden;
}.sv-scene-root-scene-08 .s-scene-08-bar-fill{
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  width: 0%;
  background: #FFFFFF;
  transition: width 3s linear;
}.sv-scene-root-scene-08 [data-type="cached"] .s-scene-08-bar-fill{
  background: #F53501;
  box-shadow: 0 0 20px rgba(245, 53, 1, 0.4);
  transition: width 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}.sv-scene-root-scene-08 /* Impact Card */
.s-scene-08-impact-zone{
  opacity: 0;
  transform: translateX(40px);
  transition: all 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}.sv-scene-root-scene-08 .s-scene-08-impact-zone.active{
  opacity: 1;
  transform: translateX(0);
}.sv-scene-root-scene-08 .s-scene-08-impact-card{
  background: #F53501;
  padding: 40px;
  position: relative;
  text-align: center;
}.sv-scene-root-scene-08 .s-scene-08-impact-title{
  font-family: var(--sv-font-mono);
  font-size: 18px;
  color: #1B1B1B;
  font-weight: 900;
  margin-bottom: 5px;
}.sv-scene-root-scene-08 .s-scene-08-impact-stat{
  font-family: var(--sv-font-display-cn);
  font-size: 64px;
  color: #FFFFFF;
  line-height: 1;
}.sv-scene-root-scene-08 .s-scene-08-impact-line{
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 6px;
  background: #FFFFFF;
  transform: scaleX(0);
  transition: transform 0.8s ease 0.4s;
  transform-origin: left;
}.sv-scene-root-scene-08 .s-scene-08-impact-zone.active .s-scene-08-impact-line{
  transform: scaleX(1);
}.sv-scene-root-scene-08 /* Particles */
.s-scene-08-burst-container{
  position: absolute;
  inset: 0;
  pointer-events: none;
}.sv-scene-root-scene-08 .s-scene-08-particle{
  position: absolute;
  width: 10px;
  height: 10px;
  background: #F53501;
  top: 50%;
  left: 50%;
  opacity: 0;
}.sv-scene-root-scene-08 .active .s-scene-08-particle{
  animation: s-08-burst 0.8s ease-out forwards;
}.sv-scene-root-scene-08 .s-scene-08-footer{
  display: flex;
  gap: 40px;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  padding-top: 30px;
}.sv-scene-root-scene-08 .s-scene-08-metric{
  display: flex;
  flex-direction: column;
}.sv-scene-root-scene-08 .s-scene-08-m-label{
  font-family: var(--sv-font-mono);
  font-size: 12px;
  opacity: 0.5;
}.sv-scene-root-scene-08 .s-scene-08-m-val{
  font-size: 24px;
  font-weight: bold;
  color: #F53501;
}@keyframes s-08-glow{
  from { opacity: 0.5; transform: scale(1); }
  to { opacity: 1; transform: scale(1.1); }
}@keyframes s-08-burst{
  0% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
  100% { transform: translate(calc(-50% + var(--tx)), calc(-50% + var(--ty))) scale(0); opacity: 0; }
}.sv-scene-root-scene-08 .s-scene-08-particle:nth-child(1){ --tx: -100px; --ty: -80px; }.sv-scene-root-scene-08 .s-scene-08-particle:nth-child(2){ --tx: 100px; --ty: -80px; }.sv-scene-root-scene-08 .s-scene-08-particle:nth-child(3){ --tx: -80px; --ty: 80px; }.sv-scene-root-scene-08 .s-scene-08-particle:nth-child(4){ --tx: 80px; --ty: 80px; }

/* scene-09 */
.sv-scene-root-scene-09 .s-scene-09-wrapper{
  position: relative;
  width: 100%;
  height: 100%;
  background: #1B1B1B;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #FFFFFF;
  font-family: var(--sv-font-body-cn);
}.sv-scene-root-scene-09 /* Background Decor */
.s-scene-09-bg-grid{
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(245, 53, 1, 0.05) 1px, transparent 1px), 
                    linear-gradient(90deg, rgba(245, 53, 1, 0.05) 1px, transparent 1px);
  background-size: 50px 50px;
  z-index: 1;
}.sv-scene-root-scene-09 .s-scene-09-ambient-glow{
  position: absolute;
  width: 800px;
  height: 800px;
  background: radial-gradient(circle, rgba(245, 53, 1, 0.1) 0%, transparent 70%);
  z-index: 2;
  animation: s-09-pulse 10s infinite alternate ease-in-out;
}.sv-scene-root-scene-09 .s-scene-09-ghost-text{
  position: absolute;
  bottom: 5%;
  right: 5%;
  font-family: var(--sv-font-display-cn);
  font-size: 140px;
  color: #FFFFFF;
  opacity: 0.03;
  pointer-events: none;
  line-height: 1;
}.sv-scene-root-scene-09 /* Main Layout */
.s-scene-09-container{
  position: relative;
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
}.sv-scene-root-scene-09 /* Brain Icon Core */
.s-scene-09-circuit-brain{
  position: relative;
  width: 200px;
  height: 200px;
  display: flex;
  align-items: center;
  justify-content: center;
}.sv-scene-root-scene-09 .s-scene-09-brain-icon{
  font-size: 120px;
  color: #F53501;
  filter: drop-shadow(0 0 20px rgba(245, 53, 1, 0.6));
  animation: s-09-float 4s infinite ease-in-out;
  z-index: 5;
}.sv-scene-root-scene-09 .s-scene-09-ring{
  position: absolute;
  border: 1px solid rgba(245, 53, 1, 0.3);
  border-radius: 50%;
  z-index: 1;
}.sv-scene-root-scene-09 .s-scene-09-ring-1{
  width: 240px;
  height: 240px;
  animation: s-09-spin 12s linear infinite;
  border-style: dashed;
}.sv-scene-root-scene-09 .s-scene-09-ring-2{
  width: 300px;
  height: 300px;
  animation: s-09-spin 20s linear infinite reverse;
  opacity: 0.5;
}.sv-scene-root-scene-09 /* Text Zone */
.s-scene-09-text-zone{
  text-align: center;
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.8s cubic-bezier(0.22, 1, 0.36, 1);
}.sv-scene-root-scene-09 .s-scene-09-text-zone.active{
  opacity: 1;
  transform: translateY(0);
}.sv-scene-root-scene-09 .s-scene-09-hero-title{
  font-family: var(--sv-font-display-cn);
  font-size: 96px;
  margin: 0;
  letter-spacing: 4px;
  color: #FFFFFF;
  text-shadow: 0 10px 30px rgba(0,0,0,0.5);
}.sv-scene-root-scene-09 .s-scene-09-subtitle-bar{
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
  margin-top: 10px;
}.sv-scene-root-scene-09 .s-scene-09-tag{
  font-family: var(--sv-font-mono);
  font-size: 16px;
  color: #F53501;
  letter-spacing: 2px;
}.sv-scene-root-scene-09 .s-scene-09-line{
  width: 40px;
  height: 2px;
  background: rgba(255, 255, 255, 0.2);
}.sv-scene-root-scene-09 /* Light Rays (Step 2) */
.s-scene-09-rays-container{
  position: absolute;
  inset: -100px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1s ease;
}.sv-scene-root-scene-09 .s-scene-09-rays-container.active{
  opacity: 1;
}.sv-scene-root-scene-09 .s-scene-09-ray{
  position: absolute;
  top: 50%;
  left: 50%;
  width: 2px;
  height: 400px;
  background: linear-gradient(to top, #F53501, transparent);
  transform-origin: bottom center;
  opacity: 0.4;
}.sv-scene-root-scene-09 /* Ray Positioning */
.s-scene-09-ray:nth-child(1){ transform: translate(-50%, -100%) rotate(0deg); }.sv-scene-root-scene-09 .s-scene-09-ray:nth-child(2){ transform: translate(-50%, -100%) rotate(45deg); }.sv-scene-root-scene-09 .s-scene-09-ray:nth-child(3){ transform: translate(-50%, -100%) rotate(90deg); }.sv-scene-root-scene-09 .s-scene-09-ray:nth-child(4){ transform: translate(-50%, -100%) rotate(135deg); }.sv-scene-root-scene-09 .s-scene-09-ray:nth-child(5){ transform: translate(-50%, -100%) rotate(180deg); }.sv-scene-root-scene-09 .s-scene-09-ray:nth-child(6){ transform: translate(-50%, -100%) rotate(225deg); }.sv-scene-root-scene-09 .s-scene-09-ray:nth-child(7){ transform: translate(-50%, -100%) rotate(270deg); }.sv-scene-root-scene-09 .s-scene-09-ray:nth-child(8){ transform: translate(-50%, -100%) rotate(315deg); }.sv-scene-root-scene-09 /* UI Corners */
.s-scene-09-corner{
  position: absolute;
  font-family: var(--sv-font-mono);
  font-size: 12px;
  color: rgba(255, 255, 255, 0.3);
  padding: 20px;
}.sv-scene-root-scene-09 .s-scene-09-tl{ top: 0; left: 0; border-left: 2px solid #F53501; }.sv-scene-root-scene-09 .s-scene-09-br{ bottom: 0; right: 0; border-right: 2px solid #F53501; }.sv-scene-root-scene-09 /* Animations */
@keyframes s-09-pulse{
  from { transform: scale(1); opacity: 0.1; }
  to { transform: scale(1.2); opacity: 0.2; }
}@keyframes s-09-float{
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-10px); }
}@keyframes s-09-spin{
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
  </style>
</head>
<body data-orientation="landscape">
  <div id="app">
    <div id="viewport">
      <div id="stage">

<section class="scene" data-scene-id="scene-01">
  <div class="sv-scene-root sv-scene-root-scene-01" data-scene-root-id="scene-01">
<div class="s-scene-01-container">
  <!-- Background Ambient Layer -->
  <div class="s-scene-01-bg-grid"></div>
  <div class="s-scene-01-ambient-glow"></div>
  <div class="s-scene-01-ghost-text">LATENCY</div>

  <!-- Main Content Area -->
  <div class="s-scene-01-content">
    <div class="s-scene-01-header" data-step="0">
      <div class="s-scene-01-tag"><span class="s-scene-01-dot"></span> SYSTEM STATUS</div>
      <h1 class="s-scene-01-title">THE THINKING PROCESS</h1>
    </div>

    <!-- Terminal Window -->
    <div class="s-scene-01-terminal" data-step="0">
      <div class="s-scene-01-terminal-bar">
        <div class="s-scene-01-terminal-btns">
          <span></span><span></span><span></span>
        </div>
        <div class="s-scene-01-terminal-tab">AI_QUERY_LOG</div>
      </div>
      
      <div class="s-scene-01-terminal-body">
        <div class="s-scene-01-line">
          <span class="s-scene-01-prompt">User:</span>
          <span class="s-scene-01-typewriter" data-step="1">Explain Quantum Physics...</span>
          <span class="s-scene-01-cursor"></span>
        </div>
        
        <div class="s-scene-01-thinking" data-step="2">
          <span class="s-scene-01-thinking-label">AI is processing</span>
          <div class="s-scene-01-dots">
            <span></span><span></span><span></span>
          </div>
        </div>
      </div>
    </div>

    <!-- Annotation Label -->
    <div class="s-scene-01-annotation" data-step="2">
      <div class="s-scene-01-line-pointer"></div>
      <div class="s-scene-01-anno-content">
        <div class="s-scene-01-anno-tag">LATENCY ANALYSIS</div>
        <div class="s-scene-01-anno-value">350ms - 1200ms</div>
      </div>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-02">
  <div class="sv-scene-root sv-scene-root-scene-02" data-scene-root-id="scene-02">
<div class="s-scene-02-wrapper">
  <!-- Ambient Background Layer -->
  <div class="s-scene-02-bg-grid"></div>
  <div class="s-scene-02-nodes" id="scene-02-nodes-canvas"></div>
  <div class="s-scene-02-ghost-text">OPTIMIZATION</div>

  <!-- Main Hero Card Area -->
  <div class="s-scene-02-main">
    <div class="s-scene-02-card-container" data-step="0">
      <div class="s-scene-02-glitch-border"></div>
      <div class="s-scene-02-content-box">
        <div class="s-scene-02-eyebrow">
          <i data-lucide="zap"></i> PERFORMANCE CORE
        </div>
        <h1 class="s-scene-02-hero-text">
          <span class="s-scene-02-char-stream">CACHING</span>
        </h1>
        <div class="s-scene-02-footer-tag">
          <span class="s-scene-02-status-dot"></span>
          SYSTEM ACCELERATED
        </div>
      </div>
    </div>

    <!-- Data Flow Annotation -->
    <div class="s-scene-02-annotation" data-step="1">
      <div class="s-scene-02-flow-line"></div>
      <div class="s-scene-02-data-info">
        <span class="s-scene-02-label">LATENCY REDUCTION</span>
        <span class="s-scene-02-value">95.4%</span>
      </div>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-03">
  <div class="sv-scene-root sv-scene-root-scene-03" data-scene-root-id="scene-03">
<div class="s-scene-03-wrapper">
  <!-- Ambient Background Layer -->
  <div class="s-scene-03-bg-grid"></div>
  <div class="s-scene-03-ghost-text">AUTOREGRESSIVE</div>
  <div class="s-scene-03-ambient-glow"></div>

  <!-- Main Content Area -->
  <div class="s-scene-03-container">
    <!-- Header Label -->
    <div class="s-scene-03-header">
      <div class="s-scene-03-tag">
        <i data-lucide="refresh-cw"></i> NEXT TOKEN PREDICTION
      </div>
      <h2 class="s-scene-03-title">SEQUENCE GENERATION</h2>
    </div>

    <!-- The Token Sequence Track -->
    <div class="s-scene-03-sequence-area">
      <div class="s-scene-03-token-list">
        <div class="s-scene-03-token" data-step="0">The</div>
        <div class="s-scene-03-token" data-step="0">cat</div>
        <div class="s-scene-03-token" data-step="0">sat</div>
        <!-- The slot for the next token -->
        <div class="s-scene-03-token s-scene-03-slot" data-step="1">
          <div class="s-scene-03-token-new" data-step="2">on</div>
          <div class="s-scene-03-cursor" data-step="1"></div>
        </div>
      </div>

      <!-- Logic Indicators -->
      <div class="s-scene-03-logic-overlay">
        <!-- Arrow from sequence to slot -->
        <svg class="s-scene-03-arrow-svg" data-step="1" viewBox="0 0 400 60">
          <path d="M20,30 Q180,60 340,30" class="s-scene-03-path-bg" />
          <path d="M20,30 Q180,60 340,30" class="s-scene-03-path-active" />
          <polygon points="340,30 330,25 330,35" fill="#F53501" />
        </svg>

        <div class="s-scene-03-loop-indicator" data-step="3">
          <i data-lucide="repeat"></i>
          <span>RECURSIVE LOOP ACTIVE</span>
        </div>
      </div>
    </div>

    <!-- Technical Stats -->
    <div class="s-scene-03-stats" data-step="2">
      <div class="s-scene-03-stat-item">
        <span class="s-scene-03-stat-label">PROBABILITY</span>
        <span class="s-scene-03-stat-value">0.982</span>
      </div>
      <div class="s-scene-03-stat-item">
        <span class="s-scene-03-stat-label">CONTEXT WINDOW</span>
        <span class="s-scene-03-stat-value">ACTIVE</span>
      </div>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-04">
  <div class="sv-scene-root sv-scene-root-scene-04" data-scene-root-id="scene-04">
<div class="s-scene-04-wrapper">
  <!-- Ambient Background Layer -->
  <div class="s-scene-04-bg-grid"></div>
  <div class="s-scene-04-ghost-text">INEFFICIENT</div>
  <div class="s-scene-04-ambient-glow"></div>

  <!-- Main Content Area -->
  <div class="s-scene-04-container">
    <div class="s-scene-04-header">
      <div class="s-scene-04-tag">
        <iconify-icon icon="mdi:alert-decagram-outline"></iconify-icon> COMPUTATIONAL WASTE
      </div>
      <h2 class="s-scene-04-title">RE-PROCESSING OVERHEAD</h2>
    </div>

    <div class="s-scene-04-stage">
      <!-- Left: Previous Math (Stack of Papers) -->
      <div class="s-scene-04-source-area" data-step="0">
        <div class="s-scene-04-label">PREVIOUS CONTEXT</div>
        <div class="s-scene-04-paper-stack">
          <div class="s-scene-04-paper" style="--i:0"><span>MATH DATA</span></div>
          <div class="s-scene-04-paper" style="--i:1"><span>KV TENSORS</span></div>
          <div class="s-scene-04-paper" style="--i:2"><span>ATTENTION</span></div>
          <div class="s-scene-04-paper s-scene-04-new-page" data-step="1">
             <span class="s-scene-04-highlight">NEW WORD</span>
          </div>
        </div>
      </div>

      <!-- Center: The Giant Mechanical Arm (GPU) -->
      <div class="s-scene-04-gpu-unit" data-step="1">
        <div class="s-scene-04-arm-base">
          <div class="s-scene-04-mechanical-arm">
            <div class="s-scene-04-scanner-head">
              <div class="s-scene-04-laser-beam"></div>
            </div>
          </div>
        </div>
        <div class="s-scene-04-gpu-core">
           <iconify-icon icon="simple-icons:nvidia" class="s-scene-04-gpu-icon"></iconify-icon>
           <span class="s-scene-04-core-label">GPU ENGINE</span>
        </div>
        
        <!-- Warning Indicators -->
        <div class="s-scene-04-heat-ripples" data-step="2"></div>
        <div class="s-scene-04-warning-icons" data-step="2">
           <iconify-icon icon="mdi:fire" class="s-scene-04-alert-icon"></iconify-icon>
           <iconify-icon icon="mdi:alert" class="s-scene-04-alert-icon"></iconify-icon>
        </div>
      </div>

      <!-- Right: Stats -->
      <div class="s-scene-04-stats-panel" data-step="2">
        <div class="s-scene-04-stat-card">
           <div class="s-scene-04-stat-label">COMPUTE COST</div>
           <div class="s-scene-04-stat-value text-red">O(N²)</div>
        </div>
        <div class="s-scene-04-stat-card">
           <div class="s-scene-04-stat-label">REDUNDANCY</div>
           <div class="s-scene-04-stat-value">99.9%</div>
        </div>
      </div>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-05">
  <div class="sv-scene-root sv-scene-root-scene-05" data-scene-root-id="scene-05">
<div class="s-scene-05-wrapper">
  <!-- Ambient Layer -->
  <div class="s-scene-05-bg-grid"></div>
  <div class="s-scene-05-ambient-glow"></div>
  <div class="s-scene-05-ghost-text">KV CACHE</div>

  <!-- Main Content Area -->
  <div class="s-scene-05-container">
    <div class="s-scene-05-header">
      <div class="s-scene-05-tag">
        <iconify-icon icon="mdi:memory"></iconify-icon> EFFICIENCY MODULE
      </div>
      <h2 class="s-scene-05-title">KV CACHING ARCHITECTURE</h2>
    </div>

    <!-- Split Screen Vault Area -->
    <div class="s-scene-05-vault-stage">
      
      <!-- Left: Keys Column -->
      <div class="s-scene-05-vault-column" data-type="keys">
        <div class="s-scene-05-vault-header">
          <span class="s-scene-05-vault-label">KEYS (K)</span>
          <div class="s-scene-05-vault-status">READY</div>
        </div>
        <div class="s-scene-05-grid-container">
          <div class="s-scene-05-grid" id="grid-keys">
            <!-- Blocks generated by JS -->
          </div>
        </div>
      </div>

      <!-- Center Interface: Save Pulse -->
      <div class="s-scene-05-center-interface" data-step="2">
        <div class="s-scene-05-save-ring">
          <div class="s-scene-05-save-icon-wrap">
            <iconify-icon icon="mdi:content-save-cog" class="s-scene-05-save-icon"></iconify-icon>
          </div>
          <div class="s-scene-05-save-pulse"></div>
          <div class="s-scene-05-save-text">CACHING...</div>
        </div>
      </div>

      <!-- Right: Values Column -->
      <div class="s-scene-05-vault-column" data-type="values">
        <div class="s-scene-05-vault-header">
          <span class="s-scene-05-vault-label">VALUES (V)</span>
          <div class="s-scene-05-vault-status">SYNCED</div>
        </div>
        <div class="s-scene-05-grid-container">
          <div class="s-scene-05-grid" id="grid-values">
            <!-- Blocks generated by JS -->
          </div>
        </div>
      </div>

    </div>

    <!-- Footer Specs -->
    <div class="s-scene-05-footer-specs" data-step="1">
       <div class="s-scene-05-spec-item">
         <span class="s-scene-05-spec-name">MEMORY ALLOCATION</span>
         <span class="s-scene-05-spec-value">DYNAMIC</span>
       </div>
       <div class="s-scene-05-spec-item">
         <span class="s-scene-05-spec-name">COMPUTATION SAVED</span>
         <span class="s-scene-05-spec-value text-gold">95%</span>
       </div>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-06">
  <div class="sv-scene-root sv-scene-root-scene-06" data-scene-root-id="scene-06">
<div class="s-scene-06-wrapper">
  <!-- Ambient Layer -->
  <div class="s-scene-06-bg-grid"></div>
  <div class="s-scene-06-ghost-text">PRE-COMPUTED</div>
  <div class="s-scene-06-ambient-glow"></div>

  <!-- Main Content Area -->
  <div class="s-scene-06-container">
    <!-- Header Section -->
    <div class="s-scene-06-header">
      <div class="s-scene-06-tag">
        <iconify-icon icon="mdi:chef-hat"></iconify-icon> ANALOGY MODE
      </div>
      <h2 class="s-scene-06-title">THE EFFICIENCY PRINCIPLE</h2>
    </div>

    <!-- Main Isometric Stage -->
    <div class="s-scene-06-stage">
      
      <!-- Step 0: The Organized Counter -->
      <div class="s-scene-06-counter">
        <div class="s-scene-06-iso-group" data-step="0">
          <!-- Ingredients Containers -->
          <div class="s-scene-06-container-box" style="--offset: 0">
            <div class="s-scene-06-label">K-VECTOR</div>
            <div class="s-scene-06-cube"></div>
          </div>
          <div class="s-scene-06-container-box" style="--offset: 1">
            <div class="s-scene-06-label">V-VECTOR</div>
            <div class="s-scene-06-cube"></div>
          </div>
          <div class="s-scene-06-container-box" style="--offset: 2">
            <div class="s-scene-06-label">CONTEXT</div>
            <div class="s-scene-06-cube"></div>
          </div>
        </div>

        <!-- Step 1: The Chef Action & Pot -->
        <div class="s-scene-06-cooking-area" data-step="1">
          <div class="s-scene-06-chef-arm">
             <iconify-icon icon="mdi:hand-back-right" class="s-scene-06-hand-icon"></iconify-icon>
          </div>
          <div class="s-scene-06-pot-wrap">
             <div class="s-scene-06-pot-steam"></div>
             <iconify-icon icon="mdi:pot-steam" class="s-scene-06-pot-icon"></iconify-icon>
          </div>
        </div>

        <!-- Step 2: Ready Status -->
        <div class="s-scene-06-status-overlay" data-step="2">
           <div class="s-scene-06-checkmark-circle">
              <iconify-icon icon="mdi:check-bold"></iconify-icon>
           </div>
           <div class="s-scene-06-status-text">RESPONSE READY</div>
        </div>
      </div>

      <!-- Info Panel (Side) -->
      <div class="s-scene-06-info-panel">
         <div class="s-scene-06-metric" data-step="1">
            <span class="s-scene-06-metric-label">PROCESS TIME</span>
            <span class="s-scene-06-metric-value">-90%</span>
            <div class="s-scene-06-progress-bar"><div class="s-scene-06-progress-fill"></div></div>
         </div>
         <div class="s-scene-06-quote" data-step="0">
            PRE-CHOPPED INGREDIENTS SAVES TIME FOR EVERY ORDER.
         </div>
      </div>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-07">
  <div class="sv-scene-root sv-scene-root-scene-07" data-scene-root-id="scene-07">
<div class="s-scene-07-wrapper">
  <!-- Ambient Layer -->
  <div class="s-scene-07-bg-grid"></div>
  <div class="s-scene-07-ambient-glow"></div>
  <div class="s-scene-07-ghost-text">LONG-TERM MEMORY</div>

  <div class="s-scene-07-main">
    <!-- Header -->
    <div class="s-scene-07-header">
       <div class="s-scene-07-badge">
          <iconify-icon icon="ph:seal-check-fill"></iconify-icon>
          OPTIMIZED RETRIEVAL
       </div>
       <h1 class="s-scene-07-title">PROMPT CACHING</h1>
    </div>

    <!-- Central Visual Area -->
    <div class="s-scene-07-canvas">
      
      <!-- Step 0: The Document System Prompt -->
      <div class="s-scene-07-doc-container" data-step="0">
        <div class="s-scene-07-doc-card">
           <div class="s-scene-07-doc-frost"></div>
           <iconify-icon icon="ph:file-text-bold" class="s-scene-07-doc-icon"></iconify-icon>
           <div class="s-scene-07-doc-label">SYSTEM PROMPT</div>
           <div class="s-scene-07-doc-lines">
             <div class="s-scene-07-line"></div>
             <div class="s-scene-07-line"></div>
             <div class="s-scene-07-line width-short"></div>
           </div>
           <!-- Step 1: Frost Overlay -->
           <div class="s-scene-07-lock-overlay" data-step="1">
              <iconify-icon icon="ph:snowflake-bold" class="s-scene-07-ice-icon"></iconify-icon>
              <span class="s-scene-07-lock-tag">CACHED & FROZEN</span>
           </div>
        </div>
      </div>

      <!-- Step 2: Multiple Conversations -->
      <div class="s-scene-07-chats-grid" data-step="2">
         <div class="s-scene-07-chat-node" style="--i: 0">
            <div class="s-scene-07-link-line"></div>
            <div class="s-scene-07-bubble">
               <iconify-icon icon="ph:chat-teardrop-dots-bold"></iconify-icon>
               <span>SESSION A</span>
            </div>
         </div>
         <div class="s-scene-07-chat-node" style="--i: 1">
            <div class="s-scene-07-link-line"></div>
            <div class="s-scene-07-bubble">
               <iconify-icon icon="ph:chat-teardrop-dots-bold"></iconify-icon>
               <span>SESSION B</span>
            </div>
         </div>
         <div class="s-scene-07-chat-node" style="--i: 2">
            <div class="s-scene-07-link-line"></div>
            <div class="s-scene-07-bubble">
               <iconify-icon icon="ph:chat-teardrop-dots-bold"></iconify-icon>
               <span>SESSION C</span>
            </div>
         </div>
      </div>
    </div>

    <!-- Side Info Panel -->
    <div class="s-scene-07-side-info">
       <div class="s-scene-07-stat-block" data-step="1">
          <span class="s-scene-07-stat-label">REUSE STATUS</span>
          <span class="s-scene-07-stat-value">READY</span>
          <div class="s-scene-07-status-indicator"></div>
       </div>
       <div class="s-scene-07-desc" data-step="0">
          RETAINING CONTEXT ACROSS MULTIPLE SESSIONS WITHOUT RE-PROCESSING.
       </div>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-08">
  <div class="sv-scene-root sv-scene-root-scene-08" data-scene-root-id="scene-08">
<div class="s-scene-08-wrapper">
  <!-- Ambient Layer -->
  <div class="s-scene-08-bg-grid"></div>
  <div class="s-scene-08-ambient-glow"></div>
  <div class="s-scene-08-ghost-text">PERFORMANCE</div>

  <div class="s-scene-08-main">
    <!-- Top Section: Header -->
    <div class="s-scene-08-header">
      <div class="s-scene-08-badge">
        <iconify-icon icon="ph:speedometer-fill"></iconify-icon>
        LATENCY BENCHMARK
      </div>
      <h1 class="s-scene-08-title">TTFT REDUCTION</h1>
    </div>

    <!-- Middle Section: Performance Chart Area -->
    <div class="s-scene-08-content">
      <div class="s-scene-08-chart-container">
        <!-- Standard Row -->
        <div class="s-scene-08-bar-group" data-type="standard">
          <div class="s-scene-08-bar-info">
            <span class="s-scene-08-bar-label">STANDARD REQUEST</span>
            <span class="s-scene-08-bar-value" id="val-standard">0ms</span>
          </div>
          <div class="s-scene-08-bar-track">
            <div class="s-scene-08-bar-fill" id="fill-standard"></div>
          </div>
        </div>

        <!-- Cached Row -->
        <div class="s-scene-08-bar-group" data-type="cached">
          <div class="s-scene-08-bar-info">
            <span class="s-scene-08-bar-label">WITH PROMPT CACHE</span>
            <span class="s-scene-08-bar-value" id="val-cached">0ms</span>
          </div>
          <div class="s-scene-08-bar-track">
            <div class="s-scene-08-bar-fill" id="fill-cached"></div>
          </div>
        </div>
      </div>

      <!-- Step 1: Big Impact Label -->
      <div class="s-scene-08-impact-zone" data-step="1">
        <div class="s-scene-08-impact-card">
          <div class="s-scene-08-burst-container">
            <div class="s-scene-08-particle"></div>
            <div class="s-scene-08-particle"></div>
            <div class="s-scene-08-particle"></div>
            <div class="s-scene-08-particle"></div>
          </div>
          <div class="s-scene-08-impact-title">TTFT REDUCED</div>
          <div class="s-scene-08-impact-stat">UP TO 90%</div>
          <div class="s-scene-08-impact-line"></div>
        </div>
      </div>
    </div>

    <!-- Bottom Info -->
    <div class="s-scene-08-footer">
      <div class="s-scene-08-metric">
        <span class="s-scene-08-m-label">EFFICIENCY</span>
        <span class="s-scene-08-m-val">MAXIMIZED</span>
      </div>
      <div class="s-scene-08-divider"></div>
      <div class="s-scene-08-metric">
        <span class="s-scene-08-m-label">RESPONSE</span>
        <span class="s-scene-08-m-val">INSTANT</span>
      </div>
    </div>
  </div>
</div>
  </div>
</section>

<section class="scene" data-scene-id="scene-09">
  <div class="sv-scene-root sv-scene-root-scene-09" data-scene-root-id="scene-09">
<div class="s-scene-09-wrapper">
  <!-- Ambient Background Layer -->
  <div class="s-scene-09-bg-grid"></div>
  <div class="s-scene-09-ambient-glow"></div>
  <div class="s-scene-09-ghost-text">INTELLIGENCE</div>

  <div class="s-scene-09-container">
    <!-- Step 0: The Central Brain Core -->
    <div class="s-scene-09-core-zone">
      <div class="s-scene-09-circuit-brain">
        <!-- Glowing Brain Icon via Iconify -->
        <iconify-icon icon="ph:brain-duotone" class="s-scene-09-brain-icon"></iconify-icon>
        
        <!-- Light Ray Particles (Step 2) -->
        <div class="s-scene-09-rays-container" data-step="2">
          <div class="s-scene-09-ray"></div>
          <div class="s-scene-09-ray"></div>
          <div class="s-scene-09-ray"></div>
          <div class="s-scene-09-ray"></div>
          <div class="s-scene-09-ray"></div>
          <div class="s-scene-09-ray"></div>
          <div class="s-scene-09-ray"></div>
          <div class="s-scene-09-ray"></div>
        </div>

        <!-- Circular Scanning Rings -->
        <div class="s-scene-09-ring s-scene-09-ring-1"></div>
        <div class="s-scene-09-ring s-scene-09-ring-2"></div>
      </div>
    </div>

    <!-- Step 1: Text Fade In -->
    <div class="s-scene-09-text-zone" data-step="1">
      <h1 class="s-scene-09-hero-title">INTELLIGENCE</h1>
      <div class="s-scene-09-subtitle-bar">
        <span class="s-scene-09-tag">REAL-TIME FOUNDATION</span>
        <div class="s-scene-09-line"></div>
        <span class="s-scene-09-tag">CACHING REVOLUTION</span>
      </div>
    </div>
  </div>

  <!-- UI Decorative Elements -->
  <div class="s-scene-09-corner s-scene-09-tl">[ SYS_FINAL ]</div>
  <div class="s-scene-09-corner s-scene-09-br">0x00_COMPLETE</div>
</div>
  </div>
</section>
      </div>
    </div>
  </div>
  <script id="__SVGVIDEO_META__" type="application/json">{"version":2,"format":"json","title":"Unlocking Speed: How Large Model Caching Works","fullScript":"Have you ever wondered why Large Language Models sometimes take a moment to 'think' before they start typing? The secret behind their speed—or the lack of it—often comes down to one thing: Caching. To understand this, we first need to look at how these models generate text. It’s an autoregressive process, meaning the model predicts the next token based on all previous ones. Without caching, the model would have to re-process every single word from the beginning for every new word it generates. That's a massive waste of compute. This is where KV Caching comes in. By storing the 'Keys' and 'Values' of previous tokens in memory, the model only needs to calculate the new token. Think of it like a chef who keeps pre-chopped ingredients ready instead of starting from scratch for every order. But it doesn't stop there. Prompt Caching takes it a step further by remembering common instructions or long documents across different conversations. This drastically reduces the time to first token. In the world of AI, caching isn't just a trick; it's the foundation of real-time intelligence.","visualStyleId":"kejibozhu","orientation":"landscape","scenes":[{"id":"scene-01","title":"The Latency Question","steps":3,"status":"success","prompt":"Landscape 16:9 layout. A dark-themed terminal window centered in the frame with a glowing cursor. Step 0: The terminal frame appears with a glassmorphism effect. Step 1: A user prompt 'Explain Quantum Physics...' is typed character by character. Step 2: A 'thinking' animation appears—three pulsing dots with a soft blue neon glow. Style: High-tech minimalist, soft gradients, deep indigo background.","scriptText":"Have you ever wondered why Large Language Models sometimes take a moment to 'think' before they start typing?","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_c1f72662-950f-4dce-b155-a816b6131bc9/s_scene-01/v_xiaoxiao-hd/a_b8d65ac1_1778728055456_smhlat.mp3","audioDurationMs":5508,"voiceName":"xiaoxiao-hd","relatedSceneIds":["scene-02"],"transition":"door"},{"id":"scene-02","title":"The Hidden Secret","steps":2,"status":"success","prompt":"Focus on a large, central text card reading 'CACHING' in bold, futuristic typography. Step 0: The word 'CACHING' slams into the center with a subtle shake effect. Step 1: An inner glow effect flows through the letters like a data stream. Background: Abstract network nodes moving slowly. Layout: Symmetrical and impactful.","scriptText":"The secret behind their speed—or the lack of it—often comes down to one thing: Caching.","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_c1f72662-950f-4dce-b155-a816b6131bc9/s_scene-02/v_xiaoxiao-hd/a_49b90f81_1778728076883_wnjch6.mp3","audioDurationMs":4716,"voiceName":"xiaoxiao-hd","relatedSceneIds":["scene-03"],"transition":"door"},{"id":"scene-03","title":"Autoregressive Mechanism","steps":4,"status":"success","prompt":"Visualizing the token generation process. Step 0: A sequence of word blocks [The][cat][sat] appears on a horizontal line. Step 1: An arrow points from the whole sequence to a new empty slot. Step 2: A new block [on] fades in with a spring animation. Step 3: A loop icon appears, indicating the process repeats. Style: Clean flat UI, vibrant purple and teal accents.","scriptText":"To understand this, we first need to look at how these models generate text. It’s an autoregressive process, meaning the model predicts the next token based on all previous ones.","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_c1f72662-950f-4dce-b155-a816b6131bc9/s_scene-03/v_xiaoxiao-hd/a_75d4a4d1_1778728102569_03xwpx.mp3","audioDurationMs":10476,"voiceName":"xiaoxiao-hd","relatedSceneIds":["scene-04"],"transition":"door"},{"id":"scene-04","title":"The Inefficiency Problem","steps":3,"status":"success","prompt":"A visual metaphor for wasted effort. Step 0: A stack of papers representing 'Previous Math' on the left. Step 1: A giant mechanical arm (representing the GPU) frantically re-scanning all papers from the top every time a new page is added. Step 2: Red 'Warning' icons and heat waves ripple from the GPU. Layout: Left-to-right flow, chaotic motion.","scriptText":"Without caching, the model would have to re-process every single word from the beginning for every new word it generates. That's a massive waste of compute.","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_c1f72662-950f-4dce-b155-a816b6131bc9/s_scene-04/v_xiaoxiao-hd/a_9f387708_1778728130599_lmt4w9.mp3","audioDurationMs":9468,"voiceName":"xiaoxiao-hd","relatedSceneIds":["scene-05"],"transition":"door"},{"id":"scene-05","title":"Enter KV Caching","steps":3,"status":"success","prompt":"Introducing the solution. Step 0: A split screen. On the left, 'Keys (K)'; on the right, 'Values (V)'. Step 1: Grid-like cells fill up with glowing golden data blocks. Step 2: A 'Save' icon pulsates between the grids. Style: Digital vault aesthetic, gold and amber tones, high-contrast borders.","scriptText":"This is where KV Caching comes in. By storing the 'Keys' and 'Values' of previous tokens in memory, the model only needs to calculate the new token.","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_c1f72662-950f-4dce-b155-a816b6131bc9/s_scene-05/v_xiaoxiao-hd/a_c0fb46af_1778728156581_3c55q7.mp3","audioDurationMs":8712,"voiceName":"xiaoxiao-hd","relatedSceneIds":["scene-06"],"transition":"door"},{"id":"scene-06","title":"The Chef Metaphor","steps":3,"status":"success","prompt":"Conceptual illustration. Step 0: A stylized kitchen counter with neatly organized containers labeled 'Ingredients'. Step 1: A chef character quickly grabs a container and adds it to a pot. Step 2: A 'Ready' checkmark appears. Style: Isometric 2.5D illustration, friendly and bright colors, smooth motion.","scriptText":"Think of it like a chef who keeps pre-chopped ingredients ready instead of starting from scratch for every order.","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_c1f72662-950f-4dce-b155-a816b6131bc9/s_scene-06/v_xiaoxiao-hd/a_1d24e678_1778728181732_2fu0ww.mp3","audioDurationMs":6012,"voiceName":"xiaoxiao-hd","relatedSceneIds":["scene-07"],"transition":"door"},{"id":"scene-07","title":"Prompt Caching","steps":3,"status":"success","prompt":"Visualizing long-term memory. Step 0: A large document icon representing 'System Prompt' or 'Context' slides in. Step 1: A 'Freeze' or 'Lock' animation applies a crystalline frost effect over the document. Step 2: Multiple conversation bubbles appear below, all linked to this frozen document. Layout: Top-down hierarchy.","scriptText":"But it doesn't stop there. Prompt Caching takes it a step further by remembering common instructions or long documents across different conversations.","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_c1f72662-950f-4dce-b155-a816b6131bc9/s_scene-07/v_xiaoxiao-hd/a_10c023ec_1778728208475_nmbuvj.mp3","audioDurationMs":8604,"voiceName":"xiaoxiao-hd","relatedSceneIds":["scene-08"],"transition":"door"},{"id":"scene-08","title":"The Speed Result","steps":2,"status":"success","prompt":"Side-by-side performance chart. Step 0: Two progress bars appear: 'Standard' (slowly filling) and 'With Cache' (instantly jumping to 100%). Step 1: A large 'TTFT Reduced' label pops up with a burst of particles. Style: Dashboard UI, neon green success colors, sharp data lines.","scriptText":"This drastically reduces the time to first token.","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_c1f72662-950f-4dce-b155-a816b6131bc9/s_scene-08/v_xiaoxiao-hd/a_5b360ca9_1778728234777_fgxwo0.mp3","audioDurationMs":2952,"voiceName":"xiaoxiao-hd","relatedSceneIds":["scene-09"],"transition":"door"},{"id":"scene-09","title":"Conclusion: Real-time Intelligence","steps":3,"status":"success","prompt":"Final summary. Step 0: A brain icon made of glowing circuit paths centers the screen. Step 1: The word 'Intelligence' fades in below. Step 2: Light rays emit from the center, filling the frame. Style: Epic and cinematic, bokeh background, particle emission. Layout: Centered focus.","scriptText":"In the world of AI, caching isn't just a trick; it's the foundation of real-time intelligence.","audioObjectKey":"sv-video/v1/u_1aa5e8b3-d1b1-4121-b796-bb5ac9fcd45a/p_c1f72662-950f-4dce-b155-a816b6131bc9/s_scene-09/v_xiaoxiao-hd/a_1b0c4c8b_1778728257748_tss7xt.mp3","audioDurationMs":5652,"voiceName":"xiaoxiao-hd","transition":"door"}]}</script>
  <script id="__SVGVIDEO_SCENE_DATA__" type="application/json">[{"id":"scene-01","title":"The Latency Question","steps":3,"html":"<div class=\"s-scene-01-container\">\n  <!-- Background Ambient Layer -->\n  <div class=\"s-scene-01-bg-grid\"></div>\n  <div class=\"s-scene-01-ambient-glow\"></div>\n  <div class=\"s-scene-01-ghost-text\">LATENCY</div>\n\n  <!-- Main Content Area -->\n  <div class=\"s-scene-01-content\">\n    <div class=\"s-scene-01-header\" data-step=\"0\">\n      <div class=\"s-scene-01-tag\"><span class=\"s-scene-01-dot\"></span> SYSTEM STATUS</div>\n      <h1 class=\"s-scene-01-title\">THE THINKING PROCESS</h1>\n    </div>\n\n    <!-- Terminal Window -->\n    <div class=\"s-scene-01-terminal\" data-step=\"0\">\n      <div class=\"s-scene-01-terminal-bar\">\n        <div class=\"s-scene-01-terminal-btns\">\n          <span></span><span></span><span></span>\n        </div>\n        <div class=\"s-scene-01-terminal-tab\">AI_QUERY_LOG</div>\n      </div>\n      \n      <div class=\"s-scene-01-terminal-body\">\n        <div class=\"s-scene-01-line\">\n          <span class=\"s-scene-01-prompt\">User:</span>\n          <span class=\"s-scene-01-typewriter\" data-step=\"1\">Explain Quantum Physics...</span>\n          <span class=\"s-scene-01-cursor\"></span>\n        </div>\n        \n        <div class=\"s-scene-01-thinking\" data-step=\"2\">\n          <span class=\"s-scene-01-thinking-label\">AI is processing</span>\n          <div class=\"s-scene-01-dots\">\n            <span></span><span></span><span></span>\n          </div>\n        </div>\n      </div>\n    </div>\n\n    <!-- Annotation Label -->\n    <div class=\"s-scene-01-annotation\" data-step=\"2\">\n      <div class=\"s-scene-01-line-pointer\"></div>\n      <div class=\"s-scene-01-anno-content\">\n        <div class=\"s-scene-01-anno-tag\">LATENCY ANALYSIS</div>\n        <div class=\"s-scene-01-anno-value\">350ms - 1200ms</div>\n      </div>\n    </div>\n  </div>\n</div>","css":".s-scene-01-container {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #1B1B1B;\n  overflow: hidden;\n  font-family: var(--sv-font-body-cn);\n  color: #FFFFFF;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.s-scene-01-bg-grid {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);\n  background-size: 40px 40px;\n  z-index: 1;\n}\n\n.s-scene-01-ambient-glow {\n  position: absolute;\n  width: 60%;\n  height: 60%;\n  background: radial-gradient(circle, rgba(245, 53, 1, 0.08) 0%, transparent 70%);\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n  animation: s-01-pulse 10s ease-in-out infinite;\n  z-index: 2;\n}\n\n.s-scene-01-ghost-text {\n  position: absolute;\n  bottom: 5%;\n  right: 5%;\n  font-family: var(--sv-font-display-cn);\n  font-size: 120px;\n  opacity: 0.04;\n  letter-spacing: -2px;\n  user-select: none;\n  z-index: 1;\n}\n\n.s-scene-01-content {\n  position: relative;\n  z-index: 10;\n  width: 80%;\n  max-width: 1000px;\n  display: flex;\n  flex-direction: column;\n  gap: 30px;\n}\n\n.s-scene-01-header {\n  display: flex;\n  flex-direction: column;\n  gap: 10px;\n}\n\n.s-scene-01-title {\n  font-family: var(--sv-font-display-cn);\n  font-size: 56px;\n  margin: 0;\n  line-height: 1;\n  text-transform: uppercase;\n}\n\n.s-scene-01-tag {\n  font-family: var(--sv-font-mono);\n  color: #F53501;\n  font-size: 14px;\n  letter-spacing: 2px;\n  display: flex;\n  align-items: center;\n  gap: 8px;\n}\n\n.s-scene-01-dot {\n  width: 6px;\n  height: 6px;\n  background: #F53501;\n  border-radius: 50%;\n}\n\n.s-scene-01-terminal {\n  background: rgba(20, 20, 20, 0.8);\n  backdrop-filter: blur(12px);\n  border: 1px solid rgba(255, 255, 255, 0.1);\n  border-radius: 12px;\n  overflow: hidden;\n  box-shadow: 0 40px 100px rgba(0, 0, 0, 0.5);\n  transform: translateY(20px);\n  opacity: 0;\n  transition: all 0.6s cubic-bezier(0.22, 1, 0.36, 1);\n}\n\n[data-step=\"0\"] .s-scene-01-terminal,\n[data-step=\"1\"] .s-scene-01-terminal,\n[data-step=\"2\"] .s-scene-01-terminal {\n  transform: translateY(0);\n  opacity: 1;\n}\n\n.s-scene-01-terminal-bar {\n  background: rgba(255, 255, 255, 0.05);\n  padding: 12px 20px;\n  display: flex;\n  align-items: center;\n  gap: 15px;\n  border-bottom: 1px solid rgba(255, 255, 255, 0.05);\n}\n\n.s-scene-01-terminal-btns {\n  display: flex;\n  gap: 6px;\n}\n\n.s-scene-01-terminal-btns span {\n  width: 8px;\n  height: 8px;\n  border-radius: 50%;\n  background: rgba(255, 255, 255, 0.2);\n}\n\n.s-scene-01-terminal-tab {\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  color: rgba(255, 255, 255, 0.4);\n}\n\n.s-scene-01-terminal-body {\n  padding: 40px;\n  min-height: 200px;\n  font-family: var(--sv-font-mono);\n  font-size: 24px;\n  position: relative;\n}\n\n.s-scene-01-prompt {\n  color: #F53501;\n  margin-right: 15px;\n}\n\n.s-scene-01-cursor {\n  display: inline-block;\n  width: 12px;\n  height: 24px;\n  background: #F53501;\n  vertical-align: middle;\n  margin-left: 4px;\n  animation: s-01-blink 1s step-end infinite;\n}\n\n.s-scene-01-thinking {\n  margin-top: 40px;\n  display: flex;\n  align-items: center;\n  gap: 20px;\n  opacity: 0;\n  transform: translateX(-10px);\n  transition: all 0.4s ease-out;\n}\n\n[data-step=\"2\"] .s-scene-01-thinking {\n  opacity: 1;\n  transform: translateX(0);\n}\n\n.s-scene-01-thinking-label {\n  font-size: 16px;\n  color: rgba(255, 255, 255, 0.4);\n  text-transform: uppercase;\n  letter-spacing: 1px;\n}\n\n.s-scene-01-dots {\n  display: flex;\n  gap: 8px;\n}\n\n.s-scene-01-dots span {\n  width: 10px;\n  height: 10px;\n  background: #F53501;\n  border-radius: 50%;\n  animation: s-01-dots-pulse 1.4s infinite ease-in-out both;\n}\n\n.s-scene-01-dots span:nth-child(1) { animation-delay: -0.32s; }\n.s-scene-01-dots span:nth-child(2) { animation-delay: -0.16s; }\n\n.s-scene-01-annotation {\n  position: absolute;\n  right: -20px;\n  bottom: -40px;\n  display: flex;\n  align-items: center;\n  gap: 15px;\n  opacity: 0;\n  transform: translateY(10px);\n  transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);\n  transition-delay: 0.3s;\n}\n\n[data-step=\"2\"] .s-scene-01-annotation {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.s-scene-01-line-pointer {\n  width: 60px;\n  height: 1px;\n  background: #F53501;\n  position: relative;\n}\n\n.s-scene-01-line-pointer::before {\n  content: '';\n  position: absolute;\n  left: 0;\n  top: -2px;\n  width: 5px;\n  height: 5px;\n  background: #F53501;\n  border-radius: 50%;\n}\n\n.s-scene-01-anno-content {\n  background: #F53501;\n  padding: 10px 15px;\n  color: #FFFFFF;\n}\n\n.s-scene-01-anno-tag {\n  font-size: 10px;\n  font-weight: bold;\n  opacity: 0.8;\n}\n\n.s-scene-01-anno-value {\n  font-family: var(--sv-font-mono);\n  font-size: 18px;\n  font-weight: 900;\n}\n\n@keyframes s-01-pulse {\n  0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 0.08; }\n  50% { transform: translate(-50%, -50%) scale(1.2); opacity: 0.12; }\n}\n\n@keyframes s-01-blink {\n  0%, 100% { opacity: 1; }\n  50% { opacity: 0; }\n}\n\n@keyframes s-01-dots-pulse {\n  0%, 80%, 100% { transform: scale(0); opacity: 0.3; }\n  40% { transform: scale(1); opacity: 1; }\n}","js":"window.SceneLifecycle.register('scene-01', {\n  enter() {\n    const root = document.querySelector('[data-scene-id=\"scene-01\"]');\n    const typewriter = root.querySelector('.s-scene-01-typewriter');\n    if (typewriter) typewriter.textContent = '';\n  },\n  step(step) {\n    const root = document.querySelector('[data-scene-id=\"scene-01\"]');\n    if (step === 1) {\n      const text = \"Explain Quantum Physics...\";\n      const target = root.querySelector('.s-scene-01-typewriter');\n      let i = 0;\n      target.textContent = '';\n      const interval = setInterval(() => {\n        if (i < text.length) {\n          target.textContent += text.charAt(i);\n          i++;\n        } else {\n          clearInterval(interval);\n        }\n      }, 50);\n    }\n  }\n});"},{"id":"scene-02","title":"The Hidden Secret","steps":2,"html":"<div class=\"s-scene-02-wrapper\">\n  <!-- Ambient Background Layer -->\n  <div class=\"s-scene-02-bg-grid\"></div>\n  <div class=\"s-scene-02-nodes\" id=\"scene-02-nodes-canvas\"></div>\n  <div class=\"s-scene-02-ghost-text\">OPTIMIZATION</div>\n\n  <!-- Main Hero Card Area -->\n  <div class=\"s-scene-02-main\">\n    <div class=\"s-scene-02-card-container\" data-step=\"0\">\n      <div class=\"s-scene-02-glitch-border\"></div>\n      <div class=\"s-scene-02-content-box\">\n        <div class=\"s-scene-02-eyebrow\">\n          <i data-lucide=\"zap\"></i> PERFORMANCE CORE\n        </div>\n        <h1 class=\"s-scene-02-hero-text\">\n          <span class=\"s-scene-02-char-stream\">CACHING</span>\n        </h1>\n        <div class=\"s-scene-02-footer-tag\">\n          <span class=\"s-scene-02-status-dot\"></span>\n          SYSTEM ACCELERATED\n        </div>\n      </div>\n    </div>\n\n    <!-- Data Flow Annotation -->\n    <div class=\"s-scene-02-annotation\" data-step=\"1\">\n      <div class=\"s-scene-02-flow-line\"></div>\n      <div class=\"s-scene-02-data-info\">\n        <span class=\"s-scene-02-label\">LATENCY REDUCTION</span>\n        <span class=\"s-scene-02-value\">95.4%</span>\n      </div>\n    </div>\n  </div>\n</div>","css":".s-scene-02-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #1B1B1B;\n  overflow: hidden;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FFFFFF;\n  font-family: var(--sv-font-body-cn);\n}\n\n.s-scene-02-bg-grid {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);\n  background-size: 60px 60px;\n  z-index: 1;\n}\n\n.s-scene-02-nodes {\n  position: absolute;\n  inset: 0;\n  z-index: 2;\n  opacity: 0.3;\n}\n\n.s-scene-02-ghost-text {\n  position: absolute;\n  top: 10%;\n  left: 5%;\n  font-family: var(--sv-font-display-cn);\n  font-size: 140px;\n  opacity: 0.03;\n  letter-spacing: -5px;\n  user-select: none;\n  z-index: 1;\n}\n\n.s-scene-02-main {\n  position: relative;\n  z-index: 10;\n  perspective: 1000px;\n}\n\n.s-scene-02-card-container {\n  position: relative;\n  background: rgba(30, 30, 30, 0.9);\n  border: 1px solid rgba(255, 255, 255, 0.1);\n  padding: 40px 80px;\n  box-shadow: 0 50px 100px rgba(0, 0, 0, 0.8);\n  animation: s-02-slam 0.5s cubic-bezier(0.17, 0.89, 0.32, 1.2) both;\n}\n\n[data-step=\"0\"] .s-scene-02-card-container {\n  opacity: 1;\n}\n\n.s-scene-02-eyebrow {\n  display: flex;\n  align-items: center;\n  gap: 10px;\n  color: #F53501;\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  letter-spacing: 3px;\n  margin-bottom: 20px;\n}\n\n.s-scene-02-hero-text {\n  font-family: var(--sv-font-display-cn);\n  font-size: 120px;\n  margin: 0;\n  line-height: 0.9;\n  letter-spacing: -2px;\n  color: #FFFFFF;\n  position: relative;\n  overflow: hidden;\n}\n\n/* Step 1 Letter Glow Stream Effect */\n.s-scene-02-char-stream {\n  position: relative;\n  display: inline-block;\n}\n\n[data-step=\"1\"] .s-scene-02-char-stream::after {\n  content: 'CACHING';\n  position: absolute;\n  left: 0;\n  top: 0;\n  color: #F53501;\n  filter: blur(8px);\n  animation: s-02-glow-flow 2s infinite linear;\n  clip-path: inset(0 100% 0 0);\n}\n\n.s-scene-02-footer-tag {\n  margin-top: 30px;\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  color: rgba(255, 255, 255, 0.4);\n  display: flex;\n  align-items: center;\n  gap: 8px;\n}\n\n.s-scene-02-status-dot {\n  width: 6px;\n  height: 6px;\n  background: #F53501;\n  border-radius: 50%;\n  box-shadow: 0 0 10px #F53501;\n}\n\n.s-scene-02-annotation {\n  position: absolute;\n  bottom: -60px;\n  right: -40px;\n  display: flex;\n  align-items: flex-start;\n  gap: 15px;\n  opacity: 0;\n  transform: translateX(20px);\n  transition: all 0.5s ease-out;\n}\n\n[data-step=\"1\"] .s-scene-02-annotation {\n  opacity: 1;\n  transform: translateX(0);\n}\n\n.s-scene-02-flow-line {\n  width: 1px;\n  height: 80px;\n  background: linear-gradient(to bottom, #F53501, transparent);\n}\n\n.s-scene-02-data-info {\n  display: flex;\n  flex-direction: column;\n  gap: 4px;\n}\n\n.s-scene-02-label {\n  font-size: 12px;\n  color: rgba(255, 255, 255, 0.5);\n  letter-spacing: 1px;\n}\n\n.s-scene-02-value {\n  font-family: var(--sv-font-display-cn);\n  font-size: 36px;\n  color: #F53501;\n}\n\n@keyframes s-02-slam {\n  0% {\n    opacity: 0;\n    transform: scale(1.5) translateZ(100px);\n    filter: blur(20px);\n  }\n  70% {\n    transform: scale(0.98) translateZ(0);\n    filter: blur(0);\n  }\n  100% {\n    opacity: 1;\n    transform: scale(1) translateZ(0);\n    filter: blur(0);\n  }\n}\n\n@keyframes s-02-glow-flow {\n  0% { clip-path: inset(0 100% 0 0); opacity: 0; }\n  20% { opacity: 1; }\n  80% { opacity: 1; }\n  100% { clip-path: inset(0 0 0 100%); opacity: 0; }\n}","js":"window.SceneLifecycle.register('scene-02', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-02\"]');\n    if (!sceneRoot) return;\n\n    // Create simple background network nodes\n    const canvasContainer = sceneRoot.querySelector('#scene-02-nodes-canvas');\n    canvasContainer.innerHTML = '';\n    const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n    svg.setAttribute('width', '100%');\n    svg.setAttribute('height', '100%');\n    svg.style.position = 'absolute';\n\n    const nodes = [];\n    for (let i = 0; i < 15; i++) {\n      const x = Math.random() * 100;\n      const y = Math.random() * 100;\n      const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');\n      circle.setAttribute('cx', `${x}%`);\n      circle.setAttribute('cy', `${y}%`);\n      circle.setAttribute('r', '1.5');\n      circle.setAttribute('fill', '#F53501');\n      \n      const animateX = document.createElementNS('http://www.w3.org/2000/svg', 'animate');\n      animateX.setAttribute('attributeName', 'cx');\n      animateX.setAttribute('values', `${x}%;${x + (Math.random() - 0.5) * 5}%;${x}%`);\n      animateX.setAttribute('dur', `${10 + Math.random() * 10}s`);\n      animateX.setAttribute('repeatCount', 'indefinite');\n      \n      circle.appendChild(animateX);\n      svg.appendChild(circle);\n    }\n    canvasContainer.appendChild(svg);\n    \n    window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n  },\n  step(step) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-02\"]');\n    if (step === 0) {\n      // Shake effect on slam\n      sceneRoot.style.animation = 'none';\n      void sceneRoot.offsetWidth; \n      sceneRoot.style.animation = 's-02-shake 0.4s cubic-bezier(.36,.07,.19,.97) both';\n    }\n  }\n});\n\n// Add specialized shake animation\nconst style = document.createElement('style');\nstyle.textContent = `\n@keyframes s-02-shake {\n  10%, 90% { transform: translate3d(-1px, 0, 0); }\n  20%, 80% { transform: translate3d(2px, 0, 0); }\n  30%, 50%, 70% { transform: translate3d(-4px, 0, 0); }\n  40%, 60% { transform: translate3d(4px, 0, 0); }\n}`;\ndocument.head.appendChild(style);"},{"id":"scene-03","title":"Autoregressive Mechanism","steps":4,"html":"<div class=\"s-scene-03-wrapper\">\n  <!-- Ambient Background Layer -->\n  <div class=\"s-scene-03-bg-grid\"></div>\n  <div class=\"s-scene-03-ghost-text\">AUTOREGRESSIVE</div>\n  <div class=\"s-scene-03-ambient-glow\"></div>\n\n  <!-- Main Content Area -->\n  <div class=\"s-scene-03-container\">\n    <!-- Header Label -->\n    <div class=\"s-scene-03-header\">\n      <div class=\"s-scene-03-tag\">\n        <i data-lucide=\"refresh-cw\"></i> NEXT TOKEN PREDICTION\n      </div>\n      <h2 class=\"s-scene-03-title\">SEQUENCE GENERATION</h2>\n    </div>\n\n    <!-- The Token Sequence Track -->\n    <div class=\"s-scene-03-sequence-area\">\n      <div class=\"s-scene-03-token-list\">\n        <div class=\"s-scene-03-token\" data-step=\"0\">The</div>\n        <div class=\"s-scene-03-token\" data-step=\"0\">cat</div>\n        <div class=\"s-scene-03-token\" data-step=\"0\">sat</div>\n        <!-- The slot for the next token -->\n        <div class=\"s-scene-03-token s-scene-03-slot\" data-step=\"1\">\n          <div class=\"s-scene-03-token-new\" data-step=\"2\">on</div>\n          <div class=\"s-scene-03-cursor\" data-step=\"1\"></div>\n        </div>\n      </div>\n\n      <!-- Logic Indicators -->\n      <div class=\"s-scene-03-logic-overlay\">\n        <!-- Arrow from sequence to slot -->\n        <svg class=\"s-scene-03-arrow-svg\" data-step=\"1\" viewBox=\"0 0 400 60\">\n          <path d=\"M20,30 Q180,60 340,30\" class=\"s-scene-03-path-bg\" />\n          <path d=\"M20,30 Q180,60 340,30\" class=\"s-scene-03-path-active\" />\n          <polygon points=\"340,30 330,25 330,35\" fill=\"#F53501\" />\n        </svg>\n\n        <div class=\"s-scene-03-loop-indicator\" data-step=\"3\">\n          <i data-lucide=\"repeat\"></i>\n          <span>RECURSIVE LOOP ACTIVE</span>\n        </div>\n      </div>\n    </div>\n\n    <!-- Technical Stats -->\n    <div class=\"s-scene-03-stats\" data-step=\"2\">\n      <div class=\"s-scene-03-stat-item\">\n        <span class=\"s-scene-03-stat-label\">PROBABILITY</span>\n        <span class=\"s-scene-03-stat-value\">0.982</span>\n      </div>\n      <div class=\"s-scene-03-stat-item\">\n        <span class=\"s-scene-03-stat-label\">CONTEXT WINDOW</span>\n        <span class=\"s-scene-03-stat-value\">ACTIVE</span>\n      </div>\n    </div>\n  </div>\n</div>","css":".s-scene-03-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #1B1B1B;\n  overflow: hidden;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FFFFFF;\n  font-family: var(--sv-font-body-cn);\n}\n\n.s-scene-03-bg-grid {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);\n  background-size: 50px 50px;\n  z-index: 1;\n}\n\n.s-scene-03-ambient-glow {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 600px;\n  height: 400px;\n  background: radial-gradient(circle, rgba(245, 53, 1, 0.05) 0%, transparent 70%);\n  transform: translate(-50%, -50%);\n  animation: s-03-pulse 8s infinite ease-in-out;\n  z-index: 1;\n}\n\n.s-scene-03-ghost-text {\n  position: absolute;\n  bottom: 5%;\n  right: 5%;\n  font-family: var(--sv-font-display-cn);\n  font-size: 100px;\n  opacity: 0.03;\n  letter-spacing: -2px;\n  z-index: 1;\n}\n\n.s-scene-03-container {\n  position: relative;\n  z-index: 10;\n  width: 80%;\n  display: flex;\n  flex-direction: column;\n  gap: 60px;\n}\n\n.s-scene-03-header {\n  display: flex;\n  flex-direction: column;\n  gap: 10px;\n}\n\n.s-scene-03-tag {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  color: #F53501;\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  letter-spacing: 2px;\n}\n\n.s-scene-03-title {\n  font-family: var(--sv-font-display-cn);\n  font-size: 64px;\n  margin: 0;\n  color: #FFFFFF;\n}\n\n.s-scene-03-sequence-area {\n  position: relative;\n  padding: 40px 0;\n}\n\n.s-scene-03-token-list {\n  display: flex;\n  gap: 15px;\n  align-items: center;\n}\n\n.s-scene-03-token {\n  background: rgba(255, 255, 255, 0.05);\n  border: 1px solid rgba(255, 255, 255, 0.1);\n  padding: 15px 30px;\n  font-size: 32px;\n  font-family: var(--sv-font-display-cn);\n  border-radius: 4px;\n  transition: all 0.5s cubic-bezier(0.22, 1, 0.36, 1);\n  transform: translateY(20px);\n  opacity: 0;\n}\n\n[data-step=\"0\"] .s-scene-03-token:not(.s-scene-03-slot) {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.s-scene-03-slot {\n  min-width: 100px;\n  min-height: 70px;\n  background: rgba(245, 53, 1, 0.05);\n  border: 2px dashed #F53501;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  position: relative;\n}\n\n[data-step=\"1\"] .s-scene-03-slot {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.s-scene-03-token-new {\n  color: #F53501;\n  opacity: 0;\n  transform: scale(0.5);\n}\n\n[data-step=\"2\"] .s-scene-03-token-new {\n  opacity: 1;\n  transform: scale(1);\n  animation: s-03-spring 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;\n}\n\n.s-scene-03-cursor {\n  position: absolute;\n  width: 2px;\n  height: 30px;\n  background: #F53501;\n  animation: s-03-blink 0.8s infinite step-end;\n}\n\n[data-step=\"2\"] .s-scene-03-cursor {\n  display: none;\n}\n\n.s-scene-03-arrow-svg {\n  position: absolute;\n  top: -40px;\n  left: 0;\n  width: 100%;\n  height: 80px;\n  pointer-events: none;\n  opacity: 0;\n}\n\n[data-step=\"1\"] .s-scene-03-arrow-svg {\n  opacity: 1;\n}\n\n.s-scene-03-path-bg {\n  fill: none;\n  stroke: rgba(255, 255, 255, 0.1);\n  stroke-width: 2;\n}\n\n.s-scene-03-path-active {\n  fill: none;\n  stroke: #F53501;\n  stroke-width: 2;\n  stroke-dasharray: 400;\n  stroke-dashoffset: 400;\n  animation: s-03-draw 1.5s ease-out forwards;\n}\n\n.s-scene-03-loop-indicator {\n  position: absolute;\n  top: 100px;\n  left: 50%;\n  transform: translateX(-50%);\n  display: flex;\n  align-items: center;\n  gap: 10px;\n  color: #F53501;\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  opacity: 0;\n}\n\n[data-step=\"3\"] .s-scene-03-loop-indicator {\n  opacity: 1;\n  animation: s-03-fade-in 0.5s ease-out forwards;\n}\n\n.s-scene-03-stats {\n  display: flex;\n  gap: 40px;\n  opacity: 0;\n  transform: translateY(10px);\n  transition: all 0.5s ease-out 0.2s;\n}\n\n[data-step=\"2\"] .s-scene-03-stats {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.s-scene-03-stat-item {\n  display: flex;\n  flex-direction: column;\n  gap: 5px;\n}\n\n.s-scene-03-stat-label {\n  font-size: 12px;\n  color: rgba(255, 255, 255, 0.4);\n  letter-spacing: 1px;\n}\n\n.s-scene-03-stat-value {\n  font-family: var(--sv-font-mono);\n  font-size: 24px;\n  color: #F53501;\n  font-variant-numeric: tabular-nums;\n}\n\n@keyframes s-03-pulse {\n  0%, 100% { opacity: 0.05; transform: translate(-50%, -50%) scale(1); }\n  50% { opacity: 0.12; transform: translate(-50%, -50%) scale(1.1); }\n}\n\n@keyframes s-03-blink {\n  0%, 100% { opacity: 1; }\n  50% { opacity: 0; }\n}\n\n@keyframes s-03-draw {\n  to { stroke-dashoffset: 0; }\n}\n\n@keyframes s-03-spring {\n  0% { transform: scale(0.5); opacity: 0; }\n  100% { transform: scale(1); opacity: 1; }\n}\n\n@keyframes s-03-fade-in {\n  from { opacity: 0; transform: translate(-50%, -10px); }\n  to { opacity: 1; transform: translate(-50%, 0); }\n}","js":"window.SceneLifecycle.register('scene-03', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-03\"]');\n    if (!sceneRoot) return;\n    \n    // Refresh icons\n    window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n    \n    // Stagger initial tokens entry\n    const tokens = sceneRoot.querySelectorAll('.s-scene-03-token:not(.s-scene-03-slot)');\n    tokens.forEach((t, i) => {\n      t.style.transitionDelay = `${i * 0.15}s`;\n    });\n  },\n  step(step) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-03\"]');\n    if (!sceneRoot) return;\n\n    if (step === 3) {\n      // Add a rotation class to the loop icon\n      const loopIcon = sceneRoot.querySelector('.s-scene-03-loop-indicator i');\n      if (loopIcon) {\n        loopIcon.style.animation = 's-03-spin 2s linear infinite';\n      }\n    }\n  }\n});\n\n// Add rotation animation\nif (!document.getElementById('s-03-extra-styles')) {\n  const style = document.createElement('style');\n  style.id = 's-03-extra-styles';\n  style.textContent = `\n    @keyframes s-03-spin {\n      from { transform: rotate(0deg); }\n      to { transform: rotate(360deg); }\n    }\n  `;\n  document.head.appendChild(style);\n}"},{"id":"scene-04","title":"The Inefficiency Problem","steps":3,"html":"<div class=\"s-scene-04-wrapper\">\n  <!-- Ambient Background Layer -->\n  <div class=\"s-scene-04-bg-grid\"></div>\n  <div class=\"s-scene-04-ghost-text\">INEFFICIENT</div>\n  <div class=\"s-scene-04-ambient-glow\"></div>\n\n  <!-- Main Content Area -->\n  <div class=\"s-scene-04-container\">\n    <div class=\"s-scene-04-header\">\n      <div class=\"s-scene-04-tag\">\n        <iconify-icon icon=\"mdi:alert-decagram-outline\"></iconify-icon> COMPUTATIONAL WASTE\n      </div>\n      <h2 class=\"s-scene-04-title\">RE-PROCESSING OVERHEAD</h2>\n    </div>\n\n    <div class=\"s-scene-04-stage\">\n      <!-- Left: Previous Math (Stack of Papers) -->\n      <div class=\"s-scene-04-source-area\" data-step=\"0\">\n        <div class=\"s-scene-04-label\">PREVIOUS CONTEXT</div>\n        <div class=\"s-scene-04-paper-stack\">\n          <div class=\"s-scene-04-paper\" style=\"--i:0\"><span>MATH DATA</span></div>\n          <div class=\"s-scene-04-paper\" style=\"--i:1\"><span>KV TENSORS</span></div>\n          <div class=\"s-scene-04-paper\" style=\"--i:2\"><span>ATTENTION</span></div>\n          <div class=\"s-scene-04-paper s-scene-04-new-page\" data-step=\"1\">\n             <span class=\"s-scene-04-highlight\">NEW WORD</span>\n          </div>\n        </div>\n      </div>\n\n      <!-- Center: The Giant Mechanical Arm (GPU) -->\n      <div class=\"s-scene-04-gpu-unit\" data-step=\"1\">\n        <div class=\"s-scene-04-arm-base\">\n          <div class=\"s-scene-04-mechanical-arm\">\n            <div class=\"s-scene-04-scanner-head\">\n              <div class=\"s-scene-04-laser-beam\"></div>\n            </div>\n          </div>\n        </div>\n        <div class=\"s-scene-04-gpu-core\">\n           <iconify-icon icon=\"simple-icons:nvidia\" class=\"s-scene-04-gpu-icon\"></iconify-icon>\n           <span class=\"s-scene-04-core-label\">GPU ENGINE</span>\n        </div>\n        \n        <!-- Warning Indicators -->\n        <div class=\"s-scene-04-heat-ripples\" data-step=\"2\"></div>\n        <div class=\"s-scene-04-warning-icons\" data-step=\"2\">\n           <iconify-icon icon=\"mdi:fire\" class=\"s-scene-04-alert-icon\"></iconify-icon>\n           <iconify-icon icon=\"mdi:alert\" class=\"s-scene-04-alert-icon\"></iconify-icon>\n        </div>\n      </div>\n\n      <!-- Right: Stats -->\n      <div class=\"s-scene-04-stats-panel\" data-step=\"2\">\n        <div class=\"s-scene-04-stat-card\">\n           <div class=\"s-scene-04-stat-label\">COMPUTE COST</div>\n           <div class=\"s-scene-04-stat-value text-red\">O(N²)</div>\n        </div>\n        <div class=\"s-scene-04-stat-card\">\n           <div class=\"s-scene-04-stat-label\">REDUNDANCY</div>\n           <div class=\"s-scene-04-stat-value\">99.9%</div>\n        </div>\n      </div>\n    </div>\n  </div>\n</div>","css":".s-scene-04-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #1B1B1B;\n  overflow: hidden;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FFFFFF;\n  font-family: var(--sv-font-body-cn);\n}\n\n.s-scene-04-bg-grid {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);\n  background-size: 40px 40px;\n  z-index: 1;\n}\n\n.s-scene-04-ambient-glow {\n  position: absolute;\n  top: 50%;\n  left: 60%;\n  width: 800px;\n  height: 600px;\n  background: radial-gradient(circle, rgba(245, 53, 1, 0.08) 0%, transparent 70%);\n  transform: translate(-50%, -50%);\n  animation: s-04-pulse 10s infinite ease-in-out;\n}\n\n.s-scene-04-ghost-text {\n  position: absolute;\n  top: 10%;\n  left: 5%;\n  font-family: var(--sv-font-display-cn);\n  font-size: 120px;\n  opacity: 0.04;\n  letter-spacing: -4px;\n  z-index: 1;\n}\n\n.s-scene-04-container {\n  position: relative;\n  z-index: 10;\n  width: 90%;\n  max-width: 1200px;\n  display: flex;\n  flex-direction: column;\n  gap: 40px;\n}\n\n.s-scene-04-tag {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  color: #F53501;\n  font-family: var(--sv-font-mono);\n  font-size: 16px;\n  letter-spacing: 2px;\n  margin-bottom: 8px;\n}\n\n.s-scene-04-title {\n  font-family: var(--sv-font-display-cn);\n  font-size: 56px;\n  line-height: 1;\n  margin: 0;\n  color: #FFFFFF;\n}\n\n.s-scene-04-stage {\n  display: grid;\n  grid-template-columns: 1fr 1.5fr 0.8fr;\n  align-items: center;\n  gap: 40px;\n  height: 450px;\n}\n\n/* Paper Stack */\n.s-scene-04-source-area {\n  display: flex;\n  flex-direction: column;\n  gap: 20px;\n}\n\n.s-scene-04-label {\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  color: rgba(255, 255, 255, 0.5);\n  border-left: 2px solid #F53501;\n  padding-left: 12px;\n}\n\n.s-scene-04-paper-stack {\n  position: relative;\n  height: 300px;\n  width: 200px;\n}\n\n.s-scene-04-paper {\n  position: absolute;\n  width: 100%;\n  height: 240px;\n  background: #2A2A2A;\n  border: 1px solid rgba(255, 255, 255, 0.2);\n  border-radius: 4px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  color: rgba(255, 255, 255, 0.4);\n  box-shadow: 0 10px 30px rgba(0,0,0,0.5);\n  transform: translateY(calc(var(--i) * -15px)) translateX(calc(var(--i) * 10px));\n  transition: all 0.5s cubic-bezier(0.22, 1, 0.36, 1);\n}\n\n.s-scene-04-new-page {\n  background: rgba(245, 53, 1, 0.1);\n  border: 2px dashed #F53501;\n  z-index: 10;\n  transform: translateY(-60px) translateX(30px) scale(1.1);\n  opacity: 0;\n}\n\n[data-step=\"1\"] .s-scene-04-new-page {\n  opacity: 1;\n  transform: translateY(-45px) translateX(30px) scale(1);\n}\n\n.s-scene-04-highlight {\n  color: #F53501;\n  font-weight: bold;\n  font-size: 18px;\n}\n\n/* GPU & Mechanical Arm */\n.s-scene-04-gpu-unit {\n  position: relative;\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n}\n\n.s-scene-04-gpu-core {\n  width: 180px;\n  height: 180px;\n  background: linear-gradient(135deg, #2A2A2A 0%, #1B1B1B 100%);\n  border: 2px solid rgba(255,255,255,0.1);\n  border-radius: 12px;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  gap: 15px;\n  z-index: 5;\n  position: relative;\n}\n\n.s-scene-04-gpu-icon {\n  font-size: 64px;\n  color: #F53501;\n}\n\n.s-scene-04-core-label {\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  letter-spacing: 2px;\n  color: rgba(255,255,255,0.8);\n}\n\n.s-scene-04-mechanical-arm {\n  position: absolute;\n  width: 300px;\n  height: 4px;\n  background: #F53501;\n  top: 50%;\n  right: 50%;\n  transform-origin: right center;\n  z-index: 6;\n  opacity: 0;\n}\n\n[data-step=\"1\"] .s-scene-04-mechanical-arm {\n  opacity: 1;\n  animation: s-04-scan-swing 1.5s infinite ease-in-out;\n}\n\n.s-scene-04-scanner-head {\n  position: absolute;\n  left: 0;\n  top: -20px;\n  width: 40px;\n  height: 40px;\n  background: #F53501;\n  border-radius: 4px;\n}\n\n.s-scene-04-laser-beam {\n  position: absolute;\n  left: 20px;\n  top: 40px;\n  width: 2px;\n  height: 200px;\n  background: linear-gradient(to bottom, #F53501, transparent);\n  box-shadow: 0 0 15px #F53501;\n}\n\n/* Warning & Heat */\n.s-scene-04-heat-ripples {\n  position: absolute;\n  inset: -20px;\n  border: 2px solid #F53501;\n  border-radius: 20px;\n  opacity: 0;\n  animation: s-04-heat 1s infinite;\n}\n\n[data-step=\"2\"] .s-scene-04-heat-ripples {\n  opacity: 1;\n}\n\n.s-scene-04-warning-icons {\n  position: absolute;\n  top: -40px;\n  display: flex;\n  gap: 20px;\n}\n\n.s-scene-04-alert-icon {\n  font-size: 32px;\n  color: #F53501;\n  animation: s-04-blink 0.5s infinite alternate;\n}\n\n/* Stats */\n.s-scene-04-stats-panel {\n  display: flex;\n  flex-direction: column;\n  gap: 20px;\n}\n\n.s-scene-04-stat-card {\n  background: rgba(255,255,255,0.03);\n  border: 1px solid rgba(255,255,255,0.1);\n  padding: 20px;\n  border-radius: 8px;\n}\n\n.s-scene-04-stat-label {\n  font-size: 12px;\n  color: rgba(255,255,255,0.5);\n  margin-bottom: 5px;\n}\n\n.s-scene-04-stat-value {\n  font-family: var(--sv-font-display-cn);\n  font-size: 36px;\n}\n\n.text-red { color: #F53501; }\n\n/* Animations */\n@keyframes s-04-pulse {\n  0%, 100% { opacity: 0.08; transform: translate(-50%, -50%) scale(1); }\n  50% { opacity: 0.15; transform: translate(-50%, -50%) scale(1.1); }\n}\n\n@keyframes s-04-scan-swing {\n  0% { transform: rotate(15deg); }\n  50% { transform: rotate(-45deg); }\n  100% { transform: rotate(15deg); }\n}\n\n@keyframes s-04-heat {\n  0% { transform: scale(1); opacity: 0.5; }\n  100% { transform: scale(1.2); opacity: 0; }\n}\n\n@keyframes s-04-blink {\n  from { opacity: 1; transform: scale(1); }\n  to { opacity: 0.5; transform: scale(0.9); }\n}","js":"window.SceneLifecycle.register('scene-04', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-04\"]');\n    if (!sceneRoot) return;\n\n    // Initial paper entry delay\n    const papers = sceneRoot.querySelectorAll('.s-scene-04-paper:not(.s-scene-04-new-page)');\n    papers.forEach((p, i) => {\n      p.style.opacity = '0';\n      p.style.transform += ' translateY(40px)';\n      setTimeout(() => {\n        p.style.opacity = '1';\n        p.style.transform = p.style.transform.replace('translateY(40px)', '');\n      }, i * 150 + 200);\n    });\n\n    window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n  },\n  \n  step(step) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-04\"]');\n    if (!sceneRoot) return;\n\n    if (step === 1) {\n      // Speed up animation when scanning\n      const arm = sceneRoot.querySelector('.s-scene-04-mechanical-arm');\n      if(arm) arm.style.animationDuration = '0.8s';\n    }\n\n    if (step === 2) {\n      // Intense chaotic scanning\n      const arm = sceneRoot.querySelector('.s-scene-04-mechanical-arm');\n      if(arm) arm.style.animationDuration = '0.3s';\n      \n      // Add screen shake effect temporarily\n      sceneRoot.style.animation = 's-04-shake 0.2s infinite';\n    }\n  }\n});\n\n// Add Shake Animation to style\nif (!document.getElementById('s-04-extra-styles')) {\n  const style = document.createElement('style');\n  style.id = 's-04-extra-styles';\n  style.textContent = `\n    @keyframes s-04-shake {\n      0% { transform: translate(1px, 1px); }\n      25% { transform: translate(-1px, -1px); }\n      50% { transform: translate(1px, -1px); }\n      75% { transform: translate(-1px, 1px); }\n      100% { transform: translate(1px, 1px); }\n    }\n  `;\n  document.head.appendChild(style);\n}"},{"id":"scene-05","title":"Enter KV Caching","steps":3,"html":"<div class=\"s-scene-05-wrapper\">\n  <!-- Ambient Layer -->\n  <div class=\"s-scene-05-bg-grid\"></div>\n  <div class=\"s-scene-05-ambient-glow\"></div>\n  <div class=\"s-scene-05-ghost-text\">KV CACHE</div>\n\n  <!-- Main Content Area -->\n  <div class=\"s-scene-05-container\">\n    <div class=\"s-scene-05-header\">\n      <div class=\"s-scene-05-tag\">\n        <iconify-icon icon=\"mdi:memory\"></iconify-icon> EFFICIENCY MODULE\n      </div>\n      <h2 class=\"s-scene-05-title\">KV CACHING ARCHITECTURE</h2>\n    </div>\n\n    <!-- Split Screen Vault Area -->\n    <div class=\"s-scene-05-vault-stage\">\n      \n      <!-- Left: Keys Column -->\n      <div class=\"s-scene-05-vault-column\" data-type=\"keys\">\n        <div class=\"s-scene-05-vault-header\">\n          <span class=\"s-scene-05-vault-label\">KEYS (K)</span>\n          <div class=\"s-scene-05-vault-status\">READY</div>\n        </div>\n        <div class=\"s-scene-05-grid-container\">\n          <div class=\"s-scene-05-grid\" id=\"grid-keys\">\n            <!-- Blocks generated by JS -->\n          </div>\n        </div>\n      </div>\n\n      <!-- Center Interface: Save Pulse -->\n      <div class=\"s-scene-05-center-interface\" data-step=\"2\">\n        <div class=\"s-scene-05-save-ring\">\n          <div class=\"s-scene-05-save-icon-wrap\">\n            <iconify-icon icon=\"mdi:content-save-cog\" class=\"s-scene-05-save-icon\"></iconify-icon>\n          </div>\n          <div class=\"s-scene-05-save-pulse\"></div>\n          <div class=\"s-scene-05-save-text\">CACHING...</div>\n        </div>\n      </div>\n\n      <!-- Right: Values Column -->\n      <div class=\"s-scene-05-vault-column\" data-type=\"values\">\n        <div class=\"s-scene-05-vault-header\">\n          <span class=\"s-scene-05-vault-label\">VALUES (V)</span>\n          <div class=\"s-scene-05-vault-status\">SYNCED</div>\n        </div>\n        <div class=\"s-scene-05-grid-container\">\n          <div class=\"s-scene-05-grid\" id=\"grid-values\">\n            <!-- Blocks generated by JS -->\n          </div>\n        </div>\n      </div>\n\n    </div>\n\n    <!-- Footer Specs -->\n    <div class=\"s-scene-05-footer-specs\" data-step=\"1\">\n       <div class=\"s-scene-05-spec-item\">\n         <span class=\"s-scene-05-spec-name\">MEMORY ALLOCATION</span>\n         <span class=\"s-scene-05-spec-value\">DYNAMIC</span>\n       </div>\n       <div class=\"s-scene-05-spec-item\">\n         <span class=\"s-scene-05-spec-name\">COMPUTATION SAVED</span>\n         <span class=\"s-scene-05-spec-value text-gold\">95%</span>\n       </div>\n    </div>\n  </div>\n</div>","css":".s-scene-05-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #1B1B1B;\n  overflow: hidden;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FFFFFF;\n  font-family: var(--sv-font-body-cn);\n}\n\n.s-scene-05-bg-grid {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(245, 53, 1, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(245, 53, 1, 0.05) 1px, transparent 1px);\n  background-size: 50px 50px;\n  z-index: 1;\n}\n\n.s-scene-05-ambient-glow {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 1200px;\n  height: 800px;\n  background: radial-gradient(circle, rgba(245, 53, 1, 0.05) 0%, transparent 70%);\n  transform: translate(-50%, -50%);\n  pointer-events: none;\n}\n\n.s-scene-05-ghost-text {\n  position: absolute;\n  bottom: 5%;\n  right: 5%;\n  font-family: var(--sv-font-display-cn);\n  font-size: 160px;\n  opacity: 0.03;\n  letter-spacing: -5px;\n  z-index: 1;\n  pointer-events: none;\n}\n\n.s-scene-05-container {\n  position: relative;\n  z-index: 10;\n  width: 90%;\n  max-width: 1300px;\n  display: flex;\n  flex-direction: column;\n  gap: 30px;\n}\n\n.s-scene-05-tag {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  color: #F53501;\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  letter-spacing: 2px;\n  margin-bottom: 8px;\n}\n\n.s-scene-05-title {\n  font-family: var(--sv-font-display-cn);\n  font-size: 52px;\n  line-height: 1;\n  margin: 0;\n  text-transform: uppercase;\n}\n\n.s-scene-05-vault-stage {\n  display: grid;\n  grid-template-columns: 1fr 180px 1fr;\n  gap: 20px;\n  height: 480px;\n  align-items: stretch;\n}\n\n.s-scene-05-vault-column {\n  background: rgba(255, 255, 255, 0.02);\n  border: 1px solid rgba(255, 255, 255, 0.1);\n  border-radius: 8px;\n  display: flex;\n  flex-direction: column;\n  overflow: hidden;\n}\n\n.s-scene-05-vault-header {\n  padding: 15px 20px;\n  border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  background: rgba(255, 255, 255, 0.02);\n}\n\n.s-scene-05-vault-label {\n  font-family: var(--sv-font-display-cn);\n  font-size: 24px;\n  color: #F53501;\n}\n\n.s-scene-05-vault-status {\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  padding: 4px 8px;\n  border: 1px solid rgba(245, 53, 1, 0.4);\n  border-radius: 4px;\n  color: #F53501;\n}\n\n.s-scene-05-grid-container {\n  flex: 1;\n  padding: 20px;\n  display: flex;\n  align-items: flex-start;\n  justify-content: center;\n  overflow: hidden;\n}\n\n.s-scene-05-grid {\n  display: grid;\n  grid-template-columns: repeat(8, 1fr);\n  gap: 8px;\n  width: 100%;\n}\n\n.s-scene-05-data-block {\n  aspect-ratio: 1;\n  background: rgba(245, 53, 1, 0.05);\n  border: 1px solid rgba(255, 255, 255, 0.1);\n  border-radius: 2px;\n  opacity: 0;\n  transform: scale(0.8);\n}\n\n.s-scene-05-data-block.active {\n  opacity: 1;\n  transform: scale(1);\n  background: #F53501;\n  box-shadow: 0 0 15px rgba(245, 53, 1, 0.5);\n  border-color: #FFFFFF;\n  transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n}\n\n.s-scene-05-center-interface {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  opacity: 0;\n  transform: scale(0.9);\n  transition: all 0.5s ease-out;\n}\n\n[data-step=\"2\"] .s-scene-05-center-interface {\n  opacity: 1;\n  transform: scale(1);\n}\n\n.s-scene-05-save-ring {\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 15px;\n}\n\n.s-scene-05-save-icon-wrap {\n  width: 80px;\n  height: 80px;\n  background: #F53501;\n  border-radius: 50%;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  z-index: 2;\n}\n\n.s-scene-05-save-icon {\n  font-size: 40px;\n  color: #FFFFFF;\n}\n\n.s-scene-05-save-pulse {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 80px;\n  height: 80px;\n  border: 2px solid #F53501;\n  border-radius: 50%;\n  animation: s-05-pulse 1.5s infinite;\n}\n\n.s-scene-05-save-text {\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  color: #F53501;\n  letter-spacing: 2px;\n  font-weight: bold;\n}\n\n.s-scene-05-footer-specs {\n  display: flex;\n  gap: 40px;\n  padding-top: 20px;\n  border-top: 1px solid rgba(255, 255, 255, 0.1);\n  opacity: 0;\n  transform: translateY(20px);\n  transition: all 0.5s 0.2s;\n}\n\n[data-step=\"1\"] .s-scene-05-footer-specs {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.s-scene-05-spec-item {\n  display: flex;\n  flex-direction: column;\n  gap: 4px;\n}\n\n.s-scene-05-spec-name {\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  color: rgba(255, 255, 255, 0.4);\n}\n\n.s-scene-05-spec-value {\n  font-family: var(--sv-font-display-cn);\n  font-size: 32px;\n}\n\n.text-gold { color: #F53501; }\n\n@keyframes s-05-pulse {\n  0% { transform: scale(1); opacity: 0.8; }\n  100% { transform: scale(2.2); opacity: 0; }\n}\n\n/* Desktop specific layout tweaks */\n@media (min-width: 1024px) {\n  .s-scene-05-vault-stage {\n     padding: 0 40px;\n  }\n}","js":"window.SceneLifecycle.register('scene-05', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-05\"]');\n    if (!sceneRoot) return;\n\n    const grids = sceneRoot.querySelectorAll('.s-scene-05-grid');\n    grids.forEach(grid => {\n      grid.innerHTML = '';\n      for (let i = 0; i < 48; i++) {\n        const block = document.createElement('div');\n        block.className = 's-scene-05-data-block';\n        grid.appendChild(block);\n      }\n    });\n\n    window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n  },\n\n  step(step) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-05\"]');\n    if (!sceneRoot) return;\n\n    if (step === 1) {\n      // Fill grids with glowing golden blocks\n      const blocks = sceneRoot.querySelectorAll('.s-scene-05-data-block');\n      blocks.forEach((block, index) => {\n        const delay = (index % 8) * 50 + Math.floor(index / 8) * 40;\n        setTimeout(() => {\n          block.classList.add('active');\n          // Randomly vary the glow intensity\n          if (Math.random() > 0.7) {\n            block.style.boxShadow = '0 0 25px #F53501';\n          }\n        }, delay);\n      });\n    }\n\n    if (step === 2) {\n      // Save icon pulsating - CSS animation handles the loop,\n      // we just ensure icons are refreshed if dynamically added\n      window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n      \n      // Add an extra burst effect to the blocks when saved\n      const activeBlocks = sceneRoot.querySelectorAll('.s-scene-05-data-block.active');\n      activeBlocks.forEach((b, i) => {\n        setTimeout(() => {\n          b.style.transform = 'scale(1.1)';\n          setTimeout(() => b.style.transform = 'scale(1)', 200);\n        }, i * 10);\n      });\n    }\n  }\n});"},{"id":"scene-06","title":"The Chef Metaphor","steps":3,"html":"<div class=\"s-scene-06-wrapper\">\n  <!-- Ambient Layer -->\n  <div class=\"s-scene-06-bg-grid\"></div>\n  <div class=\"s-scene-06-ghost-text\">PRE-COMPUTED</div>\n  <div class=\"s-scene-06-ambient-glow\"></div>\n\n  <!-- Main Content Area -->\n  <div class=\"s-scene-06-container\">\n    <!-- Header Section -->\n    <div class=\"s-scene-06-header\">\n      <div class=\"s-scene-06-tag\">\n        <iconify-icon icon=\"mdi:chef-hat\"></iconify-icon> ANALOGY MODE\n      </div>\n      <h2 class=\"s-scene-06-title\">THE EFFICIENCY PRINCIPLE</h2>\n    </div>\n\n    <!-- Main Isometric Stage -->\n    <div class=\"s-scene-06-stage\">\n      \n      <!-- Step 0: The Organized Counter -->\n      <div class=\"s-scene-06-counter\">\n        <div class=\"s-scene-06-iso-group\" data-step=\"0\">\n          <!-- Ingredients Containers -->\n          <div class=\"s-scene-06-container-box\" style=\"--offset: 0\">\n            <div class=\"s-scene-06-label\">K-VECTOR</div>\n            <div class=\"s-scene-06-cube\"></div>\n          </div>\n          <div class=\"s-scene-06-container-box\" style=\"--offset: 1\">\n            <div class=\"s-scene-06-label\">V-VECTOR</div>\n            <div class=\"s-scene-06-cube\"></div>\n          </div>\n          <div class=\"s-scene-06-container-box\" style=\"--offset: 2\">\n            <div class=\"s-scene-06-label\">CONTEXT</div>\n            <div class=\"s-scene-06-cube\"></div>\n          </div>\n        </div>\n\n        <!-- Step 1: The Chef Action & Pot -->\n        <div class=\"s-scene-06-cooking-area\" data-step=\"1\">\n          <div class=\"s-scene-06-chef-arm\">\n             <iconify-icon icon=\"mdi:hand-back-right\" class=\"s-scene-06-hand-icon\"></iconify-icon>\n          </div>\n          <div class=\"s-scene-06-pot-wrap\">\n             <div class=\"s-scene-06-pot-steam\"></div>\n             <iconify-icon icon=\"mdi:pot-steam\" class=\"s-scene-06-pot-icon\"></iconify-icon>\n          </div>\n        </div>\n\n        <!-- Step 2: Ready Status -->\n        <div class=\"s-scene-06-status-overlay\" data-step=\"2\">\n           <div class=\"s-scene-06-checkmark-circle\">\n              <iconify-icon icon=\"mdi:check-bold\"></iconify-icon>\n           </div>\n           <div class=\"s-scene-06-status-text\">RESPONSE READY</div>\n        </div>\n      </div>\n\n      <!-- Info Panel (Side) -->\n      <div class=\"s-scene-06-info-panel\">\n         <div class=\"s-scene-06-metric\" data-step=\"1\">\n            <span class=\"s-scene-06-metric-label\">PROCESS TIME</span>\n            <span class=\"s-scene-06-metric-value\">-90%</span>\n            <div class=\"s-scene-06-progress-bar\"><div class=\"s-scene-06-progress-fill\"></div></div>\n         </div>\n         <div class=\"s-scene-06-quote\" data-step=\"0\">\n            PRE-CHOPPED INGREDIENTS SAVES TIME FOR EVERY ORDER.\n         </div>\n      </div>\n    </div>\n  </div>\n</div>","css":".s-scene-06-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #1B1B1B;\n  overflow: hidden;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: #FFFFFF;\n  font-family: var(--sv-font-body-cn);\n}\n\n.s-scene-06-bg-grid {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(245, 53, 1, 0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(245, 53, 1, 0.05) 1px, transparent 1px);\n  background-size: 60px 60px;\n  z-index: 1;\n}\n\n.s-scene-06-ghost-text {\n  position: absolute;\n  top: 10%;\n  left: 5%;\n  font-family: var(--sv-font-display-cn);\n  font-size: 120px;\n  opacity: 0.03;\n  letter-spacing: -2px;\n  pointer-events: none;\n  z-index: 1;\n}\n\n.s-scene-06-ambient-glow {\n  position: absolute;\n  width: 800px;\n  height: 800px;\n  background: radial-gradient(circle, rgba(245, 53, 1, 0.08) 0%, transparent 70%);\n  filter: blur(60px);\n  animation: s-06-float 15s infinite ease-in-out;\n}\n\n.s-scene-06-container {\n  position: relative;\n  z-index: 10;\n  width: 90%;\n  max-width: 1200px;\n}\n\n.s-scene-06-header {\n  margin-bottom: 40px;\n}\n\n.s-scene-06-tag {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  color: #F53501;\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  letter-spacing: 2px;\n  margin-bottom: 8px;\n}\n\n.s-scene-06-title {\n  font-family: var(--sv-font-display-cn);\n  font-size: 56px;\n  margin: 0;\n  line-height: 1;\n  text-transform: uppercase;\n}\n\n.s-scene-06-stage {\n  display: grid;\n  grid-template-columns: 1.2fr 0.8fr;\n  gap: 60px;\n  align-items: center;\n}\n\n.s-scene-06-counter {\n  position: relative;\n  height: 400px;\n  background: rgba(255, 255, 255, 0.02);\n  border: 1px solid rgba(255, 255, 255, 0.05);\n  border-radius: 12px;\n  perspective: 1000px;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n}\n\n.s-scene-06-iso-group {\n  display: flex;\n  gap: 20px;\n  transform: rotateX(45deg) rotateZ(-20deg);\n}\n\n.s-scene-06-container-box {\n  position: relative;\n  width: 100px;\n  height: 100px;\n  background: rgba(245, 53, 1, 0.1);\n  border: 2px solid #F53501;\n  border-radius: 8px;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n  transition-delay: calc(var(--offset) * 0.1s);\n}\n\n.s-scene-06-label {\n  font-family: var(--sv-font-mono);\n  font-size: 10px;\n  color: #F53501;\n  position: absolute;\n  top: -25px;\n  white-space: nowrap;\n  background: rgba(0,0,0,0.5);\n  padding: 2px 6px;\n}\n\n.s-scene-06-cube {\n  width: 40px;\n  height: 40px;\n  background: #F53501;\n  box-shadow: 0 0 20px rgba(245, 53, 1, 0.4);\n  transform: translateZ(20px);\n}\n\n.s-scene-06-cooking-area {\n  position: absolute;\n  right: 15%;\n  bottom: 20%;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n}\n\n.s-scene-06-pot-icon {\n  font-size: 100px;\n  color: #FFFFFF;\n  filter: drop-shadow(0 0 15px rgba(255,255,255,0.2));\n}\n\n.s-scene-06-chef-arm {\n  position: absolute;\n  top: -80px;\n  right: -50px;\n  font-size: 60px;\n  color: #F53501;\n  opacity: 0;\n}\n\n[data-step=\"1\"] .s-scene-06-chef-arm {\n  opacity: 1;\n  animation: s-06-grab 1.2s infinite ease-in-out;\n}\n\n.s-scene-06-status-overlay {\n  position: absolute;\n  inset: 0;\n  background: rgba(27, 27, 27, 0.8);\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  backdrop-filter: blur(8px);\n  z-index: 20;\n}\n\n.s-scene-06-checkmark-circle {\n  width: 100px;\n  height: 100px;\n  border-radius: 50%;\n  background: #F53501;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  font-size: 60px;\n  margin-bottom: 20px;\n  box-shadow: 0 0 40px rgba(245, 53, 1, 0.4);\n  animation: s-06-pop 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n}\n\n.s-scene-06-status-text {\n  font-family: var(--sv-font-display-cn);\n  font-size: 32px;\n  letter-spacing: 2px;\n}\n\n.s-scene-06-info-panel {\n  display: flex;\n  flex-direction: column;\n  gap: 30px;\n}\n\n.s-scene-06-metric {\n  border-left: 4px solid #F53501;\n  padding-left: 20px;\n}\n\n.s-scene-06-metric-label {\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  color: rgba(255, 255, 255, 0.5);\n  display: block;\n}\n\n.s-scene-06-metric-value {\n  font-family: var(--sv-font-display-cn);\n  font-size: 64px;\n  color: #F53501;\n  line-height: 1;\n}\n\n.s-scene-06-progress-bar {\n  width: 100%;\n  height: 4px;\n  background: rgba(255, 255, 255, 0.1);\n  margin-top: 10px;\n}\n\n.s-scene-06-progress-fill {\n  width: 0%;\n  height: 100%;\n  background: #F53501;\n  transition: width 1s ease-out;\n}\n\n[data-step=\"1\"] .s-scene-06-progress-fill {\n  width: 90%;\n}\n\n.s-scene-06-quote {\n  font-size: 20px;\n  line-height: 1.5;\n  opacity: 0.8;\n  font-style: italic;\n  border-top: 1px solid rgba(255, 255, 255, 0.1);\n  padding-top: 20px;\n}\n\n/* Animations */\n@keyframes s-06-float {\n  0%, 100% { transform: translate(-20%, -20%) scale(1); }\n  50% { transform: translate(-10%, -10%) scale(1.1); }\n}\n\n@keyframes s-06-grab {\n  0% { transform: translate(0, 0) rotate(0deg); }\n  30% { transform: translate(-150px, 80px) rotate(-20deg); }\n  60% { transform: translate(-150px, 80px) rotate(-20deg) scale(0.9); }\n  100% { transform: translate(0, 0) rotate(0deg); }\n}\n\n@keyframes s-06-pop {\n  0% { transform: scale(0); opacity: 0; }\n  100% { transform: scale(1); opacity: 1; }\n}\n\n[data-step] {\n  transition: all 0.5s ease-out;\n  opacity: 0;\n  transform: translateY(20px);\n}\n\n[data-step].active {\n  opacity: 1;\n  transform: translateY(0);\n}","js":"window.SceneLifecycle.register('scene-06', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-06\"]');\n    if (!sceneRoot) return;\n    \n    // Initial state setup\n    this.step(0);\n    window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n  },\n\n  step(step) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-06\"]');\n    if (!sceneRoot) return;\n\n    // Manage step visibility\n    const elements = sceneRoot.querySelectorAll('[data-step]');\n    elements.forEach(el => {\n      const elStep = parseInt(el.getAttribute('data-step'));\n      if (step >= elStep) {\n        el.classList.add('active');\n        el.style.visibility = 'visible';\n      } else {\n        el.classList.remove('active');\n        el.style.visibility = 'hidden';\n      }\n    });\n\n    // Step-specific logic\n    if (step === 1) {\n      const cubes = sceneRoot.querySelectorAll('.s-scene-06-cube');\n      cubes.forEach((cube, idx) => {\n         setTimeout(() => {\n           cube.style.transform = 'translateZ(60px) scale(1.1)';\n           setTimeout(() => {\n             cube.style.transform = 'translateZ(20px) scale(1)';\n           }, 500);\n         }, idx * 200);\n      });\n    }\n    \n    if (step === 2) {\n      // Trigger success sound or feedback if any\n    }\n\n    window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n  }\n});"},{"id":"scene-07","title":"Prompt Caching","steps":3,"html":"<div class=\"s-scene-07-wrapper\">\n  <!-- Ambient Layer -->\n  <div class=\"s-scene-07-bg-grid\"></div>\n  <div class=\"s-scene-07-ambient-glow\"></div>\n  <div class=\"s-scene-07-ghost-text\">LONG-TERM MEMORY</div>\n\n  <div class=\"s-scene-07-main\">\n    <!-- Header -->\n    <div class=\"s-scene-07-header\">\n       <div class=\"s-scene-07-badge\">\n          <iconify-icon icon=\"ph:seal-check-fill\"></iconify-icon>\n          OPTIMIZED RETRIEVAL\n       </div>\n       <h1 class=\"s-scene-07-title\">PROMPT CACHING</h1>\n    </div>\n\n    <!-- Central Visual Area -->\n    <div class=\"s-scene-07-canvas\">\n      \n      <!-- Step 0: The Document System Prompt -->\n      <div class=\"s-scene-07-doc-container\" data-step=\"0\">\n        <div class=\"s-scene-07-doc-card\">\n           <div class=\"s-scene-07-doc-frost\"></div>\n           <iconify-icon icon=\"ph:file-text-bold\" class=\"s-scene-07-doc-icon\"></iconify-icon>\n           <div class=\"s-scene-07-doc-label\">SYSTEM PROMPT</div>\n           <div class=\"s-scene-07-doc-lines\">\n             <div class=\"s-scene-07-line\"></div>\n             <div class=\"s-scene-07-line\"></div>\n             <div class=\"s-scene-07-line width-short\"></div>\n           </div>\n           <!-- Step 1: Frost Overlay -->\n           <div class=\"s-scene-07-lock-overlay\" data-step=\"1\">\n              <iconify-icon icon=\"ph:snowflake-bold\" class=\"s-scene-07-ice-icon\"></iconify-icon>\n              <span class=\"s-scene-07-lock-tag\">CACHED & FROZEN</span>\n           </div>\n        </div>\n      </div>\n\n      <!-- Step 2: Multiple Conversations -->\n      <div class=\"s-scene-07-chats-grid\" data-step=\"2\">\n         <div class=\"s-scene-07-chat-node\" style=\"--i: 0\">\n            <div class=\"s-scene-07-link-line\"></div>\n            <div class=\"s-scene-07-bubble\">\n               <iconify-icon icon=\"ph:chat-teardrop-dots-bold\"></iconify-icon>\n               <span>SESSION A</span>\n            </div>\n         </div>\n         <div class=\"s-scene-07-chat-node\" style=\"--i: 1\">\n            <div class=\"s-scene-07-link-line\"></div>\n            <div class=\"s-scene-07-bubble\">\n               <iconify-icon icon=\"ph:chat-teardrop-dots-bold\"></iconify-icon>\n               <span>SESSION B</span>\n            </div>\n         </div>\n         <div class=\"s-scene-07-chat-node\" style=\"--i: 2\">\n            <div class=\"s-scene-07-link-line\"></div>\n            <div class=\"s-scene-07-bubble\">\n               <iconify-icon icon=\"ph:chat-teardrop-dots-bold\"></iconify-icon>\n               <span>SESSION C</span>\n            </div>\n         </div>\n      </div>\n    </div>\n\n    <!-- Side Info Panel -->\n    <div class=\"s-scene-07-side-info\">\n       <div class=\"s-scene-07-stat-block\" data-step=\"1\">\n          <span class=\"s-scene-07-stat-label\">REUSE STATUS</span>\n          <span class=\"s-scene-07-stat-value\">READY</span>\n          <div class=\"s-scene-07-status-indicator\"></div>\n       </div>\n       <div class=\"s-scene-07-desc\" data-step=\"0\">\n          RETAINING CONTEXT ACROSS MULTIPLE SESSIONS WITHOUT RE-PROCESSING.\n       </div>\n    </div>\n  </div>\n</div>","css":".s-scene-07-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #1B1B1B;\n  overflow: hidden;\n  color: #FFFFFF;\n  font-family: var(--sv-font-body-cn);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.s-scene-07-bg-grid {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(245, 53, 1, 0.05) 1px, transparent 1px), \n                    linear-gradient(90deg, rgba(245, 53, 1, 0.05) 1px, transparent 1px);\n  background-size: 50px 50px;\n  z-index: 1;\n}\n\n.s-scene-07-ambient-glow {\n  position: absolute;\n  width: 120%;\n  height: 120%;\n  background: radial-gradient(circle at 70% 30%, rgba(245, 53, 1, 0.08) 0%, transparent 60%);\n  z-index: 2;\n  animation: s-07-glow-pulse 10s infinite ease-in-out;\n}\n\n.s-scene-07-ghost-text {\n  position: absolute;\n  bottom: 5%;\n  right: 5%;\n  font-family: var(--sv-font-display-cn);\n  font-size: 80px;\n  color: #FFFFFF;\n  opacity: 0.04;\n  pointer-events: none;\n}\n\n.s-scene-07-main {\n  position: relative;\n  z-index: 10;\n  width: 90%;\n  max-width: 1200px;\n  height: 80%;\n  display: grid;\n  grid-template-columns: 1fr 300px;\n  grid-template-rows: auto 1fr;\n  gap: 40px;\n}\n\n.s-scene-07-header {\n  grid-column: 1 / -1;\n}\n\n.s-scene-07-badge {\n  display: inline-flex;\n  align-items: center;\n  gap: 8px;\n  background: rgba(245, 53, 1, 0.1);\n  border: 1px solid #F53501;\n  color: #F53501;\n  padding: 4px 12px;\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  margin-bottom: 12px;\n}\n\n.s-scene-07-title {\n  font-family: var(--sv-font-display-cn);\n  font-size: 64px;\n  margin: 0;\n  text-transform: uppercase;\n  letter-spacing: -1px;\n}\n\n.s-scene-07-canvas {\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  padding-top: 40px;\n}\n\n/* Document Card */\n.s-scene-07-doc-card {\n  position: relative;\n  width: 200px;\n  height: 260px;\n  background: rgba(255, 255, 255, 0.05);\n  border: 1px solid rgba(255, 255, 255, 0.2);\n  border-radius: 4px;\n  padding: 24px;\n  display: flex;\n  flex-direction: column;\n  gap: 15px;\n  box-shadow: 0 20px 40px rgba(0,0,0,0.4);\n  z-index: 5;\n}\n\n.s-scene-07-doc-icon { font-size: 40px; color: #F53501; }\n.s-scene-07-doc-label {\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  opacity: 0.6;\n}\n\n.s-scene-07-doc-lines .s-scene-07-line {\n  height: 4px;\n  background: rgba(255,255,255,0.1);\n  margin-bottom: 8px;\n  border-radius: 2px;\n}\n.s-scene-07-line.width-short { width: 60%; }\n\n/* Step 1: Frost/Lock */\n.s-scene-07-lock-overlay {\n  position: absolute;\n  inset: 0;\n  background: rgba(180, 220, 255, 0.15);\n  backdrop-filter: blur(4px);\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  opacity: 0;\n  transform: scale(1.1);\n  transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);\n  border: 2px solid #50a3ff;\n}\n\n[data-step=\"1\"].active .s-scene-07-lock-overlay {\n  opacity: 1;\n  transform: scale(1);\n}\n\n.s-scene-07-ice-icon {\n  font-size: 60px;\n  color: #50a3ff;\n  filter: drop-shadow(0 0 10px rgba(80, 163, 255, 0.5));\n  animation: s-07-rotate 10s linear infinite;\n}\n\n.s-scene-07-lock-tag {\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  color: #50a3ff;\n  margin-top: 10px;\n  font-weight: bold;\n}\n\n/* Step 2: Connections */\n.s-scene-07-chats-grid {\n  display: flex;\n  gap: 60px;\n  margin-top: 80px;\n  width: 100%;\n  justify-content: center;\n}\n\n.s-scene-07-chat-node {\n  position: relative;\n  opacity: 0;\n  transform: translateY(20px);\n  transition: all 0.5s ease-out;\n  transition-delay: calc(var(--i) * 0.15s);\n}\n\n[data-step=\"2\"].active .s-scene-07-chat-node {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.s-scene-07-link-line {\n  position: absolute;\n  top: -80px;\n  left: 50%;\n  width: 2px;\n  height: 80px;\n  background: linear-gradient(to bottom, #50a3ff, transparent);\n  transform: translateX(-50%);\n}\n\n.s-scene-07-bubble {\n  background: #252525;\n  border: 1px solid rgba(255,255,255,0.1);\n  padding: 12px 20px;\n  border-radius: 30px;\n  display: flex;\n  align-items: center;\n  gap: 10px;\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  box-shadow: 0 10px 20px rgba(0,0,0,0.3);\n}\n\n.s-scene-07-bubble iconify-icon {\n  color: #F53501;\n}\n\n/* Side Panel */\n.s-scene-07-side-info {\n  display: flex;\n  flex-direction: column;\n  gap: 30px;\n  border-left: 1px solid rgba(255,255,255,0.1);\n  padding-left: 30px;\n}\n\n.s-scene-07-stat-block {\n  padding: 20px;\n  background: rgba(245, 53, 1, 0.03);\n  border-radius: 8px;\n}\n\n.s-scene-07-stat-label {\n  font-size: 12px;\n  font-family: var(--sv-font-mono);\n  opacity: 0.5;\n  display: block;\n}\n\n.s-scene-07-stat-value {\n  font-size: 40px;\n  font-family: var(--sv-font-display-cn);\n  color: #F53501;\n}\n\n.s-scene-07-status-indicator {\n  width: 100%;\n  height: 4px;\n  background: #F53501;\n  margin-top: 10px;\n  box-shadow: 0 0 10px #F53501;\n}\n\n.s-scene-07-desc {\n  font-size: 18px;\n  line-height: 1.6;\n  color: rgba(255,255,255,0.7);\n}\n\n/* Animation Keyframes */\n@keyframes s-07-glow-pulse {\n  0%, 100% { opacity: 0.5; }\n  50% { opacity: 1; }\n}\n\n@keyframes s-07-rotate {\n  from { transform: rotate(0deg); }\n  to { transform: rotate(360deg); }\n}\n\n[data-step] {\n  transition: all 0.6s cubic-bezier(0.22, 1, 0.36, 1);\n  opacity: 0;\n  transform: translateY(30px);\n}\n\n[data-step].active {\n  opacity: 1;\n  transform: translateY(0);\n}","js":"window.SceneLifecycle.register('scene-07', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-07\"]');\n    if (!sceneRoot) return;\n    \n    // Initial state\n    const steps = sceneRoot.querySelectorAll('[data-step]');\n    steps.forEach(s => s.classList.remove('active'));\n    \n    this.step(0);\n  },\n\n  step(stepIndex) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-07\"]');\n    if (!sceneRoot) return;\n\n    const steps = sceneRoot.querySelectorAll('[data-step]');\n    steps.forEach(el => {\n      const elStep = parseInt(el.getAttribute('data-step'));\n      if (stepIndex >= elStep) {\n        el.classList.add('active');\n      } else {\n        el.classList.remove('active');\n      }\n    });\n\n    // Specific logic for Step 1 (Frost effect)\n    if (stepIndex === 1) {\n      const docCard = sceneRoot.querySelector('.s-scene-07-doc-card');\n      if (docCard) {\n        docCard.style.transform = 'scale(1.05)';\n        setTimeout(() => {\n          docCard.style.transform = 'scale(1)';\n        }, 400);\n      }\n    }\n\n    window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n  }\n});"},{"id":"scene-08","title":"The Speed Result","steps":2,"html":"<div class=\"s-scene-08-wrapper\">\n  <!-- Ambient Layer -->\n  <div class=\"s-scene-08-bg-grid\"></div>\n  <div class=\"s-scene-08-ambient-glow\"></div>\n  <div class=\"s-scene-08-ghost-text\">PERFORMANCE</div>\n\n  <div class=\"s-scene-08-main\">\n    <!-- Top Section: Header -->\n    <div class=\"s-scene-08-header\">\n      <div class=\"s-scene-08-badge\">\n        <iconify-icon icon=\"ph:speedometer-fill\"></iconify-icon>\n        LATENCY BENCHMARK\n      </div>\n      <h1 class=\"s-scene-08-title\">TTFT REDUCTION</h1>\n    </div>\n\n    <!-- Middle Section: Performance Chart Area -->\n    <div class=\"s-scene-08-content\">\n      <div class=\"s-scene-08-chart-container\">\n        <!-- Standard Row -->\n        <div class=\"s-scene-08-bar-group\" data-type=\"standard\">\n          <div class=\"s-scene-08-bar-info\">\n            <span class=\"s-scene-08-bar-label\">STANDARD REQUEST</span>\n            <span class=\"s-scene-08-bar-value\" id=\"val-standard\">0ms</span>\n          </div>\n          <div class=\"s-scene-08-bar-track\">\n            <div class=\"s-scene-08-bar-fill\" id=\"fill-standard\"></div>\n          </div>\n        </div>\n\n        <!-- Cached Row -->\n        <div class=\"s-scene-08-bar-group\" data-type=\"cached\">\n          <div class=\"s-scene-08-bar-info\">\n            <span class=\"s-scene-08-bar-label\">WITH PROMPT CACHE</span>\n            <span class=\"s-scene-08-bar-value\" id=\"val-cached\">0ms</span>\n          </div>\n          <div class=\"s-scene-08-bar-track\">\n            <div class=\"s-scene-08-bar-fill\" id=\"fill-cached\"></div>\n          </div>\n        </div>\n      </div>\n\n      <!-- Step 1: Big Impact Label -->\n      <div class=\"s-scene-08-impact-zone\" data-step=\"1\">\n        <div class=\"s-scene-08-impact-card\">\n          <div class=\"s-scene-08-burst-container\">\n            <div class=\"s-scene-08-particle\"></div>\n            <div class=\"s-scene-08-particle\"></div>\n            <div class=\"s-scene-08-particle\"></div>\n            <div class=\"s-scene-08-particle\"></div>\n          </div>\n          <div class=\"s-scene-08-impact-title\">TTFT REDUCED</div>\n          <div class=\"s-scene-08-impact-stat\">UP TO 90%</div>\n          <div class=\"s-scene-08-impact-line\"></div>\n        </div>\n      </div>\n    </div>\n\n    <!-- Bottom Info -->\n    <div class=\"s-scene-08-footer\">\n      <div class=\"s-scene-08-metric\">\n        <span class=\"s-scene-08-m-label\">EFFICIENCY</span>\n        <span class=\"s-scene-08-m-val\">MAXIMIZED</span>\n      </div>\n      <div class=\"s-scene-08-divider\"></div>\n      <div class=\"s-scene-08-metric\">\n        <span class=\"s-scene-08-m-label\">RESPONSE</span>\n        <span class=\"s-scene-08-m-val\">INSTANT</span>\n      </div>\n    </div>\n  </div>\n</div>","css":".s-scene-08-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #1B1B1B;\n  overflow: hidden;\n  color: #FFFFFF;\n  font-family: var(--sv-font-body-cn);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.s-scene-08-bg-grid {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(245, 53, 1, 0.05) 1px, transparent 1px), \n                    linear-gradient(90deg, rgba(245, 53, 1, 0.05) 1px, transparent 1px);\n  background-size: 40px 40px;\n  z-index: 1;\n}\n\n.s-scene-08-ambient-glow {\n  position: absolute;\n  width: 100%;\n  height: 100%;\n  background: radial-gradient(circle at 80% 20%, rgba(245, 53, 1, 0.1) 0%, transparent 50%);\n  z-index: 2;\n  animation: s-08-glow 8s infinite alternate ease-in-out;\n}\n\n.s-scene-08-ghost-text {\n  position: absolute;\n  top: 10%;\n  left: 5%;\n  font-family: var(--sv-font-display-cn);\n  font-size: 120px;\n  color: #FFFFFF;\n  opacity: 0.03;\n  pointer-events: none;\n  letter-spacing: -2px;\n}\n\n.s-scene-08-main {\n  position: relative;\n  z-index: 10;\n  width: 85%;\n  max-width: 1100px;\n  display: flex;\n  flex-direction: column;\n  gap: 60px;\n}\n\n.s-scene-08-badge {\n  display: inline-flex;\n  align-items: center;\n  gap: 8px;\n  background: rgba(245, 53, 1, 0.1);\n  border-left: 3px solid #F53501;\n  color: #F53501;\n  padding: 6px 16px;\n  font-family: var(--sv-font-mono);\n  font-size: 14px;\n  margin-bottom: 15px;\n}\n\n.s-scene-08-title {\n  font-family: var(--sv-font-display-cn);\n  font-size: 72px;\n  margin: 0;\n  text-transform: uppercase;\n  line-height: 1;\n}\n\n.s-scene-08-content {\n  display: grid;\n  grid-template-columns: 1.2fr 0.8fr;\n  gap: 50px;\n  align-items: center;\n}\n\n.s-scene-08-chart-container {\n  display: flex;\n  flex-direction: column;\n  gap: 40px;\n}\n\n.s-scene-08-bar-group {\n  width: 100%;\n}\n\n.s-scene-08-bar-info {\n  display: flex;\n  justify-content: space-between;\n  margin-bottom: 12px;\n  font-family: var(--sv-font-mono);\n  font-size: 16px;\n}\n\n.s-scene-08-bar-label {\n  opacity: 0.7;\n}\n\n.s-scene-08-bar-value {\n  font-weight: bold;\n  font-variant-numeric: tabular-nums;\n}\n\n.s-scene-08-bar-track {\n  height: 40px;\n  background: rgba(255, 255, 255, 0.05);\n  border: 1px solid rgba(255, 255, 255, 0.1);\n  position: relative;\n  overflow: hidden;\n}\n\n.s-scene-08-bar-fill {\n  position: absolute;\n  left: 0;\n  top: 0;\n  height: 100%;\n  width: 0%;\n  background: #FFFFFF;\n  transition: width 3s linear;\n}\n\n[data-type=\"cached\"] .s-scene-08-bar-fill {\n  background: #F53501;\n  box-shadow: 0 0 20px rgba(245, 53, 1, 0.4);\n  transition: width 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n/* Impact Card */\n.s-scene-08-impact-zone {\n  opacity: 0;\n  transform: translateX(40px);\n  transition: all 0.6s cubic-bezier(0.22, 1, 0.36, 1);\n}\n\n.s-scene-08-impact-zone.active {\n  opacity: 1;\n  transform: translateX(0);\n}\n\n.s-scene-08-impact-card {\n  background: #F53501;\n  padding: 40px;\n  position: relative;\n  text-align: center;\n}\n\n.s-scene-08-impact-title {\n  font-family: var(--sv-font-mono);\n  font-size: 18px;\n  color: #1B1B1B;\n  font-weight: 900;\n  margin-bottom: 5px;\n}\n\n.s-scene-08-impact-stat {\n  font-family: var(--sv-font-display-cn);\n  font-size: 64px;\n  color: #FFFFFF;\n  line-height: 1;\n}\n\n.s-scene-08-impact-line {\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  width: 100%;\n  height: 6px;\n  background: #FFFFFF;\n  transform: scaleX(0);\n  transition: transform 0.8s ease 0.4s;\n  transform-origin: left;\n}\n\n.s-scene-08-impact-zone.active .s-scene-08-impact-line {\n  transform: scaleX(1);\n}\n\n/* Particles */\n.s-scene-08-burst-container {\n  position: absolute;\n  inset: 0;\n  pointer-events: none;\n}\n\n.s-scene-08-particle {\n  position: absolute;\n  width: 10px;\n  height: 10px;\n  background: #F53501;\n  top: 50%;\n  left: 50%;\n  opacity: 0;\n}\n\n.active .s-scene-08-particle {\n  animation: s-08-burst 0.8s ease-out forwards;\n}\n\n.s-scene-08-footer {\n  display: flex;\n  gap: 40px;\n  border-top: 1px solid rgba(255, 255, 255, 0.1);\n  padding-top: 30px;\n}\n\n.s-scene-08-metric {\n  display: flex;\n  flex-direction: column;\n}\n\n.s-scene-08-m-label {\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  opacity: 0.5;\n}\n\n.s-scene-08-m-val {\n  font-size: 24px;\n  font-weight: bold;\n  color: #F53501;\n}\n\n@keyframes s-08-glow {\n  from { opacity: 0.5; transform: scale(1); }\n  to { opacity: 1; transform: scale(1.1); }\n}\n\n@keyframes s-08-burst {\n  0% { transform: translate(-50%, -50%) scale(1); opacity: 1; }\n  100% { transform: translate(calc(-50% + var(--tx)), calc(-50% + var(--ty))) scale(0); opacity: 0; }\n}\n\n.s-scene-08-particle:nth-child(1) { --tx: -100px; --ty: -80px; }\n.s-scene-08-particle:nth-child(2) { --tx: 100px; --ty: -80px; }\n.s-scene-08-particle:nth-child(3) { --tx: -80px; --ty: 80px; }\n.s-scene-08-particle:nth-child(4) { --tx: 80px; --ty: 80px; }","js":"window.SceneLifecycle.register('scene-08', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-08\"]');\n    if (!sceneRoot) return;\n\n    // Reset elements\n    const standardFill = sceneRoot.querySelector('#fill-standard');\n    const cachedFill = sceneRoot.querySelector('#fill-cached');\n    const standardVal = sceneRoot.querySelector('#val-standard');\n    const cachedVal = sceneRoot.querySelector('#val-cached');\n\n    standardFill.style.width = '0%';\n    cachedFill.style.width = '0%';\n    standardVal.textContent = '0ms';\n    cachedVal.textContent = '0ms';\n\n    this.step(0);\n  },\n\n  step(stepIndex) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-08\"]');\n    if (!sceneRoot) return;\n\n    const steps = sceneRoot.querySelectorAll('[data-step]');\n    steps.forEach(el => {\n      const elStep = parseInt(el.getAttribute('data-step'));\n      el.classList.toggle('active', stepIndex >= elStep);\n    });\n\n    const standardFill = sceneRoot.querySelector('#fill-standard');\n    const cachedFill = sceneRoot.querySelector('#fill-cached');\n    const standardVal = sceneRoot.querySelector('#val-standard');\n    const cachedVal = sceneRoot.querySelector('#val-cached');\n\n    if (stepIndex >= 0) {\n      // Standard bar fills slowly\n      standardFill.style.transition = 'width 4s cubic-bezier(0.1, 0, 0.2, 1)';\n      standardFill.style.width = '100%';\n\n      // Cached bar jumps instantly\n      cachedFill.style.width = '100%';\n\n      // Counter animations\n      this.animateCounter(standardVal, 2400, 4000);\n      this.animateCounter(cachedVal, 150, 300);\n    }\n\n    window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n  },\n\n  animateCounter(el, target, duration) {\n    let start = 0;\n    const startTime = performance.now();\n\n    const update = (now) => {\n      const progress = Math.min((now - startTime) / duration, 1);\n      const current = Math.floor(progress * target);\n      el.textContent = `${current}ms`;\n      if (progress < 1) requestAnimationFrame(update);\n    };\n    requestAnimationFrame(update);\n  }\n});"},{"id":"scene-09","title":"Conclusion: Real-time Intelligence","steps":3,"html":"<div class=\"s-scene-09-wrapper\">\n  <!-- Ambient Background Layer -->\n  <div class=\"s-scene-09-bg-grid\"></div>\n  <div class=\"s-scene-09-ambient-glow\"></div>\n  <div class=\"s-scene-09-ghost-text\">INTELLIGENCE</div>\n\n  <div class=\"s-scene-09-container\">\n    <!-- Step 0: The Central Brain Core -->\n    <div class=\"s-scene-09-core-zone\">\n      <div class=\"s-scene-09-circuit-brain\">\n        <!-- Glowing Brain Icon via Iconify -->\n        <iconify-icon icon=\"ph:brain-duotone\" class=\"s-scene-09-brain-icon\"></iconify-icon>\n        \n        <!-- Light Ray Particles (Step 2) -->\n        <div class=\"s-scene-09-rays-container\" data-step=\"2\">\n          <div class=\"s-scene-09-ray\"></div>\n          <div class=\"s-scene-09-ray\"></div>\n          <div class=\"s-scene-09-ray\"></div>\n          <div class=\"s-scene-09-ray\"></div>\n          <div class=\"s-scene-09-ray\"></div>\n          <div class=\"s-scene-09-ray\"></div>\n          <div class=\"s-scene-09-ray\"></div>\n          <div class=\"s-scene-09-ray\"></div>\n        </div>\n\n        <!-- Circular Scanning Rings -->\n        <div class=\"s-scene-09-ring s-scene-09-ring-1\"></div>\n        <div class=\"s-scene-09-ring s-scene-09-ring-2\"></div>\n      </div>\n    </div>\n\n    <!-- Step 1: Text Fade In -->\n    <div class=\"s-scene-09-text-zone\" data-step=\"1\">\n      <h1 class=\"s-scene-09-hero-title\">INTELLIGENCE</h1>\n      <div class=\"s-scene-09-subtitle-bar\">\n        <span class=\"s-scene-09-tag\">REAL-TIME FOUNDATION</span>\n        <div class=\"s-scene-09-line\"></div>\n        <span class=\"s-scene-09-tag\">CACHING REVOLUTION</span>\n      </div>\n    </div>\n  </div>\n\n  <!-- UI Decorative Elements -->\n  <div class=\"s-scene-09-corner s-scene-09-tl\">[ SYS_FINAL ]</div>\n  <div class=\"s-scene-09-corner s-scene-09-br\">0x00_COMPLETE</div>\n</div>","css":".s-scene-09-wrapper {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #1B1B1B;\n  overflow: hidden;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  color: #FFFFFF;\n  font-family: var(--sv-font-body-cn);\n}\n\n/* Background Decor */\n.s-scene-09-bg-grid {\n  position: absolute;\n  inset: 0;\n  background-image: linear-gradient(rgba(245, 53, 1, 0.05) 1px, transparent 1px), \n                    linear-gradient(90deg, rgba(245, 53, 1, 0.05) 1px, transparent 1px);\n  background-size: 50px 50px;\n  z-index: 1;\n}\n\n.s-scene-09-ambient-glow {\n  position: absolute;\n  width: 800px;\n  height: 800px;\n  background: radial-gradient(circle, rgba(245, 53, 1, 0.1) 0%, transparent 70%);\n  z-index: 2;\n  animation: s-09-pulse 10s infinite alternate ease-in-out;\n}\n\n.s-scene-09-ghost-text {\n  position: absolute;\n  bottom: 5%;\n  right: 5%;\n  font-family: var(--sv-font-display-cn);\n  font-size: 140px;\n  color: #FFFFFF;\n  opacity: 0.03;\n  pointer-events: none;\n  line-height: 1;\n}\n\n/* Main Layout */\n.s-scene-09-container {\n  position: relative;\n  z-index: 10;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 40px;\n}\n\n/* Brain Icon Core */\n.s-scene-09-circuit-brain {\n  position: relative;\n  width: 200px;\n  height: 200px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.s-scene-09-brain-icon {\n  font-size: 120px;\n  color: #F53501;\n  filter: drop-shadow(0 0 20px rgba(245, 53, 1, 0.6));\n  animation: s-09-float 4s infinite ease-in-out;\n  z-index: 5;\n}\n\n.s-scene-09-ring {\n  position: absolute;\n  border: 1px solid rgba(245, 53, 1, 0.3);\n  border-radius: 50%;\n  z-index: 1;\n}\n\n.s-scene-09-ring-1 {\n  width: 240px;\n  height: 240px;\n  animation: s-09-spin 12s linear infinite;\n  border-style: dashed;\n}\n\n.s-scene-09-ring-2 {\n  width: 300px;\n  height: 300px;\n  animation: s-09-spin 20s linear infinite reverse;\n  opacity: 0.5;\n}\n\n/* Text Zone */\n.s-scene-09-text-zone {\n  text-align: center;\n  opacity: 0;\n  transform: translateY(30px);\n  transition: all 0.8s cubic-bezier(0.22, 1, 0.36, 1);\n}\n\n.s-scene-09-text-zone.active {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n.s-scene-09-hero-title {\n  font-family: var(--sv-font-display-cn);\n  font-size: 96px;\n  margin: 0;\n  letter-spacing: 4px;\n  color: #FFFFFF;\n  text-shadow: 0 10px 30px rgba(0,0,0,0.5);\n}\n\n.s-scene-09-subtitle-bar {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  gap: 20px;\n  margin-top: 10px;\n}\n\n.s-scene-09-tag {\n  font-family: var(--sv-font-mono);\n  font-size: 16px;\n  color: #F53501;\n  letter-spacing: 2px;\n}\n\n.s-scene-09-line {\n  width: 40px;\n  height: 2px;\n  background: rgba(255, 255, 255, 0.2);\n}\n\n/* Light Rays (Step 2) */\n.s-scene-09-rays-container {\n  position: absolute;\n  inset: -100px;\n  pointer-events: none;\n  opacity: 0;\n  transition: opacity 1s ease;\n}\n\n.s-scene-09-rays-container.active {\n  opacity: 1;\n}\n\n.s-scene-09-ray {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 2px;\n  height: 400px;\n  background: linear-gradient(to top, #F53501, transparent);\n  transform-origin: bottom center;\n  opacity: 0.4;\n}\n\n/* Ray Positioning */\n.s-scene-09-ray:nth-child(1) { transform: translate(-50%, -100%) rotate(0deg); }\n.s-scene-09-ray:nth-child(2) { transform: translate(-50%, -100%) rotate(45deg); }\n.s-scene-09-ray:nth-child(3) { transform: translate(-50%, -100%) rotate(90deg); }\n.s-scene-09-ray:nth-child(4) { transform: translate(-50%, -100%) rotate(135deg); }\n.s-scene-09-ray:nth-child(5) { transform: translate(-50%, -100%) rotate(180deg); }\n.s-scene-09-ray:nth-child(6) { transform: translate(-50%, -100%) rotate(225deg); }\n.s-scene-09-ray:nth-child(7) { transform: translate(-50%, -100%) rotate(270deg); }\n.s-scene-09-ray:nth-child(8) { transform: translate(-50%, -100%) rotate(315deg); }\n\n/* UI Corners */\n.s-scene-09-corner {\n  position: absolute;\n  font-family: var(--sv-font-mono);\n  font-size: 12px;\n  color: rgba(255, 255, 255, 0.3);\n  padding: 20px;\n}\n\n.s-scene-09-tl { top: 0; left: 0; border-left: 2px solid #F53501; }\n.s-scene-09-br { bottom: 0; right: 0; border-right: 2px solid #F53501; }\n\n/* Animations */\n@keyframes s-09-pulse {\n  from { transform: scale(1); opacity: 0.1; }\n  to { transform: scale(1.2); opacity: 0.2; }\n}\n\n@keyframes s-09-float {\n  0%, 100% { transform: translateY(0); }\n  50% { transform: translateY(-10px); }\n}\n\n@keyframes s-09-spin {\n  from { transform: rotate(0deg); }\n  to { transform: rotate(360deg); }\n}","js":"window.SceneLifecycle.register('scene-09', {\n  enter() {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-09\"]');\n    if (!sceneRoot) return;\n\n    // Initial state setup\n    const rayContainer = sceneRoot.querySelector('.s-scene-09-rays-container');\n    const textZone = sceneRoot.querySelector('.s-scene-09-text-zone');\n    \n    if (rayContainer) rayContainer.classList.remove('active');\n    if (textZone) textZone.classList.remove('active');\n\n    this.step(0);\n  },\n\n  step(stepIndex) {\n    const sceneRoot = document.querySelector('[data-scene-id=\"scene-09\"]');\n    if (!sceneRoot) return;\n\n    const steps = sceneRoot.querySelectorAll('[data-step]');\n    steps.forEach(el => {\n      const elStep = parseInt(el.getAttribute('data-step'));\n      el.classList.toggle('active', stepIndex >= elStep);\n    });\n\n    // Specialized logic for ray emission intensity\n    if (stepIndex >= 2) {\n      const rays = sceneRoot.querySelectorAll('.s-scene-09-ray');\n      rays.forEach((ray, idx) => {\n        ray.style.transition = `all 1s ease ${idx * 0.1}s`;\n        ray.style.height = '600px';\n        ray.style.opacity = '0.8';\n      });\n    }\n\n    window.__SVGVIDEO_REFRESH_ICONS(sceneRoot);\n  }\n});"}]</script>
  <script defer src="https://unpkg.com/lucide@latest"></script>
  <script defer src="https://code.iconify.design/iconify-icon/2.3.0/iconify-icon.min.js"></script>
  <script>
    (function () {
      var state = { sceneId: 'scene-09', step: 0, direction: 1 };
      var TRANSITION_PRESETS={'door':{'--sv-stage-perspective':'900px','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'rotateY(90deg)','--sv-trans-enter-filter':'blur(6px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'rotateY(0deg)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'rotateY(-90deg)','--sv-trans-exit-filter':'blur(4px)','--sv-trans-duration':'0.65s','--sv-trans-ease':'cubic-bezier(0.36, 0, 0.66, 1)'},'burst':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'scale(0.1)','--sv-trans-enter-filter':'blur(40px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'scale(1.6)','--sv-trans-exit-filter':'blur(24px)','--sv-trans-duration':'0.55s','--sv-trans-ease':'cubic-bezier(0.34, 1.3, 0.64, 1)'},'slam':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'translateX(var(--scene-enter-offset, 180px)) rotate(8deg)','--sv-trans-enter-filter':'blur(24px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'translateX(0) rotate(0deg)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'translateX(var(--scene-exit-offset, -120px)) rotate(-5deg)','--sv-trans-exit-filter':'blur(18px)','--sv-trans-duration':'0.50s','--sv-trans-ease':'cubic-bezier(0.2, 0.8, 0.2, 1)'},'push-up':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'1','--sv-trans-enter-transform':'translateY(105%)','--sv-trans-enter-filter':'blur(0px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'translateY(0)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0.3','--sv-trans-exit-transform':'translateY(-60px)','--sv-trans-exit-filter':'blur(8px)','--sv-trans-duration':'0.55s','--sv-trans-ease':'cubic-bezier(0.22, 1, 0.36, 1)'},'spin':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'rotate(180deg) scale(0.2)','--sv-trans-enter-filter':'blur(24px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'rotate(0deg) scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'rotate(-90deg) scale(0.4)','--sv-trans-exit-filter':'blur(16px)','--sv-trans-duration':'0.55s','--sv-trans-ease':'cubic-bezier(0.34, 1.3, 0.64, 1)'},'tunnel':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'scale(1.28)','--sv-trans-enter-filter':'blur(12px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'scale(0.88)','--sv-trans-exit-filter':'blur(10px)','--sv-trans-duration':'0.60s','--sv-trans-ease':'cubic-bezier(0.22, 1, 0.36, 1)'},'glitch':{'--sv-stage-perspective':'none','--sv-trans-enter-opacity':'0','--sv-trans-enter-transform':'scale(0.95)','--sv-trans-enter-filter':'blur(2px)','--sv-trans-active-opacity':'1','--sv-trans-active-transform':'scale(1)','--sv-trans-active-filter':'blur(0px)','--sv-trans-exit-opacity':'0','--sv-trans-exit-transform':'scale(0.95)','--sv-trans-exit-filter':'none','--sv-trans-duration':'0.25s','--sv-trans-ease':'ease-out'},};
      // Per-scene transition mapping — built from meta at init time
      var sceneTransitionMap = {};
      var previousSceneId = null;
      var exitCleanupTimer = null;
      var isPlaying = false;
      var playTimer = null;
      var progressRaf = null;
      var STEP_INTERVAL_MS = 1400;
      var SCENE_FINISH_PAUSE_MS = 2000;
      var autoplayFromFirstScene = false;
      var progressWrap = document.getElementById('sv-progress-wrap');
      var progressFill = document.getElementById('sv-progress-fill');
      var progressThumb = document.getElementById('sv-progress-thumb');
      var playBtn = document.getElementById('sv-play-btn');
      var expandBtn = document.getElementById('sv-expand-btn');
      var statusText = document.getElementById('sv-status-text');
      var sceneButtonList = Array.prototype.slice.call(document.querySelectorAll('[data-panel-scene-id]'));
      var sceneRetryButtonList = Array.prototype.slice.call(document.querySelectorAll('[data-retry-scene-id]'));
      var editorOverlay = document.getElementById('sv-editor-overlay');
      var editorBackdrop = document.getElementById('sv-editor-backdrop');
      var editorSheet = document.getElementById('sv-editor-sheet');
      var editorResizeHandle = document.getElementById('sv-editor-resize-handle');
      var editorCloseBtn = document.getElementById('sv-editor-close-btn');
      var editorSaveBtn = document.getElementById('sv-editor-save-btn');
      var editorList = document.getElementById('sv-editor-list');
      var editorSaveTip = document.getElementById('sv-editor-save-tip');
      var editorTipTimer = null;
      var isEditorOpen = false;
      var isEditorDirty = false;
      var editorHeightVh = 50;
      var hostCaps = { canRetry: false, canEditPanel: false, locale: 'zh', theme: 'dark' };
      var metaJson = document.getElementById('__SVGVIDEO_META__');
      var meta = { scenes: [] };
      try {
        meta = JSON.parse((metaJson && metaJson.textContent) || '{}');
      } catch (e) {
        meta = { scenes: [] };
      }
      var metaSceneMap = {};
      var metaScenes = Array.isArray(meta.scenes) ? meta.scenes : [];
      metaScenes.forEach(function (scene) {
        if (scene && typeof scene.id === 'string' && scene.id) {
          metaSceneMap[scene.id] = scene;
          sceneTransitionMap[scene.id] = (typeof scene.transition === 'string' && TRANSITION_PRESETS[scene.transition]) ? scene.transition : 'door';
        }
      });
      function refreshFrameworkIcons(root) {
        var refreshRoot = root || document;
        try {
          if (window.lucide && typeof window.lucide.createIcons === 'function') {
            window.lucide.createIcons({ root: refreshRoot });
          }
        } catch (iconErr) {
          console.warn('[svg-video] lucide refresh failed', iconErr);
        }
      }
      window.__SVGVIDEO_REFRESH_ICONS = refreshFrameworkIcons;
      var sceneModels = Array.prototype.slice.call(document.querySelectorAll('#stage > [data-scene-id]')).map(function (node, index) {
        var sceneId = node.getAttribute('data-scene-id') || ('scene-' + (index + 1));
        var metaScene = metaSceneMap[sceneId] || {};
        var sceneTitle = typeof metaScene.title === 'string' && metaScene.title ? metaScene.title : ('分镜' + (index + 1));
        var sceneSteps = Math.max(1, Number(metaScene.steps) || 1);
        var sceneStatus = typeof metaScene.status === 'string' ? metaScene.status : 'pending';
        var scenePrompt = typeof metaScene.prompt === 'string' ? metaScene.prompt : '';
        var sceneScript = typeof metaScene.scriptText === 'string' ? metaScene.scriptText : '';
        var sceneAudioObjectKey = typeof metaScene.audioObjectKey === 'string' ? metaScene.audioObjectKey : '';
        var sceneAudioDurationMs = Number(metaScene.audioDurationMs) > 0 ? Number(metaScene.audioDurationMs) : 0;
        var sceneVoiceName = typeof metaScene.voiceName === 'string' ? metaScene.voiceName : '';
        var sceneVoiceStyle = typeof metaScene.voiceStyle === 'string' ? metaScene.voiceStyle : '';
        var relatedSceneIds = Array.isArray(metaScene.relatedSceneIds) ? metaScene.relatedSceneIds : [];
        return {
          id: sceneId,
          title: sceneTitle,
          steps: sceneSteps,
          status: sceneStatus,
          prompt: scenePrompt,
          scriptText: sceneScript,
          audioObjectKey: sceneAudioObjectKey,
          audioDurationMs: sceneAudioDurationMs,
          voiceName: sceneVoiceName,
          voiceStyle: sceneVoiceStyle,
          relatedSceneIds: relatedSceneIds,
          transition: sceneTransitionMap[sceneId] || 'door'
        };
      });
      if (!sceneModels.length && metaScenes.length) {
        sceneModels = metaScenes.map(function (scene, index) {
          return {
            id: scene.id || ('scene-' + (index + 1)),
            title: scene.title || ('分镜' + (index + 1)),
            steps: Math.max(1, Number(scene.steps) || 1),
            status: typeof scene.status === 'string' ? scene.status : 'pending',
            prompt: typeof scene.prompt === 'string' ? scene.prompt : '',
            scriptText: typeof scene.scriptText === 'string' ? scene.scriptText : '',
            audioObjectKey: typeof scene.audioObjectKey === 'string' ? scene.audioObjectKey : '',
            audioDurationMs: Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0,
            voiceName: typeof scene.voiceName === 'string' ? scene.voiceName : '',
            voiceStyle: typeof scene.voiceStyle === 'string' ? scene.voiceStyle : '',
            relatedSceneIds: Array.isArray(scene.relatedSceneIds) ? scene.relatedSceneIds : [],
            transition: sceneTransitionMap[scene.id] || 'door'
          };
        });
      }
      function i18nText(zh, en) {
        return hostCaps.locale === 'en' ? en : zh;
      }
      function applyI18nTexts() {
        var toolbarTitleEl = document.getElementById('sv-toolbar-title');
        var titleEl = document.getElementById('sv-editor-header-title');
        if (toolbarTitleEl) toolbarTitleEl.textContent = i18nText('分镜面板', 'Storyboard');
        if (titleEl) titleEl.textContent = i18nText('分镜详情编辑', 'Storyboard details');
        if (expandBtn) {
          var expandText = i18nText('展开分镜详情', 'Open storyboard details');
          expandBtn.setAttribute('aria-label', expandText);
          expandBtn.setAttribute('title', expandText);
        }
        if (editorSaveBtn) editorSaveBtn.textContent = isEditorDirty ? i18nText('保存*', 'Save*') : i18nText('保存', 'Save');
        if (editorCloseBtn) editorCloseBtn.textContent = i18nText('关闭', 'Close');
        if (editorSaveTip) editorSaveTip.textContent = i18nText('已保存', 'Saved');
      }
      function clampEditorHeightVh(value) {
        return Math.max(32, Math.min(80, Number(value) || 50));
      }
      function applyEditorHeight(vh) {
        editorHeightVh = clampEditorHeightVh(vh);
        document.documentElement.style.setProperty('--sv-editor-height', editorHeightVh + 'vh');
      }
      function persistMetaToScript() {
        meta.title = typeof meta.title === 'string' ? meta.title : '';
        meta.version = meta.version || 1;
        meta.scenes = sceneModels.map(function (scene) {
          return {
            id: scene.id,
            title: scene.title || '',
            steps: Math.max(1, Number(scene.steps) || 1),
            status: scene.status || 'pending',
            prompt: scene.prompt || '',
            scriptText: scene.scriptText || '',
            audioObjectKey: scene.audioObjectKey || '',
            audioDurationMs: Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0,
            voiceName: scene.voiceName || '',
            voiceStyle: scene.voiceStyle || '',
            relatedSceneIds: Array.isArray(scene.relatedSceneIds) ? scene.relatedSceneIds : [],
            transition: scene.transition || 'door'
          };
        });
        if (metaJson) metaJson.textContent = JSON.stringify(meta);
      }
      function showSavedTip() {
        if (!editorSaveTip) return;
        if (editorTipTimer) {
          clearTimeout(editorTipTimer);
          editorTipTimer = null;
        }
        editorSaveTip.classList.add('is-visible');
        editorTipTimer = setTimeout(function () {
          editorSaveTip.classList.remove('is-visible');
        }, 1200);
      }
      function markEditorDirty() {
        isEditorDirty = true;
        applyI18nTexts();
      }
      function clearEditorDirty() {
        isEditorDirty = false;
        applyI18nTexts();
      }
      function getStatusLabel(status) {
        if (status === 'success') return i18nText('已生成', 'Done');
        if (status === 'generating') return i18nText('生成中', 'Generating');
        if (status === 'failed') return i18nText('失败', 'Failed');
        return i18nText('未生成', 'Pending');
      }
      function getStatusClass(status) {
        if (status === 'generating') return 'is-generating';
        if (status === 'success') return 'is-success';
        return 'is-failed';
      }
      function getRetryButtonInnerHtml(isGenerating) {
        if (isGenerating) return '<span class="scene-chip-retry-spinner"></span>';
        return '<svg class="scene-chip-retry-icon" viewBox="0 0 1024 1024" width="16" height="16" fill="currentColor"><path d="M698.569 531.322a39.825 39.825 0 0 0-23.898 7.949c-17.702 13.216-21.34 38.28-8.124 55.982l95.716 128.212c7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949c17.702-13.216 21.34-38.28 8.124-55.982l-95.716-128.212c-7.853-10.521-19.892-16.074-32.084-16.073z" /><path d="M922.498 563.818a39.825 39.825 0 0 0-23.898 7.949l-128.212 95.716c-17.703 13.216-21.34 38.28-8.124 55.982 7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949l128.212-95.716c17.702-13.216 21.34-38.28 8.124-55.982-7.854-10.521-19.893-16.074-32.084-16.073zM229.652 282.148a39.825 39.825 0 0 0-23.898 7.949c-17.702 13.216-21.34 38.28-8.124 55.982l95.716 128.212c7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949c17.702-13.216 21.34-38.28 8.124-55.982l-95.716-128.212c-7.854-10.521-19.892-16.074-32.084-16.073z" /><path d="M229.652 282.148a39.825 39.825 0 0 0-23.898 7.949L77.542 385.813c-17.702 13.216-21.34 38.28-8.124 55.982 7.854 10.521 19.893 16.073 32.084 16.073a39.825 39.825 0 0 0 23.898-7.949l128.213-95.716c17.702-13.216 21.34-38.28 8.124-55.982-7.855-10.521-19.893-16.073-32.085-16.073z" /><path d="M614.968 763.65c-44.13 18.171-94.005 25.121-146.168 16.968C353.747 762.636 261.364 670.253 243.381 555.2c-9.681-61.936 1.932-120.646 28.337-170.344l-58.657-58.657c-40.139 64.442-60.11 142.746-50.806 226.152 17.993 161.306 148.088 291.401 309.394 309.394 62.041 6.92 121.259-2.357 174.048-24.083 26.535-10.921 33.625-45.203 13.335-65.493l-0.098-0.098c-11.555-11.555-28.854-14.643-43.966-8.421zM409.033 260.35c44.131-18.171 94.007-25.122 146.169-16.968 115.051 17.985 207.431 110.365 225.416 225.416 9.682 61.935-1.931 120.646-28.337 170.346l58.658 58.658c40.139-64.443 60.109-142.747 50.805-226.155-17.993-161.305-148.087-291.399-309.391-309.391-62.042-6.92-121.26 2.356-174.05 24.082-26.535 10.921-33.625 45.203-13.335 65.493l0.099 0.099c11.555 11.554 28.854 14.642 43.966 8.42z" /></svg>';
      }
      function setSceneStatus(sceneId, status) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return;
        sceneModels[index].status = status;
        persistMetaToScript();
        var statusClass = getStatusClass(status);
        var chipWrap = document.querySelector('[data-chip-scene-id="' + sceneId + '"]');
        if (chipWrap) {
          chipWrap.classList.remove('is-success', 'is-failed', 'is-generating');
          chipWrap.classList.add(statusClass);
          var chipBtn = chipWrap.querySelector('.scene-chip');
          if (chipBtn) {
            chipBtn.classList.remove('is-success', 'is-failed', 'is-generating');
            chipBtn.classList.add(statusClass);
          }
          var retryBtn = chipWrap.querySelector('.scene-chip-retry');
          if (retryBtn) {
            retryBtn.innerHTML = getRetryButtonInnerHtml(status === 'generating');
            if (status === 'generating') retryBtn.setAttribute('disabled', 'disabled');
            else retryBtn.removeAttribute('disabled');
          }
        }
        renderStatus();
      }
      function requestSceneRetry(sceneId) {
        if (!hostCaps.canRetry) return;
        var idx = getSceneIndexById(sceneId);
        if (idx < 0) return;
        var scene = sceneModels[idx];
        setSceneStatus(sceneId, 'generating');
        focusScene(sceneId);
        if (window.parent && window.parent !== window) {
          window.parent.postMessage(
            { type: '__SVGVIDEO_RETRY_SCENE', sceneId: sceneId, prompt: scene.prompt || '' },
            '*'
          );
        }
      }
      function renderEditorList() {
        if (!editorList) return;
        editorList.innerHTML = '';
        var fragment = document.createDocumentFragment();
        sceneModels.forEach(function (scene, index) {
          var item = document.createElement('section');
          item.className = 'sv-editor-item';
          item.setAttribute('data-editor-scene-id', scene.id);

          var head = document.createElement('div');
          head.className = 'sv-editor-item-head';

          var jumpBtn = document.createElement('button');
          jumpBtn.type = 'button';
          jumpBtn.className = 'sv-editor-item-title';
          jumpBtn.textContent = i18nText('分镜', 'Scene') + (index + 1) + ' · ' + (scene.title || '');
          jumpBtn.addEventListener('click', function () {
            focusScene(scene.id);
          });
          head.appendChild(jumpBtn);

          var statusWrap = document.createElement('div');
          statusWrap.className = 'sv-editor-status-wrap';
          var status = document.createElement('span');
          status.className = 'sv-editor-status';
          status.textContent = getStatusLabel(scene.status);
          statusWrap.appendChild(status);
          var retryBtn = document.createElement('button');
          retryBtn.type = 'button';
          retryBtn.className = 'scene-chip-retry sv-editor-retry';
          retryBtn.setAttribute('aria-label', i18nText('重新生成当前分镜', 'Retry this scene'));
          retryBtn.setAttribute('title', i18nText('重新生成当前分镜', 'Retry this scene'));
          retryBtn.innerHTML = getRetryButtonInnerHtml(scene.status === 'generating');
          if (scene.status === 'generating' || !hostCaps.canRetry) retryBtn.setAttribute('disabled', 'disabled');
          retryBtn.addEventListener('click', function (event) {
            event.preventDefault();
            event.stopPropagation();
            requestSceneRetry(scene.id);
            if (isEditorOpen) renderEditorList();
          });
          statusWrap.appendChild(retryBtn);
          head.appendChild(statusWrap);

          item.appendChild(head);

          var scriptField = document.createElement('label');
          scriptField.className = 'sv-editor-field';
          var scriptLabel = document.createElement('span');
          scriptLabel.className = 'sv-editor-label';
          scriptLabel.textContent = i18nText('脚本', 'Script');
          var scriptInput = document.createElement('div');
          scriptInput.className = 'sv-editor-script-view';
          scriptInput.setAttribute('data-field-scene-id', scene.id);
          scriptInput.textContent = scene.scriptText || '';
          scriptField.appendChild(scriptLabel);
          scriptField.appendChild(scriptInput);
          item.appendChild(scriptField);

          var promptField = document.createElement('label');
          promptField.className = 'sv-editor-field';
          var promptLabel = document.createElement('span');
          promptLabel.className = 'sv-editor-label';
          promptLabel.textContent = i18nText('提示词', 'Prompt');
          var promptInput = document.createElement('textarea');
          promptInput.className = 'sv-editor-textarea';
          promptInput.setAttribute('data-field-scene-id', scene.id);
          promptInput.setAttribute('data-field', 'prompt');
          promptInput.value = scene.prompt || '';
          promptInput.addEventListener('click', function (event) {
            event.stopPropagation();
          });
          promptInput.addEventListener('input', function () {
            scene.prompt = promptInput.value;
            markEditorDirty();
          });
          promptField.appendChild(promptLabel);
          promptField.appendChild(promptInput);
          item.appendChild(promptField);
          item.addEventListener('click', function () {
            focusScene(scene.id);
          });

          fragment.appendChild(item);
        });
        editorList.appendChild(fragment);
        highlightActiveEditorItem();
      }
      function highlightActiveEditorItem() {
        if (!editorList) return;
        var itemList = Array.prototype.slice.call(editorList.querySelectorAll('[data-editor-scene-id]'));
        itemList.forEach(function (item) {
          if (item.getAttribute('data-editor-scene-id') === state.sceneId) item.classList.add('is-active');
          else item.classList.remove('is-active');
        });
      }
      function openEditor() {
        if (!hostCaps.canEditPanel) return;
        if (!editorOverlay) return;
        renderEditorList();
        applyEditorHeight(editorHeightVh);
        editorOverlay.classList.add('is-open');
        editorOverlay.setAttribute('aria-hidden', 'false');
        document.body.classList.add('sv-editor-open');
        isEditorOpen = true;
      }
      function closeEditor() {
        if (!editorOverlay) return;
        editorOverlay.classList.remove('is-open');
        editorOverlay.setAttribute('aria-hidden', 'true');
        document.body.classList.remove('sv-editor-open');
        isEditorOpen = false;
      }
      function saveEditor() {
        persistMetaToScript();
        clearEditorDirty();
        showSavedTip();
        if (window.parent && window.parent !== window) {
          window.parent.postMessage({ type: '__SVGVIDEO_META_UPDATED', meta: meta }, '*');
        }
      }
      function getTotalSteps() {
        return sceneModels.reduce(function (sum, scene) { return sum + Math.max(1, Number(scene.steps) || 1); }, 0);
      }
      function getSceneIndexById(sceneId) {
        for (var i = 0; i < sceneModels.length; i++) {
          if (sceneModels[i].id === sceneId) return i;
        }
        return -1;
      }
      function getSceneInitialStep(sceneId) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return 0;
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        return Math.max(0, maxSteps - 1);
      }
      function focusScene(sceneId) {
        var index = getSceneIndexById(sceneId);
        if (index < 0) return;
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        stopPlayback();
        window.__SVGVIDEO_SET_STATE(sceneId, 0, 1);
        if (maxSteps > 1) {
          setTimeout(function () {
            window.__SVGVIDEO_SET_STATE(sceneId, Math.max(0, maxSteps - 1), 1);
          }, 90);
        }
      }
      function getProgressPercent(sceneId, step) {
        var total = getTotalSteps();
        if (!total) return 0;
        var index = getSceneIndexById(sceneId);
        if (index < 0) return 0;
        var completed = 0;
        for (var i = 0; i < index; i++) completed += Math.max(1, Number(sceneModels[i].steps) || 1);
        var maxSteps = Math.max(1, Number(sceneModels[index].steps) || 1);
        var localStep = Math.max(0, Math.min(maxSteps - 1, Number(step) || 0));
        return Math.max(0, Math.min(100, ((completed + localStep) / total) * 100));
      }
      function updateProgressUi(percent) {
        var pct = Math.max(0, Math.min(100, percent || 0));
        if (progressFill) progressFill.style.width = pct + '%';
        if (progressThumb) progressThumb.style.left = pct + '%';
      }
      function stopProgressAnimation() {
        if (progressRaf) {
          cancelAnimationFrame(progressRaf);
          progressRaf = null;
        }
      }
      function startProgressSegment(fromPercent, toPercent, durationMs) {
        stopProgressAnimation();
        var from = Math.max(0, Math.min(100, Number(fromPercent) || 0));
        var to = Math.max(0, Math.min(100, Number(toPercent) || 0));
        var duration = Math.max(1, Number(durationMs) || 1);
        if (duration <= 1 || to <= from) {
          updateProgressUi(to);
          return;
        }
        var startAt = performance.now();
        var tick = function (now) {
          if (!isPlaying) {
            stopProgressAnimation();
            return;
          }
          var elapsed = now - startAt;
          var ratio = Math.max(0, Math.min(1, elapsed / duration));
          var current = from + (to - from) * ratio;
          updateProgressUi(current);
          if (ratio < 1) {
            progressRaf = requestAnimationFrame(tick);
          } else {
            stopProgressAnimation();
          }
        };
        progressRaf = requestAnimationFrame(tick);
      }
      function getPlaybackSegment(sceneIndex, step) {
        var scene = sceneModels[sceneIndex];
        if (!scene) return null;
        var currentPercent = getProgressPercent(scene.id, step);
        var maxSteps = Math.max(1, Number(scene.steps) || 1);
        if (step < maxSteps - 1) {
          return {
            from: currentPercent,
            to: getProgressPercent(scene.id, step + 1),
            duration: STEP_INTERVAL_MS
          };
        }
        if (sceneIndex < sceneModels.length - 1) {
          var nextScene = sceneModels[sceneIndex + 1];
          var nextPercent = nextScene ? getProgressPercent(nextScene.id, 0) : currentPercent;
          return {
            from: currentPercent,
            to: nextPercent,
            duration: SCENE_FINISH_PAUSE_MS
          };
        }
        return {
          from: currentPercent,
          to: 100,
          duration: STEP_INTERVAL_MS
        };
      }
      function renderStatus() {
        if (!statusText) return;
        var done = sceneModels.filter(function (scene) { return scene.status === 'success'; }).length;
        var pending = sceneModels.filter(function (scene) { return scene.status === 'pending' || scene.status === 'generating'; }).length;
        var failed = sceneModels.filter(function (scene) { return scene.status === 'failed'; }).length;
        statusText.textContent = '已生成 ' + done + '/' + sceneModels.length + ' · 待生成 ' + pending + ' · 失败 ' + failed;
      }
      function updatePlayButton() {
        if (!playBtn) return;
        playBtn.innerHTML = isPlaying
          ? '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><rect x="6" y="5" width="4" height="14" rx="1"></rect><rect x="14" y="5" width="4" height="14" rx="1"></rect></svg>'
          : '<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M7 5v14l11-7z"></path></svg>';
        playBtn.setAttribute('aria-label', isPlaying ? '暂停播放' : '播放分镜');
        playBtn.setAttribute('title', isPlaying ? '暂停播放' : '播放分镜');
      }
      function applyHostCaps() {
        if (hostCaps.canRetry) document.body.classList.add('sv-host-can-retry');
        else document.body.classList.remove('sv-host-can-retry');
        if (hostCaps.canEditPanel) document.body.classList.add('sv-host-can-edit-panel');
        else document.body.classList.remove('sv-host-can-edit-panel');
        if (hostCaps.theme === 'light') document.body.classList.add('sv-theme-light');
        else document.body.classList.remove('sv-theme-light');
      }
      function highlightActiveSceneButton() {
        sceneButtonList.forEach(function (button) {
          var targetId = button.getAttribute('data-panel-scene-id');
          if (targetId === state.sceneId) button.classList.add('is-active');
          else button.classList.remove('is-active');
        });
      }
      function stopPlayback() {
        if (playTimer) {
          clearTimeout(playTimer);
          playTimer = null;
        }
        stopProgressAnimation();
        isPlaying = false;
        updatePlayButton();
      }
      function startPlayback() {
        if (!sceneModels.length) return;
        stopPlayback();
        var sceneIndex = Math.max(0, getSceneIndexById(state.sceneId));
        var step = 0;
        var applyPlaybackState = function (direction) {
          var scene = sceneModels[sceneIndex];
          if (!scene) return false;
          window.__SVGVIDEO_SET_STATE(scene.id, step, direction);
          updateProgressUi(getProgressPercent(scene.id, step));
          var segment = getPlaybackSegment(sceneIndex, step);
          if (segment) startProgressSegment(segment.from, segment.to, segment.duration);
          return true;
        };
        var scheduleAdvance = function (delay) {
          playTimer = setTimeout(function () {
            var currentScene = sceneModels[sceneIndex];
            if (!currentScene) {
              stopPlayback();
              return;
            }
            var maxSteps = Math.max(1, Number(currentScene.steps) || 1);
            if (step < maxSteps - 1) {
              step += 1;
              applyPlaybackState(1);
              scheduleAdvance(STEP_INTERVAL_MS);
              return;
            }
            if (sceneIndex < sceneModels.length - 1) {
              playTimer = setTimeout(function () {
                sceneIndex += 1;
                step = 0;
                if (!applyPlaybackState(1)) {
                  stopPlayback();
                  return;
                }
                scheduleAdvance(STEP_INTERVAL_MS);
              }, SCENE_FINISH_PAUSE_MS);
              return;
            }
            stopPlayback();
          }, delay);
        };
        isPlaying = true;
        updatePlayButton();
        if (!applyPlaybackState(1)) {
          stopPlayback();
          return;
        }
        scheduleAdvance(STEP_INTERVAL_MS);
      }
      window.SceneLifecycle = {
        handlers: {},
        register: function (sceneId, handler) { this.handlers[sceneId] = handler || {}; }
      };

      (function () {
        var sceneDataJson = document.getElementById('__SVGVIDEO_SCENE_DATA__');
        var runtimeScenes = [];
        try {
          runtimeScenes = JSON.parse((sceneDataJson && sceneDataJson.textContent) || '[]');
        } catch (_e) {
          runtimeScenes = [];
        }
        runtimeScenes.forEach(function (scene) {
          if (!scene || typeof scene.id !== 'string') return;
          var js = typeof scene.js === 'string' ? scene.js.trim() : '';
          if (!js) return;
          try {
            var factory = new Function(js);
            factory.call(window);
          } catch (err) {
            console.error('[svg-video] scene runtime failed', scene.id, err);
          }
        });
        refreshFrameworkIcons(document);
      })();

      function applyStepVisibility(sceneEl) {
        var stepNodes = sceneEl.querySelectorAll('[data-step]');
        stepNodes.forEach(function (node) {
          var minStep = Number(node.getAttribute('data-step') || '0');
          var visible = state.step >= minStep;
          node.style.opacity = visible ? '1' : '0';
          node.style.visibility = visible ? 'visible' : 'hidden';
          node.style.pointerEvents = visible ? 'auto' : 'none';
          node.style.transform = visible ? 'translateY(0)' : 'translateY(8px)';
          node.style.filter = visible ? 'blur(0px)' : 'blur(4px)';
        });
      }
      function applySceneState() {
        var scenes = document.querySelectorAll('#stage > [data-scene-id]');
        var currentSceneEl = null;
        var previousSceneEl = null;
        var glitchTimer = null;
        scenes.forEach(function (sceneEl) {
          var sceneId = sceneEl.getAttribute('data-scene-id');
          if (sceneId === state.sceneId) currentSceneEl = sceneEl;
          if (sceneId === previousSceneId) previousSceneEl = sceneEl;
        });
        var direction = state.direction >= 0 ? 1 : -1;
        document.documentElement.style.setProperty('--scene-enter-offset', direction > 0 ? '200px' : '-200px');
        document.documentElement.style.setProperty('--scene-exit-offset', direction > 0 ? '-140px' : '140px');
        var isSceneChange = previousSceneId !== state.sceneId;
        var targetTransition = sceneTransitionMap[state.sceneId] || 'door';
        var needsGlitch = isSceneChange && targetTransition === 'glitch' && currentSceneEl;

        // Apply per-scene transition CSS vars before switching
        if (isSceneChange) {
          var preset = TRANSITION_PRESETS[targetTransition] || TRANSITION_PRESETS['door'];
          var rootStyle = document.documentElement.style;
          for (var varKey in preset) {
            rootStyle.setProperty(varKey, preset[varKey]);
          }
        }

        function doSwitch() {
          if (exitCleanupTimer) {
            clearTimeout(exitCleanupTimer);
            exitCleanupTimer = null;
          }
          scenes.forEach(function (sceneEl) {
            if (sceneEl !== currentSceneEl && sceneEl !== previousSceneEl) {
              sceneEl.classList.remove('scene-active');
              sceneEl.classList.remove('scene-exit');
            }
          });
          if (previousSceneEl && previousSceneEl !== currentSceneEl) {
            previousSceneEl.classList.remove('scene-active');
            previousSceneEl.classList.add('scene-exit');
          }
          if (currentSceneEl) {
            currentSceneEl.classList.remove('scene-exit');
            currentSceneEl.classList.add('scene-active');
            applyStepVisibility(currentSceneEl);
          }
          if (previousSceneEl && previousSceneEl !== currentSceneEl) {
            exitCleanupTimer = setTimeout(function () { previousSceneEl.classList.remove('scene-exit'); }, 650);
          }
          if (previousSceneId !== state.sceneId) {
            if (previousSceneId && window.SceneLifecycle.handlers[previousSceneId] && typeof window.SceneLifecycle.handlers[previousSceneId].leave === 'function') {
              try { window.SceneLifecycle.handlers[previousSceneId].leave(); } catch (e) {}
            }
          }
          if (currentSceneEl && window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].enter === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].enter(); } catch (e) {}
          }
          if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].step === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].step(state.step); } catch (e) {}
          }
          if (currentSceneEl) {
            refreshFrameworkIcons(currentSceneEl);
          }
          previousSceneId = state.sceneId;
          highlightActiveSceneButton();
          highlightActiveEditorItem();
          updateProgressUi(getProgressPercent(state.sceneId, state.step));
        }

        function runGlitchSequence() {
          if (!currentSceneEl) return;
          // Step 1: blur bomb + shift (instant, disable transition first)
          var noTrans = document.getElementById('sv-no-transition');
          if (!noTrans) {
            noTrans = document.createElement('style');
            noTrans.id = 'sv-no-transition';
            noTrans.textContent = '.scene { transition: none !important; }';
            document.head.appendChild(noTrans);
          }
          currentSceneEl.style.filter = 'blur(24px) brightness(1.5)';
          currentSceneEl.style.transform = 'translateX(30px) scale(0.96)';
          // Step 2: snap to other side (80ms)
          glitchTimer = setTimeout(function () {
            if (!currentSceneEl) return;
            currentSceneEl.style.filter = 'blur(3px) brightness(1.1)';
            currentSceneEl.style.transform = 'translateX(-15px) scale(1.02)';
            // Step 3: settle with slight bounce (160ms)
            glitchTimer = setTimeout(function () {
              if (!currentSceneEl) return;
              currentSceneEl.style.filter = 'blur(0px) brightness(1)';
              currentSceneEl.style.transform = 'translateX(0) scale(1)';
              if (noTrans && noTrans.parentNode) noTrans.parentNode.removeChild(noTrans);
              if (currentSceneEl) {
                refreshFrameworkIcons(currentSceneEl);
              }
            }, 70);
          }, 80);
        }

        if (needsGlitch) {
          // Kill old scene instantly
          if (previousSceneEl) {
            previousSceneEl.classList.remove('scene-active');
            previousSceneEl.classList.add('scene-exit');
            exitCleanupTimer = setTimeout(function () { previousSceneEl.classList.remove('scene-exit'); }, 650);
          }
          // Show new scene for glitch base
          if (currentSceneEl) {
            currentSceneEl.classList.remove('scene-exit');
            currentSceneEl.classList.add('scene-active');
            applyStepVisibility(currentSceneEl);
          }
          // Fire lifecycle immediately so scene JS can initialize
          if (previousSceneId && window.SceneLifecycle.handlers[previousSceneId] && typeof window.SceneLifecycle.handlers[previousSceneId].leave === 'function') {
            try { window.SceneLifecycle.handlers[previousSceneId].leave(); } catch (e) {}
          }
          if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].enter === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].enter(); } catch (e) {}
          }
          if (window.SceneLifecycle.handlers[state.sceneId] && typeof window.SceneLifecycle.handlers[state.sceneId].step === 'function') {
            try { window.SceneLifecycle.handlers[state.sceneId].step(state.step); } catch (e) {}
          }
          previousSceneId = state.sceneId;
          highlightActiveSceneButton();
          highlightActiveEditorItem();
          updateProgressUi(getProgressPercent(state.sceneId, state.step));
          runGlitchSequence();
        } else {
          doSwitch();
        }
      }
      window.__SVGVIDEO_SET_STATE = function (sceneId, step, direction) {
        if (typeof sceneId === 'string' && sceneId) {
          if (typeof direction === 'number' && Number.isFinite(direction)) {
            state.direction = direction >= 0 ? 1 : -1;
          } else {
            var nextIndex = getSceneIndexById(sceneId);
            var prevIndex = getSceneIndexById(state.sceneId);
            if (nextIndex !== -1 && prevIndex !== -1) state.direction = nextIndex >= prevIndex ? 1 : -1;
          }
          state.sceneId = sceneId;
        }
        if (typeof step === 'number' && Number.isFinite(step)) state.step = Math.max(0, Math.floor(step));
        applySceneState();
      };
      if (state.sceneId && getSceneIndexById(state.sceneId) === -1 && sceneModels.length) {
        state.sceneId = sceneModels[0].id;
      }
      if (playBtn) {
        playBtn.addEventListener('click', function () {
          if (isPlaying) stopPlayback();
          else startPlayback();
        });
      }
      if (expandBtn) {
        expandBtn.addEventListener('click', function () {
          if (isEditorOpen) closeEditor();
          else openEditor();
        });
      }
      if (editorCloseBtn) {
        editorCloseBtn.addEventListener('click', closeEditor);
      }
      if (editorBackdrop) {
        editorBackdrop.addEventListener('click', closeEditor);
      }
      if (editorSaveBtn) {
        editorSaveBtn.addEventListener('click', saveEditor);
      }
      if (editorResizeHandle && editorSheet) {
        editorResizeHandle.addEventListener('mousedown', function (event) {
          event.preventDefault();
          var startY = event.clientY;
          var startHeightPx = (window.innerHeight * editorHeightVh) / 100;
          var onMove = function (moveEvent) {
            var delta = startY - moveEvent.clientY;
            var nextHeightPx = startHeightPx + delta;
            var nextHeightVh = (nextHeightPx / Math.max(1, window.innerHeight)) * 100;
            applyEditorHeight(nextHeightVh);
          };
          var onUp = function () {
            window.removeEventListener('mousemove', onMove);
            window.removeEventListener('mouseup', onUp);
          };
          window.addEventListener('mousemove', onMove);
          window.addEventListener('mouseup', onUp);
        });
      }
      sceneButtonList.forEach(function (button) {
        button.addEventListener('click', function () {
          var sceneId = button.getAttribute('data-panel-scene-id');
          if (!sceneId) return;
          focusScene(sceneId);
        });
      });
      sceneRetryButtonList.forEach(function (button) {
        button.addEventListener('click', function (event) {
          event.preventDefault();
          event.stopPropagation();
          var sceneId = button.getAttribute('data-retry-scene-id');
          if (!sceneId) return;
          requestSceneRetry(sceneId);
        });
      });
      if (progressWrap) {
        progressWrap.addEventListener('click', function (event) {
          var rect = progressWrap.getBoundingClientRect();
          var pct = Math.max(0, Math.min(100, ((event.clientX - rect.left) / rect.width) * 100));
          var totalSteps = getTotalSteps();
          var targetStep = Math.round((pct / 100) * totalSteps);
          var accumulated = 0;
          for (var i = 0; i < sceneModels.length; i++) {
            var sceneSteps = Math.max(1, Number(sceneModels[i].steps) || 1);
            if (accumulated + sceneSteps > targetStep) {
              var localStep = Math.max(0, Math.min(sceneSteps - 1, targetStep - accumulated));
              stopPlayback();
              window.__SVGVIDEO_SET_STATE(sceneModels[i].id, localStep, 1);
              updateProgressUi(pct);
              return;
            }
            accumulated += sceneSteps;
          }
        });
      }
      window.addEventListener('message', function (event) {
        var data = event && event.data;
        if (!data || typeof data.type !== 'string') return;
        if (data.type === '__SVGVIDEO_SET_STATE') {
          window.__SVGVIDEO_SET_STATE(data.sceneId, data.step, data.direction);
          return;
        }
        if (data.type === '__SVGVIDEO_PLAY') {
          startPlayback();
          return;
        }
        if (data.type === '__SVGVIDEO_STOP') {
          stopPlayback();
          return;
        }
        if (data.type === '__SVGVIDEO_SET_HOST_CAPS') {
          hostCaps.canRetry = Boolean(data.canRetry);
          hostCaps.canEditPanel = Boolean(data.canEditPanel);
          hostCaps.locale = data.locale === 'en' ? 'en' : 'zh';
          hostCaps.theme = data.theme === 'light' ? 'light' : 'dark';
          applyI18nTexts();
          applyHostCaps();
          if (isEditorOpen) renderEditorList();
          return;
        }
        if (data.type === '__SVGVIDEO_SET_SCENE_STATUS') {
          var sceneId = typeof data.sceneId === 'string' ? data.sceneId : '';
          var status = typeof data.status === 'string' ? data.status : '';
          if (sceneId && status) {
            setSceneStatus(sceneId, status);
            if (isEditorOpen) renderEditorList();
          }
          return;
        }
        if (data.type === '__SVGVIDEO_SET_RECORDING') {
          if (data && data.active) {
            document.body.classList.add('sv-recording');
            // 如果指定了初始分镜，无过渡动画地跳转过去，避免录制开头残留旧分镜画面
            if (data.sceneId) {
              var noTransStyle = document.createElement('style');
              noTransStyle.id = 'sv-no-transition';
              noTransStyle.textContent = '.scene, [data-step] { transition: none !important; }';
              document.head.appendChild(noTransStyle);
              window.__SVGVIDEO_SET_STATE(data.sceneId, 0, 1);
              // 强制 reflow 后恢复过渡动画
              void document.body.offsetHeight;
              requestAnimationFrame(function () {
                var s = document.getElementById('sv-no-transition');
                if (s) s.remove();
              });
            }
          } else {
            document.body.classList.remove('sv-recording');
          }
          return;
        }
        if (data.type === '__SVGVIDEO_SET_META' && data.meta && typeof data.meta === 'object') {
          meta = data.meta;
          var freshScenes = Array.isArray(meta.scenes) ? meta.scenes : [];
          freshScenes.forEach(function (scene) {
            var idx = getSceneIndexById(scene.id);
            if (idx < 0) return;
            sceneModels[idx].prompt = typeof scene.prompt === 'string' ? scene.prompt : '';
            sceneModels[idx].scriptText = typeof scene.scriptText === 'string' ? scene.scriptText : '';
            sceneModels[idx].audioObjectKey = typeof scene.audioObjectKey === 'string' ? scene.audioObjectKey : '';
            sceneModels[idx].audioDurationMs = Number(scene.audioDurationMs) > 0 ? Number(scene.audioDurationMs) : 0;
            sceneModels[idx].voiceName = typeof scene.voiceName === 'string' ? scene.voiceName : '';
            sceneModels[idx].voiceStyle = typeof scene.voiceStyle === 'string' ? scene.voiceStyle : '';
          });
          persistMetaToScript();
          if (isEditorOpen) renderEditorList();
        }
      });
      document.addEventListener('keydown', function (event) {
        if (event.key === 'Escape' && isEditorOpen) closeEditor();
      });
      window.__SVGVIDEO_PLAY = startPlayback;
      window.__SVGVIDEO_STOP = stopPlayback;
      window.__SVGVIDEO_OPEN_EDITOR = openEditor;
      window.__SVGVIDEO_CLOSE_EDITOR = closeEditor;
      applyEditorHeight(editorHeightVh);
      renderStatus();
      updatePlayButton();
      applyHostCaps();
      clearEditorDirty();
      applyI18nTexts();
      applySceneState();
      if (autoplayFromFirstScene && sceneModels.length) {
        state.sceneId = sceneModels[0].id;
        state.step = 0;
        state.direction = 1;
        applySceneState();
        startPlayback();
      }
    })();
  </script>
</body>
</html>2:[["$","$L7",null,{"id":"webapplication-jsonld","type":"application/ld+json","dangerouslySetInnerHTML":{"__html":"{\"@context\":\"https://schema.org\",\"@type\":\"WebApplication\",\"name\":\"SvgAnimate\",\"url\":\"https://svganimate.ai\",\"description\":\"AI 驱动的网页动画与 HTML 视频生成器，支持 SVG 动画、HTML 视频、交互网页与产品演示。\",\"applicationCategory\":\"DesignApplication\",\"operatingSystem\":\"Web\",\"browserRequirements\":\"Requires a modern web browser\",\"offers\":{\"@type\":\"Offer\",\"price\":\"0\",\"priceCurrency\":\"USD\"}}"}}],["$","$Le",null,{"locale":"zh","initialPage":"home","initialTemplates":[],"initialFeaturedTemplates":[{"id":"62574c6d-8ac1-43ff-8ab8-d4a1a16f8fc4","exportName":"$undefined","title":"Linux内核超级漏洞：Copy Fail 深度解析","description":"“兄弟们，一个超级离谱的Linux内核漏洞刚刚曝光！\n普通用户一句话，就能把服务器的root权限直接抢到手！\n它的编号叫CVE-2026-31431，代号Copy Fail！这个漏洞影响了2017年之后几乎所有主流Linux发行版，Ubuntu、CentOS、RHEL、阿里云、AWS、SUSE通通中招。只要你在服务器上有一个普通账号，就能完成提权，连容器都能逃逸到主机上。原理其实特别巧妙，听我给你捋清楚：正常情况下，文件的内容会缓存在内存里，叫做page cache。我们普通用户只能读它，不能随便改它。但是黑客利用了内核提供的一个加密接口AF_ALG，再配合splice这个系统调用，把目标文件——比如/usr/bin/su——偷偷塞进了内核的加密流程里。因为2017年内核做了一个性能优化，这个优化让内核把这个文件的内存页面，当成了‘可写的缓冲区’来使用！结果，黑客在加密计算的过程中，就往里面精准地写入了4个自己控制的字节。虽然最后加密验证失败了，但那4个字节已经实实在在地改进了内存里的su程序！重复操作几次，就能把su改造成一个‘直接给我root’的恶意程序。一执行，权限就到手了！整个过程不需要猜内核地址，也不用竞态条件，稳得一批。”“目前各大厂商已经紧急推送了补丁，大家赶紧更新内核！\n临时缓解的话，可以把algif_aead模块禁用掉。这个漏洞再次告诉我们：再小的代码优化，如果没想清楚，也可能埋下致命的炸弹。好了，今天的分享就到这里，点赞关注，我们下期再见！”","category":"html-video","tags":[],"likes":0,"favorites":0,"views":213,"sourceType":"HTMLVideo","componentSource":"$f","isLiked":false,"isFavorited":false},{"id":"27b578da-9595-4751-9334-8710c8e8c7b7","exportName":"$undefined","title":"展示Python异常处理的基本语法与原理","description":"展示Python异常处理的基本语法与原理","category":"custom","tags":[],"likes":1,"favorites":0,"views":425,"sourceType":"SvgAnimation","componentSource":"$10","isLiked":false,"isFavorited":false},{"id":"5640993b-edd4-480b-89f0-36cd4325fb5e","exportName":"$undefined","title":"腾讯公司发展历程：连接的演变","description":"讲解腾讯公司发展历程","category":"html-video","tags":[],"likes":1,"favorites":0,"views":210,"sourceType":"HTMLVideo","componentSource":"$11","isLiked":false,"isFavorited":false},{"id":"0ecaed6b-2393-4bff-89fc-e62dee3a32c4","exportName":"$undefined","title":"使用three.js创建一个3D的文字动画，用棱角分明的字体","description":"使用three.js创建一个3D的文字动画，用棱角分明的字体显示SvgAnimate几个字母。画面采用亮色主题，文字呈玻璃质感。自动缓慢立体旋转。","category":"text-svg-animation","tags":[],"likes":0,"favorites":0,"views":311,"sourceType":"SvgAnimation","componentSource":"$12","isLiked":false,"isFavorited":false},{"id":"6da4394f-610e-4e1f-92c7-d6ecff10f250","exportName":"$undefined","title":"做一个tracert命令的运行逻辑，每一步都用动画呈现出来","description":"做一个tracert命令的运行逻辑，每一步都用动画呈现出来","category":"flowchart-animation","tags":[],"likes":0,"favorites":0,"views":3955,"sourceType":"SvgAnimation","componentSource":"$13","isLiked":false,"isFavorited":false},{"id":"437e921a-803b-49f8-ac19-10593eef6e75","exportName":"$undefined","title":"开发一个简单的台球动画，用户可以通过鼠标操作发球，可以调整角","description":"开发一个简单的台球动画，用户可以通过鼠标操作发球，可以调整角度和力度","category":"svg-mini-game","tags":[],"likes":1,"favorites":0,"views":4699,"sourceType":"SvgAnimation","componentSource":"$14","isLiked":false,"isFavorited":false},{"id":"b5fa6a71-3a69-41e6-aad0-fb7d6a9b6530","exportName":"$undefined","title":"创建一个基于SVG代码的高质量等距视角（Isometric）","description":"创建一个基于SVG代码的高质量等距视角（Isometric）动画，画面中心放置两部风格极简的现代智能手机，机身呈30度角倾斜排列，边缘圆润，具有哑光质感。\n左侧手机屏幕呈现柔和的薄荷绿UI界面，代表发送端；右侧手机屏幕呈现静谧的天空蓝UI界面，中心有一个简化的数字钱包图标，代表接收端。\n动画核心是一个明亮的扁平化金币，带有细腻的边缘高光。动画开始时，金币从左侧屏幕中心以弹簧效果（Spring easing）弹出，伴随轻微的垂直位移。\n金币沿着一条优雅的抛物线轨迹飞行，轨迹由动态流动的虚线（Dashed Line）构成，虚线颜色为半透明的深青色，随金币运动方向产生各向异性的流动感。\n当金币接触右侧手机屏幕时，数字钱包图标产生轻微的缩放呼吸效果或涟漪特效，模拟“入账”的反馈，金币随后平滑地缩小并消失在钱包开口处。\n整体视觉风格严格遵循扁平化设计（Flat Design），无复杂阴影，仅通过色彩明度区分层次。背景色为极淡的灰白色（#F5F7FA），营造干净、专业的金融科技氛围。\n动画节奏设置为2-3秒的无缝循环，关键帧之间使用Ease-in-out缓动函数，确保金币飞行和UI反馈的动作自然流畅。","category":"product-demo-animation","tags":[],"likes":2,"favorites":0,"views":4399,"sourceType":"SvgAnimation","componentSource":"$15","isLiked":false,"isFavorited":false},{"id":"474864d6-3140-47ba-a0ce-87ee6ea1d384","exportName":"$undefined","title":"把“马年起飞”四个字也加一个像血条那样的边框。给攻击后会点亮","description":"把“马年起飞”四个字也加一个像血条那样的边框。给攻击后会点亮文字的敌方坦克添加红色发光效果，区分普通的敌方坦克。再随机增加一些金色坦克，攻击后再画面随机位置（注意不要与建筑物重叠）出现攻击武器。玩家坦克吃掉后火力和射速增强三倍。其他不要改变。","category":"svg-mini-game","tags":[],"likes":0,"favorites":0,"views":5415,"sourceType":"SvgAnimation","componentSource":"$16","isLiked":false,"isFavorited":false},{"id":"a534989e-ce9b-492e-bc4d-cebf4130eb20","exportName":"$undefined","title":"一个人从地球上好望角出发，经过非洲大陆、亚洲大陆，通过白令海","description":"一个人从地球上好望角出发，经过非洲大陆、亚洲大陆，通过白令海峡进入美洲大陆，从北美洲最后来到南美洲最南端，呈现全程路径图，把一些关键位置标注出来","category":"svg-map-animation","tags":[],"likes":0,"favorites":0,"views":5786,"sourceType":"SvgAnimation","componentSource":"$17","isLiked":false,"isFavorited":false}],"initialEntryAnimationMap":{"stem-knowledge-animation":{"id":"2cc6ac72-af60-499a-8a6d-d140c1285cd7","exportName":"$undefined","title":"电磁感应实验","description":"电磁感应实验","category":"stem-knowledge-animation","tags":[],"likes":0,"favorites":0,"views":2893,"sourceType":"SvgAnimation","componentSource":"$18","isLiked":false,"isFavorited":false},"svg-map-animation":{"id":"a534989e-ce9b-492e-bc4d-cebf4130eb20","exportName":"$undefined","title":"一个人从地球上好望角出发，经过非洲大陆、亚洲大陆，通过白令海","description":"一个人从地球上好望角出发，经过非洲大陆、亚洲大陆，通过白令海峡进入美洲大陆，从北美洲最后来到南美洲最南端，呈现全程路径图，把一些关键位置标注出来","category":"svg-map-animation","tags":[],"likes":0,"favorites":0,"views":5786,"sourceType":"SvgAnimation","componentSource":"$19","isLiked":false,"isFavorited":false},"data-visualization-animation":{"id":"73bf9841-d71b-452a-aea8-85c491d592bc","exportName":"$undefined","title":"用3D立体饼图展示世界经济体排名","description":"用3D立体饼图展示世界经济体排名","category":"data-visualization-animation","tags":[],"likes":0,"favorites":0,"views":398,"sourceType":"SvgAnimation","componentSource":"$1a","isLiked":false,"isFavorited":false},"3d-animation":{"id":"b657e467-0a38-4e3d-9a96-ce4bb9f07844","exportName":"$undefined","title":"创建一个可交互的咖啡因分子（C8H10N4O2）3D 可视化","description":"创建一个可交互的咖啡因分子（C8H10N4O2）3D 可视化。原子用颜色区分的球体渲染：碳深灰、氢白色、氮蓝色、氧红色，化学键用圆柱体连接。分子在深蓝渐变背景上沿纵轴缓慢自转，背景带有淡淡的网格雾效。启用 OrbitControls，观众可自由旋转、缩放、平移。使用前上方柔和主光源、后方冷色轮廓光和环境补光，使每根化学键都清晰可见。每个原子旁边浮动始终朝向相机的文字标签（C/H/N/O）。场景首次加载时，原子从外侧飞入并就位，随后进入自转循环。画面一角叠加极简 HUD，显示分子式与摩尔质量。整体冷静、教学级化学课堂品质。","category":"3d-animation","tags":[],"likes":0,"favorites":0,"views":126,"sourceType":"SvgAnimation","componentSource":"$1b","isLiked":false,"isFavorited":false},"hand-drawn-animation":{"id":"40a90dd8-7cb4-49fd-b034-379b11c2829a","exportName":"$undefined","title":"画一只圣诞老人，细节要丰富","description":"画一只猫，细节要丰富","category":"hand-drawn-animation","tags":[],"likes":0,"favorites":0,"views":158,"sourceType":"SvgAnimation","componentSource":"$1c","isLiked":false,"isFavorited":false},"text-svg-animation":{"id":"f652bd2b-8b9c-41f9-a6da-0b419e5184cb","exportName":"$undefined","title":"把上面字母S的主题色换成金黄色，其他动效保持不变","description":"把上面字母S的主题色换成金黄色，其他动效保持不变","category":"text-svg-animation","tags":[],"likes":0,"favorites":0,"views":270,"sourceType":"SvgAnimation","componentSource":"$1d","isLiked":false,"isFavorited":false},"svg-logo-animation":{"id":"7de1eec5-6a85-4964-9277-2aec5e5a2ad5","exportName":"$undefined","title":"用线条慢慢勾勒出苹果公司的logo","description":"用线条慢慢勾勒出苹果公司的logo","category":"svg-logo-animation","tags":[],"likes":0,"favorites":0,"views":385,"sourceType":"SvgAnimation","componentSource":"$1e","isLiked":false,"isFavorited":false},"product-demo-animation":{"id":"226a52af-7b37-4cb9-9632-6de41e3f92a0","exportName":"$undefined","title":"微信发送消息过程","description":"微信发送消息过程","category":"product-demo-animation","tags":[],"likes":0,"favorites":0,"views":2335,"sourceType":"SvgAnimation","componentSource":"$1f","isLiked":false,"isFavorited":false},"flowchart-animation":{"id":"6da4394f-610e-4e1f-92c7-d6ecff10f250","exportName":"$undefined","title":"做一个tracert命令的运行逻辑，每一步都用动画呈现出来","description":"做一个tracert命令的运行逻辑，每一步都用动画呈现出来","category":"flowchart-animation","tags":[],"likes":0,"favorites":0,"views":3955,"sourceType":"SvgAnimation","componentSource":"$20","isLiked":false,"isFavorited":false},"svg-loading-animation":{"id":"fe263417-709e-405f-be5f-052c28dcdf14","exportName":"$undefined","title":"生成一个数据加载动画，转圈+呼吸灯的效果","description":"生成一个数据加载动画，转圈+呼吸灯的效果","category":"svg-loading-animation","tags":[],"likes":0,"favorites":0,"views":353,"sourceType":"SvgAnimation","componentSource":"$21","isLiked":false,"isFavorited":false},"stick-figure-animation":{"id":"d686d8bd-9eed-47e5-9fc3-9ebfe325ddcb","exportName":"$undefined","title":"兩個火柴人使用各種炫酷技能打架，例：巨大化、招喚黑洞、激光、","description":"兩個火柴人使用各種炫酷技能打架，例：巨大化、招喚黑洞、激光、護盾、時間暫停、隔空取物、萬劍歸宗等","category":"stick-figure-animation","tags":[],"likes":2,"favorites":0,"views":1010,"sourceType":"SvgAnimation","componentSource":"$22","isLiked":false,"isFavorited":false},"interactive-svg-animation":{"id":"b3c0e65a-e55c-40f7-8522-fec6e1962b40","exportName":"$undefined","title":"月相的变化，设置农历初一、初三、初五、初七、初十、十五、十八","description":"月相的变化，设置农历初一、初三、初五、初七、初十、十五、十八、二十、二十三、二十五、二十七、三十动画演示变化，按钮分两行，点按钮出现月相变化过程，按钮可以点。旁边，总结月相变化的规律，上半月亮面在左还是右，由缺到圆还是由圆到缺","category":"interactive-svg-animation","tags":[],"likes":2,"favorites":0,"views":2337,"sourceType":"SvgAnimation","componentSource":"$23","isLiked":false,"isFavorited":false},"svg-line-drawing":{"id":"dada64a2-00d3-4517-a851-aad4061c14ab","exportName":"$undefined","title":"使用线条勾勒形状","description":"使用线条勾勒 Chrome 浏览器的形状","category":"svg-line-drawing","tags":[],"likes":0,"favorites":0,"views":75,"sourceType":"SvgAnimation","componentSource":"$24","isLiked":false,"isFavorited":false},"svg-mini-game":{"id":"cefb9cbf-b98f-49cb-9997-7c66bad62fa3","exportName":"$undefined","title":"俯瞰视角的复古像素风与现代扁平化矢量设计结合，背景采用深灰色","description":"俯瞰视角的复古像素风与现代扁平化矢量设计结合，背景采用深灰色磨砂质感的战场地图。\n红褐色砖墙具有清晰的纹理，银灰色钢块带有金属拉丝光泽，翠绿色灌木丛呈现半透明叠加效果。\n两辆坦克分别为明亮的柠檬黄与深沉的森林绿，车体细节包括旋转的履带和带有高光边缘的炮塔。\n坦克在迷宫中呈直角转向移动，履带滚动时伴随细微的尘土飞扬颗粒动画。\n炮塔快速旋转并锁定目标，发射出带有橙色霓虹光效的圆形炮弹","category":"svg-mini-game","tags":[],"likes":0,"favorites":0,"views":2015,"sourceType":"SvgAnimation","componentSource":"$25","isLiked":false,"isFavorited":false},"dynamic-view-webpage":{"id":"c5e463ce-a951-4780-a3b1-8b6b8dd13633","exportName":"$undefined","title":"讲解一下三体系列","description":"讲解一下三体系列","category":"dynamic-view-webpage","tags":[],"likes":2,"favorites":0,"views":6316,"sourceType":"DynamicView","componentSource":"$26","isLiked":false,"isFavorited":false}},"initialHomeHtmlVideoCases":{"4e23e305-be79-44b4-a112-e3bc47ea46f7":{"id":"4e23e305-be79-44b4-a112-e3bc47ea46f7","exportName":"$undefined","title":"深度拆解：大语言模型（LLM）是如何练成的？","description":"讲解大模型训练的过程","category":"html-video","tags":[],"likes":0,"favorites":0,"views":603,"sourceType":"HTMLVideo","componentSource":"$27"},"ea23d8c8-817a-4ca3-a581-2a2c85792166":{"id":"ea23d8c8-817a-4ca3-a581-2a2c85792166","exportName":"$undefined","title":"高中数学：数列的奥秘与规律","description":"讲解高中数学中数列的知识","category":"html-video","tags":[],"likes":0,"favorites":0,"views":55,"sourceType":"HTMLVideo","componentSource":"$28"},"1cdf4d72-1ddc-4ce5-9527-9ebae041b871":{"id":"1cdf4d72-1ddc-4ce5-9527-9ebae041b871","exportName":"$undefined","title":"极简物理史：从万有引力到量子群星","description":"做一个讲解物理学发展历史视频","category":"html-video","tags":[],"likes":0,"favorites":0,"views":64,"sourceType":"HTMLVideo","componentSource":"$29"},"dd23bdea-04b1-4c94-859a-0e3b9d9d4ef6":{"id":"dd23bdea-04b1-4c94-859a-0e3b9d9d4ef6","exportName":"$undefined","title":"从SVM到Transformer：自然语言处理的进化史","description":"讲解NLP中的SVM、RNN、LSTM、Transformer的严谨过程，技术原理","category":"html-video","tags":[],"likes":0,"favorites":0,"views":65,"sourceType":"HTMLVideo","componentSource":"$2a"},"c1f72662-950f-4dce-b155-a816b6131bc9":{"id":"c1f72662-950f-4dce-b155-a816b6131bc9","exportName":"$undefined","title":"解锁速度：大模型如何","description":"解释大模型缓存的原理","category":"html-video","tags":[],"likes":0,"favorites":0,"views":49,"sourceType":"HTMLVideo","componentSource":"$2b"}},"initialTotal":null}]]
