# Airshelf 设计规范 · design.md

> **唯一权威 source of truth** · 所有页面调整必须遵循本文件。
> **代号:** Restraint(克制)· V2.1 · Firecrawl-aligned
> **维护日期:** 2026-05-22
> **配套实现:** [assets/restraint.css](assets/restraint.css) (token + 100+ 组件类 · 1592 行)
> **可视样板间(归档):** [_archive/design-system.html](_archive/design-system.html)
> **历史规范(归档):** [_archive/DESIGN_SPEC_V2.md](_archive/DESIGN_SPEC_V2.md)

---

## §0 · AI 协作铁律(每次启动必读)

**Claude / 任何 AI 在做页面或 CSS 调整前,必须执行以下流程:**

1. **先 Read 本文件** · 至少读 §1 设计哲学 + §3 组件清单 + §8 Don't List
2. **检查 restraint.css 是否已有该组件** · 用 `Grep "\.btn|\.pill|\.input" assets/restraint.css` 查现成类名
3. **禁止在页面 inline `<style>` 重写 restraint.css 已有的共享类**(`.btn` `.pill` `.input` `.modal` `.drawer` `.toast` `.field` `.tabs` `.chip` 等)— 要变体先回 restraint.css 加
4. **禁止创建新色值** · 颜色必须用 §2.1 的 token,不能写裸 hex
5. **禁止动 token 数值** · 不要改 `--heat` `--background-base` `--border-faint` 等基础变量,改了破坏全站
6. **完成后对照 §8 Don't List 自检**
7. **不确定就问用户**,而不是凭感觉发挥

**违反任何一条,用户有权要求重做。**

---

## §1 · 设计哲学

**一句话:** 一台精密设备的工作面板。

**三条铁律:**
1. **克制大于装饰** · 留白 > 容器 > 内容,大量空气感
2. **单色锚点** · 全场只有一个 accent(橙),只用于 CTA / 关键状态 / 强调单词
3. **结构清晰可见** · 用 1 px 边框 + 8 px 圆角 + 准星 + 装订线 + mono 标签暴露"图纸感",而非阴影/渐变隐藏结构

**避免的 "AI 味":** 渐变铺面 / 玻璃拟态 / 彩色阴影 / emoji 图标 / 圆角无差别 / 卡片"贴纸感" / 装饰盖过内容。

**核心签名(4 个不能丢):**
- 主橙 `#fa5d19`(Firecrawl 实测)+ 单 hue alpha 阶梯
- 全场 8 px 圆角(Pill 999 例外)
- 主容器左右装订线 + 四角准星
- Mono 装饰 `[ 200 OK ]` `// 05.14` `[ /v2 ]`(品牌签名 · Firecrawl 没有)

---

## §2 · 全局 Token

### §2.1 色彩 · 你 90% 时间用这 14 个

| Token | Hex / Value | 用途 |
| ----- | ----------- | ---- |
| `--background-base` | `#f9f9f9` | 页面底色 · 冷灰无色相 |
| `--background-lighter` | `#fbfbfb` | 容器底 / hover 浅底(部分场景) |
| `--surface` | `#ffffff` | 卡片 / 主容器表面 |
| `--surface-raised` | `#ffffff` | Modal / 浮层 |
| `--border-faint` | `#ededed` | **默认 1 px 边框 ★ 80% 场景** |
| `--border-muted` | `#e8e8e8` | 略深(主分隔线) |
| `--border-loud` | `#e6e6e6` | 最深(强分隔) |
| `--accent-black` | `#262626` | **主前景色 · 文字** |
| `--heat` | `#fa5d19` | **主橙 100% · CTA / 链接 ★** |
| `--heat-12` | `rgba(250,93,25,.12)` | tint 底 · active nav / icon-box |
| `--heat-20` | `rgba(250,93,25,.20)` | pill 边框 / selection 底色 |
| `--heat-40` | `rgba(250,93,25,.40)` | focus ring / disabled CTA |
| `--accent-forest` | `#42c366` | 绿 · success / 已完成 |
| `--accent-crimson` | `#eb3424` | 红 · error / 失败 |
| `--accent-honey` | `#ecb730` | 黄 · warning |

### §2.2 Black-Alpha 阶梯(20 档 · 核心工具尺)

> **规则:** 0–24% 用 `rgba(0,0,0,...)`;32% 起换 `rgba(38,38,38,...)`(避免叠出"灰中带蓝")。

最常用 8 档:

| Token | 用途 |
| ----- | ---- |
| `--black-alpha-4` | **hover 底色 ★** |
| `--black-alpha-7` | **active 底色 ★** |
| `--black-alpha-12` | **inside-border / disabled fg ★** |
| `--black-alpha-24` | input hover 边框 |
| `--black-alpha-48` | **占位字色 ★** |
| `--black-alpha-56` | **次级文字 / 未选中 Tab ★** |
| `--black-alpha-64` | 描述文字 |
| `--black-alpha-88` | 近主前景 |

完整 20 档清单见 [assets/restraint.css](assets/restraint.css) §root。

### §2.3 状态色配套(底 / 边)

| 含义 | 主色 | 配套底色 8% | 配套边框 20% |
| ---- | ---- | ----------- | ------------ |
| 成功 | `--accent-forest` `#42c366` | `--forest-bg` | `--forest-bd` |
| 失败 | `--accent-crimson` `#eb3424` | `--crimson-bg` | `--crimson-bd` |
| 信息 | `--heat` `#fa5d19` | `--heat-12` | `--heat-20` |
| 警告 | `--accent-honey` `#ecb730` | `--honey-bg` | `--honey-bd` |

### §2.4 Selection · Firecrawl 签名细节

```css
::selection { background: var(--heat-20); color: var(--heat); }
```

任何文字选中时,底色 20% 橙 + 文字 100% 橙。已全局生效 · 不要覆盖。

### §2.5 字体族 · 中英协作

| 用途 | 字体声明 | 加载方式 |
| ---- | -------- | -------- |
| 正文 / UI · `--font-sans` | `'Inter', 'Alibaba PuHuiTi', 'PingFang SC', 'Microsoft YaHei', system-ui, sans-serif` | Inter Google Fonts + 普惠体 CDN |
| 强制纯英 · `--font-inter` | `'Inter', system-ui, sans-serif` | 用于 Ctrl K 等英文徽标 |
| 数字 / 装饰 · `--font-mono` | `'Inter', 'Alibaba PuHuiTi', 'PingFang SC', 'Microsoft YaHei', system-ui, sans-serif` | Inter Google Fonts |

**字符级 fallthrough 原理:** 浏览器对每个字符逐个查找,Inter 不含 CJK → 中文自动跳到普惠体。**不需要 JS,不会字重错位。**

**字重档位仅 3 档:** `400 / 500 / 600`。700 仅用于 `Ctrl K` 这种纯英文徽标。

### §2.6 字号 / 字重 / 行高(11 档)

| 角色 | 字号 | 字重 | 字距 | 行高 | 用途 |
| ---- | ---- | ---- | ---- | ---- | ---- |
| H1 / Hero | 36 px | 500 | -0.024em | 1.2 | 页面主标题 |
| 区块 H2 | 28 px | 500 | -0.02em | 1.25 | section-head |
| KPI 数值 | 32 px | 500 | -0.02em | 1.1 | 统计大数(`tabular-nums`) |
| 子区 H3 | 16 px | 500 | -0.01em | 1.4 | subsection |
| 卡片标题 | 14 px | 500 | normal | 1.4 | 项目名 / 商品名 |
| 正文 body | 14 px | 400 | normal | **1.65** | 默认正文 |
| 描述次级 | 13 px | 400 | normal | 1.8 | 子区说明 |
| Label / Tab | 13 px | 500 | normal | 1.4 | 按钮文字 / Tab |
| Pill | 11.5 px | 500 | normal | 1.3 | 状态徽标 |
| Inter Bold 徽标 | 11.5 px | 700 | 0.02em | 1 | Ctrl K / ESC(`--font-inter`) |
| Mono 标签 | 11 px | 400 | 0.04em | 1.5 | `[ STATUS ]` `// 注释` |
| Mono 散点 | 8.5 px | 400 | 0.04em | 1 | 背景 ASCII 装饰 |

