@spectare-personalisation/react 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.cjs CHANGED
@@ -1,15 +1,61 @@
1
- 'use strict';
2
-
3
- var react = require('react');
4
- var marked = require('marked');
5
- var DOMPurify = require('isomorphic-dompurify');
6
- var jsxRuntime = require('react/jsx-runtime');
7
-
8
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
1
+ 'use client';
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
9
30
 
10
- var DOMPurify__default = /*#__PURE__*/_interopDefault(DOMPurify);
31
+ // src/index.ts
32
+ var src_exports = {};
33
+ __export(src_exports, {
34
+ AnnouncementBar: () => AnnouncementBar,
35
+ AtomCard: () => AtomCard,
36
+ CodeBlock: () => CodeBlock,
37
+ ComparisonTable: () => ComparisonTable,
38
+ ComponentRenderer: () => ComponentRenderer,
39
+ CtaStrip: () => CtaStrip,
40
+ DEFAULT_ACCENT: () => DEFAULT_ACCENT,
41
+ FeatureList: () => FeatureList,
42
+ HeroStatement: () => HeroStatement,
43
+ ImageCtaHero: () => ImageCtaHero,
44
+ PersonalisedSection: () => PersonalisedSection,
45
+ SP_ROOT: () => SP_ROOT,
46
+ StatGrid: () => StatGrid,
47
+ TestimonialCard: () => TestimonialCard,
48
+ buildTokenCss: () => buildTokenCss,
49
+ filterAssemblyByZone: () => filterAssemblyByZone
50
+ });
51
+ module.exports = __toCommonJS(src_exports);
11
52
 
12
53
  // src/PersonalisedSection.tsx
54
+ var import_react = require("react");
55
+
56
+ // src/ComponentRenderer.tsx
57
+ var import_marked = require("marked");
58
+ var import_isomorphic_dompurify = __toESM(require("isomorphic-dompurify"), 1);
13
59
 
14
60
  // src/types.ts
15
61
  var COMPONENT_ZONES = {
@@ -31,15 +77,53 @@ function filterAssemblyByZone(assembly, zone) {
31
77
  return effectiveZone === zone;
32
78
  });
33
79
  }
80
+ var COMPONENT_CATEGORIES = {
81
+ AnnouncementBar: "conversion",
82
+ HeroStatement: "hero",
83
+ AtomCard: "content",
84
+ StatGrid: "content",
85
+ CodeBlock: "technical",
86
+ ComparisonTable: "evaluation",
87
+ FeatureList: "content",
88
+ TestimonialCard: "social-proof",
89
+ ImageCtaHero: "hero",
90
+ CtaStrip: "conversion"
91
+ };
34
92
 
35
93
  // src/tokens.ts
36
94
  var DEFAULT_ACCENT = "#60a5fa";
95
+ var DEFAULT_ACCENT_LIGHT = "#2563eb";
37
96
  var SP_ROOT = "sp-root";
