@stnd/styles 0.5.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/CHANGELOG.md +25 -0
- package/README.md +116 -0
- package/TOKENS.md +415 -0
- package/_standard-00-reset.scss +74 -0
- package/_standard-00-variables.scss +54 -0
- package/_standard-01-token.scss +287 -0
- package/_standard-02-color.scss +683 -0
- package/_standard-03-typography.scss +411 -0
- package/_standard-04-grid.scss +314 -0
- package/_standard-05-rhythm.scss +57 -0
- package/_standard-06-prose.scss +289 -0
- package/_standard-07-base.scss +216 -0
- package/_standard-08-media.scss +216 -0
- package/_standard-09-lists.scss +103 -0
- package/_standard-10-tables.scss +49 -0
- package/_standard-11-forms.scss +343 -0
- package/_standard-12-code.scss +204 -0
- package/_standard-13-components.scss +1261 -0
- package/_standard-14-analog.scss +48 -0
- package/_standard-30-contrast.scss +42 -0
- package/_standard-31-print.scss +97 -0
- package/_standard-32-eink.scss +78 -0
- package/_standard-50-utilities.scss +1117 -0
- package/_standard-99-debug.scss +474 -0
- package/dist/obsidian.css +31 -0
- package/dist/obsidian.css.map +1 -0
- package/dist/standard.css +20 -0
- package/dist/standard.css.map +1 -0
- package/index.js +1 -0
- package/obsidian.scss +18 -0
- package/package.json +46 -0
- package/standard.scss +52 -0
|
@@ -0,0 +1,683 @@
|
|
|
1
|
+
@use "standard-00-variables" as *;
|
|
2
|
+
|
|
3
|
+
/* ==========================================================================
|
|
4
|
+
STANDARD COLOR SYSTEM — Seed-First Architecture
|
|
5
|
+
|
|
6
|
+
Two seeds → two palettes → one semantic layer
|
|
7
|
+
|
|
8
|
+
The system works in four stages:
|
|
9
|
+
1. SEEDS: Light & dark foreground/background (set in tokens or themes)
|
|
10
|
+
2. PALETTES: Generate full light & dark color spectrums via relative color syntax
|
|
11
|
+
3. SEMANTICS: Map active palette to semantic tokens based on scheme
|
|
12
|
+
4. COMPUTED: Derive surfaces, shadows, borders from scheme-aware tokens
|
|
13
|
+
|
|
14
|
+
Override strategy (pick your depth):
|
|
15
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
16
|
+
│ Minimal: Set --color-light-foreground → everything else follows │
|
|
17
|
+
│ Per-scheme: Set --color-light-* and/or --color-dark-* tokens │
|
|
18
|
+
│ Full: Theme via [data-theme] selectors (highest specificity) │
|
|
19
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
20
|
+
|
|
21
|
+
Hue wheel (offsets from foreground hue):
|
|
22
|
+
Red +25° · Orange +55° · Yellow +85° · Green +145°
|
|
23
|
+
Cyan +190° · Blue +240° · Magenta +300°
|
|
24
|
+
|
|
25
|
+
How it works:
|
|
26
|
+
Each palette color is a single oklch(from <seed> ...) call.
|
|
27
|
+
Channel keywords l, c, h are resolved INSIDE the function — no
|
|
28
|
+
intermediate extraction needed. Safety clamps are applied inline:
|
|
29
|
+
• clamp(0.35, l, 0.65) — lightness for WCAG AA on light bg
|
|
30
|
+
• max(0.12, c) — chroma floor prevents gray alerts
|
|
31
|
+
• calc(h + offset) — hue rotation from seed
|
|
32
|
+
|
|
33
|
+
For achromatic seeds (h = none), CSS Color Level 5 §4.3 says
|
|
34
|
+
"none" is treated as 0 inside calc(), so the palette maps to
|
|
35
|
+
standard color positions (red ≈ 25°, blue ≈ 240°, etc.).
|
|
36
|
+
|
|
37
|
+
@since 0.2.0
|
|
38
|
+
@see AGENTS.md § OKLCH Color System
|
|
39
|
+
========================================================================== */
|
|
40
|
+
|
|
41
|
+
#{$stnd-theme-scope} {
|
|
42
|
+
/* Tell browser we support both color schemes */
|
|
43
|
+
color-scheme: light dark;
|
|
44
|
+
|
|
45
|
+
/* ===================================================================
|
|
46
|
+
STAGE 1: DARK SEED DERIVATION
|
|
47
|
+
The ink's soul carries into darkness.
|
|
48
|
+
Both dark seeds inherit hue from the light foreground — warm brown
|
|
49
|
+
ink begets a warm dark background and a warm soft foreground.
|
|
50
|
+
Themes override --color-dark-background / --color-dark-foreground
|
|
51
|
+
at [data-theme] specificity for a distinct dark mood.
|
|
52
|
+
|
|
53
|
+
Light fg #442f1c → oklch(0.30, 0.07, H≈60) warm brown ink
|
|
54
|
+
Dark bg derived → oklch(0.20, 0.02, H≈60) same hue, very dark, muted
|
|
55
|
+
Dark fg derived → oklch(0.85, 0.04, H≈60) same hue, soft reading brightness
|
|
56
|
+
=================================================================== */
|
|
57
|
+
|
|
58
|
+
/* Dark background: foreground's hue at very low lightness, muted chroma */
|
|
59
|
+
--color-dark-background: oklch(
|
|
60
|
+
from var(--color-light-foreground) 0.2
|
|
61
|
+
/* deep dark — not void-black, just dark enough */ min(c, 0.02)
|
|
62
|
+
/* muted — a whisper of the ink's chroma */ h
|
|
63
|
+
/* same hue — warm ink → warm dark */
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
/* Dark foreground: foreground's hue at comfortable reading brightness */
|
|
67
|
+
--color-dark-foreground: oklch(
|
|
68
|
+
from var(--color-light-foreground) 0.85
|
|
69
|
+
/* soft — easy on the eyes, not blinding white */ min(c, 0.04)
|
|
70
|
+
/* gentle — enough color to feel the warmth */ h
|
|
71
|
+
/* same hue — the vibe persists */
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
/* ===================================================================
|
|
75
|
+
STAGE 2: LIGHT PALETTE
|
|
76
|
+
Full spectrum generated from light foreground seed via inline
|
|
77
|
+
relative color syntax. Each color is a self-contained transform:
|
|
78
|
+
oklch(from <seed> <safe-L> <safe-C> calc(h + offset))
|
|
79
|
+
|
|
80
|
+
Channel keywords l, c, h resolve inside the function scope.
|
|
81
|
+
No extraction into intermediate custom properties needed.
|
|
82
|
+
Safety: clamp(0.65, l, 0.70) for bright vibrant tones, max(0.12, c) for saturation.
|
|
83
|
+
Achromatic seeds (h = none) → none treated as 0 in calc() per spec.
|
|
84
|
+
=================================================================== */
|
|
85
|
+
|
|
86
|
+
/* Error / Red — foreground hue + 25° */
|
|
87
|
+
--color-light-red: oklch(
|
|
88
|
+
from var(--color-light-foreground) clamp(0.65, l, 0.7) max(0.12, c)
|
|
89
|
+
calc(h + 25)
|
|
90
|
+
);
|
|
91
|
+
/* Attention / Orange — foreground hue + 55° */
|
|
92
|
+
--color-light-orange: oklch(
|
|
93
|
+
from var(--color-light-foreground) clamp(0.65, l, 0.7) max(0.12, c)
|
|
94
|
+
calc(h + 55)
|
|
95
|
+
);
|
|
96
|
+
/* Warning / Yellow — foreground hue + 85° */
|
|
97
|
+
--color-light-yellow: oklch(
|
|
98
|
+
from var(--color-light-foreground) clamp(0.65, l, 0.7) max(0.12, c)
|
|
99
|
+
calc(h + 85)
|
|
100
|
+
);
|
|
101
|
+
/* Success / Green — foreground hue + 145° */
|
|
102
|
+
--color-light-green: oklch(
|
|
103
|
+
from var(--color-light-foreground) clamp(0.65, l, 0.7) max(0.12, c)
|
|
104
|
+
calc(h + 145)
|
|
105
|
+
);
|
|
106
|
+
/* Info / Cyan — foreground hue + 190° */
|
|
107
|
+
--color-light-cyan: oklch(
|
|
108
|
+
from var(--color-light-foreground) clamp(0.65, l, 0.7) max(0.12, c)
|
|
109
|
+
calc(h + 190)
|
|
110
|
+
);
|
|
111
|
+
/* Link / Blue — foreground hue + 240° */
|
|
112
|
+
--color-light-blue: oklch(
|
|
113
|
+
from var(--color-light-foreground) clamp(0.65, l, 0.7) max(0.12, c)
|
|
114
|
+
calc(h + 240)
|
|
115
|
+
);
|
|
116
|
+
/* Magic / Magenta — foreground hue + 300° */
|
|
117
|
+
--color-light-magenta: oklch(
|
|
118
|
+
from var(--color-light-foreground) clamp(0.65, l, 0.7) max(0.12, c)
|
|
119
|
+
calc(h + 300)
|
|
120
|
+
);
|
|
121
|
+
/* Purple — foreground hue + 270° */
|
|
122
|
+
--color-light-purple: oklch(
|
|
123
|
+
from var(--color-light-foreground) clamp(0.65, l, 0.7) max(0.12, c)
|
|
124
|
+
calc(h + 270)
|
|
125
|
+
);
|
|
126
|
+
/* Pink — foreground hue + 350° */
|
|
127
|
+
--color-light-pink: oklch(
|
|
128
|
+
from var(--color-light-foreground) clamp(0.65, l, 0.7) max(0.12, c)
|
|
129
|
+
calc(h + 350)
|
|
130
|
+
);
|
|
131
|
+
/* Brown — foreground hue - 15° */
|
|
132
|
+
--color-light-brown: oklch(
|
|
133
|
+
from var(--color-light-foreground) clamp(0.65, l, 0.7) max(0.12, c)
|
|
134
|
+
calc(h - 15)
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
/* Link color defaults to blue */
|
|
138
|
+
--color-light-link: var(--color-light-accent);
|
|
139
|
+
|
|
140
|
+
/* Auto-accent strategies */
|
|
141
|
+
/* 1. Complementary (Opposite side of color wheel, +180°) - High contrast */
|
|
142
|
+
--color-light-accent-complementary: oklch(
|
|
143
|
+
from var(--color-light-foreground) calc(l + (0.65 - l) * min(1, c * 10))
|
|
144
|
+
min(0.2, c * 2) calc(h + 180)
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
/* 2. Analogous (Next to the seed color, +30°) - Harmonious, less jarring */
|
|
148
|
+
--color-light-accent-analogous: oklch(
|
|
149
|
+
from var(--color-light-foreground) calc(l + (0.65 - l) * min(1, c * 10))
|
|
150
|
+
min(0.2, c * 2) calc(h + 30)
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
/* 3. Triadic (Third of the way around, +120°) - Balanced contrast */
|
|
154
|
+
--color-light-accent-triadic: oklch(
|
|
155
|
+
from var(--color-light-foreground) calc(l + (0.65 - l) * min(1, c * 10))
|
|
156
|
+
min(0.2, c * 2) calc(h + 120)
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
/* Default to a slightly shifted analogous/triadic blend instead of pure 180 opposite
|
|
160
|
+
which can be jarring if the foreground is highly saturated.
|
|
161
|
+
+120 gives a strong but often more pleasing result than +180. */
|
|
162
|
+
--color-light-accent-auto: var(--color-light-accent-triadic);
|
|
163
|
+
--color-light-accent: var(--color-light-accent-auto);
|
|
164
|
+
|
|
165
|
+
/* ===================================================================
|
|
166
|
+
STAGE 2B: DARK PALETTE
|
|
167
|
+
Full spectrum generated from dark foreground seed.
|
|
168
|
+
NOT a simple lightening of the light palette — independent vibe.
|
|
169
|
+
A warm dark-foreground seed gives warm darks. A cool one gives
|
|
170
|
+
cool darks. Two different seeds, two different moods.
|
|
171
|
+
Safety: clamp(0.55, l, 0.70) for softer tones on dark surfaces.
|
|
172
|
+
=================================================================== */
|
|
173
|
+
|
|
174
|
+
/* Error / Red — dark foreground hue + 25° */
|
|
175
|
+
--color-dark-red: oklch(
|
|
176
|
+
from var(--color-dark-foreground) clamp(0.55, l, 0.7) max(0.12, c)
|
|
177
|
+
calc(h + 25)
|
|
178
|
+
);
|
|
179
|
+
/* Attention / Orange — dark foreground hue + 55° */
|
|
180
|
+
--color-dark-orange: oklch(
|
|
181
|
+
from var(--color-dark-foreground) clamp(0.55, l, 0.7) max(0.12, c)
|
|
182
|
+
calc(h + 55)
|
|
183
|
+
);
|
|
184
|
+
/* Warning / Yellow — dark foreground hue + 85° */
|
|
185
|
+
--color-dark-yellow: oklch(
|
|
186
|
+
from var(--color-dark-foreground) clamp(0.55, l, 0.7) max(0.12, c)
|
|
187
|
+
calc(h + 85)
|
|
188
|
+
);
|
|
189
|
+
/* Success / Green — dark foreground hue + 145° */
|
|
190
|
+
--color-dark-green: oklch(
|
|
191
|
+
from var(--color-dark-foreground) clamp(0.55, l, 0.7) max(0.12, c)
|
|
192
|
+
calc(h + 145)
|
|
193
|
+
);
|
|
194
|
+
/* Info / Cyan — dark foreground hue + 190° */
|
|
195
|
+
--color-dark-cyan: oklch(
|
|
196
|
+
from var(--color-dark-foreground) clamp(0.55, l, 0.7) max(0.12, c)
|
|
197
|
+
calc(h + 190)
|
|
198
|
+
);
|
|
199
|
+
/* Link / Blue — dark foreground hue + 240° */
|
|
200
|
+
--color-dark-blue: oklch(
|
|
201
|
+
from var(--color-dark-foreground) clamp(0.55, l, 0.7) max(0.12, c)
|
|
202
|
+
calc(h + 240)
|
|
203
|
+
);
|
|
204
|
+
/* Magic / Magenta — dark foreground hue + 300° */
|
|
205
|
+
--color-dark-magenta: oklch(
|
|
206
|
+
from var(--color-dark-foreground) clamp(0.55, l, 0.7) max(0.12, c)
|
|
207
|
+
calc(h + 300)
|
|
208
|
+
);
|
|
209
|
+
/* Purple — dark foreground hue + 270° */
|
|
210
|
+
--color-dark-purple: oklch(
|
|
211
|
+
from var(--color-dark-foreground) clamp(0.55, l, 0.7) max(0.12, c)
|
|
212
|
+
calc(h + 270)
|
|
213
|
+
);
|
|
214
|
+
/* Pink — dark foreground hue + 350° */
|
|
215
|
+
--color-dark-pink: oklch(
|
|
216
|
+
from var(--color-dark-foreground) clamp(0.55, l, 0.7) max(0.12, c)
|
|
217
|
+
calc(h + 350)
|
|
218
|
+
);
|
|
219
|
+
/* Brown — dark foreground hue - 15° */
|
|
220
|
+
--color-dark-brown: oklch(
|
|
221
|
+
from var(--color-dark-foreground) clamp(0.55, l, 0.7) max(0.12, c)
|
|
222
|
+
calc(h - 15)
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
/* Link color defaults to blue */
|
|
226
|
+
--color-dark-link: var(--color-dark-accent);
|
|
227
|
+
|
|
228
|
+
/* Auto-accent strategies for dark mode */
|
|
229
|
+
--color-dark-accent-complementary: oklch(
|
|
230
|
+
from var(--color-dark-foreground) calc(l + (0.7 - l) * min(1, c * 10))
|
|
231
|
+
min(0.2, c * 2) calc(h + 180)
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
--color-dark-accent-analogous: oklch(
|
|
235
|
+
from var(--color-dark-foreground) calc(l + (0.7 - l) * min(1, c * 10))
|
|
236
|
+
min(0.2, c * 2) calc(h + 30)
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
--color-dark-accent-triadic: oklch(
|
|
240
|
+
from var(--color-dark-foreground) calc(l + (0.7 - l) * min(1, c * 10))
|
|
241
|
+
min(0.2, c * 2) calc(h + 120)
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
--color-dark-accent-auto: var(--color-dark-accent-triadic);
|
|
245
|
+
--color-dark-accent: var(--color-dark-accent-auto);
|
|
246
|
+
/* On-accent (text drawn on accent surfaces) */
|
|
247
|
+
--color-dark-on-accent: var(--color-dark-background);
|
|
248
|
+
|
|
249
|
+
/* ===================================================================
|
|
250
|
+
STAGE 2C: COMPUTED PALETTES
|
|
251
|
+
Always available for explicit "light-in-dark" or "dark-in-light" UI.
|
|
252
|
+
=================================================================== */
|
|
253
|
+
|
|
254
|
+
/* Light Computed Palette */
|
|
255
|
+
--color-light-muted: oklch(from var(--color-light-foreground) l c h / 0.6);
|
|
256
|
+
--color-light-subtle: oklch(from var(--color-light-foreground) l c h / 0.4);
|
|
257
|
+
--color-light-border: oklch(from var(--color-light-foreground) l c h / 0.1);
|
|
258
|
+
--color-light-surface: color-mix(
|
|
259
|
+
in srgb,
|
|
260
|
+
var(--color-light-foreground) 3%,
|
|
261
|
+
var(--color-light-background)
|
|
262
|
+
);
|
|
263
|
+
--color-light-on-accent: var(--color-light-background);
|
|
264
|
+
|
|
265
|
+
/* Dark Computed Palette */
|
|
266
|
+
--color-dark-muted: oklch(from var(--color-dark-foreground) l c h / 0.65);
|
|
267
|
+
--color-dark-subtle: oklch(from var(--color-dark-foreground) l c h / 0.45);
|
|
268
|
+
--color-dark-border: oklch(
|
|
269
|
+
from var(--color-dark-background) calc(l * 0.25) calc(c * 0.5)
|
|
270
|
+
calc(h - 15) / 0.25
|
|
271
|
+
);
|
|
272
|
+
--color-dark-surface: color-mix(
|
|
273
|
+
in srgb,
|
|
274
|
+
var(--color-dark-foreground) 3%,
|
|
275
|
+
var(--color-dark-background)
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
/* Light Shadow Palette */
|
|
279
|
+
--color-light-shadow-base: oklch(
|
|
280
|
+
from var(--color-light-foreground) calc(l * 0.25) calc(c * 0.5)
|
|
281
|
+
calc(h - 15) / 0.075
|
|
282
|
+
);
|
|
283
|
+
--color-light-highlight: oklch(
|
|
284
|
+
from var(--color-light-background) min(1, calc(l + 0.05)) c h / 0.6
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
/* Dark Shadow Palette */
|
|
288
|
+
--color-dark-shadow-base: oklch(
|
|
289
|
+
from var(--color-dark-background) calc(l * 0.25) calc(c * 0.5)
|
|
290
|
+
calc(h - 15) / 0.5
|
|
291
|
+
);
|
|
292
|
+
--color-dark-highlight: oklch(
|
|
293
|
+
from var(--color-dark-foreground) min(1, calc(l + 0.05)) c h / 0.11
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
/* ===================================================================
|
|
297
|
+
STAGE 3: SEMANTIC TOKENS (Default → Light Palette)
|
|
298
|
+
These are the tokens components actually consume.
|
|
299
|
+
Never reference --color-light-* or --color-dark-* in components.
|
|
300
|
+
Always use --color-red, --color-background, etc.
|
|
301
|
+
=================================================================== */
|
|
302
|
+
--color-background: var(--color-light-background);
|
|
303
|
+
--color-foreground: var(--color-light-foreground);
|
|
304
|
+
--color-accent: var(--color-light-accent);
|
|
305
|
+
|
|
306
|
+
--color-header: var(--color-light-header, var(--color-foreground));
|
|
307
|
+
|
|
308
|
+
--color-red: var(--color-light-red);
|
|
309
|
+
--color-orange: var(--color-light-orange);
|
|
310
|
+
--color-yellow: var(--color-light-yellow);
|
|
311
|
+
--color-green: var(--color-light-green);
|
|
312
|
+
--color-cyan: var(--color-light-cyan);
|
|
313
|
+
--color-blue: var(--color-light-blue);
|
|
314
|
+
--color-magenta: var(--color-light-magenta);
|
|
315
|
+
--color-purple: var(--color-light-purple);
|
|
316
|
+
--color-pink: var(--color-light-pink);
|
|
317
|
+
--color-brown: var(--color-light-brown);
|
|
318
|
+
|
|
319
|
+
/* Semantic status aliases */
|
|
320
|
+
--color-success: var(--color-green);
|
|
321
|
+
--color-warning: var(--color-orange);
|
|
322
|
+
--color-error: var(--color-red);
|
|
323
|
+
--color-info: var(--color-blue);
|
|
324
|
+
|
|
325
|
+
--color-link: var(--color-light-link);
|
|
326
|
+
--color-italic: var(--color-light-italic, var(--color-foreground));
|
|
327
|
+
--color-bold: var(--color-light-bold, var(--color-foreground));
|
|
328
|
+
--color-on-accent: var(--color-background);
|
|
329
|
+
|
|
330
|
+
/* ===================================================================
|
|
331
|
+
STAGE 4: COMPUTED SEMANTIC COLORS
|
|
332
|
+
Derived from the scheme-aware --color-foreground/--color-background.
|
|
333
|
+
auto-adapt when the scheme switches.
|
|
334
|
+
=================================================================== */
|
|
335
|
+
--color-muted: var(--color-light-muted);
|
|
336
|
+
--color-subtle: var(--color-light-subtle);
|
|
337
|
+
--color-border: var(--color-light-border);
|
|
338
|
+
--color-surface: var(--color-light-surface);
|
|
339
|
+
|
|
340
|
+
/* Light/dark polarity aliases — always "the lighter" and "the darker" */
|
|
341
|
+
--color-light: var(--color-light-background);
|
|
342
|
+
--color-dark: var(--color-light-foreground);
|
|
343
|
+
--color-darker: oklch(from var(--color-dark) l c h / 0.15);
|
|
344
|
+
|
|
345
|
+
--color-glass: oklch(from var(--color-background) l c h / 0.8);
|
|
346
|
+
|
|
347
|
+
/* ===================================================================
|
|
348
|
+
STAGE 5: SHADOWS & SURFACES
|
|
349
|
+
OKLCH-based for perceptually uniform elevation.
|
|
350
|
+
All derived from semantic pointers — auto-adapt to dark mode.
|
|
351
|
+
=================================================================== */
|
|
352
|
+
|
|
353
|
+
/* Semantic Shadow Seeds */
|
|
354
|
+
--color-shadow: var(--color-light-shadow-base);
|
|
355
|
+
--color-highlight: var(--color-light-highlight);
|
|
356
|
+
|
|
357
|
+
/* Shadow building blocks — compose freely */
|
|
358
|
+
--shadow-ambient: 0 1px 1px var(--color-shadow); /* Felt more than seen */
|
|
359
|
+
|
|
360
|
+
/* This one pop a bit */
|
|
361
|
+
--shadow-lift:
|
|
362
|
+
0 4px 6px -1px var(--color-shadow), 0 2px 4px -2px var(--color-shadow);
|
|
363
|
+
/* Organicaly grows */
|
|
364
|
+
--shadow-glow: 0 4px var(--space) oklch(from var(--color-shadow) l c h / 0.15);
|
|
365
|
+
--shadow-inset:
|
|
366
|
+
inset 0 1px 3px var(--color-shadow), inset 0 -1px 0 0 var(--color-highlight);
|
|
367
|
+
--shadow-ring:
|
|
368
|
+
inset 0px 1px 1px var(--color-border),
|
|
369
|
+
inset 1px 0px 1px var(--color-border),
|
|
370
|
+
inset -1px 0px 1px var(--color-border),
|
|
371
|
+
inset 0px -1px 1px var(--color-border);
|
|
372
|
+
|
|
373
|
+
/* shadcn-style raised effect: inner highlight + border + shadow */
|
|
374
|
+
--shadow-raised:
|
|
375
|
+
inset 0 1px 0 0 var(--color-highlight), 0 0 0 1px var(--color-border),
|
|
376
|
+
var(--shadow-ambient);
|
|
377
|
+
|
|
378
|
+
/* Composed presets */
|
|
379
|
+
--shadow: var(--shadow-ambient), var(--shadow-ambient);
|
|
380
|
+
--shadow-lg: var(--shadow-ambient), var(--shadow-lift);
|
|
381
|
+
--shadow-xl: var(--shadow-ambient), var(--shadow-lift), var(--shadow-glow);
|
|
382
|
+
|
|
383
|
+
/* Surface elevation scale */
|
|
384
|
+
--color-surface-low: color-mix(
|
|
385
|
+
in srgb,
|
|
386
|
+
var(--color-foreground) 3%,
|
|
387
|
+
var(--color-surface)
|
|
388
|
+
);
|
|
389
|
+
--color-surface-lowest: color-mix(
|
|
390
|
+
in srgb,
|
|
391
|
+
var(--color-foreground) 3%,
|
|
392
|
+
var(--color-surface-low)
|
|
393
|
+
);
|
|
394
|
+
--color-surface-lower: color-mix(
|
|
395
|
+
in srgb,
|
|
396
|
+
var(--color-foreground) 3%,
|
|
397
|
+
transparent
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
--color-surface-high: color-mix(in srgb, white 50%, var(--color-surface));
|
|
401
|
+
--color-surface-highest: color-mix(
|
|
402
|
+
in srgb,
|
|
403
|
+
white 50%,
|
|
404
|
+
var(--color-surface-high)
|
|
405
|
+
);
|
|
406
|
+
--color-surface-higher: color-mix(in srgb, white 50%, transparent);
|
|
407
|
+
/* ===================================================================
|
|
408
|
+
STAGE 6: DESIGN TOKENS (Border Shorthands)
|
|
409
|
+
=================================================================== */
|
|
410
|
+
--border: 0 solid transparent;
|
|
411
|
+
--border-transparent: var(--stroke-width) solid transparent;
|
|
412
|
+
--border-accent: var(--stroke-width) solid
|
|
413
|
+
oklch(from var(--color-accent) l c h / 0.07);
|
|
414
|
+
--border: none;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/* =====================================================================
|
|
418
|
+
STAGE 7: DARK MODE SWITCH
|
|
419
|
+
System preference flips semantic tokens to dark palette.
|
|
420
|
+
Computed semantics (muted, subtle, border, surfaces, shadows)
|
|
421
|
+
auto-adapt because they reference scheme-aware --color-foreground
|
|
422
|
+
and --color-background.
|
|
423
|
+
===================================================================== */
|
|
424
|
+
@media (prefers-color-scheme: dark) {
|
|
425
|
+
#{$stnd-theme-scope} {
|
|
426
|
+
/* Core semantic tokens → dark palette */
|
|
427
|
+
--color-background: var(--color-dark-background);
|
|
428
|
+
--color-foreground: var(--color-dark-foreground);
|
|
429
|
+
--color-accent: var(--color-dark-accent);
|
|
430
|
+
|
|
431
|
+
/* Polarity flip: in dark mode, "light" = foreground, "dark" = background */
|
|
432
|
+
--color-light: var(--color-dark-foreground);
|
|
433
|
+
--color-dark: var(--color-dark-background);
|
|
434
|
+
|
|
435
|
+
--color-header: var(--color-dark-header, var(--color-foreground));
|
|
436
|
+
--color-on-accent: var(--color-background);
|
|
437
|
+
|
|
438
|
+
/* Hue tokens → dark palette */
|
|
439
|
+
--color-red: var(--color-dark-red);
|
|
440
|
+
--color-orange: var(--color-dark-orange);
|
|
441
|
+
--color-yellow: var(--color-dark-yellow);
|
|
442
|
+
--color-green: var(--color-dark-green);
|
|
443
|
+
--color-cyan: var(--color-dark-cyan);
|
|
444
|
+
--color-blue: var(--color-dark-blue);
|
|
445
|
+
--color-magenta: var(--color-dark-magenta);
|
|
446
|
+
|
|
447
|
+
--color-link: var(--color-dark-link);
|
|
448
|
+
--color-italic: var(--color-dark-italic, var(--color-foreground));
|
|
449
|
+
--color-bold: var(--color-dark-bold, var(--color-foreground));
|
|
450
|
+
|
|
451
|
+
/* Adjusted opacity for dark backgrounds */
|
|
452
|
+
--color-subtle: var(--color-dark-subtle);
|
|
453
|
+
--color-muted: var(--color-dark-muted);
|
|
454
|
+
--color-border: var(--color-dark-border);
|
|
455
|
+
--color-surface: var(--color-dark-surface);
|
|
456
|
+
|
|
457
|
+
--color-shadow: var(--color-dark-shadow-base);
|
|
458
|
+
--color-highlight: var(--color-dark-highlight);
|
|
459
|
+
|
|
460
|
+
--shadow-xl: var(--shadow-glow);
|
|
461
|
+
|
|
462
|
+
/* Surface elevation scale */
|
|
463
|
+
|
|
464
|
+
--color-surface-low: color-mix(in srgb, black 3%, var(--color-surface));
|
|
465
|
+
--color-surface-lowest: color-mix(
|
|
466
|
+
in srgb,
|
|
467
|
+
black 7%,
|
|
468
|
+
var(--color-surface-low)
|
|
469
|
+
);
|
|
470
|
+
--color-surface-lower: color-mix(in srgb, black 7%, transparent);
|
|
471
|
+
|
|
472
|
+
--color-surface-high: color-mix(
|
|
473
|
+
in srgb,
|
|
474
|
+
var(--color-dark-foreground) 3%,
|
|
475
|
+
var(--color-surface)
|
|
476
|
+
);
|
|
477
|
+
--color-surface-highest: color-mix(
|
|
478
|
+
in srgb,
|
|
479
|
+
var(--color-dark-foreground) 3%,
|
|
480
|
+
var(--color-surface-high)
|
|
481
|
+
);
|
|
482
|
+
--color-surface-higher: color-mix(
|
|
483
|
+
in srgb,
|
|
484
|
+
var(--color-dark-foreground) 3%,
|
|
485
|
+
transparent
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/* =====================================================================
|
|
491
|
+
STAGE 7B: THEME UTILITIES (.inverse, .theme-dark, .theme-light)
|
|
492
|
+
Provides explicit control and local context switching.
|
|
493
|
+
===================================================================== */
|
|
494
|
+
|
|
495
|
+
@mixin theme-light-tokens {
|
|
496
|
+
--color-background: var(--color-light-background);
|
|
497
|
+
--color-foreground: var(--color-light-foreground);
|
|
498
|
+
--color-accent: var(--color-light-accent);
|
|
499
|
+
--color-muted: var(--color-light-muted);
|
|
500
|
+
--color-subtle: var(--color-light-subtle);
|
|
501
|
+
--color-border: var(--color-light-border);
|
|
502
|
+
--color-surface: var(--color-light-surface);
|
|
503
|
+
--color-shadow: var(--color-light-shadow-base);
|
|
504
|
+
--color-highlight: var(--color-light-highlight);
|
|
505
|
+
--color-light: var(--color-light-background);
|
|
506
|
+
--color-dark: var(--color-light-foreground);
|
|
507
|
+
color-scheme: light;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
@mixin theme-dark-tokens {
|
|
511
|
+
--color-background: var(--color-dark-background);
|
|
512
|
+
--color-foreground: var(--color-dark-foreground);
|
|
513
|
+
--color-accent: var(--color-dark-accent);
|
|
514
|
+
--color-muted: var(--color-dark-muted);
|
|
515
|
+
--color-subtle: var(--color-dark-subtle);
|
|
516
|
+
--color-border: var(--color-dark-border);
|
|
517
|
+
--color-surface: var(--color-dark-surface);
|
|
518
|
+
--color-shadow: var(--color-dark-shadow-base);
|
|
519
|
+
--color-highlight: var(--color-dark-highlight);
|
|
520
|
+
--color-light: var(--color-dark-foreground);
|
|
521
|
+
--color-dark: var(--color-dark-background);
|
|
522
|
+
color-scheme: dark;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.theme-light {
|
|
526
|
+
@include theme-light-tokens;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.theme-dark {
|
|
530
|
+
@include theme-dark-tokens;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/* =====================================================================
|
|
534
|
+
STAGE 7C: CONTAINER THEMING
|
|
535
|
+
Re-resolves semantic tokens at element level so any element with
|
|
536
|
+
[data-theme] gets full color resolution — not just <html>.
|
|
537
|
+
Enables: themed cards, themed panels, side-by-side theme comparisons,
|
|
538
|
+
and scoped theme previews without changing the page chrome.
|
|
539
|
+
===================================================================== */
|
|
540
|
+
|
|
541
|
+
[data-theme] {
|
|
542
|
+
@include theme-light-tokens;
|
|
543
|
+
|
|
544
|
+
/* Hue tokens (not in the mixin) */
|
|
545
|
+
--color-header: var(--color-light-header, var(--color-foreground));
|
|
546
|
+
--color-red: var(--color-light-red);
|
|
547
|
+
--color-orange: var(--color-light-orange);
|
|
548
|
+
--color-yellow: var(--color-light-yellow);
|
|
549
|
+
--color-green: var(--color-light-green);
|
|
550
|
+
--color-cyan: var(--color-light-cyan);
|
|
551
|
+
--color-blue: var(--color-light-blue);
|
|
552
|
+
--color-magenta: var(--color-light-magenta);
|
|
553
|
+
--color-purple: var(--color-light-purple);
|
|
554
|
+
--color-pink: var(--color-light-pink);
|
|
555
|
+
--color-brown: var(--color-light-brown);
|
|
556
|
+
--color-link: var(--color-light-link);
|
|
557
|
+
--color-italic: var(--color-light-italic, var(--color-foreground));
|
|
558
|
+
--color-bold: var(--color-light-bold, var(--color-foreground));
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
@media (prefers-color-scheme: dark) {
|
|
562
|
+
[data-theme]:not([data-color-mode="light"]) {
|
|
563
|
+
@include theme-dark-tokens;
|
|
564
|
+
|
|
565
|
+
--color-header: var(--color-dark-header, var(--color-foreground));
|
|
566
|
+
--color-red: var(--color-dark-red);
|
|
567
|
+
--color-orange: var(--color-dark-orange);
|
|
568
|
+
--color-yellow: var(--color-dark-yellow);
|
|
569
|
+
--color-green: var(--color-dark-green);
|
|
570
|
+
--color-cyan: var(--color-dark-cyan);
|
|
571
|
+
--color-blue: var(--color-dark-blue);
|
|
572
|
+
--color-magenta: var(--color-dark-magenta);
|
|
573
|
+
--color-link: var(--color-dark-link);
|
|
574
|
+
--color-italic: var(--color-dark-italic, var(--color-foreground));
|
|
575
|
+
--color-bold: var(--color-dark-bold, var(--color-foreground));
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
[data-color-mode="dark"] [data-theme],
|
|
580
|
+
[data-color-mode="dark"][data-theme] {
|
|
581
|
+
@include theme-dark-tokens;
|
|
582
|
+
|
|
583
|
+
--color-header: var(--color-dark-header, var(--color-foreground));
|
|
584
|
+
--color-red: var(--color-dark-red);
|
|
585
|
+
--color-orange: var(--color-dark-orange);
|
|
586
|
+
--color-yellow: var(--color-dark-yellow);
|
|
587
|
+
--color-green: var(--color-dark-green);
|
|
588
|
+
--color-cyan: var(--color-dark-cyan);
|
|
589
|
+
--color-blue: var(--color-dark-blue);
|
|
590
|
+
--color-magenta: var(--color-dark-magenta);
|
|
591
|
+
--color-link: var(--color-dark-link);
|
|
592
|
+
--color-italic: var(--color-dark-italic, var(--color-foreground));
|
|
593
|
+
--color-bold: var(--color-dark-bold, var(--color-foreground));
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
[data-color-mode="light"] [data-theme],
|
|
597
|
+
[data-color-mode="light"][data-theme] {
|
|
598
|
+
@include theme-light-tokens;
|
|
599
|
+
|
|
600
|
+
--color-header: var(--color-light-header, var(--color-foreground));
|
|
601
|
+
--color-red: var(--color-light-red);
|
|
602
|
+
--color-orange: var(--color-light-orange);
|
|
603
|
+
--color-yellow: var(--color-light-yellow);
|
|
604
|
+
--color-green: var(--color-light-green);
|
|
605
|
+
--color-cyan: var(--color-light-cyan);
|
|
606
|
+
--color-blue: var(--color-light-blue);
|
|
607
|
+
--color-magenta: var(--color-light-magenta);
|
|
608
|
+
--color-link: var(--color-light-link);
|
|
609
|
+
--color-italic: var(--color-light-italic, var(--color-foreground));
|
|
610
|
+
--color-bold: var(--color-light-bold, var(--color-foreground));
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/* =====================================================================
|
|
614
|
+
STAGE 8: FALLBACKS — Graceful Degradation
|
|
615
|
+
Browsers without OKLCH support (Safari <16.4, Chrome <111, FF <113)
|
|
616
|
+
get concrete color values so the UI remains usable.
|
|
617
|
+
===================================================================== */
|
|
618
|
+
@supports not (color: oklch(50% 0.2 180)) {
|
|
619
|
+
#{$stnd-theme-scope} {
|
|
620
|
+
/* Concrete dark seeds */
|
|
621
|
+
--color-dark-background: #232323;
|
|
622
|
+
--color-dark-foreground: #d0d0d0;
|
|
623
|
+
|
|
624
|
+
/* Light palette fallbacks — standard hue positions */
|
|
625
|
+
--color-light-red: #c44040;
|
|
626
|
+
--color-light-orange: #b87020;
|
|
627
|
+
--color-light-yellow: #9a8520;
|
|
628
|
+
--color-light-green: #3a8a50;
|
|
629
|
+
--color-light-cyan: #2a8a8a;
|
|
630
|
+
--color-light-blue: #3a60b0;
|
|
631
|
+
--color-light-magenta: #9040a0;
|
|
632
|
+
--color-light-accent: #2a8a8a;
|
|
633
|
+
|
|
634
|
+
/* Dark palette fallbacks */
|
|
635
|
+
--color-dark-red: #e06060;
|
|
636
|
+
--color-dark-orange: #d09040;
|
|
637
|
+
--color-dark-yellow: #c0a840;
|
|
638
|
+
--color-dark-green: #60b070;
|
|
639
|
+
--color-dark-cyan: #50b0b0;
|
|
640
|
+
--color-dark-blue: #6080d0;
|
|
641
|
+
--color-dark-magenta: #b060c0;
|
|
642
|
+
--color-dark-accent: #50b0b0;
|
|
643
|
+
|
|
644
|
+
/* Computed fallbacks */
|
|
645
|
+
--color-muted: rgba(0, 0, 0, 0.6);
|
|
646
|
+
--color-subtle: rgba(0, 0, 0, 0.4);
|
|
647
|
+
--color-border: rgba(0, 0, 0, 0.1);
|
|
648
|
+
--color-surface: rgba(0, 0, 0, 0.03);
|
|
649
|
+
--color-shadow: rgba(0, 0, 0, 0.25);
|
|
650
|
+
--color-highlight: rgba(255, 255, 255, 0.6);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/* =====================================================================
|
|
655
|
+
STAGE 9: HIGH CONTRAST — Windows / forced-colors mode
|
|
656
|
+
===================================================================== */
|
|
657
|
+
@media (forced-colors: active) {
|
|
658
|
+
#{$stnd-theme-scope} {
|
|
659
|
+
--color-background: Canvas;
|
|
660
|
+
--color-foreground: CanvasText;
|
|
661
|
+
--color-accent: Highlight;
|
|
662
|
+
--color-border: CanvasText;
|
|
663
|
+
--color-muted: GrayText;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/* The Inverse Logic: Context-aware flipping */
|
|
668
|
+
.inverse {
|
|
669
|
+
/* Default: if root is light (either by system or choice), inverse is dark */
|
|
670
|
+
@include theme-dark-tokens;
|
|
671
|
+
|
|
672
|
+
/* If system is dark AND root hasn't forced light mode, root is dark, so inverse must be light */
|
|
673
|
+
@media (prefers-color-scheme: dark) {
|
|
674
|
+
#{$stnd-theme-scope}:not([data-color-mode="light"]) & {
|
|
675
|
+
@include theme-light-tokens;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/* If root explicitly forced dark mode, inverse must be light */
|
|
680
|
+
#{$stnd-theme-scope}[data-color-mode="dark"] & {
|
|
681
|
+
@include theme-light-tokens;
|
|
682
|
+
}
|
|
683
|
+
}
|