elvish-css 1.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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +518 -0
  3. package/dist/elvish.css +2194 -0
  4. package/dist/elvish.d.ts +78 -0
  5. package/dist/elvish.esm.js +2185 -0
  6. package/dist/elvish.iife.js +2169 -0
  7. package/dist/elvish.min.css +9 -0
  8. package/dist/elvish.umd.js +2173 -0
  9. package/elvish.css +28 -0
  10. package/elvish.js +81 -0
  11. package/global/global.css +16 -0
  12. package/global/modern.css +305 -0
  13. package/global/reset.css +507 -0
  14. package/global/tokens.css +154 -0
  15. package/global/transitions.css +288 -0
  16. package/global/transitions.js +289 -0
  17. package/global/utilities.css +151 -0
  18. package/package.json +61 -0
  19. package/primitives/adleithian/adleithian.css +16 -0
  20. package/primitives/adleithian/adleithian.js +63 -0
  21. package/primitives/bau/bau.css +86 -0
  22. package/primitives/bau/bau.js +127 -0
  23. package/primitives/enedh/enedh.css +38 -0
  24. package/primitives/enedh/enedh.js +110 -0
  25. package/primitives/esgal/esgal.css +39 -0
  26. package/primitives/esgal/esgal.js +115 -0
  27. package/primitives/fano/fano.css +28 -0
  28. package/primitives/fano/fano.js +108 -0
  29. package/primitives/gant-thala/gant-thala.css +32 -0
  30. package/primitives/gant-thala/gant-thala.js +69 -0
  31. package/primitives/glan-tholl/glan-tholl.css +71 -0
  32. package/primitives/glan-tholl/glan-tholl.js +147 -0
  33. package/primitives/glan-veleg/glan-veleg.css +45 -0
  34. package/primitives/glan-veleg/glan-veleg.js +138 -0
  35. package/primitives/gonath/gonath.css +57 -0
  36. package/primitives/gonath/gonath.js +113 -0
  37. package/primitives/gwistindor/gwistindor.css +52 -0
  38. package/primitives/gwistindor/gwistindor.js +96 -0
  39. package/primitives/hath/hath.css +39 -0
  40. package/primitives/hath/hath.js +107 -0
  41. package/primitives/him/him.css +43 -0
  42. package/primitives/him/him.js +169 -0
  43. package/primitives/miriant/miriant.css +75 -0
  44. package/primitives/miriant/miriant.js +158 -0
  45. package/primitives/thann/thann.css +57 -0
  46. package/primitives/thann/thann.js +96 -0
  47. package/primitives/tiniath/tiniath.css +16 -0
  48. package/primitives/tiniath/tiniath.js +88 -0
  49. package/primitives/vircantie/vircantie.css +24 -0
  50. package/primitives/vircantie/vircantie.js +83 -0