**数值类必加** `font-variant-numeric: tabular-nums`(或加 `.num` 工具类)。
**正文中文行高 1.65–1.8**(给中文留呼吸)。

### §2.7 圆角

| 元素 | 值 | Token |
| ---- | -- | ----- |
| 所有结构性容器 / 按钮 / 输入框 / 缩略图 | **8 px** | `--r-md` |
| 头像 / 小色块 | 6 px | — |
| Mono 标签 / kbd / badge | 4 px | `--r-sm` |
| 进度条段位 | 2 px | — |
| Pill / dot | 999 px | `--r-pill` |

**默认是 8 px。** 不确定就选 8。`>12 px` 直接判错。

### §2.8 间距(全站统一)

**基础栅格:** 4 px。
**阶梯:** `4 / 8 / 12 / 16 / 20 / 24 / 28 / 32 / 40 / 48 / 64 / 72 / 80 / 104`。

| 场景 | 值 |
| ---- | -- |
| Sidebar 宽度 | `248 px` |
| Topbar 高度 | `64 px` |
| Content padding | `48 28 72` |
| 卡片内 padding(大) | `28 30` / `24 28` |
| 卡片内 padding(列表行) | `14 18` ~ `20 24` |
| KPI cell padding | `24 28` |
| 主区块间(section margin) | `36–48 px`(子)/ `64–104 px`(主) |
| 子区标题底距 | `mb 14`(h2)/ `mb 22-28`(h1) |
| 卡片网格 gap | `14`(子区)/ `24`(主区) |
| Modal padding | `head 24 28 / body 24 28 / foot 18 28` |

**最重要的一条:** 别再吝啬空气。**当不确定 padding 是 16 还是 24 时,选 24。** 当不确定 margin 是 48 还是 64 时,选 64。

### §2.9 阴影(只 3 个允许场景)

| 场景 | 阴影 |
| ---- | ---- |
| 主 CTA(`.btn-primary`) | 4 层橙色阴影 `--shadow-cta` |
| 主 CTA hover | 阴影抬升 `--shadow-cta-hover` |
| Toast / Dropdown 浮层 | 白色 `0 4px 20px rgba(21,20,15,.06)` = `--shadow-floating` |

**禁:** 灰色阴影 / 文字阴影 / 通用 box-shadow。

### §2.10 边框策略 · inside-border

默认边框用 `::before` 伪元素绘制(而非真 `border`),hover 时让 `::before` 透明度 → 0,不触发布局抖动。

```css
.inside-border { position: relative; }
.inside-border::before {
  content: ''; position: absolute; inset: 0;
  border: 1px solid var(--black-alpha-12);
  border-radius: inherit;
  pointer-events: none;
  transition: opacity .2s, border-color .2s;
}
.inside-border:hover::before { opacity: 0; }
```

**禁:** 2 px / 3 px 实线 / 真 `border` + hover 边框消失。
**例外:** `.tip` 提示框允许 `1 px dashed`。

---

## §3 · 页面骨架(全站统一)

```
┌──────────────────────────────────────────────┐
│  <div class="app">                           │
│  ┌────────┬──────────────────────────────┐   │
│  │        │  <div class="topbar">        │   │
│  │ aside  │    crumbs · right(chips)     │   │
│  │ side   │  </div>                      │   │
│  │ bar    │  ┌────────────────────────┐  │   │
│  │ 248px  │  │ <div class="content">  │  │   │
│  │        │  │   <div class="page-head"> │   │
│  │        │  │   <div class="section-h"> │   │
│  │        │  │   ...                  │  │   │
│  │        │  │ </div>                 │  │   │
│  │        │  └────────────────────────┘  │   │
│  └────────┴──────────────────────────────┘   │
│  </div>                                      │
└──────────────────────────────────────────────┘
```

### §3.1 入口约束

每个新页面 `<head>`:
```html
<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=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/restraint.css">
```

每个新页面 `<body>` 末尾:
```html
<script src="assets/icons.js" defer></script>
<script src="assets/shell.js" defer></script>
```

`icons.js` 提供统一 Lucide-line 图标注册表;`shell.js` 自动注入 sidebar + topbar,**页面只写 `<main>` 内的 `.content` 内容**。

### §3.2 标题区(必有)

```html
<div class="page-head">
  <div>
    <h1>商品库</h1>
    <div class="sub">
      <span class="mono">// 12 个商品</span> · 你的所有商品和卖点
    </div>
  </div>
  <div class="actions">
    <button class="btn">导入</button>
    <button class="btn btn-primary">+ 新建商品</button>
  </div>
</div>
```

**page-head 内主操作按钮强制 40 px 高**(`.page-head .actions > .btn { height: 40px }` 已全局覆盖)。

### §3.3 子区块(可选)

```html
<div class="section-h">
  <h2>最近项目</h2>
  <a class="more">[ ALL · 12 ] →</a>
</div>
<!-- 内容 -->
```

`.more` mono 11.5 / `--black-alpha-48` / hover 转橙。

### §3.4 主容器装订线(签名元素 · 主工作台型必有)

工作台 / 项目列表 / 商品库 / 流水线主区:左右两条 1 px 边线 + 4 角圆弧内凹 SVG 准星。Modal / 编辑器全屏画布不必加。

```css
.workbench-container {
  max-width: 1480px;
  margin: 0 auto;
  border-left: 1px solid var(--border-faint);
  border-right: 1px solid var(--border-faint);
  position: relative;
}
/* 4 角 SVG · 用 .with-corners + .corner-tr/.corner-bl */
```

---

## §4 · 组件清单(restraint.css 已实现 · 不要重发明)

### §4.1 按钮族 · 三级体系(按功能重要性区分)

> **核心原则:** 按钮的视觉强度 = 操作的重要程度。一个区域**只能有一个**一级按钮(像航海图上只能有一个北极星)。视觉等级混乱比按钮不好看更致命。

#### 三级体系

| 等级 | 类名 | 视觉 | 语义 | 数量约束 |
| ---- | ---- | ---- | ---- | -------- |
| **一级 · Primary** | `.btn .btn-primary` | 橙底 + 4 层橙阴影 + 字重 600 | **页面/弹窗的最重要动作** · 用户主动作 | **一个区域只能有一个** ★ |
| **二级 · Secondary** | `.btn` 默认 | 白底 + inside-border + 主前景字 | 跟主操作**并列**的重要动作 | 可以有多个 |
| **三级 · Tertiary** | `.btn .btn-ghost` | 透明底 + 无框 + alpha-56 字 | **辅助/链接式**的弱化操作 | 不限 |

#### 选谁?决策表

| 操作类型 | 等级 | 例子 |
| -------- | ---- | ---- |
| 提交 / 确认 / 创建 / 下一步 / 保存 / 生成 | **一级** | "创建商品" "确认删除" "开始生成" |
| 取消 / 重置 / 导出 / 导入 / 上一步 / 关闭 | **二级** | "取消" "重置" "导出 CSV" |
| 跳过 / 了解更多 / 查看详情 / 折叠 / 链接式 | **三级** | "跳过" "了解更多 →" "[查看] [编辑] [删除]" 行内动作 |
| 破坏性(删除/危险) | **二级**(在 modal 里)或**一级**(确认按钮) | modal 里:取消[二级] + 确认删除[一级] |

#### 典型组合

| 场景 | 组合 |
| ---- | ---- |
| `.page-head .actions`(页面标题区) | [二级] + [一级] · 例:[导入] [+ 新建商品] |
| `.modal-f`(弹窗底栏) | [二级取消] + [一级确认] · 永远主操作在右 |
| 卡片行内操作 | [三级] × N · 例:[查看] [编辑] [删除] |
| 表单底部 | [三级上一步] + spacer + [二级保存草稿] + [一级提交] |
| 空状态 CTA | [一级] · 唯一一个 |

