# 设计规范 · 云微面板设计系统

> 本文是面板前端（`panel/web`）的**设计语言与组件规范**，与代码一一对应——令牌就是 `styles.css` 里的 CSS 变量，组件名就是真实的 class。改 UI 前先读这里；新增组件按此规范落地，别另起炉灶。
> 配套：架构层规范见 [架构守则.md](架构守则.md)。

## 一、设计哲学

三条主线，缺一不可：

1. **牛奶布艺（soft neumorphism）** —— 整个界面是**盖在桌面上的一整块柔软白布**，每个组件是被布从下方顶起的物体。这个比喻决定一切视觉：
   - 高光在物体**顶面**（radial 渐变，中心偏上）——布料最贴、最受光处；
   - 阴影是布料**折痕**（小半径、紧贴边缘、冷灰蓝），**不是悬浮投影**；
   - 组件亮度 **≥** 背景（越靠近光源越亮）；
   - **层级靠明度对比，不靠边框/分割线**——全站几乎没有 `border`。
2. **微信绿主色** —— `#07C160`。主按钮、选中态、强调文字、焦点环都用它。用户对这个绿有肌肉记忆，别换色相。
3. **iOS 式饱满圆角 + 克制** —— 圆角只有大/中/小三档 + 胶囊；文案精炼、层级不超过 4 级字号。

一句话检验：**任何新组件放上去，要像「同一块布下顶起的又一个物体」，而不是「贴上去的一张卡」。**

## 二、设计令牌（`:root`，深色见 `[data-theme='dark']`）

改样式**只用令牌**，不写死颜色/阴影。

### 色彩

| 令牌 | 浅色 | 深色 | 用途 |
|---|---|---|---|
| `--base` | `#ebedf1` | `#14161c` | 整块布底色（页面背景） |
| `--surface` | `#ffffff` | `#23262f` | 浮起表面（卡片/按钮 fill）——**必须 ≥ base 亮度** |
| `--trough` | `#e0e3ea` | `#0e0f14` | 凹槽（输入框/进度槽/折叠菜单条）——比 base 更暗 |
| `--text` | `#1a1d24` | `#e7eaef` | 主文字 |
| `--muted` | `#8a9099` | `#969ca6` | 次文字（**最低到此级，不用三级灰**） |
| `--wx-green` / `--wx-green-dark` | `#07c160` / `#06ad56` | 同 | 主色 / 主色按下态 |
| `--danger` | `#fa5151` | 同 | 危险/离线/删除 |
| `--shadow` | `51 66 102`(冷灰蓝) | `0 0 0`(近纯黑) | 阴影色 RGB，配 `rgba(var(--shadow)/α)` |
| `--green-rgb` / `--danger-rgb` | `7 193 96` / `250 81 81` | 同 | 半透强调用 |

深色不是简单反色：`base` 用**亮蓝黑**、`surface` 再高一档、阴影转近纯黑、顶面高光压到极淡（0.06）。

### 圆角

| 令牌 | 值 | 用途 |
|---|---|---|
| `--r-card` | `28px` | 卡片、进入入口、模态 |
| `--r-blob` | `22px` | 中等浮起块 |
| `--r-small` | `16px` | 按钮、输入框 |
| （胶囊） | `999px` | 徽标 `.tag`、分段 Tab、chip |

**禁止**直角或 <12px 小圆角——破坏「柔软布料」质感。

### 阴影与高光（布料的灵魂）

| 令牌 | 含义 |
|---|---|
| `--crease` | 浮起折痕（两层：`0 1px 3px` + `0 2px 8px`，紧贴边缘）。所有浮起组件的基础 |
| `--crease-press` | 按下态折痕（更紧更浅）——按下即收紧，模拟按进布里 |
| `--crease-accent` | 绿色折痕（主按钮/Logo），阴影色用 `--green-rgb` |
| `--sheen` | 顶面高光 radial（`ellipse at 50% 28%`，白→透明）。**所有浮起组件用 `::before` 叠这层**，否则变平贴色块 |

**硬约束**：阴影 `x` 恒为 0（俯视对称光）；`y` ≤ 6；第一层 radius ≤ 4、第二层 ≤ 14。**radius >15 或 y >5 就成了悬浮投影，违反比喻。**

