@ohhwells/bridge 0.1.149-next.400 → 0.1.149

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/OhhwellsBridge.tsx
4
- import React12, { useCallback as useCallback12, useEffect as useEffect17, useLayoutEffect as useLayoutEffect7, useRef as useRef14, useState as useState18 } from "react";
4
+ import React12, { useCallback as useCallback12, useEffect as useEffect17, useLayoutEffect as useLayoutEffect6, useRef as useRef14, useState as useState18 } from "react";
5
5
  import { createRoot as createRoot3 } from "react-dom/client";
6
6
  import { flushSync as flushSync3 } from "react-dom";
7
7
 
@@ -6542,21 +6542,6 @@ function pricingCardFeatureCount(tree, index) {
6542
6542
  const target = findPricingCollection(tree)?.children?.[index];
6543
6543
  return target ? pricingFeatureList(target).length : 0;
6544
6544
  }
6545
- function prevailingFeatureIcon(features) {
6546
- const counts = /* @__PURE__ */ new Map();
6547
- for (const row of features) {
6548
- const key = `${row.icon ?? ""}|${row.iconColor ?? ""}`;
6549
- const entry = counts.get(key) ?? { count: 0, ...row.icon ? { icon: row.icon } : {}, ...row.iconColor ? { iconColor: row.iconColor } : {} };
6550
- entry.count += 1;
6551
- counts.set(key, entry);
6552
- }
6553
- let best = null;
6554
- for (const entry of counts.values()) {
6555
- if (!best || entry.count > best.count) best = entry;
6556
- }
6557
- if (!best) return {};
6558
- return { ...best.icon ? { icon: best.icon } : {}, ...best.iconColor ? { iconColor: best.iconColor } : {} };
6559
- }
6560
6545
  function addPricingCardFeature(tree, index, text) {
6561
6546
  return withPricingCollection(tree, (collection) => {
6562
6547
  const children = collection.children;
@@ -6565,7 +6550,7 @@ function addPricingCardFeature(tree, index, text) {
6565
6550
  const features = pricingFeatureList(target);
6566
6551
  if (features.length >= PRICING_FEATURES_MAX) return false;
6567
6552
  target.slots = target.slots ?? {};
6568
- target.slots.features = [...features, { text, ...prevailingFeatureIcon(features) }];
6553
+ target.slots.features = [...features, { text }];
6569
6554
  return true;
6570
6555
  });
6571
6556
  }
@@ -7748,7 +7733,7 @@ var AI_MOBILE_CSS = [
7748
7733
  // page's first section. Top only (bottom needs no nav clearance); ~96px approximates the
7749
7734
  // template nav's own height (measured ~94px) — there's no shared `--ohw-header-h` var to read
7750
7735
  // an exact figure from (no live measurement exists), so this is a safe approximation, not a
7751
- // pixel-exact fit. Horizontal spacing already comes from `data-ai-section-inner`.
7736
+ // pixel-exact fit. Horizontal spacing already comes from `data-ai-container`.
7752
7737
  '[data-ai-overlay-clearance] [data-ai-overlap-layer="overlay"]{padding-top:96px}',
7753
7738
  // A full-bleed carousel's height is pure arithmetic: it spans the whole window, so 16/9 turns
7754
7739
  // window width straight into height. Measured at 16/9 it came out ~90% of the viewport at EVERY
@@ -7764,10 +7749,8 @@ var AI_MOBILE_CSS = [
7764
7749
  "[data-ai-section]{overflow-x:hidden}",
7765
7750
  // `:not([data-ai-full-bleed])`: this `!important` gutter beat the inline `padding: 0` that a
7766
7751
  // full-bleed section's container sets, so a carousel/media hero that is edge-to-edge on desktop
7767
- // still got a 20px band of section background down both sides on a phone. The footer's own
7768
- // container keeps the unguarded rule below — `data-ai-full-bleed` can never appear on it.
7769
- "[data-ai-section-inner]:not([data-ai-full-bleed]){padding:0 20px !important}",
7770
- "[data-ai-container]{padding:0 20px !important}",
7752
+ // still got a 20px band of section background down both sides on a phone.
7753
+ "[data-ai-container]:not([data-ai-full-bleed]){padding:0 20px !important}",
7771
7754
  "[data-ai-row]{display:flex !important;flex-direction:column !important;align-items:stretch !important}",
7772
7755
  "[data-ai-cell]{width:100%;min-width:0}",
7773
7756
  // The rule above turns every row into a COLUMN flex container on phones, which silently breaks
@@ -7972,31 +7955,6 @@ function pricingCardEmphasis(featured, ctx, hasBg) {
7972
7955
  function textAttrs(ctx, path) {
7973
7956
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
7974
7957
  }
7975
- var AI_RESPONSIVE_CSS = [
7976
- "@media (max-width: 960px) {",
7977
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
7978
- ' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
7979
- "}",
7980
- "@media (max-width: 640px) {",
7981
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
7982
- " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
7983
- // Group containers flatten to a column on phones; span placements come along for free.
7984
- // `:not([data-ai-group="overlap"])` for the same reason as the twin pair in AI_MOBILE_CSS — see
7985
- // the comment there. This sheet's copy is the narrower selector, so without the exemption it
7986
- // flattens an `overlap` hero below 640px even though the other rule stands down: measured a 390px
7987
- // viewport with the heading/CTA in flow *under* the image, 219px of section background where the
7988
- // layered text used to be.
7989
- ' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) { display: flex !important; flex-direction: column !important; }',
7990
- ' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) > * { grid-column: auto !important; }',
7991
- // `:not([data-ai-full-bleed])` for the same reason as the twin rule in AI_MOBILE_CSS: this one
7992
- // is narrower (0,2,0 vs 0,1,0) and also `!important`, so without the guard it wins outright and
7993
- // a full-bleed hero gets its 20px side band back below 640px only — the one width where the
7994
- // other rule had already been taught to stand down.
7995
- " [data-ai-responsive] [data-ai-section-inner]:not([data-ai-full-bleed]) { padding-left: 20px !important; padding-right: 20px !important; }",
7996
- " [data-ai-responsive] { overflow-x: hidden; }",
7997
- " [data-ai-responsive] img { max-width: 100%; }",
7998
- "}"
7999
- ].join("\n");
8000
7958
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
8001
7959
  function MediaBox({
8002
7960
  refValue,
@@ -8051,7 +8009,7 @@ function MediaBox({
8051
8009
  position: fill ? "absolute" : void 0,
8052
8010
  inset: fill ? 0 : void 0,
8053
8011
  width: fill ? "100%" : fixedSize ? "auto" : "100%",
8054
- height: fill ? "100%" : fixedSize ? height : void 0,
8012
+ height: fill ? "100%" : void 0,
8055
8013
  aspectRatio: fill ? void 0 : aspectRatio,
8056
8014
  minHeight: fill || fixedSize ? void 0 : height ?? (aspectRatio ? void 0 : 180),
8057
8015
  borderRadius: radius,
@@ -9547,7 +9505,7 @@ function CollectionBlock({ node, ctx, path }) {
9547
9505
  return /* @__PURE__ */ jsx(
9548
9506
  "div",
9549
9507
  {
9550
- "data-ai-grid": String(itemsPerRow),
9508
+ "data-ai-grid": "",
9551
9509
  "data-ohw-pricing-collection": isPricing ? "" : void 0,
9552
9510
  style: {
9553
9511
  display: "grid",
@@ -9849,7 +9807,7 @@ function renderNode(node, ctx, path, ambientAlign) {
9849
9807
  },
9850
9808
  children: [
9851
9809
  i > 0 && ctx.heroOverlapFullBleed ? (
9852
- // The section's `data-ai-section-inner` gave up its max-width/gutter so the base
9810
+ // The section's `data-ai-container` gave up its max-width/gutter so the base
9853
9811
  // layer (this group's i===0 sibling) can span edge-to-edge — reintroduced here,
9854
9812
  // scoped to just the overlay text, so a heading/copy/CTA stack doesn't stretch
9855
9813
  // the full section width instead of reading at the usual content width.
@@ -10268,7 +10226,6 @@ function AiTreeRenderer({
10268
10226
  ...fillHeight ? { "data-ai-fill-height": "" } : {},
10269
10227
  ...needsOverlayClearance ? { "data-ai-overlay-clearance": "" } : {},
10270
10228
  ...bgAttrs,
10271
- "data-ai-responsive": "",
10272
10229
  style: {
10273
10230
  position: "relative",
10274
10231
  padding: `${padCss} 0`,
@@ -10282,13 +10239,12 @@ function AiTreeRenderer({
10282
10239
  ...fillHeight ? { display: "grid" } : {}
10283
10240
  },
10284
10241
  children: [
10285
- /* @__PURE__ */ jsx("style", { children: AI_RESPONSIVE_CSS }),
10286
- /* @__PURE__ */ jsx("style", { children: AI_MOBILE_CSS }),
10287
10242
  isOverlay && backgroundUrl && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
10243
+ /* @__PURE__ */ jsx("style", { children: AI_MOBILE_CSS }),
10288
10244
  /* @__PURE__ */ jsx(
10289
10245
  "div",
10290
10246
  {
10291
- "data-ai-section-inner": "",
10247
+ "data-ai-container": "",
10292
10248
  ...fullBleedMedia ? { "data-ai-full-bleed": "" } : {},
10293
10249
  style: {
10294
10250
  position: "relative",
@@ -10305,7 +10261,7 @@ function AiTreeRenderer({
10305
10261
  children: tree.rows.map((row, r2) => /* @__PURE__ */ jsx(
10306
10262
  "div",
10307
10263
  {
10308
- "data-ai-columns": "",
10264
+ "data-ai-row": "",
10309
10265
  style: {
10310
10266
  display: "grid",
10311
10267
  gridTemplateColumns: "repeat(12, 1fr)",
@@ -10967,10 +10923,9 @@ function applyAiSectionsToDom(state, options) {
10967
10923
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
10968
10924
  continue;
10969
10925
  }
10926
+ const isNewMount = !existing || !existing.container.isConnected;
10970
10927
  let container = existing?.container;
10971
- let isNewMount = false;
10972
10928
  if (!container || !container.isConnected) {
10973
- isNewMount = true;
10974
10929
  existing?.root.unmount();
10975
10930
  container?.remove();
10976
10931
  container = document.createElement("div");
@@ -17412,7 +17367,6 @@ function MediaOverlay({
17412
17367
  (prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
17413
17368
  );
17414
17369
  }, [isVideo]);
17415
- const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
17416
17370
  const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
17417
17371
  const box = {
17418
17372
  position: "fixed",
@@ -17511,10 +17465,11 @@ function MediaOverlay({
17511
17465
  className: "flex items-center justify-center cursor-pointer",
17512
17466
  style: {
17513
17467
  ...box,
17514
- // Visual only. `pointer-events: auto` on this full-bleed rect covered the navbar
17515
- // (hero bg includes the absolute TopNav) and swallowed CTA press-drag. Text overlay
17516
- // and cueOnly also need clicks to fall through — Replace / video controls opt back in.
17517
- pointerEvents: "none",
17468
+ // When text overlays this media, let clicks fall THROUGH to the text underneath. In the
17469
+ // parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
17470
+ // in-document, pointer-events does it natively. The button below opts back in, so
17471
+ // Replace still works.
17472
+ pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
17518
17473
  // Selected: a firm component ring with no wash, so the image reads as chosen rather
17519
17474
  // than hovered. Hover keeps the existing tinted preview.
17520
17475
  boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
@@ -17541,17 +17496,17 @@ function MediaOverlay({
17541
17496
  },
17542
17497
  children: [
17543
17498
  isVideo ? /* @__PURE__ */ jsx16(Film, { size: 14 }) : /* @__PURE__ */ jsx16(ImageIcon, { size: 14 }),
17544
- replaceLabel
17499
+ isVideo ? "Replace video" : "Replace image"
17545
17500
  ]
17546
17501
  }
17547
17502
  ),
17548
- showChrome && replaceMode !== "none" && /* @__PURE__ */ jsxs7(
17503
+ replaceMode === "none" || cueOnly ? null : /* @__PURE__ */ jsxs7(
17549
17504
  Button,
17550
17505
  {
17551
17506
  "data-ohw-media-overlay": "",
17552
17507
  variant: "outline",
17553
17508
  size: "sm",
17554
- "aria-label": replaceLabel,
17509
+ "aria-label": isVideo ? "Replace video" : "Replace image",
17555
17510
  className: "gap-1.5 cursor-pointer hover:bg-background",
17556
17511
  style: {
17557
17512
  ...OVERLAY_BUTTON_STYLE,
@@ -17574,7 +17529,7 @@ function MediaOverlay({
17574
17529
  },
17575
17530
  children: [
17576
17531
  isVideo ? /* @__PURE__ */ jsx16(Film, { size: 14 }) : /* @__PURE__ */ jsx16(ImageIcon, { size: 14 }),
17577
- replaceMode === "full" ? replaceLabel : null
17532
+ replaceMode === "full" ? isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image" : null
17578
17533
  ]
17579
17534
  }
17580
17535
  )
@@ -18083,24 +18038,8 @@ function AiSectionOverlay({
18083
18038
  }
18084
18039
 
18085
18040
  // src/ui/ai-section/AiMediaStripOverlay.tsx
18086
- import { useCallback as useCallback3, useEffect as useEffect6, useLayoutEffect as useLayoutEffect4, useRef as useRef5, useState as useState8 } from "react";
18087
- import {
18088
- AlignCenter,
18089
- AlignLeft,
18090
- AlignRight,
18091
- ArrowLeft as ArrowLeft2,
18092
- ArrowRight as ArrowRight2,
18093
- Check as Check2,
18094
- ChevronDown as ChevronDown3,
18095
- Image as ImageIcon2,
18096
- ImageMinus,
18097
- ImagePlus,
18098
- Link as LinkIcon,
18099
- Minus,
18100
- Palette,
18101
- Plus as Plus2,
18102
- Star
18103
- } from "lucide-react";
18041
+ import { useCallback as useCallback3, useEffect as useEffect6, useRef as useRef5, useState as useState8 } from "react";
18042
+ import { Star } from "lucide-react";
18104
18043
 
18105
18044
  // src/lib/ai-media-strip-tree.ts
18106
18045
  var MEDIA_STRIP_ITEM_MIN = 1;
@@ -18214,6 +18153,14 @@ function setMediaStripItemAsset(tree, index, assetId) {
18214
18153
  return true;
18215
18154
  });
18216
18155
  }
18156
+ function setMediaStripItemAlt(tree, index, alt) {
18157
+ return withMediaStrip(tree, (block) => {
18158
+ const items = block.items;
18159
+ if (index < 0 || index >= items.length) return false;
18160
+ items[index] = { ...items[index], alt };
18161
+ return true;
18162
+ });
18163
+ }
18217
18164
  function setMediaStripItemLink(tree, index, link) {
18218
18165
  return withMediaStrip(tree, (block) => {
18219
18166
  const items = block.items;
@@ -18231,117 +18178,11 @@ function setMediaStripItemLink(tree, index, link) {
18231
18178
  });
18232
18179
  }
18233
18180
 
18234
- // src/ui/dialog.tsx
18235
- import * as React9 from "react";
18236
- import { Dialog as DialogPrimitive } from "radix-ui";
18237
- import { X as X2 } from "lucide-react";
18238
- import { jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
18239
- function Dialog2({
18240
- ...props
18241
- }) {
18242
- return /* @__PURE__ */ jsx19(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
18243
- }
18244
- function DialogPortal({
18245
- ...props
18246
- }) {
18247
- return /* @__PURE__ */ jsx19(DialogPrimitive.Portal, { ...props });
18248
- }
18249
- function DialogOverlay({
18250
- className,
18251
- ...props
18252
- }) {
18253
- return /* @__PURE__ */ jsx19(
18254
- DialogPrimitive.Overlay,
18255
- {
18256
- "data-slot": "dialog-overlay",
18257
- "data-ohw-link-modal-root": "",
18258
- className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
18259
- ...props
18260
- }
18261
- );
18262
- }
18263
- var DialogContent = React9.forwardRef(
18264
- ({ className, children, showCloseButton = true, container, ...props }, ref) => {
18265
- const positionMode = container ? "absolute" : "fixed";
18266
- return /* @__PURE__ */ jsxs10(DialogPortal, { container: container ?? void 0, children: [
18267
- /* @__PURE__ */ jsx19(DialogOverlay, { className: cn(positionMode, "inset-0") }),
18268
- /* @__PURE__ */ jsxs10(
18269
- DialogPrimitive.Content,
18270
- {
18271
- ref,
18272
- "data-slot": "dialog-content",
18273
- className: cn(
18274
- positionMode,
18275
- "left-1/2 top-1/2 z-[2147483647] flex w-full max-w-[448px] -translate-x-1/2 -translate-y-1/2 flex-col overflow-visible",
18276
- "rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
18277
- container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
18278
- className
18279
- ),
18280
- onMouseDown: (e) => e.stopPropagation(),
18281
- ...props,
18282
- children: [
18283
- children,
18284
- showCloseButton ? /* @__PURE__ */ jsx19(
18285
- DialogPrimitive.Close,
18286
- {
18287
- type: "button",
18288
- className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
18289
- "aria-label": "Close",
18290
- children: /* @__PURE__ */ jsx19(X2, { size: 16, "aria-hidden": true })
18291
- }
18292
- ) : null
18293
- ]
18294
- }
18295
- )
18296
- ] });
18297
- }
18298
- );
18299
- DialogContent.displayName = DialogPrimitive.Content.displayName;
18300
- function DialogHeader({
18301
- className,
18302
- ...props
18303
- }) {
18304
- return /* @__PURE__ */ jsx19("div", { className: cn("flex flex-col gap-1.5", className), ...props });
18305
- }
18306
- function DialogFooter({
18307
- className,
18308
- ...props
18309
- }) {
18310
- return /* @__PURE__ */ jsx19(
18311
- "div",
18312
- {
18313
- className: cn("flex items-center justify-end gap-2", className),
18314
- ...props
18315
- }
18316
- );
18317
- }
18318
- var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx19(
18319
- DialogPrimitive.Title,
18320
- {
18321
- ref,
18322
- className: cn(
18323
- "text-lg font-semibold leading-none tracking-tight text-card-foreground",
18324
- className
18325
- ),
18326
- ...props
18327
- }
18328
- ));
18329
- DialogTitle.displayName = DialogPrimitive.Title.displayName;
18330
- var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx19(
18331
- DialogPrimitive.Description,
18332
- {
18333
- ref,
18334
- className: cn("text-sm text-muted-foreground", className),
18335
- ...props
18336
- }
18337
- ));
18338
- DialogDescription.displayName = DialogPrimitive.Description.displayName;
18339
- var DialogClose = DialogPrimitive.Close;
18340
-
18341
18181
  // src/ui/ai-section/AiMediaStripOverlay.tsx
18342
- import { Fragment as Fragment6, jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
18343
- var PRIMARY3 = "var(--ohw-primary, #0885FE)";
18344
- var CHROME_SELECTOR = "[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-link-modal-root], [data-ohw-section-picker], [data-ohw-ai-review], [data-ohw-more-menu]";
18182
+ import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
18183
+ var PRIMARY3 = "#0885FE";
18184
+ var OHW_BLUE = `var(--ohw-primary, ${PRIMARY3})`;
18185
+ var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY3}) 60%, #000000)`;
18345
18186
  function findMediaStripItemElement(sectionId, index) {
18346
18187
  const sectionEl = findByInstanceId(sectionId);
18347
18188
  if (!sectionEl) return null;
@@ -18351,35 +18192,14 @@ function findMediaStripItemElement(sectionId, index) {
18351
18192
  }
18352
18193
  return null;
18353
18194
  }
18354
- function itemRefFromTarget(target) {
18355
- if (!(target instanceof Element)) return null;
18356
- if (target.closest(CHROME_SELECTOR)) return null;
18357
- const itemEl = target.closest("[data-ohw-media-strip-item]");
18358
- if (!itemEl) return null;
18359
- const sectionEl = itemEl.closest("[data-ohw-section]");
18360
- const unit = sectionEl ? movableUnit(sectionEl) : null;
18361
- const sectionId = unit ? instanceIdOf(unit) || null : null;
18362
- const index = Number(itemEl.dataset.ohwMediaStripIndex);
18363
- if (!sectionId || Number.isNaN(index)) return null;
18364
- return { sectionId, index };
18365
- }
18366
- function sameRef(a, b) {
18367
- return a?.sectionId === b?.sectionId && a?.index === b?.index;
18368
- }
18369
- function rectOf(el) {
18195
+ function readRect2(ref) {
18196
+ const el = ref && findMediaStripItemElement(ref.sectionId, ref.index);
18370
18197
  if (!el) return null;
18371
18198
  const r2 = el.getBoundingClientRect();
18372
18199
  if (r2.width <= 0 || r2.height <= 0) return null;
18373
18200
  return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
18374
18201
  }
18375
- function readRect2(ref) {
18376
- return rectOf(ref && findMediaStripItemElement(ref.sectionId, ref.index));
18377
- }
18378
- function readStripRect(ref) {
18379
- const item = ref && findMediaStripItemElement(ref.sectionId, ref.index);
18380
- return rectOf(item?.closest("[data-ohw-media-strip]") ?? item);
18381
- }
18382
- function useLiveItemRect(ref, strip = false) {
18202
+ function useLiveItemRect(ref) {
18383
18203
  const [rect, setRect] = useState8(null);
18384
18204
  useEffect6(() => {
18385
18205
  if (!ref) {
@@ -18387,7 +18207,7 @@ function useLiveItemRect(ref, strip = false) {
18387
18207
  return;
18388
18208
  }
18389
18209
  const update = () => {
18390
- const next = strip ? readStripRect(ref) : readRect2(ref);
18210
+ const next = readRect2(ref);
18391
18211
  setRect(
18392
18212
  (prev) => prev && next && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
18393
18213
  );
@@ -18402,49 +18222,9 @@ function useLiveItemRect(ref, strip = false) {
18402
18222
  window.removeEventListener("resize", update);
18403
18223
  clearInterval(interval);
18404
18224
  };
18405
- }, [ref?.sectionId, ref?.index, strip]);
18225
+ }, [ref?.sectionId, ref?.index]);
18406
18226
  return rect;
18407
18227
  }
18408
- var TOOLBAR_STRIP_GAP = 52;
18409
- var TOOLBAR_STRIP_GAP_MOBILE = 42;
18410
- var TOOLBAR_EDGE_MARGIN2 = 4;
18411
- function StripToolbarSlot({ stripRect, children }) {
18412
- const slotRef = useRef5(null);
18413
- const [shift, setShift] = useState8(0);
18414
- const centerX = stripRect.left + stripRect.width / 2;
18415
- useLayoutEffect4(() => {
18416
- const slot = slotRef.current;
18417
- if (!slot) return;
18418
- const clamp = () => {
18419
- const w = slot.offsetWidth;
18420
- if (w <= 0) return;
18421
- const half = w / 2;
18422
- const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
18423
- setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
18424
- };
18425
- clamp();
18426
- const ro = new ResizeObserver(clamp);
18427
- ro.observe(slot);
18428
- return () => ro.disconnect();
18429
- }, [centerX, children]);
18430
- const mobile = window.innerWidth <= 480;
18431
- return /* @__PURE__ */ jsx20(
18432
- "div",
18433
- {
18434
- ref: slotRef,
18435
- "data-ohw-bridge": "",
18436
- "data-ohw-item-interaction": "",
18437
- className: "pointer-events-auto fixed",
18438
- style: {
18439
- top: stripRect.top - (mobile ? TOOLBAR_STRIP_GAP_MOBILE : TOOLBAR_STRIP_GAP),
18440
- left: centerX + shift,
18441
- transform: "translate(-50%, -100%)",
18442
- zIndex: 2147483645
18443
- },
18444
- children
18445
- }
18446
- );
18447
- }
18448
18228
  function requestValidateTree(postToParent2, tree) {
18449
18229
  return new Promise((resolve) => {
18450
18230
  const id = `ai-validate-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
@@ -18481,72 +18261,116 @@ function requestAssetPick(postToParent2) {
18481
18261
  postToParent2({ type: "ow:asset-pick", id });
18482
18262
  });
18483
18263
  }
18484
- function ToolbarAction({
18264
+ function Pill({
18485
18265
  label,
18486
18266
  onClick,
18487
- disabled = false,
18488
- active = false,
18489
- children
18267
+ disabled,
18268
+ active
18490
18269
  }) {
18491
- const button = /* @__PURE__ */ jsx20(CustomToolbarButton, { type: "button", "aria-label": label, disabled, active, onClick, className: "size-8", children });
18492
- return /* @__PURE__ */ jsxs11(Tooltip, { children: [
18493
- /* @__PURE__ */ jsx20(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx20("span", { className: "inline-flex", children: button }) : button }),
18494
- /* @__PURE__ */ jsx20(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
18495
- ] });
18496
- }
18497
- function ToolbarSeparator() {
18498
- return /* @__PURE__ */ jsx20("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
18270
+ return /* @__PURE__ */ jsx19(
18271
+ "button",
18272
+ {
18273
+ type: "button",
18274
+ onClick,
18275
+ disabled,
18276
+ style: {
18277
+ height: 28,
18278
+ padding: "0 10px",
18279
+ display: "inline-flex",
18280
+ alignItems: "center",
18281
+ gap: 4,
18282
+ borderRadius: 999,
18283
+ border: "none",
18284
+ cursor: disabled ? "default" : "pointer",
18285
+ background: active ? OHW_BLUE_DARK : "#ffffff",
18286
+ color: active ? "#ffffff" : OHW_BLUE_DARK,
18287
+ opacity: disabled ? 0.4 : 1,
18288
+ fontSize: 12,
18289
+ lineHeight: "16px",
18290
+ fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
18291
+ whiteSpace: "nowrap",
18292
+ flex: "0 0 auto"
18293
+ },
18294
+ children: label
18295
+ }
18296
+ );
18499
18297
  }
18500
- function OptionMenu({
18501
- label,
18502
- value,
18503
- options,
18504
- onChange
18505
- }) {
18506
- const current = options.find((o) => o.value === value) ?? options[0];
18507
- return /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
18508
- /* @__PURE__ */ jsx20("span", { className: "text-xs text-muted-foreground", children: label }),
18509
- /* @__PURE__ */ jsxs11(DropdownMenu, { modal: false, children: [
18510
- /* @__PURE__ */ jsx20(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs11(
18511
- "button",
18512
- {
18513
- type: "button",
18514
- "aria-label": label,
18515
- className: "inline-flex h-8 min-w-[76px] items-center gap-[7px] rounded-[6px] bg-transparent px-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted data-[state=open]:bg-muted",
18516
- children: [
18517
- /* @__PURE__ */ jsx20("span", { className: "flex-1 text-left", children: current.label }),
18518
- /* @__PURE__ */ jsx20(ChevronDown3, { size: 16, style: { pointerEvents: "none" } })
18519
- ]
18520
- }
18521
- ) }),
18522
- /* @__PURE__ */ jsx20(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[132px] min-w-[132px] p-1", children: options.map((option) => {
18523
- const selected = option.value === value;
18524
- return /* @__PURE__ */ jsxs11(
18525
- DropdownMenuItem,
18298
+ function AltInput({ value, onCommit }) {
18299
+ const [draft, setDraft] = useState8(value);
18300
+ useEffect6(() => setDraft(value), [value]);
18301
+ return /* @__PURE__ */ jsxs10(
18302
+ "div",
18303
+ {
18304
+ style: {
18305
+ display: "flex",
18306
+ alignItems: "center",
18307
+ gap: 6,
18308
+ height: 28,
18309
+ padding: "0 12px",
18310
+ borderRadius: 999,
18311
+ background: "#ffffff",
18312
+ width: "100%",
18313
+ maxWidth: 260,
18314
+ boxSizing: "border-box"
18315
+ },
18316
+ children: [
18317
+ /* @__PURE__ */ jsx19(
18318
+ "span",
18526
18319
  {
18527
- role: "menuitemradio",
18528
- "aria-checked": selected,
18529
- onSelect: () => onChange(option.value),
18530
- className: cn("grid grid-cols-[1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
18531
- children: [
18532
- /* @__PURE__ */ jsx20("span", { children: option.label }),
18533
- selected && /* @__PURE__ */ jsx20(Check2, { size: 16, className: "text-bridge-primary" })
18534
- ]
18535
- },
18536
- option.value
18537
- );
18538
- }) })
18539
- ] })
18540
- ] });
18320
+ style: {
18321
+ flex: "0 0 auto",
18322
+ color: OHW_BLUE_DARK,
18323
+ fontSize: 10,
18324
+ fontWeight: 700,
18325
+ textTransform: "uppercase",
18326
+ letterSpacing: 0.4
18327
+ },
18328
+ children: "Alt"
18329
+ }
18330
+ ),
18331
+ /* @__PURE__ */ jsx19(
18332
+ "input",
18333
+ {
18334
+ type: "text",
18335
+ value: draft,
18336
+ onChange: (e) => setDraft(e.target.value),
18337
+ onBlur: () => {
18338
+ if (draft !== value) onCommit(draft);
18339
+ },
18340
+ onKeyDown: (e) => {
18341
+ if (e.key === "Enter") e.currentTarget.blur();
18342
+ if (e.key === "Escape") {
18343
+ setDraft(value);
18344
+ e.currentTarget.blur();
18345
+ }
18346
+ },
18347
+ placeholder: "Describe this image",
18348
+ "aria-label": "Image alt text",
18349
+ style: {
18350
+ flex: 1,
18351
+ minWidth: 0,
18352
+ border: "none",
18353
+ outline: "none",
18354
+ background: "transparent",
18355
+ fontSize: 12,
18356
+ lineHeight: "16px",
18357
+ fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
18358
+ color: "#1f2937"
18359
+ }
18360
+ }
18361
+ )
18362
+ ]
18363
+ }
18364
+ );
18541
18365
  }
18542
18366
  var VARIANTS = [
18543
18367
  { value: "logos", label: "Logos" },
18544
18368
  { value: "reel", label: "Reel" }
18545
18369
  ];
18546
18370
  var ALIGNS = [
18547
- { value: "left", label: "Align left", Icon: AlignLeft },
18548
- { value: "center", label: "Align center", Icon: AlignCenter },
18549
- { value: "right", label: "Align right", Icon: AlignRight }
18371
+ { value: "left", label: "Left" },
18372
+ { value: "center", label: "Center" },
18373
+ { value: "right", label: "Right" }
18550
18374
  ];
18551
18375
  var HOVERS = [
18552
18376
  { value: "none", label: "None" },
@@ -18554,104 +18378,104 @@ var HOVERS = [
18554
18378
  { value: "zoom", label: "Zoom" },
18555
18379
  { value: "fade", label: "Fade" }
18556
18380
  ];
18381
+ var TREATMENTS = [
18382
+ { value: "color", label: "Color" },
18383
+ { value: "grayscale", label: "Grayscale" }
18384
+ ];
18557
18385
  var HTTP_URL_RE = /^https?:\/\/\S+$/i;
18558
- function LinkModal({
18559
- href,
18560
- linkTarget,
18561
- onClose,
18562
- onSave
18563
- }) {
18564
- const [draft, setDraft] = useState8(href);
18565
- const [newTab, setNewTab] = useState8(linkTarget !== "same-tab");
18386
+ function LinkInput({ value, onCommit }) {
18387
+ const [draft, setDraft] = useState8(value);
18566
18388
  const [invalid, setInvalid] = useState8(false);
18567
- const save = () => {
18389
+ useEffect6(() => {
18390
+ setDraft(value);
18391
+ setInvalid(false);
18392
+ }, [value]);
18393
+ const commit = () => {
18568
18394
  const next = draft.trim();
18569
- if (next && !HTTP_URL_RE.test(next)) {
18570
- setInvalid(true);
18571
- return;
18572
- }
18573
- onSave(next, newTab ? "new-tab" : "same-tab");
18574
- onClose();
18395
+ if (next === value) return setInvalid(false);
18396
+ if (next && !HTTP_URL_RE.test(next)) return setInvalid(true);
18397
+ setInvalid(false);
18398
+ onCommit(next);
18575
18399
  };
18576
- return /* @__PURE__ */ jsx20(Dialog2, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxs11(DialogContent, { "data-ohw-link-modal-root": "", className: "max-w-[400px] gap-4 p-5", children: [
18577
- /* @__PURE__ */ jsx20(DialogHeader, { children: /* @__PURE__ */ jsx20(DialogTitle, { className: "text-base", children: "Image link" }) }),
18578
- /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-3", children: [
18579
- /* @__PURE__ */ jsx20(
18580
- "input",
18581
- {
18582
- autoFocus: true,
18583
- type: "text",
18584
- inputMode: "url",
18585
- value: draft,
18586
- onChange: (e) => {
18587
- setDraft(e.target.value);
18588
- setInvalid(false);
18589
- },
18590
- onKeyDown: (e) => {
18591
- if (e.key === "Enter") save();
18592
- },
18593
- placeholder: "https://example.com",
18594
- "aria-label": "Image link URL",
18595
- "aria-invalid": invalid,
18596
- className: cn(
18597
- "h-9 w-full rounded-[6px] border border-border bg-background px-3 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/70 focus:border-bridge-primary",
18598
- invalid && "border-destructive focus:border-destructive"
18599
- )
18600
- }
18601
- ),
18602
- invalid && /* @__PURE__ */ jsx20("p", { className: "text-xs text-destructive", children: "Enter a full URL starting with http:// or https://" }),
18603
- /* @__PURE__ */ jsxs11("label", { className: "flex items-center gap-2 text-[13px] text-foreground", children: [
18604
- /* @__PURE__ */ jsx20("input", { type: "checkbox", checked: newTab, onChange: (e) => setNewTab(e.target.checked) }),
18605
- "Open in new tab"
18606
- ] })
18607
- ] }),
18608
- /* @__PURE__ */ jsxs11(DialogFooter, { children: [
18609
- href && /* @__PURE__ */ jsx20(
18610
- "button",
18611
- {
18612
- type: "button",
18613
- onClick: () => {
18614
- onSave("", "new-tab");
18615
- onClose();
18616
- },
18617
- className: "mr-auto rounded-[6px] px-3 py-2 text-[13px] font-medium text-destructive transition-colors hover:bg-muted",
18618
- children: "Remove link"
18619
- }
18620
- ),
18621
- /* @__PURE__ */ jsx20(
18622
- "button",
18623
- {
18624
- type: "button",
18625
- onClick: onClose,
18626
- className: "rounded-[6px] px-3 py-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted",
18627
- children: "Cancel"
18628
- }
18629
- ),
18630
- /* @__PURE__ */ jsx20(
18631
- "button",
18632
- {
18633
- type: "button",
18634
- onClick: save,
18635
- className: "rounded-[6px] bg-bridge-primary px-3 py-2 text-[13px] font-medium text-primary-foreground transition-opacity hover:opacity-90",
18636
- children: "Save"
18637
- }
18638
- )
18639
- ] })
18640
- ] }) });
18400
+ return /* @__PURE__ */ jsxs10(
18401
+ "div",
18402
+ {
18403
+ style: {
18404
+ display: "flex",
18405
+ alignItems: "center",
18406
+ gap: 6,
18407
+ height: 28,
18408
+ padding: "0 12px",
18409
+ borderRadius: 999,
18410
+ background: "#ffffff",
18411
+ width: "100%",
18412
+ maxWidth: 260,
18413
+ boxSizing: "border-box",
18414
+ boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
18415
+ },
18416
+ children: [
18417
+ /* @__PURE__ */ jsx19(
18418
+ "span",
18419
+ {
18420
+ style: {
18421
+ flex: "0 0 auto",
18422
+ color: OHW_BLUE_DARK,
18423
+ fontSize: 10,
18424
+ fontWeight: 700,
18425
+ textTransform: "uppercase",
18426
+ letterSpacing: 0.4
18427
+ },
18428
+ children: "Link"
18429
+ }
18430
+ ),
18431
+ /* @__PURE__ */ jsx19(
18432
+ "input",
18433
+ {
18434
+ type: "text",
18435
+ inputMode: "url",
18436
+ value: draft,
18437
+ onChange: (e) => setDraft(e.target.value),
18438
+ onBlur: commit,
18439
+ onKeyDown: (e) => {
18440
+ if (e.key === "Enter") e.currentTarget.blur();
18441
+ if (e.key === "Escape") {
18442
+ setDraft(value);
18443
+ setInvalid(false);
18444
+ e.currentTarget.blur();
18445
+ }
18446
+ },
18447
+ placeholder: "https://example.com",
18448
+ "aria-label": "Image link URL",
18449
+ "aria-invalid": invalid,
18450
+ style: {
18451
+ flex: 1,
18452
+ minWidth: 0,
18453
+ border: "none",
18454
+ outline: "none",
18455
+ background: "transparent",
18456
+ fontSize: 12,
18457
+ lineHeight: "16px",
18458
+ fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
18459
+ color: "#1f2937"
18460
+ }
18461
+ }
18462
+ )
18463
+ ]
18464
+ }
18465
+ );
18641
18466
  }
18642
18467
  function MediaStripToolbar({
18643
18468
  entry,
18644
18469
  index,
18645
18470
  pending,
18646
18471
  error,
18647
- itemEditOn,
18648
- onToggleItemEdit,
18649
18472
  onSetVariant,
18650
18473
  onSetAlign,
18651
18474
  onSetHover,
18652
18475
  onSetTreatment,
18653
18476
  onResize,
18654
- onOpenLink,
18477
+ onSetAlt,
18478
+ onSetLink,
18655
18479
  onAddItem,
18656
18480
  onRemoveItem,
18657
18481
  onChangeImage,
@@ -18660,102 +18484,81 @@ function MediaStripToolbar({
18660
18484
  }) {
18661
18485
  const items = mediaStripItems(entry.tree);
18662
18486
  const itemCount = items.length;
18487
+ const currentAlt = items[index]?.alt ?? "";
18488
+ const currentHref = items[index]?.href ?? "";
18489
+ const currentTarget = items[index]?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
18663
18490
  const slots = findMediaStripSlots(entry.tree);
18664
18491
  const variant = slots?.variant === "reel" ? "reel" : "logos";
18665
18492
  const align = slots?.align === "left" || slots?.align === "right" ? slots.align : "center";
18666
18493
  const hover = slots?.hover === "none" || slots?.hover === "lift" || slots?.hover === "zoom" || slots?.hover === "fade" ? slots.hover : "lift";
18667
18494
  const treatment = slots?.treatment === "color" || slots?.treatment === "grayscale" ? slots.treatment : variant === "logos" ? "grayscale" : "color";
18668
18495
  const sizeValue = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
18669
- const mobile = window.innerWidth <= 480;
18670
- const gatedLabel = (label) => itemEditOn ? label : "Turn on the star to edit this image";
18671
- return /* @__PURE__ */ jsx20(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs11(
18496
+ const isMobile = window.innerWidth <= 480;
18497
+ const rowStyle = isMobile ? {
18498
+ display: "flex",
18499
+ gap: 6,
18500
+ flexWrap: "nowrap",
18501
+ justifyContent: "center",
18502
+ overflowX: "auto",
18503
+ WebkitOverflowScrolling: "touch",
18504
+ width: "100%",
18505
+ scrollbarWidth: "none"
18506
+ } : { display: "flex", gap: 6, flexWrap: "nowrap", justifyContent: "center" };
18507
+ return /* @__PURE__ */ jsxs10(
18672
18508
  "div",
18673
18509
  {
18674
18510
  "data-ohw-bridge": "",
18675
18511
  "data-ohw-toolbar": "",
18676
18512
  onMouseDown: (e) => e.stopPropagation(),
18677
- className: cn("flex flex-col items-center gap-1.5 font-sans", pending && "pointer-events-none opacity-60"),
18678
- style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
18513
+ style: {
18514
+ display: "flex",
18515
+ flexDirection: "column",
18516
+ gap: 6,
18517
+ alignItems: "center",
18518
+ background: OHW_BLUE,
18519
+ padding: 8,
18520
+ borderRadius: 12,
18521
+ boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
18522
+ pointerEvents: pending ? "none" : "auto",
18523
+ opacity: pending ? 0.6 : 1,
18524
+ maxWidth: isMobile ? "calc(100vw - 24px)" : "none"
18525
+ },
18679
18526
  children: [
18680
- /* @__PURE__ */ jsxs11(
18681
- "div",
18682
- {
18683
- className: cn(
18684
- "flex items-center gap-1 rounded-[10px] border border-border bg-background p-1 whitespace-nowrap",
18685
- "shadow-[0px_10px_15px_-3px_rgba(0,0,0,0.1),0px_4px_6px_-4px_rgba(0,0,0,0.1)]",
18686
- mobile ? "flex-wrap justify-center" : "flex-nowrap"
18687
- ),
18688
- children: [
18689
- /* @__PURE__ */ jsxs11(Tooltip, { children: [
18690
- /* @__PURE__ */ jsx20(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx20(
18691
- CustomToolbarButton,
18692
- {
18693
- type: "button",
18694
- "aria-label": itemEditOn ? "Done editing this image" : "Edit this image",
18695
- "aria-pressed": itemEditOn,
18696
- onClick: onToggleItemEdit,
18697
- className: "group size-8",
18698
- children: /* @__PURE__ */ jsx20(
18699
- Star,
18700
- {
18701
- size: 16,
18702
- fill: "currentColor",
18703
- strokeWidth: 0,
18704
- className: cn(
18705
- "transition-colors",
18706
- itemEditOn ? "text-[#f59e0b] group-hover:text-[#d97706]" : "text-[#d6d3d1] group-hover:text-[#fbbf24]"
18707
- ),
18708
- style: { pointerEvents: "none" }
18709
- }
18710
- )
18711
- }
18712
- ) }),
18713
- /* @__PURE__ */ jsx20(TooltipContent, { side: "bottom", sideOffset: 8, children: itemEditOn ? "Done editing this image" : "Edit this image" })
18714
- ] }),
18715
- /* @__PURE__ */ jsx20(ToolbarSeparator, {}),
18716
- /* @__PURE__ */ jsx20(ToolbarAction, { label: gatedLabel("Change image"), onClick: onChangeImage, disabled: !itemEditOn, children: /* @__PURE__ */ jsx20(ImageIcon2, { size: 16, style: { pointerEvents: "none" } }) }),
18717
- /* @__PURE__ */ jsx20(ToolbarAction, { label: gatedLabel("Link"), onClick: onOpenLink, disabled: !itemEditOn, children: /* @__PURE__ */ jsx20(LinkIcon, { size: 16, style: { pointerEvents: "none" } }) }),
18718
- /* @__PURE__ */ jsx20(ToolbarAction, { label: gatedLabel("Move left"), onClick: onMoveLeft, disabled: !itemEditOn || index <= 0, children: /* @__PURE__ */ jsx20(ArrowLeft2, { size: 16, style: { pointerEvents: "none" } }) }),
18719
- /* @__PURE__ */ jsx20(
18720
- ToolbarAction,
18721
- {
18722
- label: gatedLabel("Move right"),
18723
- onClick: onMoveRight,
18724
- disabled: !itemEditOn || index >= itemCount - 1,
18725
- children: /* @__PURE__ */ jsx20(ArrowRight2, { size: 16, style: { pointerEvents: "none" } })
18726
- }
18727
- ),
18728
- /* @__PURE__ */ jsx20(ToolbarAction, { label: gatedLabel("Remove image"), onClick: onRemoveItem, disabled: !itemEditOn || itemCount <= 1, children: /* @__PURE__ */ jsx20(ImageMinus, { size: 16, style: { pointerEvents: "none" } }) }),
18729
- /* @__PURE__ */ jsx20(ToolbarSeparator, {}),
18730
- /* @__PURE__ */ jsx20(OptionMenu, { label: "Layout", value: variant, options: VARIANTS, onChange: onSetVariant }),
18731
- /* @__PURE__ */ jsx20(OptionMenu, { label: "Hover", value: hover, options: HOVERS, onChange: onSetHover }),
18732
- /* @__PURE__ */ jsx20(
18733
- ToolbarAction,
18734
- {
18735
- label: treatment === "grayscale" ? "Show in color" : "Show grayscale",
18736
- active: treatment === "grayscale",
18737
- onClick: () => onSetTreatment(treatment === "grayscale" ? "color" : "grayscale"),
18738
- children: /* @__PURE__ */ jsx20(Palette, { size: 16, style: { pointerEvents: "none" } })
18739
- }
18740
- ),
18741
- /* @__PURE__ */ jsx20(ToolbarSeparator, {}),
18742
- ALIGNS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx20(ToolbarAction, { label, active: align === value, onClick: () => onSetAlign(value), children: /* @__PURE__ */ jsx20(Icon, { size: 16, style: { pointerEvents: "none" } }) }, value)),
18743
- /* @__PURE__ */ jsx20(ToolbarSeparator, {}),
18744
- /* @__PURE__ */ jsx20(ToolbarAction, { label: "Smaller", onClick: () => onResize(-8), children: /* @__PURE__ */ jsx20(Minus, { size: 16, style: { pointerEvents: "none" } }) }),
18745
- /* @__PURE__ */ jsxs11("span", { className: "min-w-[40px] text-center text-xs tabular-nums text-muted-foreground", children: [
18746
- sizeValue,
18747
- "px"
18748
- ] }),
18749
- /* @__PURE__ */ jsx20(ToolbarAction, { label: "Larger", onClick: () => onResize(8), children: /* @__PURE__ */ jsx20(Plus2, { size: 16, style: { pointerEvents: "none" } }) }),
18750
- /* @__PURE__ */ jsx20(ToolbarSeparator, {}),
18751
- /* @__PURE__ */ jsx20(ToolbarAction, { label: "Add image", onClick: onAddItem, children: /* @__PURE__ */ jsx20(ImagePlus, { size: 16, style: { pointerEvents: "none" } }) })
18752
- ]
18753
- }
18754
- ),
18755
- error && /* @__PURE__ */ jsx20("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
18527
+ /* @__PURE__ */ jsxs10("div", { style: rowStyle, children: [
18528
+ VARIANTS.map((v) => /* @__PURE__ */ jsx19(Pill, { label: v.label, active: variant === v.value, onClick: () => onSetVariant(v.value) }, v.value)),
18529
+ ALIGNS.map((a) => /* @__PURE__ */ jsx19(Pill, { label: a.label, active: align === a.value, onClick: () => onSetAlign(a.value) }, a.value))
18530
+ ] }),
18531
+ /* @__PURE__ */ jsxs10("div", { style: rowStyle, children: [
18532
+ HOVERS.map((h) => /* @__PURE__ */ jsx19(Pill, { label: h.label, active: hover === h.value, onClick: () => onSetHover(h.value) }, h.value)),
18533
+ TREATMENTS.map((t) => /* @__PURE__ */ jsx19(Pill, { label: t.label, active: treatment === t.value, onClick: () => onSetTreatment(t.value) }, t.value))
18534
+ ] }),
18535
+ /* @__PURE__ */ jsxs10("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
18536
+ /* @__PURE__ */ jsx19(Pill, { label: "\u2212", onClick: () => onResize(-8) }),
18537
+ /* @__PURE__ */ jsxs10("span", { style: { color: "#ffffff", fontSize: 12, minWidth: 34, textAlign: "center" }, children: [
18538
+ sizeValue,
18539
+ "px"
18540
+ ] }),
18541
+ /* @__PURE__ */ jsx19(Pill, { label: "+", onClick: () => onResize(8) })
18542
+ ] }),
18543
+ /* @__PURE__ */ jsx19("div", { style: { display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ jsx19(AltInput, { value: currentAlt, onCommit: onSetAlt }) }),
18544
+ /* @__PURE__ */ jsx19("div", { style: { display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ jsx19(LinkInput, { value: currentHref, onCommit: (href) => onSetLink(href, currentTarget) }) }),
18545
+ currentHref && /* @__PURE__ */ jsxs10("div", { style: rowStyle, children: [
18546
+ /* @__PURE__ */ jsx19(Pill, { label: "New tab", active: currentTarget === "new-tab", onClick: () => onSetLink(currentHref, "new-tab") }),
18547
+ /* @__PURE__ */ jsx19(Pill, { label: "Same tab", active: currentTarget === "same-tab", onClick: () => onSetLink(currentHref, "same-tab") })
18548
+ ] }),
18549
+ /* @__PURE__ */ jsxs10("div", { style: rowStyle, children: [
18550
+ /* @__PURE__ */ jsx19(Pill, { label: "Change Image", onClick: onChangeImage }),
18551
+ /* @__PURE__ */ jsx19(Pill, { label: "+ Item", onClick: onAddItem }),
18552
+ /* @__PURE__ */ jsx19(Pill, { label: "\u2212 Item", onClick: onRemoveItem, disabled: itemCount <= 1 })
18553
+ ] }),
18554
+ /* @__PURE__ */ jsxs10("div", { style: rowStyle, children: [
18555
+ /* @__PURE__ */ jsx19(Pill, { label: "\u2190 Move", onClick: onMoveLeft, disabled: index <= 0 }),
18556
+ /* @__PURE__ */ jsx19(Pill, { label: "\u2192 Move", onClick: onMoveRight, disabled: index >= itemCount - 1 })
18557
+ ] }),
18558
+ error && /* @__PURE__ */ jsx19("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
18756
18559
  ]
18757
18560
  }
18758
- ) });
18561
+ );
18759
18562
  }
18760
18563
  function findMediaStripSlots(tree) {
18761
18564
  const stack = tree.rows.flatMap((row) => row.blocks);
@@ -18774,23 +18577,31 @@ function AiMediaStripOverlay({
18774
18577
  }) {
18775
18578
  const [hover, setHover] = useState8(null);
18776
18579
  const [active, setActive] = useState8(null);
18777
- const [itemEditOn, setItemEditOn] = useState8(false);
18778
- const [linkOpen, setLinkOpen] = useState8(false);
18779
18580
  const [pending, setPending] = useState8(false);
18780
18581
  const [error, setError] = useState8(null);
18781
18582
  const activeRef = useRef5(null);
18782
18583
  activeRef.current = active;
18783
- const linkOpenRef = useRef5(false);
18784
- linkOpenRef.current = linkOpen;
18785
18584
  useEffect6(() => {
18786
18585
  const onMove = (e) => {
18787
- const ref = itemRefFromTarget(e.target);
18788
18586
  const t = e.target;
18789
- const overEditable = Boolean(t?.closest?.("[data-ohw-editable]"));
18790
- setHover((prev) => {
18791
- const next = ref && !overEditable ? ref : null;
18792
- return sameRef(prev, next) ? prev : next;
18793
- });
18587
+ if (!(t instanceof HTMLElement)) return;
18588
+ if (t.closest("[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-link-modal-root], [data-ohw-section-picker], [data-ohw-ai-review]")) {
18589
+ return;
18590
+ }
18591
+ const itemEl = t.closest("[data-ohw-media-strip-item]");
18592
+ if (!itemEl) {
18593
+ setHover(null);
18594
+ return;
18595
+ }
18596
+ const sectionEl = itemEl.closest("[data-ohw-section]");
18597
+ const unit = sectionEl ? movableUnit(sectionEl) : null;
18598
+ const sectionId = unit ? instanceIdOf(unit) || null : null;
18599
+ const index = Number(itemEl.dataset.ohwMediaStripIndex);
18600
+ if (!sectionId || Number.isNaN(index)) {
18601
+ setHover(null);
18602
+ return;
18603
+ }
18604
+ setHover({ sectionId, index });
18794
18605
  };
18795
18606
  const onLeave = () => setHover(null);
18796
18607
  document.addEventListener("mousemove", onMove, { passive: true });
@@ -18802,25 +18613,23 @@ function AiMediaStripOverlay({
18802
18613
  }, []);
18803
18614
  useEffect6(() => {
18804
18615
  const onClick = (e) => {
18616
+ const current = activeRef.current;
18617
+ if (!current) return;
18805
18618
  const t = e.target;
18806
- if (!(t instanceof Element)) return;
18807
- if (t.closest(CHROME_SELECTOR)) return;
18808
- const ref = itemRefFromTarget(t);
18809
- if (sameRef(activeRef.current, ref)) return;
18810
- if (ref) clearInteractionChromeRef.current();
18811
- setItemEditOn(false);
18619
+ if (!(t instanceof HTMLElement)) return;
18620
+ if (t.closest("[data-ohw-item-interaction]")) return;
18621
+ const itemEl = findMediaStripItemElement(current.sectionId, current.index);
18622
+ if (itemEl && itemEl.contains(t)) return;
18623
+ setActive(null);
18812
18624
  setError(null);
18813
- setActive(ref);
18814
18625
  };
18815
18626
  document.addEventListener("click", onClick, true);
18816
18627
  return () => document.removeEventListener("click", onClick, true);
18817
- }, [clearInteractionChromeRef]);
18628
+ }, []);
18818
18629
  useEffect6(() => {
18819
18630
  const onBlur = () => {
18820
18631
  if (!activeRef.current) return;
18821
18632
  setActive(null);
18822
- setItemEditOn(false);
18823
- setLinkOpen(false);
18824
18633
  setError(null);
18825
18634
  };
18826
18635
  window.addEventListener("blur", onBlur);
@@ -18830,10 +18639,7 @@ function AiMediaStripOverlay({
18830
18639
  const onKeyDown = (e) => {
18831
18640
  if (e.key !== "Escape") return;
18832
18641
  if (!activeRef.current) return;
18833
- if (linkOpenRef.current) return;
18834
- if (document.querySelector('[data-ohw-more-menu][data-state="open"]')) return;
18835
18642
  setActive(null);
18836
- setItemEditOn(false);
18837
18643
  setError(null);
18838
18644
  };
18839
18645
  document.addEventListener("keydown", onKeyDown);
@@ -18867,133 +18673,137 @@ function AiMediaStripOverlay({
18867
18673
  tree: nextTree,
18868
18674
  label: entry.label,
18869
18675
  media: extraMedia ? { ...entry.media, ...extraMedia } : entry.media,
18870
- ...entry.brand ? { brand: entry.brand } : {},
18871
- // The user is already looking at the strip they just edited — recentering the viewport
18872
- // on every edit reads as the section jumping around.
18873
- skipScrollIntoView: true
18676
+ ...entry.brand ? { brand: entry.brand } : {}
18874
18677
  });
18875
18678
  return true;
18876
18679
  },
18877
18680
  [findEntry, postToParent2, applyTreeLocalRef]
18878
18681
  );
18879
18682
  const activeEntry = active ? findEntry(active.sectionId) : null;
18683
+ const hoverHandleRect = useLiveItemRect(!active && hover ? hover : null);
18880
18684
  const activeItemRect = useLiveItemRect(active);
18881
- const activeStripRect = useLiveItemRect(active, true);
18882
- const hoverRect = useLiveItemRect(hover && !sameRef(hover, active) ? hover : null);
18883
- const activeItems = activeEntry ? mediaStripItems(activeEntry.tree) : [];
18884
- const activeItem = active ? activeItems[active.index] : void 0;
18885
- const activeHref = activeItem?.href ?? "";
18886
- const activeTarget = activeItem?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
18887
- return /* @__PURE__ */ jsxs11(Fragment6, { children: [
18888
- hoverRect && /* @__PURE__ */ jsx20(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
18889
- activeItemRect && activeStripRect && active && activeEntry && /* @__PURE__ */ jsxs11(Fragment6, { children: [
18890
- /* @__PURE__ */ jsx20(ItemInteractionLayer, { rect: activeItemRect, state: "active-top" }),
18891
- /* @__PURE__ */ jsx20(StripToolbarSlot, { stripRect: activeStripRect, children: /* @__PURE__ */ jsx20(
18892
- MediaStripToolbar,
18893
- {
18894
- entry: activeEntry,
18895
- index: active.index,
18896
- pending,
18897
- error,
18898
- itemEditOn,
18899
- onToggleItemEdit: () => setItemEditOn((on) => !on),
18900
- onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
18901
- onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
18902
- onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
18903
- onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
18904
- onResize: (delta) => {
18905
- const slots = findMediaStripSlots(activeEntry.tree);
18906
- const variant = slots?.variant === "reel" ? "reel" : "logos";
18907
- const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
18908
- void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
18909
- },
18910
- onOpenLink: () => setLinkOpen(true),
18911
- onAddItem: () => {
18912
- void requestAssetPick(postToParent2).then((picked) => {
18913
- if (!picked) return;
18914
- const item = { assetId: picked.assetId, alt: "Logo" };
18685
+ const TOOLBAR_APPROX_H = 170;
18686
+ const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
18687
+ return /* @__PURE__ */ jsxs10(Fragment6, { children: [
18688
+ hoverHandleRect && hover && /* @__PURE__ */ jsx19(
18689
+ "button",
18690
+ {
18691
+ type: "button",
18692
+ "data-ohw-toolbar": "",
18693
+ onClick: () => {
18694
+ clearInteractionChromeRef.current();
18695
+ setActive(hover);
18696
+ },
18697
+ "aria-label": "Configure media item",
18698
+ style: {
18699
+ position: "fixed",
18700
+ top: hoverHandleRect.top + 8,
18701
+ left: hoverHandleRect.left + hoverHandleRect.width - 36,
18702
+ width: 28,
18703
+ height: 28,
18704
+ borderRadius: 8,
18705
+ border: `1.5px dashed ${PRIMARY3}`,
18706
+ background: "#ffffff",
18707
+ color: PRIMARY3,
18708
+ display: "flex",
18709
+ alignItems: "center",
18710
+ justifyContent: "center",
18711
+ cursor: "pointer",
18712
+ zIndex: 2147483643,
18713
+ fontSize: 14,
18714
+ fontWeight: 700
18715
+ },
18716
+ children: /* @__PURE__ */ jsx19(Star, { size: 14, style: { pointerEvents: "none" } })
18717
+ }
18718
+ ),
18719
+ activeItemRect && active && activeEntry && /* @__PURE__ */ jsx19(
18720
+ ItemInteractionLayer,
18721
+ {
18722
+ rect: activeItemRect,
18723
+ state: toolbarState,
18724
+ toolbar: /* @__PURE__ */ jsx19(
18725
+ MediaStripToolbar,
18726
+ {
18727
+ entry: activeEntry,
18728
+ index: active.index,
18729
+ pending,
18730
+ error,
18731
+ onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
18732
+ onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
18733
+ onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
18734
+ onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
18735
+ onResize: (delta) => {
18736
+ const slots = findMediaStripSlots(activeEntry.tree);
18737
+ const variant = slots?.variant === "reel" ? "reel" : "logos";
18738
+ const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
18739
+ void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
18740
+ },
18741
+ onSetAlt: (alt) => {
18742
+ void runMutation(active.sectionId, (tree) => setMediaStripItemAlt(tree, active.index, alt));
18743
+ },
18744
+ onSetLink: (href, linkTarget) => {
18915
18745
  void runMutation(
18916
18746
  active.sectionId,
18917
- (tree) => addMediaStripItem(tree, item, active.index),
18918
- { [picked.assetId]: picked.url }
18919
- ).then((applied) => {
18920
- if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
18747
+ (tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
18748
+ );
18749
+ },
18750
+ onAddItem: () => {
18751
+ void requestAssetPick(postToParent2).then((picked) => {
18752
+ if (!picked) return;
18753
+ const item = { assetId: picked.assetId, alt: "Logo" };
18754
+ void runMutation(
18755
+ active.sectionId,
18756
+ (tree) => addMediaStripItem(tree, item, active.index),
18757
+ { [picked.assetId]: picked.url }
18758
+ ).then((applied) => {
18759
+ if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
18760
+ });
18921
18761
  });
18922
- });
18923
- },
18924
- onChangeImage: () => {
18925
- void requestAssetPick(postToParent2).then((picked) => {
18926
- if (!picked) return;
18927
- void runMutation(
18928
- active.sectionId,
18929
- (tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
18930
- { [picked.assetId]: picked.url }
18762
+ },
18763
+ onChangeImage: () => {
18764
+ void requestAssetPick(postToParent2).then((picked) => {
18765
+ if (!picked) return;
18766
+ void runMutation(
18767
+ active.sectionId,
18768
+ (tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
18769
+ { [picked.assetId]: picked.url }
18770
+ );
18771
+ });
18772
+ },
18773
+ onRemoveItem: () => {
18774
+ void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
18775
+ (applied) => {
18776
+ if (applied) setActive(null);
18777
+ }
18931
18778
  );
18932
- });
18933
- },
18934
- onRemoveItem: () => {
18935
- void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
18936
- (applied) => {
18937
- if (applied) setActive(null);
18938
- }
18939
- );
18940
- },
18941
- onMoveLeft: () => {
18942
- void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
18943
- (applied) => {
18944
- if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
18945
- }
18946
- );
18947
- },
18948
- onMoveRight: () => {
18949
- void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
18950
- (applied) => {
18951
- if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
18952
- }
18953
- );
18954
- }
18955
- }
18956
- ) }),
18957
- /* @__PURE__ */ jsx20(
18958
- "div",
18959
- {
18960
- "data-ohw-bridge": "",
18961
- "data-ohw-item-interaction": "",
18962
- "aria-hidden": true,
18963
- className: "pointer-events-none fixed rounded-[4px] px-[7px] py-[3px] font-sans text-[11px] font-medium leading-none text-primary-foreground whitespace-nowrap",
18964
- style: {
18965
- top: activeItemRect.top + activeItemRect.height + 10,
18966
- left: activeItemRect.left - 5,
18967
- background: PRIMARY3,
18968
- zIndex: 2147483644
18969
- },
18970
- children: "Media item"
18971
- }
18972
- ),
18973
- linkOpen && /* @__PURE__ */ jsx20(
18974
- LinkModal,
18975
- {
18976
- href: activeHref,
18977
- linkTarget: activeTarget,
18978
- onClose: () => setLinkOpen(false),
18979
- onSave: (href, linkTarget) => {
18980
- void runMutation(
18981
- active.sectionId,
18982
- (tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
18983
- );
18779
+ },
18780
+ onMoveLeft: () => {
18781
+ void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
18782
+ (applied) => {
18783
+ if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
18784
+ }
18785
+ );
18786
+ },
18787
+ onMoveRight: () => {
18788
+ void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
18789
+ (applied) => {
18790
+ if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
18791
+ }
18792
+ );
18793
+ }
18984
18794
  }
18985
- }
18986
- )
18987
- ] })
18795
+ )
18796
+ }
18797
+ )
18988
18798
  ] });
18989
18799
  }
18990
18800
 
18991
18801
  // src/ui/ai-section/AiPricingCardOverlay.tsx
18992
- import { useCallback as useCallback4, useEffect as useEffect7, useLayoutEffect as useLayoutEffect5, useRef as useRef6, useState as useState9 } from "react";
18993
- import { Check as Check3, ChevronDown as ChevronDown4, Minus as Minus2, Plus as Plus3, Star as Star2 } from "lucide-react";
18994
- import { Fragment as Fragment7, jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
18802
+ import { useCallback as useCallback4, useEffect as useEffect7, useLayoutEffect as useLayoutEffect4, useRef as useRef6, useState as useState9 } from "react";
18803
+ import { Check as Check2, ChevronDown as ChevronDown3, Minus, Plus as Plus2, Star as Star2 } from "lucide-react";
18804
+ import { Fragment as Fragment7, jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
18995
18805
  var PRIMARY4 = "var(--ohw-primary, #0885FE)";
18996
- var CHROME_SELECTOR2 = "[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-link-modal-root], [data-ohw-section-picker], [data-ohw-ai-review], [data-ohw-more-menu]";
18806
+ var CHROME_SELECTOR = "[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-link-modal-root], [data-ohw-section-picker], [data-ohw-ai-review], [data-ohw-more-menu]";
18997
18807
  function findPricingCardElement(sectionId, index) {
18998
18808
  const sectionEl = findByInstanceId(sectionId);
18999
18809
  if (!sectionEl) return null;
@@ -19005,7 +18815,7 @@ function findPricingCardElement(sectionId, index) {
19005
18815
  }
19006
18816
  function cardRefFromTarget(target) {
19007
18817
  if (!(target instanceof Element)) return null;
19008
- if (target.closest(CHROME_SELECTOR2)) return null;
18818
+ if (target.closest(CHROME_SELECTOR)) return null;
19009
18819
  const cardEl = target.closest("[data-ohw-pricing-card]");
19010
18820
  if (!cardEl) return null;
19011
18821
  const sectionEl = cardEl.closest("[data-ohw-section]");
@@ -19015,21 +18825,21 @@ function cardRefFromTarget(target) {
19015
18825
  if (!sectionId || Number.isNaN(index)) return null;
19016
18826
  return { sectionId, index };
19017
18827
  }
19018
- function sameRef2(a, b) {
18828
+ function sameRef(a, b) {
19019
18829
  return a?.sectionId === b?.sectionId && a?.index === b?.index;
19020
18830
  }
19021
- function rectOf2(el) {
18831
+ function rectOf(el) {
19022
18832
  if (!el) return null;
19023
18833
  const r2 = el.getBoundingClientRect();
19024
18834
  if (r2.width <= 0 || r2.height <= 0) return null;
19025
18835
  return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
19026
18836
  }
19027
18837
  function readRect3(ref) {
19028
- return rectOf2(ref && findPricingCardElement(ref.sectionId, ref.index));
18838
+ return rectOf(ref && findPricingCardElement(ref.sectionId, ref.index));
19029
18839
  }
19030
18840
  function readGridRect(ref) {
19031
18841
  const card = ref && findPricingCardElement(ref.sectionId, ref.index);
19032
- return rectOf2(card?.closest("[data-ohw-pricing-collection]") ?? card);
18842
+ return rectOf(card?.closest("[data-ohw-pricing-collection]") ?? card);
19033
18843
  }
19034
18844
  function useLiveCardRect(ref, grid = false) {
19035
18845
  const [rect, setRect] = useState9(null);
@@ -19059,19 +18869,19 @@ function useLiveCardRect(ref, grid = false) {
19059
18869
  }
19060
18870
  var TOOLBAR_GRID_GAP = 52;
19061
18871
  var TOOLBAR_GRID_GAP_MOBILE = 42;
19062
- var TOOLBAR_EDGE_MARGIN3 = 4;
18872
+ var TOOLBAR_EDGE_MARGIN2 = 4;
19063
18873
  function GridToolbarSlot({ gridRect, children }) {
19064
18874
  const slotRef = useRef6(null);
19065
18875
  const [shift, setShift] = useState9(0);
19066
18876
  const centerX = gridRect.left + gridRect.width / 2;
19067
- useLayoutEffect5(() => {
18877
+ useLayoutEffect4(() => {
19068
18878
  const slot = slotRef.current;
19069
18879
  if (!slot) return;
19070
18880
  const clamp = () => {
19071
18881
  const w = slot.offsetWidth;
19072
18882
  if (w <= 0) return;
19073
18883
  const half = w / 2;
19074
- const clamped = Math.max(TOOLBAR_EDGE_MARGIN3 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half));
18884
+ const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
19075
18885
  setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
19076
18886
  };
19077
18887
  clamp();
@@ -19080,7 +18890,7 @@ function GridToolbarSlot({ gridRect, children }) {
19080
18890
  return () => ro.disconnect();
19081
18891
  }, [centerX, children]);
19082
18892
  const mobile = window.innerWidth <= 480;
19083
- return /* @__PURE__ */ jsx21(
18893
+ return /* @__PURE__ */ jsx20(
19084
18894
  "div",
19085
18895
  {
19086
18896
  ref: slotRef,
@@ -19115,7 +18925,7 @@ function requestValidateTree2(postToParent2, tree) {
19115
18925
  });
19116
18926
  }
19117
18927
  function StyleSwatch({ style }) {
19118
- return /* @__PURE__ */ jsx21(
18928
+ return /* @__PURE__ */ jsx20(
19119
18929
  "span",
19120
18930
  {
19121
18931
  "aria-hidden": true,
@@ -19129,35 +18939,35 @@ function StyleSwatch({ style }) {
19129
18939
  );
19130
18940
  }
19131
18941
  function ButtonGlyph() {
19132
- return /* @__PURE__ */ jsxs12("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19133
- /* @__PURE__ */ jsx21("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
19134
- /* @__PURE__ */ jsx21("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
18942
+ return /* @__PURE__ */ jsxs11("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
18943
+ /* @__PURE__ */ jsx20("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
18944
+ /* @__PURE__ */ jsx20("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
19135
18945
  ] });
19136
18946
  }
19137
18947
  function FeatureGlyph({ mode }) {
19138
- return /* @__PURE__ */ jsxs12("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19139
- /* @__PURE__ */ jsx21("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
19140
- /* @__PURE__ */ jsx21("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
19141
- /* @__PURE__ */ jsx21("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
19142
- /* @__PURE__ */ jsx21("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
19143
- /* @__PURE__ */ jsx21("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
19144
- mode === "add" && /* @__PURE__ */ jsx21("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
18948
+ return /* @__PURE__ */ jsxs11("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
18949
+ /* @__PURE__ */ jsx20("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
18950
+ /* @__PURE__ */ jsx20("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
18951
+ /* @__PURE__ */ jsx20("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
18952
+ /* @__PURE__ */ jsx20("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
18953
+ /* @__PURE__ */ jsx20("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
18954
+ mode === "add" && /* @__PURE__ */ jsx20("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
19145
18955
  ] });
19146
18956
  }
19147
- function ToolbarAction2({
18957
+ function ToolbarAction({
19148
18958
  label,
19149
18959
  onClick,
19150
18960
  disabled = false,
19151
18961
  children
19152
18962
  }) {
19153
- const button = /* @__PURE__ */ jsx21(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
19154
- return /* @__PURE__ */ jsxs12(Tooltip, { children: [
19155
- /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx21("span", { className: "inline-flex", children: button }) : button }),
19156
- /* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
18963
+ const button = /* @__PURE__ */ jsx20(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
18964
+ return /* @__PURE__ */ jsxs11(Tooltip, { children: [
18965
+ /* @__PURE__ */ jsx20(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx20("span", { className: "inline-flex", children: button }) : button }),
18966
+ /* @__PURE__ */ jsx20(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
19157
18967
  ] });
19158
18968
  }
19159
- function ToolbarSeparator2() {
19160
- return /* @__PURE__ */ jsx21("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
18969
+ function ToolbarSeparator() {
18970
+ return /* @__PURE__ */ jsx20("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
19161
18971
  }
19162
18972
  function CardStyleMenu({
19163
18973
  value,
@@ -19165,7 +18975,7 @@ function CardStyleMenu({
19165
18975
  disabled = false
19166
18976
  }) {
19167
18977
  const current = PRICING_CARD_STYLES.find((s) => s.value === value) ?? PRICING_CARD_STYLES[0];
19168
- const trigger = /* @__PURE__ */ jsxs12(
18978
+ const trigger = /* @__PURE__ */ jsxs11(
19169
18979
  "button",
19170
18980
  {
19171
18981
  type: "button",
@@ -19176,28 +18986,28 @@ function CardStyleMenu({
19176
18986
  disabled && "cursor-not-allowed opacity-40 hover:bg-transparent"
19177
18987
  ),
19178
18988
  children: [
19179
- /* @__PURE__ */ jsx21(StyleSwatch, { style: current.value }),
19180
- /* @__PURE__ */ jsx21("span", { className: "flex-1 text-left", children: current.label }),
19181
- /* @__PURE__ */ jsx21(ChevronDown4, { size: 16, style: { pointerEvents: "none" } })
18989
+ /* @__PURE__ */ jsx20(StyleSwatch, { style: current.value }),
18990
+ /* @__PURE__ */ jsx20("span", { className: "flex-1 text-left", children: current.label }),
18991
+ /* @__PURE__ */ jsx20(ChevronDown3, { size: 16, style: { pointerEvents: "none" } })
19182
18992
  ]
19183
18993
  }
19184
18994
  );
19185
18995
  if (disabled) {
19186
- return /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19187
- /* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
19188
- /* @__PURE__ */ jsxs12(Tooltip, { children: [
19189
- /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx21("span", { className: "inline-flex", children: trigger }) }),
19190
- /* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
18996
+ return /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
18997
+ /* @__PURE__ */ jsx20("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
18998
+ /* @__PURE__ */ jsxs11(Tooltip, { children: [
18999
+ /* @__PURE__ */ jsx20(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx20("span", { className: "inline-flex", children: trigger }) }),
19000
+ /* @__PURE__ */ jsx20(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
19191
19001
  ] })
19192
19002
  ] });
19193
19003
  }
19194
- return /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19195
- /* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
19196
- /* @__PURE__ */ jsxs12(DropdownMenu, { modal: false, children: [
19197
- /* @__PURE__ */ jsx21(DropdownMenuTrigger, { asChild: true, children: trigger }),
19198
- /* @__PURE__ */ jsx21(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
19004
+ return /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19005
+ /* @__PURE__ */ jsx20("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
19006
+ /* @__PURE__ */ jsxs11(DropdownMenu, { modal: false, children: [
19007
+ /* @__PURE__ */ jsx20(DropdownMenuTrigger, { asChild: true, children: trigger }),
19008
+ /* @__PURE__ */ jsx20(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
19199
19009
  const selected = style.value === value;
19200
- return /* @__PURE__ */ jsxs12(
19010
+ return /* @__PURE__ */ jsxs11(
19201
19011
  DropdownMenuItem,
19202
19012
  {
19203
19013
  role: "menuitemradio",
@@ -19205,9 +19015,9 @@ function CardStyleMenu({
19205
19015
  onSelect: () => onChange(style.value),
19206
19016
  className: cn("grid grid-cols-[18px_1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
19207
19017
  children: [
19208
- /* @__PURE__ */ jsx21(StyleSwatch, { style: style.value }),
19209
- /* @__PURE__ */ jsx21("span", { children: style.label }),
19210
- selected && /* @__PURE__ */ jsx21(Check3, { size: 16, className: "text-bridge-primary" })
19018
+ /* @__PURE__ */ jsx20(StyleSwatch, { style: style.value }),
19019
+ /* @__PURE__ */ jsx20("span", { children: style.label }),
19020
+ selected && /* @__PURE__ */ jsx20(Check2, { size: 16, className: "text-bridge-primary" })
19211
19021
  ]
19212
19022
  },
19213
19023
  style.value
@@ -19237,7 +19047,7 @@ function PricingCardToolbar({
19237
19047
  const style = pricingCardStyle(entry.tree, index);
19238
19048
  const featuredTag = pricingCardFeaturedTag(entry.tree, index);
19239
19049
  const mobile = window.innerWidth <= 480;
19240
- return /* @__PURE__ */ jsx21(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs12(
19050
+ return /* @__PURE__ */ jsx20(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs11(
19241
19051
  "div",
19242
19052
  {
19243
19053
  "data-ohw-bridge": "",
@@ -19249,7 +19059,7 @@ function PricingCardToolbar({
19249
19059
  ),
19250
19060
  style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
19251
19061
  children: [
19252
- /* @__PURE__ */ jsxs12(
19062
+ /* @__PURE__ */ jsxs11(
19253
19063
  "div",
19254
19064
  {
19255
19065
  className: cn(
@@ -19258,8 +19068,8 @@ function PricingCardToolbar({
19258
19068
  mobile ? "flex-wrap justify-center" : "flex-nowrap"
19259
19069
  ),
19260
19070
  children: [
19261
- /* @__PURE__ */ jsxs12(Tooltip, { children: [
19262
- /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx21(
19071
+ /* @__PURE__ */ jsxs11(Tooltip, { children: [
19072
+ /* @__PURE__ */ jsx20(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx20(
19263
19073
  CustomToolbarButton,
19264
19074
  {
19265
19075
  type: "button",
@@ -19267,7 +19077,7 @@ function PricingCardToolbar({
19267
19077
  "aria-pressed": featuredTag,
19268
19078
  onClick: () => onSetFeaturedTag(!featuredTag),
19269
19079
  className: "group size-8",
19270
- children: /* @__PURE__ */ jsx21(
19080
+ children: /* @__PURE__ */ jsx20(
19271
19081
  Star2,
19272
19082
  {
19273
19083
  size: 16,
@@ -19282,25 +19092,25 @@ function PricingCardToolbar({
19282
19092
  )
19283
19093
  }
19284
19094
  ) }),
19285
- /* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
19095
+ /* @__PURE__ */ jsx20(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
19286
19096
  ] }),
19287
- /* @__PURE__ */ jsx21(ToolbarSeparator2, {}),
19288
- /* @__PURE__ */ jsx21(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
19289
- /* @__PURE__ */ jsx21(ToolbarSeparator2, {}),
19290
- /* @__PURE__ */ jsx21(ToolbarAction2, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ jsx21(ButtonGlyph, {}) }),
19291
- /* @__PURE__ */ jsx21(ToolbarAction2, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ jsxs12("span", { className: "relative inline-flex", children: [
19292
- /* @__PURE__ */ jsx21(ButtonGlyph, {}),
19293
- /* @__PURE__ */ jsx21(Minus2, { size: 10, strokeWidth: 2.5, className: "absolute -right-1.5 -top-1.5 rounded-full bg-background text-bridge-primary" })
19097
+ /* @__PURE__ */ jsx20(ToolbarSeparator, {}),
19098
+ /* @__PURE__ */ jsx20(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
19099
+ /* @__PURE__ */ jsx20(ToolbarSeparator, {}),
19100
+ /* @__PURE__ */ jsx20(ToolbarAction, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ jsx20(ButtonGlyph, {}) }),
19101
+ /* @__PURE__ */ jsx20(ToolbarAction, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ jsxs11("span", { className: "relative inline-flex", children: [
19102
+ /* @__PURE__ */ jsx20(ButtonGlyph, {}),
19103
+ /* @__PURE__ */ jsx20(Minus, { size: 10, strokeWidth: 2.5, className: "absolute -right-1.5 -top-1.5 rounded-full bg-background text-bridge-primary" })
19294
19104
  ] }) }),
19295
- /* @__PURE__ */ jsx21(ToolbarAction2, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ jsx21(FeatureGlyph, { mode: "add" }) }),
19296
- /* @__PURE__ */ jsx21(ToolbarAction2, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ jsx21(FeatureGlyph, { mode: "remove" }) }),
19297
- /* @__PURE__ */ jsx21(ToolbarSeparator2, {}),
19298
- /* @__PURE__ */ jsx21(ToolbarAction2, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ jsx21(Plus3, { size: 16, style: { pointerEvents: "none" } }) }),
19299
- /* @__PURE__ */ jsx21(ToolbarAction2, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ jsx21(Minus2, { size: 16, style: { pointerEvents: "none" } }) })
19105
+ /* @__PURE__ */ jsx20(ToolbarAction, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ jsx20(FeatureGlyph, { mode: "add" }) }),
19106
+ /* @__PURE__ */ jsx20(ToolbarAction, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ jsx20(FeatureGlyph, { mode: "remove" }) }),
19107
+ /* @__PURE__ */ jsx20(ToolbarSeparator, {}),
19108
+ /* @__PURE__ */ jsx20(ToolbarAction, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ jsx20(Plus2, { size: 16, style: { pointerEvents: "none" } }) }),
19109
+ /* @__PURE__ */ jsx20(ToolbarAction, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ jsx20(Minus, { size: 16, style: { pointerEvents: "none" } }) })
19300
19110
  ]
19301
19111
  }
19302
19112
  ),
19303
- error && /* @__PURE__ */ jsx21("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
19113
+ error && /* @__PURE__ */ jsx20("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
19304
19114
  ]
19305
19115
  }
19306
19116
  ) });
@@ -19334,7 +19144,7 @@ function AiPricingCardOverlay({
19334
19144
  const overEditable = Boolean(t?.closest?.("[data-ohw-editable], [data-ohw-role], a, button"));
19335
19145
  setHover((prev) => {
19336
19146
  const next = ref && !overEditable ? ref : null;
19337
- return sameRef2(prev, next) ? prev : next;
19147
+ return sameRef(prev, next) ? prev : next;
19338
19148
  });
19339
19149
  };
19340
19150
  const onLeave = () => setHover(null);
@@ -19349,10 +19159,10 @@ function AiPricingCardOverlay({
19349
19159
  const onClick = (e) => {
19350
19160
  const t = e.target;
19351
19161
  if (!(t instanceof Element)) return;
19352
- if (t.closest(CHROME_SELECTOR2)) return;
19162
+ if (t.closest(CHROME_SELECTOR)) return;
19353
19163
  const ref = cardRefFromTarget(t);
19354
- setActive((prev) => sameRef2(prev, ref) ? prev : ref);
19355
- if (!ref || !sameRef2(activeRef.current, ref)) setError(null);
19164
+ setActive((prev) => sameRef(prev, ref) ? prev : ref);
19165
+ if (!ref || !sameRef(activeRef.current, ref)) setError(null);
19356
19166
  };
19357
19167
  document.addEventListener("click", onClick, true);
19358
19168
  return () => document.removeEventListener("click", onClick, true);
@@ -19417,12 +19227,12 @@ function AiPricingCardOverlay({
19417
19227
  const activeEntry = active ? findEntry(active.sectionId) : null;
19418
19228
  const activeCardRect = useLiveCardRect(active);
19419
19229
  const activeGridRect = useLiveCardRect(active, true);
19420
- const hoverRect = useLiveCardRect(hover && !sameRef2(hover, active) ? hover : null);
19421
- return /* @__PURE__ */ jsxs12(Fragment7, { children: [
19422
- hoverRect && /* @__PURE__ */ jsx21(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
19423
- activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ jsxs12(Fragment7, { children: [
19424
- /* @__PURE__ */ jsx21(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
19425
- /* @__PURE__ */ jsx21(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ jsx21(
19230
+ const hoverRect = useLiveCardRect(hover && !sameRef(hover, active) ? hover : null);
19231
+ return /* @__PURE__ */ jsxs11(Fragment7, { children: [
19232
+ hoverRect && /* @__PURE__ */ jsx20(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
19233
+ activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ jsxs11(Fragment7, { children: [
19234
+ /* @__PURE__ */ jsx20(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
19235
+ /* @__PURE__ */ jsx20(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ jsx20(
19426
19236
  PricingCardToolbar,
19427
19237
  {
19428
19238
  entry: activeEntry,
@@ -19450,7 +19260,7 @@ function AiPricingCardOverlay({
19450
19260
  onRemoveFeature: () => runMutation(active.sectionId, (tree) => removePricingCardFeature(tree, active.index))
19451
19261
  }
19452
19262
  ) }),
19453
- /* @__PURE__ */ jsx21(
19263
+ /* @__PURE__ */ jsx20(
19454
19264
  "div",
19455
19265
  {
19456
19266
  "data-ohw-bridge": "",
@@ -19543,10 +19353,10 @@ function extractYouTubeId(input) {
19543
19353
  }
19544
19354
 
19545
19355
  // src/ui/ai-section/AiVideoOverlay.tsx
19546
- import { Fragment as Fragment8, jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
19356
+ import { Fragment as Fragment8, jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
19547
19357
  var PRIMARY5 = "#0885FE";
19548
- var OHW_BLUE = `var(--ohw-primary, ${PRIMARY5})`;
19549
- var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
19358
+ var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY5})`;
19359
+ var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
19550
19360
  function findVideoBlockElement(sectionId, path) {
19551
19361
  const sectionEl = findByInstanceId(sectionId);
19552
19362
  if (!sectionEl) return null;
@@ -19606,12 +19416,12 @@ function requestValidateTree3(postToParent2, tree) {
19606
19416
  postToParent2({ type: "ow:ai-validate-tree-request", id, tree });
19607
19417
  });
19608
19418
  }
19609
- function Pill({
19419
+ function Pill2({
19610
19420
  label,
19611
19421
  onClick,
19612
19422
  disabled
19613
19423
  }) {
19614
- return /* @__PURE__ */ jsx22(
19424
+ return /* @__PURE__ */ jsx21(
19615
19425
  "button",
19616
19426
  {
19617
19427
  type: "button",
@@ -19627,7 +19437,7 @@ function Pill({
19627
19437
  border: "none",
19628
19438
  cursor: disabled ? "default" : "pointer",
19629
19439
  background: "#ffffff",
19630
- color: OHW_BLUE_DARK,
19440
+ color: OHW_BLUE_DARK2,
19631
19441
  opacity: disabled ? 0.4 : 1,
19632
19442
  fontSize: 12,
19633
19443
  lineHeight: "16px",
@@ -19670,8 +19480,8 @@ function VideoUrlInput({ value, onCommit }) {
19670
19480
  onCommit(id);
19671
19481
  }
19672
19482
  };
19673
- return /* @__PURE__ */ jsxs13("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
19674
- /* @__PURE__ */ jsxs13(
19483
+ return /* @__PURE__ */ jsxs12("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
19484
+ /* @__PURE__ */ jsxs12(
19675
19485
  "div",
19676
19486
  {
19677
19487
  style: {
@@ -19687,12 +19497,12 @@ function VideoUrlInput({ value, onCommit }) {
19687
19497
  boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
19688
19498
  },
19689
19499
  children: [
19690
- /* @__PURE__ */ jsx22(
19500
+ /* @__PURE__ */ jsx21(
19691
19501
  "span",
19692
19502
  {
19693
19503
  style: {
19694
19504
  flex: "0 0 auto",
19695
- color: OHW_BLUE_DARK,
19505
+ color: OHW_BLUE_DARK2,
19696
19506
  fontSize: 10,
19697
19507
  lineHeight: "16px",
19698
19508
  fontWeight: 700,
@@ -19702,7 +19512,7 @@ function VideoUrlInput({ value, onCommit }) {
19702
19512
  children: "Video"
19703
19513
  }
19704
19514
  ),
19705
- /* @__PURE__ */ jsx22(
19515
+ /* @__PURE__ */ jsx21(
19706
19516
  "input",
19707
19517
  {
19708
19518
  type: "text",
@@ -19739,7 +19549,7 @@ function VideoUrlInput({ value, onCommit }) {
19739
19549
  ]
19740
19550
  }
19741
19551
  ),
19742
- invalid && /* @__PURE__ */ jsx22("div", { style: { color: "#FCA5A5", fontSize: 11, textAlign: "center" }, children: "That doesn't look like a YouTube link \u2014 try pasting the video URL again." })
19552
+ invalid && /* @__PURE__ */ jsx21("div", { style: { color: "#FCA5A5", fontSize: 11, textAlign: "center" }, children: "That doesn't look like a YouTube link \u2014 try pasting the video URL again." })
19743
19553
  ] });
19744
19554
  }
19745
19555
  function VideoToolbar({
@@ -19749,7 +19559,7 @@ function VideoToolbar({
19749
19559
  onSetVideoId,
19750
19560
  onRemove
19751
19561
  }) {
19752
- return /* @__PURE__ */ jsxs13(
19562
+ return /* @__PURE__ */ jsxs12(
19753
19563
  "div",
19754
19564
  {
19755
19565
  "data-ohw-bridge": "",
@@ -19761,7 +19571,7 @@ function VideoToolbar({
19761
19571
  gap: 6,
19762
19572
  alignItems: "center",
19763
19573
  width: 280,
19764
- background: OHW_BLUE,
19574
+ background: OHW_BLUE2,
19765
19575
  padding: 8,
19766
19576
  borderRadius: 12,
19767
19577
  boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
@@ -19769,9 +19579,9 @@ function VideoToolbar({
19769
19579
  opacity: pending ? 0.6 : 1
19770
19580
  },
19771
19581
  children: [
19772
- /* @__PURE__ */ jsx22(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
19773
- /* @__PURE__ */ jsx22(Pill, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
19774
- error && /* @__PURE__ */ jsx22("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
19582
+ /* @__PURE__ */ jsx21(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
19583
+ /* @__PURE__ */ jsx21(Pill2, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
19584
+ error && /* @__PURE__ */ jsx21("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
19775
19585
  ]
19776
19586
  }
19777
19587
  );
@@ -19891,8 +19701,8 @@ function AiVideoOverlay({
19891
19701
  const activeBlockRect = useLiveBlockRect(active);
19892
19702
  const TOOLBAR_APPROX_H = 90;
19893
19703
  const toolbarState = activeBlockRect && activeBlockRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
19894
- return /* @__PURE__ */ jsxs13(Fragment8, { children: [
19895
- hoverHandleRect && hover && /* @__PURE__ */ jsx22(
19704
+ return /* @__PURE__ */ jsxs12(Fragment8, { children: [
19705
+ hoverHandleRect && hover && /* @__PURE__ */ jsx21(
19896
19706
  "button",
19897
19707
  {
19898
19708
  type: "button",
@@ -19920,15 +19730,15 @@ function AiVideoOverlay({
19920
19730
  fontSize: 14,
19921
19731
  fontWeight: 700
19922
19732
  },
19923
- children: /* @__PURE__ */ jsx22(Star3, { size: 14, style: { pointerEvents: "none" } })
19733
+ children: /* @__PURE__ */ jsx21(Star3, { size: 14, style: { pointerEvents: "none" } })
19924
19734
  }
19925
19735
  ),
19926
- activeBlockRect && active && activeEntry && /* @__PURE__ */ jsx22(
19736
+ activeBlockRect && active && activeEntry && /* @__PURE__ */ jsx21(
19927
19737
  ItemInteractionLayer,
19928
19738
  {
19929
19739
  rect: activeBlockRect,
19930
19740
  state: toolbarState,
19931
- toolbar: /* @__PURE__ */ jsx22(
19741
+ toolbar: /* @__PURE__ */ jsx21(
19932
19742
  VideoToolbar,
19933
19743
  {
19934
19744
  videoId: videoIdAt(activeEntry.tree, active.path),
@@ -20003,10 +19813,10 @@ function setCarouselAutoplay(tree, on) {
20003
19813
  }
20004
19814
 
20005
19815
  // src/ui/ai-section/AiFadeCarouselOverlay.tsx
20006
- import { Fragment as Fragment9, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
19816
+ import { Fragment as Fragment9, jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
20007
19817
  var PRIMARY6 = "#0885FE";
20008
- var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY6})`;
20009
- var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
19818
+ var OHW_BLUE3 = `var(--ohw-primary, ${PRIMARY6})`;
19819
+ var OHW_BLUE_DARK3 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
20010
19820
  function findCarouselItemElement(sectionId, index) {
20011
19821
  const sectionEl = findByInstanceId(sectionId);
20012
19822
  if (!sectionEl) return null;
@@ -20085,8 +19895,8 @@ function requestAssetPick2(postToParent2) {
20085
19895
  postToParent2({ type: "ow:asset-pick", id });
20086
19896
  });
20087
19897
  }
20088
- function Pill2({ label, onClick, disabled }) {
20089
- return /* @__PURE__ */ jsx23(
19898
+ function Pill3({ label, onClick, disabled }) {
19899
+ return /* @__PURE__ */ jsx22(
20090
19900
  "button",
20091
19901
  {
20092
19902
  type: "button",
@@ -20102,7 +19912,7 @@ function Pill2({ label, onClick, disabled }) {
20102
19912
  border: "none",
20103
19913
  cursor: disabled ? "default" : "pointer",
20104
19914
  background: "#ffffff",
20105
- color: OHW_BLUE_DARK2,
19915
+ color: OHW_BLUE_DARK3,
20106
19916
  opacity: disabled ? 0.4 : 1,
20107
19917
  fontSize: 12,
20108
19918
  lineHeight: "16px",
@@ -20120,7 +19930,7 @@ function TogglePill({
20120
19930
  onToggle,
20121
19931
  disabled
20122
19932
  }) {
20123
- return /* @__PURE__ */ jsxs14(
19933
+ return /* @__PURE__ */ jsxs13(
20124
19934
  "button",
20125
19935
  {
20126
19936
  type: "button",
@@ -20139,7 +19949,7 @@ function TogglePill({
20139
19949
  border: "none",
20140
19950
  cursor: disabled ? "default" : "pointer",
20141
19951
  background: "#ffffff",
20142
- color: OHW_BLUE_DARK2,
19952
+ color: OHW_BLUE_DARK3,
20143
19953
  opacity: disabled ? 0.4 : 1,
20144
19954
  fontSize: 12,
20145
19955
  lineHeight: "16px",
@@ -20149,7 +19959,7 @@ function TogglePill({
20149
19959
  },
20150
19960
  children: [
20151
19961
  label,
20152
- /* @__PURE__ */ jsx23(
19962
+ /* @__PURE__ */ jsx22(
20153
19963
  "span",
20154
19964
  {
20155
19965
  "aria-hidden": true,
@@ -20162,10 +19972,10 @@ function TogglePill({
20162
19972
  // Off is a grey track, not a washed-out blue: the pill's own white background already
20163
19973
  // carries the brand colour in the text, and a pale blue track next to it read as
20164
19974
  // "disabled control" rather than "switch that is off".
20165
- background: on ? OHW_BLUE_DARK2 : "#CBD5E1",
19975
+ background: on ? OHW_BLUE_DARK3 : "#CBD5E1",
20166
19976
  transition: "background 120ms ease"
20167
19977
  },
20168
- children: /* @__PURE__ */ jsx23(
19978
+ children: /* @__PURE__ */ jsx22(
20169
19979
  "span",
20170
19980
  {
20171
19981
  style: {
@@ -20194,7 +20004,7 @@ function CarouselSlideToolbar({
20194
20004
  onChangeImage,
20195
20005
  onToggleAutoplay
20196
20006
  }) {
20197
- return /* @__PURE__ */ jsxs14(
20007
+ return /* @__PURE__ */ jsxs13(
20198
20008
  "div",
20199
20009
  {
20200
20010
  "data-ohw-bridge": "",
@@ -20205,7 +20015,7 @@ function CarouselSlideToolbar({
20205
20015
  flexDirection: "column",
20206
20016
  gap: 6,
20207
20017
  alignItems: "center",
20208
- background: OHW_BLUE2,
20018
+ background: OHW_BLUE3,
20209
20019
  padding: 8,
20210
20020
  borderRadius: 12,
20211
20021
  boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
@@ -20217,11 +20027,11 @@ function CarouselSlideToolbar({
20217
20027
  pointerEvents: pending ? "none" : "auto"
20218
20028
  },
20219
20029
  children: [
20220
- /* @__PURE__ */ jsxs14("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
20221
- /* @__PURE__ */ jsx23(Pill2, { label: "Change Image", onClick: onChangeImage }),
20222
- /* @__PURE__ */ jsx23(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
20030
+ /* @__PURE__ */ jsxs13("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
20031
+ /* @__PURE__ */ jsx22(Pill3, { label: "Change Image", onClick: onChangeImage }),
20032
+ /* @__PURE__ */ jsx22(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
20223
20033
  ] }),
20224
- error && /* @__PURE__ */ jsx23("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
20034
+ error && /* @__PURE__ */ jsx22("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
20225
20035
  ]
20226
20036
  }
20227
20037
  );
@@ -20361,8 +20171,8 @@ function AiFadeCarouselOverlay({
20361
20171
  const activeItemRect = useLiveItemRect2(active);
20362
20172
  const TOOLBAR_APPROX_H = 90;
20363
20173
  const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
20364
- return /* @__PURE__ */ jsxs14(Fragment9, { children: [
20365
- hoverHandleRect && hover && /* @__PURE__ */ jsx23(
20174
+ return /* @__PURE__ */ jsxs13(Fragment9, { children: [
20175
+ hoverHandleRect && hover && /* @__PURE__ */ jsx22(
20366
20176
  "button",
20367
20177
  {
20368
20178
  type: "button",
@@ -20391,10 +20201,10 @@ function AiFadeCarouselOverlay({
20391
20201
  fontSize: 14,
20392
20202
  fontWeight: 700
20393
20203
  },
20394
- children: /* @__PURE__ */ jsx23(Star4, { size: 14, style: { pointerEvents: "none" } })
20204
+ children: /* @__PURE__ */ jsx22(Star4, { size: 14, style: { pointerEvents: "none" } })
20395
20205
  }
20396
20206
  ),
20397
- swapping && /* @__PURE__ */ jsx23(
20207
+ swapping && /* @__PURE__ */ jsx22(
20398
20208
  "div",
20399
20209
  {
20400
20210
  ref: skeletonRef,
@@ -20412,15 +20222,15 @@ function AiFadeCarouselOverlay({
20412
20222
  zIndex: 2147483646,
20413
20223
  pointerEvents: "none"
20414
20224
  },
20415
- children: /* @__PURE__ */ jsx23("style", { children: MEDIA_SKELETON_CSS })
20225
+ children: /* @__PURE__ */ jsx22("style", { children: MEDIA_SKELETON_CSS })
20416
20226
  }
20417
20227
  ),
20418
- activeItemRect && active && activeEntry && /* @__PURE__ */ jsx23(
20228
+ activeItemRect && active && activeEntry && /* @__PURE__ */ jsx22(
20419
20229
  ItemInteractionLayer,
20420
20230
  {
20421
20231
  rect: activeItemRect,
20422
20232
  state: toolbarState,
20423
- toolbar: /* @__PURE__ */ jsx23(
20233
+ toolbar: /* @__PURE__ */ jsx22(
20424
20234
  CarouselSlideToolbar,
20425
20235
  {
20426
20236
  pending,
@@ -20773,11 +20583,118 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
20773
20583
  // src/ui/link-modal/LinkPopover.tsx
20774
20584
  import { useEffect as useEffect13 } from "react";
20775
20585
 
20586
+ // src/ui/dialog.tsx
20587
+ import * as React9 from "react";
20588
+ import { Dialog as DialogPrimitive } from "radix-ui";
20589
+ import { X as X2 } from "lucide-react";
20590
+ import { jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
20591
+ function Dialog2({
20592
+ ...props
20593
+ }) {
20594
+ return /* @__PURE__ */ jsx23(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
20595
+ }
20596
+ function DialogPortal({
20597
+ ...props
20598
+ }) {
20599
+ return /* @__PURE__ */ jsx23(DialogPrimitive.Portal, { ...props });
20600
+ }
20601
+ function DialogOverlay({
20602
+ className,
20603
+ ...props
20604
+ }) {
20605
+ return /* @__PURE__ */ jsx23(
20606
+ DialogPrimitive.Overlay,
20607
+ {
20608
+ "data-slot": "dialog-overlay",
20609
+ "data-ohw-link-modal-root": "",
20610
+ className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
20611
+ ...props
20612
+ }
20613
+ );
20614
+ }
20615
+ var DialogContent = React9.forwardRef(
20616
+ ({ className, children, showCloseButton = true, container, ...props }, ref) => {
20617
+ const positionMode = container ? "absolute" : "fixed";
20618
+ return /* @__PURE__ */ jsxs14(DialogPortal, { container: container ?? void 0, children: [
20619
+ /* @__PURE__ */ jsx23(DialogOverlay, { className: cn(positionMode, "inset-0") }),
20620
+ /* @__PURE__ */ jsxs14(
20621
+ DialogPrimitive.Content,
20622
+ {
20623
+ ref,
20624
+ "data-slot": "dialog-content",
20625
+ className: cn(
20626
+ positionMode,
20627
+ "left-1/2 top-1/2 z-[2147483647] flex w-full max-w-[448px] -translate-x-1/2 -translate-y-1/2 flex-col overflow-visible",
20628
+ "rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
20629
+ container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
20630
+ className
20631
+ ),
20632
+ onMouseDown: (e) => e.stopPropagation(),
20633
+ ...props,
20634
+ children: [
20635
+ children,
20636
+ showCloseButton ? /* @__PURE__ */ jsx23(
20637
+ DialogPrimitive.Close,
20638
+ {
20639
+ type: "button",
20640
+ className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
20641
+ "aria-label": "Close",
20642
+ children: /* @__PURE__ */ jsx23(X2, { size: 16, "aria-hidden": true })
20643
+ }
20644
+ ) : null
20645
+ ]
20646
+ }
20647
+ )
20648
+ ] });
20649
+ }
20650
+ );
20651
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
20652
+ function DialogHeader({
20653
+ className,
20654
+ ...props
20655
+ }) {
20656
+ return /* @__PURE__ */ jsx23("div", { className: cn("flex flex-col gap-1.5", className), ...props });
20657
+ }
20658
+ function DialogFooter({
20659
+ className,
20660
+ ...props
20661
+ }) {
20662
+ return /* @__PURE__ */ jsx23(
20663
+ "div",
20664
+ {
20665
+ className: cn("flex items-center justify-end gap-2", className),
20666
+ ...props
20667
+ }
20668
+ );
20669
+ }
20670
+ var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx23(
20671
+ DialogPrimitive.Title,
20672
+ {
20673
+ ref,
20674
+ className: cn(
20675
+ "text-lg font-semibold leading-none tracking-tight text-card-foreground",
20676
+ className
20677
+ ),
20678
+ ...props
20679
+ }
20680
+ ));
20681
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
20682
+ var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx23(
20683
+ DialogPrimitive.Description,
20684
+ {
20685
+ ref,
20686
+ className: cn("text-sm text-muted-foreground", className),
20687
+ ...props
20688
+ }
20689
+ ));
20690
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
20691
+ var DialogClose = DialogPrimitive.Close;
20692
+
20776
20693
  // src/ui/link-modal/LinkEditorPanel.tsx
20777
20694
  import { Info, X as X4 } from "lucide-react";
20778
20695
 
20779
20696
  // src/ui/link-modal/DestinationBreadcrumb.tsx
20780
- import { ArrowRight as ArrowRight3, File, GalleryVertical } from "lucide-react";
20697
+ import { ArrowRight as ArrowRight2, File, GalleryVertical } from "lucide-react";
20781
20698
  import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
20782
20699
  function DestinationBreadcrumb({
20783
20700
  pageTitle,
@@ -20791,7 +20708,7 @@ function DestinationBreadcrumb({
20791
20708
  /* @__PURE__ */ jsx24("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
20792
20709
  ] }),
20793
20710
  /* @__PURE__ */ jsx24(
20794
- ArrowRight3,
20711
+ ArrowRight2,
20795
20712
  {
20796
20713
  size: 16,
20797
20714
  className: "shrink-0 text-muted-foreground",
@@ -20903,7 +20820,7 @@ function Label({ className, ...props }) {
20903
20820
  }
20904
20821
 
20905
20822
  // src/ui/link-modal/UrlOrPageInput.tsx
20906
- import { ChevronDown as ChevronDown5, File as File2, X as X3 } from "lucide-react";
20823
+ import { ChevronDown as ChevronDown4, File as File2, X as X3 } from "lucide-react";
20907
20824
  import { jsx as jsx28, jsxs as jsxs17 } from "react/jsx-runtime";
20908
20825
  function FieldChevron({
20909
20826
  onClick
@@ -20916,7 +20833,7 @@ function FieldChevron({
20916
20833
  onClick,
20917
20834
  "aria-label": "Open page list",
20918
20835
  tabIndex: -1,
20919
- children: /* @__PURE__ */ jsx28(ChevronDown5, { size: 16 })
20836
+ children: /* @__PURE__ */ jsx28(ChevronDown4, { size: 16 })
20920
20837
  }
20921
20838
  );
20922
20839
  }
@@ -21146,7 +21063,7 @@ function LinkEditorPanel({ state, onClose }) {
21146
21063
  // src/ui/link-modal/SectionPickerOverlay.tsx
21147
21064
  import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo2, useRef as useRef10, useState as useState13 } from "react";
21148
21065
  import { createPortal as createPortal2 } from "react-dom";
21149
- import { ArrowLeft as ArrowLeft3, Check as Check4 } from "lucide-react";
21066
+ import { ArrowLeft as ArrowLeft2, Check as Check3 } from "lucide-react";
21150
21067
  import { usePathname, useRouter as useRouter2 } from "next/navigation";
21151
21068
 
21152
21069
  // src/lib/parent-scroll.ts
@@ -21423,7 +21340,7 @@ function SectionPickerOverlay({
21423
21340
  className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
21424
21341
  onClick: onBack,
21425
21342
  children: [
21426
- /* @__PURE__ */ jsx30(ArrowLeft3, { className: "size-4 shrink-0", "aria-hidden": true }),
21343
+ /* @__PURE__ */ jsx30(ArrowLeft2, { className: "size-4 shrink-0", "aria-hidden": true }),
21427
21344
  "Back"
21428
21345
  ]
21429
21346
  }
@@ -21492,7 +21409,7 @@ function SectionPickerOverlay({
21492
21409
  className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
21493
21410
  style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
21494
21411
  "aria-hidden": true,
21495
- children: /* @__PURE__ */ jsx30(Check4, { className: "size-5" })
21412
+ children: /* @__PURE__ */ jsx30(Check3, { className: "size-5" })
21496
21413
  }
21497
21414
  ) : null
21498
21415
  ]
@@ -21876,7 +21793,6 @@ function shouldUseDevFixtures() {
21876
21793
  function getLogoElement(el) {
21877
21794
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
21878
21795
  if (marked) return marked;
21879
- if (el.closest('[data-ohw-editable="icon"]')) return null;
21880
21796
  const root = el.closest("nav, [data-ohw-nav-root], footer");
21881
21797
  if (!root) return null;
21882
21798
  const anchor = el.closest("a");
@@ -21946,7 +21862,7 @@ function addFooterColumnWithPersist({
21946
21862
  import {
21947
21863
  useCallback as useCallback9,
21948
21864
  useEffect as useEffect14,
21949
- useLayoutEffect as useLayoutEffect6,
21865
+ useLayoutEffect as useLayoutEffect5,
21950
21866
  useRef as useRef11,
21951
21867
  useState as useState15
21952
21868
  } from "react";
@@ -22043,7 +21959,7 @@ function FloatingPanel({
22043
21959
  return () => window.removeEventListener("message", onParentScroll);
22044
21960
  }, [open]);
22045
21961
  const positionRef = useRef11(position);
22046
- useLayoutEffect6(() => {
21962
+ useLayoutEffect5(() => {
22047
21963
  if (!open) {
22048
21964
  positionRef.current = position;
22049
21965
  return;
@@ -22053,7 +21969,7 @@ function FloatingPanel({
22053
21969
  }
22054
21970
  positionRef.current = position;
22055
21971
  }, [open, position, liveScroll, parentScroll]);
22056
- useLayoutEffect6(() => {
21972
+ useLayoutEffect5(() => {
22057
21973
  if (!open || !panelRef.current) return;
22058
21974
  const el = panelRef.current;
22059
21975
  const header = el.querySelector("[data-ohw-floating-panel-header]");
@@ -22262,7 +22178,7 @@ function SocialsDisplayPanel({ display, onChange, className }) {
22262
22178
  }
22263
22179
 
22264
22180
  // src/ui/button-style-panel.tsx
22265
- import { Check as Check5 } from "lucide-react";
22181
+ import { Check as Check4 } from "lucide-react";
22266
22182
  import { jsx as jsx34, jsxs as jsxs23 } from "react/jsx-runtime";
22267
22183
  var SIZE_LABEL = { s: "S", m: "M", l: "L" };
22268
22184
  function ButtonStylePanel({
@@ -22333,7 +22249,7 @@ function ButtonStylePanel({
22333
22249
  {
22334
22250
  className: "absolute right-0.5 top-0.5 flex size-5 items-center justify-center rounded-full bg-primary text-primary-foreground",
22335
22251
  "aria-hidden": true,
22336
- children: /* @__PURE__ */ jsx34(Check5, { className: "size-3", strokeWidth: 3 })
22252
+ children: /* @__PURE__ */ jsx34(Check4, { className: "size-3", strokeWidth: 3 })
22337
22253
  }
22338
22254
  ) : null
22339
22255
  ]
@@ -23358,7 +23274,7 @@ function useSectionDrag({
23358
23274
  }
23359
23275
 
23360
23276
  // src/ui/footer-container-chrome.tsx
23361
- import { Plus as Plus4 } from "lucide-react";
23277
+ import { Plus as Plus3 } from "lucide-react";
23362
23278
  import { jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
23363
23279
  function FooterContainerChrome({
23364
23280
  rect,
@@ -23399,7 +23315,7 @@ function FooterContainerChrome({
23399
23315
  if (addDisabled) return;
23400
23316
  onAdd();
23401
23317
  },
23402
- children: /* @__PURE__ */ jsx35(Plus4, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
23318
+ children: /* @__PURE__ */ jsx35(Plus3, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
23403
23319
  }
23404
23320
  ) }),
23405
23321
  /* @__PURE__ */ jsx35(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
@@ -23578,7 +23494,7 @@ function deleteSelectedNavFooterItem(deps) {
23578
23494
  }
23579
23495
 
23580
23496
  // src/ui/navbar-container-chrome.tsx
23581
- import { Plus as Plus5 } from "lucide-react";
23497
+ import { Plus as Plus4 } from "lucide-react";
23582
23498
  import { jsx as jsx36 } from "react/jsx-runtime";
23583
23499
  function NavbarContainerChrome({
23584
23500
  rect,
@@ -23614,7 +23530,7 @@ function NavbarContainerChrome({
23614
23530
  e.stopPropagation();
23615
23531
  onAdd();
23616
23532
  },
23617
- children: /* @__PURE__ */ jsx36(Plus5, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
23533
+ children: /* @__PURE__ */ jsx36(Plus4, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
23618
23534
  }
23619
23535
  )
23620
23536
  }
@@ -23686,7 +23602,7 @@ function Badge({ className, variant, ...props }) {
23686
23602
  }
23687
23603
 
23688
23604
  // src/OhhwellsBridge.tsx
23689
- import { Brush as Brush2, Link as Link2, Plus as Plus6, Settings } from "lucide-react";
23605
+ import { Brush as Brush2, Link as Link2, Plus as Plus5, Settings } from "lucide-react";
23690
23606
  import { Fragment as Fragment12, jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
23691
23607
  var PRIMARY7 = "#0885FE";
23692
23608
  var IMAGE_FADE_MS = 300;
@@ -24463,7 +24379,7 @@ function getNavigationSelectionParent(el) {
24463
24379
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
24464
24380
  return resolveFooterLinksContainerFrom(el);
24465
24381
  }
24466
- 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)) {
24382
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
24467
24383
  return getNavigationRoot(el);
24468
24384
  }
24469
24385
  return null;
@@ -24685,6 +24601,7 @@ var ICONS = {
24685
24601
  insertUnorderedList: '<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>',
24686
24602
  insertOrderedList: '<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'
24687
24603
  };
24604
+ var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
24688
24605
  var SELECTION_CHROME_GAP2 = 4;
24689
24606
  var TOOLBAR_STROKE_GAP2 = 4;
24690
24607
  var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
@@ -24782,7 +24699,7 @@ function applyVisibleViewport(el, parentScroll) {
24782
24699
  el.style.top = `${top}px`;
24783
24700
  el.style.height = `${height}px`;
24784
24701
  }
24785
- var TOOLBAR_EDGE_MARGIN4 = 4;
24702
+ var TOOLBAR_EDGE_MARGIN3 = 4;
24786
24703
  function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
24787
24704
  const isAbove = transform.includes("translateY(-100%)");
24788
24705
  let visualTop = isAbove ? top - approxH : top;
@@ -24809,8 +24726,8 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
24809
24726
  function clampToolbarLeft(centerX, toolbarWidth) {
24810
24727
  const half = toolbarWidth / 2;
24811
24728
  return Math.max(
24812
- TOOLBAR_EDGE_MARGIN4 + half,
24813
- Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN4 - half)
24729
+ TOOLBAR_EDGE_MARGIN3 + half,
24730
+ Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half)
24814
24731
  );
24815
24732
  }
24816
24733
  function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
@@ -25249,7 +25166,7 @@ function OhhwellsBridge() {
25249
25166
  }, []);
25250
25167
  const subdomainFromQuery = searchParams.get("subdomain");
25251
25168
  const [subdomain, setSubdomain] = useState18(() => resolveSubdomain(subdomainFromQuery));
25252
- useLayoutEffect7(() => {
25169
+ useLayoutEffect6(() => {
25253
25170
  const next = resolveSubdomain(subdomainFromQuery);
25254
25171
  if (next !== subdomain) setSubdomain(next);
25255
25172
  if (next) return;
@@ -25700,6 +25617,21 @@ function OhhwellsBridge() {
25700
25617
  const [isItemDragging, setIsItemDragging] = useState18(false);
25701
25618
  const [isFooterFrameSelection, setIsFooterFrameSelection] = useState18(false);
25702
25619
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
25620
+ const [floatingPanel, setFloatingPanel] = useState18(null);
25621
+ const floatingPanelOpenRef = useRef14(false);
25622
+ floatingPanelOpenRef.current = floatingPanel !== null;
25623
+ const floatingPanelRef = useRef14(null);
25624
+ floatingPanelRef.current = floatingPanel;
25625
+ const [floatingPanelPos, setFloatingPanelPos] = useState18(null);
25626
+ const buttonCollectionDragRef = useRef14(null);
25627
+ const buttonDropInsertIndexRef = useRef14(null);
25628
+ const [buttonDropSlots, setButtonDropSlots] = useState18([]);
25629
+ const [activeButtonDropIndex, setActiveButtonDropIndex] = useState18(null);
25630
+ const buttonPointerDragRef = useRef14(null);
25631
+ const [buttonStyleTick, setButtonStyleTick] = useState18(0);
25632
+ const [logoSizeDraft, setLogoSizeDraft] = useState18(null);
25633
+ const [editorViewport, setEditorViewport] = useState18("desktop");
25634
+ const [parentScrollSnap, setParentScrollSnap] = useState18(null);
25703
25635
  const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState18(null);
25704
25636
  const [footerHeadingVisible, setFooterHeadingVisible] = useState18(null);
25705
25637
  const footerDragRef = useRef14(null);
@@ -25725,21 +25657,6 @@ function OhhwellsBridge() {
25725
25657
  const stylesRef = useRef14("");
25726
25658
  const appliedDrawerRef = useRef14(null);
25727
25659
  const pendingDeleteUndoRef = useRef14(null);
25728
- const [floatingPanel, setFloatingPanel] = useState18(null);
25729
- const floatingPanelOpenRef = useRef14(false);
25730
- const floatingPanelRef = useRef14(null);
25731
- floatingPanelRef.current = floatingPanel;
25732
- const setFloatingPanelRef = useRef14(setFloatingPanel);
25733
- const [floatingPanelPos, setFloatingPanelPos] = useState18(null);
25734
- const buttonCollectionDragRef = useRef14(null);
25735
- const buttonDropInsertIndexRef = useRef14(null);
25736
- const [buttonDropSlots, setButtonDropSlots] = useState18([]);
25737
- const [activeButtonDropIndex, setActiveButtonDropIndex] = useState18(null);
25738
- const buttonPointerDragRef = useRef14(null);
25739
- const [buttonStyleTick, setButtonStyleTick] = useState18(0);
25740
- const [logoSizeDraft, setLogoSizeDraft] = useState18(null);
25741
- const [editorViewport, setEditorViewport] = useState18("desktop");
25742
- const [parentScrollSnap, setParentScrollSnap] = useState18(null);
25743
25660
  const [sitePages, setSitePages] = useState18([]);
25744
25661
  const [sectionsByPath, setSectionsByPath] = useState18({});
25745
25662
  const sectionsPrefetchGenRef = useRef14(0);
@@ -25748,18 +25665,7 @@ function OhhwellsBridge() {
25748
25665
  const linkPopoverOpenRef = useRef14(false);
25749
25666
  const linkPopoverGraceUntilRef = useRef14(0);
25750
25667
  setLinkPopoverRef.current = setLinkPopover;
25751
- setFloatingPanelRef.current = setFloatingPanel;
25752
25668
  linkPopoverSessionRef.current = linkPopover;
25753
- floatingPanelOpenRef.current = Boolean(floatingPanel);
25754
- useEffect17(() => {
25755
- const syncViewport = () => {
25756
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
25757
- setEditorViewport((prev) => prev === next ? prev : next);
25758
- };
25759
- syncViewport();
25760
- window.addEventListener("resize", syncViewport);
25761
- return () => window.removeEventListener("resize", syncViewport);
25762
- }, []);
25763
25669
  useEffect17(() => {
25764
25670
  setSectionOrderPersistHandler((entries) => {
25765
25671
  const currentPath = window.location.pathname;
@@ -27427,7 +27333,7 @@ function OhhwellsBridge() {
27427
27333
  isFooterFrameSelection,
27428
27334
  postToParent2
27429
27335
  ]);
27430
- useLayoutEffect7(() => {
27336
+ useLayoutEffect6(() => {
27431
27337
  if (!subdomain || isEditMode) {
27432
27338
  setFetchState("done");
27433
27339
  return;
@@ -27454,7 +27360,6 @@ function OhhwellsBridge() {
27454
27360
  applyAiFooterFromContent(content);
27455
27361
  if (typeof content[STYLE_STORE_KEY] === "string") {
27456
27362
  stylesRef.current = content[STYLE_STORE_KEY];
27457
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
27458
27363
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
27459
27364
  }
27460
27365
  applyBrandChrome(content);
@@ -27465,12 +27370,12 @@ function OhhwellsBridge() {
27465
27370
  if (key === "__ohw_sections") continue;
27466
27371
  if (key === AI_SECTIONS_KEY) continue;
27467
27372
  if (key === AI_FOOTER_KEY) continue;
27468
- if (key === LOGO_PLACEHOLDER_KEY) continue;
27469
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
27470
27373
  if (key === BRAND_KIT_KEY) continue;
27471
27374
  if (key === STYLE_STORE_KEY) continue;
27472
27375
  if (BRAND_CHROME_KEYS.has(key)) continue;
27376
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
27473
27377
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
27378
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
27474
27379
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
27475
27380
  continue;
27476
27381
  }
@@ -27685,18 +27590,17 @@ function OhhwellsBridge() {
27685
27590
  }
27686
27591
  applyAiFooterFromContent(content);
27687
27592
  if (typeof content[STYLE_STORE_KEY] === "string") {
27688
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
27689
27593
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
27690
27594
  }
27691
27595
  for (const [key, val] of Object.entries(content)) {
27692
27596
  if (key === "__ohw_sections") continue;
27693
27597
  if (key === AI_SECTIONS_KEY) continue;
27694
27598
  if (key === AI_FOOTER_KEY) continue;
27695
- if (key === LOGO_PLACEHOLDER_KEY) continue;
27696
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
27697
27599
  if (key === BRAND_KIT_KEY) continue;
27698
27600
  if (key === STYLE_STORE_KEY) continue;
27699
27601
  if (BRAND_CHROME_KEYS.has(key)) continue;
27602
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
27603
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
27700
27604
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
27701
27605
  continue;
27702
27606
  }
@@ -27769,7 +27673,7 @@ function OhhwellsBridge() {
27769
27673
  if (debounceTimer) clearTimeout(debounceTimer);
27770
27674
  };
27771
27675
  }, [subdomain, isEditMode, pathname]);
27772
- useLayoutEffect7(() => {
27676
+ useLayoutEffect6(() => {
27773
27677
  const el = document.getElementById("ohw-loader");
27774
27678
  if (!el) return;
27775
27679
  const visible = Boolean(subdomain) && fetchState !== "done";
@@ -27953,11 +27857,26 @@ function OhhwellsBridge() {
27953
27857
  const t2 = setTimeout(measure, 500);
27954
27858
  const ro = new ResizeObserver(schedule);
27955
27859
  ro.observe(document.body);
27860
+ let lastWidth = window.innerWidth;
27861
+ let resizeTimers = [];
27862
+ const clearResizeTimers = () => {
27863
+ resizeTimers.forEach(clearTimeout);
27864
+ resizeTimers = [];
27865
+ };
27866
+ const handleResize = () => {
27867
+ if (window.innerWidth === lastWidth) return;
27868
+ lastWidth = window.innerWidth;
27869
+ clearResizeTimers();
27870
+ resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
27871
+ };
27872
+ window.addEventListener("resize", handleResize);
27956
27873
  return () => {
27957
27874
  clearTimeout(t1);
27958
27875
  clearTimeout(t2);
27959
27876
  if (raf != null) cancelAnimationFrame(raf);
27960
27877
  ro.disconnect();
27878
+ clearResizeTimers();
27879
+ window.removeEventListener("resize", handleResize);
27961
27880
  };
27962
27881
  }, [pathname, isEditMode, postToParent2]);
27963
27882
  useEffect17(() => {
@@ -28256,13 +28175,6 @@ function OhhwellsBridge() {
28256
28175
  if (target.closest("[data-ohw-state-toggle]")) return;
28257
28176
  if (target.closest("[data-ohw-max-badge]")) return;
28258
28177
  if (isInsideLinkEditor(target)) return;
28259
- if (isInsideFloatingPanel(target)) return;
28260
- if (target.closest("[data-ohw-form-toolbar]")) return;
28261
- if (target.closest(
28262
- '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
28263
- )) {
28264
- return;
28265
- }
28266
28178
  if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
28267
28179
  clearMediaSelectionRef.current();
28268
28180
  }
@@ -28286,6 +28198,13 @@ function OhhwellsBridge() {
28286
28198
  return;
28287
28199
  }
28288
28200
  }
28201
+ if (isInsideFloatingPanel(target)) return;
28202
+ if (target.closest("[data-ohw-form-toolbar]")) return;
28203
+ if (target.closest(
28204
+ '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
28205
+ )) {
28206
+ return;
28207
+ }
28289
28208
  {
28290
28209
  const formEl = getFormElement(target);
28291
28210
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -28439,13 +28358,9 @@ function OhhwellsBridge() {
28439
28358
  if (isIconEditable(editable) && !getSocialItem(editable)) {
28440
28359
  e.preventDefault();
28441
28360
  e.stopPropagation();
28361
+ selectIconElementRef.current(editable);
28442
28362
  const aiIcon = editable.hasAttribute("data-ai-icon");
28443
28363
  const featureIcon = aiIcon && /\.features\.\d+\.icon$/.test(editable.dataset.ohwKey ?? "");
28444
- if (aiIcon) {
28445
- aiSectionApiRef.current?.selectFromElement(editable);
28446
- } else {
28447
- selectIconElementRef.current(editable);
28448
- }
28449
28364
  postToParentRef.current({
28450
28365
  type: "ow:icon-pick",
28451
28366
  key: editable.dataset.ohwKey ?? "",
@@ -28673,9 +28588,6 @@ function OhhwellsBridge() {
28673
28588
  setHoveredItemRect(null);
28674
28589
  hoveredNavContainerRef.current = null;
28675
28590
  setHoveredNavContainerRect(null);
28676
- siblingHintElRef.current = null;
28677
- setSiblingHintRect(null);
28678
- setSiblingHintRects([]);
28679
28591
  return;
28680
28592
  }
28681
28593
  {
@@ -28796,6 +28708,7 @@ function OhhwellsBridge() {
28796
28708
  hoveredNavContainerRef.current = null;
28797
28709
  setHoveredNavContainerRect(null);
28798
28710
  hoveredItemElRef.current = editable;
28711
+ setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
28799
28712
  }
28800
28713
  }
28801
28714
  }
@@ -29505,11 +29418,7 @@ function OhhwellsBridge() {
29505
29418
  };
29506
29419
  const handleMouseMove = (e) => {
29507
29420
  const { clientX, clientY } = e;
29508
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
29509
- dismissImageHover();
29510
- clearImageHover();
29511
- return;
29512
- }
29421
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
29513
29422
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
29514
29423
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
29515
29424
  formHoverElRef.current = null;
@@ -29538,12 +29447,7 @@ function OhhwellsBridge() {
29538
29447
  setHoveredItemRect(null);
29539
29448
  hoveredNavContainerRef.current = null;
29540
29449
  setHoveredNavContainerRect(null);
29541
- siblingHintElRef.current = null;
29542
- setSiblingHintRect(null);
29543
- setSiblingHintRects([]);
29544
29450
  dismissImageHover();
29545
- clearImageHover();
29546
- setSectionGap(null);
29547
29451
  return;
29548
29452
  }
29549
29453
  if (probeSocialsRowAt(clientX, clientY)) return;
@@ -29555,11 +29459,7 @@ function OhhwellsBridge() {
29555
29459
  if (e.data?.type !== "ow:pointer-sync") return;
29556
29460
  const { clientX, clientY } = e.data;
29557
29461
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
29558
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
29559
- dismissImageHover();
29560
- clearImageHover();
29561
- return;
29562
- }
29462
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
29563
29463
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
29564
29464
  if (probeSocialsRowAt(clientX, clientY)) return;
29565
29465
  probeSectionGapAt(clientX, clientY);
@@ -29939,7 +29839,6 @@ function OhhwellsBridge() {
29939
29839
  applyAiFooterFromContent(content);
29940
29840
  if (typeof content[STYLE_STORE_KEY] === "string") {
29941
29841
  stylesRef.current = content[STYLE_STORE_KEY];
29942
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
29943
29842
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
29944
29843
  }
29945
29844
  applyBrandChrome(content);
@@ -29954,12 +29853,12 @@ function OhhwellsBridge() {
29954
29853
  }
29955
29854
  if (key === AI_SECTIONS_KEY) continue;
29956
29855
  if (key === AI_FOOTER_KEY) continue;
29957
- if (key === LOGO_PLACEHOLDER_KEY) continue;
29958
- if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
29959
29856
  if (key === BRAND_KIT_KEY) continue;
29960
29857
  if (key === STYLE_STORE_KEY) continue;
29961
29858
  if (BRAND_CHROME_KEYS.has(key)) continue;
29859
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
29962
29860
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
29861
+ if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
29963
29862
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
29964
29863
  continue;
29965
29864
  }
@@ -30595,12 +30494,6 @@ function OhhwellsBridge() {
30595
30494
  closeLinkPopoverRef.current();
30596
30495
  return;
30597
30496
  }
30598
- if (floatingPanelOpenRef.current) {
30599
- setFloatingPanelRef.current(null);
30600
- deselectRef.current();
30601
- deactivateRef.current();
30602
- return;
30603
- }
30604
30497
  deselectRef.current();
30605
30498
  deactivateRef.current();
30606
30499
  clearMediaSelectionRef.current();
@@ -31423,10 +31316,10 @@ function OhhwellsBridge() {
31423
31316
  window.removeEventListener("message", handleDeleteSection);
31424
31317
  window.removeEventListener("message", handleDuplicateSection);
31425
31318
  window.removeEventListener("message", handleDeactivate);
31319
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
31426
31320
  window.removeEventListener("message", handleToastAction);
31427
31321
  window.removeEventListener("message", handleFormCount);
31428
31322
  window.removeEventListener("message", handleUiEscape);
31429
- document.documentElement.removeAttribute("data-ohw-panel-dragging");
31430
31323
  autoSaveTimers.current.forEach(clearTimeout);
31431
31324
  autoSaveTimers.current.clear();
31432
31325
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
@@ -31720,7 +31613,7 @@ function OhhwellsBridge() {
31720
31613
  postToParent2({
31721
31614
  type: "ow:ready",
31722
31615
  version: "1",
31723
- bridgeVersion: "0.1.149",
31616
+ bridgeVersion: "0.1.148",
31724
31617
  path: pathname,
31725
31618
  nodes: collectEditableNodes(editContentRef.current),
31726
31619
  sections
@@ -32456,7 +32349,7 @@ function OhhwellsBridge() {
32456
32349
  className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
32457
32350
  onClick: () => setFieldTypePickerOpen((open) => !open),
32458
32351
  "data-ohw-add-field": "",
32459
- children: /* @__PURE__ */ jsx39(Plus6, { size: 15, "aria-hidden": true })
32352
+ children: /* @__PURE__ */ jsx39(Plus5, { size: 15, "aria-hidden": true })
32460
32353
  }
32461
32354
  ),
32462
32355
  /* @__PURE__ */ jsx39("div", { className: "mx-0.5 h-5 w-px bg-border" }),