@toyonix/web-kit 0.0.0-stage → 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.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +68 -2
  3. package/config/eslint.js +68 -0
  4. package/config/prettier.js +20 -0
  5. package/config/tsconfig.base.json +22 -0
  6. package/dist/css/base.css +58 -0
  7. package/dist/css/components.css +915 -0
  8. package/dist/css/fonts/LICENSE-Newsreader.txt +93 -0
  9. package/dist/css/fonts/LICENSE-Space-Grotesk.txt +93 -0
  10. package/dist/css/fonts/LICENSE-Space-Mono.txt +93 -0
  11. package/dist/css/fonts/newsreader-latin-ext-opsz-italic.woff2 +0 -0
  12. package/dist/css/fonts/newsreader-latin-ext-opsz-normal.woff2 +0 -0
  13. package/dist/css/fonts/newsreader-latin-opsz-italic.woff2 +0 -0
  14. package/dist/css/fonts/newsreader-latin-opsz-normal.woff2 +0 -0
  15. package/dist/css/fonts/space-grotesk-latin-400-normal.woff2 +0 -0
  16. package/dist/css/fonts/space-grotesk-latin-500-normal.woff2 +0 -0
  17. package/dist/css/fonts/space-grotesk-latin-700-normal.woff2 +0 -0
  18. package/dist/css/fonts/space-grotesk-latin-ext-400-normal.woff2 +0 -0
  19. package/dist/css/fonts/space-grotesk-latin-ext-500-normal.woff2 +0 -0
  20. package/dist/css/fonts/space-grotesk-latin-ext-700-normal.woff2 +0 -0
  21. package/dist/css/fonts/space-mono-latin-400-normal.woff2 +0 -0
  22. package/dist/css/fonts/space-mono-latin-700-normal.woff2 +0 -0
  23. package/dist/css/fonts/space-mono-latin-ext-400-normal.woff2 +0 -0
  24. package/dist/css/fonts/space-mono-latin-ext-700-normal.woff2 +0 -0
  25. package/dist/css/fonts.css +141 -0
  26. package/dist/css/index.css +10 -0
  27. package/dist/css/tailwind.css +46 -0
  28. package/dist/css/tokens.css +66 -0
  29. package/dist/env.d.ts +28 -0
  30. package/dist/env.js +62 -0
  31. package/dist/index.d.ts +4 -0
  32. package/dist/index.js +4 -0
  33. package/dist/next/index.d.ts +36 -0
  34. package/dist/next/index.js +103 -0
  35. package/dist/react/Alert.d.ts +8 -0
  36. package/dist/react/Alert.js +16 -0
  37. package/dist/react/AppLink.d.ts +11 -0
  38. package/dist/react/AppLink.js +12 -0
  39. package/dist/react/AppShell.d.ts +20 -0
  40. package/dist/react/AppShell.js +94 -0
  41. package/dist/react/Badge.d.ts +10 -0
  42. package/dist/react/Badge.js +29 -0
  43. package/dist/react/Button.d.ts +16 -0
  44. package/dist/react/Button.js +36 -0
  45. package/dist/react/Card.d.ts +21 -0
  46. package/dist/react/Card.js +61 -0
  47. package/dist/react/CodeBlock.d.ts +8 -0
  48. package/dist/react/CodeBlock.js +16 -0
  49. package/dist/react/Dialog.d.ts +16 -0
  50. package/dist/react/Dialog.js +33 -0
  51. package/dist/react/DropdownMenu.d.ts +12 -0
  52. package/dist/react/DropdownMenu.js +36 -0
  53. package/dist/react/Table.d.ts +5 -0
  54. package/dist/react/Table.js +15 -0
  55. package/dist/react/Tabs.d.ts +9 -0
  56. package/dist/react/Tabs.js +26 -0
  57. package/dist/react/ThemeScript.d.ts +9 -0
  58. package/dist/react/ThemeScript.js +15 -0
  59. package/dist/react/ThemeToggle.d.ts +5 -0
  60. package/dist/react/ThemeToggle.js +22 -0
  61. package/dist/react/Tooltip.d.ts +13 -0
  62. package/dist/react/Tooltip.js +21 -0
  63. package/dist/react/cx.d.ts +4 -0
  64. package/dist/react/cx.js +7 -0
  65. package/dist/react/form.d.ts +19 -0
  66. package/dist/react/form.js +76 -0
  67. package/dist/react/index.d.ts +21 -0
  68. package/dist/react/index.js +21 -0
  69. package/dist/react/layout.d.ts +7 -0
  70. package/dist/react/layout.js +29 -0
  71. package/dist/react/typography.d.ts +23 -0
  72. package/dist/react/typography.js +46 -0
  73. package/dist/react/use-registry.d.ts +9 -0
  74. package/dist/react/use-registry.js +41 -0
  75. package/dist/react/use-theme.d.ts +18 -0
  76. package/dist/react/use-theme.js +46 -0
  77. package/dist/registry/build.d.ts +28 -0
  78. package/dist/registry/build.js +91 -0
  79. package/dist/registry/index.d.ts +49 -0
  80. package/dist/registry/index.js +84 -0
  81. package/dist/slugs.d.ts +15 -0
  82. package/dist/slugs.js +37 -0
  83. package/dist/storage/index.d.ts +39 -0
  84. package/dist/storage/index.js +123 -0
  85. package/dist/theme.d.ts +19 -0
  86. package/dist/theme.js +26 -0
  87. package/package.json +111 -4
