@spectare-personalisation/react 0.5.0 → 0.7.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.d.ts CHANGED
@@ -44,11 +44,57 @@ interface PersonalisedSectionProps {
44
44
  align?: 'left' | 'center' | 'right';
45
45
  /**
46
46
  * Brand accent. Passed through to ComponentRenderer, which emits it into the scoped
47
- * token set. Defaults to #60a5fa.
47
+ * token set. Defaults to #60a5fa (dark) or #2563eb (light).
48
48
  */
49
49
  accent?: string;
50
+ /** dark (default) or light, matching your page's ground. See ComponentRenderer. */
51
+ theme?: 'dark' | 'light';
50
52
  }
51
- declare function PersonalisedSection({ orgSlug, baseUrl, brand, pageHint, className, style, initialAssembly, initialIntent, initialVariantId, directSummary, zone, align, accent, }: PersonalisedSectionProps): react_jsx_runtime.JSX.Element | null;
53
+ declare function PersonalisedSection({ orgSlug, baseUrl, brand, pageHint, className, style, initialAssembly, initialIntent, initialVariantId, directSummary, zone, align, accent, theme, }: PersonalisedSectionProps): react_jsx_runtime.JSX.Element | null;
54
+
55
+ /**
56
+ * The one place this package's design tokens are defined.
57
+ *
58
+ * Two things that are easy to get wrong here:
59
+ *
60
+ * 1. Tokens are declared on `.sp-root`, not `:root`. Declaring them at `:root` writes into
61
+ * the host's document, allows only one theme per page, and means a customer overriding
62
+ * `--sp-accent` competes with us at equal specificity so tag order decides the winner.
63
+ * Scoping also lets two differently themed sections sit on one page.
64
+ *
65
+ * 2. `tokens.css` must stay byte-identical to `buildTokenCss({ scope: STYLESHEET_SCOPE })`,
66
+ * which differs from the injected CSS in its selector and in nothing else.
67
+ * tests/unit/react-tokens.test.ts enforces both halves, because a customer who imports the
68
+ * stylesheet and a customer who renders the component must get the same page.
69
+ *
70
+ * components/ServerAssemblyRenderer.tsx in the Spectare app is a deliberate mirror of the
71
+ * values below. It is not the same file: that renderer uses rem, this one uses px.
72
+ */
73
+ /** The package default. `spectare.js` and the WordPress plugin default to #2563eb, which is
74
+ * a live inconsistency and a brand decision rather than a technical one, so it is left alone
75
+ * here. Pass `accent` to override on either path. */
76
+ declare const DEFAULT_ACCENT = "#60a5fa";
77
+ type SpTheme = 'dark' | 'light';
78
+ /** Class the tokens are scoped to. Applied by ComponentRenderer to its own wrapper. */
79
+ declare const SP_ROOT = "sp-root";
80
+ /**
81
+ * Returns the stylesheet a renderer injects.
82
+ *
83
+ * @param accent brand colour. Accepts anything CSS does; `--sp-accent-bg` and
84
+ * `--sp-accent-border` are derived from it so a customer sets one value
85
+ * rather than three. Defaults to DEFAULT_ACCENT.
86
+ * @param unit length unit for layout rules. 'px' for this package, 'rem' for the app's
87
+ * server renderer, which sizes in rem throughout.
88
+ * @param scope selector the custom properties are declared on. Defaults to `.sp-root`, which is
89
+ * what a renderer injecting this at runtime wants. `tokens.css` is generated with
90
+ * STYLESHEET_SCOPE instead, so importing it works without a wrapper.
91
+ */
92
+ declare function buildTokenCss({ accent, unit, scope, theme }?: {
93
+ accent?: string;
94
+ unit?: 'px' | 'rem';
95
+ scope?: string;
96
+ theme?: SpTheme;
97
+ }): string;
52
98
 
53
99
  type Unit = 'px' | 'rem';
54
100
  type Align = 'left' | 'center' | 'right';
