@syncedco/flow 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@syncedco/flow",
3
- "version": "0.2.0",
4
- "description": "AI-native fluid CSS design system for brand-consistent websites and agency builds.",
3
+ "version": "0.3.1",
4
+ "description": "AI-friendly fluid CSS design system for brand-consistent websites and agency builds.",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@11.2.2",
7
7
  "license": "MIT",
@@ -63,6 +63,7 @@
63
63
  "examples",
64
64
  "skills",
65
65
  "src",
66
+ "CHANGELOG.md",
66
67
  "CODE_OF_CONDUCT.md",
67
68
  "CONTRIBUTING.md",
68
69
  "LICENSE",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: synced-flow
3
- description: Use Synced Flow to set up and build modern fluid CSS systems with the CLI, tokens, presets, WordPress support, and source-scanned utility CSS.
3
+ description: Use Synced Flow to set up and build modern fluid CSS systems with the CLI, tokens, presets, app UI primitives, WordPress support, and source-scanned utility CSS.
4
4
  ---
5
5
 
6
6
  # Synced Flow
@@ -87,12 +87,25 @@ intact. Leave out `utilities.css` unless static helpers such as `sf-text-*`,
87
87
 
88
88
  - Prefer primitives first: `sf-container`, `sf-section`, `sf-stack`,
89
89
  `sf-cluster`, `sf-repel`, `sf-auto-grid`, `sf-split`, `sf-sidebar`,
90
- `sf-frame`, and `sf-flow`.
90
+ `sf-app-shell`, `sf-app-header`, `sf-app-sidebar`, `sf-app-main`,
91
+ `sf-app-backdrop`, `sf-frame`, and `sf-flow`.
91
92
  - Prefer component primitives for common UI: `sf-button`, `sf-card`,
92
- `sf-badge`, `sf-field`, and `sf-input`.
93
- - Use `saas-landing` for public SaaS marketing pages. Use `saas-dashboard` for
94
- authenticated app UI, admin panels, portals, CRMs, analytics dashboards,
95
- metrics, tables, account menus, and login state.
93
+ `sf-badge`, `sf-status`, `sf-field`, `sf-input`, `sf-search`,
94
+ `sf-data-table`, `sf-table-sort`, `sf-tab__count`, and `sf-toast-stack`.
95
+ - Use `saas-landing` for public SaaS marketing pages. Use `saas-dashboard` when
96
+ a full authenticated starter is useful, but prefer neutral app patterns for
97
+ reusable UI in admin panels, portals, CRMs, analytics dashboards, internal
98
+ tools, account areas, and product workspaces.
99
+ - Use app patterns before writing project CSS:
100
+ `app-shell-layout`, `row-action-menu`, `tabs-with-counts`,
101
+ `data-table-actions`, `search-field`, `modal-form`, and `toast-stack`.
102
+ - Use app shell states instead of bespoke layout CSS: `data-layout="fixed-header"`
103
+ for fixed app headers, `data-collapsed="true"` for collapsed sidebars, and
104
+ `data-mobile="drawer"` with `data-sidebar-open="true"` for mobile drawer
105
+ navigation.
106
+ - Keep product-specific structures out of Synced Flow. Kanban boards, invoices,
107
+ proposal builders, scheduling workflows, and complex editable grids should stay
108
+ in the consuming app unless they become broadly reusable primitives.
96
109
  - Do not implement authentication logic in Synced Flow markup. Wire sessions,
97
110
  providers, permissions, and sign-out actions in the consuming app.
98
111
  - Prefer native component patterns for common interaction: `sf-dialog`,
@@ -112,6 +125,10 @@ intact. Leave out `utilities.css` unless static helpers such as `sf-text-*`,
112
125
  accessibility and explicit UI styling.
113
126
  - Put brand choices in `theme` config or theme presets rather than scattered
114
127
  one-off CSS.
128
+ - Use semantic app tokens before local overrides: `surfaceRaised2`,
129
+ `surfaceHover`, `borderSubtle`, `backdrop`, and `categorical1` through
130
+ `categorical6`. Devs may still supply valid CSS colour formats such as hex,
131
+ RGB, HSL, or OKLCH in their own theme config.
115
132
  - Use modern CSS techniques already in the system: cascade layers, custom
