@neowhale/storefront 0.2.53 → 0.2.55

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.
@@ -2206,8 +2206,57 @@ function AnimatedText({ text }) {
2206
2206
  (part, i) => NUM_TEST.test(part) ? /* @__PURE__ */ jsx(AnimatedNumber, { raw: part }, i) : part
2207
2207
  ) });
2208
2208
  }
2209
- function HeroSection({ section, theme, tracking, onEvent }) {
2210
- const { title, subtitle, background_image, cta_text, cta_url, review_line } = section.content;
2209
+ 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>';
2210
+ function HeroSection({ section, theme, tracking, onEvent, data }) {
2211
+ const c = section.content;
2212
+ const [formOpen, setFormOpen] = useState(false);
2213
+ const [firstName, setFirstName] = useState("");
2214
+ const [email, setEmail] = useState("");
2215
+ const [status, setStatus] = useState("idle");
2216
+ const [errorMsg, setErrorMsg] = useState("");
2217
+ const gatewayUrl = data?.gatewayUrl || "https://whale-gateway.fly.dev";
2218
+ const storeId = data?.store?.id;
2219
+ const slug = data?.landing_page?.slug;
2220
+ async function handleSubmit(e) {
2221
+ e.preventDefault();
2222
+ if (!email || !storeId) return;
2223
+ setStatus("loading");
2224
+ setErrorMsg("");
2225
+ const urlParams = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : null;
2226
+ try {
2227
+ const res = await fetch(`${gatewayUrl}/v1/stores/${storeId}/storefront/leads`, {
2228
+ method: "POST",
2229
+ headers: { "Content-Type": "application/json" },
2230
+ body: JSON.stringify({
2231
+ email,
2232
+ first_name: firstName || void 0,
2233
+ source: c.inline_form?.source || "landing_page",
2234
+ landing_page_slug: slug || void 0,
2235
+ tags: c.inline_form?.tags || void 0,
2236
+ segment_id: c.inline_form?.segment_id || void 0,
2237
+ campaign_id: c.inline_form?.campaign_id || void 0,
2238
+ preferred_location_id: c.inline_form?.preferred_location_id || void 0,
2239
+ template_slug: c.inline_form?.template_slug || void 0,
2240
+ acquisition_campaign: c.inline_form?.acquisition_campaign || void 0,
2241
+ visitor_id: data?.analyticsContext?.visitorId || void 0,
2242
+ session_id: data?.analyticsContext?.sessionId || void 0,
2243
+ utm_source: urlParams?.get("utm_source") || void 0,
2244
+ utm_medium: urlParams?.get("utm_medium") || void 0,
2245
+ utm_campaign: urlParams?.get("utm_campaign") || void 0
2246
+ })
2247
+ });
2248
+ if (!res.ok) {
2249
+ const body = await res.json().catch(() => ({}));
2250
+ throw new Error(body?.error?.message || "something went wrong.");
2251
+ }
2252
+ setStatus("success");
2253
+ onEvent?.("lead", { email, first_name: firstName || void 0, source: c.inline_form?.source || "landing_page" });
2254
+ } catch (err) {
2255
+ setErrorMsg(err instanceof Error ? err.message : "something went wrong.");
2256
+ setStatus("error");
2257
+ }
2258
+ }
2259
+ const hasInlineForm = !!c.inline_form;
2211
2260
  return /* @__PURE__ */ jsxs("div", { style: {
2212
2261
  position: "relative",
2213
2262
  minHeight: "60vh",
@@ -2217,36 +2266,56 @@ function HeroSection({ section, theme, tracking, onEvent }) {
2217
2266
  alignItems: "center",
2218
2267
  textAlign: "center",
2219
2268
  padding: "3rem 1.5rem",
2220
- backgroundImage: background_image ? `url(${background_image})` : void 0,
2269
+ backgroundImage: c.background_image ? `url(${c.background_image})` : void 0,
2221
2270
  backgroundSize: "cover",
2222
2271
  backgroundPosition: "center"
2223
2272
  }, children: [
2224
- background_image && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: "rgba(0,0,0,0.5)" } }),
2225
- /* @__PURE__ */ jsxs("div", { style: { position: "relative", zIndex: 1, maxWidth: 640 }, children: [
2226
- title && /* @__PURE__ */ jsx("h1", { style: {
2227
- fontSize: "clamp(2rem, 8vw, 3rem)",
2273
+ c.background_image && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: "rgba(0,0,0,0.5)" } }),
2274
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", zIndex: 1, maxWidth: 640, width: "100%" }, children: [
2275
+ c.title && /* @__PURE__ */ jsx("h1", { style: {
2276
+ fontSize: "clamp(2rem, 7vw, 3.25rem)",
2228
2277
  fontWeight: 300,
2229
2278
  fontFamily: theme.fontDisplay || "inherit",
2230
- margin: "0 0 1rem",
2231
- lineHeight: 1.15,
2232
- letterSpacing: "-0.02em",
2279
+ margin: "0 0 1.25rem",
2280
+ lineHeight: 1.08,
2281
+ letterSpacing: "-0.03em",
2233
2282
  color: theme.fg
2234
- }, children: /* @__PURE__ */ jsx(AnimatedText, { text: title }) }),
2235
- subtitle && /* @__PURE__ */ jsx("p", { style: {
2236
- fontSize: "0.85rem",
2283
+ }, children: /* @__PURE__ */ jsx(AnimatedText, { text: c.title }) }),
2284
+ c.subtitle && /* @__PURE__ */ jsx("p", { style: {
2285
+ fontSize: "clamp(0.9rem, 2.5vw, 1.1rem)",
2237
2286
  color: theme.accent,
2238
2287
  margin: "0 0 2rem",
2239
2288
  lineHeight: 1.6,
2240
2289
  textTransform: "uppercase",
2241
- letterSpacing: "0.15em"
2242
- }, children: subtitle }),
2243
- cta_text && cta_url && /* @__PURE__ */ jsx(
2290
+ letterSpacing: "0.1em"
2291
+ }, children: c.subtitle }),
2292
+ hasInlineForm ? /* @__PURE__ */ jsx(
2293
+ HeroInlineForm,
2294
+ {
2295
+ ctaText: c.cta_text || "claim it",
2296
+ formOpen,
2297
+ setFormOpen,
2298
+ firstName,
2299
+ setFirstName,
2300
+ email,
2301
+ setEmail,
2302
+ status,
2303
+ errorMsg,
2304
+ onSubmit: handleSubmit,
2305
+ successHeading: c.inline_form.success_heading || "you're in.",
2306
+ successMessage: c.inline_form.success_message || "check your inbox.",
2307
+ submitText: c.inline_form.button_text || "send my code",
2308
+ theme,
2309
+ onEvent,
2310
+ tracking
2311
+ }
2312
+ ) : c.cta_text && c.cta_url ? /* @__PURE__ */ jsx(
2244
2313
  "a",
2245
2314
  {
2246
- href: cta_url,
2315
+ href: c.cta_url,
2247
2316
  onClick: () => {
2248
- trackClick(tracking, cta_text, cta_url);
2249
- onEvent?.("cta_click", { label: cta_text, url: cta_url });
2317
+ trackClick(tracking, c.cta_text, c.cta_url);
2318
+ onEvent?.("cta_click", { label: c.cta_text, url: c.cta_url });
2250
2319
  },
2251
2320
  style: {
2252
2321
  display: "inline-block",
@@ -2259,13 +2328,114 @@ function HeroSection({ section, theme, tracking, onEvent }) {
2259
2328
  letterSpacing: "0.08em",
2260
2329
  textTransform: "uppercase"
2261
2330
  },
2262
- children: cta_text
2331
+ children: c.cta_text
2263
2332
  }
2264
- ),
2265
- 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 })
2333
+ ) : null,
2334
+ 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 })
2266
2335
  ] })
