/* Starboard · Overlays v2
   DialogV2 (+Header/Body/Footer slots), AlertDialog, Sheet, Drawer,
   Menu core (AdMenuList), DropdownMenu, ContextMenu, Menubar,
   TooltipV2, PopoverV2, HoverCardV2.
   Requires a11y.js + position.js. Load with:
     <script type="text/babel" src="OverlaysV2.jsx"></script>
   Note: exported as DialogV2 / TooltipV2 / PopoverV2 / HoverCardV2
   so the v1 announcement Dialog and Overlays.jsx globals survive. */

/* ─── Shared SVG bits ─── */
const AdOvIconClose = () => (
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
       strokeWidth="2" strokeLinecap="round" aria-hidden="true"><path d="m18 6-12 12M6 6l12 12" /></svg>
);
const AdOvIconCaretRight = ({ className }) => (
  <svg className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor"
       strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="m9 6 6 6-6 6" /></svg>
);
const AdOvIconCheck = () => (
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
       strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="m4.5 12.5 5 5 10-11" /></svg>
);
const AdOvIconAlert = () => (
  <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
       strokeWidth="2" strokeLinecap="round" aria-hidden="true">
    <path d="M12 9v4m0 4h.01" /><path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z" />
  </svg>
);

/* ─── Exit choreography helper ───
   Keeps the node mounted through a `.is-closing` pass that replays
   the enter keyframe in reverse over the exit duration, then
   unmounts. Skipped entirely under prefers-reduced-motion. */
const adUseExitStage = (open, exitMs = 160) => {
  const [stage, setStage] = React.useState(open ? 'open' : 'closed');
  React.useEffect(() => {
    if (open) { setStage('open'); return; }
    setStage((prev) => {
      if (prev === 'closed') return prev;
      return adPrefersReducedMotion() ? 'closed' : 'closing';
    });
  }, [open]);
  React.useEffect(() => {
    if (stage !== 'closing') return;
    const t = setTimeout(() => setStage('closed'), exitMs);
    return () => clearTimeout(t);
  }, [stage]);
  return stage; /* 'open' | 'closing' | 'closed' */
};

/* ═══ Dialog ═══
   Controlled open/onOpenChange. size="sm"|"md"|"lg" → 430/560/720.
   Scrim from navy-black; Esc always dismisses, scrim click only
   when `dismissible`. Compose with DialogHeader/Body/Footer. */
const DialogV2 = ({
  open, onOpenChange, size = 'md', dismissible = true,
  role = 'dialog', labelledBy, describedBy, initialFocus, children, className = '',
}) => {
  const stage = adUseExitStage(open, 160);
  const panelRef = React.useRef(null);
  const mounted = stage !== 'closed';
  adUseScrollLock(mounted);
  adUseFocusTrap(panelRef, !!open, { initialFocus });
  adUseDismiss(panelRef, !!open, () => onOpenChange && onOpenChange(false), { outsideClick: dismissible, escape: true });
  if (!mounted) return null;
  const closing = stage === 'closing' ? ' is-closing' : '';
  return (
    <div className={`ad-dlg-scrim${closing}`}>
      <div
        ref={panelRef}
        role={role}
        aria-modal="true"
        aria-labelledby={labelledBy}
        aria-describedby={describedBy}
        className={`ad-dlg ad-dlg--${size}${closing} ${className}`}
      >
        {children}
      </div>
    </div>
  );
};

const DialogHeader = ({ title, description, icon, danger, onClose, titleId, descriptionId }) => (
  <div className="ad-dlg__head">
    {icon && <span className={`ad-dlg__badge${danger ? ' ad-dlg__badge--danger' : ''}`} aria-hidden="true">{icon}</span>}
    <div className="ad-dlg__heading">
      <h2 className="ad-dlg__title" id={titleId}>{title}</h2>
      {description && <p className="ad-dlg__desc" id={descriptionId}>{description}</p>}
    </div>
    {onClose && (
      <button type="button" className="ad-dlg__close" aria-label="Close dialog" onClick={onClose}><AdOvIconClose /></button>
    )}
  </div>
);

const DialogBody = ({ maxHeight, children, className = '' }) => (
  <ScrollArea maxHeight={maxHeight} className={`ad-dlg__body ${className}`}>{children}</ScrollArea>
);

