@sovereignfs/ui 0.41.0 → 0.54.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.
Files changed (256) hide show
  1. package/dist/Accordion.module.css +3 -0
  2. package/dist/Alert.module.css +62 -0
  3. package/dist/AspectRatio.module.css +15 -0
  4. package/dist/Badge.module.css +75 -9
  5. package/dist/Breadcrumb.module.css +49 -0
  6. package/dist/Button.module.css +12 -3
  7. package/dist/ButtonGroup.module.css +29 -0
  8. package/dist/Card.module.css +6 -0
  9. package/dist/Checkbox.module.css +3 -1
  10. package/dist/Collapsible.module.css +70 -0
  11. package/dist/Combobox.module.css +122 -0
  12. package/dist/Command.module.css +80 -0
  13. package/dist/ConfirmDialog.module.css +5 -1
  14. package/dist/DataTable.module.css +28 -0
  15. package/dist/DatePicker.module.css +6 -2
  16. package/dist/Dialog.module.css +3 -0
  17. package/dist/HoverCard.module.css +3 -0
  18. package/dist/Input.module.css +6 -1
  19. package/dist/Item.module.css +70 -0
  20. package/dist/Kbd.module.css +14 -0
  21. package/dist/Label.module.css +11 -0
  22. package/dist/LegalLinks.module.css +24 -0
  23. package/dist/Markdown.module.css +49 -0
  24. package/dist/Marker.module.css +33 -0
  25. package/dist/Menu.module.css +8 -1
  26. package/dist/Message.module.css +99 -0
  27. package/dist/MessageScroller.module.css +54 -0
  28. package/dist/MobileAppsDrawer.module.css +81 -0
  29. package/dist/MobileFooter.module.css +73 -0
  30. package/dist/MobileHeader.module.css +63 -0
  31. package/dist/NavigationMenu.module.css +53 -0
  32. package/dist/PageContainer.module.css +20 -0
  33. package/dist/Pagination.module.css +98 -0
  34. package/dist/Progress.module.css +20 -0
  35. package/dist/RadioGroup.module.css +88 -0
  36. package/dist/Resizable.module.css +70 -0
  37. package/dist/ScrollArea.module.css +20 -0
  38. package/dist/Select.module.css +7 -3
  39. package/dist/Slider.module.css +95 -0
  40. package/dist/SwipableMobileCarousel.module.css +55 -0
  41. package/dist/SwipableMobileCarouselDots.module.css +49 -0
  42. package/dist/SwipableMobileCarouselSlideParts.module.css +29 -0
  43. package/dist/Table.module.css +45 -0
  44. package/dist/Tabs.module.css +6 -1
  45. package/dist/Toggle.module.css +6 -1
  46. package/dist/Typography.module.css +47 -0
  47. package/dist/index.d.ts +1268 -8
  48. package/dist/index.js +3046 -975
  49. package/dist/tokens/primitives.css +47 -8
  50. package/package.json +13 -9
  51. package/src/components/Accordion/Accordion.module.css +3 -0
  52. package/src/components/Accordion/Accordion.stories.tsx +110 -0
  53. package/src/components/Accordion/Accordion.tsx +53 -0
  54. package/src/components/Accordion/__tests__/Accordion.test.tsx +61 -0
  55. package/src/components/Alert/Alert.module.css +62 -0
  56. package/src/components/Alert/Alert.stories.tsx +96 -0
  57. package/src/components/Alert/Alert.tsx +58 -0
  58. package/src/components/Alert/__tests__/Alert.test.tsx +75 -0
  59. package/src/components/AspectRatio/AspectRatio.module.css +15 -0
  60. package/src/components/AspectRatio/AspectRatio.stories.tsx +78 -0
  61. package/src/components/AspectRatio/AspectRatio.tsx +21 -0
  62. package/src/components/AspectRatio/__tests__/AspectRatio.test.tsx +27 -0
  63. package/src/components/Badge/Badge.module.css +75 -9
  64. package/src/components/Badge/Badge.stories.tsx +109 -1
  65. package/src/components/Badge/Badge.tsx +31 -9
  66. package/src/components/Badge/__tests__/Badge.test.tsx +26 -2
  67. package/src/components/Breadcrumb/Breadcrumb.module.css +49 -0
  68. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +47 -0
  69. package/src/components/Breadcrumb/Breadcrumb.tsx +57 -0
  70. package/src/components/Breadcrumb/__tests__/Breadcrumb.test.tsx +52 -0
  71. package/src/components/Button/Button.module.css +12 -3
  72. package/src/components/Button/Button.stories.tsx +3 -2
  73. package/src/components/Button/Button.tsx +1 -1
  74. package/src/components/Button/__tests__/Button.test.tsx +10 -0
  75. package/src/components/ButtonGroup/ButtonGroup.module.css +29 -0
  76. package/src/components/ButtonGroup/ButtonGroup.stories.tsx +57 -0
  77. package/src/components/ButtonGroup/ButtonGroup.tsx +27 -0
  78. package/src/components/ButtonGroup/__tests__/ButtonGroup.test.tsx +29 -0
  79. package/src/components/Card/Card.module.css +6 -0
  80. package/src/components/Checkbox/Checkbox.module.css +3 -1
  81. package/src/components/Collapsible/Collapsible.module.css +70 -0
  82. package/src/components/Collapsible/Collapsible.stories.tsx +62 -0
  83. package/src/components/Collapsible/Collapsible.tsx +66 -0
  84. package/src/components/Collapsible/__tests__/Collapsible.test.tsx +71 -0
  85. package/src/components/Combobox/Combobox.module.css +122 -0
  86. package/src/components/Combobox/Combobox.stories.tsx +79 -0
  87. package/src/components/Combobox/Combobox.tsx +186 -0
  88. package/src/components/Combobox/__tests__/Combobox.test.tsx +158 -0
  89. package/src/components/Command/Command.module.css +80 -0
  90. package/src/components/Command/Command.stories.tsx +104 -0
  91. package/src/components/Command/Command.tsx +168 -0
  92. package/src/components/Command/__tests__/Command.test.tsx +162 -0
  93. package/src/components/ConfirmDialog/ConfirmDialog.module.css +5 -1
  94. package/src/components/ContextMenu/ContextMenu.stories.tsx +81 -0
  95. package/src/components/ContextMenu/ContextMenu.tsx +100 -0
  96. package/src/components/ContextMenu/__tests__/ContextMenu.test.tsx +87 -0
  97. package/src/components/DataTable/DataTable.module.css +28 -0
  98. package/src/components/DataTable/DataTable.stories.tsx +74 -0
  99. package/src/components/DataTable/DataTable.tsx +154 -0
  100. package/src/components/DataTable/__tests__/DataTable.test.tsx +123 -0
  101. package/src/components/DatePicker/DatePicker.module.css +6 -2
  102. package/src/components/DeviceOnlyGate/DeviceOnlyGate.tsx +58 -0
  103. package/src/components/DeviceOnlyGate/__tests__/DeviceOnlyGate.test.tsx +45 -0
  104. package/src/components/DeviceStorageKeyGate/DeviceStorageKeyGate.tsx +100 -0
  105. package/src/components/DeviceStorageKeyGate/__tests__/DeviceStorageKeyGate.test.tsx +119 -0
  106. package/src/components/Dialog/Dialog.module.css +3 -0
  107. package/src/components/Dialog/Dialog.tsx +8 -59
  108. package/src/components/Drawer/Drawer.stories.tsx +44 -0
  109. package/src/components/Drawer/Drawer.tsx +18 -56
  110. package/src/components/Drawer/__tests__/Drawer.test.tsx +22 -0
  111. package/src/components/HoverCard/HoverCard.module.css +3 -0
  112. package/src/components/HoverCard/HoverCard.stories.tsx +66 -0
  113. package/src/components/HoverCard/HoverCard.tsx +111 -0
  114. package/src/components/HoverCard/__tests__/HoverCard.test.tsx +99 -0
  115. package/src/components/Icon/icons/circle-check.tsx +21 -0
  116. package/src/components/Icon/icons/circle-x.tsx +22 -0
  117. package/src/components/Icon/icons/index.ts +16 -0
  118. package/src/components/Icon/icons/menu.tsx +22 -0
  119. package/src/components/Icon/icons/smartphone.tsx +21 -0
  120. package/src/components/Input/Input.module.css +6 -1
  121. package/src/components/Item/Item.module.css +70 -0
  122. package/src/components/Item/Item.stories.tsx +62 -0
  123. package/src/components/Item/Item.tsx +54 -0
  124. package/src/components/Item/__tests__/Item.test.tsx +39 -0
  125. package/src/components/Kbd/Kbd.module.css +14 -0
  126. package/src/components/Kbd/Kbd.stories.tsx +32 -0
  127. package/src/components/Kbd/Kbd.tsx +12 -0
  128. package/src/components/Kbd/__tests__/Kbd.test.tsx +14 -0
  129. package/src/components/Label/Label.module.css +11 -0
  130. package/src/components/Label/Label.stories.tsx +40 -0
  131. package/src/components/Label/Label.tsx +24 -0
  132. package/src/components/Label/__tests__/Label.test.tsx +32 -0
  133. package/src/components/LegalLinks/LegalLinks.module.css +24 -0
  134. package/src/components/LegalLinks/LegalLinks.stories.tsx +22 -0
  135. package/src/components/LegalLinks/LegalLinks.tsx +40 -0
  136. package/src/components/Markdown/Markdown.module.css +49 -0
  137. package/src/components/Markdown/Markdown.stories.tsx +30 -0
  138. package/src/components/Markdown/Markdown.tsx +168 -0
  139. package/src/components/Marker/Marker.module.css +33 -0
  140. package/src/components/Marker/Marker.stories.tsx +39 -0
  141. package/src/components/Marker/Marker.tsx +34 -0
  142. package/src/components/Marker/__tests__/Marker.test.tsx +23 -0
  143. package/src/components/Menu/Menu.module.css +8 -1
  144. package/src/components/Menu/Menu.tsx +30 -8
  145. package/src/components/Menubar/Menubar.stories.tsx +52 -0
  146. package/src/components/Menubar/Menubar.tsx +42 -0
  147. package/src/components/Menubar/__tests__/Menubar.test.tsx +45 -0
  148. package/src/components/Message/Message.module.css +99 -0
  149. package/src/components/Message/Message.stories.tsx +79 -0
  150. package/src/components/Message/Message.tsx +41 -0
  151. package/src/components/Message/__tests__/Message.test.tsx +46 -0
  152. package/src/components/MessageScroller/MessageScroller.module.css +54 -0
  153. package/src/components/MessageScroller/MessageScroller.stories.tsx +84 -0
  154. package/src/components/MessageScroller/MessageScroller.tsx +72 -0
  155. package/src/components/MessageScroller/__tests__/MessageScroller.test.tsx +105 -0
  156. package/src/components/MobileAppsDrawer/MobileAppsDrawer.module.css +81 -0
  157. package/src/components/MobileAppsDrawer/MobileAppsDrawer.tsx +78 -0
  158. package/src/components/MobileAppsDrawer/__tests__/MobileAppsDrawer.test.tsx +80 -0
  159. package/src/components/MobileFooter/MobileFooter.module.css +73 -0
  160. package/src/components/MobileFooter/MobileFooter.stories.tsx +47 -0
  161. package/src/components/MobileFooter/MobileFooter.tsx +109 -0
  162. package/src/components/MobileFooter/__tests__/MobileFooter.test.tsx +71 -0
  163. package/src/components/MobileHeader/MobileHeader.module.css +63 -0
  164. package/src/components/MobileHeader/MobileHeader.stories.tsx +57 -0
  165. package/src/components/MobileHeader/MobileHeader.tsx +77 -0
  166. package/src/components/MobileHeader/__tests__/MobileHeader.test.tsx +58 -0
  167. package/src/components/NavTabs/NavTabs.tsx +39 -11
  168. package/src/components/NavigationMenu/NavigationMenu.module.css +53 -0
  169. package/src/components/NavigationMenu/NavigationMenu.stories.tsx +58 -0
  170. package/src/components/NavigationMenu/NavigationMenu.tsx +125 -0
  171. package/src/components/NavigationMenu/__tests__/NavigationMenu.test.tsx +93 -0
  172. package/src/components/OfflineGate/OfflineGate.tsx +44 -0
  173. package/src/components/OfflineGate/__tests__/OfflineGate.test.tsx +66 -0
  174. package/src/components/PageContainer/PageContainer.module.css +20 -0
  175. package/src/components/PageContainer/PageContainer.tsx +31 -0
  176. package/src/components/PageContainer/__tests__/PageContainer.test.tsx +37 -0
  177. package/src/components/PageHeader/PageHeader.tsx +16 -2
  178. package/src/components/Pagination/Pagination.module.css +98 -0
  179. package/src/components/Pagination/Pagination.stories.tsx +49 -0
  180. package/src/components/Pagination/Pagination.tsx +87 -0
  181. package/src/components/Pagination/__tests__/Pagination.test.tsx +56 -0
  182. package/src/components/Progress/Progress.module.css +20 -0
  183. package/src/components/Progress/Progress.stories.tsx +40 -0
  184. package/src/components/Progress/Progress.tsx +35 -0
  185. package/src/components/Progress/__tests__/Progress.test.tsx +31 -0
  186. package/src/components/RadioGroup/RadioGroup.module.css +88 -0
  187. package/src/components/RadioGroup/RadioGroup.stories.tsx +69 -0
  188. package/src/components/RadioGroup/RadioGroup.tsx +99 -0
  189. package/src/components/RadioGroup/__tests__/RadioGroup.test.tsx +59 -0
  190. package/src/components/Resizable/Resizable.module.css +70 -0
  191. package/src/components/Resizable/Resizable.stories.tsx +82 -0
  192. package/src/components/Resizable/Resizable.tsx +313 -0
  193. package/src/components/Resizable/__tests__/Resizable.test.tsx +128 -0
  194. package/src/components/ResponsiveSurface/ResponsiveSurface.tsx +24 -0
  195. package/src/components/ResponsiveSurface/__tests__/ResponsiveSurface.test.tsx +73 -0
  196. package/src/components/ScrollArea/ScrollArea.module.css +20 -0
  197. package/src/components/ScrollArea/ScrollArea.stories.tsx +57 -0
  198. package/src/components/ScrollArea/ScrollArea.tsx +27 -0
  199. package/src/components/ScrollArea/__tests__/ScrollArea.test.tsx +39 -0
  200. package/src/components/Select/Select.module.css +7 -3
  201. package/src/components/Sheet/Sheet.tsx +9 -51
  202. package/src/components/Slider/Slider.module.css +95 -0
  203. package/src/components/Slider/Slider.stories.tsx +64 -0
  204. package/src/components/Slider/Slider.tsx +77 -0
  205. package/src/components/Slider/__tests__/Slider.test.tsx +45 -0
  206. package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.module.css +55 -0
  207. package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.tsx +227 -0
  208. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlide.tsx +35 -0
  209. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideBody.tsx +42 -0
  210. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideFooter.tsx +18 -0
  211. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideHeader.tsx +21 -0
  212. package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideParts.module.css +29 -0
  213. package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarousel.test.tsx +133 -0
  214. package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarouselDevGuard.test.tsx +61 -0
  215. package/src/components/SwipableMobileCarousel/context.ts +13 -0
  216. package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.module.css +49 -0
  217. package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.tsx +62 -0
  218. package/src/components/SwipableMobileCarouselDots/__tests__/SwipableMobileCarouselDots.test.tsx +63 -0
  219. package/src/components/Table/Table.module.css +45 -0
  220. package/src/components/Table/Table.stories.tsx +125 -0
  221. package/src/components/Table/Table.tsx +51 -0
  222. package/src/components/Table/__tests__/Table.test.tsx +50 -0
  223. package/src/components/Tabs/Tabs.module.css +6 -1
  224. package/src/components/Toggle/Toggle.module.css +6 -1
  225. package/src/components/Typography/Typography.module.css +47 -0
  226. package/src/components/Typography/Typography.stories.tsx +62 -0
  227. package/src/components/Typography/Typography.tsx +30 -0
  228. package/src/components/Typography/__tests__/Typography.test.tsx +34 -0
  229. package/src/hooks/__tests__/useCarouselRouteSync.test.tsx +126 -0
  230. package/src/hooks/__tests__/useIsOffline.test.tsx +53 -0
  231. package/src/hooks/__tests__/useOfflineTileState.test.tsx +69 -0
  232. package/src/hooks/__tests__/useResponsiveLayout.test.tsx +87 -0
  233. package/src/hooks/__tests__/useSnapCarousel.test.tsx +93 -0
  234. package/src/hooks/__tests__/useSwipeReveal.test.tsx +110 -0
  235. package/src/hooks/index.ts +18 -0
  236. package/src/hooks/useCarouselRouteSync.ts +92 -0
  237. package/src/hooks/useIsOffline.ts +41 -0
  238. package/src/hooks/useOfflineTileState.ts +45 -0
  239. package/src/hooks/useResponsiveLayout.ts +36 -0
  240. package/src/hooks/useSnapCarousel.ts +79 -0
  241. package/src/hooks/useSwipeReveal.ts +107 -0
  242. package/src/index.ts +141 -3
  243. package/src/overlay-shell.ts +94 -0
  244. package/src/stories/DesignSystemOverview.stories.tsx +936 -3
  245. package/src/stories/DeviceOnlyGate.stories.tsx +35 -0
  246. package/src/stories/DeviceStorageKeyGate.stories.tsx +57 -0
  247. package/src/stories/InteractionHooks.stories.tsx +483 -0
  248. package/src/stories/MobilePatterns.stories.tsx +255 -4
  249. package/src/stories/NavTabs.stories.tsx +18 -0
  250. package/src/stories/OfflineGate.stories.tsx +42 -0
  251. package/src/stories/PageContainer.stories.tsx +37 -0
  252. package/src/stories/PageHeader.stories.tsx +11 -0
  253. package/src/stories/ResponsiveSurface.stories.tsx +47 -0
  254. package/src/stories/SwipableMobileCarousel.stories.tsx +304 -0
  255. package/src/stories/TokenGallery.stories.tsx +177 -16
  256. package/src/tokens/primitives.css +47 -8
