@digiko-npm/designsystem 0.1.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 (47) hide show
  1. package/README.md +89 -0
  2. package/dist/designsystem.css +4642 -0
  3. package/dist/designsystem.js +67 -0
  4. package/package.json +32 -0
  5. package/src/base/index.css +2 -0
  6. package/src/base/reset.css +120 -0
  7. package/src/base/typography.css +163 -0
  8. package/src/components/accordion.css +150 -0
  9. package/src/components/alert.css +150 -0
  10. package/src/components/avatar.css +109 -0
  11. package/src/components/badge.css +80 -0
  12. package/src/components/breadcrumb.css +95 -0
  13. package/src/components/button.css +168 -0
  14. package/src/components/card.css +121 -0
  15. package/src/components/command.css +185 -0
  16. package/src/components/divider.css +66 -0
  17. package/src/components/drawer.css +209 -0
  18. package/src/components/dropdown.css +139 -0
  19. package/src/components/empty-state.css +69 -0
  20. package/src/components/index.css +35 -0
  21. package/src/components/input.css +116 -0
  22. package/src/components/kbd.css +55 -0
  23. package/src/components/modal.css +103 -0
  24. package/src/components/nav.css +153 -0
  25. package/src/components/pagination.css +166 -0
  26. package/src/components/popover.css +112 -0
  27. package/src/components/progress.css +214 -0
  28. package/src/components/skeleton.css +96 -0
  29. package/src/components/slider.css +125 -0
  30. package/src/components/table.css +48 -0
  31. package/src/components/tabs.css +163 -0
  32. package/src/components/tag.css +159 -0
  33. package/src/components/timeline.css +131 -0
  34. package/src/components/toast.css +70 -0
  35. package/src/components/toggle.css +135 -0
  36. package/src/components/tooltip.css +161 -0
  37. package/src/index.css +19 -0
  38. package/src/js/theme.js +67 -0
  39. package/src/tokens/colors.css +180 -0
  40. package/src/tokens/index.css +11 -0
  41. package/src/tokens/shadows.css +26 -0
  42. package/src/tokens/spacing.css +53 -0
  43. package/src/tokens/typography.css +51 -0
  44. package/src/utilities/index.css +3 -0
  45. package/src/utilities/layout.css +134 -0
  46. package/src/utilities/spacing.css +75 -0
  47. package/src/utilities/text.css +221 -0
