@ohhwells/bridge 0.1.76-next.230 → 0.1.77

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
@@ -83,12 +83,7 @@ function parseAiSectionsState(raw) {
83
83
  media: entry.media && typeof entry.media === "object" ? entry.media : {}
84
84
  }));
85
85
  const removed = Array.isArray(parsed.removed) ? parsed.removed.filter((id) => typeof id === "string" && id.length > 0) : [];
86
- return {
87
- v: 1,
88
- sections,
89
- ...removed.length ? { removed } : {},
90
- ...parsed.hideTemplate === true ? { hideTemplate: true } : {}
91
- };
86
+ return { v: 1, sections, ...removed.length ? { removed } : {} };
92
87
  } catch {
93
88
  return EMPTY_AI_SECTIONS;
94
89
  }
@@ -101,7 +96,6 @@ function applyTreeToState(state, payload) {
101
96
  const entry = {
102
97
  id: payload.id,
103
98
  label: payload.label ?? "Generated section",
104
- ...typeof payload.path === "string" && payload.path ? { path: payload.path } : {},
105
99
  afterSection: payload.mode === "insert" && !insertBefore ? payload.targetSectionId ?? null : null,
106
100
  ...insertBefore && payload.targetSectionId ? { beforeSection: payload.targetSectionId } : {},
107
101
  ...payload.mode === "replace" && payload.targetSectionId ? { replaces: payload.targetSectionId } : {},
@@ -124,317 +118,6 @@ function deleteSectionFromState(state, sectionId) {
124
118
  return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
125
119
  }
126
120
 
127
- // src/lib/brand-chrome.ts
128
- var BRAND_NAME_KEY = "__ohw_brand_name";
129
- var BRAND_TITLE_KEY = "__ohw_site_title";
130
- var BRAND_FAVICON_LETTER_KEY = "__ohw_favicon_letter";
131
- var BRAND_CHROME_KEYS = /* @__PURE__ */ new Set([
132
- BRAND_NAME_KEY,
133
- BRAND_TITLE_KEY,
134
- BRAND_FAVICON_LETTER_KEY
135
- ]);
136
- function upsertMeta(selector, attr, token, value) {
137
- let el = document.head.querySelector(selector);
138
- if (!el) {
139
- el = document.createElement("meta");
140
- el.setAttribute(attr, token);
141
- document.head.appendChild(el);
142
- }
143
- if (el.getAttribute("content") !== value) el.setAttribute("content", value);
144
- }
145
- function escapeXml(value) {
146
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
147
- }
148
- function applyLetterFavicon(letter) {
149
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="12" fill="#111827"/><text x="32" y="46" font-family="system-ui,-apple-system,Segoe UI,sans-serif" font-size="40" font-weight="700" text-anchor="middle" fill="#ffffff">${escapeXml(letter)}</text></svg>`;
150
- const href = `data:image/svg+xml,${encodeURIComponent(svg)}`;
151
- let link = document.head.querySelector('link[rel="icon"]');
152
- if (!link) {
153
- link = document.createElement("link");
154
- link.rel = "icon";
155
- document.head.appendChild(link);
156
- }
157
- link.type = "image/svg+xml";
158
- if (link.href !== href) link.href = href;
159
- }
160
- function applyBrandChrome(content) {
161
- const name = content[BRAND_NAME_KEY];
162
- if (typeof name === "string" && name.length > 0) {
163
- document.querySelectorAll("[data-ohw-wordmark]").forEach((el) => {
164
- if (el.textContent !== name) el.textContent = name;
165
- if (el.getAttribute("title") !== name) el.setAttribute("title", name);
166
- });
167
- }
168
- const title = content[BRAND_TITLE_KEY];
169
- if (typeof title === "string" && title.length > 0) {
170
- if (document.title !== title) document.title = title;
171
- upsertMeta('meta[property="og:title"]', "property", "og:title", title);
172
- upsertMeta('meta[name="twitter:title"]', "name", "twitter:title", title);
173
- }
174
- const letter = content[BRAND_FAVICON_LETTER_KEY];
175
- if (typeof letter === "string" && letter.length > 0) {
176
- applyLetterFavicon(letter);
177
- }
178
- }
179
-
180
- // src/lib/brand-kit.ts
181
- var BRAND_KIT_KEY = "__ohw_brand";
182
- var BRAND_VAR_PREFIX = "--ohw-brand-";
183
- var BRAND_VAR_NAMES = ["primary", "accent", "light", "dark", "surface", "border", "muted"].map(
184
- (role) => `${BRAND_VAR_PREFIX}${role}`
185
- );
186
- var FONT_VARS = {
187
- heading: ["--font-heading", "--font-display", "--brand-font-heading"],
188
- body: ["--font-body", "--brand-font-body"]
189
- };
190
- var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
191
- function brandColorVars(kit) {
192
- const { dark, primary, accent, light } = kit.palette;
193
- const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
194
- return {
195
- [`${BRAND_VAR_PREFIX}primary`]: primary,
196
- [`${BRAND_VAR_PREFIX}accent`]: accent,
197
- [`${BRAND_VAR_PREFIX}light`]: light,
198
- [`${BRAND_VAR_PREFIX}dark`]: dark,
199
- [`${BRAND_VAR_PREFIX}surface`]: mix(light, 95, dark),
200
- [`${BRAND_VAR_PREFIX}border`]: mix(light, 85, dark),
201
- [`${BRAND_VAR_PREFIX}muted`]: mix(dark, 62, light)
202
- };
203
- }
204
- function parseBrandKit(raw) {
205
- if (!raw) return null;
206
- try {
207
- const parsed = JSON.parse(raw);
208
- const p = parsed?.palette;
209
- const f = parsed?.fonts;
210
- if (!p || !f || typeof p.dark !== "string" || typeof p.primary !== "string" || typeof p.accent !== "string" || typeof p.light !== "string" || typeof f.heading !== "string" || typeof f.body !== "string") {
211
- return null;
212
- }
213
- return {
214
- palette: { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light },
215
- fonts: { heading: f.heading, body: f.body }
216
- };
217
- } catch {
218
- return null;
219
- }
220
- }
221
- function familyOf(stack) {
222
- const first = stack.split(",")[0]?.trim() ?? "";
223
- return first.replace(/^['"]|['"]$/g, "");
224
- }
225
- function loadBrandFonts(families) {
226
- const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
227
- if (unique.length === 0) return;
228
- const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
229
- const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
230
- let link = document.getElementById(BRAND_FONT_LINK_ID);
231
- if (!link) {
232
- link = document.createElement("link");
233
- link.id = BRAND_FONT_LINK_ID;
234
- link.rel = "stylesheet";
235
- document.head.appendChild(link);
236
- }
237
- if (link.href !== href) link.href = href;
238
- }
239
- function applyBrandToDom(kit) {
240
- const root = document.documentElement;
241
- if (!kit) {
242
- for (const name of BRAND_VAR_NAMES) root.style.removeProperty(name);
243
- for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
244
- document.getElementById(BRAND_FONT_LINK_ID)?.remove();
245
- return;
246
- }
247
- for (const [name, value] of Object.entries(brandColorVars(kit))) root.style.setProperty(name, value);
248
- for (const name of FONT_VARS.heading) root.style.setProperty(name, kit.fonts.heading);
249
- for (const name of FONT_VARS.body) root.style.setProperty(name, kit.fonts.body);
250
- loadBrandFonts([familyOf(kit.fonts.heading), familyOf(kit.fonts.body)]);
251
- }
252
-
253
- // src/lib/section-styles.ts
254
- var STYLE_STORE_KEY = "__ohw_styles";
255
- var STYLE_SHEET_ID = "ohw-section-styles";
256
- function parseStyleStore(raw) {
257
- if (!raw) return null;
258
- try {
259
- const parsed = JSON.parse(raw);
260
- if (parsed?.v !== 1) return null;
261
- return {
262
- v: 1,
263
- sections: typeof parsed.sections === "object" && parsed.sections ? parsed.sections : {},
264
- nodes: typeof parsed.nodes === "object" && parsed.nodes ? parsed.nodes : {}
265
- };
266
- } catch {
267
- return null;
268
- }
269
- }
270
- var BG_VALUES = {
271
- surface: "color-mix(in srgb, var(--ohw-brand-light, var(--color-light, #ECECEB)) 94%, var(--ohw-brand-dark, var(--color-dark, #0C0A09)))",
272
- accent: "var(--ohw-brand-primary, var(--color-primary, #0078E5))",
273
- "accent-soft": "color-mix(in srgb, var(--ohw-brand-primary, var(--color-primary, #0078E5)) 12%, var(--ohw-brand-light, var(--color-light, #FFFFFF)))"
274
- };
275
- var HEADLINE_SIZES = { md: 24, lg: 32, xl: 40, display: 56 };
276
- function styleSheetCss() {
277
- const rules = [];
278
- for (const [tone, value] of Object.entries(BG_VALUES)) {
279
- rules.push(`[data-ohw-style-bg="${tone}"] { background: ${value} !important; }`);
280
- }
281
- rules.push(
282
- `[data-ohw-style-bg="accent"] { color: var(--ohw-brand-light, var(--color-light, #FFFFFF)) !important; }`
283
- );
284
- rules.push(
285
- `[data-ohw-style-distribution="space-between"] { display: flex !important; flex-direction: column; justify-content: space-between; }`,
286
- `[data-ohw-style-distribution="center"] { display: flex !important; flex-direction: column; justify-content: center; }`
287
- );
288
- for (const [scale, size] of Object.entries(HEADLINE_SIZES)) {
289
- rules.push(
290
- `[data-ohw-style-headline="${scale}"] :is(h1, h2, h3) { font-size: ${size}px !important; line-height: 1.15 !important; }`
291
- );
292
- }
293
- rules.push(
294
- `[data-ohw-style-aspect="fill-height"] img { height: 100% !important; aspect-ratio: auto !important; object-fit: cover; }`
295
- );
296
- for (const aspect of ["1:1", "4:5", "3:4", "3:2", "16:9", "2:1", "3:1"]) {
297
- rules.push(
298
- `[data-ohw-style-aspect="${aspect.replace(":", "-")}"] img { aspect-ratio: ${aspect.replace(":", " / ")} !important; height: auto !important; object-fit: cover; }`
299
- );
300
- }
301
- const pad = { tight: 40, balanced: 64, airy: 96 };
302
- for (const [spacing, px] of Object.entries(pad)) {
303
- rules.push(
304
- `[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
305
- );
306
- }
307
- return rules.join("\n");
308
- }
309
- var STYLE_FONT_LINK_ID = "ohw-style-fonts";
310
- function loadStyleFonts(families) {
311
- const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
312
- const existing = document.getElementById(STYLE_FONT_LINK_ID);
313
- if (unique.length === 0) {
314
- existing?.remove();
315
- return;
316
- }
317
- const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
318
- const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
319
- let link = existing;
320
- if (!link) {
321
- link = document.createElement("link");
322
- link.id = STYLE_FONT_LINK_ID;
323
- link.rel = "stylesheet";
324
- document.head.appendChild(link);
325
- }
326
- if (link.href !== href) link.href = href;
327
- }
328
- var SECTION_ATTRS = {
329
- sectionBackground: "data-ohw-style-bg",
330
- textDistribution: "data-ohw-style-distribution",
331
- headlineScale: "data-ohw-style-headline",
332
- imageAspect: "data-ohw-style-aspect",
333
- spacing: "data-ohw-style-spacing"
334
- };
335
- var NODE_WROTE_ATTR = "data-ohw-style-node";
336
- var NODE_PROPS = ["color", "font-family", "font-size", "background"];
337
- function saveInline(el, prop) {
338
- const attr = `data-ohw-style-prev-${prop}`;
339
- if (!el.hasAttribute(attr)) el.setAttribute(attr, el.style.getPropertyValue(prop));
340
- }
341
- function restoreInline(el, prop) {
342
- const attr = `data-ohw-style-prev-${prop}`;
343
- if (!el.hasAttribute(attr)) return;
344
- const prev = el.getAttribute(attr) ?? "";
345
- if (prev) el.style.setProperty(prop, prev);
346
- else el.style.removeProperty(prop);
347
- el.removeAttribute(attr);
348
- }
349
- function ensureStyleSheet() {
350
- let el = document.getElementById(STYLE_SHEET_ID);
351
- if (!el) {
352
- el = document.createElement("style");
353
- el.id = STYLE_SHEET_ID;
354
- document.head.appendChild(el);
355
- }
356
- const css = styleSheetCss();
357
- if (el.textContent !== css) el.textContent = css;
358
- }
359
- function clearSectionAttrs(root) {
360
- for (const attr of Object.values(SECTION_ATTRS)) {
361
- for (const el of Array.from(root.querySelectorAll(`[${attr}]`))) el.removeAttribute(attr);
362
- }
363
- for (const el of Array.from(root.querySelectorAll("[data-ohw-style-bgcolor]"))) {
364
- restoreInline(el, "background");
365
- el.removeAttribute("data-ohw-style-bgcolor");
366
- }
367
- }
368
- function clearNodeProps(root) {
369
- for (const el of Array.from(root.querySelectorAll(`[${NODE_WROTE_ATTR}]`))) {
370
- const h = el;
371
- for (const prop of NODE_PROPS) restoreInline(h, prop);
372
- h.removeAttribute(NODE_WROTE_ATTR);
373
- }
374
- }
375
- function buttonSurfaceOf(el) {
376
- return el.closest("a, button") ?? el;
377
- }
378
- function applyStylesToDom(store) {
379
- ensureStyleSheet();
380
- clearSectionAttrs(document);
381
- clearNodeProps(document);
382
- loadStyleFonts(
383
- store ? Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []) : []
384
- );
385
- if (!store) return;
386
- for (const [sectionId, override] of Object.entries(store.sections)) {
387
- const sections = document.querySelectorAll(
388
- `[data-ohw-section="${CSS.escape(sectionId)}"]`
389
- );
390
- for (const section of Array.from(sections)) {
391
- for (const [prop, attr] of Object.entries(SECTION_ATTRS)) {
392
- const value = override[prop];
393
- if (value === void 0) continue;
394
- if (prop === "sectionBackground" && override.sectionBackgroundColor !== void 0) continue;
395
- section.setAttribute(attr, String(value).replace(":", "-"));
396
- }
397
- if (override.sectionBackgroundColor !== void 0) {
398
- saveInline(section, "background");
399
- section.style.setProperty("background", override.sectionBackgroundColor, "important");
400
- section.setAttribute("data-ohw-style-bgcolor", "");
401
- }
402
- }
403
- }
404
- for (const [key, override] of Object.entries(store.nodes)) {
405
- const nodes = document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`);
406
- for (const el of Array.from(nodes)) {
407
- if (override.color !== void 0) {
408
- saveInline(el, "color");
409
- el.style.setProperty("color", override.color, "important");
410
- el.setAttribute(NODE_WROTE_ATTR, "");
411
- }
412
- if (override.fontFamily !== void 0) {
413
- saveInline(el, "font-family");
414
- el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
415
- el.setAttribute(NODE_WROTE_ATTR, "");
416
- }
417
- if (override.fontSize !== void 0) {
418
- saveInline(el, "font-size");
419
- el.style.setProperty("font-size", `${override.fontSize}px`, "important");
420
- el.setAttribute(NODE_WROTE_ATTR, "");
421
- }
422
- if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
423
- const surface = buttonSurfaceOf(el);
424
- if (override.buttonBackground !== void 0) {
425
- saveInline(surface, "background");
426
- surface.style.setProperty("background", override.buttonBackground, "important");
427
- }
428
- if (override.buttonText !== void 0) {
429
- saveInline(surface, "color");
430
- surface.style.setProperty("color", override.buttonText, "important");
431
- }
432
- surface.setAttribute(NODE_WROTE_ATTR, "");
433
- }
434
- }
435
- }
436
- }
437
-
438
121
  // src/ui/ai-tree/aiSectionsManager.tsx
439
122
  import { flushSync } from "react-dom";
440
123
  import { createRoot } from "react-dom/client";
@@ -449,8 +132,7 @@ function lucideByName(name) {
449
132
  }
450
133
  var typeStyle = (spec, font) => ({
451
134
  fontFamily: font,
452
- // Headings shrink with the viewport (reaching full size around ~900px wide); body copy stays put.
453
- fontSize: spec.size >= 24 ? `clamp(${Math.max(18, Math.round(spec.size * 0.6))}px, ${(spec.size / 9).toFixed(2)}vw, ${spec.size}px)` : spec.size,
135
+ fontSize: spec.size,
454
136
  lineHeight: spec.line,
455
137
  fontWeight: spec.weight
456
138
  });
@@ -459,60 +141,12 @@ var featureLines = (value) => value.split(/\n|<br\s*\/?>/i).map((line) => line.t
459
141
  var CHECK_MASK = `data:image/svg+xml,${encodeURIComponent(
460
142
  '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>'
461
143
  )}`;
462
- var AI_MOBILE_CSS = [
463
- "@media (max-width: 768px){",
464
- "[data-ai-section]{overflow-x:hidden}",
465
- "[data-ai-container]{padding:0 20px !important}",
466
- "[data-ai-row]{display:flex !important;flex-direction:column !important;align-items:stretch !important}",
467
- "[data-ai-cell]{width:100%;min-width:0}",
468
- "[data-ai-grid]{grid-template-columns:1fr !important}",
469
- // Group containers flatten to a column on phones; span placements come along for free.
470
- "[data-ai-group]{display:flex !important;flex-direction:column !important}",
471
- "[data-ai-group] > *{grid-column:auto !important}",
472
- // The 50:50 form collapses to a single stacked column on phones.
473
- "[data-ai-form]{grid-template-columns:1fr !important}",
474
- "[data-ai-section] img{max-width:100%}",
475
- "}",
476
- "@media (min-width: 769px) and (max-width: 1024px){",
477
- "[data-ai-grid]{grid-template-columns:repeat(2, 1fr) !important}",
478
- "}"
479
- ].join("");
480
144
  var FEATURE_LINE_CSS = [
481
145
  "[data-ai-features]>div{position:relative;padding-left:40px;min-height:24px}",
482
146
  '[data-ai-features]>div::before{content:"";position:absolute;left:0;top:1px;width:24px;height:24px;',
483
147
  `background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
484
148
  `mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
485
149
  ].join("");
486
- function hexLuminance(color) {
487
- const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
488
- if (!m) return null;
489
- const [r2, g, b] = [0, 2, 4].map((i) => {
490
- const c = parseInt(m[1].slice(i, i + 2), 16) / 255;
491
- return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
492
- });
493
- return 0.2126 * r2 + 0.7152 * g + 0.0722 * b;
494
- }
495
- function hexContrast(a, b) {
496
- const la = hexLuminance(a);
497
- const lb = hexLuminance(b);
498
- if (la === null || lb === null) return null;
499
- const [hi, lo] = la > lb ? [la, lb] : [lb, la];
500
- return (hi + 0.05) / (lo + 0.05);
501
- }
502
- function accentBandContext(brand) {
503
- const p = brand.palette;
504
- const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
505
- if (lightWins) {
506
- return {
507
- brand: { ...brand, palette: { dark: p.light, primary: p.light, accent: p.light, light: p.primary } },
508
- buttonLabel: p.primary
509
- };
510
- }
511
- return {
512
- brand: { ...brand, palette: { dark: p.dark, primary: p.dark, accent: p.dark, light: p.light } },
513
- buttonLabel: p.light
514
- };
515
- }
516
150
  function textAttrs(ctx, path) {
517
151
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
518
152
  }
@@ -524,12 +158,7 @@ var AI_RESPONSIVE_CSS = [
524
158
  "@media (max-width: 640px) {",
525
159
  " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
526
160
  " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
527
- // Group containers flatten to a column on phones; span placements come along for free.
528
- " [data-ai-responsive] [data-ai-group] { display: flex !important; flex-direction: column !important; }",
529
- " [data-ai-responsive] [data-ai-group] > * { grid-column: auto !important; }",
530
161
  " [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
531
- " [data-ai-responsive] { overflow-x: hidden; }",
532
- " [data-ai-responsive] img { max-width: 100%; }",
533
162
  "}"
534
163
  ].join("\n");
535
164
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
@@ -607,7 +236,7 @@ function ButtonEl({
607
236
  }) {
608
237
  const secondary = slots.variant === "secondary";
609
238
  const href = str(slots.href);
610
- const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`), "data-ohw-role": "button" } : {};
239
+ const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`) } : {};
611
240
  return /* @__PURE__ */ jsx(
612
241
  "a",
613
242
  {
@@ -623,7 +252,7 @@ function ButtonEl({
623
252
  textDecoration: "none",
624
253
  cursor: "pointer",
625
254
  ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body),
626
- ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? AI_TREE_TOKENS.textPrimaryForeground }
255
+ ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: AI_TREE_TOKENS.textPrimaryForeground }
627
256
  },
628
257
  children: /* @__PURE__ */ jsx("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
629
258
  }
@@ -1129,24 +758,7 @@ function CardBlock({ node, ctx, path }) {
1129
758
  minWidth: 0
1130
759
  },
1131
760
  children: [
1132
- media && (horizontal ? /* @__PURE__ */ jsx(
1133
- "div",
1134
- {
1135
- style: (
1136
- // An icon hugs its glyph — flex:1 gave a 48px icon half the card and pushed the
1137
- // text to the far side. Photos keep the half-and-half split. The inset has no
1138
- // inner padding (the photo split absorbed that), so the icon carries its own gap.
1139
- /^(lucide|simple):/.test(mediaRef) ? {
1140
- flexShrink: 0,
1141
- display: "flex",
1142
- alignItems: "center",
1143
- padding: mediaInset,
1144
- [mediaPosition === "right" ? "marginLeft" : "marginRight"]: 20
1145
- } : { flex: 1, minWidth: 0, display: "flex", alignItems: "center", padding: mediaInset }
1146
- ),
1147
- children: media
1148
- }
1149
- ) : /* @__PURE__ */ jsx(
761
+ media && (horizontal ? /* @__PURE__ */ jsx("div", { style: { flex: 1, minWidth: 0, display: "flex", alignItems: "center", padding: mediaInset }, children: media }) : /* @__PURE__ */ jsx(
1150
762
  "div",
1151
763
  {
1152
764
  style: /^(lucide|simple):/.test(mediaRef) ? { padding: `${AI_TREE_TOKENS.paddingBlock}px ${AI_TREE_TOKENS.paddingBlock}px 0` } : hasBg ? void 0 : { borderRadius: AI_TREE_TOKENS.radiusCard, overflow: "hidden" },
@@ -1237,44 +849,13 @@ function AccordionBlock({ node, ctx, path }) {
1237
849
  ) })
1238
850
  ] }, i)) });
1239
851
  }
