@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.cjs CHANGED
@@ -46,6 +46,7 @@ __export(index_exports, {
46
46
  DropdownMenuItem: () => DropdownMenuItem,
47
47
  DropdownMenuSeparator: () => DropdownMenuSeparator,
48
48
  DropdownMenuTrigger: () => DropdownMenuTrigger,
49
+ EmptySection: () => EmptySection,
49
50
  ItemActionToolbar: () => ItemActionToolbar,
50
51
  ItemInteractionLayer: () => ItemInteractionLayer,
51
52
  LinkEditorPanel: () => LinkEditorPanel,
@@ -74,7 +75,7 @@ __export(index_exports, {
74
75
  module.exports = __toCommonJS(index_exports);
75
76
 
76
77
  // src/OhhwellsBridge.tsx
77
- var import_react15 = __toESM(require("react"), 1);
78
+ var import_react16 = __toESM(require("react"), 1);
78
79
  var import_client2 = require("react-dom/client");
79
80
  var import_react_dom3 = require("react-dom");
80
81
 
@@ -191,6 +192,129 @@ function deleteSectionFromState(state, sectionId) {
191
192
  return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
192
193
  }
193
194
 
195
+ // src/lib/brand-chrome.ts
196
+ var BRAND_NAME_KEY = "__ohw_brand_name";
197
+ var BRAND_TITLE_KEY = "__ohw_site_title";
198
+ var BRAND_FAVICON_LETTER_KEY = "__ohw_favicon_letter";
199
+ var BRAND_CHROME_KEYS = /* @__PURE__ */ new Set([
200
+ BRAND_NAME_KEY,
201
+ BRAND_TITLE_KEY,
202
+ BRAND_FAVICON_LETTER_KEY
203
+ ]);
204
+ function upsertMeta(selector, attr, token, value) {
205
+ let el = document.head.querySelector(selector);
206
+ if (!el) {
207
+ el = document.createElement("meta");
208
+ el.setAttribute(attr, token);
209
+ document.head.appendChild(el);
210
+ }
211
+ if (el.getAttribute("content") !== value) el.setAttribute("content", value);
212
+ }
213
+ function escapeXml(value) {
214
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
215
+ }
216
+ function applyLetterFavicon(letter) {
217
+ 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>`;
218
+ const href = `data:image/svg+xml,${encodeURIComponent(svg)}`;
219
+ let link = document.head.querySelector('link[rel="icon"]');
220
+ if (!link) {
221
+ link = document.createElement("link");
222
+ link.rel = "icon";
223
+ document.head.appendChild(link);
224
+ }
225
+ link.type = "image/svg+xml";
226
+ if (link.href !== href) link.href = href;
227
+ }
228
+ function applyBrandChrome(content) {
229
+ const name = content[BRAND_NAME_KEY];
230
+ if (typeof name === "string" && name.length > 0) {
231
+ document.querySelectorAll("[data-ohw-wordmark]").forEach((el) => {
232
+ if (el.textContent !== name) el.textContent = name;
233
+ if (el.getAttribute("title") !== name) el.setAttribute("title", name);
234
+ });
235
+ }
236
+ const title = content[BRAND_TITLE_KEY];
237
+ if (typeof title === "string" && title.length > 0) {
238
+ if (document.title !== title) document.title = title;
239
+ upsertMeta('meta[property="og:title"]', "property", "og:title", title);
240
+ upsertMeta('meta[name="twitter:title"]', "name", "twitter:title", title);
241
+ }
242
+ const letter = content[BRAND_FAVICON_LETTER_KEY];
243
+ if (typeof letter === "string" && letter.length > 0) {
244
+ applyLetterFavicon(letter);
245
+ }
246
+ }
247
+
248
+ // src/lib/brand-kit.ts
249
+ var BRAND_KIT_KEY = "__ohw_brand";
250
+ var BRAND_VAR_PREFIX = "--ohw-brand-";
251
+ var BRAND_VAR_NAMES = ["primary", "accent", "light", "dark", "surface", "border", "muted"].map(
252
+ (role) => `${BRAND_VAR_PREFIX}${role}`
253
+ );
254
+ var FONT_VARS = { heading: ["--font-heading", "--font-display"], body: ["--font-body"] };
255
+ var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
256
+ function brandColorVars(kit) {
257
+ const { dark, primary, accent, light } = kit.palette;
258
+ const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
259
+ return {
260
+ [`${BRAND_VAR_PREFIX}primary`]: primary,
261
+ [`${BRAND_VAR_PREFIX}accent`]: accent,
262
+ [`${BRAND_VAR_PREFIX}light`]: light,
263
+ [`${BRAND_VAR_PREFIX}dark`]: dark,
264
+ [`${BRAND_VAR_PREFIX}surface`]: mix(light, 95, dark),
265
+ [`${BRAND_VAR_PREFIX}border`]: mix(light, 85, dark),
266
+ [`${BRAND_VAR_PREFIX}muted`]: mix(dark, 62, light)
267
+ };
268
+ }
269
+ function parseBrandKit(raw) {
270
+ if (!raw) return null;
271
+ try {
272
+ const parsed = JSON.parse(raw);
273
+ const p = parsed?.palette;
274
+ const f = parsed?.fonts;
275
+ 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") {
276
+ return null;
277
+ }
278
+ return {
279
+ palette: { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light },
280
+ fonts: { heading: f.heading, body: f.body }
281
+ };
282
+ } catch {
283
+ return null;
284
+ }
285
+ }
286
+ function familyOf(stack) {
287
+ const first = stack.split(",")[0]?.trim() ?? "";
288
+ return first.replace(/^['"]|['"]$/g, "");
289
+ }
290
+ function loadBrandFonts(families) {
291
+ const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
292
+ if (unique.length === 0) return;
293
+ const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
294
+ const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
295
+ let link = document.getElementById(BRAND_FONT_LINK_ID);
296
+ if (!link) {
297
+ link = document.createElement("link");
298
+ link.id = BRAND_FONT_LINK_ID;
299
+ link.rel = "stylesheet";
300
+ document.head.appendChild(link);
301
+ }
302
+ if (link.href !== href) link.href = href;
303
+ }
304
+ function applyBrandToDom(kit) {
305
+ const root = document.documentElement;
306
+ if (!kit) {
307
+ for (const name of BRAND_VAR_NAMES) root.style.removeProperty(name);
308
+ for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
309
+ document.getElementById(BRAND_FONT_LINK_ID)?.remove();
310
+ return;
311
+ }
312
+ for (const [name, value] of Object.entries(brandColorVars(kit))) root.style.setProperty(name, value);
313
+ for (const name of FONT_VARS.heading) root.style.setProperty(name, kit.fonts.heading);
314
+ for (const name of FONT_VARS.body) root.style.setProperty(name, kit.fonts.body);
315
+ loadBrandFonts([familyOf(kit.fonts.heading), familyOf(kit.fonts.body)]);
316
+ }
317
+
194
318
  // src/ui/ai-tree/aiSectionsManager.tsx
195
319
  var import_react_dom = require("react-dom");
196
320
  var import_client = require("react-dom/client");
@@ -235,13 +359,17 @@ function MediaBox({
235
359
  const url = refValue ? ctx.resolveMedia(refValue) : null;
236
360
  const isIcon = /^(lucide|simple):/.test(refValue);
237
361
  const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
238
- const editAttrs = ctx.keyFor && editPath && !isIcon ? { "data-ohw-key": ctx.keyFor(editPath), "data-ohw-editable": "image" } : {};
362
+ const editAttrs = ctx.keyFor && editPath ? {
363
+ "data-ohw-key": ctx.keyFor(editPath),
364
+ "data-ohw-editable": isIcon ? "icon" : "image"
365
+ } : {};
239
366
  if (isIcon) {
240
367
  const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
241
368
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
242
369
  "span",
243
370
  {
244
371
  "data-ai-icon": refValue,
372
+ ...editAttrs,
245
373
  style: {
246
374
  display: "inline-flex",
247
375
  width: 48,
@@ -1273,17 +1401,34 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
1273
1401
  var CONTAINER_ATTR = "data-ohw-ai-generated";
1274
1402
  var REPLACED_ATTR = "data-ohw-ai-replaced-by";
1275
1403
  var REMOVED_ATTR = "data-ohw-ai-removed";
1404
+ function readRootVar(name) {
1405
+ if (typeof document === "undefined") return "";
1406
+ return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
1407
+ }
1408
+ function deriveBrandOverride() {
1409
+ const dark = readRootVar("--ohw-brand-dark");
1410
+ const primary = readRootVar("--ohw-brand-primary");
1411
+ const light = readRootVar("--ohw-brand-light");
1412
+ if (!dark || !primary || !light) return null;
1413
+ const accent = readRootVar("--ohw-brand-accent");
1414
+ const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1415
+ const body = readRootVar("--font-body");
1416
+ return {
1417
+ palette: { dark, primary, accent: accent || dark, light },
1418
+ fonts: {
1419
+ heading: heading || AI_DEFAULT_BRAND.fonts.heading,
1420
+ body: body || AI_DEFAULT_BRAND.fonts.body
1421
+ }
1422
+ };
1423
+ }
1276
1424
  function deriveTemplateBrand() {
1277
- if (typeof document === "undefined") return null;
1278
- const cs = getComputedStyle(document.documentElement);
1279
- const read = (name) => cs.getPropertyValue(name).trim();
1280
- const dark = read("--color-dark");
1281
- const primary = read("--color-primary");
1282
- const light = read("--color-light");
1425
+ const dark = readRootVar("--color-dark");
1426
+ const primary = readRootVar("--color-primary");
1427
+ const light = readRootVar("--color-light");
1283
1428
  if (!dark || !primary || !light) return null;
1284
- const accent = read("--color-accent");
1285
- const heading = read("--font-heading") || read("--font-display");
1286
- const body = read("--font-body");
1429
+ const accent = readRootVar("--color-accent");
1430
+ const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1431
+ const body = readRootVar("--font-body");
1287
1432
  return {
1288
1433
  palette: { dark, primary, accent: accent || dark, light },
1289
1434
  fonts: {
@@ -1375,7 +1520,9 @@ function syncReplacedOriginals(state) {
1375
1520
  }
1376
1521
  function applyAiSectionsToDom(state, options) {
1377
1522
  if (typeof document === "undefined") return;
1523
+ const brandOverride = deriveBrandOverride();
1378
1524
  const templateBrand = deriveTemplateBrand();
1525
+ const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
1379
1526
  const activeIds = new Set(state.sections.map((entry) => entry.id));
1380
1527
  for (const [id, section] of mounted) {
1381
1528
  if (!activeIds.has(id)) {
@@ -1385,7 +1532,7 @@ function applyAiSectionsToDom(state, options) {
1385
1532
  }
1386
1533
  }
1387
1534
  for (const entry of state.sections) {
1388
- const serialized = JSON.stringify(entry);
1535
+ const serialized = JSON.stringify(entry) + brandKey;
1389
1536
  const existing = mounted.get(entry.id);
1390
1537
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
1391
1538
  continue;
@@ -1409,7 +1556,7 @@ function applyAiSectionsToDom(state, options) {
1409
1556
  AiTreeRenderer,
1410
1557
  {
1411
1558
  tree: entry.tree,
1412
- brand: entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1559
+ brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1413
1560
  resolveMedia,
1414
1561
  editKeyPrefix: `ai.${entry.id}`
1415
1562
  }
@@ -2026,7 +2173,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2026
2173
  const autoId = (0, import_react5.useId)();
2027
2174
  const insertAfter = insertAfterProp ?? autoId;
2028
2175
  const [schedule, setSchedule] = (0, import_react5.useState)(null);
2029
- const [loading, setLoading] = (0, import_react5.useState)(true);
2176
+ const [loading, setLoading] = (0, import_react5.useState)(initialScheduleId !== null);
2030
2177
  const [inEditor, setInEditor] = (0, import_react5.useState)(false);
2031
2178
  const [isHovered, setIsHovered] = (0, import_react5.useState)(false);
2032
2179
  const [modalState, setModalState] = (0, import_react5.useState)(null);
@@ -2200,8 +2347,10 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2200
2347
  "*"
2201
2348
  );
2202
2349
  };
2203
- if (!inEditor && !loading && !schedule) return null;
2204
2350
  const sectionId = `scheduling-${insertAfter}`;
2351
+ if (!inEditor && !loading && !schedule) {
2352
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("section", { "data-ohw-section": sectionId, "data-ohw-scheduling-anchor": insertAfter, style: { display: "none" } });
2353
+ }
2205
2354
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2206
2355
  "section",
2207
2356
  {
@@ -5935,6 +6084,7 @@ function ToolbarActionTooltip({
5935
6084
  function ItemActionToolbar({
5936
6085
  onEditLink,
5937
6086
  onAddItem,
6087
+ onStyle,
5938
6088
  onSelectParent,
5939
6089
  onDuplicate,
5940
6090
  onDelete,
@@ -5946,6 +6096,8 @@ function ItemActionToolbar({
5946
6096
  deleteDisabled = false,
5947
6097
  showEditLink = true,
5948
6098
  showAddItem = true,
6099
+ showStyle = false,
6100
+ styleActive = false,
5949
6101
  showMore = true,
5950
6102
  tooltipSide = "bottom",
5951
6103
  dropdownOpen = null,
@@ -6019,6 +6171,22 @@ function ItemActionToolbar({
6019
6171
  children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Link, { className: "size-4 shrink-0", "aria-hidden": true })
6020
6172
  }
6021
6173
  ) : null,
6174
+ showStyle ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6175
+ ToolbarActionTooltip,
6176
+ {
6177
+ label: "Style",
6178
+ side: tooltipSide,
6179
+ buttonProps: {
6180
+ active: styleActive,
6181
+ onMouseDown: (e) => {
6182
+ e.preventDefault();
6183
+ e.stopPropagation();
6184
+ onStyle?.();
6185
+ }
6186
+ },
6187
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Brush, { className: "size-4 shrink-0", "aria-hidden": true })
6188
+ }
6189
+ ) : null,
6022
6190
  showAddItem ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
6023
6191
  ToolbarActionTooltip,
6024
6192
  {
@@ -9525,6 +9693,449 @@ function deleteNavbarItem(sourceAnchor) {
9525
9693
  };
9526
9694
  }
9527
9695
 
9696
+ // src/lib/icon-markup.ts
9697
+ var GLYPH_SELECTOR = "svg, img";
9698
+ function referenceBox(slot) {
9699
+ const row = slot.closest("[data-ohw-socials-row]") ?? slot.closest("a")?.parentElement ?? null;
9700
+ const neighbour = row ? Array.from(row.querySelectorAll('[data-ohw-editable="icon"]')).find((el) => el !== slot) : null;
9701
+ const source = (neighbour ?? slot).querySelector(GLYPH_SELECTOR);
9702
+ const box = source?.getBoundingClientRect() ?? null;
9703
+ return box?.width && box.height ? box : null;
9704
+ }
9705
+ function iconMarkupSizedFor(slot, markup) {
9706
+ const box = referenceBox(slot);
9707
+ if (!box) return markup;
9708
+ const holder = document.createElement("div");
9709
+ holder.innerHTML = markup;
9710
+ const glyph = holder.querySelector(GLYPH_SELECTOR);
9711
+ if (!glyph) return markup;
9712
+ glyph.style.width = `${Math.round(box.width)}px`;
9713
+ glyph.style.height = `${Math.round(box.height)}px`;
9714
+ return holder.innerHTML;
9715
+ }
9716
+ function applyIconMarkup(slot, markup) {
9717
+ if (!markup) return;
9718
+ const coloured = iconMarkupInheritingColour(markup);
9719
+ const sized = iconMarkupSizedFor(slot, coloured);
9720
+ if (slot.innerHTML !== sized) slot.innerHTML = sized;
9721
+ if (sized === coloured) {
9722
+ requestAnimationFrame(() => {
9723
+ if (!slot.isConnected) return;
9724
+ const resized = iconMarkupSizedFor(slot, coloured);
9725
+ if (resized !== coloured && slot.innerHTML !== resized) slot.innerHTML = resized;
9726
+ });
9727
+ }
9728
+ }
9729
+ function detectIconStyle(el) {
9730
+ const row = el.closest("[data-ohw-socials-row]");
9731
+ const glyphs = Array.from((row ?? el).querySelectorAll("svg"));
9732
+ const outlined = glyphs.some((svg) => {
9733
+ return Array.from(svg.querySelectorAll("*")).some((node) => {
9734
+ return node.getAttribute("stroke") !== null && node.getAttribute("stroke") !== "none";
9735
+ });
9736
+ });
9737
+ return outlined ? "outline" : "fill";
9738
+ }
9739
+ function iconMarkupInheritingColour(markup) {
9740
+ const holder = document.createElement("div");
9741
+ holder.innerHTML = markup;
9742
+ holder.querySelectorAll("svg *").forEach((node) => {
9743
+ if (node.getAttribute("fill") && node.getAttribute("fill") !== "none") {
9744
+ node.setAttribute("fill", "currentColor");
9745
+ }
9746
+ if (node.getAttribute("stroke") && node.getAttribute("stroke") !== "none") {
9747
+ node.setAttribute("stroke", "currentColor");
9748
+ }
9749
+ });
9750
+ return holder.innerHTML;
9751
+ }
9752
+
9753
+ // src/lib/socials-items.ts
9754
+ var ICON_SELECTOR = '[data-ohw-editable="icon"]';
9755
+ var SOCIAL_KEY_RE = /(^|-)social(s)?(-|$)/i;
9756
+ var SOCIALS_ROW_ATTR = "data-ohw-socials-row";
9757
+ var SOCIALS_ITEM_ATTR = "data-ohw-social-item";
9758
+ function isSocialItem(el) {
9759
+ if (!el) return false;
9760
+ const anchor = el instanceof HTMLAnchorElement ? el : el.closest("a");
9761
+ if (!anchor) return false;
9762
+ if (SOCIAL_KEY_RE.test(anchor.getAttribute("data-ohw-href-key") ?? "")) return true;
9763
+ return anchor.querySelectorAll(ICON_SELECTOR).length === 1;
9764
+ }
9765
+ function getSocialItem(el) {
9766
+ const anchor = el.closest("a");
9767
+ return isSocialItem(anchor) ? anchor : null;
9768
+ }
9769
+ function findSocialsRow(el) {
9770
+ const item = getSocialItem(el);
9771
+ if (!item) return null;
9772
+ const wrapper = item.parentElement;
9773
+ const row = wrapper && wrapper.querySelectorAll("a").length === 1 && wrapper.matches("li, div, span") ? wrapper.parentElement : wrapper;
9774
+ if (!row) return null;
9775
+ const anchors = Array.from(row.querySelectorAll("a"));
9776
+ if (!anchors.length || !anchors.every((anchor) => isSocialItem(anchor))) return null;
9777
+ return row;
9778
+ }
9779
+ function isSocialsRow(el) {
9780
+ const anchors = Array.from(el.querySelectorAll("a"));
9781
+ return anchors.length > 0 && anchors.every((anchor) => isSocialItem(anchor));
9782
+ }
9783
+ function listSocialItems(row) {
9784
+ return Array.from(row.children).map((child) => {
9785
+ if (!(child instanceof HTMLElement)) return null;
9786
+ const anchor = child.matches("a") ? child : child.querySelector("a");
9787
+ return isSocialItem(anchor) ? anchor : null;
9788
+ }).filter((item) => item !== null);
9789
+ }
9790
+ function socialRowUnit(item) {
9791
+ const row = findSocialsRow(item);
9792
+ let node = item;
9793
+ while (node.parentElement && node.parentElement !== row) {
9794
+ node = node.parentElement;
9795
+ }
9796
+ return node;
9797
+ }
9798
+ function listSocialsRows(root = document) {
9799
+ const rows = /* @__PURE__ */ new Set();
9800
+ root.querySelectorAll(`${ICON_SELECTOR}, a[data-ohw-href-key]`).forEach((el) => {
9801
+ const row = findSocialsRow(el);
9802
+ if (row) rows.add(row);
9803
+ });
9804
+ root.querySelectorAll(`[${SOCIALS_ROW_ATTR}]`).forEach((row) => rows.add(row));
9805
+ return Array.from(rows);
9806
+ }
9807
+ var rowTemplates = /* @__PURE__ */ new Map();
9808
+ function markSocialsRows(root = document) {
9809
+ root.querySelectorAll(`[${SOCIALS_ITEM_ATTR}]`).forEach((item) => {
9810
+ item.removeAttribute(SOCIALS_ITEM_ATTR);
9811
+ });
9812
+ listSocialsRows(root).forEach((row) => {
9813
+ row.setAttribute(SOCIALS_ROW_ATTR, "");
9814
+ const items = listSocialItems(row);
9815
+ if (items[0]) rowTemplates.set(rowKeyOf(row), socialRowUnit(items[0]).outerHTML);
9816
+ items.forEach((item, index) => {
9817
+ item.setAttribute(SOCIALS_ITEM_ATTR, String(index));
9818
+ const iconKey = socialIconKey(item);
9819
+ if (iconKey) ensureLabelSlot(item, iconKey);
9820
+ });
9821
+ });
9822
+ }
9823
+ var SOCIALS_LABEL_ATTR = "data-ohw-social-label";
9824
+ function ensureLabelSlot(item, iconKey) {
9825
+ if (socialLabelElement(item)) return;
9826
+ const label = document.createElement("span");
9827
+ label.setAttribute("data-ohw-key", `${iconKey}-label`);
9828
+ label.setAttribute("data-ohw-editable", "text");
9829
+ label.setAttribute(SOCIALS_LABEL_ATTR, "");
9830
+ label.style.display = "none";
9831
+ label.textContent = item.getAttribute("aria-label") ?? "";
9832
+ item.appendChild(label);
9833
+ }
9834
+ function socialLabelElement(item) {
9835
+ return item.querySelector(
9836
+ `[${SOCIALS_LABEL_ATTR}], [data-ohw-editable="text"], [data-ohw-editable="plain"]`
9837
+ );
9838
+ }
9839
+ function socialLabelKey(iconKey) {
9840
+ return `${iconKey}-label`;
9841
+ }
9842
+ function applyStoredValues(item, content) {
9843
+ const hrefKey = socialHrefKey(item);
9844
+ const iconKey = socialIconKey(item);
9845
+ if (hrefKey && content[hrefKey] !== void 0) item.setAttribute("href", content[hrefKey]);
9846
+ if (iconKey) {
9847
+ const glyph = item.querySelector(ICON_SELECTOR);
9848
+ if (glyph && content[iconKey]) applyIconMarkup(glyph, content[iconKey]);
9849
+ const label = item.querySelector(`[${SOCIALS_LABEL_ATTR}]`);
9850
+ label?.setAttribute("data-ohw-key", socialLabelKey(iconKey));
9851
+ const stored = content[socialLabelKey(iconKey)];
9852
+ if (label && stored) label.textContent = stored;
9853
+ }
9854
+ }
9855
+ function socialPlatformKey(iconKey) {
9856
+ return `${iconKey}-platform`;
9857
+ }
9858
+ function socialHrefKey(item) {
9859
+ return item.getAttribute("data-ohw-href-key");
9860
+ }
9861
+ function socialIconKey(item) {
9862
+ return item.querySelector(ICON_SELECTOR)?.dataset.ohwKey ?? null;
9863
+ }
9864
+ var SOCIALS_ORDER_KEY = "__ohw_socials_order";
9865
+ function fromMarkup(markup) {
9866
+ const holder = document.createElement("div");
9867
+ holder.innerHTML = markup;
9868
+ return holder.firstElementChild instanceof HTMLElement ? holder.firstElementChild : null;
9869
+ }
9870
+ var rowKeys = /* @__PURE__ */ new WeakMap();
9871
+ function rowKeyOf(row) {
9872
+ const first = listSocialItems(row)[0];
9873
+ const itemKey = first ? socialIconKey(first) ?? socialHrefKey(first)?.replace(/-href$/, "") : null;
9874
+ const derived = itemKey?.replace(/-[^-]+$/, "") || null;
9875
+ if (derived) rowKeys.set(row, derived);
9876
+ return derived ?? rowKeys.get(row) ?? "social";
9877
+ }
9878
+ function getSocialsOrderFromDom(root = document) {
9879
+ const order = {};
9880
+ listSocialsRows(root).forEach((row) => {
9881
+ order[rowKeyOf(row)] = listSocialItems(row).map((item) => socialHrefKey(item)).filter((key) => Boolean(key));
9882
+ });
9883
+ return order;
9884
+ }
9885
+ function hasStoredValue(content, hrefKey) {
9886
+ const iconKey = hrefKey.replace(/-href$/, "");
9887
+ return Boolean(content[hrefKey]) || Boolean(content[iconKey]);
9888
+ }
9889
+ function parseSocialsOrder(raw) {
9890
+ if (!raw) return null;
9891
+ try {
9892
+ const parsed = JSON.parse(raw);
9893
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
9894
+ } catch {
9895
+ return null;
9896
+ }
9897
+ }
9898
+ function nextSocialIndex(row, rowKey, content) {
9899
+ 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));
9900
+ return Math.max(-1, ...used) + 1;
9901
+ }
9902
+ function insertSocialItem(row, after, content = {}) {
9903
+ const rowKey = rowKeyOf(row);
9904
+ const template = listSocialItems(row)[0];
9905
+ const remembered = rowTemplates.get(rowKey);
9906
+ if (!template && !remembered) return null;
9907
+ const index = nextSocialIndex(row, rowKey, content);
9908
+ const iconKey = `${rowKey}-${index}`;
9909
+ const hrefKey = `${iconKey}-href`;
9910
+ const templateUnit = template ? socialRowUnit(template) : null;
9911
+ const unit = templateUnit ? templateUnit.cloneNode(true) : fromMarkup(remembered);
9912
+ const item = unit && (unit.matches("a") ? unit : unit.querySelector("a"));
9913
+ if (!unit || !item) return null;
9914
+ item.setAttribute("data-ohw-href-key", hrefKey);
9915
+ item.setAttribute("href", "");
9916
+ item.removeAttribute("aria-label");
9917
+ item.querySelectorAll("[data-ohw-hovered], [data-ohw-selected]").forEach((el) => {
9918
+ el.removeAttribute("data-ohw-hovered");
9919
+ el.removeAttribute("data-ohw-selected");
9920
+ });
9921
+ const icon = item.querySelector(ICON_SELECTOR);
9922
+ icon?.setAttribute("data-ohw-key", iconKey);
9923
+ item.querySelector(`[${SOCIALS_LABEL_ATTR}]`)?.remove();
9924
+ const afterUnit = after ? socialRowUnit(after) : null;
9925
+ if (afterUnit && afterUnit.parentElement === row) afterUnit.insertAdjacentElement("afterend", unit);
9926
+ else row.appendChild(unit);
9927
+ markSocialsRows(row.ownerDocument);
9928
+ return { item, hrefKey, iconKey, order: getSocialsOrderFromDom(row.ownerDocument) };
9929
+ }
9930
+ function duplicateSocialItem(item, content) {
9931
+ const row = findSocialsRow(item);
9932
+ const created = row ? insertSocialItem(row, item, content) : null;
9933
+ if (!created) return null;
9934
+ const sourceHref = socialHrefKey(item);
9935
+ const sourceIcon = socialIconKey(item);
9936
+ const link = created.item;
9937
+ if (sourceHref) link.setAttribute("href", item.getAttribute("href") ?? "");
9938
+ const glyph = item.querySelector(ICON_SELECTOR)?.innerHTML;
9939
+ if (glyph) {
9940
+ const slot = link.querySelector(ICON_SELECTOR);
9941
+ if (slot) slot.innerHTML = glyph;
9942
+ }
9943
+ return {
9944
+ ...created,
9945
+ copiedFrom: { href: sourceHref, icon: sourceIcon }
9946
+ };
9947
+ }
9948
+ function removeSocialItem(item, content) {
9949
+ const row = findSocialsRow(item);
9950
+ if (!row) return null;
9951
+ const hrefKey = socialHrefKey(item);
9952
+ const iconKey = socialIconKey(item);
9953
+ const removedKeys = [hrefKey, iconKey].filter((key) => Boolean(key));
9954
+ if (!removedKeys.length) return null;
9955
+ const previousOrder = getSocialsOrderFromDom(row.ownerDocument);
9956
+ const previousContent = Object.fromEntries(
9957
+ removedKeys.filter((key) => key in content).map((key) => [key, content[key]])
9958
+ );
9959
+ const unit = socialRowUnit(item);
9960
+ const nextSibling = unit.nextElementSibling;
9961
+ unit.remove();
9962
+ markSocialsRows(row.ownerDocument);
9963
+ return {
9964
+ removedKeys,
9965
+ previousContent,
9966
+ order: getSocialsOrderFromDom(row.ownerDocument),
9967
+ previousOrder,
9968
+ undo: () => {
9969
+ if (nextSibling) nextSibling.before(unit);
9970
+ else row.appendChild(unit);
9971
+ markSocialsRows(row.ownerDocument);
9972
+ }
9973
+ };
9974
+ }
9975
+ function applySocialsOrder(order, root = document) {
9976
+ listSocialsRows(root).forEach((row) => {
9977
+ const wanted = order[rowKeyOf(row)];
9978
+ if (!wanted) return;
9979
+ const byKey = new Map(listSocialItems(row).map((item) => [socialHrefKey(item), item]));
9980
+ wanted.forEach((key) => {
9981
+ const item = byKey.get(key);
9982
+ if (item) row.appendChild(socialRowUnit(item));
9983
+ });
9984
+ });
9985
+ markSocialsRows(root);
9986
+ }
9987
+ function reconcileSocialsFromContent(content, root = document) {
9988
+ markSocialsRows(root);
9989
+ const stored = parseSocialsOrder(content[SOCIALS_ORDER_KEY]);
9990
+ if (!stored) return;
9991
+ listSocialsRows(root).forEach((row) => {
9992
+ const wanted = stored[rowKeyOf(row)];
9993
+ if (!wanted) return;
9994
+ if (!wanted.length) return;
9995
+ wanted.forEach((key) => {
9996
+ if (listSocialItems(row).some((item) => socialHrefKey(item) === key)) return;
9997
+ if (!hasStoredValue(content, key)) return;
9998
+ const created = insertSocialItem(row, null, content);
9999
+ if (created) {
10000
+ created.item.setAttribute("data-ohw-href-key", key);
10001
+ created.item.querySelector(ICON_SELECTOR)?.setAttribute("data-ohw-key", key.replace(/-href$/, ""));
10002
+ applyStoredValues(created.item, content);
10003
+ }
10004
+ });
10005
+ const present = listSocialItems(row);
10006
+ const surviving = present.filter((item) => {
10007
+ const key = socialHrefKey(item);
10008
+ return !key || wanted.includes(key);
10009
+ });
10010
+ if (surviving.length) {
10011
+ present.forEach((item) => {
10012
+ if (!surviving.includes(item)) socialRowUnit(item).remove();
10013
+ });
10014
+ }
10015
+ });
10016
+ applySocialsOrder(stored, root);
10017
+ }
10018
+ var DROP_BAR_THICKNESS = 3;
10019
+ var DROP_BAR_GAP = 8;
10020
+ function buildSocialDropSlots(row) {
10021
+ const items = listSocialItems(row);
10022
+ if (!items.length) return [];
10023
+ const rects = items.map((item) => item.getBoundingClientRect());
10024
+ return items.concat(items[items.length - 1]).map((_, index) => {
10025
+ const previous = rects[index - 1];
10026
+ const next = rects[index];
10027
+ const centre = previous && next ? (previous.right + next.left) / 2 : next ? next.left - DROP_BAR_GAP : previous.right + DROP_BAR_GAP;
10028
+ const rect = next ?? previous;
10029
+ return {
10030
+ insertIndex: index,
10031
+ columnIndex: -1,
10032
+ left: centre - DROP_BAR_THICKNESS / 2,
10033
+ top: rect.top,
10034
+ width: DROP_BAR_THICKNESS,
10035
+ height: rect.height,
10036
+ direction: "vertical"
10037
+ };
10038
+ });
10039
+ }
10040
+ function findSocialByHrefKey(hrefKey, root = document) {
10041
+ const el = root.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
10042
+ return el ? getSocialItem(el) : null;
10043
+ }
10044
+ function buildSocialDropSlotsForKey(hrefKey, root = document) {
10045
+ const item = findSocialByHrefKey(hrefKey, root);
10046
+ const row = item ? findSocialsRow(item) : null;
10047
+ return row ? buildSocialDropSlots(row) : [];
10048
+ }
10049
+ function hitTestSocialDropSlot(clientX, clientY, draggedHrefKey, root = document) {
10050
+ const distanceTo = (slot) => {
10051
+ const dx = clientX - (slot.left + slot.width / 2);
10052
+ const dy = clientY < slot.top ? slot.top - clientY : Math.max(0, clientY - (slot.top + slot.height));
10053
+ return Math.hypot(dx, dy);
10054
+ };
10055
+ const slots = buildSocialDropSlotsForKey(draggedHrefKey, root);
10056
+ return slots.reduce((best, slot) => {
10057
+ return !best || distanceTo(slot) < distanceTo(best) ? slot : best;
10058
+ }, null);
10059
+ }
10060
+ function planSocialMove(hrefKey, insertIndex, root = document) {
10061
+ const item = findSocialByHrefKey(hrefKey, root);
10062
+ const row = item ? findSocialsRow(item) : null;
10063
+ if (!row) return null;
10064
+ const order = getSocialsOrderFromDom(root);
10065
+ const key = rowKeyOf(row);
10066
+ const current = order[key];
10067
+ if (!current) return null;
10068
+ const from = current.indexOf(hrefKey);
10069
+ if (from < 0) return null;
10070
+ const next = current.filter((_, index) => index !== from);
10071
+ next.splice(insertIndex > from ? insertIndex - 1 : insertIndex, 0, hrefKey);
10072
+ return { ...order, [key]: next };
10073
+ }
10074
+ var SOCIALS_DISPLAY_KEY = "__ohw_socials_display";
10075
+ function readSocialsDisplay(row) {
10076
+ const items = listSocialItems(row);
10077
+ const visible = (el) => Boolean(el) && el.style.display !== "none" && el.getAttribute("data-ohw-hidden") === null;
10078
+ return {
10079
+ text: items.some((item) => visible(socialLabelElement(item))),
10080
+ icon: items.some((item) => visible(item.querySelector(ICON_SELECTOR)))
10081
+ };
10082
+ }
10083
+ function parseSocialsDisplay(raw) {
10084
+ if (!raw) return null;
10085
+ try {
10086
+ const parsed = JSON.parse(raw);
10087
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
10088
+ } catch {
10089
+ return null;
10090
+ }
10091
+ }
10092
+ function socialsDisplayFor(row, content) {
10093
+ return parseSocialsDisplay(content[SOCIALS_DISPLAY_KEY])?.[rowKeyOf(row)] ?? readSocialsDisplay(row);
10094
+ }
10095
+ function socialsDisplayWith(row, display, content) {
10096
+ return { ...parseSocialsDisplay(content[SOCIALS_DISPLAY_KEY]) ?? {}, [rowKeyOf(row)]: display };
10097
+ }
10098
+ function applySocialsDisplayToRow(row, display) {
10099
+ listSocialItems(row).forEach((item) => {
10100
+ const label = socialLabelElement(item);
10101
+ const icon = item.querySelector(ICON_SELECTOR);
10102
+ if (label) label.style.display = display.text ? "" : "none";
10103
+ if (icon) icon.style.display = display.icon ? "" : "none";
10104
+ });
10105
+ }
10106
+ function applySocialsDisplayFromContent(content, root = document) {
10107
+ const stored = parseSocialsDisplay(content[SOCIALS_DISPLAY_KEY]);
10108
+ if (!stored) return;
10109
+ listSocialsRows(root).forEach((row) => {
10110
+ const display = stored[rowKeyOf(row)];
10111
+ if (!display) return;
10112
+ if (display.icon) {
10113
+ listSocialItems(row).forEach((item) => {
10114
+ const iconKey = ensureIconSlot(item);
10115
+ const slot = item.querySelector(ICON_SELECTOR);
10116
+ if (iconKey && slot && content[iconKey]) applyIconMarkup(slot, content[iconKey]);
10117
+ });
10118
+ }
10119
+ applySocialsDisplayToRow(row, display);
10120
+ });
10121
+ }
10122
+ function socialsMissingIcons(row) {
10123
+ return listSocialItems(row).filter((item) => !item.querySelector(ICON_SELECTOR)).map((item) => ({ hrefKey: socialHrefKey(item) ?? "", url: item.getAttribute("href") ?? "" })).filter((entry) => Boolean(entry.hrefKey));
10124
+ }
10125
+ function ensureIconSlot(item) {
10126
+ const existing = item.querySelector(ICON_SELECTOR);
10127
+ if (existing) return existing.dataset.ohwKey ?? null;
10128
+ const hrefKey = socialHrefKey(item);
10129
+ if (!hrefKey) return null;
10130
+ const iconKey = hrefKey.replace(/-href$/, "");
10131
+ const slot = document.createElement("span");
10132
+ slot.setAttribute("data-ohw-key", iconKey);
10133
+ slot.setAttribute("data-ohw-editable", "icon");
10134
+ slot.style.display = "inline-flex";
10135
+ item.prepend(slot);
10136
+ return iconKey;
10137
+ }
10138
+
9528
10139
  // src/lib/footer-items.ts
9529
10140
  var FOOTER_ORDER_KEY = "__ohw_footer_order";
9530
10141
  var MAX_FOOTER_COLUMNS = 18;
@@ -10369,6 +10980,329 @@ function deleteFooterColumn(column) {
10369
10980
  };
10370
10981
  }
10371
10982
 
10983
+ // src/lib/logo-identity.ts
10984
+ var LOGO_TEXT_KEYS = ["nav-logo-text", "footer-logo-text", "logo-text"];
10985
+ var LOGO_IMAGE_KEYS = ["nav-logo-image", "footer-logo", "footer-logo-image"];
10986
+ var LOGO_HREF_KEYS = ["nav-logo-href", "footer-logo-href", "logo-href"];
10987
+ var LOGO_PLACEHOLDER_KEY = "logo-is-placeholder";
10988
+ var LOGO_ALT_KEY = "logo-alt";
10989
+ var LOGO_IMAGE_URL_KEY = "nav-logo-image";
10990
+ var PLACEHOLDER_BUSINESS_NAME = "Business name";
10991
+ function resolveLogoDisplayText(text) {
10992
+ const trimmed = (text ?? "").trim();
10993
+ return trimmed || PLACEHOLDER_BUSINESS_NAME;
10994
+ }
10995
+ function isFooterLogoRoot(root) {
10996
+ return Boolean(root.closest("footer") || root.closest('[data-ohw-section="footer"]'));
10997
+ }
10998
+ function imageKeyForRoot(root) {
10999
+ return isFooterLogoRoot(root) ? "footer-logo" : "nav-logo-image";
11000
+ }
11001
+ function textKeyForRoot(root) {
11002
+ return isFooterLogoRoot(root) ? "footer-logo-text" : "nav-logo-text";
11003
+ }
11004
+ function ensureLogoHrefKey(root) {
11005
+ if (!(root instanceof HTMLAnchorElement)) return;
11006
+ if (root.hasAttribute("data-ohw-href-key")) return;
11007
+ root.setAttribute("data-ohw-href-key", isFooterLogoRoot(root) ? "footer-logo-href" : "nav-logo-href");
11008
+ }
11009
+ function applyLogoIdentity(text, isPlaceholder) {
11010
+ const display = resolveLogoDisplayText(text);
11011
+ const placeholder = isPlaceholder || !text.trim() || display === PLACEHOLDER_BUSINESS_NAME;
11012
+ for (const key of LOGO_TEXT_KEYS) {
11013
+ document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
11014
+ if (el.textContent !== display) el.textContent = display;
11015
+ });
11016
+ }
11017
+ for (const key of LOGO_IMAGE_KEYS) {
11018
+ document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
11019
+ const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
11020
+ if (img) img.alt = display;
11021
+ });
11022
+ }
11023
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((el) => {
11024
+ if (placeholder) el.setAttribute("data-ohw-placeholder", "");
11025
+ else el.removeAttribute("data-ohw-placeholder");
11026
+ });
11027
+ return display;
11028
+ }
11029
+ function applyLogoImage(url, alt) {
11030
+ const displayAlt = resolveLogoDisplayText(alt);
11031
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((root) => {
11032
+ ensureLogoHrefKey(root);
11033
+ const imageKey = imageKeyForRoot(root);
11034
+ const textKey = textKeyForRoot(root);
11035
+ 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");
11036
+ let textEl = root.querySelector(`[data-ohw-key="${textKey}"]`) ?? root.querySelector('[data-ohw-key="logo-text"]');
11037
+ if (url) {
11038
+ if (!img) {
11039
+ img = document.createElement("img");
11040
+ img.setAttribute("data-ohw-editable", "image");
11041
+ img.setAttribute("data-ohw-key", imageKey);
11042
+ img.alt = displayAlt;
11043
+ img.style.height = "";
11044
+ img.style.maxHeight = "none";
11045
+ img.style.width = "auto";
11046
+ img.style.display = "block";
11047
+ img.style.objectFit = "contain";
11048
+ root.insertBefore(img, root.firstChild);
11049
+ } else {
11050
+ img.setAttribute("data-ohw-editable", "image");
11051
+ img.setAttribute("data-ohw-key", imageKey);
11052
+ }
11053
+ img.removeAttribute("srcset");
11054
+ img.removeAttribute("sizes");
11055
+ img.src = url;
11056
+ img.alt = displayAlt;
11057
+ img.style.display = "block";
11058
+ if (textEl) textEl.style.display = "none";
11059
+ root.removeAttribute("data-ohw-placeholder");
11060
+ return;
11061
+ }
11062
+ if (img) {
11063
+ img.removeAttribute("src");
11064
+ img.removeAttribute("srcset");
11065
+ img.removeAttribute("sizes");
11066
+ img.alt = displayAlt;
11067
+ img.style.display = "none";
11068
+ }
11069
+ if (!textEl) {
11070
+ textEl = document.createElement("span");
11071
+ textEl.setAttribute("data-ohw-editable", "plain");
11072
+ textEl.setAttribute("data-ohw-key", textKey);
11073
+ root.appendChild(textEl);
11074
+ }
11075
+ textEl.style.display = "";
11076
+ if (textEl.textContent !== displayAlt) textEl.textContent = displayAlt;
11077
+ if (!displayAlt.trim() || displayAlt === PLACEHOLDER_BUSINESS_NAME) {
11078
+ root.setAttribute("data-ohw-placeholder", "");
11079
+ } else {
11080
+ root.removeAttribute("data-ohw-placeholder");
11081
+ }
11082
+ });
11083
+ }
11084
+ function applyLogoHref(href) {
11085
+ const target = href.trim() || "/";
11086
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((root) => {
11087
+ ensureLogoHrefKey(root);
11088
+ if (root instanceof HTMLAnchorElement) {
11089
+ root.setAttribute("href", target);
11090
+ }
11091
+ });
11092
+ for (const key of LOGO_HREF_KEYS) setStoredLinkHref(key, target);
11093
+ }
11094
+ function readLogoIdentityFromDom() {
11095
+ let imageUrl = null;
11096
+ for (const key of LOGO_IMAGE_KEYS) {
11097
+ const el = document.querySelector(`[data-ohw-key="${key}"]`);
11098
+ const img = el instanceof HTMLImageElement ? el : el?.querySelector("img");
11099
+ const attrSrc = img?.getAttribute("src")?.trim() ?? "";
11100
+ if (attrSrc && !attrSrc.startsWith("data:") && img && img.style.display !== "none") {
11101
+ imageUrl = img.currentSrc || img.src;
11102
+ break;
11103
+ }
11104
+ }
11105
+ let text = PLACEHOLDER_BUSINESS_NAME;
11106
+ let isPlaceholder = true;
11107
+ for (const key of LOGO_TEXT_KEYS) {
11108
+ const el = document.querySelector(`[data-ohw-key="${key}"]`);
11109
+ if (el?.textContent?.trim()) {
11110
+ text = el.textContent.trim();
11111
+ const logoRoot2 = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
11112
+ isPlaceholder = logoRoot2?.hasAttribute("data-ohw-placeholder") === true || text === PLACEHOLDER_BUSINESS_NAME;
11113
+ break;
11114
+ }
11115
+ }
11116
+ if (imageUrl) {
11117
+ const logoImg = document.querySelector(
11118
+ '[data-ohw-key="nav-logo-image"], [data-ohw-key="footer-logo"]'
11119
+ );
11120
+ const alt = logoImg?.alt?.trim() || text;
11121
+ isPlaceholder = false;
11122
+ const hrefEl = document.querySelector(
11123
+ 'a[data-ohw-role="logo"], a[data-ohw-logo], [data-ohw-role="logo"]'
11124
+ );
11125
+ const href2 = (hrefEl instanceof HTMLAnchorElement ? hrefEl.getAttribute("href") : null) || hrefEl?.closest("a")?.getAttribute("href") || "/";
11126
+ return { text, isPlaceholder, imageUrl, href: href2, alt };
11127
+ }
11128
+ const logoRoot = document.querySelector('[data-ohw-role="logo"], [data-ohw-logo]');
11129
+ const href = (logoRoot instanceof HTMLAnchorElement ? logoRoot.getAttribute("href") : null) || logoRoot?.closest("a")?.getAttribute("href") || "/";
11130
+ return { text, isPlaceholder, imageUrl: null, href, alt: text };
11131
+ }
11132
+ function applyLogoFromContent(content) {
11133
+ 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);
11134
+ if (!hasLogoIdentity) return false;
11135
+ const logoText = content[LOGO_TEXT_KEYS[0]] ?? content[LOGO_TEXT_KEYS[1]] ?? readLogoIdentityFromDom().text;
11136
+ const logoAlt = content[LOGO_ALT_KEY] ?? logoText;
11137
+ const rawLogoImage = content[LOGO_IMAGE_URL_KEY] ?? content["footer-logo"] ?? content["footer-logo-image"] ?? null;
11138
+ const logoImageUrl = typeof rawLogoImage === "string" && rawLogoImage.trim() ? rawLogoImage.trim() : null;
11139
+ const imageExplicitlyCleared = LOGO_IMAGE_KEYS.some((key) => key in content) && !logoImageUrl;
11140
+ const logoIsPlaceholder = LOGO_PLACEHOLDER_KEY in content ? content[LOGO_PLACEHOLDER_KEY] !== "false" : !logoImageUrl && (!logoText.trim() || logoText === PLACEHOLDER_BUSINESS_NAME);
11141
+ if (logoImageUrl) {
11142
+ applyLogoImage(logoImageUrl, logoAlt);
11143
+ } else {
11144
+ if (imageExplicitlyCleared) applyLogoImage(null, logoAlt);
11145
+ applyLogoIdentity(logoText, logoIsPlaceholder);
11146
+ }
11147
+ const logoHref = content["nav-logo-href"] ?? content["footer-logo-href"] ?? content["logo-href"];
11148
+ if (typeof logoHref === "string" && logoHref.trim()) {
11149
+ applyLogoHref(logoHref);
11150
+ }
11151
+ return true;
11152
+ }
11153
+
11154
+ // src/lib/logo-size.ts
11155
+ var LOGO_SIZE_DEFAULTS = {
11156
+ navbar: 28,
11157
+ footer: 32
11158
+ };
11159
+ var LOGO_SIZE_MIN = 16;
11160
+ var LOGO_SIZE_MAX = 80;
11161
+ var LOGO_SIZE_DESKTOP_KEYS = {
11162
+ navbar: "nav-logo-size",
11163
+ footer: "footer-logo-size"
11164
+ };
11165
+ var LOGO_SIZE_MOBILE_KEYS = {
11166
+ navbar: "nav-logo-size-mobile",
11167
+ footer: "footer-logo-size-mobile"
11168
+ };
11169
+ var LOGO_SIZE_KEYS = [
11170
+ LOGO_SIZE_DESKTOP_KEYS.navbar,
11171
+ LOGO_SIZE_DESKTOP_KEYS.footer,
11172
+ LOGO_SIZE_MOBILE_KEYS.navbar,
11173
+ LOGO_SIZE_MOBILE_KEYS.footer
11174
+ ];
11175
+ function isFooterLogoRoot2(root) {
11176
+ return Boolean(root.closest("footer") || root.closest('[data-ohw-section="footer"]'));
11177
+ }
11178
+ function getLogoPlacement(root) {
11179
+ return isFooterLogoRoot2(root) ? "footer" : "navbar";
11180
+ }
11181
+ function parseLogoSizePx(raw, fallback) {
11182
+ if (raw == null || raw === "") return fallback;
11183
+ const n = Number.parseFloat(raw);
11184
+ if (!Number.isFinite(n)) return fallback;
11185
+ return Math.min(LOGO_SIZE_MAX, Math.max(LOGO_SIZE_MIN, Math.round(n)));
11186
+ }
11187
+ function isMobileLogoSizeFollowing(content, placement) {
11188
+ const raw = content[LOGO_SIZE_MOBILE_KEYS[placement]];
11189
+ return raw == null || raw.trim() === "";
11190
+ }
11191
+ function resolveDesktopLogoSize(content, placement) {
11192
+ return parseLogoSizePx(content[LOGO_SIZE_DESKTOP_KEYS[placement]], LOGO_SIZE_DEFAULTS[placement]);
11193
+ }
11194
+ function resolveMobileLogoSize(content, placement) {
11195
+ if (isMobileLogoSizeFollowing(content, placement)) {
11196
+ return resolveDesktopLogoSize(content, placement);
11197
+ }
11198
+ return parseLogoSizePx(
11199
+ content[LOGO_SIZE_MOBILE_KEYS[placement]],
11200
+ resolveDesktopLogoSize(content, placement)
11201
+ );
11202
+ }
11203
+ function setRootSizeVars(root, desktopPx, mobilePx, following) {
11204
+ root.style.setProperty("--ohw-logo-size", `${desktopPx}px`);
11205
+ if (following) {
11206
+ root.style.removeProperty("--ohw-logo-size-mobile");
11207
+ } else {
11208
+ root.style.setProperty("--ohw-logo-size-mobile", `${mobilePx}px`);
11209
+ }
11210
+ root.querySelectorAll("img").forEach((img) => {
11211
+ img.style.height = "";
11212
+ img.style.maxHeight = "none";
11213
+ img.style.width = "auto";
11214
+ img.style.objectFit = "contain";
11215
+ });
11216
+ }
11217
+ function applyLogoSizes(content) {
11218
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((root) => {
11219
+ const placement = getLogoPlacement(root);
11220
+ const desktop = resolveDesktopLogoSize(content, placement);
11221
+ const following = isMobileLogoSizeFollowing(content, placement);
11222
+ const mobile = following ? desktop : resolveMobileLogoSize(content, placement);
11223
+ setRootSizeVars(root, desktop, mobile, following);
11224
+ });
11225
+ }
11226
+ function applyLogoSizeToPlacement(placement, desktopPx, mobilePx, following) {
11227
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((root) => {
11228
+ if (getLogoPlacement(root) !== placement) return;
11229
+ setRootSizeVars(root, desktopPx, mobilePx, following);
11230
+ });
11231
+ }
11232
+ function logoHasUploadedImage(logoEl) {
11233
+ if (logoEl.hasAttribute("data-ohw-placeholder")) return false;
11234
+ 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");
11235
+ if (!img) return false;
11236
+ const src = img.getAttribute("src")?.trim() ?? "";
11237
+ if (!src || src.startsWith("data:")) return false;
11238
+ if (img.style.display === "none") return false;
11239
+ return true;
11240
+ }
11241
+ function getLogoInteractionRect(logoEl) {
11242
+ if (logoHasUploadedImage(logoEl)) {
11243
+ 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");
11244
+ if (img) {
11245
+ const r2 = img.getBoundingClientRect();
11246
+ if (r2.width > 0 && r2.height > 0) return r2;
11247
+ }
11248
+ }
11249
+ const text = logoEl.querySelector(
11250
+ '[data-ohw-key="nav-logo-text"], [data-ohw-key="footer-logo-text"]'
11251
+ );
11252
+ if (text) {
11253
+ const style = window.getComputedStyle(text);
11254
+ if (style.display !== "none" && style.visibility !== "hidden") {
11255
+ const r2 = text.getBoundingClientRect();
11256
+ if (r2.width > 0 && r2.height > 0) return r2;
11257
+ }
11258
+ }
11259
+ return logoEl.getBoundingClientRect();
11260
+ }
11261
+ function readLogoSizeState(content, placement) {
11262
+ const desktopPx = resolveDesktopLogoSize(content, placement);
11263
+ const mobileFollowing = isMobileLogoSizeFollowing(content, placement);
11264
+ const mobilePx = mobileFollowing ? desktopPx : resolveMobileLogoSize(content, placement);
11265
+ return { desktopPx, mobilePx, mobileFollowing };
11266
+ }
11267
+
11268
+ // src/lib/site-wide-scope.ts
11269
+ function getLogoElement(el) {
11270
+ const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
11271
+ if (marked) return marked;
11272
+ if (el.closest('[data-ohw-editable="icon"]')) return null;
11273
+ const root = el.closest("nav, [data-ohw-nav-root], footer");
11274
+ if (!root) return null;
11275
+ const anchor = el.closest("a");
11276
+ if (anchor && root.contains(anchor) && !anchor.hasAttribute("data-ohw-href-key") && !anchor.closest("[data-ohw-nav-container]") && Boolean(anchor.querySelector("img") || anchor.matches("img"))) {
11277
+ return anchor;
11278
+ }
11279
+ const img = el.matches("img") ? el : null;
11280
+ if (img && !img.closest("[data-ohw-href-key]") && !img.closest("[data-ohw-nav-container]") && (img.closest("footer") || img.closest("nav, [data-ohw-nav-root]"))) {
11281
+ return img;
11282
+ }
11283
+ return null;
11284
+ }
11285
+ function isInFooter(el) {
11286
+ if (!el) return false;
11287
+ return Boolean(el.closest("footer") || el.closest('[data-ohw-section="footer"]'));
11288
+ }
11289
+ function isSiteWideElement(el) {
11290
+ if (!el) return false;
11291
+ if (getLogoElement(el)) return true;
11292
+ if (isInFooter(el)) return true;
11293
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-root")) {
11294
+ return true;
11295
+ }
11296
+ if (el.hasAttribute("data-ohw-href-key") && el.closest("nav, [data-ohw-nav-root], [data-ohw-nav-drawer], aside")) {
11297
+ return true;
11298
+ }
11299
+ if (el.closest('[data-ohw-role="navbar-button"]')) return true;
11300
+ return false;
11301
+ }
11302
+ function isSiteWideScopeActive(args) {
11303
+ return isSiteWideElement(args.selected) || isSiteWideElement(args.hoveredItem) || isSiteWideElement(args.hoveredNavContainer) || isSiteWideElement(args.active);
11304
+ }
11305
+
10372
11306
  // src/lib/add-footer-column.ts
10373
11307
  function buildFooterColumnEditContentPatch(result) {
10374
11308
  return {
@@ -10401,40 +11335,396 @@ function addFooterColumnWithPersist({
10401
11335
  return result;
10402
11336
  }
10403
11337
 
10404
- // src/lib/item-drag-interaction.ts
10405
- function disableNativeHrefDrag(el) {
10406
- if (el.draggable) el.draggable = false;
10407
- if (el.getAttribute("draggable") !== "false") {
10408
- el.setAttribute("draggable", "false");
11338
+ // src/ui/FloatingPanel.tsx
11339
+ var import_react13 = require("react");
11340
+ var import_lucide_react13 = require("lucide-react");
11341
+ var import_jsx_runtime26 = require("react/jsx-runtime");
11342
+ var PANEL_WIDTH = 256;
11343
+ var EDGE_MARGIN = 16;
11344
+ function getVisibleClip(parentScroll) {
11345
+ const left = 0;
11346
+ const right = window.innerWidth;
11347
+ if (!parentScroll) {
11348
+ return { top: 0, bottom: window.innerHeight, left, right };
10409
11349
  }
11350
+ const { iframeOffsetTop, headerH: visibleCanvasTop, canvasH } = parentScroll;
11351
+ const top = Math.max(0, visibleCanvasTop - iframeOffsetTop);
11352
+ const bottom = Math.min(window.innerHeight, visibleCanvasTop + canvasH - iframeOffsetTop);
11353
+ return { top, bottom: Math.max(top, bottom), left, right };
10410
11354
  }
10411
- function clearTextSelection() {
10412
- const sel = window.getSelection();
10413
- if (sel && !sel.isCollapsed) sel.removeAllRanges();
10414
- }
10415
- function armItemPressDrag() {
10416
- document.documentElement.setAttribute("data-ohw-footer-press-drag", "");
10417
- }
10418
- function lockItemDuringDrag() {
10419
- document.documentElement.removeAttribute("data-ohw-footer-press-drag");
10420
- document.documentElement.setAttribute("data-ohw-item-dragging", "");
10421
- clearTextSelection();
11355
+ function defaultFloatingPanelPosition(parentScroll, panelHeight = 280) {
11356
+ const clip = getVisibleClip(parentScroll);
11357
+ return {
11358
+ x: Math.max(EDGE_MARGIN, clip.right - PANEL_WIDTH - EDGE_MARGIN),
11359
+ y: Math.min(
11360
+ Math.max(clip.top + EDGE_MARGIN, EDGE_MARGIN),
11361
+ Math.max(clip.top + EDGE_MARGIN, clip.bottom - panelHeight - EDGE_MARGIN)
11362
+ )
11363
+ };
10422
11364
  }
10423
- function unlockItemDragInteraction() {
10424
- const wasDragging = document.documentElement.hasAttribute("data-ohw-item-dragging");
10425
- document.documentElement.removeAttribute("data-ohw-footer-press-drag");
10426
- document.documentElement.removeAttribute("data-ohw-item-dragging");
10427
- if (wasDragging) clearTextSelection();
11365
+ function clampPosition(pos, parentScroll, panelW, panelH) {
11366
+ const clip = getVisibleClip(parentScroll);
11367
+ const maxX = Math.max(clip.left + EDGE_MARGIN, clip.right - panelW - EDGE_MARGIN);
11368
+ const maxY = Math.max(clip.top + EDGE_MARGIN, clip.bottom - panelH - EDGE_MARGIN);
11369
+ return {
11370
+ x: Math.min(Math.max(pos.x, clip.left + EDGE_MARGIN), maxX),
11371
+ y: Math.min(Math.max(pos.y, clip.top + EDGE_MARGIN), maxY)
11372
+ };
10428
11373
  }
10429
- var armFooterPressDrag = armItemPressDrag;
10430
- var lockFooterDuringDrag = lockItemDuringDrag;
10431
- var unlockFooterDragInteraction = unlockItemDragInteraction;
10432
-
10433
- // src/lib/nav-dnd.ts
10434
- function listReorderableNavItems() {
10435
- return listNavbarItems().filter((el) => {
10436
- const key = el.getAttribute("data-ohw-href-key");
10437
- return isNavbarHrefKey(key) && !isNestedNavChild(el);
11374
+ function FloatingPanel({
11375
+ open,
11376
+ title,
11377
+ context,
11378
+ icon,
11379
+ onClose,
11380
+ children,
11381
+ position,
11382
+ onPositionChange,
11383
+ parentScroll = null,
11384
+ className,
11385
+ bodyClassName
11386
+ }) {
11387
+ const panelRef = (0, import_react13.useRef)(null);
11388
+ const [measured, setMeasured] = (0, import_react13.useState)({ w: PANEL_WIDTH, h: 280 });
11389
+ const dragRef = (0, import_react13.useRef)(null);
11390
+ const resolved = position ?? defaultFloatingPanelPosition(parentScroll, measured.h);
11391
+ const clamped = clampPosition(resolved, parentScroll, measured.w, measured.h);
11392
+ (0, import_react13.useLayoutEffect)(() => {
11393
+ if (!open || !panelRef.current) return;
11394
+ const el = panelRef.current;
11395
+ const next = { w: el.offsetWidth || PANEL_WIDTH, h: el.offsetHeight || 280 };
11396
+ setMeasured((prev) => prev.w === next.w && prev.h === next.h ? prev : next);
11397
+ }, [open, children, title, context]);
11398
+ (0, import_react13.useEffect)(() => {
11399
+ if (!open || !position || !onPositionChange) return;
11400
+ const next = clampPosition(position, parentScroll, measured.w, measured.h);
11401
+ if (next.x !== position.x || next.y !== position.y) onPositionChange(next);
11402
+ }, [open, parentScroll, measured.w, measured.h, position, onPositionChange]);
11403
+ const onHeaderPointerDown = (0, import_react13.useCallback)(
11404
+ (e) => {
11405
+ if (e.button !== 0) return;
11406
+ if (e.target.closest("[data-ohw-floating-panel-close]")) return;
11407
+ e.preventDefault();
11408
+ e.stopPropagation();
11409
+ const el = e.currentTarget;
11410
+ el.setPointerCapture(e.pointerId);
11411
+ dragRef.current = {
11412
+ pointerId: e.pointerId,
11413
+ startX: e.clientX,
11414
+ startY: e.clientY,
11415
+ originX: clamped.x,
11416
+ originY: clamped.y
11417
+ };
11418
+ },
11419
+ [clamped.x, clamped.y]
11420
+ );
11421
+ const onHeaderPointerMove = (0, import_react13.useCallback)(
11422
+ (e) => {
11423
+ const drag = dragRef.current;
11424
+ if (!drag || drag.pointerId !== e.pointerId) return;
11425
+ e.preventDefault();
11426
+ const next = clampPosition(
11427
+ {
11428
+ x: drag.originX + (e.clientX - drag.startX),
11429
+ y: drag.originY + (e.clientY - drag.startY)
11430
+ },
11431
+ parentScroll,
11432
+ measured.w,
11433
+ measured.h
11434
+ );
11435
+ onPositionChange?.(next);
11436
+ },
11437
+ [measured.h, measured.w, onPositionChange, parentScroll]
11438
+ );
11439
+ const endDrag = (0, import_react13.useCallback)((e) => {
11440
+ const drag = dragRef.current;
11441
+ if (!drag || drag.pointerId !== e.pointerId) return;
11442
+ dragRef.current = null;
11443
+ try {
11444
+ e.currentTarget.releasePointerCapture(e.pointerId);
11445
+ } catch {
11446
+ }
11447
+ }, []);
11448
+ if (!open) return null;
11449
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
11450
+ "div",
11451
+ {
11452
+ ref: panelRef,
11453
+ "data-ohw-floating-panel": "",
11454
+ role: "dialog",
11455
+ "aria-label": title,
11456
+ className: cn(
11457
+ // Above MediaOverlay / item chrome (2147483646); link-modal content shares this tier.
11458
+ "fixed z-[2147483647] flex w-64 flex-col overflow-hidden rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
11459
+ className
11460
+ ),
11461
+ style: { left: clamped.x, top: clamped.y },
11462
+ onMouseDown: (e) => e.stopPropagation(),
11463
+ onPointerDown: (e) => e.stopPropagation(),
11464
+ onClick: (e) => e.stopPropagation(),
11465
+ children: [
11466
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
11467
+ "div",
11468
+ {
11469
+ "data-ohw-floating-panel-header": "",
11470
+ className: "relative flex cursor-grab items-start gap-2 border-b border-border py-5 pl-5 pr-11 active:cursor-grabbing",
11471
+ onPointerDown: onHeaderPointerDown,
11472
+ onPointerMove: onHeaderPointerMove,
11473
+ onPointerUp: endDrag,
11474
+ onPointerCancel: endDrag,
11475
+ children: [
11476
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
11477
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center gap-2", children: [
11478
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "shrink-0 text-foreground", children: icon }) : null,
11479
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "min-w-0 flex-1 text-lg font-semibold leading-7 text-foreground", children: title })
11480
+ ] }),
11481
+ context ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "w-full text-sm leading-5 text-muted-foreground", children: context }) : null
11482
+ ] }),
11483
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
11484
+ "button",
11485
+ {
11486
+ type: "button",
11487
+ "data-ohw-floating-panel-close": "",
11488
+ "aria-label": "Close",
11489
+ className: "absolute right-2.5 top-2.5 rounded-sm p-1.5 text-foreground hover:bg-muted/50",
11490
+ onClick: (e) => {
11491
+ e.stopPropagation();
11492
+ onClose();
11493
+ },
11494
+ onPointerDown: (e) => e.stopPropagation(),
11495
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react13.X, { size: 16, "aria-hidden": true })
11496
+ }
11497
+ )
11498
+ ]
11499
+ }
11500
+ ),
11501
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
11502
+ "div",
11503
+ {
11504
+ "data-ohw-floating-panel-body": "",
11505
+ className: cn("flex w-full flex-col gap-4 p-5", bodyClassName),
11506
+ children
11507
+ }
11508
+ )
11509
+ ]
11510
+ }
11511
+ );
11512
+ }
11513
+
11514
+ // src/ui/logo-size-panel.tsx
11515
+ var import_lucide_react14 = require("lucide-react");
11516
+ var import_jsx_runtime27 = require("react/jsx-runtime");
11517
+ function SizeSlider({
11518
+ value,
11519
+ onChange
11520
+ }) {
11521
+ const pct = (value - LOGO_SIZE_MIN) / (LOGO_SIZE_MAX - LOGO_SIZE_MIN) * 100;
11522
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex w-full flex-col gap-3", children: [
11523
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex w-full items-center gap-2 text-sm font-medium leading-5", children: [
11524
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "min-w-0 flex-1 text-foreground", children: "Size" }),
11525
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "shrink-0 whitespace-nowrap text-muted-foreground", children: [
11526
+ value,
11527
+ " px"
11528
+ ] })
11529
+ ] }),
11530
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "relative h-2 w-full rounded-full bg-primary-50", children: [
11531
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
11532
+ "div",
11533
+ {
11534
+ className: "absolute inset-y-0 left-0 rounded-full bg-primary",
11535
+ style: { width: `${pct}%` }
11536
+ }
11537
+ ),
11538
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
11539
+ "input",
11540
+ {
11541
+ type: "range",
11542
+ min: LOGO_SIZE_MIN,
11543
+ max: LOGO_SIZE_MAX,
11544
+ step: 1,
11545
+ value,
11546
+ "aria-label": "Logo size",
11547
+ className: cn(
11548
+ "absolute inset-0 h-full w-full cursor-pointer appearance-none bg-transparent",
11549
+ "[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:size-5",
11550
+ "[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2",
11551
+ "[&::-webkit-slider-thumb]:border-primary [&::-webkit-slider-thumb]:bg-background",
11552
+ "[&::-moz-range-thumb]:size-5 [&::-moz-range-thumb]:rounded-full",
11553
+ "[&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-primary",
11554
+ "[&::-moz-range-thumb]:bg-background"
11555
+ ),
11556
+ onChange: (e) => onChange(Number(e.target.value))
11557
+ }
11558
+ )
11559
+ ] })
11560
+ ] });
11561
+ }
11562
+ function LogoSizePanel({
11563
+ viewport,
11564
+ sizePx,
11565
+ mobileFollowing = true,
11566
+ onSizeChange,
11567
+ onCustomizeMobile,
11568
+ onResetMobile,
11569
+ onUpdateEverywhere,
11570
+ className
11571
+ }) {
11572
+ const showFollowing = viewport === "mobile" && mobileFollowing;
11573
+ const showMobileSlider = viewport === "mobile" && !mobileFollowing;
11574
+ const showDesktopSlider = viewport === "desktop";
11575
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: cn("flex w-full flex-col gap-4", className), children: [
11576
+ showFollowing ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
11577
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-start gap-1", children: [
11578
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react14.Link, { size: 16, className: "mt-0.5 shrink-0 text-foreground", "aria-hidden": true }),
11579
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-sm font-semibold leading-5 text-foreground", children: "Following desktop size" })
11580
+ ] }),
11581
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("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." }),
11582
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
11583
+ Button,
11584
+ {
11585
+ type: "button",
11586
+ variant: "outline",
11587
+ size: "sm",
11588
+ className: "h-9 w-full min-w-0 cursor-pointer",
11589
+ onClick: onCustomizeMobile,
11590
+ children: "Customize for mobile"
11591
+ }
11592
+ )
11593
+ ] }) : null,
11594
+ showDesktopSlider || showMobileSlider ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SizeSlider, { value: sizePx, onChange: onSizeChange }) : null,
11595
+ showMobileSlider ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
11596
+ Button,
11597
+ {
11598
+ type: "button",
11599
+ variant: "outline",
11600
+ size: "sm",
11601
+ className: "h-9 w-full min-w-0 cursor-pointer",
11602
+ onClick: onResetMobile,
11603
+ children: "Reset to desktop size"
11604
+ }
11605
+ ) : null,
11606
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "h-px w-full bg-border", role: "separator" }),
11607
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
11608
+ Button,
11609
+ {
11610
+ type: "button",
11611
+ variant: "outline",
11612
+ size: "sm",
11613
+ className: "h-9 w-full min-w-0 cursor-pointer gap-1",
11614
+ onClick: onUpdateEverywhere,
11615
+ children: [
11616
+ "Update logo everywhere",
11617
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react14.ArrowUpRight, { size: 16, "aria-hidden": true })
11618
+ ]
11619
+ }
11620
+ ),
11621
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-sm leading-5 text-muted-foreground", children: "Matches the right version to your background." })
11622
+ ] });
11623
+ }
11624
+
11625
+ // src/ui/socials-display-panel.tsx
11626
+ var import_jsx_runtime28 = require("react/jsx-runtime");
11627
+ function DisplaySwitch({
11628
+ label,
11629
+ checked,
11630
+ disabled,
11631
+ onChange
11632
+ }) {
11633
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex w-full items-center gap-2", children: [
11634
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
11635
+ "span",
11636
+ {
11637
+ className: cn(
11638
+ "min-w-0 flex-1 text-sm font-medium leading-5",
11639
+ disabled ? "text-muted-foreground" : "text-foreground"
11640
+ ),
11641
+ children: label
11642
+ }
11643
+ ),
11644
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
11645
+ "button",
11646
+ {
11647
+ type: "button",
11648
+ role: "switch",
11649
+ "aria-checked": checked,
11650
+ "aria-label": label,
11651
+ disabled,
11652
+ onClick: () => onChange(!checked),
11653
+ className: cn(
11654
+ "relative h-5 w-9 shrink-0 rounded-full transition-colors",
11655
+ checked ? "bg-primary" : "bg-primary-50",
11656
+ disabled ? "cursor-default opacity-50" : "cursor-pointer"
11657
+ ),
11658
+ children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
11659
+ "span",
11660
+ {
11661
+ className: cn(
11662
+ "absolute top-0.5 h-4 w-4 rounded-full bg-white transition-all",
11663
+ checked ? "left-[1.125rem]" : "left-0.5"
11664
+ )
11665
+ }
11666
+ )
11667
+ }
11668
+ )
11669
+ ] });
11670
+ }
11671
+ function SocialsDisplayPanel({ display, onChange, className }) {
11672
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: cn("flex w-full flex-col gap-3", className), children: [
11673
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
11674
+ DisplaySwitch,
11675
+ {
11676
+ label: "Text",
11677
+ checked: display.text,
11678
+ disabled: display.text && !display.icon,
11679
+ onChange: (text) => onChange({ ...display, text })
11680
+ }
11681
+ ),
11682
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
11683
+ DisplaySwitch,
11684
+ {
11685
+ label: "Icon",
11686
+ checked: display.icon,
11687
+ disabled: display.icon && !display.text,
11688
+ onChange: (icon) => onChange({ ...display, icon })
11689
+ }
11690
+ )
11691
+ ] });
11692
+ }
11693
+
11694
+ // src/lib/item-drag-interaction.ts
11695
+ function disableNativeHrefDrag(el) {
11696
+ if (el.draggable) el.draggable = false;
11697
+ if (el.getAttribute("draggable") !== "false") {
11698
+ el.setAttribute("draggable", "false");
11699
+ }
11700
+ }
11701
+ function clearTextSelection() {
11702
+ const sel = window.getSelection();
11703
+ if (sel && !sel.isCollapsed) sel.removeAllRanges();
11704
+ }
11705
+ function armItemPressDrag() {
11706
+ document.documentElement.setAttribute("data-ohw-footer-press-drag", "");
11707
+ }
11708
+ function lockItemDuringDrag() {
11709
+ document.documentElement.removeAttribute("data-ohw-footer-press-drag");
11710
+ document.documentElement.setAttribute("data-ohw-item-dragging", "");
11711
+ clearTextSelection();
11712
+ }
11713
+ function unlockItemDragInteraction() {
11714
+ const wasDragging = document.documentElement.hasAttribute("data-ohw-item-dragging");
11715
+ document.documentElement.removeAttribute("data-ohw-footer-press-drag");
11716
+ document.documentElement.removeAttribute("data-ohw-item-dragging");
11717
+ if (wasDragging) clearTextSelection();
11718
+ }
11719
+ var armFooterPressDrag = armItemPressDrag;
11720
+ var lockFooterDuringDrag = lockItemDuringDrag;
11721
+ var unlockFooterDragInteraction = unlockItemDragInteraction;
11722
+
11723
+ // src/lib/nav-dnd.ts
11724
+ function listReorderableNavItems() {
11725
+ return listNavbarItems().filter((el) => {
11726
+ const key = el.getAttribute("data-ohw-href-key");
11727
+ return isNavbarHrefKey(key) && !isNestedNavChild(el);
10438
11728
  });
10439
11729
  }
10440
11730
  function resolveParentNavHrefKey(child) {
@@ -10599,7 +11889,7 @@ function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
10599
11889
  }
10600
11890
 
10601
11891
  // src/useNavItemDrag.ts
10602
- var import_react13 = require("react");
11892
+ var import_react14 = require("react");
10603
11893
  function useNavItemDrag({
10604
11894
  isEditMode,
10605
11895
  editContentRef,
@@ -10623,11 +11913,11 @@ function useNavItemDrag({
10623
11913
  getNavigationItemAnchor: getNavigationItemAnchor2,
10624
11914
  isDragHandleDisabled: isDragHandleDisabled2
10625
11915
  }) {
10626
- const navDragRef = (0, import_react13.useRef)(null);
10627
- const [navDropSlots, setNavDropSlots] = (0, import_react13.useState)([]);
10628
- const [activeNavDropIndex, setActiveNavDropIndex] = (0, import_react13.useState)(null);
10629
- const navPointerDragRef = (0, import_react13.useRef)(null);
10630
- const clearNavDragVisuals = (0, import_react13.useCallback)(() => {
11916
+ const navDragRef = (0, import_react14.useRef)(null);
11917
+ const [navDropSlots, setNavDropSlots] = (0, import_react14.useState)([]);
11918
+ const [activeNavDropIndex, setActiveNavDropIndex] = (0, import_react14.useState)(null);
11919
+ const navPointerDragRef = (0, import_react14.useRef)(null);
11920
+ const clearNavDragVisuals = (0, import_react14.useCallback)(() => {
10631
11921
  const session = navDragRef.current;
10632
11922
  const keepOpenEl = session?.draggedEl?.closest("[data-ohw-nav-children]") != null ? session.draggedEl : null;
10633
11923
  navDragRef.current = null;
@@ -10644,7 +11934,7 @@ function useNavItemDrag({
10644
11934
  document.documentElement.removeAttribute("data-ohw-nav-dragging-root");
10645
11935
  unlockItemDragInteraction();
10646
11936
  }, [setDraggedItemRect, setIsItemDragging, setSiblingHintRects]);
10647
- const refreshNavDragVisuals = (0, import_react13.useCallback)(
11937
+ const refreshNavDragVisuals = (0, import_react14.useCallback)(
10648
11938
  (session, activeSlot, clientX, clientY) => {
10649
11939
  setDraggedItemRect(session.draggedEl.getBoundingClientRect());
10650
11940
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -10662,13 +11952,13 @@ function useNavItemDrag({
10662
11952
  },
10663
11953
  [setDraggedItemRect, setSiblingHintRects]
10664
11954
  );
10665
- const refreshNavDragVisualsRef = (0, import_react13.useRef)(refreshNavDragVisuals);
11955
+ const refreshNavDragVisualsRef = (0, import_react14.useRef)(refreshNavDragVisuals);
10666
11956
  refreshNavDragVisualsRef.current = refreshNavDragVisuals;
10667
- const commitNavDragRef = (0, import_react13.useRef)(() => {
11957
+ const commitNavDragRef = (0, import_react14.useRef)(() => {
10668
11958
  });
10669
- const beginNavDragRef = (0, import_react13.useRef)(() => {
11959
+ const beginNavDragRef = (0, import_react14.useRef)(() => {
10670
11960
  });
10671
- const beginNavDrag = (0, import_react13.useCallback)(
11961
+ const beginNavDrag = (0, import_react14.useCallback)(
10672
11962
  (session) => {
10673
11963
  const rect = session.draggedEl.getBoundingClientRect();
10674
11964
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -10702,7 +11992,7 @@ function useNavItemDrag({
10702
11992
  ]
10703
11993
  );
10704
11994
  beginNavDragRef.current = beginNavDrag;
10705
- const commitNavDrag = (0, import_react13.useCallback)(
11995
+ const commitNavDrag = (0, import_react14.useCallback)(
10706
11996
  (clientX, clientY) => {
10707
11997
  const session = navDragRef.current;
10708
11998
  if (!session) {
@@ -10763,7 +12053,7 @@ function useNavItemDrag({
10763
12053
  [clearNavDragVisuals, deselectRef, editContentRef, postToParentRef, selectRef]
10764
12054
  );
10765
12055
  commitNavDragRef.current = commitNavDrag;
10766
- const startNavLinkDrag = (0, import_react13.useCallback)(
12056
+ const startNavLinkDrag = (0, import_react14.useCallback)(
10767
12057
  (anchor, clientX, clientY, wasSelected) => {
10768
12058
  if (footerDragRef.current) return false;
10769
12059
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
@@ -10781,7 +12071,7 @@ function useNavItemDrag({
10781
12071
  },
10782
12072
  [beginNavDrag, footerDragRef, isDragHandleDisabled2, isCtaButton]
10783
12073
  );
10784
- const onNavDragOver = (0, import_react13.useCallback)(
12074
+ const onNavDragOver = (0, import_react14.useCallback)(
10785
12075
  (e) => {
10786
12076
  const session = navDragRef.current;
10787
12077
  if (!session) return false;
@@ -10793,7 +12083,7 @@ function useNavItemDrag({
10793
12083
  },
10794
12084
  []
10795
12085
  );
10796
- (0, import_react13.useEffect)(() => {
12086
+ (0, import_react14.useEffect)(() => {
10797
12087
  if (!isEditMode) return;
10798
12088
  const THRESHOLD = 10;
10799
12089
  const resolveWasSelected = (el) => {
@@ -10918,7 +12208,7 @@ function useNavItemDrag({
10918
12208
  setLinkPopover,
10919
12209
  suppressNextClickRef
10920
12210
  ]);
10921
- const armNavPressFromChrome = (0, import_react13.useCallback)(
12211
+ const armNavPressFromChrome = (0, import_react14.useCallback)(
10922
12212
  (selected, clientX, clientY, pointerId) => {
10923
12213
  const hrefKey = selected.getAttribute("data-ohw-href-key");
10924
12214
  if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
@@ -10949,8 +12239,8 @@ function useNavItemDrag({
10949
12239
  }
10950
12240
 
10951
12241
  // src/ui/footer-container-chrome.tsx
10952
- var import_lucide_react13 = require("lucide-react");
10953
- var import_jsx_runtime26 = require("react/jsx-runtime");
12242
+ var import_lucide_react15 = require("lucide-react");
12243
+ var import_jsx_runtime29 = require("react/jsx-runtime");
10954
12244
  function FooterContainerChrome({
10955
12245
  rect,
10956
12246
  onAdd,
@@ -10958,7 +12248,7 @@ function FooterContainerChrome({
10958
12248
  }) {
10959
12249
  const chromeGap = 6;
10960
12250
  const buttonMargin = 7;
10961
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
12251
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
10962
12252
  "div",
10963
12253
  {
10964
12254
  "data-ohw-footer-container-chrome": "",
@@ -10970,8 +12260,8 @@ function FooterContainerChrome({
10970
12260
  width: rect.width + chromeGap * 2,
10971
12261
  height: rect.height + chromeGap * 2
10972
12262
  },
10973
- children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(Tooltip, { children: [
10974
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
12263
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Tooltip, { children: [
12264
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
10975
12265
  "button",
10976
12266
  {
10977
12267
  type: "button",
@@ -10990,17 +12280,17 @@ function FooterContainerChrome({
10990
12280
  if (addDisabled) return;
10991
12281
  onAdd();
10992
12282
  },
10993
- children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react13.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
12283
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react15.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
10994
12284
  }
10995
12285
  ) }),
10996
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
12286
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
10997
12287
  ] })
10998
12288
  }
10999
12289
  ) });
11000
12290
  }
11001
12291
 
11002
12292
  // src/lib/carousel.ts
11003
- var import_react14 = require("react");
12293
+ var import_react15 = require("react");
11004
12294
  var CAROUSEL_ATTR = "data-ohw-carousel";
11005
12295
  var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
11006
12296
  var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
@@ -11062,8 +12352,8 @@ function applyCarouselNode(key, val) {
11062
12352
  return true;
11063
12353
  }
11064
12354
  function useOhwCarousel(key, initial) {
11065
- const [images, setImages] = (0, import_react14.useState)(initial);
11066
- (0, import_react14.useEffect)(() => {
12355
+ const [images, setImages] = (0, import_react15.useState)(initial);
12356
+ (0, import_react15.useEffect)(() => {
11067
12357
  const el = document.querySelector(
11068
12358
  `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
11069
12359
  );
@@ -11176,6 +12466,18 @@ function collectEditableNodes(extraContent, root = document) {
11176
12466
  }
11177
12467
  if (extraContent && !isScoped) {
11178
12468
  applyNavFooterDeleteOverrides(byKey, extraContent);
12469
+ for (const key of LOGO_IMAGE_KEYS) {
12470
+ if (!(key in extraContent)) continue;
12471
+ byKey.set(key, { key, type: "image", text: extraContent[key] ?? "" });
12472
+ }
12473
+ for (const key of [LOGO_PLACEHOLDER_KEY, LOGO_ALT_KEY]) {
12474
+ if (!(key in extraContent)) continue;
12475
+ byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
12476
+ }
12477
+ for (const key of LOGO_SIZE_KEYS) {
12478
+ if (!(key in extraContent)) continue;
12479
+ byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
12480
+ }
11179
12481
  }
11180
12482
  return Array.from(byKey.values());
11181
12483
  }
@@ -11278,7 +12580,7 @@ function isNavbarLinksContainer(el) {
11278
12580
  function isNavigationItem(el) {
11279
12581
  const anchor = el.matches("[data-ohw-href-key]") ? el : el.closest("[data-ohw-href-key]");
11280
12582
  if (!anchor) return false;
11281
- return Boolean(anchor.querySelector('[data-ohw-editable="text"]'));
12583
+ return Boolean(anchor.querySelector('[data-ohw-editable="text"]')) || Boolean(getSocialItem(anchor));
11282
12584
  }
11283
12585
  function findFooterItemGroup(item) {
11284
12586
  const explicit = item.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
@@ -11299,8 +12601,9 @@ function isInferredFooterGroup(el) {
11299
12601
  const footer = el.closest("footer");
11300
12602
  if (!footer || el === footer) return false;
11301
12603
  if (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column")) return true;
12604
+ if (isSocialsRow(el)) return false;
11302
12605
  const count = Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(
11303
- isNavigationItem
12606
+ (item) => isNavigationItem(item) && !getSocialItem(item)
11304
12607
  ).length;
11305
12608
  return count >= 2;
11306
12609
  }
@@ -11344,7 +12647,8 @@ function deleteSelectedNavFooterItem(deps) {
11344
12647
  if (key.endsWith("-href")) applyLinkByKey2(key, text);
11345
12648
  else {
11346
12649
  document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`).forEach((el) => {
11347
- el.textContent = text;
12650
+ if (el.getAttribute("data-ohw-editable") === "icon") applyIconMarkup(el, text);
12651
+ else el.textContent = text;
11348
12652
  });
11349
12653
  }
11350
12654
  }
@@ -11406,6 +12710,21 @@ function deleteSelectedNavFooterItem(deps) {
11406
12710
  });
11407
12711
  return true;
11408
12712
  }
12713
+ const social = getSocialItem(selected);
12714
+ if (social) {
12715
+ const result = removeSocialItem(social, getEditContent());
12716
+ if (!result) return false;
12717
+ finishDelete({
12718
+ toastTitle: "Social deleted",
12719
+ removedKeys: result.removedKeys,
12720
+ previousContent: result.previousContent,
12721
+ orderKey: SOCIALS_ORDER_KEY,
12722
+ orderJson: JSON.stringify(result.order),
12723
+ previousOrderJson: JSON.stringify(result.previousOrder),
12724
+ undoDom: result.undo
12725
+ });
12726
+ return true;
12727
+ }
11409
12728
  if (isFooterHrefKey(hrefKey)) {
11410
12729
  const result = deleteFooterItem(selected);
11411
12730
  if (!result) return false;
@@ -11424,14 +12743,14 @@ function deleteSelectedNavFooterItem(deps) {
11424
12743
  }
11425
12744
 
11426
12745
  // src/ui/navbar-container-chrome.tsx
11427
- var import_lucide_react14 = require("lucide-react");
11428
- var import_jsx_runtime27 = require("react/jsx-runtime");
12746
+ var import_lucide_react16 = require("lucide-react");
12747
+ var import_jsx_runtime30 = require("react/jsx-runtime");
11429
12748
  function NavbarContainerChrome({
11430
12749
  rect,
11431
12750
  onAdd
11432
12751
  }) {
11433
12752
  const chromeGap = 6;
11434
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12753
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
11435
12754
  "div",
11436
12755
  {
11437
12756
  "data-ohw-navbar-container-chrome": "",
@@ -11443,7 +12762,7 @@ function NavbarContainerChrome({
11443
12762
  width: rect.width + chromeGap * 2,
11444
12763
  height: rect.height + chromeGap * 2
11445
12764
  },
11446
- children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12765
+ children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
11447
12766
  "button",
11448
12767
  {
11449
12768
  type: "button",
@@ -11460,7 +12779,7 @@ function NavbarContainerChrome({
11460
12779
  e.stopPropagation();
11461
12780
  onAdd();
11462
12781
  },
11463
- children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react14.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
12782
+ children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react16.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
11464
12783
  }
11465
12784
  )
11466
12785
  }
@@ -11469,7 +12788,7 @@ function NavbarContainerChrome({
11469
12788
 
11470
12789
  // src/ui/drop-indicator.tsx
11471
12790
  var React10 = __toESM(require("react"), 1);
11472
- var import_jsx_runtime28 = require("react/jsx-runtime");
12791
+ var import_jsx_runtime31 = require("react/jsx-runtime");
11473
12792
  var dropIndicatorVariants = cva(
11474
12793
  "ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
11475
12794
  {
@@ -11493,7 +12812,7 @@ var dropIndicatorVariants = cva(
11493
12812
  );
11494
12813
  var DropIndicator = React10.forwardRef(
11495
12814
  ({ className, direction, state, ...props }, ref) => {
11496
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
12815
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
11497
12816
  "div",
11498
12817
  {
11499
12818
  ref,
@@ -11510,7 +12829,7 @@ var DropIndicator = React10.forwardRef(
11510
12829
  DropIndicator.displayName = "DropIndicator";
11511
12830
 
11512
12831
  // src/ui/badge.tsx
11513
- var import_jsx_runtime29 = require("react/jsx-runtime");
12832
+ var import_jsx_runtime32 = require("react/jsx-runtime");
11514
12833
  var badgeVariants = cva(
11515
12834
  "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",
11516
12835
  {
@@ -11528,12 +12847,12 @@ var badgeVariants = cva(
11528
12847
  }
11529
12848
  );
11530
12849
  function Badge({ className, variant, ...props }) {
11531
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
12850
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
11532
12851
  }
11533
12852
 
11534
12853
  // src/OhhwellsBridge.tsx
11535
- var import_lucide_react15 = require("lucide-react");
11536
- var import_jsx_runtime30 = require("react/jsx-runtime");
12854
+ var import_lucide_react17 = require("lucide-react");
12855
+ var import_jsx_runtime33 = require("react/jsx-runtime");
11537
12856
  var PRIMARY3 = "#0885FE";
11538
12857
  var IMAGE_FADE_MS = 300;
11539
12858
  function runOpacityFade(el, onDone) {
@@ -11627,21 +12946,10 @@ function parseSchedulingInsertAfter(insertAfter) {
11627
12946
  insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
11628
12947
  };
11629
12948
  }
11630
- function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
11631
- const parsed = parseSchedulingInsertAfter(insertAfter);
11632
- const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
11633
- const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
11634
- return { effectiveInsertAfter, insertBefore };
11635
- }
11636
- function getSchedulingMountPoint(insertAfter) {
11637
- const { anchor } = parseSchedulingInsertAfter(insertAfter);
11638
- let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
11639
- if (!anchorEl && anchor === "scheduling") {
11640
- const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
11641
- anchorEl = widgets.at(-1) ?? null;
11642
- }
11643
- if (!anchorEl) return null;
11644
- return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
12949
+ function resolveEntryAnchor(entry) {
12950
+ if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
12951
+ const parsed = parseSchedulingInsertAfter(entry.insertAfter);
12952
+ return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
11645
12953
  }
11646
12954
  function schedulingMountDepth(insertAfter) {
11647
12955
  if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
@@ -11658,8 +12966,7 @@ function getPageSchedulingEntries(raw) {
11658
12966
  }
11659
12967
  }
11660
12968
  function isSchedulingWidgetMissing(entry) {
11661
- const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
11662
- return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
12969
+ return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
11663
12970
  }
11664
12971
  function hasMissingSchedulingWidgets(entries) {
11665
12972
  return entries.some(isSchedulingWidgetMissing);
@@ -11689,16 +12996,17 @@ function initSectionsFromContent(content, removeExisting = false) {
11689
12996
  } catch {
11690
12997
  }
11691
12998
  }
11692
- function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
11693
- const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
11694
- const sectionId = schedulingSectionId(effectiveInsertAfter);
12999
+ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
13000
+ const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
13001
+ const sectionId = schedulingSectionId(widgetId);
11695
13002
  if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
11696
- const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
11697
- if (!mountPoint) return false;
13003
+ const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
13004
+ if (!anchorEl) return false;
13005
+ const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
11698
13006
  const container = document.createElement("div");
11699
13007
  container.dataset.ohwSectionContainer = "scheduling";
11700
- if (insertBefore) {
11701
- const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
13008
+ if (beforeId) {
13009
+ const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
11702
13010
  const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
11703
13011
  if (!beforePoint) return false;
11704
13012
  beforePoint.insertAdjacentElement("beforebegin", container);
@@ -11709,19 +13017,25 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
11709
13017
  }
11710
13018
  tail.insertAdjacentElement("afterend", container);
11711
13019
  }
11712
- const root = (0, import_client2.createRoot)(container);
11713
- (0, import_react_dom3.flushSync)(() => {
11714
- root.render(
11715
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
11716
- SchedulingWidget,
11717
- {
11718
- notifyOnConnect,
11719
- initialScheduleId: scheduleId,
11720
- insertAfter: effectiveInsertAfter
11721
- }
11722
- )
11723
- );
11724
- });
13020
+ try {
13021
+ const root = (0, import_client2.createRoot)(container);
13022
+ (0, import_react_dom3.flushSync)(() => {
13023
+ root.render(
13024
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
13025
+ SchedulingWidget,
13026
+ {
13027
+ notifyOnConnect,
13028
+ initialScheduleId: scheduleId,
13029
+ insertAfter: widgetId
13030
+ }
13031
+ )
13032
+ );
13033
+ });
13034
+ } catch (err) {
13035
+ console.error("[ow:scheduling] render threw", err);
13036
+ container.remove();
13037
+ return false;
13038
+ }
11725
13039
  const tracker = getSectionsTracker();
11726
13040
  let sections = [];
11727
13041
  try {
@@ -11729,10 +13043,12 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
11729
13043
  } catch {
11730
13044
  }
11731
13045
  const inEditor = typeof window !== "undefined" && window.self !== window.top;
11732
- if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
13046
+ if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
11733
13047
  sections.push({
11734
13048
  type: "scheduling",
11735
- insertAfter: effectiveInsertAfter,
13049
+ insertAfter: widgetId,
13050
+ anchorId,
13051
+ beforeId: beforeId ?? null,
11736
13052
  pagePath: window.location.pathname,
11737
13053
  ...scheduleId ? { scheduleId } : {}
11738
13054
  });
@@ -11746,7 +13062,8 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
11746
13062
  for (let i = pending.length - 1; i >= 0; i--) {
11747
13063
  const entry = pending[i];
11748
13064
  const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
11749
- if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId)) {
13065
+ const { anchorId, beforeId } = resolveEntryAnchor(entry);
13066
+ if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
11750
13067
  pending.splice(i, 1);
11751
13068
  }
11752
13069
  }
@@ -11760,6 +13077,17 @@ function applyLinkHref(el, val) {
11760
13077
  const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
11761
13078
  if (anchor) anchor.setAttribute("href", val);
11762
13079
  }
13080
+ function currentIconRef(el) {
13081
+ const uploaded = el instanceof HTMLImageElement ? el : el.querySelector("img");
13082
+ if (uploaded?.getAttribute("src")) {
13083
+ return uploaded.getAttribute("src") ?? "";
13084
+ }
13085
+ const svg = el instanceof SVGElement ? el : el.querySelector("svg");
13086
+ const named = Array.from(svg?.classList ?? []).find(
13087
+ (c) => c.startsWith("lucide-") && c !== "lucide-icon"
13088
+ );
13089
+ return named ? `lucide:${named.slice("lucide-".length)}` : "";
13090
+ }
11763
13091
  function getEditMeasureEl(editable) {
11764
13092
  return editable.closest("[data-ohw-href-key]") ?? editable;
11765
13093
  }
@@ -11804,8 +13132,11 @@ function isMediaEditable(el) {
11804
13132
  const t = el.dataset.ohwEditable;
11805
13133
  return t === "image" || t === "bg-image" || t === "video";
11806
13134
  }
13135
+ function isIconEditable(el) {
13136
+ return el.dataset.ohwEditable === "icon";
13137
+ }
11807
13138
  var MEDIA_SELECTOR = '[data-ohw-editable="image"], [data-ohw-editable="bg-image"], [data-ohw-editable="video"]';
11808
- var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"])';
13139
+ 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"])';
11809
13140
  function getVideoEl2(el) {
11810
13141
  return el instanceof HTMLVideoElement ? el : el.querySelector("video");
11811
13142
  }
@@ -11876,6 +13207,13 @@ function isInsideLinkEditor(target) {
11876
13207
  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"]')
11877
13208
  );
11878
13209
  }
13210
+ function isInsideFloatingPanel(target) {
13211
+ return Boolean(target.closest("[data-ohw-floating-panel]"));
13212
+ }
13213
+ function isPointOverFloatingPanel(clientX, clientY) {
13214
+ const el = document.elementFromPoint(clientX, clientY);
13215
+ return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
13216
+ }
11879
13217
  function getHrefKeyFromElement(el) {
11880
13218
  if (!el) return null;
11881
13219
  const anchor = el.closest("[data-ohw-href-key]");
@@ -11923,13 +13261,29 @@ function isNavItemPointerTarget(el) {
11923
13261
  function getNavigationItemAnchor(el) {
11924
13262
  const anchor = el.matches("[data-ohw-href-key]") ? el : el.closest("[data-ohw-href-key]");
11925
13263
  if (!anchor) return null;
11926
- if (!anchor.querySelector('[data-ohw-editable="text"]')) return null;
13264
+ if (!anchor.querySelector('[data-ohw-editable="text"]') && !getSocialItem(anchor)) return null;
11927
13265
  if (!isNavItemPointerTarget(anchor)) return null;
11928
13266
  return anchor;
11929
13267
  }
11930
13268
  function isNavigationItem2(el) {
11931
13269
  return getNavigationItemAnchor(el) !== null;
11932
13270
  }
13271
+ function requestSocialDialog(anchor, post, content) {
13272
+ const item = getSocialItem(anchor);
13273
+ if (!item) return false;
13274
+ const iconKey = item.querySelector('[data-ohw-editable="icon"]')?.dataset.ohwKey ?? "";
13275
+ post({
13276
+ type: "ow:social-pick",
13277
+ hrefKey: item.getAttribute("data-ohw-href-key") ?? "",
13278
+ iconKey,
13279
+ url: getLinkHref4(item),
13280
+ iconStyle: detectIconStyle(item),
13281
+ // What was chosen last time. Guessing from the address instead reads as "Website" for anything
13282
+ // unrecognised, and for an item with no address at all — so a deliberate choice looked lost.
13283
+ platformId: content[socialPlatformKey(iconKey)] ?? ""
13284
+ });
13285
+ return true;
13286
+ }
11933
13287
  function listNavigationItems() {
11934
13288
  return Array.from(
11935
13289
  document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
@@ -11964,7 +13318,7 @@ function getNavigationRoot(el) {
11964
13318
  return el.closest("nav, footer, aside");
11965
13319
  }
11966
13320
  function countFooterNavItems(el) {
11967
- return Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(isNavigationItem2).length;
13321
+ return Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter((item) => isNavigationItem2(item) && !getSocialItem(item)).length;
11968
13322
  }
11969
13323
  function findFooterItemGroup2(item) {
11970
13324
  const explicit = item.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
@@ -11985,10 +13339,11 @@ function isInferredFooterGroup2(el) {
11985
13339
  const footer = el.closest("footer");
11986
13340
  if (!footer || el === footer) return false;
11987
13341
  if (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column")) return true;
13342
+ if (isSocialsRow(el)) return false;
11988
13343
  return countFooterNavItems(el) >= 2;
11989
13344
  }
11990
13345
  function isNavigationContainer(el) {
11991
- 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);
13346
+ 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);
11992
13347
  }
11993
13348
  function isNavbarLinksContainer2(el) {
11994
13349
  return el.hasAttribute("data-ohw-nav-container");
@@ -12071,6 +13426,8 @@ function resolveNavContainerSelectionTarget(target, clientX, clientY) {
12071
13426
  return null;
12072
13427
  }
12073
13428
  function getNavigationSelectionParent(el) {
13429
+ const socialsRow = findSocialsRow(el);
13430
+ if (socialsRow) return socialsRow;
12074
13431
  if (isNavigationItem2(el)) {
12075
13432
  const childrenRoot = el.closest("[data-ohw-nav-children]");
12076
13433
  if (childrenRoot) {
@@ -12089,13 +13446,17 @@ function getNavigationSelectionParent(el) {
12089
13446
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
12090
13447
  return getFooterLinksContainer();
12091
13448
  }
12092
- if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
13449
+ 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)) {
12093
13450
  return getNavigationRoot(el);
12094
13451
  }
12095
13452
  return null;
12096
13453
  }
12097
13454
  function collectNavigationItemSiblingHintRects(selected) {
12098
13455
  if (!isNavigationItem2(selected)) return [];
13456
+ const socialsRow = findSocialsRow(selected);
13457
+ if (socialsRow) {
13458
+ return listSocialItems(socialsRow).filter((item) => item !== selected).map((item) => item.getBoundingClientRect());
13459
+ }
12099
13460
  const footerColumn = getFooterColumn(selected);
12100
13461
  if (footerColumn) {
12101
13462
  return listFooterLinksInColumn(footerColumn).filter((link) => link !== selected).map((link) => link.getBoundingClientRect());
@@ -12328,7 +13689,7 @@ function EditGlowChrome({
12328
13689
  hideHandle = false
12329
13690
  }) {
12330
13691
  const GAP = SELECTION_CHROME_GAP2;
12331
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
13692
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
12332
13693
  "div",
12333
13694
  {
12334
13695
  ref: elRef,
@@ -12343,7 +13704,7 @@ function EditGlowChrome({
12343
13704
  zIndex: 2147483646
12344
13705
  },
12345
13706
  children: [
12346
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
13707
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
12347
13708
  "div",
12348
13709
  {
12349
13710
  style: {
@@ -12356,7 +13717,7 @@ function EditGlowChrome({
12356
13717
  }
12357
13718
  }
12358
13719
  ),
12359
- reorderHrefKey && !hideHandle && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
13720
+ reorderHrefKey && !hideHandle && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
12360
13721
  "div",
12361
13722
  {
12362
13723
  "data-ohw-drag-handle-container": "",
@@ -12368,7 +13729,7 @@ function EditGlowChrome({
12368
13729
  transform: "translate(calc(-100% - 7px), -50%)",
12369
13730
  pointerEvents: dragDisabled ? "none" : "auto"
12370
13731
  },
12371
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
13732
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
12372
13733
  DragHandle,
12373
13734
  {
12374
13735
  "aria-label": `Reorder ${reorderHrefKey}`,
@@ -12551,9 +13912,9 @@ function FloatingToolbar({
12551
13912
  showEditLink,
12552
13913
  onEditLink
12553
13914
  }) {
12554
- const localRef = import_react15.default.useRef(null);
12555
- const [measuredW, setMeasuredW] = import_react15.default.useState(330);
12556
- const setRefs = import_react15.default.useCallback(
13915
+ const localRef = import_react16.default.useRef(null);
13916
+ const [measuredW, setMeasuredW] = import_react16.default.useState(330);
13917
+ const setRefs = import_react16.default.useCallback(
12557
13918
  (node) => {
12558
13919
  localRef.current = node;
12559
13920
  if (typeof elRef === "function") elRef(node);
@@ -12565,7 +13926,7 @@ function FloatingToolbar({
12565
13926
  },
12566
13927
  [elRef]
12567
13928
  );
12568
- import_react15.default.useLayoutEffect(() => {
13929
+ import_react16.default.useLayoutEffect(() => {
12569
13930
  const node = localRef.current;
12570
13931
  if (!node) return;
12571
13932
  const update = () => {
@@ -12578,7 +13939,7 @@ function FloatingToolbar({
12578
13939
  return () => ro.disconnect();
12579
13940
  }, [showEditLink, activeCommands]);
12580
13941
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
12581
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
13942
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
12582
13943
  "div",
12583
13944
  {
12584
13945
  ref: setRefs,
@@ -12590,12 +13951,12 @@ function FloatingToolbar({
12590
13951
  zIndex: 2147483647,
12591
13952
  pointerEvents: "auto"
12592
13953
  },
12593
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(CustomToolbar, { children: [
12594
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_react15.default.Fragment, { children: [
12595
- gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(CustomToolbarDivider, {}),
13954
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(CustomToolbar, { children: [
13955
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_react16.default.Fragment, { children: [
13956
+ gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CustomToolbarDivider, {}),
12596
13957
  btns.map((btn) => {
12597
13958
  const isActive = activeCommands.has(btn.cmd);
12598
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
13959
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
12599
13960
  CustomToolbarButton,
12600
13961
  {
12601
13962
  title: btn.title,
@@ -12604,7 +13965,7 @@ function FloatingToolbar({
12604
13965
  e.preventDefault();
12605
13966
  onCommand(btn.cmd);
12606
13967
  },
12607
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
13968
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
12608
13969
  "svg",
12609
13970
  {
12610
13971
  width: "16",
@@ -12625,7 +13986,7 @@ function FloatingToolbar({
12625
13986
  );
12626
13987
  })
12627
13988
  ] }, gi)),
12628
- showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
13989
+ showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
12629
13990
  CustomToolbarButton,
12630
13991
  {
12631
13992
  type: "button",
@@ -12639,7 +14000,7 @@ function FloatingToolbar({
12639
14000
  e.preventDefault();
12640
14001
  e.stopPropagation();
12641
14002
  },
12642
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react15.Link, { className: "size-4 shrink-0", "aria-hidden": true })
14003
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Link, { className: "size-4 shrink-0", "aria-hidden": true })
12643
14004
  }
12644
14005
  ) : null
12645
14006
  ] })
@@ -12656,7 +14017,7 @@ function StateToggle({
12656
14017
  states,
12657
14018
  onStateChange
12658
14019
  }) {
12659
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
14020
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
12660
14021
  ToggleGroup,
12661
14022
  {
12662
14023
  "data-ohw-state-toggle": "",
@@ -12670,11 +14031,12 @@ function StateToggle({
12670
14031
  left: rect.right - 8,
12671
14032
  transform: "translateX(-100%)"
12672
14033
  },
12673
- children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
14034
+ children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
12674
14035
  }
12675
14036
  );
12676
14037
  }
12677
14038
  var contentCache = /* @__PURE__ */ new Map();
14039
+ var fetchedContentPaths = /* @__PURE__ */ new Set();
12678
14040
  function resolveSubdomain(subdomainFromQuery) {
12679
14041
  if (subdomainFromQuery) return subdomainFromQuery;
12680
14042
  if (typeof window !== "undefined") {
@@ -12697,8 +14059,8 @@ function OhhwellsBridge() {
12697
14059
  const router = (0, import_navigation3.useRouter)();
12698
14060
  const searchParams = (0, import_navigation3.useSearchParams)();
12699
14061
  const isEditMode = isEditSessionActive();
12700
- const [bridgeRoot, setBridgeRoot] = (0, import_react15.useState)(null);
12701
- (0, import_react15.useEffect)(() => {
14062
+ const [bridgeRoot, setBridgeRoot] = (0, import_react16.useState)(null);
14063
+ (0, import_react16.useEffect)(() => {
12702
14064
  const figtreeFontId = "ohw-figtree-font";
12703
14065
  if (!document.getElementById(figtreeFontId)) {
12704
14066
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -12727,110 +14089,137 @@ function OhhwellsBridge() {
12727
14089
  const subdomain = resolveSubdomain(subdomainFromQuery);
12728
14090
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
12729
14091
  useSavedLinkNavigation(isEditMode);
12730
- const postToParent2 = (0, import_react15.useCallback)((data) => {
14092
+ const postToParent2 = (0, import_react16.useCallback)((data) => {
12731
14093
  if (typeof window !== "undefined" && window.parent !== window) {
12732
14094
  window.parent.postMessage(data, "*");
12733
14095
  }
12734
14096
  }, []);
12735
- const [fetchState, setFetchState] = (0, import_react15.useState)("idle");
12736
- const autoSaveTimers = (0, import_react15.useRef)(/* @__PURE__ */ new Map());
12737
- const activeElRef = (0, import_react15.useRef)(null);
12738
- const pointerHeldRef = (0, import_react15.useRef)(false);
12739
- const selectedElRef = (0, import_react15.useRef)(null);
12740
- const selectedHrefKeyRef = (0, import_react15.useRef)(null);
12741
- const selectedFooterColAttrRef = (0, import_react15.useRef)(null);
12742
- const originalContentRef = (0, import_react15.useRef)(null);
12743
- const activeStateElRef = (0, import_react15.useRef)(null);
12744
- const parentScrollRef = (0, import_react15.useRef)(null);
12745
- const visibleViewportRef = (0, import_react15.useRef)(null);
12746
- const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react15.useState)(null);
12747
- const attachVisibleViewport = (0, import_react15.useCallback)((node) => {
14097
+ const [fetchState, setFetchState] = (0, import_react16.useState)("idle");
14098
+ const autoSaveTimers = (0, import_react16.useRef)(/* @__PURE__ */ new Map());
14099
+ const activeElRef = (0, import_react16.useRef)(null);
14100
+ const pointerHeldRef = (0, import_react16.useRef)(false);
14101
+ const selectedElRef = (0, import_react16.useRef)(null);
14102
+ const selectedHrefKeyRef = (0, import_react16.useRef)(null);
14103
+ const selectedFooterColAttrRef = (0, import_react16.useRef)(null);
14104
+ const originalContentRef = (0, import_react16.useRef)(null);
14105
+ const activeStateElRef = (0, import_react16.useRef)(null);
14106
+ const parentScrollRef = (0, import_react16.useRef)(null);
14107
+ const visibleViewportRef = (0, import_react16.useRef)(null);
14108
+ const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react16.useState)(null);
14109
+ const attachVisibleViewport = (0, import_react16.useCallback)((node) => {
12748
14110
  visibleViewportRef.current = node;
12749
14111
  setDialogPortalContainer(node);
12750
14112
  if (node) applyVisibleViewport(node, parentScrollRef.current);
12751
14113
  }, []);
12752
- const toolbarElRef = (0, import_react15.useRef)(null);
12753
- const glowElRef = (0, import_react15.useRef)(null);
12754
- const hoveredImageRef = (0, import_react15.useRef)(null);
12755
- const hoveredImageHasTextOverlapRef = (0, import_react15.useRef)(false);
12756
- const dragOverElRef = (0, import_react15.useRef)(null);
12757
- const [mediaHover, setMediaHover] = (0, import_react15.useState)(null);
12758
- const [carouselHover, setCarouselHover] = (0, import_react15.useState)(null);
12759
- const [uploadingRects, setUploadingRects] = (0, import_react15.useState)({});
12760
- const hoveredGapRef = (0, import_react15.useRef)(null);
12761
- const imageUnhoverTimerRef = (0, import_react15.useRef)(null);
12762
- const imageShowTimerRef = (0, import_react15.useRef)(null);
12763
- const editStylesRef = (0, import_react15.useRef)(null);
12764
- const activateRef = (0, import_react15.useRef)(() => {
14114
+ const toolbarElRef = (0, import_react16.useRef)(null);
14115
+ const glowElRef = (0, import_react16.useRef)(null);
14116
+ const hoveredImageRef = (0, import_react16.useRef)(null);
14117
+ const hoveredImageHasTextOverlapRef = (0, import_react16.useRef)(false);
14118
+ const dragOverElRef = (0, import_react16.useRef)(null);
14119
+ const [mediaHover, setMediaHover] = (0, import_react16.useState)(null);
14120
+ const [carouselHover, setCarouselHover] = (0, import_react16.useState)(null);
14121
+ const [uploadingRects, setUploadingRects] = (0, import_react16.useState)({});
14122
+ const hoveredGapRef = (0, import_react16.useRef)(null);
14123
+ const imageUnhoverTimerRef = (0, import_react16.useRef)(null);
14124
+ const imageShowTimerRef = (0, import_react16.useRef)(null);
14125
+ const editStylesRef = (0, import_react16.useRef)(null);
14126
+ const activateRef = (0, import_react16.useRef)(() => {
14127
+ });
14128
+ const deactivateRef = (0, import_react16.useRef)(() => {
12765
14129
  });
12766
- const deactivateRef = (0, import_react15.useRef)(() => {
14130
+ const selectRef = (0, import_react16.useRef)(() => {
12767
14131
  });
12768
- const selectRef = (0, import_react15.useRef)(() => {
14132
+ const selectFrameRef = (0, import_react16.useRef)(() => {
12769
14133
  });
12770
- const selectFrameRef = (0, import_react15.useRef)(() => {
14134
+ const selectLogoRef = (0, import_react16.useRef)(() => {
12771
14135
  });
12772
- const deselectRef = (0, import_react15.useRef)(() => {
14136
+ const openLogoSizePanelRef = (0, import_react16.useRef)(() => {
12773
14137
  });
12774
- const reselectNavigationItemRef = (0, import_react15.useRef)(() => {
14138
+ const deselectRef = (0, import_react16.useRef)(() => {
12775
14139
  });
12776
- const commitNavigationTextEditRef = (0, import_react15.useRef)(() => {
14140
+ const closeFloatingPanelOnlyRef = (0, import_react16.useRef)(() => {
12777
14141
  });
12778
- const handleDeleteSelectedRef = (0, import_react15.useRef)(() => false);
12779
- const runPendingDeleteUndoRef = (0, import_react15.useRef)(() => false);
12780
- const isFooterFrameSelectionRef = (0, import_react15.useRef)(false);
12781
- const refreshActiveCommandsRef = (0, import_react15.useRef)(() => {
14142
+ const reselectNavigationItemRef = (0, import_react16.useRef)(() => {
12782
14143
  });
12783
- const postToParentRef = (0, import_react15.useRef)(postToParent2);
14144
+ const commitNavigationTextEditRef = (0, import_react16.useRef)(() => {
14145
+ });
14146
+ const handleDeleteSelectedRef = (0, import_react16.useRef)(() => false);
14147
+ const runPendingDeleteUndoRef = (0, import_react16.useRef)(() => false);
14148
+ const isFooterFrameSelectionRef = (0, import_react16.useRef)(false);
14149
+ const refreshActiveCommandsRef = (0, import_react16.useRef)(() => {
14150
+ });
14151
+ const postToParentRef = (0, import_react16.useRef)(postToParent2);
12784
14152
  postToParentRef.current = postToParent2;
12785
- const aiSectionApiRef = (0, import_react15.useRef)(null);
12786
- const sectionsLoadedRef = (0, import_react15.useRef)(false);
12787
- const pendingScheduleConfigRequests = (0, import_react15.useRef)([]);
12788
- const [toolbarRect, setToolbarRect] = (0, import_react15.useState)(null);
12789
- const [toolbarVariant, setToolbarVariant] = (0, import_react15.useState)("none");
12790
- const toolbarVariantRef = (0, import_react15.useRef)("none");
14153
+ const aiSectionApiRef = (0, import_react16.useRef)(null);
14154
+ const sectionsLoadedRef = (0, import_react16.useRef)(false);
14155
+ const pendingScheduleConfigRequests = (0, import_react16.useRef)([]);
14156
+ const [toolbarRect, setToolbarRect] = (0, import_react16.useState)(null);
14157
+ const [toolbarVariant, setToolbarVariant] = (0, import_react16.useState)("none");
14158
+ const toolbarVariantRef = (0, import_react16.useRef)("none");
12791
14159
  toolbarVariantRef.current = toolbarVariant;
12792
- const [selectedIsCta, setSelectedIsCta] = (0, import_react15.useState)(false);
12793
- const [reorderHrefKey, setReorderHrefKey] = (0, import_react15.useState)(null);
12794
- const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react15.useState)(false);
12795
- const [toggleState, setToggleState] = (0, import_react15.useState)(null);
12796
- const [maxBadge, setMaxBadge] = (0, import_react15.useState)(null);
12797
- const [activeCommands, setActiveCommands] = (0, import_react15.useState)(/* @__PURE__ */ new Set());
12798
- const [sectionGap, setSectionGap] = (0, import_react15.useState)(null);
12799
- const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react15.useState)(false);
12800
- const hoveredNavContainerRef = (0, import_react15.useRef)(null);
12801
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react15.useState)(null);
12802
- const hoveredItemElRef = (0, import_react15.useRef)(null);
12803
- const [hoveredItemRect, setHoveredItemRect] = (0, import_react15.useState)(null);
12804
- const siblingHintElRef = (0, import_react15.useRef)(null);
12805
- const [siblingHintRect, setSiblingHintRect] = (0, import_react15.useState)(null);
12806
- const [siblingHintRects, setSiblingHintRects] = (0, import_react15.useState)([]);
12807
- const [isItemDragging, setIsItemDragging] = (0, import_react15.useState)(false);
12808
- const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react15.useState)(false);
14160
+ const [selectedIsCta, setSelectedIsCta] = (0, import_react16.useState)(false);
14161
+ const [selectedIsSocial, setSelectedIsSocial] = (0, import_react16.useState)(false);
14162
+ const [selectedIsSocialsRow, setSelectedIsSocialsRow] = (0, import_react16.useState)(false);
14163
+ const [reorderHrefKey, setReorderHrefKey] = (0, import_react16.useState)(null);
14164
+ const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react16.useState)(false);
14165
+ const [toggleState, setToggleState] = (0, import_react16.useState)(null);
14166
+ const [maxBadge, setMaxBadge] = (0, import_react16.useState)(null);
14167
+ const [activeCommands, setActiveCommands] = (0, import_react16.useState)(/* @__PURE__ */ new Set());
14168
+ const [sectionGap, setSectionGap] = (0, import_react16.useState)(null);
14169
+ const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react16.useState)(false);
14170
+ const hoveredNavContainerRef = (0, import_react16.useRef)(null);
14171
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react16.useState)(null);
14172
+ const hoveredItemElRef = (0, import_react16.useRef)(null);
14173
+ const [hoveredItemRect, setHoveredItemRect] = (0, import_react16.useState)(null);
14174
+ const siblingHintElRef = (0, import_react16.useRef)(null);
14175
+ const [siblingHintRect, setSiblingHintRect] = (0, import_react16.useState)(null);
14176
+ const [siblingHintRects, setSiblingHintRects] = (0, import_react16.useState)([]);
14177
+ const [isItemDragging, setIsItemDragging] = (0, import_react16.useState)(false);
14178
+ const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react16.useState)(false);
12809
14179
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
12810
- const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react15.useState)(null);
12811
- const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react15.useState)(null);
12812
- const footerDragRef = (0, import_react15.useRef)(null);
12813
- const [footerDropSlots, setFooterDropSlots] = (0, import_react15.useState)([]);
12814
- const [activeFooterDropIndex, setActiveFooterDropIndex] = (0, import_react15.useState)(null);
12815
- const [draggedItemRect, setDraggedItemRect] = (0, import_react15.useState)(null);
12816
- const footerPointerDragRef = (0, import_react15.useRef)(null);
12817
- const suppressNextClickRef = (0, import_react15.useRef)(false);
12818
- const suppressClickUntilRef = (0, import_react15.useRef)(0);
12819
- const [linkPopover, setLinkPopover] = (0, import_react15.useState)(null);
12820
- const linkPopoverSessionRef = (0, import_react15.useRef)(null);
12821
- const addNavAfterAnchorRef = (0, import_react15.useRef)(null);
12822
- const editContentRef = (0, import_react15.useRef)({});
12823
- const aiSectionsRef = (0, import_react15.useRef)("");
12824
- const pendingDeleteUndoRef = (0, import_react15.useRef)(null);
12825
- const [sitePages, setSitePages] = (0, import_react15.useState)([]);
12826
- const [sectionsByPath, setSectionsByPath] = (0, import_react15.useState)({});
12827
- const sectionsPrefetchGenRef = (0, import_react15.useRef)(0);
12828
- const setLinkPopoverRef = (0, import_react15.useRef)(setLinkPopover);
12829
- const linkPopoverPanelRef = (0, import_react15.useRef)(null);
12830
- const linkPopoverOpenRef = (0, import_react15.useRef)(false);
12831
- const linkPopoverGraceUntilRef = (0, import_react15.useRef)(0);
14180
+ const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react16.useState)(null);
14181
+ const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react16.useState)(null);
14182
+ const footerDragRef = (0, import_react16.useRef)(null);
14183
+ const [footerDropSlots, setFooterDropSlots] = (0, import_react16.useState)([]);
14184
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = (0, import_react16.useState)(null);
14185
+ const [draggedItemRect, setDraggedItemRect] = (0, import_react16.useState)(null);
14186
+ const footerPointerDragRef = (0, import_react16.useRef)(null);
14187
+ const suppressNextClickRef = (0, import_react16.useRef)(false);
14188
+ const suppressClickUntilRef = (0, import_react16.useRef)(0);
14189
+ const [linkPopover, setLinkPopover] = (0, import_react16.useState)(null);
14190
+ const linkPopoverSessionRef = (0, import_react16.useRef)(null);
14191
+ const addNavAfterAnchorRef = (0, import_react16.useRef)(null);
14192
+ const editContentRef = (0, import_react16.useRef)({});
14193
+ const aiSectionsRef = (0, import_react16.useRef)("");
14194
+ const brandKitRef = (0, import_react16.useRef)("");
14195
+ const pendingDeleteUndoRef = (0, import_react16.useRef)(null);
14196
+ const [floatingPanel, setFloatingPanel] = (0, import_react16.useState)(null);
14197
+ const floatingPanelOpenRef = (0, import_react16.useRef)(false);
14198
+ const setFloatingPanelRef = (0, import_react16.useRef)(setFloatingPanel);
14199
+ const [floatingPanelPos, setFloatingPanelPos] = (0, import_react16.useState)(null);
14200
+ const [logoSizeDraft, setLogoSizeDraft] = (0, import_react16.useState)(null);
14201
+ const [editorViewport, setEditorViewport] = (0, import_react16.useState)("desktop");
14202
+ const [parentScrollSnap, setParentScrollSnap] = (0, import_react16.useState)(null);
14203
+ const [sitePages, setSitePages] = (0, import_react16.useState)([]);
14204
+ const [sectionsByPath, setSectionsByPath] = (0, import_react16.useState)({});
14205
+ const sectionsPrefetchGenRef = (0, import_react16.useRef)(0);
14206
+ const setLinkPopoverRef = (0, import_react16.useRef)(setLinkPopover);
14207
+ const linkPopoverPanelRef = (0, import_react16.useRef)(null);
14208
+ const linkPopoverOpenRef = (0, import_react16.useRef)(false);
14209
+ const linkPopoverGraceUntilRef = (0, import_react16.useRef)(0);
12832
14210
  setLinkPopoverRef.current = setLinkPopover;
14211
+ setFloatingPanelRef.current = setFloatingPanel;
12833
14212
  linkPopoverSessionRef.current = linkPopover;
14213
+ floatingPanelOpenRef.current = Boolean(floatingPanel);
14214
+ (0, import_react16.useEffect)(() => {
14215
+ const syncViewport = () => {
14216
+ const next = window.innerWidth <= 480 ? "mobile" : "desktop";
14217
+ setEditorViewport((prev) => prev === next ? prev : next);
14218
+ };
14219
+ syncViewport();
14220
+ window.addEventListener("resize", syncViewport);
14221
+ return () => window.removeEventListener("resize", syncViewport);
14222
+ }, []);
12834
14223
  const {
12835
14224
  navDragRef,
12836
14225
  navDropSlots,
@@ -12866,7 +14255,7 @@ function OhhwellsBridge() {
12866
14255
  const bumpLinkPopoverGrace = () => {
12867
14256
  linkPopoverGraceUntilRef.current = Date.now() + 350;
12868
14257
  };
12869
- const runSectionsPrefetch = (0, import_react15.useCallback)((pages) => {
14258
+ const runSectionsPrefetch = (0, import_react16.useCallback)((pages) => {
12870
14259
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
12871
14260
  const gen = ++sectionsPrefetchGenRef.current;
12872
14261
  const paths = pages.map((p) => p.path);
@@ -12885,9 +14274,9 @@ function OhhwellsBridge() {
12885
14274
  );
12886
14275
  });
12887
14276
  }, [isEditMode, pathname]);
12888
- const runSectionsPrefetchRef = (0, import_react15.useRef)(runSectionsPrefetch);
14277
+ const runSectionsPrefetchRef = (0, import_react16.useRef)(runSectionsPrefetch);
12889
14278
  runSectionsPrefetchRef.current = runSectionsPrefetch;
12890
- (0, import_react15.useEffect)(() => {
14279
+ (0, import_react16.useEffect)(() => {
12891
14280
  if (!linkPopover) {
12892
14281
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
12893
14282
  return;
@@ -12915,7 +14304,7 @@ function OhhwellsBridge() {
12915
14304
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
12916
14305
  };
12917
14306
  }, [linkPopover, postToParent2]);
12918
- (0, import_react15.useEffect)(() => {
14307
+ (0, import_react16.useEffect)(() => {
12919
14308
  if (!isEditMode) return;
12920
14309
  const useFixtures = shouldUseDevFixtures();
12921
14310
  if (useFixtures) {
@@ -12939,14 +14328,14 @@ function OhhwellsBridge() {
12939
14328
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
12940
14329
  return () => window.removeEventListener("message", onSitePages);
12941
14330
  }, [isEditMode, postToParent2]);
12942
- (0, import_react15.useEffect)(() => {
14331
+ (0, import_react16.useEffect)(() => {
12943
14332
  if (!isEditMode || shouldUseDevFixtures()) return;
12944
14333
  void loadAllSectionsManifest().then((manifest) => {
12945
14334
  if (Object.keys(manifest).length === 0) return;
12946
14335
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
12947
14336
  });
12948
14337
  }, [isEditMode]);
12949
- (0, import_react15.useEffect)(() => {
14338
+ (0, import_react16.useEffect)(() => {
12950
14339
  const update = () => {
12951
14340
  const el = activeElRef.current ?? selectedElRef.current;
12952
14341
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -12970,10 +14359,10 @@ function OhhwellsBridge() {
12970
14359
  vvp.removeEventListener("resize", update);
12971
14360
  };
12972
14361
  }, []);
12973
- const refreshStateRules = (0, import_react15.useCallback)(() => {
14362
+ const refreshStateRules = (0, import_react16.useCallback)(() => {
12974
14363
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
12975
14364
  }, []);
12976
- const processConfigRequest = (0, import_react15.useCallback)((insertAfterVal) => {
14365
+ const processConfigRequest = (0, import_react16.useCallback)((insertAfterVal) => {
12977
14366
  const tracker = getSectionsTracker();
12978
14367
  let entries = [];
12979
14368
  try {
@@ -12996,7 +14385,7 @@ function OhhwellsBridge() {
12996
14385
  }
12997
14386
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
12998
14387
  }, [isEditMode]);
12999
- const deactivate = (0, import_react15.useCallback)(() => {
14388
+ const deactivate = (0, import_react16.useCallback)(() => {
13000
14389
  const el = activeElRef.current;
13001
14390
  if (!el) return;
13002
14391
  const key = el.dataset.ohwKey;
@@ -13029,17 +14418,19 @@ function OhhwellsBridge() {
13029
14418
  setToolbarShowEditLink(false);
13030
14419
  postToParent2({ type: "ow:exit-edit" });
13031
14420
  }, [postToParent2]);
13032
- const clearSelectedAttr = (0, import_react15.useCallback)(() => {
14421
+ const clearSelectedAttr = (0, import_react16.useCallback)(() => {
13033
14422
  document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
13034
14423
  el.removeAttribute("data-ohw-selected");
13035
14424
  });
13036
14425
  }, []);
13037
- const deselect = (0, import_react15.useCallback)(() => {
14426
+ const deselect = (0, import_react16.useCallback)(() => {
13038
14427
  clearSelectedAttr();
13039
14428
  selectedElRef.current = null;
13040
14429
  selectedHrefKeyRef.current = null;
13041
14430
  selectedFooterColAttrRef.current = null;
13042
14431
  setSelectedIsCta(false);
14432
+ setSelectedIsSocial(false);
14433
+ setSelectedIsSocialsRow(false);
13043
14434
  setReorderHrefKey(null);
13044
14435
  setReorderDragDisabled(false);
13045
14436
  setIsFooterFrameSelection(false);
@@ -13051,17 +14442,21 @@ function OhhwellsBridge() {
13051
14442
  setIsItemDragging(false);
13052
14443
  hoveredNavContainerRef.current = null;
13053
14444
  setHoveredNavContainerRect(null);
14445
+ hoveredItemElRef.current = null;
14446
+ setHoveredItemRect(null);
14447
+ setFloatingPanel(null);
14448
+ setLogoSizeDraft(null);
13054
14449
  if (!activeElRef.current) {
13055
14450
  setNavGroupForceOpen(null, false);
13056
14451
  setToolbarRect(null);
13057
14452
  setToolbarVariant("none");
13058
14453
  }
13059
14454
  }, [clearSelectedAttr]);
13060
- const markSelected = (0, import_react15.useCallback)((el) => {
14455
+ const markSelected = (0, import_react16.useCallback)((el) => {
13061
14456
  clearSelectedAttr();
13062
14457
  el.setAttribute("data-ohw-selected", "");
13063
14458
  }, [clearSelectedAttr]);
13064
- const resolveHrefKeyElement = (0, import_react15.useCallback)((hrefKey) => {
14459
+ const resolveHrefKeyElement = (0, import_react16.useCallback)((hrefKey) => {
13065
14460
  if (isFooterHrefKey(hrefKey)) {
13066
14461
  return document.querySelector(
13067
14462
  `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
@@ -13076,7 +14471,7 @@ function OhhwellsBridge() {
13076
14471
  `[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
13077
14472
  );
13078
14473
  }, []);
13079
- const resyncSelectedNavigationItem = (0, import_react15.useCallback)(() => {
14474
+ const resyncSelectedNavigationItem = (0, import_react16.useCallback)(() => {
13080
14475
  const hrefKey = selectedHrefKeyRef.current;
13081
14476
  if (hrefKey) {
13082
14477
  const link = resolveHrefKeyElement(hrefKey);
@@ -13114,12 +14509,14 @@ function OhhwellsBridge() {
13114
14509
  );
13115
14510
  }
13116
14511
  }, [resolveHrefKeyElement]);
13117
- const reselectNavigationItem = (0, import_react15.useCallback)((navAnchor) => {
14512
+ const reselectNavigationItem = (0, import_react16.useCallback)((navAnchor) => {
13118
14513
  selectedElRef.current = navAnchor;
13119
14514
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
13120
14515
  selectedFooterColAttrRef.current = null;
13121
14516
  markSelected(navAnchor);
13122
14517
  setSelectedIsCta(isCtaButton(navAnchor));
14518
+ setSelectedIsSocial(Boolean(getSocialItem(navAnchor)));
14519
+ setSelectedIsSocialsRow(false);
13123
14520
  const isDropdownTrigger = !isNestedNavChild(navAnchor) && (navItemHasDropdownChildren(navAnchor) || navItemOwnsDropdownPanel(navAnchor));
13124
14521
  if (isNestedNavChild(navAnchor)) {
13125
14522
  setNavGroupForceOpen(navAnchor, true);
@@ -13143,7 +14540,7 @@ function OhhwellsBridge() {
13143
14540
  setToolbarShowEditLink(false);
13144
14541
  setActiveCommands(/* @__PURE__ */ new Set());
13145
14542
  }, [markSelected]);
13146
- const commitNavigationTextEdit = (0, import_react15.useCallback)((navAnchor) => {
14543
+ const commitNavigationTextEdit = (0, import_react16.useCallback)((navAnchor) => {
13147
14544
  const el = activeElRef.current;
13148
14545
  if (!el) return;
13149
14546
  const key = el.dataset.ohwKey;
@@ -13170,7 +14567,7 @@ function OhhwellsBridge() {
13170
14567
  postToParent2({ type: "ow:exit-edit" });
13171
14568
  reselectNavigationItem(navAnchor);
13172
14569
  }, [postToParent2, reselectNavigationItem]);
13173
- const handleAddTopLevelNavItem = (0, import_react15.useCallback)(() => {
14570
+ const handleAddTopLevelNavItem = (0, import_react16.useCallback)(() => {
13174
14571
  const items = listNavbarRootItems();
13175
14572
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
13176
14573
  deselectRef.current();
@@ -13182,7 +14579,7 @@ function OhhwellsBridge() {
13182
14579
  intent: "add-nav"
13183
14580
  });
13184
14581
  }, []);
13185
- const maybeWarnNavLinkDropdownConflict = (0, import_react15.useCallback)(
14582
+ const maybeWarnNavLinkDropdownConflict = (0, import_react16.useCallback)(
13186
14583
  (anchor) => {
13187
14584
  if (!isNavbarHrefKey(anchor.getAttribute("data-ohw-href-key"))) return;
13188
14585
  if (!navDropdownsOpenOnClick()) return;
@@ -13195,7 +14592,7 @@ function OhhwellsBridge() {
13195
14592
  },
13196
14593
  [postToParent2]
13197
14594
  );
13198
- const handleNavDropdownOpenChange = (0, import_react15.useCallback)((open) => {
14595
+ const handleNavDropdownOpenChange = (0, import_react16.useCallback)((open) => {
13199
14596
  const selected = selectedElRef.current;
13200
14597
  if (!selected || !isNavigationItem2(selected)) return;
13201
14598
  setNavGroupForceOpen(selected, open);
@@ -13207,7 +14604,7 @@ function OhhwellsBridge() {
13207
14604
  }
13208
14605
  });
13209
14606
  }, []);
13210
- const handleFooterHeadingVisibleChange = (0, import_react15.useCallback)(
14607
+ const handleFooterHeadingVisibleChange = (0, import_react16.useCallback)(
13211
14608
  (visible) => {
13212
14609
  const selected = selectedElRef.current;
13213
14610
  if (!selected || !isFooterFrameSelectionRef.current) return;
@@ -13231,7 +14628,7 @@ function OhhwellsBridge() {
13231
14628
  },
13232
14629
  [postToParent2]
13233
14630
  );
13234
- const enterEditOnNewItem = (0, import_react15.useCallback)((anchor) => {
14631
+ const enterEditOnNewItem = (0, import_react16.useCallback)((anchor) => {
13235
14632
  const label = anchor.querySelector('[data-ohw-editable="text"]');
13236
14633
  if (!label) {
13237
14634
  selectRef.current(anchor);
@@ -13240,9 +14637,31 @@ function OhhwellsBridge() {
13240
14637
  setNavGroupForceOpen(anchor, true);
13241
14638
  activateRef.current(label);
13242
14639
  }, []);
13243
- const handleAddChildItem = (0, import_react15.useCallback)(() => {
14640
+ const handleAddChildItem = (0, import_react16.useCallback)(() => {
13244
14641
  const selected = selectedElRef.current;
13245
14642
  if (!selected) return;
14643
+ const socialsRow = isSocialsRow(selected) ? selected : findSocialsRow(selected);
14644
+ if (socialsRow) {
14645
+ const after = getSocialItem(selected);
14646
+ const result2 = insertSocialItem(socialsRow, after, editContentRef.current);
14647
+ if (!result2) return;
14648
+ const orderJson = JSON.stringify(result2.order);
14649
+ applySocialsDisplayToRow(socialsRow, socialsDisplayFor(socialsRow, editContentRef.current));
14650
+ editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
14651
+ postToParent2({ type: "ow:change", nodes: [{ key: SOCIALS_ORDER_KEY, text: orderJson }] });
14652
+ postToParentRef.current({
14653
+ type: "ow:social-pick",
14654
+ hrefKey: result2.hrefKey,
14655
+ iconKey: result2.iconKey,
14656
+ url: "",
14657
+ iconStyle: detectIconStyle(result2.item),
14658
+ platformId: "",
14659
+ // Lets the editor undo the insert if the dialog is dismissed: an item that was never given
14660
+ // an address should not survive a Cancel.
14661
+ isNew: true
14662
+ });
14663
+ return;
14664
+ }
13246
14665
  if (toolbarVariantRef.current === "select-frame" && isFooterFrameSelection) {
13247
14666
  if (!selected.hasAttribute("data-ohw-footer-col") && !selected.closest("[data-ohw-footer-col]")) {
13248
14667
  }
@@ -13316,7 +14735,7 @@ function OhhwellsBridge() {
13316
14735
  enterEditOnNewItem(result.anchor);
13317
14736
  });
13318
14737
  }, [enterEditOnNewItem, isFooterFrameSelection, maybeWarnNavLinkDropdownConflict, postToParent2]);
13319
- const handleAddFooterColumn = (0, import_react15.useCallback)(() => {
14738
+ const handleAddFooterColumn = (0, import_react16.useCallback)(() => {
13320
14739
  if (!canAddFooterColumn()) {
13321
14740
  postToParent2({
13322
14741
  type: "ow:toast",
@@ -13337,7 +14756,7 @@ function OhhwellsBridge() {
13337
14756
  selectRef.current(result.firstLink);
13338
14757
  });
13339
14758
  }, [postToParent2]);
13340
- const clearFooterDragVisuals = (0, import_react15.useCallback)(() => {
14759
+ const clearFooterDragVisuals = (0, import_react16.useCallback)(() => {
13341
14760
  footerDragRef.current = null;
13342
14761
  setSiblingHintRects([]);
13343
14762
  setFooterDropSlots([]);
@@ -13346,7 +14765,7 @@ function OhhwellsBridge() {
13346
14765
  setIsItemDragging(false);
13347
14766
  unlockFooterDragInteraction();
13348
14767
  }, []);
13349
- const refreshFooterDragVisuals = (0, import_react15.useCallback)((session, activeSlot, clientX, clientY) => {
14768
+ const refreshFooterDragVisuals = (0, import_react16.useCallback)((session, activeSlot, clientX, clientY) => {
13350
14769
  const dragged = session.draggedEl;
13351
14770
  setDraggedItemRect(dragged.getBoundingClientRect());
13352
14771
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -13355,6 +14774,13 @@ function OhhwellsBridge() {
13355
14774
  }
13356
14775
  session.activeSlot = activeSlot;
13357
14776
  setSiblingHintRects([]);
14777
+ if (session.kind === "social") {
14778
+ const slots2 = session.hrefKey ? buildSocialDropSlotsForKey(session.hrefKey) : [];
14779
+ setFooterDropSlots(slots2);
14780
+ const activeIdx2 = activeSlot ? slots2.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
14781
+ setActiveFooterDropIndex(activeIdx2 >= 0 ? activeIdx2 : null);
14782
+ return;
14783
+ }
13358
14784
  if (session.kind === "link") {
13359
14785
  const columns = listFooterColumns();
13360
14786
  const slots2 = [];
@@ -13371,13 +14797,13 @@ function OhhwellsBridge() {
13371
14797
  const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
13372
14798
  setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
13373
14799
  }, []);
13374
- const refreshFooterDragVisualsRef = (0, import_react15.useRef)(refreshFooterDragVisuals);
14800
+ const refreshFooterDragVisualsRef = (0, import_react16.useRef)(refreshFooterDragVisuals);
13375
14801
  refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
13376
- const commitFooterDragRef = (0, import_react15.useRef)(() => {
14802
+ const commitFooterDragRef = (0, import_react16.useRef)(() => {
13377
14803
  });
13378
- const beginFooterDragRef = (0, import_react15.useRef)(() => {
14804
+ const beginFooterDragRef = (0, import_react16.useRef)(() => {
13379
14805
  });
13380
- const beginFooterDrag = (0, import_react15.useCallback)(
14806
+ const beginFooterDrag = (0, import_react16.useCallback)(
13381
14807
  (session) => {
13382
14808
  const rect = session.draggedEl.getBoundingClientRect();
13383
14809
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -13391,13 +14817,13 @@ function OhhwellsBridge() {
13391
14817
  if (session.wasSelected && selectedElRef.current === session.draggedEl) {
13392
14818
  setToolbarRect(rect);
13393
14819
  }
13394
- const initialSlot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
14820
+ 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);
13395
14821
  refreshFooterDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
13396
14822
  },
13397
14823
  [refreshFooterDragVisuals]
13398
14824
  );
13399
14825
  beginFooterDragRef.current = beginFooterDrag;
13400
- const commitFooterDrag = (0, import_react15.useCallback)(
14826
+ const commitFooterDrag = (0, import_react16.useCallback)(
13401
14827
  (clientX, clientY) => {
13402
14828
  const session = footerDragRef.current;
13403
14829
  if (!session) {
@@ -13407,8 +14833,11 @@ function OhhwellsBridge() {
13407
14833
  const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
13408
14834
  const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
13409
14835
  let nextOrder = null;
13410
- const slot = session.activeSlot ?? (session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(x, y, session.hrefKey) : session.kind === "column" ? hitTestColumnDropSlot(x, y) : null);
13411
- if (session.kind === "link" && session.hrefKey && slot) {
14836
+ let nextSocialsOrder = null;
14837
+ 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);
14838
+ if (session.kind === "social" && session.hrefKey && slot) {
14839
+ nextSocialsOrder = planSocialMove(session.hrefKey, slot.insertIndex);
14840
+ } else if (session.kind === "link" && session.hrefKey && slot) {
13412
14841
  nextOrder = planFooterLinkMove(session.hrefKey, slot.columnIndex, slot.insertIndex);
13413
14842
  } else if (session.kind === "column" && slot) {
13414
14843
  nextOrder = planFooterColumnMove(session.sourceColumnIndex, slot.insertIndex);
@@ -13466,6 +14895,27 @@ function OhhwellsBridge() {
13466
14895
  }
13467
14896
  deselectRef.current();
13468
14897
  };
14898
+ if (nextSocialsOrder) {
14899
+ const orderJson = JSON.stringify(nextSocialsOrder);
14900
+ editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
14901
+ applySocialsOrder(nextSocialsOrder);
14902
+ postToParentRef.current({
14903
+ type: "ow:change",
14904
+ nodes: [{ key: SOCIALS_ORDER_KEY, text: orderJson }]
14905
+ });
14906
+ applySelectionAfterDrop();
14907
+ clearFooterDragVisuals();
14908
+ const reapply = nextSocialsOrder;
14909
+ requestAnimationFrame(() => {
14910
+ if (editContentRef.current[SOCIALS_ORDER_KEY] === orderJson) applySocialsOrder(reapply);
14911
+ applySelectionAfterDrop();
14912
+ requestAnimationFrame(() => {
14913
+ if (editContentRef.current[SOCIALS_ORDER_KEY] === orderJson) applySocialsOrder(reapply);
14914
+ resyncSelectedNavigationItem();
14915
+ });
14916
+ });
14917
+ return;
14918
+ }
13469
14919
  if (nextOrder) {
13470
14920
  const orderJson = JSON.stringify(nextOrder);
13471
14921
  editContentRef.current = {
@@ -13501,10 +14951,25 @@ function OhhwellsBridge() {
13501
14951
  [clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
13502
14952
  );
13503
14953
  commitFooterDragRef.current = commitFooterDrag;
13504
- const startFooterLinkDrag = (0, import_react15.useCallback)(
14954
+ const startFooterLinkDrag = (0, import_react16.useCallback)(
13505
14955
  (anchor, clientX, clientY, wasSelected) => {
13506
14956
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
13507
- if (!hrefKey || !isFooterHrefKey(hrefKey)) return false;
14957
+ if (!hrefKey) return false;
14958
+ if (getSocialItem(anchor)) {
14959
+ beginFooterDrag({
14960
+ kind: "social",
14961
+ hrefKey,
14962
+ columnEl: null,
14963
+ sourceColumnIndex: 0,
14964
+ wasSelected,
14965
+ draggedEl: anchor,
14966
+ lastClientX: clientX,
14967
+ lastClientY: clientY,
14968
+ activeSlot: null
14969
+ });
14970
+ return true;
14971
+ }
14972
+ if (!isFooterHrefKey(hrefKey)) return false;
13508
14973
  const column = findFooterColumnForLink(anchor);
13509
14974
  const columns = listFooterColumns();
13510
14975
  beginFooterDrag({
@@ -13522,7 +14987,7 @@ function OhhwellsBridge() {
13522
14987
  },
13523
14988
  [beginFooterDrag]
13524
14989
  );
13525
- const startFooterColumnDrag = (0, import_react15.useCallback)(
14990
+ const startFooterColumnDrag = (0, import_react16.useCallback)(
13526
14991
  (columnEl, clientX, clientY, wasSelected) => {
13527
14992
  const columns = listFooterColumns();
13528
14993
  const idx = columns.indexOf(columnEl);
@@ -13542,7 +15007,7 @@ function OhhwellsBridge() {
13542
15007
  },
13543
15008
  [beginFooterDrag]
13544
15009
  );
13545
- const handleItemDragStart = (0, import_react15.useCallback)(
15010
+ const handleItemDragStart = (0, import_react16.useCallback)(
13546
15011
  (e) => {
13547
15012
  const selected = selectedElRef.current;
13548
15013
  if (!selected) {
@@ -13562,7 +15027,7 @@ function OhhwellsBridge() {
13562
15027
  },
13563
15028
  [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
13564
15029
  );
13565
- const handleItemDragEnd = (0, import_react15.useCallback)(
15030
+ const handleItemDragEnd = (0, import_react16.useCallback)(
13566
15031
  (e) => {
13567
15032
  if (footerDragRef.current) {
13568
15033
  const x = e?.clientX;
@@ -13588,7 +15053,7 @@ function OhhwellsBridge() {
13588
15053
  },
13589
15054
  [commitFooterDrag, commitNavDrag, navDragRef]
13590
15055
  );
13591
- const handleItemChromePointerDown = (0, import_react15.useCallback)((e) => {
15056
+ const handleItemChromePointerDown = (0, import_react16.useCallback)((e) => {
13592
15057
  if (e.button !== 0) return;
13593
15058
  const selected = selectedElRef.current;
13594
15059
  if (!selected) return;
@@ -13619,7 +15084,7 @@ function OhhwellsBridge() {
13619
15084
  }
13620
15085
  if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
13621
15086
  }, [armNavPressFromChrome]);
13622
- const handleItemChromeClick = (0, import_react15.useCallback)((clientX, clientY) => {
15087
+ const handleItemChromeClick = (0, import_react16.useCallback)((clientX, clientY) => {
13623
15088
  if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
13624
15089
  suppressNextClickRef.current = false;
13625
15090
  return;
@@ -13632,7 +15097,7 @@ function OhhwellsBridge() {
13632
15097
  }, []);
13633
15098
  reselectNavigationItemRef.current = reselectNavigationItem;
13634
15099
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
13635
- const select = (0, import_react15.useCallback)((anchor) => {
15100
+ const select = (0, import_react16.useCallback)((anchor) => {
13636
15101
  if (!isNavigationItem2(anchor)) return;
13637
15102
  if (activeElRef.current) deactivate();
13638
15103
  aiSectionApiRef.current?.selectFromElement(anchor);
@@ -13641,6 +15106,8 @@ function OhhwellsBridge() {
13641
15106
  selectedFooterColAttrRef.current = null;
13642
15107
  markSelected(anchor);
13643
15108
  setSelectedIsCta(isCtaButton(anchor));
15109
+ setSelectedIsSocial(Boolean(getSocialItem(anchor)));
15110
+ setSelectedIsSocialsRow(false);
13644
15111
  clearHrefKeyHover(anchor);
13645
15112
  const isDropdownTrigger = !isNestedNavChild(anchor) && (navItemHasDropdownChildren(anchor) || navItemOwnsDropdownPanel(anchor));
13646
15113
  if (isNestedNavChild(anchor)) {
@@ -13670,8 +15137,10 @@ function OhhwellsBridge() {
13670
15137
  setToolbarRect(anchor.getBoundingClientRect());
13671
15138
  setToolbarShowEditLink(false);
13672
15139
  setActiveCommands(/* @__PURE__ */ new Set());
15140
+ setFloatingPanel(null);
15141
+ setLogoSizeDraft(null);
13673
15142
  }, [deactivate, markSelected]);
13674
- const selectFrame = (0, import_react15.useCallback)((el) => {
15143
+ const selectFrame = (0, import_react16.useCallback)((el) => {
13675
15144
  if (!isNavigationContainer(el)) return;
13676
15145
  if (activeElRef.current) deactivate();
13677
15146
  aiSectionApiRef.current?.selectFromElement(el);
@@ -13681,6 +15150,8 @@ function OhhwellsBridge() {
13681
15150
  selectedFooterColAttrRef.current = isFooterColumn ? el.getAttribute("data-ohw-footer-col") ?? String(listFooterColumns().indexOf(el)) : null;
13682
15151
  markSelected(el);
13683
15152
  setSelectedIsCta(false);
15153
+ setSelectedIsSocial(false);
15154
+ setSelectedIsSocialsRow(isSocialsRow(el));
13684
15155
  clearHrefKeyHover(el);
13685
15156
  setNavGroupForceOpen(null, false);
13686
15157
  hoveredNavContainerRef.current = null;
@@ -13709,22 +15180,153 @@ function OhhwellsBridge() {
13709
15180
  nodes: [{ key: ensured.headingKey, text: ensured.text }]
13710
15181
  });
13711
15182
  }
13712
- setFooterHeadingVisible(isFooterColumnHeadingVisible(el));
13713
- } else {
13714
- setFooterHeadingVisible(null);
13715
- }
13716
- setToolbarVariant("select-frame");
13717
- setToolbarRect(el.getBoundingClientRect());
13718
- setToolbarShowEditLink(false);
13719
- setActiveCommands(/* @__PURE__ */ new Set());
13720
- }, [deactivate, markSelected, postToParent2]);
13721
- const activate = (0, import_react15.useCallback)((el, options) => {
15183
+ setFooterHeadingVisible(isFooterColumnHeadingVisible(el));
15184
+ } else {
15185
+ setFooterHeadingVisible(null);
15186
+ }
15187
+ setToolbarVariant("select-frame");
15188
+ setToolbarRect(el.getBoundingClientRect());
15189
+ setToolbarShowEditLink(false);
15190
+ setActiveCommands(/* @__PURE__ */ new Set());
15191
+ setFloatingPanel(null);
15192
+ setLogoSizeDraft(null);
15193
+ }, [deactivate, markSelected, postToParent2]);
15194
+ const selectLogo = (0, import_react16.useCallback)(
15195
+ (logoEl) => {
15196
+ if (activeElRef.current) deactivate();
15197
+ selectedElRef.current = logoEl;
15198
+ selectedHrefKeyRef.current = null;
15199
+ selectedFooterColAttrRef.current = null;
15200
+ markSelected(logoEl);
15201
+ setSelectedIsCta(false);
15202
+ setSelectedIsSocial(false);
15203
+ setSelectedIsSocialsRow(false);
15204
+ setSelectedIsSocialsRow(false);
15205
+ clearHrefKeyHover(logoEl);
15206
+ hoveredNavContainerRef.current = null;
15207
+ setHoveredNavContainerRect(null);
15208
+ setHoveredItemRect(null);
15209
+ hoveredItemElRef.current = null;
15210
+ siblingHintElRef.current = null;
15211
+ setSiblingHintRect(null);
15212
+ setSiblingHintRects([]);
15213
+ setIsItemDragging(false);
15214
+ setReorderHrefKey(null);
15215
+ setReorderDragDisabled(false);
15216
+ setIsFooterFrameSelection(false);
15217
+ setToolbarVariant("logo");
15218
+ setToolbarRect(getLogoInteractionRect(logoEl));
15219
+ setToolbarShowEditLink(false);
15220
+ setActiveCommands(/* @__PURE__ */ new Set());
15221
+ },
15222
+ [deactivate, markSelected]
15223
+ );
15224
+ const openLogoSizePanel = (0, import_react16.useCallback)((logoEl) => {
15225
+ const placement = getLogoPlacement(logoEl);
15226
+ const draft = readLogoSizeState(editContentRef.current, placement);
15227
+ setLogoSizeDraft(draft);
15228
+ setParentScrollSnap(parentScrollRef.current);
15229
+ setFloatingPanel({
15230
+ key: `logo-size:${placement}`,
15231
+ title: "Logo",
15232
+ context: placement === "navbar" ? "Navbar" : "Footer",
15233
+ kind: "logo-size",
15234
+ placement
15235
+ });
15236
+ }, []);
15237
+ const openSocialsDisplayPanel = (0, import_react16.useCallback)((row) => {
15238
+ setParentScrollSnap(parentScrollRef.current);
15239
+ setFloatingPanel({
15240
+ key: "socials-display",
15241
+ title: "Style",
15242
+ context: "Socials \xB7 Footer",
15243
+ kind: "socials-display",
15244
+ row
15245
+ });
15246
+ }, []);
15247
+ const changeSocialsDisplay = (0, import_react16.useCallback)(
15248
+ (row, next) => {
15249
+ if (next.icon) {
15250
+ const missing = socialsMissingIcons(row);
15251
+ listSocialItems(row).forEach((item) => ensureIconSlot(item));
15252
+ if (missing.length) {
15253
+ postToParentRef.current({ type: "ow:social-icons-needed", items: missing });
15254
+ }
15255
+ }
15256
+ applySocialsDisplayToRow(row, next);
15257
+ requestAnimationFrame(() => {
15258
+ if (selectedElRef.current === row && row.isConnected) setToolbarRect(row.getBoundingClientRect());
15259
+ });
15260
+ const displayJson = JSON.stringify(socialsDisplayWith(row, next, editContentRef.current));
15261
+ editContentRef.current = { ...editContentRef.current, [SOCIALS_DISPLAY_KEY]: displayJson };
15262
+ postToParentRef.current({
15263
+ type: "ow:change",
15264
+ nodes: [{ key: SOCIALS_DISPLAY_KEY, text: displayJson }],
15265
+ flush: true
15266
+ });
15267
+ },
15268
+ []
15269
+ );
15270
+ const closeFloatingPanelOnly = (0, import_react16.useCallback)(() => {
15271
+ setFloatingPanel(null);
15272
+ setLogoSizeDraft(null);
15273
+ }, []);
15274
+ const closeFloatingPanelAndDeselect = (0, import_react16.useCallback)(() => {
15275
+ setFloatingPanel(null);
15276
+ setLogoSizeDraft(null);
15277
+ deselectRef.current();
15278
+ }, []);
15279
+ const persistLogoSizeDraft = (0, import_react16.useCallback)(
15280
+ (placement, draft) => {
15281
+ const desktopKey = LOGO_SIZE_DESKTOP_KEYS[placement];
15282
+ const mobileKey = LOGO_SIZE_MOBILE_KEYS[placement];
15283
+ const nodes = [
15284
+ { key: desktopKey, text: String(draft.desktopPx) }
15285
+ ];
15286
+ if (draft.mobileFollowing) {
15287
+ nodes.push({ key: mobileKey, text: "" });
15288
+ } else {
15289
+ nodes.push({ key: mobileKey, text: String(draft.mobilePx) });
15290
+ }
15291
+ editContentRef.current = {
15292
+ ...editContentRef.current,
15293
+ [desktopKey]: String(draft.desktopPx),
15294
+ [mobileKey]: draft.mobileFollowing ? "" : String(draft.mobilePx)
15295
+ };
15296
+ applyLogoSizeToPlacement(
15297
+ placement,
15298
+ draft.desktopPx,
15299
+ draft.mobileFollowing ? draft.desktopPx : draft.mobilePx,
15300
+ draft.mobileFollowing
15301
+ );
15302
+ postToParent2({ type: "ow:change", nodes });
15303
+ requestAnimationFrame(() => {
15304
+ const selected = selectedElRef.current;
15305
+ if (!selected || toolbarVariantRef.current !== "logo") return;
15306
+ const rect = getLogoInteractionRect(selected);
15307
+ setToolbarRect(rect);
15308
+ if (glowElRef.current) {
15309
+ const GAP = SELECTION_CHROME_GAP2;
15310
+ glowElRef.current.style.top = `${rect.top - GAP}px`;
15311
+ glowElRef.current.style.left = `${rect.left - GAP}px`;
15312
+ glowElRef.current.style.width = `${rect.width + GAP * 2}px`;
15313
+ glowElRef.current.style.height = `${rect.height + GAP * 2}px`;
15314
+ }
15315
+ });
15316
+ },
15317
+ [postToParent2]
15318
+ );
15319
+ const activate = (0, import_react16.useCallback)((el, options) => {
13722
15320
  if (activeElRef.current === el) return;
15321
+ if (isIconEditable(el)) return;
15322
+ if (el.hasAttribute("data-ohw-social-label")) return;
13723
15323
  clearSelectedAttr();
13724
15324
  selectedElRef.current = null;
13725
15325
  selectedHrefKeyRef.current = null;
13726
15326
  selectedFooterColAttrRef.current = null;
13727
15327
  setSelectedIsCta(false);
15328
+ setSelectedIsSocial(false);
15329
+ setSelectedIsSocialsRow(false);
13728
15330
  deactivate();
13729
15331
  if (hoveredImageRef.current) {
13730
15332
  hoveredImageRef.current = null;
@@ -13794,8 +15396,38 @@ function OhhwellsBridge() {
13794
15396
  deactivateRef.current = deactivate;
13795
15397
  selectRef.current = select;
13796
15398
  selectFrameRef.current = selectFrame;
15399
+ selectLogoRef.current = selectLogo;
15400
+ openLogoSizePanelRef.current = openLogoSizePanel;
13797
15401
  deselectRef.current = deselect;
13798
- (0, import_react15.useLayoutEffect)(() => {
15402
+ closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
15403
+ const lastSiteWideScopeRef = (0, import_react16.useRef)(null);
15404
+ (0, import_react16.useEffect)(() => {
15405
+ if (!isEditMode) {
15406
+ if (lastSiteWideScopeRef.current !== false) {
15407
+ lastSiteWideScopeRef.current = false;
15408
+ postToParent2({ type: "ow:site-wide-scope", active: false });
15409
+ }
15410
+ return;
15411
+ }
15412
+ const active = isSiteWideScopeActive({
15413
+ selected: selectedElRef.current,
15414
+ hoveredItem: hoveredItemElRef.current,
15415
+ hoveredNavContainer: hoveredNavContainerRef.current,
15416
+ active: activeElRef.current
15417
+ });
15418
+ if (lastSiteWideScopeRef.current === active) return;
15419
+ lastSiteWideScopeRef.current = active;
15420
+ postToParent2({ type: "ow:site-wide-scope", active });
15421
+ }, [
15422
+ isEditMode,
15423
+ hoveredItemRect,
15424
+ hoveredNavContainerRect,
15425
+ toolbarVariant,
15426
+ toolbarRect,
15427
+ isFooterFrameSelection,
15428
+ postToParent2
15429
+ ]);
15430
+ (0, import_react16.useLayoutEffect)(() => {
13799
15431
  if (!subdomain || isEditMode) {
13800
15432
  setFetchState("done");
13801
15433
  return;
@@ -13806,9 +15438,18 @@ function OhhwellsBridge() {
13806
15438
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
13807
15439
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
13808
15440
  }
15441
+ if (typeof content[BRAND_KIT_KEY] === "string") {
15442
+ brandKitRef.current = content[BRAND_KIT_KEY];
15443
+ applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
15444
+ }
15445
+ applyBrandChrome(content);
13809
15446
  for (const [key, val] of Object.entries(content)) {
13810
15447
  if (key === "__ohw_sections") continue;
13811
15448
  if (key === AI_SECTIONS_KEY) continue;
15449
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
15450
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
15451
+ if (key === BRAND_KIT_KEY) continue;
15452
+ if (BRAND_CHROME_KEYS.has(key)) continue;
13812
15453
  if (applyVideoSettingNode(key, val)) continue;
13813
15454
  if (applyCarouselNode(key, val)) continue;
13814
15455
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -13835,14 +15476,20 @@ function OhhwellsBridge() {
13835
15476
  }
13836
15477
  } else if (el.dataset.ohwEditable === "link") {
13837
15478
  applyLinkHref(el, val);
15479
+ } else if (el.dataset.ohwEditable === "icon") {
15480
+ applyIconMarkup(el, val);
13838
15481
  } else if (el.innerHTML !== val) {
13839
15482
  el.innerHTML = val;
13840
15483
  }
13841
15484
  });
13842
15485
  applyLinkByKey(key, val);
13843
15486
  }
15487
+ applyLogoFromContent(content);
15488
+ applyLogoSizes(content);
13844
15489
  reconcileNavbarItemsFromContent(content);
13845
15490
  reconcileFooterOrderFromContent(content);
15491
+ reconcileSocialsFromContent(content);
15492
+ applySocialsDisplayFromContent(content);
13846
15493
  enforceLinkHrefs();
13847
15494
  initSectionsFromContent(content, true);
13848
15495
  sectionsLoadedRef.current = true;
@@ -13858,7 +15505,9 @@ function OhhwellsBridge() {
13858
15505
  let cancelled = false;
13859
15506
  setFetchState("loading");
13860
15507
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
13861
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
15508
+ const initialPath = pathname;
15509
+ fetchedContentPaths.add(`${subdomain}::${initialPath}`);
15510
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
13862
15511
  if (cancelled) return;
13863
15512
  const content = data?.content ?? {};
13864
15513
  contentCache.set(subdomain, content);
@@ -13871,7 +15520,7 @@ function OhhwellsBridge() {
13871
15520
  cancelled = true;
13872
15521
  };
13873
15522
  }, [subdomain, isEditMode]);
13874
- (0, import_react15.useEffect)(() => {
15523
+ (0, import_react16.useEffect)(() => {
13875
15524
  if (!subdomain || isEditMode) return;
13876
15525
  let debounceTimer = null;
13877
15526
  let observer = null;
@@ -13881,8 +15530,16 @@ function OhhwellsBridge() {
13881
15530
  retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
13882
15531
  observer?.disconnect();
13883
15532
  try {
15533
+ applyBrandChrome(content);
15534
+ if (typeof content[BRAND_KIT_KEY] === "string") {
15535
+ applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
15536
+ }
13884
15537
  for (const [key, val] of Object.entries(content)) {
13885
15538
  if (key === "__ohw_sections") continue;
15539
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
15540
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
15541
+ if (key === BRAND_KIT_KEY) continue;
15542
+ if (BRAND_CHROME_KEYS.has(key)) continue;
13886
15543
  if (applyVideoSettingNode(key, val)) continue;
13887
15544
  if (applyCarouselNode(key, val)) continue;
13888
15545
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -13903,8 +15560,11 @@ function OhhwellsBridge() {
13903
15560
  });
13904
15561
  applyLinkByKey(key, val);
13905
15562
  }
15563
+ applyLogoFromContent(content);
13906
15564
  reconcileNavbarItemsFromContent(content);
13907
15565
  reconcileFooterOrderFromContent(content);
15566
+ reconcileSocialsFromContent(content);
15567
+ applySocialsDisplayFromContent(content);
13908
15568
  } finally {
13909
15569
  observer?.observe(document.body, { childList: true, subtree: true });
13910
15570
  }
@@ -13915,6 +15575,17 @@ function OhhwellsBridge() {
13915
15575
  debounceTimer = setTimeout(applyFromCache, 150);
13916
15576
  };
13917
15577
  applyFromCache();
15578
+ const pathCacheKey = `${subdomain}::${pathname}`;
15579
+ if (!fetchedContentPaths.has(pathCacheKey)) {
15580
+ fetchedContentPaths.add(pathCacheKey);
15581
+ const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
15582
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
15583
+ if (!data?.content) return;
15584
+ contentCache.set(subdomain, data.content);
15585
+ applyFromCache();
15586
+ }).catch(() => {
15587
+ });
15588
+ }
13918
15589
  observer = new MutationObserver(scheduleApply);
13919
15590
  observer.observe(document.body, { childList: true, subtree: true });
13920
15591
  return () => {
@@ -13922,16 +15593,16 @@ function OhhwellsBridge() {
13922
15593
  if (debounceTimer) clearTimeout(debounceTimer);
13923
15594
  };
13924
15595
  }, [subdomain, isEditMode, pathname]);
13925
- (0, import_react15.useLayoutEffect)(() => {
15596
+ (0, import_react16.useLayoutEffect)(() => {
13926
15597
  const el = document.getElementById("ohw-loader");
13927
15598
  if (!el) return;
13928
15599
  const visible = Boolean(subdomain) && fetchState !== "done";
13929
15600
  el.style.display = visible ? "flex" : "none";
13930
15601
  }, [subdomain, fetchState]);
13931
- (0, import_react15.useEffect)(() => {
15602
+ (0, import_react16.useEffect)(() => {
13932
15603
  postToParent2({ type: "ow:navigation", path: pathname });
13933
15604
  }, [pathname, postToParent2]);
13934
- (0, import_react15.useEffect)(() => {
15605
+ (0, import_react16.useEffect)(() => {
13935
15606
  if (!isEditMode) return;
13936
15607
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
13937
15608
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -13939,7 +15610,7 @@ function OhhwellsBridge() {
13939
15610
  deselectRef.current();
13940
15611
  deactivateRef.current();
13941
15612
  }, [pathname, isEditMode]);
13942
- (0, import_react15.useEffect)(() => {
15613
+ (0, import_react16.useEffect)(() => {
13943
15614
  const contentForNav = () => {
13944
15615
  if (isEditMode) return editContentRef.current;
13945
15616
  if (!subdomain) return {};
@@ -13971,6 +15642,8 @@ function OhhwellsBridge() {
13971
15642
  const content = contentForNav();
13972
15643
  reconcileNavbarItemsFromContent(content);
13973
15644
  reconcileFooterOrderFromContent(content);
15645
+ reconcileSocialsFromContent(content);
15646
+ applySocialsDisplayFromContent(content);
13974
15647
  document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
13975
15648
  if (isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) {
13976
15649
  disableNativeHrefDrag(el);
@@ -14004,31 +15677,36 @@ function OhhwellsBridge() {
14004
15677
  observer?.disconnect();
14005
15678
  };
14006
15679
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
14007
- (0, import_react15.useEffect)(() => {
15680
+ (0, import_react16.useEffect)(() => {
14008
15681
  if (!isEditMode) return;
15682
+ let lastPosted = 0;
14009
15683
  const measure = () => {
14010
15684
  const h = document.body.scrollHeight;
14011
- if (h > 50) postToParent2({ type: "ow:height", height: h });
15685
+ if (h > 50 && Math.abs(h - lastPosted) > 1) {
15686
+ lastPosted = h;
15687
+ postToParent2({ type: "ow:height", height: h });
15688
+ }
15689
+ };
15690
+ let raf = null;
15691
+ const schedule = () => {
15692
+ if (raf != null) return;
15693
+ raf = requestAnimationFrame(() => {
15694
+ raf = null;
15695
+ measure();
15696
+ });
14012
15697
  };
14013
15698
  const t1 = setTimeout(measure, 50);
14014
15699
  const t2 = setTimeout(measure, 500);
14015
- let lastWidth = window.innerWidth;
14016
- let resizeTimer = null;
14017
- const handleResize = () => {
14018
- if (window.innerWidth === lastWidth) return;
14019
- lastWidth = window.innerWidth;
14020
- if (resizeTimer) clearTimeout(resizeTimer);
14021
- resizeTimer = setTimeout(measure, 150);
14022
- };
14023
- window.addEventListener("resize", handleResize);
15700
+ const ro = new ResizeObserver(schedule);
15701
+ ro.observe(document.body);
14024
15702
  return () => {
14025
15703
  clearTimeout(t1);
14026
15704
  clearTimeout(t2);
14027
- if (resizeTimer) clearTimeout(resizeTimer);
14028
- window.removeEventListener("resize", handleResize);
15705
+ if (raf != null) cancelAnimationFrame(raf);
15706
+ ro.disconnect();
14029
15707
  };
14030
15708
  }, [pathname, isEditMode, postToParent2]);
14031
- (0, import_react15.useEffect)(() => {
15709
+ (0, import_react16.useEffect)(() => {
14032
15710
  if (!subdomainFromQuery || isEditMode) return;
14033
15711
  const handleClick = (e) => {
14034
15712
  const anchor = e.target.closest("a");
@@ -14044,7 +15722,7 @@ function OhhwellsBridge() {
14044
15722
  document.addEventListener("click", handleClick, true);
14045
15723
  return () => document.removeEventListener("click", handleClick, true);
14046
15724
  }, [subdomainFromQuery, isEditMode, router]);
14047
- (0, import_react15.useEffect)(() => {
15725
+ (0, import_react16.useEffect)(() => {
14048
15726
  if (!isEditMode) {
14049
15727
  editStylesRef.current?.base.remove();
14050
15728
  editStylesRef.current?.forceHover.remove();
@@ -14173,6 +15851,7 @@ function OhhwellsBridge() {
14173
15851
  if (target.closest("[data-ohw-state-toggle]")) return;
14174
15852
  if (target.closest("[data-ohw-max-badge]")) return;
14175
15853
  if (isInsideLinkEditor(target)) return;
15854
+ if (isInsideFloatingPanel(target)) return;
14176
15855
  if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
14177
15856
  const beneath = document.elementsFromPoint(e.clientX, e.clientY).find(
14178
15857
  (el) => el instanceof HTMLElement && !el.closest("[data-ohw-bridge-root]") && el.closest("[data-ohw-section]") != null
@@ -14236,6 +15915,21 @@ function OhhwellsBridge() {
14236
15915
  return;
14237
15916
  }
14238
15917
  }
15918
+ const logoEl = getLogoElement(target);
15919
+ if (logoEl) {
15920
+ e.preventDefault();
15921
+ e.stopPropagation();
15922
+ if (!logoHasUploadedImage(logoEl)) {
15923
+ deselectRef.current();
15924
+ deactivateRef.current();
15925
+ const identity = readLogoIdentityFromDom();
15926
+ postToParentRef.current({ type: "ow:open-logo-settings", ...identity });
15927
+ return;
15928
+ }
15929
+ selectLogoRef.current(logoEl);
15930
+ openLogoSizePanelRef.current(logoEl);
15931
+ return;
15932
+ }
14239
15933
  const editable = target.closest("[data-ohw-editable]");
14240
15934
  if (editable) {
14241
15935
  if (editable.dataset.ohwEditable === "link") {
@@ -14252,6 +15946,17 @@ function OhhwellsBridge() {
14252
15946
  });
14253
15947
  return;
14254
15948
  }
15949
+ if (isIconEditable(editable) && !getSocialItem(editable)) {
15950
+ e.preventDefault();
15951
+ e.stopPropagation();
15952
+ aiSectionApiRef.current?.selectFromElement(editable);
15953
+ postToParentRef.current({
15954
+ type: "ow:icon-pick",
15955
+ key: editable.dataset.ohwKey ?? "",
15956
+ current: currentIconRef(editable)
15957
+ });
15958
+ return;
15959
+ }
14255
15960
  if (isMediaEditable(editable)) {
14256
15961
  e.preventDefault();
14257
15962
  e.stopPropagation();
@@ -14266,6 +15971,7 @@ function OhhwellsBridge() {
14266
15971
  e.stopPropagation();
14267
15972
  if (selectedElRef.current === navAnchor) {
14268
15973
  if (e.detail >= 2) return;
15974
+ if (requestSocialDialog(navAnchor, postToParentRef.current, editContentRef.current)) return;
14269
15975
  activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
14270
15976
  return;
14271
15977
  }
@@ -14282,6 +15988,7 @@ function OhhwellsBridge() {
14282
15988
  e.preventDefault();
14283
15989
  e.stopPropagation();
14284
15990
  if (selectedElRef.current === hrefAnchor) {
15991
+ if (requestSocialDialog(hrefAnchor, postToParentRef.current, editContentRef.current)) return;
14285
15992
  const textEditable = hrefAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefAnchor.querySelector("[data-ohw-editable]");
14286
15993
  if (textEditable) {
14287
15994
  activateRef.current(textEditable, {
@@ -14320,6 +16027,13 @@ function OhhwellsBridge() {
14320
16027
  selectFrameRef.current(navContainerToSelect);
14321
16028
  return;
14322
16029
  }
16030
+ const socialsRowToSelect = isSocialsRow(target) ? target : null;
16031
+ if (socialsRowToSelect && !getSocialItem(target)) {
16032
+ e.preventDefault();
16033
+ e.stopPropagation();
16034
+ selectFrameRef.current(socialsRowToSelect);
16035
+ return;
16036
+ }
14323
16037
  const footerColumnToSelect = resolveFooterColumnSelectionTarget(target, e.clientX, e.clientY);
14324
16038
  if (footerColumnToSelect) {
14325
16039
  e.preventDefault();
@@ -14368,9 +16082,11 @@ function OhhwellsBridge() {
14368
16082
  if (target.closest("[data-ohw-state-toggle]")) return;
14369
16083
  if (target.closest("[data-ohw-max-badge]")) return;
14370
16084
  if (isInsideLinkEditor(target)) return;
16085
+ if (isInsideFloatingPanel(target)) return;
14371
16086
  if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
14372
16087
  return;
14373
16088
  }
16089
+ if (getSocialItem(target)) return;
14374
16090
  const navLabel = getNavigationLabelEditable(target);
14375
16091
  const editable = navLabel?.editable ?? target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
14376
16092
  if (!editable || isMediaEditable(editable) || editable.dataset.ohwEditable === "link") return;
@@ -14394,6 +16110,16 @@ function OhhwellsBridge() {
14394
16110
  setHoveredNavContainerRect(null);
14395
16111
  return;
14396
16112
  }
16113
+ if (isInsideFloatingPanel(target) || isPointOverFloatingPanel(e.clientX, e.clientY)) {
16114
+ hoveredItemElRef.current = null;
16115
+ setHoveredItemRect(null);
16116
+ hoveredNavContainerRef.current = null;
16117
+ setHoveredNavContainerRect(null);
16118
+ siblingHintElRef.current = null;
16119
+ setSiblingHintRect(null);
16120
+ setSiblingHintRects([]);
16121
+ return;
16122
+ }
14397
16123
  {
14398
16124
  const selected2 = selectedElRef.current;
14399
16125
  const selectedIsFooterColumn = Boolean(selected2) && !isFooterLinksContainer(selected2) && (selected2.hasAttribute("data-ohw-footer-col") || selected2.hasAttribute("data-ohw-footer-column") || Boolean(selected2.closest("footer") && isInferredFooterGroup2(selected2)));
@@ -14401,7 +16127,7 @@ function OhhwellsBridge() {
14401
16127
  const allowFooterLinksHover = toolbarVariantRef.current !== "select-frame" || selectedIsFooterColumn;
14402
16128
  if (allowNavContainerHover) {
14403
16129
  const navContainer = target.closest("[data-ohw-nav-container]");
14404
- if (navContainer && !getNavigationItemAnchor(target)) {
16130
+ if (navContainer && !getNavigationItemAnchor(target) && !getLogoElement(target)) {
14405
16131
  hoveredNavContainerRef.current = navContainer;
14406
16132
  setHoveredNavContainerRect(navContainer.getBoundingClientRect());
14407
16133
  hoveredItemElRef.current = null;
@@ -14430,6 +16156,15 @@ function OhhwellsBridge() {
14430
16156
  setHoveredNavContainerRect(null);
14431
16157
  }
14432
16158
  }
16159
+ const logoEl = getLogoElement(target);
16160
+ if (logoEl) {
16161
+ hoveredNavContainerRef.current = null;
16162
+ setHoveredNavContainerRect(null);
16163
+ if (selectedElRef.current === logoEl) return;
16164
+ hoveredItemElRef.current = logoEl;
16165
+ setHoveredItemRect(getLogoInteractionRect(logoEl));
16166
+ return;
16167
+ }
14433
16168
  const navAnchor = getNavigationItemAnchor(target);
14434
16169
  if (navAnchor) {
14435
16170
  hoveredNavContainerRef.current = null;
@@ -14455,6 +16190,11 @@ function OhhwellsBridge() {
14455
16190
  const selected = selectedElRef.current;
14456
16191
  if (selected && (selected === editable || selected.contains(editable))) return;
14457
16192
  if (!isMediaEditable(editable) && !editable.hasAttribute("contenteditable")) {
16193
+ if (isIconEditable(editable) && !getSocialItem(editable)) {
16194
+ hoveredItemElRef.current = editable;
16195
+ setHoveredItemRect(editable.getBoundingClientRect());
16196
+ return;
16197
+ }
14458
16198
  const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
14459
16199
  if (hoverTarget.hasAttribute("data-ohw-href-key")) {
14460
16200
  clearHrefKeyHover(hoverTarget);
@@ -14462,6 +16202,12 @@ function OhhwellsBridge() {
14462
16202
  setHoveredItemRect(hoverTarget.getBoundingClientRect());
14463
16203
  } else if (!isInsideNavigationItem(editable)) {
14464
16204
  hoverTarget.setAttribute("data-ohw-hovered", "");
16205
+ if (editable.closest("footer") || editable.closest('[data-ohw-section="footer"]')) {
16206
+ hoveredNavContainerRef.current = null;
16207
+ setHoveredNavContainerRect(null);
16208
+ hoveredItemElRef.current = editable;
16209
+ setHoveredItemRect(editable.getBoundingClientRect());
16210
+ }
14465
16211
  }
14466
16212
  }
14467
16213
  };
@@ -14497,11 +16243,30 @@ function OhhwellsBridge() {
14497
16243
  }
14498
16244
  return;
14499
16245
  }
16246
+ const logoEl = getLogoElement(target);
16247
+ if (logoEl) {
16248
+ const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
16249
+ if (related2 && (logoEl === related2 || logoEl.contains(related2) || related2.closest?.('[data-ohw-role="logo"], [data-ohw-logo]'))) {
16250
+ return;
16251
+ }
16252
+ if (hoveredItemElRef.current === logoEl) {
16253
+ hoveredItemElRef.current = null;
16254
+ setHoveredItemRect(null);
16255
+ }
16256
+ return;
16257
+ }
14500
16258
  const editable = target.closest("[data-ohw-editable]");
14501
16259
  if (!editable) return;
14502
16260
  const related = e.relatedTarget instanceof Element ? e.relatedTarget : null;
14503
16261
  if (related?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
14504
16262
  if (!isMediaEditable(editable)) {
16263
+ if (isIconEditable(editable) && !getSocialItem(editable) && hoveredItemElRef.current === editable) {
16264
+ if (!related?.closest("[data-ohw-item-interaction]")) {
16265
+ hoveredItemElRef.current = null;
16266
+ setHoveredItemRect(null);
16267
+ }
16268
+ return;
16269
+ }
14505
16270
  const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
14506
16271
  if (hoverTarget.hasAttribute("data-ohw-href-key")) {
14507
16272
  if (!related?.closest("[data-ohw-href-key]")) {
@@ -14510,6 +16275,13 @@ function OhhwellsBridge() {
14510
16275
  }
14511
16276
  } else {
14512
16277
  hoverTarget.removeAttribute("data-ohw-hovered");
16278
+ if (hoveredItemElRef.current === editable) {
16279
+ const stillOnEditable = related instanceof Element && related.closest("[data-ohw-editable]") === editable;
16280
+ if (!stillOnEditable) {
16281
+ hoveredItemElRef.current = null;
16282
+ setHoveredItemRect(null);
16283
+ }
16284
+ }
14513
16285
  }
14514
16286
  }
14515
16287
  };
@@ -14626,6 +16398,26 @@ function OhhwellsBridge() {
14626
16398
  hoveredNavContainerRef.current = null;
14627
16399
  setHoveredNavContainerRect(null);
14628
16400
  }
16401
+ const logoCandidates = [
16402
+ ...document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]'),
16403
+ ...document.querySelectorAll("nav a:not([data-ohw-href-key]), [data-ohw-nav-root] a:not([data-ohw-href-key])"),
16404
+ ...document.querySelectorAll("footer img")
16405
+ ];
16406
+ const seenLogos = /* @__PURE__ */ new Set();
16407
+ for (const candidate of logoCandidates) {
16408
+ const logo = getLogoElement(candidate);
16409
+ if (!logo || seenLogos.has(logo)) continue;
16410
+ seenLogos.add(logo);
16411
+ const r2 = logo.getBoundingClientRect();
16412
+ if (x < r2.left || x > r2.right || y < r2.top || y > r2.bottom) continue;
16413
+ hoveredNavContainerRef.current = null;
16414
+ setHoveredNavContainerRect(null);
16415
+ if (selectedElRef.current !== logo) {
16416
+ hoveredItemElRef.current = logo;
16417
+ setHoveredItemRect(getLogoInteractionRect(logo));
16418
+ }
16419
+ return;
16420
+ }
14629
16421
  const navContainers = Array.from(
14630
16422
  document.querySelectorAll("[data-ohw-nav-container]")
14631
16423
  );
@@ -14711,7 +16503,7 @@ function OhhwellsBridge() {
14711
16503
  }
14712
16504
  };
14713
16505
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
14714
- if (linkPopoverOpenRef.current) {
16506
+ if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
14715
16507
  if (hoveredImageRef.current) {
14716
16508
  hoveredImageRef.current = null;
14717
16509
  hoveredImageHasTextOverlapRef.current = false;
@@ -14965,7 +16757,7 @@ function OhhwellsBridge() {
14965
16757
  }
14966
16758
  };
14967
16759
  const probeHoverCardsAt = (clientX, clientY, fromParentViewport = false) => {
14968
- if (linkPopoverOpenRef.current || document.documentElement.hasAttribute("data-ohw-section-picking")) {
16760
+ if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || document.documentElement.hasAttribute("data-ohw-section-picking")) {
14969
16761
  if (activeStateElRef.current) {
14970
16762
  activeStateElRef.current.removeAttribute("data-ohw-state-hovered");
14971
16763
  activeStateElRef.current = null;
@@ -15033,6 +16825,19 @@ function OhhwellsBridge() {
15033
16825
  };
15034
16826
  const handleMouseMove = (e) => {
15035
16827
  const { clientX, clientY } = e;
16828
+ if (floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
16829
+ hoveredItemElRef.current = null;
16830
+ setHoveredItemRect(null);
16831
+ hoveredNavContainerRef.current = null;
16832
+ setHoveredNavContainerRect(null);
16833
+ siblingHintElRef.current = null;
16834
+ setSiblingHintRect(null);
16835
+ setSiblingHintRects([]);
16836
+ dismissImageHover();
16837
+ clearImageHover();
16838
+ setSectionGap(null);
16839
+ return;
16840
+ }
15036
16841
  probeSectionGapAt(clientX, clientY);
15037
16842
  probeImageAt(clientX, clientY);
15038
16843
  probeHoverCardsAt(clientX, clientY);
@@ -15041,6 +16846,11 @@ function OhhwellsBridge() {
15041
16846
  if (e.data?.type !== "ow:pointer-sync") return;
15042
16847
  const { clientX, clientY } = e.data;
15043
16848
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
16849
+ if (floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
16850
+ dismissImageHover();
16851
+ clearImageHover();
16852
+ return;
16853
+ }
15044
16854
  probeSectionGapAt(clientX, clientY);
15045
16855
  probeImageAt(clientX, clientY);
15046
16856
  probeHoverCardsAt(clientX, clientY);
@@ -15050,7 +16860,7 @@ function OhhwellsBridge() {
15050
16860
  if (footerSession) {
15051
16861
  e.preventDefault();
15052
16862
  if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
15053
- const slot = footerSession.kind === "link" && footerSession.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, footerSession.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
16863
+ 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);
15054
16864
  refreshFooterDragVisualsRef.current(footerSession, slot, e.clientX, e.clientY);
15055
16865
  return;
15056
16866
  }
@@ -15102,6 +16912,62 @@ function OhhwellsBridge() {
15102
16912
  resumeAnimTracks();
15103
16913
  clearImageHover();
15104
16914
  };
16915
+ const handleSocialCancel = (e) => {
16916
+ if (e.data?.type !== "ow:social-cancel") return;
16917
+ const { hrefKey } = e.data;
16918
+ const item = hrefKey ? findSocialByHrefKey(hrefKey) : null;
16919
+ if (!item) return;
16920
+ const removed = removeSocialItem(item, editContentRef.current);
16921
+ if (!removed) return;
16922
+ const orderJson = JSON.stringify(removed.order);
16923
+ editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
16924
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: SOCIALS_ORDER_KEY, text: orderJson }] });
16925
+ deselectRef.current();
16926
+ };
16927
+ const handleSocialUpdate = (e) => {
16928
+ if (e.data?.type !== "ow:social-update") return;
16929
+ const updates = Array.isArray(e.data.items) ? e.data.items : [e.data];
16930
+ const nodes = [];
16931
+ for (const { hrefKey, iconKey, url, iconMarkup, platformId, label } of updates) {
16932
+ if (hrefKey) {
16933
+ document.querySelectorAll(`[data-ohw-href-key="${hrefKey}"]`).forEach((el) => applyLinkHref(el, url));
16934
+ nodes.push({ key: hrefKey, text: url });
16935
+ }
16936
+ if (iconKey && typeof iconMarkup === "string" && iconMarkup) {
16937
+ document.querySelectorAll(`[data-ohw-key="${iconKey}"][data-ohw-editable="icon"]`).forEach((el) => {
16938
+ applyIconMarkup(el, iconMarkup);
16939
+ });
16940
+ nodes.push({ key: iconKey, text: iconMarkup });
16941
+ }
16942
+ if (iconKey && platformId) nodes.push({ key: socialPlatformKey(iconKey), text: platformId });
16943
+ if (iconKey && label) {
16944
+ const labelKey = socialLabelKey(iconKey);
16945
+ document.querySelectorAll(`[data-ohw-key="${labelKey}"]`).forEach((el) => {
16946
+ el.textContent = label;
16947
+ });
16948
+ nodes.push({ key: labelKey, text: label });
16949
+ }
16950
+ }
16951
+ if (!nodes.length) return;
16952
+ editContentRef.current = {
16953
+ ...editContentRef.current,
16954
+ ...Object.fromEntries(nodes.map((node) => [node.key, node.text]))
16955
+ };
16956
+ postToParentRef.current({ type: "ow:change", nodes, flush: true });
16957
+ };
16958
+ const handleIconMarkup = (e) => {
16959
+ if (e.data?.type !== "ow:icon-markup") return;
16960
+ const { key, markup } = e.data;
16961
+ if (!key || typeof markup !== "string") return;
16962
+ const targets = document.querySelectorAll(
16963
+ `[data-ohw-key="${key}"][data-ohw-editable="icon"]`
16964
+ );
16965
+ if (!targets.length) return;
16966
+ targets.forEach((el) => {
16967
+ applyIconMarkup(el, markup);
16968
+ });
16969
+ postToParentRef.current({ type: "ow:change", nodes: [{ key, text: markup }], flush: true });
16970
+ };
15105
16971
  const handleImageUrl = (e) => {
15106
16972
  if (e.data?.type !== "ow:image-url") return;
15107
16973
  const { key, url } = e.data;
@@ -15234,6 +17100,11 @@ function OhhwellsBridge() {
15234
17100
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
15235
17101
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
15236
17102
  }
17103
+ if (typeof content[BRAND_KIT_KEY] === "string") {
17104
+ brandKitRef.current = content[BRAND_KIT_KEY];
17105
+ applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17106
+ }
17107
+ applyBrandChrome(content);
15237
17108
  let sectionsJson = null;
15238
17109
  for (const [key, val] of Object.entries(content)) {
15239
17110
  if (key === "__ohw_sections") {
@@ -15241,6 +17112,10 @@ function OhhwellsBridge() {
15241
17112
  continue;
15242
17113
  }
15243
17114
  if (key === AI_SECTIONS_KEY) continue;
17115
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
17116
+ if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
17117
+ if (key === BRAND_KIT_KEY) continue;
17118
+ if (BRAND_CHROME_KEYS.has(key)) continue;
15244
17119
  if (applyVideoSettingNode(key, val)) continue;
15245
17120
  if (applyCarouselNode(key, val)) continue;
15246
17121
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -15260,6 +17135,8 @@ function OhhwellsBridge() {
15260
17135
  });
15261
17136
  applyLinkByKey(key, val);
15262
17137
  }
17138
+ applyLogoFromContent(content);
17139
+ applyLogoSizes(content);
15263
17140
  if (sectionsJson) {
15264
17141
  initSectionsFromContent({ __ohw_sections: sectionsJson }, true);
15265
17142
  sectionsLoadedRef.current = true;
@@ -15274,6 +17151,58 @@ function OhhwellsBridge() {
15274
17151
  if (hydratedHeight > 50) postToParentRef.current({ type: "ow:height", height: hydratedHeight });
15275
17152
  postToParentRef.current({ type: "ow:hydrate-done" });
15276
17153
  };
17154
+ const handleUpdateLogoIdentity = (e) => {
17155
+ if (e.data?.type !== "ow:update-logo-identity") return;
17156
+ const rawText = typeof e.data.text === "string" ? e.data.text : "";
17157
+ const alt = typeof e.data.alt === "string" ? e.data.alt : rawText;
17158
+ const href = typeof e.data.href === "string" ? e.data.href : void 0;
17159
+ const imageProvided = "image" in e.data;
17160
+ const imageUrl = imageProvided && typeof e.data.image === "string" && e.data.image.trim() ? e.data.image.trim() : imageProvided ? null : void 0;
17161
+ let isPlaceholder = e.data.isPlaceholder !== false;
17162
+ if (imageUrl) isPlaceholder = false;
17163
+ else if (imageProvided && imageUrl === null) {
17164
+ isPlaceholder = e.data.isPlaceholder === true || !rawText.trim() || resolveLogoDisplayText(rawText) === PLACEHOLDER_BUSINESS_NAME;
17165
+ }
17166
+ const display = applyLogoIdentity(rawText, isPlaceholder);
17167
+ const displayAlt = resolveLogoDisplayText(alt || display);
17168
+ if (imageUrl !== void 0) {
17169
+ applyLogoImage(imageUrl, displayAlt);
17170
+ } else {
17171
+ for (const key of LOGO_IMAGE_KEYS) {
17172
+ document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
17173
+ const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
17174
+ if (img) img.alt = displayAlt;
17175
+ });
17176
+ }
17177
+ }
17178
+ if (href !== void 0) {
17179
+ applyLogoHref(href);
17180
+ applyLinkByKey("nav-logo-href", href);
17181
+ applyLinkByKey("footer-logo-href", href);
17182
+ applyLinkByKey("logo-href", href);
17183
+ }
17184
+ const nodes = [
17185
+ ...LOGO_TEXT_KEYS.map((key) => ({ key, text: display })),
17186
+ { key: LOGO_PLACEHOLDER_KEY, text: isPlaceholder ? "true" : "false" },
17187
+ { key: LOGO_ALT_KEY, text: displayAlt }
17188
+ ];
17189
+ if (imageUrl !== void 0) {
17190
+ if (imageUrl) {
17191
+ for (const key of LOGO_IMAGE_KEYS) nodes.push({ key, text: imageUrl });
17192
+ } else {
17193
+ for (const key of LOGO_IMAGE_KEYS) nodes.push({ key, text: "" });
17194
+ }
17195
+ }
17196
+ if (href !== void 0) {
17197
+ for (const key of LOGO_HREF_KEYS) nodes.push({ key, text: href.trim() || "/" });
17198
+ }
17199
+ editContentRef.current = {
17200
+ ...editContentRef.current,
17201
+ ...Object.fromEntries(nodes.map(({ key, text }) => [key, text]))
17202
+ };
17203
+ applyLogoSizes(editContentRef.current);
17204
+ postToParentRef.current({ type: "ow:change", nodes });
17205
+ };
15277
17206
  window.addEventListener("message", handleHydrate);
15278
17207
  const postAiSectionsChanged = () => {
15279
17208
  postToParentRef.current({
@@ -15330,6 +17259,17 @@ function OhhwellsBridge() {
15330
17259
  postAiSectionsChanged();
15331
17260
  };
15332
17261
  window.addEventListener("message", handleAiSetSections);
17262
+ const handleAiSetBrand = (e) => {
17263
+ if (e.data?.type !== "ow:ai-set-brand") return;
17264
+ const value = typeof e.data.value === "string" ? e.data.value : "";
17265
+ const previous = brandKitRef.current;
17266
+ brandKitRef.current = value;
17267
+ applyBrandToDom(parseBrandKit(value));
17268
+ if (aiSectionsRef.current) applyAiSectionsToDom(parseAiSectionsState(aiSectionsRef.current));
17269
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: BRAND_KIT_KEY, text: value }] });
17270
+ postToParentRef.current({ type: "ow:ai-brand-applied", previous, value });
17271
+ };
17272
+ window.addEventListener("message", handleAiSetBrand);
15333
17273
  const handleDeactivate = (e) => {
15334
17274
  if (e.data?.type !== "ow:deactivate") return;
15335
17275
  if (Date.now() < linkPopoverGraceUntilRef.current) return;
@@ -15338,6 +17278,12 @@ function OhhwellsBridge() {
15338
17278
  closeLinkPopoverRef.current();
15339
17279
  return;
15340
17280
  }
17281
+ if (floatingPanelOpenRef.current) {
17282
+ setFloatingPanelRef.current(null);
17283
+ deselectRef.current();
17284
+ deactivateRef.current();
17285
+ return;
17286
+ }
15341
17287
  deselectRef.current();
15342
17288
  deactivateRef.current();
15343
17289
  };
@@ -15357,6 +17303,10 @@ function OhhwellsBridge() {
15357
17303
  closeLinkPopoverRef.current();
15358
17304
  return;
15359
17305
  }
17306
+ if (floatingPanelOpenRef.current) {
17307
+ closeFloatingPanelOnlyRef.current();
17308
+ return;
17309
+ }
15360
17310
  if (activeElRef.current) {
15361
17311
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
15362
17312
  const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
@@ -15387,6 +17337,10 @@ function OhhwellsBridge() {
15387
17337
  return;
15388
17338
  }
15389
17339
  if (selectedElRef.current) {
17340
+ if (toolbarVariantRef.current === "logo") {
17341
+ deselectRef.current();
17342
+ return;
17343
+ }
15390
17344
  if (toolbarVariantRef.current === "select-frame") {
15391
17345
  const parent2 = getNavigationSelectionParent(selectedElRef.current);
15392
17346
  if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
@@ -15420,7 +17374,16 @@ function OhhwellsBridge() {
15420
17374
  closeLinkPopoverRef.current();
15421
17375
  return;
15422
17376
  }
17377
+ if (e.key === "Escape" && floatingPanelOpenRef.current) {
17378
+ e.preventDefault();
17379
+ closeFloatingPanelOnlyRef.current();
17380
+ return;
17381
+ }
15423
17382
  if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
17383
+ if (toolbarVariantRef.current === "logo") {
17384
+ deselectRef.current();
17385
+ return;
17386
+ }
15424
17387
  if (toolbarVariantRef.current === "select-frame") {
15425
17388
  const parent2 = getNavigationSelectionParent(selectedElRef.current);
15426
17389
  if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
@@ -15498,7 +17461,8 @@ function OhhwellsBridge() {
15498
17461
  const handleScroll = () => {
15499
17462
  const focusEl = activeElRef.current ?? selectedElRef.current;
15500
17463
  if (focusEl) {
15501
- const r2 = activeElRef.current ? getEditMeasureEl(activeElRef.current).getBoundingClientRect() : focusEl.getBoundingClientRect();
17464
+ const measureEl = activeElRef.current ? getEditMeasureEl(activeElRef.current) : toolbarVariantRef.current === "logo" ? null : focusEl;
17465
+ const r2 = measureEl ? measureEl.getBoundingClientRect() : toolbarVariantRef.current === "logo" ? getLogoInteractionRect(focusEl) : focusEl.getBoundingClientRect();
15502
17466
  applyToolbarPos(r2);
15503
17467
  setToolbarRect(r2);
15504
17468
  setMaxBadge((prev) => prev && activeElRef.current ? { ...prev, rect: r2 } : prev);
@@ -15508,7 +17472,9 @@ function OhhwellsBridge() {
15508
17472
  setToggleState((prev) => prev ? { ...prev, rect } : null);
15509
17473
  }
15510
17474
  if (hoveredItemElRef.current) {
15511
- setHoveredItemRect(hoveredItemElRef.current.getBoundingClientRect());
17475
+ const hoverEl = hoveredItemElRef.current;
17476
+ const logo = getLogoElement(hoverEl);
17477
+ setHoveredItemRect(logo ? getLogoInteractionRect(logo) : hoverEl.getBoundingClientRect());
15512
17478
  }
15513
17479
  if (hoveredNavContainerRef.current) {
15514
17480
  setHoveredNavContainerRect(hoveredNavContainerRef.current.getBoundingClientRect());
@@ -15528,7 +17494,7 @@ function OhhwellsBridge() {
15528
17494
  }
15529
17495
  if (footerDragRef.current) {
15530
17496
  const session = footerDragRef.current;
15531
- const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
17497
+ 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);
15532
17498
  refreshFooterDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
15533
17499
  }
15534
17500
  if (navDragRef.current) {
@@ -15552,6 +17518,9 @@ function OhhwellsBridge() {
15552
17518
  if (aiSectionsRef.current) {
15553
17519
  nodes.push({ key: AI_SECTIONS_KEY, type: "sections", text: aiSectionsRef.current });
15554
17520
  }
17521
+ if (brandKitRef.current) {
17522
+ nodes.push({ key: BRAND_KIT_KEY, type: "brand", text: brandKitRef.current });
17523
+ }
15555
17524
  postToParentRef.current({ type: "ow:save-result", nodes });
15556
17525
  };
15557
17526
  const handleInsertSection = (e) => {
@@ -15562,8 +17531,12 @@ function OhhwellsBridge() {
15562
17531
  if (inserted) {
15563
17532
  const tracker = getSectionsTracker();
15564
17533
  postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
15565
- const h = document.documentElement.scrollHeight;
15566
- if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
17534
+ const reportHeight = () => {
17535
+ const h = document.body.scrollHeight;
17536
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
17537
+ };
17538
+ reportHeight();
17539
+ setTimeout(reportHeight, 500);
15567
17540
  }
15568
17541
  };
15569
17542
  const handleSwitchSchedule = (e) => {
@@ -15756,13 +17729,17 @@ function OhhwellsBridge() {
15756
17729
  if (e.data?.type !== "ow:parent-scroll") return;
15757
17730
  const { iframeOffsetTop, headerH, canvasH } = e.data;
15758
17731
  parentScrollRef.current = { iframeOffsetTop, headerH, canvasH };
17732
+ if (floatingPanelOpenRef.current) {
17733
+ setParentScrollSnap({ iframeOffsetTop, headerH, canvasH });
17734
+ }
15759
17735
  if (visibleViewportRef.current) {
15760
17736
  applyVisibleViewport(visibleViewportRef.current, parentScrollRef.current);
15761
17737
  }
15762
17738
  const focusEl = activeElRef.current ?? selectedElRef.current;
15763
17739
  if (focusEl) {
15764
- const measureEl = activeElRef.current ? getEditMeasureEl(activeElRef.current) : focusEl;
15765
- applyToolbarPos(measureEl.getBoundingClientRect());
17740
+ const measureEl = activeElRef.current ? getEditMeasureEl(activeElRef.current) : toolbarVariantRef.current === "logo" ? null : focusEl;
17741
+ const r2 = measureEl ? measureEl.getBoundingClientRect() : toolbarVariantRef.current === "logo" ? getLogoInteractionRect(focusEl) : focusEl.getBoundingClientRect();
17742
+ applyToolbarPos(r2);
15766
17743
  }
15767
17744
  };
15768
17745
  const handleClickAt = (e) => {
@@ -15787,6 +17764,25 @@ function OhhwellsBridge() {
15787
17764
  postToParentRef.current({ type: "ow:image-pick", key: stateCardImage.dataset.ohwKey ?? "", elementType: stateCardImage.dataset.ohwEditable ?? "image" });
15788
17765
  return;
15789
17766
  }
17767
+ const logoAtPoint = Array.from(
17768
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]')
17769
+ ).map((el) => getLogoElement(el)).find((logo) => {
17770
+ if (!logo) return false;
17771
+ const r2 = logo.getBoundingClientRect();
17772
+ return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
17773
+ });
17774
+ if (logoAtPoint) {
17775
+ if (!logoHasUploadedImage(logoAtPoint)) {
17776
+ deselectRef.current();
17777
+ deactivateRef.current();
17778
+ const identity = readLogoIdentityFromDom();
17779
+ postToParentRef.current({ type: "ow:open-logo-settings", ...identity });
17780
+ return;
17781
+ }
17782
+ selectLogoRef.current(logoAtPoint);
17783
+ openLogoSizePanelRef.current(logoAtPoint);
17784
+ return;
17785
+ }
15790
17786
  const textEditable = Array.from(
15791
17787
  document.querySelectorAll(NON_MEDIA_SELECTOR)
15792
17788
  ).find((el) => {
@@ -15848,6 +17844,9 @@ function OhhwellsBridge() {
15848
17844
  window.addEventListener("message", handleClearSchedulingWidget);
15849
17845
  window.addEventListener("message", handleRemoveSchedulingSection);
15850
17846
  window.addEventListener("message", handleCollectSection);
17847
+ window.addEventListener("message", handleSocialCancel);
17848
+ window.addEventListener("message", handleSocialUpdate);
17849
+ window.addEventListener("message", handleIconMarkup);
15851
17850
  window.addEventListener("message", handleImageUrl);
15852
17851
  window.addEventListener("message", handleImageUploading);
15853
17852
  window.addEventListener("message", handleCarouselChange);
@@ -15855,6 +17854,14 @@ function OhhwellsBridge() {
15855
17854
  window.addEventListener("message", handleParentScroll);
15856
17855
  window.addEventListener("message", handlePointerSync);
15857
17856
  window.addEventListener("message", handleClickAt);
17857
+ window.addEventListener("message", handleUpdateLogoIdentity);
17858
+ const handleViewMode = (e) => {
17859
+ if (e.data?.type !== "ow:view-mode") return;
17860
+ const mode = e.data.mode === "Mobile" || e.data.mode === "mobile" ? "mobile" : "desktop";
17861
+ setEditorViewport(mode);
17862
+ applyLogoSizes(editContentRef.current);
17863
+ };
17864
+ window.addEventListener("message", handleViewMode);
15858
17865
  const handleViewportResize = () => {
15859
17866
  if (visibleViewportRef.current) {
15860
17867
  applyVisibleViewport(visibleViewportRef.current, parentScrollRef.current);
@@ -15899,6 +17906,9 @@ function OhhwellsBridge() {
15899
17906
  window.removeEventListener("message", handleClearSchedulingWidget);
15900
17907
  window.removeEventListener("message", handleRemoveSchedulingSection);
15901
17908
  window.removeEventListener("message", handleCollectSection);
17909
+ window.removeEventListener("message", handleSocialCancel);
17910
+ window.removeEventListener("message", handleSocialUpdate);
17911
+ window.removeEventListener("message", handleIconMarkup);
15902
17912
  window.removeEventListener("message", handleImageUrl);
15903
17913
  window.removeEventListener("message", handleImageUploading);
15904
17914
  window.removeEventListener("message", handleCarouselChange);
@@ -15907,10 +17917,13 @@ function OhhwellsBridge() {
15907
17917
  window.removeEventListener("resize", handleViewportResize);
15908
17918
  window.removeEventListener("message", handlePointerSync);
15909
17919
  window.removeEventListener("message", handleClickAt);
17920
+ window.removeEventListener("message", handleUpdateLogoIdentity);
17921
+ window.removeEventListener("message", handleViewMode);
15910
17922
  window.removeEventListener("message", handleHydrate);
15911
17923
  window.removeEventListener("message", handleAiApplyTree);
15912
17924
  window.removeEventListener("message", handleAiDeleteSection);
15913
17925
  window.removeEventListener("message", handleAiSetSections);
17926
+ window.removeEventListener("message", handleAiSetBrand);
15914
17927
  window.removeEventListener("message", handleDeactivate);
15915
17928
  window.removeEventListener("message", handleToastAction);
15916
17929
  window.removeEventListener("message", handleUiEscape);
@@ -15920,7 +17933,7 @@ function OhhwellsBridge() {
15920
17933
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
15921
17934
  };
15922
17935
  }, [isEditMode, refreshStateRules]);
15923
- (0, import_react15.useEffect)(() => {
17936
+ (0, import_react16.useEffect)(() => {
15924
17937
  if (!isEditMode) return;
15925
17938
  const THRESHOLD = 10;
15926
17939
  const resolveWasSelected = (el) => {
@@ -15940,9 +17953,9 @@ function OhhwellsBridge() {
15940
17953
  return;
15941
17954
  }
15942
17955
  if (target.closest("[data-ohw-item-drag-surface]")) return;
15943
- const anchor = getNavigationItemAnchor(target);
17956
+ const anchor = getNavigationItemAnchor(target) ?? (document.elementsFromPoint(e.clientX, e.clientY).map((el) => el instanceof HTMLElement ? getNavigationItemAnchor(el) : null).find((found) => found !== null) ?? null);
15944
17957
  const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
15945
- if (anchor && isFooterHrefKey(hrefKey)) {
17958
+ if (anchor && (isFooterHrefKey(hrefKey) || getSocialItem(anchor))) {
15946
17959
  footerPointerDragRef.current = {
15947
17960
  el: anchor,
15948
17961
  kind: "link",
@@ -15975,7 +17988,7 @@ function OhhwellsBridge() {
15975
17988
  clearTextSelection();
15976
17989
  const session = footerDragRef.current;
15977
17990
  if (!session) return;
15978
- const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, session.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
17991
+ 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);
15979
17992
  refreshFooterDragVisualsRef.current(session, slot, e.clientX, e.clientY);
15980
17993
  return;
15981
17994
  }
@@ -16002,7 +18015,7 @@ function OhhwellsBridge() {
16002
18015
  const column = findFooterColumnForLink(pending.el);
16003
18016
  const columns2 = listFooterColumns();
16004
18017
  beginFooterDragRef.current({
16005
- kind: "link",
18018
+ kind: getSocialItem(pending.el) ? "social" : "link",
16006
18019
  hrefKey: key,
16007
18020
  columnEl: column,
16008
18021
  sourceColumnIndex: column ? columns2.indexOf(column) : 0,
@@ -16074,7 +18087,7 @@ function OhhwellsBridge() {
16074
18087
  unlockFooterDragInteraction();
16075
18088
  };
16076
18089
  }, [isEditMode]);
16077
- (0, import_react15.useEffect)(() => {
18090
+ (0, import_react16.useEffect)(() => {
16078
18091
  const handler = (e) => {
16079
18092
  if (e.data?.type !== "ow:request-schedule-config") return;
16080
18093
  const insertAfterVal = e.data.insertAfter;
@@ -16090,7 +18103,7 @@ function OhhwellsBridge() {
16090
18103
  window.addEventListener("message", handler);
16091
18104
  return () => window.removeEventListener("message", handler);
16092
18105
  }, [processConfigRequest]);
16093
- (0, import_react15.useEffect)(() => {
18106
+ (0, import_react16.useEffect)(() => {
16094
18107
  if (!isEditMode) return;
16095
18108
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
16096
18109
  el.removeAttribute("data-ohw-active-state");
@@ -16114,7 +18127,7 @@ function OhhwellsBridge() {
16114
18127
  postToParent2({
16115
18128
  type: "ow:ready",
16116
18129
  version: "1",
16117
- bridgeVersion: "0.1.54",
18130
+ bridgeVersion: "0.1.55",
16118
18131
  path: pathname,
16119
18132
  nodes: collectEditableNodes(editContentRef.current),
16120
18133
  sections
@@ -16126,13 +18139,13 @@ function OhhwellsBridge() {
16126
18139
  clearTimeout(timer);
16127
18140
  };
16128
18141
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
16129
- (0, import_react15.useEffect)(() => {
18142
+ (0, import_react16.useEffect)(() => {
16130
18143
  scrollToHashSectionWhenReady();
16131
18144
  const onHashChange = () => scrollToHashSectionWhenReady();
16132
18145
  window.addEventListener("hashchange", onHashChange);
16133
18146
  return () => window.removeEventListener("hashchange", onHashChange);
16134
18147
  }, [pathname]);
16135
- const handleCommand = (0, import_react15.useCallback)((cmd) => {
18148
+ const handleCommand = (0, import_react16.useCallback)((cmd) => {
16136
18149
  const el = activeElRef.current;
16137
18150
  const selBefore = window.getSelection();
16138
18151
  let savedOffsets = null;
@@ -16168,7 +18181,7 @@ function OhhwellsBridge() {
16168
18181
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
16169
18182
  refreshActiveCommandsRef.current();
16170
18183
  }, []);
16171
- const handleStateChange = (0, import_react15.useCallback)((state) => {
18184
+ const handleStateChange = (0, import_react16.useCallback)((state) => {
16172
18185
  if (!activeStateElRef.current) return;
16173
18186
  const el = activeStateElRef.current;
16174
18187
  if (state === "Default") {
@@ -16181,7 +18194,7 @@ function OhhwellsBridge() {
16181
18194
  }
16182
18195
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
16183
18196
  }, [deactivate]);
16184
- const reselectAfterLinkPopover = (0, import_react15.useCallback)(
18197
+ const reselectAfterLinkPopover = (0, import_react16.useCallback)(
16185
18198
  (hrefKey) => {
16186
18199
  requestAnimationFrame(() => {
16187
18200
  const el = resolveHrefKeyElement(hrefKey);
@@ -16190,7 +18203,7 @@ function OhhwellsBridge() {
16190
18203
  },
16191
18204
  [resolveHrefKeyElement]
16192
18205
  );
16193
- const closeLinkPopover = (0, import_react15.useCallback)(() => {
18206
+ const closeLinkPopover = (0, import_react16.useCallback)(() => {
16194
18207
  const session = linkPopoverSessionRef.current;
16195
18208
  addNavAfterAnchorRef.current = null;
16196
18209
  setLinkPopover(null);
@@ -16198,9 +18211,9 @@ function OhhwellsBridge() {
16198
18211
  reselectAfterLinkPopover(session.key);
16199
18212
  }
16200
18213
  }, [reselectAfterLinkPopover]);
16201
- const closeLinkPopoverRef = (0, import_react15.useRef)(closeLinkPopover);
18214
+ const closeLinkPopoverRef = (0, import_react16.useRef)(closeLinkPopover);
16202
18215
  closeLinkPopoverRef.current = closeLinkPopover;
16203
- const openLinkPopoverForActive = (0, import_react15.useCallback)(() => {
18216
+ const openLinkPopoverForActive = (0, import_react16.useCallback)(() => {
16204
18217
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
16205
18218
  if (!hrefCtx) return;
16206
18219
  bumpLinkPopoverGrace();
@@ -16211,11 +18224,15 @@ function OhhwellsBridge() {
16211
18224
  });
16212
18225
  deactivate();
16213
18226
  }, [deactivate]);
16214
- const openLinkPopoverForSelected = (0, import_react15.useCallback)(() => {
18227
+ const openLinkPopoverForSelected = (0, import_react16.useCallback)(() => {
16215
18228
  const anchor = selectedElRef.current;
16216
18229
  if (!anchor) return;
16217
18230
  const key = anchor.getAttribute("data-ohw-href-key");
16218
18231
  if (!key) return;
18232
+ if (requestSocialDialog(anchor, postToParentRef.current, editContentRef.current)) {
18233
+ deselect();
18234
+ return;
18235
+ }
16219
18236
  bumpLinkPopoverGrace();
16220
18237
  setLinkPopover({
16221
18238
  key,
@@ -16224,7 +18241,7 @@ function OhhwellsBridge() {
16224
18241
  });
16225
18242
  deselect();
16226
18243
  }, [deselect]);
16227
- const handleSelectParent = (0, import_react15.useCallback)(() => {
18244
+ const handleSelectParent = (0, import_react16.useCallback)(() => {
16228
18245
  const selected = selectedElRef.current;
16229
18246
  if (!selected) return;
16230
18247
  if (toolbarVariantRef.current === "select-frame") {
@@ -16251,11 +18268,37 @@ function OhhwellsBridge() {
16251
18268
  }
16252
18269
  deselectRef.current();
16253
18270
  }, []);
16254
- const handleDuplicateSelected = (0, import_react15.useCallback)(() => {
18271
+ const handleDuplicateSelected = (0, import_react16.useCallback)(() => {
16255
18272
  const selected = selectedElRef.current;
16256
18273
  if (!selected || !isNavigationItem2(selected)) return;
16257
18274
  const hrefKey = selected.getAttribute("data-ohw-href-key");
16258
18275
  if (!hrefKey) return;
18276
+ const social = getSocialItem(selected);
18277
+ if (social) {
18278
+ const result = duplicateSocialItem(social, editContentRef.current);
18279
+ if (!result) return;
18280
+ const orderJson = JSON.stringify(result.order);
18281
+ const carried = [
18282
+ { from: result.copiedFrom?.href, to: result.hrefKey },
18283
+ { from: result.copiedFrom?.icon, to: result.iconKey },
18284
+ { from: result.copiedFrom?.icon ? socialPlatformKey(result.copiedFrom.icon) : null, to: socialPlatformKey(result.iconKey) }
18285
+ ];
18286
+ const nodes = [{ key: SOCIALS_ORDER_KEY, text: orderJson }];
18287
+ for (const { from, to } of carried) {
18288
+ const value = from ? editContentRef.current[from] : void 0;
18289
+ if (value) nodes.push({ key: to, text: value });
18290
+ }
18291
+ editContentRef.current = {
18292
+ ...editContentRef.current,
18293
+ ...Object.fromEntries(nodes.map((node) => [node.key, node.text]))
18294
+ };
18295
+ postToParent2({ type: "ow:change", nodes });
18296
+ enforceLinkHrefs();
18297
+ const copyRow = findSocialsRow(result.item);
18298
+ if (copyRow) applySocialsDisplayToRow(copyRow, socialsDisplayFor(copyRow, editContentRef.current));
18299
+ requestAnimationFrame(() => selectRef.current(result.item));
18300
+ return;
18301
+ }
16259
18302
  if (isNavbarHrefKey(hrefKey)) {
16260
18303
  const result = duplicateNavbarItem(selected);
16261
18304
  if (!result) return;
@@ -16341,7 +18384,7 @@ function OhhwellsBridge() {
16341
18384
  });
16342
18385
  }
16343
18386
  }, [postToParent2]);
16344
- const runPendingDeleteUndo = (0, import_react15.useCallback)(() => {
18387
+ const runPendingDeleteUndo = (0, import_react16.useCallback)(() => {
16345
18388
  const pending = pendingDeleteUndoRef.current;
16346
18389
  if (!pending) return false;
16347
18390
  pendingDeleteUndoRef.current = null;
@@ -16349,7 +18392,7 @@ function OhhwellsBridge() {
16349
18392
  enforceLinkHrefs();
16350
18393
  return true;
16351
18394
  }, []);
16352
- const handleDeleteSelected = (0, import_react15.useCallback)(() => {
18395
+ const handleDeleteSelected = (0, import_react16.useCallback)(() => {
16353
18396
  const selected = selectedElRef.current;
16354
18397
  if (!selected) return false;
16355
18398
  return deleteSelectedNavFooterItem({
@@ -16370,7 +18413,7 @@ function OhhwellsBridge() {
16370
18413
  }, [postToParent2]);
16371
18414
  handleDeleteSelectedRef.current = handleDeleteSelected;
16372
18415
  runPendingDeleteUndoRef.current = runPendingDeleteUndo;
16373
- const handleLinkPopoverSubmit = (0, import_react15.useCallback)(
18416
+ const handleLinkPopoverSubmit = (0, import_react16.useCallback)(
16374
18417
  (target) => {
16375
18418
  const session = linkPopoverSessionRef.current;
16376
18419
  if (!session) return;
@@ -16436,19 +18479,19 @@ function OhhwellsBridge() {
16436
18479
  const showEditLink = toolbarShowEditLink;
16437
18480
  const currentSections = sectionsByPath[pathname] ?? [];
16438
18481
  linkPopoverOpenRef.current = linkPopover !== null;
16439
- const handleMediaReplace = (0, import_react15.useCallback)(
18482
+ const handleMediaReplace = (0, import_react16.useCallback)(
16440
18483
  (key) => {
16441
18484
  postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
16442
18485
  },
16443
18486
  [postToParent2, mediaHover?.elementType]
16444
18487
  );
16445
- const handleEditCarousel = (0, import_react15.useCallback)(
18488
+ const handleEditCarousel = (0, import_react16.useCallback)(
16446
18489
  (key) => {
16447
18490
  postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
16448
18491
  },
16449
18492
  [postToParent2]
16450
18493
  );
16451
- const handleMediaFadeOutComplete = (0, import_react15.useCallback)((key) => {
18494
+ const handleMediaFadeOutComplete = (0, import_react16.useCallback)((key) => {
16452
18495
  setUploadingRects((prev) => {
16453
18496
  if (!(key in prev)) return prev;
16454
18497
  const next = { ...prev };
@@ -16456,7 +18499,7 @@ function OhhwellsBridge() {
16456
18499
  return next;
16457
18500
  });
16458
18501
  }, []);
16459
- const handleVideoSettingsChange = (0, import_react15.useCallback)(
18502
+ const handleVideoSettingsChange = (0, import_react16.useCallback)(
16460
18503
  (key, settings) => {
16461
18504
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
16462
18505
  const video = getVideoEl2(el);
@@ -16479,10 +18522,10 @@ function OhhwellsBridge() {
16479
18522
  [postToParent2]
16480
18523
  );
16481
18524
  return bridgeRoot ? (0, import_react_dom4.createPortal)(
16482
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
16483
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
16484
- isEditMode && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
16485
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
18525
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
18526
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
18527
+ isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
18528
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16486
18529
  MediaOverlay,
16487
18530
  {
16488
18531
  hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
@@ -16493,7 +18536,7 @@ function OhhwellsBridge() {
16493
18536
  },
16494
18537
  `uploading-${key}`
16495
18538
  )),
16496
- mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
18539
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16497
18540
  MediaOverlay,
16498
18541
  {
16499
18542
  hover: mediaHover,
@@ -16502,11 +18545,11 @@ function OhhwellsBridge() {
16502
18545
  onVideoSettingsChange: handleVideoSettingsChange
16503
18546
  }
16504
18547
  ),
16505
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
16506
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
16507
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
16508
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
16509
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
18548
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
18549
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
18550
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
18551
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
18552
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16510
18553
  "div",
16511
18554
  {
16512
18555
  className: "pointer-events-none fixed z-2147483646",
@@ -16516,7 +18559,7 @@ function OhhwellsBridge() {
16516
18559
  width: slot.width,
16517
18560
  height: slot.height
16518
18561
  },
16519
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
18562
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16520
18563
  DropIndicator,
16521
18564
  {
16522
18565
  direction: slot.direction,
@@ -16527,7 +18570,7 @@ function OhhwellsBridge() {
16527
18570
  },
16528
18571
  `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
16529
18572
  )),
16530
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
18573
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16531
18574
  "div",
16532
18575
  {
16533
18576
  className: "pointer-events-none fixed z-2147483646",
@@ -16537,7 +18580,7 @@ function OhhwellsBridge() {
16537
18580
  width: slot.width,
16538
18581
  height: slot.height
16539
18582
  },
16540
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
18583
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16541
18584
  DropIndicator,
16542
18585
  {
16543
18586
  direction: slot.direction,
@@ -16548,10 +18591,10 @@ function OhhwellsBridge() {
16548
18591
  },
16549
18592
  `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
16550
18593
  )),
16551
- hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
16552
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
16553
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
16554
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
18594
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
18595
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
18596
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
18597
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16555
18598
  FooterContainerChrome,
16556
18599
  {
16557
18600
  rect: toolbarRect,
@@ -16559,7 +18602,7 @@ function OhhwellsBridge() {
16559
18602
  addDisabled: !canAddFooterColumn()
16560
18603
  }
16561
18604
  ),
16562
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
18605
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16563
18606
  ItemInteractionLayer,
16564
18607
  {
16565
18608
  rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
@@ -16571,13 +18614,21 @@ function OhhwellsBridge() {
16571
18614
  dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
16572
18615
  onDragHandleDragStart: handleItemDragStart,
16573
18616
  onDragHandleDragEnd: handleItemDragEnd,
16574
- onItemPointerDown: handleItemChromePointerDown,
16575
- onItemClick: handleItemChromeClick,
16576
- itemDragSurface: !isFooterFrameSelection,
16577
- toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && isFooterFrameSelection && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
18617
+ onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
18618
+ onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
18619
+ itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
18620
+ toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16578
18621
  ItemActionToolbar,
16579
18622
  {
16580
18623
  onEditLink: openLinkPopoverForSelected,
18624
+ onStyle: () => {
18625
+ const row = selectedElRef.current;
18626
+ if (!row) return;
18627
+ if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
18628
+ else openSocialsDisplayPanel(row);
18629
+ },
18630
+ showStyle: selectedIsSocialsRow,
18631
+ styleActive: floatingPanel?.kind === "socials-display",
16581
18632
  onAddItem: handleAddChildItem,
16582
18633
  onSelectParent: handleSelectParent,
16583
18634
  onDuplicate: handleDuplicateSelected,
@@ -16585,12 +18636,12 @@ function OhhwellsBridge() {
16585
18636
  addItemDisabled: false,
16586
18637
  editLinkDisabled: false,
16587
18638
  moreDisabled: false,
16588
- duplicateDisabled: isFooterFrameSelection,
16589
- showEditLink: !isFooterFrameSelection && navDropdownPreviewOpen === null,
16590
- showAddItem: isFooterFrameSelection || !selectedIsCta && Boolean(
18639
+ duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
18640
+ showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
18641
+ showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
16591
18642
  selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
16592
18643
  ),
16593
- showMore: !selectedIsCta || isFooterFrameSelection,
18644
+ showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
16594
18645
  dropdownOpen: navDropdownPreviewOpen,
16595
18646
  onDropdownOpenChange: handleNavDropdownOpenChange,
16596
18647
  headingVisible: footerHeadingVisible,
@@ -16599,8 +18650,8 @@ function OhhwellsBridge() {
16599
18650
  ) : void 0
16600
18651
  }
16601
18652
  ),
16602
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
16603
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
18653
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
18654
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16604
18655
  EditGlowChrome,
16605
18656
  {
16606
18657
  rect: toolbarRect,
@@ -16610,7 +18661,7 @@ function OhhwellsBridge() {
16610
18661
  hideHandle: isItemDragging
16611
18662
  }
16612
18663
  ),
16613
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
18664
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16614
18665
  FloatingToolbar,
16615
18666
  {
16616
18667
  rect: toolbarRect,
@@ -16623,7 +18674,7 @@ function OhhwellsBridge() {
16623
18674
  }
16624
18675
  )
16625
18676
  ] }),
16626
- maxBadge && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
18677
+ maxBadge && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
16627
18678
  "div",
16628
18679
  {
16629
18680
  "data-ohw-max-badge": "",
@@ -16649,7 +18700,7 @@ function OhhwellsBridge() {
16649
18700
  ]
16650
18701
  }
16651
18702
  ),
16652
- toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
18703
+ toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16653
18704
  StateToggle,
16654
18705
  {
16655
18706
  rect: toggleState.rect,
@@ -16658,15 +18709,15 @@ function OhhwellsBridge() {
16658
18709
  onStateChange: handleStateChange
16659
18710
  }
16660
18711
  ),
16661
- sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
18712
+ sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
16662
18713
  "div",
16663
18714
  {
16664
18715
  "data-ohw-section-insert-line": "",
16665
18716
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
16666
18717
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
16667
18718
  children: [
16668
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
16669
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
18719
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
18720
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16670
18721
  Badge,
16671
18722
  {
16672
18723
  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",
@@ -16683,11 +18734,11 @@ function OhhwellsBridge() {
16683
18734
  children: "Add Section"
16684
18735
  }
16685
18736
  ),
16686
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
18737
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
16687
18738
  ]
16688
18739
  }
16689
18740
  ),
16690
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
18741
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
16691
18742
  LinkPopover,
16692
18743
  {
16693
18744
  panelRef: linkPopoverPanelRef,
@@ -16703,11 +18754,137 @@ function OhhwellsBridge() {
16703
18754
  onSubmit: handleLinkPopoverSubmit
16704
18755
  },
16705
18756
  linkPopover.key
18757
+ ) : null,
18758
+ floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
18759
+ FloatingPanel,
18760
+ {
18761
+ open: true,
18762
+ title: floatingPanel.title,
18763
+ context: floatingPanel.context,
18764
+ position: floatingPanelPos,
18765
+ onPositionChange: setFloatingPanelPos,
18766
+ parentScroll: parentScrollSnap ?? parentScrollRef.current,
18767
+ onClose: closeFloatingPanelOnly,
18768
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
18769
+ SocialsDisplayPanel,
18770
+ {
18771
+ display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
18772
+ onChange: (next) => {
18773
+ changeSocialsDisplay(floatingPanel.row, next);
18774
+ setFloatingPanel({ ...floatingPanel });
18775
+ }
18776
+ }
18777
+ )
18778
+ }
18779
+ ) : null,
18780
+ floatingPanel && floatingPanel.kind === "logo-size" && logoSizeDraft ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
18781
+ FloatingPanel,
18782
+ {
18783
+ open: true,
18784
+ title: floatingPanel.title,
18785
+ context: floatingPanel.context,
18786
+ position: floatingPanelPos,
18787
+ onPositionChange: setFloatingPanelPos,
18788
+ parentScroll: parentScrollSnap ?? parentScrollRef.current,
18789
+ onClose: closeFloatingPanelAndDeselect,
18790
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
18791
+ LogoSizePanel,
18792
+ {
18793
+ viewport: editorViewport,
18794
+ sizePx: editorViewport === "mobile" && !logoSizeDraft.mobileFollowing ? logoSizeDraft.mobilePx : logoSizeDraft.desktopPx,
18795
+ mobileFollowing: logoSizeDraft.mobileFollowing,
18796
+ onSizeChange: (px) => {
18797
+ const next = editorViewport === "mobile" ? { ...logoSizeDraft, mobilePx: px, mobileFollowing: false } : {
18798
+ ...logoSizeDraft,
18799
+ desktopPx: px,
18800
+ mobilePx: logoSizeDraft.mobileFollowing ? px : logoSizeDraft.mobilePx
18801
+ };
18802
+ setLogoSizeDraft(next);
18803
+ persistLogoSizeDraft(floatingPanel.placement, next);
18804
+ },
18805
+ onCustomizeMobile: () => {
18806
+ const next = {
18807
+ ...logoSizeDraft,
18808
+ mobileFollowing: false,
18809
+ mobilePx: logoSizeDraft.desktopPx
18810
+ };
18811
+ setLogoSizeDraft(next);
18812
+ persistLogoSizeDraft(floatingPanel.placement, next);
18813
+ },
18814
+ onResetMobile: () => {
18815
+ const next = {
18816
+ ...logoSizeDraft,
18817
+ mobileFollowing: true,
18818
+ mobilePx: logoSizeDraft.desktopPx
18819
+ };
18820
+ setLogoSizeDraft(next);
18821
+ persistLogoSizeDraft(floatingPanel.placement, next);
18822
+ },
18823
+ onUpdateEverywhere: () => {
18824
+ const identity = readLogoIdentityFromDom();
18825
+ postToParent2({ type: "ow:open-logo-settings", ...identity });
18826
+ }
18827
+ }
18828
+ )
18829
+ }
16706
18830
  ) : null
16707
18831
  ] }),
16708
18832
  bridgeRoot
16709
18833
  ) : null;
16710
18834
  }
18835
+
18836
+ // src/ui/EmptySection.tsx
18837
+ var import_link = __toESM(require("next/link"), 1);
18838
+ var import_jsx_runtime34 = require("react/jsx-runtime");
18839
+ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
18840
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
18841
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
18842
+ "p",
18843
+ {
18844
+ style: {
18845
+ fontFamily: "var(--brand-font-body)",
18846
+ fontSize: "0.75rem",
18847
+ fontWeight: 500,
18848
+ letterSpacing: "0.15em",
18849
+ textTransform: "uppercase",
18850
+ color: "var(--brand-accent)",
18851
+ marginBottom: "1.5rem"
18852
+ },
18853
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_link.default, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
18854
+ }
18855
+ ),
18856
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
18857
+ "h1",
18858
+ {
18859
+ style: {
18860
+ fontFamily: "var(--brand-font-heading)",
18861
+ fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
18862
+ lineHeight: 1.1,
18863
+ letterSpacing: "-0.025em",
18864
+ color: "var(--brand-text)",
18865
+ marginBottom: "1rem"
18866
+ },
18867
+ ...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
18868
+ children: title
18869
+ }
18870
+ ),
18871
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
18872
+ "p",
18873
+ {
18874
+ style: {
18875
+ fontFamily: "var(--brand-font-body)",
18876
+ fontSize: "1rem",
18877
+ lineHeight: 1.7,
18878
+ fontWeight: 300,
18879
+ color: "var(--brand-text-muted)",
18880
+ maxWidth: "340px"
18881
+ },
18882
+ ...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
18883
+ children: "This page doesn't have any content yet."
18884
+ }
18885
+ )
18886
+ ] });
18887
+ }
16711
18888
  // Annotate the CommonJS export names for ESM import in node:
16712
18889
  0 && (module.exports = {
16713
18890
  AI_DEFAULT_BRAND,
@@ -16725,6 +18902,7 @@ function OhhwellsBridge() {
16725
18902
  DropdownMenuItem,
16726
18903
  DropdownMenuSeparator,
16727
18904
  DropdownMenuTrigger,
18905
+ EmptySection,
16728
18906
  ItemActionToolbar,
16729
18907
  ItemInteractionLayer,
16730
18908
  LinkEditorPanel,