@@ -75,9 +121,10 @@ declare function HeroStatement({ headline, subheading, align, unit }: {
75
121
  align?: Align;
76
122
  unit?: Unit;
77
123
  }): react_jsx_runtime.JSX.Element;
78
- declare function AtomCard({ title, content, layout, stats, ctaText, ctaUrl, full, unit }: {
124
+ declare function AtomCard({ title, content, summary, layout, stats, ctaText, ctaUrl, full, variant, unit }: {
79
125
  title?: string;
80
126
  content?: string;
127
+ summary?: string;
81
128
  layout?: string[];
82
129
  stats?: {
83
130
  value: string;
@@ -86,6 +133,7 @@ declare function AtomCard({ title, content, layout, stats, ctaText, ctaUrl, full
86
133
  ctaText?: string;
87
134
  ctaUrl?: string;
88
135
  full?: boolean;
136
+ variant?: string;
89
137
  unit?: Unit;
90
138
  }): react_jsx_runtime.JSX.Element;
91
139
  declare function StatGrid({ stats, caption, unit }: {
@@ -169,6 +217,13 @@ interface ComponentRendererProps {
169
217
  * from it, so one value covers all three. Defaults to #60a5fa.
170
218
  */
171
219
  accent?: string;
220
+ /**
221
+ * dark (default) is the package's original near-black card set. light renders white cards
222
+ * with a dark text ramp for light host pages; without it the components paint near-white
223
+ * text and near-black slabs onto a light ground. Both palettes hold the same contrast
224
+ * floors (see tests/unit/token-contrast.test.ts).
225
+ */
226
+ theme?: SpTheme;
172
227
  /**
173
228
  * px (default) sizes components absolutely, predictable inside arbitrary host pages.
174
229
  * rem tracks the reader's font-size preference; the root then also inherits the host's
@@ -189,48 +244,6 @@ interface ComponentRendererProps {
189
244
  /** Extra attributes for the root element (e.g. a data marker a host overlay targets). */
190
245
  rootProps?: Record<string, unknown>;
191
246
  }
192
- declare function ComponentRenderer({ assembly, brand, xray, zone, align, accent, unit, renderOverride, renderItem, rootProps }: ComponentRendererProps): react_jsx_runtime.JSX.Element;
193
-
194
- /**
195
- * The one place this package's design tokens are defined.
196
- *
197
- * Two things that are easy to get wrong here:
198
- *
199
- * 1. Tokens are declared on `.sp-root`, not `:root`. Declaring them at `:root` writes into
200
- * the host's document, allows only one theme per page, and means a customer overriding
201
- * `--sp-accent` competes with us at equal specificity so tag order decides the winner.
202
- * Scoping also lets two differently themed sections sit on one page.
203
- *
204
- * 2. `tokens.css` must stay byte-identical to `buildTokenCss({ scope: STYLESHEET_SCOPE })`,
205
- * which differs from the injected CSS in its selector and in nothing else.
206
- * tests/unit/react-tokens.test.ts enforces both halves, because a customer who imports the
207
- * stylesheet and a customer who renders the component must get the same page.
208
- *
209
- * components/ServerAssemblyRenderer.tsx in the Spectare app is a deliberate mirror of the
210
- * values below. It is not the same file: that renderer uses rem, this one uses px.
211
- */
212
- /** The package default. `spectare.js` and the WordPress plugin default to #2563eb, which is
213
- * a live inconsistency and a brand decision rather than a technical one, so it is left alone
214
- * here. Pass `accent` to override on either path. */
215
- declare const DEFAULT_ACCENT = "#60a5fa";
216
- /** Class the tokens are scoped to. Applied by ComponentRenderer to its own wrapper. */
217
- declare const SP_ROOT = "sp-root";
218
- /**
219
- * Returns the stylesheet a renderer injects.
220
- *
221
- * @param accent brand colour. Accepts anything CSS does; `--sp-accent-bg` and
222
- * `--sp-accent-border` are derived from it so a customer sets one value
223
- * rather than three. Defaults to DEFAULT_ACCENT.
224
- * @param unit length unit for layout rules. 'px' for this package, 'rem' for the app's
225
- * server renderer, which sizes in rem throughout.
226
- * @param scope selector the custom properties are declared on. Defaults to `.sp-root`, which is
227
- * what a renderer injecting this at runtime wants. `tokens.css` is generated with
228
- * STYLESHEET_SCOPE instead, so importing it works without a wrapper.
229
- */
230
- declare function buildTokenCss({ accent, unit, scope }?: {
231
- accent?: string;
232
- unit?: 'px' | 'rem';
233
- scope?: string;
234
- }): string;
247
+ declare function ComponentRenderer({ assembly, brand, xray, zone, align, accent, theme, unit, renderOverride, renderItem, rootProps }: ComponentRendererProps): react_jsx_runtime.JSX.Element;
235
248
 
236
249
  export { AnnouncementBar, type AssemblyZone, AtomCard, CodeBlock, ComparisonTable, type ComponentAssembly, type ComponentName, ComponentRenderer, type ComponentRendererProps, CtaStrip, DEFAULT_ACCENT, FeatureList, HeroStatement, ImageCtaHero, PersonalisedSection, type PersonalisedSectionProps, SP_ROOT, StatGrid, TestimonialCard, buildTokenCss, filterAssemblyByZone };
package/dist/index.js CHANGED
@@ -42,19 +42,47 @@ var COMPONENT_CATEGORIES = {
42
42
 
43
43
  // src/tokens.ts
44
44
  var DEFAULT_ACCENT = "#60a5fa";
45
+ var DEFAULT_ACCENT_LIGHT = "#2563eb";
45
46
  var SP_ROOT = "sp-root";
46
47
  var STYLESHEET_SCOPE = `:where(:root),.${SP_ROOT}`;
47
- function palette(accent) {
48
- return {
48
+ function palette(accent, theme) {
49
+ const shared = {
49
50
  "--sp-accent": accent,
50
51
  "--sp-accent-bg": `color-mix(in srgb,${accent} 10%,transparent)`,
51
- "--sp-accent-border": `color-mix(in srgb,${accent} 20%,transparent)`,
52
+ "--sp-accent-border": `color-mix(in srgb,${accent} 20%,transparent)`
53
+ };
54
+ if (theme === "light") {
55
+ return {
56
+ ...shared,
57
+ "--sp-bg": "#ffffff",
58
+ "--sp-surface": "#f4f4f5",
59
+ "--sp-border": "#e4e4e7",
60
+ "--sp-text": "#18181b",
61
+ "--sp-text-sub": "#3f3f46",
62
+ "--sp-text-strong": "#27272a",
63
+ "--sp-text-muted": "#6b6b74",
64
+ "--sp-text-dim": "#82828b",
65
+ "--sp-text-body": "#52525b",
66
+ "--sp-positive": "#047857",
67
+ "--sp-cta-bg": "#18181b",
68
+ "--sp-cta-text": "#ffffff",
69
+ "--sp-divider": "rgba(0,0,0,0.06)",
70
+ "--sp-code-bg": "rgba(0,0,0,0.05)",
71
+ "--sp-code-border": "rgba(0,0,0,0.08)",
72
+ "--sp-pre-bg": "rgba(0,0,0,0.04)"
73
+ };
74
+ }
75
+ return {
76
+ ...shared,
52
77
  "--sp-bg": "#18181b",
53
78
  "--sp-surface": "#09090b",
54
79
  "--sp-border": "#27272a",
55
80
  "--sp-text": "#f4f4f5",
56
- "--sp-text-sub": "#d4d4d8",
57
- "--sp-text-strong": "#e4e4e7",
81
+ // Body prose colour. Was #d4d4d8, judged too grey against near-black at reading
82
+ // sizes; one step brighter keeps the hierarchy below --sp-text while reading as
83
+ // text rather than chrome.
84
+ "--sp-text-sub": "#e4e4e7",
85
+ "--sp-text-strong": "#ececee",
58
86
  "--sp-text-muted": "#82828b",
59
87
  "--sp-text-dim": "#6b6b74",
60
88
  "--sp-text-body": "#a1a1aa",
@@ -83,8 +111,9 @@ function rules(unit) {
83
111
  "@media(max-width:640px){.sp-root .sp-pair{grid-template-columns:1fr}}"
84
112
  ].join("");
85
113
  }
86
- function buildTokenCss({ accent = DEFAULT_ACCENT, unit = "px", scope = `.${SP_ROOT}` } = {}) {
87
- const decls = Object.entries(palette(accent)).map(([k, v]) => `${k}:${v}`).join(";");
114
+ function buildTokenCss({ accent, unit = "px", scope = `.${SP_ROOT}`, theme = "dark" } = {}) {
115
+ const resolved = accent != null ? accent : theme === "light" ? DEFAULT_ACCENT_LIGHT : DEFAULT_ACCENT;
116
+ const decls = Object.entries(palette(resolved, theme)).map(([k, v]) => `${k}:${v}`).join(";");
88
117
  return `${scope}{${decls}}${rules(unit)}`;
89
118
  }
90
119
 
@@ -138,17 +167,28 @@ var clampStyle = {
138
167
  WebkitBoxOrient: "vertical",
139
168
  overflow: "hidden"
140
169
  };
141
- function AtomCard({ title, content, layout, stats = [], ctaText, ctaUrl, full, unit = "px" }) {
170
+ function AtomCard({ title, content, summary, layout, stats = [], ctaText, ctaUrl, full, variant, unit = "px" }) {
142
171
  const u = scaler(unit);
172
+ if (variant === "card") {
173
+ const face = (summary == null ? void 0 : summary.trim()) || (content ? `${content.replace(/\s+/g, " ").split(/(?<=[.!?])\s/)[0]}` : "");
174
+ return /* @__PURE__ */ jsxs("div", { style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: u(12), padding: u(20) }, children: [
175
+ title && /* @__PURE__ */ jsx("h3", { style: { fontSize: u(18), fontWeight: 600, color: "var(--sp-text)", margin: 0, lineHeight: 1.35 }, children: title }),
176
+ face && /* @__PURE__ */ jsx("p", { style: { fontSize: u(16), color: "var(--sp-text-sub)", lineHeight: 1.6, margin: `${u(8)} 0 0` }, children: face }),
177
+ content && /* @__PURE__ */ jsxs("details", { style: { marginTop: u(10) }, children: [
178
+ /* @__PURE__ */ jsx("summary", { style: { cursor: "pointer", fontSize: u(14), fontWeight: 600, color: "var(--sp-accent)", listStyle: "none" }, children: "Read more" }),
179
+ /* @__PURE__ */ jsx("div", { className: "sp-prose", style: { fontSize: u(16), color: "var(--sp-text-sub)", lineHeight: 1.6, marginTop: u(10) }, dangerouslySetInnerHTML: { __html: renderMarkdown(content) } })
180
+ ] })
181
+ ] });
182
+ }
143
183
  const order = layout && layout.length ? layout : ATOM_LAYOUT_DEFAULT;
144
184
  const element = (name) => {
145
- if (name === "title") return title ? /* @__PURE__ */ jsx("h3", { style: { fontSize: u(16), fontWeight: 600, color: "var(--sp-text)", margin: `0 0 ${u(12)}` }, children: title }, "title") : null;
146
- if (name === "content") return content ? /* @__PURE__ */ 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;
147
- if (name === "stats") return stats.length ? /* @__PURE__ */ 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__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: u(2) }, children: [
185
+ if (name === "title") return title ? /* @__PURE__ */ jsx("h3", { style: { fontSize: u(18), fontWeight: 600, color: "var(--sp-text)", margin: `0 0 ${u(12)}` }, children: title }, "title") : null;
186
+ if (name === "content") return content ? /* @__PURE__ */ jsx("div", { className: "sp-prose", style: { fontSize: u(16), color: "var(--sp-text-sub)", lineHeight: 1.6, ...full ? {} : clampStyle }, dangerouslySetInnerHTML: { __html: renderMarkdown(content) } }, "content") : null;
187
+ if (name === "stats") return stats.length ? /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: u(20), margin: `${u(18)} 0 ${u(12)}`, padding: `0 0 ${u(14)}`, borderBottom: "1px solid var(--sp-border)" }, children: stats.map((s, i) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: u(2) }, children: [
148
188
  /* @__PURE__ */ jsx("span", { style: { fontSize: u(22), fontWeight: 700, color: "var(--sp-text)", lineHeight: 1, fontVariantNumeric: "tabular-nums" }, children: s.value }),
149
- /* @__PURE__ */ jsx("span", { style: { fontSize: u(11), color: "var(--sp-text-muted)", textTransform: "uppercase", letterSpacing: "0.06em" }, children: s.label })
189
+ /* @__PURE__ */ jsx("span", { style: { fontSize: u(12), color: "var(--sp-text-muted)", textTransform: "uppercase", letterSpacing: "0.06em" }, children: s.label })
150
190
  ] }, i)) }, "stats") : null;
151
- if (name === "cta") return ctaText && ctaUrl ? /* @__PURE__ */ 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: [
191
+ if (name === "cta") return ctaText && ctaUrl ? /* @__PURE__ */ jsxs("a", { href: ctaUrl, style: { display: "inline-flex", alignItems: "center", gap: u(4), marginTop: u(12), fontSize: u(14), fontWeight: 600, color: "var(--sp-accent)", textDecoration: "none" }, children: [
152
192
  ctaText,
153
193
  " \u2192"
154
194
  ] }, "cta") : null;
@@ -161,10 +201,10 @@ function StatGrid({ stats = [], caption, unit = "px" }) {
161
201
  const cols = stats.length === 2 ? 2 : stats.length === 3 ? 3 : 4;
162
202
  return /* @__PURE__ */ jsxs("div", { children: [
163
203
  /* @__PURE__ */ jsx("div", { style: { display: "grid", gridTemplateColumns: `repeat(${cols}, 1fr)`, gap: u(12) }, children: stats.map(({ value, label }) => /* @__PURE__ */ 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: [
164
- /* @__PURE__ */ 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 }),
204
+ /* @__PURE__ */ jsx("p", { style: { fontSize: u(12), color: "var(--sp-text-muted)", textTransform: "uppercase", letterSpacing: "0.06em", margin: `0 0 ${u(12)}`, lineHeight: 1.3 }, children: label }),
165
205
  /* @__PURE__ */ jsx("p", { style: { fontSize: u(20), fontWeight: 500, color: "var(--sp-text)", fontVariantNumeric: "tabular-nums", lineHeight: 1, margin: 0 }, children: value })
166
206
  ] }, label)) }),
167
- caption && /* @__PURE__ */ jsx("p", { style: { fontSize: u(13), color: "var(--sp-text-muted)", margin: `${u(12)} 0 0` }, children: caption })
207
+ caption && /* @__PURE__ */ jsx("p", { style: { fontSize: u(14), color: "var(--sp-text-muted)", margin: `${u(12)} 0 0` }, children: caption })
168
208
  ] });
169
209
  }
170
210
  function CodeBlock({ code, lang = "typescript", caption, unit = "px" }) {
@@ -182,14 +222,14 @@ function ComparisonTable({ brand = "Us", competitor, rows = [], unit = "px" }) {
182
222
  const cell = { textAlign: "left", padding: `${u(12)} ${u(16)}` };
183
223
  return /* @__PURE__ */ jsx("div", { style: { border: "1px solid var(--sp-border)", borderRadius: u(12), overflow: "hidden" }, children: /* @__PURE__ */ jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxs("table", { style: { width: "100%", fontSize: u(14), borderCollapse: "collapse" }, children: [
184
224
  /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { style: { borderBottom: "1px solid var(--sp-border)", background: "var(--sp-bg)" }, children: [
185
- /* @__PURE__ */ jsx("th", { style: { ...cell, color: "var(--sp-text-muted)", fontWeight: 500, fontSize: u(12), width: "33%" } }),
186
- /* @__PURE__ */ jsx("th", { scope: "col", style: { ...cell, fontWeight: 600, color: "var(--sp-accent)", fontSize: u(12) }, children: brand }),
187
- /* @__PURE__ */ jsx("th", { scope: "col", style: { ...cell, color: "var(--sp-text-muted)", fontWeight: 500, fontSize: u(12) }, children: competitor })
225
+ /* @__PURE__ */ jsx("th", { style: { ...cell, color: "var(--sp-text-muted)", fontWeight: 500, fontSize: u(13), width: "33%" } }),
226
+ /* @__PURE__ */ jsx("th", { scope: "col", style: { ...cell, fontWeight: 600, color: "var(--sp-accent)", fontSize: u(13) }, children: brand }),
227
+ /* @__PURE__ */ jsx("th", { scope: "col", style: { ...cell, color: "var(--sp-text-muted)", fontWeight: 500, fontSize: u(13) }, children: competitor })
188
228
  ] }) }),
189
229
  /* @__PURE__ */ jsx("tbody", { children: rows.map(({ label, spectare, them }) => /* @__PURE__ */ jsxs("tr", { style: { borderBottom: "1px solid var(--sp-border)" }, children: [
190
- /* @__PURE__ */ jsx("th", { scope: "row", style: { ...cell, fontSize: u(13), color: "var(--sp-text-muted)", fontWeight: 500 }, children: label }),
191
- /* @__PURE__ */ jsx("td", { style: { ...cell, fontSize: u(13), color: "var(--sp-positive)", fontWeight: 500 }, children: spectare }),
192
- /* @__PURE__ */ jsx("td", { style: { ...cell, fontSize: u(13), color: "var(--sp-text-muted)" }, children: them })
230
+ /* @__PURE__ */ jsx("th", { scope: "row", style: { ...cell, fontSize: u(14), color: "var(--sp-text-muted)", fontWeight: 500 }, children: label }),
231
+ /* @__PURE__ */ jsx("td", { style: { ...cell, fontSize: u(14), color: "var(--sp-positive)", fontWeight: 500 }, children: spectare }),
232
+ /* @__PURE__ */ jsx("td", { style: { ...cell, fontSize: u(14), color: "var(--sp-text-muted)" }, children: them })
193
233
  ] }, label)) })
194
234
  ] }) }) });
195
235
  }
@@ -199,7 +239,7 @@ function FeatureList({ items = [], unit = "px" }) {
199
239
  /* @__PURE__ */ jsx("span", { style: { color: "var(--sp-accent)", flexShrink: 0, fontSize: u(15), marginTop: u(2) }, children: "\u2713" }),
200
240
  /* @__PURE__ */ jsxs("div", { children: [
201
241
  /* @__PURE__ */ jsx("p", { style: { fontSize: u(15), fontWeight: 500, color: "var(--sp-text)", lineHeight: 1.4, margin: 0 }, children: text }),
202
- sub && /* @__PURE__ */ jsx("p", { style: { fontSize: u(13), color: "var(--sp-text-muted)", lineHeight: 1.5, margin: `${u(4)} 0 0` }, children: sub })
242
+ sub && /* @__PURE__ */ jsx("p", { style: { fontSize: u(14), color: "var(--sp-text-muted)", lineHeight: 1.5, margin: `${u(4)} 0 0` }, children: sub })
203
243
  ] })
204
244
  ] }, text)) }) });