#### 尺寸阶梯(独立于等级,按上下文密度选)

| 类名 | 高度 | padding | 字号 | 用法 |
| ---- | ---- | ------- | ---- | ---- |
| `.btn-sm` | 28 px | `0 12` | 12 | 行内 / 列表行末 / 表格内 / 紧凑工具栏 |
| 默认 | 36 px | `0 16` | 13 | **标准 ★** · 通用场景 |
| `.btn-lg` | 40 px | `0 20` | 13.5 | hero CTA / page-head 主操作(已全局覆盖) |
| `.icon-btn` 方形 | 36×36 | — | — | 纯 icon(无文字时) |

> **等级 × 尺寸** 可自由组合 — 一级可以是 sm/默认/lg,二级三级同理。

#### 5 种状态

| 状态 | 一级表现 | 二级表现 | 三级表现 |
| ---- | -------- | -------- | -------- |
| Default | 橙底 + 4 层橙阴影 | 白底 + inside-border `--black-alpha-12` | 透明 + 字 `--black-alpha-56` |
| Hover | 阴影抬升(第 3 层加亮) | 底 `--black-alpha-4` + 边 `--black-alpha-24` | 底 `--black-alpha-4` + 字转 `--accent-black` |
| Active(按下) | `scale(.995)` + 阴影 inset 加深 | 底 `--black-alpha-7` + `scale(.99)` | 底 `--black-alpha-7` |
| Focused | 2 px `--heat-40` ring · offset 2 | 同左 | 同左 |
| Disabled | 底 `--heat-40` + 字 `#fff` + 阴影消失 + `not-allowed` | 底 `--black-alpha-5` + 字 `--black-alpha-32` + 边 `--black-alpha-12` | 字 `--black-alpha-32` |

**所有按钮过渡:** `background 200ms, transform 100ms ease`。

#### 常见错误

- ❌ **一个区域两个一级按钮** — 用户视线分散 → 改为 [二级] + [一级]
- ❌ **危险操作用一级橙色** — 改为放在 modal 里二次确认,modal 内的"确认删除"用一级
- ❌ **重要操作用三级 ghost** — 弱化了主流程,改用一级或二级
- ❌ **三级按钮加边框** — 三级就是 ghost,加边框就变二级了
- ❌ **页面 inline 调高度/字号** — 用 `.btn-sm` / `.btn-lg`,不要 inline 改

### §4.2 Pill(状态徽标 · 严格 3 级分层)

> **同级别尺寸必须完全一致。** 不允许混用。

| 级别 | 类名 | 高度 | padding | 字号 | dot | 用途 |
| ---- | ---- | ---- | ------- | ---- | --- | ---- |
| L1 大胶囊 | `.pill-l1` | 28 px | `0 12` | 13 | 8 px | 项目状态 / 列表行主标签 |
| **L2 中胶囊 ★ 默认** | `.pill-l2`(或不写) | 22 px | `0 10` | 11.5 | 6 px | 卡片内 / 表格内默认 |
| L3 小胶囊 | `.pill-l3` | 18 px | `0 8` | 10.5 | 5 px | KPI 角标 / 行内 mono 标签 |

**4 种色调:**

| 类名 | 文字色 | 底色 | 边框 | 含义 |
| ---- | ------ | ---- | ---- | ---- |
| `.pill.info` | `--heat` | `--heat-12` | `--heat-20` | 信息 / 进行中 / 默认强调 |
| `.pill.ok` | `--accent-forest` | `--forest-bg` | `--forest-bd` | 成功 / 已完成 |
| `.pill.err` | `--accent-crimson` | `--crimson-bg` | `--crimson-bd` | 失败 / 错误 |
| `.pill.neutral` | `--black-alpha-56` | `--black-alpha-4` | `--border-faint` | 中性 / 已归档 |

```html
<span class="pill pill-l2 pill-info"><span class="dot"></span>生成中</span>
```

每个 pill 前置 `<span class="dot"></span>`,色继承 `currentColor`。

### §4.3 输入族

| 类名 | 高度 | 用法 |
| ---- | ---- | ---- |
| `.input` | 36 px | 单行文本框 |
| `.textarea` | 自动 | 多行 · min 88 px / line-height 1.6 / resize vertical |
| `.select` | 36 px | 下拉 · 带 chevron 背景图 |
| `.field` | flex col / gap 6 | 包 label + input + hint 的容器 |
| `.field-label` | 13 / 500 | 字段标签(必填用 `<span class="req">*</span>`) |
| `.field-hint` | 12 / `--black-alpha-48` | 字段提示 |
| `.search-box`(sidebar) | 36 px | 顶部全局搜索 + Ctrl K |
| `.toolbar .search-inline` | 36 px | 列表页工具栏内嵌搜索(左侧 icon 必加 `z-index: 2`) |

**5 种状态:**

| 状态 | 边框 | 底色 |
| ---- | ---- | ---- |
| Default | `--black-alpha-12` | `--surface` |
| Hover | `--black-alpha-24` | `--surface` |
| Focus | `--heat-40` + `inset 0 0 0 1px --heat-40` | `--surface` |
| Error | `--accent-crimson` | `--crimson-bg` |
| Disabled | `--black-alpha-12` | `--black-alpha-5` + 字 `--black-alpha-32` |

**占位字色:** `--black-alpha-48`,disabled 占位 `--black-alpha-24`。

**带 Ctrl K 搜索框关键坑:**
1. 左侧 icon 必须 `z-index: 2`(否则被 input 白底盖住)
2. 用 "Ctrl K" 纯文本,**不要用 `⌘` 字符**(Inter 不带该字形,显示成方框)
3. 快捷键提示不要 kbd 边框,**纯灰色 mono 平铺**(克制)
4. 字体用 `var(--font-inter) / 700`(Inter Bold 紧凑感)

### §4.4 表单控件(Checkbox / Radio / Switch)

**通用原则:** 全部用真 SVG indicator(via background-image data URI 或 inline `<svg>`),**禁止用 border-width / transform: rotate(45deg) 凑对勾**。

| 控件 | 容器尺寸 | Checked 表现 |
| ---- | -------- | ------------ |
| Checkbox `.ck` | 16×16 / 4 px 圆角 / 边 `--black-alpha-24` | `--heat` 底 + 12×12 白 SVG checkmark |
| Indeterminate | 同上 | `--heat` 底 + 12×12 白 SVG 横线 |
| Radio `.rd` | 16×16 圆 / 边 `--black-alpha-24` | 8×8 `--heat` 实心圆(`::after` 即可) |
| Switch `.sw` | 28×16 / 999 圆角 | On: `--heat` 底,圆球右移 `left: 14px` |

Disabled: 底 `--black-alpha-5` + 边 `--black-alpha-12` + 半透明。

### §4.5 KPI 统计行(`.stats`)

```html
<div class="stats with-corners">
  <div class="stat">
    <div class="lbl">本月营收 <span class="pill pill-l3 pill-ok"><span class="dot"></span>+33%</span></div>
    <div class="v">¥327<small>.40 K</small></div>
    <div class="delta up">↑ 较上月 +33%</div>
  </div>
  <!-- ×4 -->
</div>
```

- 1 行 4 格 grid,共用一个 inside-border 容器,圆角 8 px,**无 gap**
- 列与列之间用 `border-right: 1px solid var(--border-faint)`(最后一列去掉)
- 容器四角加 SVG "+" 准星(`.with-corners`)
- 每格结构:label + L3 pill → 大数字(32 px) → delta / mini progress

### §4.6 进度条(5 段流水线)

```html
<div class="prog">
  <span class="done"></span><span class="done"></span>
  <span class="cur"></span><!-- 或 .now -->
  <span></span><span></span>
</div>
```

每段 18×5 px / 3 px 间距 / 2 px 圆角。

