@icen.ai/ui 0.3.0 → 0.5.0

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 (78) hide show
  1. package/dist/behaviors/back-top.mjs +84 -0
  2. package/dist/behaviors/charts.mjs +188 -0
  3. package/dist/behaviors/command-palette.mjs +177 -0
  4. package/dist/behaviors/datatable.mjs +244 -24
  5. package/dist/behaviors/date-picker.mjs +228 -0
  6. package/dist/behaviors/input.mjs +170 -1
  7. package/dist/behaviors/notification.mjs +754 -0
  8. package/dist/behaviors/select.mjs +151 -22
  9. package/dist/behaviors/split-pane.mjs +102 -0
  10. package/dist/behaviors/upload.mjs +165 -14
  11. package/dist/components/back-top.css +88 -0
  12. package/dist/components/back-top.mjs +3 -0
  13. package/dist/components/badge.css +131 -0
  14. package/dist/components/badge.mjs +2 -0
  15. package/dist/components/breadcrumb.css +57 -0
  16. package/dist/components/card.css +68 -0
  17. package/dist/components/chart-area.css +15 -0
  18. package/dist/components/chart-area.mjs +4 -0
  19. package/dist/components/chart-bar.css +79 -0
  20. package/dist/components/chart-bar.mjs +4 -0
  21. package/dist/components/chart-gauge.css +38 -0
  22. package/dist/components/chart-gauge.mjs +4 -0
  23. package/dist/components/chart-heatmap.css +52 -0
  24. package/dist/components/chart-heatmap.mjs +4 -0
  25. package/dist/components/chart-line.css +15 -0
  26. package/dist/components/chart-line.mjs +4 -0
  27. package/dist/components/chart-pie.css +26 -0
  28. package/dist/components/chart-pie.mjs +4 -0
  29. package/dist/components/chart-radar.css +19 -0
  30. package/dist/components/chart-radar.mjs +4 -0
  31. package/dist/components/chart-sparkline.css +14 -0
  32. package/dist/components/chart-sparkline.mjs +4 -0
  33. package/dist/components/chart-stack.css +30 -0
  34. package/dist/components/chart-stack.mjs +4 -0
  35. package/dist/components/charts.css +7 -207
  36. package/dist/components/charts.mjs +9 -0
  37. package/dist/components/command-palette.css +246 -0
  38. package/dist/components/command-palette.mjs +3 -0
  39. package/dist/components/content.css +214 -0
  40. package/dist/components/copy.css +93 -0
  41. package/dist/components/copy.mjs +3 -0
  42. package/dist/components/datatable.css +86 -0
  43. package/dist/components/date-picker.css +244 -0
  44. package/dist/components/date-picker.mjs +3 -0
  45. package/dist/components/empty.css +73 -3
  46. package/dist/components/feedback.css +239 -1
  47. package/dist/components/form.css +119 -0
  48. package/dist/components/form.mjs +2 -0
  49. package/dist/components/input.css +24 -1
  50. package/dist/components/media.css +144 -1
  51. package/dist/components/nav.css +99 -0
  52. package/dist/components/notification.css +387 -0
  53. package/dist/components/notification.mjs +3 -0
  54. package/dist/components/panel.css +100 -5
  55. package/dist/components/pill.css +70 -0
  56. package/dist/components/scroll-area.css +112 -0
  57. package/dist/components/scroll-area.mjs +2 -0
  58. package/dist/components/segmented.css +75 -0
  59. package/dist/components/select.css +97 -2
  60. package/dist/components/sidebar.css +118 -0
  61. package/dist/components/slider.css +113 -0
  62. package/dist/components/split-pane.css +112 -0
  63. package/dist/components/split-pane.mjs +3 -0
  64. package/dist/components/stat.css +129 -6
  65. package/dist/components/steps.css +97 -0
  66. package/dist/components/switch.css +142 -0
  67. package/dist/components/table.css +86 -3
  68. package/dist/components/tabs.css +122 -1
  69. package/dist/components/tag.css +164 -0
  70. package/dist/components/tag.mjs +2 -0
  71. package/dist/components/toast.css +114 -0
  72. package/dist/components/toolbar.css +101 -0
  73. package/dist/components/toolbar.mjs +2 -0
  74. package/dist/components/upload.css +61 -4
  75. package/dist/index.mjs +2039 -62
  76. package/dist/registry.json +200 -24
  77. package/dist/ui.css +4865 -622
  78. package/package.json +1 -1