38
- function palette(accent) {
39
- return {
97
+ var STYLESHEET_SCOPE = `:where(:root),.${SP_ROOT}`;
98
+ function palette(accent, theme) {
99
+ const shared = {
40
100
  "--sp-accent": accent,
41
101
  "--sp-accent-bg": `color-mix(in srgb,${accent} 10%,transparent)`,
42
- "--sp-accent-border": `color-mix(in srgb,${accent} 20%,transparent)`,
102
+ "--sp-accent-border": `color-mix(in srgb,${accent} 20%,transparent)`
103
+ };
104
+ if (theme === "light") {
105
+ return {
106
+ ...shared,
107
+ "--sp-bg": "#ffffff",
108
+ "--sp-surface": "#f4f4f5",
109
+ "--sp-border": "#e4e4e7",
110
+ "--sp-text": "#18181b",
111
+ "--sp-text-sub": "#3f3f46",
112
+ "--sp-text-strong": "#27272a",
113
+ "--sp-text-muted": "#6b6b74",
114
+ "--sp-text-dim": "#82828b",
115
+ "--sp-text-body": "#52525b",
116
+ "--sp-positive": "#047857",
117
+ "--sp-cta-bg": "#18181b",
118
+ "--sp-cta-text": "#ffffff",
119
+ "--sp-divider": "rgba(0,0,0,0.06)",
120
+ "--sp-code-bg": "rgba(0,0,0,0.05)",
121
+ "--sp-code-border": "rgba(0,0,0,0.08)",
122
+ "--sp-pre-bg": "rgba(0,0,0,0.04)"
123
+ };
124
+ }
125
+ return {
126
+ ...shared,
43
127
  "--sp-bg": "#18181b",
44
128
  "--sp-surface": "#09090b",
45
129
  "--sp-border": "#27272a",
@@ -74,44 +158,52 @@ function rules(unit) {
74
158
  "@media(max-width:640px){.sp-root .sp-pair{grid-template-columns:1fr}}"
75
159
  ].join("");
76
160
  }
77
- function buildTokenCss({ accent = DEFAULT_ACCENT, unit = "px", scope = `.${SP_ROOT}` } = {}) {
78
- const decls = Object.entries(palette(accent)).map(([k, v]) => `${k}:${v}`).join(";");
161
+ function buildTokenCss({ accent, unit = "px", scope = `.${SP_ROOT}`, theme = "dark" } = {}) {
162
+ const resolved = accent != null ? accent : theme === "light" ? DEFAULT_ACCENT_LIGHT : DEFAULT_ACCENT;
163
+ const decls = Object.entries(palette(resolved, theme)).map(([k, v]) => `${k}:${v}`).join(";");
79
164
  return `${scope}{${decls}}${rules(unit)}`;
80
165
  }
166
+
167
+ // src/ComponentRenderer.tsx
168
+ var import_jsx_runtime = require("react/jsx-runtime");
81
169
  function renderMarkdown(content) {
82
- const raw = marked.marked.parse(content != null ? content : "", { async: false });
83
- return DOMPurify__default.default.sanitize(raw, { USE_PROFILES: { html: true } });
170
+ const raw = import_marked.marked.parse(content != null ? content : "", { async: false });
171
+ return import_isomorphic_dompurify.default.sanitize(raw, { USE_PROFILES: { html: true } });
84
172
  }
173
+ var scaler = (unit) => (n) => unit === "rem" ? `${n / 16}rem` : `${n}px`;
174
+ var PX = scaler("px");
85
175
  var HALF_COMPONENTS = /* @__PURE__ */ new Set(["TestimonialCard"]);
86
176
  var flexItems = (a) => a === "center" ? "center" : a === "right" ? "flex-end" : "flex-start";
87
- function AnnouncementBar({ text, link }) {
177
+ function AnnouncementBar({ text, link, unit = "px" }) {
178
+ const u = scaler(unit);
88
179
  if (!text) return null;
89
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
180
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
90
181
  display: "flex",
91
182
  alignItems: "center",
92
183
  justifyContent: "center",
93
- gap: "10px",
184
+ gap: u(10),
94
185
  flexWrap: "wrap",
95
186
  textAlign: "center",
96
187
  background: "var(--sp-accent-bg)",
97
188
  border: "1px solid var(--sp-accent-border)",
98
- borderRadius: "8px",
99
- padding: "8px 16px",
100
- fontSize: "14px",
189
+ borderRadius: u(8),
190
+ padding: `${u(8)} ${u(16)}`,
191
+ fontSize: u(14),
101
192
  lineHeight: 1.4,
102
193
  color: "var(--sp-text-sub)"
103
194
  }, children: [
104
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: text }),
105
- (link == null ? void 0 : link.href) && (link == null ? void 0 : link.label) && /* @__PURE__ */ jsxRuntime.jsxs("a", { href: link.href, style: { color: "var(--sp-accent)", fontWeight: 600, textDecoration: "none", whiteSpace: "nowrap" }, children: [
195
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: text }),
196
+ (link == null ? void 0 : link.href) && (link == null ? void 0 : link.label) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("a", { href: link.href, style: { color: "var(--sp-accent)", fontWeight: 600, textDecoration: "none", whiteSpace: "nowrap" }, children: [
106
197
  link.label,
107
198
  " \u2192"
108
199
  ] })
109
200
  ] });
110
201
  }
111
- function HeroStatement({ headline, subheading, align = "left" }) {
112
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: flexItems(align), textAlign: align, paddingTop: "24px", paddingBottom: "24px" }, children: [
113
- /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { fontSize: "32px", fontWeight: 700, letterSpacing: "-0.025em", lineHeight: 1.2, color: "var(--sp-text)", margin: "0 0 12px" }, children: headline }),
114
- subheading && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "18px", color: "var(--sp-text-sub)", lineHeight: 1.6, maxWidth: "672px", margin: 0 }, children: subheading })
202
+ function HeroStatement({ headline, subheading, align = "left", unit = "px" }) {
203
+ const u = scaler(unit);
204
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", alignItems: flexItems(align), textAlign: align, paddingTop: u(24), paddingBottom: u(24) }, children: [
205
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: { fontSize: u(32), fontWeight: 700, letterSpacing: "-0.025em", lineHeight: 1.2, color: "var(--sp-text)", margin: `0 0 ${u(12)}` }, children: headline }),
206
+ subheading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(18), color: "var(--sp-text-sub)", lineHeight: 1.6, maxWidth: u(672), margin: 0 }, children: subheading })
115
207
  ] });
116
208
  }
117
209
  var ATOM_LAYOUT_DEFAULT = ["title", "content", "stats", "cta"];
@@ -122,133 +214,157 @@ var clampStyle = {
122
214
  WebkitBoxOrient: "vertical",
123
215
  overflow: "hidden"
124
216
  };
125
- function AtomCard({ title, content, layout, stats = [], ctaText, ctaUrl, full }) {
217
+ function AtomCard({ title, content, summary, layout, stats = [], ctaText, ctaUrl, full, variant, unit = "px" }) {
218
+ const u = scaler(unit);
219
+ if (variant === "card") {
220
+ const face = (summary == null ? void 0 : summary.trim()) || (content ? `${content.replace(/\s+/g, " ").split(/(?<=[.!?])\s/)[0]}` : "");
221
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: u(12), padding: u(20) }, children: [
222
+ title && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { style: { fontSize: u(16), fontWeight: 600, color: "var(--sp-text)", margin: 0, lineHeight: 1.35 }, children: title }),
223
+ face && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(15), color: "var(--sp-text-sub)", lineHeight: 1.6, margin: `${u(8)} 0 0` }, children: face }),
224
+ content && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { style: { marginTop: u(10) }, children: [
225
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { style: { cursor: "pointer", fontSize: u(13), fontWeight: 600, color: "var(--sp-accent)", listStyle: "none" }, children: "Read more" }),
226
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "sp-prose", style: { fontSize: u(15), color: "var(--sp-text-sub)", lineHeight: 1.6, marginTop: u(10) }, dangerouslySetInnerHTML: { __html: renderMarkdown(content) } })
227
+ ] }),
228
+ ctaText && ctaUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("a", { href: ctaUrl, style: { display: "inline-flex", alignItems: "center", gap: u(4), marginTop: u(10), fontSize: u(13), fontWeight: 600, color: "var(--sp-accent)", textDecoration: "none" }, children: [
229
+ ctaText,
230
+ " \u2192"
231
+ ] })
232
+ ] });
233
+ }
126
234
  const order = layout && layout.length ? layout : ATOM_LAYOUT_DEFAULT;
