@digiko-npm/designsystem 0.3.34 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- /* @ds/designsystem v0.3.34 */
1
+ /* @ds/designsystem v0.4.0 */
2
2
  /* ==========================================================================
3
3
  @digiko-npm/designsystem
4
4
 
@@ -711,8 +711,8 @@ hr {
711
711
  }
712
712
 
713
713
  .ds-btn:focus-visible {
714
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
715
- outline-offset: var(--ds-ring-offset);
714
+ outline: none;
715
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
716
716
  }
717
717
 
718
718
  .ds-btn:disabled,
@@ -895,8 +895,11 @@ hr {
895
895
  transform: translateY(-4px);
896
896
  }
897
897
  .ds-card--interactive:focus-visible {
898
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
899
- outline-offset: var(--ds-ring-offset);
898
+ outline: none;
899
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
900
+ }
901
+ .ds-card--interactive:hover:focus-visible {
902
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color), var(--ds-shadow-lg);
900
903
  }
901
904
 
902
905
  /* Elevated card — visible shadow */
@@ -948,6 +951,9 @@ hr {
948
951
  object-fit: cover;
949
952
  background-color: var(--ds-color-bg-elevated);
950
953
  }
954
+ .ds-card__media--square { aspect-ratio: 1; }
955
+ .ds-card__media--video { aspect-ratio: 16/9; }
956
+ .ds-card__media--auto { aspect-ratio: auto; }
951
957
 
952
958
  /* Compact */
953
959
  .ds-card--compact .ds-card__header,
@@ -1011,10 +1017,14 @@ hr {
1011
1017
  margin-bottom: var(--ds-space-1-5);
1012
1018
  }
1013
1019
 
1020
+ .ds-input,
1021
+ .ds-textarea {
1022
+ width: 100%;
1023
+ }
1024
+
1014
1025
  .ds-input,
1015
1026
  .ds-textarea,
