@funnelsgrove/cli 0.1.87 → 0.1.89

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 (121) hide show
  1. package/dist/apiClient.d.ts +1 -0
  2. package/dist/apiClient.js +32 -1
  3. package/funnel-contract-compatibility.json +28 -28
  4. package/package.json +3 -3
  5. package/template_docs/.funnelsgrove-docs.json +3 -3
  6. package/template_docs/docs/funnelsgrove/migrations/step-contract-v3.md +1 -1
  7. package/template_docs/funnel-docs.config.json +1 -1
  8. package/template_scaffold/.funnelsgrove-docs.json +3 -3
  9. package/template_scaffold/.funnelsgrove-scaffold.json +26 -471
  10. package/template_scaffold/PLAN.md +15 -29
  11. package/template_scaffold/context/build-context.md +3 -3
  12. package/template_scaffold/docs/funnelsgrove/migrations/step-contract-v3.md +1 -1
  13. package/template_scaffold/funnel-docs.config.json +1 -1
  14. package/template_scaffold/package-lock.json +9 -9
  15. package/template_scaffold/package.json +2 -2
  16. package/template_scaffold/public/assets/email-capture-preview.svg +5 -0
  17. package/template_scaffold/public/assets/paywall-preview.svg +6 -0
  18. package/template_scaffold/src/app/sdk/page.tsx +14 -26
  19. package/template_scaffold/src/components/FunnelFlow.tsx +8 -1
  20. package/template_scaffold/src/config/billing.plans.ts +71 -21
  21. package/template_scaffold/src/config/funnel.manifest.ts +20 -59
  22. package/template_scaffold/src/runtime/checkout-runtime-config.ts +0 -7
  23. package/template_scaffold/src/runtime/step-registry.ts +0 -28
  24. package/template_scaffold/src/steps/content/step-01.content.ts +4 -9
  25. package/template_scaffold/src/steps/content/step-32-paywall.content.ts +12 -50
  26. package/template_scaffold/src/steps/step-01.tsx +43 -50
  27. package/template_scaffold/src/steps/step-31-email-capture.tsx +18 -1
  28. package/template_scaffold/src/steps/step-32-paywall.tsx +93 -299
  29. package/template_scaffold/src/steps/step-33-subscription-started.tsx +1 -1
  30. package/template_scaffold/src/steps/step-content.registry.ts +1 -26
  31. package/template_scaffold/public/claimbee/bee.png +0 -0
  32. package/template_scaffold/public/claimbee/device-iphone.png +0 -0
  33. package/template_scaffold/public/claimbee/device-macbook.png +0 -0
  34. package/template_scaffold/public/claimbee/device-none.png +0 -0
  35. package/template_scaffold/public/claimbee/device-watch.png +0 -0
  36. package/template_scaffold/public/claimbee/glow.svg +0 -3
  37. package/template_scaffold/public/claimbee/steps-sprite-alt.png +0 -0
  38. package/template_scaffold/public/claimbee/steps-sprite-default.png +0 -0
  39. package/template_scaffold/public/claimbee/testimonial-avatar.png +0 -0
  40. package/template_scaffold/public/claimbee/testimonial-star.svg +0 -3
  41. package/template_scaffold/public/paywall/ai-claim-assistant.png +0 -0
  42. package/template_scaffold/public/paywall/claim-history.png +0 -0
  43. package/template_scaffold/public/paywall/clear-progress.png +0 -0
  44. package/template_scaffold/public/paywall/hero.png +0 -0
  45. package/template_scaffold/public/paywall/money-alerts.png +0 -0
  46. package/template_scaffold/public/paywall/money-back-badge.png +0 -0
  47. package/template_scaffold/public/paywall/paywall-image.png +0 -0
  48. package/template_scaffold/public/paywall/r1.png +0 -0
  49. package/template_scaffold/public/paywall/r2.png +0 -0
  50. package/template_scaffold/public/paywall/r3.png +0 -0
  51. package/template_scaffold/public/paywall/r4.png +0 -0
  52. package/template_scaffold/public/paywall/r5.png +0 -0
  53. package/template_scaffold/public/paywall/r6.png +0 -0
  54. package/template_scaffold/public/paywall/special-offer-gift.png +0 -0
  55. package/template_scaffold/public/please/bee.png +0 -0
  56. package/template_scaffold/public/please/device-iphone.png +0 -0
  57. package/template_scaffold/public/please/device-macbook.png +0 -0
  58. package/template_scaffold/public/please/device-none.png +0 -0
  59. package/template_scaffold/public/please/device-watch.png +0 -0
  60. package/template_scaffold/public/please/glow.svg +0 -3
  61. package/template_scaffold/public/please/steps-sprite-alt.png +0 -0
  62. package/template_scaffold/public/please/steps-sprite-default.png +0 -0
  63. package/template_scaffold/public/please/testimonial-avatar.png +0 -0
  64. package/template_scaffold/public/please/testimonial-star.svg +0 -3
  65. package/template_scaffold/public/upsell/upgrade-hero.png +0 -0
  66. package/template_scaffold/src/assets/claimbee/bee.png +0 -0
  67. package/template_scaffold/src/assets/claimbee/device-iphone.png +0 -0
  68. package/template_scaffold/src/assets/claimbee/device-macbook.png +0 -0
  69. package/template_scaffold/src/assets/claimbee/device-none.png +0 -0
  70. package/template_scaffold/src/assets/claimbee/device-watch.png +0 -0
  71. package/template_scaffold/src/assets/claimbee/glow.svg +0 -3
  72. package/template_scaffold/src/assets/claimbee/steps-sprite-alt.png +0 -0
  73. package/template_scaffold/src/assets/claimbee/steps-sprite-default.png +0 -0
  74. package/template_scaffold/src/assets/claimbee/testimonial-avatar.png +0 -0
  75. package/template_scaffold/src/assets/claimbee/testimonial-star.svg +0 -3
  76. package/template_scaffold/src/components/FunnelStepImage.tsx +0 -28
  77. package/template_scaffold/src/config/offer-sets.generated.ts +0 -4
  78. package/template_scaffold/src/steps/content/manage-subscription.content.ts +0 -62
  79. package/template_scaffold/src/steps/content/paywall.content.ts +0 -191
  80. package/template_scaffold/src/steps/content/step-02.content.ts +0 -77
  81. package/template_scaffold/src/steps/content/step-03.content.ts +0 -40
  82. package/template_scaffold/src/steps/content/step-04.content.ts +0 -49
  83. package/template_scaffold/src/steps/editor/manage-subscription.editor.ts +0 -179
  84. package/template_scaffold/src/steps/editor/paywall.editor.ts +0 -232
  85. package/template_scaffold/src/steps/editor/step-02.editor.ts +0 -41
  86. package/template_scaffold/src/steps/editor/step-03.editor.ts +0 -58
  87. package/template_scaffold/src/steps/editor/step-04.editor.ts +0 -98
  88. package/template_scaffold/src/steps/pricing/paywall-b.pricing.ts +0 -12
  89. package/template_scaffold/src/steps/step-02.tsx +0 -140
  90. package/template_scaffold/src/steps/step-03.tsx +0 -262
  91. package/template_scaffold/src/steps/step-04.tsx +0 -673
  92. package/template_scaffold/src/steps/step-32b-paywall-b.tsx +0 -35
  93. package/template_scaffold/src/steps/step-35-manage-subscription.tsx +0 -46
  94. package/template_scaffold/src/steps/use-claimbee-step-content.ts +0 -15
  95. package/template_scaffold/tests/funnel-agent-docs.test.ts +0 -751
  96. package/template_scaffold/tests/package.test.ts +0 -37
  97. package/template_scaffold/tests/src/app/[stepId]/page.test.tsx +0 -59
  98. package/template_scaffold/tests/src/app/layout.test.ts +0 -26
  99. package/template_scaffold/tests/src/components/FunnelFlow.test.tsx +0 -38
  100. package/template_scaffold/tests/src/components/FunnelStepImage.test.ts +0 -15
  101. package/template_scaffold/tests/src/config/billing.plans.test.ts +0 -143
  102. package/template_scaffold/tests/src/config/funnel.manifest.test.ts +0 -166
  103. package/template_scaffold/tests/src/contract/funnel-project.validation.test.ts +0 -79
  104. package/template_scaffold/tests/src/contract/golden/golden-fixtures.test.ts +0 -190
  105. package/template_scaffold/tests/src/contract/validate-funnel.cli.test.ts +0 -191
  106. package/template_scaffold/tests/src/runtime/checkout-runtime-config.test.ts +0 -60
  107. package/template_scaffold/tests/src/runtime/funnel-runtime.test.ts +0 -25
  108. package/template_scaffold/tests/src/runtime/step-content-context.test.ts +0 -38
  109. package/template_scaffold/tests/src/runtime/use-funnel-flow-controller.integration.test.ts +0 -203
  110. package/template_scaffold/tests/src/runtime/use-funnel-flow-controller.test.ts +0 -76
  111. package/template_scaffold/tests/src/steps/paywall-checkout-options.test.ts +0 -104
  112. package/template_scaffold/tests/src/steps/shared-header-contract.test.ts +0 -29
  113. package/template_scaffold/tests/src/steps/step-01.test.ts +0 -38
  114. package/template_scaffold/tests/src/steps/step-02.test.ts +0 -43
  115. package/template_scaffold/tests/src/steps/step-03.test.ts +0 -15
  116. package/template_scaffold/tests/src/steps/step-04.test.ts +0 -32
  117. package/template_scaffold/tests/src/steps/step-31-email-capture.test.ts +0 -22
  118. package/template_scaffold/tests/src/steps/step-32-paywall.test.ts +0 -773
  119. package/template_scaffold/tests/src/steps/step-33-subscription-started.test.ts +0 -44
  120. package/template_scaffold/tests/src/steps/step-34-upsell-form.test.ts +0 -27
  121. package/template_scaffold/tests/src/steps/step-image-migration.test.ts +0 -20