const DialogFooter = ({ children, className = '' }) => (
  <div className={`ad-dlg__foot ${className}`}>{children}</div>
);

/* ═══ AlertDialog ═══
   role="alertdialog", never dismisses on scrim click, initial focus
   lands on Cancel. destructive → error badge + danger confirm. */
const AlertDialog = ({
  open, onOpenChange, title, description, destructive,
  confirmLabel = 'Confirm', cancelLabel = 'Cancel', onConfirm, children,
}) => {
  const titleId = adUseId('adlg-title');
  const descId = adUseId('adlg-desc');
  const close = () => onOpenChange && onOpenChange(false);
  return (
    <DialogV2
      open={open}
      onOpenChange={onOpenChange}
      role="alertdialog"
      size="sm"
      dismissible={false}
      labelledBy={titleId}
      describedBy={description ? descId : undefined}
      initialFocus=".ad-dlg__cancel"
    >
      <DialogHeader
        title={title}
        description={description}
        titleId={titleId}
        descriptionId={descId}
        danger={destructive}
        icon={destructive ? <AdOvIconAlert /> : undefined}
      />
      {children && <div className="ad-dlg__body">{children}</div>}
      <DialogFooter>
        <button type="button" className="ad-btn ad-btn--ghost ad-dlg__cancel" onClick={close}>{cancelLabel}</button>
        <button
          type="button"
          className={`ad-btn ${destructive ? 'ad-btn--danger' : 'ad-btn--primary'}`}
          onClick={() => { if (onConfirm) onConfirm(); close(); }}
        >
          {confirmLabel}
        </button>
      </DialogFooter>
    </DialogV2>
  );
};

/* ═══ Sheet ═══
   side="right"|"left"|"bottom". Same trap/lock/dismiss as Dialog,
   slides on --motion-panel-slide, exits faster. */
const Sheet = ({
  open, onOpenChange, side = 'right', title, footer,
  dismissible = true, initialFocus, children, className = '',
}) => {
  const stage = adUseExitStage(open, 160);
  const panelRef = React.useRef(null);
  const titleId = adUseId('sheet-title');
  const mounted = stage !== 'closed';
  adUseScrollLock(mounted);
  adUseFocusTrap(panelRef, !!open, { initialFocus });
  adUseDismiss(panelRef, !!open, () => onOpenChange && onOpenChange(false), { outsideClick: dismissible, escape: true });
  if (!mounted) return null;
  const closing = stage === 'closing' ? ' is-closing' : '';
  return (
    <React.Fragment>
      <div className={`ad-sheet-scrim${closing}`} />
      <div
        ref={panelRef}
        role="dialog"
        aria-modal="true"
        aria-labelledby={titleId}
        className={`ad-sheet ad-sheet--${side}${closing} ${className}`}
      >
        <div className="ad-sheet__head">
          <h2 className="ad-sheet__title" id={titleId}>{title}</h2>
          <button type="button" className="ad-sheet__close" aria-label="Close panel" onClick={() => onOpenChange && onOpenChange(false)}>
            <AdOvIconClose />
          </button>
        </div>
        <div className="ad-sheet__body ad-scroll">{children}</div>
        {footer && <div className="ad-sheet__foot">{footer}</div>}
      </div>
    </React.Fragment>
  );
};

/* ═══ Drawer ═══
   Sheet side="left" specialised for app navigation: 280px,
   icon + label + count rows in labeled groups. */
const Drawer = ({ open, onOpenChange, title = 'Navigation', groups = [], footer }) => (
  <Sheet open={open} onOpenChange={onOpenChange} side="left" title={title} footer={footer} className="ad-drawer">
    <nav className="ad-drawer__nav" aria-label={title}>
      {groups.map((group, gi) => (
        <div className="ad-drawer__group" key={gi}>
          {group.label && <div className="ad-drawer__group-label">{group.label}</div>}
          {group.items.map((item, ii) => (
            <a
              key={ii}
              href={item.href || '#'}
              className={`ad-drawer__row${item.active ? ' is-active' : ''}`}
              aria-current={item.active ? 'page' : undefined}
              onClick={(e) => { if (item.onClick) { e.preventDefault(); item.onClick(item); } }}
            >
              {item.icon && <span className="ad-drawer__icon" aria-hidden="true">{item.icon}</span>}
              <span className="ad-drawer__label">{item.label}</span>
              {item.count != null && <span className="ad-drawer__count">{item.count}</span>}
            </a>
          ))}
        </div>
      ))}
    </nav>
  </Sheet>
);

