Skill: kaisersong/kai-export-ppt-lite (version 1.6.9)

--- name: kai-export-ppt-lite description: Use when exporting HTML presentations to editable PPTX in sandbox environments where Playwright cannot be installed. Pure Python: bs4 + python-pptx + Pillow. Keywords: export pptx sandbox, html to pptx no browser, editable powerpoint from html. version: 1.6.9 metadata: openclaw: emoji: "📄" os: [darwin, linux, windows] requires: bins: [python3] install: - id: beautifulsoup4 kind: uv package: beautifulsoup4 label: beautifulsoup4 (HTML parsing) - id: lxml kind: uv package: lxml label: lxml (HTML parser backend) - id: python-pptx kind: uv package: python-pptx label: python-pptx (editable PPTX generation) - id: Pillow kind: uv package: Pillow label: Pillow (image handling) --- # kai-export-ppt-lite Export HTML presentations to **editable PPTX** without a browser. Pure Python — no Playwright, no Chrome, no Node.js. ## Commands | Command | What it does | |---------|-------------| | `python3 <skill-path>/scripts/export-sandbox-pptx.py <file.html> [output.pptx] [--width 1440] [--height 900]` | Canonical entrypoint; works as a real file or as inline-retrieved script | | `python3 <skill-path>/scripts/run-skill-export.py <file.html> [output.pptx] [--width 1440] [--height 900]` | Optional tiny bootstrap when the runtime exposes a real installed skill directory | ## Dependencies | Package | Install | |---------|---------| | `beautifulsoup4` | Usually auto-installed by skill metadata or `pip install beautifulsoup4` | | `lxml` | Usually auto-installed by skill metadata or `pip install lxml` | | `python-pptx` | Usually auto-installed by skill metadata or `pip install python-pptx` | | `Pillow` | Usually auto-installed by skill metadata or `pip install Pillow` | ## Usage ```bash python3 <skill-path>/scripts/export-sandbox-pptx.py <file.html> [output.pptx] [--width 1440] [--height 900] ``` Local repo execution remains available: ```bash python3 scripts/export-sandbox-pptx.py <file.html> [output.pptx] [--width 1440] [--height 900] ``` ## Sandbox Execution Do not assume anything about the agent runtime. This skill must tolerate: - no stable skill root path - no `__file__` - notebook / cell-style inline execution - dependencies either preinstalled or missing When this skill runs inside a hosted sandbox, use this decision order: 1. Default path: retrieve and execute `scripts/export-sandbox-pptx.py`. 2. If the runtime exposes a real installed skill directory, you may instead call: ```bash python3 <skill-path>/scripts/export-sandbox-pptx.py input.html output.pptx ``` 3. If the runtime only supports inline Python execution, retrieve `scripts/export-sandbox-pptx.py` and inline it directly. 4. Pass the HTML input via the sandbox VFS/attachment mechanism and write the PPTX to the sandbox artifact directory. 5. Let the script self-bootstrap dependencies first. Skill metadata / `requirements.txt` are optimizations, not assumptions. 6. `scripts/run-skill-export.py` is an optional optimization only. Do not require it for correctness. ### Why this is the stable path - `scripts/export-sandbox-pptx.py` is the only execution surface that does not require assuming a skill root, env var, or installer-specific layout. - The exporter now tolerates missing `__file__`, degrades when vendored `contracts/` are absent, and attempts runtime dependency bootstrap before failing. - `run-skill-export.py` remains useful when the environment is richer, but it is not part of the correctness boundary. - If vendored `contracts/` are unavailable, export still runs; only preset-specific fidelity hints degrade. ### Prohibited patterns - assuming an installed skill directory exists - assuming `__file__` exists in notebook / cell-based sandboxes - assuming build-time dependency installation always happened - making `run-skill-export.py` the only supported path ### Options | Flag | Description | |------|-------------| | `--width N` | Slide width in pixels (default: 1440) | | `--height N` | Slide height in pixels (default: 900) | | `--with-chrome` | Add page counter and nav dots | ## What it extracts | HTML Element | PPTX Output | |-------------|-------------| | `h1-h6, p, li, span` | Editable text boxes | | `div` with background/border | Rounded rectangles with fill | | `table, tr, td, th` | Cell rectangles with text frames | | `img` (http/file/data-uri) | Embedded pictures | | `svg` | Placeholder rectangle | ## Limitations (no browser) - CSS variables: only `:root` static substitution - Layout: simulated flex-column, not pixel-perfect - Computed styles: unavailable, relies on inline style + `<style>` blocks - JavaScript: not executed, so IntersectionObserver-gated content won't appear ## Comparison | | kai-html-export (full) | kai-export-ppt-lite | |---|---|---| | Runtime | Playwright + Chrome | Pure Python | | Sandbox compatible | ❌ | ✅ | | Output quality | Pixel-perfect | Semantic layout | | Editable text | ✅ | ✅ | | Image mode PPTX | ✅ (screenshot) | ❌ | | Dependencies | playwright, python-pptx | bs4, lxml, python-pptx, Pillow |

path: README.md
content: # kai-export-ppt-lite

Pure-Python HTML-to-PPTX export for editable slide decks in sandboxed environments.  
面向沙箱环境的纯 Python HTML 转 PPTX 导出器，目标是生成可编辑的 PowerPoint，而不是截图式 PPT。

Current release: `v1.6.9`

## 中文说明

### 这是什么

`kai-export-ppt-lite` 用来把 HTML 演示稿导出为可编辑的 `.pptx`。它不依赖 Playwright、Chrome 或 Node.js，适合浏览器运行时不可用、但仍需要可编辑 PPT 输出的环境。

它当前的核心定位是：

- 用 `BeautifulSoup` 和 `lxml` 解析 HTML/CSS
- 用 `python-pptx` 生成原生、可编辑的 PowerPoint 元素
- 在没有浏览器布局引擎的前提下，模拟文本、卡片、列表、表格、presentation rows、inline code/kbd/badge 等结构
- 配合回归测试和评估脚本，持续把 exporter 从单 deck 修补推进到可复用能力

### 当前状态

当前版本的两个主要验证锚点是：

- `Blue Sky`
  - 源 HTML：`demo/blue-sky-zh.html`
  - 本地 golden 参考：`demo/blue-sky-golden-native.pptx`
  - 最新已验证分数：`9.1/10`
- `Chinese Chan`
  - 源 HTML：`demo/chinese-chan-zh.html`
  - 最新完整视觉对比分数：`9.68/10`
  - 当前结构化评估：
  - `overflow = 0`
  - `overlap = 0`
  - `card containment = 0`
  - `element gaps = 0`
  - `total actionable = 0`
- `Swiss Modern`
  - 约束路径：`canonical + constrained compatible`
  - 最新真实回归样本：`kingdee_from_original_v7.pptx`
  - 最新完整视觉对比分数：`9.36/10`
  - 已确认文件级文字语义：
  - `P3 body wrap = square`
  - `P5 title wrap = none`
- `Aurora Mesh`
  - 源 HTML：`demo/aurora-mesh-zh.html`
  - 当前分支最新完整视觉对比分数：`9.00/10`
  - 当前结构化评估：
  - `overflow = 0`
  - `overlap = 0`
  - 这轮优化重点：
  - 动态 mesh 背景降级为接近源稿氛围的纯色，而不是伪造大椭圆或退回纯黑
  - KPI 组件默认保持紧凑，只有源 CSS 明确给出 stretch 信号时才拉宽

整体上，这条分支已经明显从“按页打补丁”转成了“增强 exporter 通用能力 + producer-aware preset contract”。仍未达到“所有风格都稳定每页 >= 9.5”的最终目标，但 `Chinese Chan` 这类高度依赖字体与换行节奏的 preset 已经被真正拉上来。

最近新增并持续强化的，是一条 `slide-creator` contract-driven 路径，正在把 `data-story / enterprise-dark / chinese-chan / swiss-modern` 这类新风格从“启发式近似”推进到“基于 preset contract 的组件与排版导出”。其中 `Chinese Chan` 和 `Swiss Modern` 已经补上：

- typography contract
- authored line-break contract
- shared runtime chrome fallback
- centered command / seal fidelity gate
- role-aware Swiss layout builders
- title/body wrap guards against PowerPoint-only reflow

### 主要能力

- 可编辑文本导出：`h1-h6`、`p`、`li`、`span`、`a`
- 卡片、圆角矩形、边框、accent bar、pill-like inline overlay
- 支持 `code`、`kbd`、`badge`、`link`、grouped inline command row
- 支持区分真实数据表格与 presentation-like rows
- 无浏览器条件下的 flex/grid 近似布局
- 面向回归的测试体系与视觉/结构 eval

### 仓库内容

GitHub 仓库当前主要包含：

- `scripts/export-sandbox-pptx.py`
  主导出器
- `scripts/test-export.py`
  回归测试
- `scripts/rigorous-eval.py`
  多维评估脚本
- `scripts/compare-visual-comprehensive.py`
  和 golden deck 的视觉结构对比
- `tests/fixtures/export-corpus/`
  手写 fixture，用于保证通用导出能力
- `SKILL.md`
  Codex skill 入口说明

以下目录/文件是本地工作资产，不作为 GitHub 仓库交付内容：

- `demo/`
  本地输入 HTML、golden deck、输出 PPTX/预览图
- `docs/`
  本地链接到 `mydocs` 的设计与复盘文档
- `memory/`
  本地工作断点和 session 记录

### 安装

```bash
pip install beautifulsoup4 lxml python-pptx Pillow
```

### 用法

导出 HTML 到 PPTX：

```bash
python3 scripts/export-sandbox-pptx.py demo/blue-sky-zh.html demo/output.pptx
```

可选参数：

```bash
python3 scripts/export-sandbox-pptx.py <file.html> [demo/output.pptx] [--width 1440] [--height 900] [--with-chrome]
```

- `--width`
  幻灯片宽度，默认 `1440`
- `--height`
  幻灯片高度，默认 `900`
- `--with-chrome`
  额外添加 exporter 提供的页码和导航点

### 验证流程

```bash
python3 -m py_compile scripts/export-sandbox-pptx.py scripts/test-export.py scripts/rigorous-eval.py
python3 scripts/test-export.py
python3 scripts/export-sandbox-pptx.py demo/blue-sky-zh.html demo/output.pptx
python3 scripts/rigorous-eval.py
```

### v1.6.9 更新重点（patch / refactor 提通用）

- 把 `_build_swiss_index_list_rows()` 里的 hairline 高度策略提为通用 helper：
  - `_hairline_height_in(border_w_px)`：1-2px 减半到 0.5px floor，3px+ 透传
  - `_build_css_hairline_shape(border_value, x, y, w, fallback_color)`：从 CSS border 速记构建 decoration shape，自动跳过 `none`/0
- `_build_swiss_index_list_rows` 现在使用通用 helper（行为不变，但代码 ~25 行 → ~10 行）
- 后续任何 builder 遇到"PPTX 把 1px CSS 边框渲染过粗"都可直接复用
- 新增两个回归测试：`test_hairline_height_halves_thin_borders_and_passes_thick_through`、`test_build_css_hairline_shape_extracts_color_and_skips_none`
- `Swiss Modern` `9.04`、`Aurora Mesh` `9.01` 与 v1.6.8 持平（refactor 无行为变化）

### v1.6.8 更新重点（patch / 用户反馈修复）

四条用户反馈的视觉缺陷修复：

- **K1 KPI 数字下方文字没对齐**：`_measure_compact_flex_child_width_in()` 给单行测量加 +0.05" 安全余量并调高字宽系数（latin 0.55→0.62, cjk 0.96→1.0），避免 "21" 这类边界数字被 PPTX wrap 引擎误判 2 行。修后 P1 三列 label 都在同一 y=8.183
- **K2 P4 分割线太粗**：`.index-item border-bottom` 从 1px 改为 ~0.5px 等效高度（`max(border_w * 0.5, 0.5px)`），更接近源 hairline 视觉
- **K3 P5 白字后面应有黑背景**：`export_table_element` 现在会把 cell 内单 inline-block bg span 的背景色提升为整 cell 背景，避免白字 on 白格不可见。`<td><span class="terminal-line">cmd</span></td>` 现在渲染为黑底白字
- **K4 P8 KPI 应靠左对齐**：扩 swiss `title_grid` canonical 接受 `.cta-inner`（之前只接 `.hero-inner` → 落到 fallback 被居中）；`_pack_relative_block_container` 改为 per-item 而非 global min_x normalize，避免 flex-row 容器（x=0）和 inline span（x=0.5）被错位定位
- 跨 deck 副作用：`_pack_relative_block_container` 改动让 data-story 测试 wrapper width 阈值 `≥6.9 → ≥6.4"`（更接近源 max-width 700px = 6.48"）
- `Swiss Modern` canonical：`9.07 → 9.04`（P5 黑底匹配度问题导致 SSIM 微降，但视觉缺陷修复优先）；`Aurora Mesh` `9.00 → 9.01`

### v1.6.7 更新重点（patch / 同步）

- `scripts/sync-slide-creator-contracts.py` 中扩 swiss-modern 的 `layout_variations` 与 `layout_contracts`，包含本次 session 新增的 `inner_panel / index_list / inst_blocks / disc_layout` 四个 role。下次执行 sync 时这些 role 不再被覆盖
- 不动代码逻辑，纯协议落地
- `Swiss Modern` canonical 保持 `9.07/10`；`Aurora Mesh` 保持 `9.00/10`

### v1.6.6 更新重点（patch）

- 新增 `disc_layout` layout role：覆盖 `.disc-header + .disc-body` 类幻灯片（Swiss Slide 3）。`_build_swiss_disc_layout` 负责顶部标题区 + 下方双列布局（左 `.disc-steps` 编号列表 + 右 `.disc-diagram` SVG 图示）
- 新增 `_build_swiss_disc_steps` helper：每个 `.disc-step` 在左数字列（min-width）+ 右内容列（剩余宽度），垂直堆叠而不是横向溢出
- SVG `.diagram-svg` 现在通过 `build_svg_container` 渲染为相对容器，rect/line/text 元素全部约束在 SVG 边界内（修前在 x=17-22"，完全屏外）
- 修前 P3 三个数字 01/02/03 横向漂移到 x=0.5/6.27/13.55；修后全部对齐 x=0.667 垂直堆叠
- 新增回归测试：`test_swiss_disc_steps_stack_vertically_with_left_number_column`
- `Swiss Modern` canonical：Slide 03 保持 `9.3/10`（结构大改但 SSIM 已在跨渲染器 cap，视觉分不动）；整体保持 `9.07/10`
- `Aurora Mesh` 视觉回归保持 `9.00/10`（SVG 装饰判定未改，未影响 Aurora）

### v1.6.5 更新重点（patch）

- 新增 `index_list` layout role：覆盖 `.sol-inner` 类幻灯片（Swiss Slide 4），处理"中央堆叠的 eyebrow + h2 + sol-rule + sol-list"结构。`_build_swiss_index_list_rows` 让每个 `.index-item` 占满全宽，数字列固定宽度（`min-width`），内容列拿剩余宽度，并按字号差近似 baseline 对齐
- 新增 `inst_blocks` layout role：覆盖 `.inst-inner` 类幻灯片（Swiss Slide 7）。`_build_swiss_inst_block_card` 处理 left-border 装饰条 + label + `.terminal-line` 黑底胶囊（paired bg shape + 文字 overlay），不再把 inline-block span bg 折成纯文字
- 新增 `_build_swiss_terminal_line` helper：把 `display:inline-block + background` 的 inline span 升级成 paired bg shape + text，padding 完整保留
- 新增三个回归测试：`test_swiss_index_list_rows_stretch_full_width_with_left_number_column`、`test_swiss_terminal_line_renders_dark_pill_with_paired_overlay`
- `Swiss Modern` canonical：Slide 04 `8.9 → 9.2`（+0.3）；Slide 07 `9.1 → 8.9`（-0.2，结构对了但 SSIM 跨渲染器对齐略差）；整体 `9.06 → 9.07`
- `Aurora Mesh` 视觉回归保持 `9.00/10`

### v1.6.4 更新重点（patch）

- `build_grid_children` 新增 compact flex-row 识别（gap + 无 `space-between/around/evenly` justify-content）：子元素按 intrinsic 内容宽度紧凑排布，不再强制平分整行宽度。修复 Slide 1 / 8 的 `.hero-stats` KPI 横跨整行问题（P1 横跨 `8.7" → 1.8"`）
- `_build_swiss_column_content` 后置 stretch：左栏块级标题/段落强制取容器内宽，避免 `<br>` 显式换行被二次折成孤字（P2 标题 `2.08" → 4.03"`，由 spAutoFit 接管高度生成 2 行干净换行）
- 新增三个回归测试：`test_compact_flex_row_packs_stat_blocks_at_intrinsic_width`、`test_compact_flex_row_falls_back_to_even_split_when_oversized`、`test_stretch_column_block_text_to_inner_width_expands_narrow_heading`
- `Swiss Modern` canonical 整体保持 `9.06/10`（cross-renderer SSIM 已逼近 cap），结构对应 source CSS 的真实意图
- `Aurora Mesh` 视觉回归保持 `9.00/10`

### v1.6.3 更新重点（patch）

- `_build_swiss_column_content` 的右栏改成跟左栏一致的垂直居中（之前 canonical tier 硬编码 `right_y = 0`）
- `_build_swiss_title_grid` 的 `justify-content` 优先从 inner panel 取（如 `.flow-inner { justify-content: center }`）
- `Swiss Modern` canonical：Slide 05 `8.6 → 9.0`、Slide 06 `8.9 → 9.0`、整体 `9.00 → 9.06`
- `Aurora Mesh` 视觉回归保持 `9.00/10`

### v1.6.2 更新重点（patch）

- `display heading` 视觉补偿排除 `noto sans` 触发条件——当 Noto Sans SC 映射到 Helvetica Neue + Hiragino Sans GB 跨渲染器稳定字对时，1.30 倍 boost 会超调并把标题误折成两行
- 新增 `inner_panel` layout role 覆盖单内容面板（无 `.bg-num` 装饰）的 Swiss 幻灯片（Slide 5 `flow-inner`、Slide 6 `feat-inner`）
- `_FONT_MAP` 锁定 Archivo / Nunito / Noto Sans SC 全部映射到 Helvetica Neue + Hiragino Sans GB 跨渲染器稳定字对
- 对比脚本注入字体覆盖样式，使 SSIM 反映 layout 一致性而非跨渲染器字体差异
- `Swiss Modern` canonical 视觉快照：整体 `8.93 → 9.00`；Slide 03/04/05/07 各 `+0.1`
- `Aurora Mesh` 视觉回归保持 `9.00/10` 不变

### 已知边界

- 当前 SSIM 跨渲染器对比 gate 下，`≥ 9.5/slide` 不可达：单页 SSIM 实测上限 `~0.92`（最佳 `0.9227`），对应 score 约 `9.34`。要进一步提分需换 gate（structural eval 或共享 renderer），不是继续调 layout。

### v1.6.1 更新重点（patch）

- 修复 `_pack_direct_child_content` 不再让 absolute/fixed 子元素污染面板内容宽度
- 新增 `_build_absolute_decoration_strips`：在 Swiss `column_content` 面板内按授权 CSS 尺寸（`width / left / right / top / bottom`）渲染装饰条
- `Swiss Modern` canonical 视觉快照：Slide 02 `8.7 → 9.3`、整体 `8.85 → 8.93`
- `Aurora Mesh` 视觉回归保持 `9.00/10` 不变
- 回归套件全量通过 `python3 scripts/test-export.py`

### v1.6.0 更新重点

- 导出管线重构成显式多段合同（`analyze → profile → slide plan → geometry plan → render`）：
  - 新增 `analyze_source` 阶段，先产出 raw signal bundle，再进入任何渲染决策
  - 新增 profile 阶段，强约束 contract evidence 必须来自本地（preset attribution + tier precedence）
  - 新增 slide planning 层，per-slide plan state 隔离，规划副作用不再串到几何阶段
  - 新增 pptx geometry planning 阶段，独占布局决策并配套强化的 stage 合同
  - render 阶段成为 geometry plan 的纯消费者，不再二次重算布局
- vendored `slide-creator` presets 同步刷新；`slide root discovery` 提到共享 helper，覆盖 generic section deck
- `Aurora Mesh` 视觉对比 `9.00/10`：
  - 弃用接近黑色的背景退化，按授权 mesh 层推导出 atmospheric 单色近似
  - KPI 默认 compact，仅当源 CSS 显式声明 stretch 时才扩展
  - 保住 wrapper 居中和 install-card 结构，`overflow = 0`、`overlap = 0`
- 回归套件全量通过 `python3 scripts/test-export.py`

### 已知边界

- 还没有实现和 native golden 完全一致
- 当前 `Swiss Modern` 仍是 `canonical + constrained compatible`，不是任意 Swiss-like HTML 的通用保真引擎
- 当前低分主要集中在：
  - canonical Swiss 的 `title_grid / column_content` 光学节奏仍有漂移
  - 若干页面的标题尺度与版心还没完全贴齐 reference
  - 本机 office-render compare 仍不是理想的最终视觉判分器

## English

### What This Is

`kai-export-ppt-lite` converts HTML presentations into editable `.pptx` files without Playwright, Chrome, or Node.js. It is built for environments where a browser-based renderer cannot be installed, but editable PowerPoint output is still required.

The current exporter is centered on:

- HTML/CSS parsing via `BeautifulSoup` and `lxml`
- Native, editable PPTX generation via `python-pptx`
- Browser-free layout approximation for text, cards, lists, tables, presentation rows, and inline code/kbd/badge patterns
- Regression tests and evaluation tooling that push the exporter toward reusable capabilities instead of deck-specific patches

### Current Status

The current validation anchors are:

- `Blue Sky`
  - Source HTML: `demo/blue-sky-zh.html`
  - Local golden reference: `demo/blue-sky-golden-native.pptx`
  - Latest verified score: `9.1/10`
- `Chinese Chan`
  - Source HTML: `demo/chinese-chan-zh.html`
  - Latest completed visual compare: `9.68/10`
  - Current structured eval:
  - `overflow = 0`
  - `overlap = 0`
  - `card containment = 0`
  - `element gaps = 0`
  - `total actionable = 0`
- `Swiss Modern`
  - Constraint path: `canonical + constrained compatible`
  - Latest real regression artifact: `kingdee_from_original_v7.pptx`
  - Latest completed visual compare: `9.36/10`
  - Confirmed file-level text semantics:
  - `P3 body wrap = square`
  - `P5 title wrap = none`

This branch has not yet reached the final goal of “every style, every slide >= 9.5”, but it is now substantially more generalized than the earlier slide-by-slide patching phase. The exporter now enforces preset-aware typography and break fidelity for decks such as `Chinese Chan` and `Swiss Modern`, not just generic geometry.

### Core Capabilities

- Editable text export for `h1-h6`, `p`, `li`, `span`, and `a`
- Rounded cards, fills, borders, accent bars, and pill-like inline overlays
- First-class handling for `code`, `kbd`, `badge`, `link`, and grouped command rows
- Separation between real data tables and presentation-like rows
- Browser-free flex/grid approximation
- Regression tests and multi-dimensional eval tooling

### Repository Contents

The GitHub repository mainly ships:

- `scripts/export-sandbox-pptx.py`
  Main exporter
- `scripts/test-export.py`
  Regression suite
- `scripts/rigorous-eval.py`
  Multi-dimensional evaluation gate
- `scripts/compare-visual-comprehensive.py`
  Golden-vs-sandbox comparison tool
- `tests/fixtures/export-corpus/`
  Handwritten fixtures for generalized exporter coverage
- `SKILL.md`
  Codex skill entry for this repository

The following assets remain local-only and are not intended as GitHub repository content:

- `demo/`
  Local input decks, golden references, generated PPTX files, and previews
- `docs/`
  Local symlink to `mydocs` for design notes and optimization history
- `memory/`
  Local checkpoints and session logs

### Installation

```bash
pip install beautifulsoup4 lxml python-pptx Pillow
```

### Usage

Export HTML to PPTX:

```bash
python3 scripts/export-sandbox-pptx.py demo/blue-sky-zh.html demo/output.pptx
```

Optional flags:

```bash
python3 scripts/export-sandbox-pptx.py <file.html> [demo/output.pptx] [--width 1440] [--height 900] [--with-chrome]
```

- `--width`
  Slide width in pixels. Default: `1440`
- `--height`
  Slide height in pixels. Default: `900`
- `--with-chrome`
  Add exporter-provided page counter and nav dots

### Validation Workflow

```bash
python3 -m py_compile scripts/export-sandbox-pptx.py scripts/test-export.py scripts/rigorous-eval.py
python3 scripts/test-export.py
python3 scripts/export-sandbox-pptx.py demo/blue-sky-zh.html demo/output.pptx
python3 scripts/rigorous-eval.py
```

### v1.6.9 Highlights (patch / refactor for reuse)

- Promoted the hairline-height policy from `_build_swiss_index_list_rows()` into two general-purpose helpers:
  - `_hairline_height_in(border_w_px)`: halves 1-2px CSS borders (with a 0.5px floor) and passes 3px+ through unchanged
  - `_build_css_hairline_shape(border_value, x, y, w, fallback_color)`: builds a decoration shape from a CSS `border` shorthand, skipping `none`/zero-width
- Refactored `_build_swiss_index_list_rows` to use the helper (~25 lines → ~10 lines, identical behavior)
- Any future builder facing "PPTX renders my 1px CSS border too thick" can now reuse this directly
- Two new regression tests cover both helpers
- `Swiss Modern` `9.04` and `Aurora Mesh` `9.01` unchanged from v1.6.8 (refactor preserves behavior)

### v1.6.8 Highlights (patch / user-reported fixes)

Four user-reported visual defects fixed:

- **K1 KPI label vertical mismatch**: `_measure_compact_flex_child_width_in()` now adds a `+0.05"` safety margin and uses looser glyph multipliers (latin `0.55→0.62`, cjk `0.96→1.0`) so a borderline two-character numeric like "21" no longer trips the PPTX wrap engine into 2 lines. P1 labels now share `y=8.183`.
- **K2 P4 divider too thick**: `.index-item border-bottom` shapes use `~0.5px` equivalent height (`max(border_w * 0.5, 0.5px)`) so the divider reads closer to the source CSS hairline.
- **K3 P5 white text on white cell**: `export_table_element` now promotes a single inline-block bg span's background up to the cell, so `<td><span class="terminal-line">cmd</span></td>` renders as a dark cell with legible white text.
- **K4 P8 KPI centered instead of left-aligned**: extended swiss `title_grid` canonical to accept `.cta-inner` (was falling to fallback path that center-fitted compact-width containers); switched `_pack_relative_block_container` to per-item x-normalization so flex-row containers (`x=0`) and inline spans (`x=0.5`) within the same packed flow no longer end up at mismatched origins.
- Cross-deck side effect: data-story `centered wrapper` test threshold relaxed `>=6.9 → >=6.4"` (matches source `max-width: 700px ≈ 6.48"`).
- `Swiss Modern` canonical: `9.07 → 9.04` (per-cell black bg match drives a small SSIM dip but visibility fix takes priority); `Aurora Mesh` `9.00 → 9.01`.

### v1.6.7 Highlights (patch / contract sync)

- Extended `scripts/sync-slide-creator-contracts.py` with the four new `swiss-modern` layout roles introduced this session: `inner_panel / index_list / inst_blocks / disc_layout`. The next contract sync will preserve these vendored roles instead of overwriting them.
- No runtime code changes; protocol-level catch-up only.
- `Swiss Modern` canonical stays at `9.07/10`; `Aurora Mesh` unchanged at `9.00/10`.

### v1.6.6 Highlights (patch)

- New `disc_layout` layout role for `.disc-header + .disc-body` slides (Swiss Slide 3). `_build_swiss_disc_layout` handles the top title block plus a bottom two-column row: left `.disc-steps` numbered list + right `.disc-diagram` SVG illustration
- New `_build_swiss_disc_steps` helper: each `.disc-step` stacks vertically with the number column at its `min-width` and the content column taking the rest, instead of spreading the three steps horizontally across the slide
- The `.diagram-svg` SVG now renders through `build_svg_container` as a relative container, so its rect/line/text descendants stay anchored inside the SVG bounds (was rendering at `x=17-22"`, fully off-slide)
- Before: 01/02/03 numbers drifted horizontally to `x=0.5 / 6.27 / 13.55"`. After: all aligned at `x=0.667"` stacked vertically
- New regression test: `test_swiss_disc_steps_stack_vertically_with_left_number_column`
- `Swiss Modern` canonical: Slide 03 stays at `9.3/10` (structure dramatically improved but SSIM is at the cross-renderer cap); overall stays at `9.07/10`
- `Aurora Mesh` visual compare unchanged at `9.00/10` (SVG decorative classifier untouched)

### v1.6.5 Highlights (patch)

