@dillingerstaffing/strand-svelte 0.4.1

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 (105) hide show
  1. package/README.md +56 -0
  2. package/dist/css/strand-ui.css +2583 -0
  3. package/dist/index.js +4154 -0
  4. package/dist/index.js.map +1 -0
  5. package/package.json +53 -0
  6. package/src/components/Alert/Alert.svelte +32 -0
  7. package/src/components/Alert/Alert.test.ts +64 -0
  8. package/src/components/Alert/index.ts +2 -0
  9. package/src/components/Avatar/Avatar.svelte +40 -0
  10. package/src/components/Avatar/Avatar.test.ts +55 -0
  11. package/src/components/Avatar/index.ts +2 -0
  12. package/src/components/Badge/Badge.svelte +41 -0
  13. package/src/components/Badge/Badge.test.ts +55 -0
  14. package/src/components/Badge/index.ts +2 -0
  15. package/src/components/Breadcrumb/Breadcrumb.svelte +29 -0
  16. package/src/components/Breadcrumb/Breadcrumb.test.ts +66 -0
  17. package/src/components/Breadcrumb/index.ts +2 -0
  18. package/src/components/Button/Button.svelte +55 -0
  19. package/src/components/Button/Button.test.ts +110 -0
  20. package/src/components/Button/index.ts +2 -0
  21. package/src/components/Card/Card.svelte +17 -0
  22. package/src/components/Card/Card.test.ts +32 -0
  23. package/src/components/Card/index.ts +2 -0
  24. package/src/components/Checkbox/Checkbox.svelte +62 -0
  25. package/src/components/Checkbox/Checkbox.test.ts +67 -0
  26. package/src/components/Checkbox/index.ts +2 -0
  27. package/src/components/CodeBlock/CodeBlock.svelte +14 -0
  28. package/src/components/CodeBlock/CodeBlock.test.ts +36 -0
  29. package/src/components/CodeBlock/index.ts +2 -0
  30. package/src/components/Container/Container.svelte +14 -0
  31. package/src/components/Container/Container.test.ts +23 -0
  32. package/src/components/Container/index.ts +2 -0
  33. package/src/components/DataReadout/DataReadout.svelte +19 -0
  34. package/src/components/DataReadout/DataReadout.test.ts +35 -0
  35. package/src/components/DataReadout/index.ts +2 -0
  36. package/src/components/Dialog/Dialog.svelte +131 -0
  37. package/src/components/Dialog/Dialog.test.ts +77 -0
  38. package/src/components/Dialog/index.ts +2 -0
  39. package/src/components/Divider/Divider.svelte +36 -0
  40. package/src/components/Divider/Divider.test.ts +34 -0
  41. package/src/components/Divider/index.ts +2 -0
  42. package/src/components/FormField/FormField.svelte +39 -0
  43. package/src/components/FormField/FormField.test.ts +58 -0
  44. package/src/components/FormField/index.ts +2 -0
  45. package/src/components/Grid/Grid.svelte +13 -0
  46. package/src/components/Grid/Grid.test.ts +32 -0
  47. package/src/components/Grid/index.ts +2 -0
  48. package/src/components/Input/Input.svelte +41 -0
  49. package/src/components/Input/Input.test.ts +64 -0
  50. package/src/components/Input/index.ts +2 -0
  51. package/src/components/Link/Link.svelte +17 -0
  52. package/src/components/Link/Link.test.ts +28 -0
  53. package/src/components/Link/index.ts +2 -0
  54. package/src/components/Nav/Nav.svelte +69 -0
  55. package/src/components/Nav/Nav.test.ts +75 -0
  56. package/src/components/Nav/index.ts +2 -0
  57. package/src/components/Progress/Progress.svelte +78 -0
  58. package/src/components/Progress/Progress.test.ts +58 -0
  59. package/src/components/Progress/index.ts +2 -0
  60. package/src/components/Radio/Radio.svelte +46 -0
  61. package/src/components/Radio/Radio.test.ts +52 -0
  62. package/src/components/Radio/index.ts +2 -0
  63. package/src/components/Section/Section.svelte +17 -0
  64. package/src/components/Section/Section.test.ts +29 -0
  65. package/src/components/Section/index.ts +2 -0
  66. package/src/components/Select/Select.svelte +45 -0
  67. package/src/components/Select/Select.test.ts +59 -0
  68. package/src/components/Select/index.ts +2 -0
  69. package/src/components/Skeleton/Skeleton.svelte +25 -0
  70. package/src/components/Skeleton/Skeleton.test.ts +44 -0
  71. package/src/components/Skeleton/index.ts +2 -0
  72. package/src/components/Slider/Slider.svelte +37 -0
  73. package/src/components/Slider/Slider.test.ts +45 -0
  74. package/src/components/Slider/index.ts +2 -0
  75. package/src/components/Spinner/Spinner.svelte +15 -0
  76. package/src/components/Spinner/Spinner.test.ts +38 -0
  77. package/src/components/Spinner/index.ts +2 -0
  78. package/src/components/Stack/Stack.svelte +27 -0
  79. package/src/components/Stack/Stack.test.ts +46 -0
  80. package/src/components/Stack/index.ts +2 -0
  81. package/src/components/Switch/Switch.svelte +48 -0
  82. package/src/components/Switch/Switch.test.ts +61 -0
  83. package/src/components/Switch/index.ts +2 -0
  84. package/src/components/Table/Table.svelte +67 -0
  85. package/src/components/Table/Table.test.ts +88 -0
  86. package/src/components/Table/index.ts +2 -0
  87. package/src/components/Tabs/Tabs.svelte +89 -0
  88. package/src/components/Tabs/Tabs.test.ts +66 -0
  89. package/src/components/Tabs/index.ts +2 -0
  90. package/src/components/Tag/Tag.svelte +33 -0
  91. package/src/components/Tag/Tag.test.ts +63 -0
  92. package/src/components/Tag/index.ts +2 -0
  93. package/src/components/Textarea/Textarea.svelte +53 -0
  94. package/src/components/Textarea/Textarea.test.ts +53 -0
  95. package/src/components/Textarea/index.ts +2 -0
  96. package/src/components/Toast/Toast.svelte +29 -0
  97. package/src/components/Toast/Toast.test.ts +60 -0
  98. package/src/components/Toast/ToastProvider.svelte +45 -0
  99. package/src/components/Toast/index.ts +5 -0
  100. package/src/components/Toast/useToast.ts +78 -0
  101. package/src/components/Tooltip/Tooltip.svelte +56 -0
  102. package/src/components/Tooltip/Tooltip.test.ts +50 -0
  103. package/src/components/Tooltip/index.ts +2 -0
  104. package/src/index.ts +46 -0
  105. package/src/test-setup.ts +7 -0