| 状态 | 颜色 | 动画 |
| ---- | ---- | ---- |
| 未开始 | `--black-alpha-8` | 静态 |
| 已完成 `.done` | `--accent-forest` | 静态 |
| 进行中 `.cur` 或 `.now` | `--heat` | **1.4s 脉动** opacity 1↔0.55 + scaleY 1↔0.7 |
| 失败 `.fail` / `.err` | `--accent-crimson` | 静态 |

**核心:** 动 = 在运行,静 = 完成/失败。脉动只给"进行中"。

### §4.7 列表行(`.list-row`)

```
[缩略图 56×72] [标题 + meta] [.prog 5 段] [.pill L2] [.btn-sm]
```

- grid: `56px 1fr auto auto auto` / gap 22
- padding: `20 24`
- 行间 1 px 分隔(`--border-faint`),最后行去
- Hover: `--black-alpha-4` 底色

#### §4.7.1 表格(`table.t` / 数据表)

**适用:** 项目列表 / 任务中心 / 成员表 / 消费流水等需要横向扫描的数据表。

- 外层只保留 1 px `--border-muted` + 8 px 圆角,形成清楚容器边界
- 表头保留 1 px `--border-muted` 下分割线,表头底色用 `--background-lighter`
- **tbody 行与行之间不画横向分割线**;用 `padding`、留白、hover 底色区分行
- 行 hover 只用 `--black-alpha-4`,不加阴影、不换 hue
- 表格内状态优先用 `.pill-l2` / `.pill`,行末操作用 `.btn-sm` 或 icon button

**禁:** 表格 tbody 每行密集 `border-bottom`、双层外框、白色/裸 hex 边框、用强阴影分隔行。

### §4.8 Tabs(主 / 副)

**主 Tab(下划线激活):**
- 高 36 px / padding `0 14` / 字号 13 / 字重 500
- 未选中: `--black-alpha-56`
- 选中: `--accent-black` + bottom 2 px `--heat` 横线
- Hover(未选中): `--black-alpha-4` 底

**副 Tab(过滤型):**
- 高 28 px / padding `0 10` / 字号 12
- 未选中: `--black-alpha-56` + 灰度 icon
- 选中: `--accent-black` + 彩色 icon
- Tab 之间用 1 px 高 12 的 `--ink-alpha-7` 竖条分隔

### §4.9 Chip 筛选(下拉)

```html
<div class="chip-wrap">
  <button class="chip"><span>商品品类</span><svg class="caret"></svg></button>
  <div class="chip-menu"><!-- .mi 选项 · 多选含 .mi-check --></div>
</div>
```

- `.chip` 高 36 / padding `0 14` / 字号 13 / 圆角 8
- Active: 边 `--heat-40` + 字 `--heat` + 底 `--heat-12`
- 打开后菜单 `.chip-wrap.open .chip-menu { display: block }`
- 选项 `.mi` 高 32 / hover `--black-alpha-4` / selected `--heat-12` + 右侧 `--heat` 勾

### §4.10 卡片 / 快捷入口

| 类名 | 描述 |
| ---- | ---- |
| `.card-hard` | 通用硬卡 · 白底 + inside-border + 8 px 圆角 |
| `.card-hard.with-corners` | 加四角 SVG 准星 |
| `.shortcut` | 快捷入口 · 左 32×32 橙 icon-box + 右标题 + mono 描述 |
| `.tip` | 提示框 · **1 px dashed** 边框 + 加粗标题 + 正文 |
| `.placeholder` | 缩略图占位 · 灰底网纹 · 内置 `.ph-frame` 显示 `9:16` |
| `.product-card / .proj-card / .asset-card` | 各类卡片(模板见现有页面) |

`.icon-box`:32×32 / 8 px 圆角 / `--heat-12` 底 / 16 px line icon(`--heat`)。

### §4.11 浮层 / 反馈

| 组件 | 类名 | 关键参数 |
| ---- | ---- | -------- |
| Modal | `.modal-bg > .modal > .modal-h/b/f` | 居中 460-480 px · 4 角 SVG 准星 · `rgba(21,20,15,.42)` 遮罩 + `backdrop-filter: blur(8px)` · 进入 `scale(.96→1)` / 250ms 弹性 · ESC / 点击遮罩关闭 |
| Drawer | `.drawer-bg > .drawer > .drawer-h/b/f` | 右侧抽屉 · 默认 540 px(商品 drawer 820 px) · 进入 `translateX(100%→0)` / 250 ms |
| Toast | `.toast`(`.show` 触发) | 右下 24 px / 白底 inside-border + `--shadow-floating` / 进入 `translateX(420→0)` 300ms 弹性 / 自动 2400 ms 消失 / 内含 24×24 橙 icon-box + 标题 + mono 副文 |
| Empty | `.empty-state.show` | 虚线边框 + 灰 icon + 标题(14/600)+ mono 描述 |
| 缺图徽标 | `.tri-missing-badge` + `.tri-missing-pop` | 商品/人物卡缩图左上角橙底告警徽标 + hover 暗色 tooltip |
| 卡片删除 | `.card-del-btn` | 卡片右上角 hover 显示 · 32×32 / 红 hover |
| 批量栏 | `.bulk-bar` | 选中后吸底浮动操作栏 |
| 卡片勾选 | `.card-check` | 卡片左上角 22×22 圆形 checkbox(编辑模式 hover 显示) |
| Spinner | `.spinner` | 18×18 旋转 · 2 px 橙边 |

### §4.12 Icon 系统

**通用规则:**
- 一律 **SVG inline**,禁止 `<img>` 引图标
- 库:统一使用本地 Lucide-line 注册表 `assets/icons.js` 的 `IconKit.svg(name, opts)`,禁止页面内临时手写另一套图标
- `stroke-width: 1.5` / `stroke-linecap: round` / `stroke-linejoin: round` / `fill: none`
- 颜色:`stroke="currentColor"` 继承
- **禁:** 彩色 emoji / filled icon

**5 档尺寸:**

| 档 | 尺寸 | 用途 |
| -- | ---- | ---- |
| S | 14 px | 内嵌 inline 文字旁 |
| **M ★ 默认** | 16 px | 按钮内 / Tab / list 行 |
| L | 20 px | 顶栏 / 快捷入口 / dropdown 触发器 |
| XL | 24 px | Modal 头 / Toast / 空状态 |
| Hero | 36 px | 空状态插画 / 大占位 |

**颜色:** 默认 `--black-alpha-56` / hover `--accent-black` / active `--heat` / disabled `--black-alpha-12` / 在主 CTA 内 `#fff`。

### §4.13 AI 对话面板(编辑器型页面专用)

> **使用范围:** AI 图片创作 / 流水线 AI 助手 / 商品 AI 优化 / 镜头脚本编辑。3 个编辑器页(pipeline / model-photo / image-optimize)定义一致 — 已成事实组件,该抽到 restraint.css。

#### HTML 结构

```html
<div class="pane chat-pane">
  <div class="pane-h">
    <span class="ic-box"><svg>...</svg></span>
    <span class="ti">AI 助手</span>
    <span class="mono" style="margin-left:auto">// chat /v2</span>
  </div>
  <div class="chat-body">
    <div class="msg ai">
      <div class="bubble">你好,我来帮你优化这张图...</div>
      <div class="mono ts">// 14:32</div>
    </div>
    <div class="msg user">
      <div class="bubble">请把背景换成咖啡厅</div>
    </div>
    <div class="msg ai">
      <div class="ai-thinking"><span class="dots"><span></span><span></span><span></span></span></div>
    </div>
  </div>
  <div class="chat-input">
    <div class="chat-input-card">
      <textarea placeholder="@AI 帮我..."></textarea>
      <div class="chat-input-actions">
        <button class="btn btn-sm btn-ghost">附件</button>
        <button class="btn btn-sm btn-primary">发送 →</button>
      </div>
    </div>
  </div>
</div>
```

#### 关键 CSS