116
133
  properties, logical properties, `clamp()`, OKLCH colour, container-aware
117
134
  layout, and `prefers-reduced-motion`.
package/src/tokens.mjs CHANGED
@@ -75,9 +75,13 @@ export const semanticTokens = {
75
75
  surface: 'var(--sf-colour-neutral-0)',
76
76
  surfaceAlt: 'var(--sf-colour-neutral-100)',
77
77
  surfaceRaised: 'var(--sf-colour-neutral-0)',
78
+ surfaceRaised2: 'var(--sf-colour-neutral-50)',
79
+ surfaceHover: 'var(--sf-colour-neutral-100)',
78
80
  surfaceInset: 'var(--sf-colour-neutral-100)',
81
+ borderSubtle: 'oklch(18% 0.026 250 / 0.08)',
79
82
  border: 'oklch(18% 0.026 250 / 0.12)',
80
83
  borderStrong: 'oklch(18% 0.026 250 / 0.22)',
84
+ backdrop: 'oklch(0% 0 0 / 0.48)',
81
85
  primary: 'var(--sf-colour-orange-600)',
82
86
  primaryHover: 'var(--sf-colour-orange-700)',
83
87
  primaryForeground: 'var(--sf-colour-neutral-0)',
@@ -99,6 +103,12 @@ export const semanticTokens = {
99
103
  info: 'var(--sf-colour-cyan-600)',
100
104
  infoForeground: 'var(--sf-colour-neutral-0)',
101
105
  infoSoft: 'oklch(70% 0.12 205 / 0.14)',
106
+ categorical1: 'var(--sf-colour-cyan-600)',
107
+ categorical2: 'var(--sf-colour-green-600)',
108
+ categorical3: 'var(--sf-colour-amber-500)',
109
+ categorical4: 'var(--sf-colour-orange-600)',
110
+ categorical5: 'var(--sf-colour-red-600)',
111
+ categorical6: 'oklch(58% 0.15 292)',
102
112
  ring: 'var(--sf-colour-orange-600)',
103
113
  },
104
114
  }
package/styles.css CHANGED
@@ -18,6 +18,7 @@
18
18
  --sf-step-6: clamp(2.986rem, 2.5863rem + 1.7763vw, 4.2915rem);
19
19
  --sf-step-7: clamp(3.5832rem, 3.0379rem + 2.4235vw, 5.3644rem);
20
20
  --sf-step-8: clamp(4.2998rem, 3.5634rem + 3.2731vw, 6.7055rem);
21
+ --sf-type-caption-sm: var(--sf-step--2);
21
22
  --sf-type-caption: var(--sf-step--1);
22
23
  --sf-type-body: var(--sf-step-0);
23
24
  --sf-type-lead: var(--sf-step-1);
@@ -107,9 +108,13 @@
107
108
  --sf-colour-surface: var(--sf-colour-neutral-0);
108
109
  --sf-colour-surface-alt: var(--sf-colour-neutral-100);
109
110
  --sf-colour-surface-raised: var(--sf-colour-neutral-0);
111
+ --sf-colour-surface-raised-2: var(--sf-colour-neutral-50);
112
+ --sf-colour-surface-hover: var(--sf-colour-neutral-100);
110
113
  --sf-colour-surface-inset: var(--sf-colour-neutral-100);
114
+ --sf-colour-border-subtle: oklch(18% 0.026 250 / 0.08);
111
115
  --sf-colour-border: oklch(18% 0.026 250 / 0.12);
112
116
  --sf-colour-border-strong: oklch(18% 0.026 250 / 0.22);
117
+ --sf-colour-backdrop: oklch(0% 0 0 / 0.48);
113
118
  --sf-colour-primary: var(--sf-colour-orange-600);
114
119
  --sf-colour-primary-hover: var(--sf-colour-orange-700);
115
120
  --sf-colour-primary-foreground: var(--sf-colour-neutral-0);
@@ -131,6 +136,12 @@
131
136
  --sf-colour-info: var(--sf-colour-cyan-600);
