@icen.ai/ui 0.9.0 → 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 (281) hide show
  1. package/AGENTS.md +138 -80
  2. package/README.md +66 -91
  3. package/dist/base.css +208 -179
  4. package/dist/behaviors/accordion.mjs +8 -8
  5. package/dist/behaviors/ai-branch.d.mts +1 -1
  6. package/dist/behaviors/ai-branch.mjs +1010 -94
  7. package/dist/behaviors/ai-chat.d.mts +7 -7
  8. package/dist/behaviors/ai-chat.mjs +1071 -161
  9. package/dist/behaviors/ai-composer.d.mts +44 -12
  10. package/dist/behaviors/ai-composer.mjs +1997 -524
  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 +1 -1
  15. package/dist/behaviors/ai-feedback.mjs +1035 -126
  16. package/dist/behaviors/ai-panel.d.mts +8 -8
  17. package/dist/behaviors/ai-panel.mjs +1284 -266
  18. package/dist/behaviors/ai-provider.mjs +1003 -101
  19. package/dist/behaviors/ai-threads.d.mts +1 -1
  20. package/dist/behaviors/ai-threads.mjs +1068 -154
  21. package/dist/behaviors/ai-tool.d.mts +2 -2
  22. package/dist/behaviors/ai-tool.mjs +2037 -396
  23. package/dist/behaviors/ai-tools.d.mts +89 -16
  24. package/dist/behaviors/ai-tools.mjs +4448 -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 +72 -8
  34. package/dist/behaviors/charts.mjs +1901 -256
  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 +120 -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 +1 -1
  68. package/dist/behaviors/kb-access.mjs +2129 -239
  69. package/dist/behaviors/kb-acl.d.mts +6 -6
  70. package/dist/behaviors/kb-acl.mjs +1119 -179
  71. package/dist/behaviors/kb-answer.mjs +2070 -418
  72. package/dist/behaviors/kb-audit.d.mts +1 -1
  73. package/dist/behaviors/kb-audit.mjs +1076 -154
  74. package/dist/behaviors/kb-canvas.mjs +1100 -177
  75. package/dist/behaviors/kb-chain.mjs +1022 -100
  76. package/dist/behaviors/kb-checkpoint.d.mts +1 -1
  77. package/dist/behaviors/kb-checkpoint.mjs +1319 -169
  78. package/dist/behaviors/kb-chunks.mjs +1152 -213
  79. package/dist/behaviors/kb-citation.d.mts +1 -1
  80. package/dist/behaviors/kb-citation.mjs +1201 -179
  81. package/dist/behaviors/kb-clarify.mjs +1058 -130
  82. package/dist/behaviors/kb-conflict.mjs +1041 -119
  83. package/dist/behaviors/kb-connector.mjs +1104 -176
  84. package/dist/behaviors/kb-core.d.mts +6 -1
  85. package/dist/behaviors/kb-core.mjs +1077 -162
  86. package/dist/behaviors/kb-eval.mjs +1971 -144
  87. package/dist/behaviors/kb-explain.d.mts +1 -1
  88. package/dist/behaviors/kb-explain.mjs +1024 -102
  89. package/dist/behaviors/kb-filter.mjs +2008 -178
  90. package/dist/behaviors/kb-gap.d.mts +1 -1
  91. package/dist/behaviors/kb-gap.mjs +1043 -121
  92. package/dist/behaviors/kb-hittest.d.mts +1 -1
  93. package/dist/behaviors/kb-hittest.mjs +1093 -150
  94. package/dist/behaviors/kb-metadata.mjs +1052 -130
  95. package/dist/behaviors/kb-passage.d.mts +2 -2
  96. package/dist/behaviors/kb-passage.mjs +1101 -161
  97. package/dist/behaviors/kb-pipeline.d.mts +2 -2
  98. package/dist/behaviors/kb-pipeline.mjs +1082 -162
  99. package/dist/behaviors/kb-qa.mjs +1088 -160
  100. package/dist/behaviors/kb-rerank.mjs +1047 -114
  101. package/dist/behaviors/kb-retrieval.mjs +2063 -224
  102. package/dist/behaviors/kb-review.mjs +1990 -159
  103. package/dist/behaviors/kb-sandbox.d.mts +1 -1
  104. package/dist/behaviors/kb-sandbox.mjs +1026 -104
  105. package/dist/behaviors/kb-segment.mjs +1111 -179
  106. package/dist/behaviors/kb-select.d.mts +24 -0
  107. package/dist/behaviors/kb-select.mjs +1989 -0
  108. package/dist/behaviors/kb-sources.d.mts +1 -1
  109. package/dist/behaviors/kb-sources.mjs +1084 -170
  110. package/dist/behaviors/kb-sql.d.mts +1 -1
  111. package/dist/behaviors/kb-sql.mjs +1143 -226
  112. package/dist/behaviors/kb-trace.d.mts +1 -1
  113. package/dist/behaviors/kb-trace.mjs +1042 -128
  114. package/dist/behaviors/kb-visibility.mjs +1086 -158
  115. package/dist/behaviors/kb-who-can.mjs +1974 -137
  116. package/dist/behaviors/mentions.d.mts +93 -0
  117. package/dist/behaviors/mentions.mjs +2152 -0
  118. package/dist/behaviors/modal.d.mts +4 -3
  119. package/dist/behaviors/modal.mjs +1055 -33
  120. package/dist/behaviors/nav.d.mts +1 -1
  121. package/dist/behaviors/nav.mjs +6 -6
  122. package/dist/behaviors/notification.d.mts +16 -8
  123. package/dist/behaviors/notification.mjs +1615 -265
  124. package/dist/behaviors/panel.d.mts +4 -0
  125. package/dist/behaviors/panel.mjs +994 -0
  126. package/dist/behaviors/popover.d.mts +28 -5
  127. package/dist/behaviors/popover.mjs +225 -24
  128. package/dist/behaviors/select.d.mts +5 -2
  129. package/dist/behaviors/select.mjs +1410 -117
  130. package/dist/behaviors/sidebar.d.mts +1 -1
  131. package/dist/behaviors/sidebar.mjs +13 -13
  132. package/dist/behaviors/slider.d.mts +1 -1
  133. package/dist/behaviors/slider.mjs +9 -9
  134. package/dist/behaviors/split-pane.d.mts +1 -1
  135. package/dist/behaviors/split-pane.mjs +7 -7
  136. package/dist/behaviors/suggestions.d.mts +27 -0
  137. package/dist/behaviors/suggestions.mjs +1089 -0
  138. package/dist/behaviors/svg-parse.d.mts +14 -0
  139. package/dist/behaviors/svg-parse.mjs +37 -0
  140. package/dist/behaviors/tabs.d.mts +2 -2
  141. package/dist/behaviors/tabs.mjs +25 -25
  142. package/dist/behaviors/tag-input.d.mts +23 -5
  143. package/dist/behaviors/tag-input.mjs +1359 -104
  144. package/dist/behaviors/theme-switcher.d.mts +24 -0
  145. package/dist/behaviors/theme-switcher.mjs +1981 -0
  146. package/dist/behaviors/theme.d.mts +15 -8
  147. package/dist/behaviors/theme.mjs +390 -28
  148. package/dist/behaviors/toast.d.mts +24 -25
  149. package/dist/behaviors/toast.mjs +1266 -88
  150. package/dist/behaviors/tooltip.d.mts +4 -0
  151. package/dist/behaviors/tooltip.mjs +378 -0
  152. package/dist/behaviors/tree-select.d.mts +69 -0
  153. package/dist/behaviors/tree-select.mjs +1907 -0
  154. package/dist/behaviors/tree.d.mts +1 -1
  155. package/dist/behaviors/tree.mjs +15 -15
  156. package/dist/behaviors/upload.d.mts +3 -2
  157. package/dist/behaviors/upload.mjs +1076 -66
  158. package/dist/cli.mjs +5 -6
  159. package/dist/components/ai-chat.css +666 -573
  160. package/dist/components/ai-diff.css +153 -132
  161. package/dist/components/ai-panel.css +351 -343
  162. package/dist/components/ai-tool.css +393 -238
  163. package/dist/components/autocomplete.css +61 -0
  164. package/dist/components/autocomplete.mjs +3 -0
  165. package/dist/components/back-top.css +34 -31
  166. package/dist/components/badge.css +44 -41
  167. package/dist/components/breadcrumb.css +67 -46
  168. package/dist/components/btn.css +80 -74
  169. package/dist/components/card.css +117 -106
  170. package/dist/components/cascader.css +311 -0
  171. package/dist/components/cascader.mjs +3 -0
  172. package/dist/components/chart-area.css +8 -2
  173. package/dist/components/chart-bar.css +95 -33
  174. package/dist/components/chart-gauge.css +14 -11
  175. package/dist/components/chart-graph.css +20 -17
  176. package/dist/components/chart-heatmap.css +96 -90
  177. package/dist/components/chart-line.css +8 -3
  178. package/dist/components/chart-pie.css +9 -6
  179. package/dist/components/chart-radar.css +8 -5
  180. package/dist/components/chart-scatter.css +9 -6
  181. package/dist/components/chart-sparkline.css +5 -2
  182. package/dist/components/chart-stack.css +14 -11
  183. package/dist/components/charts.css +164 -73
  184. package/dist/components/code-block.css +418 -0
  185. package/dist/components/code-block.mjs +4 -0
  186. package/dist/components/command-palette.css +138 -117
  187. package/dist/components/content.css +257 -251
  188. package/dist/components/copy.css +72 -44
  189. package/dist/components/datatable.css +423 -181
  190. package/dist/components/date-picker.css +135 -104
  191. package/dist/components/empty.css +68 -65
  192. package/dist/components/feedback.css +201 -183
  193. package/dist/components/form-validate.css +120 -0
  194. package/dist/components/form-validate.mjs +3 -0
  195. package/dist/components/form.css +150 -127
  196. package/dist/components/icon.css +102 -0
  197. package/dist/components/icon.mjs +3 -0
  198. package/dist/components/input.css +159 -104
  199. package/dist/components/kb-agent.css +188 -173
  200. package/dist/components/kb-data.css +257 -253
  201. package/dist/components/kb-ground.css +197 -185
  202. package/dist/components/kb-ingest.css +334 -350
  203. package/dist/components/kb-ops.css +265 -259
  204. package/dist/components/kb-perm.css +260 -271
  205. package/dist/components/kb-search.css +317 -360
  206. package/dist/components/kb.css +120 -109
  207. package/dist/components/layout.css +85 -82
  208. package/dist/components/material-chinese.css +73 -0
  209. package/dist/components/material-soviet.css +76 -0
  210. package/dist/components/material.css +275 -0
  211. package/dist/components/media.css +220 -166
  212. package/dist/components/mentions.css +189 -0
  213. package/dist/components/mentions.mjs +3 -0
  214. package/dist/components/menu.css +113 -105
  215. package/dist/components/modal.css +107 -112
  216. package/dist/components/nav.css +118 -115
  217. package/dist/components/notification.css +238 -174
  218. package/dist/components/pagination.css +56 -53
  219. package/dist/components/panel.css +66 -63
  220. package/dist/components/panel.mjs +1 -0
  221. package/dist/components/pill.css +81 -71
  222. package/dist/components/popover.css +67 -53
  223. package/dist/components/scroll-area.css +113 -110
  224. package/dist/components/segmented.css +146 -143
  225. package/dist/components/select.css +206 -186
  226. package/dist/components/sidebar.css +137 -127
  227. package/dist/components/slider.css +117 -114
  228. package/dist/components/split-pane.css +112 -109
  229. package/dist/components/stat.css +112 -106
  230. package/dist/components/steps.css +109 -103
  231. package/dist/components/switch.css +138 -134
  232. package/dist/components/table.css +131 -107
  233. package/dist/components/tabs.css +114 -108
  234. package/dist/components/tag-input.css +48 -133
  235. package/dist/components/tag.css +81 -71
  236. package/dist/components/theme-switcher.css +105 -0
  237. package/dist/components/theme-switcher.mjs +3 -0
  238. package/dist/components/toast.css +100 -86
  239. package/dist/components/toolbar.css +45 -42
  240. package/dist/components/tooltip.css +102 -43
  241. package/dist/components/tooltip.mjs +1 -0
  242. package/dist/components/tree-select.css +416 -0
  243. package/dist/components/tree-select.mjs +3 -0
  244. package/dist/components/upload.css +135 -92
  245. package/dist/fonts/LICENSES/ark-pixel/OFL.txt +96 -0
  246. package/dist/fonts/LICENSES/cubic-11/OFL.txt +108 -0
  247. package/dist/fonts/LICENSES/galmuri/LICENSE.txt +93 -0
  248. package/dist/fonts/OFL.txt +96 -0
  249. package/dist/fonts/README.md +14 -0
  250. package/dist/fonts/fusion-pixel-12px-zh-hans.woff2 +0 -0
  251. package/dist/index.d.mts +28 -14
  252. package/dist/index.mjs +20705 -9601
  253. package/dist/react.d.mts +91 -0
  254. package/dist/react.mjs +8208 -0
  255. package/dist/registry.json +130 -13
  256. package/dist/tokens/chinese.css +44 -0
  257. package/dist/tokens/colors.css +365 -1222
  258. package/dist/tokens/design.css +109 -0
  259. package/dist/tokens/dtcg.json +11198 -0
  260. package/dist/tokens/figma.variables.json +7017 -0
  261. package/dist/tokens/icon-masks.css +78 -0
  262. package/dist/tokens/pixel.css +50 -0
  263. package/dist/tokens/soviet.css +44 -0
  264. package/dist/tokens/style-profiles.css +36 -547
  265. package/dist/tokens/themes.json +308 -0
  266. package/dist/tokens/tokens-studio.json +6728 -0
  267. package/dist/tokens/typography.css +21 -18
  268. package/dist/tokens.css +1555 -1801
  269. package/dist/ui.css +11975 -9831
  270. package/dist/vue.d.mts +344 -0
  271. package/dist/vue.mjs +7781 -0
  272. package/docs/spec/ai-input-experience.md +75 -0
  273. package/docs/spec/ai-native.md +238 -147
  274. package/docs/spec/design-philosophy.md +189 -0
  275. package/docs/spec/design-primitives.md +196 -0
  276. package/docs/spec/kb-family.md +147 -115
  277. package/package.json +43 -8
  278. package/dist/retro-effects.css +0 -255
  279. package/dist/tokens/retro-effects.css +0 -255
  280. package/docs/research/2026-10-03-ai-kb-components.md +0 -392
  281. package/docs/research/2026-10-03-kb-permissions.md +0 -992
