@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.js CHANGED
@@ -279,16 +279,17 @@ var LEGACY_BRAND_VAR_NAMES = [
279
279
  "text-muted",
280
280
  "surface",
281
281
  "border",
282
- "on-primary",
283
- "navbar-background"
282
+ "on-primary"
284
283
  ].map((role) => `--brand-${role}`);
285
284
  var FONT_VARS = {
286
285
  heading: ["--font-heading", "--font-display", "--brand-font-heading"],
287
286
  body: ["--font-body", "--brand-font-body"]
288
287
  };
289
288
  var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
290
- function brandColorVars(kit) {
291
- const { dark, primary, accent, light } = kit.palette;
289
+ var CUSTOM_FONT_STYLE_ID = "ohw-brand-custom-fonts";
290
+ var CUSTOM_FONT_FORMATS = /* @__PURE__ */ new Set(["woff2", "woff", "truetype", "opentype"]);
291
+ function brandColorVars(palette) {
292
+ const { dark, primary, accent, light } = palette;
292
293
  const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
293
294
  const surface = mix(light, 95, dark);
294
295
  const border = mix(light, 85, dark);
@@ -311,22 +312,42 @@ function brandColorVars(kit) {
311
312
  "--brand-border": border,
312
313
  // Buttons/bands painted in the primary colour assume it's dark/saturated enough to need
313
314
  // light text on top — the same assumption LOGO_IMAGE's light-on-dark navbar mark makes.
314
- "--brand-on-primary": light,
315
- "--brand-navbar-background": dark
315
+ "--brand-on-primary": light
316
316
  };
317
317
  }
318
+ function parseCustomFontWeight(raw) {
319
+ if (typeof raw !== "object" || raw === null) return null;
320
+ const w = raw;
321
+ if (typeof w.weight !== "number" || !Number.isFinite(w.weight)) return null;
322
+ if (typeof w.url !== "string" || !w.url) return null;
323
+ if (typeof w.format !== "string" || !CUSTOM_FONT_FORMATS.has(w.format)) return null;
324
+ const weightEnd = typeof w.weightEnd === "number" && Number.isFinite(w.weightEnd) && w.weightEnd > w.weight ? w.weightEnd : void 0;
325
+ return { weight: w.weight, ...weightEnd !== void 0 ? { weightEnd } : {}, url: w.url, format: w.format };
326
+ }
327
+ function parseCustomFont(raw) {
328
+ if (typeof raw !== "object" || raw === null) return null;
329
+ const f = raw;
330
+ if (typeof f.family !== "string" || !f.family) return null;
331
+ if (typeof f.label !== "string" || !f.label) return null;
332
+ if (!Array.isArray(f.weights)) return null;
333
+ const weights = f.weights.map(parseCustomFontWeight).filter((w) => w !== null);
334
+ if (weights.length === 0) return null;
335
+ return { family: f.family, label: f.label, weights };
336
+ }
318
337
  function parseBrandKit(raw) {
319
338
  if (!raw) return null;
320
339
  try {
321
340
  const parsed = JSON.parse(raw);
322
341
  const p = parsed?.palette;
323
342
  const f = parsed?.fonts;
324
- 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") {
325
- return null;
326
- }
343
+ 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;
344
+ const fonts = f && typeof f.heading === "string" && typeof f.body === "string" ? { heading: f.heading, body: f.body } : void 0;
345
+ const customFonts = Array.isArray(parsed?.customFonts) ? parsed.customFonts.map(parseCustomFont).filter((c) => c !== null) : void 0;
346
+ if (!palette && !fonts && !customFonts) return null;
327
347
  return {
328
- palette: { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light },
329
- fonts: { heading: f.heading, body: f.body }
348
+ ...palette ? { palette } : {},
349
+ ...fonts ? { fonts } : {},
350
+ ...customFonts ? { customFonts } : {}
330
351
  };
331
352
  } catch {
332
353
  return null;
@@ -336,11 +357,16 @@ function familyOf(stack) {
336
357
  const first = stack.split(",")[0]?.trim() ?? "";
337
358
  return first.replace(/^['"]|['"]$/g, "");
338
359
  }
360
+ function quoteFamily(family) {
361
+ return `'${family.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
362
+ }
363
+ var WEIGHT_SCALE = [100, 200, 300, 400, 500, 600, 700, 800, 900];
339
364
  function loadBrandFonts(families) {
340
365
  const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
341
366
  if (unique.length === 0) return;
342
- const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
343
- const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
367
+ const weights = WEIGHT_SCALE.join(";");
368
+ const spec = unique.map((f) => `family=${f.replace(/ /g, "+")}:wght@${weights}`).join("&");
369
+ const href = `https://fonts.googleapis.com/css2?${spec}&display=swap`;
344
370
  let link = document.getElementById(BRAND_FONT_LINK_ID);
345
371
  if (!link) {
346
372
  link = document.createElement("link");
@@ -350,18 +376,54 @@ function loadBrandFonts(families) {
350
376
  }
351
377
  if (link.href !== href) link.href = href;
352
378
  }
379
+ function escapeCssString(value) {
380
+ return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
381
+ }
382
+ function loadCustomFonts(fonts) {
383
+ const list = fonts ?? [];
384
+ let style = document.getElementById(CUSTOM_FONT_STYLE_ID);
385
+ if (list.length === 0) {
386
+ style?.remove();
387
+ return;
388
+ }
389
+ if (!style) {
390
+ style = document.createElement("style");
391
+ style.id = CUSTOM_FONT_STYLE_ID;
392
+ document.head.appendChild(style);
393
+ }
394
+ style.textContent = list.flatMap(
395
+ (font) => font.weights.map((w) => {
396
+ const weightDescriptor = w.weightEnd ? `${w.weight} ${w.weightEnd}` : `${w.weight}`;
397
+ return `@font-face { font-family: '${escapeCssString(font.family)}'; src: url('${escapeCssString(w.url)}') format('${w.format}'); font-weight: ${weightDescriptor}; font-display: swap; }`;
398
+ })
399
+ ).join("\n");
400
+ }
353
401
  function applyBrandToDom(kit) {
354
402
  const root = document.documentElement;
355
403
  if (!kit) {
356
404
  for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES]) root.style.removeProperty(name);
357
405
  for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
358
406
  document.getElementById(BRAND_FONT_LINK_ID)?.remove();
407
+ document.getElementById(CUSTOM_FONT_STYLE_ID)?.remove();
359
408
  return;
360
409
  }
361
- for (const [name, value] of Object.entries(brandColorVars(kit))) root.style.setProperty(name, value);
362
- for (const name of FONT_VARS.heading) root.style.setProperty(name, kit.fonts.heading);
363
- for (const name of FONT_VARS.body) root.style.setProperty(name, kit.fonts.body);
364
- loadBrandFonts([familyOf(kit.fonts.heading), familyOf(kit.fonts.body)]);
410
+ if (kit.palette) {
411
+ for (const [name, value] of Object.entries(brandColorVars(kit.palette))) root.style.setProperty(name, value);
412
+ }
413
+ if (kit.customFonts) {
414
+ loadCustomFonts(kit.customFonts);
415
+ }
416
+ if (kit.fonts) {
417
+ const heading = quoteFamily(kit.fonts.heading);
418
+ const body = quoteFamily(kit.fonts.body);
419
+ for (const name of FONT_VARS.heading) root.style.setProperty(name, heading);
420
+ for (const name of FONT_VARS.body) root.style.setProperty(name, body);
421
+ const customFamilies = new Set((kit.customFonts ?? []).map((f) => f.family));
422
+ const googleFamilies = [familyOf(kit.fonts.heading), familyOf(kit.fonts.body)].filter(
423
+ (f) => !customFamilies.has(f)
424
+ );
425
+ loadBrandFonts(googleFamilies);
426
+ }
365
427
  }
366
428
 
367
429
  // src/lib/section-styles.ts
@@ -386,6 +448,20 @@ var BG_VALUES = {
386
448
  accent: "var(--ohw-brand-primary, var(--color-primary, #0078E5))",
387
449
  "accent-soft": "color-mix(in srgb, var(--ohw-brand-primary, var(--color-primary, #0078E5)) 12%, var(--ohw-brand-light, var(--color-light, #FFFFFF)))"
388
450
  };
451
+ var NAVBAR_COLOR_TOKENS = ["dark", "primary", "accent", "light"];
452
+ function navbarColorVar(token) {
453
+ const fallback = {
454
+ dark: "#0C0A09",
455
+ primary: "#0078E5",
456
+ accent: "#0078E5",
457
+ light: "#FFFFFF"
458
+ };
459
+ return `var(--ohw-brand-${token}, var(--color-${token}, ${fallback[token]}))`;
460
+ }
461
+ function resolveNavbarValue(value) {
462
+ if (value === void 0) return void 0;
463
+ return NAVBAR_COLOR_TOKENS.includes(value) ? navbarColorVar(value) : value;
464
+ }
389
465
  var HEADLINE_SIZES = { md: 24, lg: 32, xl: 40, display: 56 };
390
466
  function styleSheetCss() {
391
467
  const rules = [];
@@ -555,8 +631,18 @@ function applyStylesToDom(store) {
555
631
  for (const [sectionId, override] of Object.entries(store.sections)) {
556
632
  const escaped = CSS.escape(sectionId);
557
633
  const byInstance = document.querySelectorAll(`[data-ohw-instance="${escaped}"]`);
558
- const sections = byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`);
634
+ const sections = Array.from(
635
+ byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`)
636
+ );
637
+ const isNavbar = sectionId === "navbar";
638
+ if (isNavbar) {
639
+ const drawer = document.querySelector("[data-ohw-nav-drawer]");
640
+ if (drawer && !sections.includes(drawer)) sections.push(drawer);
641
+ const header = document.querySelector("[data-ohw-nav-root]");
642
+ if (header && !sections.includes(header)) sections.push(header);
643
+ }
559
644
  for (const marker of Array.from(sections)) {
645
+ const isDrawerMarker = isNavbar && marker.hasAttribute("data-ohw-nav-drawer");
560
646
  const section = marker.querySelector(":scope > [data-ai-section]") ?? marker;
561
647
  for (const [prop, attr] of Object.entries(SECTION_ATTRS)) {
562
648
  const value = override[prop];
@@ -564,19 +650,23 @@ function applyStylesToDom(store) {
564
650
  if (prop === "sectionBackground" && override.sectionBackgroundColor !== void 0) continue;
565
651
  section.setAttribute(attr, String(value).replace(":", "-"));
566
652
  }
567
- if (override.sectionBackgroundColor !== void 0) {
653
+ const bgOverride = isDrawerMarker ? override.navbarMobileBackground : override.sectionBackgroundColor;
654
+ const textOverride = isDrawerMarker ? override.navbarMobileTextColor : override.textColor;
655
+ const bgValue = isNavbar ? resolveNavbarValue(bgOverride) : bgOverride;
656
+ const textValue = isNavbar ? resolveNavbarValue(textOverride) : textOverride;
657
+ if (bgValue !== void 0) {
568
658
  saveInline(section, "background");
569
- section.style.setProperty("background", override.sectionBackgroundColor, "important");
659
+ section.style.setProperty("background", bgValue, "important");
570
660
  section.setAttribute("data-ohw-style-bgcolor", "");
571
661
  }
572
- if (override.textColor !== void 0 || override.fontFamily !== void 0) {
662
+ if (textValue !== void 0 || override.fontFamily !== void 0) {
573
663
  const textEls = marker.querySelectorAll(
574
664
  '[data-ohw-editable="text"], [data-ohw-editable="plain"], [data-ohw-field-label]'
575
665
  );
576
666
  for (const el of Array.from(textEls)) {
577
- if (override.textColor !== void 0) {
667
+ if (textValue !== void 0) {
578
668
  saveInline(el, "color");
579
- el.style.setProperty("color", override.textColor, "important");
669
+ el.style.setProperty("color", textValue, "important");
580
670
  el.setAttribute(NODE_WROTE_ATTR, "");
581
671
  }
582
672
  if (override.fontFamily !== void 0) {
@@ -2622,14 +2712,52 @@ function readRootVar(name) {
2622
2712
  if (typeof document === "undefined") return "";
2623
2713
  return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
2624
2714
  }
2715
+ function normalizeColorToHex(value) {
2716
+ if (!value || typeof document === "undefined") return value;
2717
+ const canvas = document.createElement("canvas");
2718
+ canvas.width = 1;
2719
+ canvas.height = 1;
2720
+ const ctx = canvas.getContext("2d");
2721
+ if (!ctx) return value;
2722
+ ctx.fillStyle = value;
2723
+ ctx.fillRect(0, 0, 1, 1);
2724
+ const [r2, g, b] = ctx.getImageData(0, 0, 1, 1).data;
2725
+ const toHex = (n) => n.toString(16).padStart(2, "0");
2726
+ return `#${toHex(r2)}${toHex(g)}${toHex(b)}`;
2727
+ }
2728
+ var GENERIC_FONT_KEYWORDS = /* @__PURE__ */ new Set([
2729
+ "serif",
2730
+ "sans-serif",
2731
+ "monospace",
2732
+ "cursive",
2733
+ "fantasy",
2734
+ "system-ui",
2735
+ "ui-serif",
2736
+ "ui-sans-serif",
2737
+ "ui-monospace",
2738
+ "ui-rounded",
2739
+ "math",
2740
+ "emoji",
2741
+ "fangsong"
2742
+ ]);
2743
+ function primaryFontFamily(stack) {
2744
+ const first = stack.split(",").map((part) => part.trim().replace(/^["']|["']$/g, "")).find((part) => part && !GENERIC_FONT_KEYWORDS.has(part.toLowerCase()));
2745
+ return first ?? "";
2746
+ }
2747
+ function humanizeFontFamily(name) {
2748
+ 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());
2749
+ }
2750
+ function readFontVar(name) {
2751
+ return humanizeFontFamily(primaryFontFamily(readRootVar(name)));
2752
+ }
2625
2753
  function deriveBrandOverride() {
2626
2754
  const dark = readRootVar("--ohw-brand-dark");
2627
2755
  const primary = readRootVar("--ohw-brand-primary");
2628
2756
  const light = readRootVar("--ohw-brand-light");
2629
2757
  if (!dark || !primary || !light) return null;
2630
2758
  const accent = readRootVar("--ohw-brand-accent");
2631
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
2632
- const body = readRootVar("--font-body");
2759
+ const heading = readFontVar("--font-heading") || readFontVar("--font-display");
2760
+ const body = readFontVar("--font-body");
2633
2761
  return {
2634
2762
  palette: { dark, primary, accent: accent || dark, light },
2635
2763
  fonts: {
@@ -2638,22 +2766,55 @@ function deriveBrandOverride() {
2638
2766
  }
2639
2767
  };
2640
2768
  }
2641
- function deriveTemplateBrand() {
2769
+ function deriveTemplateBrandLive() {
2642
2770
  const primary = readRootVar("--brand-primary") || readRootVar("--color-primary");
2643
2771
  const dark = readRootVar("--brand-text") || readRootVar("--color-dark");
2644
2772
  const light = readRootVar("--brand-background") || readRootVar("--color-light");
2645
2773
  if (!dark || !primary || !light) return null;
2646
2774
  const accent = readRootVar("--brand-accent") || readRootVar("--color-accent");
2647
- const heading = readRootVar("--brand-font-heading") || readRootVar("--font-heading") || readRootVar("--font-display");
2648
- const body = readRootVar("--brand-font-body") || readRootVar("--font-body");
2775
+ const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
2776
+ const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
2649
2777
  return {
2650
- palette: { dark, primary, accent: accent || dark, light },
2778
+ palette: {
2779
+ dark: normalizeColorToHex(dark),
2780
+ primary: normalizeColorToHex(primary),
2781
+ accent: normalizeColorToHex(accent || dark),
2782
+ light: normalizeColorToHex(light)
2783
+ },
2651
2784
  fonts: {
2652
2785
  heading: heading || AI_DEFAULT_BRAND.fonts.heading,
2653
2786
  body: body || AI_DEFAULT_BRAND.fonts.body
2654
2787
  }
2655
2788
  };
2656
2789
  }
2790
+ function deriveTemplateFontsLive() {
2791
+ const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
2792
+ const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
2793
+ if (!heading && !body) return null;
2794
+ return {
2795
+ heading: heading || AI_DEFAULT_BRAND.fonts.heading,
2796
+ body: body || AI_DEFAULT_BRAND.fonts.body
2797
+ };
2798
+ }
2799
+ var OVERRIDE_VAR_NAMES = [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES, ...FONT_VARS.heading, ...FONT_VARS.body];
2800
+ function withOverrideStripped(read) {
2801
+ const root = document.documentElement;
2802
+ const restore = OVERRIDE_VAR_NAMES.map((name) => [name, root.style.getPropertyValue(name)]);
2803
+ for (const name of OVERRIDE_VAR_NAMES) root.style.removeProperty(name);
2804
+ try {
2805
+ return read();
2806
+ } finally {
2807
+ for (const [name, value] of restore) if (value) root.style.setProperty(name, value);
2808
+ }
2809
+ }
2810
+ var TEMPLATE_BRAND_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateBrandLive);
2811
+ var TEMPLATE_FONTS_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateFontsLive);
2812
+ function deriveTemplateBrand() {
2813
+ return TEMPLATE_BRAND_SNAPSHOT;
2814
+ }
2815
+ function deriveTemplateFonts() {
2816
+ return TEMPLATE_FONTS_SNAPSHOT;
2817
+ }
2657
2818
  function deriveTemplateButtonStyle() {
2658
2819
  if (typeof document === "undefined") return null;
2659
2820
  const candidates = Array.from(
@@ -7151,12 +7312,12 @@ var cva = (base, config) => (props) => {
7151
7312
  import { Toggle as TogglePrimitive } from "radix-ui";
7152
7313
  import { jsx as jsx5 } from "react/jsx-runtime";
7153
7314
  var toggleVariants = cva(
7154
- "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",
7315
+ "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",
7155
7316
  {
7156
7317
  variants: {
7157
7318
  variant: {
7158
7319
  default: "bg-transparent border-0",
7159
- outline: "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground"
7320
+ outline: "border border-input bg-transparent shadow-xs hover:bg-bridge-accent hover:text-accent-foreground"
7160
7321
  },
7161
7322
  size: {
7162
7323
  default: "px-2 py-1",
@@ -7249,10 +7410,10 @@ var DragHandle = React4.forwardRef(
7249
7410
  type,
7250
7411
  "data-slot": "drag-handle",
7251
7412
  className: cn(
7252
- "inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-[30px]",
7413
+ "inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-7.5",
7253
7414
  "bg-white border border-transparent text-stone-500 shadow-md cursor-grab",
7254
7415
  "enabled:hover:border enabled:hover:border-stone-200 enabled:hover:text-stone-950",
7255
- "enabled:active:border enabled:active:border-primary enabled:active:bg-primary-50 enabled:active:text-stone-950 enabled:active:shadow enabled:active:cursor-grabbing",
7416
+ "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",
7256
7417
  "disabled:cursor-not-allowed disabled:opacity-40 disabled:text-stone-950 disabled:pointer-events-none",
7257
7418
  className
7258
7419
  ),
@@ -7274,7 +7435,7 @@ var CustomToolbar = React5.forwardRef(({ className, onMouseDown, ...props }, ref
7274
7435
  "data-ohw-toolbar": "",
7275
7436
  className: cn(
7276
7437
  // Figma: bg background, radius 8, gap-1, p-0.5, shadow-md — no border
7277
- "inline-flex h-8 items-center gap-1 rounded-[var(--radius,0.5rem)] bg-background p-0.5 font-sans whitespace-nowrap shadow-md",
7438
+ "inline-flex h-8 items-center gap-1 rounded-(--radius,0.5rem) bg-background p-0.5 font-sans whitespace-nowrap shadow-md",
7278
7439
  className
7279
7440
  ),
7280
7441
  onMouseDown: (e) => {
@@ -7303,7 +7464,7 @@ var CustomToolbarButton = React5.forwardRef(
7303
7464
  type,
7304
7465
  className: cn(
7305
7466
  "inline-flex size-7 shrink-0 items-center justify-center rounded-[calc(var(--radius,0.5rem)-2px)] text-foreground transition-colors",
7306
- active ? "bg-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
7467
+ active ? "bg-bridge-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
7307
7468
  className
7308
7469
  ),
7309
7470
  ...props
@@ -8567,13 +8728,13 @@ function FormFieldToolbar({
8567
8728
  ]
8568
8729
  }
8569
8730
  ) }),
8570
- /* @__PURE__ */ jsx13(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-[190px] p-1", children: FIELD_TYPES.map((entry) => {
8731
+ /* @__PURE__ */ jsx13(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-47.5 p-1", children: FIELD_TYPES.map((entry) => {
8571
8732
  const Icon = TYPE_ICONS[entry.type];
8572
8733
  return /* @__PURE__ */ jsxs6(
8573
8734
  DropdownMenuItem,
8574
8735
  {
8575
8736
  onSelect: () => onTypeChange(entry.type),
8576
- className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-primary/10" : ""),
8737
+ className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-bridge-primary/10" : ""),
8577
8738
  children: [
8578
8739
  /* @__PURE__ */ jsx13(Icon, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
8579
8740
  entry.label
@@ -8590,7 +8751,7 @@ function FormFieldToolbar({
8590
8751
  type: "button",
8591
8752
  "aria-pressed": required,
8592
8753
  onClick: onRequiredToggle,
8593
- 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"),
8754
+ 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"),
8594
8755
  "data-ohw-field-required-toggle": "",
8595
8756
  children: [
8596
8757
  /* @__PURE__ */ jsx13(Asterisk, { size: 14, strokeWidth: 2, "aria-hidden": true }),
@@ -8610,7 +8771,7 @@ function FormFieldToolbar({
8610
8771
  children: /* @__PURE__ */ jsx13(MoreHorizontal2, { size: 15, "aria-hidden": true })
8611
8772
  }
8612
8773
  ) }),
8613
- /* @__PURE__ */ jsxs6(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-[170px] p-1", children: [
8774
+ /* @__PURE__ */ jsxs6(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-42.5 p-1", children: [
8614
8775
  /* @__PURE__ */ jsxs6(DropdownMenuItem, { onSelect: onDuplicate, className: "rounded-md py-2 text-[13px]", children: [
8615
8776
  /* @__PURE__ */ jsx13(Copy2, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
8616
8777
  "Duplicate"
@@ -8638,7 +8799,7 @@ function FieldTypePicker({ onPick }) {
8638
8799
  {
8639
8800
  type: "button",
8640
8801
  onClick: () => onPick(entry.type),
8641
- 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",
8802
+ 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",
8642
8803
  children: [
8643
8804
  /* @__PURE__ */ jsx13(Icon, { size: 26, strokeWidth: 1.5, "aria-hidden": true }),
8644
8805
  entry.label
@@ -8664,7 +8825,7 @@ var buttonVariants = cva(
8664
8825
  {
8665
8826
  variants: {
8666
8827
  variant: {
8667
- default: "bg-primary text-primary-foreground hover:opacity-90",
8828
+ default: "bg-bridge-primary text-primary-foreground hover:opacity-90",
8668
8829
  outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
8669
8830
  ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
8670
8831
  },
@@ -8864,8 +9025,8 @@ function MediaOverlay({
8864
9025
  pointerEvents: hover.hasTextOverlap ? "none" : "auto",
8865
9026
  // Selected: a firm component ring with no wash, so the image reads as chosen rather
8866
9027
  // than hovered. Hover keeps the existing tinted preview.
8867
- boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
8868
- background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
9028
+ boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
9029
+ background: selected ? "transparent" : "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
8869
9030
  },
8870
9031
  onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
8871
9032
  children: [
@@ -8959,8 +9120,8 @@ function CarouselOverlay({
8959
9120
  height: rect.height,
8960
9121
  zIndex: 2147483646,
8961
9122
  pointerEvents: "auto",
8962
- boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
8963
- background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
9123
+ boxShadow: "inset 0 0 0 1.5px var(--color-bridge-primary)",
9124
+ background: "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
8964
9125
  },
8965
9126
  onClick: () => onEdit(hover.key),
8966
9127
  children: /* @__PURE__ */ jsxs8(
@@ -9028,6 +9189,57 @@ function useLiveSectionRect(sectionId) {
9028
9189
  }, [sectionId]);
9029
9190
  return rect;
9030
9191
  }
9192
+ var NAV_TOGGLE_LABEL_RE = /^(toggle menu|open menu|close menu)$/i;
9193
+ function readNavToggleRect() {
9194
+ const el = Array.from(document.querySelectorAll("button[aria-label]")).find(
9195
+ (e) => NAV_TOGGLE_LABEL_RE.test(e.getAttribute("aria-label") ?? "")
9196
+ );
9197
+ if (!el) return null;
9198
+ const r2 = el.getBoundingClientRect();
9199
+ if (r2.width <= 0 || r2.height <= 0) return null;
9200
+ return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
9201
+ }
9202
+ function useLiveNavToggleHole(active) {
9203
+ const [rect, setRect] = useState6(null);
9204
+ useEffect4(() => {
9205
+ if (!active) {
9206
+ setRect(null);
9207
+ return;
9208
+ }
9209
+ const update = () => {
9210
+ const next = readNavToggleRect();
9211
+ setRect(
9212
+ (prev) => prev && next && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
9213
+ );
9214
+ };
9215
+ update();
9216
+ const opts = { capture: true, passive: true };
9217
+ window.addEventListener("scroll", update, opts);
9218
+ window.addEventListener("resize", update);
9219
+ const interval = setInterval(update, 500);
9220
+ return () => {
9221
+ window.removeEventListener("scroll", update, opts);
9222
+ window.removeEventListener("resize", update);
9223
+ clearInterval(interval);
9224
+ };
9225
+ }, [active]);
9226
+ return rect;
9227
+ }
9228
+ function subtractRect(outer, hole) {
9229
+ if (!hole) return [outer];
9230
+ const l = Math.max(outer.left, hole.left);
9231
+ const t = Math.max(outer.top, hole.top);
9232
+ const r2 = Math.min(outer.left + outer.width, hole.left + hole.width);
9233
+ const b = Math.min(outer.top + outer.height, hole.top + hole.height);
9234
+ if (l >= r2 || t >= b) return [outer];
9235
+ const rects = [];
9236
+ if (t > outer.top) rects.push({ left: outer.left, top: outer.top, width: outer.width, height: t - outer.top });
9237
+ const midHeight = b - t;
9238
+ if (l > outer.left) rects.push({ left: outer.left, top: t, width: l - outer.left, height: midHeight });
9239
+ if (r2 < outer.left + outer.width) rects.push({ left: r2, top: t, width: outer.left + outer.width - r2, height: midHeight });
9240
+ if (b < outer.top + outer.height) rects.push({ left: outer.left, top: b, width: outer.width, height: outer.top + outer.height - b });
9241
+ return rects;
9242
+ }
9031
9243
  function computeSectionBoundaryFlags(instanceId) {
9032
9244
  const topLevel = topLevelSections();
9033
9245
  const index = topLevel.findIndex((el) => instanceIdOf(el) === instanceId);
@@ -9243,6 +9455,7 @@ function AiSectionOverlay({
9243
9455
  const activeSelectionId = reviewId ? null : selectedId;
9244
9456
  const selectionRect = useLiveSectionRect(activeSelectionId);
9245
9457
  const reviewRect = useLiveSectionRect(reviewId);
9458
+ const navToggleHole = useLiveNavToggleHole(Boolean(reviewId));
9246
9459
  const hoverRect = useLiveSectionRect(reviewId || hoveredId === selectedId ? null : hoveredId);
9247
9460
  const showSelectionBorder = Boolean(selectionRect) && !navDropdownForceOpen;
9248
9461
  useEffect4(() => {
@@ -9302,48 +9515,65 @@ function AiSectionOverlay({
9302
9515
  }
9303
9516
  }
9304
9517
  ),
9305
- reviewRect && /* @__PURE__ */ jsx17(
9306
- "div",
9307
- {
9308
- "data-ohw-ai-review": "",
9309
- style: {
9310
- position: "fixed",
9311
- top: reviewRect.top,
9312
- left: reviewRect.left,
9313
- width: reviewRect.width,
9314
- height: reviewRect.height,
9315
- border: `2px solid ${PRIMARY2}`,
9316
- borderRadius: edgeAwareRadius(reviewRect),
9317
- zIndex: 2147483200,
9318
- // The veil itself: swallows clicks so the section stays locked until decided. This
9319
- // stopPropagation only guards the bubble phase; the bridge's capture-phase click
9320
- // handlers additionally bail on `[data-ohw-ai-review]`, without which a click on
9321
- // Accept/Discard resolves to the media beneath and opens the file picker.
9322
- background: "rgba(8, 133, 254, 0.04)",
9323
- pointerEvents: "auto",
9324
- cursor: "default"
9518
+ reviewRect && /* @__PURE__ */ jsxs9(Fragment5, { children: [
9519
+ subtractRect(reviewRect, navToggleHole).map((r2, i) => /* @__PURE__ */ jsx17(
9520
+ "div",
9521
+ {
9522
+ "data-ohw-ai-review": "",
9523
+ "aria-hidden": true,
9524
+ style: {
9525
+ position: "fixed",
9526
+ top: r2.top,
9527
+ left: r2.left,
9528
+ width: r2.width,
9529
+ height: r2.height,
9530
+ background: "rgba(8, 133, 254, 0.04)",
9531
+ pointerEvents: "auto",
9532
+ cursor: "default",
9533
+ zIndex: 2147483200
9534
+ },
9535
+ onClick: (e) => e.stopPropagation()
9325
9536
  },
9326
- onClick: (e) => e.stopPropagation(),
9327
- children: !reviewButtonsHidden && /* @__PURE__ */ jsxs9(
9328
- "div",
9329
- {
9330
- style: {
9331
- position: "sticky",
9332
- top: 12,
9333
- display: "flex",
9334
- gap: 8,
9335
- justifyContent: "flex-end",
9336
- paddingRight: 12,
9337
- paddingTop: 12
9338
- },
9339
- children: [
9340
- /* @__PURE__ */ jsx17(ReviewButton, { label: "Accept", onClick: () => decide("accept"), background: PRIMARY2, color: "#ffffff", children: /* @__PURE__ */ jsx17(Check, { size: 16, strokeWidth: 2.5, "aria-hidden": true }) }),
9341
- /* @__PURE__ */ jsx17(ReviewButton, { label: "Discard", onClick: () => decide("discard"), background: "#EFF6FF", color: "#0c0a09", children: /* @__PURE__ */ jsx17(X, { size: 16, strokeWidth: 2, "aria-hidden": true }) })
9342
- ]
9537
+ i
9538
+ )),
9539
+ /* @__PURE__ */ jsx17(
9540
+ "div",
9541
+ {
9542
+ "aria-hidden": true,
9543
+ style: {
9544
+ position: "fixed",
9545
+ top: reviewRect.top,
9546
+ left: reviewRect.left,
9547
+ width: reviewRect.width,
9548
+ height: reviewRect.height,
9549
+ border: `2px solid ${PRIMARY2}`,
9550
+ borderRadius: edgeAwareRadius(reviewRect),
9551
+ pointerEvents: "none",
9552
+ zIndex: 2147483200
9343
9553
  }
9344
- )
9345
- }
9346
- )
9554
+ }
9555
+ ),
9556
+ !reviewButtonsHidden && /* @__PURE__ */ jsxs9(
9557
+ "div",
9558
+ {
9559
+ style: {
9560
+ position: "fixed",
9561
+ top: reviewRect.top + 12,
9562
+ left: reviewRect.left,
9563
+ width: reviewRect.width,
9564
+ display: "flex",
9565
+ gap: 8,
9566
+ justifyContent: "flex-end",
9567
+ paddingRight: 12,
9568
+ zIndex: 2147483201
9569
+ },
9570
+ children: [
9571
+ /* @__PURE__ */ jsx17(ReviewButton, { label: "Accept", onClick: () => decide("accept"), background: PRIMARY2, color: "#ffffff", children: /* @__PURE__ */ jsx17(Check, { size: 16, strokeWidth: 2.5, "aria-hidden": true }) }),
9572
+ /* @__PURE__ */ jsx17(ReviewButton, { label: "Discard", onClick: () => decide("discard"), background: "#EFF6FF", color: "#0c0a09", children: /* @__PURE__ */ jsx17(X, { size: 16, strokeWidth: 2, "aria-hidden": true }) })
9573
+ ]
9574
+ }
9575
+ )
9576
+ ] })
9347
9577
  ] });
9348
9578
  }
9349
9579
 
@@ -9813,7 +10043,7 @@ function SectionTreeItem({
9813
10043
  /* @__PURE__ */ jsx20(
9814
10044
  "div",
9815
10045
  {
9816
- className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
10046
+ className: "-mr-px h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
9817
10047
  "aria-hidden": true
9818
10048
  }
9819
10049
  ),
@@ -9832,7 +10062,7 @@ function SectionTreeItem({
9832
10062
  className: cn(
9833
10063
  "flex h-9 min-w-0 flex-1 items-center gap-2 rounded-md border border-border bg-background p-3",
9834
10064
  interactive && "cursor-pointer hover:bg-muted/30",
9835
- interactive && selected && "border-primary"
10065
+ interactive && selected && "border-bridge-primary"
9836
10066
  ),
9837
10067
  children: [
9838
10068
  /* @__PURE__ */ jsx20(
@@ -9962,7 +10192,7 @@ function UrlOrPageInput({
9962
10192
  };
9963
10193
  const fieldClassName = cn(
9964
10194
  "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]",
9965
- urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
10195
+ 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"
9966
10196
  );
9967
10197
  return /* @__PURE__ */ jsxs13("div", { className: "flex w-full flex-col gap-2 p-0", children: [
9968
10198
  /* @__PURE__ */ jsx23(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
@@ -11006,6 +11236,15 @@ function getNavbarDesktopContainer() {
11006
11236
  function getNavbarDrawerContainer() {
11007
11237
  return document.querySelector("[data-ohw-nav-drawer]");
11008
11238
  }
11239
+ function isNavDrawerOpen() {
11240
+ return document.querySelector('[data-ohw-nav-drawer][data-ohw-section="navbar"]') !== null;
11241
+ }
11242
+ function isPointOutsideOpenDrawer(clientX, clientY) {
11243
+ const drawer = document.querySelector('[data-ohw-nav-drawer][data-ohw-section="navbar"]');
11244
+ if (!drawer) return false;
11245
+ const r2 = drawer.getBoundingClientRect();
11246
+ return clientX < r2.left || clientX > r2.right || clientY < r2.top || clientY > r2.bottom;
11247
+ }
11009
11248
  function isNavbarListContainerVisible(el) {
11010
11249
  if (el.hasAttribute("hidden")) return false;
11011
11250
  if (el.closest("[hidden]")) return false;
@@ -14162,7 +14401,7 @@ function DisplaySwitch({
14162
14401
  onClick: () => onChange(!checked),
14163
14402
  className: cn(
14164
14403
  "relative h-5 w-9 shrink-0 rounded-full transition-colors",
14165
- checked ? "bg-primary" : "bg-primary-50",
14404
+ checked ? "bg-bridge-primary" : "bg-primary-50",
14166
14405
  disabled ? "cursor-default opacity-50" : "cursor-pointer"
14167
14406
  ),
14168
14407
  children: /* @__PURE__ */ jsx28(
@@ -14170,7 +14409,7 @@ function DisplaySwitch({
14170
14409
  {
14171
14410
  className: cn(
14172
14411
  "absolute top-0.5 h-4 w-4 rounded-full bg-white transition-all",
14173
- checked ? "left-[1.125rem]" : "left-0.5"
14412
+ checked ? "left-4.5" : "left-0.5"
14174
14413
  )
14175
14414
  }
14176
14415
  )
@@ -15805,7 +16044,7 @@ var badgeVariants = cva(
15805
16044
  {
15806
16045
  variants: {
15807
16046
  variant: {
15808
- default: "border-transparent bg-primary text-primary-foreground",
16047
+ default: "border-transparent bg-bridge-primary text-primary-foreground",
15809
16048
  secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
15810
16049
  destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
15811
16050
  outline: "text-foreground"
@@ -17738,6 +17977,7 @@ function OhhwellsBridge() {
17738
17977
  const aiSectionsRef = useRef10("");
17739
17978
  const brandKitRef = useRef10("");
17740
17979
  const stylesRef = useRef10("");
17980
+ const appliedDrawerRef = useRef10(null);
17741
17981
  const pendingDeleteUndoRef = useRef10(null);
17742
17982
  const [sitePages, setSitePages] = useState14([]);
17743
17983
  const [sectionsByPath, setSectionsByPath] = useState14({});
@@ -19274,7 +19514,9 @@ function OhhwellsBridge() {
19274
19514
  }, [isEditMode]);
19275
19515
  useEffect13(() => {
19276
19516
  if (isEditMode || fetchState !== "done") return;
19517
+ console.log("env", process.env.NEXT_PUBLIC_FLOWOPS_API_URL);
19277
19518
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
19519
+ console.log({ apiUrl, subdomain });
19278
19520
  bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
19279
19521
  }, [isEditMode, fetchState, subdomain]);
19280
19522
  useEffect13(() => {
@@ -19403,6 +19645,17 @@ function OhhwellsBridge() {
19403
19645
  if (!isEditMode) return;
19404
19646
  initSectionInstancesFromContent(editContentRef.current, pathname);
19405
19647
  }, [pathname, isEditMode]);
19648
+ useEffect13(() => {
19649
+ if (!isEditMode) return;
19650
+ const observer = new MutationObserver(() => {
19651
+ const drawer = document.querySelector("[data-ohw-nav-drawer]");
19652
+ if (!drawer || drawer === appliedDrawerRef.current) return;
19653
+ appliedDrawerRef.current = drawer;
19654
+ applyStylesToDom(parseStyleStore(stylesRef.current));
19655
+ });
19656
+ observer.observe(document.body, { childList: true, subtree: true });
19657
+ return () => observer.disconnect();
19658
+ }, [isEditMode, pathname]);
19406
19659
  useEffect13(() => {
19407
19660
  const contentForNav = () => {
19408
19661
  if (isEditMode) return editContentRef.current;
@@ -20164,6 +20417,19 @@ function OhhwellsBridge() {
20164
20417
  const handleMouseOver = (e) => {
20165
20418
  if (document.documentElement.hasAttribute("data-ohw-section-picking")) return;
20166
20419
  const target = e.target;
20420
+ if (isNavDrawerOpen() && isPointOutsideOpenDrawer(e.clientX, e.clientY)) {
20421
+ document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
20422
+ hoveredItemElRef.current = null;
20423
+ setHoveredItemRect(null);
20424
+ hoveredNavContainerRef.current = null;
20425
+ setHoveredNavContainerRect(null);
20426
+ formHoverElRef.current = null;
20427
+ setFormHoverRect(null);
20428
+ siblingHintElRef.current = null;
20429
+ setSiblingHintRect(null);
20430
+ setSiblingHintRects([]);
20431
+ return;
20432
+ }
20167
20433
  if (linkPopoverOpenRef.current) {
20168
20434
  hoveredItemElRef.current = null;
20169
20435
  setHoveredItemRect(null);
@@ -20980,6 +21246,26 @@ function OhhwellsBridge() {
20980
21246
  const handleMouseMove = (e) => {
20981
21247
  const { clientX, clientY } = e;
20982
21248
  if (pointOwnedByFloatingPanel(clientX, clientY)) return;
21249
+ if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
21250
+ document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
21251
+ formHoverElRef.current = null;
21252
+ setFormHoverRect(null);
21253
+ hoveredItemElRef.current = null;
21254
+ setHoveredItemRect(null);
21255
+ hoveredNavContainerRef.current = null;
21256
+ setHoveredNavContainerRect(null);
21257
+ dismissImageHover();
21258
+ if (hoveredGapRef.current) {
21259
+ hoveredGapRef.current = null;
21260
+ setSectionGap(null);
21261
+ }
21262
+ if (activeStateElRef.current) {
21263
+ activeStateElRef.current.removeAttribute("data-ohw-state-hovered");
21264
+ activeStateElRef.current = null;
21265
+ setToggleState(null);
21266
+ }
21267
+ return;
21268
+ }
20983
21269
  if (isOverEditorChrome(clientX, clientY)) {
20984
21270
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
20985
21271
  formHoverElRef.current = null;
@@ -21001,6 +21287,7 @@ function OhhwellsBridge() {
21001
21287
  const { clientX, clientY } = e.data;
21002
21288
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
21003
21289
  if (pointOwnedByFloatingPanel(clientX, clientY)) return;
21290
+ if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
21004
21291
  if (probeSocialsRowAt(clientX, clientY)) return;
21005
21292
  probeSectionGapAt(clientX, clientY);
21006
21293
  probeImageAt(clientX, clientY);
@@ -21579,10 +21866,26 @@ function OhhwellsBridge() {
21579
21866
  const handleGetBrand = (e) => {
21580
21867
  if (e.data?.type !== "ow:get-brand") return;
21581
21868
  const template = deriveTemplateBrand();
21582
- const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
21869
+ const fallback = template ?? (() => {
21870
+ const fonts = deriveTemplateFonts();
21871
+ return fonts ? { palette: AI_DEFAULT_BRAND.palette, fonts } : null;
21872
+ })();
21873
+ const value = brandKitRef.current || (fallback ? JSON.stringify(fallback) : "");
21583
21874
  postToParentRef.current({ type: "ow:brand-value", value });
21584
21875
  };
21585
21876
  window.addEventListener("message", handleGetBrand);
21877
+ const handleGetTemplateFonts = (e) => {
21878
+ if (e.data?.type !== "ow:get-template-fonts") return;
21879
+ const fonts = deriveTemplateFonts();
21880
+ postToParentRef.current({ type: "ow:template-fonts-value", value: fonts ? JSON.stringify(fonts) : "" });
21881
+ };
21882
+ window.addEventListener("message", handleGetTemplateFonts);
21883
+ const handleGetTemplateBrand = (e) => {
21884
+ if (e.data?.type !== "ow:get-template-brand") return;
21885
+ const brand = deriveTemplateBrand();
21886
+ postToParentRef.current({ type: "ow:template-brand-value", value: brand ? JSON.stringify(brand) : "" });
21887
+ };
21888
+ window.addEventListener("message", handleGetTemplateBrand);
21586
21889
  const handleMoveSection = (e) => {
21587
21890
  if (e.data?.type !== "ow:move-section") return;
21588
21891
  const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
@@ -22485,6 +22788,8 @@ function OhhwellsBridge() {
22485
22788
  window.removeEventListener("message", handleAiSetBrand);
22486
22789
  window.removeEventListener("message", handleAiSetStyles);
22487
22790
  window.removeEventListener("message", handleGetBrand);
22791
+ window.removeEventListener("message", handleGetTemplateFonts);
22792
+ window.removeEventListener("message", handleGetTemplateBrand);
22488
22793
  window.removeEventListener("message", handleMoveSection);
22489
22794
  window.removeEventListener("message", handlePanelDragging);
22490
22795
  window.removeEventListener("message", handleDeleteSection);
@@ -22696,7 +23001,7 @@ function OhhwellsBridge() {
22696
23001
  postToParent2({
22697
23002
  type: "ow:ready",
22698
23003
  version: "1",
22699
- bridgeVersion: "0.1.113",
23004
+ bridgeVersion: "0.1.115",
22700
23005
  path: pathname,
22701
23006
  nodes: collectEditableNodes(editContentRef.current),
22702
23007
  sections
@@ -23312,7 +23617,7 @@ function OhhwellsBridge() {
23312
23617
  "span",
23313
23618
  {
23314
23619
  "data-ohw-form-count": "",
23315
- 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",
23620
+ 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",
23316
23621
  children: formPickCount
23317
23622
  }
23318
23623
  )
@@ -23550,11 +23855,11 @@ function OhhwellsBridge() {
23550
23855
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
23551
23856
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
23552
23857
  children: [
23553
- /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
23858
+ /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } }),
23554
23859
  /* @__PURE__ */ jsx33(
23555
23860
  Badge,
23556
23861
  {
23557
- 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",
23862
+ 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",
23558
23863
  onClick: () => {
23559
23864
  window.parent.postMessage(
23560
23865
  {
@@ -23568,7 +23873,7 @@ function OhhwellsBridge() {
23568
23873
  children: "Add Section"
23569
23874
  }
23570
23875
  ),
23571
- /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } })
23876
+ /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } })
23572
23877
  ]
23573
23878
  }
23574
23879
  ),