@ohhwells/bridge 0.1.54 → 0.1.55-next.158

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
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/OhhwellsBridge.tsx
4
- import React11, { useCallback as useCallback6, useEffect as useEffect11, useLayoutEffect as useLayoutEffect3, useRef as useRef8, useState as useState10 } from "react";
4
+ import React11, { useCallback as useCallback7, useEffect as useEffect12, useLayoutEffect as useLayoutEffect4, useRef as useRef9, useState as useState11 } from "react";
5
5
  import { createRoot as createRoot2 } from "react-dom/client";
6
6
  import { flushSync as flushSync2 } from "react-dom";
7
7
 
@@ -118,6 +118,129 @@ function deleteSectionFromState(state, sectionId) {
118
118
  return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
119
119
  }
120
120
 
121
+ // src/lib/brand-chrome.ts
122
+ var BRAND_NAME_KEY = "__ohw_brand_name";
123
+ var BRAND_TITLE_KEY = "__ohw_site_title";
124
+ var BRAND_FAVICON_LETTER_KEY = "__ohw_favicon_letter";
125
+ var BRAND_CHROME_KEYS = /* @__PURE__ */ new Set([
126
+ BRAND_NAME_KEY,
127
+ BRAND_TITLE_KEY,
128
+ BRAND_FAVICON_LETTER_KEY
129
+ ]);
130
+ function upsertMeta(selector, attr, token, value) {
131
+ let el = document.head.querySelector(selector);
132
+ if (!el) {
133
+ el = document.createElement("meta");
134
+ el.setAttribute(attr, token);
135
+ document.head.appendChild(el);
136
+ }
137
+ if (el.getAttribute("content") !== value) el.setAttribute("content", value);
138
+ }
139
+ function escapeXml(value) {
140
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
141
+ }
142
+ function applyLetterFavicon(letter) {
143
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="12" fill="#111827"/><text x="32" y="46" font-family="system-ui,-apple-system,Segoe UI,sans-serif" font-size="40" font-weight="700" text-anchor="middle" fill="#ffffff">${escapeXml(letter)}</text></svg>`;
144
+ const href = `data:image/svg+xml,${encodeURIComponent(svg)}`;
145
+ let link = document.head.querySelector('link[rel="icon"]');
146
+ if (!link) {
147
+ link = document.createElement("link");
148
+ link.rel = "icon";
149
+ document.head.appendChild(link);
150
+ }
151
+ link.type = "image/svg+xml";
152
+ if (link.href !== href) link.href = href;
153
+ }
154
+ function applyBrandChrome(content) {
155
+ const name = content[BRAND_NAME_KEY];
156
+ if (typeof name === "string" && name.length > 0) {
157
+ document.querySelectorAll("[data-ohw-wordmark]").forEach((el) => {
158
+ if (el.textContent !== name) el.textContent = name;
159
+ if (el.getAttribute("title") !== name) el.setAttribute("title", name);
160
+ });
161
+ }
162
+ const title = content[BRAND_TITLE_KEY];
163
+ if (typeof title === "string" && title.length > 0) {
164
+ if (document.title !== title) document.title = title;
165
+ upsertMeta('meta[property="og:title"]', "property", "og:title", title);
166
+ upsertMeta('meta[name="twitter:title"]', "name", "twitter:title", title);
167
+ }
168
+ const letter = content[BRAND_FAVICON_LETTER_KEY];
169
+ if (typeof letter === "string" && letter.length > 0) {
170
+ applyLetterFavicon(letter);
171
+ }
172
+ }
173
+
174
+ // src/lib/brand-kit.ts
175
+ var BRAND_KIT_KEY = "__ohw_brand";
176
+ var BRAND_VAR_PREFIX = "--ohw-brand-";
177
+ var BRAND_VAR_NAMES = ["primary", "accent", "light", "dark", "surface", "border", "muted"].map(
178
+ (role) => `${BRAND_VAR_PREFIX}${role}`
179
+ );
180
+ var FONT_VARS = { heading: ["--font-heading", "--font-display"], body: ["--font-body"] };
181
+ var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
182
+ function brandColorVars(kit) {
183
+ const { dark, primary, accent, light } = kit.palette;
184
+ const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
185
+ return {
186
+ [`${BRAND_VAR_PREFIX}primary`]: primary,
187
+ [`${BRAND_VAR_PREFIX}accent`]: accent,
188
+ [`${BRAND_VAR_PREFIX}light`]: light,
189
+ [`${BRAND_VAR_PREFIX}dark`]: dark,
190
+ [`${BRAND_VAR_PREFIX}surface`]: mix(light, 95, dark),
191
+ [`${BRAND_VAR_PREFIX}border`]: mix(light, 85, dark),
192
+ [`${BRAND_VAR_PREFIX}muted`]: mix(dark, 62, light)
193
+ };
194
+ }
195
+ function parseBrandKit(raw) {
196
+ if (!raw) return null;
197
+ try {
198
+ const parsed = JSON.parse(raw);
199
+ const p = parsed?.palette;
200
+ const f = parsed?.fonts;
201
+ 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") {
202
+ return null;
203
+ }
204
+ return {
205
+ palette: { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light },
206
+ fonts: { heading: f.heading, body: f.body }
207
+ };
208
+ } catch {
209
+ return null;
210
+ }
211
+ }
212
+ function familyOf(stack) {
213
+ const first = stack.split(",")[0]?.trim() ?? "";
214
+ return first.replace(/^['"]|['"]$/g, "");
215
+ }
216
+ function loadBrandFonts(families) {
217
+ const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
218
+ if (unique.length === 0) return;
219
+ const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
220
+ const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
221
+ let link = document.getElementById(BRAND_FONT_LINK_ID);
222
+ if (!link) {
223
+ link = document.createElement("link");
224
+ link.id = BRAND_FONT_LINK_ID;
225
+ link.rel = "stylesheet";
226
+ document.head.appendChild(link);
227
+ }
228
+ if (link.href !== href) link.href = href;
229
+ }
230
+ function applyBrandToDom(kit) {
231
+ const root = document.documentElement;
232
+ if (!kit) {
233
+ for (const name of BRAND_VAR_NAMES) root.style.removeProperty(name);
234
+ for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
235
+ document.getElementById(BRAND_FONT_LINK_ID)?.remove();
236
+ return;
237
+ }
238
+ for (const [name, value] of Object.entries(brandColorVars(kit))) root.style.setProperty(name, value);
239
+ for (const name of FONT_VARS.heading) root.style.setProperty(name, kit.fonts.heading);
240
+ for (const name of FONT_VARS.body) root.style.setProperty(name, kit.fonts.body);
241
+ loadBrandFonts([familyOf(kit.fonts.heading), familyOf(kit.fonts.body)]);
242
+ }
243
+
121
244
  // src/ui/ai-tree/aiSectionsManager.tsx
122
245
  import { flushSync } from "react-dom";
123
246
  import { createRoot } from "react-dom/client";
@@ -162,13 +285,17 @@ function MediaBox({
162
285
  const url = refValue ? ctx.resolveMedia(refValue) : null;
163
286
  const isIcon = /^(lucide|simple):/.test(refValue);
164
287
  const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
165
- const editAttrs = ctx.keyFor && editPath && !isIcon ? { "data-ohw-key": ctx.keyFor(editPath), "data-ohw-editable": "image" } : {};
288
+ const editAttrs = ctx.keyFor && editPath ? {
289
+ "data-ohw-key": ctx.keyFor(editPath),
290
+ "data-ohw-editable": isIcon ? "icon" : "image"
291
+ } : {};
166
292
  if (isIcon) {
167
293
  const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
168
294
  return /* @__PURE__ */ jsx(
169
295
  "span",
170
296
  {
171
297
  "data-ai-icon": refValue,
298
+ ...editAttrs,
172
299
  style: {
173
300
  display: "inline-flex",
174
301
  width: 48,
@@ -1200,17 +1327,34 @@ import { jsx as jsx2 } from "react/jsx-runtime";
1200
1327
  var CONTAINER_ATTR = "data-ohw-ai-generated";
1201
1328
  var REPLACED_ATTR = "data-ohw-ai-replaced-by";
1202
1329
  var REMOVED_ATTR = "data-ohw-ai-removed";
1330
+ function readRootVar(name) {
1331
+ if (typeof document === "undefined") return "";
1332
+ return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
1333
+ }
1334
+ function deriveBrandOverride() {
1335
+ const dark = readRootVar("--ohw-brand-dark");
1336
+ const primary = readRootVar("--ohw-brand-primary");
1337
+ const light = readRootVar("--ohw-brand-light");
1338
+ if (!dark || !primary || !light) return null;
1339
+ const accent = readRootVar("--ohw-brand-accent");
1340
+ const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1341
+ const body = readRootVar("--font-body");
1342
+ return {
1343
+ palette: { dark, primary, accent: accent || dark, light },
1344
+ fonts: {
1345
+ heading: heading || AI_DEFAULT_BRAND.fonts.heading,
1346
+ body: body || AI_DEFAULT_BRAND.fonts.body
1347
+ }
1348
+ };
1349
+ }
1203
1350
  function deriveTemplateBrand() {
1204
- if (typeof document === "undefined") return null;
1205
- const cs = getComputedStyle(document.documentElement);
1206
- const read = (name) => cs.getPropertyValue(name).trim();
1207
- const dark = read("--color-dark");
1208
- const primary = read("--color-primary");
1209
- const light = read("--color-light");
1351
+ const dark = readRootVar("--color-dark");
1352
+ const primary = readRootVar("--color-primary");
1353
+ const light = readRootVar("--color-light");
1210
1354
  if (!dark || !primary || !light) return null;
1211
- const accent = read("--color-accent");
1212
- const heading = read("--font-heading") || read("--font-display");
1213
- const body = read("--font-body");
1355
+ const accent = readRootVar("--color-accent");
1356
+ const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1357
+ const body = readRootVar("--font-body");
1214
1358
  return {
1215
1359
  palette: { dark, primary, accent: accent || dark, light },
1216
1360
  fonts: {
@@ -1302,7 +1446,9 @@ function syncReplacedOriginals(state) {
1302
1446
  }
1303
1447
  function applyAiSectionsToDom(state, options) {
1304
1448
  if (typeof document === "undefined") return;
1449
+ const brandOverride = deriveBrandOverride();
1305
1450
  const templateBrand = deriveTemplateBrand();
1451
+ const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
1306
1452
  const activeIds = new Set(state.sections.map((entry) => entry.id));
1307
1453
  for (const [id, section] of mounted) {
1308
1454
  if (!activeIds.has(id)) {
@@ -1312,7 +1458,7 @@ function applyAiSectionsToDom(state, options) {
1312
1458
  }
1313
1459
  }
1314
1460
  for (const entry of state.sections) {
1315
- const serialized = JSON.stringify(entry);
1461
+ const serialized = JSON.stringify(entry) + brandKey;
1316
1462
  const existing = mounted.get(entry.id);
1317
1463
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
1318
1464
  continue;
@@ -1336,7 +1482,7 @@ function applyAiSectionsToDom(state, options) {
1336
1482
  AiTreeRenderer,
1337
1483
  {
1338
1484
  tree: entry.tree,
1339
- brand: entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1485
+ brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1340
1486
  resolveMedia,
1341
1487
  editKeyPrefix: `ai.${entry.id}`
1342
1488
  }
@@ -1953,7 +2099,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
1953
2099
  const autoId = useId();
1954
2100
  const insertAfter = insertAfterProp ?? autoId;
1955
2101
  const [schedule, setSchedule] = useState2(null);
1956
- const [loading, setLoading] = useState2(true);
2102
+ const [loading, setLoading] = useState2(initialScheduleId !== null);
1957
2103
  const [inEditor, setInEditor] = useState2(false);
1958
2104
  const [isHovered, setIsHovered] = useState2(false);
1959
2105
  const [modalState, setModalState] = useState2(null);
@@ -2127,8 +2273,10 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2127
2273
  "*"
2128
2274
  );
2129
2275
  };
2130
- if (!inEditor && !loading && !schedule) return null;
2131
2276
  const sectionId = `scheduling-${insertAfter}`;
2277
+ if (!inEditor && !loading && !schedule) {
2278
+ return /* @__PURE__ */ jsx4("section", { "data-ohw-section": sectionId, "data-ohw-scheduling-anchor": insertAfter, style: { display: "none" } });
2279
+ }
2132
2280
  return /* @__PURE__ */ jsxs3(
2133
2281
  "section",
2134
2282
  {
@@ -5697,7 +5845,7 @@ CustomToolbarButton.displayName = "CustomToolbarButton";
5697
5845
 
5698
5846
  // src/ui/item-action-toolbar.tsx
5699
5847
  import { useState as useState3 } from "react";
5700
- import { Copy, CornerLeftUp, Heading, Link, MoreHorizontal, Plus, Trash2 } from "lucide-react";
5848
+ import { Brush, Copy, CornerLeftUp, Heading, Link, MoreHorizontal, Plus, Trash2 } from "lucide-react";
5701
5849
 
5702
5850
  // src/ui/dropdown-menu.tsx
5703
5851
  import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
@@ -5862,6 +6010,7 @@ function ToolbarActionTooltip({
5862
6010
  function ItemActionToolbar({
5863
6011
  onEditLink,
5864
6012
  onAddItem,
6013
+ onStyle,
5865
6014
  onSelectParent,
5866
6015
  onDuplicate,
5867
6016
  onDelete,
@@ -5873,6 +6022,8 @@ function ItemActionToolbar({
5873
6022
  deleteDisabled = false,
5874
6023
  showEditLink = true,
5875
6024
  showAddItem = true,
6025
+ showStyle = false,
6026
+ styleActive = false,
5876
6027
  showMore = true,
5877
6028
  tooltipSide = "bottom",
5878
6029
  dropdownOpen = null,
@@ -5946,6 +6097,22 @@ function ItemActionToolbar({
5946
6097
  children: /* @__PURE__ */ jsx11(Link, { className: "size-4 shrink-0", "aria-hidden": true })
5947
6098
  }
5948
6099
  ) : null,
6100
+ showStyle ? /* @__PURE__ */ jsx11(
6101
+ ToolbarActionTooltip,
6102
+ {
6103
+ label: "Style",
6104
+ side: tooltipSide,
6105
+ buttonProps: {
6106
+ active: styleActive,
6107
+ onMouseDown: (e) => {
6108
+ e.preventDefault();
6109
+ e.stopPropagation();
6110
+ onStyle?.();
6111
+ }
6112
+ },
6113
+ children: /* @__PURE__ */ jsx11(Brush, { className: "size-4 shrink-0", "aria-hidden": true })
6114
+ }
6115
+ ) : null,
5949
6116
  showAddItem ? /* @__PURE__ */ jsx11(
5950
6117
  ToolbarActionTooltip,
5951
6118
  {
@@ -9452,6 +9619,449 @@ function deleteNavbarItem(sourceAnchor) {
9452
9619
  };
9453
9620
  }
9454
9621
 
9622
+ // src/lib/icon-markup.ts
9623
+ var GLYPH_SELECTOR = "svg, img";
9624
+ function referenceBox(slot) {
9625
+ const row = slot.closest("[data-ohw-socials-row]") ?? slot.closest("a")?.parentElement ?? null;
9626
+ const neighbour = row ? Array.from(row.querySelectorAll('[data-ohw-editable="icon"]')).find((el) => el !== slot) : null;
9627
+ const source = (neighbour ?? slot).querySelector(GLYPH_SELECTOR);
9628
+ const box = source?.getBoundingClientRect() ?? null;
9629
+ return box?.width && box.height ? box : null;
9630
+ }
9631
+ function iconMarkupSizedFor(slot, markup) {
9632
+ const box = referenceBox(slot);
9633
+ if (!box) return markup;
9634
+ const holder = document.createElement("div");
9635
+ holder.innerHTML = markup;
9636
+ const glyph = holder.querySelector(GLYPH_SELECTOR);
9637
+ if (!glyph) return markup;
9638
+ glyph.style.width = `${Math.round(box.width)}px`;
9639
+ glyph.style.height = `${Math.round(box.height)}px`;
9640
+ return holder.innerHTML;
9641
+ }
9642
+ function applyIconMarkup(slot, markup) {
9643
+ if (!markup) return;
9644
+ const coloured = iconMarkupInheritingColour(markup);
9645
+ const sized = iconMarkupSizedFor(slot, coloured);
9646
+ if (slot.innerHTML !== sized) slot.innerHTML = sized;
9647
+ if (sized === coloured) {
9648
+ requestAnimationFrame(() => {
9649
+ if (!slot.isConnected) return;
9650
+ const resized = iconMarkupSizedFor(slot, coloured);
9651
+ if (resized !== coloured && slot.innerHTML !== resized) slot.innerHTML = resized;
9652
+ });
9653
+ }
9654
+ }
9655
+ function detectIconStyle(el) {
9656
+ const row = el.closest("[data-ohw-socials-row]");
9657
+ const glyphs = Array.from((row ?? el).querySelectorAll("svg"));
9658
+ const outlined = glyphs.some((svg) => {
9659
+ return Array.from(svg.querySelectorAll("*")).some((node) => {
9660
+ return node.getAttribute("stroke") !== null && node.getAttribute("stroke") !== "none";
9661
+ });
9662
+ });
9663
+ return outlined ? "outline" : "fill";
9664
+ }
9665
+ function iconMarkupInheritingColour(markup) {
9666
+ const holder = document.createElement("div");
9667
+ holder.innerHTML = markup;
9668
+ holder.querySelectorAll("svg *").forEach((node) => {
9669
+ if (node.getAttribute("fill") && node.getAttribute("fill") !== "none") {
9670
+ node.setAttribute("fill", "currentColor");
9671
+ }
9672
+ if (node.getAttribute("stroke") && node.getAttribute("stroke") !== "none") {
9673
+ node.setAttribute("stroke", "currentColor");
9674
+ }
9675
+ });
9676
+ return holder.innerHTML;
9677
+ }
9678
+
9679
+ // src/lib/socials-items.ts
9680
+ var ICON_SELECTOR = '[data-ohw-editable="icon"]';
9681
+ var SOCIAL_KEY_RE = /(^|-)social(s)?(-|$)/i;
9682
+ var SOCIALS_ROW_ATTR = "data-ohw-socials-row";
9683
+ var SOCIALS_ITEM_ATTR = "data-ohw-social-item";
9684
+ function isSocialItem(el) {
9685
+ if (!el) return false;
9686
+ const anchor = el instanceof HTMLAnchorElement ? el : el.closest("a");
9687
+ if (!anchor) return false;
9688
+ if (SOCIAL_KEY_RE.test(anchor.getAttribute("data-ohw-href-key") ?? "")) return true;
9689
+ return anchor.querySelectorAll(ICON_SELECTOR).length === 1;
9690
+ }
9691
+ function getSocialItem(el) {
9692
+ const anchor = el.closest("a");
9693
+ return isSocialItem(anchor) ? anchor : null;
9694
+ }
9695
+ function findSocialsRow(el) {
9696
+ const item = getSocialItem(el);
9697
+ if (!item) return null;
9698
+ const wrapper = item.parentElement;
9699
+ const row = wrapper && wrapper.querySelectorAll("a").length === 1 && wrapper.matches("li, div, span") ? wrapper.parentElement : wrapper;
9700
+ if (!row) return null;
9701
+ const anchors = Array.from(row.querySelectorAll("a"));
9702
+ if (!anchors.length || !anchors.every((anchor) => isSocialItem(anchor))) return null;
9703
+ return row;
9704
+ }
9705
+ function isSocialsRow(el) {
9706
+ const anchors = Array.from(el.querySelectorAll("a"));
9707
+ return anchors.length > 0 && anchors.every((anchor) => isSocialItem(anchor));
9708
+ }
9709
+ function listSocialItems(row) {
9710
+ return Array.from(row.children).map((child) => {
9711
+ if (!(child instanceof HTMLElement)) return null;
9712
+ const anchor = child.matches("a") ? child : child.querySelector("a");
9713
+ return isSocialItem(anchor) ? anchor : null;
9714
+ }).filter((item) => item !== null);
9715
+ }
9716
+ function socialRowUnit(item) {
9717
+ const row = findSocialsRow(item);
9718
+ let node = item;
9719
+ while (node.parentElement && node.parentElement !== row) {
9720
+ node = node.parentElement;
9721
+ }
9722
+ return node;
9723
+ }
9724
+ function listSocialsRows(root = document) {
9725
+ const rows = /* @__PURE__ */ new Set();
9726
+ root.querySelectorAll(`${ICON_SELECTOR}, a[data-ohw-href-key]`).forEach((el) => {
9727
+ const row = findSocialsRow(el);
9728
+ if (row) rows.add(row);
9729
+ });
9730
+ root.querySelectorAll(`[${SOCIALS_ROW_ATTR}]`).forEach((row) => rows.add(row));
9731
+ return Array.from(rows);
9732
+ }
9733
+ var rowTemplates = /* @__PURE__ */ new Map();
9734
+ function markSocialsRows(root = document) {
9735
+ root.querySelectorAll(`[${SOCIALS_ITEM_ATTR}]`).forEach((item) => {
9736
+ item.removeAttribute(SOCIALS_ITEM_ATTR);
9737
+ });
9738
+ listSocialsRows(root).forEach((row) => {
9739
+ row.setAttribute(SOCIALS_ROW_ATTR, "");
9740
+ const items = listSocialItems(row);
9741
+ if (items[0]) rowTemplates.set(rowKeyOf(row), socialRowUnit(items[0]).outerHTML);
9742
+ items.forEach((item, index) => {
9743
+ item.setAttribute(SOCIALS_ITEM_ATTR, String(index));
9744
+ const iconKey = socialIconKey(item);
9745
+ if (iconKey) ensureLabelSlot(item, iconKey);
9746
+ });
9747
+ });
9748
+ }
9749
+ var SOCIALS_LABEL_ATTR = "data-ohw-social-label";
9750
+ function ensureLabelSlot(item, iconKey) {
9751
+ if (socialLabelElement(item)) return;
9752
+ const label = document.createElement("span");
9753
+ label.setAttribute("data-ohw-key", `${iconKey}-label`);
9754
+ label.setAttribute("data-ohw-editable", "text");
9755
+ label.setAttribute(SOCIALS_LABEL_ATTR, "");
9756
+ label.style.display = "none";
9757
+ label.textContent = item.getAttribute("aria-label") ?? "";
9758
+ item.appendChild(label);
9759
+ }
9760
+ function socialLabelElement(item) {
9761
+ return item.querySelector(
9762
+ `[${SOCIALS_LABEL_ATTR}], [data-ohw-editable="text"], [data-ohw-editable="plain"]`
9763
+ );
9764
+ }
9765
+ function socialLabelKey(iconKey) {
9766
+ return `${iconKey}-label`;
9767
+ }
9768
+ function applyStoredValues(item, content) {
9769
+ const hrefKey = socialHrefKey(item);
9770
+ const iconKey = socialIconKey(item);
9771
+ if (hrefKey && content[hrefKey] !== void 0) item.setAttribute("href", content[hrefKey]);
9772
+ if (iconKey) {
9773
+ const glyph = item.querySelector(ICON_SELECTOR);
9774
+ if (glyph && content[iconKey]) applyIconMarkup(glyph, content[iconKey]);
9775
+ const label = item.querySelector(`[${SOCIALS_LABEL_ATTR}]`);
9776
+ label?.setAttribute("data-ohw-key", socialLabelKey(iconKey));
9777
+ const stored = content[socialLabelKey(iconKey)];
9778
+ if (label && stored) label.textContent = stored;
9779
+ }
9780
+ }
9781
+ function socialPlatformKey(iconKey) {
9782
+ return `${iconKey}-platform`;
9783
+ }
9784
+ function socialHrefKey(item) {
9785
+ return item.getAttribute("data-ohw-href-key");
9786
+ }
9787
+ function socialIconKey(item) {
9788
+ return item.querySelector(ICON_SELECTOR)?.dataset.ohwKey ?? null;
9789
+ }
9790
+ var SOCIALS_ORDER_KEY = "__ohw_socials_order";
9791
+ function fromMarkup(markup) {
9792
+ const holder = document.createElement("div");
9793
+ holder.innerHTML = markup;
9794
+ return holder.firstElementChild instanceof HTMLElement ? holder.firstElementChild : null;
9795
+ }
9796
+ var rowKeys = /* @__PURE__ */ new WeakMap();
9797
+ function rowKeyOf(row) {
9798
+ const first = listSocialItems(row)[0];
9799
+ const itemKey = first ? socialIconKey(first) ?? socialHrefKey(first)?.replace(/-href$/, "") : null;
9800
+ const derived = itemKey?.replace(/-[^-]+$/, "") || null;
9801
+ if (derived) rowKeys.set(row, derived);
9802
+ return derived ?? rowKeys.get(row) ?? "social";
9803
+ }
9804
+ function getSocialsOrderFromDom(root = document) {
9805
+ const order = {};
9806
+ listSocialsRows(root).forEach((row) => {
9807
+ order[rowKeyOf(row)] = listSocialItems(row).map((item) => socialHrefKey(item)).filter((key) => Boolean(key));
9808
+ });
9809
+ return order;
9810
+ }
9811
+ function hasStoredValue(content, hrefKey) {
9812
+ const iconKey = hrefKey.replace(/-href$/, "");
9813
+ return Boolean(content[hrefKey]) || Boolean(content[iconKey]);
9814
+ }
9815
+ function parseSocialsOrder(raw) {
9816
+ if (!raw) return null;
9817
+ try {
9818
+ const parsed = JSON.parse(raw);
9819
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
9820
+ } catch {
9821
+ return null;
9822
+ }
9823
+ }
9824
+ function nextSocialIndex(row, rowKey, content) {
9825
+ const used = listSocialItems(row).map((item) => socialHrefKey(item)).concat(Object.keys(content)).map((key) => key?.match(new RegExp(`^${rowKey}-(\\d+)`))?.[1]).map((digits) => digits === void 0 ? -1 : Number(digits));
9826
+ return Math.max(-1, ...used) + 1;
9827
+ }
9828
+ function insertSocialItem(row, after, content = {}) {
9829
+ const rowKey = rowKeyOf(row);
9830
+ const template = listSocialItems(row)[0];
9831
+ const remembered = rowTemplates.get(rowKey);
9832
+ if (!template && !remembered) return null;
9833
+ const index = nextSocialIndex(row, rowKey, content);
9834
+ const iconKey = `${rowKey}-${index}`;
9835
+ const hrefKey = `${iconKey}-href`;
9836
+ const templateUnit = template ? socialRowUnit(template) : null;
9837
+ const unit = templateUnit ? templateUnit.cloneNode(true) : fromMarkup(remembered);
9838
+ const item = unit && (unit.matches("a") ? unit : unit.querySelector("a"));
9839
+ if (!unit || !item) return null;
9840
+ item.setAttribute("data-ohw-href-key", hrefKey);
9841
+ item.setAttribute("href", "");
9842
+ item.removeAttribute("aria-label");
9843
+ item.querySelectorAll("[data-ohw-hovered], [data-ohw-selected]").forEach((el) => {
9844
+ el.removeAttribute("data-ohw-hovered");
9845
+ el.removeAttribute("data-ohw-selected");
9846
+ });
9847
+ const icon = item.querySelector(ICON_SELECTOR);
9848
+ icon?.setAttribute("data-ohw-key", iconKey);
9849
+ item.querySelector(`[${SOCIALS_LABEL_ATTR}]`)?.remove();
9850
+ const afterUnit = after ? socialRowUnit(after) : null;
9851
+ if (afterUnit && afterUnit.parentElement === row) afterUnit.insertAdjacentElement("afterend", unit);
9852
+ else row.appendChild(unit);
9853
+ markSocialsRows(row.ownerDocument);
9854
+ return { item, hrefKey, iconKey, order: getSocialsOrderFromDom(row.ownerDocument) };
9855
+ }
9856
+ function duplicateSocialItem(item, content) {
9857
+ const row = findSocialsRow(item);
9858
+ const created = row ? insertSocialItem(row, item, content) : null;
9859
+ if (!created) return null;
9860
+ const sourceHref = socialHrefKey(item);
9861
+ const sourceIcon = socialIconKey(item);
9862
+ const link = created.item;
9863
+ if (sourceHref) link.setAttribute("href", item.getAttribute("href") ?? "");
9864
+ const glyph = item.querySelector(ICON_SELECTOR)?.innerHTML;
9865
+ if (glyph) {
9866
+ const slot = link.querySelector(ICON_SELECTOR);
9867
+ if (slot) slot.innerHTML = glyph;
9868
+ }
9869
+ return {
9870
+ ...created,
9871
+ copiedFrom: { href: sourceHref, icon: sourceIcon }
9872
+ };
9873
+ }
9874
+ function removeSocialItem(item, content) {
9875
+ const row = findSocialsRow(item);
9876
+ if (!row) return null;
9877
+ const hrefKey = socialHrefKey(item);
9878
+ const iconKey = socialIconKey(item);
9879
+ const removedKeys = [hrefKey, iconKey].filter((key) => Boolean(key));
9880
+ if (!removedKeys.length) return null;
9881
+ const previousOrder = getSocialsOrderFromDom(row.ownerDocument);
9882
+ const previousContent = Object.fromEntries(
9883
+ removedKeys.filter((key) => key in content).map((key) => [key, content[key]])
9884
+ );
9885
+ const unit = socialRowUnit(item);
9886
+ const nextSibling = unit.nextElementSibling;
9887
+ unit.remove();
9888
+ markSocialsRows(row.ownerDocument);
9889
+ return {
9890
+ removedKeys,
9891
+ previousContent,
9892
+ order: getSocialsOrderFromDom(row.ownerDocument),
9893
+ previousOrder,
9894
+ undo: () => {
9895
+ if (nextSibling) nextSibling.before(unit);
9896
+ else row.appendChild(unit);
9897
+ markSocialsRows(row.ownerDocument);
9898
+ }
9899
+ };
9900
+ }
9901
+ function applySocialsOrder(order, root = document) {
9902
+ listSocialsRows(root).forEach((row) => {
9903
+ const wanted = order[rowKeyOf(row)];
9904
+ if (!wanted) return;
9905
+ const byKey = new Map(listSocialItems(row).map((item) => [socialHrefKey(item), item]));
9906
+ wanted.forEach((key) => {
9907
+ const item = byKey.get(key);
9908
+ if (item) row.appendChild(socialRowUnit(item));
9909
+ });
9910
+ });
9911
+ markSocialsRows(root);
9912
+ }
9913
+ function reconcileSocialsFromContent(content, root = document) {
9914
+ markSocialsRows(root);
9915
+ const stored = parseSocialsOrder(content[SOCIALS_ORDER_KEY]);
9916
+ if (!stored) return;
9917
+ listSocialsRows(root).forEach((row) => {
9918
+ const wanted = stored[rowKeyOf(row)];
9919
+ if (!wanted) return;
9920
+ if (!wanted.length) return;
9921
+ wanted.forEach((key) => {
9922
+ if (listSocialItems(row).some((item) => socialHrefKey(item) === key)) return;
9923
+ if (!hasStoredValue(content, key)) return;
9924
+ const created = insertSocialItem(row, null, content);
9925
+ if (created) {
9926
+ created.item.setAttribute("data-ohw-href-key", key);
9927
+ created.item.querySelector(ICON_SELECTOR)?.setAttribute("data-ohw-key", key.replace(/-href$/, ""));
9928
+ applyStoredValues(created.item, content);
9929
+ }
9930
+ });
9931
+ const present = listSocialItems(row);
9932
+ const surviving = present.filter((item) => {
9933
+ const key = socialHrefKey(item);
9934
+ return !key || wanted.includes(key);
9935
+ });
9936
+ if (surviving.length) {
9937
+ present.forEach((item) => {
9938
+ if (!surviving.includes(item)) socialRowUnit(item).remove();
9939
+ });
9940
+ }
9941
+ });
9942
+ applySocialsOrder(stored, root);
9943
+ }
9944
+ var DROP_BAR_THICKNESS = 3;
9945
+ var DROP_BAR_GAP = 8;
9946
+ function buildSocialDropSlots(row) {
9947
+ const items = listSocialItems(row);
9948
+ if (!items.length) return [];
9949
+ const rects = items.map((item) => item.getBoundingClientRect());
9950
+ return items.concat(items[items.length - 1]).map((_, index) => {
9951
+ const previous = rects[index - 1];
9952
+ const next = rects[index];
9953
+ const centre = previous && next ? (previous.right + next.left) / 2 : next ? next.left - DROP_BAR_GAP : previous.right + DROP_BAR_GAP;
9954
+ const rect = next ?? previous;
9955
+ return {
9956
+ insertIndex: index,
9957
+ columnIndex: -1,
9958
+ left: centre - DROP_BAR_THICKNESS / 2,
9959
+ top: rect.top,
9960
+ width: DROP_BAR_THICKNESS,
9961
+ height: rect.height,
9962
+ direction: "vertical"
9963
+ };
9964
+ });
9965
+ }
9966
+ function findSocialByHrefKey(hrefKey, root = document) {
9967
+ const el = root.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
9968
+ return el ? getSocialItem(el) : null;
9969
+ }
9970
+ function buildSocialDropSlotsForKey(hrefKey, root = document) {
9971
+ const item = findSocialByHrefKey(hrefKey, root);
9972
+ const row = item ? findSocialsRow(item) : null;
9973
+ return row ? buildSocialDropSlots(row) : [];
9974
+ }
9975
+ function hitTestSocialDropSlot(clientX, clientY, draggedHrefKey, root = document) {
9976
+ const distanceTo = (slot) => {
9977
+ const dx = clientX - (slot.left + slot.width / 2);
9978
+ const dy = clientY < slot.top ? slot.top - clientY : Math.max(0, clientY - (slot.top + slot.height));
9979
+ return Math.hypot(dx, dy);
9980
+ };
9981
+ const slots = buildSocialDropSlotsForKey(draggedHrefKey, root);
9982
+ return slots.reduce((best, slot) => {
9983
+ return !best || distanceTo(slot) < distanceTo(best) ? slot : best;
9984
+ }, null);
9985
+ }
9986
+ function planSocialMove(hrefKey, insertIndex, root = document) {
9987
+ const item = findSocialByHrefKey(hrefKey, root);
9988
+ const row = item ? findSocialsRow(item) : null;
9989
+ if (!row) return null;
9990
+ const order = getSocialsOrderFromDom(root);
9991
+ const key = rowKeyOf(row);
9992
+ const current = order[key];
9993
+ if (!current) return null;
9994
+ const from = current.indexOf(hrefKey);
9995
+ if (from < 0) return null;
9996
+ const next = current.filter((_, index) => index !== from);
9997
+ next.splice(insertIndex > from ? insertIndex - 1 : insertIndex, 0, hrefKey);
9998
+ return { ...order, [key]: next };
9999
+ }
10000
+ var SOCIALS_DISPLAY_KEY = "__ohw_socials_display";
10001
+ function readSocialsDisplay(row) {
10002
+ const items = listSocialItems(row);
10003
+ const visible = (el) => Boolean(el) && el.style.display !== "none" && el.getAttribute("data-ohw-hidden") === null;
10004
+ return {
10005
+ text: items.some((item) => visible(socialLabelElement(item))),
10006
+ icon: items.some((item) => visible(item.querySelector(ICON_SELECTOR)))
10007
+ };
10008
+ }
10009
+ function parseSocialsDisplay(raw) {
10010
+ if (!raw) return null;
10011
+ try {
10012
+ const parsed = JSON.parse(raw);
10013
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
10014
+ } catch {
10015
+ return null;
10016
+ }
10017
+ }
10018
+ function socialsDisplayFor(row, content) {
10019
+ return parseSocialsDisplay(content[SOCIALS_DISPLAY_KEY])?.[rowKeyOf(row)] ?? readSocialsDisplay(row);
10020
+ }
10021
+ function socialsDisplayWith(row, display, content) {
10022
+ return { ...parseSocialsDisplay(content[SOCIALS_DISPLAY_KEY]) ?? {}, [rowKeyOf(row)]: display };
10023
+ }
10024
+ function applySocialsDisplayToRow(row, display) {
10025
+ listSocialItems(row).forEach((item) => {
10026
+ const label = socialLabelElement(item);
10027
+ const icon = item.querySelector(ICON_SELECTOR);
10028
+ if (label) label.style.display = display.text ? "" : "none";
10029
+ if (icon) icon.style.display = display.icon ? "" : "none";
10030
+ });
10031
+ }
10032
+ function applySocialsDisplayFromContent(content, root = document) {
10033
+ const stored = parseSocialsDisplay(content[SOCIALS_DISPLAY_KEY]);
10034
+ if (!stored) return;
10035
+ listSocialsRows(root).forEach((row) => {
10036
+ const display = stored[rowKeyOf(row)];
10037
+ if (!display) return;
10038
+ if (display.icon) {
10039
+ listSocialItems(row).forEach((item) => {
10040
+ const iconKey = ensureIconSlot(item);
10041
+ const slot = item.querySelector(ICON_SELECTOR);
10042
+ if (iconKey && slot && content[iconKey]) applyIconMarkup(slot, content[iconKey]);
10043
+ });
10044
+ }
10045
+ applySocialsDisplayToRow(row, display);
10046
+ });
10047
+ }
10048
+ function socialsMissingIcons(row) {
10049
+ return listSocialItems(row).filter((item) => !item.querySelector(ICON_SELECTOR)).map((item) => ({ hrefKey: socialHrefKey(item) ?? "", url: item.getAttribute("href") ?? "" })).filter((entry) => Boolean(entry.hrefKey));
10050
+ }
10051
+ function ensureIconSlot(item) {
10052
+ const existing = item.querySelector(ICON_SELECTOR);
10053
+ if (existing) return existing.dataset.ohwKey ?? null;
10054
+ const hrefKey = socialHrefKey(item);
10055
+ if (!hrefKey) return null;
10056
+ const iconKey = hrefKey.replace(/-href$/, "");
10057
+ const slot = document.createElement("span");
10058
+ slot.setAttribute("data-ohw-key", iconKey);
10059
+ slot.setAttribute("data-ohw-editable", "icon");
10060
+ slot.style.display = "inline-flex";
10061
+ item.prepend(slot);
10062
+ return iconKey;
10063
+ }
10064
+
9455
10065
  // src/lib/footer-items.ts
9456
10066
  var FOOTER_ORDER_KEY = "__ohw_footer_order";
9457
10067
  var MAX_FOOTER_COLUMNS = 18;
@@ -10296,6 +10906,329 @@ function deleteFooterColumn(column) {
10296
10906
  };
10297
10907
  }
10298
10908
 
10909
+ // src/lib/logo-identity.ts
10910
+ var LOGO_TEXT_KEYS = ["nav-logo-text", "footer-logo-text", "logo-text"];
10911
+ var LOGO_IMAGE_KEYS = ["nav-logo-image", "footer-logo", "footer-logo-image"];
10912
+ var LOGO_HREF_KEYS = ["nav-logo-href", "footer-logo-href", "logo-href"];
10913
+ var LOGO_PLACEHOLDER_KEY = "logo-is-placeholder";
10914
+ var LOGO_ALT_KEY = "logo-alt";
10915
+ var LOGO_IMAGE_URL_KEY = "nav-logo-image";
10916
+ var PLACEHOLDER_BUSINESS_NAME = "Business name";
10917
+ function resolveLogoDisplayText(text) {
10918
+ const trimmed = (text ?? "").trim();
10919
+ return trimmed || PLACEHOLDER_BUSINESS_NAME;
10920
+ }
10921
+ function isFooterLogoRoot(root) {
10922
+ return Boolean(root.closest("footer") || root.closest('[data-ohw-section="footer"]'));
10923
+ }
10924
+ function imageKeyForRoot(root) {
10925
+ return isFooterLogoRoot(root) ? "footer-logo" : "nav-logo-image";
10926
+ }
10927
+ function textKeyForRoot(root) {
10928
+ return isFooterLogoRoot(root) ? "footer-logo-text" : "nav-logo-text";
10929
+ }
10930
+ function ensureLogoHrefKey(root) {
10931
+ if (!(root instanceof HTMLAnchorElement)) return;
10932
+ if (root.hasAttribute("data-ohw-href-key")) return;
10933
+ root.setAttribute("data-ohw-href-key", isFooterLogoRoot(root) ? "footer-logo-href" : "nav-logo-href");
10934
+ }
10935
+ function applyLogoIdentity(text, isPlaceholder) {
10936
+ const display = resolveLogoDisplayText(text);
10937
+ const placeholder = isPlaceholder || !text.trim() || display === PLACEHOLDER_BUSINESS_NAME;
10938
+ for (const key of LOGO_TEXT_KEYS) {
10939
+ document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
10940
+ if (el.textContent !== display) el.textContent = display;
10941
+ });
10942
+ }
10943
+ for (const key of LOGO_IMAGE_KEYS) {
10944
+ document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
10945
+ const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
10946
+ if (img) img.alt = display;
10947
+ });
10948
+ }
10949
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((el) => {
10950
+ if (placeholder) el.setAttribute("data-ohw-placeholder", "");
10951
+ else el.removeAttribute("data-ohw-placeholder");
10952
+ });
10953
+ return display;
10954
+ }
10955
+ function applyLogoImage(url, alt) {
10956
+ const displayAlt = resolveLogoDisplayText(alt);
10957
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((root) => {
10958
+ ensureLogoHrefKey(root);
10959
+ const imageKey = imageKeyForRoot(root);
10960
+ const textKey = textKeyForRoot(root);
10961
+ let img = root.querySelector(`img[data-ohw-key="${imageKey}"]`) ?? (root.querySelector(`[data-ohw-key="${imageKey}"]`) instanceof HTMLImageElement ? root.querySelector(`[data-ohw-key="${imageKey}"]`) : null) ?? root.querySelector("img");
10962
+ let textEl = root.querySelector(`[data-ohw-key="${textKey}"]`) ?? root.querySelector('[data-ohw-key="logo-text"]');
10963
+ if (url) {
10964
+ if (!img) {
10965
+ img = document.createElement("img");
10966
+ img.setAttribute("data-ohw-editable", "image");
10967
+ img.setAttribute("data-ohw-key", imageKey);
10968
+ img.alt = displayAlt;
10969
+ img.style.height = "";
10970
+ img.style.maxHeight = "none";
10971
+ img.style.width = "auto";
10972
+ img.style.display = "block";
10973
+ img.style.objectFit = "contain";
10974
+ root.insertBefore(img, root.firstChild);
10975
+ } else {
10976
+ img.setAttribute("data-ohw-editable", "image");
10977
+ img.setAttribute("data-ohw-key", imageKey);
10978
+ }
10979
+ img.removeAttribute("srcset");
10980
+ img.removeAttribute("sizes");
10981
+ img.src = url;
10982
+ img.alt = displayAlt;
10983
+ img.style.display = "block";
10984
+ if (textEl) textEl.style.display = "none";
10985
+ root.removeAttribute("data-ohw-placeholder");
10986
+ return;
10987
+ }
10988
+ if (img) {
10989
+ img.removeAttribute("src");
10990
+ img.removeAttribute("srcset");
10991
+ img.removeAttribute("sizes");
10992
+ img.alt = displayAlt;
10993
+ img.style.display = "none";
10994
+ }
10995
+ if (!textEl) {
10996
+ textEl = document.createElement("span");
10997
+ textEl.setAttribute("data-ohw-editable", "plain");
10998
+ textEl.setAttribute("data-ohw-key", textKey);
10999
+ root.appendChild(textEl);
11000
+ }
11001
+ textEl.style.display = "";
11002
+ if (textEl.textContent !== displayAlt) textEl.textContent = displayAlt;
11003
+ if (!displayAlt.trim() || displayAlt === PLACEHOLDER_BUSINESS_NAME) {
11004
+ root.setAttribute("data-ohw-placeholder", "");
11005
+ } else {
11006
+ root.removeAttribute("data-ohw-placeholder");
11007
+ }
11008
+ });
11009
+ }
11010
+ function applyLogoHref(href) {
11011
+ const target = href.trim() || "/";
11012
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((root) => {
11013
+ ensureLogoHrefKey(root);
11014
+ if (root instanceof HTMLAnchorElement) {
11015
+ root.setAttribute("href", target);
11016
+ }
11017
+ });
11018
+ for (const key of LOGO_HREF_KEYS) setStoredLinkHref(key, target);
11019
+ }
11020
+ function readLogoIdentityFromDom() {
11021
+ let imageUrl = null;
11022
+ for (const key of LOGO_IMAGE_KEYS) {
11023
+ const el = document.querySelector(`[data-ohw-key="${key}"]`);
11024
+ const img = el instanceof HTMLImageElement ? el : el?.querySelector("img");
11025
+ const attrSrc = img?.getAttribute("src")?.trim() ?? "";
11026
+ if (attrSrc && !attrSrc.startsWith("data:") && img && img.style.display !== "none") {
11027
+ imageUrl = img.currentSrc || img.src;
11028
+ break;
11029
+ }
11030
+ }
11031
+ let text = PLACEHOLDER_BUSINESS_NAME;
11032
+ let isPlaceholder = true;
11033
+ for (const key of LOGO_TEXT_KEYS) {
11034
+ const el = document.querySelector(`[data-ohw-key="${key}"]`);
11035
+ if (el?.textContent?.trim()) {
11036
+ text = el.textContent.trim();
11037
+ const logoRoot2 = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
11038
+ isPlaceholder = logoRoot2?.hasAttribute("data-ohw-placeholder") === true || text === PLACEHOLDER_BUSINESS_NAME;
11039
+ break;
11040
+ }
11041
+ }
11042
+ if (imageUrl) {
11043
+ const logoImg = document.querySelector(
11044
+ '[data-ohw-key="nav-logo-image"], [data-ohw-key="footer-logo"]'
11045
+ );
11046
+ const alt = logoImg?.alt?.trim() || text;
11047
+ isPlaceholder = false;
11048
+ const hrefEl = document.querySelector(
11049
+ 'a[data-ohw-role="logo"], a[data-ohw-logo], [data-ohw-role="logo"]'
11050
+ );
11051
+ const href2 = (hrefEl instanceof HTMLAnchorElement ? hrefEl.getAttribute("href") : null) || hrefEl?.closest("a")?.getAttribute("href") || "/";
11052
+ return { text, isPlaceholder, imageUrl, href: href2, alt };
11053
+ }
11054
+ const logoRoot = document.querySelector('[data-ohw-role="logo"], [data-ohw-logo]');
11055
+ const href = (logoRoot instanceof HTMLAnchorElement ? logoRoot.getAttribute("href") : null) || logoRoot?.closest("a")?.getAttribute("href") || "/";
11056
+ return { text, isPlaceholder, imageUrl: null, href, alt: text };
11057
+ }
11058
+ function applyLogoFromContent(content) {
11059
+ const hasLogoIdentity = LOGO_PLACEHOLDER_KEY in content || LOGO_TEXT_KEYS.some((key) => key in content) || LOGO_IMAGE_KEYS.some((key) => key in content) || LOGO_ALT_KEY in content || LOGO_HREF_KEYS.some((key) => key in content);
11060
+ if (!hasLogoIdentity) return false;
11061
+ const logoText = content[LOGO_TEXT_KEYS[0]] ?? content[LOGO_TEXT_KEYS[1]] ?? readLogoIdentityFromDom().text;
11062
+ const logoAlt = content[LOGO_ALT_KEY] ?? logoText;
11063
+ const rawLogoImage = content[LOGO_IMAGE_URL_KEY] ?? content["footer-logo"] ?? content["footer-logo-image"] ?? null;
11064
+ const logoImageUrl = typeof rawLogoImage === "string" && rawLogoImage.trim() ? rawLogoImage.trim() : null;
11065
+ const imageExplicitlyCleared = LOGO_IMAGE_KEYS.some((key) => key in content) && !logoImageUrl;
11066
+ const logoIsPlaceholder = LOGO_PLACEHOLDER_KEY in content ? content[LOGO_PLACEHOLDER_KEY] !== "false" : !logoImageUrl && (!logoText.trim() || logoText === PLACEHOLDER_BUSINESS_NAME);
11067
+ if (logoImageUrl) {
11068
+ applyLogoImage(logoImageUrl, logoAlt);
11069
+ } else {
11070
+ if (imageExplicitlyCleared) applyLogoImage(null, logoAlt);
11071
+ applyLogoIdentity(logoText, logoIsPlaceholder);
11072
+ }
11073
+ const logoHref = content["nav-logo-href"] ?? content["footer-logo-href"] ?? content["logo-href"];
11074
+ if (typeof logoHref === "string" && logoHref.trim()) {
11075
+ applyLogoHref(logoHref);
11076
+ }
11077
+ return true;
11078
+ }
11079
+
11080
+ // src/lib/logo-size.ts
11081
+ var LOGO_SIZE_DEFAULTS = {
11082
+ navbar: 28,
11083
+ footer: 32
11084
+ };
11085
+ var LOGO_SIZE_MIN = 16;
11086
+ var LOGO_SIZE_MAX = 80;
11087
+ var LOGO_SIZE_DESKTOP_KEYS = {
11088
+ navbar: "nav-logo-size",
11089
+ footer: "footer-logo-size"
11090
+ };
11091
+ var LOGO_SIZE_MOBILE_KEYS = {
11092
+ navbar: "nav-logo-size-mobile",
11093
+ footer: "footer-logo-size-mobile"
11094
+ };
11095
+ var LOGO_SIZE_KEYS = [
11096
+ LOGO_SIZE_DESKTOP_KEYS.navbar,
11097
+ LOGO_SIZE_DESKTOP_KEYS.footer,
11098
+ LOGO_SIZE_MOBILE_KEYS.navbar,
11099
+ LOGO_SIZE_MOBILE_KEYS.footer
11100
+ ];
11101
+ function isFooterLogoRoot2(root) {
11102
+ return Boolean(root.closest("footer") || root.closest('[data-ohw-section="footer"]'));
11103
+ }
11104
+ function getLogoPlacement(root) {
11105
+ return isFooterLogoRoot2(root) ? "footer" : "navbar";
11106
+ }
11107
+ function parseLogoSizePx(raw, fallback) {
11108
+ if (raw == null || raw === "") return fallback;
11109
+ const n = Number.parseFloat(raw);
11110
+ if (!Number.isFinite(n)) return fallback;
11111
+ return Math.min(LOGO_SIZE_MAX, Math.max(LOGO_SIZE_MIN, Math.round(n)));
11112
+ }
11113
+ function isMobileLogoSizeFollowing(content, placement) {
11114
+ const raw = content[LOGO_SIZE_MOBILE_KEYS[placement]];
11115
+ return raw == null || raw.trim() === "";
11116
+ }
11117
+ function resolveDesktopLogoSize(content, placement) {
11118
+ return parseLogoSizePx(content[LOGO_SIZE_DESKTOP_KEYS[placement]], LOGO_SIZE_DEFAULTS[placement]);
11119
+ }
11120
+ function resolveMobileLogoSize(content, placement) {
11121
+ if (isMobileLogoSizeFollowing(content, placement)) {
11122
+ return resolveDesktopLogoSize(content, placement);
11123
+ }
11124
+ return parseLogoSizePx(
11125
+ content[LOGO_SIZE_MOBILE_KEYS[placement]],
11126
+ resolveDesktopLogoSize(content, placement)
11127
+ );
11128
+ }
11129
+ function setRootSizeVars(root, desktopPx, mobilePx, following) {
11130
+ root.style.setProperty("--ohw-logo-size", `${desktopPx}px`);
11131
+ if (following) {
11132
+ root.style.removeProperty("--ohw-logo-size-mobile");
11133
+ } else {
11134
+ root.style.setProperty("--ohw-logo-size-mobile", `${mobilePx}px`);
11135
+ }
11136
+ root.querySelectorAll("img").forEach((img) => {
11137
+ img.style.height = "";
11138
+ img.style.maxHeight = "none";
11139
+ img.style.width = "auto";
11140
+ img.style.objectFit = "contain";
11141
+ });
11142
+ }
11143
+ function applyLogoSizes(content) {
11144
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((root) => {
11145
+ const placement = getLogoPlacement(root);
11146
+ const desktop = resolveDesktopLogoSize(content, placement);
11147
+ const following = isMobileLogoSizeFollowing(content, placement);
11148
+ const mobile = following ? desktop : resolveMobileLogoSize(content, placement);
11149
+ setRootSizeVars(root, desktop, mobile, following);
11150
+ });
11151
+ }
11152
+ function applyLogoSizeToPlacement(placement, desktopPx, mobilePx, following) {
11153
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((root) => {
11154
+ if (getLogoPlacement(root) !== placement) return;
11155
+ setRootSizeVars(root, desktopPx, mobilePx, following);
11156
+ });
11157
+ }
11158
+ function logoHasUploadedImage(logoEl) {
11159
+ if (logoEl.hasAttribute("data-ohw-placeholder")) return false;
11160
+ const img = logoEl.querySelector('img[data-ohw-key="nav-logo-image"], img[data-ohw-key="footer-logo"], img[data-ohw-key="footer-logo-image"]') ?? logoEl.querySelector("img");
11161
+ if (!img) return false;
11162
+ const src = img.getAttribute("src")?.trim() ?? "";
11163
+ if (!src || src.startsWith("data:")) return false;
11164
+ if (img.style.display === "none") return false;
11165
+ return true;
11166
+ }
11167
+ function getLogoInteractionRect(logoEl) {
11168
+ if (logoHasUploadedImage(logoEl)) {
11169
+ const img = logoEl.querySelector('img[data-ohw-key="nav-logo-image"], img[data-ohw-key="footer-logo"], img[data-ohw-key="footer-logo-image"]') ?? logoEl.querySelector("img");
11170
+ if (img) {
11171
+ const r2 = img.getBoundingClientRect();
11172
+ if (r2.width > 0 && r2.height > 0) return r2;
11173
+ }
11174
+ }
11175
+ const text = logoEl.querySelector(
11176
+ '[data-ohw-key="nav-logo-text"], [data-ohw-key="footer-logo-text"]'
11177
+ );
11178
+ if (text) {
11179
+ const style = window.getComputedStyle(text);
11180
+ if (style.display !== "none" && style.visibility !== "hidden") {
11181
+ const r2 = text.getBoundingClientRect();
11182
+ if (r2.width > 0 && r2.height > 0) return r2;
11183
+ }
11184
+ }
11185
+ return logoEl.getBoundingClientRect();
11186
+ }
11187
+ function readLogoSizeState(content, placement) {
11188
+ const desktopPx = resolveDesktopLogoSize(content, placement);
11189
+ const mobileFollowing = isMobileLogoSizeFollowing(content, placement);
11190
+ const mobilePx = mobileFollowing ? desktopPx : resolveMobileLogoSize(content, placement);
11191
+ return { desktopPx, mobilePx, mobileFollowing };
11192
+ }
11193
+
11194
+ // src/lib/site-wide-scope.ts
11195
+ function getLogoElement(el) {
11196
+ const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
11197
+ if (marked) return marked;
11198
+ if (el.closest('[data-ohw-editable="icon"]')) return null;
11199
+ const root = el.closest("nav, [data-ohw-nav-root], footer");
11200
+ if (!root) return null;
11201
+ const anchor = el.closest("a");
11202
+ if (anchor && root.contains(anchor) && !anchor.hasAttribute("data-ohw-href-key") && !anchor.closest("[data-ohw-nav-container]") && Boolean(anchor.querySelector("img") || anchor.matches("img"))) {
11203
+ return anchor;
11204
+ }
11205
+ const img = el.matches("img") ? el : null;
11206
+ if (img && !img.closest("[data-ohw-href-key]") && !img.closest("[data-ohw-nav-container]") && (img.closest("footer") || img.closest("nav, [data-ohw-nav-root]"))) {
11207
+ return img;
11208
+ }
11209
+ return null;
11210
+ }
11211
+ function isInFooter(el) {
11212
+ if (!el) return false;
11213
+ return Boolean(el.closest("footer") || el.closest('[data-ohw-section="footer"]'));
11214
+ }
11215
+ function isSiteWideElement(el) {
11216
+ if (!el) return false;
11217
+ if (getLogoElement(el)) return true;
11218
+ if (isInFooter(el)) return true;
11219
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-root")) {
11220
+ return true;
11221
+ }
11222
+ if (el.hasAttribute("data-ohw-href-key") && el.closest("nav, [data-ohw-nav-root], [data-ohw-nav-drawer], aside")) {
11223
+ return true;
11224
+ }
11225
+ if (el.closest('[data-ohw-role="navbar-button"]')) return true;
11226
+ return false;
11227
+ }
11228
+ function isSiteWideScopeActive(args) {
11229
+ return isSiteWideElement(args.selected) || isSiteWideElement(args.hoveredItem) || isSiteWideElement(args.hoveredNavContainer) || isSiteWideElement(args.active);
11230
+ }
11231
+
10299
11232
  // src/lib/add-footer-column.ts
10300
11233
  function buildFooterColumnEditContentPatch(result) {
10301
11234
  return {
@@ -10328,41 +11261,403 @@ function addFooterColumnWithPersist({
10328
11261
  return result;
10329
11262
  }
10330
11263
 
10331
- // src/lib/item-drag-interaction.ts
10332
- function disableNativeHrefDrag(el) {
10333
- if (el.draggable) el.draggable = false;
10334
- if (el.getAttribute("draggable") !== "false") {
10335
- el.setAttribute("draggable", "false");
11264
+ // src/ui/FloatingPanel.tsx
11265
+ import {
11266
+ useCallback as useCallback5,
11267
+ useEffect as useEffect9,
11268
+ useLayoutEffect as useLayoutEffect3,
11269
+ useRef as useRef7,
11270
+ useState as useState8
11271
+ } from "react";
11272
+ import { X as X5 } from "lucide-react";
11273
+ import { jsx as jsx26, jsxs as jsxs16 } from "react/jsx-runtime";
11274
+ var PANEL_WIDTH = 256;
11275
+ var EDGE_MARGIN = 16;
11276
+ function getVisibleClip(parentScroll) {
11277
+ const left = 0;
11278
+ const right = window.innerWidth;
11279
+ if (!parentScroll) {
11280
+ return { top: 0, bottom: window.innerHeight, left, right };
10336
11281
  }
11282
+ const { iframeOffsetTop, headerH: visibleCanvasTop, canvasH } = parentScroll;
11283
+ const top = Math.max(0, visibleCanvasTop - iframeOffsetTop);
11284
+ const bottom = Math.min(window.innerHeight, visibleCanvasTop + canvasH - iframeOffsetTop);
11285
+ return { top, bottom: Math.max(top, bottom), left, right };
10337
11286
  }
10338
- function clearTextSelection() {
10339
- const sel = window.getSelection();
10340
- if (sel && !sel.isCollapsed) sel.removeAllRanges();
10341
- }
10342
- function armItemPressDrag() {
10343
- document.documentElement.setAttribute("data-ohw-footer-press-drag", "");
10344
- }
10345
- function lockItemDuringDrag() {
10346
- document.documentElement.removeAttribute("data-ohw-footer-press-drag");
10347
- document.documentElement.setAttribute("data-ohw-item-dragging", "");
10348
- clearTextSelection();
10349
- }
10350
- function unlockItemDragInteraction() {
10351
- const wasDragging = document.documentElement.hasAttribute("data-ohw-item-dragging");
10352
- document.documentElement.removeAttribute("data-ohw-footer-press-drag");
10353
- document.documentElement.removeAttribute("data-ohw-item-dragging");
10354
- if (wasDragging) clearTextSelection();
11287
+ function defaultFloatingPanelPosition(parentScroll, panelHeight = 280) {
11288
+ const clip = getVisibleClip(parentScroll);
11289
+ return {
11290
+ x: Math.max(EDGE_MARGIN, clip.right - PANEL_WIDTH - EDGE_MARGIN),
11291
+ y: Math.min(
11292
+ Math.max(clip.top + EDGE_MARGIN, EDGE_MARGIN),
11293
+ Math.max(clip.top + EDGE_MARGIN, clip.bottom - panelHeight - EDGE_MARGIN)
11294
+ )
11295
+ };
10355
11296
  }
10356
- var armFooterPressDrag = armItemPressDrag;
10357
- var lockFooterDuringDrag = lockItemDuringDrag;
10358
- var unlockFooterDragInteraction = unlockItemDragInteraction;
10359
-
10360
- // src/lib/nav-dnd.ts
10361
- function listReorderableNavItems() {
10362
- return listNavbarItems().filter((el) => {
10363
- const key = el.getAttribute("data-ohw-href-key");
10364
- return isNavbarHrefKey(key) && !isNestedNavChild(el);
10365
- });
11297
+ function clampPosition(pos, parentScroll, panelW, panelH) {
11298
+ const clip = getVisibleClip(parentScroll);
11299
+ const maxX = Math.max(clip.left + EDGE_MARGIN, clip.right - panelW - EDGE_MARGIN);
11300
+ const maxY = Math.max(clip.top + EDGE_MARGIN, clip.bottom - panelH - EDGE_MARGIN);
11301
+ return {
11302
+ x: Math.min(Math.max(pos.x, clip.left + EDGE_MARGIN), maxX),
11303
+ y: Math.min(Math.max(pos.y, clip.top + EDGE_MARGIN), maxY)
11304
+ };
11305
+ }
11306
+ function FloatingPanel({
11307
+ open,
11308
+ title,
11309
+ context,
11310
+ icon,
11311
+ onClose,
11312
+ children,
11313
+ position,
11314
+ onPositionChange,
11315
+ parentScroll = null,
11316
+ className,
11317
+ bodyClassName
11318
+ }) {
11319
+ const panelRef = useRef7(null);
11320
+ const [measured, setMeasured] = useState8({ w: PANEL_WIDTH, h: 280 });
11321
+ const dragRef = useRef7(null);
11322
+ const resolved = position ?? defaultFloatingPanelPosition(parentScroll, measured.h);
11323
+ const clamped = clampPosition(resolved, parentScroll, measured.w, measured.h);
11324
+ useLayoutEffect3(() => {
11325
+ if (!open || !panelRef.current) return;
11326
+ const el = panelRef.current;
11327
+ const next = { w: el.offsetWidth || PANEL_WIDTH, h: el.offsetHeight || 280 };
11328
+ setMeasured((prev) => prev.w === next.w && prev.h === next.h ? prev : next);
11329
+ }, [open, children, title, context]);
11330
+ useEffect9(() => {
11331
+ if (!open || !position || !onPositionChange) return;
11332
+ const next = clampPosition(position, parentScroll, measured.w, measured.h);
11333
+ if (next.x !== position.x || next.y !== position.y) onPositionChange(next);
11334
+ }, [open, parentScroll, measured.w, measured.h, position, onPositionChange]);
11335
+ const onHeaderPointerDown = useCallback5(
11336
+ (e) => {
11337
+ if (e.button !== 0) return;
11338
+ if (e.target.closest("[data-ohw-floating-panel-close]")) return;
11339
+ e.preventDefault();
11340
+ e.stopPropagation();
11341
+ const el = e.currentTarget;
11342
+ el.setPointerCapture(e.pointerId);
11343
+ dragRef.current = {
11344
+ pointerId: e.pointerId,
11345
+ startX: e.clientX,
11346
+ startY: e.clientY,
11347
+ originX: clamped.x,
11348
+ originY: clamped.y
11349
+ };
11350
+ },
11351
+ [clamped.x, clamped.y]
11352
+ );
11353
+ const onHeaderPointerMove = useCallback5(
11354
+ (e) => {
11355
+ const drag = dragRef.current;
11356
+ if (!drag || drag.pointerId !== e.pointerId) return;
11357
+ e.preventDefault();
11358
+ const next = clampPosition(
11359
+ {
11360
+ x: drag.originX + (e.clientX - drag.startX),
11361
+ y: drag.originY + (e.clientY - drag.startY)
11362
+ },
11363
+ parentScroll,
11364
+ measured.w,
11365
+ measured.h
11366
+ );
11367
+ onPositionChange?.(next);
11368
+ },
11369
+ [measured.h, measured.w, onPositionChange, parentScroll]
11370
+ );
11371
+ const endDrag = useCallback5((e) => {
11372
+ const drag = dragRef.current;
11373
+ if (!drag || drag.pointerId !== e.pointerId) return;
11374
+ dragRef.current = null;
11375
+ try {
11376
+ e.currentTarget.releasePointerCapture(e.pointerId);
11377
+ } catch {
11378
+ }
11379
+ }, []);
11380
+ if (!open) return null;
11381
+ return /* @__PURE__ */ jsxs16(
11382
+ "div",
11383
+ {
11384
+ ref: panelRef,
11385
+ "data-ohw-floating-panel": "",
11386
+ role: "dialog",
11387
+ "aria-label": title,
11388
+ className: cn(
11389
+ // Above MediaOverlay / item chrome (2147483646); link-modal content shares this tier.
11390
+ "fixed z-[2147483647] flex w-64 flex-col overflow-hidden rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
11391
+ className
11392
+ ),
11393
+ style: { left: clamped.x, top: clamped.y },
11394
+ onMouseDown: (e) => e.stopPropagation(),
11395
+ onPointerDown: (e) => e.stopPropagation(),
11396
+ onClick: (e) => e.stopPropagation(),
11397
+ children: [
11398
+ /* @__PURE__ */ jsxs16(
11399
+ "div",
11400
+ {
11401
+ "data-ohw-floating-panel-header": "",
11402
+ className: "relative flex cursor-grab items-start gap-2 border-b border-border py-5 pl-5 pr-11 active:cursor-grabbing",
11403
+ onPointerDown: onHeaderPointerDown,
11404
+ onPointerMove: onHeaderPointerMove,
11405
+ onPointerUp: endDrag,
11406
+ onPointerCancel: endDrag,
11407
+ children: [
11408
+ /* @__PURE__ */ jsxs16("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
11409
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2", children: [
11410
+ icon ? /* @__PURE__ */ jsx26("span", { className: "shrink-0 text-foreground", children: icon }) : null,
11411
+ /* @__PURE__ */ jsx26("p", { className: "min-w-0 flex-1 text-lg font-semibold leading-7 text-foreground", children: title })
11412
+ ] }),
11413
+ context ? /* @__PURE__ */ jsx26("p", { className: "w-full text-sm leading-5 text-muted-foreground", children: context }) : null
11414
+ ] }),
11415
+ /* @__PURE__ */ jsx26(
11416
+ "button",
11417
+ {
11418
+ type: "button",
11419
+ "data-ohw-floating-panel-close": "",
11420
+ "aria-label": "Close",
11421
+ className: "absolute right-2.5 top-2.5 rounded-sm p-1.5 text-foreground hover:bg-muted/50",
11422
+ onClick: (e) => {
11423
+ e.stopPropagation();
11424
+ onClose();
11425
+ },
11426
+ onPointerDown: (e) => e.stopPropagation(),
11427
+ children: /* @__PURE__ */ jsx26(X5, { size: 16, "aria-hidden": true })
11428
+ }
11429
+ )
11430
+ ]
11431
+ }
11432
+ ),
11433
+ /* @__PURE__ */ jsx26(
11434
+ "div",
11435
+ {
11436
+ "data-ohw-floating-panel-body": "",
11437
+ className: cn("flex w-full flex-col gap-4 p-5", bodyClassName),
11438
+ children
11439
+ }
11440
+ )
11441
+ ]
11442
+ }
11443
+ );
11444
+ }
11445
+
11446
+ // src/ui/logo-size-panel.tsx
11447
+ import { ArrowUpRight, Link as Link2 } from "lucide-react";
11448
+ import { jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
11449
+ function SizeSlider({
11450
+ value,
11451
+ onChange
11452
+ }) {
11453
+ const pct = (value - LOGO_SIZE_MIN) / (LOGO_SIZE_MAX - LOGO_SIZE_MIN) * 100;
11454
+ return /* @__PURE__ */ jsxs17("div", { className: "flex w-full flex-col gap-3", children: [
11455
+ /* @__PURE__ */ jsxs17("div", { className: "flex w-full items-center gap-2 text-sm font-medium leading-5", children: [
11456
+ /* @__PURE__ */ jsx27("span", { className: "min-w-0 flex-1 text-foreground", children: "Size" }),
11457
+ /* @__PURE__ */ jsxs17("span", { className: "shrink-0 whitespace-nowrap text-muted-foreground", children: [
11458
+ value,
11459
+ " px"
11460
+ ] })
11461
+ ] }),
11462
+ /* @__PURE__ */ jsxs17("div", { className: "relative h-2 w-full rounded-full bg-primary-50", children: [
11463
+ /* @__PURE__ */ jsx27(
11464
+ "div",
11465
+ {
11466
+ className: "absolute inset-y-0 left-0 rounded-full bg-primary",
11467
+ style: { width: `${pct}%` }
11468
+ }
11469
+ ),
11470
+ /* @__PURE__ */ jsx27(
11471
+ "input",
11472
+ {
11473
+ type: "range",
11474
+ min: LOGO_SIZE_MIN,
11475
+ max: LOGO_SIZE_MAX,
11476
+ step: 1,
11477
+ value,
11478
+ "aria-label": "Logo size",
11479
+ className: cn(
11480
+ "absolute inset-0 h-full w-full cursor-pointer appearance-none bg-transparent",
11481
+ "[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:size-5",
11482
+ "[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2",
11483
+ "[&::-webkit-slider-thumb]:border-primary [&::-webkit-slider-thumb]:bg-background",
11484
+ "[&::-moz-range-thumb]:size-5 [&::-moz-range-thumb]:rounded-full",
11485
+ "[&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-primary",
11486
+ "[&::-moz-range-thumb]:bg-background"
11487
+ ),
11488
+ onChange: (e) => onChange(Number(e.target.value))
11489
+ }
11490
+ )
11491
+ ] })
11492
+ ] });
11493
+ }
11494
+ function LogoSizePanel({
11495
+ viewport,
11496
+ sizePx,
11497
+ mobileFollowing = true,
11498
+ onSizeChange,
11499
+ onCustomizeMobile,
11500
+ onResetMobile,
11501
+ onUpdateEverywhere,
11502
+ className
11503
+ }) {
11504
+ const showFollowing = viewport === "mobile" && mobileFollowing;
11505
+ const showMobileSlider = viewport === "mobile" && !mobileFollowing;
11506
+ const showDesktopSlider = viewport === "desktop";
11507
+ return /* @__PURE__ */ jsxs17("div", { className: cn("flex w-full flex-col gap-4", className), children: [
11508
+ showFollowing ? /* @__PURE__ */ jsxs17("div", { className: "flex w-full flex-col gap-2", children: [
11509
+ /* @__PURE__ */ jsxs17("div", { className: "flex items-start gap-1", children: [
11510
+ /* @__PURE__ */ jsx27(Link2, { size: 16, className: "mt-0.5 shrink-0 text-foreground", "aria-hidden": true }),
11511
+ /* @__PURE__ */ jsx27("p", { className: "text-sm font-semibold leading-5 text-foreground", children: "Following desktop size" })
11512
+ ] }),
11513
+ /* @__PURE__ */ jsx27("p", { className: "text-sm leading-5 text-muted-foreground", children: "Mobile uses the desktop size until you customize it. Change the desktop size and it follows automatically." }),
11514
+ /* @__PURE__ */ jsx27(
11515
+ Button,
11516
+ {
11517
+ type: "button",
11518
+ variant: "outline",
11519
+ size: "sm",
11520
+ className: "h-9 w-full min-w-0 cursor-pointer",
11521
+ onClick: onCustomizeMobile,
11522
+ children: "Customize for mobile"
11523
+ }
11524
+ )
11525
+ ] }) : null,
11526
+ showDesktopSlider || showMobileSlider ? /* @__PURE__ */ jsx27(SizeSlider, { value: sizePx, onChange: onSizeChange }) : null,
11527
+ showMobileSlider ? /* @__PURE__ */ jsx27(
11528
+ Button,
11529
+ {
11530
+ type: "button",
11531
+ variant: "outline",
11532
+ size: "sm",
11533
+ className: "h-9 w-full min-w-0 cursor-pointer",
11534
+ onClick: onResetMobile,
11535
+ children: "Reset to desktop size"
11536
+ }
11537
+ ) : null,
11538
+ /* @__PURE__ */ jsx27("div", { className: "h-px w-full bg-border", role: "separator" }),
11539
+ /* @__PURE__ */ jsxs17(
11540
+ Button,
11541
+ {
11542
+ type: "button",
11543
+ variant: "outline",
11544
+ size: "sm",
11545
+ className: "h-9 w-full min-w-0 cursor-pointer gap-1",
11546
+ onClick: onUpdateEverywhere,
11547
+ children: [
11548
+ "Update logo everywhere",
11549
+ /* @__PURE__ */ jsx27(ArrowUpRight, { size: 16, "aria-hidden": true })
11550
+ ]
11551
+ }
11552
+ ),
11553
+ /* @__PURE__ */ jsx27("p", { className: "text-sm leading-5 text-muted-foreground", children: "Matches the right version to your background." })
11554
+ ] });
11555
+ }
11556
+
11557
+ // src/ui/socials-display-panel.tsx
11558
+ import { jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
11559
+ function DisplaySwitch({
11560
+ label,
11561
+ checked,
11562
+ disabled,
11563
+ onChange
11564
+ }) {
11565
+ return /* @__PURE__ */ jsxs18("div", { className: "flex w-full items-center gap-2", children: [
11566
+ /* @__PURE__ */ jsx28(
11567
+ "span",
11568
+ {
11569
+ className: cn(
11570
+ "min-w-0 flex-1 text-sm font-medium leading-5",
11571
+ disabled ? "text-muted-foreground" : "text-foreground"
11572
+ ),
11573
+ children: label
11574
+ }
11575
+ ),
11576
+ /* @__PURE__ */ jsx28(
11577
+ "button",
11578
+ {
11579
+ type: "button",
11580
+ role: "switch",
11581
+ "aria-checked": checked,
11582
+ "aria-label": label,
11583
+ disabled,
11584
+ onClick: () => onChange(!checked),
11585
+ className: cn(
11586
+ "relative h-5 w-9 shrink-0 rounded-full transition-colors",
11587
+ checked ? "bg-primary" : "bg-primary-50",
11588
+ disabled ? "cursor-default opacity-50" : "cursor-pointer"
11589
+ ),
11590
+ children: /* @__PURE__ */ jsx28(
11591
+ "span",
11592
+ {
11593
+ className: cn(
11594
+ "absolute top-0.5 h-4 w-4 rounded-full bg-white transition-all",
11595
+ checked ? "left-[1.125rem]" : "left-0.5"
11596
+ )
11597
+ }
11598
+ )
11599
+ }
11600
+ )
11601
+ ] });
11602
+ }
11603
+ function SocialsDisplayPanel({ display, onChange, className }) {
11604
+ return /* @__PURE__ */ jsxs18("div", { className: cn("flex w-full flex-col gap-3", className), children: [
11605
+ /* @__PURE__ */ jsx28(
11606
+ DisplaySwitch,
11607
+ {
11608
+ label: "Text",
11609
+ checked: display.text,
11610
+ disabled: display.text && !display.icon,
11611
+ onChange: (text) => onChange({ ...display, text })
11612
+ }
11613
+ ),
11614
+ /* @__PURE__ */ jsx28(
11615
+ DisplaySwitch,
11616
+ {
11617
+ label: "Icon",
11618
+ checked: display.icon,
11619
+ disabled: display.icon && !display.text,
11620
+ onChange: (icon) => onChange({ ...display, icon })
11621
+ }
11622
+ )
11623
+ ] });
11624
+ }
11625
+
11626
+ // src/lib/item-drag-interaction.ts
11627
+ function disableNativeHrefDrag(el) {
11628
+ if (el.draggable) el.draggable = false;
11629
+ if (el.getAttribute("draggable") !== "false") {
11630
+ el.setAttribute("draggable", "false");
11631
+ }
11632
+ }
11633
+ function clearTextSelection() {
11634
+ const sel = window.getSelection();
11635
+ if (sel && !sel.isCollapsed) sel.removeAllRanges();
11636
+ }
11637
+ function armItemPressDrag() {
11638
+ document.documentElement.setAttribute("data-ohw-footer-press-drag", "");
11639
+ }
11640
+ function lockItemDuringDrag() {
11641
+ document.documentElement.removeAttribute("data-ohw-footer-press-drag");
11642
+ document.documentElement.setAttribute("data-ohw-item-dragging", "");
11643
+ clearTextSelection();
11644
+ }
11645
+ function unlockItemDragInteraction() {
11646
+ const wasDragging = document.documentElement.hasAttribute("data-ohw-item-dragging");
11647
+ document.documentElement.removeAttribute("data-ohw-footer-press-drag");
11648
+ document.documentElement.removeAttribute("data-ohw-item-dragging");
11649
+ if (wasDragging) clearTextSelection();
11650
+ }
11651
+ var armFooterPressDrag = armItemPressDrag;
11652
+ var lockFooterDuringDrag = lockItemDuringDrag;
11653
+ var unlockFooterDragInteraction = unlockItemDragInteraction;
11654
+
11655
+ // src/lib/nav-dnd.ts
11656
+ function listReorderableNavItems() {
11657
+ return listNavbarItems().filter((el) => {
11658
+ const key = el.getAttribute("data-ohw-href-key");
11659
+ return isNavbarHrefKey(key) && !isNestedNavChild(el);
11660
+ });
10366
11661
  }
10367
11662
  function resolveParentNavHrefKey(child) {
10368
11663
  const childrenRoot = child.closest("[data-ohw-nav-children]");
@@ -10526,7 +11821,7 @@ function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
10526
11821
  }
10527
11822
 
10528
11823
  // src/useNavItemDrag.ts
10529
- import { useCallback as useCallback5, useEffect as useEffect9, useRef as useRef7, useState as useState8 } from "react";
11824
+ import { useCallback as useCallback6, useEffect as useEffect10, useRef as useRef8, useState as useState9 } from "react";
10530
11825
  function useNavItemDrag({
10531
11826
  isEditMode,
10532
11827
  editContentRef,
@@ -10550,11 +11845,11 @@ function useNavItemDrag({
10550
11845
  getNavigationItemAnchor: getNavigationItemAnchor2,
10551
11846
  isDragHandleDisabled: isDragHandleDisabled2
10552
11847
  }) {
10553
- const navDragRef = useRef7(null);
10554
- const [navDropSlots, setNavDropSlots] = useState8([]);
10555
- const [activeNavDropIndex, setActiveNavDropIndex] = useState8(null);
10556
- const navPointerDragRef = useRef7(null);
10557
- const clearNavDragVisuals = useCallback5(() => {
11848
+ const navDragRef = useRef8(null);
11849
+ const [navDropSlots, setNavDropSlots] = useState9([]);
11850
+ const [activeNavDropIndex, setActiveNavDropIndex] = useState9(null);
11851
+ const navPointerDragRef = useRef8(null);
11852
+ const clearNavDragVisuals = useCallback6(() => {
10558
11853
  const session = navDragRef.current;
10559
11854
  const keepOpenEl = session?.draggedEl?.closest("[data-ohw-nav-children]") != null ? session.draggedEl : null;
10560
11855
  navDragRef.current = null;
@@ -10571,7 +11866,7 @@ function useNavItemDrag({
10571
11866
  document.documentElement.removeAttribute("data-ohw-nav-dragging-root");
10572
11867
  unlockItemDragInteraction();
10573
11868
  }, [setDraggedItemRect, setIsItemDragging, setSiblingHintRects]);
10574
- const refreshNavDragVisuals = useCallback5(
11869
+ const refreshNavDragVisuals = useCallback6(
10575
11870
  (session, activeSlot, clientX, clientY) => {
10576
11871
  setDraggedItemRect(session.draggedEl.getBoundingClientRect());
10577
11872
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -10589,13 +11884,13 @@ function useNavItemDrag({
10589
11884
  },
10590
11885
  [setDraggedItemRect, setSiblingHintRects]
10591
11886
  );
10592
- const refreshNavDragVisualsRef = useRef7(refreshNavDragVisuals);
11887
+ const refreshNavDragVisualsRef = useRef8(refreshNavDragVisuals);
10593
11888
  refreshNavDragVisualsRef.current = refreshNavDragVisuals;
10594
- const commitNavDragRef = useRef7(() => {
11889
+ const commitNavDragRef = useRef8(() => {
10595
11890
  });
10596
- const beginNavDragRef = useRef7(() => {
11891
+ const beginNavDragRef = useRef8(() => {
10597
11892
  });
10598
- const beginNavDrag = useCallback5(
11893
+ const beginNavDrag = useCallback6(
10599
11894
  (session) => {
10600
11895
  const rect = session.draggedEl.getBoundingClientRect();
10601
11896
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -10629,7 +11924,7 @@ function useNavItemDrag({
10629
11924
  ]
10630
11925
  );
10631
11926
  beginNavDragRef.current = beginNavDrag;
10632
- const commitNavDrag = useCallback5(
11927
+ const commitNavDrag = useCallback6(
10633
11928
  (clientX, clientY) => {
10634
11929
  const session = navDragRef.current;
10635
11930
  if (!session) {
@@ -10690,7 +11985,7 @@ function useNavItemDrag({
10690
11985
  [clearNavDragVisuals, deselectRef, editContentRef, postToParentRef, selectRef]
10691
11986
  );
10692
11987
  commitNavDragRef.current = commitNavDrag;
10693
- const startNavLinkDrag = useCallback5(
11988
+ const startNavLinkDrag = useCallback6(
10694
11989
  (anchor, clientX, clientY, wasSelected) => {
10695
11990
  if (footerDragRef.current) return false;
10696
11991
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
@@ -10708,7 +12003,7 @@ function useNavItemDrag({
10708
12003
  },
10709
12004
  [beginNavDrag, footerDragRef, isDragHandleDisabled2, isCtaButton]
10710
12005
  );
10711
- const onNavDragOver = useCallback5(
12006
+ const onNavDragOver = useCallback6(
10712
12007
  (e) => {
10713
12008
  const session = navDragRef.current;
10714
12009
  if (!session) return false;
@@ -10720,7 +12015,7 @@ function useNavItemDrag({
10720
12015
  },
10721
12016
  []
10722
12017
  );
10723
- useEffect9(() => {
12018
+ useEffect10(() => {
10724
12019
  if (!isEditMode) return;
10725
12020
  const THRESHOLD = 10;
10726
12021
  const resolveWasSelected = (el) => {
@@ -10845,7 +12140,7 @@ function useNavItemDrag({
10845
12140
  setLinkPopover,
10846
12141
  suppressNextClickRef
10847
12142
  ]);
10848
- const armNavPressFromChrome = useCallback5(
12143
+ const armNavPressFromChrome = useCallback6(
10849
12144
  (selected, clientX, clientY, pointerId) => {
10850
12145
  const hrefKey = selected.getAttribute("data-ohw-href-key");
10851
12146
  if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
@@ -10877,7 +12172,7 @@ function useNavItemDrag({
10877
12172
 
10878
12173
  // src/ui/footer-container-chrome.tsx
10879
12174
  import { Plus as Plus2 } from "lucide-react";
10880
- import { jsx as jsx26, jsxs as jsxs16 } from "react/jsx-runtime";
12175
+ import { jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
10881
12176
  function FooterContainerChrome({
10882
12177
  rect,
10883
12178
  onAdd,
@@ -10885,7 +12180,7 @@ function FooterContainerChrome({
10885
12180
  }) {
10886
12181
  const chromeGap = 6;
10887
12182
  const buttonMargin = 7;
10888
- return /* @__PURE__ */ jsx26(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx26(
12183
+ return /* @__PURE__ */ jsx29(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx29(
10889
12184
  "div",
10890
12185
  {
10891
12186
  "data-ohw-footer-container-chrome": "",
@@ -10897,8 +12192,8 @@ function FooterContainerChrome({
10897
12192
  width: rect.width + chromeGap * 2,
10898
12193
  height: rect.height + chromeGap * 2
10899
12194
  },
10900
- children: /* @__PURE__ */ jsxs16(Tooltip, { children: [
10901
- /* @__PURE__ */ jsx26(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx26(
12195
+ children: /* @__PURE__ */ jsxs19(Tooltip, { children: [
12196
+ /* @__PURE__ */ jsx29(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx29(
10902
12197
  "button",
10903
12198
  {
10904
12199
  type: "button",
@@ -10917,17 +12212,17 @@ function FooterContainerChrome({
10917
12212
  if (addDisabled) return;
10918
12213
  onAdd();
10919
12214
  },
10920
- children: /* @__PURE__ */ jsx26(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
12215
+ children: /* @__PURE__ */ jsx29(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
10921
12216
  }
10922
12217
  ) }),
10923
- /* @__PURE__ */ jsx26(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
12218
+ /* @__PURE__ */ jsx29(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
10924
12219
  ] })
10925
12220
  }
10926
12221
  ) });
10927
12222
  }
10928
12223
 
10929
12224
  // src/lib/carousel.ts
10930
- import { useEffect as useEffect10, useState as useState9 } from "react";
12225
+ import { useEffect as useEffect11, useState as useState10 } from "react";
10931
12226
  var CAROUSEL_ATTR = "data-ohw-carousel";
10932
12227
  var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
10933
12228
  var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
@@ -10989,8 +12284,8 @@ function applyCarouselNode(key, val) {
10989
12284
  return true;
10990
12285
  }
10991
12286
  function useOhwCarousel(key, initial) {
10992
- const [images, setImages] = useState9(initial);
10993
- useEffect10(() => {
12287
+ const [images, setImages] = useState10(initial);
12288
+ useEffect11(() => {
10994
12289
  const el = document.querySelector(
10995
12290
  `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
10996
12291
  );
