@dillingerstaffing/strand-ui 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/LICENSE +21 -0
  2. package/dist/components/Alert/Alert.d.ts +16 -0
  3. package/dist/components/Alert/Alert.d.ts.map +1 -0
  4. package/dist/components/Alert/index.d.ts +3 -0
  5. package/dist/components/Alert/index.d.ts.map +1 -0
  6. package/dist/components/Avatar/Avatar.d.ts +16 -0
  7. package/dist/components/Avatar/Avatar.d.ts.map +1 -0
  8. package/dist/components/Avatar/index.d.ts +3 -0
  9. package/dist/components/Avatar/index.d.ts.map +1 -0
  10. package/dist/components/Badge/Badge.d.ts +18 -0
  11. package/dist/components/Badge/Badge.d.ts.map +1 -0
  12. package/dist/components/Badge/index.d.ts +3 -0
  13. package/dist/components/Badge/index.d.ts.map +1 -0
  14. package/dist/components/Breadcrumb/Breadcrumb.d.ts +16 -0
  15. package/dist/components/Breadcrumb/Breadcrumb.d.ts.map +1 -0
  16. package/dist/components/Breadcrumb/index.d.ts +3 -0
  17. package/dist/components/Breadcrumb/index.d.ts.map +1 -0
  18. package/dist/components/Button/Button.d.ts +22 -0
  19. package/dist/components/Button/Button.d.ts.map +1 -0
  20. package/dist/components/Button/index.d.ts +3 -0
  21. package/dist/components/Button/index.d.ts.map +1 -0
  22. package/dist/components/Card/Card.d.ts +12 -0
  23. package/dist/components/Card/Card.d.ts.map +1 -0
  24. package/dist/components/Card/index.d.ts +3 -0
  25. package/dist/components/Card/index.d.ts.map +1 -0
  26. package/dist/components/Checkbox/Checkbox.d.ts +20 -0
  27. package/dist/components/Checkbox/Checkbox.d.ts.map +1 -0
  28. package/dist/components/Checkbox/index.d.ts +3 -0
  29. package/dist/components/Checkbox/index.d.ts.map +1 -0
  30. package/dist/components/Container/Container.d.ts +10 -0
  31. package/dist/components/Container/Container.d.ts.map +1 -0
  32. package/dist/components/Container/index.d.ts +3 -0
  33. package/dist/components/Container/index.d.ts.map +1 -0
  34. package/dist/components/DataReadout/DataReadout.d.ts +12 -0
  35. package/dist/components/DataReadout/DataReadout.d.ts.map +1 -0
  36. package/dist/components/DataReadout/index.d.ts +3 -0
  37. package/dist/components/DataReadout/index.d.ts.map +1 -0
  38. package/dist/components/Dialog/Dialog.d.ts +20 -0
  39. package/dist/components/Dialog/Dialog.d.ts.map +1 -0
  40. package/dist/components/Dialog/index.d.ts +3 -0
  41. package/dist/components/Dialog/index.d.ts.map +1 -0
  42. package/dist/components/Divider/Divider.d.ts +13 -0
  43. package/dist/components/Divider/Divider.d.ts.map +1 -0
  44. package/dist/components/Divider/index.d.ts +3 -0
  45. package/dist/components/Divider/index.d.ts.map +1 -0
  46. package/dist/components/FormField/FormField.d.ts +22 -0
  47. package/dist/components/FormField/FormField.d.ts.map +1 -0
  48. package/dist/components/FormField/index.d.ts +3 -0
  49. package/dist/components/FormField/index.d.ts.map +1 -0
  50. package/dist/components/Grid/Grid.d.ts +12 -0
  51. package/dist/components/Grid/Grid.d.ts.map +1 -0
  52. package/dist/components/Grid/index.d.ts +3 -0
  53. package/dist/components/Grid/index.d.ts.map +1 -0
  54. package/dist/components/Input/Input.d.ts +18 -0
  55. package/dist/components/Input/Input.d.ts.map +1 -0
  56. package/dist/components/Input/index.d.ts +3 -0
  57. package/dist/components/Input/index.d.ts.map +1 -0
  58. package/dist/components/Link/Link.d.ts +12 -0
  59. package/dist/components/Link/Link.d.ts.map +1 -0
  60. package/dist/components/Link/index.d.ts +3 -0
  61. package/dist/components/Link/index.d.ts.map +1 -0
  62. package/dist/components/Nav/Nav.d.ts +19 -0
  63. package/dist/components/Nav/Nav.d.ts.map +1 -0
  64. package/dist/components/Nav/index.d.ts +3 -0
  65. package/dist/components/Nav/index.d.ts.map +1 -0
  66. package/dist/components/Progress/Progress.d.ts +14 -0
  67. package/dist/components/Progress/Progress.d.ts.map +1 -0
  68. package/dist/components/Progress/index.d.ts +3 -0
  69. package/dist/components/Progress/index.d.ts.map +1 -0
  70. package/dist/components/Radio/Radio.d.ts +22 -0
  71. package/dist/components/Radio/Radio.d.ts.map +1 -0
  72. package/dist/components/Radio/index.d.ts +3 -0
  73. package/dist/components/Radio/index.d.ts.map +1 -0
  74. package/dist/components/Section/Section.d.ts +12 -0
  75. package/dist/components/Section/Section.d.ts.map +1 -0
  76. package/dist/components/Section/index.d.ts +3 -0
  77. package/dist/components/Section/index.d.ts.map +1 -0
  78. package/dist/components/Select/Select.d.ts +24 -0
  79. package/dist/components/Select/Select.d.ts.map +1 -0
  80. package/dist/components/Select/index.d.ts +3 -0
  81. package/dist/components/Select/index.d.ts.map +1 -0
  82. package/dist/components/Skeleton/Skeleton.d.ts +14 -0
  83. package/dist/components/Skeleton/Skeleton.d.ts.map +1 -0
  84. package/dist/components/Skeleton/index.d.ts +3 -0
  85. package/dist/components/Skeleton/index.d.ts.map +1 -0
  86. package/dist/components/Slider/Slider.d.ts +20 -0
  87. package/dist/components/Slider/Slider.d.ts.map +1 -0
  88. package/dist/components/Slider/index.d.ts +3 -0
  89. package/dist/components/Slider/index.d.ts.map +1 -0
  90. package/dist/components/Spinner/Spinner.d.ts +10 -0
  91. package/dist/components/Spinner/Spinner.d.ts.map +1 -0
  92. package/dist/components/Spinner/index.d.ts +3 -0
  93. package/dist/components/Spinner/index.d.ts.map +1 -0
  94. package/dist/components/Stack/Stack.d.ts +18 -0
  95. package/dist/components/Stack/Stack.d.ts.map +1 -0
  96. package/dist/components/Stack/index.d.ts +3 -0
  97. package/dist/components/Stack/index.d.ts.map +1 -0
  98. package/dist/components/Switch/Switch.d.ts +18 -0
  99. package/dist/components/Switch/Switch.d.ts.map +1 -0
  100. package/dist/components/Switch/index.d.ts +3 -0
  101. package/dist/components/Switch/index.d.ts.map +1 -0
  102. package/dist/components/Table/Table.d.ts +24 -0
  103. package/dist/components/Table/Table.d.ts.map +1 -0
  104. package/dist/components/Table/index.d.ts +3 -0
  105. package/dist/components/Table/index.d.ts.map +1 -0
  106. package/dist/components/Tabs/Tabs.d.ts +19 -0
  107. package/dist/components/Tabs/Tabs.d.ts.map +1 -0
  108. package/dist/components/Tabs/index.d.ts +3 -0
  109. package/dist/components/Tabs/index.d.ts.map +1 -0
  110. package/dist/components/Tag/Tag.d.ts +18 -0
  111. package/dist/components/Tag/Tag.d.ts.map +1 -0
  112. package/dist/components/Tag/index.d.ts +3 -0
  113. package/dist/components/Tag/index.d.ts.map +1 -0
  114. package/dist/components/Textarea/Textarea.d.ts +22 -0
  115. package/dist/components/Textarea/Textarea.d.ts.map +1 -0
  116. package/dist/components/Textarea/index.d.ts +3 -0
  117. package/dist/components/Textarea/index.d.ts.map +1 -0
  118. package/dist/components/Toast/Toast.d.ts +33 -0
  119. package/dist/components/Toast/Toast.d.ts.map +1 -0
  120. package/dist/components/Toast/index.d.ts +3 -0
  121. package/dist/components/Toast/index.d.ts.map +1 -0
  122. package/dist/components/Tooltip/Tooltip.d.ts +16 -0
  123. package/dist/components/Tooltip/Tooltip.d.ts.map +1 -0
  124. package/dist/components/Tooltip/index.d.ts +3 -0
  125. package/dist/components/Tooltip/index.d.ts.map +1 -0
  126. package/dist/css/strand-ui.css +2464 -0
  127. package/dist/index.d.ts +64 -0
  128. package/dist/index.d.ts.map +1 -0
  129. package/dist/test-setup.d.ts +2 -0
  130. package/dist/test-setup.d.ts.map +1 -0
  131. package/package.json +25 -11
  132. package/src/__tests__/build-output.test.ts +200 -0
  133. package/src/__tests__/design-language.test.ts +137 -0
  134. package/src/__tests__/static.test.tsx +60 -0
  135. package/src/components/Alert/Alert.css +75 -0
  136. package/src/components/Alert/Alert.test.tsx +92 -0
  137. package/src/components/Alert/Alert.tsx +59 -0
  138. package/src/components/Alert/index.ts +2 -0
  139. package/src/components/Avatar/Avatar.css +55 -0
  140. package/src/components/Avatar/Avatar.test.tsx +123 -0
  141. package/src/components/Avatar/Avatar.tsx +67 -0
  142. package/src/components/Avatar/index.ts +2 -0
  143. package/src/components/Badge/Badge.css +72 -0
  144. package/src/components/Badge/Badge.test.tsx +121 -0
  145. package/src/components/Badge/Badge.tsx +92 -0
  146. package/src/components/Badge/index.ts +2 -0
  147. package/src/components/Breadcrumb/Breadcrumb.css +50 -0
  148. package/src/components/Breadcrumb/Breadcrumb.test.tsx +107 -0
  149. package/src/components/Breadcrumb/Breadcrumb.tsx +59 -0
  150. package/src/components/Breadcrumb/index.ts +2 -0
  151. package/src/components/Button/Button.css +195 -0
  152. package/src/components/Button/Button.test.tsx +171 -0
  153. package/src/components/Button/Button.tsx +78 -0
  154. package/src/components/Button/index.ts +2 -0
  155. package/src/components/Card/Card.css +68 -0
  156. package/src/components/Card/Card.test.tsx +90 -0
  157. package/src/components/Card/Card.tsx +41 -0
  158. package/src/components/Card/index.ts +2 -0
  159. package/src/components/Checkbox/Checkbox.css +97 -0
  160. package/src/components/Checkbox/Checkbox.test.tsx +92 -0
  161. package/src/components/Checkbox/Checkbox.tsx +137 -0
  162. package/src/components/Checkbox/index.ts +2 -0
  163. package/src/components/Container/Container.css +25 -0
  164. package/src/components/Container/Container.test.tsx +82 -0
  165. package/src/components/Container/Container.tsx +37 -0
  166. package/src/components/Container/index.ts +2 -0
  167. package/src/components/DataReadout/DataReadout.css +30 -0
  168. package/src/components/DataReadout/DataReadout.test.tsx +105 -0
  169. package/src/components/DataReadout/DataReadout.tsx +29 -0
  170. package/src/components/DataReadout/index.ts +2 -0
  171. package/src/components/Dialog/Dialog.css +81 -0
  172. package/src/components/Dialog/Dialog.test.tsx +203 -0
  173. package/src/components/Dialog/Dialog.tsx +179 -0
  174. package/src/components/Dialog/index.ts +2 -0
  175. package/src/components/Divider/Divider.css +44 -0
  176. package/src/components/Divider/Divider.test.tsx +86 -0
  177. package/src/components/Divider/Divider.tsx +81 -0
  178. package/src/components/Divider/index.ts +2 -0
  179. package/src/components/FormField/FormField.css +47 -0
  180. package/src/components/FormField/FormField.test.tsx +99 -0
  181. package/src/components/FormField/FormField.tsx +79 -0
  182. package/src/components/FormField/index.ts +2 -0
  183. package/src/components/Grid/Grid.css +27 -0
  184. package/src/components/Grid/Grid.test.tsx +86 -0
  185. package/src/components/Grid/Grid.tsx +45 -0
  186. package/src/components/Grid/index.ts +2 -0
  187. package/src/components/Input/Input.css +87 -0
  188. package/src/components/Input/Input.test.tsx +95 -0
  189. package/src/components/Input/Input.tsx +69 -0
  190. package/src/components/Input/index.ts +2 -0
  191. package/src/components/Link/Link.css +30 -0
  192. package/src/components/Link/Link.test.tsx +88 -0
  193. package/src/components/Link/Link.tsx +31 -0
  194. package/src/components/Link/index.ts +2 -0
  195. package/src/components/Nav/Nav.css +179 -0
  196. package/src/components/Nav/Nav.test.tsx +174 -0
  197. package/src/components/Nav/Nav.tsx +101 -0
  198. package/src/components/Nav/index.ts +2 -0
  199. package/src/components/Progress/Progress.css +93 -0
  200. package/src/components/Progress/Progress.test.tsx +93 -0
  201. package/src/components/Progress/Progress.tsx +104 -0
  202. package/src/components/Progress/index.ts +2 -0
  203. package/src/components/Radio/Radio.css +98 -0
  204. package/src/components/Radio/Radio.test.tsx +80 -0
  205. package/src/components/Radio/Radio.tsx +72 -0
  206. package/src/components/Radio/index.ts +2 -0
  207. package/src/components/Section/Section.css +28 -0
  208. package/src/components/Section/Section.test.tsx +100 -0
  209. package/src/components/Section/Section.tsx +41 -0
  210. package/src/components/Section/index.ts +2 -0
  211. package/src/components/Select/Select.css +75 -0
  212. package/src/components/Select/Select.test.tsx +99 -0
  213. package/src/components/Select/Select.tsx +78 -0
  214. package/src/components/Select/index.ts +2 -0
  215. package/src/components/Skeleton/Skeleton.css +52 -0
  216. package/src/components/Skeleton/Skeleton.test.tsx +96 -0
  217. package/src/components/Skeleton/Skeleton.tsx +55 -0
  218. package/src/components/Skeleton/index.ts +2 -0
  219. package/src/components/Slider/Slider.css +107 -0
  220. package/src/components/Slider/Slider.test.tsx +85 -0
  221. package/src/components/Slider/Slider.tsx +66 -0
  222. package/src/components/Slider/index.ts +2 -0
  223. package/src/components/Spinner/Spinner.css +61 -0
  224. package/src/components/Spinner/Spinner.test.tsx +56 -0
  225. package/src/components/Spinner/Spinner.tsx +38 -0
  226. package/src/components/Spinner/index.ts +2 -0
  227. package/src/components/Stack/Stack.css +71 -0
  228. package/src/components/Stack/Stack.test.tsx +130 -0
  229. package/src/components/Stack/Stack.tsx +77 -0
  230. package/src/components/Stack/index.ts +2 -0
  231. package/src/components/Switch/Switch.css +94 -0
  232. package/src/components/Switch/Switch.test.tsx +98 -0
  233. package/src/components/Switch/Switch.tsx +80 -0
  234. package/src/components/Switch/index.ts +2 -0
  235. package/src/components/Table/Table.css +83 -0
  236. package/src/components/Table/Table.test.tsx +134 -0
  237. package/src/components/Table/Table.tsx +102 -0
  238. package/src/components/Table/index.ts +2 -0
  239. package/src/components/Tabs/Tabs.css +51 -0
  240. package/src/components/Tabs/Tabs.test.tsx +164 -0
  241. package/src/components/Tabs/Tabs.tsx +126 -0
  242. package/src/components/Tabs/index.ts +2 -0
  243. package/src/components/Tag/Tag.css +98 -0
  244. package/src/components/Tag/Tag.test.tsx +112 -0
  245. package/src/components/Tag/Tag.tsx +73 -0
  246. package/src/components/Tag/index.ts +2 -0
  247. package/src/components/Textarea/Textarea.css +80 -0
  248. package/src/components/Textarea/Textarea.test.tsx +89 -0
  249. package/src/components/Textarea/Textarea.tsx +102 -0
  250. package/src/components/Textarea/index.ts +2 -0
  251. package/src/components/Toast/Toast.css +103 -0
  252. package/src/components/Toast/Toast.test.tsx +219 -0
  253. package/src/components/Toast/Toast.tsx +177 -0
  254. package/src/components/Toast/index.ts +2 -0
  255. package/src/components/Tooltip/Tooltip.css +63 -0
  256. package/src/components/Tooltip/Tooltip.test.tsx +196 -0
  257. package/src/components/Tooltip/Tooltip.tsx +89 -0
  258. package/src/components/Tooltip/index.ts +2 -0
  259. package/src/index.ts +99 -0
  260. package/src/static.css +47 -0
  261. package/src/test-setup.ts +7 -0