1240
- function useIsMobile() {
1241
- const [mobile, setMobile] = React.useState(
1242
- () => typeof window !== "undefined" && window.matchMedia("(max-width: 768px)").matches
1243
- );
1244
- React.useEffect(() => {
1245
- const mq = window.matchMedia("(max-width: 768px)");
1246
- const update = () => setMobile(mq.matches);
1247
- update();
1248
- mq.addEventListener("change", update);
1249
- return () => mq.removeEventListener("change", update);
1250
- }, []);
1251
- return mobile;
1252
- }
1253
852
  function Carousel({ items, itemsPerRow, ctx }) {
1254
- const isMobile = useIsMobile();
1255
- const perPage = isMobile ? 1 : itemsPerRow;
1256
- const pages = Math.max(1, Math.ceil(items.length / perPage));
1257
853
  const [page, setPage] = React.useState(0);
854
+ const pages = Math.max(1, Math.ceil(items.length / itemsPerRow));
1258
855
  const current = Math.min(page, pages - 1);
1259
- if (pages <= 1) {
1260
- const cols = Math.max(1, Math.min(items.length, itemsPerRow));
1261
- return /* @__PURE__ */ jsx(
1262
- "div",
1263
- {
1264
- "data-ai-grid": String(cols),
1265
- style: {
1266
- display: "grid",
1267
- gridTemplateColumns: `repeat(${cols}, 1fr)`,
1268
- gap: AI_TREE_TOKENS.spacing8,
1269
- alignItems: "start"
1270
- },
1271
- children: items
1272
- }
1273
- );
1274
- }
1275
856
  const pageGroups = Array.from(
1276
857
  { length: pages },
1277
- (_, p) => items.slice(p * perPage, (p + 1) * perPage)
858
+ (_, p) => items.slice(p * itemsPerRow, (p + 1) * itemsPerRow)
1278
859
  );
1279
860
  const chrome = (enabled) => ({
1280
861
  border: `1px solid ${ctx.brand.palette.dark}`,
@@ -1299,69 +880,55 @@ function Carousel({ items, itemsPerRow, ctx }) {
1299
880
  cursor: "pointer",
1300
881
  padding: 0
1301
882
  });
1302
- const viewport = /* @__PURE__ */ jsx("div", { style: { flex: isMobile ? "0 0 auto" : 1, minWidth: 0, width: "100%", overflow: "hidden" }, children: /* @__PURE__ */ jsx(
1303
- "div",
1304
- {
1305
- style: {
1306
- display: "flex",
1307
- transform: `translateX(-${current * 100}%)`,
1308
- transition: "transform 0.4s ease"
1309
- },
1310
- children: pageGroups.map((group, p) => /* @__PURE__ */ jsx(
883
+ return /* @__PURE__ */ jsxs("div", { "data-ai-carousel": "", style: { display: "flex", flexDirection: "column", gap: AI_TREE_TOKENS.spacing8, alignItems: "center" }, children: [
884
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: AI_TREE_TOKENS.spacing6, width: "100%" }, children: [
885
+ /* @__PURE__ */ jsx(
886
+ "button",
887
+ {
888
+ type: "button",
889
+ "aria-label": "Previous",
890
+ onClick: () => setPage((p) => Math.max(0, p - 1)),
891
+ style: chrome(current > 0),
892
+ children: /* @__PURE__ */ jsx(ArrowLeft, { size: 24, strokeWidth: 1.5, "aria-hidden": true })
893
+ }
894
+ ),
895
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, minWidth: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx(
1311
896
  "div",
1312
897
  {
1313
- "data-ai-grid": String(perPage),
1314
898
  style: {
1315
- flex: "0 0 100%",
1316
- display: "grid",
1317
- gridTemplateColumns: `repeat(${perPage}, 1fr)`,
1318
- gap: AI_TREE_TOKENS.spacing8,
1319
- alignItems: "start"
899
+ display: "flex",
900
+ transform: `translateX(-${current * 100}%)`,
901
+ transition: "transform 0.4s ease"
1320
902
  },
1321
- children: group
1322
- },
1323
- p
1324
- ))
1325
- }
1326
- ) });
1327
- const prevBtn = /* @__PURE__ */ jsx(
1328
- "button",
1329
- {
1330
- type: "button",
1331
- "aria-label": "Previous",
1332
- onClick: () => setPage((p) => Math.max(0, p - 1)),
1333
- style: chrome(current > 0),
1334
- children: /* @__PURE__ */ jsx(ArrowLeft, { size: 24, strokeWidth: 1.5, "aria-hidden": true })
1335
- }
1336
- );
1337
- const nextBtn = /* @__PURE__ */ jsx(
1338
- "button",
1339
- {
1340
- type: "button",
1341
- "aria-label": "Next",
1342
- onClick: () => setPage((p) => Math.min(pages - 1, p + 1)),
1343
- style: chrome(current < pages - 1),
1344
- children: /* @__PURE__ */ jsx(ArrowRight, { size: 24, strokeWidth: 1.5, "aria-hidden": true })
1345
- }
1346
- );
1347
- const dots = /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 9, justifyContent: "center" }, children: pageGroups.map((_, p) => /* @__PURE__ */ jsx("button", { type: "button", "aria-label": `Page ${p + 1}`, onClick: () => setPage(p), style: dot(p === current) }, p)) });
1348
- if (isMobile) {
1349
- return /* @__PURE__ */ jsxs("div", { "data-ai-carousel": "", style: { display: "flex", flexDirection: "column", gap: AI_TREE_TOKENS.spacing6, alignItems: "center" }, children: [
1350
- viewport,
1351
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: AI_TREE_TOKENS.spacing6, justifyContent: "center" }, children: [
1352
- prevBtn,
1353
- nextBtn
1354
- ] }),
1355
- dots
1356
- ] });
1357
- }
1358
- return /* @__PURE__ */ jsxs("div", { "data-ai-carousel": "", style: { display: "flex", flexDirection: "column", gap: AI_TREE_TOKENS.spacing8, alignItems: "center" }, children: [
1359
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: AI_TREE_TOKENS.spacing6, width: "100%" }, children: [
1360
- prevBtn,
1361
- viewport,
1362
- nextBtn
903
+ children: pageGroups.map((group, p) => /* @__PURE__ */ jsx(
904
+ "div",
905
+ {
906
+ "data-ai-grid": String(itemsPerRow),
907
+ style: {
908
+ flex: "0 0 100%",
909
+ display: "grid",
910
+ gridTemplateColumns: `repeat(${itemsPerRow}, 1fr)`,
911
+ gap: AI_TREE_TOKENS.spacing8,
912
+ alignItems: "start"
913
+ },
914
+ children: group
915
+ },
916
+ p
917
+ ))
918
+ }
919
+ ) }),
920
+ /* @__PURE__ */ jsx(
921
+ "button",
922
+ {
923
+ type: "button",
924
+ "aria-label": "Next",
925
+ onClick: () => setPage((p) => Math.min(pages - 1, p + 1)),
926
+ style: chrome(current < pages - 1),
927
+ children: /* @__PURE__ */ jsx(ArrowRight, { size: 24, strokeWidth: 1.5, "aria-hidden": true })
928
+ }
929
+ )
1363
930
  ] }),
