@icen.ai/ui 0.8.1 → 0.10.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 (335) hide show
  1. package/AGENTS.md +176 -75
  2. package/README.md +66 -88
  3. package/dist/base.css +208 -179
  4. package/dist/behaviors/accordion.mjs +8 -8
  5. package/dist/behaviors/ai-branch.d.mts +19 -0
  6. package/dist/behaviors/ai-branch.mjs +1133 -0
  7. package/dist/behaviors/ai-chat.d.mts +12 -10
  8. package/dist/behaviors/ai-chat.mjs +1125 -155
  9. package/dist/behaviors/ai-composer.d.mts +44 -12
  10. package/dist/behaviors/ai-composer.mjs +2084 -523
  11. package/dist/behaviors/ai-core.d.mts +1 -1
  12. package/dist/behaviors/ai-core.mjs +1016 -107
  13. package/dist/behaviors/ai-diff.mjs +1019 -127
  14. package/dist/behaviors/ai-feedback.d.mts +26 -0
  15. package/dist/behaviors/ai-feedback.mjs +1212 -0
  16. package/dist/behaviors/ai-panel.d.mts +21 -7
  17. package/dist/behaviors/ai-panel.mjs +1308 -264
  18. package/dist/behaviors/ai-provider.mjs +1003 -101
  19. package/dist/behaviors/ai-threads.d.mts +38 -0
  20. package/dist/behaviors/ai-threads.mjs +1233 -0
  21. package/dist/behaviors/ai-tool.d.mts +2 -2
  22. package/dist/behaviors/ai-tool.mjs +2042 -396
  23. package/dist/behaviors/ai-tools.d.mts +89 -16
  24. package/dist/behaviors/ai-tools.mjs +4453 -372
  25. package/dist/behaviors/autocomplete.d.mts +53 -0
  26. package/dist/behaviors/autocomplete.mjs +1600 -0
  27. package/dist/behaviors/back-top.d.mts +1 -1
  28. package/dist/behaviors/back-top.mjs +951 -14
  29. package/dist/behaviors/carousel.d.mts +1 -1
  30. package/dist/behaviors/carousel.mjs +906 -11
  31. package/dist/behaviors/cascader.d.mts +48 -0
  32. package/dist/behaviors/cascader.mjs +1853 -0
  33. package/dist/behaviors/charts.d.mts +174 -8
  34. package/dist/behaviors/charts.mjs +2632 -192
  35. package/dist/behaviors/code-block.d.mts +36 -0
  36. package/dist/behaviors/code-block.mjs +1611 -0
  37. package/dist/behaviors/command-palette.d.mts +9 -6
  38. package/dist/behaviors/command-palette.mjs +161 -59
  39. package/dist/behaviors/context-menu.d.mts +9 -8
  40. package/dist/behaviors/context-menu.mjs +1112 -44
  41. package/dist/behaviors/controls.d.mts +13 -13
  42. package/dist/behaviors/controls.mjs +989 -130
  43. package/dist/behaviors/copy.d.mts +21 -2
  44. package/dist/behaviors/copy.mjs +1206 -42
  45. package/dist/behaviors/datatable.d.mts +53 -3
  46. package/dist/behaviors/datatable.mjs +1963 -207
  47. package/dist/behaviors/date-picker.d.mts +0 -1
  48. package/dist/behaviors/date-picker.mjs +1340 -293
  49. package/dist/behaviors/design.d.mts +54 -0
  50. package/dist/behaviors/design.mjs +109 -0
  51. package/dist/behaviors/dropdown.d.mts +5 -6
  52. package/dist/behaviors/dropdown.mjs +262 -110
  53. package/dist/behaviors/events.d.mts +313 -3
  54. package/dist/behaviors/events.mjs +47 -2
  55. package/dist/behaviors/feedback.d.mts +30 -0
  56. package/dist/behaviors/feedback.mjs +296 -0
  57. package/dist/behaviors/focus.d.mts +8 -0
  58. package/dist/behaviors/focus.mjs +24 -0
  59. package/dist/behaviors/form-validate.d.mts +102 -0
  60. package/dist/behaviors/form-validate.mjs +6091 -0
  61. package/dist/behaviors/i18n.d.mts +789 -0
  62. package/dist/behaviors/i18n.mjs +1711 -0
  63. package/dist/behaviors/icons.d.mts +93 -0
  64. package/dist/behaviors/icons.mjs +113 -0
  65. package/dist/behaviors/input.d.mts +9 -1
  66. package/dist/behaviors/input.mjs +1056 -60
  67. package/dist/behaviors/kb-access.d.mts +34 -0
  68. package/dist/behaviors/kb-access.mjs +2459 -0
  69. package/dist/behaviors/kb-acl.d.mts +50 -0
  70. package/dist/behaviors/kb-acl.mjs +1345 -0
  71. package/dist/behaviors/kb-answer.d.mts +38 -0
  72. package/dist/behaviors/kb-answer.mjs +3707 -0
  73. package/dist/behaviors/kb-audit.d.mts +23 -0
  74. package/dist/behaviors/kb-audit.mjs +1297 -0
  75. package/dist/behaviors/kb-canvas.d.mts +44 -0
  76. package/dist/behaviors/kb-canvas.mjs +1512 -0
  77. package/dist/behaviors/kb-chain.d.mts +15 -0
  78. package/dist/behaviors/kb-chain.mjs +1192 -0
  79. package/dist/behaviors/kb-checkpoint.d.mts +16 -0
  80. package/dist/behaviors/kb-checkpoint.mjs +1492 -0
  81. package/dist/behaviors/kb-chunks.d.mts +31 -0
  82. package/dist/behaviors/kb-chunks.mjs +1414 -0
  83. package/dist/behaviors/kb-citation.d.mts +38 -0
  84. package/dist/behaviors/kb-citation.mjs +1699 -0
  85. package/dist/behaviors/kb-clarify.d.mts +20 -0
  86. package/dist/behaviors/kb-clarify.mjs +1176 -0
  87. package/dist/behaviors/kb-conflict.d.mts +22 -0
  88. package/dist/behaviors/kb-conflict.mjs +1206 -0
  89. package/dist/behaviors/kb-connector.d.mts +17 -0
  90. package/dist/behaviors/kb-connector.mjs +1303 -0
  91. package/dist/behaviors/kb-core.d.mts +534 -0
  92. package/dist/behaviors/kb-core.mjs +1805 -0
  93. package/dist/behaviors/kb-eval.d.mts +22 -0
  94. package/dist/behaviors/kb-eval.mjs +2235 -0
  95. package/dist/behaviors/kb-explain.d.mts +11 -0
  96. package/dist/behaviors/kb-explain.mjs +1165 -0
  97. package/dist/behaviors/kb-filter.d.mts +31 -0
  98. package/dist/behaviors/kb-filter.mjs +2417 -0
  99. package/dist/behaviors/kb-gap.d.mts +27 -0
  100. package/dist/behaviors/kb-gap.mjs +1195 -0
  101. package/dist/behaviors/kb-hittest.d.mts +34 -0
  102. package/dist/behaviors/kb-hittest.mjs +1352 -0
  103. package/dist/behaviors/kb-metadata.d.mts +29 -0
  104. package/dist/behaviors/kb-metadata.mjs +1248 -0
  105. package/dist/behaviors/kb-passage.d.mts +41 -0
  106. package/dist/behaviors/kb-passage.mjs +1469 -0
  107. package/dist/behaviors/kb-pipeline.d.mts +18 -0
  108. package/dist/behaviors/kb-pipeline.mjs +1301 -0
  109. package/dist/behaviors/kb-qa.d.mts +26 -0
  110. package/dist/behaviors/kb-qa.mjs +1260 -0
  111. package/dist/behaviors/kb-rerank.d.mts +20 -0
  112. package/dist/behaviors/kb-rerank.mjs +1248 -0
  113. package/dist/behaviors/kb-retrieval.d.mts +49 -0
  114. package/dist/behaviors/kb-retrieval.mjs +2585 -0
  115. package/dist/behaviors/kb-review.d.mts +44 -0
  116. package/dist/behaviors/kb-review.mjs +2282 -0
  117. package/dist/behaviors/kb-sandbox.d.mts +33 -0
  118. package/dist/behaviors/kb-sandbox.mjs +1247 -0
  119. package/dist/behaviors/kb-segment.d.mts +32 -0
  120. package/dist/behaviors/kb-segment.mjs +1431 -0
  121. package/dist/behaviors/kb-select.d.mts +24 -0
  122. package/dist/behaviors/kb-select.mjs +1989 -0
  123. package/dist/behaviors/kb-sources.d.mts +27 -0
  124. package/dist/behaviors/kb-sources.mjs +1287 -0
  125. package/dist/behaviors/kb-sql.d.mts +43 -0
  126. package/dist/behaviors/kb-sql.mjs +1865 -0
  127. package/dist/behaviors/kb-trace.d.mts +16 -0
  128. package/dist/behaviors/kb-trace.mjs +1328 -0
  129. package/dist/behaviors/kb-visibility.d.mts +44 -0
  130. package/dist/behaviors/kb-visibility.mjs +1331 -0
  131. package/dist/behaviors/kb-who-can.d.mts +32 -0
  132. package/dist/behaviors/kb-who-can.mjs +2216 -0
  133. package/dist/behaviors/mentions.d.mts +93 -0
  134. package/dist/behaviors/mentions.mjs +2152 -0
  135. package/dist/behaviors/modal.d.mts +4 -3
  136. package/dist/behaviors/modal.mjs +1055 -33
  137. package/dist/behaviors/nav.d.mts +1 -1
  138. package/dist/behaviors/nav.mjs +6 -6
  139. package/dist/behaviors/notification.d.mts +16 -8
  140. package/dist/behaviors/notification.mjs +1615 -265
  141. package/dist/behaviors/panel.d.mts +4 -0
  142. package/dist/behaviors/panel.mjs +994 -0
  143. package/dist/behaviors/popover.d.mts +28 -5
  144. package/dist/behaviors/popover.mjs +225 -24
  145. package/dist/behaviors/select.d.mts +5 -2
  146. package/dist/behaviors/select.mjs +1410 -117
  147. package/dist/behaviors/sidebar.d.mts +1 -1
  148. package/dist/behaviors/sidebar.mjs +13 -13
  149. package/dist/behaviors/slider.d.mts +1 -1
  150. package/dist/behaviors/slider.mjs +9 -9
  151. package/dist/behaviors/split-pane.d.mts +1 -1
  152. package/dist/behaviors/split-pane.mjs +7 -7
  153. package/dist/behaviors/suggestions.d.mts +27 -0
  154. package/dist/behaviors/suggestions.mjs +1089 -0
  155. package/dist/behaviors/svg-parse.d.mts +14 -0
  156. package/dist/behaviors/svg-parse.mjs +37 -0
  157. package/dist/behaviors/tabs.d.mts +2 -2
  158. package/dist/behaviors/tabs.mjs +25 -25
  159. package/dist/behaviors/tag-input.d.mts +23 -5
  160. package/dist/behaviors/tag-input.mjs +1359 -104
  161. package/dist/behaviors/theme-switcher.d.mts +24 -0
  162. package/dist/behaviors/theme-switcher.mjs +1981 -0
  163. package/dist/behaviors/theme.d.mts +15 -8
  164. package/dist/behaviors/theme.mjs +390 -28
  165. package/dist/behaviors/toast.d.mts +24 -25
  166. package/dist/behaviors/toast.mjs +1266 -88
  167. package/dist/behaviors/tooltip.d.mts +4 -0
  168. package/dist/behaviors/tooltip.mjs +378 -0
  169. package/dist/behaviors/tree-select.d.mts +69 -0
  170. package/dist/behaviors/tree-select.mjs +1907 -0
  171. package/dist/behaviors/tree.d.mts +1 -1
  172. package/dist/behaviors/tree.mjs +15 -15
  173. package/dist/behaviors/upload.d.mts +3 -2
  174. package/dist/behaviors/upload.mjs +1076 -66
  175. package/dist/cli.mjs +5 -6
  176. package/dist/components/ai-branch.mjs +3 -0
  177. package/dist/components/ai-chat.css +846 -458
  178. package/dist/components/ai-diff.css +153 -132
  179. package/dist/components/ai-feedback.mjs +3 -0
  180. package/dist/components/ai-panel.css +495 -270
  181. package/dist/components/ai-threads.mjs +3 -0
  182. package/dist/components/ai-tool.css +393 -238
  183. package/dist/components/autocomplete.css +61 -0
  184. package/dist/components/autocomplete.mjs +3 -0
  185. package/dist/components/back-top.css +34 -31
  186. package/dist/components/badge.css +44 -41
  187. package/dist/components/breadcrumb.css +67 -46
  188. package/dist/components/btn.css +80 -74
  189. package/dist/components/card.css +117 -106
  190. package/dist/components/cascader.css +311 -0
  191. package/dist/components/cascader.mjs +3 -0
  192. package/dist/components/chart-area.css +8 -2
  193. package/dist/components/chart-bar.css +95 -33
  194. package/dist/components/chart-gauge.css +14 -11
  195. package/dist/components/chart-graph.css +60 -0
  196. package/dist/components/chart-graph.mjs +4 -0
  197. package/dist/components/chart-heatmap.css +96 -90
  198. package/dist/components/chart-line.css +8 -3
  199. package/dist/components/chart-map.mjs +3 -0
  200. package/dist/components/chart-pie.css +9 -6
  201. package/dist/components/chart-radar.css +8 -5
  202. package/dist/components/chart-scatter.css +9 -6
  203. package/dist/components/chart-scatter.mjs +1 -1
  204. package/dist/components/chart-sparkline.css +5 -2
  205. package/dist/components/chart-stack.css +14 -11
  206. package/dist/components/charts.css +190 -67
  207. package/dist/components/charts.mjs +1 -0
  208. package/dist/components/code-block.css +418 -0
  209. package/dist/components/code-block.mjs +4 -0
  210. package/dist/components/command-palette.css +138 -117
  211. package/dist/components/content.css +257 -251
  212. package/dist/components/copy.css +72 -44
  213. package/dist/components/datatable.css +423 -181
  214. package/dist/components/date-picker.css +135 -104
  215. package/dist/components/empty.css +68 -65
  216. package/dist/components/feedback.css +201 -183
  217. package/dist/components/form-validate.css +120 -0
  218. package/dist/components/form-validate.mjs +3 -0
  219. package/dist/components/form.css +150 -127
  220. package/dist/components/icon.css +102 -0
  221. package/dist/components/icon.mjs +3 -0
  222. package/dist/components/input.css +159 -104
  223. package/dist/components/kb-access.mjs +4 -0
  224. package/dist/components/kb-acl.mjs +4 -0
  225. package/dist/components/kb-agent.css +496 -0
  226. package/dist/components/kb-answer.mjs +4 -0
  227. package/dist/components/kb-audit.mjs +4 -0
  228. package/dist/components/kb-canvas.mjs +4 -0
  229. package/dist/components/kb-chain.mjs +4 -0
  230. package/dist/components/kb-checkpoint.mjs +4 -0
  231. package/dist/components/kb-chunks.mjs +4 -0
  232. package/dist/components/kb-citation.mjs +4 -0
  233. package/dist/components/kb-clarify.mjs +4 -0
  234. package/dist/components/kb-conflict.mjs +4 -0
  235. package/dist/components/kb-connector.mjs +4 -0
  236. package/dist/components/kb-data.css +653 -0
  237. package/dist/components/kb-eval.mjs +4 -0
  238. package/dist/components/kb-explain.mjs +4 -0
  239. package/dist/components/kb-filter.mjs +4 -0
  240. package/dist/components/kb-gap.mjs +4 -0
  241. package/dist/components/kb-ground.css +578 -0
  242. package/dist/components/kb-hittest.mjs +4 -0
  243. package/dist/components/kb-ingest.css +882 -0
  244. package/dist/components/kb-metadata.mjs +4 -0
  245. package/dist/components/kb-ops.css +554 -0
  246. package/dist/components/kb-passage.mjs +4 -0
  247. package/dist/components/kb-perm.css +433 -0
  248. package/dist/components/kb-pipeline.mjs +4 -0
  249. package/dist/components/kb-qa.mjs +4 -0
  250. package/dist/components/kb-rerank.mjs +4 -0
  251. package/dist/components/kb-retrieval.mjs +4 -0
  252. package/dist/components/kb-review.mjs +4 -0
  253. package/dist/components/kb-sandbox.mjs +4 -0
  254. package/dist/components/kb-search.css +897 -0
  255. package/dist/components/kb-segment.mjs +4 -0
  256. package/dist/components/kb-sources.mjs +4 -0
  257. package/dist/components/kb-sql.mjs +4 -0
  258. package/dist/components/kb-trace.mjs +4 -0
  259. package/dist/components/kb-visibility.mjs +4 -0
  260. package/dist/components/kb-who-can.mjs +4 -0
  261. package/dist/components/kb.css +263 -0
  262. package/dist/components/kb.mjs +9 -0
  263. package/dist/components/layout.css +85 -82
  264. package/dist/components/material-chinese.css +73 -0
  265. package/dist/components/material-soviet.css +76 -0
  266. package/dist/components/material.css +275 -0
  267. package/dist/components/media.css +220 -166
  268. package/dist/components/mentions.css +189 -0
  269. package/dist/components/mentions.mjs +3 -0
  270. package/dist/components/menu.css +113 -105
  271. package/dist/components/modal.css +107 -112
  272. package/dist/components/nav.css +118 -115
  273. package/dist/components/notification.css +238 -174
  274. package/dist/components/pagination.css +56 -53
  275. package/dist/components/panel.css +66 -63
  276. package/dist/components/panel.mjs +1 -0
  277. package/dist/components/pill.css +81 -71
  278. package/dist/components/popover.css +67 -53
  279. package/dist/components/scroll-area.css +113 -110
  280. package/dist/components/segmented.css +146 -143
  281. package/dist/components/select.css +206 -186
  282. package/dist/components/sidebar.css +137 -127
  283. package/dist/components/slider.css +117 -114
  284. package/dist/components/split-pane.css +112 -109
  285. package/dist/components/stat.css +112 -106
  286. package/dist/components/steps.css +109 -103
  287. package/dist/components/switch.css +138 -134
  288. package/dist/components/table.css +131 -107
  289. package/dist/components/tabs.css +114 -108
  290. package/dist/components/tag-input.css +48 -133
  291. package/dist/components/tag.css +81 -71
  292. package/dist/components/theme-switcher.css +105 -0
  293. package/dist/components/theme-switcher.mjs +3 -0
  294. package/dist/components/toast.css +100 -86
  295. package/dist/components/toolbar.css +45 -42
  296. package/dist/components/tooltip.css +102 -43
  297. package/dist/components/tooltip.mjs +1 -0
  298. package/dist/components/tree-select.css +416 -0
  299. package/dist/components/tree-select.mjs +3 -0
  300. package/dist/components/upload.css +135 -92
  301. package/dist/fonts/LICENSES/ark-pixel/OFL.txt +96 -0
  302. package/dist/fonts/LICENSES/cubic-11/OFL.txt +108 -0
  303. package/dist/fonts/LICENSES/galmuri/LICENSE.txt +93 -0
  304. package/dist/fonts/OFL.txt +96 -0
  305. package/dist/fonts/README.md +14 -0
  306. package/dist/fonts/fusion-pixel-12px-zh-hans.woff2 +0 -0
  307. package/dist/index.d.mts +64 -15
  308. package/dist/index.mjs +28049 -8595
  309. package/dist/react.d.mts +91 -0
  310. package/dist/react.mjs +8208 -0
  311. package/dist/registry.json +454 -15
  312. package/dist/tokens/chinese.css +44 -0
  313. package/dist/tokens/colors.css +365 -1222
  314. package/dist/tokens/design.css +109 -0
  315. package/dist/tokens/dtcg.json +11198 -0
  316. package/dist/tokens/figma.variables.json +7017 -0
  317. package/dist/tokens/icon-masks.css +78 -0
  318. package/dist/tokens/pixel.css +50 -0
  319. package/dist/tokens/soviet.css +44 -0
  320. package/dist/tokens/style-profiles.css +36 -547
  321. package/dist/tokens/themes.json +308 -0
  322. package/dist/tokens/tokens-studio.json +6728 -0
  323. package/dist/tokens/typography.css +21 -18
  324. package/dist/tokens.css +1555 -1801
  325. package/dist/ui.css +16147 -8597
  326. package/dist/vue.d.mts +344 -0
  327. package/dist/vue.mjs +7781 -0
  328. package/docs/spec/ai-input-experience.md +75 -0
  329. package/docs/spec/ai-native.md +238 -147
  330. package/docs/spec/design-philosophy.md +189 -0
  331. package/docs/spec/design-primitives.md +196 -0
  332. package/docs/spec/kb-family.md +475 -0
  333. package/package.json +42 -7
  334. package/dist/retro-effects.css +0 -255
  335. package/dist/tokens/retro-effects.css +0 -255