- New `index_list` layout role for `.sol-inner` slides (Swiss Slide 4). `_build_swiss_index_list_rows` makes every `.index-item` claim the full row: a fixed-width number column from `min-width` plus a content column that consumes the rest, baseline-anchored by font-size delta
- New `inst_blocks` layout role for `.inst-inner` slides (Swiss Slide 7). `_build_swiss_inst_block_card` renders the left border accent + label + `.terminal-line` dark pill (paired bg shape + text overlay) instead of folding the inline-block span into the parent text
- New `_build_swiss_terminal_line` helper: promotes `display:inline-block + background` spans into paired bg shape + text overlay, preserving the authored pill padding
- Two new regression tests for the new builders
- `Swiss Modern` canonical: Slide 04 `8.9 → 9.2` (+0.3); Slide 07 `9.1 → 8.9` (-0.2, structure matches source but cross-renderer SSIM dips); overall `9.06 → 9.07`
- `Aurora Mesh` visual compare unchanged at `9.00/10`

### v1.6.4 Highlights (patch)

- `build_grid_children` now detects compact flex-row intent (`gap` + non-distributing `justify-content`) and packs children at their intrinsic content width instead of forcing an even split across the row. Fixes the `.hero-stats` KPI block on Swiss Slides 1 / 8 (P1 horizontal span `8.7" → 1.8"`)
- `_build_swiss_column_content` post-pack stretches block-level headings / paragraphs in column panels to the full inner panel width, so authored `<br>` line breaks survive instead of getting wrapped into orphan half-rows (P2 title `2.08" → 4.03"`, height taken over by `spAutoFit` to produce two clean lines)
- Three new regression tests: `test_compact_flex_row_packs_stat_blocks_at_intrinsic_width`, `test_compact_flex_row_falls_back_to_even_split_when_oversized`, `test_stretch_column_block_text_to_inner_width_expands_narrow_heading`
- `Swiss Modern` canonical snapshot stays at `9.06/10` overall (cross-renderer SSIM is near the empirical cap), but the structure now matches the authored CSS intent
- `Aurora Mesh` visual compare unchanged at `9.00/10`

### v1.6.3 Highlights (patch)

- `_build_swiss_column_content` right column now mirrors the left column's vertical centering (previously hard-coded `right_y = 0` on canonical tier)
- `_build_swiss_title_grid` resolves `justify-content` from the inner panel first (e.g. `.flow-inner { justify-content: center }`) before falling back to slide root
- `Swiss Modern` canonical snapshot: Slide 05 `8.6 → 9.0`, Slide 06 `8.9 → 9.0`, overall `9.00 → 9.06`
- `Aurora Mesh` visual compare unchanged at `9.00/10`

### v1.6.2 Highlights (patch)

- Excluded `noto sans` from [REDACTED_SECRET]'s trigger so the 1.30x optical boost no longer overshoots and force-wraps Swiss headings when CJK fallback resolves to Helvetica Neue + Hiragino Sans GB
- Added `inner_panel` layout role for single-panel Swiss slides without `.bg-num` decoration (Slide 5 `flow-inner`, Slide 6 `feat-inner`)
- Pinned `_FONT_MAP` for Archivo / Nunito / Noto Sans SC to the cross-renderer Helvetica Neue + Hiragino Sans GB pair
- Compare harness strips web-font dependencies before screenshotting so SSIM reflects layout fidelity rather than cross-renderer font-rasterization
- `Swiss Modern` canonical visual snapshot: overall `8.93 → 9.00`; Slide 03/04/05/07 each `+0.1`
- `Aurora Mesh` visual compare unchanged at `9.00/10`

### Known Gap

- `≥ 9.5/slide` is not reachable under the current SSIM cross-renderer gate. Single-page SSIM is empirically capped around `0.92` (best `0.9227`, score `9.34`). Reaching `9.5+` would require switching to a structural eval gate or a shared-renderer compare loop, not more layout tuning.

### v1.6.1 Highlights (patch)

- Fixed `_pack_direct_child_content` so absolute/fixed children no longer pollute the panel's measured content width
- Added `_build_absolute_decoration_strips` to harvest Swiss `column_content` decoration strips with their authored CSS dimensions (`width / left / right / top / bottom`)
- `Swiss Modern` canonical visual snapshot: Slide 02 `8.7 → 9.3`, overall `8.85 → 8.93`
- `Aurora Mesh` visual compare unchanged at `9.00/10`
- Full regression suite passes with `python3 scripts/test-export.py`

### v1.6.0 Highlights

- Restructured the export pipeline into explicit, contract-bound stages (`analyze → profile → slide plan → geometry plan → render`):
  - new `analyze_source` stage emits raw signal bundles before any rendering decision is made
  - new profile stage tightens style-profile semantics (preset attribution + tier precedence) and requires local contract evidence
  - new `slide planning` layer isolates per-slide plan state so planning side effects do not leak into geometry decisions
  - new `pptx geometry planning` stage owns layout decisions and ships a strengthened stage contract
  - `render` is now a pure consumer of geometry plans and no longer recomputes layout
- Refreshed vendored `slide-creator` presets; lifted `slide root discovery` into a reusable helper that handles generic section decks
- `Aurora Mesh` visual compare snapshot at `9.00/10`:
  - replaced the previous near-black fallback with an atmospheric solid-color approximation derived from the authored aurora mesh layers
  - kept Aurora KPI tracks compact by default, but still honor explicit authored stretch signals
  - preserved Aurora wrapper-centered layout and install-card structure with `overflow = 0` and `overlap = 0`
- Full regression suite passes with `python3 scripts/test-export.py`

### Known Gaps

- The exporter still does not fully match the native golden deck
- `Swiss Modern` is still a `canonical + constrained compatible` path, not a generic Swiss-like HTML fidelity engine
- Remaining lower-score areas are concentrated in:
  - canonical Swiss optical rhythm on some title/split pages
  - minor title scale / page-center drift on selected layouts
  - local office-render compare limitations on this machine

See [RELEASE.md](./RELEASE.md) for release notes.


path: RELEASE.md
content: # Release Notes

## v1.6.9 - 2026-04-30

Refactor: promote v1.6.8's hairline-divider policy from `_build_swiss_index_list_rows()` into two general-purpose helpers so other builders / decks can reuse them whenever a CSS hairline border needs to render close to its source weight in PPTX.

### Highlights

- New `_hairline_height_in(border_w_px)`: PPTX renders any solid-fill rectangle at minimum 1 device pixel, so a 1px CSS hairline emitted directly reads thicker than the source. The helper halves 1-2px source borders (with a 0.5px floor) so the rendered visual approximates the antialiased browser hairline; 3px+ borders pass through unchanged.
- New `_build_css_hairline_shape(border_value, x, y, w, fallback_color)`: accepts a CSS `border` shorthand string (e.g. `"1px solid #e5e5e5"`) and returns a `_is_decoration` / `layoutDone` shape sized via `_hairline_height_in()`. Returns `None` for `none` / empty / zero-width inputs.
- `_build_swiss_index_list_rows()` now consumes the helper (~25 lines → ~10 lines, identical observable behavior).
- Two new regression tests in `scripts/test-export.py` cover the height policy and the CSS-shorthand parsing.
- `Swiss Modern` `9.04/10` and `Aurora Mesh` `9.01/10` unchanged from v1.6.8 (refactor preserves behavior).

### Validation Snapshot

```bash
python3 -m py_compile scripts/export-sandbox-pptx.py scripts/test-export.py
python3 scripts/test-export.py
python3 scripts/export-sandbox-pptx.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx --outdir demo/swiss-canonical-zh-visual-compare
python3 scripts/export-sandbox-pptx.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx --outdir demo/aurora-mesh-zh-visual-compare
```

## v1.6.8 - 2026-04-30

User-reported visual defects across `Swiss Modern`. Four targeted fixes:

- **K1**: P1 `.hero-stats` first column had a 0.925" gap from number to label while columns 2/3 had 0.481" — the borderline width measurement for "21" tripped the PPTX wrap engine into 2 lines, lifting the label down. Loosened the glyph-multiplier (`latin 0.55→0.62`, `cjk 0.96→1.0`) and added a `+0.05"` safety margin in `_measure_compact_flex_child_width_in()`. All three labels now share `y=8.183`.
- **K2**: P4 `.index-item` border-bottom dividers rendered too thick. PPTX renders any solid-fill rectangle at minimum 1 device pixel, so a 1px CSS hairline reads visually thicker than the source. Use `max(border_w * 0.5, 0.5px)` for hairline dividers in `_build_swiss_index_list_rows`.
- **K3**: P5 `<td><span class="terminal-line">cmd</span></td>` renders as white-on-white. `export_table_element` now promotes a single inline-block bg span's background color up to the cell, so the dark pill becomes the cell fill and the white run text stays legible.
- **K4**: P8 `.cta-echo` KPI strip was horizontally centered (x=5.586") instead of left-aligned with the content column. Two fixes:
  1. `swiss-modern` `title_grid` canonical now accepts `.cta-inner` (was falling through to the generic fallback path that center-fitted compact-width children).
  2. `_pack_relative_block_container` changed from a single global `min_x` shift to a per-item `min_x` shift, since flex-row containers (`x=0`) and inline spans (`x=0.5`) emit inconsistent local origins. Per-item normalization keeps every packed item starting at `x=0` within its parent.

Cross-deck side effect: the `data-story` `centered wrapper` regression test threshold relaxed from `>=6.9 → >=6.4"` (matches source `max-width: 700px ≈ 6.48"` more accurately).

四条用户反馈缺陷一并修复：P1 KPI 第一列 label 高位异常、P4 索引列表分割线太粗、P5 表格内黑底胶囊白字看不见、P8 收尾 KPI 误居中。同时把 `_pack_relative_block_container` 的 `min_x` 归一化从 global 改为 per-item，避免 flex-row 容器与 inline span 在同一 packed flow 中出现不一致的 local origin。

### Visual snapshot

- `Swiss Modern` canonical: `9.07 → 9.04` overall (P5 cell-bg match drives a small SSIM dip — visibility takes priority over pixel-exact source match)
- `Aurora Mesh` regression: `9.00 → 9.01` (slight improvement from per-item normalization)
- `python3 scripts/test-export.py` 全绿（含已更新的 wrapper-width 阈值）

### Validation Snapshot

```bash
python3 -m py_compile scripts/export-sandbox-pptx.py scripts/test-export.py
python3 scripts/test-export.py
python3 scripts/export-sandbox-pptx.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx --outdir demo/swiss-canonical-zh-visual-compare
python3 scripts/export-sandbox-pptx.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx --outdir demo/aurora-mesh-zh-visual-compare
```

## v1.6.7 - 2026-04-30

This patch is a contract-sync catch-up. v1.6.4 / v1.6.5 / v1.6.6 added four new `swiss-modern` layout roles (`inner_panel`, `index_list`, `inst_blocks`, `disc_layout`) directly to the vendored contract under `contracts/slide_creator/presets/swiss-modern.json`, but the upstream-sync script in `scripts/sync-slide-creator-contracts.py` was unaware of them. Without this patch, the next sync would silently revert the vendored contract to the old four-role schema and break the Swiss Modern Slide 3 / 4 / 5 / 6 / 7 builders.

本次补丁是契约同步补齐。v1.6.4/1.6.5/1.6.6 直接给 vendored 契约 `contracts/slide_creator/presets/swiss-modern.json` 加了 4 个新 layout role（`inner_panel / index_list / inst_blocks / disc_layout`），但 `scripts/sync-slide-creator-contracts.py` 的同步脚本不认识它们。如果不打这个 patch，下次同步会把 vendored 契约静默回退到旧四角色 schema，Swiss Modern 的 Slide 3/4/5/6/7 builder 会被破坏。

### Highlights

- `scripts/sync-slide-creator-contracts.py` `swiss-modern.layout_variations` and `swiss-modern.layout_contracts` extended to include `inner_panel`, `index_list`, `inst_blocks`, `disc_layout`.
- No runtime code changes; vendored contract and exporter logic untouched.
- Swiss Modern canonical visual compare remains at `9.07/10`; Aurora Mesh unchanged at `9.00/10`.

### Validation Snapshot

```bash
python3 -m py_compile scripts/sync-slide-creator-contracts.py
python3 scripts/test-export.py
python3 scripts/export-sandbox-pptx.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx --outdir demo/swiss-canonical-zh-visual-compare
python3 scripts/export-sandbox-pptx.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx --outdir demo/aurora-mesh-zh-visual-compare
```

## v1.6.6 - 2026-04-30

This patch lands a dedicated `disc_layout` builder for the `Swiss Modern` Slide 3 ("discovery / geometric diagram"). The fallback path was spreading the three numbered steps horizontally across the slide and pushing the SVG diagram off-screen entirely; the new builder stacks the steps as a left-aligned vertical list and anchors the SVG inside the right-hand column.

本次补丁为 `Swiss Modern` 的 Slide 3（"discovery / 几何图示"）增加专用 `disc_layout` builder。fallback 路径之前把三个编号步骤横向铺到屏外（最后一个在 x=13.55"），并把 SVG 图示推到 x=17-22"（完全不在画布内）。新 builder 把步骤改为左对齐的纵向列表，并把 SVG 钉在右栏内部。

### Highlights

- New `disc_layout` layout role + `_build_swiss_disc_layout` / `_build_swiss_disc_steps` builders for `.disc-header + .disc-body` slides. The header (eyebrow / h2 / rule) packs at the authored top padding, and the body splits into a left `.disc-steps` column and a right `.disc-diagram` column.
- `_build_swiss_disc_steps` lays out each `.disc-step` as a baseline-anchored row: number column at its `min-width`, content column (title + paragraph) takes the rest. The three steps now stack vertically instead of being spread across the row.
- `.diagram-svg` is rendered through the existing `build_svg_container`, returning a relative container whose rect/line/text descendants stay inside the SVG bounds. Decorative-SVG classification is unchanged, so `Aurora Mesh` (which relies on the existing decorative filter) is not affected.
- One new regression test covers the disc_steps stacking + left-number column.

### Geometry deltas (Swiss Modern Slide 3)

| Element | Before | After |
| --- | --- | --- |
| `.disc-step` `01` x | `0.50"` | `0.667"` (with header) |
| `.disc-step` `02` x | `6.27"` (drifted right) | `0.667"` (vertically stacked) |
| `.disc-step` `03` x | `13.55"` (off-slide) | `0.667"` (vertically stacked) |
| `.diagram-svg` rect/line/text x | `17-22"` (fully off-slide) | `9.7-12.5"` (in right column) |

### Visual snapshot

- `Swiss Modern` canonical: Slide 03 stays at `9.3/10` (the structure is dramatically more correct, but per-page SSIM is already near the cross-renderer cap so the score doesn't move); overall stays at `9.07/10`
- `Aurora Mesh` regression unchanged at `9.00/10`

### Validation Snapshot

```bash
python3 -m py_compile scripts/export-sandbox-pptx.py scripts/test-export.py
python3 scripts/test-export.py
python3 scripts/export-sandbox-pptx.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx --outdir demo/swiss-canonical-zh-visual-compare
python3 scripts/export-sandbox-pptx.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx --outdir demo/aurora-mesh-zh-visual-compare
```

## v1.6.5 - 2026-04-30

This patch lands two new dedicated `Swiss Modern` builders to close the structural mismatches on Slide 4 (`.sol-inner` index list) and Slide 7 (`.inst-inner` install blocks). Slide 4's `.sol-list` now stretches every row to the full content width with a fixed left-aligned number column, and Slide 7's `.terminal-line` inline-block spans render as proper dark pills (paired background shape + text overlay) instead of being folded into the parent text.

本次补丁为 `Swiss Modern` 增加两个专用 builder，修掉 Slide 4（`.sol-inner` 索引列表）和 Slide 7（`.inst-inner` 安装块）的结构性偏差：Slide 4 的 `.sol-list` 现在每行撑满内容宽度，数字列左对齐固定宽，内容列拿剩余宽度；Slide 7 的 `.terminal-line` inline-block span 渲染为真正的深色胶囊（paired 背景 shape + 文字 overlay），不再被折进父级文本。

### Highlights

- New `index_list` layout role + `_build_swiss_index_list` / `_build_swiss_index_list_rows` builders for `.sol-inner` slides. Each `.index-item` row stretches to inner panel width; the `.index-num` span sits at the left at its `min-width`, the content `<div>` takes the remaining width, and the two are baseline-anchored by font-size delta.
- New `inst_blocks` layout role + `_build_swiss_inst_blocks` / `_build_swiss_inst_block_card` / `_build_swiss_terminal_line` builders for `.inst-inner` slides. Each `.inst-block` keeps its left-border accent, stacks label above the command pill, and renders `.terminal-line` as a paired dark bg shape + overlaid text instead of merging the span into the label text.
- `_build_swiss_terminal_line` is reusable: any `display:inline-block + background` span can be upgraded into a paired pill while preserving CSS padding.
- Two new regression tests cover both builders.

### Geometry deltas (Swiss Modern)

| Slide | Element | Before | After |
| --- | --- | --- | --- |
| 4 | `.index-num` `01` x | `5.175"` (centered) | `0.667"` (left-aligned) |
| 4 | content column width | `1.74"` | `11.28"` (full row) |
| 7 | `.inst-block` block 1 left edge | `3.20"` (centered) | `0.67"` (left-aligned) |
| 7 | `.terminal-line` rendered as | concatenated text | dark pill bg + text overlay |

### Visual snapshot

- `Swiss Modern` canonical: Slide 04 `8.9 → 9.2` (+0.3); Slide 07 `9.1 → 8.9` (-0.2, structural fix lowers cross-renderer SSIM slightly); overall `9.06 → 9.07`
- `Aurora Mesh` regression unchanged at `9.00/10`

### Validation Snapshot

```bash
python3 -m py_compile scripts/export-sandbox-pptx.py scripts/test-export.py
python3 scripts/test-export.py
python3 scripts/export-sandbox-pptx.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx --outdir demo/swiss-canonical-zh-visual-compare
python3 scripts/export-sandbox-pptx.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx --outdir demo/aurora-mesh-zh-visual-compare
```

## v1.6.4 - 2026-04-30

This patch closes two structural mismatches between source CSS and the exporter on `Swiss Modern`: `.hero-stats` KPI rows on Slide 1 / 8 were being spread evenly across the full slide width instead of packed at the authored `gap` distance, and the Slide 2 left-panel heading was shrink-wrapping to its natural text width and then re-wrapping each authored `<br>` line into orphan half-rows.

本次补丁修复了 `Swiss Modern` 上两类源 CSS 与导出器的结构性偏差：Slide 1 / 8 的 `.hero-stats` 行被错误地均匀分布到整个幻灯片宽度，而不是按源 CSS 的 `gap` 距离紧凑排布；Slide 2 左栏标题被 shrink-wrap 到自然文本宽度，导致每行 `<br>` 又被二次折成孤字。

### Highlights

- `build_grid_children` adds a compact-flex-row path: a flex row with explicit `gap` and a non-distributing `justify-content` packs each child at its intrinsic content width (`_measure_compact_flex_child_width_in()`) instead of dividing the remaining row width evenly. Falls back to the legacy even-split when intrinsic widths overflow the container.
- `_build_swiss_column_content` post-pack stretches block-level headings / paragraphs in column panels to the full inner panel width via `_stretch_column_block_text_to_inner_width()` so authored `<br>` line breaks render as the source intended.
- Aurora KPI cards keep going through the dedicated `_contract_vertical_card_prefers_stretch_width` path, so the `slide-creator/aurora-mesh` contract is not affected.
- Three new regression tests cover compact packing, the oversize fallback, and the column-text stretch behavior.

### Geometry deltas (Swiss Modern)

| Slide | Element | Before | After |
| --- | --- | --- | --- |
| 1 | `.hero-stats` `21 / 0 / 3` horizontal span | `8.7"` | `1.8"` |
| 8 | `/slide-creator` KPI row span | full row | `1.4"` |
| 2 | `.left-panel h2` width | `2.08"` (4 wrapped lines) | `4.03"` (2 clean lines via `spAutoFit`) |

### Visual snapshot

- `Swiss Modern` canonical overall stays at `9.06/10` — cross-renderer SSIM is already near its empirical cap (~`0.92` per page), so the structural fix is invisible to the score even though the layout now matches the source CSS intent
- `Aurora Mesh` regression unchanged at `9.00/10`

### Validation Snapshot

```bash
python3 -m py_compile scripts/export-sandbox-pptx.py scripts/test-export.py
python3 scripts/test-export.py
python3 scripts/export-sandbox-pptx.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx --outdir demo/swiss-canonical-zh-visual-compare
python3 scripts/export-sandbox-pptx.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx --outdir demo/aurora-mesh-zh-visual-compare
```

## v1.6.3 - 2026-04-29

This patch closes the canonical Swiss vertical-centering regression: right-side panels in `column_content` and inner-panel slides were stacking content against the top instead of honoring the authored `justify-content: center`.

本次补丁修复 canonical Swiss 垂直居中问题：`column_content` 右栏和 inner-panel 系列幻灯片之前把内容贴顶部，没尊重源 CSS 的 `justify-content: center`。

### Highlights

- `_build_swiss_column_content` right column now mirrors left-column vertical centering instead of forcing `right_y = 0` for canonical tier
- `_build_swiss_title_grid` resolves `justify-content` from the inner panel first (e.g. `.flow-inner { justify-content: center }`) before falling back to slide root
- `Swiss Modern` canonical visual snapshot: Slide 05 `8.6 → 9.0`, Slide 06 `8.9 → 9.0`, overall `9.00 → 9.06`
- `Aurora Mesh` regression unchanged at `9.00/10`

## v1.6.2 - 2026-04-29

This patch lifts `Swiss Modern` canonical visual fidelity from `8.93/10` to `9.00/10` and pulls Slide 03/04/05/06/07 each up by `+0.1`. Two real wins underneath: a `display heading` optical-boost trigger that was overshooting whenever `noto sans` appeared in the font stack, and a missing `inner_panel` layout role for slides that have a single content panel without a `.bg-num` decoration (e.g. Swiss Slide 5 `flow-inner` and Slide 6 `feat-inner`). The compare harness was also tightened so the SSIM score reflects layout fidelity rather than cross-renderer font-rasterization differences.

本次补丁把 `Swiss Modern` canonical 视觉保真从 `8.93/10` 提到 `9.00/10`，Slide 03/04/05/06/07 各 `+0.1`。两个真实根因：`display heading` 视觉补偿当字体栈出现 `noto sans` 时会触发 1.30 倍超调；以及单内容面板（无 `.bg-num` 装饰）的幻灯片缺少 `inner_panel` layout role 导致走 fallback。同时加固对比脚本，使 SSIM 反映 layout 一致性而非跨渲染器字体差异。

### Highlights

- Excluded `noto sans` from [REDACTED_SECRET]'s trigger set — when Noto Sans SC is remapped to the cross-renderer stable Helvetica Neue + Hiragino Sans GB pair, both Latin and CJK glyphs render at the authored size and the 1.30x boost overshoots and force-wraps headings
- Added `inner_panel` layout role to `swiss-modern` contract and routed it through the existing `_build_swiss_title_grid` builder; widened title_grid's accepted inner selectors to `.hero-inner / .flow-inner / .feat-inner`
- Pinned `_FONT_MAP` for Archivo / Nunito / Noto Sans SC families to the cross-renderer Helvetica Neue + Hiragino Sans GB pair, and updated the existing `Swiss display stack` font-mapping test to match the new contract
- Compare harness now strips web-font dependencies via an injected `*  { font-family: 'Helvetica Neue', 'Hiragino Sans GB', sans-serif !important }` style tag before screenshotting, so SSIM reflects layout fidelity rather than cross-renderer font-rasterization
- `Swiss Modern` canonical visual snapshot:
  - Overall `8.93 → 9.00`
  - Slide 02 `9.3` (best, ssim `0.9189`)
  - Slide 03 `9.2 → 9.3`
  - Slide 04 `8.8 → 8.9`
  - Slide 05 `8.5 → 8.6`
  - Slide 07 `9.0 → 9.1`
- `Aurora Mesh` regression unchanged at `9.00/10`
- Full regression suite still passes: `python3 scripts/test-export.py`

### Validation Snapshot

```bash
python3 -m py_compile scripts/export-sandbox-pptx.py scripts/test-export.py scripts/sync-slide-creator-contracts.py
python3 scripts/test-export.py
python3 scripts/export-sandbox-pptx.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx --outdir demo/swiss-canonical-zh-visual-compare
python3 scripts/export-sandbox-pptx.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx --outdir demo/aurora-mesh-zh-visual-compare
```

Result:

- Full regression suite: `All tests passed!`
- `Swiss Modern` canonical fixture (`demo/swiss-canonical-zh.html`): overall `9.00/10`
- `Aurora Mesh`: overall `9.00/10` (unchanged)

### Known Gap

- `≥ 9.5/slide` for canonical Swiss is not reachable under the current SSIM-based cross-renderer compare gate. After empirically exhausting layout, font-mapping, system-font, and font-neutralized-comparison angles, single-page SSIM remained capped around `0.92` (best `0.9227`). Reaching `9.5+` would require either a structural eval gate (akin to `handwritten fixture structural eval gate`) or a shared-renderer comparison loop, not further layout tuning.

## v1.6.1 - 2026-04-29

This patch fixes a real `Swiss Modern` `column_content` rendering bug surfaced while pushing canonical Swiss fidelity: an absolute-positioned decoration strip (e.g. `.red-bar`) was inheriting the panel's full content width, both blowing up the strip itself and polluting the parent container's measured width.

本次补丁修掉一条 `Swiss Modern` `column_content` 真实渲染 bug：在推进 canonical Swiss 视觉保真过程中暴露出，绝对定位的装饰条（例如 `.red-bar`）会继承面板的全部内容宽度，既把装饰条本身放大，也污染了父容器的测量宽度。

### Highlights

- Fixed `_pack_direct_child_content` to skip absolute/fixed children so they no longer pollute the panel's measured content width
- Added `_build_absolute_decoration_strips` to harvest absolute decoration strips inside Swiss `column_content` panels and render them with their authored CSS dimensions (`width / left / right / top / bottom`)
- `Swiss Modern` canonical visual snapshot:
  - Slide 02 `8.7 → 9.3` (`+0.6`)
  - Overall `8.85 → 8.93`
- `Aurora Mesh` regression unchanged at `9.00/10`
- Full regression suite still passes: `python3 scripts/test-export.py`

### Validation Snapshot

Validated with:

```bash
python3 -m py_compile scripts/export-sandbox-pptx.py scripts/test-export.py scripts/sync-slide-creator-contracts.py
python3 scripts/test-export.py
python3 scripts/export-sandbox-pptx.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/swiss-canonical-zh.html demo/swiss-canonical-zh.pptx --outdir demo/swiss-canonical-zh-visual-compare
python3 scripts/export-sandbox-pptx.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx --outdir demo/aurora-mesh-zh-visual-compare
```

Result:

- Full regression suite: `All tests passed!`
- `Swiss Modern` canonical fixture (`demo/swiss-canonical-zh.html`): overall `8.93/10`, slide 02 `9.3/10`
- `Aurora Mesh`: overall `9.00/10` (unchanged)

## v1.6.0 - 2026-04-28

This release has two main bodies of work. First, the export pipeline is restructured into explicit, contract-bound stages (`analyze → profile → slide plan → geometry plan → render`), so each stage is independently testable and the runtime stops mixing extraction, planning, and rendering on a single pass. Second, `Aurora Mesh` finishes its current optimization pass and reaches a real `9.00/10` visual compare snapshot.

本次发布有两条主线工作。第一，导出管线被重构成显式的多段合同（`analyze → profile → slide plan → geometry plan → render`），每一段都能独立测试，运行时不再把抽取、规划和渲染混在一遍流程里。第二，`Aurora Mesh` 完成本轮优化，真实视觉对比快照达到 `9.00/10`。

### Highlights

Staged export pipeline:

- New `analyze_source` stage emits raw signal bundles before any rendering decision is made
- New profile stage tightens style-profile semantics (preset attribution + tier precedence) so contract evidence has to be local
- New `slide planning` layer isolates per-slide plan state and keeps planning side effects out of geometry decisions
- New `pptx geometry planning` stage owns layout decisions and ships a strengthened stage contract
- `render` is now a pure consumer of geometry plans; it no longer recomputes layout
- Vendored `slide-creator` presets refreshed and shared `slide root discovery` lifted to a reusable helper for generic section decks

`Aurora Mesh` fidelity:

- `Aurora Mesh` visual compare snapshot: `9.00/10`
- Replaced the previous near-black fallback with an atmospheric solid-color approximation derived from the authored aurora mesh layers
- Kept Aurora KPI tracks compact by default, but still honor explicit authored stretch signals from source CSS
- Preserved Aurora wrapper-centered layout and install-card structure while keeping:
  - `overflow = 0`
  - `overlap = 0`
- Expanded Aurora regression coverage for:
  - mesh-background fallback behavior
  - compact-vs-stretch KPI width decisions
  - wrapper centering
  - install-card separation

### Validation Snapshot

Validated with:

```bash
python3 -m py_compile scripts/export-sandbox-pptx.py scripts/test-export.py scripts/sync-slide-creator-contracts.py
python3 scripts/test-export.py
python3 scripts/export-sandbox-pptx.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx
python3 scripts/compare-html-ppt-visual.py demo/aurora-mesh-zh.html demo/aurora-mesh-zh.pptx --outdir demo/aurora-mesh-zh-visual-compare
```

Result:

- Full regression suite: `All tests passed!`
- `Aurora Mesh` structured checks:
  - `overflow = 0`
  - `overlap = 0`
- `Aurora Mesh` visual compare:
  - overall `9.00/10`
  - Slide 01 `9.1/10`
  - Slide 04 `9.2/10`
  - Slide 05 `8.9/10`
  - Slide 06 `8.8/10`
  - Slide 08 `8.9/10`

## v1.5.1 - 2026-04-25

This release tightens the exporter's skill/runtime execution boundary and closes two real regressions found while rerunning the full suite. The shipped work makes the single-file exporter the correctness boundary for hosted sandboxes, while still keeping an optional bootstrap path for richer environments.

本次版本重点是收紧 exporter 的 skill/runtime 执行边界，并修掉两条在完整回归中暴露出来的真实问题。核心原则变成：单文件主导出器就是 hosted sandbox 的 correctness boundary；环境更丰富时仍可使用可选 bootstrap，但不再把它当作前提假设。

### Highlights

- Version bump to `v1.5.1`
- Hardened sandbox execution behavior:
  - tolerate missing `__file__`
  - probe repo/contracts paths opportunistically and degrade cleanly when absent
  - attempt runtime dependency bootstrap before failing hard
- Added optional hosted-sandbox bootstrap surfaces:
  - `scripts/run-skill-export.py`
  - `requirements.txt`
  - updated `SKILL.md` execution protocol
- Fixed two regressions discovered while rerunning the full suite:
  - Enterprise Dark split-right-rail test was selecting the wrong container
  - Chinese Chan closing title was incorrectly exported with `wrap="none"` instead of preserving wrapped width rhythm
- Regression coverage expanded with:
  - medium contract title wrap guard
  - retained single-line contract title no-wrap guard
  - full `Chinese Chan` roundtrip wrap fidelity

### Validation Snapshot

Validated with:

```bash
python3 -m py_compile scripts/export-sandbox-pptx.py scripts/run-skill-export.py scripts/test-export.py
python3 scripts/test-export.py
```

Result:

- Full regression suite: `All tests passed!`
- Verified regressions:
  - Enterprise Dark split cards stack in the correct right rail
  - Chinese Chan closing title keeps `wrap="square"`
  - single-line large contract titles still keep `no-wrap` where intended

## v1.5.0 - 2026-04-25

This release moves `Swiss Modern` from “recognized preset metadata” to a real contract-driven export path. The shipped work includes synced Swiss contracts, runtime role-aware layout builders, and text reflow fixes that close real regressions on the `kingdee` sample deck.

本次版本把 `Swiss Modern` 从“能识别 preset metadata”推进到“真正走 contract-driven 导出路径”。核心交付包括：同步后的 Swiss contract、运行时 role-aware layout builder，以及修掉 `kingdee` 样本里真实出现的文字回流问题。

### Highlights

- Version bump to `v1.5.0`
- Expanded vendored `Swiss Modern` contract:
  - `support_tiers`
  - `layout_contracts`
  - `signature_elements`
  - typography and line-break contract
- Export runtime now consumes Swiss component semantics for:
  - `title_grid`
  - `column_content`
  - `stat_block`
  - `pull_quote`
- Text fidelity tightened again:
  - wide measured prose no longer falls back into accidental no-wrap fit
  - single-line contract titles keep `no-wrap` when authored width already fits
  - P3 / P5 wrap behavior is verified from roundtrip PPTX XML, not just visual preview
- Regression coverage expanded for:
  - Swiss contract sync
  - compatible wrapper unwrap
  - wide multiline prose wrap
  - single-line title no-wrap guard

### Validation Snapshot

Validated with:

```bash
python3 -m py_compile scripts/export-sandbox-pptx.py scripts/test-export.py
python3 -B -m pytest scripts/test-export.py -q -k "long_editorial_prose_skips_no_wrap_fit or single_line_contract_title_stays_no_wrap or wide_multiline_prose_wraps_from_measured_height or swiss or prefer_wrap_to_preserve_size_for_body_prose or centered_subtitle_prefers_full_max_width_and_no_wrap_fit or wide_prose_adjusts_back_to_single_line or medium_card_prose_adjusts_back_to_single_line"
python3 scripts/export-sandbox-pptx.py "/Users/song/Downloads/kingdee_stock_presentation (1).html" /tmp/kingdee_from_original_v7.pptx
python3 scripts/export-sandbox-pptx.py /Users/song/Downloads/kingdee_stock_presentation_swiss_canonical.html /tmp/kingdee_swiss_canonical_v7.pptx
python3 scripts/compare-html-ppt-visual.py "/Users/song/Downloads/kingdee_stock_presentation (1).html" /tmp/kingdee_from_original_v7.pptx --outdir /tmp/kingdee_exporter_only_compare_v7
python3 scripts/compare-html-ppt-visual.py /Users/song/Downloads/kingdee_stock_presentation_swiss_canonical.html /tmp/kingdee_swiss_canonical_v7.pptx --outdir /tmp/kingdee_canonical_compare_v7
```

Result:

- Targeted regression suite: `16 passed`
- Original `kingdee` compare:
  - overall `9.36/10`
  - Slide 03 `9.3/10`
  - Slide 05 `9.5/10`
- Canonical Swiss compare:
  - overall `9.18/10`
  - Slide 03 `9.2/10`
  - Slide 05 `9.4/10`
- File-level XML checks:
  - original `P3 body wrap = square`
  - original `P5 title wrap = none`
  - canonical `P5 title wrap = none`

### Known Gaps

This release materially improves `Swiss Modern`, but it still does not meet the broader goal of every supported style scoring `>= 9.5` on every slide.

Current concentration areas remain:

- canonical Swiss optical rhythm on `title_grid / column_content`
- remaining title scale and page-center drift on selected layouts
- local office-render compare tooling is still not the ideal final visual oracle
- arbitrary third-party Swiss-like HTML is still outside the guaranteed fidelity path


## v1.4.0 - 2026-04-24

This release pushes the exporter beyond generic geometry fixes and into preset-aware text fidelity. The main shipped work is the `Chinese Chan` path: vendored preset contract, serif typography enforcement, authored line-break preservation, shared runtime chrome fallback, and closing-slide fidelity checks.

本次版本把优化重点从“通用几何近似”继续推进到“preset-aware 排版 fidelity”。核心交付是 `Chinese Chan` 这条路径：vendored preset contract、serif 字体契约、显式换行保真、shared runtime chrome fallback，以及结尾页的结构 fidelity 检查。

### Highlights

- Version bump to `v1.4.0`
- Added vendored `Chinese Chan` contract:
  - `contracts/slide_creator/presets/chinese-chan.json`
- Expanded runtime preset enforcement:
  - mixed-script serif font mapping
  - `preserveAuthoredBreaks`
  - `preferWrapToPreserveSize`
  - wrap-before-shrink behavior for constrained prose
- Shared `slide-creator` runtime chrome fallback now covers presets without a vendored contract
- Closing-slide fidelity checks now include:
  - seal border preservation
  - no-shadow border-shell rendering
  - centered command-row alignment relative to the authored content column
- Regression coverage expanded with roundtrip XML checks for:
  - wrap/auto-size fidelity
  - authored column-width preservation
  - no page overflow
  - seal border and centered command fidelity

### Validation Snapshot

Validated with:

```bash
python3 scripts/test-export.py
python3 scripts/export-sandbox-pptx.py demo/chinese-chan-zh.html demo/chinese-chan-output.pptx
python3 scripts/rigorous-eval.py --sandbox demo/chinese-chan-output.pptx --golden demo/chinese-chan-output.pptx --skip-visual
```

Result:

- `All tests passed!`
- `Chinese Chan` structured eval:
  - `overflow = 0`
  - `overlap = 0`
  - `element gaps = 0`
  - `card containment = 0`
  - `total actionable = 0`

Current completed visual compare snapshot:

- `Chinese Chan`: `9.68/10`

### Known Gaps

This release materially improves preset-aware export quality, but the exporter still does not fully meet the broader goal of every supported style scoring `>= 9.5` on every slide.

Current concentration areas remain outside the shipped `Chinese Chan` path:

- `data-story` component geometry and optical rhythm
- `enterprise-dark` split/feature-card layout depth
- local visual-compare tooling still relies on a non-ideal office-render path on this machine


## v1.3.0 - 2026-04-24

This release turns the earlier `slide-creator` contract discussion into shipped repository infrastructure: sync script, vendored preset contracts, runtime contract loading, and the first contract-driven geometry tuning path for newer presets such as `data-story`.

本次版本把之前停留在设计阶段的 `slide-creator` contract 方案正式落地成仓库内基础设施：同步脚本、vendored preset contracts、运行时 contract 读取，以及面向 `data-story` 这类新 preset 的第一批 contract-driven 几何调优路径。

### Highlights

- Version bump to `v1.3.0`
- Added `scripts/sync-slide-creator-contracts.py`
- Added and expanded vendored preset contracts under `contracts/slide_creator/`
- Export runtime now consumes:
  - producer detection
  - export hints validation
  - preset contract loading
  - contract-backed tuning for newer `slide-creator` decks
- `data-story` path improved materially through:
  - contract-driven `metric_card` rebalance
  - centered wrapper and paired pill fixes
  - CJK-safe primary font mapping in PPT text runs
- Regression coverage expanded again for:
  - `data-story`
  - `enterprise-dark`
  - contract sync behavior
  - CJK font mapping and local-grid guards

### Validation Snapshot

Validated with:

```bash
python3 scripts/test-export.py
```

Result:

- `All tests passed!`

Additional current state snapshot:

- Trusted completed visual compare for `demo/data-story-zh.html`: `8.86/10`
- Structured self-check on latest exported `demo/data-story-output.pptx`:
  - `overflow = 5`
  - `overlap = 0`
  - `element gaps = 0`
  - `card containment = 0`
  - `total actionable = 5`

### Known Gaps

This release materially improves preset-aware export quality, but it still does not meet the final target of every slide scoring `>= 9.5`.

Current concentration areas:

- `data-story` Slide 6 feature-grid final writeout geometry
- residual component-level optical differences on `data-story` Slides 2 / 4 / 6 / 7
- visual compare pipeline still occasionally stalls before writing a fresh `summary.json`

## v1.2.0 - 2026-04-22

This release packages the current generalized exporter baseline, updates the GitHub-facing docs, and cleans up the repository surface so local working assets stop leaking into the published repo.

本次版本将当前通用化 exporter 基线正式收口，同时补齐 GitHub 首页文档，并清理仓库发布面，让本地工作资产不再混入公开仓库。

### Highlights

- Bilingual GitHub-facing `README.md`
- Version bump to `v1.2.0`
- Local-only working assets removed from the repository surface:
  - `docs/` is now treated as a local external-docs link
  - historical root output artifacts are no longer part of the repo
  - `demo/` remains local-only working input/output
- Exporter improvements retained in this release:
  - stronger `presentation_rows` column width handling on the generic table renderer path
  - extra runway for shortcut-heavy first columns
  - muted trailing-link color for centered closing command rows
  - stable centering for auto-margin divider shapes
- Regression coverage expanded with exporter corpus fixtures and presentation-row heuristics

### Validation Snapshot

Validated with:

```bash
python3 -m py_compile scripts/export-sandbox-pptx.py scripts/test-export.py scripts/rigorous-eval.py
python3 scripts/test-export.py
python3 scripts/export-sandbox-pptx.py demo/blue-sky-zh.html demo/output.pptx
python3 scripts/rigorous-eval.py
```

Latest verified result for `demo/blue-sky-zh.html`:

- Overall score: `9.1/10`
- `overflow = 0`
- `overlap = 0`
- `card containment = 0`
- `element gaps = 2`
- `total actionable = 2`

Per-slide snapshot:

- Slide 1: `9.2`
- Slide 2: `8.9`
- Slide 3: `9.7`
- Slide 4: `8.9`
- Slide 5: `9.0`
- Slide 6: `9.0`
- Slide 7: `9.4`
- Slide 8: `9.5`
- Slide 9: `9.1`
- Slide 10: `8.3`

### Known Gaps

This release improves the exporter materially, but it still does not hit the target of every slide scoring `>= 9.5`.

Remaining concentration areas:

- Slide 10 closing card geometry and paragraph model
- Smaller heading/icon ink differences on selected slides
- Residual card-height and rhythm drift in a few layouts

### Compatibility

- No browser runtime required
- CLI entrypoint remains:

```bash
python3 scripts/export-sandbox-pptx.py <presentation.html> [demo/output.pptx]
```

## v1.1.0 - 2026-04-22

This release turned `kai-export-ppt-lite` from a one-deck optimization effort into a more reusable sandbox exporter with explicit regression gates and documented architecture.

## v1.0.0

Initial tagged baseline before the generalized exporter hardening phase.


path: contracts/export_hints.schema.json
content: {
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "ExportHints",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "producer": { "type": "string" },
    "producer_confidence": { "type": "string", "enum": ["high", "medium", "low", "none"] },
    "preset": { "type": "string" },
    "deck_family": { "type": "string" },
    "runtime_flags": {
      "type": "object",
      "additionalProperties": { "type": "boolean" }
    },
    "chrome_selectors": {
      "type": "array",
      "items": { "type": "string" }
    },
    "semantic_bias": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "layout_family": { "type": "string" },
        "decorative_layers": {
          "type": "array",
          "items": { "type": "string" }
        },
        "text_expectations": {
          "type": "object",
          "additionalProperties": { "type": "boolean" }
        }
      }
    },
    "contract_ref": { "type": "string" }
  }
}


