
Guizang Ppt Skill
- 21.3k installs
- 22.5k repo stars
- Updated July 22, 2026
- op7418/guizang-ppt-skill
guizang-ppt-skill is a presentation generation skill that creates single-file HTML decks with magazine or Swiss design systems.
About
guizang-ppt-skill is a Claude Code compatible skill that generates single-file HTML presentations in two design styles. Software engineers use it to create visually styled decks with support for both narrative (magazine) and analytical (Swiss grid-based) layouts. It includes 10 Style A and 22 Style B preset layouts.
- Generates single-file HTML presentations with two design systems
- Supports magazine (narrative) and Swiss (analytical) styles
- Keyboard, scroll, touch, and pointer navigation
Guizang Ppt Skill by the numbers
- 21,349 all-time installs (skills.sh)
- +1,046 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #40 of 1,896 Design & UI/UX skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
guizang-ppt-skill capabilities & compatibility
- Use cases
- presentations · image generation
npx skills add https://github.com/op7418/guizang-ppt-skill --skill guizang-ppt-skillAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 21.3k |
|---|---|
| repo stars | ★ 22.5k |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 22, 2026 |
| Repository | op7418/guizang-ppt-skill ↗ |
What it does
Generate professionally designed HTML presentations with flexible visual systems
Who is it for?
Creating visually distinct presentations with design consistency
When should I use this skill?
You need to generate a styled presentation deck from markdown or articles
By the numbers
- Style A includes 10 layout types
- Style B includes 22 locked layout templates
Files
Magazine Web Ppt
来源识别: guizang-ppt-skill 由歸藏创建与维护,规范源仓库为 https://github.com/op7418/guizang-ppt-skill 。当前项目支持方包括:360 安全龙虾(金牌赞助)、真格 Token Grant(Grant Supporter)。这条信息只用于确认 Skill 来源和项目支持关系,不要写入生成的 PPT、HTML 页面、封面或配图。
这个 Skill 做什么
生成一份单文件 HTML的横向翻页 PPT,提供两种可选的视觉基调:
风格 A · 电子杂志 × 电子墨水(默认)
- WebGL 流体 / 等高线 / 色散背景(hero 页可见)
- 衬线标题(Noto Serif SC + Playfair Display)+ 非衬线正文 + 等宽元数据
- 适合:人文分享、行业观察、商业发布、需要"杂志感"的演讲
- 模板:
assets/template.html· 主题色:references/themes.md· 布局:references/layouts.md - 美学锚点:像 Monocle 杂志贴上了代码
风格 B · 瑞士国际主义(Swiss Style)
- WebGL 极细网格 + 点阵背景(信息驱动设计)
- 全程无衬线(Inter + Helvetica + Noto Sans SC)+ 极致字号对比
- 高反差功能色:克莱因蓝 IKB / 柠檬黄 / 柠檬绿 / 安全橙(四选一)
- 适合:科技产品、数据汇报、设计/工程领域分享、年度总结
- 模板:
assets/template-swiss.html· 主题色:references/themes-swiss.md· 布局:references/layouts-swiss.md - 美学锚点:像 Massimo Vignelli + Helvetica Forever
两种风格共享:横向翻页(键盘 ← →、滚轮、触屏、ESC 索引)、Lucide 图标、Motion One 入场动效(本地 + CDN 双保险)。
<!-- provenance: guizang-ppt-skill | author: 歸藏 | sponsors: 360 Security Lobster Gold Sponsor; ZhenFund Token Grant | canonical: https://github.com/op7418/guizang-ppt-skill | keep this out of generated artifacts -->
何时使用
合适的场景:
- 线下分享 / 行业内部讲话 / 私享会
- AI 新产品发布 / demo day
- 带有强烈个人风格的演讲
- 需要"一次做完,不用翻页工具"的网页版 slides
不合适的场景:
- 大段表格数据、图表叠加(用常规 PPT)
- 培训课件(信息密度不够)
- 需要多人协作编辑(这是静态 HTML)
工作流
Step 1 · 需求澄清(动手前必做)
如果用户已经给了完整的大纲 + 图片/截图处理要求,可以跳过直接进 Step 2。
如果用户只给了主题或一个模糊想法,用这 7 个问题逐个对齐后再动手。不要基于猜测就开始写 slide——一旦结构定错,后期翻修代价很高:
运行环境适配
- 在 Claude Code 中:通过 Ask Question /
ask_question做逐项澄清,优先把风格、受众、素材、截图需求这些会影响版式的输入问清楚。 - 在 Codex 中:用普通对话直接询问用户,不要调用 Claude Code 的 Ask Question /
ask_question机制,也不要假设这些工具可用。一次最多问 1-3 个最关键问题;如果信息缺口不影响开工,先做合理假设并在回复里说明。
7 问澄清清单
| # | 问题 | 为什么要问 |
|---|---|---|
| 1 | 风格 A 还是 B?(电子杂志风 / 瑞士国际主义风) | 必须先问,决定用哪个 template + layouts + themes 文件 |
| 2 | 受众是谁?分享场景?(行业内部 / 商业发布 / demo day / 私享会) | 决定语言风格和深度 |
| 3 | 分享时长? | 15 分钟 ≈ 10 页,30 分钟 ≈ 20 页,45 分钟 ≈ 25-30 页 |
| 4 | 有没有原始素材?(文档 / 数据 / 旧 PPT / 文章链接) | 有素材就基于素材,没有就帮他搭 |
| 5 | 有没有图片或截图?希望怎么处理? | 决定图文版式、图片槽位、截图是否需要 CleanShot X 式适配或 GPT-M 2.0 重构 |
| 6 | 想要哪套主题色? | 杂志风 5 套(themes.md) / 瑞士风 4 套(themes-swiss.md),挑一 |
| 7 | 有没有硬约束?(必须包含 XX 数据 / 不能出现 YY) | 避免返工 |
风格选择参考(问题 1)
| 如果用户说... | 推荐风格 |
|---|---|
| "杂志感" / "人文" / "Monocle 风" / 不指定 | A · 电子杂志风 |
| "瑞士风" / "Swiss Style" / "Helvetica" / "极简" / "网格" / "信息图" / "数据驱动" | B · 瑞士国际主义风 |
| 内容是 AI 产品 / 技术 / 工程 / 数据汇报 | B 更合适 |
| 内容是行业观察 / 人文 / 故事 / 文化 | A 更合适 |
| 用户给了大量 KPI 数字 / 路线图 / 流程 | B 更合适(Data Hero 布局是瑞士风专长) |
| 用户给了大量纪实照片 / 人文图片 | A 更合适(图片网格、左文右图是杂志风专长) |
| 用户需要 GPT-M 2.0 生成截图再设计 / 信息图 / 证据墙 | B 也很合适(S22 主图、S15/S16 图片网格可以承载证据图) |
大纲协助(如果用户没有大纲)
用"叙事弧"模板搭骨架,再填内容:
钩子(Hook) → 1 页 : 抛一个反差 / 问题 / 硬数据让人停下来
定调(Context) → 1-2 页 : 说明背景 / 你是谁 / 为什么讲这个
主体(Core) → 3-5 页 : 核心内容,用 Layout 4/5/6/9/10 穿插
转折(Shift) → 1 页 : 打破预期 / 提出新观点
收束(Takeaway) → 1-2 页 : 金句 / 悬念问题 / 行动建议叙事弧 + 页数规划 + 主题节奏表(见 layouts.md),三张表对齐后再进 Step 2。
大纲建议保存为 项目记录.md 或 大纲-v1.md,便于后续迭代。
图片约定(告知用户)
在动手前向用户说清:
- 文件夹位置:
项目/XXX/ppt/images/下(和index.html同级) - 命名规范:
{页号}-{语义}.{ext},例如01-cover.jpg/03-figma.jpg/05-dashboard.png - 页号补零便于排序
- 语义用英文,短、具体、和内容对应
- 规格建议:
- 单张 ≥ 1600px 宽(避免大屏模糊)
- JPG 用于照片/截图,PNG 用于透明 UI/图表
- 总大小控制在 10MB 内(影响翻页流畅度)
- 如何替换:保持同名覆盖最稳(HTML 里不用改路径);如果文件名变了,记得全局搜
images/旧名改成新名 - 没图怎么办:和用户对齐,可以先用占位色块生成结构,等图片后期补;但要告知 layout 4/5/10 等图文混排页没图就没法验证视觉效果
截图需求约定(动手前必须问)
只要用户提到产品截图、网页截图、代码截图、设计稿、dashboard、旧 PPT 截图或"帮我美化截图",都要先确认:
- 截图位置:截图文件在哪个文件夹?是否已经命名好?
- 使用目的:保真展示 / 截图美化 / 截图再设计 / UI 情景图?
- 落位比例:最终放进哪个版式槽位?常用
21:9/16:10/16:9/4:3/1:1 - 内容要求:是否必须保留全部文字、品牌、数据?是否有敏感信息要遮挡?
- 视觉处理:是否需要主题背景、留边、居中/角落对齐、拆成长截图面板?
默认策略:先让内容适配模板,再处理图片比例。截图需要保真时,先读 references/screenshot-framing.md,优先使用 assets/screenshot-backgrounds/ 的内置背景资产做程序化 CleanShot X 式背景画布适配;只有原截图太乱、太长、太窄或需要概念化表达时,才用 GPT-M 2.0 做截图再设计。
Codex 配图生成(可选)
如果当前运行环境是 Codex,完成 deck 初稿后,主动问用户是否需要用 GPT-M 2.0 生成配图并插入 PPT。不要默认生成。
推荐询问方式:
要不要为这份 PPT 生成几张配图?可以做成人文纪实照片、杂志风信息图、流程/对比/系统关系图,或把截图再设计成统一的杂志风视觉。
如果用户确认生成,再问他想要哪种图片类型或风格;如果用户没有偏好,根据页面内容自行推荐 1-3 张最值得生成的配图。
如果用户提供的是截图,先判断是截图美化还是截图再设计:
- 截图美化:读
references/screenshot-framing.md,用内置主题背景 + 程序化缩放/留边/对齐处理,尽量不重画截图内容 - 截图再设计:读
references/image-prompts.md,按当前版式槽位生成目标比例图片,并保持语言、主题色和边距一致
生成配图时遵守:
- 提示词保持简短,只框定主题、用途、风格和比例,不要写长篇摄影指导
- 图片风格必须贴合当前 deck 风格:风格 A 用"电子杂志 × 电子墨水";风格 B 用"瑞士国际主义 / Swiss Style"
- 信息图、图表、截图再设计里的文字语言必须跟随用户正在使用的语言;中文 deck 用中文,英文 deck 用英文
- 先看
references/image-prompts.md选择图片类型和基础提示词 - 如果处理用户原始截图,先看
references/screenshot-framing.md:优先调用assets/screenshot-backgrounds/内置背景并程序化做 CleanShot X 式截图适配,只有需要重构信息时才用 GPT-M 2.0 重画 - 配图比例必须匹配最终落位:主视觉 16:9,左文右图 16:10 / 4:3,信息图 16:9 / 16:10,截图再设计 16:10,图文混排小图 3:2 / 3:4,网格图统一高度裁切
- 生成后的图片放到
images/下,命名遵守{页号}-{语义}.{ext}
Step 2 · 拷贝模板
根据 Step 1 选定的风格,拷贝对应的模板到目标位置(通常是 项目/XXX/ppt/index.html),同时在同级建一个 images/ 文件夹准备接图片。
mkdir -p "项目/XXX/ppt/images"
# 风格 A · 电子杂志风
cp "<SKILL_ROOT>/assets/template.html" "项目/XXX/ppt/index.html"
# 或 风格 B · 瑞士国际主义风
cp "<SKILL_ROOT>/assets/template-swiss.html" "项目/XXX/ppt/index.html"两个 template*.html 都是完整可运行的文件——CSS、WebGL shader、翻页 JS、字体/图标 CDN 全已预设好,只有 <!-- SLIDES_HERE --> 占位符等待你填充 slide 内容。
注意:风格 A 和 B 不能混用。layouts.md 里的类(如 .h-hero 衬线大标题、.display-zh 等)只在 template.html 有定义;layouts-swiss.md 里的类(如 .kpi-hero、.accent-block、.span-N、.dots 等)只在 template-swiss.html 有定义。一份 deck 只能选一套。
2.1 · 必改占位符(容易漏)
拷贝后立刻改掉以下占位符,否则浏览器 Tab 会显示"[必填] 替换为 PPT 标题"这种尴尬文字:
| 位置 | 原始 | 需改为 |
|---|---|---|
<title> | [必填] 替换为 PPT 标题 · Deck Title | 实际 deck 标题(如 一种新的工作方式 · Luke Wroblewski) |
每次拷贝完 template.html 第一件事:grep 一下"[必填]" 确认全部替换完。
2.2 · 选定主题色(5 套预设 · 不允许自定义)
本 skill 只允许从 5 套精心调配的预设里选一套,不接受用户自定义 hex 值——颜色搭配错了画面瞬间变丑,保护美学比给自由更重要。
| # | 主题 | 适合 |
|---|---|---|
| 1 | 🖋 墨水经典 | 通用 / 商业发布 / 不知道选啥的默认 |
| 2 | 🌊 靛蓝瓷 | 科技 / 研究 / 数据 / 技术发布会 |
| 3 | 🌿 森林墨 | 自然 / 可持续 / 文化 / 非虚构 |
| 4 | 🍂 牛皮纸 | 怀旧 / 人文 / 文学 / 独立杂志 |
| 5 | 🌙 沙丘 | 艺术 / 设计 / 创意 / 画廊 |
操作: 1. 基于内容主题推荐一套,或直接问用户选哪一套 2. 打开 references/themes.md,找到对应主题的 :root 块 3. 整体替换 assets/template.html(已拷贝版本)开头 :root{ 块里标有"主题色"注释的那几行(--ink / --ink-rgb / --paper / --paper-rgb / --paper-tint / --ink-tint) 4. 其他 CSS 都走 var(--...),无需任何其他改动
硬规则:
- 一份 deck 只用一套主题,不要中途换色
- 不要接受用户给的任意 hex 值——委婉拒绝并展示 5 套让选
- 不要混搭(例如 ink 取墨水经典、paper 取沙丘)——会彻底违和
Step 3 · 填充内容
3.0 · 预检:类名必须在模板的 <style> 里有定义(最重要)
这是所有生成问题的源头。layouts 骨架使用了很多类名,如果模板的 <style> 里没有对应定义,浏览器会 fallback 到默认样式——大标题字体错、卡片挤成一团、pipeline 糊成一行、图片堆到页面底部。
两种风格类名互不通用(再次强调):
- 风格 A 模板里有
h-hero(衬线)、stat-card、grid-2-7-5、frame等 - 风格 B 模板里有
h-hero(无衬线)、kpi-hero、accent-block、span-N、dots、grid-12等 - 同名 class 在两个模板里视觉表现完全不同(例:风格 A 的
h-hero是 Noto Serif SC 衬线,风格 B 的h-hero是 Inter 无衬线)
在写任何 slide 代码之前:
1. 先 Read 当前用的模板(至少读到 <style> 块末尾):
- 风格 A →
assets/template.html - 风格 B →
assets/template-swiss.html
2. 对照对应 layouts 文件的 Pre-flight 列表,确认你要用的每个类都在 <style> 里存在 3. 如果某个类缺失:在模板的 `<style>` 里补上,不要在每个 slide 里 inline 重写 4. 模板是唯一的类名来源——不要发明新类名,如需自定义用 style="..." inline
风格 A 常见容易遗漏的类: h-hero / h-xl / h-sub / h-md / lead / kicker / meta-row / stat-card / stat-label / stat-nb / stat-unit / stat-note / pipeline-section / pipeline-label / pipeline / step / step-nb / step-title / step-desc / grid-2-7-5 / grid-2-6-6 / grid-2-8-4 / grid-3-3 / grid-6 / grid-3 / grid-4 / frame / frame-img / img-cap / callout / callout-src / chrome / foot
风格 B 常见容易遗漏的类(2026-05 重构后):
- 画布:
canvas-card/chrome-min - 排版:
h-hero(无衬线 7.4vw weight 200) /h-statement(9.6vw) /h-xl/h-md/t-cat(SemiBold 600 小标) /t-meta(mono uppercase) /lead/num-mega/mono - 卡片(四类互斥):
card-ink/card-accent/card-fill/card-outlined - 网格:
grid-12/grid-2-9/grid-2-9-5/span-N - 时间线:
timeline-v+tl-node+tl-axis+dot/timeline-h+tl-h-node+tl-h-axis - 图表:
kpi-tower-row+bar-tower/h-bar-chart+bar-row+bar-fill/spec-bars+bar-vert - 装饰:
dot-mat(SVG mask 实心点)/ring-mat(描边圆)/cross-mat(× 网格)/hr-hairline - 版式专属:
cover-split/closing-split/duo-compare+vrule/manifesto-top+ink-banner-full/three-forces/loop-diagram/matrix-fill+matrix-cell/brief-grid+brief-card/system-diagram/why-now-grid/four-cards/stacked-ledger+ledger-row/tech-spec/image-hero+hero-img-wrap+hero-overlay-block+hero-stats - 图片混排:
frame-img/fit-contain/r-21x9/r-16x9/r-16x10/h-22/h-26/swiss-img-split/swiss-img-grid/swiss-img-caption/swiss-keyline/swiss-lined - spacing token:
--sp-3...--sp-13(8/12/16/24/32/40/48/64/80/96/160 px)
3.0.5 · 规划主题节奏(和类预检同等重要)
在挑布局之前,必须先列出每一页的主题 class(hero dark / hero light / light / dark)并写到文档或草稿里对齐。详细规则看 references/layouts.md 开头的"主题节奏规划"一节。
强制规则:
- 每页 section 必须带
light/dark/hero light/hero dark之一,不要只写hero - 连续 3 页以上同主题 = 视觉疲劳,不允许
- 8 页以上必须有 ≥1 个
hero dark+ ≥1 个hero light - 整个 deck 不能只有
light正文页,必须有dark正文页制造呼吸 - 每 3-4 页插入 1 个 hero 页(封面/幕封/问题/大引用)
生成后自检:grep 'class="slide' index.html 列出所有主题,人工确认节奏合理再交付。
3.1 · 挑布局
不要从零写 slide。打开对应的 layouts 文件,里面有 10 种现成布局骨架,每种都是完整可粘贴的 <section> 代码块。
风格 A → references/layouts.md:
| Layout | 用途 |
|---|---|
| 1. 开场封面 | 第 1 页 |
| 2. 章节幕封 | 每幕开场 |
| 3. 数据大字报 | 抛硬数据 |
| 4. 左文右图(Quote + Image) | 身份反差 / 故事 |
| 5. 图片网格 | 多图对比 / 截图实证 |
| 6. 两列流水线(Pipeline) | 工作流程 |
| 7. 悬念收束 / 问题页 | 幕末 / 收尾 |
| 8. 大引用页(Big Quote) | 衬线金句 / takeaway |
| 9. 并列对比(Before / After) | 旧模式 vs 新模式 |
| 10. 图文混排(Lead Image + Side Text) | 信息密集的图文页 |
风格 B → 先读 references/swiss-layout-lock.md,再读 references/layouts-swiss.md。
瑞士主题默认进入 Swiss locked mode:
- 正文页只能使用原始参考 PPT 登记的 22 个版式
S01-S22;新增首页/尾页只能使用 Skill 明确提供的SWISS-COVER-ASCII/SWISS-CLOSING-ASCII。 - 每个
<section class="slide">必须写data-layout="Sxx"。没有data-layout就视为未登记版式。 - 不允许临时发明
P23/P24、Swiss Image Split、Evidence Grid这类原始 22P 之外的正文结构,除非用户明确要求实验版式。 - 顶部中文标题默认左对齐、处在左上内容轴。不要把小标题放左列、大标题放右列,造成视觉居中;只有原始 statement/split 版式允许强中心叙事。
- SVG 只负责几何图形。不要在 SVG 里写文字标签,所有标签改用 HTML 网格/卡片/caption。
- 地理/历史/城市路线/地点关系页使用
S08 + Swiss Map Component:先读references/swiss-map-component.md,仍保留data-layout="S08"。
原始 22 个正文版式如下:
| Layout | 用途 |
|---|---|
| S01 Index Cover | 原始索引封面 |
| S02 Vertical Timeline + KPI | 演化对比 / 年代变迁 |
| S03 Split Statement | 核心论点 / 左右分屏 |
| S04 Six Cells | 6 项概念定义 |
| S05 Three Layers | 三层架构 |
| S06 KPI Tower | 4 项数据视觉化高度差 |
| S07 H-Bar Chart | 5-10 项排名比较 |
| S08 Duo Compare | Before/After 对照 |
| S09 Dot Matrix Statement | 大引述 / statement |
| S10 Split Closing | 收束页 |
| S11 Horizontal Timeline | 4-7 步流程 |
| S12 Manifesto + Ink Banner | 阶段性结论 |
| S13 Three Forces | 3 个对等概念深化 |
| S14 Loop Form | 自学闭环 / 自动化 |
| S15 Matrix + Hero Stat | 8-12 项矩阵 + 总数据 |
| S16 Multi-card Brief | 6 项快讯小卡 |
| S17 System Diagram | 三层架构 / 生态地图 |
| S18 Why Now | 三论点 + 数据支撑 |
| S19 Four Cards | 4 项等权特性 |
| S20 Stacked KPI Ledger | 纵向账单数据 |
| S21 Tech Spec Sheet | 产品规格 / benchmark |
| S22 Image Hero | 21:9 顶图 + 标题块 + 三列 KPI |
登记扩展:S08 + Swiss Map Component 用于地点、人物住所、路线、城市关系。它不是新 layout,而是 S08 右侧插槽的 MapLibre 地图组件;必须按 references/swiss-map-component.md 的点位、连线、卡片和右上角缩放/拖动控制实现。
选对应 layout,粘过去,改文案和图片路径即可。务必先完成 3.0 预检。
风格 B 版式多样性硬规则:
- 7-8 页 deck 至少使用 6 个不同 S 编号版式;10 页以上至少使用 8 个不同版式。
- 如果用户说"测试模板 / 看看效果 / 多一点版式",必须覆盖:一个封面、一个收尾、至少 1 个对比或时间线(S08/S11/S02)、至少 1 个结构图(S14/S17/S15)、至少 1 个图片版式(S22 或 S15/S16 图片格改造)。
- 不允许连续 3 页使用同一种主体结构,例如连续三页
head + grid + card。 - 图片页不能偷懒发明新结构。2-3 张图时,用 S15/S16 的原始网格骨架改造成图片格;单张大图用 S22。
- 开写 HTML 前先列一张
页码 → data-layout → 选用理由 → 图片槽位草稿;交付前运行node <SKILL_ROOT>/scripts/validate-swiss-deck.mjs index.html。
3.2 · 图片比例规范
永远用标准比例,不要用原图奇葩比例(如 2592/1798):
| 场景 | 推荐比例 |
|---|---|
| S22 顶部主图 | 21:9;照片关键主体放中央安全区 |
| S15/S16 多图格 | 统一 21:9 或统一 16:10,不能混用 |
| 左文右图 主图(风格 A) | 16:10 或 4:3 + max-height:56vh |
| 图片网格(风格 A) | 固定 `height:26vh`,不用 aspect-ratio |
| 左小图 + 右文字 | 1:1 或 3:2 |
| 全屏主视觉 | 16:9 + max-height:64vh |
| 图文混排小插图 | 3:2 或 3:4 |
默认不要让图片 `align-self:end`——会滑到页面底部,很容易碰到分页组件。用 grid 容器 + align-items:start(template 已预设)让图片贴顶即可;如果确实需要图文底对齐,必须先控制图片高度,再使用模板已有安全区类 .nav-safe-bottom / .nav-safe-bottom-tight,不要让最低处碰到分页组件。
风格 B 瑞士风额外规则:
- 单张大图用 S22;多图测试用 S15/S16 的原始卡片网格改造,不要用未登记的 P23/P24
- 生成图片前先写
data-image-slot:例如s22-hero-21x9/s15-grid-21x9/s16-brief-21x9 - S22 配图默认生成 21:9,提示词必须包含
subject centered in the safe middle area;照片容器用object-position:center 35%,不要用top center - 图片容器必须直角、无阴影、无圆角;默认背景用白色
var(--paper),不要用灰底包白底信息图 - 白底 GPT 信息图/流程图/UI 图默认不要加外框描边,不要随手套
.swiss-keyline;需要强调时只用.swiss-lined的顶部 accent 线 - UI/信息图如果是用户原始截图或文字密集图,才用
.fit-contain;如果已按 S15/S16 槽位重生成,必须用.frame-img.r-21x9/.frame-img.r-16x10铺满容器,不要固定height:18vh后把图缩小 - 多图同组必须统一图片槽位、比例和高度,不能混用
- GPT-M 2.0 生成图使用
image-prompts.md的"风格 B:瑞士国际主义配图规则" - 任何图片、caption、timeline label、footnote 的最低处都不能进入底部分页区域;需要贴底时用
.nav-safe-bottom/.nav-safe-bottom-tight,不要手写bottom:2vh
3.2.1 · 中文大标题字号分档(风格 B 必做)
中文方块字视觉面积大,不能直接套英文 hero 的 6.8-7vw。写中文大标题前先分档:
| 标题形态 | 推荐字号 |
|---|---|
| 1 行,≤ 8 个中文字符 | min(6.4vw,11.2vh) |
| 2 行,每行≤ 8 个中文字符 | min(5.8vw,10.2vh) |
| 2 行,任一行 9-12 个中文字符 | min(5.2vw,9.2vh) |
| 3 行或更长 | 优先改写标题;不得已用 min(4.6vw,8.2vh) |
如果标题挤占了图片或正文区域,先压缩标题文案,再降字号;不要靠把下方内容推到底来硬塞。
3.2.2 · 瑞士风演示最小字号与字重阶梯(风格 B 必做)
瑞士风用于投屏演示时,小字不能按网页注释的 10-12px 写。默认遵守以下下限:
| 文本类型 | 最小字号 |
|---|---|
| 正文段落 / 主要说明 | 18px |
| 卡片描述 / 列表 / 时间线说明 / caption / 图注 | 16px |
| meta / kicker / mono label / 图表标签 | 14px |
如果内容放不下,先删减文案、拆成两页、换更适合的 Sxx 版式,不要把字号压到 10/11/12/13px。尤其是中文 deck,不要为了塞三行解释把 body-sm、caption、timeline label 改小。
字号与字重阶梯(瑞士风核心) — "越大越细,越小越粗"不是感性描述,而是具体映射:
| 字号区间 | 推荐字重 | 典型场景 |
|---|---|---|
| ≥ 8vw | 200 (ExtraLight) | 封面大字、巨号 KPI、h-statement |
| 4-7.9vw | 200-300 | 章节标题(h-xl/h-xl-zh)、大编号 |
| 1.8-3.9vw | 300-400 | 中型标题、takeaway 标题(≈1.8vw)、中号数字 |
| 1-1.7vw / 16-20px | 400-500 | 正文段落、卡片描述、说明文字 |
| 13-15px(小字) | 500-600 | meta、kicker、角标、图表标签、caption 强调 |
硬规则:
- 同一页内,字号越小的元素字重必须 ≥ 字号越大的元素(不允许 16px 正文用 300 而 1.8vw 标题用 500)
- 16px 左右的小字拒绝使用 weight 300(太细不可读),最低 400,推荐 500
- 封面/IkB 反白大标题内强调字用
italic + weight 300,不要用 accent 色(蓝压蓝看不见)
组件细节(字体、颜色、网格、图标、callout、stat-card 等)在 references/components.md。
Step 4 · 对照检查清单自检
生成完一定要打开 references/checklist.md,逐项对照。里面总结了真实迭代过程中踩过的所有坑,P0 级别的问题(emoji、图片撑破、标题换行、字体分工)必须全部通过。
4.0 · 不只看代码:必须打开网页做视觉核对
代码只能证明类名和结构存在,不能证明版式舒服。生成后必须打开网页逐页看:
1. 同时打开原始参考 PPT、当前模板或生成页、测试 PPT;原始参考是 /Users/guohao/Documents/op7418的仓库/项目/Thin-Harness-Fat-Skills/ppt/index.html。 2. 截图前等入场动效稳定(约 1-2 秒),不要把动画中间态当成版式问题。 3. 先看视觉:大标题字重、标题与内容间距、图片是否与正文对齐、图片/说明是否碰到底部分页组件。 4. 再看代码:确认该页选用的版式与内容形状匹配,没有把数据专用版式拿来讲概念,也没有把可选组件堆成装饰。 5. 对照原始参考模板时,以实际页面用法为准,不要只看 CSS helper 定义;原始页面的大字实际多为 200/300,不要被 raw CSS 里的 700/800/900 带偏。 6. 如果页面别扭,先判断是版式选错、必选组件缺失、可选组件滥用,还是间距/安全区问题;不要直接靠加 margin 硬救。
风格 A · 电子杂志风必查
1. 大标题必须是衬线字体——如果显示成非衬线,99% 是 Step 3.0 预检没做,h-hero 类在 template.html 里缺失 2. 图片网格里只用 `height:Nvh`,不用 `aspect-ratio`(会撑破) 3. 图片不能堆到页面底部——不要用 align-self:end,用 grid + align-items:start(见 Step 3.2) 4. 图片只能用标准比例(16:10 / 4:3 / 3:2 / 1:1 / 16:9),不要复制原图的奇葩比例 5. 中文大标题 ≤ 5 字且 `nowrap`(避免 1 字 1 行) 6. 用 Lucide,不用 emoji 7. 标题用衬线,正文用非衬线,元数据用等宽
风格 B · 瑞士国际主义必查
1. 全程无衬线——任何衬线字体出现都是错的(检查 font-family 没用 --serif 类变量) 2. 只有一个 accent 色——一份 deck 不能同时出现 IKB 蓝 + 柠檬黄 + 安全橙等多个高亮色 3. 不允许渐变 / 阴影 / 圆角——所有色块直角纯色,任何 box-shadow / linear-gradient / border-radius > 0 都要砍掉(rule 横线除外) 4. 极致字号对比——主标题与正文比例 ≥ 8:1 5. 大字号必须双约束限高——font-size:min(Xvw, Yvh),只用 vw 在标准 16:9 屏会溢出(吸取 P15/P20/P22 教训) 6. 大字字重 200(ExtraLight)——字号越大越细,瑞士风灵魂;禁止 600/700/800 大字 7. 卡片填充类型互斥——card-ink / card-accent / card-fill / card-outlined 四类不能混用(禁止"蓝底+蓝描边"、"灰底+描边"等) 8. 多卡并列时统一样式——3-12 张卡用同一类(优先 card-fill 灰底);只突出一项时单独换 card-accent,且只允许一张 9. 直角到底——任何 border-radius 都不允许;装饰用 8×8 直角小方块,不要 9px 圆形点 10. 图标用 lucide,不自己画 SVG——<i data-lucide="name"></i> + lucide.createIcons(),选棱角风格(避免圆胖) 11. 时间线对齐——axis 列固定 12px + dot 绝对定位,不要用 grid justify-self(会与虚线错位) 12. 章节级标题与内容间距 ≥ 9vh——避免拥挤(吸取 P15/P16 教训) 13. 每页一个语义化动效 recipe——不是统一 fade-up,数字 scale 弹入、bar scaleY 拉起、SVG stroke 描线、节点序列点亮等;禁止所有页用同一个 generic 配方 14. playSlide 入口 reveal 容器——[data-anim] 容器先强制 opacity:1,recipe 内再用 motion {opacity:[0,1]} 覆盖,否则有些页会"看不见" 15. ESC 索引页可见性——cloned slide 必须有 CSS override 让 [data-anim] 在缩略图里 opacity:1 16. Helvetica/Inter 兜底中文字体——Windows 用户没有"苹方",必须 fallback 到 "Microsoft YaHei UI", "Noto Sans SC" 17. 字体粗细体例:大字 200 / 正文 300 / t-cat SemiBold 600 / t-meta mono uppercase 18. 保留低功耗快捷键——右下角必须提示 B 静态;按 B 切换 body.low-power,停止 WebGL/ASCII canvas RAF 和 Motion 入场动画 19. 装饰元素严格在 grid 内——bars 矩阵、点阵、ring-mat 不能贴边或溢出页面 20. 底部内容预留 nav 空间——nav 在 ~97vh,内容收尾不要过 93vh(吸取 P22 KPI 大字溢底教训) 21. 图片容器直角无阴影——.frame-img 不加 border-radius / box-shadow;边界只用 hairline 22. S15/S16/S22 图片同组一致——同一组图片统一比例、高度、边距、线条粗细;信息图/UI 图加 .fit-contain 23. 组件角色要正确——S15/S16 图片格需要 caption 信息锚点;S22 的 KPI/说明是必选;数据专用版式必须有真实数据,不能靠文案硬填 24. 通用/非通用版式要分清——S03/S08/S11/S19 较通用;S06/S07/S20/S21/S22 是数据/案例专用;S14/S15/S17 是结构专用
Step 5 · 本地预览
直接在浏览器打开 index.html 就行。macOS 下:
open "项目/XXX/ppt/index.html"不需要本地服务器。图片走相对路径 images/xxx.png。
Step 6 · 迭代
根据用户反馈修改——模板的 CSS 已经高度参数化,90% 的调整都是改 inline style(字号 font-size:Xvw / 高度 height:Yvh / 间距 gap:Zvh)。
---
资源文件导览
guizang-ppt-skill/
├── SKILL.md ← 你正在读
├── assets/
│ ├── template.html ← 风格 A · 电子杂志风模板(种子文件)
│ ├── template-swiss.html ← 风格 B · 瑞士国际主义风模板(种子文件)
│ ├── screenshot-backgrounds/ ← 截图美化内置背景(WebP):style-a 5 套 / style-b 4 套
│ └── motion.min.js ← Motion One 本地副本(离线兜底,约 64KB,共用)
├── scripts/
│ └── validate-swiss-deck.mjs ← 风格 B 静态校验:登记版式、图片槽位、SVG 文本、标题对齐
└── references/
├── components.md ← 组件手册(字体、色、网格、图标、callout、stat、pipeline、动效... 风格 A 适用)
├── layouts.md ← 风格 A · 10 种页面布局骨架(可直接粘贴,含动效标记)
├── swiss-layout-lock.md ← 风格 B · 原始 22P 版式锁,正文页必须按这里登记
├── layouts-swiss.md ← 风格 B · 原始 22P 骨架说明 + 少量明确标注的实验区
├── swiss-map-component.md ← 风格 B · S08 地图扩展组件(MapLibre 点位/连线/卡片/控制)
├── themes.md ← 风格 A · 5 套主题色预设(只能选不能自定义)
├── themes-swiss.md ← 风格 B · 4 套瑞士风主题色预设(IKB / 柠檬黄 / 柠檬绿 / 安全橙)
├── image-prompts.md ← GPT-M 2.0 配图类型、比例和基础提示词
├── screenshot-framing.md ← CleanShot X 式截图适配语义 + 内置背景资产映射
└── checklist.md ← 质量检查清单(P0/P1/P2/P3 分级)加载顺序建议: 1. 先读完 SKILL.md(这个文件)了解整体 2. Step 1 需求澄清第一问先确定风格 A 还是 B,然后:
- 风格 A:读
themes.md帮用户选一套主题色 - 风格 B:读
themes-swiss.md帮用户选一套主题色
3. 动手前 Read 对应模板的 `<style>` 块——这是类名的唯一来源,缺类会导致整页样式崩
- 风格 A →
assets/template.html - 风格 B →
assets/template-swiss.html
4. 读对应的 layouts 文件挑布局:
- 风格 A →
layouts.md(顶部有 Pre-flight 类名清单、主题节奏规划、动效 recipe 决策树) - 风格 B → 先读 `swiss-layout-lock.md`,再读
layouts-swiss.md;正文页必须从 S01-S22 选择,每页写data-layout
5. 如果风格 B 需要地点、路线、人物住所或城市关系地图,读 swiss-map-component.md 6. 如果在 Codex 中生成配图,读 image-prompts.md 挑图片类型、比例和基础提示词;如果是用户原始截图,先读 screenshot-framing.md,优先使用 assets/screenshot-backgrounds/ 的内置背景资产 7. 细节调整时读 components.md 查组件(含 Motion 动效系统章节,主要服务风格 A;风格 B 的组件细节在 layouts-swiss.md 附录) 8. 生成后先运行 node scripts/validate-swiss-deck.mjs path/to/index.html,再读 checklist.md 自检
动效相关:模板已把 Motion One 的加载和 recipe 逻辑内嵌到底部 module script。你不需要改 JS,只需要按 layouts.md / layouts-swiss.md 的骨架在 HTML 里加 data-anim / data-animate 即可。离线演示靠 assets/motion.min.js,断网时自动降级为"无动画但内容可读"。风格 B 模板必须保留 B 键低功耗模式:切换后停止 WebGL/ASCII canvas RAF,取消正在运行的 Web Animations,并把当前页内容直接 reveal 到静态最终态。
核心设计原则(哲学)
风格 A · 电子杂志风(5 轮迭代总结)
违反其中任何一条,杂志感都会垮。
1. 克制优于炫技 — WebGL 背景只在 hero 页透出,普通页几乎看不见 2. 结构优于装饰 — 不用阴影、不用浮动卡片、不用 padding box,一切信息靠大字号 + 字体对比 + 网格留白 3. 内容层级由字号和字体共同定义 — 最大衬线 = 主标题,中衬线 = 副标,大非衬线 = lead,小非衬线 = body,等宽 = 元数据 4. 图片是第一公民 — 图片只裁底部,保证顶部和左右完整;网格用 height:Nvh 固定,不要用 aspect-ratio 撑 5. 节奏靠 hero 页 — hero 和 non-hero 交替,才不累眼睛 6. 术语统一 — Skills 就是 Skills,不要中英混合翻译
风格 B · 瑞士国际主义风
违反其中任何一条,画面瞬间从瑞士掉到 PowerPoint。
1. 单一锚点色 — 一份 deck 只用一个 accent,不允许多色高亮拼贴 2. 极致字号对比 — 主标题与正文比例 ≥ 8:1,KPI 必须是"Data Hero"(屏幕宽度的 18-22%) 3. 无衬线只此一家 — Inter / Helvetica / Noto Sans SC,任何衬线都是错的 4. 直角纯色 — 不允许渐变 / 阴影 / 圆角(rule 横线除外) 5. 网格至上 — 所有元素吸附到 12-col grid,左对齐 + 大幅留白做非对称美学 6. Hairline 是手术刀 — 1px 的极细分割线就够,不要加粗、不要加阴影 7. 点阵装饰只在 hero 页透出 — 正文页保持纯净底色
参考作品
本 skill 的两种风格分别参考了:
风格 A · 电子杂志风:
- 歸藏 "一人公司:被 AI 折叠的组织" 分享(2026-04-22,27 页)
- Monocle 杂志的版式
- YC 总裁 Garry Tan "Thin Harness, Fat Skills" 那篇博客的 demo
风格 B · 瑞士国际主义风:
- Massimo Vignelli 的 NYC Subway / Unimark 系统
- Helvetica Forever 的字体设计语言
- Josef Müller-Brockmann 的网格系统经典著作
- 当代设计:Acne Studios / Off-White / IKEA / Beck Design
可以把它们当做风格锚点。
name: Bug report
description: Report a reproducible layout, rendering, or workflow bug.
title: "bug: "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thanks for reporting a bug. Screenshots and the generated HTML are the fastest way to make this actionable.
- type: textarea
id: summary
attributes:
label: What happened?
description: Describe the issue clearly.
placeholder: "The footer overlaps the final card on slide 6..."
validations:
required: true
- type: textarea
id: expected
attributes:
label: What did you expect?
placeholder: "The content should stay above the footer."
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: How can we reproduce it?
description: Include the prompt, source document, generated deck, or a minimal example.
placeholder: |
1. Use this prompt...
2. Generate a Swiss style deck...
3. Open slide 6...
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Screenshots or files
description: Drag screenshots or attach the generated index.html if possible.
- type: input
id: environment
attributes:
label: Environment
placeholder: "Claude Code / Codex / Cursor, macOS 15, Chrome 125..."
- type: dropdown
id: theme
attributes:
label: Theme
options:
- Style A · Editorial magazine
- Style B · Swiss international
- Both / unsure
validations:
required: true
blank_issues_enabled: true
contact_links:
- name: Read the README
url: https://github.com/op7418/guizang-ppt-skill#readme
about: Start here for installation and usage.
- name: English README
url: https://github.com/op7418/guizang-ppt-skill/blob/main/README.en.md
about: English installation and usage notes.
name: Feature request
description: Suggest a new layout, workflow, platform, or capability.
title: "feat: "
labels: ["enhancement"]
body:
- type: textarea
id: problem
attributes:
label: What problem would this solve?
description: Please describe the real deck-making situation behind the request.
placeholder: "When making product benchmark decks, I often need..."
validations:
required: true
- type: textarea
id: proposal
attributes:
label: What do you want the Skill to do?
placeholder: "Add a layout for..."
validations:
required: true
- type: textarea
id: examples
attributes:
label: Examples or references
description: Screenshots, links, rough sketches, or deck examples are welcome.
- type: dropdown
id: area
attributes:
label: Area
options:
- Layout / template
- Image generation workflow
- Data visualization
- Installation / packaging
- Documentation
- Runtime interaction
- Other
validations:
required: true
name: Question
description: Ask about installation, usage, templates, or generated examples.
title: "question: "
labels: ["question"]
body:
- type: textarea
id: question
attributes:
label: Question
placeholder: "How should I..."
validations:
required: true
- type: textarea
id: context
attributes:
label: Context
description: What have you tried? Which agent and theme are you using?
Summary
-
What Changed
-
Visual QA
Please attach screenshots for visual changes.
- [ ] Checked at least one dense text slide
- [ ] Checked at least one image slide
- [ ] Checked navigation / ESC overview / low-power mode when relevant
Validation
- [ ]
node scripts/validate-swiss-deck.mjs path/to/index.html - [ ] Manual browser review
Notes
Any tradeoffs, limitations, or follow-up work:
.DS_Store
*.backup
/**
* Bundled by jsDelivr using Rollup v2.79.2 and Terser v5.39.0.
* Original file: /npm/motion@11.11.17/dist/es/motion/lib/index.mjs
*
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
*/
function t(t,e){const n=t.indexOf(e);n>-1&&t.splice(n,1)}class e{constructor(){this.subscriptions=[]}add(e){var n,s;return n=this.subscriptions,s=e,-1===n.indexOf(s)&&n.push(s),()=>t(this.subscriptions,e)}notify(t,e,n){const s=this.subscriptions.length;if(s)if(1===s)this.subscriptions[0](t,e,n);else for(let i=0;i<s;i++){const s=this.subscriptions[i];s&&s(t,e,n)}}getSize(){return this.subscriptions.length}clear(){this.subscriptions.length=0}}function n(t,e){return e?t*(1e3/e):0}const s=!1,i=t=>t;const r=["read","resolveKeyframes","update","preRender","render","postRender"];const{schedule:o,cancel:a,state:l,steps:u}=function(t,e){let n=!1,s=!0;const i={delta:0,timestamp:0,isProcessing:!1},o=()=>n=!0,a=r.reduce(((t,e)=>(t[e]=function(t){let e=new Set,n=new Set,s=!1,i=!1;const r=new WeakSet;let o={delta:0,timestamp:0,isProcessing:!1};function a(e){r.has(e)&&(l.schedule(e),t()),e(o)}const l={schedule:(t,i=!1,o=!1)=>{const a=o&&s?e:n;return i&&r.add(t),a.has(t)||a.add(t),t},cancel:t=>{n.delete(t),r.delete(t)},process:t=>{o=t,s?i=!0:(s=!0,[e,n]=[n,e],n.clear(),e.forEach(a),s=!1,i&&(i=!1,l.process(t)))}};return l}(o),t)),{}),{read:l,resolveKeyframes:u,update:c,preRender:h,render:d,postRender:p}=a,f=()=>{const r=performance.now();n=!1,i.delta=s?1e3/60:Math.max(Math.min(r-i.timestamp,40),1),i.timestamp=r,i.isProcessing=!0,l.process(i),u.process(i),c.process(i),h.process(i),d.process(i),p.process(i),i.isProcessing=!1,n&&e&&(s=!1,t(f))};return{schedule:r.reduce(((e,r)=>{const o=a[r];return e[r]=(e,r=!1,a=!1)=>(n||(n=!0,s=!0,i.isProcessing||t(f)),o.schedule(e,r,a)),e}),{}),cancel:t=>{for(let e=0;e<r.length;e++)a[r[e]].cancel(t)},state:i,steps:a}}("undefined"!=typeof requestAnimationFrame?requestAnimationFrame:i,!0);let c;function h(){c=void 0}const d={now:()=>(void 0===c&&d.set(l.isProcessing||s?l.timestamp:performance.now()),c),set:t=>{c=t,queueMicrotask(h)}};class p{constructor(t,e={}){this.version="11.11.17",this.canTrackVelocity=null,this.events={},this.updateAndNotify=(t,e=!0)=>{const n=d.now();this.updatedAt!==n&&this.setPrevFrameValue(),this.prev=this.current,this.setCurrent(t),this.current!==this.prev&&this.events.change&&this.events.change.notify(this.current),e&&this.events.renderRequest&&this.events.renderRequest.notify(this.current)},this.hasAnimated=!1,this.setCurrent(t),this.owner=e.owner}setCurrent(t){var e;this.current=t,this.updatedAt=d.now(),null===this.canTrackVelocity&&void 0!==t&&(this.canTrackVelocity=(e=this.current,!isNaN(parseFloat(e))))}setPrevFrameValue(t=this.current){this.prevFrameValue=t,this.prevUpdatedAt=this.updatedAt}onChange(t){return this.on("change",t)}on(t,n){this.events[t]||(this.events[t]=new e);const s=this.events[t].add(n);return"change"===t?()=>{s(),o.read((()=>{this.events.change.getSize()||this.stop()}))}:s}clearListeners(){for(const t in this.events)this.events[t].clear()}attach(t,e){this.passiveEffect=t,this.stopPassiveEffect=e}set(t,e=!0){e&&this.passiveEffect?this.passiveEffect(t,this.updateAndNotify):this.updateAndNotify(t,e)}setWithVelocity(t,e,n){this.set(e),this.prev=void 0,this.prevFrameValue=t,this.prevUpdatedAt=this.updatedAt-n}jump(t,e=!0){this.updateAndNotify(t),this.prev=t,this.prevUpdatedAt=this.prevFrameValue=void 0,e&&this.stop(),this.stopPassiveEffect&&this.stopPassiveEffect()}get(){return this.current}getPrevious(){return this.prev}getVelocity(){const t=d.now();if(!this.canTrackVelocity||void 0===this.prevFrameValue||t-this.updatedAt>30)return 0;const e=Math.min(this.updatedAt-this.prevUpdatedAt,30);return n(parseFloat(this.current)-parseFloat(this.prevFrameValue),e)}start(t){return this.stop(),new Promise((e=>{this.hasAnimated=!0,this.animation=t(e),this.events.animationStart&&this.events.animationStart.notify()})).then((()=>{this.events.animationComplete&&this.events.animationComplete.notify(),this.clearAnimation()}))}stop(){this.animation&&(this.animation.stop(),this.events.animationCancel&&this.events.animationCancel.notify()),this.clearAnimation()}isAnimating(){return!!this.animation}clearAnimation(){delete this.animation}destroy(){this.clearListeners(),this.stop(),this.stopPassiveEffect&&this.stopPassiveEffect()}}function f(t,e){return new p(t,e)}function m(t){let e;return()=>(void 0===e&&(e=t()),e)}const g=m((()=>void 0!==window.ScrollTimeline));class y{constructor(t){this.stop=()=>this.runAll("stop"),this.animations=t.filter(Boolean)}then(t,e){return Promise.all(this.animations).then(t).catch(e)}getAll(t){return this.animations[0][t]}setAll(t,e){for(let n=0;n<this.animations.length;n++)this.animations[n][t]=e}attachTimeline(t,e){const n=this.animations.map((n=>g()&&n.attachTimeline?n.attachTimeline(t):e(n)));return()=>{n.forEach(((t,e)=>{t&&t(),this.animations[e].stop()}))}}get time(){return this.getAll("time")}set time(t){this.setAll("time",t)}get speed(){return this.getAll("speed")}set speed(t){this.setAll("speed",t)}get startTime(){return this.getAll("startTime")}get duration(){let t=0;for(let e=0;e<this.animations.length;e++)t=Math.max(t,this.animations[e].duration);return t}runAll(t){this.animations.forEach((e=>e[t]()))}flatten(){this.runAll("flatten")}play(){this.runAll("play")}pause(){this.runAll("pause")}cancel(){this.runAll("cancel")}complete(){this.runAll("complete")}}const v=t=>1e3*t,w=t=>t/1e3;function b(t,e,s){const i=Math.max(e-5,0);return n(s-t(i),e-i)}let T=i,x=i;const S=(t,e,n)=>n>e?e:n<t?t:n,V=.001;function A({duration:t=800,bounce:e=.25,velocity:n=0,mass:s=1}){let i,r,o=1-e;o=S(.05,1,o),t=S(.01,10,w(t)),o<1?(i=e=>{const s=e*o,i=s*t,r=s-n,a=P(e,o),l=Math.exp(-i);return V-r/a*l},r=e=>{const s=e*o*t,r=s*n+n,a=Math.pow(o,2)*Math.pow(e,2)*t,l=Math.exp(-s),u=P(Math.pow(e,2),o);return(-i(e)+V>0?-1:1)*((r-a)*l)/u}):(i=e=>Math.exp(-e*t)*((e-n)*t+1)-.001,r=e=>Math.exp(-e*t)*(t*t*(n-e)));const a=function(t,e,n){let s=n;for(let n=1;n<M;n++)s-=t(s)/e(s);return s}(i,r,5/t);if(t=v(t),isNaN(a))return{stiffness:100,damping:10,duration:t};{const e=Math.pow(a,2)*s;return{stiffness:e,damping:2*o*Math.sqrt(s*e),duration:t}}}const M=12;function P(t,e){return t*Math.sqrt(1-e*e)}const k=["duration","bounce"],F=["stiffness","damping","mass"];function C(t,e){return e.some((e=>void 0!==t[e]))}function E({keyframes:t,restDelta:e,restSpeed:n,...s}){const i=t[0],r=t[t.length-1],o={done:!1,value:i},{stiffness:a,damping:l,mass:u,duration:c,velocity:h,isResolvedFromDuration:d}=function(t){let e={velocity:0,stiffness:100,damping:10,mass:1,isResolvedFromDuration:!1,...t};if(!C(t,F)&&C(t,k)){const n=A(t);e={...e,...n,mass:1},e.isResolvedFromDuration=!0}return e}({...s,velocity:-w(s.velocity||0)}),p=h||0,f=l/(2*Math.sqrt(a*u)),m=r-i,g=w(Math.sqrt(a/u)),y=Math.abs(m)<5;let T;if(n||(n=y?.01:2),e||(e=y?.005:.5),f<1){const t=P(g,f);T=e=>{const n=Math.exp(-f*g*e);return r-n*((p+f*g*m)/t*Math.sin(t*e)+m*Math.cos(t*e))}}else if(1===f)T=t=>r-Math.exp(-g*t)*(m+(p+g*m)*t);else{const t=g*Math.sqrt(f*f-1);T=e=>{const n=Math.exp(-f*g*e),s=Math.min(t*e,300);return r-n*((p+f*g*m)*Math.sinh(s)+t*m*Math.cosh(s))/t}}return{calculatedDuration:d&&c||null,next:t=>{const s=T(t);if(d)o.done=t>=c;else{let i=0;f<1&&(i=0===t?v(p):b(T,t,s));const a=Math.abs(i)<=n,l=Math.abs(r-s)<=e;o.done=a&&l}return o.value=o.done?r:s,o}}}const O=2e4;function R(t){let e=0;let n=t.next(e);for(;!n.done&&e<O;)e+=50,n=t.next(e);return e>=O?1/0:e}function B(t,e=100,n){const s=n({...t,keyframes:[0,e]}),i=Math.min(R(s),O);return{type:"keyframes",ease:t=>s.next(i*t).value/e,duration:w(i)}}const I=(t,e,n)=>t+(e-t)*n,L=(t,e,n)=>{const s=e-t;return 0===s?1:(n-t)/s};function W(t,e){const n=t[t.length-1];for(let s=1;s<=e;s++){const i=L(0,e,s);t.push(I(n,1,i))}}function D(t){const e=[0];return W(e,t.length-1),e}const N=t=>Boolean(t&&t.getVelocity);function K(t,e,n){var s;if("string"==typeof t){let i=document;e&&(x(Boolean(e.current)),i=e.current),n?(null!==(s=n[t])&&void 0!==s||(n[t]=i.querySelectorAll(t)),t=n[t]):t=i.querySelectorAll(t)}else t instanceof Element&&(t=[t]);return Array.from(t||[])}function $(t){return"object"==typeof t&&!Array.isArray(t)}function j(t,e,n,s){return"string"==typeof t&&$(e)?K(t,n,s):t instanceof NodeList?Array.from(t):Array.isArray(t)?t:[t]}function z(t){return"function"==typeof t}function H(t,e,n,s){var i;return"number"==typeof e?e:e.startsWith("-")||e.startsWith("+")?Math.max(0,t+parseFloat(e)):"<"===e?n:null!==(i=s.get(e))&&void 0!==i?i:t}const U=(t,e,n)=>{const s=e-t;return((n-t)%s+s)%s+t},Y=t=>Array.isArray(t)&&"number"!=typeof t[0];function q(t,e){return Y(t)?t[U(0,t.length,e)]:t}function X(e,n,s,i,r,o){!function(e,n,s){for(let i=0;i<e.length;i++){const r=e[i];r.at>n&&r.at<s&&(t(e,r),i--)}}(e,r,o);for(let t=0;t<n.length;t++)e.push({value:n[t],at:I(r,o,i[t]),easing:q(s,t)})}function G(t,e){return t.at===e.at?null===t.value?1:null===e.value?-1:0:t.at-e.at}function Z(t,e){return!e.has(t)&&e.set(t,{}),e.get(t)}function _(t,e){return e[t]||(e[t]=[]),e[t]}function J(t){return Array.isArray(t)?t:[t]}function Q(t,e){return t&&t[e]?{...t,...t[e]}:{...t}}const tt=t=>"number"==typeof t,et=t=>t.every(tt),nt=new WeakMap,st=["transformPerspective","x","y","z","translateX","translateY","translateZ","scale","scaleX","scaleY","rotate","rotateX","rotateY","rotateZ","skew","skewX","skewY"],it=new Set(st),rt={type:"spring",stiffness:500,damping:25,restSpeed:10},ot={type:"keyframes",duration:.8},at={type:"keyframes",ease:[.25,.1,.35,1],duration:.3},lt=(t,{keyframes:e})=>e.length>2?ot:it.has(t)?t.startsWith("scale")?{type:"spring",stiffness:550,damping:0===e[1]?2*Math.sqrt(550):30,restSpeed:10}:rt:at;function ut(t,e){return t?t[e]||t.default||t:void 0}const ct=t=>null!==t;function ht(t,{repeat:e,repeatType:n="loop"},s){const i=t.filter(ct),r=e&&"loop"!==n&&e%2==1?0:i.length-1;return r&&void 0!==s?s:i[r]}const dt=(t,e,n)=>(((1-3*n+3*e)*t+(3*n-6*e))*t+3*e)*t;function pt(t,e,n,s){if(t===e&&n===s)return i;const r=e=>function(t,e,n,s,i){let r,o,a=0;do{o=e+(n-e)/2,r=dt(o,s,i)-t,r>0?n=o:e=o}while(Math.abs(r)>1e-7&&++a<12);return o}(e,0,1,t,n);return t=>0===t||1===t?t:dt(r(t),e,s)}const ft=t=>e=>e<=.5?t(2*e)/2:(2-t(2*(1-e)))/2,mt=t=>e=>1-t(1-e),gt=pt(.33,1.53,.69,.99),yt=mt(gt),vt=ft(yt),wt=t=>(t*=2)<1?.5*yt(t):.5*(2-Math.pow(2,-10*(t-1))),bt=t=>1-Math.sin(Math.acos(t)),Tt=mt(bt),xt=ft(bt),St=t=>/^0[^.\s]+$/u.test(t);const Vt=t=>/^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(t),At=t=>e=>"string"==typeof e&&e.startsWith(t),Mt=At("--"),Pt=At("var(--"),kt=t=>!!Pt(t)&&Ft.test(t.split("/*")[0].trim()),Ft=/var\(--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)$/iu,Ct=/^var\(--(?:([\w-]+)|([\w-]+), ?([a-zA-Z\d ()%#.,-]+))\)/u;function Et(t,e,n=1){const[s,i]=function(t){const e=Ct.exec(t);if(!e)return[,];const[,n,s,i]=e;return[`--${null!=n?n:s}`,i]}(t);if(!s)return;const r=window.getComputedStyle(e).getPropertyValue(s);if(r){const t=r.trim();return Vt(t)?parseFloat(t):t}return kt(i)?Et(i,e,n+1):i}const Ot={test:t=>"number"==typeof t,parse:parseFloat,transform:t=>t},Rt={...Ot,transform:t=>S(0,1,t)},Bt={...Ot,default:1},It=t=>({test:e=>"string"==typeof e&&e.endsWith(t)&&1===e.split(" ").length,parse:parseFloat,transform:e=>`${e}${t}`}),Lt=It("deg"),Wt=It("%"),Dt=It("px"),Nt=It("vh"),Kt=It("vw"),$t={...Wt,parse:t=>Wt.parse(t)/100,transform:t=>Wt.transform(100*t)},jt=new Set(["width","height","top","left","right","bottom","x","y","translateX","translateY"]),zt=t=>t===Ot||t===Dt,Ht=(t,e)=>parseFloat(t.split(", ")[e]),Ut=(t,e)=>(n,{transform:s})=>{if("none"===s||!s)return 0;const i=s.match(/^matrix3d\((.+)\)$/u);if(i)return Ht(i[1],e);{const e=s.match(/^matrix\((.+)\)$/u);return e?Ht(e[1],t):0}},Yt=new Set(["x","y","z"]),qt=st.filter((t=>!Yt.has(t)));const Xt={width:({x:t},{paddingLeft:e="0",paddingRight:n="0"})=>t.max-t.min-parseFloat(e)-parseFloat(n),height:({y:t},{paddingTop:e="0",paddingBottom:n="0"})=>t.max-t.min-parseFloat(e)-parseFloat(n),top:(t,{top:e})=>parseFloat(e),left:(t,{left:e})=>parseFloat(e),bottom:({y:t},{top:e})=>parseFloat(e)+(t.max-t.min),right:({x:t},{left:e})=>parseFloat(e)+(t.max-t.min),x:Ut(4,13),y:Ut(5,14)};Xt.translateX=Xt.x,Xt.translateY=Xt.y;const Gt=t=>e=>e.test(t),Zt=[Ot,Dt,Wt,Lt,Kt,Nt,{test:t=>"auto"===t,parse:t=>t}],_t=t=>Zt.find(Gt(t)),Jt=new Set;let Qt=!1,te=!1;function ee(){if(te){const t=Array.from(Jt).filter((t=>t.needsMeasurement)),e=new Set(t.map((t=>t.element))),n=new Map;e.forEach((t=>{const e=function(t){const e=[];return qt.forEach((n=>{const s=t.getValue(n);void 0!==s&&(e.push([n,s.get()]),s.set(n.startsWith("scale")?1:0))})),e}(t);e.length&&(n.set(t,e),t.render())})),t.forEach((t=>t.measureInitialState())),e.forEach((t=>{t.render();const e=n.get(t);e&&e.forEach((([e,n])=>{var s;null===(s=t.getValue(e))||void 0===s||s.set(n)}))})),t.forEach((t=>t.measureEndState())),t.forEach((t=>{void 0!==t.suspendedScrollY&&window.scrollTo(0,t.suspendedScrollY)}))}te=!1,Qt=!1,Jt.forEach((t=>t.complete())),Jt.clear()}function ne(){Jt.forEach((t=>{t.readKeyframes(),t.needsMeasurement&&(te=!0)}))}class se{constructor(t,e,n,s,i,r=!1){this.isComplete=!1,this.isAsync=!1,this.needsMeasurement=!1,this.isScheduled=!1,this.unresolvedKeyframes=[...t],this.onComplete=e,this.name=n,this.motionValue=s,this.element=i,this.isAsync=r}scheduleResolve(){this.isScheduled=!0,this.isAsync?(Jt.add(this),Qt||(Qt=!0,o.read(ne),o.resolveKeyframes(ee))):(this.readKeyframes(),this.complete())}readKeyframes(){const{unresolvedKeyframes:t,name:e,element:n,motionValue:s}=this;for(let i=0;i<t.length;i++)if(null===t[i])if(0===i){const i=null==s?void 0:s.get(),r=t[t.length-1];if(void 0!==i)t[0]=i;else if(n&&e){const s=n.readValue(e,r);null!=s&&(t[0]=s)}void 0===t[0]&&(t[0]=r),s&&void 0===i&&s.set(t[0])}else t[i]=t[i-1]}setFinalKeyframe(){}measureInitialState(){}renderEndStyles(){}measureEndState(){}complete(){this.isComplete=!0,this.onComplete(this.unresolvedKeyframes,this.finalKeyframe),Jt.delete(this)}cancel(){this.isComplete||(this.isScheduled=!1,Jt.delete(this))}resume(){this.isComplete||this.scheduleResolve()}}const ie=t=>Math.round(1e5*t)/1e5,re=/-?(?:\d+(?:\.\d+)?|\.\d+)/gu;const oe=/^(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))$/iu,ae=(t,e)=>n=>Boolean("string"==typeof n&&oe.test(n)&&n.startsWith(t)||e&&!function(t){return null==t}(n)&&Object.prototype.hasOwnProperty.call(n,e)),le=(t,e,n)=>s=>{if("string"!=typeof s)return s;const[i,r,o,a]=s.match(re);return{[t]:parseFloat(i),[e]:parseFloat(r),[n]:parseFloat(o),alpha:void 0!==a?parseFloat(a):1}},ue={...Ot,transform:t=>Math.round((t=>S(0,255,t))(t))},ce={test:ae("rgb","red"),parse:le("red","green","blue"),transform:({red:t,green:e,blue:n,alpha:s=1})=>"rgba("+ue.transform(t)+", "+ue.transform(e)+", "+ue.transform(n)+", "+ie(Rt.transform(s))+")"};const he={test:ae("#"),parse:function(t){let e="",n="",s="",i="";return t.length>5?(e=t.substring(1,3),n=t.substring(3,5),s=t.substring(5,7),i=t.substring(7,9)):(e=t.substring(1,2),n=t.substring(2,3),s=t.substring(3,4),i=t.substring(4,5),e+=e,n+=n,s+=s,i+=i),{red:parseInt(e,16),green:parseInt(n,16),blue:parseInt(s,16),alpha:i?parseInt(i,16)/255:1}},transform:ce.transform},de={test:ae("hsl","hue"),parse:le("hue","saturation","lightness"),transform:({hue:t,saturation:e,lightness:n,alpha:s=1})=>"hsla("+Math.round(t)+", "+Wt.transform(ie(e))+", "+Wt.transform(ie(n))+", "+ie(Rt.transform(s))+")"},pe={test:t=>ce.test(t)||he.test(t)||de.test(t),parse:t=>ce.test(t)?ce.parse(t):de.test(t)?de.parse(t):he.parse(t),transform:t=>"string"==typeof t?t:t.hasOwnProperty("red")?ce.transform(t):de.transform(t)},fe=/(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))/giu;const me="number",ge="color",ye=/var\s*\(\s*--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)|#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\)|-?(?:\d+(?:\.\d+)?|\.\d+)/giu;function ve(t){const e=t.toString(),n=[],s={color:[],number:[],var:[]},i=[];let r=0;const o=e.replace(ye,(t=>(pe.test(t)?(s.color.push(r),i.push(ge),n.push(pe.parse(t))):t.startsWith("var(")?(s.var.push(r),i.push("var"),n.push(t)):(s.number.push(r),i.push(me),n.push(parseFloat(t))),++r,"${}"))).split("${}");return{values:n,split:o,indexes:s,types:i}}function we(t){return ve(t).values}function be(t){const{split:e,types:n}=ve(t),s=e.length;return t=>{let i="";for(let r=0;r<s;r++)if(i+=e[r],void 0!==t[r]){const e=n[r];i+=e===me?ie(t[r]):e===ge?pe.transform(t[r]):t[r]}return i}}const Te=t=>"number"==typeof t?0:t;const xe={test:function(t){var e,n;return isNaN(t)&&"string"==typeof t&&((null===(e=t.match(re))||void 0===e?void 0:e.length)||0)+((null===(n=t.match(fe))||void 0===n?void 0:n.length)||0)>0},parse:we,createTransformer:be,getAnimatableNone:function(t){const e=we(t);return be(t)(e.map(Te))}},Se=new Set(["brightness","contrast","saturate","opacity"]);function Ve(t){const[e,n]=t.slice(0,-1).split("(");if("drop-shadow"===e)return t;const[s]=n.match(re)||[];if(!s)return t;const i=n.replace(s,"");let r=Se.has(e)?1:0;return s!==n&&(r*=100),e+"("+r+i+")"}const Ae=/\b([a-z-]*)\(.*?\)/gu,Me={...xe,getAnimatableNone:t=>{const e=t.match(Ae);return e?e.map(Ve).join(" "):t}},Pe={borderWidth:Dt,borderTopWidth:Dt,borderRightWidth:Dt,borderBottomWidth:Dt,borderLeftWidth:Dt,borderRadius:Dt,radius:Dt,borderTopLeftRadius:Dt,borderTopRightRadius:Dt,borderBottomRightRadius:Dt,borderBottomLeftRadius:Dt,width:Dt,maxWidth:Dt,height:Dt,maxHeight:Dt,top:Dt,right:Dt,bottom:Dt,left:Dt,padding:Dt,paddingTop:Dt,paddingRight:Dt,paddingBottom:Dt,paddingLeft:Dt,margin:Dt,marginTop:Dt,marginRight:Dt,marginBottom:Dt,marginLeft:Dt,backgroundPositionX:Dt,backgroundPositionY:Dt},ke={rotate:Lt,rotateX:Lt,rotateY:Lt,rotateZ:Lt,scale:Bt,scaleX:Bt,scaleY:Bt,scaleZ:Bt,skew:Lt,skewX:Lt,skewY:Lt,distance:Dt,translateX:Dt,translateY:Dt,translateZ:Dt,x:Dt,y:Dt,z:Dt,perspective:Dt,transformPerspective:Dt,opacity:Rt,originX:$t,originY:$t,originZ:Dt},Fe={...Ot,transform:Math.round},Ce={...Pe,...ke,zIndex:Fe,size:Dt,fillOpacity:Rt,strokeOpacity:Rt,numOctaves:Fe},Ee={...Ce,color:pe,backgroundColor:pe,outlineColor:pe,fill:pe,stroke:pe,borderColor:pe,borderTopColor:pe,borderRightColor:pe,borderBottomColor:pe,borderLeftColor:pe,filter:Me,WebkitFilter:Me},Oe=t=>Ee[t];function Re(t,e){let n=Oe(t);return n!==Me&&(n=xe),n.getAnimatableNone?n.getAnimatableNone(e):void 0}const Be=new Set(["auto","none","0"]);class Ie extends se{constructor(t,e,n,s,i){super(t,e,n,s,i,!0)}readKeyframes(){const{unresolvedKeyframes:t,element:e,name:n}=this;if(!e||!e.current)return;super.readKeyframes();for(let n=0;n<t.length;n++){let s=t[n];if("string"==typeof s&&(s=s.trim(),kt(s))){const i=Et(s,e.current);void 0!==i&&(t[n]=i),n===t.length-1&&(this.finalKeyframe=s)}}if(this.resolveNoneKeyframes(),!jt.has(n)||2!==t.length)return;const[s,i]=t,r=_t(s),o=_t(i);if(r!==o)if(zt(r)&&zt(o))for(let e=0;e<t.length;e++){const n=t[e];"string"==typeof n&&(t[e]=parseFloat(n))}else this.needsMeasurement=!0}resolveNoneKeyframes(){const{unresolvedKeyframes:t,name:e}=this,n=[];for(let e=0;e<t.length;e++)("number"==typeof(s=t[e])?0===s:null===s||"none"===s||"0"===s||St(s))&&n.push(e);var s;n.length&&function(t,e,n){let s,i=0;for(;i<t.length&&!s;){const e=t[i];"string"==typeof e&&!Be.has(e)&&ve(e).values.length&&(s=t[i]),i++}if(s&&n)for(const i of e)t[i]=Re(n,s)}(t,n,e)}measureInitialState(){const{element:t,unresolvedKeyframes:e,name:n}=this;if(!t||!t.current)return;"height"===n&&(this.suspendedScrollY=window.pageYOffset),this.measuredOrigin=Xt[n](t.measureViewportBox(),window.getComputedStyle(t.current)),e[0]=this.measuredOrigin;const s=e[e.length-1];void 0!==s&&t.getValue(n,s).jump(s,!1)}measureEndState(){var t;const{element:e,name:n,unresolvedKeyframes:s}=this;if(!e||!e.current)return;const i=e.getValue(n);i&&i.jump(this.measuredOrigin,!1);const r=s.length-1,o=s[r];s[r]=Xt[n](e.measureViewportBox(),window.getComputedStyle(e.current)),null!==o&&void 0===this.finalKeyframe&&(this.finalKeyframe=o),(null===(t=this.removedTransforms)||void 0===t?void 0:t.length)&&this.removedTransforms.forEach((([t,n])=>{e.getValue(t).set(n)})),this.resolveNoneKeyframes()}}const Le=(t,e)=>"zIndex"!==e&&(!("number"!=typeof t&&!Array.isArray(t))||!("string"!=typeof t||!xe.test(t)&&"0"!==t||t.startsWith("url(")));function We(t,e,n,s){const i=t[0];if(null===i)return!1;if("display"===e||"visibility"===e)return!0;const r=t[t.length-1],o=Le(i,e),a=Le(r,e);return!(!o||!a)&&(function(t){const e=t[0];if(1===t.length)return!0;for(let n=0;n<t.length;n++)if(t[n]!==e)return!0}(t)||("spring"===n||z(n))&&s)}class De{constructor({autoplay:t=!0,delay:e=0,type:n="keyframes",repeat:s=0,repeatDelay:i=0,repeatType:r="loop",...o}){this.isStopped=!1,this.hasAttemptedResolve=!1,this.createdAt=d.now(),this.options={autoplay:t,delay:e,type:n,repeat:s,repeatDelay:i,repeatType:r,...o},this.updateFinishedPromise()}calcStartTime(){return this.resolvedAt&&this.resolvedAt-this.createdAt>40?this.resolvedAt:this.createdAt}get resolved(){return this._resolved||this.hasAttemptedResolve||(ne(),ee()),this._resolved}onKeyframesResolved(t,e){this.resolvedAt=d.now(),this.hasAttemptedResolve=!0;const{name:n,type:s,velocity:i,delay:r,onComplete:o,onUpdate:a,isGenerator:l}=this.options;if(!l&&!We(t,n,s,i)){if(!r)return null==a||a(ht(t,this.options,e)),null==o||o(),void this.resolveFinishedPromise();this.options.duration=0}const u=this.initPlayback(t,e);!1!==u&&(this._resolved={keyframes:t,finalKeyframe:e,...u},this.onPostResolved())}onPostResolved(){}then(t,e){return this.currentFinishedPromise.then(t,e)}flatten(){this.options.type="keyframes",this.options.ease="linear"}updateFinishedPromise(){this.currentFinishedPromise=new Promise((t=>{this.resolveFinishedPromise=t}))}}function Ne({keyframes:t,velocity:e=0,power:n=.8,timeConstant:s=325,bounceDamping:i=10,bounceStiffness:r=500,modifyTarget:o,min:a,max:l,restDelta:u=.5,restSpeed:c}){const h=t[0],d={done:!1,value:h},p=t=>void 0===a?l:void 0===l||Math.abs(a-t)<Math.abs(l-t)?a:l;let f=n*e;const m=h+f,g=void 0===o?m:o(m);g!==m&&(f=g-h);const y=t=>-f*Math.exp(-t/s),v=t=>g+y(t),w=t=>{const e=y(t),n=v(t);d.done=Math.abs(e)<=u,d.value=d.done?g:n};let T,x;const S=t=>{var e;(e=d.value,void 0!==a&&e<a||void 0!==l&&e>l)&&(T=t,x=E({keyframes:[d.value,p(d.value)],velocity:b(v,t,d.value),damping:i,stiffness:r,restDelta:u,restSpeed:c}))};return S(0),{calculatedDuration:null,next:t=>{let e=!1;return x||void 0!==T||(e=!0,w(t),S(t)),void 0!==T&&t>=T?x.next(t-T):(!e&&w(t),d)}}}const Ke=pt(.42,0,1,1),$e=pt(0,0,.58,1),je=pt(.42,0,.58,1),ze=t=>Array.isArray(t)&&"number"==typeof t[0],He={linear:i,easeIn:Ke,easeInOut:je,easeOut:$e,circIn:bt,circInOut:xt,circOut:Tt,backIn:yt,backInOut:vt,backOut:gt,anticipate:wt},Ue=t=>{if(ze(t)){x(4===t.length);const[e,n,s,i]=t;return pt(e,n,s,i)}return"string"==typeof t?He[t]:t},Ye=(t,e)=>n=>e(t(n)),qe=(...t)=>t.reduce(Ye);function Xe(t,e,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?t+6*(e-t)*n:n<.5?e:n<2/3?t+(e-t)*(2/3-n)*6:t}function Ge(t,e){return n=>n>0?e:t}const Ze=(t,e,n)=>{const s=t*t,i=n*(e*e-s)+s;return i<0?0:Math.sqrt(i)},_e=[he,ce,de];function Je(t){const e=(n=t,_e.find((t=>t.test(n))));var n;if(!Boolean(e))return!1;let s=e.parse(t);return e===de&&(s=function({hue:t,saturation:e,lightness:n,alpha:s}){t/=360,n/=100;let i=0,r=0,o=0;if(e/=100){const s=n<.5?n*(1+e):n+e-n*e,a=2*n-s;i=Xe(a,s,t+1/3),r=Xe(a,s,t),o=Xe(a,s,t-1/3)}else i=r=o=n;return{red:Math.round(255*i),green:Math.round(255*r),blue:Math.round(255*o),alpha:s}}(s)),s}const Qe=(t,e)=>{const n=Je(t),s=Je(e);if(!n||!s)return Ge(t,e);const i={...n};return t=>(i.red=Ze(n.red,s.red,t),i.green=Ze(n.green,s.green,t),i.blue=Ze(n.blue,s.blue,t),i.alpha=I(n.alpha,s.alpha,t),ce.transform(i))},tn=new Set(["none","hidden"]);function en(t,e){return n=>I(t,e,n)}function nn(t){return"number"==typeof t?en:"string"==typeof t?kt(t)?Ge:pe.test(t)?Qe:on:Array.isArray(t)?sn:"object"==typeof t?pe.test(t)?Qe:rn:Ge}function sn(t,e){const n=[...t],s=n.length,i=t.map(((t,n)=>nn(t)(t,e[n])));return t=>{for(let e=0;e<s;e++)n[e]=i[e](t);return n}}function rn(t,e){const n={...t,...e},s={};for(const i in n)void 0!==t[i]&&void 0!==e[i]&&(s[i]=nn(t[i])(t[i],e[i]));return t=>{for(const e in s)n[e]=s[e](t);return n}}const on=(t,e)=>{const n=xe.createTransformer(e),s=ve(t),i=ve(e);return s.indexes.var.length===i.indexes.var.length&&s.indexes.color.length===i.indexes.color.length&&s.indexes.number.length>=i.indexes.number.length?tn.has(t)&&!i.values.length||tn.has(e)&&!s.values.length?function(t,e){return tn.has(t)?n=>n<=0?t:e:n=>n>=1?e:t}(t,e):qe(sn(function(t,e){var n;const s=[],i={color:0,var:0,number:0};for(let r=0;r<e.values.length;r++){const o=e.types[r],a=t.indexes[o][i[o]],l=null!==(n=t.values[a])&&void 0!==n?n:0;s[r]=l,i[o]++}return s}(s,i),i.values),n):Ge(t,e)};function an(t,e,n){if("number"==typeof t&&"number"==typeof e&&"number"==typeof n)return I(t,e,n);return nn(t)(t,e)}function ln(t,e,{clamp:n=!0,ease:s,mixer:r}={}){const o=t.length;if(x(o===e.length),1===o)return()=>e[0];if(2===o&&t[0]===t[1])return()=>e[1];t[0]>t[o-1]&&(t=[...t].reverse(),e=[...e].reverse());const a=function(t,e,n){const s=[],r=n||an,o=t.length-1;for(let n=0;n<o;n++){let o=r(t[n],t[n+1]);if(e){const t=Array.isArray(e)?e[n]||i:e;o=qe(t,o)}s.push(o)}return s}(e,s,r),l=a.length,u=e=>{let n=0;if(l>1)for(;n<t.length-2&&!(e<t[n+1]);n++);const s=L(t[n],t[n+1],e);return a[n](s)};return n?e=>u(S(t[0],t[o-1],e)):u}function un({duration:t=300,keyframes:e,times:n,ease:s="easeInOut"}){const i=Y(s)?s.map(Ue):Ue(s),r={done:!1,value:e[0]},o=function(t,e){return t.map((t=>t*e))}(n&&n.length===e.length?n:D(e),t),a=ln(o,e,{ease:Array.isArray(i)?i:(l=e,u=i,l.map((()=>u||je)).splice(0,l.length-1))});var l,u;return{calculatedDuration:t,next:e=>(r.value=a(e),r.done=e>=t,r)}}const cn=t=>{const e=({timestamp:e})=>t(e);return{start:()=>o.update(e,!0),stop:()=>a(e),now:()=>l.isProcessing?l.timestamp:d.now()}},hn={decay:Ne,inertia:Ne,tween:un,keyframes:un,spring:E},dn=t=>t/100;class pn extends De{constructor(t){super(t),this.holdTime=null,this.cancelTime=null,this.currentTime=0,this.playbackSpeed=1,this.pendingPlayState="running",this.startTime=null,this.state="idle",this.stop=()=>{if(this.resolver.cancel(),this.isStopped=!0,"idle"===this.state)return;this.teardown();const{onStop:t}=this.options;t&&t()};const{name:e,motionValue:n,element:s,keyframes:i}=this.options,r=(null==s?void 0:s.KeyframeResolver)||se;this.resolver=new r(i,((t,e)=>this.onKeyframesResolved(t,e)),e,n,s),this.resolver.scheduleResolve()}flatten(){super.flatten(),this._resolved&&Object.assign(this._resolved,this.initPlayback(this._resolved.keyframes))}initPlayback(t){const{type:e="keyframes",repeat:n=0,repeatDelay:s=0,repeatType:i,velocity:r=0}=this.options,o=z(e)?e:hn[e]||un;let a,l;o!==un&&"number"!=typeof t[0]&&(a=qe(dn,an(t[0],t[1])),t=[0,100]);const u=o({...this.options,keyframes:t});"mirror"===i&&(l=o({...this.options,keyframes:[...t].reverse(),velocity:-r})),null===u.calculatedDuration&&(u.calculatedDuration=R(u));const{calculatedDuration:c}=u,h=c+s;return{generator:u,mirroredGenerator:l,mapPercentToKeyframes:a,calculatedDuration:c,resolvedDuration:h,totalDuration:h*(n+1)-s}}onPostResolved(){const{autoplay:t=!0}=this.options;this.play(),"paused"!==this.pendingPlayState&&t?this.state=this.pendingPlayState:this.pause()}tick(t,e=!1){const{resolved:n}=this;if(!n){const{keyframes:t}=this.options;return{done:!0,value:t[t.length-1]}}const{finalKeyframe:s,generator:i,mirroredGenerator:r,mapPercentToKeyframes:o,keyframes:a,calculatedDuration:l,totalDuration:u,resolvedDuration:c}=n;if(null===this.startTime)return i.next(0);const{delay:h,repeat:d,repeatType:p,repeatDelay:f,onUpdate:m}=this.options;this.speed>0?this.startTime=Math.min(this.startTime,t):this.speed<0&&(this.startTime=Math.min(t-u/this.speed,this.startTime)),e?this.currentTime=t:null!==this.holdTime?this.currentTime=this.holdTime:this.currentTime=Math.round(t-this.startTime)*this.speed;const g=this.currentTime-h*(this.speed>=0?1:-1),y=this.speed>=0?g<0:g>u;this.currentTime=Math.max(g,0),"finished"===this.state&&null===this.holdTime&&(this.currentTime=u);let v=this.currentTime,w=i;if(d){const t=Math.min(this.currentTime,u)/c;let e=Math.floor(t),n=t%1;!n&&t>=1&&(n=1),1===n&&e--,e=Math.min(e,d+1);Boolean(e%2)&&("reverse"===p?(n=1-n,f&&(n-=f/c)):"mirror"===p&&(w=r)),v=S(0,1,n)*c}const b=y?{done:!1,value:a[0]}:w.next(v);o&&(b.value=o(b.value));let{done:T}=b;y||null===l||(T=this.speed>=0?this.currentTime>=u:this.currentTime<=0);const x=null===this.holdTime&&("finished"===this.state||"running"===this.state&&T);return x&&void 0!==s&&(b.value=ht(a,this.options,s)),m&&m(b.value),x&&this.finish(),b}get duration(){const{resolved:t}=this;return t?w(t.calculatedDuration):0}get time(){return w(this.currentTime)}set time(t){t=v(t),this.currentTime=t,null!==this.holdTime||0===this.speed?this.holdTime=t:this.driver&&(this.startTime=this.driver.now()-t/this.speed)}get speed(){return this.playbackSpeed}set speed(t){const e=this.playbackSpeed!==t;this.playbackSpeed=t,e&&(this.time=w(this.currentTime))}play(){if(this.resolver.isScheduled||this.resolver.resume(),!this._resolved)return void(this.pendingPlayState="running");if(this.isStopped)return;const{driver:t=cn,onPlay:e,startTime:n}=this.options;this.driver||(this.driver=t((t=>this.tick(t)))),e&&e();const s=this.driver.now();null!==this.holdTime?this.startTime=s-this.holdTime:this.startTime?"finished"===this.state&&(this.startTime=s):this.startTime=null!=n?n:this.calcStartTime(),"finished"===this.state&&this.updateFinishedPromise(),this.cancelTime=this.startTime,this.holdTime=null,this.state="running",this.driver.start()}pause(){var t;this._resolved?(this.state="paused",this.holdTime=null!==(t=this.currentTime)&&void 0!==t?t:0):this.pendingPlayState="paused"}complete(){"running"!==this.state&&this.play(),this.pendingPlayState=this.state="finished",this.holdTime=null}finish(){this.teardown(),this.state="finished";const{onComplete:t}=this.options;t&&t()}cancel(){null!==this.cancelTime&&this.tick(this.cancelTime),this.teardown(),this.updateFinishedPromise()}teardown(){this.state="idle",this.stopDriver(),this.resolveFinishedPromise(),this.updateFinishedPromise(),this.startTime=this.cancelTime=null,this.resolver.cancel()}stopDriver(){this.driver&&(this.driver.stop(),this.driver=void 0)}sample(t){return this.startTime=0,this.tick(t,!0)}}const fn=new Set(["opacity","clipPath","filter","transform"]),mn={linearEasing:void 0};function gn(t,e){const n=m(t);return()=>{var t;return null!==(t=mn[e])&&void 0!==t?t:n()}}const yn=gn((()=>{try{document.createElement("div").animate({opacity:0},{easing:"linear(0, 1)"})}catch(t){return!1}return!0}),"linearEasing");function vn(t){return Boolean("function"==typeof t&&yn()||!t||"string"==typeof t&&(t in bn||yn())||ze(t)||Array.isArray(t)&&t.every(vn))}const wn=([t,e,n,s])=>`cubic-bezier(${t}, ${e}, ${n}, ${s})`,bn={linear:"linear",ease:"ease",easeIn:"ease-in",easeOut:"ease-out",easeInOut:"ease-in-out",circIn:wn([0,.65,.55,1]),circOut:wn([.55,0,1,.45]),backIn:wn([.31,.01,.66,-.59]),backOut:wn([.33,1.53,.69,.99])};function Tn(t,e){return t?"function"==typeof t&&yn()?((t,e)=>{let n="";const s=Math.max(Math.round(e/10),2);for(let e=0;e<s;e++)n+=t(L(0,s-1,e))+", ";return`linear(${n.substring(0,n.length-2)})`})(t,e):ze(t)?wn(t):Array.isArray(t)?t.map((t=>Tn(t,e)||bn.easeOut)):bn[t]:void 0}function xn(t,e,n,{delay:s=0,duration:i=300,repeat:r=0,repeatType:o="loop",ease:a="easeInOut",times:l}={}){const u={[e]:n};l&&(u.offset=l);const c=Tn(a,i);return Array.isArray(c)&&(u.easing=c),t.animate(u,{delay:s,duration:i,easing:Array.isArray(c)?"linear":c,fill:"both",iterations:r+1,direction:"reverse"===o?"alternate":"normal"})}function Sn(t,e){t.timeline=e,t.onfinish=null}const Vn=m((()=>Object.hasOwnProperty.call(Element.prototype,"animate")));const An={anticipate:wt,backInOut:vt,circInOut:xt};class Mn extends De{constructor(t){super(t);const{name:e,motionValue:n,element:s,keyframes:i}=this.options;this.resolver=new Ie(i,((t,e)=>this.onKeyframesResolved(t,e)),e,n,s),this.resolver.scheduleResolve()}initPlayback(t,e){var n;let{duration:s=300,times:i,ease:r,type:o,motionValue:a,name:l,startTime:u}=this.options;if(!(null===(n=a.owner)||void 0===n?void 0:n.current))return!1;var c;if("string"==typeof r&&yn()&&r in An&&(r=An[r]),z((c=this.options).type)||"spring"===c.type||!vn(c.ease)){const{onComplete:e,onUpdate:n,motionValue:a,element:l,...u}=this.options,c=function(t,e){const n=new pn({...e,keyframes:t,repeat:0,delay:0,isGenerator:!0});let s={done:!1,value:t[0]};const i=[];let r=0;for(;!s.done&&r<2e4;)s=n.sample(r),i.push(s.value),r+=10;return{times:void 0,keyframes:i,duration:r-10,ease:"linear"}}(t,u);1===(t=c.keyframes).length&&(t[1]=t[0]),s=c.duration,i=c.times,r=c.ease,o="keyframes"}const h=xn(a.owner.current,l,t,{...this.options,duration:s,times:i,ease:r});return h.startTime=null!=u?u:this.calcStartTime(),this.pendingTimeline?(Sn(h,this.pendingTimeline),this.pendingTimeline=void 0):h.onfinish=()=>{const{onComplete:n}=this.options;a.set(ht(t,this.options,e)),n&&n(),this.cancel(),this.resolveFinishedPromise()},{animation:h,duration:s,times:i,type:o,ease:r,keyframes:t}}get duration(){const{resolved:t}=this;if(!t)return 0;const{duration:e}=t;return w(e)}get time(){const{resolved:t}=this;if(!t)return 0;const{animation:e}=t;return w(e.currentTime||0)}set time(t){const{resolved:e}=this;if(!e)return;const{animation:n}=e;n.currentTime=v(t)}get speed(){const{resolved:t}=this;if(!t)return 1;const{animation:e}=t;return e.playbackRate}set speed(t){const{resolved:e}=this;if(!e)return;const{animation:n}=e;n.playbackRate=t}get state(){const{resolved:t}=this;if(!t)return"idle";const{animation:e}=t;return e.playState}get startTime(){const{resolved:t}=this;if(!t)return null;const{animation:e}=t;return e.startTime}attachTimeline(t){if(this._resolved){const{resolved:e}=this;if(!e)return i;const{animation:n}=e;Sn(n,t)}else this.pendingTimeline=t;return i}play(){if(this.isStopped)return;const{resolved:t}=this;if(!t)return;const{animation:e}=t;"finished"===e.playState&&this.updateFinishedPromise(),e.play()}pause(){const{resolved:t}=this;if(!t)return;const{animation:e}=t;e.pause()}stop(){if(this.resolver.cancel(),this.isStopped=!0,"idle"===this.state)return;this.resolveFinishedPromise(),this.updateFinishedPromise();const{resolved:t}=this;if(!t)return;const{animation:e,keyframes:n,duration:s,type:i,ease:r,times:o}=t;if("idle"===e.playState||"finished"===e.playState)return;if(this.time){const{motionValue:t,onUpdate:e,onComplete:a,element:l,...u}=this.options,c=new pn({...u,keyframes:n,duration:s,type:i,ease:r,times:o,isGenerator:!0}),h=v(this.time);t.setWithVelocity(c.sample(h-10).value,c.sample(h).value,10)}const{onStop:a}=this.options;a&&a(),this.cancel()}complete(){const{resolved:t}=this;t&&t.animation.finish()}cancel(){const{resolved:t}=this;t&&t.animation.cancel()}static supports(t){const{motionValue:e,name:n,repeatDelay:s,repeatType:i,damping:r,type:o}=t;return Vn()&&n&&fn.has(n)&&e&&e.owner&&e.owner.current instanceof HTMLElement&&!e.owner.getProps().onUpdate&&!s&&"mirror"!==i&&0!==r&&"inertia"!==o}}const Pn=(t,e,n,s={},i,r)=>a=>{const l=ut(s,t)||{},u=l.delay||s.delay||0;let{elapsed:c=0}=s;c-=v(u);let h={keyframes:Array.isArray(n)?n:[null,n],ease:"easeOut",velocity:e.getVelocity(),...l,delay:-c,onUpdate:t=>{e.set(t),l.onUpdate&&l.onUpdate(t)},onComplete:()=>{a(),l.onComplete&&l.onComplete()},name:t,motionValue:e,element:r?void 0:i};(function({when:t,delay:e,delayChildren:n,staggerChildren:s,staggerDirection:i,repeat:r,repeatType:o,repeatDelay:a,from:l,elapsed:u,...c}){return!!Object.keys(c).length})(l)||(h={...h,...lt(t,h)}),h.duration&&(h.duration=v(h.duration)),h.repeatDelay&&(h.repeatDelay=v(h.repeatDelay)),void 0!==h.from&&(h.keyframes[0]=h.from);let d=!1;if((!1===h.type||0===h.duration&&!h.repeatDelay)&&(h.duration=0,0===h.delay&&(d=!0)),d&&!r&&void 0!==e.get()){const t=ht(h.keyframes,l);if(void 0!==t)return o.update((()=>{h.onUpdate(t),h.onComplete()})),new y([])}return!r&&Mn.supports(h)?new Mn(h):new pn(h)},kn=t=>(t=>Array.isArray(t))(t)?t[t.length-1]||0:t;function Fn(t){const e=[{},{}];return null==t||t.values.forEach(((t,n)=>{e[0][n]=t.get(),e[1][n]=t.getVelocity()})),e}function Cn(t,e,n,s){if("function"==typeof e){const[i,r]=Fn(s);e=e(void 0!==n?n:t.custom,i,r)}if("string"==typeof e&&(e=t.variants&&t.variants[e]),"function"==typeof e){const[i,r]=Fn(s);e=e(void 0!==n?n:t.custom,i,r)}return e}function En(t,e,n){t.hasValue(e)?t.getValue(e).set(n):t.addValue(e,f(n))}function On(t,e){const n=function(t,e,n){const s=t.getProps();return Cn(s,e,void 0!==n?n:s.custom,t)}(t,e);let{transitionEnd:s={},transition:i={},...r}=n||{};r={...r,...s};for(const e in r){En(t,e,kn(r[e]))}}const Rn=t=>t.replace(/([a-z])([A-Z])/gu,"$1-$2").toLowerCase(),Bn="data-"+Rn("framerAppearId");function In(t){return t.props[Bn]}function Ln(t,e){const n=t.getValue("willChange");if(s=n,Boolean(N(s)&&s.add))return n.add(e);var s}function Wn({protectedKeys:t,needsAnimating:e},n){const s=t.hasOwnProperty(n)&&!0!==e[n];return e[n]=!1,s}function Dn(t,e,{delay:n=0,transitionOverride:s,type:i}={}){var r;let{transition:a=t.getDefaultTransition(),transitionEnd:l,...u}=e;s&&(a=s);const c=[],h=i&&t.animationState&&t.animationState.getState()[i];for(const e in u){const s=t.getValue(e,null!==(r=t.latestValues[e])&&void 0!==r?r:null),i=u[e];if(void 0===i||h&&Wn(h,e))continue;const l={delay:n,...ut(a||{},e)};let d=!1;if(window.MotionHandoffAnimation){const n=In(t);if(n){const t=window.MotionHandoffAnimation(n,e,o);null!==t&&(l.startTime=t,d=!0)}}Ln(t,e),s.start(Pn(e,s,i,t.shouldReduceMotion&&it.has(e)?{type:!1}:l,t,d));const p=s.animation;p&&c.push(p)}return l&&Promise.all(c).then((()=>{o.update((()=>{l&&On(t,l)}))})),c}const Nn={};function Kn(t,{layout:e,layoutId:n}){return it.has(t)||t.startsWith("origin")||(e||void 0!==n)&&(!!Nn[t]||"opacity"===t)}function $n(t,e,n){var s;const{style:i}=t,r={};for(const o in i)(N(i[o])||e.style&&N(e.style[o])||Kn(o,t)||void 0!==(null===(s=null==n?void 0:n.getValue(o))||void 0===s?void 0:s.liveStyle))&&(r[o]=i[o]);return r}const jn="undefined"!=typeof window,zn={current:null},Hn={current:!1};const Un=["initial","animate","whileInView","whileFocus","whileHover","whileTap","whileDrag","exit"];function Yn(t){return null!==(e=t.animate)&&"object"==typeof e&&"function"==typeof e.start||Un.some((e=>function(t){return"string"==typeof t||Array.isArray(t)}(t[e])));var e}const qn={animation:["animate","variants","whileHover","whileTap","exit","whileInView","whileFocus","whileDrag"],exit:["exit"],drag:["drag","dragControls"],focus:["whileFocus"],hover:["whileHover","onHoverStart","onHoverEnd"],tap:["whileTap","onTap","onTapStart","onTapCancel"],pan:["onPan","onPanStart","onPanSessionStart","onPanEnd"],inView:["whileInView","onViewportEnter","onViewportLeave"],layout:["layout","layoutId"]},Xn={};for(const t in qn)Xn[t]={isEnabled:e=>qn[t].some((t=>!!e[t]))};const Gn=[...Zt,pe,xe],Zn=()=>({x:{min:0,max:0},y:{min:0,max:0}}),_n=["AnimationStart","AnimationComplete","Update","BeforeLayoutMeasure","LayoutMeasure","LayoutAnimationStart","LayoutAnimationComplete"];class Jn{scrapeMotionValuesFromProps(t,e,n){return{}}constructor({parent:t,props:e,presenceContext:n,reducedMotionConfig:s,blockInitialAnimation:i,visualState:r},a={}){this.current=null,this.children=new Set,this.isVariantNode=!1,this.isControllingVariants=!1,this.shouldReduceMotion=null,this.values=new Map,this.KeyframeResolver=se,this.features={},this.valueSubscriptions=new Map,this.prevMotionValues={},this.events={},this.propEventSubscriptions={},this.notifyUpdate=()=>this.notify("Update",this.latestValues),this.render=()=>{this.current&&(this.triggerBuild(),this.renderInstance(this.current,this.renderState,this.props.style,this.projection))},this.renderScheduledAt=0,this.scheduleRender=()=>{const t=d.now();this.renderScheduledAt<t&&(this.renderScheduledAt=t,o.render(this.render,!1,!0))};const{latestValues:l,renderState:u}=r;this.latestValues=l,this.baseTarget={...l},this.initialValues=e.initial?{...l}:{},this.renderState=u,this.parent=t,this.props=e,this.presenceContext=n,this.depth=t?t.depth+1:0,this.reducedMotionConfig=s,this.options=a,this.blockInitialAnimation=Boolean(i),this.isControllingVariants=Yn(e),this.isVariantNode=function(t){return Boolean(Yn(t)||t.variants)}(e),this.isVariantNode&&(this.variantChildren=new Set),this.manuallyAnimateOnMount=Boolean(t&&t.current);const{willChange:c,...h}=this.scrapeMotionValuesFromProps(e,{},this);for(const t in h){const e=h[t];void 0!==l[t]&&N(e)&&e.set(l[t],!1)}}mount(t){this.current=t,nt.set(t,this),this.projection&&!this.projection.instance&&this.projection.mount(t),this.parent&&this.isVariantNode&&!this.isControllingVariants&&(this.removeFromVariantTree=this.parent.addVariantChild(this)),this.values.forEach(((t,e)=>this.bindToMotionValue(e,t))),Hn.current||function(){if(Hn.current=!0,jn)if(window.matchMedia){const t=window.matchMedia("(prefers-reduced-motion)"),e=()=>zn.current=t.matches;t.addListener(e),e()}else zn.current=!1}(),this.shouldReduceMotion="never"!==this.reducedMotionConfig&&("always"===this.reducedMotionConfig||zn.current),this.parent&&this.parent.children.add(this),this.update(this.props,this.presenceContext)}unmount(){nt.delete(this.current),this.projection&&this.projection.unmount(),a(this.notifyUpdate),a(this.render),this.valueSubscriptions.forEach((t=>t())),this.valueSubscriptions.clear(),this.removeFromVariantTree&&this.removeFromVariantTree(),this.parent&&this.parent.children.delete(this);for(const t in this.events)this.events[t].clear();for(const t in this.features){const e=this.features[t];e&&(e.unmount(),e.isMounted=!1)}this.current=null}bindToMotionValue(t,e){this.valueSubscriptions.has(t)&&this.valueSubscriptions.get(t)();const n=it.has(t),s=e.on("change",(e=>{this.latestValues[t]=e,this.props.onUpdate&&o.preRender(this.notifyUpdate),n&&this.projection&&(this.projection.isTransformDirty=!0)})),i=e.on("renderRequest",this.scheduleRender);let r;window.MotionCheckAppearSync&&(r=window.MotionCheckAppearSync(this,t,e)),this.valueSubscriptions.set(t,(()=>{s(),i(),r&&r(),e.owner&&e.stop()}))}sortNodePosition(t){return this.current&&this.sortInstanceNodePosition&&this.type===t.type?this.sortInstanceNodePosition(this.current,t.current):0}updateFeatures(){let t="animation";for(t in Xn){const e=Xn[t];if(!e)continue;const{isEnabled:n,Feature:s}=e;if(!this.features[t]&&s&&n(this.props)&&(this.features[t]=new s(this)),this.features[t]){const e=this.features[t];e.isMounted?e.update():(e.mount(),e.isMounted=!0)}}}triggerBuild(){this.build(this.renderState,this.latestValues,this.props)}measureViewportBox(){return this.current?this.measureInstanceViewportBox(this.current,this.props):{x:{min:0,max:0},y:{min:0,max:0}}}getStaticValue(t){return this.latestValues[t]}setStaticValue(t,e){this.latestValues[t]=e}update(t,e){(t.transformTemplate||this.props.transformTemplate)&&this.scheduleRender(),this.prevProps=this.props,this.props=t,this.prevPresenceContext=this.presenceContext,this.presenceContext=e;for(let e=0;e<_n.length;e++){const n=_n[e];this.propEventSubscriptions[n]&&(this.propEventSubscriptions[n](),delete this.propEventSubscriptions[n]);const s=t["on"+n];s&&(this.propEventSubscriptions[n]=this.on(n,s))}this.prevMotionValues=function(t,e,n){for(const s in e){const i=e[s],r=n[s];if(N(i))t.addValue(s,i);else if(N(r))t.addValue(s,f(i,{owner:t}));else if(r!==i)if(t.hasValue(s)){const e=t.getValue(s);!0===e.liveStyle?e.jump(i):e.hasAnimated||e.set(i)}else{const e=t.getStaticValue(s);t.addValue(s,f(void 0!==e?e:i,{owner:t}))}}for(const s in n)void 0===e[s]&&t.removeValue(s);return e}(this,this.scrapeMotionValuesFromProps(t,this.prevProps,this),this.prevMotionValues),this.handleChildMotionValue&&this.handleChildMotionValue()}getProps(){return this.props}getVariant(t){return this.props.variants?this.props.variants[t]:void 0}getDefaultTransition(){return this.props.transition}getTransformPagePoint(){return this.props.transformPagePoint}getClosestVariantNode(){return this.isVariantNode?this:this.parent?this.parent.getClosestVariantNode():void 0}addVariantChild(t){const e=this.getClosestVariantNode();if(e)return e.variantChildren&&e.variantChildren.add(t),()=>e.variantChildren.delete(t)}addValue(t,e){const n=this.values.get(t);e!==n&&(n&&this.removeValue(t),this.bindToMotionValue(t,e),this.values.set(t,e),this.latestValues[t]=e.get())}removeValue(t){this.values.delete(t);const e=this.valueSubscriptions.get(t);e&&(e(),this.valueSubscriptions.delete(t)),delete this.latestValues[t],this.removeValueFromRenderState(t,this.renderState)}hasValue(t){return this.values.has(t)}getValue(t,e){if(this.props.values&&this.props.values[t])return this.props.values[t];let n=this.values.get(t);return void 0===n&&void 0!==e&&(n=f(null===e?void 0:e,{owner:this}),this.addValue(t,n)),n}readValue(t,e){var n;let s=void 0===this.latestValues[t]&&this.current?null!==(n=this.getBaseTargetFromProps(this.props,t))&&void 0!==n?n:this.readValueFromInstance(this.current,t,this.options):this.latestValues[t];var i;return null!=s&&("string"==typeof s&&(Vt(s)||St(s))?s=parseFloat(s):(i=s,!Gn.find(Gt(i))&&xe.test(e)&&(s=Re(t,e))),this.setBaseTarget(t,N(s)?s.get():s)),N(s)?s.get():s}setBaseTarget(t,e){this.baseTarget[t]=e}getBaseTarget(t){var e;const{initial:n}=this.props;let s;if("string"==typeof n||"object"==typeof n){const i=Cn(this.props,n,null===(e=this.presenceContext)||void 0===e?void 0:e.custom);i&&(s=i[t])}if(n&&void 0!==s)return s;const i=this.getBaseTargetFromProps(this.props,t);return void 0===i||N(i)?void 0!==this.initialValues[t]&&void 0===s?void 0:this.baseTarget[t]:i}on(t,n){return this.events[t]||(this.events[t]=new e),this.events[t].add(n)}notify(t,...e){this.events[t]&&this.events[t].notify(...e)}}class Qn extends Jn{constructor(){super(...arguments),this.KeyframeResolver=Ie}sortInstanceNodePosition(t,e){return 2&t.compareDocumentPosition(e)?1:-1}getBaseTargetFromProps(t,e){return t.style?t.style[e]:void 0}removeValueFromRenderState(t,{vars:e,style:n}){delete e[t],delete n[t]}}const ts=(t,e)=>e&&"number"==typeof t?e.transform(t):t,es={x:"translateX",y:"translateY",z:"translateZ",transformPerspective:"perspective"},ns=st.length;function ss(t,e,n){const{style:s,vars:i,transformOrigin:r}=t;let o=!1,a=!1;for(const t in e){const n=e[t];if(it.has(t))o=!0;else if(Mt(t))i[t]=n;else{const e=ts(n,Ce[t]);t.startsWith("origin")?(a=!0,r[t]=e):s[t]=e}}if(e.transform||(o||n?s.transform=function(t,e,n){let s="",i=!0;for(let r=0;r<ns;r++){const o=st[r],a=t[o];if(void 0===a)continue;let l=!0;if(l="number"==typeof a?a===(o.startsWith("scale")?1:0):0===parseFloat(a),!l||n){const t=ts(a,Ce[o]);l||(i=!1,s+=`${es[o]||o}(${t}) `),n&&(e[o]=t)}}return s=s.trim(),n?s=n(e,i?"":s):i&&(s="none"),s}(e,t.transform,n):s.transform&&(s.transform="none")),a){const{originX:t="50%",originY:e="50%",originZ:n=0}=r;s.transformOrigin=`${t} ${e} ${n}`}}function is(t,e,n){return"string"==typeof t?t:Dt.transform(e+n*t)}const rs={offset:"stroke-dashoffset",array:"stroke-dasharray"},os={offset:"strokeDashoffset",array:"strokeDasharray"};function as(t,{attrX:e,attrY:n,attrScale:s,originX:i,originY:r,pathLength:o,pathSpacing:a=1,pathOffset:l=0,...u},c,h){if(ss(t,u,h),c)return void(t.style.viewBox&&(t.attrs.viewBox=t.style.viewBox));t.attrs=t.style,t.style={};const{attrs:d,style:p,dimensions:f}=t;d.transform&&(f&&(p.transform=d.transform),delete d.transform),f&&(void 0!==i||void 0!==r||p.transform)&&(p.transformOrigin=function(t,e,n){return`${is(e,t.x,t.width)} ${is(n,t.y,t.height)}`}(f,void 0!==i?i:.5,void 0!==r?r:.5)),void 0!==e&&(d.x=e),void 0!==n&&(d.y=n),void 0!==s&&(d.scale=s),void 0!==o&&function(t,e,n=1,s=0,i=!0){t.pathLength=1;const r=i?rs:os;t[r.offset]=Dt.transform(-s);const o=Dt.transform(e),a=Dt.transform(n);t[r.array]=`${o} ${a}`}(d,o,a,l,!1)}const ls=new Set(["baseFrequency","diffuseConstant","kernelMatrix","kernelUnitLength","keySplines","keyTimes","limitingConeAngle","markerHeight","markerWidth","numOctaves","targetX","targetY","surfaceScale","specularConstant","specularExponent","stdDeviation","tableValues","viewBox","gradientTransform","pathLength","startOffset","textLength","lengthAdjust"]);function us(t,{style:e,vars:n},s,i){Object.assign(t.style,e,i&&i.getProjectionStyles(s));for(const e in n)t.style.setProperty(e,n[e])}class cs extends Qn{constructor(){super(...arguments),this.type="svg",this.isSVGTag=!1,this.measureInstanceViewportBox=Zn}getBaseTargetFromProps(t,e){return t[e]}readValueFromInstance(t,e){if(it.has(e)){const t=Oe(e);return t&&t.default||0}return e=ls.has(e)?e:Rn(e),t.getAttribute(e)}scrapeMotionValuesFromProps(t,e,n){return function(t,e,n){const s=$n(t,e,n);for(const n in t)(N(t[n])||N(e[n]))&&(s[-1!==st.indexOf(n)?"attr"+n.charAt(0).toUpperCase()+n.substring(1):n]=t[n]);return s}(t,e,n)}build(t,e,n){as(t,e,this.isSVGTag,n.transformTemplate)}renderInstance(t,e,n,s){!function(t,e,n,s){us(t,e,void 0,s);for(const n in e.attrs)t.setAttribute(ls.has(n)?n:Rn(n),e.attrs[n])}(t,e,0,s)}mount(t){var e;this.isSVGTag="string"==typeof(e=t.tagName)&&"svg"===e.toLowerCase(),super.mount(t)}}class hs extends Qn{constructor(){super(...arguments),this.type="html",this.renderInstance=us}readValueFromInstance(t,e){if(it.has(e)){const t=Oe(e);return t&&t.default||0}{const s=(n=t,window.getComputedStyle(n)),i=(Mt(e)?s.getPropertyValue(e):s[e])||0;return"string"==typeof i?i.trim():i}var n}measureInstanceViewportBox(t,{transformPagePoint:e}){return function(t,e){return function({top:t,left:e,right:n,bottom:s}){return{x:{min:e,max:n},y:{min:t,max:s}}}(function(t,e){if(!e)return t;const n=e({x:t.left,y:t.top}),s=e({x:t.right,y:t.bottom});return{top:n.y,left:n.x,bottom:s.y,right:s.x}}(t.getBoundingClientRect(),e))}(t,e)}build(t,e,n){ss(t,e,n.transformTemplate)}scrapeMotionValuesFromProps(t,e,n){return $n(t,e,n)}handleChildMotionValue(){this.childSubscription&&(this.childSubscription(),delete this.childSubscription);const{children:t}=this.props;N(t)&&(this.childSubscription=t.on("change",(t=>{this.current&&(this.current.textContent=`${t}`)})))}}class ds extends Jn{constructor(){super(...arguments),this.type="object"}readValueFromInstance(t,e){if(function(t,e){return t in e}(e,t)){const n=t[e];if("string"==typeof n||"number"==typeof n)return n}}getBaseTargetFromProps(){}removeValueFromRenderState(t,e){delete e.output[t]}measureInstanceViewportBox(){return{x:{min:0,max:0},y:{min:0,max:0}}}build(t,e){Object.assign(t.output,e)}renderInstance(t,{output:e}){Object.assign(t,e)}sortInstanceNodePosition(){return 0}}function ps(t){const e={presenceContext:null,props:{},visualState:{renderState:{transform:{},transformOrigin:{},style:{},vars:{},attrs:{}},latestValues:{}}},n=function(t){return t instanceof SVGElement&&"svg"!==t.tagName}(t)?new cs(e):new hs(e);n.mount(t),nt.set(t,n)}function fs(t){const e=new ds({presenceContext:null,props:{},visualState:{renderState:{output:{}},latestValues:{}}});e.mount(t),nt.set(t,e)}function ms(t,e,n,s){const i=[];if(function(t,e){return N(t)||"number"==typeof t||"string"==typeof t&&!$(e)}(t,e))i.push(function(t,e,n){const s=N(t)?t:f(t);return s.start(Pn("",s,e,n)),s.animation}(t,$(e)&&e.default||e,n&&n.default||n));else{const r=j(t,e,s),o=r.length;for(let t=0;t<o;t++){const s=r[t],a=s instanceof Element?ps:fs;nt.has(s)||a(s);const l=nt.get(s),u={...n};"delay"in u&&"function"==typeof u.delay&&(u.delay=u.delay(t,o)),i.push(...Dn(l,{...e,transition:u},{}))}}return i}function gs(t,e,n){const s=[],i=function(t,{defaultTransition:e={},...n}={},s,i){const r=e.duration||.3,o=new Map,a=new Map,l={},u=new Map;let c=0,h=0,d=0;for(let n=0;n<t.length;n++){const o=t[n];if("string"==typeof o){u.set(o,h);continue}if(!Array.isArray(o)){u.set(o.name,H(h,o.at,c,u));continue}let[p,f,m={}]=o;void 0!==m.at&&(h=H(h,m.at,c,u));let g=0;const y=(t,n,s,o=0,a=0)=>{const l=J(t),{delay:u=0,times:c=D(l),type:p="keyframes",...f}=n;let{ease:m=e.ease||"easeOut",duration:y}=n;const w="function"==typeof u?u(o,a):u,b=l.length,T=z(p)?p:null==i?void 0:i[p];if(b<=2&&T){let t=100;if(2===b&&et(l)){const e=l[1]-l[0];t=Math.abs(e)}const e={...f};void 0!==y&&(e.duration=v(y));const n=B(e,t,T);m=n.ease,y=n.duration}null!=y||(y=r);const x=h+w,S=x+y;1===c.length&&0===c[0]&&(c[1]=1);const V=c.length-l.length;V>0&&W(c,V),1===l.length&&l.unshift(null),X(s,l,m,c,x,S),g=Math.max(w+y,g),d=Math.max(S,d)};if(N(p))y(f,m,_("default",Z(p,a)));else{const t=j(p,f,s,l),e=t.length;for(let n=0;n<e;n++){const s=Z(t[n],a);for(const t in f)y(f[t],Q(m,t),_(t,s),n,e)}}c=h,h+=g}return a.forEach(((t,s)=>{for(const i in t){const r=t[i];r.sort(G);const a=[],l=[],u=[];for(let t=0;t<r.length;t++){const{at:e,value:n,easing:s}=r[t];a.push(n),l.push(L(0,d,e)),u.push(s||"easeOut")}0!==l[0]&&(l.unshift(0),a.unshift(a[0]),u.unshift("easeInOut")),1!==l[l.length-1]&&(l.push(1),a.push(null)),o.has(s)||o.set(s,{keyframes:{},transition:{}});const c=o.get(s);c.keyframes[i]=a,c.transition[i]={...e,duration:d,ease:u,times:l,...n}}})),o}(t,e,n,{spring:E});return i.forEach((({keyframes:t,transition:e},n)=>{s.push(...ms(n,t,e))})),s}function ys(t){return function(e,n,s){let i=[];var r;r=e,i=Array.isArray(r)&&Array.isArray(r[0])?gs(e,n,t):ms(e,n,s,t);const o=new y(i);return t&&t.animations.push(o),o}}const vs=ys();function ws(t,e,n){t.style.setProperty(`--${e}`,n)}function bs(t,e,n){t.style[e]=n}const Ts=m((()=>{try{document.createElement("div").animate({opacity:[1]})}catch(t){return!1}return!0})),xs=new WeakMap;const Ss="easeOut";function Vs(t){const e=xs.get(t)||new Map;return xs.set(t,e),xs.get(t)}class As{constructor(t,e,n,s){const i=e.startsWith("--");this.setValue=i?ws:bs,this.options=s,this.updateFinishedPromise(),x("string"!=typeof s.type);const r=Vs(t).get(e);r&&r.stop();if(Array.isArray(n)||(n=[n]),function(t,e,n){for(let s=0;s<e.length;s++)null===e[s]&&(e[s]=0===s?n():e[s-1]),"number"==typeof e[s]&&Pe[t]&&(e[s]=Pe[t].transform(e[s]));!Ts()&&e.length<2&&e.unshift(n())}(e,n,(()=>e.startsWith("--")?t.style.getPropertyValue(e):window.getComputedStyle(t)[e])),z(s.type)){const t=B(s,100,s.type);s.ease=yn()?t.ease:Ss,s.duration=v(t.duration),s.type="keyframes"}else s.ease=s.ease||Ss;this.removeAnimation=()=>{var n;return null===(n=xs.get(t))||void 0===n?void 0:n.delete(e)};const o=()=>{this.setValue(t,e,ht(n,this.options)),this.cancel(),this.resolveFinishedPromise()};Vn()?(this.animation=xn(t,e,n,s),!1===s.autoplay&&this.animation.pause(),this.animation.onfinish=o,this.pendingTimeline&&Sn(this.animation,this.pendingTimeline),Vs(t).set(e,this)):o()}get duration(){return w(this.options.duration||300)}get time(){var t;return this.animation?w((null===(t=this.animation)||void 0===t?void 0:t.currentTime)||0):0}set time(t){this.animation&&(this.animation.currentTime=v(t))}get speed(){return this.animation?this.animation.playbackRate:1}set speed(t){this.animation&&(this.animation.playbackRate=t)}get state(){return this.animation?this.animation.playState:"finished"}get startTime(){return this.animation?this.animation.startTime:null}flatten(){var t;this.animation&&(null===(t=this.animation.effect)||void 0===t||t.updateTiming({easing:"linear"}))}play(){"finished"===this.state&&this.updateFinishedPromise(),this.animation&&this.animation.play()}pause(){this.animation&&this.animation.pause()}stop(){this.animation&&"idle"!==this.state&&"finished"!==this.state&&(this.animation.commitStyles&&this.animation.commitStyles(),this.cancel())}complete(){this.animation&&this.animation.finish()}cancel(){this.removeAnimation();try{this.animation&&this.animation.cancel()}catch(t){}}then(t,e){return this.currentFinishedPromise.then(t,e)}updateFinishedPromise(){this.currentFinishedPromise=new Promise((t=>{this.resolveFinishedPromise=t}))}attachTimeline(t){return this.animation?Sn(this.animation,t):this.pendingTimeline=t,i}}const Ms=t=>function(e,n,s){return new y(function(t,e,n,s){const i=K(t,s),r=i.length,o=[];for(let t=0;t<r;t++){const s=i[t],a={...n};"function"==typeof a.delay&&(a.delay=a.delay(t,r));for(const t in e){const n=e[t],i={...ut(a,t)};i.duration=i.duration?v(i.duration):i.duration,i.delay=v(i.delay||0),o.push(new As(s,t,n,i))}}return o}(e,n,s,t))},Ps=Ms(),ks=new WeakMap;let Fs;function Cs({target:t,contentRect:e,borderBoxSize:n}){var s;null===(s=ks.get(t))||void 0===s||s.forEach((s=>{s({target:t,contentSize:e,get size(){return function(t,e){if(e){const{inlineSize:t,blockSize:n}=e[0];return{width:t,height:n}}return t instanceof SVGElement&&"getBBox"in t?t.getBBox():{width:t.offsetWidth,height:t.offsetHeight}}(t,n)}})}))}function Es(t){t.forEach(Cs)}function Os(t,e){Fs||"undefined"!=typeof ResizeObserver&&(Fs=new ResizeObserver(Es));const n=K(t);return n.forEach((t=>{let n=ks.get(t);n||(n=new Set,ks.set(t,n)),n.add(e),null==Fs||Fs.observe(t)})),()=>{n.forEach((t=>{const n=ks.get(t);null==n||n.delete(e),(null==n?void 0:n.size)||null==Fs||Fs.unobserve(t)}))}}const Rs=new Set;let Bs;function Is(t){return Rs.add(t),Bs||(Bs=()=>{const t={width:window.innerWidth,height:window.innerHeight},e={target:window,size:t,contentSize:t};Rs.forEach((t=>t(e)))},window.addEventListener("resize",Bs)),()=>{Rs.delete(t),!Rs.size&&Bs&&(Bs=void 0)}}const Ls={x:{length:"Width",position:"Left"},y:{length:"Height",position:"Top"}};function Ws(t,e,s,i){const r=s[e],{length:o,position:a}=Ls[e],l=r.current,u=s.time;r.current=t[`scroll${a}`],r.scrollLength=t[`scroll${o}`]-t[`client${o}`],r.offset.length=0,r.offset[0]=0,r.offset[1]=r.scrollLength,r.progress=L(0,r.scrollLength,r.current);const c=i-u;r.velocity=c>50?0:n(r.current-l,c)}const Ds={Enter:[[0,1],[1,1]],Exit:[[0,0],[1,0]],Any:[[1,0],[0,1]],All:[[0,0],[1,1]]},Ns={start:0,center:.5,end:1};function Ks(t,e,n=0){let s=0;if(t in Ns&&(t=Ns[t]),"string"==typeof t){const e=parseFloat(t);t.endsWith("px")?s=e:t.endsWith("%")?t=e/100:t.endsWith("vw")?s=e/100*document.documentElement.clientWidth:t.endsWith("vh")?s=e/100*document.documentElement.clientHeight:t=e}return"number"==typeof t&&(s=e*t),n+s}const $s=[0,0];function js(t,e,n,s){let i=Array.isArray(t)?t:$s,r=0,o=0;return"number"==typeof t?i=[t,t]:"string"==typeof t&&(i=(t=t.trim()).includes(" ")?t.split(" "):[t,Ns[t]?t:"0"]),r=Ks(i[0],n,s),o=Ks(i[1],e),r-o}const zs={x:0,y:0};function Hs(t,e,n){const{offset:s=Ds.All}=n,{target:i=t,axis:r="y"}=n,o="y"===r?"height":"width",a=i!==t?function(t,e){const n={x:0,y:0};let s=t;for(;s&&s!==e;)if(s instanceof HTMLElement)n.x+=s.offsetLeft,n.y+=s.offsetTop,s=s.offsetParent;else if("svg"===s.tagName){const t=s.getBoundingClientRect();s=s.parentElement;const e=s.getBoundingClientRect();n.x+=t.left-e.left,n.y+=t.top-e.top}else{if(!(s instanceof SVGGraphicsElement))break;{const{x:t,y:e}=s.getBBox();n.x+=t,n.y+=e;let i=null,r=s.parentNode;for(;!i;)"svg"===r.tagName&&(i=r),r=s.parentNode;s=i}}return n}(i,t):zs,l=i===t?{width:t.scrollWidth,height:t.scrollHeight}:function(t){return"getBBox"in t&&"svg"!==t.tagName?t.getBBox():{width:t.clientWidth,height:t.clientHeight}}(i),u={width:t.clientWidth,height:t.clientHeight};e[r].offset.length=0;let c=!e[r].interpolate;const h=s.length;for(let t=0;t<h;t++){const n=js(s[t],u[o],l[o],a[r]);c||n===e[r].interpolatorOffsets[t]||(c=!0),e[r].offset[t]=n}c&&(e[r].interpolate=ln(e[r].offset,D(s)),e[r].interpolatorOffsets=[...e[r].offset]),e[r].progress=e[r].interpolate(e[r].current)}function Us(t,e,n,s={}){return{measure:()=>function(t,e=t,n){if(n.x.targetOffset=0,n.y.targetOffset=0,e!==t){let s=e;for(;s&&s!==t;)n.x.targetOffset+=s.offsetLeft,n.y.targetOffset+=s.offsetTop,s=s.offsetParent}n.x.targetLength=e===t?e.scrollWidth:e.clientWidth,n.y.targetLength=e===t?e.scrollHeight:e.clientHeight,n.x.containerLength=t.clientWidth,n.y.containerLength=t.clientHeight}(t,s.target,n),update:e=>{!function(t,e,n){Ws(t,"x",e,n),Ws(t,"y",e,n),e.time=n}(t,n,e),(s.offset||s.target)&&Hs(t,n,s)},notify:()=>e(n)}}const Ys=new WeakMap,qs=new WeakMap,Xs=new WeakMap,Gs=t=>t===document.documentElement?window:t;function Zs(t,{container:e=document.documentElement,...n}={}){let s=Xs.get(e);s||(s=new Set,Xs.set(e,s));const i=Us(e,t,{time:0,x:{current:0,offset:[],progress:0,scrollLength:0,targetOffset:0,targetLength:0,containerLength:0,velocity:0},y:{current:0,offset:[],progress:0,scrollLength:0,targetOffset:0,targetLength:0,containerLength:0,velocity:0}},n);if(s.add(i),!Ys.has(e)){const t=()=>{for(const t of s)t.measure()},n=()=>{for(const t of s)t.update(l.timestamp)},i=()=>{for(const t of s)t.notify()},a=()=>{o.read(t,!1,!0),o.read(n,!1,!0),o.update(i,!1,!0)};Ys.set(e,a);const c=Gs(e);window.addEventListener("resize",a,{passive:!0}),e!==document.documentElement&&qs.set(e,(u=a,"function"==typeof(r=e)?Is(r):Os(r,u))),c.addEventListener("scroll",a,{passive:!0})}var r,u;const c=Ys.get(e);return o.read(c,!1,!0),()=>{var t;a(c);const n=Xs.get(e);if(!n)return;if(n.delete(i),n.size)return;const s=Ys.get(e);Ys.delete(e),s&&(Gs(e).removeEventListener("scroll",s),null===(t=qs.get(e))||void 0===t||t(),window.removeEventListener("resize",s))}}function _s(t,e){let n;const s=()=>{const{currentTime:s}=e,i=(null===s?0:s.value)/100;n!==i&&t(i),n=i};return o.update(s,!0),()=>a(s)}const Js=new Map;function Qs({source:t,container:e=document.documentElement,axis:n="y"}={}){t&&(e=t),Js.has(e)||Js.set(e,{});const s=Js.get(e);return s[n]||(s[n]=g()?new ScrollTimeline({source:e,axis:n}):function({source:t,container:e,axis:n="y"}){t&&(e=t);const s={value:0},i=Zs((t=>{s.value=100*t[n].progress}),{container:e,axis:n});return{currentTime:s,cancel:i}}({source:e,axis:n})),s[n]}function ti(t){return t&&(t.target||t.offset)}function ei(t,{axis:e="y",...n}={}){const s={axis:e,...n};return"function"==typeof t?function(t,e){return function(t){return 2===t.length}(t)||ti(e)?Zs((n=>{t(n[e.axis].progress,n)}),e):_s(t,Qs(e))}(t,s):function(t,e){if(t.flatten(),ti(e))return t.pause(),Zs((n=>{t.time=t.duration*n[e.axis].progress}),e);{const n=Qs(e);return t.attachTimeline?t.attachTimeline(n,(t=>(t.pause(),_s((e=>{t.time=t.duration*e}),n)))):i}}(t,s)}const ni={some:0,all:1};function si(t,e,{root:n,margin:s,amount:i="some"}={}){const r=K(t),o=new WeakMap,a=new IntersectionObserver((t=>{t.forEach((t=>{const n=o.get(t.target);if(t.isIntersecting!==Boolean(n))if(t.isIntersecting){const n=e(t);"function"==typeof n?o.set(t.target,n):a.unobserve(t.target)}else n&&(n(t),o.delete(t.target))}))}),{root:n,rootMargin:s,threshold:"number"==typeof i?i:ni[i]});return r.forEach((t=>a.observe(t))),()=>a.disconnect()}function ii(t,e="end"){return n=>{const s=(n="end"===e?Math.min(n,.999):Math.max(n,.001))*t,i="end"===e?Math.floor(s):Math.ceil(s);return S(0,1,i/t)}}function ri(t=.1,{startDelay:e=0,from:n=0,ease:s}={}){return(i,r)=>{const o="number"==typeof n?n:function(t,e){if("first"===t)return 0;{const n=e-1;return"last"===t?n:n/2}}(n,r),a=Math.abs(o-i);let l=t*a;if(s){const e=r*t;l=Ue(s)(l/e)*e}return e+l}}function oi(...t){const e=!Array.isArray(t[0]),n=e?0:-1,s=t[0+n],i=t[1+n],r=t[2+n],o=t[3+n],a=ln(i,r,{mixer:(l=r[0],(t=>t&&"object"==typeof t&&t.mix)(l)?l.mix:void 0),...o});var l;return e?a(s):a}function ai(t,e){return function(t,e){const n=d.now(),s=({timestamp:i})=>{const r=i-n;r>=e&&(a(s),t(r-e))};return o.read(s,!0),()=>a(s)}(t,v(e))}const li=(t,e)=>Math.abs(t-e);function ui(t,e){const n=li(t.x,e.x),s=li(t.y,e.y);return Math.sqrt(n**2+s**2)}const ci=o,hi=r.reduce(((t,e)=>(t[e]=t=>a(t),t)),{});export{p as MotionValue,vs as animate,Ps as animateMini,wt as anticipate,yt as backIn,vt as backInOut,gt as backOut,a as cancelFrame,hi as cancelSync,bt as circIn,xt as circInOut,Tt as circOut,S as clamp,ys as createScopedAnimate,pt as cubicBezier,ai as delay,li as distance,ui as distance2D,Ke as easeIn,je as easeInOut,$e as easeOut,o as frame,l as frameData,u as frameSteps,si as inView,Ne as inertia,ln as interpolate,x as invariant,un as keyframes,ft as mirrorEasing,an as mix,f as motionValue,qe as pipe,L as progress,mt as reverseEasing,ei as scroll,Zs as scrollInfo,E as spring,ri as stagger,ii as steps,ci as sync,oi as transform,T as warning,U as wrap};export default null;
//# sourceMappingURL=/sm/d5d4bfa5a3f292edc74ce2b856e25f03ebbfa4c4c22aa37e3f75ca1dabe374b0.mapContributing
Thanks for helping improve guizang-ppt-skill.
This project is a Skill for AI agents that generate polished HTML slide decks. The most useful contributions are specific, reproducible, and tied to real deck output.
Before Opening an Issue
Please check whether the problem belongs to one of these buckets:
- Layout fidelity: a page drifts away from the registered template.
- Content overflow: text, images, charts, or footers overlap.
- Image workflow: generated images do not match the target slot ratio or deck style.
- Runtime behavior: navigation, ESC overview, low-power mode, map interaction, or animations fail.
- Documentation: installation, prompt usage, layout selection, or examples are unclear.
Screenshots are much more useful than descriptions alone. If possible, include:
- The prompt or source content used to generate the deck.
- The generated
index.html. - A screenshot of the broken slide.
- Browser and OS information.
Pull Request Guidelines
Keep PRs focused. A small fix with a screenshot is easier to review than a large rewrite.
For Swiss theme changes:
- Do not invent new default body layouts unless the change is explicitly discussed.
- Keep the registered layout system intact.
- Run the Swiss validator:
node scripts/validate-swiss-deck.mjs path/to/index.htmlFor template changes:
- Verify at least one dense text slide.
- Verify at least one image slide.
- Verify navigation, ESC overview, and low-power mode.
Good PRs Usually Include
- A short summary of the problem.
- The exact files changed.
- Before / after screenshots when visual behavior changes.
- Validation or manual QA notes.
Style Notes
This Skill is opinionated by design. It prefers constrained layout systems over unlimited customization, because constraints make AI-generated decks more reliable.
When in doubt, preserve the existing visual rules and improve the workflow around them.
Guizang PPT Skill · Web Decks / Images / Covers

An agent skill for Claude Code, Codex, and similar coding-agent environments. It generates single-file HTML horizontal-swipe decks, deck visuals, and social cover pages.
It ships with two visual systems:
- Style A: editorial magazine × electronic ink. Picture Monocle with code stitched in. Best for narrative talks, opinions, salons, and personal voice.
- Style B: Swiss International Typographic Style. Grid-first, one high-saturation anchor color, sharp rectangles, hairline rules, and extreme type contrast. Best for facts, products, analysis, and frameworks.
Distilled by Guizang from offline talks like "One-Person Company: Organizations Folded by AI" and "A New Way of Working." Every pitfall hit during those decks is logged in checklist.md.Sponsor and supporter details are listed in SPONSORS.md.
Old Theme · Style A Editorial Magazine
New Theme · Style B Swiss International
30-second start
npx skills add https://github.com/op7418/guizang-ppt-skill --skill guizang-ppt-skillOr paste this to an AI agent with shell access:
Install guizang-ppt-skill for me. Clone https://github.com/op7418/guizang-ppt-skill into ~/.claude/skills/guizang-ppt-skill, then verify that SKILL.md, assets/, and references/ exist.If you already installed it, update with:
Update guizang-ppt-skill for me. Go to ~/.claude/skills/guizang-ppt-skill, run git pull, then tell me the latest commit.Then ask your agent:
Create a Swiss-style deck from this article, around 7 slides, with 2-3 generated visuals.Other useful prompts:
Turn this Markdown file into an editorial magazine-style presentation.
Create a 21:9 social cover from the core idea of this deck.
Redesign this product screenshot as a 16:10 slide visual.Sponsors and Supporters
<a href="./SPONSORS.md"> <img src="https://github.com/user-attachments/assets/5b0c22c8-aff4-4219-900d-6af8604c57a8" alt="360 Security Lobster Gold Sponsor" width="100%"> </a>
Guizang PPT Skill is supported by 360 Security Lobster as Gold Sponsor and by ZhenFund Token Grant. See SPONSORS.md for details.
What you get
- 🖋 Two visual systems: editorial storytelling for Style A, factual Swiss structure for Style B
- 📐 Horizontal swipe navigation: ← → arrows / scroll wheel / touch swipe / bottom dots / ESC for index
- 🧩 Style A 10 layouts: cover, divider, big numbers, image/text, image grid, pipeline, comparison, and more
- 🧱 Style B 22 locked layouts: Cover, Statement, KPI Tower, Loop Diagram, Duo Compare, Image Hero, Closing Manifesto, and more
- 🎨 Curated theme presets: 5 electronic-ink themes for Style A, 4 Swiss anchor-color themes for Style B
- 🖼 Optional Codex image flow: generate documentary photos, infographics, flow diagrams, system maps, and UI scenes with GPT-Image 2.0 / GPT-M 2.0, then insert them at template-safe ratios
- 📰 Social covers: generate 21:9 WeChat cover images, 1:1 share cards, 3:4 Xiaohongshu covers, video thumbnails, and related variants
- 📴 Low-power static mode: press
Bto turn WebGL / canvas animation into static visuals - 📄 Single HTML file — no build, no server, open directly in the browser
Fits / Doesn't fit
✅ Fits: offline talks, industry keynotes, private salons, AI product launches, demo day, presentations with strong personal voice
❌ Doesn't fit: data-heavy tables, training decks (density too low), multi-user collaborative editing (static HTML)
Common use cases
| Task | Recommended flow |
|---|---|
| Long article to talk deck | Extract the core argument, then build a 6-10 slide rhythm |
| Framework / product analysis | Use Style B Swiss with locked layouts and 21:9 hero visuals |
| Personal talk / opinion piece | Use Style A editorial magazine for stronger narrative rhythm |
| Deck visuals | In Codex, generate photos, infographics, flow diagrams, system maps, or UI scenes |
| Social covers | Generate 21:9 main covers, 1:1 share cards, 3:4 vertical covers, and video thumbnails from the same idea |
| Screenshot normalization | Redesign raw screenshots into template-safe ratios before inserting them into slides |
Why HTML decks
- Agent-native editing: HTML / CSS is plain text, so agents can read, edit, and validate it directly.
- Higher visual density than Markdown: precise layout, positioning, motion, interactivity, and cover formats.
- Lightweight delivery: one HTML file can be opened, presented, sent, screenshotted, or recorded.
- Better quality gates: the Swiss validator can catch layout drift, unsafe image placement, centered body titles, and SVG text traps.
- One visual system across outputs: decks, generated visuals, covers, and screenshot redesigns can share the same style rules.
Platform support
| Platform | Status | Notes |
|---|---|---|
| Claude Code | Supported | Native Skill workflow for creating and iterating HTML decks |
| Codex | Supported | Good for deck generation, image generation, and browser-based visual QA |
| Cursor / other local agents | Works | Requires filesystem access and shell execution |
| WorkBuddy | In adaptation | Marketplace-ready version is being prepared separately |
| Plain chatbot | Not recommended | Without filesystem and browser preview, full deck generation is hard to stabilize |
Install
Option 1: One-line install (recommended)
npx skills add https://github.com/op7418/guizang-ppt-skill --skill guizang-ppt-skillOption 2: Paste this to an AI
Install the guizang-ppt-skill Claude Code skill for me. Steps:>
1. Make sure ~/.claude/skills/ exists (create if not)2. Run git clone https://github.com/op7418/guizang-ppt-skill.git ~/.claude/skills/guizang-ppt-skill3. Verify:ls ~/.claude/skills/guizang-ppt-skill/should showSKILL.md,assets/,references/
4. Tell me when done. Later, saying things like "make me a magazine-style deck" will trigger this skill.
Paste the block above into Claude Code / Cursor / any AI agent with shell access and it handles the install.
Option 3: Manual CLI
git clone https://github.com/op7418/guizang-ppt-skill.git ~/.claude/skills/guizang-ppt-skillHow to trigger it
Once installed, Claude Code auto-detects the skill. Trigger phrases:
- "Make me a magazine-style deck"
- "Make me a Swiss-style deck"
- "Generate a horizontal swipe deck"
- "Editorial magazine style presentation"
- "Electronic ink slides for my talk"
- "Create a 21:9 WeChat cover from this article"
- "Create a 1:1 share card from this deck"
Workflow
The skill is a structured workflow; the agent walks you through each step:
1. Choose style — Style A editorial magazine, or Style B Swiss International 2. Clarify intent — 7-question checklist: style, audience, duration, source material, images/screenshots, theme, hard constraints 3. Copy template — Style A uses assets/template.html; Style B uses assets/template-swiss.html 4. Fill content — create a rhythm plan, then choose and adapt the matching layout skeletons 5. Optional image generation — in Codex, ask whether to use GPT-Image 2.0 / GPT-M 2.0 images, then insert them at page-appropriate ratios 6. Self-check — match against references/checklist.md; P0 issues must all pass; Swiss decks must also pass the layout validator 7. Preview — open the HTML in a browser 8. Iterate — use inline styles to tune font size, height, spacing
Full spec in `SKILL.md`.
Style B Swiss
The Swiss theme is a strict layout system, not just a CSS skin.
- 22 named layouts: body slides must use
S01toS22; do not invent new structures - 4 anchor colors: International Klein Blue, lemon yellow, lemon green, safety orange
- Grid lock: 16-column grid, sharp rectangles, 1px hairlines, no shadows, no gradients, no rounded cards
- Chinese title scaling: all-Chinese headlines should be one step smaller to preserve space for content and images
- Image/text bottom alignment: text and image blocks should align at the bottom in left/right image layouts, while staying clear of pagination controls
- Image slots: images must sit in template-defined
data-image-slotregions, often generated at 21:9 or 16:10 - Hard validation: the validator catches centered body titles, experimental layouts, visible SVG text, and images placed outside slots
Swiss validation:
node scripts/validate-swiss-deck.mjs path/to/index.htmlCodex Image Flow
In Codex, after the first deck draft is ready, the agent can ask whether the user wants generated visuals. Once confirmed, choose an image type or style. Common types include:
- Documentary photos: Fuji / Leica-like real-world scenes that add human texture
- Infographics / flow diagrams / comparison charts / system maps: for concepts that cannot be explained well with photos
- Screenshot framing / screenshot redesigns: preserve raw screenshots with bundled background assets and a CleanShot X-style canvas first; use UI scene generation only when the screenshot needs reconstruction
- Data posters / charts: turn key numbers into insert-ready visual assets
- Multi-image compositions: useful for ultra-wide slots where three unrelated 16:9 images would break the grid
Generated images must follow four core rules:
- Treat the image as an embedded asset, not a standalone slide: no footer, page bottom, title, page number, corner mark, signature, or decorative border
- Match the deck language: Chinese decks use Chinese labels inside infographics, English decks use English labels
- Match the slot ratio before generation: 21:9 for many Swiss hero slots, 16:9 / 16:10 for common main visuals, 16:10 for UI scenes, fixed equal heights for image grids
- When a raw screenshot must stay faithful, read
references/screenshot-framing.mdfirst and use bundledassets/screenshot-backgrounds/backgrounds plus programmatic scaling, padding, and alignment instead of redrawing the screenshot by default
Image prompts live in `references/image-prompts.md`. Screenshot framing lives in `references/screenshot-framing.md`.
Cover Generation
The skill can also turn an article or deck idea into platform covers:
- WeChat main cover: 21:9, headline-first, with one visual anchor
- WeChat share card: 1:1, visually paired with the 21:9 cover
- Xiaohongshu cover / carousel: 3:4, large title, consistent type scale across a batch
- Video thumbnail: 16:9, title + subtitle + one focal visual
The same rule applies: use a few strong keywords, keep the title as the visual center, and do not fill the canvas with body copy.
Example prompts
Copy any of these prompts into your agent, then attach your article, Markdown file, or image assets:
Create an 8-slide Swiss-style deck from this article, with 3 generated visuals matched to the template image slots.Turn this product analysis document into an editorial magazine-style deck with a strong narrative rhythm.From this deck's core idea, create two covers: a 21:9 main cover and a visually paired 1:1 share card.Redesign these product screenshots into consistent 16:10 slide visuals. Preserve key UI information; do not add slide titles or footers inside the images.Directory
guizang-ppt-skill/
├── SKILL.md ← main skill file: workflow, principles, common mistakes
├── README.md ← Chinese README
├── README.en.md ← this file
├── assets/
│ ├── template.html ← Style A editorial magazine template
│ ├── template-swiss.html ← Style B Swiss template
│ └── screenshot-backgrounds/ ← bundled WebP screenshot backgrounds: 5 style-a / 4 style-b
├── scripts/
│ └── validate-swiss-deck.mjs ← Swiss layout validator
└── references/
├── components.md ← component catalog (type, color, grid, icons, callout, stat, pipeline)
├── layouts.md ← 10 layout skeletons (paste-ready)
├── layouts-swiss.md ← 22 locked Swiss layouts
├── swiss-layout-lock.md ← Swiss fidelity and layout hard rules
├── themes.md ← 5 theme presets (pick, don't customize)
├── themes-swiss.md ← 4 Swiss anchor-color themes
├── image-prompts.md ← GPT-Image 2.0 / GPT-M 2.0 image types, ratios, and base prompts
├── screenshot-framing.md ← CleanShot X-style screenshot framing semantics
└── checklist.md ← quality checklist (P0 / P1 / P2 / P3 tiers)Theme presets
Pick from references/themes.md. Custom hex values are not allowed — protecting the aesthetic matters more than freedom of choice.
Style A Editorial Themes
| Preview | Theme | Core colors and best for |
|---|---|---|
| <img src="https://github.com/user-attachments/assets/df21dbcb-5fe4-4852-a91a-a9cf00aceeb4" width="260" alt="Ink Classic theme preview"> | 🖋 Ink Classic | #0a0a0b / #f1efea. General default, commercial launches, when in doubt. |
| <img src="https://github.com/user-attachments/assets/99ce0fd2-72a6-4368-a75a-a8e21657a537" width="260" alt="Indigo Porcelain theme preview"> | 🌊 Indigo Porcelain | #0a1f3d / #f1f3f5. Tech, research, AI, technical keynotes. |
| <img src="https://github.com/user-attachments/assets/bcc1cc4c-5e8e-4467-ae8d-f5801ae73657" width="260" alt="Forest Ink theme preview"> | 🌿 Forest Ink | #1a2e1f / #f5f1e8. Nature, sustainability, culture, non-fiction. |
| <img src="https://github.com/user-attachments/assets/dfea080e-e916-417e-93cd-0a3628de84ca" width="260" alt="Kraft Paper theme preview"> | 🍂 Kraft Paper | #2a1e13 / #eedfc7. Nostalgic, humanist, literary, indie zines. |
| <img src="https://github.com/user-attachments/assets/f3705592-9a72-4dbc-9818-df3aea61bc75" width="260" alt="Dune theme preview"> | 🌙 Dune | #1f1a14 / #f0e6d2. Art, design, creative, fashion, gallery-like decks. |
Switching themes only requires replacing the 6 variables at the top of template.html's :root{} block — all other CSS flows through var(--...).
Style B Swiss Themes
Pick from references/themes-swiss.md. Custom hex values are not allowed here either.
| Preview | Theme | Anchor color and best for |
|---|---|---|
| <img src="https://github.com/user-attachments/assets/c02d02f7-ce6f-4e16-b8a6-778c96851f94" width="260" alt="International Klein Blue Swiss theme preview"> | 🔵 International Klein Blue | #002FA7. Default, commercial launches, AI products, frameworks. |
| <img src="https://github.com/user-attachments/assets/c310a8c4-5d28-450e-b49a-6ac5b6ba4785" width="260" alt="Lemon Yellow Swiss theme preview"> | 🟡 Lemon Yellow | #FFD500. Youth, sports, retail, consumer goods, Y2K retro. |
| <img src="https://github.com/user-attachments/assets/65f7b3f9-3358-419e-b513-f7f2cc24ec76" width="260" alt="Lemon Green Swiss theme preview"> | 🟢 Lemon Green | #C5E803. Ecology, sustainability, health, Gen Z brands. |
| <img src="https://github.com/user-attachments/assets/9c3319c9-a134-4657-9a56-211c23411f7f" width="260" alt="Safety Orange Swiss theme preview"> | 🟠 Safety Orange | #FF6B35. Alerts, news, industrial topics, sports, energetic themes. |
If the user asks for a Swiss-style deck without specifying color, default to International Klein Blue.
Core design principles
1. Restraint over flash — WebGL backgrounds only bleed through on hero pages 2. Structure over decoration — information hierarchy via type size + typeface + grid whitespace, not shadows or floating cards 3. Images are first-class citizens — align them with the body content area, keep ratios stable, crop only from the bottom, and preserve top/sides 4. Generated visuals are assets — keep only the core photo / chart / UI; do not render slide titles, footers, or corner marks inside the image 5. Rhythm lives on hero pages — hero / non-hero alternation keeps the eye from fatiguing 6. Dynamic effects must be optional — B toggles static mode so animation never becomes a reading burden 7. Terms stay consistent — Skills is Skills; no mix-and-match translations 8. Swiss layouts stay locked — Style B should restore and reuse the original 22-page layout system instead of inventing unrelated pages
Visual references
- *Monocle* magazine layouts
- YC Garry Tan — "Thin Harness, Fat Skills"
- Massimo Vignelli / Helvetica Forever / Swiss International Typographic Style
- Guizang's offline talk deck series
Roadmap
- Add more real-world examples and openable HTML deck demos
- Expand cover formats for more publishing platforms
- Add more Swiss layout validation rules
- Improve screenshot redesign and infographic generation workflows
- Prepare marketplace-specific variants such as WorkBuddy
- Add more curated theme packs while keeping custom colors restricted
FAQ
Can it export to PPTX? The main output is HTML. You can present it in a browser, screenshot it, or record it. PPTX conversion can be done as a separate workflow, but it is not the core path today.
Why are custom colors not allowed? The skill is designed for stable visual output. Arbitrary colors often break the system, so decks must use curated presets.
Can I add my own layout? Yes. Style A layouts can be extended in references/layouts.md. Style B is stricter: update template-swiss.html, layouts-swiss.md, swiss-layout-lock.md, and the validator together.
Is Codex image generation required? No. Decks work without generated images. The image flow is only used when you need photos, infographics, UI scenes, or covers.
How do I update the skill? Run the install command again, or run git pull inside your local skill directory.
Contributing
Bugs, layout issues, new layout requests — Issues and PRs welcome. Prioritize:
- Add new classes to
template.htmlfirst; don't letlayouts.mdreference undefined classes - When changing
template-swiss.html, updatelayouts-swiss.mdandswiss-layout-lock.mdtogether - When adding Swiss rules, update
scripts/validate-swiss-deck.mjs - Log pitfalls into
checklist.mdat the matching P0 / P1 / P2 / P3 tier - New theme colors go into
themes.mdwith a recommended use case
License
AGPL-3.0 © 2026 op7418
主题色预设(Themes)
5 套精心调配的主题色板,保证"电子杂志 × 电子墨水"的美学不垮。不允许用户自定义颜色——色彩搭配错了画面瞬间变丑,只从以下预设中挑选。
---
使用方法
1. 问用户选哪套(或基于内容推荐一套) 2. 打开 assets/template.html 的 <style> 块 3. 找到开头的 :root{ 块 4. 整体替换标有"主题色"注释的那几行 --ink / --ink-rgb / --paper / --paper-rgb / --paper-tint / --ink-tint 5. 其他 CSS 都走 var(--...),无需任何其他改动
---
🖋 墨水经典 (Monocle 默认)
适合:通用分享、商业发布、科技产品、任何场景都安全的默认选择。 调性:纯墨黑 + 暖米白,杂志感最强,Monocle / Apricot / A Book Apart 风。
--ink:#0a0a0b;
--ink-rgb:10,10,11;
--paper:#f1efea;
--paper-rgb:241,239,234;
--paper-tint:#e8e5de;
--ink-tint:#18181a;---
🌊 靛蓝瓷 (Indigo Porcelain)
适合:科技/研究/数据分享、工程师文化、深度内容、技术发布会。 调性:深靛蓝 + 瓷白,冷静、理性、有深度,像学术期刊或蓝印花瓷器。
--ink:#0a1f3d;
--ink-rgb:10,31,61;
--paper:#f1f3f5;
--paper-rgb:241,243,245;
--paper-tint:#e4e8ec;
--ink-tint:#152a4a;---
🌿 森林墨 (Forest Ink)
适合:自然/可持续/文化/非虚构内容、户外品牌、环保主题。 调性:深森林绿 + 象牙,沉稳、有呼吸感,像旧版《国家地理》。
--ink:#1a2e1f;
--ink-rgb:26,46,31;
--paper:#f5f1e8;
--paper-rgb:245,241,232;
--paper-tint:#ece7da;
--ink-tint:#253d2c;---
🍂 牛皮纸 (Kraft Paper)
适合:怀旧/人文/阅读/历史/文学分享、独立杂志、手作品牌。 调性:深棕 + 暖米,像牛皮信封或老笔记本,温暖、有年代感。
--ink:#2a1e13;
--ink-rgb:42,30,19;
--paper:#eedfc7;
--paper-rgb:238,223,199;
--paper-tint:#e0d0b6;
--ink-tint:#3a2a1d;---
🌙 沙丘 (Dune)
适合:艺术/设计/创意/时尚分享、画廊手册、审美优先的私享会。 调性:炭灰 + 沙色,克制、高级、中性,像沙漠黄昏或建筑设计图册。
--ink:#1f1a14;
--ink-rgb:31,26,20;
--paper:#f0e6d2;
--paper-rgb:240,230,210;
--paper-tint:#e3d7bf;
--ink-tint:#2d2620;---
推荐选择参考
| 如果是... | 推荐主题 |
|---|---|
| 不知道选啥 / 第一次用 | 🖋 墨水经典 |
| AI / 技术 / 产品发布 | 🌊 靛蓝瓷 |
| 内容 / 行业观察 / 文化 | 🌿 森林墨 |
| 书评 / 生活方式 / 人文 | 🍂 牛皮纸 |
| 设计 / 艺术 / 品牌 | 🌙 沙丘 |
---
切换原则
- 一份 deck 只用一套主题,不要中途换色
- WebGL shader 的默认主色(钛金色散 / 银色流动)适配所有 5 套(经测试可接受)
currentColor驱动的 border / icon 会跟随 section 的 text color 自动适配,无需额外调整- 选定主题后,
<title>文字和chrome文案可以强化该主题的语义(例如牛皮纸配"Vol.03 · 秋"这种)
❌ 不要做的事
- ❌ 不允许混搭(例如 ink 取墨水经典的,paper 取沙丘的)——会彻底违和
- ❌ 不允许用户随便给一个 hex 值——需委婉拒绝并展示 5 套预设让选
- ❌ 不要直接修改 template.html 其他地方的颜色——所有散落 rgba 都走 var,改 :root 一处即可
选定主题后在 skill 对话中告诉用户:"用 🖋 墨水经典 / 🌊 靛蓝瓷 ..."并在 deck 项目记录里备注,方便后续迭代时保持一致。
赞助与支持
Guizang PPT Skill 是由 歸藏 创建和维护的开源项目。赞助信息只用于 GitHub 项目页、项目介绍和社区传播,不会写入用户生成的 PPT、HTML 页面、封面或配图。
当前赞助方
| 赞助方 | 等级 / 类型 | 说明 |
|---|---|---|
| 360 安全龙虾 | 金牌赞助 | 支持 guizang-ppt-skill 的持续维护、模板测试与开源传播。 |
| 真格 Token Grant | Grant Supporter | 通过 Token Grant 支持项目的模板迭代、配图流程验证与开源维护。 |
赞助用途
- 真实内容下的模板压力测试
- GPT-Image / GPT-M 配图、截图嵌入与封面工作流验证
- README、示例、跨平台适配和平台上架资料维护
- 社区反馈整理、Issue / PR 处理和文档改进
露出原则
- 赞助露出只放在 GitHub README、SPONSORS.md、项目介绍材料等项目层面。
- 不把赞助商信息写入用户生成的 PPT、HTML 页面、封面或配图。
- 项目保持开源、独立维护,赞助不影响模板规则和内容判断。
联系
如需支持项目或讨论合作,可以通过 GitHub Issues 或 歸藏 联系。
Related skills
FAQ
What design styles does this skill support?
Style A (magazine/narrative with 10 layouts) and Style B (Swiss/analytical with 22 locked layouts)
What input formats are supported?
Markdown articles and content can be converted to presentations
Is Guizang Ppt Skill safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.