@gradeui/ui 2.0.0 → 3.0.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/README.md +5 -12
- package/components/ui/avatar.md +28 -3
- package/components/ui/grade-loader.md +31 -0
- package/components/ui/input.md +2 -1
- package/components/ui/logo.md +39 -13
- package/components/ui/map.md +19 -10
- package/components/ui/motion.md +109 -0
- package/dist/contracts.js +5 -5
- package/dist/contracts.js.map +1 -1
- package/dist/contracts.mjs +5 -5
- package/dist/contracts.mjs.map +1 -1
- package/dist/index.d.mts +343 -21
- package/dist/index.d.ts +343 -21
- package/dist/index.js +222 -45
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +222 -45
- package/dist/index.mjs.map +1 -1
- package/dist/map/leaflet.d.mts +6 -0
- package/dist/map/leaflet.d.ts +6 -0
- package/dist/map/leaflet.js +4 -0
- package/dist/map/leaflet.js.map +1 -0
- package/dist/map/leaflet.mjs +4 -0
- package/dist/map/leaflet.mjs.map +1 -0
- package/dist/styles.css +1 -1
- package/package.json +9 -7
- package/styles/globals.css +2278 -0
- package/dist/tailwind-preset.d.mts +0 -20
- package/dist/tailwind-preset.d.ts +0 -20
- package/dist/tailwind-preset.js +0 -2
- package/dist/tailwind-preset.js.map +0 -1
- package/dist/tailwind-preset.mjs +0 -2
- package/dist/tailwind-preset.mjs.map +0 -1
|
@@ -0,0 +1,2278 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@import "@gradeui/core/tokens.css"; /* primitive ramps + semantic aliases + type scale (layers 1-2) */
|
|
3
|
+
|
|
4
|
+
/* v4 NATIVE THEME — the v3 config bridge (tailwind.config.ts →
|
|
5
|
+
tailwind-preset.ts) is retired (THEME-MIGRATION.md Phase A). Everything
|
|
6
|
+
the preset defined lives here as native @theme declarations.
|
|
7
|
+
|
|
8
|
+
Source scanning: v4's automatic detection covers everything inside this
|
|
9
|
+
package (components/, lib/, styles/ — INCLUDING the .md sidecars, whose
|
|
10
|
+
class mentions the old @config build was already picking up via
|
|
11
|
+
auto-detection; the v3 `content` globs were additive, not exclusive).
|
|
12
|
+
Only out-of-package sources need explicit @source directives. */
|
|
13
|
+
|
|
14
|
+
/* Playground scaffolds — siloed dev-only set rendered by Studio's
|
|
15
|
+
Playground tab. Scanning them here means arbitrary Tailwind values
|
|
16
|
+
(`h-[600px]`, `md:grid-cols-[minmax(0,440px)_1fr]`, etc.) get compiled
|
|
17
|
+
into dist/styles.css — the bundle Fast Frame loads in its iframe.
|
|
18
|
+
Without this, arbitrary classes would be present in the JSX but
|
|
19
|
+
generate no CSS rules. (Path is relative to this file.) */
|
|
20
|
+
@source "../../studio/src/playbook/layouts/scaffolds-playground/*.{jsx,tsx}";
|
|
21
|
+
|
|
22
|
+
/* v3 `darkMode: "class"` — same selector the @config compat layer
|
|
23
|
+
generated, so dark: variants are unchanged. */
|
|
24
|
+
@custom-variant dark (&:is(.dark *));
|
|
25
|
+
|
|
26
|
+
@plugin "tailwindcss-animate";
|
|
27
|
+
|
|
28
|
+
/* The theme bridge. `inline` because every value here references a runtime
|
|
29
|
+
CSS variable (the GradeThemeProvider contract) — utilities must carry
|
|
30
|
+
the var() reference itself, not a second-hop --color-* theme var.
|
|
31
|
+
`reference` so none of these are re-emitted into :root (the runtime
|
|
32
|
+
vars are authored in @gradeui/core/tokens.css and the :root blocks
|
|
33
|
+
below; emitting e.g. `--shadow-lift: var(--shadow-lift)` would be
|
|
34
|
+
circular). Net effect: byte-compatible with the old @config output.
|
|
35
|
+
|
|
36
|
+
Fonts are deliberately ABSENT: the runtime vars are literally named
|
|
37
|
+
--font-sans / --font-mono (same as v4's theme namespace), so preflight's
|
|
38
|
+
`--default-font-family: var(--font-sans)` already lands on them and the
|
|
39
|
+
font-sans/font-mono utilities resolve correctly with no declaration —
|
|
40
|
+
declaring them here would be the one truly circular case. */
|
|
41
|
+
/* -- Type scale extension — `2xs` (11px) is the dense tool-panel step
|
|
42
|
+
below `xs`, used by the Studio inspector and other Figma-density
|
|
43
|
+
surfaces. Declared in a PLAIN @theme block (not inline/reference) so
|
|
44
|
+
the utility references var(--text-2xs) — that's what lets the theme
|
|
45
|
+
generator re-pitch the whole named ladder at runtime (Phase B2): a
|
|
46
|
+
modular scale writes --text-2xs…--text-7xl to :root and every text-*
|
|
47
|
+
utility follows. -- */
|
|
48
|
+
@theme {
|
|
49
|
+
--text-2xs: 0.6875rem;
|
|
50
|
+
--text-2xs--line-height: 1rem;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@theme inline reference {
|
|
54
|
+
/* -- Brand color ramps — values live in @gradeui/core as --gds-* vars. -- */
|
|
55
|
+
--color-rds-green: var(--gds-green);
|
|
56
|
+
--color-rds-green-50: var(--gds-green-50);
|
|
57
|
+
--color-rds-green-100: var(--gds-green-100);
|
|
58
|
+
--color-rds-green-200: var(--gds-green-200);
|
|
59
|
+
--color-rds-green-300: var(--gds-green-300);
|
|
60
|
+
--color-rds-green-400: var(--gds-green-400);
|
|
61
|
+
--color-rds-green-500: var(--gds-green-500);
|
|
62
|
+
--color-rds-green-600: var(--gds-green-600);
|
|
63
|
+
--color-rds-green-700: var(--gds-green-700);
|
|
64
|
+
--color-rds-green-800: var(--gds-green-800);
|
|
65
|
+
--color-rds-green-900: var(--gds-green-900);
|
|
66
|
+
--color-rds-green-950: var(--gds-green-950);
|
|
67
|
+
--color-rds-yellow: var(--gds-yellow);
|
|
68
|
+
--color-rds-yellow-50: var(--gds-yellow-50);
|
|
69
|
+
--color-rds-yellow-100: var(--gds-yellow-100);
|
|
70
|
+
--color-rds-yellow-200: var(--gds-yellow-200);
|
|
71
|
+
--color-rds-yellow-300: var(--gds-yellow-300);
|
|
72
|
+
--color-rds-yellow-400: var(--gds-yellow-400);
|
|
73
|
+
--color-rds-yellow-500: var(--gds-yellow-500);
|
|
74
|
+
--color-rds-yellow-600: var(--gds-yellow-600);
|
|
75
|
+
--color-rds-yellow-700: var(--gds-yellow-700);
|
|
76
|
+
--color-rds-yellow-800: var(--gds-yellow-800);
|
|
77
|
+
--color-rds-yellow-900: var(--gds-yellow-900);
|
|
78
|
+
--color-rds-orange: var(--gds-orange);
|
|
79
|
+
--color-rds-orange-50: var(--gds-orange-50);
|
|
80
|
+
--color-rds-orange-100: var(--gds-orange-100);
|
|
81
|
+
--color-rds-orange-200: var(--gds-orange-200);
|
|
82
|
+
--color-rds-orange-300: var(--gds-orange-300);
|
|
83
|
+
--color-rds-orange-400: var(--gds-orange-400);
|
|
84
|
+
--color-rds-orange-500: var(--gds-orange-500);
|
|
85
|
+
--color-rds-orange-600: var(--gds-orange-600);
|
|
86
|
+
--color-rds-orange-700: var(--gds-orange-700);
|
|
87
|
+
--color-rds-orange-800: var(--gds-orange-800);
|
|
88
|
+
--color-rds-orange-900: var(--gds-orange-900);
|
|
89
|
+
--color-rds-red: var(--gds-red);
|
|
90
|
+
--color-rds-red-50: var(--gds-red-50);
|
|
91
|
+
--color-rds-red-100: var(--gds-red-100);
|
|
92
|
+
--color-rds-red-200: var(--gds-red-200);
|
|
93
|
+
--color-rds-red-300: var(--gds-red-300);
|
|
94
|
+
--color-rds-red-400: var(--gds-red-400);
|
|
95
|
+
--color-rds-red-500: var(--gds-red-500);
|
|
96
|
+
--color-rds-red-600: var(--gds-red-600);
|
|
97
|
+
--color-rds-red-700: var(--gds-red-700);
|
|
98
|
+
--color-rds-red-800: var(--gds-red-800);
|
|
99
|
+
--color-rds-red-900: var(--gds-red-900);
|
|
100
|
+
--color-rds-teal: var(--gds-teal);
|
|
101
|
+
--color-rds-teal-50: var(--gds-teal-50);
|
|
102
|
+
--color-rds-teal-100: var(--gds-teal-100);
|
|
103
|
+
--color-rds-teal-200: var(--gds-teal-200);
|
|
104
|
+
--color-rds-teal-300: var(--gds-teal-300);
|
|
105
|
+
--color-rds-teal-400: var(--gds-teal-400);
|
|
106
|
+
--color-rds-teal-500: var(--gds-teal-500);
|
|
107
|
+
--color-rds-teal-600: var(--gds-teal-600);
|
|
108
|
+
--color-rds-teal-700: var(--gds-teal-700);
|
|
109
|
+
--color-rds-teal-800: var(--gds-teal-800);
|
|
110
|
+
--color-rds-teal-900: var(--gds-teal-900);
|
|
111
|
+
--color-rds-teal-950: var(--gds-teal-950);
|
|
112
|
+
--color-rds-navy: var(--gds-navy);
|
|
113
|
+
--color-rds-navy-50: var(--gds-navy-50);
|
|
114
|
+
--color-rds-navy-100: var(--gds-navy-100);
|
|
115
|
+
--color-rds-navy-200: var(--gds-navy-200);
|
|
116
|
+
--color-rds-navy-300: var(--gds-navy-300);
|
|
117
|
+
--color-rds-navy-400: var(--gds-navy-400);
|
|
118
|
+
--color-rds-navy-500: var(--gds-navy-500);
|
|
119
|
+
--color-rds-navy-600: var(--gds-navy-600);
|
|
120
|
+
--color-rds-navy-700: var(--gds-navy-700);
|
|
121
|
+
--color-rds-navy-800: var(--gds-navy-800);
|
|
122
|
+
--color-rds-navy-900: var(--gds-navy-900);
|
|
123
|
+
--color-rds-blue: var(--gds-blue);
|
|
124
|
+
--color-rds-blue-50: var(--gds-blue-50);
|
|
125
|
+
--color-rds-blue-100: var(--gds-blue-100);
|
|
126
|
+
--color-rds-blue-200: var(--gds-blue-200);
|
|
127
|
+
--color-rds-blue-300: var(--gds-blue-300);
|
|
128
|
+
--color-rds-blue-400: var(--gds-blue-400);
|
|
129
|
+
--color-rds-blue-500: var(--gds-blue-500);
|
|
130
|
+
--color-rds-blue-600: var(--gds-blue-600);
|
|
131
|
+
--color-rds-blue-700: var(--gds-blue-700);
|
|
132
|
+
--color-rds-blue-800: var(--gds-blue-800);
|
|
133
|
+
--color-rds-blue-900: var(--gds-blue-900);
|
|
134
|
+
--color-rds-gray-50: var(--gds-gray-50);
|
|
135
|
+
--color-rds-gray-100: var(--gds-gray-100);
|
|
136
|
+
--color-rds-gray-200: var(--gds-gray-200);
|
|
137
|
+
--color-rds-gray-300: var(--gds-gray-300);
|
|
138
|
+
--color-rds-gray-400: var(--gds-gray-400);
|
|
139
|
+
--color-rds-gray-500: var(--gds-gray-500);
|
|
140
|
+
--color-rds-gray-600: var(--gds-gray-600);
|
|
141
|
+
--color-rds-gray-700: var(--gds-gray-700);
|
|
142
|
+
--color-rds-gray-800: var(--gds-gray-800);
|
|
143
|
+
--color-rds-gray-900: var(--gds-gray-900);
|
|
144
|
+
--color-rds-gray-950: var(--gds-gray-950);
|
|
145
|
+
--color-rds-black: var(--gds-black);
|
|
146
|
+
--color-rds-white: var(--gds-white);
|
|
147
|
+
|
|
148
|
+
/* -- Semantic roles — runtime vars hold bare "L C H" OKLCH triplets,
|
|
149
|
+
wrapped with oklch() at use. Opacity shortcuts (bg-primary/50) come
|
|
150
|
+
out as color-mix() under v4 — visually identical to the old
|
|
151
|
+
<alpha-value> substitution. -- */
|
|
152
|
+
--color-border: oklch(var(--border));
|
|
153
|
+
--color-input: oklch(var(--input));
|
|
154
|
+
--color-ring: oklch(var(--ring));
|
|
155
|
+
--color-background: oklch(var(--background));
|
|
156
|
+
--color-foreground: oklch(var(--foreground));
|
|
157
|
+
--color-primary: oklch(var(--primary));
|
|
158
|
+
--color-primary-foreground: oklch(var(--primary-foreground));
|
|
159
|
+
--color-secondary: oklch(var(--secondary));
|
|
160
|
+
--color-secondary-foreground: oklch(var(--secondary-foreground));
|
|
161
|
+
--color-destructive: oklch(var(--destructive));
|
|
162
|
+
--color-destructive-foreground: oklch(var(--destructive-foreground));
|
|
163
|
+
/* Alert surface pair — paler tinted bg + deeper on-surface text. */
|
|
164
|
+
--color-destructive-soft: oklch(var(--destructive-soft));
|
|
165
|
+
--color-destructive-deep: oklch(var(--destructive-deep));
|
|
166
|
+
--color-muted: oklch(var(--muted));
|
|
167
|
+
--color-muted-foreground: oklch(var(--muted-foreground));
|
|
168
|
+
--color-accent: oklch(var(--accent));
|
|
169
|
+
--color-accent-foreground: oklch(var(--accent-foreground));
|
|
170
|
+
--color-popover: oklch(var(--popover));
|
|
171
|
+
--color-popover-foreground: oklch(var(--popover-foreground));
|
|
172
|
+
--color-card: oklch(var(--card));
|
|
173
|
+
--color-card-foreground: oklch(var(--card-foreground));
|
|
174
|
+
/* Status colours — each exposes `-soft` / `-deep` siblings, mapping to
|
|
175
|
+
the tinted alert surface + readable text tokens generated by the
|
|
176
|
+
theme pipeline (lib/themes/oklch.ts#deriveAlertPair). */
|
|
177
|
+
--color-success: oklch(var(--success));
|
|
178
|
+
--color-success-soft: oklch(var(--success-soft));
|
|
179
|
+
--color-success-deep: oklch(var(--success-deep));
|
|
180
|
+
--color-warning: oklch(var(--warning));
|
|
181
|
+
--color-warning-soft: oklch(var(--warning-soft));
|
|
182
|
+
--color-warning-deep: oklch(var(--warning-deep));
|
|
183
|
+
--color-info: oklch(var(--info));
|
|
184
|
+
--color-info-soft: oklch(var(--info-soft));
|
|
185
|
+
--color-info-deep: oklch(var(--info-deep));
|
|
186
|
+
--color-highlight: oklch(var(--highlight));
|
|
187
|
+
--color-highlight-soft: oklch(var(--highlight-soft));
|
|
188
|
+
--color-highlight-deep: oklch(var(--highlight-deep));
|
|
189
|
+
/* Selection pair — solid fill, on-fill text, ambient glow halo. */
|
|
190
|
+
--color-selected: oklch(var(--selected));
|
|
191
|
+
--color-selected-foreground: oklch(var(--selected-foreground));
|
|
192
|
+
--color-selected-glow: oklch(var(--selected-glow));
|
|
193
|
+
/* Chart series palette — derived from theme hues by the generator. */
|
|
194
|
+
--color-chart-1: oklch(var(--chart-1));
|
|
195
|
+
--color-chart-2: oklch(var(--chart-2));
|
|
196
|
+
--color-chart-3: oklch(var(--chart-3));
|
|
197
|
+
--color-chart-4: oklch(var(--chart-4));
|
|
198
|
+
--color-chart-5: oklch(var(--chart-5));
|
|
199
|
+
|
|
200
|
+
/* -- Role ramp families (THEME-MIGRATION.md B4) — every semantic alias
|
|
201
|
+
is a whole ramp: status displays many ways (soft 100 bg, solid 600
|
|
202
|
+
fill, 800 text). The generator writes --gds-<role>-<step> OKLCH
|
|
203
|
+
triplets to :root (applyThemeToRoot); each step falls back to the
|
|
204
|
+
flat role triplet so e.g. bg-success-600 degrades to bg-success when
|
|
205
|
+
no generated theme is active. `neutral` is deliberately ABSENT from
|
|
206
|
+
the utility layer — --color-neutral-* would shadow Tailwind's
|
|
207
|
+
default neutral palette; its family ships as runtime vars only. -- */
|
|
208
|
+
--color-primary-50: oklch(var(--gds-primary-50, var(--primary)));
|
|
209
|
+
--color-primary-100: oklch(var(--gds-primary-100, var(--primary)));
|
|
210
|
+
--color-primary-200: oklch(var(--gds-primary-200, var(--primary)));
|
|
211
|
+
--color-primary-300: oklch(var(--gds-primary-300, var(--primary)));
|
|
212
|
+
--color-primary-400: oklch(var(--gds-primary-400, var(--primary)));
|
|
213
|
+
--color-primary-500: oklch(var(--gds-primary-500, var(--primary)));
|
|
214
|
+
--color-primary-600: oklch(var(--gds-primary-600, var(--primary)));
|
|
215
|
+
--color-primary-700: oklch(var(--gds-primary-700, var(--primary)));
|
|
216
|
+
--color-primary-800: oklch(var(--gds-primary-800, var(--primary)));
|
|
217
|
+
--color-primary-900: oklch(var(--gds-primary-900, var(--primary)));
|
|
218
|
+
--color-primary-950: oklch(var(--gds-primary-950, var(--primary)));
|
|
219
|
+
--color-accent-50: oklch(var(--gds-accent-50, var(--accent)));
|
|
220
|
+
--color-accent-100: oklch(var(--gds-accent-100, var(--accent)));
|
|
221
|
+
--color-accent-200: oklch(var(--gds-accent-200, var(--accent)));
|
|
222
|
+
--color-accent-300: oklch(var(--gds-accent-300, var(--accent)));
|
|
223
|
+
--color-accent-400: oklch(var(--gds-accent-400, var(--accent)));
|
|
224
|
+
--color-accent-500: oklch(var(--gds-accent-500, var(--accent)));
|
|
225
|
+
--color-accent-600: oklch(var(--gds-accent-600, var(--accent)));
|
|
226
|
+
--color-accent-700: oklch(var(--gds-accent-700, var(--accent)));
|
|
227
|
+
--color-accent-800: oklch(var(--gds-accent-800, var(--accent)));
|
|
228
|
+
--color-accent-900: oklch(var(--gds-accent-900, var(--accent)));
|
|
229
|
+
--color-accent-950: oklch(var(--gds-accent-950, var(--accent)));
|
|
230
|
+
--color-success-50: oklch(var(--gds-success-50, var(--success)));
|
|
231
|
+
--color-success-100: oklch(var(--gds-success-100, var(--success)));
|
|
232
|
+
--color-success-200: oklch(var(--gds-success-200, var(--success)));
|
|
233
|
+
--color-success-300: oklch(var(--gds-success-300, var(--success)));
|
|
234
|
+
--color-success-400: oklch(var(--gds-success-400, var(--success)));
|
|
235
|
+
--color-success-500: oklch(var(--gds-success-500, var(--success)));
|
|
236
|
+
--color-success-600: oklch(var(--gds-success-600, var(--success)));
|
|
237
|
+
--color-success-700: oklch(var(--gds-success-700, var(--success)));
|
|
238
|
+
--color-success-800: oklch(var(--gds-success-800, var(--success)));
|
|
239
|
+
--color-success-900: oklch(var(--gds-success-900, var(--success)));
|
|
240
|
+
--color-success-950: oklch(var(--gds-success-950, var(--success)));
|
|
241
|
+
--color-warning-50: oklch(var(--gds-warning-50, var(--warning)));
|
|
242
|
+
--color-warning-100: oklch(var(--gds-warning-100, var(--warning)));
|
|
243
|
+
--color-warning-200: oklch(var(--gds-warning-200, var(--warning)));
|
|
244
|
+
--color-warning-300: oklch(var(--gds-warning-300, var(--warning)));
|
|
245
|
+
--color-warning-400: oklch(var(--gds-warning-400, var(--warning)));
|
|
246
|
+
--color-warning-500: oklch(var(--gds-warning-500, var(--warning)));
|
|
247
|
+
--color-warning-600: oklch(var(--gds-warning-600, var(--warning)));
|
|
248
|
+
--color-warning-700: oklch(var(--gds-warning-700, var(--warning)));
|
|
249
|
+
--color-warning-800: oklch(var(--gds-warning-800, var(--warning)));
|
|
250
|
+
--color-warning-900: oklch(var(--gds-warning-900, var(--warning)));
|
|
251
|
+
--color-warning-950: oklch(var(--gds-warning-950, var(--warning)));
|
|
252
|
+
--color-info-50: oklch(var(--gds-info-50, var(--info)));
|
|
253
|
+
--color-info-100: oklch(var(--gds-info-100, var(--info)));
|
|
254
|
+
--color-info-200: oklch(var(--gds-info-200, var(--info)));
|
|
255
|
+
--color-info-300: oklch(var(--gds-info-300, var(--info)));
|
|
256
|
+
--color-info-400: oklch(var(--gds-info-400, var(--info)));
|
|
257
|
+
--color-info-500: oklch(var(--gds-info-500, var(--info)));
|
|
258
|
+
--color-info-600: oklch(var(--gds-info-600, var(--info)));
|
|
259
|
+
--color-info-700: oklch(var(--gds-info-700, var(--info)));
|
|
260
|
+
--color-info-800: oklch(var(--gds-info-800, var(--info)));
|
|
261
|
+
--color-info-900: oklch(var(--gds-info-900, var(--info)));
|
|
262
|
+
--color-info-950: oklch(var(--gds-info-950, var(--info)));
|
|
263
|
+
--color-highlight-50: oklch(var(--gds-highlight-50, var(--highlight)));
|
|
264
|
+
--color-highlight-100: oklch(var(--gds-highlight-100, var(--highlight)));
|
|
265
|
+
--color-highlight-200: oklch(var(--gds-highlight-200, var(--highlight)));
|
|
266
|
+
--color-highlight-300: oklch(var(--gds-highlight-300, var(--highlight)));
|
|
267
|
+
--color-highlight-400: oklch(var(--gds-highlight-400, var(--highlight)));
|
|
268
|
+
--color-highlight-500: oklch(var(--gds-highlight-500, var(--highlight)));
|
|
269
|
+
--color-highlight-600: oklch(var(--gds-highlight-600, var(--highlight)));
|
|
270
|
+
--color-highlight-700: oklch(var(--gds-highlight-700, var(--highlight)));
|
|
271
|
+
--color-highlight-800: oklch(var(--gds-highlight-800, var(--highlight)));
|
|
272
|
+
--color-highlight-900: oklch(var(--gds-highlight-900, var(--highlight)));
|
|
273
|
+
--color-highlight-950: oklch(var(--gds-highlight-950, var(--highlight)));
|
|
274
|
+
--color-destructive-50: oklch(var(--gds-destructive-50, var(--destructive)));
|
|
275
|
+
--color-destructive-100: oklch(var(--gds-destructive-100, var(--destructive)));
|
|
276
|
+
--color-destructive-200: oklch(var(--gds-destructive-200, var(--destructive)));
|
|
277
|
+
--color-destructive-300: oklch(var(--gds-destructive-300, var(--destructive)));
|
|
278
|
+
--color-destructive-400: oklch(var(--gds-destructive-400, var(--destructive)));
|
|
279
|
+
--color-destructive-500: oklch(var(--gds-destructive-500, var(--destructive)));
|
|
280
|
+
--color-destructive-600: oklch(var(--gds-destructive-600, var(--destructive)));
|
|
281
|
+
--color-destructive-700: oklch(var(--gds-destructive-700, var(--destructive)));
|
|
282
|
+
--color-destructive-800: oklch(var(--gds-destructive-800, var(--destructive)));
|
|
283
|
+
--color-destructive-900: oklch(var(--gds-destructive-900, var(--destructive)));
|
|
284
|
+
--color-destructive-950: oklch(var(--gds-destructive-950, var(--destructive)));
|
|
285
|
+
|
|
286
|
+
/* Surface backgrounds — `bg-surface-glass` etc. work alongside the
|
|
287
|
+
`.gds-surface-*` classes (those add backdrop-filter). */
|
|
288
|
+
--color-surface-solid: var(--surface-solid);
|
|
289
|
+
--color-surface-translucent: var(--surface-translucent);
|
|
290
|
+
--color-surface-glass: var(--surface-glass);
|
|
291
|
+
--color-surface-glass-strong: var(--surface-glass-strong);
|
|
292
|
+
|
|
293
|
+
/* -- Radius — pinned to the theme's --radius base. -- */
|
|
294
|
+
--radius-lg: var(--radius);
|
|
295
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
296
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
297
|
+
|
|
298
|
+
/* -- Presence — elevation tokens exposed both as semantic
|
|
299
|
+
`shadow-elevation-N` utilities AND as overrides of Tailwind's default
|
|
300
|
+
`shadow-sm/md/lg/xl/2xl` scale so existing call sites inherit the new
|
|
301
|
+
system without code changes. See PRESENCE.md.
|
|
302
|
+
(`shadow-none` stays v4's static `0 0 #0000` — that's what the old
|
|
303
|
+
build shipped too; the preset's `none: var(--elevation-0)` never won.) */
|
|
304
|
+
--shadow: var(--elevation-2);
|
|
305
|
+
--shadow-sm: var(--elevation-1);
|
|
306
|
+
--shadow-md: var(--elevation-4);
|
|
307
|
+
--shadow-lg: var(--elevation-5);
|
|
308
|
+
--shadow-xl: var(--elevation-5);
|
|
309
|
+
--shadow-2xl: var(--elevation-5);
|
|
310
|
+
--shadow-inner: var(--shadow-pressed-bevel);
|
|
311
|
+
/* Explicit elevation levels (preferred for new code) */
|
|
312
|
+
--shadow-elevation-0: var(--elevation-0);
|
|
313
|
+
--shadow-elevation-1: var(--elevation-1);
|
|
314
|
+
--shadow-elevation-2: var(--elevation-2);
|
|
315
|
+
--shadow-elevation-3: var(--elevation-3);
|
|
316
|
+
--shadow-elevation-4: var(--elevation-4);
|
|
317
|
+
--shadow-elevation-5: var(--elevation-5);
|
|
318
|
+
/* State variants for raised/tactile surfaces */
|
|
319
|
+
--shadow-raised: var(--elevation-3);
|
|
320
|
+
--shadow-hot: var(--elevation-hot);
|
|
321
|
+
--shadow-pressed: var(--elevation-pressed);
|
|
322
|
+
/* Single-layer atoms (when you need bevel-only / lift-only) */
|
|
323
|
+
--shadow-bevel-hi: var(--shadow-bevel-hi);
|
|
324
|
+
--shadow-bevel-lo: var(--shadow-bevel-lo);
|
|
325
|
+
--shadow-contact: var(--shadow-contact);
|
|
326
|
+
--shadow-lift: var(--shadow-lift);
|
|
327
|
+
--shadow-lift-deep: var(--shadow-lift-deep);
|
|
328
|
+
--shadow-heat-inner: var(--shadow-heat-inner);
|
|
329
|
+
--shadow-heat-outer: var(--shadow-heat-outer);
|
|
330
|
+
|
|
331
|
+
/* -- Backdrop blur (glass surfaces) — v4 shares the --blur-* namespace
|
|
332
|
+
between blur-* and backdrop-blur-*; only the backdrop forms are part
|
|
333
|
+
of the public API. -- */
|
|
334
|
+
--blur-glass: var(--surface-blur-glass);
|
|
335
|
+
--blur-glass-strong: var(--surface-blur-strong);
|
|
336
|
+
--blur-subtle: var(--surface-blur-subtle);
|
|
337
|
+
|
|
338
|
+
/* -- Motion -- */
|
|
339
|
+
--animate-accordion-down: accordion-down 0.2s ease-out;
|
|
340
|
+
--animate-accordion-up: accordion-up 0.2s ease-out;
|
|
341
|
+
--animate-fade-in: fade-in 0.2s ease-out;
|
|
342
|
+
--animate-fade-out: fade-out 0.2s ease-in;
|
|
343
|
+
--animate-scale-in: scale-in 0.15s ease-out;
|
|
344
|
+
--animate-slide-in-from-top: slide-in-from-top 0.2s ease-out;
|
|
345
|
+
--animate-slide-in-from-bottom: slide-in-from-bottom 0.2s ease-out;
|
|
346
|
+
--animate-slide-in-from-left: slide-in-from-left 0.2s ease-out;
|
|
347
|
+
--animate-slide-in-from-right: slide-in-from-right 0.2s ease-out;
|
|
348
|
+
--animate-energy-pulse: energy-pulse 2s ease-in-out infinite;
|
|
349
|
+
--animate-shimmer: shimmer 2s linear infinite;
|
|
350
|
+
|
|
351
|
+
@keyframes accordion-down {
|
|
352
|
+
from {
|
|
353
|
+
height: 0;
|
|
354
|
+
}
|
|
355
|
+
to {
|
|
356
|
+
height: var(--radix-accordion-content-height);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
@keyframes accordion-up {
|
|
360
|
+
from {
|
|
361
|
+
height: var(--radix-accordion-content-height);
|
|
362
|
+
}
|
|
363
|
+
to {
|
|
364
|
+
height: 0;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
@keyframes fade-in {
|
|
368
|
+
from {
|
|
369
|
+
opacity: 0;
|
|
370
|
+
}
|
|
371
|
+
to {
|
|
372
|
+
opacity: 1;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
@keyframes fade-out {
|
|
376
|
+
from {
|
|
377
|
+
opacity: 1;
|
|
378
|
+
}
|
|
379
|
+
to {
|
|
380
|
+
opacity: 0;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
@keyframes scale-in {
|
|
384
|
+
from {
|
|
385
|
+
opacity: 0;
|
|
386
|
+
transform: scale(0.95);
|
|
387
|
+
}
|
|
388
|
+
to {
|
|
389
|
+
opacity: 1;
|
|
390
|
+
transform: scale(1);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
@keyframes slide-in-from-top {
|
|
394
|
+
from {
|
|
395
|
+
opacity: 0;
|
|
396
|
+
transform: translateY(-10px);
|
|
397
|
+
}
|
|
398
|
+
to {
|
|
399
|
+
opacity: 1;
|
|
400
|
+
transform: translateY(0);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
@keyframes slide-in-from-bottom {
|
|
404
|
+
from {
|
|
405
|
+
opacity: 0;
|
|
406
|
+
transform: translateY(10px);
|
|
407
|
+
}
|
|
408
|
+
to {
|
|
409
|
+
opacity: 1;
|
|
410
|
+
transform: translateY(0);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
@keyframes slide-in-from-left {
|
|
414
|
+
from {
|
|
415
|
+
opacity: 0;
|
|
416
|
+
transform: translateX(-10px);
|
|
417
|
+
}
|
|
418
|
+
to {
|
|
419
|
+
opacity: 1;
|
|
420
|
+
transform: translateX(0);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
@keyframes slide-in-from-right {
|
|
424
|
+
from {
|
|
425
|
+
opacity: 0;
|
|
426
|
+
transform: translateX(10px);
|
|
427
|
+
}
|
|
428
|
+
to {
|
|
429
|
+
opacity: 1;
|
|
430
|
+
transform: translateX(0);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
@keyframes energy-pulse {
|
|
434
|
+
0%,
|
|
435
|
+
100% {
|
|
436
|
+
opacity: 1;
|
|
437
|
+
box-shadow: 0 0 0 0 oklch(var(--accent) / 0.4);
|
|
438
|
+
}
|
|
439
|
+
50% {
|
|
440
|
+
opacity: 0.8;
|
|
441
|
+
box-shadow: 0 0 0 8px oklch(var(--accent) / 0);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
@keyframes shimmer {
|
|
445
|
+
0% {
|
|
446
|
+
background-position: 200% 0;
|
|
447
|
+
}
|
|
448
|
+
100% {
|
|
449
|
+
background-position: -200% 0;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/* Elevation/presence shadow utilities are typed at runtime (Studio output,
|
|
455
|
+
generated screens), so the scanner never sees them in source. v4's
|
|
456
|
+
`@source inline(...)` force-emits them — this replaces the JS `safelist`
|
|
457
|
+
that v4 removed. */
|
|
458
|
+
@source inline("shadow-{elevation-0,elevation-1,elevation-2,elevation-3,elevation-4,elevation-5,raised,hot,pressed,bevel-hi,bevel-lo,contact,lift,lift-deep,heat-inner,heat-outer}");
|
|
459
|
+
|
|
460
|
+
/* The Studio inspector's WHOLE token vocabulary — every class the
|
|
461
|
+
TokenField controls can mint at runtime. None of these literals appear
|
|
462
|
+
in scanned source (they're assembled from registry scales while
|
|
463
|
+
editing), so without this block they'd produce no CSS in Fast Frame —
|
|
464
|
+
the "blend modes don't do anything" bug, one family at a time. Finite
|
|
465
|
+
sets, so safelisting is cheap and correct. */
|
|
466
|
+
@source inline("mix-blend-{normal,multiply,screen,overlay,darken,lighten,color-dodge,color-burn,difference,exclusion,hue,saturation,color,luminosity}");
|
|
467
|
+
@source inline("opacity-{0,5,10,20,30,40,50,60,70,80,90,100}");
|
|
468
|
+
@source inline("text-{2xs,xs,sm,base,lg,xl,2xl,3xl,4xl,5xl}");
|
|
469
|
+
@source inline("font-{thin,extralight,light,normal,medium,semibold,bold,extrabold,black}");
|
|
470
|
+
@source inline("rounded{,-none,-sm,-md,-lg,-xl,-2xl,-3xl,-full}");
|
|
471
|
+
@source inline("rounded-{tl,tr,br,bl,t,r,b,l}{,-none,-sm,-md,-lg,-xl,-2xl,-3xl,-full}");
|
|
472
|
+
@source inline("{p,m}{,t,r,b,l,x,y}-{0,0.5,1,1.5,2,2.5,3,3.5,4,5,6,7,8,9,10,11,12,14,16,20,24}");
|
|
473
|
+
@source inline("gap-{0,0.5,1,1.5,2,2.5,3,3.5,4,5,6,8,10,12}");
|
|
474
|
+
@source inline("grid-cols-{1,2,3,4,5,6,8,12}");
|
|
475
|
+
@source inline("shadow{,-none,-sm,-md,-lg,-xl,-2xl,-inner}");
|
|
476
|
+
@source inline("bg-{background,card,muted,secondary,accent,primary,destructive,transparent}");
|
|
477
|
+
/* Border family — the inspector's BorderGroup mints every one of these at
|
|
478
|
+
runtime (side-aware widths, styles, colours, and ring-based inside/outside
|
|
479
|
+
positions). Without the force-emit, anything the scanner hasn't seen in
|
|
480
|
+
source (border-4, border-t-8, ring-inset…) silently renders as no CSS in
|
|
481
|
+
Fast Frame — the ">2px borders don't work" bug. */
|
|
482
|
+
@source inline("border{,-t,-r,-b,-l,-x,-y}{,-0,-2,-4,-8}");
|
|
483
|
+
@source inline("border-{solid,dashed,dotted,double}");
|
|
484
|
+
@source inline("border{,-t,-r,-b,-l}-{border,foreground,primary,muted-foreground,destructive,ring}");
|
|
485
|
+
@source inline("ring{,-0,-1,-2,-4,-8}");
|
|
486
|
+
@source inline("ring-inset");
|
|
487
|
+
@source inline("ring-{border,foreground,primary,muted-foreground,destructive,ring}");
|
|
488
|
+
/* Typography family — the inspector's TypographyGroup mints these at
|
|
489
|
+
runtime (line-height, letter-spacing, text-align). Same force-emit
|
|
490
|
+
rationale as the border/blend families above. */
|
|
491
|
+
@source inline("leading-{none,tight,snug,normal,relaxed,loose}");
|
|
492
|
+
@source inline("tracking-{tighter,tight,normal,wide,wider,widest}");
|
|
493
|
+
@source inline("text-{left,center,right,justify}");
|
|
494
|
+
/* Display sizes + responsive variants — generated heroes lean on
|
|
495
|
+
`text-6xl`/`md:text-8xl`-style ladders that never appear in scanned
|
|
496
|
+
source, so the responsive variants silently no-oped in Fast Frame.
|
|
497
|
+
sm/md/lg cover BOTH model output and everything the inspector's
|
|
498
|
+
BreakpointOverridesEditor can mint (size, weight, line-height,
|
|
499
|
+
tracking, align — keep in sync with EDITABLE_BREAKPOINTS). */
|
|
500
|
+
@source inline("{,sm:,md:,lg:}text-{6xl,7xl,8xl,9xl}");
|
|
501
|
+
@source inline("{sm:,md:,lg:}text-{2xs,xs,sm,base,lg,xl,2xl,3xl,4xl,5xl}");
|
|
502
|
+
@source inline("{sm:,md:,lg:}font-{thin,extralight,light,normal,medium,semibold,bold,extrabold,black}");
|
|
503
|
+
@source inline("{sm:,md:,lg:}leading-{none,tight,snug,normal,relaxed,loose}");
|
|
504
|
+
@source inline("{sm:,md:,lg:}tracking-{tighter,tight,normal,wide,wider,widest}");
|
|
505
|
+
@source inline("{sm:,md:,lg:}text-{left,center,right,justify}");
|
|
506
|
+
/* Gradient-text + gradient-stop recipe — `bg-clip-text text-transparent
|
|
507
|
+
bg-gradient-to-b from-foreground to-foreground/75` is the canonical
|
|
508
|
+
generated-hero headline. All of it is runtime-typed (model output),
|
|
509
|
+
none of it appears in scanned source. Stops cover the semantic tokens
|
|
510
|
+
at full strength plus a sensible opacity ladder. */
|
|
511
|
+
@source inline("bg-clip-text");
|
|
512
|
+
@source inline("text-transparent");
|
|
513
|
+
@source inline("bg-gradient-to-{t,tr,r,br,b,bl,l,tl}");
|
|
514
|
+
@source inline("{from,via,to}-{background,foreground,card,card-foreground,muted,muted-foreground,primary,primary-foreground,secondary,accent,destructive,border,transparent,white,black}");
|
|
515
|
+
@source inline("{from,via,to}-{background,foreground,muted,primary,secondary,accent,white,black}/{10,20,25,30,40,50,60,70,75,80,90}");
|
|
516
|
+
/* Animate-in vocabulary (tailwindcss-animate enter/exit modifiers) +
|
|
517
|
+
easing — generated screens compose `animate-in fade-in
|
|
518
|
+
slide-in-from-top`-style entrances at runtime, so the scanner never
|
|
519
|
+
sees the pieces in source. Until the v4 native-@theme migration these
|
|
520
|
+
leaked into the build by accident (the scanner picked them out of
|
|
521
|
+
tailwind-preset.ts comment/value text); now they're force-emitted
|
|
522
|
+
deliberately. */
|
|
523
|
+
@source inline("fade-{in,out}");
|
|
524
|
+
@source inline("slide-in-from-{top,bottom,left,right}");
|
|
525
|
+
@source inline("ease-{in,out,in-out}");
|
|
526
|
+
/* Role ramp family vocabulary (THEME-MIGRATION.md B4) — bg/text/border
|
|
527
|
+
at every step for every themed role. Runtime-typed (model output +
|
|
528
|
+
future inspector token picker), so force-emit like the other
|
|
529
|
+
families. The --color-<role>-<step> @theme entries below define the
|
|
530
|
+
values; the generator's --gds-<role>-<step> vars make them live. */
|
|
531
|
+
@source inline("bg-{primary,accent,success,warning,info,highlight,destructive}-{50,100,200,300,400,500,600,700,800,900,950}");
|
|
532
|
+
@source inline("text-{primary,accent,success,warning,info,highlight,destructive}-{50,100,200,300,400,500,600,700,800,900,950}");
|
|
533
|
+
@source inline("border-{primary,accent,success,warning,info,highlight,destructive}-{50,100,200,300,400,500,600,700,800,900,950}");
|
|
534
|
+
/* Parity holdovers from the same accidental scan — shipped in every
|
|
535
|
+
previous dist/styles.css, kept so no runtime-typed class loses its
|
|
536
|
+
rules. TODO(follow-up): widen bg-surface-glass to the full
|
|
537
|
+
bg-surface-{solid,translucent,glass,glass-strong} family as a
|
|
538
|
+
deliberate (additive) API decision, and decide whether the two
|
|
539
|
+
playground measurements below should live in a scaffold instead. */
|
|
540
|
+
@source inline("bg-surface-glass");
|
|
541
|
+
@source inline("h-[600px]");
|
|
542
|
+
@source inline("md:grid-cols-[minmax(0,440px)_1fr]");
|
|
543
|
+
|
|
544
|
+
/* ============================================
|
|
545
|
+
GRADE DESIGN SYSTEM - COMPONENT-LAYER TOKENS
|
|
546
|
+
============================================ */
|
|
547
|
+
|
|
548
|
+
:root {
|
|
549
|
+
/* Brand color ramps, neutral grays, semantic aliases (--gds-success …),
|
|
550
|
+
spacing scale, and border radii moved to @gradeui/core — see the
|
|
551
|
+
`@import "@gradeui/core/tokens.css"` at the top of this file and
|
|
552
|
+
packages/core/styles/tokens.css. Component tokens stay below. */
|
|
553
|
+
/* ============================================
|
|
554
|
+
ELEVATION SYSTEM
|
|
555
|
+
============================================
|
|
556
|
+
A single vocabulary for every box-shadow in the DS. Three layers:
|
|
557
|
+
|
|
558
|
+
1. ATOMIC SUB-TOKENS — `-y` (y-offset), `-blur`, `-spread`, `-alpha`.
|
|
559
|
+
These are the bare numbers a theme tweaks to tune "depth" globally
|
|
560
|
+
without touching component CSS. e.g. lowering `--shadow-lift-alpha`
|
|
561
|
+
across the board gives the whole system a "lighter" feel.
|
|
562
|
+
|
|
563
|
+
2. COMPOSED LAYER TOKENS — full box-shadow expressions for one layer
|
|
564
|
+
each (`--shadow-bevel-hi`, `--shadow-contact`, `--shadow-lift`,
|
|
565
|
+
etc.). Components compose layers into a complete shadow stack
|
|
566
|
+
without having to know the atomic numbers.
|
|
567
|
+
|
|
568
|
+
3. ELEVATION PRESETS — `--elevation-0` through `--elevation-5` plus
|
|
569
|
+
state variants (`--elevation-hot`, `--elevation-pressed`). The
|
|
570
|
+
default contract: components read these, not the layers, unless
|
|
571
|
+
they're doing something custom (Button raised, custom cards).
|
|
572
|
+
|
|
573
|
+
Light source convention: light comes from above. Bevel-hi sits at
|
|
574
|
+
the top edge, bevel-lo at the bottom, drops fall downward (positive
|
|
575
|
+
y). Flipping this in a future "inverse light" theme = changing the
|
|
576
|
+
atomic y-offsets to negative; no component CSS changes.
|
|
577
|
+
|
|
578
|
+
Color convention:
|
|
579
|
+
bevel-hi — white (the highlight)
|
|
580
|
+
bevel-lo — black (the undercut)
|
|
581
|
+
contact — black (tight close drop)
|
|
582
|
+
lift — black (diffuse ambient drop)
|
|
583
|
+
heat-inner — var(--btn-glow) (tonal hover bloom, inset from bottom)
|
|
584
|
+
heat-outer — var(--btn-glow) (tonal hover bloom, outer drop)
|
|
585
|
+
-------------------------------------------- */
|
|
586
|
+
|
|
587
|
+
/* -- Layer 1: bevel-hi (top inset highlight) -- */
|
|
588
|
+
--shadow-bevel-hi-y: 1px;
|
|
589
|
+
--shadow-bevel-hi-alpha: 0.12;
|
|
590
|
+
--shadow-bevel-hi: inset 0 var(--shadow-bevel-hi-y) 0 oklch(1 0 0 / var(--shadow-bevel-hi-alpha));
|
|
591
|
+
|
|
592
|
+
/* -- Layer 2: bevel-lo (bottom inset shadow) -- */
|
|
593
|
+
--shadow-bevel-lo-y: 1px;
|
|
594
|
+
--shadow-bevel-lo-alpha: 0.30;
|
|
595
|
+
--shadow-bevel-lo: inset 0 calc(-1 * var(--shadow-bevel-lo-y)) 0 oklch(0 0 0 / var(--shadow-bevel-lo-alpha));
|
|
596
|
+
|
|
597
|
+
/* -- Layer 3: contact (tight outer drop, the "sitting on a surface" feel) -- */
|
|
598
|
+
--shadow-contact-y: 1px;
|
|
599
|
+
--shadow-contact-blur: 2px;
|
|
600
|
+
--shadow-contact-alpha: 0.10;
|
|
601
|
+
--shadow-contact: 0 var(--shadow-contact-y) var(--shadow-contact-blur) oklch(0 0 0 / var(--shadow-contact-alpha));
|
|
602
|
+
|
|
603
|
+
/* -- Layer 4: lift (diffuse outer drop, the "floating" feel) -- */
|
|
604
|
+
--shadow-lift-y: 4px;
|
|
605
|
+
--shadow-lift-blur: 12px;
|
|
606
|
+
--shadow-lift-alpha: 0.18;
|
|
607
|
+
--shadow-lift: 0 var(--shadow-lift-y) var(--shadow-lift-blur) oklch(0 0 0 / var(--shadow-lift-alpha));
|
|
608
|
+
|
|
609
|
+
/* -- Layer 5: lift-deep (deeper diffuse drop for dialogs/sheets) -- */
|
|
610
|
+
--shadow-lift-deep-y: 16px;
|
|
611
|
+
--shadow-lift-deep-blur: 40px;
|
|
612
|
+
--shadow-lift-deep-alpha: 0.28;
|
|
613
|
+
--shadow-lift-deep: 0 var(--shadow-lift-deep-y) var(--shadow-lift-deep-blur) oklch(0 0 0 / var(--shadow-lift-deep-alpha));
|
|
614
|
+
|
|
615
|
+
/* -- Layer 6: heat-inner (tonal hover bloom, bleeds in from bottom) -- */
|
|
616
|
+
--shadow-heat-inner-y: 10px;
|
|
617
|
+
--shadow-heat-inner-blur: 24px;
|
|
618
|
+
--shadow-heat-inner-spread: 4px;
|
|
619
|
+
--shadow-heat-inner-alpha: 0.55;
|
|
620
|
+
--shadow-heat-inner: inset 0 calc(-1 * var(--shadow-heat-inner-y)) var(--shadow-heat-inner-blur) calc(-1 * var(--shadow-heat-inner-spread)) oklch(var(--btn-glow, var(--selected-glow)) / var(--shadow-heat-inner-alpha));
|
|
621
|
+
|
|
622
|
+
/* -- Layer 7: heat-outer (tonal hover bloom, escapes outward) -- */
|
|
623
|
+
--shadow-heat-outer-y: 6px;
|
|
624
|
+
--shadow-heat-outer-blur: 18px;
|
|
625
|
+
--shadow-heat-outer-alpha: 0.30;
|
|
626
|
+
--shadow-heat-outer: 0 var(--shadow-heat-outer-y) var(--shadow-heat-outer-blur) oklch(var(--btn-glow, var(--selected-glow)) / var(--shadow-heat-outer-alpha));
|
|
627
|
+
|
|
628
|
+
/* -- Layer 8: pressed (inset shadow simulating a key push) -- */
|
|
629
|
+
--shadow-pressed-y: 2px;
|
|
630
|
+
--shadow-pressed-blur: 4px;
|
|
631
|
+
--shadow-pressed-alpha: 0.45;
|
|
632
|
+
--shadow-pressed-bevel: inset 0 var(--shadow-pressed-y) var(--shadow-pressed-blur) oklch(0 0 0 / var(--shadow-pressed-alpha));
|
|
633
|
+
|
|
634
|
+
/* -- Composed elevation presets --
|
|
635
|
+
0 = flat, 1 = minimal contact, 2 = interactive surface (bevel + contact),
|
|
636
|
+
3 = raised key (bevel + contact + lift), 4 = popover/dropdown,
|
|
637
|
+
5 = dialog/sheet/modal. Components reach for these by default. */
|
|
638
|
+
--elevation-0: 0 0 0 0 transparent;
|
|
639
|
+
--elevation-1: var(--shadow-contact);
|
|
640
|
+
--elevation-2: var(--shadow-bevel-hi), var(--shadow-bevel-lo), var(--shadow-contact);
|
|
641
|
+
--elevation-3: var(--shadow-bevel-hi), var(--shadow-bevel-lo), var(--shadow-contact), var(--shadow-lift);
|
|
642
|
+
--elevation-4: var(--shadow-contact), var(--shadow-lift);
|
|
643
|
+
--elevation-5: var(--shadow-contact), var(--shadow-lift-deep);
|
|
644
|
+
|
|
645
|
+
/* State variants for interactive surfaces (Button raised, Toggle, Tab) */
|
|
646
|
+
--elevation-hot: var(--shadow-bevel-hi), var(--shadow-bevel-lo), var(--shadow-heat-inner), var(--shadow-contact), var(--shadow-heat-outer), var(--shadow-lift);
|
|
647
|
+
--elevation-pressed: var(--shadow-pressed-bevel), inset 0 -1px 0 oklch(1 0 0 / 0.04), var(--shadow-contact);
|
|
648
|
+
|
|
649
|
+
/* ----------------------------------------
|
|
650
|
+
Legacy shadow tokens — repointed onto the elevation system so call
|
|
651
|
+
sites that read `--gds-shadow-*` directly inherit the new look
|
|
652
|
+
without a code change. Kept here as a compatibility shim; new code
|
|
653
|
+
should prefer the elevation tokens above.
|
|
654
|
+
---------------------------------------- */
|
|
655
|
+
--gds-shadow-sm: var(--elevation-1);
|
|
656
|
+
--gds-shadow-md: var(--elevation-4);
|
|
657
|
+
--gds-shadow-lg: var(--elevation-5);
|
|
658
|
+
--gds-shadow-xl: var(--elevation-5);
|
|
659
|
+
--gds-shadow-2xl: var(--elevation-5);
|
|
660
|
+
--gds-shadow-inner: var(--shadow-pressed-bevel);
|
|
661
|
+
|
|
662
|
+
/* ============================================
|
|
663
|
+
SURFACE SYSTEM
|
|
664
|
+
============================================
|
|
665
|
+
What the surface is *made of*. Independent from elevation (how
|
|
666
|
+
high it sits) and from aura (what it's radiating). A glass card
|
|
667
|
+
can sit at elevation-4 with a calm aura, or at elevation-2 with
|
|
668
|
+
no aura — these axes don't entangle.
|
|
669
|
+
|
|
670
|
+
Atomic alpha + blur sub-tokens make the look tunable per theme
|
|
671
|
+
(frosted dark vs. light glass want different opacity floors).
|
|
672
|
+
The composed `--surface-*` tokens read from `--card` so they
|
|
673
|
+
stay theme-aware — switching themes changes the glass tint.
|
|
674
|
+
-------------------------------------------- */
|
|
675
|
+
|
|
676
|
+
/* -- Atomic alphas -- */
|
|
677
|
+
--surface-alpha-solid: 1;
|
|
678
|
+
--surface-alpha-translucent: 0.82;
|
|
679
|
+
--surface-alpha-glass: 0.58;
|
|
680
|
+
--surface-alpha-glass-strong: 0.42;
|
|
681
|
+
|
|
682
|
+
/* -- Atomic blurs -- */
|
|
683
|
+
--surface-blur-subtle: 6px;
|
|
684
|
+
--surface-blur-glass: 14px;
|
|
685
|
+
--surface-blur-strong: 24px;
|
|
686
|
+
|
|
687
|
+
/* -- Atomic inner-edge highlight (the "wet" line on glass surfaces) -- */
|
|
688
|
+
--surface-edge-alpha: 0.10;
|
|
689
|
+
--surface-edge: inset 0 1px 0 oklch(1 0 0 / var(--surface-edge-alpha));
|
|
690
|
+
|
|
691
|
+
/* -- Composed surface backgrounds — theme-aware via --card -- */
|
|
692
|
+
--surface-solid: oklch(var(--card) / var(--surface-alpha-solid));
|
|
693
|
+
--surface-translucent: oklch(var(--card) / var(--surface-alpha-translucent));
|
|
694
|
+
--surface-glass: oklch(var(--card) / var(--surface-alpha-glass));
|
|
695
|
+
--surface-glass-strong: oklch(var(--card) / var(--surface-alpha-glass-strong));
|
|
696
|
+
|
|
697
|
+
/* ============================================
|
|
698
|
+
AURA SYSTEM
|
|
699
|
+
============================================
|
|
700
|
+
What's actively *radiating* from an element. State signals — AI
|
|
701
|
+
attention, generation-in-progress, selection focus. Three
|
|
702
|
+
composable styles: ring (pulsing outer shadow), gradient
|
|
703
|
+
(rotating conic border), shimmer (diagonal sweep). They stack —
|
|
704
|
+
`.gds-aura-ring.gds-aura-shimmer` runs both passes.
|
|
705
|
+
|
|
706
|
+
Per-style timing & easing vars are overridable at the consumer
|
|
707
|
+
level, so a heavyweight button can slow its pulse without
|
|
708
|
+
rewriting keyframes:
|
|
709
|
+
|
|
710
|
+
<Button className="gds-aura-ring"
|
|
711
|
+
style={{ '--aura-pulse-duration': '3.2s' }} />
|
|
712
|
+
|
|
713
|
+
Color defaults to --selected-glow (blue, themed). Override
|
|
714
|
+
per-instance via `--aura-color` for danger / success / brand
|
|
715
|
+
attention.
|
|
716
|
+
-------------------------------------------- */
|
|
717
|
+
|
|
718
|
+
/* -- Color -- */
|
|
719
|
+
--aura-color: var(--selected-glow);
|
|
720
|
+
|
|
721
|
+
/* -- Ring (pulsing outer halo via animated box-shadow) -- */
|
|
722
|
+
--aura-ring-spread: 2px;
|
|
723
|
+
--aura-ring-blur: 14px;
|
|
724
|
+
--aura-ring-alpha-min: 0.00;
|
|
725
|
+
--aura-ring-alpha-max: 0.65;
|
|
726
|
+
--aura-pulse-duration: 2400ms;
|
|
727
|
+
--aura-pulse-ease: cubic-bezier(0.4, 0, 0.2, 1);
|
|
728
|
+
|
|
729
|
+
/* -- Gradient (rotating conic-gradient border) -- */
|
|
730
|
+
--aura-gradient-thickness: 1.5px;
|
|
731
|
+
--aura-gradient-duration: 6000ms;
|
|
732
|
+
--aura-gradient-ease: linear;
|
|
733
|
+
|
|
734
|
+
/* -- Shimmer (diagonal sweep) -- */
|
|
735
|
+
--aura-shimmer-width: 28%;
|
|
736
|
+
--aura-shimmer-alpha: 0.18;
|
|
737
|
+
--aura-shimmer-duration: 2000ms;
|
|
738
|
+
--aura-shimmer-ease: cubic-bezier(0.4, 0, 0.2, 1);
|
|
739
|
+
--aura-shimmer-delay-between: 1200ms;
|
|
740
|
+
|
|
741
|
+
/* Font stacks (--font-sans / --font-mono) and the type scale
|
|
742
|
+
(--text-display … --text-overline-*) moved to @gradeui/core/tokens.css. */
|
|
743
|
+
/* ----------------------------------------
|
|
744
|
+
Animation
|
|
745
|
+
---------------------------------------- */
|
|
746
|
+
--gds-transition-fast: 150ms;
|
|
747
|
+
--gds-transition-base: 200ms;
|
|
748
|
+
--gds-transition-slow: 300ms;
|
|
749
|
+
--gds-transition-slower: 500ms;
|
|
750
|
+
|
|
751
|
+
--gds-ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
752
|
+
--gds-ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
753
|
+
--gds-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
|
754
|
+
|
|
755
|
+
/* ----------------------------------------
|
|
756
|
+
Semantic Tokens (OKLCH) — STUDIO DEFAULTS.
|
|
757
|
+
Values are bare "L C H" triplets, wrapped at call-time with
|
|
758
|
+
oklch(var(--x)) via the @theme inline reference block above.
|
|
759
|
+
These defaults mirror the current Studio look (warm-cream
|
|
760
|
+
neutrals at hue 85, near-black primary, Inter/Geist type) and
|
|
761
|
+
are SYNCED FROM apps/docs/app/globals.css — the canonical copy —
|
|
762
|
+
by the A7.1 pass (2026-06-11; the previous values here were the
|
|
763
|
+
pre-redesign terracotta theme, which leaked into any surface that
|
|
764
|
+
loaded both stylesheets — the MCP panel "pink progress bar" bug).
|
|
765
|
+
If the docs palette changes, re-sync this block. The
|
|
766
|
+
GradeThemeProvider overrides all of it at runtime.
|
|
767
|
+
---------------------------------------- */
|
|
768
|
+
--background: 0.985 0.0018 85; /* neutral 50 */
|
|
769
|
+
--foreground: 0.170 0.0048 85; /* neutral 950 */
|
|
770
|
+
--card: 1 0 0; /* pure white */
|
|
771
|
+
--card-foreground: 0.170 0.0048 85;
|
|
772
|
+
--popover: 1 0 0;
|
|
773
|
+
--popover-foreground: 0.170 0.0048 85;
|
|
774
|
+
--primary: 0.245 0.0096 85; /* near-black — Studio buttons */
|
|
775
|
+
--primary-foreground: 0.985 0.0018 85;
|
|
776
|
+
--secondary: 0.955 0.0048 85; /* neutral 100 */
|
|
777
|
+
--secondary-foreground: 0.415 0.0180 85; /* neutral 700 */
|
|
778
|
+
--muted: 0.955 0.0048 85;
|
|
779
|
+
--muted-foreground: 0.610 0.0204 85; /* neutral 500 */
|
|
780
|
+
--accent: 0.610 0.0306 85; /* warm cream accent */
|
|
781
|
+
--accent-foreground: 0.985 0.0027 85;
|
|
782
|
+
--destructive: 0.560 0.220 27;
|
|
783
|
+
--destructive-foreground: 0.990 0.005 27;
|
|
784
|
+
--border: 0.895 0.0090 85; /* neutral 200 */
|
|
785
|
+
--input: 0.895 0.0090 85;
|
|
786
|
+
--ring: 0.415 0.0180 85;
|
|
787
|
+
--radius: 0.250rem; /* Studio's compact radius base */
|
|
788
|
+
|
|
789
|
+
/* Typography defaults — Inter body, Geist display (Studio). */
|
|
790
|
+
--font-sans: var(--font-inter), system-ui, -apple-system, sans-serif;
|
|
791
|
+
--font-display: var(--font-geist), system-ui, -apple-system, sans-serif;
|
|
792
|
+
|
|
793
|
+
/* Fixed semantic colors (not hue-derived, for accessibility consistency) */
|
|
794
|
+
--success: 0.610 0.180 145;
|
|
795
|
+
--warning: 0.720 0.180 60;
|
|
796
|
+
--info: 0.580 0.200 240;
|
|
797
|
+
--highlight: 0.860 0.180 95;
|
|
798
|
+
|
|
799
|
+
/* Selection token pair — solid fill behind a selected option (radio
|
|
800
|
+
row, segmented control) and the ambient halo around it on hover /
|
|
801
|
+
focus. Blue by default; theme-overridable. Distinct from --primary
|
|
802
|
+
so a brand can keep its primary cta colour while selection stays
|
|
803
|
+
consistent, and distinct from --highlight (amber status). */
|
|
804
|
+
--selected: 0.55 0.22 258;
|
|
805
|
+
--selected-foreground: 0.985 0.0018 85;
|
|
806
|
+
--selected-glow: 0.66 0.20 258;
|
|
807
|
+
|
|
808
|
+
/* Accent glow — tonal halo for raised/tactile chrome. Defaults to
|
|
809
|
+
--primary so raised buttons read as branded by default, not as
|
|
810
|
+
selected. Themes can retune independently (e.g. lift lightness for
|
|
811
|
+
softer halos) by setting --accent-glow explicitly. Per-button
|
|
812
|
+
overrides still flow through `style={{ "--btn-glow": ... }}` for
|
|
813
|
+
"traffic light" semantics (warning iterate, success ship, etc.). */
|
|
814
|
+
--accent-glow: var(--primary);
|
|
815
|
+
|
|
816
|
+
/* Media placeholder pair — used by MediaSurface when it has no children
|
|
817
|
+
(image-not-yet-loaded slots, scaffolds without real photos, layouts
|
|
818
|
+
waiting on the image-generation pipeline). Defined here as a token
|
|
819
|
+
pair so themes can override per-brand and consumers can roll their
|
|
820
|
+
own placeholder UI with `background: var(--gds-media-placeholder-bg)`.
|
|
821
|
+
Defaults to the secondary surface so it reads visibly distinct from
|
|
822
|
+
`bg-card` and `bg-background` while staying neutral (not brand-loud).
|
|
823
|
+
Resolves dynamically against the active mode because var(--secondary)
|
|
824
|
+
itself is mode-scoped — no `.dark` duplicate needed.
|
|
825
|
+
|
|
826
|
+
Both bg and fg are SOLID (no alpha) — earlier `secondary-foreground / 0.4`
|
|
827
|
+
produced a "half-cooked" look where the icon and caption faded into the
|
|
828
|
+
surface. Solid muted-foreground reads as "intentional placeholder
|
|
829
|
+
colour", not "loading half-way". */
|
|
830
|
+
--gds-media-placeholder-bg: oklch(var(--muted));
|
|
831
|
+
--gds-media-placeholder-fg: oklch(var(--muted-foreground));
|
|
832
|
+
|
|
833
|
+
/* Canvas fill — the standard backdrop behind a screen when it doesn't fill
|
|
834
|
+
its frame: the letterbox bars in an embed/share, and the stage a
|
|
835
|
+
`<ScreenAnimator>` reveals when it flies in or pulls below 1× zoom. One
|
|
836
|
+
token so every "canvas" surface (embed, share, animator) matches and a
|
|
837
|
+
theme/brand can restyle it in one place. Mode-aware: a soft neutral in
|
|
838
|
+
light mode and a deep near-black in dark (see `.dark` below) — a neutral
|
|
839
|
+
cinematic backdrop that flatters a screen sitting on top of it in either
|
|
840
|
+
mode. Set it to `transparent` to let the host page show through. */
|
|
841
|
+
--gds-canvas-fill: #e8e8ec;
|
|
842
|
+
|
|
843
|
+
/* Sidebar knobs — the width pair drives the collapsed/expanded animation
|
|
844
|
+
on `<Sidebar>` (compound nav primitive). Header height + section
|
|
845
|
+
padding + per-section gap are exposed so consumers can retune density
|
|
846
|
+
without prop drilling. */
|
|
847
|
+
--gds-sidebar-width: 16rem;
|
|
848
|
+
--gds-sidebar-collapsed-width: 4rem;
|
|
849
|
+
--gds-sidebar-header-height: 3.25rem;
|
|
850
|
+
--gds-sidebar-content-py: 0.5rem;
|
|
851
|
+
--gds-sidebar-section-px: 0.5rem;
|
|
852
|
+
--gds-sidebar-section-gap: 0.125rem;
|
|
853
|
+
|
|
854
|
+
/* Carousel knobs — every visual dimension of <Carousel> is driven from
|
|
855
|
+
this stanza so consumers can re-skin the slideshow (dot shape, arrow
|
|
856
|
+
chrome, transition feel) without prop-drilling. The component reads
|
|
857
|
+
these as `var(--gds-carousel-* , <fallback>)` so missing values are
|
|
858
|
+
safe. */
|
|
859
|
+
--gds-carousel-gap: 0;
|
|
860
|
+
--gds-carousel-radius: var(--gds-media-radius, 0.5rem);
|
|
861
|
+
--gds-carousel-fade-ms: 200ms;
|
|
862
|
+
--gds-carousel-slide-basis: 100%;
|
|
863
|
+
/* Dots */
|
|
864
|
+
--gds-carousel-dot-size: 0.5rem;
|
|
865
|
+
--gds-carousel-dot-active-width: 1.25rem;
|
|
866
|
+
--gds-carousel-dot-color: oklch(var(--muted-foreground) / 0.4);
|
|
867
|
+
--gds-carousel-dot-active-color: oklch(var(--primary));
|
|
868
|
+
--gds-carousel-dots-gap: 0.75rem; /* between viewport and below-dots */
|
|
869
|
+
--gds-carousel-dots-spacing: 0.5rem; /* between adjacent dots */
|
|
870
|
+
--gds-carousel-dots-inset: 0.75rem; /* overlay position from bottom */
|
|
871
|
+
/* Arrows */
|
|
872
|
+
--gds-carousel-arrow-size: 2.25rem;
|
|
873
|
+
--gds-carousel-arrow-inset: 0.75rem;
|
|
874
|
+
--gds-carousel-arrow-bg: oklch(var(--background) / 0.85);
|
|
875
|
+
--gds-carousel-arrow-hover-bg: oklch(var(--background));
|
|
876
|
+
--gds-carousel-arrow-fg: oklch(var(--foreground));
|
|
877
|
+
--gds-carousel-arrow-backdrop: blur(6px);
|
|
878
|
+
--gds-carousel-arrow-shadow: 0 2px 8px oklch(0 0 0 / 0.12);
|
|
879
|
+
|
|
880
|
+
/* Alert surface pairs — paler tinted surface + readable deep text for each
|
|
881
|
+
status colour. Pre-hydration fallbacks; the JS theme pipeline overwrites
|
|
882
|
+
these via lib/themes/oklch.ts#deriveAlertPair. Kept here so the Alert
|
|
883
|
+
component has the right tokens before the theme provider mounts. */
|
|
884
|
+
--destructive-soft: 0.965 0.045 27;
|
|
885
|
+
--destructive-deep: 0.380 0.220 27;
|
|
886
|
+
--success-soft: 0.965 0.040 145;
|
|
887
|
+
--success-deep: 0.380 0.180 145;
|
|
888
|
+
--warning-soft: 0.965 0.040 60;
|
|
889
|
+
--warning-deep: 0.380 0.180 60;
|
|
890
|
+
--info-soft: 0.965 0.044 240;
|
|
891
|
+
--info-deep: 0.380 0.200 240;
|
|
892
|
+
--highlight-soft: 0.965 0.040 95;
|
|
893
|
+
--highlight-deep: 0.380 0.180 95;
|
|
894
|
+
|
|
895
|
+
/* Code surface tokens — used by `<Code>` (marketing/docs code blocks).
|
|
896
|
+
Token roles map to prism's tag types; the component reads them as
|
|
897
|
+
`color: var(--gds-code-<role>)` so the palette inverts with the
|
|
898
|
+
theme without us swapping prism themes at runtime. Light values
|
|
899
|
+
are tuned against a near-paper surface; the .dark block below
|
|
900
|
+
mirrors them for dark mode.
|
|
901
|
+
|
|
902
|
+
diff-added / diff-removed pairs are intentionally desaturated
|
|
903
|
+
surfaces with strong text — same pattern as the destructive-soft /
|
|
904
|
+
-deep alert pairs. Line-highlight is a quieter accent (no green/
|
|
905
|
+
red implication, just "look here"). */
|
|
906
|
+
--gds-code-bg: oklch(0.985 0.0018 85);
|
|
907
|
+
--gds-code-fg: oklch(0.220 0.012 250);
|
|
908
|
+
--gds-code-comment: oklch(0.620 0.030 250);
|
|
909
|
+
--gds-code-punctuation: oklch(0.420 0.020 250);
|
|
910
|
+
--gds-code-property: oklch(0.550 0.180 25);
|
|
911
|
+
--gds-code-number: oklch(0.560 0.180 35);
|
|
912
|
+
--gds-code-string: oklch(0.500 0.140 145);
|
|
913
|
+
--gds-code-operator: oklch(0.480 0.140 280);
|
|
914
|
+
--gds-code-keyword: oklch(0.490 0.220 285);
|
|
915
|
+
--gds-code-function: oklch(0.500 0.200 250);
|
|
916
|
+
--gds-code-variable: oklch(0.530 0.180 25);
|
|
917
|
+
--gds-code-tag: oklch(0.520 0.200 15);
|
|
918
|
+
--gds-code-attr-name: oklch(0.510 0.150 60);
|
|
919
|
+
--gds-code-attr-value: oklch(0.500 0.140 145);
|
|
920
|
+
--gds-code-line-highlight-bg: oklch(var(--selected-glow) / 0.10);
|
|
921
|
+
--gds-code-line-highlight-marker: oklch(var(--selected-glow) / 0.65);
|
|
922
|
+
--gds-code-diff-added-bg: oklch(var(--success) / 0.12);
|
|
923
|
+
--gds-code-diff-added-fg: oklch(0.300 0.140 145);
|
|
924
|
+
--gds-code-diff-removed-bg: oklch(var(--destructive) / 0.10);
|
|
925
|
+
--gds-code-diff-removed-fg: oklch(0.360 0.180 27);
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
.dark {
|
|
929
|
+
/* ----------------------------------------
|
|
930
|
+
Semantic Tokens — Studio dark defaults (synced from
|
|
931
|
+
apps/docs/app/globals.css, A7.1 — see the :root note).
|
|
932
|
+
---------------------------------------- */
|
|
933
|
+
--background: 0.170 0.0048 85;
|
|
934
|
+
--foreground: 0.985 0.0018 85;
|
|
935
|
+
--card: 0.245 0.0096 85; /* neutral 900 */
|
|
936
|
+
--card-foreground: 0.985 0.0018 85;
|
|
937
|
+
--popover: 0.245 0.0096 85;
|
|
938
|
+
--popover-foreground: 0.985 0.0018 85;
|
|
939
|
+
--primary: 0.955 0.0048 85; /* primary 400 */
|
|
940
|
+
--primary-foreground: 0.170 0.0048 85;
|
|
941
|
+
--secondary: 0.325 0.0144 85; /* neutral 800 */
|
|
942
|
+
--secondary-foreground: 0.895 0.0090 85;
|
|
943
|
+
--muted: 0.325 0.0144 85;
|
|
944
|
+
--muted-foreground: 0.720 0.0168 85;
|
|
945
|
+
--accent: 0.720 0.0252 85;
|
|
946
|
+
--accent-foreground: 0.170 0.0072 85;
|
|
947
|
+
--destructive: 0.680 0.220 27;
|
|
948
|
+
--destructive-foreground: 0.990 0.005 27;
|
|
949
|
+
--border: 0.325 0.0144 85;
|
|
950
|
+
--input: 0.325 0.0144 85;
|
|
951
|
+
--ring: 0.820 0.0132 85;
|
|
952
|
+
|
|
953
|
+
--success: 0.720 0.180 145;
|
|
954
|
+
--warning: 0.800 0.180 60;
|
|
955
|
+
--info: 0.700 0.200 240;
|
|
956
|
+
--highlight: 0.880 0.180 95;
|
|
957
|
+
|
|
958
|
+
/* Selection pair — dark mode. Solid fill stays vivid; halo lifts in
|
|
959
|
+
lightness so it can glow against the dark canvas. */
|
|
960
|
+
--selected: 0.62 0.22 258;
|
|
961
|
+
--selected-foreground: 0.985 0.0018 85;
|
|
962
|
+
--selected-glow: 0.74 0.20 258;
|
|
963
|
+
|
|
964
|
+
/* Accent glow — dark mode. Same theme-driven default (primary), but
|
|
965
|
+
the dark variants of --primary already carry the appropriate lift
|
|
966
|
+
for a glow against the dark canvas. */
|
|
967
|
+
--accent-glow: var(--primary);
|
|
968
|
+
|
|
969
|
+
/* Canvas fill — dark mode. Deep near-black cinematic backdrop (the light
|
|
970
|
+
default in :root is a soft neutral). One token, mode-scoped: letterbox
|
|
971
|
+
bars in embed/share/preview and the ScreenAnimator stage all match. */
|
|
972
|
+
--gds-canvas-fill: #0b0b0e;
|
|
973
|
+
|
|
974
|
+
/* Alert surface pairs — dark-mode variant: tint sits just above the dark
|
|
975
|
+
background without going gray; deep text stays bright and readable. */
|
|
976
|
+
--destructive-soft: 0.220 0.075 27;
|
|
977
|
+
--destructive-deep: 0.820 0.198 27;
|
|
978
|
+
--success-soft: 0.220 0.075 145;
|
|
979
|
+
--success-deep: 0.820 0.162 145;
|
|
980
|
+
--warning-soft: 0.220 0.075 60;
|
|
981
|
+
--warning-deep: 0.820 0.162 60;
|
|
982
|
+
--info-soft: 0.220 0.075 240;
|
|
983
|
+
--info-deep: 0.820 0.180 240;
|
|
984
|
+
--highlight-soft: 0.220 0.075 95;
|
|
985
|
+
--highlight-deep: 0.820 0.162 95;
|
|
986
|
+
|
|
987
|
+
/* -- Elevation: bump alphas in dark mode. Shadows fade against
|
|
988
|
+
dark surfaces; without this the lift looks anemic. -- */
|
|
989
|
+
--shadow-bevel-hi-alpha: 0.14;
|
|
990
|
+
--shadow-bevel-lo-alpha: 0.40;
|
|
991
|
+
--shadow-contact-alpha: 0.45;
|
|
992
|
+
--shadow-lift-alpha: 0.50;
|
|
993
|
+
--shadow-lift-deep-alpha: 0.60;
|
|
994
|
+
|
|
995
|
+
/* -- Surface: glass needs higher opacity in dark mode or the card
|
|
996
|
+
loses its boundary against the canvas. -- */
|
|
997
|
+
--surface-alpha-translucent: 0.74;
|
|
998
|
+
--surface-alpha-glass: 0.48;
|
|
999
|
+
--surface-alpha-glass-strong: 0.32;
|
|
1000
|
+
--surface-edge-alpha: 0.06;
|
|
1001
|
+
|
|
1002
|
+
/* Code surface tokens — dark mode mirror. Background sits a touch
|
|
1003
|
+
above the page bg so the code block reads as a distinct surface
|
|
1004
|
+
even on a dark hero. Tokens lift in lightness to stay readable. */
|
|
1005
|
+
--gds-code-bg: oklch(0.205 0.010 250);
|
|
1006
|
+
--gds-code-fg: oklch(0.920 0.012 250);
|
|
1007
|
+
--gds-code-comment: oklch(0.580 0.024 250);
|
|
1008
|
+
--gds-code-punctuation: oklch(0.760 0.018 250);
|
|
1009
|
+
--gds-code-property: oklch(0.780 0.150 25);
|
|
1010
|
+
--gds-code-number: oklch(0.790 0.150 60);
|
|
1011
|
+
--gds-code-string: oklch(0.780 0.140 145);
|
|
1012
|
+
--gds-code-operator: oklch(0.770 0.130 280);
|
|
1013
|
+
--gds-code-keyword: oklch(0.760 0.180 285);
|
|
1014
|
+
--gds-code-function: oklch(0.770 0.150 250);
|
|
1015
|
+
--gds-code-variable: oklch(0.790 0.160 25);
|
|
1016
|
+
--gds-code-tag: oklch(0.780 0.180 15);
|
|
1017
|
+
--gds-code-attr-name: oklch(0.800 0.140 60);
|
|
1018
|
+
--gds-code-attr-value: oklch(0.780 0.140 145);
|
|
1019
|
+
--gds-code-line-highlight-bg: oklch(var(--selected-glow) / 0.16);
|
|
1020
|
+
--gds-code-line-highlight-marker: oklch(var(--selected-glow) / 0.85);
|
|
1021
|
+
--gds-code-diff-added-bg: oklch(var(--success) / 0.18);
|
|
1022
|
+
--gds-code-diff-added-fg: oklch(0.870 0.160 145);
|
|
1023
|
+
--gds-code-diff-removed-bg: oklch(var(--destructive) / 0.18);
|
|
1024
|
+
--gds-code-diff-removed-fg: oklch(0.870 0.180 27);
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/* ============================================
|
|
1028
|
+
ENERGY THEME — scoped overrides.
|
|
1029
|
+
Engaged when data-grade-theme="energy" is set on :root (either by the
|
|
1030
|
+
pre-hydration inline script or GradeThemeProvider). Mirrors the Energy
|
|
1031
|
+
built-in (hues all at 175, teal primary, Geist sans).
|
|
1032
|
+
============================================ */
|
|
1033
|
+
:root[data-grade-theme="energy"] {
|
|
1034
|
+
--background: 0.985 0.0012 175; /* neutral 50 */
|
|
1035
|
+
--foreground: 0.170 0.0032 175; /* neutral 950 */
|
|
1036
|
+
--card: 1 0 0;
|
|
1037
|
+
--card-foreground: 0.170 0.0032 175;
|
|
1038
|
+
--popover: 1 0 0;
|
|
1039
|
+
--popover-foreground: 0.170 0.0032 175;
|
|
1040
|
+
--primary: 0.610 0.170 175; /* primary 500 — teal */
|
|
1041
|
+
--primary-foreground: 0.985 0.015 175;
|
|
1042
|
+
--secondary: 0.955 0.0032 175; /* neutral 100 */
|
|
1043
|
+
--secondary-foreground: 0.415 0.012 175; /* neutral 700 */
|
|
1044
|
+
--muted: 0.955 0.0032 175;
|
|
1045
|
+
--muted-foreground: 0.610 0.0136 175;
|
|
1046
|
+
--accent: 0.610 0.170 175;
|
|
1047
|
+
--accent-foreground: 0.985 0.015 175;
|
|
1048
|
+
--border: 0.895 0.006 175;
|
|
1049
|
+
--input: 0.895 0.006 175;
|
|
1050
|
+
--ring: 0.610 0.170 175;
|
|
1051
|
+
--radius: 0.5rem;
|
|
1052
|
+
|
|
1053
|
+
--font-sans: var(--font-geist), system-ui, sans-serif;
|
|
1054
|
+
--font-display: var(--font-geist), system-ui, sans-serif;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
.dark[data-grade-theme="energy"] {
|
|
1058
|
+
--background: 0.170 0.0032 175;
|
|
1059
|
+
--foreground: 0.985 0.0012 175;
|
|
1060
|
+
--card: 0.245 0.0064 175;
|
|
1061
|
+
--card-foreground: 0.985 0.0012 175;
|
|
1062
|
+
--popover: 0.245 0.0064 175;
|
|
1063
|
+
--popover-foreground: 0.985 0.0012 175;
|
|
1064
|
+
--primary: 0.720 0.140 175;
|
|
1065
|
+
--primary-foreground: 0.170 0.040 175;
|
|
1066
|
+
--secondary: 0.325 0.0096 175;
|
|
1067
|
+
--secondary-foreground: 0.895 0.006 175;
|
|
1068
|
+
--muted: 0.325 0.0096 175;
|
|
1069
|
+
--muted-foreground: 0.720 0.0112 175;
|
|
1070
|
+
--accent: 0.720 0.140 175;
|
|
1071
|
+
--accent-foreground: 0.170 0.040 175;
|
|
1072
|
+
--border: 0.325 0.0096 175;
|
|
1073
|
+
--input: 0.325 0.0096 175;
|
|
1074
|
+
--ring: 0.720 0.140 175;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
@layer base {
|
|
1078
|
+
* {
|
|
1079
|
+
@apply border-border;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
/* Smooth theme transitions */
|
|
1083
|
+
html {
|
|
1084
|
+
transition-property: background-color, border-color;
|
|
1085
|
+
transition-duration: 200ms;
|
|
1086
|
+
transition-timing-function: ease-in-out;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
body {
|
|
1090
|
+
@apply bg-background text-foreground;
|
|
1091
|
+
font-feature-settings: "rlig" 1, "calt" 1;
|
|
1092
|
+
font-size: var(--text-body);
|
|
1093
|
+
line-height: var(--text-body-line);
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/* Theme-driven heading font.
|
|
1097
|
+
Naked <h1>–<h4> elements pick up the active theme's display font
|
|
1098
|
+
(falls back to sans if the theme doesn't set one). Utility classes
|
|
1099
|
+
like .text-h1 still win if they set their own font, since classes
|
|
1100
|
+
outrank tag selectors. */
|
|
1101
|
+
h1, h2, h3, h4 {
|
|
1102
|
+
font-family: var(--font-display, var(--font-sans));
|
|
1103
|
+
font-weight: var(--font-heading-weight, 600);
|
|
1104
|
+
letter-spacing: var(--font-heading-tracking, -0.01em);
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
/* Link styles */
|
|
1108
|
+
a:not([class]) {
|
|
1109
|
+
@apply text-primary underline-offset-4 hover:underline;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
/* ============================================
|
|
1114
|
+
APP SHELL GRID
|
|
1115
|
+
Five slots — Header, Nav, Aside, Main, Footer — placed via CSS-grid
|
|
1116
|
+
template areas keyed off [data-nav] on the shell root. Slot order in
|
|
1117
|
+
JSX doesn't matter; each slot has a fixed grid-area class assignment.
|
|
1118
|
+
============================================ */
|
|
1119
|
+
|
|
1120
|
+
.gds-app-shell-header { grid-area: header; }
|
|
1121
|
+
.gds-app-shell-nav { grid-area: nav; }
|
|
1122
|
+
.gds-app-shell-aside { grid-area: aside; }
|
|
1123
|
+
.gds-app-shell-main { grid-area: main; }
|
|
1124
|
+
.gds-app-shell-footer { grid-area: footer; }
|
|
1125
|
+
|
|
1126
|
+
/* nav="none" — Header / Main / Footer stacked vertically. */
|
|
1127
|
+
.gds-app-shell[data-nav="none"] {
|
|
1128
|
+
grid-template-areas: "header" "main" "footer";
|
|
1129
|
+
grid-template-rows: auto 1fr auto;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
/* nav="top" — Header (site chrome), then in-app top nav, then Main. */
|
|
1133
|
+
.gds-app-shell[data-nav="top"] {
|
|
1134
|
+
grid-template-areas: "header" "nav" "main" "footer";
|
|
1135
|
+
grid-template-rows: auto auto 1fr auto;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
/* nav="side" — Header full width, Nav rail + Main below, Footer full width. */
|
|
1139
|
+
.gds-app-shell[data-nav="side"] {
|
|
1140
|
+
grid-template-areas:
|
|
1141
|
+
"header header"
|
|
1142
|
+
"nav main"
|
|
1143
|
+
"footer footer";
|
|
1144
|
+
grid-template-rows: auto 1fr auto;
|
|
1145
|
+
grid-template-columns: auto 1fr;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
/* nav="three-pane" — Header full width, Nav rail + fixed Aside + flex Main,
|
|
1149
|
+
Footer full width. Aside width is set by --gds-app-shell-aside (default
|
|
1150
|
+
320px) so callers can override per-screen via inline style or a parent
|
|
1151
|
+
class without forking the component. */
|
|
1152
|
+
.gds-app-shell[data-nav="three-pane"] {
|
|
1153
|
+
grid-template-areas:
|
|
1154
|
+
"header header header"
|
|
1155
|
+
"nav aside main"
|
|
1156
|
+
"footer footer footer";
|
|
1157
|
+
grid-template-rows: auto 1fr auto;
|
|
1158
|
+
grid-template-columns: auto var(--gds-app-shell-aside, 320px) 1fr;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
/* ============================================
|
|
1162
|
+
THEME-DRIVEN COMPONENT SHAPES
|
|
1163
|
+
Keyed off data attributes that GradeThemeProvider sets on <html>.
|
|
1164
|
+
Each rule is an additive opt-in — themes that don't set a style get
|
|
1165
|
+
the component's default look.
|
|
1166
|
+
============================================ */
|
|
1167
|
+
|
|
1168
|
+
/* Card styles */
|
|
1169
|
+
[data-card-style="outlined"] .gds-card {
|
|
1170
|
+
box-shadow: none;
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
[data-card-style="flat"] .gds-card {
|
|
1174
|
+
box-shadow: none;
|
|
1175
|
+
border-color: transparent;
|
|
1176
|
+
background-color: oklch(var(--muted));
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
[data-card-style="elevated"] .gds-card {
|
|
1180
|
+
box-shadow: var(--gds-shadow-lg);
|
|
1181
|
+
border-color: transparent;
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
[data-card-style="glass"] .gds-card {
|
|
1185
|
+
background-color: oklch(var(--card) / 0.6);
|
|
1186
|
+
backdrop-filter: blur(12px);
|
|
1187
|
+
-webkit-backdrop-filter: blur(12px);
|
|
1188
|
+
border-color: oklch(var(--border) / 0.5);
|
|
1189
|
+
box-shadow: var(--gds-shadow-md);
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
/* Button shapes — themes can set buttonShape: "pill" | "square" | "sharp".
|
|
1193
|
+
The Button component's radius comes from --radius (shadcn), so we override
|
|
1194
|
+
border-radius directly on the gds-button class when a shape is set. */
|
|
1195
|
+
[data-button-shape="pill"] .gds-button {
|
|
1196
|
+
border-radius: 9999px;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
[data-button-shape="square"] .gds-button,
|
|
1200
|
+
[data-button-shape="sharp"] .gds-button {
|
|
1201
|
+
border-radius: 0;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
/* ============================================
|
|
1205
|
+
BUTTON — RAISED VARIANT
|
|
1206
|
+
============================================
|
|
1207
|
+
Tactile "physical key" treatment composed from elevation tokens.
|
|
1208
|
+
Tone is driven by `--btn-glow` (defaults to --selected-glow); the
|
|
1209
|
+
heat-inner / heat-outer layers in the elevation system already read
|
|
1210
|
+
from --btn-glow so per-button overrides flow through automatically.
|
|
1211
|
+
|
|
1212
|
+
Tabs and Toggle pick this up too via the same data-state / aria
|
|
1213
|
+
selectors below — TabsTrigger emits `data-state="active"`, Toggle
|
|
1214
|
+
emits `data-state="on"`, both listed. */
|
|
1215
|
+
.gds-button-raised {
|
|
1216
|
+
/* Cascade: per-element style override > --accent-glow (theme accent,
|
|
1217
|
+
defaults to --primary) > --selected-glow (system selection blue).
|
|
1218
|
+
Was hardcoded to --selected-glow before May 2026 — the user
|
|
1219
|
+
flagged "should pull from theme accent, not selection blue", which
|
|
1220
|
+
this fallback chain solves without breaking existing per-button
|
|
1221
|
+
style overrides like `style={{ "--btn-glow": "var(--warning)" }}`. */
|
|
1222
|
+
--btn-glow: var(--accent-glow, var(--selected-glow));
|
|
1223
|
+
|
|
1224
|
+
background-color: oklch(var(--secondary));
|
|
1225
|
+
color: oklch(var(--secondary-foreground));
|
|
1226
|
+
|
|
1227
|
+
box-shadow: var(--elevation-3);
|
|
1228
|
+
|
|
1229
|
+
transition:
|
|
1230
|
+
box-shadow var(--gds-transition-base) var(--gds-ease-out),
|
|
1231
|
+
transform var(--gds-transition-fast) var(--gds-ease-out),
|
|
1232
|
+
background-color var(--gds-transition-base) var(--gds-ease-out);
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
.gds-button-raised:hover {
|
|
1236
|
+
box-shadow: var(--elevation-hot);
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
.gds-button-raised:active {
|
|
1240
|
+
transform: translateY(1px);
|
|
1241
|
+
box-shadow: var(--elevation-pressed);
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
.gds-button-raised[data-state="on"],
|
|
1245
|
+
.gds-button-raised[data-state="active"],
|
|
1246
|
+
.gds-button-raised[aria-pressed="true"],
|
|
1247
|
+
.gds-button-raised[data-selected="true"] {
|
|
1248
|
+
background-color: oklch(var(--selected) / 0.18);
|
|
1249
|
+
color: oklch(var(--foreground));
|
|
1250
|
+
box-shadow:
|
|
1251
|
+
var(--shadow-bevel-hi),
|
|
1252
|
+
inset 0 0 0 1px oklch(var(--selected) / 0.55),
|
|
1253
|
+
var(--shadow-heat-inner),
|
|
1254
|
+
0 0 0 1px oklch(var(--selected) / 0.20),
|
|
1255
|
+
var(--shadow-heat-outer),
|
|
1256
|
+
var(--shadow-lift);
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
.gds-button-raised:focus-visible {
|
|
1260
|
+
outline: none;
|
|
1261
|
+
box-shadow:
|
|
1262
|
+
var(--shadow-bevel-hi),
|
|
1263
|
+
var(--shadow-bevel-lo),
|
|
1264
|
+
0 0 0 2px oklch(var(--background)),
|
|
1265
|
+
0 0 0 4px oklch(var(--btn-glow) / 0.70),
|
|
1266
|
+
var(--shadow-lift);
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
/* ============================================
|
|
1270
|
+
CODE CURSOR — blinking caret for `<Code>` typewriter / terminal demos
|
|
1271
|
+
============================================
|
|
1272
|
+
Rendered as a 1ch-wide block at the tail of the active line. Uses
|
|
1273
|
+
currentColor so it inherits the surrounding token colour (which is
|
|
1274
|
+
`--gds-code-fg` by default but can be set per-line by the consumer).
|
|
1275
|
+
The 1.05s cycle is the canonical iOS/macOS caret blink rate. */
|
|
1276
|
+
@keyframes gds-code-caret-blink {
|
|
1277
|
+
0%, 49% { opacity: 1; }
|
|
1278
|
+
50%, 100% { opacity: 0; }
|
|
1279
|
+
}
|
|
1280
|
+
.gds-code-cursor {
|
|
1281
|
+
display: inline-block;
|
|
1282
|
+
width: 0.55em;
|
|
1283
|
+
height: 1.05em;
|
|
1284
|
+
vertical-align: text-bottom;
|
|
1285
|
+
margin-left: 0.05em;
|
|
1286
|
+
background-color: currentColor;
|
|
1287
|
+
border-radius: 1px;
|
|
1288
|
+
animation: gds-code-caret-blink 1.05s steps(1, end) infinite;
|
|
1289
|
+
}
|
|
1290
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1291
|
+
.gds-code-cursor { animation: none; opacity: 1; }
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
/* ============================================
|
|
1295
|
+
DEMO CURSOR — generic blinking caret used by lib/demo/ consumers
|
|
1296
|
+
============================================
|
|
1297
|
+
The shared caret used wherever a gradeui component scripts typing
|
|
1298
|
+
(Code's terminal lines, Composer's inline cursor, future surfaces).
|
|
1299
|
+
Parameterised via CSS variables so each host can dial dimensions
|
|
1300
|
+
and colour without forking the class.
|
|
1301
|
+
|
|
1302
|
+
--gds-demo-cursor-color defaults to currentColor
|
|
1303
|
+
--gds-demo-cursor-width defaults to 0.55em
|
|
1304
|
+
--gds-demo-cursor-height defaults to 1.05em
|
|
1305
|
+
--gds-demo-cursor-radius defaults to 1px
|
|
1306
|
+
|
|
1307
|
+
Two variants — `inline` (default; thin caret for text) and `block`
|
|
1308
|
+
(square cell for terminal demos). The block variant swaps width to
|
|
1309
|
+
match height. */
|
|
1310
|
+
.gds-demo-cursor {
|
|
1311
|
+
display: inline-block;
|
|
1312
|
+
width: var(--gds-demo-cursor-width, 0.55em);
|
|
1313
|
+
height: var(--gds-demo-cursor-height, 1.05em);
|
|
1314
|
+
vertical-align: text-bottom;
|
|
1315
|
+
margin-left: 0.05em;
|
|
1316
|
+
background-color: var(--gds-demo-cursor-color, currentColor);
|
|
1317
|
+
border-radius: var(--gds-demo-cursor-radius, 1px);
|
|
1318
|
+
animation: gds-code-caret-blink 1.05s steps(1, end) infinite;
|
|
1319
|
+
}
|
|
1320
|
+
.gds-demo-cursor[data-gds-variant="block"] {
|
|
1321
|
+
width: var(--gds-demo-cursor-height, 1.05em);
|
|
1322
|
+
border-radius: 0;
|
|
1323
|
+
}
|
|
1324
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1325
|
+
.gds-demo-cursor { animation: none; opacity: 1; }
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
/* ============================================
|
|
1329
|
+
COMPOSER — token palette for <Composer>
|
|
1330
|
+
============================================
|
|
1331
|
+
The generic text composition surface (chat / comments / post body).
|
|
1332
|
+
Tokens here drive the editor card, toolbar, mention pills, and
|
|
1333
|
+
attachment chips. Theme via consumer CSS to retune any surface
|
|
1334
|
+
without forking the component.
|
|
1335
|
+
|
|
1336
|
+
Two themes shipped inline: light + dark via .dark scoping. */
|
|
1337
|
+
:root {
|
|
1338
|
+
--gds-composer-bg: var(--background);
|
|
1339
|
+
--gds-composer-fg: var(--foreground);
|
|
1340
|
+
--gds-composer-muted-fg: var(--muted-foreground);
|
|
1341
|
+
--gds-composer-border: var(--border);
|
|
1342
|
+
--gds-composer-action-fg: var(--muted-foreground);
|
|
1343
|
+
--gds-composer-toolbar-fg: var(--muted-foreground);
|
|
1344
|
+
--gds-composer-toolbar-hover-bg: var(--muted);
|
|
1345
|
+
--gds-composer-toolbar-active-bg: var(--accent);
|
|
1346
|
+
--gds-composer-toolbar-active-fg: var(--accent-foreground);
|
|
1347
|
+
--gds-composer-chip-remove-bg: oklch(0.15 0 0);
|
|
1348
|
+
--gds-composer-chip-remove-fg: #fff;
|
|
1349
|
+
--gds-composer-mention-bg: oklch(var(--primary) / 0.12);
|
|
1350
|
+
--gds-composer-mention-fg: oklch(var(--primary));
|
|
1351
|
+
--gds-composer-mention-slash-bg: oklch(0.6 0.12 280 / 0.12);
|
|
1352
|
+
--gds-composer-mention-slash-fg: oklch(0.6 0.12 280);
|
|
1353
|
+
}
|
|
1354
|
+
.dark {
|
|
1355
|
+
--gds-composer-chip-remove-bg: #fff;
|
|
1356
|
+
--gds-composer-chip-remove-fg: oklch(0.15 0 0);
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
/* Mention pill — applied via Lexical theme.beautifulMentions.
|
|
1360
|
+
Renders as an inline rounded chip with a subtle background and
|
|
1361
|
+
the trigger char + value. */
|
|
1362
|
+
.gds-composer-mention {
|
|
1363
|
+
display: inline-block;
|
|
1364
|
+
padding: 0 0.4em;
|
|
1365
|
+
margin: 0 0.05em;
|
|
1366
|
+
border-radius: 0.4em;
|
|
1367
|
+
background: var(--gds-composer-mention-bg);
|
|
1368
|
+
color: var(--gds-composer-mention-fg);
|
|
1369
|
+
font-weight: 500;
|
|
1370
|
+
cursor: default;
|
|
1371
|
+
}
|
|
1372
|
+
.gds-composer-mention-slash {
|
|
1373
|
+
background: var(--gds-composer-mention-slash-bg);
|
|
1374
|
+
color: var(--gds-composer-mention-slash-fg);
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
/* Pullquote — styled variant of blockquote. The Lexical node
|
|
1378
|
+
carries a __pullquote sentinel; this rule applies whenever the
|
|
1379
|
+
blockquote DOM is tagged with data-gds-pullquote (set via a
|
|
1380
|
+
future custom node) OR carries the .gds-composer-pullquote class. */
|
|
1381
|
+
.gds-composer-pullquote,
|
|
1382
|
+
[data-gds-pullquote="true"] {
|
|
1383
|
+
border-left: 3px solid var(--primary);
|
|
1384
|
+
padding-left: 1rem;
|
|
1385
|
+
font-size: 1.125rem;
|
|
1386
|
+
font-style: normal;
|
|
1387
|
+
font-weight: 500;
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
/* ============================================
|
|
1391
|
+
SURFACE CLASSES
|
|
1392
|
+
============================================
|
|
1393
|
+
Apply one to any container. Composes with elevation classes —
|
|
1394
|
+
`<div class="gds-surface-glass shadow-elevation-4">` is a glass
|
|
1395
|
+
popover sitting at popover elevation, no conflict.
|
|
1396
|
+
|
|
1397
|
+
--card is theme-aware, so each theme automatically gets its own
|
|
1398
|
+
"frosted X" tint without per-theme overrides. */
|
|
1399
|
+
.gds-surface-solid {
|
|
1400
|
+
background-color: var(--surface-solid);
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
.gds-surface-translucent {
|
|
1404
|
+
background-color: var(--surface-translucent);
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
.gds-surface-glass {
|
|
1408
|
+
background-color: var(--surface-glass);
|
|
1409
|
+
backdrop-filter: blur(var(--surface-blur-glass));
|
|
1410
|
+
-webkit-backdrop-filter: blur(var(--surface-blur-glass));
|
|
1411
|
+
border: 1px solid oklch(var(--border) / 0.5);
|
|
1412
|
+
box-shadow: var(--surface-edge);
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
.gds-surface-glass-strong {
|
|
1416
|
+
background-color: var(--surface-glass-strong);
|
|
1417
|
+
backdrop-filter: blur(var(--surface-blur-strong));
|
|
1418
|
+
-webkit-backdrop-filter: blur(var(--surface-blur-strong));
|
|
1419
|
+
border: 1px solid oklch(var(--border) / 0.4);
|
|
1420
|
+
box-shadow: var(--surface-edge);
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
/* ============================================
|
|
1424
|
+
AURA — RING (pulsing outer halo)
|
|
1425
|
+
============================================
|
|
1426
|
+
Apply `.gds-aura-ring` to any element. Animation duration & easing
|
|
1427
|
+
are CSS vars (`--aura-pulse-duration`, `--aura-pulse-ease`) — set
|
|
1428
|
+
them at the consumer level to retune without rewriting keyframes.
|
|
1429
|
+
Tone defaults to --aura-color (= --selected-glow); override per
|
|
1430
|
+
element for danger / success attention. */
|
|
1431
|
+
@keyframes gds-aura-pulse {
|
|
1432
|
+
0%, 100% {
|
|
1433
|
+
box-shadow:
|
|
1434
|
+
0 0 0 0 oklch(var(--aura-color) / var(--aura-ring-alpha-min)),
|
|
1435
|
+
0 0 0 0 oklch(var(--aura-color) / 0);
|
|
1436
|
+
}
|
|
1437
|
+
50% {
|
|
1438
|
+
box-shadow:
|
|
1439
|
+
0 0 0 var(--aura-ring-spread) oklch(var(--aura-color) / var(--aura-ring-alpha-max)),
|
|
1440
|
+
0 0 var(--aura-ring-blur) 0 oklch(var(--aura-color) / calc(var(--aura-ring-alpha-max) * 0.6));
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
.gds-aura-ring {
|
|
1445
|
+
animation: gds-aura-pulse var(--aura-pulse-duration) var(--aura-pulse-ease) infinite;
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
/* ============================================
|
|
1449
|
+
AURA — GRADIENT (rotating conic border)
|
|
1450
|
+
============================================
|
|
1451
|
+
Uses a ::before pseudo with a conic-gradient masked to just the
|
|
1452
|
+
border ring (via the standard mask-composite trick). The angle is
|
|
1453
|
+
animated via @property so the gradient rotates rather than redrawing.
|
|
1454
|
+
Requires position:relative on the host element; class adds it. */
|
|
1455
|
+
@property --aura-gradient-angle {
|
|
1456
|
+
syntax: "<angle>";
|
|
1457
|
+
initial-value: 0deg;
|
|
1458
|
+
inherits: false;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
@keyframes gds-aura-gradient-spin {
|
|
1462
|
+
to { --aura-gradient-angle: 360deg; }
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
.gds-aura-gradient {
|
|
1466
|
+
position: relative;
|
|
1467
|
+
isolation: isolate;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
.gds-aura-gradient::before {
|
|
1471
|
+
content: "";
|
|
1472
|
+
position: absolute;
|
|
1473
|
+
inset: 0;
|
|
1474
|
+
border-radius: inherit;
|
|
1475
|
+
padding: var(--aura-gradient-thickness);
|
|
1476
|
+
background: conic-gradient(
|
|
1477
|
+
from var(--aura-gradient-angle),
|
|
1478
|
+
oklch(var(--aura-color) / 0) 0deg,
|
|
1479
|
+
oklch(var(--aura-color) / 0.9) 90deg,
|
|
1480
|
+
oklch(var(--aura-color) / 0) 180deg,
|
|
1481
|
+
oklch(var(--aura-color) / 0.9) 270deg,
|
|
1482
|
+
oklch(var(--aura-color) / 0) 360deg
|
|
1483
|
+
);
|
|
1484
|
+
/* mask trick: paint only the border ring, not the body */
|
|
1485
|
+
-webkit-mask:
|
|
1486
|
+
linear-gradient(#000 0 0) content-box,
|
|
1487
|
+
linear-gradient(#000 0 0);
|
|
1488
|
+
-webkit-mask-composite: xor;
|
|
1489
|
+
mask:
|
|
1490
|
+
linear-gradient(#000 0 0) content-box,
|
|
1491
|
+
linear-gradient(#000 0 0);
|
|
1492
|
+
mask-composite: exclude;
|
|
1493
|
+
pointer-events: none;
|
|
1494
|
+
animation: gds-aura-gradient-spin var(--aura-gradient-duration) var(--aura-gradient-ease) infinite;
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
/* ============================================
|
|
1498
|
+
AURA — SHIMMER (diagonal sweep)
|
|
1499
|
+
============================================
|
|
1500
|
+
Highlight sweeps across the element periodically. Lives on a
|
|
1501
|
+
::after pseudo with `overflow: hidden` applied to the host so the
|
|
1502
|
+
sweep clips to the element's shape. Uses background-position rather
|
|
1503
|
+
than transform so it composites cheaply with the gradient + ring
|
|
1504
|
+
layers. */
|
|
1505
|
+
@keyframes gds-aura-shimmer-sweep {
|
|
1506
|
+
0% { background-position: -150% 0; opacity: 0; }
|
|
1507
|
+
8% { opacity: var(--aura-shimmer-alpha); }
|
|
1508
|
+
60% { background-position: 250% 0; opacity: var(--aura-shimmer-alpha); }
|
|
1509
|
+
62% { opacity: 0; }
|
|
1510
|
+
100% { background-position: 250% 0; opacity: 0; }
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
.gds-aura-shimmer {
|
|
1514
|
+
position: relative;
|
|
1515
|
+
overflow: hidden;
|
|
1516
|
+
isolation: isolate;
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
.gds-aura-shimmer::after {
|
|
1520
|
+
content: "";
|
|
1521
|
+
position: absolute;
|
|
1522
|
+
inset: 0;
|
|
1523
|
+
border-radius: inherit;
|
|
1524
|
+
background-image: linear-gradient(
|
|
1525
|
+
105deg,
|
|
1526
|
+
transparent 30%,
|
|
1527
|
+
oklch(var(--aura-color) / 1) 50%,
|
|
1528
|
+
transparent 70%
|
|
1529
|
+
);
|
|
1530
|
+
background-size: var(--aura-shimmer-width) 200%;
|
|
1531
|
+
background-repeat: no-repeat;
|
|
1532
|
+
pointer-events: none;
|
|
1533
|
+
animation: gds-aura-shimmer-sweep
|
|
1534
|
+
calc(var(--aura-shimmer-duration) + var(--aura-shimmer-delay-between))
|
|
1535
|
+
var(--aura-shimmer-ease) infinite;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
/* Reduce-motion: aura animations are decorative. Honor the user's
|
|
1539
|
+
pref by holding at the "peak" frame instead of animating. */
|
|
1540
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1541
|
+
.gds-aura-ring,
|
|
1542
|
+
.gds-aura-gradient::before,
|
|
1543
|
+
.gds-aura-shimmer::after {
|
|
1544
|
+
animation: none;
|
|
1545
|
+
}
|
|
1546
|
+
.gds-aura-ring {
|
|
1547
|
+
box-shadow:
|
|
1548
|
+
0 0 0 var(--aura-ring-spread) oklch(var(--aura-color) / calc(var(--aura-ring-alpha-max) * 0.6)),
|
|
1549
|
+
0 0 var(--aura-ring-blur) 0 oklch(var(--aura-color) / calc(var(--aura-ring-alpha-max) * 0.4));
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
/* ============================================
|
|
1554
|
+
MOTION TOGGLE — data-motion="off" on <html>
|
|
1555
|
+
============================================
|
|
1556
|
+
The manual motion switch (lib/motion). Mirrors the OS reduced-motion
|
|
1557
|
+
behaviour but driven by an attribute, so it can be flipped from a toolbar
|
|
1558
|
+
and posted into Studio's Fast Frame / embed iframes (grade:set-motion).
|
|
1559
|
+
Reduce-only: this never forces motion ON, it only suppresses it.
|
|
1560
|
+
|
|
1561
|
+
Broad reset first — neutralises animation/transition on arbitrary
|
|
1562
|
+
(generated-screen) content, the same shape the canonical
|
|
1563
|
+
prefers-reduced-motion reset uses. */
|
|
1564
|
+
[data-motion="off"] *,
|
|
1565
|
+
[data-motion="off"] *::before,
|
|
1566
|
+
[data-motion="off"] *::after {
|
|
1567
|
+
animation-duration: 0.01ms !important;
|
|
1568
|
+
animation-iteration-count: 1 !important;
|
|
1569
|
+
transition-duration: 0.01ms !important;
|
|
1570
|
+
scroll-behavior: auto !important;
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
/* Aura keeps its bespoke static fallback (the broad reset can't supply the
|
|
1574
|
+
resting box-shadow). */
|
|
1575
|
+
[data-motion="off"] .gds-aura-ring {
|
|
1576
|
+
box-shadow:
|
|
1577
|
+
0 0 0 var(--aura-ring-spread) oklch(var(--aura-color) / calc(var(--aura-ring-alpha-max) * 0.6)),
|
|
1578
|
+
0 0 var(--aura-ring-blur) 0 oklch(var(--aura-color) / calc(var(--aura-ring-alpha-max) * 0.4));
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
/* ============================================
|
|
1582
|
+
STREAM-IN — data-gds-streaming on <html>
|
|
1583
|
+
============================================
|
|
1584
|
+
Live-draw treatment for streaming renders: while the attribute is
|
|
1585
|
+
stamped on <html>, every element ENTERING the DOM fades + rises in.
|
|
1586
|
+
|
|
1587
|
+
CURRENTLY DORMANT — the Fast Frame sandbox no longer stamps the
|
|
1588
|
+
attribute. Speculative drafts moved to double-buffered full
|
|
1589
|
+
remounts (every compile re-inserts EVERY element, so this rule made
|
|
1590
|
+
the whole frame pulse on each draft tick rather than easing in just
|
|
1591
|
+
the new content). Kept because the treatment is right for a future
|
|
1592
|
+
diff-aware renderer that only inserts the appended elements.
|
|
1593
|
+
|
|
1594
|
+
While stamped, every element ENTERING the DOM fades + rises in.
|
|
1595
|
+
Implemented with @starting-style + transition rather than a
|
|
1596
|
+
keyframe animation on purpose:
|
|
1597
|
+
- `@starting-style` only fires on first render of an element, so
|
|
1598
|
+
React-preserved nodes don't re-animate on every draft compile —
|
|
1599
|
+
only the newly streamed-in elements move.
|
|
1600
|
+
- It composes via `transition`, leaving each component's own
|
|
1601
|
+
`animation` (pulse, spin, aura) untouched. The universal
|
|
1602
|
+
transition does temporarily override component transitions while
|
|
1603
|
+
streaming, which is acceptable: the screen is read-only while it
|
|
1604
|
+
draws.
|
|
1605
|
+
Tunable via the --gds-stream-in-* tokens. Respects both the OS
|
|
1606
|
+
reduced-motion preference and the manual data-motion="off" toggle
|
|
1607
|
+
(the broad reset above zeroes transition-duration). */
|
|
1608
|
+
:root {
|
|
1609
|
+
--gds-stream-in-duration: 240ms;
|
|
1610
|
+
--gds-stream-in-ease: cubic-bezier(0.22, 1, 0.36, 1);
|
|
1611
|
+
--gds-stream-in-rise: 6px;
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
html[data-gds-streaming] body * {
|
|
1615
|
+
transition:
|
|
1616
|
+
opacity var(--gds-stream-in-duration) var(--gds-stream-in-ease),
|
|
1617
|
+
translate var(--gds-stream-in-duration) var(--gds-stream-in-ease);
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
html[data-gds-streaming] body * {
|
|
1621
|
+
@starting-style {
|
|
1622
|
+
opacity: 0;
|
|
1623
|
+
translate: 0 var(--gds-stream-in-rise);
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1628
|
+
html[data-gds-streaming] body * {
|
|
1629
|
+
transition: none;
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
/* ============================================
|
|
1634
|
+
EDIT FLASH — data-gds-flash on changed nodes
|
|
1635
|
+
============================================
|
|
1636
|
+
"Show me what the AI touched": when an edit turn (or any sealed
|
|
1637
|
+
re-render) commits, the Fast Frame sandbox diffs the old and new
|
|
1638
|
+
frames by data-gds-source-id and stamps `data-gds-flash` on the
|
|
1639
|
+
innermost changed nodes. One short pulse — outline ring + a faint
|
|
1640
|
+
primary wash — then the attribute is removed on animationend so the
|
|
1641
|
+
next edit re-triggers cleanly. Tunable via the --gds-edit-flash-*
|
|
1642
|
+
tokens. Honours reduced motion + the manual data-motion="off" toggle
|
|
1643
|
+
(the broad animation reset above zeroes it). */
|
|
1644
|
+
:root {
|
|
1645
|
+
--gds-edit-flash-duration: 900ms;
|
|
1646
|
+
--gds-edit-flash-color: var(--primary);
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
[data-gds-flash] {
|
|
1650
|
+
animation: gds-edit-flash var(--gds-edit-flash-duration) ease-out;
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
@keyframes gds-edit-flash {
|
|
1654
|
+
0% {
|
|
1655
|
+
outline: 2px solid oklch(var(--gds-edit-flash-color) / 0.9);
|
|
1656
|
+
outline-offset: 2px;
|
|
1657
|
+
background-color: oklch(var(--gds-edit-flash-color) / 0.1);
|
|
1658
|
+
}
|
|
1659
|
+
60% {
|
|
1660
|
+
outline: 2px solid oklch(var(--gds-edit-flash-color) / 0.45);
|
|
1661
|
+
outline-offset: 2px;
|
|
1662
|
+
background-color: oklch(var(--gds-edit-flash-color) / 0.04);
|
|
1663
|
+
}
|
|
1664
|
+
100% {
|
|
1665
|
+
outline: 2px solid transparent;
|
|
1666
|
+
outline-offset: 2px;
|
|
1667
|
+
background-color: transparent;
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1672
|
+
[data-gds-flash] {
|
|
1673
|
+
animation: none;
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
/* ============================================
|
|
1678
|
+
TYPOGRAPHY UTILITIES
|
|
1679
|
+
============================================ */
|
|
1680
|
+
|
|
1681
|
+
@layer utilities {
|
|
1682
|
+
/* Display */
|
|
1683
|
+
.text-display {
|
|
1684
|
+
font-size: var(--text-display);
|
|
1685
|
+
line-height: var(--text-display-line);
|
|
1686
|
+
letter-spacing: var(--text-display-tracking);
|
|
1687
|
+
font-weight: 700;
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
/* Headings */
|
|
1691
|
+
.text-h1 {
|
|
1692
|
+
font-size: var(--text-h1);
|
|
1693
|
+
line-height: var(--text-h1-line);
|
|
1694
|
+
letter-spacing: var(--text-h1-tracking);
|
|
1695
|
+
font-weight: 700;
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
.text-h2 {
|
|
1699
|
+
font-size: var(--text-h2);
|
|
1700
|
+
line-height: var(--text-h2-line);
|
|
1701
|
+
letter-spacing: var(--text-h2-tracking);
|
|
1702
|
+
font-weight: 600;
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
.text-h3 {
|
|
1706
|
+
font-size: var(--text-h3);
|
|
1707
|
+
line-height: var(--text-h3-line);
|
|
1708
|
+
letter-spacing: var(--text-h3-tracking);
|
|
1709
|
+
font-weight: 600;
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
.text-h4 {
|
|
1713
|
+
font-size: var(--text-h4);
|
|
1714
|
+
line-height: var(--text-h4-line);
|
|
1715
|
+
letter-spacing: var(--text-h4-tracking);
|
|
1716
|
+
font-weight: 600;
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
.text-h5 {
|
|
1720
|
+
font-size: var(--text-h5);
|
|
1721
|
+
line-height: var(--text-h5-line);
|
|
1722
|
+
letter-spacing: var(--text-h5-tracking);
|
|
1723
|
+
font-weight: 500;
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
.text-h6 {
|
|
1727
|
+
font-size: var(--text-h6);
|
|
1728
|
+
line-height: var(--text-h6-line);
|
|
1729
|
+
letter-spacing: var(--text-h6-tracking);
|
|
1730
|
+
font-weight: 500;
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
/* Body */
|
|
1734
|
+
.text-body-lg {
|
|
1735
|
+
font-size: var(--text-body-lg);
|
|
1736
|
+
line-height: var(--text-body-line);
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
.text-body {
|
|
1740
|
+
font-size: var(--text-body);
|
|
1741
|
+
line-height: var(--text-body-line);
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
.text-body-sm {
|
|
1745
|
+
font-size: var(--text-body-sm);
|
|
1746
|
+
line-height: var(--text-body-line);
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
/* Label */
|
|
1750
|
+
.text-label-lg {
|
|
1751
|
+
font-size: var(--text-label-lg);
|
|
1752
|
+
line-height: var(--text-label-line);
|
|
1753
|
+
letter-spacing: var(--text-label-tracking);
|
|
1754
|
+
font-weight: 500;
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
.text-label {
|
|
1758
|
+
font-size: var(--text-label);
|
|
1759
|
+
line-height: var(--text-label-line);
|
|
1760
|
+
letter-spacing: var(--text-label-tracking);
|
|
1761
|
+
font-weight: 500;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
/* Caption */
|
|
1765
|
+
.text-caption {
|
|
1766
|
+
font-size: var(--text-caption);
|
|
1767
|
+
line-height: var(--text-caption-line);
|
|
1768
|
+
color: oklch(var(--muted-foreground));
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
/* Overline */
|
|
1772
|
+
.text-overline {
|
|
1773
|
+
font-size: var(--text-overline);
|
|
1774
|
+
letter-spacing: var(--text-overline-tracking);
|
|
1775
|
+
text-transform: uppercase;
|
|
1776
|
+
font-weight: 600;
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
/* Code */
|
|
1780
|
+
.text-code {
|
|
1781
|
+
font-family: var(--font-mono);
|
|
1782
|
+
font-size: 0.875em;
|
|
1783
|
+
background-color: oklch(var(--muted));
|
|
1784
|
+
padding: 0.125rem 0.375rem;
|
|
1785
|
+
border-radius: 0.25rem;
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
/* Lead paragraph */
|
|
1789
|
+
.text-lead {
|
|
1790
|
+
font-size: var(--text-body-lg);
|
|
1791
|
+
line-height: var(--text-body-line);
|
|
1792
|
+
color: oklch(var(--muted-foreground));
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
/* Muted text */
|
|
1796
|
+
.text-muted {
|
|
1797
|
+
color: oklch(var(--muted-foreground));
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
/* ============================================
|
|
1802
|
+
ANIMATION UTILITIES
|
|
1803
|
+
============================================ */
|
|
1804
|
+
|
|
1805
|
+
@layer utilities {
|
|
1806
|
+
/* Hide scrollbar */
|
|
1807
|
+
.scrollbar-none {
|
|
1808
|
+
-ms-overflow-style: none; /* IE and Edge */
|
|
1809
|
+
scrollbar-width: none; /* Firefox */
|
|
1810
|
+
}
|
|
1811
|
+
.scrollbar-none::-webkit-scrollbar {
|
|
1812
|
+
display: none; /* Chrome, Safari, Opera */
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
/* Fade animations */
|
|
1816
|
+
.animate-fade-in {
|
|
1817
|
+
animation: fadeIn 0.2s ease-out;
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
.animate-fade-out {
|
|
1821
|
+
animation: fadeOut 0.2s ease-in;
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
/* Scale animations */
|
|
1825
|
+
.animate-scale-in {
|
|
1826
|
+
animation: scaleIn 0.15s ease-out;
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
/* Slide animations */
|
|
1830
|
+
.animate-slide-in-from-top {
|
|
1831
|
+
animation: slideInFromTop 0.2s ease-out;
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
.animate-slide-in-from-bottom {
|
|
1835
|
+
animation: slideInFromBottom 0.2s ease-out;
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
.animate-slide-in-from-left {
|
|
1839
|
+
animation: slideInFromLeft 0.2s ease-out;
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
.animate-slide-in-from-right {
|
|
1843
|
+
animation: slideInFromRight 0.2s ease-out;
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
/* Pulse animation for energy indicators */
|
|
1847
|
+
.animate-energy-pulse {
|
|
1848
|
+
animation: energyPulse 2s ease-in-out infinite;
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
/* Shimmer effect for loading states */
|
|
1852
|
+
.animate-shimmer {
|
|
1853
|
+
animation: shimmer 2s linear infinite;
|
|
1854
|
+
background: linear-gradient(
|
|
1855
|
+
90deg,
|
|
1856
|
+
oklch(var(--muted)) 0%,
|
|
1857
|
+
oklch(var(--muted-foreground) / 0.1) 50%,
|
|
1858
|
+
oklch(var(--muted)) 100%
|
|
1859
|
+
);
|
|
1860
|
+
background-size: 200% 100%;
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
/* Keyframes */
|
|
1865
|
+
@keyframes fadeIn {
|
|
1866
|
+
from { opacity: 0; }
|
|
1867
|
+
to { opacity: 1; }
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
@keyframes fadeOut {
|
|
1871
|
+
from { opacity: 1; }
|
|
1872
|
+
to { opacity: 0; }
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
@keyframes scaleIn {
|
|
1876
|
+
from {
|
|
1877
|
+
opacity: 0;
|
|
1878
|
+
transform: scale(0.95);
|
|
1879
|
+
}
|
|
1880
|
+
to {
|
|
1881
|
+
opacity: 1;
|
|
1882
|
+
transform: scale(1);
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
@keyframes slideInFromTop {
|
|
1887
|
+
from {
|
|
1888
|
+
opacity: 0;
|
|
1889
|
+
transform: translateY(-10px);
|
|
1890
|
+
}
|
|
1891
|
+
to {
|
|
1892
|
+
opacity: 1;
|
|
1893
|
+
transform: translateY(0);
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
@keyframes slideInFromBottom {
|
|
1898
|
+
from {
|
|
1899
|
+
opacity: 0;
|
|
1900
|
+
transform: translateY(10px);
|
|
1901
|
+
}
|
|
1902
|
+
to {
|
|
1903
|
+
opacity: 1;
|
|
1904
|
+
transform: translateY(0);
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
@keyframes slideInFromLeft {
|
|
1909
|
+
from {
|
|
1910
|
+
opacity: 0;
|
|
1911
|
+
transform: translateX(-10px);
|
|
1912
|
+
}
|
|
1913
|
+
to {
|
|
1914
|
+
opacity: 1;
|
|
1915
|
+
transform: translateX(0);
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
@keyframes slideInFromRight {
|
|
1920
|
+
from {
|
|
1921
|
+
opacity: 0;
|
|
1922
|
+
transform: translateX(10px);
|
|
1923
|
+
}
|
|
1924
|
+
to {
|
|
1925
|
+
opacity: 1;
|
|
1926
|
+
transform: translateX(0);
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
@keyframes energyPulse {
|
|
1931
|
+
0%, 100% {
|
|
1932
|
+
opacity: 1;
|
|
1933
|
+
box-shadow: 0 0 0 0 oklch(var(--accent) / 0.4);
|
|
1934
|
+
}
|
|
1935
|
+
50% {
|
|
1936
|
+
opacity: 0.8;
|
|
1937
|
+
box-shadow: 0 0 0 8px oklch(var(--accent) / 0);
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
@keyframes shimmer {
|
|
1942
|
+
0% { background-position: 200% 0; }
|
|
1943
|
+
100% { background-position: -200% 0; }
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
@keyframes pulse-glow {
|
|
1947
|
+
0%, 100% {
|
|
1948
|
+
box-shadow: 0 0 4px 1px oklch(var(--primary) / 0.2);
|
|
1949
|
+
}
|
|
1950
|
+
50% {
|
|
1951
|
+
box-shadow: 0 0 8px 2px oklch(var(--primary) / 0.35);
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
.animate-pulse-glow {
|
|
1956
|
+
animation: pulse-glow 2s ease-in-out infinite;
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
/* CSS Houdini property for animating conic-gradient angle */
|
|
1960
|
+
@property --angle {
|
|
1961
|
+
syntax: '<angle>';
|
|
1962
|
+
initial-value: 0deg;
|
|
1963
|
+
inherits: false;
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
@keyframes rotate-border {
|
|
1967
|
+
0% {
|
|
1968
|
+
--angle: 0deg;
|
|
1969
|
+
}
|
|
1970
|
+
100% {
|
|
1971
|
+
--angle: 360deg;
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
/* Border travel animation for energy flow nodes */
|
|
1976
|
+
.border-travel-animation {
|
|
1977
|
+
position: relative;
|
|
1978
|
+
border: 2px solid transparent;
|
|
1979
|
+
background:
|
|
1980
|
+
linear-gradient(white, white) padding-box,
|
|
1981
|
+
conic-gradient(
|
|
1982
|
+
from var(--angle, 0deg),
|
|
1983
|
+
rgba(34, 197, 94, 0.15) 0deg,
|
|
1984
|
+
rgba(34, 197, 94, 0.15) 350deg,
|
|
1985
|
+
#22c55e 353deg,
|
|
1986
|
+
#16a34a 356deg,
|
|
1987
|
+
#22c55e 359deg,
|
|
1988
|
+
rgba(34, 197, 94, 0.15) 360deg
|
|
1989
|
+
) border-box;
|
|
1990
|
+
animation: rotate-border 3s linear infinite;
|
|
1991
|
+
border-radius: 0.75rem;
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
.border-travel-animation.rounded-full {
|
|
1995
|
+
border-radius: 9999px;
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
.dark .border-travel-animation {
|
|
1999
|
+
background:
|
|
2000
|
+
linear-gradient(#141414, #141414) padding-box,
|
|
2001
|
+
conic-gradient(
|
|
2002
|
+
from var(--angle, 0deg),
|
|
2003
|
+
rgba(34, 197, 94, 0.1) 0deg,
|
|
2004
|
+
rgba(34, 197, 94, 0.1) 350deg,
|
|
2005
|
+
#22c55e 353deg,
|
|
2006
|
+
#16a34a 356deg,
|
|
2007
|
+
#22c55e 359deg,
|
|
2008
|
+
rgba(34, 197, 94, 0.1) 360deg
|
|
2009
|
+
) border-box;
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
/* React Flow controls positioning */
|
|
2013
|
+
.react-flow__controls {
|
|
2014
|
+
bottom: 10px !important;
|
|
2015
|
+
top: auto !important;
|
|
2016
|
+
left: 10px !important;
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
/* React Flow dark mode styles */
|
|
2020
|
+
.dark .react-flow__controls {
|
|
2021
|
+
background: #141414;
|
|
2022
|
+
border: 1px solid #262626;
|
|
2023
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
.dark .react-flow__controls-button {
|
|
2027
|
+
background: #141414;
|
|
2028
|
+
border-bottom: 1px solid #262626;
|
|
2029
|
+
fill: #a3a3a3;
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
.dark .react-flow__controls-button:hover {
|
|
2033
|
+
background: #262626;
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
.dark .react-flow__controls-button svg {
|
|
2037
|
+
fill: #a3a3a3;
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
.dark .react-flow__controls-button:hover svg {
|
|
2041
|
+
fill: #ffffff;
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
/* Dotted background pattern */
|
|
2045
|
+
.bg-dot-pattern {
|
|
2046
|
+
background-image: radial-gradient(circle, rgba(0, 0, 0, 0.08) 1px, transparent 1px);
|
|
2047
|
+
background-size: 24px 24px;
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
.dark .bg-dot-pattern {
|
|
2051
|
+
background-image: radial-gradient(circle, rgba(255, 255, 255, 0.06) 1px, transparent 1px);
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
/* Gradient fade for hero */
|
|
2055
|
+
.hero-gradient {
|
|
2056
|
+
background: linear-gradient(to bottom, transparent 0%, oklch(var(--background)) 70%, oklch(var(--background)) 100%);
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
/* ============================================
|
|
2060
|
+
INFINITE SCROLL ANIMATION (Partner Logos)
|
|
2061
|
+
============================================ */
|
|
2062
|
+
|
|
2063
|
+
@keyframes scrollLeft {
|
|
2064
|
+
0% {
|
|
2065
|
+
transform: translateX(0);
|
|
2066
|
+
}
|
|
2067
|
+
100% {
|
|
2068
|
+
transform: translateX(-50%);
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
@keyframes scrollRight {
|
|
2073
|
+
0% {
|
|
2074
|
+
transform: translateX(-50%);
|
|
2075
|
+
}
|
|
2076
|
+
100% {
|
|
2077
|
+
transform: translateX(0);
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
.animate-scroll-left {
|
|
2082
|
+
animation: scrollLeft linear infinite;
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
.animate-scroll-right {
|
|
2086
|
+
animation: scrollRight linear infinite;
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
/* Pause animation on hover */
|
|
2090
|
+
.animate-scroll-left:hover,
|
|
2091
|
+
.animate-scroll-right:hover {
|
|
2092
|
+
animation-play-state: paused;
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2096
|
+
Selection cards — RadioCard / CheckboxCard / SwitchCard
|
|
2097
|
+
---------------------------------------------------------------------------
|
|
2098
|
+
The whole card is the control, so focus / hover / checked all live on the
|
|
2099
|
+
parent surface. Every visual reads from a `--gds-selection-card-*` token
|
|
2100
|
+
with a semantic fallback, so a project can re-skin the cards via the
|
|
2101
|
+
per-project override layer (set the token at theme scope) without touching
|
|
2102
|
+
the component. Per-instance overrides still flow through `style={{ … }}`.
|
|
2103
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2104
|
+
.gds-selection-card {
|
|
2105
|
+
position: relative;
|
|
2106
|
+
display: flex;
|
|
2107
|
+
align-items: flex-start;
|
|
2108
|
+
gap: var(--gds-selection-card-gap, 0.75rem);
|
|
2109
|
+
width: 100%;
|
|
2110
|
+
text-align: left;
|
|
2111
|
+
cursor: pointer;
|
|
2112
|
+
padding: var(--gds-selection-card-padding, 1rem);
|
|
2113
|
+
border-radius: var(--gds-selection-card-radius, var(--radius));
|
|
2114
|
+
border: var(--gds-selection-card-border-width, 1px) solid
|
|
2115
|
+
oklch(var(--gds-selection-card-border, var(--border)));
|
|
2116
|
+
background: oklch(var(--gds-selection-card-bg, var(--card)));
|
|
2117
|
+
color: oklch(var(--foreground));
|
|
2118
|
+
transition:
|
|
2119
|
+
border-color 150ms ease,
|
|
2120
|
+
background-color 150ms ease,
|
|
2121
|
+
box-shadow 150ms ease;
|
|
2122
|
+
}
|
|
2123
|
+
.gds-selection-card:hover {
|
|
2124
|
+
background: var(--gds-selection-card-hover-bg, oklch(var(--muted) / 0.55));
|
|
2125
|
+
}
|
|
2126
|
+
.gds-selection-card:focus-visible {
|
|
2127
|
+
outline: none;
|
|
2128
|
+
box-shadow:
|
|
2129
|
+
0 0 0 2px oklch(var(--background)),
|
|
2130
|
+
0 0 0 4px oklch(var(--gds-selection-card-ring, var(--ring)) / 0.85);
|
|
2131
|
+
}
|
|
2132
|
+
.gds-selection-card[data-state="checked"] {
|
|
2133
|
+
border-color: oklch(
|
|
2134
|
+
var(--gds-selection-card-selected-border, var(--foreground))
|
|
2135
|
+
);
|
|
2136
|
+
background: var(
|
|
2137
|
+
--gds-selection-card-selected-bg,
|
|
2138
|
+
oklch(var(--muted) / 0.4)
|
|
2139
|
+
);
|
|
2140
|
+
}
|
|
2141
|
+
.gds-selection-card:disabled,
|
|
2142
|
+
.gds-selection-card[data-disabled] {
|
|
2143
|
+
cursor: not-allowed;
|
|
2144
|
+
opacity: 0.5;
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
/* Content blocks */
|
|
2148
|
+
.gds-selection-card__content {
|
|
2149
|
+
display: flex;
|
|
2150
|
+
flex-direction: column;
|
|
2151
|
+
gap: 0.125rem;
|
|
2152
|
+
flex: 1 1 auto;
|
|
2153
|
+
min-width: 0;
|
|
2154
|
+
}
|
|
2155
|
+
.gds-selection-card__slot {
|
|
2156
|
+
flex: 1 1 auto;
|
|
2157
|
+
min-width: 0;
|
|
2158
|
+
}
|
|
2159
|
+
.gds-selection-card__title {
|
|
2160
|
+
font-size: 0.875rem;
|
|
2161
|
+
font-weight: 500;
|
|
2162
|
+
line-height: 1.4;
|
|
2163
|
+
color: oklch(var(--foreground));
|
|
2164
|
+
}
|
|
2165
|
+
.gds-selection-card__desc {
|
|
2166
|
+
font-size: 0.875rem;
|
|
2167
|
+
line-height: 1.4;
|
|
2168
|
+
color: oklch(var(--muted-foreground));
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
/* ── Indicators (the small glyph; differs by control type) ─────────────── */
|
|
2172
|
+
.gds-selection-indicator {
|
|
2173
|
+
display: inline-flex;
|
|
2174
|
+
align-items: center;
|
|
2175
|
+
justify-content: center;
|
|
2176
|
+
flex: none;
|
|
2177
|
+
margin-top: 0.0625rem;
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
/* Radio — empty ring → filled circle with a light inner dot when checked */
|
|
2181
|
+
.gds-selection-indicator--radio {
|
|
2182
|
+
height: 1.25rem;
|
|
2183
|
+
width: 1.25rem;
|
|
2184
|
+
border-radius: 9999px;
|
|
2185
|
+
border: 1.5px solid oklch(var(--gds-selection-card-control, var(--border)));
|
|
2186
|
+
background: oklch(var(--background));
|
|
2187
|
+
transition:
|
|
2188
|
+
border-color 150ms ease,
|
|
2189
|
+
background-color 150ms ease;
|
|
2190
|
+
}
|
|
2191
|
+
.gds-selection-card[data-state="checked"] .gds-selection-indicator--radio {
|
|
2192
|
+
border-color: oklch(var(--gds-selection-card-control-checked, var(--primary)));
|
|
2193
|
+
background: oklch(var(--gds-selection-card-control-checked, var(--primary)));
|
|
2194
|
+
}
|
|
2195
|
+
.gds-selection-indicator__dot {
|
|
2196
|
+
display: block;
|
|
2197
|
+
height: 0.5rem;
|
|
2198
|
+
width: 0.5rem;
|
|
2199
|
+
border-radius: 9999px;
|
|
2200
|
+
background: oklch(var(--background));
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
/* Checkbox — rounded square, check glyph when checked */
|
|
2204
|
+
.gds-selection-indicator--checkbox {
|
|
2205
|
+
height: 1.2rem;
|
|
2206
|
+
width: 1.2rem;
|
|
2207
|
+
border-radius: 0.3rem;
|
|
2208
|
+
border: 1.5px solid oklch(var(--gds-selection-card-control, var(--border)));
|
|
2209
|
+
background: oklch(var(--background));
|
|
2210
|
+
color: oklch(var(--background));
|
|
2211
|
+
transition:
|
|
2212
|
+
border-color 150ms ease,
|
|
2213
|
+
background-color 150ms ease;
|
|
2214
|
+
}
|
|
2215
|
+
.gds-selection-card[data-state="checked"] .gds-selection-indicator--checkbox {
|
|
2216
|
+
border-color: oklch(var(--gds-selection-card-control-checked, var(--primary)));
|
|
2217
|
+
background: oklch(var(--gds-selection-card-control-checked, var(--primary)));
|
|
2218
|
+
}
|
|
2219
|
+
.gds-selection-indicator__check {
|
|
2220
|
+
display: inline-flex;
|
|
2221
|
+
align-items: center;
|
|
2222
|
+
justify-content: center;
|
|
2223
|
+
color: oklch(var(--background));
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
/* Switch — track + thumb that slides on checked */
|
|
2227
|
+
.gds-selection-indicator--switch {
|
|
2228
|
+
height: 1.25rem;
|
|
2229
|
+
width: 2.25rem;
|
|
2230
|
+
padding: 2px;
|
|
2231
|
+
border-radius: 9999px;
|
|
2232
|
+
background: oklch(var(--input));
|
|
2233
|
+
justify-content: flex-start;
|
|
2234
|
+
transition: background-color 150ms ease;
|
|
2235
|
+
}
|
|
2236
|
+
.gds-selection-card[data-state="checked"] .gds-selection-indicator--switch {
|
|
2237
|
+
background: oklch(var(--gds-selection-card-control-checked, var(--primary)));
|
|
2238
|
+
}
|
|
2239
|
+
.gds-selection-indicator__thumb {
|
|
2240
|
+
display: block;
|
|
2241
|
+
height: 1rem;
|
|
2242
|
+
width: 1rem;
|
|
2243
|
+
border-radius: 9999px;
|
|
2244
|
+
background: oklch(var(--background));
|
|
2245
|
+
box-shadow: 0 1px 2px oklch(0 0 0 / 0.25);
|
|
2246
|
+
transition: transform 150ms ease;
|
|
2247
|
+
}
|
|
2248
|
+
.gds-selection-card[data-state="checked"] .gds-selection-indicator__thumb {
|
|
2249
|
+
transform: translateX(1rem);
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2253
|
+
Elevation — real classes (JIT-proof, always in the bundle).
|
|
2254
|
+
---------------------------------------------------------------------------
|
|
2255
|
+
The `shadow-elevation-N` Tailwind utilities (declared in tailwind-preset.ts)
|
|
2256
|
+
only compile when a scanned source file actually uses the class string, so
|
|
2257
|
+
typing `shadow-elevation-3` in Studio output or a consumer screen produced
|
|
2258
|
+
no CSS. These plain classes always exist in the shipped stylesheet, exactly
|
|
2259
|
+
like `.gds-surface-*`, so elevation works everywhere regardless of the JIT
|
|
2260
|
+
content scan. Prefer these for runtime/generated UI; the Tailwind utilities
|
|
2261
|
+
remain available for component-internal use.
|
|
2262
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2263
|
+
.gds-elevation-0 { box-shadow: var(--elevation-0); }
|
|
2264
|
+
.gds-elevation-1 { box-shadow: var(--elevation-1); }
|
|
2265
|
+
.gds-elevation-2 { box-shadow: var(--elevation-2); }
|
|
2266
|
+
.gds-elevation-3 { box-shadow: var(--elevation-3); }
|
|
2267
|
+
.gds-elevation-4 { box-shadow: var(--elevation-4); }
|
|
2268
|
+
.gds-elevation-5 { box-shadow: var(--elevation-5); }
|
|
2269
|
+
.gds-elevation-hot { box-shadow: var(--elevation-hot); }
|
|
2270
|
+
.gds-elevation-pressed { box-shadow: var(--elevation-pressed); }
|
|
2271
|
+
/* Single-layer atoms, for composing a custom stack */
|
|
2272
|
+
.gds-shadow-bevel-hi { box-shadow: var(--shadow-bevel-hi); }
|
|
2273
|
+
.gds-shadow-bevel-lo { box-shadow: var(--shadow-bevel-lo); }
|
|
2274
|
+
.gds-shadow-contact { box-shadow: var(--shadow-contact); }
|
|
2275
|
+
.gds-shadow-lift { box-shadow: var(--shadow-lift); }
|
|
2276
|
+
.gds-shadow-lift-deep { box-shadow: var(--shadow-lift-deep); }
|
|
2277
|
+
.gds-shadow-heat-inner { box-shadow: var(--shadow-heat-inner); }
|
|
2278
|
+
.gds-shadow-heat-outer { box-shadow: var(--shadow-heat-outer); }
|