127
235
  const element = (name) => {
128
- if (name === "title") return title ? /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { fontSize: "16px", fontWeight: 600, color: "var(--sp-text)", margin: "0 0 12px" }, children: title }, "title") : null;
129
- if (name === "content") return content ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sp-prose", style: { fontSize: "15px", color: "var(--sp-text-sub)", lineHeight: 1.6, ...full ? {} : clampStyle }, dangerouslySetInnerHTML: { __html: renderMarkdown(content) } }, "content") : null;
130
- if (name === "stats") return stats.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "20px", margin: "0 0 12px", paddingBottom: "12px", borderBottom: "1px solid var(--sp-border)" }, children: stats.map((s, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "2px" }, children: [
131
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "22px", fontWeight: 700, color: "var(--sp-text)", lineHeight: 1, fontVariantNumeric: "tabular-nums" }, children: s.value }),
132
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "11px", color: "var(--sp-text-muted)", textTransform: "uppercase", letterSpacing: "0.06em" }, children: s.label })
236
+ if (name === "title") return title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { style: { fontSize: u(16), fontWeight: 600, color: "var(--sp-text)", margin: `0 0 ${u(12)}` }, children: title }, "title") : null;
237
+ if (name === "content") return content ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "sp-prose", style: { fontSize: u(15), color: "var(--sp-text-sub)", lineHeight: 1.6, ...full ? {} : clampStyle }, dangerouslySetInnerHTML: { __html: renderMarkdown(content) } }, "content") : null;
238
+ if (name === "stats") return stats.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: u(20), margin: `0 0 ${u(12)}`, paddingBottom: u(12), borderBottom: "1px solid var(--sp-border)" }, children: stats.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: u(2) }, children: [
239
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: u(22), fontWeight: 700, color: "var(--sp-text)", lineHeight: 1, fontVariantNumeric: "tabular-nums" }, children: s.value }),
240
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: u(11), color: "var(--sp-text-muted)", textTransform: "uppercase", letterSpacing: "0.06em" }, children: s.label })
133
241
  ] }, i)) }, "stats") : null;
134
- if (name === "cta") return ctaText && ctaUrl ? /* @__PURE__ */ jsxRuntime.jsxs("a", { href: ctaUrl, style: { display: "inline-flex", alignItems: "center", gap: "4px", marginTop: "12px", fontSize: "13px", fontWeight: 600, color: "var(--sp-accent)", textDecoration: "none" }, children: [
242
+ if (name === "cta") return ctaText && ctaUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("a", { href: ctaUrl, style: { display: "inline-flex", alignItems: "center", gap: u(4), marginTop: u(12), fontSize: u(13), fontWeight: 600, color: "var(--sp-accent)", textDecoration: "none" }, children: [
135
243
  ctaText,
136
244
  " \u2192"
137
245
  ] }, "cta") : null;
138
246
  return null;
139
247
  };
140
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: "12px", padding: "24px", height: "100%" }, children: order.map(element) });
248
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: u(12), padding: u(24), height: "100%" }, children: order.map(element) });
141
249
  }
142
- function StatGrid({ stats = [], caption }) {
250
+ function StatGrid({ stats = [], caption, unit = "px" }) {
251
+ const u = scaler(unit);
143
252
  const cols = stats.length === 2 ? 2 : stats.length === 3 ? 3 : 4;
144
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
145
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "grid", gridTemplateColumns: `repeat(${cols}, 1fr)`, gap: "12px" }, children: stats.map(({ value, label }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: "10px", padding: "16px 20px", display: "flex", flexDirection: "column", justifyContent: "space-between", minHeight: "88px" }, children: [
146
- /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "11px", color: "var(--sp-text-muted)", textTransform: "uppercase", letterSpacing: "0.06em", margin: "0 0 12px", lineHeight: 1.3 }, children: label }),
147
- /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "20px", fontWeight: 500, color: "var(--sp-text)", fontVariantNumeric: "tabular-nums", lineHeight: 1, margin: 0 }, children: value })
253
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
254
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "grid", gridTemplateColumns: `repeat(${cols}, 1fr)`, gap: u(12) }, children: stats.map(({ value, label }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: u(10), padding: `${u(16)} ${u(20)}`, display: "flex", flexDirection: "column", justifyContent: "space-between", minHeight: u(88) }, children: [
255
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(11), color: "var(--sp-text-muted)", textTransform: "uppercase", letterSpacing: "0.06em", margin: `0 0 ${u(12)}`, lineHeight: 1.3 }, children: label }),
256
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(20), fontWeight: 500, color: "var(--sp-text)", fontVariantNumeric: "tabular-nums", lineHeight: 1, margin: 0 }, children: value })
148
257
  ] }, label)) }),
149
- caption && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "13px", color: "var(--sp-text-muted)", margin: "12px 0 0" }, children: caption })
258
+ caption && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(13), color: "var(--sp-text-muted)", margin: `${u(12)} 0 0` }, children: caption })
150
259
  ] });
151
260
  }
152
- function CodeBlock({ code, lang = "typescript", caption }) {
153
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { borderRadius: "12px", overflow: "hidden", border: "1px solid var(--sp-border)" }, children: [
154
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { background: "var(--sp-bg)", padding: "10px 16px", display: "flex", alignItems: "center", justifyContent: "space-between", borderBottom: "1px solid var(--sp-border)" }, children: [
155
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "12px", color: "var(--sp-text-muted)", fontFamily: "monospace" }, children: lang }),
156
- caption && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "12px", color: "var(--sp-text-muted)" }, children: caption })
261
+ function CodeBlock({ code, lang = "typescript", caption, unit = "px" }) {
262
+ const u = scaler(unit);
263
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { borderRadius: u(12), overflow: "hidden", border: "1px solid var(--sp-border)" }, children: [
264
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { background: "var(--sp-bg)", padding: `${u(10)} ${u(16)}`, display: "flex", alignItems: "center", justifyContent: "space-between", borderBottom: "1px solid var(--sp-border)" }, children: [
265
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: u(12), color: "var(--sp-text-muted)", fontFamily: "monospace" }, children: lang }),
266
+ caption && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: u(12), color: "var(--sp-text-muted)" }, children: caption })
157
267
  ] }),
158
- /* @__PURE__ */ jsxRuntime.jsx("pre", { style: { background: "var(--sp-surface)", padding: "20px", fontSize: "13px", color: "var(--sp-text-sub)", overflowX: "auto", lineHeight: 1.6, fontFamily: "monospace", whiteSpace: "pre", margin: 0 }, children: code })
268
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { style: { background: "var(--sp-surface)", padding: u(20), fontSize: u(13), color: "var(--sp-text-sub)", overflowX: "auto", lineHeight: 1.6, fontFamily: "monospace", whiteSpace: "pre", margin: 0 }, children: code })
159
269
  ] });
