@ohhwells/bridge 0.1.151-next.406 → 0.1.152

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
  }
@@ -7749,7 +7734,7 @@ var AI_MOBILE_CSS = [
7749
7734
  // page's first section. Top only (bottom needs no nav clearance); ~96px approximates the
7750
7735
  // template nav's own height (measured ~94px) — there's no shared `--ohw-header-h` var to read
7751
7736
  // an exact figure from (no live measurement exists), so this is a safe approximation, not a
7752
- // pixel-exact fit. Horizontal spacing already comes from `data-ai-section-inner`.
7737
+ // pixel-exact fit. Horizontal spacing already comes from `data-ai-container`.
7753
7738
  '[data-ai-overlay-clearance] [data-ai-overlap-layer="overlay"]{padding-top:96px}',
7754
7739
  // A full-bleed carousel's height is pure arithmetic: it spans the whole window, so 16/9 turns
7755
7740
  // window width straight into height. Measured at 16/9 it came out ~90% of the viewport at EVERY
@@ -7765,10 +7750,8 @@ var AI_MOBILE_CSS = [
7765
7750
  "[data-ai-section]{overflow-x:hidden}",
7766
7751
  // `:not([data-ai-full-bleed])`: this `!important` gutter beat the inline `padding: 0` that a
7767
7752
  // full-bleed section's container sets, so a carousel/media hero that is edge-to-edge on desktop
7768
- // still got a 20px band of section background down both sides on a phone. The footer's own
7769
- // container keeps the unguarded rule below — `data-ai-full-bleed` can never appear on it.
7770
- "[data-ai-section-inner]:not([data-ai-full-bleed]){padding:0 20px !important}",
7771
- "[data-ai-container]{padding:0 20px !important}",
7753
+ // still got a 20px band of section background down both sides on a phone.
7754
+ "[data-ai-container]:not([data-ai-full-bleed]){padding:0 20px !important}",
7772
7755
  "[data-ai-row]{display:flex !important;flex-direction:column !important;align-items:stretch !important}",
7773
7756
  "[data-ai-cell]{width:100%;min-width:0}",
7774
7757
  // The rule above turns every row into a COLUMN flex container on phones, which silently breaks
@@ -7973,31 +7956,6 @@ function pricingCardEmphasis(featured, ctx, hasBg) {
7973
7956
  function textAttrs(ctx, path) {
7974
7957
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
7975
7958
  }
7976
- var AI_RESPONSIVE_CSS = [
7977
- "@media (max-width: 960px) {",
7978
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
7979
- ' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
7980
- "}",
7981
- "@media (max-width: 640px) {",
7982
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
7983
- " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
7984
- // Group containers flatten to a column on phones; span placements come along for free.
7985
- // `:not([data-ai-group="overlap"])` for the same reason as the twin pair in AI_MOBILE_CSS — see
7986
- // the comment there. This sheet's copy is the narrower selector, so without the exemption it
7987
- // flattens an `overlap` hero below 640px even though the other rule stands down: measured a 390px
7988
- // viewport with the heading/CTA in flow *under* the image, 219px of section background where the
7989
- // layered text used to be.
7990
- ' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) { display: flex !important; flex-direction: column !important; }',
7991
- ' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) > * { grid-column: auto !important; }',
7992
- // `:not([data-ai-full-bleed])` for the same reason as the twin rule in AI_MOBILE_CSS: this one
7993
- // is narrower (0,2,0 vs 0,1,0) and also `!important`, so without the guard it wins outright and
7994
- // a full-bleed hero gets its 20px side band back below 640px only — the one width where the
7995
- // other rule had already been taught to stand down.
7996
- " [data-ai-responsive] [data-ai-section-inner]:not([data-ai-full-bleed]) { padding-left: 20px !important; padding-right: 20px !important; }",
7997
- " [data-ai-responsive] { overflow-x: hidden; }",
7998
- " [data-ai-responsive] img { max-width: 100%; }",
7999
- "}"
8000
- ].join("\n");
8001
7959
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
8002
7960
  function MediaBox({
8003
7961
  refValue,
@@ -8052,7 +8010,7 @@ function MediaBox({
8052
8010
  position: fill ? "absolute" : void 0,
8053
8011
  inset: fill ? 0 : void 0,
8054
8012
  width: fill ? "100%" : fixedSize ? "auto" : "100%",
8055
- height: fill ? "100%" : fixedSize ? height : void 0,
8013
+ height: fill ? "100%" : void 0,
8056
8014
  aspectRatio: fill ? void 0 : aspectRatio,
8057
8015
  minHeight: fill || fixedSize ? void 0 : height ?? (aspectRatio ? void 0 : 180),
8058
8016
  borderRadius: radius,
@@ -9548,7 +9506,7 @@ function CollectionBlock({ node, ctx, path }) {
9548
9506
  return /* @__PURE__ */ jsx(
9549
9507
  "div",
9550
9508
  {
9551
- "data-ai-grid": String(itemsPerRow),
9509
+ "data-ai-grid": "",
9552
9510
  "data-ohw-pricing-collection": isPricing ? "" : void 0,
9553
9511
  style: {
9554
9512
  display: "grid",
@@ -9850,7 +9808,7 @@ function renderNode(node, ctx, path, ambientAlign) {
9850
9808
  },
9851
9809
  children: [
9852
9810
  i > 0 && ctx.heroOverlapFullBleed ? (
9853
- // The section's `data-ai-section-inner` gave up its max-width/gutter so the base
9811
+ // The section's `data-ai-container` gave up its max-width/gutter so the base
9854
9812
  // layer (this group's i===0 sibling) can span edge-to-edge — reintroduced here,
9855
9813
  // scoped to just the overlay text, so a heading/copy/CTA stack doesn't stretch
9856
9814
  // the full section width instead of reading at the usual content width.
@@ -10269,7 +10227,6 @@ function AiTreeRenderer({
10269
10227
  ...fillHeight ? { "data-ai-fill-height": "" } : {},
10270
10228
  ...needsOverlayClearance ? { "data-ai-overlay-clearance": "" } : {},
10271
10229
  ...bgAttrs,
10272
- "data-ai-responsive": "",
10273
10230
  style: {
10274
10231
  position: "relative",
10275
10232
  padding: `${padCss} 0`,
@@ -10283,13 +10240,12 @@ function AiTreeRenderer({
10283
10240
  ...fillHeight ? { display: "grid" } : {}
10284
10241
  },
10285
10242
  children: [
10286
- /* @__PURE__ */ jsx("style", { children: AI_RESPONSIVE_CSS }),
10287
- /* @__PURE__ */ jsx("style", { children: AI_MOBILE_CSS }),
10288
10243
  isOverlay && backgroundUrl && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
10244
+ /* @__PURE__ */ jsx("style", { children: AI_MOBILE_CSS }),
10289
10245
  /* @__PURE__ */ jsx(
10290
10246
  "div",
10291
10247
  {
10292
- "data-ai-section-inner": "",
10248
+ "data-ai-container": "",
10293
10249
  ...fullBleedMedia ? { "data-ai-full-bleed": "" } : {},
10294
10250
  style: {
10295
10251
  position: "relative",
@@ -10306,7 +10262,7 @@ function AiTreeRenderer({
10306
10262
  children: tree.rows.map((row, r2) => /* @__PURE__ */ jsx(
10307
10263
  "div",
10308
10264
  {
10309
- "data-ai-columns": "",
10265
+ "data-ai-row": "",
10310
10266
  style: {
10311
10267
  display: "grid",
10312
10268
  gridTemplateColumns: "repeat(12, 1fr)",
@@ -10968,10 +10924,9 @@ function applyAiSectionsToDom(state, options) {
10968
10924
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
10969
10925
  continue;
10970
10926
  }
10927
+ const isNewMount = !existing || !existing.container.isConnected;
10971
10928
  let container = existing?.container;
10972
- let isNewMount = false;
10973
10929
  if (!container || !container.isConnected) {
10974
- isNewMount = true;
10975
10930
  existing?.root.unmount();
10976
10931
  container?.remove();
10977
10932
  container = document.createElement("div");
@@ -17555,7 +17510,6 @@ function MediaOverlay({
17555
17510
  (prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
17556
17511
  );
17557
17512
  }, [isVideo]);
17558
- const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
17559
17513
  const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
17560
17514
  const box = {
17561
17515
  position: "fixed",
@@ -17654,10 +17608,11 @@ function MediaOverlay({
17654
17608
  className: "flex items-center justify-center cursor-pointer",
17655
17609
  style: {
17656
17610
  ...box,
17657
- // Visual only. `pointer-events: auto` on this full-bleed rect covered the navbar
17658
- // (hero bg includes the absolute TopNav) and swallowed CTA press-drag. Text overlay
17659
- // and cueOnly also need clicks to fall through — Replace / video controls opt back in.
17660
- pointerEvents: "none",
17611
+ // When text overlays this media, let clicks fall THROUGH to the text underneath. In the
17612
+ // parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
17613
+ // in-document, pointer-events does it natively. The button below opts back in, so
17614
+ // Replace still works.
17615
+ pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
17661
17616
  // Selected: a firm component ring with no wash, so the image reads as chosen rather
17662
17617
  // than hovered. Hover keeps the existing tinted preview.
17663
17618
  boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
@@ -17684,17 +17639,17 @@ function MediaOverlay({
17684
17639
  },
17685
17640
  children: [
17686
17641
  isVideo ? /* @__PURE__ */ jsx17(Film, { size: 14 }) : /* @__PURE__ */ jsx17(ImageIcon, { size: 14 }),
17687
- replaceLabel
17642
+ isVideo ? "Replace video" : "Replace image"
17688
17643
  ]
17689
17644
  }
17690
17645
  ),
17691
- showChrome && replaceMode !== "none" && /* @__PURE__ */ jsxs8(
17646
+ replaceMode === "none" || cueOnly ? null : /* @__PURE__ */ jsxs8(
17692
17647
  Button,
17693
17648
  {
17694
17649
  "data-ohw-media-overlay": "",
17695
17650
  variant: "outline",
17696
17651
  size: "sm",
17697
- "aria-label": replaceLabel,
17652
+ "aria-label": isVideo ? "Replace video" : "Replace image",
17698
17653
  className: "gap-1.5 cursor-pointer hover:bg-background",
17699
17654
  style: {
17700
17655
  ...OVERLAY_BUTTON_STYLE,
@@ -17717,7 +17672,7 @@ function MediaOverlay({
17717
17672
  },
17718
17673
  children: [
17719
17674
  isVideo ? /* @__PURE__ */ jsx17(Film, { size: 14 }) : /* @__PURE__ */ jsx17(ImageIcon, { size: 14 }),
17720
- replaceMode === "full" ? replaceLabel : null
17675
+ replaceMode === "full" ? isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image" : null
17721
17676
  ]
17722
17677
  }
17723
17678
  )
@@ -18226,24 +18181,8 @@ function AiSectionOverlay({
18226
18181
  }
18227
18182
 
18228
18183
  // src/ui/ai-section/AiMediaStripOverlay.tsx
18229
- import { useCallback as useCallback3, useEffect as useEffect6, useLayoutEffect as useLayoutEffect4, useRef as useRef5, useState as useState8 } from "react";
18230
- import {
18231
- AlignCenter,
18232
- AlignLeft,
18233
- AlignRight,
18234
- ArrowLeft as ArrowLeft2,
18235
- ArrowRight as ArrowRight2,
18236
- Check as Check2,
18237
- ChevronDown as ChevronDown3,
18238
- Image as ImageIcon2,
18239
- ImageMinus,
18240
- ImagePlus,
18241
- Link as LinkIcon,
18242
- Minus,
18243
- Palette,
18244
- Plus as Plus2,
18245
- Star
18246
- } from "lucide-react";
18184
+ import { useCallback as useCallback3, useEffect as useEffect6, useRef as useRef5, useState as useState8 } from "react";
18185
+ import { Star } from "lucide-react";
18247
18186
 
18248
18187
  // src/lib/ai-media-strip-tree.ts
18249
18188
  var MEDIA_STRIP_ITEM_MIN = 1;
@@ -18357,6 +18296,14 @@ function setMediaStripItemAsset(tree, index, assetId) {
18357
18296
  return true;
18358
18297
  });
18359
18298
  }
18299
+ function setMediaStripItemAlt(tree, index, alt) {
18300
+ return withMediaStrip(tree, (block) => {
18301
+ const items = block.items;
18302
+ if (index < 0 || index >= items.length) return false;
18303
+ items[index] = { ...items[index], alt };
18304
+ return true;
18305
+ });
18306
+ }
18360
18307
  function setMediaStripItemLink(tree, index, link) {
18361
18308
  return withMediaStrip(tree, (block) => {
18362
18309
  const items = block.items;
@@ -18374,117 +18321,11 @@ function setMediaStripItemLink(tree, index, link) {
18374
18321
  });
18375
18322
  }
18376
18323
 
18377
- // src/ui/dialog.tsx
18378
- import * as React9 from "react";
18379
- import { Dialog as DialogPrimitive } from "radix-ui";
18380
- import { X as X2 } from "lucide-react";
18381
- import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
18382
- function Dialog2({
18383
- ...props
18384
- }) {
18385
- return /* @__PURE__ */ jsx20(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
18386
- }
18387
- function DialogPortal({
18388
- ...props
18389
- }) {
18390
- return /* @__PURE__ */ jsx20(DialogPrimitive.Portal, { ...props });
18391
- }
18392
- function DialogOverlay({
18393
- className,
18394
- ...props
18395
- }) {
18396
- return /* @__PURE__ */ jsx20(
18397
- DialogPrimitive.Overlay,
18398
- {
18399
- "data-slot": "dialog-overlay",
18400
- "data-ohw-link-modal-root": "",
18401
- className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
18402
- ...props
18403
- }
18404
- );
18405
- }
18406
- var DialogContent = React9.forwardRef(
18407
- ({ className, children, showCloseButton = true, container, ...props }, ref) => {
18408
- const positionMode = container ? "absolute" : "fixed";
18409
- return /* @__PURE__ */ jsxs11(DialogPortal, { container: container ?? void 0, children: [
18410
- /* @__PURE__ */ jsx20(DialogOverlay, { className: cn(positionMode, "inset-0") }),
18411
- /* @__PURE__ */ jsxs11(
18412
- DialogPrimitive.Content,
18413
- {
18414
- ref,
18415
- "data-slot": "dialog-content",
18416
- className: cn(
18417
- positionMode,
18418
- "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",
18419
- "rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
18420
- container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
18421
- className
18422
- ),
18423
- onMouseDown: (e) => e.stopPropagation(),
18424
- ...props,
18425
- children: [
18426
- children,
18427
- showCloseButton ? /* @__PURE__ */ jsx20(
18428
- DialogPrimitive.Close,
18429
- {
18430
- type: "button",
18431
- className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
18432
- "aria-label": "Close",
18433
- children: /* @__PURE__ */ jsx20(X2, { size: 16, "aria-hidden": true })
18434
- }
18435
- ) : null
18436
- ]
18437
- }
18438
- )
18439
- ] });
18440
- }
18441
- );
18442
- DialogContent.displayName = DialogPrimitive.Content.displayName;
18443
- function DialogHeader({
18444
- className,
18445
- ...props
18446
- }) {
18447
- return /* @__PURE__ */ jsx20("div", { className: cn("flex flex-col gap-1.5", className), ...props });
18448
- }
18449
- function DialogFooter({
18450
- className,
18451
- ...props
18452
- }) {
18453
- return /* @__PURE__ */ jsx20(
18454
- "div",
18455
- {
18456
- className: cn("flex items-center justify-end gap-2", className),
18457
- ...props
18458
- }
18459
- );
18460
- }
18461
- var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
18462
- DialogPrimitive.Title,
18463
- {
18464
- ref,
18465
- className: cn(
18466
- "text-lg font-semibold leading-none tracking-tight text-card-foreground",
18467
- className
18468
- ),
18469
- ...props
18470
- }
18471
- ));
18472
- DialogTitle.displayName = DialogPrimitive.Title.displayName;
18473
- var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
18474
- DialogPrimitive.Description,
18475
- {
18476
- ref,
18477
- className: cn("text-sm text-muted-foreground", className),
18478
- ...props
18479
- }
18480
- ));
18481
- DialogDescription.displayName = DialogPrimitive.Description.displayName;
18482
- var DialogClose = DialogPrimitive.Close;
18483
-
18484
18324
  // src/ui/ai-section/AiMediaStripOverlay.tsx
18485
- import { Fragment as Fragment7, jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
18486
- var PRIMARY3 = "var(--ohw-primary, #0885FE)";
18487
- 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]";
18325
+ import { Fragment as Fragment7, jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
18326
+ var PRIMARY3 = "#0885FE";
18327
+ var OHW_BLUE = `var(--ohw-primary, ${PRIMARY3})`;
18328
+ var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY3}) 60%, #000000)`;
18488
18329
  function findMediaStripItemElement(sectionId, index) {
18489
18330
  const sectionEl = findByInstanceId(sectionId);
18490
18331
  if (!sectionEl) return null;
@@ -18494,35 +18335,14 @@ function findMediaStripItemElement(sectionId, index) {
18494
18335
  }
18495
18336
  return null;
18496
18337
  }
18497
- function itemRefFromTarget(target) {
18498
- if (!(target instanceof Element)) return null;
18499
- if (target.closest(CHROME_SELECTOR)) return null;
18500
- const itemEl = target.closest("[data-ohw-media-strip-item]");
18501
- if (!itemEl) return null;
18502
- const sectionEl = itemEl.closest("[data-ohw-section]");
18503
- const unit = sectionEl ? movableUnit(sectionEl) : null;
18504
- const sectionId = unit ? instanceIdOf(unit) || null : null;
18505
- const index = Number(itemEl.dataset.ohwMediaStripIndex);
18506
- if (!sectionId || Number.isNaN(index)) return null;
18507
- return { sectionId, index };
18508
- }
18509
- function sameRef(a, b) {
18510
- return a?.sectionId === b?.sectionId && a?.index === b?.index;
18511
- }
18512
- function rectOf(el) {
18338
+ function readRect2(ref) {
18339
+ const el = ref && findMediaStripItemElement(ref.sectionId, ref.index);
18513
18340
  if (!el) return null;
18514
18341
  const r2 = el.getBoundingClientRect();
18515
18342
  if (r2.width <= 0 || r2.height <= 0) return null;
18516
18343
  return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
18517
18344
  }
18518
- function readRect2(ref) {
18519
- return rectOf(ref && findMediaStripItemElement(ref.sectionId, ref.index));
18520
- }
18521
- function readStripRect(ref) {
18522
- const item = ref && findMediaStripItemElement(ref.sectionId, ref.index);
18523
- return rectOf(item?.closest("[data-ohw-media-strip]") ?? item);
18524
- }
18525
- function useLiveItemRect(ref, strip = false) {
18345
+ function useLiveItemRect(ref) {
18526
18346
  const [rect, setRect] = useState8(null);
18527
18347
  useEffect6(() => {
18528
18348
  if (!ref) {
@@ -18530,7 +18350,7 @@ function useLiveItemRect(ref, strip = false) {
18530
18350
  return;
18531
18351
  }
18532
18352
  const update = () => {
18533
- const next = strip ? readStripRect(ref) : readRect2(ref);
18353
+ const next = readRect2(ref);
18534
18354
  setRect(
18535
18355
  (prev) => prev && next && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
18536
18356
  );
@@ -18545,49 +18365,9 @@ function useLiveItemRect(ref, strip = false) {
18545
18365
  window.removeEventListener("resize", update);
18546
18366
  clearInterval(interval);
18547
18367
  };
18548
- }, [ref?.sectionId, ref?.index, strip]);
18368
+ }, [ref?.sectionId, ref?.index]);
18549
18369
  return rect;
18550
18370
  }
18551
- var TOOLBAR_STRIP_GAP = 52;
18552
- var TOOLBAR_STRIP_GAP_MOBILE = 42;
18553
- var TOOLBAR_EDGE_MARGIN2 = 4;
18554
- function StripToolbarSlot({ stripRect, children }) {
18555
- const slotRef = useRef5(null);
18556
- const [shift, setShift] = useState8(0);
18557
- const centerX = stripRect.left + stripRect.width / 2;
18558
- useLayoutEffect4(() => {
18559
- const slot = slotRef.current;
18560
- if (!slot) return;
18561
- const clamp = () => {
18562
- const w = slot.offsetWidth;
18563
- if (w <= 0) return;
18564
- const half = w / 2;
18565
- const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
18566
- setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
18567
- };
18568
- clamp();
18569
- const ro = new ResizeObserver(clamp);
18570
- ro.observe(slot);
18571
- return () => ro.disconnect();
18572
- }, [centerX, children]);
18573
- const mobile = window.innerWidth <= 480;
18574
- return /* @__PURE__ */ jsx21(
18575
- "div",
18576
- {
18577
- ref: slotRef,
18578
- "data-ohw-bridge": "",
18579
- "data-ohw-item-interaction": "",
18580
- className: "pointer-events-auto fixed",
18581
- style: {
18582
- top: stripRect.top - (mobile ? TOOLBAR_STRIP_GAP_MOBILE : TOOLBAR_STRIP_GAP),
18583
- left: centerX + shift,
18584
- transform: "translate(-50%, -100%)",
18585
- zIndex: 2147483645
18586
- },
18587
- children
18588
- }
18589
- );
18590
- }
18591
18371
  function requestValidateTree(postToParent2, tree) {
18592
18372
  return new Promise((resolve) => {
18593
18373
  const id = `ai-validate-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
@@ -18624,72 +18404,116 @@ function requestAssetPick(postToParent2) {
18624
18404
  postToParent2({ type: "ow:asset-pick", id });
18625
18405
  });
18626
18406
  }
18627
- function ToolbarAction({
18407
+ function Pill({
18628
18408
  label,
18629
18409
  onClick,
18630
- disabled = false,
18631
- active = false,
18632
- children
18410
+ disabled,
18411
+ active
18633
18412
  }) {
18634
- const button = /* @__PURE__ */ jsx21(CustomToolbarButton, { type: "button", "aria-label": label, disabled, active, onClick, className: "size-8", children });
18635
- return /* @__PURE__ */ jsxs12(Tooltip, { children: [
18636
- /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx21("span", { className: "inline-flex", children: button }) : button }),
18637
- /* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
18638
- ] });
18639
- }
18640
- function ToolbarSeparator() {
18641
- return /* @__PURE__ */ jsx21("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
18413
+ return /* @__PURE__ */ jsx20(
18414
+ "button",
18415
+ {
18416
+ type: "button",
18417
+ onClick,
18418
+ disabled,
18419
+ style: {
18420
+ height: 28,
18421
+ padding: "0 10px",
18422
+ display: "inline-flex",
18423
+ alignItems: "center",
18424
+ gap: 4,
18425
+ borderRadius: 999,
18426
+ border: "none",
18427
+ cursor: disabled ? "default" : "pointer",
18428
+ background: active ? OHW_BLUE_DARK : "#ffffff",
18429
+ color: active ? "#ffffff" : OHW_BLUE_DARK,
18430
+ opacity: disabled ? 0.4 : 1,
18431
+ fontSize: 12,
18432
+ lineHeight: "16px",
18433
+ fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
18434
+ whiteSpace: "nowrap",
18435
+ flex: "0 0 auto"
18436
+ },
18437
+ children: label
18438
+ }
18439
+ );
18642
18440
  }
18643
- function OptionMenu({
18644
- label,
18645
- value,
18646
- options,
18647
- onChange
18648
- }) {
18649
- const current = options.find((o) => o.value === value) ?? options[0];
18650
- return /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
18651
- /* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground", children: label }),
18652
- /* @__PURE__ */ jsxs12(DropdownMenu, { modal: false, children: [
18653
- /* @__PURE__ */ jsx21(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs12(
18654
- "button",
18655
- {
18656
- type: "button",
18657
- "aria-label": label,
18658
- 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",
18659
- children: [
18660
- /* @__PURE__ */ jsx21("span", { className: "flex-1 text-left", children: current.label }),
18661
- /* @__PURE__ */ jsx21(ChevronDown3, { size: 16, style: { pointerEvents: "none" } })
18662
- ]
18663
- }
18664
- ) }),
18665
- /* @__PURE__ */ jsx21(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[132px] min-w-[132px] p-1", children: options.map((option) => {
18666
- const selected = option.value === value;
18667
- return /* @__PURE__ */ jsxs12(
18668
- DropdownMenuItem,
18441
+ function AltInput({ value, onCommit }) {
18442
+ const [draft, setDraft] = useState8(value);
18443
+ useEffect6(() => setDraft(value), [value]);
18444
+ return /* @__PURE__ */ jsxs11(
18445
+ "div",
18446
+ {
18447
+ style: {
18448
+ display: "flex",
18449
+ alignItems: "center",
18450
+ gap: 6,
18451
+ height: 28,
18452
+ padding: "0 12px",
18453
+ borderRadius: 999,
18454
+ background: "#ffffff",
18455
+ width: "100%",
18456
+ maxWidth: 260,
18457
+ boxSizing: "border-box"
18458
+ },
18459
+ children: [
18460
+ /* @__PURE__ */ jsx20(
18461
+ "span",
18669
18462
  {
18670
- role: "menuitemradio",
18671
- "aria-checked": selected,
18672
- onSelect: () => onChange(option.value),
18673
- className: cn("grid grid-cols-[1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
18674
- children: [
18675
- /* @__PURE__ */ jsx21("span", { children: option.label }),
18676
- selected && /* @__PURE__ */ jsx21(Check2, { size: 16, className: "text-bridge-primary" })
18677
- ]
18678
- },
18679
- option.value
18680
- );
18681
- }) })
18682
- ] })
18683
- ] });
18463
+ style: {
18464
+ flex: "0 0 auto",
18465
+ color: OHW_BLUE_DARK,
18466
+ fontSize: 10,
18467
+ fontWeight: 700,
18468
+ textTransform: "uppercase",
18469
+ letterSpacing: 0.4
18470
+ },
18471
+ children: "Alt"
18472
+ }
18473
+ ),
18474
+ /* @__PURE__ */ jsx20(
18475
+ "input",
18476
+ {
18477
+ type: "text",
18478
+ value: draft,
18479
+ onChange: (e) => setDraft(e.target.value),
18480
+ onBlur: () => {
18481
+ if (draft !== value) onCommit(draft);
18482
+ },
18483
+ onKeyDown: (e) => {
18484
+ if (e.key === "Enter") e.currentTarget.blur();
18485
+ if (e.key === "Escape") {
18486
+ setDraft(value);
18487
+ e.currentTarget.blur();
18488
+ }
18489
+ },
18490
+ placeholder: "Describe this image",
18491
+ "aria-label": "Image alt text",
18492
+ style: {
18493
+ flex: 1,
18494
+ minWidth: 0,
18495
+ border: "none",
18496
+ outline: "none",
18497
+ background: "transparent",
18498
+ fontSize: 12,
18499
+ lineHeight: "16px",
18500
+ fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
18501
+ color: "#1f2937"
18502
+ }
18503
+ }
18504
+ )
18505
+ ]
18506
+ }
18507
+ );
18684
18508
  }
18685
18509
  var VARIANTS = [
18686
18510
  { value: "logos", label: "Logos" },
18687
18511
  { value: "reel", label: "Reel" }
18688
18512
  ];
18689
18513
  var ALIGNS = [
18690
- { value: "left", label: "Align left", Icon: AlignLeft },
18691
- { value: "center", label: "Align center", Icon: AlignCenter },
18692
- { value: "right", label: "Align right", Icon: AlignRight }
18514
+ { value: "left", label: "Left" },
18515
+ { value: "center", label: "Center" },
18516
+ { value: "right", label: "Right" }
18693
18517
  ];
18694
18518
  var HOVERS = [
18695
18519
  { value: "none", label: "None" },
@@ -18697,104 +18521,104 @@ var HOVERS = [
18697
18521
  { value: "zoom", label: "Zoom" },
18698
18522
  { value: "fade", label: "Fade" }
18699
18523
  ];
18524
+ var TREATMENTS = [
18525
+ { value: "color", label: "Color" },
18526
+ { value: "grayscale", label: "Grayscale" }
18527
+ ];
18700
18528
  var HTTP_URL_RE = /^https?:\/\/\S+$/i;
18701
- function LinkModal({
18702
- href,
18703
- linkTarget,
18704
- onClose,
18705
- onSave
18706
- }) {
18707
- const [draft, setDraft] = useState8(href);
18708
- const [newTab, setNewTab] = useState8(linkTarget !== "same-tab");
18529
+ function LinkInput({ value, onCommit }) {
18530
+ const [draft, setDraft] = useState8(value);
18709
18531
  const [invalid, setInvalid] = useState8(false);
18710
- const save = () => {
18532
+ useEffect6(() => {
18533
+ setDraft(value);
18534
+ setInvalid(false);
18535
+ }, [value]);
18536
+ const commit = () => {
18711
18537
  const next = draft.trim();
18712
- if (next && !HTTP_URL_RE.test(next)) {
18713
- setInvalid(true);
18714
- return;
18715
- }
18716
- onSave(next, newTab ? "new-tab" : "same-tab");
18717
- onClose();
18538
+ if (next === value) return setInvalid(false);
18539
+ if (next && !HTTP_URL_RE.test(next)) return setInvalid(true);
18540
+ setInvalid(false);
18541
+ onCommit(next);
18718
18542
  };
18719
- return /* @__PURE__ */ jsx21(Dialog2, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxs12(DialogContent, { "data-ohw-link-modal-root": "", className: "max-w-[400px] gap-4 p-5", children: [
18720
- /* @__PURE__ */ jsx21(DialogHeader, { children: /* @__PURE__ */ jsx21(DialogTitle, { className: "text-base", children: "Image link" }) }),
18721
- /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-3", children: [
18722
- /* @__PURE__ */ jsx21(
18723
- "input",
18724
- {
18725
- autoFocus: true,
18726
- type: "text",
18727
- inputMode: "url",
18728
- value: draft,
18729
- onChange: (e) => {
18730
- setDraft(e.target.value);
18731
- setInvalid(false);
18732
- },
18733
- onKeyDown: (e) => {
18734
- if (e.key === "Enter") save();
18735
- },
18736
- placeholder: "https://example.com",
18737
- "aria-label": "Image link URL",
18738
- "aria-invalid": invalid,
18739
- className: cn(
18740
- "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",
18741
- invalid && "border-destructive focus:border-destructive"
18742
- )
18743
- }
18744
- ),
18745
- invalid && /* @__PURE__ */ jsx21("p", { className: "text-xs text-destructive", children: "Enter a full URL starting with http:// or https://" }),
18746
- /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-2 text-[13px] text-foreground", children: [
18747
- /* @__PURE__ */ jsx21("input", { type: "checkbox", checked: newTab, onChange: (e) => setNewTab(e.target.checked) }),
18748
- "Open in new tab"
18749
- ] })
18750
- ] }),
18751
- /* @__PURE__ */ jsxs12(DialogFooter, { children: [
18752
- href && /* @__PURE__ */ jsx21(
18753
- "button",
18754
- {
18755
- type: "button",
18756
- onClick: () => {
18757
- onSave("", "new-tab");
18758
- onClose();
18759
- },
18760
- className: "mr-auto rounded-[6px] px-3 py-2 text-[13px] font-medium text-destructive transition-colors hover:bg-muted",
18761
- children: "Remove link"
18762
- }
18763
- ),
18764
- /* @__PURE__ */ jsx21(
18765
- "button",
18766
- {
18767
- type: "button",
18768
- onClick: onClose,
18769
- className: "rounded-[6px] px-3 py-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted",
18770
- children: "Cancel"
18771
- }
18772
- ),
18773
- /* @__PURE__ */ jsx21(
18774
- "button",
18775
- {
18776
- type: "button",
18777
- onClick: save,
18778
- className: "rounded-[6px] bg-bridge-primary px-3 py-2 text-[13px] font-medium text-primary-foreground transition-opacity hover:opacity-90",
18779
- children: "Save"
18780
- }
18781
- )
18782
- ] })
18783
- ] }) });
18543
+ return /* @__PURE__ */ jsxs11(
18544
+ "div",
18545
+ {
18546
+ style: {
18547
+ display: "flex",
18548
+ alignItems: "center",
18549
+ gap: 6,
18550
+ height: 28,
18551
+ padding: "0 12px",
18552
+ borderRadius: 999,
18553
+ background: "#ffffff",
18554
+ width: "100%",
18555
+ maxWidth: 260,
18556
+ boxSizing: "border-box",
18557
+ boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
18558
+ },
18559
+ children: [
18560
+ /* @__PURE__ */ jsx20(
18561
+ "span",
18562
+ {
18563
+ style: {
18564
+ flex: "0 0 auto",
18565
+ color: OHW_BLUE_DARK,
18566
+ fontSize: 10,
18567
+ fontWeight: 700,
18568
+ textTransform: "uppercase",
18569
+ letterSpacing: 0.4
18570
+ },
18571
+ children: "Link"
18572
+ }
18573
+ ),
18574
+ /* @__PURE__ */ jsx20(
18575
+ "input",
18576
+ {
18577
+ type: "text",
18578
+ inputMode: "url",
18579
+ value: draft,
18580
+ onChange: (e) => setDraft(e.target.value),
18581
+ onBlur: commit,
18582
+ onKeyDown: (e) => {
18583
+ if (e.key === "Enter") e.currentTarget.blur();
18584
+ if (e.key === "Escape") {
18585
+ setDraft(value);
18586
+ setInvalid(false);
18587
+ e.currentTarget.blur();
18588
+ }
18589
+ },
18590
+ placeholder: "https://example.com",
18591
+ "aria-label": "Image link URL",
18592
+ "aria-invalid": invalid,
18593
+ style: {
18594
+ flex: 1,
18595
+ minWidth: 0,
18596
+ border: "none",
18597
+ outline: "none",
18598
+ background: "transparent",
18599
+ fontSize: 12,
18600
+ lineHeight: "16px",
18601
+ fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
18602
+ color: "#1f2937"
18603
+ }
18604
+ }
18605
+ )
18606
+ ]
18607
+ }
18608
+ );
18784
18609
  }
18785
18610
  function MediaStripToolbar({
18786
18611
  entry,
18787
18612
  index,
18788
18613
  pending,
18789
18614
  error,
18790
- itemEditOn,
18791
- onToggleItemEdit,
18792
18615
  onSetVariant,
18793
18616
  onSetAlign,
18794
18617
  onSetHover,
18795
18618
  onSetTreatment,
18796
18619
  onResize,
18797
- onOpenLink,
18620
+ onSetAlt,
18621
+ onSetLink,
18798
18622
  onAddItem,
18799
18623
  onRemoveItem,
18800
18624
  onChangeImage,
@@ -18803,102 +18627,81 @@ function MediaStripToolbar({
18803
18627
  }) {
18804
18628
  const items = mediaStripItems(entry.tree);
18805
18629
  const itemCount = items.length;
18630
+ const currentAlt = items[index]?.alt ?? "";
18631
+ const currentHref = items[index]?.href ?? "";
18632
+ const currentTarget = items[index]?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
18806
18633
  const slots = findMediaStripSlots(entry.tree);
18807
18634
  const variant = slots?.variant === "reel" ? "reel" : "logos";
18808
18635
  const align = slots?.align === "left" || slots?.align === "right" ? slots.align : "center";
18809
18636
  const hover = slots?.hover === "none" || slots?.hover === "lift" || slots?.hover === "zoom" || slots?.hover === "fade" ? slots.hover : "lift";
18810
18637
  const treatment = slots?.treatment === "color" || slots?.treatment === "grayscale" ? slots.treatment : variant === "logos" ? "grayscale" : "color";
18811
18638
  const sizeValue = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
18812
- const mobile = window.innerWidth <= 480;
18813
- const gatedLabel = (label) => itemEditOn ? label : "Turn on the star to edit this image";
18814
- return /* @__PURE__ */ jsx21(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs12(
18639
+ const isMobile = window.innerWidth <= 480;
18640
+ const rowStyle = isMobile ? {
18641
+ display: "flex",
18642
+ gap: 6,
18643
+ flexWrap: "nowrap",
18644
+ justifyContent: "center",
18645
+ overflowX: "auto",
18646
+ WebkitOverflowScrolling: "touch",
18647
+ width: "100%",
18648
+ scrollbarWidth: "none"
18649
+ } : { display: "flex", gap: 6, flexWrap: "nowrap", justifyContent: "center" };
18650
+ return /* @__PURE__ */ jsxs11(
18815
18651
  "div",
18816
18652
  {
18817
18653
  "data-ohw-bridge": "",
18818
18654
  "data-ohw-toolbar": "",
18819
18655
  onMouseDown: (e) => e.stopPropagation(),
18820
- className: cn("flex flex-col items-center gap-1.5 font-sans", pending && "pointer-events-none opacity-60"),
18821
- style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
18656
+ style: {
18657
+ display: "flex",
18658
+ flexDirection: "column",
18659
+ gap: 6,
18660
+ alignItems: "center",
18661
+ background: OHW_BLUE,
18662
+ padding: 8,
18663
+ borderRadius: 12,
18664
+ boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
18665
+ pointerEvents: pending ? "none" : "auto",
18666
+ opacity: pending ? 0.6 : 1,
18667
+ maxWidth: isMobile ? "calc(100vw - 24px)" : "none"
18668
+ },
18822
18669
  children: [
18823
- /* @__PURE__ */ jsxs12(
18824
- "div",
18825
- {
18826
- className: cn(
18827
- "flex items-center gap-1 rounded-[10px] border border-border bg-background p-1 whitespace-nowrap",
18828
- "shadow-[0px_10px_15px_-3px_rgba(0,0,0,0.1),0px_4px_6px_-4px_rgba(0,0,0,0.1)]",
18829
- mobile ? "flex-wrap justify-center" : "flex-nowrap"
18830
- ),
18831
- children: [
18832
- /* @__PURE__ */ jsxs12(Tooltip, { children: [
18833
- /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx21(
18834
- CustomToolbarButton,
18835
- {
18836
- type: "button",
18837
- "aria-label": itemEditOn ? "Done editing this image" : "Edit this image",
18838
- "aria-pressed": itemEditOn,
18839
- onClick: onToggleItemEdit,
18840
- className: "group size-8",
18841
- children: /* @__PURE__ */ jsx21(
18842
- Star,
18843
- {
18844
- size: 16,
18845
- fill: "currentColor",
18846
- strokeWidth: 0,
18847
- className: cn(
18848
- "transition-colors",
18849
- itemEditOn ? "text-[#f59e0b] group-hover:text-[#d97706]" : "text-[#d6d3d1] group-hover:text-[#fbbf24]"
18850
- ),
18851
- style: { pointerEvents: "none" }
18852
- }
18853
- )
18854
- }
18855
- ) }),
18856
- /* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: itemEditOn ? "Done editing this image" : "Edit this image" })
18857
- ] }),
18858
- /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
18859
- /* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Change image"), onClick: onChangeImage, disabled: !itemEditOn, children: /* @__PURE__ */ jsx21(ImageIcon2, { size: 16, style: { pointerEvents: "none" } }) }),
18860
- /* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Link"), onClick: onOpenLink, disabled: !itemEditOn, children: /* @__PURE__ */ jsx21(LinkIcon, { size: 16, style: { pointerEvents: "none" } }) }),
18861
- /* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Move left"), onClick: onMoveLeft, disabled: !itemEditOn || index <= 0, children: /* @__PURE__ */ jsx21(ArrowLeft2, { size: 16, style: { pointerEvents: "none" } }) }),
18862
- /* @__PURE__ */ jsx21(
18863
- ToolbarAction,
18864
- {
18865
- label: gatedLabel("Move right"),
18866
- onClick: onMoveRight,
18867
- disabled: !itemEditOn || index >= itemCount - 1,
18868
- children: /* @__PURE__ */ jsx21(ArrowRight2, { size: 16, style: { pointerEvents: "none" } })
18869
- }
18870
- ),
18871
- /* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Remove image"), onClick: onRemoveItem, disabled: !itemEditOn || itemCount <= 1, children: /* @__PURE__ */ jsx21(ImageMinus, { size: 16, style: { pointerEvents: "none" } }) }),
18872
- /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
18873
- /* @__PURE__ */ jsx21(OptionMenu, { label: "Layout", value: variant, options: VARIANTS, onChange: onSetVariant }),
18874
- /* @__PURE__ */ jsx21(OptionMenu, { label: "Hover", value: hover, options: HOVERS, onChange: onSetHover }),
18875
- /* @__PURE__ */ jsx21(
18876
- ToolbarAction,
18877
- {
18878
- label: treatment === "grayscale" ? "Show in color" : "Show grayscale",
18879
- active: treatment === "grayscale",
18880
- onClick: () => onSetTreatment(treatment === "grayscale" ? "color" : "grayscale"),
18881
- children: /* @__PURE__ */ jsx21(Palette, { size: 16, style: { pointerEvents: "none" } })
18882
- }
18883
- ),
18884
- /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
18885
- ALIGNS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx21(ToolbarAction, { label, active: align === value, onClick: () => onSetAlign(value), children: /* @__PURE__ */ jsx21(Icon, { size: 16, style: { pointerEvents: "none" } }) }, value)),
18886
- /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
18887
- /* @__PURE__ */ jsx21(ToolbarAction, { label: "Smaller", onClick: () => onResize(-8), children: /* @__PURE__ */ jsx21(Minus, { size: 16, style: { pointerEvents: "none" } }) }),
18888
- /* @__PURE__ */ jsxs12("span", { className: "min-w-[40px] text-center text-xs tabular-nums text-muted-foreground", children: [
18889
- sizeValue,
18890
- "px"
18891
- ] }),
18892
- /* @__PURE__ */ jsx21(ToolbarAction, { label: "Larger", onClick: () => onResize(8), children: /* @__PURE__ */ jsx21(Plus2, { size: 16, style: { pointerEvents: "none" } }) }),
18893
- /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
18894
- /* @__PURE__ */ jsx21(ToolbarAction, { label: "Add image", onClick: onAddItem, children: /* @__PURE__ */ jsx21(ImagePlus, { size: 16, style: { pointerEvents: "none" } }) })
18895
- ]
18896
- }
18897
- ),
18898
- 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 })
18670
+ /* @__PURE__ */ jsxs11("div", { style: rowStyle, children: [
18671
+ VARIANTS.map((v) => /* @__PURE__ */ jsx20(Pill, { label: v.label, active: variant === v.value, onClick: () => onSetVariant(v.value) }, v.value)),
18672
+ ALIGNS.map((a) => /* @__PURE__ */ jsx20(Pill, { label: a.label, active: align === a.value, onClick: () => onSetAlign(a.value) }, a.value))
18673
+ ] }),
18674
+ /* @__PURE__ */ jsxs11("div", { style: rowStyle, children: [
18675
+ HOVERS.map((h) => /* @__PURE__ */ jsx20(Pill, { label: h.label, active: hover === h.value, onClick: () => onSetHover(h.value) }, h.value)),
18676
+ TREATMENTS.map((t) => /* @__PURE__ */ jsx20(Pill, { label: t.label, active: treatment === t.value, onClick: () => onSetTreatment(t.value) }, t.value))
18677
+ ] }),
18678
+ /* @__PURE__ */ jsxs11("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
18679
+ /* @__PURE__ */ jsx20(Pill, { label: "\u2212", onClick: () => onResize(-8) }),
18680
+ /* @__PURE__ */ jsxs11("span", { style: { color: "#ffffff", fontSize: 12, minWidth: 34, textAlign: "center" }, children: [
18681
+ sizeValue,
18682
+ "px"
18683
+ ] }),
18684
+ /* @__PURE__ */ jsx20(Pill, { label: "+", onClick: () => onResize(8) })
18685
+ ] }),
18686
+ /* @__PURE__ */ jsx20("div", { style: { display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ jsx20(AltInput, { value: currentAlt, onCommit: onSetAlt }) }),
18687
+ /* @__PURE__ */ jsx20("div", { style: { display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ jsx20(LinkInput, { value: currentHref, onCommit: (href) => onSetLink(href, currentTarget) }) }),
18688
+ currentHref && /* @__PURE__ */ jsxs11("div", { style: rowStyle, children: [
18689
+ /* @__PURE__ */ jsx20(Pill, { label: "New tab", active: currentTarget === "new-tab", onClick: () => onSetLink(currentHref, "new-tab") }),
18690
+ /* @__PURE__ */ jsx20(Pill, { label: "Same tab", active: currentTarget === "same-tab", onClick: () => onSetLink(currentHref, "same-tab") })
18691
+ ] }),
18692
+ /* @__PURE__ */ jsxs11("div", { style: rowStyle, children: [
18693
+ /* @__PURE__ */ jsx20(Pill, { label: "Change Image", onClick: onChangeImage }),
18694
+ /* @__PURE__ */ jsx20(Pill, { label: "+ Item", onClick: onAddItem }),
18695
+ /* @__PURE__ */ jsx20(Pill, { label: "\u2212 Item", onClick: onRemoveItem, disabled: itemCount <= 1 })
18696
+ ] }),
18697
+ /* @__PURE__ */ jsxs11("div", { style: rowStyle, children: [
18698
+ /* @__PURE__ */ jsx20(Pill, { label: "\u2190 Move", onClick: onMoveLeft, disabled: index <= 0 }),
18699
+ /* @__PURE__ */ jsx20(Pill, { label: "\u2192 Move", onClick: onMoveRight, disabled: index >= itemCount - 1 })
18700
+ ] }),
18701
+ error && /* @__PURE__ */ jsx20("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
18899
18702
  ]
18900
18703
  }
18901
- ) });
18704
+ );
18902
18705
  }
18903
18706
  function findMediaStripSlots(tree) {
18904
18707
  const stack = tree.rows.flatMap((row) => row.blocks);
@@ -18917,23 +18720,31 @@ function AiMediaStripOverlay({
18917
18720
  }) {
18918
18721
  const [hover, setHover] = useState8(null);
18919
18722
  const [active, setActive] = useState8(null);
18920
- const [itemEditOn, setItemEditOn] = useState8(false);
18921
- const [linkOpen, setLinkOpen] = useState8(false);
18922
18723
  const [pending, setPending] = useState8(false);
18923
18724
  const [error, setError] = useState8(null);
18924
18725
  const activeRef = useRef5(null);
18925
18726
  activeRef.current = active;
18926
- const linkOpenRef = useRef5(false);
18927
- linkOpenRef.current = linkOpen;
18928
18727
  useEffect6(() => {
18929
18728
  const onMove = (e) => {
18930
- const ref = itemRefFromTarget(e.target);
18931
18729
  const t = e.target;
18932
- const overEditable = Boolean(t?.closest?.("[data-ohw-editable]"));
18933
- setHover((prev) => {
18934
- const next = ref && !overEditable ? ref : null;
18935
- return sameRef(prev, next) ? prev : next;
18936
- });
18730
+ if (!(t instanceof HTMLElement)) return;
18731
+ 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]")) {
18732
+ return;
18733
+ }
18734
+ const itemEl = t.closest("[data-ohw-media-strip-item]");
18735
+ if (!itemEl) {
18736
+ setHover(null);
18737
+ return;
18738
+ }
18739
+ const sectionEl = itemEl.closest("[data-ohw-section]");
18740
+ const unit = sectionEl ? movableUnit(sectionEl) : null;
18741
+ const sectionId = unit ? instanceIdOf(unit) || null : null;
18742
+ const index = Number(itemEl.dataset.ohwMediaStripIndex);
18743
+ if (!sectionId || Number.isNaN(index)) {
18744
+ setHover(null);
18745
+ return;
18746
+ }
18747
+ setHover({ sectionId, index });
18937
18748
  };
18938
18749
  const onLeave = () => setHover(null);
18939
18750
  document.addEventListener("mousemove", onMove, { passive: true });
@@ -18945,25 +18756,23 @@ function AiMediaStripOverlay({
18945
18756
  }, []);
18946
18757
  useEffect6(() => {
18947
18758
  const onClick = (e) => {
18759
+ const current = activeRef.current;
18760
+ if (!current) return;
18948
18761
  const t = e.target;
18949
- if (!(t instanceof Element)) return;
18950
- if (t.closest(CHROME_SELECTOR)) return;
18951
- const ref = itemRefFromTarget(t);
18952
- if (sameRef(activeRef.current, ref)) return;
18953
- if (ref) clearInteractionChromeRef.current();
18954
- setItemEditOn(false);
18762
+ if (!(t instanceof HTMLElement)) return;
18763
+ if (t.closest("[data-ohw-item-interaction]")) return;
18764
+ const itemEl = findMediaStripItemElement(current.sectionId, current.index);
18765
+ if (itemEl && itemEl.contains(t)) return;
18766
+ setActive(null);
18955
18767
  setError(null);
18956
- setActive(ref);
18957
18768
  };
18958
18769
  document.addEventListener("click", onClick, true);
18959
18770
  return () => document.removeEventListener("click", onClick, true);
18960
- }, [clearInteractionChromeRef]);
18771
+ }, []);
18961
18772
  useEffect6(() => {
18962
18773
  const onBlur = () => {
18963
18774
  if (!activeRef.current) return;
18964
18775
  setActive(null);
18965
- setItemEditOn(false);
18966
- setLinkOpen(false);
18967
18776
  setError(null);
18968
18777
  };
18969
18778
  window.addEventListener("blur", onBlur);
@@ -18973,10 +18782,7 @@ function AiMediaStripOverlay({
18973
18782
  const onKeyDown = (e) => {
18974
18783
  if (e.key !== "Escape") return;
18975
18784
  if (!activeRef.current) return;
18976
- if (linkOpenRef.current) return;
18977
- if (document.querySelector('[data-ohw-more-menu][data-state="open"]')) return;
18978
18785
  setActive(null);
18979
- setItemEditOn(false);
18980
18786
  setError(null);
18981
18787
  };
18982
18788
  document.addEventListener("keydown", onKeyDown);
@@ -19010,133 +18816,137 @@ function AiMediaStripOverlay({
19010
18816
  tree: nextTree,
19011
18817
  label: entry.label,
19012
18818
  media: extraMedia ? { ...entry.media, ...extraMedia } : entry.media,
19013
- ...entry.brand ? { brand: entry.brand } : {},
19014
- // The user is already looking at the strip they just edited — recentering the viewport
19015
- // on every edit reads as the section jumping around.
19016
- skipScrollIntoView: true
18819
+ ...entry.brand ? { brand: entry.brand } : {}
19017
18820
  });
19018
18821
  return true;
19019
18822
  },
19020
18823
  [findEntry, postToParent2, applyTreeLocalRef]
19021
18824
  );
19022
18825
  const activeEntry = active ? findEntry(active.sectionId) : null;
18826
+ const hoverHandleRect = useLiveItemRect(!active && hover ? hover : null);
19023
18827
  const activeItemRect = useLiveItemRect(active);
19024
- const activeStripRect = useLiveItemRect(active, true);
19025
- const hoverRect = useLiveItemRect(hover && !sameRef(hover, active) ? hover : null);
19026
- const activeItems = activeEntry ? mediaStripItems(activeEntry.tree) : [];
19027
- const activeItem = active ? activeItems[active.index] : void 0;
19028
- const activeHref = activeItem?.href ?? "";
19029
- const activeTarget = activeItem?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
19030
- return /* @__PURE__ */ jsxs12(Fragment7, { children: [
19031
- hoverRect && /* @__PURE__ */ jsx21(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
19032
- activeItemRect && activeStripRect && active && activeEntry && /* @__PURE__ */ jsxs12(Fragment7, { children: [
19033
- /* @__PURE__ */ jsx21(ItemInteractionLayer, { rect: activeItemRect, state: "active-top" }),
19034
- /* @__PURE__ */ jsx21(StripToolbarSlot, { stripRect: activeStripRect, children: /* @__PURE__ */ jsx21(
19035
- MediaStripToolbar,
19036
- {
19037
- entry: activeEntry,
19038
- index: active.index,
19039
- pending,
19040
- error,
19041
- itemEditOn,
19042
- onToggleItemEdit: () => setItemEditOn((on) => !on),
19043
- onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
19044
- onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
19045
- onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
19046
- onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
19047
- onResize: (delta) => {
19048
- const slots = findMediaStripSlots(activeEntry.tree);
19049
- const variant = slots?.variant === "reel" ? "reel" : "logos";
19050
- const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
19051
- void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
19052
- },
19053
- onOpenLink: () => setLinkOpen(true),
19054
- onAddItem: () => {
19055
- void requestAssetPick(postToParent2).then((picked) => {
19056
- if (!picked) return;
19057
- const item = { assetId: picked.assetId, alt: "Logo" };
18828
+ const TOOLBAR_APPROX_H = 170;
18829
+ const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
18830
+ return /* @__PURE__ */ jsxs11(Fragment7, { children: [
18831
+ hoverHandleRect && hover && /* @__PURE__ */ jsx20(
18832
+ "button",
18833
+ {
18834
+ type: "button",
18835
+ "data-ohw-toolbar": "",
18836
+ onClick: () => {
18837
+ clearInteractionChromeRef.current();
18838
+ setActive(hover);
18839
+ },
18840
+ "aria-label": "Configure media item",
18841
+ style: {
18842
+ position: "fixed",
18843
+ top: hoverHandleRect.top + 8,
18844
+ left: hoverHandleRect.left + hoverHandleRect.width - 36,
18845
+ width: 28,
18846
+ height: 28,
18847
+ borderRadius: 8,
18848
+ border: `1.5px dashed ${PRIMARY3}`,
18849
+ background: "#ffffff",
18850
+ color: PRIMARY3,
18851
+ display: "flex",
18852
+ alignItems: "center",
18853
+ justifyContent: "center",
18854
+ cursor: "pointer",
18855
+ zIndex: 2147483643,
18856
+ fontSize: 14,
18857
+ fontWeight: 700
18858
+ },
18859
+ children: /* @__PURE__ */ jsx20(Star, { size: 14, style: { pointerEvents: "none" } })
18860
+ }
18861
+ ),
18862
+ activeItemRect && active && activeEntry && /* @__PURE__ */ jsx20(
18863
+ ItemInteractionLayer,
18864
+ {
18865
+ rect: activeItemRect,
18866
+ state: toolbarState,
18867
+ toolbar: /* @__PURE__ */ jsx20(
18868
+ MediaStripToolbar,
18869
+ {
18870
+ entry: activeEntry,
18871
+ index: active.index,
18872
+ pending,
18873
+ error,
18874
+ onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
18875
+ onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
18876
+ onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
18877
+ onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
18878
+ onResize: (delta) => {
18879
+ const slots = findMediaStripSlots(activeEntry.tree);
18880
+ const variant = slots?.variant === "reel" ? "reel" : "logos";
18881
+ const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
18882
+ void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
18883
+ },
18884
+ onSetAlt: (alt) => {
18885
+ void runMutation(active.sectionId, (tree) => setMediaStripItemAlt(tree, active.index, alt));
18886
+ },
18887
+ onSetLink: (href, linkTarget) => {
19058
18888
  void runMutation(
19059
18889
  active.sectionId,
19060
- (tree) => addMediaStripItem(tree, item, active.index),
19061
- { [picked.assetId]: picked.url }
19062
- ).then((applied) => {
19063
- if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
18890
+ (tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
18891
+ );
18892
+ },
18893
+ onAddItem: () => {
18894
+ void requestAssetPick(postToParent2).then((picked) => {
18895
+ if (!picked) return;
18896
+ const item = { assetId: picked.assetId, alt: "Logo" };
18897
+ void runMutation(
18898
+ active.sectionId,
18899
+ (tree) => addMediaStripItem(tree, item, active.index),
18900
+ { [picked.assetId]: picked.url }
18901
+ ).then((applied) => {
18902
+ if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
18903
+ });
19064
18904
  });
19065
- });
19066
- },
19067
- onChangeImage: () => {
19068
- void requestAssetPick(postToParent2).then((picked) => {
19069
- if (!picked) return;
19070
- void runMutation(
19071
- active.sectionId,
19072
- (tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
19073
- { [picked.assetId]: picked.url }
18905
+ },
18906
+ onChangeImage: () => {
18907
+ void requestAssetPick(postToParent2).then((picked) => {
18908
+ if (!picked) return;
18909
+ void runMutation(
18910
+ active.sectionId,
18911
+ (tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
18912
+ { [picked.assetId]: picked.url }
18913
+ );
18914
+ });
18915
+ },
18916
+ onRemoveItem: () => {
18917
+ void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
18918
+ (applied) => {
18919
+ if (applied) setActive(null);
18920
+ }
19074
18921
  );
19075
- });
19076
- },
19077
- onRemoveItem: () => {
19078
- void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
19079
- (applied) => {
19080
- if (applied) setActive(null);
19081
- }
19082
- );
19083
- },
19084
- onMoveLeft: () => {
19085
- void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
19086
- (applied) => {
19087
- if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
19088
- }
19089
- );
19090
- },
19091
- onMoveRight: () => {
19092
- void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
19093
- (applied) => {
19094
- if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
19095
- }
19096
- );
19097
- }
19098
- }
19099
- ) }),
19100
- /* @__PURE__ */ jsx21(
19101
- "div",
19102
- {
19103
- "data-ohw-bridge": "",
19104
- "data-ohw-item-interaction": "",
19105
- "aria-hidden": true,
19106
- className: "pointer-events-none fixed rounded-[4px] px-[7px] py-[3px] font-sans text-[11px] font-medium leading-none text-primary-foreground whitespace-nowrap",
19107
- style: {
19108
- top: activeItemRect.top + activeItemRect.height + 10,
19109
- left: activeItemRect.left - 5,
19110
- background: PRIMARY3,
19111
- zIndex: 2147483644
19112
- },
19113
- children: "Media item"
19114
- }
19115
- ),
19116
- linkOpen && /* @__PURE__ */ jsx21(
19117
- LinkModal,
19118
- {
19119
- href: activeHref,
19120
- linkTarget: activeTarget,
19121
- onClose: () => setLinkOpen(false),
19122
- onSave: (href, linkTarget) => {
19123
- void runMutation(
19124
- active.sectionId,
19125
- (tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
19126
- );
18922
+ },
18923
+ onMoveLeft: () => {
18924
+ void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
18925
+ (applied) => {
18926
+ if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
18927
+ }
18928
+ );
18929
+ },
18930
+ onMoveRight: () => {
18931
+ void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
18932
+ (applied) => {
18933
+ if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
18934
+ }
18935
+ );
18936
+ }
19127
18937
  }
19128
- }
19129
- )
19130
- ] })
18938
+ )
18939
+ }
18940
+ )
19131
18941
  ] });
19132
18942
  }
19133
18943
 
19134
18944
  // src/ui/ai-section/AiPricingCardOverlay.tsx
19135
- import { useCallback as useCallback4, useEffect as useEffect7, useLayoutEffect as useLayoutEffect5, useRef as useRef6, useState as useState9 } from "react";
19136
- import { Check as Check3, ChevronDown as ChevronDown4, Minus as Minus2, Plus as Plus3, Star as Star2 } from "lucide-react";
19137
- import { Fragment as Fragment8, jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
18945
+ import { useCallback as useCallback4, useEffect as useEffect7, useLayoutEffect as useLayoutEffect4, useRef as useRef6, useState as useState9 } from "react";
18946
+ import { Check as Check2, ChevronDown as ChevronDown3, Minus, Plus as Plus2, Star as Star2 } from "lucide-react";
18947
+ import { Fragment as Fragment8, jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
19138
18948
  var PRIMARY4 = "var(--ohw-primary, #0885FE)";
19139
- 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]";
18949
+ 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]";
19140
18950
  function findPricingCardElement(sectionId, index) {
19141
18951
  const sectionEl = findByInstanceId(sectionId);
19142
18952
  if (!sectionEl) return null;
@@ -19148,7 +18958,7 @@ function findPricingCardElement(sectionId, index) {
19148
18958
  }
19149
18959
  function cardRefFromTarget(target) {
19150
18960
  if (!(target instanceof Element)) return null;
19151
- if (target.closest(CHROME_SELECTOR2)) return null;
18961
+ if (target.closest(CHROME_SELECTOR)) return null;
19152
18962
  const cardEl = target.closest("[data-ohw-pricing-card]");
19153
18963
  if (!cardEl) return null;
19154
18964
  const sectionEl = cardEl.closest("[data-ohw-section]");
@@ -19158,21 +18968,21 @@ function cardRefFromTarget(target) {
19158
18968
  if (!sectionId || Number.isNaN(index)) return null;
19159
18969
  return { sectionId, index };
19160
18970
  }
19161
- function sameRef2(a, b) {
18971
+ function sameRef(a, b) {
19162
18972
  return a?.sectionId === b?.sectionId && a?.index === b?.index;
19163
18973
  }
19164
- function rectOf2(el) {
18974
+ function rectOf(el) {
19165
18975
  if (!el) return null;
19166
18976
  const r2 = el.getBoundingClientRect();
19167
18977
  if (r2.width <= 0 || r2.height <= 0) return null;
19168
18978
  return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
19169
18979
  }
19170
18980
  function readRect3(ref) {
19171
- return rectOf2(ref && findPricingCardElement(ref.sectionId, ref.index));
18981
+ return rectOf(ref && findPricingCardElement(ref.sectionId, ref.index));
19172
18982
  }
19173
18983
  function readGridRect(ref) {
19174
18984
  const card = ref && findPricingCardElement(ref.sectionId, ref.index);
19175
- return rectOf2(card?.closest("[data-ohw-pricing-collection]") ?? card);
18985
+ return rectOf(card?.closest("[data-ohw-pricing-collection]") ?? card);
19176
18986
  }
19177
18987
  function useLiveCardRect(ref, grid = false) {
19178
18988
  const [rect, setRect] = useState9(null);
@@ -19202,19 +19012,19 @@ function useLiveCardRect(ref, grid = false) {
19202
19012
  }
19203
19013
  var TOOLBAR_GRID_GAP = 52;
19204
19014
  var TOOLBAR_GRID_GAP_MOBILE = 42;
19205
- var TOOLBAR_EDGE_MARGIN3 = 4;
19015
+ var TOOLBAR_EDGE_MARGIN2 = 4;
19206
19016
  function GridToolbarSlot({ gridRect, children }) {
19207
19017
  const slotRef = useRef6(null);
19208
19018
  const [shift, setShift] = useState9(0);
19209
19019
  const centerX = gridRect.left + gridRect.width / 2;
19210
- useLayoutEffect5(() => {
19020
+ useLayoutEffect4(() => {
19211
19021
  const slot = slotRef.current;
19212
19022
  if (!slot) return;
19213
19023
  const clamp = () => {
19214
19024
  const w = slot.offsetWidth;
19215
19025
  if (w <= 0) return;
19216
19026
  const half = w / 2;
19217
- const clamped = Math.max(TOOLBAR_EDGE_MARGIN3 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half));
19027
+ const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
19218
19028
  setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
19219
19029
  };
19220
19030
  clamp();
@@ -19223,7 +19033,7 @@ function GridToolbarSlot({ gridRect, children }) {
19223
19033
  return () => ro.disconnect();
19224
19034
  }, [centerX, children]);
19225
19035
  const mobile = window.innerWidth <= 480;
19226
- return /* @__PURE__ */ jsx22(
19036
+ return /* @__PURE__ */ jsx21(
19227
19037
  "div",
19228
19038
  {
19229
19039
  ref: slotRef,
@@ -19258,7 +19068,7 @@ function requestValidateTree2(postToParent2, tree) {
19258
19068
  });
19259
19069
  }
19260
19070
  function StyleSwatch({ style }) {
19261
- return /* @__PURE__ */ jsx22(
19071
+ return /* @__PURE__ */ jsx21(
19262
19072
  "span",
19263
19073
  {
19264
19074
  "aria-hidden": true,
@@ -19272,35 +19082,35 @@ function StyleSwatch({ style }) {
19272
19082
  );
19273
19083
  }
19274
19084
  function ButtonGlyph() {
19275
- return /* @__PURE__ */ jsxs13("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19276
- /* @__PURE__ */ jsx22("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
19277
- /* @__PURE__ */ jsx22("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
19085
+ return /* @__PURE__ */ jsxs12("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19086
+ /* @__PURE__ */ jsx21("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
19087
+ /* @__PURE__ */ jsx21("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
19278
19088
  ] });
19279
19089
  }
19280
19090
  function FeatureGlyph({ mode }) {
19281
- return /* @__PURE__ */ jsxs13("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19282
- /* @__PURE__ */ jsx22("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
19283
- /* @__PURE__ */ jsx22("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
19284
- /* @__PURE__ */ jsx22("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
19285
- /* @__PURE__ */ jsx22("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
19286
- /* @__PURE__ */ jsx22("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
19287
- mode === "add" && /* @__PURE__ */ jsx22("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
19091
+ return /* @__PURE__ */ jsxs12("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19092
+ /* @__PURE__ */ jsx21("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
19093
+ /* @__PURE__ */ jsx21("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
19094
+ /* @__PURE__ */ jsx21("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
19095
+ /* @__PURE__ */ jsx21("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
19096
+ /* @__PURE__ */ jsx21("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
19097
+ mode === "add" && /* @__PURE__ */ jsx21("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
19288
19098
  ] });
19289
19099
  }
19290
- function ToolbarAction2({
19100
+ function ToolbarAction({
19291
19101
  label,
19292
19102
  onClick,
19293
19103
  disabled = false,
19294
19104
  children
19295
19105
  }) {
19296
- const button = /* @__PURE__ */ jsx22(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
19297
- return /* @__PURE__ */ jsxs13(Tooltip, { children: [
19298
- /* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx22("span", { className: "inline-flex", children: button }) : button }),
19299
- /* @__PURE__ */ jsx22(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
19106
+ const button = /* @__PURE__ */ jsx21(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
19107
+ return /* @__PURE__ */ jsxs12(Tooltip, { children: [
19108
+ /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx21("span", { className: "inline-flex", children: button }) : button }),
19109
+ /* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
19300
19110
  ] });
19301
19111
  }
19302
- function ToolbarSeparator2() {
19303
- return /* @__PURE__ */ jsx22("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
19112
+ function ToolbarSeparator() {
19113
+ return /* @__PURE__ */ jsx21("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
19304
19114
  }
19305
19115
  function CardStyleMenu({
19306
19116
  value,
@@ -19308,7 +19118,7 @@ function CardStyleMenu({
19308
19118
  disabled = false
19309
19119
  }) {
19310
19120
  const current = PRICING_CARD_STYLES.find((s) => s.value === value) ?? PRICING_CARD_STYLES[0];
19311
- const trigger = /* @__PURE__ */ jsxs13(
19121
+ const trigger = /* @__PURE__ */ jsxs12(
19312
19122
  "button",
19313
19123
  {
19314
19124
  type: "button",
@@ -19319,28 +19129,28 @@ function CardStyleMenu({
19319
19129
  disabled && "cursor-not-allowed opacity-40 hover:bg-transparent"
19320
19130
  ),
19321
19131
  children: [
19322
- /* @__PURE__ */ jsx22(StyleSwatch, { style: current.value }),
19323
- /* @__PURE__ */ jsx22("span", { className: "flex-1 text-left", children: current.label }),
19324
- /* @__PURE__ */ jsx22(ChevronDown4, { size: 16, style: { pointerEvents: "none" } })
19132
+ /* @__PURE__ */ jsx21(StyleSwatch, { style: current.value }),
19133
+ /* @__PURE__ */ jsx21("span", { className: "flex-1 text-left", children: current.label }),
19134
+ /* @__PURE__ */ jsx21(ChevronDown3, { size: 16, style: { pointerEvents: "none" } })
19325
19135
  ]
19326
19136
  }
19327
19137
  );
19328
19138
  if (disabled) {
19329
- return /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19330
- /* @__PURE__ */ jsx22("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
19331
- /* @__PURE__ */ jsxs13(Tooltip, { children: [
19332
- /* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx22("span", { className: "inline-flex", children: trigger }) }),
19333
- /* @__PURE__ */ jsx22(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
19139
+ return /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19140
+ /* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
19141
+ /* @__PURE__ */ jsxs12(Tooltip, { children: [
19142
+ /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx21("span", { className: "inline-flex", children: trigger }) }),
19143
+ /* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
19334
19144
  ] })
19335
19145
  ] });
19336
19146
  }
19337
- return /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19338
- /* @__PURE__ */ jsx22("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
19339
- /* @__PURE__ */ jsxs13(DropdownMenu, { modal: false, children: [
19340
- /* @__PURE__ */ jsx22(DropdownMenuTrigger, { asChild: true, children: trigger }),
19341
- /* @__PURE__ */ jsx22(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
19147
+ return /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19148
+ /* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
19149
+ /* @__PURE__ */ jsxs12(DropdownMenu, { modal: false, children: [
19150
+ /* @__PURE__ */ jsx21(DropdownMenuTrigger, { asChild: true, children: trigger }),
19151
+ /* @__PURE__ */ jsx21(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
19342
19152
  const selected = style.value === value;
19343
- return /* @__PURE__ */ jsxs13(
19153
+ return /* @__PURE__ */ jsxs12(
19344
19154
  DropdownMenuItem,
19345
19155
  {
19346
19156
  role: "menuitemradio",
@@ -19348,9 +19158,9 @@ function CardStyleMenu({
19348
19158
  onSelect: () => onChange(style.value),
19349
19159
  className: cn("grid grid-cols-[18px_1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
19350
19160
  children: [
19351
- /* @__PURE__ */ jsx22(StyleSwatch, { style: style.value }),
19352
- /* @__PURE__ */ jsx22("span", { children: style.label }),
19353
- selected && /* @__PURE__ */ jsx22(Check3, { size: 16, className: "text-bridge-primary" })
19161
+ /* @__PURE__ */ jsx21(StyleSwatch, { style: style.value }),
19162
+ /* @__PURE__ */ jsx21("span", { children: style.label }),
19163
+ selected && /* @__PURE__ */ jsx21(Check2, { size: 16, className: "text-bridge-primary" })
19354
19164
  ]
19355
19165
  },
19356
19166
  style.value
@@ -19380,7 +19190,7 @@ function PricingCardToolbar({
19380
19190
  const style = pricingCardStyle(entry.tree, index);
19381
19191
  const featuredTag = pricingCardFeaturedTag(entry.tree, index);
19382
19192
  const mobile = window.innerWidth <= 480;
19383
- return /* @__PURE__ */ jsx22(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs13(
19193
+ return /* @__PURE__ */ jsx21(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs12(
19384
19194
  "div",
19385
19195
  {
19386
19196
  "data-ohw-bridge": "",
@@ -19392,7 +19202,7 @@ function PricingCardToolbar({
19392
19202
  ),
19393
19203
  style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
19394
19204
  children: [
19395
- /* @__PURE__ */ jsxs13(
19205
+ /* @__PURE__ */ jsxs12(
19396
19206
  "div",
19397
19207
  {
19398
19208
  className: cn(
@@ -19401,8 +19211,8 @@ function PricingCardToolbar({
19401
19211
  mobile ? "flex-wrap justify-center" : "flex-nowrap"
19402
19212
  ),
19403
19213
  children: [
19404
- /* @__PURE__ */ jsxs13(Tooltip, { children: [
19405
- /* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx22(
19214
+ /* @__PURE__ */ jsxs12(Tooltip, { children: [
19215
+ /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx21(
19406
19216
  CustomToolbarButton,
19407
19217
  {
19408
19218
  type: "button",
@@ -19410,7 +19220,7 @@ function PricingCardToolbar({
19410
19220
  "aria-pressed": featuredTag,
19411
19221
  onClick: () => onSetFeaturedTag(!featuredTag),
19412
19222
  className: "group size-8",
19413
- children: /* @__PURE__ */ jsx22(
19223
+ children: /* @__PURE__ */ jsx21(
19414
19224
  Star2,
19415
19225
  {
19416
19226
  size: 16,
@@ -19425,25 +19235,25 @@ function PricingCardToolbar({
19425
19235
  )
19426
19236
  }
19427
19237
  ) }),
19428
- /* @__PURE__ */ jsx22(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
19238
+ /* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
19429
19239
  ] }),
19430
- /* @__PURE__ */ jsx22(ToolbarSeparator2, {}),
19431
- /* @__PURE__ */ jsx22(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
19432
- /* @__PURE__ */ jsx22(ToolbarSeparator2, {}),
19433
- /* @__PURE__ */ jsx22(ToolbarAction2, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ jsx22(ButtonGlyph, {}) }),
19434
- /* @__PURE__ */ jsx22(ToolbarAction2, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ jsxs13("span", { className: "relative inline-flex", children: [
19435
- /* @__PURE__ */ jsx22(ButtonGlyph, {}),
19436
- /* @__PURE__ */ jsx22(Minus2, { size: 10, strokeWidth: 2.5, className: "absolute -right-1.5 -top-1.5 rounded-full bg-background text-bridge-primary" })
19240
+ /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
19241
+ /* @__PURE__ */ jsx21(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
19242
+ /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
19243
+ /* @__PURE__ */ jsx21(ToolbarAction, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ jsx21(ButtonGlyph, {}) }),
19244
+ /* @__PURE__ */ jsx21(ToolbarAction, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ jsxs12("span", { className: "relative inline-flex", children: [
19245
+ /* @__PURE__ */ jsx21(ButtonGlyph, {}),
19246
+ /* @__PURE__ */ jsx21(Minus, { size: 10, strokeWidth: 2.5, className: "absolute -right-1.5 -top-1.5 rounded-full bg-background text-bridge-primary" })
19437
19247
  ] }) }),
19438
- /* @__PURE__ */ jsx22(ToolbarAction2, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ jsx22(FeatureGlyph, { mode: "add" }) }),
19439
- /* @__PURE__ */ jsx22(ToolbarAction2, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ jsx22(FeatureGlyph, { mode: "remove" }) }),
19440
- /* @__PURE__ */ jsx22(ToolbarSeparator2, {}),
19441
- /* @__PURE__ */ jsx22(ToolbarAction2, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ jsx22(Plus3, { size: 16, style: { pointerEvents: "none" } }) }),
19442
- /* @__PURE__ */ jsx22(ToolbarAction2, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ jsx22(Minus2, { size: 16, style: { pointerEvents: "none" } }) })
19248
+ /* @__PURE__ */ jsx21(ToolbarAction, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ jsx21(FeatureGlyph, { mode: "add" }) }),
19249
+ /* @__PURE__ */ jsx21(ToolbarAction, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ jsx21(FeatureGlyph, { mode: "remove" }) }),
19250
+ /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
19251
+ /* @__PURE__ */ jsx21(ToolbarAction, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ jsx21(Plus2, { size: 16, style: { pointerEvents: "none" } }) }),
19252
+ /* @__PURE__ */ jsx21(ToolbarAction, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ jsx21(Minus, { size: 16, style: { pointerEvents: "none" } }) })
19443
19253
  ]
19444
19254
  }
19445
19255
  ),
19446
- error && /* @__PURE__ */ jsx22("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
19256
+ 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 })
19447
19257
  ]
19448
19258
  }
19449
19259
  ) });
@@ -19477,7 +19287,7 @@ function AiPricingCardOverlay({
19477
19287
  const overEditable = Boolean(t?.closest?.("[data-ohw-editable], [data-ohw-role], a, button"));
19478
19288
  setHover((prev) => {
19479
19289
  const next = ref && !overEditable ? ref : null;
19480
- return sameRef2(prev, next) ? prev : next;
19290
+ return sameRef(prev, next) ? prev : next;
19481
19291
  });
19482
19292
  };
19483
19293
  const onLeave = () => setHover(null);
@@ -19492,10 +19302,10 @@ function AiPricingCardOverlay({
19492
19302
  const onClick = (e) => {
19493
19303
  const t = e.target;
19494
19304
  if (!(t instanceof Element)) return;
19495
- if (t.closest(CHROME_SELECTOR2)) return;
19305
+ if (t.closest(CHROME_SELECTOR)) return;
19496
19306
  const ref = cardRefFromTarget(t);
19497
- setActive((prev) => sameRef2(prev, ref) ? prev : ref);
19498
- if (!ref || !sameRef2(activeRef.current, ref)) setError(null);
19307
+ setActive((prev) => sameRef(prev, ref) ? prev : ref);
19308
+ if (!ref || !sameRef(activeRef.current, ref)) setError(null);
19499
19309
  };
19500
19310
  document.addEventListener("click", onClick, true);
19501
19311
  return () => document.removeEventListener("click", onClick, true);
@@ -19560,12 +19370,12 @@ function AiPricingCardOverlay({
19560
19370
  const activeEntry = active ? findEntry(active.sectionId) : null;
19561
19371
  const activeCardRect = useLiveCardRect(active);
19562
19372
  const activeGridRect = useLiveCardRect(active, true);
19563
- const hoverRect = useLiveCardRect(hover && !sameRef2(hover, active) ? hover : null);
19564
- return /* @__PURE__ */ jsxs13(Fragment8, { children: [
19565
- hoverRect && /* @__PURE__ */ jsx22(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
19566
- activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ jsxs13(Fragment8, { children: [
19567
- /* @__PURE__ */ jsx22(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
19568
- /* @__PURE__ */ jsx22(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ jsx22(
19373
+ const hoverRect = useLiveCardRect(hover && !sameRef(hover, active) ? hover : null);
19374
+ return /* @__PURE__ */ jsxs12(Fragment8, { children: [
19375
+ hoverRect && /* @__PURE__ */ jsx21(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
19376
+ activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ jsxs12(Fragment8, { children: [
19377
+ /* @__PURE__ */ jsx21(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
19378
+ /* @__PURE__ */ jsx21(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ jsx21(
19569
19379
  PricingCardToolbar,
19570
19380
  {
19571
19381
  entry: activeEntry,
@@ -19593,7 +19403,7 @@ function AiPricingCardOverlay({
19593
19403
  onRemoveFeature: () => runMutation(active.sectionId, (tree) => removePricingCardFeature(tree, active.index))
19594
19404
  }
19595
19405
  ) }),
19596
- /* @__PURE__ */ jsx22(
19406
+ /* @__PURE__ */ jsx21(
19597
19407
  "div",
19598
19408
  {
19599
19409
  "data-ohw-bridge": "",
@@ -19686,10 +19496,10 @@ function extractYouTubeId(input) {
19686
19496
  }
19687
19497
 
19688
19498
  // src/ui/ai-section/AiVideoOverlay.tsx
19689
- import { Fragment as Fragment9, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
19499
+ import { Fragment as Fragment9, jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
19690
19500
  var PRIMARY5 = "#0885FE";
19691
- var OHW_BLUE = `var(--ohw-primary, ${PRIMARY5})`;
19692
- var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
19501
+ var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY5})`;
19502
+ var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
19693
19503
  function findVideoBlockElement(sectionId, path) {
19694
19504
  const sectionEl = findByInstanceId(sectionId);
19695
19505
  if (!sectionEl) return null;
@@ -19749,12 +19559,12 @@ function requestValidateTree3(postToParent2, tree) {
19749
19559
  postToParent2({ type: "ow:ai-validate-tree-request", id, tree });
19750
19560
  });
19751
19561
  }
19752
- function Pill({
19562
+ function Pill2({
19753
19563
  label,
19754
19564
  onClick,
19755
19565
  disabled
19756
19566
  }) {
19757
- return /* @__PURE__ */ jsx23(
19567
+ return /* @__PURE__ */ jsx22(
19758
19568
  "button",
19759
19569
  {
19760
19570
  type: "button",
@@ -19770,7 +19580,7 @@ function Pill({
19770
19580
  border: "none",
19771
19581
  cursor: disabled ? "default" : "pointer",
19772
19582
  background: "#ffffff",
19773
- color: OHW_BLUE_DARK,
19583
+ color: OHW_BLUE_DARK2,
19774
19584
  opacity: disabled ? 0.4 : 1,
19775
19585
  fontSize: 12,
19776
19586
  lineHeight: "16px",
@@ -19813,8 +19623,8 @@ function VideoUrlInput({ value, onCommit }) {
19813
19623
  onCommit(id);
19814
19624
  }
19815
19625
  };
19816
- return /* @__PURE__ */ jsxs14("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
19817
- /* @__PURE__ */ jsxs14(
19626
+ return /* @__PURE__ */ jsxs13("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
19627
+ /* @__PURE__ */ jsxs13(
19818
19628
  "div",
19819
19629
  {
19820
19630
  style: {
@@ -19830,12 +19640,12 @@ function VideoUrlInput({ value, onCommit }) {
19830
19640
  boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
19831
19641
  },
19832
19642
  children: [
19833
- /* @__PURE__ */ jsx23(
19643
+ /* @__PURE__ */ jsx22(
19834
19644
  "span",
19835
19645
  {
19836
19646
  style: {
19837
19647
  flex: "0 0 auto",
19838
- color: OHW_BLUE_DARK,
19648
+ color: OHW_BLUE_DARK2,
19839
19649
  fontSize: 10,
19840
19650
  lineHeight: "16px",
19841
19651
  fontWeight: 700,
@@ -19845,7 +19655,7 @@ function VideoUrlInput({ value, onCommit }) {
19845
19655
  children: "Video"
19846
19656
  }
19847
19657
  ),
19848
- /* @__PURE__ */ jsx23(
19658
+ /* @__PURE__ */ jsx22(
19849
19659
  "input",
19850
19660
  {
19851
19661
  type: "text",
@@ -19882,7 +19692,7 @@ function VideoUrlInput({ value, onCommit }) {
19882
19692
  ]
19883
19693
  }
19884
19694
  ),
19885
- invalid && /* @__PURE__ */ jsx23("div", { style: { color: "#FCA5A5", fontSize: 11, textAlign: "center" }, children: "That doesn't look like a YouTube link \u2014 try pasting the video URL again." })
19695
+ 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." })
19886
19696
  ] });
19887
19697
  }
19888
19698
  function VideoToolbar({
@@ -19892,7 +19702,7 @@ function VideoToolbar({
19892
19702
  onSetVideoId,
19893
19703
  onRemove
19894
19704
  }) {
19895
- return /* @__PURE__ */ jsxs14(
19705
+ return /* @__PURE__ */ jsxs13(
19896
19706
  "div",
19897
19707
  {
19898
19708
  "data-ohw-bridge": "",
@@ -19904,7 +19714,7 @@ function VideoToolbar({
19904
19714
  gap: 6,
19905
19715
  alignItems: "center",
19906
19716
  width: 280,
19907
- background: OHW_BLUE,
19717
+ background: OHW_BLUE2,
19908
19718
  padding: 8,
19909
19719
  borderRadius: 12,
19910
19720
  boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
@@ -19912,9 +19722,9 @@ function VideoToolbar({
19912
19722
  opacity: pending ? 0.6 : 1
19913
19723
  },
19914
19724
  children: [
19915
- /* @__PURE__ */ jsx23(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
19916
- /* @__PURE__ */ jsx23(Pill, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
19917
- error && /* @__PURE__ */ jsx23("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
19725
+ /* @__PURE__ */ jsx22(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
19726
+ /* @__PURE__ */ jsx22(Pill2, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
19727
+ error && /* @__PURE__ */ jsx22("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
19918
19728
  ]
19919
19729
  }
19920
19730
  );
@@ -20034,8 +19844,8 @@ function AiVideoOverlay({
20034
19844
  const activeBlockRect = useLiveBlockRect(active);
20035
19845
  const TOOLBAR_APPROX_H = 90;
20036
19846
  const toolbarState = activeBlockRect && activeBlockRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
20037
- return /* @__PURE__ */ jsxs14(Fragment9, { children: [
20038
- hoverHandleRect && hover && /* @__PURE__ */ jsx23(
19847
+ return /* @__PURE__ */ jsxs13(Fragment9, { children: [
19848
+ hoverHandleRect && hover && /* @__PURE__ */ jsx22(
20039
19849
  "button",
20040
19850
  {
20041
19851
  type: "button",
@@ -20063,15 +19873,15 @@ function AiVideoOverlay({
20063
19873
  fontSize: 14,
20064
19874
  fontWeight: 700
20065
19875
  },
20066
- children: /* @__PURE__ */ jsx23(Star3, { size: 14, style: { pointerEvents: "none" } })
19876
+ children: /* @__PURE__ */ jsx22(Star3, { size: 14, style: { pointerEvents: "none" } })
20067
19877
  }
20068
19878
  ),
20069
- activeBlockRect && active && activeEntry && /* @__PURE__ */ jsx23(
19879
+ activeBlockRect && active && activeEntry && /* @__PURE__ */ jsx22(
20070
19880
  ItemInteractionLayer,
20071
19881
  {
20072
19882
  rect: activeBlockRect,
20073
19883
  state: toolbarState,
20074
- toolbar: /* @__PURE__ */ jsx23(
19884
+ toolbar: /* @__PURE__ */ jsx22(
20075
19885
  VideoToolbar,
20076
19886
  {
20077
19887
  videoId: videoIdAt(activeEntry.tree, active.path),
@@ -20146,10 +19956,10 @@ function setCarouselAutoplay(tree, on) {
20146
19956
  }
20147
19957
 
20148
19958
  // src/ui/ai-section/AiFadeCarouselOverlay.tsx
20149
- import { Fragment as Fragment10, jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
19959
+ import { Fragment as Fragment10, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
20150
19960
  var PRIMARY6 = "#0885FE";
20151
- var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY6})`;
20152
- var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
19961
+ var OHW_BLUE3 = `var(--ohw-primary, ${PRIMARY6})`;
19962
+ var OHW_BLUE_DARK3 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
20153
19963
  function findCarouselItemElement(sectionId, index) {
20154
19964
  const sectionEl = findByInstanceId(sectionId);
20155
19965
  if (!sectionEl) return null;
@@ -20228,8 +20038,8 @@ function requestAssetPick2(postToParent2) {
20228
20038
  postToParent2({ type: "ow:asset-pick", id });
20229
20039
  });
20230
20040
  }
20231
- function Pill2({ label, onClick, disabled }) {
20232
- return /* @__PURE__ */ jsx24(
20041
+ function Pill3({ label, onClick, disabled }) {
20042
+ return /* @__PURE__ */ jsx23(
20233
20043
  "button",
20234
20044
  {
20235
20045
  type: "button",
@@ -20245,7 +20055,7 @@ function Pill2({ label, onClick, disabled }) {
20245
20055
  border: "none",
20246
20056
  cursor: disabled ? "default" : "pointer",
20247
20057
  background: "#ffffff",
20248
- color: OHW_BLUE_DARK2,
20058
+ color: OHW_BLUE_DARK3,
20249
20059
  opacity: disabled ? 0.4 : 1,
20250
20060
  fontSize: 12,
20251
20061
  lineHeight: "16px",
@@ -20263,7 +20073,7 @@ function TogglePill({
20263
20073
  onToggle,
20264
20074
  disabled
20265
20075
  }) {
20266
- return /* @__PURE__ */ jsxs15(
20076
+ return /* @__PURE__ */ jsxs14(
20267
20077
  "button",
20268
20078
  {
20269
20079
  type: "button",
@@ -20282,7 +20092,7 @@ function TogglePill({
20282
20092
  border: "none",
20283
20093
  cursor: disabled ? "default" : "pointer",
20284
20094
  background: "#ffffff",
20285
- color: OHW_BLUE_DARK2,
20095
+ color: OHW_BLUE_DARK3,
20286
20096
  opacity: disabled ? 0.4 : 1,
20287
20097
  fontSize: 12,
20288
20098
  lineHeight: "16px",
@@ -20292,7 +20102,7 @@ function TogglePill({
20292
20102
  },
20293
20103
  children: [
20294
20104
  label,
20295
- /* @__PURE__ */ jsx24(
20105
+ /* @__PURE__ */ jsx23(
20296
20106
  "span",
20297
20107
  {
20298
20108
  "aria-hidden": true,
@@ -20305,10 +20115,10 @@ function TogglePill({
20305
20115
  // Off is a grey track, not a washed-out blue: the pill's own white background already
20306
20116
  // carries the brand colour in the text, and a pale blue track next to it read as
20307
20117
  // "disabled control" rather than "switch that is off".
20308
- background: on ? OHW_BLUE_DARK2 : "#CBD5E1",
20118
+ background: on ? OHW_BLUE_DARK3 : "#CBD5E1",
20309
20119
  transition: "background 120ms ease"
20310
20120
  },
20311
- children: /* @__PURE__ */ jsx24(
20121
+ children: /* @__PURE__ */ jsx23(
20312
20122
  "span",
20313
20123
  {
20314
20124
  style: {
@@ -20337,7 +20147,7 @@ function CarouselSlideToolbar({
20337
20147
  onChangeImage,
20338
20148
  onToggleAutoplay
20339
20149
  }) {
20340
- return /* @__PURE__ */ jsxs15(
20150
+ return /* @__PURE__ */ jsxs14(
20341
20151
  "div",
20342
20152
  {
20343
20153
  "data-ohw-bridge": "",
@@ -20348,7 +20158,7 @@ function CarouselSlideToolbar({
20348
20158
  flexDirection: "column",
20349
20159
  gap: 6,
20350
20160
  alignItems: "center",
20351
- background: OHW_BLUE2,
20161
+ background: OHW_BLUE3,
20352
20162
  padding: 8,
20353
20163
  borderRadius: 12,
20354
20164
  boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
@@ -20360,11 +20170,11 @@ function CarouselSlideToolbar({
20360
20170
  pointerEvents: pending ? "none" : "auto"
20361
20171
  },
20362
20172
  children: [
20363
- /* @__PURE__ */ jsxs15("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
20364
- /* @__PURE__ */ jsx24(Pill2, { label: "Change Image", onClick: onChangeImage }),
20365
- /* @__PURE__ */ jsx24(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
20173
+ /* @__PURE__ */ jsxs14("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
20174
+ /* @__PURE__ */ jsx23(Pill3, { label: "Change Image", onClick: onChangeImage }),
20175
+ /* @__PURE__ */ jsx23(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
20366
20176
  ] }),
20367
- error && /* @__PURE__ */ jsx24("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
20177
+ error && /* @__PURE__ */ jsx23("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
20368
20178
  ]
20369
20179
  }
20370
20180
  );
@@ -20504,8 +20314,8 @@ function AiFadeCarouselOverlay({
20504
20314
  const activeItemRect = useLiveItemRect2(active);
20505
20315
  const TOOLBAR_APPROX_H = 90;
20506
20316
  const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
20507
- return /* @__PURE__ */ jsxs15(Fragment10, { children: [
20508
- hoverHandleRect && hover && /* @__PURE__ */ jsx24(
20317
+ return /* @__PURE__ */ jsxs14(Fragment10, { children: [
20318
+ hoverHandleRect && hover && /* @__PURE__ */ jsx23(
20509
20319
  "button",
20510
20320
  {
20511
20321
  type: "button",
@@ -20534,10 +20344,10 @@ function AiFadeCarouselOverlay({
20534
20344
  fontSize: 14,
20535
20345
  fontWeight: 700
20536
20346
  },
20537
- children: /* @__PURE__ */ jsx24(Star4, { size: 14, style: { pointerEvents: "none" } })
20347
+ children: /* @__PURE__ */ jsx23(Star4, { size: 14, style: { pointerEvents: "none" } })
20538
20348
  }
20539
20349
  ),
20540
- swapping && /* @__PURE__ */ jsx24(
20350
+ swapping && /* @__PURE__ */ jsx23(
20541
20351
  "div",
20542
20352
  {
20543
20353
  ref: skeletonRef,
@@ -20555,15 +20365,15 @@ function AiFadeCarouselOverlay({
20555
20365
  zIndex: 2147483646,
20556
20366
  pointerEvents: "none"
20557
20367
  },
20558
- children: /* @__PURE__ */ jsx24("style", { children: MEDIA_SKELETON_CSS })
20368
+ children: /* @__PURE__ */ jsx23("style", { children: MEDIA_SKELETON_CSS })
20559
20369
  }
20560
20370
  ),
20561
- activeItemRect && active && activeEntry && /* @__PURE__ */ jsx24(
20371
+ activeItemRect && active && activeEntry && /* @__PURE__ */ jsx23(
20562
20372
  ItemInteractionLayer,
20563
20373
  {
20564
20374
  rect: activeItemRect,
20565
20375
  state: toolbarState,
20566
- toolbar: /* @__PURE__ */ jsx24(
20376
+ toolbar: /* @__PURE__ */ jsx23(
20567
20377
  CarouselSlideToolbar,
20568
20378
  {
20569
20379
  pending,
@@ -20916,11 +20726,118 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
20916
20726
  // src/ui/link-modal/LinkPopover.tsx
20917
20727
  import { useEffect as useEffect13 } from "react";
20918
20728
 
20729
+ // src/ui/dialog.tsx
20730
+ import * as React9 from "react";
20731
+ import { Dialog as DialogPrimitive } from "radix-ui";
20732
+ import { X as X2 } from "lucide-react";
20733
+ import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
20734
+ function Dialog2({
20735
+ ...props
20736
+ }) {
20737
+ return /* @__PURE__ */ jsx24(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
20738
+ }
20739
+ function DialogPortal({
20740
+ ...props
20741
+ }) {
20742
+ return /* @__PURE__ */ jsx24(DialogPrimitive.Portal, { ...props });
20743
+ }
20744
+ function DialogOverlay({
20745
+ className,
20746
+ ...props
20747
+ }) {
20748
+ return /* @__PURE__ */ jsx24(
20749
+ DialogPrimitive.Overlay,
20750
+ {
20751
+ "data-slot": "dialog-overlay",
20752
+ "data-ohw-link-modal-root": "",
20753
+ className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
20754
+ ...props
20755
+ }
20756
+ );
20757
+ }
20758
+ var DialogContent = React9.forwardRef(
20759
+ ({ className, children, showCloseButton = true, container, ...props }, ref) => {
20760
+ const positionMode = container ? "absolute" : "fixed";
20761
+ return /* @__PURE__ */ jsxs15(DialogPortal, { container: container ?? void 0, children: [
20762
+ /* @__PURE__ */ jsx24(DialogOverlay, { className: cn(positionMode, "inset-0") }),
20763
+ /* @__PURE__ */ jsxs15(
20764
+ DialogPrimitive.Content,
20765
+ {
20766
+ ref,
20767
+ "data-slot": "dialog-content",
20768
+ className: cn(
20769
+ positionMode,
20770
+ "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",
20771
+ "rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
20772
+ container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
20773
+ className
20774
+ ),
20775
+ onMouseDown: (e) => e.stopPropagation(),
20776
+ ...props,
20777
+ children: [
20778
+ children,
20779
+ showCloseButton ? /* @__PURE__ */ jsx24(
20780
+ DialogPrimitive.Close,
20781
+ {
20782
+ type: "button",
20783
+ className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
20784
+ "aria-label": "Close",
20785
+ children: /* @__PURE__ */ jsx24(X2, { size: 16, "aria-hidden": true })
20786
+ }
20787
+ ) : null
20788
+ ]
20789
+ }
20790
+ )
20791
+ ] });
20792
+ }
20793
+ );
20794
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
20795
+ function DialogHeader({
20796
+ className,
20797
+ ...props
20798
+ }) {
20799
+ return /* @__PURE__ */ jsx24("div", { className: cn("flex flex-col gap-1.5", className), ...props });
20800
+ }
20801
+ function DialogFooter({
20802
+ className,
20803
+ ...props
20804
+ }) {
20805
+ return /* @__PURE__ */ jsx24(
20806
+ "div",
20807
+ {
20808
+ className: cn("flex items-center justify-end gap-2", className),
20809
+ ...props
20810
+ }
20811
+ );
20812
+ }
20813
+ var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
20814
+ DialogPrimitive.Title,
20815
+ {
20816
+ ref,
20817
+ className: cn(
20818
+ "text-lg font-semibold leading-none tracking-tight text-card-foreground",
20819
+ className
20820
+ ),
20821
+ ...props
20822
+ }
20823
+ ));
20824
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
20825
+ var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
20826
+ DialogPrimitive.Description,
20827
+ {
20828
+ ref,
20829
+ className: cn("text-sm text-muted-foreground", className),
20830
+ ...props
20831
+ }
20832
+ ));
20833
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
20834
+ var DialogClose = DialogPrimitive.Close;
20835
+
20919
20836
  // src/ui/link-modal/LinkEditorPanel.tsx
20920
20837
  import { Info, X as X4 } from "lucide-react";
20921
20838
 
20922
20839
  // src/ui/link-modal/DestinationBreadcrumb.tsx
20923
- import { ArrowRight as ArrowRight3, File, GalleryVertical } from "lucide-react";
20840
+ import { ArrowRight as ArrowRight2, File, GalleryVertical } from "lucide-react";
20924
20841
  import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
20925
20842
  function DestinationBreadcrumb({
20926
20843
  pageTitle,
@@ -20934,7 +20851,7 @@ function DestinationBreadcrumb({
20934
20851
  /* @__PURE__ */ jsx25("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
20935
20852
  ] }),
20936
20853
  /* @__PURE__ */ jsx25(
20937
- ArrowRight3,
20854
+ ArrowRight2,
20938
20855
  {
20939
20856
  size: 16,
20940
20857
  className: "shrink-0 text-muted-foreground",
@@ -21046,7 +20963,7 @@ function Label({ className, ...props }) {
21046
20963
  }
21047
20964
 
21048
20965
  // src/ui/link-modal/UrlOrPageInput.tsx
21049
- import { ChevronDown as ChevronDown5, File as File2, X as X3 } from "lucide-react";
20966
+ import { ChevronDown as ChevronDown4, File as File2, X as X3 } from "lucide-react";
21050
20967
  import { jsx as jsx29, jsxs as jsxs18 } from "react/jsx-runtime";
21051
20968
  function FieldChevron({
21052
20969
  onClick
@@ -21059,7 +20976,7 @@ function FieldChevron({
21059
20976
  onClick,
21060
20977
  "aria-label": "Open page list",
21061
20978
  tabIndex: -1,
21062
- children: /* @__PURE__ */ jsx29(ChevronDown5, { size: 16 })
20979
+ children: /* @__PURE__ */ jsx29(ChevronDown4, { size: 16 })
21063
20980
  }
21064
20981
  );
21065
20982
  }
@@ -21289,7 +21206,7 @@ function LinkEditorPanel({ state, onClose }) {
21289
21206
  // src/ui/link-modal/SectionPickerOverlay.tsx
21290
21207
  import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo2, useRef as useRef10, useState as useState13 } from "react";
21291
21208
  import { createPortal as createPortal2 } from "react-dom";
21292
- import { ArrowLeft as ArrowLeft3, Check as Check4 } from "lucide-react";
21209
+ import { ArrowLeft as ArrowLeft2, Check as Check3 } from "lucide-react";
21293
21210
  import { usePathname, useRouter as useRouter2 } from "next/navigation";
21294
21211
 
21295
21212
  // src/lib/parent-scroll.ts
@@ -21566,7 +21483,7 @@ function SectionPickerOverlay({
21566
21483
  className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
21567
21484
  onClick: onBack,
21568
21485
  children: [
21569
- /* @__PURE__ */ jsx31(ArrowLeft3, { className: "size-4 shrink-0", "aria-hidden": true }),
21486
+ /* @__PURE__ */ jsx31(ArrowLeft2, { className: "size-4 shrink-0", "aria-hidden": true }),
21570
21487
  "Back"
21571
21488
  ]
21572
21489
  }
@@ -21635,7 +21552,7 @@ function SectionPickerOverlay({
21635
21552
  className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
21636
21553
  style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
21637
21554
  "aria-hidden": true,
21638
- children: /* @__PURE__ */ jsx31(Check4, { className: "size-5" })
21555
+ children: /* @__PURE__ */ jsx31(Check3, { className: "size-5" })
21639
21556
  }
21640
21557
  ) : null
21641
21558
  ]
@@ -22019,7 +21936,6 @@ function shouldUseDevFixtures() {
22019
21936
  function getLogoElement(el) {
22020
21937
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
22021
21938
  if (marked) return marked;
22022
- if (el.closest('[data-ohw-editable="icon"]')) return null;
22023
21939
  const root = el.closest("nav, [data-ohw-nav-root], footer");
22024
21940
  if (!root) return null;
22025
21941
  const anchor = el.closest("a");
@@ -22089,7 +22005,7 @@ function addFooterColumnWithPersist({
22089
22005
  import {
22090
22006
  useCallback as useCallback9,
22091
22007
  useEffect as useEffect14,
22092
- useLayoutEffect as useLayoutEffect6,
22008
+ useLayoutEffect as useLayoutEffect5,
22093
22009
  useRef as useRef11,
22094
22010
  useState as useState15
22095
22011
  } from "react";
@@ -22186,7 +22102,7 @@ function FloatingPanel({
22186
22102
  return () => window.removeEventListener("message", onParentScroll);
22187
22103
  }, [open]);
22188
22104
  const positionRef = useRef11(position);
22189
- useLayoutEffect6(() => {
22105
+ useLayoutEffect5(() => {
22190
22106
  if (!open) {
22191
22107
  positionRef.current = position;
22192
22108
  return;
@@ -22196,7 +22112,7 @@ function FloatingPanel({
22196
22112
  }
22197
22113
  positionRef.current = position;
22198
22114
  }, [open, position, liveScroll, parentScroll]);
22199
- useLayoutEffect6(() => {
22115
+ useLayoutEffect5(() => {
22200
22116
  if (!open || !panelRef.current) return;
22201
22117
  const el = panelRef.current;
22202
22118
  const header = el.querySelector("[data-ohw-floating-panel-header]");
@@ -22405,7 +22321,7 @@ function SocialsDisplayPanel({ display, onChange, className }) {
22405
22321
  }
22406
22322
 
22407
22323
  // src/ui/button-style-panel.tsx
22408
- import { Check as Check5 } from "lucide-react";
22324
+ import { Check as Check4 } from "lucide-react";
22409
22325
  import { jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
22410
22326
  var SIZE_LABEL = { s: "S", m: "M", l: "L" };
22411
22327
  function ButtonStylePanel({
@@ -22476,7 +22392,7 @@ function ButtonStylePanel({
22476
22392
  {
22477
22393
  className: "absolute right-0.5 top-0.5 flex size-5 items-center justify-center rounded-full bg-primary text-primary-foreground",
22478
22394
  "aria-hidden": true,
22479
- children: /* @__PURE__ */ jsx35(Check5, { className: "size-3", strokeWidth: 3 })
22395
+ children: /* @__PURE__ */ jsx35(Check4, { className: "size-3", strokeWidth: 3 })
22480
22396
  }
22481
22397
  ) : null
22482
22398
  ]
@@ -23501,7 +23417,7 @@ function useSectionDrag({
23501
23417
  }
23502
23418
 
23503
23419
  // src/ui/footer-container-chrome.tsx
23504
- import { Plus as Plus4 } from "lucide-react";
23420
+ import { Plus as Plus3 } from "lucide-react";
23505
23421
  import { jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
23506
23422
  function FooterContainerChrome({
23507
23423
  rect,
@@ -23542,7 +23458,7 @@ function FooterContainerChrome({
23542
23458
  if (addDisabled) return;
23543
23459
  onAdd();
23544
23460
  },
23545
- children: /* @__PURE__ */ jsx36(Plus4, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
23461
+ children: /* @__PURE__ */ jsx36(Plus3, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
23546
23462
  }
23547
23463
  ) }),
23548
23464
  /* @__PURE__ */ jsx36(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
@@ -23721,7 +23637,7 @@ function deleteSelectedNavFooterItem(deps) {
23721
23637
  }
23722
23638
 
23723
23639
  // src/ui/navbar-container-chrome.tsx
23724
- import { Plus as Plus5 } from "lucide-react";
23640
+ import { Plus as Plus4 } from "lucide-react";
23725
23641
  import { jsx as jsx37 } from "react/jsx-runtime";
23726
23642
  function NavbarContainerChrome({
23727
23643
  rect,
@@ -23757,7 +23673,7 @@ function NavbarContainerChrome({
23757
23673
  e.stopPropagation();
23758
23674
  onAdd();
23759
23675
  },
23760
- children: /* @__PURE__ */ jsx37(Plus5, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
23676
+ children: /* @__PURE__ */ jsx37(Plus4, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
23761
23677
  }
23762
23678
  )
23763
23679
  }
@@ -23829,7 +23745,7 @@ function Badge({ className, variant, ...props }) {
23829
23745
  }
23830
23746
 
23831
23747
  // src/OhhwellsBridge.tsx
23832
- import { Brush as Brush2, Link as Link2, Plus as Plus6, Settings } from "lucide-react";
23748
+ import { Brush as Brush2, Link as Link2, Plus as Plus5, Settings } from "lucide-react";
23833
23749
  import { Fragment as Fragment13, jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
23834
23750
  var PRIMARY7 = "#0885FE";
23835
23751
  var IMAGE_FADE_MS = 300;
@@ -24606,7 +24522,7 @@ function getNavigationSelectionParent(el) {
24606
24522
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
24607
24523
  return resolveFooterLinksContainerFrom(el);
24608
24524
  }
24609
- 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)) {
24525
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
24610
24526
  return getNavigationRoot(el);
24611
24527
  }
24612
24528
  return null;
@@ -24828,6 +24744,7 @@ var ICONS = {
24828
24744
  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"/>',
24829
24745
  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"/>'
24830
24746
  };
24747
+ var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
24831
24748
  var SELECTION_CHROME_GAP2 = 4;
24832
24749
  var TOOLBAR_STROKE_GAP2 = 4;
24833
24750
  var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
@@ -24925,7 +24842,7 @@ function applyVisibleViewport(el, parentScroll) {
24925
24842
  el.style.top = `${top}px`;
24926
24843
  el.style.height = `${height}px`;
24927
24844
  }
24928
- var TOOLBAR_EDGE_MARGIN4 = 4;
24845
+ var TOOLBAR_EDGE_MARGIN3 = 4;
24929
24846
  function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
24930
24847
  const isAbove = transform.includes("translateY(-100%)");
24931
24848
  let visualTop = isAbove ? top - approxH : top;
@@ -24952,8 +24869,8 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
24952
24869
  function clampToolbarLeft(centerX, toolbarWidth) {
24953
24870
  const half = toolbarWidth / 2;
24954
24871
  return Math.max(
24955
- TOOLBAR_EDGE_MARGIN4 + half,
24956
- Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN4 - half)
24872
+ TOOLBAR_EDGE_MARGIN3 + half,
24873
+ Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half)
24957
24874
  );
24958
24875
  }
24959
24876
  function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
@@ -25354,7 +25271,7 @@ function OhhwellsBridge() {
25354
25271
  }, []);
25355
25272
  const subdomainFromQuery = searchParams.get("subdomain");
25356
25273
  const [subdomain, setSubdomain] = useState18(() => resolveSubdomain(subdomainFromQuery));
25357
- useLayoutEffect7(() => {
25274
+ useLayoutEffect6(() => {
25358
25275
  const next = resolveSubdomain(subdomainFromQuery);
25359
25276
  if (next !== subdomain) setSubdomain(next);
25360
25277
  if (next) return;
@@ -25805,6 +25722,21 @@ function OhhwellsBridge() {
25805
25722
  const [isItemDragging, setIsItemDragging] = useState18(false);
25806
25723
  const [isFooterFrameSelection, setIsFooterFrameSelection] = useState18(false);
25807
25724
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
25725
+ const [floatingPanel, setFloatingPanel] = useState18(null);
25726
+ const floatingPanelOpenRef = useRef14(false);
25727
+ floatingPanelOpenRef.current = floatingPanel !== null;
25728
+ const floatingPanelRef = useRef14(null);
25729
+ floatingPanelRef.current = floatingPanel;
25730
+ const [floatingPanelPos, setFloatingPanelPos] = useState18(null);
25731
+ const buttonCollectionDragRef = useRef14(null);
25732
+ const buttonDropInsertIndexRef = useRef14(null);
25733
+ const [buttonDropSlots, setButtonDropSlots] = useState18([]);
25734
+ const [activeButtonDropIndex, setActiveButtonDropIndex] = useState18(null);
25735
+ const buttonPointerDragRef = useRef14(null);
25736
+ const [buttonStyleTick, setButtonStyleTick] = useState18(0);
25737
+ const [logoSizeDraft, setLogoSizeDraft] = useState18(null);
25738
+ const [editorViewport, setEditorViewport] = useState18("desktop");
25739
+ const [parentScrollSnap, setParentScrollSnap] = useState18(null);
25808
25740
  const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState18(null);
25809
25741
  const [footerHeadingVisible, setFooterHeadingVisible] = useState18(null);
25810
25742
  const footerDragRef = useRef14(null);
@@ -25830,21 +25762,6 @@ function OhhwellsBridge() {
25830
25762
  const stylesRef = useRef14("");
25831
25763
  const appliedDrawerRef = useRef14(null);
25832
25764
  const pendingDeleteUndoRef = useRef14(null);
25833
- const [floatingPanel, setFloatingPanel] = useState18(null);
25834
- const floatingPanelOpenRef = useRef14(false);
25835
- const floatingPanelRef = useRef14(null);
25836
- floatingPanelRef.current = floatingPanel;
25837
- const setFloatingPanelRef = useRef14(setFloatingPanel);
25838
- const [floatingPanelPos, setFloatingPanelPos] = useState18(null);
25839
- const buttonCollectionDragRef = useRef14(null);
25840
- const buttonDropInsertIndexRef = useRef14(null);
25841
- const [buttonDropSlots, setButtonDropSlots] = useState18([]);
25842
- const [activeButtonDropIndex, setActiveButtonDropIndex] = useState18(null);
25843
- const buttonPointerDragRef = useRef14(null);
25844
- const [buttonStyleTick, setButtonStyleTick] = useState18(0);
25845
- const [logoSizeDraft, setLogoSizeDraft] = useState18(null);
25846
- const [editorViewport, setEditorViewport] = useState18("desktop");
25847
- const [parentScrollSnap, setParentScrollSnap] = useState18(null);
25848
25765
  const [sitePages, setSitePages] = useState18([]);
25849
25766
  const [sectionsByPath, setSectionsByPath] = useState18({});
25850
25767
  const sectionsPrefetchGenRef = useRef14(0);
@@ -25853,18 +25770,7 @@ function OhhwellsBridge() {
25853
25770
  const linkPopoverOpenRef = useRef14(false);
25854
25771
  const linkPopoverGraceUntilRef = useRef14(0);
25855
25772
  setLinkPopoverRef.current = setLinkPopover;
25856
- setFloatingPanelRef.current = setFloatingPanel;
25857
25773
  linkPopoverSessionRef.current = linkPopover;
25858
- floatingPanelOpenRef.current = Boolean(floatingPanel);
25859
- useEffect17(() => {
25860
- const syncViewport = () => {
25861
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
25862
- setEditorViewport((prev) => prev === next ? prev : next);
25863
- };
25864
- syncViewport();
25865
- window.addEventListener("resize", syncViewport);
25866
- return () => window.removeEventListener("resize", syncViewport);
25867
- }, []);
25868
25774
  useEffect17(() => {
25869
25775
  setSectionOrderPersistHandler((entries) => {
25870
25776
  const currentPath = window.location.pathname;
@@ -27532,7 +27438,7 @@ function OhhwellsBridge() {
27532
27438
  isFooterFrameSelection,
27533
27439
  postToParent2
27534
27440
  ]);
27535
- useLayoutEffect7(() => {
27441
+ useLayoutEffect6(() => {
27536
27442
  if (!subdomain || isEditMode) {
27537
27443
  setFetchState("done");
27538
27444
  return;
@@ -27559,7 +27465,6 @@ function OhhwellsBridge() {
27559
27465
  applyAiFooterFromContent(content);
27560
27466
  if (typeof content[STYLE_STORE_KEY] === "string") {
27561
27467
  stylesRef.current = content[STYLE_STORE_KEY];
27562
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
27563
27468
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
27564
27469
  }
27565
27470
  applyBrandChrome(content);
@@ -27570,12 +27475,12 @@ function OhhwellsBridge() {
27570
27475
  if (key === "__ohw_sections") continue;
27571
27476
  if (key === AI_SECTIONS_KEY) continue;
27572
27477
  if (key === AI_FOOTER_KEY) continue;
27573
- if (key === LOGO_PLACEHOLDER_KEY) continue;
27574
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
27575
27478
  if (key === BRAND_KIT_KEY) continue;
27576
27479
  if (key === STYLE_STORE_KEY) continue;
27577
27480
  if (BRAND_CHROME_KEYS.has(key)) continue;
27481
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
27578
27482
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
27483
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
27579
27484
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
27580
27485
  continue;
27581
27486
  }
@@ -27791,18 +27696,17 @@ function OhhwellsBridge() {
27791
27696
  }
27792
27697
  applyAiFooterFromContent(content);
27793
27698
  if (typeof content[STYLE_STORE_KEY] === "string") {
27794
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
27795
27699
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
27796
27700
  }
27797
27701
  for (const [key, val] of Object.entries(content)) {
27798
27702
  if (key === "__ohw_sections") continue;
27799
27703
  if (key === AI_SECTIONS_KEY) continue;
27800
27704
  if (key === AI_FOOTER_KEY) continue;
27801
- if (key === LOGO_PLACEHOLDER_KEY) continue;
27802
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
27803
27705
  if (key === BRAND_KIT_KEY) continue;
27804
27706
  if (key === STYLE_STORE_KEY) continue;
27805
27707
  if (BRAND_CHROME_KEYS.has(key)) continue;
27708
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
27709
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
27806
27710
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
27807
27711
  continue;
27808
27712
  }
@@ -27885,7 +27789,7 @@ function OhhwellsBridge() {
27885
27789
  if (debounceTimer) clearTimeout(debounceTimer);
27886
27790
  };
27887
27791
  }, [subdomain, isEditMode, pathname]);
27888
- useLayoutEffect7(() => {
27792
+ useLayoutEffect6(() => {
27889
27793
  const el = document.getElementById("ohw-loader");
27890
27794
  if (!el) return;
27891
27795
  const visible = Boolean(subdomain) && fetchState !== "done";
@@ -28069,11 +27973,26 @@ function OhhwellsBridge() {
28069
27973
  const t2 = setTimeout(measure, 500);
28070
27974
  const ro = new ResizeObserver(schedule);
28071
27975
  ro.observe(document.body);
27976
+ let lastWidth = window.innerWidth;
27977
+ let resizeTimers = [];
27978
+ const clearResizeTimers = () => {
27979
+ resizeTimers.forEach(clearTimeout);
27980
+ resizeTimers = [];
27981
+ };
27982
+ const handleResize = () => {
27983
+ if (window.innerWidth === lastWidth) return;
27984
+ lastWidth = window.innerWidth;
27985
+ clearResizeTimers();
27986
+ resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
27987
+ };
27988
+ window.addEventListener("resize", handleResize);
28072
27989
  return () => {
28073
27990
  clearTimeout(t1);
28074
27991
  clearTimeout(t2);
28075
27992
  if (raf != null) cancelAnimationFrame(raf);
28076
27993
  ro.disconnect();
27994
+ clearResizeTimers();
27995
+ window.removeEventListener("resize", handleResize);
28077
27996
  };
28078
27997
  }, [pathname, isEditMode, postToParent2]);
28079
27998
  useEffect17(() => {
@@ -28370,13 +28289,6 @@ function OhhwellsBridge() {
28370
28289
  if (target.closest("[data-ohw-state-toggle]")) return;
28371
28290
  if (target.closest("[data-ohw-max-badge]")) return;
28372
28291
  if (isInsideLinkEditor(target)) return;
28373
- if (isInsideFloatingPanel(target)) return;
28374
- if (target.closest("[data-ohw-form-toolbar]")) return;
28375
- if (target.closest(
28376
- '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
28377
- )) {
28378
- return;
28379
- }
28380
28292
  if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
28381
28293
  clearMediaSelectionRef.current();
28382
28294
  }
@@ -28400,6 +28312,13 @@ function OhhwellsBridge() {
28400
28312
  return;
28401
28313
  }
28402
28314
  }
28315
+ if (isInsideFloatingPanel(target)) return;
28316
+ if (target.closest("[data-ohw-form-toolbar]")) return;
28317
+ if (target.closest(
28318
+ '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
28319
+ )) {
28320
+ return;
28321
+ }
28403
28322
  {
28404
28323
  const formEl = getFormElement(target);
28405
28324
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -28553,13 +28472,9 @@ function OhhwellsBridge() {
28553
28472
  if (isIconEditable(editable) && !getSocialItem(editable)) {
28554
28473
  e.preventDefault();
28555
28474
  e.stopPropagation();
28475
+ selectIconElementRef.current(editable);
28556
28476
  const aiIcon = editable.hasAttribute("data-ai-icon");
28557
28477
  const featureIcon = aiIcon && /\.features\.\d+\.icon$/.test(editable.dataset.ohwKey ?? "");
28558
- if (aiIcon) {
28559
- aiSectionApiRef.current?.selectFromElement(editable);
28560
- } else {
28561
- selectIconElementRef.current(editable);
28562
- }
28563
28478
  postToParentRef.current({
28564
28479
  type: "ow:icon-pick",
28565
28480
  key: editable.dataset.ohwKey ?? "",
@@ -28787,9 +28702,6 @@ function OhhwellsBridge() {
28787
28702
  setHoveredItemRect(null);
28788
28703
  hoveredNavContainerRef.current = null;
28789
28704
  setHoveredNavContainerRect(null);
28790
- siblingHintElRef.current = null;
28791
- setSiblingHintRect(null);
28792
- setSiblingHintRects([]);
28793
28705
  return;
28794
28706
  }
28795
28707
  {
@@ -28910,6 +28822,7 @@ function OhhwellsBridge() {
28910
28822
  hoveredNavContainerRef.current = null;
28911
28823
  setHoveredNavContainerRect(null);
28912
28824
  hoveredItemElRef.current = editable;
28825
+ setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
28913
28826
  }
28914
28827
  }
28915
28828
  }
@@ -29619,11 +29532,7 @@ function OhhwellsBridge() {
29619
29532
  };
29620
29533
  const handleMouseMove = (e) => {
29621
29534
  const { clientX, clientY } = e;
29622
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
29623
- dismissImageHover();
29624
- clearImageHover();
29625
- return;
29626
- }
29535
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
29627
29536
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
29628
29537
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
29629
29538
  formHoverElRef.current = null;
@@ -29652,12 +29561,7 @@ function OhhwellsBridge() {
29652
29561
  setHoveredItemRect(null);
29653
29562
  hoveredNavContainerRef.current = null;
29654
29563
  setHoveredNavContainerRect(null);
29655
- siblingHintElRef.current = null;
29656
- setSiblingHintRect(null);
29657
- setSiblingHintRects([]);
29658
29564
  dismissImageHover();
29659
- clearImageHover();
29660
- setSectionGap(null);
29661
29565
  return;
29662
29566
  }
29663
29567
  if (probeSocialsRowAt(clientX, clientY)) return;
@@ -29669,11 +29573,7 @@ function OhhwellsBridge() {
29669
29573
  if (e.data?.type !== "ow:pointer-sync") return;
29670
29574
  const { clientX, clientY } = e.data;
29671
29575
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
29672
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
29673
- dismissImageHover();
29674
- clearImageHover();
29675
- return;
29676
- }
29576
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
29677
29577
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
29678
29578
  if (probeSocialsRowAt(clientX, clientY)) return;
29679
29579
  probeSectionGapAt(clientX, clientY);
@@ -30053,7 +29953,6 @@ function OhhwellsBridge() {
30053
29953
  applyAiFooterFromContent(content);
30054
29954
  if (typeof content[STYLE_STORE_KEY] === "string") {
30055
29955
  stylesRef.current = content[STYLE_STORE_KEY];
30056
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
30057
29956
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
30058
29957
  }
30059
29958
  applyBrandChrome(content);
@@ -30068,12 +29967,12 @@ function OhhwellsBridge() {
30068
29967
  }
30069
29968
  if (key === AI_SECTIONS_KEY) continue;
30070
29969
  if (key === AI_FOOTER_KEY) continue;
30071
- if (key === LOGO_PLACEHOLDER_KEY) continue;
30072
- if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
30073
29970
  if (key === BRAND_KIT_KEY) continue;
30074
29971
  if (key === STYLE_STORE_KEY) continue;
30075
29972
  if (BRAND_CHROME_KEYS.has(key)) continue;
29973
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
30076
29974
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
29975
+ if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
30077
29976
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
30078
29977
  continue;
30079
29978
  }
@@ -30709,12 +30608,6 @@ function OhhwellsBridge() {
30709
30608
  closeLinkPopoverRef.current();
30710
30609
  return;
30711
30610
  }
30712
- if (floatingPanelOpenRef.current) {
30713
- setFloatingPanelRef.current(null);
30714
- deselectRef.current();
30715
- deactivateRef.current();
30716
- return;
30717
- }
30718
30611
  deselectRef.current();
30719
30612
  deactivateRef.current();
30720
30613
  clearMediaSelectionRef.current();
@@ -31537,10 +31430,10 @@ function OhhwellsBridge() {
31537
31430
  window.removeEventListener("message", handleDeleteSection);
31538
31431
  window.removeEventListener("message", handleDuplicateSection);
31539
31432
  window.removeEventListener("message", handleDeactivate);
31433
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
31540
31434
  window.removeEventListener("message", handleToastAction);
31541
31435
  window.removeEventListener("message", handleFormCount);
31542
31436
  window.removeEventListener("message", handleUiEscape);
31543
- document.documentElement.removeAttribute("data-ohw-panel-dragging");
31544
31437
  autoSaveTimers.current.forEach(clearTimeout);
31545
31438
  autoSaveTimers.current.clear();
31546
31439
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
@@ -31834,7 +31727,7 @@ function OhhwellsBridge() {
31834
31727
  postToParent2({
31835
31728
  type: "ow:ready",
31836
31729
  version: "1",
31837
- bridgeVersion: "0.1.151-next.406",
31730
+ bridgeVersion: "0.1.152",
31838
31731
  path: pathname,
31839
31732
  nodes: collectEditableNodes(editContentRef.current),
31840
31733
  sections
@@ -32569,7 +32462,7 @@ function OhhwellsBridge() {
32569
32462
  className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
32570
32463
  onClick: () => setFieldTypePickerOpen((open) => !open),
32571
32464
  "data-ohw-add-field": "",
32572
- children: /* @__PURE__ */ jsx40(Plus6, { size: 15, "aria-hidden": true })
32465
+ children: /* @__PURE__ */ jsx40(Plus5, { size: 15, "aria-hidden": true })
32573
32466
  }
32574
32467
  ),
32575
32468
  /* @__PURE__ */ jsx40("div", { className: "mx-0.5 h-5 w-px bg-border" }),