path: contracts/slide_creator/manifest.json
content: {
  "producer": "slide-creator",
  "manifest_version": "1.0.0",
  "generated_at": "2026-04-25",
  "upstream_repo": "slide-creator",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "source_snapshot_root": "source_snapshot",
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "global_reference_refs": [
    "references/aurora-mesh.md",
    "references/base-css.md",
    "references/blue-sky-starter.html",
    "references/bold-signal.md",
    "references/brief-template.json",
    "references/chinese-chan.md",
    "references/composition-8.md",
    "references/composition-guide.md",
    "references/creative-voltage.md",
    "references/dark-botanical.md",
    "references/data-story.md",
    "references/design-quality.md",
    "references/design-system.md",
    "references/diagram-patterns.md",
    "references/electric-studio.md",
    "references/enterprise-dark.md",
    "references/glassmorphism.md",
    "references/html-template.md",
    "references/impeccable-anti-patterns.md",
    "references/js-engine.md",
    "references/modern-newspaper.md",
    "references/neo-brutalism.md",
    "references/neo-retro-dev.md",
    "references/neon-cyber.md",
    "references/notebook-tabs.md",
    "references/paper-ink.md",
    "references/pastel-geometry.md",
    "references/planning-template.md",
    "references/pptx-extraction.md",
    "references/review-checklist.md",
    "references/split-pastel.md",
    "references/style-index.md",
    "references/swiss-modern.md",
    "references/terminal-green.md",
    "references/title-profile-registry.json",
    "references/title-quality.md",
    "references/vintage-editorial.md",
    "references/workflow.md"
  ],
  "global_reference_snapshot_refs": [
    "source_snapshot/references/aurora-mesh.md",
    "source_snapshot/references/base-css.md",
    "source_snapshot/references/blue-sky-starter.html",
    "source_snapshot/references/bold-signal.md",
    "source_snapshot/references/brief-template.json",
    "source_snapshot/references/chinese-chan.md",
    "source_snapshot/references/composition-8.md",
    "source_snapshot/references/composition-guide.md",
    "source_snapshot/references/creative-voltage.md",
    "source_snapshot/references/dark-botanical.md",
    "source_snapshot/references/data-story.md",
    "source_snapshot/references/design-quality.md",
    "source_snapshot/references/design-system.md",
    "source_snapshot/references/diagram-patterns.md",
    "source_snapshot/references/electric-studio.md",
    "source_snapshot/references/enterprise-dark.md",
    "source_snapshot/references/glassmorphism.md",
    "source_snapshot/references/html-template.md",
    "source_snapshot/references/impeccable-anti-patterns.md",
    "source_snapshot/references/js-engine.md",
    "source_snapshot/references/modern-newspaper.md",
    "source_snapshot/references/neo-brutalism.md",
    "source_snapshot/references/neo-retro-dev.md",
    "source_snapshot/references/neon-cyber.md",
    "source_snapshot/references/notebook-tabs.md",
    "source_snapshot/references/paper-ink.md",
    "source_snapshot/references/pastel-geometry.md",
    "source_snapshot/references/planning-template.md",
    "source_snapshot/references/pptx-extraction.md",
    "source_snapshot/references/review-checklist.md",
    "source_snapshot/references/split-pastel.md",
    "source_snapshot/references/style-index.md",
    "source_snapshot/references/swiss-modern.md",
    "source_snapshot/references/terminal-green.md",
    "source_snapshot/references/title-profile-registry.json",
    "source_snapshot/references/title-quality.md",
    "source_snapshot/references/vintage-editorial.md",
    "source_snapshot/references/workflow.md"
  ],
  "global_demo_refs": [
    "demos/ai-native-org-transformation-guide-zh.html",
    "demos/aurora-mesh-en.html",
    "demos/aurora-mesh-zh.html",
    "demos/blue-sky-en.html",
    "demos/blue-sky-zh.html",
    "demos/bold-signal-en.html",
    "demos/bold-signal-zh.html",
    "demos/chinese-chan-en.html",
    "demos/chinese-chan-zh.html",
    "demos/creative-voltage-en.html",
    "demos/creative-voltage-zh.html",
    "demos/dark-botanical-en.html",
    "demos/dark-botanical-zh.html",
    "demos/data-story-en.html",
    "demos/data-story-zh.html",
    "demos/electric-studio-en.html",
    "demos/electric-studio-zh.html",
    "demos/enterprise-dark-en.html",
    "demos/enterprise-dark-zh.html",
    "demos/glassmorphism-en.html",
    "demos/glassmorphism-zh.html",
    "demos/modern-newspaper-en.html",
    "demos/modern-newspaper-zh.html",
    "demos/neo-brutalism-en.html",
    "demos/neo-brutalism-zh.html",
    "demos/neo-retro-dev-en.html",
    "demos/neo-retro-dev-zh.html",
    "demos/neon-cyber-en.html",
    "demos/neon-cyber-zh.html",
    "demos/notebook-tabs-en.html",
    "demos/notebook-tabs-zh.html",
    "demos/paper-ink-en.html",
    "demos/paper-ink-zh.html",
    "demos/pastel-geometry-en.html",
    "demos/pastel-geometry-zh.html",
    "demos/slide-creator-intro.html",
    "demos/split-pastel-en.html",
    "demos/split-pastel-zh.html",
    "demos/swiss-modern-en.html",
    "demos/swiss-modern-zh.html",
    "demos/terminal-green-en.html",
    "demos/terminal-green-zh.html",
    "demos/vintage-editorial-en.html",
    "demos/vintage-editorial-zh.html"
  ],
  "global_demo_snapshot_refs": [
    "source_snapshot/demos/ai-native-org-transformation-guide-zh.html",
    "source_snapshot/demos/aurora-mesh-en.html",
    "source_snapshot/demos/aurora-mesh-zh.html",
    "source_snapshot/demos/blue-sky-en.html",
    "source_snapshot/demos/blue-sky-zh.html",
    "source_snapshot/demos/bold-signal-en.html",
    "source_snapshot/demos/bold-signal-zh.html",
    "source_snapshot/demos/chinese-chan-en.html",
    "source_snapshot/demos/chinese-chan-zh.html",
    "source_snapshot/demos/creative-voltage-en.html",
    "source_snapshot/demos/creative-voltage-zh.html",
    "source_snapshot/demos/dark-botanical-en.html",
    "source_snapshot/demos/dark-botanical-zh.html",
    "source_snapshot/demos/data-story-en.html",
    "source_snapshot/demos/data-story-zh.html",
    "source_snapshot/demos/electric-studio-en.html",
    "source_snapshot/demos/electric-studio-zh.html",
    "source_snapshot/demos/enterprise-dark-en.html",
    "source_snapshot/demos/enterprise-dark-zh.html",
    "source_snapshot/demos/glassmorphism-en.html",
    "source_snapshot/demos/glassmorphism-zh.html",
    "source_snapshot/demos/modern-newspaper-en.html",
    "source_snapshot/demos/modern-newspaper-zh.html",
    "source_snapshot/demos/neo-brutalism-en.html",
    "source_snapshot/demos/neo-brutalism-zh.html",
    "source_snapshot/demos/neo-retro-dev-en.html",
    "source_snapshot/demos/neo-retro-dev-zh.html",
    "source_snapshot/demos/neon-cyber-en.html",
    "source_snapshot/demos/neon-cyber-zh.html",
    "source_snapshot/demos/notebook-tabs-en.html",
    "source_snapshot/demos/notebook-tabs-zh.html",
    "source_snapshot/demos/paper-ink-en.html",
    "source_snapshot/demos/paper-ink-zh.html",
    "source_snapshot/demos/pastel-geometry-en.html",
    "source_snapshot/demos/pastel-geometry-zh.html",
    "source_snapshot/demos/slide-creator-intro.html",
    "source_snapshot/demos/split-pastel-en.html",
    "source_snapshot/demos/split-pastel-zh.html",
    "source_snapshot/demos/swiss-modern-en.html",
    "source_snapshot/demos/swiss-modern-zh.html",
    "source_snapshot/demos/terminal-green-en.html",
    "source_snapshot/demos/terminal-green-zh.html",
    "source_snapshot/demos/vintage-editorial-en.html",
    "source_snapshot/demos/vintage-editorial-zh.html"
  ],
  "presets": [
    {
      "slug": "bold-signal",
      "preset": "Bold Signal",
      "contract_id": "slide-creator/bold-signal",
      "contract_version": "1.0.0",
      "family": "high-contrast-keynote",
      "producer_version_tested": "2.16.0",
      "contract_path": "presets/bold-signal.json",
      "source_refs": [
        "references/bold-signal.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/bold-signal-zh.html",
        "demos/bold-signal-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/bold-signal.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/bold-signal-zh.html",
        "source_snapshot/demos/bold-signal-en.html"
      ]
    },
    {
      "slug": "electric-studio",
      "preset": "Electric Studio",
      "contract_id": "slide-creator/electric-studio",
      "contract_version": "1.0.0",
      "family": "clean-professional-studio",
      "producer_version_tested": "2.18.0",
      "contract_path": "presets/electric-studio.json",
      "source_refs": [
        "references/electric-studio.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/electric-studio-zh.html",
        "demos/electric-studio-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/electric-studio.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/electric-studio-zh.html",
        "source_snapshot/demos/electric-studio-en.html"
      ]
    },
    {
      "slug": "creative-voltage",
      "preset": "Creative Voltage",
      "contract_id": "slide-creator/creative-voltage",
      "contract_version": "1.0.0",
      "family": "energetic-retro-modern",
      "producer_version_tested": "2.18.0",
      "contract_path": "presets/creative-voltage.json",
      "source_refs": [
        "references/creative-voltage.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/creative-voltage-zh.html",
        "demos/creative-voltage-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/creative-voltage.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/creative-voltage-zh.html",
        "source_snapshot/demos/creative-voltage-en.html"
      ]
    },
    {
      "slug": "dark-botanical",
      "preset": "Dark Botanical",
      "contract_id": "slide-creator/dark-botanical",
      "contract_version": "1.0.0",
      "family": "elegant-premium-botanical",
      "producer_version_tested": "2.18.0",
      "contract_path": "presets/dark-botanical.json",
      "source_refs": [
        "references/dark-botanical.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/dark-botanical-zh.html",
        "demos/dark-botanical-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/dark-botanical.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/dark-botanical-zh.html",
        "source_snapshot/demos/dark-botanical-en.html"
      ]
    },
    {
      "slug": "blue-sky",
      "preset": "Blue Sky",
      "contract_id": "slide-creator/blue-sky",
      "contract_version": "1.0.0",
      "family": "bright-card-stack",
      "producer_version_tested": "2.16.0",
      "contract_path": "presets/blue-sky.json",
      "source_refs": [
        "references/blue-sky-starter.html",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/blue-sky-zh.html",
        "demos/blue-sky-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/blue-sky-starter.html",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/blue-sky-zh.html",
        "source_snapshot/demos/blue-sky-en.html"
      ]
    },
    {
      "slug": "notebook-tabs",
      "preset": "Notebook Tabs",
      "contract_id": "slide-creator/notebook-tabs",
      "contract_version": "1.0.0",
      "family": "editorial-organized-notebook",
      "producer_version_tested": "2.18.0",
      "contract_path": "presets/notebook-tabs.json",
      "source_refs": [
        "references/notebook-tabs.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/notebook-tabs-zh.html",
        "demos/notebook-tabs-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/notebook-tabs.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/notebook-tabs-zh.html",
        "source_snapshot/demos/notebook-tabs-en.html"
      ]
    },
    {
      "slug": "pastel-geometry",
      "preset": "Pastel Geometry",
      "contract_id": "slide-creator/pastel-geometry",
      "contract_version": "1.0.0",
      "family": "friendly-soft-geometric",
      "producer_version_tested": "2.18.0",
      "contract_path": "presets/pastel-geometry.json",
      "source_refs": [
        "references/pastel-geometry.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/pastel-geometry-zh.html",
        "demos/pastel-geometry-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/pastel-geometry.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/pastel-geometry-zh.html",
        "source_snapshot/demos/pastel-geometry-en.html"
      ]
    },
    {
      "slug": "split-pastel",
      "preset": "Split Pastel",
      "contract_id": "slide-creator/split-pastel",
      "contract_version": "1.0.0",
      "family": "playful-modern-split",
      "producer_version_tested": "2.18.0",
      "contract_path": "presets/split-pastel.json",
      "source_refs": [
        "references/split-pastel.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/split-pastel-zh.html",
        "demos/split-pastel-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/split-pastel.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/split-pastel-zh.html",
        "source_snapshot/demos/split-pastel-en.html"
      ]
    },
    {
      "slug": "vintage-editorial",
      "preset": "Vintage Editorial",
      "contract_id": "slide-creator/vintage-editorial",
      "contract_version": "1.0.0",
      "family": "witty-personality-editorial",
      "producer_version_tested": "2.17.0",
      "contract_path": "presets/vintage-editorial.json",
      "source_refs": [
        "references/vintage-editorial.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/vintage-editorial-zh.html",
        "demos/vintage-editorial-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/vintage-editorial.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/vintage-editorial-zh.html",
        "source_snapshot/demos/vintage-editorial-en.html"
      ]
    },
    {
      "slug": "neon-cyber",
      "preset": "Neon Cyber",
      "contract_id": "slide-creator/neon-cyber",
      "contract_version": "1.0.0",
      "family": "futuristic-cyberpunk-tech",
      "producer_version_tested": "2.17.0",
      "contract_path": "presets/neon-cyber.json",
      "source_refs": [
        "references/neon-cyber.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/neon-cyber-zh.html",
        "demos/neon-cyber-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/neon-cyber.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/neon-cyber-zh.html",
        "source_snapshot/demos/neon-cyber-en.html"
      ]
    },
    {
      "slug": "terminal-green",
      "preset": "Terminal Green",
      "contract_id": "slide-creator/terminal-green",
      "contract_version": "1.0.0",
      "family": "developer-terminal-mono",
      "producer_version_tested": "2.16.0",
      "contract_path": "presets/terminal-green.json",
      "source_refs": [
        "references/terminal-green.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/terminal-green-zh.html",
        "demos/terminal-green-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/terminal-green.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/terminal-green-zh.html",
        "source_snapshot/demos/terminal-green-en.html"
      ]
    },
    {
      "slug": "swiss-modern",
      "preset": "Swiss Modern",
      "contract_id": "slide-creator/swiss-modern",
      "contract_version": "1.0.0",
      "family": "editorial-swiss",
      "producer_version_tested": "2.18.0",
      "contract_path": "presets/swiss-modern.json",
      "source_refs": [
        "references/swiss-modern.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/swiss-modern-zh.html",
        "demos/swiss-modern-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/swiss-modern.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/swiss-modern-zh.html",
        "source_snapshot/demos/swiss-modern-en.html"
      ],
      "support_tiers": [
        "canonical",
        "compatible",
        "fallback"
      ]
    },
    {
      "slug": "paper-ink",
      "preset": "Paper & Ink",
      "contract_id": "slide-creator/paper-ink",
      "contract_version": "1.0.0",
      "family": "literary-thoughtful-editorial",
      "producer_version_tested": "2.18.0",
      "contract_path": "presets/paper-ink.json",
      "source_refs": [
        "references/paper-ink.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/paper-ink-zh.html",
        "demos/paper-ink-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/paper-ink.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/paper-ink-zh.html",
        "source_snapshot/demos/paper-ink-en.html"
      ]
    },
    {
      "slug": "aurora-mesh",
      "preset": "Aurora Mesh",
      "contract_id": "slide-creator/aurora-mesh",
      "contract_version": "1.0.0",
      "family": "premium-saas-aurora",
      "producer_version_tested": "2.18.0",
      "contract_path": "presets/aurora-mesh.json",
      "source_refs": [
        "references/aurora-mesh.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/aurora-mesh-zh.html",
        "demos/aurora-mesh-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/aurora-mesh.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/aurora-mesh-zh.html",
        "source_snapshot/demos/aurora-mesh-en.html"
      ]
    },
    {
      "slug": "enterprise-dark",
      "preset": "Enterprise Dark",
      "contract_id": "slide-creator/enterprise-dark",
      "contract_version": "1.0.0",
      "family": "consulting-dark",
      "producer_version_tested": "2.15.0",
      "contract_path": "presets/enterprise-dark.json",
      "source_refs": [
        "references/enterprise-dark.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/enterprise-dark-zh.html",
        "demos/enterprise-dark-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/enterprise-dark.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/enterprise-dark-zh.html",
        "source_snapshot/demos/enterprise-dark-en.html"
      ]
    },
    {
      "slug": "glassmorphism",
      "preset": "Glassmorphism",
      "contract_id": "slide-creator/glassmorphism",
      "contract_version": "1.0.0",
      "family": "translucent-consumer-modern",
      "producer_version_tested": "2.17.0",
      "contract_path": "presets/glassmorphism.json",
      "source_refs": [
        "references/glassmorphism.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/glassmorphism-zh.html",
        "demos/glassmorphism-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/glassmorphism.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/glassmorphism-zh.html",
        "source_snapshot/demos/glassmorphism-en.html"
      ]
    },
    {
      "slug": "neo-brutalism",
      "preset": "Neo-Brutalism",
      "contract_id": "slide-creator/neo-brutalism",
      "contract_version": "1.0.0",
      "family": "bold-uncompromising-manifesto",
      "producer_version_tested": "2.18.0",
      "contract_path": "presets/neo-brutalism.json",
      "source_refs": [
        "references/neo-brutalism.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/neo-brutalism-zh.html",
        "demos/neo-brutalism-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/neo-brutalism.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/neo-brutalism-zh.html",
        "source_snapshot/demos/neo-brutalism-en.html"
      ]
    },
    {
      "slug": "chinese-chan",
      "preset": "Chinese Chan",
      "contract_id": "slide-creator/chinese-chan",
      "contract_version": "1.0.0",
      "family": "contemplative-editorial-serif",
      "producer_version_tested": "unknown",
      "contract_path": "presets/chinese-chan.json",
      "source_refs": [
        "references/chinese-chan.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/chinese-chan-zh.html",
        "demos/chinese-chan-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/chinese-chan.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/chinese-chan-zh.html",
        "source_snapshot/demos/chinese-chan-en.html"
      ]
    },
    {
      "slug": "data-story",
      "preset": "Data Story",
      "contract_id": "slide-creator/data-story",
      "contract_version": "1.0.0",
      "family": "data-visual-narrative",
      "producer_version_tested": "2.14.0",
      "contract_path": "presets/data-story.json",
      "source_refs": [
        "references/data-story.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/data-story-zh.html",
        "demos/data-story-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/data-story.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/data-story-zh.html",
        "source_snapshot/demos/data-story-en.html"
      ]
    },
    {
      "slug": "modern-newspaper",
      "preset": "Modern Newspaper",
      "contract_id": "slide-creator/modern-newspaper",
      "contract_version": "1.0.0",
      "family": "authoritative-editorial-news",
      "producer_version_tested": "2.18.0",
      "contract_path": "presets/modern-newspaper.json",
      "source_refs": [
        "references/modern-newspaper.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/modern-newspaper-zh.html",
        "demos/modern-newspaper-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/modern-newspaper.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/modern-newspaper-zh.html",
        "source_snapshot/demos/modern-newspaper-en.html"
      ]
    },
    {
      "slug": "neo-retro-dev",
      "preset": "Neo-Retro Dev",
      "contract_id": "slide-creator/neo-retro-dev",
      "contract_version": "1.0.0",
      "family": "opinionated-handmade-dev",
      "producer_version_tested": "2.18.0",
      "contract_path": "presets/neo-retro-dev.json",
      "source_refs": [
        "references/neo-retro-dev.md",
        "references/html-template.md"
      ],
      "demo_refs": [
        "demos/neo-retro-dev-zh.html",
        "demos/neo-retro-dev-en.html"
      ],
      "source_snapshot_refs": [
        "source_snapshot/references/neo-retro-dev.md",
        "source_snapshot/references/html-template.md"
      ],
      "demo_snapshot_refs": [
        "source_snapshot/demos/neo-retro-dev-zh.html",
        "source_snapshot/demos/neo-retro-dev-en.html"
      ]
    }
  ]
}


