@ohhwells/bridge 0.1.113-next.297 → 0.1.114

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -46,7 +46,6 @@ __export(index_exports, {
46
46
  DropdownMenuItem: () => DropdownMenuItem,
47
47
  DropdownMenuSeparator: () => DropdownMenuSeparator,
48
48
  DropdownMenuTrigger: () => DropdownMenuTrigger,
49
- EmptySection: () => EmptySection,
50
49
  ItemActionToolbar: () => ItemActionToolbar,
51
50
  ItemInteractionLayer: () => ItemInteractionLayer,
52
51
  LinkEditorPanel: () => LinkEditorPanel,
@@ -105,10 +104,6 @@ function enforceLinkHrefs() {
105
104
 
106
105
  // src/lib/ai-tree.ts
107
106
  var AI_TREE_SCHEMA_VERSIONS = [1];
108
- var BUTTON_FILL_TOKENS = ["dark", "primary", "accent", "light"];
109
- var BUTTON_STYLES = ["solid", "outline", "ghost"];
110
- var BUTTON_RADII = ["square", "rounded", "pill"];
111
- var BUTTON_SIZES = ["s", "m", "l"];
112
107
  var AI_DEFAULT_BRAND = {
113
108
  palette: { dark: "#0C0A09", primary: "#0078E5", accent: "#747271", light: "#ECECEB" },
114
109
  fonts: {
@@ -357,70 +352,16 @@ var LEGACY_BRAND_VAR_NAMES = [
357
352
  "text-muted",
358
353
  "surface",
359
354
  "border",
360
- "on-primary"
355
+ "on-primary",
356
+ "navbar-background"
361
357
  ].map((role) => `--brand-${role}`);
362
358
  var FONT_VARS = {
363
359
  heading: ["--font-heading", "--font-display", "--brand-font-heading"],
364
360
  body: ["--font-body", "--brand-font-body"]
365
361
  };
366
362
  var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
367
- var CUSTOM_FONT_STYLE_ID = "ohw-brand-custom-fonts";
368
- var CUSTOM_FONT_FORMATS = /* @__PURE__ */ new Set(["woff2", "woff", "truetype", "opentype"]);
369
- var BUTTON_FILL_VAR = {
370
- dark: "var(--brand-text)",
371
- primary: "var(--brand-primary)",
372
- accent: "var(--brand-accent)",
373
- light: "var(--brand-background)"
374
- };
375
- var BUTTON_RADIUS_PX = {
376
- square: 0,
377
- rounded: AI_TREE_TOKENS.radiusButton,
378
- pill: 999
379
- };
380
- var BUTTON_SIZE_SPEC = {
381
- s: {
382
- paddingX: `${AI_TREE_TOKENS.spacing4}px`,
383
- paddingY: `${AI_TREE_TOKENS.spacing2}px`,
384
- fontSize: "14px"
385
- },
386
- m: {
387
- paddingX: `${AI_TREE_TOKENS.spacing6}px`,
388
- paddingY: `${AI_TREE_TOKENS.spacing3}px`,
389
- fontSize: `${AI_TREE_TOKENS.type.button.size}px`
390
- },
391
- l: {
392
- paddingX: `${AI_TREE_TOKENS.spacing8}px`,
393
- paddingY: `${AI_TREE_TOKENS.spacing4}px`,
394
- fontSize: "18px"
395
- }
396
- };
397
- var BUTTON_VAR_ROLES = ["bg", "text", "border", "radius", "padding-x", "padding-y", "font-size"];
398
- var BUTTON_VAR_NAMES = ["primary", "secondary"].flatMap(
399
- (variant) => BUTTON_VAR_ROLES.map((role) => `--brand-button-${variant}-${role}`)
400
- );
401
- function buttonVariantVars(variant, style) {
402
- const fill = BUTTON_FILL_VAR[style.fill];
403
- const text = BUTTON_FILL_VAR[style.textColor];
404
- const size = BUTTON_SIZE_SPEC[style.size];
405
- const { bg, border } = style.style === "outline" ? { bg: "transparent", border: fill } : style.style === "ghost" ? { bg: "transparent", border: "transparent" } : { bg: fill, border: "transparent" };
406
- return {
407
- [`--brand-button-${variant}-bg`]: bg,
408
- [`--brand-button-${variant}-text`]: text,
409
- [`--brand-button-${variant}-border`]: border,
410
- [`--brand-button-${variant}-radius`]: `${BUTTON_RADIUS_PX[style.radius]}px`,
411
- [`--brand-button-${variant}-padding-x`]: size.paddingX,
412
- [`--brand-button-${variant}-padding-y`]: size.paddingY,
413
- [`--brand-button-${variant}-font-size`]: size.fontSize
414
- };
415
- }
416
- function buttonStyleVars(buttons) {
417
- return {
418
- ...buttonVariantVars("primary", buttons.primary),
419
- ...buttonVariantVars("secondary", buttons.secondary)
420
- };
421
- }
422
- function brandColorVars(palette) {
423
- const { dark, primary, accent, light } = palette;
363
+ function brandColorVars(kit) {
364
+ const { dark, primary, accent, light } = kit.palette;
424
365
  const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
425
366
  const surface = mix(light, 95, dark);
426
367
  const border = mix(light, 85, dark);
@@ -443,50 +384,22 @@ function brandColorVars(palette) {
443
384
  "--brand-border": border,
444
385
  // Buttons/bands painted in the primary colour assume it's dark/saturated enough to need
445
386
  // light text on top — the same assumption LOGO_IMAGE's light-on-dark navbar mark makes.
446
- "--brand-on-primary": light
387
+ "--brand-on-primary": light,
388
+ "--brand-navbar-background": dark
447
389
  };
448
390
  }
449
- function isButtonStyle(value) {
450
- if (!value || typeof value !== "object") return false;
451
- const v = value;
452
- return BUTTON_FILL_TOKENS.includes(v.fill) && BUTTON_FILL_TOKENS.includes(v.textColor) && BUTTON_STYLES.includes(v.style) && BUTTON_RADII.includes(v.radius) && BUTTON_SIZES.includes(v.size);
453
- }
454
- function parseCustomFontWeight(raw) {
455
- if (typeof raw !== "object" || raw === null) return null;
456
- const w = raw;
457
- if (typeof w.weight !== "number" || !Number.isFinite(w.weight)) return null;
458
- if (typeof w.url !== "string" || !w.url) return null;
459
- if (typeof w.format !== "string" || !CUSTOM_FONT_FORMATS.has(w.format)) return null;
460
- const weightEnd = typeof w.weightEnd === "number" && Number.isFinite(w.weightEnd) && w.weightEnd > w.weight ? w.weightEnd : void 0;
461
- return { weight: w.weight, ...weightEnd !== void 0 ? { weightEnd } : {}, url: w.url, format: w.format };
462
- }
463
- function parseCustomFont(raw) {
464
- if (typeof raw !== "object" || raw === null) return null;
465
- const f = raw;
466
- if (typeof f.family !== "string" || !f.family) return null;
467
- if (typeof f.label !== "string" || !f.label) return null;
468
- if (!Array.isArray(f.weights)) return null;
469
- const weights = f.weights.map(parseCustomFontWeight).filter((w) => w !== null);
470
- if (weights.length === 0) return null;
471
- return { family: f.family, label: f.label, weights };
472
- }
473
391
  function parseBrandKit(raw) {
474
392
  if (!raw) return null;
475
393
  try {
476
394
  const parsed = JSON.parse(raw);
477
395
  const p = parsed?.palette;
478
396
  const f = parsed?.fonts;
479
- const palette = p && typeof p.dark === "string" && typeof p.primary === "string" && typeof p.accent === "string" && typeof p.light === "string" ? { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light } : void 0;
480
- const fonts = f && typeof f.heading === "string" && typeof f.body === "string" ? { heading: f.heading, body: f.body } : void 0;
481
- const customFonts = Array.isArray(parsed?.customFonts) ? parsed.customFonts.map(parseCustomFont).filter((c) => c !== null) : void 0;
482
- const b = parsed?.buttons;
483
- const buttons = b && isButtonStyle(b.primary) && isButtonStyle(b.secondary) ? { primary: b.primary, secondary: b.secondary } : void 0;
484
- if (!palette && !fonts && !customFonts && !buttons) return null;
397
+ 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") {
398
+ return null;
399
+ }
485
400
  return {
486
- ...palette ? { palette } : {},
487
- ...fonts ? { fonts } : {},
488
- ...customFonts ? { customFonts } : {},
489
- ...buttons ? { buttons } : {}
401
+ palette: { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light },
402
+ fonts: { heading: f.heading, body: f.body }
490
403
  };
491
404
  } catch {
492
405
  return null;
@@ -496,16 +409,11 @@ function familyOf(stack) {
496
409
  const first = stack.split(",")[0]?.trim() ?? "";
497
410
  return first.replace(/^['"]|['"]$/g, "");
498
411
  }
499
- function quoteFamily(family) {
500
- return `'${family.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
501
- }
502
- var WEIGHT_SCALE = [100, 200, 300, 400, 500, 600, 700, 800, 900];
503
412
  function loadBrandFonts(families) {
504
413
  const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
505
414
  if (unique.length === 0) return;
506
- const weights = WEIGHT_SCALE.join(";");
507
- const spec = unique.map((f) => `family=${f.replace(/ /g, "+")}:wght@${weights}`).join("&");
508
- const href = `https://fonts.googleapis.com/css2?${spec}&display=swap`;
415
+ const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
416
+ const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
509
417
  let link = document.getElementById(BRAND_FONT_LINK_ID);
510
418
  if (!link) {
511
419
  link = document.createElement("link");
@@ -515,59 +423,18 @@ function loadBrandFonts(families) {
515
423
  }
516
424
  if (link.href !== href) link.href = href;
517
425
  }
518
- function escapeCssString(value) {
519
- return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
520
- }
521
- function loadCustomFonts(fonts) {
522
- const list = fonts ?? [];
523
- let style = document.getElementById(CUSTOM_FONT_STYLE_ID);
524
- if (list.length === 0) {
525
- style?.remove();
526
- return;
527
- }
528
- if (!style) {
529
- style = document.createElement("style");
530
- style.id = CUSTOM_FONT_STYLE_ID;
531
- document.head.appendChild(style);
532
- }
533
- style.textContent = list.flatMap(
534
- (font) => font.weights.map((w) => {
535
- const weightDescriptor = w.weightEnd ? `${w.weight} ${w.weightEnd}` : `${w.weight}`;
536
- return `@font-face { font-family: '${escapeCssString(font.family)}'; src: url('${escapeCssString(w.url)}') format('${w.format}'); font-weight: ${weightDescriptor}; font-display: swap; }`;
537
- })
538
- ).join("\n");
539
- }
540
426
  function applyBrandToDom(kit) {
541
427
  const root = document.documentElement;
542
428
  if (!kit) {
543
- for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES, ...BUTTON_VAR_NAMES]) {
544
- root.style.removeProperty(name);
545
- }
429
+ for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES]) root.style.removeProperty(name);
546
430
  for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
547
431
  document.getElementById(BRAND_FONT_LINK_ID)?.remove();
548
- document.getElementById(CUSTOM_FONT_STYLE_ID)?.remove();
549
432
  return;
550
433
  }
551
- if (kit.palette) {
552
- for (const [name, value] of Object.entries(brandColorVars(kit.palette))) root.style.setProperty(name, value);
553
- }
554
- if (kit.buttons) {
555
- for (const [name, value] of Object.entries(buttonStyleVars(kit.buttons))) root.style.setProperty(name, value);
556
- }
557
- if (kit.customFonts) {
558
- loadCustomFonts(kit.customFonts);
559
- }
560
- if (kit.fonts) {
561
- const heading = quoteFamily(kit.fonts.heading);
562
- const body = quoteFamily(kit.fonts.body);
563
- for (const name of FONT_VARS.heading) root.style.setProperty(name, heading);
564
- for (const name of FONT_VARS.body) root.style.setProperty(name, body);
565
- const customFamilies = new Set((kit.customFonts ?? []).map((f) => f.family));
566
- const googleFamilies = [familyOf(kit.fonts.heading), familyOf(kit.fonts.body)].filter(
567
- (f) => !customFamilies.has(f)
568
- );
569
- loadBrandFonts(googleFamilies);
570
- }
434
+ for (const [name, value] of Object.entries(brandColorVars(kit))) root.style.setProperty(name, value);
435
+ for (const name of FONT_VARS.heading) root.style.setProperty(name, kit.fonts.heading);
436
+ for (const name of FONT_VARS.body) root.style.setProperty(name, kit.fonts.body);
437
+ loadBrandFonts([familyOf(kit.fonts.heading), familyOf(kit.fonts.body)]);
571
438
  }
572
439
 
573
440
  // src/lib/section-styles.ts
@@ -592,20 +459,6 @@ var BG_VALUES = {
592
459
  accent: "var(--ohw-brand-primary, var(--color-primary, #0078E5))",
593
460
  "accent-soft": "color-mix(in srgb, var(--ohw-brand-primary, var(--color-primary, #0078E5)) 12%, var(--ohw-brand-light, var(--color-light, #FFFFFF)))"
594
461
  };
595
- var NAVBAR_COLOR_TOKENS = ["dark", "primary", "accent", "light"];
596
- function navbarColorVar(token) {
597
- const fallback = {
598
- dark: "#0C0A09",
599
- primary: "#0078E5",
600
- accent: "#0078E5",
601
- light: "#FFFFFF"
602
- };
603
- return `var(--ohw-brand-${token}, var(--color-${token}, ${fallback[token]}))`;
604
- }
605
- function resolveNavbarValue(value) {
606
- if (value === void 0) return void 0;
607
- return NAVBAR_COLOR_TOKENS.includes(value) ? navbarColorVar(value) : value;
608
- }
609
462
  var HEADLINE_SIZES = { md: 24, lg: 32, xl: 40, display: 56 };
610
463
  function styleSheetCss() {
611
464
  const rules = [];
@@ -682,6 +535,7 @@ var NODE_PROPS = [
682
535
  "color",
683
536
  "font-family",
684
537
  "font-size",
538
+ "background",
685
539
  "text-align",
686
540
  "justify-content",
687
541
  "align-items"
@@ -731,6 +585,9 @@ function clearNodeProps(root) {
731
585
  h.removeAttribute(NODE_WROTE_ATTR);
732
586
  }
733
587
  }
588
+ function buttonSurfaceOf(el) {
589
+ return el.closest("a, button") ?? el;
590
+ }
734
591
  function alignSubjectOf(el) {
735
592
  const button = el.closest('[data-ohw-role="button"]');
736
593
  if (button?.parentElement) return button.parentElement;
@@ -771,18 +628,8 @@ function applyStylesToDom(store) {
771
628
  for (const [sectionId, override] of Object.entries(store.sections)) {
772
629
  const escaped = CSS.escape(sectionId);
773
630
  const byInstance = document.querySelectorAll(`[data-ohw-instance="${escaped}"]`);
774
- const sections = Array.from(
775
- byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`)
776
- );
777
- const isNavbar = sectionId === "navbar";
778
- if (isNavbar) {
779
- const drawer = document.querySelector("[data-ohw-nav-drawer]");
780
- if (drawer && !sections.includes(drawer)) sections.push(drawer);
781
- const header = document.querySelector("[data-ohw-nav-root]");
782
- if (header && !sections.includes(header)) sections.push(header);
783
- }
631
+ const sections = byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`);
784
632
  for (const marker of Array.from(sections)) {
785
- const isDrawerMarker = isNavbar && marker.hasAttribute("data-ohw-nav-drawer");
786
633
  const section = marker.querySelector(":scope > [data-ai-section]") ?? marker;
787
634
  for (const [prop, attr] of Object.entries(SECTION_ATTRS)) {
788
635
  const value = override[prop];
@@ -790,23 +637,19 @@ function applyStylesToDom(store) {
790
637
  if (prop === "sectionBackground" && override.sectionBackgroundColor !== void 0) continue;
791
638
  section.setAttribute(attr, String(value).replace(":", "-"));
792
639
  }
793
- const bgOverride = isDrawerMarker ? override.navbarMobileBackground : override.sectionBackgroundColor;
794
- const textOverride = isDrawerMarker ? override.navbarMobileTextColor : override.textColor;
795
- const bgValue = isNavbar ? resolveNavbarValue(bgOverride) : bgOverride;
796
- const textValue = isNavbar ? resolveNavbarValue(textOverride) : textOverride;
797
- if (bgValue !== void 0) {
640
+ if (override.sectionBackgroundColor !== void 0) {
798
641
  saveInline(section, "background");
799
- section.style.setProperty("background", bgValue, "important");
642
+ section.style.setProperty("background", override.sectionBackgroundColor, "important");
800
643
  section.setAttribute("data-ohw-style-bgcolor", "");
801
644
  }
802
- if (textValue !== void 0 || override.fontFamily !== void 0) {
645
+ if (override.textColor !== void 0 || override.fontFamily !== void 0) {
803
646
  const textEls = marker.querySelectorAll(
804
647
  '[data-ohw-editable="text"], [data-ohw-editable="plain"], [data-ohw-field-label]'
805
648
  );
806
649
  for (const el of Array.from(textEls)) {
807
- if (textValue !== void 0) {
650
+ if (override.textColor !== void 0) {
808
651
  saveInline(el, "color");
809
- el.style.setProperty("color", textValue, "important");
652
+ el.style.setProperty("color", override.textColor, "important");
810
653
  el.setAttribute(NODE_WROTE_ATTR, "");
811
654
  }
812
655
  if (override.fontFamily !== void 0) {
@@ -848,6 +691,18 @@ function applyStylesToDom(store) {
848
691
  );
849
692
  subject.setAttribute(NODE_WROTE_ATTR, "");
850
693
  }
694
+ if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
695
+ const surface = buttonSurfaceOf(el);
696
+ if (override.buttonBackground !== void 0) {
697
+ saveInline(surface, "background");
698
+ surface.style.setProperty("background", override.buttonBackground, "important");
699
+ }
700
+ if (override.buttonText !== void 0) {
701
+ saveInline(surface, "color");
702
+ surface.style.setProperty("color", override.buttonText, "important");
703
+ }
704
+ surface.setAttribute(NODE_WROTE_ATTR, "");
705
+ }
851
706
  }
852
707
  }
853
708
  for (const [sectionId, override] of Object.entries(store.sections)) {
@@ -1442,59 +1297,7 @@ var FEATURE_LINE_CSS = [
1442
1297
  `background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
1443
1298
  `mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
1444
1299
  ].join("");
1445
- function buttonSizeSpec(size) {
1446
- switch (size) {
1447
- case "s":
1448
- return { padding: `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px`, fontSize: 14 };
1449
- case "l":
1450
- return { padding: `${AI_TREE_TOKENS.spacing4}px ${AI_TREE_TOKENS.spacing8}px`, fontSize: 18 };
1451
- case "m":
1452
- default:
1453
- return { padding: `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`, fontSize: AI_TREE_TOKENS.type.button.size };
1454
- }
1455
- }
1456
- function buttonRadiusPx(radius) {
1457
- switch (radius) {
1458
- case "square":
1459
- return 0;
1460
- case "pill":
1461
- return 999;
1462
- case "rounded":
1463
- default:
1464
- return AI_TREE_TOKENS.radiusButton;
1465
- }
1466
- }
1467
- function resolveButtonToken(brand, token) {
1468
- return brand.palette[token];
1469
- }
1470
- function buttonColorStyle(ctx, variant) {
1471
- const token = ctx.brand.buttons?.[variant];
1472
- if (!token) return null;
1473
- const fill = resolveButtonToken(ctx.brand, token.fill);
1474
- const text = resolveButtonToken(ctx.brand, token.textColor);
1475
- switch (token.style) {
1476
- case "outline":
1477
- return { background: "transparent", border: `1px solid ${fill}`, color: text };
1478
- case "ghost":
1479
- return { background: "transparent", border: "1px solid transparent", color: text };
1480
- case "solid":
1481
- default:
1482
- return { background: fill, color: text };
1483
- }
1484
- }
1485
- function buttonShellStyle(ctx, variant, fullWidth) {
1486
- const buttonToken = ctx.brand.buttons?.[variant];
1487
- if (buttonToken) {
1488
- const { padding, fontSize } = buttonSizeSpec(buttonToken.size);
1489
- return {
1490
- borderRadius: buttonRadiusPx(buttonToken.radius),
1491
- padding,
1492
- fontFamily: ctx.brand.fonts.body,
1493
- fontSize,
1494
- lineHeight: AI_TREE_TOKENS.type.button.line,
1495
- fontWeight: AI_TREE_TOKENS.type.button.weight
1496
- };
1497
- }
1300
+ function buttonShellStyle(ctx, fullWidth) {
1498
1301
  const bs = ctx.buttonStyle;
1499
1302
  if (bs) {
1500
1303
  return {
@@ -1552,22 +1355,6 @@ function accentBandContext(brand) {
1552
1355
  function textAttrs(ctx, path) {
1553
1356
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
1554
1357
  }
1555
- var AI_RESPONSIVE_CSS = [
1556
- "@media (max-width: 960px) {",
1557
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
1558
- ' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
1559
- "}",
1560
- "@media (max-width: 640px) {",
1561
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
1562
- " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
1563
- // Group containers flatten to a column on phones; span placements come along for free.
1564
- " [data-ai-responsive] [data-ai-group] { display: flex !important; flex-direction: column !important; }",
1565
- " [data-ai-responsive] [data-ai-group] > * { grid-column: auto !important; }",
1566
- " [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
1567
- " [data-ai-responsive] { overflow-x: hidden; }",
1568
- " [data-ai-responsive] img { max-width: 100%; }",
1569
- "}"
1570
- ].join("\n");
1571
1358
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
1572
1359
  function MediaBox({
1573
1360
  refValue,
@@ -1580,17 +1367,13 @@ function MediaBox({
1580
1367
  const url = refValue ? ctx.resolveMedia(refValue) : null;
1581
1368
  const isIcon = /^(lucide|simple):/.test(refValue);
1582
1369
  const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
1583
- const editAttrs = ctx.keyFor && editPath ? {
1584
- "data-ohw-key": ctx.keyFor(editPath),
1585
- "data-ohw-editable": isIcon ? "icon" : "image"
1586
- } : {};
1370
+ const editAttrs = ctx.keyFor && editPath && !isIcon ? { "data-ohw-key": ctx.keyFor(editPath), "data-ohw-editable": "image" } : {};
1587
1371
  if (isIcon) {
1588
1372
  const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
1589
1373
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1590
1374
  "span",
1591
1375
  {
1592
1376
  "data-ai-icon": refValue,
1593
- ...editAttrs,
1594
1377
  style: {
1595
1378
  display: "inline-flex",
1596
1379
  width: 48,
@@ -1642,8 +1425,6 @@ function ButtonEl({
1642
1425
  fullWidth
1643
1426
  }) {
1644
1427
  const secondary = slots.variant === "secondary";
1645
- const variant = secondary ? "secondary" : "primary";
1646
- const tokenColorStyle = buttonColorStyle(ctx, variant);
1647
1428
  const href = str(slots.href);
1648
1429
  const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`), "data-ohw-role": "button" } : {};
1649
1430
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -1658,13 +1439,13 @@ function ButtonEl({
1658
1439
  justifyContent: "center",
1659
1440
  textDecoration: "none",
1660
1441
  cursor: "pointer",
1661
- ...buttonShellStyle(ctx, variant, fullWidth),
1662
- ...tokenColorStyle ?? (secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : (
1442
+ ...buttonShellStyle(ctx, fullWidth),
1443
+ ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : (
1663
1444
  // Off-band, prefer the template button's measured fill/label pair — a template may
1664
1445
  // fill its CTAs with any token (hvac: accent bg, primary text). On an accent band
1665
1446
  // the flipped palette keeps contrast, so the brand-driven colours stay.
1666
1447
  !ctx.buttonLabel && ctx.buttonStyle?.background ? { background: ctx.buttonStyle.background, color: ctx.buttonStyle.color } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand) }
1667
- ))
1448
+ )
1668
1449
  },
1669
1450
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
1670
1451
  }
@@ -2485,7 +2266,7 @@ function CollectionBlock({ node, ctx, path }) {
2485
2266
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2486
2267
  "div",
2487
2268
  {
2488
- "data-ai-grid": String(itemsPerRow),
2269
+ "data-ai-grid": "",
2489
2270
  style: {
2490
2271
  display: "grid",
2491
2272
  gridTemplateColumns: `repeat(${itemsPerRow}, 1fr)`,
@@ -2735,13 +2516,13 @@ function renderNode(node, ctx, path) {
2735
2516
  border: "none",
2736
2517
  cursor: "pointer",
2737
2518
  // Shape/padding/typography follow the host template's own buttons.
2738
- ...buttonShellStyle(ctx, "primary"),
2519
+ ...buttonShellStyle(ctx),
2739
2520
  // Brand-styled: the template button's measured fill/label pair off-band, else
2740
2521
  // primary fill with a brand-derived label so it reads on custom palettes.
2741
- ...buttonColorStyle(ctx, "primary") ?? (!ctx.buttonLabel && ctx.buttonStyle?.background ? { background: ctx.buttonStyle.background, color: ctx.buttonStyle.color } : {
2522
+ ...!ctx.buttonLabel && ctx.buttonStyle?.background ? { background: ctx.buttonStyle.background, color: ctx.buttonStyle.color } : {
2742
2523
  background: ctx.brand.palette.primary,
2743
2524
  color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand)
2744
- })
2525
+ }
2745
2526
  },
2746
2527
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
2747
2528
  },
@@ -2838,7 +2619,6 @@ function AiTreeRenderer({
2838
2619
  {
2839
2620
  "data-ai-section": tree.tag ?? "",
2840
2621
  ...bgAttrs,
2841
- "data-ai-responsive": "",
2842
2622
  style: {
2843
2623
  position: "relative",
2844
2624
  padding: `${pad}px 0`,
@@ -2849,13 +2629,12 @@ function AiTreeRenderer({
2849
2629
  color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
2850
2630
  },
2851
2631
  children: [
2852
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
2853
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
2854
2632
  isOverlay && backgroundUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
2633
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
2855
2634
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2856
2635
  "div",
2857
2636
  {
2858
- "data-ai-section-inner": "",
2637
+ "data-ai-container": "",
2859
2638
  style: {
2860
2639
  position: "relative",
2861
2640
  maxWidth: AI_TREE_TOKENS.sectionMaxWidth,
@@ -2866,7 +2645,7 @@ function AiTreeRenderer({
2866
2645
  children: tree.rows.map((row, r2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2867
2646
  "div",
2868
2647
  {
2869
- "data-ai-columns": "",
2648
+ "data-ai-row": "",
2870
2649
  style: {
2871
2650
  display: "grid",
2872
2651
  gridTemplateColumns: "repeat(12, 1fr)",
@@ -2916,52 +2695,14 @@ function readRootVar(name) {
2916
2695
  if (typeof document === "undefined") return "";
2917
2696
  return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
2918
2697
  }
2919
- function normalizeColorToHex(value) {
2920
- if (!value || typeof document === "undefined") return value;
2921
- const canvas = document.createElement("canvas");
2922
- canvas.width = 1;
2923
- canvas.height = 1;
2924
- const ctx = canvas.getContext("2d");
2925
- if (!ctx) return value;
2926
- ctx.fillStyle = value;
2927
- ctx.fillRect(0, 0, 1, 1);
2928
- const [r2, g, b] = ctx.getImageData(0, 0, 1, 1).data;
2929
- const toHex = (n) => n.toString(16).padStart(2, "0");
2930
- return `#${toHex(r2)}${toHex(g)}${toHex(b)}`;
2931
- }
2932
- var GENERIC_FONT_KEYWORDS = /* @__PURE__ */ new Set([
2933
- "serif",
2934
- "sans-serif",
2935
- "monospace",
2936
- "cursive",
2937
- "fantasy",
2938
- "system-ui",
2939
- "ui-serif",
2940
- "ui-sans-serif",
2941
- "ui-monospace",
2942
- "ui-rounded",
2943
- "math",
2944
- "emoji",
2945
- "fangsong"
2946
- ]);
2947
- function primaryFontFamily(stack) {
2948
- const first = stack.split(",").map((part) => part.trim().replace(/^["']|["']$/g, "")).find((part) => part && !GENERIC_FONT_KEYWORDS.has(part.toLowerCase()));
2949
- return first ?? "";
2950
- }
2951
- function humanizeFontFamily(name) {
2952
- return name.replace(/^__/, "").replace(/_[0-9a-f]{6}$/i, "").replace(/_/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").trim().replace(/\s+/g, " ").replace(/(^|\s)([a-z])/g, (_, sep, c) => sep + c.toUpperCase());
2953
- }
2954
- function readFontVar(name) {
2955
- return humanizeFontFamily(primaryFontFamily(readRootVar(name)));
2956
- }
2957
2698
  function deriveBrandOverride() {
2958
2699
  const dark = readRootVar("--ohw-brand-dark");
2959
2700
  const primary = readRootVar("--ohw-brand-primary");
2960
2701
  const light = readRootVar("--ohw-brand-light");
2961
2702
  if (!dark || !primary || !light) return null;
2962
2703
  const accent = readRootVar("--ohw-brand-accent");
2963
- const heading = readFontVar("--font-heading") || readFontVar("--font-display");
2964
- const body = readFontVar("--font-body");
2704
+ const heading = readRootVar("--font-heading") || readRootVar("--font-display");
2705
+ const body = readRootVar("--font-body");
2965
2706
  return {
2966
2707
  palette: { dark, primary, accent: accent || dark, light },
2967
2708
  fonts: {
@@ -2970,55 +2711,22 @@ function deriveBrandOverride() {
2970
2711
  }
2971
2712
  };
2972
2713
  }
2973
- function deriveTemplateBrandLive() {
2714
+ function deriveTemplateBrand() {
2974
2715
  const primary = readRootVar("--brand-primary") || readRootVar("--color-primary");
2975
2716
  const dark = readRootVar("--brand-text") || readRootVar("--color-dark");
2976
2717
  const light = readRootVar("--brand-background") || readRootVar("--color-light");
2977
2718
  if (!dark || !primary || !light) return null;
2978
2719
  const accent = readRootVar("--brand-accent") || readRootVar("--color-accent");
2979
- const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
2980
- const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
2720
+ const heading = readRootVar("--brand-font-heading") || readRootVar("--font-heading") || readRootVar("--font-display");
2721
+ const body = readRootVar("--brand-font-body") || readRootVar("--font-body");
2981
2722
  return {
2982
- palette: {
2983
- dark: normalizeColorToHex(dark),
2984
- primary: normalizeColorToHex(primary),
2985
- accent: normalizeColorToHex(accent || dark),
2986
- light: normalizeColorToHex(light)
2987
- },
2723
+ palette: { dark, primary, accent: accent || dark, light },
2988
2724
  fonts: {
2989
2725
  heading: heading || AI_DEFAULT_BRAND.fonts.heading,
2990
2726
  body: body || AI_DEFAULT_BRAND.fonts.body
2991
2727
  }
2992
2728
  };
2993
2729
  }
2994
- function deriveTemplateFontsLive() {
2995
- const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
2996
- const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
2997
- if (!heading && !body) return null;
2998
- return {
2999
- heading: heading || AI_DEFAULT_BRAND.fonts.heading,
3000
- body: body || AI_DEFAULT_BRAND.fonts.body
3001
- };
3002
- }
3003
- var OVERRIDE_VAR_NAMES = [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES, ...FONT_VARS.heading, ...FONT_VARS.body];
3004
- function withOverrideStripped(read) {
3005
- const root = document.documentElement;
3006
- const restore = OVERRIDE_VAR_NAMES.map((name) => [name, root.style.getPropertyValue(name)]);
3007
- for (const name of OVERRIDE_VAR_NAMES) root.style.removeProperty(name);
3008
- try {
3009
- return read();
3010
- } finally {
3011
- for (const [name, value] of restore) if (value) root.style.setProperty(name, value);
3012
- }
3013
- }
3014
- var TEMPLATE_BRAND_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateBrandLive);
3015
- var TEMPLATE_FONTS_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateFontsLive);
3016
- function deriveTemplateBrand() {
3017
- return TEMPLATE_BRAND_SNAPSHOT;
3018
- }
3019
- function deriveTemplateFonts() {
3020
- return TEMPLATE_FONTS_SNAPSHOT;
3021
- }
3022
2730
  function deriveTemplateButtonStyle() {
3023
2731
  if (typeof document === "undefined") return null;
3024
2732
  const candidates = Array.from(
@@ -7516,12 +7224,12 @@ var cva = (base, config) => (props) => {
7516
7224
  var import_radix_ui2 = require("radix-ui");
7517
7225
  var import_jsx_runtime5 = require("react/jsx-runtime");
7518
7226
  var toggleVariants = cva(
7519
- "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-bridge-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
7227
+ "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
7520
7228
  {
7521
7229
  variants: {
7522
7230
  variant: {
7523
7231
  default: "bg-transparent border-0",
7524
- outline: "border border-input bg-transparent shadow-xs hover:bg-bridge-accent hover:text-accent-foreground"
7232
+ outline: "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground"
7525
7233
  },
7526
7234
  size: {
7527
7235
  default: "px-2 py-1",
@@ -7614,10 +7322,10 @@ var DragHandle = React4.forwardRef(
7614
7322
  type,
7615
7323
  "data-slot": "drag-handle",
7616
7324
  className: cn(
7617
- "inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-7.5",
7325
+ "inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-[30px]",
7618
7326
  "bg-white border border-transparent text-stone-500 shadow-md cursor-grab",
7619
7327
  "enabled:hover:border enabled:hover:border-stone-200 enabled:hover:text-stone-950",
7620
- "enabled:active:border enabled:active:border-bridge-primary enabled:active:bg-primary-50 enabled:active:text-stone-950 enabled:active:shadow enabled:active:cursor-grabbing",
7328
+ "enabled:active:border enabled:active:border-primary enabled:active:bg-primary-50 enabled:active:text-stone-950 enabled:active:shadow enabled:active:cursor-grabbing",
7621
7329
  "disabled:cursor-not-allowed disabled:opacity-40 disabled:text-stone-950 disabled:pointer-events-none",
7622
7330
  className
7623
7331
  ),
@@ -7639,7 +7347,7 @@ var CustomToolbar = React5.forwardRef(({ className, onMouseDown, ...props }, ref
7639
7347
  "data-ohw-toolbar": "",
7640
7348
  className: cn(
7641
7349
  // Figma: bg background, radius 8, gap-1, p-0.5, shadow-md — no border
7642
- "inline-flex h-8 items-center gap-1 rounded-(--radius,0.5rem) bg-background p-0.5 font-sans whitespace-nowrap shadow-md",
7350
+ "inline-flex h-8 items-center gap-1 rounded-[var(--radius,0.5rem)] bg-background p-0.5 font-sans whitespace-nowrap shadow-md",
7643
7351
  className
7644
7352
  ),
7645
7353
  onMouseDown: (e) => {
@@ -7668,7 +7376,7 @@ var CustomToolbarButton = React5.forwardRef(
7668
7376
  type,
7669
7377
  className: cn(
7670
7378
  "inline-flex size-7 shrink-0 items-center justify-center rounded-[calc(var(--radius,0.5rem)-2px)] text-foreground transition-colors",
7671
- active ? "bg-bridge-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
7379
+ active ? "bg-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
7672
7380
  className
7673
7381
  ),
7674
7382
  ...props
@@ -8932,13 +8640,13 @@ function FormFieldToolbar({
8932
8640
  ]
8933
8641
  }
8934
8642
  ) }),
8935
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-47.5 p-1", children: FIELD_TYPES.map((entry) => {
8643
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-[190px] p-1", children: FIELD_TYPES.map((entry) => {
8936
8644
  const Icon = TYPE_ICONS[entry.type];
8937
8645
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
8938
8646
  DropdownMenuItem,
8939
8647
  {
8940
8648
  onSelect: () => onTypeChange(entry.type),
8941
- className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-bridge-primary/10" : ""),
8649
+ className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-primary/10" : ""),
8942
8650
  children: [
8943
8651
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
8944
8652
  entry.label
@@ -8955,7 +8663,7 @@ function FormFieldToolbar({
8955
8663
  type: "button",
8956
8664
  "aria-pressed": required,
8957
8665
  onClick: onRequiredToggle,
8958
- className: "flex h-7 items-center gap-1.5 whitespace-nowrap rounded-md px-2 text-[13px] font-medium transition-colors " + (required ? "bg-bridge-primary/10 text-bridge-primary" : "text-foreground hover:bg-muted/70"),
8666
+ className: "flex h-7 items-center gap-1.5 whitespace-nowrap rounded-md px-2 text-[13px] font-medium transition-colors " + (required ? "bg-primary/10 text-primary" : "text-foreground hover:bg-muted/70"),
8959
8667
  "data-ohw-field-required-toggle": "",
8960
8668
  children: [
8961
8669
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Asterisk, { size: 14, strokeWidth: 2, "aria-hidden": true }),
@@ -8975,7 +8683,7 @@ function FormFieldToolbar({
8975
8683
  children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.MoreHorizontal, { size: 15, "aria-hidden": true })
8976
8684
  }
8977
8685
  ) }),
8978
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-42.5 p-1", children: [
8686
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-[170px] p-1", children: [
8979
8687
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuItem, { onSelect: onDuplicate, className: "rounded-md py-2 text-[13px]", children: [
8980
8688
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Copy, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
8981
8689
  "Duplicate"
@@ -9003,7 +8711,7 @@ function FieldTypePicker({ onPick }) {
9003
8711
  {
9004
8712
  type: "button",
9005
8713
  onClick: () => onPick(entry.type),
9006
- className: "flex h-[76px] flex-col items-center justify-center gap-2 rounded-xl border border-border text-[15px] font-medium text-foreground transition-colors hover:border-bridge-primary hover:bg-bridge-primary/5",
8714
+ className: "flex h-[76px] flex-col items-center justify-center gap-2 rounded-xl border border-border text-[15px] font-medium text-foreground transition-colors hover:border-primary hover:bg-primary/5",
9007
8715
  children: [
9008
8716
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 26, strokeWidth: 1.5, "aria-hidden": true }),
9009
8717
  entry.label
@@ -9029,7 +8737,7 @@ var buttonVariants = cva(
9029
8737
  {
9030
8738
  variants: {
9031
8739
  variant: {
9032
- default: "bg-bridge-primary text-primary-foreground hover:opacity-90",
8740
+ default: "bg-primary text-primary-foreground hover:opacity-90",
9033
8741
  outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
9034
8742
  ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
9035
8743
  },
@@ -9102,7 +8810,6 @@ function MediaOverlay({
9102
8810
  fadingOut = false,
9103
8811
  selected = false,
9104
8812
  hovered = false,
9105
- cueOnly = false,
9106
8813
  onFadeOutComplete,
9107
8814
  onReplace,
9108
8815
  onSelect,
@@ -9111,7 +8818,7 @@ function MediaOverlay({
9111
8818
  const { rect } = hover;
9112
8819
  const skeletonRef = React8.useRef(null);
9113
8820
  const isVideo = hover.elementType === "video";
9114
- const showChrome = (!selected || hovered) && !cueOnly;
8821
+ const showChrome = !selected || hovered;
9115
8822
  const autoplay = hover.videoAutoplay ?? true;
9116
8823
  const muted = hover.videoMuted ?? true;
9117
8824
  const probeRef = React8.useRef(null);
@@ -9125,7 +8832,6 @@ function MediaOverlay({
9125
8832
  (prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
9126
8833
  );
9127
8834
  }, [isVideo]);
9128
- const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
9129
8835
  const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
9130
8836
  const box = {
9131
8837
  position: "fixed",
@@ -9228,11 +8934,11 @@ function MediaOverlay({
9228
8934
  // parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
9229
8935
  // in-document, pointer-events does it natively. The button below opts back in, so
9230
8936
  // Replace still works.
9231
- pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
8937
+ pointerEvents: hover.hasTextOverlap ? "none" : "auto",
9232
8938
  // Selected: a firm component ring with no wash, so the image reads as chosen rather
9233
8939
  // than hovered. Hover keeps the existing tinted preview.
9234
- boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
9235
- background: selected ? "transparent" : "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
8940
+ boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
8941
+ background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
9236
8942
  },
9237
8943
  onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
9238
8944
  children: [
@@ -9255,17 +8961,17 @@ function MediaOverlay({
9255
8961
  },
9256
8962
  children: [
9257
8963
  isVideo ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
9258
- replaceLabel
8964
+ isVideo ? "Replace video" : "Replace image"
9259
8965
  ]
9260
8966
  }
9261
8967
  ),
9262
- showChrome && replaceMode !== "none" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
8968
+ replaceMode === "none" ? null : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
9263
8969
  Button,
9264
8970
  {
9265
8971
  "data-ohw-media-overlay": "",
9266
8972
  variant: "outline",
9267
8973
  size: "sm",
9268
- "aria-label": replaceLabel,
8974
+ "aria-label": isVideo ? "Replace video" : "Replace image",
9269
8975
  className: "gap-1.5 cursor-pointer hover:bg-background",
9270
8976
  style: {
9271
8977
  ...OVERLAY_BUTTON_STYLE,
@@ -9279,7 +8985,7 @@ function MediaOverlay({
9279
8985
  justifyContent: "center"
9280
8986
  } : null,
9281
8987
  // Don't let Replace steal clicks when text (e.g. nav) sits on top of this media.
9282
- pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto"
8988
+ pointerEvents: hover.hasTextOverlap ? "none" : "auto"
9283
8989
  },
9284
8990
  onMouseDown: (e) => e.preventDefault(),
9285
8991
  onClick: (e) => {
@@ -9288,7 +8994,7 @@ function MediaOverlay({
9288
8994
  },
9289
8995
  children: [
9290
8996
  isVideo ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
9291
- replaceMode === "full" ? replaceLabel : null
8997
+ replaceMode === "full" ? isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image" : null
9292
8998
  ]
9293
8999
  }
9294
9000
  )
@@ -9309,8 +9015,7 @@ var OVERLAY_BUTTON_STYLE2 = {
9309
9015
  };
9310
9016
  function CarouselOverlay({
9311
9017
  hover,
9312
- onEdit,
9313
- cueOnly = false
9018
+ onEdit
9314
9019
  }) {
9315
9020
  const { rect } = hover;
9316
9021
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
@@ -9326,12 +9031,12 @@ function CarouselOverlay({
9326
9031
  width: rect.width,
9327
9032
  height: rect.height,
9328
9033
  zIndex: 2147483646,
9329
- pointerEvents: cueOnly ? "none" : "auto",
9330
- boxShadow: "inset 0 0 0 1.5px var(--color-bridge-primary)",
9331
- background: "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
9034
+ pointerEvents: "auto",
9035
+ boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
9036
+ background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
9332
9037
  },
9333
9038
  onClick: () => onEdit(hover.key),
9334
- children: cueOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
9039
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
9335
9040
  Button,
9336
9041
  {
9337
9042
  "data-ohw-carousel-overlay": "",
@@ -9396,57 +9101,6 @@ function useLiveSectionRect(sectionId) {
9396
9101
  }, [sectionId]);
9397
9102
  return rect;
9398
9103
  }
9399
- var NAV_TOGGLE_LABEL_RE = /^(toggle menu|open menu|close menu)$/i;
9400
- function readNavToggleRect() {
9401
- const el = Array.from(document.querySelectorAll("button[aria-label]")).find(
9402
- (e) => NAV_TOGGLE_LABEL_RE.test(e.getAttribute("aria-label") ?? "")
9403
- );
9404
- if (!el) return null;
9405
- const r2 = el.getBoundingClientRect();
9406
- if (r2.width <= 0 || r2.height <= 0) return null;
9407
- return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
9408
- }
9409
- function useLiveNavToggleHole(active) {
9410
- const [rect, setRect] = (0, import_react8.useState)(null);
9411
- (0, import_react8.useEffect)(() => {
9412
- if (!active) {
9413
- setRect(null);
9414
- return;
9415
- }
9416
- const update = () => {
9417
- const next = readNavToggleRect();
9418
- setRect(
9419
- (prev) => prev && next && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
9420
- );
9421
- };
9422
- update();
9423
- const opts = { capture: true, passive: true };
9424
- window.addEventListener("scroll", update, opts);
9425
- window.addEventListener("resize", update);
9426
- const interval = setInterval(update, 500);
9427
- return () => {
9428
- window.removeEventListener("scroll", update, opts);
9429
- window.removeEventListener("resize", update);
9430
- clearInterval(interval);
9431
- };
9432
- }, [active]);
9433
- return rect;
9434
- }
9435
- function subtractRect(outer, hole) {
9436
- if (!hole) return [outer];
9437
- const l = Math.max(outer.left, hole.left);
9438
- const t = Math.max(outer.top, hole.top);
9439
- const r2 = Math.min(outer.left + outer.width, hole.left + hole.width);
9440
- const b = Math.min(outer.top + outer.height, hole.top + hole.height);
9441
- if (l >= r2 || t >= b) return [outer];
9442
- const rects = [];
9443
- if (t > outer.top) rects.push({ left: outer.left, top: outer.top, width: outer.width, height: t - outer.top });
9444
- const midHeight = b - t;
9445
- if (l > outer.left) rects.push({ left: outer.left, top: t, width: l - outer.left, height: midHeight });
9446
- if (r2 < outer.left + outer.width) rects.push({ left: r2, top: t, width: outer.left + outer.width - r2, height: midHeight });
9447
- if (b < outer.top + outer.height) rects.push({ left: outer.left, top: b, width: outer.width, height: outer.top + outer.height - b });
9448
- return rects;
9449
- }
9450
9104
  function computeSectionBoundaryFlags(instanceId) {
9451
9105
  const topLevel = topLevelSections();
9452
9106
  const index = topLevel.findIndex((el) => instanceIdOf(el) === instanceId);
@@ -9522,8 +9176,7 @@ function ReviewButton({
9522
9176
  }
9523
9177
  function AiSectionOverlay({
9524
9178
  postToParent: postToParent2,
9525
- apiRef,
9526
- onSelectionChange
9179
+ apiRef
9527
9180
  }) {
9528
9181
  const [selectedId, setSelectedId] = (0, import_react8.useState)(null);
9529
9182
  const [reviewId, setReviewId] = (0, import_react8.useState)(null);
@@ -9532,9 +9185,6 @@ function AiSectionOverlay({
9532
9185
  reviewIdRef.current = reviewId;
9533
9186
  const selectedIdRef = (0, import_react8.useRef)(null);
9534
9187
  selectedIdRef.current = selectedId;
9535
- (0, import_react8.useEffect)(() => {
9536
- onSelectionChange?.(selectedId);
9537
- }, [selectedId, onSelectionChange]);
9538
9188
  const report = (0, import_react8.useCallback)(
9539
9189
  (el) => {
9540
9190
  const labelSrc = el ? sectionElementOf(el) : null;
@@ -9666,7 +9316,6 @@ function AiSectionOverlay({
9666
9316
  const activeSelectionId = reviewId ? null : selectedId;
9667
9317
  const selectionRect = useLiveSectionRect(activeSelectionId);
9668
9318
  const reviewRect = useLiveSectionRect(reviewId);
9669
- const navToggleHole = useLiveNavToggleHole(Boolean(reviewId));
9670
9319
  const hoverRect = useLiveSectionRect(reviewId || hoveredId === selectedId ? null : hoveredId);
9671
9320
  const showSelectionBorder = Boolean(selectionRect) && !navDropdownForceOpen;
9672
9321
  (0, import_react8.useEffect)(() => {
@@ -9726,65 +9375,48 @@ function AiSectionOverlay({
9726
9375
  }
9727
9376
  }
9728
9377
  ),
9729
- reviewRect && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
9730
- subtractRect(reviewRect, navToggleHole).map((r2, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
9731
- "div",
9732
- {
9733
- "data-ohw-ai-review": "",
9734
- "aria-hidden": true,
9735
- style: {
9736
- position: "fixed",
9737
- top: r2.top,
9738
- left: r2.left,
9739
- width: r2.width,
9740
- height: r2.height,
9741
- background: "rgba(8, 133, 254, 0.04)",
9742
- pointerEvents: "auto",
9743
- cursor: "default",
9744
- zIndex: 2147483200
9745
- },
9746
- onClick: (e) => e.stopPropagation()
9378
+ reviewRect && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
9379
+ "div",
9380
+ {
9381
+ "data-ohw-ai-review": "",
9382
+ style: {
9383
+ position: "fixed",
9384
+ top: reviewRect.top,
9385
+ left: reviewRect.left,
9386
+ width: reviewRect.width,
9387
+ height: reviewRect.height,
9388
+ border: `2px solid ${PRIMARY2}`,
9389
+ borderRadius: edgeAwareRadius(reviewRect),
9390
+ zIndex: 2147483200,
9391
+ // The veil itself: swallows clicks so the section stays locked until decided. This
9392
+ // stopPropagation only guards the bubble phase; the bridge's capture-phase click
9393
+ // handlers additionally bail on `[data-ohw-ai-review]`, without which a click on
9394
+ // Accept/Discard resolves to the media beneath and opens the file picker.
9395
+ background: "rgba(8, 133, 254, 0.04)",
9396
+ pointerEvents: "auto",
9397
+ cursor: "default"
9747
9398
  },
9748
- i
9749
- )),
9750
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
9751
- "div",
9752
- {
9753
- "aria-hidden": true,
9754
- style: {
9755
- position: "fixed",
9756
- top: reviewRect.top,
9757
- left: reviewRect.left,
9758
- width: reviewRect.width,
9759
- height: reviewRect.height,
9760
- border: `2px solid ${PRIMARY2}`,
9761
- borderRadius: edgeAwareRadius(reviewRect),
9762
- pointerEvents: "none",
9763
- zIndex: 2147483200
9399
+ onClick: (e) => e.stopPropagation(),
9400
+ children: !reviewButtonsHidden && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
9401
+ "div",
9402
+ {
9403
+ style: {
9404
+ position: "sticky",
9405
+ top: 12,
9406
+ display: "flex",
9407
+ gap: 8,
9408
+ justifyContent: "flex-end",
9409
+ paddingRight: 12,
9410
+ paddingTop: 12
9411
+ },
9412
+ children: [
9413
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ReviewButton, { label: "Accept", onClick: () => decide("accept"), background: PRIMARY2, color: "#ffffff", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.Check, { size: 16, strokeWidth: 2.5, "aria-hidden": true }) }),
9414
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ReviewButton, { label: "Discard", onClick: () => decide("discard"), background: "#EFF6FF", color: "#0c0a09", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.X, { size: 16, strokeWidth: 2, "aria-hidden": true }) })
9415
+ ]
9764
9416
  }
9765
- }
9766
- ),
9767
- !reviewButtonsHidden && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
9768
- "div",
9769
- {
9770
- style: {
9771
- position: "fixed",
9772
- top: reviewRect.top + 12,
9773
- left: reviewRect.left,
9774
- width: reviewRect.width,
9775
- display: "flex",
9776
- gap: 8,
9777
- justifyContent: "flex-end",
9778
- paddingRight: 12,
9779
- zIndex: 2147483201
9780
- },
9781
- children: [
9782
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ReviewButton, { label: "Accept", onClick: () => decide("accept"), background: PRIMARY2, color: "#ffffff", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.Check, { size: 16, strokeWidth: 2.5, "aria-hidden": true }) }),
9783
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ReviewButton, { label: "Discard", onClick: () => decide("discard"), background: "#EFF6FF", color: "#0c0a09", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.X, { size: 16, strokeWidth: 2, "aria-hidden": true }) })
9784
- ]
9785
- }
9786
- )
9787
- ] })
9417
+ )
9418
+ }
9419
+ )
9788
9420
  ] });
9789
9421
  }
9790
9422
 
@@ -10254,7 +9886,7 @@ function SectionTreeItem({
10254
9886
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
10255
9887
  "div",
10256
9888
  {
10257
- className: "-mr-px h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
9889
+ className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
10258
9890
  "aria-hidden": true
10259
9891
  }
10260
9892
  ),
@@ -10273,7 +9905,7 @@ function SectionTreeItem({
10273
9905
  className: cn(
10274
9906
  "flex h-9 min-w-0 flex-1 items-center gap-2 rounded-md border border-border bg-background p-3",
10275
9907
  interactive && "cursor-pointer hover:bg-muted/30",
10276
- interactive && selected && "border-bridge-primary"
9908
+ interactive && selected && "border-primary"
10277
9909
  ),
10278
9910
  children: [
10279
9911
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
@@ -10403,7 +10035,7 @@ function UrlOrPageInput({
10403
10035
  };
10404
10036
  const fieldClassName = cn(
10405
10037
  "data-ohw-link-field flex h-[36px] w-full items-center overflow-hidden rounded-md border bg-background pl-3 pr-3 py-2 outline-none transition-[border-color,box-shadow]",
10406
- urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-bridge-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
10038
+ urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
10407
10039
  );
10408
10040
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
10409
10041
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
@@ -11447,15 +11079,6 @@ function getNavbarDesktopContainer() {
11447
11079
  function getNavbarDrawerContainer() {
11448
11080
  return document.querySelector("[data-ohw-nav-drawer]");
11449
11081
  }
11450
- function isNavDrawerOpen() {
11451
- return document.querySelector('[data-ohw-nav-drawer][data-ohw-section="navbar"]') !== null;
11452
- }
11453
- function isPointOutsideOpenDrawer(clientX, clientY) {
11454
- const drawer = document.querySelector('[data-ohw-nav-drawer][data-ohw-section="navbar"]');
11455
- if (!drawer) return false;
11456
- const r2 = drawer.getBoundingClientRect();
11457
- return clientX < r2.left || clientX > r2.right || clientY < r2.top || clientY > r2.bottom;
11458
- }
11459
11082
  function isNavbarListContainerVisible(el) {
11460
11083
  if (el.hasAttribute("hidden")) return false;
11461
11084
  if (el.closest("[hidden]")) return false;
@@ -14319,7 +13942,6 @@ function readLogoSizeState(content, placement) {
14319
13942
  function getLogoElement(el) {
14320
13943
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
14321
13944
  if (marked) return marked;
14322
- if (el.closest('[data-ohw-editable="icon"]')) return null;
14323
13945
  const root = el.closest("nav, [data-ohw-nav-root], footer");
14324
13946
  if (!root) return null;
14325
13947
  const anchor = el.closest("a");
@@ -14607,7 +14229,7 @@ function DisplaySwitch({
14607
14229
  onClick: () => onChange(!checked),
14608
14230
  className: cn(
14609
14231
  "relative h-5 w-9 shrink-0 rounded-full transition-colors",
14610
- checked ? "bg-bridge-primary" : "bg-primary-50",
14232
+ checked ? "bg-primary" : "bg-primary-50",
14611
14233
  disabled ? "cursor-default opacity-50" : "cursor-pointer"
14612
14234
  ),
14613
14235
  children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
@@ -14615,7 +14237,7 @@ function DisplaySwitch({
14615
14237
  {
14616
14238
  className: cn(
14617
14239
  "absolute top-0.5 h-4 w-4 rounded-full bg-white transition-all",
14618
- checked ? "left-4.5" : "left-0.5"
14240
+ checked ? "left-[1.125rem]" : "left-0.5"
14619
14241
  )
14620
14242
  }
14621
14243
  )
@@ -16250,7 +15872,7 @@ var badgeVariants = cva(
16250
15872
  {
16251
15873
  variants: {
16252
15874
  variant: {
16253
- default: "border-transparent bg-bridge-primary text-primary-foreground",
15875
+ default: "border-transparent bg-primary text-primary-foreground",
16254
15876
  secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
16255
15877
  destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
16256
15878
  outline: "text-foreground"
@@ -16432,10 +16054,21 @@ function parseSchedulingInsertAfter(insertAfter) {
16432
16054
  insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
16433
16055
  };
16434
16056
  }
16435
- function resolveEntryAnchor(entry) {
16436
- if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
16437
- const parsed = parseSchedulingInsertAfter(entry.insertAfter);
16438
- return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
16057
+ function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
16058
+ const parsed = parseSchedulingInsertAfter(insertAfter);
16059
+ const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
16060
+ const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
16061
+ return { effectiveInsertAfter, insertBefore };
16062
+ }
16063
+ function getSchedulingMountPoint(insertAfter) {
16064
+ const { anchor } = parseSchedulingInsertAfter(insertAfter);
16065
+ let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
16066
+ if (!anchorEl && anchor === "scheduling") {
16067
+ const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
16068
+ anchorEl = widgets.at(-1) ?? null;
16069
+ }
16070
+ if (!anchorEl) return null;
16071
+ return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
16439
16072
  }
16440
16073
  function schedulingMountDepth(insertAfter) {
16441
16074
  if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
@@ -16452,7 +16085,8 @@ function getPageSchedulingEntries(raw) {
16452
16085
  }
16453
16086
  }
16454
16087
  function isSchedulingWidgetMissing(entry) {
16455
- return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
16088
+ const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
16089
+ return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
16456
16090
  }
16457
16091
  function hasMissingSchedulingWidgets(entries) {
16458
16092
  return entries.some(isSchedulingWidgetMissing);
@@ -16490,18 +16124,17 @@ function initSectionsFromContent(content, removeExisting = false, currentPath =
16490
16124
  } catch {
16491
16125
  }
16492
16126
  }
16493
- function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
16494
- const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
16495
- const sectionId = schedulingSectionId(widgetId);
16127
+ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
16128
+ const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
16129
+ const sectionId = schedulingSectionId(effectiveInsertAfter);
16496
16130
  if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
16497
- const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
16498
- if (!anchorEl) return false;
16499
- const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
16131
+ const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
16132
+ if (!mountPoint) return false;
16500
16133
  const container = document.createElement("div");
16501
16134
  container.dataset.ohwSectionContainer = "scheduling";
16502
16135
  container.dataset.ohwInstance = sectionId;
16503
- if (beforeId) {
16504
- const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
16136
+ if (insertBefore) {
16137
+ const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
16505
16138
  const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
16506
16139
  if (!beforePoint) return false;
16507
16140
  beforePoint.insertAdjacentElement("beforebegin", container);
@@ -16512,26 +16145,20 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
16512
16145
  }
16513
16146
  tail.insertAdjacentElement("afterend", container);
16514
16147
  }
16515
- try {
16516
- const root = (0, import_client2.createRoot)(container);
16517
- schedulingRoots.set(container, root);
16518
- (0, import_react_dom4.flushSync)(() => {
16519
- root.render(
16520
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16521
- SchedulingWidget,
16522
- {
16523
- notifyOnConnect,
16524
- initialScheduleId: scheduleId,
16525
- insertAfter: widgetId
16526
- }
16527
- )
16528
- );
16529
- });
16530
- } catch (err) {
16531
- console.error("[ow:scheduling] render threw", err);
16532
- container.remove();
16533
- return false;
16534
- }
16148
+ const root = (0, import_client2.createRoot)(container);
16149
+ schedulingRoots.set(container, root);
16150
+ (0, import_react_dom4.flushSync)(() => {
16151
+ root.render(
16152
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16153
+ SchedulingWidget,
16154
+ {
16155
+ notifyOnConnect,
16156
+ initialScheduleId: scheduleId,
16157
+ insertAfter: effectiveInsertAfter
16158
+ }
16159
+ )
16160
+ );
16161
+ });
16535
16162
  const tracker = getSectionsTracker();
16536
16163
  let sections = [];
16537
16164
  try {
@@ -16539,12 +16166,10 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
16539
16166
  } catch {
16540
16167
  }
16541
16168
  const inEditor = typeof window !== "undefined" && window.self !== window.top;
16542
- if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
16169
+ if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
16543
16170
  sections.push({
16544
16171
  type: "scheduling",
16545
- insertAfter: widgetId,
16546
- anchorId,
16547
- beforeId: beforeId ?? null,
16172
+ insertAfter: effectiveInsertAfter,
16548
16173
  pagePath: window.location.pathname,
16549
16174
  ...scheduleId ? { scheduleId } : {}
16550
16175
  });
@@ -16558,8 +16183,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
16558
16183
  for (let i = pending.length - 1; i >= 0; i--) {
16559
16184
  const entry = pending[i];
16560
16185
  const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
16561
- const { anchorId, beforeId } = resolveEntryAnchor(entry);
16562
- if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
16186
+ if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId ?? null)) {
16563
16187
  pending.splice(i, 1);
16564
16188
  }
16565
16189
  }
@@ -16640,19 +16264,6 @@ function isMediaEditable(el) {
16640
16264
  const t = el.dataset.ohwEditable;
16641
16265
  return t === "image" || t === "bg-image" || t === "video";
16642
16266
  }
16643
- var FULL_BLEED_MIN_COVERAGE = 0.98;
16644
- function fullBleedSectionIdOf(media) {
16645
- const section = media.closest("[data-ohw-section]");
16646
- if (!section) return null;
16647
- const s = section.getBoundingClientRect();
16648
- if (s.width <= 0 || s.height <= 0) return null;
16649
- const m = media.getBoundingClientRect();
16650
- const overlapX = Math.min(m.right, s.right) - Math.max(m.left, s.left);
16651
- const overlapY = Math.min(m.bottom, s.bottom) - Math.max(m.top, s.top);
16652
- if (overlapX <= 0 || overlapY <= 0) return null;
16653
- if (overlapX * overlapY / (s.width * s.height) < FULL_BLEED_MIN_COVERAGE) return null;
16654
- return instanceIdOf(movableUnit(section)) || null;
16655
- }
16656
16267
  function isIconMarkupValue(value) {
16657
16268
  return /^\s*<(svg|img)\b/i.test(value);
16658
16269
  }
@@ -16736,11 +16347,6 @@ function applyLinkByKey(key, val) {
16736
16347
  hrefAnchors.forEach((el) => applyLinkHref(el, val));
16737
16348
  }
16738
16349
  }
16739
- function isInsideLinkEditor(target) {
16740
- return Boolean(
16741
- 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"]')
16742
- );
16743
- }
16744
16350
  function isInsideFloatingPanel(target) {
16745
16351
  return Boolean(target.closest("[data-ohw-floating-panel]"));
16746
16352
  }
@@ -16748,6 +16354,11 @@ function isPointOverFloatingPanel(clientX, clientY) {
16748
16354
  const el = document.elementFromPoint(clientX, clientY);
16749
16355
  return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
16750
16356
  }
16357
+ function isInsideLinkEditor(target) {
16358
+ return Boolean(
16359
+ 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"]')
16360
+ );
16361
+ }
16751
16362
  function getHrefKeyFromElement(el) {
16752
16363
  if (!el) return null;
16753
16364
  const anchor = el.closest("[data-ohw-href-key]");
@@ -17017,7 +16628,7 @@ function getNavigationSelectionParent(el) {
17017
16628
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
17018
16629
  return getFooterLinksContainer();
17019
16630
  }
17020
- 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)) {
16631
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
17021
16632
  return getNavigationRoot(el);
17022
16633
  }
17023
16634
  return null;
@@ -17239,6 +16850,7 @@ var ICONS = {
17239
16850
  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"/>',
17240
16851
  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"/>'
17241
16852
  };
16853
+ var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
17242
16854
  var SELECTION_CHROME_GAP2 = 4;
17243
16855
  var TOOLBAR_STROKE_GAP2 = 4;
17244
16856
  var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
@@ -17622,7 +17234,6 @@ function StateToggle({
17622
17234
  );
17623
17235
  }
17624
17236
  var contentCache = /* @__PURE__ */ new Map();
17625
- var fetchedContentPaths = /* @__PURE__ */ new Set();
17626
17237
  var brandingCache = /* @__PURE__ */ new Map();
17627
17238
  var OHW_LOADER_STYLE = {
17628
17239
  position: "fixed",
@@ -17744,37 +17355,19 @@ function MadeWithOhhWells() {
17744
17355
  }
17745
17356
  );
17746
17357
  }
17747
- var OHW_LOADER_PREHYDRATE_SCRIPT = `(function(){try{var fromGlobal=typeof window!=="undefined"&&window.__OHW_SUBDOMAIN__?String(window.__OHW_SUBDOMAIN__):"";var p=location.hostname.split(".");var fromHost=location.hostname.endsWith(".ohhwells.site")&&p[0]&&p[0]!=="www"?p[0]:"";var fromQuery=new URLSearchParams(location.search).get("subdomain")||"";var fromCookie=(document.cookie.match(/(?:^|; )ohw-subdomain=([^;]*)/)||[])[1];fromCookie=fromCookie?decodeURIComponent(fromCookie):"";if(!fromGlobal&&!fromHost&&!fromQuery&&!fromCookie)return;var e=document.getElementById("ohw-loader");if(e)e.style.display="flex"}catch(e){}})();`;
17748
- function subdomainFromCookie() {
17749
- if (typeof document === "undefined") return "";
17750
- const match = document.cookie.match(/(?:^|; )ohw-subdomain=([^;]*)/);
17751
- return match ? decodeURIComponent(match[1]) : "";
17752
- }
17358
+ var OHW_LOADER_PREHYDRATE_SCRIPT = `(function(){try{var p=location.hostname.split(".");var fromHost=p.length>=3&&p[0]!=="www"?p[0]:"";var fromQuery=new URLSearchParams(location.search).get("subdomain")||"";if(!fromHost&&!fromQuery)return;var e=document.getElementById("ohw-loader");if(e)e.style.display="flex"}catch(e){}})();`;
17753
17359
  function resolveSubdomain(subdomainFromQuery) {
17754
- if (typeof window !== "undefined") {
17755
- const fromGlobal = window.__OHW_SUBDOMAIN__;
17756
- if (fromGlobal) return fromGlobal;
17757
- }
17758
17360
  if (subdomainFromQuery) return subdomainFromQuery;
17759
17361
  if (typeof window !== "undefined") {
17760
- const host = window.location.hostname.toLowerCase();
17761
- if (host.endsWith(".ohhwells.site")) {
17762
- const label = host.slice(0, -".ohhwells.site".length).split(".").pop();
17763
- if (label && label !== "www") return label;
17764
- }
17765
- const fromCookie = subdomainFromCookie();
17766
- if (fromCookie) return fromCookie;
17767
- const isPlatformHost = host.endsWith(".ohhwells.site") || host === "localhost" || host.endsWith(".localhost") || host.endsWith(".vercel.app");
17768
- if (!isPlatformHost) return "";
17362
+ const parts = window.location.hostname.split(".");
17363
+ if (parts.length >= 3 && parts[0] !== "www") return parts[0];
17769
17364
  }
17770
17365
  const siteUrl = process.env.NEXT_PUBLIC_SITE_URL;
17771
17366
  if (siteUrl) {
17772
17367
  try {
17773
17368
  const host = new URL(siteUrl).hostname;
17774
- if (host.endsWith(".ohhwells.site")) {
17775
- const label = host.slice(0, -".ohhwells.site".length).split(".").pop();
17776
- if (label && label !== "www") return label;
17777
- }
17369
+ const siteParts = host.split(".");
17370
+ if (siteParts.length >= 3 && siteParts[0] !== "www") return siteParts[0];
17778
17371
  } catch {
17779
17372
  }
17780
17373
  }
@@ -17812,26 +17405,7 @@ function OhhwellsBridge() {
17812
17405
  };
17813
17406
  }, []);
17814
17407
  const subdomainFromQuery = searchParams.get("subdomain");
17815
- const [subdomain, setSubdomain] = (0, import_react17.useState)(() => resolveSubdomain(subdomainFromQuery));
17816
- (0, import_react17.useLayoutEffect)(() => {
17817
- const next = resolveSubdomain(subdomainFromQuery);
17818
- if (next !== subdomain) setSubdomain(next);
17819
- if (next) return;
17820
- const host = window.location.hostname.toLowerCase();
17821
- if (host.endsWith(".ohhwells.site")) return;
17822
- const t = window.setTimeout(() => {
17823
- const retry = resolveSubdomain(subdomainFromQuery);
17824
- if (retry) setSubdomain(retry);
17825
- }, 0);
17826
- return () => window.clearTimeout(t);
17827
- }, [subdomainFromQuery, subdomain]);
17828
- (0, import_react17.useEffect)(() => {
17829
- if (!subdomainFromQuery || typeof window === "undefined") return;
17830
- const url = new URL(window.location.href);
17831
- if (!url.searchParams.has("subdomain")) return;
17832
- url.searchParams.delete("subdomain");
17833
- window.history.replaceState(null, "", url.pathname + url.search + url.hash);
17834
- }, [subdomainFromQuery]);
17408
+ const subdomain = resolveSubdomain(subdomainFromQuery);
17835
17409
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
17836
17410
  useSavedLinkNavigation(isEditMode);
17837
17411
  const postToParent2 = (0, import_react17.useCallback)((data) => {
@@ -17863,12 +17437,6 @@ function OhhwellsBridge() {
17863
17437
  const hoveredImageHasTextOverlapRef = (0, import_react17.useRef)(false);
17864
17438
  const dragOverElRef = (0, import_react17.useRef)(null);
17865
17439
  const [mediaHover, setMediaHover] = (0, import_react17.useState)(null);
17866
- const [selectedAiSectionId, setSelectedAiSectionId] = (0, import_react17.useState)(null);
17867
- const selectedAiSectionIdRef = (0, import_react17.useRef)(null);
17868
- const handleAiSectionSelectionChange = (0, import_react17.useCallback)((id) => {
17869
- selectedAiSectionIdRef.current = id;
17870
- setSelectedAiSectionId(id);
17871
- }, []);
17872
17440
  const [selectedMedia, setSelectedMedia] = (0, import_react17.useState)(null);
17873
17441
  const selectedMediaElRef = (0, import_react17.useRef)(null);
17874
17442
  const clearMediaSelection = (0, import_react17.useCallback)(() => {
@@ -18214,6 +17782,13 @@ function OhhwellsBridge() {
18214
17782
  const [isItemDragging, setIsItemDragging] = (0, import_react17.useState)(false);
18215
17783
  const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react17.useState)(false);
18216
17784
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
17785
+ const [floatingPanel, setFloatingPanel] = (0, import_react17.useState)(null);
17786
+ const floatingPanelOpenRef = (0, import_react17.useRef)(false);
17787
+ floatingPanelOpenRef.current = floatingPanel !== null;
17788
+ const [floatingPanelPos, setFloatingPanelPos] = (0, import_react17.useState)(null);
17789
+ const [logoSizeDraft, setLogoSizeDraft] = (0, import_react17.useState)(null);
17790
+ const [editorViewport, setEditorViewport] = (0, import_react17.useState)("desktop");
17791
+ const [parentScrollSnap, setParentScrollSnap] = (0, import_react17.useState)(null);
18217
17792
  const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react17.useState)(null);
18218
17793
  const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react17.useState)(null);
18219
17794
  const footerDragRef = (0, import_react17.useRef)(null);
@@ -18230,15 +17805,7 @@ function OhhwellsBridge() {
18230
17805
  const aiSectionsRef = (0, import_react17.useRef)("");
18231
17806
  const brandKitRef = (0, import_react17.useRef)("");
18232
17807
  const stylesRef = (0, import_react17.useRef)("");
18233
- const appliedDrawerRef = (0, import_react17.useRef)(null);
18234
17808
  const pendingDeleteUndoRef = (0, import_react17.useRef)(null);
18235
- const [floatingPanel, setFloatingPanel] = (0, import_react17.useState)(null);
18236
- const floatingPanelOpenRef = (0, import_react17.useRef)(false);
18237
- const setFloatingPanelRef = (0, import_react17.useRef)(setFloatingPanel);
18238
- const [floatingPanelPos, setFloatingPanelPos] = (0, import_react17.useState)(null);
18239
- const [logoSizeDraft, setLogoSizeDraft] = (0, import_react17.useState)(null);
18240
- const [editorViewport, setEditorViewport] = (0, import_react17.useState)("desktop");
18241
- const [parentScrollSnap, setParentScrollSnap] = (0, import_react17.useState)(null);
18242
17809
  const [sitePages, setSitePages] = (0, import_react17.useState)([]);
18243
17810
  const [sectionsByPath, setSectionsByPath] = (0, import_react17.useState)({});
18244
17811
  const sectionsPrefetchGenRef = (0, import_react17.useRef)(0);
@@ -18247,18 +17814,7 @@ function OhhwellsBridge() {
18247
17814
  const linkPopoverOpenRef = (0, import_react17.useRef)(false);
18248
17815
  const linkPopoverGraceUntilRef = (0, import_react17.useRef)(0);
18249
17816
  setLinkPopoverRef.current = setLinkPopover;
18250
- setFloatingPanelRef.current = setFloatingPanel;
18251
17817
  linkPopoverSessionRef.current = linkPopover;
18252
- floatingPanelOpenRef.current = Boolean(floatingPanel);
18253
- (0, import_react17.useEffect)(() => {
18254
- const syncViewport = () => {
18255
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
18256
- setEditorViewport((prev) => prev === next ? prev : next);
18257
- };
18258
- syncViewport();
18259
- window.addEventListener("resize", syncViewport);
18260
- return () => window.removeEventListener("resize", syncViewport);
18261
- }, []);
18262
17818
  const {
18263
17819
  navDragRef,
18264
17820
  navPointerDragRef,
@@ -19594,7 +19150,6 @@ function OhhwellsBridge() {
19594
19150
  }
19595
19151
  if (typeof content[STYLE_STORE_KEY] === "string") {
19596
19152
  stylesRef.current = content[STYLE_STORE_KEY];
19597
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
19598
19153
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
19599
19154
  }
19600
19155
  applyBrandChrome(content);
@@ -19602,11 +19157,11 @@ function OhhwellsBridge() {
19602
19157
  for (const [key, val] of Object.entries(content)) {
19603
19158
  if (key === "__ohw_sections") continue;
19604
19159
  if (key === AI_SECTIONS_KEY) continue;
19605
- if (key === LOGO_PLACEHOLDER_KEY) continue;
19606
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
19607
19160
  if (key === BRAND_KIT_KEY) continue;
19608
19161
  if (key === STYLE_STORE_KEY) continue;
19609
19162
  if (BRAND_CHROME_KEYS.has(key)) continue;
19163
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
19164
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
19610
19165
  if (applyVideoSettingNode(key, val)) continue;
19611
19166
  if (applyCarouselNode(key, val)) continue;
19612
19167
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -19677,9 +19232,7 @@ function OhhwellsBridge() {
19677
19232
  let cancelled = false;
19678
19233
  setFetchState("loading");
19679
19234
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
19680
- const initialPath = pathname;
19681
- fetchedContentPaths.add(`${subdomain}::${initialPath}`);
19682
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
19235
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
19683
19236
  if (cancelled) return;
19684
19237
  const content = data?.content ?? {};
19685
19238
  const branding = Boolean(data?.showBranding);
@@ -19788,9 +19341,7 @@ function OhhwellsBridge() {
19788
19341
  }, [isEditMode]);
19789
19342
  (0, import_react17.useEffect)(() => {
19790
19343
  if (isEditMode || fetchState !== "done") return;
19791
- console.log("env", process.env.NEXT_PUBLIC_FLOWOPS_API_URL);
19792
19344
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
19793
- console.log({ apiUrl, subdomain });
19794
19345
  bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
19795
19346
  }, [isEditMode, fetchState, subdomain]);
19796
19347
  (0, import_react17.useEffect)(() => {
@@ -19815,17 +19366,16 @@ function OhhwellsBridge() {
19815
19366
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
19816
19367
  }
19817
19368
  if (typeof content[STYLE_STORE_KEY] === "string") {
19818
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
19819
19369
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
19820
19370
  }
19821
19371
  for (const [key, val] of Object.entries(content)) {
19822
19372
  if (key === "__ohw_sections") continue;
19823
19373
  if (key === AI_SECTIONS_KEY) continue;
19824
- if (key === LOGO_PLACEHOLDER_KEY) continue;
19825
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
19826
19374
  if (key === BRAND_KIT_KEY) continue;
19827
19375
  if (key === STYLE_STORE_KEY) continue;
19828
19376
  if (BRAND_CHROME_KEYS.has(key)) continue;
19377
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
19378
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
19829
19379
  if (applyVideoSettingNode(key, val)) continue;
19830
19380
  if (applyCarouselNode(key, val)) continue;
19831
19381
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -19876,17 +19426,6 @@ function OhhwellsBridge() {
19876
19426
  debounceTimer = setTimeout(applyFromCache, 150);
19877
19427
  };
19878
19428
  applyFromCache();
19879
- const pathCacheKey = `${subdomain}::${pathname}`;
19880
- if (!fetchedContentPaths.has(pathCacheKey)) {
19881
- fetchedContentPaths.add(pathCacheKey);
19882
- const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
19883
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
19884
- if (!data?.content) return;
19885
- contentCache.set(subdomain, data.content);
19886
- applyFromCache();
19887
- }).catch(() => {
19888
- });
19889
- }
19890
19429
  observer = new MutationObserver(scheduleApply);
19891
19430
  observer.observe(document.body, { childList: true, subtree: true });
19892
19431
  return () => {
@@ -19931,17 +19470,6 @@ function OhhwellsBridge() {
19931
19470
  if (!isEditMode) return;
19932
19471
  initSectionInstancesFromContent(editContentRef.current, pathname);
19933
19472
  }, [pathname, isEditMode]);
19934
- (0, import_react17.useEffect)(() => {
19935
- if (!isEditMode) return;
19936
- const observer = new MutationObserver(() => {
19937
- const drawer = document.querySelector("[data-ohw-nav-drawer]");
19938
- if (!drawer || drawer === appliedDrawerRef.current) return;
19939
- appliedDrawerRef.current = drawer;
19940
- applyStylesToDom(parseStyleStore(stylesRef.current));
19941
- });
19942
- observer.observe(document.body, { childList: true, subtree: true });
19943
- return () => observer.disconnect();
19944
- }, [isEditMode, pathname]);
19945
19473
  (0, import_react17.useEffect)(() => {
19946
19474
  const contentForNav = () => {
19947
19475
  if (isEditMode) return editContentRef.current;
@@ -20033,11 +19561,26 @@ function OhhwellsBridge() {
20033
19561
  const t2 = setTimeout(measure, 500);
20034
19562
  const ro = new ResizeObserver(schedule);
20035
19563
  ro.observe(document.body);
19564
+ let lastWidth = window.innerWidth;
19565
+ let resizeTimers = [];
19566
+ const clearResizeTimers = () => {
19567
+ resizeTimers.forEach(clearTimeout);
19568
+ resizeTimers = [];
19569
+ };
19570
+ const handleResize = () => {
19571
+ if (window.innerWidth === lastWidth) return;
19572
+ lastWidth = window.innerWidth;
19573
+ clearResizeTimers();
19574
+ resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
19575
+ };
19576
+ window.addEventListener("resize", handleResize);
20036
19577
  return () => {
20037
19578
  clearTimeout(t1);
20038
19579
  clearTimeout(t2);
20039
19580
  if (raf != null) cancelAnimationFrame(raf);
20040
19581
  ro.disconnect();
19582
+ clearResizeTimers();
19583
+ window.removeEventListener("resize", handleResize);
20041
19584
  };
20042
19585
  }, [pathname, isEditMode, postToParent2]);
20043
19586
  (0, import_react17.useEffect)(() => {
@@ -20332,6 +19875,9 @@ function OhhwellsBridge() {
20332
19875
  if (target.closest("[data-ohw-state-toggle]")) return;
20333
19876
  if (target.closest("[data-ohw-max-badge]")) return;
20334
19877
  if (isInsideLinkEditor(target)) return;
19878
+ if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
19879
+ clearMediaSelectionRef.current();
19880
+ }
20335
19881
  if (isInsideFloatingPanel(target)) return;
20336
19882
  if (target.closest("[data-ohw-form-toolbar]")) return;
20337
19883
  if (target.closest(
@@ -20339,9 +19885,6 @@ function OhhwellsBridge() {
20339
19885
  )) {
20340
19886
  return;
20341
19887
  }
20342
- if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
20343
- clearMediaSelectionRef.current();
20344
- }
20345
19888
  {
20346
19889
  const formEl = getFormElement(target);
20347
19890
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -20505,17 +20048,17 @@ function OhhwellsBridge() {
20505
20048
  }
20506
20049
  const clickedButton = findClosestButtonLike(target);
20507
20050
  const buttonOnMedia = Boolean(clickedButton && isMediaEditable(editable) && editable.contains(clickedButton));
20051
+ console.log("[click-debug]", {
20052
+ editableType: editable.dataset.ohwEditable,
20053
+ editableTag: editable.tagName,
20054
+ targetTag: target.tagName,
20055
+ clickedButtonTag: clickedButton?.tagName ?? null,
20056
+ buttonOnMedia,
20057
+ isMediaEditableEditable: isMediaEditable(editable)
20058
+ });
20508
20059
  if (isMediaEditable(editable) && !buttonOnMedia) {
20509
20060
  e.preventDefault();
20510
20061
  e.stopPropagation();
20511
- const fullBleedSectionId = fullBleedSectionIdOf(editable);
20512
- if (fullBleedSectionId && fullBleedSectionId !== selectedAiSectionIdRef.current) {
20513
- clearMediaSelectionRef.current();
20514
- deselectRef.current();
20515
- deactivateRef.current();
20516
- aiSectionApiRef.current?.selectFromElement(editable);
20517
- return;
20518
- }
20519
20062
  if (selectedMediaElRef.current === editable) {
20520
20063
  postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
20521
20064
  } else {
@@ -20539,6 +20082,11 @@ function OhhwellsBridge() {
20539
20082
  const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
20540
20083
  const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
20541
20084
  const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
20085
+ console.log("[click-debug 2]", {
20086
+ hrefLookupTargetTag: hrefLookupTarget.tagName,
20087
+ hrefCtx: hrefCtx ? { key: hrefCtx.key } : null,
20088
+ navAnchorTag: navAnchor?.tagName ?? null
20089
+ });
20542
20090
  if (navAnchor) {
20543
20091
  e.preventDefault();
20544
20092
  e.stopPropagation();
@@ -20683,19 +20231,6 @@ function OhhwellsBridge() {
20683
20231
  const handleMouseOver = (e) => {
20684
20232
  if (document.documentElement.hasAttribute("data-ohw-section-picking")) return;
20685
20233
  const target = e.target;
20686
- if (isNavDrawerOpen() && isPointOutsideOpenDrawer(e.clientX, e.clientY)) {
20687
- document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
20688
- hoveredItemElRef.current = null;
20689
- setHoveredItemRect(null);
20690
- hoveredNavContainerRef.current = null;
20691
- setHoveredNavContainerRect(null);
20692
- formHoverElRef.current = null;
20693
- setFormHoverRect(null);
20694
- siblingHintElRef.current = null;
20695
- setSiblingHintRect(null);
20696
- setSiblingHintRects([]);
20697
- return;
20698
- }
20699
20234
  if (linkPopoverOpenRef.current) {
20700
20235
  hoveredItemElRef.current = null;
20701
20236
  setHoveredItemRect(null);
@@ -20721,9 +20256,6 @@ function OhhwellsBridge() {
20721
20256
  setHoveredItemRect(null);
20722
20257
  hoveredNavContainerRef.current = null;
20723
20258
  setHoveredNavContainerRect(null);
20724
- siblingHintElRef.current = null;
20725
- setSiblingHintRect(null);
20726
- setSiblingHintRects([]);
20727
20259
  return;
20728
20260
  }
20729
20261
  {
@@ -20844,6 +20376,7 @@ function OhhwellsBridge() {
20844
20376
  hoveredNavContainerRef.current = null;
20845
20377
  setHoveredNavContainerRect(null);
20846
20378
  hoveredItemElRef.current = editable;
20379
+ setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
20847
20380
  }
20848
20381
  }
20849
20382
  }
@@ -20967,7 +20500,6 @@ function OhhwellsBridge() {
20967
20500
  elementType: imgEl.dataset.ohwEditable ?? "image",
20968
20501
  hasTextOverlap,
20969
20502
  isDragOver,
20970
- fullBleedSectionId: fullBleedSectionIdOf(imgEl),
20971
20503
  ...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
20972
20504
  });
20973
20505
  const track = imgEl.closest("[data-ohw-hover-pause]");
@@ -21141,7 +20673,7 @@ function OhhwellsBridge() {
21141
20673
  }
21142
20674
  };
21143
20675
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
21144
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
20676
+ if (linkPopoverOpenRef.current) {
21145
20677
  if (hoveredImageRef.current) {
21146
20678
  hoveredImageRef.current = null;
21147
20679
  hoveredImageHasTextOverlapRef.current = false;
@@ -21514,31 +21046,7 @@ function OhhwellsBridge() {
21514
21046
  };
21515
21047
  const handleMouseMove = (e) => {
21516
21048
  const { clientX, clientY } = e;
21517
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
21518
- dismissImageHover();
21519
- clearImageHover();
21520
- return;
21521
- }
21522
- if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
21523
- document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
21524
- formHoverElRef.current = null;
21525
- setFormHoverRect(null);
21526
- hoveredItemElRef.current = null;
21527
- setHoveredItemRect(null);
21528
- hoveredNavContainerRef.current = null;
21529
- setHoveredNavContainerRect(null);
21530
- dismissImageHover();
21531
- if (hoveredGapRef.current) {
21532
- hoveredGapRef.current = null;
21533
- setSectionGap(null);
21534
- }
21535
- if (activeStateElRef.current) {
21536
- activeStateElRef.current.removeAttribute("data-ohw-state-hovered");
21537
- activeStateElRef.current = null;
21538
- setToggleState(null);
21539
- }
21540
- return;
21541
- }
21049
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
21542
21050
  if (isOverEditorChrome(clientX, clientY)) {
21543
21051
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
21544
21052
  formHoverElRef.current = null;
@@ -21547,12 +21055,7 @@ function OhhwellsBridge() {
21547
21055
  setHoveredItemRect(null);
21548
21056
  hoveredNavContainerRef.current = null;
21549
21057
  setHoveredNavContainerRect(null);
21550
- siblingHintElRef.current = null;
21551
- setSiblingHintRect(null);
21552
- setSiblingHintRects([]);
21553
21058
  dismissImageHover();
21554
- clearImageHover();
21555
- setSectionGap(null);
21556
21059
  return;
21557
21060
  }
21558
21061
  if (probeSocialsRowAt(clientX, clientY)) return;
@@ -21564,12 +21067,7 @@ function OhhwellsBridge() {
21564
21067
  if (e.data?.type !== "ow:pointer-sync") return;
21565
21068
  const { clientX, clientY } = e.data;
21566
21069
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
21567
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
21568
- dismissImageHover();
21569
- clearImageHover();
21570
- return;
21571
- }
21572
- if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
21070
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
21573
21071
  if (probeSocialsRowAt(clientX, clientY)) return;
21574
21072
  probeSectionGapAt(clientX, clientY);
21575
21073
  probeImageAt(clientX, clientY);
@@ -21908,7 +21406,6 @@ function OhhwellsBridge() {
21908
21406
  }
21909
21407
  if (typeof content[STYLE_STORE_KEY] === "string") {
21910
21408
  stylesRef.current = content[STYLE_STORE_KEY];
21911
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
21912
21409
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
21913
21410
  }
21914
21411
  applyBrandChrome(content);
@@ -21920,11 +21417,11 @@ function OhhwellsBridge() {
21920
21417
  continue;
21921
21418
  }
21922
21419
  if (key === AI_SECTIONS_KEY) continue;
21923
- if (key === LOGO_PLACEHOLDER_KEY) continue;
21924
- if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
21925
21420
  if (key === BRAND_KIT_KEY) continue;
21926
21421
  if (key === STYLE_STORE_KEY) continue;
21927
21422
  if (BRAND_CHROME_KEYS.has(key)) continue;
21423
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
21424
+ if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
21928
21425
  if (applyVideoSettingNode(key, val)) continue;
21929
21426
  if (applyCarouselNode(key, val)) continue;
21930
21427
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -22149,26 +21646,10 @@ function OhhwellsBridge() {
22149
21646
  const handleGetBrand = (e) => {
22150
21647
  if (e.data?.type !== "ow:get-brand") return;
22151
21648
  const template = deriveTemplateBrand();
22152
- const fallback = template ?? (() => {
22153
- const fonts = deriveTemplateFonts();
22154
- return fonts ? { palette: AI_DEFAULT_BRAND.palette, fonts } : null;
22155
- })();
22156
- const value = brandKitRef.current || (fallback ? JSON.stringify(fallback) : "");
21649
+ const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
22157
21650
  postToParentRef.current({ type: "ow:brand-value", value });
22158
21651
  };
22159
21652
  window.addEventListener("message", handleGetBrand);
22160
- const handleGetTemplateFonts = (e) => {
22161
- if (e.data?.type !== "ow:get-template-fonts") return;
22162
- const fonts = deriveTemplateFonts();
22163
- postToParentRef.current({ type: "ow:template-fonts-value", value: fonts ? JSON.stringify(fonts) : "" });
22164
- };
22165
- window.addEventListener("message", handleGetTemplateFonts);
22166
- const handleGetTemplateBrand = (e) => {
22167
- if (e.data?.type !== "ow:get-template-brand") return;
22168
- const brand = deriveTemplateBrand();
22169
- postToParentRef.current({ type: "ow:template-brand-value", value: brand ? JSON.stringify(brand) : "" });
22170
- };
22171
- window.addEventListener("message", handleGetTemplateBrand);
22172
21653
  const handleMoveSection = (e) => {
22173
21654
  if (e.data?.type !== "ow:move-section") return;
22174
21655
  const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
@@ -22361,12 +21842,6 @@ function OhhwellsBridge() {
22361
21842
  closeLinkPopoverRef.current();
22362
21843
  return;
22363
21844
  }
22364
- if (floatingPanelOpenRef.current) {
22365
- setFloatingPanelRef.current(null);
22366
- deselectRef.current();
22367
- deactivateRef.current();
22368
- return;
22369
- }
22370
21845
  deselectRef.current();
22371
21846
  deactivateRef.current();
22372
21847
  clearMediaSelectionRef.current();
@@ -22655,12 +22130,8 @@ function OhhwellsBridge() {
22655
22130
  if (inserted) {
22656
22131
  const tracker = getSectionsTracker();
22657
22132
  postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
22658
- const reportHeight = () => {
22659
- const h = document.body.scrollHeight;
22660
- if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
22661
- };
22662
- reportHeight();
22663
- setTimeout(reportHeight, 500);
22133
+ const h = document.body.scrollHeight;
22134
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
22664
22135
  }
22665
22136
  };
22666
22137
  const handleSwitchSchedule = (e) => {
@@ -22832,11 +22303,7 @@ function OhhwellsBridge() {
22832
22303
  if (!key) return;
22833
22304
  const r2 = getVisibleRect(container);
22834
22305
  setCarouselHover(
22835
- (prev) => prev && prev.key === key && prev.rect.top === r2.top && prev.rect.left === r2.left && prev.rect.width === r2.width && prev.rect.height === r2.height ? prev : {
22836
- key,
22837
- rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
22838
- fullBleedSectionId: fullBleedSectionIdOf(container)
22839
- }
22306
+ (prev) => prev && prev.key === key && prev.rect.top === r2.top && prev.rect.left === r2.left && prev.rect.width === r2.width && prev.rect.height === r2.height ? prev : { key, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } }
22840
22307
  );
22841
22308
  };
22842
22309
  const applyToolbarPos = (rect) => {
@@ -23085,17 +22552,15 @@ function OhhwellsBridge() {
23085
22552
  window.removeEventListener("message", handleAiSetBrand);
23086
22553
  window.removeEventListener("message", handleAiSetStyles);
23087
22554
  window.removeEventListener("message", handleGetBrand);
23088
- window.removeEventListener("message", handleGetTemplateFonts);
23089
- window.removeEventListener("message", handleGetTemplateBrand);
23090
22555
  window.removeEventListener("message", handleMoveSection);
23091
22556
  window.removeEventListener("message", handlePanelDragging);
23092
22557
  window.removeEventListener("message", handleDeleteSection);
23093
22558
  window.removeEventListener("message", handleDuplicateSection);
23094
22559
  window.removeEventListener("message", handleDeactivate);
22560
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
23095
22561
  window.removeEventListener("message", handleToastAction);
23096
22562
  window.removeEventListener("message", handleFormCount);
23097
22563
  window.removeEventListener("message", handleUiEscape);
23098
- document.documentElement.removeAttribute("data-ohw-panel-dragging");
23099
22564
  autoSaveTimers.current.forEach(clearTimeout);
23100
22565
  autoSaveTimers.current.clear();
23101
22566
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
@@ -23765,14 +23230,7 @@ function OhhwellsBridge() {
23765
23230
  bridgeRoot ? (0, import_react_dom5.createPortal)(
23766
23231
  /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
23767
23232
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
23768
- isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
23769
- AiSectionOverlay,
23770
- {
23771
- postToParent: postToParent2,
23772
- apiRef: aiSectionApiRef,
23773
- onSelectionChange: handleAiSectionSelectionChange
23774
- }
23775
- ),
23233
+ isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
23776
23234
  isSectionDragging && sectionDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
23777
23235
  "div",
23778
23236
  {
@@ -23805,7 +23263,6 @@ function OhhwellsBridge() {
23805
23263
  {
23806
23264
  hover: mediaHover,
23807
23265
  isUploading: false,
23808
- cueOnly: !mediaHover.isDragOver && !!mediaHover.fullBleedSectionId && mediaHover.fullBleedSectionId !== selectedAiSectionId,
23809
23266
  onReplace: handleMediaReplace,
23810
23267
  onSelect: handleMediaSelect,
23811
23268
  onVideoSettingsChange: handleVideoSettingsChange
@@ -23823,14 +23280,7 @@ function OhhwellsBridge() {
23823
23280
  onVideoSettingsChange: handleVideoSettingsChange
23824
23281
  }
23825
23282
  ),
23826
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
23827
- CarouselOverlay,
23828
- {
23829
- hover: carouselHover,
23830
- onEdit: handleEditCarousel,
23831
- cueOnly: !!carouselHover.fullBleedSectionId && carouselHover.fullBleedSectionId !== selectedAiSectionId
23832
- }
23833
- ),
23283
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
23834
23284
  siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
23835
23285
  siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
23836
23286
  isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
@@ -23929,7 +23379,7 @@ function OhhwellsBridge() {
23929
23379
  "span",
23930
23380
  {
23931
23381
  "data-ohw-form-count": "",
23932
- className: "ml-0.5 inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-bridge-primary px-1.5 text-[11px] font-semibold text-primary-foreground",
23382
+ className: "ml-0.5 inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-primary px-1.5 text-[11px] font-semibold text-primary-foreground",
23933
23383
  children: formPickCount
23934
23384
  }
23935
23385
  )
@@ -24167,11 +23617,11 @@ function OhhwellsBridge() {
24167
23617
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
24168
23618
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
24169
23619
  children: [
24170
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } }),
23620
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
24171
23621
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
24172
23622
  Badge,
24173
23623
  {
24174
- className: "px-8 py-1 bg-bridge-primary hover:bg-bridge-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
23624
+ className: "px-8 py-1 bg-primary hover:bg-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
24175
23625
  onClick: () => {
24176
23626
  window.parent.postMessage(
24177
23627
  {
@@ -24185,7 +23635,7 @@ function OhhwellsBridge() {
24185
23635
  children: "Add Section"
24186
23636
  }
24187
23637
  ),
24188
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } })
23638
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
24189
23639
  ]
24190
23640
  }
24191
23641
  ),
@@ -24233,59 +23683,6 @@ function OhhwellsBridge() {
24233
23683
  ) : null
24234
23684
  ] });
24235
23685
  }
24236
-
24237
- // src/ui/EmptySection.tsx
24238
- var import_link = __toESM(require("next/link"), 1);
24239
- var import_jsx_runtime34 = require("react/jsx-runtime");
24240
- function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
24241
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
24242
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
24243
- "p",
24244
- {
24245
- style: {
24246
- fontFamily: "var(--brand-font-body)",
24247
- fontSize: "0.75rem",
24248
- fontWeight: 500,
24249
- letterSpacing: "0.15em",
24250
- textTransform: "uppercase",
24251
- color: "var(--brand-accent)",
24252
- marginBottom: "1.5rem"
24253
- },
24254
- children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_link.default, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
24255
- }
24256
- ),
24257
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
24258
- "h1",
24259
- {
24260
- style: {
24261
- fontFamily: "var(--brand-font-heading)",
24262
- fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
24263
- lineHeight: 1.1,
24264
- letterSpacing: "-0.025em",
24265
- color: "var(--brand-text)",
24266
- marginBottom: "1rem"
24267
- },
24268
- ...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
24269
- children: title
24270
- }
24271
- ),
24272
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
24273
- "p",
24274
- {
24275
- style: {
24276
- fontFamily: "var(--brand-font-body)",
24277
- fontSize: "1rem",
24278
- lineHeight: 1.7,
24279
- fontWeight: 300,
24280
- color: "var(--brand-text-muted)",
24281
- maxWidth: "340px"
24282
- },
24283
- ...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
24284
- children: "This page doesn't have any content yet."
24285
- }
24286
- )
24287
- ] });
24288
- }
24289
23686
  // Annotate the CommonJS export names for ESM import in node:
24290
23687
  0 && (module.exports = {
24291
23688
  AI_DEFAULT_BRAND,
@@ -24303,7 +23700,6 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
24303
23700
  DropdownMenuItem,
24304
23701
  DropdownMenuSeparator,
24305
23702
  DropdownMenuTrigger,
24306
- EmptySection,
24307
23703
  ItemActionToolbar,
24308
23704
  ItemInteractionLayer,
24309
23705
  LinkEditorPanel,