205
245
  }
@@ -213,7 +253,7 @@ function TestimonialCard({ quote, name, role, company, unit = "px" }) {
213
253
  ] }),
214
254
  /* @__PURE__ */ jsxs("div", { style: { borderTop: "1px solid var(--sp-border)", paddingTop: u(16) }, children: [
215
255
  /* @__PURE__ */ jsx("p", { style: { fontSize: u(14), fontWeight: 600, color: "var(--sp-text)", margin: 0 }, children: name }),
216
- /* @__PURE__ */ jsxs("p", { style: { fontSize: u(13), color: "var(--sp-text-muted)", margin: `${u(2)} 0 0` }, children: [
256
+ /* @__PURE__ */ jsxs("p", { style: { fontSize: u(14), color: "var(--sp-text-muted)", margin: `${u(2)} 0 0` }, children: [
217
257
  role,
218
258
  company ? `, ${company}` : ""
219
259
  ] })
@@ -257,7 +297,7 @@ function renderSingle(item, brand, align, unit = "px") {
257
297
  return /* @__PURE__ */ jsx(HeroStatement, { headline: s.headline, subheading: s.subheading, align, unit });
258
298
  // A full-width card has nothing beside it, so there is nothing for a clamp to protect.
259
299
  case "AtomCard":
260
- return /* @__PURE__ */ 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", unit });
300
+ return /* @__PURE__ */ 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 });
261
301
  case "StatGrid":
262
302
  return /* @__PURE__ */ jsx(StatGrid, { stats: s.stats, caption: s.caption, unit });
263
303
  case "CodeBlock":
@@ -323,7 +363,7 @@ function XrayBadge({ name, size }) {
323
363
  /* @__PURE__ */ jsx("span", { style: { fontSize: PX(10), fontFamily: "monospace", color: "#71717a", lineHeight: 1 }, children: size })
324
364
  ] });
325
365
  }
326
- function ComponentRenderer({ assembly, brand, xray = false, zone, align, accent, unit = "px", renderOverride, renderItem, rootProps }) {
366
+ function ComponentRenderer({ assembly, brand, xray = false, zone, align, accent, theme, unit = "px", renderOverride, renderItem, rootProps }) {
327
367
  const u = scaler(unit);
328
368
  const filtered = zone ? filterAssemblyByZone(assembly, zone) : assembly;
329
369
  const layout = buildLayout(filtered);
@@ -334,7 +374,7 @@ function ComponentRenderer({ assembly, brand, xray = false, zone, align, accent,
334
374
  return renderItem ? renderItem(item, node) : node;
335
375
  };
336
376
  return /* @__PURE__ */ jsxs("div", { className: extraClass ? `${SP_ROOT} ${extraClass}` : SP_ROOT, ...restRoot, style: { ...extraStyle, display: "flex", flexDirection: "column", gap: u(20), ...unit === "px" ? { fontSize: "16px" } : {} }, children: [
337
- /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: buildTokenCss({ accent, unit }) } }),
377
+ /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: buildTokenCss({ accent, unit, theme }) } }),
338
378
  layout.map((group, i) => {
339
379
  if (group.type === "pair") {
340
380
  return /* @__PURE__ */ jsxs("div", { className: "sp-pair", children: [
@@ -427,7 +467,8 @@ function PersonalisedSection({
427
467
  directSummary,
428
468
  zone,
429
469
  align,
430
- accent
470
+ accent,
471
+ theme
431
472
  }) {
432
473
  const [assembly, setAssembly] = useState(initialAssembly != null ? initialAssembly : []);
433
474
  const [loading, setLoading] = useState(!initialAssembly);
@@ -678,7 +719,7 @@ function PersonalisedSection({
678
719
  debugIntent.stage
679
720
  ] })
680
721
  ] }),
681
- loading && assembly.length === 0 ? /* @__PURE__ */ jsx2(Shimmer, {}) : /* @__PURE__ */ jsx2(ComponentRenderer, { assembly: zone ? filterAssemblyByZone(assembly, zone) : assembly, brand: brand != null ? brand : orgName, align, accent })
722
+ loading && assembly.length === 0 ? /* @__PURE__ */ jsx2(Shimmer, {}) : /* @__PURE__ */ jsx2(ComponentRenderer, { assembly: zone ? filterAssemblyByZone(assembly, zone) : assembly, brand: brand != null ? brand : orgName, align, accent, theme })
682
723
  ] })
683
724
  ] });
684
725
  }