@invisibleloop/pulse 0.12.3 → 0.14.2

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 (181) hide show
  1. package/.claude/commands/build-page.md +5 -1
  2. package/.claude/commands/verify.md +31 -17
  3. package/.claude/pulse-checklist.md +21 -1
  4. package/.github/workflows/publish.yml +1 -0
  5. package/.pulse-verified +1 -0
  6. package/CLAUDE.md +56 -15
  7. package/docs/.claude/commands/verify.md +4 -0
  8. package/docs/.claude/pulse-checklist.md +20 -2
  9. package/docs/public/.pulse-ui-version +1 -1
  10. package/docs/public/andypixel.css +237 -0
  11. package/docs/public/bookworms.css +422 -0
  12. package/docs/public/coutumes.css +584 -0
  13. package/docs/public/images/bookworms/hero-books.jpg +0 -0
  14. package/docs/public/images/bookworms/how-we-read-now.jpg +0 -0
  15. package/docs/public/images/bookworms/lantern-keepers.jpg +0 -0
  16. package/docs/public/images/bookworms/provincial-bookseller.jpg +0 -0
  17. package/docs/public/images/journey/178.jpg +0 -0
  18. package/docs/public/images/journey/29.jpg +0 -0
  19. package/docs/public/images/retrowheels/hero.jpg +0 -0
  20. package/docs/public/images/shop/devbook-pro.jpg +0 -0
  21. package/docs/public/images/suzukibento/1015.jpg +0 -0
  22. package/docs/public/images/suzukibento/1025.jpg +0 -0
  23. package/docs/public/images/suzukibento/1043.jpg +0 -0
  24. package/docs/public/images/suzukibento/1059.jpg +0 -0
  25. package/docs/public/images/suzukibento/1062.jpg +0 -0
  26. package/docs/public/images/suzukibento/1084.jpg +0 -0
  27. package/docs/public/images/swish/1469334031218-e382a71b716b.jpg +0 -0
  28. package/docs/public/images/swish/1483985988355-763728e1935b.jpg +0 -0
  29. package/docs/public/images/swish/1485518882345-15568b007407.jpg +0 -0
  30. package/docs/public/images/swish/1490481651871-ab68de25d43d.jpg +0 -0
  31. package/docs/public/images/swish/1496747611176-843222e1e57c.jpg +0 -0
  32. package/docs/public/images/swish/1502716119720-b23a93e5fe1b.jpg +0 -0
  33. package/docs/public/images/swish/1539109136881-3be0616acf4b.jpg +0 -0
  34. package/docs/public/images/swish/1551803091-e20673f15770.jpg +0 -0
  35. package/docs/public/images/swish/1558769132-cb1aea458c5e.jpg +0 -0
  36. package/docs/public/images/swish/1572804013309-59a88b7e92f1.jpg +0 -0
  37. package/docs/public/journey.css +528 -0
  38. package/docs/public/pulse-ui.css +1036 -22
  39. package/docs/public/retrowheels.css +402 -0
  40. package/docs/public/shop.css +235 -0
  41. package/docs/public/sparkys.css +349 -0
  42. package/docs/public/suzukibento.css +517 -0
  43. package/docs/public/swish.css +394 -0
  44. package/docs/server.js +19 -4
  45. package/docs/src/lib/nav.js +14 -3
  46. package/docs/src/pages/components/decorate.js +74 -0
  47. package/docs/src/pages/components/gallery.js +102 -0
  48. package/docs/src/pages/components/hero.js +1 -0
  49. package/docs/src/pages/components/marquee.js +76 -0
  50. package/docs/src/pages/components/photo-card.js +74 -0
  51. package/docs/src/pages/components/section.js +40 -1
  52. package/docs/src/pages/meta.js +26 -0
  53. package/docs/src/pages/templates/andypixel.js +260 -0
  54. package/docs/src/pages/templates/bookworms.js +227 -0
  55. package/docs/src/pages/templates/coutumes.js +226 -0
  56. package/docs/src/pages/templates/journey.js +186 -0
  57. package/docs/src/pages/templates/retrowheels.js +342 -0
  58. package/docs/src/pages/templates/shop.js +257 -0
  59. package/docs/src/pages/templates/sparkys.js +249 -0
  60. package/docs/src/pages/templates/suzukibento.js +200 -0
  61. package/docs/src/pages/templates/swish.js +313 -0
  62. package/docs/src/pages/templates.js +313 -2
  63. package/docs/src/pages/testing.js +2 -1
  64. package/examples/.claude/commands/pulse-build.md +7 -0
  65. package/examples/.claude/commands/pulse-dev.md +7 -0
  66. package/examples/.claude/commands/pulse-start.md +9 -0
  67. package/examples/.claude/commands/pulse-stop.md +5 -0
  68. package/examples/.claude/commands/verify.md +84 -0
  69. package/examples/.claude/coverage-check.js +127 -0
  70. package/examples/.claude/pulse-checklist.md +177 -0
  71. package/examples/andypixel.css +237 -0
  72. package/examples/andypixel.js +258 -0
  73. package/examples/bookworms.css +422 -0
  74. package/examples/bookworms.js +225 -0
  75. package/examples/contact.js +1 -0
  76. package/examples/counter.js +1 -0
  77. package/examples/dev.server.js +17 -0
  78. package/examples/journey.css +528 -0
  79. package/examples/journey.js +186 -0
  80. package/examples/pricing.js +1 -0
  81. package/examples/public/.pulse-ui-version +1 -0
  82. package/examples/public/pulse-ui.css +4031 -0
  83. package/examples/public/pulse-ui.js +257 -0
  84. package/examples/quiz.js +1 -0
  85. package/examples/retrowheels.css +402 -0
  86. package/examples/retrowheels.js +340 -0
  87. package/examples/shared.js +6 -0
  88. package/examples/suzukibento.css +513 -0
  89. package/examples/suzukibento.js +200 -0
  90. package/examples/swish.css +394 -0
  91. package/examples/swish.js +311 -0
  92. package/examples/todos.js +1 -0
  93. package/package.json +2 -3
  94. package/public/.pulse-ui-version +1 -1
  95. package/public/images/bookworms/hero-books.jpg +0 -0
  96. package/public/images/bookworms/how-we-read-now.jpg +0 -0
  97. package/public/images/bookworms/lantern-keepers.jpg +0 -0
  98. package/public/images/bookworms/provincial-bookseller.jpg +0 -0
  99. package/public/images/journey/178.jpg +0 -0
  100. package/public/images/journey/29.jpg +0 -0
  101. package/public/images/retrowheels/hero.jpg +0 -0
  102. package/public/images/shop/devbook-pro.jpg +0 -0
  103. package/public/images/suzukibento/1015.jpg +0 -0
  104. package/public/images/suzukibento/1025.jpg +0 -0
  105. package/public/images/suzukibento/1043.jpg +0 -0
  106. package/public/images/suzukibento/1059.jpg +0 -0
  107. package/public/images/suzukibento/1062.jpg +0 -0
  108. package/public/images/suzukibento/1084.jpg +0 -0
  109. package/public/images/swish/1469334031218-e382a71b716b.jpg +0 -0
  110. package/public/images/swish/1483985988355-763728e1935b.jpg +0 -0
  111. package/public/images/swish/1485518882345-15568b007407.jpg +0 -0
  112. package/public/images/swish/1490481651871-ab68de25d43d.jpg +0 -0
  113. package/public/images/swish/1496747611176-843222e1e57c.jpg +0 -0
  114. package/public/images/swish/1502716119720-b23a93e5fe1b.jpg +0 -0
  115. package/public/images/swish/1539109136881-3be0616acf4b.jpg +0 -0
  116. package/public/images/swish/1551803091-e20673f15770.jpg +0 -0
  117. package/public/images/swish/1558769132-cb1aea458c5e.jpg +0 -0
  118. package/public/images/swish/1572804013309-59a88b7e92f1.jpg +0 -0
  119. package/public/pulse-ui.css +1080 -22
  120. package/scripts/build.js +72 -18
  121. package/src/agent/checklist.md +22 -2
  122. package/src/agent/commands/verify.md +4 -0
  123. package/src/agent/guide-components.md +146 -8
  124. package/src/agent/guide-design-gallery.md +288 -0
  125. package/src/agent/guide-design-references.md +172 -0
  126. package/src/agent/guide-explore.md +313 -0
  127. package/src/agent/guide-styles.md +212 -11
  128. package/src/agent/guide-templates.md +223 -10
  129. package/src/agent/guide.md +9 -4
  130. package/src/agent/identity.md +2 -1
  131. package/src/agent/skills/verify/SKILL.md +64 -28
  132. package/src/agent/workflow.md +247 -61
  133. package/src/cli/dev.js +39 -14
  134. package/src/cli/fmt.js +113 -0
  135. package/src/cli/index.js +60 -33
  136. package/src/cli/logger.js +145 -0
  137. package/src/cli/scaffold.js +57 -3
  138. package/src/html.js +6 -1
  139. package/src/mcp/server.js +2561 -99
  140. package/src/mcp/validate-worker.js +49 -5
  141. package/src/runtime/ssr.js +4 -1
  142. package/src/server/index.js +29 -5
  143. package/src/spec/schema.js +21 -0
  144. package/src/spec/schema.test.js +28 -0
  145. package/src/testing/html.js +130 -4
  146. package/src/testing/testing.test.js +58 -0
  147. package/src/ui/banner.js +24 -9
  148. package/src/ui/brand-statement.js +58 -0
  149. package/src/ui/button.js +13 -2
  150. package/src/ui/card.js +20 -1
  151. package/src/ui/colophon.js +29 -0
  152. package/src/ui/contact-row.js +41 -0
  153. package/src/ui/cta.js +18 -4
  154. package/src/ui/decorate.js +55 -0
  155. package/src/ui/display-heading.js +44 -0
  156. package/src/ui/drop-cap.js +29 -0
  157. package/src/ui/editorial-hero.js +63 -0
  158. package/src/ui/entry-list.js +36 -0
  159. package/src/ui/feature.js +20 -3
  160. package/src/ui/footer.js +78 -9
  161. package/src/ui/gallery.js +56 -0
  162. package/src/ui/hero.js +68 -18
  163. package/src/ui/image-pair.js +72 -0
  164. package/src/ui/index.js +20 -0
  165. package/src/ui/input.js +1 -0
  166. package/src/ui/marquee.js +48 -0
  167. package/src/ui/nav.js +19 -9
  168. package/src/ui/photo-card.js +44 -0
  169. package/src/ui/product-card.js +65 -0
  170. package/src/ui/pullquote.js +14 -3
  171. package/src/ui/search.js +1 -0
  172. package/src/ui/section-label.js +38 -0
  173. package/src/ui/section.js +1 -1
  174. package/src/ui/service-card.js +47 -0
  175. package/src/ui/stat-grid.js +40 -0
  176. package/src/ui/stat.js +16 -2
  177. package/src/ui/testimonial.js +17 -6
  178. package/src/ui/textarea.js +1 -0
  179. package/src/ui/top-strip.js +47 -0
  180. package/src/ui/trust-list.js +46 -0
  181. package/src/ui/ui.test.js +35 -0