132
137
  --sf-colour-info-foreground: var(--sf-colour-neutral-0);
133
138
  --sf-colour-info-soft: oklch(70% 0.12 205 / 0.14);
139
+ --sf-colour-categorical-1: var(--sf-colour-cyan-600);
140
+ --sf-colour-categorical-2: var(--sf-colour-green-600);
141
+ --sf-colour-categorical-3: var(--sf-colour-amber-500);
142
+ --sf-colour-categorical-4: var(--sf-colour-orange-600);
143
+ --sf-colour-categorical-5: var(--sf-colour-red-600);
144
+ --sf-colour-categorical-6: oklch(58% 0.15 292);
134
145
  --sf-colour-ring: var(--sf-colour-orange-600);
135
146
 
136
147
  --sf-shadow-sm: 0 0.125rem 0.375rem oklch(0% 0 0 / 0.08);
@@ -139,6 +150,13 @@
139
150
  --sf-shadow-xl: 0 1.75rem 4rem oklch(0% 0 0 / 0.18);
140
151
  --sf-shadow-inset: inset 0 0 0 1px var(--sf-colour-border);
141
152
  --sf-shadow-glow: 0 0 2rem oklch(68% 0.18 44 / 0.24);
153
+ --sf-z-sticky: 20;
154
+ --sf-z-header: 20;
155
+ --sf-z-backdrop: 25;
156
+ --sf-z-drawer: 30;
157
+ --sf-z-overlay: 40;
158
+ --sf-z-toast: 50;
159
+ --sf-z-skip-link: 999;
142
160
  --sf-duration-fast: 150ms;
143
161
  --sf-duration-normal: 220ms;
144
162
  --sf-duration-slow: 360ms;
@@ -172,9 +190,13 @@
172
190
  --sf-colour-surface: var(--sf-colour-neutral-0);
173
191
  --sf-colour-surface-alt: var(--sf-colour-neutral-100);
174
192
  --sf-colour-surface-raised: var(--sf-colour-neutral-0);
193
+ --sf-colour-surface-raised-2: var(--sf-colour-neutral-50);
194
+ --sf-colour-surface-hover: var(--sf-colour-neutral-100);
175
195
  --sf-colour-surface-inset: var(--sf-colour-neutral-100);
196
+ --sf-colour-border-subtle: oklch(18% 0.026 250 / 0.08);
176
197
  --sf-colour-border: oklch(18% 0.026 250 / 0.12);
177
198
  --sf-colour-border-strong: oklch(18% 0.026 250 / 0.22);
199
+ --sf-colour-backdrop: oklch(0% 0 0 / 0.48);
178
200
  --sf-colour-link: var(--sf-colour-orange-700);
179
201
  --sf-colour-link-hover: var(--sf-colour-orange-600);
180
202
  }
@@ -188,11 +210,34 @@
188
210
  --sf-colour-surface: var(--sf-colour-neutral-900);
189
211
  --sf-colour-surface-alt: var(--sf-colour-neutral-850);
190
212
  --sf-colour-surface-raised: var(--sf-colour-neutral-850);
213
+ --sf-colour-surface-raised-2: var(--sf-colour-neutral-800);
214
+ --sf-colour-surface-hover: color-mix(in oklch, var(--sf-colour-neutral-850) 76%, white);
191
215
  --sf-colour-surface-inset: var(--sf-colour-neutral-950);
216
+ --sf-colour-border-subtle: oklch(100% 0 0 / 0.08);
192
217
  --sf-colour-border: oklch(100% 0 0 / 0.14);
193
218
  --sf-colour-border-strong: oklch(100% 0 0 / 0.24);
219
+ --sf-colour-backdrop: oklch(0% 0 0 / 0.64);
220
+ --sf-colour-primary: var(--sf-colour-orange-500);
221
+ --sf-colour-primary-hover: oklch(80% 0.14 50);
222
+ --sf-colour-primary-foreground: var(--sf-colour-neutral-950);
223
+ --sf-colour-primary-soft: oklch(74% 0.17 48 / 0.18);
224
+ --sf-colour-primary-soft-border: oklch(74% 0.17 48 / 0.34);
194
225
  --sf-colour-link: var(--sf-colour-orange-500);