/* ═══ Menu core ═══
   items = [{ label, icon?, description?, shortcut?, danger?,
   disabled?, checked? (→ menuitemcheckbox), role?, items? (submenu),
   onSelect? } | { type:'separator' } | { type:'label', label }].
   Down/Up/Home/End roving highlight, typeahead, Enter/Space
   activates, ArrowRight opens submenu (200ms hover intent),
   ArrowLeft closes it. Disabled items are skipped. */
const AdMenuList = ({ items = [], depth = 0, closeAll, onBack, onArrowHorizontal, labelId, style, autoFocus = true }) => {
  const ref = React.useRef(null);
  const enabledIdx = items
    .map((it, i) => i)
    .filter((i) => { const it = items[i]; return it.type !== 'separator' && it.type !== 'label' && !it.disabled; });
  const [hi, setHi] = React.useState(enabledIdx.length ? enabledIdx[0] : -1);
  const [subOpen, setSubOpen] = React.useState(null);
  const intent = React.useRef(null);

  React.useEffect(() => {
    if (autoFocus && ref.current) ref.current.focus({ preventScroll: true });
    return () => clearTimeout(intent.current);
  }, []);

  const typeahead = adUseTypeahead(
    items.map((it) => (it.type === 'separator' || it.type === 'label' || it.disabled) ? ' ' : (it.label || '')),
    (i) => setHi(i)
  );

  const step = (cur, dir) => {
    const n = enabledIdx.length;
    if (!n) return cur;
    const pos = enabledIdx.indexOf(cur);
    if (pos === -1) return dir > 0 ? enabledIdx[0] : enabledIdx[n - 1];
    return enabledIdx[(pos + dir + n) % n];
  };

  const activate = (i) => {
    const it = items[i];
    if (!it || it.disabled) return;
    if (it.items) { setSubOpen(i); return; }
    if (it.onSelect) it.onSelect(it);
    if (closeAll) closeAll();
  };

  const onKeyDown = (e) => {
    e.stopPropagation();
    if (e.key === 'ArrowDown') { e.preventDefault(); setHi((h) => step(h, 1)); }
    else if (e.key === 'ArrowUp') { e.preventDefault(); setHi((h) => step(h, -1)); }
    else if (e.key === 'Home') { e.preventDefault(); setHi(enabledIdx.length ? enabledIdx[0] : -1); }
    else if (e.key === 'End') { e.preventDefault(); setHi(enabledIdx.length ? enabledIdx[enabledIdx.length - 1] : -1); }
    else if (e.key === 'ArrowRight') {
      const it = items[hi];
      if (it && it.items) { e.preventDefault(); setSubOpen(hi); }
      else if (onArrowHorizontal) { e.preventDefault(); onArrowHorizontal(1); }
    } else if (e.key === 'ArrowLeft') {
      if (onBack) { e.preventDefault(); onBack(); }
      else if (onArrowHorizontal) { e.preventDefault(); onArrowHorizontal(-1); }
    } else if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); activate(hi); }
    else typeahead(e);
  };

  return (
    <div ref={ref} role="menu" tabIndex={-1} aria-labelledby={labelId}
         className="ad-menu2" style={style} onKeyDown={onKeyDown}>
      {items.map((it, i) => {
        if (it.type === 'separator') return <div key={i} className="ad-menu2__sep" role="separator" />;
        if (it.type === 'label') return <div key={i} className="ad-menu2__group-label" role="presentation">{it.label}</div>;
        const hasSub = !!it.items;
        const role = it.role || (it.checked !== undefined ? 'menuitemcheckbox' : 'menuitem');
        return (
          <div
            key={i}
            role={role}
            aria-checked={it.checked !== undefined ? !!it.checked : undefined}
            aria-disabled={it.disabled || undefined}
            aria-haspopup={hasSub ? 'menu' : undefined}
            aria-expanded={hasSub ? subOpen === i : undefined}
            className={`ad-menu2__item${it.danger ? ' ad-menu2__item--danger' : ''}${hi === i && !it.disabled ? ' is-highlighted' : ''}`}
            onMouseEnter={() => {
              if (it.disabled) return;
              setHi(i);
              clearTimeout(intent.current);
              intent.current = setTimeout(() => setSubOpen(hasSub ? i : null), 200);
            }}
            onClick={(e) => { e.stopPropagation(); activate(i); }}
          >
            {it.checked !== undefined
              ? <span className="ad-menu2__icon">{it.checked ? <AdOvIconCheck /> : null}</span>
              : (it.icon ? <span className="ad-menu2__icon" aria-hidden="true">{it.icon}</span> : null)}
            <span className="ad-menu2__text">
              <span className="ad-menu2__label">{it.label}</span>
              {it.description && <span className="ad-menu2__desc">{it.description}</span>}
            </span>
            {it.shortcut && <span className="ad-menu2__shortcut" aria-hidden="true">{it.shortcut}</span>}
            {hasSub && <AdOvIconCaretRight className="ad-menu2__caret" />}
            {hasSub && subOpen === i && (
              <div className="ad-menu2__sub">
                <AdMenuList
                  items={it.items}
                  depth={depth + 1}
                  closeAll={closeAll}
                  onBack={() => {
                    setSubOpen(null);
                    if (ref.current) ref.current.focus({ preventScroll: true });
                  }}
                />
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
};

/* ═══ DropdownMenu ═══ */
const DropdownMenu = ({ label, trigger, items = [], placement = 'bottom-start', className = '' }) => {
  const [open, setOpen] = React.useState(false);
  const anchorRef = React.useRef(null);
  const floatRef = React.useRef(null);
  const triggerId = adUseId('ddm');
  const { style, placement: place } = adUseAnchorPosition(anchorRef, floatRef, open, { placement, offset: 6 });
  const close = () => {
    setOpen(false);
    if (anchorRef.current) anchorRef.current.focus({ preventScroll: true });
  };
  adUseDismiss(floatRef, open, close);
  return (
    <React.Fragment>
      <button
        type="button"
        ref={anchorRef}
        id={triggerId}
        className={`ad-btn ad-btn--ghost ad-btn--sm ${className}`}
        aria-haspopup="menu"
        aria-expanded={open}
        onClick={() => setOpen((o) => !o)}
        onKeyDown={(e) => { if (e.key === 'ArrowDown' || e.key === 'ArrowUp') { e.preventDefault(); setOpen(true); } }}
      >
        {trigger || label}
        <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
      </button>
      {open && (
        <div ref={floatRef} style={style} data-placement={place}>
          <AdMenuList items={items} closeAll={close} labelId={triggerId} />
        </div>
      )}
    </React.Fragment>
  );
};

/* ═══ ContextMenu ═══
   Opens the menu core at pointer coordinates, clamped to viewport. */
const ContextMenu = ({ items = [], children, className = '' }) => {
  const [pos, setPos] = React.useState(null);
  const floatRef = React.useRef(null);
  const close = () => setPos(null);
  adUseDismiss(floatRef, !!pos, close);
  React.useLayoutEffect(() => {
    if (!pos || !floatRef.current) return;
    const r = floatRef.current.getBoundingClientRect();
    const vw = document.documentElement.clientWidth;
    const vh = document.documentElement.clientHeight;
    const x = Math.max(8, Math.min(pos.x, vw - r.width - 8));
    const y = Math.max(8, Math.min(pos.y, vh - r.height - 8));
    if (x !== pos.x || y !== pos.y) setPos({ x, y });
  }, [pos && pos.x, pos && pos.y]);
  return (
    <div
      className={className}
      onContextMenu={(e) => { e.preventDefault(); setPos({ x: e.clientX, y: e.clientY }); }}
    >
      {children}
      {pos && (
        <div ref={floatRef} style={{ position: 'fixed', left: pos.x, top: pos.y, zIndex: 80 }}>
          <AdMenuList items={items} closeAll={close} />
        </div>
      )}
    </div>
  );
};

/* ═══ Menubar ═══
   menus = [{ label, items }]. Left/Right move between top-level
   triggers; while a menu is open, arrow movement and hover both
   carry the open state along. Down/Enter/Space opens. */
const Menubar = ({ menus = [], className = '' }) => {
  const [openIndex, setOpenIndex] = React.useState(null);
  const [focusIndex, setFocusIndex] = React.useState(0);
  const btnRefs = React.useRef([]);
  const barRef = React.useRef(null);
  adUseDismiss(barRef, openIndex != null, () => setOpenIndex(null));

  const moveTo = (i, keepOpen) => {
    const n = menus.length;
    const j = ((i % n) + n) % n;
    setFocusIndex(j);
    if (keepOpen) setOpenIndex(j);
    else if (btnRefs.current[j]) btnRefs.current[j].focus();
  };

  return (
    <div ref={barRef} role="menubar" className={`ad-menubar ${className}`}>
      {menus.map((menu, i) => (
        <div key={i} className="ad-menubar__wrap">
          <button
            type="button"
            ref={(el) => { btnRefs.current[i] = el; }}
            role="menuitem"
            aria-haspopup="menu"
            aria-expanded={openIndex === i}
            tabIndex={i === focusIndex ? 0 : -1}
            className={`ad-menubar__trigger${openIndex === i ? ' is-open' : ''}`}
            onClick={() => setOpenIndex(openIndex === i ? null : i)}
            onMouseEnter={() => { if (openIndex != null && openIndex !== i) { setFocusIndex(i); setOpenIndex(i); } }}
            onFocus={() => setFocusIndex(i)}
            onKeyDown={(e) => {
              if (e.key === 'ArrowRight') { e.preventDefault(); moveTo(i + 1, openIndex != null); }
              else if (e.key === 'ArrowLeft') { e.preventDefault(); moveTo(i - 1, openIndex != null); }
              else if (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setOpenIndex(i); }
              else if (e.key === 'Escape') setOpenIndex(null);
            }}
          >
            {menu.label}
          </button>
          {openIndex === i && (
            <div className="ad-menubar__panel" data-placement="bottom-start">
              <AdMenuList
                items={menu.items}
                closeAll={() => {
                  setOpenIndex(null);
                  if (btnRefs.current[i]) btnRefs.current[i].focus();
                }}
                onArrowHorizontal={(dir) => moveTo(i + dir, true)}
              />
            </div>
          )}
        </div>
      ))}
    </div>
  );
};

/* ═══ Tooltip v2 ═══
   200ms show delay shared across all tooltips — moving between
   adjacent triggers while "warm" shows instantly. Shows on
   focus-visible. role="tooltip" + aria-describedby wiring. */
const adTipV2Shared = { warm: false, timer: null };

const TooltipV2 = ({ content, shortcut, placement = 'top', children }) => {
  const [open, setOpen] = React.useState(false);
  const [shown, setShown] = React.useState(false);
  const anchorRef = React.useRef(null);
  const floatRef = React.useRef(null);
  const tipId = adUseId('tip2');
  const { style, placement: place, arrowStyle } = adUseAnchorPosition(anchorRef, floatRef, open, { placement, offset: 8 });

  const show = () => {
    clearTimeout(adTipV2Shared.timer);
    if (adTipV2Shared.warm || adPrefersReducedMotion()) setOpen(true);
    else adTipV2Shared.timer = setTimeout(() => { adTipV2Shared.warm = true; setOpen(true); }, 200);
  };
  const hide = () => {
    clearTimeout(adTipV2Shared.timer);
    setOpen(false);
    adTipV2Shared.timer = setTimeout(() => { adTipV2Shared.warm = false; }, 300);
  };

  React.useEffect(() => {
    if (!open) { setShown(false); return; }
    adTipV2Shared.warm = true;
    const raf = requestAnimationFrame(() => requestAnimationFrame(() => setShown(true)));
    return () => cancelAnimationFrame(raf);
  }, [open]);

  const child = React.isValidElement(children)
    ? React.cloneElement(children, { 'aria-describedby': open ? tipId : children.props['aria-describedby'] })
    : children;

  return (
    <span
      style={{ display: 'inline-flex' }}
      onMouseEnter={show}
      onMouseLeave={hide}
      onFocus={(e) => { if (!e.target.matches || e.target.matches(':focus-visible')) show(); }}
      onBlur={hide}
    >
      {child}
      {open && (
        <span
          ref={floatRef}
          role="tooltip"
          id={tipId}
          className={`ad-tip2${shown ? ' is-shown' : ''}`}
          style={style}
          data-side={(place || 'top').split('-')[0]}
        >
          {content}
          {shortcut && <span className="ad-tip2__shortcut">{shortcut}</span>}
          <span className="ad-tip2__arrow" style={arrowStyle} aria-hidden="true" />
        </span>
      )}
    </span>
  );
};

/* ═══ Popover v2 ═══
   Anchored panel with bordered arrow, focus moves in, Esc/outside
   dismiss returns focus to the trigger. */
const PopoverV2 = ({
  open: openProp, onOpenChange, trigger, title, subtitle, footer,
  placement = 'bottom', children, className = '',
}) => {
  const controlled = openProp !== undefined;
  const [openState, setOpenState] = React.useState(false);
  const open = controlled ? openProp : openState;
  const setOpen = (v) => {
    if (!controlled) setOpenState(v);
    if (onOpenChange) onOpenChange(v);
  };
  const anchorRef = React.useRef(null);
  const floatRef = React.useRef(null);
  const titleId = adUseId('pop2-title');
  const { style, placement: place, arrowStyle } = adUseAnchorPosition(anchorRef, floatRef, open, { placement, offset: 10 });
  const close = () => {
    setOpen(false);
    const el = anchorRef.current && anchorRef.current.querySelector(AD_FOCUSABLE);
    if (el) el.focus({ preventScroll: true });
  };
  adUseFocusTrap(floatRef, open);
  adUseDismiss(floatRef, open, close);
  return (
    <React.Fragment>
      <span ref={anchorRef} style={{ display: 'inline-flex' }} onClick={() => setOpen(!open)}>{trigger}</span>
      {open && (
        <div
          ref={floatRef}
          role="dialog"
          aria-labelledby={title ? titleId : undefined}
          className={`ad-pop2 ${className}`}
          style={style}
          data-side={(place || 'bottom').split('-')[0]}
        >
          {(title || subtitle) && (
            <div className="ad-pop2__head">
              <div>
                {title && <div className="ad-pop2__title" id={titleId}>{title}</div>}
                {subtitle && <div className="ad-pop2__sub">{subtitle}</div>}
              </div>
              <button type="button" className="ad-pop2__close" aria-label="Close popover" onClick={close}><AdOvIconClose /></button>
            </div>
          )}
          <div className="ad-pop2__body">{children}</div>
          {footer && <div className="ad-pop2__foot">{footer}</div>}
          <span className="ad-pop2__arrow" style={arrowStyle} aria-hidden="true" />
        </div>
      )}
    </React.Fragment>
  );
};

/* ═══ HoverCard v2 ═══
   350ms open intent, 300ms close grace — pointer can cross the gap
   into the card without it collapsing. */
const HoverCardV2 = ({ trigger, placement = 'bottom-start', openDelay = 350, closeDelay = 300, children }) => {
  const [open, setOpen] = React.useState(false);
  const timers = React.useRef({});
  const anchorRef = React.useRef(null);
  const floatRef = React.useRef(null);
  const { style, placement: place } = adUseAnchorPosition(anchorRef, floatRef, open, { placement, offset: 8 });
  const scheduleOpen = () => {
    clearTimeout(timers.current.close);
    timers.current.open = setTimeout(() => setOpen(true), openDelay);
  };
  const scheduleClose = () => {
    clearTimeout(timers.current.open);
    timers.current.close = setTimeout(() => setOpen(false), closeDelay);
  };
  React.useEffect(() => () => { clearTimeout(timers.current.open); clearTimeout(timers.current.close); }, []);
  return (
    <React.Fragment>
      <span
        ref={anchorRef}
        style={{ display: 'inline-flex' }}
        onMouseEnter={scheduleOpen}
        onMouseLeave={scheduleClose}
        onFocus={scheduleOpen}
        onBlur={scheduleClose}
      >
        {trigger}
      </span>
      {open && (
        <div
          ref={floatRef}
          className="ad-hcard2"
          style={style}
          data-placement={place}
          onMouseEnter={() => clearTimeout(timers.current.close)}
          onMouseLeave={scheduleClose}
        >
          {children}
        </div>
      )}
    </React.Fragment>
  );
};

Object.assign(window, {
  DialogV2, DialogHeader, DialogBody, DialogFooter, AlertDialog,
  Sheet, Drawer, AdMenuList, DropdownMenu, ContextMenu, Menubar,
  TooltipV2, PopoverV2, HoverCardV2, adUseExitStage,
});
