knight-ui 1.1.2 → 1.1.4

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.
package/tokens/tokens.css CHANGED
@@ -1,497 +1,1196 @@
1
- /* ===== Knight UI 设计 Token ===== */
2
- /* Design Token 体系. */
1
+ /* ══════════════════════════════════════════════════════════════════════════
2
+ 构建产物 —— 请勿手改。
3
3
 
4
- :root {
5
- /* ---- 基础色 ---- */
6
- --ku-grey-9: 249, 249, 249;
7
- --ku-white: 255, 255, 255;
8
- --ku-black: 0, 0, 0;
9
-
10
- /* ---- 主色 ---- */
11
- --ku-color-primary: #8b5cf6;
12
- --ku-color-primary-hover: #a78bfa;
13
- --ku-color-primary-active: #7c3aed;
14
- --ku-color-primary-disabled: #5b3e9e;
15
- --ku-color-primary-light-default: rgba(139, 92, 246, 0.08);
16
- --ku-color-primary-light-hover: rgba(139, 92, 246, 0.15);
17
- --ku-color-primary-light-active: rgba(139, 92, 246, 0.2);
18
-
19
- /* ---- 语义色 ---- */
20
- --ku-color-success: #22c55e;
21
- --ku-color-warning: #f59e0b;
22
- --ku-color-danger: #ef4444;
23
- --ku-color-info: #3b82f6;
24
-
25
- /* ---- 文字色 ---- */
26
- --ku-color-text-0: rgba(var(--ku-grey-9), 1);
27
- --ku-color-text-1: rgba(var(--ku-grey-9), 0.8);
28
- --ku-color-text-2: rgba(var(--ku-grey-9), 0.62);
29
- --ku-color-text-3: rgba(var(--ku-grey-9), 0.35);
30
-
31
- /* ---- 背景色 ---- */
32
- --ku-color-bg-0: #0a0a14;
33
- --ku-color-bg-1: #12121e;
34
- --ku-color-bg-2: #16162a;
35
- --ku-color-bg-3: #1e1e32;
36
- --ku-color-bg-4: #2a2a3e;
37
-
38
- /* ---- 填充色 ---- */
39
- --ku-color-fill-0: #111122;
40
- --ku-color-fill-1: #282840;
41
- --ku-color-fill-2: #323250;
42
-
43
- /* ---- 边框 ---- */
44
- --ku-color-border: rgba(var(--ku-white), 0.08);
45
-
46
- /* ---- 链接 ---- */
47
- --ku-color-link: #8b5cf6;
48
- --ku-color-link-hover: #a78bfa;
49
- --ku-color-link-active: #7c3aed;
50
-
51
- /* ---- 禁用 ---- */
52
- --ku-color-disabled-text: rgba(var(--ku-grey-9), 0.35);
53
- --ku-color-disabled-border: transparent;
54
- --ku-color-disabled-bg: rgba(var(--ku-grey-9), 0.04);
55
- --ku-color-disabled-fill: rgba(var(--ku-grey-9), 0.04);
56
-
57
- /* ---- 阴影 ---- */
58
- --ku-color-shadow: rgba(var(--ku-black), 0.04);
59
- --ku-shadow-elevated: 0 0 1px rgba(0,0,0,0.3), 0 4px 14px rgba(0,0,0,0.1);
60
-
61
- /* ---- 字号 ---- */
62
- --ku-font-size-xs: 10px;
63
- --ku-font-size-sm: 11px;
64
- --ku-font-size-base: 12px;
65
- --ku-font-size-md: 13px;
66
- --ku-font-size-lg: 14px;
67
- --ku-font-size-xl: 16px;
68
- --ku-font-size-2xl: 18px;
69
- --ku-font-size-3xl: 20px;
70
- --ku-font-size-4xl: 24px;
71
-
72
- /* ---- 圆角 ---- */
73
- --ku-radius-xs: 2px;
74
- --ku-radius-sm: 3px;
75
- --ku-radius-base: 4px;
76
- --ku-radius-md: 6px;
77
- --ku-radius-lg: 8px;
78
- --ku-radius-xl: 10px;
79
-
80
- /* ---- 间距 ---- */
81
- --ku-spacing-xs: 2px;
82
- --ku-spacing-sm: 4px;
83
- --ku-spacing-base: 8px;
84
- --ku-spacing-md: 12px;
85
- --ku-spacing-lg: 16px;
86
- --ku-spacing-xl: 20px;
87
-
88
- /* ---- z-index ---- */
89
- --ku-z-mask: 1000;
90
- --ku-z-overlay: 1010;
91
- --ku-z-modal: 1020;
92
- --ku-z-toast: 1030;
93
-
94
- /* ---- 过渡 ---- */
95
- --ku-transition-fast: 100ms ease;
96
- --ku-transition-base: 200ms ease;
97
- --ku-transition-slow: 300ms ease;
98
-
99
- /* ---- 组件通用 ---- */
100
- --ku-font-family: "Inter", "PingFang SC", "Microsoft YaHei", sans-serif;
101
- }
102
-
103
- /* ===== 亮色主题覆盖 ===== */
4
+ 本文件由 scripts/build-css.mjs 把下面两个源文件按序拼接而成:
5
+ 1. src/component/tokens/palette.css 色板层(裸三元组), 由 scripts/gen-palette.mjs 生成
6
+ 2. src/component/tokens/tokens.css 语义层 + 少数类规则(玻璃 / 遮罩 / 滚动条)
104
7
 
105
- :root[data-ku-theme="light"] {
106
- --ku-grey-9: 28, 31, 35;
107
- --ku-color-bg-0: #f0f2f5;
108
- --ku-color-bg-1: #f7f8fa;
109
- --ku-color-bg-2: #ffffff;
110
- --ku-color-bg-3: #e7eaf0;
111
- --ku-color-bg-4: #dce0e6;
112
- --ku-color-fill-0: #f4f4f5;
113
- --ku-color-fill-1: #ebebed;
114
- --ku-color-fill-2: #e2e2e5;
115
- --ku-color-border: rgba(var(--ku-grey-9), 0.08);
116
- }
8
+ 改配色 → scripts/gen-palette.mjs 顶部, 然后 npm run gen:palette
9
+ 改语义 → src/component/tokens/tokens.css, 然后 npm run build
10
+ ══════════════════════════════════════════════════════════════════════════ */
117
11
 
118
- /* ===== 动画关键帧 ===== */
12
+ /* ══════════════════════════════════════════════════════════════════════════
13
+ 色板层(Palette) —— 自动生成, 请勿手改。
119
14
 
120
- @keyframes ku-spin {
121
- from { transform: rotate(0deg); }
122
- to { transform: rotate(360deg); }
123
- }
15
+ 改配色请改 scripts/gen-palette.mjs 顶部的锚点/偏移表, 然后重跑:
16
+ npm run gen:palette
17
+ 校验已入库的产物是否等于脚本输出:
18
+ npm run check:palette
124
19
 
125
- /* ===== 全局交互基类 ===== */
20
+ ── 这里存的是裸 "R, G, B" 三元组, **不带 alpha** ──
21
+ 这是整个三层方案成立的前提: 只有裸三元组才能被上层写成 rgba(var(--ku-blue-5), 0.2)。
22
+ 反过来说, 把三元组直接当颜色用是错的 —— `color: var(--ku-blue-5)` 是非法值, 声明会
23
+ 被静默丢弃、元素继承父色, 没有报错。用之前必须包一层: rgb(...) / rgba(..., α)。
126
24
 
127
- /* 可聚焦元素焦点环 */
128
- .ku-focus-ring:focus-visible,
129
- .ku-select-trigger:focus-visible,
130
- .ku-input-core:focus-visible,
131
- .ku-dropdown button:focus-visible {
132
- outline: 2px solid var(--ku-color-primary);
133
- outline-offset: 1px;
134
- }
25
+ ── 阶梯方向随主题翻转 ──
26
+ 第 0 档 = 最贴该主题的底色, 第 9 档 = 最远离底色(最像墨色)。
27
+ 于是「朝墨色走一档」在两个主题里都成立 —— 暗色下变亮、亮色下变暗。
28
+ 这就是 --ku-color-primary-hover 能一行服务两个主题、且方向都正确的原因。
135
29
 
136
- /* 通用禁用态 */
137
- .ku-disabled {
138
- pointer-events: none !important;
139
- opacity: 0.5 !important;
140
- cursor: not-allowed !important;
141
- }
30
+ ── 第 5 档在两个主题里都是品牌锚点 ──
31
+ 这条不变式保证「第 N 档」在两个主题里指同一个**角色**。它的适用范围到此为止 ——
32
+ 它**不**蕴含「同一个档位号在两个主题里明度相同」: 阶梯方向是翻转的, 第 4 档在暗色下
33
+ 比锚点暗、在亮色下比锚点亮。所以需要等明度的内容色板必须按主题各选一次档
34
+ (见下面两个主题块里的 --ku-content-*)。改动偏移表时不要破坏 [5] = 0。
142
35
 
143
- /* 通用按钮基础 */
144
- .ku-btn-base {
145
- display: inline-flex;
146
- align-items: center;
147
- justify-content: center;
148
- gap: var(--ku-spacing-sm);
149
- font-family: var(--ku-font-family);
150
- font-weight: 600;
151
- border: none;
152
- cursor: pointer;
153
- user-select: none;
154
- white-space: nowrap;
155
- transition: background-color var(--ku-transition-fast),
156
- color var(--ku-transition-fast),
157
- box-shadow var(--ku-transition-fast),
158
- filter var(--ku-transition-fast);
159
- }
36
+ ── 加载顺序无所谓 ──
37
+ 自定义属性替换是惰性的: 语义层写 `rgb(var(--ku-blue-5))`, 即使本文件在 tokens.css
38
+ 之后才解析也能正确求值。所以「谁先 import」不会成为 bug。
160
39
 
161
- .ku-btn-base:disabled {
162
- cursor: not-allowed;
163
- opacity: 0.5;
164
- }
40
+ 本文件在构建期与 tokens.css 拼接成同一个 dist/tokens/tokens.css(见 package.json 的 build),
41
+ 公开契约仍然只有一个样式表。
42
+ ══════════════════════════════════════════════════════════════════════ */
165
43
 