@@ -0,0 +1,98 @@
1
+ .nav {
2
+ display: flex;
3
+ align-items: center;
4
+ gap: var(--sv-space-1);
5
+ }
6
+
7
+ .list {
8
+ display: flex;
9
+ align-items: center;
10
+ gap: var(--sv-space-1);
11
+ margin: 0;
12
+ padding: 0;
13
+ list-style: none;
14
+ }
15
+
16
+ /* Icon-only nav buttons — same footprint as Dialog's close button. */
17
+ .navButton {
18
+ display: inline-flex;
19
+ align-items: center;
20
+ justify-content: center;
21
+ width: var(--sv-space-8);
22
+ height: var(--sv-space-8);
23
+ border: none;
24
+ border-radius: var(--sv-radius-md);
25
+ background: transparent;
26
+ color: var(--sv-color-text-primary);
27
+ cursor: pointer;
28
+ }
29
+
30
+ .navButton:disabled {
31
+ opacity: 0.5;
32
+ cursor: not-allowed;
33
+ }
34
+
35
+ @media (hover: hover) {
36
+ .navButton:not(:disabled):hover {
37
+ background: var(--sv-color-surface-sunken);
38
+ }
39
+ }
40
+
41
+ .navButton:focus-visible {
42
+ outline: 2px solid var(--sv-color-focus-ring);
43
+ outline-offset: 2px;
44
+ }
45
+
46
+ @media (pointer: coarse) {
47
+ .navButton {
48
+ width: var(--sv-touch-target-min, 44px);
49
+ height: var(--sv-touch-target-min, 44px);
50
+ }
51
+ }
52
+
53
+ .pageButton {
54
+ display: inline-flex;
55
+ align-items: center;
56
+ justify-content: center;
57
+ min-width: var(--sv-space-8);
58
+ height: var(--sv-space-8);
59
+ padding: 0 var(--sv-space-2);
60
+ border: none;
61
+ border-radius: var(--sv-radius-md);
62
+ background: transparent;
63
+ color: var(--sv-color-text-primary);
64
+ font-size: var(--sv-font-size-sm);
65
+ cursor: pointer;
66
+ }
67
+
68
+ @media (hover: hover) {
69
+ .pageButton:not(.active):hover {
70
+ background: var(--sv-color-surface-sunken);
71
+ }
72
+ }
73
+
74
+ .pageButton:focus-visible {
75
+ outline: 2px solid var(--sv-color-focus-ring);
76
+ outline-offset: 2px;
77
+ }
78
+
79
+ .active {
80
+ background: var(--sv-color-accent);
81
+ color: var(--sv-color-text-on-accent);
82
+ }
83
+
84
+ @media (pointer: coarse) {
85
+ .pageButton {
86
+ min-width: var(--sv-touch-target-min, 44px);
87
+ height: var(--sv-touch-target-min, 44px);
88
+ }
89
+ }
90
+
91
+ .ellipsis {
92
+ display: inline-flex;
93
+ align-items: center;
94
+ justify-content: center;
95
+ min-width: var(--sv-space-8);
96
+ height: var(--sv-space-8);
97
+ color: var(--sv-color-text-muted);
98
+ }
@@ -0,0 +1,20 @@
1
+ .track {
2
+ width: 100%;
3
+ height: 8px;
4
+ border-radius: var(--sv-radius-full);
5
+ background: var(--sv-color-surface-sunken);
6
+ overflow: hidden;
7
+ }
8
+
9
+ .fill {
10
+ height: 100%;
11
+ border-radius: var(--sv-radius-full);
12
+ background: var(--sv-color-accent);
13
+ transition: width 0.2s ease;
14
+ }
15
+
16
+ @media (prefers-reduced-motion: reduce) {
17
+ .fill {
18
+ transition: none;
19
+ }
20
+ }
@@ -0,0 +1,88 @@
1
+ .root {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--sv-space-2);
5
+ }
6
+
7
+ .option {
8
+ display: inline-flex;
9
+ align-items: center;
10
+ gap: var(--sv-space-2);
11
+ cursor: pointer;
12
+ }
13
+
14
+ /* The visual circle — same 18px size and touch-target-expansion technique
15
+ as Checkbox's box, radius-full instead of radius-sm. */
16
+ .circle {
17
+ --radio-circle-size: 18px;
18
+ position: relative;
19
+ flex-shrink: 0;
20
+ width: var(--radio-circle-size);
21
+ height: var(--radio-circle-size);
22
+ border-radius: var(--sv-radius-full);
23
+ border: 1.5px solid var(--sv-color-border-strong);
24
+ background: var(--sv-color-surface);
25
+ transition:
26
+ background-color 0.15s ease,
27
+ border-color 0.15s ease;
28
+ display: flex;
29
+ align-items: center;
30
+ justify-content: center;
31
+ }
32
+
33
+ .checked {
34
+ border-color: var(--sv-color-accent);
35
+ }
36
+
37
+ .dot {
38
+ width: 8px;
39
+ height: 8px;
40
+ border-radius: var(--sv-radius-full);
41
+ background: var(--sv-color-accent);
42
+ pointer-events: none;
43
+ }
44
+
45
+ /* Hide the native input visually but keep it accessible */
46
+ .input {
47
+ position: absolute;
48
+ inset: 0;
49
+ opacity: 0;
50
+ margin: 0;
51
+ width: 100%;
52
+ height: 100%;
53
+ cursor: pointer;
54
+ }
55
+
56
+ .input:disabled {
57
+ cursor: not-allowed;
58
+ }
59
+
60
+ /* Expand the tappable region to the platform's minimum touch target without
61
+ growing the visible circle. Gated to (pointer: coarse), the *primary*
62
+ pointer, so a touchscreen laptop with mouse/trackpad as primary keeps
63
+ desktop density — same reasoning as Checkbox. */
64
+ @media (pointer: coarse) {
65
+ .input {
66
+ inset: calc((var(--radio-circle-size) - var(--sv-touch-target-min, 44px)) / 2);
67
+ }
68
+ }
69
+
70
+ .input:focus-visible {
71
+ outline: none;
72
+ }
73
+
74
+ .circle:has(.input:focus-visible) {
75
+ outline: 2px solid var(--sv-color-focus-ring);
76
+ outline-offset: 2px;
77
+ }
78
+
79
+ .optionLabel {
80
+ font-size: var(--sv-font-size-sm);
81
+ color: var(--sv-color-text-primary);
82
+ user-select: none;
83
+ }
84
+
85
+ .disabled {
86
+ opacity: 0.5;
87
+ cursor: not-allowed;
88
+ }
@@ -0,0 +1,70 @@
1
+ .group {
2
+ display: flex;
3
+ flex-direction: row;
4
+ width: 100%;
5
+ height: 100%;
6
+ min-height: 320px;
7
+ border: 1px solid var(--sv-color-border);
8
+ border-radius: var(--sv-radius-lg);
9
+ overflow: hidden;
10
+ background: var(--sv-color-surface);
11
+ }
12
+
13
+ .groupVertical {
14
+ flex-direction: column;
15
+ }
16
+
17
+ .panel {
18
+ min-width: 0;
19
+ min-height: 0;
20
+ overflow: auto;
21
+ background: var(--sv-color-surface);
22
+ }
23
+
24
+ .handle {
25
+ position: relative;
26
+ flex-shrink: 0;
27
+ width: 12px;
28
+ padding: 0;
29
+ border: 0;
30
+ border-inline: 1px solid var(--sv-color-border);
31
+ cursor: col-resize;
32
+ background: var(--sv-color-surface-sunken);
33
+ }
34
+
35
+ .handleVertical {
36
+ width: 100%;
37
+ height: 12px;
38
+ border-inline: 0;
39
+ border-block: 1px solid var(--sv-color-border);
40
+ cursor: row-resize;
41
+ }
42
+
43
+ .handle::before {
44
+ position: absolute;
45
+ inset-block: 50%;
46
+ inset-inline: 50%;
47
+ width: 2px;
48
+ height: 40px;
49
+ content: '';
50
+ background: var(--sv-color-border-strong);
51
+ border-radius: var(--sv-radius-full);
52
+ transform: translate(-50%, -50%);
53
+ }
54
+
55
+ .handleVertical::before {
56
+ width: 40px;
57
+ height: 2px;
58
+ }
59
+
60
+ @media (hover: hover) {
61
+ .handle:hover {
62
+ background: var(--sv-color-accent-subtle);
63
+ }
64
+ }
65
+
66
+ .handle:focus-visible {
67
+ background: var(--sv-color-accent-subtle);
68
+ outline: 2px solid var(--sv-color-focus-ring);
69
+ outline-offset: -2px;
70
+ }
@@ -0,0 +1,20 @@
1
+ .root {
2
+ overflow: auto;
3
+ overscroll-behavior: contain;
4
+ scrollbar-width: thin;
5
+ scrollbar-color: var(--sv-color-border-strong) transparent;
6
+ }
7
+
8
+ .root::-webkit-scrollbar {
9
+ width: 8px;
10
+ height: 8px;
11
+ }
12
+
13
+ .root::-webkit-scrollbar-track {
14
+ background: transparent;
15
+ }
16
+
17
+ .root::-webkit-scrollbar-thumb {
18
+ background: var(--sv-color-border-strong);
19
+ border-radius: var(--sv-radius-full);
20
+ }
@@ -8,8 +8,11 @@
8
8
  .select {
9
9
  display: block;
10
10
  width: 100%;
11
- /* Right-pad to clear the custom chevron */
12
- padding: var(--sv-space-2) var(--sv-space-8) var(--sv-space-2) var(--sv-space-3);
11
+ /* 36px rendered height. Explicit height + border-box, same technique as
12
+ Input. Right-pad to clear the custom chevron. */
13
+ height: 36px;
14
+ box-sizing: border-box;
15
+ padding: 4px var(--sv-space-8) 4px var(--sv-space-3);
13
16
  font-family: var(--sv-font-family);
14
17
  font-size: var(--sv-font-size-sm);
15
18
  line-height: 1.5;
@@ -25,8 +28,9 @@
25
28
  box-shadow 0.15s ease;
26
29
  }