path: contracts/slide_creator/presets/aurora-mesh.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/aurora-mesh",
  "preset": "Aurora Mesh",
  "family": "premium-saas-aurora",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.18.0 <3.0.0",
  "producer_version_tested": "2.18.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/aurora-mesh.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/aurora-mesh-zh.html",
    "demos/aurora-mesh-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/aurora-mesh.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/aurora-mesh-zh.html",
    "source_snapshot/demos/aurora-mesh-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [
    {
      "selector": "body",
      "kind": "aurora-mesh",
      "export_strategy": "background-layer"
    }
  ],
  "component_selectors": {
    "stat_card": [
      ".stat-col"
    ],
    "install_row": [
      ".install-item"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false,
      "metric_vertical_align": "center_remaining",
      "metric_max_height_ratio": 0.62,
      "gaps": {
        "after_metric": 0.08,
        "after_label": 0.06
      }
    },
    "install_row": {
      "layout": "vertical_card",
      "slots": [
        "label",
        "command"
      ],
      "minimum_height_in": 0.92,
      "gaps": {
        "after_metric": 0.08,
        "after_label": 0.08
      },
      "bottom_anchor_last_slot": false
    }
  },
  "layout_variations": [
    "hero-stats",
    "feature-card",
    "centered-stat-row",
    "install-rows",
    "closing-cta"
  ],
  "text_expectations": {
    "tabular_numbers": false,
    "gradient_metrics": true
  },
  "typography": {
    "display_font_stack": [
      "Space Grotesk",
      "Noto Sans SC",
      "PingFang SC",
      "Helvetica Neue",
      "sans-serif"
    ],
    "body_font_stack": [
      "DM Sans",
      "Noto Sans SC",
      "PingFang SC",
      "Helvetica Neue",
      "sans-serif"
    ],
    "role_selectors": {
      "title": [
        ".aurora-title"
      ],
      "body": [
        ".aurora-subtitle",
        ".cta-sub",
        ".feat-card-desc",
        ".style-desc",
        ".step-text",
        ".code-block"
      ],
      "label": [
        ".aurora-badge",
        ".hero-stat-label",
        ".stat-sub",
        ".install-label",
        ".feat-card-title",
        ".step-title"
      ],
      "metric": [
        ".aurora-stat",
        ".hero-stat"
      ]
    },
    "title": {
      "family_mode": "display_sans",
      "weight": 700,
      "line_height": 1.05,
      "letter_spacing": "-0.03em"
    },
    "body": {
      "family_mode": "body_sans",
      "weight": 400,
      "line_height": 1.6
    },
    "label": {
      "family_mode": "body_sans",
      "weight": 600,
      "line_height": 1.2,
      "letter_spacing": "0.08em"
    },
    "metric": {
      "family_mode": "display_sans",
      "weight": 700,
      "line_height": 1.0,
      "letter_spacing": "-0.03em"
    }
  },
  "line_break_contract": {
    "break_policy": {
      ".aurora-title": "prefer_preserve",
      ".aurora-subtitle": "preserve",
      ".cta-sub": "preserve",
      ".code-block": "preserve"
    },
    "shrink_forbidden_for": [
      ".aurora-title",
      ".aurora-stat",
      ".hero-stat"
    ],
    "overflow_strategy": "expand_container_first"
  },
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Aurora Mesh",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "a-body",
    "a-label",
    "a-subtitle",
    "a-title",
    "aurora-badge",
    "aurora-card",
    "aurora-stat",
    "aurora-subtitle",
    "aurora-title",
    "cmd",
    "cta-pill",
    "cta-sub",
    "feat-card-desc",
    "feat-card-title",
    "feat-grid",
    "h2-title",
    "hero-stat",
    "hero-stat-label",
    "install-item",
    "install-label",
    "install-row",
    "label",
    "pill",
    "slide-num-label",
    "stat",
    "stat-col",
    "stat-divider",
    "stat-row",
    "stat-sub",
    "step-title"
  ]
}


path: contracts/slide_creator/presets/blue-sky.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/blue-sky",
  "preset": "Blue Sky",
  "family": "bright-card-stack",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.16.0 <3.0.0",
  "producer_version_tested": "2.16.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/blue-sky-starter.html",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/blue-sky-zh.html",
    "demos/blue-sky-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/blue-sky-starter.html",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/blue-sky-zh.html",
    "source_snapshot/demos/blue-sky-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "pill": [
      ".pill"
    ],
    "card": [
      ".g",
      ".layer"
    ],
    "cta_row": [
      ".co",
      ".cmd",
      ".info"
    ],
    "table_card": [
      ".ctable"
    ]
  },
  "component_slot_models": {
    "pill": {
      "layout": "inline_pill",
      "slots": [
        "text"
      ]
    },
    "card": {
      "layout": "stack_card",
      "slots": [
        "eyebrow",
        "title",
        "body",
        "table_or_list",
        "footer"
      ]
    },
    "cta_row": {
      "layout": "inline_command_row",
      "slots": [
        "command",
        "separator",
        "link"
      ]
    }
  },
  "layout_variations": [
    "hero-stats",
    "pill-headers",
    "layer-cards",
    "closing-cta"
  ],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Blue Sky",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "a-body",
    "a-label",
    "a-subtitle",
    "a-title",
    "cmd",
    "label",
    "pill",
    "stat"
  ]
}


path: contracts/slide_creator/presets/bold-signal.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/bold-signal",
  "preset": "Bold Signal",
  "family": "high-contrast-keynote",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.16.0 <3.0.0",
  "producer_version_tested": "2.16.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/bold-signal.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/bold-signal-zh.html",
    "demos/bold-signal-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/bold-signal.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/bold-signal-zh.html",
    "source_snapshot/demos/bold-signal-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "stat_card": [
      ".bold-stat"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false
    }
  },
  "layout_variations": [],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Bold Signal",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "bold-body",
    "bold-card",
    "bold-cmd",
    "bold-hero-card",
    "bold-label",
    "bold-stat",
    "bold-title",
    "cmd",
    "label"
  ]
}


path: contracts/slide_creator/presets/chinese-chan.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/chinese-chan",
  "preset": "Chinese Chan",
  "family": "contemplative-editorial-serif",
  "contract_version": "1.0.0",
  "producer_version_range": ">=0.0.0 <3.0.0",
  "producer_version_tested": "unknown",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/chinese-chan.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/chinese-chan-zh.html",
    "demos/chinese-chan-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/chinese-chan.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/chinese-chan-zh.html",
    "source_snapshot/demos/chinese-chan-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [
    {
      "selector": "body::before",
      "kind": "ink-wash",
      "export_strategy": "background-layer"
    }
  ],
  "component_selectors": {
    "rule": [
      ".zen-rule"
    ],
    "rule_line": [
      ".zen-rule-line"
    ],
    "card": [
      ".zen-card"
    ],
    "list": [
      ".zen-list"
    ],
    "stat": [
      ".zen-stat"
    ],
    "command": [
      ".cmd"
    ],
    "ghost_kanji": [
      ".zen-ghost-kanji"
    ],
    "seal": [
      ".zen-seal"
    ]
  },
  "component_slot_models": {
    "card": {
      "layout": "stack_card",
      "slots": [
        "title",
        "body",
        "footer"
      ]
    },
    "stat": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label"
      ]
    },
    "command": {
      "layout": "inline_command_row",
      "slots": [
        "command"
      ]
    }
  },
  "layout_variations": [
    "editorial-cover",
    "narrow-column-sermon",
    "serif-stats",
    "closing-command"
  ],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {
    "cn_font_stack": [
      "Noto Serif CJK SC",
      "Source Han Serif SC",
      "STSong",
      "SimSun",
      "Georgia",
      "serif"
    ],
    "en_font_stack": [
      "EB Garamond",
      "Crimson Text",
      "Georgia",
      "serif"
    ],
    "font_features": [
      "palt"
    ],
    "role_selectors": {
      "title": [
        ".zen-title",
        ".zen-h2",
        ".zen-subtitle",
        ".zen-caption",
        ".zen-accent",
        ".zen-ghost-kanji"
      ],
      "body": [
        ".zen-body",
        ".zen-list"
      ],
      "command": [
        ".cmd"
      ],
      "metric": [
        ".num",
        ".label"
      ]
    },
    "title": {
      "family_mode": "cn_serif",
      "weight": 400,
      "line_height": 1.3,
      "letter_spacing": "0.08em"
    },
    "body": {
      "family_mode": "cn_serif",
      "weight": 300,
      "line_height": 1.9,
      "letter_spacing": "0.05em"
    },
    "command": {
      "family_mode": "en_serif",
      "line_height": 1.6
    },
    "metric": {
      "family_mode": "en_serif",
      "weight": 600
    }
  },
  "line_break_contract": {
    "break_policy": {
      ".zen-title": "prefer_preserve",
      ".zen-body": "preserve",
      ".cmd": "preserve"
    },
    "shrink_forbidden_for": [
      ".zen-title",
      ".zen-body",
      ".cmd"
    ],
    "overflow_strategy": "expand_container_first"
  },
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Chinese Chan",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "a-body",
    "a-label",
    "a-subtitle",
    "a-title",
    "cmd",
    "label",
    "pill",
    "stat",
    "zen-accent",
    "zen-body",
    "zen-caption",
    "zen-ghost-kanji",
    "zen-h2",
    "zen-rule",
    "zen-seal",
    "zen-stat",
    "zen-subtitle",
    "zen-title",
    "zen-vline"
  ]
}


path: contracts/slide_creator/presets/creative-voltage.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/creative-voltage",
  "preset": "Creative Voltage",
  "family": "energetic-retro-modern",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.18.0 <3.0.0",
  "producer_version_tested": "2.18.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/creative-voltage.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/creative-voltage-zh.html",
    "demos/creative-voltage-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/creative-voltage.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/creative-voltage-zh.html",
    "source_snapshot/demos/creative-voltage-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "stat_card": [
      ".stat"
    ],
    "split_layout": [
      ".voltage-split"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false
    },
    "split_layout": {
      "layout": "grid_two_column",
      "slots": [
        "left_rail",
        "right_rail"
      ],
      "track_template": "1fr 1fr"
    }
  },
  "layout_variations": [],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Creative Voltage",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "a-body",
    "a-label",
    "a-subtitle",
    "a-title",
    "blue-panel",
    "body-muted",
    "body-text",
    "cmd",
    "cta-command",
    "cta-inner",
    "cta-link",
    "cta-sub",
    "dark-panel",
    "feat-grid",
    "grid-wrap",
    "how-card",
    "install-blocks",
    "install-label",
    "label",
    "main-title",
    "panel-content",
    "pill",
    "slide-num-label",
    "stat",
    "step-card",
    "step-label",
    "tag",
    "title-accent",
    "voltage-blue-panel",
    "voltage-body",
    "voltage-card",
    "voltage-dark-panel",
    "voltage-grid",
    "voltage-neon-badge",
    "voltage-split",
    "voltage-title"
  ]
}


path: contracts/slide_creator/presets/dark-botanical.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/dark-botanical",
  "preset": "Dark Botanical",
  "family": "elegant-premium-botanical",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.18.0 <3.0.0",
  "producer_version_tested": "2.18.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/dark-botanical.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/dark-botanical-zh.html",
    "demos/dark-botanical-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/dark-botanical.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/dark-botanical-zh.html",
    "source_snapshot/demos/dark-botanical-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "stat_card": [
      ".stat",
      ".stat-label",
      ".stat-value"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false
    }
  },
  "layout_variations": [],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Dark Botanical",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "badge",
    "cta-cmd",
    "cta-sub",
    "feature",
    "feature-grid",
    "hero-title",
    "install-block",
    "install-col",
    "install-label",
    "left-col",
    "pill",
    "preset-grid",
    "preset-tag",
    "right-col",
    "slide-label",
    "slide-num-label",
    "stat",
    "stat-label",
    "stat-value"
  ]
}


path: contracts/slide_creator/presets/data-story.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/data-story",
  "preset": "Data Story",
  "family": "data-visual-narrative",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.14.0 <3.0.0",
  "producer_version_tested": "2.14.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/data-story.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/data-story-zh.html",
    "demos/data-story-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/data-story.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/data-story-zh.html",
    "source_snapshot/demos/data-story-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [
    {
      "selector": ".slide::before",
      "kind": "data-grid",
      "export_strategy": "background-layer"
    },
    {
      "selector": "body::before",
      "kind": "data-grid",
      "export_strategy": "background-layer"
    }
  ],
  "component_selectors": {
    "split_layout": [
      ".ds-split-layout"
    ],
    "left_panel": [
      ".left-panel"
    ],
    "metric_grid": [
      ".ds-kpi-grid"
    ],
    "metric_card": [
      ".ds-kpi-card"
    ],
    "hero_metric": [
      ".ds-kpi"
    ],
    "metric_label": [
      ".ds-kpi-label"
    ],
    "trend": [
      ".ds-trend"
    ],
    "insight": [
      ".ds-insight"
    ],
    "style_card": [
      ".style-card"
    ],
    "solution_card": [
      ".sol-card"
    ],
    "solution_icon": [
      ".sol-icon"
    ],
    "chart_svg": [
      ".ds-chart-svg"
    ],
    "chart_line": [
      ".ds-line"
    ],
    "chart_axis": [
      ".chart-axis",
      ".ds-axis"
    ],
    "chart_grid": [
      ".chart-grid",
      ".ds-grid"
    ],
    "matrix": [
      ".ds-matrix"
    ],
    "matrix_cell": [
      ".ds-matrix-cell"
    ],
    "feature_grid": [
      ".feat-grid"
    ],
    "feature_card": [
      ".feat-card"
    ],
    "feature_stat": [
      ".feat-stat"
    ],
    "steps": [
      ".steps"
    ],
    "step_item": [
      ".step-item"
    ],
    "step_num": [
      ".step-num"
    ],
    "install_row": [
      ".install-row"
    ],
    "install_label": [
      ".install-label"
    ],
    "install_cmd": [
      ".install-cmd"
    ]
  },
  "component_slot_models": {
    "split_layout": {
      "layout": "grid_two_column",
      "slots": [
        "metric_stack",
        "chart"
      ],
      "track_template": "1fr 1.5fr"
    },
    "metric_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "trend"
      ],
      "minimum_height_in": 1.1,
      "gaps": {
        "after_metric": 0.05,
        "after_label": 0.05
      },
      "metric_single_line": true,
      "bottom_anchor_last_slot": true,
      "metric_vertical_align": "center_remaining",
      "metric_max_height_ratio": 0.8
    },
    "style_card": {
      "layout": "vertical_card",
      "slots": [
        "preview",
        "title",
        "body",
        "trend"
      ],
      "minimum_height_in": 1.28,
      "gaps": {
        "after_metric": 0.1,
        "after_label": 0.06
      },
      "stretch_first_slot": true,
      "bottom_anchor_last_slot": false
    },
    "solution_card": {
      "layout": "vertical_card",
      "slots": [
        "icon",
        "title",
        "body"
      ],
      "minimum_height_in": 1.02,
      "gaps": {
        "after_metric": 0.08,
        "after_label": 0.06
      },
      "bottom_anchor_last_slot": false
    },
    "feature_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "title",
        "body"
      ],
      "minimum_height_in": 1.06,
      "gaps": {
        "after_metric": 0.1,
        "after_label": 0.06
      },
      "metric_single_line": true,
      "bottom_anchor_last_slot": false,
      "metric_vertical_align": "center_remaining",
      "metric_max_height_ratio": 0.58
    },
    "install_row": {
      "layout": "split_rail",
      "slots": [
        "label",
        "command"
      ],
      "keep_command_single_line": true,
      "minimum_height_in": 0.44,
      "label_min_width_px": 120,
      "gap_px": 16
    },
    "chart_svg": {
      "layout": "svg_chart",
      "slots": [
        "axes",
        "grid",
        "series",
        "labels"
      ]
    },
    "matrix_cell": {
      "layout": "vertical_card",
      "slots": [
        "label",
        "metric",
        "body"
      ]
    }
  },
  "layout_variations": [
    "hero-number",
    "kpi-row-chart",
    "chart-layout",
    "comparison-matrix",
    "feature-grid",
    "install-rows",
    "closing-kpi"
  ],
  "text_expectations": {
    "tabular_numbers": true
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Data Story",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "badge",
    "chart-axis",
    "chart-grid",
    "chart-label",
    "chart-val",
    "cta-group",
    "cta-pill",
    "ds-chart-svg",
    "ds-dot",
    "ds-insight",
    "ds-kpi",
    "ds-kpi-card",
    "ds-kpi-grid",
    "ds-kpi-label",
    "ds-line",
    "ds-split-layout",
    "ds-trend",
    "feat-card",
    "feat-grid",
    "feat-stat",
    "grid-2",
    "grid-3",
    "hero-kpi-group",
    "install-cmd",
    "install-label",
    "install-row",
    "left-panel",
    "pill",
    "slide-num-label",
    "sol-card",
    "stat",
    "stat-label",
    "stat-value",
    "style-card"
  ]
}


path: contracts/slide_creator/presets/electric-studio.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/electric-studio",
  "preset": "Electric Studio",
  "family": "clean-professional-studio",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.18.0 <3.0.0",
  "producer_version_tested": "2.18.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/electric-studio.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/electric-studio-zh.html",
    "demos/electric-studio-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/electric-studio.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/electric-studio-zh.html",
    "source_snapshot/demos/electric-studio-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "stat_card": [
      ".elec-stat-label",
      ".elec-stat-number",
      ".stat",
      ".stat-col",
      ".stat-divider",
      ".stat-group",
      ".stat-item",
      ".stat-label",
      ".stat-row",
      ".stat-sub",
      ".stat-value"
    ],
    "install_row": [
      ".install-row"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false
    },
    "install_row": {
      "layout": "split_rail",
      "slots": [
        "label",
        "command"
      ],
      "keep_command_single_line": true,
      "minimum_height_in": 0.44,
      "label_min_width_px": 120,
      "gap_px": 16
    }
  },
  "layout_variations": [],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Electric Studio",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "badge-desc",
    "badge-group",
    "badge-pill",
    "bottom-panel",
    "cta-pill",
    "cta-sub",
    "elec-body",
    "elec-label",
    "elec-stat-label",
    "elec-stat-number",
    "elec-title",
    "feat-card",
    "feat-card-desc",
    "feat-card-title",
    "feat-grid",
    "install-item",
    "install-label",
    "install-row",
    "left-panel",
    "pill",
    "right-panel",
    "slide-num-label",
    "stat",
    "stat-col",
    "stat-divider",
    "stat-group",
    "stat-item",
    "stat-label",
    "stat-row",
    "stat-sub",
    "stat-value",
    "top-panel"
  ]
}


path: contracts/slide_creator/presets/enterprise-dark.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/enterprise-dark",
  "preset": "Enterprise Dark",
  "family": "consulting-dark",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.15.0 <3.0.0",
  "producer_version_tested": "2.15.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/enterprise-dark.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/enterprise-dark-zh.html",
    "demos/enterprise-dark-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/enterprise-dark.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/enterprise-dark-zh.html",
    "source_snapshot/demos/enterprise-dark-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [
    {
      "selector": "body::before",
      "kind": "density-grid",
      "export_strategy": "background-layer"
    }
  ],
  "component_selectors": {
    "split_layout": [
      ".ent-split"
    ],
    "split_label": [
      ".ent-split-label"
    ],
    "metric_grid": [
      ".ent-kpi-grid"
    ],
    "metric_card": [
      ".ent-kpi-card"
    ],
    "data_table": [
      ".ent-table"
    ],
    "pill": [
      ".ent-pill"
    ],
    "progress_track": [
      ".ent-progress-track"
    ],
    "progress_fill": [
      ".ent-progress-fill"
    ],
    "trend": [
      ".ent-trend"
    ],
    "cta_pill": [
      ".cta-pill"
    ]
  },
  "component_slot_models": {
    "split_layout": {
      "layout": "grid_two_column",
      "slots": [
        "label_rail",
        "content_rail"
      ],
      "track_template": "clamp(160px,22%,240px) 1fr"
    },
    "metric_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "title_or_label",
        "body",
        "progress_or_trend"
      ],
      "allow_inline_variant": true
    },
    "data_table": {
      "layout": "open_table",
      "slots": [
        "header",
        "body"
      ]
    },
    "cta_pill": {
      "layout": "cta_pill",
      "slots": [
        "command"
      ]
    }
  },
  "layout_variations": [
    "hero-stats",
    "consulting-split",
    "kpi-dashboard",
    "data-table",
    "installation-cards",
    "closing-cta"
  ],
  "text_expectations": {
    "tabular_numbers": true
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Enterprise Dark",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "cta-group",
    "cta-pill",
    "ent-kpi-card",
    "ent-kpi-grid",
    "ent-kpi-label",
    "ent-kpi-number",
    "ent-label",
    "ent-pill",
    "ent-progress-fill",
    "ent-progress-track",
    "ent-sep",
    "ent-split",
    "ent-split-label",
    "ent-table",
    "ent-trend",
    "pill",
    "slide-num-label",
    "stat",
    "stat-label",
    "stat-value"
  ]
}


path: contracts/slide_creator/presets/glassmorphism.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/glassmorphism",
  "preset": "Glassmorphism",
  "family": "translucent-consumer-modern",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.17.0 <3.0.0",
  "producer_version_tested": "2.17.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/glassmorphism.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/glassmorphism-zh.html",
    "demos/glassmorphism-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/glassmorphism.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/glassmorphism-zh.html",
    "source_snapshot/demos/glassmorphism-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "stat_card": [
      ".stat",
      ".stat-card",
      ".stat-label",
      ".stat-num",
      ".stat-value"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false
    }
  },
  "layout_variations": [],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Glassmorphism",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "glass-body",
    "glass-card",
    "glass-title",
    "grid",
    "pill",
    "stat",
    "stat-card",
    "stat-label",
    "stat-num",
    "stat-value",
    "tag"
  ]
}


path: contracts/slide_creator/presets/modern-newspaper.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/modern-newspaper",
  "preset": "Modern Newspaper",
  "family": "authoritative-editorial-news",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.18.0 <3.0.0",
  "producer_version_tested": "2.18.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/modern-newspaper.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/modern-newspaper-zh.html",
    "demos/modern-newspaper-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/modern-newspaper.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/modern-newspaper-zh.html",
    "source_snapshot/demos/modern-newspaper-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "stat_card": [
      ".stat",
      ".stat-label",
      ".stat-value"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false
    }
  },
  "layout_variations": [],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Modern Newspaper",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "np-body",
    "np-cmd",
    "pill",
    "slide-num-label",
    "stat",
    "stat-label",
    "stat-value",
    "title-slide"
  ]
}


path: contracts/slide_creator/presets/neo-brutalism.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/neo-brutalism",
  "preset": "Neo-Brutalism",
  "family": "bold-uncompromising-manifesto",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.18.0 <3.0.0",
  "producer_version_tested": "2.18.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/neo-brutalism.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/neo-brutalism-zh.html",
    "demos/neo-brutalism-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/neo-brutalism.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/neo-brutalism-zh.html",
    "source_snapshot/demos/neo-brutalism-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "stat_card": [
      ".hero-kpi",
      ".hero-kpi-item",
      ".stat-label",
      ".stat-number"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false
    }
  },
  "layout_variations": [],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Neo-Brutalism",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "brute-body",
    "brute-card",
    "brute-tag",
    "brute-title",
    "cta-cmd",
    "cta-cmd-light",
    "cta-content",
    "cta-headline",
    "cta-note",
    "cta-rule",
    "cta-sub",
    "cta-tag",
    "feature-card",
    "feature-grid",
    "feature-icon",
    "hero-badge",
    "hero-kpi",
    "hero-kpi-item",
    "hero-subtitle",
    "install-block",
    "install-cmd",
    "install-platform",
    "install-section",
    "left-panel",
    "preset-tag",
    "right-panel",
    "slide-num-label",
    "stat-label",
    "stat-number",
    "style-card",
    "style-card-label",
    "style-card-preview",
    "style-card-title"
  ]
}


path: contracts/slide_creator/presets/neo-retro-dev.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/neo-retro-dev",
  "preset": "Neo-Retro Dev",
  "family": "opinionated-handmade-dev",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.18.0 <3.0.0",
  "producer_version_tested": "2.18.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/neo-retro-dev.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/neo-retro-dev-zh.html",
    "demos/neo-retro-dev-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/neo-retro-dev.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/neo-retro-dev-zh.html",
    "source_snapshot/demos/neo-retro-dev-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "stat_card": [
      ".metric-block",
      ".metric-checks",
      ".metric-num",
      ".metric-num-pink",
      ".stat",
      ".stat-label",
      ".stat-row",
      ".stat-value"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false
    }
  },
  "layout_variations": [],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Neo Retro Dev",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "arch-title",
    "ba-panel",
    "badge",
    "badge-cyan",
    "badge-cyan-bg",
    "badge-pink",
    "badge-row",
    "badge-yellow-bg",
    "body-text",
    "card-top",
    "cards-grid",
    "close-badge",
    "cmd-block-wrap",
    "cmd-cyan",
    "cmd-green",
    "cmd-pink",
    "cmd-table",
    "feat-card",
    "layer-label",
    "metric-block",
    "metric-checks",
    "metric-num",
    "metric-num-pink",
    "metrics-grid",
    "pill",
    "px-label",
    "slide-num-label",
    "stat",
    "stat-label",
    "stat-row",
    "stat-value",
    "title-block"
  ]
}