### 动效曲线

- **主 spring**：`cubic-bezier(0.2, 0.8, 0.2, 1)`，时长 0.16–0.2s（按钮、输入聚焦、Tab）。全站已用 12+ 处，别引入别的曲线。
- Toast 入场：`cubic-bezier(0.2, 0.9, 0.2, 1)`，0.32s。

## 三、布局与信息架构

- **页面容器** `.content`：移动端 `max-width:560px`；≥880px 宽屏 `max-width:940px`、加大内边距。始终居中。
- **区块** `.section-row`（标题行，`space-between`，左标题右操作）+ `.section-title`（15px/700）。区块间距 `margin-top:22px`。
- **网格** `.inst-grid`：`repeat(auto-fill, minmax(248px, 1fr))`，gap 14px，`align-items:start`（各卡按内容高度，避免展开菜单时同行被拉等高）。
- **三 Tab 信息架构**（管理页）：内容多时**按用户心智分组成 Tab**，而非一条长滚动。分组原则：
  - 日常高频（实例）/ 偶尔配置（用户）/ 出事才看（系统：残留资源+诊断+关于）；
  - Tab 上用 `.seg-dot` 红点提示「该 Tab 有待处理事项」，避免藏进 Tab 的事被漏看；
  - 记住上次停留的 Tab（`sessionStorage`）。

## 四、组件规范

所有浮起组件 = `surface` fill + `--crease` + `::before` 叠 `--sheen`。这是共用原子（`.mf-raised` 及 `.card/.enter-card/.list/.wx-state` 共享）。

### 浮起卡片 `.card` / `.inst-card`
圆角 `--r-card`，padding 18–24px，`overflow:hidden`（`::before` 高光不外溢）。**展开悬浮菜单时**才 `overflow:visible` + 抬 `z-index`。

### 按钮（三级 + 文本）
| 类 | 形态 | 用途 |
|---|---|---|
| `.btn` | surface 浮起 blob，按下 `scale(0.97)` + 折痕收紧 | 次要动作 |
| `.btn.btn-primary` | 绿底、白字、`--crease-accent`、更克制的高光（别让白 sheen 冲淡绿） | 主动作，一屏一个 |
| `.btn.btn-danger` | 红底，折痕用 danger 色 | 删除等破坏性动作 |
| `.btn-text` | 无浮起、绿字、按下淡绿底 | 行内轻操作（+新建、改名） |

统一 `height:48px`、`--r-small`。禁用 `opacity:0.6`、不改阴影。

### 输入框 `.input`（凹陷，不是浮起）
`trough` fill + **顶部内阴影**（`inset`），聚焦时叠 `0 0 0 3px` 绿色半透环。凹陷元素**不画外折痕**——它是被按进布里的槽，与浮起组件形成对比。

### 徽标体系 `.tag`（胶囊，`white-space:nowrap`）
| 变体 | 色 | 语义 |
|---|---|---|
| `.tag`（默认） | 绿 | 中性/正向标识 |
| `.tag-on` | 绿 | 在线/正常 |
| `.tag-off` | 红 | 离线/已禁用 |
| `.tag-busy` | —— | 处理中 |
| `.tag-warn` | 琥珀 | 可升级/需注意 |
| `.tag-muted` | 灰 | 纯元数据（镜像版本号），`tabular-nums` |

**布局铁律**：一个组件的标题行**最多放 名字 + 1 个状态徽标**。其余徽标（可升级、版本…）下沉到独立的 `.inst-meta` 元数据行（可换行）。塞多了就会名字被截断、徽标竖排——这是踩过的坑（见卡片布局修复）。

### 分段 Tab `.seg-tabs` / `.seg-tab`（凹槽 + 浮起选中胶囊）
外层 `trough` 凹槽胶囊（无外折痕），选中项是**顶起的 surface 白胶囊**（`--crease` + 绿字）。这套「凹槽 + 浮起 bump」和输入框凹陷同构，是本设计系统区分「选中/未选中」的标准范式。
> **理想增强**：选中指示器用 matched-geometry「滑动」而非淡入淡出（当前是 background 渐变过渡，可接受）。未来若做，用一个绝对定位的 bump + `transform` 过渡在选项间滑动。