2267
2336
  ] });
2268
2337
  }
2338
+ function HeroInlineForm({ ctaText, formOpen, setFormOpen, firstName, setFirstName, email, setEmail, status, errorMsg, onSubmit, successHeading, successMessage, submitText, theme, onEvent, tracking }) {
2339
+ const formMaxW = "min(480px, 90vw)";
2340
+ if (status === "success") {
2341
+ return /* @__PURE__ */ jsxs("div", { style: { maxWidth: formMaxW, margin: "0 auto", padding: "1.5rem 2rem", background: `${theme.fg}06`, border: `1px solid ${theme.fg}10` }, children: [
2342
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "clamp(1rem, 3vw, 1.25rem)", fontWeight: 300, color: theme.fg, margin: "0 0 0.375rem", fontFamily: theme.fontDisplay || "inherit" }, children: successHeading }),
2343
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "0.85rem", color: `${theme.fg}70`, margin: 0, lineHeight: 1.5 }, children: successMessage })
2344
+ ] });
2345
+ }
2346
+ if (!formOpen) {
2347
+ return /* @__PURE__ */ jsx(
2348
+ "button",
2349
+ {
2350
+ onClick: () => {
2351
+ setFormOpen(true);
2352
+ trackClick(tracking, ctaText, "#form");
2353
+ onEvent?.("cta_click", { label: ctaText });
2354
+ },
2355
+ style: {
2356
+ display: "inline-block",
2357
+ padding: "clamp(0.875rem, 2.5vw, 1.125rem) clamp(2rem, 5vw, 3rem)",
2358
+ background: theme.fg,
2359
+ color: theme.bg,
2360
+ border: "none",
2361
+ cursor: "pointer",
2362
+ fontSize: "clamp(0.85rem, 2vw, 1rem)",
2363
+ fontWeight: 500,
2364
+ letterSpacing: "0.06em",
2365
+ textTransform: "uppercase",
2366
+ fontFamily: "inherit"
2367
+ },
2368
+ children: ctaText
2369
+ }
2370
+ );
2371
+ }
2372
+ const inputBase = {
2373
+ padding: "clamp(0.75rem, 2vw, 0.875rem) clamp(0.75rem, 2vw, 1rem)",
2374
+ background: theme.surface,
2375
+ border: `1px solid ${theme.fg}20`,
2376
+ color: theme.fg,
2377
+ fontSize: "clamp(0.8rem, 2vw, 0.9rem)",
2378
+ fontWeight: 300,
2379
+ outline: "none",
2380
+ fontFamily: "inherit",
2381
+ boxSizing: "border-box",
2382
+ width: "100%"
2383
+ };
2384
+ return /* @__PURE__ */ jsxs("form", { onSubmit, style: { maxWidth: formMaxW, margin: "0 auto", width: "100%" }, children: [
2385
+ /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: `
2386
+ .hero-form-row{display:flex;gap:0}
2387
+ @media(max-width:480px){.hero-form-row{flex-direction:column;gap:0.5rem}}
2388
+ ` } }),
2389
+ /* @__PURE__ */ jsxs("div", { className: "hero-form-row", children: [
2390
+ /* @__PURE__ */ jsx(
2391
+ "input",
2392
+ {
2393
+ type: "text",
2394
+ placeholder: "first name",
2395
+ value: firstName,
2396
+ autoFocus: true,
2397
+ onChange: (e) => setFirstName(e.target.value),
2398
+ style: { ...inputBase, flex: 1, minWidth: 0, borderRight: "none" }
2399
+ }
2400
+ ),
2401
+ /* @__PURE__ */ jsx(
2402
+ "input",
2403
+ {
2404
+ type: "email",
2405
+ placeholder: "email",
2406
+ value: email,
2407
+ required: true,
2408
+ onChange: (e) => setEmail(e.target.value),
2409
+ style: { ...inputBase, flex: 1.2, minWidth: 0 }
2410
+ }
2411
+ )
2412
+ ] }),
2413
+ /* @__PURE__ */ jsx(
2414
+ "button",
2415
+ {
2416
+ type: "submit",
2417
+ disabled: status === "loading",
2418
+ style: {
2419
+ width: "100%",
2420
+ padding: "clamp(0.75rem, 2vw, 0.875rem)",
2421
+ background: theme.fg,
2422
+ color: theme.bg,
2423
+ border: "none",
2424
+ fontSize: "clamp(0.8rem, 2vw, 0.85rem)",
2425
+ fontWeight: 600,
2426
+ letterSpacing: "0.08em",
2427
+ textTransform: "uppercase",
2428
+ cursor: status === "loading" ? "wait" : "pointer",
2429
+ fontFamily: "inherit",
2430
+ marginTop: "0.5rem",
2431
+ opacity: status === "loading" ? 0.7 : 1
2432
+ },
2433
+ children: status === "loading" ? "..." : submitText
2434
+ }
2435
+ ),
2436
+ status === "error" && errorMsg && /* @__PURE__ */ jsx("p", { style: { fontSize: "0.75rem", color: "#e55", margin: "0.5rem 0 0", textAlign: "left" }, children: errorMsg })
2437
+ ] });
2438
+ }
2269
2439
  function TextSection({ section, theme }) {
2270
2440
  const { heading, body } = section.content;
2271
2441
  const align = section.config?.align || "left";
@@ -2367,29 +2537,100 @@ function CollageHeroSection({ section, theme, tracking, onEvent }) {
2367
2537
  ] })
