@invisibleloop/pulse 0.20.11 → 0.20.20

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 (266) hide show
  1. package/package.json +6 -5
  2. package/public/.pulse-ui-version +1 -1
  3. package/scripts/build.js +26 -0
  4. package/scripts/release-version.js +17 -8
  5. package/scripts/strip-server.test.js +60 -0
  6. package/src/agent/checklist.md +8 -12
  7. package/src/agent/commands/pulse-start.md +2 -0
  8. package/src/agent/commands/verify.md +30 -8
  9. package/src/agent/guide-components.md +7 -25
  10. package/src/agent/guide-routing.md +0 -12
  11. package/src/agent/guide-server.md +102 -1
  12. package/src/agent/guide-spec.md +8 -1
  13. package/src/agent/guide-styles.md +23 -0
  14. package/src/agent/identity.md +9 -0
  15. package/src/agent/workflow.md +4 -23
  16. package/src/cli/check-bundles.js +113 -0
  17. package/src/cli/check-bundles.test.js +137 -0
  18. package/src/cli/cli.test.js +105 -0
  19. package/src/cli/dev.js +48 -3
  20. package/src/cli/diagnose.js +105 -0
  21. package/src/cli/diagnose.test.js +124 -0
  22. package/src/cli/discover.js +9 -2
  23. package/src/cli/index.js +171 -9
  24. package/src/cli/process-utils.js +57 -0
  25. package/src/cli/process-utils.test.js +114 -0
  26. package/src/cli/review.js +391 -0
  27. package/src/cli/review.test.js +143 -0
  28. package/src/cli/scaffold.js +9 -4
  29. package/src/cli/stamp.js +102 -0
  30. package/src/cli/stamp.test.js +149 -0
  31. package/src/cli/start.js +15 -2
  32. package/src/cli/validate.js +184 -0
  33. package/src/cli/validate.test.js +153 -0
  34. package/src/mcp/mcp.test.js +261 -30
  35. package/src/mcp/server.js +207 -515
  36. package/src/mcp/validate-worker.js +18 -1
  37. package/src/runtime/index.js +144 -11
  38. package/src/runtime/runtime.test.js +199 -0
  39. package/src/runtime/ssr.js +13 -6
  40. package/src/runtime/ssr.test.js +31 -0
  41. package/src/server/index.js +162 -9
  42. package/src/server/server.test.js +225 -2
  43. package/src/spec/schema.js +1 -1
  44. package/src/ui/index.js +0 -5
  45. package/src/ui/ui.test.js +0 -75
  46. package/types/ui.d.ts +0 -21
  47. package/.claude/commands/build-page.md +0 -63
  48. package/.claude/commands/new-doc-page.md +0 -45
  49. package/.claude/commands/pulse-start.md +0 -11
  50. package/.claude/commands/pulse-stop.md +0 -5
  51. package/.claude/commands/verify.md +0 -118
  52. package/.claude/pulse-checklist.md +0 -189
  53. package/.github/workflows/ci.yml +0 -25
  54. package/.github/workflows/publish.yml +0 -45
  55. package/.pulse/load-reports/home/1773432711417.json +0 -22
  56. package/.pulse-verified +0 -1
  57. package/AGENTS.md +0 -697
  58. package/CLAUDE.md +0 -697
  59. package/README.md +0 -95
  60. package/benchmark/public/dist/counter.boot-PO6SNSJZ.js +0 -8
  61. package/benchmark/public/dist/home.boot-YK6VAEQI.js +0 -6
  62. package/benchmark/public/dist/manifest.json +0 -5
  63. package/benchmark/public/dist/runtime-5Y7ESAIB.js +0 -2
  64. package/benchmark/public/dist/runtime-KO4BHUQ3.js +0 -49
  65. package/benchmark/results/2026-03-27-09-20.json +0 -188
  66. package/benchmark/results/2026-03-27-09-21.json +0 -188
  67. package/benchmark/results/2026-03-27-09-29.json +0 -188
  68. package/benchmark/results/2026-03-27-10-14.json +0 -188
  69. package/benchmark/results/2026-03-27-10-18.json +0 -232
  70. package/benchmark/src/pages/counter.js +0 -37
  71. package/benchmark/src/pages/home.js +0 -21
  72. package/docs/.claude/commands/pulse-build.md +0 -7
  73. package/docs/.claude/commands/pulse-dev.md +0 -7
  74. package/docs/.claude/commands/pulse-start.md +0 -9
  75. package/docs/.claude/commands/pulse-stop.md +0 -5
  76. package/docs/.claude/commands/verify.md +0 -84
  77. package/docs/.claude/coverage-check.js +0 -196
  78. package/docs/.claude/pulse-checklist.md +0 -189
  79. package/docs/public/.pulse-ui-version +0 -1
  80. package/docs/public/andypixel.css +0 -237
  81. package/docs/public/bookworms.css +0 -422
  82. package/docs/public/coutumes.css +0 -561
  83. package/docs/public/docs.css +0 -2388
  84. package/docs/public/favicon.svg +0 -4
  85. package/docs/public/home-brut.css +0 -982
  86. package/docs/public/images/bookworms/hero-books.jpg +0 -0
  87. package/docs/public/images/bookworms/how-we-read-now.jpg +0 -0
  88. package/docs/public/images/bookworms/lantern-keepers.jpg +0 -0
  89. package/docs/public/images/bookworms/provincial-bookseller.jpg +0 -0
  90. package/docs/public/images/journey/178.jpg +0 -0
  91. package/docs/public/images/journey/29.jpg +0 -0
  92. package/docs/public/images/retrowheels/hero.jpg +0 -0
  93. package/docs/public/images/shop/devbook-pro.jpg +0 -0
  94. package/docs/public/images/suzukibento/1015.jpg +0 -0
  95. package/docs/public/images/suzukibento/1025.jpg +0 -0
  96. package/docs/public/images/suzukibento/1043.jpg +0 -0
  97. package/docs/public/images/suzukibento/1059.jpg +0 -0
  98. package/docs/public/images/suzukibento/1062.jpg +0 -0
  99. package/docs/public/images/suzukibento/1084.jpg +0 -0
  100. package/docs/public/images/swish/1469334031218-e382a71b716b.jpg +0 -0
  101. package/docs/public/images/swish/1483985988355-763728e1935b.jpg +0 -0
  102. package/docs/public/images/swish/1485518882345-15568b007407.jpg +0 -0
  103. package/docs/public/images/swish/1490481651871-ab68de25d43d.jpg +0 -0
  104. package/docs/public/images/swish/1496747611176-843222e1e57c.jpg +0 -0
  105. package/docs/public/images/swish/1502716119720-b23a93e5fe1b.jpg +0 -0
  106. package/docs/public/images/swish/1539109136881-3be0616acf4b.jpg +0 -0
  107. package/docs/public/images/swish/1551803091-e20673f15770.jpg +0 -0
  108. package/docs/public/images/swish/1558769132-cb1aea458c5e.jpg +0 -0
  109. package/docs/public/images/swish/1572804013309-59a88b7e92f1.jpg +0 -0
  110. package/docs/public/img/heic1501a.jpg +0 -0
  111. package/docs/public/img/placeholder-landscape.svg +0 -18
  112. package/docs/public/img/placeholder-square.svg +0 -14
  113. package/docs/public/img/placeholder-tall.svg +0 -22
  114. package/docs/public/journey.css +0 -528
  115. package/docs/public/menu.js +0 -327
  116. package/docs/public/pulse-ui.css +0 -3028
  117. package/docs/public/pulse-ui.js +0 -257
  118. package/docs/public/retrowheels.css +0 -425
  119. package/docs/public/shop.css +0 -269
  120. package/docs/public/sparkys.css +0 -382
  121. package/docs/public/suzukibento.css +0 -517
  122. package/docs/public/swish.css +0 -394
  123. package/docs/public/theme.css +0 -52
  124. package/docs/public/themes/lumio.css +0 -50
  125. package/docs/public/themes/observatory.css +0 -104
  126. package/docs/server.js +0 -161
  127. package/docs/src/lib/component-page.js +0 -49
  128. package/docs/src/lib/highlight.js +0 -2
  129. package/docs/src/lib/layout.js +0 -190
  130. package/docs/src/lib/metrics-store.js +0 -6
  131. package/docs/src/lib/nav.js +0 -171
  132. package/docs/src/lib/stats.js +0 -81
  133. package/docs/src/pages/accessibility.js +0 -157
  134. package/docs/src/pages/actions.js +0 -194
  135. package/docs/src/pages/auth.js +0 -176
  136. package/docs/src/pages/caching.js +0 -95
  137. package/docs/src/pages/components/accordion.js +0 -48
  138. package/docs/src/pages/components/alert.js +0 -35
  139. package/docs/src/pages/components/app-badge.js +0 -41
  140. package/docs/src/pages/components/avatar.js +0 -35
  141. package/docs/src/pages/components/badge.js +0 -36
  142. package/docs/src/pages/components/breadcrumbs.js +0 -94
  143. package/docs/src/pages/components/button.js +0 -84
  144. package/docs/src/pages/components/card.js +0 -225
  145. package/docs/src/pages/components/charts.js +0 -283
  146. package/docs/src/pages/components/checkbox.js +0 -129
  147. package/docs/src/pages/components/cluster.js +0 -47
  148. package/docs/src/pages/components/container.js +0 -40
  149. package/docs/src/pages/components/cta.js +0 -54
  150. package/docs/src/pages/components/divider.js +0 -37
  151. package/docs/src/pages/components/empty.js +0 -36
  152. package/docs/src/pages/components/feature.js +0 -60
  153. package/docs/src/pages/components/fieldset.js +0 -65
  154. package/docs/src/pages/components/fileupload.js +0 -128
  155. package/docs/src/pages/components/footer.js +0 -58
  156. package/docs/src/pages/components/grid.js +0 -169
  157. package/docs/src/pages/components/heading.js +0 -107
  158. package/docs/src/pages/components/hero.js +0 -123
  159. package/docs/src/pages/components/icons.js +0 -410
  160. package/docs/src/pages/components/image.js +0 -71
  161. package/docs/src/pages/components/input.js +0 -51
  162. package/docs/src/pages/components/media.js +0 -51
  163. package/docs/src/pages/components/modal.js +0 -111
  164. package/docs/src/pages/components/nav.js +0 -136
  165. package/docs/src/pages/components/phone-frame.js +0 -74
  166. package/docs/src/pages/components/progress.js +0 -102
  167. package/docs/src/pages/components/prose.js +0 -111
  168. package/docs/src/pages/components/pullquote.js +0 -71
  169. package/docs/src/pages/components/radio.js +0 -194
  170. package/docs/src/pages/components/rating.js +0 -106
  171. package/docs/src/pages/components/search.js +0 -61
  172. package/docs/src/pages/components/section.js +0 -98
  173. package/docs/src/pages/components/segmented.js +0 -121
  174. package/docs/src/pages/components/select.js +0 -45
  175. package/docs/src/pages/components/slider.js +0 -115
  176. package/docs/src/pages/components/spinner.js +0 -73
  177. package/docs/src/pages/components/stack.js +0 -48
  178. package/docs/src/pages/components/stat.js +0 -55
  179. package/docs/src/pages/components/stepper.js +0 -66
  180. package/docs/src/pages/components/table.js +0 -45
  181. package/docs/src/pages/components/textarea.js +0 -31
  182. package/docs/src/pages/components/toggle.js +0 -84
  183. package/docs/src/pages/components/tooltip.js +0 -48
  184. package/docs/src/pages/components.js +0 -200
  185. package/docs/src/pages/config.js +0 -193
  186. package/docs/src/pages/constraints.js +0 -100
  187. package/docs/src/pages/deploy.js +0 -233
  188. package/docs/src/pages/error-pages.js +0 -99
  189. package/docs/src/pages/extending.js +0 -198
  190. package/docs/src/pages/faq.js +0 -99
  191. package/docs/src/pages/forms.js +0 -129
  192. package/docs/src/pages/getting-started.js +0 -147
  193. package/docs/src/pages/guard.js +0 -120
  194. package/docs/src/pages/home.js +0 -350
  195. package/docs/src/pages/how-it-works.js +0 -244
  196. package/docs/src/pages/hydration.js +0 -108
  197. package/docs/src/pages/images.js +0 -120
  198. package/docs/src/pages/markdown.js +0 -156
  199. package/docs/src/pages/meta.js +0 -193
  200. package/docs/src/pages/mutations.js +0 -107
  201. package/docs/src/pages/navigation.js +0 -85
  202. package/docs/src/pages/performance.js +0 -157
  203. package/docs/src/pages/persist.js +0 -89
  204. package/docs/src/pages/project-structure.js +0 -91
  205. package/docs/src/pages/prompt-examples.js +0 -186
  206. package/docs/src/pages/raw-responses.js +0 -122
  207. package/docs/src/pages/routing.js +0 -120
  208. package/docs/src/pages/server-api.js +0 -291
  209. package/docs/src/pages/server-data.js +0 -203
  210. package/docs/src/pages/slash-commands.js +0 -55
  211. package/docs/src/pages/spec.js +0 -207
  212. package/docs/src/pages/state.js +0 -102
  213. package/docs/src/pages/store.js +0 -203
  214. package/docs/src/pages/streaming.js +0 -107
  215. package/docs/src/pages/stripe.js +0 -194
  216. package/docs/src/pages/supabase.js +0 -324
  217. package/docs/src/pages/templates/andypixel.js +0 -260
  218. package/docs/src/pages/templates/blog-post.js +0 -226
  219. package/docs/src/pages/templates/bookworms.js +0 -227
  220. package/docs/src/pages/templates/coutumes.js +0 -237
  221. package/docs/src/pages/templates/journey.js +0 -186
  222. package/docs/src/pages/templates/mobile-app.js +0 -371
  223. package/docs/src/pages/templates/retrowheels.js +0 -355
  224. package/docs/src/pages/templates/shop.js +0 -268
  225. package/docs/src/pages/templates/sparkys.js +0 -264
  226. package/docs/src/pages/templates/suzukibento.js +0 -200
  227. package/docs/src/pages/templates/swish.js +0 -313
  228. package/docs/src/pages/templates.js +0 -534
  229. package/docs/src/pages/testing.js +0 -199
  230. package/docs/src/pages/validation.js +0 -138
  231. package/examples/.claude/commands/pulse-build.md +0 -7
  232. package/examples/.claude/commands/pulse-dev.md +0 -7
  233. package/examples/.claude/commands/pulse-start.md +0 -9
  234. package/examples/.claude/commands/pulse-stop.md +0 -5
  235. package/examples/.claude/commands/verify.md +0 -84
  236. package/examples/.claude/coverage-check.js +0 -196
  237. package/examples/.claude/pulse-checklist.md +0 -189
  238. package/examples/andypixel.css +0 -237
  239. package/examples/andypixel.js +0 -258
  240. package/examples/bookworms.css +0 -422
  241. package/examples/bookworms.js +0 -225
  242. package/examples/contact.js +0 -166
  243. package/examples/counter.js +0 -94
  244. package/examples/dev.server.js +0 -110
  245. package/examples/examples.test.js +0 -394
  246. package/examples/journey.css +0 -528
  247. package/examples/journey.js +0 -186
  248. package/examples/pricing.js +0 -262
  249. package/examples/products.js +0 -190
  250. package/examples/public/.pulse-ui-version +0 -1
  251. package/examples/public/pulse-ui.css +0 -3028
  252. package/examples/public/pulse-ui.js +0 -257
  253. package/examples/quiz.js +0 -208
  254. package/examples/retrowheels.css +0 -425
  255. package/examples/retrowheels.js +0 -353
  256. package/examples/shared.js +0 -84
  257. package/examples/suzukibento.css +0 -513
  258. package/examples/suzukibento.js +0 -200
  259. package/examples/swish.css +0 -394
  260. package/examples/swish.js +0 -311
  261. package/examples/todos.js +0 -162
  262. package/src/ui/fieldset.js +0 -37
  263. package/src/ui/phone-frame.js +0 -40
  264. package/src/ui/search.js +0 -78
  265. package/src/ui/segmented.js +0 -50
  266. package/src/ui/tooltip.js +0 -28
