@godxjp/ui 16.5.0 → 16.6.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.
@@ -170,7 +170,7 @@
170
170
 
171
171
  .ui-skeleton-block {
172
172
  border-radius: var(--skeleton-radius);
173
- background: var(--skeleton-background);
173
+ background: var(--skeleton-background, hsl(var(--muted)));
174
174
  animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
175
175
  }
176
176
 
@@ -27,13 +27,15 @@
27
27
  * `[data-accent]` rail-width override below can win within the same cascade layer. */
28
28
  border-width: 1px;
29
29
  border-style: solid;
30
- border-color: hsl(var(--card-border));
30
+ border-color: hsl(var(--card-border, var(--border)));
31
31
  border-radius: var(--card-radius);
32
32
  /* Fill = base card colour with an opt-in role tint washed over it (--card-tint default
33
- * transparent → byte-identical at rest). Tint layer sits ABOVE the base colour. */
33
+ * transparent → byte-identical at rest). Tint layer sits ABOVE the base colour.
34
+ * --card-background defaults to the LIVE --card role at the call site (re-resolves under a
35
+ * scoped theme); a service overrides --card-background to win. */
34
36
  background:
35
37
  linear-gradient(var(--card-tint), var(--card-tint)),
36
- hsl(var(--card-background));
38
+ hsl(var(--card-background, var(--card)));
37
39
  color: hsl(var(--card-foreground));
38
40
  /* Resting elevation + opt-in brand glow — both quiet no-ops by default so a service theme can
39
41
  * lift (--card-shadow) and/or glow (--card-glow) every card with no markup change. */
@@ -126,7 +128,7 @@
126
128
  align-items: center;
127
129
  gap: var(--space-inline-md);
128
130
  padding: var(--card-space-header-y) var(--card-space-inset);
129
- border-block: 1px solid hsl(var(--card-border));
131
+ border-block: 1px solid hsl(var(--card-border, var(--border)));
130
132
  }
131
133
 
132
134
  [data-slot="card-bar"]:first-child {
@@ -154,8 +156,10 @@
154
156
  }
155
157
 
156
158
  .ui-card-header--banded {
157
- border-bottom: var(--card-header-border-bottom);
158
- background-color: hsl(var(--card-header-background) / var(--card-header-background-alpha));
159
+ border-bottom: var(--card-header-border-bottom, 1px solid hsl(var(--card-border, var(--border))));
160
+ background-color: hsl(
161
+ var(--card-header-background, var(--muted)) / var(--card-header-background-alpha)
162
+ );
159
163
  }
160
164
 
161
165
  [data-slot="card-header"][data-banded] {
@@ -343,7 +347,7 @@
343
347
  }
344
348
 
345
349
  [data-slot="card-footer"][data-separated] {
346
- border-top: 1px solid hsl(var(--card-border));
350
+ border-top: 1px solid hsl(var(--card-border, var(--border)));
347
351
  /* Divided band → symmetric vertical padding (border-aware), in sync with a banded header. */
348
352
  padding-block: var(--card-space-divided-y);
349
353
  justify-content: flex-end;
@@ -401,8 +405,8 @@
401
405
  height: var(--stat-card-icon-size);
402
406
  margin-bottom: var(--stat-card-gap);
403
407
  border-radius: var(--stat-card-icon-radius);
404
- background: var(--stat-card-icon-background);
405
- color: var(--stat-card-icon-foreground);
408
+ background: var(--stat-card-icon-background, hsl(var(--primary) / 0.1));
409
+ color: var(--stat-card-icon-foreground, hsl(var(--primary)));
406
410
  }
407
411
 
408
412
  [data-slot="stat-card-icon"] svg {
@@ -50,13 +50,13 @@
50
50
  }
51
51
 
52
52
  .ui-toggle[data-state="on"] {
53
- background: var(--toggle-on-background);
53
+ background: var(--toggle-on-background, hsl(var(--primary)));
54
54
  color: hsl(var(--primary-foreground));
55
55
  }
56
56
 
57
57
  .ui-toggle:focus-visible {
58
58
  outline: none;
59
- box-shadow: 0 0 0 3px hsl(var(--focus-ring-color) / 0.35);
59
+ box-shadow: 0 0 0 3px hsl(var(--focus-ring-color, var(--ring)) / 0.35);
60
60
  }
61
61
 
62
62
  .ui-toggle:disabled,
@@ -85,7 +85,7 @@
85
85
 
86
86
  .ui-button:focus-visible {
87
87
  outline: none;
88
- box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color));
88
+ box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color, var(--ring)));
89
89
  }
90
90
 
91
91
  .ui-button:disabled {
@@ -287,7 +287,7 @@
287
287
  .ui-slider-thumb:focus-visible,
288
288
  .ui-switch:focus-visible {
289
289
  outline: none;
290
- box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color));
290
+ box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color, var(--ring)));
291
291
  }
292
292
 
293
293
  .ui-checkbox:disabled,
@@ -299,7 +299,7 @@
299
299
  }
300
300
 
301
301
  .ui-checkbox[data-state="checked"] {
302
- background: var(--checkbox-checked-background);
302
+ background: var(--checkbox-checked-background, hsl(var(--primary)));
303
303
  color: hsl(var(--primary-foreground));
304
304
  }
305
305
 
@@ -336,7 +336,7 @@
336
336
  }
337
337
 
338
338
  .ui-switch[data-state="checked"] {
339
- background: var(--switch-checked-background);
339
+ background: var(--switch-checked-background, hsl(var(--primary)));
340
340
  }
341
341
 
342
342
  .ui-switch[data-state="unchecked"] {
@@ -374,13 +374,13 @@
374
374
  flex-grow: 1;
375
375
  overflow: hidden;
376
376
  border-radius: var(--radius-pill);
377
- background: var(--slider-track-background);
377
+ background: var(--slider-track-background, hsl(var(--primary) / 0.2));
378
378
  }
379
379
 
380
380
  .ui-slider-range {
381
381
  position: absolute;
382
382
  height: 100%;
383
- background: var(--slider-range-background);
383
+ background: var(--slider-range-background, hsl(var(--primary)));
384
384
  }
385
385
 