2368
2538
  ] });
2369
2539
  }
2370
- function GallerySection({ section, theme }) {
2371
- const { images } = section.content;
2540
+ function GallerySection({ section, theme, onEvent }) {
2541
+ const c = section.content;
2542
+ const images = c.images || [];
2372
2543
  const columns = section.config?.columns || 3;
2373
2544
  const layout = section.config?.layout || "grid";
2545
+ const loc = c.location_card;
2374
2546
  if (!images || images.length === 0) return null;
2375
2547
  if (layout === "collage") {
2376
- return /* @__PURE__ */ jsx("div", { style: { padding: "0.375rem", maxWidth: 900, margin: "0 auto" }, children: /* @__PURE__ */ jsx("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.375rem" }, children: images.map((img, i) => /* @__PURE__ */ jsx("div", { style: {
2377
- gridColumn: i === 0 ? "1 / -1" : void 0,
2378
- aspectRatio: i === 0 ? "16/9" : i % 3 === 0 ? "3/4" : "1",
2379
- overflow: "hidden",
2380
- background: theme.surface
2381
- }, children: /* @__PURE__ */ jsx(
2382
- "img",
2383
- {
2384
- src: img.url,
2385
- alt: img.alt || "",
2386
- loading: i < 2 ? "eager" : "lazy",
2387
- style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
2388
- }
2389
- ) }, i)) }) });
2548
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "0.375rem", maxWidth: 900, margin: "0 auto" }, children: [
2549
+ loc && /* @__PURE__ */ jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.375rem", marginBottom: "0.375rem" }, children: [
2550
+ /* @__PURE__ */ jsx(GalleryLocationCard, { loc, theme, onEvent }),
2551
+ /* @__PURE__ */ jsx("div", { style: { aspectRatio: "4/5", overflow: "hidden", background: theme.surface }, children: /* @__PURE__ */ jsx(
2552
+ "img",
2553
+ {
2554
+ src: images[0].url,
2555
+ alt: images[0].alt || "",
2556
+ loading: "eager",
2557
+ style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
2558
+ }
2559
+ ) })
2560
+ ] }),
2561
+ /* @__PURE__ */ jsx("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.375rem" }, children: images.slice(loc ? 1 : 0).map((img, i) => /* @__PURE__ */ jsx("div", { style: {
2562
+ gridColumn: !loc && i === 0 ? "1 / -1" : void 0,
2563
+ aspectRatio: !loc && i === 0 ? "16/9" : i % 3 === 0 ? "3/4" : "1",
2564
+ overflow: "hidden",
2565
+ background: theme.surface
2566
+ }, children: /* @__PURE__ */ jsx(
2567
+ "img",
2568
+ {
2569
+ src: img.url,
2570
+ alt: img.alt || "",
2571
+ loading: i < 2 ? "eager" : "lazy",
2572
+ style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
2573
+ }
2574
+ ) }, i)) })
2575
+ ] });
2390
2576
  }