| 类 | 关键属性 |
| -- | -------- |
| `.chat-pane` | `flex column / 高度填充父容器` |
| `.chat-body` | `flex 1 / overflow-y auto / padding 16 18 / gap 14 / flex column / max-height 460(可选)` |
| `.chat-input` | `padding 14 18 18 / border-top 1px var(--border-faint)` |
| `.chat-input-card` | `bg --background-base / border 1px --border-faint / radius 8 / padding 12 14 10` · `:focus-within` 边变 `--accent-black` + ring `0 0 0 3px rgba(0,0,0,.04)` |

#### 消息气泡(`.msg.ai` / `.msg.user`)

| 类型 | 对齐 | 气泡背景 | 气泡边框 | 字色 |
| ---- | ---- | -------- | -------- | ---- |
| `.msg.ai` | 左对齐(默认) | `--surface` 白 | `--border-faint` | `--accent-black` |
| `.msg.user` | 右对齐(`align-items: flex-end`) | `--heat-12` 浅橙 | `--heat-20` | `--accent-black` |

所有气泡共享:`max-width 90% / padding 10 14 / font-size 13 / line-height 1.6 / radius 8`。
时间戳放气泡下:mono 11 px / `--black-alpha-48` / 格式 `// 14:32`。

#### 打字指示器(`.ai-thinking`)

3 个 6×6 圆点 · 1.2 s 交替闪烁:

```css
.ai-thinking .dots { display: inline-flex; gap: 3px; }
.ai-thinking .dots span {
  width: 6px; height: 6px; background: var(--black-alpha-32);
  border-radius: 50%;
  animation: thinking 1.2s ease-in-out infinite;
}
.ai-thinking .dots span:nth-child(2) { animation-delay: .15s; }
.ai-thinking .dots span:nth-child(3) { animation-delay: .30s; }
@keyframes thinking {
  0%, 80%, 100% { opacity: .25; }
  40% { opacity: 1; }
}
```

---

### §4.14 商品 / 资产卡片体系(3 种形态)

> **核心原则:** 商品 + 资产 + 人物 + 场景共用**一套**卡片体系,按"使用场景"选形态。**不要为每种内容类型做新类。**

#### 三种形态总览

| 形态 | 类名(建议统一) | 缩图比 | 缩图宽度 | 使用场景 |
| ---- | -------------- | ------ | -------- | -------- |
| **网格主卡** | `.product-card` | 1.4:1(商品)· 1:1(资产/场景)· 3:4(人物) | 自适应宽 | 商品库 / 资产库 / 团队页主网格 |
| **行卡(列表)** | `.prod-row` 或 `.mp-prod-item` | 1:1 | 28–36 px | 表单内已选行 / 侧栏列表 |
| **选择器卡** | `.pl-card` / `.opt-card` / `.model-card` | 1:1 或 3:4 | 100–160 px | Modal 内多选 picker |

#### 4.14.1 网格主卡(`.product-card`)

```html
<div class="product-card">
  <div class="product-thumb placeholder">9:16</div>
  <div class="product-body">
    <div class="product-name">夏季新款蕾丝连衣裙</div>
    <div class="product-cat mono">// 女装 · 蓝色</div>
  </div>
  <div class="product-footer">
    <span class="stat">素材 <b>124</b></span>
    <span class="sep">·</span>
    <span class="stat">视频 <b>36</b></span>
  </div>
</div>
```

关键 CSS:
- 容器:`bg --surface / border 1px --border-faint / radius 8 / display flex column / overflow hidden / cursor pointer`
- hover:`bg --background-lighter / border --black-alpha-48`
- 缩图:`aspect-ratio` 按内容类型选 — 商品 `1.4/1` · 资产 `1/1` · 人物 `3/4`
- body:`padding 14 14 12 / flex 1`
- name:`14 / 600 / --accent-black / 单行省略`
- cat(分类):mono 11 / `--black-alpha-48`
- footer:`grid 1fr auto 1fr / padding 10 12 / border-top 1px --border-faint / bg --background-base / font 11.5 / 字 --black-alpha-56`

**变体:**
- `.product-card.with-action` — footer 右侧加一个小按钮(用于流水线 stage 2 资产库的"AI 生成"入口)
- `.product-card` 默认支持 selectable 模式:加 `.card-check` 22×22 圆形 checkbox(左上 hover 显示)+ 选中态 border 加深

#### 4.14.2 行卡(`.prod-row` / `.mp-prod-item`)

```html
<div class="prod-row">
  <div class="thumb placeholder">9:16</div>
  <div class="nm">夏季新款蕾丝连衣裙</div>
  <button class="row-swap"><svg>swap</svg></button>
  <button class="row-x"><svg>×</svg></button>
</div>
```

紧凑行卡:`flex align-center / gap 10 / padding 8 10 / bg --background-lighter / border 1px --border-faint / radius 6 / 28-36 px 缩图 + 单行文本`。

**用法:**
- 表单里"已选商品"列表(可删可换)
- 侧栏商品/演员列表(`.mp-prod-item` · 36×36 缩图)
- 流水线 stage 选中态

#### 4.14.3 选择器卡(`.pl-card`)

```html
<div class="pl-card selected">
  <div class="pl-thumb placeholder">3:4</div>
  <div class="pl-name">夏季新款蕾丝连衣裙</div>
  <div class="pl-check"><svg>✓</svg></div>
</div>
```

Modal 内多选 picker:`bg --background-lighter / padding 10 / display flex column / gap 6 / cursor pointer`。

3 种状态:

| 状态 | 视觉 |
| ---- | ---- |
| 默认 | `bg --background-lighter / border 1px --border-faint` |
| hover | `bg --surface`(变白) |
| **selected ★** | `border var(--heat) / bg var(--heat-12)` + 右上角橙色勾 SVG |

---

### §4.15 人物 / 演员 / 模特卡片(`.model-card`)

> **本质:** 选择器卡的"人物 3:4 竖图"特例。**复用 `.pl-card` 的选中态逻辑**,只换缩图比例。

```html
<div class="model-card selected">
  <div class="m-thumb placeholder">3:4</div>
  <div class="m-name">林夏 · 25 岁</div>
  <div class="m-meta mono">// 165cm · 都市风</div>
</div>
```

| 元素 | 样式 |
| ---- | ---- |
| 缩图 | `aspect-ratio: 3/4`(人物竖图标准) |
| name | 12.5 / 500 / `--accent-black` |
| meta | mono 11 / `--black-alpha-48` |
| 选中态 | 同 `.pl-card`(橙边 + 橙底 + 右上勾) |

**与 `.pl-card` 的关系:** 同一基类,仅缩图比例不同 — 商品 1:1 / 人物 3:4。
**建议实现:** `.model-card` 继承 `.pl-card` 基类 + 覆盖 `.pl-thumb` 的 `aspect-ratio`。

---

### §4.16 场景卡片(复用 `.asset-card-2`)

> 场景卡 = 资产卡的"1:1 通用"形态。**不要做新类**,只语义命名。

```html
<div class="asset-card-2 scene-card">
  <div class="thumb-2 placeholder">1:1</div>
  <div class="body-2">
    <div class="ti">咖啡厅 · 暖光</div>
    <div class="sub mono">// indoor · warm</div>
  </div>
</div>
```

`.asset-card-2`(通用资产卡基础):
- `bg --surface / border 1px --border-faint / radius 8 / overflow hidden / display flex column`
- hover:`border --heat-40 / box-shadow 0 1 3 rgba(0,0,0,.04)`
- 缩图:`aspect-ratio 1` 正方形 · 通常宽 240 px(flex shrink 0)
- body:`padding 12 14`
- ti:14 / 500 / `--accent-black` · sub:mono 11 / `--black-alpha-48`

**派生类只做语义命名:** `.scene-card` / `.person-card` / `.background-card` — 样式继承 `.asset-card-2`,**不要重新写规则**。

---

### §4.17 其他高频复用组件

以下组件已在 2-5 个页面重复定义,需要尽快抽到 restraint.css。规范在此先记录。

