@neowhale/storefront 0.2.53 → 0.2.54

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.
@@ -469,8 +469,52 @@ var WhaleStorefront = (function (exports) {
469
469
  }
470
470
 
471
471
  // src/react/components/sections/content-sections.tsx
472
- function HeroSection({ section, theme, tracking, onEvent }) {
473
- const { title, subtitle, background_image, cta_text, cta_url, review_line } = section.content;
472
+ var GOOGLE_G = '<svg width="18" height="18" viewBox="0 0 48 48"><path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"/><path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"/><path fill="#FBBC05" d="M10.53 28.59a14.5 14.5 0 010-9.18l-7.98-6.19a24.03 24.03 0 000 21.56l7.98-6.19z"/><path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"/></svg>';
473
+ function HeroSection({ section, theme, tracking, onEvent, data }) {
474
+ const c = section.content;
475
+ const [formOpen, setFormOpen] = useState(false);
476
+ const [firstName, setFirstName] = useState("");
477
+ const [email, setEmail] = useState("");
478
+ const [status, setStatus] = useState("idle");
479
+ const [errorMsg, setErrorMsg] = useState("");
480
+ const gatewayUrl = data?.gatewayUrl || "https://whale-gateway.fly.dev";
481
+ const storeId = data?.store?.id;
482
+ const slug = data?.landing_page?.slug;
483
+ async function handleSubmit(e) {
484
+ e.preventDefault();
485
+ if (!email || !storeId) return;
486
+ setStatus("loading");
487
+ setErrorMsg("");
488
+ const urlParams = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : null;
489
+ try {
490
+ const res = await fetch(`${gatewayUrl}/v1/stores/${storeId}/storefront/leads`, {
491
+ method: "POST",
492
+ headers: { "Content-Type": "application/json" },
493
+ body: JSON.stringify({
494
+ email,
495
+ first_name: firstName || void 0,
496
+ source: c.inline_form?.source || "landing_page",
497
+ landing_page_slug: slug || void 0,
498
+ tags: c.inline_form?.tags || void 0,
499
+ visitor_id: data?.analyticsContext?.visitorId || void 0,
500
+ session_id: data?.analyticsContext?.sessionId || void 0,
501
+ utm_source: urlParams?.get("utm_source") || void 0,
502
+ utm_medium: urlParams?.get("utm_medium") || void 0,
503
+ utm_campaign: urlParams?.get("utm_campaign") || void 0
504
+ })
505
+ });
506
+ if (!res.ok) {
507
+ const body = await res.json().catch(() => ({}));
508
+ throw new Error(body?.error?.message || "something went wrong.");
509
+ }
510
+ setStatus("success");
511
+ onEvent?.("lead", { email, first_name: firstName || void 0, source: c.inline_form?.source || "landing_page" });
512
+ } catch (err) {
513
+ setErrorMsg(err instanceof Error ? err.message : "something went wrong.");
514
+ setStatus("error");
515
+ }
516
+ }
517
+ const hasInlineForm = !!c.inline_form;
474
518
  return /* @__PURE__ */ jsx("div", { style: {
475
519
  position: "relative",
476
520
  minHeight: "60vh",
@@ -480,36 +524,56 @@ var WhaleStorefront = (function (exports) {
480
524
  alignItems: "center",
481
525
  textAlign: "center",
482
526
  padding: "3rem 1.5rem",
483
- backgroundImage: background_image ? `url(${background_image})` : void 0,
527
+ backgroundImage: c.background_image ? `url(${c.background_image})` : void 0,
484
528
  backgroundSize: "cover",
485
529
  backgroundPosition: "center"
486
530
  }, children: [
487
- background_image && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: "rgba(0,0,0,0.5)" } }),
488
- /* @__PURE__ */ jsx("div", { style: { position: "relative", zIndex: 1, maxWidth: 640 }, children: [
489
- title && /* @__PURE__ */ jsx("h1", { style: {
490
- fontSize: "clamp(2rem, 8vw, 3rem)",
531
+ c.background_image && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: "rgba(0,0,0,0.5)" } }),
532
+ /* @__PURE__ */ jsx("div", { style: { position: "relative", zIndex: 1, maxWidth: 640, width: "100%" }, children: [
533
+ c.title && /* @__PURE__ */ jsx("h1", { style: {
534
+ fontSize: "clamp(2rem, 7vw, 3.25rem)",
491
535
  fontWeight: 300,
492
536
  fontFamily: theme.fontDisplay || "inherit",
493
- margin: "0 0 1rem",
494
- lineHeight: 1.15,
495
- letterSpacing: "-0.02em",
537
+ margin: "0 0 1.25rem",
538
+ lineHeight: 1.08,
539
+ letterSpacing: "-0.03em",
496
540
  color: theme.fg
497
- }, children: /* @__PURE__ */ jsx(AnimatedText, { text: title }) }),
498
- subtitle && /* @__PURE__ */ jsx("p", { style: {
499
- fontSize: "0.85rem",
541
+ }, children: /* @__PURE__ */ jsx(AnimatedText, { text: c.title }) }),
542
+ c.subtitle && /* @__PURE__ */ jsx("p", { style: {
543
+ fontSize: "clamp(0.9rem, 2.5vw, 1.1rem)",
500
544
  color: theme.accent,
501
545
  margin: "0 0 2rem",
502
546
  lineHeight: 1.6,
503
547
  textTransform: "uppercase",
504
- letterSpacing: "0.15em"
505
- }, children: subtitle }),
506
- cta_text && cta_url && /* @__PURE__ */ jsx(
548
+ letterSpacing: "0.1em"
549
+ }, children: c.subtitle }),
550
+ hasInlineForm ? /* @__PURE__ */ jsx(
551
+ HeroInlineForm,
552
+ {
553
+ ctaText: c.cta_text || "claim it",
554
+ formOpen,
555
+ setFormOpen,
556
+ firstName,
557
+ setFirstName,
558
+ email,
559
+ setEmail,
560
+ status,
561
+ errorMsg,
562
+ onSubmit: handleSubmit,
563
+ successHeading: c.inline_form.success_heading || "you're in.",
564
+ successMessage: c.inline_form.success_message || "check your inbox.",
565
+ submitText: c.inline_form.button_text || "send my code",
566
+ theme,
567
+ onEvent,
568
+ tracking
569
+ }
570
+ ) : c.cta_text && c.cta_url ? /* @__PURE__ */ jsx(
507
571
  "a",
508
572
  {
509
- href: cta_url,
573
+ href: c.cta_url,
510
574
  onClick: () => {
511
- trackClick(tracking, cta_text, cta_url);
512
- onEvent?.("cta_click", { label: cta_text, url: cta_url });
575
+ trackClick(tracking, c.cta_text, c.cta_url);
576
+ onEvent?.("cta_click", { label: c.cta_text, url: c.cta_url });
513
577
  },
514
578
  style: {
515
579
  display: "inline-block",
@@ -522,13 +586,111 @@ var WhaleStorefront = (function (exports) {
522
586
  letterSpacing: "0.08em",
523
587
  textTransform: "uppercase"
524
588
  },
525
- children: cta_text
589
+ children: c.cta_text
526
590
  }
527
- ),
528
- review_line && review_line.count > 0 && /* @__PURE__ */ jsx(ReviewLine, { rating: review_line.rating, count: review_line.count, source: review_line.source, url: review_line.url, accent: theme.accent, fg: theme.fg })
591
+ ) : null,
592
+ c.review_line && c.review_line.count > 0 && /* @__PURE__ */ jsx(ReviewLine, { rating: c.review_line.rating, count: c.review_line.count, source: c.review_line.source, url: c.review_line.url, accent: theme.accent, fg: theme.fg })
529
593
  ] })
530
594
  ] });
531
595
  }
596
+ function HeroInlineForm({ ctaText, formOpen, setFormOpen, firstName, setFirstName, email, setEmail, status, errorMsg, onSubmit, successHeading, successMessage, submitText, theme, onEvent, tracking }) {
597
+ if (status === "success") {
598
+ return /* @__PURE__ */ jsx("div", { style: { padding: "1.25rem 2rem", background: `${theme.fg}08`, border: `1px solid ${theme.fg}15`, maxWidth: 420, margin: "0 auto" }, children: [
599
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "1.1rem", fontWeight: 300, color: theme.fg, margin: "0 0 0.25rem", fontFamily: theme.fontDisplay || "inherit" }, children: successHeading }),
600
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "0.8rem", color: `${theme.fg}80`, margin: 0 }, children: successMessage })
601
+ ] });
602
+ }
603
+ if (!formOpen) {
604
+ return /* @__PURE__ */ jsx(
605
+ "button",
606
+ {
607
+ onClick: () => {
608
+ setFormOpen(true);
609
+ trackClick(tracking, ctaText, "#form");
610
+ onEvent?.("cta_click", { label: ctaText });
611
+ },
612
+ style: {
613
+ display: "inline-block",
614
+ padding: "0.875rem 2rem",
615
+ background: theme.fg,
616
+ color: theme.bg,
617
+ border: "none",
618
+ cursor: "pointer",
619
+ fontSize: "0.85rem",
620
+ fontWeight: 500,
621
+ letterSpacing: "0.08em",
622
+ textTransform: "uppercase",
623
+ fontFamily: "inherit",
624
+ transition: "transform 0.2s"
625
+ },
626
+ children: ctaText
627
+ }
628
+ );
629
+ }
630
+ const inputStyle = {
631
+ flex: 1,
632
+ minWidth: 0,
633
+ padding: "0.875rem 1rem",
634
+ background: theme.surface,
635
+ border: `1px solid ${theme.fg}25`,
636
+ color: theme.fg,
637
+ fontSize: "0.9rem",
638
+ fontWeight: 300,
639
+ outline: "none",
640
+ fontFamily: "inherit",
641
+ boxSizing: "border-box"
642
+ };
643
+ return /* @__PURE__ */ jsx("form", { onSubmit, style: { maxWidth: 480, margin: "0 auto" }, children: [
644
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 0 }, children: [
645
+ /* @__PURE__ */ jsx(
646
+ "input",
647
+ {
648
+ type: "text",
649
+ placeholder: "first name",
650
+ value: firstName,
651
+ autoFocus: true,
652
+ onChange: (e) => setFirstName(e.target.value),
653
+ style: { ...inputStyle, borderRight: "none" }
654
+ }
655
+ ),
656
+ /* @__PURE__ */ jsx(
657
+ "input",
658
+ {
659
+ type: "email",
660
+ placeholder: "email",
661
+ value: email,
662
+ required: true,
663
+ onChange: (e) => setEmail(e.target.value),
664
+ style: { ...inputStyle, borderRight: "none" }
665
+ }
666
+ ),
667
+ /* @__PURE__ */ jsx(
668
+ "button",
669
+ {
670
+ type: "submit",
671
+ disabled: status === "loading",
672
+ style: {
673
+ padding: "0.875rem 1.25rem",
674
+ background: theme.fg,
675
+ color: theme.bg,
676
+ border: "none",
677
+ fontSize: "0.75rem",
678
+ fontWeight: 600,
679
+ letterSpacing: "0.08em",
680
+ textTransform: "uppercase",
681
+ cursor: status === "loading" ? "wait" : "pointer",
682
+ fontFamily: "inherit",
683
+ whiteSpace: "nowrap",
684
+ flexShrink: 0,
685
+ opacity: status === "loading" ? 0.7 : 1
686
+ },
687
+ children: status === "loading" ? "..." : submitText
688
+ }
689
+ )
690
+ ] }),
691
+ status === "error" && errorMsg && /* @__PURE__ */ jsx("p", { style: { fontSize: "0.75rem", color: "#e55", margin: "0.5rem 0 0", textAlign: "left" }, children: errorMsg })
692
+ ] });
693
+ }
532
694
  function TextSection({ section, theme }) {
533
695
  const { heading, body } = section.content;
534
696
  const align = section.config?.align || "left";
@@ -680,25 +842,21 @@ var WhaleStorefront = (function (exports) {
680
842
  }
681
843
  function ReviewLine({ rating, count, source, url, accent, fg }) {
682
844
  const label = `${rating.toFixed(1)} \xB7 ${count} ${source || "reviews"}`;
683
- const stars = /* @__PURE__ */ jsx("span", { style: { display: "inline-flex", gap: "1px" }, children: [1, 2, 3, 4, 5].map((s) => /* @__PURE__ */ jsx("svg", { width: 14, height: 14, viewBox: "0 0 20 20", fill: s <= Math.round(rating) ? accent : `${fg}20`, children: /* @__PURE__ */ jsx("path", { d: "M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" }) }, s)) });
684
- const text = /* @__PURE__ */ jsx("span", { style: { fontSize: "0.8rem", color: `${fg}80`, fontWeight: 500 }, children: label });
685
- const inner = /* @__PURE__ */ jsx("span", { style: { display: "inline-flex", alignItems: "center", gap: "0.5rem" }, children: [
686
- stars,
687
- text
845
+ const content = /* @__PURE__ */ jsx("div", { style: {
846
+ marginTop: "1.5rem",
847
+ display: "flex",
848
+ alignItems: "center",
849
+ justifyContent: "center",
850
+ gap: "0.625rem"
851
+ }, children: [
852
+ /* @__PURE__ */ jsx("span", { dangerouslySetInnerHTML: { __html: GOOGLE_G } }),
853
+ /* @__PURE__ */ jsx("span", { style: { display: "inline-flex", gap: "2px" }, children: [1, 2, 3, 4, 5].map((s) => /* @__PURE__ */ jsx("svg", { width: 16, height: 16, viewBox: "0 0 20 20", fill: s <= Math.round(rating) ? "#FBBC05" : `${fg}20`, children: /* @__PURE__ */ jsx("path", { d: "M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" }) }, s)) }),
854
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "0.9rem", color: `${fg}AA`, fontWeight: 500 }, children: label })
688
855
  ] });
689
856
  if (url) {
690
- return /* @__PURE__ */ jsx("div", { style: { marginTop: "1.25rem", textAlign: "center" }, children: /* @__PURE__ */ jsx(
691
- "a",
692
- {
693
- href: url,
694
- target: "_blank",
695
- rel: "noopener noreferrer",
696
- style: { textDecoration: "none", display: "inline-flex", alignItems: "center", gap: "0.5rem" },
697
- children: inner
698
- }
699
- ) });
857
+ return /* @__PURE__ */ jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", style: { textDecoration: "none", display: "block" }, children: content });
700
858
  }
701
- return /* @__PURE__ */ jsx("div", { style: { marginTop: "1.25rem", display: "flex", justifyContent: "center" }, children: inner });
859
+ return content;
702
860
  }
703
861
 
704
862
  // src/react/components/sections/interactive-sections.tsx
@@ -1561,7 +1719,7 @@ var WhaleStorefront = (function (exports) {
1561
1719
  const el = (() => {
1562
1720
  switch (section.type) {
1563
1721
  case "hero":
1564
- return /* @__PURE__ */ jsx(HeroSection, { section, theme, tracking, onEvent });
1722
+ return /* @__PURE__ */ jsx(HeroSection, { section, theme, tracking, onEvent, data });
1565
1723
  case "collage_hero":
1566
1724
  return /* @__PURE__ */ jsx(CollageHeroSection, { section, theme, tracking, onEvent });
1567
1725
  case "text":
@@ -2208,8 +2208,52 @@ function AnimatedText({ text }) {
2208
2208
  (part, i) => NUM_TEST.test(part) ? /* @__PURE__ */ jsxRuntime.jsx(AnimatedNumber, { raw: part }, i) : part
2209
2209
  ) });
2210
2210
  }
2211
- function HeroSection({ section, theme, tracking, onEvent }) {
2212
- const { title, subtitle, background_image, cta_text, cta_url, review_line } = section.content;
2211
+ var GOOGLE_G = '<svg width="18" height="18" viewBox="0 0 48 48"><path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"/><path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"/><path fill="#FBBC05" d="M10.53 28.59a14.5 14.5 0 010-9.18l-7.98-6.19a24.03 24.03 0 000 21.56l7.98-6.19z"/><path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"/></svg>';
2212
+ function HeroSection({ section, theme, tracking, onEvent, data }) {
2213
+ const c = section.content;
2214
+ const [formOpen, setFormOpen] = react.useState(false);
2215
+ const [firstName, setFirstName] = react.useState("");
2216
+ const [email, setEmail] = react.useState("");
2217
+ const [status, setStatus] = react.useState("idle");
2218
+ const [errorMsg, setErrorMsg] = react.useState("");
2219
+ const gatewayUrl = data?.gatewayUrl || "https://whale-gateway.fly.dev";
2220
+ const storeId = data?.store?.id;
2221
+ const slug = data?.landing_page?.slug;
2222
+ async function handleSubmit(e) {
2223
+ e.preventDefault();
2224
+ if (!email || !storeId) return;
2225
+ setStatus("loading");
2226
+ setErrorMsg("");
2227
+ const urlParams = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : null;
2228
+ try {
2229
+ const res = await fetch(`${gatewayUrl}/v1/stores/${storeId}/storefront/leads`, {
2230
+ method: "POST",
2231
+ headers: { "Content-Type": "application/json" },
2232
+ body: JSON.stringify({
2233
+ email,
2234
+ first_name: firstName || void 0,
2235
+ source: c.inline_form?.source || "landing_page",
2236
+ landing_page_slug: slug || void 0,
2237
+ tags: c.inline_form?.tags || void 0,
2238
+ visitor_id: data?.analyticsContext?.visitorId || void 0,
2239
+ session_id: data?.analyticsContext?.sessionId || void 0,
2240
+ utm_source: urlParams?.get("utm_source") || void 0,
2241
+ utm_medium: urlParams?.get("utm_medium") || void 0,
2242
+ utm_campaign: urlParams?.get("utm_campaign") || void 0
2243
+ })
2244
+ });
2245
+ if (!res.ok) {
2246
+ const body = await res.json().catch(() => ({}));
2247
+ throw new Error(body?.error?.message || "something went wrong.");
2248
+ }
2249
+ setStatus("success");
2250
+ onEvent?.("lead", { email, first_name: firstName || void 0, source: c.inline_form?.source || "landing_page" });
2251
+ } catch (err) {
2252
+ setErrorMsg(err instanceof Error ? err.message : "something went wrong.");
2253
+ setStatus("error");
2254
+ }
2255
+ }
2256
+ const hasInlineForm = !!c.inline_form;
2213
2257
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
2214
2258
  position: "relative",
2215
2259
  minHeight: "60vh",
@@ -2219,36 +2263,56 @@ function HeroSection({ section, theme, tracking, onEvent }) {
2219
2263
  alignItems: "center",
2220
2264
  textAlign: "center",
2221
2265
  padding: "3rem 1.5rem",
2222
- backgroundImage: background_image ? `url(${background_image})` : void 0,
2266
+ backgroundImage: c.background_image ? `url(${c.background_image})` : void 0,
2223
2267
  backgroundSize: "cover",
2224
2268
  backgroundPosition: "center"
2225
2269
  }, children: [
2226
- background_image && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", inset: 0, background: "rgba(0,0,0,0.5)" } }),
2227
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", zIndex: 1, maxWidth: 640 }, children: [
2228
- title && /* @__PURE__ */ jsxRuntime.jsx("h1", { style: {
2229
- fontSize: "clamp(2rem, 8vw, 3rem)",
2270
+ c.background_image && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", inset: 0, background: "rgba(0,0,0,0.5)" } }),
2271
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", zIndex: 1, maxWidth: 640, width: "100%" }, children: [
2272
+ c.title && /* @__PURE__ */ jsxRuntime.jsx("h1", { style: {
2273
+ fontSize: "clamp(2rem, 7vw, 3.25rem)",
2230
2274
  fontWeight: 300,
2231
2275
  fontFamily: theme.fontDisplay || "inherit",
2232
- margin: "0 0 1rem",
2233
- lineHeight: 1.15,
2234
- letterSpacing: "-0.02em",
2276
+ margin: "0 0 1.25rem",
2277
+ lineHeight: 1.08,
2278
+ letterSpacing: "-0.03em",
2235
2279
  color: theme.fg
2236
- }, children: /* @__PURE__ */ jsxRuntime.jsx(AnimatedText, { text: title }) }),
2237
- subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { style: {
2238
- fontSize: "0.85rem",
2280
+ }, children: /* @__PURE__ */ jsxRuntime.jsx(AnimatedText, { text: c.title }) }),
2281
+ c.subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { style: {
2282
+ fontSize: "clamp(0.9rem, 2.5vw, 1.1rem)",
2239
2283
  color: theme.accent,
2240
2284
  margin: "0 0 2rem",
2241
2285
  lineHeight: 1.6,
2242
2286
  textTransform: "uppercase",
2243
- letterSpacing: "0.15em"
2244
- }, children: subtitle }),
2245
- cta_text && cta_url && /* @__PURE__ */ jsxRuntime.jsx(
2287
+ letterSpacing: "0.1em"
2288
+ }, children: c.subtitle }),
2289
+ hasInlineForm ? /* @__PURE__ */ jsxRuntime.jsx(
2290
+ HeroInlineForm,
2291
+ {
2292
+ ctaText: c.cta_text || "claim it",
2293
+ formOpen,
2294
+ setFormOpen,
2295
+ firstName,
2296
+ setFirstName,
2297
+ email,
2298
+ setEmail,
2299
+ status,
2300
+ errorMsg,
2301
+ onSubmit: handleSubmit,
2302
+ successHeading: c.inline_form.success_heading || "you're in.",
2303
+ successMessage: c.inline_form.success_message || "check your inbox.",
2304
+ submitText: c.inline_form.button_text || "send my code",
2305
+ theme,
2306
+ onEvent,
2307
+ tracking
2308
+ }
2309
+ ) : c.cta_text && c.cta_url ? /* @__PURE__ */ jsxRuntime.jsx(
2246
2310
  "a",
2247
2311
  {
2248
- href: cta_url,
2312
+ href: c.cta_url,
2249
2313
  onClick: () => {
2250
- trackClick(tracking, cta_text, cta_url);
2251
- onEvent?.("cta_click", { label: cta_text, url: cta_url });
2314
+ trackClick(tracking, c.cta_text, c.cta_url);
2315
+ onEvent?.("cta_click", { label: c.cta_text, url: c.cta_url });
2252
2316
  },
2253
2317
  style: {
2254
2318
  display: "inline-block",
@@ -2261,13 +2325,111 @@ function HeroSection({ section, theme, tracking, onEvent }) {
2261
2325
  letterSpacing: "0.08em",
2262
2326
  textTransform: "uppercase"
2263
2327
  },
2264
- children: cta_text
2328
+ children: c.cta_text
2265
2329
  }
2266
- ),
2267
- review_line && review_line.count > 0 && /* @__PURE__ */ jsxRuntime.jsx(ReviewLine, { rating: review_line.rating, count: review_line.count, source: review_line.source, url: review_line.url, accent: theme.accent, fg: theme.fg })
2330
+ ) : null,
2331
+ c.review_line && c.review_line.count > 0 && /* @__PURE__ */ jsxRuntime.jsx(ReviewLine, { rating: c.review_line.rating, count: c.review_line.count, source: c.review_line.source, url: c.review_line.url, accent: theme.accent, fg: theme.fg })
2268
2332
  ] })
2269
2333
  ] });