2391
2577
  return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 800, margin: "0 auto" }, children: /* @__PURE__ */ jsx("div", { style: { display: "grid", gridTemplateColumns: `repeat(${columns}, 1fr)`, gap: "0.5rem" }, children: images.map((img, i) => /* @__PURE__ */ jsx("div", { style: { aspectRatio: "1", overflow: "hidden", background: theme.surface }, children: /* @__PURE__ */ jsx("img", { src: img.url, alt: img.alt || "", style: { width: "100%", height: "100%", objectFit: "cover", display: "block" } }) }, i)) }) });
2392
2578
  }
2579
+ function GalleryLocationCard({ loc, theme, onEvent }) {
2580
+ const dirUrl = loc.directions_url || `https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(loc.address + ", " + loc.city + ", " + loc.state)}`;
2581
+ const brandFont = loc.brand_font || "inherit";
2582
+ return /* @__PURE__ */ jsxs("div", { style: { background: "#0C0C0C", border: "1px solid rgba(255,255,255,0.06)", overflow: "hidden", display: "flex", flexDirection: "column" }, children: [
2583
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", flex: 1, minHeight: 0, overflow: "hidden" }, children: [
2584
+ /* @__PURE__ */ jsx("img", { src: loc.image, alt: loc.name, style: { width: "100%", height: "100%", objectFit: "cover", display: "block" } }),
2585
+ /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: "linear-gradient(to top, rgba(0,0,0,0.6) 0%, transparent 50%)" } }),
2586
+ /* @__PURE__ */ jsxs("div", { style: { position: "absolute", bottom: 0, left: 0, padding: "clamp(0.75rem, 3vw, 1.25rem)" }, children: [
2587
+ /* @__PURE__ */ jsx("p", { className: "loc-card-name", style: { fontFamily: brandFont, fontSize: "clamp(1.25rem, 5vw, 1.75rem)", color: "#fff", margin: 0, lineHeight: 1 }, children: loc.name }),
2588
+ /* @__PURE__ */ jsxs("p", { style: { fontSize: "0.6rem", letterSpacing: "0.2em", color: "rgba(255,255,255,0.6)", margin: "0.25rem 0 0", fontWeight: 600, textTransform: "uppercase" }, children: [
2589
+ loc.city,
2590
+ ", ",
2591
+ loc.state
2592
+ ] })
2593
+ ] })
2594
+ ] }),
2595
+ /* @__PURE__ */ jsxs("div", { style: { padding: "clamp(0.625rem, 2vw, 1rem)", display: "flex", flexDirection: "column", gap: "0.4rem" }, children: [
2596
+ loc.tagline && /* @__PURE__ */ jsx("p", { style: { fontSize: "0.75rem", color: "rgba(255,255,255,0.5)", fontWeight: 500, fontStyle: "italic", margin: 0 }, children: loc.tagline }),
2597
+ loc.rating != null && loc.review_count != null && loc.review_count > 0 && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.375rem" }, children: [
2598
+ /* @__PURE__ */ jsx("span", { style: { display: "inline-flex", gap: "2px" }, children: [1, 2, 3, 4, 5].map((s) => /* @__PURE__ */ jsx("svg", { width: 12, height: 12, viewBox: "0 0 20 20", fill: s <= Math.round(loc.rating) ? theme.accent : "rgba(255,255,255,0.1)", 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)) }),
2599
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "0.7rem", color: "rgba(255,255,255,0.5)", fontWeight: 500 }, children: `${loc.rating.toFixed(1)} \xB7 ${loc.review_count} reviews` })
2600
+ ] }),
2601
+ loc.address && /* @__PURE__ */ jsxs("a", { href: dirUrl, target: "_blank", rel: "noopener noreferrer", style: { fontSize: "0.7rem", color: "rgba(255,255,255,0.35)", fontWeight: 500, textDecoration: "none" }, children: [
2602
+ loc.address,
2603
+ ", ",
2604
+ loc.city,
2605
+ ", ",
2606
+ loc.state
2607
+ ] }),
2608
+ loc.phone && /* @__PURE__ */ jsx("a", { href: loc.phone_href || `tel:${loc.phone}`, style: { fontSize: "0.7rem", color: "rgba(255,255,255,0.35)", fontWeight: 500, textDecoration: "none" }, children: loc.phone }),
2609
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.375rem", marginTop: "auto", paddingTop: "0.125rem" }, children: [
2610
+ /* @__PURE__ */ jsx(
2611
+ "a",
2612
+ {
2613
+ href: dirUrl,
2614
+ target: "_blank",
2615
+ rel: "noopener noreferrer",
2616
+ onClick: () => onEvent?.("cta_click", { label: "directions", location: loc.name }),
2617
+ style: { flex: 1, display: "flex", alignItems: "center", justifyContent: "center", gap: "0.25rem", padding: "0.5rem", background: "#fff", color: "#000", fontSize: "0.65rem", fontWeight: 700, letterSpacing: "0.1em", textTransform: "uppercase", textDecoration: "none" },
2618
+ children: "directions"
2619
+ }
2620
+ ),
2621
+ loc.shop_url && /* @__PURE__ */ jsx(
2622
+ "a",
2623
+ {
2624
+ href: loc.shop_url,
2625
+ onClick: () => onEvent?.("cta_click", { label: "shop", location: loc.name }),
2626
+ style: { flex: 1, display: "flex", alignItems: "center", justifyContent: "center", gap: "0.25rem", padding: "0.5rem", border: "1px solid rgba(255,255,255,0.15)", color: "rgba(255,255,255,0.8)", fontSize: "0.65rem", fontWeight: 700, letterSpacing: "0.1em", textTransform: "uppercase", textDecoration: "none" },
2627
+ children: "shop"
2628
+ }
2629
+ )
2630
+ ] })
2631
+ ] })
2632
+ ] });
2633
+ }
2393
2634
  function SocialLinksSection({ section, theme }) {
2394
2635
  const { links } = section.content;
2395
2636
  if (!links || links.length === 0) return null;
@@ -2417,25 +2658,21 @@ function toEmbedUrl(url) {
2417
2658
  }
2418
2659
  function ReviewLine({ rating, count, source, url, accent, fg }) {
2419
2660
  const label = `${rating.toFixed(1)} \xB7 ${count} ${source || "reviews"}`;
2420
- 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)) });
2421
- const text = /* @__PURE__ */ jsx("span", { style: { fontSize: "0.8rem", color: `${fg}80`, fontWeight: 500 }, children: label });
2422
- const inner = /* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: "0.5rem" }, children: [
2423
- stars,
2424
- text
2661
+ const content = /* @__PURE__ */ jsxs("div", { style: {
2662
+ marginTop: "1.5rem",
2663
+ display: "flex",
2664
+ alignItems: "center",
2665
+ justifyContent: "center",
2666
+ gap: "0.625rem"
2667
+ }, children: [
2668
+ /* @__PURE__ */ jsx("span", { dangerouslySetInnerHTML: { __html: GOOGLE_G } }),
2669
+ /* @__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)) }),
2670
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "0.9rem", color: `${fg}AA`, fontWeight: 500 }, children: label })
2425
2671
  ] });
2426
2672
  if (url) {
2427
- return /* @__PURE__ */ jsx("div", { style: { marginTop: "1.25rem", textAlign: "center" }, children: /* @__PURE__ */ jsx(
2428
- "a",
2429
- {
2430
- href: url,
2431
- target: "_blank",
2432
- rel: "noopener noreferrer",
2433
- style: { textDecoration: "none", display: "inline-flex", alignItems: "center", gap: "0.5rem" },
2434
- children: inner
2435
- }
2436
- ) });
2673
+ return /* @__PURE__ */ jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", style: { textDecoration: "none", display: "block" }, children: content });
2437
2674
  }
2438
- return /* @__PURE__ */ jsx("div", { style: { marginTop: "1.25rem", display: "flex", justifyContent: "center" }, children: inner });
2675
+ return content;
2439
2676
  }
2440
2677
  function CTASection({ section, theme, tracking, onEvent }) {
2441
2678
  const { title, subtitle, buttons } = section.content;
@@ -2812,15 +3049,26 @@ function SuccessState({ theme, heading, message, couponCode }) {
2812
3049
  }, children: couponCode })