path: contracts/slide_creator/presets/neon-cyber.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/neon-cyber",
  "preset": "Neon Cyber",
  "family": "futuristic-cyberpunk-tech",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.17.0 <3.0.0",
  "producer_version_tested": "2.17.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/neon-cyber.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/neon-cyber-zh.html",
    "demos/neon-cyber-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/neon-cyber.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/neon-cyber-zh.html",
    "source_snapshot/demos/neon-cyber-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "stat_card": [
      ".stat",
      ".stat-label",
      ".stat-value"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false
    }
  },
  "layout_variations": [],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Neon Cyber",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "cyber-card",
    "cyber-label",
    "cyber-title",
    "grid",
    "neon-body",
    "pill",
    "stat",
    "stat-label",
    "stat-value"
  ]
}


path: contracts/slide_creator/presets/notebook-tabs.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/notebook-tabs",
  "preset": "Notebook Tabs",
  "family": "editorial-organized-notebook",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.18.0 <3.0.0",
  "producer_version_tested": "2.18.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/notebook-tabs.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/notebook-tabs-zh.html",
    "demos/notebook-tabs-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/notebook-tabs.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/notebook-tabs-zh.html",
    "source_snapshot/demos/notebook-tabs-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "stat_card": [
      ".hero-stat",
      ".metric-bar",
      ".metric-bar-fill",
      ".metric-col",
      ".metric-cols",
      ".nb-stat",
      ".stat",
      ".stat-label",
      ".stat-value"
    ],
    "split_layout": [
      ".ba-split"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false
    },
    "split_layout": {
      "layout": "grid_two_column",
      "slots": [
        "left_rail",
        "right_rail"
      ],
      "track_template": "1fr 1fr"
    }
  },
  "layout_variations": [],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Notebook Tabs",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "arch-layer-badge",
    "arch-layer-body",
    "arch-layer-title",
    "ba-split",
    "cmd-desc",
    "cmd-name",
    "cmd-row",
    "cmd-table",
    "cta-badge",
    "cta-code",
    "cta-content",
    "cta-headline",
    "cta-steps",
    "cta-sub",
    "feat-card",
    "feat-grid",
    "hero-stat",
    "hero-title",
    "metric-bar",
    "metric-bar-fill",
    "metric-col",
    "metric-cols",
    "nb-body",
    "nb-label",
    "nb-stat",
    "nb-title",
    "pill",
    "slide-num-label",
    "stat",
    "stat-label",
    "stat-value"
  ]
}


path: contracts/slide_creator/presets/paper-ink.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/paper-ink",
  "preset": "Paper & Ink",
  "family": "literary-thoughtful-editorial",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.18.0 <3.0.0",
  "producer_version_tested": "2.18.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/paper-ink.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/paper-ink-zh.html",
    "demos/paper-ink-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/paper-ink.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/paper-ink-zh.html",
    "source_snapshot/demos/paper-ink-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "stat_card": [
      ".stat",
      ".stat-label",
      ".stat-row",
      ".stat-val",
      ".stat-value"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false
    }
  },
  "layout_variations": [],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Paper & Ink",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "body-text",
    "cta-body",
    "cta-cmd",
    "cta-inner",
    "feature-desc",
    "feature-item",
    "feature-list",
    "feature-name",
    "hero-body",
    "install-block",
    "install-label",
    "pill",
    "pull-quote",
    "slide-num-label",
    "stat",
    "stat-label",
    "stat-row",
    "stat-val",
    "stat-value"
  ]
}


path: contracts/slide_creator/presets/pastel-geometry.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/pastel-geometry",
  "preset": "Pastel Geometry",
  "family": "friendly-soft-geometric",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.18.0 <3.0.0",
  "producer_version_tested": "2.18.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/pastel-geometry.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/pastel-geometry-zh.html",
    "demos/pastel-geometry-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/pastel-geometry.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/pastel-geometry-zh.html",
    "source_snapshot/demos/pastel-geometry-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "stat_card": [
      ".cta-stat",
      ".cta-stat-label",
      ".cta-stat-num",
      ".hero-stat",
      ".hero-stat-label",
      ".hero-stat-num",
      ".stat",
      ".stat-label",
      ".stat-value"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false
    }
  },
  "layout_variations": [],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Pastel Geometry",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "body-muted",
    "card-content",
    "cmd-block",
    "cmd-text",
    "cta-badge",
    "cta-command",
    "cta-inner",
    "cta-stat",
    "cta-stat-label",
    "cta-stat-num",
    "cta-stats",
    "cta-sub",
    "feat-card",
    "feat-grid",
    "flow-card",
    "hero-badge",
    "hero-stat",
    "hero-stat-label",
    "hero-stat-num",
    "hero-title",
    "install-blocks",
    "install-card",
    "install-label",
    "left-panel",
    "pill",
    "pill-bar",
    "preset-card",
    "preset-grid",
    "right-panel",
    "slide-num-label",
    "stat",
    "stat-label",
    "stat-value",
    "steps-grid",
    "tag"
  ]
}


path: contracts/slide_creator/presets/split-pastel.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/split-pastel",
  "preset": "Split Pastel",
  "family": "playful-modern-split",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.18.0 <3.0.0",
  "producer_version_tested": "2.18.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/split-pastel.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/split-pastel-zh.html",
    "demos/split-pastel-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/split-pastel.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/split-pastel-zh.html",
    "source_snapshot/demos/split-pastel-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "stat_card": [
      ".stat",
      ".stat-label",
      ".stat-num",
      ".stat-pill",
      ".stat-value"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false
    }
  },
  "layout_variations": [],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Split Pastel",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "badge",
    "badge-lavender",
    "badge-mint",
    "badge-peach",
    "badge-pink",
    "badge-yellow",
    "card",
    "cta-btn",
    "cta-cmd",
    "cta-primary",
    "cta-sub",
    "feature-card",
    "feature-grid",
    "hero-title-main",
    "install-card",
    "install-cards",
    "left-panel",
    "pill",
    "preset-chip",
    "preset-grid",
    "preview-card",
    "preview-label",
    "right-panel",
    "slide-num-label",
    "stat",
    "stat-label",
    "stat-num",
    "stat-pill",
    "stat-value"
  ]
}


path: contracts/slide_creator/presets/swiss-modern.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/swiss-modern",
  "preset": "Swiss Modern",
  "family": "editorial-swiss",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.18.0 <3.0.0",
  "producer_version_tested": "2.18.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/swiss-modern.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/swiss-modern-zh.html",
    "demos/swiss-modern-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/swiss-modern.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/swiss-modern-zh.html",
    "source_snapshot/demos/swiss-modern-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [
    {
      "selector": "body::before",
      "kind": "swiss-grid",
      "export_strategy": "background-layer"
    }
  ],
  "component_selectors": {
    "editorial_grid": [
      ".grid",
      ".editorial-grid"
    ],
    "section_label": [
      ".swiss-label",
      ".label",
      ".eyebrow"
    ],
    "card": [
      ".swiss-card",
      ".feat-card",
      ".pain-item"
    ],
    "rule": [
      ".swiss-rule",
      ".swiss-rule-thin"
    ],
    "terminal_line": [
      ".terminal-line"
    ],
    "body_columns": [
      ".right-col",
      ".swiss-body-columns"
    ]
  },
  "component_slot_models": {
    "card": {
      "layout": "editorial_card",
      "slots": [
        "label",
        "title",
        "body",
        "rule_or_stat"
      ]
    },
    "terminal_line": {
      "layout": "inline_command_row",
      "slots": [
        "command",
        "label",
        "link"
      ]
    },
    "body_columns": {
      "layout": "typographic_columns",
      "slots": [
        "body_flow"
      ],
      "column_count": 2,
      "column_gap_px": 32,
      "compatibility_tier": "compatible"
    }
  },
  "layout_variations": [
    "title_grid",
    "column_content",
    "stat_block",
    "pull_quote",
    "geometric_diagram",
    "contents_index",
    "data_table"
  ],
  "text_expectations": {
    "tabular_numbers": true,
    "single_red_accent_per_slide": true
  },
  "typography": {
    "display_font_stack": [
      "Archivo Black",
      "Arial Black",
      "Helvetica Neue",
      "sans-serif"
    ],
    "body_font_stack": [
      "Nunito",
      "Helvetica Neue",
      "Arial",
      "sans-serif"
    ],
    "label_font_stack": [
      "Archivo",
      "Helvetica Neue",
      "Arial",
      "sans-serif"
    ],
    "role_selectors": {
      "title": [
        ".swiss-title",
        ".quote-text",
        ".hero-title",
        ".index-title"
      ],
      "body": [
        ".swiss-body",
        ".pain-desc",
        ".quote-attribution",
        ".disc-step-desc",
        ".index-desc"
      ],
      "label": [
        ".swiss-label",
        ".label",
        ".eyebrow",
        ".slide-num-label",
        ".pain-title"
      ],
      "metric": [
        ".swiss-stat",
        ".hero-stat-num",
        ".pain-num",
        ".index-num"
      ]
    },
    "title": {
      "family_mode": "display_sans",
      "weight": 900,
      "line_height": 1.0,
      "letter_spacing": "-0.02em"
    },
    "body": {
      "family_mode": "body_sans",
      "weight": 400,
      "line_height": 1.55
    },
    "label": {
      "family_mode": "label_sans",
      "weight": 700,
      "line_height": 1.2,
      "letter_spacing": "0.08em"
    },
    "metric": {
      "family_mode": "display_sans",
      "weight": 900,
      "line_height": 1.0
    }
  },
  "line_break_contract": {
    "break_policy": {
      ".swiss-title": "prefer_preserve",
      ".quote-text": "prefer_preserve",
      ".swiss-body": "preserve",
      ".pain-desc": "preserve",
      ".quote-attribution": "preserve"
    },
    "shrink_forbidden_for": [
      ".swiss-title",
      ".quote-text",
      ".swiss-stat",
      ".pain-desc",
      ".quote-attribution"
    ],
    "overflow_strategy": "expand_container_first"
  },
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Swiss Modern",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "bg-num",
    "cta-block",
    "cta-echo",
    "cta-echo-label",
    "cta-echo-num",
    "cta-inner",
    "cta-sub",
    "cta-title",
    "disc-body",
    "disc-header",
    "disc-step-title",
    "feat-card",
    "feat-grid",
    "hero-stat-label",
    "hero-stat-num",
    "hero-title",
    "index-title",
    "inst-label",
    "left-panel",
    "pain-title",
    "pill",
    "right-panel",
    "slide-num-label",
    "stat",
    "stat-label",
    "stat-value",
    "swiss-label",
    "terminal-line"
  ],
  "signature_elements": {
    "page_grid": {
      "selectors": [
        "body::before"
      ],
      "export_strategy": "background-layer"
    },
    "bg_num": {
      "selectors": [
        ".bg-num"
      ],
      "export_strategy": "anchored-text"
    },
    "slide_num_label": {
      "selectors": [
        ".slide-num-label"
      ],
      "export_strategy": "anchored-text"
    },
    "hard_rule": {
      "selectors": [
        ".swiss-rule",
        ".swiss-rule.red",
        ".swiss-rule-thin"
      ],
      "export_strategy": "shape-divider"
    }
  },
  "support_tiers": {
    "canonical": {
      "description": "Official Swiss demo family or guarded generated Swiss HTML."
    },
    "compatible": {
      "description": "Swiss decks with a single content wrapper and approved structural aliases.",
      "wrapper_selectors": [
        ".slide-content",
        ".content"
      ]
    },
    "fallback": {
      "description": "Producer detection only. No Swiss-specific layout guarantees."
    }
  },
  "layout_contracts": {
    "title_grid": {
      "canonical": {
        "direct_children_all": [
          ".bg-num",
          ".slide-num-label"
        ],
        "direct_children_any": [
          ".hero-inner",
          ".cta-inner"
        ]
      },
      "compatible": {
        "wrapper_selectors": [
          ".slide-content",
          ".content"
        ],
        "wrapper_children_all": [
          ".swiss-title"
        ],
        "direct_children_all": [
          ".slide-num-label"
        ],
        "unwrap_wrapper": true
      }
    },
    "column_content": {
      "canonical": {
        "direct_children_all": [
          ".left-panel",
          ".right-panel",
          ".slide-num-label"
        ]
      },
      "compatible": {
        "wrapper_selectors": [
          ".slide-content",
          ".content"
        ],
        "wrapper_children_all": [
          ".left-col",
          ".right-col"
        ],
        "direct_children_all": [
          ".slide-num-label"
        ],
        "unwrap_wrapper": true
      }
    },
    "stat_block": {
      "canonical": {
        "direct_children_all": [
          ".stat-row",
          ".slide-num-label"
        ]
      },
      "compatible": {
        "wrapper_selectors": [
          ".slide-content",
          ".content"
        ],
        "wrapper_children_all": [
          ".stat-block",
          ".content-block"
        ],
        "direct_children_all": [
          ".slide-num-label"
        ],
        "unwrap_wrapper": true
      }
    },
    "pull_quote": {
      "canonical": {
        "direct_children_all": [
          ".pull-quote",
          ".slide-num-label"
        ]
      },
      "compatible": {
        "wrapper_selectors": [
          ".slide-content",
          ".content"
        ],
        "wrapper_children_all": [
          ".quote-block"
        ],
        "direct_children_all": [
          ".slide-num-label"
        ],
        "unwrap_wrapper": true
      }
    },
    "inner_panel": {
      "canonical": {
        "direct_children_all": [
          ".slide-num-label"
        ],
        "direct_children_any": [
          ".flow-inner",
          ".feat-inner"
        ]
      }
    },
    "index_list": {
      "canonical": {
        "direct_children_all": [
          ".slide-num-label"
        ],
        "direct_children_any": [
          ".sol-inner"
        ]
      }
    },
    "inst_blocks": {
      "canonical": {
        "direct_children_all": [
          ".slide-num-label"
        ],
        "direct_children_any": [
          ".inst-inner"
        ]
      }
    },
    "disc_layout": {
      "canonical": {
        "direct_children_all": [
          ".disc-header",
          ".disc-body",
          ".slide-num-label"
        ]
      }
    }
  },
  "style_constraints": {
    "max_red_accent_per_slide": 1,
    "allow_gradients": false,
    "allow_shadows": false,
    "allow_rounded_corners": false,
    "require_asymmetric_title_anchor": true
  }
}

path: contracts/slide_creator/presets/terminal-green.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/terminal-green",
  "preset": "Terminal Green",
  "family": "developer-terminal-mono",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.16.0 <3.0.0",
  "producer_version_tested": "2.16.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/terminal-green.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/terminal-green-zh.html",
    "demos/terminal-green-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/terminal-green.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/terminal-green-zh.html",
    "source_snapshot/demos/terminal-green-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "stat_card": [
      ".stat",
      ".stat-label",
      ".stat-row",
      ".stat-val"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false
    }
  },
  "layout_variations": [],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Terminal Green",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "a-body",
    "a-label",
    "a-subtitle",
    "a-title",
    "cmd",
    "cta-block",
    "cta-cmd",
    "cta-sub",
    "feature-card",
    "feature-desc",
    "feature-grid",
    "feature-title",
    "label",
    "main-title",
    "pill",
    "preset-grid",
    "preset-tag",
    "stat",
    "stat-label",
    "stat-row",
    "stat-val",
    "t-body",
    "t-label",
    "t-subtitle",
    "t-title"
  ]
}


path: contracts/slide_creator/presets/vintage-editorial.json
content: {
  "producer": "slide-creator",
  "contract_id": "slide-creator/vintage-editorial",
  "preset": "Vintage Editorial",
  "family": "witty-personality-editorial",
  "contract_version": "1.0.0",
  "producer_version_range": ">=2.17.0 <3.0.0",
  "producer_version_tested": "2.17.0",
  "contract_source_version": "slide-creator@b9fb3d1e569b",
  "upstream_commit": "b9fb3d1e569ba6dc3129fec20f65885a48a0e3fa",
  "generated_at": "2026-04-25",
  "source_refs": [
    "references/vintage-editorial.md",
    "references/html-template.md"
  ],
  "demo_refs": [
    "demos/vintage-editorial-zh.html",
    "demos/vintage-editorial-en.html"
  ],
  "source_snapshot_refs": [
    "source_snapshot/references/vintage-editorial.md",
    "source_snapshot/references/html-template.md"
  ],
  "demo_snapshot_refs": [
    "source_snapshot/demos/vintage-editorial-zh.html",
    "source_snapshot/demos/vintage-editorial-en.html"
  ],
  "runtime_chrome_selectors": [
    ".progress-bar",
    ".nav-dots",
    ".edit-hotzone",
    ".edit-toggle",
    "#notes-panel",
    "#present-btn",
    "#present-counter"
  ],
  "decorative_layers": [],
  "component_selectors": {
    "stat_card": [
      ".stat",
      ".stat-big",
      ".stat-item",
      ".stat-label",
      ".stat-small",
      ".stat-value"
    ]
  },
  "component_slot_models": {
    "stat_card": {
      "layout": "vertical_card",
      "slots": [
        "metric",
        "label",
        "body"
      ],
      "metric_single_line": true,
      "bottom_anchor_last_slot": false
    }
  },
  "layout_variations": [],
  "text_expectations": {
    "tabular_numbers": false
  },
  "typography": {},
  "line_break_contract": {},
  "producer_detection": {
    "body_attrs": {
      "data-preset": "Vintage Editorial",
      "data-export-progress": "true|false"
    },
    "meta_generator_contains": "kai-slide-creator",
    "watermark_contains": "By kai-slide-creator v"
  },
  "observed_component_classes": [
    "body-text",
    "display-title",
    "feature-badge",
    "feature-desc",
    "feature-name",
    "feature-row",
    "pain-body",
    "pain-title",
    "pill",
    "preset-grid",
    "preset-tag",
    "stat",
    "stat-big",
    "stat-item",
    "stat-label",
    "stat-small",
    "stat-value",
    "step-ed-body",
    "step-ed-title",
    "sub-label"
  ]
}


path: contracts/slide_creator/source_snapshot/demos/ai-native-org-transformation-guide-zh.html
content: <!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>AI原生组织转型指南 - Enterprise Dark</title>
<style>
:root {
    --bg-primary:   #0d1117;
    --bg-secondary: #161b22;
    --bg-header:    #21262d;
    --border:       #30363d;
    --text-primary: #e6edf3;
    --text-body:    #c9d1d9;
    --text-muted:   #8b949e;
    --accent-blue:  #388bfd;
    --accent-green: #3fb950;   /* positive / up */
    --accent-red:   #f85149;   /* negative / down */
    --accent-amber: #d29922;   /* warning / neutral */
}

body {
    background: var(--bg-primary);
}

/* Subtle density grid — adds visual weight without distraction */
body::before {
    content: '';
    position: fixed; inset: 0;
    background-image:
        linear-gradient(rgba(48,54,61,0.5) 1px, transparent 1px),
        linear-gradient(90deg, rgba(48,54,61,0.5) 1px, transparent 1px);
    background-size: 24px 24px;
    opacity: 0.03;
    pointer-events: none;
    z-index: 0;
}

/* All text — system fonts, tabular nums for all numeric content */
body {
    font-family: "PingFang SC", "Noto Sans CJK SC", "Segoe UI",
                 -apple-system, system-ui, sans-serif;
    font-feature-settings: "tnum"; /* tabular numbers throughout */
    -webkit-font-smoothing: antialiased;
}

/* Section label */
.ent-label {
    font-size: clamp(10px, 1.1vw, 12px);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--text-muted);
}

/* Slide title */
.ent-title {
    font-size: clamp(22px, 3.5vw, 44px);
    font-weight: 600;
    color: var(--text-primary);
    line-height: 1.12;
    letter-spacing: -0.02em;
}

/* KPI number */
.ent-kpi-number {
    font-size: clamp(36px, 5vw, 56px);
    font-weight: 800;
    font-feature-settings: "tnum";
    line-height: 1;
}
.ent-kpi-number.positive { color: var(--accent-green); }
.ent-kpi-number.negative { color: var(--accent-red); }
.ent-kpi-number.neutral  { color: var(--text-primary); }

/* KPI label */
.ent-kpi-label {
    font-size: clamp(10px, 1.1vw, 12px);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    margin-top: 4px;
}

.ent-kpi-card {
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: clamp(16px, 2.5vw, 24px) clamp(20px, 3vw, 32px);
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* KPI grid — 2 or 3 columns */
.ent-kpi-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr));
    gap: clamp(10px, 1.5vw, 16px);
}

/* Trend arrow */
.ent-trend {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: clamp(10px, 1.2vw, 12px);
    font-weight: 600;
}
.ent-trend.up   { color: var(--accent-green); }
.ent-trend.down { color: var(--accent-red); }

.ent-progress-track {
    height: 2px;
    background: var(--border);
    border-radius: 2px;
    overflow: hidden;
}
.ent-progress-fill {
    height: 100%;
    background: var(--accent-blue);
    border-radius: 2px;
    transition: width 0.8s cubic-bezier(0.16,1,0.3,1);
}

.ent-table {
    width: 100%;
    border-collapse: collapse;
    font-size: clamp(12px, 1.3vw, 15px);
    font-variant-numeric: tabular-nums;
}
.ent-table thead th {
    background: var(--bg-header);
    color: var(--text-muted);
    font-size: clamp(10px, 1.1vw, 12px);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: clamp(8px, 1.2vw, 12px) clamp(12px, 1.5vw, 16px);
    text-align: left;
    border-bottom: 1px solid var(--border);
}
.ent-table tbody td {
    padding: clamp(10px, 1.3vw, 14px) clamp(12px, 1.5vw, 16px);
    color: var(--text-primary);
    border-bottom: 1px solid var(--border);
}
.ent-table tbody tr:last-child td { border-bottom: none; }
.ent-table tbody tr:hover td { background: rgba(48,54,61,0.5); }

.ent-split {
    display: grid;
    grid-template-columns: clamp(160px, 22%, 240px) 1fr;
    gap: clamp(20px, 3vw, 36px);
    align-items: start;
}
.ent-split-label {
    font-size: clamp(10px, 1.1vw, 12px);
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: clamp(10px, 1.5vw, 14px) 0;
    border-bottom: 1px solid var(--border);
}

/* ── KPI card ── */
.ent-kpi-card {
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: clamp(16px, 2.5vw, 24px);
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1;
    min-width: 120px;
}
.ent-kpi-number {
    font-size: clamp(32px, 5vw, 56px);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1;
    letter-spacing: -0.03em;
}
.ent-kpi-number.positive { color: var(--accent-green); }
.ent-kpi-number.negative { color: var(--accent-red); }
.ent-kpi-number.neutral  { color: var(--text-primary); }

.ent-kpi-label {
    font-size: clamp(10px, 1.1vw, 12px);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
}

/* KPI row — flex container for multiple KPI cards */
.ent-kpi-row {
    display: flex;
    gap: clamp(12px, 2vw, 20px);
    flex-wrap: wrap;
}

/* ── Inline label tag ── */
.ent-label-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 3px 10px;
    font-size: clamp(10px, 1.1vw, 12px);
    font-weight: 600;
    color: var(--text-muted);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    font-variant-numeric: tabular-nums;
}

/* ── Inline badge (status indicator) ── */
.ent-badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: clamp(10px, 1.1vw, 12px);
    font-weight: 600;
    letter-spacing: 0.04em;
    font-variant-numeric: tabular-nums;
}
.ent-badge-blue {
    background: rgba(56,139,253,0.15);
    color: var(--accent-blue);
    border: 1px solid rgba(56,139,253,0.30);
}
.ent-badge-green {
    background: rgba(63,185,80,0.15);
    color: var(--accent-green);
    border: 1px solid rgba(63,185,80,0.30);
}

/* ── Status dot ── */
.ent-status-dot {
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    margin-right: 6px;
    vertical-align: middle;
}
.ent-dot-green { background: var(--accent-green); }
.ent-dot-blue  { background: var(--accent-blue); }
.ent-dot-red   { background: var(--accent-red); }

/* ── Accent color utilities ── */
.ent-accent-blue   { color: var(--accent-blue); }
.ent-accent-green  { color: var(--accent-green); }
.ent-accent-red    { color: var(--accent-red); }
.ent-accent-amber  { color: var(--accent-amber); }

/* ── Feature row (icon + text + optional badge) ── */
.ent-feature-row {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: clamp(12px, 1.8vw, 16px) 0;
    border-bottom: 1px solid var(--border);
}
.ent-feature-row:last-child { border-bottom: none; }

.ent-feature-icon {
    width: 28px;
    height: 28px;
    min-width: 28px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
}

/* ── Progress bar ── */
.ent-prog-bar {
    height: 2px;
    background: var(--border);
    border-radius: 2px;
    overflow: hidden;
}
.ent-prog-fill {
    height: 100%;
    background: var(--accent-blue);
    border-radius: 2px;
    transition: width 0.8s ease;
}

/* ── Horizontal separator ── */
.ent-sep {
    height: 1px;
    background: var(--border);
    margin: clamp(14px, 2vw, 22px) 0;
}

/* ── Content container (max-width centered) ── */
.ent-content {
    width: 100%;
    max-width: 880px;
    padding: clamp(24px, 5vw, 60px);
}

/* ── 2-column grid ── */
.ent-grid-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: clamp(10px, 1.5vw, 16px);
}

/* ── Consulting split layout ── */
.ent-split {
    display: grid;
    grid-template-columns: 200px 1fr;
    gap: clamp(20px, 3vw, 36px);
    align-items: start;
}
.ent-split-labels {
    display: flex;
    flex-direction: column;
    gap: clamp(10px, 1.5vw, 14px);
}
.ent-split-label {
    font-size: clamp(10px, 1.1vw, 12px);
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: clamp(10px, 1.5vw, 14px) 0;
    border-bottom: 1px solid var(--border);
}
.ent-split-label:last-child { border-bottom: none; }

/* ── Data table ── */
.ent-table {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}
.ent-table th {
    background: var(--bg-header);
    color: var(--text-muted);
    font-size: clamp(10px, 1.1vw, 12px);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: clamp(8px, 1.2vw, 12px) clamp(12px, 1.5vw, 16px);
    text-align: left;
    border-bottom: 1px solid var(--border);
}
.ent-table td {
    padding: clamp(10px, 1.3vw, 14px) clamp(12px, 1.5vw, 16px);
    color: var(--text-primary);
    border-bottom: 1px solid var(--border);
    font-size: clamp(12px, 1.3vw, 15px);
}
.ent-table tr:last-child td { border-bottom: none; }

/* ── Code block ── */
.ent-code {
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: clamp(12px, 1.8vw, 18px);
    font-size: clamp(11px, 1.2vw, 14px);
    color: var(--accent-blue);
    line-height: 1.6;
}
.ent-code .muted { color: var(--text-muted); }
.ent-code .green { color: var(--accent-green); }

/* ── Install command block ── */
.ent-install {
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: clamp(12px, 1.8vw, 18px);
    margin-bottom: clamp(8px, 1.2vw, 12px);
}
.ent-install-label {
    font-size: clamp(10px, 1.1vw, 12px);
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin-bottom: 6px;
}
.ent-install-cmd {
    font-family: 'SF Mono', 'Fira Code', monospace;
    font-size: clamp(11px, 1.2vw, 14px);
    color: var(--accent-green);
    word-break: break-all;
}

/* Minimal: 300ms fade only. No movement. */
.reveal {
    opacity: 0;
    transition: opacity 0.3s ease;
}
.reveal.visible { opacity: 1; }
.reveal:nth-child(1) { transition-delay: 0.05s; }
.reveal:nth-child(2) { transition-delay: 0.12s; }
.reveal:nth-child(3) { transition-delay: 0.19s; }
.reveal:nth-child(4) { transition-delay: 0.26s; }

html {
    height: 100%;
    overflow-x: hidden;
    scroll-snap-type: y mandatory;
}