2270
2334
  }
2335
+ function HeroInlineForm({ ctaText, formOpen, setFormOpen, firstName, setFirstName, email, setEmail, status, errorMsg, onSubmit, successHeading, successMessage, submitText, theme, onEvent, tracking }) {
2336
+ if (status === "success") {
2337
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "1.25rem 2rem", background: `${theme.fg}08`, border: `1px solid ${theme.fg}15`, maxWidth: 420, margin: "0 auto" }, children: [
2338
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "1.1rem", fontWeight: 300, color: theme.fg, margin: "0 0 0.25rem", fontFamily: theme.fontDisplay || "inherit" }, children: successHeading }),
2339
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.8rem", color: `${theme.fg}80`, margin: 0 }, children: successMessage })
2340
+ ] });
2341
+ }
2342
+ if (!formOpen) {
2343
+ return /* @__PURE__ */ jsxRuntime.jsx(
2344
+ "button",
2345
+ {
2346
+ onClick: () => {
2347
+ setFormOpen(true);
2348
+ trackClick(tracking, ctaText, "#form");
2349
+ onEvent?.("cta_click", { label: ctaText });
2350
+ },
2351
+ style: {
2352
+ display: "inline-block",
2353
+ padding: "0.875rem 2rem",
2354
+ background: theme.fg,
2355
+ color: theme.bg,
2356
+ border: "none",
2357
+ cursor: "pointer",
2358
+ fontSize: "0.85rem",
2359
+ fontWeight: 500,
2360
+ letterSpacing: "0.08em",
2361
+ textTransform: "uppercase",
2362
+ fontFamily: "inherit",
2363
+ transition: "transform 0.2s"
2364
+ },
2365
+ children: ctaText
2366
+ }
2367
+ );
2368
+ }
2369
+ const inputStyle = {
2370
+ flex: 1,
2371
+ minWidth: 0,
2372
+ padding: "0.875rem 1rem",
2373
+ background: theme.surface,
2374
+ border: `1px solid ${theme.fg}25`,
2375
+ color: theme.fg,
2376
+ fontSize: "0.9rem",
2377
+ fontWeight: 300,
2378
+ outline: "none",
2379
+ fontFamily: "inherit",
2380
+ boxSizing: "border-box"
2381
+ };
2382
+ return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit, style: { maxWidth: 480, margin: "0 auto" }, children: [
2383
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 0 }, children: [
2384
+ /* @__PURE__ */ jsxRuntime.jsx(
2385
+ "input",
2386
+ {
2387
+ type: "text",
2388
+ placeholder: "first name",
2389
+ value: firstName,
2390
+ autoFocus: true,
2391
+ onChange: (e) => setFirstName(e.target.value),
2392
+ style: { ...inputStyle, borderRight: "none" }
2393
+ }
2394
+ ),
2395
+ /* @__PURE__ */ jsxRuntime.jsx(
2396
+ "input",
2397
+ {
2398
+ type: "email",
2399
+ placeholder: "email",
2400
+ value: email,
2401
+ required: true,
2402
+ onChange: (e) => setEmail(e.target.value),
2403
+ style: { ...inputStyle, borderRight: "none" }
2404
+ }
2405
+ ),
2406
+ /* @__PURE__ */ jsxRuntime.jsx(
2407
+ "button",
2408
+ {
2409
+ type: "submit",
2410
+ disabled: status === "loading",
2411
+ style: {
2412
+ padding: "0.875rem 1.25rem",
2413
+ background: theme.fg,
2414
+ color: theme.bg,
2415
+ border: "none",
2416
+ fontSize: "0.75rem",
2417
+ fontWeight: 600,
2418
+ letterSpacing: "0.08em",
2419
+ textTransform: "uppercase",
2420
+ cursor: status === "loading" ? "wait" : "pointer",
2421
+ fontFamily: "inherit",
2422
+ whiteSpace: "nowrap",
2423
+ flexShrink: 0,
2424
+ opacity: status === "loading" ? 0.7 : 1
2425
+ },
2426
+ children: status === "loading" ? "..." : submitText
2427
+ }
2428
+ )
2429
+ ] }),
2430
+ status === "error" && errorMsg && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.75rem", color: "#e55", margin: "0.5rem 0 0", textAlign: "left" }, children: errorMsg })
2431
+ ] });
2432
+ }
2271
2433
  function TextSection({ section, theme }) {
2272
2434
  const { heading, body } = section.content;
2273
2435
  const align = section.config?.align || "left";
@@ -2419,25 +2581,21 @@ function toEmbedUrl(url) {
2419
2581
  }
2420
2582
  function ReviewLine({ rating, count, source, url, accent, fg }) {
2421
2583
  const label = `${rating.toFixed(1)} \xB7 ${count} ${source || "reviews"}`;
2422
- const stars = /* @__PURE__ */ jsxRuntime.jsx("span", { style: { display: "inline-flex", gap: "1px" }, children: [1, 2, 3, 4, 5].map((s) => /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 14, height: 14, viewBox: "0 0 20 20", fill: s <= Math.round(rating) ? accent : `${fg}20`, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" }) }, s)) });
2423
- const text = /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.8rem", color: `${fg}80`, fontWeight: 500 }, children: label });
2424
- const inner = /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: "0.5rem" }, children: [
2425
- stars,
2426
- text
2584
+ const content = /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
2585
+ marginTop: "1.5rem",
2586
+ display: "flex",
2587
+ alignItems: "center",
2588
+ justifyContent: "center",
2589
+ gap: "0.625rem"
2590
+ }, children: [
2591
+ /* @__PURE__ */ jsxRuntime.jsx("span", { dangerouslySetInnerHTML: { __html: GOOGLE_G } }),
2592
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { display: "inline-flex", gap: "2px" }, children: [1, 2, 3, 4, 5].map((s) => /* @__PURE__ */ jsxRuntime.jsx("svg", { width: 16, height: 16, viewBox: "0 0 20 20", fill: s <= Math.round(rating) ? "#FBBC05" : `${fg}20`, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" }) }, s)) }),
2593
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.9rem", color: `${fg}AA`, fontWeight: 500 }, children: label })
2427
2594
  ] });
2428
2595
  if (url) {
2429
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: "1.25rem", textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(
2430
- "a",
2431
- {
2432
- href: url,
2433
- target: "_blank",
2434
- rel: "noopener noreferrer",
2435
- style: { textDecoration: "none", display: "inline-flex", alignItems: "center", gap: "0.5rem" },
2436
- children: inner
2437
- }
2438
- ) });
2596
+ return /* @__PURE__ */ jsxRuntime.jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", style: { textDecoration: "none", display: "block" }, children: content });
2439
2597
  }
2440
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: "1.25rem", display: "flex", justifyContent: "center" }, children: inner });
2598
+ return content;
2441
2599
  }
2442
2600
  function CTASection({ section, theme, tracking, onEvent }) {
2443
2601
  const { title, subtitle, buttons } = section.content;
@@ -3292,7 +3450,7 @@ function SectionRenderer({
3292
3450
  const el = (() => {
3293
3451
  switch (section.type) {
3294
3452
  case "hero":
3295
- return /* @__PURE__ */ jsxRuntime.jsx(HeroSection, { section, theme, tracking, onEvent });
3453
+ return /* @__PURE__ */ jsxRuntime.jsx(HeroSection, { section, theme, tracking, onEvent, data });
3296
3454
  case "collage_hero":
3297
3455
  return /* @__PURE__ */ jsxRuntime.jsx(CollageHeroSection, { section, theme, tracking, onEvent });
3298
3456
  case "text":