# v4 视觉一体性规范 —— 8pt 网格 + 4pt 基线

> **canonical 真相源**。此后一切 v4 界面改动（新屏/新组件/调样式）动笔前先读本文件。
> 仪表：`npm run audit:spacing`（`scripts/audit-spacing.mjs`）——默认报告态；
> 纪律是**自己改过的文件不新增偏离**（`--strict` 可作硬门）。
> [PROTOCOL]: 变更时更新此文件，然后检查 styles/v4/CLAUDE.md

## 纲领：一体感，不是数字苛政

目标只有一个：**整个网站看起来是一块材料切出来的**——每个板块共用同一套视觉词汇，
而不是东一块西一块各说各话。数字（4/8 的倍数）只是手段：当所有间距、高度、圆角
都取自同一把梯子，画面自然产生统一的呼吸节奏（vertical rhythm），拼凑感就消失了。

所以规则很简单：**需要一个尺寸时，不要发明数字，从下面的梯子上取一档。**
拿不准取哪档？看同类既有组件用了哪档，跟它一致——一致性 > 精确性。

## 间距梯（padding / margin / gap / 定位偏移 / 组件高度）

只允许 **4 的倍数**，常用档位（优先取 8 的倍数）：

```
4   8   12   16   20   24   32   40   48   56   64   72   80   88
微调 元素内 紧凑  标准  舒适  区块内 区块间 大区块 节内距 —— 节与节 ——
```

- 组件高度（按钮/输入框/工具条/头部）优先 8 的倍数：`32 / 40 / 48 / 56 / 60* / 64`（*60=4×15 允许，头部导航既有值）。
- hover/active 命中区高度同上——可点击目标不小于 32px 高。
- 定位偏移（角标的 top/left 等）同梯。
- **宽度暂不强制**（侧栏 266 等历史值牵连布局公式，待独立批次对齐；新代码的固定宽度请自觉取梯）。

## 4pt 基线（line-height / 段落节奏）

- 显式 line-height 一律写 **px 且为 4 的倍数**：正文 13px 字号 → `20px`；副文 12.5px → `20px`；
  卡片标题 16px → `24px`；节标题 22-26px → `32px`；hero 40-48px → `48px / 56px`。
- 无单位 line-height 只允许 `1`（单行字形复位，盒高由容器管）。
- 段落间距（`margin` 上下）从间距梯取值，正文段间 `8 / 12`，区块间 `16 / 24`。
- 字号沿用既有 0.5 步进字阶（9.5 / 10.5 / 11.5 / 12.5 / 13.5 / 14.5 / 16 / 22 / 26 / 40+），
  **不再发明新字号**；行高落基线后，字号的半像素不破坏节奏。

## 圆角梯（v17.14.0 已全站归一；v18.0.0 按钮改圆角矩形）

```
4（微件/徽章） 8（小控件/输入框/按钮） 12（内嵌卡/缩略图/大按钮） 16（卡片/面板） 20/24（大容器） 999（非交互徽章胶囊） 50%（圆）
```

同一层级用同一档：外层卡片一律 16，卡内嵌套一律 12。
**按钮一律圆角矩形（sm/md=8 · lg=12），禁胶囊(999)**——胶囊只留给非交互徽章/标签。
微件例外：高度 ≤8px 的进度条/微点允许 1-2px 端帽圆角。
（此前散布 3/5/7/9/10/11/14/18 共 15 档随手值，已按 ≤5→4 / 6-9→8 / 10-13→12 / 14-17→16 / 18-22→20 归一。）

## 细线三档（hairline，v17.14.0 已全站归一）

黑色微透明只允许三档，同用途同档：

```
rgba(0,0,0,.07)  弱分隔（区块界线 / 极浅 hover 面）
rgba(0,0,0,.09)  标准边框（卡片 / 输入框描边）
rgba(0,0,0,.14)  强调边（hover 边 / 需要立起来的控件）
```

（此前 .05/.06/.08/.1/.12/.13/.15/.16 散布 12 档，已归并；≥.18 的深色遮罩/滚动条不属细线，不受此限。）

## 质感语言（v18.0.0：微拟物 skeuomorphic——按钮是灵魂）

