@akhil-saxena/design-system 1.2.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.
@@ -0,0 +1,4775 @@
1
+ /* @akhil-saxena/design-system v0.1.0 - primitive component CSS.
2
+ Imported via:
3
+ import "@akhil-saxena/design-system/primitives.css";
4
+ Requires tokens.css to be imported first (uses --amber, --ink-2, --rule, etc.). */
5
+
6
+ /* ─── DS atom: Button ────────────────────────────────────────────────────
7
+ Pseudo-class states that inline style={{}} cannot express (D-103).
8
+ Variant-specific hover states keyed off data-variant attribute.
9
+ Source: original handoff `.ds-btn` rules transcribed verbatim. */
10
+ .ds-atom-btn:active {
11
+ transform: scale(0.97);
12
+ }
13
+ .ds-atom-btn:disabled {
14
+ opacity: 0.4;
15
+ cursor: not-allowed;
16
+ pointer-events: none;
17
+ }
18
+ .ds-atom-btn:focus-visible {
19
+ outline: none;
20
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.25);
21
+ }
22
+ /* Primary = brand amber. Hover darkens to amber-d. */
23
+ .ds-atom-btn[data-variant="primary"]:hover:not(:disabled) {
24
+ background: var(--amber-d);
25
+ color: #fff;
26
+ }
27
+ .ds-atom-btn[data-variant="secondary"]:hover:not(:disabled) {
28
+ background: var(--cream-2);
29
+ border-color: rgba(0, 0, 0, 0.12);
30
+ }
31
+ .ds-atom-btn[data-variant="ghost"]:hover:not(:disabled) {
32
+ background: rgba(0, 0, 0, 0.04);
33
+ }
34
+ /* Danger hover: stay on the --red token, just darken via filter so the
35
+ color stays semantically tied to the system token rather than a one-off hex. */
36
+ .ds-atom-btn[data-variant="danger"]:hover:not(:disabled) {
37
+ filter: brightness(0.88);
38
+ }
39
+ .ds-atom-btn[data-loading="true"] {
40
+ pointer-events: none;
41
+ opacity: 0.8;
42
+ }
43
+ /* Dark-mode tweaks: ghost text flips to cream so it reads on dark surfaces;
44
+ primary amber stays the same hue (amber doesn't flip per handoff). */
45
+ .dark .ds-atom-btn[data-variant="ghost"] {
46
+ color: var(--ink);
47
+ }
48
+ .dark .ds-atom-btn[data-variant="ghost"]:hover:not(:disabled) {
49
+ background: rgba(255, 255, 255, 0.06);
50
+ }
51
+ .dark .ds-atom-btn[data-variant="secondary"] {
52
+ color: var(--ink);
53
+ }
54
+ /* v0.5.5 - secondary hover in dark mode: keep bg translucent-light over the
55
+ dark surface so text stays readable. The light-mode rule uses var(--cream-2)
56
+ which flips to a near-black in dark mode, causing text-on-bg contrast loss. */
57
+ .dark .ds-atom-btn[data-variant="secondary"]:hover:not(:disabled) {
58
+ background: rgba(255, 255, 255, 0.08);
59
+ border-color: rgba(255, 255, 255, 0.18);
60
+ color: var(--ink);
61
+ }
62
+
63
+ /* ─── DS atom: TextInput ─────────────────────────────────────────────────
64
+ Background is var(--cream) inline - auto-flips in dark mode via tokens.
65
+ Only dark-specific overrides needed here (border, focus ring strength). */
66
+ .ds-atom-input:focus {
67
+ border-color: var(--amber);
68
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.12);
69
+ }
70
+ .ds-atom-input:disabled {
71
+ opacity: 0.5;
72
+ cursor: not-allowed;
73
+ }
74
+ .ds-atom-input[data-error="true"] {
75
+ border-color: var(--red);
76
+ box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
77
+ }
78
+ .ds-atom-input::placeholder {
79
+ color: var(--ink-3);
80
+ }
81
+ /* Dark mode - stronger border + focus/error rings for AAA visibility */
82
+ .dark .ds-atom-input {
83
+ border-color: var(--rule);
84
+ }
85
+ .dark .ds-atom-input:focus {
86
+ border-color: var(--amber);
87
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.28);
88
+ }
89
+ .dark .ds-atom-input[data-error="true"] {
90
+ border-color: var(--red);
91
+ box-shadow: 0 0 0 3px rgba(251, 136, 136, 0.22);
92
+ }
93
+
94
+ .ds-atom-input-wrap:focus-within {
95
+ border-color: var(--amber);
96
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.12);
97
+ }
98
+ .ds-atom-input-wrap[data-error="true"] {
99
+ border-color: var(--red);
100
+ box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
101
+ }
102
+ .ds-atom-input-wrap input::placeholder {
103
+ color: var(--ink-3);
104
+ }
105
+ .dark .ds-atom-input-wrap:focus-within {
106
+ border-color: var(--amber);
107
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.28);
108
+ }
109
+ .dark .ds-atom-input-wrap[data-error="true"] {
110
+ border-color: var(--red);
111
+ box-shadow: 0 0 0 3px rgba(251, 136, 136, 0.22);
112
+ }
113
+
114
+ /* ─── DS atom: Textarea ──────────────────────────────────────────────────
115
+ Same token-flip pattern as TextInput. */
116
+ .ds-atom-textarea:focus {
117
+ border-color: var(--amber);
118
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.12);
119
+ }
120
+ .ds-atom-textarea:disabled {
121
+ opacity: 0.5;
122
+ cursor: not-allowed;
123
+ }
124
+ .ds-atom-textarea[data-error="true"] {
125
+ border-color: var(--red);
126
+ box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
127
+ }
128
+ .ds-atom-textarea::placeholder {
129
+ color: var(--ink-3);
130
+ }
131
+ .dark .ds-atom-textarea:focus {
132
+ border-color: var(--amber);
133
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.28);
134
+ }
135
+ .dark .ds-atom-textarea[data-error="true"] {
136
+ border-color: var(--red);
137
+ box-shadow: 0 0 0 3px rgba(251, 136, 136, 0.22);
138
+ }
139
+
140
+ /* ─── DS atom: Chip ──────────────────────────────────────────────────────
141
+ Source: handoff .ds-chip rule. × hover turns red. */
142
+ /* Interactive chips (role="button").
143
+ onMouseDown e.preventDefault() prevents mouse-click focus so the
144
+ browser never shows the default black focus border on click.
145
+ :focus-visible still shows the amber ring for keyboard navigation. */
146
+ .ds-atom-chip[data-interactive] {
147
+ cursor: pointer;
148
+ }
149
+ .ds-atom-chip[data-interactive]:focus {
150
+ outline: none;
151
+ }
152
+ .ds-atom-chip[data-interactive]:focus-visible {
153
+ outline: 2px solid var(--amber);
154
+ outline-offset: 2px;
155
+ }
156
+ .dark .ds-atom-chip {
157
+ background: rgba(255, 255, 255, 0.1);
158
+ border-color: rgba(255, 255, 255, 0.18);
159
+ color: var(--ink);
160
+ }
161
+ .ds-atom-chip-x {
162
+ opacity: 0.65;
163
+ }
164
+ .dark .ds-atom-chip-x {
165
+ opacity: 1;
166
+ }
167
+ .ds-atom-chip-x:hover {
168
+ opacity: 1;
169
+ color: var(--red) !important;
170
+ }
171
+
172
+ /* ─── DS atom: Checkbox ──────────────────────────────────────────────────
173
+ Native input visually hidden + sibling-selector CSS for :checked /
174
+ :disabled (D-130 / D-131). Source: handoff .ds-checkbox rule. */
175
+ .ds-atom-checkbox-input:checked + .ds-atom-checkbox-box {
176
+ background: var(--amber);
177
+ border-color: var(--amber);
178
+ }
179
+ .ds-atom-checkbox-input:checked + .ds-atom-checkbox-box .ds-atom-checkbox-check {
180
+ display: inline-block !important;
181
+ }
182
+ .ds-atom-checkbox-input:focus-visible + .ds-atom-checkbox-box {
183
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.25);
184
+ }
185
+ .ds-atom-checkbox-label.is-disabled .ds-atom-checkbox-box {
186
+ cursor: not-allowed;
187
+ }
188
+ /* Dark mode - border is inline style so needs !important to override.
189
+ --ink-5 in dark = #44403c (near-black on dark bg, fails AAA).
190
+ Use --ink-3 (#a8a29e) for a readable border; add subtle fill for legibility. */
191
+ .dark .ds-atom-checkbox-box {
192
+ border-color: var(--ink-3) !important;
193
+ background: rgba(255, 255, 255, 0.06) !important;
194
+ }
195
+ .dark .ds-atom-checkbox-input:checked + .ds-atom-checkbox-box {
196
+ background: var(--amber) !important;
197
+ border-color: var(--amber) !important;
198
+ }
199
+
200
+ /* ─── DS atom: Radio ─────────────────────────────────────────────────────
201
+ Native input visually hidden + sibling-selector CSS for :checked /
202
+ :disabled (D-130 / D-131 / D-133). Source: handoff .ds-radio rule. */
203
+ .ds-atom-radio-dot {
204
+ width: 8px;
205
+ height: 8px;
206
+ border-radius: 50%;
207
+ background: var(--amber);
208
+ display: none;
209
+ }
210
+ .ds-atom-radio-input:checked + .ds-atom-radio-box {
211
+ border-color: var(--amber);
212
+ }
213
+ .ds-atom-radio-input:checked + .ds-atom-radio-box .ds-atom-radio-dot {
214
+ display: inline-block;
215
+ }
216
+ .ds-atom-radio-input:focus-visible + .ds-atom-radio-box {
217
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.25);
218
+ }
219
+ .ds-atom-radio-label.is-disabled .ds-atom-radio-box {
220
+ cursor: not-allowed;
221
+ }
222
+ /* Dark mode - border is inline style (needs !important). --ink-4 gives visible border. */
223
+ .dark .ds-atom-radio-box {
224
+ border-color: var(--ink-3) !important;
225
+ background: rgba(255, 255, 255, 0.06) !important;
226
+ }
227
+ .dark .ds-atom-radio-input:checked + .ds-atom-radio-box {
228
+ border-color: var(--amber) !important;
229
+ background: transparent !important;
230
+ }
231
+
232
+ /* ─── DS atom: Toggle ────────────────────────────────────────────────
233
+ Native input visually hidden + sibling-selector CSS for :checked /
234
+ :focus-visible / :disabled (D-200). Source: handoff .ds-toggle rule. */
235
+ .ds-atom-toggle-track {
236
+ width: 36px;
237
+ height: 20px;
238
+ border-radius: 10px;
239
+ background: var(--ink-5);
240
+ padding: 2px;
241
+ cursor: pointer;
242
+ transition: background 0.2s;
243
+ flex-shrink: 0;
244
+ position: relative;
245
+ display: inline-block;
246
+ box-sizing: border-box;
247
+ }
248
+ .ds-atom-toggle-thumb {
249
+ width: 16px;
250
+ height: 16px;
251
+ border-radius: 50%;
252
+ background: #fff;
253
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
254
+ transition: transform 0.2s;
255
+ display: block;
256
+ }
257
+ .ds-atom-toggle-input:checked + .ds-atom-toggle-track {
258
+ background: var(--amber);
259
+ }
260
+ .ds-atom-toggle-input:checked + .ds-atom-toggle-track .ds-atom-toggle-thumb {
261
+ transform: translateX(16px);
262
+ }
263
+ .ds-atom-toggle-input:focus-visible + .ds-atom-toggle-track {
264
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.25);
265
+ }
266
+ .ds-atom-toggle-label.is-disabled .ds-atom-toggle-track {
267
+ opacity: 0.4;
268
+ cursor: not-allowed;
269
+ }
270
+
271
+ /* ─── DS atom: NumberStepper ─────────────────────────────────────────
272
+ Custom −/+ stepper with bare numeric input. Single primitive composes
273
+ percent/days/salary variants via prefix/suffix/formatFn (D-210, D-211).
274
+ Source: handoff .ds-stepper* rules. */
275
+ .ds-atom-stepper {
276
+ display: inline-flex;
277
+ align-items: center;
278
+ border: 1px solid var(--rule);
279
+ border-radius: 8px;
280
+ overflow: hidden;
281
+ background: rgba(255, 255, 255, 0.6);
282
+ }
283
+ .dark .ds-atom-stepper {
284
+ background: rgba(255, 255, 255, 0.06);
285
+ }
286
+ .ds-atom-stepper-btn {
287
+ width: 34px;
288
+ height: 36px;
289
+ display: inline-flex;
290
+ align-items: center;
291
+ justify-content: center;
292
+ border: none;
293
+ background: transparent;
294
+ cursor: pointer;
295
+ color: var(--ink-2);
296
+ transition: all 0.12s;
297
+ flex-shrink: 0;
298
+ }
299
+ .ds-atom-stepper-btn:hover:not(:disabled) {
300
+ background: var(--cream-2);
301
+ }
302
+ .ds-atom-stepper-btn:active:not(:disabled) {
303
+ background: var(--cream-3);
304
+ }
305
+ .ds-atom-stepper-btn:disabled {
306
+ opacity: 0.3;
307
+ cursor: not-allowed;
308
+ }
309
+ .ds-atom-stepper-display {
310
+ flex: 1;
311
+ display: inline-flex;
312
+ align-items: center;
313
+ justify-content: center;
314
+ gap: 2px;
315
+ border-left: 1px solid var(--rule);
316
+ border-right: 1px solid var(--rule);
317
+ padding: 0 4px;
318
+ min-width: 64px;
319
+ }
320
+ .ds-atom-stepper-input {
321
+ width: 100%;
322
+ text-align: center;
323
+ border: none;
324
+ background: none;
325
+ font-family: var(--mono);
326
+ font-size: 14px;
327
+ font-weight: 600;
328
+ color: var(--ink);
329
+ outline: none;
330
+ padding: 6px 0;
331
+ }
332
+ .ds-atom-stepper-input:disabled {
333
+ cursor: not-allowed;
334
+ }
335
+ .ds-atom-stepper-affix {
336
+ font-family: var(--mono);
337
+ font-size: 11px;
338
+ color: var(--ink-3);
339
+ flex-shrink: 0;
340
+ }
341
+
342
+ /* ─── DS atom: RollingNumber ─────────────────────────────────────────
343
+ Pure-CSS digit-strip animation. Each digit cell is overflow:hidden
344
+ with a vertical strip translateY'd to expose the current digit.
345
+ Transition is CSS-only - no JS lib (D-220).
346
+ Source: handoff .ds-rolling* rules. */
347
+ .ds-atom-rolling {
348
+ display: inline-flex;
349
+ align-items: baseline;
350
+ font-variant-numeric: tabular-nums;
351
+ font-family: var(--mono);
352
+ color: var(--ink);
353
+ }
354
+ .ds-atom-rolling-cell {
355
+ display: inline-block;
356
+ width: 14px;
357
+ height: 22px;
358
+ overflow: hidden;
359
+ vertical-align: middle;
360
+ position: relative;
361
+ }
362
+ .ds-atom-rolling-strip {
363
+ display: flex;
364
+ flex-direction: column;
365
+ transition: transform 350ms cubic-bezier(0.4, 0, 0.2, 1);
366
+ }
367
+ .ds-atom-rolling-strip > span {
368
+ height: 22px;
369
+ line-height: 22px;
370
+ display: block;
371
+ text-align: center;
372
+ font-size: 14px;
373
+ font-weight: 700;
374
+ color: inherit;
375
+ }
376
+ .ds-atom-rolling-static {
377
+ display: inline-block;
378
+ height: 22px;
379
+ line-height: 22px;
380
+ font-size: 14px;
381
+ font-weight: 700;
382
+ color: inherit;
383
+ padding: 0 1px;
384
+ }
385
+
386
+ /* ── RollingNumber variants ──────────────────────────────────────────── */
387
+
388
+ /* DARK variant - departure-board / flip-clock aesthetic.
389
+ Shell: near-black container. Cells: individual recessed tiles with subtle
390
+ inner shadow and gradient. Separators: muted to create hierarchy. */
391
+ .ds-atom-rolling[data-variant="dark"] {
392
+ align-items: center;
393
+ gap: 2px;
394
+ background: #0c0a09;
395
+ border-radius: 8px;
396
+ padding: 8px 10px;
397
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.04);
398
+ }
399
+ .ds-atom-rolling[data-variant="dark"] .ds-atom-rolling-cell {
400
+ background: linear-gradient(180deg, #252220 0%, #1c1917 100%);
401
+ border-radius: 5px;
402
+ width: 20px;
403
+ border: 1px solid #3a3530;
404
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.5), 0 1px 0 rgba(255, 255, 255, 0.03);
405
+ }
406
+ .ds-atom-rolling[data-variant="dark"] .ds-atom-rolling-strip > span {
407
+ color: #f0ede8;
408
+ font-size: 15px;
409
+ }
410
+ .ds-atom-rolling[data-variant="dark"] .ds-atom-rolling-static {
411
+ color: #6b6057;
412
+ padding: 0 3px;
413
+ font-size: 15px;
414
+ height: 22px;
415
+ line-height: 22px;
416
+ }
417
+
418
+ /* LIGHT variant - frosted-card aesthetic for dark surfaces.
419
+ Shell: near-white with soft border. Cells: pure white elevated tiles. */
420
+ .ds-atom-rolling[data-variant="light"] {
421
+ align-items: center;
422
+ gap: 2px;
423
+ background: rgba(255, 255, 255, 0.9);
424
+ border-radius: 8px;
425
+ padding: 8px 10px;
426
+ border: 1px solid rgba(0, 0, 0, 0.06);
427
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
428
+ }
429
+ .ds-atom-rolling[data-variant="light"] .ds-atom-rolling-cell {
430
+ background: #ffffff;
431
+ border-radius: 5px;
432
+ width: 20px;
433
+ border: 1px solid rgba(0, 0, 0, 0.07);
434
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
435
+ }
436
+ .ds-atom-rolling[data-variant="light"] .ds-atom-rolling-strip > span {
437
+ color: #1c1917;
438
+ font-size: 15px;
439
+ }
440
+ .ds-atom-rolling[data-variant="light"] .ds-atom-rolling-static {
441
+ color: #9b9490;
442
+ padding: 0 3px;
443
+ font-size: 15px;
444
+ height: 22px;
445
+ line-height: 22px;
446
+ }
447
+
448
+ /* ─── DS atom: RangeSlider ──────────────────────────────────────────
449
+ Hybrid native input visually hidden + custom track/fill/thumb (D-230).
450
+ Native <input type="range"> overlays the rendered track to capture
451
+ drag + keyboard events; visuals are driven by computed inline width/left.
452
+ Source: handoff .ds-slider* rules. */
453
+ .ds-atom-range {
454
+ display: flex;
455
+ flex-direction: column;
456
+ gap: 8px;
457
+ font-family: var(--font);
458
+ color: var(--ink);
459
+ font-size: 13px;
460
+ }
461
+ .ds-atom-range-label-row {
462
+ display: flex;
463
+ justify-content: space-between;
464
+ align-items: center;
465
+ }
466
+ .ds-atom-range-label {
467
+ font-size: 12px;
468
+ color: var(--ink-2);
469
+ font-weight: 600;
470
+ }
471
+ .ds-atom-range-value {
472
+ font-family: var(--mono);
473
+ font-size: 12px;
474
+ font-weight: 600;
475
+ color: var(--amber-d);
476
+ }
477
+ .ds-atom-range-track-wrap {
478
+ position: relative;
479
+ height: 16px;
480
+ display: flex;
481
+ align-items: center;
482
+ }
483
+ .ds-atom-range-input {
484
+ position: absolute;
485
+ inset: 0;
486
+ width: 100%;
487
+ height: 100%;
488
+ margin: 0;
489
+ opacity: 0;
490
+ cursor: pointer;
491
+ }
492
+ .ds-atom-range-input:disabled {
493
+ cursor: not-allowed;
494
+ }
495
+ .ds-atom-range-track {
496
+ width: 100%;
497
+ height: 6px;
498
+ background: var(--cream-2);
499
+ border-radius: 3px;
500
+ position: relative;
501
+ pointer-events: none;
502
+ }
503
+ .ds-atom-range-fill {
504
+ height: 100%;
505
+ background: var(--amber);
506
+ border-radius: 3px;
507
+ pointer-events: none;
508
+ transition: width 150ms ease;
509
+ }
510
+ .ds-atom-range-thumb {
511
+ position: absolute;
512
+ top: 50%;
513
+ width: 16px;
514
+ height: 16px;
515
+ border-radius: 50%;
516
+ background: #fff;
517
+ border: 2px solid var(--amber);
518
+ transform: translate(-50%, -50%);
519
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
520
+ transition: box-shadow 150ms;
521
+ pointer-events: none;
522
+ }
523
+ .ds-atom-range:hover .ds-atom-range-thumb {
524
+ box-shadow: 0 0 0 4px rgba(245, 158, 11, 0.15), 0 1px 4px rgba(0, 0, 0, 0.15);
525
+ }
526
+ .ds-atom-range[data-disabled="true"] {
527
+ opacity: 0.5;
528
+ }
529
+ .ds-atom-range[data-disabled="true"] .ds-atom-range-thumb {
530
+ cursor: not-allowed;
531
+ }
532
+
533
+ /* ─── DS atom: StarRating ───────────────────────────────────────────
534
+ 5 whole-star buttons in role=radiogroup. Hover preview lifted to
535
+ component state. Lucide <Star /> icon (D-240). */
536
+ .ds-atom-star {
537
+ display: inline-flex;
538
+ gap: 4px;
539
+ align-items: center;
540
+ }
541
+ .ds-atom-star[data-size="compact"] {
542
+ gap: 2px;
543
+ }
544
+ .ds-atom-star-btn {
545
+ background: transparent;
546
+ border: none;
547
+ padding: 2px;
548
+ cursor: pointer;
549
+ display: inline-flex;
550
+ align-items: center;
551
+ justify-content: center;
552
+ transition: transform 100ms;
553
+ color: inherit;
554
+ }
555
+ .ds-atom-star-btn:hover:not(:disabled) {
556
+ transform: scale(1.1);
557
+ }
558
+ .ds-atom-star-btn:focus-visible {
559
+ outline: 2px solid var(--amber);
560
+ outline-offset: 2px;
561
+ border-radius: 4px;
562
+ }
563
+ .ds-atom-star-btn:disabled {
564
+ cursor: default;
565
+ }
566
+ .ds-atom-star[data-disabled="true"] {
567
+ opacity: 0.5;
568
+ }
569
+
570
+ .ds-atom-btn-spinner {
571
+ display: inline-block;
572
+ width: 14px;
573
+ height: 14px;
574
+ border: 2px solid currentColor;
575
+ border-top-color: transparent;
576
+ border-radius: 50%;
577
+ animation: ds-atom-btn-spin 0.8s linear infinite;
578
+ }
579
+ @keyframes ds-atom-btn-spin {
580
+ to {
581
+ transform: rotate(360deg);
582
+ }
583
+ }
584
+
585
+ /* ─── DS atom: StickyNote ────────────────────────────────────────────
586
+ Yellow gradient surface with slight static rotation per data-rotation.
587
+ Always-dark text - does NOT flip in .dark (handoff invariant).
588
+ Source: design-handoff/design-system/ds-surfaces.jsx ds-sticky CSS. */
589
+ .ds-atom-stickynote {
590
+ background: linear-gradient(145deg, #fef3c7, #fde68a);
591
+ color: #292524;
592
+ padding: 16px;
593
+ border-radius: 8px;
594
+ border: 1px solid rgba(245, 158, 11, 0.35);
595
+ box-shadow: 0 2px 8px rgba(245, 158, 11, 0.18), 0 1px 2px rgba(0, 0, 0, 0.06);
596
+ box-sizing: border-box;
597
+ display: block;
598
+ transition: transform 0.15s, box-shadow 0.15s;
599
+ }
600
+ .ds-atom-stickynote[data-rotation="left"] {
601
+ transform: rotate(-2deg);
602
+ }
603
+ .ds-atom-stickynote[data-rotation="right"] {
604
+ transform: rotate(2deg);
605
+ }
606
+ .ds-atom-stickynote[data-rotation="none"] {
607
+ transform: none;
608
+ }
609
+ /* Handoff invariant: text stays dark even under :root.dark.
610
+ Without this rule, .dark body color would cascade in and tint the
611
+ text - sticky notes must read as paper-on-cream regardless of theme. */
612
+ .dark .ds-atom-stickynote {
613
+ color: #292524;
614
+ }
615
+
616
+ /* ─── DS atom: Card ──────────────────────────────────────────────────
617
+ Surface primitive with 4 variants keyed off [data-variant] (D-300).
618
+ Freely-composed children - no compound API (D-301).
619
+ Source: design-handoff/design-system/ds-surfaces.jsx CardsSection. */
620
+ .ds-atom-card {
621
+ box-sizing: border-box;
622
+ display: block;
623
+ }
624
+ .ds-atom-card[data-variant="glass"] {
625
+ background: var(--surf-1);
626
+ border: 1px solid var(--rule);
627
+ border-radius: var(--radius-lg);
628
+ padding: 20px 22px;
629
+ -webkit-backdrop-filter: blur(6px);
630
+ backdrop-filter: blur(6px);
631
+ }
632
+ .ds-atom-card[data-variant="amber"] {
633
+ background: linear-gradient(145deg, var(--amber-l), rgba(254, 243, 199, 0.5));
634
+ border: 1px solid rgba(245, 158, 11, 0.2);
635
+ border-radius: var(--radius-lg);
636
+ padding: 20px 22px;
637
+ }
638
+ /* Dark mode: drop the amber-on-cream gradient (reads muddy on dark cream-2);
639
+ replace with a solid amber-tinted surface that maintains visual identity
640
+ without the awkward gradient or amber border. */
641
+ .dark .ds-atom-card[data-variant="amber"] {
642
+ background: rgba(245, 158, 11, 0.1);
643
+ border: 1px solid rgba(245, 158, 11, 0.18);
644
+ }
645
+ .ds-atom-card[data-variant="dark"] {
646
+ background: #1c1917;
647
+ color: #f5f3f0;
648
+ border: 1px solid #1c1917;
649
+ border-radius: var(--radius-lg);
650
+ padding: 20px 22px;
651
+ }
652
+ /* Dark variant is ALWAYS dark - does NOT respond to .dark cascade.
653
+ Handoff invariant. Force rolling number text to match card color. */
654
+ .dark .ds-atom-card[data-variant="dark"] {
655
+ background: #1c1917;
656
+ color: #f5f3f0;
657
+ }
658
+ .ds-atom-card[data-variant="dark"] .ds-atom-rolling,
659
+ .ds-atom-card[data-variant="dark"] .ds-atom-rolling-strip > span,
660
+ .ds-atom-card[data-variant="dark"] .ds-atom-rolling-static {
661
+ color: #f5f3f0;
662
+ }
663
+ .ds-atom-card[data-variant="kanban"] {
664
+ background: var(--surf-1);
665
+ border: 1px solid var(--rule);
666
+ border-radius: 10px;
667
+ padding: 12px 14px;
668
+ cursor: pointer;
669
+ -webkit-backdrop-filter: blur(6px);
670
+ backdrop-filter: blur(6px);
671
+ transition: box-shadow 0.15s, border-color 0.15s;
672
+ }
673
+ .ds-atom-card[data-variant="kanban"]:hover {
674
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.07);
675
+ border-color: rgba(0, 0, 0, 0.12);
676
+ }
677
+
678
+ /* ─── DS atom: Tooltip ───────────────────────────────────────────────
679
+ Overlay surface for hover/focus reveal of contextual help text.
680
+ Mounts via DSPortal to document.body; absolute-positioned by JS at
681
+ coordinates derived from trigger.getBoundingClientRect() per
682
+ `data-placement`. (D-310, D-311, D-312)
683
+ var(--ink) bg + var(--cream) text - tokens themselves flip under
684
+ :root.dark, so no extra dark-mode override is needed.
685
+ Source: design-handoff/design-system/ds-surfaces.jsx ds-tooltip rule. */
686
+ .ds-atom-tooltip {
687
+ background: var(--ink);
688
+ color: var(--cream);
689
+ padding: 6px 10px;
690
+ border-radius: 6px;
691
+ font-family: var(--font);
692
+ font-size: 12px;
693
+ line-height: 1.4;
694
+ /* Long-text wrap: was `white-space: nowrap` which clipped beyond max-width.
695
+ Now: max-width caps width, normal whitespace allows multi-line wrap,
696
+ word-break handles unbreakable strings (URLs, mono identifiers). */
697
+ white-space: normal;
698
+ word-wrap: break-word;
699
+ overflow-wrap: break-word;
700
+ pointer-events: none;
701
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
702
+ box-sizing: border-box;
703
+ max-width: 280px;
704
+ opacity: 0;
705
+ animation: ds-atom-tooltip-fade 180ms ease-out forwards;
706
+ }
707
+ /* Per-placement selectors omitted - JS sets absolute top/left from
708
+ getBoundingClientRect(). data-placement attribute is still emitted on the
709
+ surface (used by tests + future arrow pseudo-element / Floating-UI hooks
710
+ in v2.1). Empty CSS blocks are rejected by biome's noEmptyBlock rule. */
711
+ @keyframes ds-atom-tooltip-fade {
712
+ from {
713
+ opacity: 0;
714
+ }
715
+ to {
716
+ opacity: 1;
717
+ }
718
+ }
719
+
720
+ /* ─── DS atom: Popover ────────────────────────────────────────────────
721
+ Anchor-ref positioned overlay (D-330). DSPortal-mounted to body.
722
+ ContextMenu variant (D-331) is a same-file styled variant - keyed via
723
+ [data-variant="contextmenu"] on the panel root.
724
+ Source: design-handoff/design-system/ds-surfaces.jsx .ds-popover. */
725
+ .ds-atom-popover {
726
+ position: fixed;
727
+ z-index: 100;
728
+ background: var(--cream-2);
729
+ border: 1px solid var(--rule);
730
+ border-radius: var(--radius-md);
731
+ box-shadow: var(--shadow-3);
732
+ padding: 0;
733
+ min-width: 0;
734
+ animation: ds-atom-popover-in 0.1s ease-out;
735
+ }
736
+ @keyframes ds-atom-popover-in {
737
+ from {
738
+ opacity: 0;
739
+ transform: translateY(-4px);
740
+ }
741
+ to {
742
+ opacity: 1;
743
+ transform: translateY(0);
744
+ }
745
+ }
746
+ .ds-atom-popover[data-placement="bottom-start"] {
747
+ transform-origin: top left;
748
+ }
749
+ .ds-atom-popover[data-placement="bottom-end"] {
750
+ transform-origin: top right;
751
+ }
752
+ .ds-atom-popover[data-placement="top-start"] {
753
+ transform-origin: bottom left;
754
+ }
755
+ .ds-atom-popover[data-placement="top-end"] {
756
+ transform-origin: bottom right;
757
+ }
758
+ .ds-atom-popover[data-variant="contextmenu"] {
759
+ padding: var(--space-1);
760
+ min-width: 200px;
761
+ }
762
+ .ds-atom-popover-item {
763
+ width: 100%;
764
+ background: transparent;
765
+ border: none;
766
+ padding: 8px 14px;
767
+ font-size: 13px;
768
+ font-family: var(--font);
769
+ color: var(--ink);
770
+ cursor: pointer;
771
+ border-radius: var(--radius-sm);
772
+ display: flex;
773
+ align-items: center;
774
+ gap: 8px;
775
+ text-align: left;
776
+ transition: background 0.1s;
777
+ }
778
+ .ds-atom-popover-item:hover:not(:disabled) {
779
+ background: var(--cream-3);
780
+ }
781
+ .ds-atom-popover-item:focus-visible {
782
+ outline: 2px solid var(--amber);
783
+ outline-offset: -2px;
784
+ }
785
+ .ds-atom-popover-item:disabled {
786
+ opacity: 0.4;
787
+ cursor: not-allowed;
788
+ }
789
+ .ds-atom-popover-item[data-tone="danger"] {
790
+ color: var(--red);
791
+ }
792
+ .ds-atom-popover-item[data-tone="danger"]:hover:not(:disabled) {
793
+ background: rgba(239, 68, 68, 0.08);
794
+ }
795
+
796
+ /* ─── DS atom: Modal ─────────────────────────────────────────────────
797
+ DSPortal-mounted backdrop + glass panel. Focus-trapped via useFocusTrap
798
+ (Tab); Escape close handled by Modal directly. ConfirmDialog ships from
799
+ the same file (D-287, D-356). Source: design-handoff/design-system/
800
+ ds-surfaces.jsx ModalsSection + ds-confirmdialog.jsx. Animation keyframes
801
+ namespaced (ds-atom-modal-fadein / ds-atom-modal-in) to avoid colliding
802
+ with consumer-defined fadeIn / modalIn. */
803
+ .ds-atom-modal-backdrop {
804
+ position: fixed;
805
+ inset: 0;
806
+ background: rgba(0, 0, 0, 0.65);
807
+ -webkit-backdrop-filter: blur(2px);
808
+ backdrop-filter: blur(2px);
809
+ display: flex;
810
+ align-items: center;
811
+ justify-content: center;
812
+ z-index: 1000;
813
+ animation: ds-atom-modal-fadein 0.15s ease-out;
814
+ }
815
+ .ds-atom-modal {
816
+ background: #ffffff;
817
+ border: 1px solid var(--rule);
818
+ border-radius: var(--radius-lg);
819
+ padding: 0;
820
+ max-width: 480px;
821
+ width: calc(100% - var(--space-4));
822
+ max-height: 80vh;
823
+ /* Flex column so header/footer pin while body scrolls */
824
+ display: flex;
825
+ flex-direction: column;
826
+ overflow: hidden;
827
+ box-shadow: var(--shadow-3);
828
+ animation: ds-atom-modal-in 0.2s ease-out;
829
+ font-family: var(--font);
830
+ color: var(--ink);
831
+ }
832
+ .dark .ds-atom-modal {
833
+ background: var(--cream-2);
834
+ }
835
+ .ds-atom-modal-hd {
836
+ padding: var(--space-3) var(--space-4) var(--space-3) var(--space-5);
837
+ border-bottom: 1px solid var(--rule);
838
+ display: flex;
839
+ align-items: center;
840
+ gap: var(--space-2);
841
+ flex-shrink: 0;
842
+ }
843
+ .ds-atom-modal-hd-title {
844
+ font-family: var(--display);
845
+ font-weight: 700;
846
+ font-size: 17px;
847
+ flex: 1;
848
+ min-width: 0;
849
+ }
850
+ .ds-atom-modal-body {
851
+ padding: var(--space-4) var(--space-5);
852
+ font-size: 13px;
853
+ line-height: 1.5;
854
+ color: var(--ink-2);
855
+ /* Body scrolls independently; header + footer stay pinned */
856
+ overflow-y: auto;
857
+ flex: 1;
858
+ min-height: 0;
859
+ }
860
+ .ds-atom-modal-ft {
861
+ padding: var(--space-3) var(--space-5);
862
+ border-top: 1px solid var(--rule);
863
+ display: flex;
864
+ justify-content: flex-end;
865
+ gap: var(--space-2);
866
+ flex-shrink: 0;
867
+ }
868
+ @keyframes ds-atom-modal-fadein {
869
+ from {
870
+ opacity: 0;
871
+ }
872
+ to {
873
+ opacity: 1;
874
+ }
875
+ }
876
+ @keyframes ds-atom-modal-in {
877
+ from {
878
+ opacity: 0;
879
+ transform: scale(0.96) translateY(8px);
880
+ }
881
+ to {
882
+ opacity: 1;
883
+ transform: none;
884
+ }
885
+ }
886
+
887
+ /* ─── DS atom: Sheet ─────────────────────────────────────────────────
888
+ DSPortal-mounted backdrop + side-anchored panel (right/left).
889
+ Focus-trapped via useFocusTrap. Mobile (<640px) full-width.
890
+ Source: handoff .ds-sheet + .ds-sheet-right/left + sheetIn keyframes. */
891
+ @keyframes ds-atom-sheet-fadein {
892
+ from {
893
+ opacity: 0;
894
+ }
895
+ to {
896
+ opacity: 1;
897
+ }
898
+ }
899
+ .ds-atom-sheet-backdrop {
900
+ position: fixed;
901
+ inset: 0;
902
+ background: rgba(0, 0, 0, 0.65);
903
+ -webkit-backdrop-filter: blur(2px);
904
+ backdrop-filter: blur(2px);
905
+ z-index: 1000;
906
+ animation: ds-atom-sheet-fadein 0.15s ease-out;
907
+ }
908
+ .ds-atom-sheet {
909
+ position: fixed;
910
+ top: 0;
911
+ bottom: 0;
912
+ height: 100vh;
913
+ width: 400px;
914
+ background: #ffffff;
915
+ box-shadow: var(--shadow-3);
916
+ display: flex;
917
+ flex-direction: column;
918
+ font-family: var(--font);
919
+ color: var(--ink);
920
+ z-index: 1001;
921
+ }
922
+ .dark .ds-atom-sheet {
923
+ background: var(--cream-2);
924
+ }
925
+ .ds-atom-sheet[data-side="right"] {
926
+ right: 0;
927
+ left: auto;
928
+ border-left: 1px solid var(--rule);
929
+ animation: ds-atom-sheet-in-right 0.2s ease-out;
930
+ }
931
+ .ds-atom-sheet[data-side="left"] {
932
+ left: 0;
933
+ right: auto;
934
+ border-right: 1px solid var(--rule);
935
+ animation: ds-atom-sheet-in-left 0.2s ease-out;
936
+ }
937
+ .ds-atom-sheet-hd {
938
+ padding: var(--space-3) var(--space-4) var(--space-3) var(--space-5);
939
+ border-bottom: 1px solid var(--rule);
940
+ display: flex;
941
+ align-items: center;
942
+ gap: var(--space-2);
943
+ flex-shrink: 0;
944
+ }
945
+ .ds-atom-sheet-hd-title {
946
+ font-family: var(--display);
947
+ font-weight: 700;
948
+ font-size: 17px;
949
+ flex: 1;
950
+ min-width: 0;
951
+ }
952
+ .ds-atom-sheet-body {
953
+ padding: var(--space-4) var(--space-5);
954
+ flex: 1;
955
+ overflow-y: auto;
956
+ font-size: 13px;
957
+ line-height: 1.5;
958
+ color: var(--ink-2);
959
+ }
960
+ .ds-atom-sheet-ft {
961
+ padding: var(--space-4) var(--space-5);
962
+ border-top: 1px solid var(--rule);
963
+ display: flex;
964
+ justify-content: flex-end;
965
+ gap: var(--space-2);
966
+ }
967
+ @keyframes ds-atom-sheet-in-right {
968
+ from {
969
+ transform: translateX(100%);
970
+ }
971
+ to {
972
+ transform: translateX(0);
973
+ }
974
+ }
975
+ @keyframes ds-atom-sheet-in-left {
976
+ from {
977
+ transform: translateX(-100%);
978
+ }
979
+ to {
980
+ transform: translateX(0);
981
+ }
982
+ }
983
+ @media (max-width: 640px) {
984
+ .ds-atom-sheet {
985
+ width: 100vw;
986
+ }
987
+ }
988
+
989
+ /* ─── DS atom: HoverCard ───────────────────────────────────────────────
990
+ Rich-content popover on hover with click-to-pin behavior. Uses
991
+ DSPortal + anchor-ref positioning. (D-355) Animation keyframe
992
+ namespaced (ds-atom-hovercard-fadein) to avoid colliding with
993
+ consumer-defined fadeIn. */
994
+ .ds-atom-hovercard {
995
+ /* Reset <dialog> browser defaults, then apply panel styles */
996
+ margin: 0;
997
+ position: fixed;
998
+ background: var(--cream);
999
+ border: 1px solid var(--rule);
1000
+ border-radius: var(--radius-md);
1001
+ box-shadow: var(--shadow-3);
1002
+ padding: var(--space-3);
1003
+ max-width: 320px;
1004
+ font-family: var(--font);
1005
+ font-size: 13px;
1006
+ color: var(--ink);
1007
+ animation: ds-atom-hovercard-fadein 0.15s ease-out;
1008
+ z-index: 1500;
1009
+ }
1010
+ .dark .ds-atom-hovercard {
1011
+ background: var(--cream-2);
1012
+ border-color: var(--rule);
1013
+ color: var(--ink);
1014
+ }
1015
+ @keyframes ds-atom-hovercard-fadein {
1016
+ from {
1017
+ opacity: 0;
1018
+ }
1019
+ to {
1020
+ opacity: 1;
1021
+ }
1022
+ }
1023
+
1024
+ /* ─── DS atom: BottomSheet ─────────────────────────────────────────────
1025
+ DSPortal-mounted overlay sliding up from the bottom edge with a purely
1026
+ visual drag-handle indicator. Mirrors Sheet geometry but bottom-anchored.
1027
+ (D-340) Two height variants via [data-height]:
1028
+ - 'half' (default): max-height: 60vh, top corners rounded
1029
+ - 'full': height: 100vh, no rounding (true full-screen)
1030
+ Animation namespaced (ds-atom-bottomsheet-fadein / sheetInBottom) to
1031
+ avoid colliding with consumer-defined keyframes. */
1032
+ @keyframes ds-atom-bottomsheet-fadein {
1033
+ from {
1034
+ opacity: 0;
1035
+ }
1036
+ to {
1037
+ opacity: 1;
1038
+ }
1039
+ }
1040
+ .ds-atom-bottomsheet-backdrop {
1041
+ position: fixed;
1042
+ inset: 0;
1043
+ background: rgba(0, 0, 0, 0.65);
1044
+ -webkit-backdrop-filter: blur(2px);
1045
+ backdrop-filter: blur(2px);
1046
+ z-index: 1000;
1047
+ display: flex;
1048
+ align-items: flex-end;
1049
+ justify-content: center;
1050
+ animation: ds-atom-bottomsheet-fadein 0.15s ease-out;
1051
+ }
1052
+ .ds-atom-bottomsheet {
1053
+ position: fixed;
1054
+ bottom: 0;
1055
+ left: 0;
1056
+ right: 0;
1057
+ background: var(--cream);
1058
+ border-top: 1px solid var(--rule);
1059
+ box-shadow: var(--shadow-3);
1060
+ border-radius: 16px 16px 0 0;
1061
+ animation: sheetInBottom 0.2s ease-out;
1062
+ display: flex;
1063
+ flex-direction: column;
1064
+ overflow: hidden;
1065
+ font-family: var(--font);
1066
+ color: var(--ink);
1067
+ z-index: 1001;
1068
+ /* snap-back transition; disabled while dragging via [data-dragging] */
1069
+ transition: transform 0.2s ease-out;
1070
+ }
1071
+ .dark .ds-atom-bottomsheet {
1072
+ background: var(--cream-2);
1073
+ }
1074
+ .ds-atom-bottomsheet[data-height="half"] {
1075
+ max-height: 60vh;
1076
+ }
1077
+ .ds-atom-bottomsheet[data-height="full"] {
1078
+ height: 100vh;
1079
+ padding-top: env(safe-area-inset-top, 0);
1080
+ border-radius: 0;
1081
+ }
1082
+ .ds-atom-bottomsheet[data-dragging="true"] {
1083
+ transition: none;
1084
+ }
1085
+ .ds-atom-bottomsheet-handle {
1086
+ width: 32px;
1087
+ height: 4px;
1088
+ background: var(--ink-5);
1089
+ border-radius: 2px;
1090
+ margin: var(--space-2) auto;
1091
+ flex-shrink: 0;
1092
+ /* Bigger touch target than the visual pill (32×4 too small for finger). */
1093
+ padding: 8px 24px;
1094
+ box-sizing: content-box;
1095
+ background-clip: content-box;
1096
+ cursor: grab;
1097
+ touch-action: none;
1098
+ }
1099
+ .ds-atom-bottomsheet-handle:active {
1100
+ cursor: grabbing;
1101
+ }
1102
+ .ds-atom-bottomsheet-hd {
1103
+ padding: var(--space-3) var(--space-4) 0;
1104
+ font-family: var(--display);
1105
+ font-weight: 700;
1106
+ font-size: 16px;
1107
+ color: var(--ink);
1108
+ }
1109
+ .ds-atom-bottomsheet-body {
1110
+ flex: 1;
1111
+ overflow-y: auto;
1112
+ padding: var(--space-3) var(--space-4);
1113
+ font-size: 13px;
1114
+ line-height: 1.5;
1115
+ color: var(--ink-2);
1116
+ }
1117
+ .ds-atom-bottomsheet-ft {
1118
+ padding: var(--space-3) var(--space-4);
1119
+ border-top: 1px solid var(--rule);
1120
+ display: flex;
1121
+ justify-content: flex-end;
1122
+ gap: var(--space-2);
1123
+ }
1124
+ @keyframes sheetInBottom {
1125
+ from {
1126
+ transform: translateY(100%);
1127
+ }
1128
+ to {
1129
+ transform: translateY(0);
1130
+ }
1131
+ }
1132
+
1133
+ /* ─── DS atom: Lightbox ────────────────────────────────────────────────
1134
+ Full-bleed media overlay with arrow navigation. Always-dark invariant
1135
+ - NO .dark overrides. (D-350) */
1136
+ .ds-atom-lightbox-backdrop {
1137
+ position: fixed;
1138
+ inset: 0;
1139
+ background: rgba(0, 0, 0, 0.92);
1140
+ animation: lightboxFade 0.2s ease-out;
1141
+ z-index: 2000;
1142
+ display: flex;
1143
+ flex-direction: column;
1144
+ align-items: center;
1145
+ justify-content: center;
1146
+ padding: var(--space-4);
1147
+ }
1148
+ .ds-atom-lightbox-image {
1149
+ max-width: 90vw;
1150
+ max-height: 80vh;
1151
+ object-fit: contain;
1152
+ display: block;
1153
+ }
1154
+ .ds-atom-lightbox-caption {
1155
+ color: #ffffff;
1156
+ text-align: center;
1157
+ font-family: var(--font);
1158
+ font-size: 14px;
1159
+ padding-top: var(--space-3);
1160
+ max-width: 80vw;
1161
+ }
1162
+ .ds-atom-lightbox-close {
1163
+ position: fixed;
1164
+ top: var(--space-3);
1165
+ right: var(--space-3);
1166
+ width: 40px;
1167
+ height: 40px;
1168
+ border-radius: 50%;
1169
+ background: rgba(0, 0, 0, 0.45);
1170
+ border: none;
1171
+ color: #ffffff;
1172
+ cursor: pointer;
1173
+ display: flex;
1174
+ align-items: center;
1175
+ justify-content: center;
1176
+ z-index: 2001;
1177
+ }
1178
+ .ds-atom-lightbox-close:hover {
1179
+ background: rgba(0, 0, 0, 0.6);
1180
+ }
1181
+ .ds-atom-lightbox-prev,
1182
+ .ds-atom-lightbox-next {
1183
+ position: fixed;
1184
+ top: 50%;
1185
+ transform: translateY(-50%);
1186
+ width: 40px;
1187
+ height: 40px;
1188
+ border-radius: 50%;
1189
+ background: rgba(0, 0, 0, 0.45);
1190
+ border: none;
1191
+ color: #ffffff;
1192
+ cursor: pointer;
1193
+ display: flex;
1194
+ align-items: center;
1195
+ justify-content: center;
1196
+ z-index: 2001;
1197
+ }
1198
+ .ds-atom-lightbox-prev {
1199
+ left: var(--space-3);
1200
+ }
1201
+ .ds-atom-lightbox-next {
1202
+ right: var(--space-3);
1203
+ }
1204
+ .ds-atom-lightbox-prev:hover,
1205
+ .ds-atom-lightbox-next:hover {
1206
+ background: rgba(255, 255, 255, 0.2);
1207
+ }
1208
+ @keyframes lightboxFade {
1209
+ from {
1210
+ opacity: 0;
1211
+ }
1212
+ to {
1213
+ opacity: 1;
1214
+ }
1215
+ }
1216
+
1217
+ /* ─── DS atom: ProgressBar ──────────────────────────────────────────
1218
+ Determinate (track + solid amber fill, 500ms width transition) +
1219
+ loading (3-dot pulse) variants. (DS-42) */
1220
+ .ds-atom-progress {
1221
+ box-sizing: border-box;
1222
+ display: block;
1223
+ width: 100%;
1224
+ font-family: var(--font);
1225
+ }
1226
+ .ds-atom-progress-track {
1227
+ height: 6px;
1228
+ background: var(--cream-2);
1229
+ border-radius: var(--radius-pill);
1230
+ overflow: hidden;
1231
+ position: relative;
1232
+ }
1233
+ .ds-atom-progress-fill {
1234
+ height: 100%;
1235
+ background: var(--amber);
1236
+ border-radius: var(--radius-pill);
1237
+ transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
1238
+ }
1239
+ /* Loading variant - hide track, render 3-dot pulse instead. */
1240
+ .ds-atom-progress[data-loading="true"] .ds-atom-progress-track {
1241
+ display: none;
1242
+ }
1243
+ .ds-atom-progress-dots {
1244
+ display: inline-flex;
1245
+ align-items: center;
1246
+ gap: 6px;
1247
+ min-height: 16px;
1248
+ }
1249
+ .ds-atom-progress-dot {
1250
+ width: 6px;
1251
+ height: 6px;
1252
+ border-radius: 50%;
1253
+ background: var(--ink-3);
1254
+ opacity: 0.3;
1255
+ animation: ds-atom-progress-pulse 1.2s ease-in-out infinite;
1256
+ }
1257
+ .ds-atom-progress-dot:nth-child(1) {
1258
+ animation-delay: 0s;
1259
+ }
1260
+ .ds-atom-progress-dot:nth-child(2) {
1261
+ animation-delay: 0.15s;
1262
+ }
1263
+ .ds-atom-progress-dot:nth-child(3) {
1264
+ animation-delay: 0.3s;
1265
+ }
1266
+ @keyframes ds-atom-progress-pulse {
1267
+ 0%,
1268
+ 100% {
1269
+ opacity: 0.3;
1270
+ transform: scale(1);
1271
+ }
1272
+ 50% {
1273
+ opacity: 1;
1274
+ transform: scale(1.15);
1275
+ }
1276
+ }
1277
+ /* Dark mode: 0.06 is invisible on #1c1917; lift to 0.20 for a clear track. */
1278
+ .dark .ds-atom-progress-track {
1279
+ background: rgba(255, 255, 255, 0.2);
1280
+ }
1281
+
1282
+ /* ─── DS atom: AlertBanner ──────────────────────────────────────────
1283
+ Inline-flow tone banner with [data-variant] tone keying (Card pattern).
1284
+ NO auto-dismiss (manual close via X when dismissible). Layout:
1285
+ [icon] [title + description] [dismiss-X]. Source:
1286
+ design-handoff/design-system/ds-status.jsx. */
1287
+ .ds-atom-banner {
1288
+ box-sizing: border-box;
1289
+ display: flex;
1290
+ align-items: flex-start;
1291
+ gap: 10px;
1292
+ padding: 12px 14px;
1293
+ border-radius: var(--radius-md);
1294
+ border: 1px solid var(--rule);
1295
+ font-family: var(--font);
1296
+ color: var(--ink);
1297
+ }
1298
+ .ds-atom-banner-icon {
1299
+ flex: 0 0 auto;
1300
+ display: inline-flex;
1301
+ align-items: center;
1302
+ justify-content: center;
1303
+ margin-top: 1px;
1304
+ }
1305
+ .ds-atom-banner-body {
1306
+ flex: 1 1 auto;
1307
+ display: flex;
1308
+ flex-direction: column;
1309
+ gap: 2px;
1310
+ min-width: 0;
1311
+ }
1312
+ .ds-atom-banner-title {
1313
+ font-family: var(--display);
1314
+ font-weight: 600;
1315
+ font-size: 14px;
1316
+ color: var(--ink);
1317
+ line-height: 1.3;
1318
+ }
1319
+ .ds-atom-banner-desc {
1320
+ font-family: var(--font);
1321
+ font-weight: 400;
1322
+ font-size: 12.5px;
1323
+ color: var(--ink-2);
1324
+ line-height: 1.45;
1325
+ }
1326
+ .ds-atom-banner-close {
1327
+ flex: 0 0 auto;
1328
+ width: 24px;
1329
+ height: 24px;
1330
+ display: inline-flex;
1331
+ align-items: center;
1332
+ justify-content: center;
1333
+ background: transparent;
1334
+ border: 0;
1335
+ color: var(--ink-3);
1336
+ cursor: pointer;
1337
+ border-radius: 4px;
1338
+ padding: 0;
1339
+ transition: background-color 0.12s, color 0.12s;
1340
+ }
1341
+ .ds-atom-banner-close:hover {
1342
+ background: rgba(0, 0, 0, 0.05);
1343
+ color: var(--ink);
1344
+ }
1345
+ .ds-atom-banner-close:focus-visible {
1346
+ outline: 2px solid var(--amber-d);
1347
+ outline-offset: 2px;
1348
+ }
1349
+ /* Tone-keyed bg + border + icon-color (mirrors Card data-variant). */
1350
+ .ds-atom-banner[data-variant="info"] {
1351
+ background: rgba(94, 184, 251, 0.1);
1352
+ border-color: var(--blue);
1353
+ }
1354
+ .ds-atom-banner[data-variant="info"] .ds-atom-banner-icon {
1355
+ color: var(--blue);
1356
+ }
1357
+ .ds-atom-banner[data-variant="success"] {
1358
+ background: rgba(74, 222, 128, 0.12);
1359
+ border-color: var(--green);
1360
+ }
1361
+ .ds-atom-banner[data-variant="success"] .ds-atom-banner-icon {
1362
+ color: var(--green);
1363
+ }
1364
+ .ds-atom-banner[data-variant="warning"] {
1365
+ background: var(--amber-l);
1366
+ border-color: var(--amber-d);
1367
+ }
1368
+ .ds-atom-banner[data-variant="warning"] .ds-atom-banner-icon {
1369
+ color: var(--amber-d);
1370
+ }
1371
+ /* Warning text must always be dark - amber-l bg (#fef3c7) is light,
1372
+ so --ink-2 reads grey and --ink reads correctly dark in light mode. */
1373
+ .ds-atom-banner[data-variant="warning"] .ds-atom-banner-title {
1374
+ color: #292524;
1375
+ }
1376
+ .ds-atom-banner[data-variant="warning"] .ds-atom-banner-desc {
1377
+ color: #57534e;
1378
+ }
1379
+ .ds-atom-banner[data-variant="error"] {
1380
+ background: rgba(239, 68, 68, 0.1);
1381
+ border-color: var(--red);
1382
+ }
1383
+ .ds-atom-banner[data-variant="error"] .ds-atom-banner-icon {
1384
+ color: var(--red);
1385
+ }
1386
+ /* Dark mode: lift saturation 0.10 → 0.16 so tone bgs read on cream-2 surfaces. */
1387
+ .dark .ds-atom-banner[data-variant="info"] {
1388
+ background: rgba(94, 184, 251, 0.16);
1389
+ }
1390
+ .dark .ds-atom-banner[data-variant="success"] {
1391
+ background: rgba(74, 222, 128, 0.18);
1392
+ }
1393
+ /* Warning: amber-l (#fef3c7) is too bright on dark surfaces and makes --ink
1394
+ (near-white in dark) unreadable. Swap to low-alpha amber so dark --ink text works. */
1395
+ .dark .ds-atom-banner[data-variant="warning"] {
1396
+ background: rgba(245, 158, 11, 0.15);
1397
+ border-color: #fbbf24;
1398
+ }
1399
+ .dark .ds-atom-banner[data-variant="warning"] .ds-atom-banner-title,
1400
+ .dark .ds-atom-banner[data-variant="warning"] .ds-atom-banner-desc {
1401
+ color: var(--ink);
1402
+ }
1403
+ .dark .ds-atom-banner[data-variant="warning"] .ds-atom-banner-icon {
1404
+ color: #fbbf24;
1405
+ }
1406
+ .dark .ds-atom-banner[data-variant="error"] {
1407
+ background: rgba(239, 68, 68, 0.16);
1408
+ }
1409
+ /* Dark-mode dismiss-X hover: black-alpha doesn't read on dark surfaces;
1410
+ flip to white-alpha so the hover state remains visible. */
1411
+ .dark .ds-atom-banner-close:hover {
1412
+ background: rgba(255, 255, 255, 0.08);
1413
+ color: var(--ink);
1414
+ }
1415
+
1416
+ /* ─── DS atom: Skeleton ─────────────────────────────────────────────
1417
+ Single primitive with shape prop (text/circle/pill) + cream-2 pulse
1418
+ animation. Decorative - aria-hidden is set by the component. (DS-43, D-420) */
1419
+ .ds-atom-skeleton {
1420
+ display: block;
1421
+ background: var(--cream-2);
1422
+ animation: ds-atom-skeleton-pulse 1.2s ease-in-out infinite;
1423
+ box-sizing: border-box;
1424
+ }
1425
+ .ds-atom-skeleton[data-shape="text"] {
1426
+ border-radius: var(--radius-sm);
1427
+ }
1428
+ .ds-atom-skeleton[data-shape="circle"] {
1429
+ border-radius: 50%;
1430
+ }
1431
+ .ds-atom-skeleton[data-shape="pill"] {
1432
+ border-radius: var(--radius-pill);
1433
+ }
1434
+ @keyframes ds-atom-skeleton-pulse {
1435
+ 0%,
1436
+ 100% {
1437
+ opacity: 0.6;
1438
+ }
1439
+ 50% {
1440
+ opacity: 1;
1441
+ }
1442
+ }
1443
+ /* Dark mode: cream-2 is too bright; switch to white-low-alpha. */
1444
+ .dark .ds-atom-skeleton {
1445
+ background: rgba(255, 255, 255, 0.06);
1446
+ }
1447
+
1448
+ /* ─── DS atom: Toast ─────────────────────────────────────────────────
1449
+ DSPortal-mounted top-right region (z-1100) + per-tone toast nodes.
1450
+ Slide-in/out 0.2s ease-out. Max 3 concurrent (FIFO drop); managed
1451
+ by ToastProvider state machine. (DS-40, D-400, D-401) */
1452
+ .ds-atom-toast-region {
1453
+ position: fixed;
1454
+ top: var(--space-4);
1455
+ right: var(--space-4);
1456
+ z-index: 1100;
1457
+ display: flex;
1458
+ flex-direction: column;
1459
+ gap: var(--space-2);
1460
+ pointer-events: none;
1461
+ }
1462
+ .ds-atom-toast {
1463
+ pointer-events: auto;
1464
+ display: flex;
1465
+ align-items: center;
1466
+ gap: 10px;
1467
+ min-width: 280px;
1468
+ max-width: 420px;
1469
+ padding: 10px 14px;
1470
+ border-radius: var(--radius-md);
1471
+ border: 1px solid var(--rule);
1472
+ background: var(--surf-1);
1473
+ box-shadow: var(--shadow-2);
1474
+ -webkit-backdrop-filter: blur(20px);
1475
+ backdrop-filter: blur(20px);
1476
+ font-family: var(--font);
1477
+ font-size: 13px;
1478
+ color: var(--ink);
1479
+ animation: ds-atom-toast-slidein 0.2s ease-out;
1480
+ }
1481
+ .ds-atom-toast[data-dismissing="true"] {
1482
+ animation: ds-atom-toast-slideout 0.2s ease-out forwards;
1483
+ }
1484
+ .ds-atom-toast-icon {
1485
+ display: inline-flex;
1486
+ align-items: center;
1487
+ justify-content: center;
1488
+ flex: 0 0 auto;
1489
+ }
1490
+ .ds-atom-toast-msg {
1491
+ flex: 1 1 auto;
1492
+ line-height: 1.45;
1493
+ min-width: 0;
1494
+ word-break: break-word;
1495
+ }
1496
+ .ds-atom-toast-close {
1497
+ flex: 0 0 auto;
1498
+ display: inline-flex;
1499
+ align-items: center;
1500
+ justify-content: center;
1501
+ width: 22px;
1502
+ height: 22px;
1503
+ background: transparent;
1504
+ border: 0;
1505
+ color: var(--ink-3);
1506
+ cursor: pointer;
1507
+ border-radius: 4px;
1508
+ padding: 0;
1509
+ transition: background-color 0.12s, color 0.12s;
1510
+ }
1511
+ .ds-atom-toast-close:hover {
1512
+ background: rgba(0, 0, 0, 0.05);
1513
+ color: var(--ink);
1514
+ }
1515
+ .ds-atom-toast-close:focus-visible {
1516
+ outline: 2px solid var(--amber-d);
1517
+ outline-offset: 2px;
1518
+ }
1519
+ /* Tone-keyed bg + border + icon-color (sibling-CSS, mirrors Card data-variant). */
1520
+ .ds-atom-toast[data-tone="success"] {
1521
+ background: rgba(74, 222, 128, 0.1);
1522
+ border-color: var(--green);
1523
+ }
1524
+ .ds-atom-toast[data-tone="success"] .ds-atom-toast-icon {
1525
+ color: var(--green);
1526
+ }
1527
+ .ds-atom-toast[data-tone="error"] {
1528
+ background: rgba(239, 68, 68, 0.1);
1529
+ border-color: var(--red);
1530
+ }
1531
+ .ds-atom-toast[data-tone="error"] .ds-atom-toast-icon {
1532
+ color: var(--red);
1533
+ }
1534
+ .ds-atom-toast[data-tone="warning"] {
1535
+ background: var(--amber-l);
1536
+ border-color: var(--amber-d);
1537
+ }
1538
+ .ds-atom-toast[data-tone="warning"] .ds-atom-toast-icon {
1539
+ color: var(--amber-d);
1540
+ }
1541
+ /* Warning text pinned dark - amber-l (#fef3c7) is light so --ink reads correctly. */
1542
+ .ds-atom-toast[data-tone="warning"] .ds-atom-toast-msg {
1543
+ color: #292524;
1544
+ }
1545
+ .ds-atom-toast[data-tone="info"] {
1546
+ background: rgba(94, 184, 251, 0.1);
1547
+ border-color: var(--blue);
1548
+ }
1549
+ .ds-atom-toast[data-tone="info"] .ds-atom-toast-icon {
1550
+ color: var(--blue);
1551
+ }
1552
+ /* Dark mode: lift saturation 0.10 → 0.16 so tone bgs read on cream-2 surfaces. */
1553
+ .dark .ds-atom-toast[data-tone="success"] {
1554
+ background: rgba(74, 222, 128, 0.16);
1555
+ }
1556
+ .dark .ds-atom-toast[data-tone="error"] {
1557
+ background: rgba(239, 68, 68, 0.16);
1558
+ }
1559
+ .dark .ds-atom-toast[data-tone="info"] {
1560
+ background: rgba(94, 184, 251, 0.16);
1561
+ }
1562
+ /* Warning: swap amber-l for low-alpha amber so dark --ink text is readable. */
1563
+ .dark .ds-atom-toast[data-tone="warning"] {
1564
+ background: rgba(245, 158, 11, 0.15);
1565
+ border-color: #fbbf24;
1566
+ }
1567
+ .dark .ds-atom-toast[data-tone="warning"] .ds-atom-toast-msg {
1568
+ color: var(--ink);
1569
+ }
1570
+ .dark .ds-atom-toast[data-tone="warning"] .ds-atom-toast-icon {
1571
+ color: #fbbf24;
1572
+ }
1573
+ @keyframes ds-atom-toast-slidein {
1574
+ from {
1575
+ transform: translateX(110%);
1576
+ opacity: 0;
1577
+ }
1578
+ to {
1579
+ transform: translateX(0);
1580
+ opacity: 1;
1581
+ }
1582
+ }
1583
+ @keyframes ds-atom-toast-slideout {
1584
+ from {
1585
+ transform: translateX(0);
1586
+ opacity: 1;
1587
+ }
1588
+ to {
1589
+ transform: translateX(110%);
1590
+ opacity: 0;
1591
+ }
1592
+ }
1593
+
1594
+ /* ─── DS atom: InlineConfirm ────────────────────────────────────────
1595
+ Render-prop trigger replacement: idle = consumer's trigger; pending =
1596
+ inline prompt row [text] [No] [Yes]. Same container - zero layout
1597
+ shift. (DS-45, D-430) */
1598
+ .ds-atom-confirm {
1599
+ display: inline-flex;
1600
+ align-items: center;
1601
+ gap: var(--space-2);
1602
+ font-family: var(--font);
1603
+ }
1604
+ .ds-atom-confirm-text {
1605
+ font-size: 12.5px;
1606
+ color: var(--ink);
1607
+ line-height: 1.3;
1608
+ }
1609
+
1610
+ /* ─── DS atom: EmptyState ───────────────────────────────────────────
1611
+ Centered display for no-data/no-results/first-run states.
1612
+ Structured slots: icon + title + description + children-as-CTA.
1613
+ Source: design-handoff/design-system/ds-emptystates.jsx. (DS-44, D-421) */
1614
+ .ds-atom-empty {
1615
+ display: flex;
1616
+ flex-direction: column;
1617
+ align-items: center;
1618
+ text-align: center;
1619
+ gap: var(--space-3);
1620
+ padding: var(--space-8);
1621
+ box-sizing: border-box;
1622
+ }
1623
+ .ds-atom-empty-icon {
1624
+ display: inline-flex;
1625
+ align-items: center;
1626
+ justify-content: center;
1627
+ color: var(--ink-3);
1628
+ flex: 0 0 auto;
1629
+ }
1630
+ .ds-atom-empty-title {
1631
+ font-family: var(--display);
1632
+ font-weight: 600;
1633
+ font-size: 16px;
1634
+ color: var(--ink);
1635
+ max-width: 360px;
1636
+ line-height: 1.3;
1637
+ }
1638
+ .ds-atom-empty-desc {
1639
+ font-family: var(--font);
1640
+ font-weight: 400;
1641
+ font-size: 13px;
1642
+ color: var(--ink-3);
1643
+ max-width: 360px;
1644
+ line-height: 1.5;
1645
+ }
1646
+ .ds-atom-empty-actions {
1647
+ display: inline-flex;
1648
+ align-items: center;
1649
+ gap: var(--space-2);
1650
+ flex-wrap: wrap;
1651
+ justify-content: center;
1652
+ margin-top: var(--space-1);
1653
+ }
1654
+
1655
+ /* ─── DS atom: CopyToClipboard ────────────────────────────────────────
1656
+ Mono value + Copy↔Check swap (DS-55, D-531). NO color hex hardcodes. */
1657
+ .ds-atom-copy {
1658
+ display: inline-flex;
1659
+ align-items: center;
1660
+ gap: 8px;
1661
+ background: var(--cream);
1662
+ border: 1px solid var(--rule);
1663
+ border-radius: 8px;
1664
+ padding: 6px 10px;
1665
+ cursor: pointer;
1666
+ font-family: var(--mono);
1667
+ font-size: 12px;
1668
+ color: var(--ink);
1669
+ transition: background 0.15s, border-color 0.15s, color 0.15s;
1670
+ }
1671
+ .ds-atom-copy:hover {
1672
+ background: var(--cream-2);
1673
+ }
1674
+ .ds-atom-copy:focus-visible {
1675
+ outline: 2px solid var(--amber);
1676
+ outline-offset: 2px;
1677
+ }
1678
+ /* Copied state - green border + subtle tint so the whole button communicates success */
1679
+ .ds-atom-copy[data-state="copied"] {
1680
+ border-color: var(--green);
1681
+ background: rgba(74, 222, 128, 0.08);
1682
+ }
1683
+ .ds-atom-copy-value {
1684
+ font-family: var(--mono);
1685
+ font-size: 12px;
1686
+ color: inherit;
1687
+ }
1688
+ .ds-atom-copy-icon {
1689
+ color: var(--ink-2);
1690
+ flex-shrink: 0;
1691
+ transition: color 0.15s;
1692
+ }
1693
+ .ds-atom-copy-icon-check {
1694
+ color: var(--green);
1695
+ animation: ds-atom-copy-pop 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
1696
+ }
1697
+ @keyframes ds-atom-copy-pop {
1698
+ from {
1699
+ transform: scale(0.6);
1700
+ opacity: 0;
1701
+ }
1702
+ to {
1703
+ transform: scale(1);
1704
+ opacity: 1;
1705
+ }
1706
+ }
1707
+ .dark .ds-atom-copy[data-state="copied"] {
1708
+ border-color: var(--green);
1709
+ background: rgba(74, 222, 128, 0.12);
1710
+ }
1711
+
1712
+ /* ─── DS atom: DSDropdown ─────────────────────────────────────────────
1713
+ Shared dropdown panel chrome consumed by Select/MultiSelect/Autocomplete.
1714
+ The TSX class .ds-atom-dropdown is set inline by DSDropdown.tsx; this
1715
+ block provides bg/border/shadow/scroll. (D-500 internal infra.) */
1716
+ .ds-atom-dropdown {
1717
+ background: var(--cream-2);
1718
+ border: 1px solid var(--rule);
1719
+ border-radius: 8px;
1720
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
1721
+ }
1722
+
1723
+ /* ─── DS atom: DatePicker ──────────────────────────────────────────────
1724
+ Calendar primitive (DS-53). 7×6 grid, 34×34 cells, mono headers.
1725
+ Source: design-handoff/design-system/ds-pickers.jsx. */
1726
+ .ds-atom-datepicker {
1727
+ display: inline-block;
1728
+ background: var(--cream-2);
1729
+ border: 1px solid var(--rule);
1730
+ border-radius: var(--radius-lg);
1731
+ padding: 12px;
1732
+ font-family: var(--font);
1733
+ }
1734
+ .ds-atom-datepicker-header {
1735
+ display: flex;
1736
+ align-items: center;
1737
+ justify-content: space-between;
1738
+ margin-bottom: 8px;
1739
+ }
1740
+ .ds-atom-datepicker-label {
1741
+ font-family: var(--display);
1742
+ font-weight: 700;
1743
+ font-size: 13px;
1744
+ color: var(--ink);
1745
+ }
1746
+ .ds-atom-datepicker-nav {
1747
+ background: transparent;
1748
+ border: 1px solid var(--rule);
1749
+ border-radius: 6px;
1750
+ width: 24px;
1751
+ height: 24px;
1752
+ display: inline-flex;
1753
+ align-items: center;
1754
+ justify-content: center;
1755
+ cursor: pointer;
1756
+ color: var(--ink-2);
1757
+ }
1758
+ .ds-atom-datepicker-nav:hover {
1759
+ background: var(--cream);
1760
+ }
1761
+ .ds-atom-datepicker-weekdays {
1762
+ display: grid;
1763
+ grid-template-columns: repeat(7, 34px);
1764
+ gap: 0;
1765
+ margin-bottom: 4px;
1766
+ }
1767
+ .ds-atom-datepicker-weekday {
1768
+ font-family: var(--mono);
1769
+ font-size: 9.5px;
1770
+ letter-spacing: 0.08em;
1771
+ text-transform: uppercase;
1772
+ text-align: center;
1773
+ color: var(--ink-3);
1774
+ height: 20px;
1775
+ display: flex;
1776
+ align-items: center;
1777
+ justify-content: center;
1778
+ }
1779
+ .ds-atom-datepicker-grid {
1780
+ display: grid;
1781
+ grid-template-columns: repeat(7, 34px);
1782
+ grid-template-rows: repeat(6, 34px);
1783
+ gap: 0;
1784
+ }
1785
+ .ds-atom-datepicker-cell {
1786
+ width: 34px;
1787
+ height: 34px;
1788
+ background: transparent;
1789
+ border: none;
1790
+ cursor: pointer;
1791
+ border-radius: 6px;
1792
+ font-size: 12.5px;
1793
+ color: var(--ink);
1794
+ position: relative;
1795
+ display: flex;
1796
+ align-items: center;
1797
+ justify-content: center;
1798
+ font-family: var(--font);
1799
+ }
1800
+ .ds-atom-datepicker-cell:hover:not(:disabled) {
1801
+ background: var(--cream);
1802
+ }
1803
+ .ds-atom-datepicker-cell.is-out {
1804
+ color: var(--ink-3);
1805
+ }
1806
+ .ds-atom-datepicker-cell.is-today {
1807
+ font-weight: 700;
1808
+ }
1809
+ .ds-atom-datepicker-cell.is-today::after {
1810
+ content: "";
1811
+ position: absolute;
1812
+ top: 4px;
1813
+ right: 4px;
1814
+ width: 4px;
1815
+ height: 4px;
1816
+ border-radius: 50%;
1817
+ background: var(--amber);
1818
+ }
1819
+ .ds-atom-datepicker-cell.is-selected {
1820
+ background: var(--amber);
1821
+ /* Always dark ink on amber bg - handoff invariant; --ink would flip to
1822
+ cream in dark mode and lose contrast against the amber surface. */
1823
+ color: #1c1917;
1824
+ border-radius: 6px;
1825
+ font-weight: 600;
1826
+ }
1827
+ .ds-atom-datepicker-cell.is-in-range {
1828
+ background: var(--amber-l);
1829
+ border-radius: 0;
1830
+ }
1831
+ /* v0.5.3 - half-cell light-amber bg behind start/end pills extends the
1832
+ in-range bg under the rounded selected pill, eliminating the notch
1833
+ artifact at range endpoints. Applies only on real ranges (start !== end);
1834
+ 1-day ranges render as standalone selected. */
1835
+ .ds-atom-datepicker-cell.is-range-start,
1836
+ .ds-atom-datepicker-cell.is-range-end {
1837
+ position: relative;
1838
+ }
1839
+ .ds-atom-datepicker-cell.is-range-start::before {
1840
+ content: "";
1841
+ position: absolute;
1842
+ top: 0;
1843
+ bottom: 0;
1844
+ right: 0;
1845
+ width: 50%;
1846
+ background: var(--amber-l);
1847
+ z-index: -1;
1848
+ }
1849
+ .ds-atom-datepicker-cell.is-range-end::before {
1850
+ content: "";
1851
+ position: absolute;
1852
+ top: 0;
1853
+ bottom: 0;
1854
+ left: 0;
1855
+ width: 50%;
1856
+ background: var(--amber-l);
1857
+ z-index: -1;
1858
+ }
1859
+ /* v0.5.5 - hover state preservation for cells with state modifiers.
1860
+ Without these explicit overrides, the generic .ds-atom-datepicker-cell:hover
1861
+ rule wins on source order (equal specificity) and destroys the amber pill,
1862
+ in-range bg, and v0.5.3 half-cell pseudo-elements. Each rule preserves the
1863
+ state visual + adds a subtle hover feedback (filter brightness). */
1864
+ .ds-atom-datepicker-cell.is-selected:hover:not(:disabled) {
1865
+ background: var(--amber);
1866
+ filter: brightness(0.92);
1867
+ }
1868
+ .ds-atom-datepicker-cell.is-in-range:hover:not(:disabled) {
1869
+ background: var(--amber-l);
1870
+ filter: brightness(0.97);
1871
+ }
1872
+ /* No filter here - filter creates a stacking context that makes z-index:-1
1873
+ ::before render above the cell background, causing a half-cell split.
1874
+ Use explicit slightly-darker amber instead. */
1875
+ .ds-atom-datepicker-cell.is-range-start:hover:not(:disabled),
1876
+ .ds-atom-datepicker-cell.is-range-end:hover:not(:disabled) {
1877
+ background: #d97706;
1878
+ }
1879
+ /* Today cell hover (only when not also selected/in-range/endpoint) - preserve
1880
+ amber dot indicator (rendered via ::after); use amber-l wash for hover feedback. */
1881
+ .ds-atom-datepicker-cell.is-today:not(.is-selected):not(.is-in-range):not(.is-range-start):not(
1882
+ .is-range-end
1883
+ ):hover:not(:disabled) {
1884
+ background: var(--amber-l);
1885
+ }
1886
+ .ds-atom-datepicker-cell.is-disabled {
1887
+ opacity: 0.45;
1888
+ cursor: not-allowed;
1889
+ }
1890
+ .ds-atom-datepicker-event-dot {
1891
+ position: absolute;
1892
+ bottom: 4px;
1893
+ left: 50%;
1894
+ transform: translateX(-50%);
1895
+ width: 3px;
1896
+ height: 3px;
1897
+ border-radius: 50%;
1898
+ background: var(--ink-3);
1899
+ }
1900
+ .ds-atom-datepicker-cell.is-selected .ds-atom-datepicker-event-dot {
1901
+ background: var(--ink);
1902
+ }
1903
+ /* v0.5.1 patch - full-width grid layout (HH | : | MM | AM/PM toggle).
1904
+ AM/PM is ALWAYS rendered when showTime=true (no locale gating). */
1905
+ .ds-atom-datepicker-time {
1906
+ display: flex;
1907
+ align-items: center;
1908
+ gap: 6px;
1909
+ margin-top: 12px;
1910
+ padding-top: 12px;
1911
+ border-top: 1px solid var(--rule);
1912
+ }
1913
+ .ds-atom-datepicker-time input {
1914
+ flex: 1;
1915
+ min-width: 0;
1916
+ width: 0; /* flex overrides; width:0 + flex:1 forces equal share */
1917
+ border: 1px solid var(--rule);
1918
+ border-radius: 6px;
1919
+ padding: 6px 8px;
1920
+ font-family: var(--mono);
1921
+ font-size: 14px;
1922
+ font-weight: 600;
1923
+ text-align: center;
1924
+ background: var(--cream-2);
1925
+ color: var(--ink);
1926
+ outline: none;
1927
+ }
1928
+ .ds-atom-datepicker-time input:focus {
1929
+ border-color: var(--amber);
1930
+ }
1931
+ .ds-atom-datepicker-time-sep {
1932
+ font-family: var(--mono);
1933
+ font-size: 14px;
1934
+ font-weight: 700;
1935
+ color: var(--ink-2);
1936
+ flex-shrink: 0;
1937
+ }
1938
+
1939
+ /* Dark-mode overrides (v0.5.1 patch) - most tokens auto-flip via :root.dark
1940
+ in tokens.css; the entries below are the ones that don't have a dark-mode
1941
+ value baked into the token (--amber-l) or need surface-specific tuning
1942
+ (cell hover, in-range bg, today dot visibility, time inputs). */
1943
+ .dark .ds-atom-datepicker {
1944
+ background: rgba(255, 255, 255, 0.04);
1945
+ border-color: rgba(255, 255, 255, 0.12);
1946
+ }
1947
+ .dark .ds-atom-datepicker-cell:hover:not(:disabled) {
1948
+ background: rgba(255, 255, 255, 0.08);
1949
+ }
1950
+ .dark .ds-atom-datepicker-cell.is-in-range {
1951
+ /* var(--amber-l) is light cream-yellow; in dark mode use a translucent
1952
+ amber wash so the between-state remains legible against dark bg. */
1953
+ background: rgba(245, 158, 11, 0.18);
1954
+ }
1955
+ /* v0.5.6 - dark-mode state-preserving hover rules. The light-mode v0.5.5
1956
+ hover rules have specificity 0,4,0 (e.g. .is-range-end:hover:not(:disabled)),
1957
+ but the existing .dark .ds-atom-datepicker-cell:hover:not(:disabled)
1958
+ rule is 0,4,1 (the .dark ancestor adds a class). In dark mode the
1959
+ .dark plain-hover wins, blowing away the amber pill / brown range bg
1960
+ on hover. These :root.dark.is-state:hover rules at 0,5,1 win cleanly. */
1961
+ .dark .ds-atom-datepicker-cell.is-selected:hover:not(:disabled) {
1962
+ /* Keep amber pill in dark mode; brightness lift for hover feedback. */
1963
+ background: var(--amber);
1964
+ filter: brightness(1.08);
1965
+ }
1966
+ .dark .ds-atom-datepicker-cell.is-in-range:hover:not(:disabled) {
1967
+ /* Keep translucent-amber in-range bg in dark mode; subtle lift. */
1968
+ background: rgba(245, 158, 11, 0.18);
1969
+ filter: brightness(1.08);
1970
+ }
1971
+ .dark .ds-atom-datepicker-cell.is-range-start:hover:not(:disabled),
1972
+ .dark .ds-atom-datepicker-cell.is-range-end:hover:not(:disabled) {
1973
+ /* Same fix: no filter to avoid stacking-context ::before bleed. */
1974
+ background: #fbbf24;
1975
+ }
1976
+ .dark
1977
+ .ds-atom-datepicker-cell.is-today:not(.is-selected):not(.is-in-range):not(.is-range-start):not(
1978
+ .is-range-end
1979
+ ):hover:not(:disabled) {
1980
+ /* Today cell hover (when not also a range cell): keep light-amber wash. */
1981
+ background: var(--amber-l);
1982
+ }
1983
+ .dark .ds-atom-datepicker-cell.is-today::after {
1984
+ /* Amber dot already auto-flips, but bump opacity for contrast on dark surface. */
1985
+ background: var(--amber);
1986
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2);
1987
+ }
1988
+ .dark .ds-atom-datepicker-nav {
1989
+ border-color: rgba(255, 255, 255, 0.12);
1990
+ color: var(--ink-2);
1991
+ }
1992
+ .dark .ds-atom-datepicker-nav:hover {
1993
+ background: rgba(255, 255, 255, 0.08);
1994
+ }
1995
+ .dark .ds-atom-datepicker-time input {
1996
+ background: rgba(255, 255, 255, 0.06);
1997
+ border-color: rgba(255, 255, 255, 0.12);
1998
+ color: var(--ink);
1999
+ }
2000
+
2001
+ /* ─── DS atom: SplitButton ────────────────────────────────────────────
2002
+ Primary face + chevron divider + Popover menu (DS-56, D-530). Mirrors
2003
+ Button variant + size styling via data-variant + data-size selectors.
2004
+ The chevron menu's <div role="menu"> is portaled by Popover so it
2005
+ inherits .ds-atom-popover chrome; .ds-atom-split-menu only tunes the
2006
+ inner stack layout. */
2007
+ .ds-atom-split {
2008
+ display: inline-flex;
2009
+ align-items: stretch;
2010
+ border-radius: 8px;
2011
+ overflow: hidden;
2012
+ border: 1px solid var(--rule);
2013
+ /* v0.5.5 - defend against parent flex containers with align-items: stretch
2014
+ forcing the inline-flex container to fill cross-axis. fit-content keeps
2015
+ the SplitButton at its natural button-row width regardless of parent. */
2016
+ width: fit-content;
2017
+ max-width: 100%;
2018
+ }
2019
+ .ds-atom-split-primary,
2020
+ .ds-atom-split-chevron {
2021
+ background: var(--surf-1);
2022
+ border: none;
2023
+ cursor: pointer;
2024
+ font-family: var(--font);
2025
+ color: var(--ink);
2026
+ display: inline-flex;
2027
+ align-items: center;
2028
+ gap: 6px;
2029
+ padding: 0 12px;
2030
+ }
2031
+ .ds-atom-split-primary[data-size="sm"],
2032
+ .ds-atom-split-chevron[data-size="sm"] {
2033
+ height: 28px;
2034
+ font-size: 12px;
2035
+ }
2036
+ .ds-atom-split-primary[data-size="md"],
2037
+ .ds-atom-split-chevron[data-size="md"] {
2038
+ height: 36px;
2039
+ font-size: 13px;
2040
+ }
2041
+ .ds-atom-split-primary[data-size="lg"],
2042
+ .ds-atom-split-chevron[data-size="lg"] {
2043
+ height: 44px;
2044
+ font-size: 14px;
2045
+ }
2046
+ /* v0.5.4 - chevron button is icon-only (14px ChevronDown); tighter
2047
+ horizontal padding override so it renders square-ish (~30px wide)
2048
+ instead of inheriting the primary face's 12px gutter (~38px wide).
2049
+ Must come after the shared `.ds-atom-split-primary, .ds-atom-split-chevron`
2050
+ rule above. */
2051
+ .ds-atom-split-chevron {
2052
+ border-left: 1px solid var(--rule);
2053
+ padding: 0 8px;
2054
+ }
2055
+ .ds-atom-split-primary[data-variant="primary"],
2056
+ .ds-atom-split-chevron[data-variant="primary"] {
2057
+ background: var(--amber);
2058
+ color: #1c1917;
2059
+ font-weight: 600;
2060
+ }
2061
+ .ds-atom-split-primary[data-variant="primary"]:hover,
2062
+ .ds-atom-split-chevron[data-variant="primary"]:hover {
2063
+ background: var(--amber-d);
2064
+ }
2065
+ .ds-atom-split[data-variant="primary"] {
2066
+ border-color: var(--amber-d);
2067
+ }
2068
+ .ds-atom-split-chevron[data-variant="primary"] {
2069
+ border-left-color: rgba(28, 25, 23, 0.2);
2070
+ }
2071
+ .ds-atom-split-primary[data-variant="secondary"]:hover,
2072
+ .ds-atom-split-chevron[data-variant="secondary"]:hover {
2073
+ background: var(--cream);
2074
+ }
2075
+ /* v0.5.1 patch - ghost + danger variants on the primary face/chevron + outer wrapper. */
2076
+ .ds-atom-split-primary[data-variant="ghost"],
2077
+ .ds-atom-split-chevron[data-variant="ghost"] {
2078
+ background: transparent;
2079
+ color: var(--ink-2);
2080
+ }
2081
+ .ds-atom-split-primary[data-variant="ghost"]:hover,
2082
+ .ds-atom-split-chevron[data-variant="ghost"]:hover {
2083
+ background: var(--cream);
2084
+ }
2085
+ .ds-atom-split[data-variant="ghost"] {
2086
+ border-color: var(--rule);
2087
+ }
2088
+ .ds-atom-split-primary[data-variant="danger"],
2089
+ .ds-atom-split-chevron[data-variant="danger"] {
2090
+ background: #dc2626;
2091
+ color: #fff;
2092
+ font-weight: 600;
2093
+ }
2094
+ .ds-atom-split-primary[data-variant="danger"]:hover,
2095
+ .ds-atom-split-chevron[data-variant="danger"]:hover {
2096
+ background: #b91c1c;
2097
+ }
2098
+ .ds-atom-split[data-variant="danger"] {
2099
+ border-color: #b91c1c;
2100
+ }
2101
+ .ds-atom-split-chevron[data-variant="danger"] {
2102
+ border-left-color: rgba(255, 255, 255, 0.3);
2103
+ }
2104
+ .ds-atom-split-icon {
2105
+ display: inline-flex;
2106
+ align-items: center;
2107
+ }
2108
+ .ds-atom-split-menu {
2109
+ display: flex;
2110
+ flex-direction: column;
2111
+ min-width: 180px;
2112
+ padding: 4px;
2113
+ }
2114
+ .ds-atom-split-menuitem {
2115
+ display: inline-flex;
2116
+ align-items: center;
2117
+ gap: 8px;
2118
+ width: 100%;
2119
+ background: transparent;
2120
+ border: none;
2121
+ cursor: pointer;
2122
+ padding: 7px 10px;
2123
+ font-family: var(--font);
2124
+ font-size: 13px;
2125
+ color: var(--ink);
2126
+ border-radius: 6px;
2127
+ text-align: left;
2128
+ position: relative;
2129
+ }
2130
+ /* Hover: slightly darker than the cream-2 panel background */
2131
+ .ds-atom-split-menuitem:hover {
2132
+ background: var(--cream-3);
2133
+ }
2134
+ /* Current item: checkmark via ::after, bold text - no background box */
2135
+ .ds-atom-split-menuitem.is-current {
2136
+ font-weight: 600;
2137
+ }
2138
+ .ds-atom-split-menuitem.is-current::after {
2139
+ content: "✓";
2140
+ margin-left: auto;
2141
+ font-size: 11px;
2142
+ color: var(--ink-3);
2143
+ flex-shrink: 0;
2144
+ }
2145
+ /* Variant coloring - text only, no border-left (avoids corner clipping) */
2146
+ .ds-atom-split-menuitem[data-action-variant="danger"] {
2147
+ color: var(--red);
2148
+ }
2149
+ /* Semantic tone - same text-only approach */
2150
+ .ds-atom-split-menuitem[data-tone="danger"] {
2151
+ color: var(--red);
2152
+ }
2153
+ .ds-atom-split-menuitem[data-tone="warning"] {
2154
+ color: var(--amber-d);
2155
+ }
2156
+ .ds-atom-split-menuitem[data-tone="success"] {
2157
+ color: var(--green);
2158
+ }
2159
+ /* Dark mode menu */
2160
+ .dark .ds-atom-split-menuitem:hover {
2161
+ background: var(--cream-3);
2162
+ }
2163
+ .dark .ds-atom-split-menuitem.is-current::after {
2164
+ color: var(--ink-4);
2165
+ }
2166
+ .dark .ds-atom-split-primary[data-variant="secondary"],
2167
+ .dark .ds-atom-split-chevron[data-variant="secondary"] {
2168
+ color: var(--ink);
2169
+ }
2170
+ .dark .ds-atom-split-primary[data-variant="secondary"]:hover,
2171
+ .dark .ds-atom-split-chevron[data-variant="secondary"]:hover {
2172
+ background: var(--cream-2);
2173
+ }
2174
+ .dark .ds-atom-split-primary[data-variant="ghost"],
2175
+ .dark .ds-atom-split-chevron[data-variant="ghost"] {
2176
+ color: var(--ink-2);
2177
+ }
2178
+ .dark .ds-atom-split-primary[data-variant="ghost"]:hover,
2179
+ .dark .ds-atom-split-chevron[data-variant="ghost"]:hover {
2180
+ background: var(--cream-2);
2181
+ }
2182
+
2183
+ /* ─── DS atom: Autocomplete ───────────────────────────────────────────
2184
+ Generic combobox primitive (DS-52). Native <input> trigger + recents
2185
+ header + create-as-new button. Reuses .ds-atom-dropdown chrome from
2186
+ 16-01 - this block only ships input + list + recents + create styling. */
2187
+ .ds-atom-autocomplete {
2188
+ width: 100%;
2189
+ min-width: 220px;
2190
+ height: 36px;
2191
+ padding: 0 10px;
2192
+ background: var(--surf-1);
2193
+ border: 1px solid var(--rule);
2194
+ border-radius: 8px;
2195
+ font-family: var(--font);
2196
+ font-size: 13px;
2197
+ color: var(--ink);
2198
+ outline: none;
2199
+ box-sizing: border-box;
2200
+ }
2201
+ .ds-atom-autocomplete:focus {
2202
+ border-color: var(--amber);
2203
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.12);
2204
+ }
2205
+ .ds-atom-autocomplete::placeholder {
2206
+ color: var(--ink-3);
2207
+ }
2208
+ .dark .ds-atom-autocomplete {
2209
+ background: rgba(255, 255, 255, 0.06);
2210
+ color: var(--ink);
2211
+ border-color: rgba(255, 255, 255, 0.12);
2212
+ }
2213
+ .dark .ds-atom-autocomplete::placeholder {
2214
+ color: var(--ink-3);
2215
+ }
2216
+ .ds-atom-autocomplete-section-header {
2217
+ font-family: var(--mono);
2218
+ font-size: 9.5px;
2219
+ letter-spacing: 0.08em;
2220
+ text-transform: uppercase;
2221
+ color: var(--ink-3);
2222
+ padding: 8px 10px 4px;
2223
+ }
2224
+ .ds-atom-autocomplete-list {
2225
+ list-style: none;
2226
+ margin: 0;
2227
+ padding: 4px;
2228
+ }
2229
+ .ds-atom-autocomplete-option {
2230
+ display: flex;
2231
+ align-items: center;
2232
+ gap: 8px;
2233
+ padding: 6px 8px;
2234
+ border-radius: 6px;
2235
+ cursor: pointer;
2236
+ font-size: 13px;
2237
+ color: var(--ink);
2238
+ }
2239
+ .ds-atom-autocomplete-option.is-active {
2240
+ background: var(--cream);
2241
+ }
2242
+ .dark .ds-atom-autocomplete-option.is-active {
2243
+ background: rgba(255, 255, 255, 0.08);
2244
+ }
2245
+ .ds-atom-autocomplete-clock {
2246
+ color: var(--ink-3);
2247
+ flex-shrink: 0;
2248
+ }
2249
+ .ds-atom-autocomplete-create {
2250
+ width: 100%;
2251
+ background: transparent;
2252
+ border: none;
2253
+ cursor: pointer;
2254
+ padding: 8px 10px;
2255
+ border-radius: 6px;
2256
+ text-align: left;
2257
+ font-family: var(--font);
2258
+ font-size: 13px;
2259
+ color: var(--ink);
2260
+ }
2261
+ .ds-atom-autocomplete-create:hover {
2262
+ background: var(--cream);
2263
+ }
2264
+ .dark .ds-atom-autocomplete-create:hover {
2265
+ background: rgba(255, 255, 255, 0.08);
2266
+ }
2267
+ .ds-atom-autocomplete-empty {
2268
+ padding: 16px;
2269
+ text-align: center;
2270
+ color: var(--ink-3);
2271
+ font-size: 12px;
2272
+ }
2273
+
2274
+ /* ─── DS atom: Select ─────────────────────────────────────────────────
2275
+ Single-select trigger + listbox panel (DS-50). Composes DSDropdown,
2276
+ inheriting .ds-atom-dropdown chrome from 16-01 - this block adds only
2277
+ the trigger surface + per-option visuals + search/empty rows. */
2278
+ .ds-atom-select {
2279
+ display: inline-flex;
2280
+ align-items: center;
2281
+ justify-content: space-between;
2282
+ gap: 8px;
2283
+ width: 100%;
2284
+ min-width: 180px;
2285
+ height: 36px;
2286
+ padding: 0 10px;
2287
+ background: var(--surf-1);
2288
+ border: 1px solid var(--rule);
2289
+ border-radius: 8px;
2290
+ font-family: var(--font);
2291
+ font-size: 13px;
2292
+ color: var(--ink);
2293
+ cursor: pointer;
2294
+ text-align: left;
2295
+ }
2296
+ .ds-atom-select:focus-visible {
2297
+ outline: 2px solid var(--amber);
2298
+ outline-offset: 2px;
2299
+ }
2300
+ .ds-atom-select[data-state="open"] {
2301
+ border-color: var(--amber);
2302
+ }
2303
+ .ds-atom-select:disabled {
2304
+ opacity: 0.5;
2305
+ cursor: not-allowed;
2306
+ }
2307
+ .ds-atom-select-value {
2308
+ display: inline-flex;
2309
+ align-items: center;
2310
+ gap: 6px;
2311
+ overflow: hidden;
2312
+ text-overflow: ellipsis;
2313
+ white-space: nowrap;
2314
+ }
2315
+ .ds-atom-select-placeholder {
2316
+ color: var(--ink-3);
2317
+ }
2318
+ .ds-atom-select-dot {
2319
+ display: inline-block;
2320
+ width: 8px;
2321
+ height: 8px;
2322
+ border-radius: 50%;
2323
+ flex-shrink: 0;
2324
+ }
2325
+ .ds-atom-select-chevron {
2326
+ transition: transform 0.15s;
2327
+ color: var(--ink-2);
2328
+ }
2329
+ .ds-atom-select-chevron.is-open {
2330
+ transform: rotate(180deg);
2331
+ }
2332
+ .ds-atom-select-search {
2333
+ padding: 6px;
2334
+ border-bottom: 1px solid var(--rule);
2335
+ background: var(--cream-2);
2336
+ position: sticky;
2337
+ top: 0;
2338
+ box-sizing: border-box;
2339
+ }
2340
+ .ds-atom-select-search input {
2341
+ display: block;
2342
+ width: 100%;
2343
+ box-sizing: border-box;
2344
+ border: 1px solid var(--rule);
2345
+ border-radius: 6px;
2346
+ padding: 6px 8px;
2347
+ font-family: var(--font);
2348
+ font-size: 13px;
2349
+ background: var(--cream-2);
2350
+ color: var(--ink);
2351
+ outline: none;
2352
+ }
2353
+ .ds-atom-select-search input:focus {
2354
+ border-color: var(--amber);
2355
+ }
2356
+ .ds-atom-select-list {
2357
+ list-style: none;
2358
+ margin: 0;
2359
+ padding: 4px;
2360
+ background: var(--cream-2);
2361
+ }
2362
+ .ds-atom-select-option {
2363
+ display: flex;
2364
+ align-items: center;
2365
+ gap: 8px;
2366
+ padding: 6px 8px;
2367
+ border-radius: 6px;
2368
+ cursor: pointer;
2369
+ font-size: 13px;
2370
+ color: var(--ink);
2371
+ }
2372
+ .ds-atom-select-option.is-active {
2373
+ background: var(--cream);
2374
+ }
2375
+ .ds-atom-select-option.is-selected {
2376
+ font-weight: 600;
2377
+ }
2378
+ .ds-atom-select-option-label {
2379
+ flex: 1;
2380
+ }
2381
+ .ds-atom-select-check {
2382
+ color: var(--amber);
2383
+ }
2384
+ .ds-atom-select-empty {
2385
+ padding: 16px;
2386
+ text-align: center;
2387
+ color: var(--ink-3);
2388
+ font-size: 12px;
2389
+ background: var(--cream-2);
2390
+ }
2391
+ .dark .ds-atom-select {
2392
+ background: rgba(255, 255, 255, 0.06);
2393
+ border-color: rgba(255, 255, 255, 0.12);
2394
+ }
2395
+ .dark .ds-atom-select-option.is-active {
2396
+ background: rgba(255, 255, 255, 0.08);
2397
+ }
2398
+ .dark .ds-atom-select-search input {
2399
+ background: rgba(255, 255, 255, 0.06);
2400
+ border-color: rgba(255, 255, 255, 0.12);
2401
+ }
2402
+
2403
+ /* ─── DS atom: DateRangePicker ──────────────────────────────────────────
2404
+ Single-calendar range picker (DS-54). v0.5.1 patch: collapsed from the
2405
+ original 2-cal layout (D-512) to a single .ds-atom-datepicker per user
2406
+ feedback + handoff `ds-pickers.jsx`. Wrapper is a thin pass-through -
2407
+ the inner DatePicker owns its own surface chrome.
2408
+ Between-state cells (.ds-atom-datepicker-cell.is-in-range) ship via
2409
+ 16-05 DatePicker - NOT redefined here. */
2410
+ .ds-atom-daterangepicker {
2411
+ display: inline-block;
2412
+ font-family: var(--font);
2413
+ }
2414
+
2415
+ /* ─── DS atom: MultiSelect ────────────────────────────────────────────
2416
+ Multi-select trigger (chips-in-trigger D-520) + listbox panel with
2417
+ aria-multiselectable. Reuses .ds-atom-dropdown chrome from 16-01. */
2418
+ .ds-atom-multiselect {
2419
+ display: inline-flex;
2420
+ align-items: flex-start;
2421
+ gap: 6px;
2422
+ width: 100%;
2423
+ min-width: 220px;
2424
+ min-height: 36px;
2425
+ max-height: 108px;
2426
+ padding: 4px 10px;
2427
+ background: var(--surf-1);
2428
+ border: 1px solid var(--rule);
2429
+ border-radius: 8px;
2430
+ cursor: pointer;
2431
+ font-family: var(--font);
2432
+ font-size: 13px;
2433
+ color: var(--ink);
2434
+ text-align: left;
2435
+ overflow: hidden;
2436
+ }
2437
+ .ds-atom-multiselect[data-state="open"] {
2438
+ border-color: var(--amber);
2439
+ }
2440
+ .ds-atom-multiselect:focus-visible {
2441
+ outline: 2px solid var(--amber);
2442
+ outline-offset: 2px;
2443
+ }
2444
+ .ds-atom-multiselect:disabled {
2445
+ opacity: 0.5;
2446
+ cursor: not-allowed;
2447
+ }
2448
+ .ds-atom-multiselect-chips {
2449
+ display: flex;
2450
+ flex-wrap: wrap;
2451
+ gap: 4px;
2452
+ flex: 1;
2453
+ align-items: center;
2454
+ min-height: 26px;
2455
+ }
2456
+ .ds-atom-multiselect-placeholder {
2457
+ color: var(--ink-3);
2458
+ }
2459
+ .ds-atom-multiselect-chip {
2460
+ display: inline-flex;
2461
+ align-items: center;
2462
+ gap: 4px;
2463
+ padding: 2px 6px 2px 8px;
2464
+ background: var(--cream);
2465
+ border: 1px solid var(--rule);
2466
+ border-radius: 12px;
2467
+ font-size: 12px;
2468
+ color: var(--ink);
2469
+ }
2470
+ .ds-atom-multiselect-chip-more {
2471
+ background: var(--cream-2);
2472
+ border: 1px dashed var(--rule);
2473
+ cursor: pointer;
2474
+ padding: 2px 8px;
2475
+ font-family: var(--font);
2476
+ }
2477
+ .ds-atom-multiselect-chip-x {
2478
+ background: transparent;
2479
+ border: none;
2480
+ cursor: pointer;
2481
+ color: var(--ink-2);
2482
+ padding: 0 0 0 2px;
2483
+ display: inline-flex;
2484
+ align-items: center;
2485
+ }
2486
+ .ds-atom-multiselect-chip-x:hover {
2487
+ color: var(--ink);
2488
+ }
2489
+ .ds-atom-multiselect-chevron {
2490
+ transition: transform 0.15s;
2491
+ color: var(--ink-2);
2492
+ flex-shrink: 0;
2493
+ margin-top: 6px;
2494
+ }
2495
+ .ds-atom-multiselect-chevron.is-open {
2496
+ transform: rotate(180deg);
2497
+ }
2498
+ .ds-atom-multiselect-list {
2499
+ list-style: none;
2500
+ margin: 0;
2501
+ padding: 4px;
2502
+ }
2503
+ .ds-atom-multiselect-option {
2504
+ display: flex;
2505
+ align-items: center;
2506
+ gap: 8px;
2507
+ padding: 6px 8px;
2508
+ border-radius: 6px;
2509
+ cursor: pointer;
2510
+ font-size: 13px;
2511
+ color: var(--ink);
2512
+ }
2513
+ .ds-atom-multiselect-option.is-active {
2514
+ background: var(--cream);
2515
+ }
2516
+ .dark .ds-atom-multiselect-option.is-active {
2517
+ background: rgba(255, 255, 255, 0.08);
2518
+ }
2519
+ .ds-atom-multiselect-checkbox {
2520
+ width: 16px;
2521
+ height: 16px;
2522
+ border: 1.5px solid var(--rule);
2523
+ border-radius: 4px;
2524
+ display: inline-flex;
2525
+ align-items: center;
2526
+ justify-content: center;
2527
+ flex-shrink: 0;
2528
+ background: var(--surf-1);
2529
+ color: var(--ink);
2530
+ }
2531
+ .ds-atom-multiselect-checkbox.is-checked {
2532
+ background: var(--amber);
2533
+ border-color: var(--amber);
2534
+ }
2535
+ .ds-atom-multiselect-option-label {
2536
+ flex: 1;
2537
+ }
2538
+ .dark .ds-atom-multiselect {
2539
+ background: rgba(255, 255, 255, 0.06);
2540
+ color: var(--ink);
2541
+ border-color: rgba(255, 255, 255, 0.12);
2542
+ }
2543
+ .dark .ds-atom-multiselect-chip {
2544
+ background: rgba(255, 255, 255, 0.08);
2545
+ border-color: rgba(255, 255, 255, 0.12);
2546
+ }
2547
+ .dark .ds-atom-multiselect-chip-more {
2548
+ background: transparent;
2549
+ border-color: rgba(255, 255, 255, 0.18);
2550
+ }
2551
+ .ds-atom-multiselect-more-list {
2552
+ display: flex;
2553
+ flex-direction: column;
2554
+ gap: 2px;
2555
+ padding: 4px;
2556
+ min-width: 200px;
2557
+ }
2558
+ .ds-atom-multiselect-more-item {
2559
+ display: flex;
2560
+ justify-content: space-between;
2561
+ align-items: center;
2562
+ gap: 12px;
2563
+ padding: 6px 8px;
2564
+ font-size: 13px;
2565
+ color: var(--ink);
2566
+ }
2567
+ .ds-atom-multiselect-more-item button {
2568
+ background: transparent;
2569
+ border: none;
2570
+ cursor: pointer;
2571
+ color: var(--ink-2);
2572
+ display: inline-flex;
2573
+ align-items: center;
2574
+ padding: 2px;
2575
+ }
2576
+ .ds-atom-multiselect-more-item button:hover {
2577
+ color: var(--ink);
2578
+ }
2579
+
2580
+ /* ─── DS atom: SegmentedControl (DS-63) ─────────────────────────────────
2581
+ Pill-shaped radiogroup. Cream-2 wrapper, amber active option.
2582
+ Sizes via data-size; disabled state via data-disabled. */
2583
+ .ds-atom-segmented {
2584
+ display: inline-flex;
2585
+ align-items: stretch;
2586
+ gap: 2px;
2587
+ padding: 2px;
2588
+ background: var(--cream-2);
2589
+ border: 1px solid var(--rule);
2590
+ border-radius: 999px;
2591
+ }
2592
+ .ds-atom-segmented[data-disabled="true"] {
2593
+ opacity: 0.5;
2594
+ pointer-events: none;
2595
+ }
2596
+ .ds-atom-segmented-btn {
2597
+ appearance: none;
2598
+ background: transparent;
2599
+ border: 0;
2600
+ color: var(--ink-2);
2601
+ cursor: pointer;
2602
+ padding: 0 14px;
2603
+ border-radius: 999px;
2604
+ font-family: var(--font-body);
2605
+ font-weight: 500;
2606
+ transition: background-color 120ms ease, color 120ms ease;
2607
+ }
2608
+ .ds-atom-segmented-btn:hover:not([data-active]):not(:disabled) {
2609
+ color: var(--ink);
2610
+ }
2611
+ .ds-atom-segmented-btn:focus-visible {
2612
+ outline: 2px solid var(--amber);
2613
+ outline-offset: 2px;
2614
+ }
2615
+ .ds-atom-segmented-btn[data-active] {
2616
+ background: var(--amber);
2617
+ color: #000;
2618
+ }
2619
+ .ds-atom-segmented-btn:disabled {
2620
+ cursor: not-allowed;
2621
+ opacity: 0.5;
2622
+ }
2623
+ /* Sizes */
2624
+ .ds-atom-segmented[data-size="sm"] .ds-atom-segmented-btn {
2625
+ height: 28px;
2626
+ font-size: 12px;
2627
+ padding: 0 10px;
2628
+ }
2629
+ .ds-atom-segmented[data-size="md"] .ds-atom-segmented-btn {
2630
+ height: 32px;
2631
+ font-size: 13px;
2632
+ padding: 0 14px;
2633
+ }
2634
+ .ds-atom-segmented[data-size="lg"] .ds-atom-segmented-btn {
2635
+ height: 40px;
2636
+ font-size: 14px;
2637
+ padding: 0 18px;
2638
+ }
2639
+ /* Dark mode */
2640
+ .dark .ds-atom-segmented {
2641
+ background: var(--cream-2);
2642
+ border-color: var(--rule);
2643
+ }
2644
+ .dark .ds-atom-segmented-btn {
2645
+ color: var(--ink-2);
2646
+ }
2647
+ .dark .ds-atom-segmented-btn[data-active] {
2648
+ background: var(--amber);
2649
+ color: #000;
2650
+ }
2651
+
2652
+ /* ─── DS atom: Breadcrumbs (DS-69) ──────────────────────────────────────
2653
+ Hierarchical nav. Last item is current page (ink); others are ink-2
2654
+ links. ChevronRight separator. Truncates via DSDropdown when deep. */
2655
+ .ds-atom-breadcrumbs {
2656
+ font-family: var(--font-body);
2657
+ font-size: 13px;
2658
+ }
2659
+ .ds-atom-breadcrumbs-list {
2660
+ display: flex;
2661
+ align-items: center;
2662
+ flex-wrap: wrap;
2663
+ gap: 4px;
2664
+ list-style: none;
2665
+ margin: 0;
2666
+ padding: 0;
2667
+ }
2668
+ .ds-atom-breadcrumbs-li {
2669
+ display: inline-flex;
2670
+ align-items: center;
2671
+ gap: 4px;
2672
+ }
2673
+ .ds-atom-breadcrumbs-link {
2674
+ color: var(--ink-2);
2675
+ text-decoration: none;
2676
+ transition: color 100ms ease;
2677
+ }
2678
+ .ds-atom-breadcrumbs-link:hover {
2679
+ color: var(--ink);
2680
+ text-decoration: underline;
2681
+ }
2682
+ .ds-atom-breadcrumbs-current,
2683
+ .ds-atom-breadcrumbs-text {
2684
+ color: var(--ink);
2685
+ font-weight: 500;
2686
+ }
2687
+ .ds-atom-breadcrumbs-sep {
2688
+ color: var(--ink-3, var(--ink-2));
2689
+ flex-shrink: 0;
2690
+ }
2691
+ .ds-atom-breadcrumbs-more {
2692
+ appearance: none;
2693
+ background: transparent;
2694
+ border: 0;
2695
+ cursor: pointer;
2696
+ padding: 2px 6px;
2697
+ border-radius: 4px;
2698
+ color: var(--ink-2);
2699
+ display: inline-flex;
2700
+ align-items: center;
2701
+ }
2702
+ .ds-atom-breadcrumbs-more:hover {
2703
+ background: var(--surf-2);
2704
+ color: var(--ink);
2705
+ }
2706
+ .ds-atom-breadcrumbs-more:focus-visible {
2707
+ outline: 2px solid var(--amber);
2708
+ outline-offset: 2px;
2709
+ }
2710
+ .ds-atom-breadcrumbs-menu {
2711
+ list-style: none;
2712
+ margin: 0;
2713
+ padding: 4px;
2714
+ min-width: 160px;
2715
+ }
2716
+ .ds-atom-breadcrumbs-menuitem a,
2717
+ .ds-atom-breadcrumbs-menuitem button {
2718
+ display: block;
2719
+ width: 100%;
2720
+ padding: 6px 10px;
2721
+ color: var(--ink);
2722
+ text-decoration: none;
2723
+ background: transparent;
2724
+ border: 0;
2725
+ border-radius: 4px;
2726
+ text-align: left;
2727
+ cursor: pointer;
2728
+ font-family: inherit;
2729
+ font-size: inherit;
2730
+ }
2731
+ .ds-atom-breadcrumbs-menuitem a:hover,
2732
+ .ds-atom-breadcrumbs-menuitem button:hover {
2733
+ background: var(--surf-2);
2734
+ }
2735
+ /* Dark mode */
2736
+ .dark .ds-atom-breadcrumbs-link {
2737
+ color: var(--ink-2);
2738
+ }
2739
+ .dark .ds-atom-breadcrumbs-link:hover {
2740
+ color: var(--ink);
2741
+ }
2742
+ .dark .ds-atom-breadcrumbs-current,
2743
+ .dark .ds-atom-breadcrumbs-text {
2744
+ color: var(--ink);
2745
+ }
2746
+ .dark .ds-atom-breadcrumbs-more:hover {
2747
+ background: var(--surf-2);
2748
+ }
2749
+
2750
+ /* ─── DS atom: Timeline (DS-66) ─────────────────────────────────────────────
2751
+ Read-only event sequence. Horizontal (default) or vertical orientation.
2752
+ Dot + connector line via CSS ::after pseudo-elements (no extra DOM). */
2753
+ .ds-atom-timeline {
2754
+ list-style: none;
2755
+ margin: 0;
2756
+ padding: 0;
2757
+ display: flex;
2758
+ }
2759
+ .ds-atom-timeline[data-orientation="horizontal"] {
2760
+ flex-direction: row;
2761
+ align-items: flex-start;
2762
+ gap: 0;
2763
+ }
2764
+ .ds-atom-timeline[data-orientation="vertical"] {
2765
+ flex-direction: column;
2766
+ align-items: stretch;
2767
+ gap: 0;
2768
+ }
2769
+
2770
+ /* ── Horizontal event - column: dot → date → label → desc ──────────────── */
2771
+ .ds-atom-timeline-event {
2772
+ position: relative;
2773
+ flex: 1;
2774
+ min-width: 100px;
2775
+ display: flex;
2776
+ flex-direction: column;
2777
+ align-items: flex-start;
2778
+ gap: 6px;
2779
+ padding-right: 16px;
2780
+ }
2781
+
2782
+ /* ── Vertical event - CSS grid: dot | [date, label, desc] ──────────────── */
2783
+ .ds-atom-timeline[data-orientation="vertical"] .ds-atom-timeline-event {
2784
+ flex: none;
2785
+ width: 100%;
2786
+ display: grid;
2787
+ grid-template-columns: 24px 1fr;
2788
+ grid-template-rows: auto auto auto;
2789
+ column-gap: 12px;
2790
+ row-gap: 2px;
2791
+ padding-right: 0;
2792
+ padding-bottom: 28px;
2793
+ }
2794
+ .ds-atom-timeline[data-orientation="vertical"] .ds-atom-timeline-event:last-child {
2795
+ padding-bottom: 0;
2796
+ }
2797
+
2798
+ /* Dot positioning per orientation */
2799
+ .ds-atom-timeline-dot {
2800
+ width: 10px;
2801
+ height: 10px;
2802
+ border-radius: 50%;
2803
+ background: var(--amber);
2804
+ flex-shrink: 0;
2805
+ z-index: 1;
2806
+ margin-top: 3px; /* vertically centre against first-line text */
2807
+ }
2808
+ /* In vertical grid: dot sits in col 1, rows 1-3 */
2809
+ .ds-atom-timeline[data-orientation="vertical"] .ds-atom-timeline-dot {
2810
+ grid-column: 1;
2811
+ grid-row: 1;
2812
+ justify-self: center;
2813
+ margin-top: 4px;
2814
+ }
2815
+ /* In horizontal: dot is the first flex child, no special placement needed */
2816
+ .ds-atom-timeline[data-orientation="horizontal"] .ds-atom-timeline-dot {
2817
+ margin-top: 0;
2818
+ }
2819
+
2820
+ /* Connector - horizontal */
2821
+ .ds-atom-timeline[data-orientation="horizontal"] .ds-atom-timeline-event:not(:last-child)::after {
2822
+ content: "";
2823
+ position: absolute;
2824
+ top: 4px; /* dot centre (10px / 2 = 5px, minus 1px for line half-width) */
2825
+ left: 11px;
2826
+ right: 0;
2827
+ height: 2px;
2828
+ background: var(--rule);
2829
+ z-index: 0;
2830
+ }
2831
+ /* Connector - vertical */
2832
+ .ds-atom-timeline[data-orientation="vertical"] .ds-atom-timeline-event:not(:last-child)::after {
2833
+ content: "";
2834
+ position: absolute;
2835
+ top: 18px; /* below the dot (dot top: 4px + dot height: 10px + gap: 4px) */
2836
+ bottom: 4px;
2837
+ left: 11px; /* centre of 24px grid column */
2838
+ width: 2px;
2839
+ background: var(--rule);
2840
+ z-index: 0;
2841
+ }
2842
+
2843
+ /* Content typography */
2844
+ .ds-atom-timeline-date {
2845
+ font-family: var(--font-mono);
2846
+ font-size: 11px;
2847
+ color: var(--ink-3);
2848
+ text-transform: uppercase;
2849
+ letter-spacing: 0.05em;
2850
+ line-height: 1.4;
2851
+ }
2852
+ .ds-atom-timeline-label {
2853
+ font-family: var(--font-display);
2854
+ font-size: 14px;
2855
+ color: var(--ink);
2856
+ font-weight: 600;
2857
+ line-height: 1.3;
2858
+ }
2859
+ .ds-atom-timeline-desc {
2860
+ font-family: var(--font-body);
2861
+ font-size: 12px;
2862
+ color: var(--ink-2);
2863
+ line-height: 1.5;
2864
+ }
2865
+
2866
+ /* Vertical grid placement for content */
2867
+ .ds-atom-timeline[data-orientation="vertical"] .ds-atom-timeline-date {
2868
+ grid-column: 2;
2869
+ grid-row: 1;
2870
+ }
2871
+ .ds-atom-timeline[data-orientation="vertical"] .ds-atom-timeline-label {
2872
+ grid-column: 2;
2873
+ grid-row: 2;
2874
+ }
2875
+ .ds-atom-timeline[data-orientation="vertical"] .ds-atom-timeline-desc {
2876
+ grid-column: 2;
2877
+ grid-row: 3;
2878
+ }
2879
+
2880
+ /* Trigger button - same layout as its container */
2881
+ .ds-atom-timeline-trigger {
2882
+ appearance: none;
2883
+ background: transparent;
2884
+ border: 0;
2885
+ padding: 0;
2886
+ cursor: pointer;
2887
+ text-align: left;
2888
+ display: contents; /* lets grid/flex items flow directly into parent grid */
2889
+ color: inherit;
2890
+ font: inherit;
2891
+ }
2892
+ .ds-atom-timeline-trigger:focus-visible {
2893
+ outline: 2px solid var(--amber);
2894
+ outline-offset: 2px;
2895
+ border-radius: 4px;
2896
+ }
2897
+ /* Dark mode */
2898
+ .dark .ds-atom-timeline-date {
2899
+ color: var(--ink-2);
2900
+ }
2901
+ .dark .ds-atom-timeline-label {
2902
+ color: var(--ink);
2903
+ }
2904
+ .dark .ds-atom-timeline-desc {
2905
+ color: var(--ink-2);
2906
+ }
2907
+ .dark .ds-atom-timeline-event::after {
2908
+ background: var(--rule);
2909
+ }
2910
+
2911
+ /* ─── DS atom: InfiniteList (DS-67) ─────────────────────────────────────
2912
+ Loading sentinel + end-state. No virtualization (consumer's responsibility). */
2913
+ .ds-atom-infinitelist {
2914
+ display: flex;
2915
+ flex-direction: column;
2916
+ gap: 8px;
2917
+ padding: 0;
2918
+ margin: 0;
2919
+ list-style: none;
2920
+ }
2921
+ .ds-atom-infinitelist-item {
2922
+ display: block;
2923
+ }
2924
+ .ds-atom-infinitelist-loading {
2925
+ display: flex;
2926
+ flex-direction: column;
2927
+ gap: 8px;
2928
+ padding: 12px 0;
2929
+ }
2930
+ .ds-atom-infinitelist-sentinel {
2931
+ height: 1px;
2932
+ width: 100%;
2933
+ }
2934
+ .ds-atom-infinitelist-end {
2935
+ padding: 16px;
2936
+ text-align: center;
2937
+ color: var(--ink-2);
2938
+ font-family: var(--font-mono);
2939
+ font-size: 12px;
2940
+ text-transform: uppercase;
2941
+ letter-spacing: 0.04em;
2942
+ }
2943
+ .dark .ds-atom-infinitelist-end {
2944
+ color: var(--ink-2);
2945
+ }
2946
+
2947
+ /* ─── DS atom: Accordion (DS-64) ────────────────────────────────────────
2948
+ WAI-ARIA disclosure pattern. <h><button></h> + <div role="region">.
2949
+ Chevron rotates on expand; reduced-motion skips transition. */
2950
+ .ds-atom-accordion {
2951
+ display: flex;
2952
+ flex-direction: column;
2953
+ border: 1px solid var(--rule);
2954
+ border-radius: 8px;
2955
+ overflow: hidden;
2956
+ background: var(--surf-1);
2957
+ }
2958
+ .ds-atom-accordion-item + .ds-atom-accordion-item {
2959
+ border-top: 1px solid var(--rule);
2960
+ }
2961
+ .ds-atom-accordion-heading {
2962
+ margin: 0;
2963
+ padding: 0;
2964
+ font-family: var(--font-display);
2965
+ }
2966
+ .ds-atom-accordion-trigger {
2967
+ appearance: none;
2968
+ width: 100%;
2969
+ background: transparent;
2970
+ border: 0;
2971
+ padding: 14px 16px;
2972
+ cursor: pointer;
2973
+ display: flex;
2974
+ align-items: center;
2975
+ justify-content: space-between;
2976
+ gap: 12px;
2977
+ color: var(--ink);
2978
+ font: inherit;
2979
+ font-size: 14px;
2980
+ font-weight: 600;
2981
+ text-align: left;
2982
+ }
2983
+ .ds-atom-accordion-trigger:hover:not(:disabled) {
2984
+ background: var(--surf-2);
2985
+ }
2986
+ .ds-atom-accordion-trigger:focus-visible {
2987
+ outline: 2px solid var(--amber);
2988
+ outline-offset: -2px;
2989
+ }
2990
+ .ds-atom-accordion-trigger:disabled {
2991
+ cursor: not-allowed;
2992
+ opacity: 0.5;
2993
+ }
2994
+ .ds-atom-accordion-title {
2995
+ flex: 1;
2996
+ }
2997
+ .ds-atom-accordion-chev {
2998
+ transition: transform 200ms ease;
2999
+ flex-shrink: 0;
3000
+ }
3001
+ .ds-atom-accordion-chev[data-open] {
3002
+ transform: rotate(180deg);
3003
+ }
3004
+ .ds-atom-accordion-panel {
3005
+ padding: 0 16px 16px;
3006
+ color: var(--ink);
3007
+ font-family: var(--font-body);
3008
+ font-size: 13px;
3009
+ line-height: 1.6;
3010
+ }
3011
+ /* Reduced-motion: skip chevron transition */
3012
+ .ds-atom-accordion[data-reduced-motion="true"] .ds-atom-accordion-chev {
3013
+ transition: none;
3014
+ }
3015
+ /* Dark mode */
3016
+ .dark .ds-atom-accordion {
3017
+ background: var(--surf-1);
3018
+ border-color: var(--rule);
3019
+ }
3020
+ .dark .ds-atom-accordion-trigger:hover:not(:disabled) {
3021
+ background: var(--surf-2);
3022
+ }
3023
+ .dark .ds-atom-accordion-trigger {
3024
+ color: var(--ink);
3025
+ }
3026
+ .dark .ds-atom-accordion-panel {
3027
+ color: var(--ink);
3028
+ }
3029
+
3030
+ /* ─── DS atom: Carousel (DS-65) ─────────────────────────────────────────────
3031
+ WAI-ARIA carousel. Track translateX'd; reduced-motion skips transition. */
3032
+ .ds-atom-carousel {
3033
+ position: relative;
3034
+ overflow: hidden;
3035
+ border-radius: 8px;
3036
+ }
3037
+ .ds-atom-carousel:focus-visible {
3038
+ outline: 2px solid var(--amber);
3039
+ outline-offset: 2px;
3040
+ }
3041
+ .ds-atom-carousel-viewport {
3042
+ overflow: hidden;
3043
+ touch-action: pan-y;
3044
+ }
3045
+ .ds-atom-carousel-track {
3046
+ display: flex;
3047
+ transition: transform 320ms ease;
3048
+ will-change: transform;
3049
+ }
3050
+ .ds-atom-carousel-track[data-reduced-motion="true"] {
3051
+ transition: none;
3052
+ }
3053
+ .ds-atom-carousel-slide {
3054
+ flex: 0 0 100%;
3055
+ min-width: 100%;
3056
+ box-sizing: border-box;
3057
+ }
3058
+ .ds-atom-carousel-arrow {
3059
+ position: absolute;
3060
+ top: 50%;
3061
+ transform: translateY(-50%);
3062
+ width: 40px;
3063
+ height: 40px;
3064
+ border-radius: 50%;
3065
+ background: var(--surf-1);
3066
+ border: 1px solid var(--rule);
3067
+ cursor: pointer;
3068
+ display: flex;
3069
+ align-items: center;
3070
+ justify-content: center;
3071
+ color: var(--ink);
3072
+ transition: background-color 120ms ease;
3073
+ }
3074
+ .ds-atom-carousel-arrow:hover:not(:disabled) {
3075
+ background: var(--surf-2);
3076
+ }
3077
+ .ds-atom-carousel-arrow:focus-visible {
3078
+ outline: 2px solid var(--amber);
3079
+ outline-offset: 2px;
3080
+ }
3081
+ .ds-atom-carousel-arrow:disabled {
3082
+ opacity: 0.4;
3083
+ cursor: not-allowed;
3084
+ }
3085
+ .ds-atom-carousel-arrow-prev {
3086
+ left: 12px;
3087
+ }
3088
+ .ds-atom-carousel-arrow-next {
3089
+ right: 12px;
3090
+ }
3091
+ .ds-atom-carousel-dots {
3092
+ display: flex;
3093
+ gap: 6px;
3094
+ justify-content: center;
3095
+ padding: 12px 0;
3096
+ }
3097
+ .ds-atom-carousel-dot {
3098
+ width: 8px;
3099
+ height: 8px;
3100
+ border-radius: 50%;
3101
+ background: var(--rule);
3102
+ border: 0;
3103
+ padding: 0;
3104
+ cursor: pointer;
3105
+ transition: background-color 120ms ease, transform 120ms ease;
3106
+ }
3107
+ .ds-atom-carousel-dot[data-active] {
3108
+ background: var(--amber);
3109
+ transform: scale(1.2);
3110
+ }
3111
+ .ds-atom-carousel-dot:focus-visible {
3112
+ outline: 2px solid var(--amber);
3113
+ outline-offset: 2px;
3114
+ }
3115
+ /* Dark mode */
3116
+ .dark .ds-atom-carousel-arrow {
3117
+ background: var(--surf-1);
3118
+ border-color: var(--rule);
3119
+ color: var(--ink);
3120
+ }
3121
+ .dark .ds-atom-carousel-arrow:hover:not(:disabled) {
3122
+ background: var(--surf-2);
3123
+ }
3124
+ .dark .ds-atom-carousel-dot {
3125
+ background: var(--rule);
3126
+ }
3127
+ .dark .ds-atom-carousel-dot[data-active] {
3128
+ background: var(--amber);
3129
+ }
3130
+
3131
+ /* ─── DS atom: Tabs (DS-62) ─────────────────────────────────────────────────
3132
+ WAI-ARIA tab pattern. Variants: underline (default), pill. */
3133
+ .ds-atom-tabs {
3134
+ display: flex;
3135
+ flex-direction: column;
3136
+ }
3137
+ .ds-atom-tabs-list {
3138
+ display: flex;
3139
+ gap: 4px;
3140
+ align-items: stretch;
3141
+ border-bottom: 1px solid var(--rule);
3142
+ flex-wrap: nowrap;
3143
+ overflow: hidden;
3144
+ }
3145
+ .ds-atom-tabs[data-variant="pill"] .ds-atom-tabs-list {
3146
+ border-bottom: 0;
3147
+ padding: 4px;
3148
+ background: var(--surf-2);
3149
+ border-radius: 999px;
3150
+ gap: 2px;
3151
+ }
3152
+ .ds-atom-tabs-trigger {
3153
+ appearance: none;
3154
+ background: transparent;
3155
+ border: 0;
3156
+ cursor: pointer;
3157
+ padding: 10px 14px;
3158
+ color: var(--ink-2);
3159
+ font-family: var(--font-body);
3160
+ font-weight: 500;
3161
+ font-size: 13px;
3162
+ display: inline-flex;
3163
+ align-items: center;
3164
+ gap: 6px;
3165
+ position: relative;
3166
+ white-space: nowrap;
3167
+ transition: color 120ms ease, background-color 120ms ease;
3168
+ }
3169
+ .ds-atom-tabs-trigger:hover:not(:disabled):not([data-active]) {
3170
+ color: var(--ink);
3171
+ }
3172
+ .ds-atom-tabs-trigger:focus-visible {
3173
+ outline: 2px solid var(--amber);
3174
+ outline-offset: -2px;
3175
+ border-radius: 4px;
3176
+ }
3177
+ .ds-atom-tabs-trigger:disabled {
3178
+ opacity: 0.5;
3179
+ cursor: not-allowed;
3180
+ }
3181
+ /* Underline variant: animated underline */
3182
+ .ds-atom-tabs[data-variant="underline"] .ds-atom-tabs-trigger[data-active] {
3183
+ color: var(--ink);
3184
+ }
3185
+ .ds-atom-tabs[data-variant="underline"] .ds-atom-tabs-trigger[data-active]::after {
3186
+ content: "";
3187
+ position: absolute;
3188
+ bottom: -1px;
3189
+ left: 0;
3190
+ right: 0;
3191
+ height: 2px;
3192
+ background: var(--amber);
3193
+ }
3194
+ /* Pill variant */
3195
+ .ds-atom-tabs[data-variant="pill"] .ds-atom-tabs-trigger {
3196
+ border-radius: 999px;
3197
+ padding: 6px 14px;
3198
+ }
3199
+ .ds-atom-tabs[data-variant="pill"] .ds-atom-tabs-trigger[data-active] {
3200
+ background: var(--amber);
3201
+ color: var(--ink-inverse, #000);
3202
+ }
3203
+ .ds-atom-tabs-count {
3204
+ display: inline-flex;
3205
+ align-items: center;
3206
+ justify-content: center;
3207
+ min-width: 18px;
3208
+ height: 18px;
3209
+ padding: 0 6px;
3210
+ border-radius: 999px;
3211
+ background: var(--surf-2);
3212
+ color: var(--ink-2);
3213
+ font-family: var(--font-mono);
3214
+ font-size: 11px;
3215
+ font-weight: 600;
3216
+ }
3217
+ .ds-atom-tabs[data-variant="pill"] .ds-atom-tabs-trigger[data-active] .ds-atom-tabs-count {
3218
+ background: rgba(0, 0, 0, 0.15);
3219
+ color: var(--ink-inverse, #000);
3220
+ }
3221
+ .ds-atom-tabs-panel {
3222
+ padding: 16px 0;
3223
+ outline: none;
3224
+ }
3225
+ .ds-atom-tabs-panel:focus-visible {
3226
+ outline: 2px solid var(--amber);
3227
+ outline-offset: 2px;
3228
+ border-radius: 4px;
3229
+ }
3230
+ /* Overflow - More button */
3231
+ .ds-atom-tabs-more {
3232
+ appearance: none;
3233
+ background: transparent;
3234
+ border: 0;
3235
+ padding: 8px;
3236
+ cursor: pointer;
3237
+ color: var(--ink-2);
3238
+ display: inline-flex;
3239
+ align-items: center;
3240
+ flex-shrink: 0;
3241
+ border-radius: 4px;
3242
+ }
3243
+ .ds-atom-tabs-more:hover {
3244
+ background: var(--surf-2);
3245
+ color: var(--ink);
3246
+ }
3247
+ .ds-atom-tabs-more:focus-visible {
3248
+ outline: 2px solid var(--amber);
3249
+ outline-offset: -2px;
3250
+ }
3251
+ /* Overflow dropdown menu */
3252
+ .ds-atom-tabs-overflow-menu {
3253
+ list-style: none;
3254
+ margin: 0;
3255
+ padding: 4px;
3256
+ min-width: 160px;
3257
+ }
3258
+ .ds-atom-tabs-overflow-item button {
3259
+ display: flex;
3260
+ width: 100%;
3261
+ text-align: left;
3262
+ padding: 6px 10px;
3263
+ border: 0;
3264
+ background: transparent;
3265
+ cursor: pointer;
3266
+ color: var(--ink);
3267
+ font-family: inherit;
3268
+ font-size: 13px;
3269
+ border-radius: 4px;
3270
+ justify-content: space-between;
3271
+ gap: 12px;
3272
+ align-items: center;
3273
+ }
3274
+ .ds-atom-tabs-overflow-item[data-active] button,
3275
+ .ds-atom-tabs-overflow-item button:hover {
3276
+ background: var(--surf-2);
3277
+ }
3278
+ /* Dark mode */
3279
+ .dark .ds-atom-tabs-list {
3280
+ border-bottom-color: var(--rule);
3281
+ }
3282
+ .dark .ds-atom-tabs[data-variant="pill"] .ds-atom-tabs-list {
3283
+ background: var(--surf-2);
3284
+ }
3285
+ /* Inactive tabs: clearly readable but dimmer than active */
3286
+ .dark .ds-atom-tabs-trigger {
3287
+ color: var(--ink-3);
3288
+ }
3289
+ .dark .ds-atom-tabs-trigger:hover:not(:disabled):not([data-active]) {
3290
+ color: var(--ink-2);
3291
+ }
3292
+ /* Active tabs: full brightness */
3293
+ .dark .ds-atom-tabs[data-variant="underline"] .ds-atom-tabs-trigger[data-active] {
3294
+ color: var(--ink);
3295
+ }
3296
+ .dark .ds-atom-tabs[data-variant="pill"] .ds-atom-tabs-trigger[data-active] {
3297
+ background: var(--amber);
3298
+ color: #1c1917;
3299
+ }
3300
+ .dark .ds-atom-tabs-count {
3301
+ background: var(--surf-2);
3302
+ color: var(--ink-2);
3303
+ }
3304
+ .dark .ds-atom-tabs-more:hover {
3305
+ background: var(--surf-2);
3306
+ }
3307
+ .dark .ds-atom-tabs-overflow-item[data-active] button,
3308
+ .dark .ds-atom-tabs-overflow-item button:hover {
3309
+ background: var(--surf-2);
3310
+ }
3311
+
3312
+ /* ─── DS atom: Table (DS-61, part 1) ────────────────────────────────────
3313
+ Compound table chrome with density modes + sticky header.
3314
+ Selection, resize, pagination ship in DS-61 part 2 (Plan 17-11). */
3315
+ .ds-atom-table {
3316
+ width: 100%;
3317
+ border-collapse: collapse;
3318
+ font-family: var(--font-body);
3319
+ font-size: 13px;
3320
+ color: var(--ink);
3321
+ }
3322
+ .ds-atom-table-header {
3323
+ border-bottom: 1px solid var(--rule);
3324
+ background: var(--surf-2);
3325
+ }
3326
+ .ds-atom-table[data-sticky="true"] .ds-atom-table-header {
3327
+ position: sticky;
3328
+ top: 0;
3329
+ /* Solid background so scrolled row text doesn't bleed through the semi-transparent --surf-2 */
3330
+ background: var(--cream-2);
3331
+ z-index: 1;
3332
+ }
3333
+ .ds-atom-table-headercell {
3334
+ text-align: left;
3335
+ font-family: var(--font-mono);
3336
+ font-size: 11px;
3337
+ font-weight: 600;
3338
+ text-transform: uppercase;
3339
+ letter-spacing: 0.04em;
3340
+ color: var(--ink-2);
3341
+ padding: 8px 12px;
3342
+ vertical-align: middle;
3343
+ }
3344
+ .ds-atom-table-headercell-sortable {
3345
+ cursor: pointer;
3346
+ user-select: none;
3347
+ }
3348
+ .ds-atom-table-headercell-sortable:hover {
3349
+ color: var(--ink);
3350
+ }
3351
+ .ds-atom-table-headercell-sortable:focus-visible {
3352
+ outline: 2px solid var(--amber);
3353
+ outline-offset: -2px;
3354
+ }
3355
+ .ds-atom-table-headercell-label {
3356
+ display: inline-block;
3357
+ vertical-align: middle;
3358
+ }
3359
+ .ds-atom-table-sort-indicator {
3360
+ font-family: var(--font-mono);
3361
+ font-size: 9px;
3362
+ margin-left: 6px;
3363
+ color: var(--amber);
3364
+ vertical-align: middle;
3365
+ }
3366
+ .ds-atom-table-row {
3367
+ border-bottom: 1px solid var(--rule);
3368
+ }
3369
+ .ds-atom-table-row:last-child {
3370
+ border-bottom: 0;
3371
+ }
3372
+ .ds-atom-table-row:hover {
3373
+ background: var(--surf-2);
3374
+ }
3375
+ .ds-atom-table-cell {
3376
+ padding: 8px 12px;
3377
+ vertical-align: middle;
3378
+ }
3379
+ /* Density modes */
3380
+ .ds-atom-table[data-density="cozy"] .ds-atom-table-headercell,
3381
+ .ds-atom-table[data-density="cozy"] .ds-atom-table-cell {
3382
+ padding: 4px 12px;
3383
+ }
3384
+ .ds-atom-table[data-density="cozy"] .ds-atom-table-row {
3385
+ height: 32px;
3386
+ }
3387
+ .ds-atom-table[data-density="comfortable"] .ds-atom-table-row {
3388
+ height: 40px;
3389
+ }
3390
+ .ds-atom-table[data-density="spacious"] .ds-atom-table-headercell,
3391
+ .ds-atom-table[data-density="spacious"] .ds-atom-table-cell {
3392
+ padding: 12px 14px;
3393
+ }
3394
+ .ds-atom-table[data-density="spacious"] .ds-atom-table-row {
3395
+ height: 48px;
3396
+ }
3397
+ /* Dark mode */
3398
+ .dark .ds-atom-table {
3399
+ color: var(--ink);
3400
+ }
3401
+ .dark .ds-atom-table-header {
3402
+ background: var(--surf-2);
3403
+ border-bottom-color: var(--rule);
3404
+ }
3405
+ .dark .ds-atom-table[data-sticky="true"] .ds-atom-table-header {
3406
+ background: var(--cream-2);
3407
+ }
3408
+ .dark .ds-atom-table-headercell {
3409
+ color: var(--ink-2);
3410
+ }
3411
+ .dark .ds-atom-table-headercell-sortable:hover {
3412
+ color: var(--ink);
3413
+ }
3414
+ .dark .ds-atom-table-row {
3415
+ border-bottom-color: var(--rule);
3416
+ }
3417
+ .dark .ds-atom-table-row:hover {
3418
+ background: var(--surf-2);
3419
+ }
3420
+
3421
+ /* DS-61 part 2 - Selection, resize, pagination (Plan 17-11) */
3422
+ .ds-atom-table-selectcell {
3423
+ width: 40px;
3424
+ padding: 0 8px;
3425
+ vertical-align: middle;
3426
+ }
3427
+ .ds-atom-table-row[data-selected="true"] {
3428
+ background: color-mix(in srgb, var(--amber) 14%, transparent);
3429
+ }
3430
+ .ds-atom-table-resize-handle {
3431
+ position: absolute;
3432
+ top: 0;
3433
+ right: 0;
3434
+ width: 6px;
3435
+ height: 100%;
3436
+ cursor: col-resize;
3437
+ user-select: none;
3438
+ touch-action: none;
3439
+ }
3440
+ .ds-atom-table-resize-handle:hover,
3441
+ .ds-atom-table-resize-handle:active {
3442
+ background: var(--amber);
3443
+ opacity: 0.5;
3444
+ }
3445
+ .ds-atom-table-headercell-sortable,
3446
+ .ds-atom-table-headercell {
3447
+ position: relative; /* anchor for resize handle */
3448
+ }
3449
+ .ds-atom-table-pagination {
3450
+ display: flex;
3451
+ align-items: center;
3452
+ gap: 4px;
3453
+ padding: 12px 0;
3454
+ flex-wrap: wrap;
3455
+ }
3456
+ .ds-atom-table-pagination-ellipsis {
3457
+ padding: 0 8px;
3458
+ color: var(--ink-2);
3459
+ font-family: var(--font-mono);
3460
+ }
3461
+ .ds-atom-table-pagination-summary {
3462
+ margin-left: auto;
3463
+ color: var(--ink-2);
3464
+ font-family: var(--font-mono);
3465
+ font-size: 11px;
3466
+ text-transform: uppercase;
3467
+ letter-spacing: 0.04em;
3468
+ }
3469
+ /* Dark mode */
3470
+ .dark .ds-atom-table-row[data-selected="true"] {
3471
+ background: color-mix(in srgb, var(--amber) 18%, transparent);
3472
+ }
3473
+ .dark .ds-atom-table-pagination-ellipsis,
3474
+ .dark .ds-atom-table-pagination-summary {
3475
+ color: var(--ink-2);
3476
+ }
3477
+
3478
+ /* ─── DS atom: Calendar (DS-68) ─────────────────────────────────────────
3479
+ Three views: month (default 6×7 grid), week, day.
3480
+ Today highlight in amber per DatePicker tokens (D-17-25). */
3481
+ .ds-atom-calendar {
3482
+ font-family: var(--font-body);
3483
+ background: var(--cream);
3484
+ border: 1px solid var(--rule);
3485
+ border-radius: 8px;
3486
+ padding: 16px;
3487
+ }
3488
+ .ds-atom-calendar-header {
3489
+ display: flex;
3490
+ align-items: center;
3491
+ justify-content: space-between;
3492
+ gap: 12px;
3493
+ margin-bottom: 12px;
3494
+ }
3495
+ .ds-atom-calendar-nav {
3496
+ display: flex;
3497
+ align-items: center;
3498
+ gap: 8px;
3499
+ }
3500
+ .ds-atom-calendar-navbtn {
3501
+ appearance: none;
3502
+ background: transparent;
3503
+ border: 1px solid var(--rule);
3504
+ border-radius: 4px;
3505
+ cursor: pointer;
3506
+ padding: 4px;
3507
+ color: var(--ink-2);
3508
+ display: inline-flex;
3509
+ align-items: center;
3510
+ justify-content: center;
3511
+ }
3512
+ .ds-atom-calendar-navbtn:hover {
3513
+ background: var(--cream-3);
3514
+ color: var(--ink);
3515
+ }
3516
+ .ds-atom-calendar-navbtn:focus-visible {
3517
+ outline: 2px solid var(--amber);
3518
+ outline-offset: 2px;
3519
+ }
3520
+ .ds-atom-calendar-label {
3521
+ font-family: var(--font-display);
3522
+ font-size: 16px;
3523
+ font-weight: 600;
3524
+ color: var(--ink);
3525
+ min-width: 160px;
3526
+ text-align: center;
3527
+ }
3528
+ .ds-atom-calendar-month {
3529
+ display: flex;
3530
+ flex-direction: column;
3531
+ gap: 0;
3532
+ }
3533
+ .ds-atom-calendar-weekdays,
3534
+ .ds-atom-calendar-week {
3535
+ display: grid;
3536
+ grid-template-columns: repeat(7, minmax(0, 1fr));
3537
+ }
3538
+ .ds-atom-calendar-weekday {
3539
+ padding: 6px 0;
3540
+ text-align: center;
3541
+ font-family: var(--font-mono);
3542
+ font-size: 11px;
3543
+ color: var(--ink-2);
3544
+ text-transform: uppercase;
3545
+ letter-spacing: 0.04em;
3546
+ font-weight: 600;
3547
+ }
3548
+ .ds-atom-calendar-cell {
3549
+ appearance: none;
3550
+ background: transparent;
3551
+ border: 0;
3552
+ border-top: 1px solid var(--rule);
3553
+ border-right: 1px solid var(--rule);
3554
+ cursor: pointer;
3555
+ padding: 8px;
3556
+ min-height: 80px;
3557
+ min-width: 0;
3558
+ color: var(--ink);
3559
+ font-family: inherit;
3560
+ text-align: left;
3561
+ display: flex;
3562
+ flex-direction: column;
3563
+ align-items: stretch;
3564
+ gap: 4px;
3565
+ position: relative;
3566
+ transition: background-color 100ms ease;
3567
+ overflow: hidden;
3568
+ }
3569
+ .ds-atom-calendar-week:last-child .ds-atom-calendar-cell {
3570
+ border-bottom: 1px solid var(--rule);
3571
+ }
3572
+ .ds-atom-calendar-cell:nth-child(7n + 1) {
3573
+ border-left: 1px solid var(--rule);
3574
+ }
3575
+ .ds-atom-calendar-cell:hover {
3576
+ background: var(--cream-3);
3577
+ }
3578
+ .ds-atom-calendar-cell:focus-visible {
3579
+ outline: 2px solid var(--amber);
3580
+ outline-offset: -2px;
3581
+ z-index: 1;
3582
+ }
3583
+ .ds-atom-calendar-cell[data-out-of-month] {
3584
+ color: var(--ink-3, var(--ink-2));
3585
+ opacity: 0.5;
3586
+ }
3587
+ .ds-atom-calendar-cell[data-today] .ds-atom-calendar-cell-num {
3588
+ background: var(--amber);
3589
+ color: var(--ink-inverse, #000);
3590
+ border-radius: 4px;
3591
+ padding: 2px 6px;
3592
+ font-weight: 600;
3593
+ align-self: flex-start;
3594
+ }
3595
+ .ds-atom-calendar-cell[data-selected]:not([data-today]) {
3596
+ background: color-mix(in srgb, var(--amber) 18%, transparent);
3597
+ }
3598
+ .ds-atom-calendar-cell-num {
3599
+ font-family: var(--font-display);
3600
+ font-size: 13px;
3601
+ font-weight: 500;
3602
+ align-self: flex-start;
3603
+ }
3604
+ /* Event chips in month cells */
3605
+ .ds-atom-calendar-cell-events {
3606
+ display: flex;
3607
+ flex-direction: column;
3608
+ gap: 2px;
3609
+ margin-top: 2px;
3610
+ }
3611
+ .ds-atom-calendar-chip {
3612
+ display: block;
3613
+ background: var(--amber);
3614
+ color: var(--ink-inverse, #000);
3615
+ font-size: 10px;
3616
+ font-weight: 500;
3617
+ padding: 1px 6px;
3618
+ border-radius: 3px;
3619
+ white-space: nowrap;
3620
+ overflow: hidden;
3621
+ text-overflow: ellipsis;
3622
+ }
3623
+ .ds-atom-calendar-chip-more {
3624
+ appearance: none;
3625
+ background: transparent;
3626
+ border: 0;
3627
+ cursor: pointer;
3628
+ font-family: var(--font-mono);
3629
+ font-size: 10px;
3630
+ color: var(--ink-2);
3631
+ text-align: left;
3632
+ padding: 0;
3633
+ }
3634
+ .ds-atom-calendar-chip-more:hover {
3635
+ color: var(--ink);
3636
+ text-decoration: underline;
3637
+ }
3638
+ /* Overflow events popover */
3639
+ .ds-atom-calendar-events-popover {
3640
+ padding: 12px;
3641
+ min-width: 240px;
3642
+ background: var(--surf-1);
3643
+ border: 1px solid var(--rule);
3644
+ border-radius: 6px;
3645
+ }
3646
+ .ds-atom-calendar-events-header {
3647
+ font-family: var(--font-mono);
3648
+ font-size: 11px;
3649
+ color: var(--ink-2);
3650
+ text-transform: uppercase;
3651
+ letter-spacing: 0.04em;
3652
+ margin-bottom: 8px;
3653
+ }
3654
+ .ds-atom-calendar-events-list {
3655
+ list-style: none;
3656
+ margin: 0;
3657
+ padding: 0;
3658
+ display: flex;
3659
+ flex-direction: column;
3660
+ gap: 6px;
3661
+ }
3662
+ .ds-atom-calendar-events-item {
3663
+ display: flex;
3664
+ align-items: center;
3665
+ gap: 8px;
3666
+ font-size: 13px;
3667
+ color: var(--ink);
3668
+ }
3669
+ .ds-atom-calendar-events-dot {
3670
+ width: 8px;
3671
+ height: 8px;
3672
+ border-radius: 50%;
3673
+ background: var(--amber);
3674
+ flex-shrink: 0;
3675
+ }
3676
+ /* Agenda slot */
3677
+ .ds-atom-calendar-agenda {
3678
+ list-style: none;
3679
+ margin: 0;
3680
+ padding: 0;
3681
+ display: flex;
3682
+ flex-direction: column;
3683
+ gap: 8px;
3684
+ }
3685
+ .ds-atom-calendar-agenda-item {
3686
+ display: grid;
3687
+ grid-template-columns: 12px 100px 1fr;
3688
+ gap: 12px;
3689
+ padding: 8px;
3690
+ align-items: center;
3691
+ }
3692
+ .ds-atom-calendar-agenda-dot {
3693
+ width: 10px;
3694
+ height: 10px;
3695
+ border-radius: 50%;
3696
+ background: var(--amber);
3697
+ }
3698
+ .ds-atom-calendar-agenda-time {
3699
+ font-family: var(--font-mono);
3700
+ font-size: 11px;
3701
+ color: var(--ink-2);
3702
+ }
3703
+ .ds-atom-calendar-agenda-label {
3704
+ font-size: 13px;
3705
+ color: var(--ink);
3706
+ }
3707
+ /* Week view */
3708
+ .ds-atom-calendar-weekview {
3709
+ padding-top: 8px;
3710
+ }
3711
+ .ds-atom-calendar-week-row {
3712
+ display: grid;
3713
+ grid-template-columns: repeat(7, 1fr);
3714
+ gap: 4px;
3715
+ }
3716
+ .ds-atom-calendar-weekcell {
3717
+ border: 1px solid var(--rule);
3718
+ border-radius: 6px;
3719
+ padding: 8px;
3720
+ min-height: 200px;
3721
+ display: flex;
3722
+ flex-direction: column;
3723
+ gap: 8px;
3724
+ }
3725
+ .ds-atom-calendar-weekcell[data-today] {
3726
+ border-color: var(--amber);
3727
+ }
3728
+ .ds-atom-calendar-weekcell[data-selected] {
3729
+ background: color-mix(in srgb, var(--amber) 14%, transparent);
3730
+ }
3731
+ .ds-atom-calendar-weekcell-header {
3732
+ appearance: none;
3733
+ background: transparent;
3734
+ border: 0;
3735
+ cursor: pointer;
3736
+ display: flex;
3737
+ flex-direction: column;
3738
+ align-items: flex-start;
3739
+ gap: 4px;
3740
+ color: inherit;
3741
+ font: inherit;
3742
+ }
3743
+ .ds-atom-calendar-weekcell-name {
3744
+ font-family: var(--font-mono);
3745
+ font-size: 10px;
3746
+ color: var(--ink-2);
3747
+ text-transform: uppercase;
3748
+ letter-spacing: 0.04em;
3749
+ }
3750
+ .ds-atom-calendar-weekcell-date {
3751
+ font-family: var(--font-display);
3752
+ font-size: 18px;
3753
+ font-weight: 600;
3754
+ }
3755
+ .ds-atom-calendar-weekcell-events {
3756
+ list-style: none;
3757
+ margin: 0;
3758
+ padding: 0;
3759
+ display: flex;
3760
+ flex-direction: column;
3761
+ gap: 2px;
3762
+ flex: 1;
3763
+ }
3764
+ /* Day view */
3765
+ .ds-atom-calendar-dayview {
3766
+ display: flex;
3767
+ flex-direction: column;
3768
+ gap: 8px;
3769
+ }
3770
+ .ds-atom-calendar-dayview-allday {
3771
+ display: grid;
3772
+ grid-template-columns: 60px 1fr;
3773
+ gap: 8px;
3774
+ padding: 8px 0;
3775
+ border-bottom: 1px solid var(--rule);
3776
+ }
3777
+ .ds-atom-calendar-dayview-alldaylabel {
3778
+ font-family: var(--font-mono);
3779
+ font-size: 11px;
3780
+ color: var(--ink-2);
3781
+ text-transform: uppercase;
3782
+ letter-spacing: 0.04em;
3783
+ padding-top: 2px;
3784
+ }
3785
+ .ds-atom-calendar-dayview-alldayevents {
3786
+ list-style: none;
3787
+ margin: 0;
3788
+ padding: 0;
3789
+ display: flex;
3790
+ flex-direction: column;
3791
+ gap: 2px;
3792
+ }
3793
+ .ds-atom-calendar-dayview-grid {
3794
+ display: flex;
3795
+ flex-direction: column;
3796
+ /* Height + overflow set via inline style (dayViewHeight prop, default 480px) */
3797
+ position: relative;
3798
+ }
3799
+ /* Current-time indicator - horizontal amber line across the time grid */
3800
+ .ds-atom-calendar-nowline {
3801
+ position: absolute;
3802
+ left: 60px; /* align with hour slot column, past the label */
3803
+ right: 0;
3804
+ height: 2px;
3805
+ background: var(--amber);
3806
+ z-index: 2;
3807
+ pointer-events: none;
3808
+ }
3809
+ .ds-atom-calendar-nowdot {
3810
+ position: absolute;
3811
+ left: -5px;
3812
+ top: -4px;
3813
+ width: 10px;
3814
+ height: 10px;
3815
+ border-radius: 50%;
3816
+ background: var(--amber);
3817
+ }
3818
+ .ds-atom-calendar-dayview-hour {
3819
+ display: grid;
3820
+ grid-template-columns: 60px 1fr;
3821
+ gap: 8px;
3822
+ min-height: 40px;
3823
+ border-bottom: 1px solid var(--rule);
3824
+ padding: 4px 0;
3825
+ }
3826
+ .ds-atom-calendar-dayview-hourlabel {
3827
+ font-family: var(--font-mono);
3828
+ font-size: 11px;
3829
+ color: var(--ink-2);
3830
+ }
3831
+ .ds-atom-calendar-dayview-hourslot {
3832
+ display: flex;
3833
+ flex-direction: column;
3834
+ gap: 2px;
3835
+ }
3836
+ /* Dark mode */
3837
+ .dark .ds-atom-calendar {
3838
+ background: var(--surf-1);
3839
+ border-color: var(--rule);
3840
+ color: var(--ink);
3841
+ }
3842
+ .dark .ds-atom-calendar-cell {
3843
+ color: var(--ink);
3844
+ border-color: var(--rule);
3845
+ }
3846
+ .dark .ds-atom-calendar-cell:hover {
3847
+ background: var(--surf-2);
3848
+ }
3849
+ .dark .ds-atom-calendar-cell[data-today] .ds-atom-calendar-cell-num {
3850
+ background: var(--amber);
3851
+ color: var(--ink-inverse, #000);
3852
+ }
3853
+ .dark .ds-atom-calendar-cell[data-out-of-month] {
3854
+ color: var(--ink-2);
3855
+ opacity: 0.5;
3856
+ }
3857
+ .dark .ds-atom-calendar-weekday {
3858
+ color: var(--ink-2);
3859
+ }
3860
+ .dark .ds-atom-calendar-navbtn {
3861
+ border-color: var(--rule);
3862
+ color: var(--ink-2);
3863
+ }
3864
+ .dark .ds-atom-calendar-navbtn:hover {
3865
+ background: var(--surf-2);
3866
+ color: var(--ink);
3867
+ }
3868
+ .dark .ds-atom-calendar-chip-more {
3869
+ color: var(--ink-2);
3870
+ }
3871
+ .dark .ds-atom-calendar-events-popover {
3872
+ background: var(--surf-1);
3873
+ border-color: var(--rule);
3874
+ }
3875
+ .dark .ds-atom-calendar-events-item {
3876
+ color: var(--ink);
3877
+ }
3878
+ .dark .ds-atom-calendar-weekcell {
3879
+ border-color: var(--rule);
3880
+ color: var(--ink);
3881
+ }
3882
+ .dark .ds-atom-calendar-weekcell-name {
3883
+ color: var(--ink-2);
3884
+ }
3885
+ .dark .ds-atom-calendar-weekcell-date {
3886
+ color: var(--ink);
3887
+ }
3888
+ .dark .ds-atom-calendar-weekcell-header {
3889
+ color: var(--ink);
3890
+ }
3891
+ .dark .ds-atom-calendar-dayview-alldaylabel,
3892
+ .dark .ds-atom-calendar-dayview-hourlabel {
3893
+ color: var(--ink-2);
3894
+ }
3895
+ .dark .ds-atom-calendar-dayview-allday,
3896
+ .dark .ds-atom-calendar-dayview-hour {
3897
+ border-bottom-color: var(--rule);
3898
+ }
3899
+
3900
+ /* ─── DS atom: RichText (DS-70) ─────────────────────────────────────────────
3901
+ TipTap-powered rich text editor. Toolbar uses Button ghost variant + canonical
3902
+ Icon components from ./icons. Editor surface is .ProseMirror - TipTap renders
3903
+ into it; we style prose inside it without overriding ProseMirror internals.
3904
+ Controlled-sync three-layer guard documented in src/RichText.tsx file header.
3905
+ ───────────────────────────────────────────────────────────────────────────── */
3906
+
3907
+ /* ── Wrapper ──────────────────────────────────────────────────────────────── */
3908
+ .ds-atom-richtext {
3909
+ border: 1px solid var(--rule);
3910
+ border-radius: 8px;
3911
+ background: var(--surf-1);
3912
+ overflow: hidden;
3913
+ }
3914
+ .ds-atom-richtext:focus-within {
3915
+ border-color: var(--amber);
3916
+ outline: none;
3917
+ }
3918
+ .ds-atom-richtext--loading {
3919
+ min-height: 160px;
3920
+ }
3921
+
3922
+ /* ── Toolbar ──────────────────────────────────────────────────────────────── */
3923
+ .ds-atom-richtext-toolbar {
3924
+ display: flex;
3925
+ align-items: center;
3926
+ gap: 2px;
3927
+ padding: 6px;
3928
+ border-bottom: 1px solid var(--rule);
3929
+ background: var(--surf-2);
3930
+ flex-wrap: wrap;
3931
+ }
3932
+ .ds-atom-richtext-toolbar-divider {
3933
+ width: 1px;
3934
+ height: 20px;
3935
+ background: var(--rule);
3936
+ margin: 0 4px;
3937
+ flex-shrink: 0;
3938
+ display: inline-block;
3939
+ }
3940
+ .ds-atom-richtext-toolbar [data-active] {
3941
+ background: color-mix(in srgb, var(--amber) 12%, transparent);
3942
+ color: var(--amber);
3943
+ }
3944
+
3945
+ /* ── Heading dropdown menu ────────────────────────────────────────────────── */
3946
+ .ds-atom-richtext-headingmenu {
3947
+ list-style: none;
3948
+ margin: 0;
3949
+ padding: 4px;
3950
+ min-width: 140px;
3951
+ }
3952
+ .ds-atom-richtext-headingmenu li button {
3953
+ display: block;
3954
+ width: 100%;
3955
+ text-align: left;
3956
+ padding: 6px 10px;
3957
+ border: 0;
3958
+ background: transparent;
3959
+ cursor: pointer;
3960
+ color: var(--ink);
3961
+ font: inherit;
3962
+ font-size: 13px;
3963
+ border-radius: 4px;
3964
+ transition: background 0.1s;
3965
+ }
3966
+ .ds-atom-richtext-headingmenu li[data-active] button,
3967
+ .ds-atom-richtext-headingmenu li button:hover {
3968
+ background: var(--surf-2);
3969
+ }
3970
+
3971
+ /* ── Editor surface ───────────────────────────────────────────────────────── */
3972
+ .ds-atom-richtext-surface {
3973
+ padding: 12px 16px;
3974
+ min-height: 160px;
3975
+ color: var(--ink);
3976
+ font-family: var(--font-body, var(--font));
3977
+ font-size: 14px;
3978
+ line-height: 1.6;
3979
+ }
3980
+ .ds-atom-richtext-surface .ProseMirror {
3981
+ outline: none;
3982
+ min-height: 140px;
3983
+ }
3984
+
3985
+ /* Prose typography inside ProseMirror */
3986
+ .ds-atom-richtext-surface .ProseMirror p {
3987
+ margin: 0 0 8px 0;
3988
+ }
3989
+ .ds-atom-richtext-surface .ProseMirror p:last-child {
3990
+ margin-bottom: 0;
3991
+ }
3992
+ .ds-atom-richtext-surface .ProseMirror h2 {
3993
+ font-family: var(--font-display, var(--font));
3994
+ font-size: 20px;
3995
+ font-weight: 700;
3996
+ margin: 16px 0 8px 0;
3997
+ line-height: 1.3;
3998
+ }
3999
+ .ds-atom-richtext-surface .ProseMirror h3 {
4000
+ font-family: var(--font-display, var(--font));
4001
+ font-size: 16px;
4002
+ font-weight: 600;
4003
+ margin: 14px 0 6px 0;
4004
+ line-height: 1.4;
4005
+ }
4006
+ /* Inline code */
4007
+ .ds-atom-richtext-surface .ProseMirror code {
4008
+ background: var(--cream-3);
4009
+ padding: 1px 6px;
4010
+ border-radius: 3px;
4011
+ font-family: var(--font-mono);
4012
+ font-size: 12px;
4013
+ color: var(--ink);
4014
+ }
4015
+ /* Fenced code block - lowlight adds <pre><code class="language-*"> */
4016
+ .ds-atom-richtext-surface .ProseMirror pre {
4017
+ background: var(--cream-2);
4018
+ border: 1px solid var(--rule);
4019
+ border-radius: 6px;
4020
+ padding: 12px 14px;
4021
+ margin: 8px 0;
4022
+ overflow-x: auto;
4023
+ }
4024
+ /* Dark code block - activated by Moon toggle OR page dark mode.
4025
+ Uses !important to override storybook.css's global pre background rule. */
4026
+ .ds-atom-richtext-surface[data-code-dark] .ProseMirror pre,
4027
+ .dark .ds-atom-richtext-surface .ProseMirror pre {
4028
+ background: #1c1917 !important;
4029
+ border-color: #44403c !important;
4030
+ }
4031
+ .ds-atom-richtext-surface[data-code-dark] .ProseMirror pre code,
4032
+ .dark .ds-atom-richtext-surface .ProseMirror pre code {
4033
+ color: #f5f3f0 !important;
4034
+ }
4035
+ .ds-atom-richtext-surface[data-code-dark] .ProseMirror pre .hljs-keyword,
4036
+ .ds-atom-richtext-surface[data-code-dark] .ProseMirror pre .hljs-tag,
4037
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-keyword,
4038
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-tag {
4039
+ color: #c084fc;
4040
+ }
4041
+ .ds-atom-richtext-surface[data-code-dark] .ProseMirror pre .hljs-string,
4042
+ .ds-atom-richtext-surface[data-code-dark] .ProseMirror pre .hljs-attr,
4043
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-string,
4044
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-attr {
4045
+ color: #86efac;
4046
+ }
4047
+ .ds-atom-richtext-surface[data-code-dark] .ProseMirror pre .hljs-built_in,
4048
+ .ds-atom-richtext-surface[data-code-dark] .ProseMirror pre .hljs-title.function_,
4049
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-built_in,
4050
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-title.function_ {
4051
+ color: #7dd3fc;
4052
+ }
4053
+ .ds-atom-richtext-surface[data-code-dark] .ProseMirror pre .hljs-number,
4054
+ .ds-atom-richtext-surface[data-code-dark] .ProseMirror pre .hljs-literal,
4055
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-number,
4056
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-literal {
4057
+ color: #fbbf24;
4058
+ }
4059
+ .ds-atom-richtext-surface[data-code-dark] .ProseMirror pre .hljs-comment,
4060
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-comment {
4061
+ color: #6b7280;
4062
+ font-style: italic;
4063
+ }
4064
+ .ds-atom-richtext-surface[data-code-dark] .ProseMirror pre .hljs-type,
4065
+ .ds-atom-richtext-surface[data-code-dark] .ProseMirror pre .hljs-class .hljs-title,
4066
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-type,
4067
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-class .hljs-title {
4068
+ color: #7dd3fc;
4069
+ }
4070
+ .ds-atom-richtext-surface .ProseMirror pre code {
4071
+ background: none;
4072
+ padding: 0;
4073
+ border-radius: 0;
4074
+ font-family: var(--font-mono);
4075
+ font-size: 12.5px;
4076
+ line-height: 1.65;
4077
+ color: var(--ink);
4078
+ }
4079
+ /* Syntax token colours - light mode */
4080
+ .ds-atom-richtext-surface .ProseMirror pre .hljs-keyword,
4081
+ .ds-atom-richtext-surface .ProseMirror pre .hljs-tag {
4082
+ color: #7c3aed;
4083
+ }
4084
+ .ds-atom-richtext-surface .ProseMirror pre .hljs-string,
4085
+ .ds-atom-richtext-surface .ProseMirror pre .hljs-attr {
4086
+ color: #15803d;
4087
+ }
4088
+ .ds-atom-richtext-surface .ProseMirror pre .hljs-built_in,
4089
+ .ds-atom-richtext-surface .ProseMirror pre .hljs-title.function_ {
4090
+ color: #1d4ed8;
4091
+ }
4092
+ .ds-atom-richtext-surface .ProseMirror pre .hljs-number,
4093
+ .ds-atom-richtext-surface .ProseMirror pre .hljs-literal {
4094
+ color: #b45309;
4095
+ }
4096
+ .ds-atom-richtext-surface .ProseMirror pre .hljs-comment {
4097
+ color: var(--ink-3);
4098
+ font-style: italic;
4099
+ }
4100
+ .ds-atom-richtext-surface .ProseMirror pre .hljs-type,
4101
+ .ds-atom-richtext-surface .ProseMirror pre .hljs-class .hljs-title {
4102
+ color: #0369a1;
4103
+ }
4104
+ /* Syntax token colours - dark mode */
4105
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-keyword,
4106
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-tag {
4107
+ color: #c084fc;
4108
+ }
4109
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-string,
4110
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-attr {
4111
+ color: #86efac;
4112
+ }
4113
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-built_in,
4114
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-title.function_ {
4115
+ color: #7dd3fc;
4116
+ }
4117
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-number,
4118
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-literal {
4119
+ color: #fbbf24;
4120
+ }
4121
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-comment {
4122
+ color: var(--ink-3);
4123
+ font-style: italic;
4124
+ }
4125
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-type,
4126
+ .dark .ds-atom-richtext-surface .ProseMirror pre .hljs-class .hljs-title {
4127
+ color: #7dd3fc;
4128
+ }
4129
+ .dark .ds-atom-richtext-surface .ProseMirror pre {
4130
+ background: var(--cream-3);
4131
+ border-color: var(--rule);
4132
+ }
4133
+ .ds-atom-richtext-surface .ProseMirror blockquote {
4134
+ border-left: 3px solid var(--amber);
4135
+ padding-left: 12px;
4136
+ margin: 8px 0;
4137
+ color: var(--ink-2);
4138
+ }
4139
+ .ds-atom-richtext-surface .ProseMirror ul,
4140
+ .ds-atom-richtext-surface .ProseMirror ol {
4141
+ padding-left: 24px;
4142
+ margin: 8px 0;
4143
+ }
4144
+ .ds-atom-richtext-surface .ProseMirror li + li {
4145
+ margin-top: 2px;
4146
+ }
4147
+ .ds-atom-richtext-surface .ProseMirror hr {
4148
+ border: 0;
4149
+ border-top: 1px solid var(--rule);
4150
+ margin: 12px 0;
4151
+ }
4152
+ .ds-atom-richtext-surface .ProseMirror a {
4153
+ color: var(--amber-d, var(--amber));
4154
+ text-decoration: underline;
4155
+ }
4156
+ .ds-atom-richtext-surface .ProseMirror a:hover {
4157
+ color: var(--amber);
4158
+ }
4159
+
4160
+ /* Placeholder - TipTap Placeholder extension uses data-placeholder + .is-editor-empty */
4161
+ .ds-atom-richtext-surface .ProseMirror p.is-editor-empty:first-child::before {
4162
+ content: attr(data-placeholder);
4163
+ float: left;
4164
+ color: var(--ink-3, var(--ink-2));
4165
+ pointer-events: none;
4166
+ height: 0;
4167
+ }
4168
+
4169
+ /* ── Link popover ─────────────────────────────────────────────────────────── */
4170
+ /* Reset browser <dialog> defaults first, then apply panel styles */
4171
+ .ds-atom-richtext-linkpopover {
4172
+ background: var(--cream-2);
4173
+ border: 1px solid var(--rule);
4174
+ border-radius: 6px;
4175
+ padding: 8px;
4176
+ box-shadow: var(--shadow-3);
4177
+ display: flex;
4178
+ flex-direction: column;
4179
+ gap: 8px;
4180
+ min-width: 280px;
4181
+ z-index: 1050;
4182
+ /* Ensure browser dialog outline/background don't interfere */
4183
+ outline: none;
4184
+ }
4185
+ .ds-atom-richtext-linkinput {
4186
+ appearance: none;
4187
+ width: 100%;
4188
+ padding: 6px 8px;
4189
+ border: 1px solid var(--rule);
4190
+ border-radius: 4px;
4191
+ background: var(--cream);
4192
+ color: var(--ink);
4193
+ font-family: inherit;
4194
+ font-size: 13px;
4195
+ box-sizing: border-box;
4196
+ }
4197
+ .ds-atom-richtext-linkinput:focus {
4198
+ outline: 2px solid var(--amber);
4199
+ outline-offset: -1px;
4200
+ }
4201
+ .ds-atom-richtext-linkactions {
4202
+ display: flex;
4203
+ justify-content: flex-end;
4204
+ gap: 6px;
4205
+ }
4206
+
4207
+ /* ── Dark mode ────────────────────────────────────────────────────────────── */
4208
+ .dark .ds-atom-richtext {
4209
+ background: var(--surf-1);
4210
+ border-color: var(--rule);
4211
+ }
4212
+ .dark .ds-atom-richtext-toolbar {
4213
+ background: var(--surf-2);
4214
+ border-bottom-color: var(--rule);
4215
+ }
4216
+ .dark .ds-atom-richtext-toolbar-divider {
4217
+ background: var(--rule);
4218
+ }
4219
+ .dark .ds-atom-richtext-surface {
4220
+ color: var(--ink);
4221
+ }
4222
+ .dark .ds-atom-richtext-surface .ProseMirror code {
4223
+ background: var(--surf-2);
4224
+ color: var(--ink);
4225
+ }
4226
+ .dark .ds-atom-richtext-surface .ProseMirror blockquote {
4227
+ border-left-color: var(--amber);
4228
+ color: var(--ink-2);
4229
+ }
4230
+ .dark .ds-atom-richtext-headingmenu li button {
4231
+ color: var(--ink);
4232
+ }
4233
+ .dark .ds-atom-richtext-headingmenu li[data-active] button,
4234
+ .dark .ds-atom-richtext-headingmenu li button:hover {
4235
+ background: var(--surf-2);
4236
+ }
4237
+ .dark .ds-atom-richtext-linkpopover {
4238
+ background: var(--cream-2);
4239
+ border-color: var(--rule);
4240
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
4241
+ }
4242
+ .dark .ds-atom-richtext-linkinput {
4243
+ background: var(--cream-3);
4244
+ color: var(--ink);
4245
+ border-color: var(--rule);
4246
+ }
4247
+
4248
+ /* ─── DS atom: AppShell (DS-71) ──────────────────────────────────────────── */
4249
+ .ds-atom-appshell {
4250
+ display: grid;
4251
+ grid-template:
4252
+ "topbar topbar" auto
4253
+ "sidebar main" 1fr
4254
+ / var(--ds-sidebar-w, 240px) 1fr;
4255
+ min-height: 100vh;
4256
+ background: var(--cream);
4257
+ }
4258
+ .ds-atom-appshell-topbar {
4259
+ grid-area: topbar;
4260
+ background: var(--surf-3);
4261
+ border-bottom: 1px solid var(--rule);
4262
+ position: sticky;
4263
+ top: 0;
4264
+ z-index: 10;
4265
+ }
4266
+ .ds-atom-appshell-sidebar {
4267
+ grid-area: sidebar;
4268
+ background: var(--surf-2);
4269
+ border-right: 1px solid var(--rule);
4270
+ overflow: hidden;
4271
+ transition: width 0.25s ease;
4272
+ }
4273
+ .ds-atom-appshell-main {
4274
+ grid-area: main;
4275
+ overflow: auto;
4276
+ }
4277
+ .ds-atom-appshell-footer {
4278
+ grid-column: 2;
4279
+ grid-row: 3;
4280
+ }
4281
+ /* Below 768px: hide sidebar entirely (mobile - bottom tab bar deferred per CONTEXT.md) */
4282
+ @media (max-width: 767px) {
4283
+ .ds-atom-appshell {
4284
+ grid-template:
4285
+ "topbar" auto
4286
+ "main" 1fr
4287
+ / 1fr;
4288
+ }
4289
+ .ds-atom-appshell-sidebar {
4290
+ display: none;
4291
+ }
4292
+ }
4293
+ /* Dark mode */
4294
+ .dark .ds-atom-appshell {
4295
+ background: var(--cream);
4296
+ }
4297
+ .dark .ds-atom-appshell-topbar {
4298
+ background: var(--surf-3);
4299
+ }
4300
+ .dark .ds-atom-appshell-sidebar {
4301
+ background: var(--surf-2);
4302
+ border-right-color: var(--rule);
4303
+ }
4304
+
4305
+ /* ─── DS atom: AppBar (DS-72) ──────────────────────────────────────── */
4306
+ .ds-atom-appbar {
4307
+ display: flex;
4308
+ align-items: center;
4309
+ justify-content: space-between;
4310
+ padding: 12px 20px;
4311
+ background: var(--surf-2);
4312
+ backdrop-filter: blur(14px);
4313
+ border-bottom: 1px solid transparent;
4314
+ box-shadow: none;
4315
+ transition: all 0.2s ease;
4316
+ font-family: var(--font);
4317
+ }
4318
+ .ds-atom-appbar[data-scrolled="true"] {
4319
+ background: rgba(255, 255, 255, 0.92);
4320
+ border-bottom-color: var(--rule);
4321
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
4322
+ }
4323
+ .ds-atom-appbar-search {
4324
+ background: var(--cream-2);
4325
+ border: 1px solid var(--rule);
4326
+ border-radius: 6px;
4327
+ padding: 6px 10px;
4328
+ font-size: 13px;
4329
+ font-family: var(--font);
4330
+ color: var(--ink);
4331
+ outline: none;
4332
+ width: 220px;
4333
+ }
4334
+ .ds-atom-appbar-search:focus {
4335
+ border-color: var(--amber);
4336
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.2);
4337
+ }
4338
+ .dark .ds-atom-appbar[data-scrolled="true"] {
4339
+ background: rgba(28, 25, 23, 0.92);
4340
+ }
4341
+ .dark .ds-atom-appbar-search {
4342
+ background: var(--cream-2);
4343
+ border-color: var(--rule);
4344
+ color: var(--ink);
4345
+ }
4346
+
4347
+ /* ─── DS atom: Footer (DS-73) ──────────────────────────────────────── */
4348
+ .ds-atom-footer {
4349
+ background: var(--cream);
4350
+ border-top: 1px solid var(--rule);
4351
+ font-family: var(--font);
4352
+ color: var(--ink-3);
4353
+ font-size: 12px;
4354
+ text-align: left;
4355
+ }
4356
+ .ds-atom-footer[data-variant="compact"] {
4357
+ padding: 16px 32px;
4358
+ display: flex;
4359
+ justify-content: space-between;
4360
+ align-items: center;
4361
+ gap: 16px;
4362
+ }
4363
+ .ds-atom-footer[data-variant="expanded"] {
4364
+ padding: 40px 32px 24px;
4365
+ }
4366
+ .ds-atom-footer-cols {
4367
+ display: grid;
4368
+ grid-template-columns: repeat(4, 1fr);
4369
+ gap: 32px;
4370
+ margin-bottom: 32px;
4371
+ }
4372
+ .ds-atom-footer-col {
4373
+ text-align: left;
4374
+ display: flex;
4375
+ flex-direction: column;
4376
+ }
4377
+ .ds-atom-footer-col-title {
4378
+ font-family: var(--display);
4379
+ font-size: 10px;
4380
+ font-weight: 700;
4381
+ text-transform: uppercase;
4382
+ letter-spacing: 0.08em;
4383
+ color: var(--ink);
4384
+ margin-bottom: 14px;
4385
+ }
4386
+ .ds-atom-footer-link {
4387
+ display: block;
4388
+ text-align: left;
4389
+ color: var(--ink-3);
4390
+ font-size: 12.5px;
4391
+ line-height: 1;
4392
+ background: none;
4393
+ border: none;
4394
+ cursor: pointer;
4395
+ padding: 5px 0;
4396
+ font-family: var(--font);
4397
+ text-decoration: none;
4398
+ transition: color 0.12s;
4399
+ }
4400
+ .ds-atom-footer-link:hover {
4401
+ color: var(--ink);
4402
+ }
4403
+ .dark .ds-atom-footer {
4404
+ border-top-color: var(--rule);
4405
+ }
4406
+
4407
+ /* ─── DS atom: Illustrations (DS-81) ───────────────────────────────── */
4408
+ /* illustration tokens (--ds-illust-bg, --ds-illust-bg-2, --ds-illust-shadow) live in tokens.css */
4409
+ .dark {
4410
+ --ds-illust-shadow: rgba(255, 255, 255, 0.04);
4411
+ }
4412
+
4413
+ /* ─── DS atom: Wizard (DS-74) ──────────────────────────────────────── */
4414
+ .ds-atom-wizard {
4415
+ display: flex;
4416
+ flex-direction: column;
4417
+ gap: 20px;
4418
+ font-family: var(--font);
4419
+ }
4420
+ .ds-atom-wizard-stepper {
4421
+ display: flex;
4422
+ align-items: center;
4423
+ }
4424
+ .ds-atom-wizard[data-orientation="vertical"] .ds-atom-wizard-stepper {
4425
+ flex-direction: column;
4426
+ align-items: flex-start;
4427
+ }
4428
+ .ds-atom-wizard-connector {
4429
+ flex: 1;
4430
+ height: 1px;
4431
+ background: var(--rule);
4432
+ margin: 0 8px;
4433
+ }
4434
+ .ds-atom-wizard[data-orientation="vertical"] .ds-atom-wizard-connector {
4435
+ width: 1px;
4436
+ height: 20px;
4437
+ flex: none;
4438
+ margin: 4px 13px;
4439
+ }
4440
+ .ds-atom-wizard-step {
4441
+ display: flex;
4442
+ align-items: center;
4443
+ gap: 10px;
4444
+ flex-shrink: 0;
4445
+ }
4446
+ .ds-atom-wizard-step-text {
4447
+ display: flex;
4448
+ flex-direction: column;
4449
+ gap: 1px;
4450
+ }
4451
+ .ds-atom-wizard-dot {
4452
+ width: 28px;
4453
+ height: 28px;
4454
+ border-radius: 50%;
4455
+ display: flex;
4456
+ align-items: center;
4457
+ justify-content: center;
4458
+ font-family: var(--mono);
4459
+ font-size: 11px;
4460
+ font-weight: 700;
4461
+ transition: all 0.25s ease;
4462
+ flex-shrink: 0;
4463
+ }
4464
+ .ds-atom-wizard-step[data-status="done"] .ds-atom-wizard-dot {
4465
+ background: var(--green-vivid);
4466
+ color: var(--cream);
4467
+ }
4468
+ .ds-atom-wizard-step[data-status="active"] .ds-atom-wizard-dot {
4469
+ background: var(--amber);
4470
+ color: var(--cream);
4471
+ }
4472
+ .ds-atom-wizard-step[data-status="pending"] .ds-atom-wizard-dot {
4473
+ background: var(--cream-2);
4474
+ color: var(--ink-4);
4475
+ border: 2px solid var(--ink-5);
4476
+ }
4477
+ .ds-atom-wizard-label {
4478
+ font-family: var(--display);
4479
+ font-weight: 700;
4480
+ font-size: 12.5px;
4481
+ color: var(--ink);
4482
+ transition: color 0.15s;
4483
+ }
4484
+ .ds-atom-wizard-step[data-status="pending"] .ds-atom-wizard-label {
4485
+ color: var(--ink-4);
4486
+ font-weight: 500;
4487
+ }
4488
+ .ds-atom-wizard-desc {
4489
+ font-size: 11px;
4490
+ color: var(--ink-4);
4491
+ }
4492
+ .ds-atom-wizard-content {
4493
+ min-height: 40px;
4494
+ }
4495
+ .ds-atom-wizard-error {
4496
+ font-size: 12px;
4497
+ color: var(--red);
4498
+ padding: 8px 12px;
4499
+ background: rgba(239, 68, 68, 0.08);
4500
+ border-radius: 6px;
4501
+ border: 1px solid rgba(239, 68, 68, 0.2);
4502
+ }
4503
+ .ds-atom-wizard-nav {
4504
+ display: flex;
4505
+ gap: 8px;
4506
+ justify-content: flex-end;
4507
+ }
4508
+ .dark .ds-atom-wizard-step[data-status="pending"] .ds-atom-wizard-dot {
4509
+ background: rgba(255, 255, 255, 0.06);
4510
+ border-color: var(--ink-5);
4511
+ }
4512
+
4513
+ /* ─── DS atom: FormValidation (DS-75) ──────────────────────────────── */
4514
+ .ds-atom-pwstrength {
4515
+ display: flex;
4516
+ flex-direction: column;
4517
+ gap: 6px;
4518
+ }
4519
+ .ds-atom-pwstrength-segs {
4520
+ display: flex;
4521
+ gap: 4px;
4522
+ }
4523
+ .ds-atom-pwstrength-seg {
4524
+ flex: 1;
4525
+ height: 4px;
4526
+ border-radius: 2px;
4527
+ background: var(--ink-5);
4528
+ transition: background 0.2s ease;
4529
+ }
4530
+ .ds-atom-pwstrength-label {
4531
+ font-size: 11px;
4532
+ font-family: var(--font);
4533
+ font-weight: 600;
4534
+ }
4535
+ .ds-atom-field-error {
4536
+ font-size: 12px;
4537
+ color: var(--red);
4538
+ font-family: var(--font);
4539
+ display: block;
4540
+ margin-top: 4px;
4541
+ }
4542
+ .ds-atom-form-error-summary {
4543
+ background: rgba(239, 68, 68, 0.08);
4544
+ border: 1px solid rgba(239, 68, 68, 0.2);
4545
+ border-radius: 8px;
4546
+ padding: 12px 16px;
4547
+ font-family: var(--font);
4548
+ font-size: 13px;
4549
+ color: var(--ink);
4550
+ }
4551
+ .ds-atom-form-error-summary ul {
4552
+ margin: 6px 0 0 0;
4553
+ padding-left: 16px;
4554
+ color: var(--red);
4555
+ font-size: 12px;
4556
+ }
4557
+
4558
+ /* ─── DS atom: Coachmark (DS-76) ───────────────────────────────────── */
4559
+ .ds-atom-coachmark {
4560
+ padding: 14px 16px;
4561
+ max-width: 260px;
4562
+ display: flex;
4563
+ flex-direction: column;
4564
+ gap: 8px;
4565
+ }
4566
+ /* Header row: title + dismiss button side by side */
4567
+ .ds-atom-coachmark-header {
4568
+ display: flex;
4569
+ align-items: flex-start;
4570
+ justify-content: space-between;
4571
+ gap: 8px;
4572
+ }
4573
+ .ds-atom-coachmark-title {
4574
+ font-family: var(--display);
4575
+ font-weight: 700;
4576
+ font-size: 13px;
4577
+ color: var(--ink);
4578
+ flex: 1;
4579
+ line-height: 1.4;
4580
+ }
4581
+ .ds-atom-coachmark-desc {
4582
+ font-size: 12px;
4583
+ color: var(--ink-3);
4584
+ line-height: 1.5;
4585
+ }
4586
+ /* Footer row: dots left, action button right */
4587
+ .ds-atom-coachmark-footer {
4588
+ display: flex;
4589
+ align-items: center;
4590
+ justify-content: space-between;
4591
+ gap: 8px;
4592
+ margin-top: 4px;
4593
+ }
4594
+ .ds-atom-coachmark-dots {
4595
+ display: flex;
4596
+ gap: 5px;
4597
+ align-items: center;
4598
+ }
4599
+ .ds-atom-coachmark-dot {
4600
+ width: 6px;
4601
+ height: 6px;
4602
+ border-radius: 50%;
4603
+ background: var(--ink-5);
4604
+ transition: background 0.2s ease;
4605
+ }
4606
+ .ds-atom-coachmark-dot[data-active="true"] {
4607
+ background: var(--amber);
4608
+ }
4609
+ .ds-atom-coachmark-actions {
4610
+ display: flex;
4611
+ align-items: center;
4612
+ gap: 6px;
4613
+ }
4614
+ .dark .ds-atom-coachmark-title {
4615
+ color: var(--ink);
4616
+ }
4617
+
4618
+ /* ─── DS atom: InlineEdit (DS-77) ──────────────────────────────────── */
4619
+ .ds-atom-inlineedit {
4620
+ cursor: pointer;
4621
+ border-radius: 4px;
4622
+ padding: 2px 4px;
4623
+ font-family: var(--font);
4624
+ font-size: inherit;
4625
+ color: var(--ink);
4626
+ transition: background 0.15s ease;
4627
+ }
4628
+ .ds-atom-inlineedit:hover {
4629
+ background: var(--cream-2);
4630
+ }
4631
+ .ds-atom-inlineedit:focus-visible {
4632
+ outline: none;
4633
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.25);
4634
+ }
4635
+ .ds-atom-inlineedit-wrap {
4636
+ display: inline-flex;
4637
+ flex-direction: column;
4638
+ width: 100%;
4639
+ }
4640
+ .ds-atom-inlineedit-input {
4641
+ border: 1px solid var(--amber);
4642
+ border-radius: 4px;
4643
+ padding: 2px 6px;
4644
+ font-family: var(--font);
4645
+ font-size: inherit;
4646
+ color: var(--ink);
4647
+ background: var(--cream);
4648
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.2);
4649
+ outline: none;
4650
+ width: 100%;
4651
+ box-sizing: border-box;
4652
+ }
4653
+ .ds-atom-inlineedit-input:disabled {
4654
+ opacity: 0.6;
4655
+ cursor: not-allowed;
4656
+ }
4657
+ .ds-atom-inlineedit-error {
4658
+ font-size: 11px;
4659
+ color: var(--red);
4660
+ margin-top: 4px;
4661
+ }
4662
+ .dark .ds-atom-inlineedit:hover {
4663
+ background: var(--cream-3);
4664
+ }
4665
+ .dark .ds-atom-inlineedit-input {
4666
+ background: var(--cream-2);
4667
+ color: var(--ink);
4668
+ }
4669
+
4670
+ /* ─── DS atom: SearchAndFilters (DS-78) ────────────────────────────── */
4671
+ .ds-atom-searchfilters {
4672
+ display: flex;
4673
+ flex-direction: column;
4674
+ gap: 8px;
4675
+ font-family: var(--font);
4676
+ }
4677
+ .ds-atom-searchfilters-bar {
4678
+ display: flex;
4679
+ align-items: center;
4680
+ gap: 8px;
4681
+ }
4682
+ .ds-atom-searchfilters-input {
4683
+ flex: 1;
4684
+ padding: 8px 12px;
4685
+ border: 1px solid var(--rule);
4686
+ border-radius: 8px;
4687
+ background: var(--cream-2);
4688
+ color: var(--ink);
4689
+ font-size: 13px;
4690
+ font-family: var(--font);
4691
+ outline: none;
4692
+ transition: border-color 0.15s, box-shadow 0.15s;
4693
+ }
4694
+ .ds-atom-searchfilters-input:focus {
4695
+ border-color: var(--amber);
4696
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.2);
4697
+ }
4698
+ .ds-atom-searchfilters-clear {
4699
+ font-size: 12px;
4700
+ color: var(--ink-3);
4701
+ background: none;
4702
+ border: none;
4703
+ cursor: pointer;
4704
+ font-family: var(--font);
4705
+ white-space: nowrap;
4706
+ padding: 0;
4707
+ }
4708
+ .ds-atom-searchfilters-clear:hover {
4709
+ color: var(--ink);
4710
+ }
4711
+ .ds-atom-searchfilters-chips {
4712
+ display: flex;
4713
+ flex-wrap: wrap;
4714
+ gap: 6px;
4715
+ }
4716
+ .ds-atom-searchfilters-option {
4717
+ padding: 8px 12px;
4718
+ font-size: 13px;
4719
+ cursor: pointer;
4720
+ color: var(--ink);
4721
+ }
4722
+ .ds-atom-searchfilters-option[data-active="true"] {
4723
+ background: var(--cream-2);
4724
+ }
4725
+ .dark .ds-atom-searchfilters-input {
4726
+ background: var(--cream-2);
4727
+ border-color: var(--rule);
4728
+ color: var(--ink);
4729
+ }
4730
+
4731
+ /* ─── DS atom: Sortable (DS-80) ────────────────────────────────────── */
4732
+ .ds-atom-sortable {
4733
+ display: flex;
4734
+ flex-direction: column;
4735
+ gap: 4px;
4736
+ }
4737
+ .ds-atom-sortable-item {
4738
+ user-select: none;
4739
+ cursor: grab;
4740
+ border-radius: 6px;
4741
+ transition: box-shadow 0.15s ease;
4742
+ }
4743
+ .ds-atom-sortable-item:focus-visible {
4744
+ outline: none;
4745
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.35);
4746
+ }
4747
+ .ds-atom-sortable-item[data-dragging="true"] {
4748
+ /* Source slot becomes a dotted amber outline - content hidden, space preserved */
4749
+ border: 2px dashed var(--amber) !important;
4750
+ background: rgba(245, 158, 11, 0.06) !important;
4751
+ box-shadow: none;
4752
+ cursor: grabbing;
4753
+ border-radius: 6px;
4754
+ }
4755
+ .ds-atom-sortable-item[data-dragging="true"] > * {
4756
+ opacity: 0;
4757
+ }
4758
+ .ds-atom-sortable-overlay {
4759
+ pointer-events: none;
4760
+ opacity: 0.92;
4761
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.14), 0 2px 8px rgba(0, 0, 0, 0.08);
4762
+ border-radius: 6px;
4763
+ cursor: grabbing;
4764
+ transform: scale(1.02);
4765
+ }
4766
+ /* Ghost placeholder for SortableDndContext without a renderOverlay prop */
4767
+ .ds-atom-sortable-overlay-ghost {
4768
+ height: 40px;
4769
+ border-radius: 6px;
4770
+ background: var(--amber);
4771
+ opacity: 0.18;
4772
+ }
4773
+ .dark .ds-atom-sortable-item {
4774
+ /* tokens flip automatically - no override needed */
4775
+ }