@@ -0,0 +1,387 @@
1
+ /*
2
+ * @icen.ai/ui — Component: notification(通知栈 v2,与 behaviors/notification 配套)
3
+ *
4
+ * 与 toast / alert 的差异(三件正交):
5
+ * - toast = 瞬时轻提示(2.6s 自动消失),右下角
6
+ * - alert = 内嵌警示条(页面流内,非浮层)
7
+ * - notification = 持久通知栈(右上角),工程级:
8
+ * 进度条 / 倒计时 / 头像 / 多按钮 / 已读未读 / 优先级 / hover 暂停 / 详情链接 / 折叠堆叠
9
+ *
10
+ * 完整契约(由 behavior 渲染):
11
+ * <div class="notification-container" role="region" aria-label="通知" data-position="top-right">
12
+ * <div class="notification [notif--success|warning|error|info]
13
+ * [.is-priority] [.is-unread] [.is-progress] [.is-clickable] [.is-paused]
14
+ * [.has-avatar]" role="alert|button">
15
+ * <span class="notification-icon">…svg 或 img.notification-avatar…</span>
16
+ * <div class="notification-content">
17
+ * <p class="notification-title">标题</p>
18
+ * <p class="notification-message">正文(支持换行)</p>
19
+ * <div class="notification-actions">
20
+ * <button class="notification-action [--primary|--danger]">按钮</button>
21
+ * </div>
22
+ * <div class="notification-link-wrap">
23
+ * <a class="notification-link" href="…">查看详情</a>
24
+ * </div>
25
+ * <div class="notification-progress">
26
+ * <div class="notification-progress-bar" style="width:64%"></div>
27
+ * <span class="notification-progress-label">64%</span>
28
+ * </div>
29
+ * </div>
30
+ * <button class="notification-close" aria-label="关闭">×</button>
31
+ * <div class="notification-countdown">
32
+ * <div class="notification-countdown-fill" style="animation-duration:5000ms"></div>
33
+ * </div>
34
+ * </div>
35
+ * </div>
36
+ */
37
+
38
+ .notification-container {
39
+ position: fixed;
40
+ top: var(--density-space-md);
41
+ right: var(--density-space-md);
42
+ z-index: var(--z-toast);
43
+ display: flex;
44
+ flex-direction: column;
45
+ gap: var(--density-space-sm);
46
+ width: 360px;
47
+ max-width: calc(100vw - var(--density-space-lg));
48
+ pointer-events: none;
49
+ }
50
+ .notification-container[data-position='top-left'] {
51
+ right: auto;
52
+ left: var(--density-space-md);
53
+ }
54
+ .notification-container[data-position='bottom-left'] {
55
+ top: auto;
56
+ bottom: var(--density-space-md);
57
+ right: auto;
58
+ left: var(--density-space-md);
59
+ }
60
+ .notification-container[data-position='bottom-right'] {
61
+ top: auto;
62
+ bottom: var(--density-space-md);
63
+ }
64
+
65
+ .notification {
66
+ pointer-events: auto;
67
+ position: relative;
68
+ display: flex;
69
+ align-items: flex-start;
70
+ gap: var(--density-space-sm);
71
+ background: var(--token-card-strong);
72
+ color: var(--token-text);
73
+ border: 1px solid var(--token-outline-soft);
74
+ border-left: 3px solid var(--token-info);
75
+ border-radius: var(--radius-md);
76
+ box-shadow: var(--token-shadow-overlay);
77
+ padding: var(--density-space-md) var(--density-space-md) var(--density-space-md) var(--density-space-sm);
78
+ overflow: hidden; /* 倒计时进度条贴底 */
79
+ animation: icen-notif-in var(--icen-tx-normal);
80
+ }
81
+ .notification.notif--success { border-left-color: var(--token-success); }
82
+ .notification.notif--warning { border-left-color: var(--token-warning); }
83
+ .notification.notif--error { border-left-color: var(--token-error); }
84
+ .notification.notif--info { border-left-color: var(--token-info); }
85
+
86
+ /* ── 优先级:高优先级强调(左侧加粗 + 更强阴影)── */
87
+ .notification.is-priority {
88
+ border-left-width: 4px;
89
+ box-shadow: var(--token-shadow-overlay), 0 0 0 1px color-mix(in srgb, var(--token-accent) 24%, transparent);
90
+ }
91
+ .notification.is-priority.notif--success { box-shadow: var(--token-shadow-overlay), 0 0 0 1px color-mix(in srgb, var(--token-success) 28%, transparent); }
92
+ .notification.is-priority.notif--warning { box-shadow: var(--token-shadow-overlay), 0 0 0 1px color-mix(in srgb, var(--token-warning) 28%, transparent); }
93
+ .notification.is-priority.notif--error { box-shadow: var(--token-shadow-overlay), 0 0 0 1px color-mix(in srgb, var(--token-error) 28%, transparent); }
94
+
95
+ /* ── 未读:标题左侧 4px 强调点 + 加粗 ── */
96
+ .notification.is-unread .notification-title::before {
97
+ content: '';
98
+ display: inline-block;
99
+ width: 6px;
100
+ height: 6px;
101
+ margin-right: 6px;
102
+ margin-bottom: 1px;
103
+ vertical-align: middle;
104
+ border-radius: var(--radius-full);
105
+ background: var(--token-accent);
106
+ flex-shrink: 0;
107
+ }
108
+ .notification.is-unread.notif--success .notification-title::before { background: var(--token-success); }
109
+ .notification.is-unread.notif--warning .notification-title::before { background: var(--token-warning); }
110
+ .notification.is-unread.notif--error .notification-title::before { background: var(--token-error); }
111
+
112
+ /* ── 可点击:整条 hover 抬升 ── */
113
+ .notification.is-clickable {
114
+ cursor: pointer;
115
+ transition:
116
+ transform var(--icen-tx-fast),
117
+ border-color var(--icen-tx-fast),
118
+ box-shadow var(--icen-tx-fast);
119
+ }
120
+ .notification.is-clickable:hover {
121
+ transform: translateY(-1px);
122
+ border-color: var(--token-accent);
123
+ }
124
+
125
+ /* ── 图标 ── */
126
+ .notification-icon {
127
+ display: inline-flex;
128
+ align-items: center;
129
+ justify-content: center;
130
+ flex-shrink: 0;
131
+ width: 22px;
132
+ height: 22px;
133
+ margin-top: 1px;
134
+ border-radius: var(--radius-full);
135
+ color: var(--token-text-faint);
136
+ }
137
+ .notification-icon svg { width: 16px; height: 16px; }
138
+ .notif--success .notification-icon { color: var(--token-success); }
139
+ .notif--warning .notification-icon { color: var(--token-warning); }
140
+ .notif--error .notification-icon { color: var(--token-error); }
141
+ .notif--info .notification-icon { color: var(--token-info); }
142
+
143
+ /* 头像(圆形图) */
144
+ .notification-avatar {
145
+ width: 28px;
146
+ height: 28px;
147
+ border-radius: var(--radius-full);
148
+ object-fit: cover;
149
+ display: block;
150
+ }
151
+ .notification.has-avatar .notification-icon {
152
+ width: 28px;
153
+ height: 28px;
154
+ margin-top: 0;
155
+ }
156
+
157
+ /* 进度通知的图标默认走品牌色 */
158
+ .notification.is-progress:not(.notif--success):not(.notif--warning):not(.notif--error) .notification-icon {
159
+ color: var(--token-accent);
160
+ }
161
+
162
+ /* ── 内容区 ── */
163
+ .notification-content {
164
+ flex: 1;
165
+ min-width: 0;
166
+ display: flex;
167
+ flex-direction: column;
168
+ gap: 2px;
169
+ }
170
+ .notification-title {
171
+ margin: 0;
172
+ font-size: var(--density-font-size-md);
173
+ font-weight: 600;
174
+ line-height: 1.4;
175
+ overflow: hidden;
176
+ text-overflow: ellipsis;
177
+ }
178
+ .notification.is-unread .notification-title {
179
+ font-weight: 700;
180
+ }
181
+ .notification-message {
182
+ margin: 0;
183
+ font-size: var(--density-font-size-sm);
184
+ color: var(--token-text-muted);
185
+ line-height: 1.5;
186
+ word-break: break-word;
187
+ }
188
+
189
+ /* ── 多动作按钮 ── */
190
+ .notification-actions {
191
+ display: flex;
192
+ flex-wrap: wrap;
193
+ gap: var(--density-space-xs);
194
+ margin-top: var(--density-space-sm);
195
+ }
196
+ .notification-action {
197
+ display: inline-flex;
198
+ align-items: center;
199
+ height: 24px;
200
+ padding: 0 var(--density-space-sm);
201
+ border: 1px solid var(--token-outline-soft);
202
+ border-radius: var(--radius-sm);
203
+ background: var(--token-fill-1);
204
+ color: var(--token-text-muted);
205
+ font: inherit;
206
+ font-size: var(--density-font-size-xs);
207
+ font-weight: 500;
208
+ cursor: pointer;
209
+ -webkit-tap-highlight-color: transparent;
210
+ transition: background-color var(--icen-tx-fast), color var(--icen-tx-fast), border-color var(--icen-tx-fast);
211
+ }
212
+ .notification-action:hover {
213
+ background: var(--token-fill-2);
214
+ color: var(--token-text);
215
+ border-color: var(--token-accent);
216
+ }
217
+ .notification-action:focus-visible {
218
+ outline: none;
219
+ box-shadow: var(--icen-ring);
220
+ }
221
+ /* primary:实底 accent */
222
+ .notification-action--primary {
223
+ background: var(--token-accent);
224
+ color: var(--token-on-accent, #fff);
225
+ border-color: var(--token-accent);
226
+ }
227
+ .notification-action--primary:hover {
228
+ background: var(--token-accent-deep, var(--token-accent));
229
+ color: var(--token-on-accent, #fff);
230
+ border-color: var(--token-accent-deep, var(--token-accent));
231
+ }
232
+ /* danger:实底 error */
233
+ .notification-action--danger {
234
+ background: var(--token-error);
235
+ color: var(--token-on-accent, #fff);
236
+ border-color: var(--token-error);
237
+ }
238
+ .notification-action--danger:hover {
239
+ filter: brightness(0.92);
240
+ color: var(--token-on-accent, #fff);
241
+ border-color: var(--token-error);
242
+ }
243
+
244
+ /* ── 详情链接 ── */
245
+ .notification-link-wrap {
246
+ margin-top: var(--density-space-xs);
247
+ }
248
+ .notification-link {
249
+ font-size: var(--density-font-size-sm);
250
+ color: var(--token-accent);
251
+ text-decoration: none;
252
+ border-bottom: 1px dashed color-mix(in srgb, var(--token-accent) 40%, transparent);
253
+ transition: color var(--icen-tx-fast), border-color var(--icen-tx-fast);
254
+ }
255
+ .notification-link:hover {
256
+ color: var(--token-accent-deep, var(--token-accent));
257
+ border-bottom-style: solid;
258
+ }
259
+ .notification-link:focus-visible {
260
+ outline: none;
261
+ border-radius: var(--radius-xs);
262
+ box-shadow: var(--icen-ring);
263
+ }
264
+
265
+ /* ── 进度条 ── */
266
+ .notification-progress {
267
+ display: flex;
268
+ align-items: center;
269
+ gap: var(--density-space-sm);
270
+ margin-top: var(--density-space-sm);
271
+ }
272
+ .notification-progress-track {
273
+ flex: 1 1 auto;
274
+ height: 4px;
275
+ background: var(--token-fill-2);
276
+ border-radius: var(--radius-full);
277
+ overflow: hidden;
278
+ }
279
+ .notification-progress-bar {
280
+ height: 100%;
281
+ background: var(--token-accent);
282
+ border-radius: var(--radius-full);
283
+ transition: width var(--icen-tx-normal) var(--ease-out);
284
+ }
285
+ .notification.notif--success .notification-progress-bar { background: var(--token-success); }
286
+ .notification.notif--warning .notification-progress-bar { background: var(--token-warning); }
287
+ .notification.notif--error .notification-progress-bar { background: var(--token-error); }
288
+ .notification-progress-label {
289
+ flex: 0 0 auto;
290
+ font-size: var(--density-font-size-xs);
291
+ color: var(--token-text-muted);
292
+ font-variant-numeric: tabular-nums;
293
+ }
294
+
295
+ /* ── 关闭按钮 ── */
296
+ .notification-close {
297
+ display: inline-flex;
298
+ align-items: center;
299
+ justify-content: center;
300
+ flex-shrink: 0;
301
+ width: 20px;
302
+ height: 20px;
303
+ padding: 0;
304
+ border: 0;
305
+ border-radius: var(--radius-xs);
306
+ background: transparent;
307
+ color: var(--token-text-faint);
308
+ cursor: pointer;
309
+ -webkit-tap-highlight-color: transparent;
310
+ transition: color var(--icen-tx-fast), background-color var(--icen-tx-fast);
311
+ }
312
+ .notification-close:hover {
313
+ color: var(--token-text);
314
+ background: var(--token-fill-1);
315
+ }
316
+ .notification-close:focus-visible {
317
+ outline: none;
318
+ box-shadow: var(--icen-ring);
319
+ }
320
+ .notification-close svg { width: 12px; height: 12px; }
321
+
322
+ /* ── 倒计时进度条(底部贴边) ── */
323
+ .notification-countdown {
324
+ position: absolute;
325
+ left: 0;
326
+ right: 0;
327
+ bottom: 0;
328
+ height: 2px;
329
+ background: transparent;
330
+ overflow: hidden;
331
+ }
332
+ .notification-countdown-fill {
333
+ height: 100%;
334
+ width: 100%;
335
+ transform-origin: left;
336
+ background: var(--token-text-faint);
337
+ opacity: 0.35;
338
+ animation-name: icen-notif-countdown;
339
+ animation-timing-function: linear;
340
+ animation-fill-mode: forwards;
341
+ animation-play-state: running;
342
+ }
343
+ .notification.notif--success .notification-countdown-fill { background: var(--token-success); opacity: 0.6; }
344
+ .notification.notif--warning .notification-countdown-fill { background: var(--token-warning); opacity: 0.6; }
345
+ .notification.notif--error .notification-countdown-fill { background: var(--token-error); opacity: 0.6; }
346
+ .notification.is-paused .notification-countdown-fill {
347
+ animation-play-state: paused;
348
+ }
349
+ @keyframes icen-notif-countdown {
350
+ from { transform: scaleX(1); }
351
+ to { transform: scaleX(0); }
352
+ }
353
+
354
+ /* ── 暂停态(hover 时) ── */
355
+ .notification.is-paused {
356
+ box-shadow: var(--token-shadow-overlay), 0 0 0 1px color-mix(in srgb, var(--token-accent) 14%, transparent);
357
+ }
358
+
359
+ /* ── 退场动画 ── */
360
+ .notification.leaving {
361
+ opacity: 0;
362
+ transform: translateX(20px);
363
+ transition:
364
+ opacity var(--icen-tx-normal),
365
+ transform var(--icen-tx-normal);
366
+ }
367
+
368
+ @keyframes icen-notif-in {
369
+ from { opacity: 0; transform: translateX(20px); }
370
+ to { opacity: 1; transform: translateX(0); }
371
+ }
372
+
373
+ @media (max-width: 480px) {
374
+ .notification-container {
375
+ width: auto;
376
+ left: var(--density-space-sm);
377
+ right: var(--density-space-sm);
378
+ }
379
+ .notification { padding: var(--density-space-sm) var(--density-space-sm) var(--density-space-sm) 10px; }
380
+ }
381
+
382
+ @media (prefers-reduced-motion: reduce) {
383
+ .notification { animation: none; }
384
+ .notification.leaving { transform: none; }
385
+ .notification-countdown-fill { animation: none; transform-origin: left; }
386
+ .notification-progress-bar { transition: none; }
387
+ }
@@ -0,0 +1,3 @@
1
+ // @icen.ai/ui — kit: notification(CSS + behavior 一行入口;构建产物,勿手改)
2
+ import './notification.css';
3
+ export * from '../behaviors/notification.mjs';
@@ -2,16 +2,29 @@
2
2
  * @icen.ai/ui — Component: panel(白卡片容器 + 标题栏 + 可选 footer)
3
3
  *
4
4
  * 完整契约:
5
- * <div class="panel-block [panel-block--flush]">
5
+ * <div class="panel-block [panel-block--flush] [panel-block--accent]
6
+ * [panel-block--collapsible] [.is-collapsed]">
6
7
  * <div class="panel-title">
7
- * <span>标题</span>
8
- * <div class="panel-title-actions"><button class="btn btn-sm">…</button></div>
8
+ * <div class="panel-title-text">
9
+ * <span>标题</span>
10
+ * <span class="panel-subtitle">副标题描述</span> ← 可选
11
+ * </div>
12
+ * <div class="panel-title-actions">
13
+ * <button class="btn btn-sm">…</button>
14
+ * <button class="panel-toggle" aria-expanded="true"> ← collapsible 模式
15
+ * <svg class="panel-toggle-icon">…chevron…</svg>
16
+ * </button>
17
+ * </div>
9
18
  * </div>
10
19
  * <div class="panel-body">…</div>
11
20
  * <div class="panel-foot">…可选底栏</div>
12
21
  * </div>
13
22
  *
14
23
  * --flush:body 不留 padding,使用方自行处理内层布局。
24
+ * --collapsible:标题栏出现展开/折叠钮(behavior 可选,也可靠纯 CSS details/summary)。
25
+ * --accent:强调色标题边。
26
+ * .panel-subtitle:标题下方的副标题/描述文字。
27
+ * .panel-block.is-collapsed:折叠态——隐藏 body + foot。
15
28
  */
16
29
 
17
30
  .panel-block {
@@ -22,6 +35,8 @@
22
35
  margin-bottom: var(--density-space-lg);
23
36
  overflow: hidden;
24
37
  }
38
+
39
+ /* ── 标题栏 ── */
25
40
  .panel-title {
26
41
  display: flex;
27
42
  align-items: center;
@@ -35,9 +50,24 @@
35
50
  text-transform: uppercase;
36
51
  font-weight: 600;
37
52
  }
38
- .panel-title > span:first-child {
53
+ .panel-title-text {
39
54
  flex: 1;
40
55
  min-width: 0;
56
+ display: flex;
57
+ flex-direction: column;
58
+ gap: 1px;
59
+ }
60
+ .panel-title-text > span:first-child {
61
+ overflow: hidden;
62
+ text-overflow: ellipsis;
63
+ white-space: nowrap;
64
+ }
65
+ .panel-subtitle {
66
+ font-size: 11px;
67
+ font-weight: 400;
68
+ letter-spacing: 0;
69
+ text-transform: none;
70
+ color: var(--token-text-faint);
41
71
  overflow: hidden;
42
72
  text-overflow: ellipsis;
43
73
  white-space: nowrap;
@@ -49,6 +79,55 @@
49
79
  flex-shrink: 0;
50
80
  }
51
81
 
82
+ /* ── 可折叠钮 ── */
83
+ .panel-toggle {
84
+ display: inline-flex;
85
+ align-items: center;
86
+ justify-content: center;
87
+ width: 24px;
88
+ height: 24px;
89
+ padding: 0;
90
+ border: none;
91
+ background: transparent;
92
+ color: var(--token-text-faint);
93
+ cursor: pointer;
94
+ border-radius: var(--radius-xs);
95
+ transition: color var(--icen-tx-fast), background-color var(--icen-tx-fast);
96
+ }
97
+ .panel-toggle:hover {
98
+ color: var(--token-text);
99
+ background: var(--token-fill-1);
100
+ }
101
+ .panel-toggle:focus-visible {
102
+ outline: none;
103
+ box-shadow: var(--icen-ring);
104
+ }
105
+ .panel-toggle-icon {
106
+ width: 14px;
107
+ height: 14px;
108
+ transition: transform var(--icen-tx-fast);
109
+ }
110
+ .panel-block.is-collapsed .panel-toggle-icon {
111
+ transform: rotate(-90deg);
112
+ }
113
+
114
+ /* ── 折叠态:隐藏 body + foot,去掉标题栏底边 ── */
115
+ .panel-block.is-collapsed .panel-body,
116
+ .panel-block.is-collapsed .panel-foot {
117
+ display: none;
118
+ }
119
+ .panel-block.is-collapsed .panel-title {
120
+ border-bottom-color: transparent;
121
+ }
122
+ .panel-block--collapsible .panel-body {
123
+ animation: panel-expand var(--icen-tx-normal) var(--ease-out);
124
+ }
125
+ @keyframes panel-expand {
126
+ from { opacity: 0; transform: translateY(-8px); }
127
+ to { opacity: 1; transform: translateY(0); }
128
+ }
129
+
130
+ /* ── body / foot ── */
52
131
  .panel-body {
53
132
  padding: var(--density-space-md);
54
133
  font-size: var(--density-font-size-md);
@@ -66,9 +145,25 @@
66
145
  background: color-mix(in srgb, var(--token-bg-soft) 50%, transparent);
67
146
  }
68
147
 
69
- /* 强调变体:accent 色标题边(用于警告/告警面板) */
148
+ /* ── 强调变体 ── */
70
149
  .panel-block--accent { border-color: color-mix(in srgb, var(--token-accent) 30%, transparent); }
71
150
  .panel-block--accent .panel-title {
72
151
  color: var(--token-accent);
73
152
  background: var(--token-accent-subtle);
74
153
  }
154
+
155
+ /* ── 平面变体(无阴影,嵌套时用) ── */
156
+ .panel-block--flat {
157
+ box-shadow: none;
158
+ background: var(--token-bg-soft);
159
+ }
160
+
161
+ /* ── 可折叠模式:标题栏可点(纯 CSS 方案用 details/summary) ── */
162
+ .panel-block--collapsible .panel-title {
163
+ cursor: pointer;
164
+ }
165
+
166
+ @media (prefers-reduced-motion: reduce) {
167
+ .panel-toggle-icon { transition: none; }
168
+ .panel-block--collapsible .panel-body { animation: none; }
169
+ }
@@ -86,3 +86,73 @@
86
86
  .pill--solid.warn { background: var(--token-warning); border-color: var(--token-warning); color: var(--token-on-accent, #fff); }
87
87
  .pill--solid.bad { background: var(--token-error); border-color: var(--token-error); color: var(--token-on-accent, #fff); }
88
88
  .pill--solid.info { background: var(--token-info); border-color: var(--token-info); color: var(--token-on-accent, #fff); }
89
+
90
+ /* ── 增强 ── */
91
+
92
+ /* 可关闭 pill */
93
+ .pill-close {
94
+ display: inline-flex;
95
+ align-items: center;
96
+ justify-content: center;
97
+ width: 14px;
98
+ height: 14px;
99
+ margin-left: 2px;
100
+ margin-right: -4px;
101
+ padding: 0;
102
+ border: 0;
103
+ border-radius: var(--radius-full);
104
+ background: transparent;
105
+ color: inherit;
106
+ opacity: 0.6;
107
+ cursor: pointer;
108
+ transition: opacity var(--icen-tx-fast), background-color var(--icen-tx-fast);
109
+ }
110
+ .pill-close:hover { opacity: 1; background: color-mix(in srgb, currentColor 15%, transparent); }
111
+ .pill-close svg { width: 9px; height: 9px; }
112
+
113
+ /* 图标 pill */
114
+ .pill-icon {
115
+ display: inline-flex;
116
+ align-items: center;
117
+ }
118
+ .pill-icon svg { width: 10px; height: 10px; }
119
+
120
+ /* 实时脉冲(用于"直播"/"实时"状态) */
121
+ .pill--live::before {
122
+ content: '';
123
+ display: inline-block;
124
+ width: 6px;
125
+ height: 6px;
126
+ border-radius: var(--radius-full);
127
+ background: currentColor;
128
+ margin-right: 2px;
129
+ animation: pill-pulse 1.5s ease-in-out infinite;
130
+ }
131
+ @keyframes pill-pulse {
132
+ 0%, 100% { opacity: 1; transform: scale(1); }
133
+ 50% { opacity: 0.4; transform: scale(0.7); }
134
+ }
135
+
136
+ /* 纯数字计数(不带文字) */
137
+ .pill--count {
138
+ min-width: 18px;
139
+ height: 18px;
140
+ padding: 0 5px;
141
+ justify-content: center;
142
+ font-size: 10px;
143
+ font-weight: 700;
144
+ font-variant-numeric: tabular-nums;
145
+ line-height: 1;
146
+ }
147
+
148
+ /* 渐变变体 */
149
+ .pill--gradient {
150
+ background: linear-gradient(135deg, var(--token-accent), var(--token-accent-deep, var(--token-accent)));
151
+ color: var(--token-on-accent, #fff);
152
+ border-color: transparent;
153
+ }
154
+
155
+ @media (prefers-reduced-motion: reduce) {
156
+ .pill--live::before { animation: none; }
157
+ .pill-close { transition: none; }
158
+ }