@@ -0,0 +1,2583 @@
1
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2
+
3
+ /* Alert */
4
+ /*! Strand UI | MIT License | dillingerstaffing.com */
5
+
6
+ /*! Strand UI | MIT License | dillingerstaffing.com */
7
+
8
+ /* ── Base ── */
9
+ .strand-alert {
10
+ position: relative;
11
+ display: flex;
12
+ align-items: flex-start;
13
+ justify-content: space-between;
14
+ width: 100%;
15
+ padding: var(--strand-space-6);
16
+ padding-left: var(--strand-space-5);
17
+ border-radius: var(--strand-radius-md);
18
+ border-left: 4px solid transparent;
19
+ font-family: var(--strand-font-sans);
20
+ font-size: var(--strand-text-sm);
21
+ }
22
+
23
+ /* ── Status variants ── */
24
+ .strand-alert--info {
25
+ background: var(--strand-blue-glow);
26
+ border-left-color: var(--strand-blue-primary);
27
+ }
28
+
29
+ .strand-alert--success {
30
+ background: rgba(34, 197, 94, 0.08);
31
+ border-left-color: var(--strand-green-positive);
32
+ }
33
+
34
+ .strand-alert--warning {
35
+ background: rgba(245, 158, 11, 0.08);
36
+ border-left-color: var(--strand-amber-caution);
37
+ }
38
+
39
+ .strand-alert--error {
40
+ background: rgba(239, 68, 68, 0.08);
41
+ border-left-color: var(--strand-red-alert);
42
+ }
43
+
44
+ /* ── Content ── */
45
+ .strand-alert__content {
46
+ flex: 1;
47
+ min-width: 0;
48
+ }
49
+
50
+ /* ── Dismiss button ── */
51
+ .strand-alert__dismiss {
52
+ flex-shrink: 0;
53
+ display: inline-flex;
54
+ align-items: center;
55
+ justify-content: center;
56
+ width: 24px;
57
+ height: 24px;
58
+ margin-left: var(--strand-space-4);
59
+ padding: 0;
60
+ border: none;
61
+ border-radius: var(--strand-radius-md);
62
+ background: transparent;
63
+ color: var(--strand-gray-500);
64
+ font-size: var(--strand-text-base);
65
+ cursor: pointer;
66
+ transition: background var(--strand-duration-fast) var(--strand-ease-out-quart),
67
+ color var(--strand-duration-fast) var(--strand-ease-out-quart);
68
+ }
69
+
70
+ .strand-alert__dismiss:hover {
71
+ background: var(--strand-gray-100);
72
+ color: var(--strand-gray-600);
73
+ }
74
+
75
+ /* ── Reduced motion ── */
76
+ @media (prefers-reduced-motion: reduce) {
77
+ .strand-alert__dismiss {
78
+ transition: none;
79
+ }
80
+ }
81
+
82
+
83
+ /* Avatar */
84
+ /*! Strand UI | MIT License | dillingerstaffing.com */
85
+
86
+ /*! Strand UI | MIT License | dillingerstaffing.com */
87
+
88
+ /* ── Base ── */
89
+ .strand-avatar {
90
+ display: inline-flex;
91
+ align-items: center;
92
+ justify-content: center;
93
+ border-radius: var(--strand-radius-full);
94
+ background: var(--strand-surface-recessed);
95
+ overflow: hidden;
96
+ flex-shrink: 0;
97
+ font-family: var(--strand-font-sans);
98
+ font-weight: var(--strand-weight-medium);
99
+ color: var(--strand-gray-600);
100
+ user-select: none;
101
+ }
102
+
103
+ /* ── Image ── */
104
+ .strand-avatar__img {
105
+ width: 100%;
106
+ height: 100%;
107
+ object-fit: cover;
108
+ border-radius: var(--strand-radius-full);
109
+ }
110
+
111
+ /* ── Initials ── */
112
+ .strand-avatar__initials {
113
+ text-transform: uppercase;
114
+ line-height: 1;
115
+ }
116
+
117
+ /* ── Sizes ── */
118
+ .strand-avatar--sm {
119
+ width: 32px;
120
+ height: 32px;
121
+ font-size: var(--strand-text-xs);
122
+ }
123
+
124
+ .strand-avatar--md {
125
+ width: 40px;
126
+ height: 40px;
127
+ font-size: var(--strand-text-sm);
128
+ }
129
+
130
+ .strand-avatar--lg {
131
+ width: 48px;
132
+ height: 48px;
133
+ font-size: var(--strand-text-base);
134
+ }
135
+
136
+ .strand-avatar--xl {
137
+ width: 64px;
138
+ height: 64px;
139
+ font-size: var(--strand-text-lg);
140
+ }
141
+
142
+
143
+ /* Badge */
144
+ /*! Strand UI | MIT License | dillingerstaffing.com */
145
+
146
+ /*! Strand UI | MIT License | dillingerstaffing.com */
147
+
148
+ /* ── Wrapper ── */
149
+ .strand-badge {
150
+ position: relative;
151
+ display: inline-flex;
152
+ vertical-align: middle;
153
+ }
154
+
155
+ .strand-badge--inline {
156
+ display: inline-flex;
157
+ }
158
+
159
+ /* ── Indicator (shared) ── */
160
+ .strand-badge__indicator {
161
+ display: inline-flex;
162
+ align-items: center;
163
+ justify-content: center;
164
+ font-family: var(--strand-font-sans);
165
+ font-weight: var(--strand-weight-semibold);
166
+ color: var(--strand-on-blue-primary);
167
+ }
168
+
169
+ /* Position at top-right when wrapping children */
170
+ .strand-badge:not(.strand-badge--inline) > .strand-badge__indicator {
171
+ position: absolute;
172
+ top: 0;
173
+ right: 0;
174
+ transform: translate(50%, -50%);
175
+ z-index: 1;
176
+ }
177
+
178
+ /* ── Dot variant ── */
179
+ .strand-badge--dot {
180
+ width: 8px;
181
+ height: 8px;
182
+ border-radius: var(--strand-radius-full);
183
+ font-size: 0;
184
+ padding: 0;
185
+ }
186
+
187
+ /* ── Count variant ── */
188
+ .strand-badge--count {
189
+ min-width: 20px;
190
+ height: 20px;
191
+ padding: 0 var(--strand-space-1);
192
+ border-radius: var(--strand-radius-full);
193
+ font-size: var(--strand-text-xs);
194
+ line-height: 20px;
195
+ }
196
+
197
+ /* ── Status colors ── */
198
+ .strand-badge--default {
199
+ background: var(--strand-gray-500);
200
+ }
201
+
202
+ .strand-badge--teal {
203
+ background: var(--strand-teal-vital);
204
+ }
205
+
206
+ .strand-badge--blue {
207
+ background: var(--strand-blue-primary);
208
+ }
209
+
210
+ .strand-badge--amber {
211
+ background: var(--strand-amber-caution);
212
+ color: var(--strand-blue-midnight);
213
+ }
214
+
215
+ .strand-badge--red {
216
+ background: var(--strand-red-alert);
217
+ }
218
+
219
+
220
+ /* Breadcrumb */
221
+ /*! Strand UI | MIT License | dillingerstaffing.com */
222
+
223
+ /*! Strand UI | MIT License | dillingerstaffing.com */
224
+
225
+ .strand-breadcrumb__list {
226
+ display: flex;
227
+ align-items: center;
228
+ gap: var(--strand-space-2);
229
+ list-style: none;
230
+ margin: 0;
231
+ padding: 0;
232
+ font-family: var(--strand-font-sans);
233
+ font-size: var(--strand-text-sm);
234
+ }
235
+
236
+ .strand-breadcrumb__item {
237
+ display: inline-flex;
238
+ align-items: center;
239
+ gap: var(--strand-space-2);
240
+ }
241
+
242
+ .strand-breadcrumb__separator {
243
+ color: var(--strand-gray-400);
244
+ user-select: none;
245
+ }
246
+
247
+ .strand-breadcrumb__link {
248
+ color: var(--strand-gray-500);
249
+ text-decoration: none;
250
+ transition: color var(--strand-duration-fast) var(--strand-ease-out-quart);
251
+ }
252
+
253
+ .strand-breadcrumb__link:hover {
254
+ color: var(--strand-gray-600);
255
+ }
256
+
257
+ .strand-breadcrumb__link:focus-visible {
258
+ outline: 2px solid var(--strand-blue-primary);
259
+ outline-offset: 2px;
260
+ }
261
+
262
+ .strand-breadcrumb__current {
263
+ color: var(--strand-gray-600);
264
+ font-weight: var(--strand-weight-medium);
265
+ }
266
+
267
+ /* ── Reduced motion ── */
268
+ @media (prefers-reduced-motion: reduce) {
269
+ .strand-breadcrumb__link {
270
+ transition: none;
271
+ }
272
+ }
273
+
274
+
275
+ /* Button */
276
+ /*! Strand UI | MIT License | dillingerstaffing.com */
277
+
278
+ /*! Strand UI | MIT License | dillingerstaffing.com */
279
+
280
+ /* ── Base ── */
281
+ .strand-btn {
282
+ position: relative;
283
+ display: inline-flex;
284
+ align-items: center;
285
+ justify-content: center;
286
+ gap: var(--strand-space-2);
287
+ border: 1px solid transparent;
288
+ border-radius: var(--strand-radius-md);
289
+ font-family: var(--strand-font-sans);
290
+ font-weight: var(--strand-weight-medium);
291
+ line-height: var(--strand-leading-snug);
292
+ white-space: nowrap;
293
+ cursor: pointer;
294
+ user-select: none;
295
+ transition:
296
+ background var(--strand-duration-fast) var(--strand-ease-out-quart),
297
+ border-color var(--strand-duration-fast) var(--strand-ease-out-quart),
298
+ color var(--strand-duration-fast) var(--strand-ease-out-quart),
299
+ transform var(--strand-duration-fast) var(--strand-ease-out-expo),
300
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-quart);
301
+ }
302
+
303
+ .strand-btn:active:not(:disabled) {
304
+ transform: translateY(0);
305
+ transition-duration: 75ms;
306
+ }
307
+
308
+ .strand-btn:disabled {
309
+ opacity: 0.4;
310
+ cursor: not-allowed;
311
+ }
312
+
313
+ /* ── Sizes ── */
314
+ .strand-btn--sm {
315
+ padding: var(--strand-space-1) var(--strand-space-3);
316
+ font-size: var(--strand-text-sm);
317
+ min-height: 32px;
318
+ }
319
+
320
+ .strand-btn--md {
321
+ padding: calc(var(--strand-space-2) + var(--strand-space-1) / 2) var(--strand-space-5);
322
+ font-size: var(--strand-text-sm);
323
+ min-height: 40px;
324
+ }
325
+
326
+ .strand-btn--lg {
327
+ padding: var(--strand-space-3) var(--strand-space-6);
328
+ font-size: var(--strand-text-base);
329
+ min-height: 48px;
330
+ }
331
+
332
+ /* ── Icon-only ── */
333
+ .strand-btn--icon-only.strand-btn--sm {
334
+ padding: var(--strand-space-1);
335
+ min-width: 32px;
336
+ }
337
+
338
+ .strand-btn--icon-only.strand-btn--md {
339
+ padding: var(--strand-space-2);
340
+ min-width: 40px;
341
+ }
342
+
343
+ .strand-btn--icon-only.strand-btn--lg {
344
+ padding: var(--strand-space-3);
345
+ min-width: 48px;
346
+ }
347
+
348
+ /* ── Full width ── */
349
+ .strand-btn--full-width {
350
+ width: 100%;
351
+ }
352
+
353
+ /* ── Primary variant ── */
354
+ .strand-btn--primary {
355
+ background: var(--strand-blue-primary);
356
+ color: var(--strand-on-blue-primary);
357
+ }
358
+
359
+ .strand-btn--primary:hover:not(:disabled) {
360
+ background: var(--strand-blue-vivid);
361
+ transform: translateY(-1px);
362
+ box-shadow: var(--strand-hover-shadow-primary);
363
+ }
364
+
365
+ .strand-btn--primary:active:not(:disabled) {
366
+ background: var(--strand-blue-deep);
367
+ }
368
+
369
+ /* ── Secondary variant ── */
370
+ .strand-btn--secondary {
371
+ background: var(--strand-surface-elevated);
372
+ color: var(--strand-blue-midnight);
373
+ border-color: var(--strand-gray-200);
374
+ }
375
+
376
+ .strand-btn--secondary:hover:not(:disabled) {
377
+ background: var(--strand-blue-glow);
378
+ border-color: var(--strand-blue-indicator);
379
+ transform: translateY(-1px);
380
+ box-shadow: var(--strand-elevation-1);
381
+ }
382
+
383
+ .strand-btn--secondary:active:not(:disabled) {
384
+ background: var(--strand-blue-wash);
385
+ }
386
+
387
+ /* ── Ghost variant ── */
388
+ .strand-btn--ghost {
389
+ background: transparent;
390
+ color: var(--strand-blue-primary);
391
+ }
392
+
393
+ .strand-btn--ghost:hover:not(:disabled) {
394
+ background: var(--strand-blue-glow);
395
+ transform: translateY(-1px);
396
+ }
397
+
398
+ .strand-btn--ghost:active:not(:disabled) {
399
+ background: var(--strand-blue-wash);
400
+ }
401
+
402
+ /* ── Danger variant ── */
403
+ .strand-btn--danger {
404
+ background: var(--strand-red-alert);
405
+ color: var(--strand-on-red-alert);
406
+ }
407
+
408
+ .strand-btn--danger:hover:not(:disabled) {
409
+ background: var(--strand-red-alert-vivid);
410
+ transform: translateY(-1px);
411
+ box-shadow: var(--strand-hover-shadow-danger);
412
+ }
413
+
414
+ .strand-btn--danger:active:not(:disabled) {
415
+ background: var(--strand-red-alert-deep);
416
+ }
417
+
418
+ /* ── Loading state ── */
419
+ .strand-btn--loading {
420
+ pointer-events: none;
421
+ }
422
+
423
+ .strand-btn__spinner {
424
+ position: absolute;
425
+ width: 16px;
426
+ height: 16px;
427
+ border: 2px solid currentColor;
428
+ border-top-color: transparent;
429
+ border-radius: var(--strand-radius-full);
430
+ animation: strand-btn-spin 0.8s linear infinite;
431
+ opacity: 0.8;
432
+ }
433
+
434
+ .strand-btn--lg .strand-btn__spinner {
435
+ width: 20px;
436
+ height: 20px;
437
+ }
438
+
439
+ @keyframes strand-btn-spin {
440
+ to {
441
+ transform: rotate(360deg);
442
+ }
443
+ }
444
+
445
+ /* ── Content wrapper ── */
446
+ .strand-btn__content {
447
+ display: inline-flex;
448
+ align-items: center;
449
+ gap: var(--strand-space-2);
450
+ }
451
+
452
+ /* ── Focus ring (Part XII: Accessibility Ring) ── */
453
+ .strand-btn:focus-visible {
454
+ outline: 2px solid var(--strand-blue-primary);
455
+ outline-offset: 2px;
456
+ }
457
+
458
+ /* ── Reduced motion ── */
459
+ @media (prefers-reduced-motion: reduce) {
460
+ .strand-btn {
461
+ transition: none;
462
+ }
463
+
464
+ .strand-btn:hover:not(:disabled) {
465
+ transform: none;
466
+ }
467
+
468
+ .strand-btn__spinner {
469
+ animation: none;
470
+ border-style: dotted;
471
+ }
472
+ }
473
+
474
+
475
+ /* Card */
476
+ /*! Strand UI | MIT License | dillingerstaffing.com */
477
+
478
+ /*! Strand UI | MIT License | dillingerstaffing.com */
479
+
480
+ /* ── Base ── */
481
+ .strand-card {
482
+ border-radius: var(--strand-radius-lg);
483
+ background: var(--strand-surface-elevated);
484
+ font-family: var(--strand-font-sans);
485
+ overflow: hidden;
486
+ box-sizing: border-box;
487
+ max-width: 100%;
488
+ }
489
+
490
+ /* ── Variants ── */
491
+ .strand-card--elevated {
492
+ box-shadow: var(--strand-elevation-1);
493
+ }
494
+
495
+ .strand-card--outlined {
496
+ box-shadow: none;
497
+ border: 1px solid var(--strand-gray-200);
498
+ }
499
+
500
+ .strand-card--interactive {
501
+ box-shadow: var(--strand-elevation-1);
502
+ cursor: pointer;
503
+ transition:
504
+ transform var(--strand-duration-fast) var(--strand-ease-out-expo),
505
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-expo);
506
+ }
507
+
508
+ .strand-card--interactive:hover {
509
+ transform: translateY(-2px);
510
+ box-shadow: var(--strand-elevation-2);
511
+ }
512
+
513
+ /* ── Padding ── */
514
+ .strand-card--pad-none {
515
+ padding: 0;
516
+ }
517
+
518
+ .strand-card--pad-sm {
519
+ padding: var(--strand-space-4);
520
+ }
521
+
522
+ .strand-card--pad-md {
523
+ padding: var(--strand-space-6);
524
+ }
525
+
526
+ .strand-card--pad-lg {
527
+ padding: var(--strand-space-10);
528
+ }
529
+
530
+ /* ── Focus ring (interactive cards) ── */
531
+ .strand-card--interactive:focus-visible {
532
+ outline: 2px solid var(--strand-blue-primary);
533
+ outline-offset: 2px;
534
+ }
535
+
536
+ /* ── Reduced motion ── */
537
+ @media (prefers-reduced-motion: reduce) {
538
+ .strand-card--interactive {
539
+ transition: none;
540
+ }
541
+
542
+ .strand-card--interactive:hover {
543
+ transform: none;
544
+ }
545
+ }
546
+
547
+
548
+ /* Checkbox */
549
+ /*! Strand UI | MIT License | dillingerstaffing.com */
550
+
551
+ /*! Strand UI | MIT License | dillingerstaffing.com */
552
+
553
+ /* ── Base ── */
554
+ .strand-checkbox {
555
+ display: inline-flex;
556
+ align-items: center;
557
+ gap: var(--strand-space-2);
558
+ cursor: pointer;
559
+ user-select: none;
560
+ font-family: var(--strand-font-sans);
561
+ font-size: var(--strand-text-sm);
562
+ color: var(--strand-gray-900);
563
+ line-height: var(--strand-leading-snug);
564
+ }
565
+
566
+ /* ── Hidden native input ── */
567
+ .strand-checkbox__native {
568
+ position: absolute;
569
+ width: 1px;
570
+ height: 1px;
571
+ padding: 0;
572
+ margin: -1px;
573
+ overflow: hidden;
574
+ clip: rect(0, 0, 0, 0);
575
+ white-space: nowrap;
576
+ border: 0;
577
+ }
578
+
579
+ /* ── Custom visual ── */
580
+ .strand-checkbox__control {
581
+ display: flex;
582
+ align-items: center;
583
+ justify-content: center;
584
+ width: 18px;
585
+ height: 18px;
586
+ border: 1px solid var(--strand-gray-200);
587
+ border-radius: var(--strand-radius-sm);
588
+ background: var(--strand-surface-elevated);
589
+ color: var(--strand-on-blue-primary);
590
+ flex-shrink: 0;
591
+ transition:
592
+ background var(--strand-duration-fast) var(--strand-ease-out-quart),
593
+ border-color var(--strand-duration-fast) var(--strand-ease-out-quart),
594
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-quart);
595
+ }
596
+
597
+ .strand-checkbox__icon {
598
+ width: 14px;
599
+ height: 14px;
600
+ }
601
+
602
+ /* ── Focus ring ── */
603
+ .strand-checkbox__native:focus-visible ~ .strand-checkbox__control {
604
+ border-color: var(--strand-blue-primary);
605
+ box-shadow: var(--strand-focus-ring);
606
+ }
607
+
608
+ /* ── Checked ── */
609
+ .strand-checkbox--checked .strand-checkbox__control {
610
+ background: var(--strand-blue-primary);
611
+ border-color: var(--strand-blue-primary);
612
+ }
613
+
614
+ /* ── Indeterminate ── */
615
+ .strand-checkbox--indeterminate .strand-checkbox__control {
616
+ background: var(--strand-blue-primary);
617
+ border-color: var(--strand-blue-primary);
618
+ }
619
+
620
+ /* ── Hover ── */
621
+ .strand-checkbox:hover:not(.strand-checkbox--disabled) .strand-checkbox__control {
622
+ border-color: var(--strand-blue-indicator);
623
+ }
624
+
625
+ .strand-checkbox--checked:hover:not(.strand-checkbox--disabled) .strand-checkbox__control,
626
+ .strand-checkbox--indeterminate:hover:not(.strand-checkbox--disabled) .strand-checkbox__control {
627
+ background: var(--strand-blue-vivid);
628
+ border-color: var(--strand-blue-vivid);
629
+ }
630
+
631
+ /* ── Label ── */
632
+ .strand-checkbox__label {
633
+ color: var(--strand-gray-900);
634
+ }
635
+
636
+ /* ── Disabled ── */
637
+ .strand-checkbox--disabled {
638
+ opacity: 0.4;
639
+ cursor: not-allowed;
640
+ }
641
+
642
+ /* ── Reduced motion ── */
643
+ @media (prefers-reduced-motion: reduce) {
644
+ .strand-checkbox__control {
645
+ transition: none;
646
+ }
647
+ }
648
+
649
+
650
+ /* CodeBlock */
651
+ /*! Strand UI | MIT License | dillingerstaffing.com */
652
+
653
+ /*! Strand UI | MIT License | dillingerstaffing.com */
654
+
655
+ /* ── Layout ── */
656
+ .strand-code-block {
657
+ position: relative;
658
+ }
659
+
660
+ /* ── Label (optional language indicator) ── */
661
+ .strand-code-block__label {
662
+ display: block;
663
+ font-family: var(--strand-font-mono);
664
+ font-size: var(--strand-text-xs);
665
+ font-weight: var(--strand-weight-medium);
666
+ letter-spacing: var(--strand-tracking-widest);
667
+ text-transform: uppercase;
668
+ color: var(--strand-gray-500);
669
+ margin-bottom: var(--strand-space-2);
670
+ }
671
+
672
+ /* ── Code area ── */
673
+ .strand-code-block__pre {
674
+ font-family: var(--strand-font-mono);
675
+ font-size: var(--strand-text-sm);
676
+ line-height: var(--strand-leading-relaxed);
677
+ color: var(--strand-blue-midnight);
678
+ background: var(--strand-surface-recessed);
679
+ box-shadow: inset 0 1px 3px rgba(15, 23, 42, 0.06);
680
+ border-radius: var(--strand-radius-lg);
681
+ padding: var(--strand-space-3) var(--strand-space-4);
682
+ overflow-x: auto;
683
+ white-space: pre;
684
+ tab-size: 2;
685
+ margin: 0;
686
+ }
687
+
688
+ /* ── Inline code ── */
689
+ .strand-code-inline {
690
+ font-family: var(--strand-font-mono);
691
+ font-size: 0.875em;
692
+ color: var(--strand-blue-deep);
693
+ background: var(--strand-surface-recessed);
694
+ padding: 0.125em 0.375em;
695
+ border-radius: var(--strand-radius-sm);
696
+ }
697
+
698
+
699
+ /* Container */
700
+ /*! Strand UI | MIT License | dillingerstaffing.com */
701
+
702
+ /*! Strand UI | MIT License | dillingerstaffing.com */
703
+
704
+ /* ── Base ── */
705
+ .strand-container {
706
+ width: 100%;
707
+ margin-inline: auto;
708
+ padding-inline: clamp(1.5rem, 5vw, 4rem);
709
+ }
710
+
711
+ /* ── Sizes ── */
712
+ .strand-container--narrow {
713
+ max-width: var(--strand-content-narrow);
714
+ }
715
+
716
+ .strand-container--default {
717
+ max-width: var(--strand-content-default);
718
+ }
719
+
720
+ .strand-container--wide {
721
+ max-width: var(--strand-content-wide);
722
+ }
723
+
724
+ .strand-container--full {
725
+ max-width: var(--strand-content-full);
726
+ }
727
+
728
+
729
+ /* DataReadout */
730
+ /*! Strand UI | MIT License | dillingerstaffing.com */
731
+
732
+ /*! Strand UI | MIT License | dillingerstaffing.com */
733
+
734
+ /* ── Layout ── */
735
+ .strand-data-readout {
736
+ display: flex;
737
+ flex-direction: column;
738
+ gap: var(--strand-space-1);
739
+ }
740
+
741
+ /* ── Label (overline) ── */
742
+ .strand-data-readout__label {
743
+ font-family: var(--strand-font-mono);
744
+ font-size: var(--strand-text-xs);
745
+ font-weight: var(--strand-weight-medium);
746
+ letter-spacing: var(--strand-tracking-ultra);
747
+ text-transform: uppercase;
748
+ color: var(--strand-gray-500);
749
+ line-height: var(--strand-leading-normal);
750
+ }
751
+
752
+ /* ── Value (instrument readout) ── */
753
+ .strand-data-readout__value {
754
+ font-family: var(--strand-font-mono);
755
+ font-size: var(--strand-text-3xl);
756
+ font-weight: var(--strand-weight-light);
757
+ letter-spacing: var(--strand-tracking-tighter);
758
+ color: var(--strand-blue-midnight);
759
+ line-height: var(--strand-leading-tight);
760
+ font-variant-numeric: tabular-nums;
761
+ }
762
+
763
+ /* ── Size variants ── */
764
+ .strand-data-readout--sm .strand-data-readout__value {
765
+ font-size: var(--strand-text-xl);
766
+ }
767
+
768
+ .strand-data-readout--lg .strand-data-readout__value {
769
+ font-size: var(--strand-text-4xl);
770
+ }
771
+
772
+
773
+ /* Dialog */
774
+ /*! Strand UI | MIT License | dillingerstaffing.com */
775
+
776
+ /*! Strand UI | MIT License | dillingerstaffing.com */
777
+
778
+ /* ── Backdrop ── */
779
+ .strand-dialog__backdrop {
780
+ position: fixed;
781
+ inset: 0;
782
+ z-index: 1000;
783
+ display: flex;
784
+ align-items: center;
785
+ justify-content: center;
786
+ background: var(--strand-backdrop);
787
+ }
788
+
789
+ /* ── Panel ── */
790
+ .strand-dialog__panel {
791
+ position: relative;
792
+ width: 100%;
793
+ max-width: 560px;
794
+ margin: var(--strand-space-4);
795
+ padding: var(--strand-space-8);
796
+ background: var(--strand-surface-elevated);
797
+ border-radius: var(--strand-radius-xl);
798
+ box-shadow: var(--strand-elevation-4);
799
+ font-family: var(--strand-font-sans);
800
+ outline: none;
801
+ }
802
+
803
+ /* ── Header ── */
804
+ .strand-dialog__header {
805
+ margin-bottom: var(--strand-space-4);
806
+ padding-right: var(--strand-space-8);
807
+ }
808
+
809
+ /* ── Title ── */
810
+ .strand-dialog__title {
811
+ margin: 0;
812
+ font-size: var(--strand-text-lg);
813
+ font-weight: var(--strand-weight-semibold);
814
+ color: var(--strand-blue-midnight);
815
+ line-height: var(--strand-leading-snug);
816
+ }
817
+
818
+ /* ── Close button ── */
819
+ .strand-dialog__close {
820
+ position: absolute;
821
+ top: var(--strand-space-6);
822
+ right: var(--strand-space-6);
823
+ display: inline-flex;
824
+ align-items: center;
825
+ justify-content: center;
826
+ width: 32px;
827
+ height: 32px;
828
+ padding: 0;
829
+ border: none;
830
+ border-radius: var(--strand-radius-md);
831
+ background: transparent;
832
+ color: var(--strand-gray-500);
833
+ font-size: var(--strand-text-lg);
834
+ cursor: pointer;
835
+ transition: background var(--strand-duration-fast) var(--strand-ease-out-quart),
836
+ color var(--strand-duration-fast) var(--strand-ease-out-quart);
837
+ }
838
+
839
+ .strand-dialog__close:hover {
840
+ background: var(--strand-gray-200);
841
+ color: var(--strand-gray-900);
842
+ }
843
+
844
+ /* ── Body ── */
845
+ .strand-dialog__body {
846
+ padding-top: var(--strand-space-6);
847
+ color: var(--strand-gray-600);
848
+ font-size: var(--strand-text-sm);
849
+ }
850
+
851
+ /* ── Reduced motion ── */
852
+ @media (prefers-reduced-motion: reduce) {
853
+ .strand-dialog__close {
854
+ transition: none;
855
+ }
856
+ }
857
+
858
+
859
+ /* Divider */
860
+ /*! Strand UI | MIT License | dillingerstaffing.com */
861
+
862
+ /*! Strand UI | MIT License | dillingerstaffing.com */
863
+
864
+ /* ── Base ── */
865
+ .strand-divider {
866
+ border: 0;
867
+ margin: 0;
868
+ padding: 0;
869
+ }
870
+
871
+ /* ── Horizontal (hr) ── */
872
+ .strand-divider--horizontal {
873
+ width: 100%;
874
+ border-top: 1px solid var(--strand-gray-200);
875
+ }
876
+
877
+ /* ── Vertical ── */
878
+ .strand-divider--vertical {
879
+ align-self: stretch;
880
+ border-left: 1px solid var(--strand-gray-200);
881
+ }
882
+
883
+ /* ── Labeled ── */
884
+ .strand-divider--labeled {
885
+ display: flex;
886
+ align-items: center;
887
+ gap: var(--strand-space-3);
888
+ border-top: 0;
889
+ }
890
+
891
+ .strand-divider__line {
892
+ flex: 1;
893
+ height: 0;
894
+ border-top: 1px solid var(--strand-gray-200);
895
+ }
896
+
897
+ .strand-divider__label {
898
+ font-family: var(--strand-font-mono);
899
+ font-size: var(--strand-text-xs);
900
+ font-weight: var(--strand-weight-medium);
901
+ color: var(--strand-gray-400);
902
+ letter-spacing: var(--strand-tracking-widest);
903
+ text-transform: uppercase;
904
+ white-space: nowrap;
905
+ }
906
+
907
+
908
+ /* FormField */
909
+ /*! Strand UI | MIT License | dillingerstaffing.com */
910
+
911
+ /*! Strand UI | MIT License | dillingerstaffing.com */
912
+
913
+ /* ── Base ── */
914
+ .strand-form-field {
915
+ display: flex;
916
+ flex-direction: column;
917
+ gap: var(--strand-space-2);
918
+ }
919
+
920
+ /* ── Label ── */
921
+ .strand-form-field__label {
922
+ font-family: var(--strand-font-sans);
923
+ font-size: var(--strand-text-sm);
924
+ font-weight: var(--strand-weight-medium);
925
+ color: var(--strand-gray-700);
926
+ line-height: var(--strand-leading-snug);
927
+ }
928
+
929
+ /* ── Required indicator ── */
930
+ .strand-form-field__required {
931
+ color: var(--strand-red-alert);
932
+ margin-left: var(--strand-space-1);
933
+ }
934
+
935
+ /* ── Control wrapper ── */
936
+ .strand-form-field__control {
937
+ display: flex;
938
+ flex-direction: column;
939
+ }
940
+
941
+ /* ── Hint ── */
942
+ .strand-form-field__hint {
943
+ margin: 0;
944
+ font-family: var(--strand-font-sans);
945
+ font-size: var(--strand-text-xs);
946
+ color: var(--strand-gray-500);
947
+ line-height: var(--strand-leading-normal);
948
+ }
949
+
950
+ /* ── Error message ── */
951
+ .strand-form-field__error {
952
+ margin: 0;
953
+ font-family: var(--strand-font-sans);
954
+ font-size: var(--strand-text-xs);
955
+ color: var(--strand-red-alert);
956
+ line-height: var(--strand-leading-normal);
957
+ }
958
+
959
+
960
+ /* Grid */
961
+ /*! Strand UI | MIT License | dillingerstaffing.com */
962
+
963
+ /*! Strand UI | MIT License | dillingerstaffing.com */
964
+
965
+ /* ── Base ── */
966
+ .strand-grid {
967
+ display: grid;
968
+ overflow: hidden;
969
+ max-width: 100%;
970
+ box-sizing: border-box;
971
+ }
972
+
973
+ .strand-grid > * {
974
+ min-width: 0;
975
+ }
976
+
977
+ /* ── Column utilities ── */
978
+ .strand-grid--cols-2 { grid-template-columns: repeat(2, 1fr); }
979
+ .strand-grid--cols-3 { grid-template-columns: repeat(3, 1fr); }
980
+ .strand-grid--cols-4 { grid-template-columns: repeat(4, 1fr); }
981
+
982
+ /* ── Gap utilities ── */
983
+ .strand-grid--gap-1 { gap: var(--strand-space-1); }
984
+ .strand-grid--gap-2 { gap: var(--strand-space-2); }
985
+ .strand-grid--gap-3 { gap: var(--strand-space-3); }
986
+ .strand-grid--gap-4 { gap: var(--strand-space-4); }
987
+ .strand-grid--gap-5 { gap: var(--strand-space-5); }
988
+ .strand-grid--gap-6 { gap: var(--strand-space-6); }
989
+ .strand-grid--gap-8 { gap: var(--strand-space-8); }
990
+
991
+
992
+ /* Input */
993
+ /*! Strand UI | MIT License | dillingerstaffing.com */
994
+
995
+ /*! Strand UI | MIT License | dillingerstaffing.com */
996
+
997
+ .strand-input {
998
+ position: relative;
999
+ display: flex;
1000
+ align-items: center;
1001
+ background: var(--strand-surface-elevated);
1002
+ border: 1px solid var(--strand-gray-200);
1003
+ border-radius: var(--strand-radius-md);
1004
+ transition:
1005
+ border-color var(--strand-duration-fast) var(--strand-ease-out-quart),
1006
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-quart);
1007
+ }
1008
+
1009
+ .strand-input:focus-within {
1010
+ border-color: var(--strand-blue-primary);
1011
+ box-shadow: var(--strand-focus-ring);
1012
+ }
1013
+
1014
+ /* ── Field ── */
1015
+ .strand-input__field {
1016
+ flex: 1;
1017
+ width: 100%;
1018
+ padding: var(--strand-space-3) var(--strand-space-4);
1019
+ background: transparent;
1020
+ border: none;
1021
+ font-family: var(--strand-font-sans);
1022
+ font-size: var(--strand-text-base);
1023
+ color: var(--strand-gray-900);
1024
+ outline: none;
1025
+ }
1026
+
1027
+ .strand-input__field::placeholder {
1028
+ color: var(--strand-gray-400);
1029
+ }
1030
+
1031
+ /* ── Addons ── */
1032
+ .strand-input__leading,
1033
+ .strand-input__trailing {
1034
+ display: flex;
1035
+ align-items: center;
1036
+ color: var(--strand-gray-500);
1037
+ font-size: var(--strand-text-sm);
1038
+ }
1039
+
1040
+ .strand-input__leading {
1041
+ padding-left: var(--strand-space-3);
1042
+ }
1043
+
1044
+ .strand-input__trailing {
1045
+ padding-right: var(--strand-space-3);
1046
+ }
1047
+
1048
+ .strand-input--has-leading .strand-input__field {
1049
+ padding-left: var(--strand-space-2);
1050
+ }
1051
+
1052
+ .strand-input--has-trailing .strand-input__field {
1053
+ padding-right: var(--strand-space-2);
1054
+ }
1055
+
1056
+ /* ── Error ── */
1057
+ .strand-input--error {
1058
+ border-color: var(--strand-red-alert);
1059
+ }
1060
+
1061
+ .strand-input--error:focus-within {
1062
+ border-color: var(--strand-red-alert);
1063
+ box-shadow: var(--strand-focus-ring-error);
1064
+ }
1065
+
1066
+ /* ── Disabled ── */
1067
+ .strand-input--disabled {
1068
+ opacity: 0.4;
1069
+ cursor: not-allowed;
1070
+ }
1071
+
1072
+ .strand-input--disabled .strand-input__field {
1073
+ cursor: not-allowed;
1074
+ }
1075
+
1076
+ /* ── Reduced motion ── */
1077
+ @media (prefers-reduced-motion: reduce) {
1078
+ .strand-input {
1079
+ transition: none;
1080
+ }
1081
+ }
1082
+
1083
+
1084
+ /* Link */
1085
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1086
+
1087
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1088
+
1089
+ .strand-link {
1090
+ color: var(--strand-blue-primary);
1091
+ text-decoration: none;
1092
+ font-family: var(--strand-font-sans);
1093
+ background-image: linear-gradient(currentColor, currentColor);
1094
+ background-position: 0% 100%;
1095
+ background-repeat: no-repeat;
1096
+ background-size: 0% 1px;
1097
+ transition: background-size var(--strand-duration-normal) var(--strand-ease-out-expo);
1098
+ cursor: pointer;
1099
+ }
1100
+
1101
+ .strand-link:hover {
1102
+ background-size: 100% 1px;
1103
+ }
1104
+
1105
+ /* ── Focus ring ── */
1106
+ .strand-link:focus-visible {
1107
+ outline: 2px solid var(--strand-blue-primary);
1108
+ outline-offset: 2px;
1109
+ }
1110
+
1111
+ /* ── Reduced motion ── */
1112
+ @media (prefers-reduced-motion: reduce) {
1113
+ .strand-link {
1114
+ transition: none;
1115
+ }
1116
+ }
1117
+
1118
+
1119
+ /* Nav */
1120
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1121
+
1122
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1123
+
1124
+ /* ── Nav bar ── */
1125
+ .strand-nav {
1126
+ position: relative;
1127
+ width: 100%;
1128
+ height: 64px;
1129
+ background: var(--strand-surface-elevated);
1130
+ border-bottom: 1px solid var(--strand-gray-200);
1131
+ font-family: var(--strand-font-sans);
1132
+ }
1133
+
1134
+ /* ── Inner layout ── */
1135
+ .strand-nav__inner {
1136
+ display: flex;
1137
+ align-items: center;
1138
+ height: 100%;
1139
+ padding: 0 var(--strand-space-6);
1140
+ max-width: 1280px;
1141
+ margin: 0 auto;
1142
+ }
1143
+
1144
+ /* ── Logo ── */
1145
+ .strand-nav__logo {
1146
+ flex-shrink: 0;
1147
+ margin-right: var(--strand-space-8);
1148
+ }
1149
+
1150
+ /* ── Desktop items ── */
1151
+ .strand-nav__items {
1152
+ display: flex;
1153
+ align-items: center;
1154
+ gap: var(--strand-space-6);
1155
+ flex: 1;
1156
+ }
1157
+
1158
+ /* ── Links ── */
1159
+ .strand-nav__link {
1160
+ color: var(--strand-gray-600);
1161
+ text-decoration: none;
1162
+ font-size: var(--strand-text-sm);
1163
+ font-weight: var(--strand-weight-medium);
1164
+ transition: color var(--strand-duration-fast) var(--strand-ease-out-quart);
1165
+ }
1166
+
1167
+ .strand-nav__link:hover {
1168
+ color: var(--strand-gray-900);
1169
+ }
1170
+
1171
+ .strand-nav__link:focus-visible {
1172
+ outline: 2px solid var(--strand-blue-primary);
1173
+ outline-offset: 2px;
1174
+ }
1175
+
1176
+ .strand-nav__link--active {
1177
+ color: var(--strand-blue-primary);
1178
+ font-weight: var(--strand-weight-medium);
1179
+ }
1180
+
1181
+ /* ── Actions ── */
1182
+ .strand-nav__actions {
1183
+ display: flex;
1184
+ align-items: center;
1185
+ gap: var(--strand-space-3);
1186
+ margin-left: auto;
1187
+ }
1188
+
1189
+ /* ── Hamburger ── */
1190
+ .strand-nav__hamburger {
1191
+ display: none;
1192
+ align-items: center;
1193
+ justify-content: center;
1194
+ width: 40px;
1195
+ height: 40px;
1196
+ margin-left: auto;
1197
+ padding: 0;
1198
+ border: none;
1199
+ border-radius: var(--strand-radius-md);
1200
+ background: transparent;
1201
+ color: var(--strand-gray-600);
1202
+ cursor: pointer;
1203
+ transition: background var(--strand-duration-fast) var(--strand-ease-out-quart);
1204
+ }
1205
+
1206
+ .strand-nav__hamburger:hover {
1207
+ background: var(--strand-gray-200);
1208
+ }
1209
+
1210
+ .strand-nav__hamburger:focus-visible {
1211
+ outline: 2px solid var(--strand-blue-primary);
1212
+ outline-offset: 2px;
1213
+ }
1214
+
1215
+ .strand-nav__hamburger-icon {
1216
+ display: block;
1217
+ width: 20px;
1218
+ height: 2px;
1219
+ background: currentColor;
1220
+ position: relative;
1221
+ }
1222
+
1223
+ .strand-nav__hamburger-icon::before,
1224
+ .strand-nav__hamburger-icon::after {
1225
+ content: "";
1226
+ position: absolute;
1227
+ left: 0;
1228
+ width: 100%;
1229
+ height: 2px;
1230
+ background: currentColor;
1231
+ }
1232
+
1233
+ .strand-nav__hamburger-icon::before {
1234
+ top: -6px;
1235
+ }
1236
+
1237
+ .strand-nav__hamburger-icon::after {
1238
+ top: 6px;
1239
+ }
1240
+
1241
+ /* ── Mobile menu ── */
1242
+ .strand-nav__mobile-menu {
1243
+ display: none;
1244
+ flex-direction: column;
1245
+ width: 100%;
1246
+ padding: var(--strand-space-4) var(--strand-space-6);
1247
+ background: var(--strand-surface-elevated);
1248
+ border-bottom: 1px solid var(--strand-gray-200);
1249
+ }
1250
+
1251
+ .strand-nav__mobile-link {
1252
+ display: block;
1253
+ padding: var(--strand-space-3) 0;
1254
+ color: var(--strand-gray-600);
1255
+ text-decoration: none;
1256
+ font-size: var(--strand-text-sm);
1257
+ font-weight: var(--strand-weight-medium);
1258
+ transition: color var(--strand-duration-fast) var(--strand-ease-out-quart);
1259
+ }
1260
+
1261
+ .strand-nav__mobile-link:hover {
1262
+ color: var(--strand-gray-900);
1263
+ }
1264
+
1265
+ .strand-nav__mobile-link--active {
1266
+ color: var(--strand-blue-primary);
1267
+ }
1268
+
1269
+ /* ── Responsive ── */
1270
+ @media (max-width: 767px) {
1271
+ .strand-nav__items {
1272
+ display: none;
1273
+ }
1274
+
1275
+ .strand-nav__actions {
1276
+ display: none;
1277
+ }
1278
+
1279
+ .strand-nav__hamburger {
1280
+ display: inline-flex;
1281
+ }
1282
+
1283
+ .strand-nav__mobile-menu {
1284
+ display: flex;
1285
+ }
1286
+
1287
+ .strand-nav {
1288
+ height: auto;
1289
+ min-height: 64px;
1290
+ }
1291
+ }
1292
+
1293
+ /* ── Reduced motion ── */
1294
+ @media (prefers-reduced-motion: reduce) {
1295
+ .strand-nav__link,
1296
+ .strand-nav__mobile-link,
1297
+ .strand-nav__hamburger {
1298
+ transition: none;
1299
+ }
1300
+ }
1301
+
1302
+
1303
+ /* Progress */
1304
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1305
+
1306
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1307
+
1308
+ /* ── Bar base ── */
1309
+ .strand-progress--bar {
1310
+ width: 100%;
1311
+ background: var(--strand-gray-200);
1312
+ border-radius: var(--strand-radius-full);
1313
+ overflow: hidden;
1314
+ }
1315
+
1316
+ /* ── Bar sizes ── */
1317
+ .strand-progress--bar.strand-progress--sm {
1318
+ height: 4px;
1319
+ }
1320
+
1321
+ .strand-progress--bar.strand-progress--md {
1322
+ height: 8px;
1323
+ }
1324
+
1325
+ .strand-progress--bar.strand-progress--lg {
1326
+ height: 12px;
1327
+ }
1328
+
1329
+ /* ── Bar fill ── */
1330
+ .strand-progress--bar .strand-progress__fill {
1331
+ height: 100%;
1332
+ background: var(--strand-blue-primary);
1333
+ border-radius: var(--strand-radius-full);
1334
+ transition: width var(--strand-duration-normal) var(--strand-ease-out-quart);
1335
+ }
1336
+
1337
+ /* ── Bar indeterminate ── */
1338
+ .strand-progress--bar.strand-progress--indeterminate .strand-progress__fill {
1339
+ width: 40%;
1340
+ animation: strand-progress-shimmer 1.5s var(--strand-ease-in-out-sine) infinite;
1341
+ }
1342
+
1343
+ @keyframes strand-progress-shimmer {
1344
+ 0% {
1345
+ transform: translateX(-100%);
1346
+ }
1347
+ 100% {
1348
+ transform: translateX(350%);
1349
+ }
1350
+ }
1351
+
1352
+ /* ── Ring base ── */
1353
+ .strand-progress--ring {
1354
+ display: inline-flex;
1355
+ align-items: center;
1356
+ justify-content: center;
1357
+ }
1358
+
1359
+ /* ── Ring track and fill ── */
1360
+ .strand-progress__track {
1361
+ stroke: var(--strand-gray-200);
1362
+ }
1363
+
1364
+ .strand-progress__fill {
1365
+ stroke: var(--strand-blue-primary);
1366
+ }
1367
+
1368
+ .strand-progress--ring .strand-progress__ring {
1369
+ transition: stroke-dashoffset var(--strand-duration-normal) var(--strand-ease-out-quart);
1370
+ }
1371
+
1372
+ /* ── Ring indeterminate ── */
1373
+ .strand-progress--ring.strand-progress--indeterminate .strand-progress__ring {
1374
+ animation: strand-progress-rotate 1.2s linear infinite;
1375
+ }
1376
+
1377
+ @keyframes strand-progress-rotate {
1378
+ to {
1379
+ transform: rotate(360deg);
1380
+ }
1381
+ }
1382
+
1383
+ /* ── Reduced motion ── */
1384
+ @media (prefers-reduced-motion: reduce) {
1385
+ .strand-progress--bar .strand-progress__fill {
1386
+ transition: none;
1387
+ }
1388
+
1389
+ .strand-progress--bar.strand-progress--indeterminate .strand-progress__fill {
1390
+ animation: none;
1391
+ width: 100%;
1392
+ opacity: 0.4;
1393
+ }
1394
+
1395
+ .strand-progress--ring.strand-progress--indeterminate .strand-progress__ring {
1396
+ animation: none;
1397
+ }
1398
+ }
1399
+
1400
+
1401
+ /* Radio */
1402
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1403
+
1404
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1405
+
1406
+ /* ── Base ── */
1407
+ .strand-radio {
1408
+ display: inline-flex;
1409
+ align-items: center;
1410
+ gap: var(--strand-space-2);
1411
+ cursor: pointer;
1412
+ user-select: none;
1413
+ font-family: var(--strand-font-sans);
1414
+ font-size: var(--strand-text-sm);
1415
+ color: var(--strand-gray-900);
1416
+ line-height: var(--strand-leading-snug);
1417
+ }
1418
+
1419
+ /* ── Hidden native input ── */
1420
+ .strand-radio__native {
1421
+ position: absolute;
1422
+ width: 1px;
1423
+ height: 1px;
1424
+ padding: 0;
1425
+ margin: -1px;
1426
+ overflow: hidden;
1427
+ clip: rect(0, 0, 0, 0);
1428
+ white-space: nowrap;
1429
+ border: 0;
1430
+ }
1431
+
1432
+ /* ── Custom visual ── */
1433
+ .strand-radio__control {
1434
+ display: flex;
1435
+ align-items: center;
1436
+ justify-content: center;
1437
+ width: 18px;
1438
+ height: 18px;
1439
+ border: 1px solid var(--strand-gray-200);
1440
+ border-radius: var(--strand-radius-full);
1441
+ background: var(--strand-surface-elevated);
1442
+ flex-shrink: 0;
1443
+ transition:
1444
+ background var(--strand-duration-fast) var(--strand-ease-out-quart),
1445
+ border-color var(--strand-duration-fast) var(--strand-ease-out-quart),
1446
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-quart);
1447
+ }
1448
+
1449
+ .strand-radio__dot {
1450
+ width: 8px;
1451
+ height: 8px;
1452
+ border-radius: var(--strand-radius-full);
1453
+ background: var(--strand-on-blue-primary);
1454
+ transform: scale(0);
1455
+ transition: transform var(--strand-duration-fast) var(--strand-ease-out-expo);
1456
+ }
1457
+
1458
+ /* ── Focus ring ── */
1459
+ .strand-radio__native:focus-visible ~ .strand-radio__control {
1460
+ border-color: var(--strand-blue-primary);
1461
+ box-shadow: var(--strand-focus-ring);
1462
+ }
1463
+
1464
+ /* ── Checked ── */
1465
+ .strand-radio--checked .strand-radio__control {
1466
+ background: var(--strand-blue-primary);
1467
+ border-color: var(--strand-blue-primary);
1468
+ }
1469
+
1470
+ .strand-radio--checked .strand-radio__dot {
1471
+ transform: scale(1);
1472
+ }
1473
+
1474
+ /* ── Hover ── */
1475
+ .strand-radio:hover:not(.strand-radio--disabled) .strand-radio__control {
1476
+ border-color: var(--strand-blue-indicator);
1477
+ }
1478
+
1479
+ .strand-radio--checked:hover:not(.strand-radio--disabled) .strand-radio__control {
1480
+ background: var(--strand-blue-vivid);
1481
+ border-color: var(--strand-blue-vivid);
1482
+ }
1483
+
1484
+ /* ── Label ── */
1485
+ .strand-radio__label {
1486
+ color: var(--strand-gray-900);
1487
+ }
1488
+
1489
+ /* ── Disabled ── */
1490
+ .strand-radio--disabled {
1491
+ opacity: 0.4;
1492
+ cursor: not-allowed;
1493
+ }
1494
+
1495
+ /* ── Reduced motion ── */
1496
+ @media (prefers-reduced-motion: reduce) {
1497
+ .strand-radio__control,
1498
+ .strand-radio__dot {
1499
+ transition: none;
1500
+ }
1501
+ }
1502
+
1503
+
1504
+ /* Section */
1505
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1506
+
1507
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1508
+
1509
+ /* ── Base ── */
1510
+ .strand-section {
1511
+ width: 100%;
1512
+ }
1513
+
1514
+ /* ── Variants ── */
1515
+ .strand-section--standard {
1516
+ padding-block: clamp(4rem, 8vw, 8rem);
1517
+ }
1518
+
1519
+ .strand-section--hero {
1520
+ padding-block: clamp(6rem, 12vw, 12rem);
1521
+ }
1522
+
1523
+ /* ── Backgrounds ── */
1524
+ .strand-section--bg-primary {
1525
+ background-color: var(--strand-surface-primary);
1526
+ }
1527
+
1528
+ .strand-section--bg-elevated {
1529
+ background-color: var(--strand-surface-elevated);
1530
+ }
1531
+
1532
+ .strand-section--bg-recessed {
1533
+ background-color: var(--strand-surface-recessed);
1534
+ }
1535
+
1536
+
1537
+ /* Select */
1538
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1539
+
1540
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1541
+
1542
+ /* ── Base ── */
1543
+ .strand-select {
1544
+ position: relative;
1545
+ display: inline-flex;
1546
+ align-items: center;
1547
+ background: var(--strand-surface-elevated);
1548
+ border: 1px solid var(--strand-gray-200);
1549
+ border-radius: var(--strand-radius-md);
1550
+ transition:
1551
+ border-color var(--strand-duration-fast) var(--strand-ease-out-quart),
1552
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-quart);
1553
+ }
1554
+
1555
+ .strand-select:focus-within {
1556
+ border-color: var(--strand-blue-primary);
1557
+ box-shadow: var(--strand-focus-ring);
1558
+ }
1559
+
1560
+ /* ── Field ── */
1561
+ .strand-select__field {
1562
+ flex: 1;
1563
+ width: 100%;
1564
+ padding: var(--strand-space-3) var(--strand-space-8) var(--strand-space-3) var(--strand-space-4);
1565
+ background: transparent;
1566
+ border: none;
1567
+ font-family: var(--strand-font-sans);
1568
+ font-size: var(--strand-text-base);
1569
+ color: var(--strand-gray-900);
1570
+ outline: none;
1571
+ appearance: none;
1572
+ cursor: pointer;
1573
+ }
1574
+
1575
+ /* ── Arrow indicator ── */
1576
+ .strand-select__arrow {
1577
+ position: absolute;
1578
+ right: var(--strand-space-3);
1579
+ top: 50%;
1580
+ transform: translateY(-50%);
1581
+ width: 0;
1582
+ height: 0;
1583
+ border-left: 5px solid transparent;
1584
+ border-right: 5px solid transparent;
1585
+ border-top: 5px solid var(--strand-gray-500);
1586
+ pointer-events: none;
1587
+ }
1588
+
1589
+ /* ── Error ── */
1590
+ .strand-select--error {
1591
+ border-color: var(--strand-red-alert);
1592
+ }
1593
+
1594
+ .strand-select--error:focus-within {
1595
+ border-color: var(--strand-red-alert);
1596
+ box-shadow: var(--strand-focus-ring-error);
1597
+ }
1598
+
1599
+ /* ── Disabled ── */
1600
+ .strand-select--disabled {
1601
+ opacity: 0.4;
1602
+ cursor: not-allowed;
1603
+ }
1604
+
1605
+ .strand-select--disabled .strand-select__field {
1606
+ cursor: not-allowed;
1607
+ }
1608
+
1609
+ /* ── Reduced motion ── */
1610
+ @media (prefers-reduced-motion: reduce) {
1611
+ .strand-select {
1612
+ transition: none;
1613
+ }
1614
+ }
1615
+
1616
+
1617
+ /* Skeleton */
1618
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1619
+
1620
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1621
+
1622
+ /* ── Base ── */
1623
+ .strand-skeleton {
1624
+ display: block;
1625
+ background: var(--strand-gray-100);
1626
+ }
1627
+
1628
+ /* ── Shimmer ── */
1629
+ .strand-skeleton--shimmer {
1630
+ background: linear-gradient(
1631
+ 90deg,
1632
+ var(--strand-gray-100) 25%,
1633
+ var(--strand-gray-50) 50%,
1634
+ var(--strand-gray-100) 75%
1635
+ );
1636
+ background-size: 200% 100%;
1637
+ animation: strand-skeleton-shimmer 1.8s var(--strand-ease-in-out-sine) infinite;
1638
+ }
1639
+
1640
+ @keyframes strand-skeleton-shimmer {
1641
+ 0% {
1642
+ background-position: 200% 0;
1643
+ }
1644
+ 100% {
1645
+ background-position: -200% 0;
1646
+ }
1647
+ }
1648
+
1649
+ /* ── Text variant ── */
1650
+ .strand-skeleton--text {
1651
+ height: 1em;
1652
+ border-radius: var(--strand-radius-sm);
1653
+ }
1654
+
1655
+ /* ── Rectangle variant ── */
1656
+ .strand-skeleton--rectangle {
1657
+ border-radius: var(--strand-radius-md);
1658
+ }
1659
+
1660
+ /* ── Circle variant ── */
1661
+ .strand-skeleton--circle {
1662
+ border-radius: var(--strand-radius-full);
1663
+ }
1664
+
1665
+ /* ── Reduced motion ── */
1666
+ @media (prefers-reduced-motion: reduce) {
1667
+ .strand-skeleton--shimmer {
1668
+ animation: none;
1669
+ background: var(--strand-gray-100);
1670
+ }
1671
+ }
1672
+
1673
+
1674
+ /* Slider */
1675
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1676
+
1677
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1678
+
1679
+ /* ── Base ── */
1680
+ .strand-slider {
1681
+ position: relative;
1682
+ display: flex;
1683
+ align-items: center;
1684
+ width: 100%;
1685
+ }
1686
+
1687
+ /* ── Field ── */
1688
+ .strand-slider__field {
1689
+ width: 100%;
1690
+ height: 6px;
1691
+ appearance: none;
1692
+ background: var(--strand-gray-200);
1693
+ border-radius: var(--strand-radius-full);
1694
+ outline: none;
1695
+ cursor: pointer;
1696
+ transition: background var(--strand-duration-fast) var(--strand-ease-out-quart);
1697
+ }
1698
+
1699
+ /* ── Thumb: Webkit ── */
1700
+ .strand-slider__field::-webkit-slider-thumb {
1701
+ appearance: none;
1702
+ width: 20px;
1703
+ height: 20px;
1704
+ background: var(--strand-blue-primary);
1705
+ border: 2px solid var(--strand-surface-elevated);
1706
+ border-radius: var(--strand-radius-full);
1707
+ cursor: pointer;
1708
+ box-shadow: var(--strand-elevation-1);
1709
+ transition:
1710
+ background var(--strand-duration-fast) var(--strand-ease-out-quart),
1711
+ transform var(--strand-duration-fast) var(--strand-ease-out-expo);
1712
+ }
1713
+
1714
+ .strand-slider__field:hover:not(:disabled)::-webkit-slider-thumb {
1715
+ background: var(--strand-blue-vivid);
1716
+ transform: scale(1.15);
1717
+ }
1718
+
1719
+ .strand-slider__field:active:not(:disabled)::-webkit-slider-thumb {
1720
+ background: var(--strand-blue-deep);
1721
+ transform: scale(1.05);
1722
+ }
1723
+
1724
+ /* ── Thumb: Firefox ── */
1725
+ .strand-slider__field::-moz-range-thumb {
1726
+ width: 20px;
1727
+ height: 20px;
1728
+ background: var(--strand-blue-primary);
1729
+ border: 2px solid var(--strand-surface-elevated);
1730
+ border-radius: var(--strand-radius-full);
1731
+ cursor: pointer;
1732
+ box-shadow: var(--strand-elevation-1);
1733
+ transition:
1734
+ background var(--strand-duration-fast) var(--strand-ease-out-quart),
1735
+ transform var(--strand-duration-fast) var(--strand-ease-out-expo);
1736
+ }
1737
+
1738
+ .strand-slider__field:hover:not(:disabled)::-moz-range-thumb {
1739
+ background: var(--strand-blue-vivid);
1740
+ transform: scale(1.15);
1741
+ }
1742
+
1743
+ .strand-slider__field:active:not(:disabled)::-moz-range-thumb {
1744
+ background: var(--strand-blue-deep);
1745
+ transform: scale(1.05);
1746
+ }
1747
+
1748
+ /* ── Track: Firefox ── */
1749
+ .strand-slider__field::-moz-range-track {
1750
+ height: 6px;
1751
+ background: var(--strand-gray-200);
1752
+ border-radius: var(--strand-radius-full);
1753
+ }
1754
+
1755
+ /* ── Focus ── */
1756
+ .strand-slider__field:focus-visible::-webkit-slider-thumb {
1757
+ box-shadow: var(--strand-focus-ring);
1758
+ }
1759
+
1760
+ .strand-slider__field:focus-visible::-moz-range-thumb {
1761
+ box-shadow: var(--strand-focus-ring);
1762
+ }
1763
+
1764
+ /* ── Disabled ── */
1765
+ .strand-slider--disabled {
1766
+ opacity: 0.4;
1767
+ cursor: not-allowed;
1768
+ }
1769
+
1770
+ .strand-slider--disabled .strand-slider__field {
1771
+ cursor: not-allowed;
1772
+ }
1773
+
1774
+ /* ── Reduced motion ── */
1775
+ @media (prefers-reduced-motion: reduce) {
1776
+ .strand-slider__field::-webkit-slider-thumb {
1777
+ transition: none;
1778
+ }
1779
+
1780
+ .strand-slider__field::-moz-range-thumb {
1781
+ transition: none;
1782
+ }
1783
+ }
1784
+
1785
+
1786
+ /* Spinner */
1787
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1788
+
1789
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1790
+
1791
+ /* ── Base ── */
1792
+ .strand-spinner {
1793
+ display: inline-flex;
1794
+ align-items: center;
1795
+ justify-content: center;
1796
+ }
1797
+
1798
+ /* ── Ring ── */
1799
+ .strand-spinner__ring {
1800
+ display: block;
1801
+ border: 2px solid var(--strand-gray-200);
1802
+ border-top-color: var(--strand-blue-primary);
1803
+ border-radius: var(--strand-radius-full);
1804
+ animation: strand-spinner-rotate 0.8s linear infinite;
1805
+ }
1806
+
1807
+ /* ── Sizes ── */
1808
+ .strand-spinner--sm .strand-spinner__ring {
1809
+ width: 16px;
1810
+ height: 16px;
1811
+ }
1812
+
1813
+ .strand-spinner--md .strand-spinner__ring {
1814
+ width: 20px;
1815
+ height: 20px;
1816
+ }
1817
+
1818
+ .strand-spinner--lg .strand-spinner__ring {
1819
+ width: 32px;
1820
+ height: 32px;
1821
+ }
1822
+
1823
+ /* ── Animation ── */
1824
+ @keyframes strand-spinner-rotate {
1825
+ to {
1826
+ transform: rotate(360deg);
1827
+ }
1828
+ }
1829
+
1830
+ /* ── Screen reader only text ── */
1831
+ .strand-spinner__sr-only {
1832
+ position: absolute;
1833
+ width: 1px;
1834
+ height: 1px;
1835
+ padding: 0;
1836
+ margin: -1px;
1837
+ overflow: hidden;
1838
+ clip: rect(0, 0, 0, 0);
1839
+ white-space: nowrap;
1840
+ border: 0;
1841
+ }
1842
+
1843
+ /* ── Reduced motion ── */
1844
+ @media (prefers-reduced-motion: reduce) {
1845
+ .strand-spinner__ring {
1846
+ animation: none;
1847
+ border-style: dotted;
1848
+ }
1849
+ }
1850
+
1851
+
1852
+ /* Stack */
1853
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1854
+
1855
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1856
+
1857
+ /* ── Base ── */
1858
+ .strand-stack {
1859
+ display: flex;
1860
+ max-width: 100%;
1861
+ box-sizing: border-box;
1862
+ }
1863
+
1864
+ .strand-stack > * {
1865
+ min-width: 0;
1866
+ }
1867
+
1868
+ /* ── Direction ── */
1869
+ .strand-stack--vertical {
1870
+ flex-direction: column;
1871
+ }
1872
+
1873
+ .strand-stack--horizontal {
1874
+ flex-direction: row;
1875
+ }
1876
+
1877
+ /* ── Alignment ── */
1878
+ .strand-stack--align-start {
1879
+ align-items: flex-start;
1880
+ }
1881
+
1882
+ .strand-stack--align-center {
1883
+ align-items: center;
1884
+ }
1885
+
1886
+ .strand-stack--align-end {
1887
+ align-items: flex-end;
1888
+ }
1889
+
1890
+ /* Default stretch handled by flexbox default */
1891
+
1892
+ /* ── Justification ── */
1893
+ .strand-stack--justify-start {
1894
+ justify-content: flex-start;
1895
+ }
1896
+
1897
+ .strand-stack--justify-center {
1898
+ justify-content: center;
1899
+ }
1900
+
1901
+ .strand-stack--justify-end {
1902
+ justify-content: flex-end;
1903
+ }
1904
+
1905
+ .strand-stack--justify-between {
1906
+ justify-content: space-between;
1907
+ }
1908
+
1909
+ .strand-stack--justify-around {
1910
+ justify-content: space-around;
1911
+ }
1912
+
1913
+ /* ── Wrap ── */
1914
+ .strand-stack--wrap {
1915
+ flex-wrap: wrap;
1916
+ }
1917
+
1918
+ /* ── Gap utilities ── */
1919
+ .strand-stack--gap-1 { gap: var(--strand-space-1); }
1920
+ .strand-stack--gap-2 { gap: var(--strand-space-2); }
1921
+ .strand-stack--gap-3 { gap: var(--strand-space-3); }
1922
+ .strand-stack--gap-4 { gap: var(--strand-space-4); }
1923
+ .strand-stack--gap-5 { gap: var(--strand-space-5); }
1924
+ .strand-stack--gap-6 { gap: var(--strand-space-6); }
1925
+ .strand-stack--gap-8 { gap: var(--strand-space-8); }
1926
+
1927
+
1928
+ /* Switch */
1929
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1930
+
1931
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1932
+
1933
+ /* ── Base ── */
1934
+ .strand-switch {
1935
+ display: inline-flex;
1936
+ align-items: center;
1937
+ gap: var(--strand-space-2);
1938
+ cursor: pointer;
1939
+ user-select: none;
1940
+ font-family: var(--strand-font-sans);
1941
+ font-size: var(--strand-text-sm);
1942
+ color: var(--strand-gray-900);
1943
+ line-height: var(--strand-leading-snug);
1944
+ }
1945
+
1946
+ /* ── Track ── */
1947
+ .strand-switch__track {
1948
+ position: relative;
1949
+ display: inline-flex;
1950
+ align-items: center;
1951
+ width: 40px;
1952
+ height: 22px;
1953
+ padding: 0;
1954
+ border: 1px solid var(--strand-gray-200);
1955
+ border-radius: var(--strand-radius-full);
1956
+ background: var(--strand-gray-200);
1957
+ cursor: pointer;
1958
+ flex-shrink: 0;
1959
+ transition:
1960
+ background var(--strand-duration-fast) var(--strand-ease-out-quart),
1961
+ border-color var(--strand-duration-fast) var(--strand-ease-out-quart),
1962
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-quart);
1963
+ }
1964
+
1965
+ .strand-switch__track:focus-visible {
1966
+ border-color: var(--strand-blue-primary);
1967
+ box-shadow: var(--strand-focus-ring);
1968
+ outline: none;
1969
+ }
1970
+
1971
+ /* ── Thumb ── */
1972
+ .strand-switch__thumb {
1973
+ position: absolute;
1974
+ left: 2px;
1975
+ width: 16px;
1976
+ height: 16px;
1977
+ border-radius: var(--strand-radius-full);
1978
+ background: var(--strand-surface-elevated);
1979
+ box-shadow: var(--strand-elevation-1);
1980
+ transition: transform var(--strand-duration-fast) var(--strand-ease-out-expo);
1981
+ }
1982
+
1983
+ /* ── Checked ── */
1984
+ .strand-switch--checked .strand-switch__track {
1985
+ background: var(--strand-blue-primary);
1986
+ border-color: var(--strand-blue-primary);
1987
+ }
1988
+
1989
+ .strand-switch--checked .strand-switch__thumb {
1990
+ transform: translateX(18px);
1991
+ }
1992
+
1993
+ /* ── Hover ── */
1994
+ .strand-switch:hover:not(.strand-switch--disabled) .strand-switch__track {
1995
+ border-color: var(--strand-blue-indicator);
1996
+ }
1997
+
1998
+ .strand-switch--checked:hover:not(.strand-switch--disabled) .strand-switch__track {
1999
+ background: var(--strand-blue-vivid);
2000
+ border-color: var(--strand-blue-vivid);
2001
+ }
2002
+
2003
+ /* ── Label ── */
2004
+ .strand-switch__label {
2005
+ color: var(--strand-gray-900);
2006
+ }
2007
+
2008
+ /* ── Disabled ── */
2009
+ .strand-switch--disabled {
2010
+ opacity: 0.4;
2011
+ cursor: not-allowed;
2012
+ }
2013
+
2014
+ .strand-switch--disabled .strand-switch__track {
2015
+ cursor: not-allowed;
2016
+ }
2017
+
2018
+ /* ── Reduced motion ── */
2019
+ @media (prefers-reduced-motion: reduce) {
2020
+ .strand-switch__track,
2021
+ .strand-switch__thumb {
2022
+ transition: none;
2023
+ }
2024
+ }
2025
+
2026
+
2027
+ /* Table */
2028
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2029
+
2030
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2031
+
2032
+ /* ── Wrapper (responsive scroll) ── */
2033
+ .strand-table-wrapper {
2034
+ overflow-x: auto;
2035
+ -webkit-overflow-scrolling: touch;
2036
+ }
2037
+
2038
+ /* ── Table ── */
2039
+ .strand-table {
2040
+ width: 100%;
2041
+ border-collapse: collapse;
2042
+ border-spacing: 0;
2043
+ }
2044
+
2045
+ /* ── Header ── */
2046
+ .strand-table__th {
2047
+ padding: var(--strand-space-3) var(--strand-space-4);
2048
+ font-family: var(--strand-font-mono);
2049
+ font-size: var(--strand-text-xs);
2050
+ font-weight: var(--strand-weight-medium);
2051
+ letter-spacing: var(--strand-tracking-widest);
2052
+ text-transform: uppercase;
2053
+ color: var(--strand-gray-500);
2054
+ text-align: left;
2055
+ border-bottom: 1px solid var(--strand-gray-200);
2056
+ white-space: nowrap;
2057
+ }
2058
+
2059
+ /* ── Sort button ── */
2060
+ .strand-table__sort-btn {
2061
+ display: inline-flex;
2062
+ align-items: center;
2063
+ gap: var(--strand-space-1);
2064
+ padding: 0;
2065
+ border: none;
2066
+ background: none;
2067
+ font: inherit;
2068
+ color: inherit;
2069
+ letter-spacing: inherit;
2070
+ text-transform: inherit;
2071
+ cursor: pointer;
2072
+ white-space: nowrap;
2073
+ }
2074
+
2075
+ .strand-table__sort-btn:hover {
2076
+ color: var(--strand-gray-600);
2077
+ }
2078
+
2079
+ .strand-table__sort-btn:focus-visible {
2080
+ outline: 2px solid var(--strand-blue-primary);
2081
+ outline-offset: 2px;
2082
+ }
2083
+
2084
+ .strand-table__sort-indicator {
2085
+ font-size: var(--strand-text-xs);
2086
+ opacity: 0.6;
2087
+ }
2088
+
2089
+ /* ── Body ── */
2090
+ .strand-table__td {
2091
+ padding: var(--strand-space-3) var(--strand-space-4);
2092
+ font-family: var(--strand-font-sans);
2093
+ font-size: var(--strand-text-sm);
2094
+ color: var(--strand-gray-600);
2095
+ border-bottom: 1px solid var(--strand-gray-200);
2096
+ }
2097
+
2098
+ /* ── Row hover ── */
2099
+ .strand-table__row {
2100
+ transition: background var(--strand-duration-fast) var(--strand-ease-out-quart);
2101
+ }
2102
+
2103
+ .strand-table__row:hover {
2104
+ background: var(--strand-blue-glow);
2105
+ }
2106
+
2107
+ /* ── Reduced motion ── */
2108
+ @media (prefers-reduced-motion: reduce) {
2109
+ .strand-table__row {
2110
+ transition: none;
2111
+ }
2112
+ }
2113
+
2114
+
2115
+ /* Tabs */
2116
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2117
+
2118
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2119
+
2120
+ /* ── Tab list ── */
2121
+ .strand-tabs [role="tablist"] {
2122
+ display: flex;
2123
+ gap: var(--strand-space-1);
2124
+ border-bottom: 1px solid var(--strand-gray-400);
2125
+ }
2126
+
2127
+ /* ── Tab button ── */
2128
+ .strand-tabs__tab {
2129
+ position: relative;
2130
+ padding: var(--strand-space-2) var(--strand-space-4);
2131
+ border: none;
2132
+ border-bottom: 2px solid transparent;
2133
+ background: none;
2134
+ font-family: var(--strand-font-sans);
2135
+ font-size: var(--strand-text-sm);
2136
+ font-weight: var(--strand-weight-medium);
2137
+ color: var(--strand-gray-500);
2138
+ cursor: pointer;
2139
+ transition:
2140
+ color var(--strand-duration-fast) var(--strand-ease-out-quart),
2141
+ border-color var(--strand-duration-fast) var(--strand-ease-out-expo);
2142
+ }
2143
+
2144
+ .strand-tabs__tab:hover {
2145
+ color: var(--strand-gray-600);
2146
+ }
2147
+
2148
+ .strand-tabs__tab:focus-visible {
2149
+ outline: 2px solid var(--strand-blue-primary);
2150
+ outline-offset: 2px;
2151
+ }
2152
+
2153
+ .strand-tabs__tab--active {
2154
+ color: var(--strand-blue-primary);
2155
+ border-bottom-color: var(--strand-blue-primary);
2156
+ }
2157
+
2158
+ /* ── Panel ── */
2159
+ .strand-tabs [role="tabpanel"] {
2160
+ padding: var(--strand-space-4) 0;
2161
+ }
2162
+
2163
+ /* ── Reduced motion ── */
2164
+ @media (prefers-reduced-motion: reduce) {
2165
+ .strand-tabs__tab {
2166
+ transition: none;
2167
+ }
2168
+ }
2169
+
2170
+
2171
+ /* Tag */
2172
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2173
+
2174
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2175
+
2176
+ /* ── Base ── */
2177
+ .strand-tag {
2178
+ display: inline-flex;
2179
+ align-items: center;
2180
+ gap: var(--strand-space-1);
2181
+ padding: var(--strand-space-1) var(--strand-space-2);
2182
+ border-radius: var(--strand-radius-sm);
2183
+ font-family: var(--strand-font-sans);
2184
+ font-size: var(--strand-text-xs);
2185
+ font-weight: var(--strand-weight-medium);
2186
+ line-height: var(--strand-leading-snug);
2187
+ white-space: nowrap;
2188
+ border: 1px solid transparent;
2189
+ }
2190
+
2191
+ /* ── Solid variant ── */
2192
+ .strand-tag--solid.strand-tag--default {
2193
+ background: var(--strand-surface-recessed);
2194
+ color: var(--strand-gray-600);
2195
+ }
2196
+
2197
+ .strand-tag--solid.strand-tag--teal {
2198
+ background: rgba(20, 184, 166, 0.1);
2199
+ color: var(--strand-on-teal-tint);
2200
+ }
2201
+
2202
+ .strand-tag--solid.strand-tag--blue {
2203
+ background: var(--strand-blue-glow);
2204
+ color: var(--strand-blue-deep);
2205
+ }
2206
+
2207
+ .strand-tag--solid.strand-tag--amber {
2208
+ background: rgba(245, 158, 11, 0.1);
2209
+ color: var(--strand-on-amber-tint);
2210
+ }
2211
+
2212
+ .strand-tag--solid.strand-tag--red {
2213
+ background: rgba(239, 68, 68, 0.1);
2214
+ color: var(--strand-on-red-tint);
2215
+ }
2216
+
2217
+ /* ── Outlined variant ── */
2218
+ .strand-tag--outlined {
2219
+ background: transparent;
2220
+ }
2221
+
2222
+ .strand-tag--outlined.strand-tag--default {
2223
+ border-color: var(--strand-gray-200);
2224
+ color: var(--strand-gray-600);
2225
+ }
2226
+
2227
+ .strand-tag--outlined.strand-tag--teal {
2228
+ border-color: var(--strand-teal-vital);
2229
+ color: var(--strand-on-teal-tint);
2230
+ }
2231
+
2232
+ .strand-tag--outlined.strand-tag--blue {
2233
+ border-color: var(--strand-blue-primary);
2234
+ color: var(--strand-blue-deep);
2235
+ }
2236
+
2237
+ .strand-tag--outlined.strand-tag--amber {
2238
+ border-color: var(--strand-amber-caution);
2239
+ color: var(--strand-on-amber-tint);
2240
+ }
2241
+
2242
+ .strand-tag--outlined.strand-tag--red {
2243
+ border-color: var(--strand-red-alert);
2244
+ color: var(--strand-on-red-tint);
2245
+ }
2246
+
2247
+ /* ── Remove button ── */
2248
+ .strand-tag__remove {
2249
+ display: inline-flex;
2250
+ align-items: center;
2251
+ justify-content: center;
2252
+ padding: 0;
2253
+ border: none;
2254
+ background: none;
2255
+ color: currentColor;
2256
+ opacity: 0.6;
2257
+ cursor: pointer;
2258
+ border-radius: var(--strand-radius-sm);
2259
+ transition: opacity var(--strand-duration-fast) var(--strand-ease-out-quart);
2260
+ }
2261
+
2262
+ .strand-tag__remove:hover {
2263
+ opacity: 1;
2264
+ }
2265
+
2266
+ /* ── Reduced motion ── */
2267
+ @media (prefers-reduced-motion: reduce) {
2268
+ .strand-tag__remove {
2269
+ transition: none;
2270
+ }
2271
+ }
2272
+
2273
+
2274
+ /* Textarea */
2275
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2276
+
2277
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2278
+
2279
+ /* ── Base ── */
2280
+ .strand-textarea {
2281
+ position: relative;
2282
+ display: flex;
2283
+ flex-direction: column;
2284
+ background: var(--strand-surface-elevated);
2285
+ border: 1px solid var(--strand-gray-200);
2286
+ border-radius: var(--strand-radius-md);
2287
+ transition:
2288
+ border-color var(--strand-duration-fast) var(--strand-ease-out-quart),
2289
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-quart);
2290
+ }
2291
+
2292
+ .strand-textarea:focus-within {
2293
+ border-color: var(--strand-blue-primary);
2294
+ box-shadow: var(--strand-focus-ring);
2295
+ }
2296
+
2297
+ /* ── Field ── */
2298
+ .strand-textarea__field {
2299
+ width: 100%;
2300
+ min-height: 80px;
2301
+ padding: var(--strand-space-3) var(--strand-space-4);
2302
+ background: transparent;
2303
+ border: none;
2304
+ font-family: var(--strand-font-sans);
2305
+ font-size: var(--strand-text-base);
2306
+ color: var(--strand-gray-900);
2307
+ outline: none;
2308
+ resize: vertical;
2309
+ line-height: var(--strand-leading-normal);
2310
+ }
2311
+
2312
+ .strand-textarea__field::placeholder {
2313
+ color: var(--strand-gray-400);
2314
+ }
2315
+
2316
+ /* ── Auto-resize ── */
2317
+ .strand-textarea--auto-resize .strand-textarea__field {
2318
+ resize: none;
2319
+ overflow: hidden;
2320
+ }
2321
+
2322
+ /* ── Character count ── */
2323
+ .strand-textarea__count {
2324
+ align-self: flex-end;
2325
+ padding: var(--strand-space-1) var(--strand-space-3) var(--strand-space-2);
2326
+ font-family: var(--strand-font-sans);
2327
+ font-size: var(--strand-text-xs);
2328
+ color: var(--strand-gray-500);
2329
+ }
2330
+
2331
+ /* ── Error ── */
2332
+ .strand-textarea--error {
2333
+ border-color: var(--strand-red-alert);
2334
+ }
2335
+
2336
+ .strand-textarea--error:focus-within {
2337
+ border-color: var(--strand-red-alert);
2338
+ box-shadow: var(--strand-focus-ring-error);
2339
+ }
2340
+
2341
+ /* ── Disabled ── */
2342
+ .strand-textarea--disabled {
2343
+ opacity: 0.4;
2344
+ cursor: not-allowed;
2345
+ }
2346
+
2347
+ .strand-textarea--disabled .strand-textarea__field {
2348
+ cursor: not-allowed;
2349
+ }
2350
+
2351
+ /* ── Reduced motion ── */
2352
+ @media (prefers-reduced-motion: reduce) {
2353
+ .strand-textarea {
2354
+ transition: none;
2355
+ }
2356
+ }
2357
+
2358
+
2359
+ /* Toast */
2360
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2361
+
2362
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2363
+
2364
+ /* ── Container ── */
2365
+ .strand-toast__container {
2366
+ position: fixed;
2367
+ right: var(--strand-space-6);
2368
+ bottom: var(--strand-space-6);
2369
+ z-index: 1100;
2370
+ display: flex;
2371
+ flex-direction: column-reverse;
2372
+ gap: var(--strand-space-3);
2373
+ pointer-events: none;
2374
+ }
2375
+
2376
+ /* ── Toast ── */
2377
+ .strand-toast {
2378
+ display: flex;
2379
+ align-items: center;
2380
+ justify-content: space-between;
2381
+ min-width: 280px;
2382
+ max-width: 420px;
2383
+ padding: var(--strand-space-4) var(--strand-space-5);
2384
+ background: var(--strand-surface-elevated);
2385
+ border-radius: var(--strand-radius-lg);
2386
+ border-left: 4px solid transparent;
2387
+ box-shadow: var(--strand-elevation-3);
2388
+ font-family: var(--strand-font-sans);
2389
+ font-size: var(--strand-text-sm);
2390
+ pointer-events: auto;
2391
+ animation: strand-toast-in var(--strand-duration-normal) var(--strand-ease-out-expo);
2392
+ }
2393
+
2394
+ /* ── Status accents ── */
2395
+ .strand-toast--info {
2396
+ border-left-color: var(--strand-blue-primary);
2397
+ }
2398
+
2399
+ .strand-toast--success {
2400
+ border-left-color: var(--strand-green-positive);
2401
+ }
2402
+
2403
+ .strand-toast--warning {
2404
+ border-left-color: var(--strand-amber-caution);
2405
+ }
2406
+
2407
+ .strand-toast--error {
2408
+ border-left-color: var(--strand-red-alert);
2409
+ }
2410
+
2411
+ /* ── Message ── */
2412
+ .strand-toast__message {
2413
+ flex: 1;
2414
+ min-width: 0;
2415
+ color: var(--strand-gray-900);
2416
+ }
2417
+
2418
+ /* ── Dismiss button ── */
2419
+ .strand-toast__dismiss {
2420
+ flex-shrink: 0;
2421
+ display: inline-flex;
2422
+ align-items: center;
2423
+ justify-content: center;
2424
+ width: 24px;
2425
+ height: 24px;
2426
+ margin-left: var(--strand-space-3);
2427
+ padding: 0;
2428
+ border: none;
2429
+ border-radius: var(--strand-radius-md);
2430
+ background: transparent;
2431
+ color: var(--strand-gray-500);
2432
+ font-size: var(--strand-text-base);
2433
+ cursor: pointer;
2434
+ transition: background var(--strand-duration-fast) var(--strand-ease-out-quart),
2435
+ color var(--strand-duration-fast) var(--strand-ease-out-quart);
2436
+ }
2437
+
2438
+ .strand-toast__dismiss:hover {
2439
+ background: var(--strand-gray-200);
2440
+ color: var(--strand-gray-600);
2441
+ }
2442
+
2443
+ /* ── Animations ── */
2444
+ @keyframes strand-toast-in {
2445
+ from {
2446
+ opacity: 0;
2447
+ transform: translateY(8px);
2448
+ }
2449
+ to {
2450
+ opacity: 1;
2451
+ transform: translateY(0);
2452
+ }
2453
+ }
2454
+
2455
+ /* ── Reduced motion ── */
2456
+ @media (prefers-reduced-motion: reduce) {
2457
+ .strand-toast {
2458
+ animation: none;
2459
+ }
2460
+
2461
+ .strand-toast__dismiss {
2462
+ transition: none;
2463
+ }
2464
+ }
2465
+
2466
+
2467
+ /* Tooltip */
2468
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2469
+
2470
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2471
+
2472
+ /* ── Wrapper ── */
2473
+ .strand-tooltip__wrapper {
2474
+ position: relative;
2475
+ display: inline-flex;
2476
+ }
2477
+
2478
+ /* ── Tooltip ── */
2479
+ .strand-tooltip {
2480
+ position: absolute;
2481
+ z-index: 1200;
2482
+ padding: var(--strand-space-1) var(--strand-space-2);
2483
+ background: var(--strand-gray-900);
2484
+ color: var(--strand-on-blue-primary);
2485
+ font-family: var(--strand-font-sans);
2486
+ font-size: var(--strand-text-xs);
2487
+ border-radius: var(--strand-radius-md);
2488
+ white-space: nowrap;
2489
+ pointer-events: none;
2490
+ opacity: 0;
2491
+ transition: opacity var(--strand-duration-fast) var(--strand-ease-out-quart);
2492
+ }
2493
+
2494
+ .strand-tooltip--visible {
2495
+ opacity: 1;
2496
+ }
2497
+
2498
+ /* ── Positions ── */
2499
+ .strand-tooltip--top {
2500
+ bottom: 100%;
2501
+ left: 50%;
2502
+ transform: translateX(-50%);
2503
+ margin-bottom: var(--strand-space-2);
2504
+ }
2505
+
2506
+ .strand-tooltip--bottom {
2507
+ top: 100%;
2508
+ left: 50%;
2509
+ transform: translateX(-50%);
2510
+ margin-top: var(--strand-space-2);
2511
+ }
2512
+
2513
+ .strand-tooltip--left {
2514
+ right: 100%;
2515
+ top: 50%;
2516
+ transform: translateY(-50%);
2517
+ margin-right: var(--strand-space-2);
2518
+ }
2519
+
2520
+ .strand-tooltip--right {
2521
+ left: 100%;
2522
+ top: 50%;
2523
+ transform: translateY(-50%);
2524
+ margin-left: var(--strand-space-2);
2525
+ }
2526
+
2527
+ /* ── Reduced motion ── */
2528
+ @media (prefers-reduced-motion: reduce) {
2529
+ .strand-tooltip {
2530
+ transition: none;
2531
+ }
2532
+ }
2533
+
2534
+
2535
+ /* Static & Utilities */
2536
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2537
+
2538
+ /* ── Presentation mode ──
2539
+ Add .strand-static to a parent element to render components
2540
+ at full visual fidelity without interaction.
2541
+ Use for documentation, showcases, and screenshots. */
2542
+
2543
+ .strand-static {
2544
+ pointer-events: none;
2545
+ }
2546
+
2547
+ .strand-static [disabled],
2548
+ .strand-static [aria-disabled="true"] {
2549
+ opacity: 1;
2550
+ cursor: default;
2551
+ }
2552
+
2553
+ .strand-static .strand-btn:disabled {
2554
+ opacity: 1;
2555
+ cursor: default;
2556
+ }
2557
+
2558
+ .strand-static .strand-toast {
2559
+ position: static;
2560
+ }
2561
+
2562
+ .strand-static .strand-tooltip {
2563
+ position: static;
2564
+ }
2565
+
2566
+ .strand-static *,
2567
+ .strand-static *::before,
2568
+ .strand-static *::after {
2569
+ transition: none !important;
2570
+ animation: none !important;
2571
+ }
2572
+
2573
+ /* ── Recessed viewport ──
2574
+ The instrument viewport sits below the card surface.
2575
+ Use for component previews, showcases, and documentation. */
2576
+
2577
+ .strand-viewport {
2578
+ background: var(--strand-surface-recessed);
2579
+ box-shadow: inset 0 1px 3px rgba(15, 23, 42, 0.06);
2580
+ border-radius: var(--strand-radius-lg);
2581
+ padding: var(--strand-space-6);
2582
+ }
2583
+