160
270
  }
161
- function ComparisonTable({ brand = "Us", competitor, rows = [] }) {
162
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { border: "1px solid var(--sp-border)", borderRadius: "12px", overflow: "hidden" }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsxs("table", { style: { width: "100%", fontSize: "14px", borderCollapse: "collapse" }, children: [
163
- /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { style: { borderBottom: "1px solid var(--sp-border)", background: "var(--sp-bg)" }, children: [
164
- /* @__PURE__ */ jsxRuntime.jsx("th", { style: { textAlign: "left", padding: "12px 16px", color: "var(--sp-text-muted)", fontWeight: 500, fontSize: "12px", width: "33%" } }),
165
- /* @__PURE__ */ jsxRuntime.jsx("th", { style: { textAlign: "left", padding: "12px 16px", fontWeight: 600, color: "var(--sp-accent)", fontSize: "12px" }, children: brand }),
166
- /* @__PURE__ */ jsxRuntime.jsx("th", { style: { textAlign: "left", padding: "12px 16px", color: "var(--sp-text-muted)", fontWeight: 500, fontSize: "12px" }, children: competitor })
271
+ function ComparisonTable({ brand = "Us", competitor, rows = [], unit = "px" }) {
272
+ const u = scaler(unit);
273
+ const cell = { textAlign: "left", padding: `${u(12)} ${u(16)}` };
274
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { border: "1px solid var(--sp-border)", borderRadius: u(12), overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { style: { width: "100%", fontSize: u(14), borderCollapse: "collapse" }, children: [
275
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { style: { borderBottom: "1px solid var(--sp-border)", background: "var(--sp-bg)" }, children: [
276
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: { ...cell, color: "var(--sp-text-muted)", fontWeight: 500, fontSize: u(12), width: "33%" } }),
277
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", style: { ...cell, fontWeight: 600, color: "var(--sp-accent)", fontSize: u(12) }, children: brand }),
278
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", style: { ...cell, color: "var(--sp-text-muted)", fontWeight: 500, fontSize: u(12) }, children: competitor })
167
279
  ] }) }),
168
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: rows.map(({ label, spectare, them }) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { style: { borderBottom: "1px solid var(--sp-border)" }, children: [
169
- /* @__PURE__ */ jsxRuntime.jsx("td", { style: { padding: "12px 16px", fontSize: "13px", color: "var(--sp-text-muted)", fontWeight: 500 }, children: label }),
170
- /* @__PURE__ */ jsxRuntime.jsx("td", { style: { padding: "12px 16px", fontSize: "13px", color: "var(--sp-positive)", fontWeight: 500 }, children: spectare }),
171
- /* @__PURE__ */ jsxRuntime.jsx("td", { style: { padding: "12px 16px", fontSize: "13px", color: "var(--sp-text-muted)" }, children: them })
280
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: rows.map(({ label, spectare, them }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { style: { borderBottom: "1px solid var(--sp-border)" }, children: [
281
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "row", style: { ...cell, fontSize: u(13), color: "var(--sp-text-muted)", fontWeight: 500 }, children: label }),
282
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: { ...cell, fontSize: u(13), color: "var(--sp-positive)", fontWeight: 500 }, children: spectare }),
283
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: { ...cell, fontSize: u(13), color: "var(--sp-text-muted)" }, children: them })
172
284
  ] }, label)) })
173
285
  ] }) }) });
174
286
  }
175
- function FeatureList({ items = [] }) {
176
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: "12px", padding: "24px" }, children: /* @__PURE__ */ jsxRuntime.jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: "16px" }, children: items.map(({ text, sub }) => /* @__PURE__ */ jsxRuntime.jsxs("li", { style: { display: "flex", gap: "12px" }, children: [
177
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--sp-accent)", flexShrink: 0, fontSize: "15px", marginTop: "2px" }, children: "\u2713" }),
178
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
179
- /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "15px", fontWeight: 500, color: "var(--sp-text)", lineHeight: 1.4, margin: 0 }, children: text }),
180
- sub && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "13px", color: "var(--sp-text-muted)", lineHeight: 1.5, margin: "4px 0 0" }, children: sub })
287
+ function FeatureList({ items = [], unit = "px" }) {
288
+ const u = scaler(unit);
289
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: u(12), padding: u(24) }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: u(16) }, children: items.map(({ text, sub }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { style: { display: "flex", gap: u(12) }, children: [
290
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "var(--sp-accent)", flexShrink: 0, fontSize: u(15), marginTop: u(2) }, children: "\u2713" }),
291
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
292
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(15), fontWeight: 500, color: "var(--sp-text)", lineHeight: 1.4, margin: 0 }, children: text }),
293
+ sub && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(13), color: "var(--sp-text-muted)", lineHeight: 1.5, margin: `${u(4)} 0 0` }, children: sub })
181
294
  ] })
182
295
  ] }, text)) }) });
183
296
  }
184
- function TestimonialCard({ quote, name, role, company }) {
185
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: "12px", padding: "24px", display: "flex", flexDirection: "column", gap: "20px", height: "100%" }, children: [
186
- /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { fontSize: "15px", color: "var(--sp-text-sub)", lineHeight: 1.6, flex: 1, margin: 0 }, children: [
187
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--sp-text-dim)", fontSize: "18px", lineHeight: 1, marginRight: "4px" }, children: '"' }),
297
+ function TestimonialCard({ quote, name, role, company, unit = "px" }) {
298
+ const u = scaler(unit);
299
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: u(12), padding: u(24), display: "flex", flexDirection: "column", gap: u(20), height: "100%" }, children: [
300
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: { fontSize: u(15), color: "var(--sp-text-sub)", lineHeight: 1.6, flex: 1, margin: 0 }, children: [
301
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "var(--sp-text-dim)", fontSize: u(18), lineHeight: 1, marginRight: u(4) }, children: '"' }),
188
302
  quote,
189
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--sp-text-dim)", fontSize: "18px", lineHeight: 1, marginLeft: "4px" }, children: '"' })
303
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "var(--sp-text-dim)", fontSize: u(18), lineHeight: 1, marginLeft: u(4) }, children: '"' })
190
304
  ] }),