物理模型只有一个：**光从正上方来**。每个可交互控件都是一枚「真实的键」，五层光影缺一不可：
凸面渐变（顶亮底沉）· 顶部反光（inset 高光线）· 贴地投影（近影锐+远影柔）·
反光光晕（外圈高光环，hover 变亮）· 按压内陷（:active 渐变翻转 + inset 阴影）。

- **canonical 实现**：`styles/v4/controls.css`（`.zzm-btn` 家族 + `.zzm-card` + `.zzm-input` 内凹）；
  组件装配点 `components/v4/Button.jsx`（`Btn` / `btnClass`）。
- **铁律：光影只从 controls.css 的质感类取，禁止在屏里散写 boxShadow/渐变**——
  微拟物的一体感来自全站共用同一个光照模型，各写各的光源方向必然穿帮。
- **按钮＝圆角矩形**（sm/md=8 · lg=12），**禁胶囊**；变体只有五种：纸键(默认)/墨键(--primary)/
  朱键(--accent)/幽灵键(--ghost，hover 才成键)/暗面键(--ondark)。凸的是键，凹的是输入槽。
- **等待与禁用两种语义两种脸**（v18.2.0）：`--busy`（Saving/等待）＝旋转环+保留变体本色+禁交互——
  「正在做」；`:disabled`（非等待）＝灰面灰字——「不能做」。禁用**永不**用 opacity 淡化整键
  （变体白字×半透明×灰面＝白字隐形事故）。任何点击后有等待的按钮一律 `Btn busy` / 加 `.zzm-btn--busy`。
- **可点卡链 `.zzm-cardlink`**（v18.2.0）：课节/历史/收藏等一切可点内容卡的统一容器——
  白卡承托(圆角 16·内距 12·内嵌图 12) + 悬停高亮描边/上浮 3px/柔影，与综合首页课程卡同一手感；
  新卡片不再用裸缩略图+`zzm-lift` 纯位移。
- **backdrop 模糊仍全域禁用**（性能）；阴影/渐变仅经质感类生效，不再"零阴影零渐变"（v18.0.0 废除旧律）。

## 版式节奏（板块之间的「联系感」）

- **容器**：主内容区 `maxWidth 1080 + padding 48`（窄文档流可用 820），全站节与节共用。
- **节标题**：落地页/长页一律用 `SectionHead`（mono 编号 + 标题 + 右侧注记）同一骨架，不另起炉灶。
- **卡片语法**：白卡 + 1px hairline + 圆角 16 + 内距 `16-24` + `.zzm-card` 微拟物浮起光影——
  所有内容卡共用；课程卡以 `components/v4/CourseCard` 为基准形态（Hub = 落地页同一组件）。
- **分隔**：1px hairline 与留白分层为主，抬升感交给 `.zzm-card`/`.zzm-btn` 的统一光影。

## 例外清单（审计器已放行，不要"顺手修"）

- `0`、边框宽 `1 / 1.5 / 2px`（hairline 不是间距）、`999/50%` 圆角哨兵、百分比/`calc()/var()/auto`。
- SVG 内部坐标（viewBox/points/cx/cy）、`transform`、动画关键帧数值——图形语言，不在网格辖区。
- JS 布局公式常量（如 VideoPage 拖宽 cap 里的侧栏宽）——属逻辑不属样式，改须连动测试。

## 落地方式（渐进，不搞一次性大迁移）

1. **新代码**：直接从梯子取值；写完跑 `npm run audit:spacing`，自己的文件不新增偏离。
2. **存量间距**：DC 原值（22/26/34/46 这类 ±2px 偏差）肉眼无感，**碰到哪个文件顺手把该文件对齐**，
   不为改而改——一体感优先级：圆角/细线/节奏（可感知）> 间距 ±2px（不可感知）。
3. **已完成的全量归一**（v17.14.0）：圆角梯、细线三档、落地页节间距（各节顶距一律 60px）。
4. 设计词汇可视化：后台 `#admin` → 设计系统 → 「00 · 间距与圆角梯」（活文档，与本文件同步）。
5. token：`styles/v4/tokens.css` 的 `--zzm-s-*` / `--zzm-r-*` 供 CSS 场景引用；
   JSX 内联样式允许字面量，但值必须在梯上。