195
226
  --sf-colour-link-hover: oklch(80% 0.14 50);
227
+ --sf-colour-success: oklch(72% 0.13 150);
228
+ --sf-colour-success-foreground: var(--sf-colour-neutral-950);
229
+ --sf-colour-success-soft: oklch(72% 0.13 150 / 0.16);
230
+ --sf-colour-warning: oklch(84% 0.15 82);
231
+ --sf-colour-warning-foreground: var(--sf-colour-neutral-950);
232
+ --sf-colour-warning-soft: oklch(84% 0.15 82 / 0.18);
233
+ --sf-colour-danger: oklch(70% 0.18 28);
234
+ --sf-colour-danger-foreground: var(--sf-colour-neutral-950);
235
+ --sf-colour-danger-soft: oklch(70% 0.18 28 / 0.16);
236
+ --sf-colour-info: oklch(76% 0.12 205);
237
+ --sf-colour-info-foreground: var(--sf-colour-neutral-950);
238
+ --sf-colour-info-soft: oklch(76% 0.12 205 / 0.16);
239
+ --sf-colour-ring: var(--sf-colour-orange-500);
240
+ --sf-shadow-glow: 0 0 2rem oklch(74% 0.17 48 / 0.18);
196
241
  }
197
242
  @layer reset {
198
243
  *, *::before, *::after { box-sizing: border-box; }
@@ -398,11 +443,47 @@
398
443
  }
399
444
 
400
445
  .sf-app-shell {
446
+ --sf-app-header-height: 4rem;
447
+ --sf-app-sidebar-collapsed-width: 4.75rem;
401
448
  background: var(--sf-colour-background);
402
449
  color: var(--sf-colour-foreground);
403
450
  display: grid;
404
451
  grid-template-columns: minmax(14rem, var(--sf-app-sidebar-width, 16rem)) minmax(0, 1fr);
405
452
  min-block-size: 100dvh;
453
+ position: relative;
454
+ transition: grid-template-columns var(--sf-duration-normal) var(--sf-ease-standard);
455
+ }
456
+
457
+ .sf-app-header {
458
+ align-items: center;
459
+ background: var(--sf-colour-surface);
460
+ border-block-end: 1px solid var(--sf-colour-border);
461
+ display: flex;
462
+ gap: var(--sf-space-s);
463
+ grid-column: 1 / -1;
464
+ justify-content: space-between;
465
+ min-block-size: var(--sf-app-header-height);
466
+ padding-inline: var(--sf-space-s-m);
467
+ z-index: var(--sf-z-header);
468
+ }
469
+
470
+ .sf-app-shell[data-layout~="fixed-header"] {
471
+ grid-template-rows: var(--sf-app-header-height) minmax(0, 1fr);
472
+ }
473
+
474
+ .sf-app-shell[data-layout~="fixed-header"] .sf-app-header {
475
+ inset-block-start: 0;
476
+ position: sticky;
477
+ }
478
+
479
+ .sf-app-shell[data-layout~="fixed-header"] .sf-app-sidebar {
480
+ inset-block-start: var(--sf-app-header-height);
481
+ max-block-size: calc(100dvh - var(--sf-app-header-height));
482
+ min-block-size: calc(100dvh - var(--sf-app-header-height));
483
+ }
484
+
485
+ .sf-app-shell[data-collapsed="true"] {
486
+ grid-template-columns: var(--sf-app-sidebar-collapsed-width) minmax(0, 1fr);
406
487
  }
407
488
 
408
489
  .sf-app-sidebar {
@@ -418,6 +499,7 @@
418
499
  padding: var(--sf-space-s);
419
500
  position: sticky;
420
501
  inset-block-start: 0;
502
+ transition: transform var(--sf-duration-normal) var(--sf-ease-standard), inline-size var(--sf-duration-normal) var(--sf-ease-standard);
421
503
  }
422
504
 
423
505
  .sf-app-sidebar__brand {
@@ -437,6 +519,59 @@
437
519
  padding: var(--sf-app-main-padding, var(--sf-space-m-l));
438
520
  }