@@ -11103,6 +12398,18 @@ function collectEditableNodes(extraContent, root = document) {
11103
12398
  }
11104
12399
  if (extraContent && !isScoped) {
11105
12400
  applyNavFooterDeleteOverrides(byKey, extraContent);
12401
+ for (const key of LOGO_IMAGE_KEYS) {
12402
+ if (!(key in extraContent)) continue;
12403
+ byKey.set(key, { key, type: "image", text: extraContent[key] ?? "" });
12404
+ }
12405
+ for (const key of [LOGO_PLACEHOLDER_KEY, LOGO_ALT_KEY]) {
12406
+ if (!(key in extraContent)) continue;
12407
+ byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
12408
+ }
12409
+ for (const key of LOGO_SIZE_KEYS) {
12410
+ if (!(key in extraContent)) continue;
12411
+ byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
12412
+ }
11106
12413
  }
11107
12414
  return Array.from(byKey.values());
11108
12415
  }
@@ -11205,7 +12512,7 @@ function isNavbarLinksContainer(el) {
11205
12512
  function isNavigationItem(el) {
11206
12513
  const anchor = el.matches("[data-ohw-href-key]") ? el : el.closest("[data-ohw-href-key]");
11207
12514
  if (!anchor) return false;
11208
- return Boolean(anchor.querySelector('[data-ohw-editable="text"]'));
12515
+ return Boolean(anchor.querySelector('[data-ohw-editable="text"]')) || Boolean(getSocialItem(anchor));
11209
12516
  }
11210
12517
  function findFooterItemGroup(item) {
11211
12518
  const explicit = item.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
@@ -11226,8 +12533,9 @@ function isInferredFooterGroup(el) {
11226
12533
  const footer = el.closest("footer");
11227
12534
  if (!footer || el === footer) return false;
11228
12535
  if (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column")) return true;
12536
+ if (isSocialsRow(el)) return false;
11229
12537
  const count = Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(
11230
- isNavigationItem
12538
+ (item) => isNavigationItem(item) && !getSocialItem(item)
11231
12539
  ).length;
11232
12540
  return count >= 2;
11233
12541
  }
@@ -11271,7 +12579,8 @@ function deleteSelectedNavFooterItem(deps) {
11271
12579
  if (key.endsWith("-href")) applyLinkByKey2(key, text);
11272
12580
  else {
11273
12581
  document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`).forEach((el) => {
11274
- el.textContent = text;
12582
+ if (el.getAttribute("data-ohw-editable") === "icon") applyIconMarkup(el, text);
12583
+ else el.textContent = text;
11275
12584
  });
11276
12585
  }
11277
12586
  }
@@ -11333,6 +12642,21 @@ function deleteSelectedNavFooterItem(deps) {
11333
12642
  });
11334
12643
  return true;
11335
12644
  }
12645
+ const social = getSocialItem(selected);
12646
+ if (social) {
12647
+ const result = removeSocialItem(social, getEditContent());
12648
+ if (!result) return false;
12649
+ finishDelete({
12650
+ toastTitle: "Social deleted",
12651
+ removedKeys: result.removedKeys,
12652
+ previousContent: result.previousContent,
12653
+ orderKey: SOCIALS_ORDER_KEY,
12654
+ orderJson: JSON.stringify(result.order),
12655
+ previousOrderJson: JSON.stringify(result.previousOrder),
12656
+ undoDom: result.undo
12657
+ });
12658
+ return true;
12659
+ }
11336
12660
  if (isFooterHrefKey(hrefKey)) {
11337
12661
  const result = deleteFooterItem(selected);
11338
12662
  if (!result) return false;
@@ -11352,13 +12676,13 @@ function deleteSelectedNavFooterItem(deps) {
11352
12676
 
11353
12677
  // src/ui/navbar-container-chrome.tsx
11354
12678
  import { Plus as Plus3 } from "lucide-react";
11355
- import { jsx as jsx27 } from "react/jsx-runtime";
12679
+ import { jsx as jsx30 } from "react/jsx-runtime";
11356
12680
  function NavbarContainerChrome({
11357
12681
  rect,
11358
12682
  onAdd
11359
12683
  }) {
11360
12684
  const chromeGap = 6;
11361
- return /* @__PURE__ */ jsx27(
12685
+ return /* @__PURE__ */ jsx30(
11362
12686
  "div",
11363
12687
  {
11364
12688
  "data-ohw-navbar-container-chrome": "",
@@ -11370,7 +12694,7 @@ function NavbarContainerChrome({
11370
12694
  width: rect.width + chromeGap * 2,
11371
12695
  height: rect.height + chromeGap * 2
11372
12696
  },
11373
- children: /* @__PURE__ */ jsx27(
12697
+ children: /* @__PURE__ */ jsx30(
11374
12698
  "button",
11375
12699
  {
11376
12700
  type: "button",
@@ -11387,7 +12711,7 @@ function NavbarContainerChrome({
11387
12711
  e.stopPropagation();
11388
12712
  onAdd();
11389
12713
  },
11390
- children: /* @__PURE__ */ jsx27(Plus3, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
12714
+ children: /* @__PURE__ */ jsx30(Plus3, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
11391
12715
  }
11392
12716
  )
11393
12717
  }
@@ -11396,7 +12720,7 @@ function NavbarContainerChrome({
11396
12720
 
11397
12721
  // src/ui/drop-indicator.tsx
11398
12722
  import * as React10 from "react";
11399
- import { jsx as jsx28 } from "react/jsx-runtime";
12723
+ import { jsx as jsx31 } from "react/jsx-runtime";
11400
12724
  var dropIndicatorVariants = cva(
11401
12725
  "ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
11402
12726
  {
@@ -11420,7 +12744,7 @@ var dropIndicatorVariants = cva(
11420
12744
  );
11421
12745
  var DropIndicator = React10.forwardRef(
11422
12746
  ({ className, direction, state, ...props }, ref) => {
11423
- return /* @__PURE__ */ jsx28(
12747
+ return /* @__PURE__ */ jsx31(
11424
12748
  "div",
11425
12749
  {
11426
12750
  ref,
@@ -11437,7 +12761,7 @@ var DropIndicator = React10.forwardRef(
11437
12761
  DropIndicator.displayName = "DropIndicator";
11438
12762
 
11439
12763
  // src/ui/badge.tsx
11440
- import { jsx as jsx29 } from "react/jsx-runtime";
12764
+ import { jsx as jsx32 } from "react/jsx-runtime";
11441
12765
  var badgeVariants = cva(
11442
12766
  "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
11443
12767
  {
@@ -11455,12 +12779,12 @@ var badgeVariants = cva(
11455
12779
  }
11456
12780
  );
11457
12781
  function Badge({ className, variant, ...props }) {
11458
- return /* @__PURE__ */ jsx29("div", { className: cn(badgeVariants({ variant }), className), ...props });
12782
+ return /* @__PURE__ */ jsx32("div", { className: cn(badgeVariants({ variant }), className), ...props });
11459
12783
  }
11460
12784
 
11461
12785
  // src/OhhwellsBridge.tsx
11462
- import { Link as Link2 } from "lucide-react";
11463
- import { Fragment as Fragment8, jsx as jsx30, jsxs as jsxs17 } from "react/jsx-runtime";
12786
+ import { Link as Link3 } from "lucide-react";
12787
+ import { Fragment as Fragment8, jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
11464
12788
  var PRIMARY3 = "#0885FE";
11465
12789
  var IMAGE_FADE_MS = 300;
11466
12790
  function runOpacityFade(el, onDone) {
@@ -11554,21 +12878,10 @@ function parseSchedulingInsertAfter(insertAfter) {
11554
12878
  insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
11555
12879
  };
11556
12880
  }
11557
- function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
11558
- const parsed = parseSchedulingInsertAfter(insertAfter);
11559
- const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
11560
- const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
11561
- return { effectiveInsertAfter, insertBefore };
11562
- }
11563
- function getSchedulingMountPoint(insertAfter) {
11564
- const { anchor } = parseSchedulingInsertAfter(insertAfter);
11565
- let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
11566
- if (!anchorEl && anchor === "scheduling") {
11567
- const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
11568
- anchorEl = widgets.at(-1) ?? null;
11569
- }
11570
- if (!anchorEl) return null;
11571
- return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
12881
+ function resolveEntryAnchor(entry) {
12882
+ if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
12883
+ const parsed = parseSchedulingInsertAfter(entry.insertAfter);
12884
+ return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
11572
12885
  }
11573
12886
  function schedulingMountDepth(insertAfter) {
11574
12887
  if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
@@ -11585,8 +12898,7 @@ function getPageSchedulingEntries(raw) {
11585
12898
  }
11586
12899
  }
11587
12900
  function isSchedulingWidgetMissing(entry) {
11588
- const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
11589
- return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
12901
+ return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
11590
12902
  }
11591
12903
  function hasMissingSchedulingWidgets(entries) {
11592
12904
  return entries.some(isSchedulingWidgetMissing);
@@ -11616,16 +12928,17 @@ function initSectionsFromContent(content, removeExisting = false) {
11616
12928
  } catch {
11617
12929
  }
11618
12930
  }
11619
- function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
11620
- const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
11621
- const sectionId = schedulingSectionId(effectiveInsertAfter);
12931
+ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
12932
+ const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
12933
+ const sectionId = schedulingSectionId(widgetId);
11622
12934
  if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
11623
- const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
11624
- if (!mountPoint) return false;
12935
+ const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
12936
+ if (!anchorEl) return false;
12937
+ const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
11625
12938
  const container = document.createElement("div");
11626
12939
  container.dataset.ohwSectionContainer = "scheduling";
11627
- if (insertBefore) {
11628
- const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
12940
+ if (beforeId) {
12941
+ const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
11629
12942
  const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
11630
12943
  if (!beforePoint) return false;
11631
12944
  beforePoint.insertAdjacentElement("beforebegin", container);
@@ -11636,19 +12949,25 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
11636
12949
  }
11637
12950
  tail.insertAdjacentElement("afterend", container);
11638
12951
  }
11639
- const root = createRoot2(container);
11640
- flushSync2(() => {
11641
- root.render(
11642
- /* @__PURE__ */ jsx30(
11643
- SchedulingWidget,
11644
- {
11645
- notifyOnConnect,
11646
- initialScheduleId: scheduleId,
11647
- insertAfter: effectiveInsertAfter
11648
- }
11649
- )
11650
- );
11651
- });
12952
+ try {
12953
+ const root = createRoot2(container);
12954
+ flushSync2(() => {
12955
+ root.render(
12956
+ /* @__PURE__ */ jsx33(
12957
+ SchedulingWidget,
12958
+ {
12959
+ notifyOnConnect,
12960
+ initialScheduleId: scheduleId,
12961
+ insertAfter: widgetId
12962
+ }
12963
+ )
12964
+ );
12965
+ });
12966
+ } catch (err) {
12967
+ console.error("[ow:scheduling] render threw", err);
12968
+ container.remove();
12969
+ return false;
12970
+ }
11652
12971
  const tracker = getSectionsTracker();
11653
12972
  let sections = [];
11654
12973
  try {
@@ -11656,10 +12975,12 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
11656
12975
  } catch {
11657
12976
  }
11658
12977
  const inEditor = typeof window !== "undefined" && window.self !== window.top;
11659
- if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
12978
+ if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
11660
12979
  sections.push({
11661
12980
  type: "scheduling",
11662
- insertAfter: effectiveInsertAfter,
12981
+ insertAfter: widgetId,
12982
+ anchorId,
12983
+ beforeId: beforeId ?? null,
11663
12984
  pagePath: window.location.pathname,
11664
12985
  ...scheduleId ? { scheduleId } : {}
11665
12986
  });
@@ -11673,7 +12994,8 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
11673
12994
  for (let i = pending.length - 1; i >= 0; i--) {
11674
12995
  const entry = pending[i];
11675
12996
  const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
11676
- if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId)) {
12997
+ const { anchorId, beforeId } = resolveEntryAnchor(entry);
12998
+ if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
11677
12999
  pending.splice(i, 1);
11678
13000
  }
11679
13001
  }
@@ -11687,6 +13009,17 @@ function applyLinkHref(el, val) {
11687
13009
  const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
11688
13010
  if (anchor) anchor.setAttribute("href", val);
11689
13011
  }
13012
+ function currentIconRef(el) {
13013
+ const uploaded = el instanceof HTMLImageElement ? el : el.querySelector("img");
13014
+ if (uploaded?.getAttribute("src")) {
13015
+ return uploaded.getAttribute("src") ?? "";
13016
+ }
13017
+ const svg = el instanceof SVGElement ? el : el.querySelector("svg");
13018
+ const named = Array.from(svg?.classList ?? []).find(
13019
+ (c) => c.startsWith("lucide-") && c !== "lucide-icon"
13020
+ );
13021
+ return named ? `lucide:${named.slice("lucide-".length)}` : "";
13022
+ }
11690
13023
  function getEditMeasureEl(editable) {
11691
13024
  return editable.closest("[data-ohw-href-key]") ?? editable;
11692
13025
  }
@@ -11731,8 +13064,11 @@ function isMediaEditable(el) {
11731
13064
  const t = el.dataset.ohwEditable;
11732
13065
  return t === "image" || t === "bg-image" || t === "video";
11733
13066
  }
13067
+ function isIconEditable(el) {
13068
+ return el.dataset.ohwEditable === "icon";
13069
+ }
11734
13070
  var MEDIA_SELECTOR = '[data-ohw-editable="image"], [data-ohw-editable="bg-image"], [data-ohw-editable="video"]';
11735
- var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"])';
13071
+ var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]):not([data-ohw-editable="icon"])';
11736
13072
  function getVideoEl2(el) {
11737
13073
  return el instanceof HTMLVideoElement ? el : el.querySelector("video");
11738
13074
  }
@@ -11803,6 +13139,13 @@ function isInsideLinkEditor(target) {
11803
13139
  target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest("[data-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest("[data-ohw-more-menu]") || target.closest('[data-slot="dropdown-menu-content"]') || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
11804
13140
  );
11805
13141
  }
13142
+ function isInsideFloatingPanel(target) {
13143
+ return Boolean(target.closest("[data-ohw-floating-panel]"));
13144
+ }
13145
+ function isPointOverFloatingPanel(clientX, clientY) {
13146
+ const el = document.elementFromPoint(clientX, clientY);
13147
+ return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
13148
+ }
11806
13149
  function getHrefKeyFromElement(el) {
11807
13150
  if (!el) return null;
11808
13151
  const anchor = el.closest("[data-ohw-href-key]");
@@ -11850,13 +13193,29 @@ function isNavItemPointerTarget(el) {
11850
13193
  function getNavigationItemAnchor(el) {
11851
13194
  const anchor = el.matches("[data-ohw-href-key]") ? el : el.closest("[data-ohw-href-key]");
11852
13195
  if (!anchor) return null;
11853
- if (!anchor.querySelector('[data-ohw-editable="text"]')) return null;
13196
+ if (!anchor.querySelector('[data-ohw-editable="text"]') && !getSocialItem(anchor)) return null;
11854
13197
  if (!isNavItemPointerTarget(anchor)) return null;
11855
13198
  return anchor;
11856
13199
  }
11857
13200
  function isNavigationItem2(el) {
11858
13201
  return getNavigationItemAnchor(el) !== null;
11859
13202
  }
13203
+ function requestSocialDialog(anchor, post, content) {
13204
+ const item = getSocialItem(anchor);
13205
+ if (!item) return false;
13206
+ const iconKey = item.querySelector('[data-ohw-editable="icon"]')?.dataset.ohwKey ?? "";
13207
+ post({
13208
+ type: "ow:social-pick",
13209
+ hrefKey: item.getAttribute("data-ohw-href-key") ?? "",
13210
+ iconKey,
13211
+ url: getLinkHref4(item),
13212
+ iconStyle: detectIconStyle(item),
13213
+ // What was chosen last time. Guessing from the address instead reads as "Website" for anything
13214
+ // unrecognised, and for an item with no address at all — so a deliberate choice looked lost.
13215
+ platformId: content[socialPlatformKey(iconKey)] ?? ""
13216
+ });
13217
+ return true;
13218
+ }
11860
13219
  function listNavigationItems() {
11861
13220
  return Array.from(
11862
13221
  document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
@@ -11891,7 +13250,7 @@ function getNavigationRoot(el) {
11891
13250
  return el.closest("nav, footer, aside");
11892
13251
  }
11893
13252
  function countFooterNavItems(el) {
11894
- return Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(isNavigationItem2).length;
13253
+ return Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter((item) => isNavigationItem2(item) && !getSocialItem(item)).length;
11895
13254
  }
11896
13255
  function findFooterItemGroup2(item) {
11897
13256
  const explicit = item.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
@@ -11912,10 +13271,11 @@ function isInferredFooterGroup2(el) {
11912
13271
  const footer = el.closest("footer");
11913
13272
  if (!footer || el === footer) return false;
11914
13273
  if (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column")) return true;
13274
+ if (isSocialsRow(el)) return false;
11915
13275
  return countFooterNavItems(el) >= 2;
11916
13276
  }
11917
13277
  function isNavigationContainer(el) {
11918
- return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el) || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup2(el);
13278
+ return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el) || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isSocialsRow(el) || isInferredFooterGroup2(el);
11919
13279
  }
11920
13280
  function isNavbarLinksContainer2(el) {
11921
13281
  return el.hasAttribute("data-ohw-nav-container");
@@ -11998,6 +13358,8 @@ function resolveNavContainerSelectionTarget(target, clientX, clientY) {
11998
13358
  return null;
11999
13359
  }
12000
13360
  function getNavigationSelectionParent(el) {
13361
+ const socialsRow = findSocialsRow(el);
13362
+ if (socialsRow) return socialsRow;
12001
13363
  if (isNavigationItem2(el)) {
12002
13364
  const childrenRoot = el.closest("[data-ohw-nav-children]");
12003
13365
  if (childrenRoot) {
@@ -12016,13 +13378,17 @@ function getNavigationSelectionParent(el) {
12016
13378
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
12017
13379
  return getFooterLinksContainer();
12018
13380
  }
12019
- if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
13381
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup2(el)) {
12020
13382
  return getNavigationRoot(el);
12021
13383
  }
12022
13384
  return null;
12023
13385
  }
12024
13386
  function collectNavigationItemSiblingHintRects(selected) {
12025
13387
  if (!isNavigationItem2(selected)) return [];
13388
+ const socialsRow = findSocialsRow(selected);
13389
+ if (socialsRow) {
13390
+ return listSocialItems(socialsRow).filter((item) => item !== selected).map((item) => item.getBoundingClientRect());
13391
+ }
12026
13392
  const footerColumn = getFooterColumn(selected);
12027
13393
  if (footerColumn) {
12028
13394
  return listFooterLinksInColumn(footerColumn).filter((link) => link !== selected).map((link) => link.getBoundingClientRect());
@@ -12255,7 +13621,7 @@ function EditGlowChrome({
12255
13621
  hideHandle = false
12256
13622
  }) {
12257
13623
  const GAP = SELECTION_CHROME_GAP2;
12258
- return /* @__PURE__ */ jsxs17(
13624
+ return /* @__PURE__ */ jsxs20(
12259
13625
  "div",
12260
13626
  {
12261
13627
  ref: elRef,
@@ -12270,7 +13636,7 @@ function EditGlowChrome({
12270
13636
  zIndex: 2147483646
12271
13637
  },
12272
13638
  children: [
12273
- /* @__PURE__ */ jsx30(
13639
+ /* @__PURE__ */ jsx33(
12274
13640
  "div",
12275
13641
  {
12276
13642
  style: {
@@ -12283,7 +13649,7 @@ function EditGlowChrome({
12283
13649
  }
12284
13650
  }
12285
13651
  ),
12286
- reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx30(
13652
+ reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx33(
12287
13653
  "div",
12288
13654
  {
12289
13655
  "data-ohw-drag-handle-container": "",
@@ -12295,7 +13661,7 @@ function EditGlowChrome({
12295
13661
  transform: "translate(calc(-100% - 7px), -50%)",
12296
13662
  pointerEvents: dragDisabled ? "none" : "auto"
12297
13663
  },
12298
- children: /* @__PURE__ */ jsx30(
13664
+ children: /* @__PURE__ */ jsx33(
12299
13665
  DragHandle,
12300
13666
  {
12301
13667
  "aria-label": `Reorder ${reorderHrefKey}`,
@@ -12505,7 +13871,7 @@ function FloatingToolbar({
12505
13871
  return () => ro.disconnect();
12506
13872
  }, [showEditLink, activeCommands]);
12507
13873
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
12508
- return /* @__PURE__ */ jsx30(
13874
+ return /* @__PURE__ */ jsx33(
12509
13875
  "div",
12510
13876
  {
12511
13877
  ref: setRefs,
@@ -12517,12 +13883,12 @@ function FloatingToolbar({
12517
13883
  zIndex: 2147483647,
12518
13884
  pointerEvents: "auto"
12519
13885
  },
12520
- children: /* @__PURE__ */ jsxs17(CustomToolbar, { children: [
12521
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs17(React11.Fragment, { children: [
12522
- gi > 0 && /* @__PURE__ */ jsx30(CustomToolbarDivider, {}),
13886
+ children: /* @__PURE__ */ jsxs20(CustomToolbar, { children: [
13887
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs20(React11.Fragment, { children: [
13888
+ gi > 0 && /* @__PURE__ */ jsx33(CustomToolbarDivider, {}),
12523
13889
  btns.map((btn) => {
12524
13890
  const isActive = activeCommands.has(btn.cmd);
12525
- return /* @__PURE__ */ jsx30(
13891
+ return /* @__PURE__ */ jsx33(
12526
13892
  CustomToolbarButton,
12527
13893
  {
12528
13894
  title: btn.title,
@@ -12531,7 +13897,7 @@ function FloatingToolbar({
12531
13897
  e.preventDefault();
12532
13898
  onCommand(btn.cmd);
12533
13899
  },
12534
- children: /* @__PURE__ */ jsx30(
13900
+ children: /* @__PURE__ */ jsx33(
12535
13901
  "svg",
12536
13902
  {
12537
13903
  width: "16",
@@ -12552,7 +13918,7 @@ function FloatingToolbar({
12552
13918
  );
12553
13919
  })
12554
13920
  ] }, gi)),
12555
- showEditLink ? /* @__PURE__ */ jsx30(
13921
+ showEditLink ? /* @__PURE__ */ jsx33(
12556
13922
  CustomToolbarButton,
12557
13923
  {
12558
13924
  type: "button",
@@ -12566,7 +13932,7 @@ function FloatingToolbar({
12566
13932
  e.preventDefault();
12567
13933
  e.stopPropagation();
12568
13934
  },
12569
- children: /* @__PURE__ */ jsx30(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
13935
+ children: /* @__PURE__ */ jsx33(Link3, { className: "size-4 shrink-0", "aria-hidden": true })
12570
13936
  }
12571
13937
  ) : null
12572
13938
  ] })
@@ -12583,7 +13949,7 @@ function StateToggle({
12583
13949
  states,
12584
13950
  onStateChange
12585
13951
  }) {
12586
- return /* @__PURE__ */ jsx30(
13952
+ return /* @__PURE__ */ jsx33(
12587
13953
  ToggleGroup,
12588
13954
  {
12589
13955
  "data-ohw-state-toggle": "",
@@ -12597,11 +13963,12 @@ function StateToggle({
12597
13963
  left: rect.right - 8,
12598
13964
  transform: "translateX(-100%)"
12599
13965
  },
12600
- children: states.map((state) => /* @__PURE__ */ jsx30(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
13966
+ children: states.map((state) => /* @__PURE__ */ jsx33(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
12601
13967
  }
12602
13968
  );
12603
13969
  }
12604
13970
  var contentCache = /* @__PURE__ */ new Map();
13971
+ var fetchedContentPaths = /* @__PURE__ */ new Set();
12605
13972
  function resolveSubdomain(subdomainFromQuery) {
12606
13973
  if (subdomainFromQuery) return subdomainFromQuery;
12607
13974
  if (typeof window !== "undefined") {
@@ -12624,8 +13991,8 @@ function OhhwellsBridge() {
12624
13991
  const router = useRouter3();
12625
13992
  const searchParams = useSearchParams();
12626
13993
  const isEditMode = isEditSessionActive();
12627
- const [bridgeRoot, setBridgeRoot] = useState10(null);
12628
- useEffect11(() => {
13994
+ const [bridgeRoot, setBridgeRoot] = useState11(null);
13995
+ useEffect12(() => {
12629
13996
  const figtreeFontId = "ohw-figtree-font";
12630
13997
  if (!document.getElementById(figtreeFontId)) {
12631
13998
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -12654,110 +14021,137 @@ function OhhwellsBridge() {
12654
14021
  const subdomain = resolveSubdomain(subdomainFromQuery);
12655
14022
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
12656
14023
  useSavedLinkNavigation(isEditMode);
12657
- const postToParent2 = useCallback6((data) => {
14024
+ const postToParent2 = useCallback7((data) => {
12658
14025
  if (typeof window !== "undefined" && window.parent !== window) {
12659
14026
  window.parent.postMessage(data, "*");
12660
14027
  }
12661
14028
  }, []);
12662
- const [fetchState, setFetchState] = useState10("idle");
12663
- const autoSaveTimers = useRef8(/* @__PURE__ */ new Map());
12664
- const activeElRef = useRef8(null);
12665
- const pointerHeldRef = useRef8(false);
12666
- const selectedElRef = useRef8(null);
12667
- const selectedHrefKeyRef = useRef8(null);
12668
- const selectedFooterColAttrRef = useRef8(null);
12669
- const originalContentRef = useRef8(null);
12670
- const activeStateElRef = useRef8(null);
12671
- const parentScrollRef = useRef8(null);
12672
- const visibleViewportRef = useRef8(null);
12673
- const [dialogPortalContainer, setDialogPortalContainer] = useState10(null);
12674
- const attachVisibleViewport = useCallback6((node) => {
14029
+ const [fetchState, setFetchState] = useState11("idle");
14030
+ const autoSaveTimers = useRef9(/* @__PURE__ */ new Map());
14031
+ const activeElRef = useRef9(null);
14032
+ const pointerHeldRef = useRef9(false);
14033
+ const selectedElRef = useRef9(null);
14034
+ const selectedHrefKeyRef = useRef9(null);
14035
+ const selectedFooterColAttrRef = useRef9(null);
14036
+ const originalContentRef = useRef9(null);
14037
+ const activeStateElRef = useRef9(null);
14038
+ const parentScrollRef = useRef9(null);
14039
+ const visibleViewportRef = useRef9(null);
14040
+ const [dialogPortalContainer, setDialogPortalContainer] = useState11(null);
14041
+ const attachVisibleViewport = useCallback7((node) => {
12675
14042
  visibleViewportRef.current = node;
12676
14043
  setDialogPortalContainer(node);
12677
14044
  if (node) applyVisibleViewport(node, parentScrollRef.current);
12678
14045
  }, []);
12679
- const toolbarElRef = useRef8(null);
12680
- const glowElRef = useRef8(null);
12681
- const hoveredImageRef = useRef8(null);
12682
- const hoveredImageHasTextOverlapRef = useRef8(false);
12683
- const dragOverElRef = useRef8(null);
12684
- const [mediaHover, setMediaHover] = useState10(null);
12685
- const [carouselHover, setCarouselHover] = useState10(null);
12686
- const [uploadingRects, setUploadingRects] = useState10({});
12687
- const hoveredGapRef = useRef8(null);
12688
- const imageUnhoverTimerRef = useRef8(null);
12689
- const imageShowTimerRef = useRef8(null);
12690
- const editStylesRef = useRef8(null);
12691
- const activateRef = useRef8(() => {
14046
+ const toolbarElRef = useRef9(null);
14047
+ const glowElRef = useRef9(null);
14048
+ const hoveredImageRef = useRef9(null);
14049
+ const hoveredImageHasTextOverlapRef = useRef9(false);
14050
+ const dragOverElRef = useRef9(null);
14051
+ const [mediaHover, setMediaHover] = useState11(null);
14052
+ const [carouselHover, setCarouselHover] = useState11(null);
14053
+ const [uploadingRects, setUploadingRects] = useState11({});
14054
+ const hoveredGapRef = useRef9(null);
14055
+ const imageUnhoverTimerRef = useRef9(null);
14056
+ const imageShowTimerRef = useRef9(null);
14057
+ const editStylesRef = useRef9(null);
14058
+ const activateRef = useRef9(() => {
14059
+ });
14060
+ const deactivateRef = useRef9(() => {
14061
+ });
14062
+ const selectRef = useRef9(() => {
14063
+ });
14064
+ const selectFrameRef = useRef9(() => {
12692
14065
  });
12693
- const deactivateRef = useRef8(() => {
14066
+ const selectLogoRef = useRef9(() => {
12694
14067
  });
12695
- const selectRef = useRef8(() => {
14068
+ const openLogoSizePanelRef = useRef9(() => {
12696
14069
  });
12697
- const selectFrameRef = useRef8(() => {
14070
+ const deselectRef = useRef9(() => {
12698
14071
  });
12699
- const deselectRef = useRef8(() => {
14072
+ const closeFloatingPanelOnlyRef = useRef9(() => {
12700
14073
  });
12701
- const reselectNavigationItemRef = useRef8(() => {
14074
+ const reselectNavigationItemRef = useRef9(() => {
12702
14075
  });
12703
- const commitNavigationTextEditRef = useRef8(() => {
14076
+ const commitNavigationTextEditRef = useRef9(() => {
12704
14077
  });
12705
- const handleDeleteSelectedRef = useRef8(() => false);
12706
- const runPendingDeleteUndoRef = useRef8(() => false);
12707
- const isFooterFrameSelectionRef = useRef8(false);
12708
- const refreshActiveCommandsRef = useRef8(() => {
14078
+ const handleDeleteSelectedRef = useRef9(() => false);
14079
+ const runPendingDeleteUndoRef = useRef9(() => false);
14080
+ const isFooterFrameSelectionRef = useRef9(false);
14081
+ const refreshActiveCommandsRef = useRef9(() => {
12709
14082
  });
12710
- const postToParentRef = useRef8(postToParent2);
14083
+ const postToParentRef = useRef9(postToParent2);
12711
14084
  postToParentRef.current = postToParent2;
12712
- const aiSectionApiRef = useRef8(null);
12713
- const sectionsLoadedRef = useRef8(false);
12714
- const pendingScheduleConfigRequests = useRef8([]);
12715
- const [toolbarRect, setToolbarRect] = useState10(null);
12716
- const [toolbarVariant, setToolbarVariant] = useState10("none");
12717
- const toolbarVariantRef = useRef8("none");
14085
+ const aiSectionApiRef = useRef9(null);
14086
+ const sectionsLoadedRef = useRef9(false);
14087
+ const pendingScheduleConfigRequests = useRef9([]);
14088
+ const [toolbarRect, setToolbarRect] = useState11(null);
14089
+ const [toolbarVariant, setToolbarVariant] = useState11("none");
14090
+ const toolbarVariantRef = useRef9("none");
12718
14091
  toolbarVariantRef.current = toolbarVariant;
12719
- const [selectedIsCta, setSelectedIsCta] = useState10(false);
12720
- const [reorderHrefKey, setReorderHrefKey] = useState10(null);
12721
- const [reorderDragDisabled, setReorderDragDisabled] = useState10(false);
12722
- const [toggleState, setToggleState] = useState10(null);
12723
- const [maxBadge, setMaxBadge] = useState10(null);
12724
- const [activeCommands, setActiveCommands] = useState10(/* @__PURE__ */ new Set());
12725
- const [sectionGap, setSectionGap] = useState10(null);
12726
- const [toolbarShowEditLink, setToolbarShowEditLink] = useState10(false);
12727
- const hoveredNavContainerRef = useRef8(null);
12728
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState10(null);
12729
- const hoveredItemElRef = useRef8(null);
12730
- const [hoveredItemRect, setHoveredItemRect] = useState10(null);
12731
- const siblingHintElRef = useRef8(null);
12732
- const [siblingHintRect, setSiblingHintRect] = useState10(null);
12733
- const [siblingHintRects, setSiblingHintRects] = useState10([]);
12734
- const [isItemDragging, setIsItemDragging] = useState10(false);
12735
- const [isFooterFrameSelection, setIsFooterFrameSelection] = useState10(false);
14092
+ const [selectedIsCta, setSelectedIsCta] = useState11(false);
14093
+ const [selectedIsSocial, setSelectedIsSocial] = useState11(false);
14094
+ const [selectedIsSocialsRow, setSelectedIsSocialsRow] = useState11(false);
14095
+ const [reorderHrefKey, setReorderHrefKey] = useState11(null);
14096
+ const [reorderDragDisabled, setReorderDragDisabled] = useState11(false);
14097
+ const [toggleState, setToggleState] = useState11(null);
14098
+ const [maxBadge, setMaxBadge] = useState11(null);
14099
+ const [activeCommands, setActiveCommands] = useState11(/* @__PURE__ */ new Set());
14100
+ const [sectionGap, setSectionGap] = useState11(null);
14101
+ const [toolbarShowEditLink, setToolbarShowEditLink] = useState11(false);
14102
+ const hoveredNavContainerRef = useRef9(null);
14103
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState11(null);
14104
+ const hoveredItemElRef = useRef9(null);
14105
+ const [hoveredItemRect, setHoveredItemRect] = useState11(null);
14106
+ const siblingHintElRef = useRef9(null);
14107
+ const [siblingHintRect, setSiblingHintRect] = useState11(null);
14108
+ const [siblingHintRects, setSiblingHintRects] = useState11([]);
14109
+ const [isItemDragging, setIsItemDragging] = useState11(false);
14110
+ const [isFooterFrameSelection, setIsFooterFrameSelection] = useState11(false);
12736
14111
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
12737
- const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState10(null);
12738
- const [footerHeadingVisible, setFooterHeadingVisible] = useState10(null);
12739
- const footerDragRef = useRef8(null);
12740
- const [footerDropSlots, setFooterDropSlots] = useState10([]);
12741
- const [activeFooterDropIndex, setActiveFooterDropIndex] = useState10(null);
12742
- const [draggedItemRect, setDraggedItemRect] = useState10(null);
12743
- const footerPointerDragRef = useRef8(null);
12744
- const suppressNextClickRef = useRef8(false);
12745
- const suppressClickUntilRef = useRef8(0);
12746
- const [linkPopover, setLinkPopover] = useState10(null);
12747
- const linkPopoverSessionRef = useRef8(null);
12748
- const addNavAfterAnchorRef = useRef8(null);
12749
- const editContentRef = useRef8({});
12750
- const aiSectionsRef = useRef8("");
12751
- const pendingDeleteUndoRef = useRef8(null);
12752
- const [sitePages, setSitePages] = useState10([]);
12753
- const [sectionsByPath, setSectionsByPath] = useState10({});
12754
- const sectionsPrefetchGenRef = useRef8(0);
12755
- const setLinkPopoverRef = useRef8(setLinkPopover);
12756
- const linkPopoverPanelRef = useRef8(null);
12757
- const linkPopoverOpenRef = useRef8(false);
12758
- const linkPopoverGraceUntilRef = useRef8(0);
14112
+ const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState11(null);
14113
+ const [footerHeadingVisible, setFooterHeadingVisible] = useState11(null);
14114
+ const footerDragRef = useRef9(null);
14115
+ const [footerDropSlots, setFooterDropSlots] = useState11([]);
14116
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = useState11(null);
14117
+ const [draggedItemRect, setDraggedItemRect] = useState11(null);
14118
+ const footerPointerDragRef = useRef9(null);
14119
+ const suppressNextClickRef = useRef9(false);
14120
+ const suppressClickUntilRef = useRef9(0);
14121
+ const [linkPopover, setLinkPopover] = useState11(null);
14122
+ const linkPopoverSessionRef = useRef9(null);
14123
+ const addNavAfterAnchorRef = useRef9(null);
14124
+ const editContentRef = useRef9({});
14125
+ const aiSectionsRef = useRef9("");
14126
+ const brandKitRef = useRef9("");
14127
+ const pendingDeleteUndoRef = useRef9(null);
14128
+ const [floatingPanel, setFloatingPanel] = useState11(null);
14129
+ const floatingPanelOpenRef = useRef9(false);
14130
+ const setFloatingPanelRef = useRef9(setFloatingPanel);
14131
+ const [floatingPanelPos, setFloatingPanelPos] = useState11(null);
14132
+ const [logoSizeDraft, setLogoSizeDraft] = useState11(null);
14133
+ const [editorViewport, setEditorViewport] = useState11("desktop");
14134
+ const [parentScrollSnap, setParentScrollSnap] = useState11(null);
14135
+ const [sitePages, setSitePages] = useState11([]);
14136
+ const [sectionsByPath, setSectionsByPath] = useState11({});
14137
+ const sectionsPrefetchGenRef = useRef9(0);
14138
+ const setLinkPopoverRef = useRef9(setLinkPopover);
14139
+ const linkPopoverPanelRef = useRef9(null);
14140
+ const linkPopoverOpenRef = useRef9(false);
14141
+ const linkPopoverGraceUntilRef = useRef9(0);
12759
14142
  setLinkPopoverRef.current = setLinkPopover;
14143
+ setFloatingPanelRef.current = setFloatingPanel;
12760
14144
  linkPopoverSessionRef.current = linkPopover;
14145
+ floatingPanelOpenRef.current = Boolean(floatingPanel);
14146
+ useEffect12(() => {
14147
+ const syncViewport = () => {
14148
+ const next = window.innerWidth <= 480 ? "mobile" : "desktop";
14149
+ setEditorViewport((prev) => prev === next ? prev : next);
14150
+ };
14151
+ syncViewport();
14152
+ window.addEventListener("resize", syncViewport);
14153
+ return () => window.removeEventListener("resize", syncViewport);
14154
+ }, []);
12761
14155
  const {
12762
14156
  navDragRef,
12763
14157
  navDropSlots,
@@ -12793,7 +14187,7 @@ function OhhwellsBridge() {
12793
14187
  const bumpLinkPopoverGrace = () => {
12794
14188
  linkPopoverGraceUntilRef.current = Date.now() + 350;
12795
14189
  };
12796
- const runSectionsPrefetch = useCallback6((pages) => {
14190
+ const runSectionsPrefetch = useCallback7((pages) => {
12797
14191
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
12798
14192
  const gen = ++sectionsPrefetchGenRef.current;
12799
14193
  const paths = pages.map((p) => p.path);
@@ -12812,9 +14206,9 @@ function OhhwellsBridge() {
12812
14206
  );
12813
14207
  });
12814
14208
  }, [isEditMode, pathname]);
12815
- const runSectionsPrefetchRef = useRef8(runSectionsPrefetch);
14209
+ const runSectionsPrefetchRef = useRef9(runSectionsPrefetch);
12816
14210
  runSectionsPrefetchRef.current = runSectionsPrefetch;
12817
- useEffect11(() => {
14211
+ useEffect12(() => {
12818
14212
  if (!linkPopover) {
12819
14213
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
12820
14214
  return;
@@ -12842,7 +14236,7 @@ function OhhwellsBridge() {
12842
14236
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
12843
14237
  };
12844
14238
  }, [linkPopover, postToParent2]);
12845
- useEffect11(() => {
14239
+ useEffect12(() => {
12846
14240
  if (!isEditMode) return;
12847
14241
  const useFixtures = shouldUseDevFixtures();
12848
14242
  if (useFixtures) {
@@ -12866,14 +14260,14 @@ function OhhwellsBridge() {
12866
14260
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
12867
14261
  return () => window.removeEventListener("message", onSitePages);
12868
14262
  }, [isEditMode, postToParent2]);
12869
- useEffect11(() => {
14263
+ useEffect12(() => {
12870
14264
  if (!isEditMode || shouldUseDevFixtures()) return;
12871
14265
  void loadAllSectionsManifest().then((manifest) => {
12872
14266
  if (Object.keys(manifest).length === 0) return;
12873
14267
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
12874
14268
  });
12875
14269
  }, [isEditMode]);
12876
- useEffect11(() => {
14270
+ useEffect12(() => {
12877
14271
  const update = () => {
12878
14272
  const el = activeElRef.current ?? selectedElRef.current;
12879
14273
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -12897,10 +14291,10 @@ function OhhwellsBridge() {
12897
14291
  vvp.removeEventListener("resize", update);
12898
14292
  };
12899
14293
  }, []);
12900
- const refreshStateRules = useCallback6(() => {
14294
+ const refreshStateRules = useCallback7(() => {
12901
14295
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
12902
14296
  }, []);
12903
- const processConfigRequest = useCallback6((insertAfterVal) => {
14297
+ const processConfigRequest = useCallback7((insertAfterVal) => {
12904
14298
  const tracker = getSectionsTracker();
12905
14299
  let entries = [];
12906
14300
  try {
@@ -12923,7 +14317,7 @@ function OhhwellsBridge() {
12923
14317
  }
12924
14318
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
12925
14319
  }, [isEditMode]);
12926
- const deactivate = useCallback6(() => {
14320
+ const deactivate = useCallback7(() => {
12927
14321
  const el = activeElRef.current;
12928
14322
  if (!el) return;
12929
14323
  const key = el.dataset.ohwKey;
@@ -12956,17 +14350,19 @@ function OhhwellsBridge() {
12956
14350
  setToolbarShowEditLink(false);
12957
14351
  postToParent2({ type: "ow:exit-edit" });
12958
14352
  }, [postToParent2]);
12959
- const clearSelectedAttr = useCallback6(() => {
14353
+ const clearSelectedAttr = useCallback7(() => {
12960
14354
  document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
12961
14355
  el.removeAttribute("data-ohw-selected");
12962
14356
  });
12963
14357
  }, []);
12964
- const deselect = useCallback6(() => {
14358
+ const deselect = useCallback7(() => {
12965
14359
  clearSelectedAttr();
12966
14360
  selectedElRef.current = null;
12967
14361
  selectedHrefKeyRef.current = null;
12968
14362
  selectedFooterColAttrRef.current = null;
12969
14363
  setSelectedIsCta(false);
14364
+ setSelectedIsSocial(false);
14365
+ setSelectedIsSocialsRow(false);
12970
14366
  setReorderHrefKey(null);
12971
14367
  setReorderDragDisabled(false);
12972
14368
  setIsFooterFrameSelection(false);
@@ -12978,17 +14374,21 @@ function OhhwellsBridge() {
12978
14374
  setIsItemDragging(false);
12979
14375
  hoveredNavContainerRef.current = null;
12980
14376
  setHoveredNavContainerRect(null);
14377
+ hoveredItemElRef.current = null;
14378
+ setHoveredItemRect(null);
14379
+ setFloatingPanel(null);
14380
+ setLogoSizeDraft(null);
12981
14381
  if (!activeElRef.current) {
12982
14382
  setNavGroupForceOpen(null, false);
12983
14383
  setToolbarRect(null);
12984
14384
  setToolbarVariant("none");
12985
14385
  }
12986
14386
  }, [clearSelectedAttr]);
12987
- const markSelected = useCallback6((el) => {
14387
+ const markSelected = useCallback7((el) => {
12988
14388
  clearSelectedAttr();
12989
14389
  el.setAttribute("data-ohw-selected", "");
12990
14390
  }, [clearSelectedAttr]);
12991
- const resolveHrefKeyElement = useCallback6((hrefKey) => {
14391
+ const resolveHrefKeyElement = useCallback7((hrefKey) => {
12992
14392
  if (isFooterHrefKey(hrefKey)) {
12993
14393
  return document.querySelector(
12994
14394
  `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
@@ -13003,7 +14403,7 @@ function OhhwellsBridge() {
13003
14403
  `[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
13004
14404
  );
13005
14405
  }, []);
13006
- const resyncSelectedNavigationItem = useCallback6(() => {
14406
+ const resyncSelectedNavigationItem = useCallback7(() => {
13007
14407
  const hrefKey = selectedHrefKeyRef.current;
13008
14408
  if (hrefKey) {
13009
14409
  const link = resolveHrefKeyElement(hrefKey);
@@ -13041,12 +14441,14 @@ function OhhwellsBridge() {
13041
14441
  );
13042
14442
  }
13043
14443
  }, [resolveHrefKeyElement]);
13044
- const reselectNavigationItem = useCallback6((navAnchor) => {
14444
+ const reselectNavigationItem = useCallback7((navAnchor) => {
13045
14445
  selectedElRef.current = navAnchor;
13046
14446
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
13047
14447
  selectedFooterColAttrRef.current = null;
13048
14448
  markSelected(navAnchor);
13049
14449
  setSelectedIsCta(isCtaButton(navAnchor));
14450
+ setSelectedIsSocial(Boolean(getSocialItem(navAnchor)));
14451
+ setSelectedIsSocialsRow(false);
13050
14452
  const isDropdownTrigger = !isNestedNavChild(navAnchor) && (navItemHasDropdownChildren(navAnchor) || navItemOwnsDropdownPanel(navAnchor));
13051
14453
  if (isNestedNavChild(navAnchor)) {
13052
14454
  setNavGroupForceOpen(navAnchor, true);
@@ -13070,7 +14472,7 @@ function OhhwellsBridge() {
13070
14472
  setToolbarShowEditLink(false);
13071
14473
  setActiveCommands(/* @__PURE__ */ new Set());
13072
14474
  }, [markSelected]);
13073
- const commitNavigationTextEdit = useCallback6((navAnchor) => {
14475
+ const commitNavigationTextEdit = useCallback7((navAnchor) => {
13074
14476
  const el = activeElRef.current;
13075
14477
  if (!el) return;
13076
14478
  const key = el.dataset.ohwKey;
@@ -13097,7 +14499,7 @@ function OhhwellsBridge() {
13097
14499
  postToParent2({ type: "ow:exit-edit" });
13098
14500
  reselectNavigationItem(navAnchor);
13099
14501
  }, [postToParent2, reselectNavigationItem]);
13100
- const handleAddTopLevelNavItem = useCallback6(() => {
14502
+ const handleAddTopLevelNavItem = useCallback7(() => {
13101
14503
  const items = listNavbarRootItems();
13102
14504
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
13103
14505
  deselectRef.current();
@@ -13109,7 +14511,7 @@ function OhhwellsBridge() {
13109
14511
  intent: "add-nav"
13110
14512
  });
13111
14513
  }, []);
13112
- const maybeWarnNavLinkDropdownConflict = useCallback6(
14514
+ const maybeWarnNavLinkDropdownConflict = useCallback7(
13113
14515
  (anchor) => {
13114
14516
  if (!isNavbarHrefKey(anchor.getAttribute("data-ohw-href-key"))) return;
13115
14517
  if (!navDropdownsOpenOnClick()) return;
@@ -13122,7 +14524,7 @@ function OhhwellsBridge() {
13122
14524
  },
13123
14525
  [postToParent2]
13124
14526
  );
13125
- const handleNavDropdownOpenChange = useCallback6((open) => {
14527
+ const handleNavDropdownOpenChange = useCallback7((open) => {
13126
14528
  const selected = selectedElRef.current;
13127
14529
  if (!selected || !isNavigationItem2(selected)) return;
13128
14530
  setNavGroupForceOpen(selected, open);
@@ -13134,7 +14536,7 @@ function OhhwellsBridge() {
13134
14536
  }
13135
14537
  });
13136
14538
  }, []);
13137
- const handleFooterHeadingVisibleChange = useCallback6(
14539
+ const handleFooterHeadingVisibleChange = useCallback7(
13138
14540
  (visible) => {
13139
14541
  const selected = selectedElRef.current;
13140
14542
  if (!selected || !isFooterFrameSelectionRef.current) return;
@@ -13158,7 +14560,7 @@ function OhhwellsBridge() {
13158
14560
  },
13159
14561
  [postToParent2]
13160
14562
  );
13161
- const enterEditOnNewItem = useCallback6((anchor) => {
14563
+ const enterEditOnNewItem = useCallback7((anchor) => {
13162
14564
  const label = anchor.querySelector('[data-ohw-editable="text"]');
13163
14565
  if (!label) {
13164
14566
  selectRef.current(anchor);
@@ -13167,9 +14569,31 @@ function OhhwellsBridge() {
13167
14569
  setNavGroupForceOpen(anchor, true);
13168
14570
  activateRef.current(label);
13169
14571
  }, []);
13170
- const handleAddChildItem = useCallback6(() => {
14572
+ const handleAddChildItem = useCallback7(() => {
13171
14573
  const selected = selectedElRef.current;
13172
14574
  if (!selected) return;
14575
+ const socialsRow = isSocialsRow(selected) ? selected : findSocialsRow(selected);
14576
+ if (socialsRow) {
14577
+ const after = getSocialItem(selected);
14578
+ const result2 = insertSocialItem(socialsRow, after, editContentRef.current);
14579
+ if (!result2) return;
14580
+ const orderJson = JSON.stringify(result2.order);
14581
+ applySocialsDisplayToRow(socialsRow, socialsDisplayFor(socialsRow, editContentRef.current));
14582
+ editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
14583
+ postToParent2({ type: "ow:change", nodes: [{ key: SOCIALS_ORDER_KEY, text: orderJson }] });
14584
+ postToParentRef.current({
14585
+ type: "ow:social-pick",
14586
+ hrefKey: result2.hrefKey,
14587
+ iconKey: result2.iconKey,
14588
+ url: "",
14589
+ iconStyle: detectIconStyle(result2.item),
14590
+ platformId: "",
14591
+ // Lets the editor undo the insert if the dialog is dismissed: an item that was never given
14592
+ // an address should not survive a Cancel.
14593
+ isNew: true
14594
+ });
14595
+ return;
14596
+ }
13173
14597
  if (toolbarVariantRef.current === "select-frame" && isFooterFrameSelection) {
13174
14598
  if (!selected.hasAttribute("data-ohw-footer-col") && !selected.closest("[data-ohw-footer-col]")) {
13175
14599
  }
@@ -13243,7 +14667,7 @@ function OhhwellsBridge() {
13243
14667
  enterEditOnNewItem(result.anchor);
13244
14668
  });
13245
14669
  }, [enterEditOnNewItem, isFooterFrameSelection, maybeWarnNavLinkDropdownConflict, postToParent2]);
13246
- const handleAddFooterColumn = useCallback6(() => {
14670
+ const handleAddFooterColumn = useCallback7(() => {
13247
14671
  if (!canAddFooterColumn()) {
13248
14672
  postToParent2({
13249
14673
  type: "ow:toast",
@@ -13264,7 +14688,7 @@ function OhhwellsBridge() {
13264
14688
  selectRef.current(result.firstLink);
13265
14689
  });
13266
14690
  }, [postToParent2]);
13267
- const clearFooterDragVisuals = useCallback6(() => {
14691
+ const clearFooterDragVisuals = useCallback7(() => {
13268
14692
  footerDragRef.current = null;
13269
14693
  setSiblingHintRects([]);
13270
14694
  setFooterDropSlots([]);
@@ -13273,7 +14697,7 @@ function OhhwellsBridge() {
13273
14697
  setIsItemDragging(false);
13274
14698
  unlockFooterDragInteraction();
13275
14699
  }, []);
13276
- const refreshFooterDragVisuals = useCallback6((session, activeSlot, clientX, clientY) => {
14700
+ const refreshFooterDragVisuals = useCallback7((session, activeSlot, clientX, clientY) => {
13277
14701
  const dragged = session.draggedEl;
13278
14702
  setDraggedItemRect(dragged.getBoundingClientRect());
13279
14703
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -13282,6 +14706,13 @@ function OhhwellsBridge() {
13282
14706
  }
13283
14707
  session.activeSlot = activeSlot;
13284
14708
  setSiblingHintRects([]);
14709
+ if (session.kind === "social") {
14710
+ const slots2 = session.hrefKey ? buildSocialDropSlotsForKey(session.hrefKey) : [];
14711
+ setFooterDropSlots(slots2);
14712
+ const activeIdx2 = activeSlot ? slots2.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
14713
+ setActiveFooterDropIndex(activeIdx2 >= 0 ? activeIdx2 : null);
14714
+ return;
14715
+ }
13285
14716
  if (session.kind === "link") {
13286
14717
  const columns = listFooterColumns();
13287
14718
  const slots2 = [];
@@ -13298,13 +14729,13 @@ function OhhwellsBridge() {
13298
14729
  const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
13299
14730
  setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
13300
14731
  }, []);
13301
- const refreshFooterDragVisualsRef = useRef8(refreshFooterDragVisuals);
14732
+ const refreshFooterDragVisualsRef = useRef9(refreshFooterDragVisuals);
13302
14733
  refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
13303
- const commitFooterDragRef = useRef8(() => {
14734
+ const commitFooterDragRef = useRef9(() => {
13304
14735
  });
13305
- const beginFooterDragRef = useRef8(() => {
14736
+ const beginFooterDragRef = useRef9(() => {
13306
14737
  });
13307
- const beginFooterDrag = useCallback6(
14738
+ const beginFooterDrag = useCallback7(
13308
14739
  (session) => {
13309
14740
  const rect = session.draggedEl.getBoundingClientRect();
13310
14741
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -13318,13 +14749,13 @@ function OhhwellsBridge() {
13318
14749
  if (session.wasSelected && selectedElRef.current === session.draggedEl) {
13319
14750
  setToolbarRect(rect);
13320
14751
  }
13321
- const initialSlot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
14752
+ const initialSlot = session.kind === "social" && session.hrefKey ? hitTestSocialDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
13322
14753
  refreshFooterDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
13323
14754
  },
13324
14755
  [refreshFooterDragVisuals]
13325
14756
  );
13326
14757
  beginFooterDragRef.current = beginFooterDrag;
13327
- const commitFooterDrag = useCallback6(
14758
+ const commitFooterDrag = useCallback7(
13328
14759
  (clientX, clientY) => {
13329
14760
  const session = footerDragRef.current;
13330
14761
  if (!session) {
@@ -13334,8 +14765,11 @@ function OhhwellsBridge() {
13334
14765
  const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
13335
14766
  const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
13336
14767
  let nextOrder = null;
13337
- const slot = session.activeSlot ?? (session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(x, y, session.hrefKey) : session.kind === "column" ? hitTestColumnDropSlot(x, y) : null);
13338
- if (session.kind === "link" && session.hrefKey && slot) {
14768
+ let nextSocialsOrder = null;
14769
+ const slot = session.activeSlot ?? (session.kind === "social" && session.hrefKey ? hitTestSocialDropSlot(x, y, session.hrefKey) : session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(x, y, session.hrefKey) : session.kind === "column" ? hitTestColumnDropSlot(x, y) : null);
14770
+ if (session.kind === "social" && session.hrefKey && slot) {
14771
+ nextSocialsOrder = planSocialMove(session.hrefKey, slot.insertIndex);
14772
+ } else if (session.kind === "link" && session.hrefKey && slot) {
13339
14773
  nextOrder = planFooterLinkMove(session.hrefKey, slot.columnIndex, slot.insertIndex);
13340
14774
  } else if (session.kind === "column" && slot) {
13341
14775
  nextOrder = planFooterColumnMove(session.sourceColumnIndex, slot.insertIndex);
@@ -13393,6 +14827,27 @@ function OhhwellsBridge() {
13393
14827
  }
13394
14828
  deselectRef.current();
13395
14829
  };
14830
+ if (nextSocialsOrder) {
14831
+ const orderJson = JSON.stringify(nextSocialsOrder);
14832
+ editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
14833
+ applySocialsOrder(nextSocialsOrder);
14834
+ postToParentRef.current({
14835
+ type: "ow:change",
14836
+ nodes: [{ key: SOCIALS_ORDER_KEY, text: orderJson }]
14837
+ });
14838
+ applySelectionAfterDrop();
14839
+ clearFooterDragVisuals();
14840
+ const reapply = nextSocialsOrder;
14841
+ requestAnimationFrame(() => {
14842
+ if (editContentRef.current[SOCIALS_ORDER_KEY] === orderJson) applySocialsOrder(reapply);
14843
+ applySelectionAfterDrop();
14844
+ requestAnimationFrame(() => {
14845
+ if (editContentRef.current[SOCIALS_ORDER_KEY] === orderJson) applySocialsOrder(reapply);
14846
+ resyncSelectedNavigationItem();
14847
+ });
14848
+ });
14849
+ return;
14850
+ }
13396
14851
  if (nextOrder) {
13397
14852
  const orderJson = JSON.stringify(nextOrder);
13398
14853
  editContentRef.current = {
@@ -13428,10 +14883,25 @@ function OhhwellsBridge() {
13428
14883
  [clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
13429
14884
  );
13430
14885
  commitFooterDragRef.current = commitFooterDrag;
13431
- const startFooterLinkDrag = useCallback6(
14886
+ const startFooterLinkDrag = useCallback7(
13432
14887
  (anchor, clientX, clientY, wasSelected) => {
13433
14888
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
13434
- if (!hrefKey || !isFooterHrefKey(hrefKey)) return false;
14889
+ if (!hrefKey) return false;
14890
+ if (getSocialItem(anchor)) {
14891
+ beginFooterDrag({
14892
+ kind: "social",
14893
+ hrefKey,
14894
+ columnEl: null,
14895
+ sourceColumnIndex: 0,
14896
+ wasSelected,
14897
+ draggedEl: anchor,
14898
+ lastClientX: clientX,
14899
+ lastClientY: clientY,
14900
+ activeSlot: null
14901
+ });
14902
+ return true;
14903
+ }
14904
+ if (!isFooterHrefKey(hrefKey)) return false;
13435
14905
  const column = findFooterColumnForLink(anchor);
13436
14906
  const columns = listFooterColumns();
13437
14907
  beginFooterDrag({
@@ -13449,7 +14919,7 @@ function OhhwellsBridge() {
13449
14919
  },
13450
14920
  [beginFooterDrag]
13451
14921
  );
13452
- const startFooterColumnDrag = useCallback6(
14922
+ const startFooterColumnDrag = useCallback7(
13453
14923
  (columnEl, clientX, clientY, wasSelected) => {
13454
14924
  const columns = listFooterColumns();
13455
14925
  const idx = columns.indexOf(columnEl);
@@ -13469,7 +14939,7 @@ function OhhwellsBridge() {
13469
14939
  },
13470
14940
  [beginFooterDrag]
13471
14941
  );
13472
- const handleItemDragStart = useCallback6(
14942
+ const handleItemDragStart = useCallback7(
13473
14943
  (e) => {
13474
14944
  const selected = selectedElRef.current;
13475
14945
  if (!selected) {
@@ -13489,7 +14959,7 @@ function OhhwellsBridge() {
13489
14959
  },
13490
14960
  [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
13491
14961
  );
13492
- const handleItemDragEnd = useCallback6(
14962
+ const handleItemDragEnd = useCallback7(
13493
14963
  (e) => {
13494
14964
  if (footerDragRef.current) {
13495
14965
  const x = e?.clientX;
@@ -13515,7 +14985,7 @@ function OhhwellsBridge() {
13515
14985
  },
13516
14986
  [commitFooterDrag, commitNavDrag, navDragRef]
13517
14987
  );
13518
- const handleItemChromePointerDown = useCallback6((e) => {
14988
+ const handleItemChromePointerDown = useCallback7((e) => {
13519
14989
  if (e.button !== 0) return;
13520
14990
  const selected = selectedElRef.current;
13521
14991
  if (!selected) return;
@@ -13546,7 +15016,7 @@ function OhhwellsBridge() {
13546
15016
  }
13547
15017
  if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
13548
15018
  }, [armNavPressFromChrome]);
13549
- const handleItemChromeClick = useCallback6((clientX, clientY) => {
15019
+ const handleItemChromeClick = useCallback7((clientX, clientY) => {
13550
15020
  if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
13551
15021
  suppressNextClickRef.current = false;
13552
15022
  return;
@@ -13559,7 +15029,7 @@ function OhhwellsBridge() {
13559
15029
  }, []);
13560
15030
  reselectNavigationItemRef.current = reselectNavigationItem;
13561
15031
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
13562
- const select = useCallback6((anchor) => {
15032
+ const select = useCallback7((anchor) => {
13563
15033
  if (!isNavigationItem2(anchor)) return;
13564
15034
  if (activeElRef.current) deactivate();
13565
15035
  aiSectionApiRef.current?.selectFromElement(anchor);
@@ -13568,6 +15038,8 @@ function OhhwellsBridge() {
13568
15038
  selectedFooterColAttrRef.current = null;
13569
15039
  markSelected(anchor);
13570
15040
  setSelectedIsCta(isCtaButton(anchor));
15041
+ setSelectedIsSocial(Boolean(getSocialItem(anchor)));
15042
+ setSelectedIsSocialsRow(false);
13571
15043
  clearHrefKeyHover(anchor);
13572
15044
  const isDropdownTrigger = !isNestedNavChild(anchor) && (navItemHasDropdownChildren(anchor) || navItemOwnsDropdownPanel(anchor));
13573
15045
  if (isNestedNavChild(anchor)) {
@@ -13597,8 +15069,10 @@ function OhhwellsBridge() {
13597
15069
  setToolbarRect(anchor.getBoundingClientRect());
13598
15070
  setToolbarShowEditLink(false);
13599
15071
  setActiveCommands(/* @__PURE__ */ new Set());
15072
+ setFloatingPanel(null);
15073
+ setLogoSizeDraft(null);
13600
15074
  }, [deactivate, markSelected]);
13601
- const selectFrame = useCallback6((el) => {
15075
+ const selectFrame = useCallback7((el) => {
13602
15076
  if (!isNavigationContainer(el)) return;
13603
15077
  if (activeElRef.current) deactivate();
13604
15078
  aiSectionApiRef.current?.selectFromElement(el);
@@ -13608,6 +15082,8 @@ function OhhwellsBridge() {
13608
15082
  selectedFooterColAttrRef.current = isFooterColumn ? el.getAttribute("data-ohw-footer-col") ?? String(listFooterColumns().indexOf(el)) : null;
13609
15083
  markSelected(el);
13610
15084
  setSelectedIsCta(false);
15085
+ setSelectedIsSocial(false);
15086
+ setSelectedIsSocialsRow(isSocialsRow(el));
13611
15087
  clearHrefKeyHover(el);
13612
15088
  setNavGroupForceOpen(null, false);
13613
15089
  hoveredNavContainerRef.current = null;
@@ -13644,14 +15120,145 @@ function OhhwellsBridge() {
13644
15120
  setToolbarRect(el.getBoundingClientRect());
13645
15121
  setToolbarShowEditLink(false);
13646
15122
  setActiveCommands(/* @__PURE__ */ new Set());
15123
+ setFloatingPanel(null);
15124
+ setLogoSizeDraft(null);
13647
15125
  }, [deactivate, markSelected, postToParent2]);
13648
- const activate = useCallback6((el, options) => {
15126
+ const selectLogo = useCallback7(
15127
+ (logoEl) => {
15128
+ if (activeElRef.current) deactivate();
15129
+ selectedElRef.current = logoEl;
15130
+ selectedHrefKeyRef.current = null;
15131
+ selectedFooterColAttrRef.current = null;
15132
+ markSelected(logoEl);
15133
+ setSelectedIsCta(false);
15134
+ setSelectedIsSocial(false);
15135
+ setSelectedIsSocialsRow(false);
15136
+ setSelectedIsSocialsRow(false);
15137
+ clearHrefKeyHover(logoEl);
15138
+ hoveredNavContainerRef.current = null;
15139
+ setHoveredNavContainerRect(null);
15140
+ setHoveredItemRect(null);
15141
+ hoveredItemElRef.current = null;
15142
+ siblingHintElRef.current = null;
15143
+ setSiblingHintRect(null);
15144
+ setSiblingHintRects([]);
15145
+ setIsItemDragging(false);
15146
+ setReorderHrefKey(null);
15147
+ setReorderDragDisabled(false);
15148
+ setIsFooterFrameSelection(false);
15149
+ setToolbarVariant("logo");
15150
+ setToolbarRect(getLogoInteractionRect(logoEl));
15151
+ setToolbarShowEditLink(false);
15152
+ setActiveCommands(/* @__PURE__ */ new Set());
15153
+ },
15154
+ [deactivate, markSelected]
15155
+ );
15156
+ const openLogoSizePanel = useCallback7((logoEl) => {
15157
+ const placement = getLogoPlacement(logoEl);
15158
+ const draft = readLogoSizeState(editContentRef.current, placement);
15159
+ setLogoSizeDraft(draft);
15160
+ setParentScrollSnap(parentScrollRef.current);
15161
+ setFloatingPanel({
15162
+ key: `logo-size:${placement}`,
15163
+ title: "Logo",
15164
+ context: placement === "navbar" ? "Navbar" : "Footer",
15165
+ kind: "logo-size",
15166
+ placement
15167
+ });
15168
+ }, []);
15169
+ const openSocialsDisplayPanel = useCallback7((row) => {
15170
+ setParentScrollSnap(parentScrollRef.current);
15171
+ setFloatingPanel({
15172
+ key: "socials-display",
15173
+ title: "Style",
15174
+ context: "Socials \xB7 Footer",
15175
+ kind: "socials-display",
15176
+ row
15177
+ });
15178
+ }, []);
15179
+ const changeSocialsDisplay = useCallback7(
15180
+ (row, next) => {
15181
+ if (next.icon) {
15182
+ const missing = socialsMissingIcons(row);
15183
+ listSocialItems(row).forEach((item) => ensureIconSlot(item));
15184
+ if (missing.length) {
15185
+ postToParentRef.current({ type: "ow:social-icons-needed", items: missing });
15186
+ }
15187
+ }
15188
+ applySocialsDisplayToRow(row, next);
15189
+ requestAnimationFrame(() => {
15190
+ if (selectedElRef.current === row && row.isConnected) setToolbarRect(row.getBoundingClientRect());
15191
+ });
15192
+ const displayJson = JSON.stringify(socialsDisplayWith(row, next, editContentRef.current));
15193
+ editContentRef.current = { ...editContentRef.current, [SOCIALS_DISPLAY_KEY]: displayJson };
15194
+ postToParentRef.current({
15195
+ type: "ow:change",
15196
+ nodes: [{ key: SOCIALS_DISPLAY_KEY, text: displayJson }],
15197
+ flush: true
15198
+ });
15199
+ },
15200
+ []
15201
+ );
15202
+ const closeFloatingPanelOnly = useCallback7(() => {
15203
+ setFloatingPanel(null);
15204
+ setLogoSizeDraft(null);
15205
+ }, []);
15206
+ const closeFloatingPanelAndDeselect = useCallback7(() => {
15207
+ setFloatingPanel(null);
15208
+ setLogoSizeDraft(null);
15209
+ deselectRef.current();
15210
+ }, []);
15211
+ const persistLogoSizeDraft = useCallback7(
15212
+ (placement, draft) => {
15213
+ const desktopKey = LOGO_SIZE_DESKTOP_KEYS[placement];
15214
+ const mobileKey = LOGO_SIZE_MOBILE_KEYS[placement];
15215
+ const nodes = [
15216
+ { key: desktopKey, text: String(draft.desktopPx) }
15217
+ ];
15218
+ if (draft.mobileFollowing) {
15219
+ nodes.push({ key: mobileKey, text: "" });
15220
+ } else {
15221
+ nodes.push({ key: mobileKey, text: String(draft.mobilePx) });
15222
+ }
15223
+ editContentRef.current = {
15224
+ ...editContentRef.current,
15225
+ [desktopKey]: String(draft.desktopPx),
15226
+ [mobileKey]: draft.mobileFollowing ? "" : String(draft.mobilePx)
15227
+ };
15228
+ applyLogoSizeToPlacement(
15229
+ placement,
15230
+ draft.desktopPx,
15231
+ draft.mobileFollowing ? draft.desktopPx : draft.mobilePx,
15232
+ draft.mobileFollowing
15233
+ );
15234
+ postToParent2({ type: "ow:change", nodes });
15235
+ requestAnimationFrame(() => {
15236
+ const selected = selectedElRef.current;
15237
+ if (!selected || toolbarVariantRef.current !== "logo") return;
15238
+ const rect = getLogoInteractionRect(selected);
15239
+ setToolbarRect(rect);
15240
+ if (glowElRef.current) {
15241
+ const GAP = SELECTION_CHROME_GAP2;
15242
+ glowElRef.current.style.top = `${rect.top - GAP}px`;
15243
+ glowElRef.current.style.left = `${rect.left - GAP}px`;
15244
+ glowElRef.current.style.width = `${rect.width + GAP * 2}px`;
15245
+ glowElRef.current.style.height = `${rect.height + GAP * 2}px`;
15246
+ }
15247
+ });
15248
+ },
15249
+ [postToParent2]
15250
+ );
15251
+ const activate = useCallback7((el, options) => {
13649
15252
  if (activeElRef.current === el) return;
15253
+ if (isIconEditable(el)) return;
15254
+ if (el.hasAttribute("data-ohw-social-label")) return;
13650
15255
  clearSelectedAttr();
13651
15256
  selectedElRef.current = null;
13652
15257
  selectedHrefKeyRef.current = null;
13653
15258
  selectedFooterColAttrRef.current = null;
13654
15259
  setSelectedIsCta(false);
15260
+ setSelectedIsSocial(false);
15261
+ setSelectedIsSocialsRow(false);
13655
15262
  deactivate();
13656
15263
  if (hoveredImageRef.current) {
13657
15264
  hoveredImageRef.current = null;
@@ -13721,8 +15328,38 @@ function OhhwellsBridge() {
13721
15328
  deactivateRef.current = deactivate;
13722
15329
  selectRef.current = select;
13723
15330
  selectFrameRef.current = selectFrame;
15331
+ selectLogoRef.current = selectLogo;
15332
+ openLogoSizePanelRef.current = openLogoSizePanel;
13724
15333
  deselectRef.current = deselect;
13725
- useLayoutEffect3(() => {
15334
+ closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
15335
+ const lastSiteWideScopeRef = useRef9(null);
15336
+ useEffect12(() => {
15337
+ if (!isEditMode) {
15338
+ if (lastSiteWideScopeRef.current !== false) {
15339
+ lastSiteWideScopeRef.current = false;
15340
+ postToParent2({ type: "ow:site-wide-scope", active: false });
15341
+ }
15342
+ return;
15343
+ }
15344
+ const active = isSiteWideScopeActive({
15345
+ selected: selectedElRef.current,
15346
+ hoveredItem: hoveredItemElRef.current,
15347
+ hoveredNavContainer: hoveredNavContainerRef.current,
15348
+ active: activeElRef.current
15349
+ });
15350
+ if (lastSiteWideScopeRef.current === active) return;
15351
+ lastSiteWideScopeRef.current = active;
15352
+ postToParent2({ type: "ow:site-wide-scope", active });
15353
+ }, [
15354
+ isEditMode,
15355
+ hoveredItemRect,
15356
+ hoveredNavContainerRect,
15357
+ toolbarVariant,
15358
+ toolbarRect,
15359
+ isFooterFrameSelection,
15360
+ postToParent2
15361
+ ]);
15362
+ useLayoutEffect4(() => {
13726
15363
  if (!subdomain || isEditMode) {
13727
15364
  setFetchState("done");
13728
15365
  return;
@@ -13733,9 +15370,18 @@ function OhhwellsBridge() {
13733
15370
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
13734
15371
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
13735
15372
  }
15373
+ if (typeof content[BRAND_KIT_KEY] === "string") {
15374
+ brandKitRef.current = content[BRAND_KIT_KEY];
15375
+ applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
15376
+ }
15377
+ applyBrandChrome(content);
13736
15378
  for (const [key, val] of Object.entries(content)) {
13737
15379
  if (key === "__ohw_sections") continue;
13738
15380
  if (key === AI_SECTIONS_KEY) continue;
15381
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
15382
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
15383
+ if (key === BRAND_KIT_KEY) continue;
15384
+ if (BRAND_CHROME_KEYS.has(key)) continue;
13739
15385
  if (applyVideoSettingNode(key, val)) continue;
13740
15386
  if (applyCarouselNode(key, val)) continue;
13741
15387
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -13762,14 +15408,20 @@ function OhhwellsBridge() {
13762
15408
  }
13763
15409
  } else if (el.dataset.ohwEditable === "link") {
13764
15410
  applyLinkHref(el, val);
15411
+ } else if (el.dataset.ohwEditable === "icon") {
15412
+ applyIconMarkup(el, val);
13765
15413
  } else if (el.innerHTML !== val) {
13766
15414
  el.innerHTML = val;
13767
15415
  }
13768
15416
  });
13769
15417
  applyLinkByKey(key, val);
13770
15418
  }
15419
+ applyLogoFromContent(content);
15420
+ applyLogoSizes(content);
13771
15421
  reconcileNavbarItemsFromContent(content);
13772
15422
  reconcileFooterOrderFromContent(content);
15423
+ reconcileSocialsFromContent(content);
15424
+ applySocialsDisplayFromContent(content);
13773
15425
  enforceLinkHrefs();
13774
15426
  initSectionsFromContent(content, true);
13775
15427
  sectionsLoadedRef.current = true;
@@ -13785,7 +15437,9 @@ function OhhwellsBridge() {
13785
15437
  let cancelled = false;
13786
15438
  setFetchState("loading");
13787
15439
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
13788
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
15440
+ const initialPath = pathname;
15441
+ fetchedContentPaths.add(`${subdomain}::${initialPath}`);
15442
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
13789
15443
  if (cancelled) return;
13790
15444
  const content = data?.content ?? {};
13791
15445
  contentCache.set(subdomain, content);
@@ -13798,7 +15452,7 @@ function OhhwellsBridge() {
13798
15452
  cancelled = true;
13799
15453
  };
13800
15454
  }, [subdomain, isEditMode]);
13801
- useEffect11(() => {
15455
+ useEffect12(() => {
13802
15456
  if (!subdomain || isEditMode) return;
13803
15457
  let debounceTimer = null;
13804
15458
  let observer = null;
@@ -13808,8 +15462,16 @@ function OhhwellsBridge() {
13808
15462
  retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
13809
15463
  observer?.disconnect();
13810
15464
  try {
15465
+ applyBrandChrome(content);
15466
+ if (typeof content[BRAND_KIT_KEY] === "string") {
15467
+ applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
15468
+ }
13811
15469
  for (const [key, val] of Object.entries(content)) {
13812
15470
  if (key === "__ohw_sections") continue;
15471
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
15472
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
15473
+ if (key === BRAND_KIT_KEY) continue;
15474
+ if (BRAND_CHROME_KEYS.has(key)) continue;
13813
15475
  if (applyVideoSettingNode(key, val)) continue;
13814
15476
  if (applyCarouselNode(key, val)) continue;
13815
15477
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -13830,8 +15492,11 @@ function OhhwellsBridge() {
13830
15492
  });
13831
15493
  applyLinkByKey(key, val);
13832
15494
  }
15495
+ applyLogoFromContent(content);
13833
15496
  reconcileNavbarItemsFromContent(content);
13834
15497
  reconcileFooterOrderFromContent(content);
15498
+ reconcileSocialsFromContent(content);
15499
+ applySocialsDisplayFromContent(content);
13835
15500
  } finally {
13836
15501
  observer?.observe(document.body, { childList: true, subtree: true });
13837
15502
  }
@@ -13842,6 +15507,17 @@ function OhhwellsBridge() {
13842
15507
  debounceTimer = setTimeout(applyFromCache, 150);
13843
15508
  };
13844
15509
  applyFromCache();
15510
+ const pathCacheKey = `${subdomain}::${pathname}`;
15511
+ if (!fetchedContentPaths.has(pathCacheKey)) {
15512
+ fetchedContentPaths.add(pathCacheKey);
15513
+ const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
15514
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
15515
+ if (!data?.content) return;
15516
+ contentCache.set(subdomain, data.content);
15517
+ applyFromCache();
15518
+ }).catch(() => {
15519
+ });
15520
+ }
13845
15521
  observer = new MutationObserver(scheduleApply);
13846
15522
  observer.observe(document.body, { childList: true, subtree: true });
13847
15523
  return () => {
@@ -13849,16 +15525,16 @@ function OhhwellsBridge() {
13849
15525
  if (debounceTimer) clearTimeout(debounceTimer);
13850
15526
  };
13851
15527
  }, [subdomain, isEditMode, pathname]);
13852
- useLayoutEffect3(() => {
15528
+ useLayoutEffect4(() => {
13853
15529
  const el = document.getElementById("ohw-loader");
13854
15530
  if (!el) return;
13855
15531
  const visible = Boolean(subdomain) && fetchState !== "done";
13856
15532
  el.style.display = visible ? "flex" : "none";
13857
15533
  }, [subdomain, fetchState]);
13858
- useEffect11(() => {
15534
+ useEffect12(() => {
13859
15535
  postToParent2({ type: "ow:navigation", path: pathname });
13860
15536
  }, [pathname, postToParent2]);
13861
- useEffect11(() => {
15537
+ useEffect12(() => {
13862
15538
  if (!isEditMode) return;
13863
15539
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
13864
15540
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -13866,7 +15542,7 @@ function OhhwellsBridge() {
13866
15542
  deselectRef.current();
13867
15543
  deactivateRef.current();
13868
15544
  }, [pathname, isEditMode]);
13869
- useEffect11(() => {
15545
+ useEffect12(() => {
13870
15546
  const contentForNav = () => {
13871
15547
  if (isEditMode) return editContentRef.current;
13872
15548
  if (!subdomain) return {};
@@ -13898,6 +15574,8 @@ function OhhwellsBridge() {
13898
15574
  const content = contentForNav();
13899
15575
  reconcileNavbarItemsFromContent(content);
13900
15576
  reconcileFooterOrderFromContent(content);
15577
+ reconcileSocialsFromContent(content);
15578
+ applySocialsDisplayFromContent(content);
13901
15579
  document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
13902
15580
  if (isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) {
13903
15581
  disableNativeHrefDrag(el);
@@ -13931,31 +15609,36 @@ function OhhwellsBridge() {
13931
15609
  observer?.disconnect();
13932
15610
  };
13933
15611
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
13934
- useEffect11(() => {
15612
+ useEffect12(() => {
13935
15613
  if (!isEditMode) return;
15614
+ let lastPosted = 0;
13936
15615
  const measure = () => {
13937
15616
  const h = document.body.scrollHeight;
13938
- if (h > 50) postToParent2({ type: "ow:height", height: h });
15617
+ if (h > 50 && Math.abs(h - lastPosted) > 1) {
15618
+ lastPosted = h;
15619
+ postToParent2({ type: "ow:height", height: h });
15620
+ }
15621
+ };
15622
+ let raf = null;
15623
+ const schedule = () => {
15624
+ if (raf != null) return;
15625
+ raf = requestAnimationFrame(() => {
15626
+ raf = null;
15627
+ measure();
15628
+ });
13939
15629
  };
13940
15630
  const t1 = setTimeout(measure, 50);
13941
15631
  const t2 = setTimeout(measure, 500);
13942
- let lastWidth = window.innerWidth;
13943
- let resizeTimer = null;
13944
- const handleResize = () => {
13945
- if (window.innerWidth === lastWidth) return;
13946
- lastWidth = window.innerWidth;
13947
- if (resizeTimer) clearTimeout(resizeTimer);
13948
- resizeTimer = setTimeout(measure, 150);
13949
- };
13950
- window.addEventListener("resize", handleResize);
15632
+ const ro = new ResizeObserver(schedule);
15633
+ ro.observe(document.body);
13951
15634
  return () => {
13952
15635
  clearTimeout(t1);
13953
15636
  clearTimeout(t2);
13954
- if (resizeTimer) clearTimeout(resizeTimer);
13955
- window.removeEventListener("resize", handleResize);
15637
+ if (raf != null) cancelAnimationFrame(raf);
15638
+ ro.disconnect();
13956
15639
  };
13957
15640
  }, [pathname, isEditMode, postToParent2]);
13958
- useEffect11(() => {
15641
+ useEffect12(() => {
13959
15642
  if (!subdomainFromQuery || isEditMode) return;
13960
15643
  const handleClick = (e) => {
13961
15644
  const anchor = e.target.closest("a");
@@ -13971,7 +15654,7 @@ function OhhwellsBridge() {
13971
15654
  document.addEventListener("click", handleClick, true);
13972
15655
  return () => document.removeEventListener("click", handleClick, true);
13973
15656
  }, [subdomainFromQuery, isEditMode, router]);
13974
- useEffect11(() => {
15657
+ useEffect12(() => {
13975
15658
  if (!isEditMode) {
13976
15659
  editStylesRef.current?.base.remove();
13977
15660
  editStylesRef.current?.forceHover.remove();
@@ -14100,6 +15783,7 @@ function OhhwellsBridge() {
14100
15783
  if (target.closest("[data-ohw-state-toggle]")) return;
14101
15784
  if (target.closest("[data-ohw-max-badge]")) return;
14102
15785
  if (isInsideLinkEditor(target)) return;
15786
+ if (isInsideFloatingPanel(target)) return;
14103
15787
  if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
14104
15788
  const beneath = document.elementsFromPoint(e.clientX, e.clientY).find(
14105
15789
  (el) => el instanceof HTMLElement && !el.closest("[data-ohw-bridge-root]") && el.closest("[data-ohw-section]") != null
@@ -14163,6 +15847,21 @@ function OhhwellsBridge() {
14163
15847
  return;
14164
15848
  }
14165
15849
  }
15850
+ const logoEl = getLogoElement(target);
15851
+ if (logoEl) {
15852
+ e.preventDefault();
15853
+ e.stopPropagation();
15854
+ if (!logoHasUploadedImage(logoEl)) {
15855
+ deselectRef.current();
15856
+ deactivateRef.current();
15857
+ const identity = readLogoIdentityFromDom();
15858
+ postToParentRef.current({ type: "ow:open-logo-settings", ...identity });
15859
+ return;
15860
+ }
15861
+ selectLogoRef.current(logoEl);
15862
+ openLogoSizePanelRef.current(logoEl);
15863
+ return;
15864
+ }
14166
15865
  const editable = target.closest("[data-ohw-editable]");
14167
15866
  if (editable) {
14168
15867
  if (editable.dataset.ohwEditable === "link") {
@@ -14179,6 +15878,17 @@ function OhhwellsBridge() {
14179
15878
  });
14180
15879
  return;
14181
15880
  }
15881
+ if (isIconEditable(editable) && !getSocialItem(editable)) {
15882
+ e.preventDefault();
15883
+ e.stopPropagation();
15884
+ aiSectionApiRef.current?.selectFromElement(editable);
15885
+ postToParentRef.current({
15886
+ type: "ow:icon-pick",
15887
+ key: editable.dataset.ohwKey ?? "",
15888
+ current: currentIconRef(editable)
15889
+ });
15890
+ return;
15891
+ }
14182
15892
  if (isMediaEditable(editable)) {
14183
15893
  e.preventDefault();
14184
15894
  e.stopPropagation();
@@ -14193,6 +15903,7 @@ function OhhwellsBridge() {
14193
15903
  e.stopPropagation();
14194
15904
  if (selectedElRef.current === navAnchor) {
14195
15905
  if (e.detail >= 2) return;
15906
+ if (requestSocialDialog(navAnchor, postToParentRef.current, editContentRef.current)) return;
14196
15907
  activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
14197
15908
  return;
14198
15909
  }
@@ -14209,6 +15920,7 @@ function OhhwellsBridge() {
14209
15920
  e.preventDefault();
14210
15921
  e.stopPropagation();
14211
15922
  if (selectedElRef.current === hrefAnchor) {
15923
+ if (requestSocialDialog(hrefAnchor, postToParentRef.current, editContentRef.current)) return;
14212
15924
  const textEditable = hrefAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefAnchor.querySelector("[data-ohw-editable]");
14213
15925
  if (textEditable) {
14214
15926
  activateRef.current(textEditable, {
@@ -14247,6 +15959,13 @@ function OhhwellsBridge() {
14247
15959
  selectFrameRef.current(navContainerToSelect);
14248
15960
  return;
14249
15961
  }
15962
+ const socialsRowToSelect = isSocialsRow(target) ? target : null;
15963
+ if (socialsRowToSelect && !getSocialItem(target)) {
15964
+ e.preventDefault();
15965
+ e.stopPropagation();
15966
+ selectFrameRef.current(socialsRowToSelect);
15967
+ return;
15968
+ }
14250
15969
  const footerColumnToSelect = resolveFooterColumnSelectionTarget(target, e.clientX, e.clientY);
14251
15970
  if (footerColumnToSelect) {
14252
15971
  e.preventDefault();
@@ -14295,9 +16014,11 @@ function OhhwellsBridge() {
14295
16014
  if (target.closest("[data-ohw-state-toggle]")) return;
14296
16015
  if (target.closest("[data-ohw-max-badge]")) return;
14297
16016
  if (isInsideLinkEditor(target)) return;
16017
+ if (isInsideFloatingPanel(target)) return;
14298
16018
  if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
14299
16019
  return;
14300
16020
  }
16021
+ if (getSocialItem(target)) return;
14301
16022
  const navLabel = getNavigationLabelEditable(target);
14302
16023
  const editable = navLabel?.editable ?? target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
14303
16024
  if (!editable || isMediaEditable(editable) || editable.dataset.ohwEditable === "link") return;
@@ -14321,6 +16042,16 @@ function OhhwellsBridge() {
14321
16042
  setHoveredNavContainerRect(null);
14322
16043
  return;
14323
16044
  }
16045
+ if (isInsideFloatingPanel(target) || isPointOverFloatingPanel(e.clientX, e.clientY)) {
16046
+ hoveredItemElRef.current = null;
16047
+ setHoveredItemRect(null);
16048
+ hoveredNavContainerRef.current = null;
16049
+ setHoveredNavContainerRect(null);
16050
+ siblingHintElRef.current = null;
16051
+ setSiblingHintRect(null);
16052
+ setSiblingHintRects([]);
16053
+ return;
16054
+ }
14324
16055
  {
14325
16056
  const selected2 = selectedElRef.current;
14326
16057
  const selectedIsFooterColumn = Boolean(selected2) && !isFooterLinksContainer(selected2) && (selected2.hasAttribute("data-ohw-footer-col") || selected2.hasAttribute("data-ohw-footer-column") || Boolean(selected2.closest("footer") && isInferredFooterGroup2(selected2)));
@@ -14328,7 +16059,7 @@ function OhhwellsBridge() {
14328
16059
  const allowFooterLinksHover = toolbarVariantRef.current !== "select-frame" || selectedIsFooterColumn;
14329
16060
  if (allowNavContainerHover) {
14330
16061
  const navContainer = target.closest("[data-ohw-nav-container]");
14331
- if (navContainer && !getNavigationItemAnchor(target)) {
16062
+ if (navContainer && !getNavigationItemAnchor(target) && !getLogoElement(target)) {
14332
16063
  hoveredNavContainerRef.current = navContainer;
14333
16064
  setHoveredNavContainerRect(navContainer.getBoundingClientRect());
14334
16065
  hoveredItemElRef.current = null;
@@ -14357,6 +16088,15 @@ function OhhwellsBridge() {
14357
16088
  setHoveredNavContainerRect(null);
14358
16089
  }
14359
16090
  }
16091
+ const logoEl = getLogoElement(target);
16092
+ if (logoEl) {
16093
+ hoveredNavContainerRef.current = null;
16094
+ setHoveredNavContainerRect(null);
16095
+ if (selectedElRef.current === logoEl) return;
16096
+ hoveredItemElRef.current = logoEl;
16097
+ setHoveredItemRect(getLogoInteractionRect(logoEl));
16098
+ return;
16099
+ }
14360
16100
  const navAnchor = getNavigationItemAnchor(target);
14361
16101
  if (navAnchor) {
14362
16102
  hoveredNavContainerRef.current = null;
@@ -14382,6 +16122,11 @@ function OhhwellsBridge() {
14382
16122
  const selected = selectedElRef.current;
14383
16123
  if (selected && (selected === editable || selected.contains(editable))) return;
14384
16124
  if (!isMediaEditable(editable) && !editable.hasAttribute("contenteditable")) {
16125
+ if (isIconEditable(editable) && !getSocialItem(editable)) {
16126
+ hoveredItemElRef.current = editable;
16127
+ setHoveredItemRect(editable.getBoundingClientRect());
16128
+ return;
16129
+ }
14385
16130
  const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
14386
16131
  if (hoverTarget.hasAttribute("data-ohw-href-key")) {
14387
16132
  clearHrefKeyHover(hoverTarget);
@@ -14389,6 +16134,12 @@ function OhhwellsBridge() {
14389
16134
  setHoveredItemRect(hoverTarget.getBoundingClientRect());
14390
16135
  } else if (!isInsideNavigationItem(editable)) {
14391
16136
  hoverTarget.setAttribute("data-ohw-hovered", "");
16137
+ if (editable.closest("footer") || editable.closest('[data-ohw-section="footer"]')) {
16138
+ hoveredNavContainerRef.current = null;
16139
+ setHoveredNavContainerRect(null);
16140
+ hoveredItemElRef.current = editable;
16141
+ setHoveredItemRect(editable.getBoundingClientRect());
16142
+ }
14392
16143
  }
14393
16144
  }
14394
16145
  };
@@ -14424,11 +16175,30 @@ function OhhwellsBridge() {
14424
16175
  }
14425
16176
  return;
14426
16177
  }
16178
+ const logoEl = getLogoElement(target);
16179
+ if (logoEl) {
16180
+ const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
16181
+ if (related2 && (logoEl === related2 || logoEl.contains(related2) || related2.closest?.('[data-ohw-role="logo"], [data-ohw-logo]'))) {
16182
+ return;
16183
+ }
16184
+ if (hoveredItemElRef.current === logoEl) {
16185
+ hoveredItemElRef.current = null;
16186
+ setHoveredItemRect(null);
16187
+ }
16188
+ return;
16189
+ }
14427
16190
  const editable = target.closest("[data-ohw-editable]");
14428
16191
  if (!editable) return;
14429
16192
  const related = e.relatedTarget instanceof Element ? e.relatedTarget : null;
14430
16193
  if (related?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
14431
16194
  if (!isMediaEditable(editable)) {
16195
+ if (isIconEditable(editable) && !getSocialItem(editable) && hoveredItemElRef.current === editable) {
16196
+ if (!related?.closest("[data-ohw-item-interaction]")) {
16197
+ hoveredItemElRef.current = null;
16198
+ setHoveredItemRect(null);
16199
+ }
16200
+ return;
16201
+ }
14432
16202
  const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
14433
16203
  if (hoverTarget.hasAttribute("data-ohw-href-key")) {
14434
16204
  if (!related?.closest("[data-ohw-href-key]")) {
@@ -14437,6 +16207,13 @@ function OhhwellsBridge() {
14437
16207
  }
14438
16208
  } else {
14439
16209
  hoverTarget.removeAttribute("data-ohw-hovered");
16210
+ if (hoveredItemElRef.current === editable) {
16211
+ const stillOnEditable = related instanceof Element && related.closest("[data-ohw-editable]") === editable;
16212
+ if (!stillOnEditable) {
16213
+ hoveredItemElRef.current = null;
16214
+ setHoveredItemRect(null);
16215
+ }
16216
+ }
14440
16217
  }
14441
16218
  }
14442
16219
  };
@@ -14553,6 +16330,26 @@ function OhhwellsBridge() {
14553
16330
  hoveredNavContainerRef.current = null;
14554
16331
  setHoveredNavContainerRect(null);
14555
16332
  }
16333
+ const logoCandidates = [
16334
+ ...document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]'),
16335
+ ...document.querySelectorAll("nav a:not([data-ohw-href-key]), [data-ohw-nav-root] a:not([data-ohw-href-key])"),
16336
+ ...document.querySelectorAll("footer img")
16337
+ ];
16338
+ const seenLogos = /* @__PURE__ */ new Set();
16339
+ for (const candidate of logoCandidates) {
16340
+ const logo = getLogoElement(candidate);
16341
+ if (!logo || seenLogos.has(logo)) continue;
16342
+ seenLogos.add(logo);
16343
+ const r2 = logo.getBoundingClientRect();
16344
+ if (x < r2.left || x > r2.right || y < r2.top || y > r2.bottom) continue;
16345
+ hoveredNavContainerRef.current = null;
16346
+ setHoveredNavContainerRect(null);
16347
+ if (selectedElRef.current !== logo) {
16348
+ hoveredItemElRef.current = logo;
16349
+ setHoveredItemRect(getLogoInteractionRect(logo));
16350
+ }
16351
+ return;
16352
+ }
14556
16353
  const navContainers = Array.from(
14557
16354
  document.querySelectorAll("[data-ohw-nav-container]")
14558
16355
  );
@@ -14638,7 +16435,7 @@ function OhhwellsBridge() {
14638
16435
  }
14639
16436
  };
14640
16437
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
14641
- if (linkPopoverOpenRef.current) {
16438
+ if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
14642
16439
  if (hoveredImageRef.current) {
14643
16440
  hoveredImageRef.current = null;
14644
16441
  hoveredImageHasTextOverlapRef.current = false;
@@ -14892,7 +16689,7 @@ function OhhwellsBridge() {
14892
16689
  }
14893
16690
  };
14894
16691
  const probeHoverCardsAt = (clientX, clientY, fromParentViewport = false) => {
14895
- if (linkPopoverOpenRef.current || document.documentElement.hasAttribute("data-ohw-section-picking")) {
16692
+ if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || document.documentElement.hasAttribute("data-ohw-section-picking")) {
14896
16693
  if (activeStateElRef.current) {
14897
16694
  activeStateElRef.current.removeAttribute("data-ohw-state-hovered");
14898
16695
  activeStateElRef.current = null;
@@ -14960,6 +16757,19 @@ function OhhwellsBridge() {
14960
16757
  };
14961
16758
  const handleMouseMove = (e) => {
14962
16759
  const { clientX, clientY } = e;
16760
+ if (floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
16761
+ hoveredItemElRef.current = null;
16762
+ setHoveredItemRect(null);
16763
+ hoveredNavContainerRef.current = null;
16764
+ setHoveredNavContainerRect(null);
16765
+ siblingHintElRef.current = null;
16766
+ setSiblingHintRect(null);
16767
+ setSiblingHintRects([]);
16768
+ dismissImageHover();
16769
+ clearImageHover();
16770
+ setSectionGap(null);
16771
+ return;
16772
+ }
14963
16773
  probeSectionGapAt(clientX, clientY);
14964
16774
  probeImageAt(clientX, clientY);
14965
16775
  probeHoverCardsAt(clientX, clientY);
@@ -14968,6 +16778,11 @@ function OhhwellsBridge() {
14968
16778
  if (e.data?.type !== "ow:pointer-sync") return;
14969
16779
  const { clientX, clientY } = e.data;
14970
16780
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
16781
+ if (floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
16782
+ dismissImageHover();
16783
+ clearImageHover();
16784
+ return;
16785
+ }
14971
16786
  probeSectionGapAt(clientX, clientY);
14972
16787
  probeImageAt(clientX, clientY);
14973
16788
  probeHoverCardsAt(clientX, clientY);
@@ -14977,7 +16792,7 @@ function OhhwellsBridge() {
14977
16792
  if (footerSession) {
14978
16793
  e.preventDefault();
14979
16794
  if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
14980
- const slot = footerSession.kind === "link" && footerSession.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, footerSession.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
16795
+ const slot = footerSession.kind === "social" && footerSession.hrefKey ? hitTestSocialDropSlot(e.clientX, e.clientY, footerSession.hrefKey) : footerSession.kind === "link" && footerSession.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, footerSession.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
14981
16796
  refreshFooterDragVisualsRef.current(footerSession, slot, e.clientX, e.clientY);
14982
16797
  return;
14983
16798
  }
@@ -15029,6 +16844,62 @@ function OhhwellsBridge() {
15029
16844
  resumeAnimTracks();
15030
16845
  clearImageHover();
15031
16846
  };
16847
+ const handleSocialCancel = (e) => {
16848
+ if (e.data?.type !== "ow:social-cancel") return;
16849
+ const { hrefKey } = e.data;
16850
+ const item = hrefKey ? findSocialByHrefKey(hrefKey) : null;
16851
+ if (!item) return;
16852
+ const removed = removeSocialItem(item, editContentRef.current);
16853
+ if (!removed) return;
16854
+ const orderJson = JSON.stringify(removed.order);
16855
+ editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
16856
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: SOCIALS_ORDER_KEY, text: orderJson }] });
16857
+ deselectRef.current();
16858
+ };
16859
+ const handleSocialUpdate = (e) => {
16860
+ if (e.data?.type !== "ow:social-update") return;
16861
+ const updates = Array.isArray(e.data.items) ? e.data.items : [e.data];
16862
+ const nodes = [];
16863
+ for (const { hrefKey, iconKey, url, iconMarkup, platformId, label } of updates) {
16864
+ if (hrefKey) {
16865
+ document.querySelectorAll(`[data-ohw-href-key="${hrefKey}"]`).forEach((el) => applyLinkHref(el, url));
16866
+ nodes.push({ key: hrefKey, text: url });
16867
+ }
16868
+ if (iconKey && typeof iconMarkup === "string" && iconMarkup) {
16869
+ document.querySelectorAll(`[data-ohw-key="${iconKey}"][data-ohw-editable="icon"]`).forEach((el) => {
16870
+ applyIconMarkup(el, iconMarkup);
16871
+ });
16872
+ nodes.push({ key: iconKey, text: iconMarkup });
16873
+ }
16874
+ if (iconKey && platformId) nodes.push({ key: socialPlatformKey(iconKey), text: platformId });
16875
+ if (iconKey && label) {
16876
+ const labelKey = socialLabelKey(iconKey);
16877
+ document.querySelectorAll(`[data-ohw-key="${labelKey}"]`).forEach((el) => {
16878
+ el.textContent = label;
16879
+ });
16880
+ nodes.push({ key: labelKey, text: label });
16881
+ }
16882
+ }
16883
+ if (!nodes.length) return;
16884
+ editContentRef.current = {
16885
+ ...editContentRef.current,
16886
+ ...Object.fromEntries(nodes.map((node) => [node.key, node.text]))
16887
+ };
16888
+ postToParentRef.current({ type: "ow:change", nodes, flush: true });
16889
+ };
16890
+ const handleIconMarkup = (e) => {
16891
+ if (e.data?.type !== "ow:icon-markup") return;
16892
+ const { key, markup } = e.data;
16893
+ if (!key || typeof markup !== "string") return;
16894
+ const targets = document.querySelectorAll(
16895
+ `[data-ohw-key="${key}"][data-ohw-editable="icon"]`
16896
+ );
16897
+ if (!targets.length) return;
16898
+ targets.forEach((el) => {
16899
+ applyIconMarkup(el, markup);
16900
+ });
16901
+ postToParentRef.current({ type: "ow:change", nodes: [{ key, text: markup }], flush: true });
16902
+ };
15032
16903
  const handleImageUrl = (e) => {
15033
16904
  if (e.data?.type !== "ow:image-url") return;
15034
16905
  const { key, url } = e.data;
@@ -15161,6 +17032,11 @@ function OhhwellsBridge() {
15161
17032
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
15162
17033
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
15163
17034
  }
17035
+ if (typeof content[BRAND_KIT_KEY] === "string") {
17036
+ brandKitRef.current = content[BRAND_KIT_KEY];
17037
+ applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17038
+ }
17039
+ applyBrandChrome(content);
15164
17040
  let sectionsJson = null;
15165
17041
  for (const [key, val] of Object.entries(content)) {
15166
17042
  if (key === "__ohw_sections") {
@@ -15168,6 +17044,10 @@ function OhhwellsBridge() {
15168
17044
  continue;
15169
17045
  }
15170
17046
  if (key === AI_SECTIONS_KEY) continue;
17047
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
17048
+ if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
17049
+ if (key === BRAND_KIT_KEY) continue;
17050
+ if (BRAND_CHROME_KEYS.has(key)) continue;
15171
17051
  if (applyVideoSettingNode(key, val)) continue;
15172
17052
  if (applyCarouselNode(key, val)) continue;
15173
17053
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -15187,6 +17067,8 @@ function OhhwellsBridge() {
15187
17067
  });
15188
17068
  applyLinkByKey(key, val);
15189
17069
  }
17070
+ applyLogoFromContent(content);
17071
+ applyLogoSizes(content);
15190
17072
  if (sectionsJson) {
15191
17073
  initSectionsFromContent({ __ohw_sections: sectionsJson }, true);
15192
17074
  sectionsLoadedRef.current = true;
@@ -15201,6 +17083,58 @@ function OhhwellsBridge() {
15201
17083
  if (hydratedHeight > 50) postToParentRef.current({ type: "ow:height", height: hydratedHeight });
15202
17084
  postToParentRef.current({ type: "ow:hydrate-done" });
15203
17085
  };
17086
+ const handleUpdateLogoIdentity = (e) => {
17087
+ if (e.data?.type !== "ow:update-logo-identity") return;
17088
+ const rawText = typeof e.data.text === "string" ? e.data.text : "";
17089
+ const alt = typeof e.data.alt === "string" ? e.data.alt : rawText;
17090
+ const href = typeof e.data.href === "string" ? e.data.href : void 0;
17091
+ const imageProvided = "image" in e.data;
17092
+ const imageUrl = imageProvided && typeof e.data.image === "string" && e.data.image.trim() ? e.data.image.trim() : imageProvided ? null : void 0;
17093
+ let isPlaceholder = e.data.isPlaceholder !== false;
17094
+ if (imageUrl) isPlaceholder = false;
17095
+ else if (imageProvided && imageUrl === null) {
17096
+ isPlaceholder = e.data.isPlaceholder === true || !rawText.trim() || resolveLogoDisplayText(rawText) === PLACEHOLDER_BUSINESS_NAME;
17097
+ }
17098
+ const display = applyLogoIdentity(rawText, isPlaceholder);
17099
+ const displayAlt = resolveLogoDisplayText(alt || display);
17100
+ if (imageUrl !== void 0) {
17101
+ applyLogoImage(imageUrl, displayAlt);
17102
+ } else {
17103
+ for (const key of LOGO_IMAGE_KEYS) {
17104
+ document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
17105
+ const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
17106
+ if (img) img.alt = displayAlt;
17107
+ });
17108
+ }
17109
+ }
17110
+ if (href !== void 0) {
17111
+ applyLogoHref(href);
17112
+ applyLinkByKey("nav-logo-href", href);
17113
+ applyLinkByKey("footer-logo-href", href);
17114
+ applyLinkByKey("logo-href", href);
17115
+ }
17116
+ const nodes = [
17117
+ ...LOGO_TEXT_KEYS.map((key) => ({ key, text: display })),
17118
+ { key: LOGO_PLACEHOLDER_KEY, text: isPlaceholder ? "true" : "false" },
17119
+ { key: LOGO_ALT_KEY, text: displayAlt }
17120
+ ];
17121
+ if (imageUrl !== void 0) {
17122
+ if (imageUrl) {
17123
+ for (const key of LOGO_IMAGE_KEYS) nodes.push({ key, text: imageUrl });
17124
+ } else {
17125
+ for (const key of LOGO_IMAGE_KEYS) nodes.push({ key, text: "" });
17126
+ }
17127
+ }
17128
+ if (href !== void 0) {
17129
+ for (const key of LOGO_HREF_KEYS) nodes.push({ key, text: href.trim() || "/" });
17130
+ }
17131
+ editContentRef.current = {
17132
+ ...editContentRef.current,
17133
+ ...Object.fromEntries(nodes.map(({ key, text }) => [key, text]))
17134
+ };
17135
+ applyLogoSizes(editContentRef.current);
17136
+ postToParentRef.current({ type: "ow:change", nodes });
17137
+ };
15204
17138
  window.addEventListener("message", handleHydrate);
15205
17139
  const postAiSectionsChanged = () => {
15206
17140
  postToParentRef.current({
@@ -15257,6 +17191,17 @@ function OhhwellsBridge() {
15257
17191
  postAiSectionsChanged();
15258
17192
  };
15259
17193
  window.addEventListener("message", handleAiSetSections);
17194
+ const handleAiSetBrand = (e) => {
17195
+ if (e.data?.type !== "ow:ai-set-brand") return;
17196
+ const value = typeof e.data.value === "string" ? e.data.value : "";
17197
+ const previous = brandKitRef.current;
17198
+ brandKitRef.current = value;
17199
+ applyBrandToDom(parseBrandKit(value));
17200
+ if (aiSectionsRef.current) applyAiSectionsToDom(parseAiSectionsState(aiSectionsRef.current));
17201
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: BRAND_KIT_KEY, text: value }] });
17202
+ postToParentRef.current({ type: "ow:ai-brand-applied", previous, value });
17203
+ };
17204
+ window.addEventListener("message", handleAiSetBrand);
15260
17205
  const handleDeactivate = (e) => {
15261
17206
  if (e.data?.type !== "ow:deactivate") return;
15262
17207
  if (Date.now() < linkPopoverGraceUntilRef.current) return;
@@ -15265,6 +17210,12 @@ function OhhwellsBridge() {
15265
17210
  closeLinkPopoverRef.current();
15266
17211
  return;
15267
17212
  }
17213
+ if (floatingPanelOpenRef.current) {
17214
+ setFloatingPanelRef.current(null);
17215
+ deselectRef.current();
17216
+ deactivateRef.current();
17217
+ return;
17218
+ }
15268
17219
  deselectRef.current();
15269
17220
  deactivateRef.current();
15270
17221
  };
@@ -15284,6 +17235,10 @@ function OhhwellsBridge() {
15284
17235
  closeLinkPopoverRef.current();
15285
17236
  return;
15286
17237
  }
17238
+ if (floatingPanelOpenRef.current) {
17239
+ closeFloatingPanelOnlyRef.current();
17240
+ return;
17241
+ }
15287
17242
  if (activeElRef.current) {
15288
17243
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
15289
17244
  const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
@@ -15314,6 +17269,10 @@ function OhhwellsBridge() {
15314
17269
  return;
15315
17270
  }
15316
17271
  if (selectedElRef.current) {
17272
+ if (toolbarVariantRef.current === "logo") {
17273
+ deselectRef.current();
17274
+ return;
17275
+ }
15317
17276
  if (toolbarVariantRef.current === "select-frame") {
15318
17277
  const parent2 = getNavigationSelectionParent(selectedElRef.current);
15319
17278
  if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
@@ -15347,7 +17306,16 @@ function OhhwellsBridge() {
15347
17306
  closeLinkPopoverRef.current();
15348
17307
  return;
15349
17308
  }
17309
+ if (e.key === "Escape" && floatingPanelOpenRef.current) {
17310
+ e.preventDefault();
17311
+ closeFloatingPanelOnlyRef.current();
17312
+ return;
17313
+ }
15350
17314
  if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
17315
+ if (toolbarVariantRef.current === "logo") {
17316
+ deselectRef.current();
17317
+ return;
17318
+ }
15351
17319
  if (toolbarVariantRef.current === "select-frame") {
15352
17320
  const parent2 = getNavigationSelectionParent(selectedElRef.current);
15353
17321
  if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
@@ -15425,7 +17393,8 @@ function OhhwellsBridge() {
15425
17393
  const handleScroll = () => {
15426
17394
  const focusEl = activeElRef.current ?? selectedElRef.current;
15427
17395
  if (focusEl) {
15428
- const r2 = activeElRef.current ? getEditMeasureEl(activeElRef.current).getBoundingClientRect() : focusEl.getBoundingClientRect();
17396
+ const measureEl = activeElRef.current ? getEditMeasureEl(activeElRef.current) : toolbarVariantRef.current === "logo" ? null : focusEl;
17397
+ const r2 = measureEl ? measureEl.getBoundingClientRect() : toolbarVariantRef.current === "logo" ? getLogoInteractionRect(focusEl) : focusEl.getBoundingClientRect();
15429
17398
  applyToolbarPos(r2);
15430
17399
  setToolbarRect(r2);
15431
17400
  setMaxBadge((prev) => prev && activeElRef.current ? { ...prev, rect: r2 } : prev);
@@ -15435,7 +17404,9 @@ function OhhwellsBridge() {
15435
17404
  setToggleState((prev) => prev ? { ...prev, rect } : null);
15436
17405
  }
15437
17406
  if (hoveredItemElRef.current) {
15438
- setHoveredItemRect(hoveredItemElRef.current.getBoundingClientRect());
17407
+ const hoverEl = hoveredItemElRef.current;
17408
+ const logo = getLogoElement(hoverEl);
17409
+ setHoveredItemRect(logo ? getLogoInteractionRect(logo) : hoverEl.getBoundingClientRect());
15439
17410
  }
15440
17411
  if (hoveredNavContainerRef.current) {
15441
17412
  setHoveredNavContainerRect(hoveredNavContainerRef.current.getBoundingClientRect());
@@ -15455,7 +17426,7 @@ function OhhwellsBridge() {
15455
17426
  }
15456
17427
  if (footerDragRef.current) {
15457
17428
  const session = footerDragRef.current;
15458
- const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
17429
+ const slot = session.kind === "social" && session.hrefKey ? hitTestSocialDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
15459
17430
  refreshFooterDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
15460
17431
  }
15461
17432
  if (navDragRef.current) {
@@ -15479,6 +17450,9 @@ function OhhwellsBridge() {
15479
17450
  if (aiSectionsRef.current) {
15480
17451
  nodes.push({ key: AI_SECTIONS_KEY, type: "sections", text: aiSectionsRef.current });
15481
17452
  }
17453
+ if (brandKitRef.current) {
17454
+ nodes.push({ key: BRAND_KIT_KEY, type: "brand", text: brandKitRef.current });
17455
+ }
15482
17456
  postToParentRef.current({ type: "ow:save-result", nodes });
15483
17457
  };
15484
17458
  const handleInsertSection = (e) => {
@@ -15489,8 +17463,12 @@ function OhhwellsBridge() {
15489
17463
  if (inserted) {
15490
17464
  const tracker = getSectionsTracker();
15491
17465
  postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
15492
- const h = document.documentElement.scrollHeight;
15493
- if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
17466
+ const reportHeight = () => {
17467
+ const h = document.body.scrollHeight;
17468
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
17469
+ };
17470
+ reportHeight();
17471
+ setTimeout(reportHeight, 500);
15494
17472
  }
15495
17473
  };
15496
17474
  const handleSwitchSchedule = (e) => {
@@ -15683,13 +17661,17 @@ function OhhwellsBridge() {
15683
17661
  if (e.data?.type !== "ow:parent-scroll") return;
15684
17662
  const { iframeOffsetTop, headerH, canvasH } = e.data;
15685
17663
  parentScrollRef.current = { iframeOffsetTop, headerH, canvasH };
17664
+ if (floatingPanelOpenRef.current) {
17665
+ setParentScrollSnap({ iframeOffsetTop, headerH, canvasH });
17666
+ }
15686
17667
  if (visibleViewportRef.current) {
15687
17668
  applyVisibleViewport(visibleViewportRef.current, parentScrollRef.current);
15688
17669
  }
15689
17670
  const focusEl = activeElRef.current ?? selectedElRef.current;
15690
17671
  if (focusEl) {
15691
- const measureEl = activeElRef.current ? getEditMeasureEl(activeElRef.current) : focusEl;
15692
- applyToolbarPos(measureEl.getBoundingClientRect());
17672
+ const measureEl = activeElRef.current ? getEditMeasureEl(activeElRef.current) : toolbarVariantRef.current === "logo" ? null : focusEl;
17673
+ const r2 = measureEl ? measureEl.getBoundingClientRect() : toolbarVariantRef.current === "logo" ? getLogoInteractionRect(focusEl) : focusEl.getBoundingClientRect();
17674
+ applyToolbarPos(r2);
15693
17675
  }
15694
17676
  };
15695
17677
  const handleClickAt = (e) => {
@@ -15714,6 +17696,25 @@ function OhhwellsBridge() {
15714
17696
  postToParentRef.current({ type: "ow:image-pick", key: stateCardImage.dataset.ohwKey ?? "", elementType: stateCardImage.dataset.ohwEditable ?? "image" });
15715
17697
  return;
15716
17698
  }
17699
+ const logoAtPoint = Array.from(
17700
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]')
17701
+ ).map((el) => getLogoElement(el)).find((logo) => {
17702
+ if (!logo) return false;
17703
+ const r2 = logo.getBoundingClientRect();
17704
+ return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
17705
+ });
17706
+ if (logoAtPoint) {
17707
+ if (!logoHasUploadedImage(logoAtPoint)) {
17708
+ deselectRef.current();
17709
+ deactivateRef.current();
17710
+ const identity = readLogoIdentityFromDom();
17711
+ postToParentRef.current({ type: "ow:open-logo-settings", ...identity });
17712
+ return;
17713
+ }
17714
+ selectLogoRef.current(logoAtPoint);
17715
+ openLogoSizePanelRef.current(logoAtPoint);
17716
+ return;
17717
+ }
15717
17718
  const textEditable = Array.from(
15718
17719
  document.querySelectorAll(NON_MEDIA_SELECTOR)
15719
17720
  ).find((el) => {
@@ -15775,6 +17776,9 @@ function OhhwellsBridge() {
15775
17776
  window.addEventListener("message", handleClearSchedulingWidget);
15776
17777
  window.addEventListener("message", handleRemoveSchedulingSection);
15777
17778
  window.addEventListener("message", handleCollectSection);
17779
+ window.addEventListener("message", handleSocialCancel);
17780
+ window.addEventListener("message", handleSocialUpdate);
17781
+ window.addEventListener("message", handleIconMarkup);
15778
17782
  window.addEventListener("message", handleImageUrl);
15779
17783
  window.addEventListener("message", handleImageUploading);
15780
17784
  window.addEventListener("message", handleCarouselChange);
@@ -15782,6 +17786,14 @@ function OhhwellsBridge() {
15782
17786
  window.addEventListener("message", handleParentScroll);
15783
17787
  window.addEventListener("message", handlePointerSync);
15784
17788
  window.addEventListener("message", handleClickAt);
17789
+ window.addEventListener("message", handleUpdateLogoIdentity);
17790
+ const handleViewMode = (e) => {
17791
+ if (e.data?.type !== "ow:view-mode") return;
17792
+ const mode = e.data.mode === "Mobile" || e.data.mode === "mobile" ? "mobile" : "desktop";
17793
+ setEditorViewport(mode);
17794
+ applyLogoSizes(editContentRef.current);
17795
+ };
17796
+ window.addEventListener("message", handleViewMode);
15785
17797
  const handleViewportResize = () => {
15786
17798
  if (visibleViewportRef.current) {
15787
17799
  applyVisibleViewport(visibleViewportRef.current, parentScrollRef.current);
@@ -15826,6 +17838,9 @@ function OhhwellsBridge() {
15826
17838
  window.removeEventListener("message", handleClearSchedulingWidget);
15827
17839
  window.removeEventListener("message", handleRemoveSchedulingSection);
15828
17840
  window.removeEventListener("message", handleCollectSection);
17841
+ window.removeEventListener("message", handleSocialCancel);
17842
+ window.removeEventListener("message", handleSocialUpdate);
17843
+ window.removeEventListener("message", handleIconMarkup);
15829
17844
  window.removeEventListener("message", handleImageUrl);
15830
17845
  window.removeEventListener("message", handleImageUploading);
15831
17846
  window.removeEventListener("message", handleCarouselChange);
@@ -15834,10 +17849,13 @@ function OhhwellsBridge() {
15834
17849
  window.removeEventListener("resize", handleViewportResize);
15835
17850
  window.removeEventListener("message", handlePointerSync);
15836
17851
  window.removeEventListener("message", handleClickAt);
17852
+ window.removeEventListener("message", handleUpdateLogoIdentity);
17853
+ window.removeEventListener("message", handleViewMode);
15837
17854
  window.removeEventListener("message", handleHydrate);
15838
17855
  window.removeEventListener("message", handleAiApplyTree);
15839
17856
  window.removeEventListener("message", handleAiDeleteSection);
15840
17857
  window.removeEventListener("message", handleAiSetSections);
17858
+ window.removeEventListener("message", handleAiSetBrand);
15841
17859
  window.removeEventListener("message", handleDeactivate);
15842
17860
  window.removeEventListener("message", handleToastAction);
15843
17861
  window.removeEventListener("message", handleUiEscape);
@@ -15847,7 +17865,7 @@ function OhhwellsBridge() {
15847
17865
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
15848
17866
  };
15849
17867
  }, [isEditMode, refreshStateRules]);
15850
- useEffect11(() => {
17868
+ useEffect12(() => {
15851
17869
  if (!isEditMode) return;
15852
17870
  const THRESHOLD = 10;
15853
17871
  const resolveWasSelected = (el) => {
@@ -15867,9 +17885,9 @@ function OhhwellsBridge() {
15867
17885
  return;
15868
17886
  }
15869
17887
  if (target.closest("[data-ohw-item-drag-surface]")) return;
15870
- const anchor = getNavigationItemAnchor(target);
17888
+ const anchor = getNavigationItemAnchor(target) ?? (document.elementsFromPoint(e.clientX, e.clientY).map((el) => el instanceof HTMLElement ? getNavigationItemAnchor(el) : null).find((found) => found !== null) ?? null);
15871
17889
  const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
15872
- if (anchor && isFooterHrefKey(hrefKey)) {
17890
+ if (anchor && (isFooterHrefKey(hrefKey) || getSocialItem(anchor))) {
15873
17891
  footerPointerDragRef.current = {
15874
17892
  el: anchor,
15875
17893
  kind: "link",
@@ -15902,7 +17920,7 @@ function OhhwellsBridge() {
15902
17920
  clearTextSelection();
15903
17921
  const session = footerDragRef.current;
15904
17922
  if (!session) return;
15905
- const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, session.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
17923
+ const slot = session.kind === "social" && session.hrefKey ? hitTestSocialDropSlot(e.clientX, e.clientY, session.hrefKey) : session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, session.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
15906
17924
  refreshFooterDragVisualsRef.current(session, slot, e.clientX, e.clientY);
15907
17925
  return;
15908
17926
  }
@@ -15929,7 +17947,7 @@ function OhhwellsBridge() {
15929
17947
  const column = findFooterColumnForLink(pending.el);
15930
17948
  const columns2 = listFooterColumns();
15931
17949
  beginFooterDragRef.current({
15932
- kind: "link",
17950
+ kind: getSocialItem(pending.el) ? "social" : "link",
15933
17951
  hrefKey: key,
15934
17952
  columnEl: column,
15935
17953
  sourceColumnIndex: column ? columns2.indexOf(column) : 0,
@@ -16001,7 +18019,7 @@ function OhhwellsBridge() {
16001
18019
  unlockFooterDragInteraction();
16002
18020
  };
16003
18021
  }, [isEditMode]);
16004
- useEffect11(() => {
18022
+ useEffect12(() => {
16005
18023
  const handler = (e) => {
16006
18024
  if (e.data?.type !== "ow:request-schedule-config") return;
16007
18025
  const insertAfterVal = e.data.insertAfter;
@@ -16017,7 +18035,7 @@ function OhhwellsBridge() {
16017
18035
  window.addEventListener("message", handler);
16018
18036
  return () => window.removeEventListener("message", handler);
16019
18037
  }, [processConfigRequest]);
16020
- useEffect11(() => {
18038
+ useEffect12(() => {
16021
18039
  if (!isEditMode) return;
16022
18040
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
16023
18041
  el.removeAttribute("data-ohw-active-state");
@@ -16041,7 +18059,7 @@ function OhhwellsBridge() {
16041
18059
  postToParent2({
16042
18060
  type: "ow:ready",
16043
18061
  version: "1",
16044
- bridgeVersion: "0.1.54",
18062
+ bridgeVersion: "0.1.55",
16045
18063
  path: pathname,
16046
18064
  nodes: collectEditableNodes(editContentRef.current),
16047
18065
  sections
@@ -16053,13 +18071,13 @@ function OhhwellsBridge() {
16053
18071
  clearTimeout(timer);
16054
18072
  };
16055
18073
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
16056
- useEffect11(() => {
18074
+ useEffect12(() => {
16057
18075
  scrollToHashSectionWhenReady();
16058
18076
  const onHashChange = () => scrollToHashSectionWhenReady();
16059
18077
  window.addEventListener("hashchange", onHashChange);
16060
18078
  return () => window.removeEventListener("hashchange", onHashChange);
16061
18079
  }, [pathname]);
16062
- const handleCommand = useCallback6((cmd) => {
18080
+ const handleCommand = useCallback7((cmd) => {
16063
18081
  const el = activeElRef.current;
16064
18082
  const selBefore = window.getSelection();
16065
18083
  let savedOffsets = null;
@@ -16095,7 +18113,7 @@ function OhhwellsBridge() {
16095
18113
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
16096
18114
  refreshActiveCommandsRef.current();
16097
18115
  }, []);
16098
- const handleStateChange = useCallback6((state) => {
18116
+ const handleStateChange = useCallback7((state) => {
16099
18117
  if (!activeStateElRef.current) return;
16100
18118
  const el = activeStateElRef.current;
16101
18119
  if (state === "Default") {
@@ -16108,7 +18126,7 @@ function OhhwellsBridge() {
16108
18126
  }
16109
18127
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
16110
18128
  }, [deactivate]);
16111
- const reselectAfterLinkPopover = useCallback6(
18129
+ const reselectAfterLinkPopover = useCallback7(
16112
18130
  (hrefKey) => {
16113
18131
  requestAnimationFrame(() => {
16114
18132
  const el = resolveHrefKeyElement(hrefKey);
@@ -16117,7 +18135,7 @@ function OhhwellsBridge() {
16117
18135
  },
16118
18136
  [resolveHrefKeyElement]
16119
18137
  );
16120
- const closeLinkPopover = useCallback6(() => {
18138
+ const closeLinkPopover = useCallback7(() => {
16121
18139
  const session = linkPopoverSessionRef.current;
16122
18140
  addNavAfterAnchorRef.current = null;
16123
18141
  setLinkPopover(null);
@@ -16125,9 +18143,9 @@ function OhhwellsBridge() {
16125
18143
  reselectAfterLinkPopover(session.key);
16126
18144
  }
16127
18145
  }, [reselectAfterLinkPopover]);
16128
- const closeLinkPopoverRef = useRef8(closeLinkPopover);
18146
+ const closeLinkPopoverRef = useRef9(closeLinkPopover);
16129
18147
  closeLinkPopoverRef.current = closeLinkPopover;
16130
- const openLinkPopoverForActive = useCallback6(() => {
18148
+ const openLinkPopoverForActive = useCallback7(() => {
16131
18149
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
16132
18150
  if (!hrefCtx) return;
16133
18151
  bumpLinkPopoverGrace();
@@ -16138,11 +18156,15 @@ function OhhwellsBridge() {
16138
18156
  });
16139
18157
  deactivate();
16140
18158
  }, [deactivate]);
16141
- const openLinkPopoverForSelected = useCallback6(() => {
18159
+ const openLinkPopoverForSelected = useCallback7(() => {
16142
18160
  const anchor = selectedElRef.current;
16143
18161
  if (!anchor) return;
16144
18162
  const key = anchor.getAttribute("data-ohw-href-key");
16145
18163
  if (!key) return;
18164
+ if (requestSocialDialog(anchor, postToParentRef.current, editContentRef.current)) {
18165
+ deselect();
18166
+ return;
18167
+ }
16146
18168
  bumpLinkPopoverGrace();
16147
18169
  setLinkPopover({
16148
18170
  key,
@@ -16151,7 +18173,7 @@ function OhhwellsBridge() {
16151
18173
  });
16152
18174
  deselect();
16153
18175
  }, [deselect]);
16154
- const handleSelectParent = useCallback6(() => {
18176
+ const handleSelectParent = useCallback7(() => {
16155
18177
  const selected = selectedElRef.current;
16156
18178
  if (!selected) return;
16157
18179
  if (toolbarVariantRef.current === "select-frame") {
@@ -16178,11 +18200,37 @@ function OhhwellsBridge() {
16178
18200
  }
16179
18201
  deselectRef.current();
16180
18202
  }, []);
16181
- const handleDuplicateSelected = useCallback6(() => {
18203
+ const handleDuplicateSelected = useCallback7(() => {
16182
18204
  const selected = selectedElRef.current;
16183
18205
  if (!selected || !isNavigationItem2(selected)) return;
16184
18206
  const hrefKey = selected.getAttribute("data-ohw-href-key");
16185
18207
  if (!hrefKey) return;
18208
+ const social = getSocialItem(selected);
18209
+ if (social) {
18210
+ const result = duplicateSocialItem(social, editContentRef.current);
18211
+ if (!result) return;
18212
+ const orderJson = JSON.stringify(result.order);
18213
+ const carried = [
18214
+ { from: result.copiedFrom?.href, to: result.hrefKey },
18215
+ { from: result.copiedFrom?.icon, to: result.iconKey },
18216
+ { from: result.copiedFrom?.icon ? socialPlatformKey(result.copiedFrom.icon) : null, to: socialPlatformKey(result.iconKey) }
18217
+ ];
18218
+ const nodes = [{ key: SOCIALS_ORDER_KEY, text: orderJson }];
18219
+ for (const { from, to } of carried) {
18220
+ const value = from ? editContentRef.current[from] : void 0;
18221
+ if (value) nodes.push({ key: to, text: value });
18222
+ }
18223
+ editContentRef.current = {
18224
+ ...editContentRef.current,
18225
+ ...Object.fromEntries(nodes.map((node) => [node.key, node.text]))
18226
+ };
18227
+ postToParent2({ type: "ow:change", nodes });
18228
+ enforceLinkHrefs();
18229
+ const copyRow = findSocialsRow(result.item);
18230
+ if (copyRow) applySocialsDisplayToRow(copyRow, socialsDisplayFor(copyRow, editContentRef.current));
18231
+ requestAnimationFrame(() => selectRef.current(result.item));
18232
+ return;
18233
+ }
16186
18234
  if (isNavbarHrefKey(hrefKey)) {
16187
18235
  const result = duplicateNavbarItem(selected);
16188
18236
  if (!result) return;
@@ -16268,7 +18316,7 @@ function OhhwellsBridge() {
16268
18316
  });
16269
18317
  }
16270
18318
  }, [postToParent2]);
16271
- const runPendingDeleteUndo = useCallback6(() => {
18319
+ const runPendingDeleteUndo = useCallback7(() => {
16272
18320
  const pending = pendingDeleteUndoRef.current;
16273
18321
  if (!pending) return false;
16274
18322
  pendingDeleteUndoRef.current = null;
@@ -16276,7 +18324,7 @@ function OhhwellsBridge() {
16276
18324
  enforceLinkHrefs();
16277
18325
  return true;
16278
18326
  }, []);
16279
- const handleDeleteSelected = useCallback6(() => {
18327
+ const handleDeleteSelected = useCallback7(() => {
16280
18328
  const selected = selectedElRef.current;
16281
18329
  if (!selected) return false;
16282
18330
  return deleteSelectedNavFooterItem({
@@ -16297,7 +18345,7 @@ function OhhwellsBridge() {
16297
18345
  }, [postToParent2]);
16298
18346
  handleDeleteSelectedRef.current = handleDeleteSelected;
16299
18347
  runPendingDeleteUndoRef.current = runPendingDeleteUndo;
16300
- const handleLinkPopoverSubmit = useCallback6(
18348
+ const handleLinkPopoverSubmit = useCallback7(
16301
18349
  (target) => {
16302
18350
  const session = linkPopoverSessionRef.current;
16303
18351
  if (!session) return;
@@ -16363,19 +18411,19 @@ function OhhwellsBridge() {
16363
18411
  const showEditLink = toolbarShowEditLink;
16364
18412
  const currentSections = sectionsByPath[pathname] ?? [];
16365
18413
  linkPopoverOpenRef.current = linkPopover !== null;
16366
- const handleMediaReplace = useCallback6(
18414
+ const handleMediaReplace = useCallback7(
16367
18415
  (key) => {
16368
18416
  postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
16369
18417
  },
16370
18418
  [postToParent2, mediaHover?.elementType]
16371
18419
  );
16372
- const handleEditCarousel = useCallback6(
18420
+ const handleEditCarousel = useCallback7(
16373
18421
  (key) => {
16374
18422
  postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
16375
18423
  },
16376
18424
  [postToParent2]
16377
18425
  );
16378
- const handleMediaFadeOutComplete = useCallback6((key) => {
18426
+ const handleMediaFadeOutComplete = useCallback7((key) => {
16379
18427
  setUploadingRects((prev) => {
16380
18428
  if (!(key in prev)) return prev;
16381
18429
  const next = { ...prev };
@@ -16383,7 +18431,7 @@ function OhhwellsBridge() {
16383
18431
  return next;
16384
18432
  });
16385
18433
  }, []);
16386
- const handleVideoSettingsChange = useCallback6(
18434
+ const handleVideoSettingsChange = useCallback7(
16387
18435
  (key, settings) => {
16388
18436
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
16389
18437
  const video = getVideoEl2(el);
@@ -16406,10 +18454,10 @@ function OhhwellsBridge() {
16406
18454
  [postToParent2]
16407
18455
  );
16408
18456
  return bridgeRoot ? createPortal2(
16409
- /* @__PURE__ */ jsxs17(Fragment8, { children: [
16410
- /* @__PURE__ */ jsx30("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
16411
- isEditMode && /* @__PURE__ */ jsx30(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
16412
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx30(
18457
+ /* @__PURE__ */ jsxs20(Fragment8, { children: [
18458
+ /* @__PURE__ */ jsx33("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
18459
+ isEditMode && /* @__PURE__ */ jsx33(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
18460
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx33(
16413
18461
  MediaOverlay,
16414
18462
  {
16415
18463
  hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
@@ -16420,7 +18468,7 @@ function OhhwellsBridge() {
16420
18468
  },
16421
18469
  `uploading-${key}`
16422
18470
  )),
16423
- mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx30(
18471
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx33(
16424
18472
  MediaOverlay,
16425
18473
  {
16426
18474
  hover: mediaHover,
@@ -16429,11 +18477,11 @@ function OhhwellsBridge() {
16429
18477
  onVideoSettingsChange: handleVideoSettingsChange
16430
18478
  }
16431
18479
  ),
16432
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx30(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
16433
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx30(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
16434
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx30(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
16435
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx30(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
16436
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx30(
18480
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
18481
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
18482
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
18483
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
18484
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
16437
18485
  "div",
16438
18486
  {
16439
18487
  className: "pointer-events-none fixed z-2147483646",
@@ -16443,7 +18491,7 @@ function OhhwellsBridge() {
16443
18491
  width: slot.width,
16444
18492
  height: slot.height
16445
18493
  },
16446
- children: /* @__PURE__ */ jsx30(
18494
+ children: /* @__PURE__ */ jsx33(
16447
18495
  DropIndicator,
16448
18496
  {
16449
18497
  direction: slot.direction,
@@ -16454,7 +18502,7 @@ function OhhwellsBridge() {
16454
18502
  },
16455
18503
  `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
16456
18504
  )),
16457
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx30(
18505
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
16458
18506
  "div",
16459
18507
  {
16460
18508
  className: "pointer-events-none fixed z-2147483646",
@@ -16464,7 +18512,7 @@ function OhhwellsBridge() {
16464
18512
  width: slot.width,
16465
18513
  height: slot.height
16466
18514
  },
16467
- children: /* @__PURE__ */ jsx30(
18515
+ children: /* @__PURE__ */ jsx33(
16468
18516
  DropIndicator,
16469
18517
  {
16470
18518
  direction: slot.direction,
@@ -16475,10 +18523,10 @@ function OhhwellsBridge() {
16475
18523
  },
16476
18524
  `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
16477
18525
  )),
16478
- hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx30(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
16479
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx30(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
16480
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ jsx30(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
16481
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx30(
18526
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
18527
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
18528
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ jsx33(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
18529
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx33(
16482
18530
  FooterContainerChrome,
16483
18531
  {
16484
18532
  rect: toolbarRect,
@@ -16486,7 +18534,7 @@ function OhhwellsBridge() {
16486
18534
  addDisabled: !canAddFooterColumn()
16487
18535
  }
16488
18536
  ),
16489
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx30(
18537
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ jsx33(
16490
18538
  ItemInteractionLayer,
16491
18539
  {
16492
18540
  rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
@@ -16498,13 +18546,21 @@ function OhhwellsBridge() {
16498
18546
  dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
16499
18547
  onDragHandleDragStart: handleItemDragStart,
16500
18548
  onDragHandleDragEnd: handleItemDragEnd,
16501
- onItemPointerDown: handleItemChromePointerDown,
16502
- onItemClick: handleItemChromeClick,
16503
- itemDragSurface: !isFooterFrameSelection,
16504
- toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && isFooterFrameSelection && !isItemDragging ? /* @__PURE__ */ jsx30(
18549
+ onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
18550
+ onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
18551
+ itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
18552
+ toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ jsx33(
16505
18553
  ItemActionToolbar,
16506
18554
  {
16507
18555
  onEditLink: openLinkPopoverForSelected,
18556
+ onStyle: () => {
18557
+ const row = selectedElRef.current;
18558
+ if (!row) return;
18559
+ if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
18560
+ else openSocialsDisplayPanel(row);
18561
+ },
18562
+ showStyle: selectedIsSocialsRow,
18563
+ styleActive: floatingPanel?.kind === "socials-display",
16508
18564
  onAddItem: handleAddChildItem,
16509
18565
  onSelectParent: handleSelectParent,
16510
18566
  onDuplicate: handleDuplicateSelected,
@@ -16512,12 +18568,12 @@ function OhhwellsBridge() {
16512
18568
  addItemDisabled: false,
16513
18569
  editLinkDisabled: false,
16514
18570
  moreDisabled: false,
16515
- duplicateDisabled: isFooterFrameSelection,
16516
- showEditLink: !isFooterFrameSelection && navDropdownPreviewOpen === null,
16517
- showAddItem: isFooterFrameSelection || !selectedIsCta && Boolean(
18571
+ duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
18572
+ showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
18573
+ showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
16518
18574
  selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
16519
18575
  ),
16520
- showMore: !selectedIsCta || isFooterFrameSelection,
18576
+ showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
16521
18577
  dropdownOpen: navDropdownPreviewOpen,
16522
18578
  onDropdownOpenChange: handleNavDropdownOpenChange,
16523
18579
  headingVisible: footerHeadingVisible,
@@ -16526,8 +18582,8 @@ function OhhwellsBridge() {
16526
18582
  ) : void 0
16527
18583
  }
16528
18584
  ),
16529
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs17(Fragment8, { children: [
16530
- /* @__PURE__ */ jsx30(
18585
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs20(Fragment8, { children: [
18586
+ /* @__PURE__ */ jsx33(
16531
18587
  EditGlowChrome,
16532
18588
  {
16533
18589
  rect: toolbarRect,
@@ -16537,7 +18593,7 @@ function OhhwellsBridge() {
16537
18593
  hideHandle: isItemDragging
16538
18594
  }
16539
18595
  ),
16540
- /* @__PURE__ */ jsx30(
18596
+ /* @__PURE__ */ jsx33(
16541
18597
  FloatingToolbar,
16542
18598
  {
16543
18599
  rect: toolbarRect,
@@ -16550,7 +18606,7 @@ function OhhwellsBridge() {
16550
18606
  }
16551
18607
  )
16552
18608
  ] }),
16553
- maxBadge && /* @__PURE__ */ jsxs17(
18609
+ maxBadge && /* @__PURE__ */ jsxs20(
16554
18610
  "div",
16555
18611
  {
16556
18612
  "data-ohw-max-badge": "",
@@ -16576,7 +18632,7 @@ function OhhwellsBridge() {
16576
18632
  ]
16577
18633
  }
16578
18634
  ),
16579
- toggleState && !linkPopover && /* @__PURE__ */ jsx30(
18635
+ toggleState && !linkPopover && /* @__PURE__ */ jsx33(
16580
18636
  StateToggle,
16581
18637
  {
16582
18638
  rect: toggleState.rect,
@@ -16585,15 +18641,15 @@ function OhhwellsBridge() {
16585
18641
  onStateChange: handleStateChange
16586
18642
  }
16587
18643
  ),
16588
- sectionGap && !linkPopover && /* @__PURE__ */ jsxs17(
18644
+ sectionGap && !linkPopover && /* @__PURE__ */ jsxs20(
16589
18645
  "div",
16590
18646
  {
16591
18647
  "data-ohw-section-insert-line": "",
16592
18648
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
16593
18649
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
16594
18650
  children: [
16595
- /* @__PURE__ */ jsx30("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
16596
- /* @__PURE__ */ jsx30(
18651
+ /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
18652
+ /* @__PURE__ */ jsx33(
16597
18653
  Badge,
16598
18654
  {
16599
18655
  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",
@@ -16610,11 +18666,11 @@ function OhhwellsBridge() {
16610
18666
  children: "Add Section"
16611
18667
  }
16612
18668
  ),
16613
- /* @__PURE__ */ jsx30("div", { className: "flex-1 bg-primary", style: { height: 3 } })
18669
+ /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } })
16614
18670
  ]
16615
18671
  }
16616
18672
  ),
16617
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx30(
18673
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx33(
16618
18674
  LinkPopover,
16619
18675
  {
16620
18676
  panelRef: linkPopoverPanelRef,
@@ -16630,11 +18686,137 @@ function OhhwellsBridge() {
16630
18686
  onSubmit: handleLinkPopoverSubmit
16631
18687
  },
16632
18688
  linkPopover.key
18689
+ ) : null,
18690
+ floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ jsx33(
18691
+ FloatingPanel,
18692
+ {
18693
+ open: true,
18694
+ title: floatingPanel.title,
18695
+ context: floatingPanel.context,
18696
+ position: floatingPanelPos,
18697
+ onPositionChange: setFloatingPanelPos,
18698
+ parentScroll: parentScrollSnap ?? parentScrollRef.current,
18699
+ onClose: closeFloatingPanelOnly,
18700
+ children: /* @__PURE__ */ jsx33(
18701
+ SocialsDisplayPanel,
18702
+ {
18703
+ display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
18704
+ onChange: (next) => {
18705
+ changeSocialsDisplay(floatingPanel.row, next);
18706
+ setFloatingPanel({ ...floatingPanel });
18707
+ }
18708
+ }
18709
+ )
18710
+ }
18711
+ ) : null,
18712
+ floatingPanel && floatingPanel.kind === "logo-size" && logoSizeDraft ? /* @__PURE__ */ jsx33(
18713
+ FloatingPanel,
18714
+ {
18715
+ open: true,
18716
+ title: floatingPanel.title,
18717
+ context: floatingPanel.context,
18718
+ position: floatingPanelPos,
18719
+ onPositionChange: setFloatingPanelPos,
18720
+ parentScroll: parentScrollSnap ?? parentScrollRef.current,
18721
+ onClose: closeFloatingPanelAndDeselect,
18722
+ children: /* @__PURE__ */ jsx33(
18723
+ LogoSizePanel,
18724
+ {
18725
+ viewport: editorViewport,
18726
+ sizePx: editorViewport === "mobile" && !logoSizeDraft.mobileFollowing ? logoSizeDraft.mobilePx : logoSizeDraft.desktopPx,
18727
+ mobileFollowing: logoSizeDraft.mobileFollowing,
18728
+ onSizeChange: (px) => {
18729
+ const next = editorViewport === "mobile" ? { ...logoSizeDraft, mobilePx: px, mobileFollowing: false } : {
18730
+ ...logoSizeDraft,
18731
+ desktopPx: px,
18732
+ mobilePx: logoSizeDraft.mobileFollowing ? px : logoSizeDraft.mobilePx
18733
+ };
18734
+ setLogoSizeDraft(next);
18735
+ persistLogoSizeDraft(floatingPanel.placement, next);
18736
+ },
18737
+ onCustomizeMobile: () => {
18738
+ const next = {
18739
+ ...logoSizeDraft,
18740
+ mobileFollowing: false,
18741
+ mobilePx: logoSizeDraft.desktopPx
18742
+ };
18743
+ setLogoSizeDraft(next);
18744
+ persistLogoSizeDraft(floatingPanel.placement, next);
18745
+ },
18746
+ onResetMobile: () => {
18747
+ const next = {
18748
+ ...logoSizeDraft,
18749
+ mobileFollowing: true,
18750
+ mobilePx: logoSizeDraft.desktopPx
18751
+ };
18752
+ setLogoSizeDraft(next);
18753
+ persistLogoSizeDraft(floatingPanel.placement, next);
18754
+ },
18755
+ onUpdateEverywhere: () => {
18756
+ const identity = readLogoIdentityFromDom();
18757
+ postToParent2({ type: "ow:open-logo-settings", ...identity });
18758
+ }
18759
+ }
18760
+ )
18761
+ }
16633
18762
  ) : null
16634
18763
  ] }),
16635
18764
  bridgeRoot
16636
18765
  ) : null;
16637
18766
  }
18767
+
18768
+ // src/ui/EmptySection.tsx
18769
+ import Link4 from "next/link";
18770
+ import { Fragment as Fragment9, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
18771
+ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
18772
+ return /* @__PURE__ */ jsxs21(Fragment9, { children: [
18773
+ /* @__PURE__ */ jsx34(
18774
+ "p",
18775
+ {
18776
+ style: {
18777
+ fontFamily: "var(--brand-font-body)",
18778
+ fontSize: "0.75rem",
18779
+ fontWeight: 500,
18780
+ letterSpacing: "0.15em",
18781
+ textTransform: "uppercase",
18782
+ color: "var(--brand-accent)",
18783
+ marginBottom: "1.5rem"
18784
+ },
18785
+ children: /* @__PURE__ */ jsx34(Link4, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ jsx34("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
18786
+ }
18787
+ ),
18788
+ /* @__PURE__ */ jsx34(
18789
+ "h1",
18790
+ {
18791
+ style: {
18792
+ fontFamily: "var(--brand-font-heading)",
18793
+ fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
18794
+ lineHeight: 1.1,
18795
+ letterSpacing: "-0.025em",
18796
+ color: "var(--brand-text)",
18797
+ marginBottom: "1rem"
18798
+ },
18799
+ ...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
18800
+ children: title
18801
+ }
18802
+ ),
18803
+ /* @__PURE__ */ jsx34(
18804
+ "p",
18805
+ {
18806
+ style: {
18807
+ fontFamily: "var(--brand-font-body)",
18808
+ fontSize: "1rem",
18809
+ lineHeight: 1.7,
18810
+ fontWeight: 300,
18811
+ color: "var(--brand-text-muted)",
18812
+ maxWidth: "340px"
18813
+ },
18814
+ ...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
18815
+ children: "This page doesn't have any content yet."
18816
+ }
18817
+ )
18818
+ ] });
18819
+ }
16638
18820
  export {
16639
18821
  AI_DEFAULT_BRAND,
16640
18822
  AI_TREE_SCHEMA_VERSIONS,
@@ -16651,6 +18833,7 @@ export {
16651
18833
  DropdownMenuItem,
16652
18834
  DropdownMenuSeparator,
16653
18835
  DropdownMenuTrigger,
18836
+ EmptySection,
16654
18837
  ItemActionToolbar,
16655
18838
  ItemInteractionLayer,
16656
18839
  LinkEditorPanel,