@xihan-ui/styles 1.0.0-alpha.3 → 1.0.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 (96) hide show
  1. package/CHANGELOG.md +1730 -0
  2. package/css/accordion.css +25 -2
  3. package/css/alert.css +13 -9
  4. package/css/anchor.css +1 -1
  5. package/css/avatar-group.css +5 -1
  6. package/css/avatar.css +6 -0
  7. package/css/back-top.css +6 -0
  8. package/css/badge.css +94 -36
  9. package/css/breadcrumb.css +1 -1
  10. package/css/button-group.css +4 -0
  11. package/css/button.css +6 -0
  12. package/css/calendar.css +39 -13
  13. package/css/card.css +15 -6
  14. package/css/cascader.css +29 -23
  15. package/css/checkbox-group.css +38 -10
  16. package/css/checkbox.css +21 -10
  17. package/css/collapsible.css +7 -1
  18. package/css/color-picker.css +22 -2
  19. package/css/combobox.css +18 -7
  20. package/css/context-menu.css +17 -6
  21. package/css/date-field.css +2 -2
  22. package/css/date-picker.css +27 -17
  23. package/css/descriptions.css +9 -3
  24. package/css/dialog.css +7 -1
  25. package/css/drawer.css +15 -5
  26. package/css/dynamic-input.css +7 -0
  27. package/css/ellipsis.css +6 -0
  28. package/css/empty-state.css +16 -6
  29. package/css/field.css +7 -0
  30. package/css/file-upload.css +1 -1
  31. package/css/flex.css +13 -7
  32. package/css/float-button.css +7 -0
  33. package/css/floating-panel.css +6 -0
  34. package/css/grid.css +11 -5
  35. package/css/heatmap.css +3 -2
  36. package/css/highlight.css +1 -1
  37. package/css/hotkeys.css +1 -1
  38. package/css/hover-card.css +3 -0
  39. package/css/image-cropper.css +4 -2
  40. package/css/image-viewer.css +18 -5
  41. package/css/json-viewer.css +34 -1
  42. package/css/layout.css +15 -7
  43. package/css/list.css +14 -5
  44. package/css/listbox.css +4 -2
  45. package/css/loading-bar.css +5 -4
  46. package/css/log.css +6 -2
  47. package/css/masonry.css +5 -5
  48. package/css/mention.css +13 -3
  49. package/css/menu.css +16 -5
  50. package/css/menubar.css +14 -6
  51. package/css/navigation-menu.css +2 -2
  52. package/css/notification.css +377 -0
  53. package/css/number-field.css +9 -3
  54. package/css/page-header.css +7 -0
  55. package/css/pagination.css +158 -1
  56. package/css/password-input.css +4 -4
  57. package/css/pin-input.css +2 -2
  58. package/css/popconfirm.css +9 -2
  59. package/css/popover.css +3 -0
  60. package/css/popselect.css +24 -4
  61. package/css/progress.css +8 -2
  62. package/css/radio-group.css +17 -6
  63. package/css/rating.css +2 -2
  64. package/css/result.css +15 -5
  65. package/css/scrollbar.css +3 -0
  66. package/css/segmented.css +1 -1
  67. package/css/select.css +25 -7
  68. package/css/side-nav.css +16 -5
  69. package/css/slider.css +4 -2
  70. package/css/space.css +6 -6
  71. package/css/steps.css +6 -6
  72. package/css/switch.css +9 -2
  73. package/css/table.css +16 -8
  74. package/css/tabs.css +9 -1
  75. package/css/tag.css +3 -1
  76. package/css/tags-input.css +3 -3
  77. package/css/text-field.css +3 -3
  78. package/css/thread.css +10 -2
  79. package/css/time-field.css +2 -2
  80. package/css/time-picker.css +6 -6
  81. package/css/timeline.css +7 -7
  82. package/css/toast.css +103 -53
  83. package/css/toggle-group.css +30 -4
  84. package/css/toggle.css +6 -0
  85. package/css/tone.css +47 -17
  86. package/css/tooltip.css +7 -1
  87. package/css/tour.css +9 -3
  88. package/css/transfer.css +38 -12
  89. package/css/tree-select.css +30 -5
  90. package/css/tree.css +46 -4
  91. package/css/typography.css +1 -1
  92. package/css/undefined.css +1 -0
  93. package/index.css +1 -1
  94. package/index.unlayered.css +1746 -505
  95. package/package.json +3 -3
  96. package/css/toaster.css +0 -74
@@ -56,9 +56,13 @@
56
56
  /* 一排叠放的头像:后一枚压在前一枚上。
57
57
  组内共用的直径与字号在容器上写一次,沿继承流给每一枚;自己写了档位的那一枚仍按自己的档走 */
58
58
  [data-scope='avatar-group'][data-part='root'] {
59
+ /* 组件内那几档层号只在自己人之间排序:建一个层叠上下文把它们关起来,
60
+ 既不让页面上的层号插进来,也不让它们漏出去压住别人 */
61
+ isolation: isolate;
62
+
59
63
  /* 私有槽位:整组共用的直径、字号与叠放量,换档只改这三个 */
60
64
  --xh-_avatar-group-size: var(--xh-avatar-group-size, var(--xh-control-h-md));
61
- --xh-_avatar-group-font-size: var(--xh-avatar-group-font-size, var(--xh-text-secondary-size));
65
+ --xh-_avatar-group-font-size: var(--xh-avatar-group-font-size, var(--xh-control-caption-md));
62
66
  --xh-_avatar-group-overlap: var(--xh-avatar-group-overlap, var(--xh-space-2_5));
63
67
 
64
68
  /* 流给组内每一枚 */
@@ -215,6 +219,12 @@
215
219
  mask: var(--xh-glyph-mark-chevron-up) center / contain no-repeat;
216
220
  }
217
221
 
222
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
223
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
224
+ [data-scope='back-top'][data-part='trigger'][hidden] {
225
+ display: none;
226
+ }
227
+
218
228
  /* styles/button-group.css */
219
229
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
220
230
  [data-scope='button-group'] {
@@ -225,6 +235,10 @@
225
235
  排布只能读 data-orientation——role=group 不收 aria-orientation,连接层根本不输出它。
226
236
  圆角槽位在容器上先收成 0,组内每段都取得到,两端的圆角再逐段补回来 */
227
237
  [data-scope='button-group'][data-part='root'] {
238
+ /* 组件内那几档层号只在自己人之间排序:建一个层叠上下文把它们关起来,
239
+ 既不让页面上的层号插进来,也不让它们漏出去压住别人 */
240
+ isolation: isolate;
241
+
228
242
  --xh-button-radius: 0;
229
243
 
230
244
  display: inline-flex;
@@ -392,7 +406,7 @@
392
406
  --xh-_descriptions-label-gap: var(--xh-space-2);
393
407
  --xh-_descriptions-py: var(--xh-space-2);
394
408
  --xh-_descriptions-px: var(--xh-space-3);
395
- --xh-_descriptions-font-size: var(--xh-text-body-size);
409
+ --xh-_descriptions-font-size: var(--xh-control-font-md);
396
410
  /* 标签在左时那一列的宽度:收到最长的那个标签 */
397
411
  --xh-_descriptions-label-w: max-content;
398
412
 
@@ -497,9 +511,9 @@
497
511
  > [data-scope='descriptions'][data-part='item'] {
498
512
  padding-block: var(--xh-descriptions-item-py, var(--xh-_descriptions-py));
499
513
  padding-inline: var(--xh-descriptions-item-px, var(--xh-_descriptions-px));
500
- border-block-start: var(--xh-stroke-thin) solid var(--xh-descriptions-border, var(--xh-border-subtle));
514
+ border-block-start: var(--xh-stroke-thin) solid var(--xh-descriptions-divider, var(--xh-border-subtle));
501
515
  /* 每行一组时左边没有邻居,宽度按列数补回来 */
502
- border-inline-start: 0 solid var(--xh-descriptions-border, var(--xh-border-subtle));
516
+ border-inline-start: 0 solid var(--xh-descriptions-divider, var(--xh-border-subtle));
503
517
  }
504
518
 
505
519
  [data-scope='descriptions'][data-part='root'][data-bordered]
@@ -583,6 +597,12 @@
583
597
  border-block-start-width: 0;
584
598
  }
585
599
 
600
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
601
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
602
+ [data-scope='descriptions'][data-part='item'][hidden] {
603
+ display: none;
604
+ }
605
+
586
606
  /* styles/download-trigger.css */
587
607
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
588
608
  [data-scope='download-trigger'] {
@@ -872,6 +892,13 @@
872
892
  mask: var(--xh-glyph-mark-close) center / contain no-repeat;
873
893
  }
874
894
 
895
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
896
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
897
+ [data-scope='dynamic-input'][data-part='item-content'][hidden],
898
+ [data-scope='dynamic-input'][data-part='item-action'][hidden] {
899
+ display: none;
900
+ }
901
+
875
902
  /* styles/ellipsis.css */
876
903
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
877
904
  [data-scope='ellipsis'] {
@@ -918,6 +945,12 @@
918
945
  outline-offset: var(--xh-ring-offset);
919
946
  }
920
947
 
948
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
949
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
950
+ [data-scope='ellipsis'][data-part='root'][hidden] {
951
+ display: none;
952
+ }
953
+
921
954
  /* styles/fieldset.css */
922
955
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
923
956
  [data-scope='fieldset'] {
@@ -1006,11 +1039,11 @@
1006
1039
  }
1007
1040
 
1008
1041
  /* —— 方向 —— */
1009
- [data-scope='flex'][data-part='root'][data-direction='row'] {
1042
+ [data-scope='flex'][data-part='root'][data-orientation='horizontal'] {
1010
1043
  flex-direction: row;
1011
1044
  }
1012
1045
 
1013
- [data-scope='flex'][data-part='root'][data-direction='column'] {
1046
+ [data-scope='flex'][data-part='root'][data-orientation='vertical'] {
1014
1047
  flex-direction: column;
1015
1048
  }
1016
1049
 
@@ -1068,23 +1101,29 @@
1068
1101
  /* —— 间距档位 —— */
1069
1102
  /* 每一档指向一个间距令牌,折行时行与行之间也吃这份间距 */
1070
1103
  [data-scope='flex'][data-part='root'][data-gap='xs'] {
1071
- gap: var(--xh-flex-gap, var(--xh-space-1));
1104
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-xs));
1072
1105
  }
1073
1106
 
1074
1107
  [data-scope='flex'][data-part='root'][data-gap='sm'] {
1075
- gap: var(--xh-flex-gap, var(--xh-space-2));
1108
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-sm));
1076
1109
  }
1077
1110
 
1078
1111
  [data-scope='flex'][data-part='root'][data-gap='md'] {
1079
- gap: var(--xh-flex-gap, var(--xh-space-3));
1112
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-md));
1080
1113
  }
1081
1114
 
1082
1115
  [data-scope='flex'][data-part='root'][data-gap='lg'] {
1083
- gap: var(--xh-flex-gap, var(--xh-space-4));
1116
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-lg));
1084
1117
  }
1085
1118
 
1086
1119
  [data-scope='flex'][data-part='root'][data-gap='xl'] {
1087
- gap: var(--xh-flex-gap, var(--xh-space-6));
1120
+ gap: var(--xh-flex-gap, var(--xh-layout-gap-xl));
1121
+ }
1122
+
1123
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
1124
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
1125
+ [data-scope='flex'][data-part='root'][hidden] {
1126
+ display: none;
1088
1127
  }
1089
1128
 
1090
1129
  /* styles/float-button.css */
@@ -1228,6 +1267,13 @@
1228
1267
  mask: var(--xh-glyph-mark-plus) center / contain no-repeat;
1229
1268
  }
1230
1269
 
1270
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
1271
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
1272
+ [data-scope='float-button'][data-part='root'][hidden],
1273
+ [data-scope='float-button'][data-part='trigger'][hidden] {
1274
+ display: none;
1275
+ }
1276
+
1231
1277
  /* styles/floating-panel.css */
1232
1278
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
1233
1279
  [data-scope='floating-panel'] {
@@ -1247,6 +1293,12 @@
1247
1293
  display: contents;
1248
1294
  }
1249
1295
 
1296
+ /* 浮层被搬到 portal 落点,继承不到 root 上的槽:这把尺在被搬走的那一侧再声明一次,
1297
+ 关闭钮与条目里作者塞的图标才和皮肤画的兜底字形一样大 */
1298
+ [data-scope='floating-panel'][data-part='content'] {
1299
+ --xh-icon-size: var(--xh-floating-panel-icon-size, var(--xh-glyph-size-text));
1300
+ }
1301
+
1250
1302
  [data-scope='floating-panel'][data-part='root'][hidden] {
1251
1303
  display: none;
1252
1304
  }
@@ -1876,23 +1928,23 @@
1876
1928
  /* —— 间距档位 —— */
1877
1929
  /* 每一档指向一个间距令牌,行与行之间也吃这同一份间距 */
1878
1930
  [data-scope='grid'][data-part='root'][data-gap='xs'] {
1879
- gap: var(--xh-grid-gap, var(--xh-space-1));
1931
+ gap: var(--xh-grid-gap, var(--xh-layout-gap-xs));
1880
1932
  }
1881
1933
 
1882
1934
  [data-scope='grid'][data-part='root'][data-gap='sm'] {
1883
- gap: var(--xh-grid-gap, var(--xh-space-2));
1935
+ gap: var(--xh-grid-gap, var(--xh-layout-gap-sm));
1884
1936
  }
1885
1937
 
1886
1938
  [data-scope='grid'][data-part='root'][data-gap='md'] {
1887
- gap: var(--xh-grid-gap, var(--xh-space-3));
1939
+ gap: var(--xh-grid-gap, var(--xh-layout-gap-md));
1888
1940
  }
1889
1941
 
1890
1942
  [data-scope='grid'][data-part='root'][data-gap='lg'] {
1891
- gap: var(--xh-grid-gap, var(--xh-space-4));
1943
+ gap: var(--xh-grid-gap, var(--xh-layout-gap-lg));
1892
1944
  }
1893
1945
 
1894
1946
  [data-scope='grid'][data-part='root'][data-gap='xl'] {
1895
- gap: var(--xh-grid-gap, var(--xh-space-6));
1947
+ gap: var(--xh-grid-gap, var(--xh-layout-gap-xl));
1896
1948
  }
1897
1949
 
1898
1950
  /* —— 块向对齐 —— */
@@ -2038,6 +2090,12 @@
2038
2090
  --xh-_grid-start: 12;
2039
2091
  }
2040
2092
 
2093
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
2094
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
2095
+ [data-scope='grid'][data-part='root'][hidden] {
2096
+ display: none;
2097
+ }
2098
+
2041
2099
  /* styles/heatmap.css */
2042
2100
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
2043
2101
  [data-scope='heatmap'] {
@@ -2161,10 +2219,11 @@
2161
2219
  gap: var(--xh-heatmap-grid-gap, var(--xh-_heatmap-gap));
2162
2220
  }
2163
2221
 
2164
- /* 网格自己只在没有格子可落焦点时才占 Tab 位,那几帧里也该看得出焦点在哪 */
2222
+ /* 网格自己只在没有格子可落焦点时才占 Tab 位,那几帧里也该看得出焦点在哪。
2223
+ 环往内收:网格铺满 root,root 那层 overflow-x: auto 会把画在外沿的环裁掉 */
2165
2224
  [data-scope='heatmap'][data-part='grid']:focus-visible {
2166
2225
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
2167
- outline-offset: var(--xh-ring-offset);
2226
+ outline-offset: calc(-1 * var(--xh-ring-width));
2168
2227
  }
2169
2228
 
2170
2229
  [data-scope='heatmap'][data-part='row'] {
@@ -2463,7 +2522,7 @@
2463
2522
  /* 浏览器给 mark 的默认底色是一个固定的亮黄,暗色主题下压在深底上刺眼、
2464
2523
  配的黑字也不随主题走;这里整份换成随主题走的品牌淡底 */
2465
2524
  [data-scope='highlight'][data-part='mark'] {
2466
- padding-inline: var(--xh-space-0_5);
2525
+ padding-inline: var(--xh-highlight-mark-px, var(--xh-space-0_5));
2467
2526
  border-radius: var(--xh-highlight-radius, var(--xh-shape-inset));
2468
2527
  background: var(--xh-highlight-bg, var(--xh-bg-brand-subtle));
2469
2528
  color: var(--xh-highlight-fg, var(--xh-fg-brand-strong));
@@ -2483,7 +2542,7 @@
2483
2542
  /* 一排键帽连着连接符。整块不换行:一组组合被折成两行就读不出是一组了 */
2484
2543
  [data-scope='hotkeys'][data-part='root'] {
2485
2544
  /* 尺寸档只换这两个私有槽,键帽从 root 继承它们,换档不必给每个部件各写一条选择器 */
2486
- --xh-_hotkeys-font-size: var(--xh-text-secondary-size);
2545
+ --xh-_hotkeys-font-size: var(--xh-control-caption-md);
2487
2546
  --xh-_hotkeys-key-px: var(--xh-space-1);
2488
2547
 
2489
2548
  display: inline-flex;
@@ -2704,9 +2763,10 @@
2704
2763
  cursor: not-allowed;
2705
2764
  }
2706
2765
 
2766
+ /* 环往内收:裁切框长在视口里,视口那层 overflow: hidden 会把画在外沿的环裁掉 */
2707
2767
  [data-scope='image-cropper'][data-part='crop-area']:focus-visible {
2708
2768
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
2709
- outline-offset: var(--xh-ring-offset);
2769
+ outline-offset: calc(-1 * var(--xh-ring-width));
2710
2770
  }
2711
2771
 
2712
2772
  /* 三分构图参考线:两条竖线、两条横线,落点写死在三分处,不占节点、不吃指针。
@@ -2769,9 +2829,10 @@
2769
2829
  content: '';
2770
2830
  }
2771
2831
 
2832
+ /* 与裁切框同一口径:把手也在视口的 overflow: hidden 里,环画在外沿会被裁掉 */
2772
2833
  [data-scope='image-cropper'][data-part='crop-handle']:focus-visible {
2773
2834
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
2774
- outline-offset: var(--xh-ring-offset);
2835
+ outline-offset: calc(-1 * var(--xh-ring-width));
2775
2836
  }
2776
2837
 
2777
2838
  [data-scope='image-cropper'][data-part='crop-handle'][data-resizing] {
@@ -2903,7 +2964,7 @@
2903
2964
  /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
2904
2965
  --xh-icon-size: var(--xh-json-viewer-icon-size, var(--xh-glyph-size-text));
2905
2966
 
2906
- --xh-_json-viewer-font-size: var(--xh-text-secondary-size);
2967
+ --xh-_json-viewer-font-size: var(--xh-control-caption-md);
2907
2968
  --xh-_json-viewer-row-py: var(--xh-space-0_5);
2908
2969
  --xh-_json-viewer-indent: var(--xh-space-4);
2909
2970
  --xh-json-viewer-key-fg: var(--xh-fg-brand-strong);
@@ -2913,6 +2974,11 @@
2913
2974
  --xh-json-viewer-number-fg: var(--xh-syntax-number);
2914
2975
  --xh-json-viewer-boolean-fg: var(--xh-syntax-keyword);
2915
2976
 
2977
+ /* 两档的自绘条浮在内容之上:轨道不上底色,实色轨道会沿容器边缘糊出一条灰带 */
2978
+ --xh-scrollbar-track-bg: transparent;
2979
+
2980
+ /* 自绘条绝对定位贴这一层的内边距盒,它得是定位盒 */
2981
+ position: relative;
2916
2982
  display: block;
2917
2983
  color: var(--xh-json-viewer-fg, var(--xh-fg-default));
2918
2984
  font-family: var(--xh-json-viewer-font, var(--xh-font-family-mono));
@@ -2951,6 +3017,34 @@
2951
3017
  overflow: auto;
2952
3018
  }
2953
3019
 
3020
+ /* 原文档:与树档共用同一套边框、内衬与高度令牌,两档切过去盒子不跳。
3021
+ 整块可框选——这一档存在的理由就是把与后端一字不差的那份原文交到手上 */
3022
+ [data-scope='json-viewer'][data-part='text'] {
3023
+ margin: 0;
3024
+ max-block-size: var(--xh-json-viewer-max-h, var(--xh-viewport-max-h));
3025
+ padding-block: var(--xh-json-viewer-py, var(--xh-space-2));
3026
+ padding-inline: var(--xh-json-viewer-px, var(--xh-space-2));
3027
+ border: var(--xh-stroke-thin) solid var(--xh-json-viewer-border, var(--xh-border-default));
3028
+ border-radius: var(--xh-json-viewer-radius, var(--xh-shape-surface));
3029
+ background: var(--xh-json-viewer-bg, var(--xh-bg-surface));
3030
+ color: var(--xh-json-viewer-text-fg, var(--xh-fg-default));
3031
+ font-family: var(--xh-json-viewer-font, var(--xh-font-family-mono));
3032
+ /* 缩进靠空格,行不折:折行会把层级读乱,横向给滚动条 */
3033
+ white-space: pre;
3034
+ tab-size: 2;
3035
+ overflow: auto;
3036
+ user-select: text;
3037
+ }
3038
+
3039
+ [data-scope='json-viewer'][data-part='text'][hidden] {
3040
+ display: none;
3041
+ }
3042
+
3043
+ /* 这一档没有行可落焦,环画在整块上 */
3044
+ [data-scope='json-viewer'][data-part='text']:focus-visible {
3045
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
3046
+ outline-offset: calc(-1 * var(--xh-ring-width));
3047
+ }
2954
3048
  [data-scope='json-viewer'][data-part='tree'][hidden] {
2955
3049
  display: none;
2956
3050
  }
@@ -3174,9 +3268,9 @@
3174
3268
  display: flex;
3175
3269
  grid-area: header;
3176
3270
  align-items: center;
3177
- gap: var(--xh-space-3);
3271
+ gap: var(--xh-layout-header-gap, var(--xh-space-3));
3178
3272
  block-size: var(--xh-_layout-header-h);
3179
- padding-inline: var(--xh-space-4);
3273
+ padding-inline: var(--xh-layout-header-px, var(--xh-space-4));
3180
3274
  background: var(--xh-layout-header-bg, var(--xh-bg-surface));
3181
3275
  }
3182
3276
 
@@ -3185,7 +3279,7 @@
3185
3279
  grid-area: sider;
3186
3280
  inline-size: var(--xh-_layout-sider-w);
3187
3281
  overflow: hidden;
3188
- padding: var(--xh-space-3);
3282
+ padding: var(--xh-layout-sider-padding, var(--xh-space-3));
3189
3283
  background: var(--xh-layout-sider-bg, var(--xh-bg-subtle));
3190
3284
  transition: inline-size var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
3191
3285
  }
@@ -3200,12 +3294,12 @@
3200
3294
  grid-area: content;
3201
3295
  /* 内容列已是 minmax(0, 1fr),这里再声明一次,宽表格与长串文本才撑不破列 */
3202
3296
  min-inline-size: 0;
3203
- padding: var(--xh-space-4);
3297
+ padding: var(--xh-layout-content-padding, var(--xh-space-4));
3204
3298
  }
3205
3299
 
3206
3300
  [data-scope='layout'][data-part='footer'] {
3207
3301
  grid-area: footer;
3208
- padding: var(--xh-space-3) var(--xh-space-4);
3302
+ padding: var(--xh-layout-footer-padding, var(--xh-space-3) var(--xh-space-4));
3209
3303
  background: var(--xh-layout-footer-bg, var(--xh-bg-surface));
3210
3304
  color: var(--xh-fg-muted);
3211
3305
  font-size: var(--xh-text-secondary-size);
@@ -3216,9 +3310,9 @@
3216
3310
  display: inline-flex;
3217
3311
  align-items: center;
3218
3312
  justify-content: center;
3219
- gap: var(--xh-control-gap-sm);
3313
+ gap: var(--xh-layout-sider-trigger-gap, var(--xh-control-gap-sm));
3220
3314
  block-size: var(--xh-control-h-sm);
3221
- padding-inline: var(--xh-control-px-sm);
3315
+ padding-inline: var(--xh-layout-sider-trigger-px, var(--xh-control-px-sm));
3222
3316
  border: 0;
3223
3317
  border-radius: var(--xh-layout-sider-trigger-radius, var(--xh-shape-control));
3224
3318
  background: var(--xh-layout-sider-trigger-bg, transparent);
@@ -3302,6 +3396,14 @@
3302
3396
  overflow-y: auto;
3303
3397
  }
3304
3398
 
3399
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
3400
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
3401
+ [data-scope='layout'][data-part='root'][hidden],
3402
+ [data-scope='layout'][data-part='header'][hidden],
3403
+ [data-scope='layout'][data-part='sider-trigger'][hidden] {
3404
+ display: none;
3405
+ }
3406
+
3305
3407
  /* styles/list.css */
3306
3408
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3307
3409
  [data-scope='list'] {
@@ -3312,7 +3414,7 @@
3312
3414
  /* 一个尺寸档只换这几个私有槽,条目与两行文字都从根上继承它们,
3313
3415
  换档不必给每个部件各写一条选择器 */
3314
3416
  --xh-_list-item-py: var(--xh-list-item-py-md);
3315
- --xh-_list-item-px: var(--xh-space-4);
3417
+ --xh-_list-item-px: var(--xh-list-item-px-md);
3316
3418
  --xh-_list-item-gap: var(--xh-space-3);
3317
3419
  --xh-_list-title-size: var(--xh-control-font-md);
3318
3420
  --xh-_list-description-size: var(--xh-control-caption-md);
@@ -3334,7 +3436,7 @@
3334
3436
  /* —— 尺寸 —— */
3335
3437
  [data-scope='list'][data-part='root'][data-size='sm'] {
3336
3438
  --xh-_list-item-py: var(--xh-list-item-py-sm);
3337
- --xh-_list-item-px: var(--xh-space-3);
3439
+ --xh-_list-item-px: var(--xh-list-item-px-sm);
3338
3440
  --xh-_list-item-gap: var(--xh-space-2);
3339
3441
  --xh-_list-title-size: var(--xh-control-font-sm);
3340
3442
  --xh-_list-description-size: var(--xh-control-caption-sm);
@@ -3342,7 +3444,7 @@
3342
3444
 
3343
3445
  [data-scope='list'][data-part='root'][data-size='lg'] {
3344
3446
  --xh-_list-item-py: var(--xh-list-item-py-lg);
3345
- --xh-_list-item-px: var(--xh-space-5);
3447
+ --xh-_list-item-px: var(--xh-list-item-px-lg);
3346
3448
  --xh-_list-item-gap: var(--xh-space-4);
3347
3449
  --xh-_list-title-size: var(--xh-control-font-lg);
3348
3450
  }
@@ -3370,11 +3472,11 @@
3370
3472
  [data-scope='list'][data-part='root'][data-split]
3371
3473
  > [data-scope='list'][data-part='item']
3372
3474
  + [data-scope='list'][data-part='item'] {
3373
- border-block-start: var(--xh-stroke-thin) solid var(--xh-list-border, var(--xh-border-subtle));
3475
+ border-block-start: var(--xh-stroke-thin) solid var(--xh-list-divider, var(--xh-border-subtle));
3374
3476
  }
3375
3477
 
3376
3478
  [data-scope='list'][data-part='root'][data-hoverable] > [data-scope='list'][data-part='item'] {
3377
- transition: background-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
3479
+ transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
3378
3480
  }
3379
3481
 
3380
3482
  /* 悬停换底色:只在能用指针的设备上生效,触摸端不留一个按不掉的悬停态 */
@@ -3424,6 +3526,15 @@
3424
3526
  margin-inline-start: auto;
3425
3527
  }
3426
3528
 
3529
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
3530
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
3531
+ [data-scope='list'][data-part='item'][hidden],
3532
+ [data-scope='list'][data-part='item-media'][hidden],
3533
+ [data-scope='list'][data-part='item-content'][hidden],
3534
+ [data-scope='list'][data-part='item-action'][hidden] {
3535
+ display: none;
3536
+ }
3537
+
3427
3538
  /* styles/log.css */
3428
3539
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
3429
3540
  [data-scope='log'] {
@@ -3454,14 +3565,18 @@
3454
3565
  flex-basis 取 auto,连接层写的按行数高度才算数,同时外层给了高度时还能撑满;
3455
3566
  min-block-size: 0 让它在弹性父级里能被压缩从而真的溢出;
3456
3567
  两个轴都 auto:长行不折,横向也要能滚;
3457
- overscroll-behavior: contain 阻止滚动量传给页面;
3458
- scrollbar-gutter: stable 避免滚动条出现与消失时推动文字。 */
3568
+ overscroll-behavior: contain 阻止滚动量传给页面。 */
3459
3569
  [data-scope='log'][data-part='viewport'] {
3460
3570
  flex: 1 1 auto;
3461
3571
  min-block-size: 0;
3462
3572
  block-size: calc(var(--xh-_log-line-h) * var(--xh-log-rows, 16));
3463
3573
  overflow: auto;
3464
3574
  overscroll-behavior: contain;
3575
+ }
3576
+
3577
+ /* 还在用原生滚动条的视口留一条空道,滚动条出现与消失时不推动文字。
3578
+ 带 data-xh-scrollbar 的容器已经把原生条藏成零宽,这条空道对它没有布局作用,排除掉 */
3579
+ [data-scope='log'][data-part='viewport']:not([data-xh-scrollbar]) {
3465
3580
  scrollbar-gutter: stable;
3466
3581
  }
3467
3582
 
@@ -3733,23 +3848,23 @@
3733
3848
  /* —— 间距档位 —— */
3734
3849
  /* 每一档指向一个间距令牌,列之间与列内项之间吃同一份间距 */
3735
3850
  [data-scope='masonry'][data-part='root'][data-gap='xs'] {
3736
- --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-space-1));
3851
+ --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-layout-gap-xs));
3737
3852
  }
3738
3853
 
3739
3854
  [data-scope='masonry'][data-part='root'][data-gap='sm'] {
3740
- --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-space-2));
3855
+ --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-layout-gap-sm));
3741
3856
  }
3742
3857
 
3743
3858
  [data-scope='masonry'][data-part='root'][data-gap='md'] {
3744
- --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-space-3));
3859
+ --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-layout-gap-md));
3745
3860
  }
3746
3861
 
3747
3862
  [data-scope='masonry'][data-part='root'][data-gap='lg'] {
3748
- --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-space-4));
3863
+ --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-layout-gap-lg));
3749
3864
  }
3750
3865
 
3751
3866
  [data-scope='masonry'][data-part='root'][data-gap='xl'] {
3752
- --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-space-6));
3867
+ --xh-_masonry-gap: var(--xh-masonry-gap, var(--xh-layout-gap-xl));
3753
3868
  }
3754
3869
 
3755
3870
  /* styles/mention.css */
@@ -3789,6 +3904,9 @@
3789
3904
  引擎没算(尚未落位 / 无引擎)时不额外限高 */
3790
3905
  --xh-_mention-available-h: 100vh;
3791
3906
 
3907
+ /* 候选列表的自绘条浮在内容之上:轨道不上底色,实色轨道会在列表右缘糊一条竖灰带 */
3908
+ --xh-scrollbar-track-bg: transparent;
3909
+
3792
3910
  position: fixed;
3793
3911
  z-index: var(--xh-mention-layer, var(--xh-layer-popover));
3794
3912
  /* 空壳不吃指针,交互只发生在 content 上 */
@@ -3805,9 +3923,11 @@
3805
3923
  /* 尺寸档只换这五个私有槽,输入框与候选都从这两处继承它们,换档不必给每个部件各写一条选择器 */
3806
3924
  --xh-_mention-h: var(--xh-control-h-md);
3807
3925
  --xh-_mention-px: var(--xh-control-px-md);
3926
+ --xh-_mention-item-py: var(--xh-list-option-py-md);
3927
+ --xh-_mention-item-px: var(--xh-control-px-md);
3808
3928
  --xh-_mention-py: var(--xh-field-py);
3809
3929
  --xh-_mention-gap: var(--xh-control-gap-md);
3810
- --xh-_mention-font-size: var(--xh-text-body-size);
3930
+ --xh-_mention-font-size: var(--xh-control-font-md);
3811
3931
 
3812
3932
  /* 形态档只换这三个槽:缺省即 outline(描边 + 画布底) */
3813
3933
  --xh-_mention-input-bg: var(--xh-bg-canvas);