1016
1027
  .ds-select {
1017
- width: 100%;
1018
1028
  padding: 0 var(--ds-space-4);
1019
1029
  font-family: var(--ds-font-sans);
1020
1030
  font-size: var(--ds-text-base); /* 16px — prevents iOS auto-zoom on focus */
@@ -1130,6 +1140,50 @@ hr {
1130
1140
  padding-right: var(--ds-space-8);
1131
1141
  }
1132
1142
 
1143
+ /* --- Layout Modifiers ---
1144
+ Override default width/display/chrome assumptions. */
1145
+
1146
+ /* Full width (opt-in for select, already default for input/textarea) */
1147
+ .ds-select--full {
1148
+ width: 100%;
1149
+ }
1150
+
1151
+ /* Flush — naked input inside a styled container.
1152
+ No border, no background, no padding, no focus ring.
1153
+ The container handles visual chrome. */
1154
+ .ds-input--flush {
1155
+ background: transparent;
1156
+ border: none;
1157
+ padding: 0;
1158
+ border-radius: 0;
1159
+ box-shadow: none;
1160
+ height: auto;
1161
+ }
1162
+ .ds-input--flush:hover {
1163
+ border-color: transparent;
1164
+ }
1165
+ .ds-input--flush:focus-visible {
1166
+ border-color: transparent;
1167
+ box-shadow: none;
1168
+ }
1169
+
1170
+ /* Inline — auto-width for use in flex rows */
1171
+ .ds-input--inline {
1172
+ width: auto;
1173
+ display: inline-flex;
1174
+ }
1175
+
1176
+ /* --- Input Group: icon-right ---
1177
+ Move icon to the right side, flip input padding. */
1178
+ .ds-input-group--icon-right .ds-input-group__icon {
1179
+ left: auto;
1180
+ right: var(--ds-space-3);
1181
+ }
1182
+ .ds-input-group--icon-right .ds-input {
1183
+ padding-left: var(--ds-space-4);
1184
+ padding-right: calc(var(--ds-space-3) + 1rem + var(--ds-space-2));
1185
+ }
1186
+
1133
1187
  /* Help text */
1134
1188
  .ds-help {
1135
1189
  font-size: var(--ds-text-xs);
@@ -1336,8 +1390,8 @@ hr {
1336
1390
  }
1337
1391
 
1338
1392
  .ds-nav__link:focus-visible {
1339
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
1340
- outline-offset: var(--ds-ring-offset);
1393
+ outline: none;
1394
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
1341
1395
  }
1342
1396
 
1343
1397
  .ds-nav__link--active {
@@ -1370,8 +1424,8 @@ hr {
1370
1424
  }
1371
1425
 
1372
1426
  .ds-nav__icon-btn:focus-visible {
1373
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
1374
- outline-offset: var(--ds-ring-offset);
1427
+ outline: none;
1428
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
1375
1429
  }
1376
1430
 
1377
1431
  /* --- Mobile nav overlay --- */
@@ -1449,8 +1503,8 @@ hr {
1449
1503
  }
1450
1504
 
1451
1505
  .ds-sidebar__link:focus-visible {
1452
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
1453
- outline-offset: calc(-1 * var(--ds-ring-offset));
1506
+ outline: none;
1507
+ box-shadow: inset 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
1454
1508
  }
1455
1509
 
1456
1510
  .ds-sidebar__link--active {
@@ -1543,8 +1597,8 @@ hr {
1543
1597
  color: var(--ds-color-text);
1544
1598
  }
1545
1599
  .ds-modal__close:focus-visible {
1546
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
1547
- outline-offset: var(--ds-ring-offset);
1600
+ outline: none;
1601
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
1548
1602
  }
1549
1603
 
1550
1604
  .ds-modal__body {
@@ -1566,6 +1620,24 @@ hr {
1566
1620
  .ds-modal--md .ds-modal__content { max-width: var(--ds-container-md); }
1567
1621
  .ds-modal--lg .ds-modal__content { max-width: var(--ds-container-lg); }
1568
1622
 
1623
+ /* Fullscreen on mobile */
1624
+ @media (max-width: 1023px) {
1625
+ .ds-modal--fullscreen-mobile .ds-modal__content {
1626
+ max-width: none;
1627
+ max-height: none;
1628
+ width: 100%;
1629
+ height: 100dvh;
1630
+ margin: 0;
1631
+ border-radius: 0;
1632
+ border: none;
1633
+ box-shadow: none;
1634
+ }
1635
+
1636
+ .ds-modal--fullscreen-mobile {
1637
+ padding: 0;
1638
+ }
1639
+ }
1640
+
1569
1641
  /* ==========================================================================
1570
1642
  Component: Toast
1571
1643
  ========================================================================== */
@@ -1624,8 +1696,8 @@ hr {
1624
1696
  color: var(--ds-color-text);
1625
1697
  }
1626
1698
  .ds-toast__close:focus-visible {
1627
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
1628
- outline-offset: var(--ds-ring-offset);
1699
+ outline: none;
1700
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
1629
1701
  }
1630
1702
 
1631
1703
  @keyframes ds-toast-in {
@@ -1805,8 +1877,8 @@ hr {
1805
1877
  }
1806
1878
 
1807
1879
  .ds-tab:focus-visible {
1808
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
1809
- outline-offset: var(--ds-ring-offset);
1880
+ outline: none;
1881
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
1810
1882
  border-radius: var(--ds-radius-sm);
1811
1883
  }
1812
1884
 
@@ -1970,8 +2042,8 @@ hr {
1970
2042
  }
1971
2043
 
1972
2044
  .ds-alert__close:focus-visible {
1973
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
1974
- outline-offset: var(--ds-ring-offset);
2045
+ outline: none;
2046
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
1975
2047
  }
1976
2048
 
1977
2049
  /* --- Compact Variant --- */
@@ -2144,6 +2216,11 @@ hr {
2144
2216
  transform-origin: bottom right;
2145
2217
  }
2146
2218
 
2219
+ /* --- Width variants --- */
2220
+ .ds-dropdown__menu--sm { min-width: 8rem; }
2221
+ .ds-dropdown__menu--lg { min-width: 20rem; }
2222
+ .ds-dropdown__menu--auto { min-width: auto; }
2223
+
2147
2224
  /* --- Menu item --- */
2148
2225
 
2149
2226
  .ds-dropdown__item {
@@ -2167,8 +2244,8 @@ hr {
2167
2244
  color: var(--ds-color-text);
2168
2245
  }
2169
2246
  .ds-dropdown__item:focus-visible {
2170
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
2171
- outline-offset: calc(-1 * var(--ds-ring-offset));
2247
+ outline: none;
2248
+ box-shadow: inset 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
2172
2249
  }
2173
2250
 
2174
2251
  .ds-dropdown__item--active {
@@ -2666,6 +2743,12 @@ hr {
2666
2743
  border-radius: var(--ds-radius-xl);
2667
2744
  }
2668
2745
 
2746
+ /* --- Left-aligned variant --- */
2747
+ .ds-empty-state--left {
2748
+ align-items: flex-start;
2749
+ text-align: left;
2750
+ }
2751
+
2669
2752
 
2670
2753
  /* === Tier 2 — Common === */
2671
2754
  /* ==========================================================================
@@ -2728,8 +2811,8 @@ hr {
2728
2811
  }
2729
2812
 
2730
2813
  .ds-datepicker__trigger:focus-visible {
2731
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
2732
- outline-offset: var(--ds-ring-offset);
2814
+ outline: none;
2815
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
2733
2816
  }
2734
2817
 
2735
2818
  /* Calendar panel */
@@ -2795,8 +2878,8 @@ hr {
2795
2878
  color: var(--ds-color-text);
2796
2879
  }
2797
2880
  .ds-datepicker__nav:focus-visible {
2798
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
2799
- outline-offset: calc(-1 * var(--ds-ring-offset));
2881
+ outline: none;
2882
+ box-shadow: inset 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
2800
2883
  }
2801
2884
 
2802
2885
  /* Weekday header row */
@@ -2844,8 +2927,8 @@ hr {
2844
2927
  background-color: var(--ds-color-bg-elevated);
2845
2928
  }
2846
2929
  .ds-datepicker__day:focus-visible {
2847
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
2848
- outline-offset: calc(-1 * var(--ds-ring-offset));
2930
+ outline: none;
2931
+ box-shadow: inset 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
2849
2932
  }
2850
2933
 
2851
2934
  /* Today — subtle ring */
@@ -2899,8 +2982,8 @@ hr {
2899
2982
  border-color: var(--ds-color-border-hover);
2900
2983
  }
2901
2984
  .ds-datepicker__today:focus-visible {
2902
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
2903
- outline-offset: var(--ds-ring-offset);
2985
+ outline: none;
2986
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
2904
2987
  }
2905
2988
 
2906
2989
  /* Step arrows — prev/next day buttons beside the date text */
@@ -2926,8 +3009,8 @@ hr {
2926
3009
  color: var(--ds-color-text);
2927
3010
  }
2928
3011
  .ds-datepicker__step:focus-visible {
2929
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
2930
- outline-offset: calc(-1 * var(--ds-ring-offset));
3012
+ outline: none;
3013
+ box-shadow: inset 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
2931
3014
  }
2932
3015
 
2933
3016
  /* Compact mode — for inline table cells */
@@ -3049,8 +3132,8 @@ hr {
3049
3132
  --------------------------------------------------------------------------- */
3050
3133
 
3051
3134
  .ds-toggle:focus-visible {
3052
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
3053
- outline-offset: var(--ds-ring-offset);
3135
+ outline: none;
3136
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
3054
3137
  }
3055
3138
 
3056
3139
  /* ---------------------------------------------------------------------------
@@ -3169,8 +3252,8 @@ hr {
3169
3252
  }
3170
3253
 
3171
3254
  .ds-breadcrumb__link:focus-visible {
3172
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
3173
- outline-offset: var(--ds-ring-offset);
3255
+ outline: none;
3256
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
3174
3257
  border-radius: var(--ds-radius-sm);
3175
3258
  }
3176
3259
 
@@ -3255,8 +3338,8 @@ hr {
3255
3338
  }
3256
3339
 
3257
3340
  .ds-pagination__item:focus-visible {
3258
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
3259
- outline-offset: var(--ds-ring-offset);
3341
+ outline: none;
3342
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
3260
3343
  }
3261
3344
 
3262
3345
  /* ---------------------------------------------------------------------------
@@ -3314,8 +3397,8 @@ hr {
3314
3397
 
3315
3398
  .ds-pagination__prev:focus-visible,
3316
3399
  .ds-pagination__next:focus-visible {
3317
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
3318
- outline-offset: var(--ds-ring-offset);
3400
+ outline: none;
3401
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
3319
3402
  }
3320
3403
 
3321
3404
  .ds-pagination__prev:disabled,
@@ -3407,6 +3490,7 @@ hr {
3407
3490
  /* Tags used as <button> for selection — no focus ring on click */
3408
3491
  button.ds-tag:focus-visible {
3409
3492
  outline: none;
3493
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
3410
3494
  }
3411
3495
 
3412
3496
  /* ---------------------------------------------------------------------------
@@ -3489,8 +3573,8 @@ button.ds-tag:focus-visible {
3489
3573
  }
3490
3574
 
3491
3575
  .ds-tag__remove:focus-visible {
3492
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
3493
- outline-offset: var(--ds-ring-offset);
3576
+ outline: none;
3577
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
3494
3578
  opacity: 1;
3495
3579
  }
3496
3580
 
@@ -3611,8 +3695,8 @@ button.ds-tag:focus-visible {
3611
3695
  background-color: var(--ds-color-overlay);
3612
3696
  }
3613
3697
  .ds-accordion__trigger:focus-visible {
3614
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
3615
- outline-offset: var(--ds-ring-offset);
3698
+ outline: none;
3699
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
3616
3700
  }
3617
3701
 
3618
3702
  /* Open state – rotate chevron */
@@ -3875,8 +3959,8 @@ button.ds-tag:focus-visible {
3875
3959
  color: var(--ds-color-text);
3876
3960
  }
3877
3961
  .ds-drawer__close:focus-visible {
3878
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
3879
- outline-offset: var(--ds-ring-offset);
3962
+ outline: none;
3963
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
3880
3964
  }
3881
3965
 
3882
3966
  /* ==========================================================================
@@ -4163,8 +4247,8 @@ button.ds-tag:focus-visible {
4163
4247
  background-color var(--ds-duration-fast) var(--ds-ease-default);
4164
4248
  }
4165
4249
  .ds-drop-zone:focus-visible {
4166
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
4167
- outline-offset: var(--ds-ring-offset);
4250
+ outline: none;
4251
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
4168
4252
  }
4169
4253
 
4170
4254
  :root:not(.dark) .ds-drop-zone {
@@ -4299,8 +4383,8 @@ button.ds-tag:focus-visible {
4299
4383
 
4300
4384
  .ds-custom-select__trigger:focus-visible {
4301
4385
  border-color: var(--ds-color-border-active);
4302
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
4303
- outline-offset: -1px;
4386
+ outline: none;
4387
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
4304
4388
  }
4305
4389
 
4306
4390
  .ds-custom-select__trigger--open {
@@ -4467,8 +4551,8 @@ button.ds-tag:focus-visible {
4467
4551
  color: var(--ds-color-text);
4468
4552
  }
4469
4553
  .ds-custom-select__option:focus-visible {
4470
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
4471
- outline-offset: calc(-1 * var(--ds-ring-offset));
4554
+ outline: none;
4555
+ box-shadow: inset 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
4472
4556
  }
4473
4557
 
4474
4558
  .ds-custom-select__option--selected {
@@ -4621,6 +4705,12 @@ tr:hover .ds-sortable__handle,
4621
4705
  opacity: 1;
4622
4706
  }
4623
4707
 
4708
+ .ds-sortable__handle:focus-visible {
4709
+ outline: none;
4710
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
4711
+ border-radius: var(--ds-radius-sm);
4712
+ }
4713
+
4624
4714
  tr:hover .ds-sortable__handle,
4625
4715
  .ds-sortable-row:hover .ds-sortable__handle {
4626
4716
  color: var(--ds-color-text-secondary);
@@ -4831,12 +4921,12 @@ tr:hover .ds-sortable__handle,
4831
4921
  /* Focus ring */
4832
4922
  .ds-slider input[type="range"]:focus-visible::-webkit-slider-thumb {
4833
4923
  outline: var(--ds-ring-width) solid var(--ds-ring-color);
4834
- outline-offset: var(--ds-ring-offset);
4924
+ outline-offset: 0;
4835
4925
  }
4836
4926
 
4837
4927
  .ds-slider input[type="range"]:focus-visible::-moz-range-thumb {
4838
4928
  outline: var(--ds-ring-width) solid var(--ds-ring-color);
4839
- outline-offset: var(--ds-ring-offset);
4929
+ outline-offset: 0;
4840
4930
  }
4841
4931
 
4842
4932
  /* Labels row */
@@ -5215,8 +5305,8 @@ tr:hover .ds-sortable__handle,
5215
5305
  color: var(--ds-color-text);
5216
5306
  }
5217
5307
  .ds-command__item:focus-visible {
5218
- outline: var(--ds-ring-width) solid var(--ds-ring-color);
5219
- outline-offset: calc(-1 * var(--ds-ring-offset));
5308
+ outline: none;
5309
+ box-shadow: inset 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
5220
5310
  }
5221
5311
 
5222
5312
  /* Item icon */
@@ -5256,102 +5346,940 @@ tr:hover .ds-sortable__handle,
5256
5346
  color: var(--ds-color-text-tertiary);
5257
5347
  }
5258
5348
 
5259
-
5260
5349
  /* ==========================================================================
5261
- Utilities: Layout
5262
- Container with clamp padding, generous responsive grid.
5350
+ Component: Search
5351
+ Inline search bar with dropdown results, keyboard navigation, and
5352
+ responsive mobile expansion. Distinct from ds-command (modal overlay).
5353
+
5354
+ Usage:
5355
+ <div class="ds-search">
5356
+ <span class="ds-search__icon">...</span>
5357
+ <input class="ds-search__input" placeholder="Search..." />
5358
+ <kbd class="ds-search__shortcut">Ctrl+K</kbd>
5359
+ <button class="ds-search__clear">...</button>
5360
+ </div>
5361
+ <div class="ds-search__dropdown">
5362
+ <div class="ds-search__group">
5363
+ <span class="ds-search__group-label">Pages</span>
5364
+ <button class="ds-search__result ds-search__result--active">
5365
+ <span class="ds-search__result-icon">...</span>
5366
+ <div class="ds-search__result-content">
5367
+ <span class="ds-search__result-title">Page name</span>
5368
+ <span class="ds-search__result-meta">Database</span>
5369
+ </div>
5370
+ </button>
5371
+ </div>
5372
+ <div class="ds-search__empty">No results found.</div>
5373
+ </div>
5374
+
5375
+ Modifiers:
5376
+ .ds-search--mobile-expanded — Fullscreen bar on mobile
5377
+ .ds-search__dropdown--mobile — Fullscreen dropdown on mobile
5378
+
5379
+ Mobile:
5380
+ .ds-search-mobile-trigger — Icon button shown on mobile (hidden desktop)
5381
+ .ds-search__close — Close button inside expanded mobile bar
5263
5382
  ========================================================================== */
5264
5383
 
5265
- /* --- Container --- */
5266
- .ds-container {
5384
+ .ds-search {
5385
+ position: relative;
5386
+ display: flex;
5387
+ align-items: center;
5388
+ gap: var(--ds-space-1);
5267
5389
  width: 100%;
5268
- max-width: var(--ds-container-max);
5269
- margin-inline: auto;
5270
- padding-inline: var(--ds-container-padding);
5390
+ padding: var(--ds-space-2) var(--ds-space-2-5);
5391
+ background: var(--ds-color-surface);
5392
+ border: 1px solid var(--ds-color-border);
5393
+ border-radius: var(--ds-radius-lg);
5394
+ transition:
5395
+ border-color var(--ds-duration-fast) var(--ds-ease-default),
5396
+ box-shadow var(--ds-duration-fast) var(--ds-ease-default);
5271
5397
  }
5272
5398
 
5273
- /* --- Section (generous vertical rhythm) --- */
5274
- .ds-section {
5275
- padding-block: var(--ds-section-padding);
5399
+ .ds-search:focus-within {
5400
+ border-color: var(--ds-color-border-active);
5401
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
5276
5402
  }
5277
5403
 
5278
- /* --- Flex --- */
5279
- .ds-flex { display: flex; }
5280
- .ds-inline-flex { display: inline-flex; }
5281
- .ds-flex-col { flex-direction: column; }
5282
- .ds-flex-row { flex-direction: row; }
5283
- .ds-flex-wrap { flex-wrap: wrap; }
5284
- .ds-flex-1 { flex: 1 1 0%; }
5285
- .ds-flex-auto { flex: 1 1 auto; }
5286
- .ds-flex-none { flex: none; }
5287
- .ds-shrink-0 { flex-shrink: 0; }
5288
-
5289
- /* --- Alignment --- */
5290
- .ds-items-start { align-items: flex-start; }
5291
- .ds-items-center { align-items: center; }
5292
- .ds-items-end { align-items: flex-end; }
5293
- .ds-items-stretch { align-items: stretch; }
5294
- .ds-items-baseline { align-items: baseline; }
5295
-
5296
- .ds-justify-start { justify-content: flex-start; }
5297
- .ds-justify-center { justify-content: center; }
5298
- .ds-justify-end { justify-content: flex-end; }
5299
- .ds-justify-between { justify-content: space-between; }
5300
- .ds-justify-around { justify-content: space-around; }
5301
- .ds-justify-evenly { justify-content: space-evenly; }
5302
-
5303
- .ds-self-start { align-self: flex-start; }
5304
- .ds-self-center { align-self: center; }
5305
- .ds-self-end { align-self: flex-end; }
5306
-
5307
- /* --- Grid --- */
5308
- .ds-grid {
5309
- display: grid;
5310
- gap: var(--ds-space-6);
5404
+ /* Icon */
5405
+ .ds-search__icon {
5406
+ color: var(--ds-color-text-tertiary);
5407
+ flex-shrink: 0;
5311
5408
  }
5312
5409
 
5313
- .ds-grid-cols-1 { grid-template-columns: repeat(1, 1fr); }
5314
- .ds-grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
5315
- .ds-grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
5316
- .ds-grid-cols-4 { grid-template-columns: repeat(4, 1fr); }
5317
-
5318
- /* --- Column Span --- */
5319
- .ds-col-span-1 { grid-column: span 1 / span 1; }
5320
- .ds-col-span-2 { grid-column: span 2 / span 2; }
5321
- .ds-col-span-3 { grid-column: span 3 / span 3; }
5322
- .ds-col-span-4 { grid-column: span 4 / span 4; }
5323
- .ds-col-span-full { grid-column: 1 / -1; }
5324
-
5325
- @media (min-width: 640px) {
5326
- .ds-sm\:grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
5327
- .ds-sm\:grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
5410
+ /* Input */
5411
+ .ds-search__input {
5412
+ flex: 1;
5413
+ min-width: 0;
5414
+ border: none;
5415
+ outline: none;
5416
+ background: transparent;
5417
+ color: var(--ds-color-text);
5418
+ font-size: var(--ds-text-base);
5419
+ font-family: inherit;
5420
+ line-height: 1.25;
5328
5421
  }
5329
5422
 
5330
- @media (min-width: 768px) {
5331
- .ds-md\:grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
5332
- .ds-md\:grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
5333
- .ds-md\:grid-cols-4 { grid-template-columns: repeat(4, 1fr); }
5334
- .ds-md\:col-span-1 { grid-column: span 1 / span 1; }
5335
- .ds-md\:col-span-2 { grid-column: span 2 / span 2; }
5336
- .ds-md\:col-span-3 { grid-column: span 3 / span 3; }
5337
- .ds-md\:flex-row { flex-direction: row; }
5423
+ .ds-search__input::placeholder {
5424
+ color: var(--ds-color-text-tertiary);
5338
5425
  }
5339
5426
 
5340
- @media (min-width: 1024px) {
5341
- .ds-lg\:grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
5342
- .ds-lg\:grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
5343
- .ds-lg\:grid-cols-4 { grid-template-columns: repeat(4, 1fr); }
5344
- .ds-lg\:col-span-1 { grid-column: span 1 / span 1; }
5345
- .ds-lg\:col-span-2 { grid-column: span 2 / span 2; }
5346
- .ds-lg\:col-span-3 { grid-column: span 3 / span 3; }
5427
+ /* Keyboard shortcut hint */
5428
+ .ds-search__shortcut {
5429
+ flex-shrink: 0;
5430
+ padding: 0.125rem 0.375rem;
5431
+ font-size: var(--ds-text-2xs);
5432
+ font-family: inherit;
5433
+ line-height: 1;
5434
+ color: var(--ds-color-text-tertiary);
5435
+ background: var(--ds-color-bg-elevated);
5436
+ border: 1px solid var(--ds-color-border);
5437
+ border-radius: var(--ds-radius-sm);
5438
+ pointer-events: none;
5439
+ user-select: none;
5347
5440
  }
5348
5441
 
5349
- /* --- Gap --- */
5350
- .ds-gap-0 { gap: var(--ds-space-0); }
5351
- .ds-gap-1 { gap: var(--ds-space-1); }
5352
- .ds-gap-2 { gap: var(--ds-space-2); }
5353
- .ds-gap-3 { gap: var(--ds-space-3); }
5354
- .ds-gap-4 { gap: var(--ds-space-4); }
5442
+ /* Clear button */
5443
+ .ds-search__clear {
5444
+ display: flex;
5445
+ align-items: center;
5446
+ justify-content: center;
5447
+ flex-shrink: 0;
5448
+ width: 1.25rem;
5449
+ height: 1.25rem;
5450
+ border: none;
5451
+ border-radius: var(--ds-radius-sm);
5452
+ background: transparent;
5453
+ color: var(--ds-color-text-tertiary);
5454
+ cursor: pointer;
5455
+ transition:
5456
+ color var(--ds-duration-fast) var(--ds-ease-default),
5457
+ background-color var(--ds-duration-fast) var(--ds-ease-default);
5458
+ }
5459
+
5460
+ .ds-search__clear:hover {
5461
+ background: var(--ds-color-surface-hover);
5462
+ color: var(--ds-color-text-secondary);
5463
+ }
5464
+
5465
+ /* Dropdown results panel */
5466
+ .ds-search__dropdown {
5467
+ position: fixed;
5468
+ max-height: min(22rem, calc(100dvh - 5rem));
5469
+ overflow-y: auto;
5470
+ background: var(--ds-color-bg-elevated);
5471
+ border: 1px solid var(--ds-color-border);
5472
+ border-radius: var(--ds-radius-lg);
5473
+ box-shadow: var(--ds-shadow-lg);
5474
+ z-index: var(--ds-z-tooltip);
5475
+ padding: var(--ds-space-1) 0;
5476
+ }
5477
+
5478
+ /* Result groups */
5479
+ .ds-search__group {
5480
+ padding: var(--ds-space-1) 0;
5481
+ }
5482
+
5483
+ .ds-search__group + .ds-search__group {
5484
+ border-top: 1px solid var(--ds-color-border);
5485
+ }
5486
+
5487
+ .ds-search__group-label {
5488
+ display: block;
5489
+ padding: var(--ds-space-1) var(--ds-space-3);
5490
+ font-size: var(--ds-text-2xs);
5491
+ font-weight: var(--ds-weight-medium);
5492
+ color: var(--ds-color-text-tertiary);
5493
+ text-transform: uppercase;
5494
+ letter-spacing: 0.04em;
5495
+ }
5496
+
5497
+ /* Individual result */
5498
+ .ds-search__result {
5499
+ display: flex;
5500
+ align-items: center;
5501
+ gap: var(--ds-space-2);
5502
+ width: 100%;
5503
+ padding: var(--ds-space-2-5) var(--ds-space-3);
5504
+ border: none;
5505
+ background: transparent;
5506
+ color: var(--ds-color-text);
5507
+ font-size: var(--ds-text-sm);
5508
+ font-family: inherit;
5509
+ text-align: left;
5510
+ cursor: pointer;
5511
+ transition: background-color var(--ds-duration-fast) var(--ds-ease-default);
5512
+ }
5513
+
5514
+ .ds-search__result:hover,
5515
+ .ds-search__result--active {
5516
+ background: var(--ds-color-surface-hover);
5517
+ }
5518
+
5519
+ .ds-search__result:focus-visible {
5520
+ outline: none;
5521
+ box-shadow: inset 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
5522
+ }
5523
+
5524
+ .ds-search__result-icon {
5525
+ color: var(--ds-color-text-tertiary);
5526
+ flex-shrink: 0;
5527
+ }
5528
+
5529
+ .ds-search__result-db-icon {
5530
+ display: flex;
5531
+ align-items: center;
5532
+ justify-content: center;
5533
+ width: 1.5rem;
5534
+ height: 1.5rem;
5535
+ border-radius: var(--ds-radius-md);
5536
+ flex-shrink: 0;
5537
+ }
5538
+
5539
+ .ds-search__result-content {
5540
+ display: flex;
5541
+ flex-direction: column;
5542
+ min-width: 0;
5543
+ }
5544
+
5545
+ .ds-search__result-title {
5546
+ white-space: nowrap;
5547
+ overflow: hidden;
5548
+ text-overflow: ellipsis;
5549
+ min-width: 0;
5550
+ line-height: var(--ds-leading-snug);
5551
+ }
5552
+
5553
+ .ds-search__result-meta {
5554
+ font-size: var(--ds-text-2xs);
5555
+ line-height: var(--ds-leading-snug);
5556
+ color: var(--ds-color-text-tertiary);
5557
+ white-space: nowrap;
5558
+ overflow: hidden;
5559
+ text-overflow: ellipsis;
5560
+ }
5561
+
5562
+ /* Empty state */
5563
+ .ds-search__empty {
5564
+ display: flex;
5565
+ align-items: center;
5566
+ justify-content: center;
5567
+ padding: var(--ds-space-4) var(--ds-space-2);
5568
+ color: var(--ds-color-text-tertiary);
5569
+ font-size: var(--ds-text-sm);
5570
+ }
5571
+
5572
+ /* Mobile trigger (hidden on desktop) */
5573
+ .ds-search-mobile-trigger {
5574
+ display: none;
5575
+ align-items: center;
5576
+ justify-content: center;
5577
+ width: 2.25rem;
5578
+ height: 2.25rem;
5579
+ border: none;
5580
+ border-radius: var(--ds-radius-md);
5581
+ background: transparent;
5582
+ color: var(--ds-color-text);
5583
+ cursor: pointer;
5584
+ flex-shrink: 0;
5585
+ transition: background-color var(--ds-duration-fast) var(--ds-ease-default);
5586
+ }
5587
+
5588
+ @media (hover: hover) {
5589
+ .ds-search-mobile-trigger:hover {
5590
+ background-color: var(--ds-color-surface-hover);
5591
+ }
5592
+ }
5593
+
5594
+ /* Close button (mobile expanded) */
5595
+ .ds-search__close {
5596
+ display: flex;
5597
+ align-items: center;
5598
+ justify-content: center;
5599
+ width: 2.25rem;
5600
+ height: 2.25rem;
5601
+ border: none;
5602
+ border-radius: var(--ds-radius-md);
5603
+ background: transparent;
5604
+ color: var(--ds-color-text);
5605
+ cursor: pointer;
5606
+ flex-shrink: 0;
5607
+ }
5608
+
5609
+ /* Responsive: mobile */
5610
+ @media (max-width: 1023px) {
5611
+ .ds-search__shortcut { display: none; }
5612
+ .ds-search-mobile-trigger { display: flex; }
5613
+ .ds-search { display: none; }
5614
+
5615
+ .ds-search--mobile-expanded {
5616
+ display: flex;
5617
+ position: fixed;
5618
+ top: 0;
5619
+ left: 0;
5620
+ right: 0;
5621
+ height: var(--ds-search-bar-height, 3.5rem);
5622
+ z-index: var(--ds-z-dropdown);
5623
+ border: none;
5624
+ border-bottom: 1px solid var(--ds-color-border);
5625
+ border-radius: 0;
5626
+ padding: 0 var(--ds-space-3);
5627
+ background: var(--ds-color-nav-bg);
5628
+ backdrop-filter: blur(20px) saturate(1.5);
5629
+ -webkit-backdrop-filter: blur(20px) saturate(1.5);
5630
+ }
5631
+
5632
+ .ds-search__dropdown--mobile {
5633
+ left: 0 !important;
5634
+ right: 0;
5635
+ width: auto !important;
5636
+ border-radius: 0;
5637
+ border-left: none;
5638
+ border-right: none;
5639
+ max-height: calc(100dvh - var(--ds-search-bar-height, 3.5rem));
5640
+ background: var(--ds-color-surface);
5641
+ backdrop-filter: blur(20px) saturate(1.5);
5642
+ -webkit-backdrop-filter: blur(20px) saturate(1.5);
5643
+ }
5644
+ }
5645
+
5646
+ /* ==========================================================================
5647
+ Component: Toolbar
5648
+ Fixed bar with rows of actions: toolbar buttons, filter chips, segmented
5649
+ controls, and scrollable groups. Common in data-heavy UIs below a header.
5650
+
5651
+ Usage:
5652
+ <div class="ds-toolbar">
5653
+ <div class="ds-toolbar__row">
5654
+ <div class="ds-toolbar__group">...</div>
5655
+ <div class="ds-toolbar__spacer"></div>
5656
+ <div class="ds-toolbar__group">
5657
+ <button class="ds-toolbar__btn ds-toolbar__btn--active">
5658
+ <span>Filter</span>
5659
+ <span class="ds-toolbar__badge">3</span>
5660
+ </button>
5661
+ <button class="ds-toolbar__btn">Sort</button>
5662
+ </div>
5663
+ </div>
5664
+ </div>
5665
+
5666
+ Modifiers:
5667
+ .ds-toolbar__row--scroll — Horizontally scrollable row
5668
+ .ds-toolbar__btn--active — Active/toggled button
5669
+ .ds-toolbar__group--scroll — Scrollable group within a row
5670
+
5671
+ Segmented control:
5672
+ <div class="ds-toolbar__segmented">
5673
+ <button class="ds-toolbar__segmented-btn ds-toolbar__segmented-btn--active">Past</button>
5674
+ <button class="ds-toolbar__segmented-btn">Future</button>
5675
+ </div>
5676
+ ========================================================================== */
5677
+
5678
+ /* Row container */
5679
+ .ds-toolbar__row {
5680
+ display: flex;
5681
+ align-items: center;
5682
+ height: var(--ds-toolbar-row-height, 2.5rem);
5683
+ gap: var(--ds-space-3);
5684
+ padding-inline: var(--ds-space-4);
5685
+ }
5686
+
5687
+ .ds-toolbar__row--scroll {
5688
+ overflow-x: auto;
5689
+ scrollbar-width: none;
5690
+ }
5691
+
5692
+ .ds-toolbar__row--scroll::-webkit-scrollbar { display: none; }
5693
+
5694
+ /* Group (flex row of items) */
5695
+ .ds-toolbar__group {
5696
+ display: flex;
5697
+ align-items: center;
5698
+ flex-shrink: 0;
5699
+ }
5700
+
5701
+ .ds-toolbar__group--scroll {
5702
+ flex-shrink: 1;
5703
+ min-width: 0;
5704
+ overflow-x: auto;
5705
+ scrollbar-width: none;
5706
+ }
5707
+
5708
+ .ds-toolbar__group--scroll::-webkit-scrollbar { display: none; }
5709
+
5710
+ /* Spacer */
5711
+ .ds-toolbar__spacer {
5712
+ flex: 1 1 0;
5713
+ }
5714
+
5715
+ /* Toolbar button */
5716
+ .ds-toolbar__btn {
5717
+ display: inline-flex;
5718
+ align-items: center;
5719
+ gap: var(--ds-space-1-5);
5720
+ padding: var(--ds-space-1) var(--ds-space-2-5);
5721
+ font-size: var(--ds-text-xs);
5722
+ font-weight: var(--ds-weight-medium);
5723
+ font-family: inherit;
5724
+ color: var(--ds-color-text-tertiary);
5725
+ background: transparent;
5726
+ border: 1px solid transparent;
5727
+ border-radius: var(--ds-radius-md);
5728
+ cursor: pointer;
5729
+ white-space: nowrap;
5730
+ transition:
5731
+ color var(--ds-duration-fast) var(--ds-ease-default),
5732
+ background-color var(--ds-duration-fast) var(--ds-ease-default),
5733
+ border-color var(--ds-duration-fast) var(--ds-ease-default);
5734
+ }
5735
+
5736
+ .ds-toolbar__btn:hover {
5737
+ color: var(--ds-color-text-secondary);
5738
+ background: var(--ds-color-surface-hover);
5739
+ }
5740
+
5741
+ .ds-toolbar__btn:focus-visible {
5742
+ outline: none;
5743
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
5744
+ }
5745
+
5746
+ .ds-toolbar__btn--active {
5747
+ color: var(--ds-color-text);
5748
+ background: var(--ds-color-surface);
5749
+ border-color: var(--ds-color-border);
5750
+ }
5751
+
5752
+ /* Badge (count indicator inside button) */
5753
+ .ds-toolbar__badge {
5754
+ display: inline-flex;
5755
+ align-items: center;
5756
+ justify-content: center;
5757
+ min-width: 1rem;
5758
+ height: 1rem;
5759
+ padding: 0 0.25rem;
5760
+ font-size: 0.625rem;
5761
+ font-weight: 600;
5762
+ line-height: 1;
5763
+ color: var(--ds-color-on-inverted);
5764
+ background: var(--ds-color-interactive);
5765
+ border-radius: var(--ds-radius-full);
5766
+ }
5767
+
5768
+ /* Eye toggle (visibility) */
5769
+ .ds-toolbar__eye {
5770
+ display: inline-flex;
5771
+ align-items: center;
5772
+ cursor: pointer;
5773
+ opacity: 0.7;
5774
+ transition: opacity var(--ds-duration-fast) var(--ds-ease-default);
5775
+ }
5776
+
5777
+ .ds-toolbar__eye:hover {
5778
+ opacity: 1;
5779
+ }
5780
+
5781
+ /* Segmented control */
5782
+ .ds-toolbar__segmented {
5783
+ flex-shrink: 0;
5784
+ display: flex;
5785
+ background: var(--ds-color-surface);
5786
+ border-radius: var(--ds-radius-md);
5787
+ padding: 2px;
5788
+ }
5789
+
5790
+ .ds-toolbar__segmented-btn {
5791
+ padding: var(--ds-space-1) var(--ds-space-3);
5792
+ font-size: var(--ds-text-xs);
5793
+ font-weight: var(--ds-weight-medium);
5794
+ color: var(--ds-color-text-tertiary);
5795
+ border: none;
5796
+ border-radius: var(--ds-radius-sm);
5797
+ background: transparent;
5798
+ cursor: pointer;
5799
+ transition:
5800
+ color var(--ds-duration-fast) var(--ds-ease-default),
5801
+ background-color var(--ds-duration-fast) var(--ds-ease-default);
5802
+ }
5803
+
5804
+ .ds-toolbar__segmented-btn:hover {
5805
+ color: var(--ds-color-text-secondary);
5806
+ }
5807
+
5808
+ .ds-toolbar__segmented-btn--active {
5809
+ background: var(--ds-color-bg-elevated);
5810
+ color: var(--ds-color-text);
5811
+ }
5812
+
5813
+ /* Responsive: mobile */
5814
+ @media (max-width: 1023px) {
5815
+ .ds-toolbar__row {
5816
+ padding-inline: var(--ds-space-3);
5817
+ gap: var(--ds-space-2);
5818
+ }
5819
+
5820
+ .ds-toolbar__btn-label { display: none; }
5821
+
5822
+ .ds-toolbar__btn {
5823
+ padding: var(--ds-space-2);
5824
+ min-width: var(--ds-size-2);
5825
+ min-height: var(--ds-size-2);
5826
+ justify-content: center;
5827
+ }
5828
+
5829
+ .ds-toolbar__badge {
5830
+ font-size: 0.5rem;
5831
+ min-width: 0.875rem;
5832
+ height: 0.875rem;
5833
+ }
5834
+ }
5835
+
5836
+ /* ==========================================================================
5837
+ Component: Chip
5838
+ Interactive filter/sort chips with optional remove button. Distinct from
5839
+ ds-tag (which is a static label). Chips represent active filter state.
5840
+
5841
+ Usage:
5842
+ <span class="ds-chip">
5843
+ Status: Active
5844
+ <button class="ds-chip__remove">×</button>
5845
+ </span>
5846
+ <button class="ds-chip ds-chip--logic">AND</button>
5847
+ <span class="ds-chip ds-chip--sort">Date ↑</span>
5848
+
5849
+ Modifiers:
5850
+ .ds-chip--logic — AND/OR toggle chip (clickable, no bg)
5851
+ .ds-chip--sort — Sort indicator (dashed border)
5852
+ ========================================================================== */
5853
+
5854
+ .ds-chip {
5855
+ display: inline-flex;
5856
+ align-items: center;
5857
+ gap: var(--ds-space-1);
5858
+ padding: var(--ds-space-0-5) var(--ds-space-2);
5859
+ font-size: var(--ds-text-xs);
5860
+ font-family: inherit;
5861
+ color: var(--ds-color-text-secondary);
5862
+ background: var(--ds-color-bg-elevated);
5863
+ border: 1px solid var(--ds-color-border);
5864
+ border-radius: var(--ds-radius-full);
5865
+ white-space: nowrap;
5866
+ }
5867
+
5868
+ /* Logic chip (AND/OR toggle) */
5869
+ .ds-chip--logic {
5870
+ cursor: pointer;
5871
+ font-weight: 600;
5872
+ color: var(--ds-color-text-tertiary);
5873
+ background: transparent;
5874
+ border-color: var(--ds-color-border);
5875
+ transition: background-color var(--ds-duration-fast) var(--ds-ease-default);
5876
+ }
5877
+
5878
+ .ds-chip--logic:hover {
5879
+ background: var(--ds-color-surface-hover);
5880
+ }
5881
+
5882
+ /* Sort chip (dashed border) */
5883
+ .ds-chip--sort {
5884
+ border-style: dashed;
5885
+ }
5886
+
5887
+ /* Remove button */
5888
+ .ds-chip__remove {
5889
+ display: inline-flex;
5890
+ align-items: center;
5891
+ justify-content: center;
5892
+ width: 14px;
5893
+ height: 14px;
5894
+ border: none;
5895
+ border-radius: var(--ds-radius-full);
5896
+ background: transparent;
5897
+ color: var(--ds-color-text-tertiary);
5898
+ cursor: pointer;
5899
+ transition:
5900
+ color var(--ds-duration-fast) var(--ds-ease-default),
5901
+ background-color var(--ds-duration-fast) var(--ds-ease-default);
5902
+ }
5903
+
5904
+ .ds-chip__remove:hover {
5905
+ color: var(--ds-color-text);
5906
+ background: var(--ds-color-surface-hover);
5907
+ }
5908
+
5909
+ /* ==========================================================================
5910
+ Component: Icon Button
5911
+ Standalone icon button for actions, toolbar items, and table rows.
5912
+ A minimal interactive element that wraps a single icon.
5913
+
5914
+ Usage:
5915
+ <button class="ds-icon-btn">
5916
+ <svg>...</svg>
5917
+ </button>
5918
+ <button class="ds-icon-btn ds-icon-btn--sm">...</button>
5919
+ <button class="ds-icon-btn ds-icon-btn--danger">...</button>
5920
+
5921
+ Sizes:
5922
+ .ds-icon-btn--xs — 24px (var(--ds-size-1))
5923
+ .ds-icon-btn--sm — 28px
5924
+ (default) — 32px (var(--ds-size-2))
5925
+ .ds-icon-btn--lg — 40px (var(--ds-size-3))
5926
+
5927
+ Modifiers:
5928
+ .ds-icon-btn--danger — Error color on hover
5929
+ .ds-icon-btn--ghost — No background change, color-only transition
5930
+ ========================================================================== */
5931
+
5932
+ .ds-icon-btn {
5933
+ display: inline-flex;
5934
+ align-items: center;
5935
+ justify-content: center;
5936
+ width: var(--ds-size-2);
5937
+ height: var(--ds-size-2);
5938
+ padding: var(--ds-space-1-5);
5939
+ border: none;
5940
+ border-radius: var(--ds-radius-lg);
5941
+ background: transparent;
5942
+ color: var(--ds-color-text-tertiary);
5943
+ cursor: pointer;
5944
+ flex-shrink: 0;
5945
+ transition:
5946
+ color var(--ds-duration-fast) var(--ds-ease-default),
5947
+ background-color var(--ds-duration-fast) var(--ds-ease-default);
5948
+ }
5949
+
5950
+ .ds-icon-btn:hover {
5951
+ background-color: var(--ds-color-surface-hover);
5952
+ color: var(--ds-color-text-secondary);
5953
+ }
5954
+
5955
+ .ds-icon-btn:focus-visible {
5956
+ outline: none;
5957
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
5958
+ }
5959
+
5960
+ .ds-icon-btn:disabled,
5961
+ .ds-icon-btn[aria-disabled="true"] {
5962
+ opacity: var(--ds-opacity-disabled);
5963
+ cursor: not-allowed;
5964
+ pointer-events: none;
5965
+ }
5966
+
5967
+ /* Sizes */
5968
+ .ds-icon-btn--xs {
5969
+ width: var(--ds-size-1);
5970
+ height: var(--ds-size-1);
5971
+ padding: var(--ds-space-0-5);
5972
+ border-radius: var(--ds-radius-md);
5973
+ }
5974
+
5975
+ .ds-icon-btn--sm {
5976
+ width: 1.75rem;
5977
+ height: 1.75rem;
5978
+ padding: var(--ds-space-1);
5979
+ border-radius: var(--ds-radius-md);
5980
+ }
5981
+
5982
+ .ds-icon-btn--lg {
5983
+ width: var(--ds-size-3);
5984
+ height: var(--ds-size-3);
5985
+ padding: var(--ds-space-2);
5986
+ }
5987
+
5988
+ /* Danger variant */
5989
+ .ds-icon-btn--danger:hover {
5990
+ color: var(--ds-color-error);
5991
+ background-color: color-mix(in srgb, var(--ds-color-error) 10%, transparent);
5992
+ }
5993
+
5994
+ /* Ghost variant (color only, no bg) */
5995
+ .ds-icon-btn--ghost {
5996
+ padding: 0;
5997
+ width: auto;
5998
+ height: auto;
5999
+ }
6000
+
6001
+ .ds-icon-btn--ghost:hover {
6002
+ background: transparent;
6003
+ color: var(--ds-color-text);
6004
+ }
6005
+
6006
+ /* ==========================================================================
6007
+ Component: Bottom Nav
6008
+ Mobile bottom navigation bar. Hidden on desktop, shown on mobile.
6009
+ Fixed to bottom with safe-area insets for notched devices.
6010
+
6011
+ Usage:
6012
+ <nav class="ds-bottom-nav">
6013
+ <a href="/" class="ds-bottom-nav__item ds-bottom-nav__item--active">
6014
+ <span class="ds-bottom-nav__icon">
6015
+ <svg>...</svg>
6016
+ <span class="ds-bottom-nav__badge">3</span>
6017
+ </span>
6018
+ <span class="ds-bottom-nav__label">Home</span>
6019
+ </a>
6020
+ <button class="ds-bottom-nav__item ds-bottom-nav__item--create">
6021
+ <span class="ds-bottom-nav__create-icon">+</span>
6022
+ <span class="ds-bottom-nav__label">New</span>
6023
+ </button>
6024
+ </nav>
6025
+
6026
+ Modifiers:
6027
+ .ds-bottom-nav__item--active — Active/current tab
6028
+ .ds-bottom-nav__item--create — Elevated center action button
6029
+ ========================================================================== */
6030
+
6031
+ .ds-bottom-nav {
6032
+ display: none;
6033
+ position: fixed;
6034
+ bottom: 0;
6035
+ left: 0;
6036
+ right: 0;
6037
+ z-index: var(--ds-z-dropdown);
6038
+ background: var(--ds-color-surface);
6039
+ border-top: 1px solid var(--ds-color-border);
6040
+ padding-bottom: env(safe-area-inset-bottom, 0px);
6041
+ }
6042
+
6043
+ @media (max-width: 1023px) {
6044
+ .ds-bottom-nav {
6045
+ display: flex;
6046
+ justify-content: space-around;
6047
+ align-items: stretch;
6048
+ }
6049
+ }
6050
+
6051
+ @media (min-width: 1024px) {
6052
+ .ds-bottom-nav { display: none !important; }
6053
+ }
6054
+
6055
+ /* Nav item */
6056
+ .ds-bottom-nav__item {
6057
+ display: flex;
6058
+ flex-direction: column;
6059
+ align-items: center;
6060
+ justify-content: center;
6061
+ gap: var(--ds-space-1);
6062
+ flex: 1;
6063
+ padding: var(--ds-space-2) 0;
6064
+ color: var(--ds-color-text-tertiary);
6065
+ text-decoration: none;
6066
+ border: none;
6067
+ background: none;
6068
+ cursor: pointer;
6069
+ font: inherit;
6070
+ transition: color var(--ds-duration-fast) var(--ds-ease-default);
6071
+ -webkit-tap-highlight-color: transparent;
6072
+ }
6073
+
6074
+ .ds-bottom-nav__item--active {
6075
+ color: var(--ds-color-text);
6076
+ }
6077
+
6078
+ /* Icon wrapper */
6079
+ .ds-bottom-nav__icon {
6080
+ position: relative;
6081
+ display: flex;
6082
+ align-items: center;
6083
+ justify-content: center;
6084
+ }
6085
+
6086
+ /* Notification badge */
6087
+ .ds-bottom-nav__badge {
6088
+ position: absolute;
6089
+ top: -4px;
6090
+ right: -8px;
6091
+ min-width: 16px;
6092
+ height: 16px;
6093
+ padding: 0 4px;
6094
+ border-radius: var(--ds-radius-full);
6095
+ background: var(--ds-color-error);
6096
+ color: #fff;
6097
+ font-size: 10px;
6098
+ font-weight: 600;
6099
+ line-height: 16px;
6100
+ text-align: center;
6101
+ }
6102
+
6103
+ /* Label */
6104
+ .ds-bottom-nav__label {
6105
+ font-size: 10px;
6106
+ font-weight: var(--ds-weight-medium);
6107
+ letter-spacing: 0.02em;
6108
+ }
6109
+
6110
+ /* Create button — elevated center icon */
6111
+ .ds-bottom-nav__create-icon {
6112
+ display: flex;
6113
+ align-items: center;
6114
+ justify-content: center;
6115
+ width: 2.25rem;
6116
+ height: 2.25rem;
6117
+ border-radius: var(--ds-radius-full);
6118
+ background: var(--ds-color-text);
6119
+ color: var(--ds-color-bg-base);
6120
+ }
6121
+
6122
+ .ds-bottom-nav__item--create {
6123
+ color: var(--ds-color-text-tertiary);
6124
+ }
6125
+
6126
+ /* ==========================================================================
6127
+ Component: Spinner
6128
+ CSS-only loading spinner using border animation.
6129
+
6130
+ Usage:
6131
+ <span class="ds-spinner"></span>
6132
+ <span class="ds-spinner ds-spinner--sm"></span>
6133
+ <span class="ds-spinner ds-spinner--muted"></span>
6134
+
6135
+ Sizes:
6136
+ .ds-spinner--sm — 1.25rem (20px)
6137
+ (default) — 1.5rem (24px)
6138
+ .ds-spinner--lg — 2rem (32px)
6139
+
6140
+ Variants:
6141
+ (default) — Border + interactive top
6142
+ .ds-spinner--muted — Inverted colors (for dark backgrounds)
6143
+ .ds-spinner--light — Light colors (for inverted/colored backgrounds)
6144
+ ========================================================================== */
6145
+
6146
+ .ds-spinner {
6147
+ display: inline-block;
6148
+ width: 1.5rem;
6149
+ height: 1.5rem;
6150
+ border: 2px solid var(--ds-color-border);
6151
+ border-top-color: var(--ds-color-interactive);
6152
+ border-radius: var(--ds-radius-full);
6153
+ animation: ds-spin 0.8s linear infinite;
6154
+ }
6155
+
6156
+ @keyframes ds-spin {
6157
+ to { transform: rotate(360deg); }
6158
+ }
6159
+
6160
+ /* Sizes */
6161
+ .ds-spinner--sm {
6162
+ width: 1rem;
6163
+ height: 1rem;
6164
+ }
6165
+
6166
+ .ds-spinner--md {
6167
+ width: 1.25rem;
6168
+ height: 1.25rem;
6169
+ }
6170
+
6171
+ .ds-spinner--lg {
6172
+ width: 2rem;
6173
+ height: 2rem;
6174
+ }
6175
+
6176
+ /* Color variants */
6177
+ .ds-spinner--muted {
6178
+ border-color: var(--ds-color-inverted);
6179
+ border-top-color: transparent;
6180
+ }
6181
+
6182
+ .ds-spinner--light {
6183
+ border-color: var(--ds-color-on-inverted);
6184
+ border-top-color: transparent;
6185
+ }
6186
+
6187
+
6188
+ /* ==========================================================================
6189
+ Utilities: Layout
6190
+ Container with clamp padding, generous responsive grid.
6191
+ ========================================================================== */
6192
+
6193
+ /* --- Container --- */
6194
+ .ds-container {
6195
+ width: 100%;
6196
+ max-width: var(--ds-container-max);
6197
+ margin-inline: auto;
6198
+ padding-inline: var(--ds-container-padding);
6199
+ }
6200
+
6201
+ /* --- Section (generous vertical rhythm) --- */
6202
+ .ds-section {
6203
+ padding-block: var(--ds-section-padding);
6204
+ }
6205
+
6206
+ /* --- Flex --- */
6207
+ .ds-flex { display: flex; }
6208
+ .ds-inline-flex { display: inline-flex; }
6209
+ .ds-flex-col { flex-direction: column; }
6210
+ .ds-flex-row { flex-direction: row; }
6211
+ .ds-flex-wrap { flex-wrap: wrap; }
6212
+ .ds-flex-1 { flex: 1 1 0%; }
6213
+ .ds-flex-auto { flex: 1 1 auto; }
6214
+ .ds-flex-none { flex: none; }
6215
+ .ds-shrink-0 { flex-shrink: 0; }
6216
+
6217
+ /* --- Alignment --- */
6218
+ .ds-items-start { align-items: flex-start; }
6219
+ .ds-items-center { align-items: center; }
6220
+ .ds-items-end { align-items: flex-end; }
6221
+ .ds-items-stretch { align-items: stretch; }
6222
+ .ds-items-baseline { align-items: baseline; }
6223
+
6224
+ .ds-justify-start { justify-content: flex-start; }
6225
+ .ds-justify-center { justify-content: center; }
6226
+ .ds-justify-end { justify-content: flex-end; }
6227
+ .ds-justify-between { justify-content: space-between; }
6228
+ .ds-justify-around { justify-content: space-around; }
6229
+ .ds-justify-evenly { justify-content: space-evenly; }
6230
+
6231
+ .ds-self-start { align-self: flex-start; }
6232
+ .ds-self-center { align-self: center; }
6233
+ .ds-self-end { align-self: flex-end; }
6234
+
6235
+ /* --- Grid --- */
6236
+ .ds-grid {
6237
+ display: grid;
6238
+ gap: var(--ds-space-6);
6239
+ }
6240
+
6241
+ .ds-grid-cols-1 { grid-template-columns: repeat(1, 1fr); }
6242
+ .ds-grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
6243
+ .ds-grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
6244
+ .ds-grid-cols-4 { grid-template-columns: repeat(4, 1fr); }
6245
+
6246
+ /* --- Column Span --- */
6247
+ .ds-col-span-1 { grid-column: span 1 / span 1; }
6248
+ .ds-col-span-2 { grid-column: span 2 / span 2; }
6249
+ .ds-col-span-3 { grid-column: span 3 / span 3; }
6250
+ .ds-col-span-4 { grid-column: span 4 / span 4; }
6251
+ .ds-col-span-full { grid-column: 1 / -1; }
6252
+
6253
+ @media (min-width: 640px) {
6254
+ .ds-sm\:grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
6255
+ .ds-sm\:grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
6256
+ }
6257
+
6258
+ @media (min-width: 768px) {
6259
+ .ds-md\:grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
6260
+ .ds-md\:grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
6261
+ .ds-md\:grid-cols-4 { grid-template-columns: repeat(4, 1fr); }
6262
+ .ds-md\:col-span-1 { grid-column: span 1 / span 1; }
6263
+ .ds-md\:col-span-2 { grid-column: span 2 / span 2; }
6264
+ .ds-md\:col-span-3 { grid-column: span 3 / span 3; }
6265
+ .ds-md\:flex-row { flex-direction: row; }
6266
+ }
6267
+
6268
+ @media (min-width: 1024px) {
6269
+ .ds-lg\:grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
6270
+ .ds-lg\:grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
6271
+ .ds-lg\:grid-cols-4 { grid-template-columns: repeat(4, 1fr); }
6272
+ .ds-lg\:col-span-1 { grid-column: span 1 / span 1; }
6273
+ .ds-lg\:col-span-2 { grid-column: span 2 / span 2; }
6274
+ .ds-lg\:col-span-3 { grid-column: span 3 / span 3; }
6275
+ }
6276
+
6277
+ /* --- Gap --- */
6278
+ .ds-gap-0 { gap: var(--ds-space-0); }
6279
+ .ds-gap-1 { gap: var(--ds-space-1); }
6280
+ .ds-gap-2 { gap: var(--ds-space-2); }
6281
+ .ds-gap-3 { gap: var(--ds-space-3); }
6282
+ .ds-gap-4 { gap: var(--ds-space-4); }
5355
6283
  .ds-gap-5 { gap: var(--ds-space-5); }
5356
6284
  .ds-gap-6 { gap: var(--ds-space-6); }
5357
6285
  .ds-gap-8 { gap: var(--ds-space-8); }
@@ -5978,4 +6906,121 @@ tr:hover .ds-sortable__handle,
5978
6906
  border-width: 0;
5979
6907
  }
5980
6908
 
6909
+ /* ==========================================================================
6910
+ Utilities: Interactive
6911
+ Hover states, reveal patterns, focus rings, and cursor utilities.
6912
+ ========================================================================== */
6913
+
6914
+ /* --- Hover Row (background elevation on hover) --- */
6915
+ .ds-hover-row {
6916
+ transition: background-color var(--ds-duration-fast) var(--ds-ease-default);
6917
+ }
6918
+ .ds-hover-row:hover {
6919
+ background-color: var(--ds-color-bg-elevated);
6920
+ }
6921
+
6922
+ /* Subtle variant (semi-transparent) */
6923
+ .ds-hover-row--subtle {
6924
+ transition: background-color var(--ds-duration-fast) var(--ds-ease-default);
6925
+ }
6926
+ .ds-hover-row--subtle:hover {
6927
+ background-color: color-mix(in srgb, var(--ds-color-bg-elevated) 50%, transparent);
6928
+ }
6929
+
6930
+ /* --- Group Reveal (children appear on parent hover) --- */
6931
+ .ds-reveal {
6932
+ opacity: 0;
6933
+ transition: opacity var(--ds-duration-fast) var(--ds-ease-default);
6934
+ }
6935
+ .group:hover > .ds-reveal,
6936
+ .group:hover .ds-reveal {
6937
+ opacity: 1;
6938
+ }
6939
+
6940
+ /* --- Editable Cell (pointer + bg on hover) --- */
6941
+ .ds-editable {
6942
+ cursor: pointer;
6943
+ border-radius: var(--ds-radius-default);
6944
+ transition: background-color var(--ds-duration-fast) var(--ds-ease-default);
6945
+ }
6946
+ .ds-editable:hover {
6947
+ background-color: var(--ds-color-surface-hover);
6948
+ }
6949
+
6950
+ /* --- Hover Border --- */
6951
+ .ds-hover-border {
6952
+ transition: border-color var(--ds-duration-fast) var(--ds-ease-default);
6953
+ }
6954
+ .ds-hover-border:hover {
6955
+ border-color: var(--ds-color-border-hover);
6956
+ }
6957
+
6958
+ /* --- Hover Zoom (scale on hover) --- */
6959
+ .ds-hover-zoom {
6960
+ transition: transform var(--ds-duration-fast) var(--ds-ease-default);
6961
+ }
6962
+ .ds-hover-zoom:hover {
6963
+ transform: scale(1.05);
6964
+ }
6965
+
6966
+ /* --- Opacity Hover (dim → full on hover) --- */
6967
+ .ds-opacity-hover {
6968
+ opacity: 0.5;
6969
+ transition: opacity var(--ds-duration-fast) var(--ds-ease-default);
6970
+ }
6971
+ .ds-opacity-hover:hover {
6972
+ opacity: 1;
6973
+ }
6974
+
6975
+ /* --- Focus Ring (inset ring for custom inputs) --- */
6976
+ .ds-focus-ring:focus {
6977
+ border-color: var(--ds-color-border-active);
6978
+ box-shadow: inset 0 0 0 1px var(--ds-color-border-active);
6979
+ outline: none;
6980
+ }
6981
+
6982
+ /* --- Ring States --- */
6983
+ .ds-ring-active {
6984
+ box-shadow: 0 0 0 2px var(--ds-color-border-active);
6985
+ }
6986
+
6987
+ .ds-ring-selected {
6988
+ box-shadow: 0 0 0 2px var(--ds-color-interactive), 0 0 0 3px var(--ds-color-surface);
6989
+ }
6990
+
6991
+ /* --- Semi-transparent Backgrounds --- */
6992
+ .ds-bg-elevated-50 {
6993
+ background-color: color-mix(in srgb, var(--ds-color-bg-elevated) 50%, transparent);
6994
+ }
6995
+
6996
+ .ds-bg-base-50 {
6997
+ background-color: color-mix(in srgb, var(--ds-color-bg-base) 50%, transparent);
6998
+ }
6999
+
7000
+ /* --- Hover Color Variants --- */
7001
+ .ds-hover-text-error:hover {
7002
+ color: var(--ds-color-error);
7003
+ }
7004
+
7005
+ .ds-hover-bg-error:hover {
7006
+ background-color: color-mix(in srgb, var(--ds-color-error) 10%, transparent);
7007
+ }
7008
+
7009
+ /* --- Cursor Utilities --- */
7010
+ .ds-cursor-grab {
7011
+ cursor: grab;
7012
+ }
7013
+ .ds-cursor-grab:active {
7014
+ cursor: grabbing;
7015
+ }
7016
+
7017
+ /* --- Grip Icon (secondary → primary on group hover) --- */
7018
+ .ds-grip {
7019
+ color: var(--ds-color-text-secondary);
7020
+ transition: color var(--ds-duration-fast) var(--ds-ease-default);
7021
+ }
7022
+ .group:hover .ds-grip {
7023
+ color: var(--ds-color-text);
7024
+ }
7025
+
5981
7026