@ohhwells/bridge 0.1.115 → 0.1.117

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
@@ -352,16 +352,17 @@ var LEGACY_BRAND_VAR_NAMES = [
352
352
  "text-muted",
353
353
  "surface",
354
354
  "border",
355
- "on-primary",
356
- "navbar-background"
355
+ "on-primary"
357
356
  ].map((role) => `--brand-${role}`);
358
357
  var FONT_VARS = {
359
358
  heading: ["--font-heading", "--font-display", "--brand-font-heading"],
360
359
  body: ["--font-body", "--brand-font-body"]
361
360
  };
362
361
  var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
363
- function brandColorVars(kit) {
364
- const { dark, primary, accent, light } = kit.palette;
362
+ var CUSTOM_FONT_STYLE_ID = "ohw-brand-custom-fonts";
363
+ var CUSTOM_FONT_FORMATS = /* @__PURE__ */ new Set(["woff2", "woff", "truetype", "opentype"]);
364
+ function brandColorVars(palette) {
365
+ const { dark, primary, accent, light } = palette;
365
366
  const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
366
367
  const surface = mix(light, 95, dark);
367
368
  const border = mix(light, 85, dark);
@@ -384,22 +385,42 @@ function brandColorVars(kit) {
384
385
  "--brand-border": border,
385
386
  // Buttons/bands painted in the primary colour assume it's dark/saturated enough to need
386
387
  // light text on top — the same assumption LOGO_IMAGE's light-on-dark navbar mark makes.
387
- "--brand-on-primary": light,
388
- "--brand-navbar-background": dark
388
+ "--brand-on-primary": light
389
389
  };
390
390
  }
391
+ function parseCustomFontWeight(raw) {
392
+ if (typeof raw !== "object" || raw === null) return null;
393
+ const w = raw;
394
+ if (typeof w.weight !== "number" || !Number.isFinite(w.weight)) return null;
395
+ if (typeof w.url !== "string" || !w.url) return null;
396
+ if (typeof w.format !== "string" || !CUSTOM_FONT_FORMATS.has(w.format)) return null;
397
+ const weightEnd = typeof w.weightEnd === "number" && Number.isFinite(w.weightEnd) && w.weightEnd > w.weight ? w.weightEnd : void 0;
398
+ return { weight: w.weight, ...weightEnd !== void 0 ? { weightEnd } : {}, url: w.url, format: w.format };
399
+ }
400
+ function parseCustomFont(raw) {
401
+ if (typeof raw !== "object" || raw === null) return null;
402
+ const f = raw;
403
+ if (typeof f.family !== "string" || !f.family) return null;
404
+ if (typeof f.label !== "string" || !f.label) return null;
405
+ if (!Array.isArray(f.weights)) return null;
406
+ const weights = f.weights.map(parseCustomFontWeight).filter((w) => w !== null);
407
+ if (weights.length === 0) return null;
408
+ return { family: f.family, label: f.label, weights };
409
+ }
391
410
  function parseBrandKit(raw) {
392
411
  if (!raw) return null;
393
412
  try {
394
413
  const parsed = JSON.parse(raw);
395
414
  const p = parsed?.palette;
396
415
  const f = parsed?.fonts;
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
- }
416
+ 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;
417
+ const fonts = f && typeof f.heading === "string" && typeof f.body === "string" ? { heading: f.heading, body: f.body } : void 0;
418
+ const customFonts = Array.isArray(parsed?.customFonts) ? parsed.customFonts.map(parseCustomFont).filter((c) => c !== null) : void 0;
419
+ if (!palette && !fonts && !customFonts) return null;
400
420
  return {
401
- palette: { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light },
402
- fonts: { heading: f.heading, body: f.body }
421
+ ...palette ? { palette } : {},
422
+ ...fonts ? { fonts } : {},
423
+ ...customFonts ? { customFonts } : {}
403
424
  };
404
425
  } catch {
405
426
  return null;
@@ -409,11 +430,16 @@ function familyOf(stack) {
409
430
  const first = stack.split(",")[0]?.trim() ?? "";
410
431
  return first.replace(/^['"]|['"]$/g, "");
411
432
  }
433
+ function quoteFamily(family) {
434
+ return `'${family.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
435
+ }
436
+ var WEIGHT_SCALE = [100, 200, 300, 400, 500, 600, 700, 800, 900];
412
437
  function loadBrandFonts(families) {
413
438
  const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
414
439
  if (unique.length === 0) return;
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`;
440
+ const weights = WEIGHT_SCALE.join(";");
441
+ const spec = unique.map((f) => `family=${f.replace(/ /g, "+")}:wght@${weights}`).join("&");
442
+ const href = `https://fonts.googleapis.com/css2?${spec}&display=swap`;
417
443
  let link = document.getElementById(BRAND_FONT_LINK_ID);
418
444
  if (!link) {
419
445
  link = document.createElement("link");
@@ -423,18 +449,54 @@ function loadBrandFonts(families) {
423
449
  }
424
450
  if (link.href !== href) link.href = href;
425
451
  }
452
+ function escapeCssString(value) {
453
+ return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
454
+ }
455
+ function loadCustomFonts(fonts) {
456
+ const list = fonts ?? [];
457
+ let style = document.getElementById(CUSTOM_FONT_STYLE_ID);
458
+ if (list.length === 0) {
459
+ style?.remove();
460
+ return;
461
+ }
462
+ if (!style) {
463
+ style = document.createElement("style");
464
+ style.id = CUSTOM_FONT_STYLE_ID;
465
+ document.head.appendChild(style);
466
+ }
467
+ style.textContent = list.flatMap(
468
+ (font) => font.weights.map((w) => {
469
+ const weightDescriptor = w.weightEnd ? `${w.weight} ${w.weightEnd}` : `${w.weight}`;
470
+ return `@font-face { font-family: '${escapeCssString(font.family)}'; src: url('${escapeCssString(w.url)}') format('${w.format}'); font-weight: ${weightDescriptor}; font-display: swap; }`;
471
+ })
472
+ ).join("\n");
473
+ }
426
474
  function applyBrandToDom(kit) {
427
475
  const root = document.documentElement;
428
476
  if (!kit) {
429
477
  for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES]) root.style.removeProperty(name);
430
478
  for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
431
479
  document.getElementById(BRAND_FONT_LINK_ID)?.remove();
480
+ document.getElementById(CUSTOM_FONT_STYLE_ID)?.remove();
432
481
  return;
433
482
  }
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)]);
483
+ if (kit.palette) {
484
+ for (const [name, value] of Object.entries(brandColorVars(kit.palette))) root.style.setProperty(name, value);
485
+ }
486
+ if (kit.customFonts) {
487
+ loadCustomFonts(kit.customFonts);
488
+ }
489
+ if (kit.fonts) {
490
+ const heading = quoteFamily(kit.fonts.heading);
491
+ const body = quoteFamily(kit.fonts.body);
492
+ for (const name of FONT_VARS.heading) root.style.setProperty(name, heading);
493
+ for (const name of FONT_VARS.body) root.style.setProperty(name, body);
494
+ const customFamilies = new Set((kit.customFonts ?? []).map((f) => f.family));
495
+ const googleFamilies = [familyOf(kit.fonts.heading), familyOf(kit.fonts.body)].filter(
496
+ (f) => !customFamilies.has(f)
497
+ );
498
+ loadBrandFonts(googleFamilies);
499
+ }
438
500
  }