191
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { borderTop: "1px solid var(--sp-border)", paddingTop: "16px" }, children: [
192
- /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "14px", fontWeight: 600, color: "var(--sp-text)", margin: 0 }, children: name }),
193
- /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { fontSize: "13px", color: "var(--sp-text-muted)", margin: "2px 0 0" }, children: [
305
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { borderTop: "1px solid var(--sp-border)", paddingTop: u(16) }, children: [
306
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(14), fontWeight: 600, color: "var(--sp-text)", margin: 0 }, children: name }),
307
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: { fontSize: u(13), color: "var(--sp-text-muted)", margin: `${u(2)} 0 0` }, children: [
194
308
  role,
195
309
  company ? `, ${company}` : ""
196
310
  ] })
197
311
  ] })
198
312
  ] });
199
313
  }
200
- function ImageCtaHero({ src, alt = "", headline, subheading, ctaLabel, ctaHref, align = "left" }) {
314
+ function ImageCtaHero({ src, alt = "", headline, subheading, ctaLabel, ctaHref, align = "left", unit = "px" }) {
315
+ const u = scaler(unit);
201
316
  if (!src) return null;
202
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { borderRadius: "12px", overflow: "hidden", position: "relative", width: "100%", paddingBottom: "56.25%" }, children: [
203
- /* @__PURE__ */ jsxRuntime.jsx("img", { src, alt, style: { position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" } }),
204
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", inset: 0, background: "rgba(0,0,0,0.45)" } }),
205
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", inset: 0, background: "linear-gradient(to top, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.2) 60%, transparent 100%)" } }),
206
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "absolute", bottom: 0, left: 0, right: 0, padding: "28px", textAlign: align }, children: [
207
- headline && /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { fontSize: "24px", fontWeight: 700, color: "#fff", lineHeight: 1.2, margin: "0 0 8px", letterSpacing: "-0.02em" }, children: headline }),
208
- subheading && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "15px", color: "rgba(255,255,255,0.75)", lineHeight: 1.5, margin: "0 0 20px" }, children: subheading }),
209
- ctaHref && ctaLabel && /* @__PURE__ */ jsxRuntime.jsx("a", { href: ctaHref, style: { display: "inline-block", background: "#fff", color: "#09090b", padding: "8px 20px", borderRadius: "8px", fontWeight: 600, fontSize: "14px", textDecoration: "none" }, children: ctaLabel })
317
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { borderRadius: u(12), overflow: "hidden", position: "relative", width: "100%", paddingBottom: "56.25%" }, children: [
318
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src, alt, style: { position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" } }),
319
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: "rgba(0,0,0,0.45)" } }),
320
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: "linear-gradient(to top, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.2) 60%, transparent 100%)" } }),
321
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "absolute", bottom: 0, left: 0, right: 0, padding: u(28), textAlign: align }, children: [
322
+ headline && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: { fontSize: u(24), fontWeight: 700, color: "#fff", lineHeight: 1.2, margin: `0 0 ${u(8)}`, letterSpacing: "-0.02em" }, children: headline }),
323
+ subheading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: u(15), color: "rgba(255,255,255,0.75)", lineHeight: 1.5, margin: `0 0 ${u(20)}` }, children: subheading }),
324
+ ctaHref && ctaLabel && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: ctaHref, style: { display: "inline-block", background: "#fff", color: "#09090b", padding: `${u(8)} ${u(20)}`, borderRadius: u(8), fontWeight: 600, fontSize: u(14), textDecoration: "none" }, children: ctaLabel })
210
325
  ] })
211
326
  ] });
212
327
  }
213
- function CtaStrip({ headline, primary, secondary, align = "center" }) {
214
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { border: "1px solid var(--sp-border)", borderRadius: "12px", padding: "32px", textAlign: align, background: "var(--sp-bg)" }, children: [
215
- /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { fontSize: "24px", fontWeight: 700, color: "var(--sp-text)", margin: "0 0 24px" }, children: headline }),
216
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: flexItems(align), gap: "16px", flexWrap: "wrap" }, children: [
217
- /* @__PURE__ */ jsxRuntime.jsx("a", { href: primary.href, style: { background: "var(--sp-cta-bg)", color: "var(--sp-cta-text)", padding: "10px 24px", borderRadius: "12px", fontWeight: 600, fontSize: "15px", textDecoration: "none" }, children: primary.label }),
218
- secondary && /* @__PURE__ */ jsxRuntime.jsxs("a", { href: secondary.href, style: { fontSize: "15px", color: "var(--sp-text-sub)", textDecoration: "none" }, children: [
328
+ function CtaStrip({ headline, primary, secondary, align = "center", unit = "px" }) {
329
+ const u = scaler(unit);
330
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { border: "1px solid var(--sp-border)", borderRadius: u(12), padding: u(32), textAlign: align, background: "var(--sp-bg)" }, children: [
331
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { style: { fontSize: u(24), fontWeight: 700, color: "var(--sp-text)", margin: `0 0 ${u(24)}` }, children: headline }),
332
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: flexItems(align), gap: u(16), flexWrap: "wrap" }, children: [
333
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: primary.href, style: { background: "var(--sp-cta-bg)", color: "var(--sp-cta-text)", padding: `${u(10)} ${u(24)}`, borderRadius: u(12), fontWeight: 600, fontSize: u(15), textDecoration: "none" }, children: primary.label }),
334
+ secondary && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("a", { href: secondary.href, style: { fontSize: u(15), color: "var(--sp-text-sub)", textDecoration: "none" }, children: [
219
335
  secondary.label,
220
336
  " \u2192"
221
337
  ] })
222
338
  ] })
223
339
  ] });
224
340
  }
