bsmnt 0.6.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/application/add-integration/index.d.ts.map +1 -1
  2. package/dist/application/add-integration/index.js +30 -4
  3. package/dist/application/add-integration/index.js.map +1 -1
  4. package/dist/application/shared/node-version.d.ts +8 -0
  5. package/dist/application/shared/node-version.d.ts.map +1 -0
  6. package/dist/application/shared/node-version.js +31 -0
  7. package/dist/application/shared/node-version.js.map +1 -0
  8. package/dist/application/shared/strip-ansi.d.ts +3 -0
  9. package/dist/application/shared/strip-ansi.d.ts.map +1 -0
  10. package/dist/application/shared/strip-ansi.js +7 -0
  11. package/dist/application/shared/strip-ansi.js.map +1 -0
  12. package/dist/core/create/execute-plan.d.ts +3 -0
  13. package/dist/core/create/execute-plan.d.ts.map +1 -1
  14. package/dist/core/create/execute-plan.js +3 -0
  15. package/dist/core/create/execute-plan.js.map +1 -1
  16. package/dist/domain/cms.d.ts +2 -0
  17. package/dist/domain/cms.d.ts.map +1 -1
  18. package/dist/domain/cms.js +1 -0
  19. package/dist/domain/cms.js.map +1 -1
  20. package/dist/domain/forms.d.ts +2 -2
  21. package/dist/domain/forms.js +1 -1
  22. package/dist/domain/forms.js.map +1 -1
  23. package/dist/domain/integration.d.ts +7 -3
  24. package/dist/domain/integration.d.ts.map +1 -1
  25. package/dist/domain/integration.js.map +1 -1
  26. package/dist/domain/skills.d.ts +26 -8
  27. package/dist/domain/skills.d.ts.map +1 -1
  28. package/dist/domain/skills.js +30 -9
  29. package/dist/domain/skills.js.map +1 -1
  30. package/dist/index.js +132 -16
  31. package/dist/index.js.map +1 -1
  32. package/dist/infrastructure/create/executor.d.ts.map +1 -1
  33. package/dist/infrastructure/create/executor.js +2 -1
  34. package/dist/infrastructure/create/executor.js.map +1 -1
  35. package/dist/infrastructure/create/init-git-repo.d.ts +11 -7
  36. package/dist/infrastructure/create/init-git-repo.d.ts.map +1 -1
  37. package/dist/infrastructure/create/init-git-repo.js +21 -18
  38. package/dist/infrastructure/create/init-git-repo.js.map +1 -1
  39. package/dist/infrastructure/create/sanity-auth.d.ts +11 -0
  40. package/dist/infrastructure/create/sanity-auth.d.ts.map +1 -0
  41. package/dist/infrastructure/create/sanity-auth.js +72 -0
  42. package/dist/infrastructure/create/sanity-auth.js.map +1 -0
  43. package/dist/infrastructure/create/setup-agent.d.ts +4 -3
  44. package/dist/infrastructure/create/setup-agent.d.ts.map +1 -1
  45. package/dist/infrastructure/create/setup-agent.js +51 -30
  46. package/dist/infrastructure/create/setup-agent.js.map +1 -1
  47. package/dist/infrastructure/create/setup-dotenvx.js +1 -1
  48. package/dist/infrastructure/create/setup-dotenvx.js.map +1 -1
  49. package/dist/infrastructure/create/setup-remote.d.ts +14 -0
  50. package/dist/infrastructure/create/setup-remote.d.ts.map +1 -0
  51. package/dist/infrastructure/create/setup-remote.js +139 -0
  52. package/dist/infrastructure/create/setup-remote.js.map +1 -0
  53. package/dist/infrastructure/create/setup-sanity.d.ts +3 -2
  54. package/dist/infrastructure/create/setup-sanity.d.ts.map +1 -1
  55. package/dist/infrastructure/create/setup-sanity.js +34 -49
  56. package/dist/infrastructure/create/setup-sanity.js.map +1 -1
  57. package/dist/modules/features/env/dotenvx/config.d.ts.map +1 -1
  58. package/dist/modules/features/env/dotenvx/config.js +6 -0
  59. package/dist/modules/features/env/dotenvx/config.js.map +1 -1
  60. package/dist/paths.d.ts +0 -2
  61. package/dist/paths.d.ts.map +1 -1
  62. package/dist/paths.js +0 -2
  63. package/dist/paths.js.map +1 -1
  64. package/package.json +3 -3
  65. package/src/agent-skills/hubspot-pagebuilder-block/SKILL.md +160 -0
  66. package/src/agent-skills/rss-feed/SKILL.md +158 -0
  67. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/sanity.config.ts +3 -0
  68. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/sanity.config.ts +3 -0
  69. package/src/modules/features/cms/sanity-pagebuilder/files/lib/scripts/sanity-typegen.ts +16 -25
  70. package/src/modules/features/env/dotenvx/files/push-keys.mjs +7 -7
  71. package/src/modules/features/env/dotenvx/files/save-key.mjs +27 -12
  72. package/src/modules/features/env/dotenvx/files/setup-remote.ts +182 -0
  73. package/src/modules/features/forms/hubspot/files/_sanity-adapter/form-block.ts +60 -0
  74. package/src/modules/features/forms/hubspot/files/_sanity-adapter/form-field.ts +30 -0
  75. package/src/modules/features/forms/hubspot/files/_sanity-adapter/form-select-input.tsx +169 -0
  76. package/src/modules/features/forms/hubspot/files/lib/integrations/hubspot/README.md +114 -0
  77. package/src/modules/features/forms/hubspot/files/lib/integrations/hubspot/embed.tsx +165 -0
  78. package/src/modules/features/forms/hubspot/files/lib/integrations/hubspot/form-selection.ts +40 -0
  79. package/src/modules/features/forms/hubspot/files/lib/integrations/hubspot/form.tsx +29 -0
  80. package/src/modules/features/forms/hubspot/files/lib/integrations/hubspot/forms.ts +142 -0
  81. package/src/modules/features/forms/hubspot/files/lib/integrations/hubspot/hubspot-form.css +634 -0
  82. package/src/modules/features/forms/hubspot/files/lib/integrations/hubspot/skeleton.tsx +24 -0
  83. package/src/templates/next-default/README.md +1 -0
  84. package/src/templates/next-default/knip.json +9 -1
  85. package/src/templates/next-experiments/README.md +1 -0
  86. package/src/templates/next-experiments/knip.json +9 -1
  87. package/src/templates/next-pagebuilder/README.md +1 -0
  88. package/src/templates/next-pagebuilder/knip.json +7 -2
  89. package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.types.ts +1197 -176
  90. package/src/templates/next-webgl/README.md +1 -0
  91. package/src/templates/next-webgl/knip.json +9 -1