439
501
 
440
502
  // src/lib/section-styles.ts
@@ -2723,14 +2785,52 @@ function readRootVar(name) {
2723
2785
  if (typeof document === "undefined") return "";
2724
2786
  return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
2725
2787
  }
2788
+ function normalizeColorToHex(value) {
2789
+ if (!value || typeof document === "undefined") return value;
2790
+ const canvas = document.createElement("canvas");
2791
+ canvas.width = 1;
2792
+ canvas.height = 1;
2793
+ const ctx = canvas.getContext("2d");
2794
+ if (!ctx) return value;
2795
+ ctx.fillStyle = value;
2796
+ ctx.fillRect(0, 0, 1, 1);
2797
+ const [r2, g, b] = ctx.getImageData(0, 0, 1, 1).data;
2798
+ const toHex = (n) => n.toString(16).padStart(2, "0");
2799
+ return `#${toHex(r2)}${toHex(g)}${toHex(b)}`;
2800
+ }
2801
+ var GENERIC_FONT_KEYWORDS = /* @__PURE__ */ new Set([
2802
+ "serif",
2803
+ "sans-serif",
2804
+ "monospace",
2805
+ "cursive",
2806
+ "fantasy",
2807
+ "system-ui",
2808
+ "ui-serif",
2809
+ "ui-sans-serif",
2810
+ "ui-monospace",
2811
+ "ui-rounded",
2812
+ "math",
2813
+ "emoji",
2814
+ "fangsong"
2815
+ ]);
2816
+ function primaryFontFamily(stack) {
2817
+ const first = stack.split(",").map((part) => part.trim().replace(/^["']|["']$/g, "")).find((part) => part && !GENERIC_FONT_KEYWORDS.has(part.toLowerCase()));
2818
+ return first ?? "";
2819
+ }
2820
+ function humanizeFontFamily(name) {
2821
+ 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());
2822
+ }
2823
+ function readFontVar(name) {
2824
+ return humanizeFontFamily(primaryFontFamily(readRootVar(name)));
2825
+ }
2726
2826
  function deriveBrandOverride() {
2727
2827
  const dark = readRootVar("--ohw-brand-dark");
2728
2828
  const primary = readRootVar("--ohw-brand-primary");
2729
2829
  const light = readRootVar("--ohw-brand-light");
2730
2830
  if (!dark || !primary || !light) return null;
2731
2831
  const accent = readRootVar("--ohw-brand-accent");
2732
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
2733
- const body = readRootVar("--font-body");
2832
+ const heading = readFontVar("--font-heading") || readFontVar("--font-display");
2833
+ const body = readFontVar("--font-body");
2734
2834
  return {
2735
2835
  palette: { dark, primary, accent: accent || dark, light },
2736
2836
  fonts: {
@@ -2739,22 +2839,55 @@ function deriveBrandOverride() {
2739
2839
  }
2740
2840
  };
2741
2841
  }
2742
- function deriveTemplateBrand() {
2842
+ function deriveTemplateBrandLive() {
2743
2843
  const primary = readRootVar("--brand-primary") || readRootVar("--color-primary");
2744
2844
  const dark = readRootVar("--brand-text") || readRootVar("--color-dark");
2745
2845
  const light = readRootVar("--brand-background") || readRootVar("--color-light");
2746
2846
  if (!dark || !primary || !light) return null;
2747
2847
  const accent = readRootVar("--brand-accent") || readRootVar("--color-accent");
2748
- const heading = readRootVar("--brand-font-heading") || readRootVar("--font-heading") || readRootVar("--font-display");
2749
- const body = readRootVar("--brand-font-body") || readRootVar("--font-body");
2848
+ const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
2849
+ const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
2750
2850
  return {
2751
- palette: { dark, primary, accent: accent || dark, light },
2851
+ palette: {
2852
+ dark: normalizeColorToHex(dark),
2853
+ primary: normalizeColorToHex(primary),
2854
+ accent: normalizeColorToHex(accent || dark),
2855
+ light: normalizeColorToHex(light)
2856
+ },
2752
2857
  fonts: {
2753
2858
  heading: heading || AI_DEFAULT_BRAND.fonts.heading,
2754
2859
  body: body || AI_DEFAULT_BRAND.fonts.body
2755
2860
  }
2756
2861
  };
2757
2862
  }
2863
+ function deriveTemplateFontsLive() {
2864
+ const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
2865
+ const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
2866
+ if (!heading && !body) return null;
2867
+ return {
2868
+ heading: heading || AI_DEFAULT_BRAND.fonts.heading,
2869
+ body: body || AI_DEFAULT_BRAND.fonts.body
2870
+ };
2871
+ }
2872
+ var OVERRIDE_VAR_NAMES = [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES, ...FONT_VARS.heading, ...FONT_VARS.body];
2873
+ function withOverrideStripped(read) {
2874
+ const root = document.documentElement;
2875
+ const restore = OVERRIDE_VAR_NAMES.map((name) => [name, root.style.getPropertyValue(name)]);
2876
+ for (const name of OVERRIDE_VAR_NAMES) root.style.removeProperty(name);
2877
+ try {
2878
+ return read();
2879
+ } finally {
2880
+ for (const [name, value] of restore) if (value) root.style.setProperty(name, value);
2881
+ }
2882
+ }
2883
+ var TEMPLATE_BRAND_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateBrandLive);
2884
+ var TEMPLATE_FONTS_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateFontsLive);
2885
+ function deriveTemplateBrand() {
2886
+ return TEMPLATE_BRAND_SNAPSHOT;
2887
+ }
2888
+ function deriveTemplateFonts() {
2889
+ return TEMPLATE_FONTS_SNAPSHOT;
2890
+ }
2758
2891
  function deriveTemplateButtonStyle() {
2759
2892
  if (typeof document === "undefined") return null;
2760
2893
  const candidates = Array.from(
@@ -7252,12 +7385,12 @@ var cva = (base, config) => (props) => {
7252
7385
  var import_radix_ui2 = require("radix-ui");
7253
7386
  var import_jsx_runtime5 = require("react/jsx-runtime");
7254
7387
  var toggleVariants = cva(
7255
- "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",
7388
+ "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",
7256
7389
  {
7257
7390
  variants: {
7258
7391
  variant: {
7259
7392
  default: "bg-transparent border-0",
7260
- outline: "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground"
7393
+ outline: "border border-input bg-transparent shadow-xs hover:bg-bridge-accent hover:text-accent-foreground"
7261
7394
  },
7262
7395
  size: {
7263
7396
  default: "px-2 py-1",
@@ -7350,10 +7483,10 @@ var DragHandle = React4.forwardRef(
7350
7483
  type,
7351
7484
  "data-slot": "drag-handle",
7352
7485
  className: cn(
7353
- "inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-[30px]",
7486
+ "inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-7.5",
7354
7487
  "bg-white border border-transparent text-stone-500 shadow-md cursor-grab",
7355
7488
  "enabled:hover:border enabled:hover:border-stone-200 enabled:hover:text-stone-950",
7356
- "enabled:active:border enabled:active:border-primary enabled:active:bg-primary-50 enabled:active:text-stone-950 enabled:active:shadow enabled:active:cursor-grabbing",
7489
+ "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",
7357
7490
  "disabled:cursor-not-allowed disabled:opacity-40 disabled:text-stone-950 disabled:pointer-events-none",
7358
7491
  className
7359
7492
  ),
@@ -7375,7 +7508,7 @@ var CustomToolbar = React5.forwardRef(({ className, onMouseDown, ...props }, ref
7375
7508
  "data-ohw-toolbar": "",
7376
7509
  className: cn(
7377
7510
  // Figma: bg background, radius 8, gap-1, p-0.5, shadow-md — no border
7378
- "inline-flex h-8 items-center gap-1 rounded-[var(--radius,0.5rem)] bg-background p-0.5 font-sans whitespace-nowrap shadow-md",
7511
+ "inline-flex h-8 items-center gap-1 rounded-(--radius,0.5rem) bg-background p-0.5 font-sans whitespace-nowrap shadow-md",
7379
7512
  className
7380
7513
  ),
7381
7514
  onMouseDown: (e) => {
@@ -7404,7 +7537,7 @@ var CustomToolbarButton = React5.forwardRef(
7404
7537
  type,
7405
7538
  className: cn(
7406
7539
  "inline-flex size-7 shrink-0 items-center justify-center rounded-[calc(var(--radius,0.5rem)-2px)] text-foreground transition-colors",
7407
- active ? "bg-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
7540
+ active ? "bg-bridge-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
7408
7541
  className
7409
7542
  ),
7410
7543
  ...props
@@ -8668,13 +8801,13 @@ function FormFieldToolbar({
8668
8801
  ]
8669
8802
  }
8670
8803
  ) }),
8671
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-[190px] p-1", children: FIELD_TYPES.map((entry) => {
8804
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-47.5 p-1", children: FIELD_TYPES.map((entry) => {
8672
8805
  const Icon = TYPE_ICONS[entry.type];
8673
8806
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
8674
8807
  DropdownMenuItem,
8675
8808
  {
8676
8809
  onSelect: () => onTypeChange(entry.type),
8677
- className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-primary/10" : ""),
8810
+ className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-bridge-primary/10" : ""),
8678
8811
  children: [
8679
8812
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
8680
8813
  entry.label
@@ -8691,7 +8824,7 @@ function FormFieldToolbar({
8691
8824
  type: "button",
8692
8825
  "aria-pressed": required,
8693
8826
  onClick: onRequiredToggle,
8694
- 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"),
8827
+ 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"),
8695
8828
  "data-ohw-field-required-toggle": "",
8696
8829
  children: [
8697
8830
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Asterisk, { size: 14, strokeWidth: 2, "aria-hidden": true }),
@@ -8711,7 +8844,7 @@ function FormFieldToolbar({
8711
8844
  children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.MoreHorizontal, { size: 15, "aria-hidden": true })
8712
8845
  }
8713
8846
  ) }),
8714
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-[170px] p-1", children: [
8847
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-42.5 p-1", children: [
8715
8848
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuItem, { onSelect: onDuplicate, className: "rounded-md py-2 text-[13px]", children: [
8716
8849
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Copy, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
8717
8850
  "Duplicate"
@@ -8739,7 +8872,7 @@ function FieldTypePicker({ onPick }) {
8739
8872
  {
8740
8873
  type: "button",
8741
8874
  onClick: () => onPick(entry.type),
8742
- 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",
8875
+ 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",
8743
8876
  children: [
8744
8877
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 26, strokeWidth: 1.5, "aria-hidden": true }),
8745
8878
  entry.label
@@ -8765,7 +8898,7 @@ var buttonVariants = cva(
8765
8898
  {
8766
8899
  variants: {
8767
8900
  variant: {
8768
- default: "bg-primary text-primary-foreground hover:opacity-90",
8901
+ default: "bg-bridge-primary text-primary-foreground hover:opacity-90",
8769
8902
  outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
8770
8903
  ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
8771
8904
  },
@@ -8838,6 +8971,7 @@ function MediaOverlay({
8838
8971
  fadingOut = false,
8839
8972
  selected = false,
8840
8973
  hovered = false,
8974
+ cueOnly = false,
8841
8975
  onFadeOutComplete,
8842
8976
  onReplace,
8843
8977
  onSelect,
@@ -8846,7 +8980,7 @@ function MediaOverlay({
8846
8980
  const { rect } = hover;
8847
8981
  const skeletonRef = React8.useRef(null);
8848
8982
  const isVideo = hover.elementType === "video";
8849
- const showChrome = !selected || hovered;
8983
+ const showChrome = (!selected || hovered) && !cueOnly;
8850
8984
  const autoplay = hover.videoAutoplay ?? true;
8851
8985
  const muted = hover.videoMuted ?? true;
8852
8986
  const probeRef = React8.useRef(null);
@@ -8962,11 +9096,11 @@ function MediaOverlay({
8962
9096
  // parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
8963
9097
  // in-document, pointer-events does it natively. The button below opts back in, so
8964
9098
  // Replace still works.
8965
- pointerEvents: hover.hasTextOverlap ? "none" : "auto",
9099
+ pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
8966
9100
  // Selected: a firm component ring with no wash, so the image reads as chosen rather
8967
9101
  // than hovered. Hover keeps the existing tinted preview.
8968
- boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
8969
- background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
9102
+ boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
9103
+ background: selected ? "transparent" : "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
8970
9104
  },
8971
9105
  onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
8972
9106
  children: [
@@ -8993,7 +9127,7 @@ function MediaOverlay({
8993
9127
  ]
8994
9128
  }
8995
9129
  ),
8996
- replaceMode === "none" ? null : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
9130
+ replaceMode === "none" || cueOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
8997
9131
  Button,
8998
9132
  {
8999
9133
  "data-ohw-media-overlay": "",
@@ -9013,7 +9147,7 @@ function MediaOverlay({
9013
9147
  justifyContent: "center"
9014
9148
  } : null,
9015
9149
  // Don't let Replace steal clicks when text (e.g. nav) sits on top of this media.
9016
- pointerEvents: hover.hasTextOverlap ? "none" : "auto"
9150
+ pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto"
9017
9151
  },
9018
9152
  onMouseDown: (e) => e.preventDefault(),
9019
9153
  onClick: (e) => {
@@ -9043,7 +9177,8 @@ var OVERLAY_BUTTON_STYLE2 = {
9043
9177
  };
9044
9178
  function CarouselOverlay({
9045
9179
  hover,
9046
- onEdit
9180
+ onEdit,
9181
+ cueOnly = false
9047
9182
  }) {
9048
9183
  const { rect } = hover;
9049
9184
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
@@ -9059,12 +9194,12 @@ function CarouselOverlay({
9059
9194
  width: rect.width,
9060
9195
  height: rect.height,
9061
9196
  zIndex: 2147483646,
9062
- pointerEvents: "auto",
9063
- boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
9064
- background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
9197
+ pointerEvents: cueOnly ? "none" : "auto",
9198
+ boxShadow: "inset 0 0 0 1.5px var(--color-bridge-primary)",
9199
+ background: "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
9065
9200
  },
9066
9201
  onClick: () => onEdit(hover.key),
9067
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
9202
+ children: cueOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
9068
9203
  Button,
9069
9204
  {
9070
9205
  "data-ohw-carousel-overlay": "",
@@ -9255,7 +9390,8 @@ function ReviewButton({
9255
9390
  }
9256
9391
  function AiSectionOverlay({
9257
9392
  postToParent: postToParent2,
9258
- apiRef
9393
+ apiRef,
9394
+ onSelectionChange
9259
9395
  }) {
9260
9396
  const [selectedId, setSelectedId] = (0, import_react8.useState)(null);
9261
9397
  const [reviewId, setReviewId] = (0, import_react8.useState)(null);
@@ -9264,6 +9400,9 @@ function AiSectionOverlay({
9264
9400
  reviewIdRef.current = reviewId;
9265
9401
  const selectedIdRef = (0, import_react8.useRef)(null);
9266
9402
  selectedIdRef.current = selectedId;
9403
+ (0, import_react8.useEffect)(() => {
9404
+ onSelectionChange?.(selectedId);
9405
+ }, [selectedId, onSelectionChange]);
9267
9406
  const report = (0, import_react8.useCallback)(
9268
9407
  (el) => {
9269
9408
  const labelSrc = el ? sectionElementOf(el) : null;
@@ -9281,6 +9420,7 @@ function AiSectionOverlay({
9281
9420
  const sectionEl = inner ? movableUnit(inner) : null;
9282
9421
  const id = sectionEl ? instanceIdOf(sectionEl) || null : null;
9283
9422
  if (id === selectedIdRef.current) return;
9423
+ selectedIdRef.current = id;
9284
9424
  setSelectedId(id);
9285
9425
  if (options?.report !== false) report(sectionEl);
9286
9426
  },
@@ -9301,9 +9441,11 @@ function AiSectionOverlay({
9301
9441
  return sectionEl != null;
9302
9442
  },
9303
9443
  clear: () => {
9444
+ selectedIdRef.current = null;
9304
9445
  setSelectedId(null);
9305
9446
  report(null);
9306
- }
9447
+ },
9448
+ getSelectedId: () => selectedIdRef.current
9307
9449
  };
9308
9450
  return () => {
9309
9451
  apiRef.current = null;
@@ -9312,6 +9454,7 @@ function AiSectionOverlay({
9312
9454
  (0, import_react8.useEffect)(() => {
9313
9455
  const onMessage = (e) => {
9314
9456
  if (e.data?.type === "ow:ai-select" && e.data.sectionId === null) {
9457
+ selectedIdRef.current = null;
9315
9458
  setSelectedId(null);
9316
9459
  return;
9317
9460
  }
@@ -9362,6 +9505,7 @@ function AiSectionOverlay({
9362
9505
  if (reviewIdRef.current) return;
9363
9506
  if (document.querySelector("[data-ohw-editing]")) return;
9364
9507
  if (selectedIdRef.current) {
9508
+ selectedIdRef.current = null;
9365
9509
  setSelectedId(null);
9366
9510
  report(null);
9367
9511
  }
@@ -9983,7 +10127,7 @@ function SectionTreeItem({
9983
10127
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
9984
10128
  "div",
9985
10129
  {
9986
- className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
10130
+ className: "-mr-px h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
9987
10131
  "aria-hidden": true
9988
10132
  }
9989
10133
  ),
@@ -10002,7 +10146,7 @@ function SectionTreeItem({
10002
10146
  className: cn(
10003
10147
  "flex h-9 min-w-0 flex-1 items-center gap-2 rounded-md border border-border bg-background p-3",
10004
10148
  interactive && "cursor-pointer hover:bg-muted/30",
10005
- interactive && selected && "border-primary"
10149
+ interactive && selected && "border-bridge-primary"
10006
10150
  ),
10007
10151
  children: [
10008
10152
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
@@ -10132,7 +10276,7 @@ function UrlOrPageInput({
10132
10276
  };
10133
10277
  const fieldClassName = cn(
10134
10278
  "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]",
10135
- urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
10279
+ 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"
10136
10280
  );
10137
10281
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
10138
10282
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
@@ -14335,7 +14479,7 @@ function DisplaySwitch({
14335
14479
  onClick: () => onChange(!checked),
14336
14480
  className: cn(
14337
14481
  "relative h-5 w-9 shrink-0 rounded-full transition-colors",
14338
- checked ? "bg-primary" : "bg-primary-50",
14482
+ checked ? "bg-bridge-primary" : "bg-primary-50",
14339
14483
  disabled ? "cursor-default opacity-50" : "cursor-pointer"
14340
14484
  ),
14341
14485
  children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
@@ -14343,7 +14487,7 @@ function DisplaySwitch({
14343
14487
  {
14344
14488
  className: cn(
14345
14489
  "absolute top-0.5 h-4 w-4 rounded-full bg-white transition-all",
14346
- checked ? "left-[1.125rem]" : "left-0.5"
14490
+ checked ? "left-4.5" : "left-0.5"
14347
14491
  )
14348
14492
  }
14349
14493
  )
@@ -15978,7 +16122,7 @@ var badgeVariants = cva(
15978
16122
  {
15979
16123
  variants: {
15980
16124
  variant: {
15981
- default: "border-transparent bg-primary text-primary-foreground",
16125
+ default: "border-transparent bg-bridge-primary text-primary-foreground",
15982
16126
  secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
15983
16127
  destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
15984
16128
  outline: "text-foreground"
@@ -16370,6 +16514,19 @@ function isMediaEditable(el) {
16370
16514
  const t = el.dataset.ohwEditable;
16371
16515
  return t === "image" || t === "bg-image" || t === "video";
16372
16516
  }
16517
+ var FULL_BLEED_MIN_COVERAGE = 0.98;
16518
+ function fullBleedSectionIdOf(media) {
16519
+ const section = media.closest("[data-ohw-section]");
16520
+ if (!section) return null;
16521
+ const s = section.getBoundingClientRect();
16522
+ if (s.width <= 0 || s.height <= 0) return null;
16523
+ const m = media.getBoundingClientRect();
16524
+ const overlapX = Math.min(m.right, s.right) - Math.max(m.left, s.left);
16525
+ const overlapY = Math.min(m.bottom, s.bottom) - Math.max(m.top, s.top);
16526
+ if (overlapX <= 0 || overlapY <= 0) return null;
16527
+ if (overlapX * overlapY / (s.width * s.height) < FULL_BLEED_MIN_COVERAGE) return null;
16528
+ return instanceIdOf(movableUnit(section)) || null;
16529
+ }
16373
16530
  function isIconMarkupValue(value) {
16374
16531
  return /^\s*<(svg|img)\b/i.test(value);
16375
16532
  }
@@ -17543,20 +17700,38 @@ function OhhwellsBridge() {
17543
17700
  const hoveredImageHasTextOverlapRef = (0, import_react17.useRef)(false);
17544
17701
  const dragOverElRef = (0, import_react17.useRef)(null);
17545
17702
  const [mediaHover, setMediaHover] = (0, import_react17.useState)(null);
17703
+ const [selectedAiSectionId, setSelectedAiSectionId] = (0, import_react17.useState)(null);
17704
+ const selectedAiSectionIdRef = (0, import_react17.useRef)(null);
17705
+ const handleAiSectionSelectionChange = (0, import_react17.useCallback)((id) => {
17706
+ selectedAiSectionIdRef.current = id;
17707
+ setSelectedAiSectionId(id);
17708
+ }, []);
17546
17709
  const [selectedMedia, setSelectedMedia] = (0, import_react17.useState)(null);
17547
17710
  const selectedMediaElRef = (0, import_react17.useRef)(null);
17711
+ const mediaKeyDropTokenRef = (0, import_react17.useRef)(0);
17548
17712
  const clearMediaSelection = (0, import_react17.useCallback)(() => {
17549
17713
  const prev = selectedMediaElRef.current;
17550
17714
  selectedMediaElRef.current = null;
17551
17715
  setSelectedMedia(null);
17552
17716
  const sectionEl = prev?.closest("[data-ohw-section]") ?? null;
17553
17717
  if (sectionEl) {
17554
- postToParentRef.current({
17555
- type: "ow:section-selected",
17556
- sectionId: sectionEl.dataset.ohwSection ?? null,
17557
- sectionLabel: sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? ""),
17558
- key: null
17559
- });
17718
+ const sectionInstanceId = instanceIdOf(movableUnit(sectionEl)) || null;
17719
+ if (!sectionInstanceId) return;
17720
+ const token = ++mediaKeyDropTokenRef.current;
17721
+ const onQueueDrained = (e) => {
17722
+ if (e.source !== window || e.data?.type !== "ow:media-key-drop" || e.data.token !== token) return;
17723
+ window.removeEventListener("message", onQueueDrained);
17724
+ if (aiSectionApiRef.current?.getSelectedId() !== sectionInstanceId) return;
17725
+ if (selectedMediaElRef.current) return;
17726
+ postToParentRef.current({
17727
+ type: "ow:section-selected",
17728
+ sectionId: sectionEl.dataset.ohwSection ?? null,
17729
+ sectionLabel: sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? ""),
17730
+ key: null
17731
+ });
17732
+ };
17733
+ window.addEventListener("message", onQueueDrained);
17734
+ window.postMessage({ type: "ow:media-key-drop", token }, "*");
17560
17735
  }
17561
17736
  }, []);
17562
17737
  const clearMediaSelectionRef = (0, import_react17.useRef)(clearMediaSelection);
@@ -19448,7 +19623,9 @@ function OhhwellsBridge() {
19448
19623
  }, [isEditMode]);
19449
19624
  (0, import_react17.useEffect)(() => {
19450
19625
  if (isEditMode || fetchState !== "done") return;
19626
+ console.log("env", process.env.NEXT_PUBLIC_FLOWOPS_API_URL);
19451
19627
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
19628
+ console.log({ apiUrl, subdomain });
19452
19629
  bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
19453
19630
  }, [isEditMode, fetchState, subdomain]);
19454
19631
  (0, import_react17.useEffect)(() => {
@@ -19996,6 +20173,23 @@ function OhhwellsBridge() {
19996
20173
  if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
19997
20174
  clearMediaSelectionRef.current();
19998
20175
  }
20176
+ if (selectedMediaElRef.current && target.closest("[data-ohw-media-overlay]") && !findClosestButtonLike(target)) {
20177
+ const hit = findImageAtPoint(e.clientX, e.clientY, false);
20178
+ if (hit && hit !== selectedMediaElRef.current) {
20179
+ e.preventDefault();
20180
+ e.stopPropagation();
20181
+ const fullBleedSectionId = fullBleedSectionIdOf(hit);
20182
+ if (fullBleedSectionId && fullBleedSectionId !== selectedAiSectionIdRef.current) {
20183
+ clearMediaSelectionRef.current();
20184
+ deselectRef.current();
20185
+ deactivateRef.current();
20186
+ aiSectionApiRef.current?.selectFromElement(hit);
20187
+ return;
20188
+ }
20189
+ selectMediaElementRef.current(hit);
20190
+ return;
20191
+ }
20192
+ }
19999
20193
  if (isInsideFloatingPanel(target)) return;
20000
20194
  if (target.closest("[data-ohw-form-toolbar]")) return;
20001
20195
  if (target.closest(
@@ -20177,6 +20371,14 @@ function OhhwellsBridge() {
20177
20371
  if (isMediaEditable(editable) && !buttonOnMedia) {
20178
20372
  e.preventDefault();
20179
20373
  e.stopPropagation();
20374
+ const fullBleedSectionId = fullBleedSectionIdOf(editable);
20375
+ if (fullBleedSectionId && fullBleedSectionId !== selectedAiSectionIdRef.current) {
20376
+ clearMediaSelectionRef.current();
20377
+ deselectRef.current();
20378
+ deactivateRef.current();
20379
+ aiSectionApiRef.current?.selectFromElement(editable);
20380
+ return;
20381
+ }
20180
20382
  if (selectedMediaElRef.current === editable) {
20181
20383
  postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
20182
20384
  } else {
@@ -20631,6 +20833,7 @@ function OhhwellsBridge() {
20631
20833
  elementType: imgEl.dataset.ohwEditable ?? "image",
20632
20834
  hasTextOverlap,
20633
20835
  isDragOver,
20836
+ fullBleedSectionId: fullBleedSectionIdOf(imgEl),
20634
20837
  ...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
20635
20838
  });
20636
20839
  const track = imgEl.closest("[data-ohw-hover-pause]");
@@ -20803,7 +21006,13 @@ function OhhwellsBridge() {
20803
21006
  setHoveredItemRect(null);
20804
21007
  }
20805
21008
  };
21009
+ const syncSelectedMediaPointerRelease = (released) => {
21010
+ setSelectedMedia(
21011
+ (prev) => prev && prev.hasTextOverlap !== released ? { ...prev, hasTextOverlap: released } : prev
21012
+ );
21013
+ };
20806
21014
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
21015
+ syncSelectedMediaPointerRelease(true);
20807
21016
  if (linkPopoverOpenRef.current) {
20808
21017
  if (hoveredImageRef.current) {
20809
21018
  hoveredImageRef.current = null;
@@ -20998,6 +21207,7 @@ function OhhwellsBridge() {
20998
21207
  return;
20999
21208
  }
21000
21209
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
21210
+ syncSelectedMediaPointerRelease(false);
21001
21211
  if (imgEl !== hoveredImageRef.current || hoveredImageHasTextOverlapRef.current) {
21002
21212
  hoveredImageRef.current = imgEl;
21003
21213
  showImageHover(imgEl, isDragOver);
@@ -21798,10 +22008,26 @@ function OhhwellsBridge() {
21798
22008
  const handleGetBrand = (e) => {
21799
22009
  if (e.data?.type !== "ow:get-brand") return;
21800
22010
  const template = deriveTemplateBrand();
21801
- const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
22011
+ const fallback = template ?? (() => {
22012
+ const fonts = deriveTemplateFonts();
22013
+ return fonts ? { palette: AI_DEFAULT_BRAND.palette, fonts } : null;
22014
+ })();
22015
+ const value = brandKitRef.current || (fallback ? JSON.stringify(fallback) : "");
21802
22016
  postToParentRef.current({ type: "ow:brand-value", value });
21803
22017
  };
21804
22018
  window.addEventListener("message", handleGetBrand);
22019
+ const handleGetTemplateFonts = (e) => {
22020
+ if (e.data?.type !== "ow:get-template-fonts") return;
22021
+ const fonts = deriveTemplateFonts();
22022
+ postToParentRef.current({ type: "ow:template-fonts-value", value: fonts ? JSON.stringify(fonts) : "" });
22023
+ };
22024
+ window.addEventListener("message", handleGetTemplateFonts);
22025
+ const handleGetTemplateBrand = (e) => {
22026
+ if (e.data?.type !== "ow:get-template-brand") return;
22027
+ const brand = deriveTemplateBrand();
22028
+ postToParentRef.current({ type: "ow:template-brand-value", value: brand ? JSON.stringify(brand) : "" });
22029
+ };
22030
+ window.addEventListener("message", handleGetTemplateBrand);
21805
22031
  const handleMoveSection = (e) => {
21806
22032
  if (e.data?.type !== "ow:move-section") return;
21807
22033
  const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
@@ -22455,7 +22681,11 @@ function OhhwellsBridge() {
22455
22681
  if (!key) return;
22456
22682
  const r2 = getVisibleRect(container);
22457
22683
  setCarouselHover(
22458
- (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 } }
22684
+ (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 : {
22685
+ key,
22686
+ rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
22687
+ fullBleedSectionId: fullBleedSectionIdOf(container)
22688
+ }
22459
22689
  );
22460
22690
  };
22461
22691
  const applyToolbarPos = (rect) => {
@@ -22704,6 +22934,8 @@ function OhhwellsBridge() {
22704
22934
  window.removeEventListener("message", handleAiSetBrand);
22705
22935
  window.removeEventListener("message", handleAiSetStyles);
22706
22936
  window.removeEventListener("message", handleGetBrand);
22937
+ window.removeEventListener("message", handleGetTemplateFonts);
22938
+ window.removeEventListener("message", handleGetTemplateBrand);
22707
22939
  window.removeEventListener("message", handleMoveSection);
22708
22940
  window.removeEventListener("message", handlePanelDragging);
22709
22941
  window.removeEventListener("message", handleDeleteSection);
@@ -22915,7 +23147,7 @@ function OhhwellsBridge() {
22915
23147
  postToParent2({
22916
23148
  type: "ow:ready",
22917
23149
  version: "1",
22918
- bridgeVersion: "0.1.114",
23150
+ bridgeVersion: "0.1.116",
22919
23151
  path: pathname,
22920
23152
  nodes: collectEditableNodes(editContentRef.current),
22921
23153
  sections
@@ -23382,7 +23614,14 @@ function OhhwellsBridge() {
23382
23614
  bridgeRoot ? (0, import_react_dom5.createPortal)(
23383
23615
  /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
23384
23616
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
23385
- isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
23617
+ isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
23618
+ AiSectionOverlay,
23619
+ {
23620
+ postToParent: postToParent2,
23621
+ apiRef: aiSectionApiRef,
23622
+ onSelectionChange: handleAiSectionSelectionChange
23623
+ }
23624
+ ),
23386
23625
  isSectionDragging && sectionDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
23387
23626
  "div",
23388
23627
  {
@@ -23415,6 +23654,7 @@ function OhhwellsBridge() {
23415
23654
  {
23416
23655
  hover: mediaHover,
23417
23656
  isUploading: false,
23657
+ cueOnly: !mediaHover.isDragOver && !!mediaHover.fullBleedSectionId && mediaHover.fullBleedSectionId !== selectedAiSectionId,
23418
23658
  onReplace: handleMediaReplace,
23419
23659
  onSelect: handleMediaSelect,
23420
23660
  onVideoSettingsChange: handleVideoSettingsChange
@@ -23432,7 +23672,14 @@ function OhhwellsBridge() {
23432
23672
  onVideoSettingsChange: handleVideoSettingsChange
23433
23673
  }
23434
23674
  ),
23435
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
23675
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
23676
+ CarouselOverlay,
23677
+ {
23678
+ hover: carouselHover,
23679
+ onEdit: handleEditCarousel,
23680
+ cueOnly: !!carouselHover.fullBleedSectionId && carouselHover.fullBleedSectionId !== selectedAiSectionId
23681
+ }
23682
+ ),
23436
23683
  siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
23437
23684
  siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
23438
23685
  isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
@@ -23531,7 +23778,7 @@ function OhhwellsBridge() {
23531
23778
  "span",
23532
23779
  {
23533
23780
  "data-ohw-form-count": "",
23534
- 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",
23781
+ 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",
23535
23782
  children: formPickCount
23536
23783
  }
23537
23784
  )
@@ -23769,11 +24016,11 @@ function OhhwellsBridge() {
23769
24016
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
23770
24017
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
23771
24018
  children: [
23772
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
24019
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } }),
23773
24020
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
23774
24021
  Badge,
23775
24022
  {
23776
- 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",
24023
+ 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",
23777
24024
  onClick: () => {
23778
24025
  window.parent.postMessage(
23779
24026
  {
@@ -23787,7 +24034,7 @@ function OhhwellsBridge() {
23787
24034
  children: "Add Section"
23788
24035
  }
23789
24036
  ),
23790
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
24037
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } })
23791
24038
  ]
23792
24039
  }
23793
24040
  ),