166
- /* ===== Button 按钮 ===== */
44
+ :root {
45
+ /* 无彩色: --ku-white 供 .ku-glass-menu 的奶膜, --ku-black 供 --ku-shadow-*。
46
+ 它们不随主题翻转, 所以只在这里定义一次。 */
47
+ --ku-white: 255, 255, 255; /* #ffffff · L 100.0% */
48
+ --ku-black: 0, 0, 0; /* #000000 · L 0.0% */
49
+
50
+ /* ---- grey: 显式停靠表(不走 ΔL 规则 —— 没有品牌锚点, 且每档都是承重的) ---- */
51
+ --ku-grey-0: 12, 14, 18; /* #0c0e12 · L 16.3% C 0.009 H 264.3 */
52
+ --ku-grey-1: 19, 22, 32; /* #131620 · L 20.2% C 0.021 H 271.5 */
53
+ --ku-grey-2: 26, 31, 43; /* #1a1f2b · L 24.0% C 0.024 H 267.0 */
54
+ --ku-grey-3: 38, 42, 51; /* #262a33 · L 28.5% C 0.018 H 266.3 */
55
+ --ku-grey-4: 47, 52, 60; /* #2f343c · L 32.3% C 0.016 H 259.8 */
56
+ --ku-grey-5: 58, 64, 73; /* #3a4049 · L 36.9% C 0.017 H 258.4 */
57
+ --ku-grey-6: 95, 107, 124; /* #5f6b7c · L 52.4% C 0.031 H 257.1 */
58
+ --ku-grey-7: 171, 179, 191; /* #abb3bf · L 76.4% C 0.019 H 258.4 */
59
+ --ku-grey-8: 201, 208, 218; /* #c9d0da · L 85.5% C 0.016 H 257.2 */
60
+ --ku-grey-9: 246, 247, 249; /* #f6f7f9 · L 97.6% C 0.003 H 264.5 ← 锚点 */
61
+
62
+ /* ---- blue: 第 5 档 = 品牌锚点 #4c90f0 ---- */
63
+ --ku-blue-0: 39, 72, 118; /* #274876 · L 40.0% C 0.087 H 257.0 */
64
+ --ku-blue-1: 40, 83, 144; /* #285390 · L 44.4% C 0.111 H 257.5 */
65
+ --ku-blue-2: 42, 94, 168; /* #2a5ea8 · L 48.6% C 0.131 H 257.7 */
66
+ --ku-blue-3: 45, 106, 191; /* #2d6abf · L 53.0% C 0.147 H 257.5 */
67
+ --ku-blue-4: 54, 119, 210; /* #3677d2 · L 57.4% C 0.155 H 257.5 */
68
+ --ku-blue-5: 76, 144, 240; /* #4c90f0 · L 65.5% C 0.159 H 257.4 ← 锚点 */
69
+ --ku-blue-6: 102, 163, 250; /* #66a3fa · L 71.2% C 0.143 H 257.4 */
70
+ --ku-blue-7: 128, 177, 247; /* #80b1f7 · L 75.4% C 0.114 H 257.3 */
71
+ --ku-blue-8: 162, 197, 246; /* #a2c5f6 · L 81.5% C 0.079 H 256.8 */
72
+ --ku-blue-9: 196, 217, 248; /* #c4d9f8 · L 88.0% C 0.049 H 258.0 */
73
+
74
+ /* ---- green: 第 5 档 = 品牌锚点 #22c55e ---- */
75
+ --ku-green-0: 37, 106, 56; /* #256a38 · L 46.7% C 0.105 H 149.5 */
76
+ --ku-green-1: 20, 123, 57; /* #147b39 · L 51.2% C 0.134 H 149.6 */
77
+ --ku-green-2: 0, 138, 60; /* #008a3c · L 55.3% C 0.154 H 149.5 */
78
+ --ku-green-3: 0, 154, 68; /* #009a44 · L 59.9% C 0.167 H 149.6 */
79
+ --ku-green-4: 0, 169, 75; /* #00a94b · L 64.2% C 0.179 H 149.5 */
80
+ --ku-green-5: 34, 197, 94; /* #22c55e · L 72.3% C 0.192 H 149.6 ← 锚点 */
81
+ --ku-green-6: 85, 213, 120; /* #55d578 · L 77.9% C 0.173 H 149.6 */
82
+ --ku-green-7: 126, 221, 147; /* #7edd93 · L 82.0% C 0.138 H 149.6 */
83
+ --ku-green-8: 171, 235, 183; /* #abebb7 · L 88.3% C 0.096 H 149.8 */
84
+ --ku-green-9: 212, 249, 217; /* #d4f9d9 · L 94.7% C 0.057 H 149.0 */
85
+
86
+ /* ---- cyan: 第 5 档 = 品牌锚点 #22d3ee ---- */
87
+ --ku-cyan-0: 51, 123, 136; /* #337b88 · L 54.3% C 0.074 H 211.3 */
88
+ --ku-cyan-1: 33, 139, 156; /* #218b9c · L 58.7% C 0.094 H 211.1 */
89
+ --ku-cyan-2: 0, 154, 175; /* #009aaf · L 63.0% C 0.110 H 211.6 */
90
+ --ku-cyan-3: 0, 169, 191; /* #00a9bf · L 67.4% C 0.117 H 211.0 */
91
+ --ku-cyan-4: 0, 183, 208; /* #00b7d0 · L 71.5% C 0.125 H 211.9 */
92
+ --ku-cyan-5: 34, 211, 238; /* #22d3ee · L 79.7% C 0.134 H 211.5 ← 锚点 */
93
+ --ku-cyan-6: 89, 224, 249; /* #59e0f9 · L 84.3% C 0.121 H 212.1 */
94
+ --ku-cyan-7: 133, 232, 251; /* #85e8fb · L 87.7% C 0.097 H 211.4 */
95
+ --ku-cyan-8: 183, 243, 255; /* #b7f3ff · L 92.7% C 0.062 H 211.3 */
96
+ --ku-cyan-9: 236, 252, 255; /* #ecfcff · L 98.0% C 0.017 H 210.2 */
97
+
98
+ /* ---- teal: 第 5 档 = 品牌锚点 #14b8a6 ---- */
99
+ --ku-teal-0: 31, 97, 88; /* #1f6158 · L 44.9% C 0.067 H 182.5 */
100
+ --ku-teal-1: 8, 113, 101; /* #087165 · L 49.3% C 0.086 H 182.0 */
101
+ --ku-teal-2: 0, 127, 114; /* #007f72 · L 53.5% C 0.096 H 182.5 */
102
+ --ku-teal-3: 0, 142, 127; /* #008e7f · L 58.0% C 0.104 H 182.0 */
103
+ --ku-teal-4: 0, 156, 141; /* #009c8d · L 62.2% C 0.111 H 183.0 */
104
+ --ku-teal-5: 20, 184, 166; /* #14b8a6 · L 70.4% C 0.123 H 182.5 ← 锚点 */
105
+ --ku-teal-6: 79, 200, 183; /* #4fc8b7 · L 76.0% C 0.110 H 182.5 */
106
+ --ku-teal-7: 120, 209, 195; /* #78d1c3 · L 80.1% C 0.089 H 182.8 */
107
+ --ku-teal-8: 165, 224, 213; /* #a5e0d5 · L 86.3% C 0.062 H 182.0 */
108
+ --ku-teal-9: 206, 240, 233; /* #cef0e9 · L 92.9% C 0.037 H 181.7 */
109
+
110
+ /* ---- amber: 第 5 档 = 品牌锚点 #f59e0b ---- */
111
+ --ku-amber-0: 136, 93, 37; /* #885d25 · L 51.4% C 0.091 H 70.2 */
112
+ --ku-amber-1: 158, 102, 17; /* #9e6611 · L 55.8% C 0.115 H 70.2 */
113
+ --ku-amber-2: 177, 112, 0; /* #b17000 · L 60.1% C 0.130 H 69.9 */
114
+ --ku-amber-3: 194, 124, 0; /* #c27c00 · L 64.5% C 0.139 H 70.4 */
115
+ --ku-amber-4: 212, 135, 0; /* #d48700 · L 68.7% C 0.149 H 69.8 */
116
+ --ku-amber-5: 245, 158, 11; /* #f59e0b · L 76.9% C 0.165 H 70.1 ← 锚点 */
117
+ --ku-amber-6: 255, 179, 82; /* #ffb352 · L 82.2% C 0.142 H 69.9 */
118
+ --ku-amber-7: 255, 197, 128; /* #ffc580 · L 86.1% C 0.109 H 70.4 */
119
+ --ku-amber-8: 255, 222, 185; /* #ffdeb9 · L 91.9% C 0.061 H 70.2 */
120
+ --ku-amber-9: 255, 247, 238; /* #fff7ee · L 98.0% C 0.015 H 70.9 */
121
+
122
+ /* ---- orange: 第 5 档 = 品牌锚点 #f97316 ---- */
123
+ --ku-orange-0: 130, 65, 27; /* #82411b · L 45.1% C 0.103 H 48.0 */
124
+ --ku-orange-1: 155, 69, 9; /* #9b4509 · L 49.5% C 0.131 H 47.7 */
125
+ --ku-orange-2: 175, 76, 0; /* #af4c00 · L 53.7% C 0.147 H 47.6 */
126
+ --ku-orange-3: 195, 85, 0; /* #c35500 · L 58.1% C 0.160 H 47.3 */
127
+ --ku-orange-4: 214, 95, 0; /* #d65f00 · L 62.4% C 0.171 H 47.7 */
128
+ --ku-orange-5: 249, 115, 22; /* #f97316 · L 70.5% C 0.187 H 47.6 ← 锚点 */
129
+ --ku-orange-6: 255, 144, 84; /* #ff9054 · L 76.2% C 0.154 H 47.6 */
130
+ --ku-orange-7: 255, 166, 120; /* #ffa678 · L 80.4% C 0.122 H 47.8 */
131
+ --ku-orange-8: 255, 195, 166; /* #ffc3a6 · L 86.4% C 0.079 H 47.0 */
132
+ --ku-orange-9: 255, 225, 210; /* #ffe1d2 · L 93.0% C 0.039 H 48.3 */
133
+
134
+ /* ---- red: 第 5 档 = 品牌锚点 #ef4444 ---- */
135
+ --ku-red-0: 116, 35, 33; /* #742321 · L 38.3% C 0.114 H 25.5 */
136
+ --ku-red-1: 141, 31, 33; /* #8d1f21 · L 42.5% C 0.146 H 25.2 */
137
+ --ku-red-2: 165, 29, 34; /* #a51d22 · L 46.9% C 0.171 H 25.4 */
138
+ --ku-red-3: 188, 30, 38; /* #bc1e26 · L 51.3% C 0.191 H 25.4 */
139
+ --ku-red-4: 207, 40, 46; /* #cf282e · L 55.6% C 0.201 H 25.4 */
140
+ --ku-red-5: 239, 68, 68; /* #ef4444 · L 63.7% C 0.208 H 25.3 ← 锚点 */
141
+ --ku-red-6: 251, 99, 94; /* #fb635e · L 69.3% C 0.187 H 25.1 */
142
+ --ku-red-7: 249, 128, 120; /* #f98078 · L 73.5% C 0.149 H 25.3 */
143
+ --ku-red-8: 249, 162, 154; /* #f9a29a · L 79.7% C 0.105 H 25.4 */
144
+ --ku-red-9: 248, 195, 189; /* #f8c3bd · L 86.3% C 0.062 H 25.9 */
145
+
146
+ /* ---- pink: 第 5 档 = 品牌锚点 #ec4899 ---- */
147
+ --ku-pink-0: 117, 39, 76; /* #75274c · L 40.1% C 0.116 H 354.2 */
148
+ --ku-pink-1: 141, 36, 89; /* #8d2459 · L 44.4% C 0.148 H 354.1 */
149
+ --ku-pink-2: 164, 35, 102; /* #a42366 · L 48.8% C 0.174 H 354.3 */
150
+ --ku-pink-3: 186, 36, 115; /* #ba2473 · L 53.2% C 0.195 H 354.4 */
151
+ --ku-pink-4: 205, 46, 128; /* #cd2e80 · L 57.6% C 0.205 H 354.5 */
152
+ --ku-pink-5: 236, 72, 153; /* #ec4899 · L 65.6% C 0.212 H 354.3 ← 锚点 */
153
+ --ku-pink-6: 249, 102, 170; /* #f966aa · L 71.3% C 0.191 H 354.2 */
154
+ --ku-pink-7: 248, 131, 181; /* #f883b5 · L 75.4% C 0.152 H 354.4 */
155
+ --ku-pink-8: 249, 166, 199; /* #f9a6c7 · L 81.5% C 0.106 H 354.2 */
156
+ --ku-pink-9: 251, 199, 218; /* #fbc7da · L 88.1% C 0.064 H 354.6 */
157
+
158
+ /* ---- violet: 第 5 档 = 品牌锚点 #a78bfa ---- */
159
+ --ku-violet-0: 89, 76, 130; /* #594c82 · L 45.4% C 0.087 H 293.7 */
160
+ --ku-violet-1: 102, 84, 156; /* #66549c · L 49.7% C 0.113 H 293.4 */
161
+ --ku-violet-2: 116, 93, 179; /* #745db3 · L 54.1% C 0.131 H 293.9 */
162
+ --ku-violet-3: 129, 103, 201; /* #8167c9 · L 58.4% C 0.147 H 293.6 */
163
+ --ku-violet-4: 142, 115, 220; /* #8e73dc · L 62.8% C 0.154 H 293.3 */
164
+ --ku-violet-5: 167, 139, 250; /* #a78bfa · L 70.9% C 0.159 H 293.5 ← 锚点 */
165
+ --ku-violet-6: 183, 162, 255; /* #b7a2ff · L 76.6% C 0.132 H 293.4 */
166
+ --ku-violet-7: 195, 179, 255; /* #c3b3ff · L 80.7% C 0.107 H 293.5 */
167
+ --ku-violet-8: 213, 204, 255; /* #d5ccff · L 86.9% C 0.071 H 293.0 */
168
+ --ku-violet-9: 234, 229, 255; /* #eae5ff · L 93.4% C 0.035 H 294.5 */
169
+
170
+ /* ---- 内容色板(分类色板): 每个色相一个档 ----
171
+ 各色相**等明度**是这条规则的全部目的: 分类色板里明度不齐, 就会有某一条数据序列
172
+ 在图上视觉压过其他序列(改造前 VChart 的琥珀 L .769 与它的蓝 L .623 相差 .146,
173
+ 图表看起来就是不平衡的)。
174
+
175
+ 规则: 取该主题下 L 最接近 0.74 的那一档。**两个主题各选一次** —— 阶梯方向是翻转的,
176
+ 同一个档位号在两个主题里明度不同(第 4 档暗色下比锚点暗、亮色下比锚点亮), 所以
177
+ 「一张选档表两个主题通用」是错的: 实测那会把暗色下的跨度从 .177 顶到 .353。
178
+ 本主题(暗色)的落点跨度见生成时的自检输出。
179
+
180
+ 尾注释里的 `= --ku-<hue>-<n>` 就是它的出处; 值写成字面三元组而不是 var() 引用,
181
+ 是为了让人在这里直接读到颜色本身, 也为免给裸三元组守卫开例外。 ---- */
182
+ --ku-content-blue: 128, 177, 247; /* = --ku-blue-7 · #80b1f7 · L 75.4% */
183
+ --ku-content-cyan: 0, 183, 208; /* = --ku-cyan-4 · #00b7d0 · L 71.5% */
184
+ --ku-content-teal: 79, 200, 183; /* = --ku-teal-6 · #4fc8b7 · L 76.0% */
185
+ --ku-content-green: 34, 197, 94; /* = --ku-green-5 · #22c55e · L 72.3% */
186
+ --ku-content-amber: 245, 158, 11; /* = --ku-amber-5 · #f59e0b · L 76.9% */
187
+ --ku-content-orange: 255, 144, 84; /* = --ku-orange-6 · #ff9054 · L 76.2% */
188
+ --ku-content-red: 249, 128, 120; /* = --ku-red-7 · #f98078 · L 73.5% */
189
+ --ku-content-pink: 248, 131, 181; /* = --ku-pink-7 · #f883b5 · L 75.4% */
190
+ --ku-content-violet: 183, 162, 255; /* = --ku-violet-6 · #b7a2ff · L 76.6% */
191
+ --ku-content-grey: 171, 179, 191; /* = --ku-grey-7 · #abb3bf · L 76.4% */
167
192
 
168
- .ku-button {
169
- border-radius: var(--ku-radius-base);
170
- transition: filter 0.15s ease, background-color 0.15s ease, color 0.15s ease;
171
- }
172
- .ku-button:hover:not(:disabled) {
173
- filter: brightness(1.3);
174
- }
175
- .ku-button:active:not(:disabled) {
176
- filter: brightness(0.75);
177
- }
178
- .ku-button:focus-visible {
179
- outline: 2px solid var(--ku-color-primary);
180
- outline-offset: 2px;
181
193
  }
182
194
 
183
- /* ===== FloatButton 悬浮按钮 ===== */
195
+ /* 亮色: 方向翻转(第 0 档最浅), 且**不是**暗色的倒序 —— 明度镜像但彩度不镜像。
196
+ 两段逐行对照着读即可确认: 同名的第 N 档在两边都在锚点的同一侧。 */
197
+ :root[data-ku-theme="light"] {
198
+ /* ---- grey: 显式停靠表 ---- */
199
+ --ku-grey-0: 255, 255, 255; /* #ffffff · L 100.0% C 0.000 H 89.9 */
200
+ --ku-grey-1: 245, 246, 248; /* #f5f6f8 · L 97.3% C 0.003 H 264.5 */
201
+ --ku-grey-2: 236, 237, 240; /* #ecedf0 · L 94.6% C 0.004 H 271.4 */
202
+ --ku-grey-3: 224, 226, 229; /* #e0e2e5 · L 91.2% C 0.005 H 258.3 */
203
+ --ku-grey-4: 211, 214, 219; /* #d3d6db · L 87.5% C 0.008 H 260.7 */
204
+ --ku-grey-5: 201, 201, 205; /* #c9c9cd · L 83.7% C 0.006 H 286.3 */
205
+ --ku-grey-6: 153, 160, 169; /* #99a0a9 · L 70.3% C 0.015 H 254.6 */
206
+ --ku-grey-7: 111, 116, 123; /* #6f747b · L 55.7% C 0.012 H 256.7 */
207
+ --ku-grey-8: 72, 76, 82; /* #484c52 · L 41.5% C 0.011 H 258.4 */
208
+ --ku-grey-9: 28, 31, 35; /* #1c1f23 · L 23.8% C 0.009 H 255.6 ← 锚点 */
209
+
210
+ /* ---- blue: 第 5 档 = 品牌锚点 #4c90f0 ---- */
211
+ --ku-blue-0: 231, 241, 255; /* #e7f1ff · L 95.5% C 0.022 H 256.7 */
212
+ --ku-blue-1: 202, 222, 250; /* #cadefa · L 89.5% C 0.044 H 256.8 */
213
+ --ku-blue-2: 173, 203, 246; /* #adcbf6 · L 83.5% C 0.069 H 257.4 */
214
+ --ku-blue-3: 143, 184, 243; /* #8fb8f3 · L 77.5% C 0.096 H 257.4 */
215
+ --ku-blue-4: 109, 163, 240; /* #6da3f0 · L 71.0% C 0.127 H 257.3 */
216
+ --ku-blue-5: 76, 144, 240; /* #4c90f0 · L 65.5% C 0.159 H 257.4 ← 锚点 */
217
+ --ku-blue-6: 58, 124, 216; /* #3a7cd8 · L 59.0% C 0.156 H 257.4 */
218
+ --ku-blue-7: 45, 106, 191; /* #2d6abf · L 53.0% C 0.147 H 257.5 */
219
+ --ku-blue-8: 38, 91, 164; /* #265ba4 · L 47.5% C 0.130 H 257.3 */
220
+ --ku-blue-9: 33, 76, 137; /* #214c89 · L 42.0% C 0.112 H 257.7 */
221
+
222
+ /* ---- green: 第 5 档 = 品牌锚点 #22c55e ---- */
223
+ --ku-green-0: 235, 255, 238; /* #ebffee · L 98.1% C 0.031 H 149.8 */
224
+ --ku-green-1: 207, 242, 213; /* #cff2d5 · L 92.8% C 0.053 H 150.2 */
225
+ --ku-green-2: 176, 230, 186; /* #b0e6ba · L 87.6% C 0.082 H 150.0 */
226
+ --ku-green-3: 142, 219, 157; /* #8edb9d · L 82.5% C 0.116 H 149.5 */
227
+ --ku-green-4: 98, 207, 125; /* #62cf7d · L 77.0% C 0.154 H 149.6 */
228
+ --ku-green-5: 34, 197, 94; /* #22c55e · L 72.3% C 0.192 H 149.6 ← 锚点 */
229
+ --ku-green-6: 0, 175, 78; /* #00af4e · L 65.9% C 0.184 H 149.5 */
230
+ --ku-green-7: 0, 153, 68; /* #009944 · L 59.7% C 0.166 H 149.7 */
231
+ --ku-green-8: 0, 134, 58; /* #00863a · L 54.2% C 0.151 H 149.5 */
232
+ --ku-green-9: 3, 116, 50; /* #037432 · L 48.9% C 0.135 H 149.6 */
233
+
234
+ /* ---- cyan: 第 5 档 = 品牌锚点 #22d3ee ---- */
235
+ --ku-cyan-0: 236, 252, 255; /* #ecfcff · L 98.0% C 0.017 H 210.2 */
236
+ --ku-cyan-1: 209, 244, 251; /* #d1f4fb · L 94.4% C 0.037 H 211.1 */
237
+ --ku-cyan-2: 181, 235, 246; /* #b5ebf6 · L 90.7% C 0.057 H 211.5 */
238
+ --ku-cyan-3: 148, 227, 243; /* #94e3f3 · L 87.0% C 0.080 H 211.8 */
239
+ --ku-cyan-4: 104, 218, 239; /* #68daef · L 83.0% C 0.107 H 211.3 */
240
+ --ku-cyan-5: 34, 211, 238; /* #22d3ee · L 79.7% C 0.134 H 211.5 ← 锚点 */
241
+ --ku-cyan-6: 0, 189, 214; /* #00bdd6 · L 73.2% C 0.127 H 211.4 */
242
+ --ku-cyan-7: 0, 168, 191; /* #00a8bf · L 67.1% C 0.117 H 211.8 */
243
+ --ku-cyan-8: 0, 150, 170; /* #0096aa · L 61.7% C 0.107 H 211.2 */
244
+ --ku-cyan-9: 20, 131, 149; /* #148395 · L 56.2% C 0.094 H 212.2 */
245
+
246
+ /* ---- teal: 第 5 档 = 品牌锚点 #14b8a6 ---- */
247
+ --ku-teal-0: 235, 253, 249; /* #ebfdf9 · L 98.0% C 0.020 H 181.1 */
248
+ --ku-teal-1: 206, 238, 232; /* #ceeee8 · L 92.4% C 0.034 H 183.0 */
249
+ --ku-teal-2: 174, 224, 215; /* #aee0d7 · L 86.9% C 0.053 H 182.8 */
250
+ --ku-teal-3: 139, 210, 198; /* #8bd2c6 · L 81.3% C 0.073 H 182.6 */
251
+ --ku-teal-4: 94, 196, 181; /* #5ec4b5 · L 75.5% C 0.098 H 182.7 */
252
+ --ku-teal-5: 20, 184, 166; /* #14b8a6 · L 70.4% C 0.123 H 182.5 ← 锚点 */
253
+ --ku-teal-6: 0, 162, 146; /* #00a292 · L 63.9% C 0.114 H 182.7 */
254
+ --ku-teal-7: 0, 141, 127; /* #008d7f · L 57.8% C 0.103 H 182.8 */
255
+ --ku-teal-8: 0, 123, 111; /* #007b6f · L 52.3% C 0.093 H 183.1 */
256
+ --ku-teal-9: 0, 105, 94; /* #00695e · L 46.7% C 0.083 H 182.5 */
257
+
258
+ /* ---- amber: 第 5 档 = 品牌锚点 #f59e0b ---- */
259
+ --ku-amber-0: 255, 247, 238; /* #fff7ee · L 98.0% C 0.015 H 70.9 */
260
+ --ku-amber-1: 255, 230, 202; /* #ffe6ca · L 93.8% C 0.046 H 70.4 */
261
+ --ku-amber-2: 251, 213, 170; /* #fbd5aa · L 89.5% C 0.070 H 70.2 */
262
+ --ku-amber-3: 249, 196, 134; /* #f9c486 · L 85.4% C 0.099 H 70.2 */
263
+ --ku-amber-4: 246, 176, 89; /* #f6b059 · L 80.7% C 0.132 H 69.9 */
264
+ --ku-amber-5: 245, 158, 11; /* #f59e0b · L 76.9% C 0.165 H 70.1 ← 锚点 */
265
+ --ku-amber-6: 219, 140, 0; /* #db8c00 · L 70.5% C 0.153 H 70.0 */
266
+ --ku-amber-7: 194, 123, 0; /* #c27b00 · L 64.3% C 0.139 H 69.7 */
267
+ --ku-amber-8: 172, 109, 0; /* #ac6d00 · L 58.9% C 0.127 H 70.1 */
268
+ --ku-amber-9: 150, 95, 1; /* #965f01 · L 53.3% C 0.115 H 70.5 */
269
+
270
+ /* ---- orange: 第 5 档 = 品牌锚点 #f97316 ---- */
271
+ --ku-orange-0: 255, 246, 242; /* #fff6f2 · L 97.9% C 0.011 H 45.7 */
272
+ --ku-orange-1: 255, 223, 207; /* #ffdfcf · L 92.6% C 0.042 H 48.2 */
273
+ --ku-orange-2: 255, 198, 169; /* #ffc6a9 · L 87.0% C 0.076 H 48.2 */
274
+ --ku-orange-3: 254, 172, 130; /* #feac82 · L 81.5% C 0.112 H 47.8 */
275
+ --ku-orange-4: 251, 143, 85; /* #fb8f55 · L 75.5% C 0.150 H 47.5 */
276
+ --ku-orange-5: 249, 115, 22; /* #f97316 · L 70.5% C 0.187 H 47.6 ← 锚点 */
277
+ --ku-orange-6: 221, 98, 0; /* #dd6200 · L 63.9% C 0.175 H 47.6 */
278
+ --ku-orange-7: 194, 85, 0; /* #c25500 · L 57.9% C 0.159 H 47.5 */
279
+ --ku-orange-8: 170, 74, 0; /* #aa4a00 · L 52.6% C 0.144 H 47.8 */
280
+ --ku-orange-9: 146, 62, 0; /* #923e00 · L 46.9% C 0.129 H 47.4 */
281
+
282
+ /* ---- red: 第 5 档 = 品牌锚点 #ef4444 ---- */
283
+ --ku-red-0: 255, 227, 223; /* #ffe3df · L 93.8% C 0.031 H 27.4 */
284
+ --ku-red-1: 251, 200, 195; /* #fbc8c3 · L 87.6% C 0.059 H 24.8 */
285
+ --ku-red-2: 248, 173, 166; /* #f8ada6 · L 81.7% C 0.089 H 25.1 */
286
+ --ku-red-3: 245, 143, 135; /* #f58f87 · L 75.6% C 0.125 H 25.2 */
287
+ --ku-red-4: 241, 108, 101; /* #f16c65 · L 69.2% C 0.166 H 25.3 */
288
+ --ku-red-5: 239, 68, 68; /* #ef4444 · L 63.7% C 0.208 H 25.3 ← 锚点 */
289
+ --ku-red-6: 214, 45, 50; /* #d62d32 · L 57.2% C 0.204 H 25.3 */
290
+ --ku-red-7: 188, 29, 38; /* #bc1d26 · L 51.3% C 0.192 H 25.2 */
291
+ --ku-red-8: 161, 24, 31; /* #a1181f · L 45.7% C 0.170 H 25.4 */
292
+ --ku-red-9: 133, 22, 26; /* #85161a · L 40.1% C 0.145 H 25.4 */
293
+
294
+ /* ---- pink: 第 5 档 = 品牌锚点 #ec4899 ---- */
295
+ --ku-pink-0: 255, 234, 241; /* #ffeaf1 · L 95.6% C 0.025 H 355.3 */
296
+ --ku-pink-1: 254, 205, 223; /* #fecddf · L 89.6% C 0.060 H 354.4 */
297
+ --ku-pink-2: 249, 177, 205; /* #f9b1cd · L 83.6% C 0.091 H 354.2 */
298
+ --ku-pink-3: 245, 147, 187; /* #f593bb · L 77.6% C 0.126 H 354.5 */
299
+ --ku-pink-4: 240, 111, 168; /* #f06fa8 · L 71.1% C 0.169 H 354.6 */
300
+ --ku-pink-5: 236, 72, 153; /* #ec4899 · L 65.6% C 0.212 H 354.3 ← 锚点 */
301
+ --ku-pink-6: 211, 50, 133; /* #d33285 · L 59.0% C 0.208 H 354.3 */
302
+ --ku-pink-7: 186, 36, 115; /* #ba2473 · L 53.2% C 0.195 H 354.4 */
303
+ --ku-pink-8: 160, 30, 99; /* #a01e63 · L 47.6% C 0.174 H 354.1 */
304
+ --ku-pink-9: 133, 28, 82; /* #851c52 · L 42.0% C 0.148 H 354.3 */
305
+
306
+ /* ---- violet: 第 5 档 = 品牌锚点 #a78bfa ---- */
307
+ --ku-violet-0: 248, 247, 255; /* #f8f7ff · L 97.9% C 0.011 H 292.0 */
308
+ --ku-violet-1: 231, 226, 255; /* #e7e2ff · L 92.6% C 0.039 H 293.5 */
309
+ --ku-violet-2: 214, 205, 254; /* #d6cdfe · L 87.1% C 0.068 H 293.4 */
310
+ --ku-violet-3: 198, 184, 252; /* #c6b8fc · L 81.8% C 0.096 H 293.6 */
311
+ --ku-violet-4: 181, 160, 250; /* #b5a0fa · L 75.8% C 0.128 H 293.8 */
312
+ --ku-violet-5: 167, 139, 250; /* #a78bfa · L 70.9% C 0.159 H 293.5 ← 锚点 */
313
+ --ku-violet-6: 147, 119, 226; /* #9377e2 · L 64.3% C 0.157 H 293.6 */
314
+ --ku-violet-7: 129, 103, 201; /* #8167c9 · L 58.4% C 0.147 H 293.6 */
315
+ --ku-violet-8: 112, 90, 175; /* #705aaf · L 52.9% C 0.130 H 293.4 */
316
+ --ku-violet-9: 96, 78, 148; /* #604e94 · L 47.5% C 0.111 H 293.6 */
317
+
318
+ /* ---- 内容色板(分类色板): 每个色相一个档 ----
319
+ 各色相**等明度**是这条规则的全部目的: 分类色板里明度不齐, 就会有某一条数据序列
320
+ 在图上视觉压过其他序列(改造前 VChart 的琥珀 L .769 与它的蓝 L .623 相差 .146,
321
+ 图表看起来就是不平衡的)。
322
+
323
+ 规则: 取该主题下 L 最接近 0.71 的那一档。**两个主题各选一次** —— 阶梯方向是翻转的,
324
+ 同一个档位号在两个主题里明度不同(第 4 档暗色下比锚点暗、亮色下比锚点亮), 所以
325
+ 「一张选档表两个主题通用」是错的: 实测那会把暗色下的跨度从 .177 顶到 .353。
326
+ 本主题(亮色)的落点跨度见生成时的自检输出。
327
+
328
+ 尾注释里的 `= --ku-<hue>-<n>` 就是它的出处; 值写成字面三元组而不是 var() 引用,
329
+ 是为了让人在这里直接读到颜色本身, 也为免给裸三元组守卫开例外。 ---- */
330
+ --ku-content-blue: 109, 163, 240; /* = --ku-blue-4 · #6da3f0 · L 71.0% */
331
+ --ku-content-cyan: 0, 189, 214; /* = --ku-cyan-6 · #00bdd6 · L 73.2% */
332
+ --ku-content-teal: 20, 184, 166; /* = --ku-teal-5 · #14b8a6 · L 70.4% */
333
+ --ku-content-green: 34, 197, 94; /* = --ku-green-5 · #22c55e · L 72.3% */
334
+ --ku-content-amber: 219, 140, 0; /* = --ku-amber-6 · #db8c00 · L 70.5% */
335
+ --ku-content-orange: 249, 115, 22; /* = --ku-orange-5 · #f97316 · L 70.5% */
336
+ --ku-content-red: 241, 108, 101; /* = --ku-red-4 · #f16c65 · L 69.2% */
337
+ --ku-content-pink: 240, 111, 168; /* = --ku-pink-4 · #f06fa8 · L 71.1% */
338
+ --ku-content-violet: 167, 139, 250; /* = --ku-violet-5 · #a78bfa · L 70.9% */
339
+ --ku-content-grey: 153, 160, 169; /* = --ku-grey-6 · #99a0a9 · L 70.3% */
184
340
 
185
- .ku-float-button {
186
- box-shadow: var(--ku-shadow-elevated);
187
- transition: transform 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
188
341
  }
189
- .ku-float-button:hover {
190
- transform: scale(1.08);
191
- box-shadow: 0 0 2px rgba(0,0,0,0.3), 0 8px 24px rgba(0,0,0,0.15);
192
- }
193
- .ku-float-button:active {
194
- transform: scale(0.95);
195
- }
196
-
197
- /* ===== Input 输入框 ===== */
198
342
 
199
- .ku-input:hover {
200
- border-color: var(--ku-color-primary-hover);
343
+ /* ===== Knight UI 设计 Token =====
344
+ 三层结构: 色板(palette.css, 裸 `R,G,B` 三元组, 无 alpha) → 语义(本文件的 :root) → 组件(.ku-* 类规则)。
345
+ 亮色覆盖在 :root[data-ku-theme="light"]。两个文件在构建期拼成 dist/tokens/tokens.css,
346
+ 自定义属性替换是惰性的, 谁先加载都不影响结果。
347
+
348
+ 注释只记两件事: **这个值为什么是这个值**, 以及**已知缺口**。调参沿革与试错过程不进注释。 */
349
+
350
+ :root
351
+ {
352
+ /* ---- 1. 主色 ---- */
353
+ /* 绑 blue 色阶。第 5 档在两个主题里都逐位等于品牌色 #4c90f0, 故 base 零位移。
354
+ hover 取第 6 档 —— 一行同时服务两个主题(暗色下更亮、亮色下更暗)。
355
+ active 取第 4 档(按下 = 朝底色压回), 亮色必须覆盖成第 7 档, 见亮色块第 1 节。 */
356
+ --ku-color-primary: rgb(var(--ku-blue-5));
357
+ --ku-color-primary-hover: rgb(var(--ku-blue-6));
358
+ --ku-color-primary-active: rgb(var(--ku-blue-4));
359
+ /* 三个浅底: 原为三条 rgba(76,144,240,α) 字面量, 收成一个阶梯档 + 三个 alpha, 三元组逐位不变。 */
360
+ --ku-color-primary-light-default: rgba(var(--ku-blue-5), 0.08);
361
+ --ku-color-primary-light-hover: rgba(var(--ku-blue-5), 0.15);
362
+ --ku-color-primary-light-active: rgba(var(--ku-blue-5), 0.2);
363
+
364
+ /* ---- 2. 语义色 ---- */
365
+ /* 与主色同构: base / hover / active 直接取阶梯。组件不要再用 filter: brightness() 冒充 hover —— 那会把文字
366
+ 一起提亮, 且亮色下方向相反。四个家族全部上阶梯, 无一例外。
367
+
368
+ warning 是唯一有代价的收口: 旧值 amber-400 的色相相对锚点偏 −14.5°, 而阶梯的定义性质是色相恒定, 够不到
369
+ 它。这里**就近取档**而不是留字面量 —— 代价是 hover/active 色相偏 14.5°/11.5°, 收益是语义色再无非阶梯值。
370
+ 这是一次**视觉决策**, 要退回去就把 warning 那两行换回字面量。 */
371
+ --ku-color-success: rgb(var(--ku-green-5));
372
+ --ku-color-success-hover: rgb(var(--ku-green-6));
373
+ --ku-color-success-active: rgb(var(--ku-green-4));
374
+ --ku-color-warning: rgb(var(--ku-amber-5));
375
+ --ku-color-warning-hover: rgb(var(--ku-amber-6));
376
+ --ku-color-warning-active: rgb(var(--ku-amber-4));
377
+ --ku-color-danger: rgb(var(--ku-red-5));
378
+ --ku-color-danger-hover: rgb(var(--ku-red-6));
379
+ --ku-color-danger-active: rgb(var(--ku-red-4));
380
+
381
+ /* ---- 3. 校验态 ---- */
382
+ /* border: 同色 60%, 不用满饱和 base —— 一条 1px 纯 #ef4444 叠在低饱和的冷灰面板上明暗落差过大, 校验态会
383
+ "跳出来"; 校验要"看得见", 不是"抢眼"。
384
+ light: **只服务聚焦环**。它原先还兼一份"校验浅底"(整个字段被 14% 同色铺满), 那是本库唯一一处铺面积的
385
+ 着色, 也是"校验态看着厚重"的主因。现在校验态只由上面那条 1px 描边承担(同 Ant Design 5 / Semi: 字段底回
386
+ --ku-color-fill-0, 状态只改描边)。 */
387
+ --ku-color-success-border: rgba(var(--ku-green-5), 0.6);
388
+ --ku-color-warning-border: rgba(var(--ku-amber-5), 0.6);
389
+ --ku-color-danger-border: rgba(var(--ku-red-5), 0.6);
390
+ --ku-color-success-light: rgba(var(--ku-green-5), 0.14);
391
+ --ku-color-warning-light: rgba(var(--ku-amber-5), 0.14);
392
+ --ku-color-danger-light: rgba(var(--ku-red-5), 0.14);
393
+
394
+ /* ---- 4. 文字 ---- */
395
+ /* 实色(原为 rgba(var(--ku-grey-9), α) 半透白派生 —— 半透白叠在毛玻璃上会发灰, 也拿不到 kg 的冷调)。取灰阶
396
+ 第 9/8/7/6 档, 亮度与旧值逐档对齐, 故换色不改变原有对比层级。
397
+ 因为灰阶随主题翻转, "第 0 档最贴底色、第 9 档最像墨色"这条规则本身就同时给出了两个主题的正确文字色 ——
398
+ 8 个值在两个主题下逐位不变, **亮色块里不需要再覆盖一份**。 */
399
+ --ku-color-text-0: rgb(var(--ku-grey-9));
400
+ --ku-color-text-1: rgb(var(--ku-grey-8));
401
+ --ku-color-text-2: rgb(var(--ku-grey-7));
402
+ --ku-color-text-3: rgb(var(--ku-grey-6));
403
+
404
+ /* ---- 5. 背景 ---- */
405
+ /* 去紫的冷灰蓝阶: 旧阶带紫相(~250°), 与 kg 的蓝系控件同屏会互串发脏; 亮度逐档对齐旧值, 色相移到 kg 的
406
+ ~215°。第 4 档同时装 --ku-color-border 与 fill-2, 两者同值。
407
+
408
+ **bg-1 与 bg-2 同为第 1 档 —— 唯一一处刻意的合并。** 暗色中性色原有 11 个互不相同的值而阶梯只有 10 档,
409
+ 必有合并; 选这一对是因为它不丢任何交互态差异, 而另两个候选会分别抹掉滚动条 thumb:hover 与 Button
410
+ secondary 的 hover→active 区分。另一处同档(bg-4 与 fill-2)的解法是**删掉 bg-4**: 它只有 Button secondary
411
+ 一个消费方, 而那个按钮要的是"连续三档填充", 已改从 fill-1 起跳。 */
412
+ --ku-color-bg-0: rgb(var(--ku-grey-0));
413
+ --ku-color-bg-1: rgb(var(--ku-grey-1));
414
+ --ku-color-bg-2: rgb(var(--ku-grey-1));
415
+ --ku-color-bg-3: rgb(var(--ku-grey-2));
416
+
417
+ /* 默认底纹: 毛玻璃需要有"可糊之物", 纯色底上玻璃只会读成一块纯色面板(见第 8 节)。
418
+ 停靠点只留**确属阶梯档**的那些 —— 旧值里有非阶梯档, 各归最近档会让渐变出现平台, 而铺满视口的底纹上
419
+ 平台边界是看得见的 banding; 只留阶梯档后渐变仍平滑(逐点对照旧值最大差 3/255)。 */
420
+ --ku-bg-image: radial-gradient(120% 120% at 0% 0%,
421
+ rgb(var(--ku-grey-2)) 0%, rgb(var(--ku-grey-1)) 52%, rgb(var(--ku-grey-0)) 100%);
422
+
423
+ /* ---- 6. 填充(交互面/滚动条, 叠在 bg 阶之上) ---- */
424
+ /* 四个 fill-* **保持不透明**(刻意偏离 Semi —— Semi 的 fill-* 是 alpha 的)。照搬会让 Input 的字段底变成
425
+ 半透, 违反本库已定的「单字段控件不透明、面板才是玻璃」; 而且不透明的内层表面会让身后的 backdrop-filter
426
+ 失效。半透明那一族是下面三条, 用途不同。 */
427
+ --ku-color-fill-0: rgb(var(--ku-grey-1));
428
+ --ku-color-fill-1: rgb(var(--ku-grey-3));
429
+ --ku-color-fill-2: rgb(var(--ku-grey-4));
430
+ --ku-color-fill-3: rgb(var(--ku-grey-5));
431
+ /* 半透明中性填充: 斑马纹/行悬停这类"叠在已有底上"的浅层着色。**必须半透明** —— 上面的 fill-* 是不透明的,
432
+ 铺在毛玻璃面上会糊出一片死色, 玻璃白做。
433
+ 三元组用 rgb(var(--ku-grey-9)) 一行顶两个主题: 暗色下它是近白 #f6f7f9(白膜)、亮色下是近黑 #1c1f23
434
+ (黑膜), 两行做的是同一件事(跟主题翻转的中性膜)。3% 的膜上这点差异复合后约 1–2/255。 */
435
+ --ku-color-fill-translucent: rgba(var(--ku-grey-9), 0.03);
436
+ --ku-color-fill-translucent-hover: rgba(var(--ku-grey-9), 0.06);
437
+ /* -strong: 第二档半透中性填充, 给"必须读得出来"的**静态**带子用(代码三件套的工具条)。.03 那一档的定位是
438
+ "叠在已有底上的极浅着色", 暗色下够用, 亮色下却只有约 2/255 —— 工具条整条消失, 看着像页面从代码块上方漏
439
+ 了出来。加厚到 .06 后亮色 Δ 约 13/255, 与表格的**行悬停**带子同一重量, 比斑马纹(.03)厚一档。
440
+ 值恰好等于 -hover, 但**角色不同**故独立命名: 将来谁调 hover 的深浅, 都不该顺手把工具条一起挪走。 */
441
+ --ku-color-fill-translucent-strong: rgba(var(--ku-grey-9), 0.06);
442
+
443
+ /* ---- 7. 边框 ---- */
444
+ /* 实色(原为 rgba(255,255,255,0.08) 半透白, 叠在毛玻璃面上过弱, 撑不起 kg 的描边派风格)。
445
+ 第 4 档逐位不变(#2f343c) —— 这是全库最常用的 token(171 处引用), 必须钉住。 */
446
+ --ku-color-border: rgb(var(--ku-grey-4));
447
+
448
+ /* ---- 8. 毛玻璃面 ---- */
449
+ /* 半透明膜 + 模糊, 由文件末的 .ku-glass-* 基类消费。
450
+ **玻璃必须"身后有可糊之物"才看得出通透** —— 底纹若是纯色, 玻璃等价于换了个纯色面板, 却照样付一次
451
+ backdrop-filter 的合成开销。
452
+
453
+ 五档一览(膜 α 为暗色, 亮色的膜见亮色块第 8 节):
454
+ 档 类 膜(暗) 模糊
455
+ 容器 .ku-glass rgba(grey-2, .22) --ku-blur-lg 14px / 175%
456
+ 弱档 .ku-glass-subtle rgba(grey-2, .22) --ku-blur-base 10px / 165%
457
+ 头部 .ku-glass-head rgba(grey-4, .30) --ku-blur-lg 14px / 175%
458
+ 浮层 .ku-glass-overlay rgba(grey-3, .34) --ku-blur-xl 18px / 185%
459
+ 气泡 .ku-glass-tip rgba(grey-3, .22) --ku-blur-tip 7px / 250%
460
+ 菜单 .ku-glass-menu rgba(grey-2, .70) --ku-blur-menu 22px / 195%
461
+ 另有两档不属玻璃家族: .ku-mask(遮罩, 见第 9 节)与 .ku-userguide-card(不透明面)。
462
+
463
+ **三元组只是那层膜的色相**, 它最终只以 α 的比例参与合成 —— 所以旧值(均非阶梯档)就近归到灰阶第 2/3/4 档
464
+ 即可, 逐通道最大差 5, 合成后实测 1–2/255。观感由 **α + 模糊半径** 承担。 */
465
+ --ku-color-glass: rgba(var(--ku-grey-2), 0.22);
466
+ --ku-color-glass-strong: rgba(var(--ku-grey-3), 0.34);
467
+ --ku-color-glass-head: rgba(var(--ku-grey-4), 0.30);
468
+ /* 气泡档: 三元组与 strong 同为第 3 档, 靠 alpha 再透一档 —— 这正是这一档的意图("比 strong 再透一档")。 */
469
+ --ku-color-glass-tip: rgba(var(--ku-grey-3), 0.22);
470
+ /* 菜单档: 0.70 是这一档的**承重值** —— 底色抬上去之后能透上来的只剩三成, 再靠半径把那三成糊成一片柔光。
471
+ 合成后实测 3/255, 是五个玻璃档里位移最大的一处(α 最高, 所以 α×Δ 最大)。 */
472
+ --ku-color-glass-menu: rgba(var(--ku-grey-2), 0.70);
473
+
474
+ /* 底色与模糊是一对跷跷板, 但**方向本轮翻了**, 写清楚免得下次照旧规则反着调:
475
+ 旧目标是"看得见背后有东西、但认不出是什么" —— 底越薄、半径越要顶上去; **现目标是"背景的图和颜色要透得
476
+ 过来"**, 而这个目标下**大半径本身就是障碍** —— 40px 会把一张图糊成一团色块, 只剩平均色。故本轮半径整体
477
+ 砍到约一半, 底不动, 两个旋钮同向、不再对冲。
478
+ **saturate 往上抬是另一半解法**: 膜再薄也还是盖了一层, 白膜与深膜都会洗掉背后的彩度, 不补 saturate 透上来
479
+ 的图会读成灰蒙蒙一片。
480
+ 半径是**两个主题共用**的量(不是亮色覆盖), 改它会同时动暗色的玻璃。
481
+ 原第一档 --ku-blur-sm(16px / 130%)全仓零引用, 已剪。 */
482
+ --ku-blur-base: blur(10px) saturate(165%);
483
+ --ku-blur-lg: blur(14px) saturate(175%);
484
+ --ku-blur-xl: blur(18px) saturate(185%);
485
+ /* 气泡档单独成档的原因是小**面积**: 同样的半径铺在 300px 宽的面板上和铺在 100px 宽的气泡上, 后者看起来"糊"
486
+ 得多 —— 所以这一档要的不是更大的半径, 是**更小的**。这四个数是实测标定值(排查台 test/glass-lab.html):
487
+ 半径 16 → **7px**, saturate 195 → **250%**, 亮色的膜 .28 → .38, 颗粒回到 .10。
488
+ **半径与 saturate 是反向的一对, 必须成对调**: 16px 已经把 148px 宽的小图糊成一块平均色, 砍掉一半以上背后
489
+ 那点结构才留得住; 而留下来的结构需要 saturate 顶上去(白膜会洗掉彩度), 才不读成灰蒙蒙一片。只砍半径不抬
490
+ saturate 得到一块灰玻璃, 只抬 saturate 不砍半径得到一团糊的彩色。 */
491
+ --ku-blur-tip: blur(7px) saturate(250%);
492
+ /* 菜单档的半径是五档里最大的 —— 这一档底最厚, 同样的半径在厚底上"糊"的贡献本来就最小; 砍它是为了换"背后那
493
+ 三成能看到颜色", 而菜单项自身的可读性由 0.70 的底承担, 不靠半径。
494
+ **底一旦加厚, 透上来的三成里那点模糊就已经看不见了, 磨砂感就只剩颗粒在撑。** 所以这一档不能只抬底色:
495
+ 底色负责"读得清", 颗粒负责"看着是磨砂", 缺一个都会得到"一块平板"或"一层糊字"。 */
496
+ --ku-blur-menu: blur(22px) saturate(195%);
497
+
498
+ /* 菜单的"奶膜"(只作用于 .ku-glass-menu 的第二层 background-image):
499
+ 暗色下它是**承重**的 —— 底 .70 的面板本身就是一块深色, 只铺颗粒读起来是"深色板子上撒了噪点"; 先垫一层
500
+ 几乎均匀的白把面板抬回浅冷灰调, 颗粒才有东西可依附。
501
+ **亮色下这一层置空(none), 因为它在那里是个恒等变换** —— 亮色的底本来就是纯白膜, 再叠一层白等于白叠白,
502
+ 合成结果一个通道都不变。这正是把它抽成 token 的理由: 一个只对某个主题有效的层, 写在类规则里就是一句看不
503
+ 出问题的死代码, 写成 token 才看得见它在另一个主题下是空的。 */
504
+ --ku-glass-menu-film: linear-gradient(180deg, rgba(var(--ku-white), 0.05) 0%, rgba(var(--ku-white), 0.015) 100%);
505
+
506
+ /* 磨砂颗粒:
507
+ 背景若是平滑渐变(比如默认底纹 --ku-bg-image), 模糊它得到的还是同一片平滑渐变 —— **模糊本身不产生肌理**。
508
+ 这对本库尤其致命: 默认底纹正是一条平滑径向渐变, 于是任何一档玻璃在默认底纹上, backdrop-filter 的模糊几乎
509
+ 是个视觉上的空操作 —— 透上来的只是同一片渐变稍微暗一点; 用户看到的"透明"其实是渐变在漏, 而不是"磨砂"。
510
+ **结论: 颗粒不是锦上添花的肌理, 它是这套玻璃在默认底纹上唯一的磨砂来源。** 强度必须给到看得见: 0.06 落在
511
+ 可见阈值以下, 玻璃读成"换了个纯色面板"; 0.10 刚好能看出磨砂、又还没到"电视雪花"。
512
+ 单色(saturate=0)故亮/暗共用一份; stitchTiles 让 140px 的贴图无缝平铺; **只贴浮层和小面, 不贴侧栏那种大
513
+ 面积容器** —— 大面积铺噪点会显脏。
514
+ ⚠️ **颗粒在两个主题下是同向的, 不需要分档。** 曾按"它跟主题反向"的假设做过一个亮色专用的减半档
515
+ (--ku-glass-grain-tip), 已删除 —— 那个假设把"亮色气泡不透"归因到颗粒上, 实测推翻了它(真正起作用的是半径,
516
+ 见 --ku-blur-tip)。记在这里, 免得下次又照那个假设去分档。
517
+ 嫌"磨砂感太重"时旋钮在这里(0.10 → 0.07), 而不是继续砍 --ku-blur-* 的半径: 半径只管"背后能不能看清", 砍到
518
+ 0 也去不掉那层哑光。
519
+
520
+ `<` `>` `#` 一律转义: `#` 不转义会被当成 URL 片段截断; `<` `>` 是防 CSS 压缩器把 url() 的引号省掉(省掉之后
521
+ 裸 `<` 让解析直接失败, 玻璃静默少掉一层肌理, 很难发现)。 */
522
+ --ku-glass-grain: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='140'%20height='140'%3E%3Cfilter%20id='g'%3E%3CfeTurbulence%20type='fractalNoise'%20baseFrequency='0.85'%20numOctaves='3'%20stitchTiles='stitch'/%3E%3CfeColorMatrix%20type='saturate'%20values='0'/%3E%3C/filter%3E%3Crect%20width='140'%20height='140'%20filter='url(%23g)'%20opacity='0.10'/%3E%3C/svg%3E");
523
+
524
+ /* ---- 9. 遮罩层 ---- */
525
+ /* 遮罩也做成毛玻璃: 原是一层 rgba(0,0,0,0.45) 的纯黑, 页面被"关灯"式压掉; 改成薄一点的冷色遮罩 + 模糊后
526
+ 背景还在(看得出是一大片内容), 只是失焦退到后面, 浮层因此显得"浮在页面上"而不是"页面被换掉了"。
527
+ α 取 0.34 不再低: 遮罩要承担"挡住点击 + 明确模态", 太薄看不出当前是模态态。模糊只要 10px —— 遮罩铺满
528
+ 视口, 全屏 backdrop-filter 是这里最贵的一次合成, 加半径收益小、开销线性增长。
529
+ 三元组取**该主题里最暗的那一档**: 暗色第 0 档、亮色第 9 档(见亮色块)—— 这条规则同时给出两个主题的正确
530
+ 方向, 遮罩永远要压暗。 */
531
+ --ku-color-mask: rgba(var(--ku-grey-0), 0.34);
532
+ --ku-blur-mask: blur(10px) saturate(120%);
533
+
534
+ /* ---- 10. 阴影 ---- */
535
+ /* 旧 elevated 过浅(0 4px 14px α.1), 提到 kg 量级: 纯黑无彩色偏移、大半径无 spread。
536
+ shadow-sm / -lg 是补上的缺口 —— lg 此前被 11 个文件引用却从未定义, 全靠内联 fallback 字面量生效, 导致
537
+ 弹层阴影无法由主题统一控制。 */
538
+ --ku-shadow-sm: 0 2px 8px rgba(var(--ku-black), 0.24);
539
+ --ku-shadow-elevated: 0 4px 16px rgba(var(--ku-black), 0.35);
540
+ --ku-shadow-lg: 0 8px 32px rgba(var(--ku-black), 0.45);
541
+
542
+ /* ---- 11. 链接 ---- */
543
+ /* link 逐位等于 primary(同一个蓝), 直接绑同一档。原 -hover / -active 两档全仓零引用且取值与 primary 家族
544
+ 相同, 已剪 —— 要链接 hover 直接用 primary 家族, 不丢能力。 */
545
+ --ku-color-link: rgb(var(--ku-blue-5));
546
+
547
+ /* ---- 12. 禁用 ---- */
548
+ --ku-color-disabled-text: rgba(var(--ku-grey-9), 0.35);
549
+ --ku-color-disabled-border: transparent;
550
+ --ku-color-disabled-bg: rgba(var(--ku-grey-9), 0.04);
551
+ --ku-color-disabled-fill: rgba(var(--ku-grey-9), 0.04);
552
+
553
+ /* ---- 13. 字号 ---- */
554
+ --ku-font-size-xs: 10px;
555
+ --ku-font-size-sm: 11px;
556
+ --ku-font-size-base: 12px;
557
+ --ku-font-size-md: 13px;
558
+ --ku-font-size-lg: 14px;
559
+ --ku-font-size-xl: 16px;
560
+ --ku-font-size-2xl: 18px;
561
+ --ku-font-size-3xl: 20px;
562
+
563
+ /* ---- 14. 圆角 ---- */
564
+ /* base 是"控件档"(输入框/按钮/小控件), kg 同为 4px, 保持不动。容器档(卡片/表格/导航项)在 kg 是 6px, 由组件
565
+ 各自指向 --ku-radius-md 实现 —— **不在这里抬高 base**, 否则会把输入框一并顶到 6px。 */
566
+ --ku-radius-xs: 2px;
567
+ --ku-radius-sm: 3px;
568
+ --ku-radius-base: 4px;
569
+ --ku-radius-md: 6px;
570
+ --ku-radius-lg: 8px;
571
+ --ku-radius-xl: 10px;
572
+
573
+ /* ---- 15. 间距 ---- */
574
+ --ku-spacing-xs: 2px;
575
+ --ku-spacing-sm: 4px;
576
+ --ku-spacing-base: 8px;
577
+ --ku-spacing-md: 12px;
578
+ --ku-spacing-lg: 16px;
579
+ --ku-spacing-xl: 20px;
580
+
581
+ /* ---- 16. z-index ---- */
582
+ --ku-z-mask: 1000;
583
+ --ku-z-overlay: 1010;
584
+ --ku-z-modal: 1020;
585
+ --ku-z-toast: 1030;
586
+
587
+ /* ---- 17. 过渡 ---- */
588
+ /* 原 -base(200ms) / -slow(300ms) 两档全仓零引用, 已剪 —— 只需一个"快档"给交互反馈, 真要 200ms 的消费者
589
+ 直接写 200ms。 */
590
+ --ku-transition-fast: 100ms ease;
591
+
592
+ /* ---- 18. 字体 ---- */
593
+ --ku-font-family: "Inter", "PingFang SC", "Microsoft YaHei", sans-serif;
201
594
  }
202
- .ku-input:focus-within {
203
- border-color: var(--ku-color-primary);
204
- box-shadow: 0 0 0 2px var(--ku-color-primary-light-default);
205
- }
206
-
207
- /* ===== InputNumber 数字输入 ===== */
208
595
 
209
- .ku-input-number button:hover:not(:disabled) {
210
- background-color: var(--ku-color-fill-1);
211
- }
212
- .ku-input-number button:active:not(:disabled) {
213
- background-color: var(--ku-color-fill-2);
596
+ /* ===== 亮色主题覆盖 =====
597
+ 只保留两类东西:
598
+ 1) 档位号与暗色**不同**的族 —— 因为"第 0 档 = 该主题最贴底色"在两个主题里指向相反的明度;
599
+ 2) 亮色独有的复合值(底纹、玻璃膜、遮罩、阴影、描边 alpha)。
600
+ 凡是"同一个档位号在两个主题里方向都对"的(全部 hover、全部文字色、全部 fill-translucent), 一律不在这里
601
+ 重复 —— 它们由 :root 供给。
602
+ 色板层的裸三元组(--ku-grey-* / --ku-white / --ku-black)归 palette.css, 这里不再声明。 */
603
+ :root[data-ku-theme="light"]
604
+ {
605
+ /* ---- 1. 主色 / 语义色: 只有 active 需要按主题各写一行 ---- */
606
+ /* hover 不需要, 因为第 6 档在两个主题里方向都对。但 active 不行: 按下的语义是"朝底色压回", 暗色要第 4 档、
607
+ 亮色要第 7 档, 同一个档位号满足不了两边。
608
+ 必须与 :root 的重绑同批落地, 否则会引入一处**新的**回归: 亮色此前没有 active 覆盖, 继承的是暗色字面量
609
+ #3a7edb, 恰好比 base 暗(歪打正着); 一旦 :root 改绑第 4 档, 亮色继承到的 blue-4 反而比 base **亮**, 方向
610
+ 就反了。 */
611
+ --ku-color-primary-active: rgb(var(--ku-blue-7));
612
+ --ku-color-success-active: rgb(var(--ku-green-7));
613
+ --ku-color-warning-active: rgb(var(--ku-amber-7));
614
+ --ku-color-danger-active: rgb(var(--ku-red-7));
615
+
616
+ /* ---- 5/6/7. 表面(背景 · 填充 · 边框) ---- */
617
+ /* 亮色灰阶的浅端(第 0–5 档)重排过 —— 见 palette.css 里 GREY_LIGHT 上方的注释: 原表把 6 个面档挤在 .123 的
618
+ 跨度里(暗色同段 .206), 相邻差最小 .012、还有两对同档, 于是"整个界面都是白的"; 现在摊到 .163。
619
+ 8 个表面值装进 6 档, 两处共享 —— (bg-3, fill-1) → 第 3 档, (bg-2, fill-0) → 第 0 档。
620
+ **fill-0 本轮从第 2 档移到第 0 档**: 原先与 bg-0 同档, 于是输入框底与页面底**逐位相同**(ΔL 0.000), 字段
621
+ 完全隐形。亮色的字段底本就该是纯白(暗色那边 fill-0 也与面板同档, 两个主题一致: 字段靠描边而不是靠底色
622
+ 立住)。 */
623
+ --ku-color-bg-0: rgb(var(--ku-grey-2));
624
+ --ku-color-bg-1: rgb(var(--ku-grey-1));
625
+ --ku-color-bg-2: rgb(var(--ku-grey-0));
626
+ --ku-color-bg-3: rgb(var(--ku-grey-3));
627
+ --ku-color-fill-0: rgb(var(--ku-grey-0));
628
+ --ku-color-fill-1: rgb(var(--ku-grey-3));
629
+ --ku-color-fill-2: rgb(var(--ku-grey-4));
630
+ --ku-color-fill-3: rgb(var(--ku-grey-5));
631
+ /* 亮色描边 0.08 → 0.14。这是"看不清边界"的另一半原因, 而且比灰阶更容易被忽略: **同一个 alpha 在两个主题里
632
+ 不是同一件事** —— 合成后 ΔL 从 .052 提到 .089(ΔE 5.0 → 8.8), 而暗色的 border 是 ΔL .160, 0.08 只有暗色
633
+ 重量的三分之一。取 0.14 的依据: 仍轻于暗色(亮色惯例), 也仍轻于 Ant 的 #d9d9d9 在白底上的 ΔE 11.5。 */
634
+ --ku-color-border: rgba(var(--ku-grey-9), 0.14);
635
+
636
+ /* 底纹的四个停靠点全是阶梯档(第 0/1/2/3 档), 直接换引用; 逐点最大差 5/255。 */
637
+ --ku-bg-image: radial-gradient(120% 120% at 0% 0%,
638
+ rgb(var(--ku-grey-0)) 0%, rgb(var(--ku-grey-1)) 30%, rgb(var(--ku-grey-2)) 60%, rgb(var(--ku-grey-3)) 100%);
639
+
640
+ /* ---- 8. 毛玻璃面 ---- */
641
+ /* 亮色玻璃一律是纯白膜, 只厚薄不同, 三元组直接取 --ku-white。白叠白不产生明度差, 只能靠 blur 撑通透, 所以
642
+ 同一档在亮色下天然比暗色更"实"。
643
+ ── 五档 α: .20 / .38 / .50 / .62 / .76, 次序 glass < tip < strong < head < menu ──
644
+
645
+ **先说一件做不到的事, 免得来回试: 亮色的玻璃档位靠 α 分不出来。** 页面底 #ecedf0(L .946) 到纯白只有
646
+ ΔL .054, 五档塞进去相邻档实测 ΔE 只有 0.6~1.0(可见阈值 2)。要让相邻档可辨, Δα 至少 .20、五档要跨 .80,
647
+ 而 α > .85 已是实心白板 —— 是窗口宽度不够, 不是取值没调好(暗色同样分不出来, 同因: 膜与底同色系)。
648
+ **所以 α 是"观感旋钮"而非"层次旋钮"**, 它只改这个面多实/多透; 层次由遮罩与阴影给, 两者都在位
649
+ (Modal / SideSheet 的膜叠在 .20 遮罩上; 无遮罩的弹层都带 --ku-shadow-lg / -sm)。想更透就往下降。
650
+
651
+ **唯一底线是可读性**: 浮层/气泡/菜单三档身后可能是任意内容, 最坏是近黑(代码块、图片暗部), 而亮色玻璃里
652
+ 是深色 text-0, 只能靠膜把底垫亮。实测(文字 #1c1f23 压在 #1e1e1e 上, 合成值 = 30 + 225α, AA 正文下限 4.5):
653
+ .38 → 3.54:1 (tip) .50 → 5.11:1 (strong) .62 → 7.08:1 (head) .76 → 9.99:1 (menu)
654
+ **tip 是唯一跌破的一个 —— 已知缺口, 明知故犯**。要收回就只把 tip 抬到 .46~.48, 其余四档不受影响。
655
+
656
+ ⚠️ **`glass` 降了 .10 却几乎看不出来, 别以为没生效**: 它身后是页面自己的近白底纹, 白膜叠上去挪不动几个数
657
+ (α .30 时差 6~9/255, α .20 时只剩 4~6/255)。这一档的边界靠 1px 描边与 --ku-shadow-sm —— **面板在亮色下
658
+ 糊成一片时去补描边/阴影, 不要回来加 α**。其余四档身后是内容(卡片、代码块、图片), α 一动就是实打实的差别。
659
+ ⚠️ **"暗色更稳"只在自己的底上成立**: 身后是浅色内容(#e8e8e8)时暗色 tip 只有 1.73:1 —— 同一处**已知且
660
+ 尚未处理的缺口**。
661
+ (上表只按 α 算, 未计颗粒; 颗粒均值在中灰, 压在近黑面板上约 +2/255, 在四舍五入以内。)
662
+ 半径的沿革见 --ku-blur-base / --ku-blur-tip。 */
663
+ --ku-color-glass: rgba(var(--ku-white), 0.20);
664
+ --ku-color-glass-strong: rgba(var(--ku-white), 0.50);
665
+ --ku-color-glass-head: rgba(var(--ku-white), 0.62);
666
+ --ku-color-glass-menu: rgba(var(--ku-white), 0.76);
667
+ /* 气泡档: 仍比 strong 再透一档(暗色同此关系)。**.38 是实测标定值, 不是推导值**(排查台 test/glass-lab.html)
668
+ —— 它比曾经的 .28 厚一档, 因为真正让气泡"通透"的不是更薄的膜, 而是把半径砍到 7px、saturate 抬到 250%
669
+ (见 --ku-blur-tip): 背后真有东西透上来之后, 膜反而可以退回去一点, 换来压在近黑内容上不那么吃力。
670
+ 五档次序仍然没乱(.20 < .38 < .50 < .62 < .76)。可读性 3.54:1, 仍低于 AA 4.5 —— 见上面那段。 */
671
+ --ku-color-glass-tip: rgba(var(--ku-white), 0.38);
672
+
673
+ /* 奶膜在亮色下**没有活可干**, 直接置空 —— 见 --ku-glass-menu-film 的说明。 */
674
+ --ku-glass-menu-film: none;
675
+
676
+ /* ---- 9. 遮罩 ---- */
677
+ /* 职责两个主题相同, 但**同一个 alpha 在两个主题里的感知重量差别很大**: 0.34 叠在 #0c0e12 上几乎不可见, 叠在
678
+ #ffffff 上会把页面压成一块明显的灰, 所以亮色取更轻的 0.20。三元组沿用暗色那条规则的第二半 —— "用该主题里
679
+ 最暗的那一档": 暗色第 0 档、亮色第 9 档。没有覆盖时会继承暗色的 rgba(10,13,20,0.34), 白底上是一块压得很
680
+ 重的灰 —— 这是修掉的一个真 bug。 */
681
+ --ku-color-mask: rgba(var(--ku-grey-9), 0.20);
682
+
683
+ /* ---- 10. 阴影 ---- */
684
+ /* 暗色那套重阴影(α .24/.35/.45)砸在白底上会把界面压出"发霉"的观感, 亮色要轻得多; 偏移量与模糊半径沿用,
685
+ 只换 alpha。这三个值有证据而非口味 —— 本仓 Tabs / Navigation / Pagination 三处早就各自硬编码了
686
+ rgba(0,0,0,0.15) 当弹层阴影, 那就是这个代码库已经接受的亮色阴影重量; 取 .08/.10/.14 落在它附近, 并按层级
687
+ 递增。 */
688
+ --ku-shadow-sm: 0 2px 8px rgba(var(--ku-black), 0.08);
689
+ --ku-shadow-elevated: 0 4px 16px rgba(var(--ku-black), 0.10);
690
+ --ku-shadow-lg: 0 8px 32px rgba(var(--ku-black), 0.14);
214
691
  }
215
692
 
216
- /* ===== Select 选择器 ===== */
693
+ /* ===== 动画关键帧 ===== */
217
694
 
218
- .ku-select { position: relative; }
219
- .ku-select-trigger {
220
- cursor: pointer;
221
- transition: border-color var(--ku-transition-fast), box-shadow var(--ku-transition-fast);
222
- }
223
- .ku-select-trigger:hover { border-color: var(--ku-color-primary-hover); }
224
- .ku-select-option {
225
- cursor: pointer;
226
- transition: background-color var(--ku-transition-fast);
227
- }
228
- .ku-select-option:hover { background-color: var(--ku-color-fill-0); }
229
- .ku-select-option.ku-selected {
230
- color: var(--ku-color-primary);
231
- background-color: var(--ku-color-primary-light-default);
695
+ @keyframes ku-spin
696
+ {
697
+ from
698
+ {
699
+ transform: rotate(0deg);
700
+ }
701
+
702
+ to
703
+ {
704
+ transform: rotate(360deg);
705
+ }
232
706
  }
233
707
 
234
- /* ===== Dropdown 下拉菜单 ===== */
708
+ /* ===== 全局交互基类 ===== */
235
709
 
236
- .ku-dropdown-item {
237
- cursor: pointer;
238
- transition: background-color var(--ku-transition-fast);
239
- }
240
- .ku-dropdown-item:hover:not(.ku-dropdown-item-disabled) {
241
- background-color: var(--ku-color-fill-0);
710
+ /* 可聚焦元素焦点环。挂类的是 Button / Checkbox / Switch / FloatButton 及其 Group 的触发钮 —— 这几处自己内联
711
+ outline:"none" 关掉 UA 环又没给替代。其余控件不走这条: Input 由自身 focused 状态画 box-shadow, Select 的
712
+ 触发框压根不可键盘聚焦。
713
+ **前提是那个元素内联没有 outline** —— 内联优先于类, 内联写着 outline:"none" 时这里画多粗都出不来。 */
714
+ .ku-focus-ring:focus-visible
715
+ {
716
+ outline: 2px solid var(--ku-color-primary);
717
+ outline-offset: 1px;
242
718
  }
243
719
 
244
- /* ===== Modal 对话框 ===== */
720
+ /* Chat 输入框的聚焦态。文字区(textarea)自己没有边框、也关掉了 outline, 焦点环要画在外面那口"井"上。
721
+ 这里用 :focus-within 而不是 JS 的 focused 状态: 焦点进出不该触发一次 React 渲染, 而 :focus-within 正是
722
+ "子元素拿到焦点"的 CSS 原生表达。 */
723
+ .ku-chat-inputbox:focus-within
724
+ {
725
+ border-color: var(--ku-color-primary);
726
+ }
245
727
 
246
- .ku-modal-close:hover {
247
- background-color: var(--ku-color-fill-1);
248
- color: var(--ku-color-text-0);
728
+ /* ===== FloatButton 悬浮按钮 =====
729
+ 独立按钮与该按钮组 **Group 的触发钮**共用这一个类(两者本就是同一个东西)。
730
+
731
+ ① **UA 重置不能省。** `<button>` 的 UA 默认样式带 `appearance: auto` 与一条 `2px outset` 的原生边框, 而
732
+ `outset` 画出来就是"左上亮、右下暗"的一圈立体斜角 —— 没有作者边框盖着它, 按钮外面就会多出一圈半亮半暗的环。
733
+ **注意这修不了"描边"**: 把边框色改成透明也一样, 因为那是 UA 的绘制, 不是一条可染色的边; 必须
734
+ `appearance: none` 与 `border: none` 一起下(同 .ku-layout-sider-trigger)。
735
+ `padding` / `margin` / `font` 一并归零 —— 它们都会吃进内联的 width/height, 不归零那个 `size` 就名不副实;
736
+ 触发钮折叠态渲染的是文字 `"+"`, 所以 `line-height: 1` 也要给。**顺序要紧**: `font` 简写会连 line-height 一起
737
+ 重置, 故 `line-height` 必须写在它**后面**。
738
+
739
+ ② **内联干不了的两件事**: 阴影的静置/悬停两态与它的过渡都写不进内联 —— 组件里那句内联 `boxShadow` 因此是
740
+ **删掉**的, 留着会把 `:hover` 一起盖掉, 按钮永远不抬起。
741
+
742
+ ③ 外观(圆、居中、主色、radius)全在这里, 内联只留随 props / state 变的几项(位置、size、展开态的 rotate);
743
+ 底色由 .ku-glass-tip 提供, 不在这里重复。
744
+ `:active` 写在 `:hover` 之后且只改 transform, "悬停放大 + 按下缩小"因此能叠加; 触发钮展开态的内联
745
+ `rotate(45deg)` 会盖掉 `:hover` 的 scale —— 它悬停时只变阴影、不放大, 这是有意的。 */
746
+ .ku-float-button
747
+ {
748
+ appearance: none;
749
+ border: none;
750
+ margin: 0;
751
+ padding: 0;
752
+ font: inherit;
753
+ line-height: 1;
754
+ border-radius: 50%;
755
+ display: flex;
756
+ align-items: center;
757
+ justify-content: center;
758
+ color: var(--ku-color-primary);
759
+ cursor: pointer;
760
+ user-select: none;
761
+ box-shadow: var(--ku-shadow-elevated);
762
+ transition: transform 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
249
763
  }
250
- .ku-modal-btn:hover {
251
- background-color: var(--ku-color-fill-1);
764
+
765
+ .ku-float-button:hover
766
+ {
767
+ transform: scale(1.08);
768
+ box-shadow: var(--ku-shadow-lg);
252
769
  }
253
- .ku-modal-btn-primary:hover {
254
- filter: brightness(1.2);
770
+
771
+ .ku-float-button:active
772
+ {
773
+ transform: scale(0.95);
255
774
  }
256
- .ku-modal-btn-primary:active {
257
- filter: brightness(0.85);
775
+
776
+ /* ===== Select 选择器 =====
777
+ 触发框(.ku-select-trigger)、输入框(.ku-input)与 InputNumber 的加减按钮都不在这里写规则: 它们的 cursor /
778
+ 悬停边框 / 聚焦环全在内联样式里(边框要随聚焦与校验状态算, 是一行 border 简写), 而内联优先于类 —— 同类声明
779
+ 写在这儿一条都不会生效。
780
+ 下面的 cursor 同理不写: 组件内联那份是状态驱动的(disabled ? not-allowed : pointer), 比类里一个恒定的
781
+ pointer 更准。这条对后面多处同样适用。 */
782
+ .ku-select-option
783
+ {
784
+ transition: background-color var(--ku-transition-fast);
258
785
  }
259
786
 
260
- /* ===== Switch 开关 ===== */
787
+ /* 悬停底原为 fill-0(#14171e), 而弹层底是 bg-2(#14161f) —— 两色几乎同值, 悬停等于没反馈 */
788
+ .ku-select-option:hover
789
+ {
790
+ background-color: var(--ku-color-fill-1);
791
+ }
261
792
 
262
- .ku-switch {
263
- transition: background-color var(--ku-transition-base);
264
- cursor: pointer;
793
+ .ku-select-option.ku-selected
794
+ {
795
+ color: var(--ku-color-primary);
796
+ background-color: var(--ku-color-primary-light-default);
265
797
  }
266
- .ku-switch:hover { opacity: 0.9; }
267
- .ku-switch:active { transform: none; }
268
- .ku-switch-knob {
269
- transition: transform var(--ku-transition-base);
798
+
799
+ /* 选中项被悬停时不能被 fill-1 盖掉主色底, 要走主色浅档的下一级 */
800
+ .ku-select-option.ku-selected:hover
801
+ {
802
+ background-color: var(--ku-color-primary-light-hover);
270
803
  }
271
804
 
272
- /* ===== Checkbox / Radio 复选框/单选框 ===== */
805
+ /* ===== Dropdown 下拉菜单 ===== */
806
+ .ku-dropdown-item
807
+ {
808
+ transition: background-color var(--ku-transition-fast);
809
+ }
273
810
 
274
- .ku-checkbox, .ku-radio {
275
- -webkit-tap-highlight-color: transparent;
276
- cursor: pointer;
811
+ /* 底走半透明档: 菜单面是毛玻璃, 不透明 fill-* 会在玻璃上糊出一片死色 */
812
+ .ku-dropdown-item:hover:not(.ku-dropdown-item-disabled)
813
+ {
814
+ background-color: var(--ku-color-fill-translucent-hover);
277
815
  }
278
- .ku-checkbox:hover .ku-checkbox-box,
279
- .ku-radio:hover .ku-radio-box {
280
- border-color: var(--ku-color-primary);
816
+
817
+ /* ===== Modal 对话框 ===== */
818
+ /* 关闭按钮的底色内联没写, 所以这条穿得过去; 但 color 内联恒有值, 悬停改色是白写, 故只留底色。
819
+ 底走半透明档: 对话框本身是毛玻璃, 不透明 fill-* 会在玻璃上糊出一片死色。 */
820
+ .ku-modal-close:hover
821
+ {
822
+ background-color: var(--ku-color-fill-translucent-hover);
281
823
  }
282
824
 
283
- /* ===== Slider 滑块 ===== */
825
+ /* 主按钮的悬停/按下只能靠 filter —— 它的 backgroundColor 是内联的(还要随 confirmLoading 变), 内联优先于类,
826
+ 任何 background-color 的 :hover 都穿不过去; filter 内联没写, 才拦不住。
827
+ 次级按钮连类都没有: 底色同样内联, 类规则救不回来, 悬停反馈得由组件自己给。 */
828
+ .ku-modal-btn-primary:hover
829
+ {
830
+ filter: brightness(1.2);
831
+ }
284
832
 
285
- .ku-slider-track { cursor: pointer; }
286
- .ku-slider-handle {
287
- cursor: grab;
288
- transition: box-shadow var(--ku-transition-fast), transform var(--ku-transition-fast);
833
+ .ku-modal-btn-primary:active
834
+ {
835
+ filter: brightness(0.85);
289
836
  }
290
- .ku-slider-handle:hover { transform: scale(1.15); }
291
- .ku-slider-handle:active { cursor: grabbing; transform: scale(1.05); }
292
837
 
293
- /* ===== Rating 评分 ===== */
838
+ /* ===== Switch 开关 =====
839
+ 没有类规则: cursor / transition / 禁用透明度全在内联(trackStyle / thumbStyle), 类声明一律被盖, 滑块那一层
840
+ 更是压根没挂类名。这里只剩 .ku-focus-ring 负责键盘焦点环。 */
294
841
 
295
- .ku-rating-star {
296
- cursor: pointer;
297
- transition: transform var(--ku-transition-fast), color var(--ku-transition-fast);
842
+ /* ===== Checkbox / Radio 复选框/单选框 =====
843
+ 只有 -webkit-tap-highlight-color 留得住 —— cursor 被两边的内联样式盖掉。 */
844
+ .ku-checkbox,
845
+ .ku-radio
846
+ {
847
+ -webkit-tap-highlight-color: transparent;
298
848
  }
299
- .ku-rating-star:hover { transform: scale(1.2); }
300
849
 
301
850
  /* ===== Tag 标签 ===== */
302
-
303
- .ku-tag {
304
- transition: background-color var(--ku-transition-fast);
851
+ .ku-tag
852
+ {
853
+ transition: background-color var(--ku-transition-fast);
305
854
  }
306
- .ku-tag.ku-tag-closable .ku-tag-close {
307
- cursor: pointer;
308
- transition: color var(--ku-transition-fast);
309
- }
310
- .ku-tag .ku-tag-close:hover {
311
- color: var(--ku-color-text-0);
312
- }
313
-
314
- /* ===== Tabs 选项卡 ===== */
315
855
 
316
- .ku-tabs-tab {
317
- cursor: pointer;
318
- transition: color var(--ku-transition-fast), border-color var(--ku-transition-fast);
856
+ /* ===== Collapse 折叠面板 =====
857
+ 表头没有内联底色, 悬停底才落得下来。底走半透明档: 整块折叠面板是毛玻璃, 不透明的 fill-* 会在玻璃上糊出一片
858
+ 死色(与表格行同一个理由)。cursor 不写 —— 表头内联已按禁用态给了 pointer / not-allowed; 禁用态的表头不挂这个
859
+ 类, 免得"禁用还亮一下"。 */
860
+ .ku-collapse-header
861
+ {
862
+ transition: background-color var(--ku-transition-fast);
319
863
  }
320
- .ku-tabs-tab:hover { color: var(--ku-color-primary); }
321
- .ku-tabs-tab.ku-active { color: var(--ku-color-primary); }
322
864
 
323
- /* ===== Collapse 折叠面板 ===== */
324
-
325
- .ku-collapse-header {
326
- cursor: pointer;
327
- transition: background-color var(--ku-transition-fast);
865
+ .ku-collapse-header:hover
866
+ {
867
+ background-color: var(--ku-color-fill-translucent-hover);
328
868
  }
329
- .ku-collapse-header:hover { background-color: var(--ku-color-fill-0); }
330
-
331
- /* ===== Breadcrumb 面包屑 ===== */
332
869
 
333
- .ku-breadcrumb-item {
334
- cursor: pointer;
335
- transition: color var(--ku-transition-fast);
870
+ /* ===== Card 卡片 =====
871
+ 悬停阴影只在 shadows="hover" 时给(组件此时才挂 .ku-card-hoverable) —— 原来写成 .ku-card:hover 无条件生效,
872
+ 于是 shadows="none" 也照样浮起来, 与 prop 语义相反; 而 shadows="hover" 找的 .ku-card-hoverable 反倒没有任何
873
+ 规则(死类)。一并收口。 */
874
+ .ku-card.ku-card-hoverable:hover
875
+ {
876
+ box-shadow: var(--ku-shadow-elevated);
336
877
  }
337
- .ku-breadcrumb-item:hover { color: var(--ku-color-primary); }
338
878
 
339
- /* ===== Pagination 分页 ===== */
340
-
341
- .ku-pagination-item {
342
- cursor: pointer;
343
- transition: background-color var(--ku-transition-fast), color var(--ku-transition-fast);
344
- }
345
- .ku-pagination-item:hover:not(.ku-pagination-active) { background-color: var(--ku-color-fill-0); }
346
- .ku-pagination-item.ku-pagination-active {
347
- background-color: var(--ku-color-primary);
348
- color: #fff;
879
+ /* ===== Table 表格 =====
880
+ 行悬停 / 斑马纹 / 选中底都走类。此前行悬停是 tr 上的 onMouseEnter / Leave 手写的, 于是有两处坏:
881
+ 1) 悬停画的 fill-0 与斑马纹用的是同一个颜色, 斑马表上悬停完全看不出来;
882
+ 2) 斑马纹画在 td 的内联样式上, 悬停画在 tr 上 —— td 是不透明的, 直接把 tr 的悬停底盖掉。
883
+ 交给类之后 td 不再画底, 由行统一负责, 两个状态才能叠在同一层上。
884
+ 底色一律用半透明档: 表格面是毛玻璃, 不透明的 fill-* 会在行上糊出一片死色。 */
885
+ .ku-table-row
886
+ {
887
+ transition: background-color var(--ku-transition-fast);
349
888
  }
350
889
 
351
- /* ===== Tree 树 ===== */
352
-
353
- .ku-tree-node {
354
- cursor: pointer;
355
- transition: background-color var(--ku-transition-fast);
890
+ .ku-table-striped tbody .ku-table-row:nth-child(even)
891
+ {
892
+ background-color: var(--ku-color-fill-translucent);
356
893
  }
357
- .ku-tree-node:hover { background-color: var(--ku-color-fill-0); }
358
- .ku-tree-node.ku-selected { background-color: var(--ku-color-primary-light-default); }
359
-
360
- /* ===== Steps 步骤条 ===== */
361
-
362
- .ku-steps-item { cursor: pointer; }
363
894
 
364
- /* ===== Timeline 时间轴 ===== */
895
+ .ku-table-row:hover
896
+ {
897
+ background-color: var(--ku-color-fill-translucent-hover);
898
+ }
365
899
 
366
- .ku-timeline-item { transition: color var(--ku-transition-fast); }
900
+ /* 斑马纹与悬停同时命中时悬停优先: 两者权重不等, 必须显式列出, 不能靠书写顺序 */
901
+ .ku-table-striped tbody .ku-table-row:nth-child(even):hover
902
+ {
903
+ background-color: var(--ku-color-fill-translucent-hover);
904
+ }
367
905
 
368
- /* ===== Card 卡片 ===== */
906
+ /* 选中行压在悬停之下: 悬停时不该把选中态的主色底冲掉 */
907
+ .ku-table-row.ku-selected
908
+ {
909
+ background-color: var(--ku-color-primary-light-default);
910
+ }
369
911
 
370
- .ku-card:hover { box-shadow: var(--ku-shadow-elevated); }
371
- .ku-card { transition: box-shadow var(--ku-transition-base); }
912
+ .ku-table-row.ku-selected:hover
913
+ {
914
+ background-color: var(--ku-color-primary-light-hover);
915
+ }
372
916
 
373
- /* ===== Avatar 头像 ===== */
917
+ /* 表头 sticky 且半透明 —— 必须有 backdrop-filter, 否则滚动时行内容会从表头文字后透出来 */
918
+ .ku-table-th
919
+ {
920
+ background-color: var(--ku-color-glass-head);
921
+ backdrop-filter: var(--ku-blur-base);
922
+ -webkit-backdrop-filter: var(--ku-blur-base);
923
+ }
374
924
 
375
- .ku-avatar { flex-shrink: 0; }
925
+ .ku-table-sort
926
+ {
927
+ cursor: pointer;
928
+ }
376
929
 
377
- /* ===== Badge 徽标 ===== */
930
+ .ku-table-sort:hover
931
+ {
932
+ color: var(--ku-color-primary);
933
+ }
378
934
 
379
- .ku-badge {
380
- position: relative;
381
- display: inline-flex;
935
+ /* 表头筛选: 漏斗按钮 + 弹出的选项面板(面板是毛玻璃浮层, 悬停底必须走半透明档)。
936
+ 漏斗自身的悬停改色没有类规则 —— 它的 color 内联恒有值(按"是否已筛选"算出来的), 类盖不过去。 */
937
+ .ku-table-filter-trigger
938
+ {
939
+ cursor: pointer;
940
+ padding: 0 1px;
382
941
  }
383
942
 
384
- /* ===== Table 表格 ===== */
943
+ .ku-table-filter-item
944
+ {
945
+ transition: background-color var(--ku-transition-fast);
946
+ }
385
947
 
386
- .ku-table-row { transition: background-color var(--ku-transition-fast); }
387
- .ku-table-row:hover { background-color: var(--ku-color-fill-0); }
388
- .ku-table-sort { cursor: pointer; }
389
- .ku-table-sort:hover { color: var(--ku-color-primary); }
948
+ .ku-table-filter-item:hover
949
+ {
950
+ background-color: var(--ku-color-fill-translucent-hover);
951
+ }
390
952
 
391
953
  /* ===== Calendar 日历 ===== */
392
-
393
- .ku-calendar-cell {
394
- cursor: pointer;
395
- transition: background-color var(--ku-transition-fast);
396
- }
397
- .ku-calendar-cell:hover:not(.ku-calendar-cell-disabled) {
398
- background-color: var(--ku-color-fill-0);
399
- }
400
- .ku-calendar-cell.ku-calendar-cell-today {
401
- color: var(--ku-color-primary);
402
- font-weight: 700;
403
- }
404
- .ku-calendar-cell.ku-calendar-cell-selected {
405
- background-color: var(--ku-color-primary);
406
- color: #fff;
954
+ .ku-calendar-cell
955
+ {
956
+ transition: background-color var(--ku-transition-fast);
407
957
  }
408
958
 
409
- /* ===== Carousel 轮播 ===== */
410
-
411
- .ku-carousel-dot {
412
- cursor: pointer;
413
- transition: background-color var(--ku-transition-fast), width var(--ku-transition-fast);
959
+ .ku-calendar-cell:hover:not(.ku-calendar-cell-disabled)
960
+ {
961
+ background-color: var(--ku-color-fill-translucent-hover);
414
962
  }
415
963
 
416
- /* ===== Sidebar 侧边栏 ===== */
417
-
418
- .ku-sidebar-item {
419
- cursor: pointer;
420
- transition: background-color var(--ku-transition-fast), color var(--ku-transition-fast);
964
+ /* **注意: 这两条里都没有 color** —— 日历格的文字色一律由组件内联给出(选中=白 / 今天=主色 / 补位与禁用=
965
+ text-2), 内联恒有值, 写在这儿也盖不动(见 Calendar.getDayCellStyle 的说明)。 */
966
+ .ku-calendar-cell.ku-calendar-cell-today
967
+ {
968
+ font-weight: 700;
969
+ /* 今天原先靠内联 rgba(128,128,128,0.15) 上底色 —— 那个"灰"不属于任何色阶, 暗底下既不偏蓝也不偏暖, 看着像
970
+ 一块脏点。改用半透明中性档, 与斑马纹/悬停同一族。 */
971
+ background-color: var(--ku-color-fill-translucent);
421
972
  }
422
- .ku-sidebar-item:hover { background-color: var(--ku-color-fill-0); }
423
- .ku-sidebar-item.ku-sidebar-active {
424
- color: var(--ku-color-primary);
425
- background-color: var(--ku-color-primary-light-default);
426
- }
427
-
428
- /* ===== Navigation 导航 ===== */
429
973
 
430
- .ku-nav-item {
431
- cursor: pointer;
432
- transition: background-color var(--ku-transition-fast), color var(--ku-transition-fast);
974
+ .ku-calendar-cell.ku-calendar-cell-selected
975
+ {
976
+ background-color: var(--ku-color-primary);
433
977
  }
434
- .ku-nav-item:hover { background-color: var(--ku-color-fill-0); }
435
- .ku-nav-item.ku-nav-active {
436
- color: var(--ku-color-primary);
437
- background-color: var(--ku-color-primary-light-default);
978
+
979
+ /* 悬停规则的权重(0,3,0)高于选中(0,2,0), 不显式兜一手的话悬停会把选中日的主色底冲掉 */
980
+ .ku-calendar-cell.ku-calendar-cell-selected:hover
981
+ {
982
+ background-color: var(--ku-color-primary-hover);
438
983
  }
439
984
 
440
- /* ===== Toast 轻提示 ===== */
985
+ /* ===== Layout Sider 触发钮 =====
986
+ 压在侧栏右边缘、垂直居中的圆钮。它与上一版(铺满侧栏宽度的底横条)的关键差别: 圆钮**同时骑在两种底色上**
987
+ —— 左半边是玻璃侧栏, 右半边是内容区。所以底**必须不透明**: 半透底会让同一颗钮的左右两半各取各的背景、显出
988
+ 两种颜色(与 UserGuide 卡片"压在挖洞的遮罩上"同一个病根, 只是面积小到不容易被指名)。fill-1 在两个主题里都是
989
+ "贴着 bg-1 的一档面", 骑在这两种底上都读得出来, hover 走 fill-2 仍有可见的亮度差。
990
+ (旧注释论证"横条必须半透, 否则会在玻璃上切出一道死色横缝"—— 那个论证只对横条成立: 横条完全位于玻璃内部,
991
+ 上下要连续; 骑边缘的圆钮不适用。)
992
+ 组件那边挂的是真 <button>(上一版是裸 div, 键盘够不到), 故下面三条清掉 UA 默认样式。 */
993
+ .ku-layout-sider-trigger
994
+ {
995
+ position: absolute;
996
+ top: 50%;
997
+ right: -12px;
998
+ transform: translateY(-50%);
999
+ display: flex;
1000
+ align-items: center;
1001
+ justify-content: center;
1002
+ width: 24px;
1003
+ height: 24px;
1004
+ padding: 0;
1005
+ appearance: none;
1006
+ font: inherit;
1007
+ cursor: pointer;
1008
+ border: 1px solid var(--ku-color-border);
1009
+ border-radius: 50%;
1010
+ background-color: var(--ku-color-fill-1);
1011
+ color: var(--ku-color-text-2);
1012
+ box-shadow: var(--ku-shadow-sm);
1013
+ transition: background-color var(--ku-transition-fast), color var(--ku-transition-fast);
1014
+ }
441
1015
 
442
- .ku-toast-item { pointer-events: auto; cursor: pointer; }
1016
+ .ku-layout-sider-trigger:hover
1017
+ {
1018
+ background-color: var(--ku-color-fill-2);
1019
+ color: var(--ku-color-text-0);
1020
+ }
443
1021
 
444
- /* ===== Banner 横幅 ===== */
1022
+ /* ===== 已删除的死类(规则永远不会生效, 记在这里免得再补回来) =====
1023
+ · 类名从没挂上过: .ku-timeline-item / .ku-carousel-dot / .ku-avatar / .ku-badge /
1024
+ .ku-checkbox-box:hover / .ku-sidebar-item* / .ku-toast-item / 原"移除原生控件样式"一节
1025
+ (InputNumber 的输入框是 type="text", 全仓唯一的 type="number" 在 Pagination 的跳页框里)。
1026
+ · 类挂上了但被内联盖住: .ku-nav-item*(cursor / transition / color / 底色四条全被盖, 且选中态找的
1027
+ .ku-nav-active 不是组件实际挂的 ku-nav-item-active) / .ku-banner-close / .ku-resizable-handle
1028
+ (Toast 的气泡整块是 innerHTML 字符串, 样式写在字面量里)。
1029
+ · Slider / Rating / Tabs / Pagination / Tree / Steps / Breadcrumb 的全部交互类 —— 交互态全在内联: cursor 与
1030
+ transition 恒写在 style 对象里, 悬停底/色由手写的 onMouseEnter / onMouseLeave 直接改
1031
+ e.currentTarget.style, 补类规则只会被盖掉。 */
445
1032
 
446
- .ku-banner-close {
447
- cursor: pointer;
448
- transition: color var(--ku-transition-fast), background-color var(--ku-transition-fast);
1033
+ /* ===== 滚动条美化 ===== */
1034
+ .ku-scrollbar::-webkit-scrollbar
1035
+ {
1036
+ width: 4px;
1037
+ height: 4px;
449
1038
  }
450
- .ku-banner-close:hover {
451
- color: var(--ku-color-text-0);
452
- background-color: var(--ku-color-fill-0);
1039
+
1040
+ .ku-scrollbar::-webkit-scrollbar-track
1041
+ {
1042
+ background: transparent;
453
1043
  }
454
1044
 
455
- /* ===== Resizable 拖拽把手 ===== */
1045
+ .ku-scrollbar::-webkit-scrollbar-thumb
1046
+ {
1047
+ background: var(--ku-color-fill-2);
1048
+ border-radius: 4px;
1049
+ }
456
1050
 
457
- .ku-resizable-handle {
458
- position: absolute;
459
- z-index: 10;
1051
+ .ku-scrollbar::-webkit-scrollbar-thumb:hover
1052
+ {
1053
+ background: var(--ku-color-fill-1);
460
1054
  }
461
1055
 
462
- /* ===== Layout Sider 触发按钮 ===== */
1056
+ /* ===== 毛玻璃面 =====
1057
+ **为什么必须是类而不是内联样式:**
1058
+ 1. 组件的底色此前写在内联 style 里, 而内联优先级高于类 —— 只加类不改内联, 不透明底会把玻璃整个盖住(背景
1059
+ 不透明时 backdrop-filter 糊完立刻被自身底色覆盖, 等于白付开销)。故套用玻璃的面要把自己的 backgroundColor
1060
+ 从内联移除, 交给下面的类提供。
1061
+ 2. @supports 回退无法用内联样式表达, 只能落在类里。
1062
+ 各档的膜与半径对照表见 :root 第 8 节。 */
1063
+
1064
+ /* 容器档: 侧栏 / 卡片 / 面板(kg .app-sidebar / .kg-auth-card 是 blur(18px) saturate(118%), 那是历史起点、
1065
+ 不是标定基准 —— 当前基准是"背景的图和颜色要透得过来", 见 --ku-blur-base)。 */
1066
+ .ku-glass
1067
+ {
1068
+ background-color: var(--ku-color-glass);
1069
+ backdrop-filter: var(--ku-blur-lg);
1070
+ -webkit-backdrop-filter: var(--ku-blur-lg);
1071
+ }
463
1072
 
464
- .ku-layout-sider-trigger {
465
- cursor: pointer;
466
- text-align: center;
467
- padding: 8px 0;
468
- border-top: 1px solid var(--ku-color-border);
469
- background-color: var(--ku-color-bg-2);
470
- transition: background-color var(--ku-transition-fast);
1073
+ /* 头部档: 顶栏 / 底栏(app shell 的 Header, 比容器档更实一档 —— 下方内容滚过时不透字) */
1074
+ .ku-glass-head
1075
+ {
1076
+ background-color: var(--ku-color-glass-head);
1077
+ backdrop-filter: var(--ku-blur-lg);
1078
+ -webkit-backdrop-filter: var(--ku-blur-lg);
471
1079
  }
472
- .ku-layout-sider-trigger:hover {
473
- background-color: var(--ku-color-bg-3);
1080
+
1081
+ /* 浮层档: 下拉气泡 / 弹窗 / 浮层 */
1082
+ .ku-glass-overlay
1083
+ {
1084
+ background-color: var(--ku-color-glass-strong);
1085
+ backdrop-filter: var(--ku-blur-xl);
1086
+ -webkit-backdrop-filter: var(--ku-blur-xl);
1087
+ /* 磨砂颗粒叠在底色之上(见 --ku-glass-grain 的说明) */
1088
+ background-image: var(--ku-glass-grain);
474
1089
  }
475
1090
 
476
- /* ===== 移除原生控件样式 ===== */
1091
+ /* 选项面板档: Dropdown / Select 这类**选项列表**的菜单。
1092
+ **为什么不复用浮层档**: 浮层档的其余成员(Modal / SideSheet / Toast / Notification / Feedback)都是大面积、
1093
+ 稀疏的面 —— 半透底在那里是好事。选项面板正相反: 一百多像素宽、三十像素一行的密集文字**要逐行读**, 同样
1094
+ 0.34 的底, 背后只要有一行代码就会从菜单项文字之间透上来, 读的是叠印的两层字。读的密度不同, 底的厚度就必须
1095
+ 不同 —— 这是它单独成档的全部理由。它与浮层档是**并列关系, 不是"加强版"**, 用错档只会得到过薄或过厚的面。
1096
+ 两层 background-image: 上面是颗粒、下面是奶膜。奶膜**走 token 而不是写死在这里**, 因为它是全库唯一一处只有
1097
+ 单个主题有效的层 —— 写死在类规则里就是一句看不出问题的死代码, 抽成 token 才看得见亮色那份是空的。颗粒放上层
1098
+ 是为了保住它自己的对比度(奶膜压在上面会把噪点的明暗差一起压平), 故**颗粒层两个主题都留**, 只有奶膜随主题变。 */
1099
+ .ku-glass-menu
1100
+ {
1101
+ background-color: var(--ku-color-glass-menu);
1102
+ backdrop-filter: var(--ku-blur-menu);
1103
+ -webkit-backdrop-filter: var(--ku-blur-menu);
1104
+ background-image:
1105
+ var(--ku-glass-grain),
1106
+ var(--ku-glass-menu-film);
1107
+ }
477
1108
 
478
- .ku-input-number input[type="number"]::-webkit-inner-spin-button,
479
- .ku-input-number input[type="number"]::-webkit-outer-spin-button {
480
- -webkit-appearance: none;
481
- margin: 0;
1109
+ /* 小浮层档: Popover / Tooltip 的气泡。面积小, 所以比浮层档更透; 半径**比浮层档小得多**(7 vs 18px) ——
1110
+ 小面积的面本来就更容易看清背后, 再叠大半径只是白糊, 而这一档的 saturate 是五档最高(250%), 用来把背后的颜色
1111
+ 顶上来。
1112
+ 颗粒走通用那条: 这一档曾经有过自己的减半 token(--ku-glass-grain-tip), 已删除, 理由见 --ku-glass-grain 里那条
1113
+ "两个主题同向"的更正。 */
1114
+ .ku-glass-tip
1115
+ {
1116
+ background-color: var(--ku-color-glass-tip);
1117
+ backdrop-filter: var(--ku-blur-tip);
1118
+ -webkit-backdrop-filter: var(--ku-blur-tip);
1119
+ background-image: var(--ku-glass-grain);
482
1120
  }
483
- .ku-input-number input[type="number"] {
484
- -moz-appearance: textfield;
1121
+
1122
+ /* 弱档: 表格等大面积面 */
1123
+ .ku-glass-subtle
1124
+ {
1125
+ background-color: var(--ku-color-glass);
1126
+ backdrop-filter: var(--ku-blur-base);
1127
+ -webkit-backdrop-filter: var(--ku-blur-base);
485
1128
  }
486
1129
 
487
- /* ===== 滚动条美化 ===== */
1130
+ /* 遮罩档: Modal / SideSheet / Image 预览 / UserGuide 的模态遮罩, 以及 Cropper 的裁剪蒙版。
1131
+ 与 .ku-glass-* 各档**并列**而不是复用其一 —— 遮罩铺满视口, 是唯一"面积 = 屏幕"的玻璃面, 底色和模糊都要按
1132
+ "大面积 + 全屏合成开销"单独标定(见 --ku-blur-mask 的说明)。
1133
+ Cropper 是这里的例外: 它是"盖住一张图"而不是"盖住页面", 面积小得多, 用同一档只是因为"半透 + 磨砂"的观感
1134
+ 要求一致, 顺带省掉一组几乎同值的 token。 */
1135
+ .ku-mask
1136
+ {
1137
+ background-color: var(--ku-color-mask);
1138
+ backdrop-filter: var(--ku-blur-mask);
1139
+ -webkit-backdrop-filter: var(--ku-blur-mask);
1140
+ }
488
1141
 
489
- .ku-scrollbar::-webkit-scrollbar { width: 4px; height: 4px; }
490
- .ku-scrollbar::-webkit-scrollbar-track { background: transparent; }
491
- .ku-scrollbar::-webkit-scrollbar-thumb {
492
- background: var(--ku-color-fill-2);
493
- border-radius: 4px;
1142
+ /* UserGuide 的引导卡片: **不透明**面 —— 与上面各玻璃档并列, 但它不属于玻璃家族。
1143
+ 它身后的遮罩**挖了目标的洞**(见 Mask.renderHole), 于是同一个元素有两种底: 洞外是"遮罩压暗过的页面", 洞内是
1144
+ **没压暗的原始页面**(可以是一块近黑的 Monaco)。60% 的白膜盖不住这个差 —— 实测把 alpha 抬到 .84, 卡片落在近黑
1145
+ 与纯白上仍差 ΔE≈12: 抬高只是减轻、不能消除, 还顺带把卡片自己糊成一片。README"使用前提 3"给的逃生口正是这条:
1146
+ 需要叠层时让它们做兄弟, 或把内层换成不透明的实色面。这里走后者。
1147
+ bg-3 一条声明两个主题都对, 因为卡片坐的是**遮罩压过之后的**页面: 亮色 #e0e2e5 比压过的页面(#c2–#d1)亮
1148
+ 15–30/255, 暗色 #1a1f2b 同样明显更亮。附带省掉一次全屏 blur 的合成开销。
1149
+
1150
+ 这**不是** .ku-glass-overlay 的锅: Modal / SideSheet 也用它, 但它们的遮罩**没有洞**, 身后恒为"遮罩压过的
1151
+ 页面", 玻璃是稳的。问题只在"玻璃身后同时存在挖洞与不挖洞两种区域"。 */
1152
+ .ku-userguide-card
1153
+ {
1154
+ background-color: var(--ku-color-bg-3);
494
1155
  }
495
- .ku-scrollbar::-webkit-scrollbar-thumb:hover {
496
- background: var(--ku-color-fill-1);
1156
+
1157
+ /* 不支持 backdrop-filter 时退回不透明面 —— 否则半透明底会直接漏出下层内容, 文字互相叠印不可读 */
1158
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)))
1159
+ {
1160
+ .ku-glass,
1161
+ .ku-glass-subtle,
1162
+ .ku-glass-head
1163
+ {
1164
+ background-color: var(--ku-color-bg-3);
1165
+ }
1166
+
1167
+ /* 选项面板与浮层档退到同一档: 没有模糊时, 菜单那一档更厚的底再叠上颗粒只会显脏, 而它的底色本来就比浮层档
1168
+ 实, 退到 bg-2 已经足够压住背后的内容。 */
1169
+ .ku-glass-overlay,
1170
+ .ku-glass-menu
1171
+ {
1172
+ background-color: var(--ku-color-bg-2);
1173
+ }
1174
+
1175
+ /* 气泡退回原来的不透明档(fill-2 在暗色即 #2f343c, 正是 Tooltip 原本的底色) —— 拿不到模糊就不要半透明,
1176
+ 否则文字直接和背后的内容叠印。颗粒一并去掉: 不透明的面上噪点只会显脏, 起不到"磨砂"的作用。 */
1177
+ .ku-glass-tip
1178
+ {
1179
+ background-color: var(--ku-color-fill-2);
1180
+ background-image: none;
1181
+ }
1182
+
1183
+ /* 遮罩没有"更实一档"可退 —— 退回不透明就等于关灯, 那正是这次要改掉的观感。退成一层更深的半透明黑: 拿不到
1184
+ 模糊, 至少保住"背景还在"和"模态压暗"两件事。 */
1185
+ .ku-mask
1186
+ {
1187
+ background-color: rgba(var(--ku-grey-0), 0.62);
1188
+ }
1189
+
1190
+ /* 亮色不能跟着取第 0 档 —— 亮色第 0 档是纯白, 那会变成"往页面上刷一层白", 方向正好相反。改用第 9 档(该主题
1191
+ 最暗的一档)与更轻的 alpha, 与 --ku-color-mask 的亮色覆盖同源。 */
1192
+ :root[data-ku-theme="light"] .ku-mask
1193
+ {
1194
+ background-color: rgba(var(--ku-grey-9), 0.42);
1195
+ }
497
1196
  }