### 折叠菜单 `.inst-menu-toggle` + `.inst-menu`
操作多时收进「管理」折叠菜单，按 运维/设置/危险 **分组**，危险项 `.inst-menu-danger` 单列。悬浮层不占文档流，点外部关闭。

### 空状态 `.empty-state`
中心 120px 的 surface 圆 blob（`.empty-blob` + 折痕 + 高光）+ 图标（ultraLight）+ 标题 + 副标题 + 一个主按钮。别用一行冷冰冰的「暂无数据」。

### Toast `.toast` / 进度条 `.wx-progress`
Toast 右上滑入（`.toast-ok`/`.toast-error`）。进度条：确定进度用 `width%`，不确定用 `.indeterminate` 循环。二者都是**必要状态反馈**，在 reduced-motion 下仍保留动画。

### 模态 `.modal-mask` + `.modal`
遮罩点击关闭（内容 `stopPropagation`），`.modal-actions` 右对齐（取消在左、主/危险动作在右）。

## 五、动效规范

- 状态切换用主 spring 曲线；**Tab/分段切换**倾向 matched-geometry 滑动而非淡入淡出。
- 压按反馈：`scale(0.97)` + 折痕由 `--crease` → `--crease-press`（0.18s）。
- **`prefers-reduced-motion: reduce`**：去掉装饰性过渡/位移，但**保留 spinner 与不确定进度条的循环**（否则像卡死）。已在 `styles.css` 末尾统一处理，新增装饰动画自动被覆盖。

## 六、无障碍（基线，不是可选项）

- **键盘焦点环**：全局 `:focus-visible` → 2px 绿色 outline + 2px offset。**只在键盘导航时出现**，鼠标点击不触发。无边框的拟物 UI 尤其需要它，否则键盘用户完全看不到焦点。输入框用自带内环、不叠加。
- **对比度**：文字最低到 `--muted`，**不用三级灰**（亮白 surface 上会糊）。
- **触摸目标**：交互元素 ≥ 44×44（按钮 48 高达标；小图标按钮注意留足点击区）。
- **减弱动效**：见上，尊重系统设置。

## 七、内容与文案

- 全中文；语气**像同事说人话**，不像系统报错。错误给「怎么办」，不只给「出错了」。
- 数字/版本号用 `tabular-nums`（对齐好看）。
- 破坏性操作（删除/清数据）文案明确后果 + 二次确认，危险按钮红色。

## 八、常见错误（反例 → 正例）

| ❌ | ✅ |
|---|---|
| 大半径（>15）+ 大 y 的 drop shadow | 小半径紧贴边缘的 `--crease` 折痕 |
| 组件顶部 linear 渐变高光 | 中心偏上的 radial `--sheen`（`::before`） |
| 用 border/分割线区分组件 | 靠明度（surface > base > trough）+ 折痕 |
| 组件 fill = base 或更暗 | 组件必须 `--surface`，**亮于 base** |
| 标题行塞名字+3 个徽标 | 标题行只留名字+1 状态徽标，其余进 `.inst-meta` |
| 写死 `#07c160` / `box-shadow: ...黑` | 用 `--wx-green` / `--crease` 令牌 |
| 直角或 8px 小圆角 | ≥16px 或胶囊 |
| 亮白 surface 上用三级灰文字 | 最低 `--muted` |
| 无键盘焦点样式 | 全局 `:focus-visible` 绿环 |

## 九、落地清单（改/加 UI 前逐条过）

- [ ] 只用令牌，没写死颜色/阴影/圆角；
- [ ] 浮起组件有 `surface` fill + `--crease` + `::before` 的 `--sheen`；
- [ ] 阴影 `x=0`、`y≤6`、无大散射；圆角 ≥16 或胶囊；
- [ ] 组件亮度 ≥ base；无 border/分割线；无三级灰文字；
- [ ] 标题行 ≤ 名字 + 1 徽标，其余进元数据行；
- [ ] 深浅色都过一遍（`data-theme` 切换）；
- [ ] 键盘 Tab 能看到焦点环；`prefers-reduced-motion` 下无眩晕动画；
- [ ] 交互目标 ≥44px；破坏性操作有确认 + 红色。