#### 4.17.1 流程步骤条(`.stepper` / `.stage-step`)

```html
<div class="stepper">
  <div class="stage-step done"><span class="num">1</span><span class="lbl">商品</span></div>
  <div class="stage-step active"><span class="num">2</span><span class="lbl">故事板</span></div>
  <div class="stage-step"><span class="num">3</span><span class="lbl">镜头</span></div>
  <div class="stage-step"><span class="num">4</span><span class="lbl">生成</span></div>
  <div class="stage-step"><span class="num">5</span><span class="lbl">投放</span></div>
</div>
```

| 元素 | 样式 |
| ---- | ---- |
| 容器 | `flex align-center / padding 14 18 / bg --surface / border 1px --border-faint / radius 8` |
| `.num` 编号 | 26×26 / mono 12 / 600 / radius 4 / 默认 `bg --surface + border 1px --border-faint + 字 --black-alpha-48` |
| `.done .num` | `bg --accent-black + 字 --accent-white`(已完成 · 黑) |
| **`.active .num`** | `bg --heat + 字 --accent-white`(进行中 · 橙) |
| 步间连接线 | 1 px / `--border-faint` / 高 1 px / 长度自适应 |

**与 `.prog` 区别:** `.prog` 是 5 段进度条徽标(横放在卡片角落),`.stepper` 是大尺寸主流程步骤条(放在 page-head 之下)。

#### 4.17.2 分页(`.pagination`)

```html
<div class="pagination">
  <span class="total">共 <b>12</b> 条</span>
  <button class="page-size">12 条/页</button>
  <span class="pages">
    <button>1</button>
    <button class="active">2</button>
    <button>3</button>
  </span>
  <span class="jump">跳至 <input type="number"> 页</span>
</div>
```

| 元素 | 样式 |
| ---- | ---- |
| 容器 | sticky bottom / `flex gap 16 / padding 14 0 / border-top 1px --border-faint / bg --background-base / font 12.5 / 字 --black-alpha-56` |
| 页码按钮 | 30×30 / radius 4 · 4 px 不是 8(密集场景小圆角不破节奏) |
| 默认页 | `bg --surface / border 1px --border-faint / 字 --black-alpha-72` |
| **激活页 ★** | `bg --heat / 字 --accent-white / 600 字重` |

#### 4.17.3 视图切换(`.view-toggle`)

```html
<div class="view-toggle">
  <button class="active"><svg>grid</svg></button>
  <button><svg>list</svg></button>
</div>
```

| 元素 | 样式 |
| ---- | ---- |
| 容器 | `inline-flex / bg --surface / border 1px --border-faint / radius 4 / padding 2`(外壳 4,因子按钮 4) |
| 按钮 | 30×28 / radius 4 / transparent / 字 `--black-alpha-48` |
| hover | `bg --black-alpha-4 / 字 --accent-black` |
| **激活 ★** | `bg --accent-black / 字 --accent-white`(**注意:不是橙**) |

> **为何用黑不用橙:** 视图切换是"显示模式开关",不是 CTA。黑表达"激活态"又不抢主橙的舞台。**同理:任何"模式切换"按钮组都用黑激活,不用橙。**

#### 4.17.4 操作型胶囊(`.pill-tip`)

```html
<button class="pill-tip">→ 去商品库</button>
```

- 高 28 / padding 0 14 / radius 999 / font 12 / weight 500
- 默认:`bg --heat-12 / border 1px --heat-20 / 字 --heat`
- hover:`bg --heat / 字 --accent-white / box-shadow var(--shadow-cta)`

**与 `.pill.info` 区别:** `.pill.info` 是状态徽标(静态展示),`.pill-tip` 是可点击操作(动态橙底反馈 · hover 升级到主 CTA 视觉)。

#### 4.17.5 卖点 / 编辑式列表(`.bullet-list`)

```html
<ul class="bullet-list">
  <li class="bl-item">
    <span class="num">1</span>
    <span class="bl-text">100% 棉麻 · 透气吸汗</span>
    <button class="bl-x">×</button>
  </li>
  <li class="bl-item">
    <span class="num">2</span>
    <span class="bl-text">独家设计 · 限量 200 件</span>
    <button class="bl-x">×</button>
  </li>
  <li class="bl-add">
    <span class="num">+</span>
    <input class="bl-input" placeholder="添加卖点(Enter 确认)">
  </li>
</ul>
```

| 元素 | 样式 |
| ---- | ---- |
| 行 `.bl-item` | `flex gap 10 / padding 8 12 / bg --background-lighter / border 1px --border-faint / radius 8 / mb 6` |
| 序号 `.num` | 22×22 / mono 11 / 700 / 字 `--heat` / `bg --surface / border 1px --border-faint / radius 4` |
| `.bl-text` | 13.5 / `--accent-black` / `flex 1` |
| `.bl-x` 删除 | 22×22 / 圆 · hover 时显示(默认 `opacity 0`)· hover 变红 |
| **`.bl-add` 添加行 ★** | 同 `.bl-item` 但 `border-style: dashed / bg transparent` |
| `.bl-add .num` | `bg transparent / border 1px dashed --heat-40 / 字 --heat`(显示 `+`) |
| `.bl-input` | `height 24 / border 0 / bg transparent / outline none / 字 13` |

---

### §4.18 AI 生成结果卡(`.gen-card`)

> **来源:** AI 图片创作 / 视频创作 / 任何"输入提示词 → 多候选输出"场景。
> **三个可变接口:** ① 图片比例 ② 悬浮按钮的功能 ③ 底部按钮的功能。**其他全部复用。**

#### 组件骨架

```html
<div class="gen-card">
  <!-- ① Prompt 提示词行 -->
  <div class="gen-prompt">
    <svg class="quote"><!-- 16px " 引号 --></svg>
    <span class="text">一只穿着宇航服的橘猫,漂浮在霓虹色星云中,赛博朋克风</span>
  </div>

  <!-- ② Meta chip 行(竖线分隔) -->
  <div class="gen-meta">
    <span class="m-item">Airshelf v2</span>
    <span class="m-sep">|</span>
    <span class="m-item">1:1</span>
    <span class="m-sep">|</span>
    <span class="m-item">1K · 2 天前</span>
  </div>

  <!-- ③ 图片网格(N 张候选 · 比例由 --ratio 控制) -->
  <div class="gen-images" style="--cols:4; --ratio: 1/1">
    <div class="gen-image">
      <div class="placeholder"><span class="ph-frame">1:1 · #1</span></div>
      <!-- hover 浮层 · 右上按钮组 -->
      <div class="gen-image-actions">
        <button class="gen-img-btn" data-act="regen"><svg><!-- ↻ --></svg></button>
        <button class="gen-img-btn" data-act="dl"><svg><!-- ↓ --></svg></button>
        <button class="gen-img-btn" data-act="more"><svg><!-- ··· --></svg></button>
      </div>
      <!-- 点击反馈 · 中央 toast(默认 opacity 0) -->
      <div class="gen-image-feedback">
        <svg><!-- ✓ --></svg>
        <span>已添加到剪贴板</span>
      </div>
    </div>
    <!-- × N -->
  </div>

  <!-- ④ 底部操作按钮行 -->
  <div class="gen-card-actions">
    <button class="btn btn-sm"><svg></svg>重新编辑</button>
    <button class="btn btn-sm"><svg></svg>再次生成</button>
    <button class="btn btn-sm btn-ghost"><svg></svg></button>
  </div>
</div>
```

#### 关键 CSS