27
30
 
28
- /* sm — compact for table cells and inline controls */
31
+ /* sm — compact for table cells and inline controls. 32px height. */
29
32
  .sm .select {
33
+ height: 32px;
30
34
  padding: 2px var(--sv-space-6) 2px var(--sv-space-2);
31
35
  font-size: var(--sv-font-size-sm);
32
36
  line-height: 1.4;
@@ -0,0 +1,95 @@
1
+ .root {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--sv-space-2);
5
+ }
6
+
7
+ .label {
8
+ font-size: var(--sv-font-size-sm);
9
+ color: var(--sv-color-text-primary);
10
+ }
11
+
12
+ .slider {
13
+ appearance: none;
14
+ width: 100%;
15
+ height: 20px;
16
+ background: transparent;
17
+ cursor: pointer;
18
+ margin: 0;
19
+ }
20
+
21
+ /* Expand the vertical hit area for touch dragging without thickening the
22
+ visible track — same rationale as Button/Checkbox's touch-target
23
+ expansion, gated to the primary pointer. */
24
+ @media (pointer: coarse) {
25
+ .slider {
26
+ height: var(--sv-touch-target-min, 44px);
27
+ }
28
+ }
29
+
30
+ .slider:disabled {
31
+ opacity: 0.5;
32
+ cursor: not-allowed;
33
+ }
34
+
35
+ .slider:focus-visible {
36
+ outline: 2px solid var(--sv-color-focus-ring);
37
+ outline-offset: 2px;
38
+ }
39
+
40
+ /* Track — WebKit/Blink. The filled portion is a gradient computed from the
41
+ --slider-fill custom property the component sets inline; no JS-measured
42
+ pixel math, just a CSS variable driving a hard color stop. */
43
+ .slider::-webkit-slider-runnable-track {
44
+ height: 4px;
45
+ border-radius: var(--sv-radius-full);
46
+ background: linear-gradient(
47
+ to right,
48
+ var(--sv-color-accent) var(--slider-fill),
49
+ var(--sv-color-border-strong) var(--slider-fill)
50
+ );
51
+ }
52
+
53
+ .slider::-webkit-slider-thumb {
54
+ appearance: none;
55
+ width: 16px;
56
+ height: 16px;
57
+ margin-top: -6px;
58
+ border-radius: var(--sv-radius-full);
59
+ background: var(--sv-color-accent);
60
+ box-shadow: var(--sv-shadow-control);
61
+ cursor: pointer;
62
+ }
63
+
64
+ .slider:disabled::-webkit-slider-thumb {
65
+ cursor: not-allowed;
66
+ }
67
+
68
+ /* Track — Firefox. Separate track/progress pseudo-elements instead of a
69
+ gradient — Firefox renders the filled portion natively via
70
+ ::-moz-range-progress. */
71
+ .slider::-moz-range-track {
72
+ height: 4px;
73
+ border-radius: var(--sv-radius-full);
74
+ background: var(--sv-color-border-strong);
75
+ }
76
+
77
+ .slider::-moz-range-progress {
78
+ height: 4px;
79
+ border-radius: var(--sv-radius-full);
80
+ background: var(--sv-color-accent);
81
+ }
82
+
83
+ .slider::-moz-range-thumb {
84
+ width: 16px;
85
+ height: 16px;
86
+ border: none;
87
+ border-radius: var(--sv-radius-full);
88
+ background: var(--sv-color-accent);
89
+ box-shadow: var(--sv-shadow-control);
90
+ cursor: pointer;
91
+ }
92
+
93
+ .slider:disabled::-moz-range-thumb {
94
+ cursor: not-allowed;
95
+ }
@@ -0,0 +1,55 @@
1
+ .wrap {
2
+ position: relative;
3
+ height: 100%;
4
+ width: 100%;
5
+ }
6
+
7
+ .scroller {
8
+ height: 100%;
9
+ width: 100%;
10
+ display: flex;
11
+ overflow-x: auto;
12
+ overflow-y: hidden;
13
+ scroll-snap-type: x mandatory;
14
+ /* Momentum + rubber-banding come from the browser's native scroll physics —
15
+ no hand-rolled pointer/touch dragging. Deliberately NOT
16
+ -webkit-overflow-scrolling: touch: that legacy iOS <13 hint promotes its
17
+ element to its own compositing layer for GPU-accelerated momentum
18
+ scroll, and that layer's paint order relative to siblings/fixed
19
+ descendants elsewhere in the tree isn't always reliable on real iOS
20
+ Safari (confirmed via sovereign-tasks' and sovereign-shopper's own
21
+ carousels, which hit and fixed this exact bug — a position:fixed
22
+ overlay opened above the scroller painted BEHIND it instead of above).
23
+ Removing it doesn't disable momentum scrolling on any iOS version this
24
+ platform realistically targets. */
25
+ }
26
+
27
+ .slide {
28
+ flex: 0 0 100%;
29
+ width: 100%;
30
+ height: 100%;
31
+ min-width: 0;
32
+ overflow: hidden;
33
+ scroll-snap-align: start;
34
+ scroll-snap-stop: always;
35
+ /* Slide content is a flex column so Header/Footer stay their natural size
36
+ and Body (flex: 1 1 auto, min-height: 0) fills and scrolls the rest —
37
+ see SwipableMobileCarouselSlideParts.module.css. */
38
+ display: flex;
39
+ flex-direction: column;
40
+ }
41
+
42
+ .dots {
43
+ /* Overlays the bottom of .wrap rather than taking its own layout row —
44
+ matches both sovereign-tasks' and sovereign-shopper's existing dots
45
+ placement. */
46
+ position: absolute;
47
+ left: 0;
48
+ right: 0;
49
+ bottom: var(--sv-space-3);
50
+ pointer-events: none;
51
+ }
52
+
53
+ .dots > * {
54
+ pointer-events: auto;
55
+ }
@@ -0,0 +1,49 @@
1
+ .dots {
2
+ display: flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+ gap: var(--sv-space-2);
6
+ }
7
+
8
+ .dot {
9
+ /* A 6px visible dot is too small a hit target on its own — the button's
10
+ real box is larger (20px) with the dot itself painted by ::before and
11
+ centered inside, so tap area grows without changing the visible dot
12
+ size or the row's gap-based spacing math. */
13
+ position: relative;
14
+ width: 20px;
15
+ height: 20px;
16
+ padding: 0;
17
+ border: none;
18
+ background: transparent;
19
+ cursor: pointer;
20
+ }
21
+
22
+ .dot::before {
23
+ content: '';
24
+ position: absolute;
25
+ top: 50%;
26
+ left: 50%;
27
+ width: 6px;
28
+ height: 6px;
29
+ border-radius: 50%;
30
+ background: var(--sv-color-border-strong);
31
+ transform: translate(-50%, -50%);
32
+ transition: background 0.15s ease;
33
+ }
34
+
35
+ .dot:focus-visible {
36
+ outline: 2px solid var(--sv-color-focus-ring);
37
+ outline-offset: 2px;
38
+ border-radius: 50%;
39
+ }
40
+
41
+ .dotActive::before {
42
+ background: var(--sv-color-text-primary);
43
+ }
44
+
45
+ @media (hover: hover) {
46
+ .dot:not(.dotActive):hover::before {
47
+ background: var(--sv-color-text-muted);
48
+ }
49
+ }
@@ -0,0 +1,29 @@
1
+ .header,
2
+ .footer {
3
+ flex: 0 0 auto;
4
+ }
5
+
6
+ .body {
7
+ flex: 1 1 auto;
8
+ min-height: 0; /* allow shrinking inside the slide's flex column, so it can scroll instead of overflowing */
9
+ overflow-y: auto;
10
+ overflow-x: hidden;
11
+ /* Deliberately does NOT set touch-action: pan-y here. touch-action's
12
+ effective value is the INTERSECTION of this element's and every
13
+ ancestor's value (docs/architecture-rules.md) — the ancestor .scroller
14
+ (SwipableMobileCarousel.module.css) needs the horizontal swipe gesture,
15
+ so pan-y here ∩ that horizontal handling would resolve to neither axis
16
+ working natively. Relying on the browser's default touch-action (auto)
17
+ here lets native gesture arbitration between the two nested scrollers
18
+ sort out which axis wins per-gesture — don't "fix" perceived nested-
19
+ scroll jank by adding pan-y; it silently breaks horizontal swipe instead. */
20
+ }
21
+
22
+ .loading {
23
+ display: flex;
24
+ align-items: center;
25
+ justify-content: center;
26
+ height: 100%;
27
+ color: var(--sv-color-text-subtle);
28
+ font-size: var(--sv-font-size-sm);
29
+ }
@@ -0,0 +1,45 @@
1
+ /* Horizontal scroll container — masked-edge fade + hidden scrollbar, same
2
+ technique as NavTabs. Always active (not gated to a narrow viewport):
3
+ unlike NavTabs' item count, a table's column count is content-driven and
4
+ can overflow at any screen size. */
5
+ .scrollContainer {
6
+ overflow-x: auto;
7
+ scrollbar-width: none;
8
+ -webkit-overflow-scrolling: touch;
9
+ mask-image: linear-gradient(to right, black calc(100% - 32px), transparent 100%);
10
+ }
11
+
12
+ .scrollContainer::-webkit-scrollbar {
13
+ display: none;
14
+ }
15
+
16
+ .table {
17
+ width: 100%;
18
+ border-collapse: collapse;
19
+ font-size: var(--sv-font-size-sm);
20
+ }
21
+
22
+ .head .row {
23
+ border-bottom: 1px solid var(--sv-color-border-strong);
24
+ }
25
+
26
+ .body .row {
27
+ border-bottom: 1px solid var(--sv-color-border);
28
+ }
29
+
30
+ .body .row:last-child {
31
+ border-bottom: none;
32
+ }
33
+
34
+ .th {
35
+ padding: var(--sv-space-2) var(--sv-space-3);
36
+ text-align: left;
37
+ font-weight: var(--sv-font-weight-semibold);
38
+ color: var(--sv-color-text-muted);
39
+ white-space: nowrap;
40
+ }
41
+
42
+ .td {
43
+ padding: var(--sv-space-2) var(--sv-space-3);
44
+ color: var(--sv-color-text-primary);
45
+ }
@@ -12,7 +12,12 @@
12
12
 
