@godxjp/ui 16.4.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.
- package/dist/components/data-display/card.d.ts +5 -1
- package/dist/components/data-display/card.js +4 -2
- package/dist/components/feedback/sheet.js +3 -1
- package/dist/components/navigation/steps.js +2 -2
- package/dist/lib/control-styles.d.ts +7 -5
- package/dist/lib/control-styles.js +4 -4
- package/dist/props/registry.d.ts +1 -1
- package/dist/props/registry.js +1 -1
- package/dist/styles/alert-layout.css +7 -5
- package/dist/styles/card-layout.css +42 -6
- package/dist/styles/control.css +24 -14
- package/dist/styles/data-display-layout.css +16 -13
- package/dist/styles/data-entry-layout.css +2 -2
- package/dist/styles/dialog-layout.css +6 -2
- package/dist/styles/index.css +30 -3
- package/dist/styles/layout.css +7 -1
- package/dist/styles/navigation-layout.css +10 -10
- package/dist/styles/shell-layout.css +17 -6
- package/dist/styles/table-layout.css +12 -6
- package/dist/tokens/components/card.css +33 -5
- package/dist/tokens/components/control.css +11 -1
- package/dist/tokens/components/data-display.css +26 -0
- package/dist/tokens/components/feedback.css +14 -0
- package/dist/tokens/components/list-row.css +3 -1
- package/dist/tokens/components/navigation.css +6 -0
- package/dist/tokens/components/shell.css +18 -0
- package/dist/tokens/components/table.css +13 -0
- package/dist/tokens/foundation.css +64 -0
- package/dist/tokens/semantic/layout.css +5 -0
- package/package.json +3 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
import type { LucideIcon } from "lucide-react";
|
|
3
4
|
type CardSize = "md" | "compact";
|
|
4
5
|
/** Semantic leading-edge accent stripe (border-inline-start; width via the
|
|
5
6
|
* --card-accent-rail-width token, default 6px). */
|
|
@@ -86,6 +87,9 @@ export type StatCardProps = React.HTMLAttributes<HTMLDivElement> & VariantProps<
|
|
|
86
87
|
label: React.ReactNode;
|
|
87
88
|
value: React.ReactNode;
|
|
88
89
|
hint?: React.ReactNode;
|
|
90
|
+
/** Optional leading icon, rendered as a tinted medallion above the metric. Decorative
|
|
91
|
+
* (aria-hidden) — the label carries the meaning. Tint via --stat-card-icon-* tokens. */
|
|
92
|
+
icon?: LucideIcon;
|
|
89
93
|
/** Optional compact trend text beside the value. Avoid badge-like deltas. */
|
|
90
94
|
delta?: React.ReactNode;
|
|
91
95
|
/** KPI layout: stacked = design default, inline = label left / value right. */
|
|
@@ -98,7 +102,7 @@ export type StatCardProps = React.HTMLAttributes<HTMLDivElement> & VariantProps<
|
|
|
98
102
|
accent?: CardAccent;
|
|
99
103
|
};
|
|
100
104
|
/** KPI / stat tile — token-driven layout aligned to dashboard KPI cards. */
|
|
101
|
-
export declare function StatCard({ label, value, hint, delta, layout, align, inverse, accent, className, size, ...props }: StatCardProps): import("react/jsx-runtime").JSX.Element;
|
|
105
|
+
export declare function StatCard({ label, value, hint, icon: Icon, delta, layout, align, inverse, accent, className, size, ...props }: StatCardProps): import("react/jsx-runtime").JSX.Element;
|
|
102
106
|
/** Header actions slot — pair with `CardHeader className="flex flex-row …"`. */
|
|
103
107
|
export declare const CardAction: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
|
104
108
|
export {};
|
|
@@ -96,6 +96,7 @@ function StatCard({
|
|
|
96
96
|
label,
|
|
97
97
|
value,
|
|
98
98
|
hint,
|
|
99
|
+
icon: Icon,
|
|
99
100
|
delta,
|
|
100
101
|
layout = "stacked",
|
|
101
102
|
align = "start",
|
|
@@ -117,6 +118,7 @@ function StatCard({
|
|
|
117
118
|
"data-stat-align": align,
|
|
118
119
|
...props,
|
|
119
120
|
children: [
|
|
121
|
+
Icon ? /* @__PURE__ */ jsx("span", { "data-slot": "stat-card-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Icon, {}) }) : null,
|
|
120
122
|
/* @__PURE__ */ jsxs("div", { "data-slot": "stat-card-body", children: [
|
|
121
123
|
/* @__PURE__ */ jsx("div", { "data-slot": "stat-card-label", children: label }),
|
|
122
124
|
hint && layout === "inline" ? /* @__PURE__ */ jsx("div", { "data-slot": "stat-card-hint", children: hint }) : null
|
|
@@ -130,8 +132,8 @@ function StatCard({
|
|
|
130
132
|
"data-slot": "stat-card-delta",
|
|
131
133
|
"data-delta-tone": deltaTone,
|
|
132
134
|
className: cn(
|
|
133
|
-
deltaTone === "positive" && "text-success",
|
|
134
|
-
deltaTone === "negative" && "text-
|
|
135
|
+
deltaTone === "positive" && "text-success-strong",
|
|
136
|
+
deltaTone === "negative" && "text-error-strong"
|
|
135
137
|
),
|
|
136
138
|
children: delta
|
|
137
139
|
}
|
|
@@ -24,7 +24,9 @@ const SheetOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PU
|
|
|
24
24
|
ref,
|
|
25
25
|
"data-slot": "sheet-overlay",
|
|
26
26
|
className: cn(
|
|
27
|
-
|
|
27
|
+
// Scrim colour comes from the shared --overlay-background token (see dialog-layout.css),
|
|
28
|
+
// so a service tints every overlay's backdrop from one knob instead of a baked bg-black/50.
|
|
29
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 fixed inset-0 z-50",
|
|
28
30
|
className
|
|
29
31
|
),
|
|
30
32
|
...props
|
|
@@ -17,7 +17,7 @@ function StepIcon({
|
|
|
17
17
|
if (icon)
|
|
18
18
|
return /* @__PURE__ */ jsx("span", { className: cn("flex items-center justify-center", controlIconClass), children: icon });
|
|
19
19
|
if (type === "dot") {
|
|
20
|
-
return /* @__PURE__ */ jsx(
|
|
20
|
+
return /* @__PURE__ */ jsx("span", { className: cn("flex items-center justify-center", controlIconClass), children: /* @__PURE__ */ jsx(
|
|
21
21
|
"span",
|
|
22
22
|
{
|
|
23
23
|
className: cn(
|
|
@@ -28,7 +28,7 @@ function StepIcon({
|
|
|
28
28
|
status === "wait" && "bg-muted-foreground/30"
|
|
29
29
|
)
|
|
30
30
|
}
|
|
31
|
-
);
|
|
31
|
+
) });
|
|
32
32
|
}
|
|
33
33
|
return /* @__PURE__ */ jsxs(
|
|
34
34
|
"span",
|
|
@@ -17,10 +17,12 @@ export declare const controlIconLeadingClass = "size-[length:var(--control-icon-
|
|
|
17
17
|
export declare const tableRowHeightClass = "h-[length:var(--table-row-height)]";
|
|
18
18
|
export declare const tableHeadHeightClass = "h-[length:var(--table-row-height)]";
|
|
19
19
|
export declare const tableCellPaddingClass = "py-[length:var(--table-cell-padding-y)]";
|
|
20
|
-
/** Semantic status / badge tones — always use tokens, never raw Tailwind palette.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
export declare const
|
|
24
|
-
export declare const
|
|
20
|
+
/** Semantic status / badge tones — always use tokens, never raw Tailwind palette. The TEXT uses the
|
|
21
|
+
* AA-strong status colours (text-*-strong, darker than the fill) so a small status label clears
|
|
22
|
+
* WCAG AA on the soft tint; the border/fill keep the brighter wa-iro role. */
|
|
23
|
+
export declare const toneSuccessClass = "border-success/30 bg-success/10 text-success-strong";
|
|
24
|
+
export declare const toneWarningClass = "border-warning/30 bg-warning/10 text-warning-strong";
|
|
25
|
+
export declare const toneInfoClass = "border-info/30 bg-info/10 text-info-strong";
|
|
26
|
+
export declare const toneDestructiveClass = "border-destructive/30 bg-destructive/10 text-error-strong";
|
|
25
27
|
export declare const toneMutedClass = "border-border bg-muted text-muted-foreground";
|
|
26
28
|
export declare const toneNeutralClass = "border-border bg-muted text-muted-foreground";
|
|
@@ -8,10 +8,10 @@ const controlIconLeadingClass = "size-[length:var(--control-icon-size)] shrink-0
|
|
|
8
8
|
const tableRowHeightClass = "h-[length:var(--table-row-height)]";
|
|
9
9
|
const tableHeadHeightClass = "h-[length:var(--table-row-height)]";
|
|
10
10
|
const tableCellPaddingClass = "py-[length:var(--table-cell-padding-y)]";
|
|
11
|
-
const toneSuccessClass = "border-success/30 bg-success/10 text-success";
|
|
12
|
-
const toneWarningClass = "border-warning/30 bg-warning/10 text-warning-
|
|
13
|
-
const toneInfoClass = "border-info/30 bg-info/10 text-info";
|
|
14
|
-
const toneDestructiveClass = "border-destructive/30 bg-destructive/10 text-
|
|
11
|
+
const toneSuccessClass = "border-success/30 bg-success/10 text-success-strong";
|
|
12
|
+
const toneWarningClass = "border-warning/30 bg-warning/10 text-warning-strong";
|
|
13
|
+
const toneInfoClass = "border-info/30 bg-info/10 text-info-strong";
|
|
14
|
+
const toneDestructiveClass = "border-destructive/30 bg-destructive/10 text-error-strong";
|
|
15
15
|
const toneMutedClass = "border-border bg-muted text-muted-foreground";
|
|
16
16
|
const toneNeutralClass = "border-border bg-muted text-muted-foreground";
|
|
17
17
|
export {
|
package/dist/props/registry.d.ts
CHANGED
|
@@ -1086,7 +1086,7 @@ export declare const COMPONENT_PROP_REGISTRY: {
|
|
|
1086
1086
|
readonly StatCardProp: {
|
|
1087
1087
|
readonly group: "data-display";
|
|
1088
1088
|
readonly file: "components/data-display/card.tsx";
|
|
1089
|
-
readonly vocabulary: readonly ["TitleProp", "ToneProp", "ClassNameProp"];
|
|
1089
|
+
readonly vocabulary: readonly ["TitleProp", "ToneProp", "IconProp", "ClassNameProp"];
|
|
1090
1090
|
};
|
|
1091
1091
|
readonly ResponsiveGridProp: {
|
|
1092
1092
|
readonly group: "layout";
|
package/dist/props/registry.js
CHANGED
|
@@ -1080,7 +1080,7 @@ const COMPONENT_PROP_REGISTRY = {
|
|
|
1080
1080
|
StatCardProp: {
|
|
1081
1081
|
group: "data-display",
|
|
1082
1082
|
file: "components/data-display/card.tsx",
|
|
1083
|
-
vocabulary: ["TitleProp", "ToneProp", "ClassNameProp"]
|
|
1083
|
+
vocabulary: ["TitleProp", "ToneProp", "IconProp", "ClassNameProp"]
|
|
1084
1084
|
},
|
|
1085
1085
|
ResponsiveGridProp: {
|
|
1086
1086
|
group: "layout",
|
|
@@ -120,20 +120,22 @@
|
|
|
120
120
|
line-height: 1;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
/* Title text reads the AA-strong status colour (darker than the fill) so the coloured heading
|
|
124
|
+
* clears WCAG AA on the soft alert tint; the icon keeps the brighter role colour. */
|
|
123
125
|
[data-slot="alert-title"][data-tone="destructive"] {
|
|
124
|
-
color: hsl(var(--
|
|
126
|
+
color: hsl(var(--text-error));
|
|
125
127
|
}
|
|
126
128
|
|
|
127
129
|
[data-slot="alert-title"][data-tone="warning"] {
|
|
128
|
-
color: hsl(var(--warning));
|
|
130
|
+
color: hsl(var(--text-warning));
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
[data-slot="alert-title"][data-tone="success"] {
|
|
132
|
-
color: hsl(var(--success));
|
|
134
|
+
color: hsl(var(--text-success));
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
[data-slot="alert-title"][data-tone="info"] {
|
|
136
|
-
color: hsl(var(--info));
|
|
138
|
+
color: hsl(var(--text-info));
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
[data-slot="alert-description"] {
|
|
@@ -168,7 +170,7 @@
|
|
|
168
170
|
|
|
169
171
|
.ui-skeleton-block {
|
|
170
172
|
border-radius: var(--skeleton-radius);
|
|
171
|
-
background: hsl(var(--muted));
|
|
173
|
+
background: var(--skeleton-background, hsl(var(--muted)));
|
|
172
174
|
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
173
175
|
}
|
|
174
176
|
|
|
@@ -27,10 +27,19 @@
|
|
|
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.
|
|
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. */
|
|
36
|
+
background:
|
|
37
|
+
linear-gradient(var(--card-tint), var(--card-tint)),
|
|
38
|
+
hsl(var(--card-background, var(--card)));
|
|
33
39
|
color: hsl(var(--card-foreground));
|
|
40
|
+
/* Resting elevation + opt-in brand glow — both quiet no-ops by default so a service theme can
|
|
41
|
+
* lift (--card-shadow) and/or glow (--card-glow) every card with no markup change. */
|
|
42
|
+
box-shadow: var(--card-shadow), var(--card-glow);
|
|
34
43
|
overflow: hidden;
|
|
35
44
|
}
|
|
36
45
|
|
|
@@ -119,7 +128,7 @@
|
|
|
119
128
|
align-items: center;
|
|
120
129
|
gap: var(--space-inline-md);
|
|
121
130
|
padding: var(--card-space-header-y) var(--card-space-inset);
|
|
122
|
-
border-block: 1px solid hsl(var(--card-border));
|
|
131
|
+
border-block: 1px solid hsl(var(--card-border, var(--border)));
|
|
123
132
|
}
|
|
124
133
|
|
|
125
134
|
[data-slot="card-bar"]:first-child {
|
|
@@ -147,8 +156,10 @@
|
|
|
147
156
|
}
|
|
148
157
|
|
|
149
158
|
.ui-card-header--banded {
|
|
150
|
-
border-bottom: var(--card-header-border-bottom);
|
|
151
|
-
background-color: hsl(
|
|
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
|
+
);
|
|
152
163
|
}
|
|
153
164
|
|
|
154
165
|
[data-slot="card-header"][data-banded] {
|
|
@@ -336,7 +347,7 @@
|
|
|
336
347
|
}
|
|
337
348
|
|
|
338
349
|
[data-slot="card-footer"][data-separated] {
|
|
339
|
-
border-top: 1px solid hsl(var(--card-border));
|
|
350
|
+
border-top: 1px solid hsl(var(--card-border, var(--border)));
|
|
340
351
|
/* Divided band → symmetric vertical padding (border-aware), in sync with a banded header. */
|
|
341
352
|
padding-block: var(--card-space-divided-y);
|
|
342
353
|
justify-content: flex-end;
|
|
@@ -384,6 +395,31 @@
|
|
|
384
395
|
min-width: 0;
|
|
385
396
|
}
|
|
386
397
|
|
|
398
|
+
/* Optional leading icon medallion — tinted box above the metric. Tone via tokens (default a
|
|
399
|
+
* soft brand-primary tint), so a service rethemes it with --primary or the icon tokens. */
|
|
400
|
+
[data-slot="stat-card-icon"] {
|
|
401
|
+
display: inline-flex;
|
|
402
|
+
align-items: center;
|
|
403
|
+
justify-content: center;
|
|
404
|
+
width: var(--stat-card-icon-size);
|
|
405
|
+
height: var(--stat-card-icon-size);
|
|
406
|
+
margin-bottom: var(--stat-card-gap);
|
|
407
|
+
border-radius: var(--stat-card-icon-radius);
|
|
408
|
+
background: var(--stat-card-icon-background, hsl(var(--primary) / 0.1));
|
|
409
|
+
color: var(--stat-card-icon-foreground, hsl(var(--primary)));
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
[data-slot="stat-card-icon"] svg {
|
|
413
|
+
width: var(--stat-card-icon-glyph-size);
|
|
414
|
+
height: var(--stat-card-icon-glyph-size);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/* Inline layout: medallion floats to the trailing edge so label/value keep the start column. */
|
|
418
|
+
[data-slot="card"][data-stat-layout="inline"] [data-slot="stat-card-icon"] {
|
|
419
|
+
margin-bottom: 0;
|
|
420
|
+
order: 1;
|
|
421
|
+
}
|
|
422
|
+
|
|
387
423
|
[data-slot="stat-card-label"] {
|
|
388
424
|
display: flex;
|
|
389
425
|
align-items: center;
|
package/dist/styles/control.css
CHANGED
|
@@ -50,13 +50,13 @@
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
.ui-toggle[data-state="on"] {
|
|
53
|
-
background: hsl(var(--primary));
|
|
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(--ring) / 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(--
|
|
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 {
|
|
@@ -102,7 +102,9 @@
|
|
|
102
102
|
.ui-button--default {
|
|
103
103
|
background: hsl(var(--primary));
|
|
104
104
|
color: hsl(var(--primary-foreground));
|
|
105
|
-
|
|
105
|
+
/* Brand glow layers on top of the resting shadow; --shadow-glow is invisible by default
|
|
106
|
+
* (quiet) so a service opts the CTA halo in by setting the token alone. */
|
|
107
|
+
box-shadow: var(--shadow-sm), var(--shadow-glow);
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
.ui-button--default:hover {
|
|
@@ -119,9 +121,17 @@
|
|
|
119
121
|
background: hsl(var(--destructive) / 0.9);
|
|
120
122
|
}
|
|
121
123
|
|
|
124
|
+
/* Outline + ghost set their text colour EXPLICITLY (read --foreground) — never rely on inherited
|
|
125
|
+
* body colour. Inheriting breaks in a scoped dark region (e.g. an on-navy hero): the body's
|
|
126
|
+
* computed dark colour would carry in and the label goes near-invisible on the dark fill. */
|
|
122
127
|
.ui-button--outline {
|
|
123
128
|
border: 1px solid hsl(var(--input));
|
|
124
129
|
background: hsl(var(--background));
|
|
130
|
+
color: hsl(var(--foreground));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.ui-button--ghost {
|
|
134
|
+
color: hsl(var(--foreground));
|
|
125
135
|
}
|
|
126
136
|
|
|
127
137
|
.ui-button--outline:hover,
|
|
@@ -277,7 +287,7 @@
|
|
|
277
287
|
.ui-slider-thumb:focus-visible,
|
|
278
288
|
.ui-switch:focus-visible {
|
|
279
289
|
outline: none;
|
|
280
|
-
box-shadow: 0 0 0 var(--
|
|
290
|
+
box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color, var(--ring)));
|
|
281
291
|
}
|
|
282
292
|
|
|
283
293
|
.ui-checkbox:disabled,
|
|
@@ -289,7 +299,7 @@
|
|
|
289
299
|
}
|
|
290
300
|
|
|
291
301
|
.ui-checkbox[data-state="checked"] {
|
|
292
|
-
background: hsl(var(--primary));
|
|
302
|
+
background: var(--checkbox-checked-background, hsl(var(--primary)));
|
|
293
303
|
color: hsl(var(--primary-foreground));
|
|
294
304
|
}
|
|
295
305
|
|
|
@@ -326,7 +336,7 @@
|
|
|
326
336
|
}
|
|
327
337
|
|
|
328
338
|
.ui-switch[data-state="checked"] {
|
|
329
|
-
background: hsl(var(--primary));
|
|
339
|
+
background: var(--switch-checked-background, hsl(var(--primary)));
|
|
330
340
|
}
|
|
331
341
|
|
|
332
342
|
.ui-switch[data-state="unchecked"] {
|
|
@@ -364,13 +374,13 @@
|
|
|
364
374
|
flex-grow: 1;
|
|
365
375
|
overflow: hidden;
|
|
366
376
|
border-radius: var(--radius-pill);
|
|
367
|
-
background: hsl(var(--primary) / 0.2);
|
|
377
|
+
background: var(--slider-track-background, hsl(var(--primary) / 0.2));
|
|
368
378
|
}
|
|
369
379
|
|
|
370
380
|
.ui-slider-range {
|
|
371
381
|
position: absolute;
|
|
372
382
|
height: 100%;
|
|
373
|
-
background: hsl(var(--primary));
|
|
383
|
+
background: var(--slider-range-background, hsl(var(--primary)));
|
|
374
384
|
}
|
|
375
385
|
|
|
376
386
|
.ui-slider-thumb {
|
|
@@ -646,13 +656,13 @@
|
|
|
646
656
|
}
|
|
647
657
|
.ui-otp-slot[data-active="true"] {
|
|
648
658
|
z-index: 1;
|
|
649
|
-
box-shadow: 0 0 0
|
|
659
|
+
box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color, var(--ring)));
|
|
650
660
|
}
|
|
651
661
|
.ui-otp-container:has(.ui-otp-input[aria-invalid="true"]) .ui-otp-slot {
|
|
652
662
|
border-color: hsl(var(--destructive));
|
|
653
663
|
}
|
|
654
664
|
.ui-otp-container:has(.ui-otp-input[aria-invalid="true"]) .ui-otp-slot[data-active="true"] {
|
|
655
|
-
box-shadow: 0 0 0
|
|
665
|
+
box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--destructive));
|
|
656
666
|
}
|
|
657
667
|
.ui-otp-container:has(.ui-otp-input:disabled) .ui-otp-slot {
|
|
658
668
|
cursor: not-allowed;
|
|
@@ -717,7 +727,7 @@
|
|
|
717
727
|
fill: currentColor;
|
|
718
728
|
}
|
|
719
729
|
.ui-rating-star:focus-visible {
|
|
720
|
-
outline:
|
|
730
|
+
outline: var(--focus-ring-width) solid hsl(var(--focus-ring-color, var(--ring)));
|
|
721
731
|
outline-offset: 2px;
|
|
722
732
|
border-radius: var(--radius-sm);
|
|
723
733
|
}
|
|
@@ -735,8 +745,8 @@
|
|
|
735
745
|
background: hsl(var(--background));
|
|
736
746
|
}
|
|
737
747
|
.ui-tag-input:focus-within {
|
|
738
|
-
box-shadow: 0 0 0
|
|
739
|
-
border-color: hsl(var(--ring));
|
|
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)));
|
|
740
750
|
}
|
|
741
751
|
.ui-tag-input-disabled {
|
|
742
752
|
opacity: 0.6;
|
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
justify-content: center;
|
|
10
10
|
overflow: hidden;
|
|
11
11
|
border-radius: var(--radius-pill);
|
|
12
|
-
background
|
|
12
|
+
/* Tint washes over the role background (default transparent = no-op, rule #44). */
|
|
13
|
+
background:
|
|
14
|
+
linear-gradient(var(--avatar-tint), var(--avatar-tint)),
|
|
15
|
+
var(--avatar-background, hsl(var(--muted)));
|
|
13
16
|
color: hsl(var(--muted-foreground));
|
|
14
17
|
font-size: var(--font-size-base);
|
|
15
18
|
font-weight: var(--font-weight-medium);
|
|
@@ -27,7 +30,7 @@
|
|
|
27
30
|
height: 100%;
|
|
28
31
|
align-items: center;
|
|
29
32
|
justify-content: center;
|
|
30
|
-
background: hsl(var(--muted));
|
|
33
|
+
background: var(--avatar-background, hsl(var(--muted)));
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
.ui-progress {
|
|
@@ -40,13 +43,13 @@
|
|
|
40
43
|
height: 0.5rem;
|
|
41
44
|
overflow: hidden;
|
|
42
45
|
border-radius: var(--radius-pill);
|
|
43
|
-
background: hsl(var(--secondary));
|
|
46
|
+
background: var(--progress-track-background, hsl(var(--secondary)));
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
.ui-progress-bar {
|
|
47
50
|
height: 100%;
|
|
48
51
|
border-radius: inherit;
|
|
49
|
-
background: hsl(var(--success));
|
|
52
|
+
background: var(--progress-fill-background, hsl(var(--success)));
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
.ui-progress[data-tone="warning"] .ui-progress-bar {
|
|
@@ -75,8 +78,8 @@
|
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
.ui-tree-item[data-active="true"] {
|
|
78
|
-
border-color: hsl(var(--primary) / 0.3);
|
|
79
|
-
background: hsl(var(--primary) / 0.05);
|
|
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));
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
.ui-tree-item[data-depth="1"] {
|
|
@@ -151,7 +154,7 @@
|
|
|
151
154
|
place-items: center;
|
|
152
155
|
border: 1px solid transparent;
|
|
153
156
|
border-radius: var(--radius-pill);
|
|
154
|
-
background: hsl(var(--success));
|
|
157
|
+
background: var(--timeline-dot-done-background, hsl(var(--success)));
|
|
155
158
|
color: hsl(var(--success-foreground));
|
|
156
159
|
font-size: var(--timeline-note-font-size);
|
|
157
160
|
font-weight: var(--font-weight-medium);
|
|
@@ -160,14 +163,14 @@
|
|
|
160
163
|
|
|
161
164
|
/* done → success fill. */
|
|
162
165
|
.ui-timeline-dot[data-status="done"] {
|
|
163
|
-
background: hsl(var(--success));
|
|
166
|
+
background: var(--timeline-dot-done-background, hsl(var(--success)));
|
|
164
167
|
color: hsl(var(--success-foreground));
|
|
165
168
|
}
|
|
166
169
|
|
|
167
170
|
/* current → primary fill + ring (also the legacy data-current shorthand). */
|
|
168
171
|
.ui-timeline-dot[data-status="current"],
|
|
169
172
|
.ui-timeline-dot[data-current="true"] {
|
|
170
|
-
background: hsl(var(--primary));
|
|
173
|
+
background: var(--timeline-dot-current-background, hsl(var(--primary)));
|
|
171
174
|
color: hsl(var(--primary-foreground));
|
|
172
175
|
box-shadow: 0 0 0 3px hsl(var(--primary) / 0.18);
|
|
173
176
|
}
|
|
@@ -202,7 +205,7 @@
|
|
|
202
205
|
|
|
203
206
|
/* The segment below a done/current step reads as travelled (completed). */
|
|
204
207
|
.ui-timeline-line[data-completed="true"] {
|
|
205
|
-
background: hsl(var(--primary));
|
|
208
|
+
background: var(--timeline-line-completed-background, hsl(var(--primary)));
|
|
206
209
|
}
|
|
207
210
|
|
|
208
211
|
.ui-timeline-head {
|
|
@@ -256,7 +259,7 @@
|
|
|
256
259
|
text-decoration: underline;
|
|
257
260
|
}
|
|
258
261
|
.ui-accordion-trigger:focus-visible {
|
|
259
|
-
outline:
|
|
262
|
+
outline: var(--focus-ring-width) solid hsl(var(--focus-ring-color, var(--ring)));
|
|
260
263
|
outline-offset: 2px;
|
|
261
264
|
border-radius: var(--radius-sm);
|
|
262
265
|
}
|
|
@@ -383,7 +386,7 @@
|
|
|
383
386
|
}
|
|
384
387
|
|
|
385
388
|
.ui-carousel-dot:focus-visible {
|
|
386
|
-
outline:
|
|
389
|
+
outline: var(--focus-ring-width) solid hsl(var(--focus-ring-color, var(--ring)));
|
|
387
390
|
outline-offset: 2px;
|
|
388
391
|
}
|
|
389
392
|
|
|
@@ -441,7 +444,7 @@
|
|
|
441
444
|
align-items: flex-start;
|
|
442
445
|
}
|
|
443
446
|
[data-slot="list-row"]:not(:last-child) {
|
|
444
|
-
border-block-end: var(--list-row-border);
|
|
447
|
+
border-block-end: var(--list-row-border, 1px solid hsl(var(--border)));
|
|
445
448
|
}
|
|
446
449
|
[data-slot="list-row-leading"] {
|
|
447
450
|
display: inline-flex;
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
.ui-time-input:focus-visible {
|
|
86
|
-
border-color: hsl(var(--ring));
|
|
87
|
-
box-shadow: 0 0 0 3px hsl(var(--ring) / 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"] {
|
|
@@ -21,11 +21,15 @@
|
|
|
21
21
|
border-top: 1px solid hsl(var(--border));
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
.ui-dialog-overlay,
|
|
25
|
+
[data-slot="sheet-overlay"] {
|
|
26
|
+
background-color: var(--overlay-background);
|
|
27
|
+
}
|
|
28
|
+
|
|
24
29
|
.ui-dialog-overlay {
|
|
25
30
|
position: fixed;
|
|
26
31
|
inset: 0;
|
|
27
32
|
z-index: 50;
|
|
28
|
-
background-color: rgb(0 0 0 / 0.5);
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
[data-slot="dialog-content"] {
|
|
@@ -43,7 +47,7 @@
|
|
|
43
47
|
padding: var(--dialog-space-inset);
|
|
44
48
|
/* clip so the full-bleed header/footer bands round with the dialog corners (Ant Modal). */
|
|
45
49
|
overflow: hidden;
|
|
46
|
-
box-shadow: var(--shadow-lg, 0 10px 15px -3px rgb(0 0 0 / 0.1));
|
|
50
|
+
box-shadow: var(--shadow-lg, 0 10px 15px -3px rgb(0 0 0 / 0.1)), var(--dialog-content-glow);
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
@media (min-width: 640px) {
|
package/dist/styles/index.css
CHANGED
|
@@ -41,6 +41,8 @@
|
|
|
41
41
|
* `var(--radius-2xl)` directly; without a generated utility Tailwind drops the unused var). */
|
|
42
42
|
@source inline("rounded-{xs,xl,2xl}");
|
|
43
43
|
@source inline("text-2xs");
|
|
44
|
+
@source inline("text-{3xl,4xl,5xl}");
|
|
45
|
+
@source inline("text-{success,warning,info,error}-strong");
|
|
44
46
|
/* `.js` matters: the published package ships only compiled JS under dist (no
|
|
45
47
|
* .tsx sources), and this file is copied verbatim into dist/styles — without
|
|
46
48
|
* it Tailwind finds no component classes in consumers (unstyled popovers and
|
|
@@ -64,7 +66,14 @@
|
|
|
64
66
|
@import "./navigation-layout.css";
|
|
65
67
|
@import "./chart-layout.css";
|
|
66
68
|
|
|
67
|
-
@theme
|
|
69
|
+
/* `inline` (NOT a bare @theme): Tailwind inlines each expression — e.g. `hsl(var(--primary))` —
|
|
70
|
+
* directly into every utility (`bg-primary` becomes `background-color: hsl(var(--primary))`) instead
|
|
71
|
+
* of emitting `var(--color-primary)` computed once at :root. This is THE enabler for scoped /
|
|
72
|
+
* multi-tenant theming: a `[data-tenant]{ --primary: … }` override now re-resolves at the element,
|
|
73
|
+
* so colors and radius propagate into a subtree (a plain @theme froze them at :root, so scoped
|
|
74
|
+
* overrides never reached the color utilities). Components read raw tokens like `hsl(var(--primary))`
|
|
75
|
+
* directly in their own CSS, so they re-theme the same way. */
|
|
76
|
+
@theme inline {
|
|
68
77
|
--color-background: hsl(var(--background));
|
|
69
78
|
--color-foreground: hsl(var(--foreground));
|
|
70
79
|
--color-card: hsl(var(--card));
|
|
@@ -92,6 +101,12 @@
|
|
|
92
101
|
--color-info-foreground: hsl(var(--info-foreground));
|
|
93
102
|
--color-attention: hsl(var(--attention));
|
|
94
103
|
--color-attention-foreground: hsl(var(--attention-foreground));
|
|
104
|
+
/* AA-strong status TEXT colours (text-{success,warning,info,error}-strong) — darker than the
|
|
105
|
+
* fills so small coloured labels clear WCAG AA on white; flip light on the dark theme. */
|
|
106
|
+
--color-success-strong: hsl(var(--text-success));
|
|
107
|
+
--color-warning-strong: hsl(var(--text-warning));
|
|
108
|
+
--color-info-strong: hsl(var(--text-info));
|
|
109
|
+
--color-error-strong: hsl(var(--text-error));
|
|
95
110
|
--color-chart-1: var(--chart-1);
|
|
96
111
|
--color-chart-2: var(--chart-2);
|
|
97
112
|
--color-chart-3: var(--chart-3);
|
|
@@ -145,6 +160,10 @@
|
|
|
145
160
|
--text-lg: var(--font-size-lg);
|
|
146
161
|
--text-xl: var(--font-size-xl);
|
|
147
162
|
--text-2xl: var(--font-size-2xl);
|
|
163
|
+
/* Opt-in DISPLAY ramp (marketing/hero) — wired to the display tokens, unused by the admin scale. */
|
|
164
|
+
--text-3xl: var(--font-size-3xl);
|
|
165
|
+
--text-4xl: var(--font-size-4xl);
|
|
166
|
+
--text-5xl: var(--font-size-5xl);
|
|
148
167
|
}
|
|
149
168
|
|
|
150
169
|
@layer base {
|
|
@@ -172,7 +191,9 @@
|
|
|
172
191
|
body {
|
|
173
192
|
background-color: hsl(var(--background));
|
|
174
193
|
color: hsl(var(--foreground));
|
|
175
|
-
font-family
|
|
194
|
+
/* Body reads --font-family-body (defaults to --font-family-sans → unchanged); a service that
|
|
195
|
+
* wants a dual-font brand (display + body face) overrides --font-family-body alone. */
|
|
196
|
+
font-family: var(--font-family-body);
|
|
176
197
|
font-size: var(--font-size-base);
|
|
177
198
|
line-height: var(--line-height-body);
|
|
178
199
|
font-feature-settings:
|
|
@@ -186,7 +207,13 @@
|
|
|
186
207
|
|
|
187
208
|
/* Semantic heading scale — SEO + accessibility: real <h1>–<h6> elements carry
|
|
188
209
|
* the document outline (one <h1> per page, levels never skipped). Visual size
|
|
189
|
-
* follows the dxs-kintai scale; component titles override via their own class.
|
|
210
|
+
* follows the dxs-kintai scale; component titles override via their own class.
|
|
211
|
+
* Headings read --font-family-display (defaults to --font-family-sans → unchanged) for dual-font
|
|
212
|
+
* brands (display face on headings, body face on prose). */
|
|
213
|
+
:where(h1, h2, h3, h4, h5, h6) {
|
|
214
|
+
font-family: var(--font-family-display);
|
|
215
|
+
}
|
|
216
|
+
|
|
190
217
|
h1 {
|
|
191
218
|
font-size: var(--heading-h1);
|
|
192
219
|
font-weight: var(--font-weight-medium);
|
package/dist/styles/layout.css
CHANGED
|
@@ -345,6 +345,9 @@
|
|
|
345
345
|
gap: var(--space-stack-sm);
|
|
346
346
|
padding-bottom: var(--page-header-pad-bottom);
|
|
347
347
|
border-bottom: var(--page-header-divider);
|
|
348
|
+
/* Hero banner hook — invisible by default (--gradient-hero: none); a service paints a hero
|
|
349
|
+
* gradient across the page header (full-bleed) by configuring the token alone. */
|
|
350
|
+
background-image: var(--gradient-hero);
|
|
348
351
|
}
|
|
349
352
|
|
|
350
353
|
.ui-page-header-row {
|
|
@@ -494,7 +497,10 @@
|
|
|
494
497
|
width: 3rem;
|
|
495
498
|
height: 3rem;
|
|
496
499
|
border-radius: var(--radius-pill);
|
|
497
|
-
|
|
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)));
|
|
498
504
|
}
|
|
499
505
|
}
|
|
500
506
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
background: hsl(var(--popover));
|
|
9
9
|
color: hsl(var(--popover-foreground));
|
|
10
10
|
padding: var(--space-1);
|
|
11
|
-
box-shadow: var(--shadow-md);
|
|
11
|
+
box-shadow: var(--shadow-md), var(--shadow-glow);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
.ui-context-menu-item,
|
|
@@ -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: hsl(var(--accent));
|
|
59
|
-
color: hsl(var(--accent-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: hsl(var(--accent));
|
|
72
|
-
color: hsl(var(--accent-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"],
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
background: hsl(var(--popover));
|
|
147
147
|
color: hsl(var(--popover-foreground));
|
|
148
148
|
padding: var(--space-1);
|
|
149
|
-
box-shadow: var(--shadow-md);
|
|
149
|
+
box-shadow: var(--shadow-md), var(--shadow-glow);
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
.ui-context-menu-sub-trigger-icon,
|
|
@@ -179,13 +179,13 @@
|
|
|
179
179
|
background: hsl(var(--popover));
|
|
180
180
|
color: hsl(var(--popover-foreground));
|
|
181
181
|
padding: var(--space-1);
|
|
182
|
-
box-shadow: var(--shadow-md);
|
|
182
|
+
box-shadow: var(--shadow-md), var(--shadow-glow);
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
.ui-menubar-trigger[data-state="open"],
|
|
186
186
|
.ui-menubar-sub-trigger[data-state="open"] {
|
|
187
|
-
background: hsl(var(--accent));
|
|
188
|
-
color: hsl(var(--accent-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 {
|
|
@@ -233,7 +233,7 @@
|
|
|
233
233
|
background: hsl(var(--popover));
|
|
234
234
|
color: hsl(var(--popover-foreground));
|
|
235
235
|
padding: var(--space-1);
|
|
236
|
-
box-shadow: var(--shadow-md);
|
|
236
|
+
box-shadow: var(--shadow-md), var(--shadow-glow);
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
.ui-navigation-menu-link {
|
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
overflow: hidden;
|
|
31
31
|
border-inline-end: 1px solid hsl(var(--border));
|
|
32
32
|
background: hsl(var(--card));
|
|
33
|
+
/* Opt-in brand-chrome wash — invisible by default (--sidebar-gradient: none). */
|
|
34
|
+
background-image: var(--sidebar-gradient);
|
|
33
35
|
color: hsl(var(--foreground));
|
|
34
36
|
}
|
|
35
37
|
|
|
@@ -45,6 +47,8 @@
|
|
|
45
47
|
padding-inline: var(--space-4);
|
|
46
48
|
border-bottom: 1px solid hsl(var(--border));
|
|
47
49
|
background: hsl(var(--background) / 0.92);
|
|
50
|
+
/* Opt-in brand-chrome wash — invisible by default (--topbar-gradient: none). */
|
|
51
|
+
background-image: var(--topbar-gradient);
|
|
48
52
|
backdrop-filter: blur(12px);
|
|
49
53
|
}
|
|
50
54
|
|
|
@@ -52,6 +56,9 @@
|
|
|
52
56
|
grid-area: main;
|
|
53
57
|
min-width: 0;
|
|
54
58
|
overflow: auto;
|
|
59
|
+
/* Ambient brand glow hook — invisible by default (--gradient-glow: none); a service paints a
|
|
60
|
+
* radial/linear brand wash behind the whole content area by configuring the token alone. */
|
|
61
|
+
background-image: var(--gradient-glow);
|
|
55
62
|
/* Sole scroll/clip boundary for the page area. `overflow:auto` alone does NOT reliably
|
|
56
63
|
* establish a paint-containment boundary in Chrome: tall nested scrollers (a two-pane
|
|
57
64
|
* `grid` of long lists, a nested `overflow-y:auto` region) — or any absolutely-positioned
|
|
@@ -254,13 +261,17 @@
|
|
|
254
261
|
text-align: start;
|
|
255
262
|
}
|
|
256
263
|
|
|
257
|
-
.sb-nav-item:hover
|
|
258
|
-
.sb-nav-item[data-active="true"] {
|
|
264
|
+
.sb-nav-item:hover {
|
|
259
265
|
background: hsl(var(--accent));
|
|
260
266
|
color: hsl(var(--foreground));
|
|
261
267
|
}
|
|
262
268
|
|
|
269
|
+
/* Active item reads its own bg/fg tokens (defaults = the hover look) so a service can give the
|
|
270
|
+
* selected nav row a brand treatment — e.g. a gold tint + gold text on a navy sidebar — without
|
|
271
|
+
* forking CSS. Defaults are byte-identical to the hover state. */
|
|
263
272
|
.sb-nav-item[data-active="true"] {
|
|
273
|
+
background: var(--sidebar-item-active-background, hsl(var(--accent)));
|
|
274
|
+
color: var(--sidebar-item-active-foreground, hsl(var(--foreground)));
|
|
264
275
|
font-weight: var(--font-weight-medium);
|
|
265
276
|
}
|
|
266
277
|
|
|
@@ -351,12 +362,12 @@
|
|
|
351
362
|
|
|
352
363
|
.sb-nav-item--sub[data-active="true"] {
|
|
353
364
|
background: transparent;
|
|
354
|
-
color: hsl(var(--primary));
|
|
365
|
+
color: var(--sidebar-item-active-color, hsl(var(--primary)));
|
|
355
366
|
font-weight: 500;
|
|
356
367
|
}
|
|
357
368
|
|
|
358
369
|
.sb-nav-item--sub[data-active="true"]::before {
|
|
359
|
-
background: hsl(var(--primary));
|
|
370
|
+
background: var(--sidebar-item-active-tint, hsl(var(--primary)));
|
|
360
371
|
opacity: 1;
|
|
361
372
|
}
|
|
362
373
|
|
|
@@ -406,7 +417,7 @@
|
|
|
406
417
|
}
|
|
407
418
|
|
|
408
419
|
.sb-user:focus-visible {
|
|
409
|
-
box-shadow: 0 0 0 var(--
|
|
420
|
+
box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color, var(--ring)) / 0.45);
|
|
410
421
|
}
|
|
411
422
|
|
|
412
423
|
.sb-user-avatar {
|
|
@@ -649,7 +660,7 @@
|
|
|
649
660
|
}
|
|
650
661
|
|
|
651
662
|
.tb-icon-btn:focus-visible {
|
|
652
|
-
box-shadow: 0 0 0 var(--
|
|
663
|
+
box-shadow: 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color, var(--ring)) / 0.45);
|
|
653
664
|
}
|
|
654
665
|
|
|
655
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: hsl(var(--
|
|
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: hsl(var(--muted-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: hsl(var(--muted) / 0.4);
|
|
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(
|
|
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(
|
|
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
|
}
|
|
@@ -24,15 +24,35 @@
|
|
|
24
24
|
--card-title-font-weight: var(--font-weight-semibold);
|
|
25
25
|
--card-description-font-size: var(--font-size-sm);
|
|
26
26
|
--card-description-line-height: var(--line-height-normal);
|
|
27
|
-
--card
|
|
28
|
-
|
|
29
|
-
|
|
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)) */
|
|
30
38
|
--card-header-background-alpha: 0.55;
|
|
31
39
|
/* Banded-header divider — tokenised (rule #44) so a service theme can make it
|
|
32
40
|
* dashed / heavier / none without forking CSS. Pair with
|
|
33
|
-
* --card-header-background-alpha: 0 for a quiet borderless-band header.
|
|
34
|
-
|
|
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;
|
|
35
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;
|
|
36
56
|
/* Accent edge — width of the semantic leading-edge stripe (data-accent).
|
|
37
57
|
* Tokenised (rule #44) so a service theme can re-tune it without forking CSS.
|
|
38
58
|
* The slot padding compensation in card-layout.css subtracts the same token,
|
|
@@ -47,5 +67,13 @@
|
|
|
47
67
|
--stat-card-hint-font-size: var(--font-size-xs);
|
|
48
68
|
--stat-card-gap: var(--space-stack-xs);
|
|
49
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;
|
|
50
78
|
--stat-card-delta-font-size: var(--font-size-xs);
|
|
51
79
|
}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
--control-radius: var(--radius);
|
|
21
21
|
--control-icon-size: calc(1rem * var(--scaling));
|
|
22
22
|
--control-icon-size-sm: calc(0.875rem * var(--scaling));
|
|
23
|
-
--control-focus-ring-width:
|
|
23
|
+
--control-focus-ring-width: var(--focus-ring-width);
|
|
24
24
|
|
|
25
25
|
--checkbox-size: calc(1rem * var(--scaling));
|
|
26
26
|
--checkbox-size-compact: 0.875rem;
|
|
@@ -47,6 +47,16 @@
|
|
|
47
47
|
--slider-track-height: 0.375rem;
|
|
48
48
|
--slider-thumb-size: 1rem;
|
|
49
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
|
+
|
|
50
60
|
--color-picker-input-width: 6.5rem;
|
|
51
61
|
|
|
52
62
|
--command-list-max-height: min(300px, 50vh);
|
|
@@ -5,4 +5,30 @@
|
|
|
5
5
|
--tree-item-title-font-size: var(--font-size-xs);
|
|
6
6
|
--tree-item-description-font-size: var(--font-size-xs);
|
|
7
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;
|
|
8
34
|
}
|
|
@@ -16,10 +16,24 @@
|
|
|
16
16
|
* (a brand's success-bg/-border are often more present than the faint 5%/30% default). */
|
|
17
17
|
--alert-bg-alpha: 0.05;
|
|
18
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;
|
|
19
23
|
--empty-state-space-y: var(--space-10);
|
|
20
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;
|
|
21
31
|
--skeleton-row-gap: var(--space-stack-sm);
|
|
22
32
|
--skeleton-cell-gap: var(--space-inline-lg);
|
|
23
33
|
--skeleton-card-inset: var(--space-section-active);
|
|
24
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;
|
|
25
39
|
}
|
|
@@ -5,5 +5,7 @@
|
|
|
5
5
|
--list-row-padding-y: var(--space-3);
|
|
6
6
|
--list-row-padding-x: var(--space-4);
|
|
7
7
|
--list-row-gap: var(--space-3);
|
|
8
|
-
--
|
|
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;
|
|
9
11
|
}
|
|
@@ -12,4 +12,10 @@
|
|
|
12
12
|
--filter-picker-width-md: 14rem;
|
|
13
13
|
--breadcrumb-font-size: var(--font-size-xs);
|
|
14
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;
|
|
15
21
|
}
|
|
@@ -14,4 +14,22 @@
|
|
|
14
14
|
--sidebar-logo-mark-font-size: var(--font-size-xs);
|
|
15
15
|
--sidebar-avatar-font-size: var(--font-size-2xs);
|
|
16
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;
|
|
17
35
|
}
|
|
@@ -8,6 +8,19 @@
|
|
|
8
8
|
--table-cell-padding-y: var(--space-2);
|
|
9
9
|
--table-cell-space-x: var(--control-padding-x);
|
|
10
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;
|
|
11
18
|
/* Inline-end shadow that lifts a pinned (sticky) action column off the body it scrolls over. */
|
|
12
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;
|
|
13
26
|
}
|
|
@@ -37,6 +37,13 @@
|
|
|
37
37
|
--text-disabled: 40 6% 68%; /* disabled control text */
|
|
38
38
|
--text-link: 204 100% 39%; /* inline link — defaults to brand blue */
|
|
39
39
|
--text-brand: 204 100% 39%; /* brand-colored text / numerals */
|
|
40
|
+
/* Status TEXT colours — darker than the fill roles so small coloured text (a StatCard delta, an
|
|
41
|
+
* outline status badge label) clears WCAG AA 4.5:1 on white. The fill roles (--success/--warning/
|
|
42
|
+
* --info) stay the brighter wa-iro for badges/bars; only TEXT reads these via text-*-strong. */
|
|
43
|
+
--text-success: 152 84% 22%; /* deep 若竹 — AA green text on white */
|
|
44
|
+
--text-warning: 36 100% 28%; /* dark 山吹 amber — yellow can never pass as text */
|
|
45
|
+
--text-info: 221 70% 38%; /* deep 群青 — AA blue text on white */
|
|
46
|
+
--text-error: 357 75% 38%; /* deep 茜 — AA red text on white */
|
|
40
47
|
|
|
41
48
|
/* Interaction ramp — hover / active steps (services override to their own brand ramp). */
|
|
42
49
|
--primary-hover: 204 100% 33%;
|
|
@@ -93,6 +100,35 @@
|
|
|
93
100
|
0 20px 25px -5px rgb(var(--shadow-color) / 0.1), 0 8px 10px -6px rgb(var(--shadow-color) / 0.1);
|
|
94
101
|
--shadow-2xl: 0 25px 50px -12px rgb(var(--shadow-color) / 0.25);
|
|
95
102
|
|
|
103
|
+
/* Brand GLOW — an opt-in coloured halo for the primary CTA (and any surface that opts in).
|
|
104
|
+
* Quiet by default (cardinal rule #44): a zero-size transparent shadow, which is invalid as a
|
|
105
|
+
* bare `none` inside a comma shadow list but valid as `0 0 0 0 transparent`. A service turns it
|
|
106
|
+
* on by overriding the whole value once, e.g. `--shadow-glow: 0 8px 20px hsl(var(--primary) / .32)`
|
|
107
|
+
* — the CTA then carries a brand glow with no component change. */
|
|
108
|
+
--shadow-glow: 0 0 0 0 transparent;
|
|
109
|
+
|
|
110
|
+
/* FOCUS RING — the two global knobs for the keyboard-focus affordance (WCAG 2.4.7 / 2.4.11).
|
|
111
|
+
* `--focus-ring-color` is the themeable hue (HSL components, defaults to --ring) and
|
|
112
|
+
* `--focus-ring-width` the standard thickness; override either ONCE — even scoped under a
|
|
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
|
+
--focus-ring-width: 2px;
|
|
120
|
+
|
|
121
|
+
/* GRADIENTS — opt-in decorative fills exposed at the token layer so a service can paint a hero
|
|
122
|
+
* banner, a brand wash, or a radial brand glow purely by configuring tokens (cardinal rule #45).
|
|
123
|
+
* All default to a transparent no-op so nothing renders until a theme opts in; a surface that
|
|
124
|
+
* supports a gradient reads one of these as its background-image. Examples a service might set:
|
|
125
|
+
* --gradient-brand: linear-gradient(135deg, hsl(var(--primary)), hsl(var(--accent)));
|
|
126
|
+
* --gradient-hero: linear-gradient(180deg, hsl(var(--secondary)), hsl(var(--background)));
|
|
127
|
+
* --gradient-glow: radial-gradient(60% 80% at 50% 0%, hsl(var(--primary) / .25), transparent); */
|
|
128
|
+
--gradient-brand: none;
|
|
129
|
+
--gradient-hero: none;
|
|
130
|
+
--gradient-glow: none;
|
|
131
|
+
|
|
96
132
|
/* Sans stack — script-aware per the international convention for mixed
|
|
97
133
|
* Latin/CJK UI: native Latin system fonts FIRST (clean, familiar English &
|
|
98
134
|
* DEFAULT face is the bundled "Noto Sans JP" (Japanese + clean Latin), with system sans as
|
|
@@ -103,6 +139,12 @@
|
|
|
103
139
|
"Noto Sans JP", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
|
|
104
140
|
system-ui, "Hiragino Sans", sans-serif;
|
|
105
141
|
--font-family-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
142
|
+
/* Dual-font split (opt-in) — many brand designs pair a DISPLAY face for headings with a separate
|
|
143
|
+
* BODY face (e.g. Source Sans 3 display + Inter body). Both default to --font-family-sans, so a
|
|
144
|
+
* single-font system is unchanged; a service overrides one or both. Headings read
|
|
145
|
+
* --font-family-display, body reads --font-family-body (wired in styles/index.css @layer base). */
|
|
146
|
+
--font-family-display: var(--font-family-sans);
|
|
147
|
+
--font-family-body: var(--font-family-sans);
|
|
106
148
|
/* ── Type scale — GOLDEN-RATIO modular scale (Ant/Tailwind model). ONE base + ONE ratio; every
|
|
107
149
|
* step is base × ratioⁿ, so the whole scale stays in golden proportion. `--font-size-ratio` is
|
|
108
150
|
* φ^¼ (the golden ratio's quarter-step ≈ 1.1227) — a TRUE golden ratio yet dense enough that
|
|
@@ -122,6 +164,19 @@
|
|
|
122
164
|
--font-size-xl: calc(var(--font-size-lg) * var(--font-size-ratio)); /* ratio³ ≈ 19.8px */
|
|
123
165
|
--font-size-2xl: calc(var(--font-size-xl) * var(--font-size-ratio)); /* ratio⁴ ≈ 22.3px */
|
|
124
166
|
|
|
167
|
+
/* DISPLAY type — OPT-IN large sizes for MARKETING / hero surfaces (landing pages, CTA banners).
|
|
168
|
+
* The enterprise heading scale stays small by design (h1 = 20px, 渋み restraint); these are a
|
|
169
|
+
* SEPARATE bolder ramp a marketing surface opts into via the text-3xl/-4xl/-5xl utilities (wired
|
|
170
|
+
* in styles/index.css @theme). A service rescales the whole display ramp from --font-size-display
|
|
171
|
+
* (its own base). Nothing in the admin system uses them, so defaults are unchanged. */
|
|
172
|
+
--font-size-display: 3.375rem; /* 54px — hero display (the single display knob) */
|
|
173
|
+
--font-size-display-ratio: 1.28; /* bolder step than the body φ^¼ — marketing wants more contrast */
|
|
174
|
+
--font-size-3xl: calc(
|
|
175
|
+
var(--font-size-display) / var(--font-size-display-ratio) / var(--font-size-display-ratio)
|
|
176
|
+
); /* ≈ 33 → 28px feature heading */
|
|
177
|
+
--font-size-4xl: calc(var(--font-size-display) / var(--font-size-display-ratio)); /* ≈ 36px section */
|
|
178
|
+
--font-size-5xl: var(--font-size-display); /* 54px hero */
|
|
179
|
+
|
|
125
180
|
/* Headings — also golden-derived. h1=ratio³, h2=ratio²; h3/h4 reuse body sizes (single source). */
|
|
126
181
|
--heading-h1: calc(
|
|
127
182
|
var(--font-size-base) * var(--font-size-ratio) * var(--font-size-ratio) * var(--font-size-ratio)
|
|
@@ -139,6 +194,10 @@
|
|
|
139
194
|
* so any remaining reference renders at 500. `bold` is the 700 emphasis weight. */
|
|
140
195
|
--font-weight-semibold: 500;
|
|
141
196
|
--font-weight-bold: 700;
|
|
197
|
+
/* Display/black weight — OPT-IN for marketing display type (hero/CTA). The enterprise system caps
|
|
198
|
+
* at 700 (簡素 restraint); this is only reached via the .font-display-weight utility / a service
|
|
199
|
+
* setting it on a display surface, so admin text is unchanged. */
|
|
200
|
+
--font-weight-black: 800;
|
|
142
201
|
--line-height-tight: 1.25;
|
|
143
202
|
--line-height-normal: 1.5;
|
|
144
203
|
--line-height-body: 1.7;
|
|
@@ -285,6 +344,11 @@
|
|
|
285
344
|
--text-disabled: 45 6% 40%;
|
|
286
345
|
--text-link: 204 90% 66%;
|
|
287
346
|
--text-brand: 204 90% 66%;
|
|
347
|
+
/* Status text on the dark spine reads LIGHT (AA on dark surfaces). */
|
|
348
|
+
--text-success: 146 55% 64%;
|
|
349
|
+
--text-warning: 44 95% 62%;
|
|
350
|
+
--text-info: 221 70% 72%;
|
|
351
|
+
--text-error: 357 75% 68%;
|
|
288
352
|
--primary-hover: 204 90% 66%;
|
|
289
353
|
--primary-active: 204 90% 72%;
|
|
290
354
|
--secondary-hover: 45 6% 22%;
|
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
--space-page-active-y: var(--space-page-y);
|
|
23
23
|
--space-section-active: var(--space-section);
|
|
24
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
|
+
|
|
25
30
|
/* Full-bleed rule under the PageContainer header. OFF by default — the title/body
|
|
26
31
|
* gap already separates them; a divider is a service-theme opt-in:
|
|
27
32
|
* `--page-header-divider: 1px solid hsl(var(--border));` */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@godxjp/ui",
|
|
3
|
-
"version": "16.
|
|
3
|
+
"version": "16.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"packageManager": "pnpm@10.29.1",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -275,7 +275,7 @@
|
|
|
275
275
|
"test:coverage": "vitest run --coverage",
|
|
276
276
|
"check:example-imports": "node scripts/check-example-imports.mjs",
|
|
277
277
|
"verify": "pnpm typecheck && pnpm lint && pnpm format && pnpm build && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-token-sync && pnpm check:mcp-sync && pnpm check:mcp-orphans && pnpm check:audit-sync && pnpm test",
|
|
278
|
-
"verify:release": "pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm build && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-token-sync && pnpm check:mcp-sync && pnpm check:mcp-orphans && pnpm check:audit-sync && pnpm check:mcp-prop-sync && pnpm test",
|
|
278
|
+
"verify:release": "pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm build && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-token-sync && pnpm check:mcp-sync && pnpm check:mcp-orphans && pnpm check:audit-sync && pnpm check:mcp-prop-sync && pnpm check:contrast && pnpm test",
|
|
279
279
|
"check:mcp-sync": "node scripts/check-mcp-sync.mjs",
|
|
280
280
|
"check:mcp-orphans": "node scripts/check-mcp-orphans.mjs",
|
|
281
281
|
"check:mcp-prop-sync": "node scripts/check-mcp-prop-sync.mjs",
|
|
@@ -297,6 +297,7 @@
|
|
|
297
297
|
"dev": "node scripts/dev.mjs",
|
|
298
298
|
"prepublishOnly": "pnpm run build",
|
|
299
299
|
"check:audit-sync": "node scripts/check-audit-sync.mjs",
|
|
300
|
+
"check:contrast": "node scripts/check-contrast.mjs",
|
|
300
301
|
"visual-audit": "node scripts/visual-audit.mjs",
|
|
301
302
|
"postinstall": "node scripts/postinstall.mjs",
|
|
302
303
|
"init-agent": "node scripts/init-agent-kit.mjs"
|