@akhil-saxena/design-system 1.2.0 → 1.4.2

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.
@@ -7,8 +7,33 @@
7
7
  Pseudo-class states that inline style={{}} cannot express (D-103).
8
8
  Variant-specific hover states keyed off data-variant attribute.
9
9
  Source: original handoff `.ds-btn` rules transcribed verbatim. */
10
+
11
+ /* Base transition so the :active scale animates rather than snaps. Without
12
+ a transition declared here, the scale-down and scale-back-up both snap
13
+ instantly — on a Mac trackpad tap-to-click (~30ms mousedown duration)
14
+ the browser coalesces paints and the user never sees the press feedback.
15
+ The asymmetric durations below give a quick snap-down + a longer spring-
16
+ back so the click registers even on the fastest taps. */
17
+ .ds-atom-btn {
18
+ transition:
19
+ transform 140ms cubic-bezier(0.34, 1.56, 0.64, 1),
20
+ background-color 120ms ease,
21
+ border-color 120ms ease,
22
+ color 120ms ease,
23
+ box-shadow 120ms ease,
24
+ filter 120ms ease;
25
+ will-change: transform;
26
+ }
10
27
  .ds-atom-btn:active {
11
- transform: scale(0.97);
28
+ transform: scale(0.96);
29
+ transition-duration: 60ms, 120ms, 120ms, 120ms, 120ms, 120ms;
30
+ }
31
+ @media (prefers-reduced-motion: reduce) {
32
+ .ds-atom-btn,
33
+ .ds-atom-btn:active {
34
+ transition: none;
35
+ transform: none;
36
+ }
12
37
  }
