dsh-config-manager 0.1.76 → 0.1.78

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 (84) hide show
  1. package/lib/adapters/plugin-data-declared.d.ts +12 -0
  2. package/lib/adapters/plugin-data-declared.js +57 -0
  3. package/lib/adapters/plugin-data.d.ts +4 -6
  4. package/lib/adapters/plugin-data.js +8 -36
  5. package/lib/adapters/plugins.d.ts +16 -0
  6. package/lib/adapters/plugins.js +223 -16
  7. package/lib/client.d.ts +104 -9
  8. package/lib/client.js +1800 -718
  9. package/lib/core/analyzer.js +3 -1
  10. package/lib/core/backup.d.ts +9 -0
  11. package/lib/core/backup.js +16 -1
  12. package/lib/core/messages.d.ts +11 -0
  13. package/lib/core/messages.js +22 -0
  14. package/lib/core/plugin-cli.d.ts +26 -0
  15. package/lib/core/plugin-cli.js +62 -2
  16. package/lib/core/rollback-attribution.d.ts +81 -0
  17. package/lib/core/rollback-attribution.js +236 -0
  18. package/lib/core/rollback-merge.d.ts +22 -0
  19. package/lib/core/rollback-merge.js +203 -0
  20. package/lib/core/rollback-point.d.ts +114 -0
  21. package/lib/core/rollback-point.js +534 -17
  22. package/lib/core/types.d.ts +28 -0
  23. package/lib/index.d.ts +26 -3
  24. package/lib/index.js +129 -16
  25. package/lib/routes/recovery.js +11 -0
  26. package/lib/schema/section-registry.js +5 -5
  27. package/lib/schema/types.d.ts +14 -0
  28. package/lib/ui/badge-tone.d.ts +16 -0
  29. package/lib/ui/badge-tone.js +20 -0
  30. package/lib/ui/i18n.d.ts +4 -4
  31. package/lib/ui/i18n.js +8 -8
  32. package/lib/ui/rollback-view.d.ts +95 -0
  33. package/lib/ui/rollback-view.js +55 -0
  34. package/lib/ui/selection-model.d.ts +140 -1
  35. package/lib/ui/selection-model.js +241 -9
  36. package/package.json +1 -1
  37. package/src/adapters/plugin-data-declared.ts +60 -0
  38. package/src/adapters/plugin-data.ts +7 -33
  39. package/src/adapters/plugins.test.ts +162 -0
  40. package/src/adapters/plugins.ts +236 -17
  41. package/src/adapters/units.test.ts +26 -0
  42. package/src/client/chat/ChatEntryView.tsx +147 -46
  43. package/src/client/chat/chat-entry-view.test.ts +277 -1
  44. package/src/client/chat/chat-entry-view.ts +98 -4
  45. package/src/client/chat/chat-node-registration.ts +71 -0
  46. package/src/client/chat/chat-slots.ts +30 -12
  47. package/src/client/common/ContentPicker.tsx +581 -175
  48. package/src/client/common/host-primitives.ts +64 -1
  49. package/src/client/common/ui.tsx +17 -3
  50. package/src/client/config-manager.module.css +630 -397
  51. package/src/client/css-scale-guard.test.ts +41 -3
  52. package/src/client/css-token-guard.test.ts +10 -4
  53. package/src/client/export/ExportView.tsx +2 -0
  54. package/src/client/index.ts +15 -3
  55. package/src/client/locales.ts +54 -10
  56. package/src/client/recovery/RollbackCard.tsx +56 -2
  57. package/src/client/recovery/RollbackDiffPane.tsx +5 -0
  58. package/src/client/recovery/RollbackFileChanges.tsx +46 -2
  59. package/src/client/recovery/recovery-locales.ts +22 -0
  60. package/src/client/recovery/rollback-file-changes.test.ts +1 -1
  61. package/src/core/analyzer.ts +3 -1
  62. package/src/core/backup.ts +16 -1
  63. package/src/core/messages.ts +22 -0
  64. package/src/core/plugin-cli.fs.test.ts +65 -3
  65. package/src/core/plugin-cli.ts +55 -2
  66. package/src/core/rollback-attribution.test.ts +120 -0
  67. package/src/core/rollback-attribution.ts +267 -0
  68. package/src/core/rollback-merge.test.ts +133 -0
  69. package/src/core/rollback-merge.ts +213 -0
  70. package/src/core/rollback-point.test.ts +412 -0
  71. package/src/core/rollback-point.ts +560 -20
  72. package/src/core/types.ts +29 -0
  73. package/src/index.facade.test.ts +60 -0
  74. package/src/index.ts +133 -19
  75. package/src/routes/recovery.ts +11 -0
  76. package/src/schema/section-registry.ts +5 -5
  77. package/src/schema/types.ts +14 -0
  78. package/src/ui/badge-tone.test.ts +23 -0
  79. package/src/ui/badge-tone.ts +27 -0
  80. package/src/ui/i18n.ts +8 -8
  81. package/src/ui/rollback-view.test.ts +27 -0
  82. package/src/ui/rollback-view.ts +139 -0
  83. package/src/ui/selection-model.test.ts +240 -2
  84. package/src/ui/selection-model.ts +349 -1
@@ -31,7 +31,7 @@
31
31
  height: 100%;
32
32
  min-height: 0;
33
33
  font-family: var(--dsw-font-family);
34
- font-size: 12.5px;
34
+ font-size: var(--cm-fs-base);
35
35
  line-height: 1.5;
36
36
  color: var(--dsw-alias-label-primary);
37
37
  /* 弹窗内容区内的滚动包容:本组件自己管理滚动,不外溢 */
@@ -89,26 +89,77 @@ body {
89
89
  --cm-accent-fill: var(--dsw-alias-button-info-fill);
90
90
  --cm-accent-hover: var(--dsw-alias-button-info-hover);
91
91
  --cm-ok: var(--dsw-alias-state-success-primary);
92
- --cm-info: var(--dsw-alias-state-info-primary);
92
+ /* 2026-10-17 修正:DSH 主题**没有** --dsw-alias-state-info-primary 这个 token
93
+ (已对 ui-theme 产物逐条核对:四态只有 business / success / warn / error / idle)。
94
+ 原来指向它 ⇒ 自定义属性「无效于计算值」⇒ 三处 var(--cm-info) 消费点(任务面板底色、
95
+ 状态点、行首色条)静默退化成 unset/currentColor。DSH 的 info 语义就是 business 主色
96
+ (原生 Tag 的 info tone 用的也是 --dsw-alias-state-business-primary),故按同义别名接线。 */
97
+ --cm-info: var(--cm-accent);
93
98
  --cm-warn: var(--dsw-alias-state-warn-primary);
94
99
  --cm-error: var(--dsw-alias-state-error-primary);
95
- /* 字号 scale(4 档) */
96
- --cm-fs-meta: 11px;
97
- --cm-fs-table: 12px;
100
+ /* 原生「空转/中性」状态色(原生 StateDot 的 idle 档)与品牌色(原生 checkbox 的 accent-color) */
101
+ --cm-idle: var(--dsw-alias-state-idle-primary, var(--dsw-alias-label-tertiary));
102
+ --cm-brand: var(--dsw-alias-brand-primary, var(--cm-accent));
103
+ /* 深色 toast 表面上的警示文字色(原生为「toast 常驻深色」单独发布的 token) */
104
+ --cm-warn-label: var(--dsw-alias-state-warn-label, var(--cm-warn));
105
+ /* 字号 scale(4 档)—— **全部取自 DSH 原生字体 token**(2026-10-17 对齐原生):
106
+ · meta / table / title = 原生 11 / 12 / 13 档(--dsw-font-xxxs-11 / xxs-12 / xs-13),
107
+ 与 §3 的 4 档一一对应,取值未变(换的是来源,不是数值);
108
+ · base = 12.5px —— **本插件唯一一处刻意低于原生档的字号**:原生最小正文档是 13px
109
+ (--dsw-font-xs-13),而插件画布只有 564×720、要装下高密度表格与清单,
110
+ 故取「比原生最小正文再密半档」。它**不跟随**宿主的「内容字号」轴:那条轴属于
111
+ 宿主正文档位(默认 14),面板正文跟着放大反而会撑破画布。
112
+ (聊天内回退入口是另一回事:那里镜像宿主气泡,必须跟随宿主轴 —— 见 §15b。)
113
+ 改这一档 = 全站字号地震,非必要不动(chat-entry-view.test.ts ③ 钉住了这一点)。 */
114
+ --cm-fs-meta: var(--dsw-font-xxxs-11-font-size, 11px);
115
+ --cm-fs-table: var(--dsw-font-xxs-12-font-size, 12px);
98
116
  --cm-fs-base: 12.5px;
99
- --cm-fs-title: 13px;
117
+ --cm-fs-title: var(--dsw-font-xs-13-font-size, 13px);
100
118
  /* 间距 scale(9 档) */
101
119
  --cm-sp-1: 2px; --cm-sp-2: 4px; --cm-sp-3: 6px; --cm-sp-4: 8px; --cm-sp-5: 10px;
102
120
  --cm-sp-6: 12px; --cm-sp-7: 14px; --cm-sp-8: 16px; --cm-sp-9: 24px;
103
- /* 圆角 scale(4 档) */
104
- --cm-r-1: 4px; --cm-r-2: 6px; --cm-r-3: 8px; --cm-r-pill: 999px;
121
+ /* 圆角 scale(5 档)—— 派生自原生 control-radius scale(--dsw-radius-*),按**角色**挑档:
122
+ r-1 小标记(原生 radius-xs 4px)· r-2 紧凑控件(原生 radius-sm 8px,= 原生 .button.sm)·
123
+ r-3 行/卡片/输入(原生 radius-md 12px,= 原生菜单项与设置页输入框)·
124
+ r-surface 浮层表面(原生 radius-lg 16px,= 原生 MenuSurface)· r-pill 药丸。 */
125
+ --cm-r-1: var(--dsw-radius-xs, 4px);
126
+ --cm-r-2: var(--dsw-radius-sm, 8px);
127
+ --cm-r-3: var(--dsw-radius-md, 12px);
128
+ --cm-r-surface: var(--dsw-radius-lg, 16px);
129
+ --cm-r-pill: 999px;
105
130
  /* 控件高(3 档) */
106
131
  --cm-h-sm: 24px; --cm-h-md: 28px; --cm-h-lg: 32px;
107
- /* 阴影与焦点环 */
108
- --cm-shadow-1: 0 10px 26px color-mix(in srgb, var(--dsw-alias-bg-base) 45%, transparent);
109
- --cm-shadow-2: 0 12px 32px color-mix(in srgb, var(--dsw-alias-bg-base) 40%, transparent);
110
- --cm-ring: 0 0 0 2px color-mix(in srgb, var(--cm-accent) 18%, transparent);
111
- --cm-ring-strong: 0 0 0 2px color-mix(in srgb, var(--cm-accent) 55%, transparent);
132
+ /* —— 原生表面与交互态 token(2026-10-17 对齐原生)——
133
+ 浮层表面(菜单/提示/通知/遮罩)与交互态(hover/active/danger/ghost-active)
134
+ 一律取 DSH 原生同源 token:原生把这些语义各自发布了独立 token,
135
+ 直用它们才能在主题/皮肤切换时与宿主同步,而不是自己 mix 一个近似色。 */
136
+ --cm-menu-surface: var(--dsw-menu-surface-fill, var(--dsw-alias-bg-layer-2));
137
+ --cm-menu-backdrop: var(--dsw-menu-backdrop-filter, none);
138
+ --cm-menu-icon: var(--dsw-alias-menu-icon, var(--dsw-alias-label-secondary));
139
+ --cm-tooltip-bg: var(--dsw-alias-tooltip-bg, var(--dsw-alias-bg-layer-2));
140
+ --cm-tooltip-fg: var(--dsw-static-neutral-bluish-00, var(--dsw-alias-label-primary));
141
+ --cm-toast-bg: var(--dsw-alias-toast-bg, var(--dsw-alias-bg-layer-2));
142
+ --cm-toast-fg: var(--dsw-alias-toast-label, var(--dsw-alias-label-primary));
143
+ --cm-mask: var(--dsw-alias-bg-mask-1, color-mix(in srgb, var(--dsw-alias-bg-base) 55%, transparent));
144
+ --cm-mask-blur: var(--dsw-mask-blur, none);
145
+ --cm-skeleton: var(--dsw-alias-bg-skeleton, color-mix(in srgb, var(--dsw-alias-label-tertiary) 14%, transparent));
146
+ --cm-hover: var(--dsw-alias-interactive-bg-hover);
147
+ --cm-active: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-interactive-bg-hover));
148
+ --cm-hover-danger: var(--dsw-alias-interactive-bg-hover-danger, color-mix(in srgb, var(--cm-error) 12%, transparent));
149
+ --cm-ghost-active-fill: var(--dsw-alias-button-ghost-active-fill, color-mix(in srgb, var(--cm-accent) 16%, transparent));
150
+ --cm-ghost-active-border: var(--dsw-alias-button-ghost-active-border, color-mix(in srgb, var(--cm-accent) 45%, transparent));
151
+ --cm-primary-fill: var(--dsw-alias-button-primary-fill, var(--cm-accent-fill));
152
+ --cm-primary-hover: var(--dsw-alias-button-primary-hover, var(--cm-accent-hover));
153
+ /* 阴影与焦点环(原生 elevation / focus-ring token 同源) */
154
+ --cm-shadow-1: var(--dsw-elevation-soft, 0 10px 26px color-mix(in srgb, var(--dsw-alias-bg-base) 45%, transparent));
155
+ --cm-shadow-2: var(--dsw-elevation-prominent, 0 12px 32px color-mix(in srgb, var(--dsw-alias-bg-base) 40%, transparent));
156
+ /* 焦点环 = 宿主全局 :focus-visible 规则的**同一枚 token**:
157
+ 宿主在指针输入模态下把 --dsw-focus-ring-color 置为 transparent
158
+ (html[data-input-modality=pointer] body :focus-visible:not(:read-write)),
159
+ 所以鼠标点击不画环、键盘导航才画 —— 与原生组件完全一致;
160
+ 老宿主没有该 token 时回落主色 2px 环,不会丢掉可见焦点(可访问性兜底)。 */
161
+ --cm-focus-width: var(--dsw-focus-ring-width, 2px);
162
+ --cm-focus-color: var(--dsw-focus-ring-color, var(--cm-accent));
112
163
  /* 层级(6 档语义) */
113
164
  --cm-z-raise: 1; --cm-z-sticky: 2; --cm-z-task: 90; --cm-z-mask: 100;
114
165
  --cm-z-modal: 101; --cm-z-pop: 110; --cm-z-toast: 120;