@@ -0,0 +1,4642 @@
1
+ /* @ds/designsystem v0.1.0 */
2
+ /* ==========================================================================
3
+ @ds/designsystem
4
+
5
+ Import this one file to get everything.
6
+ Or import individual layers for fine-grained control:
7
+
8
+ import '@ds/designsystem/tokens'
9
+ import '@ds/designsystem/base'
10
+ import '@ds/designsystem/components'
11
+ import '@ds/designsystem/utilities'
12
+
13
+ To customize: override any --ds-* variable in your project CSS.
14
+ Your values always win. Nothing breaks.
15
+ ========================================================================== */
16
+
17
+ /* ==========================================================================
18
+ Design Tokens — All tokens in one import
19
+
20
+ To override: just redeclare any --ds-* variable in your project's CSS.
21
+ Your values win. Nothing breaks.
22
+ ========================================================================== */
23
+
24
+ /* ==========================================================================
25
+ Design Tokens: Colors
26
+ Refined zinc palette, editorial warmth.
27
+ Light-first with elegant dark mode. Override any --ds-* variable to re-theme.
28
+ ========================================================================== */
29
+
30
+ /* Light theme (default) */
31
+ :root,
32
+ [data-theme="light"] {
33
+ /* --- Backgrounds — clean whites, warm grays --- */
34
+ --ds-color-bg: #fafafa;
35
+ --ds-color-bg-subtle: #ffffff;
36
+ --ds-color-bg-muted: #e4e4e7;
37
+ --ds-color-bg-elevated: #f4f4f5;
38
+
39
+ --ds-color-surface: #ffffff;
40
+ --ds-color-surface-hover: #fafafa;
41
+ --ds-color-surface-active: #f4f4f5;
42
+
43
+ /* --- Text — zinc hierarchy --- */
44
+ --ds-color-text: #09090b;
45
+ --ds-color-text-secondary: #52525b;
46
+ --ds-color-text-tertiary: #a1a1aa;
47
+ --ds-color-text-disabled: #d4d4d8;
48
+
49
+ /* --- Inverted (primary buttons: dark bg + light text) --- */
50
+ --ds-color-inverted: #18181b;
51
+ --ds-color-on-inverted: #fafafa;
52
+
53
+ /* --- Borders — solid zinc --- */
54
+ --ds-color-border: #e4e4e7;
55
+ --ds-color-border-hover: #d4d4d8;
56
+ --ds-color-border-active: #a1a1aa;
57
+ --ds-color-border-subtle: #f4f4f5;
58
+
59
+ /* --- Interactive --- */
60
+ --ds-color-interactive: #3f3f46;
61
+ --ds-color-interactive-hover: #27272a;
62
+
63
+ /* --- Overlays --- */
64
+ --ds-color-overlay: rgba(0, 0, 0, 0.5);
65
+ --ds-color-overlay-subtle: rgba(0, 0, 0, 0.02);
66
+ --ds-color-overlay-hover: rgba(0, 0, 0, 0.04);
67
+ --ds-color-overlay-active: rgba(0, 0, 0, 0.08);
68
+
69
+ /* --- Navigation (glass effect) --- */
70
+ --ds-color-nav-bg: rgba(250, 250, 250, 0.8);
71
+ --ds-color-nav-border: rgba(228, 228, 231, 0.6);
72
+
73
+ /* --- Selection --- */
74
+ --ds-color-selection-bg: #09090b;
75
+ --ds-color-selection-text: #fafafa;
76
+
77
+ /* --- Shadows --- */
78
+ --ds-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
79
+ --ds-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
80
+ --ds-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12);
81
+
82
+ /* --- Scrollbar --- */
83
+ --ds-scrollbar-thumb: #d4d4d4;
84
+ --ds-scrollbar-thumb-hover: #a3a3a3;
85
+
86
+ color-scheme: light;
87
+ }
88
+
89
+ /* Dark theme */
90
+ [data-theme="dark"] {
91
+ /* --- Backgrounds — deep, refined zinc-900 palette --- */
92
+ --ds-color-bg: #09090b;
93
+ --ds-color-bg-subtle: #0f0f11;
94
+ --ds-color-bg-muted: #27272a;
95
+ --ds-color-bg-elevated: #18181b;
96
+
97
+ --ds-color-surface: #0f0f11;
98
+ --ds-color-surface-hover: #18181b;
99
+ --ds-color-surface-active: #27272a;
100
+
101
+ /* --- Text --- */
102
+ --ds-color-text: #fafafa;
103
+ --ds-color-text-secondary: #a1a1aa;
104
+ --ds-color-text-tertiary: #52525b;
105
+ --ds-color-text-disabled: #3f3f46;
106
+
107
+ /* --- Inverted (primary buttons: light bg + dark text) --- */
108
+ --ds-color-inverted: #fafafa;
109
+ --ds-color-on-inverted: #09090b;
110
+
111
+ /* --- Borders --- */
112
+ --ds-color-border: #27272a;
113
+ --ds-color-border-hover: #3f3f46;
114
+ --ds-color-border-active: #52525b;
115
+ --ds-color-border-subtle: #18181b;
116
+
117
+ /* --- Interactive --- */
118
+ --ds-color-interactive: #d4d4d8;
119
+ --ds-color-interactive-hover: #fafafa;
120
+
121
+ /* --- Overlays --- */
122
+ --ds-color-overlay: rgba(0, 0, 0, 0.7);
123
+ --ds-color-overlay-subtle: rgba(255, 255, 255, 0.03);
124
+ --ds-color-overlay-hover: rgba(255, 255, 255, 0.06);
125
+ --ds-color-overlay-active: rgba(255, 255, 255, 0.1);
126
+
127
+ /* --- Navigation --- */
128
+ --ds-color-nav-bg: rgba(9, 9, 11, 0.8);
129
+ --ds-color-nav-border: rgba(39, 39, 42, 0.6);
130
+
131
+ /* --- Selection --- */
132
+ --ds-color-selection-bg: #fafafa;
133
+ --ds-color-selection-text: #09090b;
134
+
135
+ /* --- Shadows (stronger in dark) --- */
136
+ --ds-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.2);
137
+ --ds-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.3);
138
+ --ds-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.4);
139
+
140
+ /* --- Scrollbar --- */
141
+ --ds-scrollbar-thumb: #27272a;
142
+ --ds-scrollbar-thumb-hover: #3f3f46;
143
+
144
+ color-scheme: dark;
145
+ }
146
+
147
+ /* Shared tokens (same in both themes) */
148
+ :root {
149
+ /* --- Semantic Status --- */
150
+ --ds-color-success: #16a34a;
151
+ --ds-color-success-subtle: rgba(22, 163, 74, 0.1);
152
+ --ds-color-success-border: rgba(22, 163, 74, 0.2);
153
+
154
+ --ds-color-warning: #d97706;
155
+ --ds-color-warning-subtle: rgba(217, 119, 6, 0.1);
156
+ --ds-color-warning-border: rgba(217, 119, 6, 0.2);
157
+
158
+ --ds-color-error: #dc2626;
159
+ --ds-color-error-subtle: rgba(220, 38, 38, 0.1);
160
+ --ds-color-error-border: rgba(220, 38, 38, 0.2);
161
+
162
+ --ds-color-info: #2563eb;
163
+ --ds-color-info-subtle: rgba(37, 99, 235, 0.1);
164
+ --ds-color-info-border: rgba(37, 99, 235, 0.2);
165
+
166
+ /* --- Accent Colors (for badges, categories) --- */
167
+ --ds-color-accent-blue: #2563eb;
168
+ --ds-color-accent-purple: #7c3aed;
169
+ --ds-color-accent-green: #16a34a;
170
+ --ds-color-accent-orange: #d97706;
171
+ --ds-color-accent-blue-subtle: rgba(37, 99, 235, 0.1);
172
+ --ds-color-accent-purple-subtle: rgba(124, 58, 237, 0.1);
173
+ --ds-color-accent-green-subtle: rgba(22, 163, 74, 0.1);
174
+ --ds-color-accent-orange-subtle: rgba(217, 119, 6, 0.1);
175
+ }
176
+
177
+ /* Dark overrides for status/accent (brighter for contrast) */
178
+ [data-theme="dark"] {
179
+ --ds-color-success: #4ade80;
180
+ --ds-color-success-subtle: rgba(74, 222, 128, 0.1);
181
+ --ds-color-success-border: rgba(74, 222, 128, 0.2);
182
+
183
+ --ds-color-warning: #fbbf24;
184
+ --ds-color-warning-subtle: rgba(251, 191, 36, 0.1);
185
+ --ds-color-warning-border: rgba(251, 191, 36, 0.2);
186
+
187
+ --ds-color-error: #f87171;
188
+ --ds-color-error-subtle: rgba(248, 113, 113, 0.1);
189
+ --ds-color-error-border: rgba(248, 113, 113, 0.2);
190
+
191
+ --ds-color-info: #60a5fa;
192
+ --ds-color-info-subtle: rgba(96, 165, 250, 0.1);
193
+ --ds-color-info-border: rgba(96, 165, 250, 0.2);
194
+
195
+ --ds-color-accent-blue: #60a5fa;
196
+ --ds-color-accent-purple: #a78bfa;
197
+ --ds-color-accent-green: #4ade80;
198
+ --ds-color-accent-orange: #fbbf24;
199
+ --ds-color-accent-blue-subtle: rgba(96, 165, 250, 0.1);
200
+ --ds-color-accent-purple-subtle: rgba(167, 139, 250, 0.1);
201
+ --ds-color-accent-green-subtle: rgba(74, 222, 128, 0.1);
202
+ --ds-color-accent-orange-subtle: rgba(251, 191, 36, 0.1);
203
+ }
204
+
205
+ /* ==========================================================================
206
+ Design Tokens: Typography
207
+ Clash Display headings, Switzer body.
208
+ Editorial feel, generous sizing, tight tracking on display.
209
+ ========================================================================== */
210
+
211
+ :root {
212
+ /* --- Font Families ---
213
+ Override these in your project to use your own fonts.
214
+ The DS provides the architecture; you bring the typeface. */
215
+ --ds-font-display: "Clash Display", system-ui, sans-serif;
216
+ --ds-font-sans: "Switzer", system-ui, -apple-system, sans-serif;
217
+ --ds-font-mono: "Geist Mono", ui-monospace, "SF Mono", monospace;
218
+
219
+ /* --- Display Font Weight (Clash Display looks best at 400) --- */
220
+ --ds-font-display-weight: 400;
221
+
222
+ /* --- Font Sizes --- */
223
+ --ds-text-xs: 0.75rem; /* 12px */
224
+ --ds-text-sm: 0.875rem; /* 14px */
225
+ --ds-text-base: 1rem; /* 16px */
226
+ --ds-text-lg: 1.125rem; /* 18px */
227
+ --ds-text-xl: 1.25rem; /* 20px */
228
+ --ds-text-2xl: 1.5rem; /* 24px */
229
+ --ds-text-3xl: 1.875rem; /* 30px */
230
+ --ds-text-4xl: 2.25rem; /* 36px */
231
+ --ds-text-5xl: 3rem; /* 48px */
232
+ --ds-text-6xl: 3.75rem; /* 60px */
233
+ --ds-text-7xl: 4.5rem; /* 72px */
234
+
235
+ /* --- Font Weights --- */
236
+ --ds-weight-light: 300;
237
+ --ds-weight-normal: 400;
238
+ --ds-weight-medium: 500;
239
+ --ds-weight-semibold: 600;
240
+ --ds-weight-bold: 700;
241
+
242
+ /* --- Line Heights --- */
243
+ --ds-leading-none: 1;
244
+ --ds-leading-tight: 1.1;
245
+ --ds-leading-snug: 1.25;
246
+ --ds-leading-normal: 1.5;
247
+ --ds-leading-relaxed: 1.625;
248
+ --ds-leading-loose: 2;
249
+
250
+ /* --- Letter Spacing --- */
251
+ --ds-tracking-tighter: -0.02em;
252
+ --ds-tracking-tight: -0.01em;
253
+ --ds-tracking-normal: 0;
254
+ --ds-tracking-wide: 0.05em;
255
+ }
256
+
257
+ /* ==========================================================================
258
+ Design Tokens: Spacing & Layout
259
+ Generous whitespace, responsive sections.
260
+ ========================================================================== */
261
+
262
+ :root {
263
+ /* --- Spacing Scale --- */
264
+ --ds-space-0: 0;
265
+ --ds-space-0-5: 0.125rem; /* 2px */
266
+ --ds-space-1: 0.25rem; /* 4px */
267
+ --ds-space-1-5: 0.375rem; /* 6px */
268
+ --ds-space-2: 0.5rem; /* 8px */
269
+ --ds-space-2-5: 0.625rem; /* 10px */
270
+ --ds-space-3: 0.75rem; /* 12px */
271
+ --ds-space-4: 1rem; /* 16px */
272
+ --ds-space-5: 1.25rem; /* 20px */
273
+ --ds-space-6: 1.5rem; /* 24px */
274
+ --ds-space-8: 2rem; /* 32px */
275
+ --ds-space-10: 2.5rem; /* 40px */
276
+ --ds-space-12: 3rem; /* 48px */
277
+ --ds-space-16: 4rem; /* 64px */
278
+ --ds-space-20: 5rem; /* 80px */
279
+ --ds-space-24: 6rem; /* 96px */
280
+ --ds-space-32: 8rem; /* 128px */
281
+
282
+ /* --- Section Padding (responsive, generous) --- */
283
+ --ds-section-padding: clamp(80px, 12vw, 160px);
284
+
285
+ /* --- Container --- */
286
+ --ds-container-max: 1200px;
287
+ --ds-container-padding: clamp(20px, 5vw, 80px);
288
+ --ds-container-sm: 640px;
289
+ --ds-container-md: 768px;
290
+ --ds-container-lg: 1024px;
291
+
292
+ /* --- Border Radius (refined, slightly larger) --- */
293
+ --ds-radius-none: 0;
294
+ --ds-radius-sm: 6px;
295
+ --ds-radius-md: 8px;
296
+ --ds-radius-lg: 12px;
297
+ --ds-radius-xl: 16px;
298
+ --ds-radius-2xl: 20px;
299
+ --ds-radius-full: 9999px;
300
+
301
+ /* --- Z-Index Scale --- */
302
+ --ds-z-base: 0;
303
+ --ds-z-dropdown: 50;
304
+ --ds-z-sticky: 60;
305
+ --ds-z-overlay: 80;
306
+ --ds-z-modal: 100;
307
+ --ds-z-toast: 150;
308
+ --ds-z-tooltip: 200;
309
+ }
310
+
311
+ /* ==========================================================================
312
+ Design Tokens: Effects & Transitions
313
+ Expo easing, smooth editorial motion.
314
+ Shadows are defined per-theme in colors.css.
315
+ ========================================================================== */
316
+
317
+ :root {
318
+ /* --- Focus Ring --- */
319
+ --ds-ring-width: 2px;
320
+ --ds-ring-offset: 2px;
321
+ --ds-ring-color: var(--ds-color-border-active);
322
+
323
+ /* --- Transitions --- */
324
+ --ds-duration-fast: 100ms;
325
+ --ds-duration-normal: 200ms;
326
+ --ds-duration-slow: 400ms;
327
+ --ds-duration-slower: 800ms;
328
+
329
+ --ds-ease-default: ease;
330
+ --ds-ease-out: cubic-bezier(0, 0, 0.2, 1);
331
+ --ds-ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
332
+ --ds-ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
333
+
334
+ /* --- Opacity --- */
335
+ --ds-opacity-disabled: 0.5;
336
+ }
337
+
338
+
339
+ /* ==========================================================================
340
+ Base: Reset
341
+ Clean, modern, antialiased.
342
+ ========================================================================== */
343
+
344
+ *,
345
+ *::before,
346
+ *::after {
347
+ box-sizing: border-box;
348
+ margin: 0;
349
+ padding: 0;
350
+ }
351
+
352
+ html {
353
+ -webkit-font-smoothing: antialiased;
354
+ -moz-osx-font-smoothing: grayscale;
355
+ text-size-adjust: 100%;
356
+ tab-size: 4;
357
+ scroll-behavior: smooth;
358
+ }
359
+
360
+ html, body {
361
+ max-width: 100vw;
362
+ overflow-x: hidden;
363
+ }
364
+
365
+ body {
366
+ min-height: 100dvh;
367
+ font-family: var(--ds-font-sans);
368
+ font-size: var(--ds-text-base);
369
+ line-height: var(--ds-leading-normal);
370
+ color: var(--ds-color-text);
371
+ background-color: var(--ds-color-bg);
372
+ }
373
+
374
+ img, picture, video, canvas, svg {
375
+ display: block;
376
+ max-width: 100%;
377
+ height: auto;
378
+ }
379
+
380
+ input, button, textarea, select {
381
+ font: inherit;
382
+ color: inherit;
383
+ }
384
+
385
+ button,
386
+ [role="button"],
387
+ select,
388
+ summary {
389
+ cursor: pointer;
390
+ }
391
+
392
+ button {
393
+ background: none;
394
+ border: none;
395
+ }
396
+
397
+ a {
398
+ color: inherit;
399
+ text-decoration: none;
400
+ }
401
+
402
+ ul, ol {
403
+ list-style: none;
404
+ }
405
+
406
+ table {
407
+ border-collapse: collapse;
408
+ border-spacing: 0;
409
+ }
410
+
411
+ /* Hide number input spinners */
412
+ input[type="number"] { -moz-appearance: textfield; }
413
+ input[type="number"]::-webkit-outer-spin-button,
414
+ input[type="number"]::-webkit-inner-spin-button {
415
+ -webkit-appearance: none;
416
+ margin: 0;
417
+ }
418
+
419
+ /* Focus: subtle ring */
420
+ *:focus-visible {
421
+ outline: var(--ds-ring-width) solid var(--ds-ring-color);
422
+ outline-offset: var(--ds-ring-offset);
423
+ }
424
+
425
+ /* Selection — inverted */
426
+ ::selection {
427
+ background-color: var(--ds-color-selection-bg);
428
+ color: var(--ds-color-selection-text);
429
+ }
430
+
431
+ /* Scrollbar */
432
+ ::-webkit-scrollbar {
433
+ width: 8px;
434
+ height: 8px;
435
+ }
436
+ ::-webkit-scrollbar-track {
437
+ background: transparent;
438
+ }
439
+ ::-webkit-scrollbar-thumb {
440
+ background: var(--ds-scrollbar-thumb);
441
+ border-radius: var(--ds-radius-sm);
442
+ }
443
+ ::-webkit-scrollbar-thumb:hover {
444
+ background: var(--ds-scrollbar-thumb-hover);
445
+ }
446
+
447
+ .ds-no-scrollbar::-webkit-scrollbar { display: none; }
448
+ .ds-no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
449
+
450
+ /* Reduce motion */
451
+ @media (prefers-reduced-motion: reduce) {
452
+ *, *::before, *::after {
453
+ animation-duration: 0.01ms !important;
454
+ animation-iteration-count: 1 !important;
455
+ transition-duration: 0.01ms !important;
456
+ scroll-behavior: auto !important;
457
+ }
458
+ }
459
+
460
+ /* ==========================================================================
461
+ Base: Typography
462
+ Display font for headings, generous sizes, editorial hierarchy.
463
+ ========================================================================== */
464
+
465
+ /* Display font utility — use on headings to get the display typeface */
466
+ .ds-font-display {
467
+ font-family: var(--ds-font-display);
468
+ font-weight: var(--ds-font-display-weight);
469
+ }
470
+
471
+ h1, h2, h3, h4, h5, h6 {
472
+ font-family: var(--ds-font-display);
473
+ font-weight: var(--ds-font-display-weight);
474
+ line-height: var(--ds-leading-tight);
475
+ letter-spacing: var(--ds-tracking-tight);
476
+ color: var(--ds-color-text);
477
+ }
478
+
479
+ h1 { font-size: var(--ds-text-5xl); }
480
+ h2 { font-size: var(--ds-text-4xl); }
481
+ h3 { font-size: var(--ds-text-2xl); }
482
+ h4 { font-size: var(--ds-text-xl); }
483
+ h5 { font-size: var(--ds-text-lg); }
484
+ h6 { font-size: var(--ds-text-base); font-weight: var(--ds-weight-medium); }
485
+
486
+ p {
487
+ line-height: var(--ds-leading-normal);
488
+ color: var(--ds-color-text-secondary);
489
+ }
490
+
491
+ p + p {
492
+ margin-top: var(--ds-space-4);
493
+ }
494
+
495
+ small {
496
+ font-size: var(--ds-text-xs);
497
+ color: var(--ds-color-text-tertiary);
498
+ }
499
+
500
+ strong, b {
501
+ font-weight: var(--ds-weight-semibold);
502
+ }
503
+
504
+ /* Overline / label style (like "PRODUCT DESIGNER & DEVELOPER") */
505
+ .ds-overline {
506
+ font-size: var(--ds-text-sm);
507
+ font-weight: var(--ds-weight-medium);
508
+ letter-spacing: var(--ds-tracking-wide);
509
+ text-transform: uppercase;
510
+ color: var(--ds-color-text-secondary);
511
+ }
512
+
513
+ /* Section title style */
514
+ .ds-section-title {
515
+ font-family: var(--ds-font-display);
516
+ font-weight: var(--ds-font-display-weight);
517
+ font-size: var(--ds-text-3xl);
518
+ letter-spacing: var(--ds-tracking-tight);
519
+ color: var(--ds-color-text);
520
+ }
521
+
522
+ @media (min-width: 640px) {
523
+ .ds-section-title { font-size: var(--ds-text-4xl); }
524
+ }
525
+
526
+ /* Hero title — large editorial display */
527
+ .ds-hero-title {
528
+ font-family: var(--ds-font-display);
529
+ font-weight: var(--ds-font-display-weight);
530
+ font-size: var(--ds-text-4xl);
531
+ line-height: var(--ds-leading-tight);
532
+ letter-spacing: var(--ds-tracking-tight);
533
+ color: var(--ds-color-text);
534
+ }
535
+
536
+ @media (min-width: 640px) {
537
+ .ds-hero-title { font-size: var(--ds-text-5xl); }
538
+ }
539
+ @media (min-width: 768px) {
540
+ .ds-hero-title { font-size: var(--ds-text-6xl); }
541
+ }
542
+ @media (min-width: 1024px) {
543
+ .ds-hero-title { font-size: var(--ds-text-7xl); }
544
+ }
545
+
546
+ code, kbd, samp {
547
+ font-family: var(--ds-font-mono);
548
+ font-size: 0.9em;
549
+ background-color: var(--ds-color-bg-elevated);
550
+ padding: 2px 6px;
551
+ border-radius: var(--ds-radius-sm);
552
+ }
553
+
554
+ pre {
555
+ font-family: var(--ds-font-mono);
556
+ font-size: var(--ds-text-sm);
557
+ line-height: var(--ds-leading-relaxed);
558
+ background-color: var(--ds-color-surface);
559
+ border: 1px solid var(--ds-color-border);
560
+ padding: var(--ds-space-4);
561
+ border-radius: var(--ds-radius-lg);
562
+ overflow-x: auto;
563
+ }
564
+
565
+ pre code {
566
+ background: none;
567
+ padding: 0;
568
+ }
569
+
570
+ blockquote {
571
+ padding-left: var(--ds-space-4);
572
+ border-left: 2px solid var(--ds-color-border-hover);
573
+ color: var(--ds-color-text-secondary);
574
+ }
575
+
576
+ hr {
577
+ border: none;
578
+ height: 1px;
579
+ background-color: var(--ds-color-border);
580
+ margin: var(--ds-space-8) 0;
581
+ }
582
+
583
+ /* Prose: opt-in rich text styling */
584
+ .ds-prose a {
585
+ color: var(--ds-color-info);
586
+ text-decoration: underline;
587
+ text-underline-offset: 2px;
588
+ transition: color var(--ds-duration-fast) var(--ds-ease-default);
589
+ }
590
+ .ds-prose a:hover {
591
+ opacity: 0.8;
592
+ }
593
+
594
+ .ds-prose ul, .ds-prose ol {
595
+ padding-left: var(--ds-space-6);
596
+ margin-top: var(--ds-space-2);
597
+ margin-bottom: var(--ds-space-2);
598
+ }
599
+ .ds-prose ul { list-style-type: disc; }
600
+ .ds-prose ol { list-style-type: decimal; }
601
+
602
+ .ds-prose li {
603
+ line-height: var(--ds-leading-normal);
604
+ color: var(--ds-color-text-secondary);
605
+ }
606
+ .ds-prose li + li {
607
+ margin-top: var(--ds-space-1);
608
+ }
609
+
610
+ /* Tabular figures for numbers */
611
+ .ds-tabular-nums {
612
+ font-variant-numeric: tabular-nums;
613
+ }
614
+
615
+ /* Stat numbers — display font, large */
616
+ .ds-stat-number {
617
+ font-family: var(--ds-font-display);
618
+ font-weight: var(--ds-font-display-weight);
619
+ font-variant-numeric: tabular-nums;
620
+ font-size: var(--ds-text-2xl);
621
+ color: var(--ds-color-text);
622
+ }
623
+
624
+
625
+ /* === Core === */
626
+ /* ==========================================================================
627
+ Component: Button
628
+ Inverted primary, rounded-full CTAs, refined sizing.
629
+ ========================================================================== */
630
+
631
+ .ds-btn {
632
+ display: inline-flex;
633
+ align-items: center;
634
+ justify-content: center;
635
+ gap: var(--ds-space-2);
636
+ padding: var(--ds-space-2) var(--ds-space-4);
637
+ font-family: var(--ds-font-sans);
638
+ font-size: var(--ds-text-sm);
639
+ font-weight: var(--ds-weight-medium);
640
+ line-height: var(--ds-leading-none);
641
+ white-space: nowrap;
642
+ border-radius: var(--ds-radius-lg);
643
+ border: 1px solid transparent;
644
+ cursor: pointer;
645
+ transition: all var(--ds-duration-fast) ease;
646
+
647
+ /* Default: inverted (dark bg in light mode, light bg in dark mode) */
648
+ background-color: var(--ds-color-inverted);
649
+ color: var(--ds-color-on-inverted);
650
+ }
651
+
652
+ .ds-btn:hover {
653
+ opacity: 0.9;
654
+ }
655
+
656
+ .ds-btn:focus-visible {
657
+ outline: var(--ds-ring-width) solid var(--ds-ring-color);
658
+ outline-offset: var(--ds-ring-offset);
659
+ }
660
+
661
+ .ds-btn:disabled,
662
+ .ds-btn[aria-disabled="true"] {
663
+ opacity: var(--ds-opacity-disabled);
664
+ cursor: not-allowed;
665
+ pointer-events: none;
666
+ }
667
+
668
+ /* --- Variants --- */
669
+
670
+ .ds-btn--secondary {
671
+ background-color: var(--ds-color-bg-elevated);
672
+ color: var(--ds-color-text);
673
+ border-color: var(--ds-color-border);
674
+ }
675
+ .ds-btn--secondary:hover {
676
+ border-color: var(--ds-color-border-hover);
677
+ background-color: var(--ds-color-surface);
678
+ opacity: 1;
679
+ }
680
+
681
+ .ds-btn--outline {
682
+ background-color: transparent;
683
+ color: var(--ds-color-text-secondary);
684
+ border-color: var(--ds-color-border);
685
+ }
686
+ .ds-btn--outline:hover {
687
+ color: var(--ds-color-text);
688
+ border-color: var(--ds-color-border-hover);
689
+ opacity: 1;
690
+ }
691
+
692
+ .ds-btn--ghost {
693
+ background-color: transparent;
694
+ color: var(--ds-color-text-secondary);
695
+ }
696
+ .ds-btn--ghost:hover {
697
+ color: var(--ds-color-text);
698
+ background-color: var(--ds-color-bg-elevated);
699
+ opacity: 1;
700
+ }
701
+
702
+ .ds-btn--danger {
703
+ background-color: var(--ds-color-error-subtle);
704
+ color: var(--ds-color-error);
705
+ border-color: var(--ds-color-error-border);
706
+ }
707
+ .ds-btn--danger:hover {
708
+ background-color: var(--ds-color-error);
709
+ color: #fff;
710
+ opacity: 1;
711
+ }
712
+
713
+ .ds-btn--success {
714
+ background-color: var(--ds-color-success-subtle);
715
+ color: var(--ds-color-success);
716
+ border-color: var(--ds-color-success-border);
717
+ }
718
+ .ds-btn--success:hover {
719
+ background-color: var(--ds-color-success);
720
+ color: #fff;
721
+ opacity: 1;
722
+ }
723
+
724
+ /* --- Sizes --- */
725
+
726
+ .ds-btn--sm {
727
+ padding: var(--ds-space-1-5) var(--ds-space-3);
728
+ font-size: var(--ds-text-sm);
729
+ gap: var(--ds-space-1-5);
730
+ border-radius: var(--ds-radius-md);
731
+ }
732
+
733
+ .ds-btn--lg {
734
+ padding: var(--ds-space-3) var(--ds-space-6);
735
+ font-size: var(--ds-text-base);
736
+ border-radius: var(--ds-radius-lg);
737
+ }
738
+
739
+ /* --- Pill (rounded-full, like hero CTAs) --- */
740
+ .ds-btn--pill {
741
+ border-radius: var(--ds-radius-full);
742
+ padding: var(--ds-space-3) var(--ds-space-6);
743
+ }
744
+
745
+ .ds-btn--pill.ds-btn--sm {
746
+ padding: var(--ds-space-2) var(--ds-space-5);
747
+ }
748
+
749
+ /* --- Full Width --- */
750
+ .ds-btn--full { width: 100%; }
751
+
752
+ /* --- Icon Only --- */
753
+ .ds-btn--icon {
754
+ padding: 0;
755
+ width: 2.25rem;
756
+ height: 2.25rem;
757
+ border-radius: var(--ds-radius-md);
758
+ }
759
+
760
+ .ds-btn--icon.ds-btn--sm {
761
+ width: 2rem;
762
+ height: 2rem;
763
+ }
764
+
765
+ /* --- Button Group --- */
766
+ .ds-btn-group {
767
+ display: inline-flex;
768
+ }
769
+ .ds-btn-group .ds-btn { border-radius: 0; }
770
+ .ds-btn-group .ds-btn:first-child { border-radius: var(--ds-radius-lg) 0 0 var(--ds-radius-lg); }
771
+ .ds-btn-group .ds-btn:last-child { border-radius: 0 var(--ds-radius-lg) var(--ds-radius-lg) 0; }
772
+ .ds-btn-group .ds-btn + .ds-btn { margin-left: -1px; }
773
+
774
+ /* --- Loading spinner --- */
775
+ .ds-btn--loading {
776
+ position: relative;
777
+ color: transparent !important;
778
+ pointer-events: none;
779
+ }
780
+ .ds-btn--loading::after {
781
+ content: '';
782
+ position: absolute;
783
+ width: 1em;
784
+ height: 1em;
785
+ border: 2px solid currentColor;
786
+ border-right-color: transparent;
787
+ border-radius: var(--ds-radius-full);
788
+ animation: ds-btn-spin 0.6s linear infinite;
789
+ color: var(--ds-color-on-inverted);
790
+ }
791
+ @keyframes ds-btn-spin {
792
+ to { transform: rotate(360deg); }
793
+ }
794
+
795
+ /* ==========================================================================
796
+ Component: Card
797
+ Surface + border, hover with shadow lift, rounded-xl.
798
+ ========================================================================== */
799
+
800
+ .ds-card {
801
+ background-color: var(--ds-color-surface);
802
+ border: 1px solid var(--ds-color-border);
803
+ border-radius: var(--ds-radius-xl);
804
+ overflow: hidden;
805
+ transition: all var(--ds-duration-normal) var(--ds-ease-default);
806
+ }
807
+
808
+ /* Interactive card — lifts on hover (like ProjectCard) */
809
+ .ds-card--interactive {
810
+ cursor: pointer;
811
+ }
812
+ .ds-card--interactive:hover {
813
+ border-color: var(--ds-color-border-hover);
814
+ box-shadow: var(--ds-shadow-lg);
815
+ transform: translateY(-4px);
816
+ }
817
+
818
+ /* Elevated card — visible shadow */
819
+ .ds-card--elevated {
820
+ background-color: var(--ds-color-bg-elevated);
821
+ box-shadow: var(--ds-shadow-lg);
822
+ }
823
+
824
+ /* Hover card — subtle bg change */
825
+ .ds-card--hover:hover {
826
+ border-color: var(--ds-color-border-hover);
827
+ }
828
+
829
+ .ds-card__header {
830
+ padding: var(--ds-space-5);
831
+ border-bottom: 1px solid var(--ds-color-border);
832
+ }
833
+
834
+ .ds-card__header h3,
835
+ .ds-card__header .ds-card__title {
836
+ font-family: var(--ds-font-display);
837
+ font-weight: var(--ds-font-display-weight);
838
+ font-size: var(--ds-text-lg);
839
+ letter-spacing: var(--ds-tracking-tight);
840
+ color: var(--ds-color-text);
841
+ }
842
+
843
+ .ds-card__description {
844
+ font-size: var(--ds-text-sm);
845
+ color: var(--ds-color-text-tertiary);
846
+ margin-top: var(--ds-space-1);
847
+ }
848
+
849
+ .ds-card__body {
850
+ padding: var(--ds-space-5);
851
+ }
852
+
853
+ .ds-card__footer {
854
+ padding: var(--ds-space-4) var(--ds-space-5);
855
+ border-top: 1px solid var(--ds-color-border);
856
+ display: flex;
857
+ align-items: center;
858
+ gap: var(--ds-space-2);
859
+ }
860
+
861
+ .ds-card__media {
862
+ width: 100%;
863
+ aspect-ratio: 16/10;
864
+ object-fit: cover;
865
+ background-color: var(--ds-color-bg-elevated);
866
+ }
867
+
868
+ /* Compact */
869
+ .ds-card--compact .ds-card__header,
870
+ .ds-card--compact .ds-card__body,
871
+ .ds-card--compact .ds-card__footer {
872
+ padding: var(--ds-space-3) var(--ds-space-4);
873
+ }
874
+
875
+ /* Flush — no internal dividers */
876
+ .ds-card--flush .ds-card__header { border-bottom: none; }
877
+ .ds-card--flush .ds-card__footer { border-top: none; }
878
+
879
+ /* Stat card (like StatCard component) */
880
+ .ds-stat-card {
881
+ background-color: var(--ds-color-surface);
882
+ border: 1px solid var(--ds-color-border);
883
+ border-radius: var(--ds-radius-xl);
884
+ padding: var(--ds-space-5);
885
+ }
886
+
887
+ .ds-stat-card__label {
888
+ font-size: var(--ds-text-sm);
889
+ color: var(--ds-color-text-tertiary);
890
+ }
891
+
892
+ .ds-stat-card__value {
893
+ font-family: var(--ds-font-display);
894
+ font-weight: var(--ds-font-display-weight);
895
+ font-size: var(--ds-text-2xl);
896
+ color: var(--ds-color-text);
897
+ margin-top: var(--ds-space-1);
898
+ }
899
+
900
+ .ds-stat-card__detail {
901
+ font-size: var(--ds-text-xs);
902
+ color: var(--ds-color-text-tertiary);
903
+ margin-top: var(--ds-space-0-5);
904
+ }
905
+
906
+ .ds-stat-card__icon {
907
+ width: 2.5rem;
908
+ height: 2.5rem;
909
+ border-radius: var(--ds-radius-xl);
910
+ display: flex;
911
+ align-items: center;
912
+ justify-content: center;
913
+ background-color: var(--ds-color-bg-elevated);
914
+ color: var(--ds-color-text-secondary);
915
+ }
916
+
917
+ /* ==========================================================================
918
+ Component: Form Inputs
919
+ Surface bg, clean borders, focus ring.
920
+ ========================================================================== */
921
+
922
+ .ds-label {
923
+ display: block;
924
+ font-size: var(--ds-text-sm);
925
+ font-weight: var(--ds-weight-medium);
926
+ color: var(--ds-color-text-secondary);
927
+ margin-bottom: var(--ds-space-1-5);
928
+ }
929
+
930
+ .ds-input,
931
+ .ds-textarea,
932
+ .ds-select {
933
+ width: 100%;
934
+ padding: var(--ds-space-2-5) var(--ds-space-4);
935
+ font-family: var(--ds-font-sans);
936
+ font-size: var(--ds-text-sm);
937
+ line-height: var(--ds-leading-normal);
938
+ color: var(--ds-color-text);
939
+ background-color: var(--ds-color-surface);
940
+ border: 1px solid var(--ds-color-border);
941
+ border-radius: var(--ds-radius-lg);
942
+ transition: all var(--ds-duration-fast) ease;
943
+ }
944
+
945
+ .ds-input:hover,
946
+ .ds-textarea:hover,
947
+ .ds-select:hover {
948
+ border-color: var(--ds-color-border-hover);
949
+ }
950
+
951
+ .ds-input:focus,
952
+ .ds-textarea:focus,
953
+ .ds-select:focus {
954
+ border-color: var(--ds-color-border-active);
955
+ box-shadow: 0 0 0 1px var(--ds-color-border-active);
956
+ outline: none;
957
+ }
958
+
959
+ .ds-input::placeholder,
960
+ .ds-textarea::placeholder {
961
+ color: var(--ds-color-text-tertiary);
962
+ }
963
+
964
+ /* States */
965
+ .ds-input--error,
966
+ .ds-textarea--error {
967
+ border-color: var(--ds-color-error);
968
+ }
969
+ .ds-input--error:focus,
970
+ .ds-textarea--error:focus {
971
+ box-shadow: 0 0 0 1px var(--ds-color-error);
972
+ }
973
+
974
+ .ds-input--success {
975
+ border-color: var(--ds-color-success);
976
+ }
977
+
978
+ /* Sizes */
979
+ .ds-input--sm {
980
+ padding: var(--ds-space-1) var(--ds-space-2);
981
+ font-size: var(--ds-text-xs);
982
+ border-radius: var(--ds-radius-md);
983
+ }
984
+
985
+ .ds-input--lg {
986
+ padding: var(--ds-space-3) var(--ds-space-4);
987
+ font-size: var(--ds-text-base);
988
+ }
989
+
990
+ /* Textarea */
991
+ .ds-textarea {
992
+ min-height: 6rem;
993
+ padding: var(--ds-space-2-5) var(--ds-space-4);
994
+ resize: vertical;
995
+ }
996
+
997
+ /* Select */
998
+ .ds-select {
999
+ appearance: none;
1000
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23a1a1aa' d='M2 4l4 4 4-4'/%3E%3C/svg%3E");
1001
+ background-repeat: no-repeat;
1002
+ background-position: right var(--ds-space-3) center;
1003
+ padding-right: var(--ds-space-8);
1004
+ }
1005
+
1006
+ /* Help text */
1007
+ .ds-help {
1008
+ font-size: var(--ds-text-xs);
1009
+ color: var(--ds-color-text-tertiary);
1010
+ margin-top: var(--ds-space-1-5);
1011
+ }
1012
+ .ds-help--error { color: var(--ds-color-error); }
1013
+
1014
+ /* Form Group */
1015
+ .ds-form-group { margin-bottom: var(--ds-space-4); }
1016
+
1017
+ /* Checkbox / Radio */
1018
+ .ds-checkbox,
1019
+ .ds-radio {
1020
+ display: inline-flex;
1021
+ align-items: center;
1022
+ gap: var(--ds-space-2);
1023
+ cursor: pointer;
1024
+ font-size: var(--ds-text-sm);
1025
+ color: var(--ds-color-text-secondary);
1026
+ }
1027
+ .ds-checkbox input,
1028
+ .ds-radio input {
1029
+ accent-color: var(--ds-color-interactive);
1030
+ width: 0.875rem;
1031
+ height: 0.875rem;
1032
+ }
1033
+
1034
+ /* ==========================================================================
1035
+ Component: Badge
1036
+ Pill shape, border + subtle bg, clean and refined.
1037
+ ========================================================================== */
1038
+
1039
+ .ds-badge {
1040
+ display: inline-flex;
1041
+ align-items: center;
1042
+ gap: var(--ds-space-1);
1043
+ padding: var(--ds-space-0-5) var(--ds-space-2-5);
1044
+ font-size: var(--ds-text-xs);
1045
+ font-weight: var(--ds-weight-medium);
1046
+ line-height: var(--ds-leading-snug);
1047
+ border-radius: var(--ds-radius-full);
1048
+ white-space: nowrap;
1049
+ border: 1px solid var(--ds-color-border);
1050
+ background-color: var(--ds-color-bg-elevated);
1051
+ color: var(--ds-color-text-secondary);
1052
+ }
1053
+
1054
+ /* Semantic variants — subtle bg + bright text + subtle border */
1055
+ .ds-badge--primary {
1056
+ background-color: var(--ds-color-info-subtle);
1057
+ color: var(--ds-color-info);
1058
+ border-color: var(--ds-color-info-border);
1059
+ }
1060
+
1061
+ .ds-badge--success {
1062
+ background-color: var(--ds-color-success-subtle);
1063
+ color: var(--ds-color-success);
1064
+ border-color: var(--ds-color-success-border);
1065
+ }
1066
+
1067
+ .ds-badge--warning {
1068
+ background-color: var(--ds-color-warning-subtle);
1069
+ color: var(--ds-color-warning);
1070
+ border-color: var(--ds-color-warning-border);
1071
+ }
1072
+
1073
+ .ds-badge--error {
1074
+ background-color: var(--ds-color-error-subtle);
1075
+ color: var(--ds-color-error);
1076
+ border-color: var(--ds-color-error-border);
1077
+ }
1078
+
1079
+ .ds-badge--info {
1080
+ background-color: var(--ds-color-accent-blue-subtle);
1081
+ color: var(--ds-color-accent-blue);
1082
+ border-color: rgba(37, 99, 235, 0.2);
1083
+ }
1084
+
1085
+ .ds-badge--purple {
1086
+ background-color: var(--ds-color-accent-purple-subtle);
1087
+ color: var(--ds-color-accent-purple);
1088
+ border-color: rgba(124, 58, 237, 0.2);
1089
+ }
1090
+
1091
+ /* Outline (no bg) */
1092
+ .ds-badge--outline {
1093
+ background-color: transparent;
1094
+ border-color: var(--ds-color-border);
1095
+ color: var(--ds-color-text-secondary);
1096
+ }
1097
+
1098
+ /* Dot indicator */
1099
+ .ds-badge--dot::before {
1100
+ content: '';
1101
+ width: 6px;
1102
+ height: 6px;
1103
+ border-radius: var(--ds-radius-full);
1104
+ background-color: currentColor;
1105
+ }
1106
+
1107
+ /* Uppercase badge (like "NEW", "BETA") */
1108
+ .ds-badge--upper {
1109
+ text-transform: uppercase;
1110
+ font-size: 10px;
1111
+ font-weight: var(--ds-weight-semibold);
1112
+ letter-spacing: var(--ds-tracking-wide);
1113
+ }
1114
+
1115
+ /* ==========================================================================
1116
+ Component: Navigation
1117
+ Fixed glass header, backdrop-blur, h-16. Clean links.
1118
+ ========================================================================== */
1119
+
1120
+ .ds-nav {
1121
+ position: fixed;
1122
+ top: 0;
1123
+ left: 0;
1124
+ right: 0;
1125
+ z-index: var(--ds-z-sticky);
1126
+ display: flex;
1127
+ align-items: center;
1128
+ justify-content: space-between;
1129
+ padding: 0 var(--ds-container-padding);
1130
+ height: 4rem;
1131
+ background-color: var(--ds-color-nav-bg);
1132
+ border-bottom: 1px solid var(--ds-color-nav-border);
1133
+ backdrop-filter: blur(20px) saturate(1.5);
1134
+ -webkit-backdrop-filter: blur(20px) saturate(1.5);
1135
+ }
1136
+
1137
+ .ds-nav--static {
1138
+ position: relative;
1139
+ }
1140
+
1141
+ .ds-nav__inner {
1142
+ display: flex;
1143
+ align-items: center;
1144
+ justify-content: space-between;
1145
+ width: 100%;
1146
+ max-width: var(--ds-container-max);
1147
+ margin-inline: auto;
1148
+ }
1149
+
1150
+ .ds-nav__brand {
1151
+ font-family: var(--ds-font-display);
1152
+ font-weight: var(--ds-font-display-weight);
1153
+ font-size: var(--ds-text-lg);
1154
+ color: var(--ds-color-text);
1155
+ letter-spacing: var(--ds-tracking-tight);
1156
+ }
1157
+
1158
+ .ds-nav__menu {
1159
+ display: flex;
1160
+ align-items: center;
1161
+ gap: var(--ds-space-8);
1162
+ }
1163
+
1164
+ .ds-nav__link {
1165
+ font-size: var(--ds-text-sm);
1166
+ color: var(--ds-color-text-secondary);
1167
+ transition: color var(--ds-duration-normal) var(--ds-ease-default);
1168
+ }
1169
+
1170
+ .ds-nav__link:hover {
1171
+ color: var(--ds-color-text);
1172
+ }
1173
+
1174
+ .ds-nav__link--active {
1175
+ color: var(--ds-color-text);
1176
+ }
1177
+
1178
+ /* Nav actions (theme toggle, etc) */
1179
+ .ds-nav__actions {
1180
+ display: flex;
1181
+ align-items: center;
1182
+ gap: var(--ds-space-2);
1183
+ }
1184
+
1185
+ /* Icon button in nav */
1186
+ .ds-nav__icon-btn {
1187
+ display: flex;
1188
+ align-items: center;
1189
+ justify-content: center;
1190
+ width: 2.25rem;
1191
+ height: 2.25rem;
1192
+ border-radius: var(--ds-radius-md);
1193
+ color: var(--ds-color-text-secondary);
1194
+ transition: all var(--ds-duration-normal) var(--ds-ease-default);
1195
+ }
1196
+ .ds-nav__icon-btn:hover {
1197
+ color: var(--ds-color-text);
1198
+ background-color: var(--ds-color-overlay-hover);
1199
+ }
1200
+
1201
+ /* --- Mobile nav overlay --- */
1202
+ .ds-nav__mobile {
1203
+ overflow: hidden;
1204
+ max-height: 0;
1205
+ border-bottom: 0 solid var(--ds-color-nav-border);
1206
+ background-color: var(--ds-color-nav-bg);
1207
+ backdrop-filter: blur(20px);
1208
+ transition: all var(--ds-duration-slow) var(--ds-ease-out-expo);
1209
+ }
1210
+
1211
+ .ds-nav__mobile--open {
1212
+ max-height: 16rem;
1213
+ border-bottom-width: 1px;
1214
+ }
1215
+
1216
+ .ds-nav__mobile-links {
1217
+ display: flex;
1218
+ flex-direction: column;
1219
+ gap: var(--ds-space-4);
1220
+ padding: var(--ds-space-4) var(--ds-container-padding);
1221
+ }
1222
+
1223
+ /* --- Sidebar --- */
1224
+
1225
+ .ds-sidebar {
1226
+ display: flex;
1227
+ flex-direction: column;
1228
+ width: 16rem;
1229
+ padding: var(--ds-space-5);
1230
+ background-color: var(--ds-color-surface);
1231
+ border-right: 1px solid var(--ds-color-border);
1232
+ height: 100%;
1233
+ }
1234
+
1235
+ .ds-sidebar__section {
1236
+ margin-bottom: var(--ds-space-6);
1237
+ }
1238
+
1239
+ .ds-sidebar__title {
1240
+ font-size: var(--ds-text-sm);
1241
+ font-weight: var(--ds-weight-medium);
1242
+ text-transform: uppercase;
1243
+ letter-spacing: var(--ds-tracking-wide);
1244
+ color: var(--ds-color-text-tertiary);
1245
+ margin-bottom: var(--ds-space-3);
1246
+ }
1247
+
1248
+ .ds-sidebar__link {
1249
+ display: flex;
1250
+ align-items: center;
1251
+ gap: var(--ds-space-2);
1252
+ padding: var(--ds-space-2) var(--ds-space-3);
1253
+ font-size: var(--ds-text-sm);
1254
+ color: var(--ds-color-text-secondary);
1255
+ border-radius: var(--ds-radius-md);
1256
+ transition: all var(--ds-duration-normal) var(--ds-ease-default);
1257
+ }
1258
+
1259
+ .ds-sidebar__link:hover {
1260
+ color: var(--ds-color-text);
1261
+ background-color: var(--ds-color-overlay-hover);
1262
+ }
1263
+
1264
+ .ds-sidebar__link--active {
1265
+ color: var(--ds-color-text);
1266
+ background-color: var(--ds-color-bg-elevated);
1267
+ }
1268
+
1269
+ /* ==========================================================================
1270
+ Component: Modal
1271
+ Backdrop blur, shadow-2xl, rounded-xl. Smooth scale transition.
1272
+ ========================================================================== */
1273
+
1274
+ .ds-modal {
1275
+ position: fixed;
1276
+ inset: 0;
1277
+ z-index: var(--ds-z-modal);
1278
+ display: flex;
1279
+ align-items: center;
1280
+ justify-content: center;
1281
+ padding: var(--ds-space-4);
1282
+ background-color: var(--ds-color-overlay);
1283
+ backdrop-filter: blur(4px);
1284
+ -webkit-backdrop-filter: blur(4px);
1285
+ opacity: 0;
1286
+ visibility: hidden;
1287
+ transition:
1288
+ opacity var(--ds-duration-slow) var(--ds-ease-default),
1289
+ visibility var(--ds-duration-slow) var(--ds-ease-default);
1290
+ }
1291
+
1292
+ .ds-modal[open],
1293
+ .ds-modal--open {
1294
+ opacity: 1;
1295
+ visibility: visible;
1296
+ }
1297
+
1298
+ .ds-modal__content {
1299
+ width: 100%;
1300
+ max-width: 28rem;
1301
+ max-height: 90dvh;
1302
+ background-color: var(--ds-color-surface);
1303
+ border: 1px solid var(--ds-color-border);
1304
+ border-radius: var(--ds-radius-xl);
1305
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
1306
+ overflow: hidden;
1307
+ display: flex;
1308
+ flex-direction: column;
1309
+ transform: scale(0.96);
1310
+ transition: transform var(--ds-duration-slow) var(--ds-ease-out-expo);
1311
+ }
1312
+
1313
+ .ds-modal[open] .ds-modal__content,
1314
+ .ds-modal--open .ds-modal__content {
1315
+ transform: scale(1);
1316
+ }
1317
+
1318
+ .ds-modal__header {
1319
+ display: flex;
1320
+ align-items: flex-start;
1321
+ justify-content: space-between;
1322
+ padding: var(--ds-space-4) var(--ds-space-5);
1323
+ border-bottom: 1px solid var(--ds-color-border);
1324
+ }
1325
+
1326
+ .ds-modal__header h3 {
1327
+ font-family: var(--ds-font-display);
1328
+ font-weight: var(--ds-font-display-weight);
1329
+ font-size: var(--ds-text-lg);
1330
+ color: var(--ds-color-text);
1331
+ }
1332
+
1333
+ .ds-modal__header p {
1334
+ font-size: var(--ds-text-sm);
1335
+ color: var(--ds-color-text-tertiary);
1336
+ margin-top: var(--ds-space-1);
1337
+ }
1338
+
1339
+ .ds-modal__close {
1340
+ display: flex;
1341
+ align-items: center;
1342
+ justify-content: center;
1343
+ width: 2rem;
1344
+ height: 2rem;
1345
+ color: var(--ds-color-text-tertiary);
1346
+ border-radius: var(--ds-radius-md);
1347
+ transition: all var(--ds-duration-fast) var(--ds-ease-default);
1348
+ flex-shrink: 0;
1349
+ }
1350
+ .ds-modal__close:hover {
1351
+ color: var(--ds-color-text);
1352
+ }
1353
+
1354
+ .ds-modal__body {
1355
+ padding: var(--ds-space-5);
1356
+ overflow-y: auto;
1357
+ flex: 1;
1358
+ }
1359
+
1360
+ .ds-modal__footer {
1361
+ display: flex;
1362
+ align-items: center;
1363
+ justify-content: flex-end;
1364
+ gap: var(--ds-space-2);
1365
+ padding: var(--ds-space-4) var(--ds-space-5);
1366
+ border-top: 1px solid var(--ds-color-border);
1367
+ }
1368
+
1369
+ /* Size variants */
1370
+ .ds-modal--md .ds-modal__content { max-width: var(--ds-container-md); }
1371
+ .ds-modal--lg .ds-modal__content { max-width: var(--ds-container-lg); }
1372
+
1373
+ /* ==========================================================================
1374
+ Component: Toast
1375
+ ========================================================================== */
1376
+
1377
+ .ds-toast-container {
1378
+ position: fixed;
1379
+ z-index: var(--ds-z-toast);
1380
+ display: flex;
1381
+ flex-direction: column;
1382
+ gap: var(--ds-space-2);
1383
+ padding: var(--ds-space-4);
1384
+ pointer-events: none;
1385
+ }
1386
+
1387
+ .ds-toast-container--top-right { top: 0; right: 0; }
1388
+ .ds-toast-container--bottom-right { bottom: 0; right: 0; }
1389
+ .ds-toast-container--bottom-center {
1390
+ bottom: 0; left: 50%;
1391
+ transform: translateX(-50%);
1392
+ align-items: center;
1393
+ }
1394
+
1395
+ .ds-toast {
1396
+ display: flex;
1397
+ align-items: center;
1398
+ gap: var(--ds-space-3);
1399
+ padding: var(--ds-space-3) var(--ds-space-4);
1400
+ background-color: var(--ds-color-surface);
1401
+ border: 1px solid var(--ds-color-border);
1402
+ border-radius: var(--ds-radius-lg);
1403
+ box-shadow: var(--ds-shadow-lg);
1404
+ pointer-events: auto;
1405
+ min-width: 18rem;
1406
+ max-width: 28rem;
1407
+ animation: ds-toast-in var(--ds-duration-slow) var(--ds-ease-out-expo) forwards;
1408
+ }
1409
+
1410
+ .ds-toast--info { border-left: 3px solid var(--ds-color-info); }
1411
+ .ds-toast--success { border-left: 3px solid var(--ds-color-success); }
1412
+ .ds-toast--warning { border-left: 3px solid var(--ds-color-warning); }
1413
+ .ds-toast--error { border-left: 3px solid var(--ds-color-error); }
1414
+
1415
+ .ds-toast__message {
1416
+ flex: 1;
1417
+ font-size: var(--ds-text-sm);
1418
+ color: var(--ds-color-text);
1419
+ }
1420
+
1421
+ .ds-toast__close {
1422
+ color: var(--ds-color-text-tertiary);
1423
+ padding: var(--ds-space-1);
1424
+ border-radius: var(--ds-radius-sm);
1425
+ transition: color var(--ds-duration-fast) ease;
1426
+ }
1427
+ .ds-toast__close:hover {
1428
+ color: var(--ds-color-text);
1429
+ }
1430
+
1431
+ @keyframes ds-toast-in {
1432
+ from { opacity: 0; transform: translateY(-8px); }
1433
+ to { opacity: 1; transform: translateY(0); }
1434
+ }
1435
+
1436
+ .ds-toast--exit {
1437
+ animation: ds-toast-out var(--ds-duration-normal) var(--ds-ease-default) forwards;
1438
+ }
1439
+
1440
+ @keyframes ds-toast-out {
1441
+ to { opacity: 0; transform: translateX(100%); }
1442
+ }
1443
+
1444
+ /* ==========================================================================
1445
+ Component: Table
1446
+ ========================================================================== */
1447
+
1448
+ .ds-table {
1449
+ width: 100%;
1450
+ text-align: left;
1451
+ font-size: var(--ds-text-sm);
1452
+ }
1453
+
1454
+ .ds-table th {
1455
+ padding: var(--ds-space-3) var(--ds-space-4);
1456
+ font-weight: var(--ds-weight-medium);
1457
+ font-size: var(--ds-text-sm);
1458
+ color: var(--ds-color-text-tertiary);
1459
+ text-transform: uppercase;
1460
+ letter-spacing: var(--ds-tracking-wide);
1461
+ border-bottom: 1px solid var(--ds-color-border);
1462
+ }
1463
+
1464
+ .ds-table td {
1465
+ padding: var(--ds-space-3) var(--ds-space-4);
1466
+ color: var(--ds-color-text);
1467
+ border-bottom: 1px solid var(--ds-color-border-subtle);
1468
+ }
1469
+
1470
+ .ds-table tbody tr {
1471
+ transition: background-color var(--ds-duration-normal) var(--ds-ease-default);
1472
+ }
1473
+
1474
+ .ds-table tbody tr:hover {
1475
+ background-color: var(--ds-color-overlay-subtle);
1476
+ }
1477
+
1478
+ .ds-table--compact th,
1479
+ .ds-table--compact td {
1480
+ padding: var(--ds-space-2) var(--ds-space-3);
1481
+ font-size: var(--ds-text-xs);
1482
+ }
1483
+
1484
+ .ds-table-wrapper {
1485
+ overflow-x: auto;
1486
+ border: 1px solid var(--ds-color-border);
1487
+ border-radius: var(--ds-radius-xl);
1488
+ background-color: var(--ds-color-surface);
1489
+ }
1490
+
1491
+ .ds-table-wrapper .ds-table { margin: 0; }
1492
+
1493
+
1494
+ /* === Tier 1 — Essential === */
1495
+ /* ==========================================================================
1496
+ Component: Tabs
1497
+ Horizontal/vertical tab navigation with pill, small, and full-width variants.
1498
+ ========================================================================== */
1499
+
1500
+ .ds-tabs {
1501
+ display: flex;
1502
+ flex-direction: row;
1503
+ align-items: stretch;
1504
+ border-bottom: 1px solid var(--ds-color-border);
1505
+ gap: var(--ds-space-0);
1506
+ }
1507
+
1508
+ /* --- Pill variant --- */
1509
+
1510
+ .ds-tabs--pills {
1511
+ border-bottom: none;
1512
+ gap: var(--ds-space-1);
1513
+ background-color: var(--ds-color-bg-elevated);
1514
+ border-radius: var(--ds-radius-lg);
1515
+ padding: var(--ds-space-1);
1516
+ }
1517
+
1518
+ .ds-tabs--pills .ds-tab {
1519
+ border-bottom: none;
1520
+ border-radius: var(--ds-radius-md);
1521
+ padding: var(--ds-space-1-5) var(--ds-space-3);
1522
+ }
1523
+
1524
+ .ds-tabs--pills .ds-tab:hover {
1525
+ background-color: var(--ds-color-overlay-hover);
1526
+ }
1527
+
1528
+ .ds-tabs--pills .ds-tab--active {
1529
+ background-color: var(--ds-color-surface);
1530
+ color: var(--ds-color-text);
1531
+ box-shadow: var(--ds-shadow-sm);
1532
+ border-bottom: none;
1533
+ }
1534
+
1535
+ /* --- Vertical variant --- */
1536
+
1537
+ .ds-tabs--vertical {
1538
+ flex-direction: column;
1539
+ border-bottom: none;
1540
+ border-right: 1px solid var(--ds-color-border);
1541
+ gap: var(--ds-space-0-5);
1542
+ }
1543
+
1544
+ .ds-tabs--vertical .ds-tab {
1545
+ border-bottom: none;
1546
+ border-right: 2px solid transparent;
1547
+ padding: var(--ds-space-2) var(--ds-space-4);
1548
+ text-align: left;
1549
+ }
1550
+
1551
+ .ds-tabs--vertical .ds-tab--active {
1552
+ border-bottom: none;
1553
+ border-right-color: var(--ds-color-interactive);
1554
+ color: var(--ds-color-text);
1555
+ }
1556
+
1557
+ /* --- Small variant --- */
1558
+
1559
+ .ds-tabs--sm .ds-tab {
1560
+ padding: var(--ds-space-1-5) var(--ds-space-3);
1561
+ font-size: var(--ds-text-xs);
1562
+ }
1563
+
1564
+ /* --- Full width variant --- */
1565
+
1566
+ .ds-tabs--full {
1567
+ width: 100%;
1568
+ }
1569
+
1570
+ .ds-tabs--full .ds-tab {
1571
+ flex: 1;
1572
+ justify-content: center;
1573
+ }
1574
+
1575
+ /* --- Individual Tab --- */
1576
+
1577
+ .ds-tab {
1578
+ display: inline-flex;
1579
+ align-items: center;
1580
+ gap: var(--ds-space-2);
1581
+ padding: var(--ds-space-2) var(--ds-space-4);
1582
+ font-family: var(--ds-font-sans);
1583
+ font-size: var(--ds-text-sm);
1584
+ font-weight: var(--ds-weight-medium);
1585
+ line-height: var(--ds-leading-snug);
1586
+ color: var(--ds-color-text-secondary);
1587
+ cursor: pointer;
1588
+ border-bottom: 2px solid transparent;
1589
+ background: none;
1590
+ border-top: none;
1591
+ border-left: none;
1592
+ border-right: none;
1593
+ white-space: nowrap;
1594
+ transition: all var(--ds-duration-fast) ease;
1595
+ margin-bottom: -1px;
1596
+ }
1597
+
1598
+ .ds-tab:hover {
1599
+ color: var(--ds-color-text);
1600
+ }
1601
+
1602
+ .ds-tab:focus-visible {
1603
+ outline: var(--ds-ring-width) solid var(--ds-ring-color);
1604
+ outline-offset: var(--ds-ring-offset);
1605
+ border-radius: var(--ds-radius-sm);
1606
+ }
1607
+
1608
+ .ds-tab--active {
1609
+ color: var(--ds-color-text);
1610
+ border-bottom-color: var(--ds-color-interactive);
1611
+ }
1612
+
1613
+ .ds-tab:disabled,
1614
+ .ds-tab[aria-disabled="true"] {
1615
+ opacity: var(--ds-opacity-disabled);
1616
+ cursor: not-allowed;
1617
+ pointer-events: none;
1618
+ }
1619
+
1620
+ /* --- Tab Icon --- */
1621
+
1622
+ .ds-tab__icon {
1623
+ display: inline-flex;
1624
+ align-items: center;
1625
+ justify-content: center;
1626
+ width: 1rem;
1627
+ height: 1rem;
1628
+ flex-shrink: 0;
1629
+ color: currentColor;
1630
+ }
1631
+
1632
+ /* --- Tab Count Badge --- */
1633
+
1634
+ .ds-tab__count {
1635
+ display: inline-flex;
1636
+ align-items: center;
1637
+ justify-content: center;
1638
+ padding: var(--ds-space-0) var(--ds-space-1-5);
1639
+ font-size: var(--ds-text-xs);
1640
+ font-weight: var(--ds-weight-medium);
1641
+ line-height: var(--ds-leading-snug);
1642
+ color: var(--ds-color-text-tertiary);
1643
+ background-color: var(--ds-color-bg-elevated);
1644
+ border-radius: var(--ds-radius-full);
1645
+ min-width: 1.25rem;
1646
+ }
1647
+
1648
+ .ds-tab--active .ds-tab__count {
1649
+ color: var(--ds-color-text-secondary);
1650
+ background-color: var(--ds-color-overlay-active);
1651
+ }
1652
+
1653
+ /* --- Tab Panel --- */
1654
+
1655
+ .ds-tab-panel {
1656
+ padding-top: var(--ds-space-5);
1657
+ }
1658
+
1659
+ /* ==========================================================================
1660
+ Component: Alert
1661
+ Contextual feedback banners with semantic variants and dismissibility.
1662
+ ========================================================================== */
1663
+
1664
+ .ds-alert {
1665
+ display: flex;
1666
+ flex-direction: row;
1667
+ align-items: flex-start;
1668
+ gap: var(--ds-space-3);
1669
+ padding: var(--ds-space-4);
1670
+ border: 1px solid var(--ds-color-border);
1671
+ border-radius: var(--ds-radius-lg);
1672
+ background-color: var(--ds-color-surface);
1673
+ border-left: 3px solid var(--ds-color-border);
1674
+ }
1675
+
1676
+ /* --- Semantic Variants --- */
1677
+
1678
+ .ds-alert--info {
1679
+ background-color: var(--ds-color-info-subtle);
1680
+ border-color: var(--ds-color-info-border);
1681
+ border-left-color: var(--ds-color-info);
1682
+ }
1683
+
1684
+ .ds-alert--success {
1685
+ background-color: var(--ds-color-success-subtle);
1686
+ border-color: var(--ds-color-success-border);
1687
+ border-left-color: var(--ds-color-success);
1688
+ }
1689
+
1690
+ .ds-alert--warning {
1691
+ background-color: var(--ds-color-warning-subtle);
1692
+ border-color: var(--ds-color-warning-border);
1693
+ border-left-color: var(--ds-color-warning);
1694
+ }
1695
+
1696
+ .ds-alert--error {
1697
+ background-color: var(--ds-color-error-subtle);
1698
+ border-color: var(--ds-color-error-border);
1699
+ border-left-color: var(--ds-color-error);
1700
+ }
1701
+
1702
+ /* --- Icon --- */
1703
+
1704
+ .ds-alert__icon {
1705
+ display: flex;
1706
+ align-items: center;
1707
+ justify-content: center;
1708
+ flex-shrink: 0;
1709
+ width: 1.25rem;
1710
+ height: 1.25rem;
1711
+ color: var(--ds-color-text-secondary);
1712
+ }
1713
+
1714
+ .ds-alert--info .ds-alert__icon { color: var(--ds-color-info); }
1715
+ .ds-alert--success .ds-alert__icon { color: var(--ds-color-success); }
1716
+ .ds-alert--warning .ds-alert__icon { color: var(--ds-color-warning); }
1717
+ .ds-alert--error .ds-alert__icon { color: var(--ds-color-error); }
1718
+
1719
+ /* --- Content --- */
1720
+
1721
+ .ds-alert__content {
1722
+ flex: 1;
1723
+ min-width: 0;
1724
+ }
1725
+
1726
+ .ds-alert__title {
1727
+ font-family: var(--ds-font-sans);
1728
+ font-size: var(--ds-text-sm);
1729
+ font-weight: var(--ds-weight-medium);
1730
+ line-height: var(--ds-leading-snug);
1731
+ color: var(--ds-color-text);
1732
+ }
1733
+
1734
+ .ds-alert__description {
1735
+ font-size: var(--ds-text-sm);
1736
+ line-height: var(--ds-leading-normal);
1737
+ color: var(--ds-color-text-secondary);
1738
+ margin-top: var(--ds-space-1);
1739
+ }
1740
+
1741
+ .ds-alert__title + .ds-alert__description {
1742
+ margin-top: var(--ds-space-1);
1743
+ }
1744
+
1745
+ /* --- Close Button --- */
1746
+
1747
+ .ds-alert__close {
1748
+ display: flex;
1749
+ align-items: center;
1750
+ justify-content: center;
1751
+ flex-shrink: 0;
1752
+ width: 1.5rem;
1753
+ height: 1.5rem;
1754
+ padding: 0;
1755
+ border: none;
1756
+ background: none;
1757
+ color: var(--ds-color-text-tertiary);
1758
+ border-radius: var(--ds-radius-sm);
1759
+ cursor: pointer;
1760
+ transition: color var(--ds-duration-fast) ease;
1761
+ }
1762
+
1763
+ .ds-alert__close:hover {
1764
+ color: var(--ds-color-text);
1765
+ }
1766
+
1767
+ .ds-alert__close:focus-visible {
1768
+ outline: var(--ds-ring-width) solid var(--ds-ring-color);
1769
+ outline-offset: var(--ds-ring-offset);
1770
+ }
1771
+
1772
+ /* --- Compact Variant --- */
1773
+
1774
+ .ds-alert--compact {
1775
+ padding: var(--ds-space-2) var(--ds-space-3);
1776
+ border-radius: var(--ds-radius-none);
1777
+ }
1778
+
1779
+ /* --- Banner Variant --- */
1780
+
1781
+ .ds-alert--banner {
1782
+ border-radius: var(--ds-radius-none);
1783
+ border-left: none;
1784
+ border-right: none;
1785
+ border-top: 1px solid var(--ds-color-border);
1786
+ border-bottom: 1px solid var(--ds-color-border);
1787
+ width: 100%;
1788
+ }
1789
+
1790
+ .ds-alert--banner.ds-alert--info {
1791
+ border-top-color: var(--ds-color-info-border);
1792
+ border-bottom-color: var(--ds-color-info-border);
1793
+ }
1794
+
1795
+ .ds-alert--banner.ds-alert--success {
1796
+ border-top-color: var(--ds-color-success-border);
1797
+ border-bottom-color: var(--ds-color-success-border);
1798
+ }
1799
+
1800
+ .ds-alert--banner.ds-alert--warning {
1801
+ border-top-color: var(--ds-color-warning-border);
1802
+ border-bottom-color: var(--ds-color-warning-border);
1803
+ }
1804
+
1805
+ .ds-alert--banner.ds-alert--error {
1806
+ border-top-color: var(--ds-color-error-border);
1807
+ border-bottom-color: var(--ds-color-error-border);
1808
+ }
1809
+
1810
+ /* ==========================================================================
1811
+ Component: Divider
1812
+ Horizontal and vertical separators with optional centered label.
1813
+ ========================================================================== */
1814
+
1815
+ .ds-divider {
1816
+ border: none;
1817
+ border-top: 1px solid var(--ds-color-border);
1818
+ margin-block: var(--ds-space-4);
1819
+ width: 100%;
1820
+ }
1821
+
1822
+ /* --- Vertical --- */
1823
+
1824
+ .ds-divider--vertical {
1825
+ border-top: none;
1826
+ border-left: 1px solid var(--ds-color-border);
1827
+ display: inline-block;
1828
+ width: auto;
1829
+ height: auto;
1830
+ min-height: 1rem;
1831
+ align-self: stretch;
1832
+ margin-block: var(--ds-space-0);
1833
+ margin-inline: var(--ds-space-3);
1834
+ }
1835
+
1836
+ /* --- Subtle --- */
1837
+
1838
+ .ds-divider--subtle {
1839
+ border-color: var(--ds-color-border-subtle);
1840
+ }
1841
+
1842
+ /* --- Spacious --- */
1843
+
1844
+ .ds-divider--spacious {
1845
+ margin-block: var(--ds-space-8);
1846
+ }
1847
+
1848
+ .ds-divider--spacious.ds-divider--vertical {
1849
+ margin-block: var(--ds-space-0);
1850
+ margin-inline: var(--ds-space-6);
1851
+ }
1852
+
1853
+ /* --- Label (centered text with lines on either side) --- */
1854
+
1855
+ .ds-divider--label {
1856
+ border-top: none;
1857
+ display: flex;
1858
+ align-items: center;
1859
+ gap: var(--ds-space-3);
1860
+ font-family: var(--ds-font-sans);
1861
+ font-size: var(--ds-text-xs);
1862
+ font-weight: var(--ds-weight-medium);
1863
+ color: var(--ds-color-text-tertiary);
1864
+ text-transform: uppercase;
1865
+ letter-spacing: var(--ds-tracking-wide);
1866
+ white-space: nowrap;
1867
+ }
1868
+
1869
+ .ds-divider--label::before,
1870
+ .ds-divider--label::after {
1871
+ content: '';
1872
+ flex: 1;
1873
+ height: 0;
1874
+ border-top: 1px solid var(--ds-color-border);
1875
+ }
1876
+
1877
+ /* ==========================================================================
1878
+ Component: Dropdown
1879
+ Floating menu with surface bg, scale transition, keyboard-friendly items.
1880
+ ========================================================================== */
1881
+
1882
+ .ds-dropdown {
1883
+ position: relative;
1884
+ }
1885
+
1886
+ .ds-dropdown__trigger {
1887
+ display: inline-flex;
1888
+ align-items: center;
1889
+ cursor: pointer;
1890
+ }
1891
+
1892
+ /* --- Menu panel --- */
1893
+
1894
+ .ds-dropdown__menu {
1895
+ position: absolute;
1896
+ top: calc(100% + var(--ds-space-1));
1897
+ left: 0;
1898
+ z-index: var(--ds-z-dropdown);
1899
+ min-width: 12rem;
1900
+ padding-block: var(--ds-space-1);
1901
+ background-color: var(--ds-color-surface);
1902
+ border: 1px solid var(--ds-color-border);
1903
+ border-radius: var(--ds-radius-xl);
1904
+ box-shadow: var(--ds-shadow-lg);
1905
+ opacity: 0;
1906
+ visibility: hidden;
1907
+ transform: scale(0.96);
1908
+ transform-origin: top left;
1909
+ transition:
1910
+ opacity var(--ds-duration-normal) var(--ds-ease-default),
1911
+ visibility var(--ds-duration-normal) var(--ds-ease-default),
1912
+ transform var(--ds-duration-normal) var(--ds-ease-out-expo);
1913
+ }
1914
+
1915
+ /* Open state — modifier on menu or parent */
1916
+
1917
+ .ds-dropdown__menu--open,
1918
+ .ds-dropdown--open .ds-dropdown__menu {
1919
+ opacity: 1;
1920
+ visibility: visible;
1921
+ transform: scale(1);
1922
+ }
1923
+
1924
+ /* --- Alignment variants --- */
1925
+
1926
+ .ds-dropdown__menu--right {
1927
+ left: auto;
1928
+ right: 0;
1929
+ transform-origin: top right;
1930
+ }
1931
+
1932
+ .ds-dropdown__menu--up {
1933
+ top: auto;
1934
+ bottom: calc(100% + var(--ds-space-1));
1935
+ transform-origin: bottom left;
1936
+ }
1937
+
1938
+ .ds-dropdown__menu--up.ds-dropdown__menu--right {
1939
+ transform-origin: bottom right;
1940
+ }
1941
+
1942
+ /* --- Menu item --- */
1943
+
1944
+ .ds-dropdown__item {
1945
+ display: flex;
1946
+ flex-direction: row;
1947
+ align-items: center;
1948
+ gap: var(--ds-space-2);
1949
+ padding: var(--ds-space-1-5) var(--ds-space-3);
1950
+ margin-inline: var(--ds-space-1);
1951
+ font-size: var(--ds-text-sm);
1952
+ color: var(--ds-color-text-secondary);
1953
+ cursor: pointer;
1954
+ border-radius: var(--ds-radius-md);
1955
+ transition:
1956
+ color var(--ds-duration-fast) var(--ds-ease-default),
1957
+ background-color var(--ds-duration-fast) var(--ds-ease-default);
1958
+ }
1959
+
1960
+ .ds-dropdown__item:hover {
1961
+ background-color: var(--ds-color-bg-elevated);
1962
+ color: var(--ds-color-text);
1963
+ }
1964
+
1965
+ .ds-dropdown__item--active {
1966
+ background-color: var(--ds-color-bg-elevated);
1967
+ color: var(--ds-color-text);
1968
+ }
1969
+
1970
+ .ds-dropdown__item--danger:hover {
1971
+ color: var(--ds-color-error);
1972
+ }
1973
+
1974
+ .ds-dropdown__item--disabled {
1975
+ opacity: var(--ds-opacity-disabled);
1976
+ pointer-events: none;
1977
+ }
1978
+
1979
+ /* --- Item slots --- */
1980
+
1981
+ .ds-dropdown__item-icon {
1982
+ width: 1rem;
1983
+ height: 1rem;
1984
+ flex-shrink: 0;
1985
+ }
1986
+
1987
+ .ds-dropdown__item-label {
1988
+ flex: 1;
1989
+ }
1990
+
1991
+ .ds-dropdown__item-shortcut {
1992
+ margin-left: auto;
1993
+ font-size: var(--ds-text-xs);
1994
+ color: var(--ds-color-text-tertiary);
1995
+ }
1996
+
1997
+ /* --- Divider --- */
1998
+
1999
+ .ds-dropdown__divider {
2000
+ margin-block: var(--ds-space-1);
2001
+ border: 0;
2002
+ border-top: 1px solid var(--ds-color-border);
2003
+ }
2004
+
2005
+ /* --- Section header --- */
2006
+
2007
+ .ds-dropdown__header {
2008
+ padding: var(--ds-space-2) var(--ds-space-3);
2009
+ margin-inline: var(--ds-space-1);
2010
+ font-size: var(--ds-text-xs);
2011
+ font-weight: var(--ds-weight-medium);
2012
+ text-transform: uppercase;
2013
+ letter-spacing: var(--ds-tracking-wide);
2014
+ color: var(--ds-color-text-tertiary);
2015
+ }
2016
+
2017
+ /* ==========================================================================
2018
+ Component: Tooltip
2019
+ Inverted bubble with arrow, positioned via modifier classes.
2020
+ Default placement: top.
2021
+ ========================================================================== */
2022
+
2023
+ .ds-tooltip {
2024
+ position: relative;
2025
+ display: inline-flex;
2026
+ }
2027
+
2028
+ /* --- Tooltip bubble --- */
2029
+
2030
+ .ds-tooltip__content {
2031
+ position: absolute;
2032
+ z-index: var(--ds-z-tooltip);
2033
+ background-color: var(--ds-color-inverted);
2034
+ color: var(--ds-color-on-inverted);
2035
+ font-size: var(--ds-text-xs);
2036
+ font-weight: var(--ds-weight-medium);
2037
+ line-height: var(--ds-leading-snug);
2038
+ padding: var(--ds-space-1) var(--ds-space-2);
2039
+ border-radius: var(--ds-radius-md);
2040
+ white-space: nowrap;
2041
+ pointer-events: none;
2042
+ opacity: 0;
2043
+ visibility: hidden;
2044
+ transition:
2045
+ opacity var(--ds-duration-fast) var(--ds-ease-default),
2046
+ visibility var(--ds-duration-fast) var(--ds-ease-default),
2047
+ transform var(--ds-duration-fast) var(--ds-ease-out);
2048
+ }
2049
+
2050
+ /* --- Arrow (shared base) --- */
2051
+
2052
+ .ds-tooltip__content::after {
2053
+ content: '';
2054
+ position: absolute;
2055
+ border: 4px solid transparent;
2056
+ }
2057
+
2058
+ /* --- Show on hover --- */
2059
+
2060
+ .ds-tooltip:hover .ds-tooltip__content {
2061
+ opacity: 1;
2062
+ visibility: visible;
2063
+ }
2064
+
2065
+ /* --- Delay modifier --- */
2066
+
2067
+ .ds-tooltip--delay .ds-tooltip__content {
2068
+ transition-delay: 0ms;
2069
+ }
2070
+
2071
+ .ds-tooltip--delay:hover .ds-tooltip__content {
2072
+ transition-delay: 200ms;
2073
+ }
2074
+
2075
+ /* =============================================
2076
+ Placement: Top (default)
2077
+ ============================================= */
2078
+
2079
+ .ds-tooltip .ds-tooltip__content,
2080
+ .ds-tooltip--top .ds-tooltip__content {
2081
+ bottom: calc(100% + 8px);
2082
+ left: 50%;
2083
+ transform: translateX(-50%) translateY(4px);
2084
+ }
2085
+
2086
+ .ds-tooltip:hover .ds-tooltip__content,
2087
+ .ds-tooltip--top:hover .ds-tooltip__content {
2088
+ transform: translateX(-50%) translateY(0);
2089
+ }
2090
+
2091
+ /* Arrow — points down */
2092
+ .ds-tooltip .ds-tooltip__content::after,
2093
+ .ds-tooltip--top .ds-tooltip__content::after {
2094
+ top: 100%;
2095
+ left: 50%;
2096
+ transform: translateX(-50%);
2097
+ border-top-color: var(--ds-color-inverted);
2098
+ }
2099
+
2100
+ /* =============================================
2101
+ Placement: Bottom
2102
+ ============================================= */
2103
+
2104
+ .ds-tooltip--bottom .ds-tooltip__content {
2105
+ top: calc(100% + 8px);
2106
+ bottom: auto;
2107
+ left: 50%;
2108
+ transform: translateX(-50%) translateY(-4px);
2109
+ }
2110
+
2111
+ .ds-tooltip--bottom:hover .ds-tooltip__content {
2112
+ transform: translateX(-50%) translateY(0);
2113
+ }
2114
+
2115
+ /* Arrow — points up */
2116
+ .ds-tooltip--bottom .ds-tooltip__content::after {
2117
+ bottom: 100%;
2118
+ top: auto;
2119
+ left: 50%;
2120
+ transform: translateX(-50%);
2121
+ border-top-color: transparent;
2122
+ border-bottom-color: var(--ds-color-inverted);
2123
+ }
2124
+
2125
+ /* =============================================
2126
+ Placement: Left
2127
+ ============================================= */
2128
+
2129
+ .ds-tooltip--left .ds-tooltip__content {
2130
+ right: calc(100% + 8px);
2131
+ left: auto;
2132
+ bottom: auto;
2133
+ top: 50%;
2134
+ transform: translateY(-50%) translateX(4px);
2135
+ }
2136
+
2137
+ .ds-tooltip--left:hover .ds-tooltip__content {
2138
+ transform: translateY(-50%) translateX(0);
2139
+ }
2140
+
2141
+ /* Arrow — points right */
2142
+ .ds-tooltip--left .ds-tooltip__content::after {
2143
+ left: 100%;
2144
+ top: 50%;
2145
+ bottom: auto;
2146
+ right: auto;
2147
+ transform: translateY(-50%);
2148
+ border-top-color: transparent;
2149
+ border-left-color: var(--ds-color-inverted);
2150
+ }
2151
+
2152
+ /* =============================================
2153
+ Placement: Right
2154
+ ============================================= */
2155
+
2156
+ .ds-tooltip--right .ds-tooltip__content {
2157
+ left: calc(100% + 8px);
2158
+ right: auto;
2159
+ bottom: auto;
2160
+ top: 50%;
2161
+ transform: translateY(-50%) translateX(-4px);
2162
+ }
2163
+
2164
+ .ds-tooltip--right:hover .ds-tooltip__content {
2165
+ transform: translateY(-50%) translateX(0);
2166
+ }
2167
+
2168
+ /* Arrow — points left */
2169
+ .ds-tooltip--right .ds-tooltip__content::after {
2170
+ right: 100%;
2171
+ left: auto;
2172
+ top: 50%;
2173
+ bottom: auto;
2174
+ transform: translateY(-50%);
2175
+ border-top-color: transparent;
2176
+ border-right-color: var(--ds-color-inverted);
2177
+ }
2178
+
2179
+ /* ==========================================================================
2180
+ Component: Avatar
2181
+ User photos, token images, initials. Stackable in groups.
2182
+ ========================================================================== */
2183
+
2184
+ .ds-avatar {
2185
+ display: inline-flex;
2186
+ align-items: center;
2187
+ justify-content: center;
2188
+ width: 2.5rem;
2189
+ height: 2.5rem;
2190
+ border-radius: var(--ds-radius-full);
2191
+ background-color: var(--ds-color-bg-elevated);
2192
+ color: var(--ds-color-text-secondary);
2193
+ font-family: var(--ds-font-sans);
2194
+ font-size: var(--ds-text-sm);
2195
+ font-weight: var(--ds-weight-medium);
2196
+ line-height: var(--ds-leading-none);
2197
+ overflow: hidden;
2198
+ flex-shrink: 0;
2199
+ position: relative;
2200
+ }
2201
+
2202
+ .ds-avatar img {
2203
+ width: 100%;
2204
+ height: 100%;
2205
+ object-fit: cover;
2206
+ }
2207
+
2208
+ /* --- Sizes --- */
2209
+
2210
+ .ds-avatar--xs {
2211
+ width: 1.5rem;
2212
+ height: 1.5rem;
2213
+ font-size: var(--ds-text-xs);
2214
+ }
2215
+
2216
+ .ds-avatar--sm {
2217
+ width: 2rem;
2218
+ height: 2rem;
2219
+ font-size: var(--ds-text-xs);
2220
+ }
2221
+
2222
+ .ds-avatar--md {
2223
+ width: 2.5rem;
2224
+ height: 2.5rem;
2225
+ font-size: var(--ds-text-sm);
2226
+ }
2227
+
2228
+ .ds-avatar--lg {
2229
+ width: 3rem;
2230
+ height: 3rem;
2231
+ font-size: var(--ds-text-base);
2232
+ }
2233
+
2234
+ .ds-avatar--xl {
2235
+ width: 4rem;
2236
+ height: 4rem;
2237
+ font-size: var(--ds-text-lg);
2238
+ }
2239
+
2240
+ /* --- Shape variants --- */
2241
+
2242
+ .ds-avatar--square {
2243
+ border-radius: var(--ds-radius-lg);
2244
+ }
2245
+
2246
+ .ds-avatar--bordered {
2247
+ border: 2px solid var(--ds-color-surface);
2248
+ }
2249
+
2250
+ /* --- Avatar Group --- */
2251
+
2252
+ .ds-avatar-group {
2253
+ display: flex;
2254
+ align-items: center;
2255
+ }
2256
+
2257
+ .ds-avatar-group > .ds-avatar + .ds-avatar {
2258
+ margin-left: -0.5rem;
2259
+ }
2260
+
2261
+ .ds-avatar-group--sm > .ds-avatar + .ds-avatar {
2262
+ margin-left: -0.375rem;
2263
+ }
2264
+
2265
+ /* --- Status indicator --- */
2266
+
2267
+ .ds-avatar__status {
2268
+ position: absolute;
2269
+ bottom: 0;
2270
+ right: 0;
2271
+ width: 0.625rem;
2272
+ height: 0.625rem;
2273
+ border-radius: var(--ds-radius-full);
2274
+ border: 2px solid var(--ds-color-surface);
2275
+ }
2276
+
2277
+ .ds-avatar__status--online {
2278
+ background-color: var(--ds-color-success);
2279
+ }
2280
+
2281
+ .ds-avatar__status--offline {
2282
+ background-color: var(--ds-color-text-tertiary);
2283
+ }
2284
+
2285
+ .ds-avatar__status--busy {
2286
+ background-color: var(--ds-color-error);
2287
+ }
2288
+
2289
+ /* ==========================================================================
2290
+ Component: Skeleton
2291
+ Loading placeholders with a subtle pulse animation.
2292
+ ========================================================================== */
2293
+
2294
+ .ds-skeleton {
2295
+ display: block;
2296
+ background-color: var(--ds-color-bg-muted);
2297
+ border-radius: var(--ds-radius-md);
2298
+ animation: ds-skeleton-pulse var(--ds-duration-slower) var(--ds-ease-default) infinite;
2299
+ }
2300
+
2301
+ /* --- Text variants --- */
2302
+
2303
+ .ds-skeleton--text {
2304
+ height: 1rem;
2305
+ width: 100%;
2306
+ border-radius: var(--ds-radius-sm);
2307
+ margin-bottom: var(--ds-space-2);
2308
+ }
2309
+
2310
+ .ds-skeleton--text-sm {
2311
+ height: 0.75rem;
2312
+ width: 100%;
2313
+ border-radius: var(--ds-radius-sm);
2314
+ margin-bottom: var(--ds-space-2);
2315
+ }
2316
+
2317
+ .ds-skeleton--text-lg {
2318
+ height: 1.5rem;
2319
+ width: 100%;
2320
+ border-radius: var(--ds-radius-sm);
2321
+ margin-bottom: var(--ds-space-2);
2322
+ }
2323
+
2324
+ .ds-skeleton--heading {
2325
+ height: 2rem;
2326
+ width: 60%;
2327
+ border-radius: var(--ds-radius-md);
2328
+ margin-bottom: var(--ds-space-3);
2329
+ }
2330
+
2331
+ /* --- Shape variants --- */
2332
+
2333
+ .ds-skeleton--circle,
2334
+ .ds-skeleton--avatar {
2335
+ width: 2.5rem;
2336
+ height: 2.5rem;
2337
+ border-radius: var(--ds-radius-full);
2338
+ }
2339
+
2340
+ .ds-skeleton--card {
2341
+ height: 12rem;
2342
+ width: 100%;
2343
+ border-radius: var(--ds-radius-xl);
2344
+ }
2345
+
2346
+ /* --- UI element variants --- */
2347
+
2348
+ .ds-skeleton--btn {
2349
+ height: 2.25rem;
2350
+ width: 6rem;
2351
+ border-radius: var(--ds-radius-lg);
2352
+ }
2353
+
2354
+ .ds-skeleton--input {
2355
+ height: 2.5rem;
2356
+ width: 100%;
2357
+ border-radius: var(--ds-radius-lg);
2358
+ }
2359
+
2360
+ /* --- Width modifiers --- */
2361
+
2362
+ .ds-skeleton--w-1\/2 {
2363
+ width: 50%;
2364
+ }
2365
+
2366
+ .ds-skeleton--w-3\/4 {
2367
+ width: 75%;
2368
+ }
2369
+
2370
+ .ds-skeleton--w-1\/3 {
2371
+ width: 33%;
2372
+ }
2373
+
2374
+ /* --- Pulse animation --- */
2375
+
2376
+ @keyframes ds-skeleton-pulse {
2377
+ 0%,
2378
+ 100% {
2379
+ opacity: 1;
2380
+ }
2381
+ 50% {
2382
+ opacity: 0.4;
2383
+ }
2384
+ }
2385
+
2386
+ /* ==========================================================================
2387
+ Component: Empty State
2388
+ Centered message for when there's no data to display.
2389
+ ========================================================================== */
2390
+
2391
+ .ds-empty-state {
2392
+ display: flex;
2393
+ flex-direction: column;
2394
+ align-items: center;
2395
+ justify-content: center;
2396
+ text-align: center;
2397
+ padding: var(--ds-space-12);
2398
+ gap: var(--ds-space-4);
2399
+ }
2400
+
2401
+ .ds-empty-state__icon {
2402
+ width: 3rem;
2403
+ height: 3rem;
2404
+ color: var(--ds-color-text-tertiary);
2405
+ margin-bottom: var(--ds-space-2);
2406
+ }
2407
+
2408
+ .ds-empty-state__title {
2409
+ font-family: var(--ds-font-display);
2410
+ font-weight: var(--ds-font-display-weight);
2411
+ font-size: var(--ds-text-lg);
2412
+ color: var(--ds-color-text);
2413
+ letter-spacing: var(--ds-tracking-tight);
2414
+ line-height: var(--ds-leading-tight);
2415
+ }
2416
+
2417
+ .ds-empty-state__description {
2418
+ font-size: var(--ds-text-sm);
2419
+ color: var(--ds-color-text-secondary);
2420
+ max-width: 20rem;
2421
+ line-height: var(--ds-leading-relaxed);
2422
+ }
2423
+
2424
+ .ds-empty-state__actions {
2425
+ display: flex;
2426
+ flex-direction: row;
2427
+ align-items: center;
2428
+ justify-content: center;
2429
+ gap: var(--ds-space-3);
2430
+ margin-top: var(--ds-space-2);
2431
+ }
2432
+
2433
+ /* --- Compact variant --- */
2434
+
2435
+ .ds-empty-state--compact {
2436
+ padding: var(--ds-space-8);
2437
+ }
2438
+
2439
+ .ds-empty-state--compact .ds-empty-state__icon {
2440
+ width: 2rem;
2441
+ height: 2rem;
2442
+ }
2443
+
2444
+ .ds-empty-state--compact .ds-empty-state__title {
2445
+ font-size: var(--ds-text-base);
2446
+ }
2447
+
2448
+ /* --- Card variant --- */
2449
+
2450
+ .ds-empty-state--card {
2451
+ background-color: var(--ds-color-surface);
2452
+ border: 1px solid var(--ds-color-border);
2453
+ border-radius: var(--ds-radius-xl);
2454
+ }
2455
+
2456
+
2457
+ /* === Tier 2 — Common === */
2458
+ /* ==========================================================================
2459
+ Toggle / Switch Component
2460
+ ==========================================================================
2461
+ A toggle (switch) control for binary on/off states.
2462
+ Supports aria-checked attribute and modifier-class driven states.
2463
+
2464
+ Usage:
2465
+ <button class="ds-toggle" role="switch" aria-checked="false"></button>
2466
+
2467
+ <label class="ds-toggle-label">
2468
+ <button class="ds-toggle" role="switch" aria-checked="true"></button>
2469
+ <span class="ds-toggle-label__text">Dark mode</span>
2470
+ </label>
2471
+ ========================================================================== */
2472
+
2473
+ /* ---------------------------------------------------------------------------
2474
+ Track
2475
+ --------------------------------------------------------------------------- */
2476
+
2477
+ .ds-toggle {
2478
+ display: inline-flex;
2479
+ position: relative;
2480
+ width: 2.75rem;
2481
+ height: 1.5rem;
2482
+ padding: 2px;
2483
+ border: none;
2484
+ border-radius: var(--ds-radius-full);
2485
+ background-color: var(--ds-color-bg-muted);
2486
+ cursor: pointer;
2487
+ transition: background-color var(--ds-duration-normal) var(--ds-ease-out);
2488
+ -webkit-appearance: none;
2489
+ appearance: none;
2490
+ flex-shrink: 0;
2491
+ }
2492
+
2493
+ /* ---------------------------------------------------------------------------
2494
+ Thumb (pseudo-element)
2495
+ --------------------------------------------------------------------------- */
2496
+
2497
+ .ds-toggle::after {
2498
+ content: "";
2499
+ position: absolute;
2500
+ left: 2px;
2501
+ top: 50%;
2502
+ width: 1.25rem;
2503
+ height: 1.25rem;
2504
+ border-radius: var(--ds-radius-full);
2505
+ background-color: #fff;
2506
+ box-shadow: var(--ds-shadow-sm);
2507
+ transform: translateY(-50%);
2508
+ transition: transform var(--ds-duration-normal) var(--ds-ease-out);
2509
+ }
2510
+
2511
+ /* ---------------------------------------------------------------------------
2512
+ Checked state
2513
+ --------------------------------------------------------------------------- */
2514
+
2515
+ .ds-toggle[aria-checked="true"],
2516
+ .ds-toggle--checked {
2517
+ background-color: var(--ds-color-interactive);
2518
+ }
2519
+
2520
+ .ds-toggle[aria-checked="true"]::after,
2521
+ .ds-toggle--checked::after {
2522
+ transform: translateX(1.25rem) translateY(-50%);
2523
+ }
2524
+
2525
+ /* ---------------------------------------------------------------------------
2526
+ Hover
2527
+ --------------------------------------------------------------------------- */
2528
+
2529
+ .ds-toggle:hover {
2530
+ background-color: var(--ds-color-border-hover);
2531
+ }
2532
+
2533
+ .ds-toggle[aria-checked="true"]:hover,
2534
+ .ds-toggle--checked:hover {
2535
+ background-color: var(--ds-color-interactive-hover);
2536
+ }
2537
+
2538
+ /* ---------------------------------------------------------------------------
2539
+ Focus
2540
+ --------------------------------------------------------------------------- */
2541
+
2542
+ .ds-toggle:focus-visible {
2543
+ outline: 2px solid var(--ds-color-interactive);
2544
+ outline-offset: 2px;
2545
+ }
2546
+
2547
+ /* ---------------------------------------------------------------------------
2548
+ Disabled
2549
+ --------------------------------------------------------------------------- */
2550
+
2551
+ .ds-toggle:disabled,
2552
+ .ds-toggle--disabled {
2553
+ opacity: var(--ds-opacity-disabled);
2554
+ cursor: not-allowed;
2555
+ pointer-events: none;
2556
+ }
2557
+
2558
+ /* ---------------------------------------------------------------------------
2559
+ Size: Small
2560
+ --------------------------------------------------------------------------- */
2561
+
2562
+ .ds-toggle--sm {
2563
+ width: 2rem;
2564
+ height: 1.125rem;
2565
+ }
2566
+
2567
+ .ds-toggle--sm::after {
2568
+ width: 0.875rem;
2569
+ height: 0.875rem;
2570
+ }
2571
+
2572
+ .ds-toggle--sm[aria-checked="true"]::after,
2573
+ .ds-toggle--sm.ds-toggle--checked::after {
2574
+ transform: translateX(0.875rem) translateY(-50%);
2575
+ }
2576
+
2577
+ /* ---------------------------------------------------------------------------
2578
+ Label wrapper
2579
+ --------------------------------------------------------------------------- */
2580
+
2581
+ .ds-toggle-label {
2582
+ display: inline-flex;
2583
+ align-items: center;
2584
+ gap: var(--ds-space-2);
2585
+ cursor: pointer;
2586
+ font-size: var(--ds-text-sm);
2587
+ font-family: var(--ds-font-sans);
2588
+ }
2589
+
2590
+ .ds-toggle-label__text {
2591
+ color: var(--ds-color-text-secondary);
2592
+ }
2593
+
2594
+ /* ==========================================================================
2595
+ Breadcrumb Navigation
2596
+ ==========================================================================
2597
+ A horizontal breadcrumb trail for hierarchical navigation.
2598
+
2599
+ Usage:
2600
+ <nav class="ds-breadcrumb" aria-label="Breadcrumb">
2601
+ <span class="ds-breadcrumb__item">
2602
+ <a href="/" class="ds-breadcrumb__link">Home</a>
2603
+ </span>
2604
+ <span class="ds-breadcrumb__item">
2605
+ <a href="/products" class="ds-breadcrumb__link">Products</a>
2606
+ </span>
2607
+ <span class="ds-breadcrumb__item">
2608
+ <span class="ds-breadcrumb__current" aria-current="page">Widget</span>
2609
+ </span>
2610
+ </nav>
2611
+ ========================================================================== */
2612
+
2613
+ /* ---------------------------------------------------------------------------
2614
+ Container
2615
+ --------------------------------------------------------------------------- */
2616
+
2617
+ .ds-breadcrumb {
2618
+ display: flex;
2619
+ flex-direction: row;
2620
+ align-items: center;
2621
+ gap: var(--ds-space-1);
2622
+ font-size: var(--ds-text-sm);
2623
+ font-family: var(--ds-font-sans);
2624
+ list-style: none;
2625
+ margin: 0;
2626
+ padding: 0;
2627
+ }
2628
+
2629
+ /* ---------------------------------------------------------------------------
2630
+ Item
2631
+ --------------------------------------------------------------------------- */
2632
+
2633
+ .ds-breadcrumb__item {
2634
+ display: flex;
2635
+ align-items: center;
2636
+ gap: var(--ds-space-1);
2637
+ }
2638
+
2639
+ /* Separator — rendered via ::after on every item except the last */
2640
+ .ds-breadcrumb__item:not(:last-child)::after {
2641
+ content: "/";
2642
+ color: var(--ds-color-text-tertiary);
2643
+ flex-shrink: 0;
2644
+ user-select: none;
2645
+ pointer-events: none;
2646
+ }
2647
+
2648
+ /* ---------------------------------------------------------------------------
2649
+ Link
2650
+ --------------------------------------------------------------------------- */
2651
+
2652
+ .ds-breadcrumb__link {
2653
+ color: var(--ds-color-text-tertiary);
2654
+ text-decoration: none;
2655
+ transition: color var(--ds-duration-fast) var(--ds-ease-out);
2656
+ }
2657
+
2658
+ .ds-breadcrumb__link:hover {
2659
+ color: var(--ds-color-text-secondary);
2660
+ }
2661
+
2662
+ .ds-breadcrumb__link:focus-visible {
2663
+ outline: 2px solid var(--ds-color-interactive);
2664
+ outline-offset: 2px;
2665
+ border-radius: var(--ds-radius-sm);
2666
+ }
2667
+
2668
+ /* ---------------------------------------------------------------------------
2669
+ Current page (non-interactive)
2670
+ --------------------------------------------------------------------------- */
2671
+
2672
+ .ds-breadcrumb__current {
2673
+ color: var(--ds-color-text);
2674
+ font-weight: var(--ds-weight-medium);
2675
+ }
2676
+
2677
+ /* ---------------------------------------------------------------------------
2678
+ Modifier: Compact
2679
+ --------------------------------------------------------------------------- */
2680
+
2681
+ .ds-breadcrumb--compact {
2682
+ gap: var(--ds-space-0-5, 0.125rem);
2683
+ font-size: var(--ds-text-xs);
2684
+ }
2685
+
2686
+ .ds-breadcrumb--compact .ds-breadcrumb__item {
2687
+ gap: var(--ds-space-0-5, 0.125rem);
2688
+ }
2689
+
2690
+ /* ==========================================================================
2691
+ Pagination Component
2692
+ ==========================================================================
2693
+ A row of page-number controls for navigating multi-page content.
2694
+
2695
+ Usage:
2696
+ <nav class="ds-pagination" aria-label="Pagination">
2697
+ <button class="ds-pagination__prev" aria-label="Previous page">&lsaquo;</button>
2698
+ <button class="ds-pagination__item">1</button>
2699
+ <button class="ds-pagination__item ds-pagination__item--active" aria-current="page">2</button>
2700
+ <span class="ds-pagination__ellipsis">&hellip;</span>
2701
+ <button class="ds-pagination__item">10</button>
2702
+ <button class="ds-pagination__next" aria-label="Next page">&rsaquo;</button>
2703
+ </nav>
2704
+ ========================================================================== */
2705
+
2706
+ /* ---------------------------------------------------------------------------
2707
+ Container
2708
+ --------------------------------------------------------------------------- */
2709
+
2710
+ .ds-pagination {
2711
+ display: flex;
2712
+ flex-direction: row;
2713
+ align-items: center;
2714
+ gap: var(--ds-space-1);
2715
+ font-family: var(--ds-font-sans);
2716
+ }
2717
+
2718
+ /* ---------------------------------------------------------------------------
2719
+ Item (page number)
2720
+ --------------------------------------------------------------------------- */
2721
+
2722
+ .ds-pagination__item {
2723
+ display: flex;
2724
+ align-items: center;
2725
+ justify-content: center;
2726
+ min-width: 2rem;
2727
+ height: 2rem;
2728
+ padding: 0 var(--ds-space-1);
2729
+ border: none;
2730
+ border-radius: var(--ds-radius-md);
2731
+ background: transparent;
2732
+ color: var(--ds-color-text-secondary);
2733
+ font-size: var(--ds-text-sm);
2734
+ font-family: var(--ds-font-sans);
2735
+ cursor: pointer;
2736
+ transition:
2737
+ background-color var(--ds-duration-fast) var(--ds-ease-out),
2738
+ color var(--ds-duration-fast) var(--ds-ease-out);
2739
+ -webkit-appearance: none;
2740
+ appearance: none;
2741
+ }
2742
+
2743
+ .ds-pagination__item:hover {
2744
+ background-color: var(--ds-color-bg-elevated);
2745
+ color: var(--ds-color-text);
2746
+ }
2747
+
2748
+ .ds-pagination__item:focus-visible {
2749
+ outline: 2px solid var(--ds-color-interactive);
2750
+ outline-offset: 2px;
2751
+ }
2752
+
2753
+ /* ---------------------------------------------------------------------------
2754
+ Active page
2755
+ --------------------------------------------------------------------------- */
2756
+
2757
+ .ds-pagination__item--active,
2758
+ .ds-pagination__item--active:hover {
2759
+ background-color: var(--ds-color-inverted);
2760
+ color: var(--ds-color-on-inverted);
2761
+ cursor: default;
2762
+ }
2763
+
2764
+ /* ---------------------------------------------------------------------------
2765
+ Disabled item
2766
+ --------------------------------------------------------------------------- */
2767
+
2768
+ .ds-pagination__item--disabled,
2769
+ .ds-pagination__item--disabled:hover {
2770
+ opacity: var(--ds-opacity-disabled);
2771
+ pointer-events: none;
2772
+ }
2773
+
2774
+ /* ---------------------------------------------------------------------------
2775
+ Previous / Next navigation buttons
2776
+ --------------------------------------------------------------------------- */
2777
+
2778
+ .ds-pagination__prev,
2779
+ .ds-pagination__next {
2780
+ display: flex;
2781
+ align-items: center;
2782
+ justify-content: center;
2783
+ min-width: 2rem;
2784
+ height: 2rem;
2785
+ padding: 0;
2786
+ border: none;
2787
+ border-radius: var(--ds-radius-md);
2788
+ background: transparent;
2789
+ color: var(--ds-color-text-secondary);
2790
+ font-size: var(--ds-text-sm);
2791
+ font-family: var(--ds-font-sans);
2792
+ cursor: pointer;
2793
+ transition:
2794
+ background-color var(--ds-duration-fast) var(--ds-ease-out),
2795
+ color var(--ds-duration-fast) var(--ds-ease-out);
2796
+ -webkit-appearance: none;
2797
+ appearance: none;
2798
+ }
2799
+
2800
+ .ds-pagination__prev:hover,
2801
+ .ds-pagination__next:hover {
2802
+ background-color: var(--ds-color-bg-elevated);
2803
+ color: var(--ds-color-text);
2804
+ }
2805
+
2806
+ .ds-pagination__prev:focus-visible,
2807
+ .ds-pagination__next:focus-visible {
2808
+ outline: 2px solid var(--ds-color-interactive);
2809
+ outline-offset: 2px;
2810
+ }
2811
+
2812
+ .ds-pagination__prev:disabled,
2813
+ .ds-pagination__next:disabled {
2814
+ opacity: var(--ds-opacity-disabled);
2815
+ pointer-events: none;
2816
+ }
2817
+
2818
+ /* ---------------------------------------------------------------------------
2819
+ Ellipsis
2820
+ --------------------------------------------------------------------------- */
2821
+
2822
+ .ds-pagination__ellipsis {
2823
+ display: flex;
2824
+ align-items: center;
2825
+ justify-content: center;
2826
+ min-width: 2rem;
2827
+ height: 2rem;
2828
+ color: var(--ds-color-text-tertiary);
2829
+ font-size: var(--ds-text-sm);
2830
+ user-select: none;
2831
+ pointer-events: none;
2832
+ }
2833
+
2834
+ /* ---------------------------------------------------------------------------
2835
+ Page info text (e.g. "Page 1 of 10")
2836
+ --------------------------------------------------------------------------- */
2837
+
2838
+ .ds-pagination__info {
2839
+ font-size: var(--ds-text-sm);
2840
+ color: var(--ds-color-text-tertiary);
2841
+ white-space: nowrap;
2842
+ }
2843
+
2844
+ /* ---------------------------------------------------------------------------
2845
+ Modifier: Compact
2846
+ --------------------------------------------------------------------------- */
2847
+
2848
+ .ds-pagination--compact .ds-pagination__item,
2849
+ .ds-pagination--compact .ds-pagination__prev,
2850
+ .ds-pagination--compact .ds-pagination__next,
2851
+ .ds-pagination--compact .ds-pagination__ellipsis {
2852
+ min-width: 1.75rem;
2853
+ height: 1.75rem;
2854
+ font-size: var(--ds-text-xs);
2855
+ }
2856
+
2857
+ /* ==========================================================================
2858
+ Tag / Chip Component
2859
+ ==========================================================================
2860
+ Interactive, optionally removable tag for categorisation and filtering.
2861
+
2862
+ Usage:
2863
+ <span class="ds-tag">Default</span>
2864
+ <span class="ds-tag ds-tag--success">Approved</span>
2865
+ <span class="ds-tag ds-tag--removable">
2866
+ Removable
2867
+ <button class="ds-tag__remove" aria-label="Remove">&times;</button>
2868
+ </span>
2869
+ ========================================================================== */
2870
+
2871
+ /* ---------------------------------------------------------------------------
2872
+ Base
2873
+ --------------------------------------------------------------------------- */
2874
+
2875
+ .ds-tag {
2876
+ display: inline-flex;
2877
+ align-items: center;
2878
+ gap: var(--ds-space-1);
2879
+ padding: var(--ds-space-1) var(--ds-space-2-5, 0.625rem);
2880
+ font-size: var(--ds-text-xs);
2881
+ font-weight: var(--ds-weight-medium);
2882
+ font-family: var(--ds-font-sans);
2883
+ line-height: 1;
2884
+ border-radius: var(--ds-radius-full);
2885
+ background-color: var(--ds-color-bg-elevated);
2886
+ border: 1px solid var(--ds-color-border);
2887
+ color: var(--ds-color-text-secondary);
2888
+ white-space: nowrap;
2889
+ transition:
2890
+ border-color var(--ds-duration-fast) var(--ds-ease-out),
2891
+ background-color var(--ds-duration-fast) var(--ds-ease-out);
2892
+ }
2893
+
2894
+ .ds-tag:hover {
2895
+ border-color: var(--ds-color-border-hover);
2896
+ }
2897
+
2898
+ /* ---------------------------------------------------------------------------
2899
+ Color variants — subtle background + vivid text + subtle border
2900
+ --------------------------------------------------------------------------- */
2901
+
2902
+ .ds-tag--primary {
2903
+ background-color: var(--ds-color-interactive-subtle, var(--ds-color-bg-elevated));
2904
+ color: var(--ds-color-interactive);
2905
+ border-color: var(--ds-color-interactive-border, var(--ds-color-interactive));
2906
+ }
2907
+
2908
+ .ds-tag--success {
2909
+ background-color: var(--ds-color-success-subtle, var(--ds-color-bg-elevated));
2910
+ color: var(--ds-color-success);
2911
+ border-color: var(--ds-color-success-border, var(--ds-color-success));
2912
+ }
2913
+
2914
+ .ds-tag--warning {
2915
+ background-color: var(--ds-color-warning-subtle, var(--ds-color-bg-elevated));
2916
+ color: var(--ds-color-warning);
2917
+ border-color: var(--ds-color-warning-border, var(--ds-color-warning));
2918
+ }
2919
+
2920
+ .ds-tag--error {
2921
+ background-color: var(--ds-color-error-subtle, var(--ds-color-bg-elevated));
2922
+ color: var(--ds-color-error);
2923
+ border-color: var(--ds-color-error-border, var(--ds-color-error));
2924
+ }
2925
+
2926
+ .ds-tag--info {
2927
+ background-color: var(--ds-color-info-subtle, var(--ds-color-bg-elevated));
2928
+ color: var(--ds-color-info);
2929
+ border-color: var(--ds-color-info-border, var(--ds-color-info));
2930
+ }
2931
+
2932
+ .ds-tag--purple {
2933
+ background-color: var(--ds-color-purple-subtle, var(--ds-color-bg-elevated));
2934
+ color: var(--ds-color-purple, var(--ds-color-interactive));
2935
+ border-color: var(--ds-color-purple-border, var(--ds-color-purple, var(--ds-color-interactive)));
2936
+ }
2937
+
2938
+ /* ---------------------------------------------------------------------------
2939
+ Removable — tighter right padding for the close button
2940
+ --------------------------------------------------------------------------- */
2941
+
2942
+ .ds-tag--removable {
2943
+ padding-right: var(--ds-space-1);
2944
+ }
2945
+
2946
+ /* ---------------------------------------------------------------------------
2947
+ Remove button
2948
+ --------------------------------------------------------------------------- */
2949
+
2950
+ .ds-tag__remove {
2951
+ display: inline-flex;
2952
+ align-items: center;
2953
+ justify-content: center;
2954
+ width: 1rem;
2955
+ height: 1rem;
2956
+ padding: 0;
2957
+ border: none;
2958
+ border-radius: var(--ds-radius-full);
2959
+ background: transparent;
2960
+ color: currentColor;
2961
+ font-size: inherit;
2962
+ line-height: 1;
2963
+ opacity: 0.6;
2964
+ cursor: pointer;
2965
+ transition:
2966
+ opacity var(--ds-duration-fast) var(--ds-ease-out),
2967
+ background-color var(--ds-duration-fast) var(--ds-ease-out);
2968
+ -webkit-appearance: none;
2969
+ appearance: none;
2970
+ }
2971
+
2972
+ .ds-tag__remove:hover {
2973
+ opacity: 1;
2974
+ background-color: var(--ds-color-overlay-hover);
2975
+ }
2976
+
2977
+ .ds-tag__remove:focus-visible {
2978
+ outline: 2px solid var(--ds-color-interactive);
2979
+ outline-offset: 1px;
2980
+ opacity: 1;
2981
+ }
2982
+
2983
+ /* ---------------------------------------------------------------------------
2984
+ Variant: Outline
2985
+ --------------------------------------------------------------------------- */
2986
+
2987
+ .ds-tag--outline {
2988
+ background-color: transparent;
2989
+ }
2990
+
2991
+ /* ---------------------------------------------------------------------------
2992
+ Size: Small
2993
+ --------------------------------------------------------------------------- */
2994
+
2995
+ .ds-tag--sm {
2996
+ padding: var(--ds-space-0-5, 0.125rem) var(--ds-space-2, 0.5rem);
2997
+ font-size: 0.625rem;
2998
+ }
2999
+
3000
+ .ds-tag--sm.ds-tag--removable {
3001
+ padding-right: var(--ds-space-0-5, 0.125rem);
3002
+ }
3003
+
3004
+ /* ---------------------------------------------------------------------------
3005
+ Size: Large
3006
+ --------------------------------------------------------------------------- */
3007
+
3008
+ .ds-tag--lg {
3009
+ padding: var(--ds-space-1-5, 0.375rem) var(--ds-space-3);
3010
+ font-size: var(--ds-text-sm);
3011
+ }
3012
+
3013
+ .ds-tag--lg.ds-tag--removable {
3014
+ padding-right: var(--ds-space-1-5, 0.375rem);
3015
+ }
3016
+
3017
+ /* ==========================================================================
3018
+ * Accordion / Collapse
3019
+ * ==========================================================================
3020
+ *
3021
+ * A vertically stacked set of collapsible sections. Supports CSS-only
3022
+ * open/close via the `.ds-accordion__item--open` modifier.
3023
+ *
3024
+ * Variants:
3025
+ * --flush – borderless, full-bleed style
3026
+ * --separated – visually detached items with individual borders
3027
+ *
3028
+ * Markup:
3029
+ * <div class="ds-accordion">
3030
+ * <div class="ds-accordion__item ds-accordion__item--open">
3031
+ * <button class="ds-accordion__trigger">Section</button>
3032
+ * <div class="ds-accordion__content">
3033
+ * <div class="ds-accordion__body">…</div>
3034
+ * </div>
3035
+ * </div>
3036
+ * </div>
3037
+ * ========================================================================== */
3038
+
3039
+ /* Container
3040
+ * -------------------------------------------------------------------------- */
3041
+
3042
+ .ds-accordion {
3043
+ border: 1px solid var(--ds-color-border);
3044
+ border-radius: var(--ds-radius-xl);
3045
+ overflow: hidden;
3046
+ }
3047
+
3048
+ /* Item
3049
+ * -------------------------------------------------------------------------- */
3050
+
3051
+ .ds-accordion__item {
3052
+ border-top: 1px solid var(--ds-color-border);
3053
+ }
3054
+
3055
+ .ds-accordion__item:first-child {
3056
+ border-top: 0;
3057
+ }
3058
+
3059
+ /* Trigger (button)
3060
+ * -------------------------------------------------------------------------- */
3061
+
3062
+ .ds-accordion__trigger {
3063
+ display: flex;
3064
+ flex-direction: row;
3065
+ justify-content: space-between;
3066
+ align-items: center;
3067
+ width: 100%;
3068
+ padding: var(--ds-space-4);
3069
+ text-align: left;
3070
+ font-family: var(--ds-font-sans);
3071
+ font-size: var(--ds-text-sm);
3072
+ font-weight: var(--ds-weight-medium);
3073
+ color: var(--ds-color-text);
3074
+ background: transparent;
3075
+ border: 0;
3076
+ cursor: pointer;
3077
+ transition: background-color var(--ds-duration-fast) var(--ds-ease-default);
3078
+ }
3079
+
3080
+ /* Chevron indicator (CSS border-arrow) */
3081
+ .ds-accordion__trigger::after {
3082
+ content: "";
3083
+ display: inline-block;
3084
+ width: 0.5rem;
3085
+ height: 0.5rem;
3086
+ border-right: 2px solid var(--ds-color-text-secondary);
3087
+ border-bottom: 2px solid var(--ds-color-text-secondary);
3088
+ transform: rotate(45deg);
3089
+ flex-shrink: 0;
3090
+ margin-left: var(--ds-space-3);
3091
+ transition: transform var(--ds-duration-fast) var(--ds-ease-default);
3092
+ }
3093
+
3094
+ .ds-accordion__trigger:hover {
3095
+ background-color: var(--ds-color-overlay);
3096
+ }
3097
+
3098
+ /* Open state – rotate chevron */
3099
+ .ds-accordion__item--open .ds-accordion__trigger::after {
3100
+ transform: rotate(225deg);
3101
+ }
3102
+
3103
+ /* Collapsible content wrapper
3104
+ * -------------------------------------------------------------------------- */
3105
+
3106
+ .ds-accordion__content {
3107
+ max-height: 0;
3108
+ overflow: hidden;
3109
+ transition:
3110
+ max-height var(--ds-duration-normal) var(--ds-ease-default),
3111
+ padding var(--ds-duration-normal) var(--ds-ease-default);
3112
+ }
3113
+
3114
+ .ds-accordion__item--open .ds-accordion__content {
3115
+ max-height: 80rem;
3116
+ }
3117
+
3118
+ /* Inner body (visible content)
3119
+ * -------------------------------------------------------------------------- */
3120
+
3121
+ .ds-accordion__body {
3122
+ padding: var(--ds-space-4);
3123
+ padding-top: 0;
3124
+ font-size: var(--ds-text-sm);
3125
+ color: var(--ds-color-text-secondary);
3126
+ line-height: 1.625;
3127
+ }
3128
+
3129
+ /* ==========================================================================
3130
+ * Variant: Flush
3131
+ * ========================================================================== */
3132
+
3133
+ .ds-accordion--flush {
3134
+ border: 0;
3135
+ border-radius: 0;
3136
+ }
3137
+
3138
+ .ds-accordion--flush .ds-accordion__item {
3139
+ border-top: 0;
3140
+ border-bottom: 1px solid var(--ds-color-border);
3141
+ }
3142
+
3143
+ .ds-accordion--flush .ds-accordion__item:last-child {
3144
+ border-bottom: 0;
3145
+ }
3146
+
3147
+ /* ==========================================================================
3148
+ * Variant: Separated
3149
+ * ========================================================================== */
3150
+
3151
+ .ds-accordion--separated {
3152
+ border: 0;
3153
+ border-radius: 0;
3154
+ overflow: visible;
3155
+ }
3156
+
3157
+ .ds-accordion--separated .ds-accordion__item {
3158
+ border: 1px solid var(--ds-color-border);
3159
+ border-radius: var(--ds-radius-xl);
3160
+ margin-bottom: var(--ds-space-3);
3161
+ overflow: hidden;
3162
+ }
3163
+
3164
+ .ds-accordion--separated .ds-accordion__item:last-child {
3165
+ margin-bottom: 0;
3166
+ }
3167
+
3168
+ /* ==========================================================================
3169
+ * Drawer / Sheet
3170
+ * ==========================================================================
3171
+ *
3172
+ * A sliding overlay panel anchored to the edge of the viewport.
3173
+ * Default direction is right; use `--left` or `--bottom` modifiers
3174
+ * to change the slide origin.
3175
+ *
3176
+ * Sizes:
3177
+ * --sm 18 rem
3178
+ * (default) 24 rem
3179
+ * --lg 36 rem
3180
+ *
3181
+ * Markup:
3182
+ * <div class="ds-drawer ds-drawer--right ds-drawer--open">
3183
+ * <div class="ds-drawer__content">
3184
+ * <div class="ds-drawer__header">
3185
+ * <h3>Title</h3>
3186
+ * <button class="ds-drawer__close" aria-label="Close">&times;</button>
3187
+ * </div>
3188
+ * <div class="ds-drawer__body">…</div>
3189
+ * <div class="ds-drawer__footer">…</div>
3190
+ * </div>
3191
+ * </div>
3192
+ * ========================================================================== */
3193
+
3194
+ /* Overlay backdrop
3195
+ * -------------------------------------------------------------------------- */
3196
+
3197
+ .ds-drawer {
3198
+ position: fixed;
3199
+ inset: 0;
3200
+ z-index: var(--ds-z-overlay);
3201
+ background-color: var(--ds-color-overlay);
3202
+ opacity: 0;
3203
+ visibility: hidden;
3204
+ transition:
3205
+ opacity var(--ds-duration-normal) var(--ds-ease-default),
3206
+ visibility var(--ds-duration-normal) var(--ds-ease-default);
3207
+ }
3208
+
3209
+ .ds-drawer--open {
3210
+ opacity: 1;
3211
+ visibility: visible;
3212
+ }
3213
+
3214
+ /* Sliding panel
3215
+ * -------------------------------------------------------------------------- */
3216
+
3217
+ .ds-drawer__content {
3218
+ position: fixed;
3219
+ display: flex;
3220
+ flex-direction: column;
3221
+ background-color: var(--ds-color-surface);
3222
+ box-shadow: var(--ds-shadow-lg);
3223
+ overflow-y: auto;
3224
+ transition: transform var(--ds-duration-normal) var(--ds-ease-out-expo);
3225
+ }
3226
+
3227
+ /* ==========================================================================
3228
+ * Direction: Right (default)
3229
+ * ========================================================================== */
3230
+
3231
+ .ds-drawer__content,
3232
+ .ds-drawer--right .ds-drawer__content {
3233
+ top: 0;
3234
+ right: 0;
3235
+ bottom: 0;
3236
+ width: 24rem;
3237
+ max-width: 90vw;
3238
+ border-left: 1px solid var(--ds-color-border);
3239
+ transform: translateX(100%);
3240
+ }
3241
+
3242
+ .ds-drawer--open .ds-drawer__content,
3243
+ .ds-drawer--right.ds-drawer--open .ds-drawer__content {
3244
+ transform: translateX(0);
3245
+ }
3246
+
3247
+ /* ==========================================================================
3248
+ * Direction: Left
3249
+ * ========================================================================== */
3250
+
3251
+ .ds-drawer--left .ds-drawer__content {
3252
+ left: 0;
3253
+ top: 0;
3254
+ bottom: 0;
3255
+ right: auto;
3256
+ width: 24rem;
3257
+ max-width: 90vw;
3258
+ border-left: 0;
3259
+ border-right: 1px solid var(--ds-color-border);
3260
+ transform: translateX(-100%);
3261
+ }
3262
+
3263
+ .ds-drawer--left.ds-drawer--open .ds-drawer__content {
3264
+ transform: translateX(0);
3265
+ }
3266
+
3267
+ /* ==========================================================================
3268
+ * Direction: Bottom
3269
+ * ========================================================================== */
3270
+
3271
+ .ds-drawer--bottom .ds-drawer__content {
3272
+ bottom: 0;
3273
+ left: 0;
3274
+ right: 0;
3275
+ top: auto;
3276
+ width: auto;
3277
+ max-height: 90dvh;
3278
+ border-left: 0;
3279
+ border-top: 1px solid var(--ds-color-border);
3280
+ border-radius: var(--ds-radius-xl) var(--ds-radius-xl) 0 0;
3281
+ transform: translateY(100%);
3282
+ }
3283
+
3284
+ .ds-drawer--bottom.ds-drawer--open .ds-drawer__content {
3285
+ transform: translateY(0);
3286
+ }
3287
+
3288
+ /* ==========================================================================
3289
+ * Sizes
3290
+ * ========================================================================== */
3291
+
3292
+ .ds-drawer--sm .ds-drawer__content {
3293
+ width: 18rem;
3294
+ }
3295
+
3296
+ .ds-drawer--lg .ds-drawer__content {
3297
+ width: 36rem;
3298
+ }
3299
+
3300
+ /* Bottom drawers should not have a fixed width */
3301
+ .ds-drawer--bottom.ds-drawer--sm .ds-drawer__content,
3302
+ .ds-drawer--bottom.ds-drawer--lg .ds-drawer__content {
3303
+ width: auto;
3304
+ }
3305
+
3306
+ /* ==========================================================================
3307
+ * Header
3308
+ * ========================================================================== */
3309
+
3310
+ .ds-drawer__header {
3311
+ display: flex;
3312
+ justify-content: space-between;
3313
+ align-items: flex-start;
3314
+ padding: var(--ds-space-4) var(--ds-space-5);
3315
+ border-bottom: 1px solid var(--ds-color-border);
3316
+ }
3317
+
3318
+ .ds-drawer__header h3 {
3319
+ font-family: var(--ds-font-display);
3320
+ font-weight: var(--ds-font-display-weight);
3321
+ font-size: var(--ds-text-lg);
3322
+ color: var(--ds-color-text);
3323
+ margin: 0;
3324
+ }
3325
+
3326
+ /* ==========================================================================
3327
+ * Close button
3328
+ * ========================================================================== */
3329
+
3330
+ .ds-drawer__close {
3331
+ display: flex;
3332
+ align-items: center;
3333
+ justify-content: center;
3334
+ width: 2rem;
3335
+ height: 2rem;
3336
+ padding: 0;
3337
+ border: 0;
3338
+ border-radius: var(--ds-radius-md);
3339
+ background-color: transparent;
3340
+ color: var(--ds-color-text-tertiary);
3341
+ font-size: var(--ds-text-lg);
3342
+ line-height: 1;
3343
+ cursor: pointer;
3344
+ flex-shrink: 0;
3345
+ transition:
3346
+ background-color var(--ds-duration-fast) var(--ds-ease-default),
3347
+ color var(--ds-duration-fast) var(--ds-ease-default);
3348
+ }
3349
+
3350
+ .ds-drawer__close:hover {
3351
+ background-color: var(--ds-color-overlay);
3352
+ color: var(--ds-color-text);
3353
+ }
3354
+
3355
+ /* ==========================================================================
3356
+ * Body
3357
+ * ========================================================================== */
3358
+
3359
+ .ds-drawer__body {
3360
+ padding: var(--ds-space-5);
3361
+ flex: 1;
3362
+ overflow-y: auto;
3363
+ }
3364
+
3365
+ /* ==========================================================================
3366
+ * Footer
3367
+ * ========================================================================== */
3368
+
3369
+ .ds-drawer__footer {
3370
+ padding: var(--ds-space-4) var(--ds-space-5);
3371
+ border-top: 1px solid var(--ds-color-border);
3372
+ display: flex;
3373
+ align-items: center;
3374
+ justify-content: flex-end;
3375
+ gap: var(--ds-space-2);
3376
+ }
3377
+
3378
+ /* ==========================================================================
3379
+ * Progress Bar & Step Indicator
3380
+ * ==========================================================================
3381
+ *
3382
+ * Two related components for communicating progress:
3383
+ *
3384
+ * 1. **Progress bar** — a horizontal fill bar with optional label row.
3385
+ * Sizes: --sm, (default), --lg
3386
+ * Statuses: --success, --warning, --error, --info
3387
+ *
3388
+ * 2. **Step indicator** — a numbered sequence of steps with connectors.
3389
+ * States: --completed, --current, --error
3390
+ * Layout: horizontal (default), --vertical
3391
+ *
3392
+ * Progress bar markup:
3393
+ * <div class="ds-progress__label">
3394
+ * <span>Uploading…</span><span>64 %</span>
3395
+ * </div>
3396
+ * <div class="ds-progress">
3397
+ * <div class="ds-progress__bar" style="width: 64%"></div>
3398
+ * </div>
3399
+ *
3400
+ * Step indicator markup:
3401
+ * <div class="ds-steps">
3402
+ * <div class="ds-step ds-step--completed">
3403
+ * <div class="ds-step__indicator">1</div>
3404
+ * <div class="ds-step__content">
3405
+ * <span class="ds-step__title">Account</span>
3406
+ * <span class="ds-step__description">Create your account</span>
3407
+ * </div>
3408
+ * </div>
3409
+ * <div class="ds-step__connector"></div>
3410
+ * <div class="ds-step ds-step--current">…</div>
3411
+ * </div>
3412
+ * ========================================================================== */
3413
+
3414
+ /* ==========================================================================
3415
+ * Progress Bar
3416
+ * ========================================================================== */
3417
+
3418
+ /* Label row (sits above the bar) */
3419
+ .ds-progress__label {
3420
+ display: flex;
3421
+ justify-content: space-between;
3422
+ font-size: var(--ds-text-xs);
3423
+ color: var(--ds-color-text-tertiary);
3424
+ margin-bottom: var(--ds-space-1-5);
3425
+ }
3426
+
3427
+ /* Track */
3428
+ .ds-progress {
3429
+ width: 100%;
3430
+ height: 0.5rem;
3431
+ background-color: var(--ds-color-bg-muted);
3432
+ border-radius: var(--ds-radius-full);
3433
+ overflow: hidden;
3434
+ }
3435
+
3436
+ /* Fill */
3437
+ .ds-progress__bar {
3438
+ height: 100%;
3439
+ min-width: 0.25rem;
3440
+ background-color: var(--ds-color-inverted);
3441
+ border-radius: var(--ds-radius-full);
3442
+ transition: width var(--ds-duration-normal) var(--ds-ease-default);
3443
+ }
3444
+
3445
+ /* Sizes
3446
+ * -------------------------------------------------------------------------- */
3447
+
3448
+ .ds-progress--sm {
3449
+ height: 0.25rem;
3450
+ }
3451
+
3452
+ .ds-progress--lg {
3453
+ height: 0.75rem;
3454
+ }
3455
+
3456
+ /* Status colours
3457
+ * -------------------------------------------------------------------------- */
3458
+
3459
+ .ds-progress--success .ds-progress__bar {
3460
+ background-color: var(--ds-color-success);
3461
+ }
3462
+
3463
+ .ds-progress--warning .ds-progress__bar {
3464
+ background-color: var(--ds-color-warning);
3465
+ }
3466
+
3467
+ .ds-progress--error .ds-progress__bar {
3468
+ background-color: var(--ds-color-error);
3469
+ }
3470
+
3471
+ .ds-progress--info .ds-progress__bar {
3472
+ background-color: var(--ds-color-info);
3473
+ }
3474
+
3475
+ /* ==========================================================================
3476
+ * Step Indicator
3477
+ * ========================================================================== */
3478
+
3479
+ /* Steps container (horizontal by default) */
3480
+ .ds-steps {
3481
+ display: flex;
3482
+ flex-direction: row;
3483
+ align-items: center;
3484
+ gap: 0;
3485
+ }
3486
+
3487
+ /* Vertical variant */
3488
+ .ds-steps--vertical {
3489
+ flex-direction: column;
3490
+ align-items: flex-start;
3491
+ }
3492
+
3493
+ /* Single step
3494
+ * -------------------------------------------------------------------------- */
3495
+
3496
+ .ds-step {
3497
+ display: flex;
3498
+ align-items: center;
3499
+ gap: var(--ds-space-3);
3500
+ }
3501
+
3502
+ /* Circle indicator */
3503
+ .ds-step__indicator {
3504
+ display: flex;
3505
+ align-items: center;
3506
+ justify-content: center;
3507
+ width: 2rem;
3508
+ height: 2rem;
3509
+ border-radius: var(--ds-radius-full);
3510
+ border: 2px solid var(--ds-color-border);
3511
+ font-size: var(--ds-text-xs);
3512
+ font-weight: var(--ds-weight-medium);
3513
+ color: var(--ds-color-text-tertiary);
3514
+ background-color: var(--ds-color-surface);
3515
+ flex-shrink: 0;
3516
+ transition:
3517
+ background-color var(--ds-duration-fast) var(--ds-ease-default),
3518
+ border-color var(--ds-duration-fast) var(--ds-ease-default),
3519
+ color var(--ds-duration-fast) var(--ds-ease-default);
3520
+ }
3521
+
3522
+ /* Completed step */
3523
+ .ds-step--completed .ds-step__indicator {
3524
+ background-color: var(--ds-color-inverted);
3525
+ border-color: var(--ds-color-inverted);
3526
+ color: var(--ds-color-on-inverted);
3527
+ }
3528
+
3529
+ /* Current step */
3530
+ .ds-step--current .ds-step__indicator {
3531
+ border-color: var(--ds-color-interactive);
3532
+ color: var(--ds-color-text);
3533
+ }
3534
+
3535
+ /* Error step */
3536
+ .ds-step--error .ds-step__indicator {
3537
+ border-color: var(--ds-color-error);
3538
+ color: var(--ds-color-error);
3539
+ }
3540
+
3541
+ /* Step content
3542
+ * -------------------------------------------------------------------------- */
3543
+
3544
+ .ds-step__content {
3545
+ display: flex;
3546
+ flex-direction: column;
3547
+ }
3548
+
3549
+ .ds-step__title {
3550
+ font-size: var(--ds-text-sm);
3551
+ font-weight: var(--ds-weight-medium);
3552
+ color: var(--ds-color-text);
3553
+ }
3554
+
3555
+ .ds-step__description {
3556
+ font-size: var(--ds-text-xs);
3557
+ color: var(--ds-color-text-tertiary);
3558
+ }
3559
+
3560
+ /* Connector (line between steps)
3561
+ * -------------------------------------------------------------------------- */
3562
+
3563
+ /* Horizontal connector */
3564
+ .ds-step__connector {
3565
+ flex: 1;
3566
+ height: 2px;
3567
+ min-width: var(--ds-space-4);
3568
+ background-color: var(--ds-color-border);
3569
+ margin-inline: var(--ds-space-2);
3570
+ }
3571
+
3572
+ /* Filled connector after a completed step */
3573
+ .ds-step--completed + .ds-step__connector {
3574
+ background-color: var(--ds-color-inverted);
3575
+ }
3576
+
3577
+ /* Vertical connector */
3578
+ .ds-steps--vertical .ds-step__connector {
3579
+ flex: none;
3580
+ width: 2px;
3581
+ height: 2rem;
3582
+ min-width: auto;
3583
+ margin-inline: 0;
3584
+ margin-left: calc(1rem - 1px); /* center under the 2 rem indicator */
3585
+ margin-block: var(--ds-space-1);
3586
+ background-color: var(--ds-color-border-subtle);
3587
+ }
3588
+
3589
+ .ds-steps--vertical .ds-step--completed + .ds-step__connector {
3590
+ background-color: var(--ds-color-inverted);
3591
+ }
3592
+
3593
+
3594
+ /* === Tier 3 — Advanced === */
3595
+ /* ==========================================================================
3596
+ * Popover
3597
+ * ==========================================================================
3598
+ *
3599
+ * Flexible popover component for displaying complex content anchored to a
3600
+ * trigger element. Supports four placement directions (top, bottom, left,
3601
+ * right) and multiple size variants. Default placement is bottom.
3602
+ *
3603
+ * Usage:
3604
+ * <div class="ds-popover ds-popover--open">
3605
+ * <button>Trigger</button>
3606
+ * <div class="ds-popover__content">...</div>
3607
+ * </div>
3608
+ *
3609
+ * Modifiers:
3610
+ * .ds-popover--open — Shows the popover content
3611
+ * .ds-popover--top — Places content above the trigger
3612
+ * .ds-popover--bottom — Places content below the trigger (default)
3613
+ * .ds-popover--left — Places content to the left of the trigger
3614
+ * .ds-popover--right — Places content to the right of the trigger
3615
+ * .ds-popover__content--sm — Smaller popover (12rem min-width)
3616
+ * .ds-popover__content--lg — Larger popover (24rem min-width)
3617
+ * ========================================================================== */
3618
+
3619
+ .ds-popover {
3620
+ position: relative;
3621
+ display: inline-flex;
3622
+ }
3623
+
3624
+ .ds-popover__content {
3625
+ position: absolute;
3626
+ z-index: var(--ds-z-dropdown);
3627
+ background-color: var(--ds-color-surface);
3628
+ border: 1px solid var(--ds-color-border);
3629
+ border-radius: var(--ds-radius-xl);
3630
+ box-shadow: var(--ds-shadow-lg);
3631
+ padding: var(--ds-space-4);
3632
+ min-width: 16rem;
3633
+ opacity: 0;
3634
+ visibility: hidden;
3635
+ transform: scale(0.96);
3636
+ transition:
3637
+ opacity var(--ds-duration-fast) var(--ds-ease),
3638
+ visibility var(--ds-duration-fast) var(--ds-ease),
3639
+ transform var(--ds-duration-fast) var(--ds-ease-out-expo);
3640
+ }
3641
+
3642
+ /* Open state */
3643
+ .ds-popover--open .ds-popover__content {
3644
+ opacity: 1;
3645
+ visibility: visible;
3646
+ transform: scale(1);
3647
+ }
3648
+
3649
+ /* Placement: bottom (default) */
3650
+ .ds-popover__content,
3651
+ .ds-popover--bottom .ds-popover__content {
3652
+ top: calc(100% + 8px);
3653
+ left: 50%;
3654
+ transform: translateX(-50%) scale(0.96);
3655
+ }
3656
+
3657
+ .ds-popover--open .ds-popover__content,
3658
+ .ds-popover--bottom.ds-popover--open .ds-popover__content {
3659
+ transform: translateX(-50%) scale(1);
3660
+ }
3661
+
3662
+ /* Placement: top */
3663
+ .ds-popover--top .ds-popover__content {
3664
+ bottom: calc(100% + 8px);
3665
+ top: auto;
3666
+ left: 50%;
3667
+ transform: translateX(-50%) scale(0.96);
3668
+ }
3669
+
3670
+ .ds-popover--top.ds-popover--open .ds-popover__content {
3671
+ transform: translateX(-50%) scale(1);
3672
+ }
3673
+
3674
+ /* Placement: left */
3675
+ .ds-popover--left .ds-popover__content {
3676
+ right: calc(100% + 8px);
3677
+ top: 50%;
3678
+ left: auto;
3679
+ transform: translateY(-50%) scale(0.96);
3680
+ }
3681
+
3682
+ .ds-popover--left.ds-popover--open .ds-popover__content {
3683
+ transform: translateY(-50%) scale(1);
3684
+ }
3685
+
3686
+ /* Placement: right */
3687
+ .ds-popover--right .ds-popover__content {
3688
+ left: calc(100% + 8px);
3689
+ top: 50%;
3690
+ transform: translateY(-50%) scale(0.96);
3691
+ }
3692
+
3693
+ .ds-popover--right.ds-popover--open .ds-popover__content {
3694
+ transform: translateY(-50%) scale(1);
3695
+ }
3696
+
3697
+ /* Size: small */
3698
+ .ds-popover__content--sm {
3699
+ min-width: 12rem;
3700
+ padding: var(--ds-space-3);
3701
+ }
3702
+
3703
+ /* Size: large */
3704
+ .ds-popover__content--lg {
3705
+ min-width: 24rem;
3706
+ }
3707
+
3708
+ /* ==========================================================================
3709
+ * Slider
3710
+ * ==========================================================================
3711
+ *
3712
+ * Range slider input component with customizable thumb and track styling.
3713
+ * Supports labels, value display, size variants, and disabled state.
3714
+ *
3715
+ * Usage:
3716
+ * <div class="ds-slider">
3717
+ * <input type="range" min="0" max="100" value="50" />
3718
+ * <div class="ds-slider__labels">
3719
+ * <span>0</span>
3720
+ * <span>100</span>
3721
+ * </div>
3722
+ * </div>
3723
+ *
3724
+ * Modifiers:
3725
+ * .ds-slider--sm — Smaller track and thumb
3726
+ * .ds-slider--disabled — Reduced opacity, no interaction
3727
+ * ========================================================================== */
3728
+
3729
+ .ds-slider {
3730
+ width: 100%;
3731
+ position: relative;
3732
+ }
3733
+
3734
+ .ds-slider input[type="range"] {
3735
+ -webkit-appearance: none;
3736
+ -moz-appearance: none;
3737
+ appearance: none;
3738
+ width: 100%;
3739
+ height: 0.375rem;
3740
+ background-color: var(--ds-color-bg-muted);
3741
+ border-radius: var(--ds-radius-full);
3742
+ outline: none;
3743
+ cursor: pointer;
3744
+ }
3745
+
3746
+ /* Webkit thumb */
3747
+ .ds-slider input[type="range"]::-webkit-slider-thumb {
3748
+ -webkit-appearance: none;
3749
+ appearance: none;
3750
+ width: 1.25rem;
3751
+ height: 1.25rem;
3752
+ border-radius: var(--ds-radius-full);
3753
+ background-color: var(--ds-color-inverted);
3754
+ border: 2px solid var(--ds-color-surface);
3755
+ box-shadow: var(--ds-shadow-sm);
3756
+ cursor: pointer;
3757
+ transition: transform var(--ds-duration-fast) var(--ds-ease);
3758
+ }
3759
+
3760
+ /* Firefox thumb */
3761
+ .ds-slider input[type="range"]::-moz-range-thumb {
3762
+ width: 1.25rem;
3763
+ height: 1.25rem;
3764
+ border-radius: var(--ds-radius-full);
3765
+ background-color: var(--ds-color-inverted);
3766
+ border: 2px solid var(--ds-color-surface);
3767
+ box-shadow: var(--ds-shadow-sm);
3768
+ cursor: pointer;
3769
+ transition: transform var(--ds-duration-fast) var(--ds-ease);
3770
+ }
3771
+
3772
+ /* Hover: scale up thumb */
3773
+ .ds-slider input[type="range"]:hover::-webkit-slider-thumb {
3774
+ transform: scale(1.1);
3775
+ }
3776
+
3777
+ .ds-slider input[type="range"]:hover::-moz-range-thumb {
3778
+ transform: scale(1.1);
3779
+ }
3780
+
3781
+ /* Focus ring */
3782
+ .ds-slider input[type="range"]:focus-visible::-webkit-slider-thumb {
3783
+ outline: var(--ds-ring-width) solid var(--ds-ring-color);
3784
+ outline-offset: var(--ds-ring-offset);
3785
+ }
3786
+
3787
+ .ds-slider input[type="range"]:focus-visible::-moz-range-thumb {
3788
+ outline: var(--ds-ring-width) solid var(--ds-ring-color);
3789
+ outline-offset: var(--ds-ring-offset);
3790
+ }
3791
+
3792
+ /* Labels row */
3793
+ .ds-slider__labels {
3794
+ display: flex;
3795
+ justify-content: space-between;
3796
+ font-size: var(--ds-text-xs);
3797
+ color: var(--ds-color-text-tertiary);
3798
+ margin-top: var(--ds-space-1);
3799
+ }
3800
+
3801
+ /* Current value display */
3802
+ .ds-slider__value {
3803
+ font-size: var(--ds-text-sm);
3804
+ font-weight: var(--ds-weight-medium);
3805
+ color: var(--ds-color-text);
3806
+ }
3807
+
3808
+ /* Size: small */
3809
+ .ds-slider--sm input[type="range"] {
3810
+ height: 0.25rem;
3811
+ }
3812
+
3813
+ .ds-slider--sm input[type="range"]::-webkit-slider-thumb {
3814
+ width: 1rem;
3815
+ height: 1rem;
3816
+ }
3817
+
3818
+ .ds-slider--sm input[type="range"]::-moz-range-thumb {
3819
+ width: 1rem;
3820
+ height: 1rem;
3821
+ }
3822
+
3823
+ /* Disabled state */
3824
+ .ds-slider--disabled {
3825
+ opacity: var(--ds-opacity-disabled);
3826
+ cursor: not-allowed;
3827
+ }
3828
+
3829
+ .ds-slider--disabled input[type="range"] {
3830
+ cursor: not-allowed;
3831
+ pointer-events: none;
3832
+ }
3833
+
3834
+ /* ==========================================================================
3835
+ * Timeline
3836
+ * ==========================================================================
3837
+ *
3838
+ * Vertical timeline component for roadmaps, activity feeds, and step-based
3839
+ * flows. Each item has a dot indicator on a vertical line with support for
3840
+ * completed, current, and error states.
3841
+ *
3842
+ * Usage:
3843
+ * <div class="ds-timeline">
3844
+ * <div class="ds-timeline__item ds-timeline__item--completed">
3845
+ * <div class="ds-timeline__dot"></div>
3846
+ * <div class="ds-timeline__content">
3847
+ * <div class="ds-timeline__title">Step one</div>
3848
+ * <div class="ds-timeline__description">Details here.</div>
3849
+ * <div class="ds-timeline__time">2 hours ago</div>
3850
+ * </div>
3851
+ * </div>
3852
+ * </div>
3853
+ *
3854
+ * Modifiers:
3855
+ * .ds-timeline__item--completed — Green dot (success)
3856
+ * .ds-timeline__item--current — Inverted dot (active)
3857
+ * .ds-timeline__item--error — Red dot (error)
3858
+ * .ds-timeline--compact — Tighter spacing, smaller dots
3859
+ * ========================================================================== */
3860
+
3861
+ .ds-timeline {
3862
+ position: relative;
3863
+ padding-left: var(--ds-space-8);
3864
+ }
3865
+
3866
+ /* Vertical line */
3867
+ .ds-timeline::before {
3868
+ content: "";
3869
+ position: absolute;
3870
+ left: 0.9rem;
3871
+ top: 0;
3872
+ bottom: 0;
3873
+ width: 2px;
3874
+ background-color: var(--ds-color-border);
3875
+ }
3876
+
3877
+ /* Item */
3878
+ .ds-timeline__item {
3879
+ position: relative;
3880
+ padding-bottom: var(--ds-space-6);
3881
+ }
3882
+
3883
+ .ds-timeline__item:last-child {
3884
+ padding-bottom: 0;
3885
+ }
3886
+
3887
+ /* Dot */
3888
+ .ds-timeline__dot {
3889
+ position: absolute;
3890
+ left: calc(-1 * var(--ds-space-8) + 0.5rem);
3891
+ width: 1rem;
3892
+ height: 1rem;
3893
+ border-radius: var(--ds-radius-full);
3894
+ background-color: var(--ds-color-bg-elevated);
3895
+ border: 2px solid var(--ds-color-border);
3896
+ z-index: 1;
3897
+ }
3898
+
3899
+ /* Dot state: completed */
3900
+ .ds-timeline__item--completed .ds-timeline__dot {
3901
+ background-color: var(--ds-color-success);
3902
+ border-color: var(--ds-color-success);
3903
+ }
3904
+
3905
+ /* Dot state: current */
3906
+ .ds-timeline__item--current .ds-timeline__dot {
3907
+ background-color: var(--ds-color-inverted);
3908
+ border-color: var(--ds-color-inverted);
3909
+ }
3910
+
3911
+ /* Dot state: error */
3912
+ .ds-timeline__item--error .ds-timeline__dot {
3913
+ background-color: var(--ds-color-error);
3914
+ border-color: var(--ds-color-error);
3915
+ }
3916
+
3917
+ /* Content area */
3918
+ .ds-timeline__content {
3919
+ /* no additional layout needed; flows naturally after the dot */
3920
+ }
3921
+
3922
+ /* Title */
3923
+ .ds-timeline__title {
3924
+ font-size: var(--ds-text-sm);
3925
+ font-weight: var(--ds-weight-medium);
3926
+ color: var(--ds-color-text);
3927
+ }
3928
+
3929
+ /* Description */
3930
+ .ds-timeline__description {
3931
+ font-size: var(--ds-text-sm);
3932
+ color: var(--ds-color-text-secondary);
3933
+ margin-top: var(--ds-space-1);
3934
+ }
3935
+
3936
+ /* Timestamp */
3937
+ .ds-timeline__time {
3938
+ font-size: var(--ds-text-xs);
3939
+ color: var(--ds-color-text-tertiary);
3940
+ margin-top: var(--ds-space-0-5);
3941
+ }
3942
+
3943
+ /* Compact variant */
3944
+ .ds-timeline--compact {
3945
+ padding-left: var(--ds-space-6);
3946
+ }
3947
+
3948
+ .ds-timeline--compact::before {
3949
+ left: 0.6rem;
3950
+ }
3951
+
3952
+ .ds-timeline--compact .ds-timeline__item {
3953
+ padding-bottom: var(--ds-space-4);
3954
+ }
3955
+
3956
+ .ds-timeline--compact .ds-timeline__item:last-child {
3957
+ padding-bottom: 0;
3958
+ }
3959
+
3960
+ .ds-timeline--compact .ds-timeline__dot {
3961
+ left: calc(-1 * var(--ds-space-6) + 0.25rem);
3962
+ width: 0.75rem;
3963
+ height: 0.75rem;
3964
+ }
3965
+
3966
+ /* ==========================================================================
3967
+ * Kbd
3968
+ * ==========================================================================
3969
+ *
3970
+ * Keyboard shortcut display component with a raised 3D key appearance.
3971
+ * Use individually or group multiple keys with ds-kbd-group for combos
3972
+ * like "Cmd + K".
3973
+ *
3974
+ * Usage:
3975
+ * <kbd class="ds-kbd">Esc</kbd>
3976
+ *
3977
+ * <span class="ds-kbd-group">
3978
+ * <kbd class="ds-kbd">Cmd</kbd>
3979
+ * <span class="ds-kbd-group__separator">+</span>
3980
+ * <kbd class="ds-kbd">K</kbd>
3981
+ * </span>
3982
+ *
3983
+ * Modifiers:
3984
+ * .ds-kbd--lg — Larger key display
3985
+ * ========================================================================== */
3986
+
3987
+ .ds-kbd {
3988
+ display: inline-flex;
3989
+ align-items: center;
3990
+ gap: var(--ds-space-1);
3991
+ padding: var(--ds-space-0-5) var(--ds-space-1-5);
3992
+ font-family: var(--ds-font-mono);
3993
+ font-size: var(--ds-text-xs);
3994
+ background-color: var(--ds-color-bg-elevated);
3995
+ border: 1px solid var(--ds-color-border);
3996
+ border-bottom-width: 2px;
3997
+ border-radius: var(--ds-radius-sm);
3998
+ color: var(--ds-color-text-secondary);
3999
+ line-height: 1;
4000
+ vertical-align: baseline;
4001
+ }
4002
+
4003
+ /* Large variant */
4004
+ .ds-kbd--lg {
4005
+ font-size: var(--ds-text-sm);
4006
+ padding: var(--ds-space-1) var(--ds-space-2);
4007
+ }
4008
+
4009
+ /* Key group (for combos like Cmd + K) */
4010
+ .ds-kbd-group {
4011
+ display: inline-flex;
4012
+ align-items: center;
4013
+ gap: var(--ds-space-1);
4014
+ }
4015
+
4016
+ /* Separator between keys */
4017
+ .ds-kbd-group__separator {
4018
+ font-size: var(--ds-text-xs);
4019
+ color: var(--ds-color-text-tertiary);
4020
+ }
4021
+
4022
+ /* ==========================================================================
4023
+ * Command
4024
+ * ==========================================================================
4025
+ *
4026
+ * Command palette / search overlay following the Cmd+K pattern. Provides a
4027
+ * full-screen overlay with a centered search dialog, grouped results,
4028
+ * keyboard-navigable items, and a footer with shortcut hints.
4029
+ *
4030
+ * Usage:
4031
+ * <div class="ds-command ds-command--open">
4032
+ * <div class="ds-command__content">
4033
+ * <div class="ds-command__input-wrapper">
4034
+ * <span class="ds-command__input-icon">...</span>
4035
+ * <input class="ds-command__input" placeholder="Search..." />
4036
+ * </div>
4037
+ * <div class="ds-command__list">
4038
+ * <div class="ds-command__group">
4039
+ * <div class="ds-command__group-heading">Results</div>
4040
+ * <div class="ds-command__item ds-command__item--active">
4041
+ * <span class="ds-command__item-icon">...</span>
4042
+ * <span class="ds-command__item-label">Item</span>
4043
+ * <span class="ds-command__item-shortcut">Ctrl+N</span>
4044
+ * </div>
4045
+ * </div>
4046
+ * <div class="ds-command__empty">No results found.</div>
4047
+ * </div>
4048
+ * <div class="ds-command__footer">...</div>
4049
+ * </div>
4050
+ * </div>
4051
+ *
4052
+ * Modifiers:
4053
+ * .ds-command--open — Shows the command palette
4054
+ * ========================================================================== */
4055
+
4056
+ /* Overlay */
4057
+ .ds-command {
4058
+ position: fixed;
4059
+ inset: 0;
4060
+ z-index: var(--ds-z-modal);
4061
+ display: flex;
4062
+ align-items: flex-start;
4063
+ justify-content: center;
4064
+ padding-top: 20vh;
4065
+ background-color: var(--ds-color-overlay);
4066
+ opacity: 0;
4067
+ visibility: hidden;
4068
+ transition:
4069
+ opacity var(--ds-duration-fast) var(--ds-ease),
4070
+ visibility var(--ds-duration-fast) var(--ds-ease);
4071
+ }
4072
+
4073
+ /* Open state */
4074
+ .ds-command--open {
4075
+ opacity: 1;
4076
+ visibility: visible;
4077
+ }
4078
+
4079
+ /* Content panel */
4080
+ .ds-command__content {
4081
+ background-color: var(--ds-color-surface);
4082
+ border: 1px solid var(--ds-color-border);
4083
+ border-radius: var(--ds-radius-xl);
4084
+ box-shadow: var(--ds-shadow-lg);
4085
+ width: 100%;
4086
+ max-width: 32rem;
4087
+ overflow: hidden;
4088
+ transform: scale(0.96) translateY(-8px);
4089
+ transition:
4090
+ transform var(--ds-duration-fast) var(--ds-ease-out-expo);
4091
+ }
4092
+
4093
+ .ds-command--open .ds-command__content {
4094
+ transform: scale(1) translateY(0);
4095
+ }
4096
+
4097
+ /* Input wrapper */
4098
+ .ds-command__input-wrapper {
4099
+ display: flex;
4100
+ align-items: center;
4101
+ gap: var(--ds-space-3);
4102
+ padding: var(--ds-space-3) var(--ds-space-4);
4103
+ border-bottom: 1px solid var(--ds-color-border);
4104
+ }
4105
+
4106
+ /* Search icon */
4107
+ .ds-command__input-icon {
4108
+ color: var(--ds-color-text-tertiary);
4109
+ flex-shrink: 0;
4110
+ }
4111
+
4112
+ /* Search input */
4113
+ .ds-command__input {
4114
+ flex: 1;
4115
+ background-color: transparent;
4116
+ border: none;
4117
+ outline: none;
4118
+ font-size: var(--ds-text-base);
4119
+ color: var(--ds-color-text);
4120
+ font-family: var(--ds-font-sans);
4121
+ }
4122
+
4123
+ .ds-command__input::placeholder {
4124
+ color: var(--ds-color-text-tertiary);
4125
+ }
4126
+
4127
+ /* Results list */
4128
+ .ds-command__list {
4129
+ max-height: 20rem;
4130
+ overflow-y: auto;
4131
+ padding: var(--ds-space-2);
4132
+ }
4133
+
4134
+ /* Group of results */
4135
+ .ds-command__group {
4136
+ /* structural grouping — no additional visual styles needed */
4137
+ }
4138
+
4139
+ /* Group heading */
4140
+ .ds-command__group-heading {
4141
+ font-size: var(--ds-text-xs);
4142
+ text-transform: uppercase;
4143
+ letter-spacing: 0.05em;
4144
+ color: var(--ds-color-text-tertiary);
4145
+ padding: var(--ds-space-2) var(--ds-space-3);
4146
+ font-weight: var(--ds-weight-medium);
4147
+ }
4148
+
4149
+ /* Individual item */
4150
+ .ds-command__item {
4151
+ display: flex;
4152
+ align-items: center;
4153
+ gap: var(--ds-space-3);
4154
+ padding: var(--ds-space-2-5) var(--ds-space-3);
4155
+ border-radius: var(--ds-radius-lg);
4156
+ cursor: pointer;
4157
+ font-size: var(--ds-text-sm);
4158
+ color: var(--ds-color-text-secondary);
4159
+ transition:
4160
+ background-color var(--ds-duration-fast) var(--ds-ease),
4161
+ color var(--ds-duration-fast) var(--ds-ease);
4162
+ }
4163
+
4164
+ /* Item hover & active states */
4165
+ .ds-command__item:hover,
4166
+ .ds-command__item--active {
4167
+ background-color: var(--ds-color-bg-elevated);
4168
+ color: var(--ds-color-text);
4169
+ }
4170
+
4171
+ /* Item icon */
4172
+ .ds-command__item-icon {
4173
+ flex-shrink: 0;
4174
+ color: var(--ds-color-text-tertiary);
4175
+ }
4176
+
4177
+ /* Item label */
4178
+ .ds-command__item-label {
4179
+ flex: 1;
4180
+ }
4181
+
4182
+ /* Item shortcut hint */
4183
+ .ds-command__item-shortcut {
4184
+ font-size: var(--ds-text-xs);
4185
+ color: var(--ds-color-text-tertiary);
4186
+ flex-shrink: 0;
4187
+ }
4188
+
4189
+ /* Empty state */
4190
+ .ds-command__empty {
4191
+ padding: var(--ds-space-8);
4192
+ text-align: center;
4193
+ font-size: var(--ds-text-sm);
4194
+ color: var(--ds-color-text-tertiary);
4195
+ }
4196
+
4197
+ /* Footer */
4198
+ .ds-command__footer {
4199
+ display: flex;
4200
+ align-items: center;
4201
+ gap: var(--ds-space-4);
4202
+ padding: var(--ds-space-2) var(--ds-space-3);
4203
+ border-top: 1px solid var(--ds-color-border);
4204
+ font-size: var(--ds-text-xs);
4205
+ color: var(--ds-color-text-tertiary);
4206
+ }
4207
+
4208
+
4209
+ /* ==========================================================================
4210
+ Utilities: Layout
4211
+ Container with clamp padding, generous responsive grid.
4212
+ ========================================================================== */
4213
+
4214
+ /* --- Container --- */
4215
+ .ds-container {
4216
+ width: 100%;
4217
+ max-width: var(--ds-container-max);
4218
+ margin-inline: auto;
4219
+ padding-inline: var(--ds-container-padding);
4220
+ }
4221
+
4222
+ /* --- Section (generous vertical rhythm) --- */
4223
+ .ds-section {
4224
+ padding-block: var(--ds-section-padding);
4225
+ }
4226
+
4227
+ /* --- Flex --- */
4228
+ .ds-flex { display: flex; }
4229
+ .ds-inline-flex { display: inline-flex; }
4230
+ .ds-flex-col { flex-direction: column; }
4231
+ .ds-flex-row { flex-direction: row; }
4232
+ .ds-flex-wrap { flex-wrap: wrap; }
4233
+ .ds-flex-1 { flex: 1 1 0%; }
4234
+ .ds-flex-auto { flex: 1 1 auto; }
4235
+ .ds-flex-none { flex: none; }
4236
+ .ds-shrink-0 { flex-shrink: 0; }
4237
+
4238
+ /* --- Alignment --- */
4239
+ .ds-items-start { align-items: flex-start; }
4240
+ .ds-items-center { align-items: center; }
4241
+ .ds-items-end { align-items: flex-end; }
4242
+ .ds-items-stretch { align-items: stretch; }
4243
+ .ds-items-baseline { align-items: baseline; }
4244
+
4245
+ .ds-justify-start { justify-content: flex-start; }
4246
+ .ds-justify-center { justify-content: center; }
4247
+ .ds-justify-end { justify-content: flex-end; }
4248
+ .ds-justify-between { justify-content: space-between; }
4249
+ .ds-justify-around { justify-content: space-around; }
4250
+ .ds-justify-evenly { justify-content: space-evenly; }
4251
+
4252
+ .ds-self-start { align-self: flex-start; }
4253
+ .ds-self-center { align-self: center; }
4254
+ .ds-self-end { align-self: flex-end; }
4255
+
4256
+ /* --- Grid --- */
4257
+ .ds-grid {
4258
+ display: grid;
4259
+ gap: var(--ds-space-6);
4260
+ }
4261
+
4262
+ .ds-grid-cols-1 { grid-template-columns: repeat(1, 1fr); }
4263
+ .ds-grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
4264
+ .ds-grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
4265
+ .ds-grid-cols-4 { grid-template-columns: repeat(4, 1fr); }
4266
+
4267
+ @media (min-width: 640px) {
4268
+ .ds-sm\:grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
4269
+ .ds-sm\:grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
4270
+ }
4271
+
4272
+ @media (min-width: 768px) {
4273
+ .ds-md\:grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
4274
+ .ds-md\:grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
4275
+ .ds-md\:grid-cols-4 { grid-template-columns: repeat(4, 1fr); }
4276
+ .ds-md\:flex-row { flex-direction: row; }
4277
+ }
4278
+
4279
+ @media (min-width: 1024px) {
4280
+ .ds-lg\:grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
4281
+ .ds-lg\:grid-cols-4 { grid-template-columns: repeat(4, 1fr); }
4282
+ }
4283
+
4284
+ /* --- Gap --- */
4285
+ .ds-gap-0 { gap: var(--ds-space-0); }
4286
+ .ds-gap-1 { gap: var(--ds-space-1); }
4287
+ .ds-gap-2 { gap: var(--ds-space-2); }
4288
+ .ds-gap-3 { gap: var(--ds-space-3); }
4289
+ .ds-gap-4 { gap: var(--ds-space-4); }
4290
+ .ds-gap-5 { gap: var(--ds-space-5); }
4291
+ .ds-gap-6 { gap: var(--ds-space-6); }
4292
+ .ds-gap-8 { gap: var(--ds-space-8); }
4293
+ .ds-gap-12 { gap: var(--ds-space-12); }
4294
+
4295
+ /* --- Display --- */
4296
+ .ds-block { display: block; }
4297
+ .ds-inline-block { display: inline-block; }
4298
+ .ds-inline { display: inline; }
4299
+ .ds-hidden { display: none; }
4300
+
4301
+ @media (min-width: 768px) {
4302
+ .ds-md\:hidden { display: none; }
4303
+ .ds-md\:block { display: block; }
4304
+ .ds-md\:flex { display: flex; }
4305
+ }
4306
+
4307
+ /* --- Position --- */
4308
+ .ds-relative { position: relative; }
4309
+ .ds-absolute { position: absolute; }
4310
+ .ds-fixed { position: fixed; }
4311
+ .ds-sticky { position: sticky; top: 0; }
4312
+
4313
+ /* --- Overflow --- */
4314
+ .ds-overflow-hidden { overflow: hidden; }
4315
+ .ds-overflow-auto { overflow: auto; }
4316
+ .ds-overflow-x-auto { overflow-x: auto; }
4317
+
4318
+ /* --- Width/Height --- */
4319
+ .ds-w-full { width: 100%; }
4320
+ .ds-h-full { height: 100%; }
4321
+ .ds-h-screen { height: 100dvh; }
4322
+ .ds-min-h-screen { min-height: 100dvh; }
4323
+
4324
+ /* --- Stack (vertical spacing) --- */
4325
+ .ds-stack > * + * {
4326
+ margin-top: var(--ds-space-4);
4327
+ }
4328
+
4329
+ .ds-stack--sm > * + * { margin-top: var(--ds-space-2); }
4330
+ .ds-stack--lg > * + * { margin-top: var(--ds-space-8); }
4331
+
4332
+ /* --- Center content --- */
4333
+ .ds-center {
4334
+ display: flex;
4335
+ align-items: center;
4336
+ justify-content: center;
4337
+ }
4338
+
4339
+ /* --- Aspect Ratio --- */
4340
+ .ds-aspect-square { aspect-ratio: 1; }
4341
+ .ds-aspect-video { aspect-ratio: 16/9; }
4342
+ .ds-aspect-card { aspect-ratio: 16/10; }
4343
+
4344
+ /* ==========================================================================
4345
+ Utilities: Spacing (margin & padding)
4346
+ Pattern: ds-{m|p}{side}-{size}
4347
+ ========================================================================== */
4348
+
4349
+ /* --- Padding --- */
4350
+ .ds-p-0 { padding: var(--ds-space-0); }
4351
+ .ds-p-1 { padding: var(--ds-space-1); }
4352
+ .ds-p-2 { padding: var(--ds-space-2); }
4353
+ .ds-p-3 { padding: var(--ds-space-3); }
4354
+ .ds-p-4 { padding: var(--ds-space-4); }
4355
+ .ds-p-5 { padding: var(--ds-space-5); }
4356
+ .ds-p-6 { padding: var(--ds-space-6); }
4357
+ .ds-p-8 { padding: var(--ds-space-8); }
4358
+ .ds-p-10 { padding: var(--ds-space-10); }
4359
+ .ds-p-12 { padding: var(--ds-space-12); }
4360
+
4361
+ .ds-px-0 { padding-inline: var(--ds-space-0); }
4362
+ .ds-px-2 { padding-inline: var(--ds-space-2); }
4363
+ .ds-px-3 { padding-inline: var(--ds-space-3); }
4364
+ .ds-px-4 { padding-inline: var(--ds-space-4); }
4365
+ .ds-px-5 { padding-inline: var(--ds-space-5); }
4366
+ .ds-px-6 { padding-inline: var(--ds-space-6); }
4367
+ .ds-px-8 { padding-inline: var(--ds-space-8); }
4368
+
4369
+ .ds-py-0 { padding-block: var(--ds-space-0); }
4370
+ .ds-py-2 { padding-block: var(--ds-space-2); }
4371
+ .ds-py-3 { padding-block: var(--ds-space-3); }
4372
+ .ds-py-4 { padding-block: var(--ds-space-4); }
4373
+ .ds-py-5 { padding-block: var(--ds-space-5); }
4374
+ .ds-py-6 { padding-block: var(--ds-space-6); }
4375
+ .ds-py-8 { padding-block: var(--ds-space-8); }
4376
+ .ds-py-10 { padding-block: var(--ds-space-10); }
4377
+ .ds-py-12 { padding-block: var(--ds-space-12); }
4378
+ .ds-py-16 { padding-block: var(--ds-space-16); }
4379
+ .ds-py-20 { padding-block: var(--ds-space-20); }
4380
+
4381
+ .ds-pt-4 { padding-top: var(--ds-space-4); }
4382
+ .ds-pt-8 { padding-top: var(--ds-space-8); }
4383
+ .ds-pt-12 { padding-top: var(--ds-space-12); }
4384
+ .ds-pt-16 { padding-top: var(--ds-space-16); }
4385
+
4386
+ .ds-pb-4 { padding-bottom: var(--ds-space-4); }
4387
+ .ds-pb-8 { padding-bottom: var(--ds-space-8); }
4388
+
4389
+ /* --- Margin --- */
4390
+ .ds-m-0 { margin: var(--ds-space-0); }
4391
+ .ds-m-auto { margin: auto; }
4392
+
4393
+ .ds-mx-auto { margin-inline: auto; }
4394
+ .ds-mx-2 { margin-inline: var(--ds-space-2); }
4395
+ .ds-mx-4 { margin-inline: var(--ds-space-4); }
4396
+
4397
+ .ds-my-0 { margin-block: var(--ds-space-0); }
4398
+ .ds-my-2 { margin-block: var(--ds-space-2); }
4399
+ .ds-my-4 { margin-block: var(--ds-space-4); }
4400
+ .ds-my-6 { margin-block: var(--ds-space-6); }
4401
+ .ds-my-8 { margin-block: var(--ds-space-8); }
4402
+
4403
+ .ds-mt-0 { margin-top: var(--ds-space-0); }
4404
+ .ds-mt-1 { margin-top: var(--ds-space-1); }
4405
+ .ds-mt-2 { margin-top: var(--ds-space-2); }
4406
+ .ds-mt-4 { margin-top: var(--ds-space-4); }
4407
+ .ds-mt-6 { margin-top: var(--ds-space-6); }
4408
+ .ds-mt-8 { margin-top: var(--ds-space-8); }
4409
+
4410
+ .ds-mb-0 { margin-bottom: var(--ds-space-0); }
4411
+ .ds-mb-1 { margin-bottom: var(--ds-space-1); }
4412
+ .ds-mb-2 { margin-bottom: var(--ds-space-2); }
4413
+ .ds-mb-4 { margin-bottom: var(--ds-space-4); }
4414
+ .ds-mb-6 { margin-bottom: var(--ds-space-6); }
4415
+ .ds-mb-8 { margin-bottom: var(--ds-space-8); }
4416
+
4417
+ .ds-ml-auto { margin-left: auto; }
4418
+ .ds-mr-auto { margin-right: auto; }
4419
+
4420
+ /* ==========================================================================
4421
+ Utilities: Text, Visual & style helpers
4422
+ ========================================================================== */
4423
+
4424
+ /* --- Text Size --- */
4425
+ .ds-text-xs { font-size: var(--ds-text-xs); }
4426
+ .ds-text-sm { font-size: var(--ds-text-sm); }
4427
+ .ds-text-base { font-size: var(--ds-text-base); }
4428
+ .ds-text-lg { font-size: var(--ds-text-lg); }
4429
+ .ds-text-xl { font-size: var(--ds-text-xl); }
4430
+ .ds-text-2xl { font-size: var(--ds-text-2xl); }
4431
+ .ds-text-3xl { font-size: var(--ds-text-3xl); }
4432
+ .ds-text-4xl { font-size: var(--ds-text-4xl); }
4433
+ .ds-text-5xl { font-size: var(--ds-text-5xl); }
4434
+
4435
+ /* --- Text Weight --- */
4436
+ .ds-font-light { font-weight: var(--ds-weight-light); }
4437
+ .ds-font-normal { font-weight: var(--ds-weight-normal); }
4438
+ .ds-font-medium { font-weight: var(--ds-weight-medium); }
4439
+ .ds-font-semibold { font-weight: var(--ds-weight-semibold); }
4440
+ .ds-font-bold { font-weight: var(--ds-weight-bold); }
4441
+
4442
+ /* --- Text Alignment --- */
4443
+ .ds-text-left { text-align: left; }
4444
+ .ds-text-center { text-align: center; }
4445
+ .ds-text-right { text-align: right; }
4446
+ .ds-text-balance { text-wrap: balance; }
4447
+
4448
+ /* --- Text Color --- */
4449
+ .ds-text-primary { color: var(--ds-color-text); }
4450
+ .ds-text-secondary { color: var(--ds-color-text-secondary); }
4451
+ .ds-text-tertiary { color: var(--ds-color-text-tertiary); }
4452
+ .ds-text-success { color: var(--ds-color-success); }
4453
+ .ds-text-warning { color: var(--ds-color-warning); }
4454
+ .ds-text-error { color: var(--ds-color-error); }
4455
+ .ds-text-info { color: var(--ds-color-info); }
4456
+
4457
+ /* --- Background Color --- */
4458
+ .ds-bg-base { background-color: var(--ds-color-bg); }
4459
+ .ds-bg-surface { background-color: var(--ds-color-surface); }
4460
+ .ds-bg-subtle { background-color: var(--ds-color-bg-subtle); }
4461
+ .ds-bg-elevated { background-color: var(--ds-color-bg-elevated); }
4462
+ .ds-bg-inverted { background-color: var(--ds-color-inverted); color: var(--ds-color-on-inverted); }
4463
+
4464
+ /* --- Surface Card --- */
4465
+ .ds-surface {
4466
+ background-color: var(--ds-color-surface);
4467
+ border: 1px solid var(--ds-color-border);
4468
+ }
4469
+
4470
+ .ds-surface--hover {
4471
+ transition:
4472
+ background-color var(--ds-duration-normal) var(--ds-ease-default),
4473
+ border-color var(--ds-duration-normal) var(--ds-ease-default);
4474
+ }
4475
+ .ds-surface--hover:hover {
4476
+ border-color: var(--ds-color-border-hover);
4477
+ }
4478
+
4479
+ /* --- Text Decoration --- */
4480
+ .ds-underline { text-decoration: underline; text-underline-offset: 2px; }
4481
+ .ds-no-underline { text-decoration: none; }
4482
+
4483
+ /* --- Text Transform --- */
4484
+ .ds-uppercase { text-transform: uppercase; letter-spacing: var(--ds-tracking-wide); }
4485
+ .ds-lowercase { text-transform: lowercase; }
4486
+ .ds-capitalize { text-transform: capitalize; }
4487
+
4488
+ /* --- Line Height --- */
4489
+ .ds-leading-tight { line-height: var(--ds-leading-tight); }
4490
+ .ds-leading-snug { line-height: var(--ds-leading-snug); }
4491
+ .ds-leading-normal { line-height: var(--ds-leading-normal); }
4492
+ .ds-leading-relaxed { line-height: var(--ds-leading-relaxed); }
4493
+
4494
+ /* --- Tracking --- */
4495
+ .ds-tracking-tighter { letter-spacing: var(--ds-tracking-tighter); }
4496
+ .ds-tracking-tight { letter-spacing: var(--ds-tracking-tight); }
4497
+ .ds-tracking-normal { letter-spacing: var(--ds-tracking-normal); }
4498
+ .ds-tracking-wide { letter-spacing: var(--ds-tracking-wide); }
4499
+
4500
+ /* --- Truncation --- */
4501
+ .ds-truncate {
4502
+ overflow: hidden;
4503
+ text-overflow: ellipsis;
4504
+ white-space: nowrap;
4505
+ }
4506
+
4507
+ .ds-line-clamp-2 {
4508
+ display: -webkit-box;
4509
+ -webkit-line-clamp: 2;
4510
+ -webkit-box-orient: vertical;
4511
+ overflow: hidden;
4512
+ }
4513
+
4514
+ .ds-line-clamp-3 {
4515
+ display: -webkit-box;
4516
+ -webkit-line-clamp: 3;
4517
+ -webkit-box-orient: vertical;
4518
+ overflow: hidden;
4519
+ }
4520
+
4521
+ /* --- Border --- */
4522
+ .ds-border { border: 1px solid var(--ds-color-border); }
4523
+ .ds-border-t { border-top: 1px solid var(--ds-color-border); }
4524
+ .ds-border-b { border-bottom: 1px solid var(--ds-color-border); }
4525
+ .ds-border-none { border: none; }
4526
+
4527
+ /* --- Border Radius --- */
4528
+ .ds-rounded-none { border-radius: var(--ds-radius-none); }
4529
+ .ds-rounded-sm { border-radius: var(--ds-radius-sm); }
4530
+ .ds-rounded { border-radius: var(--ds-radius-md); }
4531
+ .ds-rounded-lg { border-radius: var(--ds-radius-lg); }
4532
+ .ds-rounded-xl { border-radius: var(--ds-radius-xl); }
4533
+ .ds-rounded-2xl { border-radius: var(--ds-radius-2xl); }
4534
+ .ds-rounded-full { border-radius: var(--ds-radius-full); }
4535
+
4536
+ /* --- Shadow --- */
4537
+ .ds-shadow-sm { box-shadow: var(--ds-shadow-sm); }
4538
+ .ds-shadow { box-shadow: var(--ds-shadow-md); }
4539
+ .ds-shadow-lg { box-shadow: var(--ds-shadow-lg); }
4540
+ .ds-shadow-none { box-shadow: none; }
4541
+
4542
+ /* --- Opacity --- */
4543
+ .ds-opacity-0 { opacity: 0; }
4544
+ .ds-opacity-50 { opacity: 0.5; }
4545
+ .ds-opacity-100 { opacity: 1; }
4546
+
4547
+ /* --- Cursor --- */
4548
+ .ds-cursor-pointer { cursor: pointer; }
4549
+ .ds-cursor-default { cursor: default; }
4550
+ .ds-cursor-not-allowed { cursor: not-allowed; }
4551
+
4552
+ /* --- Transitions --- */
4553
+ .ds-tr-colors {
4554
+ transition:
4555
+ color var(--ds-duration-normal) var(--ds-ease-default),
4556
+ background-color var(--ds-duration-normal) var(--ds-ease-default),
4557
+ border-color var(--ds-duration-normal) var(--ds-ease-default);
4558
+ }
4559
+
4560
+ .ds-tr-all {
4561
+ transition: all var(--ds-duration-normal) var(--ds-ease-default);
4562
+ }
4563
+
4564
+ .ds-tr-opacity {
4565
+ transition: opacity var(--ds-duration-normal) var(--ds-ease-default);
4566
+ }
4567
+
4568
+ /* --- Animations --- */
4569
+ @keyframes ds-fade-in {
4570
+ from { opacity: 0; }
4571
+ to { opacity: 1; }
4572
+ }
4573
+
4574
+ @keyframes ds-slide-up {
4575
+ from { opacity: 0; transform: translateY(8px); }
4576
+ to { opacity: 1; transform: translateY(0); }
4577
+ }
4578
+
4579
+ @keyframes ds-scale-in {
4580
+ from { opacity: 0; transform: scale(0.96); }
4581
+ to { opacity: 1; transform: scale(1); }
4582
+ }
4583
+
4584
+ @keyframes ds-spin {
4585
+ to { transform: rotate(360deg); }
4586
+ }
4587
+
4588
+ @keyframes ds-pulse {
4589
+ 0%, 100% { opacity: 1; }
4590
+ 50% { opacity: 0.5; }
4591
+ }
4592
+
4593
+ .ds-animate-fade-in { animation: ds-fade-in var(--ds-duration-fast) ease; }
4594
+ .ds-animate-slide-up { animation: ds-slide-up var(--ds-duration-normal) var(--ds-ease-out-expo); }
4595
+ .ds-animate-scale-in { animation: ds-scale-in var(--ds-duration-normal) var(--ds-ease-out-expo); }
4596
+ .ds-animate-spin { animation: ds-spin 1s linear infinite; }
4597
+ .ds-animate-pulse { animation: ds-pulse 2s ease-in-out infinite; }
4598
+
4599
+ /* --- Scroll Reveal --- */
4600
+ .ds-reveal {
4601
+ opacity: 0;
4602
+ transform: translateY(32px);
4603
+ transition:
4604
+ opacity var(--ds-duration-slower) var(--ds-ease-out-expo),
4605
+ transform var(--ds-duration-slower) var(--ds-ease-out-expo);
4606
+ }
4607
+
4608
+ .ds-reveal.ds-visible {
4609
+ opacity: 1;
4610
+ transform: translateY(0);
4611
+ }
4612
+
4613
+ .ds-reveal-delay-1 { transition-delay: 100ms; }
4614
+ .ds-reveal-delay-2 { transition-delay: 200ms; }
4615
+ .ds-reveal-delay-3 { transition-delay: 300ms; }
4616
+ .ds-reveal-delay-4 { transition-delay: 400ms; }
4617
+
4618
+ /* --- Grain Overlay (optional) --- */
4619
+ .ds-grain::before {
4620
+ content: "";
4621
+ position: fixed;
4622
+ inset: 0;
4623
+ z-index: 9999;
4624
+ pointer-events: none;
4625
+ opacity: 0.03;
4626
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
4627
+ }
4628
+
4629
+ /* --- Accessibility --- */
4630
+ .ds-sr-only {
4631
+ position: absolute;
4632
+ width: 1px;
4633
+ height: 1px;
4634
+ padding: 0;
4635
+ margin: -1px;
4636
+ overflow: hidden;
4637
+ clip: rect(0, 0, 0, 0);
4638
+ white-space: nowrap;
4639
+ border-width: 0;
4640
+ }
4641
+
4642
+