@ohhwells/bridge 0.1.114 → 0.1.116

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
@@ -459,6 +521,20 @@ var BG_VALUES = {
459
521
  accent: "var(--ohw-brand-primary, var(--color-primary, #0078E5))",
460
522
  "accent-soft": "color-mix(in srgb, var(--ohw-brand-primary, var(--color-primary, #0078E5)) 12%, var(--ohw-brand-light, var(--color-light, #FFFFFF)))"
461
523
  };
524
+ var NAVBAR_COLOR_TOKENS = ["dark", "primary", "accent", "light"];
525
+ function navbarColorVar(token) {
526
+ const fallback = {
527
+ dark: "#0C0A09",
528
+ primary: "#0078E5",
529
+ accent: "#0078E5",
530
+ light: "#FFFFFF"
531
+ };
532
+ return `var(--ohw-brand-${token}, var(--color-${token}, ${fallback[token]}))`;
533
+ }
534
+ function resolveNavbarValue(value) {
535
+ if (value === void 0) return void 0;
536
+ return NAVBAR_COLOR_TOKENS.includes(value) ? navbarColorVar(value) : value;
537
+ }
462
538
  var HEADLINE_SIZES = { md: 24, lg: 32, xl: 40, display: 56 };
463
539
  function styleSheetCss() {
464
540
  const rules = [];
@@ -628,8 +704,18 @@ function applyStylesToDom(store) {
628
704
  for (const [sectionId, override] of Object.entries(store.sections)) {
629
705
  const escaped = CSS.escape(sectionId);
630
706
  const byInstance = document.querySelectorAll(`[data-ohw-instance="${escaped}"]`);
631
- const sections = byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`);
707
+ const sections = Array.from(
708
+ byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`)
709
+ );
710
+ const isNavbar = sectionId === "navbar";
711
+ if (isNavbar) {
712
+ const drawer = document.querySelector("[data-ohw-nav-drawer]");
713
+ if (drawer && !sections.includes(drawer)) sections.push(drawer);
714
+ const header = document.querySelector("[data-ohw-nav-root]");
715
+ if (header && !sections.includes(header)) sections.push(header);
716
+ }
632
717
  for (const marker of Array.from(sections)) {
718
+ const isDrawerMarker = isNavbar && marker.hasAttribute("data-ohw-nav-drawer");
633
719
  const section = marker.querySelector(":scope > [data-ai-section]") ?? marker;
634
720
  for (const [prop, attr] of Object.entries(SECTION_ATTRS)) {
635
721
  const value = override[prop];
@@ -637,19 +723,23 @@ function applyStylesToDom(store) {
637
723
  if (prop === "sectionBackground" && override.sectionBackgroundColor !== void 0) continue;
638
724
  section.setAttribute(attr, String(value).replace(":", "-"));
639
725
  }
640
- if (override.sectionBackgroundColor !== void 0) {
726
+ const bgOverride = isDrawerMarker ? override.navbarMobileBackground : override.sectionBackgroundColor;
727
+ const textOverride = isDrawerMarker ? override.navbarMobileTextColor : override.textColor;
728
+ const bgValue = isNavbar ? resolveNavbarValue(bgOverride) : bgOverride;
729
+ const textValue = isNavbar ? resolveNavbarValue(textOverride) : textOverride;
730
+ if (bgValue !== void 0) {
641
731
  saveInline(section, "background");
642
- section.style.setProperty("background", override.sectionBackgroundColor, "important");
732
+ section.style.setProperty("background", bgValue, "important");
643
733
  section.setAttribute("data-ohw-style-bgcolor", "");
644
734
  }
645
- if (override.textColor !== void 0 || override.fontFamily !== void 0) {
735
+ if (textValue !== void 0 || override.fontFamily !== void 0) {
646
736
  const textEls = marker.querySelectorAll(
647
737
  '[data-ohw-editable="text"], [data-ohw-editable="plain"], [data-ohw-field-label]'
648
738
  );
649
739
  for (const el of Array.from(textEls)) {
650
- if (override.textColor !== void 0) {
740
+ if (textValue !== void 0) {
651
741
  saveInline(el, "color");
652
- el.style.setProperty("color", override.textColor, "important");
742
+ el.style.setProperty("color", textValue, "important");
653
743
  el.setAttribute(NODE_WROTE_ATTR, "");
654
744
  }
655
745
  if (override.fontFamily !== void 0) {
@@ -2695,14 +2785,52 @@ function readRootVar(name) {
2695
2785
  if (typeof document === "undefined") return "";
2696
2786
  return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
2697
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
+ }
2698
2826
  function deriveBrandOverride() {
2699
2827
  const dark = readRootVar("--ohw-brand-dark");
2700
2828
  const primary = readRootVar("--ohw-brand-primary");
2701
2829
  const light = readRootVar("--ohw-brand-light");
2702
2830
  if (!dark || !primary || !light) return null;
2703
2831
  const accent = readRootVar("--ohw-brand-accent");
2704
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
2705
- const body = readRootVar("--font-body");
2832
+ const heading = readFontVar("--font-heading") || readFontVar("--font-display");
2833
+ const body = readFontVar("--font-body");
2706
2834
  return {
2707
2835
  palette: { dark, primary, accent: accent || dark, light },
2708
2836
  fonts: {
@@ -2711,22 +2839,55 @@ function deriveBrandOverride() {
2711
2839
  }
2712
2840
  };
2713
2841
  }
2714
- function deriveTemplateBrand() {
2842
+ function deriveTemplateBrandLive() {
2715
2843
  const primary = readRootVar("--brand-primary") || readRootVar("--color-primary");
2716
2844
  const dark = readRootVar("--brand-text") || readRootVar("--color-dark");
2717
2845
  const light = readRootVar("--brand-background") || readRootVar("--color-light");
2718
2846
  if (!dark || !primary || !light) return null;
2719
2847
  const accent = readRootVar("--brand-accent") || readRootVar("--color-accent");
2720
- const heading = readRootVar("--brand-font-heading") || readRootVar("--font-heading") || readRootVar("--font-display");
2721
- 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");
2722
2850
  return {
2723
- 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
+ },
2724
2857
  fonts: {
2725
2858
  heading: heading || AI_DEFAULT_BRAND.fonts.heading,
2726
2859
  body: body || AI_DEFAULT_BRAND.fonts.body
2727
2860
  }
2728
2861
  };
2729
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
+ }
2730
2891
  function deriveTemplateButtonStyle() {
2731
2892
  if (typeof document === "undefined") return null;
2732
2893
  const candidates = Array.from(
@@ -7224,12 +7385,12 @@ var cva = (base, config) => (props) => {
7224
7385
  var import_radix_ui2 = require("radix-ui");
7225
7386
  var import_jsx_runtime5 = require("react/jsx-runtime");
7226
7387
  var toggleVariants = cva(
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",
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",
7228
7389
  {
7229
7390
  variants: {
7230
7391
  variant: {
7231
7392
  default: "bg-transparent border-0",
7232
- 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"
7233
7394
  },
7234
7395
  size: {
7235
7396
  default: "px-2 py-1",
@@ -7322,10 +7483,10 @@ var DragHandle = React4.forwardRef(
7322
7483
  type,
7323
7484
  "data-slot": "drag-handle",
7324
7485
  className: cn(
7325
- "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",
7326
7487
  "bg-white border border-transparent text-stone-500 shadow-md cursor-grab",
7327
7488
  "enabled:hover:border enabled:hover:border-stone-200 enabled:hover:text-stone-950",
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",
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",
7329
7490
  "disabled:cursor-not-allowed disabled:opacity-40 disabled:text-stone-950 disabled:pointer-events-none",
7330
7491
  className
7331
7492
  ),
@@ -7347,7 +7508,7 @@ var CustomToolbar = React5.forwardRef(({ className, onMouseDown, ...props }, ref
7347
7508
  "data-ohw-toolbar": "",
7348
7509
  className: cn(
7349
7510
  // Figma: bg background, radius 8, gap-1, p-0.5, shadow-md — no border
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",
7511
+ "inline-flex h-8 items-center gap-1 rounded-(--radius,0.5rem) bg-background p-0.5 font-sans whitespace-nowrap shadow-md",
7351
7512
  className
7352
7513
  ),
7353
7514
  onMouseDown: (e) => {
@@ -7376,7 +7537,7 @@ var CustomToolbarButton = React5.forwardRef(
7376
7537
  type,
7377
7538
  className: cn(
7378
7539
  "inline-flex size-7 shrink-0 items-center justify-center rounded-[calc(var(--radius,0.5rem)-2px)] text-foreground transition-colors",
7379
- 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",
7380
7541
  className
7381
7542
  ),
7382
7543
  ...props
@@ -8640,13 +8801,13 @@ function FormFieldToolbar({
8640
8801
  ]
8641
8802
  }
8642
8803
  ) }),
8643
- /* @__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) => {
8644
8805
  const Icon = TYPE_ICONS[entry.type];
8645
8806
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
8646
8807
  DropdownMenuItem,
8647
8808
  {
8648
8809
  onSelect: () => onTypeChange(entry.type),
8649
- 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" : ""),
8650
8811
  children: [
8651
8812
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
8652
8813
  entry.label
@@ -8663,7 +8824,7 @@ function FormFieldToolbar({
8663
8824
  type: "button",
8664
8825
  "aria-pressed": required,
8665
8826
  onClick: onRequiredToggle,
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"),
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"),
8667
8828
  "data-ohw-field-required-toggle": "",
8668
8829
  children: [
8669
8830
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Asterisk, { size: 14, strokeWidth: 2, "aria-hidden": true }),
@@ -8683,7 +8844,7 @@ function FormFieldToolbar({
8683
8844
  children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.MoreHorizontal, { size: 15, "aria-hidden": true })
8684
8845
  }
8685
8846
  ) }),
8686
- /* @__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: [
8687
8848
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuItem, { onSelect: onDuplicate, className: "rounded-md py-2 text-[13px]", children: [
8688
8849
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Copy, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
8689
8850
  "Duplicate"
@@ -8711,7 +8872,7 @@ function FieldTypePicker({ onPick }) {
8711
8872
  {
8712
8873
  type: "button",
8713
8874
  onClick: () => onPick(entry.type),
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",
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",
8715
8876
  children: [
8716
8877
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 26, strokeWidth: 1.5, "aria-hidden": true }),
8717
8878
  entry.label
@@ -8737,7 +8898,7 @@ var buttonVariants = cva(
8737
8898
  {
8738
8899
  variants: {
8739
8900
  variant: {
8740
- default: "bg-primary text-primary-foreground hover:opacity-90",
8901
+ default: "bg-bridge-primary text-primary-foreground hover:opacity-90",
8741
8902
  outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
8742
8903
  ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
8743
8904
  },
@@ -8937,8 +9098,8 @@ function MediaOverlay({
8937
9098
  pointerEvents: hover.hasTextOverlap ? "none" : "auto",
8938
9099
  // Selected: a firm component ring with no wash, so the image reads as chosen rather
8939
9100
  // than hovered. Hover keeps the existing tinted preview.
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)"
9101
+ boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
9102
+ background: selected ? "transparent" : "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
8942
9103
  },
8943
9104
  onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
8944
9105
  children: [
@@ -9032,8 +9193,8 @@ function CarouselOverlay({
9032
9193
  height: rect.height,
9033
9194
  zIndex: 2147483646,
9034
9195
  pointerEvents: "auto",
9035
- boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
9036
- background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
9196
+ boxShadow: "inset 0 0 0 1.5px var(--color-bridge-primary)",
9197
+ background: "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
9037
9198
  },
9038
9199
  onClick: () => onEdit(hover.key),
9039
9200
  children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
@@ -9101,6 +9262,57 @@ function useLiveSectionRect(sectionId) {
9101
9262
  }, [sectionId]);
9102
9263
  return rect;
9103
9264
  }
9265
+ var NAV_TOGGLE_LABEL_RE = /^(toggle menu|open menu|close menu)$/i;
9266
+ function readNavToggleRect() {
9267
+ const el = Array.from(document.querySelectorAll("button[aria-label]")).find(
9268
+ (e) => NAV_TOGGLE_LABEL_RE.test(e.getAttribute("aria-label") ?? "")
9269
+ );
9270
+ if (!el) return null;
9271
+ const r2 = el.getBoundingClientRect();
9272
+ if (r2.width <= 0 || r2.height <= 0) return null;
9273
+ return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
9274
+ }
9275
+ function useLiveNavToggleHole(active) {
9276
+ const [rect, setRect] = (0, import_react8.useState)(null);
9277
+ (0, import_react8.useEffect)(() => {
9278
+ if (!active) {
9279
+ setRect(null);
9280
+ return;
9281
+ }
9282
+ const update = () => {
9283
+ const next = readNavToggleRect();
9284
+ setRect(
9285
+ (prev) => prev && next && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
9286
+ );
9287
+ };
9288
+ update();
9289
+ const opts = { capture: true, passive: true };
9290
+ window.addEventListener("scroll", update, opts);
9291
+ window.addEventListener("resize", update);
9292
+ const interval = setInterval(update, 500);
9293
+ return () => {
9294
+ window.removeEventListener("scroll", update, opts);
9295
+ window.removeEventListener("resize", update);
9296
+ clearInterval(interval);
9297
+ };
9298
+ }, [active]);
9299
+ return rect;
9300
+ }
9301
+ function subtractRect(outer, hole) {
9302
+ if (!hole) return [outer];
9303
+ const l = Math.max(outer.left, hole.left);
9304
+ const t = Math.max(outer.top, hole.top);
9305
+ const r2 = Math.min(outer.left + outer.width, hole.left + hole.width);
9306
+ const b = Math.min(outer.top + outer.height, hole.top + hole.height);
9307
+ if (l >= r2 || t >= b) return [outer];
9308
+ const rects = [];
9309
+ if (t > outer.top) rects.push({ left: outer.left, top: outer.top, width: outer.width, height: t - outer.top });
9310
+ const midHeight = b - t;
9311
+ if (l > outer.left) rects.push({ left: outer.left, top: t, width: l - outer.left, height: midHeight });
9312
+ if (r2 < outer.left + outer.width) rects.push({ left: r2, top: t, width: outer.left + outer.width - r2, height: midHeight });
9313
+ if (b < outer.top + outer.height) rects.push({ left: outer.left, top: b, width: outer.width, height: outer.top + outer.height - b });
9314
+ return rects;
9315
+ }
9104
9316
  function computeSectionBoundaryFlags(instanceId) {
9105
9317
  const topLevel = topLevelSections();
9106
9318
  const index = topLevel.findIndex((el) => instanceIdOf(el) === instanceId);
@@ -9316,6 +9528,7 @@ function AiSectionOverlay({
9316
9528
  const activeSelectionId = reviewId ? null : selectedId;
9317
9529
  const selectionRect = useLiveSectionRect(activeSelectionId);
9318
9530
  const reviewRect = useLiveSectionRect(reviewId);
9531
+ const navToggleHole = useLiveNavToggleHole(Boolean(reviewId));
9319
9532
  const hoverRect = useLiveSectionRect(reviewId || hoveredId === selectedId ? null : hoveredId);
9320
9533
  const showSelectionBorder = Boolean(selectionRect) && !navDropdownForceOpen;
9321
9534
  (0, import_react8.useEffect)(() => {
@@ -9375,48 +9588,65 @@ function AiSectionOverlay({
9375
9588
  }
9376
9589
  }
9377
9590
  ),
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"
9591
+ reviewRect && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
9592
+ subtractRect(reviewRect, navToggleHole).map((r2, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
9593
+ "div",
9594
+ {
9595
+ "data-ohw-ai-review": "",
9596
+ "aria-hidden": true,
9597
+ style: {
9598
+ position: "fixed",
9599
+ top: r2.top,
9600
+ left: r2.left,
9601
+ width: r2.width,
9602
+ height: r2.height,
9603
+ background: "rgba(8, 133, 254, 0.04)",
9604
+ pointerEvents: "auto",
9605
+ cursor: "default",
9606
+ zIndex: 2147483200
9607
+ },
9608
+ onClick: (e) => e.stopPropagation()
9398
9609
  },
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
- ]
9610
+ i
9611
+ )),
9612
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
9613
+ "div",
9614
+ {
9615
+ "aria-hidden": true,
9616
+ style: {
9617
+ position: "fixed",
9618
+ top: reviewRect.top,
9619
+ left: reviewRect.left,
9620
+ width: reviewRect.width,
9621
+ height: reviewRect.height,
9622
+ border: `2px solid ${PRIMARY2}`,
9623
+ borderRadius: edgeAwareRadius(reviewRect),
9624
+ pointerEvents: "none",
9625
+ zIndex: 2147483200
9416
9626
  }
9417
- )
9418
- }
9419
- )
9627
+ }
9628
+ ),
9629
+ !reviewButtonsHidden && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
9630
+ "div",
9631
+ {
9632
+ style: {
9633
+ position: "fixed",
9634
+ top: reviewRect.top + 12,
9635
+ left: reviewRect.left,
9636
+ width: reviewRect.width,
9637
+ display: "flex",
9638
+ gap: 8,
9639
+ justifyContent: "flex-end",
9640
+ paddingRight: 12,
9641
+ zIndex: 2147483201
9642
+ },
9643
+ children: [
9644
+ /* @__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 }) }),
9645
+ /* @__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 }) })
9646
+ ]
9647
+ }
9648
+ )
9649
+ ] })
9420
9650
  ] });
9421
9651
  }
9422
9652
 
@@ -9886,7 +10116,7 @@ function SectionTreeItem({
9886
10116
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
9887
10117
  "div",
9888
10118
  {
9889
- className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
10119
+ className: "-mr-px h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
9890
10120
  "aria-hidden": true
9891
10121
  }
9892
10122
  ),
@@ -9905,7 +10135,7 @@ function SectionTreeItem({
9905
10135
  className: cn(
9906
10136
  "flex h-9 min-w-0 flex-1 items-center gap-2 rounded-md border border-border bg-background p-3",
9907
10137
  interactive && "cursor-pointer hover:bg-muted/30",
9908
- interactive && selected && "border-primary"
10138
+ interactive && selected && "border-bridge-primary"
9909
10139
  ),
9910
10140
  children: [
9911
10141
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
@@ -10035,7 +10265,7 @@ function UrlOrPageInput({
10035
10265
  };
10036
10266
  const fieldClassName = cn(
10037
10267
  "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]",
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"
10268
+ 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"
10039
10269
  );
10040
10270
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
10041
10271
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
@@ -11079,6 +11309,15 @@ function getNavbarDesktopContainer() {
11079
11309
  function getNavbarDrawerContainer() {
11080
11310
  return document.querySelector("[data-ohw-nav-drawer]");
11081
11311
  }
11312
+ function isNavDrawerOpen() {
11313
+ return document.querySelector('[data-ohw-nav-drawer][data-ohw-section="navbar"]') !== null;
11314
+ }
11315
+ function isPointOutsideOpenDrawer(clientX, clientY) {
11316
+ const drawer = document.querySelector('[data-ohw-nav-drawer][data-ohw-section="navbar"]');
11317
+ if (!drawer) return false;
11318
+ const r2 = drawer.getBoundingClientRect();
11319
+ return clientX < r2.left || clientX > r2.right || clientY < r2.top || clientY > r2.bottom;
11320
+ }
11082
11321
  function isNavbarListContainerVisible(el) {
11083
11322
  if (el.hasAttribute("hidden")) return false;
11084
11323
  if (el.closest("[hidden]")) return false;
@@ -14229,7 +14468,7 @@ function DisplaySwitch({
14229
14468
  onClick: () => onChange(!checked),
14230
14469
  className: cn(
14231
14470
  "relative h-5 w-9 shrink-0 rounded-full transition-colors",
14232
- checked ? "bg-primary" : "bg-primary-50",
14471
+ checked ? "bg-bridge-primary" : "bg-primary-50",
14233
14472
  disabled ? "cursor-default opacity-50" : "cursor-pointer"
14234
14473
  ),
14235
14474
  children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
@@ -14237,7 +14476,7 @@ function DisplaySwitch({
14237
14476
  {
14238
14477
  className: cn(
14239
14478
  "absolute top-0.5 h-4 w-4 rounded-full bg-white transition-all",
14240
- checked ? "left-[1.125rem]" : "left-0.5"
14479
+ checked ? "left-4.5" : "left-0.5"
14241
14480
  )
14242
14481
  }
14243
14482
  )
@@ -15872,7 +16111,7 @@ var badgeVariants = cva(
15872
16111
  {
15873
16112
  variants: {
15874
16113
  variant: {
15875
- default: "border-transparent bg-primary text-primary-foreground",
16114
+ default: "border-transparent bg-bridge-primary text-primary-foreground",
15876
16115
  secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
15877
16116
  destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
15878
16117
  outline: "text-foreground"
@@ -17805,6 +18044,7 @@ function OhhwellsBridge() {
17805
18044
  const aiSectionsRef = (0, import_react17.useRef)("");
17806
18045
  const brandKitRef = (0, import_react17.useRef)("");
17807
18046
  const stylesRef = (0, import_react17.useRef)("");
18047
+ const appliedDrawerRef = (0, import_react17.useRef)(null);
17808
18048
  const pendingDeleteUndoRef = (0, import_react17.useRef)(null);
17809
18049
  const [sitePages, setSitePages] = (0, import_react17.useState)([]);
17810
18050
  const [sectionsByPath, setSectionsByPath] = (0, import_react17.useState)({});
@@ -19341,7 +19581,9 @@ function OhhwellsBridge() {
19341
19581
  }, [isEditMode]);
19342
19582
  (0, import_react17.useEffect)(() => {
19343
19583
  if (isEditMode || fetchState !== "done") return;
19584
+ console.log("env", process.env.NEXT_PUBLIC_FLOWOPS_API_URL);
19344
19585
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
19586
+ console.log({ apiUrl, subdomain });
19345
19587
  bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
19346
19588
  }, [isEditMode, fetchState, subdomain]);
19347
19589
  (0, import_react17.useEffect)(() => {
@@ -19470,6 +19712,17 @@ function OhhwellsBridge() {
19470
19712
  if (!isEditMode) return;
19471
19713
  initSectionInstancesFromContent(editContentRef.current, pathname);
19472
19714
  }, [pathname, isEditMode]);
19715
+ (0, import_react17.useEffect)(() => {
19716
+ if (!isEditMode) return;
19717
+ const observer = new MutationObserver(() => {
19718
+ const drawer = document.querySelector("[data-ohw-nav-drawer]");
19719
+ if (!drawer || drawer === appliedDrawerRef.current) return;
19720
+ appliedDrawerRef.current = drawer;
19721
+ applyStylesToDom(parseStyleStore(stylesRef.current));
19722
+ });
19723
+ observer.observe(document.body, { childList: true, subtree: true });
19724
+ return () => observer.disconnect();
19725
+ }, [isEditMode, pathname]);
19473
19726
  (0, import_react17.useEffect)(() => {
19474
19727
  const contentForNav = () => {
19475
19728
  if (isEditMode) return editContentRef.current;
@@ -20231,6 +20484,19 @@ function OhhwellsBridge() {
20231
20484
  const handleMouseOver = (e) => {
20232
20485
  if (document.documentElement.hasAttribute("data-ohw-section-picking")) return;
20233
20486
  const target = e.target;
20487
+ if (isNavDrawerOpen() && isPointOutsideOpenDrawer(e.clientX, e.clientY)) {
20488
+ document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
20489
+ hoveredItemElRef.current = null;
20490
+ setHoveredItemRect(null);
20491
+ hoveredNavContainerRef.current = null;
20492
+ setHoveredNavContainerRect(null);
20493
+ formHoverElRef.current = null;
20494
+ setFormHoverRect(null);
20495
+ siblingHintElRef.current = null;
20496
+ setSiblingHintRect(null);
20497
+ setSiblingHintRects([]);
20498
+ return;
20499
+ }
20234
20500
  if (linkPopoverOpenRef.current) {
20235
20501
  hoveredItemElRef.current = null;
20236
20502
  setHoveredItemRect(null);
@@ -21047,6 +21313,26 @@ function OhhwellsBridge() {
21047
21313
  const handleMouseMove = (e) => {
21048
21314
  const { clientX, clientY } = e;
21049
21315
  if (pointOwnedByFloatingPanel(clientX, clientY)) return;
21316
+ if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
21317
+ document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
21318
+ formHoverElRef.current = null;
21319
+ setFormHoverRect(null);
21320
+ hoveredItemElRef.current = null;
21321
+ setHoveredItemRect(null);
21322
+ hoveredNavContainerRef.current = null;
21323
+ setHoveredNavContainerRect(null);
21324
+ dismissImageHover();
21325
+ if (hoveredGapRef.current) {
21326
+ hoveredGapRef.current = null;
21327
+ setSectionGap(null);
21328
+ }
21329
+ if (activeStateElRef.current) {
21330
+ activeStateElRef.current.removeAttribute("data-ohw-state-hovered");
21331
+ activeStateElRef.current = null;
21332
+ setToggleState(null);
21333
+ }
21334
+ return;
21335
+ }
21050
21336
  if (isOverEditorChrome(clientX, clientY)) {
21051
21337
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
21052
21338
  formHoverElRef.current = null;
@@ -21068,6 +21354,7 @@ function OhhwellsBridge() {
21068
21354
  const { clientX, clientY } = e.data;
21069
21355
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
21070
21356
  if (pointOwnedByFloatingPanel(clientX, clientY)) return;
21357
+ if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
21071
21358
  if (probeSocialsRowAt(clientX, clientY)) return;
21072
21359
  probeSectionGapAt(clientX, clientY);
21073
21360
  probeImageAt(clientX, clientY);
@@ -21646,10 +21933,26 @@ function OhhwellsBridge() {
21646
21933
  const handleGetBrand = (e) => {
21647
21934
  if (e.data?.type !== "ow:get-brand") return;
21648
21935
  const template = deriveTemplateBrand();
21649
- const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
21936
+ const fallback = template ?? (() => {
21937
+ const fonts = deriveTemplateFonts();
21938
+ return fonts ? { palette: AI_DEFAULT_BRAND.palette, fonts } : null;
21939
+ })();
21940
+ const value = brandKitRef.current || (fallback ? JSON.stringify(fallback) : "");
21650
21941
  postToParentRef.current({ type: "ow:brand-value", value });
21651
21942
  };
21652
21943
  window.addEventListener("message", handleGetBrand);
21944
+ const handleGetTemplateFonts = (e) => {
21945
+ if (e.data?.type !== "ow:get-template-fonts") return;
21946
+ const fonts = deriveTemplateFonts();
21947
+ postToParentRef.current({ type: "ow:template-fonts-value", value: fonts ? JSON.stringify(fonts) : "" });
21948
+ };
21949
+ window.addEventListener("message", handleGetTemplateFonts);
21950
+ const handleGetTemplateBrand = (e) => {
21951
+ if (e.data?.type !== "ow:get-template-brand") return;
21952
+ const brand = deriveTemplateBrand();
21953
+ postToParentRef.current({ type: "ow:template-brand-value", value: brand ? JSON.stringify(brand) : "" });
21954
+ };
21955
+ window.addEventListener("message", handleGetTemplateBrand);
21653
21956
  const handleMoveSection = (e) => {
21654
21957
  if (e.data?.type !== "ow:move-section") return;
21655
21958
  const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
@@ -22552,6 +22855,8 @@ function OhhwellsBridge() {
22552
22855
  window.removeEventListener("message", handleAiSetBrand);
22553
22856
  window.removeEventListener("message", handleAiSetStyles);
22554
22857
  window.removeEventListener("message", handleGetBrand);
22858
+ window.removeEventListener("message", handleGetTemplateFonts);
22859
+ window.removeEventListener("message", handleGetTemplateBrand);
22555
22860
  window.removeEventListener("message", handleMoveSection);
22556
22861
  window.removeEventListener("message", handlePanelDragging);
22557
22862
  window.removeEventListener("message", handleDeleteSection);
@@ -22763,7 +23068,7 @@ function OhhwellsBridge() {
22763
23068
  postToParent2({
22764
23069
  type: "ow:ready",
22765
23070
  version: "1",
22766
- bridgeVersion: "0.1.113",
23071
+ bridgeVersion: "0.1.115",
22767
23072
  path: pathname,
22768
23073
  nodes: collectEditableNodes(editContentRef.current),
22769
23074
  sections
@@ -23379,7 +23684,7 @@ function OhhwellsBridge() {
23379
23684
  "span",
23380
23685
  {
23381
23686
  "data-ohw-form-count": "",
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",
23687
+ 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",
23383
23688
  children: formPickCount
23384
23689
  }
23385
23690
  )
@@ -23617,11 +23922,11 @@ function OhhwellsBridge() {
23617
23922
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
23618
23923
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
23619
23924
  children: [
23620
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
23925
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } }),
23621
23926
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
23622
23927
  Badge,
23623
23928
  {
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",
23929
+ 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",
23625
23930
  onClick: () => {
23626
23931
  window.parent.postMessage(
23627
23932
  {
@@ -23635,7 +23940,7 @@ function OhhwellsBridge() {
23635
23940
  children: "Add Section"
23636
23941
  }
23637
23942
  ),
23638
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
23943
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } })
23639
23944
  ]
23640
23945
  }
23641
23946
  ),