@@ -0,0 +1,507 @@
1
+ /**
2
+ * Elvish - Modern Reset & Axioms
3
+ *
4
+ * A synthesis of Andy Bell's "More Modern CSS Reset" and Elvish's original reset.
5
+ * Optimized for Chrome/Edge with graceful degradation for Safari/Firefox.
6
+ *
7
+ * Sources:
8
+ * - [AB] Andy Bell's "A (More) Modern CSS Reset"
9
+ * - [EL] Elvish original reset
10
+ * - [NEW] New additions for modern browsers
11
+ *
12
+ * Debug Mode:
13
+ * Add .mellon or .debug to <body> or any element to reveal layout structure.
14
+ * "Mellon" is Sindarin for "friend" - the password to enter Moria.
15
+ */
16
+
17
+ /* ==========================================================================
18
+ BOX SIZING [AB + EL]
19
+ Both resets agree. Universal consensus.
20
+ ========================================================================== */
21
+
22
+ *,
23
+ *::before,
24
+ *::after {
25
+ box-sizing: border-box;
26
+ }
27
+
28
+ /* ==========================================================================
29
+ BORDER & BACKGROUND DEFAULTS [EL + NEW]
30
+
31
+ Layout-focused philosophy: visual styling is opt-in, not opt-out.
32
+ - Borders: style is solid (for easy `border-width: 1px`), but width is 0
33
+ - Backgrounds: transparent by default
34
+ - This means elements are "invisible" until explicitly styled
35
+ ========================================================================== */
36
+
37
+ *,
38
+ *::before,
39
+ *::after {
40
+ /* Border: ready to use, but invisible by default */
41
+ border-style: solid;
42
+ border-width: 0;
43
+
44
+ /* Background: transparent until explicitly set */
45
+ background-color: transparent;
46
+ }
47
+
48
+ /* Root elements get the actual background */
49
+ html {
50
+ background-color: var(--color-surface);
51
+ }
52
+
53
+ /* ==========================================================================
54
+ MARGIN RESET [AB - expanded]
55
+
56
+ DISCARDED from Elvish: `* { margin: 0 }` is too aggressive.
57
+ It breaks nested lists, fieldset legends, and third-party components.
58
+
59
+ Andy Bell's surgical approach is safer - only reset elements that commonly
60
+ have problematic default margins. Expanded to include pre, h5, h6.
61
+ ========================================================================== */
62
+
63
+ body,
64
+ h1, h2, h3, h4, h5, h6,
65
+ p,
66
+ figure,
67
+ blockquote,
68
+ dl, dd,
69
+ pre,
70
+ fieldset {
71
+ margin: 0;
72
+ }
73
+
74
+ /* ==========================================================================
75
+ MEASURE AXIOM [EL]
76
+
77
+ Not in Andy Bell's reset - this is Elvish's core philosophy.
78
+
79
+ No line of text should exceed a comfortable reading length.
80
+ Exception-based: everything gets the constraint, then we remove it
81
+ from elements that need to contain multiple adjacent boxes.
82
+ ========================================================================== */
83
+
84
+ * {
85
+ max-inline-size: var(--measure);
86
+ }
87
+
88
+ html,
89
+ body,
90
+ div,
91
+ section,
92
+ article,
93
+ aside,
94
+ header,
95
+ footer,
96
+ nav,
97
+ main,
98
+ form,
99
+ fieldset,
100
+ figure,
101
+ figcaption,
102
+ picture,
103
+ video,
104
+ canvas,
105
+ iframe,
106
+ details,
107
+ summary,
108
+ dialog,
109
+ menu,
110
+ hgroup,
111
+ address,
112
+ /* Custom elements - Elvish layout primitives (Sindarin names) */
113
+ i-hath, /* Stack */
114
+ i-bau, /* Box */
115
+ i-enedh, /* Center (horizontal) */
116
+ i-tiniath, /* Cluster */
117
+ i-glan-veleg, /* Sidebar */
118
+ i-gwistindor, /* Switcher */
119
+ i-esgal, /* Cover (vertical center) */
120
+ i-vircantie, /* Grid */
121
+ i-gant-thala, /* Frame (aspect) */
122
+ i-glan-tholl, /* Reel (side-scrolling) */
123
+ i-fano, /* Imposter (overlay) */
124
+ i-thann, /* Icon */
125
+ i-adleithian, /* Container */
126
+ i-him, /* Sticky */
127
+ i-miriant, /* Grid-placed */
128
+ i-gonath { /* Masonry */
129
+ max-inline-size: none;
130
+ }
131
+
132
+ /* ==========================================================================
133
+ ROOT DEFAULTS [AB + EL + NEW]
134
+ ========================================================================== */
135
+
136
+ html {
137
+ /* [EL] Font settings via design tokens */
138
+ font-family: var(--font-plain);
139
+ font-size: 100%; /* Respects user preferences */
140
+ line-height: var(--line-height);
141
+
142
+ /* [EL] Colors */
143
+ color: var(--color-text);
144
+ /* background-color set above in BORDER & BACKGROUND DEFAULTS */
145
+
146
+ /* [NEW] Text rendering - prioritize legibility */
147
+ text-rendering: optimizeLegibility;
148
+ -webkit-font-smoothing: antialiased;
149
+ -moz-osx-font-smoothing: grayscale;
150
+
151
+ /* [NEW] Prevent text size inflation on mobile */
152
+ -webkit-text-size-adjust: 100%;
153
+ text-size-adjust: 100%;
154
+ }
155
+
156
+ /* [AB] Smooth scrolling ONLY when using keyboard navigation */
157
+ @media (prefers-reduced-motion: no-preference) {
158
+ html:focus-within {
159
+ scroll-behavior: smooth;
160
+ }
161
+ }
162
+
163
+ /* ==========================================================================
164
+ BODY DEFAULTS [EL + NEW]
165
+ ========================================================================== */
166
+
167
+ body {
168
+ /* [EL] Full viewport height - dvh accounts for mobile browser chrome */
169
+ min-block-size: 100vh;
170
+ min-block-size: 100dvh;
171
+
172
+ /* [NEW] Prevent horizontal overflow from animations, etc. */
173
+ overflow-x: clip;
174
+
175
+ /* Body gets the surface background */
176
+ background-color: var(--color-surface);
177
+ }
178
+
179
+ /* ==========================================================================
180
+ TYPOGRAPHY [EL + NEW]
181
+ ========================================================================== */
182
+
183
+ h1, h2, h3, h4, h5, h6 {
184
+ /* [EL] Tighter line height for headings */
185
+ line-height: var(--line-height-tight);
186
+
187
+ /* [NEW] Balanced wrapping for headings (Chrome 114+, Safari 17.5+) */
188
+ text-wrap: balance;
189
+ }
190
+
191
+ /* [EL] Modular scale sizing */
192
+ h1 { font-size: var(--s4); }
193
+ h2 { font-size: var(--s3); }
194
+ h3 { font-size: var(--s2); }
195
+ h4 { font-size: var(--s1); }
196
+ h5 { font-size: var(--s0); }
197
+ h6 { font-size: var(--s-1); }
198
+
199
+ /* [NEW] Pretty wrapping for prose (Chrome 117+) */
200
+ p {
201
+ text-wrap: pretty;
202
+ }
203
+
204
+ /* ==========================================================================
205
+ LINKS [AB + EL]
206
+ ========================================================================== */
207
+
208
+ a {
209
+ /* [EL] Inherit color - style via classes or context */
210
+ color: currentColor;
211
+
212
+ /* [AB] Better underline rendering - skips descenders (g, y, p) */
213
+ text-decoration-skip-ink: auto;
214
+
215
+ /* [NEW] Modern underline offset for readability */
216
+ text-underline-offset: 0.2em;
217
+ }
218
+
219
+ /* [EL] Remove underline on hover */
220
+ a:hover {
221
+ text-decoration: none;
222
+ }
223
+
224
+ /* [NEW] Focus styles for keyboard navigation */
225
+ a:focus-visible {
226
+ outline: 2px solid var(--color-accent, currentColor);
227
+ outline-offset: 2px;
228
+ }
229
+
230
+ /* ==========================================================================
231
+ MEDIA [EL - expanded from AB]
232
+ ========================================================================== */
233
+
234
+ img,
235
+ picture,
236
+ video,
237
+ canvas,
238
+ svg {
239
+ display: block;
240
+ max-inline-size: 100%;
241
+ }
242
+
243
+ img,
244
+ picture,
245
+ video {
246
+ /* [EL] Maintain aspect ratio */
247
+ block-size: auto;
248
+ }
249
+
250
+ /* [NEW] Style for alt text when image fails to load */
251
+ img {
252
+ font-style: italic;
253
+ vertical-align: middle;
254
+ }
255
+
256
+ /* ==========================================================================
257
+ FORM ELEMENTS [AB + EL]
258
+ ========================================================================== */
259
+
260
+ input,
261
+ button,
262
+ textarea,
263
+ select {
264
+ /* [AB + EL] Inherit font from parent */
265
+ font: inherit;
266
+ /* [EL] Inherit color too */
267
+ color: inherit;
268
+ }
269
+
270
+ /* [EL] Indicate buttons are clickable */
271
+ button,
272
+ [role="button"] {
273
+ cursor: pointer;
274
+ }
275
+
276
+ /* [NEW] Textarea should not resize horizontally */
277
+ textarea {
278
+ resize: vertical;
279
+ }
280
+
281
+ /* ==========================================================================
282
+ LISTS [EL - modified]
283
+ ========================================================================== */
284
+
285
+ ul,
286
+ ol {
287
+ list-style: none;
288
+ padding: 0;
289
+ margin: 0;
290
+ }
291
+
292
+ /* [NEW] Restore list styles when explicitly marked for semantics */
293
+ ul[role="list"],
294
+ ol[role="list"],
295
+ ul.list,
296
+ ol.list {
297
+ list-style: revert;
298
+ padding-inline-start: 1em;
299
+ }
300
+
301
+ /* ==========================================================================
302
+ TABLES [EL]
303
+ ========================================================================== */
304
+
305
+ table {
306
+ border-collapse: collapse;
307
+ border-spacing: 0;
308
+ }
309
+
310
+ /* [NEW] Inherit text alignment */
311
+ th {
312
+ text-align: inherit;
313
+ font-weight: inherit;
314
+ }
315
+
316
+ /* ==========================================================================
317
+ CODE [EL]
318
+ ========================================================================== */
319
+
320
+ pre,
321
+ code,
322
+ kbd,
323
+ samp {
324
+ font-family: var(--font-mono);
325
+ }
326
+
327
+ pre {
328
+ overflow-x: auto;
329
+ white-space: pre;
330
+ }
331
+
332
+ /* ==========================================================================
333
+ MISC ELEMENTS [EL + NEW]
334
+ ========================================================================== */
335
+
336
+ /* [EL] Horizontal rule */
337
+ hr {
338
+ border-width: var(--border-thin, 1px) 0 0 0;
339
+ color: inherit;
340
+ block-size: 0;
341
+ }
342
+
343
+ /* [NEW] Abbreviations with title should indicate expandability */
344
+ abbr[title] {
345
+ text-decoration: underline dotted;
346
+ cursor: help;
347
+ }
348
+
349
+ /* [NEW] Summary cursor */
350
+ summary {
351
+ cursor: pointer;
352
+ }
353
+
354
+ /* ==========================================================================
355
+ SELECTION [NEW]
356
+ ========================================================================== */
357
+
358
+ ::selection {
359
+ background-color: var(--color-accent, highlight);
360
+ color: var(--color-accent-text, highlighttext);
361
+ }
362
+
363
+ /* ==========================================================================
364
+ FOCUS STATES [NEW]
365
+ ========================================================================== */
366
+
367
+ /* Remove default focus outline */
368
+ :focus {
369
+ outline: none;
370
+ }
371
+
372
+ /* Visible focus for keyboard navigation only */
373
+ :focus-visible {
374
+ outline: 2px solid var(--color-accent, currentColor);
375
+ outline-offset: 2px;
376
+ }
377
+
378
+ /* ==========================================================================
379
+ REDUCED MOTION [AB - expanded]
380
+ ========================================================================== */
381
+
382
+ @media (prefers-reduced-motion: reduce) {
383
+ *,
384
+ *::before,
385
+ *::after {
386
+ /* [AB] Kill all animations */
387
+ animation-duration: 0.01ms !important;
388
+ animation-iteration-count: 1 !important;
389
+
390
+ /* [AB] Kill all transitions */
391
+ transition-duration: 0.01ms !important;
392
+
393
+ /* [AB] Kill smooth scrolling */
394
+ scroll-behavior: auto !important;
395
+ }
396
+
397
+ /* [NEW] Also target View Transitions */
398
+ ::view-transition-group(*),
399
+ ::view-transition-old(*),
400
+ ::view-transition-new(*) {
401
+ animation: none !important;
402
+ }
403
+ }
404
+
405
+ /* ==========================================================================
406
+ DEBUG MODE - "MELLON" [NEW]
407
+
408
+ Add .mellon or .debug to <body> or any element to reveal layout structure.
409
+ "Mellon" is Sindarin for "friend" - the password to enter Moria.
410
+
411
+ Features:
412
+ - Dashed outlines show element boundaries (uses outline, not border)
413
+ - Each nesting level gets a different hue (rainbow effect)
414
+ - Optional .tint modifier adds subtle background colors
415
+ - Zero specificity via :where() - easily overridden by real styles
416
+
417
+ Usage:
418
+ <body class="mellon"> - Debug entire page
419
+ <body class="mellon tint"> - Debug with background tints
420
+ <div class="debug"> - Debug specific section
421
+ ========================================================================== */
422
+
423
+ /* Debug color tokens */
424
+ :root {
425
+ --debug-stroke: 1px;
426
+ --debug-style: dashed;
427
+ --debug-saturation: 0.25;
428
+ --debug-lightness: 55%;
429
+ }
430
+
431
+ /* Calculate hue based on depth (golden angle ≈ 137.5° for optimal distribution) */
432
+ :where(.mellon, .debug),
433
+ :where(.mellon, .debug) :where(*) {
434
+ --debug-hue: 0;
435
+ }
436
+
437
+ :where(.mellon, .debug) > :where(*) { --debug-hue: 137; }
438
+ :where(.mellon, .debug) > :where(*) > :where(*) { --debug-hue: 275; }
439
+ :where(.mellon, .debug) > :where(*) > :where(*) > :where(*) { --debug-hue: 52; }
440
+ :where(.mellon, .debug) > :where(*) > :where(*) > :where(*) > :where(*) { --debug-hue: 190; }
441
+ :where(.mellon, .debug) > :where(*) > :where(*) > :where(*) > :where(*) > :where(*) { --debug-hue: 327; }
442
+ :where(.mellon, .debug) > :where(*) > :where(*) > :where(*) > :where(*) > :where(*) > :where(*) { --debug-hue: 105; }
443
+
444
+ /* Show outlines in debug mode */
445
+ :where(.mellon, .debug),
446
+ :where(.mellon, .debug) :where(*) {
447
+ outline: var(--debug-stroke) var(--debug-style)
448
+ oklch(var(--debug-lightness) var(--debug-saturation) var(--debug-hue, 0)) !important;
449
+ outline-offset: -1px;
450
+ }
451
+
452
+ /* Highlight Elvish primitives more prominently */
453
+ :where(.mellon, .debug) :where(
454
+ i-hath, i-bau, i-enedh, i-tiniath, i-glan-veleg, i-gwistindor,
455
+ i-esgal, i-vircantie, i-gant-thala, i-glan-tholl, i-fano, i-thann,
456
+ i-adleithian, i-him, i-miriant, i-gonath
457
+ ) {
458
+ --debug-stroke: 2px;
459
+ --debug-style: solid;
460
+ --debug-saturation: 0.4;
461
+ }
462
+
463
+ /* Optional: Background tint mode */
464
+ :where(.mellon.tint, .debug.tint),
465
+ :where(.mellon.tint, .debug.tint) :where(*) {
466
+ background-color: oklch(
467
+ var(--debug-lightness)
468
+ calc(var(--debug-saturation) * 0.4)
469
+ var(--debug-hue, 0)
470
+ / 0.1
471
+ ) !important;
472
+ }
473
+
474
+ /* ==========================================================================
475
+ UTILITIES [EL + NEW]
476
+ ========================================================================== */
477
+
478
+ /* [EL] Hidden but accessible to screen readers */
479
+ .visually-hidden,
480
+ .sr-only {
481
+ position: absolute;
482
+ inline-size: 1px;
483
+ block-size: 1px;
484
+ padding: 0;
485
+ margin: -1px;
486
+ overflow: hidden;
487
+ clip: rect(0, 0, 0, 0);
488
+ clip-path: inset(50%);
489
+ white-space: nowrap;
490
+ border: 0;
491
+ }
492
+
493
+ /* [NEW] Skip link pattern for accessibility */
494
+ .skip-link {
495
+ position: absolute;
496
+ inset-inline-start: 0;
497
+ inset-block-start: 0;
498
+ padding: var(--s-1, 0.5rem) var(--s0, 1rem);
499
+ background: var(--color-accent, highlight);
500
+ color: var(--color-accent-text, highlighttext);
501
+ transform: translateY(-100%);
502
+ z-index: 9999;
503
+ }
504
+
505
+ .skip-link:focus {
506
+ transform: translateY(0);
507
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Elvish - Design Tokens
3
+ *
4
+ * Modular scale and design tokens for consistent spacing,
5
+ * typography, and colors throughout the system.
6
+ *
7
+ * Uses modern CSS features:
8
+ * - light-dark() for automatic theme switching
9
+ * - Relative color syntax (oklch) for derived colors
10
+ *
11
+ * RATIO MODES:
12
+ * - golden (φ = 1.618): Classical, dramatic, organic - best for CTAs & impact
13
+ * - silver (√2 = 1.414): Subtle, modern, ISO paper ratios - best for dense content
14
+ * - fifth (1.5): Musical, balanced middle-ground
15
+ *
16
+ * To change: set --ratio-mode on :root or any container
17
+ * :root { --ratio-mode: silver; }
18
+ * .documentation { --ratio-mode: silver; }
19
+ */
20
+
21
+ :root {
22
+ /* ===== COLOR SCHEME ===== */
23
+ color-scheme: light dark;
24
+
25
+ /* ===== RATIO PRESETS ===== */
26
+ --ratio-golden: 1.618; /* φ - Golden Ratio */
27
+ --ratio-silver: 1.414; /* √2 - Silver/Lichtenberg Ratio */
28
+ --ratio-fifth: 1.5; /* Perfect Fifth (musical) */
29
+
30
+ /* ===== ACTIVE RATIO ===== */
31
+ /* Default: Perfect Fifth for balanced harmony */
32
+ --ratio: var(--ratio-fifth);
33
+
34
+ /* ===== MODULAR SCALE ===== */
35
+ /*
36
+ * Golden Ratio scale at 16px base:
37
+ * s-2: 6px | s-1: 10px | s0: 16px (base)
38
+ * s1: 26px | s2: 42px | s3: 68px
39
+ * s4: 110px | s5: 178px
40
+ */
41
+ --s-5: calc(var(--s-4) / var(--ratio));
42
+ --s-4: calc(var(--s-3) / var(--ratio));
43
+ --s-3: calc(var(--s-2) / var(--ratio));
44
+ --s-2: calc(var(--s-1) / var(--ratio));
45
+ --s-1: calc(var(--s0) / var(--ratio));
46
+ --s0: 1rem;
47
+ --s1: calc(var(--s0) * var(--ratio));
48
+ --s2: calc(var(--s1) * var(--ratio));
49
+ --s3: calc(var(--s2) * var(--ratio));
50
+ --s4: calc(var(--s3) * var(--ratio));
51
+ --s5: calc(var(--s4) * var(--ratio));
52
+
53
+ /* ===== MEASURE (Text) ===== */
54
+ /* Maximum line length for readable text - varies by ratio */
55
+ --measure: 70ch; /* Default for Fifth; Golden=60ch, Silver=80ch */
56
+
57
+ /* ===== LAYOUT THRESHOLDS ===== */
58
+ /*
59
+ * These are for LAYOUT decisions, not text readability.
60
+ * Use rem (not ch) because layout is about physical space, not characters.
61
+ */
62
+ --layout-threshold-sm: 30rem; /* ~480px - phone landscape */
63
+ --layout-threshold-md: 45rem; /* ~720px - tablet portrait */
64
+ --layout-threshold-lg: 60rem; /* ~960px - tablet landscape */
65
+ --layout-threshold-xl: 75rem; /* ~1200px - small desktop */
66
+
67
+ /* ===== BRAND COLOR (Single source of truth) ===== */
68
+ /* Teal: rgba(0, 233, 188, 1) converted to OKLCH */
69
+ --brand: oklch(83% 0.17 168);
70
+
71
+ /* ===== DERIVED COLORS (Relative Color Syntax) ===== */
72
+ /* Lighten/darken by adjusting L (lightness) */
73
+ --brand-lighter: oklch(from var(--brand) calc(l + 0.3) c h);
74
+ --brand-light: oklch(from var(--brand) calc(l + 0.15) c h);
75
+ --brand-dark: oklch(from var(--brand) calc(l - 0.1) c h);
76
+ --brand-darker: oklch(from var(--brand) calc(l - 0.2) c h);
77
+
78
+ /* Desaturate by reducing C (chroma) */
79
+ --brand-muted: oklch(from var(--brand) l calc(c * 0.5) h);
80
+ --brand-subtle: oklch(from var(--brand) l calc(c * 0.25) h);
81
+
82
+ /* Transparency variants */
83
+ --brand-ghost: oklch(from var(--brand) l c h / 0.1);
84
+ --brand-overlay: oklch(from var(--brand) l c h / 0.85);
85
+
86
+ /* Complementary/Analogous via hue shift */
87
+ --brand-complement: oklch(from var(--brand) l c calc(h + 180));
88
+ --brand-analogous-1: oklch(from var(--brand) l c calc(h + 30));
89
+ --brand-analogous-2: oklch(from var(--brand) l c calc(h - 30));
90
+
91
+ /* ===== SEMANTIC COLORS (light-dark auto-switching) ===== */
92
+ --color-surface: light-dark(#ffffff, #1a1a2e);
93
+ --color-surface-raised: light-dark(#f8f9fa, #252538);
94
+ --color-surface-sunken: light-dark(#e9ecef, #12121c);
95
+
96
+ --color-text: light-dark(#1a1a2e, #f0f0f5);
97
+ --color-text-muted: light-dark(#6c757d, #9ca3af);
98
+ --color-text-subtle: light-dark(#adb5bd, #6b7280);
99
+
100
+ --color-border: light-dark(#dee2e6, #374151);
101
+ --color-border-strong: light-dark(#adb5bd, #4b5563);
102
+
103
+ /* Accent adapts to theme */
104
+ --color-accent: light-dark(
105
+ oklch(from var(--brand) calc(l - 0.05) c h),
106
+ oklch(from var(--brand) calc(l + 0.1) c h)
107
+ );
108
+ --color-accent-hover: light-dark(
109
+ oklch(from var(--brand) calc(l - 0.15) c h),
110
+ oklch(from var(--brand) calc(l + 0.2) c h)
111
+ );
112
+ --color-accent-text: light-dark(#ffffff, #1a1a2e);
113
+
114
+ /* Status colors */
115
+ --color-success: light-dark(oklch(55% 0.17 145), oklch(65% 0.17 145));
116
+ --color-warning: light-dark(oklch(70% 0.15 85), oklch(75% 0.15 85));
117
+ --color-danger: light-dark(oklch(55% 0.2 25), oklch(65% 0.2 25));
118
+ --color-info: light-dark(oklch(55% 0.15 230), oklch(65% 0.15 230));
119
+
120
+ /* Legacy aliases for backward compatibility */
121
+ --color-dark: var(--color-text);
122
+ --color-light: var(--color-surface);
123
+ --color-mid: var(--color-text-muted);
124
+
125
+ /* ===== BORDERS ===== */
126
+ --border-thin: 1px;
127
+ --border-thick: 3px;
128
+
129
+ /* ===== FONTS ===== */
130
+ --font-plain: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
131
+ --font-mono: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, monospace;
132
+
133
+ /* ===== LINE HEIGHT ===== */
134
+ --line-height: 1.5;
135
+ --line-height-tight: 1.2;
136
+ --line-height-loose: 1.8;
137
+
138
+ /* ===== TIMING ===== */
139
+ --duration-instant: 100ms;
140
+ --duration-fast: 200ms;
141
+ --duration-normal: 300ms;
142
+ --duration-slow: 500ms;
143
+
144
+ /* ===== EASING ===== */
145
+ --ease-out: cubic-bezier(0, 0, 0.2, 1);
146
+ --ease-in: cubic-bezier(0.4, 0, 1, 1);
147
+ --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
148
+ --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
149
+
150
+ /* Legacy transition shortcuts */
151
+ --transition-fast: var(--duration-fast) var(--ease-out);
152
+ --transition-medium: var(--duration-normal) var(--ease-out);
153
+ --transition-slow: var(--duration-slow) var(--ease-out);
154
+ }