AirShelf/电商AI平台/design-system.html
iye 553014cc79
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 7s
更新电商AI平台原型交互
2026-05-25 19:12:56 +08:00

3117 lines
183 KiB
HTML
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.

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>流·Studio 设计系统 · V2.1 · Interactive</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=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<!-- 引入项目共享 CSS · token + 100+ 组件类(1592 行) -->
<link rel="stylesheet" href="assets/restraint.css">
<style>
/* ============================================================
design-system.html · 演示辅助样式
============================================================
规则:
- token / 组件主类全部来自 restraint.css(看到的 = 生产用的)
- 本文件只补充"样板间专用"的展示工具类
- 任何在这里 inline 的样式都不应进入业务页面
============================================================ */
/* === 顶层布局 === */
.ds-layout { display: grid; grid-template-columns: 248px 1fr; min-height: 100vh; }
.ds-sidebar {
position: sticky; top: 0; height: 100vh;
padding: 40px 28px;
border-right: 1px solid var(--border-faint);
background: var(--surface);
overflow-y: auto;
}
.ds-sidebar h1 {
font-size: 17px; font-weight: 600; letter-spacing: -.01em;
margin: 0 0 6px; line-height: 1.4;
color: var(--accent-black);
}
.ds-sidebar .mono-sub {
font-family: var(--font-mono); font-size: 10.5px;
color: var(--black-alpha-48); letter-spacing: .04em;
margin-bottom: 32px;
}
.ds-nav { list-style: none; padding: 0; margin: 0; }
.ds-nav li { margin: 0; }
.ds-nav a {
display: block; padding: 8px 12px;
font-size: 13px; color: var(--black-alpha-64);
text-decoration: none; border-radius: var(--r-md);
transition: background var(--t-base), color var(--t-base);
}
.ds-nav a:hover { background: var(--black-alpha-4); color: var(--accent-black); }
.ds-nav a.active { background: var(--heat-12); color: var(--heat); }
.ds-nav .nav-group {
font-family: var(--font-mono); font-size: 10px;
letter-spacing: .06em; color: var(--black-alpha-32);
margin: 24px 0 8px; padding: 0 12px; text-transform: uppercase;
}
.ds-main { padding: 72px 80px 120px; max-width: 1280px; }
.ds-main > section { margin-bottom: 104px; scroll-margin-top: 32px; }
.ds-main > section:last-child { margin-bottom: 0; }
.section-head { margin-bottom: 44px; padding-bottom: 28px; border-bottom: 1px solid var(--border-faint); }
.section-head .mono-tag {
display: inline-block; font-family: var(--font-mono); font-size: 11px;
color: var(--black-alpha-48); letter-spacing: .06em; margin-bottom: 14px;
}
.section-head h2 {
font-size: 28px; font-weight: 500; letter-spacing: -.02em;
margin: 0 0 12px; line-height: 1.25;
color: var(--accent-black);
}
.section-head p {
font-size: 14px; color: var(--black-alpha-64);
margin: 0; max-width: 720px; line-height: 1.75;
}
.subsection { margin-bottom: 64px; }
.subsection h3 {
font-size: 16px; font-weight: 500; letter-spacing: -.01em;
margin: 0 0 22px; display: flex; align-items: center; gap: 12px;
line-height: 1.4; color: var(--accent-black);
}
.subsection h3 .mono-num {
font-family: var(--font-mono); font-size: 11px;
color: var(--black-alpha-32); font-weight: 400; letter-spacing: .04em;
}
.subsection p.lead {
font-size: 13px; color: var(--black-alpha-56);
margin: 0 0 22px; line-height: 1.8; max-width: 720px;
}
/* === Hero === */
.hero {
position: relative;
border: 1px solid var(--border-faint);
background: var(--surface);
border-radius: var(--r-md);
padding: 52px 56px; margin-bottom: 72px; overflow: hidden;
}
.hero .badge {
display: inline-flex; align-items: center; gap: 6px;
font-family: var(--font-mono); font-size: 11px; color: var(--heat);
background: var(--heat-12); border: 1px solid var(--heat-20);
border-radius: var(--r-pill); padding: 4px 11px; letter-spacing: .04em;
margin-bottom: 20px;
}
.hero h1 {
font-size: 36px; font-weight: 500; letter-spacing: -.024em;
margin: 0 0 14px; line-height: 1.2; color: var(--accent-black);
}
.hero p {
font-size: 15px; color: var(--black-alpha-64);
margin: 0; line-height: 1.75; max-width: 680px;
}
.hero .meta {
display: flex; gap: 16px; margin-top: 24px;
font-family: var(--font-mono); font-size: 11px;
color: var(--black-alpha-48); letter-spacing: .04em;
}
/* === 共用工具 === */
.mono { font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .04em; color: var(--black-alpha-56); }
code.tk { font-family: var(--font-mono); font-size: 11.5px; padding: 1px 6px; border-radius: 4px; background: var(--background-lighter); color: var(--accent-black); border: 1px solid var(--border-faint); }
code.tk.heat { background: var(--heat-12); color: var(--heat); border-color: var(--heat-20); }
/* === Swatch grid (色块) === */
.swatch-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 14px; }
.swatch {
background: var(--surface); border-radius: var(--r-md); overflow: hidden;
cursor: pointer; transition: transform var(--t-fast);
}
.swatch:hover { transform: translateY(-1px); }
.swatch .chip { height: 76px; position: relative; border-bottom: 1px solid var(--border-faint); }
.swatch .chip.with-grid {
background-image:
linear-gradient(45deg, #dcdcdc 25%, transparent 25%),
linear-gradient(-45deg, #dcdcdc 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #dcdcdc 75%),
linear-gradient(-45deg, transparent 75%, #dcdcdc 75%);
background-color: #f5f5f5;
background-size: 12px 12px;
background-position: 0 0, 0 6px, 6px -6px, -6px 0;
}
.swatch .meta-row {
padding: 14px;
border: 1px solid var(--border-faint);
border-top: 0;
border-radius: 0 0 var(--r-md) var(--r-md);
}
.swatch .name { font-family: var(--font-mono); font-size: 11.5px; color: var(--accent-black); font-weight: 500; letter-spacing: .02em; line-height: 1.5; }
.swatch .val { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); margin-top: 4px; letter-spacing: .04em; line-height: 1.5; }
.swatch .copy { font-family: var(--font-mono); font-size: 10px; color: var(--heat); display: none; margin-top: 3px; }
.swatch.copied .copy { display: block; }
/* === 字体 / 字号 / 字重展示 === */
.type-row {
display: grid; grid-template-columns: 220px 1fr; gap: 28px;
align-items: baseline; padding: 24px 0;
border-bottom: 1px solid var(--border-faint);
}
.type-row:last-child { border: 0; }
.type-row .meta-col {
font-family: var(--font-mono); font-size: 11px;
color: var(--black-alpha-48); letter-spacing: .04em; line-height: 1.65;
}
.type-row .meta-col strong {
display: block; color: var(--accent-black);
font-family: var(--font-sans); font-size: 13px; font-weight: 500;
margin-bottom: 6px; letter-spacing: 0;
}
.type-row .sample { color: var(--accent-black); }
/* === 圆角阶梯 === */
.radius-row { display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-end; }
.radius-box { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.radius-box .box {
background: var(--surface);
border: 1px solid var(--border-faint);
width: 88px; height: 88px;
display: grid; place-items: center;
}
.radius-box .lbl { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); letter-spacing: .04em; }
.radius-box .px { font-family: var(--font-mono); font-size: 13px; color: var(--accent-black); font-weight: 500; }
/* === 间距示例 === */
.spacing-row { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 14px; }
.spacing-box {
display: flex; flex-direction: column; align-items: center; gap: 8px;
}
.spacing-bar {
background: var(--heat-12);
border-radius: 2px;
}
.spacing-box .lbl {
font-family: var(--font-mono); font-size: 10.5px;
color: var(--black-alpha-48); letter-spacing: .04em;
}
/* === 阴影 === */
.shadow-row { display: flex; gap: 24px; flex-wrap: wrap; margin-top: 14px; }
.shadow-box {
width: 200px; height: 80px;
background: var(--surface);
border-radius: var(--r-md);
display: grid; place-items: center;
font-family: var(--font-mono); font-size: 11px;
color: var(--black-alpha-56); letter-spacing: .04em;
}
.shadow-cta-demo {
background: var(--heat); color: #fff;
box-shadow:
inset 0 -4px 8px rgba(250, 93, 25, .20),
0 1px 1px rgba(250, 93, 25, .12),
0 2px 4px rgba(250, 93, 25, .10),
0 .5px .5px rgba(250, 93, 25, .16);
}
.shadow-floating-demo {
box-shadow: 0 4px 20px rgba(21, 20, 15, .06);
}
/* === Inside-border 演示 === */
.ib-demo {
display: flex; gap: 18px; flex-wrap: wrap;
}
.ib-box {
padding: 22px 26px; background: var(--surface);
border-radius: var(--r-md); position: relative;
font-family: var(--font-mono); font-size: 11px;
color: var(--black-alpha-56); letter-spacing: .04em;
width: 200px; text-align: center;
}
.ib-box::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;
}
.ib-box:hover::before { opacity: 0; }
.ib-box:hover { background: var(--black-alpha-4); }
/* === Icons === */
.icon-row { display: flex; gap: 24px; align-items: flex-end; flex-wrap: wrap; }
.icon-cell { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.icon-cell .ic {
display: grid; place-items: center;
color: var(--black-alpha-64);
background: var(--surface);
border: 1px solid var(--border-faint);
border-radius: var(--r-md);
}
.icon-cell svg { display: block; }
.icon-cell .lbl { font-family: var(--font-mono); font-size: 10px; color: var(--black-alpha-48); letter-spacing: .04em; }
.icon-color-row { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; }
.icon-color-row .demo {
display: inline-flex; align-items: center; gap: 8px;
padding: 8px 14px; border-radius: var(--r-md);
border: 1px solid var(--border-faint);
background: var(--surface); font-size: 12.5px;
}
.icon-color-row .demo.primary { background: var(--heat); color: #fff; border-color: var(--heat); }
.icon-color-row .demo.disabled { color: var(--black-alpha-12); }
/* === 按钮演示状态 (覆盖 hover/active 视觉) === */
.btn-row { display: flex; gap: 14px; flex-wrap: wrap; align-items: center; margin-bottom: 20px; }
.btn-row .state-label {
font-family: var(--font-mono); font-size: 11px; color: var(--black-alpha-48);
letter-spacing: .04em; width: 96px; flex-shrink: 0;
}
.btn.demo-hover { background: var(--black-alpha-4); border-color: var(--black-alpha-24); }
.btn.demo-active { background: var(--black-alpha-7); transform: scale(.99); }
.btn-primary.demo-hover {
box-shadow:
inset 0 -4px 8px rgba(250, 93, 25, .20),
0 1px 1px rgba(250, 93, 25, .16),
0 4px 8px rgba(250, 93, 25, .20),
0 .5px .5px rgba(250, 93, 25, .16);
}
.btn-primary.demo-active {
transform: scale(.995);
box-shadow: inset 0 -4px 8px rgba(250, 93, 25, .28), 0 1px 2px rgba(250, 93, 25, .16);
}
.btn-ghost.demo-hover { background: var(--black-alpha-4); border-color: transparent; color: var(--accent-black); }
.btn-ghost.demo-active { background: var(--black-alpha-7); }
.btn.demo-focus { box-shadow: 0 0 0 2px var(--background-base), 0 0 0 4px var(--heat-40); }
/* === Pills 三级演示(原 restraint.css 只一档 · 这里展示分级) === */
.pill-l1 { height: 28px; padding: 0 12px; font-size: 13px; gap: 8px; }
.pill-l1 .dot { width: 8px; height: 8px; }
.pill-l2 { height: 22px; padding: 0 10px; font-size: 11.5px; gap: 6px; }
.pill-l2 .dot { width: 6px; height: 6px; }
.pill-l3 { height: 18px; padding: 0 8px; font-size: 10.5px; gap: 5px; }
.pill-l3 .dot { width: 5px; height: 5px; }
.pill-row { display: flex; gap: 14px; flex-wrap: wrap; align-items: center; }
/* === Inputs 包装 (focus / error 状态演示) === */
.field-row {
display: grid; grid-template-columns: 120px 1fr; gap: 20px;
align-items: center; margin-bottom: 18px;
}
.field-row .lbl { font-family: var(--font-mono); font-size: 11px; color: var(--black-alpha-48); letter-spacing: .04em; }
.input-wrap { position: relative; display: inline-block; max-width: 380px; width: 100%; }
.input-wrap .input { width: 100%; max-width: none; }
.input-wrap.is-error .input { background: var(--crimson-bg); border-color: var(--accent-crimson); box-shadow: inset 0 0 0 1px var(--crimson-bd); }
/* search wrap 复用 toolbar 的搜索风格 */
.search-demo { position: relative; max-width: 440px; }
.search-demo svg.ic-left {
position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
color: var(--black-alpha-56);
pointer-events: none; z-index: 2; display: flex;
}
.search-demo .input { padding-left: 42px; padding-right: 64px; }
.search-demo .k {
position: absolute; right: 14px; top: 50%; transform: translateY(-50%);
font-family: var(--font-inter, 'Inter', sans-serif); font-weight: 700;
font-size: 11.5px; color: var(--black-alpha-56);
letter-spacing: .02em; pointer-events: none; z-index: 2; line-height: 1;
}
/* === Form controls (Checkbox/Radio/Switch) === */
.ck-row { display: flex; gap: 24px; align-items: center; flex-wrap: wrap; }
.ck, .rd, .sw { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; user-select: none; font-size: 14px; color: var(--accent-black); }
.ck input, .rd input, .sw input { display: none; }
.ck .ck-box {
width: 16px; height: 16px; border-radius: var(--r-sm);
background: var(--surface); position: relative; flex-shrink: 0;
transition: background var(--t-base), box-shadow var(--t-base);
box-shadow: inset 0 0 0 1px var(--black-alpha-24);
}
.ck:hover .ck-box { box-shadow: inset 0 0 0 1px var(--black-alpha-48); }
.ck input:checked + .ck-box {
background: var(--heat); box-shadow: inset 0 0 0 1px var(--heat);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
background-repeat: no-repeat; background-position: center; background-size: 12px 12px;
}
.ck.is-indeterminate .ck-box {
background: var(--heat); box-shadow: inset 0 0 0 1px var(--heat);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3C/svg%3E");
background-repeat: no-repeat; background-position: center; background-size: 12px 12px;
}
.ck.is-disabled { opacity: .6; cursor: not-allowed; }
.ck.is-disabled .ck-box { background: var(--background-lighter); box-shadow: inset 0 0 0 1px var(--black-alpha-12); }
.rd .rd-box {
width: 16px; height: 16px; border-radius: 50%;
background: var(--surface); position: relative; flex-shrink: 0;
box-shadow: inset 0 0 0 1px var(--black-alpha-24);
transition: box-shadow var(--t-base);
}
.rd:hover .rd-box { box-shadow: inset 0 0 0 1px var(--black-alpha-48); }
.rd input:checked + .rd-box { box-shadow: inset 0 0 0 1px var(--heat); }
.rd input:checked + .rd-box::after { content: ''; position: absolute; inset: 4px; border-radius: 50%; background: var(--heat); }
.sw .sw-box {
width: 28px; height: 16px; border-radius: var(--r-pill);
background: var(--black-alpha-12); position: relative; flex-shrink: 0;
transition: background var(--t-base);
}
.sw .sw-box::after {
content: ''; position: absolute; left: 2px; top: 2px;
width: 12px; height: 12px; border-radius: 50%; background: #fff;
transition: left var(--t-base);
box-shadow: 0 1px 2px rgba(21, 20, 15, .12);
}
.sw input:checked + .sw-box { background: var(--heat); }
.sw input:checked + .sw-box::after { left: 14px; }
.sw.is-disabled { opacity: .5; cursor: not-allowed; }
/* === Tabs (sub) === */
.ds-tabs { border-bottom: 1px solid var(--border-faint); display: flex; gap: 0; margin-bottom: 16px; }
.ds-tab {
position: relative; background: none; border: 0; cursor: pointer;
height: 36px; padding: 0 14px;
font-family: inherit; font-size: 13px; font-weight: 500;
color: var(--black-alpha-56);
transition: color var(--t-base), background var(--t-base);
border-radius: var(--r-md) var(--r-md) 0 0;
}
.ds-tab:hover { color: var(--accent-black); background: var(--black-alpha-4); }
.ds-tab.is-active { color: var(--accent-black); }
.ds-tab.is-active::after {
content: ''; position: absolute; left: 0; right: 0; bottom: -1px;
height: 2px; background: var(--heat);
}
.ds-subtabs { display: flex; gap: 0; margin-bottom: 24px; }
.ds-subtab {
display: inline-flex; align-items: center; gap: 6px;
background: none; border: 0; cursor: pointer;
height: 28px; padding: 0 10px;
font-family: inherit; font-size: 12px; font-weight: 500;
color: var(--black-alpha-56);
transition: color var(--t-base); border-radius: var(--r-md);
}
.ds-subtab svg { opacity: .6; transition: opacity var(--t-base); }
.ds-subtab:hover { color: var(--accent-black); }
.ds-subtab.is-active { color: var(--accent-black); }
.ds-subtab.is-active svg { opacity: 1; color: var(--heat); }
.ds-subtab-divider { width: 1px; height: 12px; background: var(--black-alpha-7); margin: 0 4px; align-self: center; }
/* === KPI stats demo === */
.demo-stats {
background: var(--surface); border: 1px solid var(--border-faint);
border-radius: var(--r-md);
display: grid; grid-template-columns: repeat(4, 1fr);
position: relative;
}
.demo-stats .cell { padding: 28px 30px; border-right: 1px solid var(--border-faint); }
.demo-stats .cell:last-child { border-right: 0; }
.demo-stats .lbl-row { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
.demo-stats .lbl { font-family: var(--font-mono); font-size: 11px; color: var(--black-alpha-48); letter-spacing: .06em; text-transform: uppercase; }
.demo-stats .num { font-size: 32px; font-weight: 500; letter-spacing: -.02em; font-variant-numeric: tabular-nums; line-height: 1.1; color: var(--accent-black); }
.demo-stats .num small { font-size: 15px; color: var(--black-alpha-48); font-weight: 400; }
.demo-stats .delta { font-family: var(--font-mono); font-size: 11.5px; color: var(--black-alpha-48); margin-top: 10px; }
.demo-stats .delta .up { color: var(--accent-forest); }
/* === List row demo (复用 restraint.css 的 .list-row 但 inline 一些 demo) === */
.list-card-demo {
background: var(--surface); border: 1px solid var(--border-faint);
border-radius: var(--r-md); overflow: hidden;
}
.list-row-demo {
display: grid; grid-template-columns: 56px 1fr auto auto auto; gap: 22px;
align-items: center; padding: 20px 24px;
border-bottom: 1px solid var(--border-faint);
transition: background var(--t-base);
}
.list-row-demo:last-child { border-bottom: 0; }
.list-row-demo:hover { background: var(--black-alpha-4); }
.list-row-demo .thumb {
width: 56px; height: 72px; background: var(--background-lighter);
border: 1px solid var(--border-faint); border-radius: var(--r-md);
display: grid; place-items: center;
font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); letter-spacing: .04em;
}
.list-row-demo .meta .ti { font-size: 14px; font-weight: 500; color: var(--accent-black); margin-bottom: 6px; line-height: 1.4; }
.list-row-demo .meta .sub { font-family: var(--font-mono); font-size: 11.5px; color: var(--black-alpha-48); letter-spacing: .02em; line-height: 1.5; }
/* === Tip === */
.tip-demo {
background: var(--surface);
border: 1px dashed var(--border-loud);
border-radius: var(--r-md);
padding: 20px 24px;
max-width: 560px;
}
.tip-demo .head { font-size: 14px; font-weight: 500; margin-bottom: 10px; color: var(--accent-black); line-height: 1.4; }
.tip-demo .body { font-size: 13px; color: var(--black-alpha-64); line-height: 1.8; }
.tip-demo .mono-code {
display: inline-block; padding: 2px 8px;
background: var(--heat-12); color: var(--heat);
font-family: var(--font-mono); font-size: 11.5px;
border-radius: var(--r-sm); letter-spacing: .04em;
}
/* === Container demo (装订线) === */
.container-demo {
position: relative; margin: 36px auto 24px;
max-width: 720px; padding: 48px 56px;
background: var(--background-base);
border-left: 1px solid var(--border-faint);
border-right: 1px solid var(--border-faint);
}
.container-demo .corner { position: absolute; width: 22px; height: 21px; color: var(--border-muted); }
.container-demo .corner.tl { top: -10.5px; left: -11px; }
.container-demo .corner.tr { top: -10.5px; right: -11px; transform: scaleX(-1); }
.container-demo .corner.bl { bottom: -10.5px; left: -11px; transform: scaleY(-1); }
.container-demo .corner.br { bottom: -10.5px; right: -11px; transform: scale(-1, -1); }
.container-demo .inner {
background: var(--surface); border: 1px solid var(--border-faint);
border-radius: var(--r-md); padding: 24px;
font-size: 13px; color: var(--black-alpha-72); text-align: center;
}
/* === Mono decor === */
.mono-sample-row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-bottom: 10px; }
.mono-tag-sample {
font-family: var(--font-mono); font-size: 11px;
color: var(--black-alpha-48); background: var(--background-lighter);
border: 1px solid var(--border-faint);
border-radius: var(--r-sm); padding: 3px 8px; letter-spacing: .04em;
}
.mono-tag-sample.heat { color: var(--heat); background: var(--heat-12); border-color: var(--heat-20); }
/* === Page layouts (§6 · ASCII art) === */
.layout-card {
background: var(--surface); border: 1px solid var(--border-faint);
border-radius: var(--r-md); padding: 24px 28px;
margin-bottom: 18px;
}
.layout-card .h {
display: flex; align-items: center; gap: 10px; margin-bottom: 12px;
}
.layout-card .h .tag {
font-family: var(--font-mono); font-size: 10.5px;
color: var(--heat); background: var(--heat-12);
border: 1px solid var(--heat-20);
border-radius: var(--r-sm); padding: 2px 8px; letter-spacing: .04em;
font-weight: 500;
}
.layout-card .h .ti { font-size: 14px; font-weight: 500; color: var(--accent-black); }
.layout-card .desc { font-size: 13px; color: var(--black-alpha-64); line-height: 1.7; margin-bottom: 14px; }
.layout-card pre.ascii {
background: var(--background-lighter);
border: 1px solid var(--border-faint);
border-radius: var(--r-sm);
padding: 14px 18px;
font-family: var(--font-mono); font-size: 11.5px;
color: var(--black-alpha-72); line-height: 1.55;
letter-spacing: .02em; overflow-x: auto; white-space: pre;
margin: 0 0 12px;
}
.layout-card .pages {
font-family: var(--font-mono); font-size: 11px;
color: var(--black-alpha-48); letter-spacing: .04em;
}
.layout-card .pages strong { color: var(--accent-black); font-weight: 500; font-family: var(--font-sans); }
/* === Do/Don't grid === */
.dodont-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.dodont { padding: 16px 18px; border-radius: var(--r-md); border: 1px solid; }
.dodont .head {
font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .04em;
margin-bottom: 10px; display: inline-block; padding: 1px 8px;
border-radius: var(--r-sm); color: #fff;
}
.dodont.do { border-color: var(--forest-bd); background: var(--forest-bg); }
.dodont.do .head { background: var(--accent-forest); }
.dodont.dont { border-color: var(--crimson-bd); background: var(--crimson-bg); }
.dodont.dont .head { background: var(--accent-crimson); }
.dodont .body { font-size: 12.5px; line-height: 1.7; color: var(--black-alpha-72); }
.dont-list-item {
display: flex; align-items: flex-start; gap: 10px;
font-size: 12.5px; line-height: 1.7; color: var(--black-alpha-72);
padding: 8px 0; border-bottom: 1px solid var(--border-faint);
}
.dont-list-item:last-child { border-bottom: 0; }
.dont-list-item .x { color: var(--accent-crimson); font-family: var(--font-mono); flex-shrink: 0; margin-top: 2px; }
/* === Audit table (§7 待统一清单) === */
.audit-table {
width: 100%; border-collapse: collapse;
background: var(--surface);
border: 1px solid var(--border-faint);
border-radius: var(--r-md); overflow: hidden;
margin-bottom: 22px;
}
.audit-table th, .audit-table td {
padding: 12px 16px; text-align: left;
font-size: 12.5px; color: var(--accent-black);
border-bottom: 1px solid var(--border-faint);
vertical-align: top;
}
.audit-table th {
font-family: var(--font-mono); font-size: 11px;
font-weight: 500; color: var(--black-alpha-56);
letter-spacing: .04em; text-transform: uppercase;
background: var(--black-alpha-3);
}
.audit-table tbody tr:last-child td { border-bottom: 0; }
.audit-table td:first-child { font-family: var(--font-mono); font-size: 12px; color: var(--heat); width: 32px; }
.audit-table td.problem { color: var(--accent-crimson); font-weight: 500; }
.audit-table td.now { font-family: var(--font-mono); font-size: 11.5px; color: var(--black-alpha-64); }
.audit-table td.should { font-weight: 500; color: var(--accent-forest); }
.audit-section-label {
display: inline-block;
font-family: var(--font-mono); font-size: 11px;
padding: 3px 10px; border-radius: var(--r-sm);
letter-spacing: .04em; margin-bottom: 10px;
}
.audit-section-label.hi { background: var(--crimson-bg); color: var(--accent-crimson); border: 1px solid var(--crimson-bd); }
.audit-section-label.mid { background: var(--honey-bg); color: var(--accent-honey); border: 1px solid var(--honey-bd); }
.audit-section-label.lo { background: var(--background-lighter); color: var(--black-alpha-56); border: 1px solid var(--border-faint); }
/* === Checklist === */
.cl-card {
background: var(--surface); border: 1px solid var(--border-faint);
border-radius: var(--r-md); padding: 22px 26px;
margin-bottom: 16px;
}
.cl-card .ch {
display: flex; align-items: center; gap: 10px; margin-bottom: 14px;
}
.cl-card .ch .ti { font-size: 14px; font-weight: 500; color: var(--accent-black); }
.cl-card .ch .stage {
font-family: var(--font-mono); font-size: 10.5px;
color: var(--heat); background: var(--heat-12);
border: 1px solid var(--heat-20);
border-radius: var(--r-sm); padding: 2px 8px; letter-spacing: .04em;
font-weight: 500;
}
.cl-list { list-style: none; padding: 0; margin: 0; }
.cl-list li {
display: flex; align-items: flex-start; gap: 10px;
padding: 7px 0; font-size: 13px; color: var(--accent-black); line-height: 1.6;
}
.cl-list li .mk {
width: 16px; height: 16px; border-radius: var(--r-sm);
border: 1px solid var(--black-alpha-24);
background: var(--surface); flex-shrink: 0; margin-top: 2px;
display: grid; place-items: center;
}
.cl-list li .mk svg { width: 10px; height: 10px; color: var(--heat); opacity: 0; }
/* === Toast container === */
.toast-stack { position: fixed; right: 24px; bottom: 24px; display: flex; flex-direction: column; gap: 10px; z-index: 1000; pointer-events: none; }
.toast-stack .toast { pointer-events: auto; animation: toastIn 300ms cubic-bezier(0.34,1.56,0.64,1) both; transform: translateX(0); }
.toast-stack .toast.is-leave { animation: toastOut 200ms forwards; }
@keyframes toastIn { from { transform: translateX(420px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes toastOut { to { transform: translateX(420px); opacity: 0; } }
/* === Codebox === */
.codebox {
background: var(--background-lighter);
border: 1px solid var(--border-faint);
border-radius: var(--r-md);
padding: 12px 14px; font-family: var(--font-mono);
font-size: 11.5px; line-height: 1.65;
color: var(--black-alpha-88); overflow-x: auto;
letter-spacing: .02em; white-space: pre; margin: 0;
}
/* ============================================================
§4.13§4.17 新增组件 demo CSS
============================================================ */
/* === §4.13 AI 对话面板 === */
.chat-pane {
display: flex; flex-direction: column;
background: var(--surface);
border: 1px solid var(--border-faint);
border-radius: var(--r-md);
overflow: hidden;
max-width: 520px;
}
.chat-pane .pane-h {
display: flex; align-items: center; gap: 10px;
padding: 14px 18px;
border-bottom: 1px solid var(--border-faint);
}
.chat-pane .pane-h .ic-box {
width: 28px; height: 28px; border-radius: var(--r-md);
background: var(--heat-12); color: var(--heat);
display: grid; place-items: center; flex-shrink: 0;
}
.chat-pane .pane-h .ti { font-size: 14px; font-weight: 500; color: var(--accent-black); }
.chat-body {
padding: 16px 18px;
flex: 1; overflow-y: auto;
display: flex; flex-direction: column; gap: 14px;
max-height: 360px;
}
.msg { display: flex; flex-direction: column; max-width: 90%; }
.msg.ai { align-self: flex-start; align-items: flex-start; }
.msg.user { align-self: flex-end; align-items: flex-end; }
.msg .bubble {
padding: 10px 14px; font-size: 13px; line-height: 1.6;
border: 1px solid var(--border-faint);
border-radius: var(--r-md);
color: var(--accent-black);
}
.msg.ai .bubble { background: var(--surface); }
.msg.user .bubble { background: var(--heat-12); border-color: var(--heat-20); }
.msg .ts {
font-family: var(--font-mono); font-size: 11px;
color: var(--black-alpha-48); letter-spacing: .04em;
margin-top: 4px;
}
.ai-thinking .dots { display: inline-flex; gap: 3px; padding: 12px 14px; }
.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; }
}
.chat-input { padding: 14px 18px 18px; border-top: 1px solid var(--border-faint); }
.chat-input-card {
background: var(--background-base);
border: 1px solid var(--border-faint);
border-radius: var(--r-md);
padding: 12px 14px 10px;
transition: border-color var(--t-base), box-shadow var(--t-base);
}
.chat-input-card:focus-within {
border-color: var(--accent-black);
box-shadow: 0 0 0 3px rgba(0, 0, 0, .04);
}
.chat-input-card textarea {
width: 100%; border: 0; resize: none; outline: none;
background: transparent;
font-family: inherit; font-size: 13px; line-height: 1.6;
color: var(--accent-black);
min-height: 24px; max-height: 96px;
padding: 0;
}
.chat-input-card textarea::placeholder { color: var(--black-alpha-48); }
.chat-input-actions {
display: flex; align-items: center; gap: 8px;
margin-top: 8px;
justify-content: flex-end;
}
/* === §4.14 商品 / 资产卡片 · 网格主卡 === */
.product-card {
background: var(--surface);
border: 1px solid var(--border-faint);
border-radius: var(--r-md);
cursor: pointer;
overflow: hidden;
display: flex; flex-direction: column;
transition: background var(--t-base), border-color var(--t-base);
}
.product-card:hover { background: var(--background-lighter); border-color: var(--black-alpha-48); }
.product-thumb { aspect-ratio: 1.4 / 1; }
.product-thumb.r-square { aspect-ratio: 1; }
.product-thumb.r-portrait { aspect-ratio: 3/4; }
.product-body { padding: 14px 14px 12px; flex: 1; }
.product-name {
font-size: 14px; font-weight: 600;
color: var(--accent-black);
line-height: 1.3;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
margin-bottom: 4px;
}
.product-cat {
font-family: var(--font-mono); font-size: 11px;
color: var(--black-alpha-48); letter-spacing: .04em;
}
.product-footer {
display: grid;
grid-template-columns: 1fr auto 1fr;
align-items: center;
column-gap: 8px;
padding: 10px 12px;
border-top: 1px solid var(--border-faint);
font-size: 11.5px;
color: var(--black-alpha-56);
background: var(--background-base);
}
.product-footer .stat { text-align: center; }
.product-footer .stat b { color: var(--accent-black); font-weight: 600; }
.product-footer .sep { color: var(--black-alpha-32); }
/* === §4.14 商品 / 资产卡片 · 行卡 === */
.prod-row {
display: flex; align-items: center; gap: 10px;
padding: 8px 10px;
background: var(--background-lighter);
border: 1px solid var(--border-faint);
border-radius: var(--r-sm);
transition: background var(--t-base), border-color var(--t-base);
}
.prod-row .thumb {
width: 36px; height: 36px;
background: var(--surface);
border: 1px solid var(--border-faint);
border-radius: var(--r-sm);
display: grid; place-items: center;
font-family: var(--font-mono); font-size: 9px;
color: var(--black-alpha-32); letter-spacing: .04em;
flex-shrink: 0;
}
.prod-row .nm {
font-size: 12.5px; color: var(--accent-black); font-weight: 500;
flex: 1; min-width: 0;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.prod-row .row-x {
width: 22px; height: 22px; border: 0;
background: transparent; cursor: pointer;
color: var(--black-alpha-48);
display: grid; place-items: center; border-radius: var(--r-sm);
transition: background var(--t-base), color var(--t-base);
}
.prod-row .row-x:hover { background: var(--crimson-bg); color: var(--accent-crimson); }
.prod-row .row-x svg { width: 12px; height: 12px; }
/* === §4.14 商品 / 资产卡片 · 选择器卡 === */
.pl-card {
position: relative;
background: var(--background-lighter);
border: 1px solid var(--border-faint);
border-radius: var(--r-md);
padding: 10px;
cursor: pointer;
display: flex; flex-direction: column; gap: 6px;
transition: background var(--t-base), border-color var(--t-base);
}
.pl-card:hover { background: var(--surface); }
.pl-card.selected { border-color: var(--heat); background: var(--heat-12); }
.pl-card .pl-thumb {
aspect-ratio: 1;
background: var(--surface);
border: 1px solid var(--border-faint);
border-radius: var(--r-sm);
display: grid; place-items: center;
font-family: var(--font-mono); font-size: 11px;
color: var(--black-alpha-32); letter-spacing: .04em;
}
.pl-card .pl-name {
font-size: 12.5px; font-weight: 500; color: var(--accent-black);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pl-card .pl-check {
position: absolute; top: 6px; right: 6px;
width: 18px; height: 18px;
background: var(--heat); color: #fff;
border-radius: 50%;
display: none; place-items: center;
}
.pl-card.selected .pl-check { display: grid; }
.pl-card .pl-check svg { width: 10px; height: 10px; }
/* === §4.15 人物模特卡 === */
.model-card {
position: relative;
background: var(--background-lighter);
border: 1px solid var(--border-faint);
border-radius: var(--r-md);
padding: 8px;
cursor: pointer;
display: flex; flex-direction: column; gap: 6px;
transition: background var(--t-base), border-color var(--t-base);
}
.model-card:hover { background: var(--surface); }
.model-card.selected { border-color: var(--heat); background: var(--heat-12); }
.model-card .m-thumb {
aspect-ratio: 3/4;
background: var(--surface);
border: 1px solid var(--border-faint);
border-radius: var(--r-sm);
display: grid; place-items: center;
font-family: var(--font-mono); font-size: 11px;
color: var(--black-alpha-32); letter-spacing: .04em;
}
.model-card .m-name {
font-size: 12.5px; font-weight: 500; color: var(--accent-black);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.model-card .m-meta {
font-family: var(--font-mono); font-size: 10.5px;
color: var(--black-alpha-48); letter-spacing: .04em;
}
.model-card .pl-check {
position: absolute; top: 6px; right: 6px;
width: 18px; height: 18px;
background: var(--heat); color: #fff;
border-radius: 50%;
display: none; place-items: center;
}
.model-card.selected .pl-check { display: grid; }
.model-card .pl-check svg { width: 10px; height: 10px; }
/* === §4.16 场景卡 / 通用资产卡 === */
.asset-card-2 {
background: var(--surface);
border: 1px solid var(--border-faint);
border-radius: var(--r-md);
overflow: hidden;
display: flex; flex-direction: column;
cursor: pointer;
transition: border-color var(--t-base), box-shadow var(--t-base);
}
.asset-card-2:hover {
border-color: var(--heat-40);
box-shadow: 0 1px 3px rgba(0, 0, 0, .04);
}
.asset-card-2 .thumb-2 {
aspect-ratio: 1;
background: var(--background-lighter);
display: grid; place-items: center;
font-family: var(--font-mono); font-size: 11px;
color: var(--black-alpha-32); letter-spacing: .04em;
}
.asset-card-2 .body-2 { padding: 12px 14px; }
.asset-card-2 .body-2 .ti {
font-size: 14px; font-weight: 500; color: var(--accent-black);
line-height: 1.4; margin-bottom: 4px;
}
.asset-card-2 .body-2 .sub {
font-family: var(--font-mono); font-size: 11px;
color: var(--black-alpha-48); letter-spacing: .04em;
}
/* === §4.17.1 流程步骤条 === */
.stepper {
display: flex; align-items: center; gap: 0;
padding: 14px 18px;
background: var(--surface);
border: 1px solid var(--border-faint);
border-radius: var(--r-md);
}
.stage-step {
display: flex; align-items: center; gap: 10px;
padding: 6px 14px;
cursor: pointer; user-select: none;
}
.stage-step .num {
width: 26px; height: 26px;
display: grid; place-items: center;
font-family: var(--font-mono); font-size: 12px; font-weight: 600;
border: 1px solid var(--border-faint);
border-radius: var(--r-sm);
background: var(--surface);
color: var(--black-alpha-48);
flex-shrink: 0;
transition: background var(--t-base), color var(--t-base), border-color var(--t-base);
}
.stage-step .lbl {
font-size: 13px; color: var(--black-alpha-56);
font-weight: 500;
}
.stage-step.done .num { background: var(--accent-black); border-color: var(--accent-black); color: var(--accent-white); }
.stage-step.done .lbl { color: var(--accent-black); }
.stage-step.active .num { background: var(--heat); border-color: var(--heat); color: var(--accent-white); }
.stage-step.active .lbl { color: var(--accent-black); font-weight: 600; }
.stepper-line { flex: 1; height: 1px; background: var(--border-faint); margin: 0 4px; min-width: 16px; }
/* === §4.17.2 分页 === */
.pagination-demo {
display: flex; align-items: center; gap: 16px;
padding: 14px 0;
border-top: 1px solid var(--border-faint);
font-size: 12.5px;
color: var(--black-alpha-56);
}
.pagination-demo .total b { color: var(--accent-black); font-weight: 600; }
.pagination-demo .page-size {
height: 30px; padding: 0 10px;
background: var(--surface);
border: 1px solid var(--border-faint);
border-radius: var(--r-sm);
font-size: 12.5px; color: var(--black-alpha-72);
cursor: pointer; font-family: inherit;
transition: border-color var(--t-base);
}
.pagination-demo .pages { display: inline-flex; gap: 4px; }
.pagination-demo .pages button {
min-width: 30px; height: 30px;
padding: 0 8px;
border: 1px solid var(--border-faint);
background: var(--surface);
border-radius: var(--r-sm);
cursor: pointer;
font-size: 12.5px;
color: var(--black-alpha-72);
font-family: inherit;
transition: background var(--t-base), border-color var(--t-base), color var(--t-base);
}
.pagination-demo .pages button:hover { background: var(--black-alpha-4); color: var(--accent-black); }
.pagination-demo .pages button.active {
background: var(--heat); color: var(--accent-white);
border-color: var(--heat); font-weight: 600;
}
.pagination-demo .jump input {
width: 40px; height: 24px;
border: 1px solid var(--border-faint);
border-radius: var(--r-sm);
font-family: inherit; font-size: 12.5px;
text-align: center; padding: 0 4px;
outline: none; margin: 0 4px;
color: var(--accent-black);
background: var(--surface);
}
/* === §4.17.3 视图切换 === */
.view-toggle {
display: inline-flex;
background: var(--surface);
border: 1px solid var(--border-faint);
border-radius: var(--r-sm);
padding: 2px;
}
.view-toggle button {
width: 30px; height: 28px;
display: grid; place-items: center;
border: 0; background: transparent;
color: var(--black-alpha-48);
cursor: pointer;
border-radius: 4px;
transition: background var(--t-base), color var(--t-base);
}
.view-toggle button:hover { background: var(--black-alpha-4); color: var(--accent-black); }
.view-toggle button.active { background: var(--accent-black); color: var(--accent-white); }
.view-toggle button svg { width: 14px; height: 14px; }
/* === §4.17.4 操作型胶囊 === */
.pill-tip {
display: inline-flex; align-items: center; gap: 6px;
height: 28px; padding: 0 14px;
background: var(--heat-12);
border: 1px solid var(--heat-20);
border-radius: 999px;
font-size: 12px; color: var(--heat); font-weight: 500;
cursor: pointer; font-family: inherit;
transition: background var(--t-base), color var(--t-base), border-color var(--t-base), box-shadow var(--t-base);
}
.pill-tip:hover {
background: var(--heat); color: var(--accent-white); border-color: var(--heat);
box-shadow: var(--shadow-cta);
}
/* === §4.17.5 卖点 / 编辑式列表 === */
.bullet-list-demo { list-style: none; padding: 0; margin: 0; }
.bullet-list-demo .bl-item, .bullet-list-demo .bl-add {
display: flex; align-items: center; gap: 10px;
padding: 8px 12px;
background: var(--background-lighter);
border: 1px solid var(--border-faint);
border-radius: var(--r-md);
margin-bottom: 6px;
font-size: 13.5px;
color: var(--accent-black);
transition: border-color var(--t-base);
}
.bullet-list-demo .bl-item:hover { border-color: var(--black-alpha-24); }
.bullet-list-demo .bl-add {
background: transparent;
border-style: dashed;
border-color: var(--heat-40);
}
.bullet-list-demo .num {
width: 22px; height: 22px;
background: var(--surface);
border: 1px solid var(--border-faint);
border-radius: var(--r-sm);
font-family: var(--font-mono);
font-size: 11px; color: var(--heat); font-weight: 700;
display: grid; place-items: center; flex-shrink: 0;
}
.bullet-list-demo .bl-add .num {
background: transparent; color: var(--heat);
border-color: var(--heat-40);
}
.bullet-list-demo .bl-text { flex: 1; min-width: 0; }
.bullet-list-demo .bl-input {
flex: 1; min-width: 0;
height: 24px; border: 0; padding: 0 4px;
background: transparent; font-size: 13px;
color: var(--accent-black); font-family: inherit;
outline: none;
}
.bullet-list-demo .bl-input::placeholder { color: var(--black-alpha-48); }
.bullet-list-demo .bl-x {
width: 22px; height: 22px; border: 0;
background: transparent; cursor: pointer;
color: var(--black-alpha-48);
display: grid; place-items: center; border-radius: var(--r-sm);
opacity: 0;
transition: opacity var(--t-base), background var(--t-base), color var(--t-base);
}
.bullet-list-demo .bl-item:hover .bl-x { opacity: 1; }
.bullet-list-demo .bl-x:hover { background: var(--crimson-bg); color: var(--accent-crimson); }
.bullet-list-demo .bl-x svg { width: 12px; height: 12px; }
/* === §4.18 AI 生成结果卡 === */
.gen-card {
background: var(--surface);
border: 1px solid var(--border-faint);
border-radius: var(--r-md);
padding: 16px;
display: flex; flex-direction: column; gap: 14px;
transition: border-color var(--t-base);
}
.gen-card.selected { border-color: var(--heat); }
.gen-prompt {
display: flex; align-items: flex-start; gap: 10px;
padding: 0 4px;
}
.gen-prompt .quote {
width: 16px; height: 16px;
color: var(--black-alpha-32);
margin-top: 2px; flex-shrink: 0;
}
.gen-prompt .text {
font-size: 14px; font-weight: 500;
color: var(--accent-black);
line-height: 1.5;
}
.gen-meta {
display: flex; align-items: center; gap: 8px;
padding: 0 4px;
font-family: var(--font-mono); font-size: 11.5px;
color: var(--black-alpha-48);
letter-spacing: .04em;
flex-wrap: wrap;
}
.gen-meta .m-sep { color: var(--black-alpha-24); }
.gen-images {
display: grid;
grid-template-columns: repeat(var(--cols, 4), 1fr);
gap: 10px;
}
.gen-image {
position: relative;
aspect-ratio: var(--ratio, 1/1);
border-radius: var(--r-md);
overflow: hidden;
cursor: pointer;
}
.gen-image .placeholder {
position: absolute; inset: 0;
border: 1px solid var(--border-faint);
}
.gen-image-actions {
position: absolute; top: 8px; right: 8px;
display: flex; gap: 2px;
background: var(--surface);
border: 1px solid var(--border-faint);
border-radius: var(--r-md);
padding: 2px;
opacity: 0;
z-index: 2;
box-shadow: 0 2px 8px rgba(0,0,0,.08);
transition: opacity var(--t-base);
}
.gen-image:hover .gen-image-actions { opacity: 1; }
.gen-img-btn {
width: 28px; height: 28px;
border: 0; background: transparent;
color: var(--black-alpha-56);
border-radius: 6px;
cursor: pointer;
display: grid; place-items: center;
transition: background var(--t-base), color var(--t-base);
}
.gen-img-btn:hover { background: var(--black-alpha-4); color: var(--accent-black); }
.gen-img-btn svg { width: 14px; height: 14px; }
.gen-image-feedback {
position: absolute; inset: 0;
display: flex; flex-direction: column;
align-items: center; justify-content: center;
gap: 8px;
background: rgba(38, 38, 38, .88);
color: var(--accent-white);
border-radius: var(--r-md);
opacity: 0;
pointer-events: none;
transition: opacity var(--t-base);
z-index: 3;
}
.gen-image-feedback svg { width: 20px; height: 20px; }
.gen-image-feedback span { font-size: 12.5px; font-weight: 500; }
.gen-image.show-feedback .gen-image-feedback { opacity: 1; }
.gen-card-actions {
display: flex; gap: 8px;
padding-top: 4px;
}
/* === Responsive === */
@media (max-width: 980px) {
.ds-layout { grid-template-columns: 1fr; }
.ds-sidebar { position: relative; height: auto; border-right: 0; border-bottom: 1px solid var(--border-faint); }
.ds-main { padding: 32px 24px 64px; }
.demo-stats { grid-template-columns: repeat(2, 1fr); }
.demo-stats .cell:nth-child(2) { border-right: 0; }
.demo-stats .cell:nth-child(1), .demo-stats .cell:nth-child(2) { border-bottom: 1px solid var(--border-faint); }
.dodont-grid { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<div class="ds-layout">
<!-- ============ SIDEBAR ============ -->
<aside class="ds-sidebar">
<h1>流·Studio<br>设计系统</h1>
<div class="mono-sub">// V2.1 · 2026-05-22 · INTERACTIVE</div>
<ul class="ds-nav">
<li class="nav-group">// FOUNDATION</li>
<li><a href="#philosophy">§1 设计哲学</a></li>
<li><a href="#tokens">§2.1 色彩 Tokens</a></li>
<li><a href="#alpha">§2.2 Black-Alpha</a></li>
<li><a href="#type">§2.5 字体系统</a></li>
<li><a href="#typescale">§2.6 字号阶梯</a></li>
<li><a href="#radius">§2.7 圆角</a></li>
<li><a href="#spacing">§2.8 间距</a></li>
<li><a href="#shadow">§2.9 阴影</a></li>
<li><a href="#inside-border">§2.10 inside-border</a></li>
<li class="nav-group">// SKELETON</li>
<li><a href="#skeleton">§3 页面骨架</a></li>
<li><a href="#container">§3.4 主容器装订线</a></li>
<li class="nav-group">// COMPONENTS</li>
<li><a href="#icons">§4.12 Icon 系统</a></li>
<li><a href="#buttons">§4.1 按钮</a></li>
<li><a href="#pills">§4.2 胶囊 Pills</a></li>
<li><a href="#inputs">§4.3 输入框</a></li>
<li><a href="#form-controls">§4.4 表单控件</a></li>
<li><a href="#stats">§4.5 KPI 统计</a></li>
<li><a href="#progress">§4.6 进度条</a></li>
<li><a href="#list">§4.7 列表行</a></li>
<li><a href="#tabs">§4.8 Tab</a></li>
<li><a href="#cards">§4.10 卡片</a></li>
<li><a href="#tip">§4.10 提示框</a></li>
<li><a href="#modal">§4.11 Modal</a></li>
<li><a href="#toast">§4.11 Toast</a></li>
<li><a href="#chat">§4.13 AI 对话面板 ★</a></li>
<li><a href="#card-system">§4.14 商品/资产卡 ★</a></li>
<li><a href="#model-card">§4.15 人物模特卡</a></li>
<li><a href="#scene-card">§4.16 场景卡</a></li>
<li><a href="#freq">§4.17 高频复用组件</a></li>
<li><a href="#gen-card">§4.18 AI 生成结果卡 ★</a></li>
<li class="nav-group">// SIGNATURE</li>
<li><a href="#mono-decor">§5 Mono 装饰</a></li>
<li class="nav-group">// LAYOUT</li>
<li><a href="#layouts">§6 五种布局模式</a></li>
<li class="nav-group">// GOVERNANCE</li>
<li><a href="#audit">§7 待统一清单 ★</a></li>
<li><a href="#dont">§8 Don't List</a></li>
<li><a href="#checklist">§9 Checklist</a></li>
</ul>
</aside>
<!-- ============ MAIN ============ -->
<main class="ds-main">
<!-- HERO -->
<div class="hero">
<span class="badge">// V2.1 · INTERACTIVE · 2026-05-22</span>
<h1>流·Studio 设计系统</h1>
<p>本页是 <code class="tk">design.md</code> 的可视化样板间。所有 token / 组件均来自 <code class="tk">assets/restraint.css</code> —— <strong style="color:var(--accent-black)">看到的就是页面用的</strong>。点击色块复制 token,hover / 点击组件看真实交互反馈。</p>
<div class="meta">
<span>[ Restraint · V2.1 ]</span>
<span>·</span>
<span>// 基于 design.md 整合定稿</span>
</div>
</div>
<!-- =========================================== §1 设计哲学 =========================================== -->
<section id="philosophy">
<div class="section-head">
<span class="mono-tag">// §1 · PHILOSOPHY</span>
<h2>设计哲学</h2>
<p>一句话:<strong style="color:var(--accent-black)">一台精密设备的工作面板</strong>。克制 + 单橙锚点 + 图纸装订线 + Mono 装饰。</p>
</div>
<div class="subsection">
<h3>三条铁律 <span class="mono-num">// 不可妥协</span></h3>
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:14px">
<div style="padding:22px 26px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--heat);letter-spacing:.04em;margin-bottom:10px">// RULE 1</div>
<div style="font-size:16px;font-weight:500;color:var(--accent-black);margin-bottom:8px">克制大于装饰</div>
<div style="font-size:13px;color:var(--black-alpha-64);line-height:1.7">留白 &gt; 容器 &gt; 内容,大量空气感。padding 不确定选 24,margin 不确定选 64。</div>
</div>
<div style="padding:22px 26px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--heat);letter-spacing:.04em;margin-bottom:10px">// RULE 2</div>
<div style="font-size:16px;font-weight:500;color:var(--accent-black);margin-bottom:8px">单色锚点</div>
<div style="font-size:13px;color:var(--black-alpha-64);line-height:1.7">全场只有一个 accent(橙)· 只用于 CTA / 关键状态 / 强调单词。其他颜色仅做语义信号。</div>
</div>
<div style="padding:22px 26px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--heat);letter-spacing:.04em;margin-bottom:10px">// RULE 3</div>
<div style="font-size:16px;font-weight:500;color:var(--accent-black);margin-bottom:8px">结构清晰可见</div>
<div style="font-size:13px;color:var(--black-alpha-64);line-height:1.7">用 1 px 边框 + 8 px 圆角 + 准星 + 装订线 + mono 标签暴露"图纸感",而非阴影/渐变隐藏结构。</div>
</div>
</div>
</div>
<div class="subsection">
<h3>核心签名 <span class="mono-num">// 4 个不能丢</span></h3>
<ul class="cl-list">
<li><span class="mk" style="background:var(--heat);border-color:var(--heat)"><svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" style="opacity:1"><path d="M20 6 9 17l-5-5"/></svg></span>主橙 <code class="tk heat">#fa5d19</code>(Firecrawl 实测)+ 单 hue alpha 阶梯</li>
<li><span class="mk" style="background:var(--heat);border-color:var(--heat)"><svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" style="opacity:1"><path d="M20 6 9 17l-5-5"/></svg></span>全场 8 px 圆角(Pill 999 例外)</li>
<li><span class="mk" style="background:var(--heat);border-color:var(--heat)"><svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" style="opacity:1"><path d="M20 6 9 17l-5-5"/></svg></span>主容器左右装订线 + 四角准星</li>
<li><span class="mk" style="background:var(--heat);border-color:var(--heat)"><svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" style="opacity:1"><path d="M20 6 9 17l-5-5"/></svg></span>Mono 装饰 <code class="tk">[ 200 OK ]</code> <code class="tk">// 05.14</code> <code class="tk">[ /v2 ]</code>(品牌签名 · Firecrawl 没有)</li>
</ul>
</div>
</section>
<!-- =========================================== §2.1 色彩 Tokens =========================================== -->
<section id="tokens">
<div class="section-head">
<span class="mono-tag">// §2.1 · COLOR TOKENS · FIRECRAWL-ALIGNED</span>
<h2>色彩系统</h2>
<p>冷灰底 · 单 hue 橙 · 5 色信号点。<strong style="color:var(--accent-black)">点击色块复制 token 名。</strong>禁止创建新色值,所有颜色必须用以下 token。</p>
</div>
<div class="subsection">
<h3>表面 / 背景 <span class="mono-num">// 4 档 · 冷灰无色相</span></h3>
<div class="swatch-grid" data-copy-grid>
<div class="swatch" data-hex="--background-base"><div class="chip" style="background:#f9f9f9"></div><div class="meta-row"><div class="name">--background-base</div><div class="val">#f9f9f9 · 页面底 ★</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--background-lighter"><div class="chip" style="background:#fbfbfb"></div><div class="meta-row"><div class="name">--background-lighter</div><div class="val">#fbfbfb · 容器底</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--surface"><div class="chip with-grid" style="background:#ffffff"></div><div class="meta-row"><div class="name">--surface</div><div class="val">#ffffff · 卡片 ★</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--surface-raised"><div class="chip with-grid" style="background:#ffffff"></div><div class="meta-row"><div class="name">--surface-raised</div><div class="val">#ffffff · Modal</div><div class="copy">copied</div></div></div>
</div>
</div>
<div class="subsection">
<h3>边框 <span class="mono-num">// 3 档 · 差距极小靠语义</span></h3>
<p class="lead">3 档相差只 12 色阶,肉眼几乎看不出。<strong>用语义,不用视觉对比</strong> —— 80% 场景用 <code class="tk">--border-faint</code></p>
<div class="swatch-grid" data-copy-grid>
<div class="swatch" data-hex="--border-faint"><div class="chip" style="background:#ededed"></div><div class="meta-row"><div class="name">--border-faint</div><div class="val">#ededed · 默认 ★ 80%</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--border-muted"><div class="chip" style="background:#e8e8e8"></div><div class="meta-row"><div class="name">--border-muted</div><div class="val">#e8e8e8 · 略深</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--border-loud"><div class="chip" style="background:#e6e6e6"></div><div class="meta-row"><div class="name">--border-loud</div><div class="val">#e6e6e6 · 强分隔</div><div class="copy">copied</div></div></div>
</div>
</div>
<div class="subsection">
<h3>主橙 Heat <span class="mono-num">// 单 hue #fa5d19 + 8 档 alpha</span></h3>
<p class="lead"><strong>全靠 alpha 叠加,绝不换 hue。</strong>hover 不切换深橙,而是用 90% / 16% 这些档位组合。</p>
<div class="swatch-grid" data-copy-grid>
<div class="swatch" data-hex="--heat"><div class="chip" style="background:#fa5d19"></div><div class="meta-row"><div class="name">--heat</div><div class="val">100% · CTA ★</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--heat-90"><div class="chip" style="background:rgba(250,93,25,.90)"></div><div class="meta-row"><div class="name">--heat-90</div><div class="val">90% · hover</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--heat-40"><div class="chip" style="background:rgba(250,93,25,.40)"></div><div class="meta-row"><div class="name">--heat-40</div><div class="val">40% · ring / edge</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--heat-20"><div class="chip" style="background:rgba(250,93,25,.20)"></div><div class="meta-row"><div class="name">--heat-20</div><div class="val">20% · pill border / selection</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--heat-16"><div class="chip" style="background:rgba(250,93,25,.16)"></div><div class="meta-row"><div class="name">--heat-16</div><div class="val">16% · hover bg</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--heat-12"><div class="chip" style="background:rgba(250,93,25,.12)"></div><div class="meta-row"><div class="name">--heat-12</div><div class="val">12% · tint bg ★</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--heat-8"><div class="chip" style="background:rgba(250,93,25,.08)"></div><div class="meta-row"><div class="name">--heat-8</div><div class="val">8%</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--heat-4"><div class="chip" style="background:rgba(250,93,25,.04)"></div><div class="meta-row"><div class="name">--heat-4</div><div class="val">4% · 极弱</div><div class="copy">copied</div></div></div>
</div>
</div>
<div class="subsection">
<h3>Accent 多彩点 <span class="mono-num">// 5 色信号 · 限定语义场景</span></h3>
<p class="lead"><strong>只用于语义信号</strong>(代码高亮 / info / 状态色),<strong>禁止做大面积装饰</strong> —— 全场依然只有橙色一个 accent。</p>
<div class="swatch-grid" data-copy-grid>
<div class="swatch" data-hex="--accent-black"><div class="chip" style="background:#262626"></div><div class="meta-row"><div class="name">--accent-black</div><div class="val">#262626 · 主前景 ★</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--accent-white"><div class="chip with-grid" style="background:#ffffff"></div><div class="meta-row"><div class="name">--accent-white</div><div class="val">#ffffff · 反色文字</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--accent-amethyst"><div class="chip" style="background:#9061ff"></div><div class="meta-row"><div class="name">--accent-amethyst</div><div class="val">#9061ff · 紫 / code</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--accent-bluetron"><div class="chip" style="background:#2a6dfb"></div><div class="meta-row"><div class="name">--accent-bluetron</div><div class="val">#2a6dfb · 蓝 / info</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--accent-crimson"><div class="chip" style="background:#eb3424"></div><div class="meta-row"><div class="name">--accent-crimson</div><div class="val">#eb3424 · 红 / error ★</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--accent-forest"><div class="chip" style="background:#42c366"></div><div class="meta-row"><div class="name">--accent-forest</div><div class="val">#42c366 · 绿 / success ★</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--accent-honey"><div class="chip" style="background:#ecb730"></div><div class="meta-row"><div class="name">--accent-honey</div><div class="val">#ecb730 · 黄 / warning</div><div class="copy">copied</div></div></div>
</div>
</div>
<div class="subsection">
<h3>状态色配套(底 / 边) <span class="mono-num">// 8% / 20% alpha</span></h3>
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px">
<div style="padding:16px 18px;background:var(--forest-bg);border:1px solid var(--forest-bd);border-radius:8px;color:var(--accent-forest);font-size:13px;font-weight:500"><span class="dot" style="display:inline-block;width:6px;height:6px;border-radius:50%;background:currentColor;margin-right:8px"></span>成功 · forest</div>
<div style="padding:16px 18px;background:var(--crimson-bg);border:1px solid var(--crimson-bd);border-radius:8px;color:var(--accent-crimson);font-size:13px;font-weight:500"><span class="dot" style="display:inline-block;width:6px;height:6px;border-radius:50%;background:currentColor;margin-right:8px"></span>失败 · crimson</div>
<div style="padding:16px 18px;background:var(--heat-12);border:1px solid var(--heat-20);border-radius:8px;color:var(--heat);font-size:13px;font-weight:500"><span class="dot" style="display:inline-block;width:6px;height:6px;border-radius:50%;background:currentColor;margin-right:8px"></span>信息 · heat</div>
<div style="padding:16px 18px;background:var(--honey-bg);border:1px solid var(--honey-bd);border-radius:8px;color:var(--accent-honey);font-size:13px;font-weight:500"><span class="dot" style="display:inline-block;width:6px;height:6px;border-radius:50%;background:currentColor;margin-right:8px"></span>警告 · honey</div>
</div>
</div>
<div class="subsection">
<h3>Selection · Firecrawl 签名细节</h3>
<p class="lead">页面任何文字选中时,底色 <code class="tk heat">--heat-20</code> + 字色 <code class="tk heat">--heat</code><strong>试选下面这行字看效果:</strong></p>
<p style="font-size:14px;line-height:1.7;padding:14px 18px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface);color:var(--accent-black)">本月营收 ¥327,400 较上月增长 33%,有 5 个项目处于"生成中"状态。其中 2 个需要重新调整模特模板。</p>
</div>
</section>
<!-- =========================================== §2.2 Black-Alpha =========================================== -->
<section id="alpha">
<div class="section-head">
<span class="mono-tag">// §2.2 · BLACK-ALPHA · 20 档核心工具尺</span>
<h2>Black-Alpha 阶梯</h2>
<p><strong>日常用得最多的 token。</strong>024% 用 <code class="tk">rgba(0,0,0,...)</code>;32% 起换 <code class="tk">rgba(38,38,38,...)</code>(避免叠出"灰中带蓝")。</p>
</div>
<div class="subsection">
<div class="swatch-grid" data-copy-grid>
<div class="swatch" data-hex="--black-alpha-1"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.01)"></div></div><div class="meta-row"><div class="name">--black-alpha-1</div><div class="val">1%</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--black-alpha-2"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.02)"></div></div><div class="meta-row"><div class="name">--black-alpha-2</div><div class="val">2%</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--black-alpha-3"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.03)"></div></div><div class="meta-row"><div class="name">--black-alpha-3</div><div class="val">3%</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--black-alpha-4"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.04)"></div></div><div class="meta-row"><div class="name">--black-alpha-4</div><div class="val">4% · hover bg ★</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--black-alpha-5"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.05)"></div></div><div class="meta-row"><div class="name">--black-alpha-5</div><div class="val">5% · disabled bg</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--black-alpha-7"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.07)"></div></div><div class="meta-row"><div class="name">--black-alpha-7</div><div class="val">7% · active bg ★</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--black-alpha-8"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.08)"></div></div><div class="meta-row"><div class="name">--black-alpha-8</div><div class="val">8% · prog 未开始</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--black-alpha-12"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.12)"></div></div><div class="meta-row"><div class="name">--black-alpha-12</div><div class="val">12% · inside-border ★</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--black-alpha-24"><div class="chip with-grid"><div style="position:absolute;inset:0;background:rgba(0,0,0,.24)"></div></div><div class="meta-row"><div class="name">--black-alpha-24</div><div class="val">24% · input hover</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--black-alpha-32"><div class="chip" style="background:rgba(38,38,38,.32)"></div><div class="meta-row"><div class="name">--black-alpha-32</div><div class="val">32% · base 切换 →</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--black-alpha-48"><div class="chip" style="background:rgba(38,38,38,.48)"></div><div class="meta-row"><div class="name">--black-alpha-48</div><div class="val">48% · 占位字色 ★</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--black-alpha-56"><div class="chip" style="background:rgba(38,38,38,.56)"></div><div class="meta-row"><div class="name">--black-alpha-56</div><div class="val">56% · 次级文字 ★</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--black-alpha-64"><div class="chip" style="background:rgba(38,38,38,.64)"></div><div class="meta-row"><div class="name">--black-alpha-64</div><div class="val">64% · 描述</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--black-alpha-72"><div class="chip" style="background:rgba(38,38,38,.72)"></div><div class="meta-row"><div class="name">--black-alpha-72</div><div class="val">72%</div><div class="copy">copied</div></div></div>
<div class="swatch" data-hex="--black-alpha-88"><div class="chip" style="background:rgba(38,38,38,.88)"></div><div class="meta-row"><div class="name">--black-alpha-88</div><div class="val">88% · 近主前景</div><div class="copy">copied</div></div></div>
</div>
</div>
</section>
<!-- =========================================== §2.5 字体系统 =========================================== -->
<section id="type">
<div class="section-head">
<span class="mono-tag">// §2.5 · TYPE · MIXED STRATEGY</span>
<h2>字体系统 · 中英协作</h2>
<p><code class="tk">Inter</code>(英文/数字)+ <code class="tk">Alibaba PuHuiTi</code>(中文)+ <code class="tk">JetBrains Mono</code>(装饰)。浏览器按字符级 fallthrough,<strong>不需要 JS,中英自然分工</strong></p>
</div>
<div class="subsection">
<h3>字体族原理 <span class="mono-num">// browser-level character fallthrough</span></h3>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:14px;margin-bottom:24px">
<div style="padding:24px 26px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--black-alpha-48);letter-spacing:.06em;margin-bottom:14px">// 01 · ENGLISH</div>
<div style="font-family:'Inter',sans-serif;font-size:24px;font-weight:500;letter-spacing:-.01em;color:var(--accent-black);margin-bottom:8px">Inter</div>
<div style="font-family:'Inter',sans-serif;font-size:13px;color:var(--black-alpha-64);line-height:1.6">The quick brown fox jumps. 0123456789 — Vercel / Linear / Stripe 御用,屏幕 UI 优化。</div>
</div>
<div style="padding:24px 26px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--black-alpha-48);letter-spacing:.06em;margin-bottom:14px">// 02 · 中文</div>
<div style="font-family:'Alibaba PuHuiTi','PingFang SC',sans-serif;font-size:24px;font-weight:500;letter-spacing:-.01em;color:var(--accent-black);margin-bottom:8px">阿里普惠体</div>
<div style="font-family:'Alibaba PuHuiTi','PingFang SC',sans-serif;font-size:13px;color:var(--black-alpha-64);line-height:1.6">为中英混排专门设计的笔画粗细配比,与 Inter 视觉重量贴近。</div>
</div>
<div style="padding:24px 26px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--black-alpha-48);letter-spacing:.06em;margin-bottom:14px">// 03 · 装饰 MONO</div>
<div style="font-family:var(--font-mono);font-size:22px;font-weight:500;color:var(--accent-black);margin-bottom:8px">JetBrains</div>
<div style="font-family:var(--font-mono);font-size:12px;color:var(--black-alpha-64);line-height:1.6;letter-spacing:.02em">[ 200 OK ] · // 05.14 · /v2 — 仅装饰,不参与正文。</div>
</div>
</div>
<div style="padding:22px 26px;background:var(--heat-8);border:1px solid var(--heat-20);border-radius:8px">
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--heat);letter-spacing:.06em;margin-bottom:10px">// 混排实测 · MIXED RENDERING</div>
<div style="font-size:18px;font-weight:500;color:var(--accent-black);line-height:1.5">本月营收 ¥327,400 较上月 +33%,共 5 个 AI 项目处于 "生成中" 状态</div>
<div style="font-family:var(--font-mono);font-size:11px;color:var(--black-alpha-48);margin-top:10px;letter-spacing:.04em">↑ 中文走 PuHuiTi · "¥" "327,400" "+33%" "5" "AI" 走 Inter · 字重视觉匀质,无错位</div>
</div>
</div>
<div class="subsection">
<h3>字重档位 <span class="mono-num">// 400 / 500 / 600 · 700 仅徽标</span></h3>
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px">
<div style="padding:20px 22px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--black-alpha-48);letter-spacing:.04em;margin-bottom:10px">// REGULAR · 400</div>
<div style="font-size:18px;font-weight:400;color:var(--accent-black)">流·Studio · Aa Bb 123</div>
</div>
<div style="padding:20px 22px;border:1px solid var(--heat-20);border-radius:8px;background:var(--heat-8)">
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--heat);letter-spacing:.04em;margin-bottom:10px">// MEDIUM · 500 ★ 默认</div>
<div style="font-size:18px;font-weight:500;color:var(--accent-black)">流·Studio · Aa Bb 123</div>
</div>
<div style="padding:20px 22px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--black-alpha-48);letter-spacing:.04em;margin-bottom:10px">// SEMIBOLD · 600</div>
<div style="font-size:18px;font-weight:600;color:var(--accent-black)">流·Studio · Aa Bb 123</div>
</div>
<div style="padding:20px 22px;border:1px solid var(--border-faint);border-radius:8px;background:var(--surface)">
<div style="font-family:var(--font-mono);font-size:10.5px;color:var(--black-alpha-48);letter-spacing:.04em;margin-bottom:10px">// BOLD · 700 · 限徽标</div>
<div style="font-size:18px;font-weight:700;color:var(--accent-black)">流·Studio · Aa Bb 123</div>
</div>
</div>
<p class="mono" style="margin-top:14px">// Bold 700 仅用于 Ctrl K 这种纯英文徽标场景 · 正文严禁 700(中英字重错位会暴露)</p>
</div>
</section>
<!-- =========================================== §2.6 字号阶梯 =========================================== -->
<section id="typescale">
<div class="section-head">
<span class="mono-tag">// §2.6 · TYPE SCALE</span>
<h2>字号 / 字重 / 行高(11 档)</h2>
<p>数值类必须加 <code class="tk">tabular-nums</code><code class="tk">.num</code>。中文正文行高 1.651.8。</p>
</div>
<div class="subsection">
<div class="type-row">
<div class="meta-col"><strong>H1 / Hero</strong>36 / 500 / -0.024em / 1.2</div>
<div class="sample" style="font-size:36px;font-weight:500;letter-spacing:-.024em;line-height:1.2">早上好,大莱</div>
</div>
<div class="type-row">
<div class="meta-col"><strong>区块 H2</strong>28 / 500 / -0.02em / 1.25</div>
<div class="sample" style="font-size:28px;font-weight:500;letter-spacing:-.02em;line-height:1.25">设计系统总览</div>
</div>
<div class="type-row">
<div class="meta-col"><strong>KPI 数值</strong>32 / 500 / -0.02em / tabular-nums</div>
<div class="sample" style="font-size:32px;font-weight:500;letter-spacing:-.02em;font-variant-numeric:tabular-nums">¥327<small style="font-size:15px;color:var(--black-alpha-48)">.40 K</small></div>
</div>
<div class="type-row">
<div class="meta-col"><strong>子区 H3</strong>16 / 500 / -0.01em / 1.4</div>
<div class="sample" style="font-size:16px;font-weight:500;letter-spacing:-.01em">最近项目</div>
</div>
<div class="type-row">
<div class="meta-col"><strong>卡片标题</strong>14 / 500 / normal / 1.4</div>
<div class="sample" style="font-size:14px;font-weight:500">夏季新款蕾丝连衣裙 · 蓝色 / M</div>
</div>
<div class="type-row">
<div class="meta-col"><strong>正文 body</strong>14 / 400 / normal / 1.65</div>
<div class="sample" style="font-size:14px;line-height:1.65">商家可能没有现成的商品图,需要新增一种「AI 生成」模式 —— 上传一张随手拍的原图,AI 生成 4 张满意的头图。</div>
</div>
<div class="type-row">
<div class="meta-col"><strong>Label · 按钮 / Tab</strong>13 / 500 / normal</div>
<div class="sample" style="font-size:13px;font-weight:500">查看 Demo</div>
</div>
<div class="type-row">
<div class="meta-col"><strong>描述次级</strong>13 / 400 / black-alpha-64 / 1.8</div>
<div class="sample" style="font-size:13px;color:var(--black-alpha-64);line-height:1.8">本月营收较上月增长 33%,5 个项目处于"生成中"状态,2 个需要重新调整模特模板</div>
</div>
<div class="type-row">
<div class="meta-col"><strong>Pill 文字</strong>11.5 / 500 / normal</div>
<div class="sample" style="font-size:11.5px;font-weight:500">生成中</div>
</div>
<div class="type-row">
<div class="meta-col"><strong>Inter Bold 徽标</strong>11.5 / 700 / Inter only</div>
<div class="sample" style="font-family:'Inter',sans-serif;font-size:11.5px;font-weight:700;color:var(--black-alpha-56);letter-spacing:.02em">Ctrl K · ESC · Enter · ⇧+Tab</div>
</div>
<div class="type-row">
<div class="meta-col"><strong>Mono 标签</strong>11 / 400 / 0.04em · JetBrains</div>
<div class="sample" style="font-family:var(--font-mono);font-size:11px;letter-spacing:.04em;color:var(--black-alpha-48)">[ 200 OK ] [ .MP4 · 9:16 ] [ /v2 ]</div>
</div>
<div class="type-row">
<div class="meta-col"><strong>Mono 散点装饰</strong>8.5 / 400 / 0.04em</div>
<div class="sample" style="font-family:var(--font-mono);font-size:8.5px;letter-spacing:.04em;color:var(--black-alpha-12)">· · &nbsp;+ · &nbsp;+XX+ +XXXX· +X·</div>
</div>
</div>
</section>
<!-- =========================================== §2.7 圆角 =========================================== -->
<section id="radius">
<div class="section-head">
<span class="mono-tag">// §2.7 · RADIUS</span>
<h2>圆角阶梯</h2>
<p>统一 <strong style="color:var(--accent-black)">8 px</strong> 作为默认主圆角。完全圆 999 px 仅用于 pill / dot。<strong>不确定就选 8 · &gt;12 px 直接判错。</strong></p>
</div>
<div class="radius-row">
<div class="radius-box"><div class="box" style="border-radius:0;background:var(--crimson-bg);border-color:var(--crimson-bd)"><span class="mono" style="color:var(--accent-crimson)"></span></div><div class="lbl" style="color:var(--accent-crimson)">禁用 V1</div><div class="px">0 px</div></div>
<div class="radius-box"><div class="box" style="border-radius:2px"></div><div class="lbl">progress</div><div class="px">2 px</div></div>
<div class="radius-box"><div class="box" style="border-radius:4px"></div><div class="lbl">kbd / badge</div><div class="px">4 px</div></div>
<div class="radius-box"><div class="box" style="border-radius:6px"></div><div class="lbl">小色块</div><div class="px">6 px</div></div>
<div class="radius-box"><div class="box" style="border-radius:8px;border-color:var(--heat);background:var(--heat-8)"></div><div class="lbl" style="color:var(--heat);font-weight:500">主默认</div><div class="px" style="color:var(--heat)">8 px ★</div></div>
<div class="radius-box"><div class="box" style="border-radius:999px;width:160px;height:48px"><span class="mono">pill</span></div><div class="lbl">pill / dot</div><div class="px">999 px</div></div>
</div>
</section>
<!-- =========================================== §2.8 间距 =========================================== -->
<section id="spacing">
<div class="section-head">
<span class="mono-tag">// §2.8 · SPACING</span>
<h2>间距阶梯</h2>
<p>基础栅格 4 px。<strong>当不确定 padding 是 16 还是 24 时,选 24。</strong>当不确定 margin 是 48 还是 64 时,选 64。</p>
</div>
<div class="subsection">
<h3>常用阶梯</h3>
<div class="spacing-row">
<div class="spacing-box"><div class="spacing-bar" style="width:4px;height:36px"></div><div class="lbl">4</div></div>
<div class="spacing-box"><div class="spacing-bar" style="width:8px;height:36px"></div><div class="lbl">8</div></div>
<div class="spacing-box"><div class="spacing-bar" style="width:12px;height:36px"></div><div class="lbl">12</div></div>
<div class="spacing-box"><div class="spacing-bar" style="width:16px;height:36px"></div><div class="lbl">16</div></div>
<div class="spacing-box"><div class="spacing-bar" style="width:20px;height:36px"></div><div class="lbl">20</div></div>
<div class="spacing-box"><div class="spacing-bar" style="width:24px;height:36px"></div><div class="lbl">24 ★</div></div>
<div class="spacing-box"><div class="spacing-bar" style="width:32px;height:36px"></div><div class="lbl">32</div></div>
<div class="spacing-box"><div class="spacing-bar" style="width:40px;height:36px"></div><div class="lbl">40</div></div>
<div class="spacing-box"><div class="spacing-bar" style="width:48px;height:36px"></div><div class="lbl">48</div></div>
<div class="spacing-box"><div class="spacing-bar" style="width:64px;height:36px"></div><div class="lbl">64 ★</div></div>
<div class="spacing-box"><div class="spacing-bar" style="width:80px;height:36px"></div><div class="lbl">80</div></div>
<div class="spacing-box"><div class="spacing-bar" style="width:104px;height:36px"></div><div class="lbl">104</div></div>
</div>
</div>
<div class="subsection">
<h3>典型场景</h3>
<table class="audit-table">
<thead><tr><th>场景</th><th></th></tr></thead>
<tbody>
<tr><td colspan="1" style="color:var(--accent-black)">Sidebar 宽度</td><td class="now">248 px</td></tr>
<tr><td colspan="1" style="color:var(--accent-black)">Topbar 高度</td><td class="now">64 px</td></tr>
<tr><td colspan="1" style="color:var(--accent-black)">Content padding</td><td class="now">48 · 28 · 72</td></tr>
<tr><td colspan="1" style="color:var(--accent-black)">卡片内 padding(大)</td><td class="now">28 · 30 或 24 · 28</td></tr>
<tr><td colspan="1" style="color:var(--accent-black)">列表行 padding</td><td class="now">14 · 18 ~ 20 · 24</td></tr>
<tr><td colspan="1" style="color:var(--accent-black)">KPI cell padding</td><td class="now">24 · 28</td></tr>
<tr><td colspan="1" style="color:var(--accent-black)">主区块 margin</td><td class="now">64104 px</td></tr>
<tr><td colspan="1" style="color:var(--accent-black)">子区块 margin</td><td class="now">3648 px</td></tr>
<tr><td colspan="1" style="color:var(--accent-black)">卡片网格 gap</td><td class="now">14(子区)/ 24(主区)</td></tr>
</tbody>
</table>
</div>
</section>
<!-- =========================================== §2.9 阴影 =========================================== -->
<section id="shadow">
<div class="section-head">
<span class="mono-tag">// §2.9 · SHADOW</span>
<h2>阴影 · 只 3 个允许场景</h2>
<p>主 CTA(4 层橙色发光)+ Toast/Dropdown 浮层(白色 6%)。其他场景<strong style="color:var(--accent-crimson)">一律禁阴影</strong></p>
</div>
<div class="shadow-row">
<div class="shadow-box shadow-cta-demo">主 CTA · 4 层橙阴影</div>
<div class="shadow-box shadow-cta-demo" style="box-shadow:inset 0 -4px 8px rgba(250,93,25,.20),0 1px 1px rgba(250,93,25,.16),0 4px 8px rgba(250,93,25,.20),0 .5px .5px rgba(250,93,25,.16)">主 CTA · hover 抬升</div>
<div class="shadow-box shadow-floating-demo">Toast / Dropdown · 白阴影</div>
</div>
</section>
<!-- =========================================== §2.10 inside-border =========================================== -->
<section id="inside-border">
<div class="section-head">
<span class="mono-tag">// §2.10 · INSIDE-BORDER</span>
<h2>边框策略 · inside-border</h2>
<p>默认边框用 <code class="tk">::before</code> 伪元素绘制(而非真 <code class="tk">border</code>),hover 时让 <code class="tk">::before</code> 透明度 → 0,<strong>不触发布局抖动</strong><strong>hover 下面的卡看效果。</strong></p>
</div>
<div class="ib-demo">
<div class="ib-box">// 默认</div>
<div class="ib-box">// hover 我看</div>
<div class="ib-box">// hover 我看</div>
</div>
</section>
<!-- =========================================== §3 页面骨架 =========================================== -->
<section id="skeleton">
<div class="section-head">
<span class="mono-tag">// §3 · SKELETON</span>
<h2>页面骨架(全站统一)</h2>
<p>每个新页面都用同一套 HTML 骨架。<code class="tk">shell.js</code> 自动注入 sidebar + topbar,<strong>页面只写 <code class="tk">&lt;main&gt;</code> 内的 <code class="tk">.content</code> 内容</strong></p>
</div>
<div class="subsection">
<h3>HTML 模板</h3>
<pre class="codebox">&lt;link rel="stylesheet" href="assets/restraint.css"&gt;
&lt;link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700
&amp;family=JetBrains+Mono:wght@400;500&amp;display=swap" rel="stylesheet"&gt;
&lt;div class="app"&gt;
&lt;aside class="sidebar"&gt;&lt;!-- shell.js 注入 --&gt;&lt;/aside&gt;
&lt;main&gt;
&lt;div class="topbar"&gt;&lt;!-- shell.js 注入:crumbs · right --&gt;&lt;/div&gt;
&lt;div class="content"&gt;
&lt;div class="page-head"&gt;
&lt;div&gt;
&lt;h1&gt;商品库&lt;/h1&gt;
&lt;div class="sub"&gt;&lt;span class="mono"&gt;// 12 个商品&lt;/span&gt; · 描述&lt;/div&gt;
&lt;/div&gt;
&lt;div class="actions"&gt;
&lt;button class="btn"&gt;导入&lt;/button&gt;
&lt;button class="btn btn-primary"&gt;+ 新建商品&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section-h"&gt;
&lt;h2&gt;最近项目&lt;/h2&gt;
&lt;a class="more"&gt;[ ALL · 12 ] →&lt;/a&gt;
&lt;/div&gt;
&lt;!-- 内容 --&gt;
&lt;/div&gt;
&lt;/main&gt;
&lt;/div&gt;
&lt;script src="assets/shell.js" defer&gt;&lt;/script&gt;</pre>
</div>
</section>
<!-- =========================================== §3.4 主容器装订线 =========================================== -->
<section id="container">
<div class="section-head">
<span class="mono-tag">// §3.4 · SIGNATURE · CONTAINER GUTTER</span>
<h2>主容器装订线</h2>
<p>工作台 / 项目列表 / 商品库 / 流水线主区:左右两条 1 px 边线 + 4 角圆弧内凹 SVG 准星。Modal / 编辑器全屏画布<strong>不必加</strong></p>
</div>
<div class="container-demo">
<svg class="corner tl" viewBox="0 0 22 21" fill="currentColor"><path d="M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z"/></svg>
<svg class="corner tr" viewBox="0 0 22 21" fill="currentColor"><path d="M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z"/></svg>
<svg class="corner bl" viewBox="0 0 22 21" fill="currentColor"><path d="M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z"/></svg>
<svg class="corner br" viewBox="0 0 22 21" fill="currentColor"><path d="M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z"/></svg>
<div class="inner">
这块容器左右贯穿两条 1 px 边线,四角带圆弧内凹的 SVG 准星<br>
<span class="mono">// container-demo · max-width: 720 · border-x only</span>
</div>
</div>
</section>
<!-- =========================================== §4.12 Icon 系统 =========================================== -->
<section id="icons">
<div class="section-head">
<span class="mono-tag">// §4.12 · ICONS</span>
<h2>Icon 系统</h2>
<p>统一 SVG line icon · <code class="tk">stroke 1.5</code> · <code class="tk">linecap round</code> · 颜色通过 <code class="tk">currentColor</code> 继承。<strong>禁用 emoji / filled icon</strong></p>
</div>
<div class="subsection">
<h3>尺寸阶梯 <span class="mono-num">// 5 档</span></h3>
<div class="icon-row">
<div class="icon-cell">
<div class="ic" style="width:32px;height:32px"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg></div>
<div class="lbl">S · 14 px</div>
</div>
<div class="icon-cell">
<div class="ic" style="width:36px;height:36px"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg></div>
<div class="lbl">M · 16 px ★</div>
</div>
<div class="icon-cell">
<div class="ic" style="width:40px;height:40px"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg></div>
<div class="lbl">L · 20 px</div>
</div>
<div class="icon-cell">
<div class="ic" style="width:48px;height:48px"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg></div>
<div class="lbl">XL · 24 px</div>
</div>
<div class="icon-cell">
<div class="ic" style="width:64px;height:64px"><svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg></div>
<div class="lbl">Hero · 36 px</div>
</div>
</div>
</div>
<div class="subsection">
<h3>颜色场景 <span class="mono-num">// 通过 currentColor 继承</span></h3>
<div class="icon-color-row">
<div class="demo" style="color:var(--black-alpha-56)">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
<span>默认 alpha-56</span>
</div>
<div class="demo" style="background:var(--black-alpha-4);color:var(--accent-black)">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
<span>hover · 主前景</span>
</div>
<div class="demo" style="color:var(--heat);background:var(--heat-12);border-color:var(--heat-20)">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
<span>active · heat</span>
</div>
<div class="demo primary">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
<span>在主 CTA 内</span>
</div>
<div class="demo disabled">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
<span>disabled</span>
</div>
</div>
</div>
<div class="subsection">
<h3>Icon Box <span class="mono-num">// 快捷入口 / Modal 头部用</span></h3>
<div style="display:flex;gap:14px;align-items:center;flex-wrap:wrap">
<div style="width:32px;height:32px;border-radius:8px;background:var(--heat-12);display:grid;place-items:center"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--heat)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><path d="m9 11 3 3L22 4"/></svg></div>
<div style="width:32px;height:32px;border-radius:8px;background:var(--heat-12);display:grid;place-items:center"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--heat)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="m9 9 6 6m0-6-6 6"/></svg></div>
<div style="width:32px;height:32px;border-radius:8px;background:var(--heat-12);display:grid;place-items:center"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--heat)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83"/></svg></div>
<span class="mono">32×32 · 8 px 圆角 · --heat-12 底 · 16 px line icon</span>
</div>
</div>
</section>
<!-- =========================================== §4.1 按钮 · 三级体系 =========================================== -->
<section id="buttons">
<div class="section-head">
<span class="mono-tag">// §4.1 · BUTTONS · 三级体系(按功能重要性)</span>
<h2>按钮 · 按功能重要性分 3 级</h2>
<p><strong style="color:var(--accent-black)">视觉强度 = 操作重要程度。</strong>一个区域只能有<strong style="color:var(--heat)">一个</strong>一级按钮(像航海图上只能有一个北极星)。<strong style="color:var(--accent-crimson)">视觉等级混乱比按钮不好看更致命</strong></p>
</div>
<div class="subsection">
<h3>三级体系总览 <span class="mono-num">// 视觉 / 语义 / 数量约束</span></h3>
<table class="audit-table">
<thead><tr><th>等级</th><th>类名</th><th>视觉</th><th>语义</th><th>数量约束</th></tr></thead>
<tbody>
<tr>
<td><span class="pill pill-l3 info"><span class="dot"></span>L1</span></td>
<td class="now">.btn.btn-primary</td>
<td>橙底 + 4 层橙阴影 + 字重 600</td>
<td style="color:var(--accent-black);font-weight:500">页面/弹窗最重要动作 · 主动作</td>
<td class="should">一个区域只 1 个 ★</td>
</tr>
<tr>
<td><span class="pill pill-l3 neutral"><span class="dot"></span>L2</span></td>
<td class="now">.btn</td>
<td>白底 + inside-border + 主前景字</td>
<td style="color:var(--accent-black);font-weight:500">跟主操作并列的重要动作</td>
<td class="should">可多个</td>
</tr>
<tr>
<td><span class="pill pill-l3 neutral"><span class="dot"></span>L3</span></td>
<td class="now">.btn.btn-ghost</td>
<td>透明底 + 无框 + alpha-56 字</td>
<td style="color:var(--accent-black);font-weight:500">辅助 / 链接式弱化操作</td>
<td class="should">不限</td>
</tr>
</tbody>
</table>
</div>
<div class="subsection">
<h3>选谁?决策表 <span class="mono-num">// 操作类型 → 等级</span></h3>
<table class="audit-table">
<thead><tr><th>操作类型</th><th>等级</th><th>例子</th></tr></thead>
<tbody>
<tr><td style="color:var(--accent-black)">提交 / 确认 / 创建 / 下一步 / 保存 / 生成</td><td><span class="pill pill-l3 info"><span class="dot"></span>L1 一级</span></td><td class="now">创建商品 · 确认删除 · 开始生成</td></tr>
<tr><td style="color:var(--accent-black)">取消 / 重置 / 导出 / 导入 / 上一步 / 关闭</td><td><span class="pill pill-l3 neutral"><span class="dot"></span>L2 二级</span></td><td class="now">取消 · 重置 · 导出 CSV</td></tr>
<tr><td style="color:var(--accent-black)">跳过 / 了解更多 / 查看详情 / 行内动作</td><td><span class="pill pill-l3 neutral"><span class="dot"></span>L3 三级</span></td><td class="now">跳过 · 了解更多 → · [查看] [编辑] [删除] 行内</td></tr>
<tr><td style="color:var(--accent-black)">破坏性(删除 / 危险)</td><td><span class="pill pill-l3 err"><span class="dot"></span>L1 in Modal</span></td><td class="now">列表里的"删除"用二级 → 弹 modal,modal 里的"确认删除"才是一级</td></tr>
</tbody>
</table>
</div>
<div class="subsection">
<h3>一级按钮 · Primary <span class="mono-num">// .btn-primary · 一个区域只 1 个</span></h3>
<p class="lead"><strong>语义:</strong>用户在当前页面/弹窗最希望完成的<strong>那一个</strong>动作。视觉上需要"被看到"。</p>
<div class="btn-row"><span class="state-label">// default</span><button class="btn btn-primary">创建商品</button><button class="btn btn-primary">下一步<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg></button></div>
<div class="btn-row"><span class="state-label">// hover</span><button class="btn btn-primary demo-hover">创建商品</button></div>
<div class="btn-row"><span class="state-label">// active</span><button class="btn btn-primary demo-active">创建商品</button></div>
<div class="btn-row"><span class="state-label">// focused</span><button class="btn btn-primary demo-focus">创建商品</button></div>
<div class="btn-row"><span class="state-label">// disabled</span><button class="btn btn-primary" disabled>创建商品</button></div>
</div>
<div class="subsection">
<h3>二级按钮 · Secondary <span class="mono-num">// .btn · 并列动作 · 可多个</span></h3>
<p class="lead"><strong>语义:</strong>跟主操作并列出现的动作,但不是首要焦点 —— 取消、重置、导出、上一步、关闭。</p>
<div class="btn-row"><span class="state-label">// default</span><button class="btn">取消</button><button class="btn"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>导出</button></div>
<div class="btn-row"><span class="state-label">// hover</span><button class="btn demo-hover">取消</button></div>
<div class="btn-row"><span class="state-label">// active</span><button class="btn demo-active">取消</button></div>
<div class="btn-row"><span class="state-label">// focused</span><button class="btn demo-focus">取消</button></div>
<div class="btn-row"><span class="state-label">// disabled</span><button class="btn" disabled>取消</button></div>
</div>
<div class="subsection">
<h3>三级按钮 · Tertiary <span class="mono-num">// .btn-ghost · 弱化辅助 · 不限</span></h3>
<p class="lead"><strong>语义:</strong>视觉降级的辅助动作 —— 跳过、了解更多、行内 [查看]/[编辑]/[删除]。<strong>不抢夺主流程注意力</strong></p>
<div class="btn-row"><span class="state-label">// default</span><button class="btn btn-ghost">跳过</button><button class="btn btn-ghost">了解更多 →</button></div>
<div class="btn-row"><span class="state-label">// hover</span><button class="btn btn-ghost demo-hover">跳过</button></div>
<div class="btn-row"><span class="state-label">// active</span><button class="btn btn-ghost demo-active">跳过</button></div>
<div class="btn-row"><span class="state-label">// disabled</span><button class="btn btn-ghost" disabled>跳过</button></div>
</div>
<div class="subsection">
<h3>典型组合 <span class="mono-num">// 一个区域如何摆放 4 种场景</span></h3>
<p class="lead">// 1 · <strong>page-head 标题区</strong> · 模式 <code class="tk">[L2] + [L1]</code></p>
<div style="background:var(--surface);border:1px solid var(--border-faint);border-radius:8px;padding:18px 22px;margin-bottom:18px;display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap">
<div><div style="font-size:18px;color:var(--accent-black);font-weight:500;margin-bottom:6px">商品库</div><div class="mono">// 12 个商品 · 你的所有商品和卖点</div></div>
<div style="display:flex;gap:10px"><button class="btn btn-lg">导入</button><button class="btn btn-primary btn-lg">+ 新建商品</button></div>
</div>
<p class="lead">// 2 · <strong>Modal 底栏</strong> · 模式 <code class="tk">[L2 取消] + [L1 确认]</code> · <strong style="color:var(--accent-black)">主操作永远在右</strong></p>
<div style="background:var(--surface);border:1px solid var(--border-faint);border-radius:8px;padding:18px 22px;margin-bottom:18px;display:flex;justify-content:flex-end;align-items:center;gap:10px">
<button class="btn">取消</button>
<button class="btn btn-primary">确认删除</button>
</div>
<p class="lead">// 3 · <strong>卡片 / 列表行内</strong> · 模式 <code class="tk">[L3] × N</code> · 弱化避免抢戏</p>
<div style="background:var(--surface);border:1px solid var(--border-faint);border-radius:8px;padding:18px 22px;margin-bottom:18px;display:flex;justify-content:space-between;align-items:center;gap:16px">
<div style="min-width:0;flex:1"><div style="font-size:14px;color:var(--accent-black);font-weight:500;margin-bottom:4px">夏季新款蕾丝连衣裙</div><div class="mono">// 05.14 · 蓝色 / M</div></div>
<div style="display:flex;gap:2px"><button class="btn btn-ghost btn-sm">查看</button><button class="btn btn-ghost btn-sm">编辑</button><button class="btn btn-ghost btn-sm">删除</button></div>
</div>
<p class="lead">// 4 · <strong>表单 / 向导底部</strong> · 模式 <code class="tk">[L3] + spacer + [L2] + [L1]</code></p>
<div style="background:var(--surface);border:1px solid var(--border-faint);border-radius:8px;padding:18px 22px;display:flex;align-items:center;gap:10px;flex-wrap:wrap">
<button class="btn btn-ghost">← 上一步</button>
<div style="flex:1"></div>
<button class="btn">保存草稿</button>
<button class="btn btn-primary">提交</button>
</div>
</div>
<div class="subsection">
<h3>尺寸阶梯 <span class="mono-num">// 独立于等级 · 按上下文密度选</span></h3>
<p class="lead">尺寸跟等级<strong>正交</strong> — 一级可以是 sm/默认/lg,二级三级同理。按上下文密度选尺寸。</p>
<div class="btn-row">
<button class="btn btn-sm">Small · 28h</button>
<button class="btn">Default · 36h ★</button>
<button class="btn btn-lg">Large · 40h</button>
</div>
<div class="btn-row" style="margin-top:12px">
<button class="btn btn-primary btn-sm">Small</button>
<button class="btn btn-primary">Default</button>
<button class="btn btn-primary btn-lg">Large</button>
</div>
<p class="mono" style="margin-top:14px">// sm 用于:行内/列表行末/表格内/紧凑工具栏 · lg 用于:hero CTA / page-head 主操作(已全局覆盖)</p>
</div>
<div class="subsection">
<h3>常见错误 <span class="mono-num">// Do / Don't 对照</span></h3>
<div class="dodont-grid">
<div class="dodont dont">
<span class="head">DON'T</span>
<div class="body"><strong>一个区域两个一级橙按钮并列</strong> — 用户视线分散,不知道该点哪个</div>
</div>
<div class="dodont do">
<span class="head">DO</span>
<div class="body">[二级] + [一级] · 永远只有一个真正的主动作</div>
</div>
<div class="dodont dont">
<span class="head">DON'T</span>
<div class="body"><strong>"取消"做成橙色 primary</strong> — 取消是退出动作,不应该是焦点</div>
</div>
<div class="dodont do">
<span class="head">DO</span>
<div class="body">"取消" 永远是二级 .btn,放在主操作的<strong>左边</strong></div>
</div>
<div class="dodont dont">
<span class="head">DON'T</span>
<div class="body"><strong>重要操作用 ghost 三级</strong> — 弱化了主流程,用户找不到入口</div>
</div>
<div class="dodont do">
<span class="head">DO</span>
<div class="body">按重要性分级:主动作橙 · 次重要白 · 弱化 ghost</div>
</div>
<div class="dodont dont">
<span class="head">DON'T</span>
<div class="body"><strong>三级按钮 inline 加边框</strong> — 加了边框就退化成二级了</div>
</div>
<div class="dodont do">
<span class="head">DO</span>
<div class="body">三级保持 ghost 无框,只 hover 时出 4% 浅底</div>
</div>
<div class="dodont dont">
<span class="head">DON'T</span>
<div class="body"><strong>页面 inline 改 .btn 高度/字号</strong> — 用 .btn-sm / .btn-lg,不要 inline</div>
</div>
<div class="dodont do">
<span class="head">DO</span>
<div class="body">需要新尺寸 → 先回 restraint.css 加,不污染页面 inline</div>
</div>
</div>
</div>
</section>
<!-- =========================================== §4.2 Pills =========================================== -->
<section id="pills">
<div class="section-head">
<span class="mono-tag">// §4.2 · PILLS</span>
<h2>胶囊 · 严格 3 级分层</h2>
<p><strong style="color:var(--accent-black)">同级别尺寸必须完全一致。</strong>pill 永远是 <code class="tk">999 px</code>(完全圆),靠 dot 体现状态。</p>
</div>
<div class="subsection">
<h3>L1 · 大胶囊 <span class="mono-num">// h:28 / fs:13 / dot:8 · 项目状态 / 列表行主标签</span></h3>
<div class="pill-row">
<span class="pill pill-l1 info"><span class="dot"></span>生成中</span>
<span class="pill pill-l1 ok"><span class="dot"></span>已完成</span>
<span class="pill pill-l1 err"><span class="dot"></span>失败</span>
<span class="pill pill-l1 neutral"><span class="dot"></span>已归档</span>
</div>
</div>
<div class="subsection">
<h3>L2 · 中胶囊 <span class="mono-num">// h:22 / fs:11.5 / dot:6 ★ 默认</span></h3>
<p class="lead">最常用尺寸。卡片内 / 表格内默认。</p>
<div class="pill-row">
<span class="pill pill-l2 info"><span class="dot"></span>生成中</span>
<span class="pill pill-l2 ok"><span class="dot"></span>200 OK</span>
<span class="pill pill-l2 err"><span class="dot"></span>超时</span>
<span class="pill pill-l2 neutral"><span class="dot"></span>已归档</span>
</div>
</div>
<div class="subsection">
<h3>L3 · 小胶囊 <span class="mono-num">// h:18 / fs:10.5 / dot:5 · KPI 角标</span></h3>
<div class="pill-row">
<span class="pill pill-l3 info"><span class="dot"></span>NEW</span>
<span class="pill pill-l3 ok"><span class="dot"></span>+33%</span>
<span class="pill pill-l3 err"><span class="dot"></span>-1.2%</span>
</div>
</div>
<div class="subsection">
<h3>对比 <span class="mono-num">// 同色 3 级并列</span></h3>
<div style="display:flex;gap:14px;align-items:center;flex-wrap:wrap;padding:24px;background:var(--surface);border:1px solid var(--border-faint);border-radius:8px">
<span class="pill pill-l1 info"><span class="dot"></span>L1 · 生成中</span>
<span class="pill pill-l2 info"><span class="dot"></span>L2 · 生成中</span>
<span class="pill pill-l3 info"><span class="dot"></span>L3 · 生成中</span>
</div>
</div>
</section>
<!-- =========================================== §4.3 输入框 =========================================== -->
<section id="inputs">
<div class="section-head">
<span class="mono-tag">// §4.3 · INPUTS</span>
<h2>输入框 · 5 状态</h2>
<p>高 36 px / 圆角 8 / inside-border。focused 时橙色 ring 内嵌 1 px,error 时红边 + 红软底。<strong>点击下面字段看真实 focus 反馈。</strong></p>
</div>
<div class="subsection">
<div class="field-row"><span class="lbl">// default</span><div class="input-wrap"><input class="input" placeholder="搜索商品 / 项目..."/></div></div>
<div class="field-row"><span class="lbl">// focused</span><div class="input-wrap"><input class="input" value="已聚焦" style="border-color:var(--heat-40);box-shadow:inset 0 0 0 1px var(--heat-40)"/></div></div>
<div class="field-row"><span class="lbl">// error</span><div class="input-wrap is-error"><input class="input" value="invalid@example"/></div></div>
<div class="field-row"><span class="lbl">// disabled</span><div class="input-wrap"><input class="input" placeholder="不可编辑" disabled/></div></div>
</div>
<div class="subsection">
<h3>带图标 / 搜索 <span class="mono-num">// 含 Ctrl K 提示</span></h3>
<div class="search-demo">
<svg class="ic-left" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
<input class="input" placeholder="搜索任意内容..."/>
<span class="k">Ctrl K</span>
</div>
<p class="mono" style="margin-top:12px">// 关键坑:左侧 icon 必须 z-index: 2(否则被 input 白底盖住)· Ctrl K 用纯文本不用 ⌘(JetBrains Mono 不带该字形)</p>
</div>
</section>
<!-- =========================================== §4.4 表单控件 =========================================== -->
<section id="form-controls">
<div class="section-head">
<span class="mono-tag">// §4.4 · FORM CONTROLS</span>
<h2>表单控件 · Checkbox / Radio / Switch</h2>
<p>全部用真 SVG indicator,<strong>禁止 border-width / rotate(45deg) 凑对勾</strong>(在缩放/字体渲染下会变形)。<strong>点击下面控件试试。</strong></p>
</div>
<div class="subsection">
<h3>Checkbox</h3>
<div class="ck-row">
<label class="ck"><input type="checkbox"/><span class="ck-box"></span>未选中</label>
<label class="ck"><input type="checkbox" checked/><span class="ck-box"></span>已选中</label>
<label class="ck is-indeterminate"><input type="checkbox"/><span class="ck-box"></span>半选中</label>
<label class="ck is-disabled"><input type="checkbox" disabled/><span class="ck-box"></span>Disabled</label>
</div>
</div>
<div class="subsection">
<h3>Radio</h3>
<div class="ck-row">
<label class="rd"><input type="radio" name="rdemo"/><span class="rd-box"></span>选项 A</label>
<label class="rd"><input type="radio" name="rdemo" checked/><span class="rd-box"></span>选项 B(已选)</label>
<label class="rd"><input type="radio" name="rdemo"/><span class="rd-box"></span>选项 C</label>
<label class="rd" style="opacity:.5;cursor:not-allowed"><input type="radio" disabled/><span class="rd-box"></span>Disabled</label>
</div>
</div>
<div class="subsection">
<h3>Switch</h3>
<div class="ck-row">
<label class="sw"><input type="checkbox"/><span class="sw-box"></span></label>
<label class="sw"><input type="checkbox" checked/><span class="sw-box"></span></label>
<label class="sw is-disabled"><input type="checkbox" disabled/><span class="sw-box"></span>Disabled</label>
</div>
</div>
</section>
<!-- =========================================== §4.5 KPI 统计行 =========================================== -->
<section id="stats">
<div class="section-head">
<span class="mono-tag">// §4.5 · KPI STATS</span>
<h2>KPI 统计行 · 4 格</h2>
<p>1 行 4 格 grid · 共用一个 inside-border 容器 · <strong>无 gap</strong>。列与列之间用 1 px 分隔线。</p>
</div>
<div class="demo-stats">
<div class="cell">
<div class="lbl-row"><span class="lbl">本月营收</span><span class="pill pill-l3 ok"><span class="dot"></span>+33%</span></div>
<div class="num">¥327<small>.40 K</small></div>
<div class="delta"><span class="up">↑ 较上月 +33%</span></div>
</div>
<div class="cell">
<div class="lbl-row"><span class="lbl">活跃项目</span></div>
<div class="num">12</div>
<div class="delta">↑ 本月 +3</div>
</div>
<div class="cell">
<div class="lbl-row"><span class="lbl">生成中</span><span class="pill pill-l3 info"><span class="dot"></span>RUN</span></div>
<div class="num">5</div>
<div class="prog" style="margin-top:8px"><span class="done"></span><span class="done"></span><span class="cur"></span><span></span><span></span></div>
</div>
<div class="cell">
<div class="lbl-row"><span class="lbl">资产总数</span></div>
<div class="num">847</div>
<div class="delta">· MP4 · JPG · PNG</div>
</div>
</div>
</section>
<!-- =========================================== §4.6 进度条 =========================================== -->
<section id="progress">
<div class="section-head">
<span class="mono-tag">// §4.6 · PROGRESS · 5 段流水线专用</span>
<h2>进度条段位</h2>
<p><strong>动 = 在运行,静 = 完成/失败。</strong>脉动只给"进行中"(橙)。已完成绿、失败红、未开始灰。</p>
</div>
<div style="display:flex;gap:24px;flex-wrap:wrap">
<div><div class="prog"><span></span><span></span><span></span><span></span><span></span></div><div class="mono" style="margin-top:6px">未开始</div></div>
<div><div class="prog"><span class="done"></span><span class="done"></span><span class="cur"></span><span></span><span></span></div><div class="mono" style="margin-top:6px">进行中(2/5)· 脉动</div></div>
<div><div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span></div><div class="mono" style="margin-top:6px">已完成</div></div>
<div><div class="prog"><span class="done"></span><span class="fail"></span><span></span><span></span><span></span></div><div class="mono" style="margin-top:6px">失败</div></div>
</div>
</section>
<!-- =========================================== §4.7 列表行 =========================================== -->
<section id="list">
<div class="section-head">
<span class="mono-tag">// §4.7 · LIST ROW</span>
<h2>列表行</h2>
<p>grid: <code class="tk">56px 1fr auto auto auto</code> · gap 22 · padding 20·24。<strong>hover 我看整行底色变化。</strong></p>
</div>
<div class="list-card-demo">
<div class="list-row-demo">
<div class="thumb">9:16</div>
<div class="meta"><div class="ti">夏季新款蕾丝连衣裙</div><div class="sub">// 创建于 05.14 · 蓝色 / M</div></div>
<div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="cur"></span><span></span></div>
<span class="pill pill-l2 info"><span class="dot"></span>生成中</span>
<button class="btn btn-sm">查看</button>
</div>
<div class="list-row-demo">
<div class="thumb">4:5</div>
<div class="meta"><div class="ti">秋季风衣 · 卡其色</div><div class="sub">// 创建于 05.12 · M / L</div></div>
<div class="prog"><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span><span class="done"></span></div>
<span class="pill pill-l2 ok"><span class="dot"></span>已完成</span>
<button class="btn btn-sm">导出</button>
</div>
<div class="list-row-demo">
<div class="thumb">1:1</div>
<div class="meta"><div class="ti">运动 T 恤 · 黑白款</div><div class="sub">// 创建于 05.10 · 全色系</div></div>
<div class="prog"><span class="done"></span><span class="fail"></span><span></span><span></span><span></span></div>
<span class="pill pill-l2 err"><span class="dot"></span>生成失败</span>
<button class="btn btn-sm">重试</button>
</div>
</div>
</section>
<!-- =========================================== §4.8 Tab =========================================== -->
<section id="tabs">
<div class="section-head">
<span class="mono-tag">// §4.8 · TABS</span>
<h2>Tab · 双层结构</h2>
<p>主 Tab 用<strong>下划线激活</strong>(2 px <code class="tk heat">--heat</code> 横线)。副 Tab 用灰度→彩色 icon 反馈。<strong>点击切换。</strong></p>
</div>
<div class="subsection">
<h3>主 Tab</h3>
<div class="ds-tabs" data-tabs>
<button class="ds-tab is-active" data-tab="all">全部</button>
<button class="ds-tab" data-tab="img">商品图</button>
<button class="ds-tab" data-tab="vid">短视频</button>
<button class="ds-tab" data-tab="ad">投放素材</button>
</div>
<div style="padding:20px 24px;background:var(--surface);border:1px solid var(--border-faint);border-radius:8px">当前显示:<span data-tab-content style="color:var(--heat);font-weight:500">全部</span></div>
</div>
<div class="subsection">
<h3>副 Tab · 灰度→彩色</h3>
<div class="ds-subtabs" data-subtabs>
<button class="ds-subtab is-active"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>Search</button>
<div class="ds-subtab-divider"></div>
<button class="ds-subtab"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg>Scrape</button>
<div class="ds-subtab-divider"></div>
<button class="ds-subtab"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>Parse</button>
<div class="ds-subtab-divider"></div>
<button class="ds-subtab"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="3 6 9 3 15 6 21 3 21 18 15 21 9 18 3 21 3 6"/></svg>Map</button>
</div>
</div>
</section>
<!-- =========================================== §4.10 卡片 =========================================== -->
<section id="cards">
<div class="section-head">
<span class="mono-tag">// §4.10 · CARDS</span>
<h2>卡片 / 快捷入口</h2>
<p>所有卡片统一 <code class="tk">8 px 圆角 · 1 px 边框 · 无阴影</code>。快捷入口含 hover / active 状态。</p>
</div>
<div class="subsection">
<h3>快捷入口 <span class="mono-num">// hover 我</span></h3>
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px">
<a href="#" style="display:flex;align-items:center;gap:16px;background:var(--surface);border:1px solid var(--border-faint);border-radius:8px;padding:18px 20px;cursor:pointer;text-decoration:none;color:inherit;transition:background var(--t-base)" onmouseenter="this.style.background='var(--black-alpha-4)'" onmouseleave="this.style.background='var(--surface)'">
<div style="width:32px;height:32px;border-radius:8px;background:var(--heat-12);display:grid;place-items:center;flex-shrink:0"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--heat)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg></div>
<div style="flex:1;min-width:0"><div style="font-size:14px;font-weight:500;color:var(--accent-black);margin-bottom:4px;line-height:1.4">新建商品</div><div class="mono">// AI 生成 / 上传图</div></div>
</a>
<a href="#" style="display:flex;align-items:center;gap:16px;background:var(--surface);border:1px solid var(--border-faint);border-radius:8px;padding:18px 20px;cursor:pointer;text-decoration:none;color:inherit;transition:background var(--t-base)" onmouseenter="this.style.background='var(--black-alpha-4)'" onmouseleave="this.style.background='var(--surface)'">
<div style="width:32px;height:32px;border-radius:8px;background:var(--heat-12);display:grid;place-items:center;flex-shrink:0"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--heat)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="20" height="12" rx="2"/><path d="m10 9 5 3-5 3z" fill="currentColor"/></svg></div>
<div style="flex:1;min-width:0"><div style="font-size:14px;font-weight:500;color:var(--accent-black);margin-bottom:4px;line-height:1.4">短视频工坊</div><div class="mono">// 9:16 · MP4</div></div>
</a>
<a href="#" style="display:flex;align-items:center;gap:16px;background:var(--surface);border:1px solid var(--border-faint);border-radius:8px;padding:18px 20px;cursor:pointer;text-decoration:none;color:inherit;transition:background var(--t-base)" onmouseenter="this.style.background='var(--black-alpha-4)'" onmouseleave="this.style.background='var(--surface)'">
<div style="width:32px;height:32px;border-radius:8px;background:var(--heat-12);display:grid;place-items:center;flex-shrink:0"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--heat)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></div>
<div style="flex:1;min-width:0"><div style="font-size:14px;font-weight:500;color:var(--accent-black);margin-bottom:4px;line-height:1.4">投放话术库</div><div class="mono">// /v2 · 模板</div></div>
</a>
</div>
</div>
</section>
<!-- =========================================== §4.10 提示框 =========================================== -->
<section id="tip">
<div class="section-head">
<span class="mono-tag">// §4.10 · TIP</span>
<h2>提示框</h2>
<p>白底 · 1 px 虚线边框(<code class="tk">dashed</code>)· 8 px 圆角 · 加粗标题 + 正文。</p>
</div>
<div class="tip-demo">
<div class="head">小提示</div>
<div class="body">使用 <span class="mono-code">Ctrl K</span> 快速搜索任意项目、商品或资产。Tab 切换不同维度,Enter 直达。</div>
</div>
</section>
<!-- =========================================== §4.11 Modal =========================================== -->
<section id="modal">
<div class="section-head">
<span class="mono-tag">// §4.11 · MODAL</span>
<h2>弹窗 Modal</h2>
<p>居中 460480 px · 4 角 SVG 准星 · 8 px 圆角 · <code class="tk">backdrop-filter: blur(8px)</code> · 弹性入场。<strong>点击下方按钮打开 · ESC / 点击遮罩关闭。</strong></p>
</div>
<button class="btn btn-primary" id="open-modal">打开 Modal Demo</button>
</section>
<!-- =========================================== §4.11 Toast =========================================== -->
<section id="toast">
<div class="section-head">
<span class="mono-tag">// §4.11 · TOAST</span>
<h2>Toast 通知</h2>
<p>右下角浮出 · 300ms 弹性入场 · 2400ms 自动消失。<strong>触发演示:</strong></p>
</div>
<div style="display:flex;gap:10px;flex-wrap:wrap">
<button class="btn" data-toast='{"ti":"项目已保存","sub":"// 200 OK · /projects/12"}'>触发默认 Toast</button>
<button class="btn btn-primary" data-toast='{"ti":"商品生成完成","sub":"// 4 张待审核 · 02:34"}'>主 CTA Toast</button>
</div>
</section>
<!-- =========================================== §4.13 AI 对话面板 =========================================== -->
<section id="chat">
<div class="section-head">
<span class="mono-tag">// §4.13 · CHAT · AI 对话面板</span>
<h2>AI 对话面板</h2>
<p>编辑器型页面专用(AI 图片创作 / 流水线 AI 助手 / 商品 AI 优化 / 镜头脚本)。<strong>3 个编辑器页定义一致</strong>,已成事实组件 — 应抽到 restraint.css。</p>
</div>
<div class="subsection">
<h3>完整对话面板 <span class="mono-num">// .chat-pane · 试在输入框打字看 focus 反馈</span></h3>
<div class="chat-pane">
<div class="pane-h">
<span class="ic-box"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 8V4H8M4 12h16M16 4v4M4 8a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z"/><path d="M9 13v-1M15 13v-1"/></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="ts">// 14:30</div>
</div>
<div class="msg user">
<div class="bubble">把背景换成咖啡厅,加暖色光线</div>
<div class="ts">// 14:32</div>
</div>
<div class="msg ai">
<div class="bubble">收到,正在生成 4 个候选...</div>
<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 帮我..." rows="2"></textarea>
<div class="chat-input-actions">
<button class="btn btn-sm btn-ghost"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>附件</button>
<button class="btn btn-sm btn-primary">发送 →</button>
</div>
</div>
</div>
</div>
</div>
<div class="subsection">
<h3>消息气泡规则 <span class="mono-num">// .msg.ai vs .msg.user</span></h3>
<table class="audit-table">
<thead><tr><th>类型</th><th>对齐</th><th>气泡背景</th><th>气泡边框</th></tr></thead>
<tbody>
<tr><td><code class="tk">.msg.ai</code></td><td>左对齐(默认)</td><td><code class="tk">--surface</code></td><td><code class="tk">--border-faint</code></td></tr>
<tr><td><code class="tk">.msg.user</code></td><td>右对齐(<code class="tk">flex-end</code>)</td><td><code class="tk heat">--heat-12</code> 浅橙</td><td><code class="tk heat">--heat-20</code></td></tr>
</tbody>
</table>
<p class="mono" style="margin-top:8px">// 所有气泡共享:max-width 90% / padding 10·14 / font 13 / line-height 1.6 / radius 8 · 时间戳放气泡下用 mono 11px / alpha-48</p>
</div>
<div class="subsection">
<h3>打字指示器 <span class="mono-num">// .ai-thinking · 1.2s 交替闪烁</span></h3>
<div style="display:flex;align-items:center;gap:14px;background:var(--surface);border:1px solid var(--border-faint);border-radius:8px;padding:14px 18px">
<span>AI 正在思考</span>
<span class="ai-thinking"><span class="dots"><span></span><span></span><span></span></span></span>
</div>
</div>
</section>
<!-- =========================================== §4.14 商品 / 资产卡片体系 =========================================== -->
<section id="card-system">
<div class="section-head">
<span class="mono-tag">// §4.14 · CARD SYSTEM · 商品 / 资产卡片三种形态</span>
<h2>商品 / 资产卡片体系</h2>
<p><strong style="color:var(--accent-black)">商品 + 资产 + 人物 + 场景共用一套卡片体系。</strong>按"使用场景"选形态,<strong style="color:var(--accent-crimson)">不要为每种内容类型做新类</strong></p>
</div>
<div class="subsection">
<h3>三种形态对照 <span class="mono-num">// 选谁?看场景</span></h3>
<table class="audit-table">
<thead><tr><th>形态</th><th>类名</th><th>缩图比</th><th>缩图宽度</th><th>使用场景</th></tr></thead>
<tbody>
<tr><td style="color:var(--accent-black);font-weight:500">网格主卡</td><td class="now">.product-card</td><td>1.4:1 / 1:1 / 3:4</td><td>自适应宽</td><td>商品库 / 资产库 / 主网格</td></tr>
<tr><td style="color:var(--accent-black);font-weight:500">行卡(列表)</td><td class="now">.prod-row / .mp-prod-item</td><td>1:1</td><td>2836 px</td><td>表单已选行 / 侧栏列表</td></tr>
<tr><td style="color:var(--accent-black);font-weight:500">选择器卡</td><td class="now">.pl-card / .opt-card</td><td>1:1 或 3:4</td><td>100160 px</td><td>Modal 内多选 picker</td></tr>
</tbody>
</table>
</div>
<div class="subsection">
<h3>形态 1 · 网格主卡 <span class="mono-num">// .product-card · 主网格用</span></h3>
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px">
<div class="product-card">
<div class="product-thumb placeholder"><span class="ph-frame">9:16</span></div>
<div class="product-body">
<div class="product-name">夏季新款蕾丝连衣裙</div>
<div class="product-cat">// 女装 · 蓝色</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>
<div class="product-card">
<div class="product-thumb placeholder"><span class="ph-frame">9:16</span></div>
<div class="product-body">
<div class="product-name">秋季风衣 · 卡其色</div>
<div class="product-cat">// 女装 · M / L</div>
</div>
<div class="product-footer">
<span class="stat">素材 <b>67</b></span>
<span class="sep">·</span>
<span class="stat">视频 <b>12</b></span>
</div>
</div>
<div class="product-card">
<div class="product-thumb placeholder"><span class="ph-frame">9:16</span></div>
<div class="product-body">
<div class="product-name">运动 T 恤 · 黑白款</div>
<div class="product-cat">// 男女同款</div>
</div>
<div class="product-footer">
<span class="stat">素材 <b>89</b></span>
<span class="sep">·</span>
<span class="stat">视频 <b>23</b></span>
</div>
</div>
</div>
<p class="mono" style="margin-top:12px">// 缩图比例按内容类型选 · 商品 1.4:1(.product-thumb 默认)· 资产 1:1(加 .r-square)· 人物 3:4(加 .r-portrait)</p>
</div>
<div class="subsection">
<h3>形态 2 · 行卡 <span class="mono-num">// .prod-row · 表单 / 侧栏用</span></h3>
<div style="display:flex;flex-direction:column;gap:6px;max-width:380px">
<div class="prod-row">
<div class="thumb">9:16</div>
<div class="nm">夏季新款蕾丝连衣裙</div>
<button class="row-x"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
</div>
<div class="prod-row">
<div class="thumb">4:5</div>
<div class="nm">秋季风衣 · 卡其色</div>
<button class="row-x"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
</div>
</div>
<p class="mono" style="margin-top:12px">// hover 右侧 X 变红 · 用于"已选商品"列表 / 流水线 stage 选中态</p>
</div>
<div class="subsection">
<h3>形态 3 · 选择器卡 <span class="mono-num">// .pl-card · Modal 多选 picker · 点击切换 selected</span></h3>
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:10px;background:var(--background-base);padding:16px;border:1px solid var(--border-faint);border-radius:8px" data-pl-group>
<div class="pl-card" data-pl><div class="pl-thumb">1:1</div><div class="pl-name">商品 A</div><div class="pl-check"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div></div>
<div class="pl-card selected" data-pl><div class="pl-thumb">1:1</div><div class="pl-name">商品 B(已选)</div><div class="pl-check"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div></div>
<div class="pl-card selected" data-pl><div class="pl-thumb">1:1</div><div class="pl-name">商品 C(已选)</div><div class="pl-check"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div></div>
<div class="pl-card" data-pl><div class="pl-thumb">1:1</div><div class="pl-name">商品 D</div><div class="pl-check"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div></div>
<div class="pl-card" data-pl><div class="pl-thumb">1:1</div><div class="pl-name">商品 E</div><div class="pl-check"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div></div>
</div>
<p class="mono" style="margin-top:12px">// 3 种状态:默认浅灰 / hover 变白 / selected 橙边 + 浅橙底 + 右上勾</p>
</div>
</section>
<!-- =========================================== §4.15 人物模特卡 =========================================== -->
<section id="model-card">
<div class="section-head">
<span class="mono-tag">// §4.15 · MODEL CARD · 人物 / 演员 / 模特卡</span>
<h2>人物 / 演员 / 模特卡</h2>
<p>选择器卡的"人物 3:4 竖图"特例。<strong>复用 .pl-card 的选中态逻辑</strong>,只换缩图比例为 3:4。<strong>点击切换</strong>:</p>
</div>
<div class="subsection">
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:10px;background:var(--background-base);padding:16px;border:1px solid var(--border-faint);border-radius:8px" data-pl-group>
<div class="model-card" data-pl>
<div class="m-thumb">3:4</div>
<div class="m-name">林夏 · 25 岁</div>
<div class="m-meta">// 165cm · 都市风</div>
<div class="pl-check"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div>
</div>
<div class="model-card selected" data-pl>
<div class="m-thumb">3:4</div>
<div class="m-name">陈宇 · 28 岁(已选)</div>
<div class="m-meta">// 178cm · 商务休闲</div>
<div class="pl-check"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div>
</div>
<div class="model-card" data-pl>
<div class="m-thumb">3:4</div>
<div class="m-name">王悦 · 22 岁</div>
<div class="m-meta">// 168cm · 学院风</div>
<div class="pl-check"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div>
</div>
<div class="model-card" data-pl>
<div class="m-thumb">3:4</div>
<div class="m-name">张涛 · 30 岁</div>
<div class="m-meta">// 180cm · 运动型</div>
<div class="pl-check"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div>
</div>
</div>
<p class="mono" style="margin-top:12px">// 跟 .pl-card 同基础 · 只是 .m-thumb 用 aspect-ratio: 3/4(人物竖图标准) · 多了 .m-meta 行</p>
</div>
</section>
<!-- =========================================== §4.16 场景卡 =========================================== -->
<section id="scene-card">
<div class="section-head">
<span class="mono-tag">// §4.16 · SCENE CARD · 场景卡(复用 asset-card-2)</span>
<h2>场景 / 通用资产卡</h2>
<p>场景卡 = 资产卡的"1:1 通用"形态。<strong style="color:var(--accent-crimson)">不要做新类</strong>,派生类(`.scene-card / .person-card / .background-card`)只语义命名,样式继承 `.asset-card-2`。</p>
</div>
<div class="subsection">
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:14px">
<div class="asset-card-2 scene-card">
<div class="thumb-2">1:1</div>
<div class="body-2">
<div class="ti">咖啡厅 · 暖光</div>
<div class="sub">// indoor · warm</div>
</div>
</div>
<div class="asset-card-2 scene-card">
<div class="thumb-2">1:1</div>
<div class="body-2">
<div class="ti">街头 · 黄昏</div>
<div class="sub">// outdoor · sunset</div>
</div>
</div>
<div class="asset-card-2 scene-card">
<div class="thumb-2">1:1</div>
<div class="body-2">
<div class="ti">极简白底</div>
<div class="sub">// studio · pure</div>
</div>
</div>
<div class="asset-card-2 scene-card">
<div class="thumb-2">1:1</div>
<div class="body-2">
<div class="ti">海滩 · 蓝调</div>
<div class="sub">// outdoor · cool</div>
</div>
</div>
</div>
<p class="mono" style="margin-top:12px">// hover 边变橙 + 浅阴影 · 通常宽 240px(可放在 flex 横滑容器里) · 同样 class 也用于素材库 / 人物库 通用卡</p>
</div>
</section>
<!-- =========================================== §4.17 高频组件 =========================================== -->
<section id="freq">
<div class="section-head">
<span class="mono-tag">// §4.17 · FREQUENT · 其他高频复用组件</span>
<h2>其他高频复用组件</h2>
<p>以下组件已在 25 个页面重复定义,需要尽快抽到 restraint.css。在此先做规范展示。</p>
</div>
<div class="subsection">
<h3>§4.17.1 流程步骤条 <span class="mono-num">// .stepper · 大尺寸主流程</span></h3>
<div class="stepper">
<div class="stage-step done"><span class="num">1</span><span class="lbl">商品</span></div>
<div class="stepper-line"></div>
<div class="stage-step done"><span class="num">2</span><span class="lbl">故事板</span></div>
<div class="stepper-line"></div>
<div class="stage-step active"><span class="num">3</span><span class="lbl">镜头</span></div>
<div class="stepper-line"></div>
<div class="stage-step"><span class="num">4</span><span class="lbl">生成</span></div>
<div class="stepper-line"></div>
<div class="stage-step"><span class="num">5</span><span class="lbl">投放</span></div>
</div>
<p class="mono" style="margin-top:12px">// 已完成:黑底白字 · 进行中:橙底白字 + 600 字重 · 未开始:白底灰字 · 与 .prog 区别:.prog 是小徽标横在卡片角,.stepper 是大尺寸主流程</p>
</div>
<div class="subsection">
<h3>§4.17.2 分页 <span class="mono-num">// .pagination · sticky bottom</span></h3>
<div class="pagination-demo">
<span class="total"><b>247</b></span>
<button class="page-size">12 条/页 ▾</button>
<span class="pages">
<button></button>
<button>1</button>
<button class="active">2</button>
<button>3</button>
<button>4</button>
<button></button>
</span>
<span class="jump">跳至 <input type="number" value="2"></span>
</div>
<p class="mono" style="margin-top:12px">// 激活页用橙底白字 600 · 页码按钮 30×30 / 4 px 圆角(密集场景小圆角不破节奏)</p>
</div>
<div class="subsection">
<h3>§4.17.3 视图切换 <span class="mono-num">// .view-toggle · 模式切换组</span></h3>
<div style="display:flex;gap:14px;align-items:center;flex-wrap:wrap">
<div class="view-toggle" data-vt>
<button class="active" data-v="grid"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></svg></button>
<button data-v="list"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg></button>
</div>
<span class="mono">// 当前 <b style="color:var(--accent-black)" data-vt-cur>grid</b> 视图 · 点击切换</span>
</div>
<div class="dodont-grid" style="margin-top:14px">
<div class="dodont do">
<span class="head">DO</span>
<div class="body">激活态用 <code class="tk">--accent-black</code> 黑底白字 · 模式开关不抢主橙的舞台</div>
</div>
<div class="dodont dont">
<span class="head">DON'T</span>
<div class="body">用橙底 — 视图切换不是 CTA,用了橙就跟主操作按钮抢戏</div>
</div>
</div>
</div>
<div class="subsection">
<h3>§4.17.4 操作型胶囊 <span class="mono-num">// .pill-tip · 可点击的链接式 CTA</span></h3>
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center">
<button class="pill-tip">→ 去商品库</button>
<button class="pill-tip">+ 新建模板</button>
<button class="pill-tip">查看 4 条候选 →</button>
</div>
<p class="mono" style="margin-top:12px">// hover 时 bg → 橙 / 字 → 白 + shadow-cta · 与 .pill.info(静态状态徽标)区别:.pill-tip 是可点击操作</p>
</div>
<div class="subsection">
<h3>§4.17.5 卖点 / 编辑式列表 <span class="mono-num">// .bullet-list · 表单常用</span></h3>
<ul class="bullet-list-demo" style="max-width:480px">
<li class="bl-item">
<span class="num">1</span>
<span class="bl-text">100% 棉麻 · 透气吸汗</span>
<button class="bl-x"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
</li>
<li class="bl-item">
<span class="num">2</span>
<span class="bl-text">独家设计 · 限量 200 件</span>
<button class="bl-x"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
</li>
<li class="bl-item">
<span class="num">3</span>
<span class="bl-text">隐形拉链 · 显瘦剪裁</span>
<button class="bl-x"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
</li>
<li class="bl-add">
<span class="num">+</span>
<input class="bl-input" placeholder="添加卖点(Enter 确认)">
</li>
</ul>
<p class="mono" style="margin-top:12px">// 序号 .num 22×22 mono 700 字色 heat · 最后一行 .bl-add 用 dashed 虚线区别于已添加项 · hover 时删除按钮显示</p>
</div>
</section>
<!-- =========================================== §4.18 AI 生成结果卡 =========================================== -->
<section id="gen-card">
<div class="section-head">
<span class="mono-tag">// §4.18 · GEN CARD · AI 生成结果卡</span>
<h2>AI 生成结果卡</h2>
<p>用于"输入提示词 → 多候选输出"场景(AI 图片 / 视频创作 · 模板生成 · 批量预览)。<strong style="color:var(--accent-black)">三个可变接口:① 图片比例 ② 悬浮按钮 ③ 底部按钮</strong>,其他全部复用。</p>
</div>
<div class="subsection">
<h3>完整示例 <span class="mono-num">// hover 图片看右上浮层 · 点击图片看中央反馈 toast</span></h3>
<!-- 默认 1:1 / 4 列 / 3 张悬浮按钮 / 3 个底部按钮 -->
<div class="gen-card">
<!-- ① Prompt -->
<div class="gen-prompt">
<svg class="quote" viewBox="0 0 24 24" fill="currentColor"><path d="M6 17h3l2-4V7H5v6h3l-2 4zm8 0h3l2-4V7h-6v6h3l-2 4z"/></svg>
<span class="text">一只穿着宇航服的橘猫,漂浮在霓虹色星云中,赛博朋克风</span>
</div>
<!-- ② Meta -->
<div class="gen-meta">
<span class="m-item">流·Studio 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>
<!-- ③ 图片网格 · 4 张 1:1 -->
<div class="gen-images" style="--cols:4; --ratio: 1/1" data-gen-grid>
<div class="gen-image">
<div class="placeholder"><span class="ph-frame">1:1 · #1</span></div>
<div class="gen-image-actions">
<button class="gen-img-btn" title="重新生成"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 15.4-6.4M21 4v5h-5"/><path d="M21 12a9 9 0 0 1-15.4 6.4M3 20v-5h5"/></svg></button>
<button class="gen-img-btn" title="下载"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg></button>
<button class="gen-img-btn" title="更多"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg></button>
</div>
<div class="gen-image-feedback">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
<span>已添加到剪贴板</span>
</div>
</div>
<div class="gen-image">
<div class="placeholder"><span class="ph-frame">1:1 · #2</span></div>
<div class="gen-image-actions">
<button class="gen-img-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 15.4-6.4M21 4v5h-5"/><path d="M21 12a9 9 0 0 1-15.4 6.4M3 20v-5h5"/></svg></button>
<button class="gen-img-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg></button>
<button class="gen-img-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg></button>
</div>
<div class="gen-image-feedback">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
<span>已添加到剪贴板</span>
</div>
</div>
<div class="gen-image">
<div class="placeholder"><span class="ph-frame">1:1 · #3</span></div>
<div class="gen-image-actions">
<button class="gen-img-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 15.4-6.4M21 4v5h-5"/><path d="M21 12a9 9 0 0 1-15.4 6.4M3 20v-5h5"/></svg></button>
<button class="gen-img-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg></button>
<button class="gen-img-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg></button>
</div>
<div class="gen-image-feedback">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
<span>已添加到剪贴板</span>
</div>
</div>
<div class="gen-image">
<div class="placeholder"><span class="ph-frame">1:1 · #4</span></div>
<div class="gen-image-actions">
<button class="gen-img-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 15.4-6.4M21 4v5h-5"/><path d="M21 12a9 9 0 0 1-15.4 6.4M3 20v-5h5"/></svg></button>
<button class="gen-img-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg></button>
<button class="gen-img-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg></button>
</div>
<div class="gen-image-feedback">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
<span>已添加到剪贴板</span>
</div>
</div>
</div>
<!-- ④ 底部按钮 -->
<div class="gen-card-actions">
<button class="btn btn-sm"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4z"/></svg>重新编辑</button>
<button class="btn btn-sm"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 15.4-6.4M21 4v5h-5"/><path d="M21 12a9 9 0 0 1-15.4 6.4M3 20v-5h5"/></svg>再次生成</button>
<button class="btn btn-sm btn-ghost"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg></button>
</div>
</div>
</div>
<div class="subsection">
<h3>变体 · 9:16 竖图 / 2 列 <span class="mono-num">// --ratio: 9/16 --cols: 2</span></h3>
<div class="gen-card" style="max-width:560px">
<div class="gen-prompt">
<svg class="quote" viewBox="0 0 24 24" fill="currentColor"><path d="M6 17h3l2-4V7H5v6h3l-2 4zm8 0h3l2-4V7h-6v6h3l-2 4z"/></svg>
<span class="text">东方美人 · 古典园林背景 · 短视频 9:16</span>
</div>
<div class="gen-meta">
<span class="m-item">流·Studio v2</span>
<span class="m-sep">|</span>
<span class="m-item">9:16</span>
<span class="m-sep">|</span>
<span class="m-item">2K · 刚刚</span>
</div>
<div class="gen-images" style="--cols:2; --ratio: 9/16" data-gen-grid>
<div class="gen-image">
<div class="placeholder"><span class="ph-frame">9:16 · #1</span></div>
<div class="gen-image-actions">
<button class="gen-img-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg></button>
<button class="gen-img-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8M16 6l-4-4-4 4M12 2v13"/></svg></button>
</div>
<div class="gen-image-feedback">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
<span>已收藏</span>
</div>
</div>
<div class="gen-image">
<div class="placeholder"><span class="ph-frame">9:16 · #2</span></div>
<div class="gen-image-actions">
<button class="gen-img-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg></button>
<button class="gen-img-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8M16 6l-4-4-4 4M12 2v13"/></svg></button>
</div>
<div class="gen-image-feedback">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
<span>已收藏</span>
</div>
</div>
</div>
<div class="gen-card-actions">
<button class="btn btn-sm">编辑分镜</button>
<button class="btn btn-sm">导出 MP4</button>
<button class="btn btn-sm btn-ghost"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg></button>
</div>
</div>
<p class="mono" style="margin-top:12px">// 切换 --ratio 和 --cols 即可适配视频 9:16 / 横屏 16:9 / 海报 4:5 / 头像 1:1 · 悬浮按钮和底部按钮按业务定制</p>
</div>
<div class="subsection">
<h3>三个可变接口对照 <span class="mono-num">// 决策表</span></h3>
<table class="audit-table">
<thead><tr><th>维度</th><th>怎么变</th><th>典型场景</th></tr></thead>
<tbody>
<tr><td style="color:var(--accent-black);font-weight:500">① 图片比例</td><td class="now">style="--ratio: 9/16; --cols: 2"</td><td>1:1 头像 · 9:16 短视频 · 16:9 横屏 · 4:5 海报</td></tr>
<tr><td style="color:var(--accent-black);font-weight:500">② 悬浮按钮</td><td class="now">.gen-image-actions 内放 14 个 .gen-img-btn</td><td>重新生成 · 下载 · 收藏 · 分享 · 用作参考 · 更多 ···</td></tr>
<tr><td style="color:var(--accent-black);font-weight:500">③ 底部按钮</td><td class="now">.gen-card-actions 内放 .btn-sm</td><td>重新编辑 · 再次生成 · 编辑分镜 · 导出 · 更多 ···</td></tr>
</tbody>
</table>
</div>
<div class="subsection">
<h3>Don't <span class="mono-num">// 常见错误</span></h3>
<div style="background:var(--surface);border:1px solid var(--border-faint);border-radius:8px;padding:18px 22px">
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">悬浮按钮放图片底部</strong> · 永远放右上(避免遮挡图片主体)</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">用全局 toast 通知"已复制"</strong> · 用本组件内的 .gen-image-feedback(就地反馈,用户不必转头看屏幕角落)</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">把 prompt 文字截断省略</strong> · 完整显示 — 它就是用户的输入,要看清</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">底部按钮做成主橙 primary</strong> · 抢了 prompt 视觉重心,用二级 .btn 即可</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">给每个图片单独写卡样式</strong> · 用 .gen-image 通用 · 比例靠 --ratio CSS 变量切换</span></div>
</div>
</div>
</section>
<!-- =========================================== §5 Mono 装饰 =========================================== -->
<section id="mono-decor">
<div class="section-head">
<span class="mono-tag">// §5 · MONO DECOR · 品牌签名</span>
<h2>Mono 装饰元素</h2>
<p>方括号标签 / 双斜杠注释 / 中点连接 —— 这些是流·Studio 独有的"调试视图感",<strong>Firecrawl 没有,绝对保留</strong></p>
</div>
<div class="subsection">
<h3>方括号标签</h3>
<div class="mono-sample-row">
<span class="mono-tag-sample">[ 200 OK ]</span>
<span class="mono-tag-sample">[ /v2 ]</span>
<span class="mono-tag-sample">[ .MP4 · 9:16 ]</span>
<span class="mono-tag-sample heat">[ STUDIO ]</span>
<span class="mono-tag-sample">[ ALL · 12 ] →</span>
</div>
</div>
<div class="subsection">
<h3>注释样式时间戳</h3>
<div class="mono" style="font-size:13px">// 05.14 · 周五 · 14:32</div>
</div>
<div class="subsection">
<h3>命令路径</h3>
<div class="mono" style="font-size:13px;color:var(--black-alpha-64)">/sidebar collapse · /toast dismiss · /modal open</div>
</div>
<div class="subsection">
<h3>数值后缀</h3>
<div style="font-size:32px;font-weight:500;letter-spacing:-.02em;font-variant-numeric:tabular-nums;color:var(--accent-black)">¥327<small style="font-size:15px;color:var(--black-alpha-48);font-weight:400">.40 K</small></div>
<p class="mono" style="margin-top:8px">// 主体大字 + 小字次级用 &lt;small&gt;</p>
</div>
<div class="subsection">
<h3>ASCII 散点(背景装饰)</h3>
<div style="font-family:var(--font-mono);font-size:11px;color:var(--black-alpha-12);line-height:1.4;letter-spacing:.04em;background:var(--surface);border:1px solid var(--border-faint);border-radius:8px;padding:18px 22px">
· · &nbsp;+<br>
·&nbsp; +XX+<br>
&nbsp;+XXXX·<br>
&nbsp;&nbsp; +X·
</div>
</div>
<div class="subsection">
<h3>强调单词上色</h3>
<p style="font-size:13.5px;color:var(--black-alpha-72);max-width:680px;line-height:1.7">
本月营收较上月增长 <b style="color:var(--accent-black)">+33%</b>,有 <b style="color:var(--accent-black)">5 个项目</b>处于"生成中"状态。其中 <b style="color:var(--accent-black)">2 个</b>需要重新调整模特模板。
</p>
<p class="mono" style="margin-top:8px">// 关键名词加深一档(不变橙),橙色只留给 CTA</p>
</div>
</section>
<!-- =========================================== §6 五种页面布局 =========================================== -->
<section id="layouts">
<div class="section-head">
<span class="mono-tag">// §6 · LAYOUT MODES · 5 种</span>
<h2>五种页面级布局模式</h2>
<p>页面骨架统一,<strong>内容区布局按用途分 5 类</strong>。新页面归类后选对应模式。</p>
</div>
<div class="subsection">
<div class="layout-card">
<div class="h"><span class="tag">A</span><span class="ti">看板型 · Dashboard</span></div>
<div class="desc">KPI 行 + 多个 section + 列表行 / shortcut 网格。</div>
<pre class="ascii">[ stats.with-corners · KPI 4 列 ]
[ section-h ]
[ ░░ recent-row × N ░░ ] [ shortcut × N ]
[ tip · 虚线提示 ]</pre>
<div class="pages">代表页:<strong>index.html · projects.html(列表)· library.html</strong></div>
</div>
<div class="layout-card">
<div class="h"><span class="tag">B</span><span class="ti">列表 + 筛选型 · List + Filter</span></div>
<div class="desc">Toolbar(搜索 + chip 筛选 + 视图切换)+ 卡片网格 + 分页 + 批量栏。</div>
<pre class="ascii">[ toolbar: search-inline + chip-wrap × n + view-toggle ] sticky top
[ result-meta · 共 N 条 ]
[ ░░ 卡片网格 / 列表 ░░ ]
[ pagination ] sticky bottom
[ bulk-bar(选中后显示) ] 吸底浮动</pre>
<div class="pages">代表页:<strong>products.html · projects.html · library.html · team.html</strong></div>
</div>
<div class="layout-card">
<div class="h"><span class="tag">C</span><span class="ti">编辑器型 · Editor / IDE</span></div>
<div class="desc">锁视口高度 · 多栏内部滚 · 大量页面级独有样式。<strong style="color:var(--accent-crimson)">⚠️ 这类定制最多 · 改之前先确认 restraint.css 没现成组件</strong></div>
<pre class="ascii">[ 左栏 · 资产/导航 sticky ] [ 中央 · 画布/参数 ] [ 右栏 · 预览/AI 助手 ]
└───────── 整页 viewport 高度锁定 · 不滚 main ────────┘</pre>
<div class="pages">代表页:<strong>pipeline.html · model-photo.html · image-optimize.html · studio.html</strong></div>
</div>
<div class="layout-card">
<div class="h"><span class="tag">D</span><span class="ti">表单 / 向导型 · Wizard / Form</span></div>
<div class="desc">左侧 sticky 步数条 + 右侧多 pane 同时显示(非 Tab 切换)。</div>
<pre class="ascii">[ .wizard ]
├─ .steps · 200 px sticky ← 左步数条
└─ .panes · 1fr ← 右滚
├─ .wiz-pane #step-1
├─ .wiz-pane #step-2
└─ .wiz-pane #step-3</pre>
<div class="pages">代表页:<strong>projects-new.html · products.html drawer · account.html · settings.html</strong></div>
</div>
<div class="layout-card">
<div class="h"><span class="tag">E</span><span class="ti">单卡型 · Single Screen</span></div>
<div class="desc">不渲染 sidebar/topbar · 全屏灰底 + 中心白卡。</div>
<pre class="ascii"> ┌─────────────────┐
│ │
│ .input × N │
│ .btn-primary │
│ │
└─────────────────┘</pre>
<div class="pages">代表页:<strong>login.html · register.html</strong></div>
</div>
</div>
</section>
<!-- =========================================== §7 待统一清单 =========================================== -->
<section id="audit">
<div class="section-head">
<span class="mono-tag">// §7 · AUDIT · V2.1 落地待统一清单 ★</span>
<h2>待统一清单</h2>
<p>扫完 18 个 HTML 发现的偏离点。按影响视觉一致性程度排序。<strong>改页面时遇到这些点,顺手改正。</strong></p>
</div>
<div class="subsection">
<span class="audit-section-label hi">// 高优先级 · 影响视觉对齐</span>
<table class="audit-table">
<thead><tr><th>#</th><th>问题</th><th>现状</th><th>应改为</th></tr></thead>
<tbody>
<tr><td>1</td><td class="problem">按钮等级混乱 ★</td><td class="now">各页随意选 .btn / .btn-primary / .btn-ghost,部分页面 2 个一级橙并列,"取消"被做成主橙;尺寸也乱(38/32/44 混)</td><td class="should">按 §4.1 三级体系:一个区域只 1 个一级(主动作) · 二级(并列动作) · 三级(辅助) · 尺寸默认 36 / lg 40 / sm 28</td></tr>
<tr><td>2</td><td class="problem">输入框高度</td><td class="now">products 38 / projects search 32 / login 36</td><td class="should">统一 36</td></tr>
<tr><td>3</td><td class="problem">Tab 激活样式</td><td class="now">product-detail 下划线 / library 底色填充</td><td class="should">统一下划线 + bottom 2 px heat</td></tr>
<tr><td>4</td><td class="problem">Hover 底色</td><td class="now">多数 bg-lighter / 部分 black-alpha-4</td><td class="should">统一 black-alpha-4</td></tr>
<tr><td>5</td><td class="problem">卡片标题字号</td><td class="now">projects 13.5 / products 14</td><td class="should">统一 14 / 500</td></tr>
<tr><td>6</td><td class="problem">卡片网格列宽</td><td class="now">products 240 / library auto 180 / projects-new 4 列</td><td class="should">商品 240 · 资产 180 · 通用 auto-fill 220</td></tr>
</tbody>
</table>
</div>
<div class="subsection">
<span class="audit-section-label mid">// 中优先级 · 语义偏离</span>
<table class="audit-table">
<thead><tr><th>#</th><th>问题</th><th>现状</th><th>应改为</th></tr></thead>
<tbody>
<tr><td>7</td><td class="problem">Pill 变体不全</td><td class="now">restraint.css 4 种 / library 用了 .pill.archive 没定义</td><td class="should">补 .pill.archive(灰)/ .pill.warn(honey)</td></tr>
<tr><td>8</td><td class="problem">X 关闭按钮</td><td class="now">drawer 30 / modal 32 / toast 28</td><td class="should">统一 32×32 / 8 px 圆角</td></tr>
<tr><td>9</td><td class="problem">label 字重</td><td class="now">products 500 / product-detail 600</td><td class="should">统一 500</td></tr>
<tr><td>10</td><td class="problem">mono 装饰</td><td class="now">部分页有 4 角 [ 200 OK ],部分没</td><td class="should">主工作台型必有 · 编辑器型可省</td></tr>
<tr><td>11</td><td class="problem">section-h 分隔</td><td class="now">部分 border-bottom / 部分没</td><td class="should">统一不用(留白即分隔)</td></tr>
</tbody>
</table>
</div>
<div class="subsection">
<span class="audit-section-label lo">// 低优先级 · 架构清理</span>
<table class="audit-table">
<thead><tr><th>#</th><th>问题</th><th>现状</th><th>应改为</th></tr></thead>
<tbody>
<tr><td>12</td><td class="problem">编辑器页 inline style 过大</td><td class="now">pipeline 795 / model-photo 1393 / platform-cover 1003 行</td><td class="should">抽 .stepper / .shot-card 到 restraint.css 或 editor.css</td></tr>
<tr><td>13</td><td class="problem">四角准星重复 SVG</td><td class="now">部分页定义自己的 SVG 背景</td><td class="should">全部改用 .with-corners + .corner-tr/.corner-bl</td></tr>
<tr><td>14</td><td class="problem">滚动条样式残留</td><td class="now">部分页 inline scrollbar-width: thin</td><td class="should">restraint.css 已全局隐藏 · 清理 inline</td></tr>
<tr><td>15</td><td class="problem">mono 字体里的中文</td><td class="now">部分页直接写 font-family: monospace</td><td class="should">全部换 var(--font-mono)</td></tr>
</tbody>
</table>
</div>
</section>
<!-- =========================================== §8 Don't List =========================================== -->
<section id="dont">
<div class="section-head">
<span class="mono-tag">// §8 · GUARDRAILS</span>
<h2>Don't List · 绝对禁止</h2>
<p>任何 mockup / 代码 review 时,对照此清单。<strong style="color:var(--accent-crimson)">每一条违反都判错</strong></p>
</div>
<div class="dodont-grid" style="margin-bottom:18px">
<div class="dodont do">
<span class="head">DO</span>
<div class="body">用 8 px 统一圆角 + 准星 + 装订线 + mono 装饰做"图纸感"</div>
</div>
<div class="dodont dont">
<span class="head">DON'T</span>
<div class="body">用 0 px 硬切角的卡片 —— V1 的做法,V2 起判错</div>
</div>
<div class="dodont do">
<span class="head">DO</span>
<div class="body">橙色 hover 用 <code class="tk heat">--heat-90</code> 等 alpha 阶梯</div>
</div>
<div class="dodont dont">
<span class="head">DON'T</span>
<div class="body">hover 时切换到更深的橙 hex(如 #D04E1F)</div>
</div>
<div class="dodont do">
<span class="head">DO</span>
<div class="body">主 CTA 用多层橙色阴影(4 层)制造发光感</div>
</div>
<div class="dodont dont">
<span class="head">DON'T</span>
<div class="body">用灰色阴影 / 文字阴影 / 通用 box-shadow 装饰</div>
</div>
</div>
<div style="background:var(--surface);border:1px solid var(--border-faint);border-radius:8px;padding:18px 22px">
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">渐变背景</strong> · 只有 hero 区可考虑,首选纯色。绝禁多色渐变。</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">玻璃拟态</strong> · <code class="tk">backdrop-filter</code> 只用于 modal 遮罩</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">彩色 emoji / filled icon</strong> · 一律 SVG line(stroke 1.5)</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">多 accent 色</strong> · 全场只有橙色一个 accent</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">大圆角容器(&gt;12 px)</strong> · 直接判错</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">真 border + hover 边框消失</strong> · 用 inside-border ::before</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">荧光鲜艳状态色</strong> · 避免霓虹绿、电光蓝、霓虹粉</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">居中对齐大段正文</strong> · 全部左对齐</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">装饰当主角</strong> · 场记板 / 丝绒 / 霓虹灯都不要</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">无意义微动效</strong> · hover 旋转、缩放、彩虹流光,禁</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">同一行混用直角和圆角</strong> · 用户原话:"不要有些是直角,胶囊又是圆角"</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">页面 inline style 重写共享类</strong> · 要变体先改 restraint.css</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">新建色值</strong> · 必须复用现有 token</span></div>
<div class="dont-list-item"><span class="x">×</span><span><strong style="color:var(--accent-black)">⌘ Unicode 字符</strong> · JetBrains Mono 不带该字形 · 用 "Ctrl K" 纯文本</span></div>
</div>
</section>
<!-- =========================================== §9 Checklist =========================================== -->
<section id="checklist">
<div class="section-head">
<span class="mono-tag">// §9 · CHECKLIST</span>
<h2>新页面 / 改页面 checklist</h2>
<p>每次开工前过一遍。<strong style="color:var(--accent-black)">3 个阶段都不能跳。</strong></p>
</div>
<div class="cl-card">
<div class="ch"><span class="stage">// STAGE 01</span><span class="ti">写代码前</span></div>
<ul class="cl-list">
<li><span class="mk"></span>已 Read [电商AI平台/design.md](design.md) §1 §3 §8(至少)</li>
<li><span class="mk"></span>用 Grep 查 restraint.css 是否已有该组件</li>
<li><span class="mk"></span>看本 design-system.html 找视觉参考</li>
<li><span class="mk"></span>不确定的设计点 → <strong>先问用户</strong>,不要凭感觉</li>
</ul>
</div>
<div class="cl-card">
<div class="ch"><span class="stage">// STAGE 02</span><span class="ti">写代码时</span></div>
<ul class="cl-list">
<li><span class="mk"></span>HTML 用 <code class="tk">app &gt; sidebar + main &gt; topbar + content</code> 骨架</li>
<li><span class="mk"></span>head 含 <code class="tk">assets/restraint.css</code> + Inter + JetBrains Mono</li>
<li><span class="mk"></span>body 末尾 <code class="tk">assets/shell.js</code></li>
<li><span class="mk"></span>标题区用 <code class="tk">.page-head &gt; h1 + .sub</code></li>
<li><span class="mk"></span>主操作按钮放 <code class="tk">.page-head &gt; .actions</code>(自动 40 px 高)</li>
<li><span class="mk"></span>子区块用 <code class="tk">.section-h &gt; h2 + .more</code></li>
<li><span class="mk"></span>按钮全 <code class="tk">.btn</code> 系列 · 不要自己写</li>
<li><span class="mk"></span>状态徽标全 <code class="tk">.pill.info/.ok/.err/.neutral</code></li>
<li><span class="mk"></span>输入框全 <code class="tk">.input / .select / .textarea</code> · 字段用 <code class="tk">.field</code></li>
<li><span class="mk"></span>浮层全用现成 Modal / Drawer / Toast</li>
<li><span class="mk"></span>图标 SVG line · stroke 1.5 · linecap round · <code class="tk">stroke="currentColor"</code></li>
<li><span class="mk"></span>时间戳 mono 注释 <code class="tk">// 05.22 · 周四</code></li>
<li><span class="mk"></span>强调单词加深(不变橙)<code class="tk">&lt;b style="color:var(--accent-black)"&gt;3 个&lt;/b&gt;</code></li>
<li><span class="mk"></span>数字加 <code class="tk">.num</code><code class="tk">tabular-nums</code></li>
<li><span class="mk"></span>状态色按语义选 <code class="tk">--heat / --accent-forest / --accent-crimson / --accent-honey</code></li>
</ul>
</div>
<div class="cl-card">
<div class="ch"><span class="stage">// STAGE 03</span><span class="ti">写完自检</span></div>
<ul class="cl-list">
<li><span class="mk"></span>对照 §8 Don't List 逐条过</li>
<li><span class="mk"></span>浏览器打开页面 · 截图 + 跟本 design-system.html 对比</li>
<li><span class="mk"></span>测 hover / focus / active / disabled 状态都正确</li>
<li><span class="mk"></span>测 dark mode(给 body 加 <code class="tk">.dark</code> class 看是否破)</li>
<li><span class="mk"></span>移动端缩到 1100 px 以下看响应式</li>
<li><span class="mk"></span>不在 master/main 上,在 dev 分支</li>
<li><span class="mk"></span>不带 <code class="tk">--no-verify</code>,不跳过 hook</li>
</ul>
</div>
</section>
</main>
</div>
<!-- ===== Modal HTML ===== -->
<div class="modal-bg" id="modal-mask">
<div class="modal" role="dialog">
<span class="corner-tr" aria-hidden></span>
<span class="corner-bl" aria-hidden></span>
<div class="modal-h">
<div class="ic-m"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 8v4M12 16h.01"/></svg></div>
<div class="ti">确认删除此商品?<span>// /products/dlt · IRREVERSIBLE</span></div>
</div>
<div class="modal-b">
该操作不可撤销。商品「夏季新款蕾丝连衣裙」及其关联的 <b style="color:var(--accent-black)">4 张候选图</b><b style="color:var(--accent-black)">2 段短视频</b>将一并删除。
</div>
<div class="modal-f">
<button class="btn" data-close-modal>取消</button>
<button class="btn btn-primary" data-close-modal>确认删除</button>
</div>
</div>
</div>
<!-- ===== Toast container ===== -->
<div class="toast-stack" id="toast-stack"></div>
<script>
/* ====== 复制色值 token 名 ====== */
document.querySelectorAll('[data-copy-grid] .swatch').forEach(sw => {
sw.addEventListener('click', () => {
const tk = sw.dataset.hex;
navigator.clipboard?.writeText(tk);
sw.classList.add('copied');
setTimeout(() => sw.classList.remove('copied'), 1200);
});
});
/* ====== Checkbox indeterminate click toggle ====== */
document.querySelectorAll('.ck.is-indeterminate input').forEach(cb => {
cb.addEventListener('change', e => {
e.target.closest('.ck').classList.remove('is-indeterminate');
});
});
/* ====== Tabs ====== */
document.querySelectorAll('[data-tabs]').forEach(group => {
const out = document.querySelector('[data-tab-content]');
group.addEventListener('click', e => {
const btn = e.target.closest('.ds-tab');
if (!btn) return;
group.querySelectorAll('.ds-tab').forEach(b => b.classList.remove('is-active'));
btn.classList.add('is-active');
if (out) out.textContent = btn.textContent;
});
});
/* ====== Subtabs ====== */
document.querySelectorAll('[data-subtabs]').forEach(group => {
group.addEventListener('click', e => {
const btn = e.target.closest('.ds-subtab');
if (!btn) return;
group.querySelectorAll('.ds-subtab').forEach(b => b.classList.remove('is-active'));
btn.classList.add('is-active');
});
});
/* ====== Modal ====== */
const mask = document.getElementById('modal-mask');
document.getElementById('open-modal').addEventListener('click', () => mask.classList.add('show'));
mask.addEventListener('click', e => {
if (e.target === mask || e.target.matches('[data-close-modal]')) mask.classList.remove('show');
});
document.addEventListener('keydown', e => { if (e.key === 'Escape') mask.classList.remove('show'); });
/* ====== Toast ====== */
const stack = document.getElementById('toast-stack');
document.querySelectorAll('[data-toast]').forEach(btn => {
btn.addEventListener('click', () => {
const data = JSON.parse(btn.dataset.toast);
const t = document.createElement('div');
t.className = 'toast show';
t.innerHTML = `
<div class="ic-t"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div>
<div class="txt">${data.ti}<span class="mono">${data.sub}</span></div>
`;
stack.appendChild(t);
setTimeout(() => { t.classList.add('is-leave'); setTimeout(() => t.remove(), 240); }, 2400);
});
});
/* ====== §4.14 / §4.15 picker 多选切换 ====== */
document.querySelectorAll('[data-pl-group]').forEach(group => {
group.addEventListener('click', e => {
const card = e.target.closest('[data-pl]');
if (!card) return;
card.classList.toggle('selected');
});
});
/* ====== §4.17.3 view-toggle 切换 ====== */
document.querySelectorAll('[data-vt]').forEach(group => {
const cur = document.querySelector('[data-vt-cur]');
group.addEventListener('click', e => {
const btn = e.target.closest('button');
if (!btn) return;
group.querySelectorAll('button').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
if (cur) cur.textContent = btn.dataset.v;
});
});
/* ====== §4.18 gen-image 点击反馈 ====== */
document.querySelectorAll('[data-gen-grid] .gen-image').forEach(img => {
img.addEventListener('click', e => {
// 点击浮层按钮不触发图片反馈
if (e.target.closest('.gen-image-actions')) return;
img.classList.add('show-feedback');
setTimeout(() => img.classList.remove('show-feedback'), 1500);
});
});
/* ====== §4.17.2 分页按钮切换 ====== */
document.querySelectorAll('.pagination-demo .pages').forEach(group => {
group.addEventListener('click', e => {
const btn = e.target.closest('button');
if (!btn) return;
// 跳过 切换按钮
if (btn.textContent === '' || btn.textContent === '') return;
group.querySelectorAll('button').forEach(b => {
if (b.textContent !== '' && b.textContent !== '') b.classList.remove('active');
});
btn.classList.add('active');
});
});
/* ====== Nav active on scroll ====== */
const navLinks = document.querySelectorAll('.ds-nav a');
const sections = [...document.querySelectorAll('.ds-main > section')];
function syncNav() {
const y = window.scrollY + 100;
let cur = sections[0]?.id;
sections.forEach(s => { if (s.offsetTop <= y) cur = s.id; });
navLinks.forEach(a => a.classList.toggle('active', a.getAttribute('href') === '#' + cur));
}
window.addEventListener('scroll', syncNav, { passive: true });
syncNav();
</script>
</body>
</html>