386
386
  .ui-slider-thumb {
@@ -656,7 +656,7 @@
656
656
  }
657
657
  .ui-otp-slot[data-active="true"] {
658
658
  z-index: 1;
659
- box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color));
659
+ box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color, var(--ring)));
660
660
  }
661
661
  .ui-otp-container:has(.ui-otp-input[aria-invalid="true"]) .ui-otp-slot {
662
662
  border-color: hsl(var(--destructive));
@@ -727,7 +727,7 @@
727
727
  fill: currentColor;
728
728
  }
729
729
  .ui-rating-star:focus-visible {
730
- outline: var(--focus-ring-width) solid hsl(var(--focus-ring-color));
730
+ outline: var(--focus-ring-width) solid hsl(var(--focus-ring-color, var(--ring)));
731
731
  outline-offset: 2px;
732
732
  border-radius: var(--radius-sm);
733
733
  }
@@ -745,8 +745,8 @@
745
745
  background: hsl(var(--background));
746
746
  }
747
747
  .ui-tag-input:focus-within {
748
- box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color));
749
- border-color: hsl(var(--focus-ring-color));
748
+ box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color, var(--ring)));
749
+ border-color: hsl(var(--focus-ring-color, var(--ring)));
750
750
  }
751
751
  .ui-tag-input-disabled {
752
752
  opacity: 0.6;
@@ -12,7 +12,7 @@
12
12
  /* Tint washes over the role background (default transparent = no-op, rule #44). */
13
13
  background:
14
14
  linear-gradient(var(--avatar-tint), var(--avatar-tint)),
15
- var(--avatar-background);
15
+ var(--avatar-background, hsl(var(--muted)));
16
16
  color: hsl(var(--muted-foreground));
17
17
  font-size: var(--font-size-base);
18
18
  font-weight: var(--font-weight-medium);
@@ -30,7 +30,7 @@
30
30
  height: 100%;
31
31
  align-items: center;
32
32
  justify-content: center;
33
- background: var(--avatar-background);
33
+ background: var(--avatar-background, hsl(var(--muted)));
34
34
  }
35
35
 
36
36
  .ui-progress {
@@ -43,13 +43,13 @@
43
43
  height: 0.5rem;
44
44
  overflow: hidden;
45
45
  border-radius: var(--radius-pill);
46
- background: var(--progress-track-background);
46
+ background: var(--progress-track-background, hsl(var(--secondary)));
47
47
  }
48
48
 
49
49
  .ui-progress-bar {
50
50
  height: 100%;
51
51
  border-radius: inherit;
52
- background: var(--progress-fill-background);
52
+ background: var(--progress-fill-background, hsl(var(--success)));
53
53
  }
54
54
 
55
55
  .ui-progress[data-tone="warning"] .ui-progress-bar {
@@ -78,8 +78,8 @@
78
78
  }
79
79
 
80
80
  .ui-tree-item[data-active="true"] {
81
- border-color: var(--tree-item-active-border);
82
- background: var(--tree-item-active-background);
81
+ border-color: var(--tree-item-active-border, hsl(var(--primary) / 0.3));
82
+ background: var(--tree-item-active-background, hsl(var(--primary) / 0.05));
83
83
  }
84
84
 
85
85
  .ui-tree-item[data-depth="1"] {
@@ -154,7 +154,7 @@
154
154
  place-items: center;
155
155
  border: 1px solid transparent;
156
156
  border-radius: var(--radius-pill);
157
- background: var(--timeline-dot-done-background);
157
+ background: var(--timeline-dot-done-background, hsl(var(--success)));
158
158
  color: hsl(var(--success-foreground));
159
159
  font-size: var(--timeline-note-font-size);
160
160
  font-weight: var(--font-weight-medium);
@@ -163,14 +163,14 @@
163
163
 
164
164
  /* done → success fill. */
165
165
  .ui-timeline-dot[data-status="done"] {
166
- background: var(--timeline-dot-done-background);
166
+ background: var(--timeline-dot-done-background, hsl(var(--success)));
167
167
  color: hsl(var(--success-foreground));
168
168
  }
169
169
 
170
170
  /* current → primary fill + ring (also the legacy data-current shorthand). */
171
171
  .ui-timeline-dot[data-status="current"],
172
172
  .ui-timeline-dot[data-current="true"] {
173
- background: var(--timeline-dot-current-background);
173
+ background: var(--timeline-dot-current-background, hsl(var(--primary)));
174
174
  color: hsl(var(--primary-foreground));
175
175
  box-shadow: 0 0 0 3px hsl(var(--primary) / 0.18);
176
176
  }
@@ -205,7 +205,7 @@
205
205
 
206
206
  /* The segment below a done/current step reads as travelled (completed). */
207
207
  .ui-timeline-line[data-completed="true"] {
208
- background: var(--timeline-line-completed-background);
208
+ background: var(--timeline-line-completed-background, hsl(var(--primary)));
209
209
  }
210
210
 
211
211
  .ui-timeline-head {
@@ -259,7 +259,7 @@
259
259
  text-decoration: underline;
260
260
  }
261
261
  .ui-accordion-trigger:focus-visible {
262
- outline: var(--focus-ring-width) solid hsl(var(--focus-ring-color));
262
+ outline: var(--focus-ring-width) solid hsl(var(--focus-ring-color, var(--ring)));
263
263
  outline-offset: 2px;
264
264
  border-radius: var(--radius-sm);
265
265
  }
@@ -386,7 +386,7 @@
386
386
  }
387
387
 
388
388
  .ui-carousel-dot:focus-visible {
389
- outline: var(--focus-ring-width) solid hsl(var(--focus-ring-color));
389
+ outline: var(--focus-ring-width) solid hsl(var(--focus-ring-color, var(--ring)));
390
390
  outline-offset: 2px;
391
391
  }
392
392
 
@@ -444,7 +444,7 @@
444
444
  align-items: flex-start;
445
445
  }
446
446
  [data-slot="list-row"]:not(:last-child) {
447
- border-block-end: var(--list-row-border);
447
+ border-block-end: var(--list-row-border, 1px solid hsl(var(--border)));
448
448
  }