2813
3050
  ] }) });
2814
3051
  }
3052
+ var GOOGLE_G_LG = '<svg width="28" height="28" 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>';
3053
+ var GOOGLE_G_SM = '<svg width="14" height="14" 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>';
2815
3054
  function TestimonialsSection({ section, theme }) {
2816
3055
  const c = section.content;
2817
- const layout = section.config?.layout || "grid";
3056
+ section.config?.layout || "grid";
2818
3057
  const reviews = c.reviews || [];
2819
3058
  if (reviews.length === 0) return null;
2820
3059
  const overallRating = c.rating ?? 5;
2821
3060
  const reviewCount = c.review_count ?? reviews.length;
2822
- return /* @__PURE__ */ jsxs("div", { style: { padding: "3rem 1.5rem", maxWidth: 640, margin: "0 auto" }, children: [
2823
- /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", marginBottom: "2rem" }, children: [
3061
+ const googleUrl = section.config?.google_url || void 0;
3062
+ const directionsUrl = section.config?.directions_url || void 0;
3063
+ `reviews-${section.id}`;
3064
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "3rem 0", overflow: "hidden" }, children: [
3065
+ /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: `
3066
+ .rv-scroll{display:flex;gap:clamp(0.5rem,2vw,0.75rem);overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;scrollbar-width:none;padding:0 clamp(1rem,4vw,3rem)}
3067
+ .rv-scroll::-webkit-scrollbar{display:none}
3068
+ .rv-card{flex:0 0 clamp(260px,40vw,320px);scroll-snap-align:start}
3069
+ ` } }),
3070
+ /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", marginBottom: "2rem", padding: "0 1.5rem" }, children: [
3071
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "center", marginBottom: "0.75rem" }, children: /* @__PURE__ */ jsx("span", { dangerouslySetInnerHTML: { __html: GOOGLE_G_LG } }) }),
2824
3072
  c.heading && /* @__PURE__ */ jsx("h2", { style: {
2825
3073
  fontSize: "clamp(1.25rem, 4vw, 1.75rem)",
2826
3074
  fontWeight: 300,
@@ -2831,42 +3079,121 @@ function TestimonialsSection({ section, theme }) {
2831
3079
  color: theme.fg
2832
3080
  }, children: /* @__PURE__ */ jsx(AnimatedText, { text: c.heading }) }),
2833
3081
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: "0.5rem", marginBottom: "0.25rem" }, children: [
2834
- /* @__PURE__ */ jsx(Stars, { rating: overallRating, color: theme.accent, size: 18 }),
3082
+ /* @__PURE__ */ jsx(Stars, { rating: overallRating, color: "#FBBC05", size: 18 }),
2835
3083
  /* @__PURE__ */ jsx("span", { style: { fontSize: "1.1rem", fontWeight: 500, color: theme.fg }, children: /* @__PURE__ */ jsx(AnimatedText, { text: overallRating.toFixed(1) }) })
2836
3084
  ] }),