@@ -3832,6 +3952,8 @@
3832
3952
  [data-scope='mention']:is([data-part='root'], [data-part='positioner'])[data-size='sm'] {
3833
3953
  --xh-_mention-h: var(--xh-control-h-sm);
3834
3954
  --xh-_mention-px: var(--xh-control-px-sm);
3955
+ --xh-_mention-item-py: var(--xh-list-option-py-sm);
3956
+ --xh-_mention-item-px: var(--xh-control-px-sm);
3835
3957
  --xh-_mention-py: var(--xh-space-1);
3836
3958
  --xh-_mention-gap: var(--xh-control-gap-sm);
3837
3959
  --xh-_mention-font-size: var(--xh-control-font-sm);
@@ -3840,6 +3962,8 @@
3840
3962
  [data-scope='mention']:is([data-part='root'], [data-part='positioner'])[data-size='lg'] {
3841
3963
  --xh-_mention-h: var(--xh-control-h-lg);
3842
3964
  --xh-_mention-px: var(--xh-control-px-lg);
3965
+ --xh-_mention-item-py: var(--xh-list-option-py-lg);
3966
+ --xh-_mention-item-px: var(--xh-control-px-lg);
3843
3967
  --xh-_mention-py: var(--xh-space-3);
3844
3968
  --xh-_mention-gap: var(--xh-control-gap-lg);
3845
3969
  --xh-_mention-font-size: var(--xh-control-font-lg);
@@ -3939,6 +4063,7 @@ input[data-scope='mention'][data-part='input'] {
3939
4063
  [data-scope='mention'][data-part='content'] {
3940
4064
  display: flex;
3941
4065
  flex-direction: column;
4066
+ gap: var(--xh-mention-content-gap, var(--xh-list-option-gap));
3942
4067
  min-inline-size: var(--xh-mention-content-min-w, var(--xh-overlay-min-w));
3943
4068
  max-inline-size: var(--xh-mention-content-max-w, var(--xh-overlay-max-w));
3944
4069
  max-block-size: min(var(--xh-mention-content-max-h, var(--xh-overlay-max-h)), var(--xh-_mention-available-h));
@@ -3985,8 +4110,8 @@ input[data-scope='mention'][data-part='input'] {
3985
4110
  display: flex;
3986
4111
  align-items: center;
3987
4112
  gap: var(--xh-mention-item-gap, var(--xh-_mention-gap));
3988
- padding-block: var(--xh-mention-item-py, var(--xh-space-1_5));
3989
- padding-inline: var(--xh-mention-item-px, var(--xh-control-px-md));
4113
+ padding-block: var(--xh-mention-item-py, var(--xh-_mention-item-py));
4114
+ padding-inline: var(--xh-mention-item-px, var(--xh-_mention-item-px));
3990
4115
  border-radius: var(--xh-mention-item-radius, var(--xh-shape-control));
3991
4116
  color: var(--xh-mention-item-fg, var(--xh-fg-default));
3992
4117
  font-size: var(--xh-mention-item-font-size, var(--xh-_mention-font-size));
@@ -4164,6 +4289,13 @@ input[data-scope='mention'][data-part='input'] {
4164
4289
  line-height: var(--xh-leading-normal);
4165
4290
  }
4166
4291
 
4292
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
4293
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
4294
+ [data-scope='page-header'][data-part='back-trigger'][hidden],
4295
+ [data-scope='page-header'][data-part='extra'][hidden] {
4296
+ display: none;
4297
+ }
4298
+
4167
4299
  /* styles/password-input.css */
4168
4300
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
4169
4301
  [data-scope='password-input'] {
@@ -4183,11 +4315,11 @@ input[data-scope='mention'][data-part='input'] {
4183
4315
  --xh-_password-input-h: var(--xh-control-h-md);
4184
4316
  --xh-_password-input-px: var(--xh-control-px-md);
4185
4317
  --xh-_password-input-gap: var(--xh-control-gap-md);
4186
- --xh-_password-input-font-size: var(--xh-text-body-size);
4187
- --xh-_password-input-label-font-size: var(--xh-text-label-size);
4318
+ --xh-_password-input-font-size: var(--xh-control-font-md);
4319
+ --xh-_password-input-label-font-size: var(--xh-control-font-md);
4188
4320
  /* 提示与切换钮里的字形都比正文小一档,三个尺寸档各自换过,不是一个恒等的中转 */
4189
- --xh-_password-input-hint-font-size: var(--xh-text-secondary-size);
4190
- --xh-_password-input-trigger-font-size: var(--xh-text-secondary-size);
4321
+ --xh-_password-input-hint-font-size: var(--xh-control-caption-md);
4322
+ --xh-_password-input-trigger-font-size: var(--xh-control-caption-md);
4191
4323
 
4192
4324
  /* 盒子的圆角 */
4193
4325
  --xh-_password-input-radius: var(--xh-password-input-input-radius, var(--xh-shape-control));
@@ -4659,9 +4791,9 @@ input[data-scope='mention'][data-part='input'] {
4659
4791
  align-items: center;
4660
4792
  justify-content: center;
4661
4793
  block-size: var(--xh-control-h-sm);
4662
- padding-inline: var(--xh-control-px-sm);
4794
+ padding-inline: var(--xh-popconfirm-cancel-trigger-px, var(--xh-control-px-sm));
4663
4795
  border: var(--xh-stroke-thin) solid transparent;
4664
- border-radius: var(--xh-shape-control);
4796
+ border-radius: var(--xh-popconfirm-action-radius, var(--xh-shape-control));
4665
4797
  font-size: var(--xh-text-secondary-size);
4666
4798
  font-weight: var(--xh-text-label-weight);
4667
4799
  line-height: var(--xh-leading-none);
@@ -4746,6 +4878,13 @@ input[data-scope='mention'][data-part='input'] {
4746
4878
  animation: none;
4747
4879
  }
4748
4880
 
4881
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
4882
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
4883
+ [data-scope='popconfirm'][data-part='root'][hidden],
4884
+ [data-scope='popconfirm'][data-part='cancel-trigger'][hidden] {
4885
+ display: none;
4886
+ }
4887
+
4749
4888
  /* styles/popselect.css */
4750
4889
  /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
4751
4890
  动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
@@ -4783,6 +4922,9 @@ input[data-scope='mention'][data-part='input'] {
4783
4922
  引擎没算(尚未落位 / 无引擎 / 贴边归零)时退回自己那档静态上限 */
4784
4923
  --xh-_popselect-available-h: 100vh;
4785
4924
 
4925
+ /* 候选列表的自绘条浮在内容之上:轨道不上底色,实色轨道会在列表右缘糊一条竖灰带 */
4926
+ --xh-scrollbar-track-bg: transparent;
4927
+
4786
4928
  position: fixed;
4787
4929
  z-index: var(--xh-popselect-layer, var(--xh-layer-popover));
4788
4930
  /* 空壳不吃指针,交互只发生在 content 上 */
@@ -4799,8 +4941,10 @@ input[data-scope='mention'][data-part='input'] {
4799
4941
  /* 尺寸档只换这四个私有槽,触发器与条目都从这两处继承它们,换档不必给每个部件各写一条选择器 */
4800
4942
  --xh-_popselect-h: var(--xh-control-h-md);
4801
4943
  --xh-_popselect-px: var(--xh-control-px-md);
4944
+ --xh-_popselect-item-py: var(--xh-list-option-py-md);
4945
+ --xh-_popselect-item-px: var(--xh-control-px-md);
4802
4946
  --xh-_popselect-gap: var(--xh-control-gap-md);
4803
- --xh-_popselect-font-size: var(--xh-text-body-size);
4947
+ --xh-_popselect-font-size: var(--xh-control-font-md);
4804
4948
 
4805
4949
  /* 形态档只换这三个槽:缺省即 outline(描边 + 画布底) */
4806
4950
  --xh-_popselect-control-bg: var(--xh-bg-canvas);
@@ -4810,7 +4954,7 @@ input[data-scope='mention'][data-part='input'] {
4810
4954
  /* 聚焦环恒用固定环色;强调色随语气走,只落在勾选标记与选中文字上,正文文字色不动。
4811
4955
  没写 data-tone 时 --xh-_tone 没被声明,两处都退回原来的取值 */
4812
4956
  --xh-_popselect-ring: var(--xh-ring-focus);
4813
- --xh-_popselect-accent: var(--xh-_tone, var(--xh-bg-brand));
4957
+ --xh-_popselect-accent: var(--xh-_tone, var(--xh-fg-brand));
4814
4958
  --xh-_popselect-item-selected-fg: var(--xh-_tone-fg, var(--xh-fg-brand-strong));
4815
4959
  }
4816
4960
 
@@ -4837,6 +4981,8 @@ input[data-scope='mention'][data-part='input'] {
4837
4981
  [data-scope='popselect']:is([data-part='root'], [data-part='positioner'])[data-size='sm'] {
4838
4982
  --xh-_popselect-h: var(--xh-control-h-sm);
4839
4983
  --xh-_popselect-px: var(--xh-control-px-sm);
4984
+ --xh-_popselect-item-py: var(--xh-list-option-py-sm);
4985
+ --xh-_popselect-item-px: var(--xh-control-px-sm);
4840
4986
  --xh-_popselect-gap: var(--xh-control-gap-sm);
4841
4987
  --xh-_popselect-font-size: var(--xh-control-font-sm);
4842
4988
  }
@@ -4844,6 +4990,8 @@ input[data-scope='mention'][data-part='input'] {
4844
4990
  [data-scope='popselect']:is([data-part='root'], [data-part='positioner'])[data-size='lg'] {
4845
4991
  --xh-_popselect-h: var(--xh-control-h-lg);
4846
4992
  --xh-_popselect-px: var(--xh-control-px-lg);
4993
+ --xh-_popselect-item-py: var(--xh-list-option-py-lg);
4994
+ --xh-_popselect-item-px: var(--xh-control-px-lg);
4847
4995
  --xh-_popselect-gap: var(--xh-control-gap-lg);
4848
4996
  --xh-_popselect-font-size: var(--xh-control-font-lg);
4849
4997
  }
@@ -4991,6 +5139,7 @@ input[data-scope='mention'][data-part='input'] {
4991
5139
  [data-scope='popselect'][data-part='content'] {
4992
5140
  display: flex;
4993
5141
  flex-direction: column;
5142
+ gap: var(--xh-popselect-content-gap, var(--xh-list-option-gap));
4994
5143
  min-inline-size: var(--xh-popselect-content-min-w, var(--xh-overlay-menu-min-w));
4995
5144
  max-inline-size: var(--xh-popselect-content-max-w, var(--xh-overlay-max-w));
4996
5145
  max-block-size: min(var(--xh-popselect-content-max-h, var(--xh-overlay-menu-max-h)), var(--xh-_popselect-available-h));
@@ -5036,8 +5185,8 @@ input[data-scope='mention'][data-part='input'] {
5036
5185
  display: flex;
5037
5186
  align-items: center;
5038
5187
  gap: var(--xh-popselect-item-gap, var(--xh-_popselect-gap));
5039
- padding-block: var(--xh-popselect-item-py, var(--xh-space-1_5));
5040
- padding-inline: var(--xh-popselect-item-px, var(--xh-control-px-md));
5188
+ padding-block: var(--xh-popselect-item-py, var(--xh-_popselect-item-py));
5189
+ padding-inline: var(--xh-popselect-item-px, var(--xh-_popselect-item-px));
5041
5190
  border-radius: var(--xh-popselect-item-radius, var(--xh-shape-control));
5042
5191
  color: var(--xh-popselect-item-fg, var(--xh-fg-default));
5043
5192
  font-size: var(--xh-popselect-item-font-size, var(--xh-_popselect-font-size));
@@ -5115,6 +5264,16 @@ input[data-scope='mention'][data-part='input'] {
5115
5264
  visibility: visible;
5116
5265
  }
5117
5266
 
5267
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
5268
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
5269
+ [data-scope='popselect'][data-part='root'][hidden],
5270
+ [data-scope='popselect'][data-part='control'][hidden],
5271
+ [data-scope='popselect'][data-part='trigger'][hidden],
5272
+ [data-scope='popselect'][data-part='item'][hidden],
5273
+ [data-scope='popselect'][data-part='item-indicator'][hidden] {
5274
+ display: none;
5275
+ }
5276
+
5118
5277
  /* styles/qr-code.css */
5119
5278
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
5120
5279
  [data-scope='qr-code'] {
@@ -5220,7 +5379,7 @@ input[data-scope='mention'][data-part='input'] {
5220
5379
  /* 三个尺寸档只换这几个私有槽,图标与标题都从 root 继承它们,
5221
5380
  换档不必给每个部件各写一条选择器 */
5222
5381
  --xh-_result-gap: var(--xh-stack-gap-md);
5223
- --xh-_result-py: var(--xh-section-py);
5382
+ --xh-_result-py: var(--xh-section-py-md);
5224
5383
  --xh-_result-icon-size: var(--xh-glyph-size-3xl);
5225
5384
  --xh-_result-title-size: var(--xh-text-heading-3-size);
5226
5385
  /* 说明的读行宽度:整句话不收窄就会拉成一条难读的长行 */
@@ -5246,15 +5405,15 @@ input[data-scope='mention'][data-part='input'] {
5246
5405
 
5247
5406
  /* —— 尺寸 —— */
5248
5407
  [data-scope='result'][data-part='root'][data-size='sm'] {
5249
- --xh-_result-gap: var(--xh-space-3);
5250
- --xh-_result-py: var(--xh-space-6);
5408
+ --xh-_result-gap: var(--xh-stack-gap-sm);
5409
+ --xh-_result-py: var(--xh-section-py-sm);
5251
5410
  --xh-_result-icon-size: var(--xh-glyph-size-2xl);
5252
5411
  --xh-_result-title-size: var(--xh-control-font-lg);
5253
5412
  }
5254
5413
 
5255
5414
  [data-scope='result'][data-part='root'][data-size='lg'] {
5256
- --xh-_result-gap: var(--xh-space-6);
5257
- --xh-_result-py: var(--xh-space-8);
5415
+ --xh-_result-gap: var(--xh-stack-gap-lg);
5416
+ --xh-_result-py: var(--xh-section-py-lg);
5258
5417
  --xh-_result-icon-size: var(--xh-glyph-size-4xl);
5259
5418
  --xh-_result-title-size: var(--xh-text-heading-2-size);
5260
5419
  }
@@ -5287,6 +5446,9 @@ input[data-scope='mention'][data-part='input'] {
5287
5446
  align-items: center;
5288
5447
  justify-content: center;
5289
5448
  flex: none;
5449
+ /* 作者塞进图标槽的 XhIcon 与皮肤画的字形同一把尺,都按展示档的图标框量 */
5450
+ --xh-icon-size: var(--xh-result-icon-size, var(--xh-_result-icon-size));
5451
+
5290
5452
  block-size: var(--xh-result-icon-size, var(--xh-_result-icon-size));
5291
5453
  inline-size: var(--xh-result-icon-size, var(--xh-_result-icon-size));
5292
5454
  color: var(--xh-result-icon-fg, var(--xh-_result-accent));
@@ -5319,6 +5481,13 @@ input[data-scope='mention'][data-part='input'] {
5319
5481
  gap: var(--xh-result-action-gap, var(--xh-space-2));
5320
5482
  }
5321
5483
 
5484
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
5485
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
5486
+ [data-scope='result'][data-part='icon'][hidden],
5487
+ [data-scope='result'][data-part='action'][hidden] {
5488
+ display: none;
5489
+ }
5490
+
5322
5491
  /* styles/segmented.css */
5323
5492
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
5324
5493
  [data-scope='segmented'] {
@@ -5332,7 +5501,7 @@ input[data-scope='mention'][data-part='input'] {
5332
5501
  --xh-_segmented-h: var(--xh-control-h-md);
5333
5502
  --xh-_segmented-px: var(--xh-control-px-md);
5334
5503
  --xh-_segmented-gap: var(--xh-control-gap-md);
5335
- --xh-_segmented-font-size: var(--xh-text-label-size);
5504
+ --xh-_segmented-font-size: var(--xh-control-font-md);
5336
5505
  /* 指示器底色与选中段的文字色;没写 data-tone 时就是这里的取值 */
5337
5506
  --xh-_segmented-indicator-bg: var(--xh-bg-surface);
5338
5507
  --xh-_segmented-fg-selected: var(--xh-fg-default);
@@ -5688,7 +5857,7 @@ input[data-scope='mention'][data-part='input'] {
5688
5857
  display: flex;
5689
5858
  flex-wrap: nowrap;
5690
5859
  /* 不写档位也按 md 留白,这是与裸弹性容器的分野;使用者槽位排在档位之前,写死一个值即盖过所有档 */
5691
- gap: var(--xh-space-gap, var(--xh-space-3));
5860
+ gap: var(--xh-space-gap, var(--xh-layout-gap-md));
5692
5861
  }
5693
5862
 
5694
5863
  /* 声明了 display 就盖掉了 UA 的 [hidden] 规则,这里还回去 */
@@ -5776,23 +5945,23 @@ input[data-scope='mention'][data-part='input'] {
5776
5945
  /* —— 间距档位 —— */
5777
5946
  /* 每一档指向一个间距令牌,折行时行与行之间也吃这份间距 */
5778
5947
  [data-scope='space'][data-part='root'][data-gap='xs'] {
5779
- gap: var(--xh-space-gap, var(--xh-space-1));
5948
+ gap: var(--xh-space-gap, var(--xh-layout-gap-xs));
5780
5949
  }
5781
5950
 
5782
5951
  [data-scope='space'][data-part='root'][data-gap='sm'] {
5783
- gap: var(--xh-space-gap, var(--xh-space-2));
5952
+ gap: var(--xh-space-gap, var(--xh-layout-gap-sm));
5784
5953
  }
5785
5954
 
5786
5955
  [data-scope='space'][data-part='root'][data-gap='md'] {
5787
- gap: var(--xh-space-gap, var(--xh-space-3));
5956
+ gap: var(--xh-space-gap, var(--xh-layout-gap-md));
5788
5957
  }
5789
5958
 
5790
5959
  [data-scope='space'][data-part='root'][data-gap='lg'] {
5791
- gap: var(--xh-space-gap, var(--xh-space-4));
5960
+ gap: var(--xh-space-gap, var(--xh-layout-gap-lg));
5792
5961
  }
5793
5962
 
5794
5963
  [data-scope='space'][data-part='root'][data-gap='xl'] {
5795
- gap: var(--xh-space-gap, var(--xh-space-6));
5964
+ gap: var(--xh-space-gap, var(--xh-layout-gap-xl));
5796
5965
  }
5797
5966
 
5798
5967
  /* styles/statistic.css */
@@ -5999,8 +6168,10 @@ input[data-scope='mention'][data-part='input'] {
5999
6168
  color: var(--xh-tag-fg, var(--xh-fg-default));
6000
6169
  }
6001
6170
 
6171
+ /* 描边档的边就是这枚标签的全部轮廓,走「可操作区边界」那一支:
6172
+ 兑了底色的 --xh-_tone-border 六族都在 1.44-2.18,当轮廓看不清 */
6002
6173
  [data-scope='tag'][data-part='root'][data-variant='outline'][data-tone] {
6003
- border-color: var(--xh-tag-border, var(--xh-_tone-border, var(--xh-border-default)));
6174
+ border-color: var(--xh-tag-border, var(--xh-_tone-border-control, var(--xh-border-default)));
6004
6175
  color: var(--xh-tag-fg, var(--xh-_tone-fg, var(--xh-fg-default)));
6005
6176
  }
6006
6177
 
@@ -6081,7 +6252,7 @@ input[data-scope='mention'][data-part='input'] {
6081
6252
  --xh-_timeline-dot-size: var(--xh-space-2_5);
6082
6253
  --xh-_timeline-gutter: var(--xh-space-3);
6083
6254
  --xh-_timeline-item-gap: var(--xh-space-5);
6084
- --xh-_timeline-title-font-size: var(--xh-text-label-size);
6255
+ --xh-_timeline-title-font-size: var(--xh-control-font-md);
6085
6256
  --xh-_timeline-caption-font-size: var(--xh-text-caption-size);
6086
6257
  /* 标题首行占多高。圆点按它居中下移,圆心才落在标题这一行的中线上 */
6087
6258
  --xh-_timeline-line-h: calc(
@@ -6163,7 +6334,7 @@ input[data-scope='mention'][data-part='input'] {
6163
6334
  justify-content: center;
6164
6335
  inline-size: var(--xh-timeline-indicator-size, var(--xh-_timeline-dot-size));
6165
6336
  block-size: var(--xh-timeline-indicator-size, var(--xh-_timeline-dot-size));
6166
- border-radius: var(--xh-shape-pill);
6337
+ border-radius: var(--xh-timeline-indicator-radius, var(--xh-shape-pill));
6167
6338
  /* 使用者令牌排在语气之前;两者都没有时退回一个中性的实心点 */
6168
6339
  background: var(--xh-timeline-indicator-bg, var(--xh-_tone-soft, var(--xh-fg-muted)));
6169
6340
  color: var(--xh-timeline-indicator-fg, var(--xh-_tone-on, var(--xh-fg-on-brand)));
@@ -6191,7 +6362,7 @@ input[data-scope='mention'][data-part='input'] {
6191
6362
 
6192
6363
  /* —— 连线 —— */
6193
6364
  [data-scope='timeline'][data-part='connector'] {
6194
- border-radius: var(--xh-shape-pill);
6365
+ border-radius: var(--xh-timeline-connector-radius, var(--xh-shape-pill));
6195
6366
  background: var(--xh-timeline-connector-bg, var(--xh-border-default));
6196
6367
  }
6197
6368
 
@@ -6229,7 +6400,7 @@ input[data-scope='mention'][data-part='input'] {
6229
6400
  [data-scope='timeline'][data-part='content'] {
6230
6401
  display: flex;
6231
6402
  flex-direction: column;
6232
- gap: var(--xh-space-1);
6403
+ gap: var(--xh-timeline-content-gap, var(--xh-space-1));
6233
6404
  min-inline-size: 0;
6234
6405
  }
6235
6406
 
@@ -6247,7 +6418,7 @@ input[data-scope='mention'][data-part='input'] {
6247
6418
  [data-scope='timeline'][data-part='item'][data-orientation='horizontal'] [data-scope='timeline'][data-part='content'] {
6248
6419
  grid-column: 1 / -1;
6249
6420
  grid-row: 2;
6250
- padding-block-start: var(--xh-space-2);
6421
+ padding-block-start: var(--xh-timeline-content-pt, var(--xh-space-2));
6251
6422
  padding-inline-end: var(--xh-timeline-item-gap, var(--xh-_timeline-item-gap));
6252
6423
  }
6253
6424
 
@@ -6312,7 +6483,7 @@ input[data-scope='mention'][data-part='input'] {
6312
6483
  grid-row: 1;
6313
6484
  align-self: end;
6314
6485
  padding-block-start: 0;
6315
- padding-block-end: var(--xh-space-2);
6486
+ padding-block-end: var(--xh-timeline-content-pb, var(--xh-space-2));
6316
6487
  }
6317
6488
 
6318
6489
  [data-scope='timeline'][data-part='item'][data-orientation='horizontal'][data-placement='alternate'] {
@@ -6333,7 +6504,7 @@ input[data-scope='mention'][data-part='input'] {
6333
6504
  grid-row: 1;
6334
6505
  align-self: end;
6335
6506
  padding-block-start: 0;
6336
- padding-block-end: var(--xh-space-2);
6507
+ padding-block-end: var(--xh-timeline-content-pb, var(--xh-space-2));
6337
6508
  }
6338
6509
 
6339
6510
  /* —— 文字 —— */
@@ -6604,7 +6775,7 @@ input[data-scope='mention'][data-part='input'] {
6604
6775
  padding-inline: var(--xh-typography-code-px, var(--xh-space-1));
6605
6776
  border-radius: var(--xh-typography-code-radius, var(--xh-shape-inset));
6606
6777
  background: var(--xh-typography-code-bg, var(--xh-bg-subtle));
6607
- font-family: var(--xh-font-family-mono);
6778
+ font-family: var(--xh-typography-code-font, var(--xh-font-family-mono));
6608
6779
  font-size: var(--xh-typography-code-font-size, var(--xh-_typography-code-size));
6609
6780
  }
6610
6781
 
@@ -6662,6 +6833,7 @@ input[data-scope='mention'][data-part='input'] {
6662
6833
  xh-menu,
6663
6834
  xh-menubar,
6664
6835
  xh-navigation-menu,
6836
+ xh-pagination,
6665
6837
  xh-popconfirm,
6666
6838
  xh-popover,
6667
6839
  xh-popselect,
@@ -6707,19 +6879,25 @@ input[data-scope='mention'][data-part='input'] {
6707
6879
  * 这里只声明私有槽,各组件的形态规则去消费。所以加一个语气是改这一处 6 条规则,
6708
6880
  * 而不是逐个组件写 6 遍。
6709
6881
  *
6710
- * --xh-_tone-on 是实心底上的前景色,按实测对比度分派而非统一白字:
6711
- * 600 档上白字对 brand 5.08、neutral 7.80、danger 4.83 达标,而 success 3.04、
6712
- * warning 2.70、info 3.47 都不到 4.5,这三族必须配深字。
6882
+ * --xh-_tone-on 是实心底上的前景色,--xh-_tone-shift 是交互态要往哪个方向挪
6883
+ * (永远背离前景色走,悬停与按下才不会反过来压低对比度)。两者都由 --xh-_tone 现推:
6884
+ * WCAG 的权重算出语气色的相对亮度,低于 0.179 配白字、高于配深字,shift 取反面。
6885
+ * 0.179 是白字与黑字对比度相等的那一点,解析解。
6713
6886
  *
6714
- * --xh-_tone-shift 是交互态要往哪个方向挪:永远背离前景色走,悬停与按下才不会
6715
- * 反过来压低对比度。白字族往深处挪,深字族往浅处挪。
6887
+ * 现推是因为语气色可换肤:写死的分派只对本仓这套 600 档成立,使用者换一套调色板
6888
+ * 配对就不再成立,而门禁只验本仓的色,换肤后的失配一路绿灯。
6716
6889
  *
6717
- * 这两个槽用的都是固定原语而不是 --xh-fg-default:实心底本身是原语色、不随主题翻,
6718
- * 配色若跟着主题翻,暗色下就会变成白字压在浅黄底上(实测对比度 2.70)。
6890
+ * 够不到相对颜色语法的引擎退回逐族写死的那一份,取值是本仓这套色的实测结果:
6891
+ * 600 档上白字对 brand 5.08、neutral 7.80、danger 4.83 达标,而 success 3.04、
6892
+ * warning 2.70、info 3.47 都不到 4.5,这三族配深字。兜底那一份用的是固定原语而不是
6893
+ * --xh-fg-default:实心底本身是原语色、不随主题翻,配色若跟着主题翻,暗色下就会变成
6894
+ * 白字压在浅黄底上(实测对比度 2.70)。
6719
6895
  *
6720
6896
  * brand 是例外:那一族的色相归使用者,所以它的底与前景走 --xh-bg-brand / --xh-fg-on-brand
6721
6897
  * 这两个语义令牌。缺省主题下它们就解析成 brand-600 与 neutral-0,与其余五族同值;
6722
6898
  * 改写过品牌色的使用者只改这两个令牌,实心底与它上面的字就一起跟着走。
6899
+ * 底与前景既然随主题翻,brand 的 shift 也必须随主题翻——现推那一档自动跟着底色走,
6900
+ * 文件末尾那条深色覆盖是给兜底那一档用的。
6723
6901
  */
6724
6902
 
6725
6903
  [data-tone] {
@@ -6727,9 +6905,6 @@ input[data-scope='mention'][data-part='input'] {
6727
6905
  而不是让 --xh-_tone 悬空——悬空会让下面每条 color-mix 变成计算期无效,
6728
6906
  用它的声明会整条失效,且 var() 兜底也救不回来(槽位是「已声明但无效」)。 */
6729
6907
  --xh-_tone: var(--xh-color-neutral-600);
6730
- /* 装饰性强调(色条、图标这类)用 500 档:600 是给实心底与文字用的强调档,
6731
- 压在细长的色条上偏重。alert 与 toast 原本就用 500,接语气层不该改变它们的观感 */
6732
- --xh-_tone-soft: var(--xh-color-neutral-500);
6733
6908
  --xh-_tone-on: var(--xh-color-neutral-0);
6734
6909
  --xh-_tone-shift: var(--xh-color-neutral-950);
6735
6910
 
@@ -6743,13 +6918,18 @@ input[data-scope='mention'][data-part='input'] {
6743
6918
  /* 控件的可操作区边界要 3:1,兑了底色的 --xh-_tone-border 六族全在 1.44–2.18,够不着。
6744
6919
  这一支直接取主色本体;两族在各自的底上仍不够,在下面按主题单独兜 */
6745
6920
  --xh-_tone-border-control: var(--xh-_tone);
6746
- /* 在普通背景上表达该语气的文字色:往前景色兑,浅色态变深、深色态变浅 */
6747
- --xh-_tone-fg: color-mix(in oklab, var(--xh-_tone) 72%, var(--xh-fg-default));
6921
+ /* 装饰性强调(色条、指示条、锚点高亮这类)是非文字图形,同样要 3:1,
6922
+ 要求与可操作区边界一模一样,就直接跟着那一支走,连它按主题兜的两族一并继承。
6923
+ 要读得清的状态文字不在此列,那些走 --xh-_tone-fg */
6924
+ --xh-_tone-soft: var(--xh-_tone-border-control);
6925
+ /* 在普通背景上表达该语气的文字色:往前景色兑,浅色态变深、深色态变浅。
6926
+ 兑到 60% 是实测出来的:这一档要同时压得住淡底的静态/悬停/按下三态、面与抬起的面
6927
+ 共五种底,72% 时六族里有三族够不到 4.5(最低 3.66),60% 全部达标且留有余量 */
6928
+ --xh-_tone-fg: color-mix(in oklab, var(--xh-_tone) 60%, var(--xh-fg-default));
6748
6929
  }
6749
6930
 
6750
6931
  [data-tone='brand'] {
6751
6932
  --xh-_tone: var(--xh-bg-brand);
6752
- --xh-_tone-soft: var(--xh-color-brand-500);
6753
6933
  --xh-_tone-on: var(--xh-fg-on-brand);
6754
6934
  --xh-_tone-shift: var(--xh-color-neutral-950);
6755
6935
  }
@@ -6762,28 +6942,24 @@ input[data-scope='mention'][data-part='input'] {
6762
6942
 
6763
6943
  [data-tone='danger'] {
6764
6944
  --xh-_tone: var(--xh-color-danger-600);
6765
- --xh-_tone-soft: var(--xh-color-danger-500);
6766
6945
  --xh-_tone-on: var(--xh-color-neutral-0);
6767
6946
  --xh-_tone-shift: var(--xh-color-neutral-950);
6768
6947
  }
6769
6948
 
6770
6949
  [data-tone='success'] {
6771
6950
  --xh-_tone: var(--xh-color-success-600);
6772
- --xh-_tone-soft: var(--xh-color-success-500);
6773
6951
  --xh-_tone-on: var(--xh-color-neutral-950);
6774
6952
  --xh-_tone-shift: var(--xh-color-neutral-0);
6775
6953
  }
6776
6954
 
6777
6955
  [data-tone='warning'] {
6778
6956
  --xh-_tone: var(--xh-color-warning-600);
6779
- --xh-_tone-soft: var(--xh-color-warning-500);
6780
6957
  --xh-_tone-on: var(--xh-color-neutral-950);
6781
6958
  --xh-_tone-shift: var(--xh-color-neutral-0);
6782
6959
  }
6783
6960
 
6784
6961
  [data-tone='info'] {
6785
6962
  --xh-_tone: var(--xh-color-info-600);
6786
- --xh-_tone-soft: var(--xh-color-info-500);
6787
6963
  --xh-_tone-on: var(--xh-color-neutral-950);
6788
6964
  --xh-_tone-shift: var(--xh-color-neutral-0);
6789
6965
  }
@@ -6808,6 +6984,32 @@ input[data-scope='mention'][data-part='input'] {
6808
6984
  --xh-_tone-border-control: var(--xh-color-neutral-550);
6809
6985
  }
6810
6986
 
6987
+ /* 把语气色转成线性 sRGB 分量、按 WCAG 的权重算出相对亮度:低于 0.179 前景取白、
6988
+ 高于取黑,挪动方向取前景的反面。三个通道写同一个式子,算出来的是纯白或纯黑;
6989
+ alpha 显式写 1,不然会连语气色的透明度一起继承过来。
6990
+ 探针按这里实际用到的整个形态测,只测得起 color(from …) 的引擎不会落进半截支持。
6991
+ 上面各族写死的那一份是兜底:引擎不认这条语法时整块丢弃,退回那一份 */
6992
+ @supports (color: color(from red srgb-linear clamp(0, (0.179 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * infinity, 1) 0 0 / 1)) {
6993
+ [data-tone] {
6994
+ --xh-_tone-on: color(from var(--xh-_tone) srgb-linear
6995
+ clamp(0, (0.179 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * infinity, 1)
6996
+ clamp(0, (0.179 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * infinity, 1)
6997
+ clamp(0, (0.179 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * infinity, 1) / 1);
6998
+ --xh-_tone-shift: color(from var(--xh-_tone) srgb-linear
6999
+ clamp(0, ((0.2126 * r + 0.7152 * g + 0.0722 * b) - 0.179) * infinity, 1)
7000
+ clamp(0, ((0.2126 * r + 0.7152 * g + 0.0722 * b) - 0.179) * infinity, 1)
7001
+ clamp(0, ((0.2126 * r + 0.7152 * g + 0.0722 * b) - 0.179) * infinity, 1) / 1);
7002
+ }
7003
+ }
7004
+
7005
+ /* brand 的底与前景走语义令牌、随主题翻,所以它的 shift 也必须跟着翻,
7006
+ 否则深色下前景是深字而 shift 仍往深处挪,悬停与按下反而压低对比度
7007
+ (实测 5.29 → 4.25 → 3.49,而不写 tone 的品牌链是 5.29 → 7.33 → 10.85)。
7008
+ 其余五族的底是固定原语、不随主题翻,shift 也就不必翻 */
7009
+ :is([data-theme='dark'] *, [data-theme='dark'])[data-tone='brand'] {
7010
+ --xh-_tone-shift: var(--xh-color-neutral-0);
7011
+ }
7012
+
6811
7013
  /* styles/alert.css */
6812
7014
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
6813
7015
  [data-scope='alert'] {
@@ -6818,13 +7020,11 @@ input[data-scope='mention'][data-part='input'] {
6818
7020
  /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
6819
7021
  --xh-icon-size: var(--xh-alert-icon-size, var(--xh-glyph-size-text));
6820
7022
 
6821
- /* 强调色随语气走,底色/描边/图标色都由它推导出来,换语气不必逐条属性各写一遍。
6822
- 没写 data-tone --xh-_tone 没被声明,退回原来的 info 蓝 */
6823
- --xh-_alert-accent: var(--xh-_tone-soft, var(--xh-color-info-500));
6824
- /* 底色与描边由语气色兑进当前表面色得到:表面色本身跟着深浅模式翻,
6825
- 兑出来的淡底也就跟着翻,不必为深色再写一套选择器 */
6826
- --xh-_alert-tint: color-mix(in oklab, var(--xh-_alert-accent) 12%, var(--xh-bg-surface));
6827
- --xh-_alert-edge: color-mix(in oklab, var(--xh-_alert-accent) 32%, var(--xh-bg-surface));
7023
+ /* 底色、描边、图标色一律取语气层派生好的槽:连接层给 alert 兜了 tone=info 的缺省,
7024
+ data-tone 恒在,语气层的槽也就恒被声明。此前这里自己又兑了一遍(12% / 32%),
7025
+ 与语气层的公式差一档,图标压上去只有 1.79–2.47 */
7026
+ --xh-_alert-tint: var(--xh-_tone-subtle);
7027
+ --xh-_alert-edge: var(--xh-_tone-border);
6828
7028
 
6829
7029
  display: flex;
6830
7030
  /* 说明用 flex: 1 1 100% 独占一行,容器不换行的话它只会挤在标题旁边 */
@@ -6854,8 +7054,8 @@ input[data-scope='mention'][data-part='input'] {
6854
7054
  flex: none;
6855
7055
  /* 与首行文字对齐:图标框高取一行正文的行高 */
6856
7056
  block-size: calc(var(--xh-text-body-size) * var(--xh-leading-normal));
6857
- inline-size: var(--xh-alert-icon-size, var(--xh-control-indicator-size));
6858
- color: var(--xh-alert-icon-fg, var(--xh-_alert-accent));
7057
+ inline-size: var(--xh-alert-icon-box, var(--xh-control-indicator-size));
7058
+ color: var(--xh-alert-icon-fg, var(--xh-_tone-fg));
6859
7059
  }
6860
7060
 
6861
7061
  /* 标题与说明摞成一列,占满 root 剩下的横向空间,
@@ -6946,6 +7146,12 @@ input[data-scope='mention'][data-part='input'] {
6946
7146
  mask: var(--xh-glyph-mark-close) center / contain no-repeat;
6947
7147
  }
6948
7148
 
7149
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
7150
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
7151
+ [data-scope='alert'][data-part='icon'][hidden] {
7152
+ display: none;
7153
+ }
7154
+
6949
7155
  /* styles/empty-state.css */
6950
7156
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
6951
7157
  [data-scope='empty-state'] {
@@ -6956,7 +7162,7 @@ input[data-scope='mention'][data-part='input'] {
6956
7162
  /* 三个尺寸档只换这几个私有槽,图标与标题都从 root 继承它们,
6957
7163
  换档不必给每个部件各写一条选择器 */
6958
7164
  --xh-_empty-state-gap: var(--xh-stack-gap-md);
6959
- --xh-_empty-state-py: var(--xh-section-py);
7165
+ --xh-_empty-state-py: var(--xh-section-py-md);
6960
7166
  --xh-_empty-state-icon-size: var(--xh-glyph-size-2xl);
6961
7167
  --xh-_empty-state-title-size: var(--xh-control-font-lg);
6962
7168
  /* 说明的读行宽度:整句话不收窄就会拉成一条难读的长行 */
@@ -6979,15 +7185,15 @@ input[data-scope='mention'][data-part='input'] {
6979
7185
  }
6980
7186
 
6981
7187
  [data-scope='empty-state'][data-part='root'][data-size='sm'] {
6982
- --xh-_empty-state-gap: var(--xh-space-2);
6983
- --xh-_empty-state-py: var(--xh-space-4);
7188
+ --xh-_empty-state-gap: var(--xh-stack-gap-sm);
7189
+ --xh-_empty-state-py: var(--xh-section-py-sm);
6984
7190
  --xh-_empty-state-icon-size: var(--xh-glyph-size-xl);
6985
7191
  --xh-_empty-state-title-size: var(--xh-control-font-md);
6986
7192
  }
6987
7193
 
6988
7194
  [data-scope='empty-state'][data-part='root'][data-size='lg'] {
6989
- --xh-_empty-state-gap: var(--xh-space-6);
6990
- --xh-_empty-state-py: var(--xh-space-8);
7195
+ --xh-_empty-state-gap: var(--xh-stack-gap-lg);
7196
+ --xh-_empty-state-py: var(--xh-section-py-lg);
6991
7197
  --xh-_empty-state-icon-size: var(--xh-glyph-size-3xl);
6992
7198
  --xh-_empty-state-title-size: var(--xh-text-heading-3-size);
6993
7199
  }
@@ -6997,11 +7203,14 @@ input[data-scope='mention'][data-part='input'] {
6997
7203
  align-items: center;
6998
7204
  justify-content: center;
6999
7205
  flex: none;
7206
+ /* 作者塞进图标槽的 XhIcon 与皮肤画的字形同一把尺,都按展示档的图标框量 */
7207
+ --xh-icon-size: var(--xh-empty-state-icon-size, var(--xh-_empty-state-icon-size));
7208
+
7000
7209
  block-size: var(--xh-empty-state-icon-size, var(--xh-_empty-state-icon-size));
7001
7210
  inline-size: var(--xh-empty-state-icon-size, var(--xh-_empty-state-icon-size));
7002
7211
  color: var(--xh-empty-state-icon-fg, var(--xh-fg-subtle));
7003
7212
  /* 图标常是一个字形,字号跟着图标框走,line-height 不再另占高度 */
7004
- font-size: var(--xh-empty-state-icon-font-size, var(--xh-text-heading-1-size));
7213
+ font-size: var(--xh-empty-state-icon-font-size, var(--xh-_empty-state-icon-size));
7005
7214
  line-height: var(--xh-leading-none);
7006
7215
  }
7007
7216
 
@@ -7029,6 +7238,13 @@ input[data-scope='mention'][data-part='input'] {
7029
7238
  gap: var(--xh-empty-state-action-gap, var(--xh-space-2));
7030
7239
  }
7031
7240
 
7241
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
7242
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
7243
+ [data-scope='empty-state'][data-part='icon'][hidden],
7244
+ [data-scope='empty-state'][data-part='action'][hidden] {
7245
+ display: none;
7246
+ }
7247
+
7032
7248
  /* styles/skeleton.css */
7033
7249
  /* 一条比底色略亮的窄带从头扫到尾。背景图比自身宽一倍,靠移动背景位置扫过去,
7034
7250
  不动 transform 也不动布局,整段动画只在合成层上跑 */
@@ -7221,7 +7437,7 @@ input[data-scope='mention'][data-part='input'] {
7221
7437
  --xh-_accordion-trigger-h: var(--xh-control-h-md);
7222
7438
  --xh-_accordion-trigger-px: var(--xh-control-px-md);
7223
7439
  --xh-_accordion-trigger-gap: var(--xh-control-gap-md);
7224
- --xh-_accordion-trigger-font-size: var(--xh-text-label-size);
7440
+ --xh-_accordion-trigger-font-size: var(--xh-control-font-md);
7225
7441
 
7226
7442
  /* 语气落在展开着的标题上,指示器写在标题里、跟着继承这个色,不另立规则。
7227
7443
  没写 data-tone 时 --xh-_tone-fg 没被声明,退回原来的前景色。
@@ -7254,10 +7470,25 @@ input[data-scope='mention'][data-part='input'] {
7254
7470
  }
7255
7471
 
7256
7472
  [data-scope='accordion'][data-part='item'] {
7257
- border-block-end: var(--xh-stroke-thin) solid var(--xh-accordion-item-border, var(--xh-border-default));
7258
7473
  min-inline-size: 0;
7259
7474
  }
7260
7475
 
7476
+ /* 分隔线画在后一条的起始边,条与条之间才只有一条,末条也不会留一条悬空线
7477
+ (根没有外框接住它)。只认自己的直接子条目:套在条目里的另一份手风琴由它自己的根管。
7478
+ 横排时换成行内轴那一侧 */
7479
+ [data-scope='accordion'][data-part='root']
7480
+ > [data-scope='accordion'][data-part='item']
7481
+ + [data-scope='accordion'][data-part='item'] {
7482
+ border-block-start: var(--xh-stroke-thin) solid var(--xh-accordion-item-border, var(--xh-border-subtle));
7483
+ }
7484
+
7485
+ [data-scope='accordion'][data-part='root'][data-orientation='horizontal']
7486
+ > [data-scope='accordion'][data-part='item']
7487
+ + [data-scope='accordion'][data-part='item'] {
7488
+ border-block-start: 0;
7489
+ border-inline-start: var(--xh-stroke-thin) solid var(--xh-accordion-item-border, var(--xh-border-subtle));
7490
+ }
7491
+
7261
7492
  [data-scope='accordion'][data-part='header'] {
7262
7493
  margin: 0;
7263
7494
  font: inherit;
@@ -7369,6 +7600,14 @@ input[data-scope='mention'][data-part='input'] {
7369
7600
  }
7370
7601
  }
7371
7602
 
7603
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
7604
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
7605
+ [data-scope='accordion'][data-part='root'][hidden],
7606
+ [data-scope='accordion'][data-part='trigger'][hidden],
7607
+ [data-scope='accordion'][data-part='indicator'][hidden] {
7608
+ display: none;
7609
+ }
7610
+
7372
7611
  /* styles/anchor.css */
7373
7612
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
7374
7613
  [data-scope='anchor'] {
@@ -7379,7 +7618,7 @@ input[data-scope='mention'][data-part='input'] {
7379
7618
  这里不给 display,UA 的 [hidden]{display:none} 就仍然压得住 */
7380
7619
  [data-scope='anchor'][data-part='root'] {
7381
7620
  /* 尺寸档只换这两个私有槽,链接从 root 继承它们,换档不必给每个部件各写一条选择器 */
7382
- --xh-_anchor-font-size: var(--xh-text-label-size);
7621
+ --xh-_anchor-font-size: var(--xh-control-font-md);
7383
7622
  --xh-_anchor-link-px: var(--xh-control-px-md);
7384
7623
  /* 当前那一节的指示条与文字随语气走。没写 data-tone 时这两个槽都没被声明,退回原来的品牌色。
7385
7624
  指示条是装饰性的色条,取柔和档;文字要压在普通背景上读,取语气的文字档。
@@ -7571,73 +7810,137 @@ input[data-scope='mention'][data-part='input'] {
7571
7810
  display: none;
7572
7811
  }
7573
7812
 
7813
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
7814
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
7815
+ [data-scope='avatar'][data-part='root'][hidden] {
7816
+ display: none;
7817
+ }
7818
+
7574
7819
  /* styles/badge.css */
7575
7820
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
7576
7821
  [data-scope='badge'] {
7577
7822
  --xh-badge-skin: 1;
7578
7823
  }
7579
7824
 
7825
+ /* 锚点:被标记的那个东西(按钮、头像、标签页)放进它里面。
7826
+ 角标绝对定位在它的角上,所以这一层必须建定位上下文,且不能自己撑出尺寸 */
7580
7827
  [data-scope='badge'][data-part='root'] {
7828
+ position: relative;
7829
+ display: inline-flex;
7830
+ /* 角标探出宿主边界是常态,不能被裁掉 */
7831
+ overflow: visible;
7832
+ vertical-align: middle;
7833
+ }
7834
+
7835
+ /* 锚点也可能被作者整块收起 */
7836
+ [data-scope='badge'][data-part='root'][hidden] {
7837
+ display: none;
7838
+ }
7839
+
7840
+ /* 角标本身。档位换的是圆点直径、两位数时的最小宽度与字号——
7841
+ 不是药丸那套内衬与行高:那是 tag 的活 */
7842
+ [data-scope='badge'][data-part='indicator'] {
7843
+ /* 每一档的盒都要大于字号:两位数在等高的盒里会被撑破。
7844
+ 字号刻度最小就是 12px,所以往上抬盒子而不是往下压字 */
7845
+ --xh-_badge-dot: var(--xh-space-2);
7846
+ --xh-_badge-min: var(--xh-space-5);
7847
+ --xh-_badge-px: var(--xh-space-1);
7848
+ --xh-_badge-font: var(--xh-text-secondary-size);
7849
+
7850
+ /* 不设 z-index:角标在 DOM 序里排在宿主之后,本来就压在上面 */
7851
+ position: absolute;
7581
7852
  display: inline-flex;
7582
7853
  align-items: center;
7583
- gap: var(--xh-space-1);
7584
- padding-inline: var(--xh-space-2);
7585
- padding-block: var(--xh-space-0_5);
7586
- border: var(--xh-stroke-thin) solid transparent;
7587
- border-radius: var(--xh-shape-pill);
7588
- background: var(--xh-badge-bg, var(--xh-bg-subtle));
7589
- color: var(--xh-badge-fg, var(--xh-fg-default));
7590
- font-size: var(--xh-badge-font-size, var(--xh-text-caption-size));
7854
+ justify-content: center;
7855
+ box-sizing: border-box;
7856
+ min-inline-size: var(--xh-badge-min-size, var(--xh-_badge-min));
7857
+ block-size: var(--xh-badge-min-size, var(--xh-_badge-min));
7858
+ padding-inline: var(--xh-badge-px, var(--xh-_badge-px));
7859
+ border: var(--xh-stroke-thin) solid var(--xh-badge-ring, var(--xh-bg-surface));
7860
+ border-radius: var(--xh-badge-radius, var(--xh-shape-pill));
7861
+ /* 角标默认就是实心的:贴在别的东西上,淡底与描边都看不清 */
7862
+ background: var(--xh-badge-bg, var(--xh-_tone, var(--xh-bg-brand)));
7863
+ color: var(--xh-badge-fg, var(--xh-_tone-on, var(--xh-fg-on-brand)));
7864
+ font-size: var(--xh-badge-font-size, var(--xh-_badge-font));
7591
7865
  font-weight: var(--xh-badge-font-weight, var(--xh-font-weight-medium));
7592
7866
  line-height: var(--xh-leading-none);
7867
+ /* 出的是计数,数字必须等宽:不然 9 跳到 10 时角标的宽度会抖一下 */
7868
+ font-variant-numeric: tabular-nums;
7593
7869
  white-space: nowrap;
7870
+ pointer-events: none;
7594
7871
  }
7595
7872
 
7596
7873
  /* 声明了 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
7597
7874
  计数为 0 且没开 showZero 时连接层会发 hidden */
7598
- [data-scope='badge'][data-part='root'][hidden] {
7875
+ [data-scope='badge'][data-part='indicator'][hidden] {
7599
7876
  display: none;
7600
7877
  }
7601
7878
 
7602
7879
  /* 圆点形态:只表示「有」,不表示「有几个」——收掉内边距与文字盒 */
7603
- [data-scope='badge'][data-part='root'][data-dot] {
7604
- inline-size: var(--xh-badge-dot-size, var(--xh-space-2));
7605
- block-size: var(--xh-badge-dot-size, var(--xh-space-2));
7880
+ [data-scope='badge'][data-part='indicator'][data-dot] {
7881
+ min-inline-size: var(--xh-badge-dot-size, var(--xh-_badge-dot));
7882
+ inline-size: var(--xh-badge-dot-size, var(--xh-_badge-dot));
7883
+ block-size: var(--xh-badge-dot-size, var(--xh-_badge-dot));
7606
7884
  padding: 0;
7607
7885
  font-size: 0;
7608
7886
  }
7609
7887
 
7610
- /* —— 变体 —— */
7611
- /* 形态只决定颜色怎么用;用哪族颜色由 data-tone 决定,没写 tone 就沿用原来的品牌/中性配色 */
7612
- [data-scope='badge'][data-part='root'][data-variant='solid'] {
7613
- background: var(--xh-_tone, var(--xh-bg-brand));
7614
- color: var(--xh-_tone-on, var(--xh-fg-on-brand));
7888
+ /* —— 落点 —— */
7889
+ /* inset 的逻辑属性写,rtl end 自动落到左边;translate 让角标压住宿主的角 */
7890
+ [data-scope='badge'][data-part='indicator'][data-placement='top-end'] {
7891
+ inset-block-start: 0;
7892
+ inset-inline-end: 0;
7893
+ translate: 50% -50%;
7615
7894
  }
7616
7895
 
7617
- [data-scope='badge'][data-part='root'][data-variant='subtle'] {
7618
- background: var(--xh-_tone-subtle, var(--xh-bg-subtle));
7619
- color: var(--xh-_tone-fg, var(--xh-fg-default));
7896
+ [data-scope='badge'][data-part='indicator'][data-placement='top-start'] {
7897
+ inset-block-start: 0;
7898
+ inset-inline-start: 0;
7899
+ translate: -50% -50%;
7620
7900
  }
7621
7901
 
7622
- [data-scope='badge'][data-part='root'][data-variant='outline'] {
7623
- border-color: var(--xh-_tone-border, var(--xh-border-default));
7624
- background: transparent;
7625
- color: var(--xh-_tone-fg, var(--xh-fg-default));
7902
+ [data-scope='badge'][data-part='indicator'][data-placement='bottom-end'] {
7903
+ inset-block-end: 0;
7904
+ inset-inline-end: 0;
7905
+ translate: 50% 50%;
7906
+ }
7907
+
7908
+ [data-scope='badge'][data-part='indicator'][data-placement='bottom-start'] {
7909
+ inset-block-end: 0;
7910
+ inset-inline-start: 0;
7911
+ translate: -50% 50%;
7912
+ }
7913
+
7914
+ /* rtl 下 translate 的行内轴要跟着翻,否则角标会往宿主外面跑 */
7915
+ [dir='rtl'] [data-scope='badge'][data-part='indicator'][data-placement='top-end'] {
7916
+ translate: -50% -50%;
7917
+ }
7918
+
7919
+ [dir='rtl'] [data-scope='badge'][data-part='indicator'][data-placement='top-start'] {
7920
+ translate: 50% -50%;
7921
+ }
7922
+
7923
+ [dir='rtl'] [data-scope='badge'][data-part='indicator'][data-placement='bottom-end'] {
7924
+ translate: -50% 50%;
7925
+ }
7926
+
7927
+ [dir='rtl'] [data-scope='badge'][data-part='indicator'][data-placement='bottom-start'] {
7928
+ translate: 50% 50%;
7626
7929
  }
7627
7930
 
7628
7931
  /* —— 尺寸 —— */
7629
- /* 徽标是随文排的药丸,不占控件行高,档位走间距与字号而不是 control-h */
7630
- [data-scope='badge'][data-part='root'][data-size='sm'] {
7631
- gap: var(--xh-space-0_5);
7632
- padding-inline: var(--xh-space-1_5);
7633
- padding-block: var(--xh-space-0);
7932
+ [data-scope='badge'][data-part='indicator'][data-size='sm'] {
7933
+ --xh-_badge-dot: var(--xh-space-1_5);
7934
+ --xh-_badge-min: var(--xh-space-4);
7935
+ --xh-_badge-px: var(--xh-space-0_5);
7936
+ --xh-_badge-font: var(--xh-text-caption-size);
7634
7937
  }
7635
7938
 
7636
- [data-scope='badge'][data-part='root'][data-size='lg'] {
7637
- gap: var(--xh-space-1_5);
7638
- padding-inline: var(--xh-space-3);
7639
- padding-block: var(--xh-space-1);
7640
- font-size: var(--xh-text-secondary-size);
7939
+ [data-scope='badge'][data-part='indicator'][data-size='lg'] {
7940
+ --xh-_badge-dot: var(--xh-space-2_5);
7941
+ --xh-_badge-min: var(--xh-space-6);
7942
+ --xh-_badge-px: var(--xh-space-1_5);
7943
+ --xh-_badge-font: var(--xh-text-body-size);
7641
7944
  }
7642
7945
 
7643
7946
  /* styles/breadcrumb.css */
@@ -7653,7 +7956,7 @@ input[data-scope='mention'][data-part='input'] {
7653
7956
  --xh-icon-size: var(--xh-breadcrumb-icon-size, var(--xh-glyph-size-text));
7654
7957
 
7655
7958
  /* 尺寸档只换这两个私有槽,列表与链接都从 root 继承它们,换档不必给每个部件各写一条选择器 */
7656
- --xh-_breadcrumb-font-size: var(--xh-text-label-size);
7959
+ --xh-_breadcrumb-font-size: var(--xh-control-font-md);
7657
7960
  --xh-_breadcrumb-gap: var(--xh-space-2);
7658
7961
  /* 当前项与链接悬停的强调色随语气走。没写 data-tone 时 --xh-_tone-fg 没被声明,
7659
7962
  退回原来的前景色。聚焦环不在其列,它恒是 --xh-ring-focus */
@@ -7934,6 +8237,12 @@ input[data-scope='mention'][data-part='input'] {
7934
8237
  animation: none;
7935
8238
  }
7936
8239
 
8240
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
8241
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
8242
+ [data-scope='button'][data-part='root'][hidden] {
8243
+ display: none;
8244
+ }
8245
+
7937
8246
  /* styles/calendar.css */
7938
8247
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
7939
8248
  [data-scope='calendar'] {
@@ -8034,33 +8343,33 @@ input[data-scope='mention'][data-part='input'] {
8034
8343
  transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
8035
8344
  }
8036
8345
 
8037
- [data-scope='calendar'][data-part='prev-year-trigger'],
8346
+ [data-scope='calendar'][data-part='prev-year-trigger'][hidden],
8038
8347
  [data-scope='calendar'][data-part='prev-trigger'][hidden],
8039
- [data-scope='calendar'][data-part='next-year-trigger'],
8348
+ [data-scope='calendar'][data-part='next-year-trigger'][hidden],
8040
8349
  [data-scope='calendar'][data-part='next-trigger'][hidden] {
8041
8350
  display: none;
8042
8351
  }
8043
8352
 
8044
- [data-scope='calendar'][data-part='prev-year-trigger'],
8353
+ [data-scope='calendar'][data-part='prev-year-trigger']:hover:not(:disabled),
8045
8354
  [data-scope='calendar'][data-part='prev-trigger']:hover:not(:disabled),
8046
- [data-scope='calendar'][data-part='next-year-trigger'],
8355
+ [data-scope='calendar'][data-part='next-year-trigger']:hover:not(:disabled),
8047
8356
  [data-scope='calendar'][data-part='next-trigger']:hover:not(:disabled) {
8048
8357
  background: var(--xh-calendar-nav-bg-hover, var(--xh-bg-subtle-hover));
8049
8358
  color: var(--xh-fg-default);
8050
8359
  }
8051
8360
 
8052
8361
  /* 翻月是单体控件,禁用走原生 :disabled(连接层输出的正是原生 disabled) */
8053
- [data-scope='calendar'][data-part='prev-year-trigger'],
8362
+ [data-scope='calendar'][data-part='prev-year-trigger']:disabled,
8054
8363
  [data-scope='calendar'][data-part='prev-trigger']:disabled,
8055
- [data-scope='calendar'][data-part='next-year-trigger'],
8364
+ [data-scope='calendar'][data-part='next-year-trigger']:disabled,
8056
8365
  [data-scope='calendar'][data-part='next-trigger']:disabled {
8057
8366
  color: var(--xh-fg-disabled);
8058
8367
  cursor: not-allowed;
8059
8368
  }
8060
8369
 
8061
- [data-scope='calendar'][data-part='prev-year-trigger'],
8370
+ [data-scope='calendar'][data-part='prev-year-trigger']:focus-visible,
8062
8371
  [data-scope='calendar'][data-part='prev-trigger']:focus-visible,
8063
- [data-scope='calendar'][data-part='next-year-trigger'],
8372
+ [data-scope='calendar'][data-part='next-year-trigger']:focus-visible,
8064
8373
  [data-scope='calendar'][data-part='next-trigger']:focus-visible {
8065
8374
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
8066
8375
  outline-offset: var(--xh-ring-offset);
@@ -8160,9 +8469,10 @@ input[data-scope='mention'][data-part='input'] {
8160
8469
  display: none;
8161
8470
  }
8162
8471
 
8163
- /* 格子是区间底色的画布:连续背景铺在这一层,圆角的选中片留给 trigger。
8472
+ /* 格子是区间底色的画布:底色由格子的 ::before 铺出来,圆角的选中片留给 trigger。
8164
8473
  铺在 trigger 上会被格间空隙切断,区间看起来就是一串断开的圆点 */
8165
8474
  [data-scope='calendar'][data-part='cell'] {
8475
+ position: relative;
8166
8476
  display: flex;
8167
8477
  align-items: center;
8168
8478
  justify-content: center;
@@ -8173,22 +8483,46 @@ input[data-scope='mention'][data-part='input'] {
8173
8483
  display: none;
8174
8484
  }
8175
8485
 
8176
- [data-scope='calendar'][data-part='cell'][data-in-range] {
8486
+ /* 区间底色:横向铺满格子,相邻两格接成一条;纵向收在格子内衬里,行与行之间留出空当 */
8487
+ [data-scope='calendar'][data-part='cell'][data-in-range]::before {
8488
+ content: '';
8489
+ position: absolute;
8490
+ inset-block: var(--xh-calendar-cell-gap, var(--xh-space-0_5));
8491
+ inset-inline: 0;
8177
8492
  background: var(--xh-calendar-range-bg, var(--xh-bg-brand-subtle));
8178
8493
  }
8179
8494
 
8180
- /* 区间两端各自收圆:中间那些格子保持直角,底色才连成一条 */
8181
- [data-scope='calendar'][data-part='cell'][data-range-start] {
8495
+ /* 两端那一格只铺半格,另外半格由选中片占满:区间收在圆点上而不是收在格子边上。
8496
+ 起止落在同一格时两条一起生效,底色宽度归零,只剩那枚圆点 */
8497
+ [data-scope='calendar'][data-part='cell'][data-in-range][data-range-start]::before {
8498
+ inset-inline-start: 50%;
8499
+ }
8500
+
8501
+ [data-scope='calendar'][data-part='cell'][data-in-range][data-range-end]::before {
8502
+ inset-inline-end: 50%;
8503
+ }
8504
+
8505
+ /* 行首与行尾收圆:区间跨周时每一行各是一条两头圆的横杠。
8506
+ 摆了周序号格的行里,行首那一格排在它后面 */
8507
+ [data-scope='calendar'][data-part='week-row'] > [data-part='cell'][data-in-range]:first-child::before,
8508
+ [data-scope='calendar'][data-part='week-row'] > [data-part='week-number'] + [data-part='cell'][data-in-range]::before {
8182
8509
  border-start-start-radius: var(--xh-calendar-cell-radius, var(--xh-shape-pill));
8183
8510
  border-end-start-radius: var(--xh-calendar-cell-radius, var(--xh-shape-pill));
8184
8511
  }
8185
8512
 
8186
- [data-scope='calendar'][data-part='cell'][data-range-end] {
8513
+ [data-scope='calendar'][data-part='week-row'] > [data-part='cell'][data-in-range]:last-child::before {
8187
8514
  border-start-end-radius: var(--xh-calendar-cell-radius, var(--xh-shape-pill));
8188
8515
  border-end-end-radius: var(--xh-calendar-cell-radius, var(--xh-shape-pill));
8189
8516
  }
8190
8517
 
8518
+ /* 粗粒度的格子之间有间隙,底色本就接不成一条,每一格各自收圆 */
8519
+ [data-scope='calendar'][data-part='grid']:is([data-view='month'], [data-view='quarter'], [data-view='year']) > [data-part='cell'][data-in-range]::before {
8520
+ border-radius: var(--xh-calendar-cell-radius, var(--xh-shape-pill));
8521
+ }
8522
+
8191
8523
  [data-scope='calendar'][data-part='cell-trigger'] {
8524
+ /* 区间底色是格子上绝对定位的伪元素,选中片得定位才排在它之后 */
8525
+ position: relative;
8192
8526
  display: flex;
8193
8527
  flex: 1;
8194
8528
  align-items: center;
@@ -8344,10 +8678,10 @@ input[data-scope='mention'][data-part='input'] {
8344
8678
  [data-scope='card'][data-part='header'] {
8345
8679
  display: flex;
8346
8680
  flex-direction: column;
8347
- gap: var(--xh-space-1);
8681
+ gap: var(--xh-card-header-gap, var(--xh-space-1));
8348
8682
  padding: var(--xh-_card-pad);
8349
8683
  /* 头下面若还有别的段,间距由那一段自己的内边距接上,这里不重复留白 */
8350
- padding-block-end: var(--xh-space-2);
8684
+ padding-block-end: var(--xh-card-header-pb, var(--xh-space-2));
8351
8685
  }
8352
8686
 
8353
8687
  [data-scope='card'][data-part='title'] {
@@ -8373,22 +8707,22 @@ input[data-scope='mention'][data-part='input'] {
8373
8707
 
8374
8708
  /* 头与身相邻时,头已经收窄了下边距,身不必再从顶上留一份 */
8375
8709
  [data-scope='card'][data-part='header'] + [data-part='body'] {
8376
- padding-block-start: var(--xh-space-2);
8710
+ padding-block-start: var(--xh-card-body-pt, var(--xh-space-2));
8377
8711
  }
8378
8712
 
8379
8713
  [data-scope='card'][data-part='footer'] {
8380
8714
  display: flex;
8381
8715
  align-items: center;
8382
- gap: var(--xh-space-2);
8716
+ gap: var(--xh-card-footer-gap, var(--xh-space-2));
8383
8717
  padding: var(--xh-_card-pad);
8384
- padding-block-start: var(--xh-space-2);
8718
+ padding-block-start: var(--xh-card-footer-pt, var(--xh-space-2));
8385
8719
  }
8386
8720
 
8387
8721
  /* —— 分段 —— */
8388
8722
  /* 分隔线画在下一段的上边,段与段之间才只有一条 */
8389
8723
  [data-scope='card'][data-part='root'][data-segmented] [data-part='body'],
8390
8724
  [data-scope='card'][data-part='root'][data-segmented] [data-part='footer'] {
8391
- border-block-start: var(--xh-stroke-thin) solid var(--xh-card-border, var(--xh-border-subtle));
8725
+ border-block-start: var(--xh-stroke-thin) solid var(--xh-card-divider, var(--xh-border-subtle));
8392
8726
  padding-block-start: var(--xh-_card-pad);
8393
8727
  }
8394
8728
 
@@ -8396,6 +8730,15 @@ input[data-scope='mention'][data-part='input'] {
8396
8730
  padding-block-end: var(--xh-_card-pad);
8397
8731
  }
8398
8732
 
8733
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
8734
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
8735
+ [data-scope='card'][data-part='root'][hidden],
8736
+ [data-scope='card'][data-part='cover'][hidden],
8737
+ [data-scope='card'][data-part='header'][hidden],
8738
+ [data-scope='card'][data-part='footer'][hidden] {
8739
+ display: none;
8740
+ }
8741
+
8399
8742
  /* styles/carousel.css */
8400
8743
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
8401
8744
  [data-scope='carousel'] {
@@ -8633,6 +8976,9 @@ input[data-scope='mention'][data-part='input'] {
8633
8976
 
8634
8977
  /* 坐标由定位引擎写进 style(inset-inline-start / inset-block-start),这里只定位模式与层级 */
8635
8978
  [data-scope='cascader'][data-part='positioner'] {
8979
+ /* 列区的自绘条浮在内容之上:轨道不上底色,实色轨道会在列区下缘糊出一条灰带 */
8980
+ --xh-scrollbar-track-bg: transparent;
8981
+
8636
8982
  position: fixed;
8637
8983
  z-index: var(--xh-cascader-layer, var(--xh-layer-popover));
8638
8984
  /* 空壳不吃指针,交互只发生在 content 里 */
@@ -8652,9 +8998,11 @@ input[data-scope='mention'][data-part='input'] {
8652
8998
  /* 尺寸档只换这几个私有槽,盒与列里的条目都从这两处继承它们,换档不必给每个部件各写一条选择器 */
8653
8999
  --xh-_cascader-h: var(--xh-control-h-md);
8654
9000
  --xh-_cascader-px: var(--xh-control-px-md);
9001
+ --xh-_cascader-row-py: var(--xh-list-option-py-md);
9002
+ --xh-_cascader-row-px: var(--xh-control-px-md);
8655
9003
  --xh-_cascader-gap: var(--xh-control-gap-md);
8656
- --xh-_cascader-font-size: var(--xh-text-body-size);
8657
- --xh-_cascader-label-font-size: var(--xh-text-label-size);
9004
+ --xh-_cascader-font-size: var(--xh-control-font-md);
9005
+ --xh-_cascader-label-font-size: var(--xh-control-font-md);
8658
9006
 
8659
9007
  /* 形态档只换触发框的描边与底色这三个槽,浮层与列不跟着变:
8660
9008
  变的是「这是个输入位」的表达方式,不是弹出内容的表达方式 */
@@ -8713,6 +9061,8 @@ input[data-scope='mention'][data-part='input'] {
8713
9061
  --xh-icon-size: var(--xh-cascader-icon-size, var(--xh-glyph-size-sm));
8714
9062
  --xh-_cascader-h: var(--xh-control-h-sm);
8715
9063
  --xh-_cascader-px: var(--xh-control-px-sm);
9064
+ --xh-_cascader-row-py: var(--xh-list-option-py-sm);
9065
+ --xh-_cascader-row-px: var(--xh-control-px-sm);
8716
9066
  --xh-_cascader-gap: var(--xh-control-gap-sm);
8717
9067
  --xh-_cascader-font-size: var(--xh-control-font-sm);
8718
9068
  --xh-_cascader-label-font-size: var(--xh-control-font-sm);
@@ -8722,6 +9072,8 @@ input[data-scope='mention'][data-part='input'] {
8722
9072
  --xh-icon-size: var(--xh-cascader-icon-size, var(--xh-glyph-size-lg));
8723
9073
  --xh-_cascader-h: var(--xh-control-h-lg);
8724
9074
  --xh-_cascader-px: var(--xh-control-px-lg);
9075
+ --xh-_cascader-row-py: var(--xh-list-option-py-lg);
9076
+ --xh-_cascader-row-px: var(--xh-control-px-lg);
8725
9077
  --xh-_cascader-gap: var(--xh-control-gap-lg);
8726
9078
  --xh-_cascader-font-size: var(--xh-control-font-lg);
8727
9079
  --xh-_cascader-label-font-size: var(--xh-control-font-lg);
@@ -8961,6 +9313,7 @@ input[data-scope='mention'][data-part='input'] {
8961
9313
  display: flex;
8962
9314
  flex: none;
8963
9315
  flex-direction: column;
9316
+ gap: var(--xh-cascader-column-gap, var(--xh-list-option-gap));
8964
9317
  min-inline-size: var(--xh-cascader-column-min-w, 7rem);
8965
9318
  block-size: var(--xh-cascader-column-h, var(--xh-viewport-h-sm));
8966
9319
  padding-block: var(--xh-cascader-column-py, var(--xh-space-1));
@@ -8996,8 +9349,8 @@ input[data-scope='mention'][data-part='input'] {
8996
9349
  align-items: center;
8997
9350
  gap: var(--xh-cascader-row-gap, var(--xh-_cascader-gap));
8998
9351
  max-inline-size: var(--xh-cascader-row-max-w, var(--xh-overlay-max-w));
8999
- padding-block: var(--xh-cascader-row-py, var(--xh-space-1_5));
9000
- padding-inline: var(--xh-cascader-row-px, var(--xh-control-px-md));
9352
+ padding-block: var(--xh-cascader-row-py, var(--xh-_cascader-row-py));
9353
+ padding-inline: var(--xh-cascader-row-px, var(--xh-_cascader-row-px));
9001
9354
  border-radius: var(--xh-cascader-row-radius, var(--xh-shape-control));
9002
9355
  color: var(--xh-cascader-row-fg, var(--xh-fg-default));
9003
9356
  font-size: var(--xh-cascader-row-font-size, var(--xh-_cascader-font-size));
@@ -9050,22 +9403,17 @@ input[data-scope='mention'][data-part='input'] {
9050
9403
  cursor: not-allowed;
9051
9404
  }
9052
9405
 
9053
- /* 分支条目行尾画右向小箭头:不点开也看得出还有下一级。
9054
- 全边框描好后抹掉块末与行首两边,剩下的直角旋成箭头;位置由 item-text 的 flex:1 顶到行尾 */
9406
+ /* 分支条目行尾画右向小箭头:不点开也看得出还有下一级。位置由 item-text 的 flex:1 顶到行尾。
9407
+ 与菜单族的子菜单箭头同走字形令牌——此前这里是「描全边框再抹掉两条、把剩下的直角旋 45 度」,
9408
+ 作者换掉标记时换不动它,RTL 还得再翻一次旋转角 */
9055
9409
  [data-scope='cascader'][data-part='item'][data-branch]::after {
9056
9410
  content: '';
9057
9411
  flex: none;
9058
- inline-size: var(--xh-cascader-branch-arrow-size, var(--xh-space-1_5));
9059
- block-size: var(--xh-cascader-branch-arrow-size, var(--xh-space-1_5));
9060
- border: var(--xh-glyph-stroke-light) solid var(--xh-cascader-branch-arrow-fg, var(--xh-fg-subtle));
9061
- border-block-end: 0;
9062
- border-inline-start: 0;
9063
- rotate: 45deg;
9064
- }
9065
-
9066
- /* rtl 下剩下的是块首与行末(物理左上)两边,反向旋 45 度才指向行进方向 */
9067
- [dir='rtl'] [data-scope='cascader'][data-part='item'][data-branch]::after {
9068
- rotate: -45deg;
9412
+ inline-size: var(--xh-cascader-branch-arrow-size, var(--xh-icon-size, var(--xh-glyph-size-text)));
9413
+ block-size: var(--xh-cascader-branch-arrow-size, var(--xh-icon-size, var(--xh-glyph-size-text)));
9414
+ background-color: var(--xh-cascader-branch-arrow-fg, var(--xh-fg-subtle));
9415
+ -webkit-mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
9416
+ mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
9069
9417
  }
9070
9418
 
9071
9419
  [data-scope='cascader'][data-part='item'][data-branch][data-disabled]::after {
@@ -9087,7 +9435,7 @@ input[data-scope='mention'][data-part='input'] {
9087
9435
  align-items: center;
9088
9436
  justify-content: center;
9089
9437
  inline-size: var(--xh-cascader-item-indicator-size, var(--xh-control-indicator-size));
9090
- color: var(--xh-cascader-item-indicator-fg, var(--xh-_tone, var(--xh-bg-brand)));
9438
+ color: var(--xh-cascader-item-indicator-fg, var(--xh-_tone, var(--xh-fg-brand)));
9091
9439
  visibility: hidden;
9092
9440
  }
9093
9441
 
@@ -9113,11 +9461,11 @@ input[data-scope='mention'][data-part='input'] {
9113
9461
 
9114
9462
  /* 级联勾选的半选态只在皮肤自绘(:empty)时露面画横杠:
9115
9463
  作者塞了自己的选中图形时,半选放出来会顶着一个语义相反的勾,表达交还作者 */
9116
- [data-scope='cascader'][data-part='item-indicator'][data-indeterminate]:empty {
9464
+ [data-scope='cascader'][data-part='item-indicator'][data-state='indeterminate']:empty {
9117
9465
  visibility: visible;
9118
9466
  }
9119
9467
 
9120
- [data-scope='cascader'][data-part='item-indicator'][data-indeterminate]:not([data-state='checked']):empty::before {
9468
+ [data-scope='cascader'][data-part='item-indicator'][data-state='indeterminate']:empty::before {
9121
9469
  content: '';
9122
9470
  display: inline-block;
9123
9471
  inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
@@ -9144,7 +9492,7 @@ input[data-scope='mention'][data-part='input'] {
9144
9492
  padding-block: var(--xh-cascader-input-py, var(--xh-space-2));
9145
9493
  padding-inline: var(--xh-cascader-input-px, var(--xh-control-px-md));
9146
9494
  border: none;
9147
- border-block-end: var(--xh-stroke-thin) solid var(--xh-cascader-content-border, var(--xh-border-default));
9495
+ border-block-end: var(--xh-stroke-thin) solid var(--xh-cascader-search-divider, var(--xh-border-subtle));
9148
9496
  border-start-start-radius: inherit;
9149
9497
  border-start-end-radius: inherit;
9150
9498
  background: none;
@@ -9167,6 +9515,7 @@ input[data-scope='mention'][data-part='input'] {
9167
9515
  display: flex;
9168
9516
  flex-basis: 100%;
9169
9517
  flex-direction: column;
9518
+ gap: var(--xh-cascader-search-list-gap, var(--xh-list-option-gap));
9170
9519
  block-size: var(--xh-cascader-column-h, var(--xh-viewport-h-sm));
9171
9520
  padding: var(--xh-cascader-search-p, var(--xh-space-1));
9172
9521
  overflow-y: auto;
@@ -9188,8 +9537,8 @@ input[data-scope='mention'][data-part='input'] {
9188
9537
 
9189
9538
  /* 候选与列内条目同一套行度量,虚拟高亮与悬停同用轻档 */
9190
9539
  [data-scope='cascader'][data-part='search-item'] {
9191
- padding-block: var(--xh-cascader-row-py, var(--xh-space-1_5));
9192
- padding-inline: var(--xh-cascader-row-px, var(--xh-control-px-md));
9540
+ padding-block: var(--xh-cascader-row-py, var(--xh-_cascader-row-py));
9541
+ padding-inline: var(--xh-cascader-row-px, var(--xh-_cascader-row-px));
9193
9542
  overflow: hidden;
9194
9543
  border-radius: var(--xh-cascader-row-radius, var(--xh-shape-control));
9195
9544
  color: var(--xh-cascader-row-fg, var(--xh-fg-default));
@@ -9293,7 +9642,7 @@ input[data-scope='mention'][data-part='input'] {
9293
9642
 
9294
9643
  /* 尺寸档只换方框边长这一个私有槽,勾的字号按边长的比例跟着走;
9295
9644
  指示器从 root 继承这两个槽,换档不必给每个部件各写一条选择器 */
9296
- --xh-_checkbox-box: var(--xh-control-indicator-size);
9645
+ --xh-_checkbox-box: var(--xh-control-indicator-md);
9297
9646
  --xh-_checkbox-glyph: calc(var(--xh-_checkbox-box) * 0.75);
9298
9647
 
9299
9648
  /* 选中态的底与描边随语气走。没写 data-tone 时 --xh-_tone 没被声明,退回原来的品牌色 */
@@ -9310,7 +9659,7 @@ input[data-scope='mention'][data-part='input'] {
9310
9659
  block-size: var(--xh-_checkbox-box);
9311
9660
  padding: 0;
9312
9661
  border: var(--xh-stroke-thin) solid var(--xh-checkbox-border, var(--xh-border-control));
9313
- border-radius: var(--xh-shape-inset);
9662
+ border-radius: var(--xh-checkbox-radius, var(--xh-shape-inset));
9314
9663
  background: var(--xh-checkbox-bg, var(--xh-bg-canvas));
9315
9664
  color: var(--xh-checkbox-fg, var(--xh-_checkbox-on-accent));
9316
9665
  cursor: pointer;
@@ -9320,7 +9669,7 @@ input[data-scope='mention'][data-part='input'] {
9320
9669
  }
9321
9670
 
9322
9671
  /* 半选与全选同样是「有值」,方框都得填上:
9323
- 只填全选的话,半选那条横杠是实心底上的前景色(白),压在白画布上等于没画 */
9672
+ 只填全选的话,半选那条横杠是实心底上的前景色,压在同色画布上等于没画 */
9324
9673
  [data-scope='checkbox'][data-part='root'][data-state='checked'],
9325
9674
  [data-scope='checkbox'][data-part='root'][data-state='indeterminate'] {
9326
9675
  border-color: var(--xh-checkbox-border-checked, var(--xh-_checkbox-accent));
@@ -9354,11 +9703,11 @@ input[data-scope='mention'][data-part='input'] {
9354
9703
  /* —— 尺寸 —— */
9355
9704
  /* 缺省档写在上面的基础规则里 */
9356
9705
  [data-scope='checkbox'][data-part='root'][data-size='sm'] {
9357
- --xh-_checkbox-box: calc(var(--xh-control-indicator-size) - var(--xh-space-1));
9706
+ --xh-_checkbox-box: var(--xh-control-indicator-sm);
9358
9707
  }
9359
9708
 
9360
9709
  [data-scope='checkbox'][data-part='root'][data-size='lg'] {
9361
- --xh-_checkbox-box: calc(var(--xh-control-indicator-size) + var(--xh-space-1));
9710
+ --xh-_checkbox-box: var(--xh-control-indicator-lg);
9362
9711
  }
9363
9712
 
9364
9713
  [data-scope='checkbox'][data-part='indicator'] {
@@ -9387,7 +9736,9 @@ input[data-scope='mention'][data-part='input'] {
9387
9736
  display: none;
9388
9737
  }
9389
9738
 
9390
- /* 半选画一条横杠盖住勾:aria-checked=mixed 在视觉上也得与「全选」分得开 */
9739
+ /* 半选换一枚横杠字形盖住勾:aria-checked=mixed 在视觉上也得与「全选」分得开。
9740
+ 横杠与勾同走字形令牌,作者换掉标记时两态一起换;此前这条是手画的几何盒
9741
+ (60% × stroke-thick),同一页上会出现两种横杠 */
9391
9742
  [data-scope='checkbox'][data-part='indicator'][data-state='indeterminate'] {
9392
9743
  position: relative;
9393
9744
  color: transparent;
@@ -9395,11 +9746,12 @@ input[data-scope='mention'][data-part='input'] {
9395
9746
 
9396
9747
  [data-scope='checkbox'][data-part='indicator'][data-state='indeterminate']::after {
9397
9748
  position: absolute;
9398
- inline-size: 60%;
9399
- block-size: var(--xh-stroke-thick);
9400
- border-radius: var(--xh-shape-pill);
9401
- background: var(--xh-checkbox-indicator-fg, var(--xh-_checkbox-on-accent));
9749
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
9750
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
9751
+ background-color: var(--xh-checkbox-indicator-fg, var(--xh-_checkbox-on-accent));
9402
9752
  content: '';
9753
+ -webkit-mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
9754
+ mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
9403
9755
  }
9404
9756
 
9405
9757
  /* —— 带文字的整行:<label> 包住控件与文字,与 checkbox-group 的条目同一副样子 —— */
@@ -9423,6 +9775,14 @@ input[data-scope='mention'][data-part='input'] {
9423
9775
  user-select: none;
9424
9776
  }
9425
9777
 
9778
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
9779
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
9780
+ [data-scope='checkbox'][data-part='root'][hidden],
9781
+ [data-scope='checkbox'][data-part='indicator'][hidden],
9782
+ [data-scope='checkbox'][data-part='label'][hidden] {
9783
+ display: none;
9784
+ }
9785
+
9426
9786
  /* styles/checkbox-group.css */
9427
9787
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
9428
9788
  [data-scope='checkbox-group'] {
@@ -9554,25 +9914,51 @@ input[data-scope='mention'][data-part='input'] {
9554
9914
  }
9555
9915
 
9556
9916
  /* 全选格的三态:checked 打勾、indeterminate 打横杠、unchecked 留空。
9557
- indeterminate 就是读屏听到的 aria-checked=mixed,两者同源,样式只认 data-state */
9558
- [data-scope='checkbox-group'][data-part='trigger'][data-state='checked']::before {
9917
+ indeterminate 就是读屏听到的 aria-checked=mixed,两者同源,样式只认 data-state
9918
+
9919
+ 字形走 ::after 而不是画方框的那颗 ::before:mask 会把所在元素的描边与底色一并裁成
9920
+ 字形的轮廓,写在 ::before 上就等于把方框本身裁没了,只剩一枚白勾。条目那一侧是
9921
+ 真实节点当方框、它的 ::before 当字形的两层结构,这里 anatomy 到 trigger 为止、
9922
+ 没有第二个节点,只能用第二个伪元素补上那一层。
9923
+ 方框是行首那颗 ::before、宽度即指示符尺寸,所以字形按「盒与字形的宽度差之半」
9924
+ 内推即落在圆心;纵向靠 inset-block: 0 + margin-block: auto 居中。
9925
+ font-size 与 ::before 同值,--xh-icon-size 的 1em 兜底才和条目那侧量得一样大 */
9926
+ [data-scope='checkbox-group'][data-part='trigger'][data-state='checked']::after {
9559
9927
  content: '';
9560
- display: inline-block;
9928
+ position: absolute;
9929
+ inset-block: 0;
9930
+ inset-inline-start: 0;
9931
+ margin-block: auto;
9932
+ margin-inline-start: calc(
9933
+ (
9934
+ var(--xh-checkbox-group-indicator-size, var(--xh-control-indicator-size)) -
9935
+ var(--xh-icon-size, var(--xh-glyph-size-text))
9936
+ ) / 2
9937
+ );
9561
9938
  inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
9562
9939
  block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
9563
- vertical-align: var(--xh-glyph-baseline-shift);
9564
- background-color: currentColor;
9940
+ background-color: var(--xh-checkbox-group-indicator-fg, var(--xh-fg-on-brand));
9941
+ font-size: var(--xh-checkbox-group-indicator-font-size, calc(var(--xh-control-indicator-size) * 0.75));
9565
9942
  -webkit-mask: var(--xh-glyph-mark-check) center / contain no-repeat;
9566
9943
  mask: var(--xh-glyph-mark-check) center / contain no-repeat;
9567
9944
  }
9568
9945
 
9569
- [data-scope='checkbox-group'][data-part='trigger'][data-state='indeterminate']::before {
9946
+ [data-scope='checkbox-group'][data-part='trigger'][data-state='indeterminate']::after {
9570
9947
  content: '';
9571
- display: inline-block;
9948
+ position: absolute;
9949
+ inset-block: 0;
9950
+ inset-inline-start: 0;
9951
+ margin-block: auto;
9952
+ margin-inline-start: calc(
9953
+ (
9954
+ var(--xh-checkbox-group-indicator-size, var(--xh-control-indicator-size)) -
9955
+ var(--xh-icon-size, var(--xh-glyph-size-text))
9956
+ ) / 2
9957
+ );
9572
9958
  inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
9573
9959
  block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
9574
- vertical-align: var(--xh-glyph-baseline-shift);
9575
- background-color: currentColor;
9960
+ background-color: var(--xh-checkbox-group-indicator-fg, var(--xh-fg-on-brand));
9961
+ font-size: var(--xh-checkbox-group-indicator-font-size, calc(var(--xh-control-indicator-size) * 0.75));
9576
9962
  -webkit-mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
9577
9963
  mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
9578
9964
  }
@@ -9589,8 +9975,10 @@ input[data-scope='mention'][data-part='input'] {
9589
9975
  }
9590
9976
 
9591
9977
  /* 全选格与条目同形,但字重加一档,读起来才不像又一个普通选项。
9592
- 它是普通元素而非原生控件(三态只有非原生控件表达得出),禁用态同样只能读 data-disabled */
9978
+ 它是普通元素而非原生控件(三态只有非原生控件表达得出),禁用态同样只能读 data-disabled
9979
+ position 是给叠在方框上的那颗字形 ::after 当定位基准 */
9593
9980
  [data-scope='checkbox-group'][data-part='trigger'] {
9981
+ position: relative;
9594
9982
  display: inline-flex;
9595
9983
  align-items: center;
9596
9984
  gap: var(--xh-checkbox-group-trigger-gap, var(--xh-control-gap-md));
@@ -9877,7 +10265,7 @@ input[data-scope='mention'][data-part='input'] {
9877
10265
  --xh-_collapsible-trigger-h: var(--xh-control-h-md);
9878
10266
  --xh-_collapsible-trigger-px: var(--xh-control-px-md);
9879
10267
  --xh-_collapsible-trigger-gap: var(--xh-control-gap-md);
9880
- --xh-_collapsible-trigger-font-size: var(--xh-text-label-size);
10268
+ --xh-_collapsible-trigger-font-size: var(--xh-control-font-md);
9881
10269
  }
9882
10270
 
9883
10271
  /* —— 尺寸 —— */
@@ -9971,6 +10359,12 @@ input[data-scope='mention'][data-part='input'] {
9971
10359
  }
9972
10360
  }
9973
10361
 
10362
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
10363
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
10364
+ [data-scope='collapsible'][data-part='trigger'][hidden] {
10365
+ display: none;
10366
+ }
10367
+
9974
10368
  /* styles/color-picker.css */
9975
10369
  @keyframes xh-pop-in {
9976
10370
  from {
@@ -10011,7 +10405,7 @@ input[data-scope='mention'][data-part='input'] {
10011
10405
  --xh-_color-picker-h: var(--xh-control-h-md);
10012
10406
  --xh-_color-picker-px: var(--xh-control-px-md);
10013
10407
  --xh-_color-picker-gap: var(--xh-control-gap-md);
10014
- --xh-_color-picker-label-font-size: var(--xh-text-label-size);
10408
+ --xh-_color-picker-label-font-size: var(--xh-control-font-md);
10015
10409
 
10016
10410
  /* 聚焦环恒用固定环色 */
10017
10411
  --xh-_color-picker-ring: var(--xh-ring-focus);
@@ -10021,6 +10415,23 @@ input[data-scope='mention'][data-part='input'] {
10021
10415
  gap: var(--xh-color-picker-gap, var(--xh-space-1));
10022
10416
  }
10023
10417
 
10418
+ /* —— 尺寸 —— */
10419
+ /* 缺省档写在上面的基础规则里。浮层那一侧也要挂:positioner 被搬到 portal 落点,
10420
+ 继承不到根上的私有槽,所以两个部件一起收 */
10421
+ [data-scope='color-picker']:is([data-part='root'], [data-part='positioner'])[data-size='sm'] {
10422
+ --xh-_color-picker-h: var(--xh-control-h-sm);
10423
+ --xh-_color-picker-px: var(--xh-control-px-sm);
10424
+ --xh-_color-picker-gap: var(--xh-control-gap-sm);
10425
+ --xh-_color-picker-label-font-size: var(--xh-control-font-sm);
10426
+ }
10427
+
10428
+ [data-scope='color-picker']:is([data-part='root'], [data-part='positioner'])[data-size='lg'] {
10429
+ --xh-_color-picker-h: var(--xh-control-h-lg);
10430
+ --xh-_color-picker-px: var(--xh-control-px-lg);
10431
+ --xh-_color-picker-gap: var(--xh-control-gap-lg);
10432
+ --xh-_color-picker-label-font-size: var(--xh-control-font-lg);
10433
+ }
10434
+
10024
10435
  [data-scope='color-picker'][data-part='label'] {
10025
10436
  color: var(--xh-color-picker-label-fg, var(--xh-fg-default));
10026
10437
  font-size: var(--xh-color-picker-label-font-size, var(--xh-_color-picker-label-font-size));
@@ -10132,6 +10543,9 @@ input[data-scope='mention'][data-part='input'] {
10132
10543
  引擎没算(尚未落位 / 无引擎 / 贴边归零)时不额外限高 */
10133
10544
  --xh-_color-picker-available-h: 100vh;
10134
10545
 
10546
+ /* 面板的自绘条浮在内容之上:轨道不上底色,实色轨道会在面板右缘糊出一条竖灰带 */
10547
+ --xh-scrollbar-track-bg: transparent;
10548
+
10135
10549
  position: fixed;
10136
10550
  z-index: var(--xh-color-picker-layer, var(--xh-layer-popover));
10137
10551
  /* 空壳不吃指针,交互只发生在 content 上 */
@@ -10427,7 +10841,7 @@ input[data-scope='mention'][data-part='input'] {
10427
10841
  inline-size: var(--xh-color-picker-swatch-item-size, 1.25rem);
10428
10842
  block-size: var(--xh-color-picker-swatch-item-size, 1.25rem);
10429
10843
  padding: 0;
10430
- border: var(--xh-stroke-thin) solid var(--xh-color-picker-swatch-border, var(--xh-border-control));
10844
+ border: var(--xh-stroke-thin) solid var(--xh-color-picker-swatch-border, var(--xh-border-default));
10431
10845
  border-radius: var(--xh-color-picker-swatch-radius, var(--xh-shape-inset));
10432
10846
  cursor: pointer;
10433
10847
  }
@@ -10517,6 +10931,9 @@ input[data-scope='mention'][data-part='input'] {
10517
10931
  引擎没算(尚未落位 / 无引擎)时不额外限高 */
10518
10932
  --xh-_combobox-available-h: 100vh;
10519
10933
 
10934
+ /* 候选列表的自绘条浮在内容之上:轨道不上底色,实色轨道会在列表右缘糊一条竖灰带 */
10935
+ --xh-scrollbar-track-bg: transparent;
10936
+
10520
10937
  position: fixed;
10521
10938
  z-index: var(--xh-combobox-layer, var(--xh-layer-popover));
10522
10939
  /* 空壳不吃指针,交互只发生在 content 与 empty 上 */
@@ -10534,9 +10951,11 @@ input[data-scope='mention'][data-part='input'] {
10534
10951
  换档不必给每个部件各写一条选择器 */
10535
10952
  --xh-_combobox-h: var(--xh-control-h-md);
10536
10953
  --xh-_combobox-px: var(--xh-control-px-md);
10954
+ --xh-_combobox-item-py: var(--xh-list-option-py-md);
10955
+ --xh-_combobox-item-px: var(--xh-control-px-md);
10537
10956
  --xh-_combobox-gap: var(--xh-control-gap-md);
10538
- --xh-_combobox-font-size: var(--xh-text-body-size);
10539
- --xh-_combobox-label-font-size: var(--xh-text-label-size);
10957
+ --xh-_combobox-font-size: var(--xh-control-font-md);
10958
+ --xh-_combobox-label-font-size: var(--xh-control-font-md);
10540
10959
 
10541
10960
  /* 作者塞进指示符槽的图标跟着控件的尺寸档走;它自己写了 size 时仍以作者的为准 */
10542
10961
  --xh-icon-size: var(--xh-combobox-icon-size, var(--xh-glyph-size-md));
@@ -10549,7 +10968,7 @@ input[data-scope='mention'][data-part='input'] {
10549
10968
  /* 聚焦环恒用固定环色;强调色随语气走,只落在勾选标记与选中文字上,正文文字色不动。
10550
10969
  没写 data-tone 时 --xh-_tone 没被声明,两处都退回原来的取值 */
10551
10970
  --xh-_combobox-ring: var(--xh-ring-focus);
10552
- --xh-_combobox-accent: var(--xh-_tone, var(--xh-bg-brand));
10971
+ --xh-_combobox-accent: var(--xh-_tone, var(--xh-fg-brand));
10553
10972
  --xh-_combobox-item-selected-fg: var(--xh-_tone-fg, var(--xh-fg-brand-strong));
10554
10973
  }
10555
10974
 
@@ -10569,6 +10988,8 @@ input[data-scope='mention'][data-part='input'] {
10569
10988
  [data-scope='combobox']:is([data-part='root'], [data-part='positioner'])[data-size='sm'] {
10570
10989
  --xh-_combobox-h: var(--xh-control-h-sm);
10571
10990
  --xh-_combobox-px: var(--xh-control-px-sm);
10991
+ --xh-_combobox-item-py: var(--xh-list-option-py-sm);
10992
+ --xh-_combobox-item-px: var(--xh-control-px-sm);
10572
10993
  --xh-_combobox-gap: var(--xh-control-gap-sm);
10573
10994
  --xh-_combobox-font-size: var(--xh-control-font-sm);
10574
10995
  --xh-_combobox-label-font-size: var(--xh-control-font-sm);
@@ -10579,6 +11000,8 @@ input[data-scope='mention'][data-part='input'] {
10579
11000
  [data-scope='combobox']:is([data-part='root'], [data-part='positioner'])[data-size='lg'] {
10580
11001
  --xh-_combobox-h: var(--xh-control-h-lg);
10581
11002
  --xh-_combobox-px: var(--xh-control-px-lg);
11003
+ --xh-_combobox-item-py: var(--xh-list-option-py-lg);
11004
+ --xh-_combobox-item-px: var(--xh-control-px-lg);
10582
11005
  --xh-_combobox-gap: var(--xh-control-gap-lg);
10583
11006
  --xh-_combobox-font-size: var(--xh-control-font-lg);
10584
11007
  --xh-_combobox-label-font-size: var(--xh-control-font-lg);
@@ -10697,7 +11120,7 @@ input[data-scope='mention'][data-part='input'] {
10697
11120
  [data-scope='combobox'][data-part='control']:has([data-part='input'][data-multiline]) {
10698
11121
  align-items: start;
10699
11122
  block-size: auto;
10700
- padding-block: var(--xh-field-py);
11123
+ padding-block: var(--xh-combobox-input-py, var(--xh-field-py));
10701
11124
  }
10702
11125
 
10703
11126
  [data-scope='combobox'][data-part='input'][data-multiline] {
@@ -10810,6 +11233,7 @@ input[data-scope='mention'][data-part='input'] {
10810
11233
  [data-scope='combobox'][data-part='content'] {
10811
11234
  display: flex;
10812
11235
  flex-direction: column;
11236
+ gap: var(--xh-combobox-content-gap, var(--xh-list-option-gap));
10813
11237
  min-inline-size: var(--xh-combobox-content-min-w, var(--xh-overlay-min-w));
10814
11238
  max-inline-size: var(--xh-combobox-content-max-w, var(--xh-overlay-max-w));
10815
11239
  max-block-size: min(var(--xh-combobox-content-max-h, var(--xh-overlay-max-h)), var(--xh-_combobox-available-h));
@@ -10849,6 +11273,7 @@ input[data-scope='mention'][data-part='input'] {
10849
11273
  [data-scope='combobox'][data-part='item-group'] {
10850
11274
  display: flex;
10851
11275
  flex-direction: column;
11276
+ gap: var(--xh-combobox-item-group-gap, var(--xh-list-option-gap));
10852
11277
  }
10853
11278
 
10854
11279
  [data-scope='combobox'][data-part='item-group'][hidden] {
@@ -10857,7 +11282,7 @@ input[data-scope='mention'][data-part='input'] {
10857
11282
 
10858
11283
  /* 组间留白只加在后继分组上:首组顶上已经有 content 的内边距,再加一层会显得头重 */
10859
11284
  [data-scope='combobox'][data-part='item-group'] + [data-scope='combobox'][data-part='item-group'] {
10860
- margin-block-start: var(--xh-combobox-group-gap, var(--xh-space-2));
11285
+ margin-block-start: var(--xh-combobox-group-gap, var(--xh-space-1_5));
10861
11286
  }
10862
11287
 
10863
11288
  /* 分组标题不是候选、进不了导航,画成小号次要文字,内缩与候选对齐(同一个 padding-inline) */
@@ -10880,8 +11305,8 @@ input[data-scope='mention'][data-part='input'] {
10880
11305
  display: flex;
10881
11306
  align-items: center;
10882
11307
  gap: var(--xh-combobox-item-gap, var(--xh-_combobox-gap));
10883
- padding-block: var(--xh-combobox-item-py, var(--xh-space-1_5));
10884
- padding-inline: var(--xh-combobox-item-px, var(--xh-control-px-md));
11308
+ padding-block: var(--xh-combobox-item-py, var(--xh-_combobox-item-py));
11309
+ padding-inline: var(--xh-combobox-item-px, var(--xh-_combobox-item-px));
10885
11310
  border-radius: var(--xh-combobox-item-radius, var(--xh-shape-control));
10886
11311
  color: var(--xh-combobox-item-fg, var(--xh-fg-default));
10887
11312
  font-size: var(--xh-combobox-item-font-size, var(--xh-_combobox-font-size));
@@ -11139,6 +11564,9 @@ input[data-scope='mention'][data-part='input'] {
11139
11564
  引擎没算(尚未落位 / 无引擎)时不额外限高 */
11140
11565
  --xh-_context-menu-available-h: 100vh;
11141
11566
 
11567
+ /* 条目列表的自绘条浮在内容之上:轨道不上底色,实色轨道会在菜单右缘糊一条竖灰带 */
11568
+ --xh-scrollbar-track-bg: transparent;
11569
+
11142
11570
  position: fixed;
11143
11571
  z-index: var(--xh-context-menu-layer, var(--xh-layer-popover));
11144
11572
  /* 空壳不吃指针,交互只发生在 content 上 */
@@ -11154,10 +11582,10 @@ input[data-scope='mention'][data-part='input'] {
11154
11582
  [data-scope='context-menu']:is([data-part='root'], [data-part='positioner']) {
11155
11583
  /* 尺寸档只换这四个私有槽,条目与分组标题都从这两处继承它们,
11156
11584
  换档不必给每个部件各写一条选择器 */
11157
- --xh-_context-menu-item-py: var(--xh-space-1_5);
11585
+ --xh-_context-menu-item-py: var(--xh-list-option-py-md);
11158
11586
  --xh-_context-menu-item-px: var(--xh-control-px-md);
11159
11587
  --xh-_context-menu-item-gap: var(--xh-control-gap-md);
11160
- --xh-_context-menu-font-size: var(--xh-text-body-size);
11588
+ --xh-_context-menu-font-size: var(--xh-control-font-md);
11161
11589
 
11162
11590
  /* 打开子菜单的触发条目走品牌淡底强档,随语气换色相;没写 data-tone 时退回品牌淡底。
11163
11591
  悬停与键盘焦点恒中性灰轻档、不接语气槽——两档同色相的话打开路径就认不出来了 */
@@ -11172,6 +11600,12 @@ input[data-scope='mention'][data-part='input'] {
11172
11600
  display: contents;
11173
11601
  }
11174
11602
 
11603
+ /* 浮层被搬到 portal 落点,继承不到 root 上的槽:这把尺在被搬走的那一侧再声明一次,
11604
+ 关闭钮与条目里作者塞的图标才和皮肤画的兜底字形一样大 */
11605
+ [data-scope='context-menu'][data-part='content'] {
11606
+ --xh-icon-size: var(--xh-context-menu-icon-size, var(--xh-glyph-size-text));
11607
+ }
11608
+
11175
11609
  [data-scope='context-menu'][data-part='root'][hidden] {
11176
11610
  display: none;
11177
11611
  }
@@ -11180,14 +11614,14 @@ input[data-scope='mention'][data-part='input'] {
11180
11614
  /* 缺省档写在上面的基础规则里。条目高度由 padding 撑出来:
11181
11615
  纵向走 space 档、行内内缩走 control-px 档(随密度轴),换档各挪一级 */
11182
11616
  [data-scope='context-menu']:is([data-part='root'], [data-part='positioner'])[data-size='sm'] {
11183
- --xh-_context-menu-item-py: var(--xh-space-1);
11617
+ --xh-_context-menu-item-py: var(--xh-list-option-py-sm);
11184
11618
  --xh-_context-menu-item-px: var(--xh-control-px-sm);
11185
11619
  --xh-_context-menu-item-gap: var(--xh-control-gap-sm);
11186
11620
  --xh-_context-menu-font-size: var(--xh-control-font-sm);
11187
11621
  }
11188
11622
 
11189
11623
  [data-scope='context-menu']:is([data-part='root'], [data-part='positioner'])[data-size='lg'] {
11190
- --xh-_context-menu-item-py: var(--xh-space-2);
11624
+ --xh-_context-menu-item-py: var(--xh-list-option-py-lg);
11191
11625
  --xh-_context-menu-item-px: var(--xh-control-px-lg);
11192
11626
  --xh-_context-menu-item-gap: var(--xh-control-gap-lg);
11193
11627
  --xh-_context-menu-font-size: var(--xh-control-font-lg);
@@ -11208,6 +11642,7 @@ input[data-scope='mention'][data-part='input'] {
11208
11642
  [data-scope='context-menu'][data-part='content'] {
11209
11643
  display: flex;
11210
11644
  flex-direction: column;
11645
+ gap: var(--xh-context-menu-content-gap, var(--xh-list-option-gap));
11211
11646
  min-inline-size: var(--xh-context-menu-min-w, var(--xh-overlay-menu-min-w));
11212
11647
  max-inline-size: var(--xh-context-menu-max-w, var(--xh-overlay-max-w));
11213
11648
  /* 两道上限取更小的那道:自己的高度上限,以及落定那一侧真正剩下的空间。
@@ -11257,6 +11692,7 @@ input[data-scope='mention'][data-part='input'] {
11257
11692
  [data-scope='context-menu'][data-part='group'] {
11258
11693
  display: flex;
11259
11694
  flex-direction: column;
11695
+ gap: var(--xh-context-menu-group-gap, var(--xh-list-option-gap));
11260
11696
  }
11261
11697
 
11262
11698
  [data-scope='context-menu'][data-part='group'][hidden] {
@@ -11370,7 +11806,7 @@ input[data-scope='mention'][data-part='input'] {
11370
11806
  align-items: center;
11371
11807
  justify-content: center;
11372
11808
  inline-size: var(--xh-context-menu-item-indicator-size, var(--xh-control-indicator-size));
11373
- color: var(--xh-context-menu-item-indicator-fg, var(--xh-fg-brand));
11809
+ color: var(--xh-context-menu-item-indicator-fg, var(--xh-_tone, var(--xh-fg-brand)));
11374
11810
  }
11375
11811
 
11376
11812
  [data-scope='context-menu'][data-part='item-indicator'][hidden] {
@@ -11383,7 +11819,7 @@ input[data-scope='mention'][data-part='input'] {
11383
11819
 
11384
11820
  [data-scope='context-menu'][data-part='separator'] {
11385
11821
  block-size: var(--xh-context-menu-separator-thickness, var(--xh-stroke-thin));
11386
- margin-block: var(--xh-context-menu-separator-my, var(--xh-space-1));
11822
+ margin-block: var(--xh-context-menu-separator-my, var(--xh-space-0_5));
11387
11823
  background: var(--xh-context-menu-separator-color, var(--xh-border-default));
11388
11824
  }
11389
11825
 
@@ -11459,8 +11895,8 @@ input[data-scope='mention'][data-part='input'] {
11459
11895
  --xh-_date-field-control-h: var(--xh-control-h-md);
11460
11896
  --xh-_date-field-control-px: var(--xh-control-px-md);
11461
11897
  --xh-_date-field-gap: var(--xh-control-gap-md);
11462
- --xh-_date-field-font-size: var(--xh-text-body-size);
11463
- --xh-_date-field-label-font-size: var(--xh-text-label-size);
11898
+ --xh-_date-field-font-size: var(--xh-control-font-md);
11899
+ --xh-_date-field-label-font-size: var(--xh-control-font-md);
11464
11900
  /* 形态档只换这三个私有槽:底色与两档描边 */
11465
11901
  --xh-_date-field-control-bg: var(--xh-bg-canvas);
11466
11902
  --xh-_date-field-control-border: var(--xh-border-control);
@@ -11738,6 +12174,9 @@ input[data-scope='mention'][data-part='input'] {
11738
12174
  引擎没算(尚未落位 / 无引擎 / 贴边归零)时不额外限高 */
11739
12175
  --xh-_date-picker-available-h: 100vh;
11740
12176
 
12177
+ /* 面板的自绘条浮在内容之上:轨道不上底色,实色轨道会在面板右缘糊出一条竖灰带 */
12178
+ --xh-scrollbar-track-bg: transparent;
12179
+
11741
12180
  position: fixed;
11742
12181
  z-index: var(--xh-date-picker-layer, var(--xh-layer-popover));
11743
12182
  /* 空壳不吃指针,交互只发生在 content 里 */
@@ -11756,8 +12195,8 @@ input[data-scope='mention'][data-part='input'] {
11756
12195
  --xh-_date-picker-control-h: var(--xh-control-h-md);
11757
12196
  --xh-_date-picker-control-px: var(--xh-control-px-md);
11758
12197
  --xh-_date-picker-gap: var(--xh-control-gap-md);
11759
- --xh-_date-picker-font-size: var(--xh-text-body-size);
11760
- --xh-_date-picker-label-font-size: var(--xh-text-label-size);
12198
+ --xh-_date-picker-font-size: var(--xh-control-font-md);
12199
+ --xh-_date-picker-label-font-size: var(--xh-control-font-md);
11761
12200
 
11762
12201
  /* 形态档只换这三个私有槽:底色与两档描边 */
11763
12202
  --xh-_date-picker-control-bg: var(--xh-bg-canvas);
@@ -12053,6 +12492,11 @@ input[data-scope='mention'][data-part='input'] {
12053
12492
  border-inline-start: var(--xh-stroke-thin) solid var(--xh-date-picker-panel-divider, var(--xh-border-subtle));
12054
12493
  }
12055
12494
 
12495
+ /* 快捷选项列与它旁边那张日历之间留出同样的空当,两道分隔线左右对称 */
12496
+ [data-scope='date-picker'][data-part='presets'] + [data-scope='date-picker'][data-part='calendar'] {
12497
+ padding-inline-start: var(--xh-date-picker-panel-gap, var(--xh-space-3));
12498
+ }
12499
+
12056
12500
  [data-scope='date-picker'][data-part='calendar'] {
12057
12501
  display: flex;
12058
12502
  flex-direction: column;
@@ -12069,13 +12513,15 @@ input[data-scope='mention'][data-part='input'] {
12069
12513
  [data-scope='date-picker'][data-part='presets'] {
12070
12514
  display: flex;
12071
12515
  flex: none;
12516
+ /* 这一列的高度由并排的日历给:不写就按内容收,右侧那道分隔线只画到最后一条选项 */
12517
+ align-self: stretch;
12072
12518
  flex-direction: column;
12073
- gap: var(--xh-date-picker-presets-gap, var(--xh-space-0_5));
12519
+ gap: var(--xh-date-picker-presets-gap, var(--xh-list-option-gap));
12074
12520
  /* 选项多起来时这一列自己滚,不把整张面板撑高 */
12075
- max-block-size: var(--xh-date-picker-presets-h, var(--xh-viewport-h-sm));
12076
- padding: var(--xh-space-1);
12521
+ max-block-size: var(--xh-date-picker-presets-h, var(--xh-viewport-h-lg));
12522
+ padding: var(--xh-date-picker-presets-padding, var(--xh-space-1));
12077
12523
  overflow-y: auto;
12078
- border-inline-end: var(--xh-stroke-thin) solid var(--xh-date-picker-content-border, var(--xh-border-default));
12524
+ border-inline-end: var(--xh-stroke-thin) solid var(--xh-date-picker-column-divider, var(--xh-border-subtle));
12079
12525
  }
12080
12526
 
12081
12527
  [data-scope='date-picker'][data-part='presets'][hidden] {
@@ -12083,9 +12529,9 @@ input[data-scope='mention'][data-part='input'] {
12083
12529
  }
12084
12530
 
12085
12531
  [data-scope='date-picker'][data-part='preset'] {
12086
- padding-block: var(--xh-space-1);
12087
- padding-inline: var(--xh-space-3);
12088
- border-radius: var(--xh-shape-control);
12532
+ padding-block: var(--xh-date-picker-preset-py, var(--xh-space-1));
12533
+ padding-inline: var(--xh-date-picker-preset-px, var(--xh-space-3));
12534
+ border-radius: var(--xh-date-picker-preset-radius, var(--xh-shape-control));
12089
12535
  font-size: var(--xh-text-secondary-size);
12090
12536
  line-height: var(--xh-leading-normal);
12091
12537
  white-space: nowrap;
@@ -12120,12 +12566,12 @@ input[data-scope='mention'][data-part='input'] {
12120
12566
  [data-scope='date-picker'][data-part='time-column'] {
12121
12567
  display: flex;
12122
12568
  flex-direction: column;
12123
- gap: var(--xh-date-picker-time-column-gap, var(--xh-space-0_5));
12569
+ gap: var(--xh-date-picker-time-column-gap, var(--xh-list-option-gap));
12124
12570
  /* 几列并排:定高而不是随内容收,否则时列与分列的可选值一多一少就错位 */
12125
12571
  block-size: var(--xh-date-picker-time-column-h, var(--xh-viewport-h-sm));
12126
- padding: var(--xh-space-1);
12572
+ padding: var(--xh-date-picker-time-column-padding, var(--xh-space-1));
12127
12573
  overflow-y: auto;
12128
- border-inline-start: var(--xh-stroke-thin) solid var(--xh-date-picker-content-border, var(--xh-border-default));
12574
+ border-inline-start: var(--xh-stroke-thin) solid var(--xh-date-picker-column-divider, var(--xh-border-subtle));
12129
12575
  }
12130
12576
 
12131
12577
  [data-scope='date-picker'][data-part='time-column'][hidden] {
@@ -12133,9 +12579,9 @@ input[data-scope='mention'][data-part='input'] {
12133
12579
  }
12134
12580
 
12135
12581
  [data-scope='date-picker'][data-part='time-item'] {
12136
- padding-block: var(--xh-space-1);
12137
- padding-inline: var(--xh-space-3);
12138
- border-radius: var(--xh-shape-control);
12582
+ padding-block: var(--xh-date-picker-time-item-py, var(--xh-space-1));
12583
+ padding-inline: var(--xh-date-picker-time-item-px, var(--xh-space-3));
12584
+ border-radius: var(--xh-date-picker-time-item-radius, var(--xh-shape-control));
12139
12585
  font-size: var(--xh-text-secondary-size);
12140
12586
  line-height: var(--xh-leading-normal);
12141
12587
  text-align: center;
@@ -12165,9 +12611,9 @@ input[data-scope='mention'][data-part='input'] {
12165
12611
  align-items: center;
12166
12612
  justify-content: center;
12167
12613
  block-size: var(--xh-control-h-sm);
12168
- padding-inline: var(--xh-control-px-sm);
12614
+ padding-inline: var(--xh-date-picker-confirm-trigger-px, var(--xh-control-px-sm));
12169
12615
  border: none;
12170
- border-radius: var(--xh-shape-control);
12616
+ border-radius: var(--xh-date-picker-confirm-trigger-radius, var(--xh-shape-control));
12171
12617
  background: var(--xh-date-picker-confirm-bg, var(--xh-_date-picker-accent));
12172
12618
  color: var(--xh-date-picker-confirm-fg, var(--xh-_date-picker-accent-fg));
12173
12619
  font-size: var(--xh-text-secondary-size);
@@ -12315,7 +12761,7 @@ input[data-scope='mention'][data-part='input'] {
12315
12761
  display: flex;
12316
12762
  align-items: center;
12317
12763
  justify-content: center;
12318
- padding: var(--xh-space-4);
12764
+ padding: var(--xh-dialog-positioner-padding, var(--xh-space-4));
12319
12765
  }
12320
12766
 
12321
12767
  [data-scope='dialog'][data-part='positioner'][data-position='top'] {
@@ -12446,6 +12892,12 @@ input[data-scope='mention'][data-part='input'] {
12446
12892
  mask: var(--xh-glyph-mark-close) center / contain no-repeat;
12447
12893
  }
12448
12894
 
12895
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
12896
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
12897
+ [data-scope='dialog'][data-part='positioner'][hidden] {
12898
+ display: none;
12899
+ }
12900
+
12449
12901
  /* styles/drawer.css */
12450
12902
  /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
12451
12903
  动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
@@ -12570,6 +13022,12 @@ input[data-scope='mention'][data-part='input'] {
12570
13022
  display: contents;
12571
13023
  }
12572
13024
 
13025
+ /* 浮层被搬到 portal 落点,继承不到 root 上的槽:这把尺在被搬走的那一侧再声明一次,
13026
+ 关闭钮与条目里作者塞的图标才和皮肤画的兜底字形一样大 */
13027
+ [data-scope='drawer'][data-part='content'] {
13028
+ --xh-icon-size: var(--xh-drawer-icon-size, var(--xh-glyph-size-text));
13029
+ }
13030
+
12573
13031
  /* 声明了 display 就盖掉了 UA 的 [hidden]{display:none},作者手写 hidden 时得还回去 */
12574
13032
  [data-scope='drawer'][data-part='root'][hidden] {
12575
13033
  display: none;
@@ -12630,11 +13088,14 @@ input[data-scope='mention'][data-part='input'] {
12630
13088
  background: var(--xh-drawer-backdrop-bg, var(--xh-bg-overlay));
12631
13089
  }
12632
13090
 
12633
- /* 挂在局部容器里:遮罩与定位层从视口坐标换成容器坐标,只罩住那个容器。
13091
+ /* 挂在局部容器里:遮罩、定位层与面板一起从视口坐标换成容器坐标,只罩住那个容器。
12634
13092
  作者要给那个容器加 position(relative 之类),否则 absolute 会往上找到别的定位祖先——
12635
- 这一条写进了示例与 props 说明 */
13093
+ 这一条写进了示例与 props 说明。
13094
+ content 必须一起换:它的贴边是 inset-block/inline 参照包含块算的,留在 fixed 上就会
13095
+ 照旧贴视口边,遮罩缩进容器、面板却跑到屏幕边上——与 contained 的承诺正好相反 */
12636
13096
  [data-scope='drawer'][data-part='backdrop'][data-contained],
12637
- [data-scope='drawer'][data-part='positioner'][data-contained] {
13097
+ [data-scope='drawer'][data-part='positioner'][data-contained],
13098
+ [data-scope='drawer'][data-part='content'][data-contained] {
12638
13099
  position: absolute;
12639
13100
  }
12640
13101
 
@@ -12660,8 +13121,9 @@ input[data-scope='mention'][data-part='input'] {
12660
13121
  /* 贴边写在 content 自己身上,而不是交给 positioner:
12661
13122
  positioner 在抽屉里不是必需部件,最小合规结构只有 root + content,
12662
13123
  贴边若挂在 positioner 上,那种结构下面板会直接塌回文档流。
12663
- content 是 fixed,包住它的 positioner 没有 transform / filter,
12664
- 不构成固定定位的包含块,两种结构下参照的都是视口,位置一致。 */
13124
+ 非 contained 时 content 是 fixed,包住它的 positioner 没有 transform / filter,
13125
+ 不构成固定定位的包含块,两种结构下参照的都是视口,位置一致;
13126
+ contained 时上面那条把它一并换成 absolute,参照的就是作者那个容器。 */
12665
13127
  [data-scope='drawer'][data-part='content'] {
12666
13128
  /* 位移方向的私有槽位:默认按 LTR,RTL 在下面整体翻符号 */
12667
13129
  --xh-_drawer-shift-inline: 100%;
@@ -13228,6 +13690,13 @@ input[data-scope='mention'][data-part='input'] {
13228
13690
  line-height: var(--xh-leading-normal);
13229
13691
  }
13230
13692
 
13693
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
13694
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
13695
+ [data-scope='field'][data-part='root'][hidden],
13696
+ [data-scope='form'][data-part='root'][hidden] {
13697
+ display: none;
13698
+ }
13699
+
13231
13700
  /* styles/file-upload.css */
13232
13701
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
13233
13702
  [data-scope='file-upload'] {
@@ -13423,7 +13892,7 @@ input[data-scope='mention'][data-part='input'] {
13423
13892
  只挑图标色不换底色:底色一换,一列文件里图片那几行会跳出来抢戏。
13424
13893
  取语义 token 而不是品牌色阶原值,深色主题才跟着走 */
13425
13894
  [data-scope='file-upload'][data-part='item-preview'][data-file-type^='image/'] {
13426
- color: var(--xh-file-upload-preview-fg-image, var(--xh-bg-brand));
13895
+ color: var(--xh-file-upload-preview-fg-image, var(--xh-fg-brand));
13427
13896
  }
13428
13897
 
13429
13898
  /* 塞进来的真缩略图撑满这个方框,长宽比不对就裁掉,不许把格子顶变形 */
@@ -13836,6 +14305,9 @@ input[data-scope='mention'][data-part='input'] {
13836
14305
  引擎没算(尚未落位 / 无引擎 / 贴边归零)时不额外限高 */
13837
14306
  --xh-_hover-card-available-h: 100vh;
13838
14307
 
14308
+ /* 卡片内容的自绘条浮在内容之上:轨道不上底色,实色轨道会在卡片右缘糊一条竖灰带 */
14309
+ --xh-scrollbar-track-bg: transparent;
14310
+
13839
14311
  position: fixed;
13840
14312
  z-index: var(--xh-hover-card-layer, var(--xh-layer-popover));
13841
14313
  /* 空壳不吃指针:trigger 与 content 之间那段间隙要能点得穿,
@@ -14088,6 +14560,10 @@ input[data-scope='mention'][data-part='input'] {
14088
14560
  }
14089
14561
 
14090
14562
  [data-scope='image-viewer'][data-part='content'] {
14563
+ /* 组件内那几档层号只在自己人之间排序:建一个层叠上下文把它们关起来,
14564
+ 既不让页面上的层号插进来,也不让它们漏出去压住别人 */
14565
+ isolation: isolate;
14566
+
14091
14567
  /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
14092
14568
  --xh-icon-size: var(--xh-image-viewer-icon-size, var(--xh-glyph-size-text));
14093
14569
 
@@ -14148,7 +14624,7 @@ input[data-scope='mention'][data-part='input'] {
14148
14624
  background: var(--xh-image-viewer-chrome-bg, color-mix(in oklab, var(--xh-color-neutral-950) 55%, transparent));
14149
14625
  color: inherit;
14150
14626
  border: none;
14151
- border-radius: var(--xh-shape-pill);
14627
+ border-radius: var(--xh-image-viewer-overlay-radius, var(--xh-shape-pill));
14152
14628
  }
14153
14629
 
14154
14630
  [data-scope='image-viewer'][data-part='toolbar'] {
@@ -14157,8 +14633,8 @@ input[data-scope='mention'][data-part='input'] {
14157
14633
  translate: -50% 0;
14158
14634
  display: flex;
14159
14635
  align-items: center;
14160
- gap: var(--xh-space-1);
14161
- padding: var(--xh-space-1_5) var(--xh-space-3);
14636
+ gap: var(--xh-image-viewer-toolbar-gap, var(--xh-space-1));
14637
+ padding: var(--xh-image-viewer-toolbar-padding, var(--xh-space-1_5) var(--xh-space-3));
14162
14638
  }
14163
14639
 
14164
14640
  /* 工具条里的按钮:底色交给工具条,本体只管命中区 */
@@ -14171,7 +14647,7 @@ input[data-scope='mention'][data-part='input'] {
14171
14647
  block-size: var(--xh-control-action-size);
14172
14648
  background: none;
14173
14649
  border: none;
14174
- border-radius: var(--xh-shape-control);
14650
+ border-radius: var(--xh-image-viewer-toolbar-radius, var(--xh-shape-control));
14175
14651
  color: inherit;
14176
14652
  font-size: var(--xh-glyph-size-sm);
14177
14653
  cursor: pointer;
@@ -14181,7 +14657,7 @@ input[data-scope='mention'][data-part='input'] {
14181
14657
  inset-block-start: var(--xh-space-6);
14182
14658
  inset-inline-start: 50%;
14183
14659
  translate: -50% 0;
14184
- padding: var(--xh-space-1) var(--xh-space-3);
14660
+ padding: var(--xh-image-viewer-counter-padding, var(--xh-space-1) var(--xh-space-3));
14185
14661
  font-size: var(--xh-text-secondary-size);
14186
14662
  }
14187
14663
 
@@ -14353,6 +14829,15 @@ input[data-scope='mention'][data-part='input'] {
14353
14829
  mask: var(--xh-glyph-mark-close) center / contain no-repeat;
14354
14830
  }
14355
14831
 
14832
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
14833
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
14834
+ [data-scope='image-viewer'][data-part='positioner'][hidden],
14835
+ [data-scope='image-viewer'][data-part='viewport'][hidden],
14836
+ [data-scope='image-viewer'][data-part='toolbar'][hidden],
14837
+ [data-scope='image-viewer'][data-part='next-trigger'][hidden] {
14838
+ display: none;
14839
+ }
14840
+
14356
14841
  /* styles/listbox.css */
14357
14842
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
14358
14843
  [data-scope='listbox'] {
@@ -14389,6 +14874,7 @@ input[data-scope='mention'][data-part='input'] {
14389
14874
  [data-scope='listbox'][data-part='content'] {
14390
14875
  display: flex;
14391
14876
  flex-direction: column;
14877
+ gap: var(--xh-listbox-content-gap, var(--xh-list-option-gap));
14392
14878
  max-block-size: var(--xh-listbox-content-max-h, var(--xh-viewport-h-md));
14393
14879
  padding-block: var(--xh-listbox-content-py, var(--xh-space-1));
14394
14880
  padding-inline: var(--xh-listbox-content-px, var(--xh-space-1));
@@ -14421,6 +14907,7 @@ input[data-scope='mention'][data-part='input'] {
14421
14907
  [data-scope='listbox'][data-part='item-group'] {
14422
14908
  display: flex;
14423
14909
  flex-direction: column;
14910
+ gap: var(--xh-listbox-item-group-gap, var(--xh-list-option-gap));
14424
14911
  }
14425
14912
 
14426
14913
  [data-scope='listbox'][data-part='item-group'][hidden] {
@@ -14429,7 +14916,7 @@ input[data-scope='mention'][data-part='input'] {
14429
14916
 
14430
14917
  /* 组间留白只加在后继分组上:首组顶上已经有 content 的内边距,再加一层会显得头重 */
14431
14918
  [data-scope='listbox'][data-part='item-group'] + [data-scope='listbox'][data-part='item-group'] {
14432
- margin-block-start: var(--xh-listbox-group-gap, var(--xh-space-2));
14919
+ margin-block-start: var(--xh-listbox-group-gap, var(--xh-space-1_5));
14433
14920
  }
14434
14921
 
14435
14922
  /* 分组标题不是选项、进不了导航,画成小号次要文字,
@@ -14523,7 +15010,7 @@ input[data-scope='mention'][data-part='input'] {
14523
15010
  align-items: center;
14524
15011
  justify-content: center;
14525
15012
  inline-size: var(--xh-listbox-item-indicator-size, var(--xh-control-indicator-size));
14526
- color: var(--xh-listbox-item-indicator-fg, var(--xh-bg-brand));
15013
+ color: var(--xh-listbox-item-indicator-fg, var(--xh-fg-brand));
14527
15014
  visibility: hidden;
14528
15015
  }
14529
15016
 
@@ -14584,8 +15071,9 @@ input[data-scope='mention'][data-part='input'] {
14584
15071
  display: none;
14585
15072
  }
14586
15073
 
14587
- /* 冲到 100 之后进入淡出:机器会在淡出窗口走完之前一直停在 finishing
14588
- 这段过渡才有时间跑完;窗口与时长两处默认值都是 200ms,改一处记得对齐另一处 */
15074
+ /* 冲到 100 之后进入淡出:机器会在淡出窗口走完之前一直停在 finishing,这段过渡才有时间跑完。
15075
+ 窗口(machine 的 LOADING_BAR_FADE_DURATION,200ms)比过渡本身(motion-duration-exit,120ms)
15076
+ 宽出一截是有意的余量;两者不是同一个数,改窗口时只要保证它仍不短于过渡 */
14589
15077
  [data-scope='loading-bar'][data-part='root'][data-state='finishing'] {
14590
15078
  opacity: 0;
14591
15079
  }
@@ -14603,8 +15091,8 @@ input[data-scope='mention'][data-part='input'] {
14603
15091
  * 进度段。宽度那条轴(inline-size)由连接层写进内联样式,这里绝不重复写。
14604
15092
  * 背景色同理:给了 color 就走内联,盖过下面这条。
14605
15093
  *
14606
- * 语气取柔和档 --xh-_tone-soft(500)而不是 --xh-_tone(600):600 是给实心底与
14607
- * 文字用的强调档,压在这么一条细带上偏重。槽位由 root 上的 data-tone 声明,继承下来。
15094
+ * 语气取装饰档 --xh-_tone-soft:那一档压在画布上够 3:1,细带才看得出来。
15095
+ * 槽位由 root 上的 data-tone 声明,继承下来。
14608
15096
  * 没写 data-tone 时该槽没被声明,退回原来的品牌色。
14609
15097
  */
14610
15098
  [data-scope='loading-bar'][data-part='range'] {
@@ -14665,6 +15153,9 @@ input[data-scope='mention'][data-part='input'] {
14665
15153
  引擎没算(尚未落位 / 无引擎)时不额外限高 */
14666
15154
  --xh-_menu-available-h: 100vh;
14667
15155
 
15156
+ /* 条目列表的自绘条浮在内容之上:轨道不上底色,实色轨道会在菜单右缘糊一条竖灰带 */
15157
+ --xh-scrollbar-track-bg: transparent;
15158
+
14668
15159
  position: fixed;
14669
15160
  z-index: var(--xh-menu-layer, var(--xh-layer-popover));
14670
15161
  /* 空壳不吃指针,交互只发生在 content 上 */
@@ -14695,10 +15186,10 @@ input[data-scope='mention'][data-part='input'] {
14695
15186
 
14696
15187
  /* 尺寸档只换这四个私有槽,条目从 content 继承它们,换档不必给每个部件各写一条选择器。
14697
15188
  菜单没有 root 部件(浮层树的最外层就是 content),三轴属性都落在这里 */
14698
- --xh-_menu-item-py: var(--xh-space-1_5);
15189
+ --xh-_menu-item-py: var(--xh-list-option-py-md);
14699
15190
  --xh-_menu-item-px: var(--xh-control-px-md);
14700
15191
  --xh-_menu-item-gap: var(--xh-control-gap-md);
14701
- --xh-_menu-font-size: var(--xh-text-body-size);
15192
+ --xh-_menu-font-size: var(--xh-control-font-md);
14702
15193
 
14703
15194
  /* 打开子菜单的触发条目走品牌淡底强档,随语气换色相;没写 data-tone 时退回品牌淡底。
14704
15195
  悬停与键盘焦点恒中性灰轻档、不接语气槽——两档同色相的话打开路径就认不出来了 */
@@ -14706,6 +15197,7 @@ input[data-scope='mention'][data-part='input'] {
14706
15197
 
14707
15198
  display: flex;
14708
15199
  flex-direction: column;
15200
+ gap: var(--xh-menu-content-gap, var(--xh-list-option-gap));
14709
15201
  min-inline-size: var(--xh-menu-min-w, var(--xh-overlay-menu-min-w));
14710
15202
  max-inline-size: var(--xh-menu-max-w, var(--xh-overlay-max-w));
14711
15203
  /* 两道上限取更小的那道:自己的高度上限,以及落定那一侧真正剩下的空间。
@@ -14748,14 +15240,14 @@ input[data-scope='mention'][data-part='input'] {
14748
15240
  /* 缺省档写在 content 的基础规则里。条目高度由 padding 撑出来:
14749
15241
  纵向走 space 档、行内内缩走 control-px 档(随密度轴),换档各挪一级 */
14750
15242
  [data-scope='menu'][data-part='content'][data-size='sm'] {
14751
- --xh-_menu-item-py: var(--xh-space-1);
15243
+ --xh-_menu-item-py: var(--xh-list-option-py-sm);
14752
15244
  --xh-_menu-item-px: var(--xh-control-px-sm);
14753
15245
  --xh-_menu-item-gap: var(--xh-control-gap-sm);
14754
15246
  --xh-_menu-font-size: var(--xh-control-font-sm);
14755
15247
  }
14756
15248
 
14757
15249
  [data-scope='menu'][data-part='content'][data-size='lg'] {
14758
- --xh-_menu-item-py: var(--xh-space-2);
15250
+ --xh-_menu-item-py: var(--xh-list-option-py-lg);
14759
15251
  --xh-_menu-item-px: var(--xh-control-px-lg);
14760
15252
  --xh-_menu-item-gap: var(--xh-control-gap-lg);
14761
15253
  --xh-_menu-font-size: var(--xh-control-font-lg);
@@ -14828,6 +15320,7 @@ input[data-scope='mention'][data-part='input'] {
14828
15320
  [data-scope='menu'][data-part='group'] {
14829
15321
  display: flex;
14830
15322
  flex-direction: column;
15323
+ gap: var(--xh-menu-group-gap, var(--xh-list-option-gap));
14831
15324
  }
14832
15325
 
14833
15326
  [data-scope='menu'][data-part='group'][hidden] {
@@ -14853,7 +15346,7 @@ input[data-scope='mention'][data-part='input'] {
14853
15346
 
14854
15347
  [data-scope='menu'][data-part='separator'] {
14855
15348
  block-size: var(--xh-menu-separator-thickness, var(--xh-stroke-thin));
14856
- margin-block: var(--xh-menu-separator-my, var(--xh-space-1));
15349
+ margin-block: var(--xh-menu-separator-my, var(--xh-space-0_5));
14857
15350
  background: var(--xh-menu-separator-color, var(--xh-border-default));
14858
15351
  }
14859
15352
 
@@ -14870,6 +15363,12 @@ input[data-scope='mention'][data-part='input'] {
14870
15363
  border: var(--xh-stroke-thin) solid var(--xh-menu-border, var(--xh-border-default));
14871
15364
  }
14872
15365
 
15366
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
15367
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
15368
+ [data-scope='menu'][data-part='item'][hidden] {
15369
+ display: none;
15370
+ }
15371
+
14873
15372
  /* styles/menubar.css */
14874
15373
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
14875
15374
  [data-scope='menubar'] {
@@ -14891,6 +15390,12 @@ input[data-scope='mention'][data-part='input'] {
14891
15390
  color: var(--xh-menubar-root-fg, var(--xh-fg-default));
14892
15391
  }
14893
15392
 
15393
+ /* 浮层被搬到 portal 落点,继承不到 root 上的槽:这把尺在被搬走的那一侧再声明一次,
15394
+ 关闭钮与条目里作者塞的图标才和皮肤画的兜底字形一样大 */
15395
+ [data-scope='menubar'][data-part='content'] {
15396
+ --xh-icon-size: var(--xh-menubar-icon-size, var(--xh-glyph-size-text));
15397
+ }
15398
+
14894
15399
  [data-scope='menubar'][data-part='root'][hidden] {
14895
15400
  display: none;
14896
15401
  }
@@ -14983,10 +15488,10 @@ input[data-scope='mention'][data-part='input'] {
14983
15488
  [data-scope='menubar']:is([data-part='root'], [data-part='positioner']) {
14984
15489
  --xh-_menubar-trigger-py: var(--xh-space-1);
14985
15490
  --xh-_menubar-trigger-px: var(--xh-control-px-md);
14986
- --xh-_menubar-item-py: var(--xh-space-1_5);
15491
+ --xh-_menubar-item-py: var(--xh-list-option-py-md);
14987
15492
  --xh-_menubar-item-px: var(--xh-control-px-md);
14988
15493
  --xh-_menubar-item-gap: var(--xh-control-gap-md);
14989
- --xh-_menubar-font-size: var(--xh-text-body-size);
15494
+ --xh-_menubar-font-size: var(--xh-control-font-md);
14990
15495
 
14991
15496
  /* 展开着的那张菜单的 trigger 走品牌淡底强档,随语气换色相;没写 data-tone 时退回品牌淡底。
14992
15497
  悬停与键盘焦点恒中性灰轻档、不接语气槽——两档同色相的话哪张开着就认不出来了。
@@ -15000,7 +15505,7 @@ input[data-scope='mention'][data-part='input'] {
15000
15505
  [data-scope='menubar'][data-size='sm']:is([data-part='root'], [data-part='positioner']) {
15001
15506
  --xh-_menubar-trigger-py: var(--xh-space-0_5);
15002
15507
  --xh-_menubar-trigger-px: var(--xh-control-px-sm);
15003
- --xh-_menubar-item-py: var(--xh-space-1);
15508
+ --xh-_menubar-item-py: var(--xh-list-option-py-sm);
15004
15509
  --xh-_menubar-item-px: var(--xh-control-px-sm);
15005
15510
  --xh-_menubar-item-gap: var(--xh-control-gap-sm);
15006
15511
  --xh-_menubar-font-size: var(--xh-control-font-sm);
@@ -15009,7 +15514,7 @@ input[data-scope='mention'][data-part='input'] {
15009
15514
  [data-scope='menubar'][data-size='lg']:is([data-part='root'], [data-part='positioner']) {
15010
15515
  --xh-_menubar-trigger-py: var(--xh-space-2);
15011
15516
  --xh-_menubar-trigger-px: var(--xh-control-px-lg);
15012
- --xh-_menubar-item-py: var(--xh-space-2);
15517
+ --xh-_menubar-item-py: var(--xh-list-option-py-lg);
15013
15518
  --xh-_menubar-item-px: var(--xh-control-px-lg);
15014
15519
  --xh-_menubar-item-gap: var(--xh-control-gap-lg);
15015
15520
  --xh-_menubar-font-size: var(--xh-control-font-lg);
@@ -15018,6 +15523,7 @@ input[data-scope='mention'][data-part='input'] {
15018
15523
  [data-scope='menubar'][data-part='content'] {
15019
15524
  display: flex;
15020
15525
  flex-direction: column;
15526
+ gap: var(--xh-menubar-content-gap, var(--xh-list-option-gap));
15021
15527
  min-inline-size: var(--xh-menubar-min-w, var(--xh-overlay-menu-min-w));
15022
15528
  max-inline-size: var(--xh-menubar-max-w, var(--xh-overlay-max-w));
15023
15529
  /* 两道上限取更小的那道:自己的高度上限,以及落定那一侧真正剩下的空间。
@@ -15067,6 +15573,7 @@ input[data-scope='mention'][data-part='input'] {
15067
15573
  [data-scope='menubar'][data-part='group'] {
15068
15574
  display: flex;
15069
15575
  flex-direction: column;
15576
+ gap: var(--xh-menubar-group-gap, var(--xh-list-option-gap));
15070
15577
  }
15071
15578
 
15072
15579
  [data-scope='menubar'][data-part='group'][hidden] {
@@ -15178,7 +15685,7 @@ input[data-scope='mention'][data-part='input'] {
15178
15685
  align-items: center;
15179
15686
  justify-content: center;
15180
15687
  inline-size: var(--xh-menubar-item-indicator-size, var(--xh-control-indicator-size));
15181
- color: var(--xh-menubar-item-indicator-fg, var(--xh-fg-brand));
15688
+ color: var(--xh-menubar-item-indicator-fg, var(--xh-_tone, var(--xh-fg-brand)));
15182
15689
  }
15183
15690
 
15184
15691
  [data-scope='menubar'][data-part='item-indicator'][hidden] {
@@ -15193,7 +15700,7 @@ input[data-scope='mention'][data-part='input'] {
15193
15700
  不给 display,因此 UA 的 [hidden]{display:none} 自己就压得住 */
15194
15701
  [data-scope='menubar'][data-part='separator'] {
15195
15702
  block-size: var(--xh-menubar-separator-thickness, var(--xh-stroke-thin));
15196
- margin-block: var(--xh-menubar-separator-my, var(--xh-space-1));
15703
+ margin-block: var(--xh-menubar-separator-my, var(--xh-space-0_5));
15197
15704
  background: var(--xh-menubar-separator-color, var(--xh-border-default));
15198
15705
  }
15199
15706
 
@@ -15271,13 +15778,13 @@ input[data-scope='mention'][data-part='input'] {
15271
15778
  /* 尺寸档只换这五个私有槽,trigger 与面板里的链接都从 root 继承它们,
15272
15779
  换档不必给每个部件各写一条选择器。面板与共享外壳都是 root 的后代,一并继承。
15273
15780
  trigger 写的是 font: inherit,字号跟着 root 这一档走,不另立槽 */
15274
- --xh-_navigation-menu-font-size: var(--xh-text-label-size);
15781
+ --xh-_navigation-menu-font-size: var(--xh-control-font-md);
15275
15782
  --xh-_navigation-menu-trigger-h: var(--xh-control-h-md);
15276
15783
  --xh-_navigation-menu-trigger-px: var(--xh-control-px-md);
15277
15784
  --xh-_navigation-menu-trigger-gap: var(--xh-control-gap-md);
15278
15785
  --xh-_navigation-menu-link-py: var(--xh-space-1_5);
15279
15786
  --xh-_navigation-menu-link-px: var(--xh-control-px-md);
15280
- --xh-_navigation-menu-link-font-size: var(--xh-text-body-size);
15787
+ --xh-_navigation-menu-link-font-size: var(--xh-control-font-md);
15281
15788
 
15282
15789
  /* 悬停与键盘锚点恒中性灰轻档、不接语气槽——两档同色相的话打开路径就认不出来了 */
15283
15790
  --xh-_navigation-menu-highlight-bg: var(--xh-bg-subtle);
@@ -15532,6 +16039,381 @@ input[data-scope='mention'][data-part='input'] {
15532
16039
  inset-inline-start: calc(100% + var(--xh-navigation-menu-content-offset, var(--xh-space-1)));
15533
16040
  }
15534
16041
 
16042
+ /* styles/notification.css */
16043
+ /*
16044
+ * 九个位共用同一条进出场,位移不跟着落位走:要按位置分方向,就得从 group 的
16045
+ * data-placement 反向选到卡片上,落位一改名整条动效静默失效。
16046
+ * 竖向一小段位移在九个位上都说得通。
16047
+ */
16048
+ @keyframes xh-notification-in {
16049
+ from {
16050
+ opacity: 0;
16051
+ translate: 0 var(--xh-motion-distance-md);
16052
+ scale: var(--xh-motion-scale-enter);
16053
+ }
16054
+
16055
+ to {
16056
+ opacity: 1;
16057
+ translate: 0 0;
16058
+ scale: 1;
16059
+ }
16060
+ }
16061
+
16062
+ /* loading 那枚字形自己转。逐皮肤自带一份:跨皮肤共用动画名,
16063
+ 引用方那份皮肤不在场时动画就静默不跑 */
16064
+ @keyframes xh-notification-spin {
16065
+ to {
16066
+ rotate: 360deg;
16067
+ }
16068
+ }
16069
+
16070
+ @keyframes xh-notification-out {
16071
+ from {
16072
+ opacity: 1;
16073
+ translate: 0 0;
16074
+ scale: 1;
16075
+ }
16076
+
16077
+ to {
16078
+ opacity: 0;
16079
+ translate: 0 var(--xh-motion-distance-md);
16080
+ scale: var(--xh-motion-scale-enter);
16081
+ }
16082
+ }
16083
+
16084
+ /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
16085
+ [data-scope='notification'] {
16086
+ --xh-notification-skin: 1;
16087
+ }
16088
+
16089
+ /* 作用域包装不占布局:通知落在哪儿由九个 group 各自的 fixed 说了算,
16090
+ root 只是把队列的作用域圈起来(地标挂在那一摞上,不在这里)。
16091
+ 它若留下一个块盒,写在页面中段的用法(按钮和队列摆在一起)就会凭空多出一行空白。
16092
+ 另一件必须提防的事:fixed 认的是视口,祖先上一旦出现
16093
+ transform / filter / backdrop-filter / contain,包含块就被抢走,整摞通知立刻贴错位置——
16094
+ 所以这里连 position 都不碰,也别往覆盖钩子里加这几个属性。 */
16095
+ [data-scope='notification'][data-part='root'] {
16096
+ display: contents;
16097
+ }
16098
+
16099
+ /* 只要声明过 display,就盖掉了 UA 的 [hidden]{display:none},收起态得自己补回来 */
16100
+ [data-scope='notification'][data-part='root'][hidden] {
16101
+ display: none;
16102
+ }
16103
+
16104
+ /*
16105
+ * 一摞 = 一整面视口大小的定位面:贴边靠 padding,九个位靠 justify/align 表达。
16106
+ * 不用四角 inset 逐个摆,是因为 column flex 的 align-items 走的是行内轴,
16107
+ * RTL 下 start/end 自动跟着翻;写死 inset-inline-start 的话居中那三个位
16108
+ * 还得再配一次 translate,方向一变就错。
16109
+ * 条目次序按队列原样(旧的在前):贴底那三个位于是新的离屏幕边最近,符合直觉。
16110
+ */
16111
+ [data-scope='notification'][data-part='group'] {
16112
+ position: fixed;
16113
+ inset-block: 0;
16114
+ inset-inline: 0;
16115
+ z-index: var(--xh-notification-layer, var(--xh-layer-toast));
16116
+ display: flex;
16117
+ flex-direction: column;
16118
+ /* 基线按默认落位 bottom-end 写,下面只覆盖跟它不同的那几个位 */
16119
+ justify-content: flex-end;
16120
+ align-items: center;
16121
+ padding-block: var(--xh-notification-inset, var(--xh-space-6));
16122
+ padding-inline: var(--xh-notification-inset, var(--xh-space-6));
16123
+ /* 摞内间距由连接层写进内联 style(两个适配器共用同一份),这里绝不重复写:
16124
+ 写了也会被内联盖掉,只会让人误以为间距归样式层管 */
16125
+ /* 整面铺开就等于罩住了整块视口。面本身不吃指针,只有卡片吃(见下),
16126
+ 否则九个位一叠,底下的页面就再也点不动了 */
16127
+ pointer-events: none;
16128
+ }
16129
+
16130
+ [data-scope='notification'][data-part='group'][hidden] {
16131
+ display: none;
16132
+ }
16133
+
16134
+ /* 空摞直接撤掉:九个位同时挂九张全屏定位面,白白多九个合成层 */
16135
+ [data-scope='notification'][data-part='group'][data-empty] {
16136
+ display: none;
16137
+ }
16138
+
16139
+ /* 块轴落位:^= 一次吃掉某一行的三个位(top / top-start / top-end) */
16140
+ [data-scope='notification'][data-part='group'][data-placement^='top'] {
16141
+ justify-content: flex-start;
16142
+ }
16143
+
16144
+ [data-scope='notification'][data-part='group'][data-placement^='middle'] {
16145
+ justify-content: center;
16146
+ }
16147
+
16148
+ /* 行内轴落位:不带后缀的 top / middle / bottom 用基线的居中 */
16149
+ [data-scope='notification'][data-part='group'][data-placement$='-start'] {
16150
+ align-items: flex-start;
16151
+ }
16152
+
16153
+ [data-scope='notification'][data-part='group'][data-placement$='-end'] {
16154
+ align-items: flex-end;
16155
+ }
16156
+
16157
+ /*
16158
+ * 一张通知卡:左列一枚类型字形,右列「标题 + 说明 + 操作」竖着排,叉钉在右上角。
16159
+ * 用网格而不是竖排 flex:叉要脱离文档流钉到角上,正文要在字形右边成一列——
16160
+ * 竖排 flex 里这两件事都做不到(叉会变成第三行)。
16161
+ * 底与描边一律中性,语气只由左列那枚字形承载:整片兑色是轻提示那条的做法,
16162
+ * 一张有标题有正文的卡片全片染色会把两层文字都压在同一片语气色上。
16163
+ */
16164
+ [data-scope='notification'][data-part='item'] {
16165
+ /* 叉与操作钮的兜底字形按控件指示符那一档走;左列那枚类型字形另有自己的尺寸 */
16166
+ --xh-icon-size: var(--xh-notification-icon-size, var(--xh-control-indicator-size));
16167
+
16168
+ position: relative;
16169
+ display: grid;
16170
+ /* 左列宽度由字形自己决定,作者不放指示符时它就是 0,正文自然贴到左内衬 */
16171
+ grid-template-columns: auto 1fr;
16172
+ align-items: start;
16173
+ column-gap: var(--xh-notification-gap, var(--xh-space-3));
16174
+ row-gap: var(--xh-notification-row-gap, var(--xh-space-2));
16175
+ inline-size: var(--xh-notification-w, var(--xh-overlay-max-w-lg));
16176
+ /* 摞是整面视口宽的定位面且带内边距,取 100% 就等于自动让出两侧留白,
16177
+ 窄屏上不必再算一遍 viewport 减法 */
16178
+ max-inline-size: 100%;
16179
+ padding-block: var(--xh-notification-py, var(--xh-space-4));
16180
+ padding-inline: var(--xh-notification-px, var(--xh-space-4));
16181
+ border: var(--xh-stroke-thin) solid var(--xh-notification-border, var(--xh-border-default));
16182
+ border-radius: var(--xh-notification-radius, var(--xh-shape-surface));
16183
+ background: var(--xh-notification-bg, var(--xh-bg-surface-raised));
16184
+ color: var(--xh-notification-fg, var(--xh-fg-default));
16185
+ box-shadow: var(--xh-notification-shadow, var(--xh-elevation-sheet));
16186
+ font-size: var(--xh-notification-font-size, var(--xh-text-body-size));
16187
+ line-height: var(--xh-notification-leading, var(--xh-text-body-leading));
16188
+ /* 摞的定位面整面铺开且不吃指针,卡片必须自己吃回来:
16189
+ 悬停按住计时、按钮可点、焦点进出,全指着这一条 */
16190
+ pointer-events: auto;
16191
+ }
16192
+
16193
+ /* 除指示符外一律落第二列:作者往卡片里塞的任何东西都跟着正文走 */
16194
+ [data-scope='notification'][data-part='item'] > *:not([data-part='item-indicator']) {
16195
+ grid-column: 2;
16196
+ }
16197
+
16198
+ /* 退场窗口走完连接层给的是 hidden 属性,而上面声明了 display——
16199
+ 漏掉这条,已经"卸载"的通知会一直杵在屏幕上,且再也没人来收 */
16200
+ [data-scope='notification'][data-part='item'][hidden] {
16201
+ display: none;
16202
+ }
16203
+
16204
+ /* 生命周期只有三段,unmounted 那段由上面的 [hidden] 收走,这里只管前两段 */
16205
+ [data-scope='notification'][data-part='item'][data-state='visible'] {
16206
+ animation: xh-notification-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
16207
+ }
16208
+
16209
+ /* forwards 不能省:退场窗口(removeDelay 默认 200ms)比退场动画长,
16210
+ 不定住末帧的话动画跑完会弹回全不透明,卡片在被收起前先闪一下 */
16211
+ [data-scope='notification'][data-part='item'][data-state='dismissing'] {
16212
+ animation: xh-notification-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
16213
+ }
16214
+
16215
+ /* 独占第一列第一行,并与标题首行顶对齐:盒高取一行标题的行高,
16216
+ 字形在盒里居中,标题字号改了也不会错位 */
16217
+ [data-scope='notification'][data-part='item-indicator'] {
16218
+ --xh-icon-size: var(--xh-notification-indicator-size, var(--xh-glyph-size-md));
16219
+
16220
+ grid-column: 1;
16221
+ grid-row: 1;
16222
+ display: inline-flex;
16223
+ align-items: center;
16224
+ justify-content: center;
16225
+ block-size: calc(var(--xh-notification-title-font-size, var(--xh-text-label-size)) * var(--xh-leading-tight));
16226
+ inline-size: var(--xh-notification-indicator-size, var(--xh-glyph-size-md));
16227
+ color: var(--xh-notification-indicator-fg, var(--xh-_tone-fg));
16228
+ }
16229
+
16230
+ [data-scope='notification'][data-part='item-indicator'][hidden] {
16231
+ display: none;
16232
+ }
16233
+
16234
+ /* 作者没往指示符里写内容就由皮肤画兜底字形,按语气各画一枚;
16235
+ 塞了自己的图形这几条即不命中 */
16236
+ [data-scope='notification'][data-part='item-indicator']:empty::before {
16237
+ content: '';
16238
+ display: inline-block;
16239
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
16240
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
16241
+ vertical-align: var(--xh-glyph-baseline-shift);
16242
+ background-color: currentColor;
16243
+ -webkit-mask: var(--xh-glyph-mark-info) center / contain no-repeat;
16244
+ mask: var(--xh-glyph-mark-info) center / contain no-repeat;
16245
+ }
16246
+
16247
+ [data-scope='notification'][data-part='item'][data-type='success'] [data-part='item-indicator']:empty::before {
16248
+ -webkit-mask-image: var(--xh-glyph-mark-check);
16249
+ mask-image: var(--xh-glyph-mark-check);
16250
+ }
16251
+
16252
+ [data-scope='notification'][data-part='item'][data-type='warning'] [data-part='item-indicator']:empty::before {
16253
+ -webkit-mask-image: var(--xh-glyph-mark-warning);
16254
+ mask-image: var(--xh-glyph-mark-warning);
16255
+ }
16256
+
16257
+ [data-scope='notification'][data-part='item'][data-type='error'] [data-part='item-indicator']:empty::before {
16258
+ -webkit-mask-image: var(--xh-glyph-mark-close);
16259
+ mask-image: var(--xh-glyph-mark-close);
16260
+ }
16261
+
16262
+ /* loading 说的是「事情还没完」,不是好消息也不是坏消息:走中性前景档而不是语气色 */
16263
+ [data-scope='notification'][data-part='item'][data-type='loading'] [data-part='item-indicator'] {
16264
+ color: var(--xh-notification-indicator-fg, var(--xh-fg-muted));
16265
+ }
16266
+
16267
+ [data-scope='notification'][data-part='item'][data-type='loading'] [data-part='item-indicator']:empty::before {
16268
+ -webkit-mask-image: var(--xh-glyph-mark-rotate-right);
16269
+ mask-image: var(--xh-glyph-mark-rotate-right);
16270
+ animation: xh-notification-spin var(--xh-spin-duration) linear infinite;
16271
+ }
16272
+
16273
+ /* 减少动效:转圈停下,静止的箭头仍然读得出「还没好」;
16274
+ "在等什么"由卡片上的 role=status 与可见文案继续承担。
16275
+ 两组规则是同一件事的两个触发条件:系统偏好与作者打的 data-motion */
16276
+ @media (prefers-reduced-motion: reduce) {
16277
+ [data-scope='notification'][data-part='item'][data-type='loading'] [data-part='item-indicator']:empty::before {
16278
+ animation: none;
16279
+ }
16280
+ }
16281
+
16282
+ :where([data-motion='reduce']) [data-scope='notification'][data-part='item'][data-type='loading'] [data-part='item-indicator']:empty::before {
16283
+ animation: none;
16284
+ }
16285
+
16286
+ [data-scope='notification'][data-part='item-title'] {
16287
+ /* 作者可能把它写成 h2/p,外边距得先归零,否则卡片内的行距对不上 */
16288
+ margin: 0;
16289
+ color: var(--xh-notification-title-fg, var(--xh-fg-default));
16290
+ font-size: var(--xh-notification-title-font-size, var(--xh-text-label-size));
16291
+ font-weight: var(--xh-notification-title-font-weight, var(--xh-font-weight-semibold));
16292
+ line-height: var(--xh-notification-title-leading, var(--xh-leading-tight));
16293
+ }
16294
+
16295
+ /* 叉钉在右上角,标题得给它让位;说明与操作在第二行往下,不受影响 */
16296
+ [data-scope='notification'][data-part='item']:has([data-part='item-close-trigger']) [data-part='item-title'] {
16297
+ padding-inline-end: calc(var(--xh-notification-close-size, var(--xh-control-h-sm)) + var(--xh-space-2));
16298
+ }
16299
+
16300
+ [data-scope='notification'][data-part='item-description'] {
16301
+ margin: 0;
16302
+ color: var(--xh-notification-description-fg, var(--xh-fg-muted));
16303
+ font-size: var(--xh-notification-description-font-size, var(--xh-text-secondary-size));
16304
+ }
16305
+
16306
+ /* 没给文案的那一个仍然要留在 DOM 里(aria-labelledby / aria-describedby 指着它),
16307
+ 但空盒子会照吃一份 gap,卡片看着就多出一截莫名的留白 */
16308
+ [data-scope='notification'][data-part='item-title']:empty,
16309
+ [data-scope='notification'][data-part='item-description']:empty {
16310
+ display: none;
16311
+ }
16312
+
16313
+ [data-scope='notification'][data-part='item-title'][hidden],
16314
+ [data-scope='notification'][data-part='item-description'][hidden] {
16315
+ display: none;
16316
+ }
16317
+
16318
+ [data-scope='notification'][data-part='item-action-trigger'] {
16319
+ /* 网格列默认拉满,按钮要贴着起始侧收成自己的宽度 */
16320
+ justify-self: start;
16321
+ display: inline-flex;
16322
+ align-items: center;
16323
+ justify-content: center;
16324
+ block-size: var(--xh-notification-action-h, var(--xh-control-h-sm));
16325
+ padding-inline: var(--xh-notification-action-px, var(--xh-control-px-sm));
16326
+ border: var(--xh-stroke-thin) solid var(--xh-notification-action-border, var(--xh-border-default));
16327
+ border-radius: var(--xh-notification-action-radius, var(--xh-shape-control));
16328
+ background: var(--xh-notification-action-bg, var(--xh-bg-subtle));
16329
+ color: var(--xh-notification-action-fg, var(--xh-fg-default));
16330
+ /* 按钮不继承字族字号,不接回来的话卡片里会突然冒出一段系统 UI 字体 */
16331
+ font: inherit;
16332
+ font-weight: var(--xh-notification-action-font-weight, var(--xh-font-weight-medium));
16333
+ line-height: var(--xh-leading-none);
16334
+ cursor: pointer;
16335
+ }
16336
+
16337
+ [data-scope='notification'][data-part='item-action-trigger'][hidden] {
16338
+ display: none;
16339
+ }
16340
+
16341
+ [data-scope='notification'][data-part='item-action-trigger']:hover:not(:disabled) {
16342
+ background: var(--xh-notification-action-bg-hover, var(--xh-bg-subtle-hover));
16343
+ }
16344
+
16345
+ [data-scope='notification'][data-part='item-action-trigger']:active:not(:disabled) {
16346
+ background: var(--xh-notification-action-bg-active, var(--xh-bg-subtle-active));
16347
+ }
16348
+
16349
+ [data-scope='notification'][data-part='item-action-trigger']:focus-visible {
16350
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
16351
+ outline-offset: var(--xh-ring-offset);
16352
+ }
16353
+
16354
+ /* 钉在右上角的内衬处,不参与网格排布——留在流里它会变成正文下面的第三行 */
16355
+ [data-scope='notification'][data-part='item-close-trigger'] {
16356
+ position: absolute;
16357
+ inset-block-start: var(--xh-notification-close-inset, var(--xh-space-3));
16358
+ inset-inline-end: var(--xh-notification-close-inset, var(--xh-space-3));
16359
+ display: inline-flex;
16360
+ align-items: center;
16361
+ justify-content: center;
16362
+ block-size: var(--xh-notification-close-size, var(--xh-control-h-sm));
16363
+ inline-size: var(--xh-notification-close-size, var(--xh-control-h-sm));
16364
+ border: 0;
16365
+ border-radius: var(--xh-notification-close-radius, var(--xh-shape-control));
16366
+ background: transparent;
16367
+ color: var(--xh-notification-close-fg, var(--xh-fg-muted));
16368
+ font: inherit;
16369
+ line-height: var(--xh-leading-none);
16370
+ cursor: pointer;
16371
+ transition:
16372
+ background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
16373
+ color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
16374
+ scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
16375
+ }
16376
+
16377
+ /* closable=false 时连接层同时给了 hidden 与 disabled,这条是它真正收起的那一半:
16378
+ 上面声明了 display,不补回来就会留下一个按不动的叉,比压根没有叉更让人困惑 */
16379
+ [data-scope='notification'][data-part='item-close-trigger'][hidden] {
16380
+ display: none;
16381
+ }
16382
+
16383
+ [data-scope='notification'][data-part='item-close-trigger']:hover:not(:disabled) {
16384
+ background: var(--xh-notification-close-bg-hover, var(--xh-bg-subtle-hover));
16385
+ color: var(--xh-notification-close-fg-hover, var(--xh-fg-default));
16386
+ }
16387
+
16388
+ [data-scope='notification'][data-part='item-close-trigger']:active {
16389
+ background: var(--xh-notification-close-bg-active, var(--xh-bg-subtle-active));
16390
+ scale: var(--xh-motion-scale-press);
16391
+ }
16392
+
16393
+ /* 单体控件用原生 disabled。常规路径下它与 hidden 同时出现看不见,
16394
+ 但作者若在覆盖层把收起改了回来,至少还能看出这颗叉是按不动的 */
16395
+ [data-scope='notification'][data-part='item-close-trigger']:disabled {
16396
+ color: var(--xh-fg-disabled);
16397
+ cursor: not-allowed;
16398
+ }
16399
+
16400
+ [data-scope='notification'][data-part='item-close-trigger']:focus-visible {
16401
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
16402
+ outline-offset: var(--xh-ring-offset);
16403
+ }
16404
+
16405
+ /* 没写内容就由皮肤画兜底字形;作者往部件里塞了自己的图形,这几条即不命中 */
16406
+ [data-scope='notification'][data-part='item-close-trigger']:empty::before {
16407
+ content: '';
16408
+ display: inline-block;
16409
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
16410
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
16411
+ vertical-align: var(--xh-glyph-baseline-shift);
16412
+ background-color: currentColor;
16413
+ -webkit-mask: var(--xh-glyph-mark-close) center / contain no-repeat;
16414
+ mask: var(--xh-glyph-mark-close) center / contain no-repeat;
16415
+ }
16416
+
15535
16417
  /* styles/number-field.css */
15536
16418
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
15537
16419
  [data-scope='number-field'] {
@@ -15551,9 +16433,9 @@ input[data-scope='mention'][data-part='input'] {
15551
16433
  --xh-_number-field-h: var(--xh-control-h-md);
15552
16434
  --xh-_number-field-px: var(--xh-control-px-md);
15553
16435
  --xh-_number-field-gap: var(--xh-control-gap-md);
15554
- --xh-_number-field-font-size: var(--xh-text-body-size);
15555
- --xh-_number-field-label-font-size: var(--xh-text-label-size);
15556
- --xh-_number-field-trigger-font-size: var(--xh-text-body-size);
16436
+ --xh-_number-field-font-size: var(--xh-control-font-md);
16437
+ --xh-_number-field-label-font-size: var(--xh-control-font-md);
16438
+ --xh-_number-field-trigger-font-size: var(--xh-control-font-md);
15557
16439
 
15558
16440
  /* 盒子的圆角 */
15559
16441
  --xh-_number-field-radius: var(--xh-number-field-input-radius, var(--xh-shape-control));
@@ -15913,7 +16795,38 @@ input[data-scope='mention'][data-part='input'] {
15913
16795
  mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
15914
16796
  }
15915
16797
 
16798
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
16799
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
16800
+ [data-scope='number-field'][data-part='control'][hidden] {
16801
+ display: none;
16802
+ }
16803
+
15916
16804
  /* styles/pagination.css */
16805
+ /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
16806
+ 动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
16807
+ @keyframes xh-pop-in {
16808
+ from {
16809
+ opacity: 0;
16810
+ scale: var(--xh-motion-scale-enter);
16811
+ }
16812
+
16813
+ to {
16814
+ opacity: 1;
16815
+ scale: 1;
16816
+ }
16817
+ }
16818
+ @keyframes xh-pop-out {
16819
+ from {
16820
+ opacity: 1;
16821
+ scale: 1;
16822
+ }
16823
+
16824
+ to {
16825
+ opacity: 0;
16826
+ scale: var(--xh-motion-scale-enter);
16827
+ }
16828
+ }
16829
+
15917
16830
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
15918
16831
  [data-scope='pagination'] {
15919
16832
  --xh-pagination-skin: 1;
@@ -15923,11 +16836,14 @@ input[data-scope='mention'][data-part='input'] {
15923
16836
  页数为 0 时连接层会打 data-empty,这里不拿它做隐藏:作者常把「第 x-y 条」这类
15924
16837
  区间回显也写在 nav 里,整块藏掉会连那行字一起吞了,是否隐藏交给作者决定 */
15925
16838
  [data-scope='pagination'][data-part='root'] {
16839
+ /* 作者塞进上一页/下一页的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
16840
+ --xh-icon-size: var(--xh-pagination-icon-size, var(--xh-glyph-size-text));
16841
+
15926
16842
  /* 尺寸档只换这三个私有槽,上一页/下一页、页码与省略号都从 root 继承它们,
15927
16843
  换档不必给每个部件各写一条选择器 */
15928
16844
  --xh-_pagination-item-size: var(--xh-control-h-md);
15929
16845
  --xh-_pagination-item-px: var(--xh-control-px-md);
15930
- --xh-_pagination-font-size: var(--xh-text-label-size);
16846
+ --xh-_pagination-font-size: var(--xh-control-font-md);
15931
16847
 
15932
16848
  /* 当前页的选中态随语气走。没写 data-tone 时这几个 --xh-_tone-* 都没被声明,
15933
16849
  退回原来的品牌底与其配色。聚焦环不在其列,它恒是 --xh-ring-focus */
@@ -16048,22 +16964,149 @@ input[data-scope='mention'][data-part='input'] {
16048
16964
  color: var(--xh-pagination-item-fg-selected, var(--xh-_pagination-selected-fg));
16049
16965
  }
16050
16966
 
16051
- [data-scope='pagination'][data-part='item'][data-current]:hover {
16052
- border-color: var(--xh-pagination-item-border-selected-hover, var(--xh-_pagination-selected-bg-hover));
16053
- background: var(--xh-pagination-item-bg-selected-hover, var(--xh-_pagination-selected-bg-hover));
16967
+ [data-scope='pagination'][data-part='item'][data-current]:hover {
16968
+ border-color: var(--xh-pagination-item-border-selected-hover, var(--xh-_pagination-selected-bg-hover));
16969
+ background: var(--xh-pagination-item-bg-selected-hover, var(--xh-_pagination-selected-bg-hover));
16970
+ }
16971
+
16972
+ [data-scope='pagination'][data-part='item'][data-current]:active {
16973
+ border-color: var(--xh-pagination-item-border-selected-active, var(--xh-_pagination-selected-bg-active));
16974
+ background: var(--xh-pagination-item-bg-selected-active, var(--xh-_pagination-selected-bg-active));
16975
+ }
16976
+
16977
+ /* 省略号是纯视觉占位,读屏那边已被 aria-hidden 摘掉:
16978
+ 吞掉指针事件,免得它出现悬停反馈、看起来像一颗点得动的按钮 */
16979
+ [data-scope='pagination'][data-part='ellipsis'] {
16980
+ color: var(--xh-pagination-ellipsis-fg, var(--xh-fg-subtle));
16981
+ cursor: default;
16982
+ pointer-events: none;
16983
+ }
16984
+ /* 每页条数控制器:原生 select,抹掉系统外观后与页码格子共用同一副骨架。
16985
+ 箭头用背景图而非伪元素——原生 select 不生成 ::before */
16986
+ [data-scope='pagination'][data-part='page-size-select'] {
16987
+ flex: none;
16988
+ block-size: var(--xh-pagination-item-h, var(--xh-_pagination-item-size));
16989
+ padding-inline: var(--xh-pagination-item-px, var(--xh-_pagination-item-px));
16990
+ /* 右侧让开箭头 */
16991
+ padding-inline-end: calc(
16992
+ var(--xh-pagination-item-px, var(--xh-_pagination-item-px)) +
16993
+ var(--xh-icon-size, var(--xh-glyph-size-text)) + var(--xh-space-1)
16994
+ );
16995
+ border: var(--xh-stroke-thin) solid var(--xh-pagination-page-size-border, var(--xh-border-default));
16996
+ border-radius: var(--xh-pagination-item-radius, var(--xh-shape-control));
16997
+ background: var(--xh-pagination-page-size-bg, var(--xh-bg-surface));
16998
+ color: var(--xh-pagination-item-fg, var(--xh-fg-default));
16999
+ font-size: var(--xh-pagination-font-size, var(--xh-_pagination-font-size));
17000
+ line-height: var(--xh-leading-none);
17001
+ appearance: none;
17002
+ cursor: pointer;
17003
+ }
17004
+
17005
+ [data-scope='pagination'][data-part='page-size-select']:hover:not(:disabled) {
17006
+ border-color: var(--xh-pagination-page-size-border-hover, var(--xh-border-strong));
17007
+ }
17008
+
17009
+ [data-scope='pagination'][data-part='page-size-select']:focus-visible {
17010
+ outline: var(--xh-ring-width) solid var(--xh-ring-focus);
17011
+ outline-offset: var(--xh-ring-offset);
17012
+ }
17013
+
17014
+ [data-scope='pagination'][data-part='page-size-select']:disabled {
17015
+ color: var(--xh-fg-disabled);
17016
+ cursor: not-allowed;
17017
+ }
17018
+
17019
+ /* 摊开省略位的定位层。三处坐标系必须同为 fixed:机器交给引擎的 strategy、
17020
+ 连接层的内联 position、这里 —— 差一处就会算在错的坐标系里 */
17021
+ [data-scope='pagination'][data-part='positioner'] {
17022
+ /* 落定那一侧的可用高度,由定位引擎经内联自定义属性写进来,面板继承它限高;
17023
+ 引擎没算(尚未落位 / 无引擎 / 贴边归零)时不额外限高 */
17024
+ --xh-_pagination-available-h: 100vh;
17025
+
17026
+ /* 页码面板的自绘条浮在内容之上:轨道不上底色,实色轨道会在面板右缘糊一条竖灰带 */
17027
+ --xh-scrollbar-track-bg: transparent;
17028
+
17029
+ position: fixed;
17030
+ z-index: var(--xh-pagination-layer, var(--xh-layer-popover));
17031
+ /* 空壳不吃指针:省略位与面板之间那段间隙要能点得穿 */
17032
+ pointer-events: none;
17033
+ }
17034
+
17035
+ /* 锚点被滚出可视区:整个浮层随之收起 */
17036
+ [data-scope='pagination'][data-part='positioner'][data-hidden] {
17037
+ visibility: hidden;
17038
+ }
17039
+
17040
+ /* 摊开的页码面板:一串页码格子,横着排、必要时折行 */
17041
+ [data-scope='pagination'][data-part='content'] {
17042
+ /* 浮层被搬到 portal 落点,继承不到 root 上那把尺,这里再声明一遍 */
17043
+ --xh-icon-size: var(--xh-pagination-icon-size, var(--xh-glyph-size-text));
17044
+
17045
+ display: flex;
17046
+ flex-flow: row wrap;
17047
+ gap: var(--xh-pagination-gap, var(--xh-space-1));
17048
+ /* 页码不可预知有多少:不限高就整块伸出视口且滚不到 */
17049
+ max-inline-size: var(--xh-pagination-content-max-w, var(--xh-overlay-max-w));
17050
+ max-block-size: min(
17051
+ var(--xh-pagination-content-max-h, var(--xh-overlay-max-h)),
17052
+ var(--xh-_pagination-available-h)
17053
+ );
17054
+ overflow-y: auto;
17055
+ padding: var(--xh-pagination-content-p, var(--xh-space-1));
17056
+ border: var(--xh-stroke-thin) solid var(--xh-pagination-content-border, var(--xh-border-default));
17057
+ border-radius: var(--xh-pagination-content-radius, var(--xh-shape-surface));
17058
+ background: var(--xh-pagination-content-bg, var(--xh-bg-surface));
17059
+ box-shadow: var(--xh-pagination-content-shadow, var(--xh-elevation-floating));
17060
+ /* 定位层不吃指针,面板本体必须吃:里面的页码要点得到 */
17061
+ pointer-events: auto;
17062
+ }
17063
+
17064
+ [data-scope='pagination'][data-part='content'][data-state='open'] {
17065
+ animation: xh-pop-in var(--xh-motion-duration-enter) var(--xh-motion-ease-enter);
17066
+ }
17067
+
17068
+ /* 退场:收起那一帧 hidden 由退场闸门押后,这里才播得出来。forwards 把末态钉住,
17069
+ 免得动画结束到真收起之间闪一下原样 */
17070
+ [data-scope='pagination'][data-part='content'][data-state='closed'] {
17071
+ animation: xh-pop-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
17072
+ }
17073
+
17074
+ /* 这里刻意没有 [data-part='content'][hidden] { display: none }:
17075
+ 补了退场就一帧都播不出来,真正的收起由适配器落成内联 display */
17076
+
17077
+ /* 没写内容就由皮肤画兜底字形:上一页/下一页默认就是两枚箭头,
17078
+ 作者往部件里塞了自己的图形或文字,这两条即不命中 */
17079
+ [data-scope='pagination'][data-part='prev-trigger']:empty::before {
17080
+ content: '';
17081
+ display: inline-block;
17082
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
17083
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
17084
+ vertical-align: var(--xh-glyph-baseline-shift);
17085
+ background-color: currentColor;
17086
+ -webkit-mask: var(--xh-glyph-mark-chevron-left) center / contain no-repeat;
17087
+ mask: var(--xh-glyph-mark-chevron-left) center / contain no-repeat;
17088
+ }
17089
+
17090
+ [data-scope='pagination'][data-part='next-trigger']:empty::before {
17091
+ content: '';
17092
+ display: inline-block;
17093
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
17094
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
17095
+ vertical-align: var(--xh-glyph-baseline-shift);
17096
+ background-color: currentColor;
17097
+ -webkit-mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
17098
+ mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
16054
17099
  }
16055
17100
 
16056
- [data-scope='pagination'][data-part='item'][data-current]:active {
16057
- border-color: var(--xh-pagination-item-border-selected-active, var(--xh-_pagination-selected-bg-active));
16058
- background: var(--xh-pagination-item-bg-selected-active, var(--xh-_pagination-selected-bg-active));
17101
+ /* rtl 下页序从右往左走,箭头跟着指向行进方向 */
17102
+ [dir='rtl'] [data-scope='pagination'][data-part='prev-trigger']:empty::before {
17103
+ -webkit-mask-image: var(--xh-glyph-mark-chevron-right);
17104
+ mask-image: var(--xh-glyph-mark-chevron-right);
16059
17105
  }
16060
17106
 
16061
- /* 省略号是纯视觉占位,读屏那边已被 aria-hidden 摘掉:
16062
- 吞掉指针事件,免得它出现悬停反馈、看起来像一颗点得动的按钮 */
16063
- [data-scope='pagination'][data-part='ellipsis'] {
16064
- color: var(--xh-pagination-ellipsis-fg, var(--xh-fg-subtle));
16065
- cursor: default;
16066
- pointer-events: none;
17107
+ [dir='rtl'] [data-scope='pagination'][data-part='next-trigger']:empty::before {
17108
+ -webkit-mask-image: var(--xh-glyph-mark-chevron-left);
17109
+ mask-image: var(--xh-glyph-mark-chevron-left);
16067
17110
  }
16068
17111
 
16069
17112
  /* styles/pin-input.css */
@@ -16076,9 +17119,9 @@ input[data-scope='mention'][data-part='input'] {
16076
17119
  [data-scope='pin-input'][data-part='root'] {
16077
17120
  /* 尺寸档只换这四个私有槽,标题与格子都从 root 继承它们,换档不必给每个部件各写一条选择器 */
16078
17121
  --xh-_pin-input-box-size: var(--xh-control-box-md);
16079
- --xh-_pin-input-box-gap: var(--xh-space-2);
17122
+ --xh-_pin-input-box-gap: var(--xh-control-gap-md);
16080
17123
  --xh-_pin-input-box-font-size: var(--xh-text-heading-3-size);
16081
- --xh-_pin-input-label-font-size: var(--xh-text-label-size);
17124
+ --xh-_pin-input-label-font-size: var(--xh-control-font-md);
16082
17125
  /* 形态档只换这三个私有槽,缺省这一份就是描边式(描边 + 画布底) */
16083
17126
  --xh-_pin-input-box-bg: var(--xh-bg-canvas);
16084
17127
  --xh-_pin-input-box-border: var(--xh-border-control);
@@ -16269,6 +17312,9 @@ input[data-scope='mention'][data-part='input'] {
16269
17312
  引擎没算(尚未落位 / 无引擎 / 贴边归零)时不额外限高 */
16270
17313
  --xh-_popover-available-h: 100vh;
16271
17314
 
17315
+ /* 面板内容的自绘条浮在内容之上:轨道不上底色,实色轨道会在面板右缘糊一条竖灰带 */
17316
+ --xh-scrollbar-track-bg: transparent;
17317
+
16272
17318
  position: fixed;
16273
17319
  z-index: var(--xh-popover-layer, var(--xh-layer-popover));
16274
17320
  /* 空壳不吃指针,交互只发生在 content 上 */
@@ -16458,7 +17504,7 @@ input[data-scope='mention'][data-part='input'] {
16458
17504
  overflow: hidden;
16459
17505
  inline-size: 100%;
16460
17506
  block-size: var(--xh-_thickness);
16461
- border-radius: var(--xh-shape-pill);
17507
+ border-radius: var(--xh-progress-track-radius, var(--xh-shape-pill));
16462
17508
  background: var(--xh-progress-track, var(--xh-bg-subtle-active));
16463
17509
  }
16464
17510
 
@@ -16466,7 +17512,7 @@ input[data-scope='mention'][data-part='input'] {
16466
17512
  轨道不跟着换族:只有已完成的那段换色,底槽保持中性才读得出"完成了多少"。 */
16467
17513
  [data-scope='progress'][data-part='range'] {
16468
17514
  block-size: 100%;
16469
- border-radius: var(--xh-shape-pill);
17515
+ border-radius: var(--xh-progress-range-radius, var(--xh-shape-pill));
16470
17516
  background: var(--xh-progress-range, var(--xh-_tone, var(--xh-bg-brand)));
16471
17517
  transition: inline-size var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
16472
17518
  }
@@ -16573,6 +17619,12 @@ input[data-scope='mention'][data-part='input'] {
16573
17619
  visibility: hidden;
16574
17620
  }
16575
17621
 
17622
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
17623
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
17624
+ [data-scope='progress'][data-part='root'][hidden] {
17625
+ display: none;
17626
+ }
17627
+
16576
17628
  /* styles/radio-group.css */
16577
17629
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
16578
17630
  [data-scope='radio-group'] {
@@ -16582,7 +17634,8 @@ input[data-scope='mention'][data-part='input'] {
16582
17634
  [data-scope='radio-group'][data-part='root'] {
16583
17635
  /* 尺寸档只换这两个私有槽,标题与条目都从 root 继承它们,换档不必给每个部件各写一条选择器 */
16584
17636
  --xh-_radio-group-item-gap: var(--xh-control-gap-md);
16585
- --xh-_radio-group-font-size: var(--xh-text-label-size);
17637
+ --xh-_radio-group-font-size: var(--xh-control-font-md);
17638
+ --xh-_radio-group-indicator: var(--xh-control-indicator-md);
16586
17639
  /* 选中色随语气走。没写 data-tone 时 --xh-_tone 没被声明,退回原来的品牌色 */
16587
17640
  --xh-_radio-group-accent: var(--xh-_tone, var(--xh-bg-brand));
16588
17641
 
@@ -16603,11 +17656,13 @@ input[data-scope='mention'][data-part='input'] {
16603
17656
  [data-scope='radio-group'][data-part='root'][data-size='sm'] {
16604
17657
  --xh-_radio-group-item-gap: var(--xh-control-gap-sm);
16605
17658
  --xh-_radio-group-font-size: var(--xh-control-font-sm);
17659
+ --xh-_radio-group-indicator: var(--xh-control-indicator-sm);
16606
17660
  }
16607
17661
 
16608
17662
  [data-scope='radio-group'][data-part='root'][data-size='lg'] {
16609
17663
  --xh-_radio-group-item-gap: var(--xh-control-gap-lg);
16610
17664
  --xh-_radio-group-font-size: var(--xh-control-font-lg);
17665
+ --xh-_radio-group-indicator: var(--xh-control-indicator-lg);
16611
17666
  }
16612
17667
 
16613
17668
  [data-scope='radio-group'][data-part='label'] {
@@ -16646,10 +17701,10 @@ input[data-scope='mention'][data-part='input'] {
16646
17701
  flex: none;
16647
17702
  align-items: center;
16648
17703
  justify-content: center;
16649
- inline-size: var(--xh-radio-group-indicator-size, var(--xh-control-indicator-size));
16650
- block-size: var(--xh-radio-group-indicator-size, var(--xh-control-indicator-size));
17704
+ inline-size: var(--xh-radio-group-indicator-size, var(--xh-_radio-group-indicator));
17705
+ block-size: var(--xh-radio-group-indicator-size, var(--xh-_radio-group-indicator));
16651
17706
  border: var(--xh-stroke-thin) solid var(--xh-radio-group-indicator-border, var(--xh-border-control));
16652
- border-radius: var(--xh-shape-pill);
17707
+ border-radius: var(--xh-radio-group-indicator-radius, var(--xh-shape-pill));
16653
17708
  background: var(--xh-radio-group-indicator-bg, var(--xh-bg-canvas));
16654
17709
  transition: border-color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
16655
17710
  }
@@ -16668,8 +17723,8 @@ input[data-scope='mention'][data-part='input'] {
16668
17723
  直径取指示器的一半:换尺寸档时圈与点一起走,比例不散 */
16669
17724
  [data-scope='radio-group'][data-part='indicator']::before {
16670
17725
  content: '';
16671
- inline-size: calc(var(--xh-radio-group-indicator-size, var(--xh-control-indicator-size)) / 2);
16672
- block-size: calc(var(--xh-radio-group-indicator-size, var(--xh-control-indicator-size)) / 2);
17726
+ inline-size: calc(var(--xh-radio-group-indicator-size, var(--xh-_radio-group-indicator)) / 2);
17727
+ block-size: calc(var(--xh-radio-group-indicator-size, var(--xh-_radio-group-indicator)) / 2);
16673
17728
  border-radius: var(--xh-shape-pill);
16674
17729
  background: var(--xh-radio-group-indicator-dot, var(--xh-_radio-group-accent));
16675
17730
  scale: 0;
@@ -16685,6 +17740,14 @@ input[data-scope='mention'][data-part='input'] {
16685
17740
  user-select: none;
16686
17741
  }
16687
17742
 
17743
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
17744
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
17745
+ [data-scope='radio-group'][data-part='root'][hidden],
17746
+ [data-scope='radio-group'][data-part='item'][hidden],
17747
+ [data-scope='radio-group'][data-part='indicator'][hidden] {
17748
+ display: none;
17749
+ }
17750
+
16688
17751
  /* styles/rating.css */
16689
17752
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
16690
17753
  [data-scope='rating'] {
@@ -16695,9 +17758,9 @@ input[data-scope='mention'][data-part='input'] {
16695
17758
  根上不留基准它就会贴到更外层的定位祖先上,原生校验提示跟着飘到页面别处。 */
16696
17759
  [data-scope='rating'][data-part='root'] {
16697
17760
  /* 尺寸档只换这三个私有槽,标题与星星都从 root 继承它们,换档不必给每个部件各写一条选择器 */
16698
- --xh-_rating-item-gap: var(--xh-space-1);
17761
+ --xh-_rating-item-gap: var(--xh-control-gap-md);
16699
17762
  --xh-_rating-item-size: var(--xh-font-size-2xl);
16700
- --xh-_rating-font-size: var(--xh-text-label-size);
17763
+ --xh-_rating-font-size: var(--xh-control-font-md);
16701
17764
  /* 点亮色随语气走。没写 data-tone 时 --xh-_tone 没被声明,退回原来的警示色 */
16702
17765
  --xh-_rating-accent: var(--xh-_tone, var(--xh-color-warning-500));
16703
17766
 
@@ -17007,6 +18070,9 @@ input[data-scope='mention'][data-part='input'] {
17007
18070
  --xh-_scrollbar-thickness: var(--xh-scrollbar-thickness-md);
17008
18071
 
17009
18072
  position: absolute;
18073
+ /* 浮层的 positioner 一律 pointer-events: none,条子作为它的子节点会继承到,拖不动也点不着;
18074
+ 收起态那条规则优先级更高,仍旧穿透 */
18075
+ pointer-events: auto;
17010
18076
  /* touch-action 关掉浏览器自己的手势:不关的话手指一按滑块页面就跟着滚,
17011
18077
  指针随即被系统收走(pointercancel),拖到一半的滑块停在原地。
17012
18078
  user-select 同理——拖动时选中页面文字会让滑块"粘"住。 */
@@ -17199,9 +18265,11 @@ input[data-scope='mention'][data-part='input'] {
17199
18265
  换档不必给每个部件各写一条选择器 */
17200
18266
  --xh-_select-h: var(--xh-control-h-md);
17201
18267
  --xh-_select-px: var(--xh-control-px-md);
18268
+ --xh-_select-item-py: var(--xh-list-option-py-md);
18269
+ --xh-_select-item-px: var(--xh-control-px-md);
17202
18270
  --xh-_select-gap: var(--xh-control-gap-md);
17203
- --xh-_select-font-size: var(--xh-text-body-size);
17204
- --xh-_select-label-font-size: var(--xh-text-label-size);
18271
+ --xh-_select-font-size: var(--xh-control-font-md);
18272
+ --xh-_select-label-font-size: var(--xh-control-font-md);
17205
18273
 
17206
18274
  /* 形态档只换这三个槽:缺省即 outline(描边 + 画布底) */
17207
18275
  --xh-_select-control-bg: var(--xh-bg-canvas);
@@ -17211,7 +18279,7 @@ input[data-scope='mention'][data-part='input'] {
17211
18279
  /* 聚焦环恒用固定环色;强调色随语气走,只落在勾选标记与选中文字上,正文文字色不动。
17212
18280
  没写 data-tone 时 --xh-_tone 没被声明,两处都退回原来的取值 */
17213
18281
  --xh-_select-ring: var(--xh-ring-focus);
17214
- --xh-_select-accent: var(--xh-_tone, var(--xh-bg-brand));
18282
+ --xh-_select-accent: var(--xh-_tone, var(--xh-fg-brand));
17215
18283
  --xh-_select-item-selected-fg: var(--xh-_tone-fg, var(--xh-fg-brand-strong));
17216
18284
  }
17217
18285
 
@@ -17231,6 +18299,8 @@ input[data-scope='mention'][data-part='input'] {
17231
18299
  [data-scope='select']:is([data-part='root'], [data-part='positioner'])[data-size='sm'] {
17232
18300
  --xh-_select-h: var(--xh-control-h-sm);
17233
18301
  --xh-_select-px: var(--xh-control-px-sm);
18302
+ --xh-_select-item-py: var(--xh-list-option-py-sm);
18303
+ --xh-_select-item-px: var(--xh-control-px-sm);
17234
18304
  --xh-_select-gap: var(--xh-control-gap-sm);
17235
18305
  --xh-_select-font-size: var(--xh-control-font-sm);
17236
18306
  --xh-_select-label-font-size: var(--xh-control-font-sm);
@@ -17248,6 +18318,8 @@ input[data-scope='mention'][data-part='input'] {
17248
18318
  [data-scope='select']:is([data-part='root'], [data-part='positioner'])[data-size='lg'] {
17249
18319
  --xh-_select-h: var(--xh-control-h-lg);
17250
18320
  --xh-_select-px: var(--xh-control-px-lg);
18321
+ --xh-_select-item-py: var(--xh-list-option-py-lg);
18322
+ --xh-_select-item-px: var(--xh-control-px-lg);
17251
18323
  --xh-_select-gap: var(--xh-control-gap-lg);
17252
18324
  --xh-_select-font-size: var(--xh-control-font-lg);
17253
18325
  --xh-_select-label-font-size: var(--xh-control-font-lg);
@@ -17296,8 +18368,6 @@ input[data-scope='mention'][data-part='input'] {
17296
18368
  block-size: var(--xh-select-control-h, var(--xh-_select-h));
17297
18369
  padding-inline: var(--xh-select-control-px, var(--xh-_select-px));
17298
18370
  min-inline-size: var(--xh-select-control-min-w, var(--xh-control-min-w));
17299
- /* 多选会把 N 项的文本连成一串,框宽必须封顶;与浮层同一个上限,两半看着才是一件东西 */
17300
- max-inline-size: var(--xh-select-control-max-w, var(--xh-overlay-max-w));
17301
18371
  border: var(--xh-stroke-thin) solid var(--xh-select-control-border, var(--xh-_select-control-border));
17302
18372
  border-radius: var(--xh-select-control-radius, var(--xh-shape-control));
17303
18373
  background: var(--xh-select-control-bg, var(--xh-_select-control-bg));
@@ -17544,6 +18614,7 @@ input[data-scope='mention'][data-part='input'] {
17544
18614
  display: flex;
17545
18615
  flex: 1 1 auto;
17546
18616
  flex-direction: column;
18617
+ gap: var(--xh-select-list-gap, var(--xh-list-option-gap));
17547
18618
  min-block-size: 0;
17548
18619
  overflow-y: auto;
17549
18620
  }
@@ -17598,8 +18669,8 @@ input[data-scope='mention'][data-part='input'] {
17598
18669
  display: flex;
17599
18670
  align-items: center;
17600
18671
  gap: var(--xh-select-item-gap, var(--xh-_select-gap));
17601
- padding-block: var(--xh-select-item-py, var(--xh-space-1_5));
17602
- padding-inline: var(--xh-select-item-px, var(--xh-control-px-md));
18672
+ padding-block: var(--xh-select-item-py, var(--xh-_select-item-py));
18673
+ padding-inline: var(--xh-select-item-px, var(--xh-_select-item-px));
17603
18674
  border-radius: var(--xh-select-item-radius, var(--xh-shape-control));
17604
18675
  color: var(--xh-select-item-fg, var(--xh-fg-default));
17605
18676
  font-size: var(--xh-select-item-font-size, var(--xh-_select-font-size));
@@ -17706,6 +18777,19 @@ input[data-scope='mention'][data-part='input'] {
17706
18777
  mask: var(--xh-glyph-mark-close) center / contain no-repeat;
17707
18778
  }
17708
18779
 
18780
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
18781
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
18782
+ [data-scope='select'][data-part='root'][hidden],
18783
+ [data-scope='select'][data-part='control'][hidden],
18784
+ [data-scope='select'][data-part='trigger'][hidden],
18785
+ [data-scope='select'][data-part='tag'][hidden],
18786
+ [data-scope='select'][data-part='indicator'][hidden],
18787
+ [data-scope='select'][data-part='list'][hidden],
18788
+ [data-scope='select'][data-part='item'][hidden],
18789
+ [data-scope='select'][data-part='item-indicator'][hidden] {
18790
+ display: none;
18791
+ }
18792
+
17709
18793
  /* styles/separator.css */
17710
18794
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
17711
18795
  [data-scope='separator'] {
@@ -17804,8 +18888,8 @@ input[data-scope='mention'][data-part='input'] {
17804
18888
  }
17805
18889
 
17806
18890
  [data-scope='side-nav'][data-part='group-label'] {
17807
- padding-block: var(--xh-space-1);
17808
- padding-inline: var(--xh-control-px-md);
18891
+ padding-block: var(--xh-side-nav-group-label-py, var(--xh-space-1));
18892
+ padding-inline: var(--xh-side-nav-group-label-px, var(--xh-control-px-md));
17809
18893
  font-size: var(--xh-text-caption-size);
17810
18894
  color: var(--xh-fg-subtle);
17811
18895
  user-select: none;
@@ -17835,12 +18919,12 @@ input[data-scope='mention'][data-part='input'] {
17835
18919
  [data-scope='side-nav'][data-part='link'] {
17836
18920
  display: flex;
17837
18921
  align-items: center;
17838
- gap: var(--xh-control-gap-md);
18922
+ gap: var(--xh-side-nav-link-gap, var(--xh-control-gap-md));
17839
18923
  inline-size: 100%;
17840
18924
  min-block-size: var(--xh-control-h-md);
17841
- padding-inline: var(--xh-control-px-md);
18925
+ padding-inline: var(--xh-side-nav-link-px, var(--xh-control-px-md));
17842
18926
  border: none;
17843
- border-radius: var(--xh-shape-control);
18927
+ border-radius: var(--xh-side-nav-link-radius, var(--xh-shape-control));
17844
18928
  background: none;
17845
18929
  color: inherit;
17846
18930
  font-size: var(--xh-text-body-size);
@@ -17986,6 +19070,17 @@ input[data-scope='mention'][data-part='input'] {
17986
19070
  mask: var(--xh-glyph-mark-chevron-right) center / contain no-repeat;
17987
19071
  }
17988
19072
 
19073
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
19074
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
19075
+ [data-scope='side-nav'][data-part='root'][hidden],
19076
+ [data-scope='side-nav'][data-part='group'][hidden],
19077
+ [data-scope='side-nav'][data-part='branch'][hidden],
19078
+ [data-scope='side-nav'][data-part='item'][hidden],
19079
+ [data-scope='side-nav'][data-part='link'][hidden],
19080
+ [data-scope='side-nav'][data-part='branch-indicator'][hidden] {
19081
+ display: none;
19082
+ }
19083
+
17989
19084
  /* styles/slider.css */
17990
19085
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
17991
19086
  [data-scope='slider'] {
@@ -18120,7 +19215,9 @@ input[data-scope='mention'][data-part='input'] {
18120
19215
  background: var(--xh-slider-thumb-bg, var(--xh-_tone, var(--xh-bg-brand)));
18121
19216
  box-shadow: var(--xh-slider-thumb-shadow, var(--xh-elevation-raised));
18122
19217
  cursor: grab;
18123
- transition: scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
19218
+ transition:
19219
+ scale var(--xh-motion-duration-micro) var(--xh-motion-ease-enter),
19220
+ box-shadow var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
18124
19221
  }
18125
19222
 
18126
19223
  /* 内联样式把 inset-inline-start 定在值所在的比例上,那是拇指的**起始边**不是圆心;
@@ -18191,7 +19288,7 @@ input[data-scope='mention'][data-part='input'] {
18191
19288
  inset-block-start: 50%;
18192
19289
  inline-size: var(--xh-slider-mark-size, var(--xh-space-1));
18193
19290
  block-size: var(--xh-slider-mark-size, var(--xh-space-1));
18194
- border-radius: var(--xh-shape-pill);
19291
+ border-radius: var(--xh-slider-mark-radius, var(--xh-shape-pill));
18195
19292
  background: var(--xh-slider-mark-bg, var(--xh-border-strong));
18196
19293
  translate: -50% -50%;
18197
19294
  }
@@ -18387,8 +19484,8 @@ input[data-scope='mention'][data-part='input'] {
18387
19484
 
18388
19485
  /* 尺寸档只换这三个私有槽,序号圆点、标题与说明都从 root 继承它们,
18389
19486
  换档不必给每个部件各写一条选择器 */
18390
- --xh-_steps-indicator-size: var(--xh-control-h-sm);
18391
- --xh-_steps-title-font-size: var(--xh-text-label-size);
19487
+ --xh-_steps-indicator-size: var(--xh-space-7);
19488
+ --xh-_steps-title-font-size: var(--xh-control-font-md);
18392
19489
  --xh-_steps-caption-font-size: var(--xh-text-caption-size);
18393
19490
 
18394
19491
  /* 语气落在走过与当前这两步的标记和连接线上:强调色画描边与填充,
@@ -18530,8 +19627,8 @@ input[data-scope='mention'][data-part='input'] {
18530
19627
  justify-content: center;
18531
19628
  inline-size: var(--xh-steps-indicator-size, var(--xh-_steps-indicator-size));
18532
19629
  block-size: var(--xh-steps-indicator-size, var(--xh-_steps-indicator-size));
18533
- border: var(--xh-stroke-thin) solid var(--xh-steps-indicator-border, var(--xh-border-strong));
18534
- border-radius: var(--xh-shape-pill);
19630
+ border: var(--xh-stroke-thin) solid var(--xh-steps-indicator-border, var(--xh-border-control));
19631
+ border-radius: var(--xh-steps-indicator-radius, var(--xh-shape-pill));
18535
19632
  background: var(--xh-steps-indicator-bg, transparent);
18536
19633
  color: var(--xh-steps-indicator-fg, var(--xh-fg-muted));
18537
19634
  font-size: var(--xh-steps-indicator-font-size, var(--xh-_steps-caption-font-size));
@@ -18563,7 +19660,7 @@ input[data-scope='mention'][data-part='input'] {
18563
19660
  }
18564
19661
 
18565
19662
  [data-scope='steps'][data-part='item'][data-disabled] [data-scope='steps'][data-part='indicator'] {
18566
- border-color: var(--xh-steps-indicator-border-disabled, var(--xh-fg-disabled));
19663
+ border-color: var(--xh-steps-indicator-border-disabled, var(--xh-border-subtle));
18567
19664
  color: var(--xh-steps-indicator-fg-disabled, var(--xh-fg-disabled));
18568
19665
  }
18569
19666
 
@@ -18599,7 +19696,7 @@ input[data-scope='mention'][data-part='input'] {
18599
19696
  flex: 1;
18600
19697
  min-inline-size: var(--xh-steps-separator-min-length, var(--xh-space-4));
18601
19698
  block-size: var(--xh-steps-separator-thickness, var(--xh-stroke-thick));
18602
- border-radius: var(--xh-shape-pill);
19699
+ border-radius: var(--xh-steps-separator-radius, var(--xh-shape-pill));
18603
19700
  background: var(--xh-steps-separator-bg, var(--xh-border-default));
18604
19701
  transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
18605
19702
  }
@@ -18679,7 +19776,7 @@ input[data-scope='mention'][data-part='input'] {
18679
19776
  block-size: var(--xh-_switch-track-h);
18680
19777
  padding: var(--xh-_switch-pad);
18681
19778
  border: 0;
18682
- border-radius: var(--xh-shape-pill);
19779
+ border-radius: var(--xh-switch-radius, var(--xh-shape-pill));
18683
19780
  background: var(--xh-switch-bg, var(--xh-bg-subtle-active));
18684
19781
  cursor: pointer;
18685
19782
  transition: background var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
@@ -18717,7 +19814,7 @@ input[data-scope='mention'][data-part='input'] {
18717
19814
  [data-scope='switch'][data-part='thumb'] {
18718
19815
  inline-size: var(--xh-_switch-thumb-size);
18719
19816
  block-size: var(--xh-_switch-thumb-size);
18720
- border-radius: var(--xh-shape-pill);
19817
+ border-radius: var(--xh-switch-thumb-radius, var(--xh-shape-pill));
18721
19818
  background: var(--xh-switch-thumb, var(--xh-bg-canvas));
18722
19819
  box-shadow: var(--xh-switch-thumb-shadow, var(--xh-elevation-raised));
18723
19820
  transition: translate var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
@@ -18784,6 +19881,13 @@ input[data-scope='mention'][data-part='input'] {
18784
19881
  animation: none;
18785
19882
  }
18786
19883
 
19884
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
19885
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
19886
+ [data-scope='switch'][data-part='root'][hidden],
19887
+ [data-scope='switch'][data-part='label'][hidden] {
19888
+ display: none;
19889
+ }
19890
+
18787
19891
  /* styles/table.css */
18788
19892
  /* 加载态自己冒出来,用户没按任何键:一段极轻的呼吸就够,别抢走正在读表的注意力 */
18789
19893
  @keyframes xh-table-loading-pulse {
@@ -18803,13 +19907,17 @@ input[data-scope='mention'][data-part='input'] {
18803
19907
 
18804
19908
  /* 表格自己滚动:吸顶表头与横向吸附列都要一个确定的滚动容器才钉得住 */
18805
19909
  [data-scope='table'][data-part='root'] {
19910
+ /* 组件内那几档层号只在自己人之间排序:建一个层叠上下文把它们关起来,
19911
+ 既不让页面上的层号插进来,也不让它们漏出去压住别人 */
19912
+ isolation: isolate;
19913
+
18806
19914
  /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
18807
19915
  --xh-icon-size: var(--xh-table-icon-size, var(--xh-glyph-size-text));
18808
19916
 
18809
19917
  /* 密度档只换这两个私有槽:单元格与列标题从 root 继承前者,字号靠 font-size 本身继承下去,
18810
19918
  换档不必给每个部件各写一条选择器,列宽那套算法也一点不碰 */
18811
19919
  --xh-_table-cell-py: var(--xh-table-cell-py-md);
18812
- --xh-_table-font-size: var(--xh-text-body-size);
19920
+ --xh-_table-font-size: var(--xh-control-font-md);
18813
19921
 
18814
19922
  display: flex;
18815
19923
  position: relative;
@@ -19068,7 +20176,8 @@ input[data-scope='mention'][data-part='input'] {
19068
20176
  color: transparent;
19069
20177
  }
19070
20178
 
19071
- /* 半选画一条横杠盖住勾:aria-checked=mixed 在视觉上也得与"全选"分得开 */
20179
+ /* 半选换一枚横杠字形盖住勾:aria-checked=mixed 在视觉上也得与"全选"分得开。
20180
+ 横杠与勾同走字形令牌,作者换掉标记时两态一起换 */
19072
20181
  [data-scope='table'][data-part='select-all-trigger'][data-state='indeterminate'] {
19073
20182
  position: relative;
19074
20183
  color: transparent;
@@ -19076,11 +20185,12 @@ input[data-scope='mention'][data-part='input'] {
19076
20185
 
19077
20186
  [data-scope='table'][data-part='select-all-trigger'][data-state='indeterminate']::after {
19078
20187
  position: absolute;
19079
- inline-size: 60%;
19080
- block-size: var(--xh-stroke-thick);
19081
- border-radius: var(--xh-shape-pill);
19082
- background: var(--xh-table-trigger-fg, var(--xh-fg-on-brand));
20188
+ inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
20189
+ block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
20190
+ background-color: var(--xh-table-trigger-fg, var(--xh-fg-on-brand));
19083
20191
  content: '';
20192
+ -webkit-mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
20193
+ mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
19084
20194
  }
19085
20195
 
19086
20196
  [data-scope='table'][data-part='select-all-trigger'][data-disabled],
@@ -19091,10 +20201,12 @@ input[data-scope='mention'][data-part='input'] {
19091
20201
  cursor: not-allowed;
19092
20202
  }
19093
20203
 
19094
- /* 全选把手是表头里独立的 Tab 停靠点,环得画在它自己身上 */
20204
+ /* 全选把手是表头里独立的 Tab 停靠点,环得画在它自己身上。
20205
+ 往内收,与行、排序把手同一口径:把手长在列头里,列头与根都收 overflow,
20206
+ 环画在外沿会被裁掉 */
19095
20207
  [data-scope='table'][data-part='select-all-trigger']:focus-visible {
19096
20208
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
19097
- outline-offset: var(--xh-ring-offset);
20209
+ outline-offset: calc(-1 * var(--xh-ring-width));
19098
20210
  }
19099
20211
 
19100
20212
  /* 行选择把手不占 Tab 位(键盘那一路走 Space),只服务指针 */
@@ -19295,7 +20407,7 @@ input[data-scope='mention'][data-part='input'] {
19295
20407
  /* 尺寸档只换这三个私有槽,标签从 root 继承它们,换档不必给每个部件各写一条选择器 */
19296
20408
  --xh-_tabs-trigger-h: var(--xh-control-h-md);
19297
20409
  --xh-_tabs-trigger-px: var(--xh-control-px-md);
19298
- --xh-_tabs-trigger-font-size: var(--xh-text-label-size);
20410
+ --xh-_tabs-trigger-font-size: var(--xh-control-font-md);
19299
20411
 
19300
20412
  /* 形态档只换这几个私有槽:列表的底、内边距、基线,与标签的描边、选中底、选中态那道指示。
19301
20413
  缺省档(line)是一条基线加一行标签,选中只换文字色——这里的取值即现状 */
@@ -19447,6 +20559,14 @@ input[data-scope='mention'][data-part='input'] {
19447
20559
  outline-offset: var(--xh-ring-offset);
19448
20560
  }
19449
20561
 
20562
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
20563
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
20564
+ [data-scope='tabs'][data-part='root'][hidden],
20565
+ [data-scope='tabs'][data-part='list'][hidden],
20566
+ [data-scope='tabs'][data-part='trigger'][hidden] {
20567
+ display: none;
20568
+ }
20569
+
19450
20570
  /* styles/tags-input.css */
19451
20571
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
19452
20572
  [data-scope='tags-input'] {
@@ -19464,9 +20584,9 @@ input[data-scope='mention'][data-part='input'] {
19464
20584
  --xh-_tags-input-control-h: var(--xh-control-h-md);
19465
20585
  --xh-_tags-input-control-px: var(--xh-control-px-md);
19466
20586
  --xh-_tags-input-control-gap: var(--xh-control-gap-md);
19467
- --xh-_tags-input-input-font-size: var(--xh-text-body-size);
19468
- --xh-_tags-input-item-font-size: var(--xh-text-secondary-size);
19469
- --xh-_tags-input-label-font-size: var(--xh-text-label-size);
20587
+ --xh-_tags-input-input-font-size: var(--xh-control-font-md);
20588
+ --xh-_tags-input-item-font-size: var(--xh-control-caption-md);
20589
+ --xh-_tags-input-label-font-size: var(--xh-control-font-md);
19470
20590
  /* 形态档只换这三个私有槽,缺省这一份就是描边式(描边 + 画布底) */
19471
20591
  --xh-_tags-input-control-bg: var(--xh-bg-canvas);
19472
20592
  --xh-_tags-input-control-border: var(--xh-border-control);
@@ -19868,9 +20988,9 @@ input[data-scope='mention'][data-part='input'] {
19868
20988
  --xh-_text-field-h: var(--xh-control-h-md);
19869
20989
  --xh-_text-field-px: var(--xh-control-px-md);
19870
20990
  --xh-_text-field-gap: var(--xh-control-gap-md);
19871
- --xh-_text-field-font-size: var(--xh-text-body-size);
19872
- --xh-_text-field-label-font-size: var(--xh-text-label-size);
19873
- --xh-_text-field-action-font-size: var(--xh-text-secondary-size);
20991
+ --xh-_text-field-font-size: var(--xh-control-font-md);
20992
+ --xh-_text-field-label-font-size: var(--xh-control-font-md);
20993
+ --xh-_text-field-action-font-size: var(--xh-control-caption-md);
19874
20994
 
19875
20995
  /* 形态档只换这三个私有槽:底、常态描边、悬停描边 */
19876
20996
  --xh-_text-field-bg: var(--xh-bg-canvas);
@@ -20185,6 +21305,10 @@ input[data-scope='mention'][data-part='input'] {
20185
21305
  /* 自建定位上下文,作为绝对定位的回到底部按钮的参照系;
20186
21306
  block-size: 100% 让高度由外部决定,使滚动发生在内部。 */
20187
21307
  [data-scope='thread'][data-part='root'] {
21308
+ /* 组件内那几档层号只在自己人之间排序:建一个层叠上下文把它们关起来,
21309
+ 既不让页面上的层号插进来,也不让它们漏出去压住别人 */
21310
+ isolation: isolate;
21311
+
20188
21312
  position: relative;
20189
21313
  display: flex;
20190
21314
  flex-direction: column;
@@ -20198,14 +21322,18 @@ input[data-scope='mention'][data-part='input'] {
20198
21322
 
20199
21323
  /* 滚动容器,粘底读的是它的 scrollTop / clientHeight / scrollHeight。
20200
21324
  min-block-size: 0 让弹性子项能被压缩从而触发溢出;
20201
- overscroll-behavior: contain 阻止滚动量传给页面;
20202
- scrollbar-gutter: stable 避免滚动条出现与消失时推动文字。 */
21325
+ overscroll-behavior: contain 阻止滚动量传给页面。 */
20203
21326
  [data-scope='thread'][data-part='viewport'] {
20204
21327
  flex: 1;
20205
21328
  min-block-size: 0;
20206
21329
  /* 逻辑属性 overflow-block 尚无可用实现,写物理轴 */
20207
21330
  overflow-y: auto;
20208
21331
  overscroll-behavior: contain;
21332
+ }
21333
+
21334
+ /* 还在用原生滚动条的视口留一条空道,滚动条出现与消失时不推动文字。
21335
+ 带 data-xh-scrollbar 的容器已经把原生条藏成零宽,这条空道对它没有布局作用,排除掉 */
21336
+ [data-scope='thread'][data-part='viewport']:not([data-xh-scrollbar]) {
20209
21337
  scrollbar-gutter: stable;
20210
21338
  }
20211
21339
 
@@ -20303,8 +21431,8 @@ input[data-scope='mention'][data-part='input'] {
20303
21431
  --xh-_time-field-control-h: var(--xh-control-h-md);
20304
21432
  --xh-_time-field-control-px: var(--xh-control-px-md);
20305
21433
  --xh-_time-field-gap: var(--xh-control-gap-md);
20306
- --xh-_time-field-font-size: var(--xh-text-body-size);
20307
- --xh-_time-field-label-font-size: var(--xh-text-label-size);
21434
+ --xh-_time-field-font-size: var(--xh-control-font-md);
21435
+ --xh-_time-field-label-font-size: var(--xh-control-font-md);
20308
21436
  /* 形态档只换这三个私有槽:底色与两档描边 */
20309
21437
  --xh-_time-field-control-bg: var(--xh-bg-canvas);
20310
21438
  --xh-_time-field-control-border: var(--xh-border-control);
@@ -20600,8 +21728,8 @@ input[data-scope='mention'][data-part='input'] {
20600
21728
  --xh-_time-picker-control-h: var(--xh-control-h-md);
20601
21729
  --xh-_time-picker-control-px: var(--xh-control-px-md);
20602
21730
  --xh-_time-picker-gap: var(--xh-control-gap-md);
20603
- --xh-_time-picker-font-size: var(--xh-text-body-size);
20604
- --xh-_time-picker-label-font-size: var(--xh-text-label-size);
21731
+ --xh-_time-picker-font-size: var(--xh-control-font-md);
21732
+ --xh-_time-picker-label-font-size: var(--xh-control-font-md);
20605
21733
  --xh-_time-picker-item-px: var(--xh-control-px-md);
20606
21734
 
20607
21735
  /* 形态档只换这三个私有槽:底色与两档描边 */
@@ -20917,7 +22045,7 @@ input[data-scope='mention'][data-part='input'] {
20917
22045
  display: flex;
20918
22046
  flex: none;
20919
22047
  flex-direction: column;
20920
- gap: var(--xh-time-picker-presets-gap, var(--xh-space-0_5));
22048
+ gap: var(--xh-time-picker-presets-gap, var(--xh-list-option-gap));
20921
22049
  max-block-size: var(--xh-time-picker-presets-h, var(--xh-viewport-h-sm));
20922
22050
  padding-inline: var(--xh-time-picker-presets-px, var(--xh-space-1));
20923
22051
  overflow-y: auto;
@@ -20932,7 +22060,7 @@ input[data-scope='mention'][data-part='input'] {
20932
22060
  [data-scope='time-picker'][data-part='preset'] {
20933
22061
  padding-block: var(--xh-time-picker-preset-py, var(--xh-space-1));
20934
22062
  padding-inline: var(--xh-time-picker-preset-px, var(--xh-space-3));
20935
- border-radius: var(--xh-shape-control);
22063
+ border-radius: var(--xh-time-picker-preset-radius, var(--xh-shape-control));
20936
22064
  font-size: var(--xh-text-secondary-size);
20937
22065
  line-height: var(--xh-leading-normal);
20938
22066
  white-space: nowrap;
@@ -20972,7 +22100,7 @@ input[data-scope='mention'][data-part='input'] {
20972
22100
  display: flex;
20973
22101
  flex: none;
20974
22102
  flex-direction: column;
20975
- gap: var(--xh-time-picker-column-gap, var(--xh-space-0_5));
22103
+ gap: var(--xh-time-picker-column-gap, var(--xh-list-option-gap));
20976
22104
  min-inline-size: var(--xh-time-picker-column-min-w, 3.5rem);
20977
22105
  /* 几列并排:定高而不是随内容收,否则时列与分列的可选值一多一少就错位 */
20978
22106
  block-size: var(--xh-time-picker-column-h, var(--xh-viewport-h-sm));
@@ -21007,7 +22135,7 @@ input[data-scope='mention'][data-part='input'] {
21007
22135
  flex: none;
21008
22136
  align-items: center;
21009
22137
  justify-content: center;
21010
- padding-block: var(--xh-time-picker-item-py, var(--xh-space-1_5));
22138
+ padding-block: var(--xh-time-picker-item-py, var(--xh-list-option-py-md));
21011
22139
  padding-inline: var(--xh-time-picker-item-px, var(--xh-_time-picker-item-px));
21012
22140
  border-radius: var(--xh-time-picker-item-radius, var(--xh-shape-control));
21013
22141
  color: var(--xh-time-picker-item-fg, var(--xh-fg-default));
@@ -21125,9 +22253,9 @@ input[data-scope='mention'][data-part='input'] {
21125
22253
 
21126
22254
  /* styles/toast.css */
21127
22255
  /*
21128
- * 九个位共用同一条进出场,位移不跟着落位走:要按位置分方向,就得从 toaster 的
21129
- * data-placement 反向选到卡片上,等于把一个组件的动效写进另一个组件的选择器里,
21130
- * 两边任意一侧改名都会静默失效。竖向一小段位移在九个位上都说得通。
22256
+ * 九个位共用同一条进出场,位移不跟着落位走:要按位置分方向就得从摞的
22257
+ * data-placement 反向选到条子上,落位一改名整条动效静默失效。
22258
+ * 竖向一小段位移在九个位上都说得通。
21131
22259
  */
21132
22260
  @keyframes xh-toast-in {
21133
22261
  from {
@@ -21162,45 +22290,95 @@ input[data-scope='mention'][data-part='input'] {
21162
22290
  --xh-toast-skin: 1;
21163
22291
  }
21164
22292
 
22293
+ /*
22294
+ * 一摞 = 一整面视口大小的定位面:贴边靠 padding,落位靠 justify/align 表达。
22295
+ * 不用四角 inset 逐个摆,是因为 column flex 的 align-items 走的是行内轴,
22296
+ * RTL 下 start/end 自动跟着翻;写死 inset-inline-start 的话居中那三个位
22297
+ * 还得再配一次 translate,方向一变就错。
22298
+ * 摞由全局服务渲染,没有对应的容器组件——一次操作的反馈落在哪儿是整个服务的口径。
22299
+ */
22300
+ [data-scope='toast'][data-part='group'] {
22301
+ position: fixed;
22302
+ inset-block: 0;
22303
+ inset-inline: 0;
22304
+ z-index: var(--xh-toast-layer, var(--xh-layer-toast));
22305
+ display: flex;
22306
+ flex-direction: column;
22307
+ /* 基线按默认落位 top 写,下面只覆盖跟它不同的那几个位 */
22308
+ justify-content: flex-start;
22309
+ align-items: center;
22310
+ padding-block: var(--xh-toast-inset, var(--xh-space-6));
22311
+ padding-inline: var(--xh-toast-inset, var(--xh-space-6));
22312
+ /* 摞内间距由服务写进内联 style,这里绝不重复写:
22313
+ 写了也会被内联盖掉,只会让人误以为间距归样式层管 */
22314
+ /* 整面铺开就等于罩住了整块视口。面本身不吃指针,只有条子吃(见下),
22315
+ 否则底下的页面就再也点不动了 */
22316
+ pointer-events: none;
22317
+ }
22318
+
22319
+ [data-scope='toast'][data-part='group'][hidden] {
22320
+ display: none;
22321
+ }
22322
+
22323
+ /* 块轴落位:^= 一次吃掉某一行的三个位(top / top-start / top-end) */
22324
+ [data-scope='toast'][data-part='group'][data-placement^='middle'] {
22325
+ justify-content: center;
22326
+ }
22327
+
22328
+ [data-scope='toast'][data-part='group'][data-placement^='bottom'] {
22329
+ justify-content: flex-end;
22330
+ }
22331
+
22332
+ /* 行内轴落位:不带后缀的 top / middle / bottom 用基线的居中 */
22333
+ [data-scope='toast'][data-part='group'][data-placement$='-start'] {
22334
+ align-items: flex-start;
22335
+ }
22336
+
22337
+ [data-scope='toast'][data-part='group'][data-placement$='-end'] {
22338
+ align-items: flex-end;
22339
+ }
22340
+
22341
+ /*
22342
+ * 一条轻提示是「一句话 + 一枚状态字形」,横排一行、贴着文字收缩。
22343
+ * 语气由淡底、描边与字形三者一起承载,正文留中性——正文也跟着兑成语气色的话,
22344
+ * 绿字压在绿底上,对比度是整条里最差的那一处。
22345
+ */
21165
22346
  [data-scope='toast'][data-part='root'] {
21166
- /* 作者塞进指示符槽的图标跟着字号走,与皮肤画的兜底字形同一把尺 */
21167
- --xh-icon-size: var(--xh-toast-icon-size, var(--xh-glyph-size-text));
22347
+ /* 状态字形按控件指示符那一档走,与 alert 的图标框同一把尺 */
22348
+ --xh-icon-size: var(--xh-toast-icon-size, var(--xh-control-indicator-size));
22349
+
22350
+ /* 底与描边取语气层派生好的槽,不在这儿自己再兑一遍:
22351
+ 兑法差一档,字形压上去的对比度就跟着差一档(alert 踩过这个坑) */
22352
+ --xh-_toast-tint: var(--xh-_tone-subtle);
22353
+ --xh-_toast-edge: var(--xh-_tone-border);
21168
22354
 
21169
22355
  display: flex;
21170
- flex-direction: column;
21171
- gap: var(--xh-toast-gap, var(--xh-space-1));
21172
- inline-size: var(--xh-toast-w, var(--xh-overlay-max-w));
22356
+ align-items: center;
22357
+ gap: var(--xh-toast-gap, var(--xh-control-gap-md));
22358
+ /* 收缩包裹:一句「已保存」撑成定宽方块,右边那片空白会让它读起来像一张公告卡 */
22359
+ inline-size: var(--xh-toast-w, auto);
21173
22360
  /* 摞是整面视口宽的定位面且带内边距,取 100% 就等于自动让出两侧留白,
21174
- 窄屏上不必再算一遍 viewport 减法 */
21175
- max-inline-size: 100%;
21176
- padding-block: var(--xh-toast-py, var(--xh-surface-py-sm));
22361
+ 窄屏上不必再算一遍 viewport 减法;再叠一道绝对上限,免得一条长文案铺成横幅 */
22362
+ max-inline-size: min(var(--xh-overlay-max-w-xl), 100%);
22363
+ /* 纵内衬取控件档而不是面档:面档(12px)叠上 21px 行盒与两道细边就是 47px 高,
22364
+ 那是卡片的体量;控件档(8px)落在 39px,与短消息该有的高度一致
22365
+ (带叉 42px、带操作钮 46px,那两档本就不是默认排版) */
22366
+ padding-block: var(--xh-toast-py, var(--xh-field-py));
21177
22367
  padding-inline: var(--xh-toast-px, var(--xh-surface-px-sm));
21178
- border: var(--xh-stroke-thin) solid var(--xh-toast-border, var(--xh-border-default));
21179
- /* 语气色条做成起始侧的粗边,而不是伪元素:圆角与阴影都不用再对第二遍。
21180
- 两条必须排在 border 简写之后,否则被简写重置回细边与常规描边色。
21181
- 颜色由 connect 从 type 派生的 data-tone 经语气层给出,作者写 --xh-toast-accent
21182
- 就能把某一条整体改色;两者都没有时退回原来的 info 蓝 */
21183
- border-inline-start-width: var(--xh-toast-accent-width, var(--xh-space-1));
21184
- border-inline-start-color: var(--xh-toast-accent, var(--xh-_tone-soft, var(--xh-color-info-500)));
22368
+ border: var(--xh-stroke-thin) solid var(--xh-toast-border, var(--xh-_toast-edge));
21185
22369
  border-radius: var(--xh-toast-radius, var(--xh-shape-surface));
21186
- background: var(--xh-toast-bg, var(--xh-bg-surface-raised));
22370
+ background: var(--xh-toast-bg, var(--xh-_toast-tint));
21187
22371
  color: var(--xh-toast-fg, var(--xh-fg-default));
21188
22372
  box-shadow: var(--xh-toast-shadow, var(--xh-elevation-sheet));
21189
- font-size: var(--xh-toast-font-size, var(--xh-text-secondary-size));
21190
- line-height: var(--xh-toast-leading, var(--xh-leading-normal));
21191
- /* 摞的定位面整面铺开且不吃指针,卡片必须自己吃回来:
22373
+ font-size: var(--xh-toast-font-size, var(--xh-text-body-size));
22374
+ line-height: var(--xh-toast-leading, var(--xh-text-body-leading));
22375
+ /* 摞的定位面整面铺开且不吃指针,条子必须自己吃回来:
21192
22376
  悬停按住计时、按钮可点、焦点进出,全指着这一条 */
21193
22377
  pointer-events: auto;
21194
22378
  }
21195
22379
 
21196
- /* loading 说的是「事情还没完」,不是好消息也不是坏消息,走中性灰。
21197
- 它不是语气:连接层给它派生的 neutral 档是 500,而这里要的是 fg-muted(600) */
21198
- [data-scope='toast'][data-part='root'][data-type='loading'] {
21199
- border-inline-start-color: var(--xh-toast-accent, var(--xh-fg-muted));
21200
- }
21201
-
21202
22380
  /* 退场窗口走完连接层给的是 hidden 属性,而上面声明了 display——
21203
- 漏掉这条,已经"卸载"的通知会一直杵在屏幕上,且再也没人来收 */
22381
+ 漏掉这条,已经"卸载"的提示会一直杵在屏幕上,且再也没人来收 */
21204
22382
  [data-scope='toast'][data-part='root'][hidden] {
21205
22383
  display: none;
21206
22384
  }
@@ -21211,41 +22389,39 @@ input[data-scope='mention'][data-part='input'] {
21211
22389
  }
21212
22390
 
21213
22391
  /* forwards 不能省:退场窗口(removeDelay 默认 200ms)比退场动画长,
21214
- 不定住末帧的话动画跑完会弹回全不透明,卡片在被收起前先闪一下 */
22392
+ 不定住末帧的话动画跑完会弹回全不透明,条子在被收起前先闪一下 */
21215
22393
  [data-scope='toast'][data-part='root'][data-state='dismissing'] {
21216
22394
  animation: xh-toast-out var(--xh-motion-duration-exit) var(--xh-motion-ease-exit) forwards;
21217
22395
  }
21218
22396
 
21219
22397
  [data-scope='toast'][data-part='title'] {
21220
- /* 作者可能把它写成 h2/p,外边距得先归零,否则卡片内的行距对不上 */
22398
+ /* 作者可能把它写成 h2/p,外边距得先归零,否则条子内的行距对不上 */
21221
22399
  margin: 0;
22400
+ /* 吃掉剩余宽度,把操作钮与叉推到行尾;min-inline-size 让它在撞上宽度上限时能换行,
22401
+ flex 项的 min-width 默认是 auto,不归零的话长文案会把条子顶出上限 */
22402
+ flex: 1 1 auto;
22403
+ min-inline-size: 0;
21222
22404
  color: var(--xh-toast-title-fg, var(--xh-fg-default));
21223
- font-size: var(--xh-toast-title-font-size, var(--xh-text-label-size));
21224
- font-weight: var(--xh-toast-title-font-weight, var(--xh-font-weight-semibold));
21225
- line-height: var(--xh-toast-title-leading, var(--xh-leading-tight));
21226
- }
21227
-
21228
- [data-scope='toast'][data-part='description'] {
21229
- margin: 0;
21230
- color: var(--xh-toast-description-fg, var(--xh-fg-muted));
21231
- font-size: var(--xh-toast-description-font-size, var(--xh-text-secondary-size));
22405
+ /* 与条子同字号同行高、不加粗:加粗是"这是标题、下面还有正文"的信号,
22406
+ 而轻提示没有正文——那一层是 notification 的 */
22407
+ font-size: var(--xh-toast-title-font-size, var(--xh-text-body-size));
22408
+ font-weight: var(--xh-toast-title-font-weight, var(--xh-text-body-weight));
22409
+ line-height: var(--xh-toast-title-leading, var(--xh-text-body-leading));
21232
22410
  }
21233
22411
 
21234
- /* 没给文案的那一个仍然要留在 DOM 里(aria-labelledby / aria-describedby 指着它),
21235
- 但空盒子会照吃一份 gap,卡片看着就多出一截莫名的留白 */
21236
- [data-scope='toast'][data-part='title']:empty,
21237
- [data-scope='toast'][data-part='description']:empty {
22412
+ /* 没给文案时仍然要留在 DOM 里(aria-labelledby 指着它),
22413
+ 但空盒子会照吃一份 gap,条子看着就多出一截莫名的留白 */
22414
+ [data-scope='toast'][data-part='title']:empty {
21238
22415
  display: none;
21239
22416
  }
21240
22417
 
21241
- [data-scope='toast'][data-part='title'][hidden],
21242
- [data-scope='toast'][data-part='description'][hidden] {
22418
+ [data-scope='toast'][data-part='title'][hidden] {
21243
22419
  display: none;
21244
22420
  }
21245
22421
 
21246
22422
  [data-scope='toast'][data-part='action-trigger'] {
21247
- /* 作为卡片直接子元素时不跟着拉满整行;被作者包进一行里时它只影响交叉轴,无副作用 */
21248
- align-self: flex-start;
22423
+ /* 条子是单行 flex,按钮不参与伸缩:文案长了该换行的是文字,不是把按钮压扁 */
22424
+ flex: none;
21249
22425
  display: inline-flex;
21250
22426
  align-items: center;
21251
22427
  justify-content: center;
@@ -21255,7 +22431,7 @@ input[data-scope='mention'][data-part='input'] {
21255
22431
  border-radius: var(--xh-toast-action-radius, var(--xh-shape-control));
21256
22432
  background: var(--xh-toast-action-bg, var(--xh-bg-subtle));
21257
22433
  color: var(--xh-toast-action-fg, var(--xh-fg-default));
21258
- /* 按钮不继承字族字号,不接回来的话卡片里会突然冒出一段系统 UI 字体 */
22434
+ /* 按钮不继承字族字号,不接回来的话条子里会突然冒出一段系统 UI 字体 */
21259
22435
  font: inherit;
21260
22436
  font-weight: var(--xh-toast-action-font-weight, var(--xh-font-weight-medium));
21261
22437
  line-height: var(--xh-leading-none);
@@ -21280,14 +22456,16 @@ input[data-scope='mention'][data-part='input'] {
21280
22456
  }
21281
22457
 
21282
22458
  [data-scope='toast'][data-part='close-trigger'] {
21283
- align-self: flex-start;
21284
- /* 和操作按钮同处一行时把叉推到行尾;单独作为卡片子元素时则贴到行内末侧 */
22459
+ flex: none;
22460
+ /* 推到行内末侧;和操作按钮同处一行时排在它后面 */
21285
22461
  margin-inline-start: auto;
21286
22462
  display: inline-flex;
21287
22463
  align-items: center;
21288
22464
  justify-content: center;
21289
- block-size: var(--xh-toast-close-size, var(--xh-control-h-sm));
21290
- inline-size: var(--xh-toast-close-size, var(--xh-control-h-sm));
22465
+ /* 行级动作钮那一档(24px),不是浮层角落钮的 28px:
22466
+ 后者比一行正文的行盒还高,单它就把整条顶高一截 */
22467
+ block-size: var(--xh-toast-close-size, var(--xh-control-action-size));
22468
+ inline-size: var(--xh-toast-close-size, var(--xh-control-action-size));
21291
22469
  border: 0;
21292
22470
  border-radius: var(--xh-toast-close-radius, var(--xh-shape-control));
21293
22471
  background: transparent;
@@ -21341,80 +22519,6 @@ input[data-scope='mention'][data-part='input'] {
21341
22519
  mask: var(--xh-glyph-mark-close) center / contain no-repeat;
21342
22520
  }
21343
22521
 
21344
- /* styles/toaster.css */
21345
- /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
21346
- [data-scope='toaster'] {
21347
- --xh-toaster-skin: 1;
21348
- }
21349
-
21350
- /* 地标容器不占布局:通知落在哪儿由九个 group 各自的 fixed 说了算,
21351
- root 只是给读屏一个可跳转的落点。它若留下一个块盒,写在页面中段的用法
21352
- (按钮和队列摆在一起)就会凭空多出一行空白。
21353
- 另一件必须提防的事:fixed 认的是视口,祖先上一旦出现
21354
- transform / filter / backdrop-filter / contain,包含块就被抢走,整摞通知立刻贴错位置——
21355
- 所以这里连 position 都不碰,也别往覆盖钩子里加这几个属性。 */
21356
- [data-scope='toaster'][data-part='root'] {
21357
- display: contents;
21358
- }
21359
-
21360
- /* 只要声明过 display,就盖掉了 UA 的 [hidden]{display:none},收起态得自己补回来 */
21361
- [data-scope='toaster'][data-part='root'][hidden] {
21362
- display: none;
21363
- }
21364
-
21365
- /*
21366
- * 一摞 = 一整面视口大小的定位面:贴边靠 padding,九个位靠 justify/align 表达。
21367
- * 不用四角 inset 逐个摆,是因为 column flex 的 align-items 走的是行内轴,
21368
- * RTL 下 start/end 自动跟着翻;写死 inset-inline-start 的话居中那三个位
21369
- * 还得再配一次 translate,方向一变就错。
21370
- * 条目次序按队列原样(旧的在前):贴底那三个位于是新的离屏幕边最近,符合直觉。
21371
- */
21372
- [data-scope='toaster'][data-part='group'] {
21373
- position: fixed;
21374
- inset-block: 0;
21375
- inset-inline: 0;
21376
- z-index: var(--xh-toaster-layer, var(--xh-layer-toast));
21377
- display: flex;
21378
- flex-direction: column;
21379
- /* 基线按默认落位 bottom-end 写,下面只覆盖跟它不同的那几个位 */
21380
- justify-content: flex-end;
21381
- align-items: center;
21382
- padding-block: var(--xh-toaster-inset, var(--xh-space-6));
21383
- padding-inline: var(--xh-toaster-inset, var(--xh-space-6));
21384
- /* 摞内间距由连接层写进内联 style(两个适配器共用同一份),这里绝不重复写:
21385
- 写了也会被内联盖掉,只会让人误以为间距归样式层管 */
21386
- /* 整面铺开就等于罩住了整块视口。面本身不吃指针,只有卡片吃(见 toast.css),
21387
- 否则九个位一叠,底下的页面就再也点不动了 */
21388
- pointer-events: none;
21389
- }
21390
-
21391
- [data-scope='toaster'][data-part='group'][hidden] {
21392
- display: none;
21393
- }
21394
-
21395
- /* 空摞直接撤掉:九个位同时挂九张全屏定位面,白白多九个合成层 */
21396
- [data-scope='toaster'][data-part='group'][data-empty] {
21397
- display: none;
21398
- }
21399
-
21400
- /* 块轴落位:^= 一次吃掉某一行的三个位(top / top-start / top-end) */
21401
- [data-scope='toaster'][data-part='group'][data-placement^='top'] {
21402
- justify-content: flex-start;
21403
- }
21404
-
21405
- [data-scope='toaster'][data-part='group'][data-placement^='middle'] {
21406
- justify-content: center;
21407
- }
21408
-
21409
- /* 行内轴落位:不带后缀的 top / middle / bottom 用基线的居中 */
21410
- [data-scope='toaster'][data-part='group'][data-placement$='-start'] {
21411
- align-items: flex-start;
21412
- }
21413
-
21414
- [data-scope='toaster'][data-part='group'][data-placement$='-end'] {
21415
- align-items: flex-end;
21416
- }
21417
-
21418
22522
  /* styles/toggle.css */
21419
22523
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
21420
22524
  [data-scope='toggle'] {
@@ -21523,6 +22627,12 @@ input[data-scope='mention'][data-part='input'] {
21523
22627
  font-size: var(--xh-toggle-font-size, var(--xh-control-font-lg));
21524
22628
  }
21525
22629
 
22630
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
22631
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
22632
+ [data-scope='toggle'][data-part='root'][hidden] {
22633
+ display: none;
22634
+ }
22635
+
21526
22636
  /* styles/toggle-group.css */
21527
22637
  /* 皮肤在场的标记:开发模式下按 scope 探一次,取不到就说明这份皮肤没被引入。 */
21528
22638
  [data-scope='toggle-group'] {
@@ -21532,10 +22642,36 @@ input[data-scope='mention'][data-part='input'] {
21532
22642
  /* 分段控件:段与段之间不留缝,靠共边连成一体,所以 root 不设 gap。
21533
22643
  排布只能读 data-orientation——aria-orientation 在多选模式下连接层根本不输出(role=group 不收) */
21534
22644
  [data-scope='toggle-group'][data-part='root'] {
22645
+ /* 组件内那几档层号只在自己人之间排序:建一个层叠上下文把它们关起来,
22646
+ 既不让页面上的层号插进来,也不让它们漏出去压住别人 */
22647
+ isolation: isolate;
22648
+
22649
+ /* 段的度量与字号走私有槽中转,与同族的分段控件一处对一处 */
22650
+ --xh-_toggle-group-h: var(--xh-control-h-md);
22651
+ --xh-_toggle-group-px: var(--xh-control-px-md);
22652
+ --xh-_toggle-group-gap: var(--xh-control-gap-md);
22653
+ --xh-_toggle-group-font-size: var(--xh-control-font-md);
22654
+
21535
22655
  display: inline-flex;
21536
22656
  align-items: stretch;
21537
22657
  }
21538
22658
 
22659
+ /* —— 尺寸 —— */
22660
+ /* 缺省档写在上面的基础规则里 */
22661
+ [data-scope='toggle-group'][data-part='root'][data-size='sm'] {
22662
+ --xh-_toggle-group-h: var(--xh-control-h-sm);
22663
+ --xh-_toggle-group-px: var(--xh-control-px-sm);
22664
+ --xh-_toggle-group-gap: var(--xh-control-gap-sm);
22665
+ --xh-_toggle-group-font-size: var(--xh-control-font-sm);
22666
+ }
22667
+
22668
+ [data-scope='toggle-group'][data-part='root'][data-size='lg'] {
22669
+ --xh-_toggle-group-h: var(--xh-control-h-lg);
22670
+ --xh-_toggle-group-px: var(--xh-control-px-lg);
22671
+ --xh-_toggle-group-gap: var(--xh-control-gap-lg);
22672
+ --xh-_toggle-group-font-size: var(--xh-control-font-lg);
22673
+ }
22674
+
21539
22675
  [data-scope='toggle-group'][data-part='root'][data-orientation='horizontal'] {
21540
22676
  flex-direction: row;
21541
22677
  }
@@ -21570,15 +22706,15 @@ input[data-scope='mention'][data-part='input'] {
21570
22706
  display: inline-flex;
21571
22707
  align-items: center;
21572
22708
  justify-content: center;
21573
- gap: var(--xh-toggle-group-item-gap, var(--xh-control-gap-md));
21574
- block-size: var(--xh-toggle-group-item-h, var(--xh-control-h-md));
21575
- padding-inline: var(--xh-toggle-group-item-px, var(--xh-control-px-md));
22709
+ gap: var(--xh-toggle-group-item-gap, var(--xh-_toggle-group-gap));
22710
+ block-size: var(--xh-toggle-group-item-h, var(--xh-_toggle-group-h));
22711
+ padding-inline: var(--xh-toggle-group-item-px, var(--xh-_toggle-group-px));
21576
22712
  border: var(--xh-stroke-thin) solid var(--xh-_border);
21577
22713
  /* 中间段一律直角,圆角只由首末两端补回来 */
21578
22714
  border-radius: 0;
21579
22715
  background: var(--xh-_bg);
21580
22716
  color: var(--xh-_fg);
21581
- font-size: var(--xh-toggle-group-item-font-size, var(--xh-text-label-size));
22717
+ font-size: var(--xh-toggle-group-item-font-size, var(--xh-_toggle-group-font-size));
21582
22718
  font-weight: var(--xh-toggle-group-item-font-weight, var(--xh-text-label-weight));
21583
22719
  line-height: var(--xh-leading-none);
21584
22720
  white-space: nowrap;
@@ -21876,7 +23012,7 @@ input[data-scope='mention'][data-part='input'] {
21876
23012
  箭头是它的后代,语气槽一并继承 */
21877
23013
  --xh-_tooltip-py: var(--xh-space-1);
21878
23014
  --xh-_tooltip-px: var(--xh-space-2);
21879
- --xh-_tooltip-font-size: var(--xh-text-secondary-size);
23015
+ --xh-_tooltip-font-size: var(--xh-control-caption-md);
21880
23016
 
21881
23017
  /* 与 positioner 相反:浮层本体要能接指针,指针停在提示上就不该收起
21882
23018
  (长文案需要停留细看)。positioner 仍是 none,空白区域照样点得穿。 */
@@ -21935,6 +23071,12 @@ input[data-scope='mention'][data-part='input'] {
21935
23071
  background: var(--xh-tooltip-bg, var(--xh-_tone, var(--xh-fg-default)));
21936
23072
  }
21937
23073
 
23074
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
23075
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
23076
+ [data-scope='tooltip'][data-part='trigger'][hidden] {
23077
+ display: none;
23078
+ }
23079
+
21938
23080
  /* styles/tour.css */
21939
23081
  /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
21940
23082
  动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
@@ -22022,6 +23164,12 @@ input[data-scope='mention'][data-part='input'] {
22022
23164
  color: var(--xh-tour-fg, var(--xh-fg-default));
22023
23165
  }
22024
23166
 
23167
+ /* 浮层被搬到 portal 落点,继承不到 root 上的槽:这把尺在被搬走的那一侧再声明一次,
23168
+ 关闭钮与条目里作者塞的图标才和皮肤画的兜底字形一样大 */
23169
+ [data-scope='tour'][data-part='content'] {
23170
+ --xh-icon-size: var(--xh-tour-icon-size, var(--xh-glyph-size-text));
23171
+ }
23172
+
22025
23173
  /* 遮罩:整页压暗,把注意力逼到高亮框那一块上 */
22026
23174
  [data-scope='tour'][data-part='backdrop'] {
22027
23175
  position: fixed;
@@ -22100,7 +23248,7 @@ input[data-scope='mention'][data-part='input'] {
22100
23248
  display: flex;
22101
23249
  align-items: center;
22102
23250
  justify-content: center;
22103
- padding: var(--xh-space-4);
23251
+ padding: var(--xh-tour-positioner-padding, var(--xh-space-4));
22104
23252
  }
22105
23253
 
22106
23254
  /* 必须排在 data-position='center' 之后:两条选择器的特指度相同(都是三个属性),
@@ -22181,9 +23329,9 @@ input[data-scope='mention'][data-part='input'] {
22181
23329
  align-items: center;
22182
23330
  justify-content: center;
22183
23331
  block-size: var(--xh-control-h-sm);
22184
- padding-inline: var(--xh-control-px-md);
23332
+ padding-inline: var(--xh-tour-skip-trigger-px, var(--xh-control-px-md));
22185
23333
  border: var(--xh-stroke-thin) solid transparent;
22186
- border-radius: var(--xh-shape-control);
23334
+ border-radius: var(--xh-tour-action-radius, var(--xh-shape-control));
22187
23335
  font-size: var(--xh-text-secondary-size);
22188
23336
  cursor: pointer;
22189
23337
  }
@@ -22490,6 +23638,7 @@ input[data-scope='mention'][data-part='input'] {
22490
23638
  display: flex;
22491
23639
  flex: 1 1 auto;
22492
23640
  flex-direction: column;
23641
+ gap: var(--xh-transfer-list-gap, var(--xh-list-option-gap));
22493
23642
  block-size: var(--xh-transfer-list-h, var(--xh-viewport-h-md));
22494
23643
  padding-block: var(--xh-transfer-list-py, var(--xh-space-1));
22495
23644
  padding-inline: var(--xh-transfer-list-px, var(--xh-space-1));
@@ -22582,8 +23731,7 @@ input[data-scope='mention'][data-part='input'] {
22582
23731
  }
22583
23732
 
22584
23733
  /* 没写内容就由皮肤画勾;作者往格子里塞了自己的图形,这条规则即不命中。
22585
- 底下两处(全选格的两态)不带这条守卫:那里的 ::before 是方框本身,
22586
- 而触发器里装的是全选那行文字,:empty 恒不命中,加了勾号会整个消失 */
23734
+ 底下两处(全选格的两态)不带这条守卫:触发器里装的是全选那行文字,:empty 恒不命中 */
22587
23735
  [data-scope='transfer'][data-part='item-checkbox'][data-state='checked']:empty::before {
22588
23736
  content: '';
22589
23737
  display: inline-block;
@@ -22596,25 +23744,47 @@ input[data-scope='mention'][data-part='input'] {
22596
23744
  }
22597
23745
 
22598
23746
  /* 全选格的三态:all 打勾、some 打横杠、none 留空。
22599
- some 就是读屏听到的 aria-checked=mixed,两者同源,样式只认 data-state */
22600
- [data-scope='transfer'][data-part='select-all-trigger'][data-state='checked']::before {
23747
+ some 就是读屏听到的 aria-checked=mixed,两者同源,样式只认 data-state
23748
+
23749
+ 字形走 ::after 而不是画方框的那颗 ::before:mask 会把所在元素的描边与底色一并裁成
23750
+ 字形的轮廓,写在 ::before 上就等于把方框本身裁没了,只剩一枚白勾。条目那一侧是
23751
+ 真实节点当方框、它的 ::before 当字形的两层结构,这里没有第二个节点,只能用
23752
+ 第二个伪元素补上那一层。
23753
+ 方框是行首那颗 ::before、宽度即勾选格尺寸,所以字形按「盒与字形的宽度差之半」
23754
+ 内推即落在圆心;纵向靠 inset-block: 0 + margin-block: auto 居中。
23755
+ font-size 与 ::before 同值,--xh-icon-size 的 1em 兜底才和条目那侧量得一样大 */
23756
+ [data-scope='transfer'][data-part='select-all-trigger'][data-state='checked']::after {
22601
23757
  content: '';
22602
- display: inline-block;
23758
+ position: absolute;
23759
+ inset-block: 0;
23760
+ inset-inline-start: 0;
23761
+ margin-block: auto;
23762
+ margin-inline-start: calc(
23763
+ (var(--xh-transfer-checkbox-size, var(--xh-control-indicator-size)) - var(--xh-icon-size, var(--xh-glyph-size-text))) /
23764
+ 2
23765
+ );
22603
23766
  inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
22604
23767
  block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
22605
- vertical-align: var(--xh-glyph-baseline-shift);
22606
- background-color: currentColor;
23768
+ background-color: var(--xh-transfer-checkbox-fg, var(--xh-fg-on-brand));
23769
+ font-size: var(--xh-transfer-checkbox-font-size, calc(var(--xh-control-indicator-size) * 0.75));
22607
23770
  -webkit-mask: var(--xh-glyph-mark-check) center / contain no-repeat;
22608
23771
  mask: var(--xh-glyph-mark-check) center / contain no-repeat;
22609
23772
  }
22610
23773
 
22611
- [data-scope='transfer'][data-part='select-all-trigger'][data-state='indeterminate']::before {
23774
+ [data-scope='transfer'][data-part='select-all-trigger'][data-state='indeterminate']::after {
22612
23775
  content: '';
22613
- display: inline-block;
23776
+ position: absolute;
23777
+ inset-block: 0;
23778
+ inset-inline-start: 0;
23779
+ margin-block: auto;
23780
+ margin-inline-start: calc(
23781
+ (var(--xh-transfer-checkbox-size, var(--xh-control-indicator-size)) - var(--xh-icon-size, var(--xh-glyph-size-text))) /
23782
+ 2
23783
+ );
22614
23784
  inline-size: var(--xh-icon-size, var(--xh-glyph-size-text));
22615
23785
  block-size: var(--xh-icon-size, var(--xh-glyph-size-text));
22616
- vertical-align: var(--xh-glyph-baseline-shift);
22617
- background-color: currentColor;
23786
+ background-color: var(--xh-transfer-checkbox-fg, var(--xh-fg-on-brand));
23787
+ font-size: var(--xh-transfer-checkbox-font-size, calc(var(--xh-control-indicator-size) * 0.75));
22618
23788
  -webkit-mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
22619
23789
  mask: var(--xh-glyph-mark-minus) center / contain no-repeat;
22620
23790
  }
@@ -22626,7 +23796,9 @@ input[data-scope='mention'][data-part='input'] {
22626
23796
 
22627
23797
  /* 全选格是原生按钮(三态经 aria-checked 上报,激活由平台负责),
22628
23798
  禁用因此写 :disabled,不写 data-disabled */
23799
+ /* position 是给叠在方框上的那颗字形 ::after 当定位基准 */
22629
23800
  [data-scope='transfer'][data-part='select-all-trigger'] {
23801
+ position: relative;
22630
23802
  display: inline-flex;
22631
23803
  flex: none;
22632
23804
  gap: var(--xh-transfer-select-all-gap, var(--xh-control-gap-sm));
@@ -22642,9 +23814,11 @@ input[data-scope='mention'][data-part='input'] {
22642
23814
  cursor: pointer;
22643
23815
  }
22644
23816
 
23817
+ /* 往内收,与搜索框、条目同一口径:全选格长在面板里,面板收 overflow,
23818
+ 环画在外沿会被裁掉 */
22645
23819
  [data-scope='transfer'][data-part='select-all-trigger']:focus-visible {
22646
23820
  outline: var(--xh-ring-width) solid var(--xh-ring-focus);
22647
- outline-offset: var(--xh-ring-offset);
23821
+ outline-offset: calc(-1 * var(--xh-ring-width));
22648
23822
  }
22649
23823
 
22650
23824
  [data-scope='transfer'][data-part='select-all-trigger']:disabled {
@@ -22769,6 +23943,7 @@ input[data-scope='mention'][data-part='input'] {
22769
23943
  [data-scope='tree'][data-part='tree'] {
22770
23944
  display: flex;
22771
23945
  flex-direction: column;
23946
+ gap: var(--xh-tree-tree-gap, var(--xh-list-option-gap));
22772
23947
  max-block-size: var(--xh-tree-max-h, var(--xh-viewport-h-lg));
22773
23948
  padding-block: var(--xh-tree-py, var(--xh-space-1));
22774
23949
  padding-inline: var(--xh-tree-px, var(--xh-space-1));
@@ -22790,8 +23965,15 @@ input[data-scope='mention'][data-part='input'] {
22790
23965
  outline: none;
22791
23966
  }
22792
23967
 
22793
- /* 分支只是"这一行 + 它的子层"的外壳,不自带行距与内边距:
22794
- 真正长成一行的是 branch-control,子层缩进归 branch-content */
23968
+ /* 分支只是"这一行 + 它的子层"的外壳,不自带内边距:
23969
+ 真正长成一行的是 branch-control,子层缩进归 branch-content
23970
+ 行距由这里出:分支自己那一行与它展开的子层之间,同样按条目间距断开 */
23971
+ [data-scope='tree'][data-part='branch'] {
23972
+ display: flex;
23973
+ flex-direction: column;
23974
+ gap: var(--xh-tree-branch-gap, var(--xh-list-option-gap));
23975
+ }
23976
+
22795
23977
  [data-scope='tree'][data-part='branch'][hidden] {
22796
23978
  display: none;
22797
23979
  }
@@ -22814,7 +23996,7 @@ input[data-scope='mention'][data-part='input'] {
22814
23996
  display: flex;
22815
23997
  align-items: center;
22816
23998
  gap: var(--xh-tree-row-gap, var(--xh-control-gap-md));
22817
- padding-block: var(--xh-tree-row-py, var(--xh-space-1_5));
23999
+ padding-block: var(--xh-tree-row-py, var(--xh-list-option-py-md));
22818
24000
  padding-inline: var(--xh-tree-row-px, var(--xh-control-px-md));
22819
24001
  border-radius: var(--xh-tree-row-radius, var(--xh-shape-control));
22820
24002
  color: var(--xh-tree-row-fg, var(--xh-fg-default));
@@ -22829,6 +24011,19 @@ input[data-scope='mention'][data-part='input'] {
22829
24011
  color var(--xh-motion-duration-micro) var(--xh-motion-ease-enter);
22830
24012
  }
22831
24013
 
24014
+ /* 分支行的首格是展开箭头,叶子行没有这一格。作者摆了 item-indicator 时由它顶着,
24015
+ 没摆(如勾选档首位直接是 item-checkbox)就由行盒自己补出来,
24016
+ 否则叶子会比同级分支往行首缩一格,层级关系读不出来 */
24017
+ [data-orientation='vertical'] > [data-scope='tree'][data-part='item']:not(
24018
+ :has(> [data-scope='tree'][data-part='item-indicator'])
24019
+ ) {
24020
+ padding-inline-start: calc(
24021
+ var(--xh-tree-row-px, var(--xh-control-px-md)) +
24022
+ var(--xh-tree-indicator-size, var(--xh-control-indicator-size)) +
24023
+ var(--xh-tree-row-gap, var(--xh-control-gap-md))
24024
+ );
24025
+ }
24026
+
22832
24027
  [data-scope='tree'][data-part='item'][hidden],
22833
24028
  [data-scope='tree'][data-part='branch-control'][hidden] {
22834
24029
  display: none;
@@ -22937,7 +24132,7 @@ input[data-scope='mention'][data-part='input'] {
22937
24132
  align-items: center;
22938
24133
  justify-content: center;
22939
24134
  inline-size: var(--xh-tree-indicator-size, var(--xh-control-indicator-size));
22940
- color: var(--xh-tree-indicator-fg, var(--xh-bg-brand));
24135
+ color: var(--xh-tree-indicator-fg, var(--xh-fg-brand));
22941
24136
  visibility: hidden;
22942
24137
  }
22943
24138
 
@@ -22998,9 +24193,24 @@ input[data-scope='mention'][data-part='input'] {
22998
24193
  [data-scope='tree'][data-part='branch-content'] {
22999
24194
  display: flex;
23000
24195
  flex-direction: column;
24196
+ gap: var(--xh-tree-branch-content-gap, var(--xh-list-option-gap));
23001
24197
  padding-inline-start: var(--xh-tree-indent, var(--xh-space-4));
23002
24198
  }
23003
24199
 
24200
+ /* 末端那一层横排:子节点并排铺开、必要时折行。缩进照旧由子层容器自己顶——
24201
+ 那是这一层相对上一层的位置,与层内怎么排无关 */
24202
+ [data-scope='tree'][data-part='branch-content'][data-orientation='horizontal'] {
24203
+ flex-flow: row wrap;
24204
+ align-items: center;
24205
+ column-gap: var(--xh-tree-leaf-row-gap, var(--xh-space-3));
24206
+ row-gap: var(--xh-tree-branch-content-gap, var(--xh-list-option-gap));
24207
+ }
24208
+
24209
+ /* 横排的一层里节点并排,行盒不能再各自吃满一行 */
24210
+ [data-orientation='horizontal'] > [data-scope='tree'][data-part='item'] {
24211
+ flex: none;
24212
+ }
24213
+
23004
24214
  /* 收起态的唯一开关:display 会盖掉 hidden 属性的 UA 规则,漏了这条整棵子树就收不起来 */
23005
24215
  [data-scope='tree'][data-part='branch-content'][hidden] {
23006
24216
  display: none;
@@ -23030,6 +24240,12 @@ input[data-scope='mention'][data-part='input'] {
23030
24240
  mask: var(--xh-glyph-mark-check) center / contain no-repeat;
23031
24241
  }
23032
24242
 
24243
+ /* 声明过任何 display 就盖掉了 UA 的 [hidden]{display:none},收起态得自己还回去。
24244
+ 写在文件末尾:兜底必须排在该部件所有 display 声明之后 */
24245
+ [data-scope='tree'][data-part='branch-checkbox'][hidden] {
24246
+ display: none;
24247
+ }
24248
+
23033
24249
  /* styles/tree-select.css */
23034
24250
  /* 动画名的查找只认「文档里有没有这个名字」:引用别处文件里的名字,那份文件不一定在场,
23035
24251
  动画会静默地整个不跑。每份皮肤都能单独引入,所以它用到的关键帧都写在自己身上。 */
@@ -23067,6 +24283,9 @@ input[data-scope='mention'][data-part='input'] {
23067
24283
  引擎没算(尚未落位 / 无引擎)时不额外限高 */
23068
24284
  --xh-_tree-select-available-h: 100vh;
23069
24285
 
24286
+ /* 树的自绘条浮在内容之上:轨道不上底色,实色轨道会沿内容边缘糊出一条灰带 */
24287
+ --xh-scrollbar-track-bg: transparent;
24288
+
23070
24289
  position: fixed;
23071
24290
  z-index: var(--xh-tree-select-layer, var(--xh-layer-popover));
23072
24291
  /* 空壳不吃指针,交互只发生在 content 里 */
@@ -23086,9 +24305,11 @@ input[data-scope='mention'][data-part='input'] {
23086
24305
  /* 尺寸档只换这几个私有槽,盒与树里的行都从这两处继承它们,换档不必给每个部件各写一条选择器 */
23087
24306
  --xh-_tree-select-h: var(--xh-control-h-md);
23088
24307
  --xh-_tree-select-px: var(--xh-control-px-md);
24308
+ --xh-_tree-select-row-py: var(--xh-list-option-py-md);
24309
+ --xh-_tree-select-row-px: var(--xh-control-px-md);
23089
24310
  --xh-_tree-select-gap: var(--xh-control-gap-md);
23090
- --xh-_tree-select-font-size: var(--xh-text-body-size);
23091
- --xh-_tree-select-label-font-size: var(--xh-text-label-size);
24311
+ --xh-_tree-select-font-size: var(--xh-control-font-md);
24312
+ --xh-_tree-select-label-font-size: var(--xh-control-font-md);
23092
24313
 
23093
24314
  /* 形态档只换触发框的描边与底色这三个槽,浮层与树不跟着变:
23094
24315
  变的是「这是个输入位」的表达方式,不是弹出内容的表达方式 */
@@ -23144,6 +24365,8 @@ input[data-scope='mention'][data-part='input'] {
23144
24365
  --xh-icon-size: var(--xh-tree-select-icon-size, var(--xh-glyph-size-sm));
23145
24366
  --xh-_tree-select-h: var(--xh-control-h-sm);
23146
24367
  --xh-_tree-select-px: var(--xh-control-px-sm);
24368
+ --xh-_tree-select-row-py: var(--xh-list-option-py-sm);
24369
+ --xh-_tree-select-row-px: var(--xh-control-px-sm);
23147
24370
  --xh-_tree-select-gap: var(--xh-control-gap-sm);
23148
24371
  --xh-_tree-select-font-size: var(--xh-control-font-sm);
23149
24372
  --xh-_tree-select-label-font-size: var(--xh-control-font-sm);
@@ -23153,6 +24376,8 @@ input[data-scope='mention'][data-part='input'] {
23153
24376
  --xh-icon-size: var(--xh-tree-select-icon-size, var(--xh-glyph-size-lg));
23154
24377
  --xh-_tree-select-h: var(--xh-control-h-lg);
23155
24378
  --xh-_tree-select-px: var(--xh-control-px-lg);
24379
+ --xh-_tree-select-row-py: var(--xh-list-option-py-lg);
24380
+ --xh-_tree-select-row-px: var(--xh-control-px-lg);
23156
24381
  --xh-_tree-select-gap: var(--xh-control-gap-lg);
23157
24382
  --xh-_tree-select-font-size: var(--xh-control-font-lg);
23158
24383
  --xh-_tree-select-label-font-size: var(--xh-control-font-lg);
@@ -23382,6 +24607,7 @@ input[data-scope='mention'][data-part='input'] {
23382
24607
  [data-scope='tree-select'][data-part='tree'] {
23383
24608
  display: flex;
23384
24609
  flex-direction: column;
24610
+ gap: var(--xh-tree-select-tree-gap, var(--xh-list-option-gap));
23385
24611
  }
23386
24612
 
23387
24613
  [data-scope='tree-select'][data-part='tree'][hidden] {
@@ -23399,6 +24625,20 @@ input[data-scope='mention'][data-part='input'] {
23399
24625
  outline: none;
23400
24626
  }
23401
24627
 
24628
+ /* 分支是"这一行 + 它的子层"的外壳,不自带内边距:真正长成一行的是 branch-control,
24629
+ 子层缩进归 branch-content。行距由这里出:分支自己那一行与它展开的子层之间,
24630
+ 同样按条目间距断开 */
24631
+ [data-scope='tree-select'][data-part='branch'] {
24632
+ display: flex;
24633
+ flex-direction: column;
24634
+ gap: var(--xh-tree-select-branch-gap, var(--xh-list-option-gap));
24635
+ }
24636
+
24637
+ /* display 盖掉了 UA 的 [hidden]{display:none},收起时要显式让位 */
24638
+ [data-scope='tree-select'][data-part='branch'][hidden] {
24639
+ display: none;
24640
+ }
24641
+
23402
24642
  /* 焦点落在 branch 上(它才是 treeitem),但环画在它自己那一行上:
23403
24643
  整棵子树套一圈描边会把展开的层级全框进去 */
23404
24644
  [data-scope='tree-select'][data-part='branch']:focus-visible {
@@ -23417,8 +24657,8 @@ input[data-scope='mention'][data-part='input'] {
23417
24657
  display: flex;
23418
24658
  align-items: center;
23419
24659
  gap: var(--xh-tree-select-row-gap, var(--xh-_tree-select-gap));
23420
- padding-block: var(--xh-tree-select-row-py, var(--xh-space-1_5));
23421
- padding-inline: var(--xh-tree-select-row-px, var(--xh-control-px-md));
24660
+ padding-block: var(--xh-tree-select-row-py, var(--xh-_tree-select-row-py));
24661
+ padding-inline: var(--xh-tree-select-row-px, var(--xh-_tree-select-row-px));
23422
24662
  border-radius: var(--xh-tree-select-row-radius, var(--xh-shape-control));
23423
24663
  color: var(--xh-tree-select-row-fg, var(--xh-fg-default));
23424
24664
  font-size: var(--xh-tree-select-row-font-size, var(--xh-_tree-select-font-size));
@@ -23482,7 +24722,7 @@ input[data-scope='mention'][data-part='input'] {
23482
24722
  align-items: center;
23483
24723
  justify-content: center;
23484
24724
  inline-size: var(--xh-tree-select-indicator-size, var(--xh-control-indicator-size));
23485
- color: var(--xh-tree-select-item-indicator-fg, var(--xh-_tone, var(--xh-bg-brand)));
24725
+ color: var(--xh-tree-select-item-indicator-fg, var(--xh-_tone, var(--xh-fg-brand)));
23486
24726
  visibility: hidden;
23487
24727
  }
23488
24728
 
@@ -23543,6 +24783,7 @@ input[data-scope='mention'][data-part='input'] {
23543
24783
  [data-scope='tree-select'][data-part='branch-content'] {
23544
24784
  display: flex;
23545
24785
  flex-direction: column;
24786
+ gap: var(--xh-tree-select-branch-content-gap, var(--xh-list-option-gap));
23546
24787
  padding-inline-start: var(--xh-tree-select-indent, var(--xh-space-4));
23547
24788
  }
23548
24789