| 区域 | 样式 |
| ---- | ---- |
| 容器 `.gen-card` | `bg --surface / border 1px --border-faint / radius 8 / padding 16 / display flex column / gap 14` |
| 选中态 `.gen-card.selected` | `border-color --heat`(可选 modifier) |
| Prompt `.gen-prompt` | `flex align-start / gap 10 / padding 0 4` |
| Prompt 引号 `svg.quote` | 16×16 / `--black-alpha-32` / margin-top 2 |
| Prompt 文本 `.text` | 14 / 500 / `--accent-black` |
| Meta 行 `.gen-meta` | `flex align-center / gap 8 / padding 0 4 / font 11.5 mono / 字 --black-alpha-48 / letter-spacing .04em` |
| Meta 分隔 `.m-sep` | `--black-alpha-24`(直接用 `\|` 字符) |
| 图片网格 `.gen-images` | `display grid / grid-template-columns repeat(var(--cols), 1fr) / gap 10` |
| 单张图 `.gen-image` | `position relative / aspect-ratio var(--ratio) / radius 8 / overflow hidden / cursor pointer` |
| 浮层按钮组 `.gen-image-actions` | `absolute / top 8 right 8 / flex gap 2 / bg --surface / border 1px --border-faint / radius 8 / padding 2 / opacity 0 / z-index 2 / shadow 0 2 8 rgba(0,0,0,.08)` · hover `.gen-image` 时 `opacity 1` |
| 浮层按钮 `.gen-img-btn` | `28×28 / radius 6 / bg transparent / 字 --black-alpha-56 / border 0 / cursor pointer` · hover `bg --black-alpha-4 / 字 --accent-black` |
| 中央反馈 `.gen-image-feedback` | `absolute / inset 0 / flex column center / gap 8 / bg rgba(38,38,38,.88) / 字 --accent-white / radius 8 / opacity 0 / transition opacity .2s / pointer-events none` |
| 反馈触发态 `.gen-image.show-feedback .gen-image-feedback` | `opacity 1`(1.5 s 后 JS 移除) |
| 反馈 icon | 20×20 / 白 SVG ✓ |
| 反馈文字 | 12.5 / 500 / 白 |
| 底部按钮行 `.gen-card-actions` | `flex gap 8 / padding-top 4` |

#### 三个可变接口

| 维度 | 怎么变 |
| ---- | ------ |
| **① 图片比例** | 改 `style="--ratio: 1/1"` 为 `9/16` `16/9` `4/5` `3/4` 等 · 同时可改 `--cols` 控制列数(4 张方图 4 列 / 2 张竖图 2 列) |
| **② 悬浮按钮功能** | 改 `<button data-act="X">` 的 act 名 + icon SVG · 数量 1–4 个(超过 4 个合并到 ··· 弹出菜单) |
| **③ 底部按钮功能** | `.gen-card-actions` 内放 `.btn.btn-sm` · 通常 1-2 个二级 + 1 个三级 ghost ··· · **不放主橙**(避免抢 prompt 视觉) |

#### 反馈 toast 触发 JS

```js
img.addEventListener('click', () => {
  img.classList.add('show-feedback');
  setTimeout(() => img.classList.remove('show-feedback'), 1500);
});
```

#### 适用场景

- AI 图片创作(2-8 张候选图 · 1:1 或 9:16)
- AI 视频创作(1-4 段候选视频 · 16:9 或 9:16 · 缩图用 video poster)
- 模板生成结果(批量预览选择)
- 任何"prompt 输入 → 多候选输出"流程

#### Don't

- ❌ **给每个图片单独写卡样式** — 用 `.gen-image` 通用
- ❌ **悬浮按钮组放图片底部** — 永远右上(避免遮挡图片主体)
- ❌ **用全局 toast 通知"已复制"** — 用本组件内的 `.gen-image-feedback`(就地反馈,用户不必转头看屏幕角落)
- ❌ **把 prompt 文字截断省略** — 完整显示(它就是用户的输入 · 要看清)
- ❌ **底部按钮做成主橙 primary** — 抢了 prompt 的视觉重心,用二级 `.btn` 即可

---

## §5 · Mono 装饰元素(品牌签名 · 不能丢)

> 方括号标签 / 双斜杠注释 / 中点连接 —— 这些是Airshelf 独有的"调试视图感",Firecrawl 没有,绝对保留。

| 用法 | 示例 |
| ---- | ---- |
| 方括号标签 | `[ 200 OK ]` `[ /v2 ]` `[ .MP4 · 9:16 ]` `[ STUDIO ]` `[ ALL · 12 ] →` |
| 注释时间戳 | `// 05.14 · 周五 · 14:32` |
| 命令路径 | `/sidebar collapse · /toast dismiss` |
| 数值后缀 | `¥327`(主体大字)+ `<small>.40</small>`(小字次级) |
| 强调单词上色 | `<b style="color: var(--accent-black)">3 个项目</b>` — 加深一档,**不变橙**。橙色只留给 CTA |
| ASCII 散点装饰 | 主区域 4 角撒 `· · + +XX+ +XXXX·` / 8.5 px / `--black-alpha-12` |
| 边角 Mono 标签 | 主区域 4 角:左上 `[ 200 OK ]` / 右上 `[ /v2 ]` / 左下 `[ .MP4 · 9:16 ]` / 右下 `[ STUDIO ]` |
| 链接式"更多" | `[ ALL · 12 ] →` — mono 标签 + 箭头,`--black-alpha-48`,hover 转橙 |
| 缩略图占位 | 不放假图,放比例 `9:16` mono 字符 |

**字体:** `var(--font-mono)` / 11 px / `0.04em` 字距(标签场景)。

---

## §6 · 五种页面级布局模式

页面骨架统一,**内容区布局**按用途分 5 类:

### A · 看板型(Dashboard)
**代表页:** [index.html](index.html) · [projects.html](projects.html)(列表)· [library.html](library.html)
**布局:** KPI 行(`.stats.with-corners`)→ 多个 section(`.section-h` + 内容卡)→ 列表行 / shortcut 网格
**辅助类:** `.dash-grid`(1.7 fr + 1 fr 主辅)/ `.recent-row` / `.shortcut` / `.tip`(虚线提示)

### B · 列表 + 筛选型(List + Filter)
**代表页:** [products.html](products.html) · [projects.html](projects.html) · [library.html](library.html) · [team.html](team.html)
**布局:**
```
[ toolbar(search-inline + chip-wrap × n + view-toggle) ]  ← sticky top
[ result-meta · 共 N 条 ]
[ ░░ 卡片网格 / 列表 ░░ ]
[ pagination ]                                            ← sticky bottom
[ bulk-bar(选中后显示) ]                                  ← 吸底浮动
```
**辅助类:** `.product-card / .proj-card / .asset-card` · `.view-toggle` · `.pagination` · `.bulk-bar` · `.card-check` · `.card-del-btn`

### C · 编辑器型(Editor / IDE)
**代表页:** [pipeline.html](pipeline.html) · [model-photo.html](model-photo.html) · [image-optimize.html](image-optimize.html) · [studio.html](studio.html)
**特征:** 锁视口高度 · 多栏内部滚 · 大量页面级独有样式(目前 inline `<style>` 600-1400 行)
**布局:** 左栏(资产/导航 sticky)+ 中央(画布/参数)+ 右栏(预览/AI 助手)
**⚠️ 警告:** 这一类页面定制最多,改之前先确认 restraint.css 没有现成组件再加 inline。

### D · 表单 / 向导型(Wizard / Form)
**代表页:** [projects-new.html](projects-new.html) · [products.html](products.html) drawer · [account.html](account.html) · [settings.html](settings.html)
**布局:** 左侧 sticky 步数条 + 右侧多 pane 同时显示(非 Tab 切换)
**辅助类:** `.wizard` · `.steps .step` · `.wiz-pane` · `.opt-card` · `.bullet-list`

### E · 单卡型(Single Screen)
**代表页:** [login.html](login.html) · [register.html](register.html)
**特征:** 不渲染 sidebar/topbar · 全屏灰底 + 中心白卡

---

## §7 · 待统一清单(V2.1 落地偏离点)

> 扫完 18 个 HTML 发现的偏离点。按影响视觉一致性的程度排序。**改页面时遇到这些点,顺手改正。**

### 高优先级(影响视觉对齐)

