@icen.ai/ui 0.5.0 → 0.8.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 (138) hide show
  1. package/AGENTS.md +256 -0
  2. package/README.md +47 -13
  3. package/dist/base.css +31 -4
  4. package/dist/behaviors/accordion.d.mts +4 -0
  5. package/dist/behaviors/accordion.mjs +4 -3
  6. package/dist/behaviors/ai-chat.d.mts +57 -0
  7. package/dist/behaviors/ai-chat.mjs +557 -0
  8. package/dist/behaviors/ai-composer.d.mts +112 -0
  9. package/dist/behaviors/ai-composer.mjs +2032 -0
  10. package/dist/behaviors/ai-core.d.mts +151 -0
  11. package/dist/behaviors/ai-core.mjs +491 -0
  12. package/dist/behaviors/ai-diff.d.mts +53 -0
  13. package/dist/behaviors/ai-diff.mjs +282 -0
  14. package/dist/behaviors/ai-panel.d.mts +98 -0
  15. package/dist/behaviors/ai-panel.mjs +1012 -0
  16. package/dist/behaviors/ai-provider.d.mts +198 -0
  17. package/dist/behaviors/ai-provider.mjs +1055 -0
  18. package/dist/behaviors/ai-tool.d.mts +18 -0
  19. package/dist/behaviors/ai-tool.mjs +2125 -0
  20. package/dist/behaviors/ai-tools.d.mts +81 -0
  21. package/dist/behaviors/ai-tools.mjs +1658 -0
  22. package/dist/behaviors/back-top.d.mts +20 -0
  23. package/dist/behaviors/back-top.mjs +49 -32
  24. package/dist/behaviors/carousel.d.mts +4 -0
  25. package/dist/behaviors/carousel.mjs +34 -16
  26. package/dist/behaviors/charts.d.mts +250 -0
  27. package/dist/behaviors/charts.mjs +1301 -448
  28. package/dist/behaviors/command-palette.d.mts +8 -0
  29. package/dist/behaviors/command-palette.mjs +24 -12
  30. package/dist/behaviors/context-menu.d.mts +36 -0
  31. package/dist/behaviors/context-menu.mjs +6 -2
  32. package/dist/behaviors/copy.d.mts +4 -0
  33. package/dist/behaviors/copy.mjs +7 -6
  34. package/dist/behaviors/datatable.d.mts +78 -0
  35. package/dist/behaviors/datatable.mjs +54 -11
  36. package/dist/behaviors/date-picker.d.mts +4 -0
  37. package/dist/behaviors/date-picker.mjs +104 -36
  38. package/dist/behaviors/dropdown.d.mts +4 -0
  39. package/dist/behaviors/dropdown.mjs +7 -3
  40. package/dist/behaviors/input.d.mts +4 -0
  41. package/dist/behaviors/input.mjs +29 -22
  42. package/dist/behaviors/modal.d.mts +11 -0
  43. package/dist/behaviors/modal.mjs +11 -6
  44. package/dist/behaviors/nav.d.mts +7 -0
  45. package/dist/behaviors/nav.mjs +25 -9
  46. package/dist/behaviors/notification.d.mts +172 -0
  47. package/dist/behaviors/notification.mjs +243 -89
  48. package/dist/behaviors/popover.d.mts +46 -0
  49. package/dist/behaviors/popover.mjs +2 -1
  50. package/dist/behaviors/select.d.mts +4 -0
  51. package/dist/behaviors/select.mjs +131 -26
  52. package/dist/behaviors/sidebar.d.mts +4 -0
  53. package/dist/behaviors/sidebar.mjs +4 -3
  54. package/dist/behaviors/slider.d.mts +4 -0
  55. package/dist/behaviors/slider.mjs +4 -3
  56. package/dist/behaviors/split-pane.d.mts +4 -0
  57. package/dist/behaviors/split-pane.mjs +13 -13
  58. package/dist/behaviors/tabs.d.mts +8 -0
  59. package/dist/behaviors/tabs.mjs +44 -19
  60. package/dist/behaviors/tag-input.d.mts +4 -0
  61. package/dist/behaviors/tag-input.mjs +12 -3
  62. package/dist/behaviors/theme.d.mts +25 -0
  63. package/dist/behaviors/theme.mjs +3 -1
  64. package/dist/behaviors/toast.d.mts +26 -0
  65. package/dist/behaviors/toast.mjs +24 -18
  66. package/dist/behaviors/tree.d.mts +4 -0
  67. package/dist/behaviors/tree.mjs +4 -3
  68. package/dist/behaviors/upload.d.mts +4 -0
  69. package/dist/behaviors/upload.mjs +63 -26
  70. package/dist/components/ai-chat.css +1037 -0
  71. package/dist/components/ai-chat.mjs +3 -0
  72. package/dist/components/ai-composer.mjs +3 -0
  73. package/dist/components/ai-context.mjs +2 -0
  74. package/dist/components/ai-diff.css +311 -0
  75. package/dist/components/ai-diff.mjs +3 -0
  76. package/dist/components/ai-files.mjs +3 -0
  77. package/dist/components/ai-message.mjs +3 -0
  78. package/dist/components/ai-panel.css +682 -0
  79. package/dist/components/ai-reasoning.mjs +3 -0
  80. package/dist/components/ai-subagent.mjs +2 -0
  81. package/dist/components/ai-todo.mjs +2 -0
  82. package/dist/components/ai-tool-call.mjs +2 -0
  83. package/dist/components/ai-tool.css +532 -0
  84. package/dist/components/ai-usage.mjs +3 -0
  85. package/dist/components/badge.css +4 -8
  86. package/dist/components/breadcrumb.css +1 -5
  87. package/dist/components/btn.css +4 -7
  88. package/dist/components/card.css +3 -6
  89. package/dist/components/chart-bar.css +10 -0
  90. package/dist/components/chart-calendar.mjs +5 -0
  91. package/dist/components/chart-gauge.css +1 -1
  92. package/dist/components/chart-heatmap.css +40 -0
  93. package/dist/components/chart-scatter.css +24 -0
  94. package/dist/components/chart-scatter.mjs +4 -0
  95. package/dist/components/charts.css +86 -1
  96. package/dist/components/charts.mjs +1 -0
  97. package/dist/components/command-palette.css +2 -2
  98. package/dist/components/content.css +8 -9
  99. package/dist/components/copy.css +8 -8
  100. package/dist/components/datatable.css +4 -8
  101. package/dist/components/date-picker.css +3 -7
  102. package/dist/components/empty.css +0 -4
  103. package/dist/components/feedback.css +10 -17
  104. package/dist/components/form.css +13 -14
  105. package/dist/components/input.css +2 -2
  106. package/dist/components/layout.css +36 -36
  107. package/dist/components/media.css +12 -8
  108. package/dist/components/menu.css +2 -2
  109. package/dist/components/modal.css +1 -1
  110. package/dist/components/nav.css +11 -6
  111. package/dist/components/notification.css +28 -28
  112. package/dist/components/pagination.css +1 -1
  113. package/dist/components/panel.css +16 -16
  114. package/dist/components/pill.css +15 -15
  115. package/dist/components/segmented.css +5 -5
  116. package/dist/components/segmented.mjs +1 -0
  117. package/dist/components/select.css +12 -20
  118. package/dist/components/sidebar.css +1 -1
  119. package/dist/components/split-pane.css +0 -1
  120. package/dist/components/stat.css +14 -18
  121. package/dist/components/steps.css +2 -2
  122. package/dist/components/switch.css +8 -12
  123. package/dist/components/table.css +46 -47
  124. package/dist/components/tabs.css +35 -46
  125. package/dist/components/tag-input.css +4 -4
  126. package/dist/components/toast.css +16 -13
  127. package/dist/components/tooltip.css +2 -2
  128. package/dist/index.d.mts +37 -0
  129. package/dist/index.mjs +7890 -1199
  130. package/dist/registry.json +113 -4
  131. package/dist/retro-effects.css +21 -17
  132. package/dist/tokens/colors.css +4 -1
  133. package/dist/tokens/retro-effects.css +21 -17
  134. package/dist/tokens/style-profiles.css +21 -0
  135. package/dist/tokens.css +25 -1
  136. package/dist/ui.css +3168 -433
  137. package/docs/spec/ai-native.md +659 -0
  138. package/package.json +15 -5
