@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.cjs CHANGED
@@ -6652,21 +6652,6 @@ function pricingCardFeatureCount(tree, index) {
6652
6652
  const target = findPricingCollection(tree)?.children?.[index];
6653
6653
  return target ? pricingFeatureList(target).length : 0;
6654
6654
  }
6655
- function prevailingFeatureIcon(features) {
6656
- const counts = /* @__PURE__ */ new Map();
6657
- for (const row of features) {
6658
- const key = `${row.icon ?? ""}|${row.iconColor ?? ""}`;
6659
- const entry = counts.get(key) ?? { count: 0, ...row.icon ? { icon: row.icon } : {}, ...row.iconColor ? { iconColor: row.iconColor } : {} };
6660
- entry.count += 1;
6661
- counts.set(key, entry);
6662
- }
6663
- let best = null;
6664
- for (const entry of counts.values()) {
6665
- if (!best || entry.count > best.count) best = entry;
6666
- }
6667
- if (!best) return {};
6668
- return { ...best.icon ? { icon: best.icon } : {}, ...best.iconColor ? { iconColor: best.iconColor } : {} };
6669
- }
6670
6655
  function addPricingCardFeature(tree, index, text) {
6671
6656
  return withPricingCollection(tree, (collection) => {
6672
6657
  const children = collection.children;
@@ -6675,7 +6660,7 @@ function addPricingCardFeature(tree, index, text) {
6675
6660
  const features = pricingFeatureList(target);
6676
6661
  if (features.length >= PRICING_FEATURES_MAX) return false;
6677
6662
  target.slots = target.slots ?? {};
6678
- target.slots.features = [...features, { text, ...prevailingFeatureIcon(features) }];
6663
+ target.slots.features = [...features, { text }];
6679
6664
  return true;
6680
6665
  });
6681
6666
  }
@@ -7286,21 +7271,6 @@ function applyCustomCodeToHead(content) {
7286
7271
  if (beforeNodes.length > 0) document.head.append(...beforeNodes);
7287
7272
  }
7288
7273
 
7289
- // src/lib/selectNavContainer.ts
7290
- function isOnScreen(el) {
7291
- const rect = el.getBoundingClientRect();
7292
- if (rect.width <= 0 || rect.height <= 0) return false;
7293
- if (el.offsetParent !== null) return true;
7294
- return getComputedStyle(el).position === "fixed";
7295
- }
7296
- function findSelectableNavContainer(doc = document) {
7297
- const visible = Array.from(doc.querySelectorAll("[data-ohw-nav-container]")).filter(isOnScreen);
7298
- if (visible.length === 0) return null;
7299
- return visible.reduce(
7300
- (best, el) => el.getBoundingClientRect().top < best.getBoundingClientRect().top ? el : best
7301
- );
7302
- }
7303
-
7304
7274
  // src/ui/ai-tree/aiSectionsManager.tsx
7305
7275
  var import_react_dom = require("react-dom");
7306
7276
  var import_client = require("react-dom/client");
@@ -7874,7 +7844,7 @@ var AI_MOBILE_CSS = [
7874
7844
  // page's first section. Top only (bottom needs no nav clearance); ~96px approximates the
7875
7845
  // template nav's own height (measured ~94px) — there's no shared `--ohw-header-h` var to read
7876
7846
  // an exact figure from (no live measurement exists), so this is a safe approximation, not a
7877
- // pixel-exact fit. Horizontal spacing already comes from `data-ai-section-inner`.
7847
+ // pixel-exact fit. Horizontal spacing already comes from `data-ai-container`.
7878
7848
  '[data-ai-overlay-clearance] [data-ai-overlap-layer="overlay"]{padding-top:96px}',
7879
7849
  // A full-bleed carousel's height is pure arithmetic: it spans the whole window, so 16/9 turns
7880
7850
  // window width straight into height. Measured at 16/9 it came out ~90% of the viewport at EVERY
@@ -7890,10 +7860,8 @@ var AI_MOBILE_CSS = [
7890
7860
  "[data-ai-section]{overflow-x:hidden}",
7891
7861
  // `:not([data-ai-full-bleed])`: this `!important` gutter beat the inline `padding: 0` that a
7892
7862
  // full-bleed section's container sets, so a carousel/media hero that is edge-to-edge on desktop
7893
- // still got a 20px band of section background down both sides on a phone. The footer's own
7894
- // container keeps the unguarded rule below — `data-ai-full-bleed` can never appear on it.
7895
- "[data-ai-section-inner]:not([data-ai-full-bleed]){padding:0 20px !important}",
7896
- "[data-ai-container]{padding:0 20px !important}",
7863
+ // still got a 20px band of section background down both sides on a phone.
7864
+ "[data-ai-container]:not([data-ai-full-bleed]){padding:0 20px !important}",
7897
7865
  "[data-ai-row]{display:flex !important;flex-direction:column !important;align-items:stretch !important}",
7898
7866
  "[data-ai-cell]{width:100%;min-width:0}",
7899
7867
  // The rule above turns every row into a COLUMN flex container on phones, which silently breaks
@@ -8098,31 +8066,6 @@ function pricingCardEmphasis(featured, ctx, hasBg) {
8098
8066
  function textAttrs(ctx, path) {
8099
8067
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
8100
8068
  }
8101
- var AI_RESPONSIVE_CSS = [
8102
- "@media (max-width: 960px) {",
8103
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
8104
- ' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
8105
- "}",
8106
- "@media (max-width: 640px) {",
8107
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
8108
- " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
8109
- // Group containers flatten to a column on phones; span placements come along for free.
8110
- // `:not([data-ai-group="overlap"])` for the same reason as the twin pair in AI_MOBILE_CSS — see
8111
- // the comment there. This sheet's copy is the narrower selector, so without the exemption it
8112
- // flattens an `overlap` hero below 640px even though the other rule stands down: measured a 390px
8113
- // viewport with the heading/CTA in flow *under* the image, 219px of section background where the
8114
- // layered text used to be.
8115
- ' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) { display: flex !important; flex-direction: column !important; }',
8116
- ' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) > * { grid-column: auto !important; }',
8117
- // `:not([data-ai-full-bleed])` for the same reason as the twin rule in AI_MOBILE_CSS: this one
8118
- // is narrower (0,2,0 vs 0,1,0) and also `!important`, so without the guard it wins outright and
8119
- // a full-bleed hero gets its 20px side band back below 640px only — the one width where the
8120
- // other rule had already been taught to stand down.
8121
- " [data-ai-responsive] [data-ai-section-inner]:not([data-ai-full-bleed]) { padding-left: 20px !important; padding-right: 20px !important; }",
8122
- " [data-ai-responsive] { overflow-x: hidden; }",
8123
- " [data-ai-responsive] img { max-width: 100%; }",
8124
- "}"
8125
- ].join("\n");
8126
8069
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
8127
8070
  function MediaBox({
8128
8071
  refValue,
@@ -8177,7 +8120,7 @@ function MediaBox({
8177
8120
  position: fill ? "absolute" : void 0,
8178
8121
  inset: fill ? 0 : void 0,
8179
8122
  width: fill ? "100%" : fixedSize ? "auto" : "100%",
8180
- height: fill ? "100%" : fixedSize ? height : void 0,
8123
+ height: fill ? "100%" : void 0,
8181
8124
  aspectRatio: fill ? void 0 : aspectRatio,
8182
8125
  minHeight: fill || fixedSize ? void 0 : height ?? (aspectRatio ? void 0 : 180),
8183
8126
  borderRadius: radius,
@@ -9673,7 +9616,7 @@ function CollectionBlock({ node, ctx, path }) {
9673
9616
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
9674
9617
  "div",
9675
9618
  {
9676
- "data-ai-grid": String(itemsPerRow),
9619
+ "data-ai-grid": "",
9677
9620
  "data-ohw-pricing-collection": isPricing ? "" : void 0,
9678
9621
  style: {
9679
9622
  display: "grid",
@@ -9975,7 +9918,7 @@ function renderNode(node, ctx, path, ambientAlign) {
9975
9918
  },
9976
9919
  children: [
9977
9920
  i > 0 && ctx.heroOverlapFullBleed ? (
9978
- // The section's `data-ai-section-inner` gave up its max-width/gutter so the base
9921
+ // The section's `data-ai-container` gave up its max-width/gutter so the base
9979
9922
  // layer (this group's i===0 sibling) can span edge-to-edge — reintroduced here,
9980
9923
  // scoped to just the overlay text, so a heading/copy/CTA stack doesn't stretch
9981
9924
  // the full section width instead of reading at the usual content width.
@@ -10394,7 +10337,6 @@ function AiTreeRenderer({
10394
10337
  ...fillHeight ? { "data-ai-fill-height": "" } : {},
10395
10338
  ...needsOverlayClearance ? { "data-ai-overlay-clearance": "" } : {},
10396
10339
  ...bgAttrs,
10397
- "data-ai-responsive": "",
10398
10340
  style: {
10399
10341
  position: "relative",
10400
10342
  padding: `${padCss} 0`,
@@ -10408,13 +10350,12 @@ function AiTreeRenderer({
10408
10350
  ...fillHeight ? { display: "grid" } : {}
10409
10351
  },
10410
10352
  children: [
10411
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
10412
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
10413
10353
  isOverlay && backgroundUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
10354
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
10414
10355
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
10415
10356
  "div",
10416
10357
  {
10417
- "data-ai-section-inner": "",
10358
+ "data-ai-container": "",
10418
10359
  ...fullBleedMedia ? { "data-ai-full-bleed": "" } : {},
10419
10360
  style: {
10420
10361
  position: "relative",
@@ -10431,7 +10372,7 @@ function AiTreeRenderer({
10431
10372
  children: tree.rows.map((row, r2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
10432
10373
  "div",
10433
10374
  {
10434
- "data-ai-columns": "",
10375
+ "data-ai-row": "",
10435
10376
  style: {
10436
10377
  display: "grid",
10437
10378
  gridTemplateColumns: "repeat(12, 1fr)",
@@ -11093,10 +11034,9 @@ function applyAiSectionsToDom(state, options) {
11093
11034
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
11094
11035
  continue;
11095
11036
  }
11037
+ const isNewMount = !existing || !existing.container.isConnected;
11096
11038
  let container = existing?.container;
11097
- let isNewMount = false;
11098
11039
  if (!container || !container.isConnected) {
11099
- isNewMount = true;
11100
11040
  existing?.root.unmount();
11101
11041
  container?.remove();
11102
11042
  container = document.createElement("div");
@@ -17089,7 +17029,7 @@ function apiBase() {
17089
17029
  function bridgeVersion() {
17090
17030
  try {
17091
17031
  if (true) {
17092
- return "0.1.152-next.410";
17032
+ return "0.1.153";
17093
17033
  }
17094
17034
  } catch {
17095
17035
  }
@@ -17103,7 +17043,7 @@ function stampBridgeVersionOnDocument() {
17103
17043
  return;
17104
17044
  }
17105
17045
  try {
17106
- const v = true ? "0.1.152-next.410" : "";
17046
+ const v = true ? "0.1.153" : "";
17107
17047
  if (v) {
17108
17048
  document.documentElement.setAttribute("data-ohw-bridge-version", v);
17109
17049
  window.__OHW_BRIDGE_VERSION__ = v;
@@ -17768,7 +17708,6 @@ function MediaOverlay({
17768
17708
  (prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
17769
17709
  );
17770
17710
  }, [isVideo]);
17771
- const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
17772
17711
  const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
17773
17712
  const box = {
17774
17713
  position: "fixed",
@@ -17867,10 +17806,11 @@ function MediaOverlay({
17867
17806
  className: "flex items-center justify-center cursor-pointer",
17868
17807
  style: {
17869
17808
  ...box,
17870
- // Visual only. `pointer-events: auto` on this full-bleed rect covered the navbar
17871
- // (hero bg includes the absolute TopNav) and swallowed CTA press-drag. Text overlay
17872
- // and cueOnly also need clicks to fall through — Replace / video controls opt back in.
17873
- pointerEvents: "none",
17809
+ // When text overlays this media, let clicks fall THROUGH to the text underneath. In the
17810
+ // parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
17811
+ // in-document, pointer-events does it natively. The button below opts back in, so
17812
+ // Replace still works.
17813
+ pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
17874
17814
  // Selected: a firm component ring with no wash, so the image reads as chosen rather
17875
17815
  // than hovered. Hover keeps the existing tinted preview.
17876
17816
  boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
@@ -17897,17 +17837,17 @@ function MediaOverlay({
17897
17837
  },
17898
17838
  children: [
17899
17839
  isVideo ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
17900
- replaceLabel
17840
+ isVideo ? "Replace video" : "Replace image"
17901
17841
  ]
17902
17842
  }
17903
17843
  ),
17904
- showChrome && replaceMode !== "none" && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
17844
+ replaceMode === "none" || cueOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
17905
17845
  Button,
17906
17846
  {
17907
17847
  "data-ohw-media-overlay": "",
17908
17848
  variant: "outline",
17909
17849
  size: "sm",
17910
- "aria-label": replaceLabel,
17850
+ "aria-label": isVideo ? "Replace video" : "Replace image",
17911
17851
  className: "gap-1.5 cursor-pointer hover:bg-background",
17912
17852
  style: {
17913
17853
  ...OVERLAY_BUTTON_STYLE,
@@ -17930,7 +17870,7 @@ function MediaOverlay({
17930
17870
  },
17931
17871
  children: [
17932
17872
  isVideo ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
17933
- replaceMode === "full" ? replaceLabel : null
17873
+ replaceMode === "full" ? isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image" : null
17934
17874
  ]
17935
17875
  }
17936
17876
  )
@@ -18440,7 +18380,7 @@ function AiSectionOverlay({
18440
18380
 
18441
18381
  // src/ui/ai-section/AiMediaStripOverlay.tsx
18442
18382
  var import_react10 = require("react");
18443
- var import_lucide_react9 = require("lucide-react");
18383
+ var import_lucide_react8 = require("lucide-react");
18444
18384
 
18445
18385
  // src/lib/ai-media-strip-tree.ts
18446
18386
  var MEDIA_STRIP_ITEM_MIN = 1;
@@ -18554,6 +18494,14 @@ function setMediaStripItemAsset(tree, index, assetId) {
18554
18494
  return true;
18555
18495
  });
18556
18496
  }
18497
+ function setMediaStripItemAlt(tree, index, alt) {
18498
+ return withMediaStrip(tree, (block) => {
18499
+ const items = block.items;
18500
+ if (index < 0 || index >= items.length) return false;
18501
+ items[index] = { ...items[index], alt };
18502
+ return true;
18503
+ });
18504
+ }
18557
18505
  function setMediaStripItemLink(tree, index, link) {
18558
18506
  return withMediaStrip(tree, (block) => {
18559
18507
  const items = block.items;
@@ -18571,117 +18519,11 @@ function setMediaStripItemLink(tree, index, link) {
18571
18519
  });
18572
18520
  }
18573
18521
 
18574
- // src/ui/dialog.tsx
18575
- var React9 = __toESM(require("react"), 1);
18576
- var import_radix_ui6 = require("radix-ui");
18577
- var import_lucide_react8 = require("lucide-react");
18578
- var import_jsx_runtime20 = require("react/jsx-runtime");
18579
- function Dialog2({
18580
- ...props
18581
- }) {
18582
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
18583
- }
18584
- function DialogPortal({
18585
- ...props
18586
- }) {
18587
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
18588
- }
18589
- function DialogOverlay({
18590
- className,
18591
- ...props
18592
- }) {
18593
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18594
- import_radix_ui6.Dialog.Overlay,
18595
- {
18596
- "data-slot": "dialog-overlay",
18597
- "data-ohw-link-modal-root": "",
18598
- className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
18599
- ...props
18600
- }
18601
- );
18602
- }
18603
- var DialogContent = React9.forwardRef(
18604
- ({ className, children, showCloseButton = true, container, ...props }, ref) => {
18605
- const positionMode = container ? "absolute" : "fixed";
18606
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DialogPortal, { container: container ?? void 0, children: [
18607
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
18608
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
18609
- import_radix_ui6.Dialog.Content,
18610
- {
18611
- ref,
18612
- "data-slot": "dialog-content",
18613
- className: cn(
18614
- positionMode,
18615
- "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",
18616
- "rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
18617
- container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
18618
- className
18619
- ),
18620
- onMouseDown: (e) => e.stopPropagation(),
18621
- ...props,
18622
- children: [
18623
- children,
18624
- showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18625
- import_radix_ui6.Dialog.Close,
18626
- {
18627
- type: "button",
18628
- className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
18629
- "aria-label": "Close",
18630
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react8.X, { size: 16, "aria-hidden": true })
18631
- }
18632
- ) : null
18633
- ]
18634
- }
18635
- )
18636
- ] });
18637
- }
18638
- );
18639
- DialogContent.displayName = import_radix_ui6.Dialog.Content.displayName;
18640
- function DialogHeader({
18641
- className,
18642
- ...props
18643
- }) {
18644
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
18645
- }
18646
- function DialogFooter({
18647
- className,
18648
- ...props
18649
- }) {
18650
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18651
- "div",
18652
- {
18653
- className: cn("flex items-center justify-end gap-2", className),
18654
- ...props
18655
- }
18656
- );
18657
- }
18658
- var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18659
- import_radix_ui6.Dialog.Title,
18660
- {
18661
- ref,
18662
- className: cn(
18663
- "text-lg font-semibold leading-none tracking-tight text-card-foreground",
18664
- className
18665
- ),
18666
- ...props
18667
- }
18668
- ));
18669
- DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
18670
- var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18671
- import_radix_ui6.Dialog.Description,
18672
- {
18673
- ref,
18674
- className: cn("text-sm text-muted-foreground", className),
18675
- ...props
18676
- }
18677
- ));
18678
- DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
18679
- var DialogClose = import_radix_ui6.Dialog.Close;
18680
-
18681
18522
  // src/ui/ai-section/AiMediaStripOverlay.tsx
18682
- var import_jsx_runtime21 = require("react/jsx-runtime");
18683
- var PRIMARY3 = "var(--ohw-primary, #0885FE)";
18684
- 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]";
18523
+ var import_jsx_runtime20 = require("react/jsx-runtime");
18524
+ var PRIMARY3 = "#0885FE";
18525
+ var OHW_BLUE = `var(--ohw-primary, ${PRIMARY3})`;
18526
+ var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY3}) 60%, #000000)`;
18685
18527
  function findMediaStripItemElement(sectionId, index) {
18686
18528
  const sectionEl = findByInstanceId(sectionId);
18687
18529
  if (!sectionEl) return null;
@@ -18691,35 +18533,14 @@ function findMediaStripItemElement(sectionId, index) {
18691
18533
  }
18692
18534
  return null;
18693
18535
  }
18694
- function itemRefFromTarget(target) {
18695
- if (!(target instanceof Element)) return null;
18696
- if (target.closest(CHROME_SELECTOR)) return null;
18697
- const itemEl = target.closest("[data-ohw-media-strip-item]");
18698
- if (!itemEl) return null;
18699
- const sectionEl = itemEl.closest("[data-ohw-section]");
18700
- const unit = sectionEl ? movableUnit(sectionEl) : null;
18701
- const sectionId = unit ? instanceIdOf(unit) || null : null;
18702
- const index = Number(itemEl.dataset.ohwMediaStripIndex);
18703
- if (!sectionId || Number.isNaN(index)) return null;
18704
- return { sectionId, index };
18705
- }
18706
- function sameRef(a, b) {
18707
- return a?.sectionId === b?.sectionId && a?.index === b?.index;
18708
- }
18709
- function rectOf(el) {
18536
+ function readRect2(ref) {
18537
+ const el = ref && findMediaStripItemElement(ref.sectionId, ref.index);
18710
18538
  if (!el) return null;
18711
18539
  const r2 = el.getBoundingClientRect();
18712
18540
  if (r2.width <= 0 || r2.height <= 0) return null;
18713
18541
  return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
18714
18542
  }
18715
- function readRect2(ref) {
18716
- return rectOf(ref && findMediaStripItemElement(ref.sectionId, ref.index));
18717
- }
18718
- function readStripRect(ref) {
18719
- const item = ref && findMediaStripItemElement(ref.sectionId, ref.index);
18720
- return rectOf(item?.closest("[data-ohw-media-strip]") ?? item);
18721
- }
18722
- function useLiveItemRect(ref, strip = false) {
18543
+ function useLiveItemRect(ref) {
18723
18544
  const [rect, setRect] = (0, import_react10.useState)(null);
18724
18545
  (0, import_react10.useEffect)(() => {
18725
18546
  if (!ref) {
@@ -18727,7 +18548,7 @@ function useLiveItemRect(ref, strip = false) {
18727
18548
  return;
18728
18549
  }
18729
18550
  const update = () => {
18730
- const next = strip ? readStripRect(ref) : readRect2(ref);
18551
+ const next = readRect2(ref);
18731
18552
  setRect(
18732
18553
  (prev) => prev && next && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
18733
18554
  );
@@ -18742,49 +18563,9 @@ function useLiveItemRect(ref, strip = false) {
18742
18563
  window.removeEventListener("resize", update);
18743
18564
  clearInterval(interval);
18744
18565
  };
18745
- }, [ref?.sectionId, ref?.index, strip]);
18566
+ }, [ref?.sectionId, ref?.index]);
18746
18567
  return rect;
18747
18568
  }
18748
- var TOOLBAR_STRIP_GAP = 52;
18749
- var TOOLBAR_STRIP_GAP_MOBILE = 42;
18750
- var TOOLBAR_EDGE_MARGIN2 = 4;
18751
- function StripToolbarSlot({ stripRect, children }) {
18752
- const slotRef = (0, import_react10.useRef)(null);
18753
- const [shift, setShift] = (0, import_react10.useState)(0);
18754
- const centerX = stripRect.left + stripRect.width / 2;
18755
- (0, import_react10.useLayoutEffect)(() => {
18756
- const slot = slotRef.current;
18757
- if (!slot) return;
18758
- const clamp = () => {
18759
- const w = slot.offsetWidth;
18760
- if (w <= 0) return;
18761
- const half = w / 2;
18762
- const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
18763
- setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
18764
- };
18765
- clamp();
18766
- const ro = new ResizeObserver(clamp);
18767
- ro.observe(slot);
18768
- return () => ro.disconnect();
18769
- }, [centerX, children]);
18770
- const mobile = window.innerWidth <= 480;
18771
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
18772
- "div",
18773
- {
18774
- ref: slotRef,
18775
- "data-ohw-bridge": "",
18776
- "data-ohw-item-interaction": "",
18777
- className: "pointer-events-auto fixed",
18778
- style: {
18779
- top: stripRect.top - (mobile ? TOOLBAR_STRIP_GAP_MOBILE : TOOLBAR_STRIP_GAP),
18780
- left: centerX + shift,
18781
- transform: "translate(-50%, -100%)",
18782
- zIndex: 2147483645
18783
- },
18784
- children
18785
- }
18786
- );
18787
- }
18788
18569
  function requestValidateTree(postToParent2, tree) {
18789
18570
  return new Promise((resolve) => {
18790
18571
  const id = `ai-validate-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
@@ -18821,177 +18602,221 @@ function requestAssetPick(postToParent2) {
18821
18602
  postToParent2({ type: "ow:asset-pick", id });
18822
18603
  });
18823
18604
  }
18824
- function ToolbarAction({
18605
+ function Pill({
18825
18606
  label,
18826
18607
  onClick,
18827
- disabled = false,
18828
- active = false,
18829
- children
18608
+ disabled,
18609
+ active
18830
18610
  }) {
18831
- const button = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, active, onClick, className: "size-8", children });
18832
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
18833
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "inline-flex", children: button }) : button }),
18834
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
18835
- ] });
18836
- }
18837
- function ToolbarSeparator() {
18838
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
18611
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18612
+ "button",
18613
+ {
18614
+ type: "button",
18615
+ onClick,
18616
+ disabled,
18617
+ style: {
18618
+ height: 28,
18619
+ padding: "0 10px",
18620
+ display: "inline-flex",
18621
+ alignItems: "center",
18622
+ gap: 4,
18623
+ borderRadius: 999,
18624
+ border: "none",
18625
+ cursor: disabled ? "default" : "pointer",
18626
+ background: active ? OHW_BLUE_DARK : "#ffffff",
18627
+ color: active ? "#ffffff" : OHW_BLUE_DARK,
18628
+ opacity: disabled ? 0.4 : 1,
18629
+ fontSize: 12,
18630
+ lineHeight: "16px",
18631
+ fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
18632
+ whiteSpace: "nowrap",
18633
+ flex: "0 0 auto"
18634
+ },
18635
+ children: label
18636
+ }
18637
+ );
18839
18638
  }
18840
- function OptionMenu({
18841
- label,
18842
- value,
18843
- options,
18844
- onChange
18845
- }) {
18846
- const current = options.find((o) => o.value === value) ?? options[0];
18847
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
18848
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-xs text-muted-foreground", children: label }),
18849
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DropdownMenu, { modal: false, children: [
18850
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
18851
- "button",
18852
- {
18853
- type: "button",
18854
- "aria-label": label,
18855
- 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",
18856
- children: [
18857
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "flex-1 text-left", children: current.label }),
18858
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ChevronDown, { size: 16, style: { pointerEvents: "none" } })
18859
- ]
18860
- }
18861
- ) }),
18862
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[132px] min-w-[132px] p-1", children: options.map((option) => {
18863
- const selected = option.value === value;
18864
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
18865
- DropdownMenuItem,
18639
+ function AltInput({ value, onCommit }) {
18640
+ const [draft, setDraft] = (0, import_react10.useState)(value);
18641
+ (0, import_react10.useEffect)(() => setDraft(value), [value]);
18642
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
18643
+ "div",
18644
+ {
18645
+ style: {
18646
+ display: "flex",
18647
+ alignItems: "center",
18648
+ gap: 6,
18649
+ height: 28,
18650
+ padding: "0 12px",
18651
+ borderRadius: 999,
18652
+ background: "#ffffff",
18653
+ width: "100%",
18654
+ maxWidth: 260,
18655
+ boxSizing: "border-box"
18656
+ },
18657
+ children: [
18658
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18659
+ "span",
18866
18660
  {
18867
- role: "menuitemradio",
18868
- "aria-checked": selected,
18869
- onSelect: () => onChange(option.value),
18870
- className: cn("grid grid-cols-[1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
18871
- children: [
18872
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: option.label }),
18873
- selected && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Check, { size: 16, className: "text-bridge-primary" })
18874
- ]
18875
- },
18876
- option.value
18877
- );
18878
- }) })
18879
- ] })
18880
- ] });
18881
- }
18882
- var VARIANTS = [
18883
- { value: "logos", label: "Logos" },
18884
- { value: "reel", label: "Reel" }
18885
- ];
18886
- var ALIGNS = [
18887
- { value: "left", label: "Align left", Icon: import_lucide_react9.AlignLeft },
18888
- { value: "center", label: "Align center", Icon: import_lucide_react9.AlignCenter },
18889
- { value: "right", label: "Align right", Icon: import_lucide_react9.AlignRight }
18890
- ];
18891
- var HOVERS = [
18892
- { value: "none", label: "None" },
18893
- { value: "lift", label: "Lift" },
18661
+ style: {
18662
+ flex: "0 0 auto",
18663
+ color: OHW_BLUE_DARK,
18664
+ fontSize: 10,
18665
+ fontWeight: 700,
18666
+ textTransform: "uppercase",
18667
+ letterSpacing: 0.4
18668
+ },
18669
+ children: "Alt"
18670
+ }
18671
+ ),
18672
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18673
+ "input",
18674
+ {
18675
+ type: "text",
18676
+ value: draft,
18677
+ onChange: (e) => setDraft(e.target.value),
18678
+ onBlur: () => {
18679
+ if (draft !== value) onCommit(draft);
18680
+ },
18681
+ onKeyDown: (e) => {
18682
+ if (e.key === "Enter") e.currentTarget.blur();
18683
+ if (e.key === "Escape") {
18684
+ setDraft(value);
18685
+ e.currentTarget.blur();
18686
+ }
18687
+ },
18688
+ placeholder: "Describe this image",
18689
+ "aria-label": "Image alt text",
18690
+ style: {
18691
+ flex: 1,
18692
+ minWidth: 0,
18693
+ border: "none",
18694
+ outline: "none",
18695
+ background: "transparent",
18696
+ fontSize: 12,
18697
+ lineHeight: "16px",
18698
+ fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
18699
+ color: "#1f2937"
18700
+ }
18701
+ }
18702
+ )
18703
+ ]
18704
+ }
18705
+ );
18706
+ }
18707
+ var VARIANTS = [
18708
+ { value: "logos", label: "Logos" },
18709
+ { value: "reel", label: "Reel" }
18710
+ ];
18711
+ var ALIGNS = [
18712
+ { value: "left", label: "Left" },
18713
+ { value: "center", label: "Center" },
18714
+ { value: "right", label: "Right" }
18715
+ ];
18716
+ var HOVERS = [
18717
+ { value: "none", label: "None" },
18718
+ { value: "lift", label: "Lift" },
18894
18719
  { value: "zoom", label: "Zoom" },
18895
18720
  { value: "fade", label: "Fade" }
18896
18721
  ];
18722
+ var TREATMENTS = [
18723
+ { value: "color", label: "Color" },
18724
+ { value: "grayscale", label: "Grayscale" }
18725
+ ];
18897
18726
  var HTTP_URL_RE = /^https?:\/\/\S+$/i;
18898
- function LinkModal({
18899
- href,
18900
- linkTarget,
18901
- onClose,
18902
- onSave
18903
- }) {
18904
- const [draft, setDraft] = (0, import_react10.useState)(href);
18905
- const [newTab, setNewTab] = (0, import_react10.useState)(linkTarget !== "same-tab");
18727
+ function LinkInput({ value, onCommit }) {
18728
+ const [draft, setDraft] = (0, import_react10.useState)(value);
18906
18729
  const [invalid, setInvalid] = (0, import_react10.useState)(false);
18907
- const save = () => {
18730
+ (0, import_react10.useEffect)(() => {
18731
+ setDraft(value);
18732
+ setInvalid(false);
18733
+ }, [value]);
18734
+ const commit = () => {
18908
18735
  const next = draft.trim();
18909
- if (next && !HTTP_URL_RE.test(next)) {
18910
- setInvalid(true);
18911
- return;
18912
- }
18913
- onSave(next, newTab ? "new-tab" : "same-tab");
18914
- onClose();
18736
+ if (next === value) return setInvalid(false);
18737
+ if (next && !HTTP_URL_RE.test(next)) return setInvalid(true);
18738
+ setInvalid(false);
18739
+ onCommit(next);
18915
18740
  };
18916
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Dialog2, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DialogContent, { "data-ohw-link-modal-root": "", className: "max-w-[400px] gap-4 p-5", children: [
18917
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DialogTitle, { className: "text-base", children: "Image link" }) }),
18918
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-3", children: [
18919
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
18920
- "input",
18921
- {
18922
- autoFocus: true,
18923
- type: "text",
18924
- inputMode: "url",
18925
- value: draft,
18926
- onChange: (e) => {
18927
- setDraft(e.target.value);
18928
- setInvalid(false);
18929
- },
18930
- onKeyDown: (e) => {
18931
- if (e.key === "Enter") save();
18932
- },
18933
- placeholder: "https://example.com",
18934
- "aria-label": "Image link URL",
18935
- "aria-invalid": invalid,
18936
- className: cn(
18937
- "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",
18938
- invalid && "border-destructive focus:border-destructive"
18939
- )
18940
- }
18941
- ),
18942
- invalid && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-xs text-destructive", children: "Enter a full URL starting with http:// or https://" }),
18943
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "flex items-center gap-2 text-[13px] text-foreground", children: [
18944
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "checkbox", checked: newTab, onChange: (e) => setNewTab(e.target.checked) }),
18945
- "Open in new tab"
18946
- ] })
18947
- ] }),
18948
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DialogFooter, { children: [
18949
- href && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
18950
- "button",
18951
- {
18952
- type: "button",
18953
- onClick: () => {
18954
- onSave("", "new-tab");
18955
- onClose();
18956
- },
18957
- className: "mr-auto rounded-[6px] px-3 py-2 text-[13px] font-medium text-destructive transition-colors hover:bg-muted",
18958
- children: "Remove link"
18959
- }
18960
- ),
18961
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
18962
- "button",
18963
- {
18964
- type: "button",
18965
- onClick: onClose,
18966
- className: "rounded-[6px] px-3 py-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted",
18967
- children: "Cancel"
18968
- }
18969
- ),
18970
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
18971
- "button",
18972
- {
18973
- type: "button",
18974
- onClick: save,
18975
- className: "rounded-[6px] bg-bridge-primary px-3 py-2 text-[13px] font-medium text-primary-foreground transition-opacity hover:opacity-90",
18976
- children: "Save"
18977
- }
18978
- )
18979
- ] })
18980
- ] }) });
18741
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
18742
+ "div",
18743
+ {
18744
+ style: {
18745
+ display: "flex",
18746
+ alignItems: "center",
18747
+ gap: 6,
18748
+ height: 28,
18749
+ padding: "0 12px",
18750
+ borderRadius: 999,
18751
+ background: "#ffffff",
18752
+ width: "100%",
18753
+ maxWidth: 260,
18754
+ boxSizing: "border-box",
18755
+ boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
18756
+ },
18757
+ children: [
18758
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18759
+ "span",
18760
+ {
18761
+ style: {
18762
+ flex: "0 0 auto",
18763
+ color: OHW_BLUE_DARK,
18764
+ fontSize: 10,
18765
+ fontWeight: 700,
18766
+ textTransform: "uppercase",
18767
+ letterSpacing: 0.4
18768
+ },
18769
+ children: "Link"
18770
+ }
18771
+ ),
18772
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18773
+ "input",
18774
+ {
18775
+ type: "text",
18776
+ inputMode: "url",
18777
+ value: draft,
18778
+ onChange: (e) => setDraft(e.target.value),
18779
+ onBlur: commit,
18780
+ onKeyDown: (e) => {
18781
+ if (e.key === "Enter") e.currentTarget.blur();
18782
+ if (e.key === "Escape") {
18783
+ setDraft(value);
18784
+ setInvalid(false);
18785
+ e.currentTarget.blur();
18786
+ }
18787
+ },
18788
+ placeholder: "https://example.com",
18789
+ "aria-label": "Image link URL",
18790
+ "aria-invalid": invalid,
18791
+ style: {
18792
+ flex: 1,
18793
+ minWidth: 0,
18794
+ border: "none",
18795
+ outline: "none",
18796
+ background: "transparent",
18797
+ fontSize: 12,
18798
+ lineHeight: "16px",
18799
+ fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
18800
+ color: "#1f2937"
18801
+ }
18802
+ }
18803
+ )
18804
+ ]
18805
+ }
18806
+ );
18981
18807
  }
18982
18808
  function MediaStripToolbar({
18983
18809
  entry,
18984
18810
  index,
18985
18811
  pending,
18986
18812
  error,
18987
- itemEditOn,
18988
- onToggleItemEdit,
18989
18813
  onSetVariant,
18990
18814
  onSetAlign,
18991
18815
  onSetHover,
18992
18816
  onSetTreatment,
18993
18817
  onResize,
18994
- onOpenLink,
18818
+ onSetAlt,
18819
+ onSetLink,
18995
18820
  onAddItem,
18996
18821
  onRemoveItem,
18997
18822
  onChangeImage,
@@ -19000,102 +18825,81 @@ function MediaStripToolbar({
19000
18825
  }) {
19001
18826
  const items = mediaStripItems(entry.tree);
19002
18827
  const itemCount = items.length;
18828
+ const currentAlt = items[index]?.alt ?? "";
18829
+ const currentHref = items[index]?.href ?? "";
18830
+ const currentTarget = items[index]?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
19003
18831
  const slots = findMediaStripSlots(entry.tree);
19004
18832
  const variant = slots?.variant === "reel" ? "reel" : "logos";
19005
18833
  const align = slots?.align === "left" || slots?.align === "right" ? slots.align : "center";
19006
18834
  const hover = slots?.hover === "none" || slots?.hover === "lift" || slots?.hover === "zoom" || slots?.hover === "fade" ? slots.hover : "lift";
19007
18835
  const treatment = slots?.treatment === "color" || slots?.treatment === "grayscale" ? slots.treatment : variant === "logos" ? "grayscale" : "color";
19008
18836
  const sizeValue = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
19009
- const mobile = window.innerWidth <= 480;
19010
- const gatedLabel = (label) => itemEditOn ? label : "Turn on the star to edit this image";
19011
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
18837
+ const isMobile = window.innerWidth <= 480;
18838
+ const rowStyle = isMobile ? {
18839
+ display: "flex",
18840
+ gap: 6,
18841
+ flexWrap: "nowrap",
18842
+ justifyContent: "center",
18843
+ overflowX: "auto",
18844
+ WebkitOverflowScrolling: "touch",
18845
+ width: "100%",
18846
+ scrollbarWidth: "none"
18847
+ } : { display: "flex", gap: 6, flexWrap: "nowrap", justifyContent: "center" };
18848
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
19012
18849
  "div",
19013
18850
  {
19014
18851
  "data-ohw-bridge": "",
19015
18852
  "data-ohw-toolbar": "",
19016
18853
  onMouseDown: (e) => e.stopPropagation(),
19017
- className: cn("flex flex-col items-center gap-1.5 font-sans", pending && "pointer-events-none opacity-60"),
19018
- style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
18854
+ style: {
18855
+ display: "flex",
18856
+ flexDirection: "column",
18857
+ gap: 6,
18858
+ alignItems: "center",
18859
+ background: OHW_BLUE,
18860
+ padding: 8,
18861
+ borderRadius: 12,
18862
+ boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
18863
+ pointerEvents: pending ? "none" : "auto",
18864
+ opacity: pending ? 0.6 : 1,
18865
+ maxWidth: isMobile ? "calc(100vw - 24px)" : "none"
18866
+ },
19019
18867
  children: [
19020
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
19021
- "div",
19022
- {
19023
- className: cn(
19024
- "flex items-center gap-1 rounded-[10px] border border-border bg-background p-1 whitespace-nowrap",
19025
- "shadow-[0px_10px_15px_-3px_rgba(0,0,0,0.1),0px_4px_6px_-4px_rgba(0,0,0,0.1)]",
19026
- mobile ? "flex-wrap justify-center" : "flex-nowrap"
19027
- ),
19028
- children: [
19029
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
19030
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19031
- CustomToolbarButton,
19032
- {
19033
- type: "button",
19034
- "aria-label": itemEditOn ? "Done editing this image" : "Edit this image",
19035
- "aria-pressed": itemEditOn,
19036
- onClick: onToggleItemEdit,
19037
- className: "group size-8",
19038
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19039
- import_lucide_react9.Star,
19040
- {
19041
- size: 16,
19042
- fill: "currentColor",
19043
- strokeWidth: 0,
19044
- className: cn(
19045
- "transition-colors",
19046
- itemEditOn ? "text-[#f59e0b] group-hover:text-[#d97706]" : "text-[#d6d3d1] group-hover:text-[#fbbf24]"
19047
- ),
19048
- style: { pointerEvents: "none" }
19049
- }
19050
- )
19051
- }
19052
- ) }),
19053
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: itemEditOn ? "Done editing this image" : "Edit this image" })
19054
- ] }),
19055
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
19056
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: gatedLabel("Change image"), onClick: onChangeImage, disabled: !itemEditOn, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Image, { size: 16, style: { pointerEvents: "none" } }) }),
19057
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: gatedLabel("Link"), onClick: onOpenLink, disabled: !itemEditOn, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Link, { size: 16, style: { pointerEvents: "none" } }) }),
19058
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: gatedLabel("Move left"), onClick: onMoveLeft, disabled: !itemEditOn || index <= 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ArrowLeft, { size: 16, style: { pointerEvents: "none" } }) }),
19059
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19060
- ToolbarAction,
19061
- {
19062
- label: gatedLabel("Move right"),
19063
- onClick: onMoveRight,
19064
- disabled: !itemEditOn || index >= itemCount - 1,
19065
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ArrowRight, { size: 16, style: { pointerEvents: "none" } })
19066
- }
19067
- ),
19068
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: gatedLabel("Remove image"), onClick: onRemoveItem, disabled: !itemEditOn || itemCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ImageMinus, { size: 16, style: { pointerEvents: "none" } }) }),
19069
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
19070
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(OptionMenu, { label: "Layout", value: variant, options: VARIANTS, onChange: onSetVariant }),
19071
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(OptionMenu, { label: "Hover", value: hover, options: HOVERS, onChange: onSetHover }),
19072
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19073
- ToolbarAction,
19074
- {
19075
- label: treatment === "grayscale" ? "Show in color" : "Show grayscale",
19076
- active: treatment === "grayscale",
19077
- onClick: () => onSetTreatment(treatment === "grayscale" ? "color" : "grayscale"),
19078
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Palette, { size: 16, style: { pointerEvents: "none" } })
19079
- }
19080
- ),
19081
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
19082
- ALIGNS.map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label, active: align === value, onClick: () => onSetAlign(value), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Icon, { size: 16, style: { pointerEvents: "none" } }) }, value)),
19083
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
19084
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Smaller", onClick: () => onResize(-8), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Minus, { size: 16, style: { pointerEvents: "none" } }) }),
19085
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "min-w-[40px] text-center text-xs tabular-nums text-muted-foreground", children: [
19086
- sizeValue,
19087
- "px"
19088
- ] }),
19089
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Larger", onClick: () => onResize(8), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Plus, { size: 16, style: { pointerEvents: "none" } }) }),
19090
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
19091
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Add image", onClick: onAddItem, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ImagePlus, { size: 16, style: { pointerEvents: "none" } }) })
19092
- ]
19093
- }
19094
- ),
19095
- error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
18868
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: rowStyle, children: [
18869
+ VARIANTS.map((v) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: v.label, active: variant === v.value, onClick: () => onSetVariant(v.value) }, v.value)),
18870
+ ALIGNS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: a.label, active: align === a.value, onClick: () => onSetAlign(a.value) }, a.value))
18871
+ ] }),
18872
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: rowStyle, children: [
18873
+ HOVERS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: h.label, active: hover === h.value, onClick: () => onSetHover(h.value) }, h.value)),
18874
+ TREATMENTS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: t.label, active: treatment === t.value, onClick: () => onSetTreatment(t.value) }, t.value))
18875
+ ] }),
18876
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
18877
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "\u2212", onClick: () => onResize(-8) }),
18878
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { style: { color: "#ffffff", fontSize: 12, minWidth: 34, textAlign: "center" }, children: [
18879
+ sizeValue,
18880
+ "px"
18881
+ ] }),
18882
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "+", onClick: () => onResize(8) })
18883
+ ] }),
18884
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(AltInput, { value: currentAlt, onCommit: onSetAlt }) }),
18885
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LinkInput, { value: currentHref, onCommit: (href) => onSetLink(href, currentTarget) }) }),
18886
+ currentHref && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: rowStyle, children: [
18887
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "New tab", active: currentTarget === "new-tab", onClick: () => onSetLink(currentHref, "new-tab") }),
18888
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "Same tab", active: currentTarget === "same-tab", onClick: () => onSetLink(currentHref, "same-tab") })
18889
+ ] }),
18890
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: rowStyle, children: [
18891
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "Change Image", onClick: onChangeImage }),
18892
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "+ Item", onClick: onAddItem }),
18893
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "\u2212 Item", onClick: onRemoveItem, disabled: itemCount <= 1 })
18894
+ ] }),
18895
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: rowStyle, children: [
18896
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "\u2190 Move", onClick: onMoveLeft, disabled: index <= 0 }),
18897
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Pill, { label: "\u2192 Move", onClick: onMoveRight, disabled: index >= itemCount - 1 })
18898
+ ] }),
18899
+ error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
19096
18900
  ]
19097
18901
  }
19098
- ) });
18902
+ );
19099
18903
  }
19100
18904
  function findMediaStripSlots(tree) {
19101
18905
  const stack = tree.rows.flatMap((row) => row.blocks);
@@ -19114,23 +18918,31 @@ function AiMediaStripOverlay({
19114
18918
  }) {
19115
18919
  const [hover, setHover] = (0, import_react10.useState)(null);
19116
18920
  const [active, setActive] = (0, import_react10.useState)(null);
19117
- const [itemEditOn, setItemEditOn] = (0, import_react10.useState)(false);
19118
- const [linkOpen, setLinkOpen] = (0, import_react10.useState)(false);
19119
18921
  const [pending, setPending] = (0, import_react10.useState)(false);
19120
18922
  const [error, setError] = (0, import_react10.useState)(null);
19121
18923
  const activeRef = (0, import_react10.useRef)(null);
19122
18924
  activeRef.current = active;
19123
- const linkOpenRef = (0, import_react10.useRef)(false);
19124
- linkOpenRef.current = linkOpen;
19125
18925
  (0, import_react10.useEffect)(() => {
19126
18926
  const onMove = (e) => {
19127
- const ref = itemRefFromTarget(e.target);
19128
18927
  const t = e.target;
19129
- const overEditable = Boolean(t?.closest?.("[data-ohw-editable]"));
19130
- setHover((prev) => {
19131
- const next = ref && !overEditable ? ref : null;
19132
- return sameRef(prev, next) ? prev : next;
19133
- });
18928
+ if (!(t instanceof HTMLElement)) return;
18929
+ 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]")) {
18930
+ return;
18931
+ }
18932
+ const itemEl = t.closest("[data-ohw-media-strip-item]");
18933
+ if (!itemEl) {
18934
+ setHover(null);
18935
+ return;
18936
+ }
18937
+ const sectionEl = itemEl.closest("[data-ohw-section]");
18938
+ const unit = sectionEl ? movableUnit(sectionEl) : null;
18939
+ const sectionId = unit ? instanceIdOf(unit) || null : null;
18940
+ const index = Number(itemEl.dataset.ohwMediaStripIndex);
18941
+ if (!sectionId || Number.isNaN(index)) {
18942
+ setHover(null);
18943
+ return;
18944
+ }
18945
+ setHover({ sectionId, index });
19134
18946
  };
19135
18947
  const onLeave = () => setHover(null);
19136
18948
  document.addEventListener("mousemove", onMove, { passive: true });
@@ -19142,25 +18954,23 @@ function AiMediaStripOverlay({
19142
18954
  }, []);
19143
18955
  (0, import_react10.useEffect)(() => {
19144
18956
  const onClick = (e) => {
18957
+ const current = activeRef.current;
18958
+ if (!current) return;
19145
18959
  const t = e.target;
19146
- if (!(t instanceof Element)) return;
19147
- if (t.closest(CHROME_SELECTOR)) return;
19148
- const ref = itemRefFromTarget(t);
19149
- if (sameRef(activeRef.current, ref)) return;
19150
- if (ref) clearInteractionChromeRef.current();
19151
- setItemEditOn(false);
18960
+ if (!(t instanceof HTMLElement)) return;
18961
+ if (t.closest("[data-ohw-item-interaction]")) return;
18962
+ const itemEl = findMediaStripItemElement(current.sectionId, current.index);
18963
+ if (itemEl && itemEl.contains(t)) return;
18964
+ setActive(null);
19152
18965
  setError(null);
19153
- setActive(ref);
19154
18966
  };
19155
18967
  document.addEventListener("click", onClick, true);
19156
18968
  return () => document.removeEventListener("click", onClick, true);
19157
- }, [clearInteractionChromeRef]);
18969
+ }, []);
19158
18970
  (0, import_react10.useEffect)(() => {
19159
18971
  const onBlur = () => {
19160
18972
  if (!activeRef.current) return;
19161
18973
  setActive(null);
19162
- setItemEditOn(false);
19163
- setLinkOpen(false);
19164
18974
  setError(null);
19165
18975
  };
19166
18976
  window.addEventListener("blur", onBlur);
@@ -19170,10 +18980,7 @@ function AiMediaStripOverlay({
19170
18980
  const onKeyDown = (e) => {
19171
18981
  if (e.key !== "Escape") return;
19172
18982
  if (!activeRef.current) return;
19173
- if (linkOpenRef.current) return;
19174
- if (document.querySelector('[data-ohw-more-menu][data-state="open"]')) return;
19175
18983
  setActive(null);
19176
- setItemEditOn(false);
19177
18984
  setError(null);
19178
18985
  };
19179
18986
  document.addEventListener("keydown", onKeyDown);
@@ -19207,133 +19014,137 @@ function AiMediaStripOverlay({
19207
19014
  tree: nextTree,
19208
19015
  label: entry.label,
19209
19016
  media: extraMedia ? { ...entry.media, ...extraMedia } : entry.media,
19210
- ...entry.brand ? { brand: entry.brand } : {},
19211
- // The user is already looking at the strip they just edited — recentering the viewport
19212
- // on every edit reads as the section jumping around.
19213
- skipScrollIntoView: true
19017
+ ...entry.brand ? { brand: entry.brand } : {}
19214
19018
  });
19215
19019
  return true;
19216
19020
  },
19217
19021
  [findEntry, postToParent2, applyTreeLocalRef]
19218
19022
  );
19219
19023
  const activeEntry = active ? findEntry(active.sectionId) : null;
19024
+ const hoverHandleRect = useLiveItemRect(!active && hover ? hover : null);
19220
19025
  const activeItemRect = useLiveItemRect(active);
19221
- const activeStripRect = useLiveItemRect(active, true);
19222
- const hoverRect = useLiveItemRect(hover && !sameRef(hover, active) ? hover : null);
19223
- const activeItems = activeEntry ? mediaStripItems(activeEntry.tree) : [];
19224
- const activeItem = active ? activeItems[active.index] : void 0;
19225
- const activeHref = activeItem?.href ?? "";
19226
- const activeTarget = activeItem?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
19227
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
19228
- hoverRect && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
19229
- activeItemRect && activeStripRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
19230
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: activeItemRect, state: "active-top" }),
19231
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StripToolbarSlot, { stripRect: activeStripRect, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19232
- MediaStripToolbar,
19233
- {
19234
- entry: activeEntry,
19235
- index: active.index,
19236
- pending,
19237
- error,
19238
- itemEditOn,
19239
- onToggleItemEdit: () => setItemEditOn((on) => !on),
19240
- onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
19241
- onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
19242
- onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
19243
- onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
19244
- onResize: (delta) => {
19245
- const slots = findMediaStripSlots(activeEntry.tree);
19246
- const variant = slots?.variant === "reel" ? "reel" : "logos";
19247
- const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
19248
- void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
19249
- },
19250
- onOpenLink: () => setLinkOpen(true),
19251
- onAddItem: () => {
19252
- void requestAssetPick(postToParent2).then((picked) => {
19253
- if (!picked) return;
19254
- const item = { assetId: picked.assetId, alt: "Logo" };
19026
+ const TOOLBAR_APPROX_H = 170;
19027
+ const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
19028
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
19029
+ hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19030
+ "button",
19031
+ {
19032
+ type: "button",
19033
+ "data-ohw-toolbar": "",
19034
+ onClick: () => {
19035
+ clearInteractionChromeRef.current();
19036
+ setActive(hover);
19037
+ },
19038
+ "aria-label": "Configure media item",
19039
+ style: {
19040
+ position: "fixed",
19041
+ top: hoverHandleRect.top + 8,
19042
+ left: hoverHandleRect.left + hoverHandleRect.width - 36,
19043
+ width: 28,
19044
+ height: 28,
19045
+ borderRadius: 8,
19046
+ border: `1.5px dashed ${PRIMARY3}`,
19047
+ background: "#ffffff",
19048
+ color: PRIMARY3,
19049
+ display: "flex",
19050
+ alignItems: "center",
19051
+ justifyContent: "center",
19052
+ cursor: "pointer",
19053
+ zIndex: 2147483643,
19054
+ fontSize: 14,
19055
+ fontWeight: 700
19056
+ },
19057
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react8.Star, { size: 14, style: { pointerEvents: "none" } })
19058
+ }
19059
+ ),
19060
+ activeItemRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19061
+ ItemInteractionLayer,
19062
+ {
19063
+ rect: activeItemRect,
19064
+ state: toolbarState,
19065
+ toolbar: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19066
+ MediaStripToolbar,
19067
+ {
19068
+ entry: activeEntry,
19069
+ index: active.index,
19070
+ pending,
19071
+ error,
19072
+ onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
19073
+ onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
19074
+ onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
19075
+ onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
19076
+ onResize: (delta) => {
19077
+ const slots = findMediaStripSlots(activeEntry.tree);
19078
+ const variant = slots?.variant === "reel" ? "reel" : "logos";
19079
+ const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
19080
+ void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
19081
+ },
19082
+ onSetAlt: (alt) => {
19083
+ void runMutation(active.sectionId, (tree) => setMediaStripItemAlt(tree, active.index, alt));
19084
+ },
19085
+ onSetLink: (href, linkTarget) => {
19255
19086
  void runMutation(
19256
19087
  active.sectionId,
19257
- (tree) => addMediaStripItem(tree, item, active.index),
19258
- { [picked.assetId]: picked.url }
19259
- ).then((applied) => {
19260
- if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
19088
+ (tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
19089
+ );
19090
+ },
19091
+ onAddItem: () => {
19092
+ void requestAssetPick(postToParent2).then((picked) => {
19093
+ if (!picked) return;
19094
+ const item = { assetId: picked.assetId, alt: "Logo" };
19095
+ void runMutation(
19096
+ active.sectionId,
19097
+ (tree) => addMediaStripItem(tree, item, active.index),
19098
+ { [picked.assetId]: picked.url }
19099
+ ).then((applied) => {
19100
+ if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
19101
+ });
19261
19102
  });
19262
- });
19263
- },
19264
- onChangeImage: () => {
19265
- void requestAssetPick(postToParent2).then((picked) => {
19266
- if (!picked) return;
19267
- void runMutation(
19268
- active.sectionId,
19269
- (tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
19270
- { [picked.assetId]: picked.url }
19103
+ },
19104
+ onChangeImage: () => {
19105
+ void requestAssetPick(postToParent2).then((picked) => {
19106
+ if (!picked) return;
19107
+ void runMutation(
19108
+ active.sectionId,
19109
+ (tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
19110
+ { [picked.assetId]: picked.url }
19111
+ );
19112
+ });
19113
+ },
19114
+ onRemoveItem: () => {
19115
+ void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
19116
+ (applied) => {
19117
+ if (applied) setActive(null);
19118
+ }
19271
19119
  );
19272
- });
19273
- },
19274
- onRemoveItem: () => {
19275
- void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
19276
- (applied) => {
19277
- if (applied) setActive(null);
19278
- }
19279
- );
19280
- },
19281
- onMoveLeft: () => {
19282
- void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
19283
- (applied) => {
19284
- if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
19285
- }
19286
- );
19287
- },
19288
- onMoveRight: () => {
19289
- void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
19290
- (applied) => {
19291
- if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
19292
- }
19293
- );
19294
- }
19295
- }
19296
- ) }),
19297
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19298
- "div",
19299
- {
19300
- "data-ohw-bridge": "",
19301
- "data-ohw-item-interaction": "",
19302
- "aria-hidden": true,
19303
- className: "pointer-events-none fixed rounded-[4px] px-[7px] py-[3px] font-sans text-[11px] font-medium leading-none text-primary-foreground whitespace-nowrap",
19304
- style: {
19305
- top: activeItemRect.top + activeItemRect.height + 10,
19306
- left: activeItemRect.left - 5,
19307
- background: PRIMARY3,
19308
- zIndex: 2147483644
19309
- },
19310
- children: "Media item"
19311
- }
19312
- ),
19313
- linkOpen && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19314
- LinkModal,
19315
- {
19316
- href: activeHref,
19317
- linkTarget: activeTarget,
19318
- onClose: () => setLinkOpen(false),
19319
- onSave: (href, linkTarget) => {
19320
- void runMutation(
19321
- active.sectionId,
19322
- (tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
19323
- );
19120
+ },
19121
+ onMoveLeft: () => {
19122
+ void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
19123
+ (applied) => {
19124
+ if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
19125
+ }
19126
+ );
19127
+ },
19128
+ onMoveRight: () => {
19129
+ void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
19130
+ (applied) => {
19131
+ if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
19132
+ }
19133
+ );
19134
+ }
19324
19135
  }
19325
- }
19326
- )
19327
- ] })
19136
+ )
19137
+ }
19138
+ )
19328
19139
  ] });
19329
19140
  }
19330
19141
 
19331
19142
  // src/ui/ai-section/AiPricingCardOverlay.tsx
19332
19143
  var import_react11 = require("react");
19333
- var import_lucide_react10 = require("lucide-react");
19334
- var import_jsx_runtime22 = require("react/jsx-runtime");
19144
+ var import_lucide_react9 = require("lucide-react");
19145
+ var import_jsx_runtime21 = require("react/jsx-runtime");
19335
19146
  var PRIMARY4 = "var(--ohw-primary, #0885FE)";
19336
- 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]";
19147
+ 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]";
19337
19148
  function findPricingCardElement(sectionId, index) {
19338
19149
  const sectionEl = findByInstanceId(sectionId);
19339
19150
  if (!sectionEl) return null;
@@ -19345,7 +19156,7 @@ function findPricingCardElement(sectionId, index) {
19345
19156
  }
19346
19157
  function cardRefFromTarget(target) {
19347
19158
  if (!(target instanceof Element)) return null;
19348
- if (target.closest(CHROME_SELECTOR2)) return null;
19159
+ if (target.closest(CHROME_SELECTOR)) return null;
19349
19160
  const cardEl = target.closest("[data-ohw-pricing-card]");
19350
19161
  if (!cardEl) return null;
19351
19162
  const sectionEl = cardEl.closest("[data-ohw-section]");
@@ -19355,21 +19166,21 @@ function cardRefFromTarget(target) {
19355
19166
  if (!sectionId || Number.isNaN(index)) return null;
19356
19167
  return { sectionId, index };
19357
19168
  }
19358
- function sameRef2(a, b) {
19169
+ function sameRef(a, b) {
19359
19170
  return a?.sectionId === b?.sectionId && a?.index === b?.index;
19360
19171
  }
19361
- function rectOf2(el) {
19172
+ function rectOf(el) {
19362
19173
  if (!el) return null;
19363
19174
  const r2 = el.getBoundingClientRect();
19364
19175
  if (r2.width <= 0 || r2.height <= 0) return null;
19365
19176
  return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
19366
19177
  }
19367
19178
  function readRect3(ref) {
19368
- return rectOf2(ref && findPricingCardElement(ref.sectionId, ref.index));
19179
+ return rectOf(ref && findPricingCardElement(ref.sectionId, ref.index));
19369
19180
  }
19370
19181
  function readGridRect(ref) {
19371
19182
  const card = ref && findPricingCardElement(ref.sectionId, ref.index);
19372
- return rectOf2(card?.closest("[data-ohw-pricing-collection]") ?? card);
19183
+ return rectOf(card?.closest("[data-ohw-pricing-collection]") ?? card);
19373
19184
  }
19374
19185
  function useLiveCardRect(ref, grid = false) {
19375
19186
  const [rect, setRect] = (0, import_react11.useState)(null);
@@ -19399,7 +19210,7 @@ function useLiveCardRect(ref, grid = false) {
19399
19210
  }
19400
19211
  var TOOLBAR_GRID_GAP = 52;
19401
19212
  var TOOLBAR_GRID_GAP_MOBILE = 42;
19402
- var TOOLBAR_EDGE_MARGIN3 = 4;
19213
+ var TOOLBAR_EDGE_MARGIN2 = 4;
19403
19214
  function GridToolbarSlot({ gridRect, children }) {
19404
19215
  const slotRef = (0, import_react11.useRef)(null);
19405
19216
  const [shift, setShift] = (0, import_react11.useState)(0);
@@ -19411,7 +19222,7 @@ function GridToolbarSlot({ gridRect, children }) {
19411
19222
  const w = slot.offsetWidth;
19412
19223
  if (w <= 0) return;
19413
19224
  const half = w / 2;
19414
- const clamped = Math.max(TOOLBAR_EDGE_MARGIN3 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half));
19225
+ const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
19415
19226
  setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
19416
19227
  };
19417
19228
  clamp();
@@ -19420,7 +19231,7 @@ function GridToolbarSlot({ gridRect, children }) {
19420
19231
  return () => ro.disconnect();
19421
19232
  }, [centerX, children]);
19422
19233
  const mobile = window.innerWidth <= 480;
19423
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
19234
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19424
19235
  "div",
19425
19236
  {
19426
19237
  ref: slotRef,
@@ -19455,7 +19266,7 @@ function requestValidateTree2(postToParent2, tree) {
19455
19266
  });
19456
19267
  }
19457
19268
  function StyleSwatch({ style }) {
19458
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
19269
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19459
19270
  "span",
19460
19271
  {
19461
19272
  "aria-hidden": true,
@@ -19469,35 +19280,35 @@ function StyleSwatch({ style }) {
19469
19280
  );
19470
19281
  }
19471
19282
  function ButtonGlyph() {
19472
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19473
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
19474
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
19283
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19284
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
19285
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
19475
19286
  ] });
19476
19287
  }
19477
19288
  function FeatureGlyph({ mode }) {
19478
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19479
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
19480
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
19481
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
19482
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
19483
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
19484
- mode === "add" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
19289
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19290
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
19291
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
19292
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
19293
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
19294
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
19295
+ mode === "add" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
19485
19296
  ] });
19486
19297
  }
19487
- function ToolbarAction2({
19298
+ function ToolbarAction({
19488
19299
  label,
19489
19300
  onClick,
19490
19301
  disabled = false,
19491
19302
  children
19492
19303
  }) {
19493
- const button = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
19494
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Tooltip, { children: [
19495
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "inline-flex", children: button }) : button }),
19496
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
19304
+ const button = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
19305
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
19306
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "inline-flex", children: button }) : button }),
19307
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
19497
19308
  ] });
19498
19309
  }
19499
- function ToolbarSeparator2() {
19500
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
19310
+ function ToolbarSeparator() {
19311
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
19501
19312
  }
19502
19313
  function CardStyleMenu({
19503
19314
  value,
@@ -19505,7 +19316,7 @@ function CardStyleMenu({
19505
19316
  disabled = false
19506
19317
  }) {
19507
19318
  const current = PRICING_CARD_STYLES.find((s) => s.value === value) ?? PRICING_CARD_STYLES[0];
19508
- const trigger = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
19319
+ const trigger = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
19509
19320
  "button",
19510
19321
  {
19511
19322
  type: "button",
@@ -19516,28 +19327,28 @@ function CardStyleMenu({
19516
19327
  disabled && "cursor-not-allowed opacity-40 hover:bg-transparent"
19517
19328
  ),
19518
19329
  children: [
19519
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(StyleSwatch, { style: current.value }),
19520
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "flex-1 text-left", children: current.label }),
19521
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.ChevronDown, { size: 16, style: { pointerEvents: "none" } })
19330
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StyleSwatch, { style: current.value }),
19331
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "flex-1 text-left", children: current.label }),
19332
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.ChevronDown, { size: 16, style: { pointerEvents: "none" } })
19522
19333
  ]
19523
19334
  }
19524
19335
  );
19525
19336
  if (disabled) {
19526
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19527
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
19528
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Tooltip, { children: [
19529
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "inline-flex", children: trigger }) }),
19530
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
19337
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19338
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
19339
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
19340
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "inline-flex", children: trigger }) }),
19341
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
19531
19342
  ] })
19532
19343
  ] });
19533
19344
  }
19534
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19535
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
19536
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DropdownMenu, { modal: false, children: [
19537
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DropdownMenuTrigger, { asChild: true, children: trigger }),
19538
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
19345
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19346
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
19347
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DropdownMenu, { modal: false, children: [
19348
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuTrigger, { asChild: true, children: trigger }),
19349
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
19539
19350
  const selected = style.value === value;
19540
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
19351
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
19541
19352
  DropdownMenuItem,
19542
19353
  {
19543
19354
  role: "menuitemradio",
@@ -19545,9 +19356,9 @@ function CardStyleMenu({
19545
19356
  onSelect: () => onChange(style.value),
19546
19357
  className: cn("grid grid-cols-[18px_1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
19547
19358
  children: [
19548
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(StyleSwatch, { style: style.value }),
19549
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: style.label }),
19550
- selected && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.Check, { size: 16, className: "text-bridge-primary" })
19359
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StyleSwatch, { style: style.value }),
19360
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: style.label }),
19361
+ selected && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Check, { size: 16, className: "text-bridge-primary" })
19551
19362
  ]
19552
19363
  },
19553
19364
  style.value
@@ -19577,7 +19388,7 @@ function PricingCardToolbar({
19577
19388
  const style = pricingCardStyle(entry.tree, index);
19578
19389
  const featuredTag = pricingCardFeaturedTag(entry.tree, index);
19579
19390
  const mobile = window.innerWidth <= 480;
19580
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
19391
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
19581
19392
  "div",
19582
19393
  {
19583
19394
  "data-ohw-bridge": "",
@@ -19589,7 +19400,7 @@ function PricingCardToolbar({
19589
19400
  ),
19590
19401
  style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
19591
19402
  children: [
19592
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
19403
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
19593
19404
  "div",
19594
19405
  {
19595
19406
  className: cn(
@@ -19598,8 +19409,8 @@ function PricingCardToolbar({
19598
19409
  mobile ? "flex-wrap justify-center" : "flex-nowrap"
19599
19410
  ),
19600
19411
  children: [
19601
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Tooltip, { children: [
19602
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
19412
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
19413
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19603
19414
  CustomToolbarButton,
19604
19415
  {
19605
19416
  type: "button",
@@ -19607,8 +19418,8 @@ function PricingCardToolbar({
19607
19418
  "aria-pressed": featuredTag,
19608
19419
  onClick: () => onSetFeaturedTag(!featuredTag),
19609
19420
  className: "group size-8",
19610
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
19611
- import_lucide_react10.Star,
19421
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19422
+ import_lucide_react9.Star,
19612
19423
  {
19613
19424
  size: 16,
19614
19425
  fill: "currentColor",
@@ -19622,25 +19433,25 @@ function PricingCardToolbar({
19622
19433
  )
19623
19434
  }
19624
19435
  ) }),
19625
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
19436
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
19626
19437
  ] }),
19627
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarSeparator2, {}),
19628
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
19629
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarSeparator2, {}),
19630
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ButtonGlyph, {}) }),
19631
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "relative inline-flex", children: [
19632
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ButtonGlyph, {}),
19633
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.Minus, { size: 10, strokeWidth: 2.5, className: "absolute -right-1.5 -top-1.5 rounded-full bg-background text-bridge-primary" })
19438
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
19439
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
19440
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
19441
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ButtonGlyph, {}) }),
19442
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "relative inline-flex", children: [
19443
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ButtonGlyph, {}),
19444
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Minus, { size: 10, strokeWidth: 2.5, className: "absolute -right-1.5 -top-1.5 rounded-full bg-background text-bridge-primary" })
19634
19445
  ] }) }),
19635
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(FeatureGlyph, { mode: "add" }) }),
19636
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(FeatureGlyph, { mode: "remove" }) }),
19637
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarSeparator2, {}),
19638
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.Plus, { size: 16, style: { pointerEvents: "none" } }) }),
19639
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToolbarAction2, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.Minus, { size: 16, style: { pointerEvents: "none" } }) })
19446
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(FeatureGlyph, { mode: "add" }) }),
19447
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(FeatureGlyph, { mode: "remove" }) }),
19448
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator, {}),
19449
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Plus, { size: 16, style: { pointerEvents: "none" } }) }),
19450
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react9.Minus, { size: 16, style: { pointerEvents: "none" } }) })
19640
19451
  ]
19641
19452
  }
19642
19453
  ),
19643
- error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
19454
+ error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
19644
19455
  ]
19645
19456
  }
19646
19457
  ) });
@@ -19674,7 +19485,7 @@ function AiPricingCardOverlay({
19674
19485
  const overEditable = Boolean(t?.closest?.("[data-ohw-editable], [data-ohw-role], a, button"));
19675
19486
  setHover((prev) => {
19676
19487
  const next = ref && !overEditable ? ref : null;
19677
- return sameRef2(prev, next) ? prev : next;
19488
+ return sameRef(prev, next) ? prev : next;
19678
19489
  });
19679
19490
  };
19680
19491
  const onLeave = () => setHover(null);
@@ -19689,10 +19500,10 @@ function AiPricingCardOverlay({
19689
19500
  const onClick = (e) => {
19690
19501
  const t = e.target;
19691
19502
  if (!(t instanceof Element)) return;
19692
- if (t.closest(CHROME_SELECTOR2)) return;
19503
+ if (t.closest(CHROME_SELECTOR)) return;
19693
19504
  const ref = cardRefFromTarget(t);
19694
- setActive((prev) => sameRef2(prev, ref) ? prev : ref);
19695
- if (!ref || !sameRef2(activeRef.current, ref)) setError(null);
19505
+ setActive((prev) => sameRef(prev, ref) ? prev : ref);
19506
+ if (!ref || !sameRef(activeRef.current, ref)) setError(null);
19696
19507
  };
19697
19508
  document.addEventListener("click", onClick, true);
19698
19509
  return () => document.removeEventListener("click", onClick, true);
@@ -19757,12 +19568,12 @@ function AiPricingCardOverlay({
19757
19568
  const activeEntry = active ? findEntry(active.sectionId) : null;
19758
19569
  const activeCardRect = useLiveCardRect(active);
19759
19570
  const activeGridRect = useLiveCardRect(active, true);
19760
- const hoverRect = useLiveCardRect(hover && !sameRef2(hover, active) ? hover : null);
19761
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
19762
- hoverRect && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
19763
- activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
19764
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
19765
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
19571
+ const hoverRect = useLiveCardRect(hover && !sameRef(hover, active) ? hover : null);
19572
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
19573
+ hoverRect && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
19574
+ activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
19575
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
19576
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19766
19577
  PricingCardToolbar,
19767
19578
  {
19768
19579
  entry: activeEntry,
@@ -19790,7 +19601,7 @@ function AiPricingCardOverlay({
19790
19601
  onRemoveFeature: () => runMutation(active.sectionId, (tree) => removePricingCardFeature(tree, active.index))
19791
19602
  }
19792
19603
  ) }),
19793
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
19604
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19794
19605
  "div",
19795
19606
  {
19796
19607
  "data-ohw-bridge": "",
@@ -19812,7 +19623,7 @@ function AiPricingCardOverlay({
19812
19623
 
19813
19624
  // src/ui/ai-section/AiVideoOverlay.tsx
19814
19625
  var import_react12 = require("react");
19815
- var import_lucide_react11 = require("lucide-react");
19626
+ var import_lucide_react10 = require("lucide-react");
19816
19627
 
19817
19628
  // src/lib/ai-video-tree.ts
19818
19629
  function resolveVideoBlock(tree, path) {
@@ -19883,10 +19694,10 @@ function extractYouTubeId(input) {
19883
19694
  }
19884
19695
 
19885
19696
  // src/ui/ai-section/AiVideoOverlay.tsx
19886
- var import_jsx_runtime23 = require("react/jsx-runtime");
19697
+ var import_jsx_runtime22 = require("react/jsx-runtime");
19887
19698
  var PRIMARY5 = "#0885FE";
19888
- var OHW_BLUE = `var(--ohw-primary, ${PRIMARY5})`;
19889
- var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
19699
+ var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY5})`;
19700
+ var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
19890
19701
  function findVideoBlockElement(sectionId, path) {
19891
19702
  const sectionEl = findByInstanceId(sectionId);
19892
19703
  if (!sectionEl) return null;
@@ -19946,12 +19757,12 @@ function requestValidateTree3(postToParent2, tree) {
19946
19757
  postToParent2({ type: "ow:ai-validate-tree-request", id, tree });
19947
19758
  });
19948
19759
  }
19949
- function Pill({
19760
+ function Pill2({
19950
19761
  label,
19951
19762
  onClick,
19952
19763
  disabled
19953
19764
  }) {
19954
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
19765
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
19955
19766
  "button",
19956
19767
  {
19957
19768
  type: "button",
@@ -19967,7 +19778,7 @@ function Pill({
19967
19778
  border: "none",
19968
19779
  cursor: disabled ? "default" : "pointer",
19969
19780
  background: "#ffffff",
19970
- color: OHW_BLUE_DARK,
19781
+ color: OHW_BLUE_DARK2,
19971
19782
  opacity: disabled ? 0.4 : 1,
19972
19783
  fontSize: 12,
19973
19784
  lineHeight: "16px",
@@ -20010,8 +19821,8 @@ function VideoUrlInput({ value, onCommit }) {
20010
19821
  onCommit(id);
20011
19822
  }
20012
19823
  };
20013
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
20014
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
19824
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
19825
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
20015
19826
  "div",
20016
19827
  {
20017
19828
  style: {
@@ -20027,12 +19838,12 @@ function VideoUrlInput({ value, onCommit }) {
20027
19838
  boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
20028
19839
  },
20029
19840
  children: [
20030
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
19841
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
20031
19842
  "span",
20032
19843
  {
20033
19844
  style: {
20034
19845
  flex: "0 0 auto",
20035
- color: OHW_BLUE_DARK,
19846
+ color: OHW_BLUE_DARK2,
20036
19847
  fontSize: 10,
20037
19848
  lineHeight: "16px",
20038
19849
  fontWeight: 700,
@@ -20042,7 +19853,7 @@ function VideoUrlInput({ value, onCommit }) {
20042
19853
  children: "Video"
20043
19854
  }
20044
19855
  ),
20045
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
19856
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
20046
19857
  "input",
20047
19858
  {
20048
19859
  type: "text",
@@ -20079,7 +19890,7 @@ function VideoUrlInput({ value, onCommit }) {
20079
19890
  ]
20080
19891
  }
20081
19892
  ),
20082
- invalid && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, textAlign: "center" }, children: "That doesn't look like a YouTube link \u2014 try pasting the video URL again." })
19893
+ invalid && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, textAlign: "center" }, children: "That doesn't look like a YouTube link \u2014 try pasting the video URL again." })
20083
19894
  ] });
20084
19895
  }
20085
19896
  function VideoToolbar({
@@ -20089,7 +19900,7 @@ function VideoToolbar({
20089
19900
  onSetVideoId,
20090
19901
  onRemove
20091
19902
  }) {
20092
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
19903
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
20093
19904
  "div",
20094
19905
  {
20095
19906
  "data-ohw-bridge": "",
@@ -20101,7 +19912,7 @@ function VideoToolbar({
20101
19912
  gap: 6,
20102
19913
  alignItems: "center",
20103
19914
  width: 280,
20104
- background: OHW_BLUE,
19915
+ background: OHW_BLUE2,
20105
19916
  padding: 8,
20106
19917
  borderRadius: 12,
20107
19918
  boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
@@ -20109,9 +19920,9 @@ function VideoToolbar({
20109
19920
  opacity: pending ? 0.6 : 1
20110
19921
  },
20111
19922
  children: [
20112
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
20113
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Pill, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
20114
- error && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
19923
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
19924
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Pill2, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
19925
+ error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
20115
19926
  ]
20116
19927
  }
20117
19928
  );
@@ -20231,8 +20042,8 @@ function AiVideoOverlay({
20231
20042
  const activeBlockRect = useLiveBlockRect(active);
20232
20043
  const TOOLBAR_APPROX_H = 90;
20233
20044
  const toolbarState = activeBlockRect && activeBlockRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
20234
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
20235
- hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20045
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
20046
+ hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
20236
20047
  "button",
20237
20048
  {
20238
20049
  type: "button",
@@ -20260,15 +20071,15 @@ function AiVideoOverlay({
20260
20071
  fontSize: 14,
20261
20072
  fontWeight: 700
20262
20073
  },
20263
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.Star, { size: 14, style: { pointerEvents: "none" } })
20074
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.Star, { size: 14, style: { pointerEvents: "none" } })
20264
20075
  }
20265
20076
  ),
20266
- activeBlockRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20077
+ activeBlockRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
20267
20078
  ItemInteractionLayer,
20268
20079
  {
20269
20080
  rect: activeBlockRect,
20270
20081
  state: toolbarState,
20271
- toolbar: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20082
+ toolbar: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
20272
20083
  VideoToolbar,
20273
20084
  {
20274
20085
  videoId: videoIdAt(activeEntry.tree, active.path),
@@ -20292,7 +20103,7 @@ function AiVideoOverlay({
20292
20103
 
20293
20104
  // src/ui/ai-section/AiFadeCarouselOverlay.tsx
20294
20105
  var import_react13 = require("react");
20295
- var import_lucide_react12 = require("lucide-react");
20106
+ var import_lucide_react11 = require("lucide-react");
20296
20107
 
20297
20108
  // src/lib/ai-carousel-tree.ts
20298
20109
  function isCarouselBlock(node) {
@@ -20343,10 +20154,10 @@ function setCarouselAutoplay(tree, on) {
20343
20154
  }
20344
20155
 
20345
20156
  // src/ui/ai-section/AiFadeCarouselOverlay.tsx
20346
- var import_jsx_runtime24 = require("react/jsx-runtime");
20157
+ var import_jsx_runtime23 = require("react/jsx-runtime");
20347
20158
  var PRIMARY6 = "#0885FE";
20348
- var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY6})`;
20349
- var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
20159
+ var OHW_BLUE3 = `var(--ohw-primary, ${PRIMARY6})`;
20160
+ var OHW_BLUE_DARK3 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
20350
20161
  function findCarouselItemElement(sectionId, index) {
20351
20162
  const sectionEl = findByInstanceId(sectionId);
20352
20163
  if (!sectionEl) return null;
@@ -20425,8 +20236,8 @@ function requestAssetPick2(postToParent2) {
20425
20236
  postToParent2({ type: "ow:asset-pick", id });
20426
20237
  });
20427
20238
  }
20428
- function Pill2({ label, onClick, disabled }) {
20429
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
20239
+ function Pill3({ label, onClick, disabled }) {
20240
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20430
20241
  "button",
20431
20242
  {
20432
20243
  type: "button",
@@ -20442,7 +20253,7 @@ function Pill2({ label, onClick, disabled }) {
20442
20253
  border: "none",
20443
20254
  cursor: disabled ? "default" : "pointer",
20444
20255
  background: "#ffffff",
20445
- color: OHW_BLUE_DARK2,
20256
+ color: OHW_BLUE_DARK3,
20446
20257
  opacity: disabled ? 0.4 : 1,
20447
20258
  fontSize: 12,
20448
20259
  lineHeight: "16px",
@@ -20460,7 +20271,7 @@ function TogglePill({
20460
20271
  onToggle,
20461
20272
  disabled
20462
20273
  }) {
20463
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
20274
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
20464
20275
  "button",
20465
20276
  {
20466
20277
  type: "button",
@@ -20479,7 +20290,7 @@ function TogglePill({
20479
20290
  border: "none",
20480
20291
  cursor: disabled ? "default" : "pointer",
20481
20292
  background: "#ffffff",
20482
- color: OHW_BLUE_DARK2,
20293
+ color: OHW_BLUE_DARK3,
20483
20294
  opacity: disabled ? 0.4 : 1,
20484
20295
  fontSize: 12,
20485
20296
  lineHeight: "16px",
@@ -20489,7 +20300,7 @@ function TogglePill({
20489
20300
  },
20490
20301
  children: [
20491
20302
  label,
20492
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
20303
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20493
20304
  "span",
20494
20305
  {
20495
20306
  "aria-hidden": true,
@@ -20502,10 +20313,10 @@ function TogglePill({
20502
20313
  // Off is a grey track, not a washed-out blue: the pill's own white background already
20503
20314
  // carries the brand colour in the text, and a pale blue track next to it read as
20504
20315
  // "disabled control" rather than "switch that is off".
20505
- background: on ? OHW_BLUE_DARK2 : "#CBD5E1",
20316
+ background: on ? OHW_BLUE_DARK3 : "#CBD5E1",
20506
20317
  transition: "background 120ms ease"
20507
20318
  },
20508
- children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
20319
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20509
20320
  "span",
20510
20321
  {
20511
20322
  style: {
@@ -20534,7 +20345,7 @@ function CarouselSlideToolbar({
20534
20345
  onChangeImage,
20535
20346
  onToggleAutoplay
20536
20347
  }) {
20537
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
20348
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
20538
20349
  "div",
20539
20350
  {
20540
20351
  "data-ohw-bridge": "",
@@ -20545,7 +20356,7 @@ function CarouselSlideToolbar({
20545
20356
  flexDirection: "column",
20546
20357
  gap: 6,
20547
20358
  alignItems: "center",
20548
- background: OHW_BLUE2,
20359
+ background: OHW_BLUE3,
20549
20360
  padding: 8,
20550
20361
  borderRadius: 12,
20551
20362
  boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
@@ -20557,11 +20368,11 @@ function CarouselSlideToolbar({
20557
20368
  pointerEvents: pending ? "none" : "auto"
20558
20369
  },
20559
20370
  children: [
20560
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
20561
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Pill2, { label: "Change Image", onClick: onChangeImage }),
20562
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
20371
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
20372
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Pill3, { label: "Change Image", onClick: onChangeImage }),
20373
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
20563
20374
  ] }),
20564
- error && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
20375
+ error && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
20565
20376
  ]
20566
20377
  }
20567
20378
  );
@@ -20701,8 +20512,8 @@ function AiFadeCarouselOverlay({
20701
20512
  const activeItemRect = useLiveItemRect2(active);
20702
20513
  const TOOLBAR_APPROX_H = 90;
20703
20514
  const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
20704
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
20705
- hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
20515
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
20516
+ hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20706
20517
  "button",
20707
20518
  {
20708
20519
  type: "button",
@@ -20731,10 +20542,10 @@ function AiFadeCarouselOverlay({
20731
20542
  fontSize: 14,
20732
20543
  fontWeight: 700
20733
20544
  },
20734
- children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.Star, { size: 14, style: { pointerEvents: "none" } })
20545
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.Star, { size: 14, style: { pointerEvents: "none" } })
20735
20546
  }
20736
20547
  ),
20737
- swapping && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
20548
+ swapping && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20738
20549
  "div",
20739
20550
  {
20740
20551
  ref: skeletonRef,
@@ -20752,15 +20563,15 @@ function AiFadeCarouselOverlay({
20752
20563
  zIndex: 2147483646,
20753
20564
  pointerEvents: "none"
20754
20565
  },
20755
- children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("style", { children: MEDIA_SKELETON_CSS })
20566
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("style", { children: MEDIA_SKELETON_CSS })
20756
20567
  }
20757
20568
  ),
20758
- activeItemRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
20569
+ activeItemRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20759
20570
  ItemInteractionLayer,
20760
20571
  {
20761
20572
  rect: activeItemRect,
20762
20573
  state: toolbarState,
20763
- toolbar: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
20574
+ toolbar: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20764
20575
  CarouselSlideToolbar,
20765
20576
  {
20766
20577
  pending,
@@ -21113,6 +20924,113 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
21113
20924
  // src/ui/link-modal/LinkPopover.tsx
21114
20925
  var import_react17 = require("react");
21115
20926
 
20927
+ // src/ui/dialog.tsx
20928
+ var React9 = __toESM(require("react"), 1);
20929
+ var import_radix_ui6 = require("radix-ui");
20930
+ var import_lucide_react12 = require("lucide-react");
20931
+ var import_jsx_runtime24 = require("react/jsx-runtime");
20932
+ function Dialog2({
20933
+ ...props
20934
+ }) {
20935
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
20936
+ }
20937
+ function DialogPortal({
20938
+ ...props
20939
+ }) {
20940
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
20941
+ }
20942
+ function DialogOverlay({
20943
+ className,
20944
+ ...props
20945
+ }) {
20946
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
20947
+ import_radix_ui6.Dialog.Overlay,
20948
+ {
20949
+ "data-slot": "dialog-overlay",
20950
+ "data-ohw-link-modal-root": "",
20951
+ className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
20952
+ ...props
20953
+ }
20954
+ );
20955
+ }
20956
+ var DialogContent = React9.forwardRef(
20957
+ ({ className, children, showCloseButton = true, container, ...props }, ref) => {
20958
+ const positionMode = container ? "absolute" : "fixed";
20959
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DialogPortal, { container: container ?? void 0, children: [
20960
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
20961
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
20962
+ import_radix_ui6.Dialog.Content,
20963
+ {
20964
+ ref,
20965
+ "data-slot": "dialog-content",
20966
+ className: cn(
20967
+ positionMode,
20968
+ "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",
20969
+ "rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
20970
+ container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
20971
+ className
20972
+ ),
20973
+ onMouseDown: (e) => e.stopPropagation(),
20974
+ ...props,
20975
+ children: [
20976
+ children,
20977
+ showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
20978
+ import_radix_ui6.Dialog.Close,
20979
+ {
20980
+ type: "button",
20981
+ className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
20982
+ "aria-label": "Close",
20983
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.X, { size: 16, "aria-hidden": true })
20984
+ }
20985
+ ) : null
20986
+ ]
20987
+ }
20988
+ )
20989
+ ] });
20990
+ }
20991
+ );
20992
+ DialogContent.displayName = import_radix_ui6.Dialog.Content.displayName;
20993
+ function DialogHeader({
20994
+ className,
20995
+ ...props
20996
+ }) {
20997
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
20998
+ }
20999
+ function DialogFooter({
21000
+ className,
21001
+ ...props
21002
+ }) {
21003
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
21004
+ "div",
21005
+ {
21006
+ className: cn("flex items-center justify-end gap-2", className),
21007
+ ...props
21008
+ }
21009
+ );
21010
+ }
21011
+ var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
21012
+ import_radix_ui6.Dialog.Title,
21013
+ {
21014
+ ref,
21015
+ className: cn(
21016
+ "text-lg font-semibold leading-none tracking-tight text-card-foreground",
21017
+ className
21018
+ ),
21019
+ ...props
21020
+ }
21021
+ ));
21022
+ DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
21023
+ var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
21024
+ import_radix_ui6.Dialog.Description,
21025
+ {
21026
+ ref,
21027
+ className: cn("text-sm text-muted-foreground", className),
21028
+ ...props
21029
+ }
21030
+ ));
21031
+ DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
21032
+ var DialogClose = import_radix_ui6.Dialog.Close;
21033
+
21116
21034
  // src/ui/link-modal/LinkEditorPanel.tsx
21117
21035
  var import_lucide_react16 = require("lucide-react");
21118
21036
 
@@ -22216,7 +22134,6 @@ function shouldUseDevFixtures() {
22216
22134
  function getLogoElement(el) {
22217
22135
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
22218
22136
  if (marked) return marked;
22219
- if (el.closest('[data-ohw-editable="icon"]')) return null;
22220
22137
  const root = el.closest("nav, [data-ohw-nav-root], footer");
22221
22138
  if (!root) return null;
22222
22139
  const anchor = el.closest("a");
@@ -24797,7 +24714,7 @@ function getNavigationSelectionParent(el) {
24797
24714
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
24798
24715
  return resolveFooterLinksContainerFrom(el);
24799
24716
  }
24800
- 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)) {
24717
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
24801
24718
  return getNavigationRoot(el);
24802
24719
  }
24803
24720
  return null;
@@ -25019,6 +24936,7 @@ var ICONS = {
25019
24936
  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"/>',
25020
24937
  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"/>'
25021
24938
  };
24939
+ var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
25022
24940
  var SELECTION_CHROME_GAP2 = 4;
25023
24941
  var TOOLBAR_STROKE_GAP2 = 4;
25024
24942
  var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
@@ -25116,7 +25034,7 @@ function applyVisibleViewport(el, parentScroll) {
25116
25034
  el.style.top = `${top}px`;
25117
25035
  el.style.height = `${height}px`;
25118
25036
  }
25119
- var TOOLBAR_EDGE_MARGIN4 = 4;
25037
+ var TOOLBAR_EDGE_MARGIN3 = 4;
25120
25038
  function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
25121
25039
  const isAbove = transform.includes("translateY(-100%)");
25122
25040
  let visualTop = isAbove ? top - approxH : top;
@@ -25143,8 +25061,8 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
25143
25061
  function clampToolbarLeft(centerX, toolbarWidth) {
25144
25062
  const half = toolbarWidth / 2;
25145
25063
  return Math.max(
25146
- TOOLBAR_EDGE_MARGIN4 + half,
25147
- Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN4 - half)
25064
+ TOOLBAR_EDGE_MARGIN3 + half,
25065
+ Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half)
25148
25066
  );
25149
25067
  }
25150
25068
  function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
@@ -26024,6 +25942,21 @@ function OhhwellsBridge() {
26024
25942
  const [isItemDragging, setIsItemDragging] = (0, import_react21.useState)(false);
26025
25943
  const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react21.useState)(false);
26026
25944
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
25945
+ const [floatingPanel, setFloatingPanel] = (0, import_react21.useState)(null);
25946
+ const floatingPanelOpenRef = (0, import_react21.useRef)(false);
25947
+ floatingPanelOpenRef.current = floatingPanel !== null;
25948
+ const floatingPanelRef = (0, import_react21.useRef)(null);
25949
+ floatingPanelRef.current = floatingPanel;
25950
+ const [floatingPanelPos, setFloatingPanelPos] = (0, import_react21.useState)(null);
25951
+ const buttonCollectionDragRef = (0, import_react21.useRef)(null);
25952
+ const buttonDropInsertIndexRef = (0, import_react21.useRef)(null);
25953
+ const [buttonDropSlots, setButtonDropSlots] = (0, import_react21.useState)([]);
25954
+ const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react21.useState)(null);
25955
+ const buttonPointerDragRef = (0, import_react21.useRef)(null);
25956
+ const [buttonStyleTick, setButtonStyleTick] = (0, import_react21.useState)(0);
25957
+ const [logoSizeDraft, setLogoSizeDraft] = (0, import_react21.useState)(null);
25958
+ const [editorViewport, setEditorViewport] = (0, import_react21.useState)("desktop");
25959
+ const [parentScrollSnap, setParentScrollSnap] = (0, import_react21.useState)(null);
26027
25960
  const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react21.useState)(null);
26028
25961
  const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react21.useState)(null);
26029
25962
  const footerDragRef = (0, import_react21.useRef)(null);
@@ -26049,21 +25982,6 @@ function OhhwellsBridge() {
26049
25982
  const stylesRef = (0, import_react21.useRef)("");
26050
25983
  const appliedDrawerRef = (0, import_react21.useRef)(null);
26051
25984
  const pendingDeleteUndoRef = (0, import_react21.useRef)(null);
26052
- const [floatingPanel, setFloatingPanel] = (0, import_react21.useState)(null);
26053
- const floatingPanelOpenRef = (0, import_react21.useRef)(false);
26054
- const floatingPanelRef = (0, import_react21.useRef)(null);
26055
- floatingPanelRef.current = floatingPanel;
26056
- const setFloatingPanelRef = (0, import_react21.useRef)(setFloatingPanel);
26057
- const [floatingPanelPos, setFloatingPanelPos] = (0, import_react21.useState)(null);
26058
- const buttonCollectionDragRef = (0, import_react21.useRef)(null);
26059
- const buttonDropInsertIndexRef = (0, import_react21.useRef)(null);
26060
- const [buttonDropSlots, setButtonDropSlots] = (0, import_react21.useState)([]);
26061
- const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react21.useState)(null);
26062
- const buttonPointerDragRef = (0, import_react21.useRef)(null);
26063
- const [buttonStyleTick, setButtonStyleTick] = (0, import_react21.useState)(0);
26064
- const [logoSizeDraft, setLogoSizeDraft] = (0, import_react21.useState)(null);
26065
- const [editorViewport, setEditorViewport] = (0, import_react21.useState)("desktop");
26066
- const [parentScrollSnap, setParentScrollSnap] = (0, import_react21.useState)(null);
26067
25985
  const [sitePages, setSitePages] = (0, import_react21.useState)([]);
26068
25986
  const [sectionsByPath, setSectionsByPath] = (0, import_react21.useState)({});
26069
25987
  const sectionsPrefetchGenRef = (0, import_react21.useRef)(0);
@@ -26072,18 +25990,7 @@ function OhhwellsBridge() {
26072
25990
  const linkPopoverOpenRef = (0, import_react21.useRef)(false);
26073
25991
  const linkPopoverGraceUntilRef = (0, import_react21.useRef)(0);
26074
25992
  setLinkPopoverRef.current = setLinkPopover;
26075
- setFloatingPanelRef.current = setFloatingPanel;
26076
25993
  linkPopoverSessionRef.current = linkPopover;
26077
- floatingPanelOpenRef.current = Boolean(floatingPanel);
26078
- (0, import_react21.useEffect)(() => {
26079
- const syncViewport = () => {
26080
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
26081
- setEditorViewport((prev) => prev === next ? prev : next);
26082
- };
26083
- syncViewport();
26084
- window.addEventListener("resize", syncViewport);
26085
- return () => window.removeEventListener("resize", syncViewport);
26086
- }, []);
26087
25994
  (0, import_react21.useEffect)(() => {
26088
25995
  setSectionOrderPersistHandler((entries) => {
26089
25996
  const currentPath = window.location.pathname;
@@ -27778,7 +27685,6 @@ function OhhwellsBridge() {
27778
27685
  applyAiFooterFromContent(content);
27779
27686
  if (typeof content[STYLE_STORE_KEY] === "string") {
27780
27687
  stylesRef.current = content[STYLE_STORE_KEY];
27781
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
27782
27688
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
27783
27689
  }
27784
27690
  applyBrandChrome(content);
@@ -27789,12 +27695,12 @@ function OhhwellsBridge() {
27789
27695
  if (key === "__ohw_sections") continue;
27790
27696
  if (key === AI_SECTIONS_KEY) continue;
27791
27697
  if (key === AI_FOOTER_KEY) continue;
27792
- if (key === LOGO_PLACEHOLDER_KEY) continue;
27793
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
27794
27698
  if (key === BRAND_KIT_KEY) continue;
27795
27699
  if (key === STYLE_STORE_KEY) continue;
27796
27700
  if (BRAND_CHROME_KEYS.has(key)) continue;
27701
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
27797
27702
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
27703
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
27798
27704
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
27799
27705
  continue;
27800
27706
  }
@@ -28025,18 +27931,17 @@ function OhhwellsBridge() {
28025
27931
  }
28026
27932
  applyAiFooterFromContent(content);
28027
27933
  if (typeof content[STYLE_STORE_KEY] === "string") {
28028
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
28029
27934
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
28030
27935
  }
28031
27936
  for (const [key, val] of Object.entries(content)) {
28032
27937
  if (key === "__ohw_sections") continue;
28033
27938
  if (key === AI_SECTIONS_KEY) continue;
28034
27939
  if (key === AI_FOOTER_KEY) continue;
28035
- if (key === LOGO_PLACEHOLDER_KEY) continue;
28036
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
28037
27940
  if (key === BRAND_KIT_KEY) continue;
28038
27941
  if (key === STYLE_STORE_KEY) continue;
28039
27942
  if (BRAND_CHROME_KEYS.has(key)) continue;
27943
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
27944
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
28040
27945
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
28041
27946
  continue;
28042
27947
  }
@@ -28303,11 +28208,26 @@ function OhhwellsBridge() {
28303
28208
  const t2 = setTimeout(measure, 500);
28304
28209
  const ro = new ResizeObserver(schedule);
28305
28210
  ro.observe(document.body);
28211
+ let lastWidth = window.innerWidth;
28212
+ let resizeTimers = [];
28213
+ const clearResizeTimers = () => {
28214
+ resizeTimers.forEach(clearTimeout);
28215
+ resizeTimers = [];
28216
+ };
28217
+ const handleResize = () => {
28218
+ if (window.innerWidth === lastWidth) return;
28219
+ lastWidth = window.innerWidth;
28220
+ clearResizeTimers();
28221
+ resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
28222
+ };
28223
+ window.addEventListener("resize", handleResize);
28306
28224
  return () => {
28307
28225
  clearTimeout(t1);
28308
28226
  clearTimeout(t2);
28309
28227
  if (raf != null) cancelAnimationFrame(raf);
28310
28228
  ro.disconnect();
28229
+ clearResizeTimers();
28230
+ window.removeEventListener("resize", handleResize);
28311
28231
  };
28312
28232
  }, [pathname, isEditMode, postToParent2]);
28313
28233
  (0, import_react21.useEffect)(() => {
@@ -28604,13 +28524,6 @@ function OhhwellsBridge() {
28604
28524
  if (target.closest("[data-ohw-state-toggle]")) return;
28605
28525
  if (target.closest("[data-ohw-max-badge]")) return;
28606
28526
  if (isInsideLinkEditor(target)) return;
28607
- if (isInsideFloatingPanel(target)) return;
28608
- if (target.closest("[data-ohw-form-toolbar]")) return;
28609
- if (target.closest(
28610
- '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
28611
- )) {
28612
- return;
28613
- }
28614
28527
  if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
28615
28528
  clearMediaSelectionRef.current();
28616
28529
  }
@@ -28634,6 +28547,13 @@ function OhhwellsBridge() {
28634
28547
  return;
28635
28548
  }
28636
28549
  }
28550
+ if (isInsideFloatingPanel(target)) return;
28551
+ if (target.closest("[data-ohw-form-toolbar]")) return;
28552
+ if (target.closest(
28553
+ '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
28554
+ )) {
28555
+ return;
28556
+ }
28637
28557
  {
28638
28558
  const formEl = getFormElement(target);
28639
28559
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -28787,13 +28707,9 @@ function OhhwellsBridge() {
28787
28707
  if (isIconEditable(editable) && !getSocialItem(editable)) {
28788
28708
  e.preventDefault();
28789
28709
  e.stopPropagation();
28710
+ selectIconElementRef.current(editable);
28790
28711
  const aiIcon = editable.hasAttribute("data-ai-icon");
28791
28712
  const featureIcon = aiIcon && /\.features\.\d+\.icon$/.test(editable.dataset.ohwKey ?? "");
28792
- if (aiIcon) {
28793
- aiSectionApiRef.current?.selectFromElement(editable);
28794
- } else {
28795
- selectIconElementRef.current(editable);
28796
- }
28797
28713
  postToParentRef.current({
28798
28714
  type: "ow:icon-pick",
28799
28715
  key: editable.dataset.ohwKey ?? "",
@@ -29021,9 +28937,6 @@ function OhhwellsBridge() {
29021
28937
  setHoveredItemRect(null);
29022
28938
  hoveredNavContainerRef.current = null;
29023
28939
  setHoveredNavContainerRect(null);
29024
- siblingHintElRef.current = null;
29025
- setSiblingHintRect(null);
29026
- setSiblingHintRects([]);
29027
28940
  return;
29028
28941
  }
29029
28942
  {
@@ -29144,6 +29057,7 @@ function OhhwellsBridge() {
29144
29057
  hoveredNavContainerRef.current = null;
29145
29058
  setHoveredNavContainerRect(null);
29146
29059
  hoveredItemElRef.current = editable;
29060
+ setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
29147
29061
  }
29148
29062
  }
29149
29063
  }
@@ -29853,11 +29767,7 @@ function OhhwellsBridge() {
29853
29767
  };
29854
29768
  const handleMouseMove = (e) => {
29855
29769
  const { clientX, clientY } = e;
29856
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
29857
- dismissImageHover();
29858
- clearImageHover();
29859
- return;
29860
- }
29770
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
29861
29771
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
29862
29772
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
29863
29773
  formHoverElRef.current = null;
@@ -29886,12 +29796,7 @@ function OhhwellsBridge() {
29886
29796
  setHoveredItemRect(null);
29887
29797
  hoveredNavContainerRef.current = null;
29888
29798
  setHoveredNavContainerRect(null);
29889
- siblingHintElRef.current = null;
29890
- setSiblingHintRect(null);
29891
- setSiblingHintRects([]);
29892
29799
  dismissImageHover();
29893
- clearImageHover();
29894
- setSectionGap(null);
29895
29800
  return;
29896
29801
  }
29897
29802
  if (probeSocialsRowAt(clientX, clientY)) return;
@@ -29903,11 +29808,7 @@ function OhhwellsBridge() {
29903
29808
  if (e.data?.type !== "ow:pointer-sync") return;
29904
29809
  const { clientX, clientY } = e.data;
29905
29810
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
29906
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
29907
- dismissImageHover();
29908
- clearImageHover();
29909
- return;
29910
- }
29811
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
29911
29812
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
29912
29813
  if (probeSocialsRowAt(clientX, clientY)) return;
29913
29814
  probeSectionGapAt(clientX, clientY);
@@ -30287,7 +30188,6 @@ function OhhwellsBridge() {
30287
30188
  applyAiFooterFromContent(content);
30288
30189
  if (typeof content[STYLE_STORE_KEY] === "string") {
30289
30190
  stylesRef.current = content[STYLE_STORE_KEY];
30290
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
30291
30191
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
30292
30192
  }
30293
30193
  applyBrandChrome(content);
@@ -30302,12 +30202,12 @@ function OhhwellsBridge() {
30302
30202
  }
30303
30203
  if (key === AI_SECTIONS_KEY) continue;
30304
30204
  if (key === AI_FOOTER_KEY) continue;
30305
- if (key === LOGO_PLACEHOLDER_KEY) continue;
30306
- if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
30307
30205
  if (key === BRAND_KIT_KEY) continue;
30308
30206
  if (key === STYLE_STORE_KEY) continue;
30309
30207
  if (BRAND_CHROME_KEYS.has(key)) continue;
30208
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
30310
30209
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
30210
+ if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
30311
30211
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
30312
30212
  continue;
30313
30213
  }
@@ -30943,24 +30843,12 @@ function OhhwellsBridge() {
30943
30843
  closeLinkPopoverRef.current();
30944
30844
  return;
30945
30845
  }
30946
- if (floatingPanelOpenRef.current) {
30947
- setFloatingPanelRef.current(null);
30948
- deselectRef.current();
30949
- deactivateRef.current();
30950
- return;
30951
- }
30952
30846
  deselectRef.current();
30953
30847
  deactivateRef.current();
30954
30848
  clearMediaSelectionRef.current();
30955
30849
  clearIconSelectionRef.current();
30956
30850
  };
30957
30851
  window.addEventListener("message", handleDeactivate);
30958
- const handleSelectNav = (e) => {
30959
- if (e.data?.type !== "ow:select-nav") return;
30960
- const navContainer = findSelectableNavContainer();
30961
- if (navContainer) selectFrameRef.current(navContainer);
30962
- };
30963
- window.addEventListener("message", handleSelectNav);
30964
30852
  const handleToastAction = (e) => {
30965
30853
  if (e.data?.type !== "ow:toast-action") return;
30966
30854
  const actionId = typeof e.data.actionId === "string" ? e.data.actionId : null;
@@ -31777,11 +31665,10 @@ function OhhwellsBridge() {
31777
31665
  window.removeEventListener("message", handleDeleteSection);
31778
31666
  window.removeEventListener("message", handleDuplicateSection);
31779
31667
  window.removeEventListener("message", handleDeactivate);
31780
- window.removeEventListener("message", handleSelectNav);
31668
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
31781
31669
  window.removeEventListener("message", handleToastAction);
31782
31670
  window.removeEventListener("message", handleFormCount);
31783
31671
  window.removeEventListener("message", handleUiEscape);
31784
- document.documentElement.removeAttribute("data-ohw-panel-dragging");
31785
31672
  autoSaveTimers.current.forEach(clearTimeout);
31786
31673
  autoSaveTimers.current.clear();
31787
31674
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
@@ -32075,7 +31962,7 @@ function OhhwellsBridge() {
32075
31962
  postToParent2({
32076
31963
  type: "ow:ready",
32077
31964
  version: "1",
32078
- bridgeVersion: "0.1.152-next.410",
31965
+ bridgeVersion: "0.1.153",
32079
31966
  path: pathname,
32080
31967
  nodes: collectEditableNodes(editContentRef.current),
32081
31968
  sections