449
449
  [data-slot="list-row-leading"] {
450
450
  display: inline-flex;
@@ -83,8 +83,8 @@
83
83
  }
84
84
 
85
85
  .ui-time-input:focus-visible {
86
- border-color: hsl(var(--focus-ring-color));
87
- box-shadow: 0 0 0 3px hsl(var(--focus-ring-color) / 0.3);
86
+ border-color: hsl(var(--focus-ring-color, var(--ring)));
87
+ box-shadow: 0 0 0 3px hsl(var(--focus-ring-color, var(--ring)) / 0.3);
88
88
  }
89
89
 
90
90
  .ui-time-input[aria-invalid="true"] {
@@ -497,7 +497,10 @@
497
497
  width: 3rem;
498
498
  height: 3rem;
499
499
  border-radius: var(--radius-pill);
500
- background-color: hsl(var(--muted));
500
+ /* Medallion fill + glyph colour read their knobs, defaulting to the LIVE --muted /
501
+ * --muted-foreground roles at the call site (re-resolves under a scoped theme). */
502
+ background-color: var(--empty-state-icon-tint, hsl(var(--muted)));
503
+ color: var(--empty-state-icon-foreground, hsl(var(--muted-foreground)));
501
504
  }
502
505
  }
503
506
 
@@ -55,8 +55,8 @@
55
55
  .ui-menubar-sub-trigger:hover,
56
56
  .ui-navigation-menu-link:hover,
57
57
  .ui-navigation-menu-item:hover {
58
- background: var(--menubar-item-hover-background);
59
- color: var(--menubar-item-hover-foreground);
58
+ background: var(--menubar-item-hover-background, hsl(var(--accent)));
59
+ color: var(--menubar-item-hover-foreground, hsl(var(--accent-foreground)));
60
60
  }
61
61
 
62
62
  .ui-context-menu-item[data-state="open"],
@@ -68,8 +68,8 @@
68
68
  .ui-menubar-sub-trigger[data-state="open"],
69
69
  .ui-navigation-menu-link[data-highlighted],
70
70
  .ui-navigation-menu-item[data-focus-visible] {
71
- background: var(--menubar-item-hover-background);
72
- color: var(--menubar-item-hover-foreground);
71
+ background: var(--menubar-item-hover-background, hsl(var(--accent)));
72
+ color: var(--menubar-item-hover-foreground, hsl(var(--accent-foreground)));
73
73
  }
74
74
 
75
75
  .ui-context-menu-item[data-variant="destructive"],
@@ -184,8 +184,8 @@
184
184
 
185
185
  .ui-menubar-trigger[data-state="open"],
186
186
  .ui-menubar-sub-trigger[data-state="open"] {
187
- background: var(--menubar-item-hover-background);
188
- color: var(--menubar-item-hover-foreground);
187
+ background: var(--menubar-item-hover-background, hsl(var(--accent)));
188
+ color: var(--menubar-item-hover-foreground, hsl(var(--accent-foreground)));
189
189
  }
190
190
 
191
191
  .ui-navigation-menu {
@@ -270,8 +270,8 @@
270
270
  * selected nav row a brand treatment — e.g. a gold tint + gold text on a navy sidebar — without
271
271
  * forking CSS. Defaults are byte-identical to the hover state. */
272
272
  .sb-nav-item[data-active="true"] {
273
- background: var(--sidebar-item-active-background);
274
- color: var(--sidebar-item-active-foreground);
273
+ background: var(--sidebar-item-active-background, hsl(var(--accent)));
274
+ color: var(--sidebar-item-active-foreground, hsl(var(--foreground)));
275
275
  font-weight: var(--font-weight-medium);
276
276
  }
277
277
 
@@ -362,12 +362,12 @@
362
362
 
363
363
  .sb-nav-item--sub[data-active="true"] {
364
364
  background: transparent;
365
- color: var(--sidebar-item-active-color);
365
+ color: var(--sidebar-item-active-color, hsl(var(--primary)));
366
366
  font-weight: 500;
367
367
  }
368
368
 
369
369
  .sb-nav-item--sub[data-active="true"]::before {
370
- background: var(--sidebar-item-active-tint);
370
+ background: var(--sidebar-item-active-tint, hsl(var(--primary)));
371
371
  opacity: 1;
372
372
  }
373
373
 
@@ -417,7 +417,7 @@
417
417
  }
418
418
 
419
419
  .sb-user:focus-visible {
420
- box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color) / 0.45);
420
+ box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color, var(--ring)) / 0.45);
421
421
  }
422
422
 
423
423
  .sb-user-avatar {
@@ -660,7 +660,7 @@
660
660
  }
661
661
 
662
662
  .tb-icon-btn:focus-visible {
663
- box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color) / 0.45);
663
+ box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color, var(--ring)) / 0.45);
664
664
  }
665
665
 
666
666
  .tb-bell {
@@ -8,10 +8,10 @@
8
8
  padding: var(--table-cell-padding-y) var(--table-cell-space-x);
9
9
  text-align: start;
10
10
  vertical-align: middle;
11
- background: var(--table-header-background);
11
+ background: var(--table-header-background, hsl(var(--muted)));
12
12
  font-size: var(--table-head-font-size);
13
13
  font-weight: var(--font-weight-medium);
14
- color: var(--table-header-foreground);
14
+ color: var(--table-header-foreground, hsl(var(--muted-foreground)));
15
15
  white-space: nowrap;
16
16
  }
17
17
 
@@ -97,7 +97,7 @@
97
97
  /* Zebra striping (opt-in via the `striped` prop). Selected rows keep their
98
98
  * own emphasis, so they are excluded from the stripe. */
99
99
  .ui-data-table-surface[data-striped] tbody tr:nth-child(even):not([data-state="selected"]) {
100
- background-color: var(--table-row-striped-background);
100
+ background-color: var(--table-row-striped-background, hsl(var(--muted) / 0.4));
101
101
  }
102
102
 
103
103
  /* Empty-state cell hosts the built-in EmptyState (which brings its own padding). */
@@ -110,7 +110,7 @@
110
110
  }
111
111
 