body {
    margin: 0;
    min-height: 100%;
    overflow-x: hidden;
    color: var(--text-primary, var(--text, #f3f4f6));
    background: var(--bg-primary, var(--bg, #0f1117));
}

*, *::before, *::after { box-sizing: border-box; }

.slide {
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
    scroll-snap-align: start;
    display: flex;
    flex-direction: column;
    position: relative;
    background: var(--bg-primary, var(--bg, #0f1117));
}



.slide-content {
    position: relative;
    z-index: 1;
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: clamp(10px, 1.5vw, 18px);
    padding: clamp(24px, 4vw, 52px);
    max-height: 100%;
    overflow: hidden;
}

.title-balance {
    display: flex;
    flex-direction: column;
    gap: 0.02em;
    text-wrap: balance;
}

.title-line {
    display: block;
    white-space: nowrap;
}

#brand-mark {
    position: fixed;
    top: 20px;
    left: 28px;
    font-weight: 800;
    font-size: 15px;
    z-index: 1000;
    color: var(--text-primary, var(--text, #f3f4f6));
    letter-spacing: 0.06em;
}

.progress-bar {
    position: fixed;
    top: 0;
    left: 0;
    width: 0;
    height: 4px;
    background: var(--accent-blue, var(--chart-primary, #3b82f6));
    z-index: 1000;
    transition: width 0.3s ease;
}

.nav-dots { position: fixed; right: 20px; top: 50%; transform: translateY(-50%); z-index: 1000; }

.edit-hotzone {
    position: fixed;
    top: 0;
    left: 0;
    width: 84px;
    height: 84px;
    z-index: 9998;
}

.edit-toggle {
    position: fixed;
    top: 18px;
    left: 18px;
    z-index: 9999;
    border: none;
    background: rgba(0, 0, 0, 0.86);
    color: #fff;
    padding: 8px 12px;
    border-radius: 999px;
    font-size: 12px;
    cursor: pointer;
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity 0.2s ease, transform 0.2s ease;
}

.edit-toggle.show,
.edit-toggle.active {
    opacity: 1;
    transform: translateY(0);
}

#notes-panel {
    position: fixed;
    right: 18px;
    bottom: 18px;
    width: min(380px, 36vw);
    background: rgba(15, 23, 42, 0.94);
    color: #f8fafc;
    border: 1px solid rgba(148, 163, 184, 0.25);
    z-index: 9996;
    box-shadow: 0 14px 40px rgba(0, 0, 0, 0.3);
}

#notes-panel.collapsed #notes-body { display: none; }

#notes-panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 14px;
    cursor: pointer;
    border-bottom: 1px solid rgba(148, 163, 184, 0.16);
}

#notes-panel-label {
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgba(226, 232, 240, 0.7);
}

#notes-body { padding: 12px 14px 14px; }

#notes-textarea {
    width: 100%;
    min-height: 160px;
    resize: vertical;
    border: none;
    background: transparent;
    color: inherit;
    font: inherit;
    outline: none;
}

#notes-collapse-btn {
    border: none;
    background: transparent;
    color: inherit;
    font-size: 16px;
    cursor: pointer;
}

#present-btn {
    position: fixed;
    right: 18px;
    bottom: 18px;
    z-index: 9997;
    width: 42px;
    height: 42px;
    border-radius: 999px;
    border: none;
    background: rgba(0, 0, 0, 0.86);
    color: #fff;
    cursor: pointer;
}

#present-counter {
    display: none;
    position: fixed;
    bottom: 18px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 9997;
    font-size: 11px;
    letter-spacing: 0.12em;
    color: rgba(226, 232, 240, 0.38);
}

body.presenting {
    background: #000 !important;
    overflow: hidden !important;
}

body.presenting .slide {
    position: fixed !important;
    inset: 0;
    width: 100vw !important;
    height: 100vh !important;
    transform-origin: center center;
    scroll-snap-align: none !important;
    display: none !important;
}

body.presenting .slide.p-on { display: flex !important; }
body.presenting #present-btn { display: none !important; }
body.presenting #present-counter { display: block; }
body.presenting.presenting-black .slide { visibility: hidden !important; }
body.presenting.presenting-black::after {
    content: '';
    position: fixed;
    inset: 0;
    background: #000;
    z-index: 99999;
}

.slide-num-label {
    position: absolute;
    right: 28px;
    bottom: 24px;
    font-size: 11px;
    letter-spacing: 0.12em;
    color: rgba(148, 163, 184, 0.55);
    z-index: 2;
}

.slide-credit {
    position: absolute;
    bottom: 8px;
    right: 14px;
    font-size: 9px;
    color: rgba(148, 163, 184, 0.35);
    pointer-events: none;
    z-index: 1;
    font-family: system-ui, sans-serif;
}

body.presenting .slide-credit { display: none !important; }

.ent-shell {
    width: 100%;
    max-width: 1120px;
    margin: 0 auto;
}

.ent-hero-title {
    font-size: clamp(28px, 4.8vw, 56px);
    line-height: 1.04;
    font-weight: 700;
    color: var(--text-primary);
    letter-spacing: -0.03em;
    margin: 0;
}

.ent-kpi-meta {
    font-size: 12px;
    color: var(--text-muted);
}

.ent-pull {
    max-width: 16ch;
    font-size: clamp(28px, 4vw, 52px);
    line-height: 1.08;
    color: var(--text-primary);
    letter-spacing: -0.03em;
    font-weight: 650;
}

.ent-arch-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 18px;
    width: 100%;
}

.ent-arch-card {
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 18px;
}

.ent-timeline {
    position: relative;
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 20px;
    margin-top: 24px;
}

.ent-timeline::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 15px;
    height: 1px;
    background: var(--border);
}

.ent-timeline-item {
    position: relative;
    padding-top: 28px;
}

.ent-timeline-dot {
    position: absolute;
    top: 8px;
    left: 0;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--accent-blue);
    box-shadow: 0 0 0 4px rgba(56,139,253,0.14);
}

.ent-timeline-date {
    font-size: 11px;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    text-transform: uppercase;
}

.ent-timeline-copy {
    font-size: 14px;
    color: var(--text-body);
    line-height: 1.5;
}

.ent-matrix {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
}
</style>
</head>
<body data-export-progress="true" data-preset="Enterprise Dark">
<span id="brand-mark">slide-creator</span>
<div class="progress-bar"></div>
<nav class="nav-dots" aria-label="Slide navigation"></nav>
<div class="edit-hotzone"></div>
<button class="edit-toggle" id="editToggle" title="Edit mode (E)">Edit</button>
<div id="notes-panel">
    <div id="notes-panel-header">
        <div id="notes-panel-label">SPEAKER NOTES - SLIDE 1 / 12</div>
        <div id="notes-drag-hint"></div>
        <button id="notes-collapse-btn" title="Collapse / expand">▾</button>
    </div>
    <div id="notes-body">
        <textarea id="notes-textarea" placeholder="Add speaker notes..."></textarea>
    </div>
</div>
<section class="slide enterprise-dashboard" id="slide-1" data-notes="cover: 转型目标不是局部提效，而是让需求、设计、研发、测试、发布和复盘形成新的默认工作方式" aria-label="cover" data-export-role="kpi_dashboard">
        <div class="slide-content">
            <div class="ent-shell">
                <span class="ent-label-tag reveal">AI landscape</span>
                <h1 class="ent-hero-title reveal title-balance"><span class="title-line ent-accent-blue">AI 原生组织不是“多用几个</span><span class="title-line ent-accent-blue">AI 工具”，而是把产研流水线</span><span class="title-line ent-accent-blue">重写成“人+智能体”协同系统</span></h1>
                <div class="ent-sep reveal"></div>
                <p class="ent-kpi-meta reveal">转型目标不是局部提效，而是让需求、设计、研发、测试、发布和复盘形成新的默认工作方式</p>
                <div class="ent-kpi-row">
                    
            <div class="ent-kpi-card reveal">
                <div class="ent-kpi-number positive">01</div>
                <div class="ent-kpi-label">战略目标</div>
                <div class="ent-trend up">▲ 从工具试用升级到组织重写</div>
            </div>
            
            <div class="ent-kpi-card reveal">
                <div class="ent-kpi-number neutral">02</div>
                <div class="ent-kpi-label">协同模式</div>
                <div class="ent-trend up">▲ 人定义目标与门禁，AI承担高频执行</div>
            </div>
            
            <div class="ent-kpi-card reveal">
                <div class="ent-kpi-number positive">03</div>
                <div class="ent-kpi-label">核心主链</div>
                <div class="ent-trend up">▲ 需求、设计、研发、测试、发布、复盘全部重写</div>
            </div>
            
                </div>
            </div>
        </div>
        <span class="slide-num-label">01 / 12</span>
    </section>

<section class="slide enterprise-split" id="slide-2" data-notes="problem: 公开案例显示收益来自使用深度、标准化复用和组织准备度，而不是偶尔写几段提示词" aria-label="problem" data-export-role="consulting_split">
        <div class="ent-split">
            <div class="ent-split-labels slide-content">
                <span class="ent-label-tag reveal">section</span>
                <h2 class="ent-title reveal title-balance"><span class="title-line">市场已经进入“深度使用决</span><span class="title-line">定差距”的阶段，试点心态</span><span class="title-line">会把团队锁死在效率下游</span></h2>
                <div class="ent-sep reveal"></div>
                <div class="ent-split-label">公开案例显示收益来自使用深度</div><div class="ent-split-label">标准化复用和组织准备度</div><div class="ent-split-label">而不是偶尔写几段提示词</div>
            </div>
            <div class="slide-content">
                <div class="ent-kpi-card">
                    
        <div class="ent-feature-row reveal">
            <div class="ent-feature-icon">1</div>
            <div style="flex:1;">
                <h3 style="margin:0 0 6px;color:var(--text-primary);font-size:1rem;">公开趋势：AI使用深度决定收益</h3>
                <p style="margin:0;color:var(--text-body);font-size:0.92rem;line-height:1.5;">外部趋势与组织差距对照</p>
                <div class="ent-prog-bar" style="margin-top:10px;"><div class="ent-prog-fill" style="width:70%"></div></div>
            </div>
            <span class="ent-badge ent-badge-blue">Flow</span>
        </div>
        
        <div class="ent-feature-row reveal">
            <div class="ent-feature-icon">2</div>
            <div style="flex:1;">
                <h3 style="margin:0 0 6px;color:var(--text-primary);font-size:1rem;">集团方向：企业管理AI公司</h3>
                <p style="margin:0;color:var(--text-body);font-size:0.92rem;line-height:1.5;">外部趋势与组织差距对照</p>
                <div class="ent-prog-bar" style="margin-top:10px;"><div class="ent-prog-fill" style="width:55%"></div></div>
            </div>
            <span class="ent-badge ent-badge-blue">Flow</span>
        </div>
        
        <div class="ent-feature-row reveal">
            <div class="ent-feature-icon">3</div>
            <div style="flex:1;">
                <h3 style="margin:0 0 6px;color:var(--text-primary);font-size:1rem;">组织底座：数据治理、评测、AI champions</h3>
                <p style="margin:0;color:var(--text-body);font-size:0.92rem;line-height:1.5;">外部趋势与组织差距对照</p>
                <div class="ent-prog-bar" style="margin-top:10px;"><div class="ent-prog-fill" style="width:40%"></div></div>
            </div>
            <span class="ent-badge ent-badge-blue">Flow</span>
        </div>
        
                </div>
            </div>
        </div>
        <span class="slide-num-label">02 / 12</span>
    </section>

<section class="slide enterprise-architecture" id="slide-3" data-notes="discovery: 金蝶公开强调思维转型、业务变革、新一代软件与数据治理同步推进，云之家必须把集团方向翻译成日常动作" aria-label="discovery" data-export-role="architecture_map">
        <div class="slide-content">
            <div class="ent-shell">
                <span class="ent-label-tag reveal">system map</span>
                <h2 class="ent-title reveal title-balance"><span class="title-line">金蝶的要求已经很清楚：</span><span class="title-line">转型目标不是工具加法，</span><span class="title-line">而是成为企业管理 AI 公司</span></h2>
                <div class="ent-sep reveal"></div>
                <div class="ent-arch-grid"><div class="ent-arch-card reveal"><div class="ent-label">01</div><h3 style="margin:6px 0;color:var(--text-primary);">金蝶公开强调思维转型</h3><p style="margin:0;color:var(--text-body);line-height:1.5;">集团战略到产研动作的映射图</p></div><div class="ent-arch-card reveal"><div class="ent-label">02</div><h3 style="margin:6px 0;color:var(--text-primary);">业务变革</h3><p style="margin:0;color:var(--text-body);line-height:1.5;">集团战略到产研动作的映射图</p></div><div class="ent-arch-card reveal"><div class="ent-label">03</div><h3 style="margin:6px 0;color:var(--text-primary);">新一代软件与数据治理同步推进</h3><p style="margin:0;color:var(--text-body);line-height:1.5;">集团战略到产研动作的映射图</p></div></div>
            </div>
        </div>
        <span class="slide-num-label">03 / 12</span>
    </section>

<section class="slide enterprise-pull" id="slide-4" data-notes="solution: 入口、审批、门户、知识、低代码、数据协同都已经在云之家上，最适合先跑出“人+智能体场景化协作”的样板" aria-label="solution" data-export-role="insight_pull">
        <div class="slide-content">
            <div class="ent-shell">
                <span class="ent-label-tag reveal">insight</span>
                <div class="ent-pull reveal title-balance"><span class="title-line">云之家最适合率先打样，因为</span><span class="title-line">它天然就是“统一入口+协同</span><span class="title-line">流程+数据连接”的工作前台</span></div>
                <div class="ent-sep reveal" style="max-width:180px;"></div>
                <p style="max-width:34rem;color:var(--text-body);line-height:1.6;" class="reveal">入口、审批、门户、知识、低代码、数据协同都已经在云之家上，最适合先跑出“人+智能体场景化协作”的样板</p>
            </div>
        </div>
        <span class="slide-num-label">04 / 12</span>
    </section>

<section class="slide enterprise-split" id="slide-5" data-notes="workflow: 外部最佳实践都指向同一件事：先探索、再规划、后执行、最后验证，让每类任务都有模板、工具链和门禁" aria-label="workflow" data-export-role="consulting_split">
        <div class="ent-split">
            <div class="ent-split-labels slide-content">
                <span class="ent-label-tag reveal">section</span>
                <h2 class="ent-title reveal title-balance"><span class="title-line">AI 原生产研的核心不是替</span><span class="title-line">代人，而是把“探索、规划、执</span><span class="title-line">行、验证”做成可复用闭环</span></h2>
                <div class="ent-sep reveal"></div>
                <div class="ent-split-label">外部最佳实践都指向同一件事：先探索</div><div class="ent-split-label">再规划</div><div class="ent-split-label">后执行</div>
            </div>
            <div class="slide-content">
                <div class="ent-kpi-card">
                    
        <div class="ent-feature-row reveal">
            <div class="ent-feature-icon">1</div>
            <div style="flex:1;">
                <h3 style="margin:0 0 6px;color:var(--text-primary);font-size:1rem;">公开趋势：AI使用深度决定收益</h3>
                <p style="margin:0;color:var(--text-body);font-size:0.92rem;line-height:1.5;">探索规划执行验证四段闭环</p>
                <div class="ent-prog-bar" style="margin-top:10px;"><div class="ent-prog-fill" style="width:70%"></div></div>
            </div>
            <span class="ent-badge ent-badge-blue">Flow</span>
        </div>
        
        <div class="ent-feature-row reveal">
            <div class="ent-feature-icon">2</div>
            <div style="flex:1;">
                <h3 style="margin:0 0 6px;color:var(--text-primary);font-size:1rem;">集团方向：企业管理AI公司</h3>
                <p style="margin:0;color:var(--text-body);font-size:0.92rem;line-height:1.5;">探索规划执行验证四段闭环</p>
                <div class="ent-prog-bar" style="margin-top:10px;"><div class="ent-prog-fill" style="width:55%"></div></div>
            </div>
            <span class="ent-badge ent-badge-blue">Flow</span>
        </div>
        
        <div class="ent-feature-row reveal">
            <div class="ent-feature-icon">3</div>
            <div style="flex:1;">
                <h3 style="margin:0 0 6px;color:var(--text-primary);font-size:1rem;">组织底座：数据治理、评测、AI champions</h3>
                <p style="margin:0;color:var(--text-body);font-size:0.92rem;line-height:1.5;">探索规划执行验证四段闭环</p>
                <div class="ent-prog-bar" style="margin-top:10px;"><div class="ent-prog-fill" style="width:40%"></div></div>
            </div>
            <span class="ent-badge ent-badge-blue">Flow</span>
        </div>
        
                </div>
            </div>
        </div>
        <span class="slide-num-label">05 / 12</span>
    </section>

<section class="slide enterprise-matrix" id="slide-6" data-notes="feature: 需求澄清、方案设计、设计出稿、开发实现、测试回归、上线复盘都应该有明确的AI默认动作与人工审批点" aria-label="feature" data-export-role="comparison_matrix">
        <div class="slide-content">
            <div class="ent-shell">
                <span class="ent-label-tag reveal">comparison</span>
                <h2 class="ent-title reveal title-balance"><span class="title-line">云之家现有产研主链路可</span><span class="title-line">以不推倒重来，但每个环</span><span class="title-line">节都要插入 AI 默认动作</span></h2>
                <div class="ent-sep reveal"></div>
                <div class="ent-matrix">
        <div class="ent-kpi-card reveal">
            <div class="ent-label">需求输入</div>
            <h3 style="margin:8px 0;color:var(--text-primary);">Opportunity Brief</h3>
            <p style="margin:0;color:var(--text-body);line-height:1.5;">汇总访谈、工单、商机和反馈，聚类痛点并生成一页式问题定义。</p>
        </div>
        
        <div class="ent-kpi-card reveal">
            <div class="ent-label">方案设计</div>
            <h3 style="margin:8px 0;color:var(--text-primary);">ADR + 风险清单</h3>
            <p style="margin:0;color:var(--text-body);line-height:1.5;">生成候选方案、接口变更点、风险列表与回滚预案，再进入架构评审。</p>
        </div>
        
        <div class="ent-kpi-card reveal">
            <div class="ent-label">开发与测试</div>
            <h3 style="margin:8px 0;color:var(--text-primary);">Task Pack + Test Matrix</h3>
            <p style="margin:0;color:var(--text-body);line-height:1.5;">拆任务、补单测、生成联调脚本与回归矩阵，把执行和验证放在同一闭环里。</p>
        </div>
        
        <div class="ent-kpi-card reveal">
            <div class="ent-label">发布与复盘</div>
            <h3 style="margin:8px 0;color:var(--text-primary);">Release Pack + Postmortem</h3>
            <p style="margin:0;color:var(--text-body);line-height:1.5;">生成变更说明、灰度策略、监控项与异常聚类结果，把经验沉淀成下一轮模板。</p>
        </div>
        </div>
            </div>
        </div>
        <span class="slide-num-label">06 / 12</span>
    </section>

<section class="slide enterprise-matrix" id="slide-7" data-notes="features: 角色不会消失，但职责会迁移到问题定义、上下文组织、智能体编排、结果校验和风险兜底上" aria-label="features" data-export-role="comparison_matrix">
        <div class="slide-content">
            <div class="ent-shell">
                <span class="ent-label-tag reveal">comparison</span>
                <h2 class="ent-title reveal title-balance"><span class="title-line">产品、设计、研发、测试、项</span><span class="title-line">目经理要从“单点交付”转</span><span class="title-line">向“任务编排+结果验收”</span></h2>
                <div class="ent-sep reveal"></div>
                <div class="ent-matrix">
        <div class="ent-kpi-card reveal">
            <div class="ent-label">产品经理</div>
            <h3 style="margin:8px 0;color:var(--text-primary);">问题定义与验收 owner</h3>
            <p style="margin:0;color:var(--text-body);line-height:1.5;">把需求、目标、优先级与验收标准说清楚，让人和智能体理解同一个问题。</p>
        </div>
        
        <div class="ent-kpi-card reveal">
            <div class="ent-label">设计师</div>
            <h3 style="margin:8px 0;color:var(--text-primary);">方案生成与交互验证</h3>
            <p style="margin:0;color:var(--text-body);line-height:1.5;">快速生成多版方案、组件状态和文案，再用反馈回路收敛成可复用设计系统。</p>
        </div>
        
        <div class="ent-kpi-card reveal">
            <div class="ent-label">研发工程师</div>
            <h3 style="margin:8px 0;color:var(--text-primary);">智能体编排与代码审查</h3>
            <p style="margin:0;color:var(--text-body);line-height:1.5;">负责任务拆解、架构边界、自动验证和风险兜底，而不是只盯着手工实现细节。</p>
        </div>
        
        <div class="ent-kpi-card reveal">
            <div class="ent-label">QA / 项目经理</div>
            <h3 style="margin:8px 0;color:var(--text-primary);">评测与节奏 owner</h3>
            <p style="margin:0;color:var(--text-body);line-height:1.5;">维护评测集、发布门禁和周月看板节奏，让 AI 从个人技巧变成团队系统能力。</p>
        </div>
        </div>
            </div>
        </div>
        <span class="slide-num-label">07 / 12</span>
    </section>

<section class="slide enterprise-table" id="slide-8" data-notes="evidence: 首批试点必须高频、低耦合、容易验证，先在三个闭环拿到速度、质量和可复制性，再扩面" aria-label="evidence" data-export-role="data_table">
        <div class="slide-content">
            <div class="ent-shell">
                <span class="ent-label-tag reveal">evidence</span>
                <h2 class="ent-title reveal title-balance"><span class="title-line">第一批场景不要贪大，先</span><span class="title-line">打透需求分析、研发提效</span><span class="title-line">、测试回归三个高频闭环</span></h2>
                <div class="ent-sep reveal"></div>
                <table class="ent-table reveal">
                    <thead><tr><th>Signal</th><th>Meaning</th><th>State</th></tr></thead>
                    <tbody><tr><td><span class="ent-status-dot ent-dot-green"></span>需求洞察自动化</td><td>访谈、工单、商机和竞品信息先压缩成一页问题定义，再进入需求评审。</td><td><span class="ent-badge ent-badge-green">pilot</span></td></tr><tr><td><span class="ent-status-dot ent-dot-blue"></span>研发实现提效</td><td>代码、文档、单测和联调脚本在同一上下文里生成并验证，减少重复劳动。</td><td><span class="ent-badge ent-badge-blue">pilot</span></td></tr><tr><td><span class="ent-status-dot ent-dot-red"></span>测试回归自动化</td><td>测试矩阵、回归脚本与发布检查表可重复执行，先拿到稳定可验证的收益。</td><td><span class="ent-badge ent-badge-blue">pilot</span></td></tr></tbody>
                </table>
            </div>
        </div>
        <span class="slide-num-label">08 / 12</span>
    </section>

<section class="slide enterprise-dashboard" id="slide-9" data-notes="metrics: 知识沉淀、接口治理、数据分级、评测集、过程指标和结果指标必须先建起来，速度才不会反噬质量" aria-label="metrics" data-export-role="kpi_dashboard">
        <div class="slide-content">
            <div class="ent-shell">
                <span class="ent-label-tag reveal">AI landscape</span>
                <h1 class="ent-hero-title reveal title-balance"><span class="title-line ent-accent-blue">没有评测和数据治理</span><span class="title-line ent-accent-blue">的 AI 转型只会制造更</span><span class="title-line ent-accent-blue">多“看起来很快”的返工</span></h1>
                <div class="ent-sep reveal"></div>
                <p class="ent-kpi-meta reveal">知识沉淀、接口治理、数据分级、评测集、过程指标和结果指标必须先建起来，速度才不会反噬质量</p>
                <div class="ent-kpi-row">
                    
            <div class="ent-kpi-card reveal">
                <div class="ent-kpi-number positive">3</div>
                <div class="ent-kpi-label">三类底座</div>
                <div class="ent-trend up">▲ 知识、数据、评测缺一不可</div>
            </div>
            
            <div class="ent-kpi-card reveal">
                <div class="ent-kpi-number neutral">2</div>
                <div class="ent-kpi-label">两类指标</div>
                <div class="ent-trend up">▲ 过程指标与结果指标要同时看</div>
            </div>
            
            <div class="ent-kpi-card reveal">
                <div class="ent-kpi-number positive">1</div>
                <div class="ent-kpi-label">一套门禁</div>
                <div class="ent-trend up">▲ 权限、审批、留痕必须内建</div>
            </div>
            
                </div>
            </div>
        </div>
        <span class="slide-num-label">09 / 12</span>
    </section>

<section class="slide enterprise-timeline" id="slide-10" data-notes="timeline: 先打通试点，再沉淀模板和指标，最后扩展到团队级默认流程，用小闭环滚出组织信心" aria-label="timeline" data-export-role="timeline">
        <div class="slide-content">
            <div class="ent-shell">
                <span class="ent-label-tag reveal">timeline</span>
                <h2 class="ent-title reveal title-balance"><span class="title-line">30-60-90 天推进法比“</span><span class="title-line">大跃进式全员铺开”更</span><span class="title-line">容易形成组织正反馈</span></h2>
                <div class="ent-sep reveal"></div>
                <div class="ent-timeline">
            <div class="ent-timeline-item reveal">
                <div class="ent-timeline-dot"></div>
                <div class="ent-timeline-date">30</div>
                <div class="ent-timeline-copy">先打通试点</div>
            </div>
            
            <div class="ent-timeline-item reveal">
                <div class="ent-timeline-dot"></div>
                <div class="ent-timeline-date">60</div>
                <div class="ent-timeline-copy">再沉淀模板和指标</div>
            </div>
            
            <div class="ent-timeline-item reveal">
                <div class="ent-timeline-dot"></div>
                <div class="ent-timeline-date">90</div>
                <div class="ent-timeline-copy">最后扩展到团队级默认流程</div>
            </div>
            
            <div class="ent-timeline-item reveal">
                <div class="ent-timeline-dot"></div>
                <div class="ent-timeline-date">120</div>
                <div class="ent-timeline-copy">把 AI 指标纳入经营节奏并形成样板间</div>
            </div>
            </div>
            </div>
        </div>
        <span class="slide-num-label">10 / 12</span>
    </section>

<section class="slide enterprise-timeline" id="slide-11" data-notes="checkpoint: 日会、周会、复盘会、月度经营会都要纳入AI使用率、模板复用率、评测通过率和场景ROI" aria-label="checkpoint" data-export-role="timeline">
        <div class="slide-content">
            <div class="ent-shell">
                <span class="ent-label-tag reveal">timeline</span>
                <h2 class="ent-title reveal title-balance"><span class="title-line">周节奏和月节奏必须改</span><span class="title-line">掉，否则 AI 会停留在个</span><span class="title-line">人技巧而不是组织能力</span></h2>
                <div class="ent-sep reveal"></div>
                <div class="ent-timeline">
            <div class="ent-timeline-item reveal">
                <div class="ent-timeline-dot"></div>
                <div class="ent-timeline-date">日</div>
                <div class="ent-timeline-copy">站会同步 AI 使用、阻塞与上下文缺口</div>
            </div>
            
            <div class="ent-timeline-item reveal">
                <div class="ent-timeline-dot"></div>
                <div class="ent-timeline-date">周</div>
                <div class="ent-timeline-copy">项目周会检查模板复用率与评测通过率</div>
            </div>
            
            <div class="ent-timeline-item reveal">
                <div class="ent-timeline-dot"></div>
                <div class="ent-timeline-date">版</div>
                <div class="ent-timeline-copy">版本复盘沉淀经验、更新模板和门禁规则</div>
            </div>
            
            <div class="ent-timeline-item reveal">
                <div class="ent-timeline-dot"></div>
                <div class="ent-timeline-date">月</div>
                <div class="ent-timeline-copy">经营会跟踪 ROI、扩面节奏和样板间复制进展</div>
            </div>
            </div>
            </div>
        </div>
        <span class="slide-num-label">11 / 12</span>
    </section>

<section class="slide enterprise-close" id="slide-12" data-notes="closing: 从同一入口、同一评测、同一方法开始，先在云之家跑通，再复制到集团更多业务与管理场景" aria-label="closing" data-export-role="cta_close">
        <div class="slide-content">
            <div class="ent-shell">
                <span class="ent-label-tag reveal">close</span>
                <h2 class="ent-hero-title reveal title-balance"><span class="title-line ent-accent-blue">云之家要交付的不是一个工</span><span class="title-line ent-accent-blue">具包，而是一套能复制到金</span><span class="title-line ent-accent-blue">蝶全集团的 AI 原生样板间</span></h2>
                <div class="ent-sep reveal"></div>
                <div class="ent-code reveal"><span class="green">thesis</span> = 从同一入口、同一评测、同一方法开始，先在云之家跑通，再复制到集团更多业务与管理场景</div>
                <div class="ent-kpi-row" style="margin-top:18px;">
                    <div class="ent-kpi-card reveal"><div class="ent-kpi-number neutral">3</div><div class="ent-kpi-label">首批试点闭环</div></div>
                    <div class="ent-kpi-card reveal"><div class="ent-kpi-number neutral">1</div><div class="ent-kpi-label">统一入口方法</div></div>
                    <div class="ent-kpi-card reveal"><div class="ent-kpi-number positive">90天</div><div class="ent-kpi-label">形成可复制样板</div></div>
                </div>
            </div>
        </div>
        <span class="slide-num-label">12 / 12</span>
    </section>
<script>
class SlidePresentation {
    constructor() {
        this.slides = document.querySelectorAll('.slide');
        this.currentSlide = 0;
        this.channel = new BroadcastChannel('slide-creator-presenter');
        this.slides[0]?.classList.add('visible');
        this.slides[0]?.querySelectorAll('.reveal').forEach(function(r) { r.classList.add('visible'); });
        this.setupNavDots(); this.setupObserver(); this.setupKeyboard();
        this.setupTouch(); this.setupWheel(); this.setupPresenter(); this.setupEditor(); this.updateProgress();
    }

    setupNavDots() {
        const nav = document.querySelector('.nav-dots');
        if (!nav) return;
        this.slides.forEach((_, i) => {
            const dot = document.createElement('button');
            dot.setAttribute('aria-label', 'Go to slide ' + (i + 1));
            dot.style.cssText = 'width:8px;height:8px;border-radius:50%;border:none;cursor:pointer;background:rgba(255,255,255,0.3);transition:all 0.3s;';
            dot.addEventListener('click', () => this.goTo(i)); nav.appendChild(dot);
        });
        nav.style.cssText = 'position:fixed;right:1.5rem;top:50%;transform:translateY(-50%);display:flex;flex-direction:column;gap:8px;z-index:100;';
    }

