iye bbe29622c2
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 4m39s
Polish static UI flows
2026-05-28 12:29:12 +08:00

1152 lines
51 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 档 · 核心工具尺)
> **规则:** 024% 用 `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.651.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) | `3648 px`(子)/ `64104 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 | 2836 px | 表单内已选行 / 侧栏列表 |
| **选择器卡** | `.pl-card` / `.opt-card` / `.model-card` | 1:1 或 3:4 | 100160 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 · 数量 14 个(超过 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>` 里偷偷扩展规范。**