@icen.ai/ui 0.1.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.
@@ -0,0 +1,540 @@
1
+ /*
2
+ * Icen Design System — 风格配置 (Style Profiles)
3
+ *
4
+ * 这是颜色主题之上的第二层抽象:
5
+ * .style-modern → 默认现代风格(不覆盖)
6
+ * .style-retro → 8-bit / 红白机 / 像素风
7
+ * .style-terminal → 命令行 / CRT 终端(预留)
8
+ *
9
+ * 规则:
10
+ * 1. 这些类挂在 <html> 上,与 .clay/.piano/.art/.vangogh/.ink/.retro 共存。
11
+ * 2. 只覆盖与“风格”相关的变量:字体、圆角、阴影硬度、抗锯齿、图像渲染。
12
+ * 3. 颜色仍由 preset 决定,保持正交。
13
+ */
14
+
15
+ /* ══════════════════════════════════════════════════════════════
16
+ 字体资源
17
+ ══════════════════════════════════════════════════════════════ */
18
+
19
+ /* Press Start 2P — 经典 8-bit 像素字体(西文) */
20
+ @font-face {
21
+ font-family: "Pixel Retro";
22
+ src:
23
+ local("Press Start 2P"),
24
+ local("VT323"),
25
+ url("https://fonts.gstatic.com/s/pressstart2p/v15/e3t4euO8T-267oIAQAu6jDQyK3nVivM.woff2") format("woff2");
26
+ font-weight: 400;
27
+ font-style: normal;
28
+ font-display: swap;
29
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
30
+ }
31
+
32
+ /* 中文像素风回退:无通用免费像素中文字体,使用系统等宽/宋体保持清晰 */
33
+ @font-face {
34
+ font-family: "Pixel CJK Fallback";
35
+ src:
36
+ local("Zpix"),
37
+ local("SimSun"),
38
+ local("Songti SC"),
39
+ local("STSong"),
40
+ local("Noto Serif SC"),
41
+ local("PingFang SC"),
42
+ local("Microsoft YaHei");
43
+ font-weight: 400;
44
+ font-style: normal;
45
+ font-display: swap;
46
+ }
47
+
48
+ :root {
49
+ /* ══════════════════════════════════════════════════════════════
50
+ 风格底层 token(兜底值)
51
+ 由 .style-* 覆盖;保持与颜色 preset 正交。
52
+ ══════════════════════════════════════════════════════════════ */
53
+
54
+ /* ── Density 密度 ── */
55
+ --density-space-xs: 0.25rem;
56
+ --density-space-sm: 0.5rem;
57
+ --density-space-md: 0.75rem;
58
+ --density-space-lg: 1rem;
59
+ --density-input-height-sm: 28px;
60
+ --density-input-height-md: 36px;
61
+ --density-input-height-lg: 44px;
62
+ --density-font-size-xs: 11px;
63
+ --density-font-size-sm: 12px;
64
+ --density-font-size-md: 13px;
65
+ --density-font-size-lg: 14px;
66
+
67
+ /* ── Motion 动效 ── */
68
+ --duration-instant: 0ms;
69
+ --duration-fast: 150ms;
70
+ --duration-normal: 200ms;
71
+ --duration-slow: 300ms;
72
+ --ease-linear: linear;
73
+ --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
74
+ --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
75
+
76
+ /* ── Typography 字体 ── */
77
+ --font-body: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
78
+ --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
79
+ --font-mono-paper: ui-monospace, SFMono-Regular, 'JetBrains Mono', 'Courier New', monospace;
80
+ --font-heading: var(--font-body);
81
+ --letter-spacing-body: 0;
82
+ --letter-spacing-heading: 0;
83
+ --line-height-body: 1.5;
84
+ --line-height-heading: 1.2;
85
+ }
86
+
87
+ /* ══════════════════════════════════════════════════════════════
88
+ MODERN — 默认现代风格(兜底值即为现代值,显式声明便于阅读)
89
+ ══════════════════════════════════════════════════════════════ */
90
+
91
+ .style-modern {
92
+ /* ── Density ── */
93
+ --density-space-xs: 0.25rem;
94
+ --density-space-sm: 0.5rem;
95
+ --density-space-md: 0.75rem;
96
+ --density-space-lg: 1rem;
97
+ --density-input-height-sm: 28px;
98
+ --density-input-height-md: 36px;
99
+ --density-input-height-lg: 44px;
100
+ --density-font-size-xs: 11px;
101
+ --density-font-size-sm: 12px;
102
+ --density-font-size-md: 13px;
103
+ --density-font-size-lg: 14px;
104
+
105
+ /* ── Motion ── */
106
+ --duration-fast: 150ms;
107
+ --duration-normal: 200ms;
108
+ --duration-slow: 300ms;
109
+ --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
110
+
111
+ /* ── Typography ── */
112
+ --font-body: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
113
+ --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
114
+ --font-mono-paper: ui-monospace, SFMono-Regular, 'JetBrains Mono', 'Courier New', monospace;
115
+ --font-heading: var(--font-body);
116
+ --letter-spacing-body: 0;
117
+ --letter-spacing-heading: 0;
118
+ --line-height-body: 1.5;
119
+ --line-height-heading: 1.2;
120
+ }
121
+
122
+ /* ══════════════════════════════════════════════════════════════
123
+ RETRO — 8-bit / 红白机 / 像素风
124
+ ══════════════════════════════════════════════════════════════ */
125
+
126
+ .style-retro {
127
+ /* ── Density:像素风更紧凑 ── */
128
+ --density-space-xs: 0.125rem;
129
+ --density-space-sm: 0.25rem;
130
+ --density-space-md: 0.5rem;
131
+ --density-space-lg: 0.75rem;
132
+ --density-input-height-sm: 24px;
133
+ --density-input-height-md: 32px;
134
+ --density-input-height-lg: 40px;
135
+ --density-font-size-xs: 9px;
136
+ --density-font-size-sm: 10px;
137
+ --density-font-size-md: 11px;
138
+ --density-font-size-lg: 12px;
139
+
140
+ /* ── Motion:像素风瞬间切换 ── */
141
+ --duration-fast: 0ms;
142
+ --duration-normal: 0ms;
143
+ --duration-slow: 0ms;
144
+ --ease-out: linear;
145
+
146
+ /* ── Typography:像素字体 ── */
147
+ --font-body: "Pixel Retro", "Pixel CJK Fallback", "Press Start 2P", "VT323", "SimSun", "Songti SC", "STSong", monospace;
148
+ --font-mono: "Pixel Retro", "VT323", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
149
+ --font-mono-paper: "Pixel Retro", "JetBrains Mono", "Courier New", monospace;
150
+ --font-heading: "Pixel Retro", "Press Start 2P", "VT323", var(--font-body);
151
+ --letter-spacing-body: 0.02em;
152
+ --letter-spacing-heading: 0.04em;
153
+ --line-height-body: 1.5;
154
+ --line-height-heading: 1.2;
155
+
156
+ /* ── 圆角:像素风几乎无圆角 ── */
157
+ --radius-xs: 0px;
158
+ --radius-sm: 0px;
159
+ --radius-md: 2px;
160
+ --radius-lg: 2px;
161
+ --radius-xl: 2px;
162
+ --radius-full: 0px;
163
+
164
+ /* ── 滚动条 ── */
165
+ --token-scrollbar-size: 10px;
166
+
167
+ /* ── 渲染 ── */
168
+ image-rendering: pixelated;
169
+ -webkit-font-smoothing: none;
170
+ -moz-osx-font-smoothing: unset;
171
+ }
172
+
173
+ /* 全局排版覆盖 */
174
+ .style-retro body {
175
+ font-family: "Numeric Math", var(--font-body);
176
+ line-height: var(--line-height-body);
177
+ letter-spacing: var(--letter-spacing-body);
178
+ }
179
+
180
+ /* 标题强化像素感 */
181
+ .style-retro h1,
182
+ .style-retro h2,
183
+ .style-retro h3,
184
+ .style-retro h4,
185
+ .style-retro h5,
186
+ .style-retro h6 {
187
+ font-family: var(--font-heading);
188
+ letter-spacing: var(--letter-spacing-heading);
189
+ line-height: var(--line-height-heading);
190
+ text-transform: uppercase;
191
+ }
192
+
193
+ /* ══════════════════════════════════════════════════════════════
194
+ 按钮 / 可点击元素 — 8-bit 像素按钮
195
+ ══════════════════════════════════════════════════════════════ */
196
+
197
+ .style-retro .og-pressable,
198
+ .style-retro button,
199
+ .style-retro [role="button"],
200
+ .style-retro input[type="button"],
201
+ .style-retro input[type="submit"],
202
+ .style-retro input[type="reset"] {
203
+ position: relative;
204
+ border-radius: var(--radius-md);
205
+ border: 2px solid var(--token-line-strong);
206
+ box-shadow:
207
+ inset -2px -2px 0 var(--token-line-soft),
208
+ inset 2px 2px 0 var(--token-surface-strong),
209
+ 2px 2px 0 var(--token-line);
210
+ transition: all var(--duration-fast) var(--ease-out);
211
+ }
212
+
213
+ .style-retro .og-pressable::after,
214
+ .style-retro button::after {
215
+ display: none;
216
+ }
217
+
218
+ /* 悬停:像素高亮 */
219
+ .style-retro .og-pressable:hover,
220
+ .style-retro button:hover {
221
+ outline: 2px solid var(--token-accent);
222
+ outline-offset: -2px;
223
+ }
224
+
225
+ /* 按下:内移 + 阴影消失 */
226
+ .style-retro .og-pressable:active,
227
+ .style-retro button:active,
228
+ .style-retro [role="button"]:active {
229
+ transform: translate(2px, 2px);
230
+ box-shadow:
231
+ inset -2px -2px 0 var(--token-line-soft),
232
+ inset 2px 2px 0 var(--token-surface-strong);
233
+ }
234
+
235
+ /* 禁用状态 */
236
+ .style-retro .og-pressable:where(:disabled, [aria-disabled="true"], [data-disabled]),
237
+ .style-retro button:disabled {
238
+ transform: none;
239
+ box-shadow: none;
240
+ outline: none;
241
+ opacity: 0.5;
242
+ }
243
+
244
+ /* ══════════════════════════════════════════════════════════════
245
+ 输入框 / 表单元素 — 像素输入框
246
+ ══════════════════════════════════════════════════════════════ */
247
+
248
+ .style-retro .og-control,
249
+ .style-retro input,
250
+ .style-retro textarea,
251
+ .style-retro select {
252
+ border-radius: var(--radius-md);
253
+ border: 2px solid var(--token-line);
254
+ background: var(--token-bg);
255
+ box-shadow:
256
+ inset 2px 2px 0 var(--token-line-soft),
257
+ inset -1px -1px 0 var(--token-surface-strong);
258
+ transition: none;
259
+ }
260
+
261
+ .style-retro .og-control::after {
262
+ display: none;
263
+ }
264
+
265
+ /* 被 og-control / vn-editable-field 容器包裹的输入框:自身边框透明化,
266
+ 完全交给外层容器承担像素边框,避免常驻/聚焦状态出现双层内框。 */
267
+ .style-retro .og-control input:not([type="checkbox"]):not([type="radio"]),
268
+ .style-retro .og-control textarea,
269
+ .style-retro .og-control select,
270
+ .style-retro .vn-editable-field input:not([type="checkbox"]):not([type="radio"]),
271
+ .style-retro .vn-editable-field textarea,
272
+ .style-retro .vn-editable-field [contenteditable="true"] {
273
+ border-color: transparent !important;
274
+ box-shadow: none !important;
275
+ background: transparent !important;
276
+ }
277
+
278
+ .style-retro input:hover,
279
+ .style-retro textarea:hover,
280
+ .style-retro select:hover,
281
+ .style-retro .og-control:hover,
282
+ .style-retro .vn-editable-field:hover {
283
+ border-color: var(--token-accent);
284
+ }
285
+
286
+ .style-retro .og-control:focus-within,
287
+ .style-retro .vn-editable-field:focus-within {
288
+ border-color: var(--token-accent);
289
+ box-shadow:
290
+ inset 2px 2px 0 var(--token-line-soft),
291
+ inset -1px -1px 0 var(--token-surface-strong);
292
+ outline: 2px solid var(--token-accent);
293
+ outline-offset: -2px;
294
+ }
295
+
296
+ /* 文本输入区自身无焦点环,完全交给外层容器 */
297
+ .style-retro input:focus,
298
+ .style-retro textarea:focus,
299
+ .style-retro select:focus,
300
+ .style-retro input:focus-visible,
301
+ .style-retro textarea:focus-visible,
302
+ .style-retro select:focus-visible,
303
+ .style-retro [contenteditable="true"]:focus,
304
+ .style-retro [contenteditable="true"]:focus-visible {
305
+ outline: none !important;
306
+ box-shadow: none !important;
307
+ border-color: transparent !important;
308
+ }
309
+
310
+ /* 占位符文字 */
311
+ .style-retro input::placeholder,
312
+ .style-retro textarea::placeholder {
313
+ color: var(--token-text-faint);
314
+ opacity: 0.7;
315
+ }
316
+
317
+ /* ══════════════════════════════════════════════════════════════
318
+ 开关 / 复选框 — 像素开关
319
+ ══════════════════════════════════════════════════════════════ */
320
+
321
+ .style-retro input[type="checkbox"],
322
+ .style-retro input[type="radio"] {
323
+ appearance: none;
324
+ width: 16px;
325
+ height: 16px;
326
+ border: 2px solid var(--token-line-strong);
327
+ background: var(--token-bg);
328
+ box-shadow:
329
+ inset -2px -2px 0 var(--token-line-soft),
330
+ inset 2px 2px 0 var(--token-surface-strong);
331
+ cursor: pointer;
332
+ }
333
+
334
+ .style-retro input[type="checkbox"]:checked,
335
+ .style-retro input[type="radio"]:checked {
336
+ background: var(--token-accent);
337
+ border-color: var(--token-accent);
338
+ box-shadow:
339
+ inset 2px 2px 0 color-mix(in srgb, var(--token-on-accent) 50%, transparent),
340
+ inset -2px -2px 0 color-mix(in srgb, var(--token-accent-cold) 30%, transparent);
341
+ }
342
+
343
+ .style-retro input[type="checkbox"]:checked::after {
344
+ content: "";
345
+ display: block;
346
+ width: 6px;
347
+ height: 10px;
348
+ margin: 1px 0 0 4px;
349
+ border: solid var(--token-on-accent);
350
+ border-width: 0 2px 2px 0;
351
+ transform: rotate(45deg);
352
+ }
353
+
354
+ .style-retro input[type="radio"] {
355
+ border-radius: 0;
356
+ }
357
+
358
+ .style-retro input[type="radio"]:checked::after {
359
+ content: "";
360
+ display: block;
361
+ width: 6px;
362
+ height: 6px;
363
+ margin: 3px;
364
+ background: var(--token-on-accent);
365
+ }
366
+
367
+ /* ══════════════════════════════════════════════════════════════
368
+ 卡片 / 面板 / 表面 — 硬像素边框
369
+ ══════════════════════════════════════════════════════════════ */
370
+
371
+ .style-retro .surface-elevated,
372
+ .style-retro [class*="shadow-[var(--token-shadow-card)"] {
373
+ box-shadow:
374
+ 2px 2px 0 var(--token-line);
375
+ border-width: 2px;
376
+ border-style: solid;
377
+ border-color: var(--token-line-strong);
378
+ }
379
+
380
+ /* 禁用平滑悬停提升 */
381
+ .style-retro .og-surface-lift:hover {
382
+ transform: none;
383
+ box-shadow:
384
+ 2px 2px 0 var(--token-accent);
385
+ border-color: var(--token-accent);
386
+ }
387
+
388
+ /* ══════════════════════════════════════════════════════════════
389
+ 滚动条 — 方块像素滚动条
390
+ ══════════════════════════════════════════════════════════════ */
391
+
392
+ .style-retro * {
393
+ scrollbar-width: thin;
394
+ scrollbar-color: var(--token-accent) var(--token-bg-soft);
395
+ }
396
+
397
+ .style-retro ::-webkit-scrollbar {
398
+ width: var(--token-scrollbar-size);
399
+ height: var(--token-scrollbar-size);
400
+ }
401
+
402
+ .style-retro ::-webkit-scrollbar-track {
403
+ background: var(--token-bg-soft);
404
+ border: 1px solid var(--token-line);
405
+ }
406
+
407
+ .style-retro ::-webkit-scrollbar-thumb {
408
+ background: var(--token-accent);
409
+ border: 1px solid var(--token-line-strong);
410
+ border-radius: 0;
411
+ }
412
+
413
+ .style-retro ::-webkit-scrollbar-thumb:hover {
414
+ background: var(--token-accent-cold);
415
+ }
416
+
417
+ .style-retro ::-webkit-scrollbar-button {
418
+ display: block;
419
+ width: var(--token-scrollbar-size);
420
+ height: var(--token-scrollbar-size);
421
+ background: var(--token-bg-soft);
422
+ border: 1px solid var(--token-line);
423
+ }
424
+
425
+ .style-retro ::-webkit-scrollbar-button:hover {
426
+ background: var(--token-accent-subtle);
427
+ }
428
+
429
+ /* ══════════════════════════════════════════════════════════════
430
+ 光标 / caret
431
+ ══════════════════════════════════════════════════════════════ */
432
+
433
+ .style-retro * {
434
+ caret-color: var(--token-accent);
435
+ }
436
+
437
+ /* ══════════════════════════════════════════════════════════════
438
+ 悬停效果 — 像素高亮
439
+ ══════════════════════════════════════════════════════════════ */
440
+
441
+ .style-retro a:hover,
442
+ .style-retro [role="link"]:hover {
443
+ text-decoration: underline;
444
+ text-decoration-style: dashed;
445
+ text-underline-offset: 3px;
446
+ }
447
+
448
+ /* ══════════════════════════════════════════════════════════════
449
+ Markdown / 富文本 — 禁用圆角
450
+ ══════════════════════════════════════════════════════════════ */
451
+
452
+ .style-retro .markdown-body img,
453
+ .style-retro .markdown-body blockquote,
454
+ .style-retro .markdown-body code,
455
+ .style-retro .markdown-body pre {
456
+ border-radius: 0;
457
+ }
458
+
459
+ /* ══════════════════════════════════════════════════════════════
460
+ RETRO 全局硬化 — 处理无法仅靠 token 表达的现代风残留
461
+ ══════════════════════════════════════════════════════════════ */
462
+
463
+ /* 禁用现代毛玻璃,用实色面板替代 */
464
+ .style-retro .backdrop-blur-sm,
465
+ .style-retro .backdrop-blur-md,
466
+ .style-retro .backdrop-blur-xl,
467
+ .style-retro .backdrop-blur-2xl {
468
+ backdrop-filter: none;
469
+ -webkit-backdrop-filter: none;
470
+ }
471
+
472
+ /* 兜底:覆盖仍使用固定 Tailwind 圆角工具类的组件/页面元素。
473
+ 组件层已迁移到 radiusClass() 读取 --radius-*,但 feature 页面和
474
+ 第三方类名可能仍残留 rounded-*,这里做最后一层保险。 */
475
+ .style-retro .rounded-none { border-radius: 0; }
476
+ .style-retro .rounded-sm,
477
+ .style-retro .rounded,
478
+ .style-retro .rounded-md,
479
+ .style-retro .rounded-lg,
480
+ .style-retro .rounded-xl,
481
+ .style-retro .rounded-2xl,
482
+ .style-retro .rounded-3xl {
483
+ border-radius: var(--radius-md);
484
+ }
485
+ /* Note: we do NOT override .rounded-full globally. Components that should be
486
+ theme-aware use radiusClass('full') which reads --radius-full; elements that
487
+ are inherently circular (e.g. loading spinners) keep Tailwind's rounded-full. */
488
+
489
+ /* 兜底:现代柔和阴影在 retro 下转为硬像素投影 */
490
+ .style-retro .shadow-sm,
491
+ .style-retro .shadow-md,
492
+ .style-retro .shadow-lg,
493
+ .style-retro .shadow-xl,
494
+ .style-retro .shadow-2xl {
495
+ box-shadow: var(--token-shadow-card);
496
+ }
497
+
498
+ /* 非文本元素的硬像素焦点环(已在 retro-effects.css 有基础,这里强化 specificity) */
499
+ .style-retro :focus-visible:not(input):not(textarea):not(select):not([contenteditable="true"]) {
500
+ outline: 2px solid var(--token-accent);
501
+ outline-offset: -2px;
502
+ box-shadow: none;
503
+ border-radius: var(--radius-md);
504
+ }
505
+
506
+ /* 非输入按钮在 retro 下禁用现代渐变高光(::after 渐变由 .og-pressable 提供) */
507
+ .style-retro .og-pressable::after {
508
+ display: none;
509
+ }
510
+
511
+ /* ══════════════════════════════════════════════════════════════
512
+ TERMINAL — 命令行 / CRT 终端(预留,可组合任意 dark preset)
513
+ ══════════════════════════════════════════════════════════════ */
514
+
515
+ .style-terminal {
516
+ /* ── 字体 ── */
517
+ --font-body: ui-monospace, SFMono-Regular, "JetBrains Mono", "Courier New", "Noto Sans Mono CJK SC", "SimSun", monospace;
518
+ --font-mono: ui-monospace, SFMono-Regular, "JetBrains Mono", "Consolas", "Noto Sans Mono CJK SC", monospace;
519
+ --font-mono-paper: "JetBrains Mono", "Courier New", monospace;
520
+
521
+ /* ── 圆角 ── */
522
+ --radius-xs: 0px;
523
+ --radius-sm: 0px;
524
+ --radius-md: 0px;
525
+ --radius-lg: 0px;
526
+ --radius-xl: 0px;
527
+ --radius-full: 0px;
528
+
529
+ /* ── 滚动条 ── */
530
+ --token-scrollbar-size: 8px;
531
+
532
+ /* ── 渲染 ── */
533
+ -webkit-font-smoothing: antialiased;
534
+ -moz-osx-font-smoothing: grayscale;
535
+ }
536
+
537
+ .style-terminal body {
538
+ font-family: var(--font-body);
539
+ line-height: 1.4;
540
+ }
@@ -0,0 +1,49 @@
1
+ /*
2
+ * @icen.ai/ui — Typography Tokens(icen canonical)
3
+ * 美学基调:等宽数字精密感 × 衬线书卷气(宋体标题)
4
+ * 默认(:root)即 icen 品牌形态;.style-modern 显式回退 system-ui 栈(见 style-profiles.css)
5
+ */
6
+
7
+ /* ── 数学/等宽数字字体(数字密集区的精密感) ── */
8
+ @font-face {
9
+ font-family: "Numeric Math";
10
+ src:
11
+ local("Cambria Math"),
12
+ local("STIX Two Math"),
13
+ local("Latin Modern Math"),
14
+ local("Asana Math");
15
+ unicode-range: U+0025-003A, U+00A5, U+2212, U+223C;
16
+ }
17
+
18
+ :root {
19
+ /* ── icen 品牌字体栈 ──
20
+ body/mono:IBM Plex Mono(未安装时回退系统等宽,行为与 accounts 一致,不打包 webfont)
21
+ heading:CJK 宋体系(页面标题/品牌名的书卷气) */
22
+ --font-body: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Consolas, 'Courier New', monospace;
23
+ --font-mono: var(--font-body);
24
+ --font-heading: 'Songti SC', 'STSong', 'Noto Serif SC', 'Source Han Serif SC', SimSun, serif;
25
+ --font-cjk: var(--font-heading);
26
+ --line-height-body: 1.7;
27
+ --line-height-heading: 1.2;
28
+ }
29
+
30
+ /* ── 全局排版 ── */
31
+ body {
32
+ font-family: "Numeric Math", var(--font-body);
33
+ line-height: var(--line-height-body);
34
+ -webkit-font-smoothing: antialiased;
35
+ -moz-osx-font-smoothing: grayscale;
36
+ font-feature-settings: "rlig" 1, "calt" 1;
37
+ font-variant-numeric: lining-nums tabular-nums;
38
+ }
39
+
40
+ h1, h2, h3, h4, h5, h6 {
41
+ font-family: var(--font-heading);
42
+ line-height: var(--line-height-heading);
43
+ }
44
+
45
+ /* ── 数字密集区工具类 ── */
46
+ .font-math {
47
+ font-family: "Numeric Math", math, var(--font-body);
48
+ font-variant-numeric: lining-nums tabular-nums;
49
+ }