@@ -1,8 +1,7 @@
1
- import type { LocalizedStepContent, StepImage } from '@funnelsgrove/runtime';
1
+ import type { LocalizedStepContent } from '@funnelsgrove/runtime';
2
2
 
3
3
  export type StepOneLocaleContent = {
4
4
  headline: readonly string[];
5
- artwork: StepImage;
6
5
  };
7
6
 
8
7
  export const stepOneContent = {
@@ -10,14 +9,10 @@ export const stepOneContent = {
10
9
  locales: {
11
10
  en: {
12
11
  headline: [
13
- 'People getting',
14
- 'free money',
15
- 'know one secret',
12
+ 'Build a plan',
13
+ 'made for you',
14
+ 'in a few quick steps',
16
15
  ],
17
- artwork: {
18
- src: '/claimbee/steps-sprite-default.png',
19
- alt: '',
20
- },
21
16
  },
22
17
  },
23
18
  } as const satisfies LocalizedStepContent<StepOneLocaleContent>;
@@ -76,8 +76,6 @@ type StepPaywallLocaleContent = {
76
76
  subtitle: string;
77
77
  assistant: InfoItem;
78
78
  quickFeatures: readonly InfoItem[];
79
- history: InfoItem;
80
- detailedFeatures: readonly InfoItem[];
81
79
  };
82
80
  stories: {
83
81
  title: string;
@@ -106,8 +104,8 @@ export const stepPaywallContent = {
106
104
  hero: {
107
105
  pills: ['Find hidden money and', "claim what's yours"],
108
106
  image: {
109
- src: '/paywall/hero.png',
110
- alt: 'ClaimBee family illustration',
107
+ src: '',
108
+ alt: '',
111
109
  },
112
110
  },
113
111
  promo: {
@@ -118,7 +116,7 @@ export const stepPaywallContent = {
118
116
  highlight: {
119
117
  title: ['Get money you', 'didn’t know about'],
120
118
  description:
121
- 'Discover settlement payouts you’re owed from past purchases, ClaimBee finds them for you.',
119
+ 'Discover settlement payouts you’re owed from past purchases. The app finds them for you.',
122
120
  },
123
121
  plans: {
124
122
  title: 'Choose your plan',
@@ -178,8 +176,8 @@ export const stepPaywallContent = {
178
176
  "You'll be charged {amount} today for your selected plan. Your subscription renews automatically unless cancelled at least 24 hours before renewal date.",
179
177
  specialOffer: {
180
178
  image: {
181
- src: '/paywall/special-offer-gift.png',
182
- alt: 'Gift box with offer label',
179
+ src: 'data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22160%22 height=%22120%22 viewBox=%220 0 160 120%22%3E%3Crect x=%2240%22 y=%2242%22 width=%2280%22 height=%2260%22 rx=%2214%22 fill=%22%234361ee%22/%3E%3Cpath d=%22M80 42v60M38 62h84%22 stroke=%22white%22 stroke-width=%228%22/%3E%3Cpath d=%22M78 41c-21 0-30-23-12-23 10 0 14 12 14 23Zm4 0c21 0 30-23 12-23-10 0-14 12-14 23Z%22 fill=%22none%22 stroke=%22%234361ee%22 stroke-width=%228%22/%3E%3C/svg%3E',
180
+ alt: 'Gift box',
183
181
  },
184
182
  discountLabel: '-46%',
185
183
  title: 'Special Offer',
@@ -195,12 +193,6 @@ export const stepPaywallContent = {
195
193
  assistant: {
196
194
  id: 'assistant',
197
195
  title: 'AI claim assistant',
198
- description:
199
- 'It reviews your info, finds matches, and shows you what to do next',
200
- image: {
201
- src: '/paywall/ai-claim-assistant.png',
202
- alt: 'AI claim assistant illustration',
203
- },
204
196
  },
205
197
  quickFeatures: [
206
198
  {
@@ -220,36 +212,6 @@ export const stepPaywallContent = {
220
212
  title: 'Unlimited\nclaim checks',
221
213
  },
222
214
  ],
223
- history: {
224
- id: 'history',
225
- title: 'Claim for your own past\nbuys, bills, or services',
226
- image: {
227
- src: '/paywall/claim-history.png',
228
- alt: 'Past claims illustration',
229
- },
230
- },
231
- detailedFeatures: [
232
- {
233
- id: 'tracking',
234
- title: 'Clear progress\nand tracking',
235
- description:
236
- 'See which claims you started, submitted, and are waiting to be paid.',
237
- image: {
238
- src: '/paywall/clear-progress.png',
239
- alt: 'Claim progress illustration',
240
- },
241
- },
242
- {
243
- id: 'alerts',
244
- title: 'Personalized\nMoney Alerts',
245
- description:
246
- 'Instant alerts when we find a new settlement you could qualify for.',
247
- image: {
248
- src: '/paywall/money-alerts.png',
249
- alt: 'Money alert illustration',
250
- },
251
- },
252
- ],
253
215
  },
254
216
  stories: {
255
217
  title: 'Stories from our users',
@@ -257,7 +219,7 @@ export const stepPaywallContent = {
257
219
  {
258
220
  id: 'elizabeth',
259
221
  quote:
260
- 'I realized ClaimBee saves me more money than it costs - this pays for itself',
222
+ 'I realized the app saves me more money than it costs - this pays for itself',
261
223
  author: 'Elizabeth L.',
262
224
  },
263
225
  {
@@ -280,7 +242,7 @@ export const stepPaywallContent = {
280
242
  {
281
243
  id: 'peter',
282
244
  quote:
283
- 'ClaimBee told me about money I was owed even though my friends and social feeds never mentioned it.',
245
+ 'The app told me about money I was owed even though my friends and social feeds never mentioned it.',
284
246
  author: 'Peter P.',
285
247
  },
286
248
  {
@@ -306,21 +268,21 @@ export const stepPaywallContent = {
306
268
  question:
307
269
  'What if there’s a settlement for an item I bought years ago and I don’t have the receipt?',
308
270
  answer:
309
- 'Don’t worry, this is very common. Many settlements do not require proof of purchase for smaller claim amounts.\n\nFurthermore, ClaimBee can help you search your connected digital history for records you might have forgotten existed, helping you "restore" a claim you might have otherwise abandoned.',
271
+ 'Don’t worry, this is very common. Many settlements do not require proof of purchase for smaller claim amounts.\n\nThe app can also help you search your connected digital history for records you might have forgotten existed, helping you "restore" a claim you might have otherwise abandoned.',
310
272
  },
311
273
  {
312
274
  id: 'faq-scam',
313
275
  question:
314
276
  'This sounds too good to be true. Is this a scam or a "free money" scheme?',
315
277
  answer:
316
- 'Not at all. We aren’t generating "free money"; we are simply helping you claim money that is already yours legally.\n\nSettlements are court-ordered compensations for wrongdoings. ClaimBee is just a tool that organizes this fragmented legal data to make the process accessible, transparent, and manageable for you.',
278
+ 'Not at all. We aren’t generating "free money"; we are simply helping you claim money that is already yours legally.\n\nThe app is a tool that organizes this fragmented legal data to make the process accessible, transparent, and manageable for you.',
317
279
  },
318
280
  {
319
281
  id: 'faq-approval',
320
282
  question:
321
283
  'If I file through an app, is my claim less likely to be approved than if I filed on the official website?',
322
284
  answer:
323
- 'No. When you submit through ClaimBee, we generate the exact information and forms required by the settlement administrator.\n\nThe legal validity is the same; we just make the experience of filling it out much faster and less prone to errors than the manual method.',
285
+ 'No. When you submit through the app, we generate the exact information and forms required by the settlement administrator.\n\nThe legal validity is the same; we just make the experience of filling it out much faster and less prone to errors than the manual method.',
324
286
  },
325
287
  {
326
288
  id: 'faq-fees',
@@ -333,8 +295,8 @@ export const stepPaywallContent = {
333
295
  },
334
296
  guarantee: {
335
297
  image: {
336
- src: '/paywall/money-back-badge.png',
337
- alt: '30 day money back guarantee badge',
298
+ src: '',
299
+ alt: '',
338
300
  },
339
301
  title: 'Money-Back guarantee',
340
302
  description:
@@ -1,46 +1,21 @@
1
- import { useState } from 'react';
2
- import { FunnelStepImage } from '@/components/FunnelStepImage';
3
1
  import { FunnelStepHeader } from '@/components/step/FunnelStepHeader';
4
2
  import {
5
3
  usePreviewStepLocalizedContent,
6
4
  useFunnel,
7
- type StepImage,
8
5
  type FunnelStepMeta,
9
6
  } from '@funnelsgrove/runtime';
10
- import stepsSpriteDefault from '@/assets/claimbee/steps-sprite-default.png';
11
7
  import { getStepContentLocale } from '@/runtime/step-content-context';
12
8
  import { stepOneContent } from '@/steps/content/step-01.content';
13
9
 
14
10
  export const stepOneId = 'step-1';
15
11
 
16
- type ImportedStepAsset = string | { src: string };
17
-
18
- export const resolveStepOneImportedAssetSrc = (asset: ImportedStepAsset): string => {
19
- return typeof asset === 'string' ? asset : asset.src;
20
- };
21
-
22
- export const resolveStepOneArtworkSrc = (
23
- artwork: StepImage | null | undefined,
24
- fallbackSrc: string,
25
- hasLoadError = false,
26
- ): string => {
27
- const configuredSrc = artwork?.src?.trim() || '';
28
- if (!hasLoadError && configuredSrc) {
29
- return configuredSrc;
30
- }
31
-
32
- return fallbackSrc;
33
- };
34
-
35
- const stepOneFallbackArtworkSrc = resolveStepOneImportedAssetSrc(stepsSpriteDefault);
36
-
37
12
  export const stepOne: FunnelStepMeta = {
38
13
  id: stepOneId,
39
14
  name: 'step-1',
40
15
  type: 'intro_hero',
41
16
  figmaNodeId: 'template-01-intro',
42
- title: 'People getting free money know one secret',
43
- description: 'ClaimBee-style opening hero with resilient sprite fallback.',
17
+ title: 'Build a plan that fits you',
18
+ description: 'Lightweight opening step with no image dependencies.',
44
19
  };
45
20
 
46
21
  export function StepOne() {
@@ -50,14 +25,6 @@ export function StepOne() {
50
25
  stepOneContent,
51
26
  getStepContentLocale(attributes),
52
27
  );
53
- const configuredArtworkSrc = content.artwork.src?.trim() || '';
54
- const [failedArtworkSrc, setFailedArtworkSrc] = useState<string | null>(null);
55
- const artworkSrc = resolveStepOneArtworkSrc(
56
- content.artwork,
57
- stepOneFallbackArtworkSrc,
58
- Boolean(configuredArtworkSrc) && failedArtworkSrc === configuredArtworkSrc,
59
- );
60
-
61
28
  return (
62
29
  <>
63
30
  <section className="figma-step-screen step-one-screen" data-node-id="template:01-intro">
@@ -73,21 +40,10 @@ export function StepOne() {
73
40
  }
74
41
  />
75
42
 
76
- <div className="figma-artwork" aria-hidden>
77
- <FunnelStepImage
78
- src={artworkSrc}
79
- alt={content.artwork.alt || ''}
80
- width={stepsSpriteDefault.width}
81
- height={stepsSpriteDefault.height}
82
- className="figma-artwork-sprite"
83
- draggable={false}
84
- priority
85
- onError={() => {
86
- if (configuredArtworkSrc) {
87
- setFailedArtworkSrc(configuredArtworkSrc);
88
- }
89
- }}
90
- />
43
+ <div className="template-starter-art" aria-hidden>
44
+ <span className="template-starter-orbit template-starter-orbit-one" />
45
+ <span className="template-starter-orbit template-starter-orbit-two" />
46
+ <span className="template-starter-mark">✓</span>
91
47
  </div>
92
48
  </section>
93
49
 
@@ -105,4 +61,41 @@ const stepOneStyles = `
105
61
  .step-one-screen .figma-headline-line.is-accent {
106
62
  color: var(--color-primary);
107
63
  }
64
+
65
+ .template-starter-art {
66
+ position: relative;
67
+ width: min(72vw, 310px);
68
+ aspect-ratio: 1;
69
+ margin: auto;
70
+ display: grid;
71
+ place-items: center;
72
+ border-radius: 999px;
73
+ background: color-mix(in srgb, var(--color-primary) 12%, white);
74
+ }
75
+
76
+ .template-starter-orbit {
77
+ position: absolute;
78
+ inset: 14%;
79
+ border: 2px solid color-mix(in srgb, var(--color-primary) 28%, transparent);
80
+ border-radius: 42% 58% 54% 46%;
81
+ transform: rotate(24deg);
82
+ }
83
+
84
+ .template-starter-orbit-two {
85
+ inset: 26%;
86
+ transform: rotate(-32deg);
87
+ }
88
+
89
+ .template-starter-mark {
90
+ display: grid;
91
+ width: 96px;
92
+ height: 96px;
93
+ place-items: center;
94
+ border-radius: 30px;
95
+ background: var(--color-primary);
96
+ color: white;
97
+ font-size: 52px;
98
+ font-weight: 800;
99
+ box-shadow: 0 22px 50px color-mix(in srgb, var(--color-primary) 28%, transparent);
100
+ }
108
101
  `;
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { useMemo, useState } from 'react';
4
+ import Image from 'next/image';
4
5
  import {
5
6
  usePreviewStepLocalizedContent,
6
7
  useFunnel,
@@ -8,6 +9,7 @@ import {
8
9
  import type { FunnelStepMeta } from '@funnelsgrove/runtime';
9
10
  import { emailCaptureContent } from '@/steps/content/email-capture.content';
10
11
  import { getStepContentLocale } from '@/runtime/step-content-context';
12
+ import { funnelManifest } from '@/config/funnel.manifest';
11
13
 
12
14
  export const stepEmailCaptureId = 'email-capture';
13
15
 
@@ -17,7 +19,7 @@ export const stepEmailCapture: FunnelStepMeta = {
17
19
  type: 'form_input',
18
20
  figmaNodeId: 'template-31-email-capture',
19
21
  title: 'Email Capture',
20
- description: 'Shared email capture shell used before paywall steps.',
22
+ description: 'Canonical unique email identity used before checkout and returning-subscriber lookup.',
21
23
  actionBar: {
22
24
  hidden: true,
23
25
  },
@@ -33,6 +35,7 @@ export function StepEmailCapture() {
33
35
  const [email, setEmail] = useState(user.email);
34
36
  const [error, setError] = useState<string | null>(null);
35
37
  const [submitting, setSubmitting] = useState(false);
38
+ const previewAsset = funnelManifest.assets.emailCapturePreview;
36
39
 
37
40
  const isValidEmail = useMemo(() => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email), [email]);
38
41
 
@@ -59,6 +62,14 @@ export function StepEmailCapture() {
59
62
  <>
60
63
  <div className="template-email-capture-step" data-node-id="template-31-email-capture">
61
64
  <section className="template-email-capture-copy">
65
+ <Image
66
+ src={previewAsset.src}
67
+ alt=""
68
+ width={previewAsset.width}
69
+ height={previewAsset.height}
70
+ className="template-email-capture-preview"
71
+ aria-hidden="true"
72
+ />
62
73
  <p className="template-email-capture-kicker">{content.kicker}</p>
63
74
  <h2 className="template-email-capture-title">{content.title}</h2>
64
75
  <p className="template-email-capture-text">{content.description}</p>
@@ -122,6 +133,12 @@ const stepEmailCaptureStyles = `
122
133
  gap: 12px;
123
134
  }
124
135
 
136
+ .template-email-capture-preview {
137
+ width: 120px;
138
+ height: 90px;
139
+ object-fit: contain;
140
+ }
141
+
125
142
  .template-email-capture-kicker {
126
143
  margin: 0;
127
144
  color: #556070;