13
38
  .ds-atom-btn:disabled {
14
39
  opacity: 0.4;
@@ -725,14 +750,26 @@
725
750
  .ds-atom-popover {
726
751
  position: fixed;
727
752
  z-index: 100;
728
- background: var(--cream-2);
729
- border: 1px solid var(--rule);
753
+ /* Pure white floor + faint rule + layered shadow so the menu reads as a
754
+ clean floating sheet above the cream page tone. Previous --cream bg sat
755
+ at the page tone and the --rule border added a visible grey rim — both
756
+ bled into the page and made the menu feel "dull". */
757
+ background: #ffffff;
758
+ border: 1px solid rgba(31, 27, 23, 0.04);
730
759
  border-radius: var(--radius-md);
731
- box-shadow: var(--shadow-3);
760
+ box-shadow: 0 1px 2px rgba(31, 27, 23, 0.04), 0 12px 32px rgba(31, 27, 23, 0.12), 0 0 0 0.5px
761
+ rgba(31, 27, 23, 0.04);
732
762
  padding: 0;
733
763
  min-width: 0;
734
764
  animation: ds-atom-popover-in 0.1s ease-out;
735
765
  }
766
+ .dark .ds-atom-popover {
767
+ /* Dark-mode: lifted surface above the page bg, with a slightly stronger
768
+ shadow to compensate for the lower contrast pop. */
769
+ background: #211d18;
770
+ border-color: rgba(255, 255, 255, 0.06);
771
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 12px 32px rgba(0, 0, 0, 0.55);
772
+ }
736
773
  @keyframes ds-atom-popover-in {
737
774
  from {
738
775
  opacity: 0;
@@ -776,7 +813,12 @@
776
813
  transition: background 0.1s;
777
814
  }
778
815
  .ds-atom-popover-item:hover:not(:disabled) {
779
- background: var(--cream-3);
816
+ /* Warm ink-wash hover — cream-3 was too grey against the white panel.
817
+ The 4% ink tint keeps it subtle but reads warmer + cleaner. */
818
+ background: rgba(31, 27, 23, 0.04);
819
+ }
820
+ .dark .ds-atom-popover-item:hover:not(:disabled) {
821
+ background: rgba(255, 255, 255, 0.06);
780
822
  }
781
823
  .ds-atom-popover-item:focus-visible {
782
824
  outline: 2px solid var(--amber);
@@ -1316,6 +1358,9 @@
1316
1358
  color: var(--ink);
1317
1359
  line-height: 1.3;
1318
1360
  }
1361
+ .ds-atom-banner[data-bold-title="false"] .ds-atom-banner-title {
1362
+ font-weight: var(--weight-regular, 400);
1363
+ }
1319
1364
  .ds-atom-banner-desc {
1320
1365
  font-family: var(--font);
1321
1366
  font-weight: 400;
@@ -1549,6 +1594,121 @@
1549
1594
  .ds-atom-toast[data-tone="info"] .ds-atom-toast-icon {
1550
1595
  color: var(--blue);
1551
1596
  }
1597
+
1598
+ /* ─── DS atom: Snackbar ──────────────────────────────────────────────────
1599
+ Bottom-center action surface. Solid ink fill (no translucency) so the
1600
+ message stays readable on top-heavy apps where the Toast's frosted
1601
+ surface can clash with the page chrome. Companion to Toast — Snackbar
1602
+ pairs with an action (UNDO / RETRY), Toast is passive. */
1603
+ .ds-atom-snackbar-region {
1604
+ position: fixed;
1605
+ left: 0;
1606
+ right: 0;
1607
+ bottom: var(--space-5);
1608
+ z-index: 1100;
1609
+ display: flex;
1610
+ justify-content: center;
1611
+ pointer-events: none;
1612
+ }
1613
+ .ds-atom-snackbar {
1614
+ pointer-events: auto;
1615
+ display: inline-flex;
1616
+ align-items: center;
1617
+ gap: 14px;
1618
+ min-width: 280px;
1619
+ max-width: 520px;
1620
+ padding: 10px 12px 10px 16px;
1621
+ border-radius: var(--radius-md);
1622
+ background: var(--ink);
1623
+ color: var(--cream);
1624
+ box-shadow: var(--shadow-3);
1625
+ font-family: var(--font);
1626
+ font-size: 13px;
1627
+ line-height: 1.45;
1628
+ animation: ds-atom-snackbar-slidein 0.2s ease-out;
1629
+ }
1630
+ .ds-atom-snackbar[data-dismissing="true"] {
1631
+ animation: ds-atom-snackbar-slideout 0.2s ease-out forwards;
1632
+ }
1633
+ .ds-atom-snackbar[data-tone="success"] {
1634
+ border-left: 3px solid var(--green, #1f8a5b);
1635
+ }
1636
+ .ds-atom-snackbar[data-tone="error"] {
1637
+ border-left: 3px solid var(--red, #9b2c2c);
1638
+ }
1639
+ .ds-atom-snackbar-msg {
1640
+ flex: 1 1 auto;
1641
+ min-width: 0;
1642
+ color: var(--cream);
1643
+ }
1644
+ .ds-atom-snackbar-action {
1645
+ flex: 0 0 auto;
1646
+ background: transparent;
1647
+ border: 0;
1648
+ padding: 4px 8px;
1649
+ border-radius: 6px;
1650
+ font-family: var(--mono);
1651
+ font-size: 11px;
1652
+ font-weight: 700;
1653
+ letter-spacing: 0.1em;
1654
+ text-transform: uppercase;
1655
+ color: var(--amber);
1656
+ cursor: pointer;
1657
+ transition: background-color 0.12s, color 0.12s;
1658
+ }
1659
+ .ds-atom-snackbar-action:hover {
1660
+ background: rgba(255, 255, 255, 0.08);
1661
+ color: var(--amber);
1662
+ }
1663
+ .ds-atom-snackbar-action:focus-visible {
1664
+ outline: 2px solid var(--amber);
1665
+ outline-offset: 2px;
1666
+ }
1667
+ .ds-atom-snackbar-close {
1668
+ flex: 0 0 auto;
1669
+ display: inline-flex;
1670
+ align-items: center;
1671
+ justify-content: center;
1672
+ width: 22px;
1673
+ height: 22px;
1674
+ background: transparent;
1675
+ border: 0;
1676
+ color: rgba(250, 250, 247, 0.7);
1677
+ cursor: pointer;
1678
+ border-radius: 4px;
1679
+ padding: 0;
1680
+ transition: background-color 0.12s, color 0.12s;
1681
+ }
1682
+ .ds-atom-snackbar-close:hover {
1683
+ background: rgba(255, 255, 255, 0.08);
1684
+ color: var(--cream);
1685
+ }
1686
+ .ds-atom-snackbar-close:focus-visible {
1687
+ outline: 2px solid var(--amber);
1688
+ outline-offset: 2px;
1689
+ }
1690
+ @keyframes ds-atom-snackbar-slidein {
1691
+ from {
1692
+ opacity: 0;
1693
+ transform: translateY(12px);
1694
+ }
1695
+ to {
1696
+ opacity: 1;
1697
+ transform: translateY(0);
1698
+ }
1699
+ }
1700
+ @keyframes ds-atom-snackbar-slideout {
1701
+ to {
1702
+ opacity: 0;
1703
+ transform: translateY(8px);
1704
+ }
1705
+ }
1706
+ @media (prefers-reduced-motion: reduce) {
1707
+ .ds-atom-snackbar,
1708
+ .ds-atom-snackbar[data-dismissing="true"] {
1709
+ animation: none;
1710
+ }
1711
+ }
1552
1712
  /* Dark mode: lift saturation 0.10 → 0.16 so tone bgs read on cream-2 surfaces. */
1553
1713
  .dark .ds-atom-toast[data-tone="success"] {
1554
1714
  background: rgba(74, 222, 128, 0.16);
@@ -1828,39 +1988,44 @@
1828
1988
  background: var(--amber-l);
1829
1989
  border-radius: 0;
1830
1990
  }
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. */
1991
+ /* v0.6 — range endpoints: amber-l half-strip on the connected side + amber pill.
1992
+ The cell itself carries the amber-l strip via a CSS gradient; the amber pill is
1993
+ a ::before pseudo-element at z-index:0 painted on top of it. The old z:-1 ::before
1994
+ approach was wrong: a z:-1 pseudo-element goes into the PARENT stacking context,
1995
+ below the cell at z-auto. The cell's solid amber background (from is-selected)
1996
+ painted over it entirely — only tiny corner-notch leaks from border-radius,
1997
+ not the full half-strip the design requires. The new approach:
1998
+ 1. Cell background = gradient (transparent | amber-l split at 50%)
1999
+ 2. ::before at z:0 = full-inset amber pill with border-radius
2000
+ 3. .ds-atom-datepicker-cell-num at z:1 lifts the date number above the pill */
1835
2001
  .ds-atom-datepicker-cell.is-range-start,
1836
2002
  .ds-atom-datepicker-cell.is-range-end {
1837
2003
  position: relative;
1838
2004
  }
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;
2005
+ .ds-atom-datepicker-cell.is-selected.is-range-start {
2006
+ background: linear-gradient(to right, transparent 50%, var(--amber-l) 50%);
2007
+ border-radius: 0;
2008
+ }
2009
+ .ds-atom-datepicker-cell.is-selected.is-range-end {
2010
+ background: linear-gradient(to right, var(--amber-l) 50%, transparent 50%);
2011
+ border-radius: 0;
1848
2012
  }
1849
- .ds-atom-datepicker-cell.is-range-end::before {
2013
+ .ds-atom-datepicker-cell.is-selected.is-range-start::before,
2014
+ .ds-atom-datepicker-cell.is-selected.is-range-end::before {
1850
2015
  content: "";
1851
2016
  position: absolute;
1852
- top: 0;
1853
- bottom: 0;
1854
- left: 0;
1855
- width: 50%;
1856
- background: var(--amber-l);
1857
- z-index: -1;
2017
+ inset: 0;
2018
+ background: var(--amber);
2019
+ border-radius: 6px;
2020
+ z-index: 0;
1858
2021
  }
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). */
2022
+ /* Lift the date number above the amber ::before pill. Applied unconditionally
2023
+ so the number is always above any ::before on the cell. */
2024
+ .ds-atom-datepicker-cell-num {
2025
+ position: relative;
2026
+ z-index: 1;
2027
+ }
2028
+ /* Hover state preservation. */
1864
2029
  .ds-atom-datepicker-cell.is-selected:hover:not(:disabled) {
1865
2030
  background: var(--amber);
1866
2031
  filter: brightness(0.92);
@@ -1869,11 +2034,18 @@
1869
2034
  background: var(--amber-l);
1870
2035
  filter: brightness(0.97);
1871
2036
  }
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) {
2037
+ /* Range endpoints on hover: keep the gradient strip, cancel filter (would create
2038
+ a stacking context), darken the pill via ::before. */
2039
+ .ds-atom-datepicker-cell.is-selected.is-range-start:hover:not(:disabled) {
2040
+ background: linear-gradient(to right, transparent 50%, var(--amber-l) 50%);
2041
+ filter: none;
2042
+ }
2043
+ .ds-atom-datepicker-cell.is-selected.is-range-end:hover:not(:disabled) {
2044
+ background: linear-gradient(to right, var(--amber-l) 50%, transparent 50%);
2045
+ filter: none;
2046
+ }
2047
+ .ds-atom-datepicker-cell.is-selected.is-range-start:hover:not(:disabled)::before,
2048
+ .ds-atom-datepicker-cell.is-selected.is-range-end:hover:not(:disabled)::before {
1877
2049
  background: #d97706;
1878
2050
  }
1879
2051
  /* Today cell hover (only when not also selected/in-range/endpoint) - preserve
@@ -1896,6 +2068,7 @@
1896
2068
  height: 3px;
1897
2069
  border-radius: 50%;
1898
2070
  background: var(--ink-3);
2071
+ z-index: 1;
1899
2072
  }
1900
2073
  .ds-atom-datepicker-cell.is-selected .ds-atom-datepicker-event-dot {
1901
2074
  background: var(--ink);
@@ -1968,9 +2141,23 @@
1968
2141
  background: rgba(245, 158, 11, 0.18);
1969
2142
  filter: brightness(1.08);
1970
2143
  }
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. */
2144
+ /* Dark mode range endpoints: translucent amber strip (matches is-in-range dark bg). */
2145
+ .dark .ds-atom-datepicker-cell.is-selected.is-range-start {
2146
+ background: linear-gradient(to right, transparent 50%, rgba(245, 158, 11, 0.18) 50%);
2147
+ }
2148
+ .dark .ds-atom-datepicker-cell.is-selected.is-range-end {
2149
+ background: linear-gradient(to right, rgba(245, 158, 11, 0.18) 50%, transparent 50%);
2150
+ }
2151
+ .dark .ds-atom-datepicker-cell.is-selected.is-range-start:hover:not(:disabled) {
2152
+ background: linear-gradient(to right, transparent 50%, rgba(245, 158, 11, 0.18) 50%);
2153
+ filter: none;
2154
+ }
2155
+ .dark .ds-atom-datepicker-cell.is-selected.is-range-end:hover:not(:disabled) {
2156
+ background: linear-gradient(to right, rgba(245, 158, 11, 0.18) 50%, transparent 50%);
2157
+ filter: none;
2158
+ }
2159
+ .dark .ds-atom-datepicker-cell.is-selected.is-range-start:hover:not(:disabled)::before,
2160
+ .dark .ds-atom-datepicker-cell.is-selected.is-range-end:hover:not(:disabled)::before {
1974
2161
  background: #fbbf24;
1975
2162
  }
1976
2163
  .dark
@@ -1998,6 +2185,99 @@
1998
2185
  color: var(--ink);
1999
2186
  }
2000
2187
 
2188
+ /* ─── DS atom: DatePicker · popover variant (v0.6.0) ──────────────────
2189
+ Trigger pill + anchored Popover wrapper. Pill is a compact mono-font
2190
+ button that flips to a paper-warm / amber-border highlight while the
2191
+ popover is open (matches add-round handoff §02 State B). The popover
2192
+ container itself is .ds-atom-popover (from the Popover primitive); the
2193
+ datepicker inside uses .is-popover to drop the outer border/padding
2194
+ since the popover chrome already provides them. */
2195
+ .ds-atom-datepicker-trigger {
2196
+ display: inline-flex;
2197
+ align-items: center;
2198
+ gap: 6px;
2199
+ padding: 7px 11px;
2200
+ border: 1px solid var(--rule);
2201
+ border-radius: 7px;
2202
+ background: var(--panel, #ffffff);
2203
+ color: var(--ink);
2204
+ font-family: var(--mono);
2205
+ font-size: 11.5px;
2206
+ font-weight: 600;
2207
+ letter-spacing: 0.01em;
2208
+ line-height: 1;
2209
+ cursor: pointer;
2210
+ transition: background 0.08s ease, border-color 0.08s ease;
2211
+ }
2212
+ .ds-atom-datepicker-trigger:hover {
2213
+ border-color: var(--ink-3);
2214
+ }
2215
+ .ds-atom-datepicker-trigger:focus-visible {
2216
+ outline: 2px solid var(--amber);
2217
+ outline-offset: 2px;
2218
+ }
2219
+ .ds-atom-datepicker-trigger.is-open {
2220
+ background: var(--paper-warm, #f8f3e5);
2221
+ border-color: #e8d9ac;
2222
+ color: var(--amber-ink, var(--ink));
2223
+ }
2224
+ .ds-atom-datepicker-trigger-label.is-placeholder {
2225
+ color: var(--ink-4);
2226
+ font-style: italic;
2227
+ font-family: var(--serif, "Newsreader", Georgia, serif);
2228
+ font-weight: 500;
2229
+ font-size: 12px;
2230
+ letter-spacing: 0;
2231
+ }
2232
+ .ds-atom-datepicker-trigger-caret {
2233
+ color: var(--ink-3);
2234
+ font-size: 10px;
2235
+ line-height: 1;
2236
+ transform: translateY(-0.5px);
2237
+ }
2238
+ .ds-atom-datepicker-trigger.is-open .ds-atom-datepicker-trigger-caret {
2239
+ color: var(--amber-ink, var(--ink));
2240
+ }
2241
+ /* Popover wrapper: clamp width on narrow viewports so it never overflows. */
2242
+ .ds-atom-popover.ds-atom-datepicker-popover {
2243
+ padding: 0;
2244
+ max-width: calc(100vw - 24px);
2245
+ }
2246
+ /* Inside-popover calendar: shed the outer chrome (border/bg/padding) so the
2247
+ popover panel itself frames the calendar; the actions row below adds its
2248
+ own divider. */
2249
+ .ds-atom-datepicker.is-popover {
2250
+ display: block;
2251
+ background: transparent;
2252
+ border: 0;
2253
+ border-radius: 0;
2254
+ padding: 10px 10px 0;
2255
+ }
2256
+ .ds-atom-datepicker-popover-actions {
2257
+ display: flex;
2258
+ justify-content: flex-end;
2259
+ gap: 6px;
2260
+ padding: 8px 10px;
2261
+ margin-top: 4px;
2262
+ border-top: 1px solid var(--rule);
2263
+ }
2264
+ .dark .ds-atom-datepicker-trigger {
2265
+ background: rgba(255, 255, 255, 0.04);
2266
+ border-color: rgba(255, 255, 255, 0.12);
2267
+ color: var(--ink);
2268
+ }
2269
+ .dark .ds-atom-datepicker-trigger:hover {
2270
+ border-color: rgba(255, 255, 255, 0.22);
2271
+ }
2272
+ .dark .ds-atom-datepicker-trigger.is-open {
2273
+ background: rgba(245, 158, 11, 0.12);
2274
+ border-color: rgba(245, 158, 11, 0.45);
2275
+ color: var(--amber);
2276
+ }
2277
+ .dark .ds-atom-datepicker-popover-actions {
2278
+ border-top-color: rgba(255, 255, 255, 0.12);
2279
+ }
2280
+
2001
2281
  /* ─── DS atom: SplitButton ────────────────────────────────────────────
2002
2282
  Primary face + chevron divider + Popover menu (DS-56, D-530). Mirrors
2003
2283
  Button variant + size styling via data-variant + data-size selectors.
@@ -2304,6 +2584,37 @@
2304
2584
  opacity: 0.5;
2305
2585
  cursor: not-allowed;
2306
2586
  }
2587
+ /* Size scale — `sm` shrinks height + padding + text. Mirror of the
2588
+ matching MultiSelect rule. */
2589
+ .ds-atom-select[data-size="sm"] {
2590
+ height: 28px;
2591
+ min-width: 0;
2592
+ padding: 0 8px;
2593
+ font-size: 12px;
2594
+ border-radius: var(--radius-sm);
2595
+ gap: 6px;
2596
+ }
2597
+ /* Solid tone — ink-fill trigger with cream text. Mirror of the matching
2598
+ MultiSelect rule so filter rows mixing both stay visually consistent. */
2599
+ .ds-atom-select[data-tone="solid"] {
2600
+ background: var(--ink);
2601
+ color: var(--cream);
2602
+ border-color: transparent;
2603
+ }
2604
+ .ds-atom-select[data-tone="solid"] .ds-atom-select-placeholder,
2605
+ .ds-atom-select[data-tone="solid"] .ds-atom-select-value,
2606
+ .ds-atom-select[data-tone="solid"] .ds-atom-select-chevron {
2607
+ color: var(--cream);
2608
+ }
2609
+ .ds-atom-select[data-tone="solid"] .ds-atom-select-chevron {
2610
+ opacity: 0.7;
2611
+ }
2612
+ .ds-atom-select[data-tone="solid"]:hover:not(:disabled) {
2613
+ background: var(--ink-2);
2614
+ }
2615
+ .ds-atom-select[data-tone="solid"][data-state="open"] {
2616
+ border-color: var(--amber);
2617
+ }
2307
2618
  .ds-atom-select-value {
2308
2619
  display: inline-flex;
2309
2620
  align-items: center;
@@ -2441,6 +2752,59 @@
2441
2752
  outline: 2px solid var(--amber);
2442
2753
  outline-offset: 2px;
2443
2754
  }
2755
+ /* Compact mode (single-row count summary): the trigger no longer needs to host
2756
+ chips, so drop the 220px floor and collapse the multi-line max-height down
2757
+ to a single 36px row. Consumer wraps still control the outer width. */
2758
+ .ds-atom-multiselect-compact {
2759
+ min-width: 0;
2760
+ min-height: 36px;
2761
+ max-height: 36px;
2762
+ height: 36px;
2763
+ align-items: center;
2764
+ }
2765
+
2766
+ /* Size scale — `sm` shrinks height + padding + text. The compact mode
2767
+ already kills the chip-wrap; this lets a filter row sit at chip rhythm
2768
+ rather than form-input rhythm. */
2769
+ .ds-atom-multiselect[data-size="sm"] {
2770
+ min-height: 28px;
2771
+ max-height: 28px;
2772
+ height: 28px;
2773
+ padding: 0 10px;
2774
+ font-size: 12px;
2775
+ border-radius: var(--radius-sm);
2776
+ }
2777
+ .ds-atom-multiselect[data-size="sm"] .ds-atom-multiselect-chips {
2778
+ gap: 4px;
2779
+ }
2780
+ .ds-atom-multiselect[data-size="sm"].ds-atom-multiselect-compact {
2781
+ min-height: 28px;
2782
+ max-height: 28px;
2783
+ height: 28px;
2784
+ }
2785
+
2786
+ /* Solid tone — ink-fill trigger with cream text. The confident "filter
2787
+ applied" affordance, designed to pair with `compact` for a count-summary
2788
+ chip. Border collapses since the ink fill carries its own edge.
2789
+ Mirrors .ds-atom-select[data-tone="solid"] below. */
2790
+ .ds-atom-multiselect[data-tone="solid"] {
2791
+ background: var(--ink);
2792
+ color: var(--cream);
2793
+ border-color: transparent;
2794
+ }
2795
+ .ds-atom-multiselect[data-tone="solid"] .ds-atom-multiselect-placeholder {
2796
+ color: var(--cream);
2797
+ }
2798
+ .ds-atom-multiselect[data-tone="solid"] .ds-atom-multiselect-chevron {
2799
+ color: var(--cream);
2800
+ opacity: 0.7;
2801
+ }
2802
+ .ds-atom-multiselect[data-tone="solid"]:hover:not(:disabled) {
2803
+ background: var(--ink-2);
2804
+ }
2805
+ .ds-atom-multiselect[data-tone="solid"][data-state="open"] {
2806
+ border-color: var(--amber);
2807
+ }
2444
2808
  .ds-atom-multiselect:disabled {
2445
2809
  opacity: 0.5;
2446
2810
  cursor: not-allowed;
@@ -2495,6 +2859,13 @@
2495
2859
  .ds-atom-multiselect-chevron.is-open {
2496
2860
  transform: rotate(180deg);
2497
2861
  }
2862
+ /* Compact + sm: the trigger is align-items:center (single-row count summary)
2863
+ so the multi-row chip alignment offset on the chevron has to be cleared,
2864
+ otherwise it sits below center. */
2865
+ .ds-atom-multiselect-compact .ds-atom-multiselect-chevron,
2866
+ .ds-atom-multiselect[data-size="sm"] .ds-atom-multiselect-chevron {
2867
+ margin-top: 0;
2868
+ }
2498
2869
  .ds-atom-multiselect-list {
2499
2870
  list-style: none;
2500
2871
  margin: 0;
@@ -2531,6 +2902,10 @@
2531
2902
  .ds-atom-multiselect-checkbox.is-checked {
2532
2903
  background: var(--amber);
2533
2904
  border-color: var(--amber);
2905
+ /* Pinned dark on amber regardless of theme. var(--ink) flips to warm-cream
2906
+ in dark mode, which gave us light-on-bright-amber — illegible. The amber
2907
+ fill is constant across themes, so its glyph color is constant too. */
2908
+ color: #1f1b17;
2534
2909
  }
2535
2910
  .ds-atom-multiselect-option-label {
2536
2911
  flex: 1;
@@ -3938,8 +4313,8 @@
3938
4313
  display: inline-block;
3939
4314
  }
3940
4315
  .ds-atom-richtext-toolbar [data-active] {
3941
- background: color-mix(in srgb, var(--amber) 12%, transparent);
3942
- color: var(--amber);
4316
+ background: color-mix(in srgb, var(--amber) 12%, transparent) !important;
4317
+ color: var(--amber) !important;
3943
4318
  }
3944
4319
 
3945
4320
  /* ── Heading dropdown menu ────────────────────────────────────────────────── */
@@ -4003,6 +4378,13 @@
4003
4378
  margin: 14px 0 6px 0;
4004
4379
  line-height: 1.4;
4005
4380
  }
4381
+ /* Highlight mark */
4382
+ .ds-atom-richtext-surface .ProseMirror mark {
4383
+ background: #fef08a;
4384
+ color: inherit;
4385
+ border-radius: 2px;
4386
+ padding: 0 1px;
4387
+ }
4006
4388
  /* Inline code */
4007
4389
  .ds-atom-richtext-surface .ProseMirror code {
4008
4390
  background: var(--cream-3);
@@ -4773,3 +5155,778 @@
4773
5155
  .dark .ds-atom-sortable-item {
4774
5156
  /* tokens flip automatically - no override needed */
4775
5157
  }
5158
+ /* ─── DS atom: Kbd ───────────────────────────────────────────────────
5159
+ Keyboard key label. Mono font, bordered chip. Token-driven dark mode. */
5160
+ .ds-atom-kbd {
5161
+ font-family: var(--mono);
5162
+ font-size: 11px;
5163
+ line-height: 1;
5164
+ padding: 2px 6px;
5165
+ border-radius: 4px;
5166
+ border: 1px solid var(--rule);
5167
+ background: var(--cream-2);
5168
+ color: var(--ink-2);
5169
+ display: inline-flex;
5170
+ align-items: center;
5171
+ white-space: nowrap;
5172
+ box-shadow: 0 1px 0 var(--rule);
5173
+ flex-shrink: 0;
5174
+ }
5175
+ .dark .ds-atom-kbd {
5176
+ background: rgba(255, 255, 255, 0.08);
5177
+ border-color: rgba(255, 255, 255, 0.18);
5178
+ color: var(--ink);
5179
+ }
5180
+ /* ─── DS atom: RelativeTime ─────────────────────────────────────────
5181
+ Inline relative timestamp. Mono font, cursor-default. Token-driven. */
5182
+ .ds-atom-relative-time {
5183
+ font-family: var(--mono);
5184
+ font-size: 11px;
5185
+ font-weight: 700;
5186
+ color: var(--ink-2);
5187
+ cursor: default;
5188
+ }
5189
+ /* ─── DS atom: Pagination ────────────────────────────────────────────
5190
+ Page navigation: prev/next icon buttons + numbered page buttons + ellipsis. */
5191
+ .ds-atom-pagination {
5192
+ display: flex;
5193
+ flex-direction: column;
5194
+ gap: 4px;
5195
+ }
5196
+ .ds-atom-pagination-list {
5197
+ display: flex;
5198
+ align-items: center;
5199
+ gap: 4px;
5200
+ list-style: none;
5201
+ margin: 0;
5202
+ padding: 0;
5203
+ }
5204
+ .ds-atom-pagination-icbtn {
5205
+ width: 28px;
5206
+ height: 28px;
5207
+ border-radius: 7px;
5208
+ border: 1px solid var(--rule);
5209
+ background: var(--g-bg);
5210
+ display: inline-flex;
5211
+ align-items: center;
5212
+ justify-content: center;
5213
+ color: var(--ink-2);
5214
+ cursor: pointer;
5215
+ transition: all 0.15s;
5216
+ outline: none;
5217
+ }
5218
+ .ds-atom-pagination-icbtn:hover:not(:disabled) {
5219
+ background: var(--cream-2);
5220
+ border-color: rgba(0, 0, 0, 0.12);
5221
+ }
5222
+ .ds-atom-pagination-icbtn:disabled {
5223
+ opacity: 0.4;
5224
+ cursor: not-allowed;
5225
+ }
5226
+ .ds-atom-pagination-icbtn:focus-visible {
5227
+ outline: none;
5228
+ box-shadow: var(--focus-ring);
5229
+ border-color: var(--focus);
5230
+ }
5231
+ .dark .ds-atom-pagination-icbtn:hover:not(:disabled) {
5232
+ background: rgba(255, 255, 255, 0.08);
5233
+ border-color: var(--ink-4);
5234
+ }
5235
+ .ds-atom-pagination-btn {
5236
+ width: 28px;
5237
+ height: 28px;
5238
+ border-radius: 7px;
5239
+ border: 1px solid transparent;
5240
+ background: transparent;
5241
+ font-size: 12px;
5242
+ font-weight: 400;
5243
+ cursor: pointer;
5244
+ color: var(--ink-2);
5245
+ display: inline-flex;
5246
+ align-items: center;
5247
+ justify-content: center;
5248
+ transition: all 0.12s;
5249
+ font-family: var(--font);
5250
+ }
5251
+ .ds-atom-pagination-btn:hover:not([aria-current="page"]):not(:disabled) {
5252
+ background: var(--cream-2);
5253
+ }
5254
+ .ds-atom-pagination-btn[aria-current="page"] {
5255
+ background: var(--ink);
5256
+ color: var(--cream);
5257
+ font-weight: 700;
5258
+ cursor: default;
5259
+ }
5260
+ .ds-atom-pagination-btn:focus-visible {
5261
+ outline: none;
5262
+ box-shadow: var(--focus-ring);
5263
+ border-color: var(--focus);
5264
+ }
5265
+ .ds-atom-pagination-ellipsis {
5266
+ width: 28px;
5267
+ height: 28px;
5268
+ display: inline-flex;
5269
+ align-items: center;
5270
+ justify-content: center;
5271
+ font-size: 12px;
5272
+ color: var(--ink-4);
5273
+ pointer-events: none;
5274
+ user-select: none;
5275
+ }
5276
+ .ds-atom-pagination-label {
5277
+ font-family: var(--mono);
5278
+ font-size: 10px;
5279
+ color: var(--ink-4);
5280
+ margin-left: 6px;
5281
+ }
5282
+ .ds-atom-pagination-count {
5283
+ font-family: var(--mono);
5284
+ font-size: 11px;
5285
+ font-weight: 700;
5286
+ }
5287
+
5288
+ /* ─── DS atom: CommandPalette ────────────────────────────────────────────────
5289
+ DSPortal-mounted search panel. Backdrop reuses .ds-atom-modal-backdrop.
5290
+ Panel positioned at 15vh from top via backdrop inline style override
5291
+ (alignItems:flex-start, paddingTop:15vh) set in the component.
5292
+ Focus-trapped via useFocusTrap(panel, open). Document-level keyboard:
5293
+ Escape → onClose+clearQuery, ArrowDown/Up → clamp activeIndex,
5294
+ Enter → onSelect+onClose+clearQuery. Namespace: ds-atom-cmd-*. */
5295
+
5296
+ .ds-atom-cmd-panel {
5297
+ background: rgba(255, 255, 255, 0.97); /* always-light — NOT cream token; matches ConfirmDialog CONSTRAINT-010 */
5298
+ -webkit-backdrop-filter: blur(14px);
5299
+ backdrop-filter: blur(14px);
5300
+ border: 1px solid var(--rule);
5301
+ border-radius: var(--radius-lg);
5302
+ box-shadow: var(--shadow-3);
5303
+ width: 560px;
5304
+ max-width: calc(100% - var(--space-4));
5305
+ max-height: 420px;
5306
+ display: flex;
5307
+ flex-direction: column;
5308
+ overflow: hidden;
5309
+ font-family: var(--font);
5310
+ color: var(--ink);
5311
+ animation: ds-atom-cmd-in 0.18s ease-out;
5312
+ }
5313
+ .dark .ds-atom-cmd-panel {
5314
+ background: var(--cream-2);
5315
+ border-color: var(--rule);
5316
+ }
5317
+
5318
+ /* search input row */
5319
+ .ds-atom-cmd-search {
5320
+ display: flex;
5321
+ align-items: center;
5322
+ gap: 10px;
5323
+ padding: 12px 14px;
5324
+ border-bottom: 1px solid var(--rule);
5325
+ flex-shrink: 0;
5326
+ }
5327
+ .ds-atom-cmd-input {
5328
+ flex: 1;
5329
+ border: none;
5330
+ outline: none;
5331
+ background: transparent;
5332
+ font-family: var(--font);
5333
+ font-size: 15px;
5334
+ color: var(--ink);
5335
+ min-width: 0;
5336
+ }
5337
+ .ds-atom-cmd-input::placeholder {
5338
+ color: var(--ink-4);
5339
+ }
5340
+
5341
+ /* scrollable results list */
5342
+ .ds-atom-cmd-list {
5343
+ overflow-y: auto;
5344
+ flex: 1;
5345
+ padding: 6px 0;
5346
+ }
5347
+
5348
+ /* group header */
5349
+ .ds-atom-cmd-group {
5350
+ font-family: var(--mono);
5351
+ font-size: 9px;
5352
+ font-weight: 700;
5353
+ text-transform: uppercase;
5354
+ letter-spacing: 0.08em;
5355
+ color: var(--ink-4);
5356
+ padding: 8px 14px 4px;
5357
+ }
5358
+
5359
+ /* result item */
5360
+ .ds-atom-cmd-item {
5361
+ display: flex;
5362
+ align-items: center;
5363
+ gap: 10px;
5364
+ padding: 8px 14px;
5365
+ cursor: pointer;
5366
+ border-radius: 8px;
5367
+ margin: 0 6px;
5368
+ font-size: 13.5px;
5369
+ color: var(--ink);
5370
+ transition: background 0.1s;
5371
+ }
5372
+ .ds-atom-cmd-item:hover,
5373
+ .ds-atom-cmd-item[aria-selected="true"] {
5374
+ background: var(--cream-2);
5375
+ }
5376
+ .dark .ds-atom-cmd-item:hover,
5377
+ .dark .ds-atom-cmd-item[aria-selected="true"] {
5378
+ background: var(--cream-3);
5379
+ }
5380
+
5381
+ /* item sub-elements */
5382
+ .ds-atom-cmd-item-icon {
5383
+ display: inline-flex;
5384
+ align-items: center;
5385
+ justify-content: center;
5386
+ width: 18px;
5387
+ height: 18px;
5388
+ color: var(--ink-3);
5389
+ flex-shrink: 0;
5390
+ }
5391
+ .ds-atom-cmd-item-label {
5392
+ flex: 1;
5393
+ min-width: 0;
5394
+ white-space: nowrap;
5395
+ overflow: hidden;
5396
+ text-overflow: ellipsis;
5397
+ }
5398
+ .ds-atom-cmd-item-shortcut {
5399
+ margin-left: auto;
5400
+ flex-shrink: 0;
5401
+ }
5402
+
5403
+ /* no-results empty state */
5404
+ .ds-atom-cmd-empty {
5405
+ padding: 24px 14px;
5406
+ text-align: center;
5407
+ font-size: 13px;
5408
+ color: var(--ink-4);
5409
+ font-family: var(--font);
5410
+ }
5411
+
5412
+ @keyframes ds-atom-cmd-in {
5413
+ from {
5414
+ opacity: 0;
5415
+ transform: scale(0.96) translateY(-8px);
5416
+ }
5417
+ to {
5418
+ opacity: 1;
5419
+ transform: none;
5420
+ }
5421
+ }
5422
+
5423
+ /* ─── DS atom: ColorPicker ──────────────────────────────────────────────
5424
+ Most ColorPicker styles are inline (consistent with DatePicker / StatCard).
5425
+ This block covers only what cannot be expressed inline:
5426
+ pointer-events passthrough on thumbs, focus rings on keyboard-draggable
5427
+ areas, and button-reset on swatch/strip cells. */
5428
+
5429
+ /* Thumbs must not intercept pointer events — the parent track div owns drag. */
5430
+ .ds-atom-colorpicker-thumb {
5431
+ pointer-events: none;
5432
+ position: absolute;
5433
+ transform: translate(-50%, -50%);
5434
+ }
5435
+
5436
+ /* Focus ring on keyboard-draggable areas (role="slider"). */
5437
+ .ds-atom-colorpicker-canvas:focus-visible,
5438
+ .ds-atom-colorpicker-huebar:focus-visible,
5439
+ .ds-atom-colorpicker-opacitybar:focus-visible {
5440
+ outline: none;
5441
+ box-shadow: var(--focus-ring);
5442
+ border-radius: 6px;
5443
+ }
5444
+
5445
+ /* Preset swatch buttons and tonal strip cell buttons. */
5446
+ .ds-atom-colorpicker-swatch,
5447
+ .ds-atom-colorpicker-cell {
5448
+ appearance: none;
5449
+ border: none;
5450
+ padding: 0;
5451
+ cursor: pointer;
5452
+ transition: transform 0.12s ease;
5453
+ }
5454
+
5455
+ .ds-atom-colorpicker-swatch:focus-visible,
5456
+ .ds-atom-colorpicker-cell:focus-visible {
5457
+ outline: none;
5458
+ box-shadow: var(--focus-ring);
5459
+ }
5460
+
5461
+ /* ─── DS atom: DataGrid (DS-62) ─────────────────────────────────────────────
5462
+ Composed wrapper: bulk-action bar + scroll + footer around Table.
5463
+ Inner table chrome uses existing ds-atom-table-* classes. */
5464
+
5465
+ /* Outer glass container */
5466
+ .ds-atom-datagrid {
5467
+ border-radius: 14px;
5468
+ overflow: hidden;
5469
+ }
5470
+
5471
+ /* Scroll container — enables horizontal scroll when columns exceed viewport */
5472
+ .ds-atom-datagrid-scroll {
5473
+ overflow-x: auto;
5474
+ }
5475
+
5476
+ /* Bulk-action bar — amber tint, shown when rows are selected */
5477
+ .ds-atom-datagrid-bulkbar {
5478
+ padding: 8px 16px;
5479
+ background: rgba(245, 158, 11, 0.05);
5480
+ border-bottom: 1px solid var(--rule);
5481
+ display: flex;
5482
+ align-items: center;
5483
+ gap: 10px;
5484
+ font-size: 12px;
5485
+ }
5486
+ .ds-atom-datagrid-bulkbar-count {
5487
+ font-weight: 600;
5488
+ font-family: var(--mono);
5489
+ font-size: 11px;
5490
+ }
5491
+ .dark .ds-atom-datagrid-bulkbar {
5492
+ background: rgba(245, 158, 11, 0.07);
5493
+ }
5494
+
5495
+ /* Footer — row count (left) + Pagination (right) */
5496
+ .ds-atom-datagrid-footer {
5497
+ padding: 10px 16px;
5498
+ border-top: 1px solid var(--rule);
5499
+ display: flex;
5500
+ align-items: center;
5501
+ justify-content: space-between;
5502
+ }
5503
+ .ds-atom-datagrid-footer-count {
5504
+ font-family: var(--mono);
5505
+ font-size: 10px;
5506
+ color: var(--ink-4);
5507
+ }
5508
+
5509
+ /* ─── DS atom: OAuthButton ─────────────────────────────────────────────
5510
+ Geometry baseline (height/radius/font/padding) lives here so the theme
5511
+ layer can override; prop-derived bits (dark-mode bg/color/border) ride
5512
+ inline styles in the component.
5513
+ Inherits the same interaction conventions as DS Button — :active scale,
5514
+ :focus-visible amber ring, :disabled opacity — so OAuth and email-form
5515
+ buttons feel identical to the user. */
5516
+ .ds-atom-oauthbtn {
5517
+ display: inline-flex;
5518
+ align-items: center;
5519
+ justify-content: center;
5520
+ gap: 10px;
5521
+ height: 44px;
5522
+ width: 100%;
5523
+ padding: 0 18px;
5524
+ border-radius: 9px;
5525
+ font-family: var(--font);
5526
+ font-size: 13px;
5527
+ font-weight: 600;
5528
+ cursor: pointer;
5529
+ transition: background-color 0.15s, border-color 0.15s, transform 0.08s;
5530
+ user-select: none;
5531
+ -webkit-tap-highlight-color: transparent;
5532
+ }
5533
+ .ds-atom-oauthbtn:active:not(:disabled) {
5534
+ transform: scale(0.97);
5535
+ }
5536
+ .ds-atom-oauthbtn:disabled {
5537
+ opacity: 0.4;
5538
+ cursor: not-allowed;
5539
+ pointer-events: none;
5540
+ }
5541
+ .ds-atom-oauthbtn:focus-visible {
5542
+ outline: none;
5543
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.25);
5544
+ }
5545
+ .ds-atom-oauthbtn:hover:not(:disabled) {
5546
+ background: var(--cream-2);
5547
+ border-color: rgba(0, 0, 0, 0.12);
5548
+ }
5549
+ .ds-atom-oauthbtn[data-dark="true"]:hover:not(:disabled) {
5550
+ background: rgba(255, 255, 255, 0.08);
5551
+ border-color: rgba(255, 255, 255, 0.18);
5552
+ }
5553
+
5554
+ /* ─── DS atom: Link ─────────────────────────────────────────────────────
5555
+ Three variants (inline / footer / action). Hover deepens the underline
5556
+ from 25% → 100% opacity (light) / 40% → 100% (dark) per the design's
5557
+ "full-opacity underline on hover" convention. No :active transform —
5558
+ links aren't buttons; the underline change is the press affordance. */
5559
+ .ds-atom-link {
5560
+ text-decoration: underline;
5561
+ text-underline-offset: 2px;
5562
+ cursor: pointer;
5563
+ transition: color 0.15s, text-decoration-color 0.15s;
5564
+ }
5565
+ .ds-atom-link:hover {
5566
+ text-decoration-color: currentColor;
5567
+ }
5568
+ .ds-atom-link:focus-visible {
5569
+ outline: none;
5570
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.25);
5571
+ border-radius: 2px;
5572
+ }
5573
+ .dark .ds-atom-link[data-variant="footer"],
5574
+ .dark .ds-atom-link[data-variant="action"] {
5575
+ color: var(--ink);
5576
+ text-decoration-color: rgba(255, 255, 255, 0.4);
5577
+ }
5578
+
5579
+ /* ─── DS atom: Heading / Text / Eyebrow ────────────────────────────────
5580
+ Non-interactive primitives — colors flow via tokens.css :root.dark
5581
+ automatically. No hover/focus rules needed. */
5582
+
5583
+ /* ─── DS atom: Divider ─────────────────────────────────────────────────
5584
+ Hairline rules use var(--rule) which flips in dark mode via tokens.css.
5585
+ The labeled-variant <span> children inherit the labelStyle inline. */
5586
+
5587
+ /* ─── DS atom: DotGrid ─────────────────────────────────────────────────
5588
+ Geometry baseline; the radial-gradient image + opacity ride inline
5589
+ styles (prop-derived). pointer-events: none so the overlay never
5590
+ blocks pointer interaction with the content beneath. */
5591
+ .ds-atom-dotgrid {
5592
+ position: absolute;
5593
+ inset: 0;
5594
+ pointer-events: none;
5595
+ }
5596
+
5597
+ /* ─── DS layout: SplitHero ─────────────────────────────────────────────
5598
+ All sizing/responsive concerns are emitted by the component (inline
5599
+ <style> with component-scoped class). No global rules needed here. */
5600
+
5601
+ /* ─── DS atom: StatusPill ──────────────────────────────────────────────
5602
+ Per-stage pipeline chip. Six locked stages map to subtle tints. Used in
5603
+ both kanban cards and DataGrid status columns from the same atom so the
5604
+ visual contract stays single-sourced.
5605
+ Ported from design/cairn_ds_additions/Cairn DS Additions.html §01. */
5606
+ .ds-atom-statuspill {
5607
+ display: inline-flex;
5608
+ align-items: center;
5609
+ gap: 5px;
5610
+ font-size: 11px;
5611
+ font-weight: 600;
5612
+ padding: 3px 9px;
5613
+ border-radius: 999px;
5614
+ font-family: var(--font);
5615
+ border: 1px solid transparent;
5616
+ white-space: nowrap;
5617
+ cursor: pointer;
5618
+ transition: filter 0.12s, border-color 0.12s;
5619
+ background: transparent;
5620
+ }
5621
+ .ds-atom-statuspill[data-interactive="false"] {
5622
+ cursor: default;
5623
+ }
5624
+ .ds-atom-statuspill:hover {
5625
+ filter: brightness(0.97);
5626
+ }
5627
+ .dark .ds-atom-statuspill:hover {
5628
+ filter: brightness(1.08);
5629
+ }
5630
+ .ds-atom-statuspill-chev {
5631
+ font-size: 10px;
5632
+ opacity: 0.65;
5633
+ margin-left: 1px;
5634
+ }
5635
+ .ds-atom-statuspill[data-stage="wishlist"] {
5636
+ background: var(--cream-2);
5637
+ color: var(--ink-3);
5638
+ border-color: var(--rule);
5639
+ }
5640
+ .ds-atom-statuspill[data-stage="applied"] {
5641
+ background: transparent;
5642
+ color: var(--ink-2);
5643
+ border-color: var(--ink-5);
5644
+ }
5645
+ .ds-atom-statuspill[data-stage="screening"] {
5646
+ background: rgba(245, 158, 11, 0.1);
5647
+ color: var(--amber-d);
5648
+ }
5649
+ .ds-atom-statuspill[data-stage="interviewing"] {
5650
+ background: rgba(245, 158, 11, 0.18);
5651
+ color: var(--amber-d);
5652
+ font-weight: 700;
5653
+ }
5654
+ .ds-atom-statuspill[data-stage="offer"] {
5655
+ background: rgba(34, 197, 94, 0.14);
5656
+ color: var(--green);
5657
+ }
5658
+ .ds-atom-statuspill[data-stage="closed"] {
5659
+ background: var(--cream-3);
5660
+ color: var(--ink-3);
5661
+ }
5662
+ .dark .ds-atom-statuspill[data-stage="offer"] {
5663
+ background: rgba(34, 197, 94, 0.18);
5664
+ color: var(--green-vivid);
5665
+ }
5666
+ .ds-atom-statuspill:focus-visible {
5667
+ outline: none;
5668
+ box-shadow: var(--focus-ring);
5669
+ }
5670
+
5671
+ /* ─── DS atom: Heading (data-attr extensions) ─────────────────────────
5672
+ The TS Heading component already drives sizing via inline styles when
5673
+ `size` is numeric. These rules add a data-attr-driven path so calls
5674
+ like <Heading size="2xl" weight="black" tone="amber"> work declaratively
5675
+ (CSS does the work, no inline style allocation). Bundle: §02. */
5676
+ /* Body-size tokens read better at --lh-snug (1.08) — small headings stack
5677
+ in dense UI; display sizes use --lh-tight (0.94) so multiline heroes hug
5678
+ tightly. Letter-spacing follows the same break. */
5679
+ .ds-atom-heading[data-size="2xs"] {
5680
+ font-size: var(--text-2xs);
5681
+ line-height: var(--lh-snug);
5682
+ }
5683
+ .ds-atom-heading[data-size="xs"] {
5684
+ font-size: var(--text-xs);
5685
+ line-height: var(--lh-snug);
5686
+ }
5687
+ .ds-atom-heading[data-size="sm"] {
5688
+ font-size: var(--text-sm);
5689
+ line-height: var(--lh-snug);
5690
+ }
5691
+ .ds-atom-heading[data-size="base"] {
5692
+ font-size: var(--text-base);
5693
+ line-height: var(--lh-snug);
5694
+ }
5695
+ .ds-atom-heading[data-size="md"] {
5696
+ font-size: var(--text-md);
5697
+ line-height: var(--lh-snug);
5698
+ }
5699
+ .ds-atom-heading[data-size="lg"] {
5700
+ font-size: var(--text-lg);
5701
+ line-height: var(--lh-snug);
5702
+ }
5703
+ .ds-atom-heading[data-size="xl"] {
5704
+ font-size: var(--text-xl);
5705
+ line-height: var(--lh-snug);
5706
+ }
5707
+ .ds-atom-heading[data-size="2xl"] {
5708
+ font-size: var(--text-2xl);
5709
+ line-height: var(--lh-snug);
5710
+ }
5711
+ .ds-atom-heading[data-size="3xl"] {
5712
+ font-size: var(--text-3xl);
5713
+ line-height: var(--lh-tight);
5714
+ letter-spacing: var(--ls-tighter);
5715
+ }
5716
+ .ds-atom-heading[data-size="4xl"] {
5717
+ font-size: var(--text-4xl);
5718
+ line-height: var(--lh-tight);
5719
+ letter-spacing: var(--ls-tighter);
5720
+ }
5721
+ .ds-atom-heading[data-weight="regular"] {
5722
+ font-weight: 500;
5723
+ }
5724
+ .ds-atom-heading[data-weight="medium"] {
5725
+ font-weight: 600;
5726
+ }
5727
+ .ds-atom-heading[data-weight="bold"] {
5728
+ font-weight: 700;
5729
+ }
5730
+ .ds-atom-heading[data-weight="black"] {
5731
+ font-weight: 900;
5732
+ }
5733
+ .ds-atom-heading[data-tone="ink-2"] {
5734
+ color: var(--ink-2);
5735
+ }
5736
+ .ds-atom-heading[data-tone="ink-3"] {
5737
+ color: var(--ink-3);
5738
+ }
5739
+ .ds-atom-heading[data-tone="amber"] {
5740
+ color: var(--amber-d);
5741
+ }
5742
+
5743
+ /* ─── DS atom: Text (data-attr extensions) ────────────────────────────
5744
+ Adds a declarative path next to the existing `variant`-driven one.
5745
+ Variants ('body'|'small'|'caption'|'legal') still work via the TS
5746
+ inline-style path; size/weight/tone/mono/leading are the new data-
5747
+ attr-driven path. Bundle: §03. */
5748
+ .ds-atom-text[data-size="2xs"] {
5749
+ font-size: var(--text-2xs);
5750
+ }
5751
+ .ds-atom-text[data-size="xs"] {
5752
+ font-size: var(--text-xs);
5753
+ }
5754
+ .ds-atom-text[data-size="sm"] {
5755
+ font-size: var(--text-sm);
5756
+ }
5757
+ .ds-atom-text[data-size="base"] {
5758
+ font-size: var(--text-base);
5759
+ }
5760
+ .ds-atom-text[data-size="md"] {
5761
+ font-size: var(--text-md);
5762
+ }
5763
+ .ds-atom-text[data-size="lg"] {
5764
+ font-size: var(--text-lg);
5765
+ }
5766
+ .ds-atom-text[data-weight="regular"] {
5767
+ font-weight: 400;
5768
+ }
5769
+ .ds-atom-text[data-weight="medium"] {
5770
+ font-weight: 500;
5771
+ }
5772
+ .ds-atom-text[data-weight="bold"] {
5773
+ font-weight: 600;
5774
+ }
5775
+ .ds-atom-text[data-weight="black"] {
5776
+ font-weight: 700;
5777
+ }
5778
+ .ds-atom-text[data-tone="ink"] {
5779
+ color: var(--ink);
5780
+ }
5781
+ .ds-atom-text[data-tone="ink-3"] {
5782
+ color: var(--ink-3);
5783
+ }
5784
+ .ds-atom-text[data-tone="ink-4"] {
5785
+ color: var(--ink-4);
5786
+ }
5787
+ .ds-atom-text[data-tone="amber"] {
5788
+ color: var(--amber-d);
5789
+ }
5790
+ .ds-atom-text[data-tone="red"] {
5791
+ color: var(--red);
5792
+ }
5793
+ .ds-atom-text[data-tone="green"] {
5794
+ color: var(--green);
5795
+ }
5796
+ .ds-atom-text[data-mono="true"] {
5797
+ font-family: var(--mono);
5798
+ letter-spacing: 0.02em;
5799
+ }
5800
+ .ds-atom-text[data-leading="tight"] {
5801
+ line-height: var(--lh-tight);
5802
+ }
5803
+ .ds-atom-text[data-leading="snug"] {
5804
+ line-height: var(--lh-snug);
5805
+ }
5806
+ .ds-atom-text[data-leading="relaxed"] {
5807
+ line-height: var(--lh-relaxed);
5808
+ }
5809
+
5810
+ /* ─── DS atom: Eyebrow (tone data-attr extension) ─────────────────────
5811
+ Existing `size` + `color` props still work via inline style; new `tone`
5812
+ prop is data-attr-driven. Bundle: §04. */
5813
+ .ds-atom-eyebrow[data-tone="amber"] {
5814
+ color: var(--amber-d);
5815
+ }
5816
+ .ds-atom-eyebrow[data-tone="ink-4"] {
5817
+ color: var(--ink-4);
5818
+ }
5819
+
5820
+ /* ─── DS atom: Card (data-attr extensions) ────────────────────────────
5821
+ The TS Card has `variant` ('glass'|'amber'|'dark'|'kanban'). New
5822
+ data-attrs (padding/radius/hover/tone) are independent and additive:
5823
+ they layer on top of the variant. Bundle: §05. */
5824
+ .ds-atom-card[data-padding="none"] {
5825
+ padding: 0;
5826
+ }
5827
+ .ds-atom-card[data-padding="sm"] {
5828
+ padding: var(--space-3);
5829
+ }
5830
+ .ds-atom-card[data-padding="md"] {
5831
+ padding: var(--space-4);
5832
+ }
5833
+ .ds-atom-card[data-padding="lg"] {
5834
+ padding: var(--space-6);
5835
+ }
5836
+ .ds-atom-card[data-padding="xl"] {
5837
+ padding: var(--space-8);
5838
+ }
5839
+ .ds-atom-card[data-radius="sm"] {
5840
+ border-radius: var(--radius-sm);
5841
+ }
5842
+ .ds-atom-card[data-radius="md"] {
5843
+ border-radius: var(--radius-md);
5844
+ }
5845
+ .ds-atom-card[data-radius="lg"] {
5846
+ border-radius: var(--radius-lg);
5847
+ }
5848
+ .ds-atom-card[data-radius="xl"] {
5849
+ border-radius: var(--radius-xl);
5850
+ }
5851
+ .ds-atom-card[data-hover="elevate"] {
5852
+ cursor: pointer;
5853
+ transition: box-shadow 0.15s, border-color 0.15s;
5854
+ }
5855
+ .ds-atom-card[data-hover="elevate"]:hover {
5856
+ box-shadow: var(--shadow-2);
5857
+ border-color: rgba(0, 0, 0, 0.12);
5858
+ }
5859
+ .dark .ds-atom-card[data-hover="elevate"]:hover {
5860
+ border-color: var(--ink-4);
5861
+ }
5862
+ .ds-atom-card[data-tone="amber"] {
5863
+ background: var(--amber-l);
5864
+ border-color: rgba(245, 158, 11, 0.3);
5865
+ }
5866
+ .ds-atom-card[data-tone="cream-2"] {
5867
+ background: var(--cream-2);
5868
+ }
5869
+ .ds-atom-card[data-tone="flat"] {
5870
+ background: transparent;
5871
+ border: 1px dashed var(--rule);
5872
+ }
5873
+
5874
+ /* ─── DS atom: Link (quiet + default variants) ────────────────────────
5875
+ The TS Link already supports inline / footer / action. Bundle adds
5876
+ `default` (neutral underline that turns amber on hover) and `quiet`
5877
+ (no underline until hover). Bundle: §06. */
5878
+ .ds-atom-link[data-variant="default"] {
5879
+ color: var(--ink-2);
5880
+ text-decoration: underline;
5881
+ text-decoration-thickness: 1px;
5882
+ text-underline-offset: 2px;
5883
+ }
5884
+ .ds-atom-link[data-variant="default"]:hover {
5885
+ color: var(--ink);
5886
+ text-decoration-color: var(--amber);
5887
+ }
5888
+ .ds-atom-link[data-variant="quiet"] {
5889
+ color: var(--ink-3);
5890
+ text-decoration: none;
5891
+ }
5892
+ .ds-atom-link[data-variant="quiet"]:hover {
5893
+ color: var(--ink);
5894
+ text-decoration: underline;
5895
+ }
5896
+
5897
+ /* ─── DS atom: Divider (spacing + style extensions) ───────────────────
5898
+ The TS Divider already supports horizontal/vertical + optional label.
5899
+ New data-attrs add spacing presets + dashed/amber-accent styles.
5900
+ Bundle: §07. */
5901
+ .ds-atom-divider[data-spacing="none"] {
5902
+ margin: 0;
5903
+ }
5904
+ .ds-atom-divider[data-spacing="sm"][data-orient="horizontal"] {
5905
+ margin: var(--space-2) 0;
5906
+ }
5907
+ .ds-atom-divider[data-spacing="md"][data-orient="horizontal"] {
5908
+ margin: var(--space-4) 0;
5909
+ }
5910
+ .ds-atom-divider[data-spacing="lg"][data-orient="horizontal"] {
5911
+ margin: var(--space-6) 0;
5912
+ }
5913
+ .ds-atom-divider[data-spacing="xl"][data-orient="horizontal"] {
5914
+ margin: var(--space-8) 0;
5915
+ }
5916
+ .ds-atom-divider[data-spacing="sm"][data-orient="vertical"] {
5917
+ margin: 0 var(--space-2);
5918
+ }
5919
+ .ds-atom-divider[data-spacing="md"][data-orient="vertical"] {
5920
+ margin: 0 var(--space-3);
5921
+ }
5922
+ .ds-atom-divider[data-spacing="lg"][data-orient="vertical"] {
5923
+ margin: 0 var(--space-4);
5924
+ }
5925
+ .ds-atom-divider[data-style="dashed"] {
5926
+ background: transparent;
5927
+ border-top: 1px dashed var(--rule);
5928
+ }
5929
+ .ds-atom-divider[data-style="amber"] {
5930
+ background: rgba(245, 158, 11, 0.3);
5931
+ height: 2px;
5932
+ }