@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,584 @@
1
+ /* ============================================================
2
+ Coutumes Recreation CSS
3
+ Substitute fonts: Bebas Neue (→ Plaak 3), Cormorant Garamond (→ Exposure Regular)
4
+ Brand amber: #F9AF26 | Text: #000 | Background: #fff
5
+ ============================================================ */
6
+
7
+ :root {
8
+ --coutumes-amber: #F9AF26;
9
+ --coutumes-black: #000000;
10
+ --coutumes-white: #ffffff;
11
+ --coutumes-font-display: 'Bebas Neue', sans-serif;
12
+ --coutumes-font-body: 'Cormorant Garamond', serif;
13
+ --coutumes-font-ui: 'Barlow', system-ui, sans-serif;
14
+ }
15
+
16
+ .coutumes-sr-only {
17
+ position: absolute;
18
+ width: 1px;
19
+ height: 1px;
20
+ padding: 0;
21
+ margin: -1px;
22
+ overflow: hidden;
23
+ clip: rect(0, 0, 0, 0);
24
+ white-space: nowrap;
25
+ border: 0;
26
+ }
27
+
28
+ /* Base reset for this page */
29
+ .coutumes-hero,
30
+ .coutumes-nav,
31
+ .coutumes-editorial-quote,
32
+ .coutumes-product-grid,
33
+ .coutumes-split-images,
34
+ .coutumes-statement,
35
+ .coutumes-portrait,
36
+ .coutumes-footer,
37
+ .coutumes-announce {
38
+ font-family: var(--coutumes-font-body);
39
+ color: var(--coutumes-black);
40
+ background: var(--coutumes-white);
41
+ }
42
+
43
+ /* ── Announcement bar ── */
44
+ .coutumes-announce {
45
+ position: fixed;
46
+ bottom: 0;
47
+ left: 0;
48
+ right: 0;
49
+ z-index: 100;
50
+ background: var(--coutumes-white);
51
+ border-top: 1px solid #e5e5e5;
52
+ padding: 10px 24px;
53
+ display: flex;
54
+ align-items: center;
55
+ justify-content: center;
56
+ font-family: var(--coutumes-font-ui);
57
+ font-size: 0.6875rem;
58
+ letter-spacing: 0.12em;
59
+ text-transform: uppercase;
60
+ }
61
+
62
+ .coutumes-announce-close {
63
+ position: absolute;
64
+ right: 16px;
65
+ background: none;
66
+ border: none;
67
+ cursor: pointer;
68
+ font-size: 0.75rem;
69
+ color: var(--coutumes-black);
70
+ padding: 4px;
71
+ }
72
+
73
+ /* ── Nav ── */
74
+ .coutumes-nav {
75
+ position: sticky;
76
+ top: 0;
77
+ z-index: 50;
78
+ background: var(--coutumes-white);
79
+ border-bottom: none;
80
+ display: flex;
81
+ align-items: center;
82
+ justify-content: space-between;
83
+ padding: 0 24px;
84
+ height: 60px;
85
+ font-family: var(--coutumes-font-ui);
86
+ font-size: 0.8125rem;
87
+ }
88
+
89
+ .coutumes-nav-left {
90
+ display: flex;
91
+ align-items: center;
92
+ gap: 32px;
93
+ }
94
+
95
+ .coutumes-logo {
96
+ font-family: var(--coutumes-font-display);
97
+ font-size: 1.125rem;
98
+ letter-spacing: 0.05em;
99
+ color: var(--coutumes-black);
100
+ text-decoration: none;
101
+ }
102
+
103
+ .coutumes-nav-links {
104
+ display: flex;
105
+ gap: 28px;
106
+ list-style: none;
107
+ margin: 0;
108
+ padding: 0;
109
+ }
110
+
111
+ .coutumes-nav-links a,
112
+ .coutumes-nav-right a {
113
+ color: var(--coutumes-black);
114
+ text-decoration: none;
115
+ font-size: 0.8125rem;
116
+ }
117
+
118
+ .coutumes-nav-links a:hover,
119
+ .coutumes-nav-right a:hover {
120
+ opacity: 0.6;
121
+ }
122
+
123
+ .coutumes-nav-right {
124
+ display: flex;
125
+ align-items: center;
126
+ gap: 24px;
127
+ }
128
+
129
+ /* ── Hero ── */
130
+ .coutumes-hero {
131
+ position: relative;
132
+ overflow: hidden;
133
+ min-height: 100svh;
134
+ }
135
+
136
+ .coutumes-hero-images {
137
+ display: grid;
138
+ grid-template-columns: 1fr 1fr;
139
+ height: 100svh;
140
+ min-height: 600px;
141
+ }
142
+
143
+ .coutumes-hero-img {
144
+ overflow: hidden;
145
+ }
146
+
147
+ .coutumes-hero-img img {
148
+ width: 100%;
149
+ height: 100%;
150
+ object-fit: cover;
151
+ display: block;
152
+ }
153
+
154
+ /* Overlapping amber display type */
155
+ .coutumes-hero-text {
156
+ position: absolute;
157
+ inset: 0;
158
+ display: flex;
159
+ flex-direction: column;
160
+ justify-content: center;
161
+ padding: 0;
162
+ pointer-events: none;
163
+ z-index: 10;
164
+ }
165
+
166
+ .coutumes-hero-text span {
167
+ display: block;
168
+ font-family: var(--coutumes-font-display);
169
+ font-size: clamp(5rem, 14vw, 11rem);
170
+ line-height: 0.92;
171
+ letter-spacing: -0.02em;
172
+ color: var(--coutumes-amber);
173
+ padding: 0 2vw;
174
+ /* Mix-blend-mode makes it appear to interact with the photos like the original */
175
+ mix-blend-mode: multiply;
176
+ }
177
+
178
+ .coutumes-hero-cta {
179
+ position: absolute;
180
+ bottom: 32px;
181
+ left: 50%;
182
+ transform: translateX(-50%);
183
+ font-family: var(--coutumes-font-ui);
184
+ font-size: 0.6875rem;
185
+ letter-spacing: 0.12em;
186
+ text-transform: uppercase;
187
+ color: var(--coutumes-white);
188
+ text-decoration: none;
189
+ white-space: nowrap;
190
+ z-index: 20;
191
+ }
192
+
193
+ /* ── Editorial quote ── */
194
+ .coutumes-editorial-quote {
195
+ padding: 80px 24px;
196
+ text-align: center;
197
+ }
198
+
199
+ .coutumes-editorial-quote-inner {
200
+ max-width: 680px;
201
+ margin: 0 auto;
202
+ }
203
+
204
+ .coutumes-quote-text {
205
+ font-family: var(--coutumes-font-body);
206
+ font-size: clamp(1.5rem, 3.5vw, 2.25rem);
207
+ line-height: 1.4;
208
+ font-weight: 400;
209
+ margin: 0 0 24px;
210
+ }
211
+
212
+ .coutumes-quote-caption {
213
+ font-family: var(--coutumes-font-body);
214
+ font-size: 0.9375rem;
215
+ font-style: italic;
216
+ color: #666;
217
+ margin: 0;
218
+ }
219
+
220
+ /* ── Product grid ── */
221
+ .coutumes-product-grid {
222
+ display: grid;
223
+ grid-template-columns: repeat(3, 1fr);
224
+ gap: 0;
225
+ }
226
+
227
+ .coutumes-product-card {
228
+ position: relative;
229
+ display: block;
230
+ overflow: hidden;
231
+ text-decoration: none;
232
+ color: var(--coutumes-black);
233
+ aspect-ratio: 4/5;
234
+ }
235
+
236
+ .coutumes-product-card img {
237
+ width: 100%;
238
+ height: 100%;
239
+ object-fit: cover;
240
+ display: block;
241
+ transition: transform 0.5s ease;
242
+ }
243
+
244
+ .coutumes-product-card:hover img {
245
+ transform: scale(1.03);
246
+ }
247
+
248
+ .coutumes-product-badge {
249
+ position: absolute;
250
+ top: 12px;
251
+ left: 12px;
252
+ background: var(--coutumes-white);
253
+ color: var(--coutumes-black);
254
+ font-family: var(--coutumes-font-ui);
255
+ font-size: 0.625rem;
256
+ letter-spacing: 0.08em;
257
+ padding: 3px 7px;
258
+ z-index: 5;
259
+ }
260
+
261
+ .coutumes-product-name {
262
+ position: absolute;
263
+ bottom: 16px;
264
+ left: 16px;
265
+ font-family: var(--coutumes-font-body);
266
+ font-size: 0.9375rem;
267
+ color: var(--coutumes-white);
268
+ text-shadow: 0 1px 4px rgba(0,0,0,0.3);
269
+ }
270
+
271
+ /* ── 50/50 split images ── */
272
+ .coutumes-split-images {
273
+ display: grid;
274
+ grid-template-columns: 1fr 1fr;
275
+ height: 70vw;
276
+ max-height: 800px;
277
+ }
278
+
279
+ .coutumes-split-img {
280
+ overflow: hidden;
281
+ }
282
+
283
+ .coutumes-split-img img {
284
+ width: 100%;
285
+ height: 100%;
286
+ object-fit: cover;
287
+ display: block;
288
+ }
289
+
290
+ /* ── Large editorial statement ── */
291
+ .coutumes-statement {
292
+ padding: 100px 24px;
293
+ text-align: center;
294
+ }
295
+
296
+ .coutumes-statement-inner {
297
+ max-width: 860px;
298
+ margin: 0 auto;
299
+ }
300
+
301
+ .coutumes-statement-inner p {
302
+ font-family: var(--coutumes-font-body);
303
+ font-size: clamp(1.75rem, 4.5vw, 3rem);
304
+ line-height: 1.25;
305
+ font-weight: 400;
306
+ margin: 0;
307
+ }
308
+
309
+ /* ── Portrait ── */
310
+ .coutumes-portrait {
311
+ display: flex;
312
+ justify-content: center;
313
+ padding: 40px 0 80px;
314
+ }
315
+
316
+ .coutumes-portrait img {
317
+ width: min(500px, 80vw);
318
+ height: auto;
319
+ display: block;
320
+ }
321
+
322
+ /* ── Footer ── */
323
+ .coutumes-footer {
324
+ background: var(--coutumes-amber);
325
+ padding: 60px 40px 0;
326
+ }
327
+
328
+ .coutumes-footer-top {
329
+ display: grid;
330
+ grid-template-columns: 1fr 1.5fr;
331
+ gap: 40px;
332
+ margin-bottom: 60px;
333
+ align-items: start;
334
+ }
335
+
336
+ .coutumes-footer-bird svg {
337
+ width: 120px;
338
+ height: 80px;
339
+ opacity: 0.4;
340
+ }
341
+
342
+ .coutumes-footer-subscribe-label {
343
+ font-family: var(--coutumes-font-ui);
344
+ font-size: 0.6875rem;
345
+ letter-spacing: 0.12em;
346
+ text-transform: uppercase;
347
+ margin: 0 0 16px;
348
+ }
349
+
350
+ .coutumes-footer-form {
351
+ display: flex;
352
+ align-items: center;
353
+ border-bottom: 1px solid var(--coutumes-black);
354
+ margin-bottom: 12px;
355
+ }
356
+
357
+ .coutumes-footer-form input {
358
+ flex: 1;
359
+ background: none;
360
+ border: none;
361
+ outline: none;
362
+ font-family: var(--coutumes-font-body);
363
+ font-size: 1.0625rem;
364
+ padding: 8px 0;
365
+ color: var(--coutumes-black);
366
+ }
367
+
368
+ .coutumes-footer-form input::placeholder {
369
+ color: rgba(0,0,0,0.5);
370
+ }
371
+
372
+ .coutumes-footer-form button {
373
+ background: none;
374
+ border: none;
375
+ cursor: pointer;
376
+ font-family: var(--coutumes-font-ui);
377
+ font-size: 0.6875rem;
378
+ letter-spacing: 0.08em;
379
+ color: var(--coutumes-black);
380
+ padding: 8px 0 8px 16px;
381
+ white-space: nowrap;
382
+ }
383
+
384
+ .coutumes-footer-legal {
385
+ font-family: var(--coutumes-font-ui);
386
+ font-size: 0.6875rem;
387
+ line-height: 1.5;
388
+ opacity: 0.7;
389
+ margin: 0;
390
+ }
391
+
392
+ .coutumes-footer-legal a {
393
+ color: var(--coutumes-black);
394
+ }
395
+
396
+ /* Footer link columns */
397
+ .coutumes-footer-links {
398
+ display: grid;
399
+ grid-template-columns: repeat(3, 1fr);
400
+ gap: 24px;
401
+ padding-bottom: 40px;
402
+ }
403
+
404
+ .coutumes-footer-col-title {
405
+ font-family: var(--coutumes-font-ui);
406
+ font-size: 0.625rem;
407
+ letter-spacing: 0.14em;
408
+ text-transform: uppercase;
409
+ margin: 0 0 16px;
410
+ font-weight: 500;
411
+ }
412
+
413
+ .coutumes-footer-col ul {
414
+ list-style: none;
415
+ margin: 0;
416
+ padding: 0;
417
+ display: flex;
418
+ flex-direction: column;
419
+ gap: 8px;
420
+ }
421
+
422
+ .coutumes-footer-col a {
423
+ font-family: var(--coutumes-font-body);
424
+ font-size: 0.9375rem;
425
+ color: var(--coutumes-black);
426
+ text-decoration: none;
427
+ }
428
+
429
+ .coutumes-footer-col a:hover {
430
+ opacity: 0.6;
431
+ }
432
+
433
+ /* Giant wordmark */
434
+ .coutumes-footer-wordmark {
435
+ font-family: var(--coutumes-font-display);
436
+ font-size: clamp(5rem, 18vw, 14rem);
437
+ line-height: 0.85;
438
+ letter-spacing: -0.02em;
439
+ color: var(--coutumes-black);
440
+ margin: 0 -40px;
441
+ overflow: hidden;
442
+ }
443
+
444
+ /* Legal row */
445
+ .coutumes-footer-legal-row {
446
+ display: flex;
447
+ gap: 24px;
448
+ align-items: center;
449
+ padding: 16px 0 24px;
450
+ font-family: var(--coutumes-font-ui);
451
+ font-size: 0.6875rem;
452
+ opacity: 0.7;
453
+ flex-wrap: wrap;
454
+ }
455
+
456
+ .coutumes-footer-legal-row a {
457
+ color: var(--coutumes-black);
458
+ text-decoration: none;
459
+ }
460
+
461
+ /* Padding utilities (if pulse-ui.css not loaded) */
462
+ .u-py-12 { padding-top: 3rem; padding-bottom: 3rem; }
463
+ .u-py-16 { padding-top: 4rem; padding-bottom: 4rem; }
464
+ .u-sr-only {
465
+ position: absolute;
466
+ width: 1px; height: 1px;
467
+ padding: 0; margin: -1px;
468
+ overflow: hidden;
469
+ clip: rect(0,0,0,0);
470
+ white-space: nowrap;
471
+ border: 0;
472
+ }
473
+
474
+ /* ── Responsive ── */
475
+ @media (max-width: 768px) {
476
+ .coutumes-nav-links { display: none; }
477
+ .coutumes-hero-text span { font-size: clamp(3rem, 18vw, 6rem); }
478
+ .coutumes-product-grid { grid-template-columns: 1fr; }
479
+ .coutumes-split-images { grid-template-columns: 1fr; height: auto; }
480
+ .coutumes-split-img { aspect-ratio: 4/3; }
481
+ .coutumes-footer-top { grid-template-columns: 1fr; }
482
+ .coutumes-footer-links { grid-template-columns: 1fr 1fr; }
483
+ }
484
+
485
+ /* Override Pulse accent purple → coutumes black for banner contrast (WCAG AA) */
486
+ .ui-banner--promo {
487
+ background: var(--coutumes-black);
488
+ color: var(--coutumes-white);
489
+ }
490
+
491
+ /* Hero overlay — sans-serif display font, top-aligned so text clips at top */
492
+ .coutumes-hero .ui-editorial-hero-overlay {
493
+ justify-content: flex-start;
494
+ padding-top: 0;
495
+ bottom: -2em; /* extend past hero bottom → clips there */
496
+ mix-blend-mode: normal;
497
+ }
498
+ .coutumes-hero .ui-editorial-hero-overlay span {
499
+ font-family: var(--coutumes-font-display);
500
+ font-weight: 400;
501
+ font-size: clamp(5rem, 14vw, 18rem);
502
+ }
503
+ /* Bigger gap between SILVER LANDS and CAPSULE */
504
+ .coutumes-hero .ui-editorial-hero-overlay span:nth-child(3) {
505
+ margin-top: 1.7em;
506
+ }
507
+ /* Lock hero images to viewport height (prevents 3/4 aspect-ratio making hero ~1700px tall) */
508
+ .coutumes-hero .ui-editorial-hero-images {
509
+ aspect-ratio: unset;
510
+ height: 100svh;
511
+ }
512
+
513
+ /* Pull hero up behind the sticky nav so the text clips at the top */
514
+ .coutumes-hero {
515
+ margin-top: -40px;
516
+ }
517
+
518
+ /* Image pair links */
519
+ .ui-image-pair {
520
+ background: var(--coutumes-white);
521
+ }
522
+
523
+ .ui-image-pair-link {
524
+ font-family: var(--coutumes-font-body);
525
+ color: var(--coutumes-black);
526
+ padding: 0.75rem 0;
527
+ display: block;
528
+ }
529
+
530
+ /* Product grid — name/price below image */
531
+ .coutumes-product-grid .ui-product-card-caption {
532
+ background: var(--coutumes-white);
533
+ padding-bottom: 10rem;
534
+ }
535
+ .coutumes-product-grid .ui-product-card-name {
536
+ font-family: var(--coutumes-font-body);
537
+ font-size: 1.0625rem;
538
+ color: var(--coutumes-black);
539
+ }
540
+ .coutumes-product-grid .ui-product-card-price {
541
+ font-family: var(--coutumes-font-ui);
542
+ font-size: 0.875rem;
543
+ color: var(--coutumes-black);
544
+ opacity: 0.75;
545
+ }
546
+
547
+ /* Editorial quote — non-italic, generous padding, narrow column */
548
+ #collection {
549
+ background: var(--coutumes-white);
550
+ position: relative;
551
+ z-index: 1;
552
+ }
553
+ #collection .ui-pullquote--editorial {
554
+ padding: 8rem 1.5rem;
555
+ }
556
+ #collection .ui-pullquote--editorial .ui-pullquote-text {
557
+ font-style: normal;
558
+ max-width: 480px;
559
+ font-family: var(--coutumes-font-body);
560
+ color: var(--coutumes-black);
561
+ font-size: clamp(1.5rem, 2.5vw, 1.875rem);
562
+ line-height: 1.25;
563
+ }
564
+ #collection .ui-pullquote--editorial .ui-pullquote-cite {
565
+ font-style: italic;
566
+ font-family: var(--coutumes-font-body);
567
+ font-size: 0.875rem;
568
+ color: var(--coutumes-black);
569
+ margin-top: 1.5rem;
570
+ }
571
+
572
+ /* Fix nav — serif font, correct size, no wrapping */
573
+ .ui-nav .ui-nav-logo {
574
+ color: var(--coutumes-black);
575
+ font-family: var(--coutumes-font-display);
576
+ }
577
+ .ui-nav .ui-nav-link {
578
+ color: var(--coutumes-black);
579
+ font-family: var(--coutumes-font-body);
580
+ font-size: 1.0625rem;
581
+ white-space: nowrap;
582
+ letter-spacing: 0.02em;
583
+ }
584
+