@@ -0,0 +1,2464 @@
1
+ /*! Strand UI v0.2.0 | MIT License | dillingerstaffing.com */
2
+
3
+ /* Alert */
4
+ /*! Strand UI | MIT License | dillingerstaffing.com */
5
+
6
+ /* ── Base ── */
7
+ .strand-alert {
8
+ position: relative;
9
+ display: flex;
10
+ align-items: flex-start;
11
+ justify-content: space-between;
12
+ width: 100%;
13
+ padding: var(--strand-space-6);
14
+ padding-left: var(--strand-space-5);
15
+ border-radius: var(--strand-radius-md);
16
+ border-left: 4px solid transparent;
17
+ font-family: var(--strand-font-sans);
18
+ font-size: var(--strand-text-sm);
19
+ }
20
+
21
+ /* ── Status variants ── */
22
+ .strand-alert--info {
23
+ background: var(--strand-blue-glow);
24
+ border-left-color: var(--strand-blue-primary);
25
+ }
26
+
27
+ .strand-alert--success {
28
+ background: rgba(34, 197, 94, 0.08);
29
+ border-left-color: var(--strand-green-positive);
30
+ }
31
+
32
+ .strand-alert--warning {
33
+ background: rgba(245, 158, 11, 0.08);
34
+ border-left-color: var(--strand-amber-caution);
35
+ }
36
+
37
+ .strand-alert--error {
38
+ background: rgba(239, 68, 68, 0.08);
39
+ border-left-color: var(--strand-red-alert);
40
+ }
41
+
42
+ /* ── Content ── */
43
+ .strand-alert__content {
44
+ flex: 1;
45
+ min-width: 0;
46
+ }
47
+
48
+ /* ── Dismiss button ── */
49
+ .strand-alert__dismiss {
50
+ flex-shrink: 0;
51
+ display: inline-flex;
52
+ align-items: center;
53
+ justify-content: center;
54
+ width: 24px;
55
+ height: 24px;
56
+ margin-left: var(--strand-space-4);
57
+ padding: 0;
58
+ border: none;
59
+ border-radius: var(--strand-radius-md);
60
+ background: transparent;
61
+ color: var(--strand-gray-500);
62
+ font-size: var(--strand-text-base);
63
+ cursor: pointer;
64
+ transition: background var(--strand-duration-fast) var(--strand-ease-out-quart),
65
+ color var(--strand-duration-fast) var(--strand-ease-out-quart);
66
+ }
67
+
68
+ .strand-alert__dismiss:hover {
69
+ background: var(--strand-gray-100);
70
+ color: var(--strand-gray-600);
71
+ }
72
+
73
+ /* ── Reduced motion ── */
74
+ @media (prefers-reduced-motion: reduce) {
75
+ .strand-alert__dismiss {
76
+ transition: none;
77
+ }
78
+ }
79
+
80
+
81
+ /* Avatar */
82
+ /*! Strand UI | MIT License | dillingerstaffing.com */
83
+
84
+ /* ── Base ── */
85
+ .strand-avatar {
86
+ display: inline-flex;
87
+ align-items: center;
88
+ justify-content: center;
89
+ border-radius: var(--strand-radius-full);
90
+ background: var(--strand-surface-recessed);
91
+ overflow: hidden;
92
+ flex-shrink: 0;
93
+ font-family: var(--strand-font-sans);
94
+ font-weight: var(--strand-weight-medium);
95
+ color: var(--strand-gray-600);
96
+ user-select: none;
97
+ }
98
+
99
+ /* ── Image ── */
100
+ .strand-avatar__img {
101
+ width: 100%;
102
+ height: 100%;
103
+ object-fit: cover;
104
+ border-radius: var(--strand-radius-full);
105
+ }
106
+
107
+ /* ── Initials ── */
108
+ .strand-avatar__initials {
109
+ text-transform: uppercase;
110
+ line-height: 1;
111
+ }
112
+
113
+ /* ── Sizes ── */
114
+ .strand-avatar--sm {
115
+ width: 32px;
116
+ height: 32px;
117
+ font-size: var(--strand-text-xs);
118
+ }
119
+
120
+ .strand-avatar--md {
121
+ width: 40px;
122
+ height: 40px;
123
+ font-size: var(--strand-text-sm);
124
+ }
125
+
126
+ .strand-avatar--lg {
127
+ width: 48px;
128
+ height: 48px;
129
+ font-size: var(--strand-text-base);
130
+ }
131
+
132
+ .strand-avatar--xl {
133
+ width: 64px;
134
+ height: 64px;
135
+ font-size: var(--strand-text-lg);
136
+ }
137
+
138
+
139
+ /* Badge */
140
+ /*! Strand UI | MIT License | dillingerstaffing.com */
141
+
142
+ /* ── Wrapper ── */
143
+ .strand-badge {
144
+ position: relative;
145
+ display: inline-flex;
146
+ vertical-align: middle;
147
+ }
148
+
149
+ .strand-badge--inline {
150
+ display: inline-flex;
151
+ }
152
+
153
+ /* ── Indicator (shared) ── */
154
+ .strand-badge__indicator {
155
+ display: inline-flex;
156
+ align-items: center;
157
+ justify-content: center;
158
+ font-family: var(--strand-font-sans);
159
+ font-weight: var(--strand-weight-semibold);
160
+ color: var(--strand-on-blue-primary);
161
+ }
162
+
163
+ /* Position at top-right when wrapping children */
164
+ .strand-badge:not(.strand-badge--inline) > .strand-badge__indicator {
165
+ position: absolute;
166
+ top: 0;
167
+ right: 0;
168
+ transform: translate(50%, -50%);
169
+ z-index: 1;
170
+ }
171
+
172
+ /* ── Dot variant ── */
173
+ .strand-badge--dot {
174
+ width: 8px;
175
+ height: 8px;
176
+ border-radius: var(--strand-radius-full);
177
+ font-size: 0;
178
+ padding: 0;
179
+ }
180
+
181
+ /* ── Count variant ── */
182
+ .strand-badge--count {
183
+ min-width: 20px;
184
+ height: 20px;
185
+ padding: 0 var(--strand-space-1);
186
+ border-radius: var(--strand-radius-full);
187
+ font-size: var(--strand-text-xs);
188
+ line-height: 20px;
189
+ }
190
+
191
+ /* ── Status colors ── */
192
+ .strand-badge--default {
193
+ background: var(--strand-gray-500);
194
+ }
195
+
196
+ .strand-badge--teal {
197
+ background: var(--strand-teal-vital);
198
+ }
199
+
200
+ .strand-badge--blue {
201
+ background: var(--strand-blue-primary);
202
+ }
203
+
204
+ .strand-badge--amber {
205
+ background: var(--strand-amber-caution);
206
+ color: var(--strand-blue-midnight);
207
+ }
208
+
209
+ .strand-badge--red {
210
+ background: var(--strand-red-alert);
211
+ }
212
+
213
+
214
+ /* Breadcrumb */
215
+ /*! Strand UI | MIT License | dillingerstaffing.com */
216
+
217
+ .strand-breadcrumb__list {
218
+ display: flex;
219
+ align-items: center;
220
+ gap: var(--strand-space-2);
221
+ list-style: none;
222
+ margin: 0;
223
+ padding: 0;
224
+ font-family: var(--strand-font-sans);
225
+ font-size: var(--strand-text-sm);
226
+ }
227
+
228
+ .strand-breadcrumb__item {
229
+ display: inline-flex;
230
+ align-items: center;
231
+ gap: var(--strand-space-2);
232
+ }
233
+
234
+ .strand-breadcrumb__separator {
235
+ color: var(--strand-gray-400);
236
+ user-select: none;
237
+ }
238
+
239
+ .strand-breadcrumb__link {
240
+ color: var(--strand-gray-500);
241
+ text-decoration: none;
242
+ transition: color var(--strand-duration-fast) var(--strand-ease-out-quart);
243
+ }
244
+
245
+ .strand-breadcrumb__link:hover {
246
+ color: var(--strand-gray-600);
247
+ }
248
+
249
+ .strand-breadcrumb__link:focus-visible {
250
+ outline: 2px solid var(--strand-blue-primary);
251
+ outline-offset: 2px;
252
+ }
253
+
254
+ .strand-breadcrumb__current {
255
+ color: var(--strand-gray-600);
256
+ font-weight: var(--strand-weight-medium);
257
+ }
258
+
259
+ /* ── Reduced motion ── */
260
+ @media (prefers-reduced-motion: reduce) {
261
+ .strand-breadcrumb__link {
262
+ transition: none;
263
+ }
264
+ }
265
+
266
+
267
+ /* Button */
268
+ /*! Strand UI | MIT License | dillingerstaffing.com */
269
+
270
+ /* ── Base ── */
271
+ .strand-btn {
272
+ position: relative;
273
+ display: inline-flex;
274
+ align-items: center;
275
+ justify-content: center;
276
+ gap: var(--strand-space-2);
277
+ border: 1px solid transparent;
278
+ border-radius: var(--strand-radius-md);
279
+ font-family: var(--strand-font-sans);
280
+ font-weight: var(--strand-weight-medium);
281
+ line-height: var(--strand-leading-snug);
282
+ white-space: nowrap;
283
+ cursor: pointer;
284
+ user-select: none;
285
+ transition:
286
+ background var(--strand-duration-fast) var(--strand-ease-out-quart),
287
+ border-color var(--strand-duration-fast) var(--strand-ease-out-quart),
288
+ color var(--strand-duration-fast) var(--strand-ease-out-quart),
289
+ transform var(--strand-duration-fast) var(--strand-ease-out-expo),
290
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-quart);
291
+ }
292
+
293
+ .strand-btn:active:not(:disabled) {
294
+ transform: translateY(0);
295
+ transition-duration: 75ms;
296
+ }
297
+
298
+ .strand-btn:disabled {
299
+ opacity: 0.4;
300
+ cursor: not-allowed;
301
+ }
302
+
303
+ /* ── Sizes ── */
304
+ .strand-btn--sm {
305
+ padding: var(--strand-space-1) var(--strand-space-3);
306
+ font-size: var(--strand-text-sm);
307
+ min-height: 32px;
308
+ }
309
+
310
+ .strand-btn--md {
311
+ padding: calc(var(--strand-space-2) + var(--strand-space-1) / 2) var(--strand-space-5);
312
+ font-size: var(--strand-text-sm);
313
+ min-height: 40px;
314
+ }
315
+
316
+ .strand-btn--lg {
317
+ padding: var(--strand-space-3) var(--strand-space-6);
318
+ font-size: var(--strand-text-base);
319
+ min-height: 48px;
320
+ }
321
+
322
+ /* ── Icon-only ── */
323
+ .strand-btn--icon-only.strand-btn--sm {
324
+ padding: var(--strand-space-1);
325
+ min-width: 32px;
326
+ }
327
+
328
+ .strand-btn--icon-only.strand-btn--md {
329
+ padding: var(--strand-space-2);
330
+ min-width: 40px;
331
+ }
332
+
333
+ .strand-btn--icon-only.strand-btn--lg {
334
+ padding: var(--strand-space-3);
335
+ min-width: 48px;
336
+ }
337
+
338
+ /* ── Full width ── */
339
+ .strand-btn--full-width {
340
+ width: 100%;
341
+ }
342
+
343
+ /* ── Primary variant ── */
344
+ .strand-btn--primary {
345
+ background: var(--strand-blue-primary);
346
+ color: var(--strand-on-blue-primary);
347
+ }
348
+
349
+ .strand-btn--primary:hover:not(:disabled) {
350
+ background: var(--strand-blue-vivid);
351
+ transform: translateY(-1px);
352
+ box-shadow: var(--strand-hover-shadow-primary);
353
+ }
354
+
355
+ .strand-btn--primary:active:not(:disabled) {
356
+ background: var(--strand-blue-deep);
357
+ }
358
+
359
+ /* ── Secondary variant ── */
360
+ .strand-btn--secondary {
361
+ background: var(--strand-surface-elevated);
362
+ color: var(--strand-blue-midnight);
363
+ border-color: var(--strand-gray-200);
364
+ }
365
+
366
+ .strand-btn--secondary:hover:not(:disabled) {
367
+ background: var(--strand-blue-glow);
368
+ border-color: var(--strand-blue-indicator);
369
+ transform: translateY(-1px);
370
+ box-shadow: var(--strand-elevation-1);
371
+ }
372
+
373
+ .strand-btn--secondary:active:not(:disabled) {
374
+ background: var(--strand-blue-wash);
375
+ }
376
+
377
+ /* ── Ghost variant ── */
378
+ .strand-btn--ghost {
379
+ background: transparent;
380
+ color: var(--strand-blue-primary);
381
+ }
382
+
383
+ .strand-btn--ghost:hover:not(:disabled) {
384
+ background: var(--strand-blue-glow);
385
+ transform: translateY(-1px);
386
+ }
387
+
388
+ .strand-btn--ghost:active:not(:disabled) {
389
+ background: var(--strand-blue-wash);
390
+ }
391
+
392
+ /* ── Danger variant ── */
393
+ .strand-btn--danger {
394
+ background: var(--strand-red-alert);
395
+ color: var(--strand-on-red-alert);
396
+ }
397
+
398
+ .strand-btn--danger:hover:not(:disabled) {
399
+ background: var(--strand-red-alert-vivid);
400
+ transform: translateY(-1px);
401
+ box-shadow: var(--strand-hover-shadow-danger);
402
+ }
403
+
404
+ .strand-btn--danger:active:not(:disabled) {
405
+ background: var(--strand-red-alert-deep);
406
+ }
407
+
408
+ /* ── Loading state ── */
409
+ .strand-btn--loading {
410
+ pointer-events: none;
411
+ }
412
+
413
+ .strand-btn__spinner {
414
+ position: absolute;
415
+ width: 16px;
416
+ height: 16px;
417
+ border: 2px solid currentColor;
418
+ border-top-color: transparent;
419
+ border-radius: var(--strand-radius-full);
420
+ animation: strand-btn-spin 0.8s linear infinite;
421
+ opacity: 0.8;
422
+ }
423
+
424
+ .strand-btn--lg .strand-btn__spinner {
425
+ width: 20px;
426
+ height: 20px;
427
+ }
428
+
429
+ @keyframes strand-btn-spin {
430
+ to {
431
+ transform: rotate(360deg);
432
+ }
433
+ }
434
+
435
+ /* ── Content wrapper ── */
436
+ .strand-btn__content {
437
+ display: inline-flex;
438
+ align-items: center;
439
+ gap: var(--strand-space-2);
440
+ }
441
+
442
+ /* ── Focus ring (Part XII: Accessibility Ring) ── */
443
+ .strand-btn:focus-visible {
444
+ outline: 2px solid var(--strand-blue-primary);
445
+ outline-offset: 2px;
446
+ }
447
+
448
+ /* ── Reduced motion ── */
449
+ @media (prefers-reduced-motion: reduce) {
450
+ .strand-btn {
451
+ transition: none;
452
+ }
453
+
454
+ .strand-btn:hover:not(:disabled) {
455
+ transform: none;
456
+ }
457
+
458
+ .strand-btn__spinner {
459
+ animation: none;
460
+ border-style: dotted;
461
+ }
462
+ }
463
+
464
+
465
+ /* Card */
466
+ /*! Strand UI | MIT License | dillingerstaffing.com */
467
+
468
+ /* ── Base ── */
469
+ .strand-card {
470
+ border-radius: var(--strand-radius-lg);
471
+ background: var(--strand-surface-elevated);
472
+ font-family: var(--strand-font-sans);
473
+ overflow: hidden;
474
+ box-sizing: border-box;
475
+ max-width: 100%;
476
+ }
477
+
478
+ /* ── Variants ── */
479
+ .strand-card--elevated {
480
+ box-shadow: var(--strand-elevation-1);
481
+ }
482
+
483
+ .strand-card--outlined {
484
+ box-shadow: none;
485
+ border: 1px solid var(--strand-gray-200);
486
+ }
487
+
488
+ .strand-card--interactive {
489
+ box-shadow: var(--strand-elevation-1);
490
+ cursor: pointer;
491
+ transition:
492
+ transform var(--strand-duration-fast) var(--strand-ease-out-expo),
493
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-expo);
494
+ }
495
+
496
+ .strand-card--interactive:hover {
497
+ transform: translateY(-2px);
498
+ box-shadow: var(--strand-elevation-2);
499
+ }
500
+
501
+ /* ── Padding ── */
502
+ .strand-card--pad-none {
503
+ padding: 0;
504
+ }
505
+
506
+ .strand-card--pad-sm {
507
+ padding: var(--strand-space-4);
508
+ }
509
+
510
+ .strand-card--pad-md {
511
+ padding: var(--strand-space-6);
512
+ }
513
+
514
+ .strand-card--pad-lg {
515
+ padding: var(--strand-space-10);
516
+ }
517
+
518
+ /* ── Focus ring (interactive cards) ── */
519
+ .strand-card--interactive:focus-visible {
520
+ outline: 2px solid var(--strand-blue-primary);
521
+ outline-offset: 2px;
522
+ }
523
+
524
+ /* ── Reduced motion ── */
525
+ @media (prefers-reduced-motion: reduce) {
526
+ .strand-card--interactive {
527
+ transition: none;
528
+ }
529
+
530
+ .strand-card--interactive:hover {
531
+ transform: none;
532
+ }
533
+ }
534
+
535
+
536
+ /* Checkbox */
537
+ /*! Strand UI | MIT License | dillingerstaffing.com */
538
+
539
+ /* ── Base ── */
540
+ .strand-checkbox {
541
+ display: inline-flex;
542
+ align-items: center;
543
+ gap: var(--strand-space-2);
544
+ cursor: pointer;
545
+ user-select: none;
546
+ font-family: var(--strand-font-sans);
547
+ font-size: var(--strand-text-sm);
548
+ color: var(--strand-gray-900);
549
+ line-height: var(--strand-leading-snug);
550
+ }
551
+
552
+ /* ── Hidden native input ── */
553
+ .strand-checkbox__native {
554
+ position: absolute;
555
+ width: 1px;
556
+ height: 1px;
557
+ padding: 0;
558
+ margin: -1px;
559
+ overflow: hidden;
560
+ clip: rect(0, 0, 0, 0);
561
+ white-space: nowrap;
562
+ border: 0;
563
+ }
564
+
565
+ /* ── Custom visual ── */
566
+ .strand-checkbox__control {
567
+ display: flex;
568
+ align-items: center;
569
+ justify-content: center;
570
+ width: 18px;
571
+ height: 18px;
572
+ border: 1px solid var(--strand-gray-200);
573
+ border-radius: var(--strand-radius-sm);
574
+ background: var(--strand-surface-elevated);
575
+ color: var(--strand-on-blue-primary);
576
+ flex-shrink: 0;
577
+ transition:
578
+ background var(--strand-duration-fast) var(--strand-ease-out-quart),
579
+ border-color var(--strand-duration-fast) var(--strand-ease-out-quart),
580
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-quart);
581
+ }
582
+
583
+ .strand-checkbox__icon {
584
+ width: 14px;
585
+ height: 14px;
586
+ }
587
+
588
+ /* ── Focus ring ── */
589
+ .strand-checkbox__native:focus-visible ~ .strand-checkbox__control {
590
+ border-color: var(--strand-blue-primary);
591
+ box-shadow: var(--strand-focus-ring);
592
+ }
593
+
594
+ /* ── Checked ── */
595
+ .strand-checkbox--checked .strand-checkbox__control {
596
+ background: var(--strand-blue-primary);
597
+ border-color: var(--strand-blue-primary);
598
+ }
599
+
600
+ /* ── Indeterminate ── */
601
+ .strand-checkbox--indeterminate .strand-checkbox__control {
602
+ background: var(--strand-blue-primary);
603
+ border-color: var(--strand-blue-primary);
604
+ }
605
+
606
+ /* ── Hover ── */
607
+ .strand-checkbox:hover:not(.strand-checkbox--disabled) .strand-checkbox__control {
608
+ border-color: var(--strand-blue-indicator);
609
+ }
610
+
611
+ .strand-checkbox--checked:hover:not(.strand-checkbox--disabled) .strand-checkbox__control,
612
+ .strand-checkbox--indeterminate:hover:not(.strand-checkbox--disabled) .strand-checkbox__control {
613
+ background: var(--strand-blue-vivid);
614
+ border-color: var(--strand-blue-vivid);
615
+ }
616
+
617
+ /* ── Label ── */
618
+ .strand-checkbox__label {
619
+ color: var(--strand-gray-900);
620
+ }
621
+
622
+ /* ── Disabled ── */
623
+ .strand-checkbox--disabled {
624
+ opacity: 0.4;
625
+ cursor: not-allowed;
626
+ }
627
+
628
+ /* ── Reduced motion ── */
629
+ @media (prefers-reduced-motion: reduce) {
630
+ .strand-checkbox__control {
631
+ transition: none;
632
+ }
633
+ }
634
+
635
+
636
+ /* Container */
637
+ /*! Strand UI | MIT License | dillingerstaffing.com */
638
+
639
+ /* ── Base ── */
640
+ .strand-container {
641
+ width: 100%;
642
+ margin-inline: auto;
643
+ padding-inline: clamp(1.5rem, 5vw, 4rem);
644
+ }
645
+
646
+ /* ── Sizes ── */
647
+ .strand-container--narrow {
648
+ max-width: var(--strand-content-narrow);
649
+ }
650
+
651
+ .strand-container--default {
652
+ max-width: var(--strand-content-default);
653
+ }
654
+
655
+ .strand-container--wide {
656
+ max-width: var(--strand-content-wide);
657
+ }
658
+
659
+ .strand-container--full {
660
+ max-width: var(--strand-content-full);
661
+ }
662
+
663
+
664
+ /* DataReadout */
665
+ /*! Strand UI | MIT License | dillingerstaffing.com */
666
+
667
+ /* ── Layout ── */
668
+ .strand-data-readout {
669
+ display: flex;
670
+ flex-direction: column;
671
+ gap: var(--strand-space-1);
672
+ }
673
+
674
+ /* ── Label (overline) ── */
675
+ .strand-data-readout__label {
676
+ font-family: var(--strand-font-mono);
677
+ font-size: var(--strand-text-xs);
678
+ font-weight: var(--strand-weight-medium);
679
+ letter-spacing: var(--strand-tracking-ultra);
680
+ text-transform: uppercase;
681
+ color: var(--strand-gray-500);
682
+ line-height: var(--strand-leading-normal);
683
+ }
684
+
685
+ /* ── Value (instrument readout) ── */
686
+ .strand-data-readout__value {
687
+ font-family: var(--strand-font-mono);
688
+ font-size: var(--strand-text-3xl);
689
+ font-weight: var(--strand-weight-light);
690
+ letter-spacing: var(--strand-tracking-tighter);
691
+ color: var(--strand-blue-midnight);
692
+ line-height: var(--strand-leading-tight);
693
+ font-variant-numeric: tabular-nums;
694
+ }
695
+
696
+
697
+ /* Dialog */
698
+ /*! Strand UI | MIT License | dillingerstaffing.com */
699
+
700
+ /* ── Backdrop ── */
701
+ .strand-dialog__backdrop {
702
+ position: fixed;
703
+ inset: 0;
704
+ z-index: 1000;
705
+ display: flex;
706
+ align-items: center;
707
+ justify-content: center;
708
+ background: var(--strand-backdrop);
709
+ }
710
+
711
+ /* ── Panel ── */
712
+ .strand-dialog__panel {
713
+ position: relative;
714
+ width: 100%;
715
+ max-width: 560px;
716
+ margin: var(--strand-space-4);
717
+ padding: var(--strand-space-8);
718
+ background: var(--strand-surface-elevated);
719
+ border-radius: var(--strand-radius-xl);
720
+ box-shadow: var(--strand-elevation-4);
721
+ font-family: var(--strand-font-sans);
722
+ outline: none;
723
+ }
724
+
725
+ /* ── Header ── */
726
+ .strand-dialog__header {
727
+ margin-bottom: var(--strand-space-4);
728
+ padding-right: var(--strand-space-8);
729
+ }
730
+
731
+ /* ── Title ── */
732
+ .strand-dialog__title {
733
+ margin: 0;
734
+ font-size: var(--strand-text-lg);
735
+ font-weight: var(--strand-weight-semibold);
736
+ color: var(--strand-blue-midnight);
737
+ line-height: var(--strand-leading-snug);
738
+ }
739
+
740
+ /* ── Close button ── */
741
+ .strand-dialog__close {
742
+ position: absolute;
743
+ top: var(--strand-space-6);
744
+ right: var(--strand-space-6);
745
+ display: inline-flex;
746
+ align-items: center;
747
+ justify-content: center;
748
+ width: 32px;
749
+ height: 32px;
750
+ padding: 0;
751
+ border: none;
752
+ border-radius: var(--strand-radius-md);
753
+ background: transparent;
754
+ color: var(--strand-gray-500);
755
+ font-size: var(--strand-text-lg);
756
+ cursor: pointer;
757
+ transition: background var(--strand-duration-fast) var(--strand-ease-out-quart),
758
+ color var(--strand-duration-fast) var(--strand-ease-out-quart);
759
+ }
760
+
761
+ .strand-dialog__close:hover {
762
+ background: var(--strand-gray-200);
763
+ color: var(--strand-gray-900);
764
+ }
765
+
766
+ /* ── Body ── */
767
+ .strand-dialog__body {
768
+ padding-top: var(--strand-space-6);
769
+ color: var(--strand-gray-600);
770
+ font-size: var(--strand-text-sm);
771
+ }
772
+
773
+ /* ── Reduced motion ── */
774
+ @media (prefers-reduced-motion: reduce) {
775
+ .strand-dialog__close {
776
+ transition: none;
777
+ }
778
+ }
779
+
780
+
781
+ /* Divider */
782
+ /*! Strand UI | MIT License | dillingerstaffing.com */
783
+
784
+ /* ── Base ── */
785
+ .strand-divider {
786
+ border: 0;
787
+ margin: 0;
788
+ padding: 0;
789
+ }
790
+
791
+ /* ── Horizontal (hr) ── */
792
+ .strand-divider--horizontal {
793
+ width: 100%;
794
+ border-top: 1px solid var(--strand-gray-200);
795
+ }
796
+
797
+ /* ── Vertical ── */
798
+ .strand-divider--vertical {
799
+ align-self: stretch;
800
+ border-left: 1px solid var(--strand-gray-200);
801
+ }
802
+
803
+ /* ── Labeled ── */
804
+ .strand-divider--labeled {
805
+ display: flex;
806
+ align-items: center;
807
+ gap: var(--strand-space-3);
808
+ border-top: 0;
809
+ }
810
+
811
+ .strand-divider__line {
812
+ flex: 1;
813
+ height: 0;
814
+ border-top: 1px solid var(--strand-gray-200);
815
+ }
816
+
817
+ .strand-divider__label {
818
+ font-family: var(--strand-font-mono);
819
+ font-size: var(--strand-text-xs);
820
+ font-weight: var(--strand-weight-medium);
821
+ color: var(--strand-gray-400);
822
+ letter-spacing: var(--strand-tracking-widest);
823
+ text-transform: uppercase;
824
+ white-space: nowrap;
825
+ }
826
+
827
+
828
+ /* FormField */
829
+ /*! Strand UI | MIT License | dillingerstaffing.com */
830
+
831
+ /* ── Base ── */
832
+ .strand-form-field {
833
+ display: flex;
834
+ flex-direction: column;
835
+ gap: var(--strand-space-2);
836
+ }
837
+
838
+ /* ── Label ── */
839
+ .strand-form-field__label {
840
+ font-family: var(--strand-font-sans);
841
+ font-size: var(--strand-text-sm);
842
+ font-weight: var(--strand-weight-medium);
843
+ color: var(--strand-gray-700);
844
+ line-height: var(--strand-leading-snug);
845
+ }
846
+
847
+ /* ── Required indicator ── */
848
+ .strand-form-field__required {
849
+ color: var(--strand-red-alert);
850
+ margin-left: var(--strand-space-1);
851
+ }
852
+
853
+ /* ── Control wrapper ── */
854
+ .strand-form-field__control {
855
+ display: flex;
856
+ flex-direction: column;
857
+ }
858
+
859
+ /* ── Hint ── */
860
+ .strand-form-field__hint {
861
+ margin: 0;
862
+ font-family: var(--strand-font-sans);
863
+ font-size: var(--strand-text-xs);
864
+ color: var(--strand-gray-500);
865
+ line-height: var(--strand-leading-normal);
866
+ }
867
+
868
+ /* ── Error message ── */
869
+ .strand-form-field__error {
870
+ margin: 0;
871
+ font-family: var(--strand-font-sans);
872
+ font-size: var(--strand-text-xs);
873
+ color: var(--strand-red-alert);
874
+ line-height: var(--strand-leading-normal);
875
+ }
876
+
877
+
878
+ /* Grid */
879
+ /*! Strand UI | MIT License | dillingerstaffing.com */
880
+
881
+ /* ── Base ── */
882
+ .strand-grid {
883
+ display: grid;
884
+ overflow: hidden;
885
+ max-width: 100%;
886
+ box-sizing: border-box;
887
+ }
888
+
889
+ .strand-grid > * {
890
+ min-width: 0;
891
+ }
892
+
893
+ /* ── Column utilities ── */
894
+ .strand-grid--cols-2 { grid-template-columns: repeat(2, 1fr); }
895
+ .strand-grid--cols-3 { grid-template-columns: repeat(3, 1fr); }
896
+ .strand-grid--cols-4 { grid-template-columns: repeat(4, 1fr); }
897
+
898
+ /* ── Gap utilities ── */
899
+ .strand-grid--gap-1 { gap: var(--strand-space-1); }
900
+ .strand-grid--gap-2 { gap: var(--strand-space-2); }
901
+ .strand-grid--gap-3 { gap: var(--strand-space-3); }
902
+ .strand-grid--gap-4 { gap: var(--strand-space-4); }
903
+ .strand-grid--gap-5 { gap: var(--strand-space-5); }
904
+ .strand-grid--gap-6 { gap: var(--strand-space-6); }
905
+ .strand-grid--gap-8 { gap: var(--strand-space-8); }
906
+
907
+
908
+ /* Input */
909
+ /*! Strand UI | MIT License | dillingerstaffing.com */
910
+
911
+ .strand-input {
912
+ position: relative;
913
+ display: flex;
914
+ align-items: center;
915
+ background: var(--strand-surface-elevated);
916
+ border: 1px solid var(--strand-gray-200);
917
+ border-radius: var(--strand-radius-md);
918
+ transition:
919
+ border-color var(--strand-duration-fast) var(--strand-ease-out-quart),
920
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-quart);
921
+ }
922
+
923
+ .strand-input:focus-within {
924
+ border-color: var(--strand-blue-primary);
925
+ box-shadow: var(--strand-focus-ring);
926
+ }
927
+
928
+ /* ── Field ── */
929
+ .strand-input__field {
930
+ flex: 1;
931
+ width: 100%;
932
+ padding: var(--strand-space-3) var(--strand-space-4);
933
+ background: transparent;
934
+ border: none;
935
+ font-family: var(--strand-font-sans);
936
+ font-size: var(--strand-text-base);
937
+ color: var(--strand-gray-900);
938
+ outline: none;
939
+ }
940
+
941
+ .strand-input__field::placeholder {
942
+ color: var(--strand-gray-400);
943
+ }
944
+
945
+ /* ── Addons ── */
946
+ .strand-input__leading,
947
+ .strand-input__trailing {
948
+ display: flex;
949
+ align-items: center;
950
+ color: var(--strand-gray-500);
951
+ font-size: var(--strand-text-sm);
952
+ }
953
+
954
+ .strand-input__leading {
955
+ padding-left: var(--strand-space-3);
956
+ }
957
+
958
+ .strand-input__trailing {
959
+ padding-right: var(--strand-space-3);
960
+ }
961
+
962
+ .strand-input--has-leading .strand-input__field {
963
+ padding-left: var(--strand-space-2);
964
+ }
965
+
966
+ .strand-input--has-trailing .strand-input__field {
967
+ padding-right: var(--strand-space-2);
968
+ }
969
+
970
+ /* ── Error ── */
971
+ .strand-input--error {
972
+ border-color: var(--strand-red-alert);
973
+ }
974
+
975
+ .strand-input--error:focus-within {
976
+ border-color: var(--strand-red-alert);
977
+ box-shadow: var(--strand-focus-ring-error);
978
+ }
979
+
980
+ /* ── Disabled ── */
981
+ .strand-input--disabled {
982
+ opacity: 0.4;
983
+ cursor: not-allowed;
984
+ }
985
+
986
+ .strand-input--disabled .strand-input__field {
987
+ cursor: not-allowed;
988
+ }
989
+
990
+ /* ── Reduced motion ── */
991
+ @media (prefers-reduced-motion: reduce) {
992
+ .strand-input {
993
+ transition: none;
994
+ }
995
+ }
996
+
997
+
998
+ /* Link */
999
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1000
+
1001
+ .strand-link {
1002
+ color: var(--strand-blue-primary);
1003
+ text-decoration: none;
1004
+ font-family: var(--strand-font-sans);
1005
+ background-image: linear-gradient(currentColor, currentColor);
1006
+ background-position: 0% 100%;
1007
+ background-repeat: no-repeat;
1008
+ background-size: 0% 1px;
1009
+ transition: background-size var(--strand-duration-normal) var(--strand-ease-out-expo);
1010
+ cursor: pointer;
1011
+ }
1012
+
1013
+ .strand-link:hover {
1014
+ background-size: 100% 1px;
1015
+ }
1016
+
1017
+ /* ── Focus ring ── */
1018
+ .strand-link:focus-visible {
1019
+ outline: 2px solid var(--strand-blue-primary);
1020
+ outline-offset: 2px;
1021
+ }
1022
+
1023
+ /* ── Reduced motion ── */
1024
+ @media (prefers-reduced-motion: reduce) {
1025
+ .strand-link {
1026
+ transition: none;
1027
+ }
1028
+ }
1029
+
1030
+
1031
+ /* Nav */
1032
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1033
+
1034
+ /* ── Nav bar ── */
1035
+ .strand-nav {
1036
+ position: relative;
1037
+ width: 100%;
1038
+ height: 64px;
1039
+ background: var(--strand-surface-elevated);
1040
+ border-bottom: 1px solid var(--strand-gray-200);
1041
+ font-family: var(--strand-font-sans);
1042
+ }
1043
+
1044
+ /* ── Inner layout ── */
1045
+ .strand-nav__inner {
1046
+ display: flex;
1047
+ align-items: center;
1048
+ height: 100%;
1049
+ padding: 0 var(--strand-space-6);
1050
+ max-width: 1280px;
1051
+ margin: 0 auto;
1052
+ }
1053
+
1054
+ /* ── Logo ── */
1055
+ .strand-nav__logo {
1056
+ flex-shrink: 0;
1057
+ margin-right: var(--strand-space-8);
1058
+ }
1059
+
1060
+ /* ── Desktop items ── */
1061
+ .strand-nav__items {
1062
+ display: flex;
1063
+ align-items: center;
1064
+ gap: var(--strand-space-6);
1065
+ flex: 1;
1066
+ }
1067
+
1068
+ /* ── Links ── */
1069
+ .strand-nav__link {
1070
+ color: var(--strand-gray-600);
1071
+ text-decoration: none;
1072
+ font-size: var(--strand-text-sm);
1073
+ font-weight: var(--strand-weight-medium);
1074
+ transition: color var(--strand-duration-fast) var(--strand-ease-out-quart);
1075
+ }
1076
+
1077
+ .strand-nav__link:hover {
1078
+ color: var(--strand-gray-900);
1079
+ }
1080
+
1081
+ .strand-nav__link:focus-visible {
1082
+ outline: 2px solid var(--strand-blue-primary);
1083
+ outline-offset: 2px;
1084
+ }
1085
+
1086
+ .strand-nav__link--active {
1087
+ color: var(--strand-blue-primary);
1088
+ font-weight: var(--strand-weight-medium);
1089
+ }
1090
+
1091
+ /* ── Actions ── */
1092
+ .strand-nav__actions {
1093
+ display: flex;
1094
+ align-items: center;
1095
+ gap: var(--strand-space-3);
1096
+ margin-left: auto;
1097
+ }
1098
+
1099
+ /* ── Hamburger ── */
1100
+ .strand-nav__hamburger {
1101
+ display: none;
1102
+ align-items: center;
1103
+ justify-content: center;
1104
+ width: 40px;
1105
+ height: 40px;
1106
+ margin-left: auto;
1107
+ padding: 0;
1108
+ border: none;
1109
+ border-radius: var(--strand-radius-md);
1110
+ background: transparent;
1111
+ color: var(--strand-gray-600);
1112
+ cursor: pointer;
1113
+ transition: background var(--strand-duration-fast) var(--strand-ease-out-quart);
1114
+ }
1115
+
1116
+ .strand-nav__hamburger:hover {
1117
+ background: var(--strand-gray-200);
1118
+ }
1119
+
1120
+ .strand-nav__hamburger:focus-visible {
1121
+ outline: 2px solid var(--strand-blue-primary);
1122
+ outline-offset: 2px;
1123
+ }
1124
+
1125
+ .strand-nav__hamburger-icon {
1126
+ display: block;
1127
+ width: 20px;
1128
+ height: 2px;
1129
+ background: currentColor;
1130
+ position: relative;
1131
+ }
1132
+
1133
+ .strand-nav__hamburger-icon::before,
1134
+ .strand-nav__hamburger-icon::after {
1135
+ content: "";
1136
+ position: absolute;
1137
+ left: 0;
1138
+ width: 100%;
1139
+ height: 2px;
1140
+ background: currentColor;
1141
+ }
1142
+
1143
+ .strand-nav__hamburger-icon::before {
1144
+ top: -6px;
1145
+ }
1146
+
1147
+ .strand-nav__hamburger-icon::after {
1148
+ top: 6px;
1149
+ }
1150
+
1151
+ /* ── Mobile menu ── */
1152
+ .strand-nav__mobile-menu {
1153
+ display: none;
1154
+ flex-direction: column;
1155
+ width: 100%;
1156
+ padding: var(--strand-space-4) var(--strand-space-6);
1157
+ background: var(--strand-surface-elevated);
1158
+ border-bottom: 1px solid var(--strand-gray-200);
1159
+ }
1160
+
1161
+ .strand-nav__mobile-link {
1162
+ display: block;
1163
+ padding: var(--strand-space-3) 0;
1164
+ color: var(--strand-gray-600);
1165
+ text-decoration: none;
1166
+ font-size: var(--strand-text-sm);
1167
+ font-weight: var(--strand-weight-medium);
1168
+ transition: color var(--strand-duration-fast) var(--strand-ease-out-quart);
1169
+ }
1170
+
1171
+ .strand-nav__mobile-link:hover {
1172
+ color: var(--strand-gray-900);
1173
+ }
1174
+
1175
+ .strand-nav__mobile-link--active {
1176
+ color: var(--strand-blue-primary);
1177
+ }
1178
+
1179
+ /* ── Responsive ── */
1180
+ @media (max-width: 767px) {
1181
+ .strand-nav__items {
1182
+ display: none;
1183
+ }
1184
+
1185
+ .strand-nav__actions {
1186
+ display: none;
1187
+ }
1188
+
1189
+ .strand-nav__hamburger {
1190
+ display: inline-flex;
1191
+ }
1192
+
1193
+ .strand-nav__mobile-menu {
1194
+ display: flex;
1195
+ }
1196
+
1197
+ .strand-nav {
1198
+ height: auto;
1199
+ min-height: 64px;
1200
+ }
1201
+ }
1202
+
1203
+ /* ── Reduced motion ── */
1204
+ @media (prefers-reduced-motion: reduce) {
1205
+ .strand-nav__link,
1206
+ .strand-nav__mobile-link,
1207
+ .strand-nav__hamburger {
1208
+ transition: none;
1209
+ }
1210
+ }
1211
+
1212
+
1213
+ /* Progress */
1214
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1215
+
1216
+ /* ── Bar base ── */
1217
+ .strand-progress--bar {
1218
+ width: 100%;
1219
+ background: var(--strand-gray-200);
1220
+ border-radius: var(--strand-radius-full);
1221
+ overflow: hidden;
1222
+ }
1223
+
1224
+ /* ── Bar sizes ── */
1225
+ .strand-progress--bar.strand-progress--sm {
1226
+ height: 4px;
1227
+ }
1228
+
1229
+ .strand-progress--bar.strand-progress--md {
1230
+ height: 8px;
1231
+ }
1232
+
1233
+ .strand-progress--bar.strand-progress--lg {
1234
+ height: 12px;
1235
+ }
1236
+
1237
+ /* ── Bar fill ── */
1238
+ .strand-progress--bar .strand-progress__fill {
1239
+ height: 100%;
1240
+ background: var(--strand-blue-primary);
1241
+ border-radius: var(--strand-radius-full);
1242
+ transition: width var(--strand-duration-normal) var(--strand-ease-out-quart);
1243
+ }
1244
+
1245
+ /* ── Bar indeterminate ── */
1246
+ .strand-progress--bar.strand-progress--indeterminate .strand-progress__fill {
1247
+ width: 40%;
1248
+ animation: strand-progress-shimmer 1.5s var(--strand-ease-in-out-sine) infinite;
1249
+ }
1250
+
1251
+ @keyframes strand-progress-shimmer {
1252
+ 0% {
1253
+ transform: translateX(-100%);
1254
+ }
1255
+ 100% {
1256
+ transform: translateX(350%);
1257
+ }
1258
+ }
1259
+
1260
+ /* ── Ring base ── */
1261
+ .strand-progress--ring {
1262
+ display: inline-flex;
1263
+ align-items: center;
1264
+ justify-content: center;
1265
+ }
1266
+
1267
+ /* ── Ring track and fill ── */
1268
+ .strand-progress__track {
1269
+ stroke: var(--strand-gray-200);
1270
+ }
1271
+
1272
+ .strand-progress__fill {
1273
+ stroke: var(--strand-blue-primary);
1274
+ }
1275
+
1276
+ .strand-progress--ring .strand-progress__ring {
1277
+ transition: stroke-dashoffset var(--strand-duration-normal) var(--strand-ease-out-quart);
1278
+ }
1279
+
1280
+ /* ── Ring indeterminate ── */
1281
+ .strand-progress--ring.strand-progress--indeterminate .strand-progress__ring {
1282
+ animation: strand-progress-rotate 1.2s linear infinite;
1283
+ }
1284
+
1285
+ @keyframes strand-progress-rotate {
1286
+ to {
1287
+ transform: rotate(360deg);
1288
+ }
1289
+ }
1290
+
1291
+ /* ── Reduced motion ── */
1292
+ @media (prefers-reduced-motion: reduce) {
1293
+ .strand-progress--bar .strand-progress__fill {
1294
+ transition: none;
1295
+ }
1296
+
1297
+ .strand-progress--bar.strand-progress--indeterminate .strand-progress__fill {
1298
+ animation: none;
1299
+ width: 100%;
1300
+ opacity: 0.4;
1301
+ }
1302
+
1303
+ .strand-progress--ring.strand-progress--indeterminate .strand-progress__ring {
1304
+ animation: none;
1305
+ }
1306
+ }
1307
+
1308
+
1309
+ /* Radio */
1310
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1311
+
1312
+ /* ── Base ── */
1313
+ .strand-radio {
1314
+ display: inline-flex;
1315
+ align-items: center;
1316
+ gap: var(--strand-space-2);
1317
+ cursor: pointer;
1318
+ user-select: none;
1319
+ font-family: var(--strand-font-sans);
1320
+ font-size: var(--strand-text-sm);
1321
+ color: var(--strand-gray-900);
1322
+ line-height: var(--strand-leading-snug);
1323
+ }
1324
+
1325
+ /* ── Hidden native input ── */
1326
+ .strand-radio__native {
1327
+ position: absolute;
1328
+ width: 1px;
1329
+ height: 1px;
1330
+ padding: 0;
1331
+ margin: -1px;
1332
+ overflow: hidden;
1333
+ clip: rect(0, 0, 0, 0);
1334
+ white-space: nowrap;
1335
+ border: 0;
1336
+ }
1337
+
1338
+ /* ── Custom visual ── */
1339
+ .strand-radio__control {
1340
+ display: flex;
1341
+ align-items: center;
1342
+ justify-content: center;
1343
+ width: 18px;
1344
+ height: 18px;
1345
+ border: 1px solid var(--strand-gray-200);
1346
+ border-radius: var(--strand-radius-full);
1347
+ background: var(--strand-surface-elevated);
1348
+ flex-shrink: 0;
1349
+ transition:
1350
+ background var(--strand-duration-fast) var(--strand-ease-out-quart),
1351
+ border-color var(--strand-duration-fast) var(--strand-ease-out-quart),
1352
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-quart);
1353
+ }
1354
+
1355
+ .strand-radio__dot {
1356
+ width: 8px;
1357
+ height: 8px;
1358
+ border-radius: var(--strand-radius-full);
1359
+ background: var(--strand-on-blue-primary);
1360
+ transform: scale(0);
1361
+ transition: transform var(--strand-duration-fast) var(--strand-ease-out-expo);
1362
+ }
1363
+
1364
+ /* ── Focus ring ── */
1365
+ .strand-radio__native:focus-visible ~ .strand-radio__control {
1366
+ border-color: var(--strand-blue-primary);
1367
+ box-shadow: var(--strand-focus-ring);
1368
+ }
1369
+
1370
+ /* ── Checked ── */
1371
+ .strand-radio--checked .strand-radio__control {
1372
+ background: var(--strand-blue-primary);
1373
+ border-color: var(--strand-blue-primary);
1374
+ }
1375
+
1376
+ .strand-radio--checked .strand-radio__dot {
1377
+ transform: scale(1);
1378
+ }
1379
+
1380
+ /* ── Hover ── */
1381
+ .strand-radio:hover:not(.strand-radio--disabled) .strand-radio__control {
1382
+ border-color: var(--strand-blue-indicator);
1383
+ }
1384
+
1385
+ .strand-radio--checked:hover:not(.strand-radio--disabled) .strand-radio__control {
1386
+ background: var(--strand-blue-vivid);
1387
+ border-color: var(--strand-blue-vivid);
1388
+ }
1389
+
1390
+ /* ── Label ── */
1391
+ .strand-radio__label {
1392
+ color: var(--strand-gray-900);
1393
+ }
1394
+
1395
+ /* ── Disabled ── */
1396
+ .strand-radio--disabled {
1397
+ opacity: 0.4;
1398
+ cursor: not-allowed;
1399
+ }
1400
+
1401
+ /* ── Reduced motion ── */
1402
+ @media (prefers-reduced-motion: reduce) {
1403
+ .strand-radio__control,
1404
+ .strand-radio__dot {
1405
+ transition: none;
1406
+ }
1407
+ }
1408
+
1409
+
1410
+ /* Section */
1411
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1412
+
1413
+ /* ── Base ── */
1414
+ .strand-section {
1415
+ width: 100%;
1416
+ }
1417
+
1418
+ /* ── Variants ── */
1419
+ .strand-section--standard {
1420
+ padding-block: clamp(4rem, 8vw, 8rem);
1421
+ }
1422
+
1423
+ .strand-section--hero {
1424
+ padding-block: clamp(6rem, 12vw, 12rem);
1425
+ }
1426
+
1427
+ /* ── Backgrounds ── */
1428
+ .strand-section--bg-primary {
1429
+ background-color: var(--strand-surface-primary);
1430
+ }
1431
+
1432
+ .strand-section--bg-elevated {
1433
+ background-color: var(--strand-surface-elevated);
1434
+ }
1435
+
1436
+ .strand-section--bg-recessed {
1437
+ background-color: var(--strand-surface-recessed);
1438
+ }
1439
+
1440
+
1441
+ /* Select */
1442
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1443
+
1444
+ /* ── Base ── */
1445
+ .strand-select {
1446
+ position: relative;
1447
+ display: inline-flex;
1448
+ align-items: center;
1449
+ background: var(--strand-surface-elevated);
1450
+ border: 1px solid var(--strand-gray-200);
1451
+ border-radius: var(--strand-radius-md);
1452
+ transition:
1453
+ border-color var(--strand-duration-fast) var(--strand-ease-out-quart),
1454
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-quart);
1455
+ }
1456
+
1457
+ .strand-select:focus-within {
1458
+ border-color: var(--strand-blue-primary);
1459
+ box-shadow: var(--strand-focus-ring);
1460
+ }
1461
+
1462
+ /* ── Field ── */
1463
+ .strand-select__field {
1464
+ flex: 1;
1465
+ width: 100%;
1466
+ padding: var(--strand-space-3) var(--strand-space-8) var(--strand-space-3) var(--strand-space-4);
1467
+ background: transparent;
1468
+ border: none;
1469
+ font-family: var(--strand-font-sans);
1470
+ font-size: var(--strand-text-base);
1471
+ color: var(--strand-gray-900);
1472
+ outline: none;
1473
+ appearance: none;
1474
+ cursor: pointer;
1475
+ }
1476
+
1477
+ /* ── Arrow indicator ── */
1478
+ .strand-select__arrow {
1479
+ position: absolute;
1480
+ right: var(--strand-space-3);
1481
+ top: 50%;
1482
+ transform: translateY(-50%);
1483
+ width: 0;
1484
+ height: 0;
1485
+ border-left: 5px solid transparent;
1486
+ border-right: 5px solid transparent;
1487
+ border-top: 5px solid var(--strand-gray-500);
1488
+ pointer-events: none;
1489
+ }
1490
+
1491
+ /* ── Error ── */
1492
+ .strand-select--error {
1493
+ border-color: var(--strand-red-alert);
1494
+ }
1495
+
1496
+ .strand-select--error:focus-within {
1497
+ border-color: var(--strand-red-alert);
1498
+ box-shadow: var(--strand-focus-ring-error);
1499
+ }
1500
+
1501
+ /* ── Disabled ── */
1502
+ .strand-select--disabled {
1503
+ opacity: 0.4;
1504
+ cursor: not-allowed;
1505
+ }
1506
+
1507
+ .strand-select--disabled .strand-select__field {
1508
+ cursor: not-allowed;
1509
+ }
1510
+
1511
+ /* ── Reduced motion ── */
1512
+ @media (prefers-reduced-motion: reduce) {
1513
+ .strand-select {
1514
+ transition: none;
1515
+ }
1516
+ }
1517
+
1518
+
1519
+ /* Skeleton */
1520
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1521
+
1522
+ /* ── Base ── */
1523
+ .strand-skeleton {
1524
+ display: block;
1525
+ background: var(--strand-gray-100);
1526
+ }
1527
+
1528
+ /* ── Shimmer ── */
1529
+ .strand-skeleton--shimmer {
1530
+ background: linear-gradient(
1531
+ 90deg,
1532
+ var(--strand-gray-100) 25%,
1533
+ var(--strand-gray-50) 50%,
1534
+ var(--strand-gray-100) 75%
1535
+ );
1536
+ background-size: 200% 100%;
1537
+ animation: strand-skeleton-shimmer 1.8s var(--strand-ease-in-out-sine) infinite;
1538
+ }
1539
+
1540
+ @keyframes strand-skeleton-shimmer {
1541
+ 0% {
1542
+ background-position: 200% 0;
1543
+ }
1544
+ 100% {
1545
+ background-position: -200% 0;
1546
+ }
1547
+ }
1548
+
1549
+ /* ── Text variant ── */
1550
+ .strand-skeleton--text {
1551
+ height: 1em;
1552
+ border-radius: var(--strand-radius-sm);
1553
+ }
1554
+
1555
+ /* ── Rectangle variant ── */
1556
+ .strand-skeleton--rectangle {
1557
+ border-radius: var(--strand-radius-md);
1558
+ }
1559
+
1560
+ /* ── Circle variant ── */
1561
+ .strand-skeleton--circle {
1562
+ border-radius: var(--strand-radius-full);
1563
+ }
1564
+
1565
+ /* ── Reduced motion ── */
1566
+ @media (prefers-reduced-motion: reduce) {
1567
+ .strand-skeleton--shimmer {
1568
+ animation: none;
1569
+ background: var(--strand-gray-100);
1570
+ }
1571
+ }
1572
+
1573
+
1574
+ /* Slider */
1575
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1576
+
1577
+ /* ── Base ── */
1578
+ .strand-slider {
1579
+ position: relative;
1580
+ display: flex;
1581
+ align-items: center;
1582
+ width: 100%;
1583
+ }
1584
+
1585
+ /* ── Field ── */
1586
+ .strand-slider__field {
1587
+ width: 100%;
1588
+ height: 6px;
1589
+ appearance: none;
1590
+ background: var(--strand-gray-200);
1591
+ border-radius: var(--strand-radius-full);
1592
+ outline: none;
1593
+ cursor: pointer;
1594
+ transition: background var(--strand-duration-fast) var(--strand-ease-out-quart);
1595
+ }
1596
+
1597
+ /* ── Thumb: Webkit ── */
1598
+ .strand-slider__field::-webkit-slider-thumb {
1599
+ appearance: none;
1600
+ width: 20px;
1601
+ height: 20px;
1602
+ background: var(--strand-blue-primary);
1603
+ border: 2px solid var(--strand-surface-elevated);
1604
+ border-radius: var(--strand-radius-full);
1605
+ cursor: pointer;
1606
+ box-shadow: var(--strand-elevation-1);
1607
+ transition:
1608
+ background var(--strand-duration-fast) var(--strand-ease-out-quart),
1609
+ transform var(--strand-duration-fast) var(--strand-ease-out-expo);
1610
+ }
1611
+
1612
+ .strand-slider__field:hover:not(:disabled)::-webkit-slider-thumb {
1613
+ background: var(--strand-blue-vivid);
1614
+ transform: scale(1.15);
1615
+ }
1616
+
1617
+ .strand-slider__field:active:not(:disabled)::-webkit-slider-thumb {
1618
+ background: var(--strand-blue-deep);
1619
+ transform: scale(1.05);
1620
+ }
1621
+
1622
+ /* ── Thumb: Firefox ── */
1623
+ .strand-slider__field::-moz-range-thumb {
1624
+ width: 20px;
1625
+ height: 20px;
1626
+ background: var(--strand-blue-primary);
1627
+ border: 2px solid var(--strand-surface-elevated);
1628
+ border-radius: var(--strand-radius-full);
1629
+ cursor: pointer;
1630
+ box-shadow: var(--strand-elevation-1);
1631
+ transition:
1632
+ background var(--strand-duration-fast) var(--strand-ease-out-quart),
1633
+ transform var(--strand-duration-fast) var(--strand-ease-out-expo);
1634
+ }
1635
+
1636
+ .strand-slider__field:hover:not(:disabled)::-moz-range-thumb {
1637
+ background: var(--strand-blue-vivid);
1638
+ transform: scale(1.15);
1639
+ }
1640
+
1641
+ .strand-slider__field:active:not(:disabled)::-moz-range-thumb {
1642
+ background: var(--strand-blue-deep);
1643
+ transform: scale(1.05);
1644
+ }
1645
+
1646
+ /* ── Track: Firefox ── */
1647
+ .strand-slider__field::-moz-range-track {
1648
+ height: 6px;
1649
+ background: var(--strand-gray-200);
1650
+ border-radius: var(--strand-radius-full);
1651
+ }
1652
+
1653
+ /* ── Focus ── */
1654
+ .strand-slider__field:focus-visible::-webkit-slider-thumb {
1655
+ box-shadow: var(--strand-focus-ring);
1656
+ }
1657
+
1658
+ .strand-slider__field:focus-visible::-moz-range-thumb {
1659
+ box-shadow: var(--strand-focus-ring);
1660
+ }
1661
+
1662
+ /* ── Disabled ── */
1663
+ .strand-slider--disabled {
1664
+ opacity: 0.4;
1665
+ cursor: not-allowed;
1666
+ }
1667
+
1668
+ .strand-slider--disabled .strand-slider__field {
1669
+ cursor: not-allowed;
1670
+ }
1671
+
1672
+ /* ── Reduced motion ── */
1673
+ @media (prefers-reduced-motion: reduce) {
1674
+ .strand-slider__field::-webkit-slider-thumb {
1675
+ transition: none;
1676
+ }
1677
+
1678
+ .strand-slider__field::-moz-range-thumb {
1679
+ transition: none;
1680
+ }
1681
+ }
1682
+
1683
+
1684
+ /* Spinner */
1685
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1686
+
1687
+ /* ── Base ── */
1688
+ .strand-spinner {
1689
+ display: inline-flex;
1690
+ align-items: center;
1691
+ justify-content: center;
1692
+ }
1693
+
1694
+ /* ── Ring ── */
1695
+ .strand-spinner__ring {
1696
+ display: block;
1697
+ border: 2px solid var(--strand-gray-200);
1698
+ border-top-color: var(--strand-blue-primary);
1699
+ border-radius: var(--strand-radius-full);
1700
+ animation: strand-spinner-rotate 0.8s linear infinite;
1701
+ }
1702
+
1703
+ /* ── Sizes ── */
1704
+ .strand-spinner--sm .strand-spinner__ring {
1705
+ width: 16px;
1706
+ height: 16px;
1707
+ }
1708
+
1709
+ .strand-spinner--md .strand-spinner__ring {
1710
+ width: 20px;
1711
+ height: 20px;
1712
+ }
1713
+
1714
+ .strand-spinner--lg .strand-spinner__ring {
1715
+ width: 32px;
1716
+ height: 32px;
1717
+ }
1718
+
1719
+ /* ── Animation ── */
1720
+ @keyframes strand-spinner-rotate {
1721
+ to {
1722
+ transform: rotate(360deg);
1723
+ }
1724
+ }
1725
+
1726
+ /* ── Screen reader only text ── */
1727
+ .strand-spinner__sr-only {
1728
+ position: absolute;
1729
+ width: 1px;
1730
+ height: 1px;
1731
+ padding: 0;
1732
+ margin: -1px;
1733
+ overflow: hidden;
1734
+ clip: rect(0, 0, 0, 0);
1735
+ white-space: nowrap;
1736
+ border: 0;
1737
+ }
1738
+
1739
+ /* ── Reduced motion ── */
1740
+ @media (prefers-reduced-motion: reduce) {
1741
+ .strand-spinner__ring {
1742
+ animation: none;
1743
+ border-style: dotted;
1744
+ }
1745
+ }
1746
+
1747
+
1748
+ /* Stack */
1749
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1750
+
1751
+ /* ── Base ── */
1752
+ .strand-stack {
1753
+ display: flex;
1754
+ max-width: 100%;
1755
+ box-sizing: border-box;
1756
+ }
1757
+
1758
+ .strand-stack > * {
1759
+ min-width: 0;
1760
+ }
1761
+
1762
+ /* ── Direction ── */
1763
+ .strand-stack--vertical {
1764
+ flex-direction: column;
1765
+ }
1766
+
1767
+ .strand-stack--horizontal {
1768
+ flex-direction: row;
1769
+ }
1770
+
1771
+ /* ── Alignment ── */
1772
+ .strand-stack--align-start {
1773
+ align-items: flex-start;
1774
+ }
1775
+
1776
+ .strand-stack--align-center {
1777
+ align-items: center;
1778
+ }
1779
+
1780
+ .strand-stack--align-end {
1781
+ align-items: flex-end;
1782
+ }
1783
+
1784
+ /* Default stretch handled by flexbox default */
1785
+
1786
+ /* ── Justification ── */
1787
+ .strand-stack--justify-start {
1788
+ justify-content: flex-start;
1789
+ }
1790
+
1791
+ .strand-stack--justify-center {
1792
+ justify-content: center;
1793
+ }
1794
+
1795
+ .strand-stack--justify-end {
1796
+ justify-content: flex-end;
1797
+ }
1798
+
1799
+ .strand-stack--justify-between {
1800
+ justify-content: space-between;
1801
+ }
1802
+
1803
+ .strand-stack--justify-around {
1804
+ justify-content: space-around;
1805
+ }
1806
+
1807
+ /* ── Wrap ── */
1808
+ .strand-stack--wrap {
1809
+ flex-wrap: wrap;
1810
+ }
1811
+
1812
+ /* ── Gap utilities ── */
1813
+ .strand-stack--gap-1 { gap: var(--strand-space-1); }
1814
+ .strand-stack--gap-2 { gap: var(--strand-space-2); }
1815
+ .strand-stack--gap-3 { gap: var(--strand-space-3); }
1816
+ .strand-stack--gap-4 { gap: var(--strand-space-4); }
1817
+ .strand-stack--gap-5 { gap: var(--strand-space-5); }
1818
+ .strand-stack--gap-6 { gap: var(--strand-space-6); }
1819
+ .strand-stack--gap-8 { gap: var(--strand-space-8); }
1820
+
1821
+
1822
+ /* Switch */
1823
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1824
+
1825
+ /* ── Base ── */
1826
+ .strand-switch {
1827
+ display: inline-flex;
1828
+ align-items: center;
1829
+ gap: var(--strand-space-2);
1830
+ cursor: pointer;
1831
+ user-select: none;
1832
+ font-family: var(--strand-font-sans);
1833
+ font-size: var(--strand-text-sm);
1834
+ color: var(--strand-gray-900);
1835
+ line-height: var(--strand-leading-snug);
1836
+ }
1837
+
1838
+ /* ── Track ── */
1839
+ .strand-switch__track {
1840
+ position: relative;
1841
+ display: inline-flex;
1842
+ align-items: center;
1843
+ width: 40px;
1844
+ height: 22px;
1845
+ padding: 0;
1846
+ border: 1px solid var(--strand-gray-200);
1847
+ border-radius: var(--strand-radius-full);
1848
+ background: var(--strand-gray-200);
1849
+ cursor: pointer;
1850
+ flex-shrink: 0;
1851
+ transition:
1852
+ background var(--strand-duration-fast) var(--strand-ease-out-quart),
1853
+ border-color var(--strand-duration-fast) var(--strand-ease-out-quart),
1854
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-quart);
1855
+ }
1856
+
1857
+ .strand-switch__track:focus-visible {
1858
+ border-color: var(--strand-blue-primary);
1859
+ box-shadow: var(--strand-focus-ring);
1860
+ outline: none;
1861
+ }
1862
+
1863
+ /* ── Thumb ── */
1864
+ .strand-switch__thumb {
1865
+ position: absolute;
1866
+ left: 2px;
1867
+ width: 16px;
1868
+ height: 16px;
1869
+ border-radius: var(--strand-radius-full);
1870
+ background: var(--strand-surface-elevated);
1871
+ box-shadow: var(--strand-elevation-1);
1872
+ transition: transform var(--strand-duration-fast) var(--strand-ease-out-expo);
1873
+ }
1874
+
1875
+ /* ── Checked ── */
1876
+ .strand-switch--checked .strand-switch__track {
1877
+ background: var(--strand-blue-primary);
1878
+ border-color: var(--strand-blue-primary);
1879
+ }
1880
+
1881
+ .strand-switch--checked .strand-switch__thumb {
1882
+ transform: translateX(18px);
1883
+ }
1884
+
1885
+ /* ── Hover ── */
1886
+ .strand-switch:hover:not(.strand-switch--disabled) .strand-switch__track {
1887
+ border-color: var(--strand-blue-indicator);
1888
+ }
1889
+
1890
+ .strand-switch--checked:hover:not(.strand-switch--disabled) .strand-switch__track {
1891
+ background: var(--strand-blue-vivid);
1892
+ border-color: var(--strand-blue-vivid);
1893
+ }
1894
+
1895
+ /* ── Label ── */
1896
+ .strand-switch__label {
1897
+ color: var(--strand-gray-900);
1898
+ }
1899
+
1900
+ /* ── Disabled ── */
1901
+ .strand-switch--disabled {
1902
+ opacity: 0.4;
1903
+ cursor: not-allowed;
1904
+ }
1905
+
1906
+ .strand-switch--disabled .strand-switch__track {
1907
+ cursor: not-allowed;
1908
+ }
1909
+
1910
+ /* ── Reduced motion ── */
1911
+ @media (prefers-reduced-motion: reduce) {
1912
+ .strand-switch__track,
1913
+ .strand-switch__thumb {
1914
+ transition: none;
1915
+ }
1916
+ }
1917
+
1918
+
1919
+ /* Table */
1920
+ /*! Strand UI | MIT License | dillingerstaffing.com */
1921
+
1922
+ /* ── Wrapper (responsive scroll) ── */
1923
+ .strand-table-wrapper {
1924
+ overflow-x: auto;
1925
+ -webkit-overflow-scrolling: touch;
1926
+ }
1927
+
1928
+ /* ── Table ── */
1929
+ .strand-table {
1930
+ width: 100%;
1931
+ border-collapse: collapse;
1932
+ border-spacing: 0;
1933
+ }
1934
+
1935
+ /* ── Header ── */
1936
+ .strand-table__th {
1937
+ padding: var(--strand-space-3) var(--strand-space-4);
1938
+ font-family: var(--strand-font-mono);
1939
+ font-size: var(--strand-text-xs);
1940
+ font-weight: var(--strand-weight-medium);
1941
+ letter-spacing: var(--strand-tracking-widest);
1942
+ text-transform: uppercase;
1943
+ color: var(--strand-gray-500);
1944
+ text-align: left;
1945
+ border-bottom: 1px solid var(--strand-gray-200);
1946
+ white-space: nowrap;
1947
+ }
1948
+
1949
+ /* ── Sort button ── */
1950
+ .strand-table__sort-btn {
1951
+ display: inline-flex;
1952
+ align-items: center;
1953
+ gap: var(--strand-space-1);
1954
+ padding: 0;
1955
+ border: none;
1956
+ background: none;
1957
+ font: inherit;
1958
+ color: inherit;
1959
+ letter-spacing: inherit;
1960
+ text-transform: inherit;
1961
+ cursor: pointer;
1962
+ white-space: nowrap;
1963
+ }
1964
+
1965
+ .strand-table__sort-btn:hover {
1966
+ color: var(--strand-gray-600);
1967
+ }
1968
+
1969
+ .strand-table__sort-btn:focus-visible {
1970
+ outline: 2px solid var(--strand-blue-primary);
1971
+ outline-offset: 2px;
1972
+ }
1973
+
1974
+ .strand-table__sort-indicator {
1975
+ font-size: var(--strand-text-xs);
1976
+ opacity: 0.6;
1977
+ }
1978
+
1979
+ /* ── Body ── */
1980
+ .strand-table__td {
1981
+ padding: var(--strand-space-3) var(--strand-space-4);
1982
+ font-family: var(--strand-font-sans);
1983
+ font-size: var(--strand-text-sm);
1984
+ color: var(--strand-gray-600);
1985
+ border-bottom: 1px solid var(--strand-gray-200);
1986
+ }
1987
+
1988
+ /* ── Row hover ── */
1989
+ .strand-table__row {
1990
+ transition: background var(--strand-duration-fast) var(--strand-ease-out-quart);
1991
+ }
1992
+
1993
+ .strand-table__row:hover {
1994
+ background: var(--strand-blue-glow);
1995
+ }
1996
+
1997
+ /* ── Reduced motion ── */
1998
+ @media (prefers-reduced-motion: reduce) {
1999
+ .strand-table__row {
2000
+ transition: none;
2001
+ }
2002
+ }
2003
+
2004
+
2005
+ /* Tabs */
2006
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2007
+
2008
+ /* ── Tab list ── */
2009
+ .strand-tabs [role="tablist"] {
2010
+ display: flex;
2011
+ gap: var(--strand-space-1);
2012
+ border-bottom: 1px solid var(--strand-gray-400);
2013
+ }
2014
+
2015
+ /* ── Tab button ── */
2016
+ .strand-tabs__tab {
2017
+ position: relative;
2018
+ padding: var(--strand-space-2) var(--strand-space-4);
2019
+ border: none;
2020
+ border-bottom: 2px solid transparent;
2021
+ background: none;
2022
+ font-family: var(--strand-font-sans);
2023
+ font-size: var(--strand-text-sm);
2024
+ font-weight: var(--strand-weight-medium);
2025
+ color: var(--strand-gray-500);
2026
+ cursor: pointer;
2027
+ transition:
2028
+ color var(--strand-duration-fast) var(--strand-ease-out-quart),
2029
+ border-color var(--strand-duration-fast) var(--strand-ease-out-expo);
2030
+ }
2031
+
2032
+ .strand-tabs__tab:hover {
2033
+ color: var(--strand-gray-600);
2034
+ }
2035
+
2036
+ .strand-tabs__tab:focus-visible {
2037
+ outline: 2px solid var(--strand-blue-primary);
2038
+ outline-offset: 2px;
2039
+ }
2040
+
2041
+ .strand-tabs__tab--active {
2042
+ color: var(--strand-blue-primary);
2043
+ border-bottom-color: var(--strand-blue-primary);
2044
+ }
2045
+
2046
+ /* ── Panel ── */
2047
+ .strand-tabs [role="tabpanel"] {
2048
+ padding: var(--strand-space-4) 0;
2049
+ }
2050
+
2051
+ /* ── Reduced motion ── */
2052
+ @media (prefers-reduced-motion: reduce) {
2053
+ .strand-tabs__tab {
2054
+ transition: none;
2055
+ }
2056
+ }
2057
+
2058
+
2059
+ /* Tag */
2060
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2061
+
2062
+ /* ── Base ── */
2063
+ .strand-tag {
2064
+ display: inline-flex;
2065
+ align-items: center;
2066
+ gap: var(--strand-space-1);
2067
+ padding: var(--strand-space-1) var(--strand-space-2);
2068
+ border-radius: var(--strand-radius-sm);
2069
+ font-family: var(--strand-font-sans);
2070
+ font-size: var(--strand-text-xs);
2071
+ font-weight: var(--strand-weight-medium);
2072
+ line-height: var(--strand-leading-snug);
2073
+ white-space: nowrap;
2074
+ border: 1px solid transparent;
2075
+ }
2076
+
2077
+ /* ── Solid variant ── */
2078
+ .strand-tag--solid.strand-tag--default {
2079
+ background: var(--strand-surface-recessed);
2080
+ color: var(--strand-gray-600);
2081
+ }
2082
+
2083
+ .strand-tag--solid.strand-tag--teal {
2084
+ background: rgba(20, 184, 166, 0.1);
2085
+ color: var(--strand-on-teal-tint);
2086
+ }
2087
+
2088
+ .strand-tag--solid.strand-tag--blue {
2089
+ background: var(--strand-blue-glow);
2090
+ color: var(--strand-blue-deep);
2091
+ }
2092
+
2093
+ .strand-tag--solid.strand-tag--amber {
2094
+ background: rgba(245, 158, 11, 0.1);
2095
+ color: var(--strand-on-amber-tint);
2096
+ }
2097
+
2098
+ .strand-tag--solid.strand-tag--red {
2099
+ background: rgba(239, 68, 68, 0.1);
2100
+ color: var(--strand-on-red-tint);
2101
+ }
2102
+
2103
+ /* ── Outlined variant ── */
2104
+ .strand-tag--outlined {
2105
+ background: transparent;
2106
+ }
2107
+
2108
+ .strand-tag--outlined.strand-tag--default {
2109
+ border-color: var(--strand-gray-200);
2110
+ color: var(--strand-gray-600);
2111
+ }
2112
+
2113
+ .strand-tag--outlined.strand-tag--teal {
2114
+ border-color: var(--strand-teal-vital);
2115
+ color: var(--strand-on-teal-tint);
2116
+ }
2117
+
2118
+ .strand-tag--outlined.strand-tag--blue {
2119
+ border-color: var(--strand-blue-primary);
2120
+ color: var(--strand-blue-deep);
2121
+ }
2122
+
2123
+ .strand-tag--outlined.strand-tag--amber {
2124
+ border-color: var(--strand-amber-caution);
2125
+ color: var(--strand-on-amber-tint);
2126
+ }
2127
+
2128
+ .strand-tag--outlined.strand-tag--red {
2129
+ border-color: var(--strand-red-alert);
2130
+ color: var(--strand-on-red-tint);
2131
+ }
2132
+
2133
+ /* ── Remove button ── */
2134
+ .strand-tag__remove {
2135
+ display: inline-flex;
2136
+ align-items: center;
2137
+ justify-content: center;
2138
+ padding: 0;
2139
+ border: none;
2140
+ background: none;
2141
+ color: currentColor;
2142
+ opacity: 0.6;
2143
+ cursor: pointer;
2144
+ border-radius: var(--strand-radius-sm);
2145
+ transition: opacity var(--strand-duration-fast) var(--strand-ease-out-quart);
2146
+ }
2147
+
2148
+ .strand-tag__remove:hover {
2149
+ opacity: 1;
2150
+ }
2151
+
2152
+ /* ── Reduced motion ── */
2153
+ @media (prefers-reduced-motion: reduce) {
2154
+ .strand-tag__remove {
2155
+ transition: none;
2156
+ }
2157
+ }
2158
+
2159
+
2160
+ /* Textarea */
2161
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2162
+
2163
+ /* ── Base ── */
2164
+ .strand-textarea {
2165
+ position: relative;
2166
+ display: flex;
2167
+ flex-direction: column;
2168
+ background: var(--strand-surface-elevated);
2169
+ border: 1px solid var(--strand-gray-200);
2170
+ border-radius: var(--strand-radius-md);
2171
+ transition:
2172
+ border-color var(--strand-duration-fast) var(--strand-ease-out-quart),
2173
+ box-shadow var(--strand-duration-fast) var(--strand-ease-out-quart);
2174
+ }
2175
+
2176
+ .strand-textarea:focus-within {
2177
+ border-color: var(--strand-blue-primary);
2178
+ box-shadow: var(--strand-focus-ring);
2179
+ }
2180
+
2181
+ /* ── Field ── */
2182
+ .strand-textarea__field {
2183
+ width: 100%;
2184
+ min-height: 80px;
2185
+ padding: var(--strand-space-3) var(--strand-space-4);
2186
+ background: transparent;
2187
+ border: none;
2188
+ font-family: var(--strand-font-sans);
2189
+ font-size: var(--strand-text-base);
2190
+ color: var(--strand-gray-900);
2191
+ outline: none;
2192
+ resize: vertical;
2193
+ line-height: var(--strand-leading-normal);
2194
+ }
2195
+
2196
+ .strand-textarea__field::placeholder {
2197
+ color: var(--strand-gray-400);
2198
+ }
2199
+
2200
+ /* ── Auto-resize ── */
2201
+ .strand-textarea--auto-resize .strand-textarea__field {
2202
+ resize: none;
2203
+ overflow: hidden;
2204
+ }
2205
+
2206
+ /* ── Character count ── */
2207
+ .strand-textarea__count {
2208
+ align-self: flex-end;
2209
+ padding: var(--strand-space-1) var(--strand-space-3) var(--strand-space-2);
2210
+ font-family: var(--strand-font-sans);
2211
+ font-size: var(--strand-text-xs);
2212
+ color: var(--strand-gray-500);
2213
+ }
2214
+
2215
+ /* ── Error ── */
2216
+ .strand-textarea--error {
2217
+ border-color: var(--strand-red-alert);
2218
+ }
2219
+
2220
+ .strand-textarea--error:focus-within {
2221
+ border-color: var(--strand-red-alert);
2222
+ box-shadow: var(--strand-focus-ring-error);
2223
+ }
2224
+
2225
+ /* ── Disabled ── */
2226
+ .strand-textarea--disabled {
2227
+ opacity: 0.4;
2228
+ cursor: not-allowed;
2229
+ }
2230
+
2231
+ .strand-textarea--disabled .strand-textarea__field {
2232
+ cursor: not-allowed;
2233
+ }
2234
+
2235
+ /* ── Reduced motion ── */
2236
+ @media (prefers-reduced-motion: reduce) {
2237
+ .strand-textarea {
2238
+ transition: none;
2239
+ }
2240
+ }
2241
+
2242
+
2243
+ /* Toast */
2244
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2245
+
2246
+ /* ── Container ── */
2247
+ .strand-toast__container {
2248
+ position: fixed;
2249
+ right: var(--strand-space-6);
2250
+ bottom: var(--strand-space-6);
2251
+ z-index: 1100;
2252
+ display: flex;
2253
+ flex-direction: column-reverse;
2254
+ gap: var(--strand-space-3);
2255
+ pointer-events: none;
2256
+ }
2257
+
2258
+ /* ── Toast ── */
2259
+ .strand-toast {
2260
+ display: flex;
2261
+ align-items: center;
2262
+ justify-content: space-between;
2263
+ min-width: 280px;
2264
+ max-width: 420px;
2265
+ padding: var(--strand-space-4) var(--strand-space-5);
2266
+ background: var(--strand-surface-elevated);
2267
+ border-radius: var(--strand-radius-lg);
2268
+ border-left: 4px solid transparent;
2269
+ box-shadow: var(--strand-elevation-3);
2270
+ font-family: var(--strand-font-sans);
2271
+ font-size: var(--strand-text-sm);
2272
+ pointer-events: auto;
2273
+ animation: strand-toast-in var(--strand-duration-normal) var(--strand-ease-out-expo);
2274
+ }
2275
+
2276
+ /* ── Status accents ── */
2277
+ .strand-toast--info {
2278
+ border-left-color: var(--strand-blue-primary);
2279
+ }
2280
+
2281
+ .strand-toast--success {
2282
+ border-left-color: var(--strand-green-positive);
2283
+ }
2284
+
2285
+ .strand-toast--warning {
2286
+ border-left-color: var(--strand-amber-caution);
2287
+ }
2288
+
2289
+ .strand-toast--error {
2290
+ border-left-color: var(--strand-red-alert);
2291
+ }
2292
+
2293
+ /* ── Message ── */
2294
+ .strand-toast__message {
2295
+ flex: 1;
2296
+ min-width: 0;
2297
+ color: var(--strand-gray-900);
2298
+ }
2299
+
2300
+ /* ── Dismiss button ── */
2301
+ .strand-toast__dismiss {
2302
+ flex-shrink: 0;
2303
+ display: inline-flex;
2304
+ align-items: center;
2305
+ justify-content: center;
2306
+ width: 24px;
2307
+ height: 24px;
2308
+ margin-left: var(--strand-space-3);
2309
+ padding: 0;
2310
+ border: none;
2311
+ border-radius: var(--strand-radius-md);
2312
+ background: transparent;
2313
+ color: var(--strand-gray-500);
2314
+ font-size: var(--strand-text-base);
2315
+ cursor: pointer;
2316
+ transition: background var(--strand-duration-fast) var(--strand-ease-out-quart),
2317
+ color var(--strand-duration-fast) var(--strand-ease-out-quart);
2318
+ }
2319
+
2320
+ .strand-toast__dismiss:hover {
2321
+ background: var(--strand-gray-200);
2322
+ color: var(--strand-gray-600);
2323
+ }
2324
+
2325
+ /* ── Animations ── */
2326
+ @keyframes strand-toast-in {
2327
+ from {
2328
+ opacity: 0;
2329
+ transform: translateY(8px);
2330
+ }
2331
+ to {
2332
+ opacity: 1;
2333
+ transform: translateY(0);
2334
+ }
2335
+ }
2336
+
2337
+ /* ── Reduced motion ── */
2338
+ @media (prefers-reduced-motion: reduce) {
2339
+ .strand-toast {
2340
+ animation: none;
2341
+ }
2342
+
2343
+ .strand-toast__dismiss {
2344
+ transition: none;
2345
+ }
2346
+ }
2347
+
2348
+
2349
+ /* Tooltip */
2350
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2351
+
2352
+ /* ── Wrapper ── */
2353
+ .strand-tooltip__wrapper {
2354
+ position: relative;
2355
+ display: inline-flex;
2356
+ }
2357
+
2358
+ /* ── Tooltip ── */
2359
+ .strand-tooltip {
2360
+ position: absolute;
2361
+ z-index: 1200;
2362
+ padding: var(--strand-space-1) var(--strand-space-2);
2363
+ background: var(--strand-gray-900);
2364
+ color: var(--strand-on-blue-primary);
2365
+ font-family: var(--strand-font-sans);
2366
+ font-size: var(--strand-text-xs);
2367
+ border-radius: var(--strand-radius-md);
2368
+ white-space: nowrap;
2369
+ pointer-events: none;
2370
+ opacity: 0;
2371
+ transition: opacity var(--strand-duration-fast) var(--strand-ease-out-quart);
2372
+ }
2373
+
2374
+ .strand-tooltip--visible {
2375
+ opacity: 1;
2376
+ }
2377
+
2378
+ /* ── Positions ── */
2379
+ .strand-tooltip--top {
2380
+ bottom: 100%;
2381
+ left: 50%;
2382
+ transform: translateX(-50%);
2383
+ margin-bottom: var(--strand-space-2);
2384
+ }
2385
+
2386
+ .strand-tooltip--bottom {
2387
+ top: 100%;
2388
+ left: 50%;
2389
+ transform: translateX(-50%);
2390
+ margin-top: var(--strand-space-2);
2391
+ }
2392
+
2393
+ .strand-tooltip--left {
2394
+ right: 100%;
2395
+ top: 50%;
2396
+ transform: translateY(-50%);
2397
+ margin-right: var(--strand-space-2);
2398
+ }
2399
+
2400
+ .strand-tooltip--right {
2401
+ left: 100%;
2402
+ top: 50%;
2403
+ transform: translateY(-50%);
2404
+ margin-left: var(--strand-space-2);
2405
+ }
2406
+
2407
+ /* ── Reduced motion ── */
2408
+ @media (prefers-reduced-motion: reduce) {
2409
+ .strand-tooltip {
2410
+ transition: none;
2411
+ }
2412
+ }
2413
+
2414
+
2415
+ /* Static */
2416
+ /*! Strand UI | MIT License | dillingerstaffing.com */
2417
+
2418
+ /* ── Presentation mode ──
2419
+ Add .strand-static to a parent element to render components
2420
+ at full visual fidelity without interaction.
2421
+ Use for documentation, showcases, and screenshots. */
2422
+
2423
+ .strand-static {
2424
+ pointer-events: none;
2425
+ }
2426
+
2427
+ .strand-static [disabled],
2428
+ .strand-static [aria-disabled="true"] {
2429
+ opacity: 1;
2430
+ cursor: default;
2431
+ }
2432
+
2433
+ .strand-static .strand-btn:disabled {
2434
+ opacity: 1;
2435
+ cursor: default;
2436
+ }
2437
+
2438
+ .strand-static .strand-toast {
2439
+ position: static;
2440
+ }
2441
+
2442
+ .strand-static .strand-tooltip {
2443
+ position: static;
2444
+ }
2445
+
2446
+ .strand-static *,
2447
+ .strand-static *::before,
2448
+ .strand-static *::after {
2449
+ transition: none !important;
2450
+ animation: none !important;
2451
+ }
2452
+
2453
+ /* ── Recessed viewport ──
2454
+ The instrument viewport sits below the card surface.
2455
+ Use for component previews, showcases, and documentation. */
2456
+
2457
+ .strand-viewport {
2458
+ background: var(--strand-surface-recessed);
2459
+ box-shadow: inset 0 1px 3px rgba(15, 23, 42, 0.06);
2460
+ border-radius: var(--strand-radius-lg);
2461
+ padding: var(--strand-space-6);
2462
+ }
2463
+
2464
+