@wycm9527/morganite 0.0.0-stage → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +171 -0
  2. package/LICENSE +33 -0
  3. package/README.md +62 -2
  4. package/bridge/base.css +138 -0
  5. package/bridge/echarts.d.ts +44 -0
  6. package/bridge/echarts.js +217 -0
  7. package/bridge/element-plus.css +785 -0
  8. package/bridge/fonts.css +124 -0
  9. package/bridge/icon-merge.d.ts +5 -0
  10. package/bridge/icon-merge.js +103 -0
  11. package/bridge/iconpark.config.ts +75 -0
  12. package/bridge/iconpark.css +29 -0
  13. package/bridge/react/ConfirmBar.tsx +43 -0
  14. package/bridge/react/EChart.tsx +45 -0
  15. package/bridge/react/PageHeader.tsx +24 -0
  16. package/bridge/react/SectionHeader.tsx +17 -0
  17. package/bridge/react/StatCard.tsx +33 -0
  18. package/bridge/react/TableSkeleton.tsx +11 -0
  19. package/bridge/react/TrendChart.tsx +8 -0
  20. package/bridge/recipes.css +444 -0
  21. package/bridge/shadcn-globals.css +6 -0
  22. package/bridge/shadcn.css +238 -0
  23. package/bridge/vue/ConfirmBar.vue +23 -0
  24. package/bridge/vue/EChart.vue +43 -0
  25. package/bridge/vue/KitchenSink.vue +507 -0
  26. package/bridge/vue/PageHeader.vue +23 -0
  27. package/bridge/vue/SectionHeader.vue +15 -0
  28. package/bridge/vue/StatCard.vue +33 -0
  29. package/bridge/vue/TableSkeleton.vue +14 -0
  30. package/bridge/vue/TrendChart.vue +11 -0
  31. package/bridge/vue/confirm.js +18 -0
  32. package/bridge/vue/inlineConfirm.js +21 -0
  33. package/design-system/AUDIT.md +277 -0
  34. package/design-system/DESIGN.md +176 -0
  35. package/design-system/contrast.md +71 -0
  36. package/design-system/preview/drawer.html +38 -0
  37. package/design-system/preview/form.html +40 -0
  38. package/design-system/preview/index.html +21 -0
  39. package/design-system/preview/preview.css +190 -0
  40. package/design-system/preview/preview.local.css +17 -0
  41. package/design-system/preview/shell.html +50 -0
  42. package/design-system/scope-map.json +4 -0
  43. package/design-system/style-dictionary.config.mjs +172 -0
  44. package/design-system/theme-map.json +16 -0
  45. package/design-system/themes/dark/THEME.md +29 -0
  46. package/design-system/themes/dark/tokens/semantic.tokens.json +354 -0
  47. package/design-system/token-board.html +137 -0
  48. package/design-system/tokens/primitives.tokens.json +1898 -0
  49. package/design-system/tokens/semantic.tokens.json +1080 -0
  50. package/design-system.json +217 -0
  51. package/migration/roles.json +743 -0
  52. package/package.json +82 -4
  53. package/templates/AGENTS.md +13 -0
  54. package/templates/KitchenSink.tsx +179 -0
  55. package/templates/accept.config.mjs +28 -0
  56. package/templates/entry-css.css +6 -0
  57. package/templates/entry-element-plus.css +9 -0
  58. package/templates/entry-shadcn.css +7 -0
  59. package/templates/notes-css.md +4 -0
  60. package/templates/notes-element-plus.md +7 -0
  61. package/templates/notes-shadcn.md +7 -0