439
521
 
522
+ .sf-app-shell[data-collapsed="true"] .sf-app-sidebar {
523
+ overflow-x: hidden;
524
+ }
525
+
526
+ .sf-app-shell[data-collapsed="true"] .sf-app-sidebar__brand,
527
+ .sf-app-shell[data-collapsed="true"] .sf-app-sidebar .sf-nav__link {
528
+ justify-content: center;
529
+ }
530
+
531
+ .sf-app-shell[data-collapsed="true"] [data-hide-collapsed="true"] {
532
+ display: none;
533
+ }
534
+
535
+ .sf-app-backdrop {
536
+ display: none;
537
+ }
538
+
539
+ @media (max-width: 48rem) {
540
+ .sf-app-shell[data-mobile="drawer"] {
541
+ display: block;
542
+ }
543
+
544
+ .sf-app-shell[data-mobile="drawer"] .sf-app-header {
545
+ position: sticky;
546
+ inset-block-start: 0;
547
+ }
548
+
549
+ .sf-app-shell[data-mobile="drawer"] .sf-app-sidebar {
550
+ block-size: 100dvh;
551
+ box-shadow: var(--sf-shadow-xl);
552
+ inline-size: min(18rem, calc(100vw - var(--sf-space-l)));
553
+ inset-block: 0;
554
+ inset-inline-start: 0;
555
+ max-block-size: none;
556
+ min-block-size: 100dvh;
557
+ position: fixed;
558
+ transform: translateX(-100%);
559
+ z-index: var(--sf-z-drawer);
560
+ }
561
+
562
+ .sf-app-shell[data-mobile="drawer"][data-sidebar-open="true"] .sf-app-sidebar {
563
+ transform: translateX(0);
564
+ }
565
+
566
+ .sf-app-shell[data-mobile="drawer"][data-sidebar-open="true"] .sf-app-backdrop {
567
+ background: var(--sf-colour-backdrop);
568
+ display: block;
569
+ inset: 0;
570
+ position: fixed;
571
+ z-index: var(--sf-z-backdrop);
572
+ }
573
+ }
574
+
440
575
  .sf-grid {
441
576
  display: grid;
442
577
  gap: var(--sf-grid-gap, var(--sf-gutter));
@@ -577,7 +712,7 @@
577
712
  .sf-sticky-top {
578
713
  position: sticky;
579
714
  inset-block-start: var(--sf-sticky-offset, 0);
580
- z-index: var(--sf-sticky-z, 20);
715
+ z-index: var(--sf-sticky-z, var(--sf-z-sticky));
581
716
  }
582
717
 
583
718
  .sf-media-object {
@@ -1098,6 +1233,16 @@
1098
1233
  to { transform: translateX(-50%); }
1099
1234
  }
1100
1235
 
1236
+ @media (prefers-reduced-motion: reduce) {
1237
+ :where(.sf-button:hover, .sf-card--interactive:hover) {
1238
+ transform: none;
1239
+ }
1240
+
1241
+ .sf-marquee__track {
1242
+ animation: none;
1243
+ }
1244
+ }
1245
+
1101
1246
  .sf-command-list {
1102
1247
  display: grid;
1103
1248
  font-family: var(--sf-font-mono);
@@ -1503,7 +1648,7 @@
1503
1648
  }
1504
1649
 
1505
1650
  .sf-filter-bar {
1506
- align-items: end;
1651
+ align-items: var(--sf-filter-bar-align, center);
1507
1652
  background: var(--sf-colour-surface);
1508
1653
  border: 1px solid var(--sf-colour-border);
1509
1654
  border-radius: var(--sf-radius-panel);
@@ -1551,6 +1696,76 @@
1551
1696
  --sf-data-table-padding-inline: var(--sf-space-xs);
1552
1697
  }
1553
1698
 
1699
+ .sf-data-table :where(th button, .sf-table-sort) {
1700
+ align-items: center;
1701
+ color: inherit;
1702
+ display: inline-flex;
1703
+ font: inherit;
1704
+ font-weight: inherit;
1705
+ gap: var(--sf-space-3xs);
1706
+ padding: 0;
1707
+ }
1708
+
1709
+ .sf-data-table :where(th button, .sf-table-sort)[aria-sort]::after {
1710
+ color: var(--sf-colour-subtle);
1711
+ content: "\2195";
1712
+ font-size: var(--sf-step--2);
1713
+ }
1714
+
1715
+ .sf-data-table :where(th button, .sf-table-sort)[aria-sort="ascending"]::after { content: "\2191"; }
1716
+ .sf-data-table :where(th button, .sf-table-sort)[aria-sort="descending"]::after { content: "\2193"; }
1717
+
1718
+ .sf-data-table tr[data-clickable="true"] {
1719
+ cursor: pointer;
1720
+ }
1721
+
1722
+ .sf-data-table tr[data-clickable="true"]:focus-within {
1723
+ outline: 0.125rem solid var(--sf-colour-ring);
1724
+ outline-offset: -0.125rem;
1725
+ }
1726
+
1727
+ @container (max-width: 38rem) {
1728
+ .sf-table-wrap[data-view="cards"] {
1729
+ border: 0;
1730
+ overflow: visible;
1731
+ }
1732
+
1733
+ .sf-table-wrap[data-view="cards"] .sf-data-table,
1734
+ .sf-table-wrap[data-view="cards"] .sf-data-table :where(thead, tbody, tr, th, td) {
1735
+ display: block;
1736
+ min-inline-size: 0;
1737
+ }
1738
+
1739
+ .sf-table-wrap[data-view="cards"] .sf-data-table thead {
1740
+ display: none;
1741
+ }
1742
+
1743
+ .sf-table-wrap[data-view="cards"] .sf-data-table tr {
1744
+ background: var(--sf-colour-surface);
1745
+ border: 1px solid var(--sf-colour-border);
1746
+ border-radius: var(--sf-radius-panel);
1747
+ margin-block-end: var(--sf-space-xs);
1748
+ padding: var(--sf-space-xs);
1749
+ }
1750
+
1751
+ .sf-table-wrap[data-view="cards"] .sf-data-table td {
1752
+ align-items: center;
1753
+ border: 0;
1754
+ display: flex;
1755
+ gap: var(--sf-space-s);
1756
+ justify-content: space-between;
1757
+ padding-block: var(--sf-space-2xs);
1758
+ padding-inline: 0;
1759
+ }
1760
+
1761
+ .sf-table-wrap[data-view="cards"] .sf-data-table td::before {
1762
+ color: var(--sf-colour-muted);
1763
+ content: attr(data-label);
1764
+ font-size: var(--sf-step--1);
1765
+ font-weight: 800;
1766
+ }
1767
+ }
1768
+
1554
1769
  .sf-status {
1555
1770
  align-items: center;
1556
1771
  background: var(--sf-status-bg, var(--sf-colour-surface-alt));
@@ -1566,6 +1781,12 @@
1566
1781
  padding-inline: .7em;
1567
1782
  }
1568
1783
 
1784
+ .sf-status[data-size="sm"] {
1785
+ font-size: var(--sf-step--2);
1786
+ min-block-size: 1.35rem;
1787
+ padding-inline: .55em;
1788
+ }
1789
+
1569
1790
  .sf-status::before {
1570
1791
  background: currentColor;
1571
1792
  block-size: .42em;
@@ -1574,6 +1795,10 @@
1574
1795
  inline-size: .42em;
1575
1796
  }
1576
1797
 
1798
+ :where(.sf-status[data-dot="false"], .sf-status--label)::before {
1799
+ content: none;
1800
+ }
1801
+
1577
1802
  .sf-status[data-tone="success"] {
1578
1803
  --sf-status-bg: var(--sf-colour-success-soft);
1579
1804
  --sf-status-border: color-mix(in oklch, var(--sf-colour-success) 34%, transparent);
@@ -1721,6 +1946,13 @@
1721
1946
  gap: var(--sf-form-gap, var(--sf-space-s-m));
1722
1947
  }
1723
1948
 
1949
+ .sf-form[data-density="compact"],
1950
+ .sf-field[data-density="compact"] {
1951
+ --sf-form-gap: var(--sf-space-xs);
1952
+ --sf-input-block-size: 2.25rem;
1953
+ --sf-input-padding-inline: var(--sf-space-xs);
1954
+ }
1955
+
1724
1956
  .sf-fieldset {
1725
1957
  border: 1px solid var(--sf-colour-border);
1726
1958
  border-radius: var(--sf-radius-panel);
@@ -1786,6 +2018,45 @@
1786
2018
  transition: background-color var(--sf-duration-fast) var(--sf-ease-standard), border-color var(--sf-duration-fast) var(--sf-ease-standard), box-shadow var(--sf-duration-fast) var(--sf-ease-standard);
1787
2019
  }
1788
2020
 
2021
+ .sf-search {
2022
+ position: relative;
2023
+ }
2024
+
2025
+ .sf-search::before {
2026
+ block-size: .75em;
2027
+ border: 0.125em solid currentColor;
2028
+ border-radius: var(--sf-radius-full);
2029
+ color: var(--sf-colour-subtle);
2030
+ content: "";
2031
+ inline-size: .75em;
2032
+ inset-block-start: 50%;
2033
+ inset-inline-start: var(--sf-space-xs);
2034
+ line-height: 1;
2035
+ position: absolute;
2036
+ transform: translateY(-58%);
2037
+ }
2038
+
2039
+ .sf-search::after {
2040
+ background: var(--sf-colour-subtle);
2041
+ block-size: .125em;
2042
+ content: "";
2043
+ inline-size: .45em;
2044
+ inset-block-start: 50%;
2045
+ inset-inline-start: calc(var(--sf-space-xs) + .58em);
2046
+ position: absolute;
2047
+ transform: translateY(120%) rotate(45deg);
2048
+ transform-origin: inline-start center;
2049
+ }
2050
+
2051
+ .sf-search > .sf-input {
2052
+ padding-inline-start: var(--sf-space-l);
2053
+ }
2054
+
2055
+ .sf-help[data-density="compact"],
2056
+ .sf-error[data-density="compact"] {
2057
+ font-size: var(--sf-step--2);
2058
+ }
2059
+
1789
2060
  .sf-textarea {
1790
2061
  min-block-size: var(--sf-textarea-block-size, 8rem);
1791
2062
  padding-block: var(--sf-space-xs);
@@ -1906,7 +2177,7 @@
1906
2177
  .sf-dialog::backdrop,
1907
2178
  .sf-popover::backdrop,
1908
2179
  .sf-drawer::backdrop {
1909
- background: oklch(0% 0 0 / 0.48);
2180
+ background: var(--sf-colour-backdrop);
1910
2181
  }
1911
2182
 
1912
2183
  .sf-dialog__header,
@@ -1932,6 +2203,11 @@
1932
2203
  justify-content: flex-end;
1933
2204
  }
1934
2205
 
2206
+ .sf-dialog[data-layout="form"] .sf-dialog__body {
2207
+ display: grid;
2208
+ gap: var(--sf-space-s);
2209
+ }
2210
+
1935
2211
  .sf-popover,
1936
2212
  .sf-menu-popover,
1937
2213
  .sf-tooltip,
@@ -1957,6 +2233,7 @@
1957
2233
  :where(.sf-popover, .sf-menu-popover, .sf-tooltip, .sf-toast, .sf-banner, .sf-drawer):popover-open {
1958
2234
  display: grid;
1959
2235
  gap: var(--sf-space-xs);
2236
+ z-index: var(--sf-z-overlay);
1960
2237
  }
1961
2238
 
1962
2239
  .sf-popover {
@@ -1985,6 +2262,16 @@
1985
2262
  background: var(--sf-colour-surface-alt);
1986
2263
  }
1987
2264
 
2265
+ .sf-menu :where(a, button)[data-variant="danger"],
2266
+ .sf-menu-popover :where(a, button)[data-variant="danger"] {
2267
+ color: var(--sf-colour-danger);
2268
+ }
2269
+
2270
+ .sf-menu :where(a, button)[data-variant="danger"]:hover,
2271
+ .sf-menu-popover :where(a, button)[data-variant="danger"]:hover {
2272
+ background: var(--sf-colour-danger-soft);
2273
+ }
2274
+
1988
2275
  .sf-tooltip {
1989
2276
  border-radius: var(--sf-radius-md);
1990
2277
  box-shadow: var(--sf-shadow-md);
@@ -2011,6 +2298,16 @@
2011
2298
  top: var(--sf-space-s);
2012
2299
  }
2013
2300
 
2301
+ .sf-toast-stack {
2302
+ display: grid;
2303
+ gap: var(--sf-space-xs);
2304
+ inline-size: min(100% - (var(--sf-gutter) * 2), var(--sf-toast-width, 24rem));
2305
+ inset-block-start: var(--sf-space-s);
2306
+ inset-inline-end: var(--sf-space-s);
2307
+ position: fixed;
2308
+ z-index: var(--sf-z-toast);
2309
+ }
2310
+
2014
2311
  .sf-banner {
2015
2312
  block-size: auto;
2016
2313
  border-radius: var(--sf-radius-lg);
@@ -2123,15 +2420,23 @@
2123
2420
  }
2124
2421
 
2125
2422
  .sf-tab {
2423
+ align-items: center;
2126
2424
  border-block-end: 0.125rem solid transparent;
2425
+ border-radius: var(--sf-radius-full);
2127
2426
  color: var(--sf-colour-muted);
2128
2427
  display: inline-flex;
2428
+ gap: var(--sf-space-2xs);
2129
2429
  font-weight: 800;
2130
2430
  padding-block: var(--sf-space-xs);
2131
2431
  padding-inline: var(--sf-space-s);
2132
2432
  text-decoration: none;
2133
2433
  }
2134
2434
 
2435
+ .sf-tab[data-variant="pill"] {
2436
+ border: 1px solid transparent;
2437
+ padding-block: var(--sf-space-2xs);
2438
+ }
2439
+
2135
2440
  .sf-tab:hover,
2136
2441
  .sf-tab[aria-selected="true"],
2137
2442
  .sf-tab[data-state="active"] {
@@ -2139,6 +2444,24 @@
2139
2444
  color: var(--sf-colour-foreground);
2140
2445
  }
2141
2446
 
2447
+ .sf-tab[data-variant="pill"]:hover,
2448
+ .sf-tab[data-variant="pill"][aria-selected="true"],
2449
+ .sf-tab[data-variant="pill"][data-state="active"] {
2450
+ background: var(--sf-colour-primary-soft);
2451
+ border-color: var(--sf-colour-primary-soft-border);
2452
+ color: var(--sf-colour-primary);
2453
+ }
2454
+
2455
+ .sf-tab__count {
2456
+ background: var(--sf-colour-surface-alt);
2457
+ border: 1px solid var(--sf-colour-border);
2458
+ border-radius: var(--sf-radius-full);
2459
+ color: var(--sf-colour-muted);
2460
+ font-size: var(--sf-step--2);
2461
+ line-height: 1;
2462
+ padding: .25em .55em;
2463
+ }
2464
+
2142
2465
  .sf-tab-panel {
2143
2466
  background: var(--sf-colour-surface);
2144
2467
  border: 1px solid var(--sf-colour-border);
@@ -2315,6 +2638,7 @@
2315
2638
  .sf-table-wrap {
2316
2639
  border: 1px solid var(--sf-colour-border);
2317
2640
  border-radius: var(--sf-radius-panel);
2641
+ container-type: inline-size;
2318
2642
  overflow-x: auto;
2319
2643
  }
2320
2644
 
@@ -2375,7 +2699,7 @@
2375
2699
  text-decoration: none;
2376
2700
  transform: translateY(calc(-100% - var(--sf-space-m)));
2377
2701
  transition: opacity var(--sf-duration-fast) var(--sf-ease-standard), transform var(--sf-duration-fast) var(--sf-ease-standard);
2378
- z-index: 999;
2702
+ z-index: var(--sf-z-skip-link);
2379
2703
  }
2380
2704
 
2381
2705
  .sf-skip-link:focus-visible {