@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
package/dist/base.css CHANGED
@@ -1,7 +1,8 @@
1
+ @layer icen.base {
1
2
  /*
2
3
  * @icen.ai/ui — Base(元素基线 + 交互基元 + 统一抽象层 + 滚动条)
3
4
  *
4
- * 全部消费 --token-*;任何 preset / 明暗 / style profile 下自洽。
5
+ * 全部消费 --icen-token-*;任何 preset / 明暗 / style profile 下自洽。
5
6
  * 在 tokens 之后、components 之前引入。
6
7
  *
7
8
  * ════════════════════════════════════════════════════════════════════════
@@ -19,18 +20,18 @@
19
20
  * --icen-tx-fast / -normal / -slow ← 统一过渡时长+缓动
20
21
  *
21
22
  * 组件直接写:
22
- * .btn:focus-visible { box-shadow: var(--icen-ring); }
23
- * .btn:disabled { opacity: var(--icen-disabled-opacity); }
23
+ * .icen-btn:focus-visible { box-shadow: var(--icen-ring); }
24
+ * .icen-btn:disabled { opacity: var(--icen-disabled-opacity); }
24
25
  *
25
- * 风格 profile 覆盖原语:
26
- * .style-retro { --icen-ring: 2px solid var(--token-accent); --icen-press: translate(2px,2px); }
26
+ * 原语覆盖反馈配方:
27
+ * [data-icen-style="chinese"] { --icen-press: scale(.995); --icen-hover-border: var(--icen-token-line); }
27
28
  *
28
29
  * ── 层 2:6 个交互基元 class(HTML 显式组合 API)
29
- * .pressable / .control / .field / .lift / .surface-elevated / .focus-ring
30
+ * .icen-pressable / .icen-control / .icen-field / .icen-lift / .icen-surface-elevated / .icen-focus-ring
30
31
  *
31
32
  * 用法(任选其一):
32
- * <button class="btn pressable focus-ring"> ← 类组合,体积最小
33
- * <button class="btn"> ← 自洽,CSS 引用同一原语 token
33
+ * <button class="icen-btn icen-pressable icen-focus-ring"> ← 类组合,体积最小
34
+ * <button class="icen-btn"> ← 自洽,CSS 引用同一原语 token
34
35
  *
35
36
  * ── 命名约定(所有组件统一)
36
37
  * 根类: .component
@@ -38,64 +39,66 @@
38
39
  * 尺寸: .component--sm / --lg / --xl
39
40
  * 状态: .is-loading / .is-error / .is-disabled / .is-open / .is-selected /
40
41
  * .is-focused / .is-active / .is-empty / .is-filled
41
- * aria 等价: [aria-busy=true]↔.is-loading、[data-invalid=true]↔.is-error、
42
- * [aria-disabled=true]/[data-disabled]↔.is-disabled、
42
+ * aria 等价: [aria-busy=true]↔.is-loading、[data-icen-invalid=true]↔.is-error、
43
+ * [aria-disabled=true]/[data-icen-disabled]↔.is-disabled、
43
44
  * [aria-expanded=true]↔.is-open、[aria-selected=true]/[aria-current=page]↔.is-active
44
45
  *
45
46
  * ── Token 纪律
46
- * 颜色: 仅 --token-success / -warning / -error / -info / -accent(语义)
47
- * 间距: --density-space-*
48
- * 字号: --density-font-size-*
49
- * 控件高度: --density-input-height-*
50
- * 圆角: --radius-*
51
- * 阴影: --token-shadow-*
52
- * 时长/缓动: --duration-* / --ease-*(或直接用 --icen-tx-*)
53
- * z-index: --z-*
47
+ * 颜色: 仅 --icen-token-success / -warning / -error / -info / -accent(语义)
48
+ * 间距: --icen-density-space-*
49
+ * 字号: --icen-density-font-size-*
50
+ * 控件高度: --icen-density-input-height-*
51
+ * 圆角: --icen-radius-*
52
+ * 阴影: --icen-token-shadow-*
53
+ * 时长/缓动: --icen-duration-* / --icen-ease-*(或直接用 --icen-tx-*)
54
+ * z-index: --icen-z-*
54
55
  *
55
56
  * 暴露的契约:
56
57
  * - 元素基线:box-sizing / body / a / code / pre / img / ::selection
57
- * - 滚动条:贴 --token-scrollbar-*(retro profile 另有硬覆盖)
58
- * - 工具类:.mono / .serif / .dim / .faint / .numeric / .sr-only / .skip-link
59
- * - z-index 标尺:--z-* (浮层一律 portal 到 body)
58
+ * - 滚动条:贴 --icen-token-scrollbar-*
59
+ * - 工具类:.icen-mono / .icen-serif / .icen-dim / .icen-faint / .icen-numeric / .icen-sr-only / .icen-skip-link
60
+ * - z-index 标尺:--icen-z-* (浮层一律 portal 到 body)
60
61
  * - 共享 keyframes:icen-pop-in(弹层进场)/ icen-spin(旋转)/ icen-skeleton-pulse(骨架脉冲)
61
- * - 交互基元 class:.pressable / .control / .field / .lift / .surface-elevated / .focus-ring / .motion
62
- * - 状态约定:[aria-disabled] / [aria-busy] / [data-loading] / [data-disabled] / [data-invalid]
62
+ * - 交互基元 class:.icen-pressable / .icen-control / .icen-field / .icen-lift / .icen-surface-elevated / .icen-focus-ring / .icen-motion
63
+ * - 状态约定:[aria-disabled] / [aria-busy] / [data-icen-loading] / [data-icen-disabled] / [data-icen-invalid]
64
+ * - 触屏底线:@media (pointer: coarse) 下交互基元与控件目标尺寸 ≥40px
65
+ * (min-block/inline-size: max(var(--icen-density-input-height-md), 40px);WCAG 2.5.5 的工程折中)
66
+ * - 悬停守卫:.icen-lift 的 hover 抬升包在 @media (hover: hover) and (pointer: fine)(触屏关闭)
63
67
  */
64
68
 
65
69
  /* ══════════════════════════════════════════════════════════════
66
70
  icen 统一抽象层(--icen-* 原语 token)
67
71
  ───────────────────────────────────────────────────────────────
68
72
  所有组件消费的"原语级"变量:聚焦环、悬停、按下、禁用、过渡。
69
- 风格 profile(如 .style-retro)只需覆盖这里的少数变量,
70
- 即可让 56 个组件整体换肤;组件自身无需感知风格切换。
73
+ 原语只需覆盖这里的少数变量即可让组件整体换肤;组件自身无需感知风格切换。
71
74
  ══════════════════════════════════════════════════════════════ */
72
75
  :root {
73
76
  /* ── 聚焦环(focus-visible) ── */
74
- --icen-ring: 0 0 0 2px var(--token-bg), 0 0 0 4px color-mix(in srgb, var(--token-accent) 50%, transparent);
75
- --icen-ring-soft: 0 0 0 3px color-mix(in srgb, var(--token-accent) 16%, transparent);
76
- --icen-ring-error: 0 0 0 2px var(--token-bg), 0 0 0 4px color-mix(in srgb, var(--token-error) 50%, transparent);
77
- --icen-ring-success: 0 0 0 2px var(--token-bg), 0 0 0 4px color-mix(in srgb, var(--token-success) 50%, transparent);
78
- --icen-ring-warning: 0 0 0 2px var(--token-bg), 0 0 0 4px color-mix(in srgb, var(--token-warning) 50%, transparent);
77
+ --icen-ring: 0 0 0 2px var(--icen-token-bg), 0 0 0 4px color-mix(in srgb, var(--icen-token-accent) 50%, transparent);
78
+ --icen-ring-soft: 0 0 0 3px color-mix(in srgb, var(--icen-token-accent) 16%, transparent);
79
+ --icen-ring-error: 0 0 0 2px var(--icen-token-bg), 0 0 0 4px color-mix(in srgb, var(--icen-token-error) 50%, transparent);
80
+ --icen-ring-success: 0 0 0 2px var(--icen-token-bg), 0 0 0 4px color-mix(in srgb, var(--icen-token-success) 50%, transparent);
81
+ --icen-ring-warning: 0 0 0 2px var(--icen-token-bg), 0 0 0 4px color-mix(in srgb, var(--icen-token-warning) 50%, transparent);
79
82
  /* inset 聚焦环:空间受限的网格/表头单元格用内阴影聚焦(2px 内描边 + 3px 内光晕) */
80
- --icen-ring-inset: inset 0 0 0 2px color-mix(in srgb, var(--token-accent) 50%, transparent), inset 0 0 0 5px color-mix(in srgb, var(--token-accent) 14%, transparent);
83
+ --icen-ring-inset: inset 0 0 0 2px color-mix(in srgb, var(--icen-token-accent) 50%, transparent), inset 0 0 0 5px color-mix(in srgb, var(--icen-token-accent) 14%, transparent);
81
84
 
82
85
  /* ── 悬停 / 按下 / 禁用 ── */
83
- --icen-hover-border: color-mix(in srgb, var(--token-accent) 30%, var(--token-line));
84
- --icen-hover-border-strong: color-mix(in srgb, var(--token-accent) 55%, var(--token-line));
86
+ --icen-hover-border: color-mix(in srgb, var(--icen-token-accent) 30%, var(--icen-token-line));
87
+ --icen-hover-border-strong: color-mix(in srgb, var(--icen-token-accent) 55%, var(--icen-token-line));
85
88
  --icen-press: translateY(1px) scale(0.985);
86
89
  --icen-press-soft: translateY(1px);
87
90
  --icen-disabled-opacity: 0.5;
88
91
 
89
92
  /* ── 表单控件聚焦(wrapper 视角) ── */
90
- --icen-control-focus-shadow: var(--token-shadow-inset), 0 0 0 3px color-mix(in srgb, var(--token-accent) 14%, transparent);
91
- --icen-control-focus-border: color-mix(in srgb, var(--token-accent) 55%, var(--token-line));
92
- --icen-control-error-shadow: var(--token-shadow-inset), 0 0 0 3px color-mix(in srgb, var(--token-error) 16%, transparent);
93
+ --icen-control-focus-shadow: var(--icen-token-shadow-inset), 0 0 0 3px color-mix(in srgb, var(--icen-token-accent) 14%, transparent);
94
+ --icen-control-focus-border: color-mix(in srgb, var(--icen-token-accent) 55%, var(--icen-token-line));
95
+ --icen-control-error-shadow: var(--icen-token-shadow-inset), 0 0 0 3px color-mix(in srgb, var(--icen-token-error) 16%, transparent);
93
96
 
94
97
  /* ── 统一过渡(时长 + 缓动打包) ── */
95
- --icen-tx-fast: var(--duration-fast) var(--ease-out);
96
- --icen-tx-normal: var(--duration-normal) var(--ease-out);
97
- --icen-tx-slow: var(--duration-slow) var(--ease-out);
98
- --icen-tx-bounce: var(--duration-normal) var(--ease-bounce);
98
+ --icen-tx-fast: var(--icen-duration-fast) var(--icen-ease-out);
99
+ --icen-tx-normal: var(--icen-duration-normal) var(--icen-ease-out);
100
+ --icen-tx-slow: var(--icen-duration-slow) var(--icen-ease-out);
101
+ --icen-tx-bounce: var(--icen-duration-normal) var(--icen-ease-bounce);
99
102
  }
100
103
 
101
104
  /* ══════════════════════════════════════════════════════════════
@@ -113,11 +116,11 @@ html {
113
116
  }
114
117
 
115
118
  body {
116
- background: var(--token-bg);
117
- color: var(--token-text);
118
- font-family: "Numeric Math", var(--font-body);
119
+ background: var(--icen-token-bg);
120
+ color: var(--icen-token-text);
121
+ font-family: "Numeric Math", var(--icen-font-body);
119
122
  font-size: 14px;
120
- line-height: var(--line-height-body, 1.6);
123
+ line-height: var(--icen-line-height-body, 1.6);
121
124
  min-height: 100vh;
122
125
  -webkit-font-smoothing: antialiased;
123
126
  -moz-osx-font-smoothing: grayscale;
@@ -127,21 +130,21 @@ body {
127
130
  }
128
131
 
129
132
  a {
130
- color: var(--token-accent);
133
+ color: var(--icen-token-accent-text);
131
134
  text-decoration: none;
132
- transition: color var(--duration-fast) var(--ease-out);
135
+ transition: color var(--icen-duration-fast) var(--icen-ease-out);
133
136
  }
134
137
  a:hover { text-decoration: underline; text-underline-offset: 3px; }
135
138
  a:focus-visible {
136
- outline: 2px solid var(--token-accent);
139
+ outline: 2px solid var(--icen-token-accent);
137
140
  outline-offset: 2px;
138
- border-radius: var(--radius-xs);
141
+ border-radius: var(--icen-radius-xs);
139
142
  }
140
143
 
141
144
  code, pre {
142
- font-family: var(--font-mono);
143
- background: var(--token-bg-soft);
144
- border-radius: var(--radius-xs);
145
+ font-family: var(--icen-font-mono);
146
+ background: var(--icen-token-bg-soft);
147
+ border-radius: var(--icen-radius-xs);
145
148
  }
146
149
  code { padding: 1px 5px; }
147
150
  pre { padding: 12px 14px; overflow-x: auto; }
@@ -155,38 +158,37 @@ input, button, textarea, select { font: inherit; color: inherit; }
155
158
  /* 标题用 heading 栈(typography.css 已声明,这里只兜底防缺字体场景) */
156
159
  h1, h2, h3, h4, h5, h6 {
157
160
  margin: 0;
158
- line-height: var(--line-height-heading, 1.2);
161
+ line-height: var(--icen-line-height-heading, 1.2);
159
162
  }
160
163
 
161
164
  /* 段落兜底(消费项目可以覆盖) */
162
165
  p { margin: 0 0 1em; }
163
166
 
164
- /* 选区:亮色 accent 25%,retro 在 retro-effects.css 里硬覆盖 */
167
+ /* 选区随当前主题强调色变化;深色提高覆盖度。 */
165
168
  ::selection {
166
- background: color-mix(in srgb, var(--token-accent) 25%, transparent);
169
+ background: color-mix(in srgb, var(--icen-token-accent) 25%, transparent);
167
170
  color: inherit;
168
171
  }
169
- .dark ::selection {
170
- background: color-mix(in srgb, var(--token-accent) 35%, transparent);
172
+ [data-icen-theme="dark"] ::selection {
173
+ background: color-mix(in srgb, var(--icen-token-accent) 35%, transparent);
171
174
  }
172
175
 
173
176
  /* ══════════════════════════════════════════════════════════════
174
177
  全局滚动条:细薄、无上下箭头、贴 token
175
- 尺寸/轨道/滑块/按钮全部走 --token-scrollbar-*,
176
- 每个色彩预设可在自己的块里覆盖以表达品牌色差;
177
- .style-retro 在 style-profiles.css 里另有像素化硬覆盖。
178
+ 尺寸/轨道/滑块/按钮全部走 --icen-token-scrollbar-*,
179
+ 每个色彩预设可在自己的块里覆盖以表达品牌色差。
178
180
  ══════════════════════════════════════════════════════════════ */
179
181
 
180
- ::-webkit-scrollbar { width: var(--token-scrollbar-size); height: var(--token-scrollbar-size); }
181
- ::-webkit-scrollbar-track { background: var(--token-scrollbar-track); }
182
+ ::-webkit-scrollbar { width: var(--icen-token-scrollbar-size); height: var(--icen-token-scrollbar-size); }
183
+ ::-webkit-scrollbar-track { background: var(--icen-token-scrollbar-track); }
182
184
  ::-webkit-scrollbar-thumb {
183
- background: var(--token-scrollbar-thumb);
184
- border-radius: 999px;
185
+ background: var(--icen-token-scrollbar-thumb);
186
+ border-radius: var(--icen-radius-full);
185
187
  border: 2px solid transparent;
186
188
  background-clip: padding-box;
187
189
  }
188
190
  ::-webkit-scrollbar-thumb:hover {
189
- background: var(--token-scrollbar-thumb-hover);
191
+ background: var(--icen-token-scrollbar-thumb-hover);
190
192
  background-clip: padding-box;
191
193
  }
192
194
  ::-webkit-scrollbar-button,
@@ -194,26 +196,26 @@ p { margin: 0 0 1em; }
194
196
  ::-webkit-scrollbar-corner { background: transparent; }
195
197
  html {
196
198
  scrollbar-width: thin;
197
- scrollbar-color: var(--token-scrollbar-thumb) var(--token-scrollbar-track);
199
+ scrollbar-color: var(--icen-token-scrollbar-thumb) var(--icen-token-scrollbar-track);
198
200
  }
199
201
 
200
202
  /* ══════════════════════════════════════════════════════════════
201
203
  通用工具类
202
204
  ══════════════════════════════════════════════════════════════ */
203
205
 
204
- .mono { font-family: var(--font-mono); }
205
- .dim { color: var(--token-text-muted); }
206
- .faint { color: var(--token-text-faint); }
207
- .serif { font-family: var(--font-heading); }
206
+ .icen-mono { font-family: var(--icen-font-mono); }
207
+ .icen-dim { color: var(--icen-token-text-muted); }
208
+ .icen-faint { color: var(--icen-token-text-faint); }
209
+ .icen-serif { font-family: var(--icen-font-heading); }
208
210
 
209
211
  /* 数字密集区:tabular-nums + 数学字体 */
210
- .numeric {
211
- font-family: "Numeric Math", var(--font-mono);
212
+ .icen-numeric {
213
+ font-family: "Numeric Math", var(--icen-font-mono);
212
214
  font-variant-numeric: lining-nums tabular-nums;
213
215
  }
214
216
 
215
217
  /* 无障碍:屏幕阅读器可见、视觉隐藏 */
216
- .sr-only {
218
+ .icen-sr-only {
217
219
  position: absolute;
218
220
  width: 1px; height: 1px;
219
221
  padding: 0; margin: -1px;
@@ -225,23 +227,23 @@ html {
225
227
  }
226
228
 
227
229
  /* 跳转链接:默认视觉隐藏,聚焦时显形(无障碍要求) */
228
- .skip-link {
230
+ .icen-skip-link {
229
231
  position: fixed;
230
- top: var(--density-space-sm, 8px);
231
- left: var(--density-space-sm, 8px);
232
- z-index: var(--z-tooltip);
232
+ top: var(--icen-density-space-sm, 8px);
233
+ left: var(--icen-density-space-sm, 8px);
234
+ z-index: var(--icen-z-tooltip);
233
235
  padding: 8px 14px;
234
- background: var(--token-surface);
235
- color: var(--token-text);
236
- border: 1px solid var(--token-line);
237
- border-radius: var(--radius-sm);
238
- box-shadow: var(--token-shadow-elevated);
236
+ background: var(--icen-token-surface);
237
+ color: var(--icen-token-text);
238
+ border: 1px solid var(--icen-token-line);
239
+ border-radius: var(--icen-radius-sm);
240
+ box-shadow: var(--icen-token-shadow-elevated);
239
241
  transform: translateY(-150%);
240
- transition: transform var(--duration-normal) var(--ease-out);
242
+ transition: transform var(--icen-duration-normal) var(--icen-ease-out);
241
243
  }
242
- .skip-link:focus {
244
+ .icen-skip-link:focus {
243
245
  transform: translateY(0);
244
- outline: 2px solid var(--token-accent);
246
+ outline: 2px solid var(--icen-token-accent);
245
247
  outline-offset: 2px;
246
248
  }
247
249
 
@@ -257,19 +259,19 @@ html {
257
259
  dialog → 模态对话框 + backdrop
258
260
  popover → 弹出层/下拉菜单(高于 dialog 因为常常 portal 出去)
259
261
  tooltip → 工具提示
260
- fx → 效果层(retro 扫描线/噪点等,永远在最上)
262
+ fx → 效果层(永远在最上)
261
263
  ══════════════════════════════════════════════════════════════ */
262
264
  :root {
263
- --z-base: 0;
264
- --z-raised: 10;
265
- --z-sticky: 50;
266
- --z-chrome: 200;
267
- --z-toast: 400;
268
- --z-banner: 450;
269
- --z-dialog: 500;
270
- --z-popover: 620;
271
- --z-tooltip: 700;
272
- --z-fx: 1000;
265
+ --icen-z-base: 0;
266
+ --icen-z-raised: 10;
267
+ --icen-z-sticky: 50;
268
+ --icen-z-chrome: 200;
269
+ --icen-z-toast: 400;
270
+ --icen-z-banner: 450;
271
+ --icen-z-dialog: 500;
272
+ --icen-z-popover: 620;
273
+ --icen-z-tooltip: 700;
274
+ --icen-z-fx: 1000;
273
275
  }
274
276
 
275
277
  /* ══════════════════════════════════════════════════════════════
@@ -277,12 +279,12 @@ html {
277
279
  icen-pop-in → 弹层进场(scale .96 + translateY -4px)
278
280
  icen-spin → 旋转(spinner / 加载态)
279
281
  icen-skeleton-pulse → 骨架脉冲
280
- 注:menu.css / popover.css 保留自己的 scale(.95)±8px 四方向版
281
- (方向语义不同:按 data-side 反向位移),不并入 icen-pop-in。
282
+ 注:menu.css / popover.css 保留自己的 scale(.985)±3px 四方向版
283
+ (方向语义不同:按 data-icen-side 反向位移),不并入 icen-pop-in。
282
284
  ══════════════════════════════════════════════════════════════ */
283
285
  @keyframes icen-pop-in {
284
- from { opacity: 0; transform: scale(0.96) translateY(-4px); }
285
- to { opacity: 1; transform: scale(1) translateY(0); }
286
+ from { opacity: 0; }
287
+ to { opacity: 1; }
286
288
  }
287
289
  @keyframes icen-spin {
288
290
  to { transform: rotate(360deg); }
@@ -295,14 +297,13 @@ html {
295
297
  /* ══════════════════════════════════════════════════════════════
296
298
  交互基元(全组件地基)
297
299
  规格:源 self-contained,命名空间不含 opengal 的 og-/vn- 前缀。
298
- style-profiles.css 的 .style-retro 段会按 .pressable/.control/.lift
299
- 这些类名施加像素化覆盖;改名前请同步修 style-profiles.css。
300
+ 原语通过 --icen-* 反馈变量覆盖这些基元,类名契约保持稳定。
300
301
  ══════════════════════════════════════════════════════════════ */
301
302
 
302
- /* ── .pressable — 可按压(按钮、卡片按钮、tag close 等)
303
+ /* ── .icen-pressable — 可按压(按钮、卡片按钮、tag close 等)
303
304
  hover:顶部高光 ::after 渐入;focus-visible:同样高光 + 描边
304
305
  active:下陷 + 微缩;aria-busy:减淡;disabled / aria-disabled:50% + 禁手势 */
305
- .pressable {
306
+ .icen-pressable {
306
307
  position: relative;
307
308
  overflow: hidden;
308
309
  will-change: transform;
@@ -314,7 +315,7 @@ html {
314
315
  opacity var(--icen-tx-normal),
315
316
  transform var(--icen-tx-normal);
316
317
  }
317
- .pressable::after {
318
+ .icen-pressable::after {
318
319
  content: '';
319
320
  position: absolute;
320
321
  inset: 0;
@@ -322,129 +323,136 @@ html {
322
323
  opacity: 0;
323
324
  pointer-events: none;
324
325
  background: linear-gradient(180deg,
325
- color-mix(in srgb, var(--token-surface) 24%, transparent),
326
+ color-mix(in srgb, var(--icen-token-surface) 24%, transparent),
326
327
  transparent 46%);
327
328
  transition: opacity var(--icen-tx-normal);
328
329
  }
329
- .pressable:hover::after,
330
- .pressable:focus-visible::after { opacity: 1; }
331
- .pressable:focus-visible {
330
+ .icen-pressable:hover::after,
331
+ .icen-pressable:focus-visible::after { opacity: 1; }
332
+ .icen-pressable:focus-visible {
332
333
  outline: none;
333
334
  box-shadow: var(--icen-ring);
334
335
  }
335
- .pressable:active {
336
+ .icen-pressable:active {
336
337
  transform: var(--icen-press);
337
338
  }
338
- .pressable[aria-busy='true'],
339
- .pressable[data-loading] {
339
+ .icen-pressable[aria-busy='true'],
340
+ .icen-pressable[data-icen-loading] {
340
341
  cursor: progress;
341
342
  opacity: 0.7;
342
343
  pointer-events: none;
343
344
  }
344
- .pressable:disabled,
345
- .pressable[aria-disabled='true'],
346
- .pressable[data-disabled] {
345
+ .icen-pressable:disabled,
346
+ .icen-pressable[aria-disabled='true'],
347
+ .icen-pressable[data-icen-disabled] {
347
348
  transform: none;
348
349
  opacity: var(--icen-disabled-opacity);
349
350
  cursor: not-allowed;
350
351
  pointer-events: none;
351
352
  }
352
- .pressable:disabled::after,
353
- .pressable[aria-disabled='true']::after,
354
- .pressable[data-disabled]::after { display: none; }
353
+ .icen-pressable:disabled::after,
354
+ .icen-pressable[aria-disabled='true']::after,
355
+ .icen-pressable[data-icen-disabled]::after { display: none; }
355
356
 
356
- /* ── .control — 表单控件 wrapper 基元(包裹原生 input/textarea/select)
357
+ /* ── .icen-control — 表单控件 wrapper 基元(包裹原生 input/textarea/select)
357
358
  hover:边框稍深;focus-within:内嵌阴影 + accent 3px 光晕
358
- :invalid / [data-invalid]:error 色边框 + error 色光晕 */
359
- .control {
359
+ :invalid / [data-icen-invalid]:error 色边框 + error 色光晕 */
360
+ .icen-control {
360
361
  transition: background-color var(--icen-tx-normal),
361
362
  border-color var(--icen-tx-normal),
362
363
  box-shadow var(--icen-tx-normal);
363
364
  }
364
- .control:hover {
365
+ .icen-control:hover {
365
366
  border-color: var(--icen-hover-border);
366
367
  }
367
- .control:focus-within {
368
+ .icen-control:focus-within {
368
369
  box-shadow: var(--icen-control-focus-shadow);
369
370
  border-color: var(--icen-control-focus-border);
370
371
  }
371
- .control:where(:has(:invalid), [data-invalid='true']) {
372
- border-color: var(--token-error);
372
+ .icen-control:where(:has(:invalid), [data-icen-invalid='true']) {
373
+ border-color: var(--icen-token-error);
373
374
  }
374
- .control:where(:has(:invalid), [data-invalid='true']):focus-within {
375
+ .icen-control:where(:has(:invalid), [data-icen-invalid='true']):focus-within {
375
376
  box-shadow: var(--icen-control-error-shadow);
376
- border-color: var(--token-error);
377
+ border-color: var(--icen-token-error);
377
378
  }
378
379
  /* 内部裸 input/textarea/select 不再有自己的边框/阴影,交给 wrapper 表达 */
379
- .control > input:not([type='checkbox']):not([type='radio']):not([type='file']),
380
- .control > textarea,
381
- .control > select {
380
+ .icen-control > input:not([type='checkbox']):not([type='radio']):not([type='file']),
381
+ .icen-control > textarea,
382
+ .icen-control > select {
382
383
  background: transparent;
383
384
  border: 0;
384
385
  outline: none;
385
386
  box-shadow: none;
386
387
  }
387
388
 
388
- /* ── .field — 带 label / hint / error 的表单字段容器(取代旧 .vn-editable-field)
389
+ /* ── .icen-field — 带 label / hint / error 的表单字段容器
389
390
  契约:
390
- <label class="field">
391
- <span class="field-label">姓名</span>
392
- <span class="control"><input /></span>
393
- <span class="field-hint">必填</span>
394
- <span class="field-error">错误</span>
391
+ <label class="icen-field">
392
+ <span class="icen-field-label">姓名</span>
393
+ <span class="icen-control"><icen-input /></span>
394
+ <span class="icen-field-hint">必填</span>
395
+ <span class="icen-field-error">错误</span>
395
396
  </label> */
396
- .field {
397
+ .icen-field {
397
398
  display: flex;
398
399
  flex-direction: column;
399
- gap: var(--density-space-xs);
400
+ gap: var(--icen-density-space-xs);
400
401
  }
401
- .field-label {
402
- font-size: var(--density-font-size-sm);
403
- color: var(--token-text-muted);
402
+ .icen-field-label {
403
+ font-size: var(--icen-density-font-size-sm);
404
+ color: var(--icen-token-text-muted);
404
405
  letter-spacing: 0.02em;
405
406
  }
406
- .field-hint {
407
- font-size: var(--density-font-size-xs);
408
- color: var(--token-text-faint);
407
+ .icen-field-hint {
408
+ font-size: var(--icen-density-font-size-xs);
409
+ color: var(--icen-token-text-faint);
409
410
  }
410
- .field-error {
411
- font-size: var(--density-font-size-xs);
412
- color: var(--token-error);
411
+ .icen-field-error {
412
+ font-size: var(--icen-density-font-size-xs);
413
+ color: var(--icen-token-error);
413
414
  }
414
- .field[data-invalid='true'] .field-label { color: var(--token-error); }
415
+ .icen-field[data-icen-invalid='true'] .icen-field-label { color: var(--icen-token-error); }
415
416
 
416
- /* ── .lift — 可交互卡片悬停浮起(pressable 的轻量版,无 ::after 高光)
417
- hover / focus-within:上移 1px + accent 边 + card 阴影 */
418
- .lift {
417
+ /* ── .icen-lift — 可交互卡片悬停浮起(pressable 的轻量版,无 ::after 高光)
418
+ hover:仅在可悬停设备生效(触屏关闭抬升,AGENTS 动效守卫);
419
+ focus-within:全设备生效(键盘/触屏焦点同样给浮起反馈) */
420
+ .icen-lift {
419
421
  transition: border-color var(--icen-tx-slow),
420
422
  box-shadow var(--icen-tx-slow),
421
423
  transform var(--icen-tx-slow);
422
424
  }
423
- .lift:hover,
424
- .lift:focus-within {
425
+ @media (hover: hover) and (pointer: fine) {
426
+ .icen-lift:hover {
427
+ transform: translateY(-1px);
428
+ border-color: color-mix(in srgb, var(--icen-token-accent) 26%, var(--icen-token-outline-soft));
429
+ box-shadow: var(--icen-token-shadow-card);
430
+ }
431
+ }
432
+ .icen-lift:focus-within {
425
433
  transform: translateY(-1px);
426
- border-color: color-mix(in srgb, var(--token-accent) 26%, var(--token-outline-soft));
427
- box-shadow: var(--token-shadow-card);
434
+ border-color: color-mix(in srgb, var(--icen-token-accent) 26%, var(--icen-token-outline-soft));
435
+ box-shadow: var(--icen-token-shadow-card);
428
436
  }
429
437
 
430
- /* ── .surface-elevated — 提升的静态表面(非交互卡片)
438
+ /* ── .icen-surface-elevated — 提升的静态表面(非交互卡片)
431
439
  用于不需要 hover 反馈但需要脱离背景的面板/对话框内嵌区域 */
432
- .surface-elevated {
433
- background: var(--token-surface);
434
- border: 1px solid var(--token-line-soft);
435
- border-radius: var(--radius-md);
436
- box-shadow: var(--token-shadow-card);
440
+ .icen-surface-elevated {
441
+ background: var(--icen-token-surface);
442
+ border: 1px solid var(--icen-token-line-soft);
443
+ border-radius: var(--icen-radius-md);
444
+ box-shadow: var(--icen-token-shadow-card);
437
445
  }
438
446
 
439
- /* ── .focus-ring — 显式聚焦环工具类(ring-2 + offset-1 等价) */
440
- .focus-ring:focus-visible {
447
+ /* ── .icen-focus-ring — 显式聚焦环工具类(ring-2 + offset-1 等价) */
448
+ .icen-focus-ring:focus-visible {
441
449
  outline: none;
442
450
  box-shadow: var(--icen-ring);
443
451
  }
444
452
 
445
- /* ── .motion — 显式动画工具类(仅在 prefers-reduced-motion: no-preference 时生效) */
453
+ /* ── .icen-motion — 显式动画工具类(仅在 prefers-reduced-motion: no-preference 时生效) */
446
454
  @media (prefers-reduced-motion: no-preference) {
447
- .motion { transition: all var(--icen-tx-normal); }
455
+ .icen-motion { transition: all var(--icen-tx-normal); }
448
456
  }
449
457
 
450
458
  /* ══════════════════════════════════════════════════════════════
@@ -454,26 +462,25 @@ html {
454
462
  /* reduced-motion:所有动画/过渡压缩到 ~0ms(保留可访问性最小可视信号) */
455
463
  @media (prefers-reduced-motion: reduce) {
456
464
  *, *::before, *::after {
457
- animation-duration: 0.01ms !important;
458
- animation-iteration-count: 1 !important;
459
- transition-duration: 0.01ms !important;
460
- scroll-behavior: auto !important;
465
+ animation-duration: 0.01ms !important; /* guard:allow-important 动效守卫:降级媒体查询需压制组件动画 */
466
+ animation-iteration-count: 1 !important; /* guard:allow-important 动效守卫:降级媒体查询需压制组件动画 */
467
+ transition-duration: 0.01ms !important; /* guard:allow-important 动效守卫:降级媒体查询需压制组件动画 */
468
+ scroll-behavior: auto !important; /* guard:allow-important 动效守卫:降级媒体查询需压制组件动画 */
461
469
  }
462
470
  }
463
471
 
464
- /* 触屏设备(无精细指针):关闭 hover 抬升、压低 pressable scale */
472
+ /* 触屏设备(无精细指针):压低 pressable 按下形变(hover 抬升已由 hover 守卫关闭) */
465
473
  @media (pointer: coarse) {
466
- .lift:hover { transform: none; }
467
- .pressable:active { transform: translateY(0) scale(0.99); }
474
+ .icen-pressable:active { transform: translateY(0) scale(0.99); }
468
475
  }
469
476
 
470
477
  /* 高对比度模式(Windows High Contrast / 强制 colors) */
471
478
  @media (forced-colors: active) {
472
- .pressable, .control, .lift, .surface-elevated, .focus-ring:focus-visible {
479
+ .icen-pressable, .icen-control, .icen-lift, .icen-surface-elevated, .icen-focus-ring:focus-visible {
473
480
  forced-color-adjust: none;
474
481
  }
475
- .focus-ring:focus-visible,
476
- .pressable:focus-visible {
482
+ .icen-focus-ring:focus-visible,
483
+ .icen-pressable:focus-visible {
477
484
  outline: 2px solid Highlight;
478
485
  outline-offset: 2px;
479
486
  }
@@ -482,15 +489,37 @@ html {
482
489
  /* 打印:去掉阴影/背景/动效,节约墨水并避免打印截断 */
483
490
  @media print {
484
491
  *, *::before, *::after {
485
- background: transparent !important;
486
- color: #000 !important;
487
- box-shadow: none !important;
488
- text-shadow: none !important;
492
+ background: transparent !important; /* guard:allow-important 打印样式需确定性覆盖 */
493
+ color: #000 !important; /* guard:allow-important 打印样式需确定性覆盖 */
494
+ box-shadow: none !important; /* guard:allow-important 打印样式需确定性覆盖 */
495
+ text-shadow: none !important; /* guard:allow-important 打印样式需确定性覆盖 */
489
496
  }
490
497
  body { font-size: 12pt; line-height: 1.4; }
491
498
  a, a:visited { text-decoration: underline; }
492
499
  a[href]::after { content: ' (' attr(href) ')'; font-size: 90%; }
493
500
  pre, blockquote { border: 1px solid #999; page-break-inside: avoid; }
494
501
  h1, h2, h3 { page-break-after: avoid; }
495
- .pressable, .lift, .surface-elevated { box-shadow: none !important; transform: none !important; }
502
+ .icen-pressable, .icen-lift, .icen-surface-elevated { box-shadow: none !important; /* guard:allow-important 状态/守卫覆盖需压制变体优先级 */ transform: none !important; }
503
+ }
504
+
505
+ /* ══════════════════════════════════════════════════════════════
506
+ 触屏目标尺寸底线(@media pointer: coarse)
507
+ ───────────────────────────────────────────────────────────────
508
+ 交互基元与控件的可点区域在触屏下抬到 ≥40px:WCAG 2.5.5(Target
509
+ Size AAA 44px)的工程折中。用 max() 保住密度 token 的调节权——
510
+ 密度档高于 40px 时仍按 token 走;逻辑属性形态(block/inline)
511
+ 与全库书写方向自洽。块与内联同时给底线(方形命中区)。
512
+ ══════════════════════════════════════════════════════════════ */
513
+ @media (pointer: coarse) {
514
+ .icen-pressable,
515
+ .icen-control,
516
+ .icen-field,
517
+ .icen-lift,
518
+ button.icen-btn,
519
+ a[role='button'] {
520
+ min-block-size: max(var(--icen-density-input-height-md), 40px);
521
+ min-inline-size: max(var(--icen-density-input-height-md), 40px);
522
+ }
523
+ }
524
+
496
525
  }