@ohhwells/bridge 0.1.152-next.410 → 0.1.153

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
  }
@@ -7176,21 +7161,6 @@ function applyCustomCodeToHead(content) {
7176
7161
  if (beforeNodes.length > 0) document.head.append(...beforeNodes);
7177
7162
  }
7178
7163
 
7179
- // src/lib/selectNavContainer.ts
7180
- function isOnScreen(el) {
7181
- const rect = el.getBoundingClientRect();
7182
- if (rect.width <= 0 || rect.height <= 0) return false;
7183
- if (el.offsetParent !== null) return true;
7184
- return getComputedStyle(el).position === "fixed";
7185
- }
7186
- function findSelectableNavContainer(doc = document) {
7187
- const visible = Array.from(doc.querySelectorAll("[data-ohw-nav-container]")).filter(isOnScreen);
7188
- if (visible.length === 0) return null;
7189
- return visible.reduce(
7190
- (best, el) => el.getBoundingClientRect().top < best.getBoundingClientRect().top ? el : best
7191
- );
7192
- }
7193
-
7194
7164
  // src/ui/ai-tree/aiSectionsManager.tsx
7195
7165
  import { flushSync } from "react-dom";
7196
7166
  import { createRoot } from "react-dom/client";
@@ -7764,7 +7734,7 @@ var AI_MOBILE_CSS = [
7764
7734
  // page's first section. Top only (bottom needs no nav clearance); ~96px approximates the
7765
7735
  // template nav's own height (measured ~94px) — there's no shared `--ohw-header-h` var to read
7766
7736
  // an exact figure from (no live measurement exists), so this is a safe approximation, not a
7767
- // pixel-exact fit. Horizontal spacing already comes from `data-ai-section-inner`.
7737
+ // pixel-exact fit. Horizontal spacing already comes from `data-ai-container`.
7768
7738
  '[data-ai-overlay-clearance] [data-ai-overlap-layer="overlay"]{padding-top:96px}',
7769
7739
  // A full-bleed carousel's height is pure arithmetic: it spans the whole window, so 16/9 turns
7770
7740
  // window width straight into height. Measured at 16/9 it came out ~90% of the viewport at EVERY
@@ -7780,10 +7750,8 @@ var AI_MOBILE_CSS = [
7780
7750
  "[data-ai-section]{overflow-x:hidden}",
7781
7751
  // `:not([data-ai-full-bleed])`: this `!important` gutter beat the inline `padding: 0` that a
7782
7752
  // full-bleed section's container sets, so a carousel/media hero that is edge-to-edge on desktop
7783
- // still got a 20px band of section background down both sides on a phone. The footer's own
7784
- // container keeps the unguarded rule below — `data-ai-full-bleed` can never appear on it.
7785
- "[data-ai-section-inner]:not([data-ai-full-bleed]){padding:0 20px !important}",
7786
- "[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}",
7787
7755
  "[data-ai-row]{display:flex !important;flex-direction:column !important;align-items:stretch !important}",
7788
7756
  "[data-ai-cell]{width:100%;min-width:0}",
7789
7757
  // The rule above turns every row into a COLUMN flex container on phones, which silently breaks
@@ -7988,31 +7956,6 @@ function pricingCardEmphasis(featured, ctx, hasBg) {
7988
7956
  function textAttrs(ctx, path) {
7989
7957
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
7990
7958
  }
7991
- var AI_RESPONSIVE_CSS = [
7992
- "@media (max-width: 960px) {",
7993
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
7994
- ' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
7995
- "}",
7996
- "@media (max-width: 640px) {",
7997
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
7998
- " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
7999
- // Group containers flatten to a column on phones; span placements come along for free.
8000
- // `:not([data-ai-group="overlap"])` for the same reason as the twin pair in AI_MOBILE_CSS — see
8001
- // the comment there. This sheet's copy is the narrower selector, so without the exemption it
8002
- // flattens an `overlap` hero below 640px even though the other rule stands down: measured a 390px
8003
- // viewport with the heading/CTA in flow *under* the image, 219px of section background where the
8004
- // layered text used to be.
8005
- ' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) { display: flex !important; flex-direction: column !important; }',
8006
- ' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) > * { grid-column: auto !important; }',
8007
- // `:not([data-ai-full-bleed])` for the same reason as the twin rule in AI_MOBILE_CSS: this one
8008
- // is narrower (0,2,0 vs 0,1,0) and also `!important`, so without the guard it wins outright and
8009
- // a full-bleed hero gets its 20px side band back below 640px only — the one width where the
8010
- // other rule had already been taught to stand down.
8011
- " [data-ai-responsive] [data-ai-section-inner]:not([data-ai-full-bleed]) { padding-left: 20px !important; padding-right: 20px !important; }",
8012
- " [data-ai-responsive] { overflow-x: hidden; }",
8013
- " [data-ai-responsive] img { max-width: 100%; }",
8014
- "}"
8015
- ].join("\n");
8016
7959
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
8017
7960
  function MediaBox({
8018
7961
  refValue,
@@ -8067,7 +8010,7 @@ function MediaBox({
8067
8010
  position: fill ? "absolute" : void 0,
8068
8011
  inset: fill ? 0 : void 0,
8069
8012
  width: fill ? "100%" : fixedSize ? "auto" : "100%",
8070
- height: fill ? "100%" : fixedSize ? height : void 0,
8013
+ height: fill ? "100%" : void 0,
8071
8014
  aspectRatio: fill ? void 0 : aspectRatio,
8072
8015
  minHeight: fill || fixedSize ? void 0 : height ?? (aspectRatio ? void 0 : 180),
8073
8016
  borderRadius: radius,
@@ -9563,7 +9506,7 @@ function CollectionBlock({ node, ctx, path }) {
9563
9506
  return /* @__PURE__ */ jsx(
9564
9507
  "div",
9565
9508
  {
9566
- "data-ai-grid": String(itemsPerRow),
9509
+ "data-ai-grid": "",
9567
9510
  "data-ohw-pricing-collection": isPricing ? "" : void 0,
9568
9511
  style: {
9569
9512
  display: "grid",
@@ -9865,7 +9808,7 @@ function renderNode(node, ctx, path, ambientAlign) {
9865
9808
  },
9866
9809
  children: [
9867
9810
  i > 0 && ctx.heroOverlapFullBleed ? (
9868
- // 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
9869
9812
  // layer (this group's i===0 sibling) can span edge-to-edge — reintroduced here,
9870
9813
  // scoped to just the overlay text, so a heading/copy/CTA stack doesn't stretch
9871
9814
  // the full section width instead of reading at the usual content width.
@@ -10284,7 +10227,6 @@ function AiTreeRenderer({
10284
10227
  ...fillHeight ? { "data-ai-fill-height": "" } : {},
10285
10228
  ...needsOverlayClearance ? { "data-ai-overlay-clearance": "" } : {},
10286
10229
  ...bgAttrs,
10287
- "data-ai-responsive": "",
10288
10230
  style: {
10289
10231
  position: "relative",
10290
10232
  padding: `${padCss} 0`,
@@ -10298,13 +10240,12 @@ function AiTreeRenderer({
10298
10240
  ...fillHeight ? { display: "grid" } : {}
10299
10241
  },
10300
10242
  children: [
10301
- /* @__PURE__ */ jsx("style", { children: AI_RESPONSIVE_CSS }),
10302
- /* @__PURE__ */ jsx("style", { children: AI_MOBILE_CSS }),
10303
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 }),
10304
10245
  /* @__PURE__ */ jsx(
10305
10246
  "div",
10306
10247
  {
10307
- "data-ai-section-inner": "",
10248
+ "data-ai-container": "",
10308
10249
  ...fullBleedMedia ? { "data-ai-full-bleed": "" } : {},
10309
10250
  style: {
10310
10251
  position: "relative",
@@ -10321,7 +10262,7 @@ function AiTreeRenderer({
10321
10262
  children: tree.rows.map((row, r2) => /* @__PURE__ */ jsx(
10322
10263
  "div",
10323
10264
  {
10324
- "data-ai-columns": "",
10265
+ "data-ai-row": "",
10325
10266
  style: {
10326
10267
  display: "grid",
10327
10268
  gridTemplateColumns: "repeat(12, 1fr)",
@@ -10983,10 +10924,9 @@ function applyAiSectionsToDom(state, options) {
10983
10924
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
10984
10925
  continue;
10985
10926
  }
10927
+ const isNewMount = !existing || !existing.container.isConnected;
10986
10928
  let container = existing?.container;
10987
- let isNewMount = false;
10988
10929
  if (!container || !container.isConnected) {
10989
- isNewMount = true;
10990
10930
  existing?.root.unmount();
10991
10931
  container?.remove();
10992
10932
  container = document.createElement("div");
@@ -16979,7 +16919,7 @@ function apiBase() {
16979
16919
  function bridgeVersion() {
16980
16920
  try {
16981
16921
  if (true) {
16982
- return "0.1.152-next.410";
16922
+ return "0.1.153";
16983
16923
  }
16984
16924
  } catch {
16985
16925
  }
@@ -16993,7 +16933,7 @@ function stampBridgeVersionOnDocument() {
16993
16933
  return;
16994
16934
  }
16995
16935
  try {
16996
- const v = true ? "0.1.152-next.410" : "";
16936
+ const v = true ? "0.1.153" : "";
16997
16937
  if (v) {
16998
16938
  document.documentElement.setAttribute("data-ohw-bridge-version", v);
16999
16939
  window.__OHW_BRIDGE_VERSION__ = v;
@@ -17658,7 +17598,6 @@ function MediaOverlay({
17658
17598
  (prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
17659
17599
  );
17660
17600
  }, [isVideo]);
17661
- const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
17662
17601
  const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
17663
17602
  const box = {
17664
17603
  position: "fixed",
@@ -17757,10 +17696,11 @@ function MediaOverlay({
17757
17696
  className: "flex items-center justify-center cursor-pointer",
17758
17697
  style: {
17759
17698
  ...box,
17760
- // Visual only. `pointer-events: auto` on this full-bleed rect covered the navbar
17761
- // (hero bg includes the absolute TopNav) and swallowed CTA press-drag. Text overlay
17762
- // and cueOnly also need clicks to fall through — Replace / video controls opt back in.
17763
- pointerEvents: "none",
17699
+ // When text overlays this media, let clicks fall THROUGH to the text underneath. In the
17700
+ // parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
17701
+ // in-document, pointer-events does it natively. The button below opts back in, so
17702
+ // Replace still works.
17703
+ pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
17764
17704
  // Selected: a firm component ring with no wash, so the image reads as chosen rather
17765
17705
  // than hovered. Hover keeps the existing tinted preview.
17766
17706
  boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
@@ -17787,17 +17727,17 @@ function MediaOverlay({
17787
17727
  },
17788
17728
  children: [
17789
17729
  isVideo ? /* @__PURE__ */ jsx17(Film, { size: 14 }) : /* @__PURE__ */ jsx17(ImageIcon, { size: 14 }),
17790
- replaceLabel
17730
+ isVideo ? "Replace video" : "Replace image"
17791
17731
  ]
17792
17732
  }
17793
17733
  ),
17794
- showChrome && replaceMode !== "none" && /* @__PURE__ */ jsxs8(
17734
+ replaceMode === "none" || cueOnly ? null : /* @__PURE__ */ jsxs8(
17795
17735
  Button,
17796
17736
  {
17797
17737
  "data-ohw-media-overlay": "",
17798
17738
  variant: "outline",
17799
17739
  size: "sm",
17800
- "aria-label": replaceLabel,
17740
+ "aria-label": isVideo ? "Replace video" : "Replace image",
17801
17741
  className: "gap-1.5 cursor-pointer hover:bg-background",
17802
17742
  style: {
17803
17743
  ...OVERLAY_BUTTON_STYLE,
@@ -17820,7 +17760,7 @@ function MediaOverlay({
17820
17760
  },
17821
17761
  children: [
17822
17762
  isVideo ? /* @__PURE__ */ jsx17(Film, { size: 14 }) : /* @__PURE__ */ jsx17(ImageIcon, { size: 14 }),
17823
- replaceMode === "full" ? replaceLabel : null
17763
+ replaceMode === "full" ? isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image" : null
17824
17764
  ]
17825
17765
  }
17826
17766
  )
@@ -18329,24 +18269,8 @@ function AiSectionOverlay({
18329
18269
  }
18330
18270
 
18331
18271
  // src/ui/ai-section/AiMediaStripOverlay.tsx
18332
- import { useCallback as useCallback3, useEffect as useEffect6, useLayoutEffect as useLayoutEffect4, useRef as useRef5, useState as useState8 } from "react";
18333
- import {
18334
- AlignCenter,
18335
- AlignLeft,
18336
- AlignRight,
18337
- ArrowLeft as ArrowLeft2,
18338
- ArrowRight as ArrowRight2,
18339
- Check as Check2,
18340
- ChevronDown as ChevronDown3,
18341
- Image as ImageIcon2,
18342
- ImageMinus,
18343
- ImagePlus,
18344
- Link as LinkIcon,
18345
- Minus,
18346
- Palette,
18347
- Plus as Plus2,
18348
- Star
18349
- } from "lucide-react";
18272
+ import { useCallback as useCallback3, useEffect as useEffect6, useRef as useRef5, useState as useState8 } from "react";
18273
+ import { Star } from "lucide-react";
18350
18274
 
18351
18275
  // src/lib/ai-media-strip-tree.ts
18352
18276
  var MEDIA_STRIP_ITEM_MIN = 1;
@@ -18460,6 +18384,14 @@ function setMediaStripItemAsset(tree, index, assetId) {
18460
18384
  return true;
18461
18385
  });
18462
18386
  }
18387
+ function setMediaStripItemAlt(tree, index, alt) {
18388
+ return withMediaStrip(tree, (block) => {
18389
+ const items = block.items;
18390
+ if (index < 0 || index >= items.length) return false;
18391
+ items[index] = { ...items[index], alt };
18392
+ return true;
18393
+ });
18394
+ }
18463
18395
  function setMediaStripItemLink(tree, index, link) {
18464
18396
  return withMediaStrip(tree, (block) => {
18465
18397
  const items = block.items;
@@ -18477,117 +18409,11 @@ function setMediaStripItemLink(tree, index, link) {
18477
18409
  });
18478
18410
  }
18479
18411
 
18480
- // src/ui/dialog.tsx
18481
- import * as React9 from "react";
18482
- import { Dialog as DialogPrimitive } from "radix-ui";
18483
- import { X as X2 } from "lucide-react";
18484
- import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
18485
- function Dialog2({
18486
- ...props
18487
- }) {
18488
- return /* @__PURE__ */ jsx20(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
18489
- }
18490
- function DialogPortal({
18491
- ...props
18492
- }) {
18493
- return /* @__PURE__ */ jsx20(DialogPrimitive.Portal, { ...props });
18494
- }
18495
- function DialogOverlay({
18496
- className,
18497
- ...props
18498
- }) {
18499
- return /* @__PURE__ */ jsx20(
18500
- DialogPrimitive.Overlay,
18501
- {
18502
- "data-slot": "dialog-overlay",
18503
- "data-ohw-link-modal-root": "",
18504
- className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
18505
- ...props
18506
- }
18507
- );
18508
- }
18509
- var DialogContent = React9.forwardRef(
18510
- ({ className, children, showCloseButton = true, container, ...props }, ref) => {
18511
- const positionMode = container ? "absolute" : "fixed";
18512
- return /* @__PURE__ */ jsxs11(DialogPortal, { container: container ?? void 0, children: [
18513
- /* @__PURE__ */ jsx20(DialogOverlay, { className: cn(positionMode, "inset-0") }),
18514
- /* @__PURE__ */ jsxs11(
18515
- DialogPrimitive.Content,
18516
- {
18517
- ref,
18518
- "data-slot": "dialog-content",
18519
- className: cn(
18520
- positionMode,
18521
- "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",
18522
- "rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
18523
- container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
18524
- className
18525
- ),
18526
- onMouseDown: (e) => e.stopPropagation(),
18527
- ...props,
18528
- children: [
18529
- children,
18530
- showCloseButton ? /* @__PURE__ */ jsx20(
18531
- DialogPrimitive.Close,
18532
- {
18533
- type: "button",
18534
- className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
18535
- "aria-label": "Close",
18536
- children: /* @__PURE__ */ jsx20(X2, { size: 16, "aria-hidden": true })
18537
- }
18538
- ) : null
18539
- ]
18540
- }
18541
- )
18542
- ] });
18543
- }
18544
- );
18545
- DialogContent.displayName = DialogPrimitive.Content.displayName;
18546
- function DialogHeader({
18547
- className,
18548
- ...props
18549
- }) {
18550
- return /* @__PURE__ */ jsx20("div", { className: cn("flex flex-col gap-1.5", className), ...props });
18551
- }
18552
- function DialogFooter({
18553
- className,
18554
- ...props
18555
- }) {
18556
- return /* @__PURE__ */ jsx20(
18557
- "div",
18558
- {
18559
- className: cn("flex items-center justify-end gap-2", className),
18560
- ...props
18561
- }
18562
- );
18563
- }
18564
- var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
18565
- DialogPrimitive.Title,
18566
- {
18567
- ref,
18568
- className: cn(
18569
- "text-lg font-semibold leading-none tracking-tight text-card-foreground",
18570
- className
18571
- ),
18572
- ...props
18573
- }
18574
- ));
18575
- DialogTitle.displayName = DialogPrimitive.Title.displayName;
18576
- var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
18577
- DialogPrimitive.Description,
18578
- {
18579
- ref,
18580
- className: cn("text-sm text-muted-foreground", className),
18581
- ...props
18582
- }
18583
- ));
18584
- DialogDescription.displayName = DialogPrimitive.Description.displayName;
18585
- var DialogClose = DialogPrimitive.Close;
18586
-
18587
18412
  // src/ui/ai-section/AiMediaStripOverlay.tsx
18588
- import { Fragment as Fragment7, jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
18589
- var PRIMARY3 = "var(--ohw-primary, #0885FE)";
18590
- 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]";
18413
+ import { Fragment as Fragment7, jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
18414
+ var PRIMARY3 = "#0885FE";
18415
+ var OHW_BLUE = `var(--ohw-primary, ${PRIMARY3})`;
18416
+ var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY3}) 60%, #000000)`;
18591
18417
  function findMediaStripItemElement(sectionId, index) {
18592
18418
  const sectionEl = findByInstanceId(sectionId);
18593
18419
  if (!sectionEl) return null;
@@ -18597,35 +18423,14 @@ function findMediaStripItemElement(sectionId, index) {
18597
18423
  }
18598
18424
  return null;
18599
18425
  }
18600
- function itemRefFromTarget(target) {
18601
- if (!(target instanceof Element)) return null;
18602
- if (target.closest(CHROME_SELECTOR)) return null;
18603
- const itemEl = target.closest("[data-ohw-media-strip-item]");
18604
- if (!itemEl) return null;
18605
- const sectionEl = itemEl.closest("[data-ohw-section]");
18606
- const unit = sectionEl ? movableUnit(sectionEl) : null;
18607
- const sectionId = unit ? instanceIdOf(unit) || null : null;
18608
- const index = Number(itemEl.dataset.ohwMediaStripIndex);
18609
- if (!sectionId || Number.isNaN(index)) return null;
18610
- return { sectionId, index };
18611
- }
18612
- function sameRef(a, b) {
18613
- return a?.sectionId === b?.sectionId && a?.index === b?.index;
18614
- }
18615
- function rectOf(el) {
18426
+ function readRect2(ref) {
18427
+ const el = ref && findMediaStripItemElement(ref.sectionId, ref.index);
18616
18428
  if (!el) return null;
18617
18429
  const r2 = el.getBoundingClientRect();
18618
18430
  if (r2.width <= 0 || r2.height <= 0) return null;
18619
18431
  return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
18620
18432
  }
18621
- function readRect2(ref) {
18622
- return rectOf(ref && findMediaStripItemElement(ref.sectionId, ref.index));
18623
- }
18624
- function readStripRect(ref) {
18625
- const item = ref && findMediaStripItemElement(ref.sectionId, ref.index);
18626
- return rectOf(item?.closest("[data-ohw-media-strip]") ?? item);
18627
- }
18628
- function useLiveItemRect(ref, strip = false) {
18433
+ function useLiveItemRect(ref) {
18629
18434
  const [rect, setRect] = useState8(null);
18630
18435
  useEffect6(() => {
18631
18436
  if (!ref) {
@@ -18633,7 +18438,7 @@ function useLiveItemRect(ref, strip = false) {
18633
18438
  return;
18634
18439
  }
18635
18440
  const update = () => {
18636
- const next = strip ? readStripRect(ref) : readRect2(ref);
18441
+ const next = readRect2(ref);
18637
18442
  setRect(
18638
18443
  (prev) => prev && next && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
18639
18444
  );
@@ -18648,49 +18453,9 @@ function useLiveItemRect(ref, strip = false) {
18648
18453
  window.removeEventListener("resize", update);
18649
18454
  clearInterval(interval);
18650
18455
  };
18651
- }, [ref?.sectionId, ref?.index, strip]);
18456
+ }, [ref?.sectionId, ref?.index]);
18652
18457
  return rect;
18653
18458
  }
18654
- var TOOLBAR_STRIP_GAP = 52;
18655
- var TOOLBAR_STRIP_GAP_MOBILE = 42;
18656
- var TOOLBAR_EDGE_MARGIN2 = 4;
18657
- function StripToolbarSlot({ stripRect, children }) {
18658
- const slotRef = useRef5(null);
18659
- const [shift, setShift] = useState8(0);
18660
- const centerX = stripRect.left + stripRect.width / 2;
18661
- useLayoutEffect4(() => {
18662
- const slot = slotRef.current;
18663
- if (!slot) return;
18664
- const clamp = () => {
18665
- const w = slot.offsetWidth;
18666
- if (w <= 0) return;
18667
- const half = w / 2;
18668
- const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
18669
- setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
18670
- };
18671
- clamp();
18672
- const ro = new ResizeObserver(clamp);
18673
- ro.observe(slot);
18674
- return () => ro.disconnect();
18675
- }, [centerX, children]);
18676
- const mobile = window.innerWidth <= 480;
18677
- return /* @__PURE__ */ jsx21(
18678
- "div",
18679
- {
18680
- ref: slotRef,
18681
- "data-ohw-bridge": "",
18682
- "data-ohw-item-interaction": "",
18683
- className: "pointer-events-auto fixed",
18684
- style: {
18685
- top: stripRect.top - (mobile ? TOOLBAR_STRIP_GAP_MOBILE : TOOLBAR_STRIP_GAP),
18686
- left: centerX + shift,
18687
- transform: "translate(-50%, -100%)",
18688
- zIndex: 2147483645
18689
- },
18690
- children
18691
- }
18692
- );
18693
- }
18694
18459
  function requestValidateTree(postToParent2, tree) {
18695
18460
  return new Promise((resolve) => {
18696
18461
  const id = `ai-validate-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
@@ -18727,177 +18492,221 @@ function requestAssetPick(postToParent2) {
18727
18492
  postToParent2({ type: "ow:asset-pick", id });
18728
18493
  });
18729
18494
  }
18730
- function ToolbarAction({
18495
+ function Pill({
18731
18496
  label,
18732
18497
  onClick,
18733
- disabled = false,
18734
- active = false,
18735
- children
18498
+ disabled,
18499
+ active
18736
18500
  }) {
18737
- const button = /* @__PURE__ */ jsx21(CustomToolbarButton, { type: "button", "aria-label": label, disabled, active, onClick, className: "size-8", children });
18738
- return /* @__PURE__ */ jsxs12(Tooltip, { children: [
18739
- /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx21("span", { className: "inline-flex", children: button }) : button }),
18740
- /* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
18741
- ] });
18742
- }
18743
- function ToolbarSeparator() {
18744
- return /* @__PURE__ */ jsx21("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
18501
+ return /* @__PURE__ */ jsx20(
18502
+ "button",
18503
+ {
18504
+ type: "button",
18505
+ onClick,
18506
+ disabled,
18507
+ style: {
18508
+ height: 28,
18509
+ padding: "0 10px",
18510
+ display: "inline-flex",
18511
+ alignItems: "center",
18512
+ gap: 4,
18513
+ borderRadius: 999,
18514
+ border: "none",
18515
+ cursor: disabled ? "default" : "pointer",
18516
+ background: active ? OHW_BLUE_DARK : "#ffffff",
18517
+ color: active ? "#ffffff" : OHW_BLUE_DARK,
18518
+ opacity: disabled ? 0.4 : 1,
18519
+ fontSize: 12,
18520
+ lineHeight: "16px",
18521
+ fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
18522
+ whiteSpace: "nowrap",
18523
+ flex: "0 0 auto"
18524
+ },
18525
+ children: label
18526
+ }
18527
+ );
18745
18528
  }
18746
- function OptionMenu({
18747
- label,
18748
- value,
18749
- options,
18750
- onChange
18751
- }) {
18752
- const current = options.find((o) => o.value === value) ?? options[0];
18753
- return /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
18754
- /* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground", children: label }),
18755
- /* @__PURE__ */ jsxs12(DropdownMenu, { modal: false, children: [
18756
- /* @__PURE__ */ jsx21(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs12(
18757
- "button",
18758
- {
18759
- type: "button",
18760
- "aria-label": label,
18761
- 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",
18762
- children: [
18763
- /* @__PURE__ */ jsx21("span", { className: "flex-1 text-left", children: current.label }),
18764
- /* @__PURE__ */ jsx21(ChevronDown3, { size: 16, style: { pointerEvents: "none" } })
18765
- ]
18766
- }
18767
- ) }),
18768
- /* @__PURE__ */ jsx21(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[132px] min-w-[132px] p-1", children: options.map((option) => {
18769
- const selected = option.value === value;
18770
- return /* @__PURE__ */ jsxs12(
18771
- DropdownMenuItem,
18529
+ function AltInput({ value, onCommit }) {
18530
+ const [draft, setDraft] = useState8(value);
18531
+ useEffect6(() => setDraft(value), [value]);
18532
+ return /* @__PURE__ */ jsxs11(
18533
+ "div",
18534
+ {
18535
+ style: {
18536
+ display: "flex",
18537
+ alignItems: "center",
18538
+ gap: 6,
18539
+ height: 28,
18540
+ padding: "0 12px",
18541
+ borderRadius: 999,
18542
+ background: "#ffffff",
18543
+ width: "100%",
18544
+ maxWidth: 260,
18545
+ boxSizing: "border-box"
18546
+ },
18547
+ children: [
18548
+ /* @__PURE__ */ jsx20(
18549
+ "span",
18772
18550
  {
18773
- role: "menuitemradio",
18774
- "aria-checked": selected,
18775
- onSelect: () => onChange(option.value),
18776
- className: cn("grid grid-cols-[1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
18777
- children: [
18778
- /* @__PURE__ */ jsx21("span", { children: option.label }),
18779
- selected && /* @__PURE__ */ jsx21(Check2, { size: 16, className: "text-bridge-primary" })
18780
- ]
18781
- },
18782
- option.value
18783
- );
18784
- }) })
18785
- ] })
18786
- ] });
18787
- }
18788
- var VARIANTS = [
18789
- { value: "logos", label: "Logos" },
18790
- { value: "reel", label: "Reel" }
18791
- ];
18792
- var ALIGNS = [
18793
- { value: "left", label: "Align left", Icon: AlignLeft },
18794
- { value: "center", label: "Align center", Icon: AlignCenter },
18795
- { value: "right", label: "Align right", Icon: AlignRight }
18796
- ];
18797
- var HOVERS = [
18798
- { value: "none", label: "None" },
18799
- { value: "lift", label: "Lift" },
18800
- { value: "zoom", label: "Zoom" },
18801
- { value: "fade", label: "Fade" }
18802
- ];
18551
+ style: {
18552
+ flex: "0 0 auto",
18553
+ color: OHW_BLUE_DARK,
18554
+ fontSize: 10,
18555
+ fontWeight: 700,
18556
+ textTransform: "uppercase",
18557
+ letterSpacing: 0.4
18558
+ },
18559
+ children: "Alt"
18560
+ }
18561
+ ),
18562
+ /* @__PURE__ */ jsx20(
18563
+ "input",
18564
+ {
18565
+ type: "text",
18566
+ value: draft,
18567
+ onChange: (e) => setDraft(e.target.value),
18568
+ onBlur: () => {
18569
+ if (draft !== value) onCommit(draft);
18570
+ },
18571
+ onKeyDown: (e) => {
18572
+ if (e.key === "Enter") e.currentTarget.blur();
18573
+ if (e.key === "Escape") {
18574
+ setDraft(value);
18575
+ e.currentTarget.blur();
18576
+ }
18577
+ },
18578
+ placeholder: "Describe this image",
18579
+ "aria-label": "Image alt text",
18580
+ style: {
18581
+ flex: 1,
18582
+ minWidth: 0,
18583
+ border: "none",
18584
+ outline: "none",
18585
+ background: "transparent",
18586
+ fontSize: 12,
18587
+ lineHeight: "16px",
18588
+ fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
18589
+ color: "#1f2937"
18590
+ }
18591
+ }
18592
+ )
18593
+ ]
18594
+ }
18595
+ );
18596
+ }
18597
+ var VARIANTS = [
18598
+ { value: "logos", label: "Logos" },
18599
+ { value: "reel", label: "Reel" }
18600
+ ];
18601
+ var ALIGNS = [
18602
+ { value: "left", label: "Left" },
18603
+ { value: "center", label: "Center" },
18604
+ { value: "right", label: "Right" }
18605
+ ];
18606
+ var HOVERS = [
18607
+ { value: "none", label: "None" },
18608
+ { value: "lift", label: "Lift" },
18609
+ { value: "zoom", label: "Zoom" },
18610
+ { value: "fade", label: "Fade" }
18611
+ ];
18612
+ var TREATMENTS = [
18613
+ { value: "color", label: "Color" },
18614
+ { value: "grayscale", label: "Grayscale" }
18615
+ ];
18803
18616
  var HTTP_URL_RE = /^https?:\/\/\S+$/i;
18804
- function LinkModal({
18805
- href,
18806
- linkTarget,
18807
- onClose,
18808
- onSave
18809
- }) {
18810
- const [draft, setDraft] = useState8(href);
18811
- const [newTab, setNewTab] = useState8(linkTarget !== "same-tab");
18617
+ function LinkInput({ value, onCommit }) {
18618
+ const [draft, setDraft] = useState8(value);
18812
18619
  const [invalid, setInvalid] = useState8(false);
18813
- const save = () => {
18620
+ useEffect6(() => {
18621
+ setDraft(value);
18622
+ setInvalid(false);
18623
+ }, [value]);
18624
+ const commit = () => {
18814
18625
  const next = draft.trim();
18815
- if (next && !HTTP_URL_RE.test(next)) {
18816
- setInvalid(true);
18817
- return;
18818
- }
18819
- onSave(next, newTab ? "new-tab" : "same-tab");
18820
- onClose();
18626
+ if (next === value) return setInvalid(false);
18627
+ if (next && !HTTP_URL_RE.test(next)) return setInvalid(true);
18628
+ setInvalid(false);
18629
+ onCommit(next);
18821
18630
  };
18822
- 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: [
18823
- /* @__PURE__ */ jsx21(DialogHeader, { children: /* @__PURE__ */ jsx21(DialogTitle, { className: "text-base", children: "Image link" }) }),
18824
- /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-3", children: [
18825
- /* @__PURE__ */ jsx21(
18826
- "input",
18827
- {
18828
- autoFocus: true,
18829
- type: "text",
18830
- inputMode: "url",
18831
- value: draft,
18832
- onChange: (e) => {
18833
- setDraft(e.target.value);
18834
- setInvalid(false);
18835
- },
18836
- onKeyDown: (e) => {
18837
- if (e.key === "Enter") save();
18838
- },
18839
- placeholder: "https://example.com",
18840
- "aria-label": "Image link URL",
18841
- "aria-invalid": invalid,
18842
- className: cn(
18843
- "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",
18844
- invalid && "border-destructive focus:border-destructive"
18845
- )
18846
- }
18847
- ),
18848
- invalid && /* @__PURE__ */ jsx21("p", { className: "text-xs text-destructive", children: "Enter a full URL starting with http:// or https://" }),
18849
- /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-2 text-[13px] text-foreground", children: [
18850
- /* @__PURE__ */ jsx21("input", { type: "checkbox", checked: newTab, onChange: (e) => setNewTab(e.target.checked) }),
18851
- "Open in new tab"
18852
- ] })
18853
- ] }),
18854
- /* @__PURE__ */ jsxs12(DialogFooter, { children: [
18855
- href && /* @__PURE__ */ jsx21(
18856
- "button",
18857
- {
18858
- type: "button",
18859
- onClick: () => {
18860
- onSave("", "new-tab");
18861
- onClose();
18862
- },
18863
- className: "mr-auto rounded-[6px] px-3 py-2 text-[13px] font-medium text-destructive transition-colors hover:bg-muted",
18864
- children: "Remove link"
18865
- }
18866
- ),
18867
- /* @__PURE__ */ jsx21(
18868
- "button",
18869
- {
18870
- type: "button",
18871
- onClick: onClose,
18872
- className: "rounded-[6px] px-3 py-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted",
18873
- children: "Cancel"
18874
- }
18875
- ),
18876
- /* @__PURE__ */ jsx21(
18877
- "button",
18878
- {
18879
- type: "button",
18880
- onClick: save,
18881
- className: "rounded-[6px] bg-bridge-primary px-3 py-2 text-[13px] font-medium text-primary-foreground transition-opacity hover:opacity-90",
18882
- children: "Save"
18883
- }
18884
- )
18885
- ] })
18886
- ] }) });
18631
+ return /* @__PURE__ */ jsxs11(
18632
+ "div",
18633
+ {
18634
+ style: {
18635
+ display: "flex",
18636
+ alignItems: "center",
18637
+ gap: 6,
18638
+ height: 28,
18639
+ padding: "0 12px",
18640
+ borderRadius: 999,
18641
+ background: "#ffffff",
18642
+ width: "100%",
18643
+ maxWidth: 260,
18644
+ boxSizing: "border-box",
18645
+ boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
18646
+ },
18647
+ children: [
18648
+ /* @__PURE__ */ jsx20(
18649
+ "span",
18650
+ {
18651
+ style: {
18652
+ flex: "0 0 auto",
18653
+ color: OHW_BLUE_DARK,
18654
+ fontSize: 10,
18655
+ fontWeight: 700,
18656
+ textTransform: "uppercase",
18657
+ letterSpacing: 0.4
18658
+ },
18659
+ children: "Link"
18660
+ }
18661
+ ),
18662
+ /* @__PURE__ */ jsx20(
18663
+ "input",
18664
+ {
18665
+ type: "text",
18666
+ inputMode: "url",
18667
+ value: draft,
18668
+ onChange: (e) => setDraft(e.target.value),
18669
+ onBlur: commit,
18670
+ onKeyDown: (e) => {
18671
+ if (e.key === "Enter") e.currentTarget.blur();
18672
+ if (e.key === "Escape") {
18673
+ setDraft(value);
18674
+ setInvalid(false);
18675
+ e.currentTarget.blur();
18676
+ }
18677
+ },
18678
+ placeholder: "https://example.com",
18679
+ "aria-label": "Image link URL",
18680
+ "aria-invalid": invalid,
18681
+ style: {
18682
+ flex: 1,
18683
+ minWidth: 0,
18684
+ border: "none",
18685
+ outline: "none",
18686
+ background: "transparent",
18687
+ fontSize: 12,
18688
+ lineHeight: "16px",
18689
+ fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
18690
+ color: "#1f2937"
18691
+ }
18692
+ }
18693
+ )
18694
+ ]
18695
+ }
18696
+ );
18887
18697
  }
18888
18698
  function MediaStripToolbar({
18889
18699
  entry,
18890
18700
  index,
18891
18701
  pending,
18892
18702
  error,
18893
- itemEditOn,
18894
- onToggleItemEdit,
18895
18703
  onSetVariant,
18896
18704
  onSetAlign,
18897
18705
  onSetHover,
18898
18706
  onSetTreatment,
18899
18707
  onResize,
18900
- onOpenLink,
18708
+ onSetAlt,
18709
+ onSetLink,
18901
18710
  onAddItem,
18902
18711
  onRemoveItem,
18903
18712
  onChangeImage,
@@ -18906,102 +18715,81 @@ function MediaStripToolbar({
18906
18715
  }) {
18907
18716
  const items = mediaStripItems(entry.tree);
18908
18717
  const itemCount = items.length;
18718
+ const currentAlt = items[index]?.alt ?? "";
18719
+ const currentHref = items[index]?.href ?? "";
18720
+ const currentTarget = items[index]?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
18909
18721
  const slots = findMediaStripSlots(entry.tree);
18910
18722
  const variant = slots?.variant === "reel" ? "reel" : "logos";
18911
18723
  const align = slots?.align === "left" || slots?.align === "right" ? slots.align : "center";
18912
18724
  const hover = slots?.hover === "none" || slots?.hover === "lift" || slots?.hover === "zoom" || slots?.hover === "fade" ? slots.hover : "lift";
18913
18725
  const treatment = slots?.treatment === "color" || slots?.treatment === "grayscale" ? slots.treatment : variant === "logos" ? "grayscale" : "color";
18914
18726
  const sizeValue = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
18915
- const mobile = window.innerWidth <= 480;
18916
- const gatedLabel = (label) => itemEditOn ? label : "Turn on the star to edit this image";
18917
- return /* @__PURE__ */ jsx21(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs12(
18727
+ const isMobile = window.innerWidth <= 480;
18728
+ const rowStyle = isMobile ? {
18729
+ display: "flex",
18730
+ gap: 6,
18731
+ flexWrap: "nowrap",
18732
+ justifyContent: "center",
18733
+ overflowX: "auto",
18734
+ WebkitOverflowScrolling: "touch",
18735
+ width: "100%",
18736
+ scrollbarWidth: "none"
18737
+ } : { display: "flex", gap: 6, flexWrap: "nowrap", justifyContent: "center" };
18738
+ return /* @__PURE__ */ jsxs11(
18918
18739
  "div",
18919
18740
  {
18920
18741
  "data-ohw-bridge": "",
18921
18742
  "data-ohw-toolbar": "",
18922
18743
  onMouseDown: (e) => e.stopPropagation(),
18923
- className: cn("flex flex-col items-center gap-1.5 font-sans", pending && "pointer-events-none opacity-60"),
18924
- style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
18744
+ style: {
18745
+ display: "flex",
18746
+ flexDirection: "column",
18747
+ gap: 6,
18748
+ alignItems: "center",
18749
+ background: OHW_BLUE,
18750
+ padding: 8,
18751
+ borderRadius: 12,
18752
+ boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
18753
+ pointerEvents: pending ? "none" : "auto",
18754
+ opacity: pending ? 0.6 : 1,
18755
+ maxWidth: isMobile ? "calc(100vw - 24px)" : "none"
18756
+ },
18925
18757
  children: [
18926
- /* @__PURE__ */ jsxs12(
18927
- "div",
18928
- {
18929
- className: cn(
18930
- "flex items-center gap-1 rounded-[10px] border border-border bg-background p-1 whitespace-nowrap",
18931
- "shadow-[0px_10px_15px_-3px_rgba(0,0,0,0.1),0px_4px_6px_-4px_rgba(0,0,0,0.1)]",
18932
- mobile ? "flex-wrap justify-center" : "flex-nowrap"
18933
- ),
18934
- children: [
18935
- /* @__PURE__ */ jsxs12(Tooltip, { children: [
18936
- /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx21(
18937
- CustomToolbarButton,
18938
- {
18939
- type: "button",
18940
- "aria-label": itemEditOn ? "Done editing this image" : "Edit this image",
18941
- "aria-pressed": itemEditOn,
18942
- onClick: onToggleItemEdit,
18943
- className: "group size-8",
18944
- children: /* @__PURE__ */ jsx21(
18945
- Star,
18946
- {
18947
- size: 16,
18948
- fill: "currentColor",
18949
- strokeWidth: 0,
18950
- className: cn(
18951
- "transition-colors",
18952
- itemEditOn ? "text-[#f59e0b] group-hover:text-[#d97706]" : "text-[#d6d3d1] group-hover:text-[#fbbf24]"
18953
- ),
18954
- style: { pointerEvents: "none" }
18955
- }
18956
- )
18957
- }
18958
- ) }),
18959
- /* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: itemEditOn ? "Done editing this image" : "Edit this image" })
18960
- ] }),
18961
- /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
18962
- /* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Change image"), onClick: onChangeImage, disabled: !itemEditOn, children: /* @__PURE__ */ jsx21(ImageIcon2, { size: 16, style: { pointerEvents: "none" } }) }),
18963
- /* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Link"), onClick: onOpenLink, disabled: !itemEditOn, children: /* @__PURE__ */ jsx21(LinkIcon, { size: 16, style: { pointerEvents: "none" } }) }),
18964
- /* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Move left"), onClick: onMoveLeft, disabled: !itemEditOn || index <= 0, children: /* @__PURE__ */ jsx21(ArrowLeft2, { size: 16, style: { pointerEvents: "none" } }) }),
18965
- /* @__PURE__ */ jsx21(
18966
- ToolbarAction,
18967
- {
18968
- label: gatedLabel("Move right"),
18969
- onClick: onMoveRight,
18970
- disabled: !itemEditOn || index >= itemCount - 1,
18971
- children: /* @__PURE__ */ jsx21(ArrowRight2, { size: 16, style: { pointerEvents: "none" } })
18972
- }
18973
- ),
18974
- /* @__PURE__ */ jsx21(ToolbarAction, { label: gatedLabel("Remove image"), onClick: onRemoveItem, disabled: !itemEditOn || itemCount <= 1, children: /* @__PURE__ */ jsx21(ImageMinus, { size: 16, style: { pointerEvents: "none" } }) }),
18975
- /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
18976
- /* @__PURE__ */ jsx21(OptionMenu, { label: "Layout", value: variant, options: VARIANTS, onChange: onSetVariant }),
18977
- /* @__PURE__ */ jsx21(OptionMenu, { label: "Hover", value: hover, options: HOVERS, onChange: onSetHover }),
18978
- /* @__PURE__ */ jsx21(
18979
- ToolbarAction,
18980
- {
18981
- label: treatment === "grayscale" ? "Show in color" : "Show grayscale",
18982
- active: treatment === "grayscale",
18983
- onClick: () => onSetTreatment(treatment === "grayscale" ? "color" : "grayscale"),
18984
- children: /* @__PURE__ */ jsx21(Palette, { size: 16, style: { pointerEvents: "none" } })
18985
- }
18986
- ),
18987
- /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
18988
- 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)),
18989
- /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
18990
- /* @__PURE__ */ jsx21(ToolbarAction, { label: "Smaller", onClick: () => onResize(-8), children: /* @__PURE__ */ jsx21(Minus, { size: 16, style: { pointerEvents: "none" } }) }),
18991
- /* @__PURE__ */ jsxs12("span", { className: "min-w-[40px] text-center text-xs tabular-nums text-muted-foreground", children: [
18992
- sizeValue,
18993
- "px"
18994
- ] }),
18995
- /* @__PURE__ */ jsx21(ToolbarAction, { label: "Larger", onClick: () => onResize(8), children: /* @__PURE__ */ jsx21(Plus2, { size: 16, style: { pointerEvents: "none" } }) }),
18996
- /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
18997
- /* @__PURE__ */ jsx21(ToolbarAction, { label: "Add image", onClick: onAddItem, children: /* @__PURE__ */ jsx21(ImagePlus, { size: 16, style: { pointerEvents: "none" } }) })
18998
- ]
18999
- }
19000
- ),
19001
- 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 })
18758
+ /* @__PURE__ */ jsxs11("div", { style: rowStyle, children: [
18759
+ VARIANTS.map((v) => /* @__PURE__ */ jsx20(Pill, { label: v.label, active: variant === v.value, onClick: () => onSetVariant(v.value) }, v.value)),
18760
+ ALIGNS.map((a) => /* @__PURE__ */ jsx20(Pill, { label: a.label, active: align === a.value, onClick: () => onSetAlign(a.value) }, a.value))
18761
+ ] }),
18762
+ /* @__PURE__ */ jsxs11("div", { style: rowStyle, children: [
18763
+ HOVERS.map((h) => /* @__PURE__ */ jsx20(Pill, { label: h.label, active: hover === h.value, onClick: () => onSetHover(h.value) }, h.value)),
18764
+ TREATMENTS.map((t) => /* @__PURE__ */ jsx20(Pill, { label: t.label, active: treatment === t.value, onClick: () => onSetTreatment(t.value) }, t.value))
18765
+ ] }),
18766
+ /* @__PURE__ */ jsxs11("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
18767
+ /* @__PURE__ */ jsx20(Pill, { label: "\u2212", onClick: () => onResize(-8) }),
18768
+ /* @__PURE__ */ jsxs11("span", { style: { color: "#ffffff", fontSize: 12, minWidth: 34, textAlign: "center" }, children: [
18769
+ sizeValue,
18770
+ "px"
18771
+ ] }),
18772
+ /* @__PURE__ */ jsx20(Pill, { label: "+", onClick: () => onResize(8) })
18773
+ ] }),
18774
+ /* @__PURE__ */ jsx20("div", { style: { display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ jsx20(AltInput, { value: currentAlt, onCommit: onSetAlt }) }),
18775
+ /* @__PURE__ */ jsx20("div", { style: { display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ jsx20(LinkInput, { value: currentHref, onCommit: (href) => onSetLink(href, currentTarget) }) }),
18776
+ currentHref && /* @__PURE__ */ jsxs11("div", { style: rowStyle, children: [
18777
+ /* @__PURE__ */ jsx20(Pill, { label: "New tab", active: currentTarget === "new-tab", onClick: () => onSetLink(currentHref, "new-tab") }),
18778
+ /* @__PURE__ */ jsx20(Pill, { label: "Same tab", active: currentTarget === "same-tab", onClick: () => onSetLink(currentHref, "same-tab") })
18779
+ ] }),
18780
+ /* @__PURE__ */ jsxs11("div", { style: rowStyle, children: [
18781
+ /* @__PURE__ */ jsx20(Pill, { label: "Change Image", onClick: onChangeImage }),
18782
+ /* @__PURE__ */ jsx20(Pill, { label: "+ Item", onClick: onAddItem }),
18783
+ /* @__PURE__ */ jsx20(Pill, { label: "\u2212 Item", onClick: onRemoveItem, disabled: itemCount <= 1 })
18784
+ ] }),
18785
+ /* @__PURE__ */ jsxs11("div", { style: rowStyle, children: [
18786
+ /* @__PURE__ */ jsx20(Pill, { label: "\u2190 Move", onClick: onMoveLeft, disabled: index <= 0 }),
18787
+ /* @__PURE__ */ jsx20(Pill, { label: "\u2192 Move", onClick: onMoveRight, disabled: index >= itemCount - 1 })
18788
+ ] }),
18789
+ error && /* @__PURE__ */ jsx20("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
19002
18790
  ]
19003
18791
  }
19004
- ) });
18792
+ );
19005
18793
  }
19006
18794
  function findMediaStripSlots(tree) {
19007
18795
  const stack = tree.rows.flatMap((row) => row.blocks);
@@ -19020,23 +18808,31 @@ function AiMediaStripOverlay({
19020
18808
  }) {
19021
18809
  const [hover, setHover] = useState8(null);
19022
18810
  const [active, setActive] = useState8(null);
19023
- const [itemEditOn, setItemEditOn] = useState8(false);
19024
- const [linkOpen, setLinkOpen] = useState8(false);
19025
18811
  const [pending, setPending] = useState8(false);
19026
18812
  const [error, setError] = useState8(null);
19027
18813
  const activeRef = useRef5(null);
19028
18814
  activeRef.current = active;
19029
- const linkOpenRef = useRef5(false);
19030
- linkOpenRef.current = linkOpen;
19031
18815
  useEffect6(() => {
19032
18816
  const onMove = (e) => {
19033
- const ref = itemRefFromTarget(e.target);
19034
18817
  const t = e.target;
19035
- const overEditable = Boolean(t?.closest?.("[data-ohw-editable]"));
19036
- setHover((prev) => {
19037
- const next = ref && !overEditable ? ref : null;
19038
- return sameRef(prev, next) ? prev : next;
19039
- });
18818
+ if (!(t instanceof HTMLElement)) return;
18819
+ 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]")) {
18820
+ return;
18821
+ }
18822
+ const itemEl = t.closest("[data-ohw-media-strip-item]");
18823
+ if (!itemEl) {
18824
+ setHover(null);
18825
+ return;
18826
+ }
18827
+ const sectionEl = itemEl.closest("[data-ohw-section]");
18828
+ const unit = sectionEl ? movableUnit(sectionEl) : null;
18829
+ const sectionId = unit ? instanceIdOf(unit) || null : null;
18830
+ const index = Number(itemEl.dataset.ohwMediaStripIndex);
18831
+ if (!sectionId || Number.isNaN(index)) {
18832
+ setHover(null);
18833
+ return;
18834
+ }
18835
+ setHover({ sectionId, index });
19040
18836
  };
19041
18837
  const onLeave = () => setHover(null);
19042
18838
  document.addEventListener("mousemove", onMove, { passive: true });
@@ -19048,25 +18844,23 @@ function AiMediaStripOverlay({
19048
18844
  }, []);
19049
18845
  useEffect6(() => {
19050
18846
  const onClick = (e) => {
18847
+ const current = activeRef.current;
18848
+ if (!current) return;
19051
18849
  const t = e.target;
19052
- if (!(t instanceof Element)) return;
19053
- if (t.closest(CHROME_SELECTOR)) return;
19054
- const ref = itemRefFromTarget(t);
19055
- if (sameRef(activeRef.current, ref)) return;
19056
- if (ref) clearInteractionChromeRef.current();
19057
- setItemEditOn(false);
18850
+ if (!(t instanceof HTMLElement)) return;
18851
+ if (t.closest("[data-ohw-item-interaction]")) return;
18852
+ const itemEl = findMediaStripItemElement(current.sectionId, current.index);
18853
+ if (itemEl && itemEl.contains(t)) return;
18854
+ setActive(null);
19058
18855
  setError(null);
19059
- setActive(ref);
19060
18856
  };
19061
18857
  document.addEventListener("click", onClick, true);
19062
18858
  return () => document.removeEventListener("click", onClick, true);
19063
- }, [clearInteractionChromeRef]);
18859
+ }, []);
19064
18860
  useEffect6(() => {
19065
18861
  const onBlur = () => {
19066
18862
  if (!activeRef.current) return;
19067
18863
  setActive(null);
19068
- setItemEditOn(false);
19069
- setLinkOpen(false);
19070
18864
  setError(null);
19071
18865
  };
19072
18866
  window.addEventListener("blur", onBlur);
@@ -19076,10 +18870,7 @@ function AiMediaStripOverlay({
19076
18870
  const onKeyDown = (e) => {
19077
18871
  if (e.key !== "Escape") return;
19078
18872
  if (!activeRef.current) return;
19079
- if (linkOpenRef.current) return;
19080
- if (document.querySelector('[data-ohw-more-menu][data-state="open"]')) return;
19081
18873
  setActive(null);
19082
- setItemEditOn(false);
19083
18874
  setError(null);
19084
18875
  };
19085
18876
  document.addEventListener("keydown", onKeyDown);
@@ -19113,133 +18904,137 @@ function AiMediaStripOverlay({
19113
18904
  tree: nextTree,
19114
18905
  label: entry.label,
19115
18906
  media: extraMedia ? { ...entry.media, ...extraMedia } : entry.media,
19116
- ...entry.brand ? { brand: entry.brand } : {},
19117
- // The user is already looking at the strip they just edited — recentering the viewport
19118
- // on every edit reads as the section jumping around.
19119
- skipScrollIntoView: true
18907
+ ...entry.brand ? { brand: entry.brand } : {}
19120
18908
  });
19121
18909
  return true;
19122
18910
  },
19123
18911
  [findEntry, postToParent2, applyTreeLocalRef]
19124
18912
  );
19125
18913
  const activeEntry = active ? findEntry(active.sectionId) : null;
18914
+ const hoverHandleRect = useLiveItemRect(!active && hover ? hover : null);
19126
18915
  const activeItemRect = useLiveItemRect(active);
19127
- const activeStripRect = useLiveItemRect(active, true);
19128
- const hoverRect = useLiveItemRect(hover && !sameRef(hover, active) ? hover : null);
19129
- const activeItems = activeEntry ? mediaStripItems(activeEntry.tree) : [];
19130
- const activeItem = active ? activeItems[active.index] : void 0;
19131
- const activeHref = activeItem?.href ?? "";
19132
- const activeTarget = activeItem?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
19133
- return /* @__PURE__ */ jsxs12(Fragment7, { children: [
19134
- hoverRect && /* @__PURE__ */ jsx21(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
19135
- activeItemRect && activeStripRect && active && activeEntry && /* @__PURE__ */ jsxs12(Fragment7, { children: [
19136
- /* @__PURE__ */ jsx21(ItemInteractionLayer, { rect: activeItemRect, state: "active-top" }),
19137
- /* @__PURE__ */ jsx21(StripToolbarSlot, { stripRect: activeStripRect, children: /* @__PURE__ */ jsx21(
19138
- MediaStripToolbar,
19139
- {
19140
- entry: activeEntry,
19141
- index: active.index,
19142
- pending,
19143
- error,
19144
- itemEditOn,
19145
- onToggleItemEdit: () => setItemEditOn((on) => !on),
19146
- onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
19147
- onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
19148
- onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
19149
- onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
19150
- onResize: (delta) => {
19151
- const slots = findMediaStripSlots(activeEntry.tree);
19152
- const variant = slots?.variant === "reel" ? "reel" : "logos";
19153
- const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
19154
- void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
19155
- },
19156
- onOpenLink: () => setLinkOpen(true),
19157
- onAddItem: () => {
19158
- void requestAssetPick(postToParent2).then((picked) => {
19159
- if (!picked) return;
19160
- const item = { assetId: picked.assetId, alt: "Logo" };
18916
+ const TOOLBAR_APPROX_H = 170;
18917
+ const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
18918
+ return /* @__PURE__ */ jsxs11(Fragment7, { children: [
18919
+ hoverHandleRect && hover && /* @__PURE__ */ jsx20(
18920
+ "button",
18921
+ {
18922
+ type: "button",
18923
+ "data-ohw-toolbar": "",
18924
+ onClick: () => {
18925
+ clearInteractionChromeRef.current();
18926
+ setActive(hover);
18927
+ },
18928
+ "aria-label": "Configure media item",
18929
+ style: {
18930
+ position: "fixed",
18931
+ top: hoverHandleRect.top + 8,
18932
+ left: hoverHandleRect.left + hoverHandleRect.width - 36,
18933
+ width: 28,
18934
+ height: 28,
18935
+ borderRadius: 8,
18936
+ border: `1.5px dashed ${PRIMARY3}`,
18937
+ background: "#ffffff",
18938
+ color: PRIMARY3,
18939
+ display: "flex",
18940
+ alignItems: "center",
18941
+ justifyContent: "center",
18942
+ cursor: "pointer",
18943
+ zIndex: 2147483643,
18944
+ fontSize: 14,
18945
+ fontWeight: 700
18946
+ },
18947
+ children: /* @__PURE__ */ jsx20(Star, { size: 14, style: { pointerEvents: "none" } })
18948
+ }
18949
+ ),
18950
+ activeItemRect && active && activeEntry && /* @__PURE__ */ jsx20(
18951
+ ItemInteractionLayer,
18952
+ {
18953
+ rect: activeItemRect,
18954
+ state: toolbarState,
18955
+ toolbar: /* @__PURE__ */ jsx20(
18956
+ MediaStripToolbar,
18957
+ {
18958
+ entry: activeEntry,
18959
+ index: active.index,
18960
+ pending,
18961
+ error,
18962
+ onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
18963
+ onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
18964
+ onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
18965
+ onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
18966
+ onResize: (delta) => {
18967
+ const slots = findMediaStripSlots(activeEntry.tree);
18968
+ const variant = slots?.variant === "reel" ? "reel" : "logos";
18969
+ const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
18970
+ void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
18971
+ },
18972
+ onSetAlt: (alt) => {
18973
+ void runMutation(active.sectionId, (tree) => setMediaStripItemAlt(tree, active.index, alt));
18974
+ },
18975
+ onSetLink: (href, linkTarget) => {
19161
18976
  void runMutation(
19162
18977
  active.sectionId,
19163
- (tree) => addMediaStripItem(tree, item, active.index),
19164
- { [picked.assetId]: picked.url }
19165
- ).then((applied) => {
19166
- if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
18978
+ (tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
18979
+ );
18980
+ },
18981
+ onAddItem: () => {
18982
+ void requestAssetPick(postToParent2).then((picked) => {
18983
+ if (!picked) return;
18984
+ const item = { assetId: picked.assetId, alt: "Logo" };
18985
+ void runMutation(
18986
+ active.sectionId,
18987
+ (tree) => addMediaStripItem(tree, item, active.index),
18988
+ { [picked.assetId]: picked.url }
18989
+ ).then((applied) => {
18990
+ if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
18991
+ });
19167
18992
  });
19168
- });
19169
- },
19170
- onChangeImage: () => {
19171
- void requestAssetPick(postToParent2).then((picked) => {
19172
- if (!picked) return;
19173
- void runMutation(
19174
- active.sectionId,
19175
- (tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
19176
- { [picked.assetId]: picked.url }
18993
+ },
18994
+ onChangeImage: () => {
18995
+ void requestAssetPick(postToParent2).then((picked) => {
18996
+ if (!picked) return;
18997
+ void runMutation(
18998
+ active.sectionId,
18999
+ (tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
19000
+ { [picked.assetId]: picked.url }
19001
+ );
19002
+ });
19003
+ },
19004
+ onRemoveItem: () => {
19005
+ void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
19006
+ (applied) => {
19007
+ if (applied) setActive(null);
19008
+ }
19177
19009
  );
19178
- });
19179
- },
19180
- onRemoveItem: () => {
19181
- void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
19182
- (applied) => {
19183
- if (applied) setActive(null);
19184
- }
19185
- );
19186
- },
19187
- onMoveLeft: () => {
19188
- void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
19189
- (applied) => {
19190
- if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
19191
- }
19192
- );
19193
- },
19194
- onMoveRight: () => {
19195
- void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
19196
- (applied) => {
19197
- if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
19198
- }
19199
- );
19200
- }
19201
- }
19202
- ) }),
19203
- /* @__PURE__ */ jsx21(
19204
- "div",
19205
- {
19206
- "data-ohw-bridge": "",
19207
- "data-ohw-item-interaction": "",
19208
- "aria-hidden": true,
19209
- className: "pointer-events-none fixed rounded-[4px] px-[7px] py-[3px] font-sans text-[11px] font-medium leading-none text-primary-foreground whitespace-nowrap",
19210
- style: {
19211
- top: activeItemRect.top + activeItemRect.height + 10,
19212
- left: activeItemRect.left - 5,
19213
- background: PRIMARY3,
19214
- zIndex: 2147483644
19215
- },
19216
- children: "Media item"
19217
- }
19218
- ),
19219
- linkOpen && /* @__PURE__ */ jsx21(
19220
- LinkModal,
19221
- {
19222
- href: activeHref,
19223
- linkTarget: activeTarget,
19224
- onClose: () => setLinkOpen(false),
19225
- onSave: (href, linkTarget) => {
19226
- void runMutation(
19227
- active.sectionId,
19228
- (tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
19229
- );
19010
+ },
19011
+ onMoveLeft: () => {
19012
+ void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
19013
+ (applied) => {
19014
+ if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
19015
+ }
19016
+ );
19017
+ },
19018
+ onMoveRight: () => {
19019
+ void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
19020
+ (applied) => {
19021
+ if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
19022
+ }
19023
+ );
19024
+ }
19230
19025
  }
19231
- }
19232
- )
19233
- ] })
19026
+ )
19027
+ }
19028
+ )
19234
19029
  ] });
19235
19030
  }
19236
19031
 
19237
19032
  // src/ui/ai-section/AiPricingCardOverlay.tsx
19238
- import { useCallback as useCallback4, useEffect as useEffect7, useLayoutEffect as useLayoutEffect5, useRef as useRef6, useState as useState9 } from "react";
19239
- import { Check as Check3, ChevronDown as ChevronDown4, Minus as Minus2, Plus as Plus3, Star as Star2 } from "lucide-react";
19240
- import { Fragment as Fragment8, jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
19033
+ import { useCallback as useCallback4, useEffect as useEffect7, useLayoutEffect as useLayoutEffect4, useRef as useRef6, useState as useState9 } from "react";
19034
+ import { Check as Check2, ChevronDown as ChevronDown3, Minus, Plus as Plus2, Star as Star2 } from "lucide-react";
19035
+ import { Fragment as Fragment8, jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
19241
19036
  var PRIMARY4 = "var(--ohw-primary, #0885FE)";
19242
- 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]";
19037
+ 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]";
19243
19038
  function findPricingCardElement(sectionId, index) {
19244
19039
  const sectionEl = findByInstanceId(sectionId);
19245
19040
  if (!sectionEl) return null;
@@ -19251,7 +19046,7 @@ function findPricingCardElement(sectionId, index) {
19251
19046
  }
19252
19047
  function cardRefFromTarget(target) {
19253
19048
  if (!(target instanceof Element)) return null;
19254
- if (target.closest(CHROME_SELECTOR2)) return null;
19049
+ if (target.closest(CHROME_SELECTOR)) return null;
19255
19050
  const cardEl = target.closest("[data-ohw-pricing-card]");
19256
19051
  if (!cardEl) return null;
19257
19052
  const sectionEl = cardEl.closest("[data-ohw-section]");
@@ -19261,21 +19056,21 @@ function cardRefFromTarget(target) {
19261
19056
  if (!sectionId || Number.isNaN(index)) return null;
19262
19057
  return { sectionId, index };
19263
19058
  }
19264
- function sameRef2(a, b) {
19059
+ function sameRef(a, b) {
19265
19060
  return a?.sectionId === b?.sectionId && a?.index === b?.index;
19266
19061
  }
19267
- function rectOf2(el) {
19062
+ function rectOf(el) {
19268
19063
  if (!el) return null;
19269
19064
  const r2 = el.getBoundingClientRect();
19270
19065
  if (r2.width <= 0 || r2.height <= 0) return null;
19271
19066
  return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
19272
19067
  }
19273
19068
  function readRect3(ref) {
19274
- return rectOf2(ref && findPricingCardElement(ref.sectionId, ref.index));
19069
+ return rectOf(ref && findPricingCardElement(ref.sectionId, ref.index));
19275
19070
  }
19276
19071
  function readGridRect(ref) {
19277
19072
  const card = ref && findPricingCardElement(ref.sectionId, ref.index);
19278
- return rectOf2(card?.closest("[data-ohw-pricing-collection]") ?? card);
19073
+ return rectOf(card?.closest("[data-ohw-pricing-collection]") ?? card);
19279
19074
  }
19280
19075
  function useLiveCardRect(ref, grid = false) {
19281
19076
  const [rect, setRect] = useState9(null);
@@ -19305,19 +19100,19 @@ function useLiveCardRect(ref, grid = false) {
19305
19100
  }
19306
19101
  var TOOLBAR_GRID_GAP = 52;
19307
19102
  var TOOLBAR_GRID_GAP_MOBILE = 42;
19308
- var TOOLBAR_EDGE_MARGIN3 = 4;
19103
+ var TOOLBAR_EDGE_MARGIN2 = 4;
19309
19104
  function GridToolbarSlot({ gridRect, children }) {
19310
19105
  const slotRef = useRef6(null);
19311
19106
  const [shift, setShift] = useState9(0);
19312
19107
  const centerX = gridRect.left + gridRect.width / 2;
19313
- useLayoutEffect5(() => {
19108
+ useLayoutEffect4(() => {
19314
19109
  const slot = slotRef.current;
19315
19110
  if (!slot) return;
19316
19111
  const clamp = () => {
19317
19112
  const w = slot.offsetWidth;
19318
19113
  if (w <= 0) return;
19319
19114
  const half = w / 2;
19320
- const clamped = Math.max(TOOLBAR_EDGE_MARGIN3 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half));
19115
+ const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
19321
19116
  setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
19322
19117
  };
19323
19118
  clamp();
@@ -19326,7 +19121,7 @@ function GridToolbarSlot({ gridRect, children }) {
19326
19121
  return () => ro.disconnect();
19327
19122
  }, [centerX, children]);
19328
19123
  const mobile = window.innerWidth <= 480;
19329
- return /* @__PURE__ */ jsx22(
19124
+ return /* @__PURE__ */ jsx21(
19330
19125
  "div",
19331
19126
  {
19332
19127
  ref: slotRef,
@@ -19361,7 +19156,7 @@ function requestValidateTree2(postToParent2, tree) {
19361
19156
  });
19362
19157
  }
19363
19158
  function StyleSwatch({ style }) {
19364
- return /* @__PURE__ */ jsx22(
19159
+ return /* @__PURE__ */ jsx21(
19365
19160
  "span",
19366
19161
  {
19367
19162
  "aria-hidden": true,
@@ -19375,35 +19170,35 @@ function StyleSwatch({ style }) {
19375
19170
  );
19376
19171
  }
19377
19172
  function ButtonGlyph() {
19378
- return /* @__PURE__ */ jsxs13("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19379
- /* @__PURE__ */ jsx22("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
19380
- /* @__PURE__ */ jsx22("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
19173
+ return /* @__PURE__ */ jsxs12("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19174
+ /* @__PURE__ */ jsx21("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
19175
+ /* @__PURE__ */ jsx21("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
19381
19176
  ] });
19382
19177
  }
19383
19178
  function FeatureGlyph({ mode }) {
19384
- return /* @__PURE__ */ jsxs13("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19385
- /* @__PURE__ */ jsx22("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
19386
- /* @__PURE__ */ jsx22("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
19387
- /* @__PURE__ */ jsx22("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
19388
- /* @__PURE__ */ jsx22("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
19389
- /* @__PURE__ */ jsx22("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
19390
- mode === "add" && /* @__PURE__ */ jsx22("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
19179
+ return /* @__PURE__ */ jsxs12("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19180
+ /* @__PURE__ */ jsx21("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
19181
+ /* @__PURE__ */ jsx21("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
19182
+ /* @__PURE__ */ jsx21("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
19183
+ /* @__PURE__ */ jsx21("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
19184
+ /* @__PURE__ */ jsx21("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
19185
+ mode === "add" && /* @__PURE__ */ jsx21("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
19391
19186
  ] });
19392
19187
  }
19393
- function ToolbarAction2({
19188
+ function ToolbarAction({
19394
19189
  label,
19395
19190
  onClick,
19396
19191
  disabled = false,
19397
19192
  children
19398
19193
  }) {
19399
- const button = /* @__PURE__ */ jsx22(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
19400
- return /* @__PURE__ */ jsxs13(Tooltip, { children: [
19401
- /* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx22("span", { className: "inline-flex", children: button }) : button }),
19402
- /* @__PURE__ */ jsx22(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
19194
+ const button = /* @__PURE__ */ jsx21(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
19195
+ return /* @__PURE__ */ jsxs12(Tooltip, { children: [
19196
+ /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx21("span", { className: "inline-flex", children: button }) : button }),
19197
+ /* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
19403
19198
  ] });
19404
19199
  }
19405
- function ToolbarSeparator2() {
19406
- return /* @__PURE__ */ jsx22("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
19200
+ function ToolbarSeparator() {
19201
+ return /* @__PURE__ */ jsx21("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
19407
19202
  }
19408
19203
  function CardStyleMenu({
19409
19204
  value,
@@ -19411,7 +19206,7 @@ function CardStyleMenu({
19411
19206
  disabled = false
19412
19207
  }) {
19413
19208
  const current = PRICING_CARD_STYLES.find((s) => s.value === value) ?? PRICING_CARD_STYLES[0];
19414
- const trigger = /* @__PURE__ */ jsxs13(
19209
+ const trigger = /* @__PURE__ */ jsxs12(
19415
19210
  "button",
19416
19211
  {
19417
19212
  type: "button",
@@ -19422,28 +19217,28 @@ function CardStyleMenu({
19422
19217
  disabled && "cursor-not-allowed opacity-40 hover:bg-transparent"
19423
19218
  ),
19424
19219
  children: [
19425
- /* @__PURE__ */ jsx22(StyleSwatch, { style: current.value }),
19426
- /* @__PURE__ */ jsx22("span", { className: "flex-1 text-left", children: current.label }),
19427
- /* @__PURE__ */ jsx22(ChevronDown4, { size: 16, style: { pointerEvents: "none" } })
19220
+ /* @__PURE__ */ jsx21(StyleSwatch, { style: current.value }),
19221
+ /* @__PURE__ */ jsx21("span", { className: "flex-1 text-left", children: current.label }),
19222
+ /* @__PURE__ */ jsx21(ChevronDown3, { size: 16, style: { pointerEvents: "none" } })
19428
19223
  ]
19429
19224
  }
19430
19225
  );
19431
19226
  if (disabled) {
19432
- return /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19433
- /* @__PURE__ */ jsx22("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
19434
- /* @__PURE__ */ jsxs13(Tooltip, { children: [
19435
- /* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx22("span", { className: "inline-flex", children: trigger }) }),
19436
- /* @__PURE__ */ jsx22(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
19227
+ return /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19228
+ /* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
19229
+ /* @__PURE__ */ jsxs12(Tooltip, { children: [
19230
+ /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx21("span", { className: "inline-flex", children: trigger }) }),
19231
+ /* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
19437
19232
  ] })
19438
19233
  ] });
19439
19234
  }
19440
- return /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19441
- /* @__PURE__ */ jsx22("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
19442
- /* @__PURE__ */ jsxs13(DropdownMenu, { modal: false, children: [
19443
- /* @__PURE__ */ jsx22(DropdownMenuTrigger, { asChild: true, children: trigger }),
19444
- /* @__PURE__ */ jsx22(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
19235
+ return /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19236
+ /* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
19237
+ /* @__PURE__ */ jsxs12(DropdownMenu, { modal: false, children: [
19238
+ /* @__PURE__ */ jsx21(DropdownMenuTrigger, { asChild: true, children: trigger }),
19239
+ /* @__PURE__ */ jsx21(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
19445
19240
  const selected = style.value === value;
19446
- return /* @__PURE__ */ jsxs13(
19241
+ return /* @__PURE__ */ jsxs12(
19447
19242
  DropdownMenuItem,
19448
19243
  {
19449
19244
  role: "menuitemradio",
@@ -19451,9 +19246,9 @@ function CardStyleMenu({
19451
19246
  onSelect: () => onChange(style.value),
19452
19247
  className: cn("grid grid-cols-[18px_1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
19453
19248
  children: [
19454
- /* @__PURE__ */ jsx22(StyleSwatch, { style: style.value }),
19455
- /* @__PURE__ */ jsx22("span", { children: style.label }),
19456
- selected && /* @__PURE__ */ jsx22(Check3, { size: 16, className: "text-bridge-primary" })
19249
+ /* @__PURE__ */ jsx21(StyleSwatch, { style: style.value }),
19250
+ /* @__PURE__ */ jsx21("span", { children: style.label }),
19251
+ selected && /* @__PURE__ */ jsx21(Check2, { size: 16, className: "text-bridge-primary" })
19457
19252
  ]
19458
19253
  },
19459
19254
  style.value
@@ -19483,7 +19278,7 @@ function PricingCardToolbar({
19483
19278
  const style = pricingCardStyle(entry.tree, index);
19484
19279
  const featuredTag = pricingCardFeaturedTag(entry.tree, index);
19485
19280
  const mobile = window.innerWidth <= 480;
19486
- return /* @__PURE__ */ jsx22(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs13(
19281
+ return /* @__PURE__ */ jsx21(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs12(
19487
19282
  "div",
19488
19283
  {
19489
19284
  "data-ohw-bridge": "",
@@ -19495,7 +19290,7 @@ function PricingCardToolbar({
19495
19290
  ),
19496
19291
  style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
19497
19292
  children: [
19498
- /* @__PURE__ */ jsxs13(
19293
+ /* @__PURE__ */ jsxs12(
19499
19294
  "div",
19500
19295
  {
19501
19296
  className: cn(
@@ -19504,8 +19299,8 @@ function PricingCardToolbar({
19504
19299
  mobile ? "flex-wrap justify-center" : "flex-nowrap"
19505
19300
  ),
19506
19301
  children: [
19507
- /* @__PURE__ */ jsxs13(Tooltip, { children: [
19508
- /* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx22(
19302
+ /* @__PURE__ */ jsxs12(Tooltip, { children: [
19303
+ /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx21(
19509
19304
  CustomToolbarButton,
19510
19305
  {
19511
19306
  type: "button",
@@ -19513,7 +19308,7 @@ function PricingCardToolbar({
19513
19308
  "aria-pressed": featuredTag,
19514
19309
  onClick: () => onSetFeaturedTag(!featuredTag),
19515
19310
  className: "group size-8",
19516
- children: /* @__PURE__ */ jsx22(
19311
+ children: /* @__PURE__ */ jsx21(
19517
19312
  Star2,
19518
19313
  {
19519
19314
  size: 16,
@@ -19528,25 +19323,25 @@ function PricingCardToolbar({
19528
19323
  )
19529
19324
  }
19530
19325
  ) }),
19531
- /* @__PURE__ */ jsx22(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
19326
+ /* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
19532
19327
  ] }),
19533
- /* @__PURE__ */ jsx22(ToolbarSeparator2, {}),
19534
- /* @__PURE__ */ jsx22(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
19535
- /* @__PURE__ */ jsx22(ToolbarSeparator2, {}),
19536
- /* @__PURE__ */ jsx22(ToolbarAction2, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ jsx22(ButtonGlyph, {}) }),
19537
- /* @__PURE__ */ jsx22(ToolbarAction2, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ jsxs13("span", { className: "relative inline-flex", children: [
19538
- /* @__PURE__ */ jsx22(ButtonGlyph, {}),
19539
- /* @__PURE__ */ jsx22(Minus2, { size: 10, strokeWidth: 2.5, className: "absolute -right-1.5 -top-1.5 rounded-full bg-background text-bridge-primary" })
19328
+ /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
19329
+ /* @__PURE__ */ jsx21(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
19330
+ /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
19331
+ /* @__PURE__ */ jsx21(ToolbarAction, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ jsx21(ButtonGlyph, {}) }),
19332
+ /* @__PURE__ */ jsx21(ToolbarAction, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ jsxs12("span", { className: "relative inline-flex", children: [
19333
+ /* @__PURE__ */ jsx21(ButtonGlyph, {}),
19334
+ /* @__PURE__ */ jsx21(Minus, { size: 10, strokeWidth: 2.5, className: "absolute -right-1.5 -top-1.5 rounded-full bg-background text-bridge-primary" })
19540
19335
  ] }) }),
19541
- /* @__PURE__ */ jsx22(ToolbarAction2, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ jsx22(FeatureGlyph, { mode: "add" }) }),
19542
- /* @__PURE__ */ jsx22(ToolbarAction2, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ jsx22(FeatureGlyph, { mode: "remove" }) }),
19543
- /* @__PURE__ */ jsx22(ToolbarSeparator2, {}),
19544
- /* @__PURE__ */ jsx22(ToolbarAction2, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ jsx22(Plus3, { size: 16, style: { pointerEvents: "none" } }) }),
19545
- /* @__PURE__ */ jsx22(ToolbarAction2, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ jsx22(Minus2, { size: 16, style: { pointerEvents: "none" } }) })
19336
+ /* @__PURE__ */ jsx21(ToolbarAction, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ jsx21(FeatureGlyph, { mode: "add" }) }),
19337
+ /* @__PURE__ */ jsx21(ToolbarAction, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ jsx21(FeatureGlyph, { mode: "remove" }) }),
19338
+ /* @__PURE__ */ jsx21(ToolbarSeparator, {}),
19339
+ /* @__PURE__ */ jsx21(ToolbarAction, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ jsx21(Plus2, { size: 16, style: { pointerEvents: "none" } }) }),
19340
+ /* @__PURE__ */ jsx21(ToolbarAction, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ jsx21(Minus, { size: 16, style: { pointerEvents: "none" } }) })
19546
19341
  ]
19547
19342
  }
19548
19343
  ),
19549
- 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 })
19344
+ 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 })
19550
19345
  ]
19551
19346
  }
19552
19347
  ) });
@@ -19580,7 +19375,7 @@ function AiPricingCardOverlay({
19580
19375
  const overEditable = Boolean(t?.closest?.("[data-ohw-editable], [data-ohw-role], a, button"));
19581
19376
  setHover((prev) => {
19582
19377
  const next = ref && !overEditable ? ref : null;
19583
- return sameRef2(prev, next) ? prev : next;
19378
+ return sameRef(prev, next) ? prev : next;
19584
19379
  });
19585
19380
  };
19586
19381
  const onLeave = () => setHover(null);
@@ -19595,10 +19390,10 @@ function AiPricingCardOverlay({
19595
19390
  const onClick = (e) => {
19596
19391
  const t = e.target;
19597
19392
  if (!(t instanceof Element)) return;
19598
- if (t.closest(CHROME_SELECTOR2)) return;
19393
+ if (t.closest(CHROME_SELECTOR)) return;
19599
19394
  const ref = cardRefFromTarget(t);
19600
- setActive((prev) => sameRef2(prev, ref) ? prev : ref);
19601
- if (!ref || !sameRef2(activeRef.current, ref)) setError(null);
19395
+ setActive((prev) => sameRef(prev, ref) ? prev : ref);
19396
+ if (!ref || !sameRef(activeRef.current, ref)) setError(null);
19602
19397
  };
19603
19398
  document.addEventListener("click", onClick, true);
19604
19399
  return () => document.removeEventListener("click", onClick, true);
@@ -19663,12 +19458,12 @@ function AiPricingCardOverlay({
19663
19458
  const activeEntry = active ? findEntry(active.sectionId) : null;
19664
19459
  const activeCardRect = useLiveCardRect(active);
19665
19460
  const activeGridRect = useLiveCardRect(active, true);
19666
- const hoverRect = useLiveCardRect(hover && !sameRef2(hover, active) ? hover : null);
19667
- return /* @__PURE__ */ jsxs13(Fragment8, { children: [
19668
- hoverRect && /* @__PURE__ */ jsx22(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
19669
- activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ jsxs13(Fragment8, { children: [
19670
- /* @__PURE__ */ jsx22(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
19671
- /* @__PURE__ */ jsx22(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ jsx22(
19461
+ const hoverRect = useLiveCardRect(hover && !sameRef(hover, active) ? hover : null);
19462
+ return /* @__PURE__ */ jsxs12(Fragment8, { children: [
19463
+ hoverRect && /* @__PURE__ */ jsx21(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
19464
+ activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ jsxs12(Fragment8, { children: [
19465
+ /* @__PURE__ */ jsx21(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
19466
+ /* @__PURE__ */ jsx21(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ jsx21(
19672
19467
  PricingCardToolbar,
19673
19468
  {
19674
19469
  entry: activeEntry,
@@ -19696,7 +19491,7 @@ function AiPricingCardOverlay({
19696
19491
  onRemoveFeature: () => runMutation(active.sectionId, (tree) => removePricingCardFeature(tree, active.index))
19697
19492
  }
19698
19493
  ) }),
19699
- /* @__PURE__ */ jsx22(
19494
+ /* @__PURE__ */ jsx21(
19700
19495
  "div",
19701
19496
  {
19702
19497
  "data-ohw-bridge": "",
@@ -19789,10 +19584,10 @@ function extractYouTubeId(input) {
19789
19584
  }
19790
19585
 
19791
19586
  // src/ui/ai-section/AiVideoOverlay.tsx
19792
- import { Fragment as Fragment9, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
19587
+ import { Fragment as Fragment9, jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
19793
19588
  var PRIMARY5 = "#0885FE";
19794
- var OHW_BLUE = `var(--ohw-primary, ${PRIMARY5})`;
19795
- var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
19589
+ var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY5})`;
19590
+ var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
19796
19591
  function findVideoBlockElement(sectionId, path) {
19797
19592
  const sectionEl = findByInstanceId(sectionId);
19798
19593
  if (!sectionEl) return null;
@@ -19852,12 +19647,12 @@ function requestValidateTree3(postToParent2, tree) {
19852
19647
  postToParent2({ type: "ow:ai-validate-tree-request", id, tree });
19853
19648
  });
19854
19649
  }
19855
- function Pill({
19650
+ function Pill2({
19856
19651
  label,
19857
19652
  onClick,
19858
19653
  disabled
19859
19654
  }) {
19860
- return /* @__PURE__ */ jsx23(
19655
+ return /* @__PURE__ */ jsx22(
19861
19656
  "button",
19862
19657
  {
19863
19658
  type: "button",
@@ -19873,7 +19668,7 @@ function Pill({
19873
19668
  border: "none",
19874
19669
  cursor: disabled ? "default" : "pointer",
19875
19670
  background: "#ffffff",
19876
- color: OHW_BLUE_DARK,
19671
+ color: OHW_BLUE_DARK2,
19877
19672
  opacity: disabled ? 0.4 : 1,
19878
19673
  fontSize: 12,
19879
19674
  lineHeight: "16px",
@@ -19916,8 +19711,8 @@ function VideoUrlInput({ value, onCommit }) {
19916
19711
  onCommit(id);
19917
19712
  }
19918
19713
  };
19919
- return /* @__PURE__ */ jsxs14("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
19920
- /* @__PURE__ */ jsxs14(
19714
+ return /* @__PURE__ */ jsxs13("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
19715
+ /* @__PURE__ */ jsxs13(
19921
19716
  "div",
19922
19717
  {
19923
19718
  style: {
@@ -19933,12 +19728,12 @@ function VideoUrlInput({ value, onCommit }) {
19933
19728
  boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
19934
19729
  },
19935
19730
  children: [
19936
- /* @__PURE__ */ jsx23(
19731
+ /* @__PURE__ */ jsx22(
19937
19732
  "span",
19938
19733
  {
19939
19734
  style: {
19940
19735
  flex: "0 0 auto",
19941
- color: OHW_BLUE_DARK,
19736
+ color: OHW_BLUE_DARK2,
19942
19737
  fontSize: 10,
19943
19738
  lineHeight: "16px",
19944
19739
  fontWeight: 700,
@@ -19948,7 +19743,7 @@ function VideoUrlInput({ value, onCommit }) {
19948
19743
  children: "Video"
19949
19744
  }
19950
19745
  ),
19951
- /* @__PURE__ */ jsx23(
19746
+ /* @__PURE__ */ jsx22(
19952
19747
  "input",
19953
19748
  {
19954
19749
  type: "text",
@@ -19985,7 +19780,7 @@ function VideoUrlInput({ value, onCommit }) {
19985
19780
  ]
19986
19781
  }
19987
19782
  ),
19988
- 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." })
19783
+ 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." })
19989
19784
  ] });
19990
19785
  }
19991
19786
  function VideoToolbar({
@@ -19995,7 +19790,7 @@ function VideoToolbar({
19995
19790
  onSetVideoId,
19996
19791
  onRemove
19997
19792
  }) {
19998
- return /* @__PURE__ */ jsxs14(
19793
+ return /* @__PURE__ */ jsxs13(
19999
19794
  "div",
20000
19795
  {
20001
19796
  "data-ohw-bridge": "",
@@ -20007,7 +19802,7 @@ function VideoToolbar({
20007
19802
  gap: 6,
20008
19803
  alignItems: "center",
20009
19804
  width: 280,
20010
- background: OHW_BLUE,
19805
+ background: OHW_BLUE2,
20011
19806
  padding: 8,
20012
19807
  borderRadius: 12,
20013
19808
  boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
@@ -20015,9 +19810,9 @@ function VideoToolbar({
20015
19810
  opacity: pending ? 0.6 : 1
20016
19811
  },
20017
19812
  children: [
20018
- /* @__PURE__ */ jsx23(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
20019
- /* @__PURE__ */ jsx23(Pill, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
20020
- error && /* @__PURE__ */ jsx23("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
19813
+ /* @__PURE__ */ jsx22(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
19814
+ /* @__PURE__ */ jsx22(Pill2, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
19815
+ error && /* @__PURE__ */ jsx22("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
20021
19816
  ]
20022
19817
  }
20023
19818
  );
@@ -20137,8 +19932,8 @@ function AiVideoOverlay({
20137
19932
  const activeBlockRect = useLiveBlockRect(active);
20138
19933
  const TOOLBAR_APPROX_H = 90;
20139
19934
  const toolbarState = activeBlockRect && activeBlockRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
20140
- return /* @__PURE__ */ jsxs14(Fragment9, { children: [
20141
- hoverHandleRect && hover && /* @__PURE__ */ jsx23(
19935
+ return /* @__PURE__ */ jsxs13(Fragment9, { children: [
19936
+ hoverHandleRect && hover && /* @__PURE__ */ jsx22(
20142
19937
  "button",
20143
19938
  {
20144
19939
  type: "button",
@@ -20166,15 +19961,15 @@ function AiVideoOverlay({
20166
19961
  fontSize: 14,
20167
19962
  fontWeight: 700
20168
19963
  },
20169
- children: /* @__PURE__ */ jsx23(Star3, { size: 14, style: { pointerEvents: "none" } })
19964
+ children: /* @__PURE__ */ jsx22(Star3, { size: 14, style: { pointerEvents: "none" } })
20170
19965
  }
20171
19966
  ),
20172
- activeBlockRect && active && activeEntry && /* @__PURE__ */ jsx23(
19967
+ activeBlockRect && active && activeEntry && /* @__PURE__ */ jsx22(
20173
19968
  ItemInteractionLayer,
20174
19969
  {
20175
19970
  rect: activeBlockRect,
20176
19971
  state: toolbarState,
20177
- toolbar: /* @__PURE__ */ jsx23(
19972
+ toolbar: /* @__PURE__ */ jsx22(
20178
19973
  VideoToolbar,
20179
19974
  {
20180
19975
  videoId: videoIdAt(activeEntry.tree, active.path),
@@ -20249,10 +20044,10 @@ function setCarouselAutoplay(tree, on) {
20249
20044
  }
20250
20045
 
20251
20046
  // src/ui/ai-section/AiFadeCarouselOverlay.tsx
20252
- import { Fragment as Fragment10, jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
20047
+ import { Fragment as Fragment10, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
20253
20048
  var PRIMARY6 = "#0885FE";
20254
- var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY6})`;
20255
- var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
20049
+ var OHW_BLUE3 = `var(--ohw-primary, ${PRIMARY6})`;
20050
+ var OHW_BLUE_DARK3 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
20256
20051
  function findCarouselItemElement(sectionId, index) {
20257
20052
  const sectionEl = findByInstanceId(sectionId);
20258
20053
  if (!sectionEl) return null;
@@ -20331,8 +20126,8 @@ function requestAssetPick2(postToParent2) {
20331
20126
  postToParent2({ type: "ow:asset-pick", id });
20332
20127
  });
20333
20128
  }
20334
- function Pill2({ label, onClick, disabled }) {
20335
- return /* @__PURE__ */ jsx24(
20129
+ function Pill3({ label, onClick, disabled }) {
20130
+ return /* @__PURE__ */ jsx23(
20336
20131
  "button",
20337
20132
  {
20338
20133
  type: "button",
@@ -20348,7 +20143,7 @@ function Pill2({ label, onClick, disabled }) {
20348
20143
  border: "none",
20349
20144
  cursor: disabled ? "default" : "pointer",
20350
20145
  background: "#ffffff",
20351
- color: OHW_BLUE_DARK2,
20146
+ color: OHW_BLUE_DARK3,
20352
20147
  opacity: disabled ? 0.4 : 1,
20353
20148
  fontSize: 12,
20354
20149
  lineHeight: "16px",
@@ -20366,7 +20161,7 @@ function TogglePill({
20366
20161
  onToggle,
20367
20162
  disabled
20368
20163
  }) {
20369
- return /* @__PURE__ */ jsxs15(
20164
+ return /* @__PURE__ */ jsxs14(
20370
20165
  "button",
20371
20166
  {
20372
20167
  type: "button",
@@ -20385,7 +20180,7 @@ function TogglePill({
20385
20180
  border: "none",
20386
20181
  cursor: disabled ? "default" : "pointer",
20387
20182
  background: "#ffffff",
20388
- color: OHW_BLUE_DARK2,
20183
+ color: OHW_BLUE_DARK3,
20389
20184
  opacity: disabled ? 0.4 : 1,
20390
20185
  fontSize: 12,
20391
20186
  lineHeight: "16px",
@@ -20395,7 +20190,7 @@ function TogglePill({
20395
20190
  },
20396
20191
  children: [
20397
20192
  label,
20398
- /* @__PURE__ */ jsx24(
20193
+ /* @__PURE__ */ jsx23(
20399
20194
  "span",
20400
20195
  {
20401
20196
  "aria-hidden": true,
@@ -20408,10 +20203,10 @@ function TogglePill({
20408
20203
  // Off is a grey track, not a washed-out blue: the pill's own white background already
20409
20204
  // carries the brand colour in the text, and a pale blue track next to it read as
20410
20205
  // "disabled control" rather than "switch that is off".
20411
- background: on ? OHW_BLUE_DARK2 : "#CBD5E1",
20206
+ background: on ? OHW_BLUE_DARK3 : "#CBD5E1",
20412
20207
  transition: "background 120ms ease"
20413
20208
  },
20414
- children: /* @__PURE__ */ jsx24(
20209
+ children: /* @__PURE__ */ jsx23(
20415
20210
  "span",
20416
20211
  {
20417
20212
  style: {
@@ -20440,7 +20235,7 @@ function CarouselSlideToolbar({
20440
20235
  onChangeImage,
20441
20236
  onToggleAutoplay
20442
20237
  }) {
20443
- return /* @__PURE__ */ jsxs15(
20238
+ return /* @__PURE__ */ jsxs14(
20444
20239
  "div",
20445
20240
  {
20446
20241
  "data-ohw-bridge": "",
@@ -20451,7 +20246,7 @@ function CarouselSlideToolbar({
20451
20246
  flexDirection: "column",
20452
20247
  gap: 6,
20453
20248
  alignItems: "center",
20454
- background: OHW_BLUE2,
20249
+ background: OHW_BLUE3,
20455
20250
  padding: 8,
20456
20251
  borderRadius: 12,
20457
20252
  boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
@@ -20463,11 +20258,11 @@ function CarouselSlideToolbar({
20463
20258
  pointerEvents: pending ? "none" : "auto"
20464
20259
  },
20465
20260
  children: [
20466
- /* @__PURE__ */ jsxs15("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
20467
- /* @__PURE__ */ jsx24(Pill2, { label: "Change Image", onClick: onChangeImage }),
20468
- /* @__PURE__ */ jsx24(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
20261
+ /* @__PURE__ */ jsxs14("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
20262
+ /* @__PURE__ */ jsx23(Pill3, { label: "Change Image", onClick: onChangeImage }),
20263
+ /* @__PURE__ */ jsx23(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
20469
20264
  ] }),
20470
- error && /* @__PURE__ */ jsx24("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
20265
+ error && /* @__PURE__ */ jsx23("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
20471
20266
  ]
20472
20267
  }
20473
20268
  );
@@ -20607,8 +20402,8 @@ function AiFadeCarouselOverlay({
20607
20402
  const activeItemRect = useLiveItemRect2(active);
20608
20403
  const TOOLBAR_APPROX_H = 90;
20609
20404
  const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
20610
- return /* @__PURE__ */ jsxs15(Fragment10, { children: [
20611
- hoverHandleRect && hover && /* @__PURE__ */ jsx24(
20405
+ return /* @__PURE__ */ jsxs14(Fragment10, { children: [
20406
+ hoverHandleRect && hover && /* @__PURE__ */ jsx23(
20612
20407
  "button",
20613
20408
  {
20614
20409
  type: "button",
@@ -20637,10 +20432,10 @@ function AiFadeCarouselOverlay({
20637
20432
  fontSize: 14,
20638
20433
  fontWeight: 700
20639
20434
  },
20640
- children: /* @__PURE__ */ jsx24(Star4, { size: 14, style: { pointerEvents: "none" } })
20435
+ children: /* @__PURE__ */ jsx23(Star4, { size: 14, style: { pointerEvents: "none" } })
20641
20436
  }
20642
20437
  ),
20643
- swapping && /* @__PURE__ */ jsx24(
20438
+ swapping && /* @__PURE__ */ jsx23(
20644
20439
  "div",
20645
20440
  {
20646
20441
  ref: skeletonRef,
@@ -20658,15 +20453,15 @@ function AiFadeCarouselOverlay({
20658
20453
  zIndex: 2147483646,
20659
20454
  pointerEvents: "none"
20660
20455
  },
20661
- children: /* @__PURE__ */ jsx24("style", { children: MEDIA_SKELETON_CSS })
20456
+ children: /* @__PURE__ */ jsx23("style", { children: MEDIA_SKELETON_CSS })
20662
20457
  }
20663
20458
  ),
20664
- activeItemRect && active && activeEntry && /* @__PURE__ */ jsx24(
20459
+ activeItemRect && active && activeEntry && /* @__PURE__ */ jsx23(
20665
20460
  ItemInteractionLayer,
20666
20461
  {
20667
20462
  rect: activeItemRect,
20668
20463
  state: toolbarState,
20669
- toolbar: /* @__PURE__ */ jsx24(
20464
+ toolbar: /* @__PURE__ */ jsx23(
20670
20465
  CarouselSlideToolbar,
20671
20466
  {
20672
20467
  pending,
@@ -21019,11 +20814,118 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
21019
20814
  // src/ui/link-modal/LinkPopover.tsx
21020
20815
  import { useEffect as useEffect13 } from "react";
21021
20816
 
20817
+ // src/ui/dialog.tsx
20818
+ import * as React9 from "react";
20819
+ import { Dialog as DialogPrimitive } from "radix-ui";
20820
+ import { X as X2 } from "lucide-react";
20821
+ import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
20822
+ function Dialog2({
20823
+ ...props
20824
+ }) {
20825
+ return /* @__PURE__ */ jsx24(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
20826
+ }
20827
+ function DialogPortal({
20828
+ ...props
20829
+ }) {
20830
+ return /* @__PURE__ */ jsx24(DialogPrimitive.Portal, { ...props });
20831
+ }
20832
+ function DialogOverlay({
20833
+ className,
20834
+ ...props
20835
+ }) {
20836
+ return /* @__PURE__ */ jsx24(
20837
+ DialogPrimitive.Overlay,
20838
+ {
20839
+ "data-slot": "dialog-overlay",
20840
+ "data-ohw-link-modal-root": "",
20841
+ className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
20842
+ ...props
20843
+ }
20844
+ );
20845
+ }
20846
+ var DialogContent = React9.forwardRef(
20847
+ ({ className, children, showCloseButton = true, container, ...props }, ref) => {
20848
+ const positionMode = container ? "absolute" : "fixed";
20849
+ return /* @__PURE__ */ jsxs15(DialogPortal, { container: container ?? void 0, children: [
20850
+ /* @__PURE__ */ jsx24(DialogOverlay, { className: cn(positionMode, "inset-0") }),
20851
+ /* @__PURE__ */ jsxs15(
20852
+ DialogPrimitive.Content,
20853
+ {
20854
+ ref,
20855
+ "data-slot": "dialog-content",
20856
+ className: cn(
20857
+ positionMode,
20858
+ "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",
20859
+ "rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
20860
+ container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
20861
+ className
20862
+ ),
20863
+ onMouseDown: (e) => e.stopPropagation(),
20864
+ ...props,
20865
+ children: [
20866
+ children,
20867
+ showCloseButton ? /* @__PURE__ */ jsx24(
20868
+ DialogPrimitive.Close,
20869
+ {
20870
+ type: "button",
20871
+ className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
20872
+ "aria-label": "Close",
20873
+ children: /* @__PURE__ */ jsx24(X2, { size: 16, "aria-hidden": true })
20874
+ }
20875
+ ) : null
20876
+ ]
20877
+ }
20878
+ )
20879
+ ] });
20880
+ }
20881
+ );
20882
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
20883
+ function DialogHeader({
20884
+ className,
20885
+ ...props
20886
+ }) {
20887
+ return /* @__PURE__ */ jsx24("div", { className: cn("flex flex-col gap-1.5", className), ...props });
20888
+ }
20889
+ function DialogFooter({
20890
+ className,
20891
+ ...props
20892
+ }) {
20893
+ return /* @__PURE__ */ jsx24(
20894
+ "div",
20895
+ {
20896
+ className: cn("flex items-center justify-end gap-2", className),
20897
+ ...props
20898
+ }
20899
+ );
20900
+ }
20901
+ var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
20902
+ DialogPrimitive.Title,
20903
+ {
20904
+ ref,
20905
+ className: cn(
20906
+ "text-lg font-semibold leading-none tracking-tight text-card-foreground",
20907
+ className
20908
+ ),
20909
+ ...props
20910
+ }
20911
+ ));
20912
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
20913
+ var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
20914
+ DialogPrimitive.Description,
20915
+ {
20916
+ ref,
20917
+ className: cn("text-sm text-muted-foreground", className),
20918
+ ...props
20919
+ }
20920
+ ));
20921
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
20922
+ var DialogClose = DialogPrimitive.Close;
20923
+
21022
20924
  // src/ui/link-modal/LinkEditorPanel.tsx
21023
20925
  import { Info, X as X4 } from "lucide-react";
21024
20926
 
21025
20927
  // src/ui/link-modal/DestinationBreadcrumb.tsx
21026
- import { ArrowRight as ArrowRight3, File, GalleryVertical } from "lucide-react";
20928
+ import { ArrowRight as ArrowRight2, File, GalleryVertical } from "lucide-react";
21027
20929
  import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
21028
20930
  function DestinationBreadcrumb({
21029
20931
  pageTitle,
@@ -21037,7 +20939,7 @@ function DestinationBreadcrumb({
21037
20939
  /* @__PURE__ */ jsx25("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
21038
20940
  ] }),
21039
20941
  /* @__PURE__ */ jsx25(
21040
- ArrowRight3,
20942
+ ArrowRight2,
21041
20943
  {
21042
20944
  size: 16,
21043
20945
  className: "shrink-0 text-muted-foreground",
@@ -21149,7 +21051,7 @@ function Label({ className, ...props }) {
21149
21051
  }
21150
21052
 
21151
21053
  // src/ui/link-modal/UrlOrPageInput.tsx
21152
- import { ChevronDown as ChevronDown5, File as File2, X as X3 } from "lucide-react";
21054
+ import { ChevronDown as ChevronDown4, File as File2, X as X3 } from "lucide-react";
21153
21055
  import { jsx as jsx29, jsxs as jsxs18 } from "react/jsx-runtime";
21154
21056
  function FieldChevron({
21155
21057
  onClick
@@ -21162,7 +21064,7 @@ function FieldChevron({
21162
21064
  onClick,
21163
21065
  "aria-label": "Open page list",
21164
21066
  tabIndex: -1,
21165
- children: /* @__PURE__ */ jsx29(ChevronDown5, { size: 16 })
21067
+ children: /* @__PURE__ */ jsx29(ChevronDown4, { size: 16 })
21166
21068
  }
21167
21069
  );
21168
21070
  }
@@ -21392,7 +21294,7 @@ function LinkEditorPanel({ state, onClose }) {
21392
21294
  // src/ui/link-modal/SectionPickerOverlay.tsx
21393
21295
  import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo2, useRef as useRef10, useState as useState13 } from "react";
21394
21296
  import { createPortal as createPortal2 } from "react-dom";
21395
- import { ArrowLeft as ArrowLeft3, Check as Check4 } from "lucide-react";
21297
+ import { ArrowLeft as ArrowLeft2, Check as Check3 } from "lucide-react";
21396
21298
  import { usePathname, useRouter as useRouter2 } from "next/navigation";
21397
21299
 
21398
21300
  // src/lib/parent-scroll.ts
@@ -21669,7 +21571,7 @@ function SectionPickerOverlay({
21669
21571
  className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
21670
21572
  onClick: onBack,
21671
21573
  children: [
21672
- /* @__PURE__ */ jsx31(ArrowLeft3, { className: "size-4 shrink-0", "aria-hidden": true }),
21574
+ /* @__PURE__ */ jsx31(ArrowLeft2, { className: "size-4 shrink-0", "aria-hidden": true }),
21673
21575
  "Back"
21674
21576
  ]
21675
21577
  }
@@ -21738,7 +21640,7 @@ function SectionPickerOverlay({
21738
21640
  className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
21739
21641
  style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
21740
21642
  "aria-hidden": true,
21741
- children: /* @__PURE__ */ jsx31(Check4, { className: "size-5" })
21643
+ children: /* @__PURE__ */ jsx31(Check3, { className: "size-5" })
21742
21644
  }
21743
21645
  ) : null
21744
21646
  ]
@@ -22122,7 +22024,6 @@ function shouldUseDevFixtures() {
22122
22024
  function getLogoElement(el) {
22123
22025
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
22124
22026
  if (marked) return marked;
22125
- if (el.closest('[data-ohw-editable="icon"]')) return null;
22126
22027
  const root = el.closest("nav, [data-ohw-nav-root], footer");
22127
22028
  if (!root) return null;
22128
22029
  const anchor = el.closest("a");
@@ -22192,7 +22093,7 @@ function addFooterColumnWithPersist({
22192
22093
  import {
22193
22094
  useCallback as useCallback9,
22194
22095
  useEffect as useEffect14,
22195
- useLayoutEffect as useLayoutEffect6,
22096
+ useLayoutEffect as useLayoutEffect5,
22196
22097
  useRef as useRef11,
22197
22098
  useState as useState15
22198
22099
  } from "react";
@@ -22289,7 +22190,7 @@ function FloatingPanel({
22289
22190
  return () => window.removeEventListener("message", onParentScroll);
22290
22191
  }, [open]);
22291
22192
  const positionRef = useRef11(position);
22292
- useLayoutEffect6(() => {
22193
+ useLayoutEffect5(() => {
22293
22194
  if (!open) {
22294
22195
  positionRef.current = position;
22295
22196
  return;
@@ -22299,7 +22200,7 @@ function FloatingPanel({
22299
22200
  }
22300
22201
  positionRef.current = position;
22301
22202
  }, [open, position, liveScroll, parentScroll]);
22302
- useLayoutEffect6(() => {
22203
+ useLayoutEffect5(() => {
22303
22204
  if (!open || !panelRef.current) return;
22304
22205
  const el = panelRef.current;
22305
22206
  const header = el.querySelector("[data-ohw-floating-panel-header]");
@@ -22508,7 +22409,7 @@ function SocialsDisplayPanel({ display, onChange, className }) {
22508
22409
  }
22509
22410
 
22510
22411
  // src/ui/button-style-panel.tsx
22511
- import { Check as Check5 } from "lucide-react";
22412
+ import { Check as Check4 } from "lucide-react";
22512
22413
  import { jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
22513
22414
  var SIZE_LABEL = { s: "S", m: "M", l: "L" };
22514
22415
  function ButtonStylePanel({
@@ -22579,7 +22480,7 @@ function ButtonStylePanel({
22579
22480
  {
22580
22481
  className: "absolute right-0.5 top-0.5 flex size-5 items-center justify-center rounded-full bg-primary text-primary-foreground",
22581
22482
  "aria-hidden": true,
22582
- children: /* @__PURE__ */ jsx35(Check5, { className: "size-3", strokeWidth: 3 })
22483
+ children: /* @__PURE__ */ jsx35(Check4, { className: "size-3", strokeWidth: 3 })
22583
22484
  }
22584
22485
  ) : null
22585
22486
  ]
@@ -23604,7 +23505,7 @@ function useSectionDrag({
23604
23505
  }
23605
23506
 
23606
23507
  // src/ui/footer-container-chrome.tsx
23607
- import { Plus as Plus4 } from "lucide-react";
23508
+ import { Plus as Plus3 } from "lucide-react";
23608
23509
  import { jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
23609
23510
  function FooterContainerChrome({
23610
23511
  rect,
@@ -23645,7 +23546,7 @@ function FooterContainerChrome({
23645
23546
  if (addDisabled) return;
23646
23547
  onAdd();
23647
23548
  },
23648
- children: /* @__PURE__ */ jsx36(Plus4, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
23549
+ children: /* @__PURE__ */ jsx36(Plus3, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
23649
23550
  }
23650
23551
  ) }),
23651
23552
  /* @__PURE__ */ jsx36(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
@@ -23824,7 +23725,7 @@ function deleteSelectedNavFooterItem(deps) {
23824
23725
  }
23825
23726
 
23826
23727
  // src/ui/navbar-container-chrome.tsx
23827
- import { Plus as Plus5 } from "lucide-react";
23728
+ import { Plus as Plus4 } from "lucide-react";
23828
23729
  import { jsx as jsx37 } from "react/jsx-runtime";
23829
23730
  function NavbarContainerChrome({
23830
23731
  rect,
@@ -23860,7 +23761,7 @@ function NavbarContainerChrome({
23860
23761
  e.stopPropagation();
23861
23762
  onAdd();
23862
23763
  },
23863
- children: /* @__PURE__ */ jsx37(Plus5, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
23764
+ children: /* @__PURE__ */ jsx37(Plus4, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
23864
23765
  }
23865
23766
  )
23866
23767
  }
@@ -23932,7 +23833,7 @@ function Badge({ className, variant, ...props }) {
23932
23833
  }
23933
23834
 
23934
23835
  // src/OhhwellsBridge.tsx
23935
- import { Brush as Brush2, Link as Link2, Plus as Plus6, Settings } from "lucide-react";
23836
+ import { Brush as Brush2, Link as Link2, Plus as Plus5, Settings } from "lucide-react";
23936
23837
  import { Fragment as Fragment13, jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
23937
23838
  var PRIMARY7 = "#0885FE";
23938
23839
  var IMAGE_FADE_MS = 300;
@@ -24709,7 +24610,7 @@ function getNavigationSelectionParent(el) {
24709
24610
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
24710
24611
  return resolveFooterLinksContainerFrom(el);
24711
24612
  }
24712
- 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)) {
24613
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
24713
24614
  return getNavigationRoot(el);
24714
24615
  }
24715
24616
  return null;
@@ -24931,6 +24832,7 @@ var ICONS = {
24931
24832
  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"/>',
24932
24833
  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"/>'
24933
24834
  };
24835
+ var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
24934
24836
  var SELECTION_CHROME_GAP2 = 4;
24935
24837
  var TOOLBAR_STROKE_GAP2 = 4;
24936
24838
  var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
@@ -25028,7 +24930,7 @@ function applyVisibleViewport(el, parentScroll) {
25028
24930
  el.style.top = `${top}px`;
25029
24931
  el.style.height = `${height}px`;
25030
24932
  }
25031
- var TOOLBAR_EDGE_MARGIN4 = 4;
24933
+ var TOOLBAR_EDGE_MARGIN3 = 4;
25032
24934
  function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
25033
24935
  const isAbove = transform.includes("translateY(-100%)");
25034
24936
  let visualTop = isAbove ? top - approxH : top;
@@ -25055,8 +24957,8 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
25055
24957
  function clampToolbarLeft(centerX, toolbarWidth) {
25056
24958
  const half = toolbarWidth / 2;
25057
24959
  return Math.max(
25058
- TOOLBAR_EDGE_MARGIN4 + half,
25059
- Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN4 - half)
24960
+ TOOLBAR_EDGE_MARGIN3 + half,
24961
+ Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half)
25060
24962
  );
25061
24963
  }
25062
24964
  function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
@@ -25457,7 +25359,7 @@ function OhhwellsBridge() {
25457
25359
  }, []);
25458
25360
  const subdomainFromQuery = searchParams.get("subdomain");
25459
25361
  const [subdomain, setSubdomain] = useState18(() => resolveSubdomain(subdomainFromQuery));
25460
- useLayoutEffect7(() => {
25362
+ useLayoutEffect6(() => {
25461
25363
  const next = resolveSubdomain(subdomainFromQuery);
25462
25364
  if (next !== subdomain) setSubdomain(next);
25463
25365
  if (next) return;
@@ -25936,6 +25838,21 @@ function OhhwellsBridge() {
25936
25838
  const [isItemDragging, setIsItemDragging] = useState18(false);
25937
25839
  const [isFooterFrameSelection, setIsFooterFrameSelection] = useState18(false);
25938
25840
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
25841
+ const [floatingPanel, setFloatingPanel] = useState18(null);
25842
+ const floatingPanelOpenRef = useRef14(false);
25843
+ floatingPanelOpenRef.current = floatingPanel !== null;
25844
+ const floatingPanelRef = useRef14(null);
25845
+ floatingPanelRef.current = floatingPanel;
25846
+ const [floatingPanelPos, setFloatingPanelPos] = useState18(null);
25847
+ const buttonCollectionDragRef = useRef14(null);
25848
+ const buttonDropInsertIndexRef = useRef14(null);
25849
+ const [buttonDropSlots, setButtonDropSlots] = useState18([]);
25850
+ const [activeButtonDropIndex, setActiveButtonDropIndex] = useState18(null);
25851
+ const buttonPointerDragRef = useRef14(null);
25852
+ const [buttonStyleTick, setButtonStyleTick] = useState18(0);
25853
+ const [logoSizeDraft, setLogoSizeDraft] = useState18(null);
25854
+ const [editorViewport, setEditorViewport] = useState18("desktop");
25855
+ const [parentScrollSnap, setParentScrollSnap] = useState18(null);
25939
25856
  const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState18(null);
25940
25857
  const [footerHeadingVisible, setFooterHeadingVisible] = useState18(null);
25941
25858
  const footerDragRef = useRef14(null);
@@ -25961,21 +25878,6 @@ function OhhwellsBridge() {
25961
25878
  const stylesRef = useRef14("");
25962
25879
  const appliedDrawerRef = useRef14(null);
25963
25880
  const pendingDeleteUndoRef = useRef14(null);
25964
- const [floatingPanel, setFloatingPanel] = useState18(null);
25965
- const floatingPanelOpenRef = useRef14(false);
25966
- const floatingPanelRef = useRef14(null);
25967
- floatingPanelRef.current = floatingPanel;
25968
- const setFloatingPanelRef = useRef14(setFloatingPanel);
25969
- const [floatingPanelPos, setFloatingPanelPos] = useState18(null);
25970
- const buttonCollectionDragRef = useRef14(null);
25971
- const buttonDropInsertIndexRef = useRef14(null);
25972
- const [buttonDropSlots, setButtonDropSlots] = useState18([]);
25973
- const [activeButtonDropIndex, setActiveButtonDropIndex] = useState18(null);
25974
- const buttonPointerDragRef = useRef14(null);
25975
- const [buttonStyleTick, setButtonStyleTick] = useState18(0);
25976
- const [logoSizeDraft, setLogoSizeDraft] = useState18(null);
25977
- const [editorViewport, setEditorViewport] = useState18("desktop");
25978
- const [parentScrollSnap, setParentScrollSnap] = useState18(null);
25979
25881
  const [sitePages, setSitePages] = useState18([]);
25980
25882
  const [sectionsByPath, setSectionsByPath] = useState18({});
25981
25883
  const sectionsPrefetchGenRef = useRef14(0);
@@ -25984,18 +25886,7 @@ function OhhwellsBridge() {
25984
25886
  const linkPopoverOpenRef = useRef14(false);
25985
25887
  const linkPopoverGraceUntilRef = useRef14(0);
25986
25888
  setLinkPopoverRef.current = setLinkPopover;
25987
- setFloatingPanelRef.current = setFloatingPanel;
25988
25889
  linkPopoverSessionRef.current = linkPopover;
25989
- floatingPanelOpenRef.current = Boolean(floatingPanel);
25990
- useEffect17(() => {
25991
- const syncViewport = () => {
25992
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
25993
- setEditorViewport((prev) => prev === next ? prev : next);
25994
- };
25995
- syncViewport();
25996
- window.addEventListener("resize", syncViewport);
25997
- return () => window.removeEventListener("resize", syncViewport);
25998
- }, []);
25999
25890
  useEffect17(() => {
26000
25891
  setSectionOrderPersistHandler((entries) => {
26001
25892
  const currentPath = window.location.pathname;
@@ -27663,7 +27554,7 @@ function OhhwellsBridge() {
27663
27554
  isFooterFrameSelection,
27664
27555
  postToParent2
27665
27556
  ]);
27666
- useLayoutEffect7(() => {
27557
+ useLayoutEffect6(() => {
27667
27558
  if (!subdomain || isEditMode) {
27668
27559
  setFetchState("done");
27669
27560
  return;
@@ -27690,7 +27581,6 @@ function OhhwellsBridge() {
27690
27581
  applyAiFooterFromContent(content);
27691
27582
  if (typeof content[STYLE_STORE_KEY] === "string") {
27692
27583
  stylesRef.current = content[STYLE_STORE_KEY];
27693
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
27694
27584
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
27695
27585
  }
27696
27586
  applyBrandChrome(content);
@@ -27701,12 +27591,12 @@ function OhhwellsBridge() {
27701
27591
  if (key === "__ohw_sections") continue;
27702
27592
  if (key === AI_SECTIONS_KEY) continue;
27703
27593
  if (key === AI_FOOTER_KEY) continue;
27704
- if (key === LOGO_PLACEHOLDER_KEY) continue;
27705
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
27706
27594
  if (key === BRAND_KIT_KEY) continue;
27707
27595
  if (key === STYLE_STORE_KEY) continue;
27708
27596
  if (BRAND_CHROME_KEYS.has(key)) continue;
27597
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
27709
27598
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
27599
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
27710
27600
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
27711
27601
  continue;
27712
27602
  }
@@ -27937,18 +27827,17 @@ function OhhwellsBridge() {
27937
27827
  }
27938
27828
  applyAiFooterFromContent(content);
27939
27829
  if (typeof content[STYLE_STORE_KEY] === "string") {
27940
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
27941
27830
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
27942
27831
  }
27943
27832
  for (const [key, val] of Object.entries(content)) {
27944
27833
  if (key === "__ohw_sections") continue;
27945
27834
  if (key === AI_SECTIONS_KEY) continue;
27946
27835
  if (key === AI_FOOTER_KEY) continue;
27947
- if (key === LOGO_PLACEHOLDER_KEY) continue;
27948
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
27949
27836
  if (key === BRAND_KIT_KEY) continue;
27950
27837
  if (key === STYLE_STORE_KEY) continue;
27951
27838
  if (BRAND_CHROME_KEYS.has(key)) continue;
27839
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
27840
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
27952
27841
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
27953
27842
  continue;
27954
27843
  }
@@ -28031,7 +27920,7 @@ function OhhwellsBridge() {
28031
27920
  if (debounceTimer) clearTimeout(debounceTimer);
28032
27921
  };
28033
27922
  }, [subdomain, isEditMode, pathname]);
28034
- useLayoutEffect7(() => {
27923
+ useLayoutEffect6(() => {
28035
27924
  const el = document.getElementById("ohw-loader");
28036
27925
  if (!el) return;
28037
27926
  const visible = Boolean(subdomain) && fetchState !== "done";
@@ -28215,11 +28104,26 @@ function OhhwellsBridge() {
28215
28104
  const t2 = setTimeout(measure, 500);
28216
28105
  const ro = new ResizeObserver(schedule);
28217
28106
  ro.observe(document.body);
28107
+ let lastWidth = window.innerWidth;
28108
+ let resizeTimers = [];
28109
+ const clearResizeTimers = () => {
28110
+ resizeTimers.forEach(clearTimeout);
28111
+ resizeTimers = [];
28112
+ };
28113
+ const handleResize = () => {
28114
+ if (window.innerWidth === lastWidth) return;
28115
+ lastWidth = window.innerWidth;
28116
+ clearResizeTimers();
28117
+ resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
28118
+ };
28119
+ window.addEventListener("resize", handleResize);
28218
28120
  return () => {
28219
28121
  clearTimeout(t1);
28220
28122
  clearTimeout(t2);
28221
28123
  if (raf != null) cancelAnimationFrame(raf);
28222
28124
  ro.disconnect();
28125
+ clearResizeTimers();
28126
+ window.removeEventListener("resize", handleResize);
28223
28127
  };
28224
28128
  }, [pathname, isEditMode, postToParent2]);
28225
28129
  useEffect17(() => {
@@ -28516,13 +28420,6 @@ function OhhwellsBridge() {
28516
28420
  if (target.closest("[data-ohw-state-toggle]")) return;
28517
28421
  if (target.closest("[data-ohw-max-badge]")) return;
28518
28422
  if (isInsideLinkEditor(target)) return;
28519
- if (isInsideFloatingPanel(target)) return;
28520
- if (target.closest("[data-ohw-form-toolbar]")) return;
28521
- if (target.closest(
28522
- '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
28523
- )) {
28524
- return;
28525
- }
28526
28423
  if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
28527
28424
  clearMediaSelectionRef.current();
28528
28425
  }
@@ -28546,6 +28443,13 @@ function OhhwellsBridge() {
28546
28443
  return;
28547
28444
  }
28548
28445
  }
28446
+ if (isInsideFloatingPanel(target)) return;
28447
+ if (target.closest("[data-ohw-form-toolbar]")) return;
28448
+ if (target.closest(
28449
+ '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
28450
+ )) {
28451
+ return;
28452
+ }
28549
28453
  {
28550
28454
  const formEl = getFormElement(target);
28551
28455
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -28699,13 +28603,9 @@ function OhhwellsBridge() {
28699
28603
  if (isIconEditable(editable) && !getSocialItem(editable)) {
28700
28604
  e.preventDefault();
28701
28605
  e.stopPropagation();
28606
+ selectIconElementRef.current(editable);
28702
28607
  const aiIcon = editable.hasAttribute("data-ai-icon");
28703
28608
  const featureIcon = aiIcon && /\.features\.\d+\.icon$/.test(editable.dataset.ohwKey ?? "");
28704
- if (aiIcon) {
28705
- aiSectionApiRef.current?.selectFromElement(editable);
28706
- } else {
28707
- selectIconElementRef.current(editable);
28708
- }
28709
28609
  postToParentRef.current({
28710
28610
  type: "ow:icon-pick",
28711
28611
  key: editable.dataset.ohwKey ?? "",
@@ -28933,9 +28833,6 @@ function OhhwellsBridge() {
28933
28833
  setHoveredItemRect(null);
28934
28834
  hoveredNavContainerRef.current = null;
28935
28835
  setHoveredNavContainerRect(null);
28936
- siblingHintElRef.current = null;
28937
- setSiblingHintRect(null);
28938
- setSiblingHintRects([]);
28939
28836
  return;
28940
28837
  }
28941
28838
  {
@@ -29056,6 +28953,7 @@ function OhhwellsBridge() {
29056
28953
  hoveredNavContainerRef.current = null;
29057
28954
  setHoveredNavContainerRect(null);
29058
28955
  hoveredItemElRef.current = editable;
28956
+ setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
29059
28957
  }
29060
28958
  }
29061
28959
  }
@@ -29765,11 +29663,7 @@ function OhhwellsBridge() {
29765
29663
  };
29766
29664
  const handleMouseMove = (e) => {
29767
29665
  const { clientX, clientY } = e;
29768
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
29769
- dismissImageHover();
29770
- clearImageHover();
29771
- return;
29772
- }
29666
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
29773
29667
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
29774
29668
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
29775
29669
  formHoverElRef.current = null;
@@ -29798,12 +29692,7 @@ function OhhwellsBridge() {
29798
29692
  setHoveredItemRect(null);
29799
29693
  hoveredNavContainerRef.current = null;
29800
29694
  setHoveredNavContainerRect(null);
29801
- siblingHintElRef.current = null;
29802
- setSiblingHintRect(null);
29803
- setSiblingHintRects([]);
29804
29695
  dismissImageHover();
29805
- clearImageHover();
29806
- setSectionGap(null);
29807
29696
  return;
29808
29697
  }
29809
29698
  if (probeSocialsRowAt(clientX, clientY)) return;
@@ -29815,11 +29704,7 @@ function OhhwellsBridge() {
29815
29704
  if (e.data?.type !== "ow:pointer-sync") return;
29816
29705
  const { clientX, clientY } = e.data;
29817
29706
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
29818
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
29819
- dismissImageHover();
29820
- clearImageHover();
29821
- return;
29822
- }
29707
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
29823
29708
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
29824
29709
  if (probeSocialsRowAt(clientX, clientY)) return;
29825
29710
  probeSectionGapAt(clientX, clientY);
@@ -30199,7 +30084,6 @@ function OhhwellsBridge() {
30199
30084
  applyAiFooterFromContent(content);
30200
30085
  if (typeof content[STYLE_STORE_KEY] === "string") {
30201
30086
  stylesRef.current = content[STYLE_STORE_KEY];
30202
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
30203
30087
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
30204
30088
  }
30205
30089
  applyBrandChrome(content);
@@ -30214,12 +30098,12 @@ function OhhwellsBridge() {
30214
30098
  }
30215
30099
  if (key === AI_SECTIONS_KEY) continue;
30216
30100
  if (key === AI_FOOTER_KEY) continue;
30217
- if (key === LOGO_PLACEHOLDER_KEY) continue;
30218
- if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
30219
30101
  if (key === BRAND_KIT_KEY) continue;
30220
30102
  if (key === STYLE_STORE_KEY) continue;
30221
30103
  if (BRAND_CHROME_KEYS.has(key)) continue;
30104
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
30222
30105
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
30106
+ if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
30223
30107
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
30224
30108
  continue;
30225
30109
  }
@@ -30855,24 +30739,12 @@ function OhhwellsBridge() {
30855
30739
  closeLinkPopoverRef.current();
30856
30740
  return;
30857
30741
  }
30858
- if (floatingPanelOpenRef.current) {
30859
- setFloatingPanelRef.current(null);
30860
- deselectRef.current();
30861
- deactivateRef.current();
30862
- return;
30863
- }
30864
30742
  deselectRef.current();
30865
30743
  deactivateRef.current();
30866
30744
  clearMediaSelectionRef.current();
30867
30745
  clearIconSelectionRef.current();
30868
30746
  };
30869
30747
  window.addEventListener("message", handleDeactivate);
30870
- const handleSelectNav = (e) => {
30871
- if (e.data?.type !== "ow:select-nav") return;
30872
- const navContainer = findSelectableNavContainer();
30873
- if (navContainer) selectFrameRef.current(navContainer);
30874
- };
30875
- window.addEventListener("message", handleSelectNav);
30876
30748
  const handleToastAction = (e) => {
30877
30749
  if (e.data?.type !== "ow:toast-action") return;
30878
30750
  const actionId = typeof e.data.actionId === "string" ? e.data.actionId : null;
@@ -31689,11 +31561,10 @@ function OhhwellsBridge() {
31689
31561
  window.removeEventListener("message", handleDeleteSection);
31690
31562
  window.removeEventListener("message", handleDuplicateSection);
31691
31563
  window.removeEventListener("message", handleDeactivate);
31692
- window.removeEventListener("message", handleSelectNav);
31564
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
31693
31565
  window.removeEventListener("message", handleToastAction);
31694
31566
  window.removeEventListener("message", handleFormCount);
31695
31567
  window.removeEventListener("message", handleUiEscape);
31696
- document.documentElement.removeAttribute("data-ohw-panel-dragging");
31697
31568
  autoSaveTimers.current.forEach(clearTimeout);
31698
31569
  autoSaveTimers.current.clear();
31699
31570
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
@@ -31987,7 +31858,7 @@ function OhhwellsBridge() {
31987
31858
  postToParent2({
31988
31859
  type: "ow:ready",
31989
31860
  version: "1",
31990
- bridgeVersion: "0.1.152-next.410",
31861
+ bridgeVersion: "0.1.153",
31991
31862
  path: pathname,
31992
31863
  nodes: collectEditableNodes(editContentRef.current),
31993
31864
  sections
@@ -32722,7 +32593,7 @@ function OhhwellsBridge() {
32722
32593
  className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
32723
32594
  onClick: () => setFieldTypePickerOpen((open) => !open),
32724
32595
  "data-ohw-add-field": "",
32725
- children: /* @__PURE__ */ jsx40(Plus6, { size: 15, "aria-hidden": true })
32596
+ children: /* @__PURE__ */ jsx40(Plus5, { size: 15, "aria-hidden": true })
32726
32597
  }
32727
32598
  ),
32728
32599
  /* @__PURE__ */ jsx40("div", { className: "mx-0.5 h-5 w-px bg-border" }),