@@ -133,7 +184,7 @@ body {
133
184
 
134
185
  /* 键盘焦点环:仅键盘导航(:focus-visible)触发 */
135
186
  .section :is(button, a, input, select, textarea, [role='tab']):focus-visible {
136
- outline: 2px solid var(--cm-accent);
187
+ outline: var(--cm-focus-width) solid var(--cm-focus-color);
137
188
  outline-offset: 2px;
138
189
  }
139
190
 
@@ -172,9 +223,9 @@ body {
172
223
  flex: 1 1 auto;
173
224
  min-width: 0;
174
225
  padding: 2px;
175
- border: 1px solid var(--dsw-alias-border-l1);
176
- border-radius: 8px;
177
- background: var(--dsw-alias-bg-layer-2);
226
+ border: none;
227
+ border-radius: var(--cm-r-3);
228
+ background: var(--cm-hover);
178
229
  /* 不横向滚动:放不下的项由 ui/nav-model.ts 移进「更多 ▾」,不会藏在视口外。
179
230
  overflow: hidden 只是防极端情况(量测失败)撑破宿主布局,正常路径下从不触发。 */
180
231
  overflow: hidden;
@@ -196,10 +247,10 @@ body {
196
247
  height: 24px;
197
248
  padding: 0 10px;
198
249
  border: none;
199
- border-radius: 6px;
250
+ border-radius: var(--cm-r-2);
200
251
  background: none;
201
252
  font: inherit;
202
- font-size: 12px;
253
+ font-size: var(--cm-fs-table);
203
254
  font-weight: 500;
204
255
  color: var(--dsw-alias-label-secondary);
205
256
  cursor: pointer;
@@ -214,15 +265,15 @@ body {
214
265
 
215
266
  .navTab:focus-visible,
216
267
  .navMore:focus-visible {
217
- outline: 2px solid var(--cm-accent);
268
+ outline: var(--cm-focus-width) solid var(--cm-focus-color);
218
269
  outline-offset: 1px;
219
- border-radius: 6px;
270
+ border-radius: var(--cm-r-2);
220
271
  }
221
272
 
222
273
  .navTab[data-active],
223
274
  .navMore[data-active] {
224
- background: color-mix(in srgb, var(--cm-accent) 16%, transparent);
225
- box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--cm-accent) 45%, transparent);
275
+ background: var(--cm-ghost-active-fill);
276
+ box-shadow: inset 0 0 0 1px var(--cm-ghost-active-border);
226
277
  color: var(--dsw-alias-label-primary);
227
278
  font-weight: 600;
228
279
  }
@@ -278,14 +329,14 @@ body {
278
329
  display: inline-flex;
279
330
  align-items: center;
280
331
  justify-content: center;
281
- width: 26px;
282
- height: 26px;
332
+ width: 28px;
333
+ height: 28px;
283
334
  padding: 0;
284
335
  border: none;
285
- border-radius: 6px;
336
+ border-radius: var(--cm-r-2);
286
337
  background: none;
287
338
  font: inherit;
288
- font-size: 13px;
339
+ font-size: var(--cm-fs-title);
289
340
  line-height: 1.25;
290
341
  color: var(--dsw-alias-label-secondary);
291
342
  cursor: pointer;
@@ -293,17 +344,17 @@ body {
293
344
  }
294
345
 
295
346
  .iconBtn:hover {
296
- background: var(--dsw-alias-interactive-bg-hover);
347
+ background: var(--cm-hover);
297
348
  color: var(--dsw-alias-label-primary);
298
349
  }
299
350
 
300
351
  .iconBtn:focus-visible {
301
- outline: 2px solid var(--cm-accent);
352
+ outline: var(--cm-focus-width) solid var(--cm-focus-color);
302
353
  outline-offset: 1px;
303
354
  }
304
355
 
305
356
  .iconBtn:disabled {
306
- opacity: 0.45;
357
+ opacity: 0.4;
307
358
  cursor: default;
308
359
  }
309
360
 
@@ -312,11 +363,12 @@ body {
312
363
  .iconBtn[data-size='sm'] {
313
364
  width: 18px;
314
365
  height: 18px;
315
- border-radius: 4px;
366
+ border-radius: var(--cm-r-1);
316
367
  }
317
368
 
318
369
  .iconBtn[data-active] {
319
- background: color-mix(in srgb, var(--cm-accent) 14%, transparent);
370
+ background: var(--cm-ghost-active-fill);
371
+ box-shadow: inset 0 0 0 1px var(--cm-ghost-active-border);
320
372
  color: var(--cm-accent);
321
373
  }
322
374
 
@@ -469,7 +521,7 @@ body {
469
521
  }
470
522
 
471
523
  .taskTitle {
472
- font-size: 13px;
524
+ font-size: var(--cm-fs-title);
473
525
  font-weight: 700;
474
526
  color: var(--dsw-alias-label-primary);
475
527
  min-width: 0;
@@ -500,9 +552,9 @@ body {
500
552
  margin: 0 8px 8px;
501
553
  padding: 0 10px;
502
554
  border: 1px solid var(--dsw-alias-border-l1);
503
- border-radius: 8px;
555
+ border-radius: var(--cm-r-3);
504
556
  background: var(--dsw-alias-bg-layer-2);
505
- font-size: 11px;
557
+ font-size: var(--cm-fs-meta);
506
558
  color: var(--dsw-alias-label-tertiary);
507
559
  white-space: nowrap;
508
560
  overflow: hidden;
@@ -562,35 +614,46 @@ body {
562
614
 
563
615
  .statusDot {
564
616
  display: inline-block;
565
- width: 7px;
566
- height: 7px;
617
+ width: 10px;
618
+ height: 10px;
567
619
  border-radius: 50%;
568
- background: var(--dsw-alias-label-tertiary);
620
+ /* 原生 StateDot 几何:10px 槽位里画一枚 6px 实心核(inset 20%),色走 currentColor */
621
+ color: var(--cm-idle);
569
622
  flex: none;
570
623
  /* 状态色随任务起停切换(idle → info → ok):瞬变像「闪了一下」。 */
571
- transition: background-color var(--cm-motion-fast) ease;
624
+ transition: color var(--cm-motion-fast) ease;
572
625
  }
573
626
 
574
627
  .statusDot[data-kind='ok'] {
575
- background: var(--cm-ok);
628
+ color: var(--cm-ok);
576
629
  }
577
630
 
578
631
  .statusDot[data-kind='info'] {
579
- background: var(--cm-accent);
632
+ color: var(--cm-accent);
580
633
  }
581
634
 
582
635
  .statusDot[data-kind='warn'] {
583
- background: var(--cm-warn);
636
+ color: var(--cm-warn);
584
637
  }
585
638
 
586
639
  .statusDot[data-kind='error'] {
587
- background: var(--cm-error);
640
+ color: var(--cm-error);
588
641
  }
589
642
 
590
643
  .statusDot[data-pulse] {
591
644
  animation: statusPulse 1.2s ease-in-out infinite;
592
645
  }
593
646
 
647
+ .statusDot::after {
648
+ content: '';
649
+ display: block;
650
+ width: 60%;
651
+ height: 60%;
652
+ margin: 20%;
653
+ border-radius: 50%;
654
+ background: currentColor;
655
+ }
656
+
594
657
  @keyframes statusPulse {
595
658
  0%, 100% { opacity: 1; }
596
659
  50% { opacity: 0.35; }
@@ -621,14 +684,14 @@ body {
621
684
  display: inline-flex;
622
685
  align-items: center;
623
686
  justify-content: center;
624
- gap: 6px;
687
+ gap: 4px;
625
688
  height: 28px;
626
- padding: 0 12px;
627
- border-radius: 6px;
628
- border: 1px solid transparent;
689
+ padding: 0 10px;
690
+ border-radius: var(--cm-r-2);
691
+ border: 0.5px solid transparent;
629
692
  font: inherit;
630
- font-size: 12.5px;
631
- font-weight: 600;
693
+ font-size: var(--cm-fs-table);
694
+ font-weight: 500;
632
695
  line-height: 1.25;
633
696
  white-space: nowrap;
634
697
  cursor: pointer;
@@ -636,22 +699,27 @@ body {
636
699
  }
637
700
 
638
701
  .primaryButton {
639
- background: var(--cm-accent-fill);
702
+ background: var(--cm-primary-fill);
640
703
  color: var(--cm-text-on-accent);
641
704
  }
642
705
 
643
706
  .primaryButton:hover:not(:disabled) {
644
- background: var(--cm-accent-hover);
707
+ background: var(--cm-primary-hover);
645
708
  }
646
709
 
647
710
  .ghostButton {
648
711
  background: transparent;
649
- border-color: var(--dsw-alias-border-l2);
712
+ border-color: var(--dsw-alias-border-l3);
650
713
  color: var(--dsw-alias-label-primary);
651
714
  }
652
715
 
653
716
  .ghostButton:hover:not(:disabled) {
654
- background: var(--dsw-alias-interactive-bg-hover);
717
+ background: var(--cm-hover);
718
+ }
719
+
720
+ /* 按下态:原生 .button.ghost:active 的 interactive-bg-active */
721
+ .ghostButton:active:not(:disabled) {
722
+ background: var(--cm-active);
655
723
  }
656
724
 
657
725
  .dangerButton {
@@ -661,21 +729,21 @@ body {
661
729
  }
662
730
 
663
731
  .dangerButton:hover:not(:disabled) {
664
- background: color-mix(in srgb, var(--cm-error) 12%, transparent);
732
+ background: var(--cm-hover-danger);
665
733
  border-color: var(--cm-error);
666
734
  }
667
735
 
668
736
  .primaryButton:focus-visible,
669
737
  .ghostButton:focus-visible,
670
738
  .dangerButton:focus-visible {
671
- outline: 2px solid var(--cm-accent);
739
+ outline: var(--cm-focus-width) solid var(--cm-focus-color);
672
740
  outline-offset: 1px;
673
741
  }
674
742
 
675
743
  .primaryButton:disabled,
676
744
  .ghostButton:disabled,
677
745
  .dangerButton:disabled {
678
- opacity: 0.45;
746
+ opacity: 0.4;
679
747
  cursor: default;
680
748
  }
681
749
 
@@ -685,19 +753,19 @@ body {
685
753
  .dangerButton[data-size='sm'] {
686
754
  height: 24px;
687
755
  padding: 0 8px;
688
- font-size: 11px;
689
- border-radius: 6px;
756
+ font-size: var(--cm-fs-meta);
757
+ border-radius: var(--cm-r-2);
690
758
  }
691
759
 
692
760
  /* —— 输入 / 选择 —— */
693
761
  .input {
694
762
  height: 28px;
695
763
  padding: 0 8px;
696
- border: 1px solid var(--dsw-alias-border-l2);
697
- border-radius: 6px;
764
+ border: 0.5px solid var(--dsw-alias-border-l4);
765
+ border-radius: var(--cm-r-2);
698
766
  background: var(--dsw-specific-input-major);
699
767
  font: inherit;
700
- font-size: 12.5px;
768
+ font-size: var(--cm-fs-base);
701
769
  color: var(--dsw-alias-label-primary);
702
770
  box-sizing: border-box;
703
771
  }
@@ -713,7 +781,7 @@ body {
713
781
  }
714
782
 
715
783
  .input::placeholder {
716
- color: var(--dsw-alias-label-tertiary);
784
+ color: var(--dsw-alias-label-dimmed);
717
785
  }
718
786
 
719
787
  .input:hover {
@@ -723,18 +791,17 @@ body {
723
791
  .input:focus {
724
792
  outline: none;
725
793
  border-color: var(--cm-accent);
726
- box-shadow: 0 0 0 2px color-mix(in srgb, var(--cm-accent) 18%, transparent);
727
794
  }
728
795
 
729
796
  .input:disabled {
730
- opacity: 0.5;
797
+ color: var(--dsw-alias-label-tertiary);
731
798
  cursor: default;
732
799
  }
733
800
 
734
801
  /* 密码/路径输入(等宽利于核对) */
735
802
  .input[type='password'] {
736
803
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
737
- font-size: 12px;
804
+ font-size: var(--cm-fs-table);
738
805
  }
739
806
 
740
807
  /* —— 自定义下拉(common/Select.tsx) ——
@@ -748,7 +815,7 @@ body {
748
815
  max-width: 100%;
749
816
  min-width: 0;
750
817
  vertical-align: middle;
751
- font-size: 12.5px;
818
+ font-size: var(--cm-fs-base);
752
819
  }
753
820
 
754
821
  .selectTrigger {
@@ -759,11 +826,11 @@ body {
759
826
  height: 28px;
760
827
  padding: 0 8px;
761
828
  box-sizing: border-box;
762
- border: 1px solid var(--dsw-alias-border-l2);
763
- border-radius: 6px;
829
+ border: 0.5px solid var(--dsw-alias-border-l4);
830
+ border-radius: var(--cm-r-2);
764
831
  background: var(--dsw-specific-input-major);
765
832
  font: inherit;
766
- font-size: 12.5px;
833
+ font-size: var(--cm-fs-base);
767
834
  color: var(--dsw-alias-label-primary);
768
835
  text-align: left;
769
836
  cursor: pointer;
@@ -781,11 +848,10 @@ body {
781
848
  .selectRoot[data-open] .selectTrigger {
782
849
  outline: none;
783
850
  border-color: var(--cm-accent);
784
- box-shadow: 0 0 0 2px color-mix(in srgb, var(--cm-accent) 18%, transparent);
785
851
  }
786
852
 
787
853
  .selectTrigger:disabled {
788
- opacity: 0.5;
854
+ color: var(--dsw-alias-label-tertiary);
789
855
  cursor: default;
790
856
  }
791
857
 
@@ -828,10 +894,11 @@ body {
828
894
  overflow-y: auto;
829
895
  overscroll-behavior: contain;
830
896
  padding: 4px;
831
- border: 1px solid var(--dsw-alias-border-l2);
832
- border-radius: 8px;
833
- background: var(--dsw-alias-bg-layer-2);
834
- box-shadow: 0 10px 26px color-mix(in srgb, var(--dsw-alias-bg-base) 45%, transparent);
897
+ border: 0;
898
+ border-radius: var(--cm-r-surface);
899
+ background: var(--cm-menu-surface);
900
+ backdrop-filter: var(--cm-menu-backdrop);
901
+ box-shadow: var(--cm-shadow-2);
835
902
  transform-origin: top center;
836
903
  animation: selectMenuIn var(--cm-motion-fast) var(--cm-motion-ease-out);
837
904
  }
@@ -878,14 +945,14 @@ body {
878
945
  align-items: center;
879
946
  gap: 8px;
880
947
  padding: 6px 8px;
881
- border-radius: 6px;
882
- font-size: 12.5px;
948
+ border-radius: var(--cm-r-3);
949
+ font-size: var(--cm-fs-base);
883
950
  color: var(--dsw-alias-label-primary);
884
951
  cursor: pointer;
885
952
  }
886
953
 
887
954
  .selectOption[data-active] {
888
- background: var(--dsw-alias-interactive-bg-hover);
955
+ background: var(--cm-hover);
889
956
  }
890
957
 
891
958
  /* 选中项:主色文字 + 左侧主色竖条(此前用右侧对勾,用户要求移除该图标)。
@@ -894,12 +961,12 @@ body {
894
961
  .selectOption[aria-checked='true'] {
895
962
  color: var(--cm-accent);
896
963
  font-weight: 600;
897
- background: color-mix(in srgb, var(--cm-accent) 10%, transparent);
964
+ background: var(--cm-ghost-active-fill);
898
965
  box-shadow: inset 2px 0 0 var(--cm-accent);
899
966
  }
900
967
 
901
968
  .selectOption[data-disabled] {
902
- opacity: 0.45;
969
+ opacity: 0.4;
903
970
  cursor: default;
904
971
  }
905
972
 
@@ -920,7 +987,7 @@ body {
920
987
  margin-top: 8px;
921
988
  padding: 2px;
922
989
  border: 1px solid var(--dsw-alias-border-l1);
923
- border-radius: 8px;
990
+ border-radius: var(--cm-r-3);
924
991
  background: var(--dsw-alias-bg-layer-2);
925
992
  overflow: hidden;
926
993
  }
@@ -933,10 +1000,10 @@ body {
933
1000
  height: 24px;
934
1001
  padding: 0 8px;
935
1002
  border: none;
936
- border-radius: 6px;
1003
+ border-radius: var(--cm-r-2);
937
1004
  background: none;
938
1005
  font: inherit;
939
- font-size: 12px;
1006
+ font-size: var(--cm-fs-table);
940
1007
  color: var(--dsw-alias-label-secondary);
941
1008
  cursor: pointer;
942
1009
  white-space: nowrap;
@@ -955,7 +1022,7 @@ body {
955
1022
 
956
1023
  /* 计数:只在对应来源加载成功后渲染(加载中/失败时整个不出现,绝不显示 0) */
957
1024
  .libraryFilterCount {
958
- font-size: 11px;
1025
+ font-size: var(--cm-fs-meta);
959
1026
  color: var(--dsw-alias-label-tertiary);
960
1027
  }
961
1028
 
@@ -971,10 +1038,10 @@ body {
971
1038
  margin-top: 8px;
972
1039
  padding: 0 8px;
973
1040
  border: 1px solid var(--dsw-alias-border-l2);
974
- border-radius: 6px;
1041
+ border-radius: var(--cm-r-2);
975
1042
  background: var(--dsw-specific-input-major);
976
1043
  font: inherit;
977
- font-size: 12.5px;
1044
+ font-size: var(--cm-fs-base);
978
1045
  color: var(--dsw-alias-label-primary);
979
1046
  }
980
1047
 
@@ -996,7 +1063,7 @@ body {
996
1063
  }
997
1064
 
998
1065
  .libraryCount {
999
- font-size: 12px;
1066
+ font-size: var(--cm-fs-table);
1000
1067
  color: var(--dsw-alias-label-secondary);
1001
1068
  }
1002
1069
 
@@ -1066,14 +1133,14 @@ body {
1066
1133
  height: 20px;
1067
1134
  padding: 0;
1068
1135
  border: none;
1069
- border-radius: 4px;
1136
+ border-radius: var(--cm-r-1);
1070
1137
  background: none;
1071
1138
  color: var(--dsw-alias-label-secondary);
1072
1139
  cursor: pointer;
1073
1140
  }
1074
1141
 
1075
1142
  .artifactExpand:focus-visible {
1076
- outline: 2px solid var(--cm-accent);
1143
+ outline: var(--cm-focus-width) solid var(--cm-focus-color);
1077
1144
  outline-offset: 1px;
1078
1145
  }
1079
1146
 
@@ -1090,7 +1157,7 @@ body {
1090
1157
  }
1091
1158
 
1092
1159
  .artifactName {
1093
- font-size: 12.5px;
1160
+ font-size: var(--cm-fs-base);
1094
1161
  font-weight: 600;
1095
1162
  color: var(--dsw-alias-label-primary);
1096
1163
  overflow: hidden;
@@ -1100,7 +1167,7 @@ body {
1100
1167
 
1101
1168
  .artifactMeta {
1102
1169
  margin-top: 2px;
1103
- font-size: 11px;
1170
+ font-size: var(--cm-fs-meta);
1104
1171
  color: var(--dsw-alias-label-tertiary);
1105
1172
  overflow: hidden;
1106
1173
  text-overflow: ellipsis;
@@ -1169,10 +1236,10 @@ body {
1169
1236
  height: 32px;
1170
1237
  padding: 0 10px;
1171
1238
  border: 1px solid var(--dsw-alias-border-l2);
1172
- border-radius: 6px;
1239
+ border-radius: var(--cm-r-2);
1173
1240
  background: var(--dsw-specific-input-major);
1174
1241
  font: inherit;
1175
- font-size: 13px;
1242
+ font-size: var(--cm-fs-title);
1176
1243
  color: var(--dsw-alias-label-primary);
1177
1244
  }
1178
1245
 
@@ -1196,7 +1263,7 @@ body {
1196
1263
  所以比条目更小、更淡、不可选中,且每个非首组先起一条分隔线 —— 标题与条目不再同节奏排列。 */
1197
1264
  .paletteGroup {
1198
1265
  padding: 8px 8px 4px;
1199
- font-size: 11px;
1266
+ font-size: var(--cm-fs-meta);
1200
1267
  font-weight: 500;
1201
1268
  letter-spacing: 0.02em;
1202
1269
  color: var(--dsw-alias-label-tertiary);
@@ -1213,8 +1280,8 @@ body {
1213
1280
  align-items: center;
1214
1281
  gap: 8px;
1215
1282
  padding: 6px 8px;
1216
- border-radius: 6px;
1217
- font-size: 12.5px;
1283
+ border-radius: var(--cm-r-2);
1284
+ font-size: var(--cm-fs-base);
1218
1285
  color: var(--dsw-alias-label-primary);
1219
1286
  cursor: pointer;
1220
1287
  }
@@ -1239,13 +1306,13 @@ body {
1239
1306
 
1240
1307
  .paletteItemGroup {
1241
1308
  flex: none;
1242
- font-size: 11px;
1309
+ font-size: var(--cm-fs-meta);
1243
1310
  color: var(--dsw-alias-label-tertiary);
1244
1311
  }
1245
1312
 
1246
1313
  .paletteEmpty {
1247
1314
  padding: 10px 8px;
1248
- font-size: 12.5px;
1315
+ font-size: var(--cm-fs-base);
1249
1316
  color: var(--dsw-alias-label-tertiary);
1250
1317
  }
1251
1318
 
@@ -1253,7 +1320,7 @@ body {
1253
1320
  margin-top: 8px;
1254
1321
  padding-top: 6px;
1255
1322
  border-top: 1px solid var(--dsw-alias-border-l1);
1256
- font-size: 11px;
1323
+ font-size: var(--cm-fs-meta);
1257
1324
  color: var(--dsw-alias-label-tertiary);
1258
1325
  }
1259
1326
 
@@ -1264,23 +1331,23 @@ body {
1264
1331
  align-items: flex-start;
1265
1332
  gap: 6px;
1266
1333
  cursor: pointer;
1267
- font-size: 12.5px;
1334
+ font-size: var(--cm-fs-base);
1268
1335
  color: var(--dsw-alias-label-primary);
1269
1336
  }
1270
1337
 
1271
1338
  .checkboxRow input,
1272
1339
  .radioLabel input {
1273
- width: 14px;
1274
- height: 14px;
1340
+ width: 16px;
1341
+ height: 16px;
1275
1342
  margin: 2px 0 0;
1276
- accent-color: var(--cm-accent);
1343
+ accent-color: var(--cm-brand);
1277
1344
  cursor: pointer;
1278
1345
  flex: none;
1279
1346
  }
1280
1347
 
1281
1348
  .checkboxRow input:focus-visible,
1282
1349
  .radioLabel input:focus-visible {
1283
- outline: 2px solid var(--cm-accent);
1350
+ outline: var(--cm-focus-width) solid var(--cm-focus-color);
1284
1351
  outline-offset: 2px;
1285
1352
  }
1286
1353
 
@@ -1289,15 +1356,44 @@ body {
1289
1356
  display: inline-flex;
1290
1357
  align-items: center;
1291
1358
  gap: 4px;
1292
- height: 18px;
1293
- padding: 0 6px;
1294
- border-radius: 8px;
1295
- font-size: 11px;
1296
- font-weight: 600;
1359
+ height: 19px;
1360
+ padding: 0 8px;
1361
+ border-radius: var(--cm-r-pill);
1362
+ font-size: var(--cm-fs-meta);
1363
+ font-weight: 500;
1297
1364
  line-height: 1.25;
1298
1365
  white-space: nowrap;
1299
- border: 1px solid var(--dsw-alias-border-l2);
1300
- color: var(--dsw-alias-label-secondary);
1366
+ border: none;
1367
+ color: var(--dsw-alias-label-tertiary);
1368
+ }
1369
+
1370
+ /* 四态 tone:与原生 Tag 同口径(同色 10% tint 作底,warning 用 12%)。
1371
+ 此前 ui.tsx 计算的 badgeOk/badgeInfo/... 类名在本表里**从未存在**,四态徽章看起来完全一样。 */
1372
+ .badge[data-kind='ok'] {
1373
+ background: color-mix(in srgb, var(--cm-ok) 10%, transparent);
1374
+ color: var(--cm-ok);
1375
+ }
1376
+
1377
+ .badge[data-kind='info'] {
1378
+ background: color-mix(in srgb, var(--cm-accent) 10%, transparent);
1379
+ color: var(--cm-accent);
1380
+ }
1381
+
1382
+ .badge[data-kind='warn'] {
1383
+ background: color-mix(in srgb, var(--cm-warn) 12%, transparent);
1384
+ color: var(--cm-warn);
1385
+ }
1386
+
1387
+ .badge[data-kind='error'] {
1388
+ background: color-mix(in srgb, var(--cm-error) 10%, transparent);
1389
+ color: var(--cm-error);
1390
+ }
1391
+
1392
+ /* 原生 Tag 路径下的 wrapper:只为承载 title 悬停提示(原生 Tag 不接受 title),
1393
+ 自身不产生盒模型效果(inline-flex 与 Tag 自身的 inline-flex 同形)。 */
1394
+ .badgeHost {
1395
+ display: inline-flex;
1396
+ align-items: center;
1301
1397
  }
1302
1398
 
1303
1399
  /* —— 横幅(四态;紧凑) —— */
@@ -1308,10 +1404,10 @@ body {
1308
1404
  flex-wrap: wrap;
1309
1405
  gap: 6px 10px;
1310
1406
  padding: 8px 12px;
1311
- border-radius: 8px;
1312
- border: 1px solid var(--dsw-alias-border-l2);
1407
+ border-radius: var(--cm-r-3);
1408
+ border: 0.5px solid var(--dsw-alias-border-l2);
1313
1409
  background: var(--dsw-alias-bg-layer-2);
1314
- font-size: 12.5px;
1410
+ font-size: var(--cm-fs-base);
1315
1411
  margin: 0 0 10px;
1316
1412
  /* 通栏元素:flex 父容器(.viewBody 等)里不随内容收缩 */
1317
1413
  width: 100%;
@@ -1320,22 +1416,22 @@ body {
1320
1416
 
1321
1417
  .banner[data-kind='ok'] {
1322
1418
  border-color: color-mix(in srgb, var(--cm-ok) 35%, transparent);
1323
- background: color-mix(in srgb, var(--cm-ok) 9%, transparent);
1419
+ background: color-mix(in srgb, var(--cm-ok) 10%, transparent);
1324
1420
  }
1325
1421
 
1326
1422
  .banner[data-kind='info'] {
1327
1423
  border-color: color-mix(in srgb, var(--cm-accent) 30%, transparent);
1328
- background: color-mix(in srgb, var(--cm-accent) 8%, transparent);
1424
+ background: color-mix(in srgb, var(--cm-accent) 10%, transparent);
1329
1425
  }
1330
1426
 
1331
1427
  .banner[data-kind='warn'] {
1332
1428
  border-color: color-mix(in srgb, var(--cm-warn) 40%, transparent);
1333
- background: color-mix(in srgb, var(--cm-warn) 9%, transparent);
1429
+ background: color-mix(in srgb, var(--cm-warn) 12%, transparent);
1334
1430
  }
1335
1431
 
1336
1432
  .banner[data-kind='error'] {
1337
1433
  border-color: color-mix(in srgb, var(--cm-error) 45%, transparent);
1338
- background: color-mix(in srgb, var(--cm-error) 9%, transparent);
1434
+ background: color-mix(in srgb, var(--cm-error) 10%, transparent);
1339
1435
  }
1340
1436
 
1341
1437
  /* —— Spinner —— */
@@ -1387,7 +1483,7 @@ body {
1387
1483
  }
1388
1484
 
1389
1485
  .spinnerLabel {
1390
- font-size: 12px;
1486
+ font-size: var(--cm-fs-table);
1391
1487
  /* 跟随所在上下文的前景色(主色按钮上是前景白),略带降权但不至于读不出来 */
1392
1488
  color: inherit;
1393
1489
  opacity: 0.85;
@@ -1414,8 +1510,8 @@ body {
1414
1510
 
1415
1511
  .skeletonBar {
1416
1512
  display: block;
1417
- border-radius: 4px;
1418
- background-color: color-mix(in srgb, var(--dsw-alias-label-tertiary) 14%, transparent);
1513
+ border-radius: var(--cm-r-1);
1514
+ background-color: var(--cm-skeleton);
1419
1515
  background-image: linear-gradient(
1420
1516
  90deg,
1421
1517
  transparent,
@@ -1433,10 +1529,10 @@ body {
1433
1529
  }
1434
1530
 
1435
1531
  /* 形态:标题 / 正文行 / 区块 / 行条目 */
1436
- .skeletonTitle { height: 13px; width: 42%; border-radius: 6px; }
1532
+ .skeletonTitle { height: 13px; width: 42%; border-radius: var(--cm-r-2); }
1437
1533
  .skeletonLine { height: 11px; }
1438
- .skeletonBlock { height: 46px; border-radius: 8px; }
1439
- .skeletonRow { height: 30px; border-radius: 6px; }
1534
+ .skeletonBlock { height: 46px; border-radius: var(--cm-r-3); }
1535
+ .skeletonRow { height: 30px; border-radius: var(--cm-r-2); }
1440
1536
 
1441
1537
  /* 多行骨架的长短交错(全等宽看起来像表格)+ 逐条递进延迟(像正在逐块填充,而不是整块齐闪) */
1442
1538
  .skeletonBars > .skeletonBar:nth-child(4n + 2) { width: 92%; }
@@ -1454,7 +1550,7 @@ body {
1454
1550
  gap: 8px;
1455
1551
  padding: 12px;
1456
1552
  border: 1px solid var(--dsw-alias-border-l1);
1457
- border-radius: 8px;
1553
+ border-radius: var(--cm-r-3);
1458
1554
  background: var(--dsw-alias-bg-layer-2);
1459
1555
  }
1460
1556
 
@@ -1464,7 +1560,7 @@ body {
1464
1560
  /* 表格骨架:行高/内边距对齐 .dataTable,三列按「名称 / 说明 / 时间」分配宽度 */
1465
1561
  .skeletonTable {
1466
1562
  border: 1px solid var(--dsw-alias-border-l1);
1467
- border-radius: 8px;
1563
+ border-radius: var(--cm-r-3);
1468
1564
  overflow: hidden;
1469
1565
  }
1470
1566
 
@@ -1495,7 +1591,7 @@ body {
1495
1591
 
1496
1592
  /* 骨架下方的可见文案(与 Spinner 的 label 同义):加载反馈必须能被读到,不只靠色块 */
1497
1593
  .skeletonCaption {
1498
- font-size: 11px;
1594
+ font-size: var(--cm-fs-meta);
1499
1595
  color: var(--dsw-alias-label-tertiary);
1500
1596
  }
1501
1597
 
@@ -1503,7 +1599,7 @@ body {
1503
1599
 
1504
1600
  .card {
1505
1601
  border: 1px solid var(--dsw-alias-border-l1);
1506
- border-radius: 8px;
1602
+ border-radius: var(--cm-r-3);
1507
1603
  background: var(--dsw-alias-bg-layer-2);
1508
1604
  padding: 12px;
1509
1605
  margin: 0 0 10px;
@@ -1512,7 +1608,7 @@ body {
1512
1608
  /* 分组标题(卡内小节头) */
1513
1609
  .groupLabel {
1514
1610
  display: block;
1515
- font-size: 11px;
1611
+ font-size: var(--cm-fs-meta);
1516
1612
  font-weight: 700;
1517
1613
  letter-spacing: 0.02em;
1518
1614
  color: var(--dsw-alias-label-tertiary);
@@ -1534,7 +1630,7 @@ body {
1534
1630
  }
1535
1631
 
1536
1632
  .groupNote {
1537
- font-size: 11px;
1633
+ font-size: var(--cm-fs-meta);
1538
1634
  color: var(--dsw-alias-label-tertiary);
1539
1635
  }
1540
1636
 
@@ -1562,19 +1658,19 @@ body {
1562
1658
  }
1563
1659
 
1564
1660
  .fieldLabel {
1565
- font-size: 11px;
1661
+ font-size: var(--cm-fs-meta);
1566
1662
  font-weight: 600;
1567
1663
  color: var(--dsw-alias-label-secondary);
1568
1664
  }
1569
1665
 
1570
1666
  .hint {
1571
- font-size: 11px;
1667
+ font-size: var(--cm-fs-meta);
1572
1668
  line-height: 1.5;
1573
1669
  color: var(--dsw-alias-label-tertiary);
1574
1670
  }
1575
1671
 
1576
1672
  .formError {
1577
- font-size: 11px;
1673
+ font-size: var(--cm-fs-meta);
1578
1674
  color: var(--cm-error);
1579
1675
  }
1580
1676
 
@@ -1602,7 +1698,7 @@ body {
1602
1698
  height: 18px;
1603
1699
  padding: 0;
1604
1700
  border: none;
1605
- border-radius: 4px;
1701
+ border-radius: var(--cm-r-1);
1606
1702
  background: none;
1607
1703
  font: inherit;
1608
1704
  line-height: 1.25;
@@ -1623,7 +1719,7 @@ body {
1623
1719
  那条路径下气泡不会打开(见 InfoHint.tsx 的 onFocus)—— 于是焦点环与 data-open 同进同出:
1624
1720
  键盘用户 Tab 到 ⓘ 时气泡必然同时打开,焦点环照常可见,可访问性不受影响。 */
1625
1721
  .infoHintBtn[data-open]:focus-visible {
1626
- outline: 2px solid var(--cm-accent);
1722
+ outline: var(--cm-focus-width) solid var(--cm-focus-color);
1627
1723
  outline-offset: 1px;
1628
1724
  }
1629
1725
 
@@ -1650,12 +1746,12 @@ body {
1650
1746
  max-height: min(480px, calc(100vh - 16px));
1651
1747
  overflow-y: auto;
1652
1748
  padding: 8px 10px;
1653
- border: 1px solid var(--dsw-alias-border-l2);
1654
- border-radius: 8px;
1655
- background: var(--dsw-alias-bg-layer-2);
1656
- box-shadow: 0 10px 26px color-mix(in srgb, var(--dsw-alias-bg-base) 45%, transparent);
1657
- color: var(--dsw-alias-label-secondary);
1658
- font-size: 11px;
1749
+ border: 0;
1750
+ border-radius: var(--cm-r-2);
1751
+ background: var(--cm-tooltip-bg);
1752
+ box-shadow: var(--cm-shadow-1);
1753
+ color: var(--cm-tooltip-fg);
1754
+ font-size: var(--cm-fs-table);
1659
1755
  line-height: 1.5;
1660
1756
  /* 多行换行:长文本折行、显式换行符保留,绝不省略号截断 */
1661
1757
  white-space: pre-wrap;
@@ -1711,7 +1807,7 @@ body {
1711
1807
 
1712
1808
  .sectionTitle {
1713
1809
  margin: 0;
1714
- font-size: 13px;
1810
+ font-size: var(--cm-fs-title);
1715
1811
  font-weight: 700;
1716
1812
  line-height: 1.5;
1717
1813
  color: var(--dsw-alias-label-primary);
@@ -1719,7 +1815,7 @@ body {
1719
1815
 
1720
1816
  .sectionSubtitle {
1721
1817
  margin: 1px 0 0;
1722
- font-size: 11px;
1818
+ font-size: var(--cm-fs-meta);
1723
1819
  color: var(--dsw-alias-label-tertiary);
1724
1820
  }
1725
1821
 
@@ -1733,9 +1829,9 @@ body {
1733
1829
  gap: 4px;
1734
1830
  padding: 24px 16px;
1735
1831
  border: 1px dashed var(--dsw-alias-border-l2);
1736
- border-radius: 8px;
1832
+ border-radius: var(--cm-r-3);
1737
1833
  text-align: center;
1738
- font-size: 12px;
1834
+ font-size: var(--cm-fs-table);
1739
1835
  color: var(--dsw-alias-label-tertiary);
1740
1836
  /* 通栏占位:不被 flex 父容器压成内容宽 */
1741
1837
  width: 100%;
@@ -1752,7 +1848,7 @@ body {
1752
1848
  /* —— 数据表 —— */
1753
1849
  .tableWrap {
1754
1850
  border: 1px solid var(--dsw-alias-border-l1);
1755
- border-radius: 8px;
1851
+ border-radius: var(--cm-r-3);
1756
1852
  background: var(--dsw-alias-bg-layer-2);
1757
1853
  overflow: hidden;
1758
1854
  margin-bottom: 10px;
@@ -1774,7 +1870,7 @@ body {
1774
1870
  .dataTable {
1775
1871
  width: 100%;
1776
1872
  border-collapse: collapse;
1777
- font-size: 12px;
1873
+ font-size: var(--cm-fs-table);
1778
1874
  }
1779
1875
 
1780
1876
  .dataTable th,
@@ -1810,17 +1906,17 @@ body {
1810
1906
  z-index: var(--cm-z-raise);
1811
1907
  padding: 6px 10px;
1812
1908
  text-align: left;
1813
- font-size: 11px;
1909
+ font-size: var(--cm-fs-meta);
1814
1910
  font-weight: 600;
1815
1911
  color: var(--dsw-alias-label-tertiary);
1816
1912
  background: var(--dsw-alias-bg-layer-2);
1817
- border-bottom: 1px solid var(--dsw-alias-border-l1);
1913
+ border-bottom: 0.5px solid var(--dsw-alias-border-l2);
1818
1914
  white-space: nowrap;
1819
1915
  }
1820
1916
 
1821
1917
  .dataTable td {
1822
1918
  padding: 6px 10px;
1823
- border-bottom: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1) 55%, transparent);
1919
+ border-bottom: 0.5px solid var(--dsw-alias-border-l2);
1824
1920
  vertical-align: middle;
1825
1921
  color: var(--dsw-alias-label-primary);
1826
1922
  }
@@ -1844,7 +1940,7 @@ body {
1844
1940
  .dataTable .num {
1845
1941
  text-align: right;
1846
1942
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
1847
- font-size: 12px;
1943
+ font-size: var(--cm-fs-table);
1848
1944
  white-space: nowrap;
1849
1945
  }
1850
1946
 
@@ -1893,7 +1989,7 @@ body {
1893
1989
  display: inline-flex;
1894
1990
  align-items: center;
1895
1991
  gap: 6px;
1896
- font-size: 11px;
1992
+ font-size: var(--cm-fs-meta);
1897
1993
  color: var(--dsw-alias-label-tertiary);
1898
1994
  overflow: hidden;
1899
1995
  min-width: 0;
@@ -1924,8 +2020,8 @@ body {
1924
2020
  align-items: baseline;
1925
2021
  gap: 10px;
1926
2022
  padding: 4px 0;
1927
- border-bottom: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1) 55%, transparent);
1928
- font-size: 12px;
2023
+ border-bottom: 0.5px solid var(--dsw-alias-border-l2);
2024
+ font-size: var(--cm-fs-table);
1929
2025
  min-width: 0;
1930
2026
  }
1931
2027
 
@@ -1940,11 +2036,18 @@ body {
1940
2036
  margin-top: 8px;
1941
2037
  }
1942
2038
 
2039
+ /* 复选框行之后紧跟的操作行:补 10px 上间距(区块间距档)。
2040
+ 与上一条同因:.checkboxRow 没有下外边距、.actionRow 只有下外边距 → 两者相邻时按钮紧贴勾选框
2041
+ (用户实测 2026-10-17:导入向导最后一步「失败时整体回滚」与「上一步 / 确认导入」挤在一起)。 */
2042
+ .checkboxRow + .actionRow {
2043
+ margin-top: 10px;
2044
+ }
2045
+
1943
2046
  .kvKey {
1944
2047
  flex: none;
1945
2048
  width: 88px;
1946
2049
  color: var(--dsw-alias-label-tertiary);
1947
- font-size: 11px;
2050
+ font-size: var(--cm-fs-meta);
1948
2051
  }
1949
2052
 
1950
2053
  .kvValue {
@@ -1954,7 +2057,7 @@ body {
1954
2057
  }
1955
2058
 
1956
2059
  .kvValue.mono {
1957
- font-size: 12px;
2060
+ font-size: var(--cm-fs-table);
1958
2061
  color: var(--dsw-alias-label-secondary);
1959
2062
  }
1960
2063
 
@@ -1965,9 +2068,9 @@ body {
1965
2068
  align-items: center;
1966
2069
  gap: 2px;
1967
2070
  padding: 2px;
1968
- border: 1px solid var(--dsw-alias-border-l2);
1969
- border-radius: 8px;
1970
- background: var(--dsw-alias-bg-base);
2071
+ border: none;
2072
+ border-radius: var(--cm-r-3);
2073
+ background: var(--cm-hover);
1971
2074
  margin: 0 0 10px;
1972
2075
  }
1973
2076
 
@@ -1976,13 +2079,13 @@ body {
1976
2079
  display: inline-flex;
1977
2080
  align-items: center;
1978
2081
  gap: 4px;
1979
- height: 22px;
1980
- padding: 0 8px;
2082
+ height: 24px;
2083
+ padding: 0 10px;
1981
2084
  border: none;
1982
- border-radius: 6px;
2085
+ border-radius: var(--cm-r-2);
1983
2086
  background: none;
1984
2087
  font: inherit;
1985
- font-size: 11px;
2088
+ font-size: var(--cm-fs-table);
1986
2089
  font-weight: 500;
1987
2090
  color: var(--dsw-alias-label-secondary);
1988
2091
  cursor: pointer;
@@ -1996,20 +2099,20 @@ body {
1996
2099
 
1997
2100
  .segItem:focus-visible,
1998
2101
  .modeTab:focus-visible {
1999
- outline: 2px solid var(--cm-accent);
2102
+ outline: var(--cm-focus-width) solid var(--cm-focus-color);
2000
2103
  outline-offset: 1px;
2001
2104
  }
2002
2105
 
2003
2106
  .segItem[data-active],
2004
2107
  .modeTab[data-active] {
2005
- background: var(--dsw-alias-bg-layer-2);
2108
+ background: var(--dsw-alias-bg-layer-1);
2006
2109
  color: var(--dsw-alias-label-primary);
2007
- font-weight: 600;
2008
- box-shadow: 0 0 0 1px var(--dsw-alias-border-l1);
2110
+ font-weight: 500;
2111
+ box-shadow: var(--cm-shadow-1);
2009
2112
  }
2010
2113
 
2011
2114
  .modeHint {
2012
- font-size: 11px;
2115
+ font-size: var(--cm-fs-meta);
2013
2116
  color: var(--dsw-alias-label-tertiary);
2014
2117
  margin: -4px 0 10px;
2015
2118
  }
@@ -2052,7 +2155,7 @@ body {
2052
2155
  height: 17px;
2053
2156
  border-radius: 50%;
2054
2157
  border: 1.5px solid var(--dsw-alias-border-l2);
2055
- font-size: 11px;
2158
+ font-size: var(--cm-fs-meta);
2056
2159
  font-weight: 700;
2057
2160
  color: var(--dsw-alias-label-tertiary);
2058
2161
  background: var(--dsw-alias-bg-layer-2);
@@ -2072,7 +2175,7 @@ body {
2072
2175
  }
2073
2176
 
2074
2177
  .stepperLabel {
2075
- font-size: 11px;
2178
+ font-size: var(--cm-fs-meta);
2076
2179
  color: var(--dsw-alias-label-tertiary);
2077
2180
  white-space: nowrap;
2078
2181
  }
@@ -2106,7 +2209,7 @@ body {
2106
2209
  .progressTrack {
2107
2210
  position: relative;
2108
2211
  height: 5px;
2109
- border-radius: 4px;
2212
+ border-radius: var(--cm-r-1);
2110
2213
  background: color-mix(in srgb, var(--dsw-alias-border-l1) 80%, transparent);
2111
2214
  overflow: hidden;
2112
2215
  }
@@ -2114,7 +2217,7 @@ body {
2114
2217
  .progressBar {
2115
2218
  position: absolute;
2116
2219
  inset: 0 auto 0 0;
2117
- border-radius: 4px;
2220
+ border-radius: var(--cm-r-1);
2118
2221
  background: var(--cm-accent);
2119
2222
  transition: width var(--cm-motion-slow) var(--cm-motion-ease-out);
2120
2223
  }
@@ -2133,7 +2236,7 @@ body {
2133
2236
  top: 0;
2134
2237
  bottom: 0;
2135
2238
  width: 34%;
2136
- border-radius: 4px;
2239
+ border-radius: var(--cm-r-1);
2137
2240
  background: var(--cm-accent);
2138
2241
  animation: indet 1.15s var(--cm-motion-ease-in-out) infinite;
2139
2242
  }
@@ -2148,7 +2251,7 @@ body {
2148
2251
  align-items: center;
2149
2252
  gap: 8px;
2150
2253
  margin-top: 4px;
2151
- font-size: 11px;
2254
+ font-size: var(--cm-fs-meta);
2152
2255
  color: var(--dsw-alias-label-secondary);
2153
2256
  }
2154
2257
 
@@ -2170,13 +2273,13 @@ body {
2170
2273
  align-items: center;
2171
2274
  gap: 4px;
2172
2275
  flex: none;
2173
- font-size: 11px;
2276
+ font-size: var(--cm-fs-meta);
2174
2277
  color: var(--dsw-alias-label-tertiary);
2175
2278
  }
2176
2279
 
2177
2280
  .progressBadgeCount {
2178
2281
  padding: 0 4px;
2179
- border-radius: 8px;
2282
+ border-radius: var(--cm-r-3);
2180
2283
  background: color-mix(in srgb, var(--cm-info) 14%, transparent);
2181
2284
  color: var(--dsw-alias-label-secondary);
2182
2285
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
@@ -2188,7 +2291,7 @@ body {
2188
2291
 
2189
2292
  .progressDetail {
2190
2293
  margin-top: 2px;
2191
- font-size: 11px;
2294
+ font-size: var(--cm-fs-meta);
2192
2295
  color: var(--dsw-alias-label-tertiary);
2193
2296
  }
2194
2297
 
@@ -2203,7 +2306,7 @@ body {
2203
2306
  overflow: auto;
2204
2307
  max-height: 380px;
2205
2308
  border: 1px solid var(--dsw-alias-border-l1);
2206
- border-radius: 8px;
2309
+ border-radius: var(--cm-r-3);
2207
2310
  background: var(--dsw-alias-bg-base);
2208
2311
  }
2209
2312
 
@@ -2229,7 +2332,8 @@ body {
2229
2332
  display: flex;
2230
2333
  align-items: center;
2231
2334
  justify-content: center;
2232
- background: color-mix(in srgb, var(--dsw-alias-bg-base) 55%, transparent);
2335
+ background: var(--cm-mask);
2336
+ backdrop-filter: var(--cm-mask-blur);
2233
2337
  /* 遮罩淡入:Radix Dialog 只在 open 时挂载 Overlay/Content,元素创建即播放一次。 */
2234
2338
  animation: maskIn var(--cm-motion-fast) var(--cm-motion-ease-out);
2235
2339
  }
@@ -2298,16 +2402,16 @@ body {
2298
2402
  max-height: min(600px, calc(100vh - 64px), 92%);
2299
2403
  display: flex;
2300
2404
  flex-direction: column;
2301
- border: 1px solid var(--dsw-alias-border-l1);
2302
- border-radius: 8px;
2405
+ border: 0;
2406
+ border-radius: var(--cm-r-surface);
2303
2407
  background: var(--dsw-alias-bg-layer-2);
2304
- box-shadow: 0 12px 32px color-mix(in srgb, var(--dsw-alias-bg-base) 40%, transparent);
2408
+ box-shadow: var(--cm-shadow-2);
2305
2409
  }
2306
2410
 
2307
2411
  .dialogHeader {
2308
2412
  padding: 12px 16px 0;
2309
- font-size: 13px;
2310
- font-weight: 700;
2413
+ font-size: var(--cm-fs-title);
2414
+ font-weight: 500;
2311
2415
  color: var(--dsw-alias-label-primary);
2312
2416
  }
2313
2417
 
@@ -2336,7 +2440,7 @@ body {
2336
2440
  min-height: 0;
2337
2441
  overflow-y: auto;
2338
2442
  padding: 8px 16px 12px;
2339
- font-size: 12.5px;
2443
+ font-size: var(--cm-fs-base);
2340
2444
  color: var(--dsw-alias-label-secondary);
2341
2445
  }
2342
2446
 
@@ -2356,7 +2460,7 @@ body {
2356
2460
  gap: 8px;
2357
2461
  padding: 10px 16px 14px;
2358
2462
  margin: 0;
2359
- border-top: 1px solid var(--dsw-alias-border-l1);
2463
+ border-top: 0.5px solid var(--dsw-alias-border-l2);
2360
2464
  }
2361
2465
 
2362
2466
  /* —— 插件自更新弹窗(「新版本 → 立即更新」,2026-10)——
@@ -2375,7 +2479,7 @@ body {
2375
2479
  }
2376
2480
 
2377
2481
  .updateVersionTarget {
2378
- font-size: 13px;
2482
+ font-size: var(--cm-fs-title);
2379
2483
  font-weight: 600;
2380
2484
  color: var(--dsw-alias-label-primary);
2381
2485
  }
@@ -2411,15 +2515,15 @@ body {
2411
2515
  align-items: flex-start;
2412
2516
  gap: 8px;
2413
2517
  width: fit-content;
2414
- max-width: 340px;
2415
- padding: 8px 10px;
2416
- border: 1px solid var(--dsw-alias-border-l1);
2417
- border-radius: 8px;
2418
- background: var(--dsw-alias-bg-layer-2);
2419
- box-shadow: 0 8px 24px color-mix(in srgb, var(--dsw-alias-bg-base) 45%, transparent);
2420
- font-size: 12px;
2518
+ max-width: 420px;
2519
+ padding: 12px 16px;
2520
+ border: 0;
2521
+ border-radius: var(--cm-r-surface);
2522
+ background: var(--cm-toast-bg);
2523
+ box-shadow: var(--cm-shadow-2);
2524
+ font-size: var(--cm-fs-title);
2421
2525
  line-height: 1.5;
2422
- color: var(--dsw-alias-label-primary);
2526
+ color: var(--cm-toast-fg);
2423
2527
  animation: toastIn var(--cm-motion-base) var(--cm-motion-ease-out);
2424
2528
  }
2425
2529
 
@@ -2429,10 +2533,6 @@ body {
2429
2533
  }
2430
2534
 
2431
2535
  /* 四态语义:左侧色条 + 图标着色(复用 Badge/Banner 的 --dsw-* 状态色) */
2432
- .toast[data-kind='ok'] {
2433
- border-color: color-mix(in srgb, var(--cm-ok) 40%, transparent);
2434
- }
2435
-
2436
2536
  .toast[data-kind='ok'] .toastGlyph {
2437
2537
  color: var(--cm-ok);
2438
2538
  }
@@ -2441,16 +2541,8 @@ body {
2441
2541
  color: var(--cm-accent);
2442
2542
  }
2443
2543
 
2444
- .toast[data-kind='warn'] {
2445
- border-color: color-mix(in srgb, var(--cm-warn) 40%, transparent);
2446
- }
2447
-
2448
2544
  .toast[data-kind='warn'] .toastGlyph {
2449
- color: var(--cm-warn);
2450
- }
2451
-
2452
- .toast[data-kind='error'] {
2453
- border-color: color-mix(in srgb, var(--cm-error) 45%, transparent);
2545
+ color: var(--cm-warn-label);
2454
2546
  }
2455
2547
 
2456
2548
  .toast[data-kind='error'] .toastGlyph {
@@ -2512,9 +2604,9 @@ body {
2512
2604
  }
2513
2605
 
2514
2606
  .statusAction:focus-visible {
2515
- outline: 2px solid var(--cm-accent);
2607
+ outline: var(--cm-focus-width) solid var(--cm-focus-color);
2516
2608
  outline-offset: 1px;
2517
- border-radius: 4px;
2609
+ border-radius: var(--cm-r-1);
2518
2610
  }
2519
2611
 
2520
2612
  .runsCenter {
@@ -2531,7 +2623,7 @@ body {
2531
2623
  }
2532
2624
 
2533
2625
  .runsSummaryTitle {
2534
- font-size: 12px;
2626
+ font-size: var(--cm-fs-table);
2535
2627
  font-weight: 700;
2536
2628
  color: var(--dsw-alias-label-primary);
2537
2629
  }
@@ -2545,7 +2637,7 @@ body {
2545
2637
  }
2546
2638
 
2547
2639
  .runsCardTitle {
2548
- font-size: 12.5px;
2640
+ font-size: var(--cm-fs-base);
2549
2641
  font-weight: 600;
2550
2642
  color: var(--dsw-alias-label-primary);
2551
2643
  }
@@ -2555,9 +2647,9 @@ body {
2555
2647
  margin: 8px 0 0;
2556
2648
  padding: 6px 8px;
2557
2649
  border: 1px solid color-mix(in srgb, var(--cm-warn) 45%, transparent);
2558
- border-radius: 6px;
2650
+ border-radius: var(--cm-r-2);
2559
2651
  background: color-mix(in srgb, var(--cm-warn) 10%, transparent);
2560
- font-size: 11px;
2652
+ font-size: var(--cm-fs-meta);
2561
2653
  color: var(--dsw-alias-label-secondary);
2562
2654
  }
2563
2655
 
@@ -2568,14 +2660,14 @@ body {
2568
2660
 
2569
2661
  .runsCardTime {
2570
2662
  margin-left: auto;
2571
- font-size: 11px;
2663
+ font-size: var(--cm-fs-meta);
2572
2664
  color: var(--dsw-alias-label-tertiary);
2573
2665
  white-space: nowrap;
2574
2666
  }
2575
2667
 
2576
2668
  .runsCounts {
2577
2669
  margin: 8px 0 0;
2578
- font-size: 11px;
2670
+ font-size: var(--cm-fs-meta);
2579
2671
  color: var(--dsw-alias-label-tertiary);
2580
2672
  }
2581
2673
 
@@ -2585,10 +2677,10 @@ body {
2585
2677
  overflow-y: auto;
2586
2678
  padding: 6px 8px;
2587
2679
  border: 1px solid var(--dsw-alias-border-l1);
2588
- border-radius: 6px;
2680
+ border-radius: var(--cm-r-2);
2589
2681
  background: var(--dsw-alias-bg-base);
2590
2682
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
2591
- font-size: 11px;
2683
+ font-size: var(--cm-fs-meta);
2592
2684
  line-height: 1.5;
2593
2685
  color: var(--dsw-alias-label-secondary);
2594
2686
  }
@@ -2614,7 +2706,7 @@ body {
2614
2706
  margin: 0 0 8px;
2615
2707
  padding: 8px 10px;
2616
2708
  border: 1px solid var(--dsw-alias-border-l2);
2617
- border-radius: 8px;
2709
+ border-radius: var(--cm-r-3);
2618
2710
  background: var(--dsw-alias-bg-layer-2);
2619
2711
  font: inherit;
2620
2712
  color: var(--dsw-alias-label-primary);
@@ -2627,7 +2719,7 @@ body {
2627
2719
  }
2628
2720
 
2629
2721
  .runsOption:focus-visible {
2630
- outline: 2px solid var(--cm-accent);
2722
+ outline: var(--cm-focus-width) solid var(--cm-focus-color);
2631
2723
  outline-offset: 1px;
2632
2724
  }
2633
2725
 
@@ -2640,19 +2732,19 @@ body {
2640
2732
  display: flex;
2641
2733
  align-items: center;
2642
2734
  gap: 6px;
2643
- font-size: 12.5px;
2735
+ font-size: var(--cm-fs-base);
2644
2736
  font-weight: 600;
2645
2737
  }
2646
2738
 
2647
2739
  .runsOptionDesc {
2648
- font-size: 11px;
2740
+ font-size: var(--cm-fs-meta);
2649
2741
  color: var(--dsw-alias-label-tertiary);
2650
2742
  }
2651
2743
 
2652
2744
  .runsOptionTag {
2653
2745
  padding: 0 4px;
2654
2746
  border-radius: 999px;
2655
- font-size: 11px;
2747
+ font-size: var(--cm-fs-meta);
2656
2748
  font-weight: 600;
2657
2749
  background: color-mix(in srgb, var(--cm-accent) 14%, transparent);
2658
2750
  color: var(--cm-accent);
@@ -2752,7 +2844,7 @@ body {
2752
2844
  gap: 0;
2753
2845
  min-height: 32px;
2754
2846
  border: 1px solid var(--dsw-alias-border-l1);
2755
- border-radius: 8px;
2847
+ border-radius: var(--cm-r-3);
2756
2848
  background: var(--dsw-alias-bg-layer-2);
2757
2849
  margin-bottom: 10px;
2758
2850
  /* 放不下就**换行**,绝不隐藏:v1 的「隐藏滚动条 + 渐隐遮罩」已被真机判定为不可发现
@@ -2791,7 +2883,7 @@ body {
2791
2883
  /* 左右 8px(原 12px):中文 5 段实测 547px > 画布可用 ~527px,收窄 20px 才回到单行(2026-10-08 真机);
2792
2884
  上下 4px:仅在**折行**时让两行文字离开边框,单行时整段被 stretch 到 32px,视觉与 0 无异 */
2793
2885
  padding: 4px 8px;
2794
- font-size: 12px;
2886
+ font-size: var(--cm-fs-table);
2795
2887
  font-weight: 600;
2796
2888
  color: var(--dsw-alias-label-primary);
2797
2889
  white-space: nowrap;
@@ -2804,7 +2896,7 @@ body {
2804
2896
  border: none;
2805
2897
  background: none;
2806
2898
  font: inherit;
2807
- font-size: 12px;
2899
+ font-size: var(--cm-fs-table);
2808
2900
  font-weight: 600;
2809
2901
  cursor: pointer;
2810
2902
  text-align: left;
@@ -2815,9 +2907,9 @@ body {
2815
2907
  }
2816
2908
 
2817
2909
  .statHealthAction:focus-visible {
2818
- outline: 2px solid var(--cm-accent);
2910
+ outline: var(--cm-focus-width) solid var(--cm-focus-color);
2819
2911
  outline-offset: -2px;
2820
- border-radius: 6px;
2912
+ border-radius: var(--cm-r-2);
2821
2913
  }
2822
2914
 
2823
2915
  .statSeg {
@@ -2829,7 +2921,7 @@ body {
2829
2921
  border-left: 1px solid var(--dsw-alias-border-l1);
2830
2922
  background: none;
2831
2923
  font: inherit;
2832
- font-size: 11px;
2924
+ font-size: var(--cm-fs-meta);
2833
2925
  color: var(--dsw-alias-label-secondary);
2834
2926
  white-space: nowrap;
2835
2927
  cursor: pointer;
@@ -2851,7 +2943,7 @@ body {
2851
2943
  }
2852
2944
 
2853
2945
  .statSeg:focus-visible {
2854
- outline: 2px solid var(--cm-accent);
2946
+ outline: var(--cm-focus-width) solid var(--cm-focus-color);
2855
2947
  outline-offset: -2px;
2856
2948
  }
2857
2949
 
@@ -2883,7 +2975,7 @@ body {
2883
2975
  }
2884
2976
 
2885
2977
  .infoValue .mono {
2886
- font-size: 11px;
2978
+ font-size: var(--cm-fs-meta);
2887
2979
  color: var(--dsw-alias-label-secondary);
2888
2980
  overflow: hidden;
2889
2981
  text-overflow: ellipsis;
@@ -2899,10 +2991,10 @@ body {
2899
2991
  height: 20px;
2900
2992
  padding: 0;
2901
2993
  border: none;
2902
- border-radius: 4px;
2994
+ border-radius: var(--cm-r-1);
2903
2995
  background: none;
2904
2996
  font: inherit;
2905
- font-size: 11px;
2997
+ font-size: var(--cm-fs-meta);
2906
2998
  line-height: 1.25;
2907
2999
  color: var(--dsw-alias-label-tertiary);
2908
3000
  cursor: pointer;
@@ -2915,7 +3007,7 @@ body {
2915
3007
  }
2916
3008
 
2917
3009
  .copyBtn:focus-visible {
2918
- outline: 2px solid var(--cm-accent);
3010
+ outline: var(--cm-focus-width) solid var(--cm-focus-color);
2919
3011
  outline-offset: 1px;
2920
3012
  }
2921
3013
 
@@ -2973,7 +3065,7 @@ body {
2973
3065
 
2974
3066
  .activityTitle {
2975
3067
  flex: 1 1 auto;
2976
- font-size: 11px;
3068
+ font-size: var(--cm-fs-meta);
2977
3069
  font-weight: 700;
2978
3070
  letter-spacing: 0.02em;
2979
3071
  color: var(--dsw-alias-label-tertiary);
@@ -2987,7 +3079,7 @@ body {
2987
3079
  min-height: 0;
2988
3080
  overflow-y: auto;
2989
3081
  border: 1px solid var(--dsw-alias-border-l1);
2990
- border-radius: 8px;
3082
+ border-radius: var(--cm-r-3);
2991
3083
  background: var(--dsw-alias-bg-base);
2992
3084
  }
2993
3085
 
@@ -2998,8 +3090,8 @@ body {
2998
3090
  align-items: center;
2999
3091
  gap: 10px;
3000
3092
  padding: 4px 10px;
3001
- border-bottom: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1) 55%, transparent);
3002
- font-size: 12px;
3093
+ border-bottom: 0.5px solid var(--dsw-alias-border-l2);
3094
+ font-size: var(--cm-fs-table);
3003
3095
  line-height: 1.5;
3004
3096
  min-width: 0;
3005
3097
  }
@@ -3013,7 +3105,7 @@ body {
3013
3105
  line-height: 1.5;
3014
3106
  color: var(--dsw-alias-label-tertiary);
3015
3107
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
3016
- font-size: 11px;
3108
+ font-size: var(--cm-fs-meta);
3017
3109
  white-space: nowrap;
3018
3110
  }
3019
3111
 
@@ -3021,7 +3113,7 @@ body {
3021
3113
  flex: none;
3022
3114
  line-height: 1.5;
3023
3115
  color: var(--dsw-alias-label-tertiary);
3024
- font-size: 11px;
3116
+ font-size: var(--cm-fs-meta);
3025
3117
  white-space: nowrap;
3026
3118
  }
3027
3119
 
@@ -3032,7 +3124,7 @@ body {
3032
3124
  align-items: center;
3033
3125
  gap: 6px;
3034
3126
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
3035
- font-size: 11px;
3127
+ font-size: var(--cm-fs-meta);
3036
3128
  color: var(--dsw-alias-label-secondary);
3037
3129
  }
3038
3130
 
@@ -3056,7 +3148,7 @@ body {
3056
3148
  align-items: center;
3057
3149
  gap: 4px;
3058
3150
  line-height: 1.5;
3059
- font-size: 11px;
3151
+ font-size: var(--cm-fs-meta);
3060
3152
  color: var(--dsw-alias-label-tertiary);
3061
3153
  white-space: nowrap;
3062
3154
  }
@@ -3076,13 +3168,13 @@ body {
3076
3168
  }
3077
3169
 
3078
3170
  .factLabel {
3079
- font-size: 11px;
3171
+ font-size: var(--cm-fs-meta);
3080
3172
  color: var(--dsw-alias-label-tertiary);
3081
3173
  white-space: nowrap;
3082
3174
  }
3083
3175
 
3084
3176
  .factValue {
3085
- font-size: 12px;
3177
+ font-size: var(--cm-fs-table);
3086
3178
  font-weight: 600;
3087
3179
  color: var(--dsw-alias-label-primary);
3088
3180
  white-space: nowrap;
@@ -3105,8 +3197,8 @@ body {
3105
3197
  align-items: center;
3106
3198
  gap: 10px;
3107
3199
  padding: 4px 0;
3108
- border-bottom: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1) 55%, transparent);
3109
- font-size: 12px;
3200
+ border-bottom: 0.5px solid var(--dsw-alias-border-l2);
3201
+ font-size: var(--cm-fs-table);
3110
3202
  min-width: 0;
3111
3203
  }
3112
3204
 
@@ -3117,7 +3209,7 @@ body {
3117
3209
  .sectionName {
3118
3210
  min-width: 0;
3119
3211
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
3120
- font-size: 11px;
3212
+ font-size: var(--cm-fs-meta);
3121
3213
  color: var(--dsw-alias-label-secondary);
3122
3214
  overflow: hidden;
3123
3215
  text-overflow: ellipsis;
@@ -3127,14 +3219,14 @@ body {
3127
3219
  .sectionCount {
3128
3220
  justify-self: end;
3129
3221
  color: var(--dsw-alias-label-tertiary);
3130
- font-size: 11px;
3222
+ font-size: var(--cm-fs-meta);
3131
3223
  font-variant-numeric: tabular-nums;
3132
3224
  white-space: nowrap;
3133
3225
  }
3134
3226
 
3135
3227
  .sectionSize {
3136
3228
  justify-self: end;
3137
- font-size: 11px;
3229
+ font-size: var(--cm-fs-meta);
3138
3230
  color: var(--dsw-alias-label-secondary);
3139
3231
  font-variant-numeric: tabular-nums;
3140
3232
  white-space: nowrap;
@@ -3143,7 +3235,7 @@ body {
3143
3235
  /* 活动空态(紧凑) */
3144
3236
  .activityEmpty {
3145
3237
  padding: 16px;
3146
- font-size: 11px;
3238
+ font-size: var(--cm-fs-meta);
3147
3239
  color: var(--dsw-alias-label-tertiary);
3148
3240
  text-align: center;
3149
3241
  }
@@ -3160,7 +3252,7 @@ body {
3160
3252
 
3161
3253
  .snapshotRow {
3162
3254
  border: 1px solid var(--dsw-alias-border-l1);
3163
- border-radius: 8px;
3255
+ border-radius: var(--cm-r-3);
3164
3256
  background: var(--dsw-alias-bg-layer-2);
3165
3257
  /* T15:卡片内边距加大 —— 原先 9px 12px 让文字贴着圆角边框(用户反馈「挤在一起」) */
3166
3258
  padding: 12px 14px;
@@ -3179,7 +3271,7 @@ body {
3179
3271
  display: flex;
3180
3272
  align-items: center;
3181
3273
  gap: 8px;
3182
- font-size: 12px;
3274
+ font-size: var(--cm-fs-table);
3183
3275
  }
3184
3276
 
3185
3277
  .snapshotRowMain {
@@ -3204,7 +3296,7 @@ body {
3204
3296
 
3205
3297
  .snapshotRowName {
3206
3298
  font-weight: 500;
3207
- font-size: 12.5px;
3299
+ font-size: var(--cm-fs-base);
3208
3300
  word-break: break-all;
3209
3301
  line-height: 1.5;
3210
3302
  }
@@ -3214,7 +3306,7 @@ body {
3214
3306
  align-items: center;
3215
3307
  gap: 10px;
3216
3308
  min-width: 0;
3217
- font-size: 12px;
3309
+ font-size: var(--cm-fs-table);
3218
3310
  color: var(--dsw-alias-label-secondary);
3219
3311
  }
3220
3312
 
@@ -3369,7 +3461,7 @@ body {
3369
3461
  display: flex;
3370
3462
  align-items: center;
3371
3463
  justify-content: center;
3372
- border-radius: 8px;
3464
+ border-radius: var(--cm-r-3);
3373
3465
  background: color-mix(in srgb, var(--dsw-alias-bg-layer-2) 62%, transparent);
3374
3466
  backdrop-filter: blur(1px);
3375
3467
  }
@@ -3390,7 +3482,7 @@ body {
3390
3482
  overflow: auto;
3391
3483
  max-height: 320px;
3392
3484
  border: 1px solid var(--dsw-alias-border-l1);
3393
- border-radius: 8px;
3485
+ border-radius: var(--cm-r-3);
3394
3486
  background: var(--dsw-alias-bg-layer-2);
3395
3487
  padding: 4px 10px;
3396
3488
  }
@@ -3425,7 +3517,7 @@ body {
3425
3517
  }
3426
3518
 
3427
3519
  .pickerGroup + .pickerGroup {
3428
- border-top: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1) 55%, transparent);
3520
+ border-top: 0.5px solid var(--dsw-alias-border-l2);
3429
3521
  }
3430
3522
 
3431
3523
  /* 单元行缩进,视觉从属其分区 */
@@ -3438,7 +3530,7 @@ body {
3438
3530
  }
3439
3531
 
3440
3532
  .pickerUnitName {
3441
- font-size: 12px;
3533
+ font-size: var(--cm-fs-table);
3442
3534
  color: var(--dsw-alias-label-primary);
3443
3535
  /* 长单元名(长路径 / 会话标题)不得撑宽列表(UI-16):文本已由 tailWeightedEllipsis 中段省略,
3444
3536
  这里再用 CSS 省略兜底实际容器宽度,行宽始终跟随容器而不是内容。完整值走 title。 */
@@ -3473,13 +3565,35 @@ body {
3473
3565
  height: 18px;
3474
3566
  }
3475
3567
 
3568
+ /* 分区组标题(General / 插件与扩展 / …):**不是选项** —— 字号更小、颜色更淡、不可选中,
3569
+ 非首组起一条分隔线(DESIGN.md §CommandPalette 同款口径:否则会被读成「灰掉的选项」)。 */
3570
+ .pickerGroupTitle {
3571
+ display: flex;
3572
+ align-items: center;
3573
+ gap: 6px;
3574
+ padding: 8px 0 4px;
3575
+ border-top: 1px solid var(--dsw-alias-border-l2);
3576
+ }
3577
+
3578
+ .pickerGroupTitle:first-child {
3579
+ border-top: none;
3580
+ padding-top: 0;
3581
+ }
3582
+
3583
+ .pickerGroupTitleName {
3584
+ font-size: var(--cm-fs-meta);
3585
+ font-weight: 600;
3586
+ letter-spacing: 0.02em;
3587
+ color: var(--dsw-alias-label-secondary);
3588
+ }
3589
+
3476
3590
  /* 二级分组(sessions 按工作区聚合,issue:按工作区分类对话):标题行与单元行同一缩进体系 */
3477
3591
  .pickerSubgroup {
3478
3592
  padding-left: 18px;
3479
3593
  }
3480
3594
 
3481
3595
  .pickerSubgroupName {
3482
- font-size: 11px;
3596
+ font-size: var(--cm-fs-meta);
3483
3597
  font-weight: 600;
3484
3598
  color: var(--dsw-alias-label-secondary);
3485
3599
  min-width: 0;
@@ -3488,9 +3602,21 @@ body {
3488
3602
  white-space: nowrap;
3489
3603
  }
3490
3604
 
3491
- /* 分组内的单元:与分组行同一左缘(分组行的 chevron 位置由等宽占位顶掉) */
3605
+ /* 子树容器:**每一层子树都自带竖线 + 缩进**(逐层累加)。
3606
+ 为什么必须是「容器」而不是给叶子行加缩进(2026-10-17 用户实测两轮):
3607
+ 只给叶子行加时,中间层(「插件」→ 某个插件 → 它的数据目录)没有竖线也没有缩进 ——
3608
+ 只要有中间层,层级就又看不出来了。容器在每个 Collapse 内部,层级因此自动逐层累加。
3609
+ 几何(2026-10-17 第二轮按用户反馈收紧):margin-left 8px 让竖线落在父行 chevron 的中线下,
3610
+ padding-left **4px** —— 每层只推进 13px(父行勾选框 22px → 子层 35px → 孙层 48px)。
3611
+ 第一版用 14px(每层 23px)被用户判为「子项离父项太远」:层级感由**竖线**承担,不靠大间距。 */
3612
+ .pickerChildren {
3613
+ margin-left: 8px;
3614
+ padding-left: 4px;
3615
+ border-left: 1px solid var(--dsw-alias-border-l1);
3616
+ }
3617
+
3618
+ /* 子单元行:左缘由 .pickerChildren 提供,这里只保留勾选框前的等宽占位与行内间距 */
3492
3619
  .pickerUnitNested {
3493
- padding-left: 18px;
3494
3620
  gap: 4px;
3495
3621
  }
3496
3622
 
@@ -3504,14 +3630,14 @@ body {
3504
3630
  .pickerUnitDetail {
3505
3631
  max-width: 220px;
3506
3632
  overflow: hidden;
3507
- font-size: 11px;
3633
+ font-size: var(--cm-fs-meta);
3508
3634
  color: var(--dsw-alias-label-tertiary);
3509
3635
  text-overflow: ellipsis;
3510
3636
  white-space: nowrap;
3511
3637
  }
3512
3638
 
3513
3639
  .pickerCount {
3514
- font-size: 11px;
3640
+ font-size: var(--cm-fs-meta);
3515
3641
  color: var(--dsw-alias-label-tertiary);
3516
3642
  font-variant-numeric: tabular-nums;
3517
3643
  white-space: nowrap;
@@ -3520,7 +3646,7 @@ body {
3520
3646
  .pickerFooter {
3521
3647
  padding-top: 6px;
3522
3648
  border-top: 1px solid var(--dsw-alias-border-l1);
3523
- font-size: 11px;
3649
+ font-size: var(--cm-fs-meta);
3524
3650
  color: var(--dsw-alias-label-secondary);
3525
3651
  }
3526
3652
 
@@ -3586,7 +3712,7 @@ body {
3586
3712
  }
3587
3713
 
3588
3714
  .categoryDesc {
3589
- font-size: 11px;
3715
+ font-size: var(--cm-fs-meta);
3590
3716
  color: var(--dsw-alias-label-tertiary);
3591
3717
  min-width: 0;
3592
3718
  }
@@ -3622,7 +3748,7 @@ body {
3622
3748
  .warnList {
3623
3749
  margin: 4px 0 0;
3624
3750
  padding-left: 18px;
3625
- font-size: 11px;
3751
+ font-size: var(--cm-fs-meta);
3626
3752
  color: var(--dsw-alias-label-secondary);
3627
3753
  }
3628
3754
 
@@ -3649,7 +3775,7 @@ body {
3649
3775
 
3650
3776
  .conflictItem {
3651
3777
  border: 1px solid color-mix(in srgb, var(--cm-warn) 35%, transparent);
3652
- border-radius: 8px;
3778
+ border-radius: var(--cm-r-3);
3653
3779
  background: var(--dsw-alias-bg-layer-2);
3654
3780
  padding: 10px 12px;
3655
3781
  }
@@ -3659,7 +3785,7 @@ body {
3659
3785
  align-items: center;
3660
3786
  gap: 8px;
3661
3787
  margin-bottom: 6px;
3662
- font-size: 12px;
3788
+ font-size: var(--cm-fs-table);
3663
3789
  }
3664
3790
 
3665
3791
  .conflictId {
@@ -3692,9 +3818,9 @@ body {
3692
3818
  gap: 6px;
3693
3819
  padding: 8px 10px;
3694
3820
  border: 1px solid var(--dsw-alias-border-l2);
3695
- border-radius: 8px;
3821
+ border-radius: var(--cm-r-3);
3696
3822
  background: var(--dsw-alias-bg-base);
3697
- font-size: 12px;
3823
+ font-size: var(--cm-fs-table);
3698
3824
  font-weight: 500;
3699
3825
  color: var(--dsw-alias-label-secondary);
3700
3826
  cursor: pointer;
@@ -3706,7 +3832,7 @@ body {
3706
3832
  }
3707
3833
 
3708
3834
  .choiceCard:focus-within {
3709
- outline: 2px solid var(--cm-accent);
3835
+ outline: var(--cm-focus-width) solid var(--cm-focus-color);
3710
3836
  outline-offset: 1px;
3711
3837
  }
3712
3838
 
@@ -3731,10 +3857,10 @@ body {
3731
3857
  .conflictDetail {
3732
3858
  padding: 8px 10px;
3733
3859
  border: 1px solid var(--dsw-alias-border-l1);
3734
- border-radius: 6px;
3860
+ border-radius: var(--cm-r-2);
3735
3861
  background: var(--dsw-alias-bg-base);
3736
3862
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
3737
- font-size: 11px;
3863
+ font-size: var(--cm-fs-meta);
3738
3864
  color: var(--dsw-alias-label-secondary);
3739
3865
  overflow-wrap: anywhere;
3740
3866
  /* 原为 <pre>(white-space:pre 不换行)→ 长配置会横向溢出并产生左右滚动条;
@@ -3757,7 +3883,7 @@ body {
3757
3883
 
3758
3884
  /* 两行之间的分割线(第一行不加,避免与容器上边框重复) */
3759
3885
  .conflictLine + .conflictLine {
3760
- border-top: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1) 55%, transparent);
3886
+ border-top: 0.5px solid var(--dsw-alias-border-l2);
3761
3887
  }
3762
3888
 
3763
3889
  .conflictLineLabel {
@@ -3790,10 +3916,10 @@ body {
3790
3916
  gap: 8px;
3791
3917
  padding: 8px 10px;
3792
3918
  border: 1px solid var(--dsw-alias-border-l1);
3793
- border-radius: 8px;
3919
+ border-radius: var(--cm-r-3);
3794
3920
  background: var(--dsw-alias-bg-layer-2);
3795
3921
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
3796
- font-size: 11px;
3922
+ font-size: var(--cm-fs-meta);
3797
3923
  }
3798
3924
 
3799
3925
  .pathOld,
@@ -3806,7 +3932,7 @@ body {
3806
3932
  flex-direction: column;
3807
3933
  padding: 4px 8px;
3808
3934
  border: 1px solid var(--dsw-alias-border-l2);
3809
- border-radius: 6px;
3935
+ border-radius: var(--cm-r-2);
3810
3936
  background: var(--dsw-alias-bg-base);
3811
3937
  overflow-wrap: anywhere;
3812
3938
  flex: 1 1 auto;
@@ -3864,7 +3990,7 @@ body {
3864
3990
  /* 导入日志面板 */
3865
3991
  .logPanel {
3866
3992
  border: 1px solid var(--dsw-alias-border-l1);
3867
- border-radius: 8px;
3993
+ border-radius: var(--cm-r-3);
3868
3994
  background: var(--dsw-alias-bg-base);
3869
3995
  overflow: hidden;
3870
3996
  margin-bottom: 10px;
@@ -3876,7 +4002,7 @@ body {
3876
4002
  gap: 8px;
3877
4003
  padding: 6px 10px;
3878
4004
  border-bottom: 1px solid var(--dsw-alias-border-l1);
3879
- font-size: 11px;
4005
+ font-size: var(--cm-fs-meta);
3880
4006
  font-weight: 600;
3881
4007
  color: var(--dsw-alias-label-tertiary);
3882
4008
  background: var(--dsw-alias-bg-layer-2);
@@ -3885,7 +4011,7 @@ body {
3885
4011
  .logLine {
3886
4012
  padding: 1px 10px;
3887
4013
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
3888
- font-size: 11px;
4014
+ font-size: var(--cm-fs-meta);
3889
4015
  line-height: 1.5;
3890
4016
  color: var(--dsw-alias-label-secondary);
3891
4017
  white-space: pre-wrap;
@@ -3902,7 +4028,7 @@ body {
3902
4028
  border: none;
3903
4029
  background: none;
3904
4030
  font: inherit;
3905
- font-size: 11px;
4031
+ font-size: var(--cm-fs-meta);
3906
4032
  color: var(--cm-accent);
3907
4033
  cursor: pointer;
3908
4034
  padding: 0 4px;
@@ -3916,7 +4042,7 @@ body {
3916
4042
  /* 一条计划项(同 itemId 的开始/命令/收尾合并):与相邻项之间用细分隔线分段,
3917
4043
  避免合并后仍读成一屏连续流水 */
3918
4044
  .logEntry + .logEntry {
3919
- border-top: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1) 55%, transparent);
4045
+ border-top: 0.5px solid var(--dsw-alias-border-l2);
3920
4046
  }
3921
4047
 
3922
4048
  /* 项状态行:按级别着色(✗ 红 / ⚠ 黄 / ✓ 绿 / ⏭ 灰 / ▶ 主文本)—— 一眼看出哪些要处理 */
@@ -3944,7 +4070,7 @@ body {
3944
4070
  .logDetail {
3945
4071
  padding: 0 10px 0 22px;
3946
4072
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
3947
- font-size: 11px;
4073
+ font-size: var(--cm-fs-meta);
3948
4074
  line-height: 1.5;
3949
4075
  color: var(--dsw-alias-label-tertiary);
3950
4076
  white-space: pre-wrap;
@@ -3957,7 +4083,7 @@ body {
3957
4083
 
3958
4084
  .logEmpty {
3959
4085
  padding: 12px;
3960
- font-size: 11px;
4086
+ font-size: var(--cm-fs-meta);
3961
4087
  color: var(--dsw-alias-label-tertiary);
3962
4088
  text-align: center;
3963
4089
  }
@@ -3967,7 +4093,7 @@ body {
3967
4093
  border: none;
3968
4094
  background: none;
3969
4095
  font: inherit;
3970
- font-size: 11px;
4096
+ font-size: var(--cm-fs-meta);
3971
4097
  color: var(--cm-accent);
3972
4098
  cursor: pointer;
3973
4099
  padding: 0 4px;
@@ -3976,7 +4102,7 @@ body {
3976
4102
  /* 报告 / 错误 */
3977
4103
  .reportView {
3978
4104
  border: 1px solid var(--dsw-alias-border-l1);
3979
- border-radius: 8px;
4105
+ border-radius: var(--cm-r-3);
3980
4106
  background: var(--dsw-alias-bg-layer-2);
3981
4107
  overflow: hidden;
3982
4108
  margin-bottom: 10px;
@@ -4011,7 +4137,7 @@ body {
4011
4137
  .confirmItemDesc {
4012
4138
  flex: 1 1 200px;
4013
4139
  min-width: 0;
4014
- font-size: 12.5px;
4140
+ font-size: var(--cm-fs-base);
4015
4141
  color: var(--dsw-alias-label-primary);
4016
4142
  overflow-wrap: anywhere;
4017
4143
  }
@@ -4044,14 +4170,14 @@ body {
4044
4170
 
4045
4171
  .reportProblemText {
4046
4172
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
4047
- font-size: 12px;
4173
+ font-size: var(--cm-fs-table);
4048
4174
  color: var(--dsw-alias-label-primary);
4049
4175
  overflow-wrap: anywhere;
4050
4176
  }
4051
4177
 
4052
4178
  .reportProblemReason {
4053
4179
  margin-top: 2px;
4054
- font-size: 11px;
4180
+ font-size: var(--cm-fs-meta);
4055
4181
  line-height: 1.5;
4056
4182
  color: var(--dsw-alias-label-secondary);
4057
4183
  overflow-wrap: anywhere;
@@ -4067,7 +4193,7 @@ body {
4067
4193
 
4068
4194
  .reportWarningRow {
4069
4195
  padding: 2px 10px;
4070
- font-size: 11px;
4196
+ font-size: var(--cm-fs-meta);
4071
4197
  line-height: 1.5;
4072
4198
  color: var(--cm-warn);
4073
4199
  overflow-wrap: anywhere;
@@ -4076,7 +4202,7 @@ body {
4076
4202
  /* 完整文本报告(渐进披露):结构化视图是主路径,这里是「逐字核对」的原文入口 */
4077
4203
  .reportDetails {
4078
4204
  margin-top: 4px;
4079
- font-size: 11px;
4205
+ font-size: var(--cm-fs-meta);
4080
4206
  color: var(--dsw-alias-label-tertiary);
4081
4207
  }
4082
4208
 
@@ -4111,14 +4237,14 @@ body {
4111
4237
 
4112
4238
  /* 结构化报告的首行状态(如「备份已创建」):比区块标题高一级,作为面板抬头 */
4113
4239
  .reportHeadline {
4114
- font-size: 12.5px;
4240
+ font-size: var(--cm-fs-base);
4115
4241
  font-weight: 600;
4116
4242
  color: var(--dsw-alias-label-primary);
4117
4243
  margin-bottom: 2px;
4118
4244
  }
4119
4245
 
4120
4246
  .reportText {
4121
- font-size: 12px;
4247
+ font-size: var(--cm-fs-table);
4122
4248
  color: var(--dsw-alias-label-secondary);
4123
4249
  /* 报告正文是纯文本块:<pre> 的 UA 默认 white-space: pre 会让长行(导入失败原因 /
4124
4250
  回滚项 / 警告文本)横向溢出,并被父容器 .reportView 的 overflow: hidden 直接裁掉 ——
@@ -4145,10 +4271,10 @@ body {
4145
4271
  gap: 8px;
4146
4272
  padding: 8px 12px;
4147
4273
  border: 1px solid color-mix(in srgb, var(--cm-error) 45%, transparent);
4148
- border-radius: 8px;
4274
+ border-radius: var(--cm-r-3);
4149
4275
  background: color-mix(in srgb, var(--cm-error) 8%, transparent);
4150
4276
  margin: 0 0 10px;
4151
- font-size: 12px;
4277
+ font-size: var(--cm-fs-table);
4152
4278
  }
4153
4279
 
4154
4280
  .errorTitle {
@@ -4167,7 +4293,7 @@ body {
4167
4293
  .errorList {
4168
4294
  margin: 4px 0 0;
4169
4295
  padding-left: 18px;
4170
- font-size: 11px;
4296
+ font-size: var(--cm-fs-meta);
4171
4297
  }
4172
4298
 
4173
4299
  .errorItem {
@@ -4206,9 +4332,9 @@ body {
4206
4332
  align-items: center;
4207
4333
  height: 16px;
4208
4334
  padding: 0 6px;
4209
- border-radius: 4px;
4335
+ border-radius: var(--cm-r-1);
4210
4336
  background: var(--dsw-alias-interactive-bg-hover);
4211
- font-size: 11px;
4337
+ font-size: var(--cm-fs-meta);
4212
4338
  font-weight: 600;
4213
4339
  color: var(--dsw-alias-label-secondary);
4214
4340
  white-space: nowrap;
@@ -4259,7 +4385,7 @@ body {
4259
4385
  gap: 8px;
4260
4386
  width: 100%;
4261
4387
  padding: 4px 6px;
4262
- border-radius: 6px;
4388
+ border-radius: var(--cm-r-2);
4263
4389
  }
4264
4390
 
4265
4391
  .restorePlanRow {
@@ -4284,7 +4410,7 @@ body {
4284
4410
  flex: 1;
4285
4411
  min-width: 0;
4286
4412
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
4287
- font-size: 12px;
4413
+ font-size: var(--cm-fs-table);
4288
4414
  color: var(--dsw-alias-label-primary);
4289
4415
  overflow: hidden;
4290
4416
  text-overflow: ellipsis;
@@ -4294,7 +4420,7 @@ body {
4294
4420
  .restorePlanStat {
4295
4421
  flex: none;
4296
4422
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
4297
- font-size: 11px;
4423
+ font-size: var(--cm-fs-meta);
4298
4424
  color: var(--dsw-alias-label-tertiary);
4299
4425
  font-variant-numeric: tabular-nums;
4300
4426
  white-space: nowrap;
@@ -4308,7 +4434,7 @@ body {
4308
4434
 
4309
4435
  .restorePlanNote {
4310
4436
  padding: 0 6px 4px 24px;
4311
- font-size: 11px;
4437
+ font-size: var(--cm-fs-meta);
4312
4438
  color: var(--dsw-alias-label-secondary);
4313
4439
  overflow-wrap: anywhere;
4314
4440
  }
@@ -4334,7 +4460,7 @@ body {
4334
4460
  background: none;
4335
4461
  padding: 0;
4336
4462
  color: var(--dsw-alias-label-secondary);
4337
- font-size: 11px;
4463
+ font-size: var(--cm-fs-meta);
4338
4464
  font-weight: 700;
4339
4465
  cursor: pointer;
4340
4466
  }
@@ -4345,13 +4471,13 @@ body {
4345
4471
 
4346
4472
  .diffGroupToggle:focus-visible {
4347
4473
  outline: none;
4348
- border-radius: 4px;
4474
+ border-radius: var(--cm-r-1);
4349
4475
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--cm-accent) 55%, transparent);
4350
4476
  }
4351
4477
 
4352
4478
  .diffStatTotal {
4353
4479
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
4354
- font-size: 11px;
4480
+ font-size: var(--cm-fs-meta);
4355
4481
  font-variant-numeric: tabular-nums;
4356
4482
  }
4357
4483
 
@@ -4383,7 +4509,7 @@ body {
4383
4509
  padding: 2px 6px;
4384
4510
  border-bottom: 1px solid var(--dsw-alias-border-l1);
4385
4511
  /* 与差异正文同一档字号:文件头是这半张表的标题,不应比正文小一号 */
4386
- font-size: 12px;
4512
+ font-size: var(--cm-fs-table);
4387
4513
  line-height: 1.5;
4388
4514
  }
4389
4515
 
@@ -4453,7 +4579,7 @@ body {
4453
4579
  /* 编辑器式行节奏(2026-10-14 用户要求按参考图对齐):12px × 1.5 + 单元格上下 1px 内边距
4454
4580
  ⇒ 每行 20px(参考图是 22px;845px 宽的侧栏里 24 行会折成 35 个视觉行,22px 差一行就溢出
4455
4581
  ⇒ 用户第二次实测「还是有滚动条」,故收到 20px 换掉那条滚动条)。 */
4456
- font-size: 12px;
4582
+ font-size: var(--cm-fs-table);
4457
4583
  line-height: 1.5;
4458
4584
  }
4459
4585
 
@@ -4471,7 +4597,7 @@ body {
4471
4597
  border-bottom: 1px solid var(--dsw-alias-border-l1);
4472
4598
  border-right: 1px solid var(--dsw-alias-border-l1);
4473
4599
  color: var(--dsw-alias-label-tertiary);
4474
- font-size: 11px;
4600
+ font-size: var(--cm-fs-meta);
4475
4601
  line-height: 1.5;
4476
4602
  font-weight: 600;
4477
4603
  text-align: left;
@@ -4549,7 +4675,7 @@ body {
4549
4675
 
4550
4676
  .rollbackBox {
4551
4677
  border: 1px solid var(--dsw-alias-border-l2);
4552
- border-radius: 8px;
4678
+ border-radius: var(--cm-r-3);
4553
4679
  background: var(--dsw-alias-bg-base);
4554
4680
  padding: 8px 10px;
4555
4681
  margin-bottom: 10px;
@@ -4589,7 +4715,7 @@ body {
4589
4715
  .cliName,
4590
4716
  .cliCommand {
4591
4717
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
4592
- font-size: 11px;
4718
+ font-size: var(--cm-fs-meta);
4593
4719
  }
4594
4720
 
4595
4721
  .cliCommand {
@@ -4614,8 +4740,8 @@ body {
4614
4740
  /* 左右内边距:行位于 .historyScroll(带边框的滚动容器)内,此前 padding 只有纵向
4615
4741
  → 时间/摘要文字紧贴容器左边框(实测仅 1px,即边框本身)。 */
4616
4742
  padding: 6px 8px;
4617
- border-bottom: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1) 55%, transparent);
4618
- font-size: 12px;
4743
+ border-bottom: 0.5px solid var(--dsw-alias-border-l2);
4744
+ font-size: var(--cm-fs-table);
4619
4745
  }
4620
4746
 
4621
4747
  .historyRow:last-child {
@@ -4645,19 +4771,19 @@ body {
4645
4771
  .historyTime {
4646
4772
  flex: none;
4647
4773
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
4648
- font-size: 11px;
4774
+ font-size: var(--cm-fs-meta);
4649
4775
  color: var(--dsw-alias-label-tertiary);
4650
4776
  padding-top: 1px;
4651
4777
  }
4652
4778
 
4653
4779
  .historySections {
4654
- font-size: 11px;
4780
+ font-size: var(--cm-fs-meta);
4655
4781
  color: var(--dsw-alias-label-tertiary);
4656
4782
  }
4657
4783
 
4658
4784
  .profileRow {
4659
4785
  border: 1px solid var(--dsw-alias-border-l1);
4660
- border-radius: 8px;
4786
+ border-radius: var(--cm-r-3);
4661
4787
  background: var(--dsw-alias-bg-layer-2);
4662
4788
  padding: 8px 12px;
4663
4789
  margin-bottom: 6px;
@@ -4672,7 +4798,7 @@ body {
4672
4798
  display: flex;
4673
4799
  align-items: center;
4674
4800
  gap: 8px;
4675
- font-size: 12px;
4801
+ font-size: var(--cm-fs-table);
4676
4802
  }
4677
4803
 
4678
4804
  .profileRowMain {
@@ -4720,7 +4846,7 @@ button.profileRowMain {
4720
4846
  .profileRowMeta {
4721
4847
  display: block;
4722
4848
  max-width: 100%;
4723
- font-size: 11px;
4849
+ font-size: var(--cm-fs-meta);
4724
4850
  font-weight: 400;
4725
4851
  color: var(--dsw-alias-label-tertiary);
4726
4852
  overflow: hidden;
@@ -4733,7 +4859,7 @@ button.profileRowMain {
4733
4859
  display: flex;
4734
4860
  flex-direction: column;
4735
4861
  gap: 2px;
4736
- font-size: 11px;
4862
+ font-size: var(--cm-fs-meta);
4737
4863
  min-width: 0;
4738
4864
  }
4739
4865
 
@@ -4782,7 +4908,7 @@ button.profileRowMain:hover {
4782
4908
  /* 作者名外链(AboutPanel):该组件一直在引用本类,但此前从未定义 ——
4783
4909
  作者名因此落回浏览器默认 <a> 样式(下划线 + 字号/行高与相邻标签不一致)。 */
4784
4910
  .aboutAuthor {
4785
- font-size: 12.5px;
4911
+ font-size: var(--cm-fs-base);
4786
4912
  font-weight: 600;
4787
4913
  color: var(--cm-accent);
4788
4914
  text-decoration: none;
@@ -4794,15 +4920,15 @@ button.profileRowMain:hover {
4794
4920
  }
4795
4921
 
4796
4922
  .aboutAuthor:focus-visible {
4797
- outline: 2px solid var(--cm-accent);
4923
+ outline: var(--cm-focus-width) solid var(--cm-focus-color);
4798
4924
  outline-offset: 1px;
4799
- border-radius: 4px;
4925
+ border-radius: var(--cm-r-1);
4800
4926
  }
4801
4927
 
4802
4928
  .consultDimension {
4803
4929
  padding: 6px 0;
4804
- border-bottom: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1) 55%, transparent);
4805
- font-size: 12px;
4930
+ border-bottom: 0.5px solid var(--dsw-alias-border-l2);
4931
+ font-size: var(--cm-fs-table);
4806
4932
  }
4807
4933
 
4808
4934
  .consultDimension:last-child {
@@ -4909,7 +5035,7 @@ button.profileRowMain:hover {
4909
5035
 
4910
5036
  .marketReviewScroll {
4911
5037
  border: 1px solid var(--dsw-alias-border-l1);
4912
- border-radius: 8px;
5038
+ border-radius: var(--cm-r-3);
4913
5039
  background: var(--dsw-alias-bg-base);
4914
5040
  padding: 6px 10px;
4915
5041
  }
@@ -5023,7 +5149,7 @@ button.profileRowMain:hover {
5023
5149
  gap: 8px;
5024
5150
  padding: 8px 10px;
5025
5151
  border: 1px solid var(--dsw-alias-border-l1);
5026
- border-radius: 8px;
5152
+ border-radius: var(--cm-r-3);
5027
5153
  background: var(--dsw-alias-bg-layer-2);
5028
5154
  min-width: 0;
5029
5155
  }
@@ -5053,7 +5179,7 @@ button.profileRowMain:hover {
5053
5179
  }
5054
5180
 
5055
5181
  .sourceRowName {
5056
- font-size: 12px;
5182
+ font-size: var(--cm-fs-table);
5057
5183
  font-weight: 600;
5058
5184
  color: var(--dsw-alias-label-primary);
5059
5185
  min-width: 0;
@@ -5071,7 +5197,7 @@ button.profileRowMain:hover {
5071
5197
  display: block;
5072
5198
  margin-top: 4px;
5073
5199
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
5074
- font-size: 11px;
5200
+ font-size: var(--cm-fs-meta);
5075
5201
  line-height: 1.5;
5076
5202
  color: var(--dsw-alias-label-tertiary);
5077
5203
  overflow-wrap: anywhere;
@@ -5084,7 +5210,7 @@ button.profileRowMain:hover {
5084
5210
  gap: 4px;
5085
5211
  margin: 6px 0 0;
5086
5212
  padding: 0;
5087
- font-size: 11px;
5213
+ font-size: var(--cm-fs-meta);
5088
5214
  color: var(--dsw-alias-label-secondary);
5089
5215
  }
5090
5216
 
@@ -5102,9 +5228,9 @@ button.profileRowMain:hover {
5102
5228
  .skipCode {
5103
5229
  flex: none;
5104
5230
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
5105
- font-size: 11px;
5231
+ font-size: var(--cm-fs-meta);
5106
5232
  padding: 1px 4px;
5107
- border-radius: 4px;
5233
+ border-radius: var(--cm-r-1);
5108
5234
  background: color-mix(in srgb, var(--dsw-alias-label-tertiary) 12%, transparent);
5109
5235
  color: var(--dsw-alias-label-secondary);
5110
5236
  white-space: nowrap;
@@ -5120,7 +5246,7 @@ button.profileRowMain:hover {
5120
5246
  /* 未迁移项的计数与来源(如「来源:claude-code · 3 项」):仍是文本,但比解释低一级 */
5121
5247
  .skipMeta {
5122
5248
  flex: none;
5123
- font-size: 11px;
5249
+ font-size: var(--cm-fs-meta);
5124
5250
  color: var(--dsw-alias-label-tertiary);
5125
5251
  font-variant-numeric: tabular-nums;
5126
5252
  }
@@ -5130,11 +5256,18 @@ button.profileRowMain:hover {
5130
5256
  定位:本插件**接管** ui-chat 的 conversation.chat.node / user 渲染器后,自己渲染的用户消息气泡。
5131
5257
  它渲染在**插件设置页子树之外**(聊天流里,不是 .section 的 DOM 子树),因此 §1 定义在 .section
5132
5258
  上的 --cm-* token 在这里**不会继承** —— .chatEntryScope 把用到的那一小撮就地重声明一次。
5133
- ⚠️ 这里**不新增 token 档位**(字号/间距/圆角全部复用 §1 已冻结的档位):
5134
- 宿主用户气泡用的是 --dsw-radius-xl / --dsw-specific-bubble / 14px,本仓库 token 层没有这三档
5135
- (**底色是唯一必须跟随宿主的**:2026-10-15 修「浅色下气泡看不见」—— 见 --cm-chat-bubble 的定义行),
5136
- 剩余差异是**已知且如实登记**的(圆角 8px < 宿主 14px、字号 12.5px < 宿主 14px),
5137
- 如需逐像素一致必须先改 DESIGN.md §3–§5 —— 本任务明确不做。
5259
+ ⚠️ 这里**不新增 scale 档位**(间距/圆角全部复用 §1 已冻结的档位;字号/行高/限宽是**跟随宿主的活值**,
5260
+ 见下面 --cm-fs-base / --cm-lh-base 的定义行 —— 那不是新档位,是宿主同一个变量的镜像)。
5261
+ **必须跟随宿主的四档**(逐条都在 §15b 的规则里注明理由):
5262
+ · 底色 --dsw-specific-bubble(2026-10-15 修「浅色下气泡看不见」);
5263
+ · 字号 --dsh-content-font-size(2026-10-17 修 issue #93「用户气泡字号写死 12.5px,不跟随内容字号」);
5264
+ · 行高 calc(22px + --dsh-content-font-delta)(同上,宿主 .bubble 同一条公式);
5265
+ · 限宽 calc(--dsh-chat-content-width * .702)(同上,宿主 .userStack 同一条公式)。
5266
+ **2026-10-17(用户要求「与 DSH 原生气泡完全一致」)**:不再留「近似档」—— 圆角/内边距/间距/
5267
+ 动作行几何/文件卡/引用行全部改成宿主 MessageItem + MessageIconActions 的同一条取值(见
5268
+ .chatEntryScope 里那组镜像 token 的注释)。已登记的上一版近似档(圆角 8px、动作行 24px、
5269
+ 时间 11px、附件行 gap 4px)**全部收回**;仍未做的是**时间文案**(宿主按「今天/昨天」自动切换,
5270
+ 我们只显示 HH:mm)与 rest 块的 JsonBlock 外观。
5138
5271
 
5139
5272
  类名与审查口径:
5140
5273
  · .chatBubble 负责「用户消息绝不消失」的**可见文本**承载(white-space: pre-wrap 保留换行/空白);
@@ -5151,7 +5284,38 @@ button.profileRowMain:hover {
5151
5284
  --cm-line-1: var(--dsw-alias-border-l1);
5152
5285
  --cm-line-2: var(--dsw-alias-border-l2);
5153
5286
  --cm-fs-meta: 11px;
5154
- --cm-fs-base: 12.5px;
5287
+ /* 正文基准**跟随宿主「内容字号」**(2026-10-17 修 issue #93)。宿主同一条气泡写的就是
5288
+ var(--dsh-content-font-size,14px)(ui-chat 的 .bubble),而 --dsh-content-font-size 由
5289
+ ui-layout 的 ThemePresenter 写在 **body** 上 ⇒ 聊天流里直接继承得到,这里消费即可。
5290
+ 此前写死 12.5px(= §1 的面板基准),后果是 DSH 的「内容字号」设置**在用户自己的消息上完全失效**:
5291
+ 真机(内容字号 21 / 深浅色无关)同一张截图量字形高 —— 助手正文 19px、我们的气泡 11px,比例 0.58。
5292
+ 兜底 14px = 宿主缺档时的同一取值(**不能**兜回 12.5px:那是面板档,会让这里重新脱钩)。
5293
+ ⚠️ 只有这**一处**改:§1 body 的 --cm-fs-base 仍是 12.5px(插件面板基准),一动就全站字号地震。
5294
+ --cm-fs-meta 也不动(时间戳 / 动作标签 / 文件卡仍是 11px 档,pinned by 本文件 §15b 的其余规则)。 */
5295
+ --cm-fs-base: var(--dsh-content-font-size, 14px);
5296
+ /* 行高也跟随宿主**同一条公式**(宿主 .bubble = calc(22px + var(--dsh-content-font-delta,0px)))。
5297
+ 只改字号不够:21px 下 line-height:1.5 = 31.5px,宿主是 29px(22 + delta 7)⇒ 气泡比助手正文松 2.5px/行。
5298
+ --dsh-content-font-delta 同样由宿主定义在 body 上(= 内容字号 - 14px,缺档时 0px ⇒ 退化成 22px)。 */
5299
+ --cm-lh-base: calc(22px + var(--dsh-content-font-delta, 0px));
5300
+ /* —— 2026-10-17:与宿主的 MessageItem / MessageIconActions **逐值对齐**(用户要求「完全一致」)。
5301
+ 取值全部从本机 app.asar 的 ui-chat 产物抽出(MessageItem:.userRow/.userStack/.bubble/
5302
+ .attachmentRow/.fileCard/.fileIcon/.fileContent/.fileName/.fileMeta/.referenceSummary;
5303
+ MessageIconActions:.actions/.timeStart/.action)。与上一条同一条纪律:**这些是「宿主活值的镜像」,
5304
+ 不是我们的新 scale 档位**;凡 `--dsw-*` 只出现在本定义块里(三层单向依赖)。
5305
+ 宿主 radius 档(ui-theme 抽出):xs 4 / sm 8 / md 12 / lg 16 / **xl 20** —— 气泡与文件卡用的是 xl。 */
5306
+ --cm-text-2: var(--dsw-alias-label-secondary);
5307
+ --cm-r-chat: var(--dsw-radius-xl, 20px);
5308
+ --cm-r-act: var(--dsw-radius-sm, 8px);
5309
+ --cm-chat-card-bg: var(--dsw-specific-input-major, transparent);
5310
+ --cm-chat-hover-bg: var(--dsw-alias-interactive-bg-hover, var(--cm-line-1));
5311
+ --cm-fs-second: var(--dsh-content-font-size-secondary, 13px);
5312
+ --cm-lh-second: calc(24px + var(--dsh-content-font-delta, 0px));
5313
+ --cm-lh-ref: calc(18px + var(--dsh-content-font-delta-secondary, 0px));
5314
+ --cm-fs-card: 14px;
5315
+ --cm-lh-card: 22px;
5316
+ --cm-lh-meta: 15px;
5317
+ --cm-chat-action: calc(28px + var(--dsh-content-font-delta, 0px));
5318
+ --cm-chat-glyph: calc(15px + var(--dsh-content-font-delta, 0px));
5155
5319
  --cm-sp-2: 4px;
5156
5320
  --cm-sp-3: 6px;
5157
5321
  --cm-sp-4: 8px;
@@ -5164,7 +5328,7 @@ button.profileRowMain:hover {
5164
5328
  min-width: 0;
5165
5329
  color: var(--cm-text-1);
5166
5330
  font-size: var(--cm-fs-base);
5167
- line-height: 1.5;
5331
+ line-height: var(--cm-lh-base);
5168
5332
  }
5169
5333
 
5170
5334
  /* 用户消息行:右对齐(与宿主 .userRow 同构) */
@@ -5175,24 +5339,28 @@ button.profileRowMain:hover {
5175
5339
  gap: var(--cm-sp-3);
5176
5340
  }
5177
5341
 
5178
- /* 气泡列:限宽(宿主是 min(画布宽 * .702, 82%);我们是固定近似,见文件头注释) */
5342
+ /* 气泡列:限宽 —— 与宿主 .userStack 同一条公式(2026-10-17 修 issue #93)。
5343
+ 旧值是固定近似 min(620px, 82%):字号调大后 620px 会明显早于宿主换行(宿主同宽度下按
5344
+ --dsh-chat-content-width * .702 算,默认 748 * .702 ≈ 525px)。兜底 748px = 宿主缺档时的同一取值。
5345
+ ⚠️ 变量定义在 ui-conversation 的聊天 body(.body / .embeddedBody)上,本节点恒在它之下。 */
5179
5346
  .chatEntryStack {
5180
5347
  display: flex;
5181
5348
  flex-direction: column;
5182
5349
  align-items: flex-end;
5183
5350
  gap: var(--cm-sp-4);
5184
5351
  min-width: 0;
5185
- max-width: min(620px, 82%);
5352
+ max-width: min(calc(var(--dsh-chat-content-width, 748px) * .702), 82%);
5186
5353
  }
5187
5354
 
5188
- /* 用户气泡:pre-wrap 保留换行与空白(禁用! 会改文案语义),长词强制断行 */
5355
+ /* 用户气泡:与宿主 .bubble **逐值同式**(background / border-radius / max-width / padding /
5356
+ white-space / word-break;字号与行高由 .chatEntryScope 的同名镜像给出)。
5357
+ 2026-10-17(用户要求「完全一致」):① 圆角改成宿主那一档 `--dsw-radius-xl`(= 20px,不是此前登记的
5358
+ 8px 近似档);② **去掉此前的 `display:flex; flex-direction:column; gap:6px`** —— 宿主那条气泡是**块**,
5359
+ 正文与技能/引用 chip 在同一行内流;flex 列会把每个 chip 挤成独立一行(消息一带技能就明显变形)。 */
5189
5360
  .chatBubble {
5190
- display: flex;
5191
- flex-direction: column;
5192
- gap: var(--cm-sp-3);
5193
5361
  max-width: 100%;
5194
5362
  padding: var(--cm-sp-5) var(--cm-sp-8);
5195
- border-radius: var(--cm-r-3);
5363
+ border-radius: var(--cm-r-chat);
5196
5364
  background: var(--cm-chat-bubble);
5197
5365
  color: var(--cm-text-1);
5198
5366
  white-space: pre-wrap;
@@ -5209,35 +5377,57 @@ button.profileRowMain:hover {
5209
5377
  border-left: 2px solid var(--cm-text-1);
5210
5378
  }
5211
5379
 
5212
- /* 附件行(图片 + 文件卡):宿主是 .attachmentRow,横向排列、允许换行 */
5380
+ /* 附件行:宿主 .attachmentRow = flex-wrap:wrap + justify-content:flex-end + gap:8px + max-width:100% */
5213
5381
  .chatAttachmentRow {
5214
5382
  display: flex;
5215
5383
  flex-wrap: wrap;
5216
- align-items: flex-end;
5217
5384
  justify-content: flex-end;
5218
- gap: var(--cm-sp-2);
5219
- min-width: 0;
5385
+ gap: var(--cm-sp-4);
5386
+ max-width: 100%;
5220
5387
  }
5221
5388
 
5222
- /* 文件卡:扩展名徽标 + 文件名 + 体积(宿主用 ui-primitives 的 FileTypeIcon,本仓库拿不到,
5223
- 用扩展名徽标做**类型图标兜底** —— 不新增图标、不新增依赖) */
5389
+ /* 文件卡:与宿主 .fileCard **逐值同式**(2026-10-17「完全一致」)——
5390
+ 宿主 = flex:0 0 240px + width:240px + min-height:64px + padding:8px 12px + gap:10px +
5391
+ radius `--dsw-radius-xl`(20px) + border .5px `--dsw-alias-border-l2` + 底 `--dsw-specific-input-major`;
5392
+ 内部 = 28px 类型图标 + 右列(文件名 14px/500/22px、元信息 12px/15px)。
5393
+ 类型图标**优先宿主的 FileTypeIcon**(帧内惰取);拿不到才回落 .chatFileExt 扩展名徽标。 */
5224
5394
  .chatFileCard {
5225
5395
  display: inline-flex;
5396
+ flex: 0 0 240px;
5226
5397
  align-items: center;
5227
- gap: var(--cm-sp-3);
5228
- max-width: 100%;
5229
- padding: var(--cm-sp-2) var(--cm-sp-4);
5230
- /* 2026-10-15 与宿主对齐:宿主文件卡 = .5px solid --dsw-alias-border-l2(浅色 #0000001a ≈ 10% 黑),
5231
- 我们此前用 --cm-line-1(= border-l1 = #0000000a ≈ 4% 黑)—— 卡片描边比宿主淡一档。 */
5398
+ gap: var(--cm-sp-5);
5399
+ box-sizing: border-box;
5400
+ width: 240px;
5401
+ min-height: 64px;
5402
+ padding: var(--cm-sp-4) var(--cm-sp-6);
5232
5403
  border: 0.5px solid var(--cm-line-2);
5233
- border-radius: var(--cm-r-2);
5234
- background: var(--cm-surface-2);
5235
- font-size: var(--cm-fs-meta);
5404
+ border-radius: var(--cm-r-chat);
5405
+ background: var(--cm-chat-card-bg);
5236
5406
  }
5237
5407
 
5408
+ /* 宿主 .fileIcon:图标固定 28px(我们的 FileTypeIcon 由组件传 size=28) */
5409
+ .chatFileIcon {
5410
+ flex: none;
5411
+ width: 28px;
5412
+ height: 28px;
5413
+ }
5414
+
5415
+ /* 宿主 .fileContent:右列(文件名 + 元信息) */
5416
+ .chatFileContent {
5417
+ display: flex;
5418
+ flex-direction: column;
5419
+ flex: 1;
5420
+ min-width: 0;
5421
+ }
5422
+
5423
+ /* 类型图标兜底(宿主 FileTypeIcon 拿不到时):占住同一个 28px 槽位,不改变卡片尺寸 */
5238
5424
  .chatFileExt {
5425
+ display: inline-flex;
5239
5426
  flex: none;
5240
- padding: 0 var(--cm-sp-2);
5427
+ align-items: center;
5428
+ justify-content: center;
5429
+ min-width: 28px;
5430
+ height: 28px;
5241
5431
  border-radius: var(--cm-r-2);
5242
5432
  background: var(--cm-line-1);
5243
5433
  color: var(--cm-text-1);
@@ -5245,17 +5435,25 @@ button.profileRowMain:hover {
5245
5435
  letter-spacing: 0.02em;
5246
5436
  }
5247
5437
 
5438
+ /* 宿主 .fileName:primary / 14px / 500 / 行高 22px(宿主写死字面量,这里镜像同一个值) */
5248
5439
  .chatFileName {
5249
- min-width: 0;
5250
5440
  overflow: hidden;
5441
+ color: var(--cm-text-1);
5442
+ font-size: var(--cm-fs-card);
5443
+ font-weight: 500;
5444
+ line-height: var(--cm-lh-card);
5251
5445
  text-overflow: ellipsis;
5252
5446
  white-space: nowrap;
5253
5447
  }
5254
5448
 
5449
+ /* 宿主 .fileMeta:tertiary / 12px / 行高 15px */
5255
5450
  .chatFileMeta {
5256
- flex: none;
5451
+ overflow: hidden;
5257
5452
  color: var(--cm-text-3);
5258
- font-size: var(--cm-fs-meta);
5453
+ font-size: 12px;
5454
+ line-height: var(--cm-lh-meta);
5455
+ text-overflow: ellipsis;
5456
+ white-space: nowrap;
5259
5457
  }
5260
5458
 
5261
5459
  /* 未知 / rest 块:宿主是 JsonBlock,这里用原生 details + 预格式化 JSON */
@@ -5280,20 +5478,31 @@ button.profileRowMain:hover {
5280
5478
  word-break: break-all;
5281
5479
  }
5282
5480
 
5283
- /* 动作行:时间 + 复制 + 回退(宿主把 MessageIconActions 与气泡并排在同一行) */
5481
+ /* 动作行:宿主 MessageIconActions = .actions(height 28px+delta / gap 8px)+ MessageItem 的
5482
+ .actions(margin-top:4px / margin-left:-6px,用负外边距把图标行与气泡右缘对齐)。
5483
+ ⚠️ 这块**不能**用 --cm-r-* / --cm-sp-* 的近似档:宿主写的是 calc(28px + --dsh-content-font-delta),
5484
+ 内容字号放大时图标行跟着长高,写死 28px 会在 21px 字号下比宿主矮 7px。 */
5284
5485
  .chatEntryActions {
5285
5486
  display: flex;
5286
5487
  align-items: center;
5287
- gap: var(--cm-sp-2);
5488
+ gap: var(--cm-sp-4);
5489
+ height: var(--cm-chat-action);
5490
+ margin-top: var(--cm-sp-2);
5491
+ margin-left: calc(-1 * var(--cm-sp-3));
5288
5492
  }
5289
5493
 
5494
+ /* 时刻:宿主 .timeStart(tertiary / 13px 次级字号 / 行高 24+delta / 右侧 12px 让位给图标) */
5290
5495
  .chatEntryTime {
5291
5496
  color: var(--cm-text-3);
5292
- font-size: var(--cm-fs-meta);
5497
+ font-size: var(--cm-fs-second);
5498
+ line-height: var(--cm-lh-second);
5499
+ white-space: nowrap;
5500
+ padding-right: var(--cm-sp-6);
5293
5501
  }
5294
5502
 
5295
5503
  .chatEntryNotice {
5296
- max-width: min(620px, 82%);
5504
+ /* 与 .chatEntryStack 同一口径(见上面那条注释) */
5505
+ max-width: min(calc(var(--dsh-chat-content-width, 748px) * .702), 82%);
5297
5506
  color: var(--cm-text-3);
5298
5507
  font-size: var(--cm-fs-meta);
5299
5508
  }
@@ -5302,27 +5511,51 @@ button.profileRowMain:hover {
5302
5511
  我们只复刻这一行的**文本**;chip 外观与可点开能力仍是已登记差距(G-39)。 */
5303
5512
  .chatEntryReference {
5304
5513
  color: var(--cm-text-3);
5305
- font-size: var(--cm-fs-meta);
5514
+ font-size: var(--cm-fs-second);
5515
+ line-height: var(--cm-lh-ref);
5306
5516
  }
5307
5517
 
5308
- /* 复制动作按钮:26px 触达区,与 IconButton 观感同源(图标走 currentColor) */
5518
+ /* 图标动作按钮:与宿主 .action 逐值同式 —— 28px+delta 触达区、padding 6px、radius-sm、
5519
+ 图标 15px+delta(宿主 `.action svg` 同一条公式)、hover 底色走宿主的 interactive-bg-hover。 */
5309
5520
  .chatActionBtn {
5310
5521
  display: inline-flex;
5311
5522
  align-items: center;
5312
5523
  justify-content: center;
5313
- width: 24px;
5314
- height: 24px;
5315
- padding: 0;
5524
+ width: var(--cm-chat-action);
5525
+ height: var(--cm-chat-action);
5526
+ padding: var(--cm-sp-3);
5316
5527
  border: 0;
5317
- border-radius: var(--cm-r-2);
5528
+ border-radius: var(--cm-r-act);
5318
5529
  background: transparent;
5319
5530
  color: var(--cm-text-3);
5320
5531
  cursor: pointer;
5321
5532
  }
5322
5533
 
5534
+ .chatActionBtn svg {
5535
+ width: var(--cm-chat-glyph);
5536
+ height: var(--cm-chat-glyph);
5537
+ }
5538
+
5323
5539
  .chatActionBtn:hover {
5324
- background: var(--cm-line-1);
5325
- color: var(--cm-text-1);
5540
+ background: var(--cm-chat-hover-bg);
5541
+ color: var(--cm-text-2);
5542
+ }
5543
+
5544
+ /* 动作行的显现语义(宿主 MessageIconActions 同一条规则):
5545
+ 在支持 hover 的设备上,**后面还有用户/steering 消息**的那几条默认把动作行藏起来(opacity 0),
5546
+ 指针进入或键盘焦点落到这一行时显现;最后一条用户消息的动作行则常亮。
5547
+ 用宿主自己的 `data-chat-flow-kind` 祖先属性表达「后面还有一条」——本节点就渲染在那个行的内部,
5548
+ 所以这条选择器与宿主对自家 .actions 用的是同一套结构(绝不自己数 DOM 节点)。 */
5549
+ @media (hover: hover) {
5550
+ :is([data-chat-flow-kind='user'], [data-chat-flow-kind='steering']):has(~ :is([data-chat-flow-kind='user'], [data-chat-flow-kind='steering'])) .chatEntryActions {
5551
+ opacity: 0;
5552
+ transition: opacity var(--cm-motion-fast);
5553
+ }
5554
+
5555
+ :is([data-chat-flow-kind='user'], [data-chat-flow-kind='steering']):has(~ :is([data-chat-flow-kind='user'], [data-chat-flow-kind='steering'])):hover .chatEntryActions,
5556
+ :is([data-chat-flow-kind='user'], [data-chat-flow-kind='steering']):has(~ :is([data-chat-flow-kind='user'], [data-chat-flow-kind='steering'])):focus-within .chatEntryActions {
5557
+ opacity: 1;
5558
+ }
5326
5559
  }
5327
5560
 
5328
5561
  /* 回退入口与复制入口共用上面这颗图标按钮(无文字标签、无边框):
@@ -5551,7 +5784,7 @@ button.profileRowMain:hover {
5551
5784
 
5552
5785
  /* 数据摘要(「共 N 个回滚点 · M 个会话」):机制说明进 ⓘ,屏上只留数字 */
5553
5786
  .rollbackSummary {
5554
- font-size: 12px;
5787
+ font-size: var(--cm-fs-table);
5555
5788
  font-weight: 600;
5556
5789
  color: var(--dsw-alias-label-secondary);
5557
5790
  font-variant-numeric: tabular-nums;
@@ -5573,7 +5806,7 @@ button.profileRowMain:hover {
5573
5806
  gap: 8px;
5574
5807
  padding: 8px 10px;
5575
5808
  border: 1px solid var(--dsw-alias-border-l1);
5576
- border-radius: 8px;
5809
+ border-radius: var(--cm-r-3);
5577
5810
  background: var(--dsw-alias-bg-layer-2);
5578
5811
  }
5579
5812
 
@@ -5588,7 +5821,7 @@ button.profileRowMain:hover {
5588
5821
 
5589
5822
  /* 会话标题:等宽(配合 .mono)+ 可断行 —— 会话 id 在 Windows 上恒为长串 */
5590
5823
  .rollbackGroupTitle {
5591
- font-size: 12px;
5824
+ font-size: var(--cm-fs-table);
5592
5825
  font-weight: 600;
5593
5826
  color: var(--dsw-alias-label-secondary);
5594
5827
  overflow-wrap: anywhere;
@@ -5603,7 +5836,7 @@ button.profileRowMain:hover {
5603
5836
  text-overflow: ellipsis;
5604
5837
  white-space: nowrap;
5605
5838
  text-align: right;
5606
- font-size: 11px;
5839
+ font-size: var(--cm-fs-meta);
5607
5840
  color: var(--dsw-alias-label-tertiary);
5608
5841
  }
5609
5842
 
@@ -5621,7 +5854,7 @@ button.profileRowMain:hover {
5621
5854
  padding: 8px 10px;
5622
5855
  border: 1px solid var(--dsw-alias-border-l1);
5623
5856
  border-left-width: 2px;
5624
- border-radius: 8px;
5857
+ border-radius: var(--cm-r-3);
5625
5858
  background: var(--dsw-alias-bg-base);
5626
5859
  }
5627
5860
 
@@ -5645,7 +5878,7 @@ button.profileRowMain:hover {
5645
5878
  }
5646
5879
 
5647
5880
  .rollbackPointTurn {
5648
- font-size: 12px;
5881
+ font-size: var(--cm-fs-table);
5649
5882
  font-weight: 600;
5650
5883
  color: var(--dsw-alias-label-primary);
5651
5884
  font-variant-numeric: tabular-nums;
@@ -5665,7 +5898,7 @@ button.profileRowMain:hover {
5665
5898
  align-items: center;
5666
5899
  gap: 6px;
5667
5900
  flex-wrap: wrap;
5668
- font-size: 11px;
5901
+ font-size: var(--cm-fs-meta);
5669
5902
  line-height: 1.5;
5670
5903
  color: var(--dsw-alias-label-tertiary);
5671
5904
  }
@@ -5722,7 +5955,7 @@ button.profileRowMain:hover {
5722
5955
  }
5723
5956
 
5724
5957
  .rollbackSessionId {
5725
- font-size: 12px;
5958
+ font-size: var(--cm-fs-table);
5726
5959
  overflow: hidden;
5727
5960
  text-overflow: ellipsis;
5728
5961
  white-space: nowrap;
@@ -5732,7 +5965,7 @@ button.profileRowMain:hover {
5732
5965
  display: flex;
5733
5966
  align-items: center;
5734
5967
  gap: 2px;
5735
- font-size: 11px;
5968
+ font-size: var(--cm-fs-meta);
5736
5969
  line-height: 1.5;
5737
5970
  color: var(--dsw-alias-label-tertiary);
5738
5971
  }
@@ -5800,7 +6033,7 @@ button.profileRowMain:hover {
5800
6033
  padding: 12px 14px;
5801
6034
  margin: 0 0 10px;
5802
6035
  border: 1px solid var(--dsw-alias-border-l1);
5803
- border-radius: 8px;
6036
+ border-radius: var(--cm-r-3);
5804
6037
  background: var(--dsw-alias-bg-layer-2);
5805
6038
  }
5806
6039
 
@@ -5819,7 +6052,7 @@ button.profileRowMain:hover {
5819
6052
  }
5820
6053
 
5821
6054
  .shMetricValue {
5822
- font-size: 13px;
6055
+ font-size: var(--cm-fs-title);
5823
6056
  font-weight: 600;
5824
6057
  line-height: 1.25;
5825
6058
  color: var(--dsw-alias-label-primary);
@@ -5827,7 +6060,7 @@ button.profileRowMain:hover {
5827
6060
  }
5828
6061
 
5829
6062
  .shMetricLabel {
5830
- font-size: 11px;
6063
+ font-size: var(--cm-fs-meta);
5831
6064
  color: var(--dsw-alias-label-tertiary);
5832
6065
  }
5833
6066
 
@@ -5856,7 +6089,7 @@ button.profileRowMain:hover {
5856
6089
  border: 1px solid var(--dsw-alias-border-l1);
5857
6090
  border-radius: 999px;
5858
6091
  background: var(--dsw-alias-bg-base);
5859
- font-size: 11px;
6092
+ font-size: var(--cm-fs-meta);
5860
6093
  line-height: 1.5;
5861
6094
  color: var(--dsw-alias-label-secondary);
5862
6095
  white-space: nowrap;
@@ -5902,7 +6135,7 @@ button.profileRowMain:hover {
5902
6135
  }
5903
6136
 
5904
6137
  .shSectionTitle {
5905
- font-size: 13px;
6138
+ font-size: var(--cm-fs-title);
5906
6139
  font-weight: 600;
5907
6140
  line-height: 1.25;
5908
6141
  color: var(--dsw-alias-label-primary);
@@ -5923,7 +6156,7 @@ button.profileRowMain:hover {
5923
6156
  padding: 8px 10px;
5924
6157
  border: 1px solid var(--dsw-alias-border-l1);
5925
6158
  border-left-width: 2px;
5926
- border-radius: 8px;
6159
+ border-radius: var(--cm-r-3);
5927
6160
  background: var(--dsw-alias-bg-layer-2);
5928
6161
  }
5929
6162
 
@@ -5955,7 +6188,7 @@ button.profileRowMain:hover {
5955
6188
  overflow: hidden;
5956
6189
  text-overflow: ellipsis;
5957
6190
  white-space: nowrap;
5958
- font-size: 12px;
6191
+ font-size: var(--cm-fs-table);
5959
6192
  font-weight: 600;
5960
6193
  color: var(--dsw-alias-label-primary);
5961
6194
  }
@@ -5974,7 +6207,7 @@ button.profileRowMain:hover {
5974
6207
  align-items: center;
5975
6208
  gap: 6px;
5976
6209
  flex-wrap: wrap;
5977
- font-size: 11px;
6210
+ font-size: var(--cm-fs-meta);
5978
6211
  line-height: 1.5;
5979
6212
  color: var(--dsw-alias-label-tertiary);
5980
6213
  }
@@ -5984,7 +6217,7 @@ button.profileRowMain:hover {
5984
6217
  display: inline-flex;
5985
6218
  align-items: center;
5986
6219
  padding: 2px 6px;
5987
- border-radius: 4px;
6220
+ border-radius: var(--cm-r-1);
5988
6221
  background: color-mix(in srgb, var(--dsw-alias-label-tertiary) 12%, transparent);
5989
6222
  color: var(--dsw-alias-label-secondary);
5990
6223
  }
@@ -6013,7 +6246,7 @@ button.profileRowMain:hover {
6013
6246
  padding: 10px 12px;
6014
6247
  margin: 0 0 10px;
6015
6248
  border: 1px solid var(--dsw-alias-border-l2);
6016
- border-radius: 8px;
6249
+ border-radius: var(--cm-r-3);
6017
6250
  background: var(--dsw-alias-bg-base);
6018
6251
  }
6019
6252
 
@@ -6031,7 +6264,7 @@ button.profileRowMain:hover {
6031
6264
  overflow: hidden;
6032
6265
  text-overflow: ellipsis;
6033
6266
  white-space: nowrap;
6034
- font-size: 12px;
6267
+ font-size: var(--cm-fs-table);
6035
6268
  font-weight: 600;
6036
6269
  color: var(--dsw-alias-label-primary);
6037
6270
  }
@@ -6042,7 +6275,7 @@ button.profileRowMain:hover {
6042
6275
  margin: 0 0 10px;
6043
6276
  padding: 0;
6044
6277
  border: 1px solid var(--dsw-alias-border-l1);
6045
- border-radius: 8px;
6278
+ border-radius: var(--cm-r-3);
6046
6279
  background: var(--dsw-alias-bg-layer-2);
6047
6280
  overflow: hidden;
6048
6281
  }
@@ -6063,7 +6296,7 @@ button.profileRowMain:hover {
6063
6296
  flex: 1 1 auto;
6064
6297
  min-width: 0;
6065
6298
  overflow-wrap: anywhere;
6066
- font-size: 11px;
6299
+ font-size: var(--cm-fs-meta);
6067
6300
  color: var(--dsw-alias-label-secondary);
6068
6301
  }
6069
6302