@@ -1,3028 +0,0 @@
1
- /**
2
- * Pulse UI — Component stylesheet
3
- *
4
- * Import this file in your page spec:
5
- * meta: { styles: ['/pulse-ui.css', '/app.css'] }
6
- *
7
- * Theming: override these custom properties in :root in your app.css.
8
- * Do not edit this file — extend via new CSS modifier classes only.
9
- *
10
- * Token fallback chain: project token → ui default
11
- * e.g. --ui-accent falls back to --accent, then to a hardcoded default.
12
- */
13
-
14
- /* ─── UI tokens ─────────────────────────────────────────────────────────────
15
- All component styles reference --ui-* tokens only.
16
- Override these in :root to retheme the entire library at once. */
17
- :root {
18
- --ui-bg: var(--bg, #0d0d10);
19
- --ui-surface: var(--surface, #111116);
20
- --ui-surface-2: var(--surface-2, #18181f);
21
- --ui-border: var(--border, #38383f);
22
- --ui-text: var(--text, #e2e2ea);
23
- --ui-muted: var(--muted, #9090a0);
24
- --ui-accent: var(--accent, #9b8dff);
25
- --ui-accent-hover: var(--accent-hover, #b5aaff);
26
- --ui-accent-dim: var(--accent-dim, rgba(155,141,255,.12));
27
- --ui-accent-text: var(--accent-text, #0d0a20);
28
- /* Inline code in dark theme — accent passes WCAG AA on surface-2 by default */
29
- --ui-code-color: var(--code-color, var(--ui-accent));
30
- --ui-green: var(--green, #3dd68c);
31
- --ui-green-dim: rgba(61, 214, 140, .12);
32
- --ui-red: var(--red, #ff6b6b);
33
- --ui-red-dim: rgba(255, 107, 107, .12);
34
- --ui-yellow: #f5a623;
35
- --ui-yellow-dim: rgba(245, 166, 35, .12);
36
- --ui-blue: #60a5fa;
37
- --ui-blue-dim: rgba( 96, 165, 250, .12);
38
- --ui-radius: var(--radius, 8px);
39
- --ui-radius-sm: 4px;
40
- --ui-font: var(--font, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif);
41
- --ui-font-display: var(--font-display, var(--ui-font));
42
- --ui-mono: var(--mono, 'Fira Code', 'Cascadia Code', monospace);
43
- --ui-letter-spacing-display: var(--letter-spacing-display, -0.025em);
44
-
45
- /* Touch target minimum per WCAG 2.5.5 */
46
- --ui-touch-min: 44px;
47
-
48
- /* ── Spacing scale ── */
49
- --ui-space-1: 0.25rem; /* 4px */
50
- --ui-space-2: 0.5rem; /* 8px */
51
- --ui-space-3: 0.75rem; /* 12px */
52
- --ui-space-4: 1rem; /* 16px */
53
- --ui-space-5: 1.25rem; /* 20px */
54
- --ui-space-6: 1.5rem; /* 24px */
55
- --ui-space-8: 2rem; /* 32px */
56
- --ui-space-10: 2.5rem; /* 40px */
57
- --ui-space-12: 3rem; /* 48px */
58
- --ui-space-16: 4rem; /* 64px */
59
- --ui-space-20: 5rem; /* 80px */
60
- --ui-space-24: 6rem; /* 96px */
61
-
62
- /* ── Type scale ── */
63
- --ui-text-xs: 0.75rem; /* 12px */
64
- --ui-text-sm: 0.875rem; /* 14px */
65
- --ui-text-base: 1rem; /* 16px */
66
- --ui-text-lg: 1.125rem; /* 18px */
67
- --ui-text-xl: 1.25rem; /* 20px */
68
- --ui-text-2xl: 1.5rem; /* 24px */
69
- --ui-text-3xl: 1.875rem; /* 30px */
70
- --ui-text-4xl: 2.25rem; /* 36px */
71
- }
72
-
73
- /* ─── Base reset ─────────────────────────────────────────────────────────────
74
- Apply the dark background and text colour to the document root so the page
75
- background matches the component surface colours out of the box.
76
- Projects can opt into a light theme via meta.theme: 'light' (sets
77
- data-theme="light" on <body>) or override :root tokens in app.css. */
78
- *, *::before, *::after { box-sizing: border-box; }
79
- h1, h2, h3, h4, h5, h6, p, ul, ol, li { margin: 0; }
80
- ul, ol { list-style: none; }
81
-
82
- html, body {
83
- margin: 0;
84
- background-color: var(--ui-bg);
85
- color: var(--ui-text);
86
- font-family: var(--ui-font);
87
- min-height: 100dvh;
88
- }
89
-
90
- /* ─── Focus style ────────────────────────────────────────────────────────────
91
- Applied via :focus-visible to avoid showing on mouse click.
92
- All interactive components inherit this. */
93
- .ui-btn:focus-visible,
94
- .ui-input:focus-visible,
95
- .ui-select:focus-visible,
96
- .ui-textarea:focus-visible {
97
- outline: 2px solid var(--ui-accent);
98
- outline-offset: 2px;
99
- }
100
-
101
- /* ─── Button ─────────────────────────────────────────────────────────────── */
102
- .ui-btn {
103
- box-sizing: border-box;
104
- display: inline-flex;
105
- align-items: center;
106
- justify-content: center;
107
- gap: .45rem;
108
- padding: 0 1.2rem;
109
- height: var(--ui-touch-min);
110
- min-width: var(--ui-touch-min);
111
- border: 1px solid transparent;
112
- border-radius: var(--ui-radius);
113
- font-family: var(--ui-font);
114
- font-size: .9rem;
115
- font-weight: 600;
116
- line-height: 1;
117
- text-decoration: none;
118
- white-space: nowrap;
119
- cursor: pointer;
120
- transition: background .15s, color .15s, border-color .15s, opacity .15s;
121
- -webkit-font-smoothing: antialiased;
122
- }
123
-
124
- /* Variants */
125
- .ui-btn--primary {
126
- background: var(--ui-accent);
127
- color: var(--ui-bg);
128
- }
129
- .ui-btn--primary:hover:not(.ui-btn--disabled):not([disabled]) {
130
- background: var(--ui-accent-hover);
131
- }
132
-
133
- .ui-btn--secondary {
134
- background: var(--ui-surface-2);
135
- color: var(--ui-text);
136
- border-color: var(--ui-muted);
137
- }
138
- .ui-btn--secondary:hover:not(.ui-btn--disabled):not([disabled]) {
139
- background: var(--ui-surface);
140
- border-color: var(--ui-text);
141
- }
142
-
143
- .ui-btn--ghost {
144
- background: transparent;
145
- color: var(--ui-muted);
146
- border: none;
147
- }
148
- .ui-btn--ghost:hover:not(.ui-btn--disabled):not([disabled]) {
149
- background: var(--ui-surface-2);
150
- color: var(--ui-text);
151
- }
152
-
153
- /* ghost-light — use on dark section backgrounds (e.g. navy hero, section--dark).
154
- Renders with light/white text and a subtle light border so it remains legible
155
- regardless of whether the surrounding theme is light or dark. */
156
- .ui-btn--ghost-light {
157
- background: transparent;
158
- color: rgba(255, 255, 255, 0.9);
159
- border: 1px solid rgba(255, 255, 255, 0.35);
160
- }
161
- .ui-btn--ghost-light:hover:not(.ui-btn--disabled):not([disabled]) {
162
- background: rgba(255, 255, 255, 0.1);
163
- border-color: rgba(255, 255, 255, 0.65);
164
- color: #ffffff;
165
- }
166
-
167
- .ui-btn--danger {
168
- background: var(--ui-red-dim);
169
- color: var(--ui-red);
170
- border-color: var(--ui-red);
171
- }
172
- .ui-btn--danger:hover:not(.ui-btn--disabled):not([disabled]) {
173
- background: var(--ui-red);
174
- color: var(--ui-bg);
175
- }
176
-
177
- /* Sizes */
178
- .ui-btn--sm {
179
- height: 36px;
180
- padding: 0 .85rem;
181
- font-size: .82rem;
182
- min-width: 36px;
183
- }
184
- .ui-btn--lg {
185
- height: 52px;
186
- padding: 0 1.75rem;
187
- font-size: 1rem;
188
- }
189
-
190
- /* Modifiers */
191
- .ui-btn--full { width: 100%; }
192
- .ui-btn--disabled,
193
- .ui-btn[disabled] {
194
- opacity: .45;
195
- cursor: not-allowed;
196
- pointer-events: none;
197
- }
198
-
199
- .ui-btn-icon {
200
- display: inline-flex;
201
- align-items: center;
202
- flex-shrink: 0;
203
- }
204
-
205
- /* ─── Badge ──────────────────────────────────────────────────────────────── */
206
- .ui-badge {
207
- display: inline-flex;
208
- align-items: center;
209
- align-self: flex-start;
210
- padding: .3em .55em;
211
- border-radius: var(--ui-radius-sm);
212
- font-family: var(--ui-font);
213
- font-size: .72rem;
214
- font-weight: 600;
215
- line-height: 1;
216
- white-space: nowrap;
217
- letter-spacing: .02em;
218
- }
219
-
220
- .ui-badge--default { background: var(--ui-surface-2); color: var(--ui-muted); }
221
- .ui-badge--success { background: var(--ui-green-dim); color: var(--ui-green); }
222
- .ui-badge--warning { background: var(--ui-yellow-dim);color: var(--ui-yellow); }
223
- .ui-badge--error { background: var(--ui-red-dim); color: var(--ui-red); }
224
- .ui-badge--info { background: var(--ui-blue-dim); color: var(--ui-blue); }
225
-
226
- /* ─── Card ───────────────────────────────────────────────────────────────── */
227
- .ui-card {
228
- background: var(--ui-surface);
229
- border: 1px solid var(--ui-border);
230
- border-radius: var(--ui-radius);
231
- overflow: hidden;
232
- }
233
-
234
- .ui-card-header {
235
- padding: 1rem 1.25rem;
236
- border-bottom: 1px solid var(--ui-border);
237
- }
238
-
239
- .ui-card-title {
240
- margin: 0;
241
- font-size: .95rem;
242
- font-weight: 600;
243
- color: var(--ui-text);
244
- line-height: 1.4;
245
- }
246
-
247
- .ui-card-body { padding: 1.25rem; }
248
-
249
- .ui-card--flush .ui-card-body { padding: 0; }
250
-
251
- /* Card variants */
252
- .ui-card--elevated {
253
- box-shadow: 0 4px 24px rgba(0,0,0,.22), 0 1px 4px rgba(0,0,0,.12);
254
- border-color: transparent;
255
- }
256
- .ui-card--bordered {
257
- box-shadow: none;
258
- border-width: 2px;
259
- }
260
- .ui-card--flat {
261
- box-shadow: none;
262
- border-color: transparent;
263
- }
264
- .ui-card--glass {
265
- background: rgba(255,255,255,.06);
266
- border-color: rgba(255,255,255,.12);
267
- box-shadow: 0 4px 24px rgba(0,0,0,.18);
268
- backdrop-filter: blur(12px);
269
- -webkit-backdrop-filter: blur(12px);
270
- }
271
- [data-theme="light"] .ui-card--glass {
272
- background: rgba(255,255,255,.72);
273
- border-color: rgba(0,0,0,.08);
274
- }
275
- .ui-card--tinted {
276
- background: var(--ui-accent-dim, rgba(99,102,241,.1));
277
- border-color: var(--ui-accent-dim, rgba(99,102,241,.2));
278
- box-shadow: none;
279
- }
280
-
281
- .ui-card-footer {
282
- padding: 1rem 1.25rem;
283
- border-top: 1px solid var(--ui-border);
284
- background: var(--ui-surface-2);
285
- }
286
-
287
- /* ============================================================
288
- Fieldset
289
- ============================================================ */
290
-
291
- .ui-fieldset {
292
- border: 1px solid var(--ui-border);
293
- border-radius: var(--ui-radius);
294
- padding: 0;
295
- margin: 0;
296
- }
297
-
298
- .ui-fieldset-legend {
299
- margin-left: 1rem;
300
- padding: 0 0.375rem;
301
- font-size: 0.75rem;
302
- font-weight: 600;
303
- letter-spacing: 0.06em;
304
- text-transform: uppercase;
305
- color: var(--ui-muted);
306
- line-height: 1;
307
- }
308
-
309
- .ui-fieldset-body {
310
- display: flex;
311
- flex-direction: column;
312
- gap: 1rem;
313
- padding: 1.25rem;
314
- }
315
-
316
- .ui-fieldset--gap-xs .ui-fieldset-body { gap: 0.375rem; }
317
- .ui-fieldset--gap-sm .ui-fieldset-body { gap: 0.625rem; }
318
- .ui-fieldset--gap-lg .ui-fieldset-body { gap: 1.5rem; }
319
-
320
- /* ─── Form fields (shared base) ──────────────────────────────────────────── */
321
- .ui-field {
322
- display: flex;
323
- flex-direction: column;
324
- gap: .4rem;
325
- }
326
-
327
- .ui-label {
328
- font-family: var(--ui-font);
329
- font-size: .85rem;
330
- font-weight: 600;
331
- color: var(--ui-text);
332
- line-height: 1.4;
333
- }
334
-
335
- .ui-required {
336
- color: var(--ui-red);
337
- margin-left: .15rem;
338
- }
339
-
340
- .ui-hint {
341
- font-size: .8rem;
342
- color: var(--ui-muted);
343
- margin: 0;
344
- line-height: 1.5;
345
- }
346
-
347
- .ui-error {
348
- font-size: .8rem;
349
- color: var(--ui-red);
350
- margin: 0;
351
- line-height: 1.5;
352
- }
353
-
354
- /* ─── Input ──────────────────────────────────────────────────────────────── */
355
- .ui-input {
356
- width: 100%;
357
- height: var(--ui-touch-min);
358
- padding: 0 .85rem;
359
- background: var(--ui-surface);
360
- border: 1px solid var(--ui-border);
361
- border-radius: var(--ui-radius);
362
- font-family: var(--ui-font);
363
- font-size: .9rem;
364
- color: var(--ui-text);
365
- transition: border-color .15s;
366
- appearance: none;
367
- -webkit-appearance: none;
368
- }
369
-
370
- /* iOS Safari auto-zooms the page when a focused input's font-size is under
371
- 16px, forcing the user to pinch back out afterwards. On touch devices form
372
- controls must never go below 16px — desktop keeps the compact .9rem. */
373
- @media (pointer: coarse) {
374
- .ui-input,
375
- .ui-textarea,
376
- .ui-select,
377
- .ui-search-input {
378
- font-size: max(1rem, 16px);
379
- }
380
- }
381
-
382
- .ui-input::placeholder { color: var(--ui-muted); }
383
-
384
- .ui-input:hover:not(:disabled) { border-color: var(--ui-muted); }
385
-
386
- .ui-input:disabled {
387
- opacity: .5;
388
- cursor: not-allowed;
389
- }
390
-
391
- .ui-field--error .ui-input {
392
- border-color: var(--ui-red);
393
- }
394
-
395
- /* ─── Search ─────────────────────────────────────────────────────────────── */
396
- .ui-search-wrap {
397
- position: relative;
398
- display: flex;
399
- align-items: center;
400
- }
401
-
402
- .ui-search-icon {
403
- position: absolute;
404
- left: .75rem;
405
- display: flex;
406
- align-items: center;
407
- color: var(--ui-muted);
408
- pointer-events: none;
409
- }
410
-
411
- .ui-search-input {
412
- width: 100%;
413
- height: var(--ui-touch-min);
414
- padding: 0 2.5rem 0 2.5rem;
415
- background: var(--ui-surface);
416
- border: 1px solid var(--ui-border);
417
- border-radius: var(--ui-radius);
418
- font-family: var(--ui-font);
419
- font-size: .9rem;
420
- color: var(--ui-text);
421
- transition: border-color .15s;
422
- appearance: none;
423
- -webkit-appearance: none;
424
- }
425
-
426
- .ui-search-input::placeholder { color: var(--ui-muted); }
427
-
428
- .ui-search-input:hover:not(:disabled) { border-color: var(--ui-muted); }
429
-
430
- .ui-search-input:disabled { opacity: .5; cursor: not-allowed; }
431
-
432
- /* Hide native browser cancel button — the component provides its own */
433
- .ui-search-input::-webkit-search-cancel-button { display: none; }
434
-
435
- .ui-search-clear {
436
- position: absolute;
437
- right: .5rem;
438
- display: flex;
439
- align-items: center;
440
- justify-content: center;
441
- width: 1.75rem;
442
- height: 1.75rem;
443
- padding: 0;
444
- background: transparent;
445
- border: none;
446
- border-radius: var(--ui-radius-sm);
447
- color: var(--ui-muted);
448
- cursor: pointer;
449
- transition: color .15s, background .15s;
450
- }
451
-
452
- .ui-search-clear:hover { color: var(--ui-text); background: var(--ui-surface-2); }
453
-
454
- /* ─── Select ─────────────────────────────────────────────────────────────── */
455
- .ui-select-wrap {
456
- position: relative;
457
- display: flex;
458
- }
459
-
460
- .ui-select {
461
- width: 100%;
462
- height: var(--ui-touch-min);
463
- padding: 0 2.5rem 0 .85rem;
464
- background: var(--ui-surface);
465
- border: 1px solid var(--ui-border);
466
- border-radius: var(--ui-radius);
467
- font-family: var(--ui-font);
468
- font-size: .9rem;
469
- color: var(--ui-text);
470
- cursor: pointer;
471
- appearance: none;
472
- -webkit-appearance: none;
473
- transition: border-color .15s;
474
- }
475
-
476
- .ui-select:hover:not(:disabled) { border-color: var(--ui-muted); }
477
-
478
- .ui-select:disabled {
479
- opacity: .5;
480
- cursor: not-allowed;
481
- }
482
-
483
- .ui-field--error .ui-select { border-color: var(--ui-red); }
484
-
485
- .ui-select-chevron {
486
- position: absolute;
487
- right: .85rem;
488
- top: 50%;
489
- transform: translateY(-50%);
490
- pointer-events: none;
491
- color: var(--ui-muted);
492
- display: flex;
493
- align-items: center;
494
- }
495
-
496
- /* ─── Textarea ───────────────────────────────────────────────────────────── */
497
- .ui-textarea {
498
- width: 100%;
499
- padding: .65rem .85rem;
500
- background: var(--ui-surface);
501
- border: 1px solid var(--ui-border);
502
- border-radius: var(--ui-radius);
503
- font-family: var(--ui-font);
504
- font-size: .9rem;
505
- color: var(--ui-text);
506
- resize: vertical;
507
- transition: border-color .15s;
508
- min-height: calc(var(--ui-touch-min) * 2);
509
- appearance: none;
510
- }
511
-
512
- .ui-textarea::placeholder { color: var(--ui-muted); }
513
-
514
- .ui-textarea:hover:not(:disabled) { border-color: var(--ui-muted); }
515
-
516
- .ui-textarea:disabled {
517
- opacity: .5;
518
- cursor: not-allowed;
519
- }
520
-
521
- .ui-field--error .ui-textarea { border-color: var(--ui-red); }
522
-
523
- /* ─── Alert ──────────────────────────────────────────────────────────────── */
524
- .ui-alert {
525
- display: flex;
526
- align-items: flex-start;
527
- gap: .75rem;
528
- padding: .85rem 1rem;
529
- border-radius: var(--ui-radius);
530
- border: 1px solid transparent;
531
- font-size: .88rem;
532
- line-height: 1.6;
533
- }
534
-
535
- .ui-alert--info { background: var(--ui-blue-dim); border-color: var(--ui-blue); color: var(--ui-blue); }
536
- .ui-alert--success { background: var(--ui-green-dim); border-color: var(--ui-green); color: var(--ui-green); }
537
- .ui-alert--warning { background: var(--ui-yellow-dim);border-color: var(--ui-yellow); color: var(--ui-yellow);}
538
- .ui-alert--error { background: var(--ui-red-dim); border-color: var(--ui-red); color: var(--ui-red); }
539
-
540
- .ui-alert-icon {
541
- display: flex;
542
- align-items: center;
543
- flex-shrink: 0;
544
- margin-top: .1rem;
545
- }
546
-
547
- .ui-alert-body { color: var(--ui-text); }
548
-
549
- .ui-alert-title { font-weight: 600; }
550
-
551
- /* ─── Stat ───────────────────────────────────────────────────────────────── */
552
- .ui-stat {
553
- display: flex;
554
- flex-direction: column;
555
- gap: .3rem;
556
- }
557
-
558
- .ui-stat-label {
559
- font-size: .8rem;
560
- color: var(--ui-muted);
561
- font-weight: 500;
562
- margin: 0;
563
- }
564
-
565
- .ui-stat-value {
566
- font-size: 2rem;
567
- font-weight: 700;
568
- color: var(--ui-text);
569
- line-height: 1;
570
- margin: 0;
571
- letter-spacing: -.02em;
572
- }
573
-
574
- .ui-stat-change {
575
- display: inline-flex;
576
- align-items: center;
577
- gap: .3rem;
578
- font-size: .8rem;
579
- font-weight: 600;
580
- margin: 0;
581
- }
582
-
583
- .ui-stat-change--up { color: var(--ui-green); }
584
- .ui-stat-change--down { color: var(--ui-red); }
585
- .ui-stat-change--neutral { color: var(--ui-muted); }
586
-
587
- .ui-stat--center { align-items: center; text-align: center; }
588
- .ui-stat--center .ui-stat-change { margin-inline: auto; }
589
-
590
- /* Stat sizes */
591
- .ui-stat--sm .ui-stat-value { font-size: 1.25rem; letter-spacing: -.01em; }
592
- .ui-stat--sm .ui-stat-label { font-size: .72rem; }
593
- .ui-stat--lg .ui-stat-value { font-size: 3.5rem; letter-spacing: -.04em; line-height: .9; }
594
- .ui-stat--lg .ui-stat-label { font-size: .9rem; }
595
-
596
- /* ─── Avatar ─────────────────────────────────────────────────────────────── */
597
- .ui-avatar {
598
- display: inline-flex;
599
- align-items: center;
600
- justify-content: center;
601
- border-radius: 50%;
602
- overflow: hidden;
603
- background: var(--ui-accent-dim);
604
- color: var(--ui-accent);
605
- font-family: var(--ui-font);
606
- font-weight: 700;
607
- flex-shrink: 0;
608
- object-fit: cover;
609
- }
610
-
611
- .ui-avatar--sm { width: 28px; height: 28px; font-size: .65rem; }
612
- .ui-avatar--md { width: 40px; height: 40px; font-size: .85rem; }
613
- .ui-avatar--lg { width: 56px; height: 56px; font-size: 1.1rem; }
614
- .ui-avatar--xl { width: 80px; height: 80px; font-size: 1.5rem; }
615
-
616
- /* ─── Empty state ────────────────────────────────────────────────────────── */
617
- .ui-empty {
618
- display: flex;
619
- flex-direction: column;
620
- align-items: center;
621
- text-align: center;
622
- gap: .75rem;
623
- padding: 3rem 1.5rem;
624
- }
625
-
626
- .ui-empty-title {
627
- font-size: 1.05rem;
628
- font-weight: 600;
629
- color: var(--ui-text);
630
- margin: 0;
631
- }
632
-
633
- .ui-empty-desc {
634
- font-size: .88rem;
635
- color: var(--ui-muted);
636
- max-width: 36ch;
637
- margin: 0;
638
- line-height: 1.6;
639
- }
640
-
641
- /* ─── Table ──────────────────────────────────────────────────────────────── */
642
- .ui-table-wrap {
643
- overflow-x: auto;
644
- border: 1px solid var(--ui-border);
645
- border-radius: var(--ui-radius);
646
- /* Explicit outline for keyboard-scrollable region */
647
- }
648
-
649
- .ui-table-wrap:focus-visible {
650
- outline: 2px solid var(--ui-accent);
651
- outline-offset: 2px;
652
- }
653
-
654
- .ui-table {
655
- width: 100%;
656
- border-collapse: collapse;
657
- font-size: .88rem;
658
- }
659
-
660
- .ui-table-caption {
661
- caption-side: top;
662
- text-align: left;
663
- padding: .75rem 1rem;
664
- font-size: .8rem;
665
- font-weight: 600;
666
- color: var(--ui-muted);
667
- text-transform: uppercase;
668
- letter-spacing: .06em;
669
- border-bottom: 1px solid var(--ui-border);
670
- }
671
-
672
- .ui-table thead th {
673
- padding: .65rem 1rem;
674
- text-align: left;
675
- font-size: .78rem;
676
- font-weight: 600;
677
- color: var(--ui-muted);
678
- text-transform: uppercase;
679
- letter-spacing: .06em;
680
- border-bottom: 1px solid var(--ui-border);
681
- background: var(--ui-surface-2);
682
- white-space: nowrap;
683
- }
684
-
685
- .ui-table tbody td {
686
- padding: .75rem 1rem;
687
- border-bottom: 1px solid var(--ui-border);
688
- color: var(--ui-text);
689
- vertical-align: top;
690
- line-height: 1.5;
691
- }
692
-
693
- .ui-table tbody tr:last-child td { border-bottom: none; }
694
-
695
- .ui-table tbody tr:nth-child(even) { background: var(--ui-surface-2); }
696
-
697
- /* ─── Container ──────────────────────────────────────────────────────────── */
698
- .ui-container { width: 100%; margin-left: auto; margin-right: auto; padding-left: 1.5rem; padding-right: 1.5rem; }
699
- .ui-container--sm { max-width: 640px; }
700
- .ui-container--md { max-width: 768px; }
701
- .ui-container--lg { max-width: 1100px; }
702
- .ui-container--xl { max-width: 1280px; }
703
-
704
- /* ─── Section ────────────────────────────────────────────────────────────── */
705
- .ui-section { padding-top: 5rem; padding-bottom: 5rem; }
706
- .ui-section--sm { padding-top: 3rem; padding-bottom: 3rem; }
707
- .ui-section--lg { padding-top: 7rem; padding-bottom: 7rem; }
708
- .ui-section--alt { background: var(--ui-surface, var(--surface, #111116)); }
709
- .ui-section--dark { background: var(--ui-surface-2, var(--surface-2, #18181f)); }
710
-
711
- /* In light theme, --ui-surface-2 resolves to a light grey — not "dark".
712
- Override so section--dark always renders a genuinely dark background that
713
- contrasts with the page, regardless of the active theme. */
714
- [data-theme="light"] .ui-section--dark,
715
- .ui-theme-light .ui-section--dark {
716
- background: var(--ui-dark-bg, #1a1a2e);
717
- color: var(--ui-dark-text, #e2e2ea);
718
- }
719
- /* Ensure text children inherit the light colour in the dark section */
720
- [data-theme="light"] .ui-section--dark .ui-section-title,
721
- [data-theme="light"] .ui-section--dark .ui-section-eyebrow,
722
- [data-theme="light"] .ui-section--dark .ui-section-subtitle,
723
- .ui-theme-light .ui-section--dark .ui-section-title,
724
- .ui-theme-light .ui-section--dark .ui-section-eyebrow,
725
- .ui-theme-light .ui-section--dark .ui-section-subtitle {
726
- color: inherit;
727
- }
728
- /* Ghost button inside a dark section on a light-theme page */
729
- [data-theme="light"] .ui-section--dark .ui-btn--ghost,
730
- .ui-theme-light .ui-section--dark .ui-btn--ghost {
731
- color: var(--ui-dark-text, #e2e2ea);
732
- border-color: rgba(226, 226, 234, 0.35);
733
- }
734
- [data-theme="light"] .ui-section--dark .ui-btn--ghost:hover:not(.ui-btn--disabled):not([disabled]),
735
- .ui-theme-light .ui-section--dark .ui-btn--ghost:hover:not(.ui-btn--disabled):not([disabled]) {
736
- background: rgba(226, 226, 234, 0.1);
737
- border-color: rgba(226, 226, 234, 0.65);
738
- color: var(--ui-dark-text, #e2e2ea);
739
- }
740
-
741
- /* diagonal — tapered bottom edge; follow with a section that starts flush */
742
- .ui-section--diagonal {
743
- background: var(--ui-surface, var(--surface, #111116));
744
- padding-bottom: calc(5rem + 3.5rem);
745
- clip-path: polygon(0 0, 100% 0, 100% calc(100% - 3.5rem), 0 100%);
746
- }
747
- /* paper — subtle dot-grid texture on a raised surface */
748
- .ui-section--paper {
749
- position: relative;
750
- background-color: var(--ui-surface, var(--surface, #111116));
751
- background-image: radial-gradient(circle, var(--ui-border) 1px, transparent 0);
752
- background-size: 22px 22px;
753
- }
754
- /* spotlight — accent glow from center top */
755
- .ui-section--spotlight {
756
- background: radial-gradient(ellipse 70% 60% at 50% 30%, var(--ui-accent-dim, rgba(155,141,255,.15)), var(--ui-surface, #111116) 80%);
757
- }
758
-
759
- /* ─── Grid ───────────────────────────────────────────────────────────────── */
760
- .ui-grid { display: grid; gap: 2rem; }
761
-
762
- .ui-grid--cols-1 { grid-template-columns: 1fr; }
763
- .ui-grid--cols-2 { grid-template-columns: repeat(2, 1fr); }
764
- .ui-grid--cols-3 { grid-template-columns: repeat(3, 1fr); }
765
- .ui-grid--cols-4 { grid-template-columns: repeat(4, 1fr); }
766
-
767
- .ui-grid--gap-sm { gap: 1rem; }
768
- .ui-grid--gap-lg { gap: 3rem; }
769
-
770
- /* ─── Stack ──────────────────────────────────────────────────────────────── */
771
- .ui-stack { display: flex; flex-direction: column; gap: 1rem; }
772
-
773
- .ui-stack--gap-xs { gap: .25rem; }
774
- .ui-stack--gap-sm { gap: .5rem; }
775
- .ui-stack--gap-lg { gap: 2rem; }
776
- .ui-stack--gap-xl { gap: 3rem; }
777
-
778
- .ui-stack--align-start { align-items: flex-start; }
779
- .ui-stack--align-center { align-items: center; }
780
- .ui-stack--align-end { align-items: flex-end; }
781
-
782
- /* ─── Cluster ────────────────────────────────────────────────────────────── */
783
- .ui-cluster { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; }
784
-
785
- .ui-cluster--gap-xs { gap: .25rem; }
786
- .ui-cluster--gap-sm { gap: .5rem; }
787
- .ui-cluster--gap-lg { gap: 2rem; }
788
-
789
- .ui-cluster--justify-center { justify-content: center; }
790
- .ui-cluster--justify-end { justify-content: flex-end; }
791
- .ui-cluster--justify-between { justify-content: space-between; }
792
-
793
- .ui-cluster--align-start { align-items: flex-start; }
794
- .ui-cluster--align-end { align-items: flex-end; }
795
-
796
- .ui-cluster--nowrap { flex-wrap: nowrap; }
797
-
798
- /* ─── Divider ────────────────────────────────────────────────────────────── */
799
- hr.ui-divider {
800
- border: none;
801
- border-top: 1px solid var(--ui-border, var(--border, #222228));
802
- margin: 0;
803
- }
804
-
805
- .ui-divider--label {
806
- display: flex;
807
- align-items: center;
808
- gap: .75rem;
809
- }
810
-
811
- .ui-divider-line {
812
- flex: 1;
813
- height: 1px;
814
- background: var(--ui-border, var(--border, #222228));
815
- display: block;
816
- }
817
-
818
- .ui-divider-text {
819
- font-size: .8rem;
820
- color: var(--ui-muted, var(--muted, #9090a0));
821
- white-space: nowrap;
822
- flex-shrink: 0;
823
- }
824
-
825
- /* ─── Media ──────────────────────────────────────────────────────────────── */
826
- .ui-media {
827
- display: grid;
828
- grid-template-columns: 1fr 1fr;
829
- gap: 3rem;
830
- align-items: center;
831
- }
832
-
833
- .ui-media--reverse { direction: rtl; }
834
- .ui-media--reverse > * { direction: ltr; }
835
-
836
- .ui-media--align-start { align-items: flex-start; }
837
-
838
- .ui-media--gap-sm { gap: 1.5rem; }
839
- .ui-media--gap-lg { gap: 5rem; }
840
-
841
- .ui-media-image { min-width: 0; }
842
- .ui-media-content { min-width: 0; }
843
-
844
- .ui-media-image img {
845
- width: 100%;
846
- height: auto;
847
- border-radius: var(--ui-radius, 8px);
848
- display: block;
849
- }
850
-
851
- /* ─── Hero ───────────────────────────────────────────────────────────────── */
852
- .ui-hero { padding: 5rem 1.5rem; text-align: center; }
853
- .ui-hero--left { text-align: left; }
854
- .ui-hero--sm { padding-top: 2.5rem; padding-bottom: 0; }
855
- .ui-hero-inner { max-width: 720px; margin: 0 auto; }
856
- .ui-hero--left .ui-hero-inner { margin: 0; }
857
-
858
- .ui-hero-eyebrow {
859
- font-size: .78rem;
860
- font-weight: 600;
861
- letter-spacing: .08em;
862
- text-transform: uppercase;
863
- color: var(--ui-accent, var(--accent, #9b8dff));
864
- margin: 0 0 .75rem;
865
- }
866
-
867
- .ui-hero-title {
868
- font-size: clamp(2.2rem, 6vw, 3.5rem);
869
- font-weight: 800;
870
- line-height: 1.1;
871
- letter-spacing: var(--ui-letter-spacing-display, -.02em);
872
- font-family: var(--ui-font-display, var(--ui-font));
873
- color: var(--ui-text, var(--text, #e2e2ea));
874
- margin: 0 0 1.25rem;
875
- }
876
-
877
- .ui-hero-subtitle {
878
- font-size: 1.125rem;
879
- color: var(--ui-muted, var(--muted, #9090a0));
880
- line-height: 1.65;
881
- margin: 0 0 2rem;
882
- }
883
-
884
- .ui-hero-actions {
885
- display: flex;
886
- gap: .75rem;
887
- flex-wrap: wrap;
888
- justify-content: center;
889
- }
890
- .ui-hero--left .ui-hero-actions { justify-content: flex-start; }
891
-
892
- /* Split (text + image, 50/50) */
893
- .ui-hero--split { text-align: left; }
894
- .ui-hero--split .ui-hero-inner {
895
- max-width: 1100px;
896
- margin: 0 auto;
897
- display: grid;
898
- grid-template-columns: 1fr 1fr;
899
- gap: 3rem;
900
- align-items: center;
901
- }
902
- .ui-hero--split .ui-hero-actions { justify-content: flex-start; }
903
- .ui-hero--split .ui-hero-media { display: flex; align-items: center; justify-content: center; }
904
- .ui-hero--split .ui-hero-media img { width: 100%; height: auto; border-radius: var(--ui-radius, 8px); display: block; }
905
- .ui-hero--media-left .ui-hero-media { order: -1; }
906
-
907
- /* Asymmetric (text 60%, image 40%) */
908
- .ui-hero--asymmetric { text-align: left; }
909
- .ui-hero--asymmetric .ui-hero-inner {
910
- max-width: 1100px;
911
- margin: 0 auto;
912
- display: grid;
913
- grid-template-columns: 3fr 2fr;
914
- gap: 3rem;
915
- align-items: center;
916
- }
917
- .ui-hero--asymmetric .ui-hero-actions { justify-content: flex-start; }
918
- .ui-hero--asymmetric .ui-hero-media { display: flex; align-items: center; justify-content: center; }
919
- .ui-hero--asymmetric .ui-hero-media img { width: 100%; height: auto; border-radius: var(--ui-radius, 8px); display: block; }
920
- .ui-hero--asymmetric.ui-hero--media-left .ui-hero-media { order: -1; }
921
- .ui-hero--asymmetric.ui-hero--media-left .ui-hero-inner { grid-template-columns: 2fr 3fr; }
922
-
923
- /* Overlap (image fills section, text overlaid) */
924
- .ui-hero--overlap {
925
- position: relative;
926
- min-height: 60vh;
927
- overflow: hidden;
928
- padding: 0;
929
- display: flex;
930
- align-items: flex-end;
931
- text-align: left;
932
- }
933
- .ui-hero--overlap .ui-hero-overlap-media {
934
- position: absolute;
935
- inset: 0;
936
- z-index: 0;
937
- }
938
- .ui-hero--overlap .ui-hero-overlap-media img,
939
- .ui-hero--overlap .ui-hero-overlap-media video {
940
- width: 100%;
941
- height: 100%;
942
- object-fit: cover;
943
- display: block;
944
- }
945
- .ui-hero--overlap .ui-hero-inner {
946
- position: relative;
947
- z-index: 1;
948
- width: 100%;
949
- max-width: none;
950
- padding: 4rem 2rem;
951
- background: linear-gradient(to top, rgba(0,0,0,.75) 0%, rgba(0,0,0,.3) 60%, transparent 100%);
952
- }
953
- .ui-hero--overlap .ui-hero-content { max-width: 600px; }
954
- .ui-hero--overlap .ui-hero-eyebrow { color: rgba(255,255,255,.75); }
955
- .ui-hero--overlap .ui-hero-title { color: #fff; text-shadow: 0 2px 8px rgba(0,0,0,.4); }
956
- .ui-hero--overlap .ui-hero-subtitle{ color: rgba(255,255,255,.8); }
957
- .ui-hero--overlap .ui-hero-actions { justify-content: flex-start; }
958
-
959
- /* ─── Feature ────────────────────────────────────────────────────────────── */
960
- .ui-feature { display: flex; flex-direction: column; gap: .75rem; }
961
- .ui-feature-image { width: 100%; border-radius: var(--ui-radius-sm); overflow: hidden; }
962
- .ui-feature-image img { width: 100%; height: auto; display: block; }
963
-
964
- .ui-feature-icon {
965
- display: block;
966
- flex-shrink: 0;
967
- line-height: 1;
968
- }
969
-
970
- .ui-feature-title { font-size: 1rem; font-weight: 600; color: var(--ui-text, var(--text, #e2e2ea)); margin: 0; }
971
- .ui-feature-desc { font-size: .9rem; color: var(--ui-muted, var(--muted, #9090a0)); line-height: 1.6; margin: 0; }
972
-
973
- .ui-feature--center { align-items: center; text-align: center; }
974
-
975
- /* ─── Accordion ──────────────────────────────────────────────────────────── */
976
- .ui-accordion { display: flex; flex-direction: column; gap: .5rem; width: 100%; }
977
-
978
- .ui-accordion-item {
979
- background: var(--ui-surface, var(--surface, #111116));
980
- border: 1px solid var(--ui-border, var(--border, #222228));
981
- border-radius: var(--ui-radius, 8px);
982
- overflow: hidden;
983
- }
984
-
985
- .ui-accordion-summary {
986
- display: flex;
987
- justify-content: space-between;
988
- align-items: center;
989
- padding: 1rem 1.25rem;
990
- cursor: pointer;
991
- font-size: .95rem;
992
- font-weight: 500;
993
- color: var(--ui-text, var(--text, #e2e2ea));
994
- list-style: none;
995
- user-select: none;
996
- gap: 1rem;
997
- }
998
- .ui-accordion-summary::-webkit-details-marker { display: none; }
999
- .ui-accordion-summary:hover { color: var(--ui-accent, var(--accent, #9b8dff)); }
1000
-
1001
- .ui-accordion-icon {
1002
- width: 16px;
1003
- height: 16px;
1004
- position: relative;
1005
- flex-shrink: 0;
1006
- }
1007
- .ui-accordion-icon::before,
1008
- .ui-accordion-icon::after {
1009
- content: '';
1010
- position: absolute;
1011
- background: currentColor;
1012
- border-radius: 2px;
1013
- transition: transform .2s;
1014
- }
1015
- .ui-accordion-icon::before { width: 10px; height: 1.5px; top: 7px; left: 3px; }
1016
- .ui-accordion-icon::after { width: 1.5px; height: 10px; top: 3px; left: 7px; }
1017
- .ui-accordion-item[open] .ui-accordion-icon::after { transform: rotate(90deg); }
1018
-
1019
- .ui-accordion-body { padding: 0 1.25rem 1rem; }
1020
- .ui-accordion-body p { font-size: .9rem; color: var(--ui-muted, var(--muted, #9090a0)); line-height: 1.7; margin: 0; }
1021
-
1022
- /* ─── Tooltip ────────────────────────────────────────────────────────────── */
1023
- .ui-tooltip {
1024
- position: relative;
1025
- display: inline-block;
1026
- }
1027
-
1028
- .ui-tooltip::after {
1029
- content: attr(data-tip);
1030
- position: absolute;
1031
- bottom: calc(100% + 8px);
1032
- left: 50%;
1033
- transform: translateX(-50%) translateY(4px);
1034
- background: var(--ui-surface-2, var(--surface-2, #1a1a26));
1035
- color: var(--ui-text, var(--text, #e2e2ea));
1036
- font-size: .78rem;
1037
- font-weight: 500;
1038
- line-height: 1.4;
1039
- white-space: nowrap;
1040
- padding: .35rem .7rem;
1041
- border-radius: 6px;
1042
- border: 1px solid var(--ui-border, var(--border, #2a2a38));
1043
- pointer-events: none;
1044
- opacity: 0;
1045
- transition: opacity .15s, transform .15s;
1046
- z-index: var(--ui-z-tooltip, 200);
1047
- }
1048
-
1049
- .ui-tooltip::before {
1050
- content: '';
1051
- position: absolute;
1052
- bottom: calc(100% + 2px);
1053
- left: 50%;
1054
- transform: translateX(-50%);
1055
- border: 5px solid transparent;
1056
- border-top-color: var(--ui-border, var(--border, #2a2a38));
1057
- pointer-events: none;
1058
- opacity: 0;
1059
- transition: opacity .15s;
1060
- z-index: var(--ui-z-tooltip, 200);
1061
- }
1062
-
1063
- .ui-tooltip:hover::after,
1064
- .ui-tooltip:focus-within::after {
1065
- opacity: 1;
1066
- transform: translateX(-50%) translateY(0);
1067
- }
1068
- .ui-tooltip:hover::before,
1069
- .ui-tooltip:focus-within::before { opacity: 1; }
1070
-
1071
- /* bottom */
1072
- .ui-tooltip--bottom::after { bottom: auto; top: calc(100% + 8px); transform: translateX(-50%) translateY(-4px); }
1073
- .ui-tooltip--bottom::before { bottom: auto; top: calc(100% + 2px); border-top-color: transparent; border-bottom-color: var(--ui-border, var(--border, #2a2a38)); }
1074
- .ui-tooltip--bottom:hover::after,
1075
- .ui-tooltip--bottom:focus-within::after { transform: translateX(-50%) translateY(0); }
1076
-
1077
- /* left */
1078
- .ui-tooltip--left::after { bottom: auto; top: 50%; left: auto; right: calc(100% + 8px); transform: translateY(-50%) translateX(4px); }
1079
- .ui-tooltip--left::before { bottom: auto; top: 50%; left: auto; right: calc(100% + 2px); transform: translateY(-50%); border-top-color: transparent; border-left-color: var(--ui-border, var(--border, #2a2a38)); }
1080
- .ui-tooltip--left:hover::after,
1081
- .ui-tooltip--left:focus-within::after { transform: translateY(-50%) translateX(0); }
1082
-
1083
- /* right */
1084
- .ui-tooltip--right::after { bottom: auto; top: 50%; left: calc(100% + 8px); transform: translateY(-50%) translateX(-4px); }
1085
- .ui-tooltip--right::before { bottom: auto; top: 50%; left: calc(100% + 2px); transform: translateY(-50%); border-top-color: transparent; border-right-color: var(--ui-border, var(--border, #2a2a38)); }
1086
- .ui-tooltip--right:hover::after,
1087
- .ui-tooltip--right:focus-within::after { transform: translateY(-50%) translateX(0); }
1088
-
1089
- /* ─── Modal ──────────────────────────────────────────────────────────────── */
1090
- .ui-modal {
1091
- position: fixed;
1092
- inset: 0;
1093
- margin: auto;
1094
- width: min(560px, calc(100vw - 2rem));
1095
- max-height: min(80vh, calc(100dvh - 2rem));
1096
- padding: 0;
1097
- background: var(--ui-surface, var(--surface, #13131e));
1098
- border: 1px solid var(--ui-border, var(--border, #2a2a38));
1099
- border-radius: var(--ui-radius, 12px);
1100
- overflow: hidden;
1101
- box-shadow: 0 20px 60px rgba(0, 0, 0, .5);
1102
- }
1103
-
1104
- .ui-modal--sm { width: min(400px, calc(100vw - 2rem)); }
1105
- .ui-modal--lg { width: min(760px, calc(100vw - 2rem)); }
1106
- .ui-modal--xl { width: min(1000px, calc(100vw - 2rem)); }
1107
-
1108
- .ui-modal::backdrop {
1109
- background: rgba(0, 0, 0, .6);
1110
- backdrop-filter: blur(2px);
1111
- }
1112
-
1113
- .ui-modal-inner {
1114
- display: flex;
1115
- flex-direction: column;
1116
- max-height: inherit;
1117
- margin: 0;
1118
- border: none;
1119
- padding: 0;
1120
- background: transparent;
1121
- }
1122
-
1123
- .ui-modal-header {
1124
- display: flex;
1125
- align-items: center;
1126
- gap: 1rem;
1127
- padding: 1.25rem 1.5rem;
1128
- border-bottom: 1px solid var(--ui-border, var(--border, #2a2a38));
1129
- flex-shrink: 0;
1130
- }
1131
-
1132
- .ui-modal-title {
1133
- flex: 1;
1134
- font-size: 1.1rem;
1135
- font-weight: 700;
1136
- color: var(--ui-text, var(--text, #e2e2ea));
1137
- margin: 0;
1138
- }
1139
-
1140
- .ui-modal-close {
1141
- display: flex;
1142
- align-items: center;
1143
- justify-content: center;
1144
- width: 32px;
1145
- height: 32px;
1146
- padding: 0;
1147
- background: transparent;
1148
- border: none;
1149
- border-radius: 6px;
1150
- color: var(--ui-muted, var(--muted, #9090a0));
1151
- cursor: pointer;
1152
- transition: color .15s, background .15s;
1153
- flex-shrink: 0;
1154
- }
1155
- .ui-modal-close:hover {
1156
- color: var(--ui-text, var(--text, #e2e2ea));
1157
- background: var(--ui-surface-2, var(--surface-2, #1a1a26));
1158
- }
1159
-
1160
- .ui-modal-body {
1161
- flex: 1;
1162
- overflow-y: auto;
1163
- padding: 1.5rem;
1164
- color: var(--ui-text, var(--text, #e2e2ea));
1165
- }
1166
-
1167
- .ui-modal-footer {
1168
- display: flex;
1169
- align-items: center;
1170
- justify-content: flex-end;
1171
- gap: .75rem;
1172
- padding: 1rem 1.5rem;
1173
- border-top: 1px solid var(--ui-border, var(--border, #2a2a38));
1174
- flex-shrink: 0;
1175
- }
1176
-
1177
- /* ─── Nav ────────────────────────────────────────────────────────────────── */
1178
- .ui-nav {
1179
- position: relative;
1180
- background: var(--ui-bg, var(--bg, #0d0d10));
1181
- border-bottom: 1px solid var(--ui-border, var(--border, #222228));
1182
- padding-inline: 1.5rem;
1183
- }
1184
-
1185
- .ui-nav--sticky {
1186
- position: sticky;
1187
- top: 0;
1188
- z-index: 100;
1189
- backdrop-filter: blur(12px);
1190
- -webkit-backdrop-filter: blur(12px);
1191
- background: var(--ui-nav-sticky-bg, rgba(13, 13, 16, .85));
1192
- }
1193
-
1194
- .ui-nav-inner {
1195
- max-width: 1100px;
1196
- margin: 0 auto;
1197
- padding: .875rem 0;
1198
- display: flex;
1199
- align-items: center;
1200
- gap: 2rem;
1201
- }
1202
-
1203
- .ui-nav-logo {
1204
- font-size: 1rem;
1205
- font-weight: 700;
1206
- color: var(--ui-text, var(--text, #e2e2ea));
1207
- text-decoration: none;
1208
- display: flex;
1209
- align-items: center;
1210
- gap: .5rem;
1211
- flex-shrink: 0;
1212
- }
1213
- .ui-nav-logo:hover { color: var(--ui-accent, var(--accent, #9b8dff)); }
1214
-
1215
- .ui-nav-links { display: flex; gap: 1.5rem; align-items: center; flex: 1; }
1216
- .ui-nav-utility { flex: 0; margin-left: auto; }
1217
-
1218
- .ui-nav-link {
1219
- font-size: .875rem;
1220
- color: var(--ui-muted, var(--muted, #9090a0));
1221
- text-decoration: none;
1222
- transition: color .15s;
1223
- min-height: 44px;
1224
- display: flex;
1225
- align-items: center;
1226
- }
1227
- .ui-nav-link:hover { color: var(--ui-text, var(--text, #e2e2ea)); }
1228
-
1229
- .ui-nav-action { margin-left: auto; }
1230
-
1231
- .ui-nav--burger-left .ui-nav-burger { order: -1; margin-left: 0; margin-right: auto; }
1232
-
1233
- .ui-nav-burger {
1234
- display: none;
1235
- margin-left: auto;
1236
- padding: .35rem;
1237
- background: none;
1238
- border: none;
1239
- color: var(--ui-text, var(--text, #e2e2ea));
1240
- cursor: pointer;
1241
- align-items: center;
1242
- justify-content: center;
1243
- border-radius: var(--ui-radius-sm, 6px);
1244
- transition: background .15s;
1245
- }
1246
- .ui-nav-burger:hover { background: var(--ui-surface, var(--surface, #111116)); }
1247
- .ui-nav-burger-close { display: none; }
1248
- .ui-nav--open .ui-nav-burger-open { display: none; }
1249
- .ui-nav--open .ui-nav-burger-close { display: block; }
1250
-
1251
- .ui-nav-mobile {
1252
- display: none;
1253
- position: absolute;
1254
- top: 100%;
1255
- left: 0;
1256
- right: 0;
1257
- z-index: 99;
1258
- background: var(--ui-bg, var(--bg, #0d0d10));
1259
- border-bottom: 1px solid var(--ui-border, var(--border, #222228));
1260
- padding: 1rem 1.5rem;
1261
- flex-direction: column;
1262
- gap: .25rem;
1263
- }
1264
- .ui-nav--open .ui-nav-mobile { display: flex; }
1265
-
1266
- .ui-nav-mobile nav {
1267
- display: flex;
1268
- flex-direction: column;
1269
- }
1270
- .ui-nav-mobile .ui-nav-link {
1271
- padding: .6rem 0;
1272
- border-bottom: 1px solid var(--ui-border, var(--border, #222228));
1273
- }
1274
- .ui-nav-mobile .ui-nav-link:last-child { border-bottom: none; }
1275
- .ui-nav-mobile-action { padding-top: .75rem; }
1276
- .ui-nav-mobile-section {
1277
- font-size: .7rem;
1278
- font-weight: 600;
1279
- text-transform: uppercase;
1280
- letter-spacing: .08em;
1281
- color: var(--ui-muted, var(--muted, #6b6b80));
1282
- margin: .75rem 0 .25rem;
1283
- padding: 0;
1284
- }
1285
-
1286
- /* ─── Mega nav ───────────────────────────────────────────────────────────── */
1287
- .ui-nav-mega-wrap { position: relative; }
1288
-
1289
- .ui-nav-mega-trigger {
1290
- background: none;
1291
- border: none;
1292
- cursor: pointer;
1293
- display: inline-flex;
1294
- align-items: center;
1295
- gap: .3rem;
1296
- padding: 0;
1297
- font: inherit;
1298
- font-size: .875rem;
1299
- }
1300
-
1301
- .ui-nav-mega-chevron { transition: transform .2s ease; flex-shrink: 0; }
1302
- .ui-nav-mega-wrap--open .ui-nav-mega-chevron { transform: rotate(180deg); }
1303
-
1304
- .ui-nav-mega-panel {
1305
- position: absolute;
1306
- top: calc(100% + .875rem);
1307
- left: 50%;
1308
- transform: translateX(-50%);
1309
- background: var(--ui-bg, var(--bg, #0d0d10));
1310
- border: 1px solid var(--ui-border, var(--border, #232329));
1311
- border-radius: var(--ui-radius, 8px);
1312
- box-shadow: 0 8px 40px rgba(0,0,0,.35);
1313
- padding: 1.5rem;
1314
- z-index: 200;
1315
- min-width: 360px;
1316
- }
1317
- .ui-nav-mega-panel[hidden] { display: none !important; }
1318
-
1319
- .ui-nav-mega-inner { display: flex; gap: 2rem; }
1320
-
1321
- .ui-nav-mega-col { flex: 1; min-width: 140px; }
1322
-
1323
- .ui-nav-mega-heading {
1324
- font-size: .7rem;
1325
- font-weight: 600;
1326
- text-transform: uppercase;
1327
- letter-spacing: .08em;
1328
- color: var(--ui-muted, var(--muted, #6b6b80));
1329
- margin: 0 0 .5rem;
1330
- padding: 0 .5rem;
1331
- }
1332
-
1333
- .ui-nav-mega-item {
1334
- display: flex;
1335
- flex-direction: column;
1336
- gap: .15rem;
1337
- padding: .5rem;
1338
- border-radius: calc(var(--ui-radius, 8px) * .65);
1339
- transition: background .15s;
1340
- }
1341
- .ui-nav-mega-item:hover { background: var(--ui-surface, var(--surface, #111116)); }
1342
- .ui-nav-mega-item-label {
1343
- font-size: .875rem;
1344
- font-weight: 500;
1345
- color: var(--ui-text, var(--text, #e2e2ea));
1346
- text-decoration: none;
1347
- }
1348
- .ui-nav-mega-item-label:hover { color: var(--ui-accent, var(--accent, #9b8dff)); }
1349
- .ui-nav-mega-item-desc { font-size: .75rem; color: var(--ui-muted, var(--muted, #6b6b80)); }
1350
-
1351
- [data-theme="light"] .ui-nav-mega-panel { box-shadow: 0 8px 40px rgba(0,0,0,.12); }
1352
-
1353
- /* ─── App Badge ──────────────────────────────────────────────────────────── */
1354
- .ui-app-badge {
1355
- display: inline-flex;
1356
- align-items: center;
1357
- gap: .625rem;
1358
- background: var(--ui-text, var(--text, #e2e2ea));
1359
- color: var(--ui-bg, var(--bg, #0d0d10));
1360
- border-radius: 10px;
1361
- padding: .625rem 1.25rem;
1362
- text-decoration: none;
1363
- transition: opacity .15s;
1364
- min-width: 148px;
1365
- }
1366
- .ui-app-badge:hover { opacity: .85; }
1367
-
1368
- .ui-app-badge-text { display: flex; flex-direction: column; gap: .05rem; }
1369
- .ui-app-badge-line1 { font-size: .65rem; font-weight: 400; line-height: 1; }
1370
- .ui-app-badge-line2 { font-size: .95rem; font-weight: 700; line-height: 1; }
1371
-
1372
- /* ─── Mobile ─────────────────────────────────────────────────────────────── */
1373
- @media (max-width: 640px) {
1374
- .ui-btn--lg {
1375
- height: 48px;
1376
- padding: 0 1.25rem;
1377
- font-size: .95rem;
1378
- }
1379
-
1380
- .ui-stat-value { font-size: 1.6rem; }
1381
-
1382
- /* Full-width buttons in narrow containers */
1383
- .ui-btn--full { font-size: .9rem; }
1384
-
1385
- /* Layout */
1386
- .ui-section { padding-top: 3rem; padding-bottom: 3rem; }
1387
- .ui-section--sm { padding-top: 2rem; padding-bottom: 2rem; }
1388
- .ui-section--lg { padding-top: 4rem; padding-bottom: 4rem; }
1389
-
1390
- .ui-grid--cols-2,
1391
- .ui-grid--cols-3,
1392
- .ui-grid--cols-4 { grid-template-columns: 1fr; }
1393
-
1394
- .ui-media { grid-template-columns: 1fr; }
1395
- .ui-media--reverse { direction: ltr; }
1396
-
1397
- .ui-hero { padding: 3rem 1.25rem; }
1398
- .ui-hero-title { font-size: 2rem; }
1399
- .ui-hero-subtitle { font-size: 1rem; }
1400
- .ui-hero--split .ui-hero-inner { grid-template-columns: 1fr; }
1401
- .ui-hero--media-left .ui-hero-media { order: 0; }
1402
-
1403
- .ui-nav-links { display: none; }
1404
- .ui-nav-burger { display: flex; }
1405
- .ui-nav-inner { gap: .75rem; }
1406
- }
1407
-
1408
- /* ─── Utilities ──────────────────────────────────────────────────────────────
1409
- Single-purpose helpers for spacing, typography, and layout.
1410
- Use these in page HTML instead of writing custom CSS for common patterns.
1411
- Prefix: u- (distinct from component classes which use ui-) */
1412
-
1413
- /* Screen-reader only — visually hidden but accessible to assistive tech */
1414
- /* u-visually-hidden is an alias — use either */
1415
- .ui-sr-only,
1416
- .u-visually-hidden {
1417
- position: absolute;
1418
- width: 1px; height: 1px;
1419
- padding: 0; margin: -1px;
1420
- overflow: hidden;
1421
- clip: rect(0,0,0,0);
1422
- white-space: nowrap;
1423
- border: 0;
1424
- }
1425
-
1426
- /* Spacing scale: 1=4px 2=8px 3=12px 4=16px 5=20px 6=24px 8=32px 10=40px 12=48px 16=64px */
1427
-
1428
- /* Margin top */
1429
- .u-mt-0 { margin-top: 0; }
1430
- .u-mt-1 { margin-top: .25rem; }
1431
- .u-mt-2 { margin-top: .5rem; }
1432
- .u-mt-3 { margin-top: .75rem; }
1433
- .u-mt-4 { margin-top: 1rem; }
1434
- .u-mt-5 { margin-top: 1.25rem; }
1435
- .u-mt-6 { margin-top: 1.5rem; }
1436
- .u-mt-8 { margin-top: 2rem; }
1437
- .u-mt-10 { margin-top: 2.5rem; }
1438
- .u-mt-12 { margin-top: 3rem; }
1439
- .u-mt-16 { margin-top: 4rem; }
1440
-
1441
- /* Margin bottom */
1442
- .u-mb-0 { margin-bottom: 0; }
1443
- .u-mb-1 { margin-bottom: .25rem; }
1444
- .u-mb-2 { margin-bottom: .5rem; }
1445
- .u-mb-3 { margin-bottom: .75rem; }
1446
- .u-mb-4 { margin-bottom: 1rem; }
1447
- .u-mb-5 { margin-bottom: 1.25rem; }
1448
- .u-mb-6 { margin-bottom: 1.5rem; }
1449
- .u-mb-8 { margin-bottom: 2rem; }
1450
- .u-mb-10 { margin-bottom: 2.5rem; }
1451
- .u-mb-12 { margin-bottom: 3rem; }
1452
- .u-mb-16 { margin-bottom: 4rem; }
1453
-
1454
- /* Margin left / right / auto */
1455
- .u-ml-auto { margin-left: auto; }
1456
- .u-mr-auto { margin-right: auto; }
1457
- .u-mx-auto { margin-left: auto; margin-right: auto; }
1458
-
1459
- /* Padding */
1460
- .u-p-0 { padding: 0; }
1461
- .u-p-1 { padding: .25rem; }
1462
- .u-p-2 { padding: .5rem; }
1463
- .u-p-3 { padding: .75rem; }
1464
- .u-p-4 { padding: 1rem; }
1465
- .u-p-5 { padding: 1.25rem; }
1466
- .u-p-6 { padding: 1.5rem; }
1467
- .u-p-8 { padding: 2rem; }
1468
-
1469
- .u-px-0 { padding-left: 0; padding-right: 0; }
1470
- .u-px-2 { padding-left: .5rem; padding-right: .5rem; }
1471
- .u-px-3 { padding-left: .75rem; padding-right: .75rem; }
1472
- .u-px-4 { padding-left: 1rem; padding-right: 1rem; }
1473
- .u-px-5 { padding-left: 1.25rem;padding-right: 1.25rem; }
1474
- .u-px-6 { padding-left: 1.5rem; padding-right: 1.5rem; }
1475
- .u-px-8 { padding-left: 2rem; padding-right: 2rem; }
1476
-
1477
- .u-py-0 { padding-top: 0; padding-bottom: 0; }
1478
- .u-py-2 { padding-top: .5rem; padding-bottom: .5rem; }
1479
- .u-py-3 { padding-top: .75rem; padding-bottom: .75rem; }
1480
- .u-py-4 { padding-top: 1rem; padding-bottom: 1rem; }
1481
- .u-py-5 { padding-top: 1.25rem;padding-bottom: 1.25rem; }
1482
- .u-py-6 { padding-top: 1.5rem; padding-bottom: 1.5rem; }
1483
- .u-py-8 { padding-top: 2rem; padding-bottom: 2rem; }
1484
-
1485
- /* Typography — size */
1486
- .u-text-xs { font-size: .75rem; line-height: 1.4; }
1487
- .u-text-sm { font-size: .875rem; line-height: 1.5; }
1488
- .u-text-base { font-size: 1rem; line-height: 1.6; }
1489
- .u-text-lg { font-size: 1.125rem;line-height: 1.5; }
1490
- .u-text-xl { font-size: 1.25rem; line-height: 1.4; }
1491
- .u-text-2xl { font-size: 1.5rem; line-height: 1.3; }
1492
- .u-text-3xl { font-size: 1.875rem;line-height: 1.2; }
1493
- .u-text-4xl { font-size: 2.25rem; line-height: 1.15; }
1494
- .u-text-5xl { font-size: 3rem; line-height: 1.1; }
1495
- .u-text-6xl { font-size: 4rem; line-height: 1.05; }
1496
- .u-text-7xl { font-size: 5rem; line-height: 1; }
1497
-
1498
- /* Typography — weight */
1499
- .u-font-normal { font-weight: 400; }
1500
- .u-font-medium { font-weight: 500; }
1501
- .u-font-semibold { font-weight: 600; }
1502
- .u-font-bold { font-weight: 700; }
1503
-
1504
- /* Typography — alignment */
1505
- .u-text-left { text-align: left; }
1506
- .u-text-center { text-align: center; }
1507
- .u-text-right { text-align: right; }
1508
- .u-text-balance { text-wrap: balance; }
1509
-
1510
- /* Typography — color (uses tokens so theme overrides apply) */
1511
- .u-text-default { color: var(--ui-text); }
1512
- .u-text-muted { color: var(--ui-muted); }
1513
- .u-text-accent { color: var(--ui-accent); }
1514
- .u-text-green { color: var(--ui-green); }
1515
- .u-text-red { color: var(--ui-red); }
1516
- .u-text-yellow { color: var(--ui-yellow); }
1517
- .u-text-blue { color: var(--ui-blue); }
1518
-
1519
- /* Typography — line height */
1520
- .u-leading-tight { line-height: 1.25; }
1521
- .u-leading-snug { line-height: 1.375; }
1522
- .u-leading-normal { line-height: 1.5; }
1523
- .u-leading-relaxed { line-height: 1.625; }
1524
- .u-leading-loose { line-height: 2; }
1525
-
1526
- /* Width */
1527
- .u-w-full { width: 100%; }
1528
- .u-w-auto { width: auto; }
1529
- .u-max-w-xs { max-width: 320px; }
1530
- .u-max-w-sm { max-width: 480px; }
1531
- .u-max-w-md { max-width: 640px; }
1532
- .u-max-w-lg { max-width: 800px; }
1533
- .u-max-w-xl { max-width: 1024px; }
1534
- .u-max-w-prose { max-width: 65ch; }
1535
-
1536
- /* Display */
1537
- .u-block { display: block; }
1538
- .u-inline { display: inline; }
1539
- .u-inline-block { display: inline-block; }
1540
- .u-hidden { display: none; }
1541
-
1542
- /* Flexbox */
1543
- .u-flex { display: flex; }
1544
- .u-flex-col { display: flex; flex-direction: column; }
1545
- .u-flex-wrap { flex-wrap: wrap; }
1546
- .u-flex-1 { flex: 1; }
1547
- .u-shrink-0 { flex-shrink: 0; }
1548
-
1549
- .u-items-start { align-items: flex-start; }
1550
- .u-items-center { align-items: center; }
1551
- .u-items-end { align-items: flex-end; }
1552
- .u-items-stretch { align-items: stretch; }
1553
-
1554
- .u-justify-start { justify-content: flex-start; }
1555
- .u-justify-center { justify-content: center; }
1556
- .u-justify-end { justify-content: flex-end; }
1557
- .u-justify-between { justify-content: space-between; }
1558
-
1559
- .u-gap-1 { gap: .25rem; }
1560
- .u-gap-2 { gap: .5rem; }
1561
- .u-gap-3 { gap: .75rem; }
1562
- .u-gap-4 { gap: 1rem; }
1563
- .u-gap-5 { gap: 1.25rem; }
1564
- .u-gap-6 { gap: 1.5rem; }
1565
- .u-gap-8 { gap: 2rem; }
1566
-
1567
- /* Border radius */
1568
- .u-rounded { border-radius: var(--ui-radius-sm); }
1569
- .u-rounded-md { border-radius: var(--ui-radius); }
1570
- .u-rounded-lg { border-radius: calc(var(--ui-radius) * 1.5); }
1571
- .u-rounded-xl { border-radius: calc(var(--ui-radius) * 2); }
1572
- .u-rounded-full { border-radius: 9999px; }
1573
-
1574
- /* Border */
1575
- .u-border { border: 1px solid var(--ui-border); }
1576
- .u-border-t { border-top: 1px solid var(--ui-border); }
1577
- .u-border-b { border-bottom: 1px solid var(--ui-border); }
1578
-
1579
- /* Background */
1580
- .u-bg-surface { background: var(--ui-surface); }
1581
- .u-bg-surface2 { background: var(--ui-surface-2); }
1582
- .u-bg-accent { background: var(--ui-accent); }
1583
-
1584
- /* Overflow */
1585
- .u-overflow-hidden { overflow: hidden; }
1586
- .u-overflow-auto { overflow: auto; }
1587
-
1588
- /* Position */
1589
- .u-relative { position: relative; }
1590
- .u-absolute { position: absolute; }
1591
-
1592
- /* Opacity */
1593
- .u-opacity-50 { opacity: .5; }
1594
- .u-opacity-75 { opacity: .75; }
1595
-
1596
- /* Numeric formatting */
1597
- .u-tabular-nums { font-variant-numeric: tabular-nums; }
1598
-
1599
- /* ─── Section header ─────────────────────────────────────────────────────────
1600
- Optional heading block prepended to section() when eyebrow/title/subtitle
1601
- props are supplied. Sits above the content slot. */
1602
- .ui-section-header { width: 100%; max-width: 1100px; margin: 0 auto 2.5rem; padding-left: 1.5rem; padding-right: 1.5rem; }
1603
- .ui-section-header--center { text-align: center; }
1604
- .ui-section-header--gap-none { margin-bottom: 0; }
1605
- .ui-section-header--gap-sm { margin-bottom: 1.25rem; }
1606
- .ui-section-header--gap-lg { margin-bottom: 4rem; }
1607
-
1608
- .ui-section-eyebrow {
1609
- display: block;
1610
- font-size: .75rem;
1611
- font-weight: 600;
1612
- letter-spacing: .08em;
1613
- text-transform: uppercase;
1614
- color: var(--ui-accent);
1615
- margin: 0 0 2rem;
1616
- }
1617
-
1618
- .ui-section-title {
1619
- font-size: 2rem;
1620
- font-weight: 700;
1621
- line-height: 1.15;
1622
- letter-spacing: var(--ui-letter-spacing-display, -0.025em);
1623
- font-family: var(--ui-font-display, var(--ui-font));
1624
- color: var(--ui-text);
1625
- margin: 0 0 1.25rem;
1626
- }
1627
-
1628
- .ui-section-subtitle {
1629
- font-size: 1rem;
1630
- color: var(--ui-muted);
1631
- line-height: 1.65;
1632
- margin: 0;
1633
- max-width: 58ch;
1634
- }
1635
-
1636
- .ui-section-header--center .ui-section-subtitle { margin-left: auto; margin-right: auto; }
1637
-
1638
- @media (max-width: 640px) {
1639
- .ui-section-title { font-size: 1.5rem; }
1640
- .ui-section-header { margin-bottom: 2rem; }
1641
- }
1642
-
1643
- /* ─── CTA ────────────────────────────────────────────────────────────────────
1644
- Call-to-action block. Sits inside section() + container(). */
1645
- .ui-cta { text-align: center; }
1646
- .ui-cta--left { text-align: left; }
1647
-
1648
- .ui-cta-eyebrow {
1649
- display: block;
1650
- font-size: .75rem;
1651
- font-weight: 600;
1652
- letter-spacing: .08em;
1653
- text-transform: uppercase;
1654
- color: var(--ui-accent);
1655
- margin: 0 0 .75rem;
1656
- }
1657
-
1658
- .ui-cta-title {
1659
- font-size: 2.5rem;
1660
- font-weight: 700;
1661
- line-height: 1.1;
1662
- color: var(--ui-text);
1663
- margin: 0 0 1rem;
1664
- }
1665
-
1666
- .ui-cta-subtitle {
1667
- font-size: 1.05rem;
1668
- color: var(--ui-muted);
1669
- line-height: 1.65;
1670
- max-width: 56ch;
1671
- margin: 0 auto 2rem;
1672
- }
1673
-
1674
- .ui-cta--left .ui-cta-subtitle { margin-left: 0; }
1675
-
1676
- .ui-cta-actions {
1677
- display: flex;
1678
- gap: 1rem;
1679
- flex-wrap: wrap;
1680
- justify-content: center;
1681
- }
1682
-
1683
- .ui-cta--left .ui-cta-actions { justify-content: flex-start; }
1684
-
1685
- @media (max-width: 640px) {
1686
- .ui-cta-title { font-size: 1.75rem; }
1687
- .ui-cta-actions { flex-direction: column; align-items: stretch; }
1688
- }
1689
-
1690
- /* ─── Code Window ────────────────────────────────────────────────────────────
1691
- macOS-style window chrome around a <pre><code> block. */
1692
- .ui-code-window {
1693
- background: var(--ui-surface-2);
1694
- border: 1px solid var(--ui-border);
1695
- border-radius: var(--ui-radius);
1696
- overflow: hidden;
1697
- }
1698
-
1699
- .ui-code-window-chrome {
1700
- display: flex;
1701
- align-items: center;
1702
- gap: .4rem;
1703
- padding: .6rem 1rem;
1704
- background: var(--ui-surface);
1705
- border-bottom: 1px solid var(--ui-border);
1706
- }
1707
-
1708
- .ui-code-window-dot {
1709
- width: 10px;
1710
- height: 10px;
1711
- border-radius: 50%;
1712
- flex-shrink: 0;
1713
- }
1714
-
1715
- .ui-code-window-dot:nth-child(1) { background: #ff5f57; }
1716
- .ui-code-window-dot:nth-child(2) { background: #febc2e; }
1717
- .ui-code-window-dot:nth-child(3) { background: #28c840; }
1718
-
1719
- .ui-code-window-filename {
1720
- font-size: .75rem;
1721
- font-family: var(--ui-mono);
1722
- color: var(--ui-muted);
1723
- margin-left: .35rem;
1724
- }
1725
-
1726
- .ui-code-window-lang {
1727
- font-size: .7rem;
1728
- font-family: var(--ui-mono);
1729
- color: var(--ui-muted);
1730
- margin-left: auto;
1731
- }
1732
-
1733
- .ui-code-window-pre {
1734
- margin: 0;
1735
- padding: 1.25rem 1.5rem;
1736
- overflow-x: auto;
1737
- font-family: var(--ui-mono);
1738
- font-size: .85rem;
1739
- line-height: 1.7;
1740
- color: var(--ui-text);
1741
- tab-size: 2;
1742
- }
1743
-
1744
- .ui-code-window-code { font-family: inherit; }
1745
-
1746
- /* ─── Phone Frame ────────────────────────────────────────────────────────────
1747
- Realistic CSS mobile phone frame — body, dynamic island, side buttons,
1748
- home indicator. Drop any HTML into the content slot. */
1749
- .ui-phone {
1750
- position: relative;
1751
- display: inline-flex;
1752
- width: 260px;
1753
- background: linear-gradient(160deg, #1e1e28 0%, #141418 100%);
1754
- border-radius: 3rem;
1755
- border: 1.5px solid rgba(255, 255, 255, 0.1);
1756
- box-shadow:
1757
- 0 0 0 1px rgba(0, 0, 0, 0.8),
1758
- 0 2px 0 1px rgba(255, 255, 255, 0.05) inset,
1759
- 0 48px 96px rgba(0, 0, 0, 0.55),
1760
- 0 12px 32px rgba(0, 0, 0, 0.4);
1761
- padding: 12px;
1762
- }
1763
-
1764
- /* Side buttons */
1765
- .ui-phone-btn {
1766
- position: absolute;
1767
- background: linear-gradient(90deg, #1a1a22 0%, #26262e 100%);
1768
- border-radius: 2px;
1769
- }
1770
- .ui-phone-btn--mute { left: -3px; top: 88px; width: 3px; height: 28px; }
1771
- .ui-phone-btn--vol-up { left: -3px; top: 128px; width: 3px; height: 48px; }
1772
- .ui-phone-btn--vol-down { left: -3px; top: 186px; width: 3px; height: 48px; }
1773
- .ui-phone-btn--power { right: -3px; top: 140px; width: 3px; height: 64px; }
1774
-
1775
- /* Phone inner — holds screen + chrome */
1776
- .ui-phone-inner {
1777
- width: 100%;
1778
- background: #000;
1779
- border-radius: 2.5rem;
1780
- overflow: hidden;
1781
- display: flex;
1782
- flex-direction: column;
1783
- }
1784
-
1785
- /* Dynamic island */
1786
- .ui-phone-island {
1787
- flex-shrink: 0;
1788
- display: flex;
1789
- align-items: center;
1790
- justify-content: center;
1791
- height: 32px;
1792
- background: #000;
1793
- }
1794
- .ui-phone-camera {
1795
- display: block;
1796
- width: 10px;
1797
- height: 10px;
1798
- background: radial-gradient(circle at 35% 35%, #2a2a3a, #0a0a0a);
1799
- border-radius: 50%;
1800
- box-shadow: 0 0 0 1px rgba(255,255,255,0.06);
1801
- }
1802
-
1803
- /* Screen */
1804
- .ui-phone-screen {
1805
- flex: 1;
1806
- overflow: hidden;
1807
- }
1808
-
1809
- /* Home indicator */
1810
- .ui-phone-home {
1811
- flex-shrink: 0;
1812
- display: flex;
1813
- align-items: center;
1814
- justify-content: center;
1815
- height: 24px;
1816
- background: #000;
1817
- }
1818
- .ui-phone-home::after {
1819
- content: '';
1820
- display: block;
1821
- width: 80px;
1822
- height: 4px;
1823
- background: rgba(255, 255, 255, 0.25);
1824
- border-radius: 2px;
1825
- }
1826
-
1827
- /* Hover tilt — enabled by .ui-phone--tilt */
1828
- .ui-phone--tilt {
1829
- transform-style: preserve-3d;
1830
- transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 0.4s ease;
1831
- will-change: transform;
1832
- }
1833
- .ui-phone--tilt:hover {
1834
- transform: perspective(900px) rotateY(-8deg) rotateX(3deg);
1835
- box-shadow:
1836
- 0 0 0 1px rgba(0, 0, 0, 0.8),
1837
- 0 2px 0 1px rgba(255, 255, 255, 0.07) inset,
1838
- 8px 56px 120px rgba(0, 0, 0, 0.65),
1839
- 4px 16px 40px rgba(0, 0, 0, 0.5);
1840
- }
1841
-
1842
- /* ─── Footer ─────────────────────────────────────────────────────────────────
1843
- Site footer — logo, nav links, legal text. Stacks on mobile. */
1844
- .ui-footer {
1845
- padding: 3rem 1.5rem;
1846
- border-top: 1px solid var(--ui-border);
1847
- }
1848
-
1849
- .ui-footer-inner {
1850
- max-width: 1200px;
1851
- margin: 0 auto;
1852
- display: flex;
1853
- align-items: center;
1854
- gap: 2rem;
1855
- flex-wrap: wrap;
1856
- }
1857
-
1858
- .ui-footer-logo {
1859
- font-size: 1rem;
1860
- font-weight: 600;
1861
- color: var(--ui-text);
1862
- text-decoration: none;
1863
- flex-shrink: 0;
1864
- transition: color .15s;
1865
- }
1866
-
1867
- .ui-footer-logo:hover { color: var(--ui-accent); }
1868
- .ui-footer-logo:focus-visible {
1869
- outline: 2px solid var(--ui-accent);
1870
- outline-offset: 2px;
1871
- border-radius: 2px;
1872
- }
1873
-
1874
- .ui-footer-links {
1875
- display: flex;
1876
- gap: 1.5rem;
1877
- flex-wrap: wrap;
1878
- flex: 1;
1879
- }
1880
-
1881
- .ui-footer-link {
1882
- font-size: .875rem;
1883
- color: var(--ui-muted);
1884
- text-decoration: none;
1885
- transition: color .15s;
1886
- }
1887
-
1888
- .ui-footer-link:hover { color: var(--ui-text); }
1889
- .ui-footer-link:focus-visible {
1890
- outline: 2px solid var(--ui-accent);
1891
- outline-offset: 2px;
1892
- border-radius: 2px;
1893
- }
1894
-
1895
- .ui-footer-legal {
1896
- font-size: .8rem;
1897
- color: var(--ui-muted);
1898
- margin: 0 0 0 auto;
1899
- }
1900
-
1901
- @media (max-width: 640px) {
1902
- .ui-footer-inner { flex-direction: column; align-items: flex-start; gap: 1.25rem; }
1903
- .ui-footer-legal { margin-left: 0; }
1904
- .ui-footer-links { gap: 1rem; }
1905
- }
1906
-
1907
- /* ─── Footer — Rich variant ─────────────────────────────────────────────── */
1908
- .ui-footer--rich {
1909
- padding: 0;
1910
- border-top: none;
1911
- }
1912
-
1913
- .ui-footer--rich .ui-footer-top {
1914
- display: flex;
1915
- justify-content: space-between;
1916
- align-items: flex-start;
1917
- gap: 2rem;
1918
- padding: 3rem 2rem 2rem;
1919
- flex-wrap: wrap;
1920
- }
1921
-
1922
- .ui-footer--rich .ui-footer-logo {
1923
- font-size: 1.5rem;
1924
- }
1925
-
1926
- .ui-footer--rich .ui-footer-subscribe {
1927
- max-width: 480px;
1928
- flex: 1;
1929
- }
1930
-
1931
- .ui-footer-columns {
1932
- display: grid;
1933
- grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
1934
- gap: 2rem;
1935
- padding: 2rem 2rem;
1936
- border-top: 1px solid currentcolor;
1937
- opacity-on-border: 0.15;
1938
- }
1939
-
1940
- .ui-footer-col-title {
1941
- font-size: 0.6875rem;
1942
- font-weight: 600;
1943
- letter-spacing: 0.1em;
1944
- text-transform: uppercase;
1945
- margin: 0 0 1rem;
1946
- color: var(--ui-muted, currentcolor);
1947
- }
1948
-
1949
- .ui-footer-col-links {
1950
- list-style: none;
1951
- margin: 0;
1952
- padding: 0;
1953
- display: flex;
1954
- flex-direction: column;
1955
- gap: 0.6rem;
1956
- }
1957
-
1958
- .ui-footer-col-links a {
1959
- display: block;
1960
- padding: 0.3rem 0;
1961
- min-height: 24px;
1962
- font-size: 0.9375rem;
1963
- color: var(--ui-muted, inherit);
1964
- text-decoration: none;
1965
- transition: color 0.15s;
1966
- }
1967
- .ui-footer-col-links a:hover { color: var(--ui-text, currentcolor); }
1968
-
1969
- .ui-footer-wordmark {
1970
- padding: 1rem 1.5rem 0;
1971
- overflow: hidden;
1972
- }
1973
- .ui-footer-wordmark::after {
1974
- content: attr(data-wordmark);
1975
- display: block;
1976
- font-size: clamp(4rem, 16vw, 14rem);
1977
- font-weight: 700;
1978
- letter-spacing: -0.03em;
1979
- line-height: 0.9;
1980
- word-break: break-all;
1981
- }
1982
-
1983
- .ui-footer-legal-row {
1984
- display: flex;
1985
- gap: 1.5rem;
1986
- align-items: center;
1987
- flex-wrap: wrap;
1988
- padding: 1.5rem 2rem;
1989
- font-size: 0.8125rem;
1990
- color: var(--ui-muted, currentcolor);
1991
- border-top: 1px solid var(--ui-border, currentcolor);
1992
- }
1993
-
1994
- .ui-footer-legal-row a {
1995
- color: inherit;
1996
- text-decoration: none;
1997
- }
1998
- .ui-footer-legal-row a:hover { text-decoration: underline; }
1999
-
2000
- @media (max-width: 640px) {
2001
- .ui-footer--rich .ui-footer-top { flex-direction: column; }
2002
- .ui-footer-columns { grid-template-columns: repeat(2, 1fr); }
2003
- }
2004
-
2005
- /* ─── Icon wrapper ───────────────────────────────────────────────────────────
2006
- Wraps any icon in a tinted background shape.
2007
- bg: 'circle' → border-radius: 50% | bg: 'square' → var(--ui-radius) */
2008
-
2009
- .ui-icon-wrap {
2010
- display: inline-flex;
2011
- align-items: center;
2012
- justify-content: center;
2013
- padding: .55em;
2014
- flex-shrink: 0;
2015
- line-height: 1;
2016
- }
2017
-
2018
- .ui-icon-wrap--circle { border-radius: 50%; }
2019
- .ui-icon-wrap--square { border-radius: var(--ui-radius); }
2020
-
2021
- .ui-icon-wrap--accent { background: var(--ui-accent-dim); color: var(--ui-accent); }
2022
- .ui-icon-wrap--success { background: var(--ui-green-dim); color: var(--ui-green); }
2023
- .ui-icon-wrap--warning { background: var(--ui-yellow-dim); color: var(--ui-yellow); }
2024
- .ui-icon-wrap--error { background: var(--ui-red-dim); color: var(--ui-red); }
2025
- .ui-icon-wrap--muted { background: var(--ui-surface-2); color: var(--ui-muted); }
2026
-
2027
- /* ─── Switch ─────────────────────────────────────────────────────────────── */
2028
- .ui-switch-input {
2029
- position: absolute;
2030
- width: 1px;
2031
- height: 1px;
2032
- padding: 0;
2033
- margin: -1px;
2034
- overflow: hidden;
2035
- clip: rect(0,0,0,0);
2036
- border: 0;
2037
- }
2038
-
2039
- .ui-switch-label {
2040
- display: inline-flex;
2041
- align-items: center;
2042
- gap: .65rem;
2043
- cursor: pointer;
2044
- user-select: none;
2045
- }
2046
-
2047
- .ui-switch-label--disabled {
2048
- opacity: .5;
2049
- cursor: not-allowed;
2050
- }
2051
-
2052
- .ui-switch-track {
2053
- position: relative;
2054
- display: inline-flex;
2055
- align-items: center;
2056
- width: 3rem;
2057
- height: 1.75rem;
2058
- border-radius: 999px;
2059
- background: var(--ui-border);
2060
- transition: background .2s;
2061
- flex-shrink: 0;
2062
- }
2063
-
2064
- .ui-switch-thumb {
2065
- position: absolute;
2066
- left: .2rem;
2067
- width: 1.35rem;
2068
- height: 1.35rem;
2069
- border-radius: 50%;
2070
- background: #fff;
2071
- box-shadow: 0 1px 3px rgba(0,0,0,.3);
2072
- transition: transform .2s cubic-bezier(.34,1.56,.64,1), background .2s;
2073
- }
2074
-
2075
- .ui-switch-input:checked + .ui-switch-track {
2076
- background: var(--ui-accent);
2077
- }
2078
-
2079
- .ui-switch-input:checked + .ui-switch-track .ui-switch-thumb {
2080
- transform: translateX(1.25rem);
2081
- }
2082
-
2083
- .ui-switch-input:focus-visible + .ui-switch-track {
2084
- outline: 2px solid var(--ui-accent);
2085
- outline-offset: 2px;
2086
- }
2087
-
2088
- .ui-switch-text {
2089
- font-family: var(--ui-font);
2090
- font-size: .9rem;
2091
- color: var(--ui-text);
2092
- line-height: 1.4;
2093
- }
2094
-
2095
- /* ─── Radio ──────────────────────────────────────────────────────────────── */
2096
- .ui-radio-group {
2097
- border: 1px solid var(--ui-border);
2098
- border-radius: var(--ui-radius);
2099
- padding: 0;
2100
- margin: 0;
2101
- }
2102
-
2103
- .ui-radio-group-body {
2104
- display: flex;
2105
- flex-direction: column;
2106
- gap: var(--radio-gap, .75rem);
2107
- padding: 1.25rem;
2108
- }
2109
-
2110
- /* ─── Checkbox ───────────────────────────────────────────────────────────── */
2111
- .ui-checkbox {
2112
- display: inline-flex;
2113
- align-items: flex-start;
2114
- gap: .6rem;
2115
- cursor: pointer;
2116
- user-select: none;
2117
- }
2118
-
2119
- .ui-checkbox--disabled {
2120
- opacity: .5;
2121
- cursor: not-allowed;
2122
- }
2123
-
2124
- .ui-checkbox-input {
2125
- position: absolute;
2126
- width: 1px;
2127
- height: 1px;
2128
- padding: 0;
2129
- margin: -1px;
2130
- overflow: hidden;
2131
- clip: rect(0,0,0,0);
2132
- border: 0;
2133
- }
2134
-
2135
- .ui-checkbox-box {
2136
- position: relative;
2137
- display: inline-flex;
2138
- align-items: center;
2139
- justify-content: center;
2140
- width: 1.125rem;
2141
- height: 1.125rem;
2142
- border-radius: .25rem;
2143
- border: 2px solid var(--ui-border);
2144
- background: var(--ui-surface);
2145
- flex-shrink: 0;
2146
- margin-top: .125rem;
2147
- transition: border-color .15s, background .15s;
2148
- }
2149
-
2150
- .ui-checkbox-box::after {
2151
- content: '';
2152
- position: absolute;
2153
- width: .3rem;
2154
- height: .55rem;
2155
- border-right: 2px solid var(--ui-bg);
2156
- border-bottom: 2px solid var(--ui-bg);
2157
- transform: rotate(45deg) scale(0);
2158
- transform-origin: center;
2159
- margin-top: -.1rem;
2160
- opacity: 0;
2161
- transition: opacity .1s, transform .15s cubic-bezier(.34, 1.56, .64, 1);
2162
- }
2163
-
2164
- .ui-checkbox-input:checked + .ui-checkbox-box {
2165
- border-color: var(--ui-accent);
2166
- background: var(--ui-accent);
2167
- }
2168
-
2169
- .ui-checkbox-input:checked + .ui-checkbox-box::after {
2170
- opacity: 1;
2171
- transform: rotate(45deg) scale(1);
2172
- }
2173
-
2174
- .ui-checkbox-input:focus-visible + .ui-checkbox-box {
2175
- outline: 2px solid var(--ui-accent);
2176
- outline-offset: 2px;
2177
- }
2178
-
2179
- .ui-checkbox--error .ui-checkbox-box {
2180
- border-color: var(--ui-red);
2181
- }
2182
-
2183
- .ui-checkbox-label {
2184
- font-family: var(--ui-font);
2185
- font-size: .9rem;
2186
- color: var(--ui-text);
2187
- line-height: 1.4;
2188
- }
2189
-
2190
- /* ─── Radio ──────────────────────────────────────────────────────────────── */
2191
- .ui-radio {
2192
- display: inline-flex;
2193
- align-items: center;
2194
- gap: .6rem;
2195
- cursor: pointer;
2196
- user-select: none;
2197
- }
2198
-
2199
- .ui-radio--disabled {
2200
- opacity: .5;
2201
- cursor: not-allowed;
2202
- }
2203
-
2204
- .ui-radio-input {
2205
- position: absolute;
2206
- width: 1px;
2207
- height: 1px;
2208
- padding: 0;
2209
- margin: -1px;
2210
- overflow: hidden;
2211
- clip: rect(0,0,0,0);
2212
- border: 0;
2213
- }
2214
-
2215
- .ui-radio-dot {
2216
- position: relative;
2217
- display: inline-flex;
2218
- align-items: center;
2219
- justify-content: center;
2220
- width: 1.25rem;
2221
- height: 1.25rem;
2222
- border-radius: 50%;
2223
- border: 2px solid var(--ui-border);
2224
- background: var(--ui-surface);
2225
- flex-shrink: 0;
2226
- transition: border-color .15s, background .15s;
2227
- }
2228
-
2229
- .ui-radio-dot::after {
2230
- content: '';
2231
- width: .5rem;
2232
- height: .5rem;
2233
- border-radius: 50%;
2234
- background: var(--ui-bg);
2235
- opacity: 0;
2236
- transform: scale(0);
2237
- transition: opacity .15s, transform .2s cubic-bezier(.34,1.56,.64,1);
2238
- }
2239
-
2240
- .ui-radio-input:checked + .ui-radio-dot {
2241
- border-color: var(--ui-accent);
2242
- background: var(--ui-accent);
2243
- }
2244
-
2245
- .ui-radio-input:checked + .ui-radio-dot::after {
2246
- opacity: 1;
2247
- transform: scale(1);
2248
- }
2249
-
2250
- .ui-radio-input:focus-visible + .ui-radio-dot {
2251
- outline: 2px solid var(--ui-accent);
2252
- outline-offset: 2px;
2253
- }
2254
-
2255
- .ui-radio-label {
2256
- font-family: var(--ui-font);
2257
- font-size: .9rem;
2258
- color: var(--ui-text);
2259
- line-height: 1.4;
2260
- }
2261
-
2262
- .ui-radio-group--error .ui-radio-dot {
2263
- border-color: var(--ui-red);
2264
- }
2265
-
2266
- /* ─── Rating ─────────────────────────────────────────────────────────────── */
2267
- .ui-rating {
2268
- display: inline-flex;
2269
- align-items: center;
2270
- gap: .1em;
2271
- font-size: var(--rating-size, 1.5rem);
2272
- color: var(--ui-muted);
2273
- line-height: 1;
2274
- }
2275
-
2276
- /* Read-only stars */
2277
- .ui-rating-star--filled,
2278
- .ui-rating-star--half { color: var(--ui-yellow); }
2279
-
2280
- /* Interactive stars container — row-reverse makes high→low DOM order appear as 1…max */
2281
- .ui-rating-stars {
2282
- display: inline-flex;
2283
- flex-direction: row-reverse;
2284
- gap: .1em;
2285
- font-size: var(--rating-size, 1.5rem);
2286
- line-height: 1;
2287
- }
2288
-
2289
- /* Each input is nested inside its label — hidden but in the tab order */
2290
- .ui-rating-input {
2291
- position: absolute;
2292
- width: 1px;
2293
- height: 1px;
2294
- padding: 0;
2295
- margin: -1px;
2296
- overflow: hidden;
2297
- clip: rect(0,0,0,0);
2298
- border: 0;
2299
- }
2300
-
2301
- /* Star labels — only flex items, no invisible elements between them */
2302
- .ui-rating-stars .ui-rating-star {
2303
- color: var(--ui-muted);
2304
- cursor: pointer;
2305
- transition: color .1s;
2306
- user-select: none;
2307
- }
2308
-
2309
- /* Checked: colour the label containing the checked input + all DOM-subsequent
2310
- labels (= visually lower-numbered stars due to row-reverse) */
2311
- .ui-rating-stars .ui-rating-star:has(input:checked),
2312
- .ui-rating-stars .ui-rating-star:has(input:checked) ~ .ui-rating-star {
2313
- color: var(--ui-yellow);
2314
- }
2315
-
2316
- /* Hover: reset everything, then re-highlight up to the hovered star */
2317
- .ui-rating-stars:hover .ui-rating-star { color: var(--ui-muted); }
2318
- .ui-rating-stars .ui-rating-star:hover,
2319
- .ui-rating-stars .ui-rating-star:hover ~ .ui-rating-star { color: var(--ui-yellow); }
2320
-
2321
- /* Focus ring on the label when its input is keyboard-focused */
2322
- .ui-rating-star:focus-within {
2323
- outline: 2px solid var(--ui-accent);
2324
- outline-offset: 2px;
2325
- border-radius: 2px;
2326
- }
2327
-
2328
- /* Disabled */
2329
- fieldset[disabled] .ui-rating-star {
2330
- cursor: not-allowed;
2331
- opacity: .5;
2332
- }
2333
- fieldset[disabled] .ui-rating-stars:hover .ui-rating-star { color: revert; }
2334
- fieldset[disabled] .ui-rating-stars .ui-rating-star:hover,
2335
- fieldset[disabled] .ui-rating-stars .ui-rating-star:hover ~ .ui-rating-star { color: revert; }
2336
-
2337
- /* ─── Spinner ────────────────────────────────────────────────────────────── */
2338
- @keyframes ui-spin {
2339
- to { transform: rotate(360deg); }
2340
- }
2341
-
2342
- .ui-spinner {
2343
- display: inline-block;
2344
- width: var(--spinner-size, 1.5rem);
2345
- height: var(--spinner-size, 1.5rem);
2346
- border: 2px solid color-mix(in srgb, var(--spinner-color, var(--ui-accent)) 20%, transparent);
2347
- border-top-color: var(--spinner-color, var(--ui-accent));
2348
- border-radius: 50%;
2349
- animation: ui-spin .7s linear infinite;
2350
- flex-shrink: 0;
2351
- }
2352
-
2353
- /* ─── Progress ───────────────────────────────────────────────────────────── */
2354
- .ui-progress { width: 100%; }
2355
-
2356
- .ui-progress-header {
2357
- display: flex;
2358
- justify-content: space-between;
2359
- align-items: baseline;
2360
- margin-bottom: .4rem;
2361
- gap: 1rem;
2362
- }
2363
-
2364
- .ui-progress-label {
2365
- font-size: .8rem;
2366
- font-weight: 600;
2367
- color: var(--ui-text);
2368
- }
2369
-
2370
- .ui-progress-value {
2371
- font-size: .8rem;
2372
- color: var(--ui-muted);
2373
- font-variant-numeric: tabular-nums;
2374
- }
2375
-
2376
- .ui-progress-track {
2377
- width: 100%;
2378
- height: var(--progress-height, .5rem);
2379
- background: var(--ui-border);
2380
- border-radius: 999px;
2381
- overflow: hidden;
2382
- }
2383
-
2384
- .ui-progress-fill {
2385
- height: 100%;
2386
- border-radius: 999px;
2387
- transition: width .3s ease;
2388
- }
2389
-
2390
- /* Variants */
2391
- .ui-progress--accent .ui-progress-fill { background: var(--ui-accent); }
2392
- .ui-progress--success .ui-progress-fill { background: var(--ui-green); }
2393
- .ui-progress--warning .ui-progress-fill { background: var(--ui-yellow); }
2394
- .ui-progress--error .ui-progress-fill { background: var(--ui-red); }
2395
-
2396
- /* Indeterminate — animates a fill bar back and forth */
2397
- @keyframes ui-progress-indeterminate {
2398
- 0% { transform: translateX(-100%) scaleX(.4); }
2399
- 50% { transform: translateX( 60%) scaleX(.6); }
2400
- 100% { transform: translateX( 200%) scaleX(.4); }
2401
- }
2402
-
2403
- .ui-progress--indeterminate .ui-progress-fill {
2404
- width: 50%;
2405
- animation: ui-progress-indeterminate 1.4s ease infinite;
2406
- transform-origin: left center;
2407
- }
2408
-
2409
- /* ─── Slider ─────────────────────────────────────────────────────────────── */
2410
- .ui-slider {
2411
- width: 100%;
2412
- height: var(--ui-touch-min);
2413
- -webkit-appearance: none;
2414
- appearance: none;
2415
- background: transparent;
2416
- cursor: pointer;
2417
- padding: 0;
2418
- margin: 0;
2419
- }
2420
- .ui-slider::-webkit-slider-runnable-track {
2421
- height: 4px;
2422
- border-radius: 999px;
2423
- background: linear-gradient(
2424
- to right,
2425
- var(--ui-accent) 0% var(--slider-fill, 50%),
2426
- var(--ui-border) var(--slider-fill, 50%) 100%
2427
- );
2428
- }
2429
- .ui-slider::-moz-range-track {
2430
- height: 4px;
2431
- border-radius: 999px;
2432
- background: var(--ui-border);
2433
- }
2434
- .ui-slider::-moz-range-progress {
2435
- height: 4px;
2436
- border-radius: 999px;
2437
- background: var(--ui-accent);
2438
- }
2439
- .ui-slider::-webkit-slider-thumb {
2440
- -webkit-appearance: none;
2441
- width: 20px;
2442
- height: 20px;
2443
- border-radius: 50%;
2444
- background: var(--ui-accent);
2445
- margin-top: -8px;
2446
- box-shadow: 0 1px 4px rgba(0,0,0,.3);
2447
- transition: transform .15s;
2448
- }
2449
- .ui-slider::-moz-range-thumb {
2450
- width: 20px;
2451
- height: 20px;
2452
- border-radius: 50%;
2453
- background: var(--ui-accent);
2454
- border: none;
2455
- box-shadow: 0 1px 4px rgba(0,0,0,.3);
2456
- }
2457
- .ui-slider::-webkit-slider-thumb:hover { transform: scale(1.15); }
2458
- .ui-slider:focus-visible { outline: none; }
2459
- .ui-slider:focus-visible::-webkit-slider-thumb {
2460
- outline: 2px solid var(--ui-accent);
2461
- outline-offset: 3px;
2462
- }
2463
- .ui-slider:disabled { opacity: .5; cursor: not-allowed; }
2464
-
2465
- .ui-label--row {
2466
- display: flex;
2467
- justify-content: space-between;
2468
- align-items: baseline;
2469
- }
2470
- .ui-slider-output {
2471
- font-size: .8125rem;
2472
- color: var(--ui-muted);
2473
- font-variant-numeric: tabular-nums;
2474
- min-width: 3ch;
2475
- text-align: right;
2476
- }
2477
-
2478
- /* ─── File Upload ────────────────────────────────────────────────────────── */
2479
-
2480
- .ui-upload {
2481
- position: relative;
2482
- display: flex;
2483
- align-items: center;
2484
- justify-content: center;
2485
- padding: 2rem 1.5rem;
2486
- background: var(--ui-surface);
2487
- border: 1.5px dashed var(--ui-border);
2488
- border-radius: var(--ui-radius);
2489
- cursor: pointer;
2490
- transition: border-color .15s, background .15s;
2491
- outline: none;
2492
- user-select: none;
2493
- }
2494
-
2495
- .ui-upload:hover:not(.ui-upload--disabled),
2496
- .ui-upload:focus-visible {
2497
- border-color: var(--ui-accent);
2498
- background: color-mix(in srgb, var(--ui-accent) 5%, var(--ui-surface));
2499
- }
2500
-
2501
- .ui-upload--active {
2502
- border-color: var(--ui-accent);
2503
- background: color-mix(in srgb, var(--ui-accent) 8%, var(--ui-surface));
2504
- }
2505
-
2506
- .ui-upload--error { border-color: var(--ui-red); }
2507
- .ui-upload--selected { border-color: var(--ui-accent); }
2508
- .ui-upload--selected .ui-upload-text { color: var(--ui-text); font-weight: 500; }
2509
-
2510
- .ui-upload--disabled {
2511
- opacity: .5;
2512
- cursor: not-allowed;
2513
- }
2514
-
2515
- .ui-upload-body {
2516
- display: flex;
2517
- flex-direction: column;
2518
- align-items: center;
2519
- gap: .6rem;
2520
- pointer-events: none;
2521
- }
2522
-
2523
- .ui-upload-icon { color: var(--ui-muted); display: block; }
2524
-
2525
- .ui-upload:hover:not(.ui-upload--disabled) .ui-upload-icon,
2526
- .ui-upload--active .ui-upload-icon { color: var(--ui-accent); }
2527
-
2528
- .ui-upload-text {
2529
- font-size: .875rem;
2530
- color: var(--ui-muted);
2531
- text-align: center;
2532
- line-height: 1.5;
2533
- }
2534
-
2535
- .ui-upload-browse {
2536
- color: var(--ui-accent);
2537
- text-decoration: underline;
2538
- text-underline-offset: 2px;
2539
- }
2540
-
2541
- .ui-upload-input {
2542
- display: none;
2543
- }
2544
-
2545
- /* ─── Segmented ─────────────────────────────────────────────────────────── */
2546
- .ui-segmented {
2547
- display: inline-flex;
2548
- background: var(--ui-surface-2);
2549
- border-radius: var(--ui-radius);
2550
- padding: 3px;
2551
- gap: 2px;
2552
- }
2553
- .ui-segmented-input {
2554
- position: absolute;
2555
- width: 1px; height: 1px;
2556
- padding: 0; margin: -1px;
2557
- overflow: hidden; clip: rect(0,0,0,0); border: 0;
2558
- }
2559
- .ui-segmented-label {
2560
- display: inline-flex;
2561
- align-items: center;
2562
- padding: .4rem .9rem;
2563
- border-radius: calc(var(--ui-radius) - 2px);
2564
- font-size: .85rem;
2565
- font-weight: 500;
2566
- color: var(--ui-muted);
2567
- cursor: pointer;
2568
- user-select: none;
2569
- white-space: nowrap;
2570
- transition: background .15s, color .15s, box-shadow .15s;
2571
- }
2572
- .ui-segmented--sm .ui-segmented-label { font-size: .75rem; padding: .25rem .65rem; }
2573
- .ui-segmented--lg .ui-segmented-label { font-size: .95rem; padding: .55rem 1.1rem; }
2574
- .ui-segmented-input:checked + .ui-segmented-label {
2575
- background: var(--ui-surface);
2576
- color: var(--ui-text);
2577
- box-shadow: 0 1px 3px rgba(0,0,0,.25);
2578
- }
2579
- .ui-segmented-input:focus-visible + .ui-segmented-label {
2580
- outline: 2px solid var(--ui-accent);
2581
- outline-offset: 1px;
2582
- }
2583
-
2584
- /* ─── Breadcrumbs ────────────────────────────────────────────────────────── */
2585
- .ui-breadcrumbs-list {
2586
- display: flex;
2587
- flex-wrap: wrap;
2588
- align-items: center;
2589
- gap: .25rem;
2590
- list-style: none;
2591
- padding: 0;
2592
- margin: 0;
2593
- font-size: .85rem;
2594
- }
2595
- .ui-breadcrumbs-item {
2596
- display: flex;
2597
- align-items: center;
2598
- gap: .25rem;
2599
- }
2600
- .ui-breadcrumbs-link {
2601
- color: var(--ui-muted);
2602
- text-decoration: none;
2603
- transition: color .15s;
2604
- }
2605
- .ui-breadcrumbs-link:hover { color: var(--ui-text); }
2606
- .ui-breadcrumbs-current { color: var(--ui-text); }
2607
- .ui-breadcrumbs-sep { color: var(--ui-border); user-select: none; }
2608
-
2609
- /* ─── Stepper ────────────────────────────────────────────────────────────── */
2610
- .ui-stepper {
2611
- display: flex;
2612
- align-items: flex-start;
2613
- width: 100%;
2614
- }
2615
- .ui-stepper-item {
2616
- flex: 1;
2617
- display: flex;
2618
- flex-direction: column;
2619
- align-items: center;
2620
- position: relative;
2621
- }
2622
- .ui-stepper-item:not(:last-child)::after {
2623
- content: '';
2624
- position: absolute;
2625
- top: 13px;
2626
- left: 50%;
2627
- width: 100%;
2628
- height: 2px;
2629
- background: var(--ui-border);
2630
- }
2631
- .ui-stepper-item--complete:not(:last-child)::after { background: var(--ui-accent); }
2632
- .ui-stepper-dot {
2633
- position: relative;
2634
- z-index: 1;
2635
- width: 28px;
2636
- height: 28px;
2637
- border-radius: 50%;
2638
- display: flex;
2639
- align-items: center;
2640
- justify-content: center;
2641
- font-size: .75rem;
2642
- font-weight: 700;
2643
- background: var(--ui-surface-2);
2644
- border: 2px solid var(--ui-border);
2645
- color: var(--ui-muted);
2646
- transition: background .2s, border-color .2s, color .2s;
2647
- }
2648
- .ui-stepper-item--complete .ui-stepper-dot {
2649
- background: var(--ui-accent);
2650
- border-color: var(--ui-accent);
2651
- color: var(--ui-bg);
2652
- }
2653
- .ui-stepper-item--active .ui-stepper-dot {
2654
- border-color: var(--ui-accent);
2655
- color: var(--ui-accent);
2656
- }
2657
- .ui-stepper-label {
2658
- margin-top: .5rem;
2659
- font-size: .72rem;
2660
- color: var(--ui-muted);
2661
- text-align: center;
2662
- line-height: 1.3;
2663
- padding: 0 .25rem;
2664
- }
2665
- .ui-stepper-item--active .ui-stepper-label { color: var(--ui-text); font-weight: 600; }
2666
- .ui-stepper-item--complete .ui-stepper-label { color: var(--ui-muted); }
2667
-
2668
- /* ─── Image ──────────────────────────────────────────────────────────────── */
2669
- .ui-image {
2670
- display: block;
2671
- }
2672
- .ui-image-crop {
2673
- overflow: hidden;
2674
- border-radius: var(--ui-radius);
2675
- }
2676
- .ui-image-wrap {
2677
- display: block;
2678
- overflow: hidden;
2679
- border-radius: var(--ui-radius);
2680
- }
2681
- .ui-image-img--cover {
2682
- display: block;
2683
- width: 100%;
2684
- height: 100%;
2685
- object-fit: cover;
2686
- }
2687
- .ui-image-img {
2688
- display: block;
2689
- max-width: 100%;
2690
- height: auto;
2691
- }
2692
- .ui-image--rounded .ui-image-crop { border-radius: var(--ui-radius-lg, 1rem); }
2693
- .ui-image--rounded .ui-image-wrap { border-radius: var(--ui-radius-lg, 1rem); }
2694
- .ui-image--pill .ui-image-crop { border-radius: 999px; }
2695
- .ui-image--pill .ui-image-wrap { border-radius: 999px; }
2696
- .ui-image-caption {
2697
- margin: .5rem 0 0;
2698
- font-size: .8rem;
2699
- color: var(--ui-muted);
2700
- line-height: 1.5;
2701
- }
2702
-
2703
- /* ─── Pullquote ──────────────────────────────────────────────────────────── */
2704
- .ui-pullquote {
2705
- border-left: 3px solid var(--ui-accent);
2706
- padding: .75rem 0 .75rem 1.5rem;
2707
- margin: 0;
2708
- }
2709
- .ui-pullquote blockquote { margin: 0; padding: 0; }
2710
- .ui-pullquote-text {
2711
- font-size: 1.15rem;
2712
- line-height: 1.6;
2713
- color: var(--ui-text);
2714
- font-style: italic;
2715
- margin: 0;
2716
- }
2717
- .ui-pullquote--lg .ui-pullquote-text { font-size: 1.5rem; }
2718
- .ui-pullquote-cite {
2719
- display: block;
2720
- margin-top: .75rem;
2721
- font-size: .85rem;
2722
- color: var(--ui-muted);
2723
- font-style: normal;
2724
- }
2725
-
2726
- /* Editorial variant — centred large serif, no left border */
2727
- .ui-pullquote--editorial {
2728
- border-left: none;
2729
- padding: 4rem 1.5rem;
2730
- text-align: center;
2731
- }
2732
- .ui-pullquote--editorial .ui-pullquote-text {
2733
- font-size: clamp(1.5rem, 3.5vw, 2.25rem);
2734
- line-height: 1.4;
2735
- font-style: italic;
2736
- font-weight: 400;
2737
- max-width: 640px;
2738
- margin-left: auto;
2739
- margin-right: auto;
2740
- }
2741
- .ui-pullquote--editorial.ui-pullquote--lg .ui-pullquote-text {
2742
- font-size: clamp(1.75rem, 4vw, 3rem);
2743
- }
2744
- .ui-pullquote--editorial .ui-pullquote-cite {
2745
- text-align: center;
2746
- margin-top: 1.25rem;
2747
- font-size: 0.9375rem;
2748
- }
2749
-
2750
- /* ─── Prose ──────────────────────────────────────────────────────────────────
2751
- Typography wrapper for rich text: CMS output, markdown-rendered HTML,
2752
- blog/article bodies. Styles all descendant elements without class names. */
2753
- .ui-prose {
2754
- color: var(--ui-text);
2755
- line-height: 1.75;
2756
- font-size: 1rem;
2757
- }
2758
- .ui-prose--sm { font-size: .875rem; }
2759
- .ui-prose--lg { font-size: 1.125rem; }
2760
-
2761
- .ui-prose h1,
2762
- .ui-prose h2,
2763
- .ui-prose h3,
2764
- .ui-prose h4,
2765
- .ui-prose h5,
2766
- .ui-prose h6 {
2767
- color: var(--ui-text);
2768
- font-weight: 700;
2769
- line-height: 1.3;
2770
- margin-top: 2em;
2771
- margin-bottom: .6em;
2772
- }
2773
- .ui-prose h1 { font-size: 2rem; }
2774
- .ui-prose h2 { font-size: 1.5rem; }
2775
- .ui-prose h3 { font-size: 1.25rem; font-weight: 600; }
2776
- .ui-prose h4 { font-size: 1rem; font-weight: 600; }
2777
- .ui-prose h5 { font-size: .875rem; font-weight: 600; }
2778
- .ui-prose h6 { font-size: .875rem; font-weight: 600; color: var(--ui-muted); }
2779
-
2780
- .ui-prose :is(h1, h2, h3, h4, h5, h6):first-child { margin-top: 0; }
2781
-
2782
- .ui-prose p { margin-bottom: 1.25em; }
2783
- .ui-prose p:last-child { margin-bottom: 0; }
2784
-
2785
- .ui-prose a {
2786
- color: var(--ui-accent);
2787
- text-decoration: underline;
2788
- text-underline-offset: 2px;
2789
- }
2790
- .ui-prose a:hover { color: var(--ui-accent-hover); }
2791
-
2792
- .ui-prose strong { font-weight: 700; }
2793
- .ui-prose em { font-style: italic; }
2794
-
2795
- .ui-prose ul,
2796
- .ui-prose ol {
2797
- padding-left: 1.5em;
2798
- margin-bottom: 1.25em;
2799
- }
2800
- .ui-prose ul { list-style-type: disc; }
2801
- .ui-prose ol { list-style-type: decimal; }
2802
- .ui-prose ul ul { list-style-type: circle; }
2803
- .ui-prose ul.contains-task-list { list-style: none; padding-left: 0; }
2804
- .ui-prose li.task-list-item input[type="checkbox"] { margin-right: .4em; }
2805
- .ui-prose li { margin-bottom: .375em; }
2806
- .ui-prose li > ul,
2807
- .ui-prose li > ol { margin-top: .375em; margin-bottom: .375em; }
2808
-
2809
- .ui-prose blockquote {
2810
- border-left: 3px solid var(--ui-border);
2811
- padding: .5em 0 .5em 1.25em;
2812
- margin: 1.5em 0;
2813
- color: var(--ui-muted);
2814
- font-style: italic;
2815
- }
2816
- .ui-prose blockquote p { margin-bottom: 0; }
2817
-
2818
- .ui-prose code {
2819
- background: var(--ui-surface-2);
2820
- color: var(--ui-code-color);
2821
- padding: .1em .35em;
2822
- border-radius: var(--ui-radius-sm);
2823
- font-size: .875em;
2824
- font-family: var(--ui-mono);
2825
- }
2826
- .ui-prose pre {
2827
- background: var(--ui-surface-2);
2828
- border: 1px solid var(--ui-border);
2829
- border-radius: var(--ui-radius);
2830
- padding: 1em 1.25em;
2831
- overflow-x: auto;
2832
- margin-bottom: 1.25em;
2833
- font-family: var(--ui-mono);
2834
- font-size: .875em;
2835
- line-height: 1.7;
2836
- }
2837
- .ui-prose pre code {
2838
- background: none;
2839
- color: inherit;
2840
- padding: 0;
2841
- font-size: inherit;
2842
- }
2843
-
2844
- .ui-prose hr {
2845
- border: none;
2846
- border-top: 1px solid var(--ui-border);
2847
- margin: 2em 0;
2848
- }
2849
-
2850
- .ui-prose img {
2851
- max-width: 100%;
2852
- border-radius: var(--ui-radius);
2853
- height: auto;
2854
- }
2855
- .ui-prose figure { margin: 1.5em 0; }
2856
- .ui-prose figcaption {
2857
- font-size: .875em;
2858
- color: var(--ui-muted);
2859
- margin-top: .5em;
2860
- text-align: center;
2861
- }
2862
-
2863
- .ui-prose table {
2864
- width: 100%;
2865
- border-collapse: collapse;
2866
- margin-bottom: 1.25em;
2867
- font-size: .9375em;
2868
- }
2869
- .ui-prose th {
2870
- text-align: left;
2871
- padding: .5em .75em;
2872
- border-bottom: 2px solid var(--ui-border);
2873
- font-weight: 600;
2874
- color: var(--ui-text);
2875
- }
2876
- .ui-prose td {
2877
- padding: .5em .75em;
2878
- border-bottom: 1px solid var(--ui-border);
2879
- color: var(--ui-text);
2880
- }
2881
-
2882
- /* ─── Syntax highlighting tokens ────────────────────────────────────────────
2883
- Used by ui-prose pre code blocks rendered via @invisibleloop/pulse/md.
2884
- Dark theme defaults; light theme overrides below. */
2885
- :root {
2886
- --tok-kw: #c792ea;
2887
- --tok-str: #c3e88d;
2888
- --tok-cmt: #7a8a9a;
2889
- --tok-num: #f78c6c;
2890
- --tok-fn: #82aaff;
2891
- --tok-op: #89ddff;
2892
- --tok-punct: #7e8899;
2893
- }
2894
- .tok-kw { color: var(--tok-kw); }
2895
- .tok-str { color: var(--tok-str); }
2896
- .tok-cmt { color: var(--tok-cmt); font-style: italic; }
2897
- .tok-num { color: var(--tok-num); }
2898
- .tok-fn { color: var(--tok-fn); }
2899
- .tok-op { color: var(--tok-op); }
2900
- .tok-punct { color: var(--tok-punct); }
2901
-
2902
- /* ─── Light theme ────────────────────────────────────────────────────────────
2903
- Apply to any ancestor element: <body data-theme="light"> or .ui-theme-light
2904
- All --ui-* tokens are overridden; component markup stays identical. */
2905
- [data-theme="light"],
2906
- .ui-theme-light {
2907
- --ui-bg: var(--bg, #ffffff);
2908
- --ui-surface: var(--surface, #f8f8fc);
2909
- --ui-surface-2: var(--surface-2, #f0f0f8);
2910
- --ui-border: var(--border, #d8d8e8);
2911
- --ui-text: var(--text, #111118);
2912
- --ui-muted: var(--muted, #60607a);
2913
- --ui-accent: var(--accent, #6b5ce7);
2914
- --ui-accent-hover: var(--accent-hover, #5847d6);
2915
- --ui-accent-dim: var(--accent-dim, rgba(107, 92, 231, .12));
2916
- --ui-accent-text: var(--accent-text, #ffffff);
2917
- /* Inline code uses a slightly darker accent so it passes WCAG AA on --ui-surface-2 */
2918
- --ui-code-color: var(--code-color, #4a3db5);
2919
- --ui-green: var(--green, #166534);
2920
- --ui-green-dim: rgba(22, 163, 74, .12);
2921
- --ui-red: var(--red, #991b1b);
2922
- --ui-red-dim: rgba(220, 38, 38, .12);
2923
- --ui-yellow: #92400e;
2924
- --ui-yellow-dim: rgba(217, 119, 6, .12);
2925
- --ui-blue: #1e40af;
2926
- --ui-blue-dim: rgba( 30, 64, 175, .12);
2927
- --ui-nav-sticky-bg: rgba(255, 255, 255, .85);
2928
- --ui-muted-bg: var(--muted-bg, rgba(0, 0, 0, .04));
2929
- --ui-shadow: var(--shadow, 0 1px 3px rgba(0,0,0,.10), 0 1px 2px rgba(0,0,0,.06));
2930
- --tok-kw: #7c3aed;
2931
- --tok-str: #15803d;
2932
- --tok-cmt: #6b7280;
2933
- --tok-num: #c2410c;
2934
- --tok-fn: #1d4ed8;
2935
- --tok-op: #0891b2;
2936
- --tok-punct: #6b7280;
2937
- }
2938
-
2939
- /* ─── Vibe presets ────────────────────────────────────────────────────────────
2940
- meta.vibe sets data-vibe on <body>. Each vibe adjusts geometry and type
2941
- tokens without touching colour — pair with a custom theme.css for full
2942
- personality. All agents: set meta.vibe to get instant personality.
2943
-
2944
- warm — rounded, friendly, inviting (local businesses, wellness)
2945
- editorial — sharp, serif display, tight tracking (blogs, publications)
2946
- playful — very rounded, loose, energetic (kids, lifestyle, food)
2947
- minimal — razor-sharp, no shadows, refined (portfolios, luxury)
2948
- bold — impact headings, strong presence (agencies, startups)
2949
- brutalist — zero radius, oversized type, raw (art, fashion, counter-culture)
2950
- retro — slab serif, medium radius, warm (vintage, craft, nostalgia)
2951
- corporate — conservative geometry, tight tracking (B2B, finance, legal)
2952
- neon — futuristic mono headline, glow-ready (tech, gaming, crypto)
2953
- paper — organic radius, soft shadows, tactile (journals, bookshops) */
2954
-
2955
- [data-vibe="warm"] {
2956
- --ui-radius: 14px;
2957
- --ui-radius-sm: 8px;
2958
- --ui-letter-spacing-display: -0.01em;
2959
- }
2960
-
2961
- [data-vibe="editorial"] {
2962
- --ui-radius: 0px;
2963
- --ui-radius-sm: 0px;
2964
- --ui-font-display: Georgia, 'Times New Roman', serif;
2965
- --ui-letter-spacing-display: -0.04em;
2966
- }
2967
-
2968
- [data-vibe="playful"] {
2969
- --ui-radius: 22px;
2970
- --ui-radius-sm: 14px;
2971
- --ui-letter-spacing-display: 0em;
2972
- }
2973
-
2974
- [data-vibe="minimal"] {
2975
- --ui-radius: 2px;
2976
- --ui-radius-sm: 1px;
2977
- --ui-letter-spacing-display: 0.02em;
2978
- }
2979
-
2980
- [data-vibe="bold"] {
2981
- --ui-radius: 6px;
2982
- --ui-letter-spacing-display: -0.05em;
2983
- }
2984
-
2985
- [data-vibe="brutalist"] {
2986
- --ui-radius: 0px;
2987
- --ui-radius-sm: 0px;
2988
- --ui-font-display: 'Arial Black', 'Impact', sans-serif;
2989
- --ui-letter-spacing-display: -0.02em;
2990
- }
2991
-
2992
- [data-vibe="retro"] {
2993
- --ui-radius: 8px;
2994
- --ui-radius-sm: 4px;
2995
- --ui-font-display: 'Rockwell', 'Courier New', Georgia, serif;
2996
- --ui-letter-spacing-display: 0.01em;
2997
- }
2998
-
2999
- [data-vibe="corporate"] {
3000
- --ui-radius: 4px;
3001
- --ui-radius-sm: 2px;
3002
- --ui-letter-spacing-display: -0.01em;
3003
- }
3004
-
3005
- [data-vibe="neon"] {
3006
- --ui-radius: 3px;
3007
- --ui-radius-sm: 2px;
3008
- --ui-font-display: 'Courier New', 'Lucida Console', monospace;
3009
- --ui-letter-spacing-display: -0.03em;
3010
- }
3011
-
3012
- [data-vibe="paper"] {
3013
- --ui-radius: 10px;
3014
- --ui-radius-sm: 6px;
3015
- --ui-font-display: Georgia, 'Palatino Linotype', serif;
3016
- --ui-letter-spacing-display: -0.02em;
3017
- }
3018
-
3019
- /* Stat suffix — icon/rating appended to the value */
3020
- .ui-stat-suffix {
3021
- display: inline-flex;
3022
- align-items: center;
3023
- margin-left: 0.2em;
3024
- font-size: 0.6em;
3025
- vertical-align: middle;
3026
- line-height: 0;
3027
- }
3028
-