225
- function renderSingle(item, brand, align) {
341
+ function renderSingle(item, brand, align, unit = "px") {
226
342
  var _a, _b;
227
343
  const s = (_a = item.slots) != null ? _a : {};
228
344
  switch (item.component) {
229
345
  case "AnnouncementBar":
230
- return /* @__PURE__ */ jsxRuntime.jsx(AnnouncementBar, { text: s.text, link: s.link });
346
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnnouncementBar, { text: s.text, link: s.link, unit });
231
347
  case "HeroStatement":
232
- return /* @__PURE__ */ jsxRuntime.jsx(HeroStatement, { headline: s.headline, subheading: s.subheading, align });
348
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HeroStatement, { headline: s.headline, subheading: s.subheading, align, unit });
233
349
  // A full-width card has nothing beside it, so there is nothing for a clamp to protect.
234
350
  case "AtomCard":
235
- return /* @__PURE__ */ jsxRuntime.jsx(AtomCard, { title: s.title, content: s.content, layout: s.layout, stats: s.stats, ctaText: s.ctaText, ctaUrl: s.ctaUrl, full: s.full || resolvedSize(item) === "full" });
351
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AtomCard, { title: s.title, content: s.content, summary: s.summary, layout: s.layout, stats: s.stats, ctaText: s.ctaText, ctaUrl: s.ctaUrl, full: s.full || resolvedSize(item) === "full", variant: s.variant, unit });
236
352
  case "StatGrid":
237
- return /* @__PURE__ */ jsxRuntime.jsx(StatGrid, { stats: s.stats, caption: s.caption });
353
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatGrid, { stats: s.stats, caption: s.caption, unit });
238
354
  case "CodeBlock":
239
- return /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: s.code, lang: s.lang, caption: s.caption });
355
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CodeBlock, { code: s.code, lang: s.lang, caption: s.caption, unit });
240
356
  case "ComparisonTable":
241
- return /* @__PURE__ */ jsxRuntime.jsx(ComparisonTable, { brand: (_b = s.brand) != null ? _b : brand, competitor: s.competitor, rows: s.rows });
357
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ComparisonTable, { brand: (_b = s.brand) != null ? _b : brand, competitor: s.competitor, rows: s.rows, unit });
242
358
  case "FeatureList":
243
- return /* @__PURE__ */ jsxRuntime.jsx(FeatureList, { items: s.items });
359
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FeatureList, { items: s.items, unit });
244
360
  case "TestimonialCard":
245
- return /* @__PURE__ */ jsxRuntime.jsx(TestimonialCard, { quote: s.quote, name: s.name, role: s.role, company: s.company });
361
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TestimonialCard, { quote: s.quote, name: s.name, role: s.role, company: s.company, unit });
246
362
  case "ImageCtaHero":
247
- return /* @__PURE__ */ jsxRuntime.jsx(ImageCtaHero, { src: s.src, alt: s.alt, headline: s.headline, subheading: s.subheading, ctaLabel: s.ctaLabel, ctaHref: s.ctaHref, align });
363
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImageCtaHero, { src: s.src, alt: s.alt, headline: s.headline, subheading: s.subheading, ctaLabel: s.ctaLabel, ctaHref: s.ctaHref, align, unit });
248
364
  case "CtaStrip":
249
- return /* @__PURE__ */ jsxRuntime.jsx(CtaStrip, { headline: s.headline, primary: s.primary, secondary: s.secondary, align });
365
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CtaStrip, { headline: s.headline, primary: s.primary, secondary: s.secondary, align, unit });
250
366
  // An unrecognised component name used to render nothing at all. A component needs a
251
- // renderer in three places plus the WordPress plugin, so missing one made its content
367
+ // renderer here plus spectare.js plus the WordPress plugin, so missing one made its content
252
368
  // silently absent on that surface only: no error, no warning, just a shorter page that
253
369
  // looks deliberate. That is the failure mode to remove before the registry grows.
254
370
  //
@@ -259,7 +375,7 @@ function renderSingle(item, brand, align) {
259
375
  default: {
260
376
  console.warn(`[spectare] ComponentRenderer: no renderer for "${item.component}", falling back to AtomCard`);
261
377
  if (!s.title && !s.content) return null;
262
- return /* @__PURE__ */ jsxRuntime.jsx(AtomCard, { title: s.title, content: s.content, stats: s.stats, ctaText: s.ctaText, ctaUrl: s.ctaUrl, full: true });
378
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AtomCard, { title: s.title, content: s.content, stats: s.stats, ctaText: s.ctaText, ctaUrl: s.ctaUrl, full: true, unit });
263
379
  }
264
380
  }
265
381
  }
@@ -267,13 +383,19 @@ function resolvedSize(item) {
267
383
  if (item.size) return item.size;
268
384
  return HALF_COMPONENTS.has(item.component) ? "half" : "full";
269
385
  }
386
+ function pairable(a, b) {
387
+ const catOf = (x) => COMPONENT_CATEGORIES[x.component];
388
+ const ca = catOf(a);
389
+ const cb = catOf(b);
390
+ return ca !== void 0 && ca === cb;
391
+ }
270
392
  function buildLayout(assembly) {
271
393
  const groups = [];
272
394
  let i = 0;
273
395
  while (i < assembly.length) {
274
396
  const cur = assembly[i];
275
397
  const next = assembly[i + 1];
276
- if (resolvedSize(cur) === "half" && next && resolvedSize(next) === "half") {
398
+ if (resolvedSize(cur) === "half" && next && resolvedSize(next) === "half" && pairable(cur, next)) {
277
399
  groups.push({ type: "pair", items: [cur, next] });
278
400
  i += 2;
279
401
  } else if (resolvedSize(cur) === "half") {
@@ -287,42 +409,46 @@ function buildLayout(assembly) {
287
409
  return groups;
288
410
  }
289
411
  function XrayBadge({ name, size }) {
290
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "absolute", top: "8px", left: "8px", zIndex: 10, display: "flex", alignItems: "center", gap: "6px", pointerEvents: "none", userSelect: "none" }, children: [
291
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "10px", fontFamily: "monospace", background: "rgba(59,130,246,0.9)", color: "#fff", padding: "2px 6px", borderRadius: "4px", lineHeight: 1 }, children: name }),
292
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "10px", fontFamily: "monospace", color: "#71717a", lineHeight: 1 }, children: size })
412
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "absolute", top: PX(8), left: PX(8), zIndex: 10, display: "flex", alignItems: "center", gap: PX(6), pointerEvents: "none", userSelect: "none" }, children: [
413
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: PX(10), fontFamily: "monospace", background: "rgba(59,130,246,0.9)", color: "#fff", padding: `${PX(2)} ${PX(6)}`, borderRadius: PX(4), lineHeight: 1 }, children: name }),
414
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: PX(10), fontFamily: "monospace", color: "#71717a", lineHeight: 1 }, children: size })
293
415
  ] });
