@nextlyhq/ui 0.0.2-alpha.5 → 0.0.2-alpha.50
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 +98 -23
- package/dist/index.cjs +1118 -1096
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +98 -265
- package/dist/index.d.ts +98 -265
- package/dist/index.mjs +878 -838
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +2 -0
- package/dist/styles.scoped.css +2 -0
- package/dist/tailwind-preset.cjs +98 -0
- package/dist/tailwind-preset.cjs.map +1 -0
- package/dist/tailwind-preset.d.cts +80 -0
- package/dist/tailwind-preset.d.ts +80 -0
- package/dist/tailwind-preset.mjs +93 -0
- package/dist/tailwind-preset.mjs.map +1 -0
- package/dist/theme.css +997 -0
- package/dist/utils.cjs +13 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.cts +17 -0
- package/dist/utils.d.ts +17 -0
- package/dist/utils.mjs +11 -0
- package/dist/utils.mjs.map +1 -0
- package/docs/plugin-ui-authoring.md +228 -0
- package/package.json +56 -15
package/dist/theme.css
ADDED
|
@@ -0,0 +1,997 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nextly design-system theme.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for tokens, the Tailwind `@theme inline` mappings, the
|
|
5
|
+
* dark variant, and the animation keyframes. It does NOT include a base reset —
|
|
6
|
+
* that lives in `index.css` and ships in the pre-compiled `styles.css` bundle.
|
|
7
|
+
* Consumed two ways:
|
|
8
|
+
* - Source: `@import "@nextlyhq/ui/theme.css"` after `@import "tailwindcss"`
|
|
9
|
+
* to compile against the token contract (admin, power-user plugins).
|
|
10
|
+
* - Pre-compiled: `@nextlyhq/ui/styles.css` bundles this behind a Tailwind
|
|
11
|
+
* build so plugins get styled components with zero setup.
|
|
12
|
+
*
|
|
13
|
+
* Selectors are unscoped (`:root` / `.dark`); a consumer that embeds the UI in a
|
|
14
|
+
* host page scopes them at build time (admin rewrites to `.nextly-admin`).
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Activate `dark:` utilities from the `.dark` class rather than the OS
|
|
19
|
+
* `prefers-color-scheme`, so an explicit light choice wins over system dark.
|
|
20
|
+
*/
|
|
21
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
22
|
+
|
|
23
|
+
@theme inline {
|
|
24
|
+
/* ============================================
|
|
25
|
+
* ANIMATIONS (Tailwind v4.1)
|
|
26
|
+
* ============================================ */
|
|
27
|
+
--animate-accordion-down: accordion-down 0.3s cubic-bezier(0.87, 0, 0.13, 1);
|
|
28
|
+
--animate-accordion-up: accordion-up 0.3s cubic-bezier(0.87, 0, 0.13, 1);
|
|
29
|
+
--animate-fade-in: fade-in 0.2s ease-out;
|
|
30
|
+
--animate-fade-out: fade-out 0.2s ease-in;
|
|
31
|
+
--animate-zoom-in-95: zoom-in-95 0.1s ease-out;
|
|
32
|
+
--animate-zoom-out-95: zoom-out-95 0.1s ease-in;
|
|
33
|
+
--animate-slide-in-from-top-2: slide-in-from-top-2 0.2s ease-out;
|
|
34
|
+
--animate-slide-in-from-bottom-2: slide-in-from-bottom-2 0.2s ease-out;
|
|
35
|
+
--animate-slide-in-from-left-2: slide-in-from-left-2 0.2s ease-out;
|
|
36
|
+
--animate-slide-in-from-right-2: slide-in-from-right-2 0.2s ease-out;
|
|
37
|
+
--animate-brand-orbit: brand-orbit 2.4s linear infinite;
|
|
38
|
+
--animate-brand-pulse: brand-pulse 2s cubic-bezier(0.2, 0.8, 0.2, 1) infinite;
|
|
39
|
+
|
|
40
|
+
/* ============================================
|
|
41
|
+
* COLOR PALETTE (Tailwind v4.1)
|
|
42
|
+
* Monochrome design system, WCAG 2.2 AA compliant.
|
|
43
|
+
*
|
|
44
|
+
* Color Format Strategy:
|
|
45
|
+
* - Reference scales (blue/slate/etc.): HEX, kept for utility classes.
|
|
46
|
+
* - Semantic tokens: OKLCH full-color values defined in `:root` / `.dark`,
|
|
47
|
+
* mapped here via `@theme inline` with bare `var()` so scoped/dark
|
|
48
|
+
* overrides resolve at the consuming element.
|
|
49
|
+
* ============================================ */
|
|
50
|
+
|
|
51
|
+
/* Blue Scale - Primary Brand Color */
|
|
52
|
+
--color-blue-50: #eff6ff;
|
|
53
|
+
--color-blue-100: #dbeafe;
|
|
54
|
+
--color-blue-200: #bfdbfe;
|
|
55
|
+
--color-blue-300: #93c5fd;
|
|
56
|
+
--color-blue-400: #60a5fa;
|
|
57
|
+
--color-blue-500: #3b82f6;
|
|
58
|
+
--color-blue-600: #2563eb;
|
|
59
|
+
--color-blue-700: #1d4ed8;
|
|
60
|
+
--color-blue-800: #1e40af;
|
|
61
|
+
--color-blue-900: #1e3a8a;
|
|
62
|
+
--color-blue-950: #172554;
|
|
63
|
+
|
|
64
|
+
/* Cyan Scale - Accent Color */
|
|
65
|
+
--color-cyan-50: #ecfeff;
|
|
66
|
+
--color-cyan-100: #cffafe;
|
|
67
|
+
--color-cyan-200: #a5f3fc;
|
|
68
|
+
--color-cyan-300: #67e8f9;
|
|
69
|
+
--color-cyan-400: #22d3ee;
|
|
70
|
+
--color-cyan-500: #06b6d4;
|
|
71
|
+
--color-cyan-600: #0891b2;
|
|
72
|
+
--color-cyan-700: #0e7490;
|
|
73
|
+
--color-cyan-800: #155e75;
|
|
74
|
+
--color-cyan-900: #164e63;
|
|
75
|
+
--color-cyan-950: #083344;
|
|
76
|
+
|
|
77
|
+
/* Green Scale - Success Color */
|
|
78
|
+
--color-green-50: #f0fdf4;
|
|
79
|
+
--color-green-100: #dcfce7;
|
|
80
|
+
--color-green-200: #bbf7d0;
|
|
81
|
+
--color-green-300: #86efac;
|
|
82
|
+
--color-green-400: #4ade80;
|
|
83
|
+
--color-green-500: #22c55e;
|
|
84
|
+
--color-green-600: #16a34a;
|
|
85
|
+
--color-green-700: #15803d;
|
|
86
|
+
--color-green-800: #166534;
|
|
87
|
+
--color-green-900: #14532d;
|
|
88
|
+
--color-green-950: #052e16;
|
|
89
|
+
|
|
90
|
+
/* Amber Scale - Warning Color */
|
|
91
|
+
--color-amber-50: #fffbeb;
|
|
92
|
+
--color-amber-100: #fef3c7;
|
|
93
|
+
--color-amber-200: #fde68a;
|
|
94
|
+
--color-amber-300: #fcd34d;
|
|
95
|
+
--color-amber-400: #fbbf24;
|
|
96
|
+
--color-amber-500: #f59e0b;
|
|
97
|
+
--color-amber-600: #d97706;
|
|
98
|
+
--color-amber-700: #b45309;
|
|
99
|
+
--color-amber-800: #92400e;
|
|
100
|
+
--color-amber-900: #78350f;
|
|
101
|
+
--color-amber-950: #451a03;
|
|
102
|
+
|
|
103
|
+
/* Red Scale - Error/Destructive Color */
|
|
104
|
+
--color-red-50: #fef2f2;
|
|
105
|
+
--color-red-100: #fee2e2;
|
|
106
|
+
--color-red-200: #fecaca;
|
|
107
|
+
--color-red-300: #fca5a5;
|
|
108
|
+
--color-red-400: #f87171;
|
|
109
|
+
--color-red-500: #ef4444;
|
|
110
|
+
--color-red-600: #dc2626;
|
|
111
|
+
--color-red-700: #b91c1c;
|
|
112
|
+
--color-red-800: #991b1b;
|
|
113
|
+
--color-red-900: #7f1d1d;
|
|
114
|
+
--color-red-950: #450a0a;
|
|
115
|
+
|
|
116
|
+
/* Slate Scale - Neutral Colors */
|
|
117
|
+
--color-slate-50: #f8fafc;
|
|
118
|
+
--color-slate-100: #f1f5f9;
|
|
119
|
+
--color-slate-200: #e2e8f0;
|
|
120
|
+
--color-slate-300: #cbd5e1;
|
|
121
|
+
--color-slate-400: #94a3b8;
|
|
122
|
+
--color-slate-500: #64748b;
|
|
123
|
+
--color-slate-600: #475569;
|
|
124
|
+
--color-slate-700: #334155;
|
|
125
|
+
--color-slate-800: #1e293b;
|
|
126
|
+
--color-slate-900: #0f172a;
|
|
127
|
+
--color-slate-950: #020617;
|
|
128
|
+
|
|
129
|
+
/* ============================================
|
|
130
|
+
* SEMANTIC COLOR TOKENS (Tailwind v4.1)
|
|
131
|
+
* Reference color scales defined above
|
|
132
|
+
* ============================================ */
|
|
133
|
+
|
|
134
|
+
/* shadcn/ui semantic colors - reference CSS variables defined below */
|
|
135
|
+
--color-border: var(--nx-border);
|
|
136
|
+
--color-border-subtle: var(--nx-border-subtle);
|
|
137
|
+
--color-border-strong: var(--nx-border-strong);
|
|
138
|
+
--color-input: var(--nx-input);
|
|
139
|
+
--color-ring: var(--nx-ring);
|
|
140
|
+
--color-background: var(--nx-background);
|
|
141
|
+
--color-foreground: var(--nx-foreground);
|
|
142
|
+
|
|
143
|
+
--color-primary: var(--nx-primary);
|
|
144
|
+
--color-primary-50: color-mix(in srgb, var(--nx-primary), white 95%);
|
|
145
|
+
--color-primary-100: color-mix(in srgb, var(--nx-primary), white 90%);
|
|
146
|
+
--color-primary-200: color-mix(in srgb, var(--nx-primary), white 70%);
|
|
147
|
+
--color-primary-300: color-mix(in srgb, var(--nx-primary), white 50%);
|
|
148
|
+
--color-primary-400: color-mix(in srgb, var(--nx-primary), white 30%);
|
|
149
|
+
--color-primary-500: var(--nx-primary);
|
|
150
|
+
--color-primary-600: color-mix(in srgb, var(--nx-primary), black 10%);
|
|
151
|
+
--color-primary-700: color-mix(in srgb, var(--nx-primary), black 30%);
|
|
152
|
+
--color-primary-800: color-mix(in srgb, var(--nx-primary), black 50%);
|
|
153
|
+
--color-primary-900: color-mix(in srgb, var(--nx-primary), black 70%);
|
|
154
|
+
--color-primary-950: color-mix(in srgb, var(--nx-primary), black 85%);
|
|
155
|
+
--color-primary-foreground: var(--nx-primary-foreground);
|
|
156
|
+
|
|
157
|
+
--color-secondary: var(--nx-secondary);
|
|
158
|
+
--color-secondary-foreground: var(--nx-secondary-foreground);
|
|
159
|
+
|
|
160
|
+
/* Status scales, derived the same way as the primary scale above.
|
|
161
|
+
*
|
|
162
|
+
* A status role is one token; the scale is mixed from it, so retheming
|
|
163
|
+
* `--nx-success` moves every shade with it and they cannot drift apart. The
|
|
164
|
+
* shades exist because a status needs more than its solid colour: a tinted
|
|
165
|
+
* surface, a border on that surface, and text dark enough to read on it.
|
|
166
|
+
* Mixing toward white and black keeps 50 pale and 900 deep in both modes,
|
|
167
|
+
* which is what a `dark:` pair at the call site already assumes. */
|
|
168
|
+
--color-destructive: var(--nx-destructive);
|
|
169
|
+
--color-destructive-50: color-mix(in srgb, var(--nx-destructive), white 95%);
|
|
170
|
+
--color-destructive-100: color-mix(in srgb, var(--nx-destructive), white 90%);
|
|
171
|
+
--color-destructive-200: color-mix(in srgb, var(--nx-destructive), white 70%);
|
|
172
|
+
--color-destructive-300: color-mix(in srgb, var(--nx-destructive), white 50%);
|
|
173
|
+
--color-destructive-400: color-mix(in srgb, var(--nx-destructive), white 30%);
|
|
174
|
+
--color-destructive-500: var(--nx-destructive);
|
|
175
|
+
--color-destructive-600: color-mix(in srgb, var(--nx-destructive), black 10%);
|
|
176
|
+
--color-destructive-700: color-mix(in srgb, var(--nx-destructive), black 30%);
|
|
177
|
+
--color-destructive-800: color-mix(in srgb, var(--nx-destructive), black 50%);
|
|
178
|
+
--color-destructive-900: color-mix(in srgb, var(--nx-destructive), black 70%);
|
|
179
|
+
--color-destructive-950: color-mix(in srgb, var(--nx-destructive), black 85%);
|
|
180
|
+
/* Saturated fill for solid buttons; distinct from the text-tuned base so
|
|
181
|
+
* white on-color text stays AA in both modes. */
|
|
182
|
+
--color-destructive-solid: var(--nx-destructive-solid);
|
|
183
|
+
--color-destructive-foreground: var(--nx-destructive-foreground);
|
|
184
|
+
|
|
185
|
+
--color-success: var(--nx-success);
|
|
186
|
+
--color-success-50: color-mix(in srgb, var(--nx-success), white 95%);
|
|
187
|
+
--color-success-100: color-mix(in srgb, var(--nx-success), white 90%);
|
|
188
|
+
--color-success-200: color-mix(in srgb, var(--nx-success), white 70%);
|
|
189
|
+
--color-success-300: color-mix(in srgb, var(--nx-success), white 50%);
|
|
190
|
+
--color-success-400: color-mix(in srgb, var(--nx-success), white 30%);
|
|
191
|
+
--color-success-500: var(--nx-success);
|
|
192
|
+
--color-success-600: color-mix(in srgb, var(--nx-success), black 10%);
|
|
193
|
+
--color-success-700: color-mix(in srgb, var(--nx-success), black 30%);
|
|
194
|
+
--color-success-800: color-mix(in srgb, var(--nx-success), black 50%);
|
|
195
|
+
--color-success-900: color-mix(in srgb, var(--nx-success), black 70%);
|
|
196
|
+
--color-success-950: color-mix(in srgb, var(--nx-success), black 85%);
|
|
197
|
+
/* Saturated fill for solid usage; distinct from the text-tuned base. */
|
|
198
|
+
--color-success-solid: var(--nx-success-solid);
|
|
199
|
+
--color-success-foreground: var(--nx-success-foreground);
|
|
200
|
+
|
|
201
|
+
--color-warning: var(--nx-warning);
|
|
202
|
+
--color-warning-50: color-mix(in srgb, var(--nx-warning), white 95%);
|
|
203
|
+
--color-warning-100: color-mix(in srgb, var(--nx-warning), white 90%);
|
|
204
|
+
--color-warning-200: color-mix(in srgb, var(--nx-warning), white 70%);
|
|
205
|
+
--color-warning-300: color-mix(in srgb, var(--nx-warning), white 50%);
|
|
206
|
+
--color-warning-400: color-mix(in srgb, var(--nx-warning), white 30%);
|
|
207
|
+
--color-warning-500: var(--nx-warning);
|
|
208
|
+
--color-warning-600: color-mix(in srgb, var(--nx-warning), black 10%);
|
|
209
|
+
--color-warning-700: color-mix(in srgb, var(--nx-warning), black 30%);
|
|
210
|
+
--color-warning-800: color-mix(in srgb, var(--nx-warning), black 50%);
|
|
211
|
+
--color-warning-900: color-mix(in srgb, var(--nx-warning), black 70%);
|
|
212
|
+
--color-warning-950: color-mix(in srgb, var(--nx-warning), black 85%);
|
|
213
|
+
--color-warning-foreground: var(--nx-warning-foreground);
|
|
214
|
+
|
|
215
|
+
/* The editor's highlight mark. A token rather than a literal because it
|
|
216
|
+
* styles authored content, which an integrator restyles to their own site
|
|
217
|
+
* and which has to stay readable on a dark page. */
|
|
218
|
+
--color-highlight: var(--nx-highlight);
|
|
219
|
+
--color-highlight-foreground: var(--nx-highlight-foreground);
|
|
220
|
+
|
|
221
|
+
/* Syntax colors, so code tokens are styled the same way as everything else
|
|
222
|
+
* (text-code-keyword, bg-code-bg) instead of through bespoke CSS. */
|
|
223
|
+
--color-code-bg: var(--nx-code-bg);
|
|
224
|
+
--color-code-fg: var(--nx-code-fg);
|
|
225
|
+
--color-code-comment: var(--nx-code-comment);
|
|
226
|
+
--color-code-keyword: var(--nx-code-keyword);
|
|
227
|
+
--color-code-string: var(--nx-code-string);
|
|
228
|
+
--color-code-number: var(--nx-code-number);
|
|
229
|
+
--color-code-function: var(--nx-code-function);
|
|
230
|
+
--color-code-operator: var(--nx-code-operator);
|
|
231
|
+
--color-code-punctuation: var(--nx-code-punctuation);
|
|
232
|
+
--color-code-variable: var(--nx-code-variable);
|
|
233
|
+
--color-code-tag: var(--nx-code-tag);
|
|
234
|
+
--color-code-deleted: var(--nx-code-deleted);
|
|
235
|
+
--color-code-inserted: var(--nx-code-inserted);
|
|
236
|
+
|
|
237
|
+
--color-muted: var(--nx-muted);
|
|
238
|
+
--color-muted-foreground: var(--nx-muted-foreground);
|
|
239
|
+
|
|
240
|
+
--color-accent: var(--nx-accent);
|
|
241
|
+
--color-accent-50: color-mix(in srgb, var(--nx-accent), white 95%);
|
|
242
|
+
--color-accent-100: color-mix(in srgb, var(--nx-accent), white 90%);
|
|
243
|
+
--color-accent-200: color-mix(in srgb, var(--nx-accent), white 70%);
|
|
244
|
+
--color-accent-300: color-mix(in srgb, var(--nx-accent), white 50%);
|
|
245
|
+
--color-accent-400: color-mix(in srgb, var(--nx-accent), white 30%);
|
|
246
|
+
--color-accent-500: var(--nx-accent);
|
|
247
|
+
--color-accent-600: color-mix(in srgb, var(--nx-accent), black 10%);
|
|
248
|
+
--color-accent-700: color-mix(in srgb, var(--nx-accent), black 30%);
|
|
249
|
+
--color-accent-800: color-mix(in srgb, var(--nx-accent), black 50%);
|
|
250
|
+
--color-accent-900: color-mix(in srgb, var(--nx-accent), black 70%);
|
|
251
|
+
--color-accent-950: color-mix(in srgb, var(--nx-accent), black 85%);
|
|
252
|
+
--color-accent-foreground: var(--nx-accent-foreground);
|
|
253
|
+
|
|
254
|
+
--color-card: var(--nx-card);
|
|
255
|
+
--color-card-foreground: var(--nx-card-foreground);
|
|
256
|
+
|
|
257
|
+
--color-popover: var(--nx-popover);
|
|
258
|
+
--color-popover-foreground: var(--nx-popover-foreground);
|
|
259
|
+
|
|
260
|
+
/* Sidebar semantic tokens */
|
|
261
|
+
--color-sidebar: var(--nx-sidebar-background);
|
|
262
|
+
--color-sidebar-background: var(--nx-sidebar-background);
|
|
263
|
+
--color-sidebar-foreground: var(--nx-sidebar-foreground);
|
|
264
|
+
--color-sidebar-primary: var(--nx-sidebar-primary);
|
|
265
|
+
--color-sidebar-primary-foreground: var(--nx-sidebar-primary-foreground);
|
|
266
|
+
--color-sidebar-accent: var(--nx-sidebar-accent);
|
|
267
|
+
--color-sidebar-accent-background: var(--nx-sidebar-accent);
|
|
268
|
+
--color-sidebar-accent-foreground: var(--nx-sidebar-accent-foreground);
|
|
269
|
+
--color-sidebar-border: var(--nx-sidebar-border);
|
|
270
|
+
--color-sidebar-ring: var(--nx-sidebar-ring);
|
|
271
|
+
|
|
272
|
+
/* ============================================
|
|
273
|
+
* TYPOGRAPHY (Tailwind v4.1)
|
|
274
|
+
* Perfect Fourth Scale (1.333 ratio) - WCAG 2.2 AA Compliant
|
|
275
|
+
* ============================================ */
|
|
276
|
+
|
|
277
|
+
/* Font Families live in the non-inline @theme block below. */
|
|
278
|
+
|
|
279
|
+
/* Type Scale - Base Size: 16px (1rem) */
|
|
280
|
+
--text-xs: 0.75rem;
|
|
281
|
+
/* 12px */
|
|
282
|
+
--text-sm: 0.875rem;
|
|
283
|
+
/* 14px */
|
|
284
|
+
--text-base: 1rem;
|
|
285
|
+
/* 16px - body text (WCAG minimum) */
|
|
286
|
+
--text-lg: 1.125rem;
|
|
287
|
+
/* 18px */
|
|
288
|
+
--text-xl: 1.25rem;
|
|
289
|
+
/* 20px */
|
|
290
|
+
--text-2xl: 1.5rem;
|
|
291
|
+
/* 24px */
|
|
292
|
+
--text-3xl: 1.875rem;
|
|
293
|
+
/* 30px */
|
|
294
|
+
--text-4xl: 2.25rem;
|
|
295
|
+
/* 36px */
|
|
296
|
+
--text-5xl: 3rem;
|
|
297
|
+
/* 48px */
|
|
298
|
+
--text-6xl: 3.75rem;
|
|
299
|
+
/* 60px */
|
|
300
|
+
|
|
301
|
+
/* Line Heights (Leading) */
|
|
302
|
+
--leading-none: 1;
|
|
303
|
+
/* Large display text */
|
|
304
|
+
--leading-tight: 1.25;
|
|
305
|
+
/* Headings */
|
|
306
|
+
--leading-snug: 1.375;
|
|
307
|
+
/* Tight UI elements */
|
|
308
|
+
--leading-normal: 1.5;
|
|
309
|
+
/* Default for UI text */
|
|
310
|
+
--leading-relaxed: 1.625;
|
|
311
|
+
/* Long-form content */
|
|
312
|
+
--leading-loose: 2;
|
|
313
|
+
/* Very spacious text */
|
|
314
|
+
|
|
315
|
+
/* Letter Spacing (Tracking) */
|
|
316
|
+
--tracking-tighter: -0.05em;
|
|
317
|
+
/* -0.8px at 16px */
|
|
318
|
+
--tracking-tight: -0.025em;
|
|
319
|
+
/* -0.4px at 16px - for large headings */
|
|
320
|
+
--tracking-normal: 0em;
|
|
321
|
+
/* Default */
|
|
322
|
+
--tracking-wide: 0.025em;
|
|
323
|
+
/* +0.4px at 16px - for small text */
|
|
324
|
+
--tracking-wider: 0.05em;
|
|
325
|
+
/* +0.8px at 16px - for uppercase */
|
|
326
|
+
--tracking-widest: 0.1em;
|
|
327
|
+
/* +1.6px at 16px */
|
|
328
|
+
|
|
329
|
+
/* ============================================
|
|
330
|
+
* SPACING & LAYOUT (Tailwind v4.1)
|
|
331
|
+
* 8px Grid System - Industry Standard
|
|
332
|
+
* ============================================ */
|
|
333
|
+
|
|
334
|
+
/* Spacing Scale (8px base unit) */
|
|
335
|
+
--space-0: 0rem;
|
|
336
|
+
/* 0px */
|
|
337
|
+
--space-px: 0.0625rem;
|
|
338
|
+
/* 1px - for fine borders */
|
|
339
|
+
--space-0-5: 0.125rem;
|
|
340
|
+
/* 2px */
|
|
341
|
+
--space-1: 0.25rem;
|
|
342
|
+
/* 4px - icon padding, tiny gaps */
|
|
343
|
+
--space-1-5: 0.375rem;
|
|
344
|
+
/* 6px */
|
|
345
|
+
--space-2: 0.5rem;
|
|
346
|
+
/* 8px - tight spacing, inline elements */
|
|
347
|
+
--space-2-5: 0.625rem;
|
|
348
|
+
/* 10px */
|
|
349
|
+
--space-3: 0.75rem;
|
|
350
|
+
/* 12px - between related elements */
|
|
351
|
+
--space-3-5: 0.875rem;
|
|
352
|
+
/* 14px */
|
|
353
|
+
--space-4: 1rem;
|
|
354
|
+
/* 16px - standard element spacing */
|
|
355
|
+
--space-5: 1.25rem;
|
|
356
|
+
/* 20px */
|
|
357
|
+
--space-6: 1.5rem;
|
|
358
|
+
/* 24px - between form fields */
|
|
359
|
+
--space-7: 1.75rem;
|
|
360
|
+
/* 28px */
|
|
361
|
+
--space-8: 2rem;
|
|
362
|
+
/* 32px - between sections */
|
|
363
|
+
--space-9: 2.25rem;
|
|
364
|
+
/* 36px */
|
|
365
|
+
--space-10: 2.5rem;
|
|
366
|
+
/* 40px */
|
|
367
|
+
--space-11: 2.75rem;
|
|
368
|
+
/* 44px - minimum touch target */
|
|
369
|
+
--space-12: 3rem;
|
|
370
|
+
/* 48px - between major sections */
|
|
371
|
+
--space-14: 3.5rem;
|
|
372
|
+
/* 56px */
|
|
373
|
+
--space-16: 4rem;
|
|
374
|
+
/* 64px - page margins */
|
|
375
|
+
--space-20: 5rem;
|
|
376
|
+
/* 80px */
|
|
377
|
+
--space-24: 6rem;
|
|
378
|
+
/* 96px - large section breaks */
|
|
379
|
+
|
|
380
|
+
/* ============================================
|
|
381
|
+
* BORDER RADIUS (Tailwind v4.1)
|
|
382
|
+
*
|
|
383
|
+
* The contract is three steps — sm, md, lg — all derived from the single
|
|
384
|
+
* --radius knob (shadcn pattern), so the whole admin re-rounds from one
|
|
385
|
+
* declaration. Those three are also exactly what `tailwind-preset.ts` exports,
|
|
386
|
+
* so a plugin built against the published preset gets the same scale.
|
|
387
|
+
*
|
|
388
|
+
* That only holds if components pick a TIER BY ELEMENT CATEGORY instead of
|
|
389
|
+
* naming a length. A component that hardcodes a corner value — `rounded-none`
|
|
390
|
+
* as much as `rounded-[6px]` — pins itself at that value and silently opts
|
|
391
|
+
* out of the knob. The tiers, and what the shipped components put in each:
|
|
392
|
+
*
|
|
393
|
+
* rounded-lg (--radius-lg, the knob itself)
|
|
394
|
+
* Floating and grouping containers: cards, dialogs, alert dialogs,
|
|
395
|
+
* popovers, tooltips, dropdown / select / command panels, empty-state
|
|
396
|
+
* panels.
|
|
397
|
+
*
|
|
398
|
+
* rounded-md (--radius-md, one step tighter)
|
|
399
|
+
* Controls and the inline surfaces that sit among them: buttons, inputs,
|
|
400
|
+
* textareas, select triggers, icon buttons, alerts, table wrappers and
|
|
401
|
+
* image frames. A control nested in a container reads as inset when its
|
|
402
|
+
* corner is tighter than the surface holding it.
|
|
403
|
+
*
|
|
404
|
+
* rounded-sm (--radius-sm, tighter again)
|
|
405
|
+
* Small controls and adornments: menu and list items, badges, chips,
|
|
406
|
+
* tags, checkboxes, toolbar affordances — anything already inside a
|
|
407
|
+
* control or a dense row.
|
|
408
|
+
*
|
|
409
|
+
* Circles sit deliberately outside the scale: avatars, status dots, spinners,
|
|
410
|
+
* progress tracks and switch tracks and thumbs use `rounded-full`, which is
|
|
411
|
+
* 9999px and not a --radius step. They are round because of their shape, not
|
|
412
|
+
* because of the theme, so a retheme must not flatten them.
|
|
413
|
+
*
|
|
414
|
+
* rounded-xl / rounded-2xl are NOT tiers of this knob. `tailwind-preset.ts`
|
|
415
|
+
* exports only lg/md/sm, so a plugin using the preset gets Tailwind's fixed
|
|
416
|
+
* 0.75rem / 1rem for them, detached from --radius; and the definitions below
|
|
417
|
+
* add to the knob rather than subtracting, so at the shipped --radius: 0 they
|
|
418
|
+
* resolve to 4px and 8px — visibly round inside a square admin. Nothing in the
|
|
419
|
+
* repo uses them. Treat them as off-contract and pick from sm/md/lg.
|
|
420
|
+
*
|
|
421
|
+
* What --radius: 0 really does: `lg` is 0, and `sm` and `md` compute to -4px
|
|
422
|
+
* and -2px. They render square only because border-radius clamps a negative
|
|
423
|
+
* length to 0 at used-value time. The token itself stays negative, so reading
|
|
424
|
+
* `--radius-sm` for padding, an inset, or through getComputedStyle yields
|
|
425
|
+
* -4px, not 0. Anything that consumes a step as a length rather than as a
|
|
426
|
+
* corner must clamp it itself.
|
|
427
|
+
*
|
|
428
|
+
* A site that genuinely must stay square keeps `rounded-none` WITH an inline
|
|
429
|
+
* comment saying why — overlapped-border strips, full-bleed fills inside an
|
|
430
|
+
* already-rounded parent, underline tabs (which is why Tabs is square, not a
|
|
431
|
+
* `rounded-sm` adornment). Square with a stated reason is a decision; square
|
|
432
|
+
* without one is an element that was never wired to the knob. Sheet is the
|
|
433
|
+
* standing example of the latter: it is anchored to the viewport edge and
|
|
434
|
+
* carries no radius class at all.
|
|
435
|
+
*
|
|
436
|
+
* Corollary for containers: a rounded box whose child paints a background to
|
|
437
|
+
* its edge must either clip that child (`overflow-hidden`) or give the child
|
|
438
|
+
* a matching corner (`rounded-b-[inherit]` and friends). Otherwise the child's
|
|
439
|
+
* fill paints square across the parent's curve at any nonzero --radius.
|
|
440
|
+
* ============================================ */
|
|
441
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
442
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
443
|
+
--radius-lg: var(--radius);
|
|
444
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
445
|
+
--radius-2xl: calc(var(--radius) + 8px);
|
|
446
|
+
|
|
447
|
+
/* ============================================
|
|
448
|
+
* BOX SHADOWS (Tailwind v4.1)
|
|
449
|
+
* The ramp's colour comes from --nx-shadow-color, mixed down to each step's
|
|
450
|
+
* alpha. `@theme inline` copies a declaration's value into the generated
|
|
451
|
+
* utility, so a literal rgba() would be frozen at build time while this
|
|
452
|
+
* var() stays live and re-resolves per mode / per scope at the element.
|
|
453
|
+
* ============================================ */
|
|
454
|
+
--shadow-sm: 0 1px 2px 0
|
|
455
|
+
color-mix(in srgb, var(--nx-shadow-color) 5%, transparent);
|
|
456
|
+
--shadow-md:
|
|
457
|
+
0 4px 6px -1px color-mix(in srgb, var(--nx-shadow-color) 10%, transparent),
|
|
458
|
+
0 2px 4px -1px color-mix(in srgb, var(--nx-shadow-color) 6%, transparent);
|
|
459
|
+
--shadow-lg:
|
|
460
|
+
0 10px 15px -3px color-mix(in srgb, var(--nx-shadow-color) 10%, transparent),
|
|
461
|
+
0 4px 6px -2px color-mix(in srgb, var(--nx-shadow-color) 5%, transparent);
|
|
462
|
+
--shadow-xl:
|
|
463
|
+
0 20px 25px -5px color-mix(in srgb, var(--nx-shadow-color) 10%, transparent),
|
|
464
|
+
0 10px 10px -5px color-mix(in srgb, var(--nx-shadow-color) 4%, transparent);
|
|
465
|
+
|
|
466
|
+
/* Custom Functional Shadows (Fixes build warnings from arbitrary values) */
|
|
467
|
+
--shadow-inner-subtle: 0 -4px 6px -1px
|
|
468
|
+
color-mix(in srgb, var(--nx-shadow-color) 5%, transparent);
|
|
469
|
+
--shadow-glow-success: 0 0 10px
|
|
470
|
+
color-mix(in srgb, var(--nx-success) 10%, transparent);
|
|
471
|
+
--shadow-glow-primary: 0 0 15px
|
|
472
|
+
color-mix(in srgb, var(--nx-primary) 50%, transparent);
|
|
473
|
+
--shadow-elevation-primary: 0 8px 20px -8px
|
|
474
|
+
color-mix(in srgb, var(--nx-primary) 40%, transparent);
|
|
475
|
+
--shadow-soft-primary: 0 8px 30px
|
|
476
|
+
color-mix(in srgb, var(--nx-primary) 6%, transparent);
|
|
477
|
+
--shadow-neo: 4px 4px 0px 0px
|
|
478
|
+
color-mix(in srgb, var(--nx-shadow-color) 10%, transparent);
|
|
479
|
+
|
|
480
|
+
/* ============================================
|
|
481
|
+
* FLUID TYPOGRAPHY (Tailwind v4.1)
|
|
482
|
+
* Fixes build warnings from arbitrary values
|
|
483
|
+
* ============================================ */
|
|
484
|
+
--text-fluid-2xs: clamp(0.6rem, 0.55rem + 0.1vw, 0.65rem);
|
|
485
|
+
--text-fluid-xs: clamp(0.65rem, 0.6rem + 0.1vw, 0.7rem);
|
|
486
|
+
--text-fluid-sm: clamp(0.7rem, 0.65rem + 0.1vw, 0.75rem);
|
|
487
|
+
--text-fluid-base: clamp(0.875rem, 0.8rem + 0.2vw, 1rem);
|
|
488
|
+
--text-fluid-lg: clamp(1rem, 2vw, 1.125rem);
|
|
489
|
+
--text-fluid-xl: clamp(1.25rem, 3vw, 1.5rem);
|
|
490
|
+
--text-fluid-2xl: clamp(1.5rem, 5vw, 2.25rem);
|
|
491
|
+
--text-fluid-3xl: clamp(1.5rem, 5vw, 2.5rem);
|
|
492
|
+
--text-fluid-4xl: clamp(1.75rem, 5vw, 2.5rem);
|
|
493
|
+
|
|
494
|
+
/* Custom Transitions */
|
|
495
|
+
--ease-premium: cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/* ============================================
|
|
499
|
+
* FONT FAMILIES & WEIGHTS (Tailwind v4.1)
|
|
500
|
+
*
|
|
501
|
+
* Deliberately a non-inline `@theme`. `@theme inline` copies a declaration's
|
|
502
|
+
* value into whatever consumes it, which froze these stacks into
|
|
503
|
+
* `--default-font-family` / `--default-mono-font-family` and into the
|
|
504
|
+
* `font-mono` utility at build time, so the variables existed but nothing read
|
|
505
|
+
* them and re-declaring one on a scope changed nothing. A plain `@theme`
|
|
506
|
+
* emits each token as a real custom property and makes its consumers
|
|
507
|
+
* reference it with `var()`, so the base rule and the `font-*` utilities
|
|
508
|
+
* re-resolve wherever the token is redeclared. The weights sit here for the
|
|
509
|
+
* same reason, and to match the weights Tailwind ships (`--font-weight-black`
|
|
510
|
+
* and friends), which the `font-*` utilities also reach through `var()`.
|
|
511
|
+
*
|
|
512
|
+
* `--font-*` is the font-FAMILY namespace and `--font-weight-*` is the weight
|
|
513
|
+
* one, so a weight declared as `--font-bold` registers a family literally named
|
|
514
|
+
* "bold": `font-bold` then compiles to `font-family: 700`, which browsers drop,
|
|
515
|
+
* and it shadows the real weight utility rather than adding to it.
|
|
516
|
+
* ============================================ */
|
|
517
|
+
@theme {
|
|
518
|
+
--font-sans: var(--font-inter), Inter, sans-serif;
|
|
519
|
+
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
|
|
520
|
+
--font-mono:
|
|
521
|
+
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
|
|
522
|
+
"Courier New", monospace;
|
|
523
|
+
|
|
524
|
+
/* Body text, captions */
|
|
525
|
+
--font-weight-normal: 400;
|
|
526
|
+
/* Subheadings, emphasis */
|
|
527
|
+
--font-weight-medium: 500;
|
|
528
|
+
/* Headings, buttons */
|
|
529
|
+
--font-weight-semibold: 600;
|
|
530
|
+
/* Strong emphasis (rarely used) */
|
|
531
|
+
--font-weight-bold: 700;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/* ============================================
|
|
535
|
+
* RESPONSIVE TYPOGRAPHY (Desktop)
|
|
536
|
+
* Scale up larger text sizes on desktop screens
|
|
537
|
+
* Must be outside @theme block due to Tailwind v4.1 restrictions
|
|
538
|
+
* ============================================ */
|
|
539
|
+
@media (min-width: 768px) {
|
|
540
|
+
@theme {
|
|
541
|
+
--text-2xl: 1.75rem;
|
|
542
|
+
/* 28px on desktop (from 24px) */
|
|
543
|
+
--text-3xl: 2.25rem;
|
|
544
|
+
/* 36px on desktop (from 30px) */
|
|
545
|
+
--text-4xl: 3rem;
|
|
546
|
+
/* 48px on desktop (from 36px) */
|
|
547
|
+
--text-5xl: 4rem;
|
|
548
|
+
/* 64px on desktop (from 48px) */
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/* Animation keyframes referenced by the --animate-* tokens above. */
|
|
553
|
+
/* Keyframes for custom animations */
|
|
554
|
+
@keyframes brand-orbit {
|
|
555
|
+
from {
|
|
556
|
+
transform: rotate(0deg);
|
|
557
|
+
}
|
|
558
|
+
to {
|
|
559
|
+
transform: rotate(360deg);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
@keyframes brand-pulse {
|
|
564
|
+
0%,
|
|
565
|
+
100% {
|
|
566
|
+
transform: scale(0.97);
|
|
567
|
+
filter: drop-shadow(
|
|
568
|
+
0 0 10px color-mix(in srgb, var(--nx-primary) 8%, transparent)
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
50% {
|
|
572
|
+
transform: scale(1.03);
|
|
573
|
+
filter: drop-shadow(
|
|
574
|
+
0 0 20px color-mix(in srgb, var(--nx-primary) 22%, transparent)
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
@keyframes accordion-down {
|
|
580
|
+
from {
|
|
581
|
+
height: 0;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
to {
|
|
585
|
+
height: var(--radix-accordion-content-height);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
@keyframes accordion-up {
|
|
590
|
+
from {
|
|
591
|
+
height: var(--radix-accordion-content-height);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
to {
|
|
595
|
+
height: 0;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
@keyframes fade-in {
|
|
600
|
+
from {
|
|
601
|
+
opacity: 0;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
to {
|
|
605
|
+
opacity: 1;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
@keyframes fade-out {
|
|
610
|
+
from {
|
|
611
|
+
opacity: 1;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
to {
|
|
615
|
+
opacity: 0;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
@keyframes zoom-in-95 {
|
|
620
|
+
from {
|
|
621
|
+
opacity: 0;
|
|
622
|
+
transform: scale(0.95);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
to {
|
|
626
|
+
opacity: 1;
|
|
627
|
+
transform: scale(1);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
@keyframes zoom-out-95 {
|
|
632
|
+
from {
|
|
633
|
+
opacity: 1;
|
|
634
|
+
transform: scale(1);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
to {
|
|
638
|
+
opacity: 0;
|
|
639
|
+
transform: scale(0.95);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
@keyframes slide-in-from-top-2 {
|
|
644
|
+
from {
|
|
645
|
+
transform: translateY(-0.5rem);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
to {
|
|
649
|
+
transform: translateY(0);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
@keyframes slide-in-from-bottom-2 {
|
|
654
|
+
from {
|
|
655
|
+
transform: translateY(0.5rem);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
to {
|
|
659
|
+
transform: translateY(0);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
@keyframes slide-in-from-left-2 {
|
|
664
|
+
from {
|
|
665
|
+
transform: translateX(-0.5rem);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
to {
|
|
669
|
+
transform: translateX(0);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
@keyframes slide-in-from-right-2 {
|
|
674
|
+
from {
|
|
675
|
+
transform: translateX(0.5rem);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
to {
|
|
679
|
+
transform: translateX(0);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
:root {
|
|
684
|
+
/* Base colors - using Slate neutral scale */
|
|
685
|
+
--nx-background: oklch(1 0 0);
|
|
686
|
+
/* Pure white for weightless aesthetic */
|
|
687
|
+
--nx-page-background: oklch(0.9818 0 0);
|
|
688
|
+
/* #f9f9f9 for page content area */
|
|
689
|
+
--nx-foreground: oklch(0.2079 0.0399 265.73);
|
|
690
|
+
/* slate-900 */
|
|
691
|
+
|
|
692
|
+
/* Component colors */
|
|
693
|
+
--nx-card: oklch(1 0 0);
|
|
694
|
+
/* pure white for cards to pop on off-white bg */
|
|
695
|
+
--nx-card-foreground: oklch(0.2079 0.0399 265.73);
|
|
696
|
+
/* slate-900 */
|
|
697
|
+
--nx-popover: oklch(1 0 0);
|
|
698
|
+
/* white */
|
|
699
|
+
--nx-popover-foreground: oklch(0.2079 0.0399 265.73);
|
|
700
|
+
/* slate-900 */
|
|
701
|
+
|
|
702
|
+
/* Brand colors - Blue-Cyan Professional Palette */
|
|
703
|
+
--nx-primary: oklch(0 0 0);
|
|
704
|
+
/* Black for premium minimalist aesthetic */
|
|
705
|
+
--nx-primary-foreground: oklch(1 0 0);
|
|
706
|
+
/* white */
|
|
707
|
+
|
|
708
|
+
/* Secondary colors - using slate-100 for subtle backgrounds */
|
|
709
|
+
--nx-secondary: oklch(0.9684 0.0068 247.9);
|
|
710
|
+
/* slate-100 */
|
|
711
|
+
--nx-secondary-foreground: oklch(0.2079 0.0399 265.73);
|
|
712
|
+
/* slate-900 */
|
|
713
|
+
|
|
714
|
+
/* Utility colors */
|
|
715
|
+
--nx-muted: oklch(0.9696 0 0);
|
|
716
|
+
/* Darkened so muted text clears WCAG 4.5:1 on the muted surface (was 4.35:1). */
|
|
717
|
+
--nx-muted-foreground: oklch(0.54 0.0407 257.44);
|
|
718
|
+
/* slate-500 */
|
|
719
|
+
--nx-accent: oklch(0.5547 0.0407 257.44);
|
|
720
|
+
/* Slate-500 per user request #64748b */
|
|
721
|
+
--nx-accent-foreground: oklch(1 0 0);
|
|
722
|
+
/* white */
|
|
723
|
+
|
|
724
|
+
/* State colors - WCAG 2.2 AA Compliant.
|
|
725
|
+
* Each status has two roles kept as separate tokens, the industry-standard
|
|
726
|
+
* split (Radix/Primer): the base token is the readable TEXT color used by
|
|
727
|
+
* `text-destructive` and derived shades, and `-solid` is the saturated FILL
|
|
728
|
+
* used by buttons under white on-color text. One value cannot serve both in
|
|
729
|
+
* dark mode (a fill dark enough for white text is too dark to read as text
|
|
730
|
+
* on the page), so they diverge there. */
|
|
731
|
+
/* Darkened from red-500; renders as #d92c32, ~4.8:1 as text on white. */
|
|
732
|
+
--nx-destructive: oklch(0.5778 0.2078 25.33);
|
|
733
|
+
--nx-destructive-solid: oklch(0.5778 0.2078 25.33);
|
|
734
|
+
--nx-destructive-foreground: oklch(1 0 0);
|
|
735
|
+
/* white */
|
|
736
|
+
/* Darkened from green-600; renders as #00852c, ~4.8:1 as text on white. */
|
|
737
|
+
--nx-success: oklch(0.53 0.17 149.2);
|
|
738
|
+
--nx-success-solid: oklch(0.53 0.17 149.2);
|
|
739
|
+
--nx-success-foreground: oklch(1 0 0);
|
|
740
|
+
/* white */
|
|
741
|
+
/* Darkened from amber-500 so it reads as text on white at WCAG 4.5:1 (was
|
|
742
|
+
* 2.15:1); its light shades still tint badge/alert surfaces. */
|
|
743
|
+
--nx-warning: oklch(0.565 0.1646 70.11);
|
|
744
|
+
--nx-warning-foreground: oklch(0.2079 0.0399 265.73);
|
|
745
|
+
/* slate-900 - REQUIRED for AA contrast (warning-500 on white = 3.4:1, fails AA) */
|
|
746
|
+
|
|
747
|
+
/* The highlighter mark in authored content. Kept a light yellow in both
|
|
748
|
+
* modes on purpose: it stands for a marker pen drawn over the text, and the
|
|
749
|
+
* pairing below is what keeps that readable rather than the page's own
|
|
750
|
+
* foreground, which would be white-on-yellow in dark mode. */
|
|
751
|
+
--nx-highlight: oklch(0.9297 0.1638 101.06);
|
|
752
|
+
/* yellow-200 */
|
|
753
|
+
--nx-highlight-foreground: oklch(0.2079 0.0399 265.73);
|
|
754
|
+
/* slate-900 — the mark keeps its own dark text, whatever the page does */
|
|
755
|
+
|
|
756
|
+
/* Syntax colors. The tokenizer reports what a token *is*; these decide how
|
|
757
|
+
* it looks, so a code block carries no colour of its own and renders from
|
|
758
|
+
* whichever mode is active. Kept muted against the monochrome chrome, and
|
|
759
|
+
* held above 4.5:1 on --nx-code-bg since code is small text. */
|
|
760
|
+
--nx-code-bg: oklch(0.9761 0.0035 247.86);
|
|
761
|
+
--nx-code-fg: oklch(0.2079 0.0399 265.73);
|
|
762
|
+
/* Darkened slightly to clear WCAG 4.5:1 on the code surface (was 4.44:1). */
|
|
763
|
+
--nx-code-comment: oklch(0.541 0.0407 257.44);
|
|
764
|
+
--nx-code-keyword: oklch(0.4882 0.2172 303.9);
|
|
765
|
+
--nx-code-string: oklch(0.4478 0.1189 152.1);
|
|
766
|
+
--nx-code-number: oklch(0.5106 0.1518 44.2);
|
|
767
|
+
--nx-code-function: oklch(0.4757 0.1444 254.6);
|
|
768
|
+
--nx-code-operator: oklch(0.4936 0.1418 8.4);
|
|
769
|
+
/* Darkened slightly to clear WCAG 4.5:1 on the code surface (was 4.44:1). */
|
|
770
|
+
--nx-code-punctuation: oklch(0.541 0.0407 257.44);
|
|
771
|
+
--nx-code-variable: oklch(0.4694 0.1173 62.3);
|
|
772
|
+
--nx-code-tag: oklch(0.5054 0.1905 27.5);
|
|
773
|
+
--nx-code-deleted: oklch(0.5054 0.1905 27.5);
|
|
774
|
+
--nx-code-inserted: oklch(0.4478 0.1189 152.1);
|
|
775
|
+
|
|
776
|
+
/* Element colors — 3-tier translucent border scale (monochrome).
|
|
777
|
+
* The first two tiers are decorative and are tuned by eye: subtle = faint
|
|
778
|
+
* dividers, default = the container edge on cards, groups, and tables
|
|
779
|
+
* (composites to a light grey on white, a hairline rather than a rule). The third
|
|
780
|
+
* is not decorative — strong marks the edge of a control that has no other
|
|
781
|
+
* boundary, so it is held to a contrast minimum instead. */
|
|
782
|
+
--nx-border-subtle: oklch(0 0 0 / 0.08);
|
|
783
|
+
--nx-border: oklch(0 0 0 / 0.14);
|
|
784
|
+
/* Alpha raised so the composited strong border clears WCAG 3:1 / ~4:1 (was 2.11:1). */
|
|
785
|
+
--nx-border-strong: oklch(0 0 0 / 0.502);
|
|
786
|
+
/* Darkened so the field border clears WCAG 3:1 on the page (was 2.32:1). */
|
|
787
|
+
--nx-input: oklch(0.6454 0.0116 286.11);
|
|
788
|
+
--nx-ring: var(--nx-primary);
|
|
789
|
+
|
|
790
|
+
/* The base colour of the elevation ramp (--shadow-sm..xl, -inner-subtle,
|
|
791
|
+
* -neo). Each step mixes this down to its own alpha, so retinting every
|
|
792
|
+
* shadow at once is a single token change. */
|
|
793
|
+
--nx-shadow-color: oklch(0 0 0);
|
|
794
|
+
|
|
795
|
+
/* Chart colors for data visualization */
|
|
796
|
+
--nx-chart-1: var(--nx-primary);
|
|
797
|
+
--nx-chart-2: oklch(0.7399 0.1277 209.34);
|
|
798
|
+
/* cyan-500 */
|
|
799
|
+
--nx-chart-3: oklch(0.6273 0.17 149.2);
|
|
800
|
+
/* green-600 */
|
|
801
|
+
--nx-chart-4: oklch(0.7686 0.1646 70.11);
|
|
802
|
+
/* amber-500 */
|
|
803
|
+
--nx-chart-5: oklch(0.6368 0.2078 25.33);
|
|
804
|
+
/* red-500 */
|
|
805
|
+
|
|
806
|
+
/* Design tokens */
|
|
807
|
+
--radius: 0px;
|
|
808
|
+
|
|
809
|
+
/* Control sizing — derived from a single height knob so control density
|
|
810
|
+
* scales from one place. Steps map to the control size variants:
|
|
811
|
+
* sm 32px, md 36px, default 40px, lg 44px. */
|
|
812
|
+
--nx-control-height: 2.5rem;
|
|
813
|
+
--nx-control-height-sm: calc(var(--nx-control-height) - 0.5rem);
|
|
814
|
+
--nx-control-height-md: calc(var(--nx-control-height) - 0.25rem);
|
|
815
|
+
--nx-control-height-lg: calc(var(--nx-control-height) + 0.25rem);
|
|
816
|
+
|
|
817
|
+
/* Focus ring colors */
|
|
818
|
+
--nx-focus-ring: var(--nx-primary);
|
|
819
|
+
--nx-focus-ring-offset: oklch(1 0 0);
|
|
820
|
+
/* white */
|
|
821
|
+
|
|
822
|
+
/* Sidebar specific colors - using Slate scale */
|
|
823
|
+
--nx-sidebar-background: var(--nx-background);
|
|
824
|
+
/* flat with the content surface; nav is separated by borders, not fill */
|
|
825
|
+
--nx-sidebar-foreground: oklch(0.372 0.0392 257.3);
|
|
826
|
+
/* slate-700 */
|
|
827
|
+
--nx-sidebar-primary: oklch(0.2079 0.0399 265.73);
|
|
828
|
+
/* slate-900 */
|
|
829
|
+
--nx-sidebar-primary-foreground: oklch(0.9838 0.0035 247.86);
|
|
830
|
+
/* slate-50 */
|
|
831
|
+
--nx-sidebar-accent: oklch(0.9684 0.0068 247.9);
|
|
832
|
+
/* slate-100 */
|
|
833
|
+
--nx-sidebar-accent-foreground: oklch(0.2079 0.0399 265.73);
|
|
834
|
+
/* slate-900 */
|
|
835
|
+
/* Darkened so the sidebar border clears WCAG 3:1 on its surface (was 1.23:1). */
|
|
836
|
+
--nx-sidebar-border: oklch(0.6446 0.0126 255.53);
|
|
837
|
+
/* slate-200 */
|
|
838
|
+
--nx-sidebar-ring: var(--nx-primary);
|
|
839
|
+
|
|
840
|
+
/* Data table specific colors */
|
|
841
|
+
--nx-table-row-hover: oklch(0.9848 0 0);
|
|
842
|
+
--nx-table-row-selected: var(--nx-primary);
|
|
843
|
+
--nx-table-border: var(--nx-border);
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
/* Dark theme overrides when using class-based theming */
|
|
847
|
+
.dark {
|
|
848
|
+
/* Base colors - using Slate dark scale */
|
|
849
|
+
--nx-background: oklch(0.1358 0.0163 262.71);
|
|
850
|
+
/* ultra deep dark background (darker than slate-950) */
|
|
851
|
+
--nx-page-background: oklch(0.1358 0.0163 262.71);
|
|
852
|
+
/* Matches background in dark mode */
|
|
853
|
+
--nx-foreground: oklch(0.9838 0.0035 247.86);
|
|
854
|
+
/* slate-50 */
|
|
855
|
+
|
|
856
|
+
/* Component colors */
|
|
857
|
+
--nx-card: oklch(0.1916 0.0228 266.36);
|
|
858
|
+
/* raised one tonal step above --nx-background (222 47% 4%) so panels/cards
|
|
859
|
+
* read as distinct surfaces in dark mode instead of merging into the page */
|
|
860
|
+
--nx-card-foreground: oklch(0.9838 0.0035 247.86);
|
|
861
|
+
/* slate-50 */
|
|
862
|
+
/* Darkened toward the card elevation so borders, inputs, and muted text
|
|
863
|
+
* placed on a popover clear their WCAG minimums (border was 2.85:1, input
|
|
864
|
+
* 1.73:1); the surface was too light for its own contents. */
|
|
865
|
+
--nx-popover: oklch(0.24 0.0249 257.44);
|
|
866
|
+
/* slate-800 */
|
|
867
|
+
--nx-popover-foreground: oklch(0.9838 0.0035 247.86);
|
|
868
|
+
/* slate-50 */
|
|
869
|
+
|
|
870
|
+
/* Brand colors - Blue-Cyan Professional Palette (Dark Mode) */
|
|
871
|
+
--nx-primary: oklch(1 0 0); /* High contrast White for dark mode */
|
|
872
|
+
--nx-primary-foreground: oklch(0.2079 0.0399 265.73);
|
|
873
|
+
/* slate-900 */
|
|
874
|
+
|
|
875
|
+
/* Secondary colors - using slate-800 for dark backgrounds */
|
|
876
|
+
--nx-secondary: oklch(0.28 0.0369 259.97);
|
|
877
|
+
/* slate-800 */
|
|
878
|
+
--nx-secondary-foreground: oklch(0.9838 0.0035 247.86);
|
|
879
|
+
/* slate-50 */
|
|
880
|
+
|
|
881
|
+
/* Utility colors */
|
|
882
|
+
--nx-muted: oklch(0.28 0.0369 259.97);
|
|
883
|
+
/* slate-800 */
|
|
884
|
+
--nx-muted-foreground: oklch(0.7107 0.0351 256.79);
|
|
885
|
+
/* slate-400 */
|
|
886
|
+
--nx-accent: oklch(
|
|
887
|
+
0.5547 0.0407 257.44
|
|
888
|
+
); /* Slate-500 per user request #64748b */
|
|
889
|
+
--nx-accent-foreground: oklch(1 0 0);
|
|
890
|
+
/* white */
|
|
891
|
+
|
|
892
|
+
/* State colors - WCAG 2.2 AA Compliant (Dark Mode).
|
|
893
|
+
* The base token is lightened from the fill color so it reads as text on the
|
|
894
|
+
* dark page at 4.5:1; `-solid` keeps the darker fill so white on-color text
|
|
895
|
+
* on buttons still clears 4.5:1. Warning is already light enough to read on
|
|
896
|
+
* dark, so its base is unchanged here. */
|
|
897
|
+
/* Lightened red so it reads as text at WCAG 4.5:1 on the dark page and on the
|
|
898
|
+
* lighter popover surface (was 4.17:1 on the page, 4.25:1 on a popover). */
|
|
899
|
+
--nx-destructive: oklch(0.65 0.2078 25.33);
|
|
900
|
+
/* Darker red fill so white on-color button text clears 4.5:1. */
|
|
901
|
+
--nx-destructive-solid: oklch(0.5778 0.2078 25.33);
|
|
902
|
+
--nx-destructive-foreground: oklch(1 0 0);
|
|
903
|
+
/* white */
|
|
904
|
+
/* Lightened green so it reads as text at WCAG 4.5:1 on the dark page and on
|
|
905
|
+
* the lighter popover surface (was 4.17:1 on the page, 4.29:1 on a popover). */
|
|
906
|
+
--nx-success: oklch(0.6 0.1921 149.58);
|
|
907
|
+
/* Darker green fill so white on-color button text clears 4.5:1. */
|
|
908
|
+
--nx-success-solid: oklch(0.5225 0.1921 149.58);
|
|
909
|
+
--nx-success-foreground: oklch(1 0 0);
|
|
910
|
+
/* white */
|
|
911
|
+
--nx-warning: oklch(0.7686 0.1646 70.11);
|
|
912
|
+
/* amber-500 */
|
|
913
|
+
--nx-warning-foreground: oklch(0.2079 0.0399 265.73);
|
|
914
|
+
/* slate-900 */
|
|
915
|
+
|
|
916
|
+
/* Dimmed so the mark reads as highlighted rather than as a lamp on a dark
|
|
917
|
+
* page, while its own foreground stays dark enough to read against it. */
|
|
918
|
+
--nx-highlight: oklch(0.8 0.1425 101.06);
|
|
919
|
+
/* yellow-300-ish, pulled back for the dark surface */
|
|
920
|
+
--nx-highlight-foreground: oklch(0.2079 0.0399 265.73);
|
|
921
|
+
/* slate-900 */
|
|
922
|
+
|
|
923
|
+
/* Syntax colors (dark). Lightened rather than reused from light mode: the
|
|
924
|
+
* light hues sit near 0.45-0.5 lightness and disappear on the dark surface.
|
|
925
|
+
* Chroma is pulled back slightly so they don't vibrate against it. */
|
|
926
|
+
--nx-code-bg: oklch(0.1916 0.0228 266.36);
|
|
927
|
+
--nx-code-fg: oklch(0.9838 0.0035 247.86);
|
|
928
|
+
--nx-code-comment: oklch(0.6626 0.0364 256.79);
|
|
929
|
+
--nx-code-keyword: oklch(0.7482 0.1235 303.9);
|
|
930
|
+
--nx-code-string: oklch(0.7654 0.1476 152.1);
|
|
931
|
+
--nx-code-number: oklch(0.7807 0.1189 44.2);
|
|
932
|
+
--nx-code-function: oklch(0.7365 0.1163 254.6);
|
|
933
|
+
--nx-code-operator: oklch(0.7549 0.1234 8.4);
|
|
934
|
+
--nx-code-punctuation: oklch(0.6626 0.0364 256.79);
|
|
935
|
+
--nx-code-variable: oklch(0.7938 0.1052 62.3);
|
|
936
|
+
--nx-code-tag: oklch(0.7118 0.1476 27.5);
|
|
937
|
+
--nx-code-deleted: oklch(0.7118 0.1476 27.5);
|
|
938
|
+
--nx-code-inserted: oklch(0.7654 0.1476 152.1);
|
|
939
|
+
|
|
940
|
+
/* Element colors — 3-tier translucent border scale (white-alpha for dark).
|
|
941
|
+
* Recomputed as white-over-dark alpha (not a flipped hex) so dividers read
|
|
942
|
+
* on the deep background without glowing. The decorative tiers carry the same
|
|
943
|
+
* alphas as light mode, which lands the container edge at a matched 1.41:1 on
|
|
944
|
+
* the page (1.38:1 light), so a hairline weighs the same in both modes. */
|
|
945
|
+
--nx-border-subtle: oklch(1 0 0 / 0.08);
|
|
946
|
+
--nx-border: oklch(1 0 0 / 0.14);
|
|
947
|
+
/* Alpha raised so the composited strong border clears WCAG 3:1 / ~4:1 (was 3.00:1). */
|
|
948
|
+
--nx-border-strong: oklch(1 0 0 / 0.418);
|
|
949
|
+
/* Brightened so the field border clears WCAG 3:1 on the lighter popover
|
|
950
|
+
* surface as well as the page and card (was 1.73:1 on a popover). */
|
|
951
|
+
--nx-input: oklch(0.54 0.0128 285.92);
|
|
952
|
+
--nx-ring: var(--nx-primary);
|
|
953
|
+
|
|
954
|
+
/* Black in dark mode too: the ramp reads as depth against the deep surfaces
|
|
955
|
+
* rather than as a glow, which a lightened shadow colour would produce. */
|
|
956
|
+
--nx-shadow-color: oklch(0 0 0);
|
|
957
|
+
|
|
958
|
+
/* Chart colors for data visualization (same as light mode) */
|
|
959
|
+
--nx-chart-1: var(--nx-primary);
|
|
960
|
+
--nx-chart-2: oklch(0.7399 0.1277 209.34);
|
|
961
|
+
/* cyan-500 */
|
|
962
|
+
--nx-chart-3: oklch(0.7229 0.1921 149.58);
|
|
963
|
+
/* green-500 */
|
|
964
|
+
--nx-chart-4: oklch(0.7686 0.1646 70.11);
|
|
965
|
+
/* amber-500 */
|
|
966
|
+
--nx-chart-5: oklch(0.6368 0.2078 25.33);
|
|
967
|
+
/* red-500 */
|
|
968
|
+
|
|
969
|
+
/* Sidebar specific colors - dark mode */
|
|
970
|
+
--nx-sidebar-background: var(--nx-background);
|
|
971
|
+
/* flat with the content surface; nav is separated by borders, not fill */
|
|
972
|
+
/* Resting nav ink, dimmed off slate-50 so it sits a step below
|
|
973
|
+
* --nx-sidebar-accent-foreground the way the light pair does: the lightness
|
|
974
|
+
* gap here (0.164) is the same one light mode puts between slate-600 and
|
|
975
|
+
* slate-900, so an active row reads as emphasised by its ink and not only by
|
|
976
|
+
* its fill. Chroma and hue track the theme's other secondary ink
|
|
977
|
+
* (--nx-muted-foreground) so lightness alone carries the hierarchy. */
|
|
978
|
+
--nx-sidebar-foreground: oklch(0.82 0.0351 256.79);
|
|
979
|
+
--nx-sidebar-primary: oklch(0.9838 0.0035 247.86);
|
|
980
|
+
/* slate-50 */
|
|
981
|
+
--nx-sidebar-primary-foreground: oklch(0.2079 0.0399 265.73);
|
|
982
|
+
/* slate-900 */
|
|
983
|
+
--nx-sidebar-accent: oklch(0.28 0.0369 259.97);
|
|
984
|
+
/* slate-800 */
|
|
985
|
+
--nx-sidebar-accent-foreground: oklch(0.9838 0.0035 247.86);
|
|
986
|
+
/* slate-50 */
|
|
987
|
+
/* Lightened so the sidebar border clears WCAG 3:1 on its surface (was 1.19:1). */
|
|
988
|
+
--nx-sidebar-border: oklch(0.4975 0.0129 257.43);
|
|
989
|
+
--nx-sidebar-ring: var(--nx-primary);
|
|
990
|
+
|
|
991
|
+
/* Data table specific colors - dark mode */
|
|
992
|
+
--nx-table-row-hover: oklch(0.28 0.0369 259.97);
|
|
993
|
+
/* slate-800 */
|
|
994
|
+
--nx-table-row-selected: var(--nx-primary);
|
|
995
|
+
--nx-table-border: var(--nx-border);
|
|
996
|
+
/* inherit the retuned white-alpha border (was a fixed faint slate) */
|
|
997
|
+
}
|