@@ -0,0 +1,915 @@
1
+ /*
2
+ * Component styles (spec §5.2). Loaded in the `components` cascade layer.
3
+ * Class names (`tx-*`) are public API: React components emit them, and non-React sites can
4
+ * use them directly. Renaming one is a breaking change.
5
+ */
6
+
7
+ /* ============================== layout ============================== */
8
+
9
+ .tx-container {
10
+ max-width: 1120px;
11
+ margin: 0 auto;
12
+ padding: 0 24px;
13
+ }
14
+
15
+ .tx-section {
16
+ padding: 48px 0;
17
+ }
18
+
19
+ .tx-stack {
20
+ display: grid;
21
+ gap: 28px;
22
+ }
23
+
24
+ .tx-row {
25
+ display: flex;
26
+ flex-wrap: wrap;
27
+ align-items: center;
28
+ gap: 20px;
29
+ }
30
+
31
+ .tx-grid-2 {
32
+ display: grid;
33
+ grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
34
+ gap: 32px;
35
+ align-items: start;
36
+ }
37
+
38
+ .tx-muted {
39
+ color: var(--tx-text-muted);
40
+ }
41
+
42
+ /* ============================== shell ============================== */
43
+
44
+ .tx-header {
45
+ position: sticky;
46
+ top: 0;
47
+ z-index: 20;
48
+ background: var(--tx-bg);
49
+ border-bottom: var(--tx-border-width) solid var(--tx-border);
50
+ }
51
+
52
+ .tx-header__inner {
53
+ display: flex;
54
+ align-items: center;
55
+ gap: 16px;
56
+ min-height: 64px;
57
+ }
58
+
59
+ .tx-logo {
60
+ display: flex;
61
+ align-items: center;
62
+ gap: 10px;
63
+ color: var(--tx-text);
64
+ font-family: var(--tx-font-heading);
65
+ font-size: 23px;
66
+ font-style: italic;
67
+ font-weight: 600;
68
+ letter-spacing: var(--tx-heading-tracking);
69
+ text-decoration: none;
70
+ }
71
+
72
+ .tx-logo__mark {
73
+ display: grid;
74
+ place-items: center;
75
+ width: 30px;
76
+ height: 30px;
77
+ border: var(--tx-border-width) solid var(--tx-border);
78
+ border-radius: var(--tx-radius-sm);
79
+ background: var(--tx-accent);
80
+ color: var(--tx-accent-contrast);
81
+ font-family: var(--tx-font-heading);
82
+ font-size: 15px;
83
+ font-style: italic;
84
+ font-weight: 700;
85
+ }
86
+
87
+ .tx-nav {
88
+ display: flex;
89
+ flex-wrap: wrap;
90
+ gap: 2px;
91
+ margin-left: auto;
92
+ }
93
+
94
+ .tx-nav a {
95
+ padding: 6px 12px;
96
+ border-radius: var(--tx-radius-sm);
97
+ color: var(--tx-text-muted);
98
+ font-size: 15px;
99
+ font-weight: 500;
100
+ text-decoration: none;
101
+ }
102
+
103
+ .tx-nav a:hover {
104
+ background: var(--tx-surface-2);
105
+ color: var(--tx-text);
106
+ }
107
+
108
+ .tx-nav a[aria-current] {
109
+ background: var(--tx-accent);
110
+ color: var(--tx-accent-contrast);
111
+ outline: var(--tx-border-width) solid var(--tx-border);
112
+ }
113
+
114
+ .tx-subnav {
115
+ border-bottom: var(--tx-border-width) solid var(--tx-border);
116
+ background: var(--tx-surface);
117
+ }
118
+
119
+ .tx-subnav__inner {
120
+ display: flex;
121
+ flex-wrap: wrap;
122
+ gap: 4px 20px;
123
+ padding: 10px 24px;
124
+ }
125
+
126
+ .tx-subnav a {
127
+ color: var(--tx-text-muted);
128
+ font-family: var(--tx-font-mono);
129
+ font-size: 13px;
130
+ text-decoration: none;
131
+ }
132
+
133
+ .tx-subnav a:hover,
134
+ .tx-subnav a[aria-current] {
135
+ color: var(--tx-text);
136
+ text-decoration: underline;
137
+ text-decoration-color: var(--tx-accent);
138
+ text-decoration-thickness: 3px;
139
+ }
140
+
141
+ .tx-icon-btn {
142
+ display: grid;
143
+ place-items: center;
144
+ width: 38px;
145
+ height: 38px;
146
+ border: var(--tx-border-width) solid var(--tx-border);
147
+ border-radius: var(--tx-radius-sm);
148
+ background: var(--tx-surface);
149
+ box-shadow: var(--tx-btn-shadow);
150
+ color: var(--tx-text);
151
+ font-size: 17px;
152
+ cursor: pointer;
153
+ }
154
+
155
+ .tx-footer {
156
+ margin-top: 48px;
157
+ padding: 32px 0;
158
+ border-top: var(--tx-border-width) solid var(--tx-border);
159
+ color: var(--tx-text-muted);
160
+ font-size: 14px;
161
+ }
162
+
163
+ .tx-footer__inner {
164
+ display: flex;
165
+ flex-wrap: wrap;
166
+ justify-content: space-between;
167
+ gap: 16px;
168
+ }
169
+
170
+ .tx-footer a {
171
+ color: inherit;
172
+ }
173
+
174
+ /* ============================== type ============================== */
175
+
176
+ .tx-display {
177
+ margin: 0 0 0.5em;
178
+ font-size: clamp(46px, 7vw, 84px);
179
+ line-height: 1.05;
180
+ }
181
+
182
+ /* Signature marker highlight: <em> in display headings, or any .tx-mark. */
183
+ .tx-display em,
184
+ .tx-mark {
185
+ padding: 0 0.08em;
186
+ background: linear-gradient(transparent 58%, var(--tx-accent) 58%, var(--tx-accent) 92%, transparent 92%);
187
+ color: var(--tx-text);
188
+ font-style: italic;
189
+ -webkit-box-decoration-break: clone;
190
+ box-decoration-break: clone;
191
+ }
192
+
193
+ .tx-lead {
194
+ max-width: 60ch;
195
+ margin: 0 0 32px;
196
+ color: var(--tx-text-muted);
197
+ font-size: 19px;
198
+ }
199
+
200
+ .tx-eyebrow {
201
+ margin: 0 0 16px;
202
+ color: var(--tx-text-muted);
203
+ font-family: var(--tx-font-mono);
204
+ font-size: 13px;
205
+ letter-spacing: 0.06em;
206
+ text-transform: uppercase;
207
+ }
208
+
209
+ .tx-section-label {
210
+ display: inline-block;
211
+ margin: 0 0 24px;
212
+ padding: 4px 14px 6px;
213
+ background: var(--tx-text);
214
+ color: var(--tx-bg);
215
+ font-family: var(--tx-font-heading);
216
+ font-size: 22px;
217
+ font-style: italic;
218
+ font-weight: 500;
219
+ letter-spacing: 0;
220
+ line-height: 1.15;
221
+ text-transform: none;
222
+ transform: rotate(-1.5deg);
223
+ }
224
+
225
+ /* ============================== buttons ============================== */
226
+
227
+ .tx-btn-row {
228
+ display: flex;
229
+ flex-wrap: wrap;
230
+ align-items: center;
231
+ gap: 12px;
232
+ }
233
+
234
+ .tx-btn {
235
+ display: inline-flex;
236
+ align-items: center;
237
+ gap: 8px;
238
+ padding: 10px 18px;
239
+ border: var(--tx-border-width) solid var(--tx-border);
240
+ border-radius: var(--tx-radius);
241
+ box-shadow: var(--tx-btn-shadow);
242
+ font: inherit;
243
+ font-size: 15px;
244
+ font-weight: 600;
245
+ line-height: 1.2;
246
+ text-decoration: none;
247
+ cursor: pointer;
248
+ transition:
249
+ transform 0.12s,
250
+ box-shadow 0.12s,
251
+ background 0.12s,
252
+ filter 0.12s;
253
+ }
254
+
255
+ .tx-btn:hover {
256
+ transform: translate(var(--tx-hover-shift));
257
+ }
258
+
259
+ .tx-btn--primary {
260
+ background: var(--tx-accent);
261
+ color: var(--tx-accent-contrast);
262
+ }
263
+
264
+ .tx-btn--primary:hover {
265
+ filter: brightness(1.07);
266
+ }
267
+
268
+ .tx-btn--secondary {
269
+ background: var(--tx-surface);
270
+ color: var(--tx-text);
271
+ }
272
+
273
+ .tx-btn--secondary:hover {
274
+ background: var(--tx-surface-2);
275
+ }
276
+
277
+ .tx-btn--ghost {
278
+ border-color: transparent;
279
+ background: transparent;
280
+ box-shadow: none;
281
+ color: var(--tx-text);
282
+ }
283
+
284
+ .tx-btn--ghost:hover {
285
+ background: var(--tx-surface-2);
286
+ }
287
+
288
+ .tx-btn--danger {
289
+ background: var(--tx-danger);
290
+ color: #fff;
291
+ }
292
+
293
+ .tx-btn:disabled,
294
+ .tx-btn[aria-disabled="true"] {
295
+ opacity: 0.45;
296
+ cursor: not-allowed;
297
+ transform: none;
298
+ }
299
+
300
+ /* ============================== cards ============================== */
301
+
302
+ .tx-card {
303
+ padding: 24px;
304
+ border: var(--tx-border-width) solid var(--tx-border);
305
+ border-radius: var(--tx-radius);
306
+ background: var(--tx-surface);
307
+ box-shadow: var(--tx-shadow);
308
+ }
309
+
310
+ .tx-card--link {
311
+ display: flex;
312
+ flex-direction: column;
313
+ gap: 6px;
314
+ color: inherit;
315
+ text-decoration: none;
316
+ transition:
317
+ transform 0.15s,
318
+ box-shadow 0.15s,
319
+ border-color 0.15s;
320
+ }
321
+
322
+ .tx-card--link:hover {
323
+ box-shadow: var(--tx-shadow-hover);
324
+ transform: translate(var(--tx-hover-shift));
325
+ }
326
+
327
+ .tx-card__top {
328
+ display: flex;
329
+ align-items: center;
330
+ justify-content: space-between;
331
+ gap: 12px;
332
+ margin-bottom: 8px;
333
+ }
334
+
335
+ .tx-card__meta {
336
+ color: var(--tx-text-muted);
337
+ font-family: var(--tx-font-mono);
338
+ font-size: 13px;
339
+ }
340
+
341
+ .tx-card__title {
342
+ margin: 0 0 16px;
343
+ font-size: 20px;
344
+ }
345
+
346
+ .tx-card--link .tx-card__title {
347
+ margin: 0;
348
+ }
349
+
350
+ .tx-card__body {
351
+ margin: 0 0 10px;
352
+ color: var(--tx-text-muted);
353
+ }
354
+
355
+ .tx-card__cta {
356
+ margin-top: 14px;
357
+ color: var(--tx-accent-text);
358
+ font-size: 14px;
359
+ font-weight: 600;
360
+ }
361
+
362
+ /* Color-blocked, tilted cards (the project grid). Cards cycle card-1 → card-2 → card-3. */
363
+ .tx-card-grid {
364
+ display: grid;
365
+ grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
366
+ gap: 20px;
367
+ }
368
+
369
+ .tx-card-grid > .tx-card {
370
+ --tx-text: var(--tx-on-card);
371
+ --tx-text-muted: #2b2b2b;
372
+ --tx-accent-text: var(--tx-on-card);
373
+ color: var(--tx-on-card);
374
+ }
375
+
376
+ .tx-card-grid > .tx-card:nth-child(3n + 1) {
377
+ background: var(--tx-card-1);
378
+ transform: rotate(-0.7deg);
379
+ }
380
+
381
+ .tx-card-grid > .tx-card:nth-child(3n + 2) {
382
+ background: var(--tx-card-2);
383
+ transform: rotate(0.6deg);
384
+ }
385
+
386
+ .tx-card-grid > .tx-card:nth-child(3n + 3) {
387
+ background: var(--tx-card-3);
388
+ transform: rotate(-0.4deg);
389
+ }
390
+
391
+ /* Must out-rank the tilt rules above: hovering straightens the card and lifts it. */
392
+ .tx-card-grid > .tx-card.tx-card--link:hover {
393
+ transform: rotate(0deg) translate(var(--tx-hover-shift));
394
+ }
395
+
396
+ .tx-card-grid .tx-card__title {
397
+ font-size: 27px;
398
+ }
399
+
400
+ .tx-card-grid .tx-tag,
401
+ .tx-card-grid .tx-badge {
402
+ border: 2px solid var(--tx-on-card);
403
+ background: #fff;
404
+ color: var(--tx-on-card);
405
+ }
406
+
407
+ /* ============================== tags, badges ============================== */
408
+
409
+ .tx-tags {
410
+ display: flex;
411
+ flex-wrap: wrap;
412
+ gap: 6px;
413
+ margin-top: auto;
414
+ }
415
+
416
+ .tx-tag {
417
+ padding: 2px 8px;
418
+ border-radius: var(--tx-radius-sm);
419
+ background: var(--tx-surface-2);
420
+ color: var(--tx-text-muted);
421
+ font-family: var(--tx-font-mono);
422
+ font-size: 12px;
423
+ }
424
+
425
+ .tx-badges {
426
+ display: flex;
427
+ flex-wrap: wrap;
428
+ gap: 8px;
429
+ }
430
+
431
+ .tx-badge {
432
+ --tx-badge-color: var(--tx-text-muted);
433
+ display: inline-flex;
434
+ align-items: center;
435
+ gap: 6px;
436
+ padding: 1px 10px;
437
+ border: 1px solid color-mix(in srgb, currentColor 35%, transparent);
438
+ border-radius: var(--tx-radius-pill);
439
+ background: color-mix(in srgb, var(--tx-badge-color) 12%, transparent);
440
+ color: var(--tx-badge-color);
441
+ font-size: 12px;
442
+ font-weight: 600;
443
+ line-height: 1.6;
444
+ }
445
+
446
+ .tx-badge::before {
447
+ content: "";
448
+ width: 6px;
449
+ height: 6px;
450
+ border-radius: var(--tx-radius-pill);
451
+ background: currentColor;
452
+ }
453
+
454
+ .tx-badge--success {
455
+ --tx-badge-color: var(--tx-success);
456
+ }
457
+
458
+ .tx-badge--warning {
459
+ --tx-badge-color: var(--tx-warning);
460
+ }
461
+
462
+ .tx-badge--danger {
463
+ --tx-badge-color: var(--tx-danger);
464
+ }
465
+
466
+ .tx-badge--accent {
467
+ --tx-badge-color: var(--tx-accent-text);
468
+ }
469
+
470
+ .tx-badge--neutral {
471
+ background: var(--tx-surface-2);
472
+ }
473
+
474
+ /* ============================== alerts ============================== */
475
+
476
+ .tx-alert {
477
+ --tx-alert-color: var(--tx-ring);
478
+ padding: 12px 16px;
479
+ border: var(--tx-border-width) solid color-mix(in srgb, var(--tx-alert-color) 30%, var(--tx-border));
480
+ border-left: 4px solid var(--tx-alert-color);
481
+ border-radius: var(--tx-radius);
482
+ background: color-mix(in srgb, var(--tx-alert-color) 9%, var(--tx-surface));
483
+ box-shadow: 3px 3px 0 var(--tx-border);
484
+ font-size: 15px;
485
+ }
486
+
487
+ .tx-alert__title {
488
+ display: block;
489
+ margin-bottom: 2px;
490
+ font-weight: 700;
491
+ }
492
+
493
+ .tx-alert--success {
494
+ --tx-alert-color: var(--tx-success);
495
+ }
496
+
497
+ .tx-alert--warning {
498
+ --tx-alert-color: var(--tx-warning);
499
+ }
500
+
501
+ .tx-alert--danger {
502
+ --tx-alert-color: var(--tx-danger);
503
+ }
504
+
505
+ /* ============================== prose (articles) ============================== */
506
+
507
+ .tx-prose {
508
+ max-width: 68ch;
509
+ font-family: var(--tx-font-prose);
510
+ font-size: 20px;
511
+ line-height: 1.75;
512
+ }
513
+
514
+ .tx-prose p {
515
+ margin: 0 0 1em;
516
+ }
517
+
518
+ .tx-prose h2 {
519
+ margin: 0 0 0.5em;
520
+ font-size: clamp(28px, 3.4vw, 40px);
521
+ }
522
+
523
+ .tx-prose h3 {
524
+ margin: 1.6em 0 0.5em;
525
+ font-size: 20px;
526
+ }
527
+
528
+ .tx-prose :not(pre) > code {
529
+ padding: 0.12em 0.4em;
530
+ border: 1px solid var(--tx-border);
531
+ border-radius: var(--tx-radius-sm);
532
+ background: var(--tx-surface-2);
533
+ font-size: 0.86em;
534
+ }
535
+
536
+ .tx-prose ol,
537
+ .tx-prose ul {
538
+ margin: 0 0 1em;
539
+ padding-left: 1.3em;
540
+ }
541
+
542
+ /* Restated because resets (Tailwind preflight) remove list markers. */
543
+ .tx-prose ol {
544
+ list-style: decimal;
545
+ }
546
+
547
+ .tx-prose ul {
548
+ list-style: disc;
549
+ }
550
+
551
+ .tx-prose li {
552
+ margin: 0.3em 0;
553
+ }
554
+
555
+ .tx-prose blockquote {
556
+ margin: 1.5em 0;
557
+ padding: 4px 0 4px 20px;
558
+ border-left: 6px solid var(--tx-accent);
559
+ color: var(--tx-text);
560
+ font-family: var(--tx-font-heading);
561
+ font-size: 1.35em;
562
+ font-style: italic;
563
+ }
564
+
565
+ .tx-dropcap::first-letter,
566
+ .tx-prose--dropcap > p:first-of-type::first-letter {
567
+ float: left;
568
+ padding: 0.08em 0.1em 0 0;
569
+ color: var(--tx-accent-text);
570
+ font-family: var(--tx-font-heading);
571
+ font-size: 3.7em;
572
+ line-height: 0.82;
573
+ }
574
+
575
+ /* ============================== code ============================== */
576
+
577
+ .tx-code,
578
+ .tx-prose pre {
579
+ margin: 0 0 1.4em;
580
+ padding: 18px 20px;
581
+ overflow: auto;
582
+ border: var(--tx-border-width) solid var(--tx-border);
583
+ border-radius: var(--tx-radius);
584
+ background: var(--tx-code-bg);
585
+ box-shadow: var(--tx-shadow);
586
+ color: var(--tx-code-text);
587
+ font-family: var(--tx-font-mono);
588
+ font-size: 14px;
589
+ line-height: 1.6;
590
+ }
591
+
592
+ .tx-code__comment {
593
+ color: color-mix(in srgb, var(--tx-code-text) 50%, transparent);
594
+ font-style: italic;
595
+ }
596
+
597
+ .tx-code__key {
598
+ color: var(--tx-code-key);
599
+ }
600
+
601
+ .tx-code__string {
602
+ color: var(--tx-code-string);
603
+ }
604
+
605
+ /* ============================== forms ============================== */
606
+
607
+ .tx-form {
608
+ display: grid;
609
+ gap: 16px;
610
+ }
611
+
612
+ .tx-field {
613
+ display: grid;
614
+ gap: 6px;
615
+ }
616
+
617
+ .tx-label {
618
+ font-size: 14px;
619
+ font-weight: 600;
620
+ }
621
+
622
+ .tx-hint {
623
+ color: var(--tx-text-muted);
624
+ font-size: 13px;
625
+ }
626
+
627
+ .tx-input,
628
+ .tx-select,
629
+ .tx-textarea {
630
+ width: 100%;
631
+ padding: 10px 12px;
632
+ border: var(--tx-border-width) solid var(--tx-border);
633
+ border-radius: var(--tx-radius-sm);
634
+ outline: none;
635
+ background: var(--tx-bg);
636
+ color: var(--tx-text);
637
+ font: inherit;
638
+ font-size: 15px;
639
+ transition:
640
+ border-color 0.12s,
641
+ box-shadow 0.12s;
642
+ }
643
+
644
+ .tx-input:focus,
645
+ .tx-select:focus,
646
+ .tx-textarea:focus {
647
+ border-color: var(--tx-ring);
648
+ box-shadow: 4px 4px 0 var(--tx-ring);
649
+ }
650
+
651
+ .tx-textarea {
652
+ min-height: 84px;
653
+ resize: vertical;
654
+ }
655
+
656
+ .tx-check {
657
+ display: flex;
658
+ align-items: center;
659
+ gap: 10px;
660
+ font-size: 15px;
661
+ cursor: pointer;
662
+ }
663
+
664
+ .tx-check input:not(.tx-switch) {
665
+ width: 18px;
666
+ height: 18px;
667
+ margin: 0;
668
+ accent-color: var(--tx-ring);
669
+ }
670
+
671
+ .tx-switch {
672
+ position: relative;
673
+ flex: none;
674
+ width: 40px;
675
+ height: 22px;
676
+ margin: 0;
677
+ border: var(--tx-border-width) solid var(--tx-border);
678
+ border-radius: var(--tx-radius-pill);
679
+ background: var(--tx-surface-2);
680
+ cursor: pointer;
681
+ -webkit-appearance: none;
682
+ appearance: none;
683
+ transition: background 0.15s;
684
+ }
685
+
686
+ .tx-switch::before {
687
+ content: "";
688
+ position: absolute;
689
+ top: 2px;
690
+ left: 2px;
691
+ width: 13px;
692
+ height: 13px;
693
+ border-radius: var(--tx-radius-pill);
694
+ background: var(--tx-text-muted);
695
+ transition:
696
+ transform 0.15s,
697
+ background 0.15s;
698
+ }
699
+
700
+ .tx-switch:checked {
701
+ background: var(--tx-accent);
702
+ }
703
+
704
+ .tx-switch:checked::before {
705
+ background: var(--tx-accent-contrast);
706
+ transform: translateX(18px);
707
+ }
708
+
709
+ /* ============================== table ============================== */
710
+
711
+ .tx-table-wrap {
712
+ overflow: auto;
713
+ border: var(--tx-border-width) solid var(--tx-border);
714
+ border-radius: var(--tx-radius);
715
+ background: var(--tx-surface);
716
+ box-shadow: var(--tx-shadow);
717
+ }
718
+
719
+ .tx-table {
720
+ width: 100%;
721
+ border-collapse: collapse;
722
+ font-size: 14px;
723
+ }
724
+
725
+ .tx-table th {
726
+ padding: 10px 14px;
727
+ border-bottom: var(--tx-border-width) solid var(--tx-border);
728
+ color: var(--tx-text-muted);
729
+ font-size: 12px;
730
+ font-weight: 600;
731
+ letter-spacing: 0.06em;
732
+ text-align: left;
733
+ text-transform: uppercase;
734
+ }
735
+
736
+ .tx-table td {
737
+ padding: 12px 14px;
738
+ border-bottom: 1px solid var(--tx-border);
739
+ }
740
+
741
+ .tx-table tr:last-child td {
742
+ border-bottom: none;
743
+ }
744
+
745
+ /* ============================== overlays (Radix) ============================== */
746
+
747
+ .tx-overlay {
748
+ position: fixed;
749
+ inset: 0;
750
+ z-index: 50;
751
+ background: color-mix(in srgb, #0f1530 55%, transparent);
752
+ }
753
+
754
+ .tx-dialog {
755
+ position: fixed;
756
+ top: 50%;
757
+ left: 50%;
758
+ z-index: 51;
759
+ width: min(520px, calc(100vw - 32px));
760
+ max-height: calc(100vh - 64px);
761
+ overflow: auto;
762
+ padding: 24px;
763
+ border: var(--tx-border-width) solid var(--tx-border);
764
+ background: var(--tx-surface);
765
+ box-shadow: var(--tx-shadow-hover);
766
+ color: var(--tx-text);
767
+ transform: translate(-50%, -50%);
768
+ }
769
+
770
+ .tx-dialog__title {
771
+ margin: 0 0 8px;
772
+ font-size: 26px;
773
+ }
774
+
775
+ .tx-dialog__description {
776
+ margin: 0 0 20px;
777
+ color: var(--tx-text-muted);
778
+ }
779
+
780
+ .tx-dialog__close {
781
+ position: absolute;
782
+ top: 12px;
783
+ right: 12px;
784
+ }
785
+
786
+ .tx-menu {
787
+ z-index: 60;
788
+ min-width: 180px;
789
+ padding: 6px;
790
+ border: var(--tx-border-width) solid var(--tx-border);
791
+ background: var(--tx-surface);
792
+ box-shadow: var(--tx-shadow);
793
+ color: var(--tx-text);
794
+ }
795
+
796
+ .tx-menu__item {
797
+ display: flex;
798
+ align-items: center;
799
+ gap: 8px;
800
+ padding: 8px 10px;
801
+ outline: none;
802
+ font-size: 15px;
803
+ cursor: pointer;
804
+ user-select: none;
805
+ }
806
+
807
+ .tx-menu__item[data-highlighted] {
808
+ background: var(--tx-accent);
809
+ color: var(--tx-accent-contrast);
810
+ }
811
+
812
+ .tx-menu__item[data-disabled] {
813
+ opacity: 0.45;
814
+ cursor: not-allowed;
815
+ }
816
+
817
+ .tx-menu__separator {
818
+ height: 2px;
819
+ margin: 6px 0;
820
+ background: var(--tx-border);
821
+ }
822
+
823
+ .tx-menu__label {
824
+ padding: 6px 10px 4px;
825
+ color: var(--tx-text-muted);
826
+ font-family: var(--tx-font-mono);
827
+ font-size: 12px;
828
+ letter-spacing: 0.06em;
829
+ text-transform: uppercase;
830
+ }
831
+
832
+ .tx-tooltip {
833
+ z-index: 70;
834
+ padding: 4px 10px;
835
+ background: var(--tx-text);
836
+ color: var(--tx-bg);
837
+ font-family: var(--tx-font-mono);
838
+ font-size: 12px;
839
+ line-height: 1.5;
840
+ }
841
+
842
+ .tx-tabs__list {
843
+ display: flex;
844
+ flex-wrap: wrap;
845
+ gap: 4px;
846
+ margin-bottom: 20px;
847
+ padding-bottom: 8px;
848
+ border-bottom: var(--tx-border-width) solid var(--tx-border);
849
+ }
850
+
851
+ .tx-tabs__trigger {
852
+ padding: 6px 12px;
853
+ border: none;
854
+ background: transparent;
855
+ color: var(--tx-text-muted);
856
+ font: inherit;
857
+ font-size: 15px;
858
+ font-weight: 500;
859
+ cursor: pointer;
860
+ }
861
+
862
+ .tx-tabs__trigger:hover {
863
+ background: var(--tx-surface-2);
864
+ color: var(--tx-text);
865
+ }
866
+
867
+ .tx-tabs__trigger[data-state="active"] {
868
+ background: var(--tx-accent);
869
+ color: var(--tx-accent-contrast);
870
+ outline: var(--tx-border-width) solid var(--tx-border);
871
+ }
872
+
873
+ /* ============================== motion ============================== */
874
+
875
+ @media (prefers-reduced-motion: reduce) {
876
+ .tx-btn,
877
+ .tx-card--link,
878
+ .tx-switch,
879
+ .tx-switch::before,
880
+ .tx-input,
881
+ .tx-select,
882
+ .tx-textarea {
883
+ transition: none;
884
+ }
885
+
886
+ .tx-btn:hover,
887
+ .tx-card--link:hover,
888
+ .tx-card-grid > .tx-card.tx-card--link:hover {
889
+ transform: none;
890
+ }
891
+ }
892
+
893
+ /* ============================== a11y ============================== */
894
+
895
+ .tx-skip-link {
896
+ position: absolute;
897
+ top: 8px;
898
+ left: 8px;
899
+ z-index: 100;
900
+ padding: 8px 14px;
901
+ border: var(--tx-border-width) solid var(--tx-border);
902
+ background: var(--tx-accent);
903
+ color: var(--tx-accent-contrast);
904
+ font-weight: 700;
905
+ transform: translateY(-200%);
906
+ }
907
+
908
+ .tx-skip-link:focus {
909
+ transform: none;
910
+ }
911
+
912
+ .tx-main {
913
+ display: block;
914
+ min-height: 50vh;
915
+ }