@@ -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
- }
541
-
542
- /* ── v2 工具条(composer-box 内底部,业界主流形态)── */
547
+ /* ── 工具条(composer-box 内底部,业界主流形态)── */
543
548
 
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);
681
- }
682
- .ai-composer-popup-search-input:focus {
683
- border-color: var(--token-accent);
678
+ padding: 4px 8px 8px;
679
+ color: var(--icen-token-text-muted);
680
+ border-bottom: 1px solid var(--icen-token-line-soft);
684
681
  }
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,41 +1001,41 @@
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; }
1038
1027
 
1039
1028
  /* ══════════════ ai-threads · 会话列表侧栏(§5.27,behaviors/ai-threads.ts) ══════════════ */
1040
1029
 
1041
1030
  /*
1042
- * <div class="ai-threads"> ← 240px 侧栏形态(--ai-threads-width 可调)
1043
- * <div class="ai-threads-group" data-group="今天" [.is-collapsed]>
1044
- * <button class="ai-threads-group-head" aria-expanded="true">今天</button>
1045
- * <div class="ai-threads-group-list">
1046
- * <div class="ai-thread [.is-active|.is-archived]" role="button" tabindex="0" data-key="…">
1047
- * <span class="ai-thread-icon">…svg…</span>
1048
- * <span class="ai-thread-label">…</span>
1049
- * <button class="ai-thread-action">···</button> ← 动作菜单挂载点(宿主实现)
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> ← 动作菜单挂载点(宿主实现)
1050
1039
  * </div>…
1051
1040
  * </div>
1052
1041
  * </div>… ← 「已归档」组由 behavior 沉底
@@ -1054,123 +1043,133 @@
1054
1043
  * .is-active:左 2px accent;.is-archived:降透明;组头 11px faint。
1055
1044
  */