@@ -0,0 +1,634 @@
1
+ /* Styles HubSpot's injected DOM, scoped under `.hubspot-form-wrapper`.
2
+ *
3
+ * Tokens map onto the basement starter design system — `--color-primary`
4
+ * (surface), `--color-secondary` (text), `--color-contrast` (accent) and
5
+ * `--font-mono` — so the form inherits the project's palette and light/dark
6
+ * theme (`[data-theme]`) automatically. Each maps with a standalone fallback
7
+ * for use outside the starter. Override any `--hs-*` from a parent scope to
8
+ * customize. */
9
+
10
+ .hubspot-form-wrapper,
11
+ .hubspot-form-card {
12
+ --hs-surface: var(--color-primary, #ffffff);
13
+ --hs-surface-focus: color-mix(
14
+ in srgb,
15
+ var(--color-secondary, #000000) 8%,
16
+ var(--color-primary, #ffffff)
17
+ );
18
+ --hs-border: color-mix(
19
+ in srgb,
20
+ var(--color-secondary, #000000) 28%,
21
+ transparent
22
+ );
23
+ --hs-card-border: color-mix(
24
+ in srgb,
25
+ var(--color-secondary, #000000) 16%,
26
+ transparent
27
+ );
28
+ --hs-muted: var(--color-gray-400, #858585);
29
+ --hs-text: var(--color-secondary, #18181b);
30
+ --hs-text-strong: var(--color-secondary, #18181b);
31
+ --hs-accent: var(--color-contrast, #ff4d00);
32
+ --hs-accent-contrast: var(--color-primary, #ffffff);
33
+ --hs-error: #ff5c5c;
34
+
35
+ /* Prefer the host's sans font, then its mono (the starter ships mono only),
36
+ * then a system stack. */
37
+ --hs-font-sans: var(
38
+ --font-sans,
39
+ var(--font-mono, ui-sans-serif, system-ui, sans-serif)
40
+ );
41
+ --hs-font-mono: var(--font-mono, ui-monospace, monospace);
42
+ --hs-radius: 4px;
43
+
44
+ /* Grid rhythm: column gap, row gap, inline-error gutter. */
45
+ --hs-col-gap: 1.125rem;
46
+ --hs-row-gap: 0.5rem;
47
+ --hs-error-gutter: 18px;
48
+
49
+ --hs-select-arrow: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%23858585'><path d='M5.23 7.21a.75.75 0 011.06.02L10 11.06l3.71-3.83a.75.75 0 111.08 1.04l-4.25 4.39a.75.75 0 01-1.08 0L5.21 8.27a.75.75 0 01.02-1.06z'/></svg>");
50
+ }
51
+
52
+ /* ---------- Card (optional wrapper from <HubSpotForm />) ---------- */
53
+ .hubspot-form-card {
54
+ display: flex;
55
+ flex-direction: column;
56
+ gap: 1.5rem;
57
+ width: 100%;
58
+ padding: 1.5rem;
59
+ border: 1px solid var(--hs-card-border);
60
+ border-radius: calc(var(--hs-radius) * 2);
61
+ background: var(--hs-surface);
62
+ }
63
+
64
+ /* ---------- Wrapper ---------- */
65
+ .hubspot-form-wrapper {
66
+ position: relative;
67
+ display: flex;
68
+ flex-direction: column;
69
+ /* Reserve space so remote forms (unmeasurable at SSR) shift the page less. */
70
+ min-height: 400px;
71
+ }
72
+
73
+ .hubspot-form-error {
74
+ text-align: center;
75
+ font-family: var(--hs-font-sans);
76
+ font-size: 0.875rem;
77
+ color: var(--hs-error);
78
+ }
79
+
80
+ /* ---------- Loading skeleton ----------
81
+ * In-flow (flex: 1) so it fills the reserved min-height on desktop and grows
82
+ * the card on mobile, where stacked fields exceed 400px. */
83
+ .hubspot-form-skeleton {
84
+ flex: 1;
85
+ display: flex;
86
+ flex-direction: column;
87
+ gap: 1.5rem;
88
+ pointer-events: none;
89
+ animation: hubspot-form-skeleton-pulse 1.4s ease-in-out infinite;
90
+ }
91
+
92
+ .hubspot-form-skeleton-row {
93
+ display: grid;
94
+ grid-template-columns: 1fr 1fr;
95
+ gap: var(--hs-col-gap);
96
+ }
97
+
98
+ @media (max-width: 767px) {
99
+ .hubspot-form-skeleton-row {
100
+ grid-template-columns: 1fr;
101
+ }
102
+ }
103
+
104
+ /* Label bar (::before) above an input bar (::after), mirroring a real field. */
105
+ .hubspot-form-skeleton-field {
106
+ display: flex;
107
+ flex-direction: column;
108
+ gap: 0.5rem;
109
+ }
110
+
111
+ .hubspot-form-skeleton-field::before {
112
+ content: "";
113
+ width: 40%;
114
+ height: 12px;
115
+ border-radius: var(--hs-radius);
116
+ background: var(--hs-surface-focus);
117
+ }
118
+
119
+ .hubspot-form-skeleton-field::after {
120
+ content: "";
121
+ height: 42px;
122
+ border-radius: var(--hs-radius);
123
+ background: var(--hs-surface-focus);
124
+ }
125
+
126
+ .hubspot-form-skeleton-field--textarea::after {
127
+ height: 118px;
128
+ }
129
+
130
+ /* Sits at the bottom of the reserved area, like the real submit button. */
131
+ .hubspot-form-skeleton-button {
132
+ margin-top: auto;
133
+ height: 32px;
134
+ border-radius: var(--hs-radius);
135
+ background: var(--hs-surface-focus);
136
+ }
137
+
138
+ @keyframes hubspot-form-skeleton-pulse {
139
+ 0%,
140
+ 100% {
141
+ opacity: 1;
142
+ }
143
+ 50% {
144
+ opacity: 0.55;
145
+ }
146
+ }
147
+
148
+ @media (prefers-reduced-motion: reduce) {
149
+ .hubspot-form-skeleton {
150
+ animation: none;
151
+ }
152
+ }
153
+
154
+ /* ---------- Iframe fallback (HubSpot Free portals) ---------- */
155
+ .hubspot-form-embed .hs-form-iframe {
156
+ display: block;
157
+ width: 100%;
158
+ border: 0;
159
+ }
160
+
161
+ /* ---------- Form grid ----------
162
+ * Text fields pair into a 2-col grid; full-width types span both columns. */
163
+ .hubspot-form-embed .hs-form-private {
164
+ position: relative;
165
+ display: grid;
166
+ grid-template-columns: repeat(2, minmax(0, 1fr));
167
+ column-gap: var(--hs-col-gap);
168
+ /* Each field reserves --hs-error-gutter below, so input-to-input spacing is
169
+ * row-gap + gutter. */
170
+ row-gap: var(--hs-row-gap);
171
+ }
172
+
173
+ @media (max-width: 767px) {
174
+ .hubspot-form-embed .hs-form-private {
175
+ grid-template-columns: 1fr;
176
+ }
177
+ }
178
+
179
+ .hubspot-form-embed .hs-form-private > .hs-fieldtype-textarea,
180
+ .hubspot-form-embed .hs-form-private > .hs-fieldtype-booleancheckbox,
181
+ .hubspot-form-embed .hs-form-private > .hs-fieldtype-radio,
182
+ .hubspot-form-embed .hs-form-private > .hs-fieldtype-select,
183
+ .hubspot-form-embed .hs-form-private > .hs-richtext,
184
+ .hubspot-form-embed .hs-form-private > .legal-consent-container,
185
+ .hubspot-form-embed .hs-form-private > .hs_submit,
186
+ /* HubSpot sometimes wraps section-heading rich text in an unnamed <div> that
187
+ * becomes the grid child — span it full width too. */
188
+ .hubspot-form-embed .hs-form-private
189
+ > div:has(> .hs-richtext.hs-main-font-element) {
190
+ grid-column: 1 / -1;
191
+ }
192
+
193
+ /* HubSpot's legacy fieldset layout (fallback). */
194
+ .hubspot-form-embed .hs-form-private fieldset {
195
+ max-width: none;
196
+ border: 0;
197
+ margin: 0;
198
+ padding: 0;
199
+ grid-column: 1 / -1;
200
+ }
201
+
202
+ /* HubSpot V3 wraps fields in `<fieldset>`s; keep the same grid rhythm. */
203
+ .hubspot-form-embed .hs-form-private fieldset.form-columns-1 {
204
+ display: grid;
205
+ grid-template-columns: 1fr;
206
+ row-gap: var(--hs-row-gap);
207
+ }
208
+
209
+ .hubspot-form-embed .hs-form-private fieldset.form-columns-2 {
210
+ display: grid;
211
+ grid-template-columns: 1fr 1fr;
212
+ column-gap: var(--hs-col-gap);
213
+ row-gap: var(--hs-row-gap);
214
+ }
215
+
216
+ .hubspot-form-embed .hs-form-private fieldset > .hs-richtext {
217
+ grid-column: 1 / -1;
218
+ }
219
+
220
+ /* Extra top space above section headings (skip the first child). */
221
+ .hubspot-form-embed .hs-form-private
222
+ > fieldset:has(> .hs-richtext.hs-main-font-element):not(:first-child),
223
+ .hubspot-form-embed
224
+ .hs-form-private
225
+ > div:has(> .hs-richtext.hs-main-font-element):not(:first-child) {
226
+ margin-top: 0.5rem;
227
+ }
228
+
229
+ .hubspot-form-embed .hs-form-private fieldset.form-columns-3 {
230
+ display: grid;
231
+ grid-template-columns: 1fr 1fr 1fr;
232
+ gap: 1.125rem;
233
+ }
234
+
235
+ @media (max-width: 767px) {
236
+ .hubspot-form-embed .hs-form-private fieldset.form-columns-2,
237
+ .hubspot-form-embed .hs-form-private fieldset.form-columns-3 {
238
+ grid-template-columns: 1fr;
239
+ gap: var(--hs-row-gap);
240
+ }
241
+ }
242
+
243
+ .hubspot-form-embed .hs-form-private fieldset .hs-form-field {
244
+ width: 100%;
245
+ float: none;
246
+ /* Keep the bottom error gutter; zero the other sides. */
247
+ padding-left: 0;
248
+ padding-right: 0;
249
+ padding-top: 0;
250
+ padding-bottom: var(--hs-error-gutter);
251
+ }
252
+
253
+ /* Pull HubSpot's tracking inputs/iframes out of the grid so they don't claim
254
+ * cells. */
255
+ .hubspot-form-embed .hs-form-private > input[type="hidden"],
256
+ .hubspot-form-embed .hs-form-private > iframe {
257
+ position: absolute;
258
+ width: 0;
259
+ height: 0;
260
+ pointer-events: none;
261
+ visibility: hidden;
262
+ }
263
+
264
+ /* ---------- Field ----------
265
+ * padding-bottom reserves the error gutter so toggling an error never shifts. */
266
+ .hubspot-form-embed .hs-form-field {
267
+ position: relative;
268
+ display: flex;
269
+ flex-direction: column;
270
+ gap: 0.5rem;
271
+ padding-bottom: var(--hs-error-gutter);
272
+ }
273
+
274
+ .hubspot-form-embed .hs-form-field > .input {
275
+ width: 100%;
276
+ margin: 0;
277
+ }
278
+
279
+ /* ---------- Label ---------- */
280
+ .hubspot-form-embed .hs-form-field > label {
281
+ margin: 0;
282
+ font-family: var(--hs-font-sans);
283
+ font-size: 0.875rem;
284
+ font-weight: 400;
285
+ line-height: 1.2;
286
+ letter-spacing: -0.01em;
287
+ color: var(--hs-text);
288
+ }
289
+
290
+ .hubspot-form-embed .hs-form-required {
291
+ margin-left: 2px;
292
+ color: var(--hs-text);
293
+ }
294
+
295
+ .hubspot-form-embed .hs-field-desc {
296
+ margin: 0;
297
+ font-family: var(--hs-font-sans);
298
+ font-size: 0.75rem;
299
+ line-height: 1.2;
300
+ color: var(--hs-muted);
301
+ }
302
+
303
+ /* ---------- Inputs ---------- */
304
+ .hubspot-form-embed .hs-input {
305
+ display: block;
306
+ box-sizing: border-box;
307
+ width: 100%;
308
+ height: 42px;
309
+ padding: 10px 12px;
310
+ border: 1px solid var(--hs-border);
311
+ border-radius: var(--hs-radius);
312
+ background: var(--hs-surface);
313
+ font-family: var(--hs-font-sans);
314
+ font-size: 0.875rem;
315
+ font-weight: 400;
316
+ line-height: 1.2;
317
+ letter-spacing: -0.01em;
318
+ color: var(--hs-text);
319
+ transition:
320
+ border-color 150ms ease,
321
+ background-color 150ms ease;
322
+ }
323
+
324
+ .hubspot-form-embed .hs-input::placeholder {
325
+ color: var(--hs-muted);
326
+ opacity: 1;
327
+ }
328
+
329
+ .hubspot-form-embed
330
+ .hs-input:hover:not(:disabled):not(.invalid):not(.error):not(:focus) {
331
+ border-color: var(--hs-muted);
332
+ }
333
+
334
+ .hubspot-form-embed .hs-input:focus,
335
+ .hubspot-form-embed .hs-input:focus-visible {
336
+ background: var(--hs-surface-focus);
337
+ border-color: var(--hs-accent);
338
+ outline: none;
339
+ }
340
+
341
+ /* Override autofill's background with an inset shadow to match the focus fill. */
342
+ .hubspot-form-embed .hs-input:-webkit-autofill,
343
+ .hubspot-form-embed .hs-input:-webkit-autofill:hover,
344
+ .hubspot-form-embed .hs-input:-webkit-autofill:focus {
345
+ -webkit-box-shadow: 0 0 0 1000px var(--hs-surface-focus) inset;
346
+ box-shadow: 0 0 0 1000px var(--hs-surface-focus) inset;
347
+ -webkit-text-fill-color: var(--hs-text);
348
+ caret-color: var(--hs-text);
349
+ }
350
+
351
+ .hubspot-form-embed textarea.hs-input {
352
+ min-height: 118px;
353
+ height: 118px;
354
+ padding: 10px 12px;
355
+ resize: none;
356
+ font-family: var(--hs-font-sans);
357
+ }
358
+
359
+ .hubspot-form-embed select.hs-input {
360
+ appearance: none;
361
+ -webkit-appearance: none;
362
+ padding-right: 36px;
363
+ background-image: var(--hs-select-arrow);
364
+ background-repeat: no-repeat;
365
+ background-position: right 10px center;
366
+ background-size: 16px;
367
+ }
368
+
369
+ /* ---------- Checkbox + Radio ---------- */
370
+ .hubspot-form-embed input[type="checkbox"],
371
+ .hubspot-form-embed input[type="radio"] {
372
+ appearance: none;
373
+ -webkit-appearance: none;
374
+ position: relative;
375
+ flex-shrink: 0;
376
+ box-sizing: border-box;
377
+ width: 20px;
378
+ height: 20px;
379
+ margin: 0;
380
+ border: 1.5px solid var(--hs-border);
381
+ background: var(--hs-surface);
382
+ cursor: pointer;
383
+ transition:
384
+ border-color 150ms ease,
385
+ background-color 150ms ease;
386
+ }
387
+
388
+ .hubspot-form-embed input[type="checkbox"] {
389
+ border-radius: var(--hs-radius);
390
+ }
391
+
392
+ .hubspot-form-embed input[type="radio"] {
393
+ border-radius: 50%;
394
+ }
395
+
396
+ .hubspot-form-embed input[type="checkbox"]:hover:not(:disabled),
397
+ .hubspot-form-embed input[type="radio"]:hover:not(:disabled) {
398
+ border-color: var(--hs-muted);
399
+ }
400
+
401
+ .hubspot-form-embed input[type="checkbox"]:focus-visible,
402
+ .hubspot-form-embed input[type="radio"]:focus-visible {
403
+ outline: 2px solid var(--hs-accent);
404
+ outline-offset: 2px;
405
+ }
406
+
407
+ .hubspot-form-embed input[type="checkbox"]:checked,
408
+ .hubspot-form-embed input[type="radio"]:checked {
409
+ border-color: var(--hs-accent);
410
+ background: var(--hs-accent);
411
+ }
412
+
413
+ /* Checkmark glyph (two borders rotated into a tick) */
414
+ .hubspot-form-embed input[type="checkbox"]:checked::after {
415
+ content: "";
416
+ position: absolute;
417
+ top: 50%;
418
+ left: 50%;
419
+ width: 10px;
420
+ height: 5px;
421
+ border-left: 2px solid var(--hs-accent-contrast);
422
+ border-bottom: 2px solid var(--hs-accent-contrast);
423
+ transform: translate(-50%, -65%) rotate(-45deg);
424
+ }
425
+
426
+ /* Radio inner dot */
427
+ .hubspot-form-embed input[type="radio"]:checked::after {
428
+ content: "";
429
+ position: absolute;
430
+ top: 50%;
431
+ left: 50%;
432
+ width: 8px;
433
+ height: 8px;
434
+ border-radius: 50%;
435
+ background: var(--hs-accent-contrast);
436
+ transform: translate(-50%, -50%);
437
+ }
438
+
439
+ .hubspot-form-embed input[type="checkbox"]:disabled,
440
+ .hubspot-form-embed input[type="radio"]:disabled {
441
+ cursor: not-allowed;
442
+ opacity: 0.55;
443
+ }
444
+
445
+ /* Multi-option lists as a 2-col grid; `.input >` avoids matching
446
+ * .hs-error-msgs (also an .inputs-list). */
447
+ .hubspot-form-embed .input > .inputs-list {
448
+ display: grid;
449
+ grid-template-columns: repeat(2, minmax(0, 1fr));
450
+ gap: 0.75rem 1.125rem;
451
+ margin: 0;
452
+ padding: 0;
453
+ list-style: none;
454
+ }
455
+
456
+ .hubspot-form-embed .hs-form-booleancheckbox .input > .inputs-list {
457
+ grid-template-columns: 1fr;
458
+ }
459
+
460
+ @media (max-width: 767px) {
461
+ .hubspot-form-embed .input > .inputs-list {
462
+ grid-template-columns: 1fr;
463
+ }
464
+ }
465
+
466
+ .hubspot-form-embed .input > .inputs-list > li {
467
+ margin: 0;
468
+ padding: 0;
469
+ list-style: none;
470
+ }
471
+
472
+ .hubspot-form-embed .input > .inputs-list label {
473
+ display: inline-flex;
474
+ align-items: center;
475
+ gap: 0.5rem;
476
+ margin: 0;
477
+ font-family: var(--hs-font-sans);
478
+ font-size: 0.875rem;
479
+ line-height: 1.2;
480
+ letter-spacing: -0.01em;
481
+ color: var(--hs-text);
482
+ cursor: pointer;
483
+ }
484
+
485
+ .hubspot-form-embed .input > .inputs-list label > span {
486
+ user-select: none;
487
+ }
488
+
489
+ /* ---------- Errors ---------- */
490
+ /* Collapse HubSpot's empty `.hs_error_rollup`; errors show per-field instead. */
491
+ .hubspot-form-embed .hs_error_rollup {
492
+ display: none;
493
+ }
494
+
495
+ .hubspot-form-embed .hs-input.invalid,
496
+ .hubspot-form-embed .hs-input.error,
497
+ .hubspot-form-embed .hs-form-field.invalid .hs-input {
498
+ border-color: var(--hs-error);
499
+ }
500
+
501
+ /* Absolutely position the error list into the field's reserved gutter. */
502
+ .hubspot-form-embed .hs-error-msgs {
503
+ position: absolute;
504
+ bottom: 0;
505
+ left: 0;
506
+ right: 0;
507
+ margin: 0;
508
+ padding: 0;
509
+ list-style: none;
510
+ line-height: 1.2;
511
+ }
512
+
513
+ .hubspot-form-embed .hs-error-msgs li {
514
+ margin: 0;
515
+ padding: 0;
516
+ list-style: none;
517
+ line-height: 1.2;
518
+ }
519
+
520
+ .hubspot-form-embed .hs-error-msg {
521
+ display: block;
522
+ margin: 0;
523
+ padding: 0;
524
+ font-family: var(--hs-font-sans);
525
+ font-size: 0.75rem;
526
+ font-weight: 400;
527
+ line-height: 1.2;
528
+ letter-spacing: -0.01em;
529
+ color: var(--hs-error);
530
+ }
531
+
532
+ /* ---------- Submit button ---------- */
533
+ .hubspot-form-embed .hs_submit {
534
+ margin: 0;
535
+ }
536
+
537
+ .hubspot-form-embed .hs_submit .actions {
538
+ display: flex;
539
+ width: 100%;
540
+ margin: 0;
541
+ padding: 0;
542
+ }
543
+
544
+ .hubspot-form-embed .hs-button {
545
+ appearance: none;
546
+ -webkit-appearance: none;
547
+ display: inline-flex;
548
+ align-items: center;
549
+ justify-content: center;
550
+ width: 100%;
551
+ height: 40px;
552
+ padding: 8px 16px;
553
+ border: 1px solid var(--hs-accent);
554
+ border-radius: var(--hs-radius);
555
+ background: var(--hs-accent);
556
+ color: var(--hs-accent-contrast);
557
+ font-family: var(--hs-font-mono);
558
+ font-size: 0.875rem;
559
+ font-weight: 400;
560
+ line-height: 1.2;
561
+ letter-spacing: 0;
562
+ text-transform: uppercase;
563
+ cursor: pointer;
564
+ transition: filter 200ms ease;
565
+ }
566
+
567
+ .hubspot-form-embed .hs-button:hover:not(:disabled) {
568
+ filter: brightness(1.1);
569
+ }
570
+
571
+ .hubspot-form-embed .hs-button:focus-visible {
572
+ outline: 2px solid var(--hs-text-strong);
573
+ outline-offset: 2px;
574
+ }
575
+
576
+ .hubspot-form-embed .hs-button:disabled {
577
+ background: var(--hs-surface-focus);
578
+ border-color: var(--hs-border);
579
+ color: var(--hs-muted);
580
+ cursor: not-allowed;
581
+ }
582
+
583
+ /* ---------- Legal consent (centered) ---------- */
584
+ .hubspot-form-embed .legal-consent-container {
585
+ font-family: var(--hs-font-sans);
586
+ font-size: 0.875rem;
587
+ line-height: 1.2;
588
+ letter-spacing: -0.01em;
589
+ color: var(--hs-muted);
590
+ text-align: center;
591
+ }
592
+
593
+ .hubspot-form-embed .legal-consent-container p {
594
+ margin: 0;
595
+ }
596
+
597
+ /* ---------- Rich text (section headings / help copy, left-aligned) ---------- */
598
+ .hubspot-form-embed .hs-richtext {
599
+ margin-bottom: 1rem;
600
+ font-family: var(--hs-font-sans);
601
+ font-size: 0.875rem;
602
+ line-height: 1.4;
603
+ letter-spacing: -0.01em;
604
+ color: var(--hs-muted);
605
+ }
606
+
607
+ .hubspot-form-embed .hs-richtext > * + * {
608
+ margin-top: 0.5rem;
609
+ }
610
+
611
+ .hubspot-form-embed .hs-richtext h1,
612
+ .hubspot-form-embed .hs-richtext h2,
613
+ .hubspot-form-embed .hs-richtext h3,
614
+ .hubspot-form-embed .hs-richtext h4 {
615
+ margin: 0;
616
+ font-family: var(--hs-font-sans);
617
+ font-size: 1.125rem;
618
+ font-weight: 400;
619
+ line-height: 1.2;
620
+ letter-spacing: -0.01em;
621
+ color: var(--hs-muted);
622
+ }
623
+
624
+ .hubspot-form-embed .hs-richtext p {
625
+ margin: 0;
626
+ }
627
+
628
+ .hubspot-form-embed .legal-consent-container a,
629
+ .hubspot-form-embed .hs-richtext a {
630
+ font-weight: 500;
631
+ color: var(--hs-accent);
632
+ text-decoration: underline;
633
+ text-underline-offset: 2px;
634
+ }
@@ -0,0 +1,24 @@
1
+ export function HubSpotFormSkeleton() {
2
+ return (
3
+ <div
4
+ aria-busy="true"
5
+ aria-label="Loading form"
6
+ className="hubspot-form-skeleton"
7
+ role="status"
8
+ >
9
+ <div className="hubspot-form-skeleton-row" aria-hidden="true">
10
+ <span className="hubspot-form-skeleton-field" />
11
+ <span className="hubspot-form-skeleton-field" />
12
+ </div>
13
+ <div className="hubspot-form-skeleton-row" aria-hidden="true">
14
+ <span className="hubspot-form-skeleton-field" />
15
+ <span className="hubspot-form-skeleton-field" />
16
+ </div>
17
+ <span
18
+ aria-hidden="true"
19
+ className="hubspot-form-skeleton-field hubspot-form-skeleton-field--textarea"
20
+ />
21
+ <span aria-hidden="true" className="hubspot-form-skeleton-button" />
22
+ </div>
23
+ )
24
+ }
@@ -27,6 +27,7 @@ bun dev
27
27
  | `bun env:setup` | Restore `.env.keys` from 1Password |
28
28
  | `bun env:view` | Print the decrypted `.env` (`--preview` / `--prod`) |
29
29
  | `bun env:setup-remote` | Push private keys to GitHub / Vercel (`github`/`vercel`, or pick) |
30
+ | `bun setup-remote` | Create the GitHub repo, link a Vercel project, and push the key to Vercel env |
30
31
  | `bun env:save` | Save the private key to 1Password (Development vault) |
31
32
 
32
33
  ## Environment variables
@@ -9,6 +9,14 @@
9
9
  ],
10
10
  "ignoreDependencies": [
11
11
  "zod",
12
- "@svgr/webpack"
12
+ "@svgr/webpack",
13
+ "gsap",
14
+ "@gsap/react",
15
+ "motion"
16
+ ],
17
+ "ignoreBinaries": [
18
+ "op",
19
+ "gh",
20
+ "vercel"
13
21
  ]
14
22
  }
@@ -27,6 +27,7 @@ bun dev
27
27
  | `bun env:setup` | Restore `.env.keys` from 1Password |
28
28
  | `bun env:view` | Print the decrypted `.env` (`--preview` / `--prod`) |
29
29
  | `bun env:setup-remote` | Push private keys to GitHub / Vercel (`github`/`vercel`, or pick) |
30
+ | `bun setup-remote` | Create the GitHub repo, link a Vercel project, and push the key to Vercel env |
30
31
  | `bun env:save` | Save the private key to 1Password (Development vault) |
31
32
 
32
33
  ## Environment variables
@@ -9,6 +9,14 @@
9
9
  "ignoreDependencies": [
10
10
  "zod",
11
11
  "three",
12
- "@svgr/webpack"
12
+ "@svgr/webpack",
13
+ "gsap",
14
+ "@gsap/react",
15
+ "motion"
16
+ ],
17
+ "ignoreBinaries": [
18
+ "op",
19
+ "gh",
20
+ "vercel"
13
21
  ]
14
22
  }
@@ -26,6 +26,7 @@ bun dev
26
26
  - `bun env:setup` - Restore `.env.keys` from 1Password
27
27
  - `bun env:view` - Print the decrypted `.env` (`--preview` / `--prod`)
28
28
  - `bun env:setup-remote` - Push private keys to GitHub / Vercel (`github`/`vercel`, or pick)
29
+ - `bun setup-remote` - Create the GitHub repo, link a Vercel project, and push the key to Vercel env
29
30
  - `bun env:save` - Save the private key to 1Password (Development vault)
30
31
 
31
32
  ## Environment variables