2837
3085
  c.subtitle ? /* @__PURE__ */ jsx("p", { style: { fontSize: "0.8rem", color: theme.muted, margin: 0, letterSpacing: "0.1em", textTransform: "uppercase" }, children: c.subtitle }) : /* @__PURE__ */ jsxs("p", { style: { fontSize: "0.8rem", color: theme.muted, margin: 0, letterSpacing: "0.1em", textTransform: "uppercase" }, children: [
2838
3086
  "from ",
2839
3087
  /* @__PURE__ */ jsx(AnimatedText, { text: String(reviewCount) }),
2840
3088
  " reviews"
3089
+ ] }),
3090
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.625rem", justifyContent: "center", marginTop: "1.5rem", flexWrap: "wrap" }, children: [
3091
+ googleUrl && /* @__PURE__ */ jsxs("a", { href: googleUrl, target: "_blank", rel: "noopener noreferrer", style: {
3092
+ display: "inline-flex",
3093
+ alignItems: "center",
3094
+ gap: "0.5rem",
3095
+ padding: "clamp(0.75rem, 2vw, 0.875rem) clamp(1.25rem, 3vw, 2rem)",
3096
+ background: theme.fg,
3097
+ color: theme.bg,
3098
+ textDecoration: "none",
3099
+ fontSize: "clamp(0.8rem, 2vw, 0.9rem)",
3100
+ fontWeight: 600,
3101
+ letterSpacing: "0.06em",
3102
+ textTransform: "uppercase"
3103
+ }, children: [
3104
+ /* @__PURE__ */ jsx("span", { dangerouslySetInnerHTML: { __html: GOOGLE_G_SM } }),
3105
+ `see all ${reviewCount} reviews`
3106
+ ] }),
3107
+ directionsUrl && /* @__PURE__ */ jsx("a", { href: directionsUrl, target: "_blank", rel: "noopener noreferrer", style: {
3108
+ display: "inline-flex",
3109
+ alignItems: "center",
3110
+ gap: "0.5rem",
3111
+ padding: "clamp(0.75rem, 2vw, 0.875rem) clamp(1.25rem, 3vw, 2rem)",
3112
+ border: `1px solid ${theme.fg}25`,
3113
+ color: theme.fg,
3114
+ textDecoration: "none",
3115
+ fontSize: "clamp(0.8rem, 2vw, 0.9rem)",
3116
+ fontWeight: 600,
3117
+ letterSpacing: "0.06em",
3118
+ textTransform: "uppercase"
3119
+ }, children: "get directions" })
2841
3120
  ] })