294
416
  }
295
- function ComponentRenderer({ assembly, brand, xray = false, zone, align, accent }) {
417
+ function ComponentRenderer({ assembly, brand, xray = false, zone, align, accent, theme, unit = "px", renderOverride, renderItem, rootProps }) {
418
+ const u = scaler(unit);
296
419
  const filtered = zone ? filterAssemblyByZone(assembly, zone) : assembly;
297
420
  const layout = buildLayout(filtered);
298
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: SP_ROOT, style: { display: "flex", flexDirection: "column", gap: "20px", fontSize: "16px" }, children: [
299
- /* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: buildTokenCss({ accent }) } }),
421
+ const { className: extraClass, style: extraStyle, ...restRoot } = rootProps != null ? rootProps : {};
422
+ const renderOne = (item) => {
423
+ const override = renderOverride == null ? void 0 : renderOverride(item);
424
+ const node = override === void 0 ? renderSingle(item, brand, align, unit) : override;
425
+ return renderItem ? renderItem(item, node) : node;
426
+ };
427
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: extraClass ? `${SP_ROOT} ${extraClass}` : SP_ROOT, ...restRoot, style: { ...extraStyle, display: "flex", flexDirection: "column", gap: u(20), ...unit === "px" ? { fontSize: "16px" } : {} }, children: [
428
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { dangerouslySetInnerHTML: { __html: buildTokenCss({ accent, unit, theme }) } }),
300
429
  layout.map((group, i) => {
301
- if (group.type === "full") {
302
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: xray ? { position: "relative" } : void 0, children: [
303
- xray && /* @__PURE__ */ jsxRuntime.jsx(XrayBadge, { name: group.item.component, size: "full" }),
304
- renderSingle(group.item, brand, align)
305
- ] }, i);
306
- }
307
430
  if (group.type === "pair") {
308
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sp-pair", children: [
309
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: xray ? { position: "relative" } : void 0, children: [
310
- xray && /* @__PURE__ */ jsxRuntime.jsx(XrayBadge, { name: group.items[0].component, size: "half" }),
311
- renderSingle(group.items[0], brand, align)
431
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "sp-pair", children: [
432
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: xray ? { position: "relative" } : void 0, children: [
433
+ xray && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(XrayBadge, { name: group.items[0].component, size: "half" }),
434
+ renderOne(group.items[0])
312
435
  ] }),
313
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: xray ? { position: "relative" } : void 0, children: [
314
- xray && /* @__PURE__ */ jsxRuntime.jsx(XrayBadge, { name: group.items[1].component, size: "half" }),
315
- renderSingle(group.items[1], brand, align)
436
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: xray ? { position: "relative" } : void 0, children: [
437
+ xray && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(XrayBadge, { name: group.items[1].component, size: "half" }),
438
+ renderOne(group.items[1])
316
439
  ] })
317
440
  ] }, i);
318
441
  }
319
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: xray ? { position: "relative" } : void 0, children: [
320
- xray && /* @__PURE__ */ jsxRuntime.jsx(XrayBadge, { name: group.item.component, size: "full" }),
321
- renderSingle(group.item, brand, align)
442
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: xray ? { position: "relative" } : void 0, children: [
443
+ xray && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(XrayBadge, { name: group.item.component, size: group.type === "half-solo" ? "half" : "full" }),
444
+ renderOne(group.item)
322
445
  ] }, i);
323
446
  })
324
447
  ] });
325
448
  }
449
+
450
+ // src/PersonalisedSection.tsx
451
+ var import_jsx_runtime2 = require("react/jsx-runtime");
326
452
  var VARIANT_KEY = (orgSlug) => `_spectare_variant_${orgSlug}`;
327
453
  function readVariantId(orgSlug) {
328
454
  try {
@@ -372,11 +498,11 @@ function readVisitPath(orgSlug) {
372
498
  }
373
499
  }
374
500
  function Shimmer() {
375
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
376
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "20px", background: "rgba(39,39,42,0.6)", borderRadius: "8px", width: "75%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
377
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "14px", background: "rgba(39,39,42,0.4)", borderRadius: "8px", width: "100%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
378
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "14px", background: "rgba(39,39,42,0.4)", borderRadius: "8px", width: "83%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
379
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "14px", background: "rgba(39,39,42,0.4)", borderRadius: "8px", width: "67%", animation: "sp-pulse 1.5s ease-in-out infinite" } })
501
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
502
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { height: "20px", background: "rgba(39,39,42,0.6)", borderRadius: "8px", width: "75%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
503
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { height: "14px", background: "rgba(39,39,42,0.4)", borderRadius: "8px", width: "100%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
504
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { height: "14px", background: "rgba(39,39,42,0.4)", borderRadius: "8px", width: "83%", animation: "sp-pulse 1.5s ease-in-out infinite" } }),
505
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { height: "14px", background: "rgba(39,39,42,0.4)", borderRadius: "8px", width: "67%", animation: "sp-pulse 1.5s ease-in-out infinite" } })
380
506
  ] });
381
507
  }