@@ -0,0 +1,190 @@
1
+ /* 虚拟项目的组件样式:只引用 token 变量,按 DESIGN「组件配方」的角色拼出来。
2
+ 颜色类角色缺失时露出洋红 --pv-miss,尺寸类缺失时用保守后备——预览里看到洋红 = 这个系统类型要求的角色没填。
3
+ 结构性布局(grid / flex / 断点镜像 768px)不是设计决定,可以写死。 */
4
+ :root {
5
+ --pv-miss: #ff00ff;
6
+ --pv-radius-control: var(--radius-md, 0px);
7
+ --pv-radius-card: var(--radius-lg, 0px);
8
+ color-scheme: light dark;
9
+ }
10
+ html { font-size: var(--layout-root-font-size, 16px); }
11
+ *, *::before, *::after { box-sizing: border-box; }
12
+ body {
13
+ margin: 0;
14
+ background: var(--color-bg-page, var(--pv-miss));
15
+ color: var(--color-text-primary, var(--pv-miss));
16
+ font-family: var(--font-family-body, system-ui, sans-serif);
17
+ font-size: var(--text-body-size, 1rem);
18
+ line-height: var(--text-body-line-height, 1.5);
19
+ -webkit-font-smoothing: auto;
20
+ }
21
+ h1, h2, h3, h4, p, ul, figure { margin: 0; }
22
+ ul { padding: 0; list-style: none; }
23
+ a { color: inherit; text-decoration: none; }
24
+ img, svg { display: block; max-width: 100%; }
25
+ button, input, select, textarea { font: inherit; color: inherit; }
26
+
27
+ /* —— 布局 —— */
28
+ .pv-container { max-width: var(--layout-container-max-width, 1200px); margin: 0 auto; padding-left: var(--space-gutter, 24px); padding-right: var(--space-gutter, 24px); }
29
+ .pv-section { padding-top: var(--space-stack, 16px); padding-bottom: var(--space-stack, 16px); }
30
+ .pv-section--tall { padding-top: calc(var(--space-stack, 16px) * 3); padding-bottom: calc(var(--space-stack, 16px) * 3); }
31
+ .pv-section--surface { background: var(--color-bg-surface, var(--pv-miss)); }
32
+ .pv-section--subtle { background: var(--color-bg-subtle, var(--pv-miss)); }
33
+ .pv-section--inverse { background: var(--color-bg-inverse, var(--pv-miss)); color: var(--color-text-inverse, var(--pv-miss)); }
34
+ .pv-section--brand { background: var(--color-bg-brand, var(--pv-miss)); color: var(--color-text-on-brand, var(--pv-miss)); }
35
+ .pv-grid { display: grid; gap: var(--space-stack, 16px); grid-template-columns: repeat(3, minmax(0, 1fr)); }
36
+ .pv-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
37
+ .pv-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
38
+ .pv-row { display: flex; gap: var(--space-inline, 8px); align-items: center; flex-wrap: wrap; }
39
+ .pv-stack { display: grid; gap: var(--space-stack, 16px); }
40
+ .pv-stack--tight { gap: var(--space-inline, 8px); }
41
+ .pv-divider { border: 0; border-top: var(--border-width-default, 1px) solid var(--color-border-default, var(--pv-miss)); margin: var(--space-stack, 16px) 0; }
42
+ @media (max-width: 767px) {
43
+ .pv-grid, .pv-grid--2, .pv-grid--4 { grid-template-columns: 1fr; }
44
+ .pv-hide-mobile { display: none !important; }
45
+ /* 窄屏字号降两档:hero → display,display → heading(token 只收了桌面值,这是通用做法的镜像) */
46
+ .pv-hero-title { font-size: var(--text-display-size, 2.5rem); line-height: var(--text-display-line-height, 1.1); }
47
+ .pv-display { font-size: var(--text-heading-size, 1.5rem); }
48
+ }
49
+
50
+ /* —— 文字 —— */
51
+ .pv-eyebrow { color: var(--color-text-brand, var(--pv-miss)); font-size: var(--text-small-size, 0.875rem); font-weight: var(--text-weight-label, 500); letter-spacing: var(--font-letter-spacing-wide, 0.04em); text-transform: uppercase; }
52
+ .pv-hero-title { font-family: var(--font-family-heading, var(--font-family-body, inherit)); font-size: var(--text-hero-size, var(--text-display-size, 3rem)); line-height: var(--text-hero-line-height, var(--text-display-line-height, 1.1)); font-weight: var(--text-weight-brand, 700); letter-spacing: var(--text-display-tracking, 0); }
53
+ .pv-display { font-family: var(--font-family-heading, var(--font-family-body, inherit)); font-size: var(--text-display-size, 2.5rem); line-height: var(--text-display-line-height, 1.1); font-weight: var(--text-display-weight, 700); letter-spacing: var(--text-display-tracking, 0); }
54
+ .pv-h2 { font-family: var(--font-family-heading, var(--font-family-body, inherit)); font-size: var(--text-heading-size, 1.5rem); line-height: var(--text-heading-line-height, 1.25); font-weight: var(--text-weight-strong, 600); }
55
+ .pv-h3 { font-size: var(--text-title-size, 1.125rem); line-height: var(--text-heading-line-height, 1.25); font-weight: var(--text-weight-strong, 600); }
56
+ .pv-h4 { font-size: var(--text-title-sm-size, 1rem); font-weight: var(--text-weight-strong, 600); }
57
+ .pv-lead { font-size: var(--text-title-size, 1.125rem); color: var(--color-text-secondary, var(--pv-miss)); line-height: var(--text-paragraph-line-height, var(--text-body-line-height, 1.5)); }
58
+ .pv-secondary { color: var(--color-text-secondary, var(--pv-miss)); }
59
+ .pv-muted { color: var(--color-text-muted, var(--pv-miss)); }
60
+ .pv-small { font-size: var(--text-small-size, 0.875rem); }
61
+ .pv-caption { font-size: var(--text-caption-size, 0.75rem); color: var(--color-text-muted, var(--pv-miss)); }
62
+ .pv-brand { color: var(--color-text-brand, var(--pv-miss)); }
63
+ .pv-strong { font-weight: var(--text-weight-strong, 600); }
64
+ .pv-link { color: var(--color-text-link, var(--pv-miss)); text-decoration: var(--text-link-decoration, underline); text-underline-offset: 0.15em; }
65
+ .pv-link:hover { color: var(--color-text-link-hover, var(--color-text-link, var(--pv-miss))); }
66
+ .pv-prose { max-width: 68ch; }
67
+ .pv-prose > * + * { margin-top: var(--space-stack, 16px); }
68
+ .pv-prose p { line-height: var(--text-paragraph-line-height, var(--text-body-line-height, 1.6)); }
69
+ .pv-prose ul { list-style: disc; padding-left: 1.4em; }
70
+ .pv-prose blockquote { margin: 0; padding-left: var(--space-card, 16px); border-left: var(--border-width-indicator, 3px) solid var(--color-brand-indicator, var(--pv-miss)); color: var(--color-text-secondary, var(--pv-miss)); }
71
+ .pv-prose code, .pv-code { font-family: var(--font-family-code, ui-monospace, monospace); font-size: var(--text-small-size, 0.875em); background: var(--color-bg-subtle, var(--pv-miss)); padding: 0.1em 0.4em; border-radius: var(--radius-sm, var(--pv-radius-control)); }
72
+ .pv-prose pre { background: var(--color-bg-subtle, var(--pv-miss)); padding: var(--space-card, 16px); border-radius: var(--pv-radius-card); overflow: auto; }
73
+ .pv-prose pre code { background: none; padding: 0; }
74
+ .pv-numeric { font-variant-numeric: var(--text-numeric-variant, tabular-nums); }
75
+
76
+ /* —— 导航 / 顶栏 / 页脚 —— */
77
+ .pv-nav { position: sticky; top: 0; z-index: var(--layer-sticky, 10); height: var(--layout-topbar-height, 56px); display: flex; align-items: center; background: var(--color-bg-page, var(--pv-miss)); }
78
+ .pv-nav--surface { background: var(--color-bg-surface, var(--pv-miss)); border-bottom: var(--border-width-default, 1px) solid var(--color-border-default, var(--pv-miss)); }
79
+ .pv-nav .pv-container { display: flex; align-items: center; justify-content: space-between; gap: var(--space-stack, 16px); width: 100%; }
80
+ .pv-logo { font-family: var(--font-family-heading, var(--font-family-body, inherit)); font-weight: var(--text-weight-logo, var(--text-weight-strong, 700)); font-size: var(--text-title-size, 1.125rem); letter-spacing: var(--font-letter-spacing-wide, 0); }
81
+ .pv-menu { display: flex; gap: var(--space-inline, 8px); align-items: center; }
82
+ .pv-menu a { display: inline-flex; align-items: center; height: var(--control-height-md, 36px); padding: 0 var(--spacing-3, var(--space-inline, 12px)); font-weight: var(--text-weight-label, 500); color: var(--color-text-secondary, var(--pv-miss)); border-radius: var(--pv-radius-control); }
83
+ .pv-menu a:hover { background: var(--color-bg-hover, var(--pv-miss)); color: var(--color-text-primary, var(--pv-miss)); }
84
+ .pv-menu a.is-current { color: var(--color-text-primary, var(--pv-miss)); box-shadow: inset 0 calc(-1 * var(--border-width-active, 2px)) 0 var(--color-border-current, var(--pv-miss)); }
85
+ .pv-footer { padding: calc(var(--space-stack, 16px) * 2) 0; color: var(--color-text-secondary, var(--pv-miss)); border-top: var(--border-width-default, 1px) solid var(--color-border-default, var(--pv-miss)); }
86
+ .pv-footer .pv-grid a { display: block; padding: 2px 0; color: var(--color-text-secondary, var(--pv-miss)); }
87
+
88
+ /* —— 按钮 —— */
89
+ .pv-btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-inline, 8px); height: var(--control-height-md, 36px); padding: 0 var(--spacing-4, 16px); border-radius: var(--pv-radius-control); border: var(--border-width-default, 1px) solid transparent; font-weight: var(--text-weight-label, 500); font-size: var(--text-body-size, 1rem); line-height: 1; cursor: pointer; white-space: nowrap; transition: background var(--motion-duration-fast, 120ms) var(--motion-easing-standard, ease), color var(--motion-duration-fast, 120ms) var(--motion-easing-standard, ease); }
90
+ .pv-btn--primary { background: var(--color-action-primary, var(--pv-miss)); color: var(--color-text-on-primary, var(--pv-miss)); border-color: var(--color-action-primary, var(--pv-miss)); }
91
+ .pv-btn--primary:hover { background: var(--color-action-primary-hover, var(--color-action-primary)); border-color: var(--color-action-primary-hover, var(--color-action-primary)); }
92
+ .pv-btn--secondary { background: transparent; color: var(--color-text-primary, var(--pv-miss)); border-color: var(--color-border-strong, var(--pv-miss)); }
93
+ .pv-btn--secondary:hover { background: var(--color-bg-hover, var(--pv-miss)); }
94
+ .pv-btn--quiet { background: transparent; color: var(--color-text-link, var(--pv-miss)); }
95
+ .pv-btn--quiet:hover { background: var(--color-action-quiet-hover, var(--color-bg-hover, var(--pv-miss))); }
96
+ .pv-btn--danger { background: var(--color-action-danger, var(--pv-miss)); color: var(--color-text-on-danger, var(--pv-miss)); border-color: var(--color-action-danger, var(--pv-miss)); }
97
+ .pv-btn--lg { height: var(--control-height-lg, var(--control-height-md, 44px)); padding: 0 var(--spacing-6, 24px); font-size: var(--text-title-sm-size, var(--text-body-size)); }
98
+ .pv-btn--sm { height: var(--control-height-sm, 28px); padding: 0 var(--spacing-3, 12px); font-size: var(--text-small-size, 0.875rem); }
99
+ .pv-btn--inverse { background: var(--color-bg-inverse, var(--pv-miss)); color: var(--color-text-inverse, var(--pv-miss)); border-color: var(--color-bg-inverse, var(--pv-miss)); }
100
+ .pv-btn--on-brand { background: transparent; color: var(--color-text-on-brand, var(--pv-miss)); border-color: var(--color-text-on-brand, var(--pv-miss)); }
101
+ .pv-btn:focus-visible, .pv-input:focus-visible { outline: var(--focus-ring-width, 2px) solid var(--color-focus-ring, var(--pv-miss)); outline-offset: 2px; }
102
+ .is-disabled { opacity: var(--opacity-disabled, 0.5); pointer-events: none; }
103
+
104
+ /* —— 表单 —— */
105
+ .pv-field { display: grid; gap: var(--space-inline, 8px); }
106
+ .pv-label { font-size: var(--text-body-sm-size, var(--text-body-size)); font-weight: var(--text-weight-label, 500); color: var(--color-text-primary, var(--pv-miss)); }
107
+ .pv-help { font-size: var(--text-small-size, 0.875rem); color: var(--color-text-muted, var(--pv-miss)); }
108
+ .pv-input { height: var(--control-height-md, 36px); width: 100%; padding: 0 var(--spacing-3, 12px); background: var(--color-bg-input, var(--pv-miss)); color: var(--color-text-primary, var(--pv-miss)); border: var(--border-width-default, 1px) solid var(--color-border-input, var(--pv-miss)); border-radius: var(--pv-radius-control); }
109
+ .pv-input::placeholder { color: var(--color-text-placeholder, var(--pv-miss)); }
110
+ .pv-input:focus { outline: var(--focus-ring-width, 2px) solid var(--color-focus-ring, var(--pv-miss)); border-color: var(--color-border-focus, var(--pv-miss)); }
111
+ textarea.pv-input { height: auto; min-height: calc(var(--control-height-md, 36px) * 3); padding-top: var(--spacing-2, 8px); resize: vertical; }
112
+ .pv-input--readonly { background: var(--color-bg-readonly, var(--color-bg-subtle, var(--pv-miss))); }
113
+ .pv-form-h { display: grid; grid-template-columns: var(--layout-form-label-width, 112px) 1fr; gap: var(--space-inline, 8px) var(--space-stack, 16px); align-items: center; max-width: var(--layout-form-max-width, 720px); }
114
+ .pv-form-h .pv-label { text-align: right; }
115
+ .pv-check { display: inline-flex; align-items: center; gap: var(--space-inline, 8px); }
116
+ .pv-check i { width: 16px; height: 16px; border: var(--border-width-control, var(--border-width-default, 1px)) solid var(--color-border-input, var(--pv-miss)); border-radius: var(--radius-xs, var(--radius-sm, 2px)); background: var(--color-bg-input, var(--pv-miss)); }
117
+ .pv-check i.is-on { background: var(--color-action-primary, var(--pv-miss)); border-color: var(--color-action-primary, var(--pv-miss)); }
118
+
119
+ /* —— 卡片 / 媒体 —— */
120
+ .pv-card { background: var(--color-bg-surface, var(--pv-miss)); border-radius: var(--pv-radius-card); padding: var(--space-card, 16px); box-shadow: 0 var(--elevation-card-y, 0) var(--elevation-card-blur, 0) var(--elevation-card-color, transparent); display: grid; gap: var(--space-inline, 8px); align-content: start; }
121
+ .pv-card--bordered { border: var(--border-width-default, 1px) solid var(--color-border-default, var(--pv-miss)); }
122
+ .pv-card--flush { padding: 0; overflow: hidden; }
123
+ .pv-card--flush .pv-card__body { padding: var(--space-card, 16px); display: grid; gap: var(--space-inline, 8px); }
124
+ .pv-media { aspect-ratio: 16 / 9; border-radius: var(--pv-radius-card); background: linear-gradient(135deg, var(--color-bg-subtle, var(--pv-miss)) 0%, var(--color-bg-surface, var(--pv-miss)) 60%, var(--color-bg-brand, var(--pv-miss)) 100%); position: relative; overflow: hidden; }
125
+ .pv-media--square { aspect-ratio: 1; }
126
+ .pv-media--wide { aspect-ratio: 21 / 9; }
127
+ .pv-media::after { content: ""; position: absolute; inset: auto 0 0 0; height: var(--border-width-indicator, 3px); background: var(--color-brand-indicator, var(--pv-miss)); }
128
+ .pv-cover { position: relative; border-radius: var(--pv-radius-card); overflow: hidden; display: grid; align-items: end; min-height: 320px; background: linear-gradient(160deg, var(--color-bg-brand, var(--pv-miss)), var(--color-bg-subtle, var(--pv-miss))); }
129
+ .pv-cover::before { content: ""; position: absolute; inset: 0; background: var(--color-bg-overlay, var(--pv-miss)); }
130
+ .pv-cover > * { position: relative; padding: var(--space-card, 16px); color: var(--color-text-on-overlay, var(--pv-miss)); }
131
+ .pv-stat { display: grid; gap: 4px; }
132
+ .pv-stat b { font-size: var(--text-display-size, 2rem); line-height: var(--text-display-line-height, 1.1); font-weight: var(--text-display-weight, 600); letter-spacing: var(--text-display-tracking, 0); font-variant-numeric: var(--text-numeric-variant, tabular-nums); }
133
+
134
+ /* —— 徽标 / 标签 / 状态 —— */
135
+ .pv-badge { display: inline-flex; align-items: center; height: var(--control-height-sm, 24px); padding: 0 var(--spacing-2, 8px); border-radius: var(--radius-full, 999px); font-size: var(--text-small-size, 0.875rem); font-weight: var(--text-weight-label, 500); white-space: nowrap; }
136
+ .pv-badge--success { background: var(--color-status-success-bg, var(--pv-miss)); color: var(--color-status-success, var(--pv-miss)); }
137
+ .pv-badge--warning { background: var(--color-status-warning-bg, var(--pv-miss)); color: var(--color-status-warning, var(--pv-miss)); }
138
+ .pv-badge--error { background: var(--color-status-error-bg, var(--pv-miss)); color: var(--color-status-error, var(--pv-miss)); }
139
+ .pv-badge--info { background: var(--color-status-info-bg, var(--pv-miss)); color: var(--color-status-info, var(--pv-miss)); }
140
+ .pv-badge--neutral { background: var(--color-status-neutral-bg, var(--pv-miss)); color: var(--color-status-neutral, var(--pv-miss)); }
141
+ .pv-tag { display: inline-flex; align-items: center; height: var(--control-height-sm, var(--control-height-md, 24px)); padding: 0 var(--spacing-2, 8px); border-radius: var(--pv-radius-control); background: var(--color-bg-subtle, var(--pv-miss)); color: var(--color-text-secondary, var(--pv-miss)); font-size: var(--text-small-size, 0.875rem); letter-spacing: var(--font-letter-spacing-wide, 0); }
142
+ .pv-alert { display: flex; gap: var(--space-inline, 8px); padding: var(--spacing-3, 12px) var(--space-card, 16px); border-radius: var(--pv-radius-control); background: var(--color-status-info-bg, var(--pv-miss)); color: var(--color-status-info, var(--pv-miss)); }
143
+ .pv-alert--warning { background: var(--color-status-warning-bg, var(--pv-miss)); color: var(--color-status-warning, var(--pv-miss)); }
144
+ .pv-dot { width: 8px; height: 8px; border-radius: var(--radius-full, 999px); background: var(--color-brand-indicator, var(--pv-miss)); display: inline-block; }
145
+
146
+ /* —— 表格 / 分页 / 标签页 —— */
147
+ .pv-table { width: 100%; border-collapse: collapse; background: var(--color-bg-surface, var(--pv-miss)); }
148
+ .pv-table th { text-align: left; background: var(--color-bg-subtle, var(--pv-miss)); color: var(--color-text-secondary, var(--pv-miss)); font-weight: var(--text-weight-label, 500); font-size: var(--text-body-sm-size, var(--text-body-size)); padding: var(--table-cell-padding-y, 12px) var(--table-cell-padding-x, 16px); border-bottom: var(--border-width-default, 1px) solid var(--color-border-default, var(--pv-miss)); }
149
+ .pv-table td { padding: var(--table-cell-padding-y, 12px) var(--table-cell-padding-x, 16px); border-bottom: var(--border-width-default, 1px) solid var(--color-border-default, var(--pv-miss)); vertical-align: middle; }
150
+ .pv-table tr:hover td { background: var(--color-bg-hover, var(--pv-miss)); }
151
+ .pv-table tr.is-selected td { background: var(--color-bg-selected-subtle, var(--pv-miss)); }
152
+ .pv-table .pv-muted { font-size: var(--text-small-size, 0.875rem); }
153
+ .pv-pagination { display: flex; gap: var(--space-inline, 8px); align-items: center; }
154
+ .pv-pagination a { display: inline-flex; align-items: center; justify-content: center; min-width: var(--control-height-sm, 28px); height: var(--control-height-sm, 28px); padding: 0 var(--spacing-2, 8px); border-radius: var(--pv-radius-control); color: var(--color-text-secondary, var(--pv-miss)); font-variant-numeric: var(--text-numeric-variant, tabular-nums); }
155
+ .pv-pagination a.is-current { background: var(--color-action-selected, var(--pv-miss)); color: var(--color-text-on-selected, var(--pv-miss)); }
156
+ .pv-tabs { display: flex; gap: var(--space-stack, 16px); border-bottom: var(--border-width-default, 1px) solid var(--color-border-default, var(--pv-miss)); }
157
+ .pv-tabs a { display: inline-flex; align-items: center; height: var(--control-height-md, 36px); color: var(--color-text-secondary, var(--pv-miss)); font-weight: var(--text-weight-label, 500); }
158
+ .pv-tabs a.is-current { color: var(--color-text-primary, var(--pv-miss)); box-shadow: inset 0 calc(-1 * var(--border-width-active, 2px)) 0 var(--color-border-current, var(--pv-miss)); }
159
+ .pv-toolbar { display: flex; gap: var(--space-inline, 8px); align-items: center; justify-content: space-between; flex-wrap: wrap; }
160
+ .pv-search { width: var(--layout-search-width, 240px); }
161
+ .pv-skeleton { height: 12px; border-radius: var(--radius-full, 999px); background: linear-gradient(90deg, var(--color-bg-skeleton, var(--pv-miss)), var(--color-bg-skeleton-highlight, var(--color-bg-skeleton, var(--pv-miss))), var(--color-bg-skeleton, var(--pv-miss))); }
162
+
163
+ /* —— 中后台壳层 —— */
164
+ .pv-shell { display: grid; grid-template-columns: var(--layout-sidebar-width, 240px) minmax(0, 1fr); min-height: 100vh; }
165
+ .pv-sidebar { background: var(--color-bg-sidebar, var(--pv-miss)); color: var(--color-text-sidebar, var(--pv-miss)); border-right: var(--border-width-default, 1px) solid var(--color-border-sidebar, var(--pv-miss)); padding: var(--space-card, 16px) var(--spacing-3, 12px); display: grid; gap: var(--space-stack, 16px); align-content: start; }
166
+ .pv-sidebar .pv-logo { color: var(--color-text-sidebar-strong, var(--pv-miss)); padding: 0 var(--spacing-3, 12px); }
167
+ .pv-sidebar .pv-group { font-size: var(--text-caption-size, 0.75rem); color: var(--color-text-sidebar-muted, var(--pv-miss)); padding: 0 var(--spacing-3, 12px); text-transform: uppercase; letter-spacing: var(--font-letter-spacing-wide, 0.04em); }
168
+ .pv-sidebar a { display: flex; align-items: center; gap: var(--space-inline, 8px); height: var(--control-height-md, 36px); padding: 0 var(--spacing-3, 12px); border-radius: var(--pv-radius-control); color: var(--color-text-sidebar, var(--pv-miss)); font-weight: var(--text-weight-label, 500); }
169
+ .pv-sidebar a:hover { background: var(--color-bg-sidebar-hover, var(--pv-miss)); }
170
+ .pv-sidebar a.is-current { background: var(--color-bg-sidebar-selected, var(--pv-miss)); color: var(--color-text-sidebar-selected, var(--pv-miss)); box-shadow: inset var(--border-width-indicator, 3px) 0 0 var(--color-brand-indicator, var(--pv-miss)); }
171
+ .pv-sidebar i { width: 16px; height: 16px; border-radius: var(--radius-xs, 3px); background: currentColor; opacity: 0.7; }
172
+ .pv-main { display: grid; grid-template-rows: auto 1fr; min-width: 0; }
173
+ .pv-topbar { height: var(--layout-topbar-height, 56px); background: var(--color-bg-surface, var(--pv-miss)); border-bottom: var(--border-width-default, 1px) solid var(--color-border-default, var(--pv-miss)); display: flex; align-items: center; justify-content: space-between; padding: 0 var(--space-gutter, 24px); position: sticky; top: 0; z-index: var(--layer-sticky, 10); }
174
+ .pv-content { padding: var(--space-gutter, 24px); display: grid; gap: var(--space-stack, 16px); align-content: start; }
175
+ .pv-avatar { width: var(--avatar-size-md, 32px); height: var(--avatar-size-md, 32px); border-radius: var(--radius-full, 999px); background: var(--color-bg-brand, var(--pv-miss)); }
176
+ @media (max-width: 767px) { .pv-shell { grid-template-columns: 1fr; } .pv-sidebar { display: none; } }
177
+
178
+ /* —— 浮层 —— */
179
+ .pv-overlay { position: fixed; inset: 0; background: var(--color-bg-overlay, var(--pv-miss)); z-index: var(--layer-modal, 1000); display: flex; align-items: center; justify-content: center; padding: var(--space-gutter, 24px); }
180
+ .pv-overlay--right { justify-content: flex-end; padding: 0; }
181
+ .pv-dialog { width: min(100%, var(--layout-modal-width-md, 640px)); background: var(--color-bg-elevated, var(--pv-miss)); border-radius: var(--pv-radius-card); padding: var(--space-card, 16px); display: grid; gap: var(--space-stack, 16px); box-shadow: 0 var(--elevation-modal-y, 0) var(--elevation-modal-blur, 0) var(--elevation-modal-color, transparent); }
182
+ .pv-dialog--sm { width: min(100%, var(--layout-modal-width-sm, 420px)); }
183
+ .pv-drawer { width: min(100%, var(--layout-drawer-width, 480px)); height: 100%; background: var(--color-bg-elevated, var(--pv-miss)); padding: var(--space-card, 16px); display: grid; gap: var(--space-stack, 16px); align-content: start; box-shadow: 0 var(--elevation-modal-y, 0) var(--elevation-modal-blur, 0) var(--elevation-modal-color, transparent); }
184
+ .pv-popover { background: var(--color-bg-elevated, var(--pv-miss)); border: var(--border-width-default, 1px) solid var(--color-border-default, var(--pv-miss)); border-radius: var(--pv-radius-card); padding: var(--spacing-2, 8px); display: grid; gap: 2px; width: 200px; box-shadow: 0 var(--elevation-popover-y, 0) var(--elevation-popover-blur, 0) var(--elevation-popover-color, transparent); }
185
+ .pv-popover a { display: block; padding: var(--spacing-2, 8px) var(--spacing-3, 12px); border-radius: var(--pv-radius-control); }
186
+ .pv-popover a:hover { background: var(--color-bg-hover, var(--pv-miss)); }
187
+ .pv-popover a.is-danger { color: var(--color-text-danger, var(--pv-miss)); }
188
+ .pv-tooltip { display: inline-block; background: var(--color-bg-inverse, var(--pv-miss)); color: var(--color-text-inverse, var(--pv-miss)); padding: var(--spacing-1, 4px) var(--spacing-2, 8px); border-radius: var(--pv-radius-control); font-size: var(--text-small-size, 0.875rem); }
189
+ .pv-menu-overlay { position: fixed; inset: 0; background: var(--color-bg-overlay, var(--pv-miss)); z-index: var(--layer-modal, 1000); display: grid; align-content: center; justify-items: center; gap: var(--space-stack, 16px); }
190
+ .pv-menu-overlay a { font-family: var(--font-family-heading, var(--font-family-body, inherit)); font-size: var(--text-display-size, 2.5rem); line-height: var(--text-display-line-height, 1.1); color: var(--color-text-on-overlay, var(--pv-miss)); font-weight: var(--text-weight-brand, 700); }
@@ -0,0 +1,17 @@
1
+ :root { --pv-radius-control: var(--radius-md, 0px); --pv-radius-card: var(--radius-lg, 0px); }
2
+
3
+ /* Morganite 配方在虚拟项目里的对应(重新渲染时用 render-preview --local-css 传入本段):
4
+ 卡片标题 = 14px 深色标题(color.text.card-title);统计卡标题 = 字距小标题;顶栏搜索 = 胶囊;勾选框未选中描 border.strong(填充式下 border.input 透明);
5
+ 侧栏当前项只用底块、不加指示条;标签页选中文字用 color.text.selected;输入框聚焦只换边线、不加外环;
6
+ 表格选中行与悬停同色;分页当前页金底白字(生成器默认的白块在本系统是白底白卡) */
7
+ .pv-card .pv-h3 { font-size: var(--text-body-size); font-weight: var(--text-weight-strong); color: var(--color-text-card-title); }
8
+ .pv-stat > .pv-secondary.pv-small { font-size: var(--text-small-size); font-weight: var(--text-weight-strong); color: var(--color-text-secondary); letter-spacing: var(--text-tracking-caps); text-transform: uppercase; }
9
+ .pv-search { border-radius: var(--radius-full); }
10
+ .pv-check i { border-color: var(--color-border-strong); }
11
+ .pv-check i.is-on { border-color: var(--color-action-primary); }
12
+ .pv-sidebar a.is-current { box-shadow: none; }
13
+ .pv-tabs a.is-current { color: var(--color-text-selected); }
14
+ .pv-input:focus, .pv-input:focus-visible { outline: none; }
15
+ .pv-table tr.is-selected td { background: var(--color-bg-hover); }
16
+ .pv-pagination a.is-current { background: var(--color-action-primary); color: var(--color-text-on-primary); font-weight: var(--text-weight-strong); }
17
+
@@ -0,0 +1,50 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Morganite 玫瑰金 · 工作台 · 虚拟项目</title>
7
+ <link rel="stylesheet" href="../dist/index.css">
8
+ <link rel="stylesheet" href="../../bridge/base.css">
9
+ <link rel="stylesheet" href="preview.css">
10
+ <link rel="stylesheet" href="preview.local.css">
11
+ </head>
12
+ <body>
13
+ <div class="pv-shell">
14
+ <aside class="pv-sidebar">
15
+ <span class="pv-logo">Morganite 玫瑰金</span>
16
+ <nav class="pv-stack pv-stack--tight">
17
+ <span class="pv-group">工作台</span>
18
+ <a class="is-current" href="#"><i></i>产品</a><a href="#"><i></i>案例</a><a href="#"><i></i>关于</a>
19
+ <span class="pv-group">管理</span>
20
+ <a href="#"><i></i>联系</a><a href="#"><i></i>设置</a>
21
+ </nav>
22
+ </aside>
23
+ <div class="pv-main">
24
+ <header class="pv-topbar"><div class="pv-row"><span class="pv-secondary pv-small">产品 / 概览</span></div><div class="pv-row"><input class="pv-input pv-search pv-hide-mobile" placeholder="搜索…"><button class="pv-btn pv-btn--primary pv-btn--sm" type="button">立即开始</button><span class="pv-avatar"></span></div></header>
25
+ <main class="pv-content">
26
+ <div class="pv-toolbar"><h1 class="pv-h2">Morganite 玫瑰金 让每一次决定都有来处</h1><nav class="pv-tabs" style="border: 0"><a class="is-current" href="#">今日</a><a href="#">本周</a><a href="#">本月</a></nav></div>
27
+ <div class="pv-grid pv-grid--4">
28
+ <div class="pv-card pv-stat"><span class="pv-secondary pv-small">板块一</span><b class="pv-numeric">12,480</b><span class="pv-small" style="color: var(--color-data-increase, var(--color-status-success))">▲ 8.2%</span></div>
29
+ <div class="pv-card pv-stat"><span class="pv-secondary pv-small">板块二</span><b class="pv-numeric">96.4%</b><span class="pv-small" style="color: var(--color-data-increase, var(--color-status-success))">▲ 0.6%</span></div>
30
+ <div class="pv-card pv-stat"><span class="pv-secondary pv-small">板块三</span><b class="pv-numeric">37</b><span class="pv-small" style="color: var(--color-data-decrease, var(--color-status-error))">▼ 3.1%</span></div>
31
+ <div class="pv-card pv-stat"><span class="pv-secondary pv-small">图表色</span><div class="pv-row" style="align-items: flex-end; height: 48px; gap: 4px"><i style="flex:1;height:60%;background:var(--color-chart-1, var(--pv-miss))"></i><i style="flex:1;height:90%;background:var(--color-chart-2, var(--pv-miss))"></i><i style="flex:1;height:40%;background:var(--color-chart-3, var(--pv-miss))"></i><i style="flex:1;height:70%;background:var(--color-chart-4, var(--pv-miss))"></i><i style="flex:1;height:30%;background:var(--color-chart-5, var(--pv-miss))"></i><i style="flex:1;height:55%;background:var(--color-chart-6, var(--pv-miss))"></i></div></div>
32
+ </div>
33
+ <div class="pv-card pv-card--flush">
34
+ <div class="pv-toolbar" style="padding: var(--space-card, 16px)"><h2 class="pv-h3">产品</h2><div class="pv-row"><input class="pv-input" style="width: 180px" placeholder="筛选"><button class="pv-btn pv-btn--secondary pv-btn--sm" type="button">导出</button></div></div>
35
+ <table class="pv-table">
36
+ <thead><tr><th style="width: 40px"><span class="pv-check"><i></i></span></th><th>名称</th><th>负责人</th><th>状态</th><th class="pv-numeric" style="text-align: right">金额</th><th>更新时间</th><th></th></tr></thead>
37
+ <tbody>
38
+ <tr class="is-selected"><td><span class="pv-check"><i class="is-on"></i></span></td><td><div class="pv-strong">板块一</div><div class="pv-muted">副行说明</div></td><td>王小明</td><td><span class="pv-badge pv-badge--success">已通过</span></td><td class="pv-numeric" style="text-align: right">12,800.00</td><td class="pv-secondary">今天 10:24</td><td><a class="pv-link pv-small" href="#">编辑</a></td></tr>
39
+ <tr><td><span class="pv-check"><i></i></span></td><td><div class="pv-strong">板块二</div><div class="pv-muted">副行说明</div></td><td>李华</td><td><span class="pv-badge pv-badge--warning">待审批</span></td><td class="pv-numeric" style="text-align: right">3,200.00</td><td class="pv-secondary">昨天</td><td><a class="pv-link pv-small" href="#">编辑</a></td></tr>
40
+ <tr><td><span class="pv-check"><i></i></span></td><td><div class="pv-strong">板块三</div><div class="pv-muted">副行说明</div></td><td>张三</td><td><span class="pv-badge pv-badge--error">已驳回</span></td><td class="pv-numeric" style="text-align: right">980.00</td><td class="pv-secondary">3 天前</td><td><a class="pv-link pv-small" href="#">编辑</a></td></tr>
41
+ <tr><td><span class="pv-check"><i></i></span></td><td><div class="pv-strong">第四条</div><div class="pv-muted">副行说明</div></td><td>陈静</td><td><span class="pv-badge pv-badge--info">提示</span></td><td class="pv-numeric" style="text-align: right">45,000.00</td><td class="pv-secondary">上周</td><td><a class="pv-link pv-small" href="#">编辑</a></td></tr>
42
+ </tbody>
43
+ </table>
44
+ <div class="pv-toolbar" style="padding: var(--space-card, 16px)"><span class="pv-secondary pv-small">第 1–4 条,共 128 条</span><nav class="pv-pagination"><a href="#">‹</a><a class="is-current" href="#">1</a><a href="#">2</a><a href="#">3</a><a href="#">›</a></nav></div>
45
+ </div>
46
+ </main>
47
+ </div>
48
+ </div>
49
+ </body>
50
+ </html>
@@ -0,0 +1,4 @@
1
+ {
2
+ "scopes": [],
3
+ "version": 1
4
+ }
@@ -0,0 +1,172 @@
1
+ import path from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+
4
+ const root = path.dirname(fileURLToPath(import.meta.url));
5
+
6
+ function environmentPathList(name, fallback) {
7
+ const raw = process.env[name];
8
+ if (!raw) {
9
+ return fallback;
10
+ }
11
+ let parsed;
12
+ try {
13
+ parsed = JSON.parse(raw);
14
+ } catch (error) {
15
+ throw new Error(`${name} must be a JSON array of absolute token globs: ${error.message}`);
16
+ }
17
+ if (!Array.isArray(parsed) || parsed.some((entry) => typeof entry !== "string" || !path.isAbsolute(entry))) {
18
+ throw new Error(`${name} must be a JSON array of absolute token globs`);
19
+ }
20
+ return parsed;
21
+ }
22
+
23
+ function outputDestination() {
24
+ const destination = process.env.DS_SCOPE_DESTINATION ?? "tokens.css";
25
+ if (path.isAbsolute(destination) || destination.split(/[\\/]/).includes("..")) {
26
+ throw new Error("DS_SCOPE_DESTINATION must be a relative CSS file path");
27
+ }
28
+ if (!destination.endsWith(".css")) {
29
+ throw new Error("DS_SCOPE_DESTINATION must end in .css");
30
+ }
31
+ return destination;
32
+ }
33
+
34
+ function mediaQuery() {
35
+ const query = process.env.DS_SCOPE_MEDIA;
36
+ if (!query) {
37
+ return null;
38
+ }
39
+ if (!/^\(prefers-color-scheme: (?:dark|light)\)$/.test(query)) {
40
+ throw new Error("DS_SCOPE_MEDIA must be a supported prefers-color-scheme query");
41
+ }
42
+ return query;
43
+ }
44
+
45
+ function collectReferences(value) {
46
+ if (typeof value !== "string") {
47
+ return [];
48
+ }
49
+ return [...value.matchAll(/\{([^{}]+)\}/g)].map((match) => match[1]);
50
+ }
51
+
52
+ function sourceFirst(tokens) {
53
+ const sourceTokens = tokens.filter((token) => token.isSource);
54
+ const byPath = new Map(sourceTokens.map((token) => [token.path.join("."), token]));
55
+ const sorted = [];
56
+ const state = new Map();
57
+
58
+ function visit(token) {
59
+ const tokenPath = token.path.join(".");
60
+ const current = state.get(tokenPath) ?? "unseen";
61
+ if (current === "visiting" || current === "done") {
62
+ return;
63
+ }
64
+ state.set(tokenPath, "visiting");
65
+ const original = token.original.$value ?? token.original.value;
66
+ for (const reference of collectReferences(original).sort((left, right) => left.localeCompare(right))) {
67
+ const dependency = byPath.get(reference);
68
+ if (dependency) {
69
+ visit(dependency);
70
+ }
71
+ }
72
+ state.set(tokenPath, "done");
73
+ sorted.push(token);
74
+ }
75
+
76
+ for (const token of [...sourceTokens].sort((left, right) => left.name.localeCompare(right.name))) {
77
+ visit(token);
78
+ }
79
+ return sorted;
80
+ }
81
+
82
+ function cssValue(token, namesByPath) {
83
+ const original = token.original.$value ?? token.original.value;
84
+ if (typeof original === "string" && original.includes("{")) {
85
+ return original.replace(/\{([^{}]+)\}/g, (match, reference) => {
86
+ const target = namesByPath.get(reference);
87
+ return target ? `var(--${target.name})` : match;
88
+ });
89
+ }
90
+ if (original && typeof original === "object" && !Array.isArray(original) && typeof original.hex === "string") {
91
+ return original.hex.trim();
92
+ }
93
+
94
+ const value = token.$value ?? token.value;
95
+ const type = token.$type ?? token.type ?? token.original.$type ?? token.original.type;
96
+ if (value && typeof value === "object" && !Array.isArray(value)
97
+ && (type === "dimension" || type === "duration")
98
+ && typeof value.value === "number" && typeof value.unit === "string") {
99
+ return `${value.value}${value.unit}`;
100
+ }
101
+ if (Array.isArray(value)) {
102
+ return type === "cubicBezier" ? `cubic-bezier(${value.join(", ")})` : value.join(", ");
103
+ }
104
+ if (value && typeof value === "object") {
105
+ throw new Error(`CSS profile did not transform ${token.path.join(".")} into a CSS value`);
106
+ }
107
+ return String(value);
108
+ }
109
+
110
+ /**
111
+ * Style Dictionary receives all ancestor tokens as `include` and only the
112
+ * current layer as `source`. The formatter therefore resolves aliases from the
113
+ * complete dictionary but writes only `isSource` delta tokens.
114
+ */
115
+ async function scopeDeltaCss({ dictionary, options }) {
116
+ const selector = options.selector ?? ":root";
117
+ const allTokens = dictionary.unfilteredAllTokens ?? dictionary.allTokens;
118
+ const namesByPath = new Map(allTokens.map((token) => [token.path.join("."), token]));
119
+ const lines = sourceFirst(dictionary.allTokens)
120
+ .map((token) => ` --${token.name}: ${cssValue(token, namesByPath)};`);
121
+ if (lines.length === 0) {
122
+ return "";
123
+ }
124
+ const body = `${selector} {\n${lines.join("\n")}\n}\n`;
125
+ if (!options.media) {
126
+ return body;
127
+ }
128
+ return `@media ${options.media} {\n${body.replace(/^/gm, " ").replace(/\n*$/, "")}\n}\n`;
129
+ }
130
+
131
+ const outputRoot = process.env.DS_OUTPUT_DIR
132
+ ? path.resolve(process.env.DS_OUTPUT_DIR)
133
+ : path.join(root, "dist");
134
+ const source = environmentPathList(
135
+ "DS_SCOPE_SOURCE",
136
+ [path.join(root, "tokens", "**", "*.tokens.json")]
137
+ );
138
+ const include = environmentPathList("DS_SCOPE_INCLUDE", []);
139
+ const media = mediaQuery();
140
+
141
+ export default {
142
+ include,
143
+ log: {
144
+ warnings: "error"
145
+ },
146
+ source,
147
+ hooks: {
148
+ formats: {
149
+ "design-system-steward/scope-delta": scopeDeltaCss
150
+ }
151
+ },
152
+ platforms: {
153
+ css: {
154
+ transformGroup: "css",
155
+ buildPath: `${outputRoot}${path.sep}`,
156
+ log: {
157
+ warnings: "error"
158
+ },
159
+ files: [
160
+ {
161
+ destination: outputDestination(),
162
+ format: "design-system-steward/scope-delta",
163
+ options: {
164
+ media,
165
+ selector: process.env.DS_SCOPE_SELECTOR ?? ":root",
166
+ showFileHeader: false
167
+ }
168
+ }
169
+ ]
170
+ }
171
+ }
172
+ };
@@ -0,0 +1,16 @@
1
+ {
2
+ "activation": {
3
+ "kind": "class"
4
+ },
5
+ "defaultTheme": "light",
6
+ "themes": [
7
+ {
8
+ "id": "dark",
9
+ "reason": "取证时手动打开 Pro 设置抽屉的「暗色风格(实验功能)」拿到另一模式;delta 64 条,页面底 / 表面 / 文字 / 边线 / 悬停来自实测,其余按 antd 暗色算法推断、2026-10-09 用户已确认,品牌相关的按用户决定。",
10
+ "runtimeOwner": "接入项目:在 <html> 上切换 dark 类;来源站 Ant Design Pro 通过设置抽屉切换,设置只存在内存里。",
11
+ "source": "https://preview.pro.ant.design/dashboard/analysis(toggle-dark)",
12
+ "status": "active"
13
+ }
14
+ ],
15
+ "version": 1
16
+ }
@@ -0,0 +1,29 @@
1
+ # Theme:dark
2
+
3
+ > Core Token 是确认的默认 Theme。本文件只记录当前 Theme 相对 Core 的意图、适用范围和运行时约束;具体值只写在本目录 `tokens/*.tokens.json`,不要复制 Core 或手改生成 CSS。
4
+
5
+ ## 映射
6
+
7
+ - 默认 Theme:`light`
8
+ - 当前 Theme:`dark`
9
+ - 状态:`active`
10
+ - 激活方式:`:root.dark`
11
+ - 权威来源:`https://preview.pro.ant.design/dashboard/analysis(toggle-dark)`
12
+ - 运行时所有者:接入项目——在 `<html>` 上切换 `dark` 类;来源站 Ant Design Pro 通过设置抽屉切换,且设置只存在内存里。
13
+ - 设计理由:取证时手动打开 Pro 设置抽屉的「暗色风格(实验功能)」拿到另一模式;delta 64 条,页面底 / 表面 / 文字 / 边线 / 悬停来自实测,其余按 antd 暗色算法推断、2026-10-09 用户已确认,品牌相关的按用户决定。
14
+
15
+ ## 相对 Core 的设计意图
16
+
17
+ - delta 覆写 66 条(取证时 64 条,之后按用户决定加了图表提示气泡与卡片标题),每条的来源写在 `tokens/semantic.tokens.json` 的 `$description` 里。下面这些「通常也随模式变化」的角色逐条确认过,**保持 Core 值**:`color.bg.overlay`(antd 暗色遮罩与亮色同值)、`color.text.inverse`(反色底在暗色换成深灰,白字不变)、`color.text.brand` / `color.border.current` / `color.icon.brand` / `color.chart.1`(品牌金在深底上对比更高)、`color.border.input`(填充式,亮暗都不画边线)、`elevation.card.color` / `elevation.popover.color` / `elevation.modal.color`(沿用 antd:暗色仍是黑色阴影,深底上几乎看不见,层次改靠浮层表面亮一档)。
18
+ - 品牌色 / 主按钮保持 Core 值:金底白字亮暗一致,品牌色一个值都不动。
19
+ - 浮层表面(`color.bg.elevated`)比 `color.bg.surface` 亮一档,页面底最深;三层顺序与 antd 暗色算法一致。卡片与亮色一样不投影,靠底色差分层;暗色卡片边线保持 antd 暗色分隔线那一档,不跟亮色改成半透明黑。
20
+ - 状态色文字换成更亮的一档,浅底改为 antd 暗色色板的预混实色,胶囊对比都在底线以上。
21
+ - 侧栏当前项换成金色暗阶、文字换成亮金;表格选中行与悬停同色(白 8%),再悬停用白 12%(亮色当前项是主色底块配白字,暗色按用户要求保持金色暗底配亮金字);筹码底取暗色筹码字色亮金的 10%(与亮色「字色同色 10%」同一规则,用户 2026-10-09 确认);图表的「深灰 / 浅灰」两个分类色在深底上互换明暗,绿与涨跌色换亮一档;卡片标题取暗色正文色(与亮色的 #212121 同一层级,用户 2026-10-13 确认)。
22
+ - 字体、尺寸、间距、线宽、动效等结构层 Token 不随 Theme 变化,本 Theme 不覆写它们。
23
+ - 优先覆写 Core Semantic token;Component token 仅用于已批准的组件例外。
24
+ - 不覆写 Core Primitive,也不在此处创建主题开关、持久化或系统偏好逻辑。
25
+
26
+ ## 与 Scope 的关系
27
+
28
+ - Theme 是同一界面的模式,Scope 是页面边界;二者不自动组合。
29
+ - 若当前 Theme 与某个 Scope 需要同时覆写同一 Semantic,先提出提案并获得确认;不要添加猜测性 CSS。