1056
1045
 
1057
- .ai-threads {
1046
+ .icen-ai-threads {
1058
1047
  display: flex;
1059
1048
  flex-direction: column;
1060
- gap: var(--density-space-xs);
1049
+ gap: var(--icen-density-space-xs);
1061
1050
  width: var(--ai-threads-width, 240px);
1062
1051
  min-width: 0;
1063
1052
  align-self: stretch; /* 宽度自稳定:宿主 flex/grid 居中时不 shrink-wrap */
1064
- font-size: var(--density-font-size-sm);
1053
+ font-size: var(--icen-density-font-size-sm);
1065
1054
  }
1066
1055
 
1067
- .ai-threads-group {
1056
+ .icen-ai-threads-group {
1068
1057
  display: flex;
1069
1058
  flex-direction: column;
1070
1059
  gap: 2px;
1071
1060
  min-width: 0;
1072
1061
  }
1073
1062
 
1074
- /* 组头:11px faint 小标,可折叠(aria-expanded 驱动 CSS 三角,与 .ai-reasoning-head 同款) */
1075
- .ai-threads-group-head {
1063
+ /* 组头:11px faint 小标,可折叠(aria-expanded 驱动 CSS 三角,与 .icen-ai-reasoning-head 同款) */
1064
+ .icen-ai-threads-group-head {
1076
1065
  display: flex;
1077
1066
  align-items: center;
1078
1067
  gap: 4px;
1079
- padding: var(--density-space-xs) 2px;
1068
+ padding: var(--icen-density-space-xs) 2px;
1080
1069
  border: 0;
1081
1070
  background: none;
1082
1071
  font-size: 11px;
1083
1072
  font-weight: 500;
1084
- color: var(--token-text-faint);
1073
+ color: var(--icen-token-text-faint);
1085
1074
  letter-spacing: 0.02em;
1086
- text-align: left;
1075
+ text-align: start;
1087
1076
  cursor: pointer;
1088
1077
  transition: color var(--icen-tx-fast);
1089
1078
  }
1090
- .ai-threads-group-head:hover {
1091
- color: var(--token-text-muted);
1079
+ .icen-ai-threads-group-head:hover {
1080
+ color: var(--icen-token-text-muted);
1092
1081
  }
1093
- .ai-threads-group-head:focus-visible {
1082
+ .icen-ai-threads-group-head:focus-visible {
1094
1083
  outline: none;
1095
1084
  box-shadow: var(--icen-ring);
1096
- border-radius: var(--radius-xs);
1085
+ border-radius: var(--icen-radius-xs);
1097
1086
  }
1098
- .ai-threads-group-head::before {
1087
+ .icen-ai-threads-group-head::before {
1099
1088
  content: '';
1100
1089
  flex-shrink: 0;
1101
- width: 6px;
1102
- height: 6px;
1103
- border-right: 1.5px solid currentColor;
1104
- border-bottom: 1.5px solid currentColor;
1105
- transform: rotate(-45deg);
1090
+ inline-size: 10px;
1091
+ block-size: 10px;
1092
+ background: currentColor;
1093
+ mask: var(--icen-token-icon-chevron-right) center / contain no-repeat;
1106
1094
  transition: transform var(--icen-tx-fast);
1107
1095
  }
1108
- .ai-threads-group-head[aria-expanded='true']::before {
1109
- transform: rotate(45deg);
1096
+ .icen-ai-threads-group-head[aria-expanded='true']::before {
1097
+ transform: rotate(90deg);
1110
1098
  }
1111
- .ai-threads-group.is-collapsed .ai-threads-group-list {
1099
+ .icen-ai-threads-group.is-collapsed .icen-ai-threads-group-list {
1112
1100
  display: none;
1113
1101
  }
1114
1102
 
1115
- .ai-threads-group-list {
1103
+ .icen-ai-threads-group-list {
1116
1104
  display: flex;
1117
1105
  flex-direction: column;
1118
1106
  gap: 1px;
1119
1107
  min-width: 0;
1120
1108
  }
1121
1109
 
1122
- /* 会话行:激活左 2px accent 线;归档降透明 */
1123
- .ai-thread {
1110
+ /* 会话行:中性容器(激活起始缘 2px accent 线);交互 affordance 归 .icen-ai-thread-main 真按钮 */
1111
+ .icen-ai-thread {
1124
1112
  position: relative;
1125
1113
  display: flex;
1126
1114
  align-items: center;
1127
- gap: var(--density-space-xs);
1128
- min-width: 0;
1129
- padding: var(--density-space-xs) var(--density-space-sm);
1130
- border-left: 2px solid transparent;
1131
- border-radius: var(--radius-xs);
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
1132
  background: transparent;
1133
- color: var(--token-text-muted);
1134
- font-size: var(--density-font-size-sm);
1135
- text-align: left;
1133
+ color: inherit;
1134
+ font: inherit;
1135
+ text-align: start;
1136
1136
  cursor: pointer;
1137
1137
  transition:
1138
1138
  background-color var(--icen-tx-fast),
1139
- color var(--icen-tx-fast),
1140
- border-color var(--icen-tx-fast),
1141
- opacity var(--icen-tx-fast);
1139
+ color var(--icen-tx-fast);
1142
1140
  }
1143
- .ai-thread:hover {
1144
- background: var(--token-fill-1);
1145
- color: var(--token-text);
1141
+ .icen-ai-thread-main:hover {
1142
+ background: var(--icen-token-fill-1);
1143
+ color: var(--icen-token-text);
1146
1144
  }
1147
- .ai-thread:focus-visible {
1145
+ .icen-ai-thread-main:focus-visible {
1148
1146
  outline: none;
1149
1147
  box-shadow: var(--icen-ring);
1150
1148
  }
1151
- .ai-thread.is-active {
1152
- border-left-color: var(--token-accent);
1153
- background: var(--token-fill-1);
1154
- color: var(--token-text);
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);
1155
1153
  }
1156
- .ai-thread.is-archived {
1157
- opacity: 0.55;
1154
+ .icen-ai-thread.is-archived .icen-ai-thread-label {
1155
+ color: var(--icen-token-text-muted);
1158
1156
  }
1159
- .ai-thread-icon {
1157
+ .icen-ai-thread.is-archived .icen-ai-thread-icon { opacity: 0.7; }
1158
+ .icen-ai-thread-icon {
1160
1159
  display: inline-flex;
1161
1160
  align-items: center;
1162
1161
  justify-content: center;
1163
1162
  flex-shrink: 0;
1164
- color: var(--token-text-faint);
1163
+ color: var(--icen-token-text-faint);
1165
1164
  }
1166
- .ai-thread-icon svg {
1165
+ .icen-ai-thread-icon svg {
1167
1166
  width: 14px;
1168
1167
  height: 14px;
1169
1168
  }
1170
- .ai-thread.is-active .ai-thread-icon {
1171
- color: var(--token-accent);
1169
+ .icen-ai-thread.is-active .icen-ai-thread-icon {
1170
+ color: var(--icen-token-accent);
1172
1171
  }
1173
- .ai-thread-label {
1172
+ .icen-ai-thread-label {
1174
1173
  flex: 1;
1175
1174
  min-width: 0;
1176
1175
  overflow: hidden;
@@ -1179,7 +1178,7 @@
1179
1178
  }
1180
1179
 
1181
1180
  /* 动作钮「···」:hover/聚焦/激活才出现(菜单本体由宿主经 icen:ai-thread-action 实现) */
1182
- .ai-thread-action {
1181
+ .icen-ai-thread-action {
1183
1182
  display: none;
1184
1183
  flex-shrink: 0;
1185
1184
  align-items: center;
@@ -1188,9 +1187,9 @@
1188
1187
  height: 20px;
1189
1188
  padding: 0;
1190
1189
  border: 0;
1191
- border-radius: var(--radius-xs);
1190
+ border-radius: var(--icen-radius-xs);
1192
1191
  background: transparent;
1193
- color: var(--token-text-faint);
1192
+ color: var(--icen-token-text-faint);
1194
1193
  font-size: 13px;
1195
1194
  font-weight: 700;
1196
1195
  letter-spacing: 0.04em;
@@ -1200,16 +1199,16 @@
1200
1199
  color var(--icen-tx-fast),
1201
1200
  background-color var(--icen-tx-fast);
1202
1201
  }
1203
- .ai-thread:hover .ai-thread-action,
1204
- .ai-thread:focus-within .ai-thread-action,
1205
- .ai-thread.is-active .ai-thread-action {
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 {
1206
1205
  display: inline-flex;
1207
1206
  }
1208
- .ai-thread-action:hover {
1209
- color: var(--token-accent);
1210
- background: var(--token-fill-2);
1207
+ .icen-ai-thread-action:hover {
1208
+ color: var(--icen-token-accent);
1209
+ background: var(--icen-token-fill-2);
1211
1210
  }
1212
- .ai-thread-action:focus-visible {
1211
+ .icen-ai-thread-action:focus-visible {
1213
1212
  outline: none;
1214
1213
  box-shadow: var(--icen-ring);
1215
1214
  }
@@ -1217,22 +1216,22 @@
1217
1216
  /* ══════════════ ai-branch · 分支版本切换器(§5.27,behaviors/ai-branch.ts) ══════════════ */
1218
1217
 
1219
1218
  /*
1220
- * <div class="ai-branch" data-index data-count role="group">
1221
- * <button class="ai-branch-prev" [disabled]>‹</button>
1222
- * <span class="ai-branch-page">2/3</span> ← mono 数字(当前从 1 计)
1223
- * <button class="ai-branch-next" [disabled]>›</button>
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>
1224
1223
  * </div>
1225
1224
  * count ≤ 1 时挂载容器由 behavior 置空 + hidden/aria-hidden(此处无额外规则)。
1226
1225
  */
1227
1226
 
1228
- .ai-branch {
1227
+ .icen-ai-branch {
1229
1228
  display: inline-flex;
1230
1229
  align-items: center;
1231
1230
  gap: 3px;
1232
- color: var(--token-text-muted);
1231
+ color: var(--icen-token-text-muted);
1233
1232
  }
1234
- .ai-branch-prev,
1235
- .ai-branch-next {
1233
+ .icen-ai-branch-prev,
1234
+ .icen-ai-branch-next {
1236
1235
  display: inline-flex;
1237
1236
  align-items: center;
1238
1237
  justify-content: center;
@@ -1240,10 +1239,10 @@
1240
1239
  height: 22px;
1241
1240
  padding: 0;
1242
1241
  border: 0;
1243
- border-radius: var(--radius-xs);
1242
+ border-radius: var(--icen-radius-xs);
1244
1243
  background: transparent;
1245
- color: var(--token-text-muted);
1246
- font-family: var(--font-mono);
1244
+ color: var(--icen-token-text-muted);
1245
+ font-family: var(--icen-font-mono);
1247
1246
  font-size: 13px;
1248
1247
  line-height: 1;
1249
1248
  cursor: pointer;
@@ -1251,46 +1250,48 @@
1251
1250
  color var(--icen-tx-fast),
1252
1251
  background-color var(--icen-tx-fast);
1253
1252
  }
1254
- .ai-branch-prev:hover,
1255
- .ai-branch-next:hover {
1256
- color: var(--token-text);
1257
- background: var(--token-fill-1);
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);
1258
1257
  }
1259
- .ai-branch-prev:focus-visible,
1260
- .ai-branch-next:focus-visible {
1258
+ .icen-ai-branch-prev:focus-visible,
1259
+ .icen-ai-branch-next:focus-visible {
1261
1260
  outline: none;
1262
1261
  box-shadow: var(--icen-ring);
1263
1262
  }
1264
- .ai-branch-prev:disabled,
1265
- .ai-branch-next:disabled {
1263
+ .icen-ai-branch-prev:disabled,
1264
+ .icen-ai-branch-next:disabled {
1266
1265
  opacity: 0.4;
1267
1266
  cursor: default;
1268
1267
  background: transparent;
1269
1268
  }
1270
- .ai-branch-page {
1271
- min-width: 2.5em;
1269
+ .icen-ai-branch-page {
1270
+ min-inline-size: 2.5em;
1272
1271
  text-align: center;
1273
- font-family: var(--font-mono);
1274
- font-size: var(--density-font-size-xs);
1275
- color: var(--token-text-faint);
1272
+ font-family: var(--icen-font-mono);
1273
+ font-size: var(--icen-density-font-size-xs);
1274
+ color: var(--icen-token-text-faint);
1276
1275
  font-variant-numeric: tabular-nums;
1277
1276
  user-select: none;
1278
1277
  }
1279
1278
 
1280
1279
  /* ══════════════ ai-msg-continue · aborted「继续生成」槽(§5.27,createAiStream fail/cancel) ══════════════ */
1281
1280
 
1282
- /* ghost 小钮右浮:挂在 .ai-msg-body 尾部(消息尾),点按 → icen:ai-retry {el} */
1283
- .ai-msg-continue {
1281
+ /* ghost 小钮行内末端浮动:挂在 .icen-ai-msg-body 尾部(消息尾),点按 → icen:ai-retry {el} */
1282
+ .icen-ai-msg-continue {
1284
1283
  display: inline-flex;
1285
1284
  align-items: center;
1286
- float: right;
1287
- margin: var(--density-space-2xs, 2px) 0 0 var(--density-space-xs);
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);
1288
1289
  padding: 2px 10px;
1289
- border: 1px solid var(--token-line);
1290
- border-radius: var(--radius-full);
1290
+ border: 1px solid var(--icen-token-line);
1291
+ border-radius: var(--icen-radius-full);
1291
1292
  background: transparent;
1292
- color: var(--token-text-muted);
1293
- font-size: var(--density-font-size-xs);
1293
+ color: var(--icen-token-text-muted);
1294
+ font-size: var(--icen-density-font-size-xs);
1294
1295
  white-space: nowrap;
1295
1296
  cursor: pointer;
1296
1297
  transition:
@@ -1298,35 +1299,127 @@
1298
1299
  border-color var(--icen-tx-fast),
1299
1300
  background-color var(--icen-tx-fast);
1300
1301
  }
1301
- .ai-msg-continue:hover {
1302
- color: var(--token-accent);
1302
+ .icen-ai-msg-continue:hover {
1303
+ color: var(--icen-token-accent);
1303
1304
  border-color: var(--icen-hover-border);
1304
- background: var(--token-fill-1);
1305
+ background: var(--icen-token-fill-1);
1305
1306
  }
1306
- .ai-msg-continue:focus-visible {
1307
+ .icen-ai-msg-continue:focus-visible {
1307
1308
  outline: none;
1308
1309
  box-shadow: var(--icen-ring);
1309
1310
  }
1310
1311
 
1311
- /* §5.27 reasoning 自动收起无新样式:复用 .ai-reasoning 既有折叠/耗时规则 */
1312
+ /* §5.27 reasoning 自动收起无新样式:复用 .icen-ai-reasoning 既有折叠/耗时规则 */
1312
1313
 
1313
1314
  /* ── 动效守卫(§5.27 新增段) ── */
1314
1315
 
1315
1316
  @media (prefers-reduced-motion: reduce) {
1316
- .ai-thread,
1317
- .ai-thread-action,
1318
- .ai-threads-group-head,
1319
- .ai-threads-group-head::before,
1320
- .ai-branch-prev,
1321
- .ai-branch-next,
1322
- .ai-msg-continue {
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 {
1323
1324
  transition: none;
1324
1325
  }
1325
1326
  }
1326
1327
 
1327
1328
  /* 触屏无 hover:动作钮常显(否则不可达) */
1328
1329
  @media (pointer: coarse) {
1329
- .ai-thread .ai-thread-action {
1330
+ .icen-ai-thread .icen-ai-thread-action {
1330
1331
  display: inline-flex;
1331
1332
  }
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
+ }