@invisibleloop/pulse 0.20.11 → 0.20.19

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,528 +0,0 @@
1
- /*
2
- * journey.css — Journey example
3
- *
4
- * Token definitions (hex values) + layout styles (var() only).
5
- * Deep-night dark palette with gold accent.
6
- */
7
-
8
- /* ─── Token definitions ──────────────────────────────────────── */
9
-
10
- :root {
11
- --journey-bg: #0A0A0F;
12
- --journey-surface: #12121A;
13
- --journey-border: #2A2A38;
14
- --journey-text: #F0EDE8;
15
- --journey-muted: #8A8A9C;
16
- --journey-gold: #C9A96E;
17
- --journey-gold-dim: #8A6F42;
18
-
19
- /* Translucent shells — used once each; defined as tokens for hex-free app styles */
20
- --journey-nav-bg: rgba(10, 10, 15, 0.7);
21
- --journey-nav-border: rgba(42, 42, 56, 0.6);
22
-
23
- /* Pulse-ui token overrides — bare tokens cascade into --ui-* */
24
- --bg: #0A0A0F;
25
- --surface: #1A1A26;
26
- --text: #F0EDE8;
27
- --muted: #8A8A9C;
28
- --border: #2A2A38;
29
- --accent: #C9A96E;
30
- }
31
-
32
- /* ─── Base ───────────────────────────────────────────────────── */
33
-
34
- *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
35
-
36
- body {
37
- background: var(--journey-bg);
38
- color: var(--journey-text);
39
- font-family: var(--ui-font, system-ui, sans-serif);
40
- line-height: 1.6;
41
- }
42
-
43
- /* ─── Skip link ──────────────────────────────────────────────── */
44
-
45
- .j-skip-link {
46
- position: absolute;
47
- left: -9999px;
48
- top: var(--ui-space-2);
49
- z-index: 999;
50
- padding: var(--ui-space-2) var(--ui-space-4);
51
- background: var(--journey-gold);
52
- color: var(--journey-bg);
53
- font-size: var(--ui-text-sm);
54
- font-weight: 700;
55
- text-decoration: none;
56
- }
57
-
58
- .j-skip-link:focus {
59
- left: var(--ui-space-4);
60
- }
61
-
62
- .j-visually-hidden {
63
- position: absolute;
64
- width: 1px;
65
- height: 1px;
66
- padding: 0;
67
- margin: -1px;
68
- overflow: hidden;
69
- clip: rect(0, 0, 0, 0);
70
- white-space: nowrap;
71
- border: 0;
72
- }
73
-
74
- /* ─── Nav ────────────────────────────────────────────────────── */
75
-
76
- .j-nav {
77
- position: fixed;
78
- top: 0;
79
- left: 0;
80
- right: 0;
81
- z-index: 100;
82
- height: 64px;
83
- display: flex;
84
- align-items: center;
85
- justify-content: space-between;
86
- padding: 0 var(--ui-space-8);
87
- background: var(--journey-nav-bg);
88
- backdrop-filter: blur(12px);
89
- -webkit-backdrop-filter: blur(12px);
90
- border-bottom: 1px solid var(--journey-nav-border);
91
- }
92
-
93
- .j-nav-wordmark {
94
- font-size: var(--ui-text-sm);
95
- font-weight: 700;
96
- letter-spacing: 0.18em;
97
- text-transform: uppercase;
98
- color: var(--journey-text);
99
- text-decoration: none;
100
- }
101
-
102
- /* ─── Hero + Timeline split ──────────────────────────────────── */
103
-
104
- .j-hero-split {
105
- display: grid;
106
- grid-template-columns: 1fr 1fr;
107
- min-height: 100svh;
108
- }
109
-
110
- /* ─── Hero ───────────────────────────────────────────────────── */
111
-
112
- .j-hero {
113
- display: flex;
114
- flex-direction: column;
115
- justify-content: center;
116
- padding: 128px var(--ui-space-8) var(--ui-space-16);
117
- position: relative;
118
- overflow: hidden;
119
- border-right: 1px solid var(--journey-border);
120
- }
121
-
122
- .j-hero-eyebrow {
123
- font-size: var(--ui-text-xs);
124
- letter-spacing: 0.2em;
125
- text-transform: uppercase;
126
- color: var(--journey-gold);
127
- margin-bottom: var(--ui-space-6);
128
- }
129
-
130
- .j-hero-title {
131
- font-size: clamp(3.5rem, 11vw, 9.5rem);
132
- font-weight: 800;
133
- line-height: 0.92;
134
- letter-spacing: -0.04em;
135
- color: var(--journey-text);
136
- max-width: 14ch;
137
- }
138
-
139
- .j-hero-title em {
140
- font-style: normal;
141
- color: var(--journey-gold);
142
- }
143
-
144
- .j-hero-sub {
145
- margin-top: var(--ui-space-8);
146
- font-size: var(--ui-text-lg);
147
- color: var(--journey-muted);
148
- max-width: 42ch;
149
- line-height: 1.5;
150
- }
151
-
152
- .j-hero-cta {
153
- margin-top: var(--ui-space-10);
154
- display: flex;
155
- align-items: center;
156
- gap: var(--ui-space-6);
157
- }
158
-
159
- .j-btn-primary {
160
- display: inline-flex;
161
- align-items: center;
162
- gap: var(--ui-space-2);
163
- background: var(--journey-gold);
164
- color: var(--journey-bg);
165
- font-weight: 700;
166
- font-size: var(--ui-text-sm);
167
- letter-spacing: 0.05em;
168
- text-transform: uppercase;
169
- text-decoration: none;
170
- padding: var(--ui-space-4) var(--ui-space-8);
171
- white-space: nowrap;
172
- transition: opacity 0.2s;
173
- }
174
-
175
- .j-btn-primary:hover {
176
- opacity: 0.85;
177
- }
178
-
179
- .j-btn-ghost {
180
- display: inline-flex;
181
- align-items: center;
182
- gap: var(--ui-space-2);
183
- color: var(--journey-muted);
184
- font-size: var(--ui-text-sm);
185
- letter-spacing: 0.05em;
186
- text-decoration: none;
187
- white-space: nowrap;
188
- transition: color 0.2s;
189
- }
190
-
191
- .j-btn-ghost:hover {
192
- color: var(--journey-text);
193
- }
194
-
195
- .j-hero-scroll {
196
- position: absolute;
197
- bottom: var(--ui-space-8);
198
- left: var(--ui-space-8);
199
- display: none;
200
- align-items: center;
201
- gap: var(--ui-space-3);
202
- font-size: var(--ui-text-xs);
203
- letter-spacing: 0.15em;
204
- text-transform: uppercase;
205
- color: var(--journey-muted);
206
- }
207
-
208
- .j-hero-line {
209
- width: 2rem;
210
- height: 1px;
211
- background: var(--journey-border);
212
- }
213
-
214
- /* ─── Timeline section ───────────────────────────────────────── */
215
-
216
- .j-timeline-section {
217
- padding: 128px var(--ui-space-8) var(--ui-space-16);
218
- position: sticky;
219
- top: 0;
220
- height: 100svh;
221
- overflow-y: auto;
222
- scrollbar-width: none;
223
- }
224
-
225
- .j-timeline-section::-webkit-scrollbar {
226
- display: none;
227
- }
228
-
229
- .j-section-label {
230
- font-size: var(--ui-text-xs);
231
- letter-spacing: 0.2em;
232
- text-transform: uppercase;
233
- color: var(--journey-gold);
234
- margin-bottom: var(--ui-space-16);
235
- }
236
-
237
- .j-timeline {
238
- position: relative;
239
- }
240
-
241
- /* Centre thread */
242
- .j-timeline::before {
243
- content: '';
244
- position: absolute;
245
- left: 50%;
246
- top: 0;
247
- bottom: 0;
248
- width: 1px;
249
- background: linear-gradient(
250
- to bottom,
251
- transparent,
252
- var(--journey-gold-dim) 5%,
253
- var(--journey-gold-dim) 95%,
254
- transparent
255
- );
256
- transform: translateX(-50%);
257
- }
258
-
259
- .j-tl-item {
260
- display: flex;
261
- align-items: flex-start;
262
- margin-bottom: var(--ui-space-10);
263
- position: relative;
264
- }
265
-
266
- /* Dot on centre thread */
267
- .j-tl-item::before {
268
- content: '';
269
- position: absolute;
270
- left: 50%;
271
- top: 1.25rem;
272
- width: 8px;
273
- height: 8px;
274
- border-radius: 50%;
275
- background: var(--journey-gold);
276
- border: 2px solid var(--journey-bg);
277
- transform: translateX(-50%);
278
- box-shadow: 0 0 0 1px var(--journey-gold);
279
- z-index: 1;
280
- }
281
-
282
- /* Odd: card on left half */
283
- .j-tl-item:nth-child(odd) {
284
- justify-content: flex-start;
285
- }
286
- .j-tl-item:nth-child(odd) .j-tl-card {
287
- width: calc(50% - var(--ui-space-8));
288
- margin-right: var(--ui-space-8);
289
- }
290
-
291
- /* Even: card on right half */
292
- .j-tl-item:nth-child(even) {
293
- justify-content: flex-end;
294
- }
295
- .j-tl-item:nth-child(even) .j-tl-card {
296
- width: calc(50% - var(--ui-space-8));
297
- margin-left: var(--ui-space-8);
298
- }
299
-
300
- .j-tl-card {
301
- background: var(--journey-surface);
302
- border: 1px solid var(--journey-border);
303
- overflow: hidden;
304
- transition: border-color 0.2s;
305
- }
306
-
307
- .j-tl-card:not(.j-tl-card--image) {
308
- padding: var(--ui-space-5);
309
- }
310
-
311
- .j-tl-card:hover {
312
- border-color: var(--journey-gold-dim);
313
- }
314
-
315
- .j-tl-image {
316
- display: block;
317
- width: 100%;
318
- aspect-ratio: 16 / 9;
319
- object-fit: cover;
320
- }
321
-
322
- .j-tl-content {
323
- padding: var(--ui-space-5);
324
- }
325
-
326
- .j-tl-year {
327
- font-size: var(--ui-text-xs);
328
- letter-spacing: 0.15em;
329
- text-transform: uppercase;
330
- color: var(--journey-gold);
331
- margin-bottom: var(--ui-space-2);
332
- }
333
-
334
- .j-tl-title {
335
- font-size: var(--ui-text-lg);
336
- font-weight: 700;
337
- color: var(--journey-text);
338
- letter-spacing: -0.02em;
339
- margin-bottom: var(--ui-space-2);
340
- }
341
-
342
- .j-tl-body {
343
- font-size: var(--ui-text-sm);
344
- color: var(--journey-muted);
345
- line-height: 1.6;
346
- }
347
-
348
- .j-tl-tag {
349
- display: inline-flex;
350
- align-items: center;
351
- gap: var(--ui-space-1);
352
- margin-top: var(--ui-space-3);
353
- font-size: 0.65rem;
354
- letter-spacing: 0.12em;
355
- text-transform: uppercase;
356
- color: var(--journey-gold-dim);
357
- border: 1px solid var(--journey-border);
358
- padding: 2px var(--ui-space-2);
359
- }
360
-
361
- /* ─── Features strip ─────────────────────────────────────────── */
362
-
363
- .j-features {
364
- border-top: 1px solid var(--journey-border);
365
- border-bottom: 1px solid var(--journey-border);
366
- padding: var(--ui-space-12) var(--ui-space-8);
367
- display: grid;
368
- grid-template-columns: repeat(3, 1fr);
369
- gap: var(--ui-space-8);
370
- }
371
-
372
- .j-feature-label {
373
- display: flex;
374
- align-items: center;
375
- gap: var(--ui-space-2);
376
- font-size: var(--ui-text-xs);
377
- letter-spacing: 0.15em;
378
- text-transform: uppercase;
379
- color: var(--journey-gold);
380
- margin-bottom: var(--ui-space-2);
381
- }
382
-
383
- .j-feature-body {
384
- font-size: var(--ui-text-sm);
385
- color: var(--journey-muted);
386
- line-height: 1.5;
387
- }
388
-
389
- /* ─── CTA section ────────────────────────────────────────────── */
390
-
391
- .j-cta {
392
- padding: var(--ui-space-16) var(--ui-space-8);
393
- text-align: center;
394
- background: var(--journey-surface);
395
- border-top: 1px solid var(--journey-border);
396
- }
397
-
398
- .j-cta-eyebrow {
399
- font-size: var(--ui-text-xs);
400
- letter-spacing: 0.2em;
401
- text-transform: uppercase;
402
- color: var(--journey-muted);
403
- margin-bottom: var(--ui-space-6);
404
- }
405
-
406
- .j-cta-title {
407
- font-size: clamp(2rem, 5vw, 4rem);
408
- font-weight: 800;
409
- letter-spacing: -0.03em;
410
- line-height: 1.05;
411
- color: var(--journey-text);
412
- margin-bottom: var(--ui-space-8);
413
- }
414
-
415
- .j-cta-title em {
416
- font-style: normal;
417
- color: var(--journey-gold);
418
- }
419
-
420
- .j-cta-badges {
421
- display: flex;
422
- align-items: center;
423
- justify-content: center;
424
- gap: var(--ui-space-4);
425
- }
426
-
427
- /* ─── Footer ─────────────────────────────────────────────────── */
428
-
429
- .j-footer {
430
- padding: var(--ui-space-8);
431
- display: flex;
432
- align-items: center;
433
- justify-content: space-between;
434
- border-top: 1px solid var(--journey-border);
435
- }
436
-
437
- .j-footer-word {
438
- display: flex;
439
- align-items: center;
440
- gap: var(--ui-space-2);
441
- font-size: var(--ui-text-xs);
442
- letter-spacing: 0.18em;
443
- text-transform: uppercase;
444
- color: var(--journey-muted);
445
- }
446
-
447
- .j-footer-links {
448
- display: flex;
449
- gap: var(--ui-space-6);
450
- }
451
-
452
- .j-footer-links a {
453
- font-size: var(--ui-text-xs);
454
- letter-spacing: 0.1em;
455
- text-transform: uppercase;
456
- color: var(--journey-muted);
457
- text-decoration: none;
458
- transition: color 0.2s;
459
- }
460
-
461
- .j-footer-links a:hover {
462
- color: var(--journey-text);
463
- }
464
-
465
- /* ─── Responsive ─────────────────────────────────────────────── */
466
-
467
- @media (max-width: 768px) {
468
- .j-hero-split {
469
- grid-template-columns: 1fr;
470
- }
471
-
472
- .j-hero {
473
- min-height: auto;
474
- border-right: none;
475
- border-bottom: 1px solid var(--journey-border);
476
- padding: 104px var(--ui-space-6) var(--ui-space-8);
477
- }
478
-
479
- .j-timeline-section {
480
- position: static;
481
- height: auto;
482
- overflow-y: visible;
483
- padding: var(--ui-space-10) var(--ui-space-6);
484
- }
485
-
486
- .j-hero-scroll {
487
- display: flex;
488
- position: static;
489
- margin-top: var(--ui-space-8);
490
- }
491
-
492
- .j-timeline::before {
493
- left: 0;
494
- transform: none;
495
- }
496
-
497
- .j-tl-item::before {
498
- left: 0;
499
- transform: translateX(-50%);
500
- }
501
-
502
- .j-tl-item:nth-child(odd),
503
- .j-tl-item:nth-child(even) {
504
- justify-content: flex-start;
505
- }
506
-
507
- .j-tl-item:nth-child(odd) .j-tl-card,
508
- .j-tl-item:nth-child(even) .j-tl-card {
509
- width: 100%;
510
- margin-left: var(--ui-space-6);
511
- margin-right: 0;
512
- }
513
-
514
- .j-features {
515
- grid-template-columns: 1fr;
516
- gap: var(--ui-space-6);
517
- }
518
-
519
- .j-footer {
520
- flex-direction: column;
521
- gap: var(--ui-space-4);
522
- text-align: center;
523
- }
524
-
525
- .j-nav {
526
- padding: 0 var(--ui-space-6);
527
- }
528
- }
@@ -1,186 +0,0 @@
1
- /**
2
- * Pulse — Journey example
3
- *
4
- * Demonstrates:
5
- * - Mode B creative override — raw HTML throughout, no structural components
6
- * - Split-screen layout: sticky hero left / scrollable timeline right (100svh grid)
7
- * - appBadge component from @invisibleloop/pulse/ui
8
- * - Deep-night palette (#0A0A0F) with gold (#C9A96E) accent
9
- * - Alternating left/right timeline cards with centred thread + connector dots
10
- * - calc(50% - var(--ui-space-8)) pattern for half-width timeline cards
11
- * - Sticky positioned timeline column with overflow-y: auto + scrollbar-width: none
12
- * - Frosted glass nav: rgba translucency + backdrop-filter blur
13
- * - Skip link, visually-hidden headings, section aria-labelledby — full a11y
14
- * - Mobile responsive: stacks vertically, thread moves left, full-width cards
15
- * - iconTag, iconPlus, iconSend, iconArrowDown, iconFeather from icons.js
16
- * - picsum.photos/id/* for stable prototype images
17
- *
18
- * Run: node examples/dev.server.js → http://localhost:3001/journey
19
- */
20
-
21
- import { appBadge } from '../src/ui/index.js'
22
- import { iconTag, iconPlus, iconSend, iconArrowDown, iconFeather } from '../src/ui/icons.js'
23
-
24
- // ---------------------------------------------------------------------------
25
- // Timeline data
26
- // ---------------------------------------------------------------------------
27
-
28
- const timelineEvents = [
29
- {
30
- year: '2019',
31
- title: 'First Day in the City',
32
- body: 'Packed everything into one suitcase. The apartment was smaller than expected. The feeling was not.',
33
- tag: 'Milestone',
34
- image: { src: '/images/journey/29.jpg', alt: 'City street view' },
35
- },
36
- {
37
- year: '2020',
38
- title: 'Learning to Stay Still',
39
- body: 'The world paused. Finished three books. Started painting. Discovered what quiet actually sounds like.',
40
- tag: 'Reflection',
41
- },
42
- {
43
- year: '2021',
44
- title: 'The Road Trip',
45
- body: '4,200 miles across eleven states. Every diner looks the same after midnight. Every sunrise does not.',
46
- tag: 'Adventure',
47
- image: { src: '/images/journey/178.jpg', alt: 'Open road through a landscape' },
48
- },
49
- {
50
- year: '2022',
51
- title: 'Said Yes',
52
- body: 'On a Tuesday. In the kitchen. No ring yet, just the question and the answer and the rest of our lives.',
53
- tag: 'Love',
54
- },
55
- {
56
- year: '2024',
57
- title: 'This Is Home Now',
58
- body: 'The boxes are gone. The walls have pictures. The cat has a name. The journey continues.',
59
- tag: 'Present',
60
- },
61
- ]
62
-
63
- // ---------------------------------------------------------------------------
64
- // Timeline card helper
65
- // ---------------------------------------------------------------------------
66
-
67
- const tlCard = ({ year, title, body, tag, image }) => `
68
- <div class="j-tl-card${image ? ' j-tl-card--image' : ''}">
69
- ${image ? `<img class="j-tl-image" src="${image.src}" alt="${image.alt}" width="600" height="340" loading="lazy" decoding="async">` : ''}
70
- <div class="j-tl-content">
71
- <p class="j-tl-year">${year}</p>
72
- <h3 class="j-tl-title">${title}</h3>
73
- <p class="j-tl-body">${body}</p>
74
- <span class="j-tl-tag">${iconTag({ size: 10 })}${tag}</span>
75
- </div>
76
- </div>
77
- `
78
-
79
- // ---------------------------------------------------------------------------
80
- // Spec
81
- // ---------------------------------------------------------------------------
82
-
83
- export default {
84
- route: '/journey',
85
-
86
- meta: {
87
- title: 'Journey \u2014 Your story, in order',
88
- description: 'Plot your life\u2019s journey. Map events, milestones, and memories on a beautiful timeline.',
89
- styles: ['/pulse-ui.css', '/examples/journey.css'],
90
- theme: 'dark',
91
- },
92
-
93
- view: () => `
94
- <a href="#main-content" class="j-skip-link">Skip to main content</a>
95
-
96
- <header role="banner">
97
- <nav class="j-nav" aria-label="Site navigation">
98
- <a href="/journey" class="j-nav-wordmark" aria-label="Journey \u2014 home">Journey</a>
99
- ${appBadge({ store: 'apple', href: '#download' })}
100
- </nav>
101
- </header>
102
-
103
- <main id="main-content">
104
-
105
- <!-- Hero + Timeline split -->
106
- <div class="j-hero-split">
107
-
108
- <!-- Hero -->
109
- <section class="j-hero" aria-labelledby="journey-hero-title">
110
- <p class="j-hero-eyebrow" aria-hidden="true">Your story \u00b7 In order</p>
111
- <h1 class="j-hero-title" id="journey-hero-title">
112
- Every<br>moment<br><em>matters.</em>
113
- </h1>
114
- <p class="j-hero-sub">
115
- Journey is a beautiful timeline for your life. Plot events, mark milestones,
116
- and explore the story only you can tell.
117
- </p>
118
- <div class="j-hero-cta">
119
- <a href="#download" class="j-btn-primary">
120
- Download free
121
- </a>
122
- <a href="#journey-timeline" class="j-btn-ghost">
123
- See how it works ${iconArrowDown({ size: 14 })}
124
- </a>
125
- </div>
126
- <div class="j-hero-scroll" aria-hidden="true">
127
- <span class="j-hero-line"></span>
128
- <span>Scroll to explore</span>
129
- </div>
130
- </section>
131
-
132
- <!-- Timeline demo -->
133
- <section class="j-timeline-section" id="journey-timeline" aria-labelledby="journey-timeline-heading">
134
- <p class="j-section-label" aria-hidden="true">01 \u2014 Your timeline</p>
135
- <h2 class="j-visually-hidden" id="journey-timeline-heading">Example journey timeline</h2>
136
- <div class="j-timeline" role="list">
137
- ${timelineEvents.map(ev => `
138
- <div class="j-tl-item" role="listitem">
139
- ${tlCard(ev)}
140
- </div>
141
- `).join('')}
142
- </div>
143
- </section>
144
-
145
- </div><!-- end j-hero-split -->
146
-
147
- <!-- Features -->
148
- <section class="j-features" aria-labelledby="journey-features-heading">
149
- <h2 class="j-visually-hidden" id="journey-features-heading">Features</h2>
150
- <div>
151
- <p class="j-feature-label">${iconPlus({ size: 12 })}Plot your path</p>
152
- <p class="j-feature-body">Add any event \u2014 big or small \u2014 and watch your story take shape along a living timeline.</p>
153
- </div>
154
- <div>
155
- <p class="j-feature-label">${iconTag({ size: 12 })}Tag &amp; explore</p>
156
- <p class="j-feature-body">Organise moments by theme, mood, or chapter. Filter your timeline to find any memory instantly.</p>
157
- </div>
158
- <div>
159
- <p class="j-feature-label">${iconSend({ size: 12 })}Share your journey</p>
160
- <p class="j-feature-body">Export a beautiful visual timeline to share with the people who made it worth living.</p>
161
- </div>
162
- </section>
163
-
164
- <!-- CTA / Download -->
165
- <section class="j-cta" id="download" aria-labelledby="journey-cta-heading">
166
- <p class="j-cta-eyebrow">Available now \u00b7 iOS</p>
167
- <h2 class="j-cta-title" id="journey-cta-heading">
168
- Begin your<br><em>journey</em> today.
169
- </h2>
170
- <div class="j-cta-badges">
171
- ${appBadge({ store: 'apple', href: '#' })}
172
- </div>
173
- </section>
174
-
175
- </main>
176
-
177
- <footer class="j-footer" role="contentinfo">
178
- <span class="j-footer-word">${iconFeather({ size: 12 })} Journey &copy; 2025</span>
179
- <nav class="j-footer-links" aria-label="Footer navigation">
180
- <a href="#privacy">Privacy</a>
181
- <a href="#terms">Terms</a>
182
- <a href="#contact">Contact</a>
183
- </nav>
184
- </footer>
185
- `,
186
- }