382
508
  function PersonalisedSection({
@@ -392,23 +518,24 @@ function PersonalisedSection({
392
518
  directSummary,
393
519
  zone,
394
520
  align,
395
- accent
521
+ accent,
522
+ theme
396
523
  }) {
397
- const [assembly, setAssembly] = react.useState(initialAssembly != null ? initialAssembly : []);
398
- const [loading, setLoading] = react.useState(!initialAssembly);
399
- const [orgName, setOrgName] = react.useState(void 0);
400
- const [debugMode, setDebugMode] = react.useState(false);
401
- const [debugIntent, setDebugIntent] = react.useState(null);
402
- const tokenRef = react.useRef(null);
403
- const conversionFiredRef = react.useRef(false);
404
- react.useEffect(() => {
524
+ const [assembly, setAssembly] = (0, import_react.useState)(initialAssembly != null ? initialAssembly : []);
525
+ const [loading, setLoading] = (0, import_react.useState)(!initialAssembly);
526
+ const [orgName, setOrgName] = (0, import_react.useState)(void 0);
527
+ const [debugMode, setDebugMode] = (0, import_react.useState)(false);
528
+ const [debugIntent, setDebugIntent] = (0, import_react.useState)(null);
529
+ const tokenRef = (0, import_react.useRef)(null);
530
+ const conversionFiredRef = (0, import_react.useRef)(false);
531
+ (0, import_react.useEffect)(() => {
405
532
  setDebugMode(new URLSearchParams(window.location.search).has("spectare_debug"));
406
533
  if (initialIntent) setDebugIntent(initialIntent);
407
534
  }, [initialIntent]);
408
- react.useEffect(() => {
535
+ (0, import_react.useEffect)(() => {
409
536
  if (initialVariantId) writeVariantId(orgSlug, initialVariantId);
410
537
  }, [orgSlug, initialVariantId]);
411
- react.useEffect(() => {
538
+ (0, import_react.useEffect)(() => {
412
539
  let cancelled = false;
413
540
  async function load() {
414
541
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
@@ -574,7 +701,7 @@ function PersonalisedSection({
574
701
  cancelled = true;
575
702
  };
576
703
  }, [orgSlug, baseUrl, pageHint, initialAssembly, initialIntent, directSummary]);
577
- react.useEffect(() => {
704
+ (0, import_react.useEffect)(() => {
578
705
  if (!assembly.length || conversionFiredRef.current) return;
579
706
  const token = tokenRef.current;
580
707
  if (!token) return;
@@ -631,38 +758,39 @@ function PersonalisedSection({
631
758
  }, [assembly, orgSlug, baseUrl]);
632
759
  if (!loading && assembly.length === 0) return null;
633
760
  const debugStyle = debugMode ? { outline: "2px solid rgba(96,165,250,0.5)", borderRadius: "0.5rem", position: "relative", padding: "0.5rem", ...style } : style;
634
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
635
- /* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: "@keyframes sp-pulse{0%,100%{opacity:1}50%{opacity:0.4}}" } }),
636
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: debugStyle, children: [
637
- debugMode && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "absolute", top: "-1px", right: "-1px", zIndex: 20, display: "flex", alignItems: "center", gap: "0.375rem", background: "rgba(96,165,250,0.9)", borderRadius: "0 0.5rem 0 0.375rem", padding: "0.25rem 0.625rem", fontSize: "0.625rem", fontFamily: "monospace", color: "#fff", pointerEvents: "none", userSelect: "none" }, children: [
761
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
762
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { dangerouslySetInnerHTML: { __html: "@keyframes sp-pulse{0%,100%{opacity:1}50%{opacity:0.4}}" } }),
763
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className, style: debugStyle, children: [
764
+ debugMode && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { position: "absolute", top: "-1px", right: "-1px", zIndex: 20, display: "flex", alignItems: "center", gap: "0.375rem", background: "rgba(96,165,250,0.9)", borderRadius: "0 0.5rem 0 0.375rem", padding: "0.25rem 0.625rem", fontSize: "0.625rem", fontFamily: "monospace", color: "#fff", pointerEvents: "none", userSelect: "none" }, children: [
638
765
  "Personalised by Spectare",
639
- debugIntent && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { opacity: 0.75 }, children: [
766
+ debugIntent && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { opacity: 0.75 }, children: [
640
767
  " ",
641
768
  debugIntent.audience,
642
769
  "/",
643
770
  debugIntent.stage
644
771
  ] })
645
772
  ] }),
646
- loading && assembly.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(Shimmer, {}) : /* @__PURE__ */ jsxRuntime.jsx(ComponentRenderer, { assembly: zone ? filterAssemblyByZone(assembly, zone) : assembly, brand: brand != null ? brand : orgName, align, accent })
773
+ loading && assembly.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Shimmer, {}) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ComponentRenderer, { assembly: zone ? filterAssemblyByZone(assembly, zone) : assembly, brand: brand != null ? brand : orgName, align, accent, theme })
647
774
  ] })
648
775
  ] });
649
776
  }
650
-
651
- exports.AnnouncementBar = AnnouncementBar;
652
- exports.AtomCard = AtomCard;
653
- exports.CodeBlock = CodeBlock;
654
- exports.ComparisonTable = ComparisonTable;
655
- exports.ComponentRenderer = ComponentRenderer;
656
- exports.CtaStrip = CtaStrip;
657
- exports.DEFAULT_ACCENT = DEFAULT_ACCENT;
658
- exports.FeatureList = FeatureList;
659
- exports.HeroStatement = HeroStatement;
660
- exports.ImageCtaHero = ImageCtaHero;
661
- exports.PersonalisedSection = PersonalisedSection;
662
- exports.SP_ROOT = SP_ROOT;
663
- exports.StatGrid = StatGrid;
664
- exports.TestimonialCard = TestimonialCard;
665
- exports.buildTokenCss = buildTokenCss;
666
- exports.filterAssemblyByZone = filterAssemblyByZone;
667
- //# sourceMappingURL=index.cjs.map
777
+ // Annotate the CommonJS export names for ESM import in node:
778
+ 0 && (module.exports = {
779
+ AnnouncementBar,
780
+ AtomCard,
781
+ CodeBlock,
782
+ ComparisonTable,
783
+ ComponentRenderer,
784
+ CtaStrip,
785
+ DEFAULT_ACCENT,
786
+ FeatureList,
787
+ HeroStatement,
788
+ ImageCtaHero,
789
+ PersonalisedSection,
790
+ SP_ROOT,
791
+ StatGrid,
792
+ TestimonialCard,
793
+ buildTokenCss,
794
+ filterAssemblyByZone
795
+ });
668
796
  //# sourceMappingURL=index.cjs.map