13
13
  .tab {
14
14
  flex-shrink: 0;
15
- padding: var(--sv-space-2) var(--sv-space-4);
15
+ /* 36px rendered height, matching this scale's other 36px controls (Input,
16
+ Select). Vertical padding hardcoded to hit the exact height, same
17
+ reasoning as Button — accounting for the 2px border-bottom below,
18
+ which (content-box) adds to the rendered height on top of font-size +
19
+ padding. */
20
+ padding: 10px var(--sv-space-4);
16
21
  border: none;
17
22
  border-bottom: 2px solid transparent;
18
23
  /* Negative margin pulls the 2px border flush with the tablist border-bottom */
@@ -1,5 +1,10 @@
1
1
  .track {
2
- /* 38×22px pill — spec dimensions */
2
+ /* 38×22px pill — spec dimensions. Sizing audit: despite the component
3
+ name, this renders as a binary pill switch (role="switch"), not a
4
+ pressable toggle button — reviewed against this scale's other compact
5
+ controls with that in mind. Kept dimensions unchanged, generously
6
+ sized for touch-friendliness. (The name vs. actual behavior mismatch
7
+ is a separate, pre-existing naming note, not addressed here.) */
3
8
  display: inline-flex;
4
9
  align-items: center;
5
10
  width: 38px;
@@ -0,0 +1,47 @@
1
+ .h1 {
2
+ margin: 0;
3
+ font-size: var(--sv-font-size-2xl);
4
+ font-weight: var(--sv-font-weight-semibold);
5
+ color: var(--sv-color-text-primary);
6
+ }
7
+
8
+ .h2 {
9
+ margin: 0;
10
+ font-size: var(--sv-font-size-xl);
11
+ font-weight: var(--sv-font-weight-semibold);
12
+ color: var(--sv-color-text-primary);
13
+ }
14
+
15
+ .h3 {
16
+ margin: 0;
17
+ font-size: var(--sv-font-size-lg);
18
+ font-weight: var(--sv-font-weight-semibold);
19
+ color: var(--sv-color-text-primary);
20
+ }
21
+
22
+ .h4 {
23
+ margin: 0;
24
+ font-size: var(--sv-font-size-md);
25
+ font-weight: var(--sv-font-weight-semibold);
26
+ color: var(--sv-color-text-primary);
27
+ }
28
+
29
+ .body {
30
+ margin: 0;
31
+ font-size: var(--sv-font-size-sm);
32
+ color: var(--sv-color-text-primary);
33
+ }
34
+
35
+ .caption {
36
+ margin: 0;
37
+ font-size: var(--sv-font-size-caption);
38
+ color: var(--sv-color-text-muted);
39
+ }
40
+
41
+ .label {
42
+ font-size: var(--sv-font-size-label);
43
+ font-weight: var(--sv-font-weight-semibold);
44
+ color: var(--sv-color-text-muted);
45
+ text-transform: uppercase;
46
+ letter-spacing: 0.04em;
47
+ }