| # | 问题 | 现状 | 应改为 |
| - | ---- | ---- | ------ |
| 1 | **按钮等级混乱**(★ 最严重) | 各页随意选 `.btn` / `.btn-primary` / `.btn-ghost`,有的页面 2 个一级按钮并列,有的把"取消"做成主橙;尺寸也乱(38/32/44 混) | 按 §4.1 三级体系:**一个区域只 1 个一级**(`.btn-primary`,主动作)· 二级 `.btn`(并列动作)· 三级 `.btn-ghost`(辅助)· 尺寸默认 36 / lg 40 / sm 28 |
| 2 | 输入框高度 | products 38 / projects search 32 / login 36 | 统一 36 |
| 3 | Tab 激活样式 | product-detail 下划线 / library 底色填充 | **统一下划线 + bottom 2 px `--heat`** |
| 4 | Hover 底色 | 多数 `--background-lighter` / 部分 `--black-alpha-4` | **统一 `--black-alpha-4`** |
| 5 | 卡片标题字号 | projects 13.5 / products 14 | **统一 14 px / 500** |
| 6 | 卡片网格列宽 | products 240 固定 / library auto-fill 180 / projects-new 4 列固定 | 商品类 240 · 资产类 180 · 通用 `auto-fill minmax(220px, 1fr)` |

### 中优先级(语义偏离)

| # | 问题 | 现状 | 应改为 |
| - | ---- | ---- | ------ |
| 7 | Pill 变体不全 | restraint.css 只 4 种(info/ok/err/neutral),library 用了 `.pill.archive` 没定义 | 在 restraint.css 补 `.pill.archive`(灰)、`.pill.warn`(honey 黄) |
| 8 | X 关闭按钮 | drawer 30 / modal 32 / toast inline 28 | **统一 32×32 / 8 px 圆角** |
| 9 | label 字重 | products 500 / product-detail 600 | **统一 500** |
| 10 | mono 装饰 | 部分页有 4 角 `[ 200 OK ]`,部分没 | **主工作台型必须有,编辑器型可省** |
| 11 | section-h 分隔 | 部分用 `border-bottom`,部分不用 | **统一不用**(留白即分隔) |

### 低优先级(架构清理)

| # | 问题 | 现状 | 应改为 |
| - | ---- | ---- | ------ |
| 12 | 编辑器页 inline `<style>` 过大 | pipeline 795 / model-photo 1393 / platform-cover 1003 行 | 抽 `.stepper / .shot-card / .mp-prod-item / .pl-modal` 等高频组件到 restraint.css 或独立 editor.css |
| 13 | 四角准星重复 SVG | restraint.css 已有 `.with-corners` 工具,部分页面又自己定义了 SVG 背景 | 全部改用 `.with-corners` + `<span class="corner-tr/.corner-bl">` |
| 14 | 滚动条样式残留 | 部分页 inline `scrollbar-width: thin` | restraint.css 已 `!important` 全局隐藏,清理 inline |
| 15 | mono 字体里的中文 | 部分页直接写 `font-family: monospace` 走系统字体 | 全部换 `var(--font-mono)` |

---

## §8 · Don't List(绝对禁止 · 每次自检)

- ❌ **0 px 硬切角的卡片** — 一律 8 px
- ❌ **大圆角 `>12 px`** — 直接判错
- ❌ **渐变背景 / 玻璃拟态** — 只允许 modal 遮罩 `backdrop-filter: blur`
- ❌ **彩色 emoji** — 一律 SVG line icon · stroke 1.5
- ❌ **多个 accent 色** — 全场只有橙(其他色仅做语义信号点)
- ❌ **hover 时换深 hue 的橙** — 用 alpha,不用更深的橙(`#D04E1F` 这种判错)
- ❌ **真 `border` + hover 边框消失** — 用 inside-border `::before`
- ❌ **居中对齐大段正文** — 全部左对齐
- ❌ **同一行混用直角和圆角** — "不要有些是直角,胶囊又是圆角"
- ❌ **荧光状态色** — 避免霓虹绿、电光蓝、霓虹粉
- ❌ **页面内 `<style>` 重写共享类**(`.btn` `.pill` `.input` `.modal` 等)— 改 restraint.css
- ❌ **新建色 token** — 必须复用现有 token
- ❌ **`⌘` Unicode 字符** — Inter webfont 不带该字形,显示成方框 → 用 "Ctrl K" 纯文本或 SVG
- ❌ **多色 emoji icon / filled icon** — 一律 line icon
- ❌ **居中卡片浮在背景上的"贴纸感"** — 用边框 + 装订线,不用阴影
- ❌ **彩虹流光 / hover 旋转缩放** — 无意义微动效
- ❌ **场记板 / 丝绒 / 霓虹灯** — 装饰盖过内容,判错

---

## §9 · 新页面 / 改页面 checklist(每次必过)

### 写代码前
- [ ] 已 Read 本文件 §1 § 3 § 8(至少)
- [ ] 用 `Grep` 查 restraint.css 是否已有该组件
- [ ] 看 `_archive/design-system.html` 找视觉参考(用浏览器打开 file://)
- [ ] 不确定的设计点 — **先问用户**,不要凭感觉

### 写代码时
- [ ] HTML 用 `<div class="app"><aside class="sidebar"></aside><main><div class="topbar"></div><div class="content">…</div></main></div>` 骨架
- [ ] head 含 `<link rel="stylesheet" href="assets/restraint.css">` + Inter Google Fonts
- [ ] body 末尾先引 `<script src="assets/icons.js" defer></script>`,再引 `<script src="assets/shell.js" defer></script>`
- [ ] 标题区用 `.page-head > h1 + .sub`
- [ ] 主操作按钮放 `.page-head > .actions`(自动 40 px 高)
- [ ] 子区块用 `.section-h > h2 + .more`
- [ ] 按钮全 `.btn` 系列 · 不要自己写
- [ ] 状态徽标全 `.pill.info/.ok/.err/.neutral` · 要新变体先回 restraint.css 加
- [ ] 输入框全 `.input / .select / .textarea` · 字段用 `.field`
- [ ] 浮层全用现成 Modal / Drawer / Toast
- [ ] 图标统一走 `IconKit.svg()` · SVG line icon · stroke 1.5 / linecap round / `stroke="currentColor"`
- [ ] 时间戳 mono 注释 `// 05.22 · 周四`
- [ ] 强调单词加深(不变橙) `<b style="color:var(--accent-black)">3 个</b>`
- [ ] 数字加 `.num` 或 `tabular-nums`
- [ ] 状态色按语义选 `--heat / --accent-forest / --accent-crimson / --accent-honey`

### 写完自检
- [ ] 对照 §8 Don't List 逐条过
- [ ] 在浏览器打开页面 · 截图 + 跟 design-system.html 对比
- [ ] 测 hover / focus / active / disabled 状态都正确
- [ ] 测 dark mode(给 body 加 `.dark` class 看是否破)
- [ ] 移动端缩到 1100 px 以下看响应式

### 提交前
- [ ] 不在 master/main 上,在 dev 分支
- [ ] 不带 `--no-verify`,不跳过 hook
- [ ] commit 信息简洁,说"为什么"不只是"什么"

---

## §10 · 参考资料

- [assets/restraint.css](assets/restraint.css) — 共享 CSS · token 定义 + 100+ 组件类(1592 行)· 实现层
- [assets/shell.js](assets/shell.js) — 通用 sidebar / topbar 注入
- [_archive/design-system.html](_archive/design-system.html) — 历史交互样板间(浏览器打开看效果)
- [_archive/DESIGN_SPEC_V2.md](_archive/DESIGN_SPEC_V2.md) — 历史详细规范(理论依据 / 迁移轨迹)
- 视觉灵感:Firecrawl Playground · Linear · Stripe Dashboard
- 图纸感来源:印刷套版准星 + 老 Unix 终端

---

**任何条款不清晰、想加新组件、或想改 token,先在群里讨论 → 写进本文件 → 改 restraint.css。**
**永远不要在某个页面 inline `<style>` 里偷偷扩展规范。**