@@ -0,0 +1,402 @@
1
+ /*
2
+ * retrowheels.css — Retro Wheels Co. bicycle shop example
3
+ *
4
+ * 1970s enamel-sign aesthetic: cream paper, burnt orange, mustard yellow,
5
+ * forest green, oxidised navy. Rockwell slab serif + Courier New monospace.
6
+ * All system fonts — zero external HTTP requests.
7
+ *
8
+ * Split into two logical sections:
9
+ * 1. Token overrides — hex values, palette definitions
10
+ * 2. Component styles — layout, typography, custom elements (var() only)
11
+ */
12
+
13
+ /* ==========================================================================
14
+ 1. Token overrides (hex values live here)
15
+ ========================================================================== */
16
+
17
+ /* Named palette — referenced throughout this file via var() */
18
+ :root {
19
+ --rw-orange: #c8431f;
20
+ --rw-orange-dark: #a8351a;
21
+ --rw-cream: #f4e9d3;
22
+ --rw-cream-deep: #ead9b8;
23
+ --rw-navy: #1f2a3a;
24
+ --rw-mustard: #d9a441;
25
+ --rw-mustard-dark: #8a6418;
26
+ --rw-green: #2f5d3a;
27
+ --rw-green-dark: #1f3f27;
28
+ --rw-ink: #2b2018;
29
+ }
30
+
31
+ /* System slab-serif stack for headings — no Google Fonts needed */
32
+ :root {
33
+ --font: Georgia, 'Bookman Old Style', serif;
34
+ --font-display: 'Rockwell', 'Bookman Old Style', Georgia, serif;
35
+ }
36
+
37
+ [data-theme="light"] {
38
+ --ui-bg: #f4e9d3;
39
+ --ui-surface: #fbf3df;
40
+ --ui-surface-2: #ead9b8;
41
+ --ui-border: #c9b890;
42
+ --ui-text: #2b2018;
43
+ --ui-muted: #6b5d48;
44
+ --ui-accent: #a8351a;
45
+ --ui-accent-hover: #8a2912;
46
+ --ui-accent-dim: rgba(168, 53, 26, 0.12);
47
+ --ui-accent-text: #fbf3df;
48
+ }
49
+
50
+ [data-theme="light"] .ui-btn--primary {
51
+ color: #fbf3df;
52
+ }
53
+
54
+ /* ==========================================================================
55
+ 2. Component styles (var() only — no hex values below this line)
56
+ ========================================================================== */
57
+
58
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
59
+
60
+ body {
61
+ font-family: var(--ui-font);
62
+ line-height: 1.6;
63
+ color: var(--ui-text);
64
+ background: var(--ui-bg);
65
+ }
66
+
67
+ /* Slab-serif for all headings and named component titles */
68
+ h1, h2, h3, h4, h5, h6,
69
+ .ui-hero-title, .ui-section-title, .ui-card-title,
70
+ .ui-cta-title, .ui-feature-title, .ui-stat-value {
71
+ font-family: var(--ui-font-display);
72
+ letter-spacing: -0.01em;
73
+ }
74
+
75
+ /* --------------------------------------------------------------------------
76
+ Brand logo wordmark
77
+ -------------------------------------------------------------------------- */
78
+ .rw-logo-text {
79
+ font-family: var(--ui-font-display);
80
+ font-weight: 900;
81
+ letter-spacing: -0.01em;
82
+ font-size: 1.1rem;
83
+ }
84
+
85
+ /* --------------------------------------------------------------------------
86
+ Skip link
87
+ -------------------------------------------------------------------------- */
88
+ .rw-skip-link {
89
+ position: absolute;
90
+ left: -9999px;
91
+ top: 0;
92
+ }
93
+
94
+ .rw-skip-link:focus {
95
+ left: var(--ui-space-2);
96
+ top: var(--ui-space-2);
97
+ background: var(--rw-cream);
98
+ color: var(--rw-navy);
99
+ padding: var(--ui-space-2) var(--ui-space-3);
100
+ z-index: 1000;
101
+ }
102
+
103
+ /* --------------------------------------------------------------------------
104
+ Eyebrow labels
105
+ -------------------------------------------------------------------------- */
106
+ .rw-eyebrow {
107
+ font-family: 'Courier New', monospace;
108
+ letter-spacing: 0.25em;
109
+ text-transform: uppercase;
110
+ font-size: var(--ui-text-xs);
111
+ color: var(--rw-orange-dark);
112
+ }
113
+
114
+ .rw-eyebrow--on-orange {
115
+ color: var(--rw-cream);
116
+ }
117
+
118
+ /* --------------------------------------------------------------------------
119
+ Decorative rule
120
+ -------------------------------------------------------------------------- */
121
+ .rw-rule {
122
+ border: 0;
123
+ border-top: 3px double var(--ui-border);
124
+ margin: var(--ui-space-8) 0;
125
+ }
126
+
127
+ /* --------------------------------------------------------------------------
128
+ Full-bleed hero
129
+ -------------------------------------------------------------------------- */
130
+ .rw-hero {
131
+ position: relative;
132
+ min-height: 70vh;
133
+ background:
134
+ linear-gradient(180deg, rgba(31, 42, 58, 0.55) 0%, rgba(31, 42, 58, 0.85) 100%),
135
+ url('/images/retrowheels/hero.jpg') center / cover no-repeat;
136
+ color: var(--rw-cream);
137
+ padding: var(--ui-space-24) var(--ui-space-6);
138
+ display: flex;
139
+ align-items: flex-end;
140
+ }
141
+
142
+ .rw-hero-inner {
143
+ max-width: 64rem;
144
+ margin: 0 auto;
145
+ width: 100%;
146
+ }
147
+
148
+ .rw-hero-eyebrow {
149
+ font-family: 'Courier New', monospace;
150
+ letter-spacing: 0.3em;
151
+ text-transform: uppercase;
152
+ font-size: var(--ui-text-sm);
153
+ color: var(--rw-mustard);
154
+ display: inline-block;
155
+ padding: var(--ui-space-1) var(--ui-space-3);
156
+ border: 2px solid var(--rw-mustard);
157
+ margin-bottom: var(--ui-space-6);
158
+ }
159
+
160
+ .rw-hero-title {
161
+ font-family: var(--ui-font-display);
162
+ font-weight: 900;
163
+ font-size: clamp(2.5rem, 7vw, 5.5rem);
164
+ line-height: 1.05;
165
+ letter-spacing: -0.02em;
166
+ margin-bottom: var(--ui-space-5);
167
+ text-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
168
+ }
169
+
170
+ .rw-hero-title em {
171
+ font-style: italic;
172
+ color: var(--rw-mustard);
173
+ }
174
+
175
+ .rw-hero-sub {
176
+ font-size: var(--ui-text-xl);
177
+ max-width: 38rem;
178
+ margin-bottom: var(--ui-space-6);
179
+ color: var(--rw-cream);
180
+ opacity: 0.95;
181
+ }
182
+
183
+ .rw-hero-actions {
184
+ display: flex;
185
+ gap: var(--ui-space-3);
186
+ flex-wrap: wrap;
187
+ }
188
+
189
+ .rw-hero-image-credit {
190
+ position: absolute;
191
+ bottom: var(--ui-space-2);
192
+ right: var(--ui-space-3);
193
+ font-size: var(--ui-text-xs);
194
+ opacity: 0.6;
195
+ font-family: 'Courier New', monospace;
196
+ }
197
+
198
+ /* --------------------------------------------------------------------------
199
+ Stat strip (inverted navy bar)
200
+ -------------------------------------------------------------------------- */
201
+ .rw-stat-strip {
202
+ background: var(--rw-navy);
203
+ color: var(--rw-cream);
204
+ padding: var(--ui-space-8) var(--ui-space-6);
205
+ }
206
+
207
+ .rw-stat-strip .ui-stat-label {
208
+ color: var(--rw-mustard);
209
+ font-family: 'Courier New', monospace;
210
+ letter-spacing: 0.2em;
211
+ text-transform: uppercase;
212
+ font-size: var(--ui-text-xs);
213
+ }
214
+
215
+ .rw-stat-strip .ui-stat-value {
216
+ color: var(--rw-cream);
217
+ font-family: var(--ui-font-display);
218
+ font-size: var(--ui-text-4xl);
219
+ }
220
+
221
+ .rw-stat-strip-inner {
222
+ max-width: 64rem;
223
+ margin: 0 auto;
224
+ display: grid;
225
+ grid-template-columns: repeat(4, 1fr);
226
+ gap: var(--ui-space-6);
227
+ text-align: center;
228
+ }
229
+
230
+ @media (max-width: 640px) {
231
+ .rw-stat-strip-inner {
232
+ grid-template-columns: repeat(2, 1fr);
233
+ }
234
+ }
235
+
236
+ /* --------------------------------------------------------------------------
237
+ Editorial prose section (drop cap on first paragraph)
238
+ -------------------------------------------------------------------------- */
239
+ .rw-editorial {
240
+ max-width: 42rem;
241
+ margin: 0 auto;
242
+ padding: var(--ui-space-16) var(--ui-space-6);
243
+ }
244
+
245
+ .rw-editorial p {
246
+ font-size: var(--ui-text-lg);
247
+ margin-bottom: var(--ui-space-5);
248
+ }
249
+
250
+ .rw-editorial hr + p::first-letter {
251
+ font-family: var(--ui-font-display);
252
+ font-size: 3.5rem;
253
+ font-weight: 900;
254
+ float: left;
255
+ line-height: 0.9;
256
+ padding: 0.25rem var(--ui-space-2) 0 0;
257
+ color: var(--rw-orange-dark);
258
+ }
259
+
260
+ /* --------------------------------------------------------------------------
261
+ Section template
262
+ -------------------------------------------------------------------------- */
263
+ .rw-section {
264
+ padding: var(--ui-space-16) var(--ui-space-6);
265
+ }
266
+
267
+ .rw-section--alt {
268
+ background: var(--rw-cream-deep);
269
+ }
270
+
271
+ .rw-section-inner {
272
+ max-width: 64rem;
273
+ margin: 0 auto;
274
+ }
275
+
276
+ .rw-section-title {
277
+ font-family: var(--ui-font-display);
278
+ font-size: var(--ui-text-4xl);
279
+ font-weight: 900;
280
+ margin-bottom: var(--ui-space-2);
281
+ letter-spacing: -0.01em;
282
+ }
283
+
284
+ .rw-section-deck {
285
+ color: var(--ui-muted);
286
+ font-size: var(--ui-text-lg);
287
+ margin-bottom: var(--ui-space-10);
288
+ max-width: 36rem;
289
+ }
290
+
291
+ /* --------------------------------------------------------------------------
292
+ Services grid
293
+ -------------------------------------------------------------------------- */
294
+ .rw-service-grid {
295
+ display: grid;
296
+ grid-template-columns: repeat(3, 1fr);
297
+ gap: var(--ui-space-6);
298
+ }
299
+
300
+ @media (max-width: 900px) { .rw-service-grid { grid-template-columns: repeat(2, 1fr); } }
301
+ @media (max-width: 600px) { .rw-service-grid { grid-template-columns: 1fr; } }
302
+
303
+ .rw-service {
304
+ background: var(--ui-surface);
305
+ border: 2px solid var(--ui-border);
306
+ padding: var(--ui-space-6);
307
+ position: relative;
308
+ }
309
+
310
+ .rw-service-num {
311
+ font-family: 'Courier New', monospace;
312
+ font-size: var(--ui-text-xs);
313
+ letter-spacing: 0.2em;
314
+ color: var(--rw-orange-dark);
315
+ margin-bottom: var(--ui-space-3);
316
+ }
317
+
318
+ .rw-service h3 {
319
+ font-family: var(--ui-font-display);
320
+ font-size: var(--ui-text-xl);
321
+ font-weight: 900;
322
+ margin-bottom: var(--ui-space-2);
323
+ }
324
+
325
+ .rw-service p {
326
+ color: var(--ui-muted);
327
+ margin-bottom: var(--ui-space-4);
328
+ }
329
+
330
+ .rw-service-price {
331
+ font-family: 'Courier New', monospace;
332
+ font-size: var(--ui-text-sm);
333
+ color: var(--rw-green-dark);
334
+ border-top: 1px dashed var(--ui-border);
335
+ padding-top: var(--ui-space-3);
336
+ }
337
+
338
+ /* --------------------------------------------------------------------------
339
+ Visit section — hours + booking card
340
+ -------------------------------------------------------------------------- */
341
+ .rw-visit-grid {
342
+ display: grid;
343
+ grid-template-columns: 1fr 1fr;
344
+ gap: var(--ui-space-12);
345
+ align-items: start;
346
+ }
347
+
348
+ @media (max-width: 720px) {
349
+ .rw-visit-grid { grid-template-columns: 1fr; }
350
+ }
351
+
352
+ .rw-hours-heading {
353
+ font-family: var(--ui-font-display);
354
+ font-size: var(--ui-text-xl);
355
+ font-weight: 900;
356
+ margin-bottom: var(--ui-space-3);
357
+ }
358
+
359
+ .rw-hours {
360
+ font-family: 'Courier New', monospace;
361
+ font-size: var(--ui-text-base);
362
+ list-style: none;
363
+ }
364
+
365
+ .rw-hours-row {
366
+ display: flex;
367
+ justify-content: space-between;
368
+ padding: var(--ui-space-2) 0;
369
+ border-bottom: 1px dashed var(--ui-border);
370
+ }
371
+
372
+ .rw-hours li:last-child { border-bottom: 0; }
373
+
374
+ .rw-closed { color: var(--rw-orange-dark); }
375
+
376
+ .rw-address {
377
+ margin-top: var(--ui-space-6);
378
+ line-height: 1.7;
379
+ }
380
+
381
+ /* --------------------------------------------------------------------------
382
+ Saturday ride banner (full-bleed burnt orange)
383
+ -------------------------------------------------------------------------- */
384
+ .rw-ride-banner {
385
+ background: var(--rw-orange-dark);
386
+ color: var(--rw-cream);
387
+ padding: var(--ui-space-16) var(--ui-space-6);
388
+ text-align: center;
389
+ }
390
+
391
+ .rw-ride-banner h2 {
392
+ color: var(--rw-cream);
393
+ font-size: clamp(2rem, 5vw, 3.5rem);
394
+ font-weight: 900;
395
+ margin-bottom: var(--ui-space-3);
396
+ }
397
+
398
+ .rw-ride-banner p {
399
+ font-size: var(--ui-text-lg);
400
+ max-width: 40rem;
401
+ margin: 0 auto var(--ui-space-6);
402
+ }
@@ -0,0 +1,235 @@
1
+ /*
2
+ * shop.css — Template: Shop / Product Page
3
+ * Theme tokens + layout styles for the Tech Stuff Inc. product page template.
4
+ */
5
+
6
+ /* ── Theme tokens ─────────────────────────────────────────────────────────── */
7
+
8
+ [data-theme="light"] {
9
+ --accent: #1D4ED8;
10
+ --ui-color-muted: #374151;
11
+ --ui-surface: #F5F5F5;
12
+ --cart-bubble-text: #ffffff;
13
+ }
14
+
15
+ /* ── Base ─────────────────────────────────────────────────────────────────── */
16
+
17
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
18
+
19
+ body {
20
+ font-family: var(--ui-font, system-ui, sans-serif);
21
+ line-height: 1.6;
22
+ background: var(--ui-bg);
23
+ }
24
+
25
+ #pulse-root {
26
+ max-width: 100%;
27
+ overflow-x: hidden;
28
+ }
29
+
30
+ /* Constrain content to match nav width (1100px) */
31
+ .page-body {
32
+ max-width: 1100px;
33
+ margin-left: auto;
34
+ margin-right: auto;
35
+ width: 100%;
36
+ }
37
+
38
+ /* ── Product display ──────────────────────────────────────────────────────── */
39
+
40
+ .product-display {
41
+ padding: var(--ui-space-16) var(--ui-space-6) var(--ui-space-8);
42
+ }
43
+
44
+ .product-display .ui-display-heading {
45
+ font-size: clamp(3rem, 10vw, 8rem);
46
+ line-height: 1;
47
+ letter-spacing: -0.04em;
48
+ font-weight: 700;
49
+ color: var(--ui-text);
50
+ }
51
+
52
+ .product-display .product-tagline {
53
+ margin-top: var(--ui-space-4);
54
+ font-size: var(--ui-text-xl);
55
+ color: var(--ui-color-muted);
56
+ max-width: 48ch;
57
+ }
58
+
59
+ .product-display .product-meta-row {
60
+ margin-top: var(--ui-space-6);
61
+ display: flex;
62
+ align-items: center;
63
+ gap: var(--ui-space-4);
64
+ flex-wrap: wrap;
65
+ }
66
+
67
+ /* ── Product photo ────────────────────────────────────────────────────────── */
68
+
69
+ .product-photo {
70
+ width: 100%;
71
+ max-height: 70vh;
72
+ object-fit: cover;
73
+ display: block;
74
+ }
75
+
76
+ /* ── Purchase section ─────────────────────────────────────────────────────── */
77
+
78
+ .product-purchase {
79
+ padding: var(--ui-space-10) var(--ui-space-6);
80
+ border-bottom: 1px solid var(--ui-border);
81
+ }
82
+
83
+ .product-price {
84
+ font-size: var(--ui-text-4xl);
85
+ font-weight: 700;
86
+ letter-spacing: -0.02em;
87
+ color: var(--ui-text);
88
+ line-height: 1;
89
+ margin-bottom: var(--ui-space-6);
90
+ }
91
+
92
+ .qty-control {
93
+ display: flex;
94
+ align-items: center;
95
+ gap: var(--ui-space-3);
96
+ margin-bottom: var(--ui-space-6);
97
+ }
98
+
99
+ .qty-value {
100
+ font-size: var(--ui-text-lg);
101
+ font-weight: 600;
102
+ min-width: 2ch;
103
+ text-align: center;
104
+ }
105
+
106
+ .cart-actions {
107
+ display: flex;
108
+ gap: var(--ui-space-3);
109
+ flex-wrap: wrap;
110
+ align-items: center;
111
+ margin-bottom: var(--ui-space-4);
112
+ }
113
+
114
+ .added-confirm {
115
+ font-size: var(--ui-text-sm);
116
+ color: var(--ui-color-muted);
117
+ }
118
+
119
+ /* ── Specs section ────────────────────────────────────────────────────────── */
120
+
121
+ .product-specs {
122
+ padding: var(--ui-space-10) var(--ui-space-6);
123
+ border-bottom: 1px solid var(--ui-border);
124
+ }
125
+
126
+ .spec-grid {
127
+ display: grid;
128
+ grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
129
+ gap: var(--ui-space-6);
130
+ margin-top: var(--ui-space-6);
131
+ }
132
+
133
+ .spec-item {
134
+ display: flex;
135
+ flex-direction: column;
136
+ gap: var(--ui-space-1);
137
+ }
138
+
139
+ .spec-label {
140
+ font-size: var(--ui-text-xs);
141
+ text-transform: uppercase;
142
+ letter-spacing: 0.08em;
143
+ color: var(--ui-color-muted);
144
+ font-weight: 600;
145
+ }
146
+
147
+ .spec-value {
148
+ font-size: var(--ui-text-base);
149
+ font-weight: 500;
150
+ color: var(--ui-text);
151
+ }
152
+
153
+ /* ── Stats section ────────────────────────────────────────────────────────── */
154
+
155
+ .product-stats {
156
+ padding: var(--ui-space-10) var(--ui-space-6);
157
+ }
158
+
159
+ .product-stats-grid {
160
+ margin-top: var(--ui-space-6);
161
+ }
162
+
163
+ /* ── Qty buttons — icon only, hide text span visually ─────────────────────── */
164
+
165
+ .qty-btn > span:not(.ui-btn-icon) {
166
+ position: absolute;
167
+ width: 1px;
168
+ height: 1px;
169
+ padding: 0;
170
+ margin: -1px;
171
+ overflow: hidden;
172
+ clip: rect(0,0,0,0);
173
+ white-space: nowrap;
174
+ border: 0;
175
+ }
176
+
177
+ /* ── Nav cart trigger button ──────────────────────────────────────────────── */
178
+
179
+ .cart-trigger {
180
+ position: relative;
181
+ display: inline-flex;
182
+ align-items: center;
183
+ justify-content: center;
184
+ background: none;
185
+ border: none;
186
+ cursor: pointer;
187
+ padding: var(--ui-space-2);
188
+ color: var(--ui-text);
189
+ border-radius: var(--ui-radius);
190
+ }
191
+
192
+ .cart-trigger:hover { color: var(--ui-accent); }
193
+
194
+ .cart-bubble {
195
+ position: absolute;
196
+ top: -2px;
197
+ right: -4px;
198
+ background: var(--ui-accent);
199
+ color: var(--cart-bubble-text);
200
+ font-size: 10px;
201
+ font-weight: 700;
202
+ line-height: 1;
203
+ min-width: 16px;
204
+ height: 16px;
205
+ padding: 0 3px;
206
+ border-radius: 999px;
207
+ display: flex;
208
+ align-items: center;
209
+ justify-content: center;
210
+ }
211
+
212
+ /* ── Cart modal table ─────────────────────────────────────────────────────── */
213
+
214
+ .cart-table {
215
+ width: 100%;
216
+ margin-top: var(--ui-space-2);
217
+ }
218
+
219
+ .cart-col-num {
220
+ text-align: right;
221
+ white-space: nowrap;
222
+ }
223
+
224
+ .cart-total-row td {
225
+ padding-top: var(--ui-space-3);
226
+ border-top: 2px solid var(--ui-border);
227
+ }
228
+
229
+ /* ── View error fallback ──────────────────────────────────────────────────── */
230
+
231
+ .view-error {
232
+ padding: var(--ui-space-16) var(--ui-space-6);
233
+ text-align: center;
234
+ color: var(--ui-color-muted);
235
+ }