112
112
  [data-slot="card-content"][data-flush] .ui-data-table-toolbar {
113
- border-bottom: 1px solid hsl(var(--card-border));
113
+ border-bottom: 1px solid hsl(var(--card-border, var(--border)));
114
114
  padding: var(--card-space-header-y) var(--card-space-inset);
115
115
  }
116
116
 
@@ -195,10 +195,16 @@
195
195
  /* Mirror the row's hover / selected tint — a translucent muted wash layered
196
196
  * over the opaque base, so the pinned cell matches the rest of its row. */
197
197
  .ui-data-table-surface tbody tr:hover > .ui-data-table-pin-end {
198
- background-image: linear-gradient(var(--table-row-hover-background), var(--table-row-hover-background));
198
+ background-image: linear-gradient(
199
+ var(--table-row-hover-background, hsl(var(--muted) / 0.5)),
200
+ var(--table-row-hover-background, hsl(var(--muted) / 0.5))
201
+ );
199
202
  }
200
203
 
201
204
  .ui-data-table-surface tbody tr[data-state="selected"] > .ui-data-table-pin-end {
202
- background-image: linear-gradient(var(--table-row-selected-background), var(--table-row-selected-background));
205
+ background-image: linear-gradient(
206
+ var(--table-row-selected-background, hsl(var(--muted) / 0.3)),
207
+ var(--table-row-selected-background, hsl(var(--muted) / 0.3))
208
+ );
203
209
  }
204
210
  }
