@dreamtree-org/landing-kit 0.4.0 → 0.6.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.
package/dist/index.js CHANGED
@@ -129,7 +129,7 @@ function brandStyle(brand) {
129
129
  }
130
130
  function AuthShell({
131
131
  brand,
132
- title,
132
+ title: title2,
133
133
  subtitle,
134
134
  children,
135
135
  footer,
@@ -174,7 +174,7 @@ function AuthShell({
174
174
  ] }),
175
175
  /* @__PURE__ */ jsxs2("section", { className: "dt-auth-card", "aria-labelledby": headingId, children: [
176
176
  /* @__PURE__ */ jsxs2("header", { className: "dt-auth-head", children: [
177
- /* @__PURE__ */ jsx2("h1", { id: headingId, ...demoAccounts ? tapProps : {}, children: title }),
177
+ /* @__PURE__ */ jsx2("h1", { id: headingId, ...demoAccounts ? tapProps : {}, children: title2 }),
178
178
  subtitle ? /* @__PURE__ */ jsx2("p", { children: subtitle }) : null
179
179
  ] }),
180
180
  children,
@@ -316,16 +316,16 @@ function Eyebrow({ children, className = "" }) {
316
316
  if (!children) return null;
317
317
  return /* @__PURE__ */ jsx7("p", { className: `dt-lp-eyebrow ${className}`.trim(), children });
318
318
  }
319
- function SectionIntro({ id, eyebrow, title, body, align = "start", children }) {
319
+ function SectionIntro({ id, eyebrow, title: title2, body, align = "start", children }) {
320
320
  return /* @__PURE__ */ jsxs5("div", { className: `dt-lp-intro dt-lp-intro--${align}`, children: [
321
321
  /* @__PURE__ */ jsx7(Eyebrow, { children: eyebrow }),
322
- /* @__PURE__ */ jsx7("h2", { id, className: "dt-lp-h2", children: title }),
322
+ /* @__PURE__ */ jsx7("h2", { id, className: "dt-lp-h2", children: title2 }),
323
323
  body ? /* @__PURE__ */ jsx7("p", { className: "dt-lp-lead", children: body }) : null,
324
324
  children
325
325
  ] });
326
326
  }
327
- function Section({ id, labelledBy, tone = "plain", className = "", children, narrow }) {
328
- return /* @__PURE__ */ jsx7("section", { id, "aria-labelledby": labelledBy, className: `dt-lp-section dt-lp-tone--${tone} ${className}`.trim(), children: /* @__PURE__ */ jsx7(Wrap, { narrow, children }) });
327
+ function Section({ id, labelledBy, tone: tone2 = "plain", className = "", children, narrow }) {
328
+ return /* @__PURE__ */ jsx7("section", { id, "aria-labelledby": labelledBy, className: `dt-lp-section dt-lp-tone--${tone2} ${className}`.trim(), children: /* @__PURE__ */ jsx7(Wrap, { narrow, children }) });
329
329
  }
330
330
  function TextLink({ href, children, className = "", ...rest }) {
331
331
  return /* @__PURE__ */ jsxs5(SmartLink, { href, className: `dt-lp-textlink ${className}`.trim(), ...rest, children: [
@@ -467,7 +467,7 @@ function MarketingLayout({
467
467
  import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
468
468
  function Hero({
469
469
  eyebrow,
470
- title,
470
+ title: title2,
471
471
  subtitle,
472
472
  lead,
473
473
  chips,
@@ -478,7 +478,7 @@ function Hero({
478
478
  id = "hero",
479
479
  backdrop
480
480
  }) {
481
- const [first, hi] = Array.isArray(title) ? title : [title, null];
481
+ const [first, hi] = Array.isArray(title2) ? title2 : [title2, null];
482
482
  return /* @__PURE__ */ jsxs9("section", { id, "aria-labelledby": "hero-title", className: `dt-lp-hero${overlap ? " dt-lp-hero--overlap" : ""}`, children: [
483
483
  /* @__PURE__ */ jsx11("div", { className: "dt-lp-hero-glow", "aria-hidden": "true" }),
484
484
  backdrop ? /* @__PURE__ */ jsx11("div", { className: "dt-lp-hero-backdrop", "aria-hidden": "true", children: backdrop }) : null,
@@ -515,8 +515,8 @@ function Items({ items, kind }) {
515
515
  ] })
516
516
  ] }, f.title)) });
517
517
  }
518
- function Checklist({ items, icon: Icon = Check, tone = "good", labelledBy }) {
519
- return /* @__PURE__ */ jsx12("ul", { className: `dt-lp-checklist dt-lp-checklist--${tone}`, "aria-labelledby": labelledBy, children: items.map((x) => /* @__PURE__ */ jsxs10("li", { children: [
518
+ function Checklist({ items, icon: Icon = Check, tone: tone2 = "good", labelledBy }) {
519
+ return /* @__PURE__ */ jsx12("ul", { className: `dt-lp-checklist dt-lp-checklist--${tone2}`, "aria-labelledby": labelledBy, children: items.map((x) => /* @__PURE__ */ jsxs10("li", { children: [
520
520
  /* @__PURE__ */ jsx12(Icon, { size: 18 }),
521
521
  /* @__PURE__ */ jsx12("span", { children: x })
522
522
  ] }, x)) });
@@ -545,10 +545,10 @@ function Chips({ items, label, className = "" }) {
545
545
  return /* @__PURE__ */ jsx12("ul", { className: `dt-lp-chips dt-lp-chips--start ${className}`.trim(), "aria-label": label, children: items.map((c) => /* @__PURE__ */ jsx12("li", { children: c }, c)) });
546
546
  }
547
547
  function FeatureSection(props) {
548
- const { id, variant = "cards", tone, eyebrow, title, body, items = [], cta, footnote, media, reverse, bullets } = props;
549
- const hid = `${id || variant}-title`;
548
+ const { id, variant = "cards", tone: tone2, eyebrow, title: title2, body, items = [], cta, footnote, media, reverse, bullets } = props;
549
+ const hid2 = `${id || variant}-title`;
550
550
  const defaultTone = { highlight: "dark", split: "tinted", compare: "muted" }[variant] || "plain";
551
- const shell = (children, extra = {}) => /* @__PURE__ */ jsx12(Section, { id, labelledBy: hid, tone: tone || defaultTone, className: `dt-lp-feature dt-lp-feature--${variant}`, ...extra, children });
551
+ const shell = (children, extra = {}) => /* @__PURE__ */ jsx12(Section, { id, labelledBy: hid2, tone: tone2 || defaultTone, className: `dt-lp-feature dt-lp-feature--${variant}`, ...extra, children });
552
552
  switch (variant) {
553
553
  case "split":
554
554
  return shell(
@@ -557,7 +557,7 @@ function FeatureSection(props) {
557
557
  {
558
558
  className: "dt-lp-split",
559
559
  reverse,
560
- text: /* @__PURE__ */ jsxs10(SectionIntro, { id: hid, eyebrow, title, body, children: [
560
+ text: /* @__PURE__ */ jsxs10(SectionIntro, { id: hid2, eyebrow, title: title2, body, children: [
561
561
  media ? /* @__PURE__ */ jsx12(InlineItems, { items }) : null,
562
562
  (bullets == null ? void 0 : bullets.length) ? /* @__PURE__ */ jsx12(Checklist, { items: bullets }) : null,
563
563
  /* @__PURE__ */ jsx12(Cta, { cta, className: "dt-lp-mt" })
@@ -569,7 +569,7 @@ function FeatureSection(props) {
569
569
  case "list":
570
570
  return shell(
571
571
  /* @__PURE__ */ jsxs10(Fragment4, { children: [
572
- /* @__PURE__ */ jsx12(SectionIntro, { id: hid, eyebrow, title, body, align: "center" }),
572
+ /* @__PURE__ */ jsx12(SectionIntro, { id: hid2, eyebrow, title: title2, body, align: "center" }),
573
573
  /* @__PURE__ */ jsx12(Items, { items, kind: "list" }),
574
574
  /* @__PURE__ */ jsx12(Cta, { cta, className: "dt-lp-mt" })
575
575
  ] })
@@ -579,14 +579,14 @@ function FeatureSection(props) {
579
579
  return shell(
580
580
  /* @__PURE__ */ jsxs10("div", { className: "dt-lp-intro-grid", children: [
581
581
  /* @__PURE__ */ jsxs10("div", { children: [
582
- /* @__PURE__ */ jsx12(SectionIntro, { id: hid, eyebrow, title, body }),
582
+ /* @__PURE__ */ jsx12(SectionIntro, { id: hid2, eyebrow, title: title2, body }),
583
583
  subtitle ? /* @__PURE__ */ jsx12("h3", { className: "dt-lp-h3 dt-lp-h3--lg", children: subtitle }) : null,
584
584
  detail ? /* @__PURE__ */ jsx12("p", { className: "dt-lp-body", children: detail }) : null,
585
585
  note ? /* @__PURE__ */ jsx12("p", { className: "dt-lp-note", children: note }) : null,
586
586
  /* @__PURE__ */ jsx12(Cta, { cta, className: "dt-lp-mt" })
587
587
  ] }),
588
- glance.length ? /* @__PURE__ */ jsxs10("aside", { className: "dt-lp-glance", "aria-labelledby": `${hid}-glance`, children: [
589
- /* @__PURE__ */ jsx12("p", { id: `${hid}-glance`, className: "dt-lp-eyebrow", children: glanceTitle }),
588
+ glance.length ? /* @__PURE__ */ jsxs10("aside", { className: "dt-lp-glance", "aria-labelledby": `${hid2}-glance`, children: [
589
+ /* @__PURE__ */ jsx12("p", { id: `${hid2}-glance`, className: "dt-lp-eyebrow", children: glanceTitle }),
590
590
  /* @__PURE__ */ jsx12(Checklist, { items: glance }),
591
591
  props.glanceNote ? /* @__PURE__ */ jsx12("p", { className: "dt-lp-note", children: props.glanceNote }) : null,
592
592
  link ? /* @__PURE__ */ jsx12(TextLink, { href: link.href, className: "dt-lp-mt", children: link.label }) : null
@@ -598,7 +598,7 @@ function FeatureSection(props) {
598
598
  const { note, noteLabel = "Important:" } = props;
599
599
  const text = /* @__PURE__ */ jsxs10("div", { className: "dt-lp-intro", children: [
600
600
  /* @__PURE__ */ jsx12(Eyebrow, { children: eyebrow }),
601
- /* @__PURE__ */ jsx12("h2", { id: hid, className: "dt-lp-h2", children: title }),
601
+ /* @__PURE__ */ jsx12("h2", { id: hid2, className: "dt-lp-h2", children: title2 }),
602
602
  body ? /* @__PURE__ */ jsx12("p", { className: "dt-lp-lead", children: body }) : null,
603
603
  note ? /* @__PURE__ */ jsxs10("p", { className: "dt-lp-callout", children: [
604
604
  /* @__PURE__ */ jsx12(Alert, { size: 20 }),
@@ -620,7 +620,7 @@ function FeatureSection(props) {
620
620
  case "band": {
621
621
  const { examples, examplesLabel = "Examples" } = props;
622
622
  const text = /* @__PURE__ */ jsxs10("div", { children: [
623
- /* @__PURE__ */ jsx12(SectionIntro, { id: hid, eyebrow, title, body }),
623
+ /* @__PURE__ */ jsx12(SectionIntro, { id: hid2, eyebrow, title: title2, body }),
624
624
  /* @__PURE__ */ jsx12(Chips, { items: examples, label: examplesLabel, className: "dt-lp-mt" }),
625
625
  media ? /* @__PURE__ */ jsx12(InlineItems, { items }) : null,
626
626
  /* @__PURE__ */ jsx12(Cta, { cta, className: "dt-lp-mt" })
@@ -635,13 +635,13 @@ function FeatureSection(props) {
635
635
  const { columns = [] } = props;
636
636
  return shell(
637
637
  /* @__PURE__ */ jsxs10(Fragment4, { children: [
638
- /* @__PURE__ */ jsx12(SectionIntro, { id: hid, eyebrow, title, body }),
638
+ /* @__PURE__ */ jsx12(SectionIntro, { id: hid2, eyebrow, title: title2, body }),
639
639
  /* @__PURE__ */ jsx12("div", { className: "dt-lp-compare", children: columns.map((col, i) => {
640
640
  const cid = `${id || "compare"}-${i + 1}`;
641
- const tone2 = col.tone || (i === 0 ? "good" : "check");
641
+ const tone3 = col.tone || (i === 0 ? "good" : "check");
642
642
  return /* @__PURE__ */ jsxs10("div", { className: "dt-lp-card dt-lp-card--compare", children: [
643
643
  /* @__PURE__ */ jsx12("h3", { id: cid, className: "dt-lp-h3 dt-lp-h3--lg", children: col.title }),
644
- /* @__PURE__ */ jsx12(Checklist, { items: col.items, tone: tone2, icon: tone2 === "good" ? Check : Help, labelledBy: cid })
644
+ /* @__PURE__ */ jsx12(Checklist, { items: col.items, tone: tone3, icon: tone3 === "good" ? Check : Help, labelledBy: cid })
645
645
  ] }, cid);
646
646
  }) })
647
647
  ] })
@@ -650,7 +650,7 @@ function FeatureSection(props) {
650
650
  case "links":
651
651
  return shell(
652
652
  /* @__PURE__ */ jsxs10(Fragment4, { children: [
653
- /* @__PURE__ */ jsx12(SectionIntro, { id: hid, eyebrow, title, body }),
653
+ /* @__PURE__ */ jsx12(SectionIntro, { id: hid2, eyebrow, title: title2, body }),
654
654
  /* @__PURE__ */ jsx12("ul", { className: "dt-lp-grid dt-lp-grid--links", children: items.map((s) => /* @__PURE__ */ jsx12("li", { children: /* @__PURE__ */ jsxs10(SmartLink, { href: s.href, className: "dt-lp-linkcard", children: [
655
655
  /* @__PURE__ */ jsxs10("span", { className: "dt-lp-linkcard-title", children: [
656
656
  s.title,
@@ -664,7 +664,7 @@ function FeatureSection(props) {
664
664
  case "detail": {
665
665
  return shell(
666
666
  /* @__PURE__ */ jsxs10("div", { className: "dt-lp-detail", children: [
667
- /* @__PURE__ */ jsx12("h2", { id: hid, className: "dt-lp-h2", children: title }),
667
+ /* @__PURE__ */ jsx12("h2", { id: hid2, className: "dt-lp-h2", children: title2 }),
668
668
  /* @__PURE__ */ jsxs10("div", { children: [
669
669
  body ? /* @__PURE__ */ jsx12("p", { className: "dt-lp-body", children: body }) : null,
670
670
  (bullets == null ? void 0 : bullets.length) ? /* @__PURE__ */ jsx12(Checklist, { items: bullets }) : null
@@ -675,7 +675,7 @@ function FeatureSection(props) {
675
675
  default:
676
676
  return shell(
677
677
  /* @__PURE__ */ jsxs10(Fragment4, { children: [
678
- /* @__PURE__ */ jsx12(SectionIntro, { id: hid, eyebrow, title, body }),
678
+ /* @__PURE__ */ jsx12(SectionIntro, { id: hid2, eyebrow, title: title2, body }),
679
679
  /* @__PURE__ */ jsx12(Items, { items, kind: "cards" }),
680
680
  footnote ? /* @__PURE__ */ jsx12("p", { className: "dt-lp-footnote", children: footnote }) : null,
681
681
  /* @__PURE__ */ jsx12(Cta, { cta, className: "dt-lp-mt" })
@@ -686,10 +686,10 @@ function FeatureSection(props) {
686
686
 
687
687
  // src/Audiences.jsx
688
688
  import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
689
- function Audiences({ id = "audiences", eyebrow, title, body, items = [], linkLabel = "See how it works", tone = "muted" }) {
690
- const hid = `${id}-title`;
691
- return /* @__PURE__ */ jsxs11(Section, { id, labelledBy: hid, tone, className: "dt-lp-audiences", children: [
692
- /* @__PURE__ */ jsx13(SectionIntro, { id: hid, eyebrow, title, body, align: "center" }),
689
+ function Audiences({ id = "audiences", eyebrow, title: title2, body, items = [], linkLabel = "See how it works", tone: tone2 = "muted" }) {
690
+ const hid2 = `${id}-title`;
691
+ return /* @__PURE__ */ jsxs11(Section, { id, labelledBy: hid2, tone: tone2, className: "dt-lp-audiences", children: [
692
+ /* @__PURE__ */ jsx13(SectionIntro, { id: hid2, eyebrow, title: title2, body, align: "center" }),
693
693
  /* @__PURE__ */ jsx13("div", { className: `dt-lp-grid dt-lp-grid--audiences dt-lp-grid--n${Math.min(items.length, 4)}`, children: items.map((a, i) => {
694
694
  var _a;
695
695
  const aid = a.id || `${id}-${i + 1}`;
@@ -718,11 +718,11 @@ function Audiences({ id = "audiences", eyebrow, title, body, items = [], linkLab
718
718
 
719
719
  // src/HowItWorks.jsx
720
720
  import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
721
- function HowItWorks({ id = "how-it-works", eyebrow, title, body, steps, items, tone = "plain", cta }) {
721
+ function HowItWorks({ id = "how-it-works", eyebrow, title: title2, body, steps, items, tone: tone2 = "plain", cta }) {
722
722
  const list = steps || items || [];
723
- const hid = `${id}-title`;
724
- return /* @__PURE__ */ jsxs12(Section, { id, labelledBy: hid, tone, className: "dt-lp-steps", children: [
725
- /* @__PURE__ */ jsx14(SectionIntro, { id: hid, eyebrow, title, body }),
723
+ const hid2 = `${id}-title`;
724
+ return /* @__PURE__ */ jsxs12(Section, { id, labelledBy: hid2, tone: tone2, className: "dt-lp-steps", children: [
725
+ /* @__PURE__ */ jsx14(SectionIntro, { id: hid2, eyebrow, title: title2, body }),
726
726
  /* @__PURE__ */ jsx14("ol", { className: "dt-lp-grid dt-lp-grid--steps", children: list.map((st, i) => /* @__PURE__ */ jsxs12("li", { className: "dt-lp-card", children: [
727
727
  /* @__PURE__ */ jsx14("span", { className: "dt-lp-step-num", "aria-hidden": "true", children: i + 1 }),
728
728
  /* @__PURE__ */ jsx14("h3", { className: "dt-lp-h3", children: st.name || st.title }),
@@ -734,10 +734,10 @@ function HowItWorks({ id = "how-it-works", eyebrow, title, body, steps, items, t
734
734
 
735
735
  // src/Faq.jsx
736
736
  import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
737
- function Faq({ id = "faq", eyebrow, title = "Frequently asked questions", intro, items = [], openFirst = true, tone = "muted" }) {
738
- const hid = `${id}-title`;
739
- return /* @__PURE__ */ jsxs13(Section, { id, labelledBy: hid, tone, narrow: true, className: "dt-lp-faq", children: [
740
- /* @__PURE__ */ jsx15(SectionIntro, { id: hid, eyebrow, title, body: intro, align: "center" }),
737
+ function Faq({ id = "faq", eyebrow, title: title2 = "Frequently asked questions", intro: intro2, items = [], openFirst = true, tone: tone2 = "muted" }) {
738
+ const hid2 = `${id}-title`;
739
+ return /* @__PURE__ */ jsxs13(Section, { id, labelledBy: hid2, tone: tone2, narrow: true, className: "dt-lp-faq", children: [
740
+ /* @__PURE__ */ jsx15(SectionIntro, { id: hid2, eyebrow, title: title2, body: intro2, align: "center" }),
741
741
  /* @__PURE__ */ jsx15("div", { className: "dt-lp-faq-list", children: items.map((f, i) => /* @__PURE__ */ jsxs13("details", { className: "dt-lp-faq-item", open: openFirst && i === 0, children: [
742
742
  /* @__PURE__ */ jsxs13("summary", { children: [
743
743
  /* @__PURE__ */ jsx15("h3", { className: "dt-lp-h3", children: f.q }),
@@ -750,10 +750,10 @@ function Faq({ id = "faq", eyebrow, title = "Frequently asked questions", intro,
750
750
 
751
751
  // src/DemoCta.jsx
752
752
  import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
753
- function DemoCta({ id = "demo", eyebrow, title, body, label = "Book a demo", chips, chipsLabel = "Business types", note, link }) {
753
+ function DemoCta({ id = "demo", eyebrow, title: title2, body, label = "Book a demo", chips, chipsLabel = "Business types", note, link }) {
754
754
  return /* @__PURE__ */ jsx16("section", { id, "aria-labelledby": `${id}-title`, className: "dt-lp-section dt-lp-cta", children: /* @__PURE__ */ jsx16(Wrap, { children: /* @__PURE__ */ jsxs14("div", { className: "dt-lp-cta-panel", children: [
755
755
  eyebrow ? /* @__PURE__ */ jsx16("p", { className: "dt-lp-eyebrow dt-lp-eyebrow--inverse", children: eyebrow }) : null,
756
- /* @__PURE__ */ jsx16("h2", { id: `${id}-title`, className: "dt-lp-h2 dt-lp-h2--cta", children: title }),
756
+ /* @__PURE__ */ jsx16("h2", { id: `${id}-title`, className: "dt-lp-h2 dt-lp-h2--cta", children: title2 }),
757
757
  body ? /* @__PURE__ */ jsx16("p", { className: "dt-lp-cta-body", children: body }) : null,
758
758
  /* @__PURE__ */ jsx16(BookDemoButton, { size: "lg", variant: "inverse", children: label }),
759
759
  (chips == null ? void 0 : chips.length) ? /* @__PURE__ */ jsx16("ul", { className: "dt-lp-chips dt-lp-chips--inverse", "aria-label": chipsLabel, children: chips.map((k) => /* @__PURE__ */ jsx16("li", { children: k }, k)) }) : null,
@@ -858,7 +858,7 @@ var DEFAULT_DEMO_FIELDS = [
858
858
  { name: "email", label: "Email", type: "email", maxLength: 190, autoComplete: "email" },
859
859
  { name: "company", label: "Business name", maxLength: 160, autoComplete: "organization" }
860
860
  ];
861
- var initial = (fields) => Object.fromEntries(fields.map((f) => [f.name, ""]));
861
+ var initial = (fields2) => Object.fromEntries(fields2.map((f) => [f.name, ""]));
862
862
  function Field({ f, value, onChange, error }) {
863
863
  const id = `dt-demo-${f.name}`;
864
864
  const errId = `${id}-error`;
@@ -908,9 +908,9 @@ function DemoDialog({
908
908
  onClose = () => {
909
909
  },
910
910
  onSubmit,
911
- fields = DEFAULT_DEMO_FIELDS,
912
- title,
913
- intro = "Tell us a little about your business and we will walk you through the workflows that matter to your team.",
911
+ fields: fields2 = DEFAULT_DEMO_FIELDS,
912
+ title: title2,
913
+ intro: intro2 = "Tell us a little about your business and we will walk you through the workflows that matter to your team.",
914
914
  fiduciary = "Dreamtree-Org",
915
915
  consentText,
916
916
  privacyHref = "/privacy",
@@ -920,7 +920,7 @@ function DemoDialog({
920
920
  validate
921
921
  }) {
922
922
  const ref = useRef3(null);
923
- const [form, setForm] = useState4(() => initial(fields));
923
+ const [form, setForm] = useState4(() => initial(fields2));
924
924
  const [website, setWebsite] = useState4("");
925
925
  const [consent, setConsent] = useState4(false);
926
926
  const [busy, setBusy] = useState4(false);
@@ -940,7 +940,7 @@ function DemoDialog({
940
940
  setForm((f) => ({ ...f, [k]: e.target.value }));
941
941
  if (fieldErrors[k]) setFieldErrors(({ [k]: _gone, ...rest }) => rest);
942
942
  };
943
- const ready = consent && (typeof validate === "function" || fields.every((f) => !f.required || String(form[f.name] || "").trim()));
943
+ const ready = consent && (typeof validate === "function" || fields2.every((f) => !f.required || String(form[f.name] || "").trim()));
944
944
  const submit = async (e) => {
945
945
  e.preventDefault();
946
946
  if (!ready || busy) return;
@@ -977,16 +977,16 @@ function DemoDialog({
977
977
  },
978
978
  children: [
979
979
  /* @__PURE__ */ jsxs17("div", { className: "dt-lp-dialog-head", children: [
980
- /* @__PURE__ */ jsx19("h2", { id: "dt-demo-title", children: sent ? "Thank you" : title || `Book a ${name} demo` }),
980
+ /* @__PURE__ */ jsx19("h2", { id: "dt-demo-title", children: sent ? "Thank you" : title2 || `Book a ${name} demo` }),
981
981
  /* @__PURE__ */ jsx19("button", { type: "button", className: "dt-lp-dialog-x", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx19(Close, { size: 18 }) })
982
982
  ] }),
983
983
  /* @__PURE__ */ jsx19("div", { className: "dt-lp-dialog-body", children: sent ? /* @__PURE__ */ jsxs17("div", { className: "dt-lp-stack", children: [
984
984
  /* @__PURE__ */ jsx19("p", { role: "status", children: thanks }),
985
985
  /* @__PURE__ */ jsx19("button", { type: "button", className: "dt-lp-btn dt-lp-btn--outline dt-lp-btn--md", onClick: onClose, children: "Close" })
986
986
  ] }) : /* @__PURE__ */ jsxs17("form", { className: "dt-lp-stack", onSubmit: submit, noValidate: true, children: [
987
- intro ? /* @__PURE__ */ jsx19("p", { className: "dt-lp-muted", children: intro }) : null,
987
+ intro2 ? /* @__PURE__ */ jsx19("p", { className: "dt-lp-muted", children: intro2 }) : null,
988
988
  err ? /* @__PURE__ */ jsx19("p", { role: "alert", className: "dt-lp-error", children: err }) : null,
989
- /* @__PURE__ */ jsx19("div", { className: "dt-lp-fields", children: fields.map((f) => /* @__PURE__ */ jsx19(Field, { f, value: form[f.name], onChange: set(f.name), error: fieldErrors[f.name] }, f.name)) }),
989
+ /* @__PURE__ */ jsx19("div", { className: "dt-lp-fields", children: fields2.map((f) => /* @__PURE__ */ jsx19(Field, { f, value: form[f.name], onChange: set(f.name), error: fieldErrors[f.name] }, f.name)) }),
990
990
  /* @__PURE__ */ jsx19("div", { "aria-hidden": "true", className: "dt-lp-honeypot", children: /* @__PURE__ */ jsxs17("label", { children: [
991
991
  "Website",
992
992
  /* @__PURE__ */ jsx19("input", { type: "text", name: "website", tabIndex: -1, autoComplete: "off", value: website, onChange: (e) => setWebsite(e.target.value) })
@@ -1023,11 +1023,11 @@ function Breadcrumbs({ items = [] }) {
1023
1023
  ] }, `${c.label}-${i}`);
1024
1024
  }) }) });
1025
1025
  }
1026
- function PageHero({ breadcrumbs, eyebrow, title, lead, cta = "Book a demo", secondary }) {
1026
+ function PageHero({ breadcrumbs, eyebrow, title: title2, lead, cta = "Book a demo", secondary }) {
1027
1027
  return /* @__PURE__ */ jsx20("section", { "aria-labelledby": "hero-title", className: "dt-lp-hero dt-lp-hero--page", children: /* @__PURE__ */ jsxs18(Wrap, { className: "dt-lp-hero-inner dt-lp-hero-inner--start", children: [
1028
1028
  /* @__PURE__ */ jsx20(Breadcrumbs, { items: breadcrumbs }),
1029
1029
  /* @__PURE__ */ jsx20(Eyebrow, { className: "dt-lp-mt-lg", children: eyebrow }),
1030
- /* @__PURE__ */ jsx20("h1", { id: "hero-title", className: "dt-lp-h1 dt-lp-h1--page", children: title }),
1030
+ /* @__PURE__ */ jsx20("h1", { id: "hero-title", className: "dt-lp-h1 dt-lp-h1--page", children: title2 }),
1031
1031
  lead ? /* @__PURE__ */ jsx20("p", { id: "answer", className: "dt-lp-hero-lead", children: lead }) : null,
1032
1032
  /* @__PURE__ */ jsxs18("div", { className: "dt-lp-actions dt-lp-actions--start", children: [
1033
1033
  cta ? /* @__PURE__ */ jsx20(BookDemoButton, { size: "lg", children: cta }) : null,
@@ -1214,6 +1214,1012 @@ function toLandingBrand(file, copy = {}) {
1214
1214
  };
1215
1215
  return Object.fromEntries(Object.entries(brand).filter(([, v]) => v !== void 0));
1216
1216
  }
1217
+
1218
+ // src/tenant/TenantPage.jsx
1219
+ import { Component, useMemo } from "react";
1220
+
1221
+ // src/schema/sections.js
1222
+ var ICON_NAMES = [
1223
+ "shield-check",
1224
+ "badge-check",
1225
+ "truck",
1226
+ "wrench",
1227
+ "refresh",
1228
+ "battery",
1229
+ "cpu",
1230
+ "laptop",
1231
+ "star",
1232
+ "headset",
1233
+ "rupee",
1234
+ "award",
1235
+ "clock",
1236
+ "map-pin",
1237
+ "phone",
1238
+ "check",
1239
+ "sparkles",
1240
+ "tag",
1241
+ "gift",
1242
+ "heart"
1243
+ ];
1244
+ var TONES = [
1245
+ { value: "plain", label: "Plain" },
1246
+ { value: "tinted", label: "Brand tint" },
1247
+ { value: "muted", label: "Muted" },
1248
+ { value: "dark", label: "Dark" }
1249
+ ];
1250
+ var tone = (d = "plain") => ({ key: "tone", kind: "select", label: "Background", options: TONES, default: d });
1251
+ var title = (d = "", max = 90) => ({ key: "title", kind: "text", label: "Heading", max, default: d });
1252
+ var intro = { key: "intro", kind: "textarea", label: "Intro", max: 240, default: "" };
1253
+ var ctaLabel = { key: "cta_label", kind: "text", label: "Button text", max: 30, default: "" };
1254
+ var ctaHref = { key: "cta_href", kind: "url", label: "Button link", default: "" };
1255
+ var SECTION_TYPES = {
1256
+ hero_slider: {
1257
+ label: "Hero slider",
1258
+ description: "Full-width slides with an image, heading, text and a button.",
1259
+ fields: [
1260
+ {
1261
+ key: "slides",
1262
+ kind: "list",
1263
+ label: "Slides",
1264
+ min: 1,
1265
+ max: 6,
1266
+ itemLabel: "heading",
1267
+ of: [
1268
+ { key: "image", kind: "image", label: "Image (wide, 16:7)", default: null },
1269
+ { key: "mobile_image", kind: "image", label: "Phone image (4:5, optional)", default: null },
1270
+ { key: "eyebrow", kind: "text", label: "Small label above", max: 60, default: "" },
1271
+ { key: "heading", kind: "text", label: "Heading", max: 90, required: true, default: "Your headline" },
1272
+ { key: "text", kind: "textarea", label: "Text", max: 220, default: "" },
1273
+ ctaLabel,
1274
+ ctaHref,
1275
+ { key: "align", kind: "select", label: "Text position", options: [{ value: "start", label: "Left" }, { value: "center", label: "Centre" }], default: "start" },
1276
+ { key: "overlay", kind: "select", label: "Darken image", options: [{ value: "none", label: "None" }, { value: "light", label: "Light" }, { value: "strong", label: "Strong" }], default: "light" }
1277
+ ],
1278
+ default: [{ heading: "Your headline" }]
1279
+ },
1280
+ { key: "height", kind: "select", label: "Height", options: [{ value: "compact", label: "Compact" }, { value: "standard", label: "Standard" }, { value: "tall", label: "Tall" }], default: "standard" },
1281
+ { key: "autoplay", kind: "bool", label: "Move to the next slide automatically", default: true },
1282
+ { key: "interval", kind: "select", label: "Seconds per slide", options: [{ value: "4", label: "4" }, { value: "6", label: "6" }, { value: "8", label: "8" }], default: "6" }
1283
+ ]
1284
+ },
1285
+ featured: {
1286
+ label: "Featured products",
1287
+ description: "The store's newest products (filled in by the app).",
1288
+ slot: true,
1289
+ fields: [title("Featured"), intro, { key: "limit", kind: "select", label: "How many", options: [{ value: "4", label: "4" }, { value: "8", label: "8" }, { value: "12", label: "12" }], default: "8" }, tone()]
1290
+ },
1291
+ categories: {
1292
+ label: "Shop by category",
1293
+ description: "Category tiles (filled in by the app).",
1294
+ slot: true,
1295
+ fields: [title("Shop by category"), tone()]
1296
+ },
1297
+ promo_banner: {
1298
+ label: "Promo banner",
1299
+ description: "A highlighted offer with an optional image and button.",
1300
+ fields: [
1301
+ { key: "eyebrow", kind: "text", label: "Small label above", max: 60, default: "" },
1302
+ { key: "heading", kind: "text", label: "Heading", max: 90, required: true, default: "Festive offer" },
1303
+ { key: "text", kind: "textarea", label: "Text", max: 240, default: "" },
1304
+ ctaLabel,
1305
+ ctaHref,
1306
+ { key: "image", kind: "image", label: "Image (optional)", default: null },
1307
+ { key: "style", kind: "select", label: "Style", options: [{ value: "brand", label: "Brand colour" }, { value: "accent", label: "Accent colour" }, { value: "dark", label: "Dark" }], default: "brand" }
1308
+ ]
1309
+ },
1310
+ trust_badges: {
1311
+ label: "Trust badges",
1312
+ description: "Why buy from you: icon, title and a line each.",
1313
+ fields: [
1314
+ title("Why buy from us"),
1315
+ intro,
1316
+ {
1317
+ key: "items",
1318
+ kind: "list",
1319
+ label: "Badges",
1320
+ min: 1,
1321
+ max: 8,
1322
+ itemLabel: "title",
1323
+ of: [
1324
+ { key: "icon", kind: "icon", label: "Icon", default: "shield-check" },
1325
+ { key: "title", kind: "text", label: "Title", max: 50, required: true, default: "Inspected and graded" },
1326
+ { key: "text", kind: "textarea", label: "Text", max: 140, default: "" }
1327
+ ],
1328
+ default: [{ title: "Inspected and graded" }]
1329
+ },
1330
+ tone()
1331
+ ]
1332
+ },
1333
+ cta_cards: {
1334
+ label: "Action cards",
1335
+ description: "Two to four cards that each lead somewhere (repairs, sell your laptop\u2026).",
1336
+ fields: [
1337
+ title("", 90),
1338
+ {
1339
+ key: "items",
1340
+ kind: "list",
1341
+ label: "Cards",
1342
+ min: 1,
1343
+ max: 4,
1344
+ itemLabel: "title",
1345
+ of: [
1346
+ { key: "icon", kind: "icon", label: "Icon", default: "wrench" },
1347
+ { key: "title", kind: "text", label: "Title", max: 50, required: true, default: "Book a repair" },
1348
+ { key: "text", kind: "textarea", label: "Text", max: 140, default: "" },
1349
+ { key: "cta_label", kind: "text", label: "Link text", max: 30, default: "Learn more" },
1350
+ { key: "cta_href", kind: "url", label: "Link", required: true, default: "/" }
1351
+ ],
1352
+ default: [{ title: "Book a repair", cta_href: "/" }]
1353
+ },
1354
+ tone()
1355
+ ]
1356
+ },
1357
+ testimonials: {
1358
+ label: "Testimonials",
1359
+ description: "What customers say.",
1360
+ fields: [
1361
+ title("What customers say"),
1362
+ {
1363
+ key: "items",
1364
+ kind: "list",
1365
+ label: "Quotes",
1366
+ min: 1,
1367
+ max: 12,
1368
+ itemLabel: "name",
1369
+ of: [
1370
+ { key: "quote", kind: "textarea", label: "Quote", max: 400, required: true, default: "Great service." },
1371
+ { key: "name", kind: "text", label: "Name", max: 60, required: true, default: "A happy customer" },
1372
+ { key: "detail", kind: "text", label: "Detail (city, purchase)", max: 80, default: "" },
1373
+ { key: "rating", kind: "select", label: "Stars", options: ["5", "4", "3", "2", "1"].map((v) => ({ value: v, label: v })), default: "5" }
1374
+ ],
1375
+ default: [{ quote: "Great service.", name: "A happy customer" }]
1376
+ },
1377
+ tone("muted")
1378
+ ]
1379
+ },
1380
+ faq: {
1381
+ label: "FAQ",
1382
+ description: "Questions and answers (also used for search snippets).",
1383
+ fields: [
1384
+ title("Frequently asked questions"),
1385
+ intro,
1386
+ {
1387
+ key: "items",
1388
+ kind: "list",
1389
+ label: "Questions",
1390
+ min: 1,
1391
+ max: 20,
1392
+ itemLabel: "q",
1393
+ of: [
1394
+ { key: "q", kind: "text", label: "Question", max: 160, required: true, default: "A question?" },
1395
+ { key: "a", kind: "textarea", label: "Answer", max: 800, required: true, default: "The answer." }
1396
+ ],
1397
+ default: [{ q: "A question?", a: "The answer." }]
1398
+ },
1399
+ tone("muted")
1400
+ ]
1401
+ },
1402
+ rich_text: {
1403
+ label: "Text",
1404
+ description: "Free text with headings, lists and links.",
1405
+ fields: [title("", 90), { key: "html", kind: "richtext", label: "Text", max: 8e3, default: "<p>Write something about your store.</p>" }, { key: "width", kind: "select", label: "Width", options: [{ value: "narrow", label: "Narrow" }, { value: "wide", label: "Wide" }], default: "narrow" }, tone()]
1406
+ },
1407
+ usp_strip: {
1408
+ label: "Highlights strip",
1409
+ description: "A short row of selling points under the hero.",
1410
+ fields: [
1411
+ {
1412
+ key: "items",
1413
+ kind: "list",
1414
+ label: "Highlights",
1415
+ min: 2,
1416
+ max: 6,
1417
+ itemLabel: "title",
1418
+ of: [
1419
+ { key: "icon", kind: "icon", label: "Icon", default: "check" },
1420
+ { key: "title", kind: "text", label: "Title", max: 40, required: true, default: "Free delivery" },
1421
+ { key: "text", kind: "text", label: "Line", max: 80, default: "" }
1422
+ ],
1423
+ default: [{ title: "Free delivery" }, { title: "Warranty included" }]
1424
+ },
1425
+ tone("tinted")
1426
+ ]
1427
+ },
1428
+ brand_strip: {
1429
+ label: "Brands we sell",
1430
+ description: "Brand names or logos.",
1431
+ fields: [
1432
+ title("Brands we sell"),
1433
+ {
1434
+ key: "items",
1435
+ kind: "list",
1436
+ label: "Brands",
1437
+ min: 1,
1438
+ max: 16,
1439
+ itemLabel: "name",
1440
+ of: [
1441
+ { key: "name", kind: "text", label: "Brand", max: 40, required: true, default: "Brand" },
1442
+ { key: "logo", kind: "image", label: "Logo (optional)", default: null }
1443
+ ],
1444
+ default: [{ name: "Brand" }]
1445
+ },
1446
+ tone()
1447
+ ]
1448
+ },
1449
+ newsletter: {
1450
+ label: "Newsletter sign-up",
1451
+ description: "Email sign-up with consent; the app decides where it goes.",
1452
+ fields: [
1453
+ { key: "title", kind: "text", label: "Heading", max: 90, required: true, default: "Get new arrivals first" },
1454
+ { key: "text", kind: "textarea", label: "Text", max: 200, default: "" },
1455
+ { key: "button_label", kind: "text", label: "Button text", max: 30, required: true, default: "Subscribe" },
1456
+ { key: "consent_text", kind: "text", label: "Consent line", max: 160, required: true, default: "I agree to receive emails from this store. I can unsubscribe any time." },
1457
+ { key: "success_text", kind: "text", label: "Thank-you message", max: 120, default: "Thanks! You are on the list." },
1458
+ tone("tinted")
1459
+ ]
1460
+ },
1461
+ gallery: {
1462
+ label: "Gallery",
1463
+ description: "Photos of your store, workshop or products.",
1464
+ fields: [
1465
+ title("Inside our store"),
1466
+ {
1467
+ key: "items",
1468
+ kind: "list",
1469
+ label: "Photos",
1470
+ min: 1,
1471
+ max: 12,
1472
+ itemLabel: "caption",
1473
+ of: [
1474
+ { key: "image", kind: "image", label: "Photo", required: true, default: null },
1475
+ { key: "caption", kind: "text", label: "Caption", max: 100, default: "" }
1476
+ ],
1477
+ default: []
1478
+ },
1479
+ { key: "columns", kind: "select", label: "Columns", options: [{ value: "2", label: "2" }, { value: "3", label: "3" }, { value: "4", label: "4" }], default: "3" },
1480
+ tone()
1481
+ ]
1482
+ }
1483
+ };
1484
+ var SECTION_TYPE_KEYS = Object.keys(SECTION_TYPES);
1485
+ var PAGE_VERSION = 1;
1486
+ var MAX_SECTIONS = 20;
1487
+
1488
+ // src/schema/richtext.js
1489
+ var ALLOWED = /* @__PURE__ */ new Set(["p", "br", "h2", "h3", "h4", "strong", "b", "em", "i", "u", "ul", "ol", "li", "a", "blockquote"]);
1490
+ var VOID = /* @__PURE__ */ new Set(["br"]);
1491
+ var DROP_WITH_CONTENT = /<(script|style|iframe|object|embed|template|noscript|svg|math|textarea|select|title|head)\b[\s\S]*?<\/\1\s*>/gi;
1492
+ var TAG = /<!--[\s\S]*?-->|<\/?([a-zA-Z][a-zA-Z0-9]*)\b([^>]*)>/g;
1493
+ var escapeText = (s) => s.replace(/&(?!(?:[a-z][a-z0-9]{1,31}|#\d{1,7}|#x[0-9a-f]{1,6});)/gi, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1494
+ var escapeAttr = (s) => s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1495
+ var decode = (s) => s.replace(/&(amp|quot|#39|lt|gt|#x[0-9a-f]+|#\d+);/gi, (m, e) => {
1496
+ const k = e.toLowerCase();
1497
+ if (k === "amp") return "&";
1498
+ if (k === "quot") return '"';
1499
+ if (k === "#39") return "'";
1500
+ if (k === "lt") return "<";
1501
+ if (k === "gt") return ">";
1502
+ const code = k.startsWith("#x") ? parseInt(k.slice(2), 16) : parseInt(k.slice(1), 10);
1503
+ return Number.isFinite(code) && code < 1114112 ? String.fromCodePoint(code) : "";
1504
+ });
1505
+ function safeHref(raw) {
1506
+ const v = decode(String(raw || "")).replace(/[\u0000- \u007f-\u009f]/g, "");
1507
+ if (!v) return null;
1508
+ if (/^(https?:\/\/|mailto:|tel:)/i.test(v)) return v;
1509
+ if (/^\/(?!\/)/.test(v) || v.startsWith("#")) return v;
1510
+ return null;
1511
+ }
1512
+ function hrefOf(attrs) {
1513
+ var _a, _b;
1514
+ const m = /\bhref\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+))/i.exec(attrs);
1515
+ return m ? safeHref((_b = (_a = m[1]) != null ? _a : m[2]) != null ? _b : m[3]) : null;
1516
+ }
1517
+ function sanitizeRichText(html, { maxLength = 2e4 } = {}) {
1518
+ const src = String(html == null ? "" : html).slice(0, maxLength * 4).replace(/<[a-zA-Z/!][^>]*$/, "").replace(DROP_WITH_CONTENT, "");
1519
+ let out = "";
1520
+ let last = 0;
1521
+ for (const m of src.matchAll(TAG)) {
1522
+ out += escapeText(src.slice(last, m.index));
1523
+ last = m.index + m[0].length;
1524
+ const name = (m[1] || "").toLowerCase();
1525
+ if (!name || !ALLOWED.has(name)) continue;
1526
+ const closing = m[0][1] === "/";
1527
+ if (closing) {
1528
+ if (!VOID.has(name)) out += `</${name}>`;
1529
+ } else if (name === "a") {
1530
+ const href = hrefOf(m[2] || "");
1531
+ out += href ? `<a href="${escapeAttr(href)}" rel="nofollow noopener noreferrer">` : "<a>";
1532
+ } else {
1533
+ out += `<${name}>`;
1534
+ }
1535
+ }
1536
+ out += escapeText(src.slice(last));
1537
+ return out.length > maxLength ? out.slice(0, maxLength).replace(/<[^>]*$/, "") : out;
1538
+ }
1539
+
1540
+ // src/schema/validate.js
1541
+ var ID_RE = /^[a-z0-9][a-z0-9-]{0,39}$/;
1542
+ var MEDIA_RE = /^[A-Za-z0-9_-]{1,64}$/;
1543
+ var CONTROL = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g;
1544
+ function field(f, value, path, errors) {
1545
+ var _a, _b, _c, _d;
1546
+ const absent = value === void 0 || value === null;
1547
+ const missing = absent || value === "";
1548
+ switch (f.kind) {
1549
+ case "text":
1550
+ case "textarea": {
1551
+ let v = absent ? (_a = f.default) != null ? _a : "" : value;
1552
+ if (typeof v !== "string") {
1553
+ errors.push({ path, message: "must be text" });
1554
+ return (_b = f.default) != null ? _b : "";
1555
+ }
1556
+ v = v.replace(CONTROL, "");
1557
+ v = f.kind === "text" ? v.replace(/\s+/g, " ").trim() : v.trim();
1558
+ if (f.max && v.length > f.max) errors.push({ path, message: `must be at most ${f.max} characters` });
1559
+ if (f.required && !v) errors.push({ path, message: "is required" });
1560
+ return v.slice(0, f.max || v.length);
1561
+ }
1562
+ case "url": {
1563
+ if (missing) {
1564
+ if (f.required) errors.push({ path, message: "is required" });
1565
+ return "";
1566
+ }
1567
+ const v = typeof value === "string" ? safeHref(value.trim()) : null;
1568
+ if (!v || v.length > 500) {
1569
+ errors.push({ path, message: "must be a page on this site (/\u2026), a full https:// address, mailto: or tel:" });
1570
+ return "";
1571
+ }
1572
+ return v;
1573
+ }
1574
+ case "image": {
1575
+ if (missing) {
1576
+ if (f.required) errors.push({ path, message: "is required" });
1577
+ return null;
1578
+ }
1579
+ if (typeof value !== "object" || !MEDIA_RE.test(String((_c = value.media_id) != null ? _c : ""))) {
1580
+ errors.push({ path, message: "must be an uploaded image" });
1581
+ return null;
1582
+ }
1583
+ return { media_id: typeof value.media_id === "number" ? value.media_id : String(value.media_id), alt: String((_d = value.alt) != null ? _d : "").replace(CONTROL, "").slice(0, 120) };
1584
+ }
1585
+ case "icon": {
1586
+ const v = absent ? f.default : value;
1587
+ if (!ICON_NAMES.includes(v)) {
1588
+ errors.push({ path, message: `must be one of the icon names (${ICON_NAMES.slice(0, 4).join(", ")}\u2026)` });
1589
+ return f.default;
1590
+ }
1591
+ return v;
1592
+ }
1593
+ case "select": {
1594
+ const v = missing ? f.default : String(value);
1595
+ if (!f.options.some((o) => o.value === v)) {
1596
+ errors.push({ path, message: `must be one of ${f.options.map((o) => o.value).join(", ")}` });
1597
+ return f.default;
1598
+ }
1599
+ return v;
1600
+ }
1601
+ case "bool":
1602
+ if (missing) return f.default;
1603
+ if (typeof value !== "boolean") {
1604
+ errors.push({ path, message: "must be true or false" });
1605
+ return f.default;
1606
+ }
1607
+ return value;
1608
+ case "richtext": {
1609
+ const raw = absent ? f.default : value;
1610
+ if (typeof raw !== "string") {
1611
+ errors.push({ path, message: "must be text" });
1612
+ return f.default;
1613
+ }
1614
+ if (f.max && raw.length > f.max * 2) errors.push({ path, message: `must be at most ${f.max} characters` });
1615
+ return sanitizeRichText(raw, { maxLength: f.max });
1616
+ }
1617
+ case "list": {
1618
+ const arr = absent ? f.default || [] : value;
1619
+ if (!Array.isArray(arr)) {
1620
+ errors.push({ path, message: "must be a list" });
1621
+ return [];
1622
+ }
1623
+ if (f.min && arr.length < f.min) errors.push({ path, message: `needs at least ${f.min}` });
1624
+ if (f.max && arr.length > f.max) errors.push({ path, message: `can have at most ${f.max}` });
1625
+ return arr.slice(0, f.max || arr.length).map((item, i) => fields(f.of, item, `${path}[${i}]`, errors));
1626
+ }
1627
+ default:
1628
+ throw new Error(`Unknown field kind "${f.kind}" (${path})`);
1629
+ }
1630
+ }
1631
+ function fields(defs, obj, path, errors) {
1632
+ const src = obj && typeof obj === "object" && !Array.isArray(obj) ? obj : {};
1633
+ if (obj != null && src !== obj) errors.push({ path, message: "must be an object" });
1634
+ return Object.fromEntries(defs.map((f) => [f.key, field(f, Object.prototype.hasOwnProperty.call(src, f.key) ? src[f.key] : void 0, `${path}.${f.key}`, errors)]));
1635
+ }
1636
+ function validatePage(input) {
1637
+ const errors = [];
1638
+ const doc = input && typeof input === "object" && !Array.isArray(input) ? input : null;
1639
+ if (!doc) return { ok: false, errors: [{ path: "page", message: "must be an object" }], page: { version: PAGE_VERSION, sections: [] } };
1640
+ if (doc.version != null && doc.version !== PAGE_VERSION) errors.push({ path: "version", message: `must be ${PAGE_VERSION}` });
1641
+ const list = Array.isArray(doc.sections) ? doc.sections : [];
1642
+ if (!Array.isArray(doc.sections)) errors.push({ path: "sections", message: "must be a list" });
1643
+ if (list.length > MAX_SECTIONS) errors.push({ path: "sections", message: `can have at most ${MAX_SECTIONS}` });
1644
+ const seen = /* @__PURE__ */ new Set();
1645
+ const sections = [];
1646
+ list.slice(0, MAX_SECTIONS).forEach((s, i) => {
1647
+ var _a, _b;
1648
+ const path = `sections[${i}]`;
1649
+ if (!s || typeof s !== "object") {
1650
+ errors.push({ path, message: "must be an object" });
1651
+ return;
1652
+ }
1653
+ const def = SECTION_TYPES[s.type];
1654
+ if (!def) {
1655
+ errors.push({ path: `${path}.type`, message: `unknown section type "${s.type}"` });
1656
+ return;
1657
+ }
1658
+ const id = String((_a = s.id) != null ? _a : "");
1659
+ if (!ID_RE.test(id)) errors.push({ path: `${path}.id`, message: "must be 1\u201340 lowercase letters, digits or dashes" });
1660
+ else if (seen.has(id)) errors.push({ path: `${path}.id`, message: `duplicate id "${id}"` });
1661
+ seen.add(id);
1662
+ const enabled = s.enabled === void 0 ? true : s.enabled;
1663
+ if (typeof enabled !== "boolean") errors.push({ path: `${path}.enabled`, message: "must be true or false" });
1664
+ sections.push({ id, type: s.type, enabled: enabled !== false, props: fields(def.fields, (_b = s.props) != null ? _b : {}, `${path}.props`, errors) });
1665
+ });
1666
+ return { ok: errors.length === 0, errors, page: { version: PAGE_VERSION, sections } };
1667
+ }
1668
+
1669
+ // src/schema/color.js
1670
+ var HEX_RE = /^#([0-9a-f]{6})$/i;
1671
+ var isHex = (v) => typeof v === "string" && HEX_RE.test(v);
1672
+ function hexToRgb(hex) {
1673
+ const m = HEX_RE.exec(String(hex || ""));
1674
+ if (!m) throw new Error(`Not a #rrggbb colour: ${hex}`);
1675
+ const n = parseInt(m[1], 16);
1676
+ return [n >> 16 & 255, n >> 8 & 255, n & 255];
1677
+ }
1678
+ function rgbToHex([r, g, b]) {
1679
+ const c = (x) => Math.round(Math.min(255, Math.max(0, x))).toString(16).padStart(2, "0");
1680
+ return `#${c(r)}${c(g)}${c(b)}`;
1681
+ }
1682
+ var toLinear = (c) => {
1683
+ const x = c / 255;
1684
+ return x <= 0.04045 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4;
1685
+ };
1686
+ var fromLinear = (x) => 255 * (x <= 31308e-7 ? 12.92 * x : 1.055 * x ** (1 / 2.4) - 0.055);
1687
+ function hexToOklch(hex) {
1688
+ const [r, g, b] = hexToRgb(hex).map(toLinear);
1689
+ const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
1690
+ const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
1691
+ const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
1692
+ const L = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s;
1693
+ const A = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s;
1694
+ const B = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s;
1695
+ return { l: L, c: Math.hypot(A, B), h: Math.atan2(B, A) * 180 / Math.PI };
1696
+ }
1697
+ function oklchToLinear({ l, c, h }) {
1698
+ const a = c * Math.cos(h * Math.PI / 180);
1699
+ const b = c * Math.sin(h * Math.PI / 180);
1700
+ const l_ = (l + 0.3963377774 * a + 0.2158037573 * b) ** 3;
1701
+ const m_ = (l - 0.1055613458 * a - 0.0638541728 * b) ** 3;
1702
+ const s_ = (l - 0.0894841775 * a - 1.291485548 * b) ** 3;
1703
+ return [
1704
+ 4.0767416621 * l_ - 3.3077115913 * m_ + 0.2309699292 * s_,
1705
+ -1.2684380046 * l_ + 2.6097574011 * m_ - 0.3413193965 * s_,
1706
+ -0.0041960863 * l_ - 0.7034186147 * m_ + 1.707614701 * s_
1707
+ ];
1708
+ }
1709
+ var inGamut = (rgb) => rgb.every((x) => x >= -1e-4 && x <= 1 + 1e-4);
1710
+ function oklchToHex({ l, c, h }) {
1711
+ let lo = 0;
1712
+ let hi = c;
1713
+ let rgb = oklchToLinear({ l, c, h });
1714
+ if (!inGamut(rgb)) {
1715
+ for (let i = 0; i < 24; i += 1) {
1716
+ const mid = (lo + hi) / 2;
1717
+ if (inGamut(oklchToLinear({ l, c: mid, h }))) lo = mid;
1718
+ else hi = mid;
1719
+ }
1720
+ rgb = oklchToLinear({ l, c: lo, h });
1721
+ }
1722
+ return rgbToHex(rgb.map((x) => fromLinear(Math.min(1, Math.max(0, x)))));
1723
+ }
1724
+ var PALETTE_STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
1725
+ var LIGHTNESS = { 50: 0.975, 100: 0.945, 200: 0.89, 300: 0.81, 400: 0.71, 500: 0.62, 700: 0.46, 800: 0.39, 900: 0.32, 950: 0.24 };
1726
+ var CHROMA = { 50: 0.18, 100: 0.32, 200: 0.55, 300: 0.78, 400: 0.92, 500: 1, 700: 0.92, 800: 0.82, 900: 0.7, 950: 0.58 };
1727
+ function brandPalette(hex) {
1728
+ const base3 = hexToOklch(hex);
1729
+ const out = { 600: rgbToHex(hexToRgb(hex)) };
1730
+ for (const step of PALETTE_STEPS) {
1731
+ if (step === 600) continue;
1732
+ const l = step < 600 ? Math.max(LIGHTNESS[step], Math.min(0.985, base3.l + (0.985 - base3.l) * ((600 - step) / 600))) : Math.min(LIGHTNESS[step], Math.max(0.12, base3.l - base3.l * 0.6 * ((step - 600) / 350)));
1733
+ out[step] = oklchToHex({ l, c: base3.c * CHROMA[step], h: base3.h });
1734
+ }
1735
+ return Object.fromEntries(PALETTE_STEPS.map((s) => [s, out[s]]));
1736
+ }
1737
+ function luminance(hex) {
1738
+ const [r, g, b] = hexToRgb(hex).map(toLinear);
1739
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
1740
+ }
1741
+ function contrastRatio(a, b) {
1742
+ const [x, y] = [luminance(a), luminance(b)].sort((p, q) => q - p);
1743
+ return (x + 0.05) / (y + 0.05);
1744
+ }
1745
+ function readableOn(hex) {
1746
+ return contrastRatio(hex, "#ffffff") >= contrastRatio(hex, "#101828") ? "#ffffff" : "#101828";
1747
+ }
1748
+
1749
+ // src/schema/theme.js
1750
+ var FONT_PAIRS = {
1751
+ system: { label: "System (fastest)", heading: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif", body: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif", href: null },
1752
+ inter: { label: "Inter", heading: "Inter, ui-sans-serif, system-ui, sans-serif", body: "Inter, ui-sans-serif, system-ui, sans-serif", href: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" },
1753
+ poppins: { label: "Poppins + Inter", heading: "Poppins, ui-sans-serif, system-ui, sans-serif", body: "Inter, ui-sans-serif, system-ui, sans-serif", href: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Poppins:wght@600;700&display=swap" },
1754
+ dmsans: { label: "DM Sans", heading: "'DM Sans', ui-sans-serif, system-ui, sans-serif", body: "'DM Sans', ui-sans-serif, system-ui, sans-serif", href: "https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&display=swap" },
1755
+ nunito: { label: "Nunito (rounded)", heading: "Nunito, ui-rounded, ui-sans-serif, system-ui, sans-serif", body: "Nunito, ui-rounded, ui-sans-serif, system-ui, sans-serif", href: "https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;800&display=swap" },
1756
+ serif: { label: "Merriweather + Source Sans", heading: "Merriweather, Georgia, 'Times New Roman', serif", body: "'Source Sans 3', ui-sans-serif, system-ui, sans-serif", href: "https://fonts.googleapis.com/css2?family=Merriweather:wght@700&family=Source+Sans+3:wght@400;600&display=swap" }
1757
+ };
1758
+ var RADII = { none: ["0", "0"], sm: ["0.375rem", "0.5rem"], md: ["0.75rem", "1rem"], lg: ["1rem", "1.5rem"], full: ["1.5rem", "2rem"] };
1759
+ var MODES = ["light", "dark", "auto"];
1760
+ var THEME_PRESETS = {
1761
+ classic: { label: "Classic blue", primary: "#2563eb", accent: "#f59e0b", font: "inter", radius: "md", mode: "light" },
1762
+ forest: { label: "Forest", primary: "#15803d", accent: "#ca8a04", font: "dmsans", radius: "lg", mode: "light" },
1763
+ sunset: { label: "Sunset", primary: "#c2410c", accent: "#0369a1", font: "poppins", radius: "md", mode: "light" },
1764
+ midnight: { label: "Midnight", primary: "#4338ca", accent: "#0891b2", font: "inter", radius: "lg", mode: "dark" },
1765
+ slate: { label: "Minimal slate", primary: "#334155", accent: "#0f766e", font: "system", radius: "sm", mode: "light" },
1766
+ berry: { label: "Berry", primary: "#be185d", accent: "#6d28d9", font: "nunito", radius: "full", mode: "light" }
1767
+ };
1768
+ var { label: _classicLabel, ...classic } = THEME_PRESETS.classic;
1769
+ var DEFAULT_THEME = { preset: "classic", ...classic, logo: null, favicon: null };
1770
+ var mediaRef = (v, path, errors, { alt = false } = {}) => {
1771
+ if (v == null || v === "") return null;
1772
+ if (typeof v !== "object" || v.media_id == null || !/^[A-Za-z0-9_-]{1,64}$/.test(String(v.media_id))) {
1773
+ errors.push({ path, message: "must be an uploaded image" });
1774
+ return null;
1775
+ }
1776
+ const ref = { media_id: typeof v.media_id === "number" ? v.media_id : String(v.media_id) };
1777
+ if (alt) ref.alt = String(v.alt == null ? "" : v.alt).slice(0, 120);
1778
+ return ref;
1779
+ };
1780
+ function validateTheme(input) {
1781
+ const errors = [];
1782
+ const warnings = [];
1783
+ const t = input && typeof input === "object" && !Array.isArray(input) ? input : {};
1784
+ if (input != null && t !== input) errors.push({ path: "theme", message: "must be an object" });
1785
+ const preset = t.preset == null || t.preset === "" ? null : String(t.preset);
1786
+ if (preset && !THEME_PRESETS[preset] && preset !== "custom") errors.push({ path: "preset", message: `must be one of ${Object.keys(THEME_PRESETS).join(", ")} or custom` });
1787
+ const base3 = preset && THEME_PRESETS[preset] || THEME_PRESETS.classic;
1788
+ const color = (key) => {
1789
+ const v = t[key] == null || t[key] === "" ? base3[key] : String(t[key]).toLowerCase();
1790
+ if (!isHex(v)) {
1791
+ errors.push({ path: key, message: "must be a colour like #2563eb" });
1792
+ return base3[key];
1793
+ }
1794
+ return v;
1795
+ };
1796
+ const pick = (key, allowed, fallback) => {
1797
+ const v = t[key] == null || t[key] === "" ? fallback : String(t[key]);
1798
+ if (!allowed.includes(v)) {
1799
+ errors.push({ path: key, message: `must be one of ${allowed.join(", ")}` });
1800
+ return fallback;
1801
+ }
1802
+ return v;
1803
+ };
1804
+ const theme = {
1805
+ preset: preset || "classic",
1806
+ primary: color("primary"),
1807
+ accent: color("accent"),
1808
+ font: pick("font", Object.keys(FONT_PAIRS), base3.font),
1809
+ radius: pick("radius", Object.keys(RADII), base3.radius),
1810
+ mode: pick("mode", MODES, base3.mode),
1811
+ logo: mediaRef(t.logo, "logo", errors, { alt: true }),
1812
+ favicon: mediaRef(t.favicon, "favicon", errors)
1813
+ };
1814
+ const onBrand = contrastRatio(theme.primary, readableOn(theme.primary));
1815
+ if (onBrand < 4.5) warnings.push({ path: "primary", message: `Button text on this colour is hard to read (contrast ${onBrand.toFixed(1)}:1, needs 4.5:1).` });
1816
+ const onPage = contrastRatio(theme.primary, "#ffffff");
1817
+ if (onPage < 3) warnings.push({ path: "primary", message: `Links in this colour are hard to see on white (contrast ${onPage.toFixed(1)}:1, needs 3:1).` });
1818
+ const accentText = contrastRatio(theme.accent, readableOn(theme.accent));
1819
+ if (accentText < 4.5) warnings.push({ path: "accent", message: `Text on the accent colour is hard to read (contrast ${accentText.toFixed(1)}:1, needs 4.5:1).` });
1820
+ return { ok: errors.length === 0, errors, warnings, theme };
1821
+ }
1822
+ function themeVars(input) {
1823
+ const { theme } = validateTheme(input);
1824
+ const font = FONT_PAIRS[theme.font];
1825
+ const [radius, radiusLg] = RADII[theme.radius];
1826
+ return {
1827
+ theme,
1828
+ font,
1829
+ palette: { primary: brandPalette(theme.primary), accent: brandPalette(theme.accent) },
1830
+ style: {
1831
+ "--dt-brand": theme.primary,
1832
+ "--dt-brand-accent": theme.accent,
1833
+ "--dt-brand-contrast": readableOn(theme.primary),
1834
+ "--dt-brand-accent-contrast": readableOn(theme.accent),
1835
+ "--dt-lp-font": font.body,
1836
+ "--dt-lp-font-heading": font.heading,
1837
+ "--dt-lp-radius": radius,
1838
+ "--dt-lp-radius-lg": radiusLg
1839
+ }
1840
+ };
1841
+ }
1842
+
1843
+ // src/tenant/HeroSlider.jsx
1844
+ import { useCallback as useCallback2, useEffect as useEffect3, useRef as useRef4, useState as useState5 } from "react";
1845
+
1846
+ // src/tenant/icons.jsx
1847
+ import { Fragment as Fragment6, jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
1848
+ var base2 = {
1849
+ viewBox: "0 0 24 24",
1850
+ fill: "none",
1851
+ stroke: "currentColor",
1852
+ strokeWidth: 1.8,
1853
+ strokeLinecap: "round",
1854
+ strokeLinejoin: "round",
1855
+ "aria-hidden": "true",
1856
+ focusable: "false"
1857
+ };
1858
+ var PATHS = {
1859
+ "shield-check": /* @__PURE__ */ jsxs19(Fragment6, { children: [
1860
+ /* @__PURE__ */ jsx22("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z" }),
1861
+ /* @__PURE__ */ jsx22("path", { d: "m9 12 2 2 4-4" })
1862
+ ] }),
1863
+ "badge-check": /* @__PURE__ */ jsxs19(Fragment6, { children: [
1864
+ /* @__PURE__ */ jsx22("path", { d: "M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z" }),
1865
+ /* @__PURE__ */ jsx22("path", { d: "m9 12 2 2 4-4" })
1866
+ ] }),
1867
+ truck: /* @__PURE__ */ jsxs19(Fragment6, { children: [
1868
+ /* @__PURE__ */ jsx22("path", { d: "M14 18V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v11a1 1 0 0 0 1 1h2" }),
1869
+ /* @__PURE__ */ jsx22("path", { d: "M15 18H9" }),
1870
+ /* @__PURE__ */ jsx22("path", { d: "M19 18h2a1 1 0 0 0 1-1v-3.65a1 1 0 0 0-.22-.62L18.3 9.38a1 1 0 0 0-.78-.38H14" }),
1871
+ /* @__PURE__ */ jsx22("circle", { cx: "17", cy: "18", r: "2" }),
1872
+ /* @__PURE__ */ jsx22("circle", { cx: "7", cy: "18", r: "2" })
1873
+ ] }),
1874
+ wrench: /* @__PURE__ */ jsx22("path", { d: "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" }),
1875
+ refresh: /* @__PURE__ */ jsxs19(Fragment6, { children: [
1876
+ /* @__PURE__ */ jsx22("path", { d: "M3 12a9 9 0 0 1 15-6.7L21 8" }),
1877
+ /* @__PURE__ */ jsx22("path", { d: "M21 3v5h-5" }),
1878
+ /* @__PURE__ */ jsx22("path", { d: "M21 12a9 9 0 0 1-15 6.7L3 16" }),
1879
+ /* @__PURE__ */ jsx22("path", { d: "M8 16H3v5" })
1880
+ ] }),
1881
+ battery: /* @__PURE__ */ jsxs19(Fragment6, { children: [
1882
+ /* @__PURE__ */ jsx22("rect", { x: "2", y: "7", width: "16", height: "10", rx: "2" }),
1883
+ /* @__PURE__ */ jsx22("path", { d: "M22 11v2M6 11v2M10 11v2" })
1884
+ ] }),
1885
+ cpu: /* @__PURE__ */ jsxs19(Fragment6, { children: [
1886
+ /* @__PURE__ */ jsx22("rect", { x: "4", y: "4", width: "16", height: "16", rx: "2" }),
1887
+ /* @__PURE__ */ jsx22("rect", { x: "9", y: "9", width: "6", height: "6" }),
1888
+ /* @__PURE__ */ jsx22("path", { d: "M15 2v2M15 20v2M2 15h2M2 9h2M20 15h2M20 9h2M9 2v2M9 20v2" })
1889
+ ] }),
1890
+ laptop: /* @__PURE__ */ jsx22("path", { d: "M20 16V7a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v9m16 0H4m16 0 1.28 2.55a1 1 0 0 1-.9 1.45H3.62a1 1 0 0 1-.9-1.45L4 16" }),
1891
+ star: /* @__PURE__ */ jsx22("path", { d: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" }),
1892
+ headset: /* @__PURE__ */ jsx22("path", { d: "M3 14h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-7a9 9 0 0 1 18 0v7a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3" }),
1893
+ rupee: /* @__PURE__ */ jsx22("path", { d: "M6 3h12M6 8h12M6 13l8.5 8M6 13h3M9 13c6.67 0 6.67-10 0-10" }),
1894
+ award: /* @__PURE__ */ jsxs19(Fragment6, { children: [
1895
+ /* @__PURE__ */ jsx22("circle", { cx: "12", cy: "8", r: "6" }),
1896
+ /* @__PURE__ */ jsx22("path", { d: "M15.48 12.89 17 22l-5-3-5 3 1.52-9.11" })
1897
+ ] }),
1898
+ clock: /* @__PURE__ */ jsxs19(Fragment6, { children: [
1899
+ /* @__PURE__ */ jsx22("circle", { cx: "12", cy: "12", r: "10" }),
1900
+ /* @__PURE__ */ jsx22("path", { d: "M12 6v6l4 2" })
1901
+ ] }),
1902
+ "map-pin": /* @__PURE__ */ jsxs19(Fragment6, { children: [
1903
+ /* @__PURE__ */ jsx22("path", { d: "M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" }),
1904
+ /* @__PURE__ */ jsx22("circle", { cx: "12", cy: "10", r: "3" })
1905
+ ] }),
1906
+ phone: /* @__PURE__ */ jsx22("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" }),
1907
+ check: /* @__PURE__ */ jsx22("path", { d: "M20 6 9 17l-5-5" }),
1908
+ sparkles: /* @__PURE__ */ jsxs19(Fragment6, { children: [
1909
+ /* @__PURE__ */ jsx22("path", { d: "M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9L12 3z" }),
1910
+ /* @__PURE__ */ jsx22("path", { d: "M5 3v4M3 5h4M19 17v4M17 19h4" })
1911
+ ] }),
1912
+ tag: /* @__PURE__ */ jsxs19(Fragment6, { children: [
1913
+ /* @__PURE__ */ jsx22("path", { d: "M12.59 2.59A2 2 0 0 0 11.17 2H4a2 2 0 0 0-2 2v7.17a2 2 0 0 0 .59 1.42l8.7 8.7a2.43 2.43 0 0 0 3.42 0l6.58-6.58a2.43 2.43 0 0 0 0-3.42z" }),
1914
+ /* @__PURE__ */ jsx22("circle", { cx: "7.5", cy: "7.5", r: "1.5" })
1915
+ ] }),
1916
+ gift: /* @__PURE__ */ jsxs19(Fragment6, { children: [
1917
+ /* @__PURE__ */ jsx22("rect", { x: "3", y: "8", width: "18", height: "4", rx: "1" }),
1918
+ /* @__PURE__ */ jsx22("path", { d: "M12 8v13M19 12v7a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-7" }),
1919
+ /* @__PURE__ */ jsx22("path", { d: "M7.5 8a2.5 2.5 0 0 1 0-5C10 3 12 8 12 8s2-5 4.5-5a2.5 2.5 0 0 1 0 5" })
1920
+ ] }),
1921
+ heart: /* @__PURE__ */ jsx22("path", { d: "M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z" }),
1922
+ // Controls (not offered to content).
1923
+ "chevron-left": /* @__PURE__ */ jsx22("path", { d: "m15 18-6-6 6-6" }),
1924
+ "chevron-right": /* @__PURE__ */ jsx22("path", { d: "m9 18 6-6-6-6" }),
1925
+ pause: /* @__PURE__ */ jsx22("path", { d: "M8 5v14M16 5v14" }),
1926
+ play: /* @__PURE__ */ jsx22("path", { d: "M7 4.5v15l12-7.5-12-7.5Z" })
1927
+ };
1928
+ function NamedIcon({ name, size = 20, className = "dt-lp-icon" }) {
1929
+ const paths = PATHS[name];
1930
+ if (!paths) return null;
1931
+ return /* @__PURE__ */ jsx22("svg", { ...base2, width: size, height: size, className, children: paths });
1932
+ }
1933
+
1934
+ // src/tenant/HeroSlider.jsx
1935
+ import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
1936
+ var reducedMotion = () => typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
1937
+ function Slide({ slide, index, count, active, headingTag: H, media, eager }) {
1938
+ const wide = media(slide.image, "wide");
1939
+ const narrow = media(slide.mobile_image, "narrow");
1940
+ return /* @__PURE__ */ jsxs20(
1941
+ "div",
1942
+ {
1943
+ className: `dt-lp-slide dt-lp-slide--${slide.align} dt-lp-slide--overlay-${wide || narrow ? slide.overlay : "none"}${wide || narrow ? " dt-lp-slide--image" : ""}`,
1944
+ role: "group",
1945
+ "aria-roledescription": "slide",
1946
+ "aria-label": `${index + 1} of ${count}`,
1947
+ "aria-hidden": active ? void 0 : "true",
1948
+ "data-active": active ? "" : void 0,
1949
+ children: [
1950
+ wide || narrow ? /* @__PURE__ */ jsxs20("picture", { className: "dt-lp-slide-media", children: [
1951
+ narrow && wide ? /* @__PURE__ */ jsx23("source", { media: "(max-width: 640px)", srcSet: narrow }) : null,
1952
+ /* @__PURE__ */ jsx23("img", { src: wide || narrow, alt: slide.image && slide.image.alt || "", loading: eager ? "eager" : "lazy", decoding: "async" })
1953
+ ] }) : null,
1954
+ /* @__PURE__ */ jsx23("div", { className: "dt-lp-wrap dt-lp-slide-body", children: /* @__PURE__ */ jsxs20("div", { className: "dt-lp-slide-copy", children: [
1955
+ slide.eyebrow ? /* @__PURE__ */ jsx23("p", { className: "dt-lp-eyebrow dt-lp-slide-eyebrow", children: slide.eyebrow }) : null,
1956
+ /* @__PURE__ */ jsx23(H, { className: "dt-lp-slide-heading", children: slide.heading }),
1957
+ slide.text ? /* @__PURE__ */ jsx23("p", { className: "dt-lp-slide-text", children: slide.text }) : null,
1958
+ slide.cta_label && slide.cta_href ? /* @__PURE__ */ jsx23(SmartLink, { href: slide.cta_href, className: "dt-lp-btn dt-lp-btn--lg dt-lp-btn--primary dt-lp-slide-cta", tabIndex: active ? void 0 : -1, children: slide.cta_label }) : null
1959
+ ] }) })
1960
+ ]
1961
+ }
1962
+ );
1963
+ }
1964
+ function HeroSlider({ id, slides = [], height = "standard", autoplay = true, interval = "6", first = false, media }) {
1965
+ const count = slides.length;
1966
+ const [index, setIndex] = useState5(0);
1967
+ const [playing, setPlaying] = useState5(false);
1968
+ const [hold, setHold] = useState5(false);
1969
+ const touch = useRef4(null);
1970
+ const go = useCallback2((i) => setIndex((i % count + count) % count), [count]);
1971
+ useEffect3(() => {
1972
+ setPlaying(Boolean(autoplay) && count > 1 && !reducedMotion());
1973
+ }, [autoplay, count]);
1974
+ useEffect3(() => {
1975
+ if (!playing || hold || count < 2) return void 0;
1976
+ const t = setTimeout(() => go(index + 1), Math.max(3, Number(interval) || 6) * 1e3);
1977
+ return () => clearTimeout(t);
1978
+ }, [playing, hold, index, interval, count, go]);
1979
+ useEffect3(() => {
1980
+ if (index >= count) setIndex(0);
1981
+ }, [count, index]);
1982
+ if (!count) return null;
1983
+ const onKey = (e) => {
1984
+ if (e.key === "ArrowRight") {
1985
+ e.preventDefault();
1986
+ go(index + 1);
1987
+ }
1988
+ if (e.key === "ArrowLeft") {
1989
+ e.preventDefault();
1990
+ go(index - 1);
1991
+ }
1992
+ };
1993
+ const onTouchStart = (e) => {
1994
+ touch.current = e.touches[0].clientX;
1995
+ };
1996
+ const onTouchEnd = (e) => {
1997
+ if (touch.current == null) return;
1998
+ const dx = e.changedTouches[0].clientX - touch.current;
1999
+ touch.current = null;
2000
+ if (Math.abs(dx) > 40) go(index + (dx < 0 ? 1 : -1));
2001
+ };
2002
+ return /* @__PURE__ */ jsxs20(
2003
+ "section",
2004
+ {
2005
+ id,
2006
+ className: `dt-lp-hero-slider dt-lp-hero-slider--${height}`,
2007
+ "aria-roledescription": "carousel",
2008
+ "aria-label": "Highlights",
2009
+ onKeyDown: onKey,
2010
+ onMouseEnter: () => setHold(true),
2011
+ onMouseLeave: () => setHold(false),
2012
+ onFocus: () => setHold(true),
2013
+ onBlur: () => setHold(false),
2014
+ onTouchStart,
2015
+ onTouchEnd,
2016
+ children: [
2017
+ /* @__PURE__ */ jsx23("div", { className: "dt-lp-slides", "aria-live": playing && !hold ? "off" : "polite", children: slides.map((s, i) => /* @__PURE__ */ jsx23(Slide, { slide: s, index: i, count, active: i === index, eager: i === 0, headingTag: first && i === 0 ? "h1" : "h2", media }, i)) }),
2018
+ count > 1 ? /* @__PURE__ */ jsxs20("div", { className: "dt-lp-slider-controls", children: [
2019
+ /* @__PURE__ */ jsx23("button", { type: "button", className: "dt-lp-slider-btn", "aria-label": "Previous slide", onClick: () => go(index - 1), children: /* @__PURE__ */ jsx23(NamedIcon, { name: "chevron-left", size: 20 }) }),
2020
+ /* @__PURE__ */ jsx23("div", { className: "dt-lp-slider-dots", children: slides.map((s, i) => /* @__PURE__ */ jsx23("button", { type: "button", className: "dt-lp-slider-dot", "aria-label": `Go to slide ${i + 1}`, "aria-current": i === index ? "true" : void 0, onClick: () => go(i) }, i)) }),
2021
+ /* @__PURE__ */ jsx23("button", { type: "button", className: "dt-lp-slider-btn", "aria-label": "Next slide", onClick: () => go(index + 1), children: /* @__PURE__ */ jsx23(NamedIcon, { name: "chevron-right", size: 20 }) }),
2022
+ autoplay ? /* @__PURE__ */ jsx23("button", { type: "button", className: "dt-lp-slider-btn", "aria-label": playing ? "Pause slides" : "Play slides", onClick: () => setPlaying((p) => !p), children: /* @__PURE__ */ jsx23(NamedIcon, { name: playing ? "pause" : "play", size: 18 }) }) : null
2023
+ ] }) : null
2024
+ ]
2025
+ }
2026
+ );
2027
+ }
2028
+
2029
+ // src/tenant/blocks.jsx
2030
+ import { useState as useState6 } from "react";
2031
+ import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
2032
+ var hid = (id) => `${id}-title`;
2033
+ var Heading = ({ id, title: title2, intro: intro2, align = "center" }) => title2 ? /* @__PURE__ */ jsx24(SectionIntro, { id: hid(id), title: title2, body: intro2, align }) : null;
2034
+ function SlotSection({ id, title: title2, intro: intro2, tone: tone2, slot, ...props }) {
2035
+ const body = typeof slot === "function" ? slot({ title: title2, intro: intro2, ...props }) : slot;
2036
+ if (!body) return null;
2037
+ return /* @__PURE__ */ jsxs21(Section, { id, labelledBy: title2 ? hid(id) : void 0, tone: tone2, className: "dt-lp-slot", children: [
2038
+ /* @__PURE__ */ jsx24(Heading, { id, title: title2, intro: intro2, align: "start" }),
2039
+ /* @__PURE__ */ jsx24("div", { className: "dt-lp-slot-body", children: body })
2040
+ ] });
2041
+ }
2042
+ function PromoBanner({ id, eyebrow, heading, text, cta_label: label, cta_href: href, image, style = "brand", media }) {
2043
+ const src = media(image, "wide");
2044
+ return /* @__PURE__ */ jsx24("section", { id, "aria-labelledby": hid(id), className: "dt-lp-section dt-lp-promo-wrap", children: /* @__PURE__ */ jsx24("div", { className: "dt-lp-wrap", children: /* @__PURE__ */ jsxs21("div", { className: `dt-lp-promo dt-lp-promo--${style}${src ? " dt-lp-promo--image" : ""}`, children: [
2045
+ /* @__PURE__ */ jsxs21("div", { className: "dt-lp-promo-copy", children: [
2046
+ eyebrow ? /* @__PURE__ */ jsx24("p", { className: "dt-lp-eyebrow dt-lp-eyebrow--inverse", children: eyebrow }) : null,
2047
+ /* @__PURE__ */ jsx24("h2", { id: hid(id), className: "dt-lp-h2 dt-lp-promo-heading", children: heading }),
2048
+ text ? /* @__PURE__ */ jsx24("p", { className: "dt-lp-promo-text", children: text }) : null,
2049
+ label && href ? /* @__PURE__ */ jsx24(SmartLink, { href, className: "dt-lp-btn dt-lp-btn--lg dt-lp-btn--inverse", children: label }) : null
2050
+ ] }),
2051
+ src ? /* @__PURE__ */ jsx24("img", { className: "dt-lp-promo-img", src, alt: image.alt || "", loading: "lazy", decoding: "async" }) : null
2052
+ ] }) }) });
2053
+ }
2054
+ function TrustBadges({ id, title: title2, intro: intro2, items = [], tone: tone2 }) {
2055
+ return /* @__PURE__ */ jsxs21(Section, { id, labelledBy: title2 ? hid(id) : void 0, tone: tone2, children: [
2056
+ /* @__PURE__ */ jsx24(Heading, { id, title: title2, intro: intro2 }),
2057
+ /* @__PURE__ */ jsx24("ul", { className: "dt-lp-tgrid dt-lp-tgrid--4", children: items.map((it, i) => /* @__PURE__ */ jsxs21("li", { className: "dt-lp-card dt-lp-tcard", children: [
2058
+ /* @__PURE__ */ jsx24("span", { className: "dt-lp-icon-tile", children: /* @__PURE__ */ jsx24(NamedIcon, { name: it.icon, size: 22 }) }),
2059
+ /* @__PURE__ */ jsxs21("div", { className: "dt-lp-card-text", children: [
2060
+ /* @__PURE__ */ jsx24("h3", { className: "dt-lp-h3", children: it.title }),
2061
+ it.text ? /* @__PURE__ */ jsx24("p", { children: it.text }) : null
2062
+ ] })
2063
+ ] }, i)) })
2064
+ ] });
2065
+ }
2066
+ function CtaCards({ id, title: title2, items = [], tone: tone2 }) {
2067
+ return /* @__PURE__ */ jsxs21(Section, { id, labelledBy: title2 ? hid(id) : void 0, tone: tone2, children: [
2068
+ /* @__PURE__ */ jsx24(Heading, { id, title: title2 }),
2069
+ /* @__PURE__ */ jsx24("ul", { className: `dt-lp-tgrid dt-lp-tgrid--${Math.min(items.length, 4) || 1}`, children: items.map((it, i) => /* @__PURE__ */ jsx24("li", { children: /* @__PURE__ */ jsxs21(SmartLink, { href: it.cta_href, className: "dt-lp-card dt-lp-tcard dt-lp-ctacard", children: [
2070
+ /* @__PURE__ */ jsx24("span", { className: "dt-lp-icon-tile", children: /* @__PURE__ */ jsx24(NamedIcon, { name: it.icon, size: 22 }) }),
2071
+ /* @__PURE__ */ jsxs21("div", { className: "dt-lp-card-text", children: [
2072
+ /* @__PURE__ */ jsx24("h3", { className: "dt-lp-h3", children: it.title }),
2073
+ it.text ? /* @__PURE__ */ jsx24("p", { children: it.text }) : null,
2074
+ it.cta_label ? /* @__PURE__ */ jsxs21("span", { className: "dt-lp-textlink", children: [
2075
+ it.cta_label,
2076
+ " ",
2077
+ /* @__PURE__ */ jsx24(NamedIcon, { name: "chevron-right", size: 16 })
2078
+ ] }) : null
2079
+ ] })
2080
+ ] }) }, i)) })
2081
+ ] });
2082
+ }
2083
+ function Testimonials({ id, title: title2, items = [], tone: tone2 }) {
2084
+ return /* @__PURE__ */ jsxs21(Section, { id, labelledBy: title2 ? hid(id) : void 0, tone: tone2, children: [
2085
+ /* @__PURE__ */ jsx24(Heading, { id, title: title2 }),
2086
+ /* @__PURE__ */ jsx24("ul", { className: "dt-lp-tgrid dt-lp-tgrid--3", children: items.map((it, i) => {
2087
+ const stars = Math.max(1, Math.min(5, Number(it.rating) || 5));
2088
+ return /* @__PURE__ */ jsxs21("li", { className: "dt-lp-card dt-lp-quote", children: [
2089
+ /* @__PURE__ */ jsx24("p", { className: "dt-lp-stars", "aria-label": `${stars} out of 5 stars`, children: Array.from({ length: 5 }, (_, s) => /* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: s < stars ? "dt-lp-star dt-lp-star--on" : "dt-lp-star", children: "\u2605" }, s)) }),
2090
+ /* @__PURE__ */ jsx24("blockquote", { children: /* @__PURE__ */ jsx24("p", { children: it.quote }) }),
2091
+ /* @__PURE__ */ jsxs21("p", { className: "dt-lp-quote-by", children: [
2092
+ /* @__PURE__ */ jsx24("strong", { children: it.name }),
2093
+ it.detail ? /* @__PURE__ */ jsxs21("span", { children: [
2094
+ " \xB7 ",
2095
+ it.detail
2096
+ ] }) : null
2097
+ ] })
2098
+ ] }, i);
2099
+ }) })
2100
+ ] });
2101
+ }
2102
+ function FaqSection({ id, title: title2, intro: intro2, items = [], tone: tone2 }) {
2103
+ return /* @__PURE__ */ jsx24(Faq, { id, title: title2, intro: intro2, items, tone: tone2, openFirst: true });
2104
+ }
2105
+ function RichText({ id, title: title2, html, width = "narrow", tone: tone2 }) {
2106
+ return /* @__PURE__ */ jsxs21(Section, { id, labelledBy: title2 ? hid(id) : void 0, tone: tone2, narrow: width === "narrow", children: [
2107
+ title2 ? /* @__PURE__ */ jsx24("h2", { id: hid(id), className: "dt-lp-h2", children: title2 }) : null,
2108
+ /* @__PURE__ */ jsx24("div", { className: "dt-lp-prose", dangerouslySetInnerHTML: { __html: sanitizeRichText(html) } })
2109
+ ] });
2110
+ }
2111
+ function UspStrip({ id, items = [], tone: tone2 = "tinted" }) {
2112
+ return /* @__PURE__ */ jsx24("section", { id, "aria-label": "Highlights", className: `dt-lp-usp dt-lp-tone--${tone2}`, children: /* @__PURE__ */ jsx24("div", { className: "dt-lp-wrap", children: /* @__PURE__ */ jsx24("ul", { className: "dt-lp-usp-list", children: items.map((it, i) => /* @__PURE__ */ jsxs21("li", { className: "dt-lp-usp-item", children: [
2113
+ /* @__PURE__ */ jsx24(NamedIcon, { name: it.icon, size: 20, className: "dt-lp-icon dt-lp-usp-icon" }),
2114
+ /* @__PURE__ */ jsxs21("span", { children: [
2115
+ /* @__PURE__ */ jsx24("strong", { children: it.title }),
2116
+ it.text ? /* @__PURE__ */ jsx24("span", { className: "dt-lp-usp-text", children: it.text }) : null
2117
+ ] })
2118
+ ] }, i)) }) }) });
2119
+ }
2120
+ function BrandStrip({ id, title: title2, items = [], tone: tone2, media }) {
2121
+ return /* @__PURE__ */ jsxs21(Section, { id, labelledBy: title2 ? hid(id) : void 0, tone: tone2, className: "dt-lp-brands", children: [
2122
+ /* @__PURE__ */ jsx24(Heading, { id, title: title2 }),
2123
+ /* @__PURE__ */ jsx24("ul", { className: "dt-lp-brand-list", children: items.map((it, i) => {
2124
+ const src = media(it.logo, "logo");
2125
+ return /* @__PURE__ */ jsx24("li", { className: "dt-lp-brand-item", children: src ? /* @__PURE__ */ jsx24("img", { src, alt: it.name, loading: "lazy", decoding: "async" }) : /* @__PURE__ */ jsx24("span", { children: it.name }) }, i);
2126
+ }) })
2127
+ ] });
2128
+ }
2129
+ function Newsletter({ id, title: title2, text, button_label: button, consent_text: consentText, success_text: success, tone: tone2, onSubscribe }) {
2130
+ const [email, setEmail] = useState6("");
2131
+ const [consent, setConsent] = useState6(false);
2132
+ const [state, setState] = useState6({ status: "idle", message: "" });
2133
+ const submit = async (e) => {
2134
+ e.preventDefault();
2135
+ if (!onSubscribe) return;
2136
+ setState({ status: "busy", message: "" });
2137
+ try {
2138
+ await onSubscribe({ email: email.trim(), consent, section: id });
2139
+ setState({ status: "done", message: success || "Thanks!" });
2140
+ } catch (err) {
2141
+ setState({ status: "error", message: err && err.message || "Could not subscribe. Please try again." });
2142
+ }
2143
+ };
2144
+ return /* @__PURE__ */ jsxs21(Section, { id, labelledBy: hid(id), tone: tone2, narrow: true, children: [
2145
+ /* @__PURE__ */ jsx24(SectionIntro, { id: hid(id), title: title2, body: text, align: "center" }),
2146
+ state.status === "done" ? /* @__PURE__ */ jsx24("p", { className: "dt-lp-news-done", role: "status", children: state.message }) : /* @__PURE__ */ jsxs21("form", { className: "dt-lp-news", onSubmit: submit, children: [
2147
+ /* @__PURE__ */ jsxs21("div", { className: "dt-lp-news-row", children: [
2148
+ /* @__PURE__ */ jsx24("label", { className: "dt-lp-sr", htmlFor: `${id}-email`, children: "Email" }),
2149
+ /* @__PURE__ */ jsx24("input", { id: `${id}-email`, type: "email", required: true, autoComplete: "email", placeholder: "you@example.com", value: email, onChange: (e) => setEmail(e.target.value), className: "dt-lp-input" }),
2150
+ /* @__PURE__ */ jsx24("button", { type: "submit", className: "dt-lp-btn dt-lp-btn--md dt-lp-btn--primary", disabled: !consent || state.status === "busy", "aria-busy": state.status === "busy" ? "true" : void 0, children: button })
2151
+ ] }),
2152
+ /* @__PURE__ */ jsxs21("label", { className: "dt-lp-news-consent", children: [
2153
+ /* @__PURE__ */ jsx24("input", { type: "checkbox", checked: consent, onChange: (e) => setConsent(e.target.checked), required: true }),
2154
+ /* @__PURE__ */ jsx24("span", { children: consentText })
2155
+ ] }),
2156
+ state.status === "error" ? /* @__PURE__ */ jsx24("p", { className: "dt-lp-news-error", role: "alert", children: state.message }) : null
2157
+ ] })
2158
+ ] });
2159
+ }
2160
+ function Gallery({ id, title: title2, items = [], columns = "3", tone: tone2, media }) {
2161
+ const shown = items.map((it) => ({ ...it, src: media(it.image, "gallery") })).filter((it) => it.src);
2162
+ if (!shown.length) return null;
2163
+ return /* @__PURE__ */ jsxs21(Section, { id, labelledBy: title2 ? hid(id) : void 0, tone: tone2, children: [
2164
+ /* @__PURE__ */ jsx24(Heading, { id, title: title2 }),
2165
+ /* @__PURE__ */ jsx24("ul", { className: `dt-lp-gallery dt-lp-gallery--${columns}`, children: shown.map((it, i) => /* @__PURE__ */ jsx24("li", { children: /* @__PURE__ */ jsxs21("figure", { children: [
2166
+ /* @__PURE__ */ jsx24("img", { src: it.src, alt: it.image.alt || it.caption || "", loading: "lazy", decoding: "async" }),
2167
+ it.caption ? /* @__PURE__ */ jsx24("figcaption", { children: it.caption }) : null
2168
+ ] }) }, i)) })
2169
+ ] });
2170
+ }
2171
+
2172
+ // src/tenant/TenantPage.jsx
2173
+ import { jsx as jsx25 } from "react/jsx-runtime";
2174
+ var TENANT_BLOCKS = {
2175
+ hero_slider: HeroSlider,
2176
+ featured: SlotSection,
2177
+ categories: SlotSection,
2178
+ promo_banner: PromoBanner,
2179
+ trust_badges: TrustBadges,
2180
+ cta_cards: CtaCards,
2181
+ testimonials: Testimonials,
2182
+ faq: FaqSection,
2183
+ rich_text: RichText,
2184
+ usp_strip: UspStrip,
2185
+ brand_strip: BrandStrip,
2186
+ newsletter: Newsletter,
2187
+ gallery: Gallery
2188
+ };
2189
+ var SectionBoundary = class extends Component {
2190
+ constructor(props) {
2191
+ super(props);
2192
+ this.state = { failed: false };
2193
+ }
2194
+ static getDerivedStateFromError() {
2195
+ return { failed: true };
2196
+ }
2197
+ render() {
2198
+ return this.state.failed ? null : this.props.children;
2199
+ }
2200
+ };
2201
+ var noMedia = () => null;
2202
+ function TenantPage({
2203
+ page,
2204
+ theme,
2205
+ slots = {},
2206
+ resolveMedia = noMedia,
2207
+ linkComponent = null,
2208
+ onSubscribe = null,
2209
+ storeName = "",
2210
+ className = "",
2211
+ headingStart = 1
2212
+ }) {
2213
+ const doc = useMemo(() => validatePage(page).page, [page]);
2214
+ const vars = useMemo(() => themeVars(theme), [theme]);
2215
+ const ctx = useMemo(() => ({ brand: { id: "tenant", name: storeName, primary: vars.theme.primary }, linkComponent, onBookDemo: null, home: true }), [storeName, vars.theme.primary, linkComponent]);
2216
+ const media = (ref, variant) => ref && ref.media_id != null ? resolveMedia(ref, variant) : null;
2217
+ const visible = doc.sections.filter((s) => s.enabled && TENANT_BLOCKS[s.type]);
2218
+ return /* @__PURE__ */ jsx25(LandingProvider, { value: ctx, children: /* @__PURE__ */ jsx25("div", { className: `dt-landing dt-lp-tenant ${className}`.trim(), style: vars.style, "data-theme": vars.theme.mode === "auto" ? void 0 : vars.theme.mode, children: visible.map((s, i) => {
2219
+ const Block = TENANT_BLOCKS[s.type];
2220
+ return /* @__PURE__ */ jsx25(SectionBoundary, { children: /* @__PURE__ */ jsx25(Block, { ...s.props, id: `s-${s.id}`, first: i === 0 && headingStart === 1, media, slot: slots[s.type], onSubscribe }) }, s.id);
2221
+ }) }) });
2222
+ }
1217
2223
  export {
1218
2224
  Audiences,
1219
2225
  AuthShell,
@@ -1234,15 +2240,19 @@ export {
1234
2240
  FeatureSection,
1235
2241
  Header,
1236
2242
  Hero,
2243
+ HeroSlider,
1237
2244
  HowItWorks,
1238
2245
  LandingPage,
1239
2246
  LandingProvider,
1240
2247
  MarketingLayout,
2248
+ NamedIcon,
1241
2249
  PageHero,
1242
2250
  PreviewFrame,
1243
2251
  Section,
1244
2252
  SectionIntro,
1245
2253
  SmartLink,
2254
+ TENANT_BLOCKS,
2255
+ TenantPage,
1246
2256
  TextLink,
1247
2257
  Wordmark,
1248
2258
  Wrap,
@@ -1255,7 +2265,10 @@ export {
1255
2265
  resolveHref,
1256
2266
  stashDemoFill,
1257
2267
  takeDemoFill,
2268
+ themeVars,
1258
2269
  toLandingBrand,
1259
2270
  useLanding,
1260
- useTapReveal
2271
+ useTapReveal,
2272
+ validatePage,
2273
+ validateTheme
1261
2274
  };