    setupObserver() {
        const observer = new IntersectionObserver((entries) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    entry.target.classList.add('visible');
                    this.currentSlide = [...this.slides].indexOf(entry.target);
                    this.updateProgress(); this.updateDots(); this.broadcastState();
                    this.updateNotesPanel();
                }
            });
        }, { threshold: 0.5 });
        this.slides.forEach(s => observer.observe(s));
    }

    setupKeyboard() {
        document.addEventListener('keydown', (e) => {
            if (e.target.getAttribute('contenteditable') || e.target.tagName === 'TEXTAREA') return;
            if (['ArrowDown','ArrowRight',' ','PageDown','Enter'].includes(e.key)) { e.preventDefault(); this.next(); }
            else if (['ArrowUp','ArrowLeft','PageUp','Backspace'].includes(e.key)) { e.preventDefault(); this.prev(); }
            else if (e.key === 'p' || e.key === 'P') { window.open(location.href.split('?')[0] + '?presenter', 'slide-presenter-' + Date.now(), 'width=1100,menubar=no,toolbar=no,location=no'); }
            else if (e.key === 'e' || e.key === 'E') { if (this.editor && !this.editor.active) this.editor.enter(); else if (this.editor && this.editor.active) this.editor.exit(); }
        });
    }

    setupTouch() {
        let startY = 0, startX = 0;
        document.addEventListener('touchstart', e => { startY = e.touches[0].clientY; startX = e.touches[0].clientX; }, { passive: true });
        document.addEventListener('touchend', e => {
            const dy = startY - e.changedTouches[0].clientY;
            const dx = Math.abs(startX - e.changedTouches[0].clientX);
            if (Math.abs(dy) > 50 && Math.abs(dy) > dx * 1.2) dy > 0 ? this.next() : this.prev();
        });
    }

    setupWheel() {}

    setupPresenter() {
        this.channel.addEventListener('message', e => {
            if (e.data.type === 'nav-next') this.next();
            else if (e.data.type === 'nav-prev') this.prev();
            else if (e.data.type === 'request-state') this.broadcastState();
        });
    }

    broadcastState() {
        const slide = this.slides[this.currentSlide];
        this.channel.postMessage({ type: 'state', index: this.currentSlide, total: this.slides.length, notes: slide?.dataset.notes || '' });
    }

    goTo(index) {
        const idx = Math.max(0, Math.min(index, this.slides.length - 1));
        this.slides.forEach((s, i) => s.classList.toggle('visible', i === idx));
        this.slides[idx]?.scrollIntoView({ behavior: 'smooth' });
    }
    next() { this.goTo(Math.min(this.currentSlide + 1, this.slides.length - 1)); }
    prev() { this.goTo(Math.max(this.currentSlide - 1, 0)); }

    updateProgress() {
        const pct = (this.currentSlide / (this.slides.length - 1)) * 100;
        const bar = document.querySelector('.progress-bar');
        if (bar) bar.style.width = pct + '%';
    }

    updateDots() {
        document.querySelectorAll('.nav-dots button').forEach((dot, i) => {
            dot.style.background = i === this.currentSlide ? 'var(--accent)' : 'rgba(255,255,255,0.3)';
            dot.style.transform = i === this.currentSlide ? 'scale(1.3)' : 'scale(1)';
        });
    }

    setupEditor() {
        const panel = document.getElementById('notes-panel');
        const label = document.getElementById('notes-panel-label');
        const textarea = document.getElementById('notes-textarea');
        const toggle = document.getElementById('editToggle');
        const hotzone = document.querySelector('.edit-hotzone');
        let hideTimeout = null;

        hotzone.addEventListener('mouseenter', () => { clearTimeout(hideTimeout); toggle.classList.add('show'); });
        hotzone.addEventListener('mouseleave', () => { hideTimeout = setTimeout(() => { if (this.editor.active) return; toggle.classList.remove('show'); }, 400); });
        toggle.addEventListener('mouseenter', () => clearTimeout(hideTimeout));
        toggle.addEventListener('mouseleave', () => { hideTimeout = setTimeout(() => { if (this.editor.active) return; toggle.classList.remove('show'); }, 400); });
        hotzone.addEventListener('click', () => this.editor.toggle());
        toggle.addEventListener('click', () => this.editor.toggle());

        document.getElementById('notes-panel-header').addEventListener('click', () => panel.classList.toggle('collapsed'));

        textarea.addEventListener('input', () => {
            const slide = this.slides[this.currentSlide];
            if (slide) { slide.dataset.notes = textarea.value; this.broadcastState(); }
        });

        document.addEventListener('keydown', (e) => {
            if ((e.ctrlKey || e.metaKey) && e.key === 's') { e.preventDefault(); this.saveFile(); }
        });

        this.editor = {
            active: false,
            toggle: () => this.editor.active ? this.editor.exit() : this.editor.enter(),
            enter: () => {
                this.editor.active = true;
                toggle.classList.add('active'); toggle.textContent = 'Done';
                this.slides.forEach(s => s.querySelectorAll('h1,h2,h3,p,li,span,td,th').forEach(el => {
                    el.setAttribute('contenteditable', 'true'); el.style.outline = 'none';
                }));
                panel.classList.add('active'); this.updateNotesPanel();
            },
            exit: () => {
                this.editor.active = false;
                toggle.classList.remove('active'); toggle.textContent = 'Edit';
                this.slides.forEach(s => s.querySelectorAll('[contenteditable]').forEach(el => {
                    el.removeAttribute('contenteditable'); el.style.outline = '';
                }));
                panel.classList.remove('active');
            }
        };
        this._notesLabel = label; this._notesTextarea = textarea;
    }

    updateNotesPanel() {
        if (!this.editor?.active) return;
        const slide = this.slides[this.currentSlide];
        this._notesLabel.textContent = 'SPEAKER NOTES \u2014 SLIDE ' + (this.currentSlide + 1) + ' / ' + this.slides.length;
        this._notesTextarea.value = slide?.dataset.notes || '';
    }

    saveFile() {
        const html = '<!DOCTYPE html>\n' + document.documentElement.outerHTML;
        const bytes = new TextEncoder().encode(html);
        fetch(location.pathname, { method: 'PUT', body: bytes, headers: { 'Content-Type': 'text/html' } })
            .catch(() => {
                const a = Object.assign(document.createElement('a'), {
                    href: URL.createObjectURL(new Blob([html], { type: 'text/html' })),
                    download: location.pathname.split('/').pop() || 'presentation.html'
                }); a.click(); URL.revokeObjectURL(a.href);
            });
    }
}

if (new URLSearchParams(location.search).has('presenter')) {
    document.title = 'Presenter \u2014 ' + document.title;
    document.body.innerHTML = `
    <style>
        * { box-sizing: border-box; margin: 0; }
        body { background: #111; color: #fff; font-family: system-ui, sans-serif; }
        #pv { display: grid; grid-template-columns: 1fr 220px; gap: 1rem; padding: 1.25rem; align-items: start; }
        .pv-panel { background: #1e1e1e; border-radius: 12px; padding: 1.25rem; }
        #pv-label { font-size: 0.6rem; letter-spacing: 0.18em; text-transform: uppercase; color: #555; margin-bottom: 0.6rem; }
        #pv-notes { font-size: 1.05rem; line-height: 1.85; color: #d0d0d0; }
        #pv-right { display: flex; flex-direction: column; gap: 1rem; }
        #pv-nav { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
        .pv-arrow { width: 32px; height: 32px; border-radius: 6px; border: 1px solid #333; background: #2a2a2a; color: #aaa; font-size: 1rem; cursor: pointer; display: flex; align-items: center; justify-content: center; }
        .pv-arrow:hover { background: #383838; color: #fff; }
        #pv-counter { text-align: center; flex: 1; }
        #pv-num { font-size: 1.6rem; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1; }
        #pv-of { color: #555; font-size: 0.75rem; margin-top: 0.2rem; }
        #pv-timer { font-size: 1.5rem; font-weight: 700; font-family: monospace; font-variant-numeric: tabular-nums; }
        #pv-timer-label { font-size: 0.6rem; letter-spacing: 0.18em; text-transform: uppercase; color: #555; }
    </style>
    <div id="pv">
        <div class="pv-panel"><div id="pv-label">Speaker Notes</div><div id="pv-notes">Waiting for main window...</div></div>
        <div id="pv-right">
            <div class="pv-panel"><div id="pv-nav">
                <button class="pv-arrow" id="pv-prev">\u2190</button>
                <div id="pv-counter"><div id="pv-num">\u2014</div><div id="pv-of">/ \u2014</div></div>
                <button class="pv-arrow" id="pv-next">\u2192</button>
            </div></div>
            <div class="pv-panel"><div id="pv-timer-label">Elapsed</div><div id="pv-timer">0:00</div></div>
        </div>
    </div>`;

    const ch = new BroadcastChannel('slide-creator-presenter');
    let startTime = null;
    const pv = document.getElementById('pv');
    let lastH = 0, roTimer = null;
    new ResizeObserver(() => {
        clearTimeout(roTimer);
        roTimer = setTimeout(() => {
            const h = Math.ceil(pv.getBoundingClientRect().height);
            if (h === lastH) return;
            lastH = h;
            const chrome = window.outerHeight - window.innerHeight;
            window.resizeTo(window.outerWidth, Math.max(260, h + chrome + 4));
        }, 40);
    }).observe(pv);

    ch.addEventListener('message', e => {
        if (e.data.type !== 'state') return;
        if (!startTime) startTime = Date.now();
        document.getElementById('pv-notes').textContent = e.data.notes || '(no notes for this slide)';
        document.getElementById('pv-num').textContent = e.data.index + 1;
        document.getElementById('pv-of').textContent = '/ ' + e.data.total;
    });
    ch.postMessage({ type: 'request-state' });

    setInterval(() => {
        if (!startTime) return;
        const s = Math.floor((Date.now() - startTime) / 1000);
        document.getElementById('pv-timer').textContent = Math.floor(s / 60) + ':' + String(s % 60).padStart(2, '0');
    }, 1000);

    document.getElementById('pv-prev').addEventListener('click', () => ch.postMessage({ type: 'nav-prev' }));
    document.getElementById('pv-next').addEventListener('click', () => ch.postMessage({ type: 'nav-next' }));
    document.addEventListener('keydown', e => {
        if (e.key === 'ArrowRight' || e.key === 'ArrowDown' || e.key === ' ' || e.key === 'PageDown' || e.key === 'Enter') ch.postMessage({ type: 'nav-next' });
        else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp' || e.key === 'PageUp' || e.key === 'Backspace') ch.postMessage({ type: 'nav-prev' });
    });

} else {
// PresentMode class goes here, then: new PresentMode(new SlidePresentation());

class PresentMode {
    constructor(ctrl) {
        this.ctrl = ctrl;
        this.baseW = 1440; this.baseH = 900;
        this.active = false;
        const btn = document.createElement('button');
        btn.id = 'present-btn'; btn.title = 'Present (F5)'; btn.setAttribute('aria-label', 'Present'); btn.textContent = '\u25B6';
        document.body.appendChild(btn);
        const counter = document.createElement('div');
        counter.id = 'present-counter'; document.body.appendChild(counter);
        btn.addEventListener('click', () => this.enter());
        document.addEventListener('keydown', e => {
            if (e.key === 'F5') { e.preventDefault(); this.enter(); }
            if (e.key === 'Escape' && this.active) this.exit();
            if ((e.key === 'b' || e.key === 'B') && this.active) document.body.classList.toggle('presenting-black');
        });
        document.addEventListener('fullscreenchange', () => { if (this.active) { setTimeout(() => this._scale(), 100); } if (!document.fullscreenElement && this.active) this.exit(); });
        window.addEventListener('resize', () => { if (this.active) this._scale(); });
    }
    enter() {
        if (this.active) return;
        this.active = true;
        document.body.classList.add('presenting');
        if (document.documentElement.requestFullscreen) document.documentElement.requestFullscreen().catch(() => {});
        this._scale();
        this._show(this.ctrl.currentSlide);
        this._updateCounter();
        this._origGoTo = this.ctrl.goTo.bind(this.ctrl);
        this.ctrl.goTo = (i) => {
            const idx = Math.max(0, Math.min(i, this.ctrl.slides.length - 1));
            this.ctrl.currentSlide = idx;
            this.ctrl.slides.forEach((s, j) => s.classList.toggle('visible', j === idx));
            this._show(idx);
            this.ctrl.updateProgress?.();
            this.ctrl.updateDots?.();
            this.ctrl.broadcastState?.();
        };
    }
    exit() {
        if (!this.active) return;
        this.active = false;
        document.body.classList.remove('presenting', 'presenting-black');
        this._reset();
        if (document.fullscreenElement) document.exitFullscreen?.();
        if (this._origGoTo) { this.ctrl.goTo = this._origGoTo; this._origGoTo = null; }
        this.ctrl.slides[this.ctrl.currentSlide]?.scrollIntoView({ behavior: 'instant' });
    }
    _scale() {
        const vw = window.innerWidth;
        const vh = window.innerHeight;
        const s = Math.min(vw / this.baseW, vh / this.baseH);
        const ox = (vw - this.baseW * s) / 2;
        const oy = (vh - this.baseH * s) / 2;
        this.ctrl.slides.forEach(slide => {
            slide.style.transform = 'translate(' + ox + 'px, ' + oy + 'px) scale(' + s + ')';
        });
    }
    _reset() {
        this.ctrl.slides.forEach(slide => { slide.style.transform = ''; slide.classList.remove('p-on'); });
    }
    _show(i) {
        this.ctrl.slides.forEach((s, idx) => s.classList.toggle('p-on', idx === i));
    }
    _updateCounter() {
        const c = document.getElementById('present-counter');
        if (c) c.textContent = (this.ctrl.currentSlide + 1) + ' / ' + this.ctrl.slides.length;
    }
}
new PresentMode(new SlidePresentation());
}

(function() {
    var slides = document.querySelectorAll('.slide');
    if (!slides.length) return;
    var last = slides[slides.length - 1];
    var credit = document.createElement('div');
    credit.className = 'slide-credit';
    credit.textContent = 'By kai-slide-creator v[version] · [preset-name]';
    last.appendChild(credit);
})();
</script>
</body>
</html>


path: contracts/slide_creator/source_snapshot/demos/aurora-mesh-en.html
content: <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>kai-slide-creator — Zero-Dependency HTML Presentation Generator</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;600;700&family=DM+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>

/* ═══════════════════════════════════════════════
   AURORA MESH DESIGN TOKENS
   ═══════════════════════════════════════════════ */
:root {
  --bg:          #0a0a1a;
  --accent:      #00f5c4;
  --accent-rgb:   0,245,196;
  --text:        #ffffff;
  --text-body:   rgba(255,255,255,0.70);
  --text-m:      rgba(255,255,255,0.45);
  --card-bg:     rgba(255,255,255,0.05);
  --card-border: rgba(255,255,255,0.10);
  --divider:     rgba(255,255,255,0.15);

  /* Typography */
  --font-display: 'Space Grotesk', sans-serif;
  --font-body: 'DM Sans', system-ui, sans-serif;
  --title-size: clamp(1.8rem, 5vw, 4rem);
  --subtitle-size: clamp(0.85rem, 1.5vw, 1.2rem);
  --body-size: clamp(0.75rem, 1.3vw, 0.95rem);
  --slide-padding: clamp(1.5rem, 4vw, 4rem);
  --content-gap: clamp(1rem, 2vw, 2rem);

  /* Animation */
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --duration-normal: 0.7s;
  --text-primary: var(--text);
  --text-secondary: var(--text-m);
  --bg-primary: var(--bg);
}

::selection { background: rgba(0,245,196,0.30); color: #00f5c4; }

/* Reset */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

html {
  scroll-snap-type: y mandatory;
  height: 100%;
}

body {
  font-family: var(--font-body);
  color: var(--text);
  height: 100%;
  background-color: #0a0a1a;
  background-image:
    radial-gradient(ellipse at 20% 50%, rgba(120,40,200,0.40) 0%, transparent 60%),
    radial-gradient(ellipse at 80% 20%, rgba(0,180,255,0.30) 0%, transparent 50%),
    radial-gradient(ellipse at 60% 80%, rgba(0,255,180,0.20) 0%, transparent 50%);
  animation: auroraDrift 20s ease-in-out infinite alternate;
  background-size: 200% 200%;
}
@keyframes auroraDrift {
  0%   { background-position: 0% 50%; }
  33%  { background-position: 50% 20%; }
  66%  { background-position: 80% 80%; }
  100% { background-position: 100% 50%; }
}

/* ── Slide Container ── */
.slide {
  width: 100vw;
  height: 100vh;
  height: 100dvh;
  padding: var(--slide-padding);
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  justify-content: center;
  position: relative;
  overflow: hidden;
  background: transparent;
}

.slide-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  max-height: 100%;
  overflow: hidden;
  max-width: min(90vw, 1000px);
  position: relative;
  z-index: 1;
}

/* ── Typography ── */
.a-title {
  font-family: var(--font-display);
  font-size: var(--title-size);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: #fff;
}

.a-h2 {
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 3.5vw, 2.5rem);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: #fff;
  line-height: 1.2;
  margin-bottom: clamp(0.5rem, 1.5vw, 1rem);
}

.a-subtitle {
  font-size: var(--subtitle-size);
  color: var(--text-body);
  line-height: 1.6;
  margin-top: 0.5rem;
}

.a-body {
  font-size: var(--body-size);
  color: var(--text-body);
  line-height: 1.7;
}

.a-label {
  font-size: clamp(0.6rem, 1vw, 0.7rem);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
}

.a-accent { color: var(--accent); font-weight: 600; }

/* ── Components ── */
.g {
  background: rgba(255,255,255,0.05);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(255,255,255,0.10);
  border-radius: 16px;
  padding: clamp(14px, 2.5vw, 24px);
}

.stat { text-align: center; padding: clamp(12px, 2vw, 20px); }
.stat .num {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 3vw, 2.5rem);
  font-weight: 700;
  background: linear-gradient(135deg, #00f5c4, #00b4d8);
  -webkit-background-clip: text; -webkit-text-fill-color: transparent;
  background-clip: text;
}
.stat .label {
  font-size: clamp(0.6rem, 1vw, 0.75rem);
  color: var(--text-m);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-top: 4px;
}

.pill {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 14px; border-radius: 9999px;
  font-size: clamp(0.6rem, 1vw, 0.7rem);
  font-weight: 600; letter-spacing: 0.12em;
  text-transform: uppercase;
  background: rgba(var(--accent-rgb),0.12);
  border: 1px solid rgba(var(--accent-rgb),0.30);
  color: var(--accent);
}

kbd {
  display: inline-block; padding: 2px 8px;
  font-size: 0.8em; font-weight: 600;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.20);
  border-radius: 6px;
  color: var(--accent);
  vertical-align: middle;
}

.co, .info-callout {
  padding: clamp(8px, 1.5vw, 14px) clamp(12px, 2vw, 18px);
  border-radius: 10px;
  font-size: clamp(0.65rem, 1.1vw, 0.8rem);
  line-height: 1.6;
}
.co {
  background: rgba(var(--accent-rgb),0.08);
  border-left: 3px solid var(--accent);
  color: rgba(255,255,255,0.80);
}
.info-callout {
  background: rgba(0,180,255,0.08);
  border-left: 3px solid #00b4d8;
  color: rgba(255,255,255,0.80);
}

.cmd {
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 10px;
  padding: clamp(8px, 1.5vw, 14px) clamp(12px, 2vw, 18px);
  font-family: var(--font-display), monospace;
  font-size: clamp(0.7rem, 1.2vw, 0.9rem);
  color: var(--accent);
  line-height: 1.6;
}
.cmd::before { content: '> '; color: var(--text-m); }

.layer {
  display: flex; gap: 16px;
  padding: clamp(8px, 1.2vw, 12px) 0;
  border-bottom: 1px solid rgba(255,255,255,0.08);
  align-items: flex-start;
}
.layer:last-child { border-bottom: none; }
.layer-num {
  font-family: var(--font-display);
  font-size: 0.75rem; font-weight: 700;
  color: var(--accent);
  min-width: 24px;
}

.cols2 { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(12px, 2vw, 20px); }
.cols3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(12px, 2vw, 20px); }
.cols4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(8px, 1.5vw, 16px); }

.bento {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: minmax(60px, auto);
  gap: clamp(8px, 1.5vw, 14px);
}
.bento .span2 { grid-column: span 2; }

.a-divider { height: 1px; background: rgba(255,255,255,0.15); margin: clamp(12px, 2vw, 20px) 0; }

.step { position: relative; padding-left: 32px; }
.step::before {
  content: attr(data-step);
  position: absolute; left: 0; top: 0;
  font-size: 0.65rem; font-weight: 700;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

/* ── Reveal animations ── */
.reveal {
  opacity: 0; transform: translateY(20px);
  transition: opacity var(--duration-normal) var(--ease-out-expo),
              transform var(--duration-normal) var(--ease-out-expo);
}
.slide.visible .reveal { opacity: 1; transform: translateY(0); }
.reveal:nth-child(1) { transition-delay: 0.05s; }
.reveal:nth-child(2) { transition-delay: 0.15s; }
.reveal:nth-child(3) { transition-delay: 0.25s; }
.reveal:nth-child(4) { transition-delay: 0.35s; }

.chapter-num {
  font-family: var(--font-display);
  font-size: clamp(3rem, 10vw, 8rem);
  font-weight: 700;
  background: linear-gradient(135deg, rgba(var(--accent-rgb),0.3), rgba(120,40,200,0.2));
  -webkit-background-clip: text; -webkit-text-fill-color: transparent;
  background-clip: text;
  line-height: 1;
}

.a-eof {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 4vw, 3rem);
  font-weight: 700;
  background: linear-gradient(135deg, #00f5c4, #00b4d8);
  -webkit-background-clip: text; -webkit-text-fill-color: transparent;
  background-clip: text;
  text-align: center;
}
.a-eof-sub {
  font-size: clamp(0.75rem, 1.5vw, 1rem);
  color: var(--text-m);
  text-align: center;
  margin-top: 8px;
}

.a-table {
  width: 100%; border-collapse: collapse;
  font-size: clamp(0.65rem, 1.1vw, 0.8rem);
}
.a-table th {
  text-align: left; padding: 8px 12px;
  border-bottom: 1px solid rgba(255,255,255,0.15);
  color: var(--accent); font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.08em;
  font-size: clamp(0.55rem, 1vw, 0.7rem);
}
.a-table td {
  padding: 8px 12px;
  border-bottom: 1px solid rgba(255,255,255,0.06);
  color: var(--text-body);
}
.a-table tr:last-child td { border-bottom: none; }

/* ── Responsive ── */
@media (max-height: 700px) {
  :root {
    --slide-padding: clamp(0.75rem, 3vw, 2rem);
    --title-size: clamp(1.2rem, 4vw, 2.5rem);
  }
}
@media (max-height: 600px) {
  :root {
    --slide-padding: clamp(0.5rem, 2.5vw, 1.5rem);
    --title-size: clamp(1rem, 3.5vw, 2rem);
    --body-size: clamp(0.7rem, 1.2vw, 0.95rem);
  }
  .nav-dots, .keyboard-hint, .decorative { display: none; }
}
@media (max-height: 500px) {
  :root {
    --slide-padding: clamp(0.4rem, 2vw, 1rem);
    --title-size: clamp(1rem, 3.5vw, 1.5rem);
  }
}
@media (max-width: 600px) {
  .cols2, .cols3, .cols4, .bento { grid-template-columns: 1fr; }
  .bento .span2 { grid-column: span 1; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.2s !important;
  }
  html { scroll-behavior: auto; }
}

/* ═══════════════════════════════════════════════
   PRESENT MODE CSS
   ═══════════════════════════════════════════════ */
#present-btn {
  position: fixed; bottom: 1.5rem; right: 1.5rem; z-index: 9997;
  width: 44px; height: 44px; border-radius: 50%;
  background: rgba(var(--accent-rgb),0.2); color: var(--accent);
  border: 1.5px solid rgba(var(--accent-rgb),0.4);
  font-size: 1rem; cursor: pointer;
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  display: flex; align-items: center; justify-content: center;
  opacity: 0; transition: opacity 0.2s; pointer-events: none;
}
body:hover #present-btn { opacity: 1; pointer-events: auto; }
#present-btn:hover { background: rgba(var(--accent-rgb),0.35); }

#present-counter {
  display: none; position: fixed; bottom: 1.4rem; left: 50%;
  transform: translateX(-50%); z-index: 9997;
  font-size: 0.65rem; letter-spacing: 0.14em; font-family: var(--font-body);
  color: var(--text-m); opacity: 0.5;
}

body.presenting { background: #000 !important; overflow: hidden !important; }
body.presenting .slide { position: fixed !important; inset: 0; width: 100vw !important; height: 100vh !important; transform-origin: center center; scroll-snap-align: none !important; display: none !important; }
body.presenting .slide.p-on { display: flex !important; }
body.presenting .nav-dots,
body.presenting .keyboard-hint,
body.presenting .slide-credit { display: none !important; }
body.presenting #present-btn { display: none !important; }
body.presenting #present-counter { display: block; }

/* ═══════════════════════════════════════════════
   PROGRESS BAR & NAV DOTS
   ═══════════════════════════════════════════════ */
.progress-bar {
  position: fixed; top: 0; left: 0; height: 3px;
  background: var(--accent); width: 0%; z-index: 100;
  transition: width 0.3s ease;
}

/* ═══════════════════════════════════════════════
   EDIT MODE
   ═══════════════════════════════════════════════ */
.edit-hotzone {
  position: fixed; top: 0; left: 0; width: 48px; height: 48px;
  z-index: 9990; cursor: pointer;
}
.edit-toggle {
  position: fixed; top: 8px; left: 8px; z-index: 9991;
  background: rgba(10,10,26,0.8); backdrop-filter: blur(12px);
  border: 1px solid rgba(255,255,255,0.15);
  border-radius: 6px; padding: 3px 8px;
  font-family: var(--font-body); font-size: 0.65rem;
  color: var(--text-m); cursor: pointer;
  opacity: 0; transition: opacity 0.2s;
}
.edit-hotzone:hover ~ .edit-toggle,
.edit-toggle.show { opacity: 0.6; }
.edit-toggle:hover, .edit-toggle.active { opacity: 1 !important; color: var(--accent); border-color: var(--accent); }

#notes-panel {
  position: fixed; top: 0; right: 0; width: 320px; height: 100vh;
  background: rgba(10,10,26,0.95); backdrop-filter: blur(12px);
  border-left: 1px solid rgba(255,255,255,0.1);
  z-index: 9992; display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform 0.3s ease;
}
.edit-toggle.active ~ #notes-panel,
#notes-panel.active { transform: translateX(0) !important; }
#notes-panel.collapsed #notes-body { display: none; }
#notes-panel-header {
  padding: 8px 12px; border-bottom: 1px solid rgba(255,255,255,0.15);
  cursor: pointer; font-size: 0.65rem; color: var(--text-m);
  text-transform: uppercase; letter-spacing: 0.1em;
  display: flex; align-items: center; justify-content: space-between;
}
#notes-panel-header:hover { background: rgba(255,255,255,0.03); }
#notes-panel-label { flex: 1; }
#notes-collapse-btn {
  font-size: 1rem; color: var(--text-m); background: none; border: none;
  cursor: pointer; transition: transform 0.2s;
}
#notes-panel.collapsed #notes-collapse-btn { transform: rotate(180deg); }
#notes-body { padding: 0 12px 12px; }
#notes-textarea {
  width: 100%; height: 72px; min-height: 48px; max-height: 200px;
  resize: vertical; background: transparent; border: none; outline: none;
  color: var(--text); font-size: 0.75rem; line-height: 1.6;
  font-family: var(--font-body);
}

</style>
</head>
<body data-export-progress="true" data-preset="Aurora Mesh">

<div class="progress-bar"></div>

<nav class="nav-dots" aria-label="Slide navigation"></nav>

<!-- ═══════════════════════ SLIDES ═══════════════════════ -->

<!-- Slide 1: Hero — Full-screen declaration -->
<section class="slide" data-notes="kai-slide-creator product intro, zero dependencies and 21 presets" aria-label="Hero">
  <div class="slide-content" style="text-align: center; align-items: center;">
    <div class="reveal a-label" style="margin-bottom: 8px;">Zero-Dependency HTML Presentations</div>
    <div class="reveal a-title" style="background: linear-gradient(135deg, #fff 30%, rgba(var(--accent-rgb),0.8)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; margin-bottom: 16px;">kai-slide-creator</div>
    <div class="reveal a-subtitle">Three commands. 21 design presets. Pure HTML.<br>No templates, no exports, no platforms.</div>
    <div class="reveal" style="margin-top: clamp(20px, 3vw, 36px); display: flex; gap: 8px; flex-wrap: wrap; justify-content: center;">
      <span class="pill">0 Dependencies</span>
      <span class="pill">21 Presets</span>
      <span class="pill" style="border-color: rgba(120,40,200,0.30); color: #b388ff; background: rgba(120,40,200,0.12);">Pure HTML</span>
    </div>
  </div>
</section>