@@ -0,0 +1,10 @@
1
+ /* Badge component tokens. */
2
+
3
+ :root {
4
+ --badge-space-gap: var(--space-inline-xs);
5
+ --badge-space-x: var(--space-2);
6
+ --badge-space-y: var(--space-1);
7
+ /* Small-by-design (badge/pill/counter). A knob (rule #45) so a service can
8
+ * re-tune badge text without touching the global --font-size-xs step. */
9
+ --badge-font-size: var(--font-size-xs);
10
+ }
@@ -0,0 +1,79 @@
1
+ /* Card component tokens: card chrome derives from semantic layout tokens. */
2
+
3
+ :root {
4
+ /* Horizontal inset of every slot (header / content / footer) + the resting top/bottom
5
+ * shell padding. This is the column the title, body and footer all align to. */
6
+ --card-space-inset: var(--space-section-active);
7
+ /* Vertical padding of a BANDED header band (top = bottom). Drives --card-space-divided-y. */
8
+ --card-space-header-y: var(--space-stack-sm);
9
+ /* Gap between the header and the body, and the body's own top padding — the breathing
10
+ * room under a title before content begins. */
11
+ --card-space-body-y: var(--space-section-active);
12
+ /* Vertical padding of a SEPARATED footer band (top = bottom). Drives --card-space-divided-y. */
13
+ --card-space-footer-y: var(--space-stack-sm);
14
+ /* DIVIDED-section vertical padding (rule #44/#45). A header/footer that carries a divider
15
+ * border (banded header, separated footer) reads as its own band, so it pads SYMMETRICALLY
16
+ * top+bottom — distinct from a plain header that flows into the body (top inset, no bottom).
17
+ * One themeable knob keeps the header- and footer-band rhythm in sync; a service theme tunes
18
+ * the band density here instead of forking per-slot CSS. */
19
+ --card-space-divided-y: var(--card-space-header-y);
20
+ /* Vertical gap between stacked items WITHIN a slot (e.g. title ↕ description in the header). */
21
+ --card-space-gap: var(--space-stack-xs);
22
+ --card-title-font-size: var(--font-size-base);
23
+ --card-title-line-height: var(--line-height-tight);
24
+ --card-title-font-weight: var(--font-weight-semibold);
25
+ --card-description-font-size: var(--font-size-sm);
26
+ --card-description-line-height: var(--line-height-normal);
27
+ /* Card fill + edge — opt-in knobs that DEFAULT to the live --card / --border roles. Declared
28
+ * `initial` (not `var(--card)`) so the default re-resolves at the call site under a scoped theme:
29
+ * a :root binding to a role var freezes at the :root value and a scoped `[data-tenant]` override of
30
+ * the role never reaches it (see docs/STANDARDS-vocabulary-tokens.md · "role-mirror knobs"). A
31
+ * service still overrides the knob directly (--card-background: …) to win over the role default. */
32
+ --card-background: initial; /* default = hsl(var(--card)) */
33
+ --card-border: initial; /* default = hsl(var(--border)) */
34
+ /* Banded-header fill — role-tintable (rule #45): a service points this at any role,
35
+ * e.g. --card-header-background: var(--primary), and tunes --card-header-background-alpha for
36
+ * the wash strength. Default = the live --muted role (resolved at the call site). */
37
+ --card-header-background: initial; /* default = hsl(var(--muted)) */
38
+ --card-header-background-alpha: 0.55;
39
+ /* Banded-header divider — tokenised (rule #44) so a service theme can make it
40
+ * dashed / heavier / none without forking CSS. Pair with
41
+ * --card-header-background-alpha: 0 for a quiet borderless-band header.
42
+ * Default = 1px solid hsl(var(--card-border)) (resolved at the call site). */
43
+ --card-header-border-bottom: initial;
44
+ --card-radius: var(--radius);
45
+ /* Resting elevation — quiet by default (rule #44): cards are flat (1px border, no shadow) in the
46
+ * dxs-kintai baseline. A service that wants lifted cards sets this to an elevation token once,
47
+ * e.g. --card-shadow: var(--shadow-sm), and every Card picks up the shadow with no markup change. */
48
+ --card-shadow: 0 0 0 0 transparent;
49
+ /* Brand glow layer — invisible no-op at rest (rule #44). Paired AFTER --card-shadow in the
50
+ * surface box-shadow so a service can wash every card with the global glow, e.g.
51
+ * --card-glow: var(--shadow-glow), with no markup change. */
52
+ --card-glow: 0 0 0 0 transparent;
53
+ /* Fill tint — subtle role wash over the card background (default transparent = invisible).
54
+ * Painted as an overlay so a service sets --card-tint: hsl(var(--primary) / 0.04) once. */
55
+ --card-tint: transparent;
56
+ /* Accent edge — width of the semantic leading-edge stripe (data-accent).
57
+ * Tokenised (rule #44) so a service theme can re-tune it without forking CSS.
58
+ * The slot padding compensation in card-layout.css subtracts the same token,
59
+ * so content stays aligned on the shell whatever the rail width. */
60
+ --card-accent-rail-width: 6px;
61
+ --stat-card-label-font-size: var(--font-size-xs);
62
+ --stat-card-label-font-weight: var(--font-weight-medium);
63
+ --stat-card-label-letter-spacing: 0.04em;
64
+ --stat-card-value-font-size: var(--font-size-2xl);
65
+ --stat-card-value-line-height: 1.1;
66
+ --stat-card-value-font-weight: var(--font-weight-semibold);
67
+ --stat-card-hint-font-size: var(--font-size-xs);
68
+ --stat-card-gap: var(--space-stack-xs);
69
+ --stat-card-icon-size: 2.25rem;
70
+ --stat-card-icon-glyph-size: 1.25rem;
71
+ --stat-card-icon-radius: var(--radius-md);
72
+ /* Medallion tint — soft brand wash + brand glyph by default; a service retints by overriding
73
+ * --primary or these tokens directly (rule #44/#45). `initial` so the --primary default
74
+ * re-resolves at the call site under a scoped theme (no :root freeze).
75
+ * Defaults = hsl(var(--primary) / 0.1) fill · hsl(var(--primary)) glyph. */
76
+ --stat-card-icon-background: initial;
77
+ --stat-card-icon-foreground: initial;
78
+ --stat-card-delta-font-size: var(--font-size-xs);
79
+ }
@@ -0,0 +1,92 @@
1
+ /* Control primitive tokens: heights, horizontal padding, adjacent control sizes. */
2
+
3
+ :root {
4
+ --control-height-compact: 1.75rem;
5
+ --control-height-default: 2rem;
6
+ --control-height-comfortable: 2.75rem;
7
+ --control-padding-x-compact: var(--space-2);
8
+ --control-padding-x-default: var(--space-3);
9
+ --control-padding-x-comfortable: var(--space-4);
10
+
11
+ --control-height: calc(var(--control-height-default) * var(--scaling));
12
+ /* Adjacent control sizes, derived from the active --control-height. The ±step
13
+ * is scaled too so the whole control ladder stays proportional under --scaling. */
14
+ --control-height-sm: calc(var(--control-height) - calc(0.25rem * var(--scaling)));
15
+ --control-height-lg: calc(var(--control-height) + calc(0.25rem * var(--scaling)));
16
+ --control-height-xs: calc(var(--control-height) - calc(0.5rem * var(--scaling)));
17
+ --control-padding-x: var(--control-padding-x-default);
18
+ --control-gap: var(--space-inline-sm);
19
+ --control-gap-sm: var(--space-inline-xs);
20
+ --control-radius: var(--radius);
21
+ --control-icon-size: calc(1rem * var(--scaling));
22
+ --control-icon-size-sm: calc(0.875rem * var(--scaling));
23
+ --control-focus-ring-width: var(--focus-ring-width);
24
+
25
+ --checkbox-size: calc(1rem * var(--scaling));
26
+ --checkbox-size-compact: 0.875rem;
27
+ --checkbox-size-comfortable: 1.125rem;
28
+ --choice-gap: var(--space-inline-sm);
29
+ --choice-group-gap-x: var(--space-6);
30
+ --choice-group-gap-y: var(--space-3);
31
+ --choice-description-gap: 0.125rem;
32
+ --choice-control-offset: 0.125rem;
33
+
34
+ --switch-width: calc(2.25rem * var(--scaling));
35
+ --switch-width-compact: 2rem;
36
+ --switch-width-comfortable: 2.5rem;
37
+ --switch-height: calc(1.25rem * var(--scaling));
38
+ --switch-height-compact: 1.125rem;
39
+ --switch-height-comfortable: 1.375rem;
40
+ --switch-thumb-size: calc(1rem * var(--scaling));
41
+ --switch-thumb-size-compact: 0.875rem;
42
+ --switch-thumb-size-comfortable: 1.125rem;
43
+ --switch-thumb-translate: calc(1rem * var(--scaling));
44
+ --switch-thumb-translate-compact: 0.875rem;
45
+ --switch-thumb-translate-comfortable: 1.125rem;
46
+
47
+ --slider-track-height: 0.375rem;
48
+ --slider-thumb-size: 1rem;
49
+
50
+ /* Checked/on/active fills — `initial` so the --primary default re-resolves at the call site
51
+ * under a scoped theme (a :root binding to var(--primary) freezes at the :root value and a scoped
52
+ * [data-tenant] override of --primary never reaches it). A service retints the "selected" state
53
+ * by overriding these directly. Defaults = hsl(var(--primary)) · slider track 0.2α. */
54
+ --checkbox-checked-background: initial;
55
+ --switch-checked-background: initial;
56
+ --toggle-on-background: initial;
57
+ --slider-track-background: initial;
58
+ --slider-range-background: initial;
59
+
60
+ --color-picker-input-width: 6.5rem;
61
+
62
+ --command-list-max-height: min(300px, 50vh);
63
+ --command-input-padding-x: var(--space-3);
64
+ --command-group-padding: var(--space-1);
65
+ --command-item-padding-y: var(--space-2);
66
+ --command-item-padding-x: var(--space-2);
67
+ --search-input-edge-inset: var(--space-3);
68
+ --search-input-start-padding: calc(
69
+ var(--search-input-edge-inset) + var(--control-icon-size) + var(--control-gap)
70
+ );
71
+ --search-input-end-padding: calc(
72
+ var(--search-input-edge-inset) + var(--control-icon-size) + var(--control-gap)
73
+ );
74
+
75
+ --choice-description-font-size: var(--font-size-xs);
76
+ --color-picker-hex-font-size: var(--font-size-xs);
77
+ --command-group-heading-font-size: var(--font-size-xs);
78
+ --search-input-label-font-size: var(--font-size-xs);
79
+ --tag-input-chip-font-size: var(--font-size-xs);
80
+ --toggle-sm-font-size: var(--font-size-xs);
81
+ --button-sm-font-size: var(--font-size-xs);
82
+ }
83
+
84
+ /* Rule #24 — on touch devices (coarse pointer) interactive controls keep a ≥44px tap target
85
+ * regardless of density; desktop (fine pointer) keeps the compact heights above. --control-height
86
+ * resolves through these via var(), so inputs/buttons/selects/table rows all bump together. */
87
+ @media (pointer: coarse) {
88
+ :root {
89
+ --control-height-compact: 2.75rem;
90
+ --control-height-default: 2.75rem;
91
+ }
92
+ }
@@ -0,0 +1,34 @@
1
+ /* Data-display component tokens — small-by-design text knobs (rule #45/#46). */
2
+
3
+ :root {
4
+ --progress-label-font-size: var(--font-size-xs);
5
+ --tree-item-title-font-size: var(--font-size-xs);
6
+ --tree-item-description-font-size: var(--font-size-xs);
7
+ --timeline-note-font-size: var(--font-size-xs);
8
+
9
+ /* Avatar surface — `initial` so the --muted default re-resolves at the call site under a scoped
10
+ theme (a :root binding to a role var freezes at :root; a scoped role override never reaches it).
11
+ A service re-tints the placeholder fill once (e.g. --avatar-background: hsl(var(--accent))).
12
+ Default = hsl(var(--muted)). */
13
+ --avatar-background: initial;
14
+ /* Optional role wash over the avatar (default transparent = invisible, rule #44).
15
+ Painted as an overlay so a service sets --avatar-tint: hsl(var(--primary) / 0.08). */
16
+ --avatar-tint: transparent;
17
+
18
+ /* Progress track + fill — `initial` so the role defaults re-resolve under a scoped theme.
19
+ Track reads --secondary, fill reads --success; a service re-tones once.
20
+ Defaults = hsl(var(--secondary)) track · hsl(var(--success)) fill. */
21
+ --progress-track-background: initial;
22
+ --progress-fill-background: initial;
23
+
24
+ /* Timeline accents — `initial` so the dot/line role defaults re-resolve under a scoped theme.
25
+ Defaults = hsl(var(--success)) done · hsl(var(--primary)) current/line. */
26
+ --timeline-dot-done-background: initial;
27
+ --timeline-dot-current-background: initial;
28
+ --timeline-line-completed-background: initial;
29
+
30
+ /* Tree active item — border + soft bg tint over the --primary role. `initial` so the default
31
+ re-resolves under a scoped theme. Defaults = hsl(var(--primary) / 0.3) border · 0.05 fill. */
32
+ --tree-item-active-border: initial;
33
+ --tree-item-active-background: initial;
34
+ }
@@ -0,0 +1,6 @@
1
+ /* Data-entry component tokens — small-by-design text knobs (rule #45/#46). */
2
+
3
+ :root {
4
+ --password-strength-score-font-size: var(--font-size-xs);
5
+ --password-strength-checklist-font-size: var(--font-size-xs);
6
+ }
@@ -0,0 +1,9 @@
1
+ /* Descriptions component tokens. */
2
+
3
+ :root {
4
+ /* Width of the label column when <Descriptions layout="horizontal">. Labels align to this
5
+ * shared column so the values line up (the horizontal-detail look, mirroring <Form layout>).
6
+ * A rem value gives a fixed aligned column; set `max-content` to size each label to its text.
7
+ * (rule #44/#45 — a service theme tunes it here instead of forking CSS.) */
8
+ --descriptions-label-width: 8rem;
9
+ }
@@ -0,0 +1,39 @@
1
+ /* Feedback primitive tokens: dialog, alert, empty state. */
2
+
3
+ :root {
4
+ /* Dialog inset defaults to the shared global chrome tokens (override --space-chrome-* once for the
5
+ * whole system, or --dialog-space-x/-y for dialogs only). */
6
+ --dialog-space-x: var(--space-chrome-x);
7
+ --dialog-space-y: var(--space-chrome-y);
8
+ --dialog-space-inset: var(--dialog-space-y) var(--dialog-space-x);
9
+ --dialog-space-gap: var(--space-stack-md);
10
+ --dialog-close-space-offset: var(--space-4);
11
+ --alert-space-inset: var(--space-section-active);
12
+ --alert-space-gap: var(--space-inline-md);
13
+ --alert-inner-space-gap: var(--space-stack-sm);
14
+ --alert-dismiss-space-offset: var(--space-3);
15
+ /* Soft (subtle) semantic tint ratios — themeable so a service can hit its exact spec
16
+ * (a brand's success-bg/-border are often more present than the faint 5%/30% default). */
17
+ --alert-bg-alpha: 0.05;
18
+ --alert-border-alpha: 0.3;
19
+ /* Brand glow layer for the raised dialog/sheet panel — invisible no-op at rest (rule #44).
20
+ * Paired AFTER --shadow-lg in the surface box-shadow so a service can wash the overlay with the
21
+ * global glow, e.g. --dialog-content-glow: var(--shadow-glow), with no markup change. */
22
+ --dialog-content-glow: 0 0 0 0 transparent;
23
+ --empty-state-space-y: var(--space-10);
24
+ --empty-state-space-x: var(--space-6);
25
+ /* EmptyState icon medallion colour — `initial` so the role defaults re-resolve at the call site
26
+ * under a scoped theme (rule #44). A service recolours the glyph (--empty-state-icon-foreground)
27
+ * or washes the medallion fill (--empty-state-icon-tint) without forking.
28
+ * Defaults = hsl(var(--muted-foreground)) glyph · hsl(var(--muted)) fill. */
29
+ --empty-state-icon-foreground: initial;
30
+ --empty-state-icon-tint: initial;
31
+ --skeleton-row-gap: var(--space-stack-sm);
32
+ --skeleton-cell-gap: var(--space-inline-lg);
33
+ --skeleton-card-inset: var(--space-section-active);
34
+ --skeleton-radius: var(--radius);
35
+ /* Skeleton placeholder fill — `initial` so the --muted default re-resolves at the call site under
36
+ * a scoped theme (a :root binding to a role var freezes at :root). A service tints the shimmer to
37
+ * its surface (rule #44) without forking the keyframes. Default = hsl(var(--muted)). */
38
+ --skeleton-background: initial;
39
+ }
@@ -0,0 +1,11 @@
1
+ /* Form layout tokens: horizontal-layout label column geometry. */
2
+
3
+ :root {
4
+ /* Width of the label column in horizontal/inline layout. A service theme sets
5
+ * this once (e.g. 110px) to align every form to its design grid; the Form/
6
+ * FormField `labelWidth` prop overrides per form/field. */
7
+ --form-label-width: max-content;
8
+
9
+ /* Column gap between the label and its control in horizontal/inline layout. */
10
+ --form-label-gap: var(--space-4); /* 16px */
11
+ }
@@ -0,0 +1,11 @@
1
+ /* ListRow component tokens — a single-line entity row for short lists inside a Card
2
+ * (sessions / API tokens / linked accounts / passkeys …). Sits in a flush CardContent;
3
+ * rows separate with a quiet divider (#44 — chrome defaults to the calm semantic border). */
4
+ :root {
5
+ --list-row-padding-y: var(--space-3);
6
+ --list-row-padding-x: var(--space-4);
7
+ --list-row-gap: var(--space-3);
8
+ /* Row divider — `initial` so the --border default re-resolves at the call site under a scoped
9
+ * theme (a :root binding to a role var freezes at :root). Default = 1px solid hsl(var(--border)). */
10
+ --list-row-border: initial;
11
+ }
@@ -0,0 +1,21 @@
1
+ /* Navigation primitive tokens: pagination, filters, compact pickers. */
2
+
3
+ :root {
4
+ --pagination-gap: var(--space-inline-sm);
5
+ --pagination-item-gap: var(--space-inline-xs);
6
+ --pagination-size-width: 5.5rem;
7
+ --pagination-total-font-size: var(--font-size-sm);
8
+ --filter-bar-gap: var(--space-3);
9
+ --filter-bar-padding-y: var(--space-2);
10
+ --filter-label-font-size: var(--font-size-xs);
11
+ --filter-picker-width-sm: 11rem;
12
+ --filter-picker-width-md: 14rem;
13
+ --breadcrumb-font-size: var(--font-size-xs);
14
+ --menubar-shortcut-font-size: var(--font-size-xs);
15
+
16
+ /* Menu item hover/highlight tint — `initial` so the --accent default re-resolves at the call site
17
+ * under a scoped theme (a :root binding to a role var freezes at :root).
18
+ * Defaults = hsl(var(--accent)) fill · hsl(var(--accent-foreground)) text. */
19
+ --menubar-item-hover-background: initial;
20
+ --menubar-item-hover-foreground: initial;
21
+ }
@@ -0,0 +1,35 @@
1
+ /* Shell (sidebar / topbar / kbd) component tokens — small-by-design text
2
+ * knobs (rule #45/#46). A service re-tunes chrome text without moving the
3
+ * global scale. */
4
+
5
+ :root {
6
+ --sidebar-section-label-font-size: var(--font-size-2xs);
7
+ --sidebar-product-tenant-font-size: var(--font-size-2xs);
8
+ --sidebar-badge-font-size: var(--font-size-2xs);
9
+ --sidebar-user-role-font-size: var(--font-size-2xs);
10
+ --sidebar-nav-sub-font-size: var(--font-size-xs);
11
+ --sidebar-flyout-title-font-size: var(--font-size-xs);
12
+ --topbar-chip-icon-font-size: var(--font-size-2xs);
13
+ --kbd-font-size: var(--font-size-2xs);
14
+ --sidebar-logo-mark-font-size: var(--font-size-xs);
15
+ --sidebar-avatar-font-size: var(--font-size-2xs);
16
+ --sidebar-user-name-font-size: var(--font-size-xs);
17
+
18
+ /* Brand-chrome gradient hooks — opt-in, invisible by default. A service paints
19
+ * the sidebar/topbar surface by setting these to a gradient (no-op = none). */
20
+ --sidebar-gradient: none;
21
+ --topbar-gradient: none;
22
+
23
+ /* Sidebar active-item tint/marker — `initial` so the role defaults re-resolve at the call site
24
+ * under a scoped theme (a :root binding to a role var freezes at :root; a scoped role override
25
+ * never reaches it). A service re-tunes the active sub-item accent without forking CSS.
26
+ * Defaults = hsl(var(--primary)) marker/tint. */
27
+ --sidebar-item-active-color: initial;
28
+ --sidebar-item-active-tint: initial;
29
+ /* Main nav-item active row — defaults mirror the hover state (accent bg, foreground text); a
30
+ * service overrides these to brand the selected row (e.g. a gold tint + gold text on a navy
31
+ * sidebar). `initial` so the defaults re-resolve under a scoped theme.
32
+ * Defaults = hsl(var(--accent)) fill · hsl(var(--foreground)) text. */
33
+ --sidebar-item-active-background: initial;
34
+ --sidebar-item-active-foreground: initial;
35
+ }
@@ -0,0 +1,26 @@
1
+ /* Table component tokens: row height, cell padding. */
2
+
3
+ :root {
4
+ --table-row-height-compact: 1.75rem;
5
+ --table-row-height-default: 2rem;
6
+ --table-row-height-comfortable: 2.75rem;
7
+ --table-row-height: calc(var(--table-row-height-default) * var(--scaling));
8
+ --table-cell-padding-y: var(--space-2);
9
+ --table-cell-space-x: var(--control-padding-x);
10
+ --table-head-font-size: var(--font-size-xs);
11
+ /* Header band — its OWN bg + fg knobs (decoupled from --secondary). Declared `initial` so the
12
+ * default re-resolves to the LIVE --muted / --muted-foreground roles at the call site: a :root
13
+ * binding to a role var freezes at the :root value and a scoped [data-tenant] role override never
14
+ * reaches it. A brand sets both header tokens together to keep band/text contrast.
15
+ * Defaults = hsl(var(--muted)) band · hsl(var(--muted-foreground)) text. */
16
+ --table-header-background: initial;
17
+ --table-header-foreground: initial;
18
+ /* Inline-end shadow that lifts a pinned (sticky) action column off the body it scrolls over. */
19
+ --table-pin-shadow: -6px 0 6px -5px hsl(var(--foreground) / 0.12);
20
+ /* Row-state tint washes — translucent muted over the opaque base. `initial` so the --muted
21
+ * default re-resolves under a scoped theme; a service retints by reading another role (e.g.
22
+ * --primary). Defaults = hsl(var(--muted) / 0.4 striped · 0.5 hover · 0.3 selected). */
23
+ --table-row-striped-background: initial;
24
+ --table-row-hover-background: initial;
25
+ --table-row-selected-background: initial;
26
+ }
@@ -110,12 +110,12 @@
110
110
  /* FOCUS RING — the two global knobs for the keyboard-focus affordance (WCAG 2.4.7 / 2.4.11).
111
111
  * `--focus-ring-color` is the themeable hue (HSL components, defaults to --ring) and
112
112
  * `--focus-ring-width` the standard thickness; override either ONCE — even scoped under a
113
- * `[data-tenant]` — to retint or resize EVERY focus ring. Both are leaf tokens (a colour and a
114
- * length, no nested var) so they re-resolve at the element that paints the ring; every
115
- * :focus-visible rule reads them DIRECTLY as `0 0 0 var(--focus-ring-width)
116
- * hsl(var(--focus-ring-color))`, never via an intermediate composite (a `:root`-declared
117
- * composite that wraps these would freeze at :root and ignore a scoped override). */
118
- --focus-ring-color: var(--ring);
113
+ * `[data-tenant]` — to retint or resize EVERY focus ring. `--focus-ring-color` is declared
114
+ * `initial` (NOT `var(--ring)`): a :root binding to a role var would freeze at the :root --ring
115
+ * and a scoped [data-tenant] override of --ring alone would never reach it. Every :focus-visible
116
+ * rule reads it with the live-role fallback `hsl(var(--focus-ring-color, var(--ring)))`, so the
117
+ * default re-resolves at the element that paints the ring while an explicit override still wins. */
118
+ --focus-ring-color: initial; /* default = the live --ring role */
119
119
  --focus-ring-width: 2px;