@@ -0,0 +1,682 @@
1
+ /*
2
+ * @icen.ai/ui — Component: ai-panel(AI 任务面板族:todo / context / usage,与 behaviors/ai-panel.ts 配套)
3
+ *
4
+ * 完整 DOM 契约(类名与规格 §4.8/§4.9/§4.10 一致):
5
+ * <div class="ai-todo" [.is-complete] [data-ai-todo-interactive]>
6
+ * <div class="ai-todo-head">
7
+ * <span class="ai-todo-progress">2/5</span>
8
+ * <div class="ai-todo-bar" role="progressbar" …><i style="width:40%"></i></div>
9
+ * </div>
10
+ * <div class="ai-todo-item is-pending|running|streaming|approval|done|error|cancelled
11
+ * [role="button" tabindex="0"]" data-index="0">
12
+ * <span class="ai-item-status"></span> <!-- 状态点,纯 CSS 由 .is-* 驱动 -->
13
+ * <span class="ai-todo-text">实现登录页</span>
14
+ * <span class="ai-todo-active">正在实现登录页…</span> <!-- is-running 时替换 text(CSS 驱动) -->
15
+ * </div>
16
+ * </div>
17
+ *
18
+ * <div class="ai-usage">
19
+ * <div class="ai-usage-bar" role="img" aria-label="…">
20
+ * <i class="ai-usage-seg ai-usage-seg--input|output|cache-read|cache-write|reasoning" style="width:35%"></i>…
21
+ * </div>
22
+ * <div class="ai-usage-legend">
23
+ * <span class="ai-usage-legend-item">
24
+ * <i class="ai-usage-dot ai-usage-seg--input"></i>
25
+ * <span class="ai-usage-legend-label">输入</span> <span class="ai-usage-legend-value">35k</span>
26
+ * </span>…
27
+ * </div>
28
+ * <div class="ai-usage-total">82k / 200k · 41%</div>
29
+ * </div>
30
+ *
31
+ * <aside class="ai-context [.ai-context--inline]" hidden role="dialog" aria-label="上下文">
32
+ * <div class="ai-context-head"><span>上下文</span>
33
+ * <button type="button" data-ai-context-close aria-label="关闭">×</button></div>
34
+ * <section class="ai-context-section"><h3>…</h3>
35
+ * <div class="ai-context-section-body">…renderAiContext 产物…</div> <!-- 可选包裹,亦可直接放内容 -->
36
+ * </section>…
37
+ * </aside>
38
+ *
39
+ * .ai-item 行(MCP / Skills,规格 §2 基元):
40
+ * <div class="ai-item is-done|is-error" style="--ai-item-tint: var(--token-accent)">
41
+ * <span class="ai-item-icon">…svg…</span>
42
+ * <span class="ai-item-main">
43
+ * <span class="ai-item-title">github</span><span class="ai-item-sub">…</span>
44
+ * </span>
45
+ * <span class="ai-item-side"><span class="ai-item-status"></span><span class="ai-item-meta">12 工具</span></span>
46
+ * </div>
47
+ *
48
+ * 依赖说明:
49
+ * - .ai-item 完整版在 ai-tool.css(S2)。此处按任务约定重新声明最小骨架(含 --ai-item-tint
50
+ * 局部变量与状态点),保证 ai-panel.css 单独引入时 todo/context 可用;两边类名/语义一致,
51
+ * 同页面共存时后加载者覆盖同款属性,视觉不冲突。
52
+ * - keyframes ai-status-pulse 为组件局部定义(等同 pill.css 的 pill-pulse),
53
+ * 时长走 var(--pill-pulse-duration, 1.5s):pill.css 在场时与其同步,否则自洽。
54
+ * - blink keyframes 来自 tokens/colors.css(.animate-blink 同款,共享复用)。
55
+ * - base.css:--z-chrome / --icen-tx-* / --icen-ring。只消费 --token-* / --density-* / --radius-*。
56
+ */
57
+
58
+ /* ══════════════ .ai-item 最小基元(自包含,兼容 ai-tool.css 完整版) ══════════════ */
59
+
60
+ .ai-item {
61
+ --ai-item-tint: var(--token-accent);
62
+ display: flex;
63
+ align-items: center;
64
+ gap: var(--density-space-sm);
65
+ padding: var(--density-space-xs) var(--density-space-sm);
66
+ border-radius: var(--radius-sm);
67
+ font-size: var(--density-font-size-sm);
68
+ min-width: 0;
69
+ align-self: stretch; /* 宽度自稳定:宿主 flex/grid 居中时不 shrink-wrap */
70
+ }
71
+
72
+ .ai-item-icon {
73
+ flex-shrink: 0;
74
+ display: inline-flex;
75
+ color: var(--ai-item-tint);
76
+ }
77
+ .ai-item-icon svg {
78
+ width: 15px;
79
+ height: 15px;
80
+ }
81
+
82
+ .ai-item-main {
83
+ flex: 1;
84
+ min-width: 0;
85
+ display: flex;
86
+ flex-direction: column;
87
+ gap: 1px;
88
+ }
89
+ .ai-item-title {
90
+ color: var(--token-text);
91
+ line-height: 1.4;
92
+ overflow: hidden;
93
+ text-overflow: ellipsis;
94
+ white-space: nowrap;
95
+ }
96
+ .ai-item-sub {
97
+ font-size: var(--density-font-size-xs);
98
+ color: var(--token-text-muted);
99
+ overflow: hidden;
100
+ text-overflow: ellipsis;
101
+ white-space: nowrap;
102
+ }
103
+
104
+ .ai-item-side {
105
+ flex-shrink: 0;
106
+ display: inline-flex;
107
+ align-items: center;
108
+ gap: var(--density-space-xs);
109
+ }
110
+ .ai-item-meta {
111
+ font-size: var(--density-font-size-xs);
112
+ color: var(--token-text-faint);
113
+ font-variant-numeric: tabular-nums;
114
+ }
115
+
116
+ /* ── 状态点 .ai-item-status:纯 CSS 圆点,由 .is-* 驱动(ai-item 与 ai-todo-item 共用) ── */
117
+
118
+ .ai-item-status {
119
+ flex-shrink: 0;
120
+ width: 8px;
121
+ height: 8px;
122
+ border-radius: var(--radius-full);
123
+ border: 1.5px solid var(--token-text-faint);
124
+ background: transparent;
125
+ }
126
+
127
+ /* pending:faint 空心点(默认态即空心) */
128
+ .ai-item.is-pending > .ai-item-status,
129
+ .ai-todo-item.is-pending > .ai-item-status { }
130
+
131
+ /* running / streaming:accent 脉冲点 */
132
+ .ai-item.is-running > .ai-item-status,
133
+ .ai-todo-item.is-running > .ai-item-status,
134
+ .ai-item.is-streaming > .ai-item-status,
135
+ .ai-todo-item.is-streaming > .ai-item-status {
136
+ border-color: var(--token-accent);
137
+ background: var(--token-accent);
138
+ animation: ai-status-pulse var(--pill-pulse-duration, 1.5s) ease-in-out infinite;
139
+ }
140
+
141
+ /* approval:warning 点 */
142
+ .ai-item.is-approval > .ai-item-status,
143
+ .ai-todo-item.is-approval > .ai-item-status {
144
+ border-color: var(--token-warning);
145
+ background: var(--token-warning);
146
+ }
147
+
148
+ /* done:success 点 */
149
+ .ai-item.is-done > .ai-item-status,
150
+ .ai-todo-item.is-done > .ai-item-status {
151
+ border-color: var(--token-success);
152
+ background: var(--token-success);
153
+ }
154
+
155
+ /* error:error 点 */
156
+ .ai-item.is-error > .ai-item-status,
157
+ .ai-todo-item.is-error > .ai-item-status {
158
+ border-color: var(--token-error);
159
+ background: var(--token-error);
160
+ }
161
+
162
+ /* cancelled:faint 实心点 + 标题删除线(规格 §1) */
163
+ .ai-item.is-cancelled > .ai-item-status,
164
+ .ai-todo-item.is-cancelled > .ai-item-status {
165
+ border-color: var(--token-text-faint);
166
+ background: var(--token-text-faint);
167
+ }
168
+ .ai-item.is-cancelled .ai-item-title,
169
+ .ai-todo-item.is-cancelled .ai-todo-text {
170
+ text-decoration: line-through;
171
+ }
172
+
173
+ /* 组件局部 keyframes(等同 pill-pulse,避免硬依赖 pill.css) */
174
+ @keyframes ai-status-pulse {
175
+ 0%, 100% { opacity: 1; transform: scale(1); }
176
+ 50% { opacity: 0.4; transform: scale(0.7); }
177
+ }
178
+
179
+ /* ══════════════ ai-todo · 任务清单(§4.8) ══════════════ */
180
+
181
+ .ai-todo {
182
+ display: flex;
183
+ flex-direction: column;
184
+ gap: var(--density-space-xs);
185
+ font-size: var(--density-font-size-sm);
186
+ min-width: 0;
187
+ align-self: stretch; /* 输出容器宽度自稳定 */
188
+ }
189
+
190
+ .ai-todo-head {
191
+ display: flex;
192
+ align-items: center;
193
+ gap: var(--density-space-sm);
194
+ min-width: 0;
195
+ }
196
+
197
+ .ai-todo-progress {
198
+ flex-shrink: 0;
199
+ font-size: var(--density-font-size-xs);
200
+ color: var(--token-text-muted);
201
+ font-variant-numeric: tabular-nums;
202
+ }
203
+
204
+ /* 进度条:feedback progress 视觉(token 消费) */
205
+ .ai-todo-bar {
206
+ flex: 1;
207
+ height: 4px;
208
+ border-radius: var(--radius-full);
209
+ overflow: hidden;
210
+ background: color-mix(in srgb, var(--token-line-soft) 40%, transparent);
211
+ }
212
+ .ai-todo-bar > i {
213
+ display: block;
214
+ height: 100%;
215
+ border-radius: var(--radius-full);
216
+ background: var(--token-accent);
217
+ transition: width var(--icen-tx-slow);
218
+ }
219
+ .ai-todo.is-complete .ai-todo-bar > i {
220
+ background: var(--token-success);
221
+ }
222
+
223
+ .ai-todo-item {
224
+ display: flex;
225
+ align-items: center;
226
+ gap: var(--density-space-sm);
227
+ padding: 3px var(--density-space-xs);
228
+ border-radius: var(--radius-xs);
229
+ min-width: 0;
230
+ }
231
+
232
+ /* 交互模式(initAiTodo 升级 role=button) */
233
+ .ai-todo-item[role='button'] {
234
+ cursor: pointer;
235
+ transition: background-color var(--icen-tx-fast);
236
+ }
237
+ .ai-todo-item[role='button']:hover {
238
+ background: var(--token-fill-1);
239
+ }
240
+ .ai-todo-item:focus-visible {
241
+ outline: none;
242
+ box-shadow: var(--icen-ring);
243
+ }
244
+
245
+ .ai-todo-text {
246
+ min-width: 0;
247
+ overflow: hidden;
248
+ text-overflow: ellipsis;
249
+ white-space: nowrap;
250
+ }
251
+
252
+ /* activeForm:运行中替换式强调(Claude Code 模式) */
253
+ .ai-todo-active {
254
+ display: none;
255
+ min-width: 0;
256
+ overflow: hidden;
257
+ text-overflow: ellipsis;
258
+ white-space: nowrap;
259
+ color: var(--token-accent-deep);
260
+ }
261
+ .ai-todo-item.is-running .ai-todo-text { display: none; }
262
+ .ai-todo-item.is-running .ai-todo-active { display: inline; }
263
+
264
+ /* done/cancelled:淡化 + 删除线 */
265
+ .ai-todo-item.is-done .ai-todo-text,
266
+ .ai-todo-item.is-cancelled .ai-todo-text {
267
+ color: var(--token-text-faint);
268
+ text-decoration: line-through;
269
+ }
270
+
271
+ /* ══════════════ ai-usage · 用量条(§4.9) ══════════════ */
272
+
273
+ .ai-usage {
274
+ display: flex;
275
+ flex-direction: column;
276
+ gap: var(--density-space-xs);
277
+ font-size: var(--density-font-size-xs);
278
+ color: var(--token-text-muted);
279
+ min-width: 0;
280
+ align-self: stretch; /* 输出容器宽度自稳定 */
281
+ }
282
+
283
+ .ai-usage-bar {
284
+ display: flex;
285
+ height: 6px;
286
+ border-radius: var(--radius-full);
287
+ overflow: hidden;
288
+ background: color-mix(in srgb, var(--token-line-soft) 40%, transparent);
289
+ }
290
+
291
+ .ai-usage-seg {
292
+ display: block;
293
+ height: 100%;
294
+ min-width: 0;
295
+ transition: width var(--icen-tx-slow);
296
+ }
297
+
298
+ /* 配色契约:input=accent / output=success / cacheRead=info / cacheWrite=warning / reasoning=faint */
299
+ .ai-usage-seg--input { background: var(--token-accent); }
300
+ .ai-usage-seg--output { background: var(--token-success); }
301
+ .ai-usage-seg--cache-read { background: var(--token-info); }
302
+ .ai-usage-seg--cache-write { background: var(--token-warning); }
303
+ .ai-usage-seg--reasoning { background: var(--token-text-faint); }
304
+
305
+ /* 图例:色点 + 标签 + 数值(缓存分列,计费诚实) */
306
+ .ai-usage-legend {
307
+ display: flex;
308
+ flex-wrap: wrap;
309
+ gap: var(--density-space-xs) var(--density-space-sm);
310
+ }
311
+ .ai-usage-legend-item {
312
+ display: inline-flex;
313
+ align-items: center;
314
+ gap: 5px;
315
+ font-variant-numeric: tabular-nums;
316
+ }
317
+ .ai-usage-dot {
318
+ flex-shrink: 0;
319
+ width: 8px;
320
+ height: 8px;
321
+ border-radius: var(--radius-full);
322
+ }
323
+ .ai-usage-legend-label { color: var(--token-text-muted); }
324
+ .ai-usage-legend-value { color: var(--token-text); font-weight: 500; }
325
+
326
+ .ai-usage-total {
327
+ font-variant-numeric: tabular-nums;
328
+ color: var(--token-text-muted);
329
+ }
330
+
331
+ /* ══════════════ ai-usage-ring · 上下文窗口环形指示器(点击弹出完整分解) ══════════════ */
332
+
333
+ .ai-usage-ring {
334
+ position: relative;
335
+ display: inline-flex;
336
+ align-items: center;
337
+ justify-content: center;
338
+ width: 36px;
339
+ height: 36px;
340
+ padding: 0;
341
+ border: 0;
342
+ background: transparent;
343
+ border-radius: var(--radius-full);
344
+ color: var(--token-text-muted);
345
+ cursor: pointer;
346
+ flex-shrink: 0;
347
+ transition:
348
+ color var(--icen-tx-fast),
349
+ background-color var(--icen-tx-fast);
350
+ }
351
+ .ai-usage-ring:hover {
352
+ background: var(--token-fill-1);
353
+ color: var(--token-text);
354
+ }
355
+ .ai-usage-ring:focus-visible {
356
+ outline: none;
357
+ box-shadow: var(--icen-ring);
358
+ }
359
+
360
+ .ai-usage-ring > svg {
361
+ position: absolute;
362
+ inset: 0;
363
+ width: 100%;
364
+ height: 100%;
365
+ transform: rotate(-90deg); /* 12 点起笔 */
366
+ }
367
+ .ai-usage-ring-track {
368
+ fill: none;
369
+ stroke: var(--token-fill-2);
370
+ stroke-width: 3;
371
+ }
372
+ .ai-usage-ring-fill {
373
+ fill: none;
374
+ stroke: var(--token-accent);
375
+ stroke-width: 3;
376
+ stroke-linecap: round;
377
+ transition:
378
+ stroke-dasharray var(--icen-tx-slow),
379
+ stroke var(--icen-tx-fast);
380
+ }
381
+ /* 状态档:<60% ok(accent)/ 60–85% warn / >85% hot */
382
+ .ai-usage-ring.is-warn .ai-usage-ring-fill { stroke: var(--token-warning); }
383
+ .ai-usage-ring.is-hot .ai-usage-ring-fill { stroke: var(--token-error); }
384
+ .ai-usage-ring.is-hot {
385
+ animation: ai-usage-ring-pulse var(--ai-usage-ring-pulse-duration, 1.6s) ease-in-out infinite;
386
+ }
387
+ @keyframes ai-usage-ring-pulse {
388
+ 0%, 100% { opacity: 1; }
389
+ 50% { opacity: 0.55; }
390
+ }
391
+
392
+ .ai-usage-ring-pct {
393
+ position: relative;
394
+ font-family: var(--font-mono);
395
+ font-size: 9px;
396
+ font-weight: 600;
397
+ letter-spacing: -0.02em;
398
+ font-variant-numeric: tabular-nums;
399
+ user-select: none;
400
+ }
401
+
402
+ /* 大号变体(常驻工具栏/头部用) */
403
+ .ai-usage-ring--lg {
404
+ width: 44px;
405
+ height: 44px;
406
+ }
407
+ .ai-usage-ring--lg .ai-usage-ring-pct { font-size: 10px; }
408
+
409
+ /* 弹层(复用 .popover 基座,内容区只补间距) */
410
+ .ai-usage-popover {
411
+ display: flex;
412
+ flex-direction: column;
413
+ gap: var(--density-space-sm);
414
+ padding: var(--density-space-md);
415
+ }
416
+ .ai-usage-popover-title {
417
+ font-size: var(--density-font-size-sm);
418
+ font-weight: 600;
419
+ color: var(--token-text);
420
+ }
421
+
422
+ @media (prefers-reduced-motion: reduce) {
423
+ .ai-usage-ring.is-hot { animation: none; }
424
+ .ai-usage-ring-fill { transition: none; }
425
+ }
426
+
427
+ /* ══════════════ ai-context · 上下文抽屉(§4.10) ══════════════ */
428
+
429
+ .ai-context {
430
+ position: fixed;
431
+ inset: 0 0 0 auto;
432
+ width: min(360px, 92vw);
433
+ z-index: var(--z-chrome);
434
+ display: flex;
435
+ flex-direction: column;
436
+ background: var(--token-surface);
437
+ border-left: 1px solid var(--token-line-soft);
438
+ box-shadow: var(--token-shadow-overlay);
439
+ transform: translateX(100%);
440
+ transition: transform var(--ai-context-duration, var(--duration-normal)) var(--ease-out);
441
+ overflow-y: auto;
442
+ }
443
+ .ai-context[hidden] {
444
+ display: none;
445
+ }
446
+ .ai-context.is-open {
447
+ transform: translateX(0);
448
+ }
449
+
450
+ /* 页面流内嵌变体:不做 fixed、不滑入 */
451
+ .ai-context--inline {
452
+ position: static;
453
+ inset: auto;
454
+ width: auto;
455
+ z-index: auto;
456
+ transform: none;
457
+ transition: none;
458
+ border: 1px solid var(--token-line-soft);
459
+ border-radius: var(--radius-md);
460
+ box-shadow: var(--token-shadow-elevated);
461
+ overflow-y: visible;
462
+ }
463
+
464
+ .ai-context-head {
465
+ position: sticky;
466
+ top: 0;
467
+ z-index: 1;
468
+ display: flex;
469
+ align-items: center;
470
+ justify-content: space-between;
471
+ gap: var(--density-space-sm);
472
+ padding: var(--density-space-sm) var(--density-space-md);
473
+ background: var(--token-surface);
474
+ border-bottom: 1px solid var(--token-line-soft);
475
+ font-size: var(--density-font-size-sm);
476
+ font-weight: 600;
477
+ color: var(--token-text);
478
+ }
479
+
480
+ .ai-context-head [data-ai-context-close] {
481
+ flex-shrink: 0;
482
+ display: inline-flex;
483
+ align-items: center;
484
+ justify-content: center;
485
+ width: 26px;
486
+ height: 26px;
487
+ padding: 0;
488
+ border: 0;
489
+ border-radius: var(--radius-xs);
490
+ background: none;
491
+ color: var(--token-text-faint);
492
+ font-size: 16px;
493
+ line-height: 1;
494
+ cursor: pointer;
495
+ transition:
496
+ background-color var(--icen-tx-fast),
497
+ color var(--icen-tx-fast);
498
+ }
499
+ .ai-context-head [data-ai-context-close]:hover {
500
+ color: var(--token-text);
501
+ background: var(--token-fill-1);
502
+ }
503
+ .ai-context-head [data-ai-context-close]:focus-visible {
504
+ outline: none;
505
+ box-shadow: var(--icen-ring);
506
+ }
507
+
508
+ .ai-context-section {
509
+ display: flex;
510
+ flex-direction: column;
511
+ gap: var(--density-space-xs);
512
+ padding: var(--density-space-sm) var(--density-space-md);
513
+ min-width: 0;
514
+ }
515
+ .ai-context-section ~ .ai-context-section {
516
+ border-top: 1px solid var(--token-line-soft);
517
+ }
518
+ .ai-context-section h3 {
519
+ margin: 0;
520
+ font-size: var(--density-font-size-xs);
521
+ font-weight: 600;
522
+ color: var(--token-text-muted);
523
+ }
524
+ .ai-context-section-body {
525
+ display: flex;
526
+ flex-direction: column;
527
+ gap: var(--density-space-xs);
528
+ min-width: 0;
529
+ }
530
+
531
+ /* ══════════════ ai-audit(renderAiAudit,规格 §12.2) ══════════════ */
532
+
533
+ /*
534
+ * <div class="ai-audit">
535
+ * <div class="ai-audit-totals"><span class="ai-audit-totals-text">12 次请求 · 1 失败 · 1.2M tok · $0.42 · TTFT 240ms</span></div>
536
+ * <div class="ai-audit-models">
537
+ * <div class="ai-audit-model-row"><span class="ai-audit-model-name">kimi/kimi-k3</span>
538
+ * <span class="ai-audit-model-meta">8 次 · 900k tok · $0.31</span></div>…
539
+ * </div>
540
+ * <div class="ai-audit-list">
541
+ * <div class="ai-audit-item is-done|is-error">
542
+ * <span class="ai-audit-dot"></span>
543
+ * <span class="ai-audit-item-main"><span class="ai-audit-item-model">kimi · kimi-k3</span>
544
+ * <span class="ai-audit-item-meta">14:03 · 1.2s · TTFT 240ms · 12.3k tok</span></span>
545
+ * <span class="ai-audit-item-error">网络请求失败:…</span> <!-- 仅 is-error -->
546
+ * </div>…
547
+ * </div>
548
+ * <button class="btn btn-sm ai-audit-clear">清除审计</button>
549
+ * </div>
550
+ */
551
+
552
+ .ai-audit {
553
+ display: flex;
554
+ flex-direction: column;
555
+ gap: var(--density-space-sm);
556
+ align-self: stretch;
557
+ min-width: 0;
558
+ font-size: var(--density-font-size-sm);
559
+ }
560
+ .ai-audit-empty {
561
+ padding: var(--density-space-md);
562
+ text-align: center;
563
+ color: var(--token-text-faint);
564
+ font-size: var(--density-font-size-xs);
565
+ }
566
+
567
+ /* totals 行:等宽数字,faint 汇总 */
568
+ .ai-audit-totals-text {
569
+ display: block;
570
+ font-family: var(--font-mono);
571
+ font-size: var(--density-font-size-xs);
572
+ color: var(--token-text-faint);
573
+ font-variant-numeric: tabular-nums;
574
+ }
575
+
576
+ /* byModel 分组行 */
577
+ .ai-audit-models {
578
+ display: flex;
579
+ flex-direction: column;
580
+ gap: 2px;
581
+ }
582
+ .ai-audit-model-row {
583
+ display: flex;
584
+ align-items: baseline;
585
+ justify-content: space-between;
586
+ gap: var(--density-space-sm);
587
+ min-width: 0;
588
+ }
589
+ .ai-audit-model-name {
590
+ font-family: var(--font-mono);
591
+ font-size: var(--density-font-size-xs);
592
+ color: var(--token-text);
593
+ overflow: hidden;
594
+ text-overflow: ellipsis;
595
+ white-space: nowrap;
596
+ }
597
+ .ai-audit-model-meta {
598
+ flex-shrink: 0;
599
+ font-family: var(--font-mono);
600
+ font-size: var(--density-font-size-2xs);
601
+ color: var(--token-text-faint);
602
+ font-variant-numeric: tabular-nums;
603
+ }
604
+
605
+ /* 最近条目(最新在前) */
606
+ .ai-audit-list {
607
+ display: flex;
608
+ flex-direction: column;
609
+ gap: 2px;
610
+ max-height: 280px;
611
+ overflow-y: auto;
612
+ }
613
+ .ai-audit-item {
614
+ display: flex;
615
+ align-items: baseline;
616
+ gap: var(--density-space-xs);
617
+ padding: 2px var(--density-space-xs);
618
+ border-radius: var(--radius-xs);
619
+ min-width: 0;
620
+ }
621
+ .ai-audit-item:hover {
622
+ background: var(--token-fill-1);
623
+ }
624
+ .ai-audit-dot {
625
+ flex-shrink: 0;
626
+ width: 6px;
627
+ height: 6px;
628
+ border-radius: 50%;
629
+ background: var(--token-text-faint);
630
+ }
631
+ .ai-audit-item.is-done .ai-audit-dot {
632
+ background: var(--token-success);
633
+ }
634
+ .ai-audit-item.is-error .ai-audit-dot {
635
+ background: var(--token-error);
636
+ }
637
+ .ai-audit-item-main {
638
+ display: flex;
639
+ flex-direction: column;
640
+ min-width: 0;
641
+ flex: 1;
642
+ }
643
+ .ai-audit-item-model {
644
+ font-family: var(--font-mono);
645
+ font-size: var(--density-font-size-2xs);
646
+ color: var(--token-text);
647
+ overflow: hidden;
648
+ text-overflow: ellipsis;
649
+ white-space: nowrap;
650
+ }
651
+ .ai-audit-item-meta {
652
+ font-family: var(--font-mono);
653
+ font-size: var(--density-font-size-2xs);
654
+ color: var(--token-text-faint);
655
+ font-variant-numeric: tabular-nums;
656
+ }
657
+ .ai-audit-item-error {
658
+ flex-shrink: 0;
659
+ max-width: 45%;
660
+ font-size: var(--density-font-size-2xs);
661
+ color: var(--token-error);
662
+ overflow: hidden;
663
+ text-overflow: ellipsis;
664
+ white-space: nowrap;
665
+ }
666
+ .ai-audit-item.is-error .ai-audit-item-model {
667
+ color: var(--token-error);
668
+ }
669
+
670
+ /* 清除钮(右对齐;视觉复用 .btn .btn-sm) */
671
+ .ai-audit-clear {
672
+ align-self: flex-end;
673
+ }
674
+
675
+ /* ── 动效守卫 ── */
676
+
677
+ @media (prefers-reduced-motion: reduce) {
678
+ .ai-todo-bar > i,
679
+ .ai-usage-seg { transition: none; }
680
+ .ai-context { transition: none; }
681
+ .ai-item-status { animation: none; }
682
+ }
@@ -0,0 +1,3 @@
1
+ // @icen.ai/ui — kit: ai-reasoning(CSS + behavior 一行入口;构建产物,勿手改)
2
+ import './ai-chat.css';
3
+ export { createAiStream, initAiChat } from '../behaviors/ai-chat.mjs';
@@ -0,0 +1,2 @@
1
+ // @icen.ai/ui — kit: ai-subagent(CSS + behavior 一行入口;构建产物,勿手改)
2
+ import './ai-tool.css';
@@ -0,0 +1,2 @@
1
+ // @icen.ai/ui — kit: ai-todo(CSS + behavior 一行入口;构建产物,勿手改)
2
+ import './ai-panel.css';
@@ -0,0 +1,2 @@
1
+ // @icen.ai/ui — kit: ai-tool-call(CSS + behavior 一行入口;构建产物,勿手改)
2
+ import './ai-tool-call.css';