@@ -1,60 +1,59 @@
1
+ @layer icen.components {
1
2
  /*
2
3
  * @icen.ai/ui — Component: ai-chat(AI 原生组件族:ai-chat / ai-message / ai-reasoning / ai-composer)
3
4
  *
4
5
  * 完整契约:
5
- * <div class="ai-chat" data-density="normal"> ← verbose|normal|summary 三档
6
- * <div class="ai-chat-scroll">
7
- * <div class="ai-msg ai-msg--user|ai-msg--assistant|ai-msg--system|ai-msg--tool">
8
- * <span class="ai-msg-avatar"></span>
9
- * <div class="ai-msg-body">…消费方自行渲染 markdown…</div>
10
- * <div class="ai-msg-actions"><button data-ai-msg-action="copy|retry">…</button></div>
11
- * <div class="ai-msg-meta">12:04 · 1.2k tok</div>
6
+ * <div class="icen-ai-chat" data-icen-density="normal"> ← verbose|normal|summary 三档
7
+ * <div class="icen-ai-chat-scroll">
8
+ * <div class="icen-ai-msg icen-ai-msg--user|icen-ai-msg--assistant|icen-ai-msg--system|icen-ai-msg--tool">
9
+ * <span class="icen-ai-msg-avatar"></span>
10
+ * <div class="icen-ai-msg-body">…消费方自行渲染 markdown…</div>
11
+ * <div class="icen-ai-msg-actions"><button data-icen-ai-msg-action="copy|retry">…</button></div>
12
+ * <div class="icen-ai-msg-meta">12:04 · 1.2k tok</div>
12
13
  * </div>
13
14
  * </div>
14
- * <button class="ai-chat-jump" hidden>回到底部 · N 条新消息</button>
15
+ * <button class="icen-ai-chat-jump" hidden>回到底部 · N 条新消息</button>
15
16
  * </div>
16
17
  *
17
- * <div class="ai-reasoning [.is-streaming|.is-done]">
18
- * <button class="ai-reasoning-head" aria-expanded="false">
19
- * <span class="ai-reasoning-label">思考过程</span><span class="ai-reasoning-time">3s</span>
18
+ * <div class="icen-ai-reasoning [.is-streaming|.is-done]">
19
+ * <button class="icen-ai-reasoning-head" aria-expanded="false">
20
+ * <span class="icen-ai-reasoning-label">思考过程</span><span class="icen-ai-reasoning-time">3s</span>
20
21
  * </button>
21
- * <div class="ai-reasoning-body" hidden>…</div>
22
+ * <div class="icen-ai-reasoning-body" hidden>…</div>
22
23
  * </div>
23
24
  *
24
- * <div class="ai-composer" data-ai-composer [.is-running]>
25
- * <div class="ai-composer-queue" hidden><span class="ai-composer-chip">
26
- * <span class="ai-composer-chip-text">…</span>
27
- * <button class="ai-composer-chip-remove" aria-label="移除">×</button>
25
+ * <div class="icen-ai-composer" data-icen-ai-composer [.is-running]>
26
+ * <div class="icen-ai-composer-queue" hidden><span class="icen-ai-composer-chip">
27
+ * <span class="icen-ai-composer-chip-text">…</span>
28
+ * <button class="icen-ai-composer-chip-remove" aria-label="移除">×</button>
28
29
  * </span></div>
29
- * <div class="ai-composer-refs" hidden><!-- @ 引用 chips,结构同上(v2 setComposerRefs) --></div>
30
- * <div class="ai-composer-attach" hidden><!-- 附件 chips,结构同上 --></div>
31
- * <div class="ai-composer-box control">
32
- * <textarea class="ai-composer-input" rows="1" placeholder="…"></textarea>
33
- * <div class="ai-composer-actions"><!-- v1 旧结构(无 toolbar 配置时保留): -->
34
- * <button class="ai-composer-btn" data-ai-attach aria-label="附件"></button>
35
- * <button class="ai-composer-send" data-ai-send aria-label="发送"></button> ← 运行态 .is-stop
36
- * </div>
37
- * <div class="ai-composer-toolbar"><!-- v2 工具条(setComposerModels/Usage 配置时 JS 装配):
38
- * <button class="ai-composer-model" data-ai-model-open>provider 图标/首字母章 + 模型名 + chevron</button>
39
- * <span class="ai-composer-spacer"></span>
40
- * <span class="ai-composer-usage" data-ai-usage></span> ← 用量环挂载点(renderAiUsageRing)
41
- * <button class="ai-composer-btn" data-ai-attach></button>
42
- * <button class="ai-composer-send" data-ai-send></button> ← 运行态 .is-stop
30
+ * <div class="icen-ai-composer-refs" hidden><!-- @ 引用 chips,结构同上(v2 setComposerRefs) --></div>
31
+ * <div class="icen-ai-composer-attach" hidden><!-- 附件 chips,结构同上 --></div>
32
+ * <div class="icen-ai-composer-box icen-control">
33
+ * <icen-textarea class="icen-ai-composer-input" rows="1" placeholder="…"></icen-textarea>
34
+ * <div class="icen-ai-composer-toolbar"><!-- 工具条(手写或 setComposerModels/Usage 配置时 JS 装配):
35
+ * <button class="icen-ai-composer-btn" data-icen-ai-attach aria-label="附件"></button>
36
+ * <button class="icen-ai-composer-send" data-icen-ai-send aria-label="发送"></button> ← 运行态 .is-stop
37
+ * <button class="icen-ai-composer-model" data-icen-ai-model-open>provider 图标/首字母章 + 模型名 + chevron</button>
38
+ * <span class="icen-ai-composer-spacer"></span>
39
+ * <span class="icen-ai-composer-usage" data-icen-ai-usage></span> ← 用量环挂载点(renderAiUsageRing)
40
+ * <button class="icen-ai-composer-btn" data-icen-ai-attach></button>
41
+ * <button class="icen-ai-composer-send" data-icen-ai-send></button> ← 运行态 .is-stop
43
42
  * </div>
44
43
  * </div>
45
44
  * </div>
46
- * 弹层 .ai-composer-popup(portal body,JS 动态创建):模型切换 / 斜杠命令 / @ 引用
47
- * 三模式共用基座——.ai-composer-popup-search 搜索框、.ai-composer-popup-list(listbox)
48
- * > .ai-composer-popup-group > .ai-composer-popup-group-label + .ai-composer-popup-option(role=option),
49
- * .ai-composer-popup-empty 空态、.ai-composer-popup-foot 底部提示。
45
+ * 弹层 .icen-ai-composer-popup(portal body,JS 动态创建):模型切换 / 斜杠命令 / @ 引用
46
+ * 三模式共用基座——.icen-ai-composer-popup-search 搜索框、.icen-ai-composer-popup-list(listbox)
47
+ * > .icen-ai-composer-popup-group > .icen-ai-composer-popup-group-label + .icen-ai-composer-popup-option(role=option),
48
+ * .icen-ai-composer-popup-empty 空态、.icen-ai-composer-popup-foot 底部提示。
50
49
  *
51
50
  * 配套 behaviors:behaviors/ai-chat.ts(initAiChat / createAiStream)
52
51
  * + behaviors/ai-composer.ts(initAiComposer / setComposerRunning
53
52
  * + v2:setComposerModels / setComposerCommands / setComposerRefs / setComposerUsage)。
54
- * 状态机 7 态 .is-* 中的 streaming/done 在本文件消费;running 脉冲点等条目态见 ai-tool.css(.ai-item 基元)。
55
- * data-density:summary 档隐藏 meta、默认折叠 reasoning(纯 CSS);
53
+ * 状态机 7 态 .is-* 中的 streaming/done 在本文件消费;running 脉冲点等条目态见 ai-tool.css(.icen-ai-item 基元)。
54
+ * data-icen-density:summary 档隐藏 meta、默认折叠 reasoning(纯 CSS);
56
55
  * tool/system 类次要消息在 summary 档压淡。verbose 与 normal 目前同视觉(透明度两档生效)。
57
- * 流式光标复用 tokens 的 blink keyframes(.animate-blink 同款);reasoning shimmer 时长走
56
+ * 流式光标复用 tokens 的 blink keyframes(.icen-animate-blink 同款);reasoning shimmer 时长走
58
57
  * --ai-shimmer-duration 局部变量(默认值 1.6s)。
59
58
  */
60
59
 
@@ -63,144 +62,144 @@
63
62
  /* 输出容器宽度自稳定契约:即使宿主是 flex/grid 居中上下文(shrink-wrap 陷阱),
64
63
  也不随内容多少改变宽度——流式内容只允许纵向生长。
65
64
  (用 align-self 而非 width:100%——width 在 shrink-wrap 父级下会塌成 min-content) */
66
- .ai-chat,
67
- .ai-reasoning,
68
- .ai-composer {
65
+ .icen-ai-chat,
66
+ .icen-ai-reasoning,
67
+ .icen-ai-composer {
69
68
  align-self: stretch;
70
69
  }
71
70
 
72
- .ai-chat {
71
+ .icen-ai-chat {
73
72
  position: relative;
74
73
  display: flex;
75
74
  flex-direction: column;
76
75
  height: 100%;
77
76
  min-height: 0;
78
- gap: var(--density-space-sm);
77
+ gap: var(--icen-density-space-sm);
79
78
  }
80
79
 
81
- .ai-chat-scroll {
80
+ .icen-ai-chat-scroll {
82
81
  flex: 1;
83
82
  min-height: 0;
84
83
  overflow-y: auto;
85
84
  display: flex;
86
85
  flex-direction: column;
87
- gap: var(--density-space-md);
88
- padding: var(--density-space-xs) var(--density-space-2xs, 2px);
86
+ gap: var(--icen-density-space-md);
87
+ padding: var(--icen-density-space-xs) var(--icen-density-space-2xs, 2px);
89
88
  scroll-behavior: smooth;
90
89
  }
91
90
 
92
91
  /* 「回到底部 · N 条新消息」浮动钮(用户上滚暂停跟随时出现,initAiChat 驱动) */
93
- .ai-chat-jump {
92
+ .icen-ai-chat-jump {
94
93
  position: absolute;
95
- left: 50%;
96
- bottom: var(--density-space-md);
94
+ left: 50%; /* guard:allow-physical 水平居中(translateX(-50%) 配套) */
95
+ bottom: var(--icen-density-space-md);
97
96
  transform: translateX(-50%);
98
- z-index: var(--z-raised);
97
+ z-index: var(--icen-z-raised);
99
98
  display: inline-flex;
100
99
  align-items: center;
101
- gap: var(--density-space-xs);
102
- padding: var(--density-space-xs) var(--density-space-md);
103
- border: 1px solid var(--token-line-soft);
104
- border-radius: var(--radius-full);
105
- background: var(--token-surface);
106
- box-shadow: var(--token-shadow-card);
107
- color: var(--token-text-muted);
108
- font-family: var(--font-mono);
109
- font-size: var(--density-font-size-xs);
100
+ gap: var(--icen-density-space-xs);
101
+ padding: var(--icen-density-space-xs) var(--icen-density-space-md);
102
+ border: 1px solid var(--icen-token-line-soft);
103
+ border-radius: var(--icen-radius-full);
104
+ background: var(--icen-token-surface);
105
+ box-shadow: var(--icen-token-shadow-card);
106
+ color: var(--icen-token-text-muted);
107
+ font-family: var(--icen-font-mono);
108
+ font-size: var(--icen-density-font-size-xs);
110
109
  letter-spacing: 0.02em;
111
110
  white-space: nowrap;
112
111
  cursor: pointer;
113
- animation: icen-pop-in var(--ai-jump-enter-duration, var(--duration-normal)) var(--ease-out);
112
+ animation: icen-pop-in var(--ai-jump-enter-duration, var(--icen-duration-normal)) var(--icen-ease-out);
114
113
  transition:
115
114
  color var(--icen-tx-fast),
116
115
  border-color var(--icen-tx-fast),
117
116
  box-shadow var(--icen-tx-fast);
118
117
  }
119
- .ai-chat-jump:hover {
120
- color: var(--token-accent);
118
+ .icen-ai-chat-jump:hover {
119
+ color: var(--icen-token-accent);
121
120
  border-color: var(--icen-hover-border);
122
121
  }
123
- .ai-chat-jump:focus-visible {
122
+ .icen-ai-chat-jump:focus-visible {
124
123
  outline: none;
125
124
  box-shadow: var(--icen-ring);
126
125
  }
127
- .ai-chat-jump[hidden] {
126
+ .icen-ai-chat-jump[hidden] {
128
127
  display: none;
129
128
  }
130
129
 
131
130
  /* ══════════════ ai-message ══════════════ */
132
131
 
133
- .ai-msg {
132
+ .icen-ai-msg {
134
133
  position: relative;
135
134
  display: grid;
136
135
  grid-template-columns: auto 1fr;
137
- gap: var(--density-space-sm);
138
- padding: var(--density-space-sm) var(--density-space-md);
139
- border-radius: var(--radius-md);
140
- animation: icen-pop-in var(--ai-msg-enter-duration, var(--duration-normal)) var(--ease-out);
136
+ gap: var(--icen-density-space-sm);
137
+ padding: var(--icen-density-space-sm) var(--icen-density-space-md);
138
+ border-radius: var(--icen-radius-md);
139
+ animation: icen-pop-in var(--ai-msg-enter-duration, var(--icen-duration-normal)) var(--icen-ease-out);
141
140
  }
142
141
 
143
- .ai-msg-avatar {
142
+ .icen-ai-msg-avatar {
144
143
  width: 28px;
145
144
  height: 28px;
146
145
  flex-shrink: 0;
147
146
  display: inline-flex;
148
147
  align-items: center;
149
148
  justify-content: center;
150
- border-radius: var(--radius-sm);
151
- background: var(--token-fill-2);
152
- color: var(--token-text-muted);
153
- font-family: var(--font-mono);
154
- font-size: var(--density-font-size-2xs);
149
+ border-radius: var(--icen-radius-sm);
150
+ background: var(--icen-token-fill-2);
151
+ color: var(--icen-token-text-muted);
152
+ font-family: var(--icen-font-mono);
153
+ font-size: var(--icen-density-font-size-2xs);
155
154
  letter-spacing: 0.04em;
156
155
  user-select: none;
157
156
  }
158
- .ai-msg--user .ai-msg-avatar {
159
- background: color-mix(in srgb, var(--token-accent) 14%, transparent);
160
- color: var(--token-accent);
157
+ .icen-ai-msg--user .icen-ai-msg-avatar {
158
+ background: color-mix(in srgb, var(--icen-token-accent) 14%, transparent);
159
+ color: var(--icen-token-accent);
161
160
  }
162
- .ai-msg--assistant .ai-msg-avatar {
163
- background: color-mix(in srgb, var(--token-success) 12%, transparent);
164
- color: var(--token-success);
161
+ .icen-ai-msg--assistant .icen-ai-msg-avatar {
162
+ background: color-mix(in srgb, var(--icen-token-success) 12%, transparent);
163
+ color: var(--icen-token-success);
165
164
  }
166
- .ai-msg--system .ai-msg-avatar {
167
- background: color-mix(in srgb, var(--token-warning) 12%, transparent);
168
- color: var(--token-warning);
165
+ .icen-ai-msg--system .icen-ai-msg-avatar {
166
+ background: color-mix(in srgb, var(--icen-token-warning) 12%, transparent);
167
+ color: var(--icen-token-warning);
169
168
  }
170
- .ai-msg--tool .ai-msg-avatar {
171
- background: color-mix(in srgb, var(--token-info) 12%, transparent);
172
- color: var(--token-info);
169
+ .icen-ai-msg--tool .icen-ai-msg-avatar {
170
+ background: color-mix(in srgb, var(--icen-token-info) 12%, transparent);
171
+ color: var(--icen-token-info);
173
172
  }
174
173
 
175
- .ai-msg-body {
174
+ .icen-ai-msg-body {
176
175
  min-width: 0;
177
176
  min-height: 1.6em; /* 流式从空开始时占住一行高度,不塌 */
178
- font-size: var(--density-font-size-md);
177
+ font-size: var(--icen-density-font-size-md);
179
178
  line-height: 1.6;
180
179
  white-space: pre-wrap;
181
180
  word-break: break-word;
182
181
  }
183
182
 
184
- /* 流式光标(▍闪烁,复用 tokens 的 blink keyframes,同 .animate-blink) */
185
- .ai-msg-body.is-streaming::after,
186
- .ai-reasoning-body.is-streaming::after {
183
+ /* 流式光标(▍闪烁,复用 tokens 的 blink keyframes,同 .icen-animate-blink) */
184
+ .icen-ai-msg-body.is-streaming::after,
185
+ .icen-ai-reasoning-body.is-streaming::after {
187
186
  content: '▍';
188
- margin-left: 1px;
189
- color: var(--token-accent);
187
+ margin-inline-start: 1px;
188
+ color: var(--icen-token-accent);
190
189
  animation: blink 1s step-end infinite;
191
190
  }
192
191
 
193
192
  /* 消息操作:hover / focus-within 才出现(键盘可达等价) */
194
- .ai-msg-actions {
193
+ .icen-ai-msg-actions {
195
194
  position: absolute;
196
- top: var(--density-space-xs);
197
- right: var(--density-space-xs);
195
+ top: var(--icen-density-space-xs);
196
+ inset-inline-end: var(--icen-density-space-xs);
198
197
  display: flex;
199
198
  gap: 2px;
200
199
  padding: 2px;
201
- border-radius: var(--radius-sm);
202
- background: var(--token-surface);
203
- border: 1px solid var(--token-line-soft);
200
+ border-radius: var(--icen-radius-sm);
201
+ background: var(--icen-token-surface);
202
+ border: 1px solid var(--icen-token-line-soft);
204
203
  opacity: 0;
205
204
  visibility: hidden;
206
205
  transform: translateY(-2px);
@@ -209,13 +208,13 @@
209
208
  transform var(--icen-tx-fast),
210
209
  visibility var(--icen-tx-fast);
211
210
  }
212
- .ai-msg:hover .ai-msg-actions,
213
- .ai-msg:focus-within .ai-msg-actions {
211
+ .icen-ai-msg:hover .icen-ai-msg-actions,
212
+ .icen-ai-msg:focus-within .icen-ai-msg-actions {
214
213
  opacity: 1;
215
214
  visibility: visible;
216
215
  transform: translateY(0);
217
216
  }
218
- .ai-msg-actions [data-ai-msg-action] {
217
+ .icen-ai-msg-actions [data-icen-ai-msg-action] {
219
218
  display: inline-flex;
220
219
  align-items: center;
221
220
  justify-content: center;
@@ -223,190 +222,191 @@
223
222
  height: 22px;
224
223
  padding: 0;
225
224
  border: 0;
226
- border-radius: var(--radius-xs);
225
+ border-radius: var(--icen-radius-xs);
227
226
  background: transparent;
228
- color: var(--token-text-muted);
227
+ color: var(--icen-token-text-muted);
229
228
  cursor: pointer;
230
229
  transition:
231
230
  color var(--icen-tx-fast),
232
231
  background-color var(--icen-tx-fast);
233
232
  }
234
- .ai-msg-actions [data-ai-msg-action]:hover {
235
- color: var(--token-accent);
236
- background: var(--token-fill-2);
233
+ .icen-ai-msg-actions [data-icen-ai-msg-action]:hover {
234
+ color: var(--icen-token-accent);
235
+ background: var(--icen-token-fill-2);
237
236
  }
238
- .ai-msg-actions [data-ai-msg-action]:focus-visible {
237
+ .icen-ai-msg-actions [data-icen-ai-msg-action]:focus-visible {
239
238
  outline: none;
240
239
  box-shadow: var(--icen-ring);
241
240
  }
242
- .ai-msg-actions [data-ai-msg-action] svg {
241
+ .icen-ai-msg-actions [data-icen-ai-msg-action] svg {
243
242
  width: 12px;
244
243
  height: 12px;
245
244
  }
246
245
 
247
246
  /* meta:时间 · token 数(summary 档隐藏) */
248
- .ai-msg-meta {
247
+ .icen-ai-msg-meta {
248
+ grid-column: 2; /* 归属正文列:落在 auto 第一列会把列宽撑到 meta 宽度,正文被挤窄(流式收尾时突跳) */
249
249
  margin-top: 2px;
250
- font-family: var(--font-mono);
251
- font-size: var(--density-font-size-2xs);
252
- color: var(--token-text-faint);
250
+ font-family: var(--icen-font-mono);
251
+ font-size: var(--icen-density-font-size-2xs);
252
+ color: var(--icen-token-text-faint);
253
253
  font-variant-numeric: tabular-nums;
254
254
  }
255
255
 
256
256
  /* ── 多模态消息部件(renderAiMessage,spec §10)── */
257
257
 
258
- .ai-msg-text {
258
+ .icen-ai-msg-text {
259
259
  display: block;
260
260
  }
261
261
 
262
262
  /* 图片 / 音频 / 视频:宽度自稳定(不超正文列),纵向生长 */
263
- .ai-msg-media {
263
+ .icen-ai-msg-media {
264
264
  display: block;
265
- max-width: min(100%, 360px);
266
- margin: var(--density-space-xs) 0;
267
- border: 1px solid var(--token-line-soft);
268
- border-radius: var(--radius-md);
269
- background: var(--token-surface);
270
- }
271
- .ai-msg-media--image {
272
- max-height: 320px;
265
+ max-inline-size: min(100%, 360px);
266
+ margin: var(--icen-density-space-xs) 0;
267
+ border: 1px solid var(--icen-token-line-soft);
268
+ border-radius: var(--icen-radius-md);
269
+ background: var(--icen-token-surface);
270
+ }
271
+ .icen-ai-msg-media--image {
272
+ max-block-size: 320px;
273
273
  object-fit: contain;
274
274
  }
275
- .ai-msg-media--audio {
276
- width: min(100%, 300px);
275
+ .icen-ai-msg-media--audio {
276
+ inline-size: min(100%, 300px);
277
277
  height: 40px;
278
278
  }
279
- .ai-msg-media--video {
280
- max-width: min(100%, 480px);
281
- max-height: 300px;
279
+ .icen-ai-msg-media--video {
280
+ max-inline-size: min(100%, 480px);
281
+ max-block-size: 300px;
282
282
  }
283
283
 
284
- /* 文件 chip(含可选下载链接) */
285
- .ai-msg-file {
284
+ /* 文件 chip(含可选下载链接;行内方向间距:inline-end 侧留隙) */
285
+ .icen-ai-msg-file {
286
286
  display: inline-flex;
287
287
  align-items: center;
288
- gap: var(--density-space-xs);
289
- margin: 2px var(--density-space-xs) 2px 0;
290
- padding: 2px var(--density-space-sm);
291
- border: 1px solid var(--token-line);
292
- border-radius: var(--radius-sm);
293
- background: var(--token-surface);
294
- font-family: var(--font-mono);
295
- font-size: var(--density-font-size-xs);
296
- color: var(--token-text);
297
- }
298
- .ai-msg-file-link {
299
- color: var(--token-accent);
288
+ gap: var(--icen-density-space-xs);
289
+ margin-block: 2px;
290
+ margin-inline-end: var(--icen-density-space-xs);
291
+ padding: 2px var(--icen-density-space-sm);
292
+ border: 1px solid var(--icen-token-line);
293
+ border-radius: var(--icen-radius-sm);
294
+ background: var(--icen-token-surface);
295
+ font-family: var(--icen-font-mono);
296
+ font-size: var(--icen-density-font-size-xs);
297
+ color: var(--icen-token-text);
298
+ }
299
+ .icen-ai-msg-file-link {
300
+ color: var(--icen-token-accent);
300
301
  text-decoration: none;
301
302
  }
302
- .ai-msg-file-link:hover {
303
+ .icen-ai-msg-file-link:hover {
303
304
  text-decoration: underline;
304
305
  }
305
306
 
306
307
  /* MCP ResourceLink 等资源引用 */
307
- .ai-msg-link {
308
- color: var(--token-accent);
308
+ .icen-ai-msg-link {
309
+ color: var(--icen-token-accent);
309
310
  }
310
311
 
311
312
  /* assistant 消息的模型名标签 */
312
- .ai-msg-model {
313
+ .icen-ai-msg-model {
313
314
  display: inline-block;
314
- margin-left: var(--density-space-xs);
315
+ margin-inline-start: var(--icen-density-space-xs);
315
316
  padding: 0 6px;
316
- border-radius: var(--radius-xs);
317
- background: var(--token-fill-1);
318
- color: var(--token-text-faint);
319
- font-family: var(--font-mono);
320
- font-size: var(--density-font-size-2xs);
317
+ border-radius: var(--icen-radius-xs);
318
+ background: var(--icen-token-fill-1);
319
+ color: var(--icen-token-text-faint);
320
+ font-family: var(--icen-font-mono);
321
+ font-size: var(--icen-density-font-size-2xs);
321
322
  vertical-align: middle;
322
323
  }
323
324
 
324
325
  /* ── 错误变体(renderAiMessage.setError / createAiStream.fail)── */
325
326
 
326
- .ai-msg--error .ai-msg-body {
327
- border-left: 2px solid var(--token-error);
328
- padding-left: var(--density-space-sm);
327
+ .icen-ai-msg--error .icen-ai-msg-body {
328
+ border-inline-start: 2px solid var(--icen-token-error);
329
+ padding-inline-start: var(--icen-density-space-sm);
329
330
  }
330
- .ai-msg-error-text {
331
+ .icen-ai-msg-error-text {
331
332
  display: block;
332
- margin-top: var(--density-space-xs);
333
- color: var(--token-error);
334
- font-size: var(--density-font-size-xs);
333
+ margin-top: var(--icen-density-space-xs);
334
+ color: var(--icen-token-error);
335
+ font-size: var(--icen-density-font-size-xs);
335
336
  }
336
337
 
337
338
  /* ══════════════ ai-reasoning ══════════════ */
338
339
 
339
- .ai-reasoning {
340
- margin: var(--density-space-xs) 0;
341
- padding-left: var(--density-space-md);
342
- border-left: 2px solid var(--token-line-soft);
340
+ .icen-ai-reasoning {
341
+ margin: var(--icen-density-space-xs) 0;
342
+ padding-inline-start: var(--icen-density-space-md);
343
+ border-inline-start: 2px solid var(--icen-token-line-soft);
343
344
  }
344
345
 
345
- .ai-reasoning-head {
346
+ .icen-ai-reasoning-head {
346
347
  display: flex;
347
348
  align-items: center;
348
- gap: var(--density-space-sm);
349
+ gap: var(--icen-density-space-sm);
349
350
  width: 100%;
350
- padding: var(--density-space-xs) 0;
351
+ padding: var(--icen-density-space-xs) 0;
351
352
  border: 0;
352
353
  background: none;
353
- color: var(--token-text-muted);
354
- font-family: var(--font-mono);
355
- font-size: var(--density-font-size-sm);
354
+ color: var(--icen-token-text-muted);
355
+ font-family: var(--icen-font-mono);
356
+ font-size: var(--icen-density-font-size-sm);
356
357
  letter-spacing: 0.02em;
357
358
  cursor: pointer;
358
- text-align: left;
359
+ text-align: start;
359
360
  }
360
- .ai-reasoning-head:hover {
361
- color: var(--token-text);
361
+ .icen-ai-reasoning-head:hover {
362
+ color: var(--icen-token-text);
362
363
  }
363
- .ai-reasoning-head:focus-visible {
364
+ .icen-ai-reasoning-head:focus-visible {
364
365
  outline: none;
365
366
  box-shadow: var(--icen-ring);
366
- border-radius: var(--radius-xs);
367
+ border-radius: var(--icen-radius-xs);
367
368
  }
368
369
 
369
- /* 折叠指示 chevron(CSS 三角,展开时旋转) */
370
- .ai-reasoning-head::before {
370
+ /* 折叠指示(共享 chevron-right mask;展开旋转 90° 朝下) */
371
+ .icen-ai-reasoning-head::before {
371
372
  content: '';
372
373
  flex-shrink: 0;
373
- width: 6px;
374
- height: 6px;
375
- border-right: 1.5px solid currentColor;
376
- border-bottom: 1.5px solid currentColor;
377
- transform: rotate(-45deg);
374
+ inline-size: 12px;
375
+ block-size: 12px;
376
+ background: currentColor;
377
+ mask: var(--icen-token-icon-chevron-right) center / contain no-repeat;
378
378
  transition: transform var(--icen-tx-fast);
379
379
  }
380
- .ai-reasoning:has(.ai-reasoning-head[aria-expanded='true']) .ai-reasoning-head::before {
381
- transform: rotate(45deg);
380
+ .icen-ai-reasoning:has(.icen-ai-reasoning-head[aria-expanded='true']) .icen-ai-reasoning-head::before {
381
+ transform: rotate(90deg);
382
382
  }
383
383
 
384
- .ai-reasoning-label {
384
+ .icen-ai-reasoning-label {
385
385
  overflow: hidden;
386
386
  text-overflow: ellipsis;
387
387
  white-space: nowrap;
388
388
  }
389
389
 
390
- .ai-reasoning-time {
391
- margin-left: auto;
392
- font-size: var(--density-font-size-2xs);
393
- color: var(--token-text-faint);
390
+ .icen-ai-reasoning-time {
391
+ margin-inline-start: auto;
392
+ font-size: var(--icen-density-font-size-2xs);
393
+ color: var(--icen-token-text-faint);
394
394
  font-variant-numeric: tabular-nums;
395
395
  }
396
396
 
397
397
  /* 流式中:耗时位换成 shimmer「正在思考…」(时长走局部变量) */
398
- .ai-reasoning.is-streaming .ai-reasoning-time {
398
+ .icen-ai-reasoning.is-streaming .icen-ai-reasoning-time {
399
399
  display: none;
400
400
  }
401
- .ai-reasoning.is-streaming .ai-reasoning-head::after {
401
+ .icen-ai-reasoning.is-streaming .icen-ai-reasoning-head::after {
402
402
  content: '正在思考…';
403
- margin-left: auto;
404
- font-size: var(--density-font-size-2xs);
403
+ margin-inline-start: auto;
404
+ font-size: var(--icen-density-font-size-2xs);
405
405
  background: linear-gradient(
406
406
  90deg,
407
- var(--token-text-faint) 25%,
408
- var(--token-text) 50%,
409
- var(--token-text-faint) 75%
407
+ var(--icen-token-text-faint) 25%,
408
+ var(--icen-token-text) 50%,
409
+ var(--icen-token-text-faint) 75%
410
410
  );
411
411
  background-size: 200% 100%;
412
412
  -webkit-background-clip: text;
@@ -416,77 +416,85 @@
416
416
  animation: ai-shimmer var(--ai-shimmer-duration, 1.6s) linear infinite;
417
417
  }
418
418
 
419
- .ai-reasoning-body {
420
- padding: var(--density-space-xs) 0 var(--density-space-sm);
421
- color: var(--token-text-muted);
422
- font-size: var(--density-font-size-sm);
419
+ .icen-ai-reasoning-body {
420
+ padding: var(--icen-density-space-xs) 0 var(--icen-density-space-sm);
421
+ color: var(--icen-token-text-muted);
422
+ font-size: var(--icen-density-font-size-sm);
423
423
  line-height: 1.6;
424
424
  white-space: pre-wrap;
425
425
  word-break: break-word;
426
426
  }
427
- .ai-reasoning-body[hidden] {
427
+ .icen-ai-reasoning-body[hidden] {
428
428
  display: none;
429
429
  }
430
430
 
431
431
  /* ══════════════ ai-composer ══════════════ */
432
432
 
433
- .ai-composer {
433
+ .icen-ai-composer {
434
434
  display: flex;
435
435
  flex-direction: column;
436
- gap: var(--density-space-xs);
437
- padding: var(--density-space-sm);
438
- border: 1px solid var(--token-line-soft);
439
- border-radius: var(--radius-lg);
440
- background: var(--token-surface);
441
- box-shadow: var(--token-shadow-card);
442
- }
443
- .ai-composer:focus-within {
444
- border-color: var(--icen-hover-border);
436
+ gap: var(--icen-density-space-xs);
437
+ min-inline-size: 0;
438
+ padding: var(--icen-density-space-sm);
439
+ border: 1px solid var(--icen-token-line);
440
+ border-radius: var(--icen-radius-lg);
441
+ background: var(--icen-token-surface);
442
+ box-shadow: var(--icen-token-shadow-card);
443
+ transition: border-color var(--icen-tx-fast), box-shadow var(--icen-tx-fast);
444
+ }
445
+ .icen-ai-composer:focus-within {
446
+ border-color: var(--icen-hover-border, var(--icen-token-accent));
447
+ }
448
+ .icen-ai-composer:has(.icen-ai-composer-input:focus-visible) {
449
+ border-color: var(--icen-control-focus-border);
450
+ box-shadow: var(--icen-token-shadow-card), 0 0 0 2px color-mix(in srgb, var(--icen-token-accent) 12%, transparent);
445
451
  }
446
452
 
447
453
  /* 排队 / 引用 / 附件 chips 行 */
448
- .ai-composer-queue,
449
- .ai-composer-refs,
450
- .ai-composer-attach {
454
+ .icen-ai-composer-queue,
455
+ .icen-ai-composer-refs,
456
+ .icen-ai-composer-attach {
451
457
  display: flex;
452
458
  flex-wrap: wrap;
453
- gap: var(--density-space-xs);
459
+ gap: var(--icen-density-space-xs);
454
460
  }
455
- .ai-composer-queue[hidden],
456
- .ai-composer-refs[hidden],
457
- .ai-composer-attach[hidden] {
461
+ .icen-ai-composer-queue[hidden],
462
+ .icen-ai-composer-refs[hidden],
463
+ .icen-ai-composer-attach[hidden] {
458
464
  display: none;
459
465
  }
460
466
 
461
- .ai-composer-chip {
467
+ .icen-ai-composer-chip {
462
468
  display: inline-flex;
463
469
  align-items: center;
464
470
  gap: 4px;
465
- max-width: 240px;
466
- padding: 2px var(--density-space-xs);
467
- border: 1px solid var(--token-line-soft);
468
- border-radius: var(--radius-full);
469
- background: var(--token-surface-strong);
470
- color: var(--token-text-muted);
471
- font-size: var(--density-font-size-xs);
471
+ max-inline-size: min(100%, 280px);
472
+ min-block-size: 30px;
473
+ padding: 2px 4px 2px 6px; /* guard:allow-physical symmetric chip padding */
474
+ border: 1px solid var(--icen-token-line-soft);
475
+ border-radius: var(--icen-radius-sm);
476
+ background: var(--icen-token-fill-1);
477
+ color: var(--icen-token-text);
478
+ font-size: var(--icen-density-font-size-xs);
472
479
  line-height: 1.4;
473
480
  }
474
- .ai-composer-chip-text {
481
+ .icen-ai-composer-chip-text {
475
482
  overflow: hidden;
476
483
  text-overflow: ellipsis;
477
484
  white-space: nowrap;
478
485
  }
479
- .ai-composer-chip-remove {
486
+ .icen-ai-composer-chip-remove {
480
487
  display: inline-flex;
481
488
  align-items: center;
482
489
  justify-content: center;
483
- width: 14px;
484
- height: 14px;
490
+ inline-size: 24px;
491
+ block-size: 24px;
492
+ flex-shrink: 0;
485
493
  padding: 0;
486
494
  border: 0;
487
- border-radius: var(--radius-full);
495
+ border-radius: var(--icen-radius-sm);
488
496
  background: transparent;
489
- color: var(--token-text-faint);
497
+ color: var(--icen-token-text-faint);
490
498
  font-size: 12px;
491
499
  line-height: 1;
492
500
  cursor: pointer;
@@ -494,371 +502,352 @@
494
502
  color var(--icen-tx-fast),
495
503
  background-color var(--icen-tx-fast);
496
504
  }
497
- .ai-composer-chip-remove:hover {
498
- color: var(--token-error);
499
- background: var(--token-error-muted);
505
+ .icen-ai-composer-chip-remove:hover {
506
+ color: var(--icen-token-error);
507
+ background: var(--icen-token-error-muted);
500
508
  }
501
- .ai-composer-chip-remove:focus-visible {
509
+ .icen-ai-composer-chip-remove:focus-visible {
502
510
  outline: none;
503
511
  box-shadow: var(--icen-ring);
504
512
  }
505
513
 
506
- /* 输入框(.control 基元提供 hover/focus 边框与光晕);flex-wrap 让工具条独占下一行 */
507
- .ai-composer-box {
514
+ /* 输入框(.icen-control 基元提供 hover/focus 边框与光晕);flex-wrap 让工具条独占下一行 */
515
+ .icen-ai-composer-box {
516
+ /* The outer composer owns text focus. */
517
+ --icen-control-focus-shadow: none;
518
+ --icen-control-focus-border: transparent;
508
519
  display: flex;
509
520
  flex-wrap: wrap;
510
521
  align-items: flex-end;
511
- gap: var(--density-space-sm);
512
- padding: var(--density-space-xs) var(--density-space-sm);
513
- border: 1px solid var(--token-line-soft);
514
- border-radius: var(--radius-md);
515
- background: var(--token-panel);
516
- box-shadow: var(--token-shadow-inset);
522
+ gap: var(--icen-density-space-sm);
523
+ padding: var(--icen-density-space-xs) var(--icen-density-space-sm);
524
+ min-inline-size: 0;
525
+ border: 0;
526
+ border-radius: var(--icen-radius-md);
527
+ background: transparent;
528
+ box-shadow: none;
517
529
  }
518
530
 
519
- .ai-composer-input {
531
+ .icen-ai-composer-input {
520
532
  flex: 1;
521
- min-width: 0;
522
- padding: var(--density-space-xs) 0;
533
+ min-inline-size: 0;
534
+ min-block-size: 64px;
535
+ padding: var(--icen-density-space-xs) 0;
523
536
  border: 0;
524
537
  outline: none;
525
538
  background: transparent;
526
539
  resize: none;
527
540
  font-family: inherit;
528
- font-size: var(--density-font-size-md);
541
+ font-size: var(--icen-density-font-size-md);
529
542
  line-height: 1.5;
530
543
  max-height: 12em;
531
544
  overflow-y: auto;
532
545
  }
533
546
 
534
- /* v1 旧结构按钮行(无 toolbar 配置时保留);v2 中按钮被移入工具条后此容器由 JS 移除 */
535
- .ai-composer-actions {
536
- display: flex;
537
- align-items: center;
538
- gap: var(--density-space-xs);
539
- flex-shrink: 0;
540
- }
547
+ /* ── 工具条(composer-box 内底部,业界主流形态)── */
541
548
 
542
- /* ── v2 工具条(composer-box 内底部,业界主流形态)── */
543
-
544
- .ai-composer-toolbar {
549
+ .icen-ai-composer-toolbar {
545
550
  flex: 0 0 100%;
546
551
  display: flex;
547
552
  align-items: center;
548
- gap: var(--density-space-xs);
549
- padding-top: var(--density-space-xs);
550
- border-top: 1px solid var(--token-line-soft);
553
+ gap: var(--icen-density-space-xs);
554
+ padding-top: var(--icen-density-space-xs);
555
+ min-inline-size: 0;
556
+ flex-wrap: wrap;
557
+ border-top: 0;
551
558
  }
552
- .ai-composer-toolbar[hidden] {
559
+ .icen-ai-composer-toolbar[hidden] {
553
560
  display: none;
554
561
  }
555
562
 
556
- .ai-composer-spacer {
563
+ .icen-ai-composer-spacer {
557
564
  flex: 1;
558
565
  }
559
566
 
560
567
  /* 模型切换钮:provider 图标/首字母章 + 模型名 + chevron */
561
- .ai-composer-model {
568
+ .icen-ai-composer-model {
562
569
  display: inline-flex;
563
570
  align-items: center;
564
571
  gap: 4px;
565
572
  max-width: 180px;
566
573
  height: 28px;
567
- padding: 0 var(--density-space-xs);
574
+ padding: 0 var(--icen-density-space-xs);
568
575
  border: 1px solid transparent;
569
- border-radius: var(--radius-sm);
576
+ border-radius: var(--icen-radius-sm);
570
577
  background: transparent;
571
- color: var(--token-text-muted);
572
- font-size: var(--density-font-size-xs);
578
+ color: var(--icen-token-text-muted);
579
+ font-size: var(--icen-density-font-size-xs);
573
580
  cursor: pointer;
574
581
  transition:
575
582
  color var(--icen-tx-fast),
576
583
  background-color var(--icen-tx-fast);
577
584
  }
578
- .ai-composer-model:hover {
579
- color: var(--token-text);
580
- background: var(--token-fill-2);
585
+ .icen-ai-composer-model:hover {
586
+ color: var(--icen-token-text);
587
+ background: var(--icen-token-fill-2);
581
588
  }
582
- .ai-composer-model:focus-visible {
589
+ .icen-ai-composer-model:focus-visible {
583
590
  outline: none;
584
591
  box-shadow: var(--icen-ring);
585
592
  }
586
- .ai-composer-model-icon,
587
- .ai-composer-model-provider-icon {
593
+ .icen-ai-composer-model-icon,
594
+ .icen-ai-composer-model-provider-icon {
588
595
  display: inline-flex;
589
596
  align-items: center;
590
597
  justify-content: center;
591
598
  flex-shrink: 0;
592
599
  }
593
- .ai-composer-model-provider-icon svg {
600
+ .icen-ai-composer-model-provider-icon svg {
594
601
  width: 14px;
595
602
  height: 14px;
596
603
  }
597
- .ai-composer-model-name {
604
+ .icen-ai-composer-model-name {
598
605
  overflow: hidden;
599
606
  text-overflow: ellipsis;
600
607
  white-space: nowrap;
601
608
  }
602
- .ai-composer-model-chevron {
609
+ .icen-ai-composer-model-chevron {
603
610
  display: inline-flex;
604
611
  align-items: center;
605
612
  justify-content: center;
606
613
  flex-shrink: 0;
607
- color: var(--token-text-faint);
614
+ color: var(--icen-token-text-faint);
608
615
  transition: transform var(--icen-tx-fast);
609
616
  }
610
- .ai-composer-model-chevron svg {
617
+ .icen-ai-composer-model-chevron svg {
611
618
  width: 12px;
612
619
  height: 12px;
613
620
  }
614
- .ai-composer-model[aria-expanded='true'] .ai-composer-model-chevron {
621
+ .icen-ai-composer-model[aria-expanded='true'] .icen-ai-composer-model-chevron {
615
622
  transform: rotate(180deg);
616
623
  }
617
624
 
618
625
  /* provider 图标缺失时的首字母圆形章(token 色) */
619
- .ai-composer-model-badge {
626
+ .icen-ai-composer-model-badge {
620
627
  display: inline-flex;
621
628
  align-items: center;
622
629
  justify-content: center;
623
630
  width: 16px;
624
631
  height: 16px;
625
- border-radius: var(--radius-full);
626
- background: color-mix(in srgb, var(--token-accent) 15%, transparent);
627
- color: var(--token-accent);
632
+ border-radius: var(--icen-radius-full);
633
+ background: color-mix(in srgb, var(--icen-token-accent) 15%, transparent);
634
+ color: var(--icen-token-accent);
628
635
  font-size: 10px;
629
636
  font-weight: 600;
630
637
  line-height: 1;
631
638
  user-select: none;
632
639
  }
633
- .ai-composer-model-icon .ai-composer-model-badge {
640
+ .icen-ai-composer-model-icon .icen-ai-composer-model-badge {
634
641
  width: 14px;
635
642
  height: 14px;
636
643
  font-size: 9px;
637
644
  }
638
645
 
639
- /* 用量环挂载点(环本体 .ai-usage-ring 在 ai-panel.css) */
640
- .ai-composer-usage {
646
+ /* 用量环挂载点(环本体 .icen-ai-usage-ring 在 ai-panel.css) */
647
+ .icen-ai-composer-usage {
641
648
  display: inline-flex;
642
649
  align-items: center;
643
650
  flex-shrink: 0;
644
651
  }
645
- .ai-composer-usage:empty {
652
+ .icen-ai-composer-usage:empty {
646
653
  display: none;
647
654
  }
648
655
 
649
656
  /* ── v2 弹层(portal body,模型/命令/引用三模式共用基座;定位 inline 由 behavior 写入)── */
650
657
 
651
- .ai-composer-popup {
658
+ .icen-ai-composer-popup {
652
659
  position: fixed;
653
- z-index: var(--z-popover);
660
+ z-index: var(--icen-z-popover);
654
661
  display: flex;
655
662
  flex-direction: column;
656
- padding: var(--density-space-2xs);
657
- border: 1px solid var(--token-line-soft);
658
- border-radius: var(--radius-md);
659
- background: var(--token-card-strong);
660
- box-shadow: var(--token-shadow-popover, var(--token-shadow-card));
663
+ padding: 6px;
664
+ border: 1px solid var(--icen-token-line);
665
+ border-radius: var(--icen-radius-lg);
666
+ background: var(--icen-token-card-strong);
667
+ box-shadow: var(--icen-token-shadow-popover, var(--icen-token-shadow-card));
661
668
  overflow: hidden;
662
- animation: icen-pop-in var(--ai-composer-popup-enter-duration, var(--duration-normal)) var(--ease-out);
669
+ animation: icen-pop-in var(--ai-composer-popup-enter-duration, var(--icen-duration-normal)) var(--icen-ease-out);
663
670
  }
664
671
 
665
672
  /* 搜索框(模型/引用过滤) */
666
- .ai-composer-popup-search {
673
+ .icen-ai-composer-popup-search {
674
+ display: flex;
675
+ align-items: center;
676
+ gap: 8px;
667
677
  flex-shrink: 0;
668
- padding: var(--density-space-2xs);
669
- border-bottom: 1px solid var(--token-line-soft);
670
- }
671
- .ai-composer-popup-search-input {
672
- width: 100%;
673
- padding: var(--density-space-2xs) var(--density-space-xs);
674
- border: 1px solid var(--token-line-soft);
675
- border-radius: var(--radius-sm);
676
- background: var(--token-panel);
677
- color: var(--token-text);
678
- font-size: var(--density-font-size-sm);
679
- outline: none;
680
- transition: border-color var(--icen-tx-fast);
678
+ padding: 4px 8px 8px;
679
+ color: var(--icen-token-text-muted);
680
+ border-bottom: 1px solid var(--icen-token-line-soft);
681
681
  }
682
- .ai-composer-popup-search-input:focus {
683
- border-color: var(--token-accent);
684
- }
685
- .ai-composer-popup-search-input::placeholder {
686
- color: var(--token-text-faint);
682
+ .icen-ai-composer-popup-search-input { min-inline-size: 0; }
683
+
684
+ .icen-ai-composer-popup-search-input::placeholder {
685
+ color: var(--icen-token-text-faint);
687
686
  }
688
687
 
689
688
  /* 列表(max-height inline 由 behavior 按 computePopoverLayout 写入) */
690
- .ai-composer-popup-list {
689
+ .icen-ai-composer-popup-list {
691
690
  flex: 1;
692
691
  min-height: 0;
693
692
  overflow-y: auto;
694
693
  overscroll-behavior: contain;
695
- padding: var(--density-space-2xs);
694
+ padding: var(--icen-density-space-2xs);
696
695
  }
697
696
 
698
697
  /* 分组(provider / ref kind) */
699
- .ai-composer-popup-group[hidden] {
698
+ .icen-ai-composer-popup-group[hidden] {
700
699
  display: none;
701
700
  }
702
- .ai-composer-popup-group-label {
701
+ .icen-ai-composer-popup-group-label {
703
702
  display: flex;
704
703
  align-items: center;
705
704
  gap: 4px;
706
- padding: var(--density-space-xs) var(--density-space-xs) var(--density-space-2xs);
707
- font-size: var(--density-font-size-2xs);
708
- color: var(--token-text-faint);
705
+ padding: var(--icen-density-space-xs) var(--icen-density-space-xs) var(--icen-density-space-2xs);
706
+ font-size: var(--icen-density-font-size-2xs);
707
+ color: var(--icen-token-text-faint);
709
708
  letter-spacing: 0.02em;
710
709
  }
711
- .ai-composer-popup-group-icon {
710
+ .icen-ai-composer-popup-group-icon {
712
711
  display: inline-flex;
713
712
  align-items: center;
714
713
  justify-content: center;
715
714
  flex-shrink: 0;
716
- color: var(--token-text-muted);
715
+ color: var(--icen-token-text-muted);
717
716
  }
718
- .ai-composer-popup-group-icon svg {
717
+ .icen-ai-composer-popup-group-icon svg {
719
718
  width: 12px;
720
719
  height: 12px;
721
720
  }
722
- .ai-composer-popup-group-icon .ai-composer-model-badge {
721
+ .icen-ai-composer-popup-group-icon .icen-ai-composer-model-badge {
723
722
  width: 12px;
724
723
  height: 12px;
725
724
  font-size: 8px;
726
725
  }
727
726
 
728
727
  /* 选项行(label + meta + check) */
729
- .ai-composer-popup-option {
728
+ .icen-ai-composer-popup-option {
730
729
  display: flex;
731
730
  align-items: center;
732
- gap: var(--density-space-xs);
731
+ gap: var(--icen-density-space-xs);
733
732
  width: 100%;
734
- padding: var(--density-space-xs);
733
+ min-block-size: 48px;
734
+ min-inline-size: 0;
735
+ padding: 8px;
735
736
  border: 0;
736
- border-radius: var(--radius-sm);
737
+ border-radius: var(--icen-radius-md);
737
738
  background: transparent;
738
- color: var(--token-text);
739
- font-size: var(--density-font-size-sm);
740
- text-align: left;
739
+ color: var(--icen-token-text);
740
+ font-size: var(--icen-density-font-size-sm);
741
+ text-align: start;
741
742
  cursor: pointer;
742
743
  transition: background-color var(--icen-tx-fast);
743
744
  }
744
- .ai-composer-popup-option:hover {
745
- background: var(--token-fill-2);
745
+ .icen-ai-composer-popup-option:hover {
746
+ background: var(--icen-token-fill-2);
746
747
  }
747
- .ai-composer-popup-option.is-focused {
748
- background: var(--token-fill-2);
748
+ .icen-ai-composer-popup-option.is-focused {
749
+ background: var(--icen-token-fill-2);
749
750
  }
750
- .ai-composer-popup-option:focus-visible {
751
+ .icen-ai-composer-popup-option:focus-visible {
751
752
  outline: none;
752
753
  box-shadow: var(--icen-ring);
753
754
  }
754
- .ai-composer-popup-option-icon {
755
+ .icen-ai-composer-popup-option-icon {
755
756
  display: inline-flex;
756
757
  align-items: center;
757
758
  justify-content: center;
758
759
  flex-shrink: 0;
759
- color: var(--token-text-muted);
760
+ color: var(--icen-token-text-muted);
760
761
  }
761
- .ai-composer-popup-option-icon svg {
762
+ .icen-ai-composer-popup-option-icon svg {
762
763
  width: 14px;
763
764
  height: 14px;
764
765
  }
765
- .ai-composer-popup-option-icon .ai-composer-model-badge {
766
+ .icen-ai-composer-popup-option-icon .icen-ai-composer-model-badge {
766
767
  width: 14px;
767
768
  height: 14px;
768
769
  font-size: 9px;
769
770
  }
770
- .ai-composer-popup-option-label {
771
+ .icen-ai-composer-popup-option-label {
771
772
  overflow: hidden;
772
773
  text-overflow: ellipsis;
773
774
  white-space: nowrap;
774
775
  }
775
- .ai-composer-popup-option-sub {
776
- margin-left: 6px;
777
- font-size: var(--density-font-size-2xs);
778
- color: var(--token-text-faint);
776
+ .icen-ai-composer-popup-option-sub {
777
+ display: block;
778
+ margin-block-start: 2px;
779
+ font-size: var(--icen-density-font-size-xs);
780
+ color: var(--icen-token-text-muted);
779
781
  }
780
- .ai-composer-popup-option-meta {
781
- margin-left: auto;
782
+ .icen-ai-composer-popup-option-meta {
783
+ margin-inline-start: auto;
782
784
  flex-shrink: 0;
783
- font-family: var(--font-mono);
784
- font-size: var(--density-font-size-2xs);
785
- color: var(--token-text-faint);
785
+ font-family: var(--icen-font-mono);
786
+ font-size: var(--icen-density-font-size-2xs);
787
+ color: var(--icen-token-text-faint);
786
788
  font-variant-numeric: tabular-nums;
787
789
  }
788
- .ai-composer-popup-option-check {
789
- display: none;
790
- flex-shrink: 0;
791
- color: var(--token-accent);
792
- }
793
- .ai-composer-popup-option-check svg {
794
- width: 12px;
795
- height: 12px;
796
- }
797
- .ai-composer-popup-option[aria-selected='true'] .ai-composer-popup-option-check {
798
- display: inline-flex;
799
- }
800
790
 
801
791
  /* 命令行:/name <argsHint> + 描述 */
802
- .ai-composer-popup-cmd {
803
- flex-direction: column;
804
- align-items: flex-start;
805
- gap: 1px;
792
+ .icen-ai-composer-popup-cmd {
793
+ flex-direction: row;
794
+ align-items: center;
806
795
  }
807
- .ai-composer-popup-cmd-line {
796
+ .icen-ai-composer-popup-cmd-line {
808
797
  display: flex;
809
798
  align-items: baseline;
810
799
  gap: 6px;
811
800
  max-width: 100%;
812
801
  }
813
- .ai-composer-popup-cmd-name {
814
- font-family: var(--font-mono);
815
- color: var(--token-accent);
802
+ .icen-ai-composer-popup-cmd-name {
803
+ font-family: var(--icen-font-mono);
804
+ color: var(--icen-token-text-muted);
816
805
  }
817
- .ai-composer-popup-cmd-args {
818
- font-family: var(--font-mono);
819
- font-size: var(--density-font-size-2xs);
820
- color: var(--token-text-faint);
806
+ .icen-ai-composer-popup-cmd-args {
807
+ font-family: var(--icen-font-mono);
808
+ font-size: var(--icen-density-font-size-2xs);
809
+ color: var(--icen-token-text-faint);
821
810
  }
822
- .ai-composer-popup-cmd-desc {
823
- font-size: var(--density-font-size-2xs);
824
- color: var(--token-text-muted);
811
+ .icen-ai-composer-popup-cmd-desc {
812
+ font-size: var(--icen-density-font-size-2xs);
813
+ color: var(--icen-token-text-muted);
825
814
  }
826
815
 
827
816
  /* 空态 */
828
- .ai-composer-popup-empty {
817
+ .icen-ai-composer-popup-empty {
829
818
  flex-shrink: 0;
830
- padding: var(--density-space-md);
819
+ padding: var(--icen-density-space-md);
831
820
  text-align: center;
832
- font-size: var(--density-font-size-sm);
833
- color: var(--token-text-faint);
821
+ font-size: var(--icen-density-font-size-sm);
822
+ color: var(--icen-token-text-faint);
834
823
  }
835
- .ai-composer-popup-empty[hidden] {
824
+ .icen-ai-composer-popup-empty[hidden] {
836
825
  display: none;
837
826
  }
838
827
 
839
828
  /* 底部提示(模型弹层:切换模型会使 prompt 缓存失效;cacheRead 占比高时 warning 色) */
840
- .ai-composer-popup-foot {
829
+ .icen-ai-composer-popup-foot {
841
830
  flex-shrink: 0;
842
831
  display: flex;
843
832
  align-items: center;
844
833
  gap: 4px;
845
- padding: var(--density-space-xs);
846
- border-top: 1px solid var(--token-line-soft);
847
- font-size: var(--density-font-size-2xs);
848
- color: var(--token-text-faint);
834
+ padding: var(--icen-density-space-xs);
835
+ border-top: 1px solid var(--icen-token-line-soft);
836
+ font-size: var(--icen-density-font-size-2xs);
837
+ color: var(--icen-token-text-faint);
849
838
  }
850
- .ai-composer-popup-foot svg {
839
+ .icen-ai-composer-popup-foot svg {
851
840
  width: 12px;
852
841
  height: 12px;
853
842
  flex-shrink: 0;
854
843
  }
855
- .ai-composer-popup-foot.is-warn {
856
- color: var(--token-warning);
844
+ .icen-ai-composer-popup-foot.is-warn {
845
+ color: var(--icen-token-warning);
857
846
  }
858
847
 
859
- /* ── 工具条按钮统一 28px 方形、svg 14px 居中(v1 旧结构按钮同样收敛)── */
848
+ /* ── 工具条按钮统一 28px 方形、svg 14px 居中 ── */
860
849
 
861
- .ai-composer-btn {
850
+ .icen-ai-composer-btn {
862
851
  display: inline-flex;
863
852
  align-items: center;
864
853
  justify-content: center;
@@ -866,29 +855,29 @@
866
855
  height: 28px;
867
856
  padding: 0;
868
857
  border: 1px solid transparent;
869
- border-radius: var(--radius-sm);
858
+ border-radius: var(--icen-radius-sm);
870
859
  background: transparent;
871
- color: var(--token-text-muted);
860
+ color: var(--icen-token-text-muted);
872
861
  cursor: pointer;
873
862
  transition:
874
863
  color var(--icen-tx-fast),
875
864
  background-color var(--icen-tx-fast);
876
865
  }
877
- .ai-composer-btn:hover {
878
- color: var(--token-text);
879
- background: var(--token-fill-2);
866
+ .icen-ai-composer-btn:hover {
867
+ color: var(--icen-token-text);
868
+ background: var(--icen-token-fill-2);
880
869
  }
881
- .ai-composer-btn:focus-visible {
870
+ .icen-ai-composer-btn:focus-visible {
882
871
  outline: none;
883
872
  box-shadow: var(--icen-ring);
884
873
  }
885
- .ai-composer-btn svg {
874
+ .icen-ai-composer-btn svg {
886
875
  width: 14px;
887
876
  height: 14px;
888
877
  }
889
878
 
890
879
  /* 发送钮:accent 实底;运行态 .is-stop 变停止钮(中性底 + error 色方标,停语气但不整钮铺红) */
891
- .ai-composer-send {
880
+ .icen-ai-composer-send {
892
881
  display: inline-flex;
893
882
  align-items: center;
894
883
  justify-content: center;
@@ -896,63 +885,63 @@
896
885
  height: 28px;
897
886
  padding: 0;
898
887
  border: 1px solid transparent;
899
- border-radius: var(--radius-sm);
900
- background: var(--token-accent);
901
- color: var(--token-on-accent);
888
+ border-radius: var(--icen-radius-sm);
889
+ background: var(--icen-token-accent-strong);
890
+ color: var(--icen-token-on-accent);
902
891
  cursor: pointer;
903
892
  transition:
904
893
  background-color var(--icen-tx-fast),
905
894
  color var(--icen-tx-fast),
906
895
  border-color var(--icen-tx-fast);
907
896
  }
908
- .ai-composer-send:hover {
909
- background: var(--token-accent-deep, var(--token-accent));
897
+ .icen-ai-composer-send:hover {
898
+ background: var(--icen-token-accent-deep, var(--icen-token-accent));
910
899
  }
911
- .ai-composer-send:focus-visible {
900
+ .icen-ai-composer-send:focus-visible {
912
901
  outline: none;
913
902
  box-shadow: var(--icen-ring);
914
903
  }
915
- .ai-composer-send svg {
904
+ .icen-ai-composer-send svg {
916
905
  width: 14px;
917
906
  height: 14px;
918
907
  }
919
- .ai-composer-send .ai-composer-send-icon[hidden] {
908
+ .icen-ai-composer-send .icen-ai-composer-send-icon[hidden] {
920
909
  display: none;
921
910
  }
922
- .ai-composer-send.is-stop {
923
- background: var(--token-surface-strong);
924
- color: var(--token-error);
925
- border-color: color-mix(in srgb, var(--token-error) 35%, transparent);
911
+ .icen-ai-composer-send.is-stop {
912
+ background: var(--icen-token-surface-strong);
913
+ color: var(--icen-token-error);
914
+ border-color: color-mix(in srgb, var(--icen-token-error) 35%, transparent);
926
915
  }
927
- .ai-composer-send.is-stop:hover {
928
- background: var(--token-error-muted);
916
+ .icen-ai-composer-send.is-stop:hover {
917
+ background: var(--icen-token-error-muted);
929
918
  }
930
919
 
931
920
  /* 运行态:输入台整体 busy 标记(aria-busy 等价,状态机语言) */
932
- .ai-composer.is-running .ai-composer-box {
933
- border-color: color-mix(in srgb, var(--token-accent) 30%, var(--token-line-soft));
921
+ .icen-ai-composer.is-running .icen-ai-composer-box {
922
+ border-color: color-mix(in srgb, var(--icen-token-accent) 30%, var(--icen-token-line-soft));
934
923
  }
935
924
 
936
925
  /* 拖放文件高亮(粘贴/拖放附件入口,spec §11) */
937
- .ai-composer-box.is-dragover {
938
- border-color: var(--token-accent);
926
+ .icen-ai-composer-box.is-dragover {
927
+ border-color: var(--icen-token-accent);
939
928
  box-shadow: var(--icen-ring);
940
929
  }
941
930
 
942
- /* ══════════════ data-density 三档(summary 纯 CSS 降噪) ══════════════ */
931
+ /* ══════════════ data-icen-density 三档(summary 纯 CSS 降噪) ══════════════ */
943
932
 
944
933
  /* summary:隐藏 meta、默认折叠 reasoning(head 展开仍可看)、次要消息压淡 */
945
- .ai-chat[data-density='summary'] .ai-msg-meta {
934
+ .icen-ai-chat[data-icen-density='summary'] .icen-ai-msg-meta {
946
935
  display: none;
947
936
  }
948
- .ai-chat[data-density='summary'] .ai-reasoning-body {
937
+ .icen-ai-chat[data-icen-density='summary'] .icen-ai-reasoning-body {
949
938
  display: none;
950
939
  }
951
- .ai-chat[data-density='summary'] .ai-reasoning:has(.ai-reasoning-head[aria-expanded='true']) .ai-reasoning-body {
940
+ .icen-ai-chat[data-icen-density='summary'] .icen-ai-reasoning:has(.icen-ai-reasoning-head[aria-expanded='true']) .icen-ai-reasoning-body {
952
941
  display: block;
953
942
  }
954
- .ai-chat[data-density='summary'] .ai-msg--tool,
955
- .ai-chat[data-density='summary'] .ai-msg--system {
943
+ .icen-ai-chat[data-icen-density='summary'] .icen-ai-msg--tool,
944
+ .icen-ai-chat[data-icen-density='summary'] .icen-ai-msg--system {
956
945
  opacity: 0.72;
957
946
  }
958
947
 
@@ -972,39 +961,39 @@
972
961
  /* ══════════════ 动效守卫 ══════════════ */
973
962
 
974
963
  @media (prefers-reduced-motion: reduce) {
975
- .ai-msg,
976
- .ai-chat-jump,
977
- .ai-composer-popup {
964
+ .icen-ai-msg,
965
+ .icen-ai-chat-jump,
966
+ .icen-ai-composer-popup {
978
967
  animation: none;
979
968
  }
980
- .ai-chat-jump,
981
- .ai-msg-actions,
982
- .ai-composer-chip-remove,
983
- .ai-composer-btn,
984
- .ai-composer-send,
985
- .ai-composer-model,
986
- .ai-composer-model-chevron,
987
- .ai-composer-popup-option,
988
- .ai-composer-popup-search-input,
989
- .ai-reasoning-head,
990
- .ai-reasoning-head::before {
969
+ .icen-ai-chat-jump,
970
+ .icen-ai-msg-actions,
971
+ .icen-ai-composer-chip-remove,
972
+ .icen-ai-composer-btn,
973
+ .icen-ai-composer-send,
974
+ .icen-ai-composer-model,
975
+ .icen-ai-composer-model-chevron,
976
+ .icen-ai-composer-popup-option,
977
+ .icen-ai-composer-popup-search-input,
978
+ .icen-ai-reasoning-head,
979
+ .icen-ai-reasoning-head::before {
991
980
  transition: none;
992
981
  }
993
- .ai-reasoning.is-streaming .ai-reasoning-head::after {
982
+ .icen-ai-reasoning.is-streaming .icen-ai-reasoning-head::after {
994
983
  animation: none;
995
984
  background: none;
996
985
  -webkit-text-fill-color: currentColor;
997
- color: var(--token-text-faint);
986
+ color: var(--icen-token-text-faint);
998
987
  }
999
- .ai-msg-body.is-streaming::after,
1000
- .ai-reasoning-body.is-streaming::after {
988
+ .icen-ai-msg-body.is-streaming::after,
989
+ .icen-ai-reasoning-body.is-streaming::after {
1001
990
  animation: none;
1002
991
  }
1003
992
  }
1004
993
 
1005
994
  /* 触屏无 hover:消息操作常显(否则不可达) */
1006
995
  @media (pointer: coarse) {
1007
- .ai-msg-actions {
996
+ .icen-ai-msg-actions {
1008
997
  opacity: 1;
1009
998
  visibility: visible;
1010
999
  transform: none;
@@ -1012,26 +1001,425 @@
1012
1001
  }
1013
1002
 
1014
1003
  /* 实时待办 chip(setComposerTodo:业界模式——plan 状态挂输入区,不进对话流) */
1015
- .ai-composer-todo {
1004
+ .icen-ai-composer-todo {
1016
1005
  display: inline-flex;
1017
1006
  align-items: center;
1018
1007
  gap: 5px;
1019
1008
  height: 28px;
1020
1009
  padding: 0 8px;
1021
- border: 1px solid var(--token-line-soft);
1022
- border-radius: var(--radius-full);
1023
- background: var(--token-surface);
1024
- color: var(--token-text-muted);
1025
- font-family: var(--font-mono);
1026
- font-size: var(--density-font-size-2xs);
1010
+ border: 1px solid var(--icen-token-line-soft);
1011
+ border-radius: var(--icen-radius-full);
1012
+ background: var(--icen-token-surface);
1013
+ color: var(--icen-token-text-muted);
1014
+ font-family: var(--icen-font-mono);
1015
+ font-size: var(--icen-density-font-size-2xs);
1027
1016
  font-variant-numeric: tabular-nums;
1028
1017
  cursor: pointer;
1029
1018
  transition: color var(--icen-tx-fast), border-color var(--icen-tx-fast);
1030
1019
  }
1031
- .ai-composer-todo svg { width: 13px; height: 13px; color: var(--token-accent); }
1032
- .ai-composer-todo:hover { border-color: var(--icen-hover-border, var(--token-line)); color: var(--token-text); }
1033
- .ai-composer-todo:focus-visible { outline: none; box-shadow: var(--icen-ring); }
1034
- .ai-composer-todo.is-done svg { color: var(--token-success); }
1035
- .ai-composer-todo.is-error svg { color: var(--token-warning); }
1036
- .ai-composer-todo-pop { min-width: 240px; max-width: 320px; }
1037
- .ai-composer-todo-pop .ai-todo { padding: 0; }
1020
+ .icen-ai-composer-todo svg { width: 13px; height: 13px; color: var(--icen-token-accent); }
1021
+ .icen-ai-composer-todo:hover { border-color: var(--icen-hover-border, var(--icen-token-line)); color: var(--icen-token-text); }
1022
+ .icen-ai-composer-todo:focus-visible { outline: none; box-shadow: var(--icen-ring); }
1023
+ .icen-ai-composer-todo.is-done svg { color: var(--icen-token-success); }
1024
+ .icen-ai-composer-todo.is-error svg { color: var(--icen-token-warning); }
1025
+ .icen-ai-composer-todo-pop { min-width: 240px; max-width: 320px; }
1026
+ .icen-ai-composer-todo-pop .icen-ai-todo { padding: 0; }
1027
+
1028
+ /* ══════════════ ai-threads · 会话列表侧栏(§5.27,behaviors/ai-threads.ts) ══════════════ */
1029
+
1030
+ /*
1031
+ * <div class="icen-ai-threads"> ← 240px 侧栏形态(--ai-threads-width 可调)
1032
+ * <div class="icen-ai-threads-group" data-icen-group="今天" [.is-collapsed]>
1033
+ * <button class="icen-ai-threads-group-head" aria-expanded="true">今天</button>
1034
+ * <div class="icen-ai-threads-group-list">
1035
+ * <div class="icen-ai-thread [.is-active|.is-archived]" role="button" tabindex="0" data-icen-key="…">
1036
+ * <span class="icen-ai-thread-icon">…svg…</span>
1037
+ * <span class="icen-ai-thread-label">…</span>
1038
+ * <button class="icen-ai-thread-action">···</button> ← 动作菜单挂载点(宿主实现)
1039
+ * </div>…
1040
+ * </div>
1041
+ * </div>… ← 「已归档」组由 behavior 沉底
1042
+ * </div>
1043
+ * .is-active:左 2px accent;.is-archived:降透明;组头 11px faint。
1044
+ */
1045
+
1046
+ .icen-ai-threads {
1047
+ display: flex;
1048
+ flex-direction: column;
1049
+ gap: var(--icen-density-space-xs);
1050
+ width: var(--ai-threads-width, 240px);
1051
+ min-width: 0;
1052
+ align-self: stretch; /* 宽度自稳定:宿主 flex/grid 居中时不 shrink-wrap */
1053
+ font-size: var(--icen-density-font-size-sm);
1054
+ }
1055
+
1056
+ .icen-ai-threads-group {
1057
+ display: flex;
1058
+ flex-direction: column;
1059
+ gap: 2px;
1060
+ min-width: 0;
1061
+ }
1062
+
1063
+ /* 组头:11px faint 小标,可折叠(aria-expanded 驱动 CSS 三角,与 .icen-ai-reasoning-head 同款) */
1064
+ .icen-ai-threads-group-head {
1065
+ display: flex;
1066
+ align-items: center;
1067
+ gap: 4px;
1068
+ padding: var(--icen-density-space-xs) 2px;
1069
+ border: 0;
1070
+ background: none;
1071
+ font-size: 11px;
1072
+ font-weight: 500;
1073
+ color: var(--icen-token-text-faint);
1074
+ letter-spacing: 0.02em;
1075
+ text-align: start;
1076
+ cursor: pointer;
1077
+ transition: color var(--icen-tx-fast);
1078
+ }
1079
+ .icen-ai-threads-group-head:hover {
1080
+ color: var(--icen-token-text-muted);
1081
+ }
1082
+ .icen-ai-threads-group-head:focus-visible {
1083
+ outline: none;
1084
+ box-shadow: var(--icen-ring);
1085
+ border-radius: var(--icen-radius-xs);
1086
+ }
1087
+ .icen-ai-threads-group-head::before {
1088
+ content: '';
1089
+ flex-shrink: 0;
1090
+ inline-size: 10px;
1091
+ block-size: 10px;
1092
+ background: currentColor;
1093
+ mask: var(--icen-token-icon-chevron-right) center / contain no-repeat;
1094
+ transition: transform var(--icen-tx-fast);
1095
+ }
1096
+ .icen-ai-threads-group-head[aria-expanded='true']::before {
1097
+ transform: rotate(90deg);
1098
+ }
1099
+ .icen-ai-threads-group.is-collapsed .icen-ai-threads-group-list {
1100
+ display: none;
1101
+ }
1102
+
1103
+ .icen-ai-threads-group-list {
1104
+ display: flex;
1105
+ flex-direction: column;
1106
+ gap: 1px;
1107
+ min-width: 0;
1108
+ }
1109
+
1110
+ /* 会话行:中性容器(激活起始缘 2px accent 线);交互 affordance 归 .icen-ai-thread-main 真按钮 */
1111
+ .icen-ai-thread {
1112
+ position: relative;
1113
+ display: flex;
1114
+ align-items: center;
1115
+ gap: var(--icen-density-space-xs);
1116
+ min-inline-size: 0;
1117
+ border-inline-start: 2px solid transparent;
1118
+ border-radius: var(--icen-radius-xs);
1119
+ background: transparent;
1120
+ color: var(--icen-token-text-muted);
1121
+ font-size: var(--icen-density-font-size-sm);
1122
+ }
1123
+ .icen-ai-thread-main {
1124
+ flex: 1;
1125
+ min-inline-size: 0;
1126
+ display: flex;
1127
+ align-items: center;
1128
+ gap: var(--icen-density-space-xs);
1129
+ padding: var(--icen-density-space-xs) var(--icen-density-space-sm);
1130
+ border: 0;
1131
+ border-radius: var(--icen-radius-xs);
1132
+ background: transparent;
1133
+ color: inherit;
1134
+ font: inherit;
1135
+ text-align: start;
1136
+ cursor: pointer;
1137
+ transition:
1138
+ background-color var(--icen-tx-fast),
1139
+ color var(--icen-tx-fast);
1140
+ }
1141
+ .icen-ai-thread-main:hover {
1142
+ background: var(--icen-token-fill-1);
1143
+ color: var(--icen-token-text);
1144
+ }
1145
+ .icen-ai-thread-main:focus-visible {
1146
+ outline: none;
1147
+ box-shadow: var(--icen-ring);
1148
+ }
1149
+ .icen-ai-thread.is-active {
1150
+ border-inline-start-color: var(--icen-token-accent);
1151
+ background: var(--icen-token-fill-1);
1152
+ color: var(--icen-token-text);
1153
+ }
1154
+ .icen-ai-thread.is-archived .icen-ai-thread-label {
1155
+ color: var(--icen-token-text-muted);
1156
+ }
1157
+ .icen-ai-thread.is-archived .icen-ai-thread-icon { opacity: 0.7; }
1158
+ .icen-ai-thread-icon {
1159
+ display: inline-flex;
1160
+ align-items: center;
1161
+ justify-content: center;
1162
+ flex-shrink: 0;
1163
+ color: var(--icen-token-text-faint);
1164
+ }
1165
+ .icen-ai-thread-icon svg {
1166
+ width: 14px;
1167
+ height: 14px;
1168
+ }
1169
+ .icen-ai-thread.is-active .icen-ai-thread-icon {
1170
+ color: var(--icen-token-accent);
1171
+ }
1172
+ .icen-ai-thread-label {
1173
+ flex: 1;
1174
+ min-width: 0;
1175
+ overflow: hidden;
1176
+ text-overflow: ellipsis;
1177
+ white-space: nowrap;
1178
+ }
1179
+
1180
+ /* 动作钮「···」:hover/聚焦/激活才出现(菜单本体由宿主经 icen:ai-thread-action 实现) */
1181
+ .icen-ai-thread-action {
1182
+ display: none;
1183
+ flex-shrink: 0;
1184
+ align-items: center;
1185
+ justify-content: center;
1186
+ width: 20px;
1187
+ height: 20px;
1188
+ padding: 0;
1189
+ border: 0;
1190
+ border-radius: var(--icen-radius-xs);
1191
+ background: transparent;
1192
+ color: var(--icen-token-text-faint);
1193
+ font-size: 13px;
1194
+ font-weight: 700;
1195
+ letter-spacing: 0.04em;
1196
+ line-height: 1;
1197
+ cursor: pointer;
1198
+ transition:
1199
+ color var(--icen-tx-fast),
1200
+ background-color var(--icen-tx-fast);
1201
+ }
1202
+ .icen-ai-thread:hover .icen-ai-thread-action,
1203
+ .icen-ai-thread:focus-within .icen-ai-thread-action,
1204
+ .icen-ai-thread.is-active .icen-ai-thread-action {
1205
+ display: inline-flex;
1206
+ }
1207
+ .icen-ai-thread-action:hover {
1208
+ color: var(--icen-token-accent);
1209
+ background: var(--icen-token-fill-2);
1210
+ }
1211
+ .icen-ai-thread-action:focus-visible {
1212
+ outline: none;
1213
+ box-shadow: var(--icen-ring);
1214
+ }
1215
+
1216
+ /* ══════════════ ai-branch · 分支版本切换器(§5.27,behaviors/ai-branch.ts) ══════════════ */
1217
+
1218
+ /*
1219
+ * <div class="icen-ai-branch" data-icen-index data-icen-count role="group">
1220
+ * <button class="icen-ai-branch-prev" [disabled]>‹</button>
1221
+ * <span class="icen-ai-branch-page">2/3</span> ← icen-mono 数字(当前从 1 计)
1222
+ * <button class="icen-ai-branch-next" [disabled]>›</button>
1223
+ * </div>
1224
+ * count ≤ 1 时挂载容器由 behavior 置空 + hidden/aria-hidden(此处无额外规则)。
1225
+ */
1226
+
1227
+ .icen-ai-branch {
1228
+ display: inline-flex;
1229
+ align-items: center;
1230
+ gap: 3px;
1231
+ color: var(--icen-token-text-muted);
1232
+ }
1233
+ .icen-ai-branch-prev,
1234
+ .icen-ai-branch-next {
1235
+ display: inline-flex;
1236
+ align-items: center;
1237
+ justify-content: center;
1238
+ width: 22px;
1239
+ height: 22px;
1240
+ padding: 0;
1241
+ border: 0;
1242
+ border-radius: var(--icen-radius-xs);
1243
+ background: transparent;
1244
+ color: var(--icen-token-text-muted);
1245
+ font-family: var(--icen-font-mono);
1246
+ font-size: 13px;
1247
+ line-height: 1;
1248
+ cursor: pointer;
1249
+ transition:
1250
+ color var(--icen-tx-fast),
1251
+ background-color var(--icen-tx-fast);
1252
+ }
1253
+ .icen-ai-branch-prev:hover,
1254
+ .icen-ai-branch-next:hover {
1255
+ color: var(--icen-token-text);
1256
+ background: var(--icen-token-fill-1);
1257
+ }
1258
+ .icen-ai-branch-prev:focus-visible,
1259
+ .icen-ai-branch-next:focus-visible {
1260
+ outline: none;
1261
+ box-shadow: var(--icen-ring);
1262
+ }
1263
+ .icen-ai-branch-prev:disabled,
1264
+ .icen-ai-branch-next:disabled {
1265
+ opacity: 0.4;
1266
+ cursor: default;
1267
+ background: transparent;
1268
+ }
1269
+ .icen-ai-branch-page {
1270
+ min-inline-size: 2.5em;
1271
+ text-align: center;
1272
+ font-family: var(--icen-font-mono);
1273
+ font-size: var(--icen-density-font-size-xs);
1274
+ color: var(--icen-token-text-faint);
1275
+ font-variant-numeric: tabular-nums;
1276
+ user-select: none;
1277
+ }
1278
+
1279
+ /* ══════════════ ai-msg-continue · aborted「继续生成」槽(§5.27,createAiStream fail/cancel) ══════════════ */
1280
+
1281
+ /* ghost 小钮行内末端浮动:挂在 .icen-ai-msg-body 尾部(消息尾),点按 → icen:ai-retry {el} */
1282
+ .icen-ai-msg-continue {
1283
+ display: inline-flex;
1284
+ align-items: center;
1285
+ float: inline-end;
1286
+ margin-block-start: var(--icen-density-space-2xs, 2px);
1287
+ margin-inline-end: 0;
1288
+ margin-inline-start: var(--icen-density-space-xs);
1289
+ padding: 2px 10px;
1290
+ border: 1px solid var(--icen-token-line);
1291
+ border-radius: var(--icen-radius-full);
1292
+ background: transparent;
1293
+ color: var(--icen-token-text-muted);
1294
+ font-size: var(--icen-density-font-size-xs);
1295
+ white-space: nowrap;
1296
+ cursor: pointer;
1297
+ transition:
1298
+ color var(--icen-tx-fast),
1299
+ border-color var(--icen-tx-fast),
1300
+ background-color var(--icen-tx-fast);
1301
+ }
1302
+ .icen-ai-msg-continue:hover {
1303
+ color: var(--icen-token-accent);
1304
+ border-color: var(--icen-hover-border);
1305
+ background: var(--icen-token-fill-1);
1306
+ }
1307
+ .icen-ai-msg-continue:focus-visible {
1308
+ outline: none;
1309
+ box-shadow: var(--icen-ring);
1310
+ }
1311
+
1312
+ /* §5.27 reasoning 自动收起无新样式:复用 .icen-ai-reasoning 既有折叠/耗时规则 */
1313
+
1314
+ /* ── 动效守卫(§5.27 新增段) ── */
1315
+
1316
+ @media (prefers-reduced-motion: reduce) {
1317
+ .icen-ai-thread,
1318
+ .icen-ai-thread-action,
1319
+ .icen-ai-threads-group-head,
1320
+ .icen-ai-threads-group-head::before,
1321
+ .icen-ai-branch-prev,
1322
+ .icen-ai-branch-next,
1323
+ .icen-ai-msg-continue {
1324
+ transition: none;
1325
+ }
1326
+ }
1327
+
1328
+ /* 触屏无 hover:动作钮常显(否则不可达) */
1329
+ @media (pointer: coarse) {
1330
+ .icen-ai-thread .icen-ai-thread-action {
1331
+ display: inline-flex;
1332
+ }
1333
+ }
1334
+
1335
+ /* ── RTL:方向性指示镜像(共享 chevron mask 经 scaleX(-1) 翻转向左) ── */
1336
+ :is([dir='rtl']) .icen-ai-reasoning-head::before { transform: scaleX(-1); }
1337
+ :is([dir='rtl']) .icen-ai-reasoning:has(.icen-ai-reasoning-head[aria-expanded='true']) .icen-ai-reasoning-head::before { transform: rotate(90deg) scaleX(-1); }
1338
+ :is([dir='rtl']) .icen-ai-threads-group-head::before { transform: scaleX(-1); }
1339
+ :is([dir='rtl']) .icen-ai-threads-group-head[aria-expanded='true']::before { transform: rotate(90deg) scaleX(-1); }
1340
+
1341
+ .icen-ai-composer-model-chevron, .icen-ai-composer-popup-option-check { display: none; }
1342
+
1343
+ /* Context has its own quiet material: icon tile → readable name → secondary detail.
1344
+ The theme owns all hues; primitive tokens own geometry. No brand-specific gradients. */
1345
+ .icen-ai-composer-popup-option-copy { display: flex; flex: 1; flex-direction: column; min-inline-size: 0; }
1346
+ .icen-ai-composer-popup-option-copy > .icen-ai-composer-popup-option-label { font-weight: 550; }
1347
+ .icen-ai-composer-popup-option-icon,
1348
+ .icen-ai-composer-chip-icon {
1349
+ display: inline-flex;
1350
+ align-items: center;
1351
+ justify-content: center;
1352
+ flex: 0 0 auto;
1353
+ inline-size: 30px;
1354
+ block-size: 30px;
1355
+ border-radius: var(--icen-radius-sm);
1356
+ background: color-mix(in srgb, var(--icen-token-accent) 9%, var(--icen-token-surface));
1357
+ color: var(--icen-token-accent);
1358
+ }
1359
+ .icen-ai-composer-popup-option-icon svg { inline-size: 18px; block-size: 18px; }
1360
+ .icen-ai-composer-chip-icon,
1361
+ .icen-ai-composer-chip > .icen-ai-composer-popup-option-icon { inline-size: 22px; block-size: 22px; background: transparent; }
1362
+ .icen-ai-composer-chip-icon svg,
1363
+ .icen-ai-composer-chip > .icen-ai-composer-popup-option-icon svg { inline-size: 16px; block-size: 16px; }
1364
+ .icen-ai-composer-chip-remove svg { inline-size: 14px; block-size: 14px; }
1365
+ .icen-ai-composer-chip-text { min-inline-size: 0; }
1366
+ .icen-ai-composer-chip-meta { color: var(--icen-token-text-muted); font-size: var(--icen-density-font-size-2xs); white-space: nowrap; }
1367
+ .icen-ai-msg-context { display: flex; flex-wrap: wrap; gap: 6px; margin-block-start: 8px; min-inline-size: 0; }
1368
+ .icen-ai-composer-refs .icen-ai-composer-chip {
1369
+ border-color: color-mix(in srgb, var(--icen-token-accent) 18%, var(--icen-token-line-soft));
1370
+ background: color-mix(in srgb, var(--icen-token-accent) 5%, var(--icen-token-surface));
1371
+ }
1372
+ .icen-ai-composer-popup-option-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1373
+ .icen-ai-composer-popup-option[aria-selected='true'] {
1374
+ background: color-mix(in srgb, var(--icen-token-accent) 9%, var(--icen-token-surface));
1375
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--icen-token-accent) 34%, transparent);
1376
+ }
1377
+ .icen-ai-composer-popup-option[aria-disabled='true'] { opacity: .5; cursor: default; }
1378
+ .icen-ai-composer-popup-option[hidden] { display: none; }
1379
+ .icen-ai-composer-popup-option mark {
1380
+ padding: 0;
1381
+ border-radius: var(--icen-radius-xs);
1382
+ color: inherit;
1383
+ background: color-mix(in srgb, var(--icen-token-accent) 18%, transparent);
1384
+ }
1385
+ .icen-ai-composer-popup-filters {
1386
+ display: flex;
1387
+ flex: 0 0 auto;
1388
+ gap: 4px;
1389
+ overflow-x: auto;
1390
+ overscroll-behavior-inline: contain;
1391
+ padding: 8px 2px;
1392
+ }
1393
+ .icen-ai-composer-popup-filters button {
1394
+ flex: 0 0 auto;
1395
+ min-block-size: 32px;
1396
+ padding: 4px 10px;
1397
+ border: 0;
1398
+ border-radius: var(--icen-radius-sm);
1399
+ background: transparent;
1400
+ color: var(--icen-token-text-muted);
1401
+ font: inherit;
1402
+ font-size: var(--icen-density-font-size-xs);
1403
+ cursor: pointer;
1404
+ }
1405
+ .icen-ai-composer-popup-filters button[aria-pressed='true'] { background: var(--icen-token-fill-2); color: var(--icen-token-text); box-shadow: inset 0 0 0 1px var(--icen-token-line); }
1406
+ .icen-ai-composer-popup-filters button:focus-visible { outline: 2px solid var(--icen-token-accent); outline-offset: -2px; }
1407
+ .icen-ai-composer-popup-cmd-line { min-inline-size: 0; flex-wrap: wrap; row-gap: 0; }
1408
+ .icen-ai-composer-popup-cmd-name, .icen-ai-composer-popup-cmd-args { overflow-wrap: anywhere; }
1409
+ .icen-ai-composer-library { background: var(--icen-token-fill-2); color: var(--icen-token-text); }
1410
+ .icen-ai-composer-model { min-inline-size: 0; max-inline-size: min(180px, 46%); }
1411
+ .icen-ai-composer[data-icen-composer-size='compact'] .icen-ai-composer-input { min-block-size: 32px; }
1412
+ @media (pointer: coarse) {
1413
+ .icen-ai-composer-chip-remove, .icen-ai-composer-btn, .icen-ai-composer-send,
1414
+ .icen-ai-composer-model, .icen-ai-composer-popup-filters button { min-inline-size: 44px; min-block-size: 44px; }
1415
+ .icen-ai-composer-input { font-size: max(16px, var(--icen-density-font-size-md)); }
1416
+ }
1417
+ @media (forced-colors: active) {
1418
+ .icen-ai-composer:focus-within { outline: 1px solid Highlight; }
1419
+ .icen-ai-composer-popup-option[aria-selected='true'], .icen-ai-composer-popup-filters button[aria-pressed='true'] { outline: 2px solid Highlight; outline-offset: -2px; }
1420
+ .icen-ai-composer-popup-option.is-focused { outline: 1px solid CanvasText; outline-offset: -1px; }
1421
+ .icen-ai-composer-popup-option-icon { border: 1px solid ButtonText; }
1422
+ }
1423
+ @media (prefers-reduced-motion: reduce) { .icen-ai-composer { transition: none; } }
1424
+
1425
+ }