120
120
 
121
121
  /* GRADIENTS — opt-in decorative fills exposed at the token layer so a service can paint a hero
@@ -0,0 +1,54 @@
1
+ /* Layout primitive tokens: page, section, stack, inline. */
2
+
3
+ :root {
4
+ /* Semantic spacing — ONE coherent 4px grid (Tailwind/Material/Ant standard). All steps reference
5
+ * the linear `--space-*` scale (NOT the golden φ scale — golden ratio is for modular SIZE scales
6
+ * like type/radius, not the spacing grid; mixing the two left an incoherent density rhythm). The
7
+ * φ tokens remain available as an optional golden-layout utility, just not the spacing baseline. */
8
+ --space-page-x: var(--space-6); /* 24px — page gutter */
9
+ --space-page-y: var(--space-6); /* 24px */
10
+ --space-section: var(--space-4); /* 16px */
11
+ --space-stack-xs: var(--space-1); /* 4px */
12
+ --space-stack-sm: var(--space-2); /* 8px */
13
+ --space-stack-md: var(--space-4); /* 16px */
14
+ --space-stack-lg: var(--space-6); /* 24px */
15
+ --space-stack-xl: var(--space-10); /* 40px */
16
+ --space-inline-xs: var(--space-1); /* 4px */
17
+ --space-inline-sm: var(--space-2); /* 8px */
18
+ --space-inline-md: var(--space-3); /* 12px */
19
+ --space-inline-lg: var(--space-4); /* 16px */
20
+
21
+ --space-page-active-x: var(--space-page-x);
22
+ --space-page-active-y: var(--space-page-y);
23
+ --space-section-active: var(--space-section);
24
+
25
+ /* Modal scrim — the single backdrop colour shared by EVERY overlay (Dialog, AlertDialog, Sheet,
26
+ * Drawer). Themeable (rule #44) so a service tints the wash to its brand once, e.g. a navy
27
+ * `--overlay-background: rgb(12 26 49 / .55)`, instead of forking each overlay. */
28
+ --overlay-background: rgb(0 0 0 / 0.5);
29
+
30
+ /* Full-bleed rule under the PageContainer header. OFF by default — the title/body
31
+ * gap already separates them; a divider is a service-theme opt-in:
32
+ * `--page-header-divider: 1px solid hsl(var(--border));` */
33
+ --page-header-divider: none;
34
+
35
+ /* Bottom inset of the page header, sized so title→body distance (this pad + the
36
+ * --space-section-active container gap) EQUALS the page's top padding — the title
37
+ * band reads vertically balanced (24 above / 24 below by default), instead of the
38
+ * old fixed 16px pad that left 24 above vs 32 below. */
39
+ --page-header-pad-bottom: calc(var(--space-page-active-y) - var(--space-section-active));
40
+
41
+ /* Section "chrome" padding — the SHARED inset for header / body / footer of every overlay-ish
42
+ * surface (Dialog · Sheet · Drawer · Card). One global knob: a service sets these once instead of
43
+ * per-component. Vertical is tightened (16 vs the old 24) and density-aware (see density.css);
44
+ * horizontal stays 24 (Ant standard). Per-component tokens (--sheet-pad-*, --dialog-space-inset…)
45
+ * default to these and only override when a surface genuinely needs to differ. */
46
+ --space-chrome-x: var(--space-6); /* 24px — horizontal inset */
47
+ --space-chrome-y: var(--space-4); /* 16px — vertical inset (header/footer/body) */
48
+ --space-chrome-gap: var(--space-stack-sm); /* gap between header ↔ body ↔ footer */
49
+
50
+ /* The ONE vertical gap between a field's LABEL and its CONTENT — same everywhere a label sits above
51
+ * a control or a value (FormField, Descriptions, Form, any label-above stack). Single source so the
52
+ * whole system stays in sync (gh feedback: Descriptions was ~0px while FormField was 8px). */
53
+ --field-label-gap: var(--space-2); /* 8px */
54
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@godxjp/ui",
3
- "version": "16.5.0",
3
+ "version": "16.6.0",
4
4
  "type": "module",
5
5
  "packageManager": "pnpm@10.29.1",
6
6
  "sideEffects": false,