2842
3121
  ] }),
2843
- /* @__PURE__ */ jsx("div", { style: {
2844
- display: "grid",
2845
- gridTemplateColumns: layout === "list" ? "1fr" : `repeat(${Math.min(reviews.length, 2)}, 1fr)`,
2846
- gap: "0.75rem"
2847
- }, children: reviews.map((review, i) => /* @__PURE__ */ jsxs("div", { style: {
2848
- background: theme.surface,
2849
- border: `1px solid ${theme.fg}08`,
2850
- padding: "1.25rem"
2851
- }, children: [
2852
- /* @__PURE__ */ jsx(Stars, { rating: review.rating ?? 5, color: theme.accent, size: 14 }),
2853
- /* @__PURE__ */ jsxs("p", { style: {
2854
- fontSize: "0.88rem",
2855
- color: `${theme.fg}CC`,
2856
- margin: "0.75rem 0",
2857
- lineHeight: 1.6,
2858
- fontWeight: 300,
2859
- fontStyle: "italic"
3122
+ /* @__PURE__ */ jsxs("div", { className: "rv-scroll", children: [
3123
+ reviews.map((review, i) => /* @__PURE__ */ jsx("div", { className: "rv-card", children: /* @__PURE__ */ jsxs("div", { style: {
3124
+ background: theme.surface,
3125
+ border: `1px solid ${theme.fg}08`,
3126
+ padding: "clamp(1rem, 3vw, 1.5rem)",
3127
+ height: "100%",
3128
+ display: "flex",
3129
+ flexDirection: "column"
2860
3130
  }, children: [
2861
- '"',
2862
- review.text,
2863
- '"'
2864
- ] }),
2865
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "baseline", gap: "0.375rem" }, children: [
2866
- /* @__PURE__ */ jsx("span", { style: { fontSize: "0.8rem", fontWeight: 500, color: theme.fg }, children: review.name }),
2867
- review.location && /* @__PURE__ */ jsx("span", { style: { fontSize: "0.7rem", color: theme.muted }, children: review.location })
2868
- ] })
2869
- ] }, i)) })
3131
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: "0.75rem" }, children: [
3132
+ /* @__PURE__ */ jsx(Stars, { rating: review.rating ?? 5, color: "#FBBC05", size: 13 }),
3133
+ review.location && /* @__PURE__ */ jsx("span", { style: { fontSize: "0.6rem", letterSpacing: "0.15em", textTransform: "uppercase", color: theme.muted, fontWeight: 500 }, children: review.location })
3134
+ ] }),
3135
+ /* @__PURE__ */ jsx("p", { style: {
3136
+ fontSize: "0.9rem",
3137
+ color: `${theme.fg}B0`,
3138
+ margin: "0 0 auto",
3139
+ lineHeight: 1.65,
3140
+ fontWeight: 400,
3141
+ paddingBottom: "1rem"
3142
+ }, children: `\u201C${review.text}\u201D` }),
3143
+ /* @__PURE__ */ jsxs("div", { style: { borderTop: `1px solid ${theme.fg}08`, paddingTop: "0.75rem", display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
3144
+ /* @__PURE__ */ jsx("div", { style: {
3145
+ width: 28,
3146
+ height: 28,
3147
+ borderRadius: "50%",
3148
+ background: `${theme.accent}18`,
3149
+ border: `1px solid ${theme.accent}15`,
3150
+ display: "flex",
3151
+ alignItems: "center",
3152
+ justifyContent: "center",
3153
+ flexShrink: 0
3154
+ }, children: /* @__PURE__ */ jsx("span", { style: { fontSize: "0.7rem", fontWeight: 600, color: theme.accent, textTransform: "uppercase" }, children: review.name.charAt(0) }) }),
3155
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "0.8rem", fontWeight: 500, color: `${theme.fg}AA` }, children: review.name })
3156
+ ] })
3157
+ ] }) }, i)),
3158
+ googleUrl && /* @__PURE__ */ jsx("div", { className: "rv-card", children: /* @__PURE__ */ jsxs("a", { href: googleUrl, target: "_blank", rel: "noopener noreferrer", style: {
3159
+ height: "100%",
3160
+ display: "flex",
3161
+ flexDirection: "column",
3162
+ alignItems: "center",
3163
+ justifyContent: "center",
3164
+ gap: "0.75rem",
3165
+ background: theme.surface,
3166
+ border: `1px solid ${theme.fg}08`,
3167
+ padding: "clamp(1rem, 3vw, 1.5rem)",
3168
+ textDecoration: "none"
3169
+ }, children: [
3170
+ /* @__PURE__ */ jsx("span", { dangerouslySetInnerHTML: { __html: GOOGLE_G_LG } }),
3171
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "0.85rem", color: theme.fg, fontWeight: 500 }, children: `read all ${reviewCount}` }),
3172
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "0.75rem", color: theme.muted, letterSpacing: "0.08em" }, children: "reviews on google" })
3173
+ ] }) })
3174
+ ] }),
3175
+ googleUrl && /* @__PURE__ */ jsx("div", { style: { textAlign: "center", marginTop: "1.5rem", padding: "0 1.5rem" }, children: /* @__PURE__ */ jsxs(
3176
+ "a",
3177
+ {
3178
+ href: googleUrl,
3179
+ target: "_blank",
3180
+ rel: "noopener noreferrer",
3181
+ style: {
3182
+ display: "inline-flex",
3183
+ alignItems: "center",
3184
+ gap: "0.5rem",
3185
+ fontSize: "0.8rem",
3186
+ color: theme.muted,
3187
+ textDecoration: "none",
3188
+ letterSpacing: "0.08em",
3189
+ fontWeight: 500
3190
+ },
3191
+ children: [
3192
+ /* @__PURE__ */ jsx("span", { dangerouslySetInnerHTML: { __html: GOOGLE_G_SM } }),
3193
+ `read all ${reviewCount} reviews on google`
3194
+ ]
3195
+ }
3196
+ ) })
2870
3197
  ] });
2871
3198
  }
2872
3199
  function Stars({ rating, color, size }) {
@@ -3290,7 +3617,7 @@ function SectionRenderer({
3290
3617
  const el = (() => {
3291
3618
  switch (section.type) {
3292
3619
  case "hero":
3293
- return /* @__PURE__ */ jsx(HeroSection, { section, theme, tracking, onEvent });
3620
+ return /* @__PURE__ */ jsx(HeroSection, { section, theme, tracking, onEvent, data });
3294
3621
  case "collage_hero":
3295
3622
  return /* @__PURE__ */ jsx(CollageHeroSection, { section, theme, tracking, onEvent });
3296
3623
  case "text":
@@ -3300,7 +3627,7 @@ function SectionRenderer({
3300
3627
  case "video":
3301
3628
  return /* @__PURE__ */ jsx(VideoSection, { section, theme });
3302
3629
  case "gallery":
3303
- return /* @__PURE__ */ jsx(GallerySection, { section, theme });
3630
+ return /* @__PURE__ */ jsx(GallerySection, { section, theme, onEvent });
3304
3631
  case "cta":
3305
3632
  return /* @__PURE__ */ jsx(CTASection, { section, theme, tracking, onEvent });
3306
3633
  case "stats":