1364
- dots
931
+ pages > 1 && /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 9, justifyContent: "center" }, children: pageGroups.map((_, p) => /* @__PURE__ */ jsx("button", { type: "button", "aria-label": `Page ${p + 1}`, onClick: () => setPage(p), style: dot(p === current) }, p)) })
1365
932
  ] });
1366
933
  }
1367
934
  function CollectionBlock({ node, ctx, path }) {
@@ -1455,49 +1022,6 @@ function renderNode(node, ctx, path) {
1455
1022
  switch (node.type) {
1456
1023
  case "text":
1457
1024
  return /* @__PURE__ */ jsx(TextBlock, { slots, ctx, path });
1458
- // Layout container: arranges child blocks, contributes no content of its own. `grid` is a
1459
- // nested 12-column grid the children span (a collage is 3–5 media on it, bottom-aligned so
1460
- // mixed aspects read as a composition); `split` is exactly two children at a ratio; `stack`
1461
- // is a column. Children render through this same dispatcher, so edit markers, media
1462
- // resolution, and copy paths all work unchanged inside a group.
1463
- case "group": {
1464
- const layout = str(slots.layout);
1465
- const gap = slots.spacing === "tight" ? AI_TREE_TOKENS.spacing3 : slots.spacing === "airy" ? AI_TREE_TOKENS.spacing8 : AI_TREE_TOKENS.spacing6;
1466
- const kids = (node.children ?? []).map((child, i) => /* @__PURE__ */ jsx(
1467
- "div",
1468
- {
1469
- style: layout === "grid" ? {
1470
- gridColumn: `span ${typeof child.span === "number" ? Math.min(12, Math.max(1, child.span)) : 12}`,
1471
- minWidth: 0
1472
- } : { minWidth: 0 },
1473
- children: renderNode(child, ctx, `${path}.c${i}`)
1474
- },
1475
- i
1476
- ));
1477
- if (layout === "grid") {
1478
- return /* @__PURE__ */ jsx(
1479
- "div",
1480
- {
1481
- "data-ai-group": "grid",
1482
- style: { display: "grid", gridTemplateColumns: "repeat(12, 1fr)", gap, alignItems: "end" },
1483
- children: kids
1484
- }
1485
- );
1486
- }
1487
- if (layout === "split") {
1488
- const ratio = str(slots.ratio);
1489
- const cols = ratio === "3:5" ? "3fr 5fr" : ratio === "5:3" ? "5fr 3fr" : "1fr 1fr";
1490
- return /* @__PURE__ */ jsx(
1491
- "div",
1492
- {
1493
- "data-ai-group": "split",
1494
- style: { display: "grid", gridTemplateColumns: cols, gap, alignItems: "center" },
1495
- children: kids
1496
- }
1497
- );
1498
- }
1499
- return /* @__PURE__ */ jsx("div", { "data-ai-group": "stack", style: { display: "flex", flexDirection: "column", gap }, children: kids });
1500
- }
1501
1025
  case "button":
1502
1026
  return /* @__PURE__ */ jsx(ButtonEl, { slots, ctx, path });
1503
1027
  case "button-row":
@@ -1578,102 +1102,33 @@ function renderNode(node, ctx, path) {
1578
1102
  }
1579
1103
  );
1580
1104
  }
1581
- case "form": {
1582
- const formAttrs = ctx.keyFor ? {
1583
- "data-ohw-editable": "form",
1584
- "data-ohw-key": ctx.keyFor(`${path}.form`),
1585
- "data-ohw-success-text": "Thanks \u2014 we'll be in touch shortly."
1586
- } : {};
1587
- const fieldStyle = {
1588
- width: "100%",
1589
- boxSizing: "border-box",
1590
- border: `1px solid ${ctx.brand.palette.accent}`,
1591
- borderRadius: AI_TREE_TOKENS.radiusButton,
1592
- padding: "12px 14px",
1593
- background: "#fff",
1594
- color: ctx.brand.palette.dark,
1595
- outline: "none",
1596
- ...typeStyle(AI_TREE_TOKENS.type.bodyM, ctx.brand.fonts.body)
1597
- };
1598
- const labelStyle = {
1599
- ...typeStyle(AI_TREE_TOKENS.type.bodyMBold, ctx.brand.fonts.body),
1600
- color: ctx.brand.palette.dark
1601
- };
1602
- return /* @__PURE__ */ jsx(
1603
- "form",
1604
- {
1605
- ...formAttrs,
1606
- "data-ai-form": "",
1607
- style: {
1608
- display: "grid",
1609
- gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
1610
- columnGap: 64,
1611
- rowGap: AI_TREE_TOKENS.spacing4
1612
- },
1613
- children: (node.children ?? []).map((child, i) => {
1614
- if (child.type === "input") {
1615
- const cs2 = child.slots ?? {};
1616
- const kind = str(cs2.kind);
1617
- const label = str(cs2.label);
1618
- const placeholder = str(cs2.placeholder);
1619
- const name = label.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "") || `field-${i}`;
1620
- const isTextarea = kind === "textarea";
1621
- return /* @__PURE__ */ jsxs(
1622
- "div",
1623
- {
1624
- style: {
1625
- display: "flex",
1626
- flexDirection: "column",
1627
- gap: 8,
1628
- ...isTextarea ? { gridColumn: "1 / -1", maxWidth: 780 } : {}
1629
- },
1630
- children: [
1631
- /* @__PURE__ */ jsx("label", { ...textAttrs(ctx, `${path}.c${i}.label`), style: labelStyle, children: label }),
1632
- isTextarea ? /* @__PURE__ */ jsx(
1633
- "textarea",
1634
- {
1635
- name,
1636
- placeholder,
1637
- style: { ...fieldStyle, height: 140, resize: "vertical" }
1638
- }
1639
- ) : /* @__PURE__ */ jsx(
1640
- "input",
1641
- {
1642
- name,
1643
- type: kind === "email" ? "email" : "text",
1644
- placeholder,
1645
- style: { ...fieldStyle, height: 48 }
1646
- }
1647
- )
1648
- ]
1649
- },
1650
- i
1651
- );
1652
- }
1653
- const cs = child.slots ?? {};
1654
- return /* @__PURE__ */ jsx(
1655
- "button",
1105
+ case "form":
1106
+ return /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: AI_TREE_TOKENS.spacing4 }, children: (node.children ?? []).map((child, i) => {
1107
+ if (child.type === "input") {
1108
+ const cs = child.slots ?? {};
1109
+ return /* @__PURE__ */ jsxs("div", { children: [
1110
+ /* @__PURE__ */ jsx(
1111
+ "div",
1112
+ {
1113
+ ...textAttrs(ctx, `${path}.c${i}.label`),
1114
+ style: { ...typeStyle(AI_TREE_TOKENS.type.bodyMBold, ctx.brand.fonts.body), color: ctx.brand.palette.dark, marginBottom: 6 },
1115
+ children: str(cs.label)
1116
+ }
1117
+ ),
1118
+ /* @__PURE__ */ jsx(
1119
+ "div",
1656
1120
  {
1657
- type: "submit",
1658
1121
  style: {
1659
- gridColumn: "1 / -1",
1660
- justifySelf: "start",
1661
- border: "none",
1662
- cursor: "pointer",
1663
- padding: `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
1122
+ border: `1px solid ${ctx.brand.palette.accent}`,
1664
1123
  borderRadius: AI_TREE_TOKENS.radiusButton,
1665
- background: ctx.brand.palette.primary,
1666
- color: AI_TREE_TOKENS.textPrimaryForeground,
1667
- ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
1668
- },
1669
- children: /* @__PURE__ */ jsx("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
1670
- },
1671
- i
1672
- );
1673
- })
1124
+ height: cs.kind === "textarea" ? 96 : 42
1125
+ }
1126
+ }
1127
+ )
1128
+ ] }, i);
1674
1129
  }
1675
- );
1676
- }
1130
+ return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ButtonEl, { slots: child.slots ?? {}, ctx, path: `${path}.c${i}` }) }, i);
1131
+ }) });
1677
1132
  case "schedule-widget":
1678
1133
  return /* @__PURE__ */ jsx(
1679
1134
  "div",
@@ -1699,14 +1154,11 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1699
1154
  return null;
1700
1155
  }
1701
1156
  const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
1702
- const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
1703
- const blockBrand = band?.brand ?? resolvedBrand;
1704
1157
  const ctx = {
1705
- brand: blockBrand,
1158
+ brand: resolvedBrand,
1706
1159
  resolveMedia: resolveMedia ?? (() => null),
1707
- cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
1708
- keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
1709
- ...band ? { buttonLabel: band.buttonLabel } : {}
1160
+ cardSurface: resolvedBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${resolvedBrand.palette.light} 90%, ${resolvedBrand.palette.dark})`,
1161
+ keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null
1710
1162
  };
1711
1163
  const settings = tree.settings ?? {};
1712
1164
  const pad = AI_TREE_TOKENS.sectionPadding[settings.spacing ?? "balanced"];
@@ -1714,20 +1166,6 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1714
1166
  const overlayAlpha = { low: 0.25, medium: 0.45, high: 0.65 }[settings.overlayIntensity ?? "medium"];
1715
1167
  const backgroundUrl = isOverlay && settings.backgroundMedia ? ctx.resolveMedia(settings.backgroundMedia) : null;
1716
1168
  const bgAttrs = ctx.keyFor && isOverlay && settings.backgroundMedia ? { "data-ohw-key": ctx.keyFor("settings.backgroundMedia"), "data-ohw-editable": "bg-image" } : {};
1717
- const toneBackground = (() => {
1718
- const { dark, primary, light } = resolvedBrand.palette;
1719
- switch (settings.sectionBackground) {
1720
- case "surface":
1721
- return `color-mix(in srgb, ${light} 94%, ${dark})`;
1722
- case "accent":
1723
- return primary;
1724
- case "accent-soft":
1725
- return `color-mix(in srgb, ${primary} 12%, ${light})`;
1726
- default:
1727
- return void 0;
1728
- }
1729
- })();
1730
- const distributed = !isOverlay && settings.textDistribution;
1731
1169
  return /* @__PURE__ */ jsxs(
1732
1170
  "section",
1733
1171
  {
@@ -1737,15 +1175,13 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1737
1175
  style: {
1738
1176
  position: "relative",
1739
1177
  padding: `${pad}px 0`,
1740
- background: toneBackground ?? (isOverlay && !backgroundUrl ? "#DBEAFE" : void 0),
1178
+ background: isOverlay && !backgroundUrl ? "#DBEAFE" : void 0,
1741
1179
  backgroundImage: backgroundUrl ? `url(${backgroundUrl})` : void 0,
1742
1180
  backgroundSize: "cover",
1743
- backgroundPosition: "center",
1744
- color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
1181
+ backgroundPosition: "center"
1745
1182
  },
1746
1183
  children: [
1747
1184
  /* @__PURE__ */ jsx("style", { children: AI_RESPONSIVE_CSS }),
1748
- /* @__PURE__ */ jsx("style", { children: AI_MOBILE_CSS }),
1749
1185
  isOverlay && backgroundUrl && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
1750
1186
  /* @__PURE__ */ jsx(
1751
1187
  "div",
@@ -1766,24 +1202,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1766
1202
  display: "grid",
1767
1203
  gridTemplateColumns: "repeat(12, 1fr)",
1768
1204
  gap: AI_TREE_TOKENS.spacing6,
1769
- alignItems: distributed === "space-between" ? "stretch" : (distributed ?? settings.verticalPosition) === "top" ? "start" : "center",
1205
+ alignItems: settings.verticalPosition === "top" ? "start" : "center",
1770
1206
  marginTop: r2 > 0 ? AI_TREE_TOKENS.spacing8 : 0
1771
1207
  },
1772
- children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ jsx(
1773
- "div",
1774
- {
1775
- "data-ai-cell": "",
1776
- style: {
1777
- gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`,
1778
- minWidth: 0,
1779
- // space-between: each column becomes a flex column whose content spreads over
1780
- // the full row height instead of clumping at the top.
1781
- ...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
1782
- },
1783
- children: renderNode(block, ctx, `r${r2}.b${b}`)
1784
- },
1785
- b
1786
- ))
1208
+ children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ jsx("div", { style: { gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`, minWidth: 0 }, children: renderNode(block, ctx, `r${r2}.b${b}`) }, b))
1787
1209
  },
1788
1210
  r2
1789
1211
  ))
@@ -1799,36 +1221,17 @@ import { jsx as jsx2 } from "react/jsx-runtime";
1799
1221
  var CONTAINER_ATTR = "data-ohw-ai-generated";
1800
1222
  var REPLACED_ATTR = "data-ohw-ai-replaced-by";
1801
1223
  var REMOVED_ATTR = "data-ohw-ai-removed";
1802
- var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
1803
- var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
1804
- function readRootVar(name) {
1805
- if (typeof document === "undefined") return "";
1806
- return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
1807
- }
1808
- function deriveBrandOverride() {
1809
- const dark = readRootVar("--ohw-brand-dark");
1810
- const primary = readRootVar("--ohw-brand-primary");
1811
- const light = readRootVar("--ohw-brand-light");
1812
- if (!dark || !primary || !light) return null;
1813
- const accent = readRootVar("--ohw-brand-accent");
1814
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1815
- const body = readRootVar("--font-body");
1816
- return {
1817
- palette: { dark, primary, accent: accent || dark, light },
1818
- fonts: {
1819
- heading: heading || AI_DEFAULT_BRAND.fonts.heading,
1820
- body: body || AI_DEFAULT_BRAND.fonts.body
1821
- }
1822
- };
1823
- }
1824
1224
  function deriveTemplateBrand() {
1825
- const dark = readRootVar("--color-dark");
1826
- const primary = readRootVar("--color-primary");
1827
- const light = readRootVar("--color-light");
1225
+ if (typeof document === "undefined") return null;
1226
+ const cs = getComputedStyle(document.documentElement);
1227
+ const read = (name) => cs.getPropertyValue(name).trim();
1228
+ const dark = read("--color-dark");
1229
+ const primary = read("--color-primary");
1230
+ const light = read("--color-light");
1828
1231
  if (!dark || !primary || !light) return null;
1829
- const accent = readRootVar("--color-accent");
1830
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1831
- const body = readRootVar("--font-body");
1232
+ const accent = read("--color-accent");
1233
+ const heading = read("--font-heading") || read("--font-display");
1234
+ const body = read("--font-body");
1832
1235
  return {
1833
1236
  palette: { dark, primary, accent: accent || dark, light },
1834
1237
  fonts: {
@@ -1900,24 +1303,6 @@ function syncRemovedSections(state) {
1900
1303
  }
1901
1304
  }
1902
1305
  }
1903
- function syncTemplateHidden(state, pageHasSections) {
1904
- const hide = state.hideTemplate === true && pageHasSections;
1905
- for (const el of Array.from(document.querySelectorAll(`[${TEMPLATE_HIDDEN_ATTR}]`))) {
1906
- if (!hide) {
1907
- el.style.removeProperty("display");
1908
- el.removeAttribute(TEMPLATE_HIDDEN_ATTR);
1909
- }
1910
- }
1911
- if (!hide) return;
1912
- for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
1913
- if (el.hasAttribute(CONTAINER_ATTR)) continue;
1914
- if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
1915
- if (el.parentElement?.closest("[data-ohw-section]")) continue;
1916
- if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR)) continue;
1917
- el.style.display = "none";
1918
- el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
1919
- }
1920
- }
1921
1306
  function syncReplacedOriginals(state) {
1922
1307
  for (const el of document.querySelectorAll(`[${REPLACED_ATTR}]`)) {
1923
1308
  const byId = el.getAttribute(REPLACED_ATTR) ?? "";
@@ -1936,63 +1321,10 @@ function syncReplacedOriginals(state) {
1936
1321
  }
1937
1322
  }
1938
1323
  }
1939
- var sectionOrderIndex = /* @__PURE__ */ new Map();
1940
- function setAiSectionOrder(raw, currentPath) {
1941
- const next = /* @__PURE__ */ new Map();
1942
- if (raw) {
1943
- try {
1944
- const entries = JSON.parse(raw);
1945
- for (const entry of entries) {
1946
- if (!entry.pagePath || entry.pagePath === currentPath) next.set(entry.instanceId, entry.order);
1947
- }
1948
- } catch {
1949
- }
1950
- }
1951
- sectionOrderIndex = next;
1952
- }
1953
- function applyExplicitOrder(entries) {
1954
- if (sectionOrderIndex.size === 0) return entries;
1955
- return entries.map((entry, index) => ({ entry, index, order: sectionOrderIndex.get(entry.id) })).sort((a, b) => {
1956
- if (a.order === void 0 && b.order === void 0) return a.index - b.index;
1957
- if (a.order === void 0) return 1;
1958
- if (b.order === void 0) return -1;
1959
- return a.order - b.order;
1960
- }).map((item) => item.entry);
1961
- }
1962
- function orderByChain(sections) {
1963
- const ids = new Set(sections.map((entry) => entry.id));
1964
- const after = /* @__PURE__ */ new Map();
1965
- const roots = [];
1966
- for (const entry of sections) {
1967
- const anchor = entry.replaces ?? entry.beforeSection ?? entry.afterSection ?? null;
1968
- if (anchor && ids.has(anchor)) {
1969
- const bucket = after.get(anchor);
1970
- if (bucket) bucket.push(entry);
1971
- else after.set(anchor, [entry]);
1972
- } else {
1973
- roots.push(entry);
1974
- }
1975
- }
1976
- const out = [];
1977
- const seen = /* @__PURE__ */ new Set();
1978
- const visit = (entry) => {
1979
- if (seen.has(entry.id)) return;
1980
- seen.add(entry.id);
1981
- out.push(entry);
1982
- for (const child of after.get(entry.id) ?? []) visit(child);
1983
- };
1984
- for (const root of roots) visit(root);
1985
- return out.length === sections.length ? out : sections;
1986
- }
1987
1324
  function applyAiSectionsToDom(state, options) {
1988
1325
  if (typeof document === "undefined") return;
1989
- const brandOverride = deriveBrandOverride();
1990
1326
  const templateBrand = deriveTemplateBrand();
1991
- const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
1992
- const pagePath = window.location.pathname;
1993
- const pageSections = state.sections.filter((entry) => (entry.path ?? "/") === pagePath);
1994
- const activeIds = new Set(pageSections.map((entry) => entry.id));
1995
- const ordered = state.hideTemplate === true ? applyExplicitOrder(orderByChain(pageSections)) : pageSections;
1327
+ const activeIds = new Set(state.sections.map((entry) => entry.id));
1996
1328
  for (const [id, section] of mounted) {
1997
1329
  if (!activeIds.has(id)) {
1998
1330
  section.root.unmount();
@@ -2000,8 +1332,8 @@ function applyAiSectionsToDom(state, options) {
2000
1332
  mounted.delete(id);
2001
1333
  }
2002
1334
  }
2003
- for (const entry of ordered) {
2004
- const serialized = JSON.stringify(entry) + brandKey;
1335
+ for (const entry of state.sections) {
1336
+ const serialized = JSON.stringify(entry);
2005
1337
  const existing = mounted.get(entry.id);
2006
1338
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
2007
1339
  continue;
@@ -2026,7 +1358,7 @@ function applyAiSectionsToDom(state, options) {
2026
1358
  AiTreeRenderer,
2027
1359
  {
2028
1360
  tree: entry.tree,
2029
- brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1361
+ brand: entry.brand ?? options?.brand ?? templateBrand ?? void 0,
2030
1362
  resolveMedia,
2031
1363
  editKeyPrefix: `ai.${entry.id}`
2032
1364
  }
@@ -2035,20 +1367,8 @@ function applyAiSectionsToDom(state, options) {
2035
1367
  });
2036
1368
  mounted.set(entry.id, { root, container, serialized });
2037
1369
  }
2038
- if (state.hideTemplate === true) {
2039
- let prev = null;
2040
- for (const entry of ordered) {
2041
- const el = mounted.get(entry.id)?.container;
2042
- if (!el) continue;
2043
- if (prev && !(prev.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING)) {
2044
- prev.insertAdjacentElement("afterend", el);
2045
- }
2046
- prev = el;
2047
- }
2048
- }
2049
1370
  syncReplacedOriginals(state);
2050
1371
  syncRemovedSections(state);
2051
- syncTemplateHidden(state, pageSections.length > 0);
2052
1372
  }
2053
1373
 
2054
1374
  // src/useLinkHrefGuardian.ts
@@ -2655,7 +1975,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2655
1975
  const autoId = useId();
2656
1976
  const insertAfter = insertAfterProp ?? autoId;
2657
1977
  const [schedule, setSchedule] = useState2(null);
2658
- const [loading, setLoading] = useState2(initialScheduleId !== null);
1978
+ const [loading, setLoading] = useState2(true);
2659
1979
  const [inEditor, setInEditor] = useState2(false);
2660
1980
  const [isHovered, setIsHovered] = useState2(false);
2661
1981
  const [modalState, setModalState] = useState2(null);
@@ -2829,10 +2149,8 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2829
2149
  "*"
2830
2150
  );
2831
2151
  };
2152
+ if (!inEditor && !loading && !schedule) return null;
2832
2153
  const sectionId = `scheduling-${insertAfter}`;
2833
- if (!inEditor && !loading && !schedule) {
2834
- return /* @__PURE__ */ jsx4("section", { "data-ohw-section": sectionId, "data-ohw-scheduling-anchor": insertAfter, style: { display: "none" } });
2835
- }
2836
2154
  return /* @__PURE__ */ jsxs3(
2837
2155
  "section",
2838
2156
  {
@@ -7749,17 +7067,13 @@ function MediaOverlay({
7749
7067
  hover,
7750
7068
  isUploading,
7751
7069
  fadingOut = false,
7752
- selected = false,
7753
- hovered = false,
7754
7070
  onFadeOutComplete,
7755
7071
  onReplace,
7756
- onSelect,
7757
7072
  onVideoSettingsChange
7758
7073
  }) {
7759
7074
  const { rect } = hover;
7760
7075
  const skeletonRef = React8.useRef(null);
7761
7076
  const isVideo = hover.elementType === "video";
7762
- const showChrome = !selected || hovered;
7763
7077
  const autoplay = hover.videoAutoplay ?? true;
7764
7078
  const muted = hover.videoMuted ?? true;
7765
7079
  const probeRef = React8.useRef(null);
@@ -7773,7 +7087,6 @@ function MediaOverlay({
7773
7087
  (prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
7774
7088
  );
7775
7089
  }, [isVideo]);
7776
- const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
7777
7090
  const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
7778
7091
  const box = {
7779
7092
  position: "fixed",
@@ -7807,7 +7120,7 @@ function MediaOverlay({
7807
7120
  }
7808
7121
  );
7809
7122
  }
7810
- const settingsBar = isVideo && !hover.isDragOver && showChrome ? /* @__PURE__ */ jsxs7(
7123
+ const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ jsxs7(
7811
7124
  "div",
7812
7125
  {
7813
7126
  "data-ohw-bridge": "",
@@ -7877,12 +7190,10 @@ function MediaOverlay({
7877
7190
  // in-document, pointer-events does it natively. The button below opts back in, so
7878
7191
  // Replace still works.
7879
7192
  pointerEvents: hover.hasTextOverlap ? "none" : "auto",
7880
- // Selected: a firm component ring with no wash, so the image reads as chosen rather
7881
- // than hovered. Hover keeps the existing tinted preview.
7882
- boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
7883
- background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7193
+ boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
7194
+ background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7884
7195
  },
7885
- onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
7196
+ onClick: () => onReplace(hover.key),
7886
7197
  children: [
7887
7198
  /* @__PURE__ */ jsxs7(
7888
7199
  Button,
@@ -7903,17 +7214,17 @@ function MediaOverlay({
7903
7214
  },
7904
7215
  children: [
7905
7216
  isVideo ? /* @__PURE__ */ jsx15(Film, { size: 14 }) : /* @__PURE__ */ jsx15(ImageIcon, { size: 14 }),
7906
- replaceLabel
7217
+ isVideo ? "Replace video" : "Replace image"
7907
7218
  ]
7908
7219
  }
7909
7220
  ),
7910
- showChrome && replaceMode !== "none" && /* @__PURE__ */ jsxs7(
7221
+ replaceMode === "none" ? null : /* @__PURE__ */ jsxs7(
7911
7222
  Button,
7912
7223
  {
7913
7224
  "data-ohw-media-overlay": "",
7914
7225
  variant: "outline",
7915
7226
  size: "sm",
7916
- "aria-label": replaceLabel,
7227
+ "aria-label": isVideo ? "Replace video" : "Replace image",
7917
7228
  className: "gap-1.5 cursor-pointer hover:bg-background",
7918
7229
  style: {
7919
7230
  ...OVERLAY_BUTTON_STYLE,
@@ -7936,7 +7247,7 @@ function MediaOverlay({
7936
7247
  },
7937
7248
  children: [
7938
7249
  isVideo ? /* @__PURE__ */ jsx15(Film, { size: 14 }) : /* @__PURE__ */ jsx15(ImageIcon, { size: 14 }),
7939
- replaceMode === "full" ? replaceLabel : null
7250
+ replaceMode === "full" ? isVideo ? "Replace video" : "Replace image" : null
7940
7251
  ]
7941
7252
  }
7942
7253
  )
@@ -8020,8 +7331,6 @@ function parseSectionsFromRoot(root) {
8020
7331
  const id = el.getAttribute("data-ohw-section") ?? "";
8021
7332
  if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
8022
7333
  if (el.parentElement?.closest("[data-ohw-section]")) continue;
8023
- if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
8024
- continue;
8025
7334
  seen.add(id);
8026
7335
  const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
8027
7336
  sections.push({ id, label });
@@ -8051,10 +7360,6 @@ function topLevelSections() {
8051
7360
  function instanceIdOf(el) {
8052
7361
  return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
8053
7362
  }
8054
- function findByInstanceId(instanceId) {
8055
- const escapedId = CSS.escape(instanceId);
8056
- return document.querySelector(`[data-ohw-instance="${escapedId}"]`) ?? document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
8057
- }
8058
7363
  function planSectionMove(instanceId, targetIndex, currentPath) {
8059
7364
  const sections = topLevelSections();
8060
7365
  const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
@@ -8090,7 +7395,7 @@ function syncRemovedFlags(entries) {
8090
7395
  }
8091
7396
  });
8092
7397
  for (const id of removedIds) {
8093
- const el = findByInstanceId(id);
7398
+ const el = document.querySelector(`[data-ohw-instance="${CSS.escape(id)}"]`);
8094
7399
  if (el) {
8095
7400
  el.style.display = "none";
8096
7401
  el.setAttribute(REMOVED_ATTR2, "");
@@ -8118,7 +7423,9 @@ function applyPersistedOrder(entries) {
8118
7423
  }
8119
7424
  }
8120
7425
  function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
8121
- if (!findByInstanceId(instanceId)) return null;
7426
+ const escapedId = CSS.escape(instanceId);
7427
+ if (!document.querySelector(`[data-ohw-instance="${escapedId}"]`) && !document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`))
7428
+ return null;
8122
7429
  const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
8123
7430
  const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
8124
7431
  (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
@@ -8307,7 +7614,6 @@ function AiSectionOverlay({
8307
7614
  }) {
8308
7615
  const [selectedId, setSelectedId] = useState5(null);
8309
7616
  const [reviewId, setReviewId] = useState5(null);
8310
- const [reviewButtonsHidden, setReviewButtonsHidden] = useState5(false);
8311
7617
  const reviewIdRef = useRef4(null);
8312
7618
  reviewIdRef.current = reviewId;
8313
7619
  const selectedIdRef = useRef4(null);
@@ -8369,7 +7675,6 @@ function AiSectionOverlay({
8369
7675
  }
8370
7676
  const found = readRect(sectionId) != null;
8371
7677
  setReviewId(found ? sectionId : null);
8372
- setReviewButtonsHidden(e.data.hideButtons === true);
8373
7678
  postToParent2({ type: "ow:ai-review-started", sectionId, found });
8374
7679
  if (found) {
8375
7680
  document.querySelector(`[data-ohw-instance="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
@@ -8497,16 +7802,13 @@ function AiSectionOverlay({
8497
7802
  border: `2px solid ${PRIMARY2}`,
8498
7803
  borderRadius: edgeAwareRadius(reviewRect),
8499
7804
  zIndex: 2147483200,
8500
- // The veil itself: swallows clicks so the section stays locked until decided. This
8501
- // stopPropagation only guards the bubble phase; the bridge's capture-phase click
8502
- // handlers additionally bail on `[data-ohw-ai-review]`, without which a click on
8503
- // Accept/Discard resolves to the media beneath and opens the file picker.
7805
+ // The veil itself: swallows clicks so the section stays locked until decided.
8504
7806
  background: "rgba(8, 133, 254, 0.04)",
8505
7807
  pointerEvents: "auto",
8506
7808
  cursor: "default"
8507
7809
  },
8508
7810
  onClick: (e) => e.stopPropagation(),
8509
- children: !reviewButtonsHidden && /* @__PURE__ */ jsxs9(
7811
+ children: /* @__PURE__ */ jsxs9(
8510
7812
  "div",
8511
7813
  {
8512
7814
  style: {
@@ -11073,13 +10375,8 @@ function referenceBox(slot) {
11073
10375
  const neighbour = row ? Array.from(row.querySelectorAll('[data-ohw-editable="icon"]')).find(
11074
10376
  (el) => el !== slot && !el.hasAttribute("data-ohw-social-icon-placeholder")
11075
10377
  ) : null;
11076
- if (neighbour) {
11077
- const box2 = neighbour.querySelector(GLYPH_SELECTOR)?.getBoundingClientRect();
11078
- if (box2?.width && box2.height) return box2;
11079
- }
11080
- const own = slot.getBoundingClientRect();
11081
- if (own.width && own.height) return own;
11082
- const box = slot.querySelector(GLYPH_SELECTOR)?.getBoundingClientRect() ?? null;
10378
+ const source = (neighbour ?? slot).querySelector(GLYPH_SELECTOR);
10379
+ const box = source?.getBoundingClientRect() ?? null;
11083
10380
  return box?.width && box.height ? box : null;
11084
10381
  }
11085
10382
  function iconMarkupSizedFor(slot, markup) {
@@ -12880,7 +12177,6 @@ function readLogoSizeState(content, placement) {
12880
12177
  function getLogoElement(el) {
12881
12178
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
12882
12179
  if (marked) return marked;
12883
- if (el.closest('[data-ohw-editable="icon"]')) return null;
12884
12180
  const root = el.closest("nav, [data-ohw-nav-root], footer");
12885
12181
  if (!root) return null;
12886
12182
  const anchor = el.closest("a");
@@ -13955,7 +13251,6 @@ function useSectionDrag({
13955
13251
  }
13956
13252
  const orderJson = JSON.stringify(entries);
13957
13253
  editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
13958
- setAiSectionOrder(orderJson, window.location.pathname);
13959
13254
  postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
13960
13255
  applyPersistedOrder(entries);
13961
13256
  clearSectionDragVisuals();
@@ -14815,10 +14110,21 @@ function parseSchedulingInsertAfter(insertAfter) {
14815
14110
  insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
14816
14111
  };
14817
14112
  }
14818
- function resolveEntryAnchor(entry) {
14819
- if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
14820
- const parsed = parseSchedulingInsertAfter(entry.insertAfter);
14821
- return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
14113
+ function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
14114
+ const parsed = parseSchedulingInsertAfter(insertAfter);
14115
+ const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
14116
+ const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
14117
+ return { effectiveInsertAfter, insertBefore };
14118
+ }
14119
+ function getSchedulingMountPoint(insertAfter) {
14120
+ const { anchor } = parseSchedulingInsertAfter(insertAfter);
14121
+ let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
14122
+ if (!anchorEl && anchor === "scheduling") {
14123
+ const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
14124
+ anchorEl = widgets.at(-1) ?? null;
14125
+ }
14126
+ if (!anchorEl) return null;
14127
+ return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
14822
14128
  }
14823
14129
  function schedulingMountDepth(insertAfter) {
14824
14130
  if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
@@ -14835,7 +14141,8 @@ function getPageSchedulingEntries(raw) {
14835
14141
  }
14836
14142
  }
14837
14143
  function isSchedulingWidgetMissing(entry) {
14838
- return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
14144
+ const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
14145
+ return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
14839
14146
  }
14840
14147
  function hasMissingSchedulingWidgets(entries) {
14841
14148
  return entries.some(isSchedulingWidgetMissing);
@@ -14865,17 +14172,16 @@ function initSectionsFromContent(content, removeExisting = false) {
14865
14172
  } catch {
14866
14173
  }
14867
14174
  }
14868
- function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
14869
- const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
14870
- const sectionId = schedulingSectionId(widgetId);
14175
+ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
14176
+ const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
14177
+ const sectionId = schedulingSectionId(effectiveInsertAfter);
14871
14178
  if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
14872
- const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
14873
- if (!anchorEl) return false;
14874
- const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
14179
+ const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
14180
+ if (!mountPoint) return false;
14875
14181
  const container = document.createElement("div");
14876
14182
  container.dataset.ohwSectionContainer = "scheduling";
14877
- if (beforeId) {
14878
- const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
14183
+ if (insertBefore) {
14184
+ const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
14879
14185
  const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
14880
14186
  if (!beforePoint) return false;
14881
14187
  beforePoint.insertAdjacentElement("beforebegin", container);
@@ -14886,25 +14192,19 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14886
14192
  }
14887
14193
  tail.insertAdjacentElement("afterend", container);
14888
14194
  }
14889
- try {
14890
- const root = createRoot2(container);
14891
- flushSync2(() => {
14892
- root.render(
14893
- /* @__PURE__ */ jsx33(
14894
- SchedulingWidget,
14895
- {
14896
- notifyOnConnect,
14897
- initialScheduleId: scheduleId,
14898
- insertAfter: widgetId
14899
- }
14900
- )
14901
- );
14902
- });
14903
- } catch (err) {
14904
- console.error("[ow:scheduling] render threw", err);
14905
- container.remove();
14906
- return false;
14907
- }
14195
+ const root = createRoot2(container);
14196
+ flushSync2(() => {
14197
+ root.render(
14198
+ /* @__PURE__ */ jsx33(
14199
+ SchedulingWidget,
14200
+ {
14201
+ notifyOnConnect,
14202
+ initialScheduleId: scheduleId,
14203
+ insertAfter: effectiveInsertAfter
14204
+ }
14205
+ )
14206
+ );
14207
+ });
14908
14208
  const tracker = getSectionsTracker();
14909
14209
  let sections = [];
14910
14210
  try {
@@ -14912,12 +14212,10 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14912
14212
  } catch {
14913
14213
  }
14914
14214
  const inEditor = typeof window !== "undefined" && window.self !== window.top;
14915
- if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
14215
+ if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
14916
14216
  sections.push({
14917
14217
  type: "scheduling",
14918
- insertAfter: widgetId,
14919
- anchorId,
14920
- beforeId: beforeId ?? null,
14218
+ insertAfter: effectiveInsertAfter,
14921
14219
  pagePath: window.location.pathname,
14922
14220
  ...scheduleId ? { scheduleId } : {}
14923
14221
  });
@@ -14931,8 +14229,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
14931
14229
  for (let i = pending.length - 1; i >= 0; i--) {
14932
14230
  const entry = pending[i];
14933
14231
  const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
14934
- const { anchorId, beforeId } = resolveEntryAnchor(entry);
14935
- if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
14232
+ if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId)) {
14936
14233
  pending.splice(i, 1);
14937
14234
  }
14938
14235
  }
@@ -15090,11 +14387,6 @@ function applyLinkByKey(key, val) {
15090
14387
  hrefAnchors.forEach((el) => applyLinkHref(el, val));
15091
14388
  }
15092
14389
  }
15093
- function isInsideLinkEditor(target) {
15094
- return Boolean(
15095
- target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest("[data-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest("[data-ohw-more-menu]") || target.closest('[data-slot="dropdown-menu-content"]') || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
15096
- );
15097
- }
15098
14390
  function isInsideFloatingPanel(target) {
15099
14391
  return Boolean(target.closest("[data-ohw-floating-panel]"));
15100
14392
  }
@@ -15102,6 +14394,11 @@ function isPointOverFloatingPanel(clientX, clientY) {
15102
14394
  const el = document.elementFromPoint(clientX, clientY);
15103
14395
  return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
15104
14396
  }
14397
+ function isInsideLinkEditor(target) {
14398
+ return Boolean(
14399
+ target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest("[data-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest("[data-ohw-more-menu]") || target.closest('[data-slot="dropdown-menu-content"]') || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
14400
+ );
14401
+ }
15105
14402
  function getHrefKeyFromElement(el) {
15106
14403
  if (!el) return null;
15107
14404
  const anchor = el.closest("[data-ohw-href-key]");
@@ -15360,7 +14657,7 @@ function getNavigationSelectionParent(el) {
15360
14657
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
15361
14658
  return getFooterLinksContainer();
15362
14659
  }
15363
- if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup2(el)) {
14660
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
15364
14661
  return getNavigationRoot(el);
15365
14662
  }
15366
14663
  return null;
@@ -15575,6 +14872,7 @@ var ICONS = {
15575
14872
  insertUnorderedList: '<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>',
15576
14873
  insertOrderedList: '<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'
15577
14874
  };
14875
+ var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
15578
14876
  var SELECTION_CHROME_GAP2 = 4;
15579
14877
  var TOOLBAR_STROKE_GAP2 = 4;
15580
14878
  var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
@@ -15954,7 +15252,6 @@ function StateToggle({
15954
15252
  );
15955
15253
  }
15956
15254
  var contentCache = /* @__PURE__ */ new Map();
15957
- var fetchedContentPaths = /* @__PURE__ */ new Set();
15958
15255
  var OHW_LOADER_STYLE = {
15959
15256
  position: "fixed",
15960
15257
  inset: 0,
@@ -16073,70 +15370,6 @@ function OhhwellsBridge() {
16073
15370
  const hoveredImageHasTextOverlapRef = useRef10(false);
16074
15371
  const dragOverElRef = useRef10(null);
16075
15372
  const [mediaHover, setMediaHover] = useState13(null);
16076
- const [selectedMedia, setSelectedMedia] = useState13(null);
16077
- const selectedMediaElRef = useRef10(null);
16078
- const clearMediaSelection = useCallback8(() => {
16079
- const prev = selectedMediaElRef.current;
16080
- selectedMediaElRef.current = null;
16081
- setSelectedMedia(null);
16082
- const sectionEl = prev?.closest("[data-ohw-section]") ?? null;
16083
- if (sectionEl) {
16084
- postToParentRef.current({
16085
- type: "ow:section-selected",
16086
- sectionId: sectionEl.dataset.ohwSection ?? null,
16087
- sectionLabel: sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? ""),
16088
- key: null
16089
- });
16090
- }
16091
- }, []);
16092
- const clearMediaSelectionRef = useRef10(clearMediaSelection);
16093
- clearMediaSelectionRef.current = clearMediaSelection;
16094
- const selectMediaElement = useCallback8((el) => {
16095
- const r2 = el.getBoundingClientRect();
16096
- const video = el.dataset.ohwEditable === "video" ? el.querySelector("video") : null;
16097
- selectedMediaElRef.current = el;
16098
- setSelectedMedia({
16099
- key: el.dataset.ohwKey ?? "",
16100
- rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
16101
- elementType: el.dataset.ohwEditable ?? "image",
16102
- hasTextOverlap: false,
16103
- isDragOver: false,
16104
- ...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
16105
- });
16106
- const sectionEl = el.closest("[data-ohw-section]");
16107
- aiSectionApiRef.current?.selectFromElement(el, { report: false });
16108
- postToParentRef.current({
16109
- type: "ow:section-selected",
16110
- sectionId: sectionEl?.dataset.ohwSection ?? null,
16111
- sectionLabel: sectionEl ? sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? "") : null,
16112
- key: el.dataset.ohwKey ?? null,
16113
- // Display name for the pill — the raw key prettifies into fragments ("Img"); the
16114
- // bridge knows what the node IS, so it names it.
16115
- keyLabel: el.dataset.ohwEditable === "video" ? "Video" : el.dataset.ohwEditable === "bg-image" ? "Background" : "Image"
16116
- });
16117
- }, []);
16118
- const selectMediaElementRef = useRef10(selectMediaElement);
16119
- selectMediaElementRef.current = selectMediaElement;
16120
- useEffect13(() => {
16121
- if (!selectedMedia) return;
16122
- const update = () => {
16123
- const el = selectedMediaElRef.current;
16124
- if (!el || !el.isConnected) {
16125
- clearMediaSelection();
16126
- return;
16127
- }
16128
- const r2 = el.getBoundingClientRect();
16129
- setSelectedMedia(
16130
- (prev) => prev ? { ...prev, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } } : prev
16131
- );
16132
- };
16133
- window.addEventListener("scroll", update, true);
16134
- window.addEventListener("resize", update);
16135
- return () => {
16136
- window.removeEventListener("scroll", update, true);
16137
- window.removeEventListener("resize", update);
16138
- };
16139
- }, [selectedMedia !== null]);
16140
15373
  const [carouselHover, setCarouselHover] = useState13(null);
16141
15374
  const [uploadingRects, setUploadingRects] = useState13({});
16142
15375
  const hoveredGapRef = useRef10(null);
@@ -16399,6 +15632,13 @@ function OhhwellsBridge() {
16399
15632
  const [isItemDragging, setIsItemDragging] = useState13(false);
16400
15633
  const [isFooterFrameSelection, setIsFooterFrameSelection] = useState13(false);
16401
15634
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
15635
+ const [floatingPanel, setFloatingPanel] = useState13(null);
15636
+ const floatingPanelOpenRef = useRef10(false);
15637
+ floatingPanelOpenRef.current = floatingPanel !== null;
15638
+ const [floatingPanelPos, setFloatingPanelPos] = useState13(null);
15639
+ const [logoSizeDraft, setLogoSizeDraft] = useState13(null);
15640
+ const [editorViewport, setEditorViewport] = useState13("desktop");
15641
+ const [parentScrollSnap, setParentScrollSnap] = useState13(null);
16402
15642
  const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState13(null);
16403
15643
  const [footerHeadingVisible, setFooterHeadingVisible] = useState13(null);
16404
15644
  const footerDragRef = useRef10(null);
@@ -16413,16 +15653,7 @@ function OhhwellsBridge() {
16413
15653
  const addNavAfterAnchorRef = useRef10(null);
16414
15654
  const editContentRef = useRef10({});
16415
15655
  const aiSectionsRef = useRef10("");
16416
- const brandKitRef = useRef10("");
16417
- const stylesRef = useRef10("");
16418
15656
  const pendingDeleteUndoRef = useRef10(null);
16419
- const [floatingPanel, setFloatingPanel] = useState13(null);
16420
- const floatingPanelOpenRef = useRef10(false);
16421
- const setFloatingPanelRef = useRef10(setFloatingPanel);
16422
- const [floatingPanelPos, setFloatingPanelPos] = useState13(null);
16423
- const [logoSizeDraft, setLogoSizeDraft] = useState13(null);
16424
- const [editorViewport, setEditorViewport] = useState13("desktop");
16425
- const [parentScrollSnap, setParentScrollSnap] = useState13(null);
16426
15657
  const [sitePages, setSitePages] = useState13([]);
16427
15658
  const [sectionsByPath, setSectionsByPath] = useState13({});
16428
15659
  const sectionsPrefetchGenRef = useRef10(0);
@@ -16431,18 +15662,7 @@ function OhhwellsBridge() {
16431
15662
  const linkPopoverOpenRef = useRef10(false);
16432
15663
  const linkPopoverGraceUntilRef = useRef10(0);
16433
15664
  setLinkPopoverRef.current = setLinkPopover;
16434
- setFloatingPanelRef.current = setFloatingPanel;
16435
15665
  linkPopoverSessionRef.current = linkPopover;
16436
- floatingPanelOpenRef.current = Boolean(floatingPanel);
16437
- useEffect13(() => {
16438
- const syncViewport = () => {
16439
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
16440
- setEditorViewport((prev) => prev === next ? prev : next);
16441
- };
16442
- syncViewport();
16443
- window.addEventListener("resize", syncViewport);
16444
- return () => window.removeEventListener("resize", syncViewport);
16445
- }, []);
16446
15666
  const {
16447
15667
  navDragRef,
16448
15668
  navDropSlots,
@@ -17753,31 +16973,15 @@ function OhhwellsBridge() {
17753
16973
  }
17754
16974
  const applyContent = (content) => {
17755
16975
  const imageLoads = [];
17756
- if (typeof content[BRAND_KIT_KEY] === "string") {
17757
- brandKitRef.current = content[BRAND_KIT_KEY];
17758
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17759
- } else {
17760
- brandKitRef.current = "";
17761
- applyBrandToDom(null);
17762
- }
17763
16976
  if (typeof content[AI_SECTIONS_KEY] === "string") {
17764
16977
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
17765
- setAiSectionOrder(content[SECTION_ORDER_KEY], window.location.pathname);
17766
16978
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
17767
16979
  }
17768
- if (typeof content[STYLE_STORE_KEY] === "string") {
17769
- stylesRef.current = content[STYLE_STORE_KEY];
17770
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17771
- }
17772
- applyBrandChrome(content);
17773
16980
  for (const [key, val] of Object.entries(content)) {
17774
16981
  if (key === "__ohw_sections") continue;
17775
16982
  if (key === AI_SECTIONS_KEY) continue;
17776
16983
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17777
16984
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17778
- if (key === BRAND_KIT_KEY) continue;
17779
- if (key === STYLE_STORE_KEY) continue;
17780
- if (BRAND_CHROME_KEYS.has(key)) continue;
17781
16985
  if (applyVideoSettingNode(key, val)) continue;
17782
16986
  if (applyCarouselNode(key, val)) continue;
17783
16987
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17843,9 +17047,7 @@ function OhhwellsBridge() {
17843
17047
  let cancelled = false;
17844
17048
  setFetchState("loading");
17845
17049
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17846
- const initialPath = pathname;
17847
- fetchedContentPaths.add(`${subdomain}::${initialPath}`);
17848
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17050
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17849
17051
  if (cancelled) return;
17850
17052
  const content = data?.content ?? {};
17851
17053
  contentCache.set(subdomain, content);
@@ -17965,28 +17167,10 @@ function OhhwellsBridge() {
17965
17167
  initSectionInstancesFromContent(content, window.location.pathname);
17966
17168
  observer?.disconnect();
17967
17169
  try {
17968
- applyBrandChrome(content);
17969
- if (typeof content[BRAND_KIT_KEY] === "string") {
17970
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17971
- } else {
17972
- applyBrandToDom(null);
17973
- }
17974
- if (typeof content[AI_SECTIONS_KEY] === "string") {
17975
- setAiSectionOrder(content[SECTION_ORDER_KEY], window.location.pathname);
17976
- applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
17977
- }
17978
- if (typeof content[STYLE_STORE_KEY] === "string") {
17979
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17980
- }
17981
17170
  for (const [key, val] of Object.entries(content)) {
17982
17171
  if (key === "__ohw_sections") continue;
17983
- if (key === AI_SECTIONS_KEY) continue;
17984
17172
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17985
17173
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17986
- if (key === BRAND_KIT_KEY) continue;
17987
- if (key === STYLE_STORE_KEY) continue;
17988
- if (key === STYLE_STORE_KEY) continue;
17989
- if (BRAND_CHROME_KEYS.has(key)) continue;
17990
17174
  if (applyVideoSettingNode(key, val)) continue;
17991
17175
  if (applyCarouselNode(key, val)) continue;
17992
17176
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -18032,17 +17216,6 @@ function OhhwellsBridge() {
18032
17216
  debounceTimer = setTimeout(applyFromCache, 150);
18033
17217
  };
18034
17218
  applyFromCache();
18035
- const pathCacheKey = `${subdomain}::${pathname}`;
18036
- if (!fetchedContentPaths.has(pathCacheKey)) {
18037
- fetchedContentPaths.add(pathCacheKey);
18038
- const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
18039
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
18040
- if (!data?.content) return;
18041
- contentCache.set(subdomain, data.content);
18042
- applyFromCache();
18043
- }).catch(() => {
18044
- });
18045
- }
18046
17219
  observer = new MutationObserver(scheduleApply);
18047
17220
  observer.observe(document.body, { childList: true, subtree: true });
18048
17221
  return () => {
@@ -18138,31 +17311,30 @@ function OhhwellsBridge() {
18138
17311
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
18139
17312
  useEffect13(() => {
18140
17313
  if (!isEditMode) return;
18141
- let lastPosted = 0;
18142
17314
  const measure = () => {
18143
17315
  const h = document.body.scrollHeight;
18144
- if (h > 50 && Math.abs(h - lastPosted) > 1) {
18145
- lastPosted = h;
18146
- postToParent2({ type: "ow:height", height: h });
18147
- }
18148
- };
18149
- let raf = null;
18150
- const schedule = () => {
18151
- if (raf != null) return;
18152
- raf = requestAnimationFrame(() => {
18153
- raf = null;
18154
- measure();
18155
- });
17316
+ if (h > 50) postToParent2({ type: "ow:height", height: h });
18156
17317
  };
18157
17318
  const t1 = setTimeout(measure, 50);
18158
17319
  const t2 = setTimeout(measure, 500);
18159
- const ro = new ResizeObserver(schedule);
18160
- ro.observe(document.body);
17320
+ let lastWidth = window.innerWidth;
17321
+ let resizeTimers = [];
17322
+ const clearResizeTimers = () => {
17323
+ resizeTimers.forEach(clearTimeout);
17324
+ resizeTimers = [];
17325
+ };
17326
+ const handleResize = () => {
17327
+ if (window.innerWidth === lastWidth) return;
17328
+ lastWidth = window.innerWidth;
17329
+ clearResizeTimers();
17330
+ resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
17331
+ };
17332
+ window.addEventListener("resize", handleResize);
18161
17333
  return () => {
18162
17334
  clearTimeout(t1);
18163
17335
  clearTimeout(t2);
18164
- if (raf != null) cancelAnimationFrame(raf);
18165
- ro.disconnect();
17336
+ clearResizeTimers();
17337
+ window.removeEventListener("resize", handleResize);
18166
17338
  };
18167
17339
  }, [pathname, isEditMode, postToParent2]);
18168
17340
  useEffect13(() => {
@@ -18403,7 +17575,6 @@ function OhhwellsBridge() {
18403
17575
  return;
18404
17576
  }
18405
17577
  const target = e.target;
18406
- if (target.closest("[data-ohw-ai-review]")) return;
18407
17578
  if (target.closest("[data-ohw-toolbar]")) return;
18408
17579
  if (target.closest("[data-ohw-state-toggle]")) return;
18409
17580
  if (target.closest("[data-ohw-max-badge]")) return;
@@ -18415,9 +17586,6 @@ function OhhwellsBridge() {
18415
17586
  )) {
18416
17587
  return;
18417
17588
  }
18418
- if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
18419
- clearMediaSelectionRef.current();
18420
- }
18421
17589
  {
18422
17590
  const formEl = getFormElement(target);
18423
17591
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -18569,14 +17737,19 @@ function OhhwellsBridge() {
18569
17737
  }
18570
17738
  const clickedButton = findClosestButtonLike(target);
18571
17739
  const buttonOnMedia = Boolean(clickedButton && isMediaEditable(editable) && editable.contains(clickedButton));
17740
+ console.log("[click-debug]", {
17741
+ editableType: editable.dataset.ohwEditable,
17742
+ editableTag: editable.tagName,
17743
+ targetTag: target.tagName,
17744
+ clickedButtonTag: clickedButton?.tagName ?? null,
17745
+ buttonOnMedia,
17746
+ isMediaEditableEditable: isMediaEditable(editable)
17747
+ });
18572
17748
  if (isMediaEditable(editable) && !buttonOnMedia) {
18573
17749
  e.preventDefault();
18574
17750
  e.stopPropagation();
18575
- if (selectedMediaElRef.current === editable) {
18576
- postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
18577
- } else {
18578
- selectMediaElementRef.current(editable);
18579
- }
17751
+ aiSectionApiRef.current?.selectFromElement(editable);
17752
+ postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
18580
17753
  return;
18581
17754
  }
18582
17755
  const socialItem = getSocialItem(editable);
@@ -18595,6 +17768,11 @@ function OhhwellsBridge() {
18595
17768
  const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
18596
17769
  const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
18597
17770
  const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
17771
+ console.log("[click-debug 2]", {
17772
+ hrefLookupTargetTag: hrefLookupTarget.tagName,
17773
+ hrefCtx: hrefCtx ? { key: hrefCtx.key } : null,
17774
+ navAnchorTag: navAnchor?.tagName ?? null
17775
+ });
18598
17776
  if (navAnchor) {
18599
17777
  e.preventDefault();
18600
17778
  e.stopPropagation();
@@ -18712,7 +17890,6 @@ function OhhwellsBridge() {
18712
17890
  };
18713
17891
  const handleDblClick = (e) => {
18714
17892
  const target = e.target;
18715
- if (target.closest("[data-ohw-ai-review]")) return;
18716
17893
  if (target.closest("[data-ohw-toolbar]")) return;
18717
17894
  if (target.closest("[data-ohw-state-toggle]")) return;
18718
17895
  if (target.closest("[data-ohw-max-badge]")) return;
@@ -18764,9 +17941,6 @@ function OhhwellsBridge() {
18764
17941
  setHoveredItemRect(null);
18765
17942
  hoveredNavContainerRef.current = null;
18766
17943
  setHoveredNavContainerRect(null);
18767
- siblingHintElRef.current = null;
18768
- setSiblingHintRect(null);
18769
- setSiblingHintRects([]);
18770
17944
  return;
18771
17945
  }
18772
17946
  {
@@ -18885,6 +18059,7 @@ function OhhwellsBridge() {
18885
18059
  hoveredNavContainerRef.current = null;
18886
18060
  setHoveredNavContainerRect(null);
18887
18061
  hoveredItemElRef.current = editable;
18062
+ setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
18888
18063
  }
18889
18064
  }
18890
18065
  }
@@ -19181,7 +18356,7 @@ function OhhwellsBridge() {
19181
18356
  }
19182
18357
  };
19183
18358
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
19184
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
18359
+ if (linkPopoverOpenRef.current) {
19185
18360
  if (hoveredImageRef.current) {
19186
18361
  hoveredImageRef.current = null;
19187
18362
  hoveredImageHasTextOverlapRef.current = false;
@@ -19515,9 +18690,7 @@ function OhhwellsBridge() {
19515
18690
  return;
19516
18691
  }
19517
18692
  const { y } = toProbeCoords(clientX, clientY, fromParentViewport);
19518
- const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
19519
- (el) => !el.hasAttribute("data-ohw-ai-template-hidden") && !el.hasAttribute("data-ohw-ai-removed") && !el.hasAttribute("data-ohw-ai-replaced-by") && el.getBoundingClientRect().height > 0
19520
- ).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
18693
+ const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
19521
18694
  const ZONE = 20;
19522
18695
  for (let i = 0; i < sections.length; i++) {
19523
18696
  const a = sections[i];
@@ -19546,7 +18719,8 @@ function OhhwellsBridge() {
19546
18719
  };
19547
18720
  const handleMouseMove = (e) => {
19548
18721
  const { clientX, clientY } = e;
19549
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
18722
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
18723
+ if (isOverEditorChrome(clientX, clientY)) {
19550
18724
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
19551
18725
  formHoverElRef.current = null;
19552
18726
  setFormHoverRect(null);
@@ -19554,12 +18728,6 @@ function OhhwellsBridge() {
19554
18728
  setHoveredItemRect(null);
19555
18729
  hoveredNavContainerRef.current = null;
19556
18730
  setHoveredNavContainerRect(null);
19557
- siblingHintElRef.current = null;
19558
- setSiblingHintRect(null);
19559
- setSiblingHintRects([]);
19560
- dismissImageHover();
19561
- clearImageHover();
19562
- setSectionGap(null);
19563
18731
  return;
19564
18732
  }
19565
18733
  if (probeSocialsRowAt(clientX, clientY)) return;
@@ -19571,11 +18739,7 @@ function OhhwellsBridge() {
19571
18739
  if (e.data?.type !== "ow:pointer-sync") return;
19572
18740
  const { clientX, clientY } = e.data;
19573
18741
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
19574
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
19575
- dismissImageHover();
19576
- clearImageHover();
19577
- return;
19578
- }
18742
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
19579
18743
  if (probeSocialsRowAt(clientX, clientY)) return;
19580
18744
  probeSectionGapAt(clientX, clientY);
19581
18745
  probeImageAt(clientX, clientY);
@@ -19858,23 +19022,10 @@ function OhhwellsBridge() {
19858
19022
  if (e.data?.type !== "ow:hydrate") return;
19859
19023
  const content = e.data.content;
19860
19024
  if (!content) return;
19861
- if (typeof content[BRAND_KIT_KEY] === "string") {
19862
- brandKitRef.current = content[BRAND_KIT_KEY];
19863
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
19864
- } else {
19865
- brandKitRef.current = "";
19866
- applyBrandToDom(null);
19867
- }
19868
19025
  if (typeof content[AI_SECTIONS_KEY] === "string") {
19869
19026
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
19870
- setAiSectionOrder(content[SECTION_ORDER_KEY], window.location.pathname);
19871
19027
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
19872
19028
  }
19873
- if (typeof content[STYLE_STORE_KEY] === "string") {
19874
- stylesRef.current = content[STYLE_STORE_KEY];
19875
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
19876
- }
19877
- applyBrandChrome(content);
19878
19029
  let sectionsJson = null;
19879
19030
  for (const [key, val] of Object.entries(content)) {
19880
19031
  if (key === "__ohw_sections") {
@@ -19884,9 +19035,6 @@ function OhhwellsBridge() {
19884
19035
  if (key === AI_SECTIONS_KEY) continue;
19885
19036
  if (key === LOGO_PLACEHOLDER_KEY) continue;
19886
19037
  if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
19887
- if (key === BRAND_KIT_KEY) continue;
19888
- if (key === STYLE_STORE_KEY) continue;
19889
- if (BRAND_CHROME_KEYS.has(key)) continue;
19890
19038
  if (applyVideoSettingNode(key, val)) continue;
19891
19039
  if (applyCarouselNode(key, val)) continue;
19892
19040
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -19900,8 +19048,6 @@ function OhhwellsBridge() {
19900
19048
  if (video && video.src !== val) applyVideoSrc(video, val);
19901
19049
  } else if (el.dataset.ohwEditable === "link") {
19902
19050
  applyLinkHref(el, val);
19903
- } else if (el.dataset.ohwEditable === "icon") {
19904
- applyIconMarkup(el, val);
19905
19051
  } else if (isIconMarkupValue(val)) {
19906
19052
  } else {
19907
19053
  el.innerHTML = val;
@@ -19986,21 +19132,12 @@ function OhhwellsBridge() {
19986
19132
  nodes: collectEditableNodes(editContentRef.current)
19987
19133
  });
19988
19134
  };
19989
- const clearInteractionChrome = () => {
19990
- deactivateRef.current();
19991
- deselectRef.current();
19992
- clearMediaSelectionRef.current();
19993
- };
19994
19135
  const handleAiApplyTree = (e) => {
19995
19136
  if (e.data?.type !== "ow:ai-apply-tree") return;
19996
19137
  const payload = e.data.payload;
19997
19138
  if (!payload || typeof payload.id !== "string" || !isRenderableTree(payload.tree)) return;
19998
- clearInteractionChrome();
19999
19139
  const previous = aiSectionsRef.current;
20000
- const nextState = applyTreeToState(parseAiSectionsState(previous), {
20001
- ...payload,
20002
- path: payload.path ?? window.location.pathname
20003
- });
19140
+ const nextState = applyTreeToState(parseAiSectionsState(previous), payload);
20004
19141
  const nextValue = serializeAiSectionsState(nextState);
20005
19142
  aiSectionsRef.current = nextValue;
20006
19143
  applyAiSectionsToDom(nextState);
@@ -20021,7 +19158,6 @@ function OhhwellsBridge() {
20021
19158
  const exists = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
20022
19159
  if (!exists) return;
20023
19160
  if (isPageFrameSection(exists)) return;
20024
- clearInteractionChrome();
20025
19161
  const previous = aiSectionsRef.current;
20026
19162
  const nextState = deleteSectionFromState(parseAiSectionsState(previous), sectionId);
20027
19163
  const nextValue = serializeAiSectionsState(nextState);
@@ -20037,10 +19173,8 @@ function OhhwellsBridge() {
20037
19173
  const handleAiSetSections = (e) => {
20038
19174
  if (e.data?.type !== "ow:ai-set-sections") return;
20039
19175
  const value = typeof e.data.value === "string" ? e.data.value : "";
20040
- clearInteractionChrome();
20041
19176
  aiSectionsRef.current = value;
20042
19177
  applyAiSectionsToDom(parseAiSectionsState(value));
20043
- applyStylesToDom(parseStyleStore(stylesRef.current));
20044
19178
  const restoredHeight = document.body.scrollHeight;
20045
19179
  if (restoredHeight > 50) postToParentRef.current({ type: "ow:height", height: restoredHeight });
20046
19180
  postToParentRef.current({ type: "ow:change", nodes: [{ key: AI_SECTIONS_KEY, text: value }] });
@@ -20056,40 +19190,10 @@ function OhhwellsBridge() {
20056
19190
  if (!entries) return;
20057
19191
  const orderJson = JSON.stringify(entries);
20058
19192
  editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
20059
- setAiSectionOrder(orderJson, window.location.pathname);
20060
19193
  postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
20061
19194
  window.dispatchEvent(new Event("resize"));
20062
19195
  };
20063
19196
  window.addEventListener("message", handleMoveSection);
20064
- const handleAiSetBrand = (e) => {
20065
- if (e.data?.type !== "ow:ai-set-brand") return;
20066
- const value = typeof e.data.value === "string" ? e.data.value : "";
20067
- const previous = brandKitRef.current;
20068
- brandKitRef.current = value;
20069
- applyBrandToDom(parseBrandKit(value));
20070
- if (aiSectionsRef.current) applyAiSectionsToDom(parseAiSectionsState(aiSectionsRef.current));
20071
- applyStylesToDom(parseStyleStore(stylesRef.current));
20072
- postToParentRef.current({ type: "ow:change", nodes: [{ key: BRAND_KIT_KEY, text: value }] });
20073
- postToParentRef.current({ type: "ow:ai-brand-applied", previous, value });
20074
- };
20075
- window.addEventListener("message", handleAiSetBrand);
20076
- const handleAiSetStyles = (e) => {
20077
- if (e.data?.type !== "ow:ai-set-styles") return;
20078
- const value = typeof e.data.value === "string" ? e.data.value : "";
20079
- const previous = stylesRef.current;
20080
- stylesRef.current = value;
20081
- applyStylesToDom(parseStyleStore(value));
20082
- postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
20083
- postToParentRef.current({ type: "ow:ai-styles-applied", previous, value });
20084
- };
20085
- window.addEventListener("message", handleAiSetStyles);
20086
- const handleGetBrand = (e) => {
20087
- if (e.data?.type !== "ow:get-brand") return;
20088
- const template = deriveTemplateBrand();
20089
- const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
20090
- postToParentRef.current({ type: "ow:brand-value", value });
20091
- };
20092
- window.addEventListener("message", handleGetBrand);
20093
19197
  const handlePanelDragging = (e) => {
20094
19198
  if (e.data?.type !== "ow:panel-dragging") return;
20095
19199
  if (e.data.dragging) document.documentElement.setAttribute("data-ohw-panel-dragging", "");
@@ -20147,15 +19251,8 @@ function OhhwellsBridge() {
20147
19251
  closeLinkPopoverRef.current();
20148
19252
  return;
20149
19253
  }
20150
- if (floatingPanelOpenRef.current) {
20151
- setFloatingPanelRef.current(null);
20152
- deselectRef.current();
20153
- deactivateRef.current();
20154
- return;
20155
- }
20156
19254
  deselectRef.current();
20157
19255
  deactivateRef.current();
20158
- clearMediaSelectionRef.current();
20159
19256
  };
20160
19257
  window.addEventListener("message", handleDeactivate);
20161
19258
  const handleToastAction = (e) => {
@@ -20241,10 +19338,6 @@ function OhhwellsBridge() {
20241
19338
  const handleKeyDown = (e) => {
20242
19339
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
20243
19340
  if (e.key === "Escape" && document.querySelector("[data-ohw-more-menu]")) return;
20244
- if (e.key === "Escape" && selectedMediaElRef.current) {
20245
- clearMediaSelectionRef.current();
20246
- return;
20247
- }
20248
19341
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
20249
19342
  e.preventDefault();
20250
19343
  selectAllTextInEditable(activeElRef.current);
@@ -20404,12 +19497,6 @@ function OhhwellsBridge() {
20404
19497
  if (aiSectionsRef.current) {
20405
19498
  nodes.push({ key: AI_SECTIONS_KEY, type: "sections", text: aiSectionsRef.current });
20406
19499
  }
20407
- if (stylesRef.current) {
20408
- nodes.push({ key: STYLE_STORE_KEY, type: "styles", text: stylesRef.current });
20409
- }
20410
- if (brandKitRef.current) {
20411
- nodes.push({ key: BRAND_KIT_KEY, type: "brand", text: brandKitRef.current });
20412
- }
20413
19500
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
20414
19501
  const formKey = formKeyOf(form);
20415
19502
  if (!formKey) return;
@@ -20427,12 +19514,8 @@ function OhhwellsBridge() {
20427
19514
  if (inserted) {
20428
19515
  const tracker = getSectionsTracker();
20429
19516
  postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
20430
- const reportHeight = () => {
20431
- const h = document.body.scrollHeight;
20432
- if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
20433
- };
20434
- reportHeight();
20435
- setTimeout(reportHeight, 500);
19517
+ const h = document.body.scrollHeight;
19518
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
20436
19519
  }
20437
19520
  };
20438
19521
  const handleSwitchSchedule = (e) => {
@@ -20829,16 +19912,13 @@ function OhhwellsBridge() {
20829
19912
  window.removeEventListener("message", handleAiDeleteSection);
20830
19913
  window.removeEventListener("message", handleAiSetSections);
20831
19914
  window.removeEventListener("message", handleMoveSection);
20832
- window.removeEventListener("message", handleAiSetBrand);
20833
- window.removeEventListener("message", handleAiSetStyles);
20834
- window.removeEventListener("message", handleGetBrand);
20835
19915
  window.removeEventListener("message", handlePanelDragging);
20836
19916
  window.removeEventListener("message", handleDeleteSection);
20837
19917
  window.removeEventListener("message", handleDeactivate);
19918
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
20838
19919
  window.removeEventListener("message", handleToastAction);
20839
19920
  window.removeEventListener("message", handleFormCount);
20840
19921
  window.removeEventListener("message", handleUiEscape);
20841
- document.documentElement.removeAttribute("data-ohw-panel-dragging");
20842
19922
  autoSaveTimers.current.forEach(clearTimeout);
20843
19923
  autoSaveTimers.current.clear();
20844
19924
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
@@ -21448,22 +20528,11 @@ function OhhwellsBridge() {
21448
20528
  const showEditLink = toolbarShowEditLink;
21449
20529
  const currentSections = sectionsByPath[pathname] ?? [];
21450
20530
  linkPopoverOpenRef.current = linkPopover !== null;
21451
- const handleMediaSelect = useCallback8((key) => {
21452
- const el = hoveredImageRef.current?.dataset.ohwKey === key ? hoveredImageRef.current : Array.from(document.querySelectorAll(MEDIA_SELECTOR)).find(
21453
- (m) => (m.dataset.ohwKey ?? "") === key
21454
- ) ?? null;
21455
- if (!el) return;
21456
- selectMediaElementRef.current(el);
21457
- }, []);
21458
20531
  const handleMediaReplace = useCallback8(
21459
20532
  (key) => {
21460
- postToParent2({
21461
- type: "ow:image-pick",
21462
- key,
21463
- elementType: mediaHover?.elementType ?? selectedMedia?.elementType ?? "image"
21464
- });
20533
+ postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
21465
20534
  },
21466
- [postToParent2, mediaHover?.elementType, selectedMedia?.elementType]
20535
+ [postToParent2, mediaHover?.elementType]
21467
20536
  );
21468
20537
  const handleEditCarousel = useCallback8(
21469
20538
  (key) => {
@@ -21535,25 +20604,12 @@ function OhhwellsBridge() {
21535
20604
  },
21536
20605
  `uploading-${key}`
21537
20606
  )),
21538
- mediaHover && !(mediaHover.key in uploadingRects) && mediaHover.key !== selectedMedia?.key && /* @__PURE__ */ jsx33(
20607
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx33(
21539
20608
  MediaOverlay,
21540
20609
  {
21541
20610
  hover: mediaHover,
21542
20611
  isUploading: false,
21543
20612
  onReplace: handleMediaReplace,
21544
- onSelect: handleMediaSelect,
21545
- onVideoSettingsChange: handleVideoSettingsChange
21546
- }
21547
- ),
21548
- selectedMedia && !(selectedMedia.key in uploadingRects) && !linkPopover && /* @__PURE__ */ jsx33(
21549
- MediaOverlay,
21550
- {
21551
- hover: selectedMedia,
21552
- selected: true,
21553
- hovered: mediaHover?.key === selectedMedia.key,
21554
- isUploading: false,
21555
- onReplace: handleMediaReplace,
21556
- onSelect: handleMediaSelect,
21557
20613
  onVideoSettingsChange: handleVideoSettingsChange
21558
20614
  }
21559
20615
  ),
@@ -21959,59 +21015,6 @@ function OhhwellsBridge() {
21959
21015
  ) : null
21960
21016
  ] });
21961
21017
  }
21962
-
21963
- // src/ui/EmptySection.tsx
21964
- import Link3 from "next/link";
21965
- import { Fragment as Fragment9, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
21966
- function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
21967
- return /* @__PURE__ */ jsxs21(Fragment9, { children: [
21968
- /* @__PURE__ */ jsx34(
21969
- "p",
21970
- {
21971
- style: {
21972
- fontFamily: "var(--brand-font-body)",
21973
- fontSize: "0.75rem",
21974
- fontWeight: 500,
21975
- letterSpacing: "0.15em",
21976
- textTransform: "uppercase",
21977
- color: "var(--brand-accent)",
21978
- marginBottom: "1.5rem"
21979
- },
21980
- children: /* @__PURE__ */ jsx34(Link3, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ jsx34("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
21981
- }
21982
- ),
21983
- /* @__PURE__ */ jsx34(
21984
- "h1",
21985
- {
21986
- style: {
21987
- fontFamily: "var(--brand-font-heading)",
21988
- fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
21989
- lineHeight: 1.1,
21990
- letterSpacing: "-0.025em",
21991
- color: "var(--brand-text)",
21992
- marginBottom: "1rem"
21993
- },
21994
- ...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
21995
- children: title
21996
- }
21997
- ),
21998
- /* @__PURE__ */ jsx34(
21999
- "p",
22000
- {
22001
- style: {
22002
- fontFamily: "var(--brand-font-body)",
22003
- fontSize: "1rem",
22004
- lineHeight: 1.7,
22005
- fontWeight: 300,
22006
- color: "var(--brand-text-muted)",
22007
- maxWidth: "340px"
22008
- },
22009
- ...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
22010
- children: "This page doesn't have any content yet."
22011
- }
22012
- )
22013
- ] });
22014
- }
22015
21018
  export {
22016
21019
  AI_DEFAULT_BRAND,
22017
21020
  AI_TREE_SCHEMA_VERSIONS,
@@ -22028,7 +21031,6 @@ export {
22028
21031
  DropdownMenuItem,
22029
21032
  DropdownMenuSeparator,
22030
21033
  DropdownMenuTrigger,
22031
- EmptySection,
22032
21034
  ItemActionToolbar,
22033
21035
  ItemInteractionLayer,
22034
21036
  LinkEditorPanel,