<!-- Slide 2: Problem — Split evidence -->
<section class="slide" data-notes="Three major pain points with existing tools" aria-label="Problem">
  <div class="slide-content">
    <div class="reveal a-label" style="margin-bottom: 12px; color: var(--accent);">Core Pain Points</div>
    <div class="reveal a-h2">Why Do Existing Presentation Tools Always Fall Short?</div>
    <div class="reveal" style="margin-top: clamp(16px, 2vw, 24px); display: flex; flex-direction: column; gap: 12px;">
      <div class="layer"><div class="layer-num">01</div><div class="a-body"><span class="a-accent">Complex toolchains</span> — Install dependencies, configure environments, manage versions — too much friction for a single deck</div></div>
      <div class="layer"><div class="layer-num">02</div><div class="a-body"><span class="a-accent">Generic AI aesthetics</span> — Every slide looks the same: gradients, rounded corners, purple tones, zero identity</div></div>
      <div class="layer"><div class="layer-num">03</div><div class="a-body"><span class="a-accent">Platform lock-in</span> — Use a platform, get trapped. Files don't export, formats are proprietary</div></div>
    </div>
  </div>
</section>

<!-- Slide 3: Discovery — Flow steps -->
<section class="slide" data-notes="Show the visual selection philosophy" aria-label="Discovery">
  <div class="slide-content" style="text-align: center; align-items: center;">
    <div class="reveal a-label" style="margin-bottom: 12px;">Core Philosophy</div>
    <div class="reveal a-h2" style="text-align: center;">See Styles, Don't Describe Them</div>
    <div class="reveal" style="margin-top: clamp(20px, 3vw, 36px); display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(12px, 2vw, 20px);">
      <div class="g" style="text-align: center;"><div class="stat"><div class="num">3</div><div class="label">Previews</div></div><div class="a-body" style="font-size: clamp(0.65rem, 1vw, 0.75rem); margin-top: 8px;">Generate 3 style previews</div></div>
      <div class="g" style="text-align: center; border-color: rgba(var(--accent-rgb),0.30);"><div class="stat"><div class="num">→</div><div class="label">Visual Choice</div></div><div class="a-body" style="font-size: clamp(0.65rem, 1vw, 0.75rem); margin-top: 8px;">Pick with your eyes</div></div>
      <div class="g" style="text-align: center;"><div class="stat"><div class="num">21</div><div class="label">Presets</div></div><div class="a-body" style="font-size: clamp(0.65rem, 1vw, 0.75rem); margin-top: 8px;">Signature visual languages</div></div>
    </div>
  </div>
</section>

<!-- Slide 4: Solution — Preset grid -->
<section class="slide" data-notes="Showcase 21 presets" aria-label="Solution">
  <div class="slide-content">
    <div class="reveal a-label" style="margin-bottom: 12px;">Design Presets</div>
    <div class="reveal a-h2">21 Styles. No Generic AI Look.</div>
    <div class="reveal" style="margin-top: clamp(12px, 2vw, 20px);">
      <div class="bento">
        <div class="g span2" style="border-left: 3px solid var(--accent);"><div class="a-label">Bold Signal</div><div class="a-body" style="font-size: clamp(0.65rem, 1vw, 0.75rem); margin-top: 4px;">Pitch decks — high contrast, bold type</div></div>
        <div class="g" style="border-left: 3px solid var(--accent); border-color: rgba(var(--accent-rgb),0.40); background: rgba(0,245,196,0.08);"><div class="a-label" style="color: var(--accent);">Aurora Mesh</div><div class="a-body" style="font-size: clamp(0.65rem, 1vw, 0.75rem); margin-top: 4px;">Product launch — animated gradient, frosted glass</div></div>
        <div class="g" style="border-left: 3px solid #00b4d8;"><div class="a-label" style="color: #00b4d8;">Terminal Green</div><div class="a-body" style="font-size: clamp(0.65rem, 1vw, 0.75rem); margin-top: 4px;">Dev tools — monospace, scan lines</div></div>
        <div class="g" style="border-left: 3px solid #b388ff;"><div class="a-label" style="color: #b388ff;">Modern Newspaper</div><div class="a-body" style="font-size: clamp(0.65rem, 1vw, 0.75rem); margin-top: 4px;">Research — editorial typography</div></div>
        <div class="g" style="border-left: 3px solid var(--text-m);"><div class="a-label" style="color: var(--text-m);">Enterprise Dark</div><div class="a-body" style="font-size: clamp(0.65rem, 1vw, 0.75rem); margin-top: 4px;">Data dashboard — dark panels</div></div>
      </div>
    </div>
  </div>
</section>

<!-- Slide 5: Workflow — Flow steps -->
<section class="slide" data-notes="Three steps to create a presentation" aria-label="Workflow">
  <div class="slide-content">
    <div class="reveal a-label" style="margin-bottom: 12px;">Workflow</div>
    <div class="reveal a-h2">Three Commands. Idea to Deck.</div>
    <div class="reveal" style="margin-top: clamp(16px, 2vw, 24px);">
      <div class="cols3">
        <div class="g"><div class="a-label" style="margin-bottom: 6px; color: var(--accent);">01 Plan</div><div class="a-body" style="line-height: 1.8;"><span class="a-accent">/slide-creator --plan</span><br>Tell the AI what you need</div></div>
        <div class="g"><div class="a-label" style="margin-bottom: 6px; color: var(--accent);">02 Generate</div><div class="a-body" style="line-height: 1.8;"><span class="a-accent">/slide-creator --generate</span><br>Pick a style, auto-generate</div></div>
        <div class="g"><div class="a-label" style="margin-bottom: 6px; color: var(--accent);">03 Present</div><div class="a-body" style="line-height: 1.8;"><span class="a-accent">Open in browser</span><br>Zero install, F5 to play</div></div>
      </div>
    </div>
    <div class="reveal" style="margin-top: 12px;">
      <div class="co">Or skip planning — give content + style, generate immediately.</div>
    </div>
  </div>
</section>

<!-- Slide 6: Features — Grid checkpoints -->
<section class="slide" data-notes="Four key capabilities" aria-label="Features">
  <div class="slide-content">
    <div class="reveal a-label" style="margin-bottom: 12px;">Key Features</div>
    <div class="reveal a-h2">Four Capabilities. Full Workflow.</div>
    <div class="reveal" style="margin-top: clamp(16px, 2vw, 24px);">
      <div class="cols2">
        <div class="g" style="text-align: center;">
          <div class="stat"><div class="num">F5</div><div class="label">Playback</div></div>
          <div class="a-body" style="font-size: clamp(0.65rem, 1vw, 0.75rem); margin-top: 8px;">Auto-scale, controls auto-hide</div>
        </div>
        <div class="g" style="text-align: center;">
          <div class="stat"><div class="num">E</div><div class="label">Edit Mode</div></div>
          <div class="a-body" style="font-size: clamp(0.65rem, 1vw, 0.75rem); margin-top: 8px;">contenteditable, Ctrl+S save</div>
        </div>
        <div class="g" style="text-align: center;">
          <div class="stat"><div class="num">P</div><div class="label">Presenter</div></div>
          <div class="a-body" style="font-size: clamp(0.65rem, 1vw, 0.75rem); margin-top: 8px;">Notes, timer, sync via BroadcastChannel</div>
        </div>
        <div class="g" style="text-align: center;">
          <div class="stat"><div class="num">PPTX</div><div class="label">Export</div></div>
          <div class="a-body" style="font-size: clamp(0.65rem, 1vw, 0.75rem); margin-top: 8px;">/kai-html-export to PPTX</div>
        </div>
      </div>
    </div>
  </div>
</section>

<!-- Slide 7: Install — Evidence list -->
<section class="slide" data-notes="Installation methods" aria-label="Install">
  <div class="slide-content">
    <div class="reveal a-label" style="margin-bottom: 12px;">Installation</div>
    <div class="reveal a-h2">One Command. Zero Dependencies.</div>
    <div class="reveal" style="margin-top: clamp(16px, 2vw, 24px); display: flex; flex-direction: column; gap: 12px;">
      <div class="g">
        <div class="a-label" style="margin-bottom: 6px;">Claude Code</div>
        <div class="a-body">Tell Claude: install kai-slide-creator</div>
      </div>
      <div class="g" style="border-color: rgba(var(--accent-rgb),0.30);">
        <div class="a-label" style="margin-bottom: 6px; color: var(--accent);">OpenClaw</div>
        <div class="a-body"><span class="a-accent">clawhub install kai-slide-creator</span></div>
      </div>
    </div>
    <div class="reveal" style="margin-top: 12px;"><div class="co">Python 3 only. No npm, no node, no build step.</div></div>
  </div>
</section>

<!-- Slide 8: CTA — Stacked action -->
<section class="slide" data-notes="Call to action" aria-label="CTA">
  <div class="slide-content" style="text-align: center; align-items: center;">
    <div class="reveal">
      <span class="pill" style="margin-bottom: 16px;">Start Now</span>
    </div>
    <div class="reveal a-title" style="background: linear-gradient(135deg, #fff 30%, rgba(var(--accent-rgb),0.8)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; margin-bottom: 16px;">Start Now</div>
    <div class="a-divider" style="background: rgba(var(--accent-rgb),0.30); margin: 20px auto; max-width: 80px;"></div>
    <div class="reveal">
      <div class="cmd" style="text-align: center; font-size: clamp(0.9rem, 1.5vw, 1.2rem);">/slide-creator</div>
    </div>
    <div class="reveal a-subtitle" style="margin-top: 12px; text-align: center;">Tell Claude to install kai-slide-creator</div>
  </div>
</section>

<!-- Edit mode UI -->
<div class="edit-hotzone"></div>
<button class="edit-toggle" id="editToggle">Edit</button>

<div id="notes-panel">
  <div id="notes-panel-header">
    <span id="notes-panel-label">SPEAKER NOTES</span>
    <button id="notes-collapse-btn" aria-label="Collapse notes">&#x25B2;</button>
  </div>
  <div id="notes-body">
    <textarea id="notes-textarea" placeholder="Speaker notes for this slide..."></textarea>
  </div>
</div>

<!-- ═══════════════════════ JAVASCRIPT ═══════════════════════ -->
<script>
class SlidePresentation {
  constructor() {
    this.slides = document.querySelectorAll('.slide');
    this.currentSlide = 0;
    this.channel = new BroadcastChannel('slide-creator-presenter');

    this.slides[0]?.classList.add('visible');
    this.slides[0]?.querySelectorAll('.reveal').forEach(r => r.classList.add('visible'));

    this.setupNavDots();
    this.setupObserver();
    this.setupKeyboard();
    this.setupTouch();
    this.setupWheel();
    this.setupPresenter();
    this.updateProgress();
    this.setupEditor();
  }

  setupNavDots() {
    const nav = document.querySelector('.nav-dots');
    if (!nav) return;
    this.slides.forEach((_, i) => {
      const dot = document.createElement('button');
      dot.setAttribute('aria-label', 'Go to slide ' + (i + 1));
      dot.style.cssText = 'width:8px;height:8px;border-radius:50%;border:none;cursor:pointer;background:rgba(255,255,255,0.15);transition:all 0.3s;';
      dot.addEventListener('click', () => this.goTo(i));
      nav.appendChild(dot);
    });
  }

  setupObserver() {
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          entry.target.classList.add('visible');
          this.currentSlide = Array.prototype.indexOf.call(this.slides, entry.target);
          this.updateProgress();
          this.updateDots();
          this.broadcastState();
          this.updateNotesPanel();
        }
      });
    }, { threshold: 0.5 });
    this.slides.forEach(s => observer.observe(s));
  }

  setupKeyboard() {
    const _self = this;
    document.addEventListener('keydown', function(e) {
      if (e.target.getAttribute('contenteditable')) return;
      if (e.key === 'ArrowDown' || e.key === 'ArrowRight' || e.key === ' ' || e.key === 'PageDown' || e.key === 'Enter') {
        e.preventDefault(); self.next();
      } else if (e.key === 'ArrowUp' || e.key === 'ArrowLeft' || e.key === 'PageUp' || e.key === 'Backspace') {
        e.preventDefault(); self.prev();
      } else if (e.key === 'Home') { e.preventDefault(); self.goTo(0); }
      else if (e.key === 'End') { e.preventDefault(); self.goTo(self.slides.length - 1); }
      else if (e.key === 'p' || e.key === 'P') {
        const url = location.href.split('?')[0] + '?presenter';
        window.open(url, 'slide-presenter-' + Date.now(), 'width=1100,menubar=no,toolbar=no');
      } else if (e.key === 'e' || e.key === 'E') {
        if (this.editor && !this.editor.active) this.editor.enter();
        else if (this.editor) this.editor.exit();
      }
    });
  }

  setupTouch() {
    const _self = this;
    let startY = 0;
    document.addEventListener('touchstart', e => { startY = e.touches[0].clientY; }, { passive: true });
    document.addEventListener('touchend', e => {
      const delta = startY - e.changedTouches[0].clientY;
      if (Math.abs(delta) > 50) delta > 0 ? self.next() : self.prev();
    });
  }

  setupWheel() {
    // scroll-snap-type: y mandatory handles wheel natively
  }

  setupPresenter() {
    const _self = this;
    this.channel.addEventListener('message', function(e) {
      if (e.data.type === 'nav-next') self.next();
      else if (e.data.type === 'nav-prev') self.prev();
      else if (e.data.type === 'request-state') self.broadcastState();
    });
  }

  broadcastState() {
    const slide = this.slides[this.currentSlide];
    this.channel.postMessage({
      type: 'state',
      index: this.currentSlide,
      total: this.slides.length,
      notes: slide?.dataset.notes || ''
    });
  }

  goTo(index) {
    this.slides[index]?.scrollIntoView({ behavior: 'smooth' });
  }
  next() { this.goTo(Math.min(this.currentSlide + 1, this.slides.length - 1)); }
  prev() { this.goTo(Math.max(this.currentSlide - 1, 0)); }

  updateProgress() {
    const pct = (this.currentSlide / (this.slides.length - 1)) * 100;
    const bar = document.querySelector('.progress-bar');
    if (bar) bar.style.width = pct + '%';
    var counter = document.getElementById('present-counter');
    if (counter) counter.textContent = (this.currentSlide + 1) + ' / ' + this.slides.length;
  }

  updateDots() {
    document.querySelectorAll('.nav-dots button').forEach((dot, i) => {
      dot.style.background = i === this.currentSlide ? 'var(--accent)' : 'rgba(255,255,255,0.15)';
      dot.style.transform = i === this.currentSlide ? 'scale(1.4)' : 'scale(1)';
    });
  }

  setupEditor() {
    const _self = this;
    const panel = document.getElementById('notes-panel');
    const label = document.getElementById('notes-panel-label');
    const textarea = document.getElementById('notes-textarea');
    const toggle = document.getElementById('editToggle');
    const hotzone = document.querySelector('.edit-hotzone');
    let hideTimeout = null;

    hotzone.addEventListener('mouseenter', function() { clearTimeout(hideTimeout); toggle.classList.add('show'); });
    hotzone.addEventListener('mouseleave', function() { hideTimeout = setTimeout(function() { if (!this.editor?.active) toggle.classList.remove('show'); }, 400); });
    toggle.addEventListener('mouseenter', function() { clearTimeout(hideTimeout); });
    toggle.addEventListener('mouseleave', function() { hideTimeout = setTimeout(function() { if (!this.editor?.active) toggle.classList.remove('show'); }, 400); });
    hotzone.addEventListener('click', function() { self.editor.toggle(); });
    toggle.addEventListener('click', function() { self.editor.toggle(); });

    document.getElementById('notes-panel-header').addEventListener('click', function() {
      panel.classList.toggle('collapsed');
    });

    textarea.addEventListener('input', function() {
      const slide = self.slides[self.currentSlide];
      if (slide) { slide.dataset.notes = textarea.value; self.broadcastState(); }
    });

    document.addEventListener('keydown', function(e) {
      if ((e.ctrlKey || e.metaKey) && e.key === 's') {
        e.preventDefault(); self.saveFile();
      }
    });

    this.editor = {
      active: false,
      toggle: function() { self.editor.active ? self.editor.exit() : self.editor.enter(); },
      enter: function() {
        self.editor.active = true;
        toggle.classList.add('active');
        toggle.textContent = 'Done';
        self.slides.forEach(function(s) {
          s.querySelectorAll('h1,h2,h3,p,li,span,td,th').forEach(function(el) {
            el.setAttribute('contenteditable', 'true');
            el.style.outline = 'none';
          });
        });
        panel.classList.add('active');
        self.updateNotesPanel();
      },
      exit: function() {
        self.editor.active = false;
        toggle.classList.remove('active');
        toggle.textContent = 'Edit';
        self.slides.forEach(function(s) {
          s.querySelectorAll('[contenteditable]').forEach(function(el) {
            el.removeAttribute('contenteditable');
            el.style.outline = '';
          });
        });
        panel.classList.remove('active');
      }
    };

    this._notesLabel = label;
    this._notesTextarea = textarea;
  }

  updateNotesPanel() {
    if (!this.editor?.active) return;
    const slide = this.slides[this.currentSlide];
    this._notesLabel.textContent = 'SPEAKER NOTES — SLIDE ' + (this.currentSlide + 1) + ' / ' + this.slides.length;
    this._notesTextarea.value = slide?.dataset.notes || '';
  }

  saveFile() {
    const html = '<!DOCTYPE html>\n' + document.documentElement.outerHTML;
    const blob = new Blob([html], { type: 'text/html' });
    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = document.title + '.html';
    a.click();
  }
}

/* ═══════════════════════ PRESENTER MODE ═══════════════════════ */
if (new URLSearchParams(location.search).has('presenter')) {
  document.title = 'Presenter — ' + document.title;
  document.body.innerHTML =
    '<style>*{box-sizing:border-box;margin:0}body{background:#111;color:#fff;font-family:system-ui,sans-serif}#pv{display:grid;grid-template-columns:1fr 220px;gap:1rem;padding:1.25rem;align-items:start}.pv-panel{background:#1e1e1e;border-radius:12px;padding:1.25rem}#pv-label{font-size:.6rem;letter-spacing:.18em;text-transform:uppercase;color:#555;margin-bottom:.6rem}#pv-notes{font-size:1.05rem;line-height:1.85;color:#d0d0d0}#pv-right{display:flex;flex-direction:column;gap:1rem}#pv-nav{display:flex;align-items:center;justify-content:space-between;gap:.5rem}.pv-arrow{width:32px;height:32px;border-radius:6px;border:1px solid #333;background:#2a2a2a;color:#aaa;font-size:1rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .15s,color .15s;flex-shrink:0}.pv-arrow:hover{background:#383838;color:#fff}#pv-counter{text-align:center;flex:1}#pv-num{font-size:1.6rem;font-weight:700;font-variant-numeric:tabular-nums;line-height:1}#pv-of{color:#555;font-size:.75rem;margin-top:.2rem}#pv-timer-box{text-align:center}#pv-timer-label{font-size:.6rem;letter-spacing:.18em;text-transform:uppercase;color:#555;margin-bottom:.3rem}#pv-timer{font-size:1.5rem;font-weight:700;font-family:monospace;font-variant-numeric:tabular-nums}</style>' +
    '<div id="pv"><div class="pv-panel"><div id="pv-label">Speaker Notes</div><div id="pv-notes">Waiting for main window\u2026</div></div><div id="pv-right"><div class="pv-panel"><div id="pv-nav"><button class="pv-arrow" id="pv-prev">\u2190</button><div id="pv-counter"><div id="pv-num">\u2014</div><div id="pv-of">/ \u2014</div></div><button class="pv-arrow" id="pv-next">\u2192</button></div></div><div class="pv-panel" id="pv-timer-box"><div id="pv-timer-label">Elapsed</div><div id="pv-timer">0:00</div></div></div></div>';

  const ch = new BroadcastChannel('slide-creator-presenter');
  let startTime = null;
  ch.addEventListener('message', function(e) {
    if (e.data.type !== 'state') return;
    if (!startTime) startTime = Date.now();
    document.getElementById('pv-notes').textContent = e.data.notes || '(no notes for this slide)';
    document.getElementById('pv-num').textContent = e.data.index + 1;
    document.getElementById('pv-of').textContent = '/ ' + e.data.total;
  });
  ch.postMessage({ type: 'request-state' });
  setInterval(function() {
    if (!startTime) return;
    const s = Math.floor((Date.now() - startTime) / 1000);
    document.getElementById('pv-timer').textContent = Math.floor(s / 60) + ':' + String(s % 60).padStart(2, '0');
  }, 1000);
  document.getElementById('pv-prev').addEventListener('click', function() { ch.postMessage({ type: 'nav-prev' }); });
  document.getElementById('pv-next').addEventListener('click', function() { ch.postMessage({ type: 'nav-next' }); });
  document.addEventListener('keydown', function(e) {
    if (e.key === 'ArrowRight' || e.key === 'ArrowDown' || e.key === ' ' || e.key === 'PageDown' || e.key === 'Enter') ch.postMessage({ type: 'nav-next' });
    else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp' || e.key === 'PageUp' || e.key === 'Backspace') ch.postMessage({ type: 'nav-prev' });
  });
} else {
  /* ═══════════════════════ PRESENT MODE ═══════════════════════ */
  class PresentMode {
    constructor(ctrl) {
      this.ctrl = ctrl;
      this.baseW = 1440; this.baseH = 900;
      this.active = false;
      const btn = document.createElement('button');
      btn.id = 'present-btn'; btn.title = 'Present (F5)';
      btn.setAttribute('aria-label', 'Present'); btn.textContent = '\u25B6';
      document.body.appendChild(btn);
      const counter = document.createElement('div');
      counter.id = 'present-counter'; document.body.appendChild(counter);
      btn.addEventListener('click', () => this.enter());
      document.addEventListener('keydown', e => {
        if (e.key === 'F5') { e.preventDefault(); this.enter(); }
        if (e.key === 'Escape' && this.active) this.exit();
        if ((e.key === 'b' || e.key === 'B') && this.active) document.body.classList.toggle('presenting-black');
      });
      document.addEventListener('fullscreenchange', () => { if (this.active) { setTimeout(() => this._scale(), 100); } if (!document.fullscreenElement && this.active) this.exit(); });
                window.addEventListener('resize', () => { if (this.active) this._scale(); });
    }
    enter() {
      if (this.active) return;
      this.active = true;
      document.body.classList.add('presenting');
      document.documentElement.requestFullscreen?.().catch(() => {});
      this._scale();
      this._show(this.ctrl.currentSlide);
      this._origGoTo = this.ctrl.goTo.bind(this.ctrl);
      this.ctrl.goTo = (i) => {
        const idx = Math.max(0, Math.min(i, this.ctrl.slides.length - 1));
        this.ctrl.currentSlide = idx;
        this.ctrl.slides.forEach((s, j) => s.classList.toggle('visible', j === idx));
        this._show(idx);
        this.ctrl.updateProgress?.();
        this.ctrl.updateDots?.();
        this.ctrl.broadcastState?.();
      };
    }
    _reset() {
                this.ctrl.slides.forEach(slide => { slide.style.transform = ''; slide.classList.remove('p-on'); });
            }
    exit() {
                if (!this.active) return;
                this.active = false;
                document.body.classList.remove('presenting', 'presenting-black');
                this._reset();
      if (document.fullscreenElement) document.exitFullscreen?.();
      if (this._origGoTo) { this.ctrl.goTo = this._origGoTo; this._origGoTo = null; }
      this.ctrl.slides[this.ctrl.currentSlide]?.scrollIntoView({ behavior: 'instant' });
    }
    _scale() {
                const vw = window.innerWidth;
                const vh = window.innerHeight;
                const scale = Math.min(vw / this.baseW, vh / this.baseH);
                this.ctrl.slides.forEach(slide => { slide.style.transform = 'scale(' + scale + ')'; });
            }
    _show(i) {
      document.querySelectorAll('.slide').forEach((s, idx) => s.classList.toggle('p-on', idx === i));
      const c = document.getElementById('present-counter');
      if (c) c.textContent = (i + 1) + ' / ' + this.ctrl.slides.length;
    }

            _updateCounter() {
                const c = document.getElementById('present-counter');
                if (c) c.textContent = (this.ctrl.currentSlide + 1) + ' / ' + this.ctrl.slides.length;
            }
  }

  new PresentMode(new SlidePresentation());
}

/* Watermark */
(function() {
  var slides = document.querySelectorAll('.slide');
  if (!slides.length) return;
  var last = slides[slides.length - 1];
  var credit = document.createElement('div');
  credit.className = 'slide-credit';
  credit.textContent = 'By kai-slide-creator v2.16.0 \u00B7 Aurora Mesh';
  last.appendChild(credit);
})();
</script>
</body>
</html>

path: contracts/slide_creator/source_snapshot/references/brief-template.json
content: {
  "schema_version": 1,
  "brief_id": "slide-creator-demo-auto",
  "mode": "auto",
  "language": "zh-CN",
  "title": "Slide Creator",
  "audience": "正在评估 slide-creator 的产品经理和开发者",
  "desired_action": "用真实内容试跑第一套 deck",
  "deck": {
    "deck_type": "user-content",
    "page_count": 8,
    "output_format": "html-slides"
  },
  "style": {
    "preset": "Blue Sky",
    "tone": "清爽、可信、偏产品介绍",
    "visual_density": "medium"
  },
  "content": {
    "source_policy": "distill-only",
    "must_include": [
      "slide-creator 是什么",
      "从 prompt 到 deck 的轻量工作流",
      "浏览器原生输出与可编辑性"
    ],
    "must_avoid": [
      "泛泛开场",
      "连续重复布局",
      "与 thesis 无关的背景信息"
    ]
  },
  "narrative": {
    "thesis": "slide-creator 把内容提炼、风格锁定和 HTML 交付压缩成一个可重复的轻量工作流。",
    "page_roles": [
      "cover",
      "problem",
      "solution",
      "workflow",
      "style-discovery",
      "output-contract",
      "best-fit",
      "closing"
    ],
    "slides": [
      {
        "slide_number": 1,
        "role": "cover",
        "title": "Slide Creator",
        "key_point": "从 prompt 到可演示 HTML deck",
        "visual": "hero statement"
      },
      {
        "slide_number": 2,
        "role": "problem",
        "title": "好内容经常被糟糕的演示稿拖累",
        "key_point": "模板老旧、排版不稳、改一版成本高",
        "visual": "comparison cards"
      },
      {
        "slide_number": 3,
        "role": "solution",
        "title": "slide-creator 让 deck 生成更稳定",
        "key_point": "把规划、风格和交付压到一个工作流里",
        "visual": "three-step flow"
      },
      {
        "slide_number": 4,
        "role": "workflow",
        "title": "默认路径足够短",
        "key_point": "先提炼 BRIEF，再生成 HTML",
        "visual": "command timeline"
      },
      {
        "slide_number": 5,
        "role": "style-discovery",
        "title": "风格选择是 wow moment",
        "key_point": "先看 3 个预览，再锁定 preset",
        "visual": "preview trio"
      },
      {
        "slide_number": 6,
        "role": "output-contract",
        "title": "输出不是一次性截图",
        "key_point": "浏览器原生运行、可播放、默认可编辑",
        "visual": "capability badges"
      },
      {
        "slide_number": 7,
        "role": "best-fit",
        "title": "适合需要高质量 deck 的日常场景",
        "key_point": "产品发布、内部汇报、技术分享都能复用",
        "visual": "use case cards"
      },
      {
        "slide_number": 8,
        "role": "closing",
        "title": "先出一版，再精修",
        "key_point": "默认快，关键 deck 再锁质量",
        "visual": "closing CTA"
      }
    ]
  },
  "runtime": {
    "editing_mode": true,
    "presenter_mode": true,
    "watermark_mode": "injected-last-slide",
    "export_intent": "none"
  },
  "plan_view": {
    "emit_planning_view": false,
    "planning_view_path": "PLANNING.md"
  },
  "timing": {
    "estimate": {
      "plan": "1-2 min",
      "generate": "1-3 min",
      "validate": "<1 min",
      "polish": "0-2 min",
      "total": "3-6 min"
    },
    "actual": {
      "plan": "0m 00s",
      "generate": "0m 00s",
      "validate": "0m 00s",
      "polish": "0m 00s",
      "total": "0m 00s"
    }
  },
  "notes": ""
}


path: memory/feedback_session24_step_circle_fix.md
content: ---
name: Session 24: Step number circle CSS dimensions + code_bg fix
description: Step circles need CSS width/height (34px) instead of text-based estimation; code_bg shape positioning searches both directions
type: feedback
---

**Step circle fix**: In `build_grid_children` at line 1771 (is_leaf_text_container path), when child has explicit CSS width/height AND visible bg/gradient, use CSS dimensions for both shape and text element bounds. Set `_use_css_dims=True` on text element to prevent layout pass from overriding width in the "short/plain text" branch (line 2287+).

**Why**: Step divs (.step) have CSS `width:34px; height:34px` but text-based estimation gives 0.172"x0.150" vs golden 0.315"x0.315". The layout pass recalculates width for non-block text — need `_use_css_dims` flag to skip recalculation.

**Code bg positioning**: In `position_code_bg_shapes`, search backward FIRST (idx-1 to 0), then forward as fallback. Code_bg shapes are emitted after their sibling text element.

**Result**: Slide 10 6.5→7.3, Slide 3 6.6→6.7. No regressions on other slides.


path: reports/score.txt
content: fail 78


path: requirements.txt
content: beautifulsoup4>=4.12.0
lxml>=4.9.0
python-pptx>=0.6.23
Pillow>=10.0.0


Security scan verdicts — ClawScan: clean | static analysis: suspicious | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)