/**
 * Impeccable Live Variant Mode - Browser Script
 *
 * Injected into the user's page via <script src="http://localhost:PORT/live.js">.
 * The server prepends window.__IMPECCABLE_TOKEN__ and window.__IMPECCABLE_PORT__
 * before this code.
 *
 * UI: a single floating bar that morphs between three states -
 * configure (pick action + go), generating (progressive dots), and cycling
 * (prev/next + accept/discard). Feels like Spotlight, not a modal.
 */
(function () {
  'use strict';
  if (typeof window === 'undefined') return;

  // Guard against double-init. Bun's HTML loader may process the <script> tag
  // and create a bundled copy alongside the external load, or HMR may re-execute.
  // Check BEFORE reading token/port to catch all cases.
  if (window.__IMPECCABLE_LIVE_INIT__) return;
  window.__IMPECCABLE_LIVE_INIT__ = true;

  const TOKEN = window.__IMPECCABLE_TOKEN__;
  const PORT = window.__IMPECCABLE_PORT__;
  const APP_ROOT = window.__IMPECCABLE_APP_ROOT__ || null;
  if (!TOKEN || !PORT) {
    window.__IMPECCABLE_LIVE_INIT__ = false; // reset so the real load can init
    return;
  }

  //
  // Design tokens
  //

  // Brand kinpaku (gold) is pinned to the site's neo-kinpaku tokens
  // (see site/styles/kinpaku-tokens.css) so Accept / knobs / cycle-dots /
  // the selection outline / the comment tag all match the site's accent,
  // not a washed theme-adjusted one. These mirror the kit's picker
  // colors in site/styles/kinpaku-kit.css; keep them in sync by hand.
  const C = {
    brand:     'oklch(84% 0.19 80.46)',         // kinpaku gold
    brandHov:  'oklch(86% 0.07 84)',            // kinpaku-pale (hover lift)
    brandSoft: 'oklch(84% 0.19 80.46 / 0.18)',  // kinpaku-dim
    ink:       'oklch(4% 0.004 95)',            // lacquer-deep
    ash:       'oklch(55% 0.018 82)',           // warm muted text
    paper:     'oklch(98% 0.005 95 / 0.92)',    // light overlay on user pages
    paperSolid:'oklch(98% 0.005 95)',
    mist:      'oklch(90% 0.008 82 / 0.6)',     // light hairline
    white:     'oklch(99% 0 0)',
  };
  // Picker bar chrome - mirrors .live-demo-gbar / .live-demo-ctx in kinpaku-kit.css.
  // Quiet neutral elevation: no gold halo ring (gold is reserved for the brand
  // mark and the active control, not the container outline).
  const PICKER_SHADOW =
    '0 16px 36px -12px oklch(0% 0 0 / 0.6)';
  const FONT = 'system-ui, -apple-system, sans-serif';
  const MONO = 'ui-monospace, SFMono-Regular, Menlo, monospace';
  // z-index: detect overlays use 99999, so our UI must be above them
  const Z = { highlight: 100001, bar: 100005, picker: 100007, toast: 100010 };
  const EASE = 'cubic-bezier(0.22, 1, 0.36, 1)'; // ease-out-quint
  const PREFIX = 'impeccable-live';
  const IMPECCABLE_COMMAND = (window.__IMPECCABLE_COMMAND_PREFIX__ || '/') + 'impeccable';
  const PICK_CURSOR_STYLE_ID = PREFIX + '-pick-cursor-style';
  const MANUAL_APPLY_STATE_TTL_MS = 15 * 60 * 1000;
  const sessionState = window.__IMPECCABLE_LIVE_SESSION__?.createLiveBrowserSessionState({
    prefix: PREFIX,
    storage: localStorage,
    idFactory: () => crypto.randomUUID().replace(/-/g, '').slice(0, 8),
  });
  if (!sessionState) {
    console.error('[impeccable] live-browser-session.js was not loaded. Live mode cannot start safely.');
    window.__IMPECCABLE_LIVE_INIT__ = false;
    return;
  }
  const HIGHLIGHT_TRANSITION =
    'top 140ms ' + EASE +
    ', left 140ms ' + EASE +
    ', width 140ms ' + EASE +
    ', height 140ms ' + EASE +
    ', opacity 150ms ease';
  const TOOLTIP_TRANSITION =
    'top 140ms ' + EASE + ', left 140ms ' + EASE + ', opacity 150ms ease';

  const SKIP_TAGS = new Set([
    'html', 'head', 'body', 'script', 'style', 'link', 'meta', 'noscript', 'br', 'wbr',
  ]);

  // Command vocabulary (values + labels + icons) comes from the canonical source,
  // skill/scripts/live/vocabulary.mjs, which live-server.mjs serializes into
  // window.__IMPECCABLE_VOCAB__ when it serves /live.js (same injection path as
  // the token/port above, so it is always present here). The icons stack above
  // each chip label and recolor to C.brand when selected (strokes use
  // currentColor). ACTIONS drives the picker grid; ICONS maps value -> svg.
  const VOCAB = Array.isArray(window.__IMPECCABLE_VOCAB__) ? window.__IMPECCABLE_VOCAB__ : [];
  const ICONS = {};
  const ACTIONS = VOCAB.map((c) => {
    ICONS[c.value] = c.icon;
    return { value: c.value, label: c.label };
  });

  const LIVE_CHROME_MOUNT_CONTRACT = ['root', 'transport', 'state', 'actions'];
  const LIVE_UI_SURFACES = [
    { key: 'global-bottom-bar', ids: [PREFIX + '-global-bar', PREFIX + '-global-bar-brand', PREFIX + '-pick-toggle', PREFIX + '-insert-toggle', PREFIX + '-detect-toggle', PREFIX + '-detect-badge', PREFIX + '-design-toggle', PREFIX + '-page-chat', PREFIX + '-page-chat-input', PREFIX + '-page-chat-voice', PREFIX + '-page-chat-send'] },
    { key: 'pending-copy-edit-dock', ids: [PREFIX + '-pending-dock'] },
    { key: 'element-selection-chrome', ids: [PREFIX + '-highlight', PREFIX + '-tooltip', PREFIX + '-bar', PREFIX + '-selection-pill', PREFIX + '-input', PREFIX + '-configure-voice', PREFIX + '-configure-bar-tooltip'] },
    { key: 'action-picker', ids: [PREFIX + '-picker'] },
    { key: 'edit-chrome', ids: [PREFIX + '-edit-badge'] },
    { key: 'generating-row', ids: [PREFIX + '-bar', PREFIX + '-shader'] },
    { key: 'variant-cycling-row', ids: [PREFIX + '-bar', PREFIX + '-params-panel'] },
    { key: 'variant-params-panel', ids: [PREFIX + '-params-panel'] },
    { key: 'saving-confirmed-rows', ids: [PREFIX + '-bar'] },
    { key: 'insert-mode-chrome', ids: [PREFIX + '-insert-line', PREFIX + '-insert-placeholder', PREFIX + '-placeholder-resize', PREFIX + '-insert-input', PREFIX + '-insert-voice', PREFIX + '-insert-create', PREFIX + '-insert-create-tooltip'] },
    { key: 'annotation-chrome', ids: [PREFIX + '-annot', PREFIX + '-annot-svg', PREFIX + '-annot-pins', PREFIX + '-annot-clear'] },
    { key: 'design-system-panel', ids: [PREFIX + '-design-host'] },
    { key: 'toasts-and-errors', ids: [PREFIX + '-toast', PREFIX + '-mount-error'] },
    { key: 'css-isolation-boundary', ids: [PREFIX + '-root'] },
  ];
  const LIVE_UI_COMPONENT_IDS = [...new Set(LIVE_UI_SURFACES.flatMap((surface) => surface.ids))];

  //
  // State
  //

  let state = 'IDLE';
  let hoveredElement = null;
  let selectedElement = null;
  let currentSessionId = null;
  let expectedVariants = 0;
  let arrivedVariants = 0;
  let visibleVariant = 0;
  let generationPhase = null;
  // Ascending order of the agent-generation lifecycle. The visible progress bar
  // must never regress: a `browser_resumed`/behind checkpoint re-broadcasts an
  // earlier phase (the server regresses the snapshot phase to `generating` on a
  // behind checkpoint), and without this the bar jumps backward mid-generation.
  // Unranked phases always pass so we never block a phase we do not model.
  //
  // Every `agent_phase` name here is emitted by recordAgentPhase() in
  // live-server.mjs and listed in AGENT_PHASES in live/vocabulary.mjs, which the
  // event validator enforces. This file is served raw and injected as an IIFE,
  // so it cannot import that list; adding a phase means adding it in both.
  // `queued`, `generating`, `variants_progress`, and `variants_ready` are set
  // locally by this file and never arrive over the wire.
  const PHASE_RANK = {
    queued: 0,
    picked_up: 1,
    scaffolding: 2,
    scaffold_fallback: 3,
    source_ready: 4,
    generation_ready: 5,
    generating: 5,
    variants_progress: 5,
    first_reviewable: 8,
    second_reviewable: 11,
    all_variants_ready: 12,
    variants_ready: 12,
  };
  function shouldAdvancePhase(current, next) {
    if (!next || next === current) return false;
    const nextRank = PHASE_RANK[next];
    const currentRank = PHASE_RANK[current];
    // Only block a known-lower phase from overwriting a known-higher one.
    if (nextRank === undefined || currentRank === undefined) return true;
    return nextRank >= currentRank;
  }
  let parameterGenerationState = 'idle';
  let parameterReadyAnnouncedSession = null;
  let svelteComponentSession = null;
  let svelteRuntimePromise = null;
  let pendingSvelteComponentRetryObserver = null;
  // The persistent mount-error card. A failed import/mount used to wipe local
  // session state and flash a 5s toast, which destroyed the only handle the
  // user had on a session the server still considered live. The card stays up
  // until the variant mounts, the user retries, or a new cycle starts.
  let mountErrorEl = null;
  let mountErrorState = null;
  let lastReportedMountFailure = null;
  let currentSourceFile = null;
  let currentPreviewFile = null;
  let currentPreviewMode = null;
  let recoveryWaitingForAnchor = false;
  let pickedAnchorSnapshot = null;
  let pickedAnchorViewportTop = null;
  let pendingVariantAnchorRetryObserver = null;
  let pendingAcceptedSession = null;
  // Survives cleanupAcceptedSession on purpose: the id of an accept whose
  // POST was acknowledged (intent durable, epoch fenced) but whose actual
  // source promotion hasn't reported back yet. Accept is optimistic, so the
  // teardown nulls pendingAcceptedSession long before live-accept.mjs runs;
  // this marker is what lets the SSE 'error' branch still recognize a late
  // accept failure and say the variant was not saved (issue #384). Released
  // when the real accept result arrives or a new session starts.
  let awaitingAcceptResult = null;
  let variantObserver = null;
  let variantSelectionInFlight = false;
  let variantSelectionPromise = null;
  let recoveringEmptyCycling = false;
  let hasProjectContext = false;
  let selectedAction = 'impeccable';
  let selectedCount = 3;
  const browserOwner = sessionState.owner;
  let checkpointTimer = null;

  // Scroll lock - holds window.scrollY at a fixed value while the session is
  // active, so HMR DOM patches and variant swaps can't drift the page. See
  // startScrollLock / stopScrollLock below.
  let scrollLockObserver = null;
  let scrollLockTargetY = null;
  let scrollLockAnchorTop = null;
  let scrollLockRaf = null;
  let scrollLockAbort = null;
  const SCROLL_ANCHOR_LOCK_ID = 'impeccable-scroll-anchor-lock';
  const VARIANT_STATE_STYLE_ID = 'impeccable-variant-state';
  const DISCARD_STATE_STYLE_ID = 'impeccable-discard-state';

  // Dedicated key for scroll position - SEPARATE from LS_KEY so that
  // saveSession's state updates don't clobber a carefully-captured scrollY.
  // (Previously: saveSession wrote scrollY alongside state, so every call
  // during resume overwrote the pre-reload value with whatever the browser
  // had landed on, typically 0.)
  function writeScrollY(y) { sessionState.writeScrollY(y); }
  function readScrollY() { return sessionState.readScrollY(); }
  function clearScrollY() { sessionState.clearScrollY(); }

  // Pre-empt the browser: apply manual scroll restoration and jump to the
  // saved scrollY at script-parse time. Retries on fonts.ready and load
  // are essential: scrollTo(y) clamps to the current document.scrollHeight,
  // which is often hundreds of pixels short of the final value until
  // async-loaded fonts swap in and reflow.
  try {
    history.scrollRestoration = 'manual';
    const savedY = readScrollY();
    if (savedY != null) {
      const apply = () => {
        if (Math.abs(window.scrollY - savedY) > 0.5) {
          window.scrollTo(0, savedY);
        }
      };
      apply();
      if (document.fonts?.ready) document.fonts.ready.then(apply).catch(() => {});
      window.addEventListener('load', apply, { once: true });
    }
  } catch {}

  // UI refs
  let highlightEl = null;
  let tooltipEl = null;
  let barEl = null;
  let barHideSeq = 0;
  let pickerEl = null;
  let toastEl = null;
  let scrollRaf = null;
  let editBadgeEl = null;
  let editBadgeProxyRoot = null;
  let editBadgeProxyByTarget = new Map();

  //
  // Helpers
  //

  const domHelpers = window.__IMPECCABLE_LIVE_DOM__?.createLiveBrowserDomHelpers({
    prefix: PREFIX,
    skipTags: SKIP_TAGS,
    document,
  });
  if (!domHelpers) {
    console.error('[impeccable] live-browser-dom.js was not loaded. Live mode cannot start safely.');
    window.__IMPECCABLE_LIVE_INIT__ = false;
    return;
  }
  const {
    own,
    pickable,
    desc,
    rectIsUsableAnchor,
    makeFrozenAnchor,
    id8,
    cssId,
    liveUiRoot,
    uiAppend,
    uiAppendStyle,
    uiGetById,
    activeElementDeep,
    defangOutsideHandlers,
  } = domHelpers;

  window.__IMPECCABLE_LIVE_CHROME_CORE__ = {
    version: 1,
    adapter: window.__IMPECCABLE_LIVE_ADAPTER__ || 'dom',
    mountContract: LIVE_CHROME_MOUNT_CONTRACT,
    surfaces: LIVE_UI_SURFACES,
    componentIds: LIVE_UI_COMPONENT_IDS,
    root: liveUiRoot,
    append: uiAppend,
    appendStyle: uiAppendStyle,
    getById: uiGetById,
    activeElementDeep,
    debugState: () => ({
      state,
      currentSessionId,
      expectedVariants,
      arrivedVariants,
      visibleVariant,
      savedSession: loadSession(),
      sourceFile: currentSourceFile,
      previewFile: currentPreviewFile,
      previewMode: currentPreviewMode,
      barText: barEl?.textContent || null,
      barConnected: !!barEl?.isConnected,
      hasSvelteComponentSession: !!svelteComponentSession,
      mountedSvelteVariant: svelteComponentSession?.mountedVariant || 0,
      pickActive,
      pendingApplyInFlight,
      hoveredElement: hoveredElement ? {
        tag: hoveredElement.tagName,
        classes: hoveredElement.className,
        pickable: pickable(hoveredElement),
      } : null,
      pendingSvelteComponentRetry: !!pendingSvelteComponentRetryObserver,
      recoveryWaitingForAnchor,
      evtSourceReadyState: evtSource ? evtSource.readyState : null,
    }),
  };

  //
  // Highlight overlay
  //

  function initHighlight() {
    highlightEl = document.createElement('div');
    highlightEl.id = PREFIX + '-highlight';
    Object.assign(highlightEl.style, {
      position: 'fixed', top: '0', left: '0', width: '0', height: '0',
      border: '2px solid ' + C.brand, borderRadius: '3px',
      pointerEvents: 'none', zIndex: Z.highlight, boxSizing: 'border-box',
      transition: HIGHLIGHT_TRANSITION,
      display: 'none', opacity: '0',
    });
    uiAppend(highlightEl);

    tooltipEl = document.createElement('div');
    tooltipEl.id = PREFIX + '-tooltip';
    Object.assign(tooltipEl.style, {
      position: 'fixed',
      background: C.ink, color: C.white,
      fontFamily: MONO, fontSize: '10px', fontWeight: '500',
      padding: '2px 6px', borderRadius: '3px',
      zIndex: Z.highlight + 1, pointerEvents: 'none',
      whiteSpace: 'nowrap', display: 'none',
      letterSpacing: '0.02em',
      transition: TOOLTIP_TRANSITION,
    });
    uiAppend(tooltipEl);
  }

  function shouldShowHighlightTagTooltip() {
    // Configure/edit carry the tag in the bar selection pill, so keep only the outline.
    return state !== 'CONFIGURING' && state !== 'EDITING';
  }

  function hideHighlightTagTooltip() {
    if (!tooltipEl) return;
    tooltipEl.style.opacity = '0';
    tooltipEl.style.display = 'none';
  }

  function showHighlight(el) {
    if (!el || !highlightEl) return;
    if (el.hasAttribute?.('data-impeccable-insert-placeholder')) return;
    const r = el.getBoundingClientRect();
    const top = (r.top - 2) + 'px', left = (r.left - 2) + 'px';
    const width = (r.width + 4) + 'px', height = (r.height + 4) + 'px';
    const showTagTooltip = shouldShowHighlightTagTooltip();

    const hiWasHidden = highlightEl.style.display === 'none' || highlightEl.style.opacity === '0';
    if (hiWasHidden) {
      // Snap to first target without animating from (0,0), then fade in.
      highlightEl.style.transition = 'none';
      Object.assign(highlightEl.style, { top, left, width, height, display: 'block' });
      void highlightEl.offsetWidth;
      highlightEl.style.transition = HIGHLIGHT_TRANSITION;
      highlightEl.style.opacity = '1';
    } else {
      Object.assign(highlightEl.style, { top, left, width, height, display: 'block', opacity: '1' });
    }

    if (!showTagTooltip) {
      hideHighlightTagTooltip();
      return;
    }

    const tipTop = r.top - 20;
    const tipY = (tipTop < 4 ? r.bottom + 4 : tipTop) + 'px';
    const tipX = Math.max(4, r.left) + 'px';
    tooltipEl.textContent = desc(el);
    if (hiWasHidden) {
      tooltipEl.style.transition = 'none';
      Object.assign(tooltipEl.style, { top: tipY, left: tipX, display: 'block' });
      void tooltipEl.offsetWidth;
      tooltipEl.style.transition = TOOLTIP_TRANSITION;
      tooltipEl.style.opacity = '1';
    } else {
      Object.assign(tooltipEl.style, { top: tipY, left: tipX, display: 'block', opacity: '1' });
    }
  }

  function hideHighlight() {
    if (highlightEl) { highlightEl.style.opacity = '0'; highlightEl.style.display = 'none'; }
    if (tooltipEl) { tooltipEl.style.opacity = '0'; tooltipEl.style.display = 'none'; }
  }

  //
  // Annotation overlay (comment pins + kinpaku strokes)
  //
  // Active while state === 'CONFIGURING'. The overlay is a fixed-positioned
  // sibling of <body> mirroring selectedElement's bounding rect. Click (no
  // drag) drops a comment pin; drag paints a kinpaku SVG stroke. All coords
  // are stored in element-local CSS px so they survive scroll / resize and
  // correlate directly with the captured PNG.
  //

  const DRAG_THRESHOLD = 5;       // px - below this, treat pointerup as a click
  const PIN_DBL_CLICK_MS = 300;   // two clicks on the same pin within this delete it
  let annotOverlayEl = null;
  let annotSvgEl = null;
  let annotPinsEl = null;
  let annotClearChipEl = null;
  let annotState = { comments: [], strokes: [] };
  let annotActive = false;
  // `annotPointer` is either:
  //   { kind: 'new',   x0, y0, moved, strokeEl, strokePoints }   creating a stroke/pin
  //   { kind: 'pin',   idx, startPointer, startPin, moved }     dragging an existing pin
  let annotPointer = null;
  let annotEditing = null;        // { idx, input, wrapEl }
  let annotLastPinClick = { idx: -1, time: 0 }; // for click-click-to-delete
  let placeholderResizeLayerEl = null;
  let placeholderResizeDrag = null;

  function initAnnotOverlay() {
    annotOverlayEl = document.createElement('div');
    annotOverlayEl.id = PREFIX + '-annot';
    Object.assign(annotOverlayEl.style, {
      position: 'fixed', top: '0', left: '0', width: '0', height: '0',
      pointerEvents: 'auto', zIndex: Z.highlight + 2,
      display: 'none', overflow: 'visible',
      cursor: 'crosshair', touchAction: 'none',
    });

    annotSvgEl = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    annotSvgEl.id = PREFIX + '-annot-svg';
    Object.assign(annotSvgEl.style, {
      position: 'absolute', top: '0', left: '0',
      width: '100%', height: '100%',
      // The SVG itself doesn't absorb clicks; individual hit-paths opt-in via
      // pointer-events=stroke so gaps still fall through to the overlay.
      pointerEvents: 'none', overflow: 'visible',
    });
    annotOverlayEl.appendChild(annotSvgEl);

    annotPinsEl = document.createElement('div');
    annotPinsEl.id = PREFIX + '-annot-pins';
    Object.assign(annotPinsEl.style, {
      position: 'absolute', inset: '0',
      pointerEvents: 'none',
    });
    annotOverlayEl.appendChild(annotPinsEl);

    annotClearChipEl = document.createElement('div');
    annotClearChipEl.id = PREFIX + '-annot-clear';
    annotClearChipEl.dataset.annotClear = 'true';
    annotClearChipEl.textContent = 'Clear';
    Object.assign(annotClearChipEl.style, {
      position: 'absolute', top: '8px', right: '8px',
      background: C.ink, color: C.white,
      fontFamily: FONT, fontSize: '10px', fontWeight: '500',
      letterSpacing: '0.08em', textTransform: 'uppercase',
      padding: '5px 12px', borderRadius: '999px',
      cursor: 'pointer', pointerEvents: 'auto',
      display: 'none', userSelect: 'none',
      boxShadow: '0 1px 3px rgba(0,0,0,0.2)',
    });
    annotOverlayEl.appendChild(annotClearChipEl);

    placeholderResizeLayerEl = document.createElement('div');
    placeholderResizeLayerEl.id = PREFIX + '-placeholder-resize';
    Object.assign(placeholderResizeLayerEl.style, {
      position: 'absolute',
      inset: '0',
      pointerEvents: 'none',
      display: 'none',
      zIndex: '2',
    });
    annotOverlayEl.appendChild(placeholderResizeLayerEl);

    annotOverlayEl.addEventListener('pointerdown', onAnnotDown);
    annotOverlayEl.addEventListener('pointermove', onAnnotMove);
    annotOverlayEl.addEventListener('pointerup', onAnnotUp);
    annotOverlayEl.addEventListener('pointercancel', onAnnotUp);
    uiAppend(annotOverlayEl);
    // Modal-host friendliness: pointer-events is already 'auto' on this
    // overlay; we only need to silence the host's outside-interaction
    // listeners. Don't override pointer-events here (the overlay toggles
    // visibility via display:none, which is fine).
    defangOutsideHandlers(annotOverlayEl, { setPointerEvents: false });
  }

  function updateClearChip() {
    if (!annotClearChipEl) return;
    const hasAny = annotState.comments.length > 0 || annotState.strokes.length > 0;
    annotClearChipEl.style.display = hasAny ? 'block' : 'none';
  }

  function showAnnotOverlay(el) {
    if (!annotOverlayEl || !el) return;
    annotActive = true;
    positionAnnotOverlay(el);
    annotOverlayEl.style.display = 'block';
    syncPlaceholderResizeHandles();
  }

  function hideAnnotOverlay() {
    annotActive = false;
    placeholderResizeDrag = null;
    if (annotOverlayEl) annotOverlayEl.style.display = 'none';
    syncPlaceholderResizeHandles();
    // Drop any in-progress edit without touching annotState - clearAnnotations
    // (if the caller is exiting configure mode) handles state reset.
    annotEditing = null;
  }

  function positionAnnotOverlay(el) {
    if (!annotOverlayEl || !el) return;
    const r = el.getBoundingClientRect();
    Object.assign(annotOverlayEl.style, {
      top: r.top + 'px', left: r.left + 'px',
      width: r.width + 'px', height: r.height + 'px',
    });
    annotSvgEl.setAttribute('viewBox', '0 0 ' + r.width + ' ' + r.height);
    syncPlaceholderResizeHandles();
  }

  function clearAnnotations() {
    annotState.comments = [];
    annotState.strokes = [];
    if (annotSvgEl) while (annotSvgEl.firstChild) annotSvgEl.removeChild(annotSvgEl.firstChild);
    if (annotPinsEl) annotPinsEl.innerHTML = '';
    annotPointer = null;
    annotEditing = null;
    annotLastPinClick = { idx: -1, time: 0 };
    updateClearChip();
  }

  // Rebuild the SVG layer. Each stroke gets a wider invisible hit path
  // beneath the visible kinpaku path so clicks register on thin lines.
  function redrawStrokes() {
    while (annotSvgEl.firstChild) annotSvgEl.removeChild(annotSvgEl.firstChild);
    annotState.strokes.forEach((s, idx) => {
      const d = pointsToPath(s.points);
      const hit = document.createElementNS('http://www.w3.org/2000/svg', 'path');
      hit.setAttribute('d', d);
      hit.setAttribute('stroke', 'transparent');
      hit.setAttribute('stroke-width', '16');
      hit.setAttribute('stroke-linecap', 'round');
      hit.setAttribute('stroke-linejoin', 'round');
      hit.setAttribute('fill', 'none');
      hit.setAttribute('pointer-events', 'stroke');
      hit.style.cursor = 'pointer';
      hit.dataset.annotStroke = String(idx);
      annotSvgEl.appendChild(hit);
      const visible = document.createElementNS('http://www.w3.org/2000/svg', 'path');
      visible.setAttribute('d', d);
      visible.setAttribute('stroke', C.brand);
      visible.setAttribute('stroke-width', '3');
      visible.setAttribute('stroke-linecap', 'round');
      visible.setAttribute('stroke-linejoin', 'round');
      visible.setAttribute('fill', 'none');
      visible.setAttribute('pointer-events', 'none');
      annotSvgEl.appendChild(visible);
    });
    updateClearChip();
  }

  function localCoords(e) {
    const rect = annotOverlayEl.getBoundingClientRect();
    return { x: e.clientX - rect.left, y: e.clientY - rect.top };
  }

  function onAnnotDown(e) {
    if (!annotActive) return;

    // 0) Insert placeholder edge resize - wins over draw / pins.
    const resizeEdge = e.target.closest?.('[data-impeccable-placeholder-resize]')?.dataset.impeccablePlaceholderResize;
    if (resizeEdge && configureKind === 'insert' && placeholderElement) {
      startPlaceholderEdgeResize(resizeEdge, e);
      return;
    }

    // 1) Clear chip → wipe all annotations
    if (e.target.closest?.('[data-annot-clear]')) {
      if (annotEditing) annotEditing = null;
      clearAnnotations();
      renderAllPins();
      redrawStrokes();
      e.stopPropagation(); e.preventDefault();
      return;
    }

    // 2) Stroke hit path → delete that stroke
    const strokeHit = e.target.closest?.('[data-annot-stroke]');
    if (strokeHit) {
      const idx = parseInt(strokeHit.dataset.annotStroke, 10);
      if (Number.isInteger(idx)) {
        annotState.strokes.splice(idx, 1);
        redrawStrokes();
      }
      e.stopPropagation(); e.preventDefault();
      return;
    }

    // 3) Pin → drag, edit, or delete-on-double-click
    const pinWrap = e.target.closest?.('[data-annot-pin]');
    if (pinWrap) {
      const idx = parseInt(pinWrap.dataset.annotPin, 10);
      if (!Number.isInteger(idx)) return;
      // Double-click (two pointerdowns on the same pin within window) → delete.
      const now = Date.now();
      if (annotLastPinClick.idx === idx && now - annotLastPinClick.time < PIN_DBL_CLICK_MS) {
        if (annotEditing && annotEditing.idx === idx) annotEditing = null;
        annotState.comments.splice(idx, 1);
        annotLastPinClick = { idx: -1, time: 0 };
        renderAllPins();
        e.stopPropagation(); e.preventDefault();
        return;
      }
      annotLastPinClick = { idx, time: now };
      // If editing a different pin, commit that edit before starting here.
      if (annotEditing && annotEditing.idx !== idx) finalizeEditingPin();
      // If already editing THIS pin and the user clicked the dot, let the
      // input keep focus (don't start a drag - the click wasn't meant as one).
      if (annotEditing && annotEditing.idx === idx) return;
      const p = localCoords(e);
      const pin = annotState.comments[idx];
      annotPointer = {
        kind: 'pin', idx,
        startPointer: p,
        startPin: { x: pin.x, y: pin.y },
        moved: false,
      };
      try { annotOverlayEl.setPointerCapture(e.pointerId); } catch {}
      e.stopPropagation(); e.preventDefault();
      return;
    }

    // 4) Empty area → commit any open edit, then start new annotation
    if (annotEditing) {
      finalizeEditingPin();
      e.stopPropagation(); e.preventDefault();
      return;
    }
    const p = localCoords(e);
    annotPointer = { kind: 'new', x0: p.x, y0: p.y, moved: false, strokeEl: null, strokePoints: null };
    try { annotOverlayEl.setPointerCapture(e.pointerId); } catch {}
    e.stopPropagation(); e.preventDefault();
  }

  function onAnnotMove(e) {
    if (!annotActive) return;

    if (placeholderResizeDrag) {
      const d = placeholderResizeDrag;
      const next = resizePlaceholderFromEdge(
        d.start,
        d.edge,
        e.clientX - d.startX,
        e.clientY - d.startY,
        d.parentWidth,
      );
      applyPlaceholderDimensions(next);
      e.stopPropagation();
      return;
    }

    if (!annotPointer) return;
    const p = localCoords(e);

    if (annotPointer.kind === 'pin') {
      const dx = p.x - annotPointer.startPointer.x;
      const dy = p.y - annotPointer.startPointer.y;
      if (!annotPointer.moved) {
        if (Math.hypot(dx, dy) < DRAG_THRESHOLD) return;
        annotPointer.moved = true;
      }
      const pin = annotState.comments[annotPointer.idx];
      if (!pin) { annotPointer = null; return; }
      pin.x = annotPointer.startPin.x + dx;
      pin.y = annotPointer.startPin.y + dy;
      renderAllPins();
      e.stopPropagation();
      return;
    }

    // kind === 'new'
    const dx = p.x - annotPointer.x0, dy = p.y - annotPointer.y0;
    if (!annotPointer.moved) {
      if (Math.hypot(dx, dy) < DRAG_THRESHOLD) return;
      annotPointer.moved = true;
      const strokeEl = document.createElementNS('http://www.w3.org/2000/svg', 'path');
      strokeEl.setAttribute('stroke', C.brand);
      strokeEl.setAttribute('stroke-width', '3');
      strokeEl.setAttribute('stroke-linecap', 'round');
      strokeEl.setAttribute('stroke-linejoin', 'round');
      strokeEl.setAttribute('fill', 'none');
      strokeEl.setAttribute('pointer-events', 'none');
      annotSvgEl.appendChild(strokeEl);
      annotPointer.strokeEl = strokeEl;
      annotPointer.strokePoints = [[annotPointer.x0, annotPointer.y0]];
    }
    annotPointer.strokePoints.push([p.x, p.y]);
    annotPointer.strokeEl.setAttribute('d', pointsToPath(annotPointer.strokePoints));
    e.stopPropagation();
  }

  function pointsToPath(points) {
    if (!points || points.length === 0) return '';
    let d = 'M' + points[0][0].toFixed(1) + ' ' + points[0][1].toFixed(1);
    for (let i = 1; i < points.length; i++) {
      d += ' L' + points[i][0].toFixed(1) + ' ' + points[i][1].toFixed(1);
    }
    return d;
  }

  function onAnnotUp(e) {
    if (placeholderResizeDrag) {
      try { annotOverlayEl.releasePointerCapture(e.pointerId); } catch {}
      placeholderResizeDrag = null;
      e.stopPropagation();
      return;
    }
    if (!annotActive || !annotPointer) return;

    if (annotPointer.kind === 'pin') {
      const wasDrag = annotPointer.moved;
      const idx = annotPointer.idx;
      try { annotOverlayEl.releasePointerCapture(e.pointerId); } catch {}
      annotPointer = null;
      if (wasDrag) {
        // A drag is an intentional reposition; a follow-up click shouldn't be
        // interpreted as a double-click-to-delete.
        annotLastPinClick = { idx: -1, time: 0 };
      } else {
        beginEditPin(idx);
      }
      e.stopPropagation();
      return;
    }

    // kind === 'new'
    const wasDrag = annotPointer.moved;
    if (wasDrag) {
      annotState.strokes.push({ points: annotPointer.strokePoints });
      // Swap the temporary preview SVG path for the full render with hit paths.
      redrawStrokes();
    } else {
      const idx = annotState.comments.length;
      annotState.comments.push({ x: annotPointer.x0, y: annotPointer.y0, text: '' });
      renderAllPins();
      beginEditPin(idx);
    }
    try { annotOverlayEl.releasePointerCapture(e.pointerId); } catch {}
    annotPointer = null;
    if (configureKind === 'insert') syncInsertCreateButton();
    e.stopPropagation();
  }

  function renderAllPins() {
    annotPinsEl.innerHTML = '';
    annotState.comments.forEach((c, idx) => {
      annotPinsEl.appendChild(buildPinElement(c, idx));
    });
    updateClearChip();
  }

  function buildPinElement(comment, idx) {
    const interactive = idx >= 0;
    const wrap = document.createElement('div');
    if (interactive) wrap.dataset.annotPin = String(idx);
    Object.assign(wrap.style, {
      position: 'absolute',
      left: (comment.x - 7) + 'px', top: (comment.y - 7) + 'px',
      pointerEvents: interactive ? 'auto' : 'none',
      display: 'flex', alignItems: 'flex-start', gap: '6px',
      cursor: interactive ? 'grab' : 'default',
      touchAction: 'none',
    });
    const dot = document.createElement('div');
    Object.assign(dot.style, {
      width: '14px', height: '14px', borderRadius: '50%',
      background: C.brand, border: '2px solid ' + C.white,
      boxShadow: '0 1px 3px rgba(0,0,0,0.25)',
      flexShrink: '0',
    });
    wrap.appendChild(dot);

    if (comment.text) {
      const bubble = document.createElement('div');
      bubble.textContent = comment.text;
      Object.assign(bubble.style, {
        background: C.ink, color: C.white,
        fontFamily: FONT, fontSize: '12px', lineHeight: '1.4',
        padding: '4px 8px', borderRadius: '3px',
        marginTop: '-2px', maxWidth: '220px',
        pointerEvents: 'none', whiteSpace: 'pre-wrap',
        wordBreak: 'break-word',
      });
      wrap.appendChild(bubble);
    }
    return wrap;
  }

  function beginEditPin(idx) {
    const wrapEl = annotPinsEl.querySelector('[data-annot-pin="' + idx + '"]');
    if (!wrapEl) return;
    // Strip any existing bubble (but keep the dot)
    wrapEl.querySelectorAll('div:not(:first-child)').forEach(n => n.remove());
    const input = document.createElement('input');
    input.type = 'text';
    input.placeholder = 'Note…';
    Object.assign(input.style, {
      background: C.ink, color: C.white,
      fontFamily: FONT, fontSize: '12px', lineHeight: '1.4',
      padding: '4px 8px', borderRadius: '3px',
      border: '1px solid ' + C.brand,
      outline: 'none', marginTop: '-2px',
      width: '220px', pointerEvents: 'auto',
    });
    const originalText = annotState.comments[idx].text || '';
    input.value = originalText;
    wrapEl.appendChild(input);
    annotEditing = { idx, input, wrapEl, originalText };
    input.addEventListener('keydown', onAnnotInputKey, true);
    input.addEventListener('blur', () => {
      // Fires on both focus-loss and programmatic blur; commit unless we
      // already handled it.
      if (annotEditing && annotEditing.input === input) finalizeEditingPin();
    });
    // Stop clicks/pointerdowns inside the input from bubbling to the overlay
    ['pointerdown', 'click'].forEach(ev => {
      input.addEventListener(ev, e => e.stopPropagation());
    });
    setTimeout(() => input.focus(), 0);
  }

  function onAnnotInputKey(e) {
    if (e.key === 'Enter') {
      e.preventDefault(); e.stopPropagation();
      finalizeEditingPin();
    } else if (e.key === 'Escape') {
      e.preventDefault(); e.stopPropagation();
      cancelEditingPin();
    } else {
      // Keep arrows / backspace from hitting global handlers
      e.stopPropagation();
    }
  }

  function finalizeEditingPin() {
    if (!annotEditing) return;
    const { idx, input } = annotEditing;
    const text = input.value.trim();
    annotEditing = null;
    if (text) annotState.comments[idx].text = text;
    else annotState.comments.splice(idx, 1);
    renderAllPins();
  }

  function cancelEditingPin() {
    if (!annotEditing) return;
    const { idx, originalText } = annotEditing;
    annotEditing = null;
    // If the pin had text before this edit, restore it. If it was a
    // just-created empty pin, Escape removes it.
    if (originalText) {
      annotState.comments[idx].text = originalText;
    } else {
      annotState.comments.splice(idx, 1);
    }
    renderAllPins();
  }

  // Build a detached annotation subtree suitable for injection into the clone
  // modern-screenshot creates. Coordinates are element-local so this slots
  // straight into an element that's been made position:relative. Takes an
  // explicit snapshot so it works after annotState has been cleared.
  function buildAnnotationsForCapture(rect, snapshot) {
    const comments = snapshot ? snapshot.comments : annotState.comments;
    const strokes = snapshot ? snapshot.strokes : annotState.strokes;
    if (comments.length === 0 && strokes.length === 0) return null;
    const wrap = document.createElement('div');
    Object.assign(wrap.style, {
      position: 'absolute', top: '0', left: '0',
      width: rect.width + 'px', height: rect.height + 'px',
      pointerEvents: 'none', overflow: 'visible',
    });
    if (strokes.length > 0) {
      const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
      svg.setAttribute('viewBox', '0 0 ' + rect.width + ' ' + rect.height);
      Object.assign(svg.style, {
        position: 'absolute', top: '0', left: '0',
        width: '100%', height: '100%', overflow: 'visible',
      });
      for (const s of strokes) {
        const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
        path.setAttribute('stroke', C.brand);
        path.setAttribute('stroke-width', '3');
        path.setAttribute('stroke-linecap', 'round');
        path.setAttribute('stroke-linejoin', 'round');
        path.setAttribute('fill', 'none');
        path.setAttribute('d', pointsToPath(s.points));
        svg.appendChild(path);
      }
      wrap.appendChild(svg);
    }
    for (const c of comments) {
      // idx=-1 means non-interactive; pointerEvents stay off in the clone
      wrap.appendChild(buildPinElement(c, -1));
    }
    return wrap;
  }

  //
  // Element context extraction
  //

  function stripManualEditRuntimeState(root) {
    if (!root || root.nodeType !== 1) return;
    unwrapMixedContentTextNodes(root);
    const nodes = [root, ...root.querySelectorAll('[data-impeccable-editable], [data-impeccable-original-text], [data-impeccable-text-wrap]')];
    for (const node of nodes) {
      const runtimeEditable = node.hasAttribute('data-impeccable-editable')
        || node.hasAttribute('data-impeccable-original-text');
      node.removeAttribute('data-impeccable-editable');
      node.removeAttribute('data-impeccable-original-text');
      node.removeAttribute('data-impeccable-text-wrap');
      if (runtimeEditable) {
        node.removeAttribute('contenteditable');
        if (node.style) {
          node.style.userSelect = '';
          node.style.cursor = '';
          node.style.outline = '';
          node.style.webkitUserModify = '';
          if (!node.getAttribute('style')?.trim()) node.removeAttribute('style');
        }
      }
    }
  }

  function sanitizedContextOuterHTML(el, maxLength) {
    if (!el || !el.cloneNode) return '';
    const clone = el.cloneNode(true);
    stripManualEditRuntimeState(clone);
    return clone.outerHTML ? clone.outerHTML.slice(0, maxLength) : '';
  }

  function extractContext(el) {
    const cs = getComputedStyle(el);
    const r = el.getBoundingClientRect();
    const props = {};
    for (const sheet of document.styleSheets) {
      try {
        for (const rule of sheet.cssRules) {
          if (rule.style) for (let i = 0; i < rule.style.length; i++) {
            const p = rule.style[i];
            if (p.startsWith('--') && !props[p]) {
              const v = cs.getPropertyValue(p).trim();
              if (v) props[p] = v;
            }
          }
        }
      } catch { /* cross-origin */ }
    }
    return {
      tagName: el.tagName.toLowerCase(), id: el.id || null,
      classes: [...el.classList],
      textContent: (el.textContent || '').slice(0, 500),
      outerHTML: sanitizedContextOuterHTML(el, 10000),
      computedStyles: {
        'font-family': cs.fontFamily, 'font-size': cs.fontSize,
        'font-weight': cs.fontWeight, 'line-height': cs.lineHeight,
        'color': cs.color, 'background': cs.background,
        'background-color': cs.backgroundColor,
        'padding': cs.padding, 'margin': cs.margin,
        'display': cs.display, 'position': cs.position,
        'gap': cs.gap, 'border-radius': cs.borderRadius,
        'box-shadow': cs.boxShadow,
      },
      cssCustomProperties: props,
      parentContext: el.parentElement
        ? '<' + el.parentElement.tagName.toLowerCase()
          + (el.parentElement.id ? ' id="' + el.parentElement.id + '"' : '')
          + (el.parentElement.className ? ' class="' + el.parentElement.className + '"' : '')
          + '>'
        : null,
      boundingRect: { width: Math.round(r.width), height: Math.round(r.height) },
    };
  }

  const MANUAL_CONTEXT_SKIP = { script: 1, style: 1, template: 1, noscript: 1, svg: 1, code: 1, pre: 1 };

  function contextElementForManualEdit(selectedEl, rows, ops) {
    if (!selectedEl) return selectedEl;
    const leafOnly =
      rows && rows.length === 1 && rows[0] && rows[0].el === selectedEl;
    if (!leafOnly) return selectedEl;

    const editedTexts = new Set();
    for (const row of rows || []) addManualContextText(editedTexts, row.text);
    for (const op of ops || []) {
      addManualContextText(editedTexts, op.originalText);
      addManualContextText(editedTexts, op.newText);
    }

    let cur = selectedEl.parentElement;
    let depth = 0;
    while (cur && cur !== document.body && cur !== document.documentElement && depth < 4) {
      if (own(cur)) break;
      if (isUsefulManualEditContext(cur, selectedEl, editedTexts)) return cur;
      cur = cur.parentElement;
      depth++;
    }
    return selectedEl;
  }

  function isUsefulManualEditContext(candidate, leafEl, editedTexts) {
    if (!candidate || !candidate.contains(leafEl)) return false;
    if (!candidate.id && candidate.classList.length === 0 && candidate.children.length < 2) return false;
    return collectManualContextPieces(candidate, editedTexts).length > 0;
  }

  function collectManualContextPieces(rootEl, editedTexts) {
    const pieces = [];
    function walk(node) {
      if (!node) return;
      if (node.nodeType === 3) {
        const text = normalizeManualContextText(node.nodeValue);
        if (isMeaningfulManualContextPiece(text, editedTexts)) pieces.push(text);
        return;
      }
      if (node.nodeType !== 1) return;
      const tag = node.tagName.toLowerCase();
      if (MANUAL_CONTEXT_SKIP[tag]) return;
      if (node !== rootEl && own(node)) return;
      for (const child of node.childNodes) walk(child);
    }
    walk(rootEl);
    return pieces.slice(0, 12);
  }

  function addManualContextText(set, value) {
    const text = normalizeManualContextText(value);
    if (text) set.add(text);
  }

  function isMeaningfulManualContextPiece(text, editedTexts) {
    if (!text || text.length < 3 || text.length > 160) return false;
    if (/^[\d.,+\-%\s]+$/.test(text)) return false;
    return !editedTexts.has(text);
  }

  function normalizeManualContextText(value) {
    return String(value || '').replace(/\s+/g, ' ').trim();
  }

  //
  // The Bar - one floating element, three modes
  //

  // Contextual-bar palette. Cached at init so every build*Row reads a
  // consistent set of colors; detectPageTheme runs once rather than on every
  // phase transition.
  let BP = null;

  // Bar shadow variants. The default projects down + subtle around. When
  // the Tune popover opens below the bar, a downward shadow lands on the
  // dark popover and reads as a bright ghost line. We swap to UP-only while
  // tune is open below so the popover's top edge is clean.
  const BAR_SHADOW_DEFAULT = '0 4px 20px oklch(0% 0 0 / 0.08), 0 1px 3px oklch(0% 0 0 / 0.06)';
  const BAR_SHADOW_UP = '0 -4px 20px oklch(0% 0 0 / 0.08), 0 -1px 3px oklch(0% 0 0 / 0.06)';
  const BAR_SHADOW_DOWN = BAR_SHADOW_DEFAULT;

  function initBar() {
    BP = barPaletteForTheme(detectPageTheme());
    barEl = document.createElement('div');
    barEl.id = PREFIX + '-bar';
    Object.assign(barEl.style, {
      position: 'fixed', zIndex: Z.bar,
      display: 'none', opacity: '0',
      transform: 'translateY(6px)',
      transition: 'opacity 0.25s ' + EASE + ', transform 0.3s ' + EASE,
      background: BP.surface,
      border: '1px solid ' + BP.border,
      borderRadius: '8px',
      boxShadow: BP.shadow,
      transition: 'box-shadow 0.2s ease, opacity 0.25s ' + EASE + ', transform 0.3s ' + EASE,
      fontFamily: FONT, fontSize: '13px', color: BP.text,
      padding: '5px',
      maxWidth: '560px', minWidth: '340px',
    });
    uiAppend(barEl);
    defangOutsideHandlers(barEl);
  }

  function positionBar() {
    if (!barEl) return;
    const barH = barEl.offsetHeight || 44;
    const barW = barEl.offsetWidth || 380;
    const GLOBAL_BAR_RESERVE = 64; // global bar height + bottom margin + breathing room
    const GAP = 8;

    // Recovery pins to document.body when the picked element is off-screen or
    // missing. Center the generating bar above the global bar instead of
    // stacking a duplicate toast in the same slot.
    if (recoveryWaitingForAnchor) {
      const barRect = globalBarEl?.getBoundingClientRect();
      const reserve = barRect && barRect.height > 0
        ? Math.max(GLOBAL_BAR_RESERVE, window.innerHeight - barRect.top + 12)
        : GLOBAL_BAR_RESERVE;
      const top = window.innerHeight - barH - reserve;
      const left = Math.max(GAP, (window.innerWidth - barW) / 2);
      Object.assign(barEl.style, { top: top + 'px', left: left + 'px' });
      return;
    }

    const anchor = resolveBarAnchor();
    if (!anchor) return;
    const r = anchor.getBoundingClientRect();

    // Prefer below the element; fall back to above; if neither fits (element
    // taller than viewport), pin to a stable viewport anchor so the bar
    // doesn't teleport between top and bottom as the user scrolls.
    let top;
    const belowTop = r.bottom + GAP;
    const aboveTop = r.top - barH - GAP;
    if (belowTop + barH + GAP <= window.innerHeight - GLOBAL_BAR_RESERVE) {
      top = belowTop;
    } else if (aboveTop >= GAP) {
      top = aboveTop;
    } else {
      top = window.innerHeight - barH - GLOBAL_BAR_RESERVE;
    }

    let left = r.left + (r.width - barW) / 2;
    if (left < GAP) left = GAP;
    if (left + barW > window.innerWidth - GAP) left = window.innerWidth - barW - GAP;
    Object.assign(barEl.style, { top: top + 'px', left: left + 'px' });
  }

  function showBar(mode) {
    barHideSeq += 1;
    if (mode === 'cycling' && !ensureCyclingRenderable('show-bar')) return;
    barEl.innerHTML = '';
    if (mode === 'configure') {
      barEl.appendChild(configureKind === 'insert' ? buildInsertConfigureRow() : buildConfigureRow());
      if (configureKind === 'insert') syncInsertCreateButton();
      applyConfigureBarChrome();
    } else {
      restorePickerBarChrome();
      if (mode === 'generating') {
        if (recoveryWaitingForAnchor) dismissToast();
        barEl.appendChild(buildGeneratingRow());
      } else if (mode === 'cycling') barEl.appendChild(buildCyclingRow());
    }
    barEl.style.display = 'block';
    positionBar();
    requestAnimationFrame(() => {
      barEl.style.opacity = '1';
      barEl.style.transform = 'translateY(0)';
      syncPageChatFocus('show-bar');
    });
  }

  function hideBar(instant) {
    if (!barEl) return;
    const hideSeq = ++barHideSeq;
    stopVoice({ suppressSubmit: true });
    if (configureKind === 'insert') clearInsertPicking();
    barEl.style.opacity = '0';
    barEl.style.transform = instant ? 'translateY(0)' : 'translateY(6px)';
    if (instant) barEl.style.display = 'none';
    else setTimeout(() => { if (barEl && hideSeq === barHideSeq) barEl.style.display = 'none'; }, 250);
    hideActionPicker();
    closeTunePopover();
    hideConfigureBarTooltip();
    if (state === 'EDITING') restoreInlineEditDrafts();
    disableInlineEdit();
  }

  function updateBarContent(mode) {
    if (!barEl || barEl.style.display === 'none') return;
    if (mode === 'cycling' && !ensureCyclingRenderable('update-bar')) return;
    barEl.innerHTML = '';
    if (mode === 'configure') {
      barEl.appendChild(configureKind === 'insert' ? buildInsertConfigureRow() : buildConfigureRow());
      if (configureKind === 'insert') syncInsertCreateButton();
      applyConfigureBarChrome();
    } else {
      restorePickerBarChrome();
      if (mode === 'generating') barEl.appendChild(buildGeneratingRow());
      else if (mode === 'cycling') barEl.appendChild(buildCyclingRow());
      else if (mode === 'saving') barEl.appendChild(buildSavingRow());
      else if (mode === 'confirmed') {
        barEl.appendChild(buildConfirmedRow());
        barEl.style.background = 'oklch(95% 0.05 145)';
        barEl.style.border = '1px solid oklch(75% 0.12 145 / 0.4)';
      }
    }
    syncPageChatFocus('update-bar-content');
  }

  // Configure row: the floating bar surface IS the input; modifier pills sit left of the field.

  const CONFIGURE_BAR_H = '36px';
  // Compact selection pill + 7px inset balances vertical centering in the 36px bar.
  const CONFIGURE_BAR_INSET = '7px';
  const CONFIGURE_PILL_RADIUS = '7px';
  const CONFIGURE_SELECTION_PILL_BORDER = '1px solid oklch(70% 0.12 188)';
  const CONFIGURE_SELECTION_PILL_PAD = '1px 4px';
  const CONFIGURE_ROW_FONT_SIZE = '12px';
  const CONFIGURE_ROW_TRACK_H = '18px';
  const CONFIGURE_PILL_PAD_Y = '3px';
  const CONFIGURE_BAR_SURFACE = 'oklch(15% 0.008 95)';
  const CONFIGURE_PILL_TEXT = 'oklch(94% 0.02 82)';
  const ICON_CONFIGURE_SUBMIT =
    '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>';

  function applyConfigureBarChrome() {
    if (!barEl) return;
    barEl.dataset.configureSurface = 'true';
    barEl.style.padding = '0';
    barEl.style.background = CONFIGURE_BAR_SURFACE;
    barEl.style.overflow = 'hidden';
    syncConfigureInputChrome();
  }

  function restorePickerBarChrome() {
    if (!barEl) return;
    barEl.dataset.configureSurface = 'false';
    barEl.removeAttribute('data-input-focused');
    barEl.removeAttribute('data-voice-listening');
    barEl.style.padding = '5px';
    barEl.style.background = BP.surface;
    barEl.style.overflow = '';
    barEl.style.border = '1px solid ' + BP.border;
    barEl.style.borderColor = BP.border;
    barEl.style.boxShadow = BP.shadow;
  }

  function syncConfigureInputChrome() {
    const input = uiGetById(PREFIX + '-input') || uiGetById(PREFIX + '-insert-input');
    const surface = barEl?.dataset.configureSurface === 'true' ? barEl : null;
    if (!surface || !input) return;
    const focused = activeElementDeep() === input;
    const listening = voiceListening && voiceCtx?.mode === 'configure';
    surface.dataset.inputFocused = focused ? 'true' : 'false';
    surface.dataset.voiceListening = listening ? 'true' : 'false';
    surface.style.borderColor = listening
      ? BP.patinaSoft
      : (focused ? BP.accentSoft : BP.border);
    surface.style.boxShadow = BP.shadow;
  }

  function configureBarPalette() {
    return BP || barPaletteForTheme(detectPageTheme());
  }

  function configureRowTextMetrics(extra = {}) {
    return {
      fontFamily: FONT,
      fontSize: CONFIGURE_ROW_FONT_SIZE,
      fontWeight: '500',
      lineHeight: CONFIGURE_ROW_TRACK_H,
      ...extra,
    };
  }

  function configureInputFieldStyle(extra = {}) {
    return {
      flex: '1', minWidth: '0', width: '100%',
      padding: '0', margin: '0',
      border: 'none', background: 'transparent',
      boxSizing: 'border-box',
      height: CONFIGURE_ROW_TRACK_H,
      color: CONFIGURE_PILL_TEXT,
      caretColor: CONFIGURE_PILL_TEXT,
      outline: 'none',
      ...configureRowTextMetrics(),
      ...extra,
    };
  }

  function configureInputShellStyle() {
    return {
      display: 'flex', alignItems: 'center', gap: '6px',
      flex: '1', minWidth: '0', height: '100%',
      padding: '0 6px 0 ' + CONFIGURE_BAR_INSET,
    };
  }

  function configureSelectionPillStyle(extra = {}) {
    const P = configureBarPalette();
    return {
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      gap: '2px', height: 'auto', flexShrink: '0',
      padding: CONFIGURE_SELECTION_PILL_PAD,
      boxSizing: 'border-box',
      border: CONFIGURE_SELECTION_PILL_BORDER,
      borderRadius: CONFIGURE_PILL_RADIUS,
      background: 'transparent',
      color: P.patina,
      cursor: 'pointer',
      transition: 'background 0.15s ease, color 0.15s ease, border-color 0.15s ease',
      whiteSpace: 'nowrap',
      ...configureRowTextMetrics({
        fontFamily: MONO, fontWeight: '600', letterSpacing: '-0.01em',
      }),
      ...extra,
    };
  }

  function configureModifierPillStyle(extra = {}) {
    const P = configureBarPalette();
    return {
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      gap: '2px', height: 'auto', minHeight: CONFIGURE_ROW_TRACK_H,
      padding: CONFIGURE_PILL_PAD_Y + ' 8px', flexShrink: '0',
      boxSizing: 'border-box',
      border: '1px solid transparent',
      borderRadius: CONFIGURE_PILL_RADIUS,
      background: 'transparent',
      color: P.textDim, cursor: 'pointer',
      transition: 'background 0.15s ease, color 0.15s ease, border-color 0.15s ease',
      whiteSpace: 'nowrap',
      ...configureRowTextMetrics(),
      ...extra,
    };
  }

  function configureInlineControlStyle(extra = {}) {
    const P = configureBarPalette();
    return {
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      gap: '2px', height: CONFIGURE_ROW_TRACK_H, flexShrink: '0',
      padding: '0', margin: '0',
      boxSizing: 'border-box',
      border: 'none', borderRadius: '0',
      background: 'transparent',
      color: P.textDim, cursor: 'pointer',
      transition: 'color 0.12s ease, background 0.12s ease',
      whiteSpace: 'nowrap',
      ...configureRowTextMetrics(),
      ...extra,
    };
  }

  function bindConfigureInlineControlHover(btn, controlsLocked) {
    btn.addEventListener('mouseenter', () => {
      if (controlsLocked) return;
      const P = configureBarPalette();
      btn.style.color = P.text;
    });
    btn.addEventListener('mouseleave', () => {
      if (controlsLocked) return;
      btn.style.color = configureBarPalette().textDim;
    });
  }

  function bindConfigureModifierPillHover(btn, controlsLocked) {
    btn.addEventListener('mouseenter', () => {
      if (controlsLocked) return;
      const P = configureBarPalette();
      btn.style.color = P.text;
      btn.style.background = P.toggleActive;
    });
    btn.addEventListener('mouseleave', () => {
      if (controlsLocked) return;
      const P = configureBarPalette();
      btn.style.color = P.textDim;
      btn.style.background = 'transparent';
    });
  }

  let configureBarTooltipEl = null;

  function ensureConfigureBarTooltip() {
    if (configureBarTooltipEl) return configureBarTooltipEl;
    const P = configureBarPalette();
    configureBarTooltipEl = el('div', {
      position: 'fixed',
      display: 'none',
      zIndex: String(Z.bar + 7),
      pointerEvents: 'none',
      maxWidth: 'min(360px, calc(100vw - 16px))',
      padding: '6px 9px',
      borderRadius: '7px',
      background: P.chatSurface,
      border: '1px solid ' + P.hairline,
      boxShadow: P.shadow,
      color: P.text,
      fontFamily: FONT,
      fontSize: '11px',
      fontWeight: '500',
      lineHeight: '1.35',
      letterSpacing: '0.01em',
      whiteSpace: 'normal',
      wordBreak: 'break-word',
    });
    configureBarTooltipEl.id = PREFIX + '-configure-bar-tooltip';
    uiAppend(configureBarTooltipEl);
    return configureBarTooltipEl;
  }

  function showConfigureBarTooltip(anchor, message) {
    if (!anchor || !message) return;
    const tip = ensureConfigureBarTooltip();
    tip.textContent = message;
    tip.style.transition = 'none';
    tip.style.display = 'block';
    tip.style.opacity = '1';
    const r = anchor.getBoundingClientRect();
    const tipW = tip.offsetWidth;
    const tipH = tip.offsetHeight;
    const left = Math.max(8, Math.min(window.innerWidth - tipW - 8, r.left + r.width / 2 - tipW / 2));
    const top = Math.max(8, r.top - tipH - 8);
    tip.style.left = left + 'px';
    tip.style.top = top + 'px';
  }

  function hideConfigureBarTooltip() {
    if (!configureBarTooltipEl) return;
    configureBarTooltipEl.style.display = 'none';
    configureBarTooltipEl.style.opacity = '0';
  }

  function selectionTagLabel(el) {
    if (!el) return '';
    if (el.hasAttribute?.('data-impeccable-insert-placeholder')) return 'slot';
    return el.tagName.toLowerCase();
  }

  function elementPath(el, maxDepth = 8) {
    if (!el) return '';
    const parts = [];
    let node = el;
    while (node && node.nodeType === 1 && node !== document.body) {
      let part = node.tagName.toLowerCase();
      if (node.id) part += '#' + node.id;
      else if (node.classList?.length) part += '.' + [...node.classList].slice(0, 2).join('.');
      parts.unshift(part);
      node = node.parentElement;
      if (parts.length >= maxDepth) break;
    }
    return parts.join(' \u203a ');
  }

  function variantCountTooltipText(count) {
    const n = Number(count) || selectedCount;
    const word = n === 1 ? 'variant' : 'variants';
    return 'Click to change \u00b7 ' + n + ' ' + word;
  }

  function removeConfigureSelection() {
    hideConfigureBarTooltip();
    if (configureKind === 'insert') {
      cancelInsertConfigure();
      return;
    }
    selectedElement = null;
    exitConfigureToPicking('selection-pill-remove', { clearHover: true });
  }

  function buildSelectionPill({ el: targetEl, controlsLocked }) {
    const tag = selectionTagLabel(targetEl);
    const path = elementPath(targetEl);
    const P = configureBarPalette();
    const pill = el('button', configureSelectionPillStyle({ minWidth: '32px' }));
    pill.id = PREFIX + '-selection-pill';
    pill.type = 'button';
    pill.setAttribute('aria-label', 'Selected element: ' + tag);
    pill.disabled = controlsLocked;
    pill.style.cursor = controlsLocked ? 'not-allowed' : 'pointer';
    pill.style.opacity = controlsLocked ? '0.58' : '1';
    pill.style.flexShrink = '0';

    const faceStack = el('span', {
      display: 'grid', placeItems: 'center',
      width: '100%', minWidth: '1.25em',
      lineHeight: CONFIGURE_ROW_TRACK_H,
    });
    const tagFace = el('span', {
      gridArea: '1 / 1',
      transition: 'opacity 0.12s ease',
      color: P.patina,
    });
    const clearFace = el('span', {
      gridArea: '1 / 1',
      opacity: '0',
      transition: 'opacity 0.12s ease',
      color: 'oklch(58% 0.15 35)',
    });
    tagFace.textContent = tag;
    clearFace.textContent = '\u00D7';
    faceStack.appendChild(tagFace);
    faceStack.appendChild(clearFace);
    pill.appendChild(faceStack);

    const setArmed = (armed) => {
      tagFace.style.opacity = armed ? '0' : '1';
      clearFace.style.opacity = armed ? '1' : '0';
      pill.style.background = armed ? P.toggleActive : 'transparent';
      pill.style.border = CONFIGURE_SELECTION_PILL_BORDER;
      pill.setAttribute('aria-label', armed ? 'Clear selection' : 'Selected element: ' + tag);
    };
    const arm = () => {
      if (controlsLocked) {
        showConfigureBarTooltip(pill, 'Apply is still running');
        return;
      }
      setArmed(true);
      if (path) showConfigureBarTooltip(pill, path);
    };
    const disarm = () => {
      hideConfigureBarTooltip();
      setArmed(false);
    };
    pill.addEventListener('mouseenter', arm);
    pill.addEventListener('mouseleave', disarm);
    pill.addEventListener('focus', arm);
    pill.addEventListener('blur', disarm);
    pill.addEventListener('click', (e) => {
      e.stopPropagation();
      if (controlsLocked) { showManualApplyBusyToast(); return; }
      removeConfigureSelection();
    });
    return pill;
  }

  function bindConfigureCountPillTooltip(count, controlsLocked) {
    count.removeAttribute('title');
    count.addEventListener('mouseenter', () => {
      if (controlsLocked) {
        showConfigureBarTooltip(count, 'Apply is still running');
        return;
      }
      showConfigureBarTooltip(count, variantCountTooltipText(selectedCount));
    });
    count.addEventListener('mouseleave', hideConfigureBarTooltip);
  }

  function buildConfigureActionControl({ controlsLocked, onClick }) {
    const control = el('button', configureInlineControlStyle());
    const label = document.createElement('span');
    label.textContent = actionLabel();
    const caret = el('span', {
      fontSize: '10px', lineHeight: '1',
      marginLeft: '2px', pointerEvents: 'none',
      color: 'inherit',
    });
    caret.textContent = '\u25BE';
    caret.setAttribute('aria-hidden', 'true');
    control.appendChild(label);
    control.appendChild(caret);
    control.disabled = controlsLocked;
    control.style.cursor = controlsLocked ? 'not-allowed' : 'pointer';
    control.style.opacity = controlsLocked ? '0.58' : '1';
    bindConfigureInlineControlHover(control, controlsLocked);
    control.addEventListener('click', onClick);
    return control;
  }

  const VARIANT_COUNT_MIN = 1;
  const VARIANT_COUNT_MAX = 4;

  function cycleSelectedCount() {
    if (selectedCount >= VARIANT_COUNT_MAX) selectedCount = VARIANT_COUNT_MIN;
    else selectedCount += 1;
    return selectedCount;
  }

  function buildConfigureCountControl({ controlsLocked, onClick }) {
    const count = el('button', configureInlineControlStyle({
      fontFamily: MONO, fontWeight: '600', letterSpacing: '0',
    }));
    count.textContent = '\u00D7' + selectedCount;
    count.disabled = controlsLocked;
    count.style.cursor = controlsLocked ? 'not-allowed' : 'pointer';
    count.style.opacity = controlsLocked ? '0.58' : '1';
    bindConfigureInlineControlHover(count, controlsLocked);
    bindConfigureCountPillTooltip(count, controlsLocked);
    count.addEventListener('click', onClick);
    return count;
  }

  function buildConfigureVoiceButton({ id, controlsLocked, onClick }) {
    const voiceBtn = el('button', {
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      boxSizing: 'border-box',
      width: CONFIGURE_BAR_H, height: '100%', flexShrink: '0',
      padding: '0', margin: '0',
      border: 'none', borderRight: '1px solid ' + BP.hairline,
      borderRadius: '0', background: 'transparent',
      color: BP.textDim, cursor: 'pointer',
      transition: 'color 0.12s ease, background 0.12s ease',
    });
    voiceBtn.id = id;
    voiceBtn.type = 'button';
    voiceBtn.setAttribute('aria-label', 'Voice input');
    voiceBtn.innerHTML = ICON_PAGE_VOICE;
    voiceBtn.disabled = controlsLocked;
    voiceBtn.style.cursor = controlsLocked ? 'not-allowed' : 'pointer';
    voiceBtn.style.opacity = controlsLocked ? '0.58' : '1';
    voiceBtn.addEventListener('mousedown', (e) => e.stopPropagation());
    voiceBtn.addEventListener('click', onClick);
    return voiceBtn;
  }

  function buildConfigureTrailingCluster(controls, voiceBtn, submitBtn) {
    const cluster = el('div', {
      display: 'inline-flex', alignItems: 'stretch', flexShrink: '0',
      height: '100%', borderLeft: '1px solid ' + BP.hairline,
    });
    if (controls.length) {
      const controlsWrap = el('div', {
        display: 'inline-flex', alignItems: 'center', gap: '8px',
        padding: '0 10px', flexShrink: '0', height: '100%',
      });
      controls.forEach((control) => controlsWrap.appendChild(control));
      cluster.appendChild(controlsWrap);
    }
    voiceBtn.style.borderLeft = '1px solid ' + BP.hairline;
    cluster.appendChild(voiceBtn);
    cluster.appendChild(submitBtn);
    return cluster;
  }

  function buildConfigureSubmitButton({ controlsLocked, onClick, ariaLabel }) {
    const btn = el('button', {
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      boxSizing: 'border-box', width: CONFIGURE_BAR_H, height: CONFIGURE_BAR_H,
      padding: '0', flexShrink: '0',
      border: 'none', borderLeft: '1px solid ' + BP.hairline,
      borderRadius: '0',
      background: BP.accent, color: C.ink,
      cursor: controlsLocked ? 'not-allowed' : 'pointer',
      transition: 'filter 0.12s ease, transform 0.1s ease',
    });
    btn.type = 'button';
    btn.setAttribute('aria-label', ariaLabel);
    btn.innerHTML = ICON_CONFIGURE_SUBMIT;
    btn.disabled = controlsLocked;
    btn.style.opacity = controlsLocked ? '0.58' : '1';
    if (controlsLocked) btn.title = 'Apply is still running';
    btn.addEventListener('mouseenter', () => { if (!controlsLocked) btn.style.filter = 'brightness(1.1)'; });
    btn.addEventListener('mouseleave', () => btn.style.filter = 'none');
    btn.addEventListener('mousedown', () => { if (!controlsLocked) btn.style.transform = 'scale(0.97)'; });
    btn.addEventListener('mouseup', () => btn.style.transform = 'scale(1)');
    btn.addEventListener('click', onClick);
    return btn;
  }

  // Insert mode helpers (mirrors skill/scripts/live/insert-ui.mjs)

  function detectInsertAxisFromStyle(style) {
    const display = style?.display || 'block';
    if (display.includes('flex')) {
      const dir = style.flexDirection || 'row';
      return dir.startsWith('row') ? 'row' : 'column';
    }
    if (display === 'grid' || display === 'inline-grid') {
      const flow = style.gridAutoFlow || 'row';
      if (flow.includes('column')) return 'column';
      const cols = (style.gridTemplateColumns || '').trim();
      if (cols && cols !== 'none') {
        const colCount = cols.split(/\s+/).filter(Boolean).length;
        if (colCount > 1) return 'row';
      }
      return 'row';
    }
    return 'column';
  }

  function detectInsertAxis(parent) {
    if (!parent || parent.nodeType !== 1) return 'column';
    const st = getComputedStyle(parent);
    return detectInsertAxisFromStyle({
      display: st.display,
      flexDirection: st.flexDirection,
      gridTemplateColumns: st.gridTemplateColumns,
      gridAutoFlow: st.gridAutoFlow,
    });
  }

  function layoutFlowChildren(parent) {
    if (!parent) return [];
    return [...parent.children]
      .filter(pickable)
      .map((el) => ({ el, rect: el.getBoundingClientRect() }));
  }

  function computeInsertPosition(clientX, clientY, rect, axis) {
    axis = axis || 'column';
    if (!rect) return 'after';
    if (axis === 'row') {
      if (!Number.isFinite(rect.width) || rect.width <= 0) return 'after';
      return clientX < rect.left + rect.width / 2 ? 'before' : 'after';
    }
    if (!Number.isFinite(rect.height) || rect.height <= 0) return 'after';
    return clientY < rect.top + rect.height / 2 ? 'before' : 'after';
  }

  function groupSiblingRows(siblings, rowThreshold) {
    rowThreshold = rowThreshold ?? 8;
    const sorted = [...siblings].sort((a, b) => a.rect.top - b.rect.top || a.rect.left - b.rect.left);
    const rows = [];
    for (const entry of sorted) {
      let placed = false;
      for (const row of rows) {
        if (Math.abs(entry.rect.top - row[0].rect.top) <= rowThreshold) {
          row.push(entry);
          placed = true;
          break;
        }
      }
      if (!placed) rows.push([entry]);
    }
    return rows;
  }

  function horizontalOverlap(a, b) {
    const left = Math.max(a.left, b.left);
    const right = Math.min(a.right, b.right);
    return Math.max(0, right - left);
  }

  function hitSiblingInsertGap(clientX, clientY, siblings, opts) {
    opts = opts || {};
    if (!siblings || siblings.length < 2) return null;
    const slop = opts.slop ?? 12;
    const minOverlap = opts.minOverlap ?? 0.25;

    for (const row of groupSiblingRows(siblings)) {
      if (row.length < 2) continue;
      const sorted = [...row].sort((a, b) => a.rect.left - b.rect.left);
      for (let i = 0; i < sorted.length - 1; i++) {
        const a = sorted[i];
        const b = sorted[i + 1];
        const aRight = a.rect.right;
        const bLeft = b.rect.left;
        if (bLeft <= aRight) continue;
        const top = Math.max(a.rect.top, b.rect.top);
        const bottom = Math.min(a.rect.bottom, b.rect.bottom);
        const span = bottom - top;
        const minH = Math.min(a.rect.height, b.rect.height);
        if (span < minH * minOverlap) continue;
        const inX = clientX >= aRight - slop && clientX <= bLeft + slop;
        const inY = clientY >= top - slop && clientY <= bottom + slop;
        if (!inX || !inY) continue;
        return {
          anchor: b.el,
          position: 'before',
          axis: 'row',
          line: { axis: 'row', left: (aRight + bLeft) / 2, top, width: 0, height: span },
        };
      }
    }

    const sortedCol = [...siblings].sort((a, b) => a.rect.top - b.rect.top || a.rect.left - b.rect.left);
    for (let i = 0; i < sortedCol.length - 1; i++) {
      const a = sortedCol[i];
      const b = sortedCol[i + 1];
      const overlap = horizontalOverlap(a.rect, b.rect);
      const minW = Math.min(a.rect.width, b.rect.width);
      if (overlap < minW * minOverlap) continue;
      const gapTop = a.rect.bottom;
      const gapBottom = b.rect.top;
      if (gapBottom <= gapTop) continue;
      const overlapLeft = Math.max(a.rect.left, b.rect.left);
      const overlapRight = Math.min(a.rect.right, b.rect.right);
      const inY = clientY >= gapTop - slop && clientY <= gapBottom + slop;
      const inX = clientX >= overlapLeft - slop && clientX <= overlapRight + slop;
      if (!inY || !inX) continue;
      return {
        anchor: b.el,
        position: 'before',
        axis: 'column',
        line: { axis: 'column', top: (gapTop + gapBottom) / 2, left: overlapLeft, width: overlap, height: 0 },
      };
    }
    return null;
  }

  function insertLineCoords(rect, position, axis) {
    axis = axis || 'column';
    if (axis === 'row') {
      const x = position === 'before' ? rect.left - 2 : rect.right + 2;
      return { axis: 'row', top: rect.top, left: x, width: 0, height: rect.height };
    }
    const y = position === 'before' ? rect.top - 2 : rect.bottom + 2;
    return { axis: 'column', top: y, left: rect.left, width: rect.width, height: 0 };
  }

  function resolveInsertHover({ clientX, clientY, target, rect, axis, siblings }) {
    const gap = hitSiblingInsertGap(clientX, clientY, siblings);
    if (gap) return gap;
    const position = computeInsertPosition(clientX, clientY, rect, axis);
    const line = insertLineCoords(rect, position, axis);
    return { anchor: target, position, axis, line };
  }

  function cursorForInsertAxis(axis) {
    return axis === 'row' ? 'ew-resize' : 'ns-resize';
  }

  function placeholderSizing({ axis, parentDisplay, parentWidth, anchorFlex }) {
    const display = parentDisplay || 'block';
    const w = Number.isFinite(parentWidth) ? parentWidth : 0;
    if (axis === 'row') {
      if (display.includes('flex')) {
        const flex = anchorFlex && anchorFlex !== 'none' && anchorFlex !== '0 1 auto'
          ? anchorFlex
          : '1 1 0';
        return { kind: 'flex', flex, minWidth: 0 };
      }
      if (display === 'grid' || display === 'inline-grid') return { kind: 'auto' };
    }
    if (w >= PLACEHOLDER_MIN_WIDTH) return { kind: 'percent' };
    return {
      kind: 'explicit',
      width: Math.max(PLACEHOLDER_MIN_WIDTH, w || PLACEHOLDER_MIN_WIDTH),
    };
  }

  function placeholderWidthIsImplicit(kind) {
    return kind === 'flex' || kind === 'percent' || kind === 'auto';
  }

  function applyPlaceholderSizingStyles(placeholder, sizing) {
    placeholder.dataset.impeccablePlaceholderWidth = sizing.kind;
    placeholder.style.flex = '';
    placeholder.style.minWidth = '';
    placeholder.style.maxWidth = '';
    placeholder.style.width = '';
    if (sizing.kind === 'flex') {
      placeholder.style.flex = sizing.flex;
      placeholder.style.minWidth = sizing.minWidth + 'px';
    } else if (sizing.kind === 'percent') {
      placeholder.style.width = '100%';
      placeholder.style.maxWidth = '100%';
    } else if (sizing.kind === 'explicit') {
      placeholder.style.width = sizing.width + 'px';
    }
  }

  function materializePlaceholderWidth(placeholder) {
    if (!placeholder) return;
    const kind = placeholder.dataset.impeccablePlaceholderWidth;
    if (!placeholderWidthIsImplicit(kind)) return;
    const w = Math.max(PLACEHOLDER_MIN_WIDTH, Math.round(placeholder.offsetWidth));
    placeholder.style.flex = '';
    placeholder.style.minWidth = '';
    placeholder.style.maxWidth = '';
    placeholder.style.width = w + 'px';
    placeholder.dataset.impeccablePlaceholderWidth = 'explicit';
  }

  function canCreateInsert({ prompt, comments, strokes }) {
    const hasPrompt = typeof prompt === 'string' && prompt.trim().length > 0;
    const hasComments = Array.isArray(comments) && comments.length > 0;
    const hasStrokes = Array.isArray(strokes) && strokes.some(
      (s) => Array.isArray(s?.points) && s.points.length >= 2,
    );
    return hasPrompt || hasComments || hasStrokes;
  }

  function insertCreateDisabledReason({ prompt, comments, strokes }) {
    if (canCreateInsert({ prompt, comments, strokes })) return null;
    return 'Add a prompt or annotate the placeholder to create';
  }

  function clampPlaceholderSize(width, height, parentWidth) {
    const maxW = Math.max(PLACEHOLDER_MIN_WIDTH, parentWidth || PLACEHOLDER_MIN_WIDTH);
    return {
      width: Math.min(maxW, Math.max(PLACEHOLDER_MIN_WIDTH, Math.round(width))),
      height: Math.max(PLACEHOLDER_MIN_HEIGHT, Math.round(height)),
    };
  }

  function cursorForPlaceholderEdge(edge) {
    if (edge === 'n' || edge === 's') return 'ns-resize';
    if (edge === 'e' || edge === 'w') return 'ew-resize';
    return 'default';
  }

  function resizePlaceholderFromEdge(start, edge, dx, dy, parentWidth) {
    const base = {
      width: start.width,
      height: start.height,
      marginLeft: start.marginLeft ?? 0,
      marginTop: start.marginTop ?? 0,
    };
    if (edge === 'e') base.width = start.width + dx;
    else if (edge === 'w') {
      base.width = start.width - dx;
      base.marginLeft = start.marginLeft + dx;
    } else if (edge === 's') base.height = start.height + dy;
    else if (edge === 'n') {
      base.height = start.height - dy;
      base.marginTop = start.marginTop + dy;
    }
    const clamped = clampPlaceholderSize(base.width, base.height, parentWidth);
    if (edge === 'w') base.marginLeft = start.marginLeft + start.width - clamped.width;
    else if (edge === 'n') base.marginTop = start.marginTop + start.height - clamped.height;
    return {
      width: clamped.width,
      height: clamped.height,
      marginLeft: Math.round(base.marginLeft),
      marginTop: Math.round(base.marginTop),
    };
  }

  function ensureInsertLine() {
    if (insertLineEl) return insertLineEl;
    insertLineEl = document.createElement('div');
    insertLineEl.id = PREFIX + '-insert-line';
    Object.assign(insertLineEl.style, {
      position: 'fixed',
      zIndex: String(Z.highlight),
      height: '0',
      borderTop: '2px dotted ' + C.brand,
      pointerEvents: 'none',
      display: 'none',
      opacity: '0.9',
    });
    uiAppend(insertLineEl);
    defangOutsideHandlers(insertLineEl);
    return insertLineEl;
  }

  function showInsertLine(resolved) {
    if (!resolved?.anchor || !resolved.line) return;
    const line = ensureInsertLine();
    const coords = resolved.line;
    if (coords.axis === 'row') {
      Object.assign(line.style, {
        display: 'block',
        top: coords.top + 'px',
        left: coords.left + 'px',
        width: '0',
        height: coords.height + 'px',
        borderTop: 'none',
        borderLeft: '2px dotted ' + C.brand,
      });
    } else {
      Object.assign(line.style, {
        display: 'block',
        top: coords.top + 'px',
        left: coords.left + 'px',
        width: coords.width + 'px',
        height: '0',
        borderLeft: 'none',
        borderTop: '2px dotted ' + C.brand,
      });
    }
    insertHoverAnchor = resolved.anchor;
    insertHoverPosition = resolved.position;
    insertHoverAxis = resolved.axis || 'column';
  }

  function hideInsertLine() {
    if (!insertLineEl) return;
    insertLineEl.style.display = 'none';
    insertHoverAnchor = null;
    insertHoverPosition = null;
    insertHoverAxis = null;
    syncPageInteractionCursor();
  }

  /**
   * Drive the page-level pick / insert cursor through the textContent of one
   * injected <style>, never by mutating <html> (className or inline style).
   * Frameworks that server-render the <html>/<body> roots (Next.js App Router)
   * report a React 19 hydration mismatch when the client adds an attribute the
   * server HTML never emitted, so a `class`/inline `style` toggled on
   * `document.documentElement` trips "a tree hydrated but some attributes ...
   * didn't match" on the next Fast-Refresh re-render. Keying the cursor off a
   * stable-id <style> keeps the effect off the hydrated host elements (same
   * shape as the scroll-anchor lock). A falsy cursor clears the rule.
   */
  function setPageInteractionCursor(cursor) {
    let style = document.getElementById(PICK_CURSOR_STYLE_ID);
    if (!cursor) {
      if (style) style.textContent = '';
      return;
    }
    if (!style) {
      style = document.createElement('style');
      style.id = PICK_CURSOR_STYLE_ID;
      // Styles the host page, not the chrome - inside the adapter's shadow UI
      // root (uiAppendStyle's target) these selectors would match nothing.
      (document.head || document.documentElement).appendChild(style);
    }
    style.textContent =
      '* { cursor: ' + cursor + ' !important; }\n'
      + '[id^="' + PREFIX + '"],\n'
      + '[id^="' + PREFIX + '"] * { cursor: revert !important; }';
  }

  /** Page-level cursor while pick or insert mode is targeting page elements. */
  function syncPageInteractionCursor() {
    let cursor = '';
    if (state === 'PICKING' && pickActive && !insertActive) {
      cursor = 'crosshair';
    } else if (state === 'PICKING' && insertActive && insertHoverAnchor) {
      cursor = cursorForInsertAxis(insertHoverAxis || 'column');
    }
    setPageInteractionCursor(cursor);
  }

  /**
   * Single entry point for interaction-state transitions. The pick-mode
   * crosshair is derived from `state`, so a bare `state = ...` assignment
   * leaves the page cursor out of sync with the mode it advertises.
   */
  function setLiveState(next) {
    state = next;
    window.__IMPECCABLE_LIVE_STATE__ = next;
    syncPageInteractionCursor();
    // Whether a queued steer is still behind a generation is a function of this
    // state, so the hint has to move with it, not only with the 5s poll.
    syncSteerQueueHint();
  }

  /** Element used to position the floating bar / shader during a session. */
  function resolveBarAnchor() {
    if (svelteComponentSession?.sessionId === currentSessionId && (state === 'GENERATING' || state === 'CYCLING')) {
      const anchor = resolveSvelteComponentAnchor();
      if (anchor) return anchor;
    }
    if (currentSessionId && (state === 'GENERATING' || state === 'CYCLING')) {
      const wrapper = document.querySelector('[data-impeccable-variants="' + currentSessionId + '"]');
      if (wrapper) {
        const variantCount = wrapper.querySelectorAll('[data-impeccable-variant]:not([data-impeccable-variant="original"])').length;
        if (variantCount > 0 && visibleVariant > 0) {
          const visEl = pickVariantContent(wrapper, visibleVariant);
          if (visEl) return visEl;
        }
        if (state === 'GENERATING') {
          const ph = ensureInsertPlaceholder();
          if (ph) return ph;
          if (insertAnchorElement && document.body.contains(insertAnchorElement)) return insertAnchorElement;
        }
      }
    }
    if (selectedElement && document.body.contains(selectedElement)) return selectedElement;
    if (placeholderElement && document.body.contains(placeholderElement)) return placeholderElement;
    if (insertAnchorElement && document.body.contains(insertAnchorElement)) return insertAnchorElement;
    return null;
  }

  function removeInsertPlaceholderDom() {
    if (placeholderElement) {
      placeholderElement.remove();
      placeholderElement = null;
    }
    placeholderResizeDrag = null;
    syncPlaceholderResizeHandles();
  }

  function finalizeInsertSession() {
    removeInsertPlaceholderDom();
    insertAnchorElement = null;
    insertAnchorPosition = null;
    insertAnchorLayoutAxis = null;
    insertPlaceholderSnapshot = null;
    if (configureKind === 'insert') configureKind = 'replace';
  }

  function buildInsertPlaceholderSnapshotFromDom(anchor, placeholder) {
    return {
      width: Math.round(placeholder.offsetWidth || 0),
      height: Math.round(placeholder.offsetHeight || PLACEHOLDER_DEFAULT_HEIGHT),
      marginLeft: parseFloat(placeholder.style.marginLeft) || 0,
      marginTop: parseFloat(placeholder.style.marginTop) || 0,
      position: insertAnchorPosition || 'before',
      layoutAxis: insertAnchorLayoutAxis || 'column',
      anchorTag: anchor.tagName || 'DIV',
      anchorClasses: anchor.className || '',
      anchorText: (anchor.textContent || '').trim().slice(0, 120),
    };
  }

  function findInsertAnchorInDom() {
    if (insertAnchorElement && document.body.contains(insertAnchorElement)) return insertAnchorElement;
    const snap = insertPlaceholderSnapshot;
    if (!snap) return null;
    const tag = (snap.anchorTag || 'div').toLowerCase();
    const cls = (snap.anchorClasses || '').split(/\s+/).filter(Boolean)[0];
    const needle = snap.anchorText || '';
    const sel = cls ? tag + '.' + cls : tag;
    const candidates = document.querySelectorAll(sel);
    for (const candidate of candidates) {
      if (own(candidate)) continue;
      if (needle && !(candidate.textContent || '').includes(needle.slice(0, 40))) continue;
      return candidate;
    }
    return null;
  }

  function isInsertGeneratingSession() {
    if (state !== 'GENERATING' || !currentSessionId) return false;
    const wrapper = document.querySelector('[data-impeccable-variants="' + currentSessionId + '"]');
    return !!wrapper && wrapper.dataset.impeccableMode === 'insert';
  }

  /** Recreate the dotted placeholder if Astro/Vite HMR removed it mid-generation. */
  function ensureInsertPlaceholder() {
    if (!isInsertGeneratingSession()) return placeholderElement;
    const wrapper = document.querySelector('[data-impeccable-variants="' + currentSessionId + '"]');
    const variantCount = wrapper.querySelectorAll('[data-impeccable-variant]:not([data-impeccable-variant="original"])').length;
    if (variantCount > 0) return placeholderElement;
    if (placeholderElement && document.body.contains(placeholderElement)) return placeholderElement;

    const anchor = findInsertAnchorInDom();
    if (!anchor) return null;

    insertAnchorElement = anchor;
    const position = insertPlaceholderSnapshot?.position || insertAnchorPosition || 'before';
    const axis = insertPlaceholderSnapshot?.layoutAxis || insertAnchorLayoutAxis;
    const ph = createInsertPlaceholder(anchor, position, axis);
    if (!ph) return null;

    if (insertPlaceholderSnapshot) {
      applyPlaceholderDimensions({
        width: insertPlaceholderSnapshot.width,
        height: insertPlaceholderSnapshot.height,
        marginLeft: insertPlaceholderSnapshot.marginLeft,
        marginTop: insertPlaceholderSnapshot.marginTop,
      });
    }
    selectedElement = ph;
    return ph;
  }

  function applyPlaceholderDimensions({ width, height, marginLeft, marginTop }) {
    const ph = placeholderElement;
    if (!ph) return;
    materializePlaceholderWidth(ph);
    ph.style.width = width + 'px';
    ph.style.height = height + 'px';
    ph.style.marginLeft = marginLeft ? marginLeft + 'px' : '';
    ph.style.marginTop = marginTop ? marginTop + 'px' : '';
    positionAnnotOverlay(ph);
    positionBar();
  }

  function showOrUpdateCyclingBar() {
    if (barEl && barEl.style.display !== 'none') updateBarContent('cycling');
    else showBar('cycling');
  }

  function buildPlaceholderResizeHandles() {
    if (!placeholderResizeLayerEl) return;
    placeholderResizeLayerEl.innerHTML = '';
    const hit = 10;
    const half = hit / 2;
    const specs = [
      { edge: 'n', top: -half, left: 0, right: 0, height: hit },
      { edge: 's', bottom: -half, left: 0, right: 0, height: hit },
      { edge: 'e', top: 0, bottom: 0, right: -half, width: hit },
      { edge: 'w', top: 0, bottom: 0, left: -half, width: hit },
    ];
    for (const spec of specs) {
      const handle = el('div', {
        position: 'absolute',
        pointerEvents: 'auto',
        cursor: cursorForPlaceholderEdge(spec.edge),
      });
      if (spec.top != null) handle.style.top = spec.top + 'px';
      if (spec.bottom != null) handle.style.bottom = spec.bottom + 'px';
      if (spec.left != null) handle.style.left = spec.left + 'px';
      if (spec.right != null) handle.style.right = spec.right + 'px';
      if (spec.width != null) handle.style.width = spec.width + 'px';
      if (spec.height != null) handle.style.height = spec.height + 'px';
      handle.dataset.impeccablePlaceholderResize = spec.edge;
      handle.setAttribute('aria-label', 'Resize placeholder');
      handle.title = 'Drag to resize';
      placeholderResizeLayerEl.appendChild(handle);
    }
  }

  function syncPlaceholderResizeHandles() {
    if (!placeholderResizeLayerEl) return;
    const show = configureKind === 'insert' && annotActive && !!placeholderElement && state === 'CONFIGURING';
    placeholderResizeLayerEl.style.display = show ? 'block' : 'none';
    if (!show) {
      placeholderResizeLayerEl.innerHTML = '';
      return;
    }
    if (!placeholderResizeLayerEl.childElementCount) buildPlaceholderResizeHandles();
  }

  function startPlaceholderEdgeResize(edge, e) {
    const ph = placeholderElement;
    if (!ph || configureKind !== 'insert') return;
    materializePlaceholderWidth(ph);
    placeholderResizeDrag = {
      edge,
      startX: e.clientX,
      startY: e.clientY,
      start: {
        width: ph.offsetWidth,
        height: ph.offsetHeight,
        marginLeft: parseFloat(ph.style.marginLeft) || 0,
        marginTop: parseFloat(ph.style.marginTop) || 0,
      },
      parentWidth: ph.parentNode?.getBoundingClientRect().width || PLACEHOLDER_MIN_WIDTH,
      pointerId: e.pointerId,
    };
    try { annotOverlayEl.setPointerCapture(e.pointerId); } catch {}
    e.stopPropagation();
    e.preventDefault();
  }

  function createInsertPlaceholder(anchor, position, layoutAxis) {
    removeInsertPlaceholderDom();
    const parent = anchor.parentNode;
    if (!parent) return null;
    const axis = layoutAxis || detectInsertAxis(parent);
    const pst = getComputedStyle(parent);
    const ast = getComputedStyle(anchor);
    const sizing = placeholderSizing({
      axis,
      parentDisplay: pst.display,
      parentWidth: parent.getBoundingClientRect().width,
      anchorFlex: ast.flex,
    });
    const placeholder = document.createElement('div');
    placeholder.id = PREFIX + '-insert-placeholder';
    placeholder.setAttribute('data-impeccable-insert-placeholder', 'true');
    placeholder.setAttribute('aria-hidden', 'true');
    Object.assign(placeholder.style, {
      boxSizing: 'border-box',
      height: PLACEHOLDER_DEFAULT_HEIGHT + 'px',
      minHeight: PLACEHOLDER_MIN_HEIGHT + 'px',
      border: '2px dotted ' + BP.accent,
      borderRadius: '0',
      background: 'transparent',
      opacity: '1',
      position: 'relative',
      marginLeft: '',
      marginTop: '',
    });
    applyPlaceholderSizingStyles(placeholder, sizing);
    if (position === 'before') parent.insertBefore(placeholder, anchor);
    else parent.insertBefore(placeholder, anchor.nextSibling);
    placeholderElement = placeholder;
    insertAnchorElement = anchor;
    insertAnchorPosition = position;
    insertAnchorLayoutAxis = axis;
    return placeholder;
  }

  function clearInsertPicking() {
    hideInsertLine();
    finalizeInsertSession();
  }

  function isInsertCreateEnabled(btn) {
    btn = btn || uiGetById(PREFIX + '-insert-create');
    return !!btn && btn.getAttribute('aria-disabled') !== 'true';
  }

  let insertCreateTooltipEl = null;

  function ensureInsertCreateTooltip() {
    if (insertCreateTooltipEl) return insertCreateTooltipEl;
    insertCreateTooltipEl = el('div', {
      position: 'fixed',
      display: 'none',
      zIndex: String(Z.bar + 7),
      pointerEvents: 'none',
      maxWidth: '240px',
      padding: '6px 9px',
      borderRadius: '7px',
      background: BP.chatSurface,
      border: '1px solid ' + BP.hairline,
      boxShadow: BP.shadow,
      color: BP.text,
      fontFamily: FONT,
      fontSize: '11px',
      fontWeight: '500',
      lineHeight: '1.35',
    });
    insertCreateTooltipEl.id = PREFIX + '-insert-create-tooltip';
    uiAppend(insertCreateTooltipEl);
    return insertCreateTooltipEl;
  }

  function showInsertCreateTooltip(anchor, message) {
    if (!anchor || !message) return;
    const tip = ensureInsertCreateTooltip();
    tip.textContent = message;
    tip.style.display = 'block';
    const r = anchor.getBoundingClientRect();
    const tipW = tip.offsetWidth;
    const tipH = tip.offsetHeight;
    const left = Math.max(8, Math.min(window.innerWidth - tipW - 8, r.left + r.width / 2 - tipW / 2));
    const top = Math.max(8, r.top - tipH - 8);
    tip.style.left = left + 'px';
    tip.style.top = top + 'px';
  }

  function hideInsertCreateTooltip() {
    if (!insertCreateTooltipEl) return;
    insertCreateTooltipEl.style.display = 'none';
  }

  function insertCreateGateState(input) {
    return {
      prompt: input?.value ?? '',
      comments: annotState.comments,
      strokes: annotState.strokes,
    };
  }

  function syncInsertCreateButton(btn, input) {
    btn = btn || uiGetById(PREFIX + '-insert-create');
    input = input || uiGetById(PREFIX + '-insert-input');
    if (!btn || !input) return;
    const gate = insertCreateGateState(input);
    const ok = canCreateInsert(gate);
    const reason = ok ? 'Create variants' : insertCreateDisabledReason(gate);
    btn.setAttribute('aria-disabled', ok ? 'false' : 'true');
    btn.setAttribute('aria-label', reason);
    if (ok) {
      hideInsertCreateTooltip();
      btn.style.background = BP.accent;
      btn.style.color = C.ink;
      btn.style.border = 'none';
      btn.style.opacity = '1';
      btn.style.cursor = 'pointer';
    } else {
      btn.style.background = 'transparent';
      btn.style.color = BP.textDim;
      btn.style.border = '1px solid ' + BP.hairline;
      btn.style.opacity = '0.72';
      btn.style.cursor = 'not-allowed';
    }
  }

  /** Stylesheet shared by the replace and insert configure rows. */
  function ensureConfigureInputStyle() {
    if (uiGetById(PREFIX + '-configure-input-style')) return;
    const s = document.createElement('style');
    s.id = PREFIX + '-configure-input-style';
    s.textContent =
      '@keyframes impeccable-configure-voice-pulse { 0%, 100% { opacity: 0.55; } 50% { opacity: 1; } }' +
      '#' + PREFIX + '-input, #' + PREFIX + '-insert-input { box-sizing: border-box; height: ' + CONFIGURE_ROW_TRACK_H + '; line-height: ' + CONFIGURE_ROW_TRACK_H + '; padding: 0; margin: 0; caret-color: ' + CONFIGURE_PILL_TEXT + '; }' +
      '#' + PREFIX + '-input::placeholder, #' + PREFIX + '-insert-input::placeholder { color: ' + BP.textDim + '; opacity: 1; }' +
      '#' + PREFIX + '-configure-voice[data-listening="true"] svg, #' + PREFIX + '-insert-voice[data-listening="true"] svg { animation: impeccable-configure-voice-pulse 1.1s ease-in-out infinite; }' +
      '@media (prefers-reduced-motion: reduce) { #' + PREFIX + '-configure-voice[data-listening="true"] svg, #' + PREFIX + '-insert-voice[data-listening="true"] svg { animation: none; opacity: 1; } }' +
      '#' + PREFIX + '-configure-voice:hover, #' + PREFIX + '-insert-voice:hover { background: oklch(27% 0 0); color: ' + BP.accent + '; }';
    uiAppendStyle(s);
  }

  function buildConfigureRow() {
    const controlsLocked = pendingApplyInFlight === true;
    const row = el('div', {
      display: 'flex', alignItems: 'stretch', width: '100%', height: CONFIGURE_BAR_H,
    });

    const inputShell = el('div', configureInputShellStyle());

    const input = document.createElement('input');
    input.id = PREFIX + '-input';
    input.type = 'text';
    input.placeholder = '';
    input.setAttribute('aria-label', 'Describe the change');
    Object.assign(input.style, configureInputFieldStyle());
    input.disabled = controlsLocked;
    if (controlsLocked) {
      input.placeholder = 'apply is running...';
      input.style.cursor = 'not-allowed';
      input.style.opacity = '0.58';
    }

    const action = buildConfigureActionControl({
      controlsLocked,
      onClick: (e) => {
        e.stopPropagation();
        if (controlsLocked) { showManualApplyBusyToast(); return; }
        toggleActionPicker();
      },
    });

    const count = buildConfigureCountControl({
      controlsLocked,
      onClick: (e) => {
        e.stopPropagation();
        if (controlsLocked) { showManualApplyBusyToast(); return; }
        count.textContent = '\u00D7' + cycleSelectedCount();
        if (count.matches(':hover')) {
          showConfigureBarTooltip(count, variantCountTooltipText(selectedCount));
        }
      },
    });

    inputShell.appendChild(buildSelectionPill({ el: selectedElement, controlsLocked }));
    inputShell.appendChild(input);

    ensureConfigureInputStyle();

    input.addEventListener('focus', () => syncConfigureInputChrome());
    input.addEventListener('blur', () => syncConfigureInputChrome());
    input.addEventListener('keydown', (e) => {
      if (e.key === 'Enter') { e.stopPropagation(); e.preventDefault(); handleGo(); return; }
      if (e.key === 'Escape') {
        e.stopPropagation();
        e.preventDefault();
        input.blur();
        exitConfigureToPicking('configure-input-escape');
        return;
      }
      if ((e.key === 'ArrowUp' || e.key === 'ArrowDown') && !input.value) return;
      e.stopPropagation();
    });

    const voiceBtn = buildConfigureVoiceButton({
      id: PREFIX + '-configure-voice',
      controlsLocked,
      onClick: (e) => {
        e.stopPropagation();
        if (controlsLocked) { showManualApplyBusyToast(); return; }
        toggleConfigureVoice();
      },
    });

    const go = buildConfigureSubmitButton({
      controlsLocked,
      ariaLabel: 'Generate variants',
      onClick: (e) => { e.stopPropagation(); handleGo(); },
    });

    row.appendChild(inputShell);
    row.appendChild(buildConfigureTrailingCluster([action, count], voiceBtn, go));
    syncConfigureInputChrome();

    if (!controlsLocked) setTimeout(() => input.focus(), 60);

    return row;
  }

  function buildInsertConfigureRow() {
    const controlsLocked = pendingApplyInFlight === true;
    const row = el('div', {
      display: 'flex', alignItems: 'stretch', width: '100%', height: CONFIGURE_BAR_H,
    });
    row.addEventListener('pointerdown', (e) => e.stopPropagation());
    row.addEventListener('mousedown', (e) => e.stopPropagation());
    row.addEventListener('click', (e) => e.stopPropagation());

    const inputShell = el('div', configureInputShellStyle());

    const input = document.createElement('input');
    input.id = PREFIX + '-insert-input';
    input.type = 'text';
    input.placeholder = '';
    input.setAttribute('aria-label', 'Describe the new element');
    Object.assign(input.style, configureInputFieldStyle());
    input.disabled = controlsLocked;
    if (controlsLocked) {
      input.placeholder = 'apply is running...';
      input.style.cursor = 'not-allowed';
      input.style.opacity = '0.58';
    }

    const count = buildConfigureCountControl({
      controlsLocked,
      onClick: (e) => {
        e.stopPropagation();
        if (controlsLocked) { showManualApplyBusyToast(); return; }
        count.textContent = '\u00D7' + cycleSelectedCount();
        if (count.matches(':hover')) {
          showConfigureBarTooltip(count, variantCountTooltipText(selectedCount));
        }
      },
    });

    inputShell.appendChild(buildSelectionPill({ el: selectedElement, controlsLocked }));
    inputShell.appendChild(input);

    ensureConfigureInputStyle();

    input.addEventListener('input', () => syncInsertCreateButton());
    input.addEventListener('pointerdown', (e) => e.stopPropagation());
    input.addEventListener('mousedown', (e) => e.stopPropagation());
    input.addEventListener('click', (e) => {
      e.stopPropagation();
      try { input.focus({ preventScroll: true }); } catch { input.focus(); }
    });
    input.addEventListener('keydown', (e) => {
      if (e.key === 'Enter') {
        e.stopPropagation(); e.preventDefault();
        if (isInsertCreateEnabled()) handleInsertCreate();
        return;
      }
      if (e.key === 'Escape') {
        e.stopPropagation(); e.preventDefault();
        cancelInsertConfigure();
        return;
      }
      e.stopPropagation();
    });
    input.addEventListener('focus', () => syncConfigureInputChrome());
    input.addEventListener('blur', () => syncConfigureInputChrome());

    const voiceBtn = buildConfigureVoiceButton({
      id: PREFIX + '-insert-voice',
      controlsLocked,
      onClick: (e) => {
        e.stopPropagation();
        if (controlsLocked) { showManualApplyBusyToast(); return; }
        toggleConfigureVoice();
      },
    });

    const create = buildConfigureSubmitButton({
      controlsLocked,
      ariaLabel: 'Create variants',
      onClick: (e) => {
        e.preventDefault();
        e.stopPropagation();
        if (controlsLocked) { showManualApplyBusyToast(); return; }
        if (!isInsertCreateEnabled(create)) return;
        handleInsertCreate();
      },
    });
    create.id = PREFIX + '-insert-create';
    create.addEventListener('mouseenter', () => {
      if (controlsLocked) return;
      if (isInsertCreateEnabled(create)) {
        hideInsertCreateTooltip();
        return;
      }
      showInsertCreateTooltip(create, insertCreateDisabledReason(insertCreateGateState(input)));
    });
    create.addEventListener('mouseleave', hideInsertCreateTooltip);
    row.appendChild(inputShell);
    row.appendChild(buildConfigureTrailingCluster([count], voiceBtn, create));
    syncInsertCreateButton(create, input);
    syncConfigureInputChrome();
    if (!controlsLocked) setTimeout(() => input.focus(), 60);
    return row;
  }

  // Generating row

  function buildGeneratingRow() {
    const row = el('div', {
      display: 'flex', alignItems: 'center', gap: '8px',
      padding: '2px 4px',
    });

    // Action label
    const label = el('span', {
      fontWeight: '600', fontSize: '12px', color: BP.text,
      flexShrink: '0', whiteSpace: 'nowrap',
    });
    label.textContent = configureKind === 'insert' ? 'Insert' : actionLabel();
    row.appendChild(label);

    // Dots
    row.appendChild(buildDots(false));

    // Status
    const status = el('span', {
      fontSize: '11px', color: BP.textDim, whiteSpace: 'nowrap',
      marginLeft: 'auto',
    });
    status.textContent = recoveryWaitingForAnchor
      ? 'Variants ready. Reveal the selected element to resume.'
      : generationStatusText();
    row.appendChild(status);

    return row;
  }

  function generationStatusText() {
    if (arrivedVariants >= expectedVariants && expectedVariants > 0) return 'Done';
    if (generationPhase === 'picked_up') return 'Agent picked up the request...';
    if (generationPhase === 'scaffolding') return 'Finding the source...';
    if (generationPhase === 'source_ready') return 'Source ready. Generating...';
    if (generationPhase === 'scaffold_fallback') return 'Agent is locating the source...';
    if (generationPhase === 'first_reviewable') return 'First variant is ready. Exploring more...';
    if (generationPhase === 'second_reviewable') return 'Checking the remaining variants...';
    return 'Generating ' + expectedVariants + ' variants...';
  }

  // Cycling row

  const TUNE_ICON_SVG = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" style="flex-shrink:0"><line x1="4" y1="8" x2="20" y2="8"/><circle cx="14" cy="8" r="2.4" fill="currentColor" stroke="none"/><line x1="4" y1="16" x2="20" y2="16"/><circle cx="10" cy="16" r="2.4" fill="currentColor" stroke="none"/></svg>';

  /**
   * Which variant the user is actually looking at. For component previews the
   * mounted component is the truth; `visibleVariant` is the intent, and the two
   * differ while a mount is in flight.
   */
  function cyclingShownVariant() {
    return svelteComponentSession?.sessionId === currentSessionId && svelteComponentSession.mountedVariant > 0
      ? svelteComponentSession.mountedVariant
      : visibleVariant;
  }

  /**
   * The single counter string. It is built here rather than at each call site
   * because the row builder and the incremental sync used to disagree on the
   * denominator: one showed the planned count, the other the arrived count, so
   * "2/3" turned into "2/2" on the next sync without anything changing on
   * screen. Arrived wins once anything has arrived; expected covers the window
   * before the first variant lands.
   */
  function cyclingCounterText() {
    const total = arrivedVariants > 0 ? arrivedVariants : expectedVariants;
    return cyclingShownVariant() + '/' + total;
  }

  function buildCyclingRow() {
    if (!ensureCyclingRenderable('build-cycling-row')) {
      return el('div', { display: 'none' });
    }
    const row = el('div', {
      display: 'flex', alignItems: 'center', gap: '6px',
      padding: '1px 2px',
    });

    // Prev
    const prev = navBtn('\u2190');
    prev.id = PREFIX + '-variant-prev';
    prev.addEventListener('click', (e) => { e.stopPropagation(); cycleVariant(-1); });
    if (cyclingShownVariant() <= 1) prev.style.opacity = '0.3';
    row.appendChild(prev);

    // Dots (clickable)
    row.appendChild(buildDots(true));

    // Counter
    const counter = el('span', {
      fontFamily: MONO, fontSize: '11px', fontWeight: '500',
      color: BP.textDim, minWidth: '24px', textAlign: 'center',
    });
    counter.id = PREFIX + '-variant-counter';
    counter.textContent = cyclingCounterText();
    row.appendChild(counter);

    // Next
    const next = navBtn('\u2192');
    next.id = PREFIX + '-variant-next';
    next.addEventListener('click', (e) => { e.stopPropagation(); cycleVariant(1); });
    if (cyclingShownVariant() >= arrivedVariants) next.style.opacity = '0.3';
    row.appendChild(next);

    // Tune chip stays visible while the deferred parameter phase is running,
    // then becomes interactive as soon as this variant exposes controls.
    const visParams = parseVariantParams(getVisibleVariantEl());
    const hasParams = visParams.length > 0;
    const paramsPending = !hasParams && (parameterGenerationState === 'pending' || parameterGenerationState === 'loading');
    if (hasParams || paramsPending) {
      const tune = el('button', {
        display: 'inline-flex', alignItems: 'center', gap: '6px',
        padding: '4px 10px', borderRadius: '5px',
        border: '1px solid transparent',
        background: tuneOpen ? BP.accentSoft : 'transparent',
        color: tuneOpen ? BP.accent : BP.text,
        fontFamily: FONT, fontSize: '11px', fontWeight: '500',
        cursor: paramsPending ? 'wait' : 'pointer',
        transition: 'color 0.12s ease, background 0.12s ease',
        whiteSpace: 'nowrap',
      });
      if (paramsPending) {
        const spinner = el('span', {
          width: '11px', height: '11px', borderRadius: '50%',
          border: '1.5px solid ' + BP.hairline,
          borderTopColor: BP.accent,
          animation: 'impeccable-spin 0.6s linear infinite',
          boxSizing: 'border-box', flexShrink: '0',
        });
        spinner.setAttribute('aria-hidden', 'true');
        tune.appendChild(spinner);
      } else {
        tune.innerHTML = TUNE_ICON_SVG;
      }
      const tuneLabel = document.createElement('span');
      tuneLabel.textContent = 'Tune';
      tune.appendChild(tuneLabel);
      if (hasParams) {
        const tuneBadge = document.createElement('span');
        Object.assign(tuneBadge.style, {
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          minWidth: '16px', height: '16px', padding: '0 4px',
          borderRadius: '999px',
          background: tuneOpen ? C.brand : BP.hairline,
          color: tuneOpen ? C.ink : 'inherit',
          fontFamily: MONO, fontSize: '9.5px', fontWeight: '600',
          lineHeight: '1',
          boxSizing: 'border-box',
        });
        tuneBadge.textContent = String(visParams.length);
        tune.appendChild(tuneBadge);
        tune.title = 'Tune this variant (' + visParams.length + ' knob' + (visParams.length === 1 ? '' : 's') + ')';
        tune.addEventListener('mouseenter', () => {
          if (!tuneOpen) tune.style.background = BP.accentSoft;
        });
        tune.addEventListener('mouseleave', () => {
          if (!tuneOpen) tune.style.background = 'transparent';
        });
        tune.addEventListener('click', (e) => { e.stopPropagation(); toggleTunePopover(); });
      } else {
        tune.disabled = true;
        tune.setAttribute('aria-label', 'Tune controls are still being prepared');
        tune.title = 'Tune controls are still being prepared';
        tune.style.opacity = '0.72';
      }
      tune.dataset.iceqTune = '1';
      row.appendChild(tune);
    }

    // Spacer
    row.appendChild(el('div', { flex: '1' }));

    if (arrivedVariants < expectedVariants) {
      const remaining = expectedVariants - arrivedVariants;
      const progress = el('span', {
        fontSize: '11px', color: BP.textDim, whiteSpace: 'nowrap',
      });
      progress.textContent = remaining + ' more arriving...';
      row.appendChild(progress);
    }

    // Accept - primary action, kinpaku gold + lacquer-deep (matches demo .live-demo-ctx-accept)
    const accept = el('button', {
      padding: '5px 14px', borderRadius: '5px',
      border: 'none', background: C.brand, color: C.ink,
      fontFamily: FONT, fontSize: '11px', fontWeight: '600',
      cursor: 'pointer', transition: 'filter 0.12s ease, transform 0.1s ease',
      whiteSpace: 'nowrap',
    });
    accept.textContent = '\u2713 Accept';
    accept.addEventListener('mouseenter', () => accept.style.filter = 'brightness(1.08)');
    accept.addEventListener('mouseleave', () => accept.style.filter = 'none');
    accept.addEventListener('mousedown', () => accept.style.transform = 'scale(0.97)');
    accept.addEventListener('mouseup', () => accept.style.transform = 'scale(1)');
    accept.addEventListener('click', (e) => { e.stopPropagation(); handleAccept(); });
    if (arrivedVariants === 0) {
      accept.style.opacity = '0.3';
      accept.style.pointerEvents = 'none';
      accept.title = 'Accept becomes available when the first variant arrives';
    }
    row.appendChild(accept);

    // Discard
    const discard = el('button', {
      padding: '4px 6px', borderRadius: '5px',
      border: '1px solid ' + BP.hairline, background: 'transparent',
      fontFamily: FONT, fontSize: '11px', color: BP.textDim,
      cursor: 'pointer', transition: 'color 0.12s ease, border-color 0.12s ease',
    });
    discard.textContent = '\u2715';
    discard.title = 'Discard all variants';
    discard.addEventListener('mouseenter', () => { discard.style.color = BP.text; discard.style.borderColor = BP.text; });
    discard.addEventListener('mouseleave', () => { discard.style.color = BP.textDim; discard.style.borderColor = BP.hairline; });
    discard.addEventListener('click', (e) => { e.stopPropagation(); handleDiscard(); });
    row.appendChild(discard);

    return row;
  }

  // Shared UI builders

  // Saving row (waiting for agent to process accept/discard)

  function buildSavingRow() {
    const row = el('div', {
      display: 'flex', alignItems: 'center', gap: '8px',
      padding: '2px 8px',
    });
    const spinner = el('div', {
      width: '14px', height: '14px', borderRadius: '50%',
      border: '2px solid ' + BP.hairline,
      borderTopColor: BP.accent,
      animation: 'impeccable-spin 0.6s linear infinite',
      flexShrink: '0',
    });
    row.appendChild(spinner);
    const label = el('span', {
      fontSize: '12px', color: BP.textDim, fontWeight: '500',
    });
    label.textContent = 'Applying variant...';
    row.appendChild(label);

    ensureSpinKeyframes();
    return row;
  }

  // Confirmed row (green success, auto-dismisses)

  function buildConfirmedRow() {
    const row = el('div', {
      display: 'flex', alignItems: 'center', gap: '8px',
      padding: '2px 8px',
    });
    const check = el('span', {
      fontSize: '15px', lineHeight: '1', flexShrink: '0',
      color: 'oklch(45% 0.18 145)',
    });
    check.textContent = '\u2713';
    row.appendChild(check);
    const label = el('span', {
      fontSize: '12px', color: 'oklch(49% 0.08 188)', fontWeight: '600',
    });
    label.textContent = 'Variant applied';
    row.appendChild(label);
    return row;
  }

  // Shared UI builders

  function buildDots(clickable) {
    const container = el('div', {
      display: 'flex', alignItems: 'center', gap: '4px',
    });
    for (let i = 1; i <= expectedVariants; i++) {
      const arrived = i <= arrivedVariants;
      const active = i === visibleVariant;
      // active: solid site-brand kinpaku dot. arrived+inactive: muted neutral.
      // pending (not yet arrived): faint outline ring. No borders on arrived
      // dots - the previous "accent ring + ash fill" combo read as noisy
      // kinpaku chips, especially when all variants had arrived and every
      // dot wore an accent ring.
      const dotBg = active ? C.brand
        : arrived ? BP.textDim
        : 'transparent';
      const dotBorder = arrived ? 'none' : '1.5px solid ' + BP.hairline;
      const dot = el('div', {
        width: active ? '8px' : '6px',
        height: active ? '8px' : '6px',
        borderRadius: '50%',
        background: dotBg,
        border: dotBorder,
        boxSizing: 'border-box',
        transition: 'all 0.2s ' + EASE,
        cursor: (clickable && arrived) ? 'pointer' : 'default',
        transform: arrived ? 'scale(1)' : 'scale(0.85)',
        opacity: arrived ? (active ? '1' : '0.6') : '0.4',
      });
      if (clickable && arrived) {
        const idx = i;
        dot.addEventListener('click', (e) => {
          e.stopPropagation();
          selectVariant(idx, 'variant_changed');
        });
      }
      container.appendChild(dot);
    }
    return container;
  }

  function navBtn(text) {
    const b = el('button', {
      width: '26px', height: '26px', borderRadius: '5px',
      border: '1px solid ' + BP.hairline, background: 'transparent',
      color: BP.text, fontFamily: FONT, fontSize: '13px',
      cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center',
      transition: 'border-color 0.12s ease, background 0.12s ease',
      padding: '0', lineHeight: '1',
    });
    b.textContent = text;
    b.addEventListener('mouseenter', () => { b.style.borderColor = BP.text; });
    b.addEventListener('mouseleave', () => { b.style.borderColor = BP.hairline; });
    return b;
  }

  function actionLabel() {
    const a = ACTIONS.find(a => a.value === selectedAction);
    return a ? a.label : 'Freeform';
  }

  function el(tag, styles) {
    const e = document.createElement(tag);
    if (String(tag).toLowerCase() === 'button') e.type = 'button';
    if (styles) Object.assign(e.style, styles);
    return e;
  }

  //
  // Action picker popover
  //

  function initActionPicker() {
    const P = barPaletteForTheme(detectPageTheme());
    pickerEl = document.createElement('div');
    pickerEl.id = PREFIX + '-picker';
    Object.assign(pickerEl.style, {
      position: 'fixed', zIndex: Z.picker,
      display: 'none', opacity: '0',
      transform: 'scale(0.96) translateY(4px)',
      transformOrigin: 'bottom right',
      transition: 'opacity 0.18s ' + EASE + ', transform 0.2s ' + EASE,
      background: P.surface,
      border: '1px solid ' + P.border,
      borderRadius: '8px',
      boxShadow: P.shadow,
      padding: '6px',
      fontFamily: FONT,
    });

    // Build the chip grid
    const grid = el('div', {
      display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: '3px',
    });

    ACTIONS.forEach(action => {
      const chip = el('button', {
        display: 'flex', flexDirection: 'column', alignItems: 'center',
        gap: '4px',
        padding: '8px 6px', borderRadius: '6px',
        border: 'none',
        background: action.value === selectedAction ? P.accentSoft : 'transparent',
        color: action.value === selectedAction ? P.accent : P.text,
        fontFamily: FONT, fontSize: '11px', fontWeight: '500',
        cursor: 'pointer',
        transition: 'background 0.1s ease, color 0.1s ease',
        textAlign: 'center', whiteSpace: 'nowrap',
      });
      const iconWrap = el('span', {
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        height: '20px', opacity: '0.9',
      });
      iconWrap.innerHTML = ICONS[action.value] || '';
      const labelEl = el('span', { lineHeight: '1' });
      labelEl.textContent = action.label;
      chip.appendChild(iconWrap);
      chip.appendChild(labelEl);
      chip.dataset.action = action.value;
      chip.addEventListener('mouseenter', () => {
        if (action.value !== selectedAction) chip.style.background = P.accentSoft;
      });
      chip.addEventListener('mouseleave', () => {
        chip.style.background = action.value === selectedAction ? P.accentSoft : 'transparent';
      });
      chip.addEventListener('click', (e) => {
        e.preventDefault();
        e.stopPropagation();
        const prompt = uiGetById(PREFIX + '-input')?.value || '';
        selectedAction = action.value;
        hideActionPicker();
        updateBarContent('configure');
        const input = uiGetById(PREFIX + '-input');
        if (input && prompt) input.value = prompt;
      });
      grid.appendChild(chip);
    });

    pickerEl.appendChild(grid);
    uiAppend(pickerEl);
    defangOutsideHandlers(pickerEl);

    // Cache the palette on the picker so toggleActionPicker's state refresh
    // uses the same theme-aware colors when it repaints chips.
    pickerEl.__iceq_palette = P;
  }

  function toggleActionPicker() {
    if (pendingApplyInFlight) { showManualApplyBusyToast(); return; }
    if (pickerEl.style.display !== 'none') { hideActionPicker(); return; }
    // Rebuild chips to reflect current selection
    const P = pickerEl.__iceq_palette || barPaletteForTheme(detectPageTheme());
    pickerEl.querySelectorAll('button').forEach(chip => {
      const isActive = chip.dataset.action === selectedAction;
      chip.style.background = isActive ? P.accentSoft : 'transparent';
      chip.style.color = isActive ? P.accent : P.text;
    });
    // Position above the bar, right-aligned to the configure bar edge.
    const barRect = barEl.getBoundingClientRect();
    const pickerH = 170; // approximate; grows with icon + label rows
    let top = barRect.top - pickerH - 6;
    if (top < 8) top = barRect.bottom + 6;
    pickerEl.style.display = 'block';
    const pickerW = pickerEl.offsetWidth;
    let left = barRect.right - pickerW;
    left = Math.max(8, Math.min(left, window.innerWidth - pickerW - 8));
    Object.assign(pickerEl.style, {
      top: top + 'px',
      left: left + 'px',
    });
    requestAnimationFrame(() => {
      pickerEl.style.opacity = '1';
      pickerEl.style.transform = 'scale(1) translateY(0)';
    });
  }

  function hideActionPicker() {
    if (!pickerEl) return;
    pickerEl.style.opacity = '0';
    pickerEl.style.transform = 'scale(0.96) translateY(4px)';
    setTimeout(() => { if (pickerEl) pickerEl.style.display = 'none'; }, 180);
  }

  function ensureCyclingRenderable(reason) {
    if (arrivedVariants > 0) {
      if (visibleVariant < 1 || visibleVariant > arrivedVariants) visibleVariant = 1;
      return true;
    }
    recoverEmptyCycling(reason);
    return false;
  }

  function recoverEmptyCycling(reason) {
    if (recoveringEmptyCycling) return;
    recoveringEmptyCycling = true;
    try {
      console.warn('[impeccable] Refusing to render empty variant cycling state:', reason);
      const message = 'No variants were mounted. Please try again.';
      if (svelteComponentSession?.sessionId === currentSessionId) {
        resetSvelteComponentSession(currentSessionId, message);
        return;
      }
      cleanup();
      showToast(message, 5000);
    } finally {
      recoveringEmptyCycling = false;
    }
  }

  //
  // Params panel (per-variant coarse controls)
  //
  // Variants may declare a parameter manifest via a JSON attribute on the
  // variant wrapper:
  //
  //   <div data-impeccable-variant="1"
  //        data-impeccable-params='[{"id":"density","kind":"steps",...}]'>
  //
  // The panel docks to the right edge of the outline during CYCLING and
  // exposes 2-5 coarse knobs. Values apply to the variant wrapper so scoped
  // CSS can respond instantly without regeneration:
  //
  //   range  / numeric toggle  -> CSS custom property used by variant styles
  //   steps  / boolean toggle  → data-p-<id> attribute  used via :scope[data-p-foo="..."]
  //
  // On variant switch, values reset to that variant's declared defaults.
  // On accept, current values are sent in the event payload so the agent
  // can bake them into the source-file write.
  //

  let paramsPanelEl = null;     // outer wrapper (overflow:hidden, clips the slide)
  let paramsPanelInner = null;  // translating content (carries bg, padding, knobs)
  let paramsPanelBody = null;   // grid holding the knob cells
  let paramsCurrentValues = {}; // {paramId: value} - mirror of the visible variant's live values
  let tuneOpen = false;         // whether the Tune popover is open right now

  // Theme-aware Tune popover. Appears as a drawer that slides out from the
  // contextual bar's bar-facing edge (below if the bar sits below the
  // element, above otherwise). Same width as the bar. Auto-wraps to extra
  // rows when the knobs exceed one row. The bar's border-radius on the
  // popover side goes flat while open so the two shapes read as one.
  let paramsPanelPalette = null;

  function initParamsPanel() {
    paramsPanelPalette = barPaletteForTheme(detectPageTheme());
    const P = paramsPanelPalette;

    // Single element, always in the DOM. The slide animation is a CSS mask
    // with mask-size growing from 0% to 100% along the bar-facing axis - no
    // display toggle, no opacity toggle, no transform trickery. The mask
    // hides everything initially; as it grows, content is revealed from
    // the bar edge outward.
    paramsPanelEl = document.createElement('div');
    paramsPanelEl.id = PREFIX + '-params-panel';
    Object.assign(paramsPanelEl.style, {
      position: 'fixed', zIndex: String(Z.bar - 1),
      background: P.surfaceDeep,
      color: P.text,
      fontFamily: FONT,
      padding: '14px 18px',
      boxSizing: 'border-box',
      borderRadius: '0 0 10px 10px',
      pointerEvents: 'none',

      // clip-path is the same conceptual reveal as mask but with rock-solid
      // transition support across engines. Closed state clips from the far
      // edge; open = inset(0) shows everything.
      clipPath: 'inset(0 0 100% 0)',
      transition: 'clip-path 0.44s ' + EASE,

      // Park off-screen until positionParamsPanel places it. These are NOT
      // in the transition list, so they snap instantly - no fly-in from the
      // top-left when first shown.
      top: '-9999px', left: '-9999px', width: '0',
    });

    paramsPanelBody = el('div', {
      display: 'grid',
      gridTemplateColumns: 'repeat(auto-fit, minmax(120px, 1fr))',
      gap: '12px 16px',
    });

    paramsPanelEl.appendChild(paramsPanelBody);
    uiAppend(paramsPanelEl);
    // Don't override pointer-events: the panel toggles between 'none' (closed,
    // click-through) and 'auto' (open) on its own. Just silence the host's
    // outside-interaction listeners while the panel is open.
    defangOutsideHandlers(paramsPanelEl, { setPointerEvents: false });
    paramsPanelInner = paramsPanelEl; // compatibility alias for the rest of the code
  }


  function getMountedSvelteComponentAnchor(session = svelteComponentSession) {
    const el = session?.mountTargetEl?.firstElementChild || null;
    if (!el || !document.body.contains(el)) return null;
    return rectIsUsableAnchor(el.getBoundingClientRect()) ? el : null;
  }

  function resolveSvelteComponentAnchor(session = svelteComponentSession) {
    return getMountedSvelteComponentAnchor(session)
      || session?.swapAnchor
      || null;
  }

  function getVisibleVariantEl() {
    if (!currentSessionId) return null;
    if (svelteComponentSession?.sessionId === currentSessionId) {
      return resolveSvelteComponentAnchor()
        || svelteComponentSession.wrapperEl
        || null;
    }
    const wrapper = document.querySelector('[data-impeccable-variants="' + currentSessionId + '"]');
    if (!wrapper) return null;
    return wrapper.querySelector('[data-impeccable-variant="' + visibleVariant + '"]');
  }

  function parseVariantParams(variantEl) {
    // Svelte component variants can't carry a `data-impeccable-params` attribute:
    // the compiler reads `{` inside attribute values as expression delimiters, so
    // JSON-with-braces breaks the build. For that path the params live in a sidecar
    // params.json keyed by variant number, loaded into the session at mount time.
    if (svelteComponentSession?.sessionId === currentSessionId) {
      const byVariant = svelteComponentSession.paramsByVariant || {};
      const params = byVariant[String(visibleVariant)] || byVariant[visibleVariant];
      return Array.isArray(params) ? params : [];
    }
    if (!variantEl) return [];
    const raw = variantEl.getAttribute('data-impeccable-params');
    if (!raw) return [];
    try {
      const parsed = JSON.parse(raw);
      return Array.isArray(parsed) ? parsed : [];
    } catch (err) {
      console.warn('[impeccable] Invalid data-impeccable-params JSON:', err.message);
      return [];
    }
  }

  function applyParamValue(variantEl, param, value) {
    if (!variantEl) return;
    const attr = 'data-p-' + param.id;
    if (param.kind === 'toggle') {
      const on = !!value;
      if (on) variantEl.setAttribute(attr, 'on');
      else variantEl.removeAttribute(attr);
    } else if (param.kind === 'steps') {
      variantEl.setAttribute(attr, String(value));
    }
    // Svelte component variants are client-mounted into
    // [data-impeccable-component-mount] with no [data-impeccable-variant="N"]
    // wrapper for the state stylesheet to target, and the element is not SSR'd,
    // so there is no React hydration to mismatch. Drive range/toggle --p-* inline
    // on the mounted element so scoped preview CSS resolves them.
    if (svelteComponentSession?.sessionId === currentSessionId) {
      if (param.kind === 'range') variantEl.style.setProperty('--p-' + param.id, String(value));
      else if (param.kind === 'toggle') variantEl.style.setProperty('--p-' + param.id, value ? '1' : '0');
      return;
    }
    // range/toggle --p-* custom properties are driven through the injected
    // variant-state stylesheet so we never mutate inline style on SSR'd divs.
    updateVariantStateStylesheet(currentSessionId, visibleVariant);
  }

  function applyParamDefaults(variantEl, params) {
    paramsCurrentValues = {};
    for (const p of params) {
      paramsCurrentValues[p.id] = p.default;
      applyParamValue(variantEl, p, p.default);
    }
  }

  function formatRangeValue(input) {
    const max = parseFloat(input.max), min = parseFloat(input.min);
    const v = parseFloat(input.value);
    if (!isFinite(v)) return input.value;
    return (max - min) <= 2 ? v.toFixed(2) : String(Math.round(v));
  }

  function buildParamsPanel(variantEl, params) {
    const P = paramsPanelPalette || barPaletteForTheme(detectPageTheme());
    paramsPanelBody.innerHTML = '';
    for (const p of params) {
      const row = el('div', { display: 'flex', flexDirection: 'column', gap: '6px' });
      const labelRow = el('div', {
        display: 'flex', justifyContent: 'space-between',
        alignItems: 'baseline', gap: '8px',
      });
      const lbl = el('span', {
        fontSize: '10.5px', fontWeight: '600', color: P.text,
        letterSpacing: '0.03em',
      });
      lbl.textContent = p.label || p.id;
      labelRow.appendChild(lbl);
      const readout = el('span', {
        fontSize: '10.5px', color: P.textDim,
        fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',
      });
      labelRow.appendChild(readout);
      row.appendChild(labelRow);

      if (p.kind === 'range') {
        const input = document.createElement('input');
        input.type = 'range';
        input.min = String(p.min != null ? p.min : 0);
        input.max = String(p.max != null ? p.max : 1);
        input.step = String(p.step != null ? p.step : 0.05);
        input.value = String(p.default);
        Object.assign(input.style, {
          width: '100%', accentColor: C.brand, cursor: 'pointer',
        });
        readout.textContent = formatRangeValue(input);
        input.addEventListener('input', (e) => {
          e.stopPropagation();
          const v = parseFloat(input.value);
          paramsCurrentValues[p.id] = v;
          readout.textContent = formatRangeValue(input);
          applyParamValue(variantEl, p, v);
          queueCheckpoint('param_changed');
        });
        row.appendChild(input);
      } else if (p.kind === 'toggle') {
        const initial = !!p.default;
        readout.textContent = initial ? 'On' : 'Off';
        const track = el('button', {
          position: 'relative', width: '36px', height: '20px',
          borderRadius: '10px', border: 'none', padding: '0',
          cursor: 'pointer',
          background: initial ? C.brand : P.hairline,
          transition: 'background 0.15s ease',
          alignSelf: 'flex-start',
        });
        const knob = el('span', {
          position: 'absolute', top: '2px',
          left: initial ? '18px' : '2px',
          width: '16px', height: '16px', borderRadius: '50%',
          background: C.ink,
          transition: 'left 0.18s ' + EASE,
          boxShadow: '0 1px 2px oklch(0% 0 0 / 0.2)',
        });
        track.appendChild(knob);
        track.addEventListener('click', (e) => {
          e.stopPropagation();
          const next = !paramsCurrentValues[p.id];
          paramsCurrentValues[p.id] = next;
          track.style.background = next ? C.brand : P.hairline;
          knob.style.left = next ? '18px' : '2px';
          readout.textContent = next ? 'On' : 'Off';
          applyParamValue(variantEl, p, next);
          queueCheckpoint('param_changed');
        });
        row.appendChild(track);
      } else if (p.kind === 'steps') {
        const opts = (p.options || []).map(o =>
          typeof o === 'string' ? { value: o, label: o } : o
        );
        const activeOpt = opts.find(o => o.value === p.default) || opts[0];
        readout.textContent = activeOpt ? activeOpt.label : String(p.default);
        const segRow = el('div', {
          display: 'grid',
          gridTemplateColumns: 'repeat(' + opts.length + ', 1fr)',
          gap: '1px', padding: '2px',
          background: P.hairline, borderRadius: '5px',
        });
        const segBtns = [];
        opts.forEach(o => {
          const active = o.value === p.default;
          const b = el('button', {
            padding: '5px 4px', border: 'none', borderRadius: '3px',
            background: active ? C.brand : 'transparent',
            color: active ? C.ink : P.text,
            fontFamily: FONT, fontSize: '10.5px', fontWeight: '500',
            cursor: 'pointer', whiteSpace: 'nowrap',
            transition: 'background 0.1s ease, color 0.1s ease',
          });
          b.textContent = o.label;
          b.addEventListener('click', (e) => {
            e.stopPropagation();
            paramsCurrentValues[p.id] = o.value;
            readout.textContent = o.label;
            segBtns.forEach(({ btn, val }) => {
              const on = val === o.value;
              btn.style.background = on ? C.brand : 'transparent';
              btn.style.color = on ? C.ink : P.text;
            });
            applyParamValue(variantEl, p, o.value);
            queueCheckpoint('param_changed');
          });
          segRow.appendChild(b);
          segBtns.push({ btn: b, val: o.value });
        });
        row.appendChild(segRow);
      }

      paramsPanelBody.appendChild(row);
    }
  }

  //
  // Inline text editing - makes pure-text descendants of the picked element
  // directly contenteditable. Save stages copy edits in the live buffer; the
  // Apply copy edits dock later asks the AI to apply the staged batch.
  //

  let inlineEditRows = [];
  let inlineEditDrafts = new Map();

  // Mixed-content elements (e.g. <p>text<code>x</code>text</p>) skip the row
  // walker's "all-children-are-text-nodes" rule. Wrap each non-whitespace direct
  // text-node child in a marker span so the walker emits a row for it. The
  // wrappers are inline display by default and inherit styles, so the page
  // shouldn't visually shift. We unwrap in disableInlineEdit.
  const MIXED_WRAP_SKIP = { script: 1, style: 1, template: 1, noscript: 1, svg: 1, code: 1, pre: 1 };

  function collectEditableTextRows(rootEl, opts) {
    if (!rootEl || rootEl.nodeType !== 1) return [];
    const isOwn = (opts && opts.isOwn) || (() => false);
    const rows = [];

    function visit(el) {
      if (!el || el.nodeType !== 1) return;
      const tag = el.tagName.toLowerCase();
      if (MIXED_WRAP_SKIP[tag]) return;
      if (el.hasAttribute && el.hasAttribute('contenteditable')) return;
      if (el !== rootEl && isOwn(el)) return;

      const children = Array.from(el.childNodes);
      const textNodes = [];
      let allText = children.length > 0;
      let hasNonWhitespaceText = false;
      for (const node of children) {
        if (node.nodeType === 3) {
          textNodes.push(node);
          if (node.nodeValue && /\S/.test(node.nodeValue)) hasNonWhitespaceText = true;
        } else {
          allText = false;
        }
      }
      if (allText && hasNonWhitespaceText) {
        rows.push({
          el,
          ref: documentRefForElement(el) || el.tagName.toLowerCase(),
          text: textNodes.map((node) => node.nodeValue).join(''),
          textNodes,
        });
      }

      for (const child of children) {
        if (child.nodeType === 1) visit(child);
      }
    }

    visit(rootEl);
    return rows;
  }

  function wrapMixedContentTextNodes(rootEl) {
    if (!rootEl || rootEl.nodeType !== 1) return;
    const tag = rootEl.tagName.toLowerCase();
    if (MIXED_WRAP_SKIP[tag]) return;
    if (rootEl.hasAttribute('contenteditable')) return;
    const children = Array.from(rootEl.childNodes);
    const hasText = children.some((n) => n.nodeType === 3 && /\S/.test(n.nodeValue || ''));
    const hasElement = children.some((n) => n.nodeType === 1);
    if (hasText && hasElement) {
      for (const node of children) {
        if (node.nodeType === 3 && /\S/.test(node.nodeValue || '')) {
          const wrap = document.createElement('span');
          wrap.dataset.impeccableTextWrap = 'true';
          wrap.textContent = node.nodeValue;
          rootEl.insertBefore(wrap, node);
          rootEl.removeChild(node);
        }
      }
    }
    for (const child of Array.from(rootEl.children)) {
      if (!child.dataset || !child.dataset.impeccableTextWrap) {
        wrapMixedContentTextNodes(child);
      }
    }
  }
  function unwrapMixedContentTextNodes(rootEl) {
    if (!rootEl || rootEl.nodeType !== 1) return;
    const wraps = rootEl.querySelectorAll('[data-impeccable-text-wrap="true"]');
    for (const wrap of wraps) {
      const parent = wrap.parentNode;
      if (!parent) continue;
      const textNode = document.createTextNode(wrap.textContent);
      parent.replaceChild(textNode, wrap);
      parent.normalize();
    }
  }
  let inlineEditRoot = null;

  function enableInlineEdit(targetEl) {
    if (!targetEl) return;
    inlineEditRoot = targetEl;
    wrapMixedContentTextNodes(targetEl);
    const rows = collectEditableTextRows(targetEl, { isOwn: own });
    inlineEditRows = rows;
    inlineEditDrafts = new Map();
    for (const row of rows) {
      row.inlineWhiteSpace = row.el.style.whiteSpace;
      row.el.style.whiteSpace = getComputedStyle(row.el).whiteSpace;
      row.el.setAttribute('contenteditable', 'true');
      row.el.dataset.impeccableEditable = 'true';
      row.el.dataset.impeccableOriginalText = row.text;
      row.el.style.userSelect = 'text';
      row.el.style.cursor = 'text';
      row.el.style.outline = 'none';
      row.el.addEventListener('input', onInlineInput);
    }
  }

  function disableInlineEdit(opts = {}) {
    for (const row of inlineEditRows) {
      if (activeElementDeep() === row.el) row.el.blur();
      row.el.removeAttribute('contenteditable');
      delete row.el.dataset.impeccableEditable;
      delete row.el.dataset.impeccableOriginalText;
      row.el.style.whiteSpace = row.inlineWhiteSpace || '';
      row.el.style.userSelect = '';
      row.el.style.cursor = '';
      row.el.style.outline = '';
      row.el.removeEventListener('input', onInlineInput);
    }
    inlineEditRows = [];
    inlineEditDrafts = new Map();
    if (inlineEditRoot && !opts.preserveMixedWraps) {
      unwrapMixedContentTextNodes(inlineEditRoot);
      inlineEditRoot = null;
    }
  }

  function onInlineInput(e) {
    inlineEditDrafts.set(e.currentTarget, e.currentTarget.textContent);
  }

  function hasTextRows(el) {
    if (!el) return false;
    // Lightweight: any descendant outside SKIP_SUBTREE_TAGS with at least one
    // non-whitespace direct text-node child means we have something editable
    // (mixed-content paragraphs included). Mirrors what the wrap+walk path
    // will produce in enableInlineEdit.
    function check(node) {
      if (!node || node.nodeType !== 1) return false;
      const tag = node.tagName.toLowerCase();
      if (MIXED_WRAP_SKIP[tag]) return false;
      if (node !== el && own(node)) return false;
      for (const child of node.childNodes) {
        if (child.nodeType === 3 && /\S/.test(child.nodeValue || '')) return true;
      }
      for (const child of node.children) {
        if (check(child)) return true;
      }
      return false;
    }
    return check(el);
  }

  function enterEditingMode() {
    if (pendingApplyInFlight) { showManualApplyBusyToast(); return; }
    setLiveState('EDITING');
    hideBar();
    hideAnnotOverlay();
    renderEditBadge('editing');
    enableInlineEdit(selectedElement);
    // Focus first editable element and position cursor at end
    if (inlineEditRows.length > 0) {
      const firstEditable = inlineEditRows[0] && inlineEditRows[0].el;
      setTimeout(() => {
        const el = firstEditable;
        if (!el || !el.isConnected || state !== 'EDITING') return;
        el.focus();
        const range = document.createRange();
        const sel = window.getSelection();
        range.selectNodeContents(el);
        range.collapse(false);
        sel.removeAllRanges();
        sel.addRange(range);
      }, 50);
    }
  }

  function restoreInlineEditDrafts() {
    for (const row of inlineEditRows) {
      if (inlineEditDrafts.has(row.el)) {
        row.el.textContent = row.el.dataset.impeccableOriginalText;
      }
    }
  }

  function cancelEditing() {
    restoreInlineEditDrafts();
    disableInlineEdit();
    setLiveState('CONFIGURING');
    showBar('configure');
    showAnnotOverlay(selectedElement);
    renderEditBadge('idle');
  }

  function cancelEditingToPicking() {
    restoreInlineEditDrafts();
    disableInlineEdit();
    hideBar();
    stopScrollTracking();
    hideAnnotOverlay();
    clearAnnotations();
    renderEditBadge('hidden');
    setLiveState('PICKING');
    hoveredElement = null;
    hideHighlight();
    syncPageChatFocus('editing-outside-click');
  }

  function teardownConfigureChrome() {
    hideConfigureBarTooltip();
    // hideBar() restores unsaved EDITING drafts before it disables inline
    // edit; disabling here first would wipe the draft metadata it needs.
    hideBar();
    stopScrollTracking();
    hideAnnotOverlay();
    clearAnnotations();
    renderEditBadge('hidden');
  }

  function exitConfigureToPicking(reason, opts = {}) {
    teardownConfigureChrome();
    setLiveState('PICKING');
    if (opts.clearHover) {
      hoveredElement = null;
      hideHighlight();
    }
    syncPageChatFocus(reason);
  }

  // Prefer the leaf's own id/class; if it has neither (e.g. a bare <em>),
  // climb to the nearest ancestor with one. The CLI uses tag+class together,
  // so tag must come from the same node as the locator.
  function buildLocatorForLeaf(leafEl, fallbackEl) {
    if (leafEl && (leafEl.id || leafEl.classList.length > 0)) {
      return {
        tag: leafEl.tagName.toLowerCase(),
        elementId: leafEl.id || null,
        classes: [...leafEl.classList],
      };
    }
    let cur = leafEl?.parentElement;
    while (cur && cur !== document.body) {
      if (cur.id || cur.classList.length > 0) {
        return {
          tag: cur.tagName.toLowerCase(),
          elementId: cur.id || null,
          classes: [...cur.classList],
        };
      }
      cur = cur.parentElement;
    }
    return {
      tag: (fallbackEl || leafEl).tagName.toLowerCase(),
      elementId: (fallbackEl || leafEl).id || null,
      classes: [...((fallbackEl || leafEl).classList || [])],
    };
  }

  function sourceHintForElement(el) {
    if (!el || !el.getAttribute) return null;
    const file = el.getAttribute('data-astro-source-file');
    const loc = el.getAttribute('data-astro-source-loc');
    if (file || loc) {
      const parsed = parseSourceLoc(loc);
      return {
        file: file || '',
        loc: loc || '',
        line: parsed.line,
        column: parsed.column,
      };
    }
    return null;
  }

  function parseSourceLoc(loc) {
    const match = String(loc || '').match(/^(\d+)(?::(\d+))?/);
    return {
      line: match ? Number(match[1]) : null,
      column: match && match[2] ? Number(match[2]) : null,
    };
  }

  function documentRefForElement(el) {
    if (!el || el.nodeType !== 1) return null;
    const parts = [];
    let cur = el;
    while (cur && cur.nodeType === 1) {
      const tag = cur.tagName.toLowerCase();
      if (tag === 'html') break;
      if (tag === 'body') {
        parts.unshift('body');
        break;
      }
      parts.unshift(documentRefSegment(cur));
      cur = cur.parentElement;
    }
    return parts.join('>') || null;
  }

  function documentRefSegment(el) {
    const tag = el.tagName.toLowerCase();
    return tag + documentRefIdSuffix(el) + documentRefClassSuffix(el) + ':nth-of-type(' + indexAmongSameTag(el) + ')';
  }

  function documentRefIdSuffix(el) {
    return el.id ? '#' + normalizeDocumentRefToken(el.id) : '';
  }

  function documentRefClassSuffix(el) {
    if (!el.classList || el.classList.length === 0) return '';
    const classes = [];
    for (const cls of el.classList) {
      if (!cls || cls.indexOf('impeccable-') === 0) continue;
      classes.push(normalizeDocumentRefToken(cls));
      if (classes.length === 2) break;
    }
    return classes.length ? '.' + classes.join('.') : '';
  }

  function normalizeDocumentRefToken(value) {
    return String(value || '').replace(/[>\s]+/g, '_');
  }

  function indexAmongSameTag(el) {
    const parent = el.parentElement;
    if (!parent) return 1;
    const tag = el.tagName.toLowerCase();
    let n = 0;
    for (const sib of parent.children) {
      if (sib.tagName.toLowerCase() === tag) {
        n++;
        if (sib === el) return n;
      }
    }
    return 1;
  }

  function copyEditLeafContext(el, originalText, newText) {
    if (!el) return null;
    return {
      ref: documentRefForElement(el),
      tagName: el.tagName ? el.tagName.toLowerCase() : null,
      id: el.id || null,
      classes: el.classList ? [...el.classList].filter((cls) => cls.indexOf('impeccable-') !== 0) : [],
      originalText,
      newText,
      textContent: (el.textContent || '').slice(0, 500),
      outerHTML: sanitizedContextOuterHTML(el, 3000) || null,
    };
  }

  function nearbyEditableTextsForManualEdit(rows, activeEl, originalText, newText) {
    const out = [];
    const seen = new Set();
    const skip = new Set([normalizeManualContextText(originalText), normalizeManualContextText(newText)]);
    for (const row of rows || []) {
      if (!row || row.el === activeEl) continue;
      const text = normalizeManualContextText(row.text);
      if (!text || text.length < 2 || seen.has(text) || skip.has(text)) continue;
      seen.add(text);
      out.push({
        ref: documentRefForElement(row.el),
        tag: row.el?.tagName ? row.el.tagName.toLowerCase() : null,
        classes: row.el?.classList ? [...row.el.classList].filter((cls) => cls.indexOf('impeccable-') !== 0) : [],
        text,
      });
      if (out.length >= 12) break;
    }
    return out;
  }

  function copyEditContainerContext(el) {
    if (!el) return null;
    return {
      ref: documentRefForElement(el),
      tagName: el.tagName ? el.tagName.toLowerCase() : null,
      id: el.id || null,
      classes: el.classList ? [...el.classList].filter((cls) => cls.indexOf('impeccable-') !== 0) : [],
      textContent: (el.textContent || '').slice(0, 1000),
      outerHTML: sanitizedContextOuterHTML(el, 10000) || null,
    };
  }

  function forbiddenManualTextChars(text) {
    const out = [];
    for (const ch of ['<', '{', '}', '`']) {
      if (String(text || '').includes(ch)) out.push(ch);
    }
    return out;
  }

  async function applyEditing() {
    if (pendingApplyInFlight) { showManualApplyBusyToast(); return; }
    const ops = [];
    for (const row of inlineEditRows) {
      const newText = inlineEditDrafts.get(row.el);
      if (newText !== undefined && newText !== row.text) {
        if (String(newText || '').trim() === '') {
          showToast('Save rejected: copy edits cannot be empty.', 5500);
          return;
        }
        const forbidden = forbiddenManualTextChars(newText);
        if (forbidden.length > 0) {
          showToast('Save rejected: newText cannot contain ' + forbidden.join(' ') + ' (plain text only; ask the AI to insert markup)', 5500);
          return;
        }
        const locator = buildLocatorForLeaf(row.el, selectedElement);
        const op = {
          ref: row.ref,
          tag: locator.tag,
          elementId: locator.elementId,
          classes: locator.classes,
          originalText: row.text,
          newText,
        };
        op.leaf = copyEditLeafContext(row.el, row.text, newText);
        op.nearbyEditableTexts = nearbyEditableTextsForManualEdit(inlineEditRows, row.el, row.text, newText);
        const restoreHint = mixedTextWrapRestoreHint(row.el);
        if (restoreHint) op.restore = restoreHint;
        const sourceHint = sourceHintForElement(row.el);
        if (sourceHint) op.sourceHint = sourceHint;
        ops.push(op);
      }
    }
    if (ops.length === 0) { cancelEditing(); return; }
    const contextElement = contextElementForManualEdit(selectedElement, inlineEditRows, ops);
    const contextRef = documentRefForElement(contextElement);
    if (contextRef) for (const op of ops) op.contextRef = contextRef;
    const container = copyEditContainerContext(contextElement);
    if (container) for (const op of ops) op.container = container;
    try {
      // Token in the query string as well as the body: the URL token is what
      // authorizes the CORS preflight when the page runs on a non-loopback
      // dev host (ddev, Valet), since the preflight carries no request body.
      const res = await fetch('http://localhost:' + PORT + '/manual-edit-stash?token=' + encodeURIComponent(TOKEN), {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          token: TOKEN,
          id: id8(),
          pageUrl: location.pathname,
          element: extractContext(contextElement),
          ops,
        }),
      });
      if (!res.ok) {
        const errBody = await res.json().catch(() => ({}));
        throw new Error(errBody.error || ('HTTP ' + res.status));
      }
      const stashResult = await res.json();
      updatePendingCounter(stashResult.pendingCount || 0);
      maybeShowFirstSaveToast();
      disableInlineEdit();
      setLiveState('CONFIGURING');
      showBar('configure');
      showAnnotOverlay(selectedElement);
      renderEditBadge('idle');
    } catch (err) {
      console.error('[impeccable] manual edit stash failed:', err);
      const detail = String(err?.message || '');
      if (detail.includes('newText cannot contain') || detail.includes('newText cannot be empty')) {
        showToast('Save rejected: ' + detail.replace(/^manual_edits:\s*/, ''), 5500);
      } else {
        showToast('Save failed - retry or cancel', 4000);
      }
    }
  }

  function schedulePendingDockPosition() {
    if (!pendingDockEl || !globalBarEl) return;
    requestAnimationFrame(positionPendingDock);
  }

  function positionPendingDock() {
    if (!pendingDockEl || !globalBarEl) return;
    const width = globalBarEl.offsetWidth;
    const height = globalBarEl.offsetHeight;
    if (!width || !height) return;
    pendingDockEl.style.left = Math.round((window.innerWidth / 2) - (width / 2) - 18) + 'px';
    pendingDockEl.style.top = 'auto';
    pendingDockEl.style.bottom = Math.round(14 + (height / 2)) + 'px';
  }

  function playPendingIntroAnimation() {
    if (!pendingPillEl || !pendingPillEl.animate || (matchMedia?.('(prefers-reduced-motion: reduce)').matches)) return;
    if (pendingIntroAnimation) pendingIntroAnimation.cancel();
    pendingIntroAnimation = pendingPillEl.animate([
      {
        opacity: 0,
        transform: 'scale(0.82)',
        filter: 'brightness(1.2)',
        boxShadow: '0 0 0 0 oklch(84% 0.19 80.46 / 0.45), 0 8px 24px oklch(0% 0 0 / 0.16)',
      },
      {
        opacity: 1,
        transform: 'scale(1.08)',
        filter: 'brightness(1.15)',
        boxShadow: '0 0 0 12px oklch(84% 0.19 80.46 / 0), 0 12px 34px oklch(0% 0 0 / 0.22)',
        offset: 0.55,
      },
      {
        opacity: 1,
        transform: 'scale(1)',
        filter: 'none',
        boxShadow: '0 4px 16px oklch(0% 0 0 / 0.16), 0 1px 3px oklch(0% 0 0 / 0.1)',
      },
    ], { duration: 620, easing: EASE });
    pendingIntroAnimation.addEventListener('finish', () => { pendingIntroAnimation = null; }, { once: true });
  }

  function ensureSpinKeyframes() {
    if (uiGetById(PREFIX + '-keyframes')) return;
    const style = document.createElement('style');
    style.id = PREFIX + '-keyframes';
    style.textContent = '@keyframes impeccable-spin { to { transform: rotate(360deg); } }';
    uiAppendStyle(style);
  }

  function pendingApplyLabel(count) {
    return count === 1 ? 'Apply copy edit' : 'Apply copy edits';
  }

  function showManualApplyBusyToast() {
    showToast('Apply is still running. Wait for it to finish.', 2800);
  }

  function manualApplyStateKey() {
    return PREFIX + ':manual-apply:' + PORT + ':' + TOKEN + ':' + location.pathname;
  }

  function readStoredManualApplyState() {
    try {
      const raw = sessionStorage.getItem(manualApplyStateKey());
      if (!raw) return null;
      const storedState = JSON.parse(raw);
      if (!storedState || storedState.pageUrl !== location.pathname || Date.now() > Number(storedState.expiresAt || 0)) {
        sessionStorage.removeItem(manualApplyStateKey());
        return null;
      }
      return storedState;
    } catch {
      return null;
    }
  }

  function writeManualApplyState(applyState) {
    try {
      sessionStorage.setItem(manualApplyStateKey(), JSON.stringify({
        ...applyState,
        pageUrl: location.pathname,
        updatedAt: Date.now(),
        expiresAt: Date.now() + MANUAL_APPLY_STATE_TTL_MS,
      }));
    } catch {
      // Best-effort only. The in-memory flag still covers non-reload flows.
    }
  }

  function storeManualApplyState(count, patch) {
    const currentCount = Number(count) || 0;
    const existing = readStoredManualApplyState() || {};
    const totalOps = Number(existing.totalOps) || Number(existing.count) || currentCount;
    if (totalOps <= 0 && currentCount <= 0) return;
    writeManualApplyState({
      count: Number(existing.count) || currentCount || totalOps,
      totalOps: totalOps || currentCount,
      completedOps: Number(existing.completedOps) || 0,
      remainingCount: Number.isFinite(Number(existing.remainingCount)) ? Number(existing.remainingCount) : currentCount,
      phase: existing.phase || 'applying',
      startedAt: Number(existing.startedAt) || Date.now(),
      ...(patch || {}),
    });
  }

  function clearStoredManualApplyState() {
    try {
      sessionStorage.removeItem(manualApplyStateKey());
    } catch {
      // Ignore storage failures; UI state can still clear in memory.
    }
  }

  function shouldResumeManualApplyLoading(count) {
    return Number(count) > 0 && readStoredManualApplyState() !== null;
  }

  function manualApplyLoadingText(fallbackCount) {
    const stored = readStoredManualApplyState();
    if (stored?.phase === 'repair-decision') return 'Apply needs attention';
    if (stored?.phase === 'repairing') {
      const attempt = Number(stored.repairAttempt) || 1;
      const max = Number(stored.repairMaxAttempts) || 3;
      return 'Fixing apply issue, attempt ' + attempt + '/' + max;
    }
    if (stored?.phase === 'verifying') return 'Verifying copy edits';
    const remaining = Number.isFinite(Number(stored?.remainingCount))
      ? Number(stored.remainingCount)
      : Number(fallbackCount) || 0;
    return remaining > 0
      ? 'Applying ' + remaining + ' copy edit' + (remaining === 1 ? '' : 's')
      : 'Verifying copy edits';
  }

  function resetManualApplyProgress(count) {
    const total = Number(count) || 0;
    if (total <= 0) return;
    writeManualApplyState({
      count: total,
      totalOps: total,
      completedOps: 0,
      remainingCount: total,
      phase: 'applying',
      startedAt: Date.now(),
    });
  }

  function updateManualApplyProgressFromChunk(chunk) {
    if (!chunk || !pendingApplyInFlight) return;
    const stored = readStoredManualApplyState() || {};
    const totalOps = Number(chunk.totalOpCount) || Number(stored.totalOps) || Number(stored.count) || parseInt(pendingPillEl?.dataset.count || '0', 10) || 0;
    const completedOps = Math.min(totalOps, (Number(stored.completedOps) || 0) + (Number(chunk.opCount) || 0));
    const remainingCount = Math.max(0, totalOps - completedOps);
    storeManualApplyState(Number(stored.count) || totalOps, {
      totalOps,
      completedOps,
      remainingCount,
      phase: remainingCount > 0 ? 'applying' : 'verifying',
    });
    setPendingApplyLoading(true, remainingCount);
  }

  function updateManualApplyRepairState(repair, phase) {
    const count = parseInt(pendingPillEl?.dataset.count || '0', 10) || Number(readStoredManualApplyState()?.count) || 0;
    if (count <= 0) return;
    storeManualApplyState(count, {
      phase,
      repairAttempt: Number(repair?.attempt || repair?.attempts) || 1,
      repairMaxAttempts: Number(repair?.maxAttempts) || 3,
    });
    setPendingApplyLoading(true, count);
  }

  function refreshLiveControlsForManualApply() {
    if (pendingApplyInFlight) {
      hideActionPicker();
      closeTunePopover();
    }
    if (barEl && barEl.style.display !== 'none' && state === 'CONFIGURING') {
      const input = uiGetById(PREFIX + '-input');
      const prompt = input ? input.value : '';
      updateBarContent('configure');
      const nextInput = uiGetById(PREFIX + '-input');
      if (nextInput) nextInput.value = prompt;
    }
    if (editBadgeEl && editBadgeEl.style.display !== 'none') {
      if (pendingApplyInFlight) renderEditBadge('idle-disabled');
      else if (state === 'CONFIGURING' && selectedElement && hasTextRows(selectedElement)) renderEditBadge('idle');
    }
    updateGlobalBarState();
  }

  function hidePendingApplyDock() {
    pendingApplyInFlight = false;
    clearStoredManualApplyState();
    if (pendingIntroAnimation) { pendingIntroAnimation.cancel(); pendingIntroAnimation = null; }
    if (pendingDockEl) pendingDockEl.style.display = 'none';
    if (pendingPillEl) {
      pendingPillEl.dataset.count = '0';
      pendingPillEl.style.display = 'none';
      pendingPillEl.disabled = false;
      pendingPillEl.setAttribute('aria-busy', 'false');
      pendingPillEl.setAttribute('aria-label', 'Apply copy edits to source');
      pendingPillEl.style.cursor = 'pointer';
      pendingPillEl.style.filter = 'none';
      pendingPillEl.style.transform = 'scale(1)';
    }
    if (pendingPillSpinnerEl) pendingPillSpinnerEl.style.display = 'none';
    if (pendingPillLabelEl) pendingPillLabelEl.textContent = pendingApplyLabel(0);
    if (pendingPillCountEl) {
      pendingPillCountEl.textContent = '0';
      pendingPillCountEl.style.display = 'inline-flex';
    }
    if (pendingTrashBtn) {
      pendingTrashBtn.style.display = 'none';
      pendingTrashBtn.disabled = false;
      pendingTrashBtn.style.cursor = 'pointer';
      pendingTrashBtn.style.opacity = '1';
    }
    if (pendingKeepFixingBtn) pendingKeepFixingBtn.style.display = 'none';
    if (pendingRollbackBtn) pendingRollbackBtn.style.display = 'none';
    refreshLiveControlsForManualApply();
  }

  function setPendingApplyLoading(loading, count) {
    if (!pendingPillEl || !pendingPillLabelEl || !pendingPillCountEl || !pendingTrashBtn) return;
    pendingApplyInFlight = loading === true;
    const currentCount = count || parseInt(pendingPillEl.dataset.count || '0', 10) || 0;
    if (pendingApplyInFlight) storeManualApplyState(currentCount);
    else clearStoredManualApplyState();
    if (pendingPillSpinnerEl) pendingPillSpinnerEl.style.display = pendingApplyInFlight ? 'inline-block' : 'none';
    pendingPillLabelEl.textContent = pendingApplyInFlight
      ? manualApplyLoadingText(currentCount)
      : pendingApplyLabel(currentCount);
    pendingPillCountEl.style.display = pendingApplyInFlight ? 'none' : 'inline-flex';
    pendingPillEl.disabled = pendingApplyInFlight;
    pendingPillEl.setAttribute('aria-busy', pendingApplyInFlight ? 'true' : 'false');
    pendingPillEl.style.cursor = pendingApplyInFlight ? 'wait' : 'pointer';
    pendingPillEl.style.filter = pendingApplyInFlight ? 'brightness(0.98)' : 'none';
    pendingPillEl.style.transform = 'scale(1)';
    pendingTrashBtn.disabled = pendingApplyInFlight;
    pendingTrashBtn.style.cursor = pendingApplyInFlight ? 'not-allowed' : 'pointer';
    pendingTrashBtn.style.opacity = pendingApplyInFlight ? '0.58' : '1';
    if (pendingApplyInFlight) {
      if (pendingKeepFixingBtn) pendingKeepFixingBtn.style.display = 'none';
      if (pendingRollbackBtn) pendingRollbackBtn.style.display = 'none';
      pendingTrashBtn.style.display = 'inline-flex';
    }
    schedulePendingDockPosition();
    refreshLiveControlsForManualApply();
  }

  function updatePendingCounter(currentPageCount) {
    if (!pendingDockEl || !pendingPillEl || !pendingPillLabelEl || !pendingPillCountEl || !pendingTrashBtn) return;
    const previousCount = parseInt(pendingPillEl.dataset.count || '0', 10);
    if (!currentPageCount || currentPageCount <= 0) {
      hidePendingApplyDock();
      return;
    }
    pendingPillLabelEl.textContent = pendingApplyLabel(currentPageCount);
    pendingPillCountEl.textContent = String(currentPageCount);
    pendingPillEl.setAttribute('aria-label', 'Apply ' + currentPageCount + ' copy edit' + (currentPageCount === 1 ? '' : 's') + ' to source');
    pendingPillEl.style.display = 'inline-flex';
    pendingTrashBtn.style.display = 'inline-flex';
    pendingDockEl.style.display = 'inline-flex';
    pendingPillEl.dataset.count = String(currentPageCount);
    if (pendingApplyInFlight || shouldResumeManualApplyLoading(currentPageCount)) setPendingApplyLoading(true, currentPageCount);
    schedulePendingDockPosition();
    if (previousCount <= 0) playPendingIntroAnimation();
  }

  function maybeShowFirstSaveToast() {
    if (!firstSaveOfSession) return;
    firstSaveOfSession = false;
    showToast('Saved. Click "Apply copy edits" to write changes.', 4500);
  }

  async function fetchPendingCount() {
    try {
      const res = await fetch(
        'http://localhost:' + PORT + '/manual-edit-stash?token=' + encodeURIComponent(TOKEN) + '&pageUrl=' + encodeURIComponent(location.pathname),
      );
      if (!res.ok) return;
      const data = await res.json();
      updatePendingCounter(data.count || 0);
    } catch (err) {
      console.warn('[impeccable] failed to fetch pending count:', err);
    }
  }

  async function onPendingPillClick() {
    const count = parseInt(pendingPillEl?.dataset.count || '0', 10);
    if (count <= 0 || pendingApplyInFlight) return;
    const ok = confirm('Apply ' + count + ' copy edit' + (count === 1 ? '' : 's') + ' to source?');
    if (!ok) return;
    let waitForSseCompletion = false;
    resetManualApplyProgress(count);
    setPendingApplyLoading(true, count);
    try {
      const res = await fetch(
        'http://localhost:' + PORT + '/manual-edit-commit?token=' + encodeURIComponent(TOKEN) + '&pageUrl=' + encodeURIComponent(location.pathname) + '&async=1',
        { method: 'POST', keepalive: true },
      );
      if (!res.ok) {
        const errBody = await res.json().catch(() => ({}));
        throw new Error(errBody.error || ('HTTP ' + res.status));
      }
      const result = await res.json();
      if (res.status === 202 || result.status === 'started') {
        waitForSseCompletion = true;
        return;
      }
      const remaining = remainingManualEditCount(result);
      updatePendingCounter(remaining);
      if (result.failed && result.failed.length > 0) {
        console.warn('[impeccable] some copy edits failed:', result.failed);
        showToast('Applied ' + (result.applied?.length || 0) + ', ' + result.failed.length + ' failed - see console', 5000);
      } else {
        const n = Array.isArray(result.applied) ? result.applied.length : (result.cleared || 0);
        if (n > 0) {
          showToast('Applied ' + n + ' edit' + (n === 1 ? '' : 's'), 2500);
        } else {
          console.warn('[impeccable] apply returned no verified edits:', result);
          showToast('No edits applied - see console', 4000);
        }
      }
    } catch (err) {
      console.error('[impeccable] commit failed:', err);
      showToast('Apply failed - see console', 4000);
    } finally {
      if (waitForSseCompletion) return;
      const remainingCount = parseInt(pendingPillEl?.dataset.count || '0', 10) || 0;
      if (remainingCount > 0) setPendingApplyLoading(false);
      else hidePendingApplyDock();
    }
  }

  async function onPendingTrashClick() {
    const count = parseInt(pendingPillEl?.dataset.count || '0', 10);
    if (count <= 0 || pendingApplyInFlight) return;
    const ok = confirm('Discard ' + count + ' copy edit' + (count === 1 ? '' : 's') + ' on this page?');
    if (!ok) return;
    try {
      const res = await fetch(
        'http://localhost:' + PORT + '/manual-edit-discard?token=' + encodeURIComponent(TOKEN) + '&pageUrl=' + encodeURIComponent(location.pathname),
        { method: 'POST' },
      );
      if (!res.ok) throw new Error('HTTP ' + res.status);
      const result = await res.json().catch(() => ({}));
      const restoreFailures = restoreDiscardedManualEdits(result.entries || []);
      updatePendingCounter(0);
      if (restoreFailures > 0) {
        showToast('Discarded ' + count + ' copy edit' + (count === 1 ? '' : 's') + ' - refresh to reset ' + restoreFailures, 4000);
      } else {
        showToast('Discarded ' + count + ' copy edit' + (count === 1 ? '' : 's'), 2500);
      }
    } catch (err) {
      console.error('[impeccable] discard failed:', err);
      showToast('Discard failed - see console', 4000);
    }
  }

  function showManualApplyDecision(msg) {
    const count = parseInt(pendingPillEl?.dataset.count || '0', 10) || numberOrNull(msg?.remainingCount) || 0;
    pendingApplyInFlight = false;
    storeManualApplyState(count, {
      phase: 'repair-decision',
      repairAttempt: numberOrNull(msg?.repair?.attempts) || numberOrNull(msg?.repair?.attempt) || 3,
      repairMaxAttempts: numberOrNull(msg?.repair?.maxAttempts) || 3,
    });
    if (pendingPillSpinnerEl) pendingPillSpinnerEl.style.display = 'none';
    if (pendingPillLabelEl) pendingPillLabelEl.textContent = 'Apply needs attention';
    if (pendingPillCountEl) pendingPillCountEl.style.display = 'none';
    if (pendingPillEl) {
      pendingPillEl.disabled = true;
      pendingPillEl.setAttribute('aria-busy', 'false');
      pendingPillEl.style.cursor = 'default';
      pendingPillEl.style.display = 'inline-flex';
    }
    if (pendingTrashBtn) pendingTrashBtn.style.display = 'none';
    if (pendingKeepFixingBtn) pendingKeepFixingBtn.style.display = 'inline-flex';
    if (pendingRollbackBtn) pendingRollbackBtn.style.display = 'inline-flex';
    if (pendingDockEl) pendingDockEl.style.display = 'inline-flex';
    schedulePendingDockPosition();
    refreshLiveControlsForManualApply();
  }

  async function onPendingKeepFixingClick() {
    const count = parseInt(pendingPillEl?.dataset.count || '0', 10) || numberOrNull(readStoredManualApplyState()?.count) || 0;
    if (count <= 0) return;
    updateManualApplyRepairState({ attempt: 1, maxAttempts: 3 }, 'repairing');
    try {
      const res = await fetch(
        'http://localhost:' + PORT + '/manual-edit-commit?token=' + encodeURIComponent(TOKEN) + '&pageUrl=' + encodeURIComponent(location.pathname) + '&async=1&repair=1',
        { method: 'POST', keepalive: true },
      );
      if (!res.ok) throw new Error('HTTP ' + res.status);
      if (pendingKeepFixingBtn) pendingKeepFixingBtn.style.display = 'none';
      if (pendingRollbackBtn) pendingRollbackBtn.style.display = 'none';
      if (pendingTrashBtn) pendingTrashBtn.style.display = 'inline-flex';
    } catch (err) {
      console.error('[impeccable] repair retry failed:', err);
      showToast('Repair retry failed - see console', 4000);
      showManualApplyDecision({ remainingCount: count, repair: readStoredManualApplyState() });
    }
  }

  async function onPendingRollbackClick() {
    const ok = confirm('Rollback source files to before this Apply and keep the edits staged?');
    if (!ok) return;
    try {
      const res = await fetch(
        'http://localhost:' + PORT + '/manual-edit-repair-decision?token=' + encodeURIComponent(TOKEN) + '&pageUrl=' + encodeURIComponent(location.pathname),
        {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ token: TOKEN, pageUrl: location.pathname, action: 'rollback' }),
        },
      );
      if (!res.ok) throw new Error('HTTP ' + res.status);
      const result = await res.json().catch(() => ({}));
      clearStoredManualApplyState();
      updatePendingCounter(numberOrNull(result.remainingCount) || 0);
      showToast('Rolled back source; copy edits are still staged.', 3500);
    } catch (err) {
      console.error('[impeccable] manual Apply rollback failed:', err);
      showToast('Rollback failed - see console', 4000);
    }
  }

  function manualEditEventForCurrentPage(msg) {
    return !msg?.pageUrl || msg.pageUrl === location.pathname;
  }

  function numberOrNull(value) {
    const n = Number(value);
    return Number.isFinite(n) ? n : null;
  }

  function remainingManualEditCount(payload) {
    const perPageCount = numberOrNull(payload?.perPage?.[location.pathname]);
    if (perPageCount !== null) return perPageCount;
    const remainingCount = numberOrNull(payload?.remainingCount);
    if (remainingCount !== null) return remainingCount;
    const totalCount = numberOrNull(payload?.totalCount);
    if (totalCount === 0) return 0;
    return null;
  }

  function handleManualEditActivity(msg) {
    if (!manualEditEventForCurrentPage(msg)) return;

    if (msg.type === 'manual_edit_stashed') {
      const pendingCount = numberOrNull(msg.pendingCount);
      if (pendingCount !== null) updatePendingCounter(pendingCount);
      return;
    }

    if (msg.type === 'manual_edit_commit_started') {
      const pendingCount = numberOrNull(msg.pendingCount);
      if (pendingCount !== null && pendingCount > 0) updatePendingCounter(pendingCount);
      if (!msg.repairOnly && pendingCount !== null && pendingCount > 0) resetManualApplyProgress(pendingCount);
      if (msg.repairOnly) updateManualApplyRepairState({ attempt: 1, maxAttempts: 3 }, 'repairing');
      setPendingApplyLoading(true, pendingCount || undefined);
      return;
    }

    if (msg.type === 'manual_edit_apply_reply_received') {
      if (msg.chunk) updateManualApplyProgressFromChunk(msg.chunk);
      if (msg.repair) updateManualApplyRepairState(msg.repair, 'repairing');
      return;
    }

    if (msg.type === 'manual_edit_apply_dispatched' && msg.repair) {
      updateManualApplyRepairState(msg.repair, 'repairing');
      return;
    }

    if (msg.type === 'manual_edit_repair_needs_decision') {
      showManualApplyDecision(msg);
      return;
    }

    if (msg.type === 'manual_edit_repair_rollback_done') {
      clearStoredManualApplyState();
      fetchPendingCount();
      return;
    }

    if (msg.type === 'manual_edit_commit_done') {
      if (msg.reason === 'manual_edit_repair_needs_decision' || msg.needsManualDecision === true) {
        showManualApplyDecision(msg);
        return;
      }
      // Clear the in-flight flag BEFORE updating the counter. updatePendingCounter
      // re-asserts setPendingApplyLoading(true) whenever the flag is still set and
      // edits remain (failed entries stay staged), which would otherwise leave the
      // picker frozen forever after a partial/failed apply.
      const wasApplying = pendingApplyInFlight;
      setPendingApplyLoading(false);
      const remainingCount = remainingManualEditCount(msg);
      updatePendingCounter(remainingCount === null ? 0 : remainingCount);
      if (wasApplying) {
        const failedCount = numberOrNull(msg.failedCount) || 0;
        const appliedCount = numberOrNull(msg.appliedCount) || numberOrNull(msg.cleared) || 0;
        if (failedCount > 0) {
          showToast('Applied ' + appliedCount + ', ' + failedCount + ' failed - see console', 5000);
        } else if (appliedCount > 0) {
          showToast('Applied ' + appliedCount + ' edit' + (appliedCount === 1 ? '' : 's'), 2500);
        }
      }
      return;
    }

    if (msg.type === 'manual_edit_commit_failed') {
      setPendingApplyLoading(false);
      fetchPendingCount();
      return;
    }

    if (msg.type === 'manual_edit_discarded') {
      fetchPendingCount();
    }
  }

  function restoreDiscardedManualEdits(entries) {
    let failures = 0;
    for (const entry of entries || []) {
      for (const op of entry.ops || []) {
        if (restoreMixedTextNodeManualEdit(op)) continue;
        const el = findManualEditRestoreElement(op);
        if (!el || typeof op.originalText !== 'string' || !canRestoreManualEditElement(el, op)) {
          failures += 1;
          continue;
        }
        el.textContent = op.originalText;
      }
    }
    if (failures > 0) {
      console.warn('[impeccable] skipped unsafe copy edit DOM restore for', failures, 'edit(s). Refresh to reset the page DOM.');
    }
    return failures;
  }

  function canRestoreManualEditElement(el, op) {
    if (!el || typeof op?.originalText !== 'string') return false;
    if (el.children && el.children.length > 0) return false;
    return normalizeManualContextText(el.textContent) === normalizeManualContextText(op.newText);
  }

  function mixedTextWrapRestoreHint(el) {
    if (!el || !el.dataset || el.dataset.impeccableTextWrap !== 'true' || !el.parentElement) return null;
    const siblings = directMixedTextRestoreNodes(el.parentElement);
    const textIndex = siblings.indexOf(el);
    return {
      kind: 'mixedTextNode',
      parentRef: documentRefForElement(el.parentElement),
      textIndex,
    };
  }

  function restoreMixedTextNodeManualEdit(op) {
    const restore = op?.restore;
    if (!restore || restore.kind !== 'mixedTextNode' || typeof op?.originalText !== 'string') return false;
    const parent = queryManualEditRef(restore.parentRef);
    if (!parent) return false;
    const textNodes = directMixedTextRestoreNodes(parent).filter((node) => node.nodeType === 3);
    const newText = normalizeManualContextText(op.newText);
    const byIndex = textNodes[Number(restore.textIndex)];
    if (byIndex && normalizeManualContextText(byIndex.nodeValue) === newText) {
      byIndex.nodeValue = op.originalText;
      return true;
    }
    const matches = textNodes.filter((node) => normalizeManualContextText(node.nodeValue) === newText);
    if (matches.length !== 1) return false;
    matches[0].nodeValue = op.originalText;
    return true;
  }

  function directMixedTextRestoreNodes(parent) {
    return Array.from(parent?.childNodes || []).filter((node) => {
      if (node.nodeType === 3) return /\S/.test(node.nodeValue || '');
      return node.nodeType === 1
        && node.dataset
        && node.dataset.impeccableTextWrap === 'true'
        && /\S/.test(node.textContent || '');
    });
  }

  function findManualEditRestoreElement(op) {
    for (const ref of [op?.ref, op?.leaf?.ref]) {
      const byRef = queryManualEditRef(ref);
      if (byRef) return byRef;
    }
    const tag = op?.tag || op?.leaf?.tagName || '*';
    const classes = Array.isArray(op?.classes) ? op.classes : (Array.isArray(op?.leaf?.classes) ? op.leaf.classes : []);
    const selector = (tag === '*' ? '' : tag) + classes.map((cls) => '.' + cssIdent(cls)).join('') || '*';
    let matches = [];
    try {
      matches = Array.from(document.querySelectorAll(selector));
    } catch {
      matches = [];
    }
    const newText = normalizeManualContextText(op?.newText);
    const filtered = matches.filter((el) => normalizeManualContextText(el.textContent) === newText);
    return filtered.length === 1 ? filtered[0] : null;
  }

  function queryManualEditRef(ref) {
    if (!ref || typeof ref !== 'string') return null;
    const parts = ref.split('>').map((part) => part.trim()).filter(Boolean);
    let current = null;
    for (let index = 0; index < parts.length; index += 1) {
      const segment = parseManualEditRefSegment(parts[index]);
      if (!segment) return null;
      if (index === 0 && segment.tag === 'body') {
        current = document.body;
        if (!elementMatchesManualRefSegment(current, segment)) return null;
        continue;
      }
      const scope = current || document.body;
      const children = Array.from(scope.children || []);
      current = children.find((child) => elementMatchesManualRefSegment(child, segment)) || null;
      if (!current) return null;
    }
    return current;
  }

  function parseManualEditRefSegment(segment) {
    const nthMatch = String(segment || '').match(/:nth-of-type\((\d+)\)$/);
    const nth = nthMatch ? Number(nthMatch[1]) : null;
    const base = nthMatch ? segment.slice(0, nthMatch.index) : segment;
    const tagMatch = base.match(/^[^#.:\s]+/);
    const tag = tagMatch ? tagMatch[0].toLowerCase() : null;
    if (!tag) return null;
    const idMatch = base.match(/#([^#.]+)/);
    const classes = base
      .slice(tag.length)
      .replace(/#[^#.]+/, '')
      .split('.')
      .filter(Boolean);
    return { tag, id: idMatch ? idMatch[1] : null, classes, nth };
  }

  function elementMatchesManualRefSegment(el, segment) {
    if (!el || !segment) return false;
    if (el.tagName.toLowerCase() !== segment.tag) return false;
    if (segment.id && el.id !== segment.id) return false;
    for (const cls of segment.classes) {
      if (!el.classList || !el.classList.contains(cls)) return false;
    }
    if (segment.nth && indexAmongSameTag(el) !== segment.nth) return false;
    return true;
  }

  function cssIdent(value) {
    if (window.CSS && typeof window.CSS.escape === 'function') return window.CSS.escape(String(value));
    return String(value).replace(/[^a-zA-Z0-9_-]/g, '\\$&');
  }

  //
  // Edit content badge - floating button at element top-right to enter EDITING mode
  //

  const EDIT_COPY_LABEL = 'Edit copy';
  const EDIT_COPY_ICON =
    '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
    '<path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/><path d="m15 5 4 4"/>' +
    '</svg>';

  function usesShadowChromeRoot() {
    const root = liveUiRoot();
    return root && root !== document.body && root.host && root.host.id === PREFIX + '-root';
  }

  function setImportantStyle(el, name, value) {
    el.style.setProperty(name, value, 'important');
  }

  function initEditBadgeHitProxies() {
    if (!usesShadowChromeRoot() || editBadgeProxyRoot) return;
    editBadgeProxyRoot = document.createElement('div');
    editBadgeProxyRoot.id = PREFIX + '-edit-badge-hit-proxies';
    editBadgeProxyRoot.setAttribute('aria-hidden', 'true');
    const styles = {
      all: 'initial',
      position: 'fixed',
      inset: '0',
      width: '100vw',
      height: '100vh',
      zIndex: String(Z.toast + 1),
      pointerEvents: 'none',
      background: 'transparent',
      overflow: 'visible',
    };
    for (const [name, value] of Object.entries(styles)) {
      setImportantStyle(editBadgeProxyRoot, name.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase()), value);
    }
    document.body.appendChild(editBadgeProxyRoot);
  }

  function styleEditBadgeProxy(proxy, target) {
    const rect = target.getBoundingClientRect();
    const cursor = getComputedStyle(target).cursor || 'pointer';
    const styles = {
      all: 'initial',
      position: 'fixed',
      left: rect.left + 'px',
      top: rect.top + 'px',
      width: rect.width + 'px',
      height: rect.height + 'px',
      margin: '0',
      padding: '0',
      border: '0',
      borderRadius: '0',
      background: 'transparent',
      color: 'transparent',
      opacity: '0.001',
      pointerEvents: 'auto',
      cursor,
      zIndex: String(Z.toast + 2),
    };
    for (const [name, value] of Object.entries(styles)) {
      setImportantStyle(proxy, name.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase()), value);
    }
  }

  function proxyMouseEvent(type, source, target) {
    let event;
    try {
      event = new MouseEvent(type, {
        bubbles: type !== 'mouseenter' && type !== 'mouseleave',
        cancelable: true,
        composed: true,
        clientX: source.clientX,
        clientY: source.clientY,
        screenX: source.screenX,
        screenY: source.screenY,
        button: source.button || 0,
        buttons: source.buttons || 0,
        ctrlKey: source.ctrlKey,
        metaKey: source.metaKey,
        shiftKey: source.shiftKey,
        altKey: source.altKey,
      });
      target.dispatchEvent(event);
    } catch {}
  }

  function bindEditBadgeProxy(proxy, target) {
    const stop = (event) => {
      event.preventDefault();
      event.stopPropagation();
    };
    proxy.addEventListener('mouseenter', (event) => {
      stop(event);
      proxyMouseEvent('mouseenter', event, target);
      proxyMouseEvent('mouseover', event, target);
    });
    proxy.addEventListener('mouseleave', (event) => {
      stop(event);
      proxyMouseEvent('mouseleave', event, target);
      proxyMouseEvent('mouseout', event, target);
    });
    proxy.addEventListener('mousedown', (event) => {
      stop(event);
      target.focus?.({ preventScroll: true });
      proxyMouseEvent('mousedown', event, target);
    });
    proxy.addEventListener('mouseup', (event) => {
      stop(event);
      proxyMouseEvent('mouseup', event, target);
    });
    proxy.addEventListener('click', (event) => {
      stop(event);
      target.click();
      syncEditBadgeHitProxies();
    });
  }

  function editBadgeProxyTargets() {
    if (!usesShadowChromeRoot() || !editBadgeEl || editBadgeEl.style.display === 'none') return [];
    return [...editBadgeEl.querySelectorAll('button')].filter((target) => {
      if (target.disabled) return false;
      const rect = target.getBoundingClientRect();
      if (rect.width < 1 || rect.height < 1) return false;
      const style = getComputedStyle(target);
      return style.display !== 'none' && style.visibility !== 'hidden';
    });
  }

  function syncEditBadgeHitProxies() {
    if (!usesShadowChromeRoot()) {
      if (editBadgeProxyRoot) editBadgeProxyRoot.remove();
      editBadgeProxyRoot = null;
      editBadgeProxyByTarget = new Map();
      return;
    }
    initEditBadgeHitProxies();
    if (!editBadgeProxyRoot) return;
    const targets = editBadgeProxyTargets();
    const active = new Set(targets);
    for (const [target, proxy] of editBadgeProxyByTarget) {
      if (!active.has(target) || !target.isConnected) {
        proxy.remove();
        editBadgeProxyByTarget.delete(target);
      }
    }
    for (const target of targets) {
      let proxy = editBadgeProxyByTarget.get(target);
      if (!proxy) {
        proxy = document.createElement('button');
        proxy.type = 'button';
        proxy.tabIndex = -1;
        proxy.dataset.impeccableEditBadgeProxy = 'true';
        proxy.setAttribute('aria-hidden', 'true');
        bindEditBadgeProxy(proxy, target);
        editBadgeProxyRoot.appendChild(proxy);
        editBadgeProxyByTarget.set(target, proxy);
      }
      proxy.title = target.title || target.getAttribute('aria-label') || target.textContent || EDIT_COPY_LABEL;
      styleEditBadgeProxy(proxy, target);
    }
  }

  function initEditBadge() {
    editBadgeEl = document.createElement('div');
    editBadgeEl.id = PREFIX + '-edit-badge';
    Object.assign(editBadgeEl.style, {
      position: 'fixed',
      zIndex: String(Z.highlight + 1),
      cursor: 'default',
      display: 'none',
      userSelect: 'none',
    });
    uiAppend(editBadgeEl);
    initEditBadgeHitProxies();

    // Remove focus rings on edit badge buttons + contenteditable elements
    if (!uiGetById(PREFIX + '-edit-badge-focus-style')) {
      const s = document.createElement('style');
      s.id = PREFIX + '-edit-badge-focus-style';
      s.textContent =
        '#' + PREFIX + '-edit-badge button { outline: none !important; box-shadow: 0 2px 8px rgba(0,0,0,0.1) !important; }' +
        '#' + PREFIX + '-edit-badge button:focus { outline: none !important; }' +
        '#' + PREFIX + '-edit-badge button:focus-visible { outline: none !important; }' +
        '[data-impeccable-editable="true"] { outline: none !important; box-shadow: none !important; }' +
        '[data-impeccable-editable="true"]:focus { outline: none !important; box-shadow: none !important; }' +
        '[data-impeccable-editable="true"]:focus-visible { outline: none !important; box-shadow: none !important; }';
      uiAppendStyle(s);
    }
  }

  function positionEditBadge() {
    if (!selectedElement || !editBadgeEl || editBadgeEl.style.display === 'none') {
      syncEditBadgeHitProxies();
      return;
    }
    const r = selectedElement.getBoundingClientRect();
    const bw = editBadgeEl.offsetWidth;
    // Match showHighlight's 2px outset so the badge right edge lines up with the outline.
    const outlineRight = r.right + 2;
    editBadgeEl.style.top = Math.max(4, r.top - 28) + 'px';
    editBadgeEl.style.left = Math.min(window.innerWidth - bw - 4, outlineRight - bw) + 'px';
    syncEditBadgeHitProxies();
  }

  function renderEditBadge(mode) {
    if (mode === 'hidden' || !editBadgeEl) {
      hideConfigureBarTooltip();
      if (editBadgeEl) editBadgeEl.style.display = 'none';
      syncEditBadgeHitProxies();
      return;
    }
    editBadgeEl.style.display = 'flex';
    editBadgeEl.style.alignItems = 'center';
    editBadgeEl.style.cursor = 'default';
    const P = BP || barPaletteForTheme(detectPageTheme());
    const ACCENT = P.accent;
    const PRIMARY_TEXT = C.ink;
    const SURFACE = P.chatSurface;
    const MUTED = P.textDim;
    const HAIRLINE = P.hairline;
    const calloutStyle = (color, borderColor) => ({
      fontFamily: FONT,
      fontSize: '10px',
      fontWeight: '600',
      lineHeight: '16px',
      letterSpacing: '0.06em',
      color: color,
      background: SURFACE,
      padding: '2px 8px',
      border: '1px solid ' + (borderColor || color),
      borderRadius: '6px',
      boxSizing: 'border-box',
      minHeight: '22px',
      margin: '0',
      appearance: 'none',
      whiteSpace: 'nowrap',
      boxShadow: '0 4px 16px oklch(0% 0 0 / 0.16), 0 1px 3px oklch(0% 0 0 / 0.08)',
      cursor: 'pointer',
      transition: 'background 0.18s ease, color 0.18s ease, border-color 0.18s ease, filter 0.18s ease',
    });
    if (mode === 'idle' || mode === 'idle-disabled') {
      const disabled = mode === 'idle-disabled';
      editBadgeEl.innerHTML = '';
      const btn = document.createElement('button');
      btn.type = 'button';
      btn.innerHTML = EDIT_COPY_ICON;
      btn.setAttribute('aria-label', EDIT_COPY_LABEL);
      Object.assign(btn.style, calloutStyle(
        disabled ? MUTED : PRIMARY_TEXT,
        disabled ? HAIRLINE : ACCENT,
      ));
      Object.assign(btn.style, {
        padding: '4px',
        minWidth: '22px',
        width: '22px',
        height: '22px',
        minHeight: '22px',
        display: 'inline-flex',
        alignItems: 'center',
        justifyContent: 'center',
        lineHeight: '0',
        letterSpacing: '0',
        background: disabled ? SURFACE : ACCENT,
      });
      if (disabled) {
        btn.style.cursor = 'not-allowed';
        btn.style.opacity = '0.55';
        btn.disabled = true;
        const disabledTip = EDIT_COPY_LABEL + ' is disabled while the current copy edit is applying';
        btn.addEventListener('mouseenter', () => showConfigureBarTooltip(btn, disabledTip));
        btn.addEventListener('mouseleave', hideConfigureBarTooltip);
      } else {
        btn.addEventListener('mouseenter', () => showConfigureBarTooltip(btn, EDIT_COPY_LABEL));
        btn.addEventListener('mouseleave', hideConfigureBarTooltip);
        btn.onclick = enterEditingMode;
      }
      editBadgeEl.appendChild(btn);
    } else {
      // 'editing' - show Cancel + Save separated
      editBadgeEl.innerHTML = '';
      editBadgeEl.style.gap = '8px';
      const cancel = document.createElement('button');
      cancel.textContent = 'Cancel';
      Object.assign(cancel.style, calloutStyle(MUTED, HAIRLINE));
      cancel.addEventListener('mouseenter', () => { cancel.style.color = P.text; });
      cancel.addEventListener('mouseleave', () => { cancel.style.color = P.textDim; });
      cancel.onclick = cancelEditing;
      const save = document.createElement('button');
      save.textContent = 'Save';
      Object.assign(save.style, calloutStyle(PRIMARY_TEXT, ACCENT));
      save.style.background = ACCENT;
      save.onclick = applyEditing;
      editBadgeEl.append(cancel, save);
    }
    positionEditBadge();
  }

  // Decide which way the popover opens: away from the picked element. If the
  // bar landed below the element, popover slides DOWN from the bar's bottom.
  // If the bar landed above, popover slides UP from the bar's top.
  function popoverDirection() {
    if (!barEl || !selectedElement) return 'below';
    const br = barEl.getBoundingClientRect();
    const er = selectedElement.getBoundingClientRect();
    return br.top >= er.bottom - 4 ? 'below' : 'above';
  }

  // The popover overlaps the bar by OVERLAP px on the bar-facing side. With
  // popover z-index below bar, that overlap sits behind bar (invisible) and
  // reinforces the "tucked behind" feel. Padding compensates so the real
  // content starts flush with bar's outer edge.
  const TUNE_OVERLAP = 6;

  // Closed clip-path depends on direction: for 'below' clip from the far
  // (bottom) edge so the reveal grows downward from the bar; for 'above'
  // clip from the top edge so the reveal grows upward from the bar.
  function closedClipPath(direction) {
    return direction === 'below' ? 'inset(0 0 100% 0)' : 'inset(100% 0 0 0)';
  }

  function setClipPath(value, withTransition) {
    const saved = paramsPanelEl.style.transition;
    if (!withTransition) paramsPanelEl.style.transition = 'none';
    paramsPanelEl.style.clipPath = value;
    if (!withTransition) {
      void paramsPanelEl.offsetHeight;
      paramsPanelEl.style.transition = saved;
    }
  }

  function positionParamsPanel() {
    if (!paramsPanelEl || !barEl || barEl.style.display === 'none') return;
    const br = barEl.getBoundingClientRect();
    const direction = popoverDirection();
    const prevDirection = paramsPanelEl.dataset.tuneDirection;

    // top/left/width are NOT in the transition list, so they snap instantly.
    paramsPanelEl.style.left = br.left + 'px';
    paramsPanelEl.style.width = br.width + 'px';

    if (direction === 'below') {
      paramsPanelEl.style.top = (br.bottom - TUNE_OVERLAP) + 'px';
      paramsPanelEl.style.borderRadius = '0 0 10px 10px';
      paramsPanelEl.style.paddingTop = (14 + TUNE_OVERLAP) + 'px';
      paramsPanelEl.style.paddingBottom = '14px';
    } else {
      const ih = paramsPanelEl.offsetHeight || 80;
      paramsPanelEl.style.top = (br.top - ih + TUNE_OVERLAP) + 'px';
      paramsPanelEl.style.borderRadius = '10px 10px 0 0';
      paramsPanelEl.style.paddingTop = '14px';
      paramsPanelEl.style.paddingBottom = (14 + TUNE_OVERLAP) + 'px';
    }
    paramsPanelEl.dataset.tuneDirection = direction;

    // If currently closed and direction flipped (or first-time setup),
    // snap the clip-path to the new direction's closed pose without
    // transitioning (so the clip doesn't slide across the element).
    if (!tuneOpen && (!prevDirection || prevDirection !== direction)) {
      setClipPath(closedClipPath(direction), false);
    }
  }

  function showParamsPanel() {
    if (!paramsPanelEl) return;
    positionParamsPanel();
    paramsPanelEl.style.pointerEvents = 'auto';
    // rAF so the positioning paint commits before the transition fires.
    requestAnimationFrame(() => {
      setClipPath('inset(0 0 0 0)', true);
    });
  }

  function hideParamsPanel() {
    if (!paramsPanelEl) return;
    paramsPanelEl.style.pointerEvents = 'none';
    const direction = paramsPanelEl.dataset.tuneDirection || 'below';
    setClipPath(closedClipPath(direction), true);
  }

  // Build/rebuild the panel's contents for the current variant AND apply
  // its defaults to the variant wrapper (so scoped CSS responds even before
  // the user opens the popover). Visibility is governed by tuneOpen.
  function refreshParamsPanel() {
    if (state !== 'CYCLING') {
      paramsCurrentValues = {};
      tuneOpen = false;
      hideParamsPanel();
      return;
    }
    const variantEl = getVisibleVariantEl();
    const params = parseVariantParams(variantEl);
    if (!variantEl || params.length === 0) {
      paramsCurrentValues = {};
      tuneOpen = false;
      hideParamsPanel();
      if (currentSessionId && visibleVariant) updateVariantStateStylesheet(currentSessionId, visibleVariant);
      return;
    }
    applyParamDefaults(variantEl, params);
    buildParamsPanel(variantEl, params);
    if (tuneOpen) {
      // If already visible (variant cycled while open), refresh in place
      // instead of re-running the clip-path animation.
      const alreadyVisible = paramsPanelEl.style.display === 'block'
        && paramsPanelEl.style.opacity === '1';
      if (alreadyVisible) positionParamsPanel();
      else showParamsPanel();
    } else {
      hideParamsPanel();
    }
  }

  function mountedParameterCount() {
    if (svelteComponentSession?.sessionId === currentSessionId) {
      return Object.values(svelteComponentSession.paramsByVariant || {})
        .reduce((total, params) => total + (Array.isArray(params) ? params.length : 0), 0);
    }
    const wrapper = document.querySelector('[data-impeccable-variants="' + currentSessionId + '"]');
    if (!wrapper) return 0;
    return [...wrapper.querySelectorAll('[data-impeccable-variant]:not([data-impeccable-variant="original"])')]
      .reduce((total, variant) => total + parseVariantParams(variant).length, 0);
  }

  function completeParameterPublication() {
    if (!currentSessionId) return;
    const ready = mountedParameterCount() > 0;
    parameterGenerationState = ready ? 'ready' : 'none';
    if (ready && parameterReadyAnnouncedSession !== currentSessionId) {
      parameterReadyAnnouncedSession = currentSessionId;
      showToast('Tune controls are ready.', 3000);
    }
    if (state === 'CYCLING') {
      refreshParamsPanel();
      showOrUpdateCyclingBar();
    }
    saveSession();
  }

  function toggleTunePopover() {
    if (pendingApplyInFlight) { showManualApplyBusyToast(); return; }
    if (tuneOpen) { closeTunePopover(); return; }
    openTunePopover();
  }

  function openTunePopover() {
    if (state !== 'CYCLING') return;
    const variantEl = getVisibleVariantEl();
    const params = parseVariantParams(variantEl);
    if (!variantEl || params.length === 0) return;
    // Build fresh to ensure the current variant's controls are shown.
    applyParamDefaults(variantEl, params);
    buildParamsPanel(variantEl, params);
    tuneOpen = true;
    showParamsPanel();
    // Kill the bar's shadow on the popover-facing side so the dark popover
    // doesn't pick up a bright glow line.
    if (barEl) {
      const direction = paramsPanelEl?.dataset.tuneDirection || 'below';
      barEl.style.boxShadow = direction === 'below' ? BAR_SHADOW_UP : BAR_SHADOW_DOWN;
    }
    // Re-render the bar so the Tune chip picks up the active styling.
    showOrUpdateCyclingBar();
  }

  function closeTunePopover() {
    tuneOpen = false;
    hideParamsPanel();
    if (barEl) barEl.style.boxShadow = BAR_SHADOW_DEFAULT;
    if (barEl && barEl.style.display !== 'none' && state === 'CYCLING') {
      showOrUpdateCyclingBar();
    }
  }

  //
  // Variant cycling in DOM
  //

  function isVariantShown(el) {
    if (!el) return false;
    return getComputedStyle(el).display !== 'none';
  }

  function scheduleCyclingBarSync(sessionId, variantNum) {
    requestAnimationFrame(() => {
      if (state !== 'CYCLING') return;
      if (currentSessionId !== sessionId) return;
      if (visibleVariant !== variantNum) return;
      showOrUpdateCyclingBar();
      syncCyclingControls();
      positionBar();
    });
  }

  function syncCyclingControls() {
    const shown = cyclingShownVariant();
    const counter = uiGetById(PREFIX + '-variant-counter');
    if (counter) counter.textContent = cyclingCounterText();
    const prev = uiGetById(PREFIX + '-variant-prev');
    const next = uiGetById(PREFIX + '-variant-next');
    if (prev) prev.style.opacity = shown <= 1 ? '0.3' : '1';
    if (next) next.style.opacity = shown >= arrivedVariants ? '0.3' : '1';
    if (currentSessionId && state === 'CYCLING') saveSession();
  }

  async function showVariantInDOM(sessionId, num) {
    if (svelteComponentSession?.sessionId === sessionId) {
      visibleVariant = num;
      const mounted = await mountSvelteComponentVariant(num);
      if (!mounted) return false;
      updateSelectedElement();
      refreshParamsPanel();
      scheduleCyclingBarSync(sessionId, num);
      return true;
    }
    const wrapper = document.querySelector('[data-impeccable-variants="' + sessionId + '"]');
    if (!wrapper) return false;
    updateVariantStateStylesheet(sessionId, num);
    // Unconditional refresh - covers first-reveal (no-op if state isn't
    // CYCLING yet, the subsequent CYCLING transition triggers its own
    // refresh) and every cycle step.
    refreshParamsPanel();
    return true;
  }

  function isSvelteComponentManifestPath(filePath) {
    return String(filePath || '').endsWith('manifest.json');
  }

  function isFrameworkComponentPreviewMode(mode) {
    return mode === 'svelte-component';
  }

  function parseOriginalMarkupElement(originalMarkup) {
    const parser = new DOMParser();
    const doc = parser.parseFromString('<div id="impeccable-anchor">' + originalMarkup + '</div>', 'text/html');
    return doc.getElementById('impeccable-anchor')?.firstElementChild || null;
  }

  function normalizeElementClassName(el) {
    if (!el) return '';
    const raw = el.getAttribute?.('class');
    if (typeof raw === 'string') return raw.trim();
    if (el.className != null) {
      const cls = el.className;
      if (typeof cls === 'string') return cls.trim();
      if (typeof cls.baseVal === 'string') return cls.baseVal.trim();
    }
    return '';
  }

  function buildPickedAnchorSnapshot(el) {
    if (!el || el.nodeType !== 1) return null;
    return {
      tag: el.tagName,
      id: el.id || '',
      classes: [...el.classList],
      text: (el.textContent || '').trim().slice(0, 120),
    };
  }

  function isUsableInjectionAnchor(el) {
    return !!el
      && el.parentElement
      && document.body.contains(el)
      && !own(el)
      && !el.closest?.('[data-impeccable-variants]');
  }

  function elementMatchesOriginalMarkup(liveEl, origContent) {
    if (!isUsableInjectionAnchor(liveEl) || !origContent) return false;
    // A matching id is decisive on its own: ids are unique, while the source
    // tag and class names may not survive the build (component tags, hashed
    // CSS-module class names).
    if (origContent.id) return liveEl.id === origContent.id;
    if (liveEl.tagName !== origContent.tagName) return false;

    const origClasses = normalizeElementClassName(origContent).split(/\s+/).filter(Boolean)
      .filter((name) => /^[A-Za-z_-][\w-]*$/.test(name));
    if (origClasses.length > 0 && !origClasses.every((name) => liveEl.classList.contains(name))) return false;

    const origText = (origContent.textContent || '').trim();
    if (origClasses.length === 0 && origText.length >= 4) {
      const liveText = (liveEl.textContent || '').trim();
      const needle = origText.slice(0, Math.min(40, origText.length));
      if (!liveText.includes(needle) && !(liveText.length >= 4 && origText.includes(liveText.slice(0, 40)))) return false;
    }
    return true;
  }

  function findLiveElementFromAnchorSnapshot(snapshot) {
    if (!snapshot) return null;
    const tag = String(snapshot.tag || '').toLowerCase();
    if (!tag) return null;
    if (snapshot.id) {
      const byId = document.getElementById(snapshot.id);
      if (isUsableInjectionAnchor(byId)) return byId;
    }
    const classes = (snapshot.classes || []).filter((name) => /^[A-Za-z_-][\w-]*$/.test(name));
    const needle = (snapshot.text || '').trim();
    const candidates = [...document.getElementsByTagName(tag)];
    for (const c of candidates) {
      if (!isUsableInjectionAnchor(c)) continue;
      if (classes.length > 0 && !classes.every((name) => c.classList.contains(name))) continue;
      if (!snapshot.id && classes.length === 0 && needle.length >= 4) {
        const text = (c.textContent || '').trim();
        if (!text.includes(needle.slice(0, 40)) && !(text.length >= 4 && needle.includes(text.slice(0, 40)))) continue;
      }
      return c;
    }
    return null;
  }

  function findLiveElementForOriginalMarkup(originalMarkup) {
    const origContent = parseOriginalMarkupElement(originalMarkup);
    if (!origContent) return null;

    const tag = origContent.tagName.toLowerCase();
    const cls = normalizeElementClassName(origContent);
    const candidates = [...document.getElementsByTagName(tag)];

    if (origContent.id) {
      const byId = document.getElementById(origContent.id);
      if (elementMatchesOriginalMarkup(byId, origContent)) return byId;
    }

    if (cls) {
      const expectedClasses = cls.split(/\s+/).filter((name) => /^[A-Za-z_-][\w-]*$/.test(name));
      if (expectedClasses.length > 0) {
        for (const c of candidates) {
          if (!isUsableInjectionAnchor(c)) continue;
          if (expectedClasses.every((name) => c.classList.contains(name))) return c;
        }
      }
    }

    const origText = (origContent.textContent || '').trim();
    if (origText.length >= 4) {
      const needle = origText.slice(0, 40);
      let best = null;
      let bestLen = Infinity;
      for (const c of candidates) {
        if (!isUsableInjectionAnchor(c)) continue;
        const text = (c.textContent || '').trim();
        if (!text.includes(needle) && !(text.length >= 4 && origText.includes(text.slice(0, 40)))) continue;
        if (text.length < bestLen) { best = c; bestLen = text.length; }
      }
      if (best) return best;
    }

    return null;
  }

  function resolveLiveInjectionAnchor(originalMarkup) {
    const origContent = parseOriginalMarkupElement(originalMarkup);
    if (!origContent) return null;

    const attempts = [
      selectedElement,
      findLiveElementFromAnchorSnapshot(pickedAnchorSnapshot),
      findLiveElementForOriginalMarkup(originalMarkup),
    ];
    for (const candidate of attempts) {
      if (elementMatchesOriginalMarkup(candidate, origContent)) return candidate;
    }

    if (isUsableInjectionAnchor(selectedElement) && selectedElement.tagName === origContent.tagName) {
      const origClasses = normalizeElementClassName(origContent).split(/\s+/).filter(Boolean);
      if (origContent.id && selectedElement.id === origContent.id) return selectedElement;
      if (origClasses.length === 0) return selectedElement;
      const overlap = origClasses.filter((name) => selectedElement.classList.contains(name));
      if (overlap.length >= 1) return selectedElement;
    }

    return null;
  }

  function isSvelteInsertManifest(manifest) {
    return manifest?.previewMode === 'svelte-component' && manifest?.mode === 'insert';
  }

  function findLiveElementForSvelteManifest(manifest) {
    if (isSvelteInsertManifest(manifest)) {
      const anchor = findInsertAnchorInDom();
      if (anchor?.parentElement) return anchor;
    }
    return resolveLiveInjectionAnchor(manifest?.originalMarkup || manifest?.anchorMarkup || '');
  }

  function waitForVariantAnchorAndRetry({ filePath, sessionId, srcWrapper, checkpointReason }) {
    if (pendingVariantAnchorRetryObserver) pendingVariantAnchorRetryObserver.disconnect();
    const origContent = srcWrapper?.querySelector('[data-impeccable-variant="original"] > :first-child');
    if (!origContent) return;
    const originalMarkup = origContent.outerHTML;

    pendingVariantAnchorRetryObserver = new MutationObserver(() => {
      // Retry once either the anchor element or the session wrapper shows up.
      // A wrapper can land incomplete ("wrap HMR landed, variant insert did
      // not"); injectVariantsFromSource owns both cases - it replaces an
      // existing wrapper from source and clears recoveryWaitingForAnchor.
      const wrapperLanded = !!document.querySelector('[data-impeccable-variants="' + sessionId + '"]');
      if (!wrapperLanded) {
        const liveEl = resolveLiveInjectionAnchor(originalMarkup);
        if (!liveEl?.parentElement) return;
      }
      pendingVariantAnchorRetryObserver.disconnect();
      pendingVariantAnchorRetryObserver = null;
      injectVariantsFromSource(filePath, sessionId);
    });
    pendingVariantAnchorRetryObserver.observe(document.body, { childList: true, subtree: true });
    if (checkpointReason) queueCheckpoint(checkpointReason);
  }

  function enterRecoveryWaitingForAnchor({ filePath, sessionId, srcWrapper, checkpointReason, trackScroll }) {
    recoveryWaitingForAnchor = true;
    selectedElement = document.body;
    setLiveState('GENERATING');
    showBar('generating');
    if (trackScroll !== false) startScrollTracking();
    saveSession();
    if (srcWrapper && filePath && sessionId) {
      waitForVariantAnchorAndRetry({ filePath, sessionId, srcWrapper, checkpointReason });
    } else if (checkpointReason) {
      queueCheckpoint(checkpointReason);
    }
  }

  // The dev server may serve under a non-root base (vite `base`) or a root
  // that differs from where the helper wrote the preview tree. Root-relative
  // URLs are tried against the detected base first; the /@fs/ absolute form
  // is the fallback that works regardless of base and root, as long as the
  // path is inside the server's fs.allow.
  let detectedDevBase = null;
  function detectDevServerBase() {
    if (detectedDevBase !== null) return detectedDevBase;
    detectedDevBase = '/';
    const scripts = document.querySelectorAll('script[type="module"][src]');
    for (const script of scripts) {
      const src = script.getAttribute('src') || '';
      const idx = src.indexOf('/@vite/client');
      if (idx > 0) { detectedDevBase = src.slice(0, idx) + '/'; break; }
      if (idx === 0) { detectedDevBase = '/'; break; }
    }
    return detectedDevBase;
  }

  function componentModuleCandidates(manifest, modulePath, absPath) {
    const base = detectDevServerBase();
    const rel = String(modulePath || '').replace(/^\/+/, '');
    const candidates = [new URL(base + rel, location.origin).href];
    if (base !== '/') candidates.push(new URL('/' + rel, location.origin).href);
    if (absPath) {
      const fsRel = '@fs/' + String(absPath).replace(/^\/+/, '');
      candidates.push(new URL(base + fsRel, location.origin).href);
      // Vite versions differ on whether @fs is served under base or at the
      // server root; with a non-root base, try both.
      if (base !== '/') candidates.push(new URL('/' + fsRel, location.origin).href);
    }
    return candidates;
  }

  async function importFirstReachable(candidates, bust) {
    let lastErr = null;
    for (const candidate of candidates) {
      try {
        const url = bust ? candidate + (candidate.includes('?') ? '&' : '?') + 't=' + Date.now() : candidate;
        const mod = await import(/* @vite-ignore */ url);
        return { mod, url: candidate };
      } catch (err) {
        lastErr = err;
      }
    }
    throw Object.assign(lastErr || new Error('no module candidates'), {
      impeccableTriedUrls: candidates,
    });
  }

  // Distinguishes "this variant is broken" from "the preview tree is not
  // reachable from the dev server at all" (wrong root, unserved directory).
  async function probePreviewTree(manifest) {
    if (!manifest?.probeModule) return { ok: true, skipped: true };
    const candidates = componentModuleCandidates(manifest, manifest.probeModule, manifest.probeModuleAbs);
    try {
      await importFirstReachable(candidates, false);
      return { ok: true };
    } catch (err) {
      return { ok: false, tried: err.impeccableTriedUrls || candidates };
    }
  }

  function loadSvelteRuntime(runtimeModule, manifest) {
    const modulePath = runtimeModule || '/src/lib/impeccable/__runtime.js';
    if (!svelteRuntimePromise) {
      const candidates = componentModuleCandidates(manifest, modulePath, manifest?.runtimeModuleAbs);
      svelteRuntimePromise = importFirstReachable(candidates, false).then((r) => r.mod);
    }
    return svelteRuntimePromise;
  }

  // Svelte component variants declare their params in a sidecar params.json under
  // componentDir (keyed by variant number), because a `data-impeccable-params`
  // attribute with JSON braces can't survive the Svelte compiler. Returns a map of
  // { "1": [...params], "2": [...] }; an empty object when the agent declared none.
  async function loadSvelteComponentParams(manifest) {
    const dir = String(manifest?.revisionDir || manifest?.componentDir || '').replace(/^\/+/, '');
    if (!dir) return {};
    const paramsPath = dir + '/params.json';
    const url = 'http://localhost:' + PORT + '/source?token=' + TOKEN + '&path=' + encodeURIComponent(paramsPath);
    try {
      const res = await fetch(url);
      if (!res.ok) return {};
      const parsed = JSON.parse(await res.text());
      if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return {};
      const out = {};
      for (const [key, value] of Object.entries(parsed)) {
        if (Array.isArray(value)) out[String(key)] = value;
      }
      return out;
    } catch {
      return {};
    }
  }



  // NOTE: the compiled component imported from the dev server already carries
  // its own scoped styles (vite-plugin-svelte injects them on module
  // evaluation). The old second injection re-fetched the raw source through
  // the helper and re-prefixed every selector un-hashed, so the same rules
  // applied twice with different specificity: preview and accepted cascades
  // disagreed. The single compiled copy is the truth now.

  function removeSvelteComponentVariantStyle(session = svelteComponentSession) {
    const style = session?.styleEl;
    if (style?.parentNode) style.parentNode.removeChild(style);
    if (session) session.styleEl = null;
  }


  function scopeCssBlock(css, prefix) {
    let out = '';
    let i = 0;
    while (i < css.length) {
      const open = css.indexOf('{', i);
      if (open === -1) {
        out += css.slice(i);
        break;
      }
      const semi = css.indexOf(';', i);
      if (semi !== -1 && semi < open) {
        out += css.slice(i, semi + 1);
        i = semi + 1;
        continue;
      }
      const prelude = css.slice(i, open).trim();
      const close = findMatchingCssBrace(css, open);
      if (close === -1) {
        out += css.slice(i);
        break;
      }
      const body = css.slice(open + 1, close);
      if (shouldScopeNestedCssAtRule(prelude)) {
        out += prelude + ' {\n' + scopeCssBlock(body, prefix) + '\n}';
      } else if (prelude.startsWith('@')) {
        out += prelude + ' {' + body + '}';
      } else {
        out += prefixCssSelectors(prelude, prefix) + ' {' + body + '}';
      }
      i = close + 1;
    }
    return out;
  }

  function shouldScopeNestedCssAtRule(prelude) {
    return /^@(media|supports|container|layer)\b/i.test(prelude || '');
  }

  function findMatchingCssBrace(css, openIndex) {
    let depth = 0;
    let quote = '';
    for (let i = openIndex; i < css.length; i++) {
      const ch = css[i];
      const prev = css[i - 1];
      if (quote) {
        if (ch === quote && prev !== '\\') quote = '';
        continue;
      }
      if (ch === '"' || ch === "'") {
        quote = ch;
      } else if (ch === '{') {
        depth++;
      } else if (ch === '}') {
        depth--;
        if (depth === 0) return i;
      }
    }
    return -1;
  }

  function prefixCssSelectors(prelude, prefix) {
    return splitCssSelectorList(prelude)
      .map((selector) => {
        const s = unwrapSvelteGlobalSelector(selector.trim());
        if (!s) return '';
        if (s.startsWith(prefix.trim())) return s;
        if (s.startsWith(':host')) return s.replace(/^:host\b/, prefix.trim());
        return prefix + s;
      })
      .filter(Boolean)
      .join(', ');
  }

  function splitCssSelectorList(selectorList) {
    const selectors = [];
    let start = 0;
    let depth = 0;
    let quote = '';
    for (let i = 0; i < selectorList.length; i++) {
      const ch = selectorList[i];
      const prev = selectorList[i - 1];
      if (quote) {
        if (ch === quote && prev !== '\\') quote = '';
        continue;
      }
      if (ch === '"' || ch === "'") {
        quote = ch;
      } else if (ch === '(' || ch === '[') {
        depth++;
      } else if ((ch === ')' || ch === ']') && depth > 0) {
        depth--;
      } else if (ch === ',' && depth === 0) {
        selectors.push(selectorList.slice(start, i));
        start = i + 1;
      }
    }
    selectors.push(selectorList.slice(start));
    return selectors;
  }

  function unwrapSvelteGlobalSelector(selector) {
    return selector.replace(/:global\(([^()]*)\)/g, '$1');
  }

  function buildSveltePropValuesFromLiveElement(liveEl, manifest) {
    const contract = manifest?.propContract || [];
    const values = {};
    if (!liveEl || contract.length === 0) return values;
    if (Number(manifest.contractVersion) === 2) {
      return buildSveltePropValuesV2(liveEl, manifest);
    }
    const sourceOriginal = parseOriginalMarkupElement(manifest.originalMarkup || '');
    if (!sourceOriginal) return values;
    const map = buildSvelteExpressionTextMap(sourceOriginal, liveEl);
    for (const entry of contract) {
      const token = entry.previewToken || ('{' + entry.expr + '}');
      values[entry.prop] = map.get(token) || '';
    }
    return values;
  }

  // Contract v2 hydration. The scaffolder preserved control flow, so props
  // come in kinds: `collection` hydrates from the live DOM's rendered items
  // (count by the item root selector, texts by slot order), `condition` from
  // whether the branch's probe element is currently rendered, `text` from the
  // v1 index-zip run over the markup WITH control-flow regions stripped and
  // the live tree WITH item elements excluded, so loop tokens can never shift
  // slots again. `handler` props keep their no-op defaults.
  function buildSveltePropValuesV2(liveEl, manifest) {
    const contract = manifest.propContract || [];
    const values = {};
    const itemElsByProp = new Map();

    for (const entry of contract) {
      if (entry.kind === 'collection' && entry.item && entry.item.rootTag) {
        const selector = entry.item.rootTag + (entry.item.rootClasses || []).map((c) => '.' + cssEscapeIdent(c)).join('');
        let matches = [];
        try { matches = Array.from(liveEl.querySelectorAll(selector)); } catch { matches = []; }
        itemElsByProp.set(entry.prop, matches);
        const statics = new Set((entry.item.staticTexts || []).map((t) => String(t).trim()));
        const slots = entry.item.textSlots || [];
        values[entry.prop] = matches.map((itemEl, index) => {
          const texts = collectVisibleTexts(itemEl).filter((t) => !statics.has(t));
          const item = {};
          slots.forEach((slot, i) => { item[slot.key] = texts[i] != null ? texts[i] : ''; });
          // Attribute-bound values (href={link.href}) hydrate from the
          // rendered attribute on the live item element or a descendant.
          for (const slot of entry.item.attrSlots || []) {
            if (item[slot.key] != null || !slot.tag) continue;
            const sel = slot.tag + (slot.classes || []).map((c) => '.' + cssEscapeIdent(c)).join('');
            let el = null;
            try { el = itemEl.matches(sel) ? itemEl : itemEl.querySelector(sel); } catch { el = null; }
            const value = el ? el.getAttribute(slot.attr) : null;
            if (value != null) item[slot.key] = value;
          }
          // Keyed each: the key field is never rendered, so hydrate it with a
          // unique per-index value or Svelte throws each_key_duplicate.
          if (entry.item.keyField && item[entry.item.keyField] == null) {
            item[entry.item.keyField] = 'impeccable-live-' + index;
          }
          return item;
        });
      } else if (entry.kind === 'condition') {
        if (entry.probe && entry.probe.tag) {
          const selector = entry.probe.tag + (entry.probe.classes || []).map((c) => '.' + cssEscapeIdent(c)).join('');
          try { values[entry.prop] = !!liveEl.querySelector(selector); } catch { /* keep default */ }
        } else if (entry.probe && entry.probe.className) {
          // class:name directive: the live DOM answers directly, either on
          // the picked element itself or on a descendant carrying the class.
          try {
            values[entry.prop] = liveEl.classList.contains(entry.probe.className)
              || !!liveEl.querySelector('.' + cssEscapeIdent(entry.probe.className));
          } catch { /* keep default */ }
        }
      }
    }

    // Text props outside control flow: strip block regions from the source
    // markup, exclude live text nodes inside any hydrated item element, then
    // run the existing zip.
    const textEntries = contract.filter((e) => e.kind === 'text' || e.kind === 'raw');
    if (textEntries.length > 0) {
      const strippedMarkup = stripSvelteBlockRegions(manifest.originalMarkup || '');
      const sourceOriginal = parseOriginalMarkupElement(strippedMarkup);
      if (sourceOriginal) {
        const excluded = [];
        for (const els of itemElsByProp.values()) excluded.push(...els);
        const filteredLive = cloneWithoutElements(liveEl, excluded);
        const map = buildSvelteExpressionTextMap(sourceOriginal, filteredLive);
        for (const entry of textEntries) {
          const token = '{' + entry.expr + '}';
          if (map.has(token)) values[entry.prop] = map.get(token) || '';
        }
      }
    }
    return values;
  }

  function cssEscapeIdent(value) {
    try { return CSS.escape(value); } catch { return String(value).replace(/[^a-zA-Z0-9_-]/g, ''); }
  }

  function collectVisibleTexts(rootEl) {
    const texts = [];
    const walker = document.createTreeWalker(rootEl, NodeFilter.SHOW_TEXT);
    let node;
    while ((node = walker.nextNode())) {
      const trimmed = String(node.textContent || '').trim();
      if (trimmed) texts.push(trimmed);
    }
    return texts;
  }

  // Remove balanced {#each}...{/each} and {#if}...{/if} regions (including
  // the delimiters) from a markup string. Nesting-aware. {#key} blocks keep
  // their CONTENT (it always renders) but lose their delimiter tokens, which
  // would otherwise consume live text slots in the zip and shift every
  // following expression.
  function stripSvelteBlockRegions(markup) {
    let out = String(markup || '');
    out = stripSvelteKeyDelimiters(out);
    for (const kind of ['each', 'if']) {
      const open = '{#' + kind;
      const close = '{/' + kind + '}';
      for (;;) {
        const start = out.indexOf(open);
        if (start === -1) break;
        let depth = 0;
        let i = start;
        let end = -1;
        while (i < out.length) {
          if (out.startsWith(open, i)) { depth++; i += open.length; continue; }
          if (out.startsWith(close, i)) {
            depth--;
            i += close.length;
            if (depth === 0) { end = i; break; }
            continue;
          }
          i++;
        }
        if (end === -1) break;
        out = out.slice(0, start) + out.slice(end);
      }
    }
    return out;
  }

  function stripSvelteKeyDelimiters(markup) {
    let out = String(markup || '');
    for (;;) {
      const start = out.indexOf('{#key');
      if (start === -1) break;
      // The opening tag runs to its matching close brace (expressions inside
      // may nest braces).
      let depth = 0;
      let i = start;
      let openEnd = -1;
      while (i < out.length) {
        if (out[i] === '{') depth++;
        else if (out[i] === '}') {
          depth--;
          if (depth === 0) { openEnd = i + 1; break; }
        }
        i++;
      }
      if (openEnd === -1) break;
      out = out.slice(0, start) + out.slice(openEnd);
    }
    return out.split('{/key}').join('');
  }

  function cloneWithoutElements(rootEl, excludedEls) {
    if (!excludedEls || excludedEls.length === 0) return rootEl;
    const excludedSet = new Set(excludedEls);
    // Mark originals, clone, then strip marked clones: identity does not
    // survive cloneNode, attributes do.
    const MARK = 'data-impeccable-hydration-excluded';
    for (const el of excludedSet) { try { el.setAttribute(MARK, '1'); } catch { /* detached */ } }
    let clone;
    try {
      clone = rootEl.cloneNode(true);
      clone.querySelectorAll('[' + MARK + ']').forEach((el) => el.remove());
    } finally {
      for (const el of excludedSet) { try { el.removeAttribute(MARK); } catch { /* detached */ } }
    }
    return clone || rootEl;
  }

  async function mountSvelteComponentVariant(variantNum) {
    if (!svelteComponentSession || !variantNum) return false;
    const { manifest, mountTargetEl, sessionId } = svelteComponentSession;
    // Resolved before the first await so the failure report can name the module
    // the browser could not reach, whichever step threw.
    const extension = manifest.componentExtension || 'svelte';
    // Prefer the server-stamped revision dir: its path changes on every
    // publish, which is what defeats stale transform caches for files the
    // dev server does not watch.
    const dirRel = manifest.revisionDir || manifest.componentDir || '';
    const dirAbs = manifest.revisionDirAbs || manifest.componentDirAbs || null;
    const moduleBase = manifest.componentModuleBase
      || ('/' + String(dirRel).replace(/^\/+/, ''));
    const modulePath = String(moduleBase).replace(/\/+$/, '') + '/v' + variantNum + '.' + extension;
    const moduleAbs = dirAbs
      ? String(dirAbs).replace(/\/+$/, '') + '/v' + variantNum + '.' + extension
      : null;
    const candidates = componentModuleCandidates(manifest, modulePath, moduleAbs);
    let moduleUrl = candidates[0];
    try {
      const previousAnchor = getMountedSvelteComponentAnchor(svelteComponentSession) || selectedElement;
      svelteComponentSession.swapAnchor = makeFrozenAnchor(previousAnchor) || svelteComponentSession.swapAnchor || null;
      const runtime = await loadSvelteRuntime(manifest.runtimeModule, manifest);
      const imported = await importFirstReachable(candidates, true);
      moduleUrl = imported.url;
      const mod = imported.mod;
      const Component = mod.default;
      if (svelteComponentSession.mountedInstance && runtime.unmount) {
        await runtime.unmount(svelteComponentSession.mountedInstance);
        svelteComponentSession.mountedInstance = null;
      }
      svelteComponentSession.mountedInstance = runtime.mount(Component, {
        target: mountTargetEl,
        props: { ...svelteComponentSession.propValues },
        intro: false,
      });
      svelteComponentSession.mountedVariant = variantNum;
      svelteComponentSession.runtime = runtime;
      removeSvelteComponentVariantStyle(svelteComponentSession);
      if (state === 'CYCLING') syncCyclingControls();
      const nextAnchor = getMountedSvelteComponentAnchor(svelteComponentSession);
      if (nextAnchor) {
        if (!isSvelteInsertManifest(manifest)) {
          applyOriginalAttrsToSvelteAnchor(nextAnchor, manifest.originalMarkup || '');
        }
        svelteComponentSession.swapAnchor = null;
        selectedElement = nextAnchor;
      } else {
        requestAnimationFrame(() => {
          if (svelteComponentSession?.sessionId !== sessionId) return;
          const settledAnchor = getMountedSvelteComponentAnchor(svelteComponentSession);
          if (!settledAnchor) return;
          if (!isSvelteInsertManifest(manifest)) {
            applyOriginalAttrsToSvelteAnchor(settledAnchor, manifest.originalMarkup || '');
          }
          svelteComponentSession.swapAnchor = null;
          selectedElement = settledAnchor;
        });
      }
      // Render truth, not publish truth: this is the only point in the whole
      // pipeline that proves the user can see variant N.
      reportVariantMounted(sessionId, variantNum, moduleUrl);
      if (mountErrorState?.sessionId === sessionId && mountErrorState.variant === variantNum) {
        clearMountErrorCard();
      }
      return true;
    } catch (err) {
      if (svelteComponentSession?.sessionId === sessionId) {
        svelteComponentSession.swapAnchor = null;
      }
      console.error('[impeccable] Failed to mount component variant ' + variantNum + ' for ' + sessionId + ':', err);
      reportVariantMountFailed(sessionId, variantNum, moduleUrl, err);
      // Every mount failure gets the card, so the variant-switch path (which
      // used to revert with no feedback whatsoever) says what broke too.
      showMountErrorCard(sessionId, {
        variant: variantNum,
        url: moduleUrl,
        message: await describeMountFailure(manifest, err),
      });
      return false;
    }
  }

  // Distinguishes a broken variant from an unreachable preview tree; the
  // recovery differs (fix the component vs fix the root/dev-server pair).
  async function describeMountFailure(manifest, err) {
    try {
      const probe = await probePreviewTree(manifest);
      if (probe.ok === false) {
        return 'The preview tree is not reachable from the dev server (probe failed on '
          + (probe.tried || []).join(', ')
          + '). The resolved app root and the dev server root likely disagree; restart live from the app the dev server serves.';
      }
    } catch { /* probe is best-effort */ }
    return 'The compiled component could not be imported or mounted. ' + (err?.message || 'Unknown error');
  }

  function teardownSvelteComponentSession(restoreOriginal) {
    if (!svelteComponentSession) return;
    const { wrapperEl, detachedOriginal, runtime, mountedInstance } = svelteComponentSession;
    removeSvelteComponentVariantStyle(svelteComponentSession);
    if (mountedInstance && runtime?.unmount) {
      try { runtime.unmount(mountedInstance); } catch { /* non-fatal */ }
    }
    if (restoreOriginal && detachedOriginal && wrapperEl?.parentElement) {
      wrapperEl.parentElement.replaceChild(detachedOriginal, wrapperEl);
    } else if (wrapperEl?.parentElement) {
      wrapperEl.remove();
    }
    svelteComponentSession = null;
    svelteRuntimePromise = null;
  }

  function applyOriginalAttrsToSvelteAnchor(el, originalMarkup) {
    if (!el || !originalMarkup) return;
    const original = parseOriginalMarkupElement(originalMarkup);
    if (!original || original.tagName !== el.tagName) return;
    for (const attr of original.attributes) {
      if (attr.name === 'class') {
        for (const className of attr.value.split(/\s+/).filter(Boolean)) {
          el.classList.add(className);
        }
      } else if (!el.hasAttribute(attr.name)) {
        el.setAttribute(attr.name, attr.value);
      }
    }
  }

  function commitAcceptedSvelteComponentToDom(sessionId) {
    if (!svelteComponentSession || svelteComponentSession.sessionId !== sessionId) return false;
    const { wrapperEl, runtime, mountedInstance, manifest } = svelteComponentSession;
    const anchor = getMountedSvelteComponentAnchor(svelteComponentSession);
    if (!anchor || !wrapperEl?.parentElement) return false;
    const committed = anchor.cloneNode(true);
    if (!isSvelteInsertManifest(manifest)) {
      applyOriginalAttrsToSvelteAnchor(committed, manifest.originalMarkup || '');
    }
    if (mountedInstance && runtime?.unmount) {
      try { runtime.unmount(mountedInstance); } catch { /* non-fatal */ }
    }
    removeSvelteComponentVariantStyle(svelteComponentSession);
    wrapperEl.parentElement.replaceChild(committed, wrapperEl);
    svelteComponentSession = null;
    svelteRuntimePromise = null;
    selectedElement = committed;
    return true;
  }

  async function injectSvelteComponentsFromManifest(manifestPath, sessionId) {
    // Every (re)injection is a fresh attempt: reset the failure dedupe so a
    // republish that is STILL broken at the same URL reports again instead of
    // being swallowed while the agent believes the repair landed.
    lastReportedMountFailure = null;
    const url = 'http://localhost:' + PORT + '/source?token=' + TOKEN + '&path=' + encodeURIComponent(manifestPath);
    try {
      const res = await fetch(url);
      if (!res.ok) throw new Error(String(res.status));
      const manifest = JSON.parse(await res.text());
      if (manifest.id !== sessionId) {
        // A manifest at the expected path belonging to a different session is
        // an agent-side publish error. Left as a bare return it stranded the
        // bar in GENERATING with no explanation and no event.
        const mismatch = 'Manifest at ' + manifestPath + ' belongs to session ' + (manifest.id || 'unknown') + ', not ' + sessionId + '.';
        reportVariantMountFailed(sessionId, visibleVariant || 1, manifestPath, mismatch);
        showMountErrorCard(sessionId, {
          variant: visibleVariant || 0,
          url: manifestPath,
          message: 'The variant manifest is for a different session. Ask the agent to republish.',
          previewFile: manifestPath,
        });
        return;
      }

      const paramsByVariant = await loadSvelteComponentParams(manifest);
      const availableVariants = Number(manifest.arrivedVariants) || Number(manifest.count) || 1;
      const componentPreviewMode = isFrameworkComponentPreviewMode(manifest.previewMode)
        ? manifest.previewMode
        : 'svelte-component';
      currentSessionId = sessionId;
      expectedVariants = Number(manifest.count) || expectedVariants || 1;
      rememberSessionFileMeta({
        sourceFile: manifest.sourceFile,
        previewFile: manifestPath,
        previewMode: componentPreviewMode,
      });
      if (state !== 'CYCLING') setLiveState('GENERATING');

      const existingWrapper = document.querySelector('[data-impeccable-variants="' + sessionId + '"]');
      if (existingWrapper && svelteComponentSession?.sessionId === sessionId) {
        recoveryWaitingForAnchor = false;
        svelteComponentSession.manifest = manifest;
        svelteComponentSession.paramsByVariant = paramsByVariant;
        arrivedVariants = availableVariants;
        expectedVariants = Number(manifest.count) || expectedVariants || arrivedVariants;
        visibleVariant = visibleVariant > 0 && visibleVariant <= arrivedVariants ? visibleVariant : 1;
        const remounted = await mountSvelteComponentVariant(visibleVariant || 1);
        if (!remounted) {
          // The mount already reported the failure and raised the card.
          // Advancing to CYCLING here would show a bar claiming variants are
          // ready over a page where nothing rendered.
          saveSession();
          return;
        }
        setLiveState('CYCLING');
        showOrUpdateCyclingBar();
        saveSession();
        if (parameterGenerationState === 'loading') completeParameterPublication();
        return;
      }

      const liveEl = findLiveElementForSvelteManifest(manifest);
      if (!liveEl?.parentElement) {
        console.warn('[impeccable] Could not find original element in live DOM.');
        arrivedVariants = availableVariants;
        expectedVariants = Number(manifest.count) || expectedVariants || arrivedVariants;
        const saved = loadSession();
        const savedVisibleVariant = saved && saved.id === sessionId ? saved.visible : 0;
        visibleVariant = visibleVariant > 0 && visibleVariant <= arrivedVariants
          ? visibleVariant
          : (savedVisibleVariant > 0 && savedVisibleVariant <= arrivedVariants ? savedVisibleVariant : 1);
        enterRecoveryWaitingForAnchor({ checkpointReason: 'component_preview_anchor_missing', trackScroll: true });
        waitForSvelteComponentTargetAndRetry({ manifestPath, sessionId, manifest });
        return;
      }

      const wrapper = document.createElement('div');
      wrapper.dataset.impeccableVariants = sessionId;
      wrapper.dataset.impeccableVariantCount = String(manifest.count || expectedVariants || 1);
      wrapper.dataset.impeccablePreview = componentPreviewMode;
      wrapper.style.display = 'contents';

      const mountTarget = document.createElement('div');
      mountTarget.dataset.impeccableComponentMount = sessionId;
      mountTarget.style.display = 'contents';
      wrapper.appendChild(mountTarget);

      const insertMode = isSvelteInsertManifest(manifest);
      const detachedOriginal = insertMode ? null : liveEl;
      if (insertMode) {
        removeInsertPlaceholderDom();
        if (manifest.position === 'before') liveEl.parentElement.insertBefore(wrapper, liveEl);
        else liveEl.parentElement.insertBefore(wrapper, liveEl.nextSibling);
      } else {
        liveEl.parentElement.replaceChild(wrapper, liveEl);
      }

      svelteComponentSession = {
        sessionId,
        manifest,
        insertMode,
        wrapperEl: wrapper,
        mountTargetEl: mountTarget,
        detachedOriginal,
        mountedInstance: null,
        mountedVariant: 0,
        runtime: null,
        propValues: buildSveltePropValuesFromLiveElement(detachedOriginal, manifest),
        paramsByVariant,
      };
      if (pendingSvelteComponentRetryObserver) {
        pendingSvelteComponentRetryObserver.disconnect();
        pendingSvelteComponentRetryObserver = null;
      }
      recoveryWaitingForAnchor = false;

      const previousVisibleVariant = currentSessionId === sessionId ? visibleVariant : 0;
      arrivedVariants = availableVariants;
      expectedVariants = Number(manifest.count) || expectedVariants || arrivedVariants;
      const saved = loadSession();
      const savedVisibleVariant = saved && saved.id === sessionId ? saved.visible : 0;
      visibleVariant = previousVisibleVariant > 0 && previousVisibleVariant <= arrivedVariants
        ? previousVisibleVariant
        : (savedVisibleVariant > 0 && savedVisibleVariant <= arrivedVariants ? savedVisibleVariant : 1);

      const mounted = await mountSvelteComponentVariant(visibleVariant);
      if (!mounted) {
        // The compiled component threw (e.g. a Svelte compile error in the
        // variant file). mountSvelteComponentVariant already reported the
        // failure and raised the card; tear the half-built preview down but
        // keep the session so Retry and a republish still have something to
        // act on.
        abortSvelteComponentInjection(sessionId);
        return;
      }

      selectedElement = mountTarget.firstElementChild || mountTarget;
      setLiveState('CYCLING');
      recoveryWaitingForAnchor = false;
      hideShaderOverlay();
      showOrUpdateCyclingBar();
      disableInlineEdit();
      refreshParamsPanel();
      positionBar();
      saveSession();
      if (parameterGenerationState === 'loading') completeParameterPublication();
      console.log('[impeccable] Mounted ' + arrivedVariants + ' ' + manifest.framework + ' component variants.');
    } catch (err) {
      console.error('[impeccable] Failed to mount component-preview variants:', err);
      // Report the manifest PATH, never the fetch URL: that URL carries the
      // live helper token and this string is journaled.
      reportVariantMountFailed(sessionId, visibleVariant || 1, manifestPath, err);
      abortSvelteComponentInjection(sessionId, {
        variant: visibleVariant || 0,
        url: manifestPath,
        message: 'Could not read the variant manifest. ' + (err?.message || 'Unknown error'),
        previewFile: manifestPath,
      });
    }
  }

  function waitForSvelteComponentTargetAndRetry({ manifestPath, sessionId, manifest }) {
    if (pendingSvelteComponentRetryObserver) pendingSvelteComponentRetryObserver.disconnect();
    pendingSvelteComponentRetryObserver = new MutationObserver(() => {
      if (svelteComponentSession?.sessionId === sessionId) {
        pendingSvelteComponentRetryObserver.disconnect();
        pendingSvelteComponentRetryObserver = null;
        return;
      }
      const liveEl = findLiveElementForSvelteManifest(manifest);
      if (!liveEl?.parentElement) return;
      pendingSvelteComponentRetryObserver.disconnect();
      pendingSvelteComponentRetryObserver = null;
      injectSvelteComponentsFromManifest(manifestPath, sessionId);
    });
    pendingSvelteComponentRetryObserver.observe(document.body, { childList: true, subtree: true });
  }

  //
  // Mount acknowledgements
  //
  // The agent's `done` says it published files. Only the browser knows whether
  // the import resolved and the component reached the DOM. These two events
  // carry that answer back, so the journal, `live-status`, and `live-resume`
  // can tell "the user is comparing variants" from "nothing ever rendered".

  // Mirror of the caps in live/event-validation.mjs. Trimming here keeps a
  // stack-trace-sized error from being rejected outright and lost.
  const MOUNT_URL_MAX = 2000;
  const MOUNT_ERROR_MAX = 1000;

  function reportVariantMounted(sessionId, variantNum, moduleUrl) {
    const variant = Math.floor(Number(variantNum) || 0);
    if (!sessionId || variant < 1) return;
    sendEvent({
      type: 'variant_mounted',
      id: sessionId,
      variant,
      url: moduleUrl ? String(moduleUrl).slice(0, MOUNT_URL_MAX) : undefined,
    });
  }

  function reportVariantMountFailed(sessionId, variantNum, moduleUrl, error) {
    if (!sessionId) return;
    const parsed = Math.floor(Number(variantNum) || 0);
    const variant = parsed >= 1 ? parsed : 1;
    const url = String(moduleUrl || 'unknown').slice(0, MOUNT_URL_MAX);
    const message = String(error?.message || error || 'Unknown mount error').slice(0, MOUNT_ERROR_MAX);
    // Progressive delivery and the Retry button both re-enter the same failure.
    // Report each distinct one once so the agent's poll queue and the journal
    // stay readable; a genuinely new failure (different variant, URL, or
    // message) still gets through.
    const key = sessionId + '|' + variant + '|' + url + '|' + message;
    if (lastReportedMountFailure === key) return;
    lastReportedMountFailure = key;
    sendEvent({ type: 'variant_mount_failed', id: sessionId, variant, url, error: message });
  }

  function truncateMiddle(value, max) {
    const text = String(value || '');
    if (text.length <= max) return text;
    const head = Math.ceil((max - 1) / 2);
    const tail = max - 1 - head;
    return text.slice(0, head) + '…' + text.slice(text.length - tail);
  }

  /**
   * Persistent failure surface. Replaces the old 5s toast: a toast that
   * disappears while the session is unusable is indistinguishable from no
   * feedback at all, and the wipe that came with it deleted the only handle on
   * a session the server still considered live.
   */
  function showMountErrorCard(sessionId, details) {
    mountErrorState = {
      sessionId: sessionId || currentSessionId || null,
      variant: Math.floor(Number(details?.variant) || 0),
      url: details?.url ? String(details.url) : '',
      message: details?.message || 'A variant failed to load.',
      previewFile: details?.previewFile || currentPreviewFile || null,
    };
    renderMountErrorCard();
  }

  function clearMountErrorCard() {
    mountErrorState = null;
    if (mountErrorEl) {
      mountErrorEl.remove();
      mountErrorEl = null;
    }
  }

  function mountErrorCardBottomOffset() {
    const barRect = globalBarEl?.getBoundingClientRect();
    return barRect && barRect.height > 0
      ? Math.max(16, window.innerHeight - barRect.top + 12)
      : 16;
  }

  function renderMountErrorCard() {
    if (!mountErrorState) return;
    if (mountErrorEl) mountErrorEl.remove();
    const P = BP || barPaletteForTheme(detectPageTheme());
    const card = el('div', {
      position: 'fixed', bottom: mountErrorCardBottomOffset() + 'px', left: '50%',
      transform: 'translateX(-50%)',
      display: 'flex', flexDirection: 'column', gap: '6px',
      background: P.surface, color: P.text,
      border: '1px solid oklch(65% 0.18 30 / 0.55)',
      borderRadius: '8px', padding: '10px 12px',
      fontFamily: FONT, fontSize: '12px',
      boxShadow: P.shadow, zIndex: Z.toast,
      maxWidth: 'min(520px, calc(100vw - 32px))',
      pointerEvents: 'auto', textAlign: 'left',
    });
    card.id = PREFIX + '-mount-error';

    const head = el('div', { display: 'flex', alignItems: 'center', gap: '8px' });
    const glyph = el('span', { fontSize: '13px', lineHeight: '1', color: 'oklch(62% 0.19 30)', flexShrink: '0' });
    glyph.textContent = '⚠';
    head.appendChild(glyph);
    const title = el('span', { fontWeight: '600', flex: '1' });
    title.textContent = mountErrorState.variant > 0
      ? 'Variant ' + mountErrorState.variant + ' failed to load'
      : 'Variants failed to load';
    head.appendChild(title);
    const dismiss = el('button', {
      border: 'none', background: 'transparent', color: P.textDim,
      cursor: 'pointer', fontFamily: FONT, fontSize: '14px', lineHeight: '1',
      padding: '0 2px', flexShrink: '0',
    });
    dismiss.textContent = '×';
    dismiss.setAttribute('aria-label', 'Dismiss');
    dismiss.addEventListener('click', (e) => {
      e.stopPropagation();
      clearMountErrorCard();
      // The card was the only recovery affordance while the bar is hidden;
      // dismissing it must hand the user back a usable surface. PICKING
      // reactivates the global mark and the picker. The saved session and
      // server truth survive, so a later republish (SSE `done`) still
      // resurrects the comparison through the normal handlers.
      if (state === 'GENERATING') setLiveState('PICKING');
    });
    head.appendChild(dismiss);
    card.appendChild(head);

    const body = el('div', { color: P.textDim, lineHeight: '1.4' });
    body.textContent = mountErrorState.message;
    card.appendChild(body);

    if (mountErrorState.url) {
      const urlLine = el('div', {
        fontFamily: MONO, fontSize: '11px', color: P.textDim,
        wordBreak: 'break-all', opacity: '0.85',
      });
      urlLine.textContent = truncateMiddle(mountErrorState.url, 72);
      urlLine.title = mountErrorState.url;
      card.appendChild(urlLine);
    }

    const actions = el('div', { display: 'flex', gap: '8px', marginTop: '2px' });
    const retry = el('button', {
      border: '1px solid ' + P.hairline, background: 'transparent',
      color: P.text, fontFamily: FONT, fontSize: '12px', fontWeight: '500',
      borderRadius: '5px', padding: '4px 10px', cursor: 'pointer',
    });
    retry.textContent = 'Retry';
    retry.dataset.impeccableMountRetry = 'true';
    retry.addEventListener('click', (e) => { e.stopPropagation(); retryMountErrorCard(); });
    actions.appendChild(retry);
    card.appendChild(actions);

    mountErrorEl = card;
    uiAppend(card);
    defangOutsideHandlers(card);
  }

  function retryMountErrorCard() {
    const info = mountErrorState;
    if (!info) return;
    const sessionId = info.sessionId || currentSessionId;
    const manifestPath = info.previewFile || currentPreviewFile;
    clearMountErrorCard();
    if (!sessionId || !manifestPath) {
      showToast('No variant manifest to retry. Ask the agent to republish.', 5000);
      return;
    }
    // A retry must be able to report the same failure again, otherwise a second
    // attempt against an unchanged broken module would look silent.
    lastReportedMountFailure = null;
    if (state !== 'CYCLING') setLiveState('GENERATING');
    injectSvelteComponentsFromManifest(manifestPath, sessionId);
  }

  // Tear down a component preview that could not mount, WITHOUT touching
  // session identity. The old version cleared localStorage, nulled
  // currentSessionId, and reset to PICKING, which orphaned a session the server
  // still had in its journal and made every recovery path unreachable. The DOM
  // teardown and observer cleanup are still right; the state wipe never was.
  function abortSvelteComponentInjection(sessionId, details) {
    try {
      if (svelteComponentSession?.sessionId === sessionId) {
        teardownSvelteComponentSession(true);
      } else {
        const orphan = document.querySelector('[data-impeccable-variants="' + sessionId + '"]');
        if (orphan) orphan.remove();
      }
    } catch (err) {
      console.warn('[impeccable] Svelte component abort cleanup failed:', err);
    }
    hideShaderOverlay();
    if (pendingSvelteComponentRetryObserver) { pendingSvelteComponentRetryObserver.disconnect(); pendingSvelteComponentRetryObserver = null; }
    if (pendingVariantAnchorRetryObserver) { pendingVariantAnchorRetryObserver.disconnect(); pendingVariantAnchorRetryObserver = null; }
    // The generate submit armed a scroll lock and a variant observer; a page
    // the user cannot scroll, watched by a stale observer, is exactly the
    // wrong place to show a card asking them to act.
    stopScrollLock();
    if (variantObserver) { variantObserver.disconnect(); variantObserver = null; }
    removeVariantStateStylesheet();
    hideBar(true);
    // currentSessionId, the saved session, and the file metadata all survive on
    // purpose: Retry, a republish from the agent, and a page reload all need
    // them. saveSession keeps the localStorage cache in step with the server.
    saveSession();
    if (details) showMountErrorCard(sessionId, details);
    else if (!mountErrorState) {
      showMountErrorCard(sessionId, { message: 'Variants could not be mounted. Retry, or ask the agent to republish.' });
    }
  }

  // Hard reset for the one case that is not a mount failure: a cycling state
  // with nothing to cycle. There is no variant to retry and no URL to report,
  // so the session really is over.
  function resetSvelteComponentSession(sessionId, message) {
    try {
      if (svelteComponentSession?.sessionId === sessionId) {
        teardownSvelteComponentSession(true);
      } else {
        const orphan = document.querySelector('[data-impeccable-variants="' + sessionId + '"]');
        if (orphan) orphan.remove();
      }
    } catch (err) {
      console.warn('[impeccable] Svelte component reset cleanup failed:', err);
    }
    hideShaderOverlay();
    if (variantObserver) { variantObserver.disconnect(); variantObserver = null; }
    if (pendingSvelteComponentRetryObserver) { pendingSvelteComponentRetryObserver.disconnect(); pendingSvelteComponentRetryObserver = null; }
    if (pendingVariantAnchorRetryObserver) { pendingVariantAnchorRetryObserver.disconnect(); pendingVariantAnchorRetryObserver = null; }
    stopScrollLock();
    removeVariantStateStylesheet();
    clearMountErrorCard();
    clearSession();
    clearHandled();
    resetSessionFileMeta();
    currentSessionId = null;
    parameterGenerationState = 'idle';
    parameterReadyAnnouncedSession = null;
    expectedVariants = 0;
    arrivedVariants = 0;
    visibleVariant = 0;
    selectedElement = null;
    setLiveState('PICKING');
    hideBar();
    if (message) showToast(message, 5000);
  }

  // How many delayed re-reads a completion-driven source fallback gets when
  // the fetched source still shows only the preflight scaffold, before the
  // failure is surfaced via recoverEmptyCycling.
  const COMPLETED_SOURCE_FALLBACK_RETRIES = 3;
  const COMPLETED_SOURCE_FALLBACK_RETRY_MS = 1200;

  /**
   * Terminal recovery for a session whose source-side scaffolding no longer
   * exists. The discard event is best-effort: with no agent polling it parks
   * the durable session in discard_requested, which no resume path adopts;
   * with an agent attached it triggers the normal discard finalization.
   */
  function discardOrphanedSession(reason) {
    const sessionId = currentSessionId;
    if (!sessionId) return;
    console.warn('[impeccable] Discarding orphaned session ' + sessionId + ': ' + reason);
    sendEvent({ type: 'discard', id: sessionId, orphaned: true }).catch(() => {});
    markSessionHandled();
    cleanup({ instantChrome: true });
    showToast('The previous live session no longer matches the source file, so it was discarded. Pick an element to start fresh.', 6000);
  }

  /**
   * No-HMR fallback: fetch the raw source file from the live server,
   * parse it, extract the variant wrapper, and inject it into the live DOM.
   * This works even when the dev server caches HTML (Bun, static servers).
   *
   * opts.generationCompleted marks callers that KNOW the agent finished (a
   * `done` arrived or the server reported a completed generation). For them an
   * empty read is a stale source view and no further event is coming, so the
   * read retries a few times and then surfaces recovery. Callers without the
   * flag may be mid-generation and wait indefinitely for the real completion.
   */
  function injectVariantsFromSource(filePath, sessionId, opts = {}) {
    if (isSvelteComponentManifestPath(filePath)) {
      injectSvelteComponentsFromManifest(filePath, sessionId);
      return;
    }
    rememberSessionFileMeta({ file: filePath });
    const url = 'http://localhost:' + PORT + '/source?token=' + TOKEN + '&path=' + encodeURIComponent(filePath);
    fetch(url)
      .then(r => { if (!r.ok) throw new Error(r.status); return r.text(); })
      .then(html => {
        const parser = new DOMParser();
        let srcWrapper = null;

        // Full-file parse works for HTML/JSX; Astro/Vue sources need marker extraction.
        const startMark = '<!-- impeccable-variants-start ' + sessionId + ' -->';
        const endMark = '<!-- impeccable-variants-end ' + sessionId + ' -->';
        const startIdx = html.indexOf(startMark);
        const endIdx = html.indexOf(endMark);
        const block = startIdx !== -1 && endIdx !== -1 && endIdx > startIdx
          ? html.slice(startIdx + startMark.length, endIdx).trim()
          : html;
        const doc = parser.parseFromString(normalizeSourceFallbackBlock(block, filePath), 'text/html');
        srcWrapper = doc.querySelector('[data-impeccable-variants="' + sessionId + '"]');
        if (!srcWrapper) {
          console.warn('[impeccable] Variant wrapper not found in source file.');
          // A resumed cycling session whose wrapper is gone from source is an
          // ORPHAN: the file was edited or regenerated out from under it, so
          // no reload, HMR push, or server restart can ever complete it, and
          // the frozen picker it leaves behind used to need a manual
          // live-complete --discarded. Retry a few reads first (an agent
          // rewrite or HMR patch may be mid-flight), then self-discard and
          // hand the surface back to the picker.
          if (opts.orphanDiscard && sessionId === currentSessionId) {
            const attempt = opts._orphanAttempt || 0;
            if (attempt < COMPLETED_SOURCE_FALLBACK_RETRIES) {
              setTimeout(() => {
                if (sessionId !== currentSessionId) return;
                if (state !== 'GENERATING' && state !== 'CYCLING') return;
                injectVariantsFromSource(filePath, sessionId, { ...opts, _orphanAttempt: attempt + 1 });
              }, COMPLETED_SOURCE_FALLBACK_RETRY_MS);
            } else {
              discardOrphanedSession('variant wrapper missing from source');
            }
          }
          return;
        }

        const previousVisibleVariant = currentSessionId === sessionId ? visibleVariant : 0;
        const wrapper = srcWrapper.cloneNode(true);

        // Wrapper already in DOM (wrap HMR landed, variant insert did not).
        const existingWrapper = document.querySelector('[data-impeccable-variants="' + sessionId + '"]');
        if (existingWrapper) {
          existingWrapper.parentElement.replaceChild(wrapper, existingWrapper);
        } else {
          const origContent = srcWrapper.querySelector('[data-impeccable-variant="original"] > :first-child');
          if (!origContent) return;

          const liveEl = resolveLiveInjectionAnchor(origContent.outerHTML);
          if (!liveEl) {
            console.warn('[impeccable] Could not find original element in live DOM.');
            enterRecoveryWaitingForAnchor({
              filePath,
              sessionId,
              srcWrapper,
              checkpointReason: 'variant_anchor_missing',
              trackScroll: false,
            });
            return;
          }

          liveEl.parentElement.replaceChild(wrapper, liveEl);
        }
        recoveryWaitingForAnchor = false;
        if (pendingVariantAnchorRetryObserver) {
          pendingVariantAnchorRetryObserver.disconnect();
          pendingVariantAnchorRetryObserver = null;
        }

        // Update state: count variants, preserving the user's current variant
        // when a late HMR/source reinjection lands after they have cycled.
        const variants = wrapper.querySelectorAll('[data-impeccable-variant]:not([data-impeccable-variant="original"])');
        arrivedVariants = variants.length;
        expectedVariants = parseInt(wrapper.dataset.impeccableVariantCount || arrivedVariants);
        if (arrivedVariants <= 0) {
          if (state === 'GENERATING') {
            // Mid-generation the source legitimately holds a scaffold wrapper
            // with no variants yet (the server-side preflight wraps before the
            // agent writes). Tearing the session down here would destroy an
            // in-flight generation; stay in GENERATING — the variant observer
            // is armed and the server re-delivers a missed `done`.
            if (!opts.generationCompleted) {
              console.log('[impeccable] Source has scaffold but no variants yet; still generating.');
              return;
            }
            // Generation finished, yet the read shows only the scaffold: the
            // source view is stale and no further event will fire. Re-read a
            // few times before surfacing recovery — a single silent return
            // here would strand the tab in GENERATING forever.
            const attempt = opts.attempt || 0;
            if (attempt < COMPLETED_SOURCE_FALLBACK_RETRIES) {
              console.log('[impeccable] Generation is done but source shows no variants yet; retrying read ('
                + (attempt + 1) + '/' + COMPLETED_SOURCE_FALLBACK_RETRIES + ').');
              setTimeout(() => {
                if (state !== 'GENERATING' || currentSessionId !== sessionId) return;
                if (arrivedVariants > 0) return;
                injectVariantsFromSource(filePath, sessionId, { ...opts, attempt: attempt + 1 });
              }, COMPLETED_SOURCE_FALLBACK_RETRY_MS);
              return;
            }
          }
          recoverEmptyCycling('source-fallback-empty');
          return;
        }
        const saved = loadSession();
        const savedVisibleVariant = saved && saved.id === sessionId ? saved.visible : 0;
        visibleVariant = previousVisibleVariant > 0 && previousVisibleVariant <= arrivedVariants
          ? previousVisibleVariant
          : (savedVisibleVariant > 0 && savedVisibleVariant <= arrivedVariants ? savedVisibleVariant : 1);
        showVariantInDOM(sessionId, visibleVariant);

        // Update selectedElement to the visible variant's content
        selectedElement = pickVariantContent(wrapper, visibleVariant) || wrapper.parentElement;

        setLiveState('CYCLING');
        recoveryWaitingForAnchor = false;
        hideShaderOverlay();
        showOrUpdateCyclingBar();
        disableInlineEdit();
        refreshParamsPanel();
        positionBar();
        saveSession();
        if (parameterGenerationState === 'loading') completeParameterPublication();
        console.log('[impeccable] Injected ' + arrivedVariants + ' variants from source file.');
      })
      .catch(err => {
        console.error('[impeccable] Failed to fetch source:', err);
        showToast('Could not load variants. Try refreshing the page.', 5000);
      });
  }

  function normalizeSourceFallbackBlock(block, filePath) {
    if (!/\.[cm]?[jt]sx$/i.test(String(filePath || ''))) return block;
    return String(block)
      .replace(
        /<style\b([^>]*)>\s*\{\s*`([\s\S]*?)`\s*\}\s*<\/style>/g,
        (_match, attrs, css) => '<style' + attrs + '>' + css + '</style>',
      )
      .replace(/\bclassName\s*=\s*\{\s*`([^`]*?)`\s*\}/g, (_match, value) => {
        const literalClasses = value.replace(/\$\{[^}]*\}/g, ' ').replace(/\s+/g, ' ').trim();
        return literalClasses ? 'class="' + escapeHtml(literalClasses) + '"' : '';
      })
      .replace(/\bclassName\s*=/g, 'class=')
      .replace(/\sstyle=\{\{([\s\S]*?)\}\}/g, (_match, body) => {
        const css = jsxStyleObjectToCss(body);
        return css ? ' style="' + escapeHtml(css) + '"' : '';
      });
  }

  function jsxStyleObjectToCss(body) {
    const declarations = [];
    const re = /(["'][^"']+["']|[A-Za-z_$][\w$-]*)\s*:\s*(?:"([^"]*)"|'([^']*)'|(-?\d+(?:\.\d+)?))/g;
    let match;
    while ((match = re.exec(String(body || '')))) {
      const prop = jsxStylePropToCss(match[1]);
      const value = match[2] ?? match[3] ?? match[4] ?? '';
      if (!prop || value === '') continue;
      declarations.push(prop + ': ' + value);
    }
    return declarations.join('; ');
  }

  function jsxStylePropToCss(prop) {
    let out = String(prop || '').trim().replace(/^["']|["']$/g, '');
    if (!out) return '';
    if (out.startsWith('--')) return out;
    return out.replace(/[A-Z]/g, (ch) => '-' + ch.toLowerCase()).replace(/^-ms-/, '-ms-');
  }

  function buildSvelteExpressionTextMap(sourceOriginal, liveOriginal) {
    const map = new Map();
    if (!sourceOriginal || !liveOriginal) return map;

    const sourceNodes = collectTextNodes(sourceOriginal)
      .filter((node) => /\{[^{}]+\}/.test(node.nodeValue || ''));
    const liveTexts = collectTextNodes(liveOriginal)
      .map((node) => normalizePreviewText(node.nodeValue || ''))
      .filter(Boolean);
    let liveIndex = 0;

    for (const sourceNode of sourceNodes) {
      const sourceText = sourceNode.nodeValue || '';
      const tokens = sourceText.match(/\{[^{}]+\}/g) || [];
      if (tokens.length === 0) continue;

      const liveText = liveTexts[liveIndex++] || '';
      if (!liveText) continue;

      if (tokens.length === 1) {
        const token = tokens[0];
        const normalizedSource = normalizePreviewText(sourceText);
        if (normalizedSource === token) {
          map.set(token, liveText);
          continue;
        }

        const match = liveText.match(expressionTextMatcher(sourceText, [token]));
        if (match && match[1]) map.set(token, match[1].trim());
        continue;
      }

      if (normalizePreviewText(sourceText) === tokens.join(' ')) {
        for (const token of tokens) {
          const tokenLiveText = liveTexts[liveIndex - 1] || '';
          if (tokenLiveText) map.set(token, tokenLiveText);
        }
      }
    }

    return map;
  }

  function expressionTextMatcher(sourceText, tokens) {
    let pattern = '^';
    let cursor = 0;
    for (const token of tokens) {
      const index = sourceText.indexOf(token, cursor);
      if (index === -1) continue;
      pattern += escapeRegExp(sourceText.slice(cursor, index)).replace(/\s+/g, '\\s*');
      pattern += '(.*?)';
      cursor = index + token.length;
    }
    pattern += escapeRegExp(sourceText.slice(cursor)).replace(/\s+/g, '\\s*') + '$';
    return new RegExp(pattern);
  }

  function collectTextNodes(root) {
    if (!root) return [];
    const nodes = [];
    const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
    let node = walker.nextNode();
    while (node) {
      nodes.push(node);
      node = walker.nextNode();
    }
    return nodes;
  }

  function normalizePreviewText(value) {
    return String(value || '').replace(/\s+/g, ' ').trim();
  }

  function escapeRegExp(value) {
    return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  }

  async function selectVariant(next, checkpointReason) {
    if (pendingApplyInFlight) { showManualApplyBusyToast(); return; }
    if (variantSelectionInFlight) return;
    if (next < 1 || next > arrivedVariants) return;
    if (next === visibleVariant) return;

    const previous = visibleVariant;
    variantSelectionInFlight = true;
    const selectionPromise = (async () => {
      visibleVariant = next;
      showOrUpdateCyclingBar();
      saveSession();
      const shown = await showVariantInDOM(currentSessionId, next); // calls refreshParamsPanel itself
      if (!shown) {
        visibleVariant = previous;
        await showVariantInDOM(currentSessionId, previous);
        showOrUpdateCyclingBar();
        saveSession();
        return;
      }
      updateSelectedElement();
      showOrUpdateCyclingBar();
      positionBar();
      saveSession();
      if (checkpointReason) queueCheckpoint(checkpointReason);
    })();
    variantSelectionPromise = selectionPromise;
    try {
      await selectionPromise;
    } finally {
      if (variantSelectionPromise === selectionPromise) variantSelectionPromise = null;
      variantSelectionInFlight = false;
    }
  }

  function cycleVariant(dir) {
    selectVariant(visibleVariant + dir, 'variant_changed');
  }

  function updateSelectedElement() {
    if (!currentSessionId) return;
    if (svelteComponentSession?.sessionId === currentSessionId) {
      const anchor = resolveSvelteComponentAnchor();
      if (anchor && !anchor.__impeccableFrozenAnchor) selectedElement = anchor;
      return;
    }
    const wrapper = document.querySelector('[data-impeccable-variants="' + currentSessionId + '"]');
    if (!wrapper) return;
    const visEl = pickVariantContent(wrapper, visibleVariant);
    if (visEl) selectedElement = visEl;
  }

  function readVisibleVariantFromDOM(sessionId) {
    if (svelteComponentSession?.sessionId === sessionId && svelteComponentSession.mountedVariant > 0) {
      return svelteComponentSession.mountedVariant;
    }
    const wrapper = document.querySelector('[data-impeccable-variants="' + sessionId + '"]');
    if (!wrapper) return 0;
    const variants = wrapper.querySelectorAll('[data-impeccable-variant]:not([data-impeccable-variant="original"])');
    for (const variant of variants) {
      if (!isVariantShown(variant)) continue;
      const idx = parseInt(variant.dataset.impeccableVariant || '0', 10);
      if (idx > 0) return idx;
    }
    return 0;
  }

  // Resolve the element that represents the variant's visible content.
  // Contract: each variant div should contain exactly one top-level element
  // (the full replacement). In practice a model may ship loose siblings or
  // lead with <style>/<script>. Be defensive: skip non-visual elements, and
  // if the variant has multiple element children, use the variant div itself
  // (it wraps all of them and gets correct bounds).
  function pickVariantContent(wrapper, index) {
    if (!wrapper) return null;
    const variantDiv = wrapper.querySelector('[data-impeccable-variant="' + index + '"]');
    if (!variantDiv) return null;
    const NON_VISUAL = new Set(['STYLE', 'SCRIPT', 'LINK', 'META', 'TEMPLATE']);
    const visual = [];
    for (const child of variantDiv.children) {
      if (!NON_VISUAL.has(child.tagName)) visual.push(child);
    }
    if (visual.length === 1) return visual[0];
    return variantDiv;
  }

  // Variant visibility and range/toggle params are expressed through ONE
  // injected stylesheet, never inline attributes on the variant divs. Those
  // divs are scaffolded into page source, so SSR frameworks (Next.js App
  // Router) server-render them; toggling their `hidden` / inline `style` /
  // `--p-*` client-side trips a React 19 hydration mismatch on the next
  // Fast-Refresh re-render — the same failure mode the scroll-anchor (#276)
  // and pick-cursor (#286) fixes address. A stylesheet rule has the same
  // computed effect without mutating any hydrated element's attributes.
  // (steps params keep driving `data-p-*` attributes, matching scoped CSS.)
  const VARIANT_HIDE_DECL = 'display: none !important;';
  const VARIANT_SHOW_DECL = 'display: block !important;';

  // Build a direct-child variant selector for a session. With `num`, targets a
  // single variant (`… > [data-impeccable-variant="N"]`); without it, targets
  // every variant via the bare `[data-impeccable-variant]` attribute.
  function variantStateSelector(sessionId, num) {
    const wrapper = '[data-impeccable-variants="' + sessionId + '"]';
    const variant = num == null
      ? '[data-impeccable-variant]'
      : '[data-impeccable-variant="' + num + '"]';
    return wrapper + ' > ' + variant;
  }

  // Serialize the visible variant's knob values into `--p-<id>` custom-property
  // declarations. Only range (number) and toggle (boolean) values become a
  // custom property; steps params drive `data-p-*` attributes instead.
  function variantParamDecls(values) {
    return Object.entries(values || {})
      .map(([id, val]) => {
        if (typeof val === 'number') return ' --p-' + id + ': ' + val + ';';
        if (typeof val === 'boolean') return ' --p-' + id + ': ' + (val ? '1' : '0') + ';';
        return '';
      })
      .join('');
  }

  function updateVariantStateStylesheet(sessionId, num) {
    if (!sessionId || num == null || num < 1) return;

    let styleEl = document.getElementById(VARIANT_STATE_STYLE_ID);
    if (!styleEl) {
      styleEl = document.createElement('style');
      styleEl.id = VARIANT_STATE_STYLE_ID;
      (document.head || document.documentElement).appendChild(styleEl);
    }

    // Hide every variant except the visible one (incl. the SSR'd "original").
    const hideOthers = variantStateSelector(sessionId)
      + ':not([data-impeccable-variant="' + num + '"]) { ' + VARIANT_HIDE_DECL + ' }';

    // Force-show the visible variant (beats the source inline display:none on
    // v2/v3) and apply its knob values as custom properties.
    const showVisible = variantStateSelector(sessionId, num)
      + ' { ' + VARIANT_SHOW_DECL + variantParamDecls(paramsCurrentValues) + ' }';

    styleEl.textContent = hideOthers + '\n' + showVisible + '\n';
  }

  function removeVariantStateStylesheet() {
    document.getElementById(VARIANT_STATE_STYLE_ID)?.remove();
  }

  function showOriginalDuringDiscard(sessionId) {
    if (!sessionId) return;
    let styleEl = document.getElementById(DISCARD_STATE_STYLE_ID);
    if (!styleEl) {
      styleEl = document.createElement('style');
      styleEl.id = DISCARD_STATE_STYLE_ID;
      (document.head || document.documentElement).appendChild(styleEl);
    }
    const wrapper = '[data-impeccable-variants="' + sessionId + '"]';
    styleEl.textContent = wrapper + ' > [data-impeccable-variant]:not([data-impeccable-variant="original"]) { display:none !important; }\n'
      + wrapper + ' > [data-impeccable-variant="original"] { display:block !important; }';
  }

  function resolveScrollLockAnchorTop() {
    const anchor = resolveBarAnchor();
    if (!anchor?.isConnected) return null;
    const top = anchor.getBoundingClientRect().top;
    return Number.isFinite(top) ? top : null;
  }

  // Hold window.scrollY at a fixed value across DOM mutations inside the
  // session's wrapper (HMR patches, variant inserts, cycle swaps).
  function startScrollLock(sessionId, initialTargetY, initialAnchorTop) {
    stopScrollLock();
    scrollLockTargetY = typeof initialTargetY === 'number' && isFinite(initialTargetY)
      ? initialTargetY
      : window.scrollY;
    scrollLockAnchorTop = typeof initialAnchorTop === 'number' && isFinite(initialAnchorTop)
      ? initialAnchorTop
      : resolveScrollLockAnchorTop();

    try { history.scrollRestoration = 'manual'; } catch {}

    // Suppress the browser's scroll-anchoring on the scroll root so it can't
    // fight our manual scroll correction. Apply this as a stylesheet rule, not
    // as inline `style` on <html>/<body>: those elements are server-rendered by
    // frameworks like Next.js App Router, and mutating their inline style makes
    // React 19 report a hydration mismatch on the next Fast-Refresh re-render.
    // A <style> rule has the same computed effect without touching any hydrated
    // element's attributes. Like the inline version, it is recreated on every
    // startScrollLock call, so reload survival (driven by the persisted scroll
    // key) is unaffected.
    let anchorLockStyle = document.getElementById(SCROLL_ANCHOR_LOCK_ID);
    if (!anchorLockStyle) {
      anchorLockStyle = document.createElement('style');
      anchorLockStyle.id = SCROLL_ANCHOR_LOCK_ID;
      anchorLockStyle.textContent = 'html,body{overflow-anchor:none !important;}';
      (document.head || document.documentElement).appendChild(anchorLockStyle);
    }

    const correct = (why) => {
      scrollLockRaf = null;
      if (scrollLockTargetY == null) return;
      const anchor = resolveBarAnchor();
      if (anchor?.isConnected && typeof scrollLockAnchorTop === 'number' && isFinite(scrollLockAnchorTop)) {
        const anchorTop = anchor.getBoundingClientRect().top;
        const anchorDelta = anchorTop - scrollLockAnchorTop;
        if (Math.abs(anchorDelta) >= 0.5) {
          window.scrollTo({ top: window.scrollY + anchorDelta, left: window.scrollX, behavior: 'instant' });
          scrollLockTargetY = window.scrollY;
          writeScrollY(scrollLockTargetY);
          return;
        }
      }
      const before = window.scrollY;
      const delta = before - scrollLockTargetY;
      if (Math.abs(delta) < 0.5) {
        return;
      }
      window.scrollTo({ top: scrollLockTargetY, left: window.scrollX, behavior: 'instant' });
    };
    const schedule = (why) => {
      if (scrollLockRaf != null) return;
      scrollLockRaf = requestAnimationFrame(() => correct(why));
    };

    scrollLockObserver = new MutationObserver((mutations) => {
      for (const m of mutations) {
        if (m.target?.closest?.('[data-impeccable-variants="' + sessionId + '"]')) {
          schedule('mutation-in-wrapper');
          return;
        }
        for (const n of m.addedNodes) {
          if (n.nodeType === 1 && (n.matches?.('[data-impeccable-variants="' + sessionId + '"]') || n.querySelector?.('[data-impeccable-variants="' + sessionId + '"]'))) {
            schedule('wrapper-added');
            return;
          }
        }
      }
    });
    scrollLockObserver.observe(document.body, { childList: true, subtree: true });

    scrollLockAbort = new AbortController();
    scrollLockAbort.signal.addEventListener('abort', () => {
      document.getElementById(SCROLL_ANCHOR_LOCK_ID)?.remove();
    }, { once: true });
    const sig = { signal: scrollLockAbort.signal };
    // Track whether the most recent scroll came from a user gesture. We
    // gate user-scroll re-anchoring on this flag so programmatic smooth
    // scrolls (browser reload-restore, scrollIntoView from other scripts)
    // don't accidentally update our target.
    let userGestureAt = 0;
    const USER_GESTURE_WINDOW_MS = 250;

    const reanchor = (why) => {
      if (scrollLockRaf != null) { cancelAnimationFrame(scrollLockRaf); scrollLockRaf = null; }
      const prevTarget = scrollLockTargetY;
      scrollLockTargetY = window.scrollY;
      scrollLockAnchorTop = resolveScrollLockAnchorTop();
      writeScrollY(scrollLockTargetY);
    };
    const markGesture = (why) => {
      userGestureAt = performance.now();
      reanchor(why);
    };
    window.addEventListener('wheel', () => markGesture('wheel'), { passive: true, ...sig });
    window.addEventListener('touchstart', () => markGesture('touchstart'), { passive: true, ...sig });
    window.addEventListener('touchmove', () => markGesture('touchmove'), { passive: true, ...sig });
    window.addEventListener('keydown', (e) => {
      if (['PageDown', 'PageUp', ' ', 'End', 'Home', 'ArrowDown', 'ArrowUp'].includes(e.key)) markGesture('key:' + e.key);
    }, sig);

    // Correct on EVERY scroll event: whether it's the browser's
    // post-reload animated restore or some other script calling
    // scrollIntoView, we want to snap back immediately. Only skip if a
    // user gesture fired in the last 250ms.
    window.addEventListener('scroll', () => {
      const now = window.scrollY;
      if (scrollLockTargetY == null) return;
      if (performance.now() - userGestureAt < USER_GESTURE_WINDOW_MS) return;
      if (Math.abs(now - scrollLockTargetY) < 0.5) return;
      window.scrollTo({ top: scrollLockTargetY, left: window.scrollX, behavior: 'instant' });
    }, { passive: true, ...sig });

    // Apply target synchronously, not via rAF - racing the browser's
    // restore or a smooth-scroll animation means we want to win now.
    if (Math.abs(window.scrollY - scrollLockTargetY) > 0.5) {
      window.scrollTo({ top: scrollLockTargetY, left: window.scrollX, behavior: 'instant' });
    }
  }

  function stopScrollLock() {
    if (scrollLockObserver) { scrollLockObserver.disconnect(); scrollLockObserver = null; }
    if (scrollLockRaf != null) { cancelAnimationFrame(scrollLockRaf); scrollLockRaf = null; }
    if (scrollLockAbort) { scrollLockAbort.abort(); scrollLockAbort = null; }
    scrollLockTargetY = null;
    scrollLockAnchorTop = null;
    // NOTE: do NOT clear the persistent scroll key here. startScrollLock
    // calls us as a reset, and clearing the key would nuke the Go-time
    // scrollY that the next resume needs to read.
  }

  //
  // MutationObserver for progressive variant reveal
  //

  function startVariantObserver(sessionId) {
    let updating = false; // re-entrancy guard

    const obs = new MutationObserver((mutations) => {
      if (updating) return;

      // Only react to mutations that add nodes with data-impeccable-variant,
      // or mutations inside the variant wrapper. Ignore our own bar/UI changes.
      let dominated = false;
      for (const m of mutations) {
        if (m.target.closest?.('[data-impeccable-variants]')) { dominated = true; break; }
        for (const n of m.addedNodes) {
          if (n.nodeType !== 1) continue;
          // Direct hit: the added node itself is the wrapper or a variant.
          if (n.dataset?.impeccableVariants || n.dataset?.impeccableVariant) {
            dominated = true; break;
          }
          // Subtree hit: framework HMR (notably SvelteKit) sometimes replaces
          // a whole subtree where the wrapper is a descendant of the added
          // node. Without this check, the observer ignores those mutations
          // and the session stays in GENERATING forever.
          if (n.querySelector?.('[data-impeccable-variants],[data-impeccable-variant]')) {
            dominated = true; break;
          }
        }
        if (dominated) break;
      }
      if (!dominated) return;

      const wrapper = document.querySelector('[data-impeccable-variants="' + sessionId + '"]');
      if (!wrapper) return;

      const variants = wrapper.querySelectorAll('[data-impeccable-variant]:not([data-impeccable-variant="original"])');
      const count = variants.length;

      // Re-anchor selectedElement if it was detached by live-wrap's HMR swap.
      // Without this, the shader / highlight / bar track a zero-rect phantom
      // and the overlay appears frozen.
      if (selectedElement && !document.body.contains(selectedElement)) {
        const isInsert = wrapper.dataset.impeccableMode === 'insert';
        if (isInsert) {
          const visEl = count > 0 ? pickVariantContent(wrapper, visibleVariant || 1) : null;
          if (visEl) {
            selectedElement = visEl;
            if (count > 0) removeInsertPlaceholderDom();
          } else {
            const ph = ensureInsertPlaceholder();
            if (ph) selectedElement = ph;
            else if (insertAnchorElement && document.body.contains(insertAnchorElement)) {
              selectedElement = insertAnchorElement;
            }
          }
        } else {
          selectedElement = pickVariantContent(wrapper, 'original') || wrapper;
        }
      } else if (isInsertGeneratingSession() && count === 0) {
        ensureInsertPlaceholder();
      }

      // Nothing new
      if (count <= arrivedVariants) return;

      updating = true;
      arrivedVariants = count;
      generationPhase = arrivedVariants >= expectedVariants ? 'variants_ready' : 'variants_progress';
      if (visibleVariant === 0 && arrivedVariants > 0) {
        const saved = loadSession();
        const savedVisibleVariant = saved && saved.id === sessionId ? saved.visible : 0;
        visibleVariant = savedVisibleVariant > 0 && savedVisibleVariant <= arrivedVariants ? savedVisibleVariant : 1;
        showVariantInDOM(sessionId, visibleVariant);
        // showVariantInDOM hid the original (display:none); if we were still
        // anchored to the original's content, its boundingRect is now zero
        // and the bar snaps to (0,0). Re-point at the visible variant instead.
        const visEl = pickVariantContent(wrapper, visibleVariant);
        if (visEl) selectedElement = visEl;
      }

      const expected = parseInt(wrapper.dataset.impeccableVariantCount || '0');
      if (expected > 0) expectedVariants = expected;

      if (arrivedVariants > 0) {
        setLiveState('CYCLING');
        recoveryWaitingForAnchor = false;
        hideShaderOverlay();
        if (wrapper.dataset.impeccableMode === 'insert') finalizeInsertSession();
        updateSelectedElement();
        showOrUpdateCyclingBar();
        disableInlineEdit();
        if (arrivedVariants >= expectedVariants && expectedVariants > 0) refreshParamsPanel();
        else hideParamsPanel();
        positionBar();
      } else if (state === 'GENERATING') {
        updateBarContent('generating');
      }
      saveSession();
      sendCheckpoint(
        arrivedVariants >= expectedVariants && expectedVariants > 0
          ? 'variants_ready'
          : 'variants_progress',
      );
      updating = false;
    });

    obs.observe(document.body, { childList: true, subtree: true });
    return obs;
  }

  //
  // Bar scroll tracking
  //

  function startScrollTracking() {
    function tick() {
      if (state === 'CONFIGURING' || state === 'GENERATING' || state === 'CYCLING') {
        if (isInsertGeneratingSession()) ensureInsertPlaceholder();
        positionBar();
        if (state === 'CONFIGURING') positionEditBadge();
        const hiTarget = resolveBarAnchor();
        if (hiTarget && !hiTarget.hasAttribute?.('data-impeccable-insert-placeholder')) {
          showHighlight(hiTarget);
        } else {
          hideHighlight();
        }
        if (tuneOpen) positionParamsPanel();
      }
      if (state === 'EDITING') {
        positionEditBadge();
        showHighlight(selectedElement);
      }
      if (annotActive) {
        const annotTarget = resolveBarAnchor();
        if (annotTarget) positionAnnotOverlay(annotTarget);
      }
      // Shader overlay (via debug P toggle or generation) is repositioned
      // by its own branch below; debug no longer has a separate overlay.
      if (shaderState) positionShaderOverlay();
      scrollRaf = requestAnimationFrame(tick);
    }
    scrollRaf = requestAnimationFrame(tick);
  }

  function stopScrollTracking() {
    if (scrollRaf) { cancelAnimationFrame(scrollRaf); scrollRaf = null; }
  }

  //
  // SSE (server→browser) + fetch POST (browser→server)
  // Zero-dependency replacement for WebSocket.
  //

  let evtSource = null;
  let sseRetries = 0;
  const SSE_MAX_RETRIES = 20;  // generous: heartbeats keep the connection alive, so retries mean real trouble

  function connectSSE() {
    evtSource = new EventSource('http://localhost:' + PORT + '/events?token=' + TOKEN);

    evtSource.onopen = () => {
      sseRetries = 0; // reset on successful (re)connect
    };

    evtSource.onmessage = (e) => {
      sseRetries = 0; // reset on any successful message
      let msg; try { msg = JSON.parse(e.data); } catch { return; }
      switch (msg.type) {
        case 'connected':
          hasProjectContext = !!msg.hasProjectContext;
          if (!hasProjectContext) showToast(`No PRODUCT.md found. Variants will be brand-agnostic. Run ${IMPECCABLE_COMMAND} init to generate one.`, 7000);
          console.log('[impeccable] Live mode connected.');
          syncAgentPollingUi(!!msg.agentPolling);
          startAgentStatusPoll();
          restoreFromActiveSessions(msg.activeSessions, 'sse_connected');
          recoverMissedGenerationCompletion(msg.activeSessions);
          if (state === 'IDLE' && (pickActive || insertActive)) setLiveState('PICKING');
          syncPageInteractionCursor();
          syncPageChatFocus('sse-connected');
          break;
        case 'agent_polling':
          syncAgentPollingUi(!!msg.connected);
          break;
        case 'agent_phase':
          if (msg.id === currentSessionId && (state === 'GENERATING' || state === 'CYCLING')) {
            // Advance the visible phase monotonically. A behind/resumed
            // checkpoint may carry an earlier phase for internal bookkeeping,
            // but the bar must not move backward.
            if (shouldAdvancePhase(generationPhase, msg.phase)) generationPhase = msg.phase;
            // The deferred parameter pass reports through `variant_progress`
            // with publicationKind 'params', not through agent_phase.
            updateBarContent(state === 'CYCLING' ? 'cycling' : 'generating');
            saveSession();
          }
          break;
        case 'variant_progress':
          if (msg.id === currentSessionId) {
            if (msg.publicationKind === 'params') parameterGenerationState = 'loading';
            rememberSessionFileMeta(msg);
            if (isFrameworkComponentPreviewMode(msg.previewMode) && msg.previewFile) {
              // Component-preview (Svelte/Vue) progressive delivery: the browser
              // mounts compiled components, so there is no framework-owned DOM
              // to race. Keep streaming each checkpoint into the preview.
              injectSvelteComponentsFromManifest(msg.previewFile, msg.id);
            }
            // Source-preview targets: do NOT source-inject per checkpoint.
            // Immediate injection races framework (React/Vue) ownership mid-
            // generation and triggers removeChild errors on the next HMR
            // commit. Let HMR own reconciliation while variants stream in;
            // source injection runs only on the final `done` (which keeps its
            // 750ms settle + retry ladder for non-HMR harnesses like Cursor).
            // The visible progress count still advances from the variant
            // MutationObserver as HMR lands each variant.
          }
          break;
        case 'steer_done':
          maybeCompleteSteer(msg);
          break;
        case 'manual_edit_stashed':
        case 'manual_edit_discarded':
        case 'manual_edit_commit_started':
        case 'manual_edit_apply_reply_received':
        case 'manual_edit_apply_dispatched':
        case 'manual_edit_repair_needs_decision':
        case 'manual_edit_repair_rollback_done':
        case 'manual_edit_commit_done':
        case 'manual_edit_commit_failed':
          handleManualEditActivity(msg);
          break;
        case 'done':
          if (maybeCompleteSteer(msg)) break;
          rememberSessionFileMeta(msg);
          if (msg.id === currentSessionId && isFrameworkComponentPreviewMode(currentPreviewMode) && currentPreviewFile) {
            injectSvelteComponentsFromManifest(currentPreviewFile, msg.id);
            break;
          }
          // Variants already arrived via HMR → normal transition.
          if (arrivedVariants >= expectedVariants && expectedVariants > 0) {
            if (state === 'GENERATING') {
              setLiveState('CYCLING');
              showOrUpdateCyclingBar();
              disableInlineEdit();
              refreshParamsPanel();
            }
            break;
          }
          // Source fallback when HMR did not land variants in this tab.
          if (msg.file && msg.id && state === 'GENERATING' && msg.id === currentSessionId) {
            setTimeout(() => {
              if (arrivedVariants >= expectedVariants && expectedVariants > 0) return;
              if (state !== 'GENERATING' || msg.id !== currentSessionId) return;
              injectVariantsFromSource(msg.file, msg.id, { generationCompleted: true });
            }, 750);
            break;
          }
          // Variants are in source but not in the DOM yet. Common when the
          // picked element lived inside conditional render (closed modal,
          // hidden tab, a route the user navigated away from). The variant
          // MutationObserver stays armed and auto-transitions to CYCLING
          // the moment the wrapper actually mounts. Nudge the user toward
          // that path with a toast - better than the prior force-reload
          // which reset framework state and left the session stuck.
          setTimeout(() => {
            if (arrivedVariants >= expectedVariants && expectedVariants > 0) return;
            if (state !== 'GENERATING') return;
            showToast(
              "Variants ready. If the picked element isn't visible, retrace the path that revealed it - they'll appear automatically.",
              15000,
            );
          }, 2000);
          break;
        case 'complete':
        case 'accept':
          // The real accept result arrived: the awaited failure window closed.
          if (awaitingAcceptResult?.id && msg.id === awaitingAcceptResult.id) awaitingAcceptResult = null;
          if (maybeCompleteAcceptedSession(msg)) break;
          break;
        case 'agent_done':
          // The deterministic accept has already committed the reviewed DOM
          // and fenced generation. Carbonize may continue in the background;
          // it must not hold the foreground picker hostage.
          // Only a carbonize agent_done is provably accept-side: accept
          // unlocks at the first variant, so a late generation agent_done
          // for the same session id can still arrive after Accept and must
          // not close the awaited failure window early (the SSE broadcast
          // carries no sourceEventType to tell the two apart).
          if (msg.data?.carbonize === true && awaitingAcceptResult?.id && msg.id === awaitingAcceptResult.id) awaitingAcceptResult = null;
          if (msg.data?.carbonize === true && maybeCompleteAcceptedSession(msg)) break;
          break;
        case 'discarded':
          if (msg.id && msg.id === currentSessionId) {
            markSessionHandled();
            cleanup();
          }
          break;
        case 'error':
          if (pendingAcceptedSession?.id && msg.id === pendingAcceptedSession.id) {
            pendingAcceptedSession = null;
            awaitingAcceptResult = null;
            setLiveState('CYCLING');
            updateBarContent('cycling');
            showToast('Could not complete accept cleanup. Try Accept again.', 5000);
            break;
          }
          // The optimistic teardown already released the session, so the
          // CYCLING recovery above can no longer match; without this branch
          // the failure fell through to the generic toast and the user had
          // no hint their variant was never written (issue #384).
          if (awaitingAcceptResult?.id && msg.id === awaitingAcceptResult.id) {
            awaitingAcceptResult = null;
            console.error('[impeccable] Accept failed after teardown:', msg.message);
            // Hedged on purpose: a carbonize-phase failure raises this same
            // error after the source WAS promoted, so "was not saved" would
            // overclaim. Normalize the server message's terminal punctuation
            // so the two sentences don't run together.
            const acceptFailDetail = String(msg.message || 'unknown error').trim().replace(/[.!?]?$/, '.');
            showToast('Accept failed: ' + acceptFailDetail + ' The variant may not have been saved. If the change is missing, pick the element and generate again.', 8000);
            break;
          }
          if (maybeCompleteSteer(msg)) break;
          console.error('[impeccable] Error:', msg.message);
          showToast('Error: ' + msg.message, 5000);
          // An agent error reply is terminal for the session it names: tear
          // it down exactly like 'discarded' (cleanup includes clearSession),
          // or the durable localStorage checkpoint survives and every reload
          // resurrects a GENERATING bar for a session the server no longer
          // knows about (issue #362).
          if (msg.id && msg.id === currentSessionId) {
            markSessionHandled();
            cleanup();
            break;
          }
          // A stored-but-not-current checkpoint naming the errored session
          // (the error raced a reload) must not resurrect either.
          if (msg.id && loadSession()?.id === msg.id) clearSession();
          hideBar();
          renderEditBadge('hidden');
          setLiveState('PICKING');
          break;
      }
    };

    evtSource.onerror = () => {
      sseRetries++;
      if (sseRetries <= SSE_MAX_RETRIES) {
        console.log('[impeccable] SSE connection lost. Retry ' + sseRetries + '/' + SSE_MAX_RETRIES + '...');
        return; // EventSource auto-reconnects
      }
      // Server is gone. Clean up gracefully.
      console.log('[impeccable] Live server unreachable. Cleaning up UI.');
      evtSource.close();
      evtSource = null;
      handleServerLost();
    };
  }

  /** Server died or became unreachable. Reset UI to a clean state. */
  function handleServerLost() {
    const recoveryState = currentSessionId ? state : 'IDLE';
    if (state === 'GENERATING' || state === 'CYCLING' || state === 'SAVING') {
      showToast('Live server connection lost. Your session is saved; reopen this page or restart live-poll.mjs to continue.', 6000);
    }
    hideBar();
    hideHighlight();
    hideShaderOverlay();
    hideAnnotOverlay();
    stopScrollTracking();
    if (variantObserver) { variantObserver.disconnect(); variantObserver = null; }
    stopScrollLock();
    // Preserve local session state on server loss. The durable journal is the
    // source of truth, but localStorage plus the variant wrapper lets the UI
    // resume after a helper restart or page reload instead of treating a
    // transient disconnect as an explicit discard.
    selectedElement = null;
    selectedAction = 'impeccable';
    setLiveState(recoveryState);
    if (currentSessionId) saveSession();
  }

  // Progress events must never overtake the event that CREATES their session:
  // the Go-time checkpoint and the generate POST are concurrent fetches, and
  // when the checkpoint lands first the server rightly refuses it as
  // unknown_session — which must mean "foreign leftovers", not "you raced
  // your own Go click". The gate serializes creation before progress.
  let sessionCreationGate = Promise.resolve();

  function sendEvent(msg, opts) {
    msg.token = TOKEN;
    function handleFailure(err) {
      if (opts && opts.throwOnError) {
        console.error('[impeccable] Failed to send event:', err);
        throw err;
      }
      console.debug('[impeccable] Dropped optional live event:', err);
      return null;
    }
    // Token in the query string as well as the body: the URL token is what
    // authorizes the CORS preflight when the page runs on a non-loopback
    // dev host (ddev, Valet), since the preflight carries no request body.
    const doSend = () => fetch('http://localhost:' + PORT + '/events?token=' + encodeURIComponent(TOKEN), {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(msg),
    }).then(async res => {
      if (res.ok) return res;
      const body = await res.json().catch(() => ({}));
      // The server refused to journal progress for a session it has never
      // seen: this browser is carrying state from another project or a
      // wiped store (two apps sharing a localhost port). Continuing to
      // report it would freeze the picker behind a session that can never
      // complete, so drop the local state and hand the surface back.
      if (body.error === 'unknown_session' && msg.type === 'checkpoint'
          && msg.id && msg.id === currentSessionId) {
        abandonForeignSession(msg.id);
        return null;
      }
      return handleFailure(new Error(body.error || ('HTTP ' + res.status + ' ' + res.statusText)));
    }).catch(handleFailure);

    if (msg.type === 'generate' || msg.type === 'steer') {
      const creation = doSend();
      sessionCreationGate = creation.then(() => {}, () => {});
      return creation;
    }
    return sessionCreationGate.then(doSend);
  }

  let abandonedForeignSessionId = null;
  function abandonForeignSession(sessionId) {
    if (abandonedForeignSessionId === sessionId || sessionId !== currentSessionId) return;
    abandonedForeignSessionId = sessionId;
    console.warn('[impeccable] The live server has no record of session ' + sessionId + '; clearing stale local state.');
    markSessionHandled();
    cleanup({ instantChrome: true });
    showToast('A saved live session belonged to a different project, so it was cleared. Pick an element to start fresh.', 6000);
  }

  function checkpointPayload(reason) {
    return {
      type: 'checkpoint',
      id: currentSessionId,
      revision: sessionState.nextCheckpointRevision(),
      revisionDomain: 'browser',
      owner: browserOwner,
      phase: String(state || '').toLowerCase(),
      reason,
      pageUrl: location.pathname,
      expectedVariants,
      arrivedVariants,
      visibleVariant,
      sourceFile: currentSourceFile || undefined,
      previewFile: currentPreviewFile || undefined,
      previewMode: currentPreviewMode || undefined,
      paramValues: { ...paramsCurrentValues },
    };
  }

  function sendCheckpoint(reason) {
    if (!currentSessionId) return Promise.resolve(null);
    return sendEvent(checkpointPayload(reason)).catch(() => null);
  }

  function sendSteerCheckpoint(id, reason, extra) {
    if (!id) return Promise.resolve(null);
    return sendEvent({
      type: 'checkpoint',
      id,
      revision: sessionState.nextCheckpointRevision(),
      revisionDomain: 'browser',
      owner: browserOwner,
      phase: 'steer',
      reason,
      pageUrl: location.pathname,
      ...(extra || {}),
    }).catch(() => null);
  }

  function queueCheckpoint(reason) {
    if (!currentSessionId) return;
    if (checkpointTimer) clearTimeout(checkpointTimer);
    checkpointTimer = setTimeout(() => {
      checkpointTimer = null;
      sendCheckpoint(reason);
    }, 120);
  }

  //
  // Event handlers
  //

  function handleMouseMove(e) {
    if (pendingApplyInFlight) return;
    if (state === 'PICKING' && insertActive) {
      const target = document.elementFromPoint(e.clientX, e.clientY);
      if (!target || own(target) || !pickable(target)) {
        hideInsertLine();
        return;
      }
      const parent = target.parentElement;
      const axis = detectInsertAxis(parent);
      const siblings = layoutFlowChildren(parent);
      const rect = target.getBoundingClientRect();
      const resolved = resolveInsertHover({
        clientX: e.clientX,
        clientY: e.clientY,
        target,
        rect,
        axis,
        siblings,
      });
      if (
        resolved.anchor !== insertHoverAnchor
        || resolved.position !== insertHoverPosition
        || resolved.axis !== insertHoverAxis
      ) {
        showInsertLine(resolved);
      }
      syncPageInteractionCursor();
      return;
    }
    if (state !== 'PICKING' || !pickActive) return;
    const target = document.elementFromPoint(e.clientX, e.clientY);
    if (!target || !pickable(target) || target === hoveredElement) return;
    hoveredElement = target;
    showHighlight(target);
  }

  function handleClick(e) {
    if (pendingApplyInFlight && !pendingDockEl?.contains(e.target)) {
      if (pickerEl?.style.display !== 'none') hideActionPicker();
      if (own(e.target)) {
        e.preventDefault();
        e.stopPropagation();
        showManualApplyBusyToast();
      }
      return;
    }
    // Close action picker on any outside click
    if (pickerEl?.style.display !== 'none' && !own(e.target)) {
      hideActionPicker();
    }
    // Close Tune popover on outside click (anything outside panel + bar)
    if (tuneOpen && paramsPanelEl && !paramsPanelEl.contains(e.target) && barEl && !barEl.contains(e.target)) {
      closeTunePopover();
    }
    // In EDITING: click outside exits the text edit flow without rebuilding configure UI first.
    if (state === 'EDITING' && !own(e.target) && selectedElement && !selectedElement.contains(e.target)) {
      cancelEditingToPicking();
      return;
    }
    // In CONFIGURING: click outside the bar and selected element returns to PICKING.
    if (
      state === 'CONFIGURING' && !own(e.target) && selectedElement
      && !selectedElement.contains(e.target)
    ) {
      if (configureKind === 'insert') { cancelInsertConfigure(); return; }
      exitConfigureToPicking('configure-outside-click', { clearHover: true });
      return;
    }
    if (state === 'PICKING' && insertActive) {
      if (own(e.target)) return;
      if (!insertHoverAnchor || !insertHoverPosition) return;
      e.preventDefault();
      e.stopPropagation();
      const placeholder = createInsertPlaceholder(
        insertHoverAnchor,
        insertHoverPosition,
        insertHoverAxis,
      );
      if (!placeholder) return;
      hideInsertLine();
      configureKind = 'insert';
      selectedElement = placeholder;
      setLiveState('CONFIGURING');
      hideHighlight();
      clearAnnotations();
      showAnnotOverlay(placeholder);
      showBar('configure');
      startScrollTracking();
      return;
    }
    if (state !== 'PICKING' || !pickActive) return;
    if (own(e.target)) return;
    if (pagePickSkipClick || pageHasHostTextSelection()) {
      pagePickSkipClick = false;
      return;
    }
    if (!hoveredElement || !pickable(hoveredElement)) return;
    e.preventDefault();
    e.stopPropagation();
    selectedElement = hoveredElement;
    setLiveState('CONFIGURING');
    showHighlight(selectedElement);
    clearAnnotations();
    showAnnotOverlay(selectedElement);
    showBar('configure');
    renderEditBadge(hasTextRows(selectedElement) ? 'idle' : 'hidden');
    startScrollTracking();
    maybePrefetchPage();
    maybeWarnConditionalAncestor(selectedElement);
  }

  /**
   * Surface a brief, non-blocking heads-up when the picked element lives
   * inside a container whose visibility is gated by ephemeral state - modals,
   * collapsible panels, popovers, off-screen tab panels. If HMR remounts the
   * parent during generation (Vite Fast Refresh, SvelteKit page reload), the
   * variants land in source but stay invisible until the user re-opens the
   * container. Telling the user upfront is much friendlier than the silent
   * timeout-then-toast that they'd otherwise hit.
   *
   * Heuristic, intentionally narrow - only fires for unambiguous cases so
   * we don't cry wolf on every nested element.
   */
  function maybeWarnConditionalAncestor(el) {
    let node = el?.parentElement;
    let depth = 0;
    while (node && depth < 12) {
      // 1. Active dialog / modal
      if (node.getAttribute && node.getAttribute('role') === 'dialog'
          && node.getAttribute('aria-modal') === 'true') {
        showToast('Heads up: this element lives inside a dialog. If state resets during generation, you may need to re-open it.', 6000);
        return;
      }
      // 2. Common Radix / shadcn / headless-ui open-state attribute
      if (node.dataset && node.dataset.state === 'open') {
        showToast('Heads up: this element lives inside an open panel. If state resets during generation, you may need to re-open it.', 6000);
        return;
      }
      // 3. Tab panel - only meaningful when the page also shows ANOTHER
      // tab as selected. A single tabpanel with no tablist is just a static
      // section in disguise and isn't conditional.
      if (node.getAttribute && node.getAttribute('role') === 'tabpanel') {
        const list = document.querySelector('[role="tablist"]');
        if (list) {
          const tabs = list.querySelectorAll('[role="tab"]');
          if (tabs.length > 1) {
            showToast('Heads up: this element lives in a tab panel. If state resets during generation, switch back to this tab.', 6000);
            return;
          }
        }
      }
      // 4. Collapsible: aria-expanded sibling. Look for the trigger button.
      if (node.id) {
        const trigger = document.querySelector(`[aria-controls="${CSS.escape(node.id)}"][aria-expanded="true"]`);
        if (trigger) {
          showToast('Heads up: this element lives inside an expandable section. If state resets during generation, re-expand it.', 6000);
          return;
        }
      }
      node = node.parentElement;
      depth++;
    }
  }

  // Fire a lightweight prefetch event the first time the user selects an
  // element on a given route. The agent uses this to Read the underlying file
  // into context before Go is hit, shaving the read off the critical path.
  // Dedupe per session by pathname - clicking around on the same page doesn't
  // re-fire.
  //
  // DISABLED: quick-Go workflows pay an extra harness round trip because
  // prefetch + generate arrive as two events instead of one. Re-enable with
  // a browser-side debounce (~800-1000ms, cancelled on Go) if we want to
  // resurrect this. Server validator and skill dispatch remain in place so
  // flipping this flag is the only change needed.
  const PREFETCH_ENABLED = false;
  const prefetchedPaths = new Set();
  function maybePrefetchPage() {
    if (!PREFETCH_ENABLED) return;
    const path = location.pathname;
    if (prefetchedPaths.has(path)) return;
    prefetchedPaths.add(path);
    sendEvent({ type: 'prefetch', pageUrl: path });
  }

  function shouldPassthroughElementNav(deepActive, e) {
    if (!deepActive || !own(deepActive)) return false;
    if (e.key !== 'ArrowUp' && e.key !== 'ArrowDown') return false;
    if (!/^(INPUT|TEXTAREA)$/.test(deepActive.tagName || '')) return false;
    if (deepActive.value) return false;
    if (deepActive.id === PREFIX + '-input' && state === 'CONFIGURING') return true;
    if (deepActive.id === PREFIX + '-page-chat-input' && state === 'PICKING') return true;
    return false;
  }

  function handleKeyDown(e) {
    // When the annotation input is focused, let it handle its own keys.
    if (annotEditing && annotEditing.input && e.target === annotEditing.input) return;
    const deepActive = activeElementDeep();
    if (
      deepActive
      && own(deepActive)
      && /^(INPUT|TEXTAREA|SELECT)$/.test(deepActive.tagName || '')
      && !shouldPassthroughElementNav(deepActive, e)
    ) {
      return;
    }
    if (isPageEditableElement(deepActive) && !isInlineEditActive(deepActive)) {
      return;
    }
    // While a contenteditable text-leaf is focused, let the browser handle
    // all keys except Escape. Escape cancels the current edit (restores
    // original text) and blurs without saving, staying in CONFIGURING.
    if (e.target.isContentEditable && isInlineEditActive(e.target)) {
      if (e.key !== 'Escape') return;
      e.preventDefault();
      e.stopPropagation();
      const original = e.target.dataset.impeccableOriginalText;
      if (original !== undefined) e.target.textContent = original;
      // Programmatic textContent doesn't fire the 'input' event, so the draft
      // map would otherwise hold the pre-cancel value and Apply would commit
      // changes the user explicitly undid.
      inlineEditDrafts.delete(e.target);
      e.target.blur();
      return;
    }
    if (pendingApplyInFlight) {
      const liveNavKey = e.key === 'Enter'
        || e.key === 'ArrowUp'
        || e.key === 'ArrowDown'
        || e.key === 'ArrowLeft'
        || e.key === 'ArrowRight';
      if (liveNavKey && (state === 'PICKING' || state === 'CONFIGURING' || state === 'CYCLING')) {
        e.preventDefault();
        e.stopPropagation();
        if (e.key === 'Enter') showManualApplyBusyToast();
      }
      return;
    }
    if (e.key === 'Escape') {
      e.preventDefault();
      if (pickerEl?.style.display !== 'none') { hideActionPicker(); return; }
      if (state === 'EDITING') { cancelEditing(); return; }
      if (state === 'CONFIGURING') {
        if (configureKind === 'insert') { cancelInsertConfigure(); return; }
        exitConfigureToPicking('escape-from-configure');
        return;
      }
      if (state === 'CYCLING') { handleDiscard(); return; }
      if (state === 'SAVING' || state === 'CONFIRMED') return; // don't interrupt
      if (state === 'PICKING') {
        if (insertActive) toggleInsert();
        else if (pickActive) togglePick();
        else { hideHighlight(); setLiveState('IDLE'); }
        return;
      }
    }

    // Arrow/Enter nav works in PICKING (hover) and CONFIGURING (selected, input empty)
    var navEl = (state === 'PICKING') ? hoveredElement : (state === 'CONFIGURING') ? selectedElement : null;
    if (navEl && (e.key === 'ArrowUp' || e.key === 'ArrowDown' || (e.key === 'Enter' && state === 'PICKING'))) {
      let next = null;
      if (e.key === 'ArrowDown' && !e.shiftKey) {
        next = navEl.nextElementSibling;
        while (next && !pickable(next)) next = next.nextElementSibling;
      } else if (e.key === 'ArrowUp' && !e.shiftKey) {
        next = navEl.previousElementSibling;
        while (next && !pickable(next)) next = next.previousElementSibling;
      } else if (e.key === 'ArrowUp' && e.shiftKey) {
        next = navEl.parentElement;
        if (next && !pickable(next)) next = null;
      } else if (e.key === 'ArrowDown' && e.shiftKey) {
        next = navEl.firstElementChild;
        while (next && !pickable(next)) next = next.nextElementSibling;
      } else if (e.key === 'Enter') {
        e.preventDefault();
        selectedElement = hoveredElement;
        setLiveState('CONFIGURING');
        showHighlight(selectedElement);
        clearAnnotations();
        showAnnotOverlay(selectedElement);
        showBar('configure');
        renderEditBadge(hasTextRows(selectedElement) ? 'idle' : 'hidden');
        startScrollTracking();
        return;
      }
      if (next) {
        e.preventDefault();
        if (state === 'PICKING') {
          hoveredElement = next;
        } else {
          // CONFIGURING: re-select the new element
          selectedElement = next;
          clearAnnotations();
          showAnnotOverlay(next);
          showBar('configure');
          disableInlineEdit();
          renderEditBadge(hasTextRows(selectedElement) ? 'idle' : 'hidden');
          startScrollTracking();
        }
        showHighlight(next);
        next.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
      }
      return;
    }

    if (state === 'CYCLING') {
      if (e.key === 'ArrowLeft') { e.preventDefault(); cycleVariant(-1); }
      if (e.key === 'ArrowRight') { e.preventDefault(); cycleVariant(1); }
      if (e.key === 'Enter') { e.preventDefault(); handleAccept(); }
    }
  }

  function handleGo() {
    if (pendingApplyInFlight) { showManualApplyBusyToast(); return; }
    if (!selectedElement || state !== 'CONFIGURING') return;
    stopVoice({ suppressSubmit: true });
    const input = uiGetById(PREFIX + '-input');
    const prompt = input ? input.value.trim() : '';

    // Commit any pending pin edit BEFORE we snapshot annotations.
    if (annotEditing) finalizeEditingPin();
    // Go captures page content, not manual-edit runtime state.
    disableInlineEdit();
    stripManualEditRuntimeState(selectedElement);

    // A new cycle publishes new modules, so the previous cycle's mount failure
    // is about files that no longer matter.
    clearMountErrorCard();
    lastReportedMountFailure = null;
    pendingAcceptedSession = null;
    // A new session supersedes any accept still awaiting its result; a late
    // failure toast for the previous session would only mislead here.
    awaitingAcceptResult = null;
    currentSessionId = id8();
    expectedVariants = selectedCount;
    arrivedVariants = 0;
    visibleVariant = 0;
    generationPhase = 'queued';
    parameterGenerationState = 'pending';
    parameterReadyAnnouncedSession = null;
    resetSessionFileMeta();

    // Flip to GENERATING immediately so the bar morphs without waiting on
    // capture + upload. The event is emitted from captureAndEmit() once the
    // screenshot is uploaded (or capture fails - we still emit, just without
    // screenshotPath).
    const elForCapture = selectedElement;
    pickedAnchorSnapshot = buildPickedAnchorSnapshot(elForCapture);
    const captureRect = elForCapture.getBoundingClientRect();
    pickedAnchorViewportTop = captureRect.top;
    const snapshot = {
      comments: annotState.comments.map(c => ({ x: c.x, y: c.y, text: c.text })),
      strokes: annotState.strokes.map(s => ({ points: s.points.map(p => [p[0], p[1]]) })),
    };
    const basePayload = {
      type: 'generate', id: currentSessionId,
      action: selectedAction,
      freeformPrompt: prompt || undefined,
      count: selectedCount,
      pageUrl: location.pathname,
      element: extractContext(elForCapture),
    };
    if (snapshot.comments.length > 0) basePayload.comments = snapshot.comments;
    if (snapshot.strokes.length > 0) basePayload.strokes = snapshot.strokes;

    // Hide the interactive overlay so it doesn't linger during generation.
    hideAnnotOverlay();
    clearAnnotations();

    setLiveState('GENERATING');
    // Disable the Edit badge: starting a manual text edit mid-generation would
    // conflict with the variant wrap that's about to land in the same DOM
    // region. Only swap if the badge was visible - picked elements with no
    // text rows have it hidden already.
    if (editBadgeEl && editBadgeEl.style.display !== 'none') renderEditBadge('idle-disabled');
    showBar('generating');
    saveSession();
    sendCheckpoint('generate_started');
    writeScrollY(window.scrollY);
    if (variantObserver) variantObserver.disconnect();
    variantObserver = startVariantObserver(currentSessionId);
    startScrollLock(currentSessionId, window.scrollY, pickedAnchorViewportTop);

    captureAndEmit(elForCapture, basePayload, snapshot, captureRect);
  }

  function cancelInsertConfigure() {
    hideBar();
    stopScrollTracking();
    hideAnnotOverlay();
    clearAnnotations();
    clearInsertPicking();
    configureKind = 'replace';
    selectedElement = null;
    setLiveState(insertActive ? 'PICKING' : 'IDLE');
    hideHighlight();
    syncPageChatFocus('insert-configure-cancel');
  }

  function handleInsertCreate() {
    if (!placeholderElement || !insertAnchorElement || state !== 'CONFIGURING' || configureKind !== 'insert') return;
    const input = uiGetById(PREFIX + '-insert-input');
    const prompt = input ? input.value.trim() : '';
    if (annotEditing) finalizeEditingPin();
    const snapshot = {
      comments: annotState.comments.map(c => ({ x: c.x, y: c.y, text: c.text })),
      strokes: annotState.strokes.map(s => ({ points: s.points.map(p => [p[0], p[1]]) })),
    };
    if (!canCreateInsert({ prompt, comments: snapshot.comments, strokes: snapshot.strokes })) return;

    stopVoice({ suppressSubmit: true });
    // A new cycle publishes new modules, so the previous cycle's mount failure
    // is about files that no longer matter.
    clearMountErrorCard();
    lastReportedMountFailure = null;
    pendingAcceptedSession = null;
    // A new session supersedes any accept still awaiting its result; a late
    // failure toast for the previous session would only mislead here.
    awaitingAcceptResult = null;
    currentSessionId = id8();
    expectedVariants = selectedCount;
    arrivedVariants = 0;
    visibleVariant = 0;
    generationPhase = 'queued';
    parameterGenerationState = 'pending';
    parameterReadyAnnouncedSession = null;
    resetSessionFileMeta();
    selectedElement = placeholderElement;
    insertPlaceholderSnapshot = buildInsertPlaceholderSnapshotFromDom(insertAnchorElement, placeholderElement);

    const elForCapture = placeholderElement;
    const captureRect = elForCapture.getBoundingClientRect();
    pickedAnchorViewportTop = captureRect.top;
    const basePayload = {
      type: 'generate',
      mode: 'insert',
      id: currentSessionId,
      count: selectedCount,
      pageUrl: location.pathname,
      insert: {
        position: insertAnchorPosition,
        anchor: extractContext(insertAnchorElement),
      },
      placeholder: {
        width: Math.round(captureRect.width),
        height: Math.round(captureRect.height),
      },
      freeformPrompt: prompt || undefined,
    };
    if (snapshot.comments.length > 0) basePayload.comments = snapshot.comments;
    if (snapshot.strokes.length > 0) basePayload.strokes = snapshot.strokes;

    hideAnnotOverlay();
    clearAnnotations();

    setLiveState('GENERATING');
    showBar('generating');
    startScrollTracking();
    saveSession();
    sendCheckpoint('generate_started');
    writeScrollY(window.scrollY);
    if (variantObserver) variantObserver.disconnect();
    variantObserver = startVariantObserver(currentSessionId);
    startScrollLock(currentSessionId, window.scrollY, pickedAnchorViewportTop);
    captureAndEmit(elForCapture, basePayload, snapshot, captureRect);
  }

  //
  // Screenshot capture + upload
  //

  let msLoadPromise = null;
  function loadModernScreenshot() {
    if (window.modernScreenshot) return Promise.resolve(window.modernScreenshot);
    if (msLoadPromise) return msLoadPromise;
    msLoadPromise = new Promise((resolve, reject) => {
      const s = document.createElement('script');
      s.src = 'http://localhost:' + PORT + '/modern-screenshot.js';
      s.onload = () => resolve(window.modernScreenshot);
      s.onerror = () => { msLoadPromise = null; reject(new Error('modern-screenshot failed to load')); };
      uiAppendStyle(s);
    });
    return msLoadPromise;
  }

  // Collect @font-face rules from every stylesheet on the page. Cross-origin
  // sheets (Google Fonts, Typekit, etc.) throw SecurityError on .cssRules
  // access, so modern-screenshot can't embed them on its own - the resulting
  // SVG falls back to system fonts and text re-wraps + renders with different
  // weight. We fetch the raw CSS text (CORS-permitted for these providers),
  // extract @font-face blocks, inline the referenced font files as base64
  // data URIs (SVGs rasterized via canvas can't fetch external resources,
  // so URLs inside the SVG silently fail without this), and pass the result
  // to modern-screenshot as font.cssText.
  const FONT_EXT_RE = /\.(woff2?|ttf|otf|eot)(\?.*)?$/i;
  const FONT_MIME = {
    woff2: 'font/woff2', woff: 'font/woff', ttf: 'font/ttf', otf: 'font/otf', eot: 'application/vnd.ms-fontobject',
  };
  function bufferToBase64(buf) {
    const bytes = new Uint8Array(buf);
    let binary = '';
    const CHUNK = 0x8000;
    for (let i = 0; i < bytes.length; i += CHUNK) {
      binary += String.fromCharCode.apply(null, bytes.subarray(i, i + CHUNK));
    }
    return btoa(binary);
  }
  async function inlineFontUrls(cssText) {
    const urlRe = /url\((['"]?)(https?:\/\/[^'")\s]+)\1\)/g;
    const urls = new Set();
    let m;
    while ((m = urlRe.exec(cssText))) {
      if (FONT_EXT_RE.test(m[2])) urls.add(m[2]);
    }
    const map = new Map();
    await Promise.all([...urls].map(async (url) => {
      try {
        const res = await fetch(url);
        if (!res.ok) return;
        const buf = await res.arrayBuffer();
        const ext = url.toLowerCase().match(FONT_EXT_RE)?.[1] || 'woff2';
        const mime = FONT_MIME[ext] || 'application/octet-stream';
        map.set(url, 'data:' + mime + ';base64,' + bufferToBase64(buf));
      } catch { /* skip; fall through to URL */ }
    }));
    return cssText.replace(urlRe, (orig, q, url) => {
      const data = map.get(url);
      return data ? 'url(' + q + data + q + ')' : orig;
    });
  }
  async function collectFontCssText() {
    const chunks = [];
    const fontFaceRe = /@font-face\s*\{[^}]*\}/g;
    for (const sheet of document.styleSheets) {
      try {
        const rules = sheet.cssRules;
        for (const rule of rules) {
          if (rule.constructor.name === 'CSSFontFaceRule' || rule.cssText?.startsWith('@font-face')) {
            chunks.push(rule.cssText);
          }
        }
      } catch {
        if (!sheet.href) continue;
        try {
          const res = await fetch(sheet.href);
          if (!res.ok) continue;
          const text = await res.text();
          let m2;
          while ((m2 = fontFaceRe.exec(text))) chunks.push(m2[0]);
        } catch { /* ignore; capture is best-effort */ }
      }
    }
    if (chunks.length === 0) return '';
    return inlineFontUrls(chunks.join('\n'));
  }

  // True if `s` is a computed color string that renders as nothing
  // (explicit `transparent`, or `rgba(...)` with alpha 0).
  function isTransparentColor(s) {
    if (!s) return true;
    if (s === 'transparent') return true;
    const m = /rgba?\(([^)]+)\)/.exec(s);
    if (!m) return false;
    const parts = m[1].split(',').map((p) => p.trim());
    if (parts.length === 4) return parseFloat(parts[3]) === 0;
    return false;
  }

  // modern-screenshot force-sets `background-color: X !important` on the
  // cloned root whenever `backgroundColor` is passed, clobbering the
  // element's own background. So we only pass it when the element is
  // genuinely transparent (no own color, no own image) - in that case
  // we resolve up the DOM to the nearest opaque ancestor so the capture
  // sits on the page's real background instead of rendering black.
  function resolveCanvasBackground(el) {
    const own = getComputedStyle(el);
    if (!isTransparentColor(own.backgroundColor)) return null;
    if (own.backgroundImage && own.backgroundImage !== 'none') return null;
    let node = el.parentElement;
    while (node) {
      const cs = getComputedStyle(node);
      if (!isTransparentColor(cs.backgroundColor)) return cs.backgroundColor;
      node = node.parentElement;
    }
    // The walk already passed through <body> and <html>; if they had been
    // opaque we would have returned. Falling through with the previous
    // `getComputedStyle(body).backgroundColor || …` chain is a trap: that
    // call returns the literal string `"rgba(0, 0, 0, 0)"` for a page that
    // never set its own bg, which is truthy and short-circuits the chain to
    // transparent-black - modern-screenshot then renders the capture on a
    // black canvas and the shader overlay flashes solid black during load.
    // The browser canvas defaults to white, so we do too.
    return '#ffffff';
  }

  function captureChromeNodes() {
    const nodes = [];
    const add = (node) => {
      if (!node || node === document.body || nodes.includes(node)) return;
      nodes.push(node);
    };
    add(document.getElementById(PREFIX + '-root'));
    [
      PREFIX + '-highlight',
      PREFIX + '-tooltip',
      PREFIX + '-bar',
      PREFIX + '-picker',
      PREFIX + '-params-panel',
      PREFIX + '-insert-line',
      PREFIX + '-insert-placeholder',
      PREFIX + '-insert-create-tooltip',
      PREFIX + '-annot',
      PREFIX + '-design-host',
      PREFIX + '-toast',
      PREFIX + '-shader',
    ].forEach((id) => add(uiGetById(id)));
    return nodes;
  }

  async function hideCaptureChromeForShaderProxy(fn) {
    const saved = captureChromeNodes().map((node) => ({
      node,
      visibility: node.style.visibility,
      priority: node.style.getPropertyPriority('visibility'),
    }));
    for (const { node } of saved) {
      node.style.setProperty('visibility', 'hidden', 'important');
    }
    await new Promise((resolve) => requestAnimationFrame(resolve));
    try {
      return await fn();
    } finally {
      for (const { node, visibility, priority } of saved) {
        node.style.setProperty('visibility', visibility, priority);
      }
    }
  }

  function shouldUseAncestorCropShaderProxy(el) {
    // TODO: Enable this proxy for React/Vue/etc. adapters once their live
    // preview mounts are covered by the same shader regression checks.
    const adapter = String(window.__IMPECCABLE_LIVE_ADAPTER__ || '').toLowerCase();
    if (adapter === 'svelte' || adapter === 'sveltekit') return true;
    if (isFrameworkComponentPreviewMode(currentPreviewMode) || svelteComponentSession) return true;
    const wrapper = el?.closest?.('[data-impeccable-variants]');
    return isFrameworkComponentPreviewMode(wrapper?.dataset?.impeccablePreview);
  }

  function paintsShaderProxySurface(node) {
    const s = getComputedStyle(node);
    return !isTransparentColor(s.backgroundColor)
      || (s.backgroundImage && s.backgroundImage !== 'none')
      || paintsBackdrop(node);
  }

  function findShaderProxyCaptureRoot(el) {
    const doc = el.ownerDocument || document;
    const er = el.getBoundingClientRect();
    let node = el.parentElement;
    while (node && node !== doc.documentElement) {
      const nr = node.getBoundingClientRect();
      const containsElement =
        nr.width > 0 && nr.height > 0 &&
        nr.left <= er.left + 0.5 &&
        nr.top <= er.top + 0.5 &&
        nr.right >= er.right - 0.5 &&
        nr.bottom >= er.bottom - 0.5;
      if (containsElement && paintsShaderProxySurface(node)) return node;
      node = node.parentElement;
    }
    return null;
  }

  // Capture the element (with current annotations baked in) and return
  // { blob, paper }: the PNG Blob, plus the representative backdrop tone for the
  // shader's halftone ground (so capture, upload, and shader all agree on what
  // sits behind the element). Shared between the Go flow (uploads the blob) and
  // the shader-resume path.
  async function captureElementFromRenderedAncestor(ms, el, opts) {
    const doc = el.ownerDocument || document;
    const captureRoot = findShaderProxyCaptureRoot(el);
    if (!captureRoot) throw new Error('No painted ancestor for Svelte shader proxy');
    const rootCanvas = await ms.domToCanvas(captureRoot, opts);
    const S = opts.scale;
    const er = el.getBoundingClientRect();
    const rr = captureRoot.getBoundingClientRect();
    const sx = (er.left - rr.left) * S;
    const sy = (er.top - rr.top) * S;
    const sw = er.width * S;
    const sh = er.height * S;
    if (sw <= 0 || sh <= 0) throw new Error('Selected element has no visible capture rect');
    const crop = doc.createElement('canvas');
    crop.width = Math.max(1, Math.round(sw));
    crop.height = Math.max(1, Math.round(sh));
    const cctx = crop.getContext('2d', { willReadFrequently: true });
    cctx.drawImage(rootCanvas, sx, sy, sw, sh, 0, 0, crop.width, crop.height);
    const paper = dominantRgb01(cctx, crop.width, crop.height) || averageRgb01(cctx, crop.width, crop.height);
    const blob = await new Promise((res) => crop.toBlob(res, 'image/png'));
    if (!blob) throw new Error('Ancestor crop failed to produce a PNG blob');
    return { blob, paper };
  }

  async function captureElementToBlob(el, snapshot, rect) {
    try { if (document.fonts?.ready) await document.fonts.ready; } catch {}
    const hasAnnotations = snapshot && (snapshot.comments.length > 0 || snapshot.strokes.length > 0);
    let annotNode = null;
    let savedPosition = null;
    if (hasAnnotations) {
      const pos = getComputedStyle(el).position;
      if (pos === 'static') {
        savedPosition = el.style.position;
        el.style.position = 'relative';
      }
      annotNode = buildAnnotationsForCapture(rect, snapshot);
      el.appendChild(annotNode);
    }
    try {
      const ms = await loadModernScreenshot();
      const fontCssText = await collectFontCssText();
      const opts = {
        scale: Math.min(window.devicePixelRatio || 1, 2),
        font: fontCssText ? { cssText: fontCssText } : undefined,
      };
      if (shouldUseAncestorCropShaderProxy(el)) {
        try {
          return await hideCaptureChromeForShaderProxy(() => captureElementFromRenderedAncestor(ms, el, opts));
        } catch (err) {
          console.warn('[impeccable] Svelte ancestor crop capture failed, falling back to element capture:', err);
        }
      }
      const bg = resolveCanvasBackground(el);
      // Fast path: the element paints its own background, or an opaque ancestor
      // color was found. modern-screenshot bakes that color; paper matches it.
      if (bg !== '#ffffff') {
        const blob = await ms.domToBlob(el, { ...opts, ...(bg ? { backgroundColor: bg } : {}) });
        return { blob, paper: bg ? cssColorToRgb01(bg) : resolvePaperRgb(el) };
      }
      // Transparent up to the root. The visible backdrop may still come from an
      // ancestor's background-image or a covering positioned layer (e.g. a hero
      // art div) that the color walk can't see. Capture that ancestor and crop
      // to the element so the real backdrop is embedded - correct for both the
      // shader and the screenshot sent to the model. Fall back to white only
      // when nothing is actually painted behind the element.
      const backdrop = findBackdropAncestor(el);
      if (!backdrop) {
        const blob = await ms.domToBlob(el, { ...opts, backgroundColor: '#ffffff' });
        return { blob, paper: SHADER_PAPER_FALLBACK };
      }
      const ancestorCanvas = await ms.domToCanvas(backdrop, opts);
      const S = opts.scale;
      const er = el.getBoundingClientRect();
      const ar = backdrop.getBoundingClientRect();
      const sx = (er.left - ar.left) * S, sy = (er.top - ar.top) * S;
      const sw = er.width * S, sh = er.height * S;
      const crop = document.createElement('canvas');
      crop.width = Math.max(1, Math.round(sw));
      crop.height = Math.max(1, Math.round(sh));
      const cctx = crop.getContext('2d', { willReadFrequently: true });
      cctx.drawImage(ancestorCanvas, sx, sy, sw, sh, 0, 0, crop.width, crop.height);
      // Ground = backdrop sampled around the element, falling back to the crop
      // mean only if the surround is fully transparent.
      const actx = ancestorCanvas.getContext('2d', { willReadFrequently: true });
      const paper = sampleSurroundingRgb(actx, sx, sy, sw, sh, ancestorCanvas.width, ancestorCanvas.height)
        || averageRgb01(cctx, crop.width, crop.height);
      const blob = await new Promise((res) => crop.toBlob(res, 'image/png'));
      return { blob, paper };
    } finally {
      if (annotNode) annotNode.remove();
      if (savedPosition !== null) el.style.position = savedPosition;
    }
  }

  async function captureAndEmit(el, basePayload, snapshot, rect) {
    const hasAnnotations = snapshot && (snapshot.comments.length > 0 || snapshot.strokes.length > 0);

    // Plain requests do not send a screenshot to the agent, so capture is
    // presentation-only. Wait only for the helper to accept the event before
    // starting CPU-heavy capture; this yields the browser task and prevents
    // rasterization from delaying the fetch itself.
    if (!hasAnnotations) {
      basePayload.clientSentAt = Date.now();
      await sendEvent(basePayload);
    }

    let screenshotPath;
    let blob;
    let paper;
    try {
      ({ blob, paper } = await captureElementToBlob(el, snapshot, rect));
    } catch (err) {
      console.warn('[impeccable] capture failed, proceeding without screenshot:', err);
    }
    // Light up the shader overlay the moment capture is ready - no reason to
    // wait for the upload to complete before the user sees something alive.
    if (blob && state === 'GENERATING') {
      showShaderOverlay(el, blob, rect, paper);
    }
    // Only upload + forward the screenshot when annotations (comments/strokes)
    // are present. Without annotations the image is pure visual anchoring -
    // it biases the model toward the current rendering and works against the
    // three-distinct-directions brief.
    if (blob && hasAnnotations) {
      try {
        const uploadRes = await fetch(
          'http://localhost:' + PORT + '/annotation?token=' + encodeURIComponent(TOKEN) +
          '&eventId=' + encodeURIComponent(basePayload.id),
          { method: 'POST', headers: { 'Content-Type': 'image/png' }, body: blob },
        );
        if (uploadRes.ok) {
          const { path: p } = await uploadRes.json();
          screenshotPath = p;
        } else {
          console.warn('[impeccable] annotation upload failed:', uploadRes.status);
        }
      } catch (err) {
        console.warn('[impeccable] annotation upload failed:', err);
      }
    }
    // Annotated requests must wait for capture + upload because the screenshot
    // is semantic input. Plain requests were already dispatched above.
    if (hasAnnotations) {
      basePayload.clientSentAt = Date.now();
      sendEvent(screenshotPath ? { ...basePayload, screenshotPath } : basePayload);
    }
  }

  //
  // Shader overlay - renders the captured screenshot as a WebGL texture and
  // runs an editorial "ink-wash" fragment shader over it during generation.
  // A single rolling band sweeps top-to-bottom, desaturating + tinting kinpaku
  // and leaving a soft trail. Makes the wait feel like a letterpress scan
  // instead of a dead spinner.
  //

  const SHADER_VS = `attribute vec2 a_position;
attribute vec2 a_uv;
varying vec2 v_uv;
void main() {
  v_uv = a_uv;
  gl_Position = vec4(a_position, 0.0, 1.0);
}`;

  const SHADER_FS = `precision highp float;
uniform sampler2D u_texture;
uniform float u_time;
uniform vec2 u_resolution;
uniform vec3 u_accent;
uniform vec3 u_paper;
varying vec2 v_uv;

// Asymmetric roller band. Product of two one-sided smoothsteps - peaks at
// d=0 with a short sharp leading ramp and a longer soft trailing tail. Clean
// outside the [-leadW, trailW] range (no rogue "trail=1 everywhere below"
// failure that reversed-edge smoothstep would give).
float bandAt(float d, float leadW, float trailW) {
  float above = smoothstep(-leadW, 0.0, d);
  float below = 1.0 - smoothstep(0.0, trailW, d);
  return above * below;
}

void main() {
  vec2 uv = v_uv;
  // Roller sweeps top-to-bottom with small overshoot so each cycle enters
  // and exits the element cleanly.
  float phase = fract(u_time / 3.4);
  float y = phase * 1.25 - 0.12;
  float band = bandAt(uv.y - y, 0.05, 0.32);

  // Halftone cell grid (fixed ~10 px pitch).
  float cellPx = 10.0;
  vec2 gridUv = uv * u_resolution / cellPx;
  vec2 cellId = floor(gridUv);
  vec2 cellUv = fract(gridUv) - 0.5;
  vec2 sampleCenter = (cellId + 0.5) * cellPx / u_resolution;
  vec3 cellImg = texture2D(u_texture, sampleCenter).rgb;
  // Dot size tracks how much the cell DIFFERS from the element's own ground
  // (u_paper), not absolute darkness. So the content - text, buttons, anything
  // that deviates from the background - always becomes the dots, on light AND
  // dark surfaces. A plain darkness curve inverts on dark elements: the dark
  // background fills with ink and the lighter content punches holes instead.
  // Capped below the cell half-width so dense content stays separated dots.
  float contrast = clamp(length(cellImg - u_paper) / 1.732, 0.0, 1.0);
  float radius = min(sqrt(contrast) * 0.6, 0.38);
  float dotMask = smoothstep(radius + 0.06, radius, length(cellUv));
  // Two-stage dissolve as the roller passes, so the element is rebuilt purely
  // from dot size (its own halftone) and never bleeds through as raw pixels
  // behind the dots:
  //   1. cover  - the element flattens to the uniform paper ground first.
  //   2. dotAmt - kinpaku dots then emerge, sized by each cell's luma.
  // A plain mix(base, halftone, band) instead left the raw element visible
  // through the band's soft core/trail. The paper ground is u_paper (the
  // element's own bg tone) rather than a fixed white, so the dissolve reads the
  // same over light and dark surfaces.
  vec4 tex = texture2D(u_texture, uv);
  vec3 base = tex.rgb;
  float cover = smoothstep(0.0, 0.35, band);
  float dotAmt = dotMask * smoothstep(0.15, 0.6, band);
  vec3 ground = mix(base, u_paper, cover);
  // Carry the capture's own alpha through, so a rounded corner or any genuinely
  // transparent region stays transparent (the live backdrop shows through the
  // canvas) instead of rendering as solid black.
  gl_FragColor = vec4(mix(ground, u_accent, dotAmt), tex.a);
}`;

  // Kinpaku gold converted to approximate sRGB 0-1 (matches oklch(84% 0.19 80.46))
  const SHADER_ACCENT = [1.0, 0.78, 0.31];
  // Fallback ground when an element and all its ancestors are transparent -
  // matches the original off-white risograph paper.
  const SHADER_PAPER_FALLBACK = [0.975, 0.965, 0.955];
  let shaderState = null; // { canvas, gl, program, texture, rafId, startTime }

  // The element's effective background tone, used as the uniform halftone
  // ground so content dissolves into dots over it. Unlike resolveCanvasBackground
  // (which returns null when the element paints its own bg), this always returns
  // a usable color: the element's own background if any, else the nearest opaque
  // ancestor, else the paper fallback.
  // Rasterize any CSS color (oklch, color(), named, hex, rgb) through a 1x1
  // canvas and read back the sRGB pixel. String-parsing computed colors is a
  // trap: Chrome returns backgroundColor as oklch()/color() for oklch inputs,
  // which a hex/rgb regex misses - every site token would fall back to white.
  let colorParseCtx = null;
  function cssColorToRgb01(str) {
    if (!colorParseCtx) {
      colorParseCtx = document.createElement('canvas').getContext('2d', { willReadFrequently: true });
    }
    // Clear first: the ctx is cached across calls, so a semi-transparent color
    // would otherwise blend (source-over) with the previous call's leftover
    // pixel, making the result depend on call history.
    colorParseCtx.clearRect(0, 0, 1, 1);
    colorParseCtx.fillStyle = '#000'; // invalid input leaves this default
    colorParseCtx.fillStyle = str;
    colorParseCtx.fillRect(0, 0, 1, 1);
    const d = colorParseCtx.getImageData(0, 0, 1, 1).data;
    return [d[0] / 255, d[1] / 255, d[2] / 255];
  }
  function resolvePaperRgb(el) {
    let node = el;
    while (node) {
      const bg = getComputedStyle(node).backgroundColor;
      if (!isTransparentColor(bg)) return cssColorToRgb01(bg);
      node = node.parentElement;
    }
    return SHADER_PAPER_FALLBACK;
  }

  // When an element is transparent up to the root, its visible backdrop can
  // still come from an ancestor's background-image or a covering positioned
  // layer that is a *child* of an ancestor (e.g. a hero's absolute art div) -
  // neither of which the ancestor background-COLOR walk can see. Return the
  // nearest such ancestor so we can capture it and crop, embedding the real
  // backdrop. Returns null when nothing is actually painted behind the element
  // (genuinely transparent → white is correct).
  function paintsBackdrop(node) {
    const s = getComputedStyle(node);
    if (s.backgroundImage && s.backgroundImage !== 'none') return true;
    const nr = node.getBoundingClientRect();
    for (const child of node.children) {
      const ccs = getComputedStyle(child);
      if (ccs.position !== 'absolute' && ccs.position !== 'fixed') continue;
      const paints = !isTransparentColor(ccs.backgroundColor)
        || (ccs.backgroundImage && ccs.backgroundImage !== 'none');
      if (!paints) continue;
      const cr = child.getBoundingClientRect();
      if (cr.width >= nr.width * 0.9 && cr.height >= nr.height * 0.9) return true;
    }
    return false;
  }
  function findBackdropAncestor(el) {
    let node = el.parentElement;
    while (node && node !== node.ownerDocument.documentElement) {
      if (paintsBackdrop(node)) return node;
      node = node.parentElement;
    }
    return null;
  }

  // Mean sRGB (0-1) of a canvas region, used as the halftone ground when the
  // backdrop was captured from an ancestor rather than read from a CSS color.
  function averageRgb01(ctx, w, h) {
    const data = ctx.getImageData(0, 0, w, h).data;
    let r = 0, g = 0, b = 0, n = 0;
    // Stride a few pixels for speed; exact average is unnecessary for a ground.
    for (let i = 0; i < data.length; i += 16) { r += data[i]; g += data[i + 1]; b += data[i + 2]; n++; }
    return n ? [r / n / 255, g / n / 255, b / n / 255] : SHADER_PAPER_FALLBACK;
  }

  // Pick the most common visible color cluster from a crop. A straight average
  // gets pulled by text and icons; the dominant bucket usually represents the
  // surface the shader should dissolve into.
  function dominantRgb01(ctx, w, h) {
    const data = ctx.getImageData(0, 0, w, h).data;
    const stride = Math.max(1, Math.floor((w * h) / 6000));
    const buckets = new Map();
    for (let p = 0; p < w * h; p += stride) {
      const i = p * 4;
      if (data[i + 3] < 16) continue;
      const key = (data[i] >> 4) + ',' + (data[i + 1] >> 4) + ',' + (data[i + 2] >> 4);
      const bucket = buckets.get(key) || { count: 0, r: 0, g: 0, b: 0 };
      bucket.count += 1;
      bucket.r += data[i];
      bucket.g += data[i + 1];
      bucket.b += data[i + 2];
      buckets.set(key, bucket);
    }
    let best = null;
    for (const bucket of buckets.values()) {
      if (!best || bucket.count > best.count) best = bucket;
    }
    return best ? [best.r / best.count / 255, best.g / best.count / 255, best.b / best.count / 255] : null;
  }

  // Average the backdrop sampled just OUTSIDE an element's rect within a larger
  // canvas. The ground tone for the dissolve must be the real backdrop, not the
  // mean of the element's own crop - averaging the crop folds in the element's
  // content (e.g. bright heading text), pulling the ground toward muddy gray.
  function sampleSurroundingRgb(ctx, sx, sy, sw, sh, W, H) {
    const pad = Math.max(2, Math.round(Math.min(sw, sh) * 0.12));
    const fx = [0.2, 0.5, 0.8].map((f) => sx + sw * f);
    const fy = [0.2, 0.5, 0.8].map((f) => sy + sh * f);
    const pts = [];
    for (const x of fx) { pts.push([x, sy - pad], [x, sy + sh + pad]); }
    for (const y of fy) { pts.push([sx - pad, y], [sx + sw + pad, y]); }
    let r = 0, g = 0, b = 0, n = 0;
    for (const [px, py] of pts) {
      const cx = Math.max(0, Math.min(W - 1, Math.round(px)));
      const cy = Math.max(0, Math.min(H - 1, Math.round(py)));
      const d = ctx.getImageData(cx, cy, 1, 1).data;
      if (d[3] === 0) continue; // outside the ancestor's paint
      r += d[0]; g += d[1]; b += d[2]; n++;
    }
    return n ? [r / n / 255, g / n / 255, b / n / 255] : null;
  }

  function compileShader(gl, type, source) {
    const sh = gl.createShader(type);
    gl.shaderSource(sh, source);
    gl.compileShader(sh);
    if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
      const info = gl.getShaderInfoLog(sh);
      gl.deleteShader(sh);
      throw new Error('shader compile failed: ' + info);
    }
    return sh;
  }

  function positionShaderOverlay() {
    if (!shaderState) return;
    const anchor = resolveBarAnchor();
    if (!anchor) return;
    const r = anchor.getBoundingClientRect();
    Object.assign(shaderState.canvas.style, {
      top: r.top + 'px', left: r.left + 'px',
      width: r.width + 'px', height: r.height + 'px',
    });
  }

  function hideShaderOverlay() {
    if (!shaderState) return;
    if (shaderState.rafId) cancelAnimationFrame(shaderState.rafId);
    if (shaderState.canvas) shaderState.canvas.remove();
    if (shaderState.objectUrl) URL.revokeObjectURL(shaderState.objectUrl);
    const lose = shaderState.gl?.getExtension?.('WEBGL_lose_context');
    try { lose?.loseContext(); } catch {}
    shaderState = null;
  }

  function showShaderBitmapFallback(canvas, blob) {
    canvas.remove();
    const objectUrl = URL.createObjectURL(blob);
    const fallback = document.createElement('div');
    fallback.id = PREFIX + '-shader';
    // Copy positioning via cssText. Object.assign across CSSStyleDeclaration
    // throws in modern Chromium because the source's indexed properties
    // (style[0], [1], ...) are read-only and the engine forbids writing
    // them on the destination.
    fallback.style.cssText = canvas.style.cssText;
    fallback.style.backgroundImage = 'url("' + objectUrl + '")';
    fallback.style.backgroundSize = '100% 100%';
    fallback.style.backgroundRepeat = 'no-repeat';
    fallback.style.outline = '2px dashed ' + C.brand;
    fallback.style.outlineOffset = '-2px';
    uiAppend(fallback);
    shaderState = { canvas: fallback, gl: null, program: null, texture: null, rafId: 0, startTime: 0, objectUrl };
  }

  async function showShaderOverlay(el, blob, rect, paper) {
    hideShaderOverlay();
    if (!blob || !el) return;
    const canvas = document.createElement('canvas');
    canvas.id = PREFIX + '-shader';
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    const radius = getComputedStyle(el).borderRadius;
    canvas.width = Math.max(1, Math.floor(rect.width * dpr));
    canvas.height = Math.max(1, Math.floor(rect.height * dpr));
    Object.assign(canvas.style, {
      position: 'fixed',
      top: rect.top + 'px', left: rect.left + 'px',
      width: rect.width + 'px', height: rect.height + 'px',
      borderRadius: radius,
      overflow: 'hidden',
      pointerEvents: 'none',
      zIndex: Z.bar - 1,
    });
    uiAppend(canvas);

    const gl = canvas.getContext('webgl', { premultipliedAlpha: false, preserveDrawingBuffer: false })
            || canvas.getContext('experimental-webgl');
    if (!gl) {
      // WebGL unavailable: use the captured bitmap as a background overlay so
      // the user still sees something meaningful during generation.
      showShaderBitmapFallback(canvas, blob);
      return;
    }

    let program, texture;
    try {
      const vs = compileShader(gl, gl.VERTEX_SHADER, SHADER_VS);
      const fs = compileShader(gl, gl.FRAGMENT_SHADER, SHADER_FS);
      program = gl.createProgram();
      gl.attachShader(program, vs);
      gl.attachShader(program, fs);
      gl.linkProgram(program);
      if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
        throw new Error('program link failed: ' + gl.getProgramInfoLog(program));
      }
      // Full-screen quad
      const buf = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, buf);
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        -1, -1, 0, 1,
         1, -1, 1, 1,
        -1,  1, 0, 0,
        -1,  1, 0, 0,
         1, -1, 1, 1,
         1,  1, 1, 0,
      ]), gl.STATIC_DRAW);
      const posLoc = gl.getAttribLocation(program, 'a_position');
      const uvLoc = gl.getAttribLocation(program, 'a_uv');
      gl.enableVertexAttribArray(posLoc);
      gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 16, 0);
      gl.enableVertexAttribArray(uvLoc);
      gl.vertexAttribPointer(uvLoc, 2, gl.FLOAT, false, 16, 8);
    } catch (err) {
      console.warn('[impeccable] shader setup failed:', err);
      canvas.remove();
      return;
    }

    // Upload the screenshot as a texture
    let bitmap;
    try {
      bitmap = await createImageBitmap(blob);
    } catch (err) {
      console.warn('[impeccable] shader bitmap decode failed:', err);
      const lose = gl.getExtension?.('WEBGL_lose_context');
      try { lose?.loseContext(); } catch {}
      showShaderBitmapFallback(canvas, blob);
      return;
    }
    texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bitmap);
    if (bitmap.close) bitmap.close();

    const uTime = gl.getUniformLocation(program, 'u_time');
    const uRes = gl.getUniformLocation(program, 'u_resolution');
    const uAccent = gl.getUniformLocation(program, 'u_accent');
    const uPaper = gl.getUniformLocation(program, 'u_paper');
    const uTex = gl.getUniformLocation(program, 'u_texture');
    const paperRgb = paper || resolvePaperRgb(el);
    const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    shaderState = { canvas, gl, program, texture, rafId: 0, startTime: performance.now(), reduced };
    function frame() {
      if (!shaderState) return;
      const elapsed = (performance.now() - shaderState.startTime) / 1000;
      const t = shaderState.reduced ? 0.0 : elapsed;
      gl.viewport(0, 0, canvas.width, canvas.height);
      gl.useProgram(program);
      gl.activeTexture(gl.TEXTURE0);
      gl.bindTexture(gl.TEXTURE_2D, texture);
      gl.uniform1i(uTex, 0);
      gl.uniform1f(uTime, t);
      gl.uniform2f(uRes, canvas.width, canvas.height);
      gl.uniform3f(uAccent, SHADER_ACCENT[0], SHADER_ACCENT[1], SHADER_ACCENT[2]);
      gl.uniform3f(uPaper, paperRgb[0], paperRgb[1], paperRgb[2]);
      gl.drawArrays(gl.TRIANGLES, 0, 6);
      shaderState.rafId = requestAnimationFrame(frame);
    }
    frame();
  }

  async function handleAccept() {
    if (pendingApplyInFlight) { showManualApplyBusyToast(); return; }
    if (pendingAcceptedSession || state === 'SAVING') return;
    if (variantSelectionPromise) {
      try { await variantSelectionPromise; } catch { /* failed selection falls back below */ }
    }
    const domVisibleVariant = readVisibleVariantFromDOM(currentSessionId);
    if (domVisibleVariant > 0) visibleVariant = domVisibleVariant;
    const acceptPayload = {
      type: 'accept',
      id: currentSessionId,
      variantId: String(visibleVariant),
      pageUrl: location.pathname,
      clientSentAt: Date.now(),
    };
    if (!currentSessionId || arrivedVariants === 0) return;
    const acceptWrapper = document.querySelector('[data-impeccable-variants="' + currentSessionId + '"]');
    if (Object.keys(paramsCurrentValues).length > 0) {
      acceptPayload.paramValues = { ...paramsCurrentValues };
    }
    // The accepted variant is already the only visible child of the wrapper
    // (all other variants are display:none). HMR from the source rewrite will
    // replace the wrapper imminently. Don't eagerly replaceChild here - React
    // reconciliation races with our mutation and throws NotFoundError in Next
    // 16 / Turbopack. Schedule a fallback that runs the manual swap only if
    // HMR hasn't cleaned up by then (keeps static-server flows working).
    const acceptedSessionId = currentSessionId;
    const acceptedVariant = visibleVariant;
    const acceptedIsSvelteComponent = svelteComponentSession?.sessionId === acceptedSessionId
      || isFrameworkComponentPreviewMode(acceptWrapper?.dataset?.impeccablePreview);
    const acceptedSnapshot = snapshotAcceptedVariantDom(acceptedSessionId, acceptedVariant);

    setLiveState('SAVING');
    updateBarContent('saving');
    pendingAcceptedSession = {
      id: acceptedSessionId,
      variant: String(acceptedVariant),
      isSvelteComponent: acceptedIsSvelteComponent,
      ...acceptedSnapshot,
      finalizing: false,
    };
    saveSession();

    sendEvent(acceptPayload, { throwOnError: true })
      .then(() => {
        const pending = pendingAcceptedSession;
        if (!pending || pending.id !== acceptedSessionId) return;
        // POST /events returns only after the accept intent is durable and the
        // generation epoch is fenced. Source promotion/carbonize can finish in
        // the background; the foreground picker is free immediately.
        markSessionHandled();
        setLiveState('CONFIRMED');
        document.documentElement.dataset.impeccableAcceptToPickingMs = String(Date.now() - acceptPayload.clientSentAt);
        awaitingAcceptResult = { id: acceptedSessionId };
        scheduleAcceptCleanup(pending);
      })
      .catch(() => {
        if (pendingAcceptedSession?.id === acceptedSessionId) pendingAcceptedSession = null;
        setLiveState('CYCLING');
        showOrUpdateCyclingBar();
        showToast('Could not confirm accept with the live server. Session kept for recovery; try Accept again.', 5000);
      });
  }

  function maybeCompleteAcceptedSession(msg) {
    const pending = pendingAcceptedSession;
    if (!pending || !msg?.id || msg.id !== pending.id) return false;
    if (currentSessionId && currentSessionId !== pending.id) {
      pendingAcceptedSession = null;
      return false;
    }
    if (pending.finalizing) return true;
    pending.finalizing = true;
    markSessionHandled();
    if (pending.isSvelteComponent) {
      commitAcceptedSvelteComponentToDom(pending.id);
    }
    setLiveState('CONFIRMED');
    updateBarContent('confirmed');
    scheduleAcceptCleanup(pending);
    return true;
  }

  function scheduleAcceptCleanup(accepted) {
    queueMicrotask(function() {
      if (pendingAcceptedSession?.id !== accepted?.id) return;
      // Svelte previews live in an adapter-owned mount rather than in source
      // wrapper markup. Promote the mounted variant before releasing the
      // session so the old adapter instance cannot linger behind the next
      // Pick → Go loop while carbonize finishes in the background.
      if (accepted?.isSvelteComponent) {
        commitAcceptedSvelteComponentToDom(accepted.id);
      }
      cleanupAcceptedSession();
    });
    // Let React/Vue/Svelte own the HMR reconciliation. Mutating their DOM in
    // the same turn as the source update causes removeChild/NotFoundError
    // races. Static servers still need a fallback, but it must not keep Live
    // in SAVING or block the user's next pick.
    if (!accepted?.isSvelteComponent) {
      setTimeout(function() {
        if (!acceptedDomAlreadyClean(accepted)) ensureAcceptedDomClean(accepted);
      }, 1200);
    }
  }

  function snapshotAcceptedVariantDom(sessionId, variantId) {
    const wrapper = document.querySelector('[data-impeccable-variants="' + sessionId + '"]');
    const accepted = wrapper?.querySelector?.('[data-impeccable-variant="' + variantId + '"]');
    const root = accepted?.firstElementChild || null;
    return {
      acceptedHtml: accepted ? accepted.innerHTML : '',
      acceptedSelector: selectorForAcceptedRoot(root),
      parentElement: wrapper?.parentElement || null,
      parentSelector: selectorForAcceptedRoot(wrapper?.parentElement || null),
      nextSibling: wrapper?.nextSibling || null,
    };
  }

  function selectorForAcceptedRoot(root) {
    if (!root || !root.tagName) return '';
    const tag = root.tagName.toLowerCase();
    const classes = [...(root.classList || [])].filter(Boolean);
    if (classes.length === 0) return tag;
    return tag + classes.map((cls) => '.' + cssIdent(cls)).join('');
  }

  function acceptedDomAlreadyClean(pending) {
    if (!pending?.acceptedSelector) return false;
    const matches = [...document.querySelectorAll(pending.acceptedSelector)];
    return matches.length > 0
      && matches.every((el) => !el.closest('[data-impeccable-variants],[data-impeccable-variant],[data-impeccable-carbonize]'));
  }

  function ensureAcceptedDomClean(pending) {
    if (acceptedDomAlreadyClean(pending)) return;
    const sessionId = pending?.id;
    const variantId = pending?.variant;
    const wrappers = findAcceptedRuntimeWrappers(sessionId);
    if (wrappers.length === 0) {
      restoreAcceptedDomFromSnapshot(pending);
      return;
    }
    for (const wrapper of wrappers) {
      if (!wrapper?.isConnected) continue;
      const accepted = wrapper.querySelector?.('[data-impeccable-variant="' + variantId + '"]');
      if (!accepted) {
        wrapper.remove();
        continue;
      }
      const parent = wrapper.parentElement;
      if (!parent) continue;
      while (accepted.firstChild) {
        parent.insertBefore(accepted.firstChild, wrapper);
      }
      wrapper.remove();
    }
    if (!acceptedDomAlreadyClean(pending)) restoreAcceptedDomFromSnapshot(pending);
  }

  function findAcceptedRuntimeWrappers(sessionId) {
    if (!sessionId) return [];
    return [...new Set([
      ...document.querySelectorAll('[data-impeccable-variants="' + sessionId + '"]'),
      ...document.querySelectorAll('[data-impeccable-carbonize="' + sessionId + '"]'),
    ])];
  }

  function restoreAcceptedDomFromSnapshot(pending) {
    if (acceptedDomAlreadyClean(pending)) return;
    if (!pending?.acceptedHtml) {
      reloadAfterMissingAcceptedDom(pending);
      return;
    }
    const parent = pending.parentElement?.isConnected
      ? pending.parentElement
      : (pending.parentSelector ? document.querySelector(pending.parentSelector) : null);
    if (!parent) {
      reloadAfterMissingAcceptedDom(pending);
      return;
    }
    const template = document.createElement('template');
    template.innerHTML = pending.acceptedHtml;
    const anchor = pending.nextSibling?.isConnected && pending.nextSibling.parentElement === parent
      ? pending.nextSibling
      : null;
    parent.insertBefore(template.content, anchor);
    if (!acceptedDomAlreadyClean(pending)) reloadAfterMissingAcceptedDom(pending);
  }

  function reloadAfterMissingAcceptedDom(pending) {
    if (acceptedDomAlreadyClean(pending)) return;
    if (pending?.id && document.querySelector('[data-impeccable-variants="' + pending.id + '"]')) return;
    location.reload();
  }

  function cleanupAcceptedSession() {
    hideBar();
    hideHighlight();
    stopScrollTracking();
    if (variantObserver) { variantObserver.disconnect(); variantObserver = null; }
    stopScrollLock();
    removeVariantStateStylesheet();
    clearScrollY();
    clearSession();
    resetSessionFileMeta();
    selectedElement = null;
    hoveredElement = null;
    pagePickSkipClick = false;
    currentSessionId = null;
    parameterGenerationState = 'idle';
    parameterReadyAnnouncedSession = null;
    selectedAction = 'impeccable';
    pendingAcceptedSession = null;
    renderEditBadge('hidden');
    setLiveState('PICKING');
  }

  function commitAcceptedVariantToDom(sessionId, variantId) {
    const wrapper = document.querySelector('[data-impeccable-variants="' + sessionId + '"]');
    if (!wrapper) return false;
    const accepted = wrapper.querySelector('[data-impeccable-variant="' + variantId + '"]');
    if (!accepted || !accepted.firstElementChild) return false;
    const parent = wrapper.parentElement;
    if (!parent) return false;

    const style = wrapper.querySelector('style[data-impeccable-css]');
    if (style && !document.querySelector('style[data-impeccable-accepted-css="' + sessionId + '"]')) {
      const promotedStyle = style.cloneNode(true);
      promotedStyle.setAttribute('data-impeccable-accepted-css', sessionId);
      parent.insertBefore(promotedStyle, wrapper);
    }

    const committed = accepted.cloneNode(true);
    committed.removeAttribute('hidden');
    committed.style.display = 'contents';
    parent.replaceChild(committed, wrapper);
    return true;
  }

  function handleDiscard() {
    if (pendingApplyInFlight) { showManualApplyBusyToast(); return; }
    if (!currentSessionId) return;
    sendEvent({ type: 'discard', id: currentSessionId }, { throwOnError: true })
      .then(() => {
        markSessionHandled();
        cleanup({ restoreOriginal: true, instantChrome: true });
      })
      .catch(() => showToast('Could not confirm discard with the live server. Session kept for recovery.', 5000));
  }

  //
  // Session persistence via live-browser-session.js
  //
  // Survives page reloads, browser close/reopen, HMR, and accidental refreshes.

  function normalizeSessionPath(value) {
    if (typeof value !== 'string') return null;
    const trimmed = value.trim();
    return trimmed ? trimmed.replace(/\\/g, '/') : null;
  }

  function resetSessionFileMeta() {
    currentSourceFile = null;
    currentPreviewFile = null;
    currentPreviewMode = null;
    recoveryWaitingForAnchor = false;
    pickedAnchorSnapshot = null;
    pickedAnchorViewportTop = null;
  }

  function rememberSessionFileMeta(meta = {}) {
    const file = normalizeSessionPath(meta.file);
    const sourceFile = normalizeSessionPath(meta.sourceFile);
    const previewFile = normalizeSessionPath(meta.previewFile);
    const previewMode = meta.previewMode || (isSvelteComponentManifestPath(previewFile || file) ? 'svelte-component' : null);

    if (isFrameworkComponentPreviewMode(previewMode) || isSvelteComponentManifestPath(file)) {
      currentPreviewMode = isFrameworkComponentPreviewMode(previewMode) ? previewMode : 'svelte-component';
      currentPreviewFile = previewFile || (isSvelteComponentManifestPath(file) ? file : currentPreviewFile);
      currentSourceFile = sourceFile || currentSourceFile;
      return;
    }

    if (sourceFile || file) currentSourceFile = sourceFile || file;
    if (previewFile) currentPreviewFile = previewFile;
    if (previewMode) currentPreviewMode = previewMode;
  }

  function applySavedSessionMeta(saved) {
    if (!saved) return;
    rememberSessionFileMeta(saved);
    if (saved.insertPlaceholder) insertPlaceholderSnapshot = saved.insertPlaceholder;
    if (saved.pickedAnchor) pickedAnchorSnapshot = saved.pickedAnchor;
    if (Number.isFinite(saved.pickedAnchorViewportTop)) pickedAnchorViewportTop = saved.pickedAnchorViewportTop;
    if (saved.action) selectedAction = saved.action;
    if (saved.count) selectedCount = saved.count;
    if (saved.previewMode) currentPreviewMode = saved.previewMode;
    if (saved.paramValues && typeof saved.paramValues === 'object') {
      paramsCurrentValues = { ...saved.paramValues };
    }
    if (saved.parameterState) parameterGenerationState = saved.parameterState;
    if (saved.generationPhase) generationPhase = saved.generationPhase;
  }

  function normalizePagePath(value) {
    if (!value || typeof value !== 'string') return null;
    try {
      return new URL(value, location.origin).pathname;
    } catch {
      return value.split(/[?#]/)[0] || null;
    }
  }

  function pageMatchesCurrent(value) {
    const path = normalizePagePath(value);
    return !path || path === location.pathname;
  }

  function isTerminalSessionSummary(session) {
    return /^(completed|discarded|discard_requested|accept_requested)$/.test(String(session?.phase || ''));
  }

  function findActiveSessionSummary(saved, activeSessions) {
    if (!saved?.id || !Array.isArray(activeSessions)) return null;
    return activeSessions.find((session) =>
      session?.id === saved.id
      && pageMatchesCurrent(session.pageUrl || saved.pageUrl)
      && !isTerminalSessionSummary(session)
    ) || null;
  }

  function clampVariantIndex(value, count) {
    const num = Number(value);
    const max = Number(count);
    if (!Number.isFinite(num) || num < 1) return 0;
    if (Number.isFinite(max) && max > 0 && num > max) return 0;
    return Math.floor(num);
  }

  /**
   * A durable server session this page can adopt when the browser has no local
   * record of it. Requires an explicit pageUrl match: a summary with no page is
   * not evidence that it belongs to THIS page, and adopting it would hijack an
   * unrelated route.
   */
  // Phases in which the user is (or should be) comparing variants. Only these
  // are adoptable by a browser with no local record. Steer and manual-edit
  // sessions have no wrapper to restore, and accept/carbonize phases are
  // agent-side work: a reload mid-carbonize must not resurrect the bar over a
  // page whose comparison is already decided (a slow-CI reload hit exactly
  // that window and left the bar stranded after accept).
  const ADOPTABLE_SESSION_PHASES = new Set([
    'generate_requested', 'variants_ready', 'generating', 'cycling',
  ]);

  function findAdoptableServerSession(activeSessions) {
    if (!Array.isArray(activeSessions)) return null;
    return activeSessions.find((session) => (
      session?.id
      && !isTerminalSessionSummary(session)
      && !isSessionHandled(session.id)
      && session.pageUrl
      && pageMatchesCurrent(session.pageUrl)
      && (session.previewFile || session.sourceFile)
      && Number(session.expectedVariants) > 0
      && ADOPTABLE_SESSION_PHASES.has(String(session.phase || ''))
    )) || null;
  }

  // Shape a server summary like a saved local session so one restore path
  // serves both. The server has no browser state machine, so an adopted session
  // always re-enters GENERATING and lets the injection settle the final state.
  function serverSessionAsSavedShape(session) {
    return {
      id: session.id,
      state: 'GENERATING',
      expected: Number(session.expectedVariants) || 0,
      arrived: Number(session.arrivedVariants) || 0,
      visible: Number(session.visibleVariant) || 0,
      sourceFile: session.sourceFile || undefined,
      previewFile: session.previewFile || undefined,
      previewMode: session.previewMode || undefined,
      pageUrl: session.pageUrl || undefined,
      paramValues: session.paramValues && typeof session.paramValues === 'object' ? session.paramValues : {},
    };
  }

  function restoreSessionWithoutWrapper(reason, activeSessions) {
    const cached = loadSession();
    // localStorage is a cache, not a gate. A cleared tab, a second browser
    // profile, or a teardown that dropped local state all leave the durable
    // server session as the only record of work in progress; adopt it instead
    // of stranding a session the server still considers live.
    const adopted = cached?.id ? null : findAdoptableServerSession(activeSessions);
    const saved = cached?.id ? cached : (adopted ? serverSessionAsSavedShape(adopted) : null);
    if (!saved?.id || isSessionHandled(saved.id)) return false;
    const savedState = String(saved.state || '').toUpperCase();
    if (savedState !== 'GENERATING' && savedState !== 'CYCLING') return false;

    const serverSession = findActiveSessionSummary(saved, activeSessions);
    if (Array.isArray(activeSessions) && activeSessions.length > 0 && !serverSession) {
      return false;
    }

    currentSessionId = saved.id;
    applySavedSessionMeta(serverSession);
    applySavedSessionMeta(saved);

    expectedVariants = Number(saved.expected || serverSession?.expectedVariants || selectedCount || 0);
    arrivedVariants = Number(saved.arrived || serverSession?.arrivedVariants || 0);
    if (arrivedVariants <= 0 && currentPreviewFile) arrivedVariants = Number(serverSession?.expectedVariants || saved.expected || selectedCount || 0);
    if (expectedVariants <= 0) expectedVariants = Number(serverSession?.expectedVariants || arrivedVariants || selectedCount || 0);
    visibleVariant = clampVariantIndex(saved.visible, arrivedVariants || expectedVariants)
      || clampVariantIndex(serverSession?.visibleVariant, arrivedVariants || expectedVariants)
      || (arrivedVariants > 0 ? 1 : 0);

    const restoredAnchor = findLiveElementFromAnchorSnapshot(pickedAnchorSnapshot);
    selectedElement = restoredAnchor || document.body;
    setLiveState('GENERATING');
    recoveryWaitingForAnchor = !restoredAnchor;
    showBar('generating');
    startScrollTracking();
    if (variantObserver) variantObserver.disconnect();
    variantObserver = startVariantObserver(currentSessionId);
    saveSession();
    queueCheckpoint(reason || 'browser_restore_without_wrapper');

    const restoreFile = isFrameworkComponentPreviewMode(currentPreviewMode)
      ? currentPreviewFile
      : (currentSourceFile || currentPreviewFile);
    if (restoreFile) {
      // A restored CYCLING session promises variants already written into
      // source; if they are not there (after retries), the session is an
      // orphan and must self-discard instead of freezing the picker (#439).
      // GENERATING restores make no such promise: deferred-wrapper flows
      // legitimately have no wrapper in source until the agent's write lands.
      injectVariantsFromSource(restoreFile, currentSessionId, {
        orphanDiscard: savedState === 'CYCLING' && !isFrameworkComponentPreviewMode(currentPreviewMode),
      });
      return true;
    }

    return true;
  }

  function restoreFromActiveSessions(activeSessions, reason) {
    const wrapper = document.querySelector('[data-impeccable-variants]');
    if (wrapper && !isFrameworkComponentPreviewMode(wrapper.dataset.impeccablePreview)) return false;
    if (svelteComponentSession?.sessionId === currentSessionId) return false;
    return restoreSessionWithoutWrapper(reason || 'sse_connected', activeSessions);
  }

  // Self-heal on SSE (re)connect. The preflight scaffold write triggers a
  // framework full-reload (Astro reloads pages for any .astro edit); if the
  // agent's variant write + `done` broadcast land while this page is
  // mid-reload, both the done SSE and the second HMR reload are missed and
  // the resumed page would wait in GENERATING at 0/N forever. The server's
  // session summary carries the durable generationCompletedAt marker, so on
  // every connect compare it against our own progress and pull the finished
  // variants from source when behind. Mirrors the `done` handler's source
  // fallback, including its give-HMR-the-first-chance settle delay.
  function recoverMissedGenerationCompletion(activeSessions) {
    if (!currentSessionId || state !== 'GENERATING') return;
    if (!Array.isArray(activeSessions)) return;
    const summary = activeSessions.find((session) => session?.id === currentSessionId);
    if (!summary?.generationCompletedAt || summary.generationCanceled) return;
    if (isTerminalSessionSummary(summary)) return;
    if (arrivedVariants > 0 && arrivedVariants >= expectedVariants) return;
    rememberSessionFileMeta(summary);
    const sessionId = currentSessionId;
    const file = isFrameworkComponentPreviewMode(currentPreviewMode)
      ? currentPreviewFile
      : (summary.sourceFile || summary.previewFile || currentSourceFile || currentPreviewFile);
    if (!file) return;
    console.log('[impeccable] Reconnected after generation completed; recovering variants from source.');
    setTimeout(() => {
      if (sessionId !== currentSessionId || state !== 'GENERATING') return;
      if (arrivedVariants > 0 && arrivedVariants >= expectedVariants) return;
      injectVariantsFromSource(file, sessionId, { generationCompleted: true });
    }, 750);
  }

  function saveSession() {
    if (!currentSessionId) return;
    // NOTE: scrollY is stored under a separate key (writeScrollY). Storing
    // it here would overwrite the Go-time value every time state changes.
    sessionState.saveSession({
      id: currentSessionId,
      appRoot: APP_ROOT || undefined,
      state,
      action: selectedAction,
      count: selectedCount,
      expected: expectedVariants,
      arrived: arrivedVariants,
      visible: visibleVariant,
      sourceFile: currentSourceFile || undefined,
      previewFile: currentPreviewFile || undefined,
      previewMode: currentPreviewMode || undefined,
      pageUrl: location.pathname,
      paramValues: { ...paramsCurrentValues },
      parameterState: parameterGenerationState,
      insertPlaceholder: insertPlaceholderSnapshot || undefined,
      pickedAnchor: pickedAnchorSnapshot || undefined,
      pickedAnchorViewportTop: Number.isFinite(pickedAnchorViewportTop) ? pickedAnchorViewportTop : undefined,
      pageHash: location.hash || undefined,
      pageSearch: location.search || undefined,
    });
  }

  function loadSession() {
    const saved = sessionState.loadSession();
    // localStorage is per-origin, and two projects routinely reuse the same
    // localhost port. A saved session stamped with another project's appRoot
    // is that project's leftover, never a session this server can complete;
    // resuming it freezes the picker behind an unfinishable banner.
    if (saved?.appRoot && APP_ROOT && saved.appRoot !== APP_ROOT) {
      console.warn('[impeccable] Ignoring saved live session from another project (' + saved.appRoot + ').');
      sessionState.clearSession();
      return null;
    }
    return saved;
  }

  function clearSession() {
    sessionState.clearSession();
  }

  /** Mark session as handled (accepted/discarded). The agent will clean up
   *  the source, but until it does the wrapper is still in the HTML. This
   *  prevents resumeSession from picking it up again after reload. */
  function markSessionHandled() {
    if (!currentSessionId) return;
    sessionState.markHandled(currentSessionId);
  }

  function isSessionHandled(id) {
    return sessionState.isHandled(id);
  }

  function clearHandled() {
    sessionState.clearHandled();
  }

  function cleanup(options) {
    const restoreOriginal = options?.restoreOriginal === true;
    const instantChrome = options?.instantChrome === true;
    const cleanupSessionId = currentSessionId;
    clearMountErrorCard();
    lastReportedMountFailure = null;
    if (svelteComponentSession?.sessionId === cleanupSessionId) {
      teardownSvelteComponentSession(true);
    } else if (cleanupSessionId) {
      // Switch visibility immediately without structurally mutating the DOM.
      // HMR from the agent's source rewrite may still be on its way,
      // and a manual replaceChild under React causes NotFoundError when the
      // reconciler later tries to remove a wrapper we already removed.
      // Schedule a 2s fallback that does the manual swap only if HMR hasn't
      // replaced the wrapper by then (keeps static-server / no-HMR flows alive).
      const wrapper = document.querySelector('[data-impeccable-variants="' + cleanupSessionId + '"]');
      if (wrapper) {
        if (restoreOriginal) showOriginalDuringDiscard(cleanupSessionId);
        else wrapper.style.display = 'none';
      }
      setTimeout(function() {
        document.getElementById(DISCARD_STATE_STYLE_ID)?.remove();
        if (!cleanupSessionId) return;
        const lateWrapper = document.querySelector('[data-impeccable-variants="' + cleanupSessionId + '"]');
        if (!lateWrapper) return;
        const orig = lateWrapper.querySelector('[data-impeccable-variant="original"]');
        if (orig) {
          const content = orig.firstElementChild;
          if (content) {
            lateWrapper.parentElement.replaceChild(content, lateWrapper);
            return;
          }
        }
        lateWrapper.remove();
      }, 2000);
    }
    hideBar(instantChrome);
    hideHighlight();
    stopScrollTracking();
    if (variantObserver) { variantObserver.disconnect(); variantObserver = null; }
    if (pendingVariantAnchorRetryObserver) { pendingVariantAnchorRetryObserver.disconnect(); pendingVariantAnchorRetryObserver = null; }
    stopScrollLock();
    removeVariantStateStylesheet();
    clearScrollY();
    finalizeInsertSession();
    clearSession();
    resetSessionFileMeta();
    selectedElement = null;
    hoveredElement = null;
    pagePickSkipClick = false;
    currentSessionId = null;
    parameterGenerationState = 'idle';
    parameterReadyAnnouncedSession = null;
    selectedAction = 'impeccable';
    renderEditBadge('hidden');
    setLiveState('PICKING');
  }

  //
  // Toast
  //

  function dismissToast() {
    if (!toastEl) return;
    toastEl.remove();
    toastEl = null;
  }

  function showToast(message, duration) {
    dismissToast();
    // Stack the toast above the global bar (which sits at bottom:14px) so
    // the two never overlap. Read the bar's actual rect - its height varies
    // with hover-expanded labels - and fall back to a sensible default
    // when the bar isn't mounted yet.
    const barRect = globalBarEl?.getBoundingClientRect();
    const barTopFromBottom = barRect && barRect.height > 0
      ? Math.max(16, window.innerHeight - barRect.top + 12)
      : 16;
    const currentToast = el('div', {
      position: 'fixed', bottom: barTopFromBottom + 'px', left: '50%',
      transform: 'translateX(-50%) translateY(8px)',
      background: C.ink, color: C.white,
      fontFamily: FONT, fontSize: '12px',
      padding: '8px 16px', borderRadius: '8px',
      zIndex: Z.toast, opacity: '0',
      transition: 'opacity 0.25s ' + EASE + ', transform 0.25s ' + EASE,
      pointerEvents: 'none', maxWidth: '420px', textAlign: 'center',
    });
    toastEl = currentToast;
    currentToast.id = PREFIX + '-toast';
    currentToast.textContent = message;
    uiAppend(currentToast);
    requestAnimationFrame(() => {
      if (toastEl !== currentToast) return;
      currentToast.style.opacity = '1';
      currentToast.style.transform = 'translateX(-50%) translateY(0)';
    });
    setTimeout(() => {
      if (toastEl !== currentToast) return;
      currentToast.style.opacity = '0';
      currentToast.style.transform = 'translateX(-50%) translateY(8px)';
      setTimeout(() => {
        if (toastEl !== currentToast) return;
        currentToast.remove();
        toastEl = null;
      }, 250);
    }, duration);
  }

  //
  // Init
  //

  // Resume an active variant session after HMR/page reload.
  // If a [data-impeccable-variants] wrapper exists in the DOM, the agent wrote
  // variants before HMR fired. Pick up where we left off.
  function resumeSession() {
    const wrapper = document.querySelector('[data-impeccable-variants]');
    if (!wrapper) {
      if (restoreSessionWithoutWrapper('browser_resumed_without_wrapper')) return true;
      clearSession();
      clearHandled();
      return false;
    }

    const sessionId = wrapper.dataset.impeccableVariants;

    // Don't resume if this session was already accepted/discarded
    if (isSessionHandled(sessionId)) return false;

    // Svelte component sessions can't be resumed by counting DOM children: the
    // wrapper holds a single mount target, not [data-impeccable-variant] nodes,
    // and a page reload unmounts every compiled variant. Counting children here
    // would strand the bar in CYCLING at 0/0. If there's no live in-memory mount
    // for this wrapper, it's an orphan (reload / failed mount): drop it and let
    // the live-server's SSE re-inject the manifest if the session is still live.
    if (isFrameworkComponentPreviewMode(wrapper.dataset.impeccablePreview)
        && svelteComponentSession?.sessionId !== sessionId) {
      wrapper.remove();
      if (restoreSessionWithoutWrapper('browser_resumed_svelte_orphan_wrapper')) return true;
      clearSession();
      clearHandled();
      return false;
    }

    if (isFrameworkComponentPreviewMode(wrapper.dataset.impeccablePreview)) {
      if (!svelteComponentSession?.mountedVariant) {
        return true;
      }
      currentSessionId = sessionId;
      expectedVariants = Number(wrapper.dataset.impeccableVariantCount)
        || Number(svelteComponentSession.manifest?.count)
        || expectedVariants
        || 1;
      arrivedVariants = expectedVariants;
      const saved = loadSession();
      applySavedSessionMeta(saved);
      const savedVisibleVariant = saved && saved.id === sessionId ? saved.visible : 0;
      visibleVariant = svelteComponentSession.mountedVariant > 0 && svelteComponentSession.mountedVariant <= arrivedVariants
        ? svelteComponentSession.mountedVariant
        : (savedVisibleVariant > 0 && savedVisibleVariant <= arrivedVariants ? savedVisibleVariant : 1);
      selectedElement = resolveSvelteComponentAnchor()
        || wrapper.parentElement;
      setLiveState('CYCLING');
      hideShaderOverlay();
      showBar('cycling');
      startScrollTracking();
      refreshParamsPanel();
      saveSession();
      queueCheckpoint('browser_resumed_svelte_component');
      return true;
    }

    currentSessionId = sessionId;
    expectedVariants = parseInt(wrapper.dataset.impeccableVariantCount || '0');
    const variants = wrapper.querySelectorAll('[data-impeccable-variant]:not([data-impeccable-variant="original"])');
    arrivedVariants = variants.length;

    // Restore state from localStorage if available
    const saved = loadSession();
    if (saved && saved.id === sessionId) {
      applySavedSessionMeta(saved);
      visibleVariant = (saved.visible > 0 && saved.visible <= arrivedVariants) ? saved.visible : (arrivedVariants > 0 ? 1 : 0);
      if (saved.action) selectedAction = saved.action;
      if (saved.count) selectedCount = saved.count;
    } else {
      visibleVariant = arrivedVariants > 0 ? 1 : 0;
    }

    if (saved && saved.id === sessionId && saved.insertPlaceholder) {
      insertPlaceholderSnapshot = saved.insertPlaceholder;
    }

    const resumedState = arrivedVariants > 0 ? 'CYCLING' : 'GENERATING';

    // Find the visible variant's content element for highlight positioning.
    const isInsert = wrapper.dataset.impeccableMode === 'insert';
    const visEl = visibleVariant > 0 ? pickVariantContent(wrapper, visibleVariant) : null;
    const origEl = pickVariantContent(wrapper, 'original');
    setLiveState(resumedState);
    if (isInsert && resumedState === 'GENERATING' && arrivedVariants === 0) {
      selectedElement = ensureInsertPlaceholder() || findInsertAnchorInDom() || wrapper;
    } else {
      selectedElement = visEl || origEl || (isInsert ? findInsertAnchorInDom() : null) || wrapper.parentElement;
    }

    // Set display state BEFORE starting observer (avoid triggering it)
    if (visibleVariant > 0) showVariantInDOM(currentSessionId, visibleVariant);

    showBar(state === 'CYCLING' ? 'cycling' : 'generating');
    startScrollTracking();
    // Build the params panel for the restored visible variant. Previously
    // this was missed on page-reload resume: showVariantInDOM above fires
    // refreshParamsPanel, but state was still IDLE at that moment so it
    // hid. Now that state is CYCLING, re-fire.
    if (state === 'CYCLING') refreshParamsPanel();
    saveSession();
    if (arrivedVariants > 0 && arrivedVariants < expectedVariants) {
      sendCheckpoint('variants_progress');
    } else {
      queueCheckpoint('browser_resumed');
    }

    // Start observing for more variants AFTER initial setup
    if (variantObserver) variantObserver.disconnect();
    variantObserver = startVariantObserver(currentSessionId);

    // Hold the target at its saved viewport top through any subsequent
    // HMR patches, variant inserts, or cycle swaps.
    startScrollLock(currentSessionId, readScrollY(), pickedAnchorViewportTop);

    // If we reloaded mid-generation (Bun's HTML HMR destroys the shader
    // canvas), re-capture the original's content and restart the shader so
    // the wait doesn't go dead.
    if (state === 'GENERATING') {
      const shaderTarget = isInsert
        ? (ensureInsertPlaceholder() || findInsertAnchorInDom())
        : origEl;
      if (shaderTarget) {
        (async () => {
          try {
            const rect = shaderTarget.getBoundingClientRect();
            if (rect.width === 0 || rect.height === 0) return;
            const { blob, paper } = await captureElementToBlob(shaderTarget, null, rect);
            if (blob && state === 'GENERATING') {
              showShaderOverlay(shaderTarget, blob, rect, paper);
            }
          } catch (err) {
            console.warn('[impeccable] shader resume failed:', err);
          }
        })();
      }
    }
    return true;
  }

  //
  // Global bar (always visible at bottom)
  //

  let globalBarEl = null;
  let globalBarBrandEl = null;
  let agentPollTooltipEl = null;
  let agentPollingConnected = false;
  let agentStatusMessage = null;
  let agentStatusPollTimer = null;
  let steerFocusSuspended = false;
  let steerFocusPauseUntil = 0;
  let pagePointerGesture = null;
  let pagePickSkipClick = false;
  let steerFocusRecoverTimer = null;
  const STEER_PAGE_FOCUS_PAUSE_MS = 500;
  let detectActive = false;
  let detectScanSeq = 0;
  let activeDetectScanId = null;
  let pendingDetectScanId = null;
  const DETECT_EMPTY_MESSAGE = 'No detector issues found.';
  const PICK_PREFS_KEY = 'impeccable-live-pick';
  const INTERACTION_PREFS_KEY = 'impeccable-live-interaction';
  const PLACEHOLDER_DEFAULT_HEIGHT = 80;
  const PLACEHOLDER_MIN_HEIGHT = 48;
  const PLACEHOLDER_MIN_WIDTH = 120;

  function loadInteractionPrefs() {
    try {
      const raw = localStorage.getItem(INTERACTION_PREFS_KEY);
      if (raw) {
        const prefs = JSON.parse(raw);
        return {
          pickActive: !!prefs.pickActive,
          insertActive: !!prefs.insertActive,
        };
      }
      const legacy = localStorage.getItem(PICK_PREFS_KEY);
      if (legacy) {
        const prefs = JSON.parse(legacy);
        return { pickActive: !!prefs.pickActive, insertActive: false };
      }
    } catch { /* ignore */ }
    return { pickActive: false, insertActive: false };
  }

  function saveInteractionPrefs() {
    try {
      localStorage.setItem(INTERACTION_PREFS_KEY, JSON.stringify({ pickActive, insertActive }));
    } catch { /* ignore */ }
  }

  function loadPickPref() {
    return loadInteractionPrefs().pickActive;
  }

  function savePickPref() {
    saveInteractionPrefs();
  }

  let pickActive = loadInteractionPrefs().pickActive;
  let insertActive = loadInteractionPrefs().insertActive;
  let configureKind = 'replace';
  let insertLineEl = null;
  let insertHoverAnchor = null;
  let insertHoverPosition = null;
  let insertHoverAxis = null;
  let insertAnchorElement = null;
  let insertAnchorPosition = null;
  let insertAnchorLayoutAxis = null;
  let insertPlaceholderSnapshot = null;
  let placeholderElement = null;
  let detectCount = 0;
  let detectScriptLoaded = false;
  let pendingDockEl = null;
  let pendingPillEl = null;
  let pendingPillSpinnerEl = null;
  let pendingPillLabelEl = null;
  let pendingPillCountEl = null;
  let pendingTrashBtn = null;
  let pendingKeepFixingBtn = null;
  let pendingRollbackBtn = null;
  let pendingDockResizeObserver = null;
  let pendingIntroAnimation = null;
  let pendingApplyInFlight = false;
  let firstSaveOfSession = true;

  // Steer - collapsed pill in the global bar; expands while typing for page-level chat.
  let pageChatEl = null;
  let pageChatInput = null;
  let pageChatHint = null;
  let pageChatVoiceBtn = null;
  let pageChatSendBtn = null;
  let pageChatQueueHintEl = null;
  let pageChatExpanded = false;
  let steerLocked = false;
  let steerRequestId = null;
  let steerPendingMessage = '';
  let steerInputWasFocused = false;
  let pageChatDotsEl = null;
  let steerAwaitTimer = null;
  let voiceRecognition = null;
  let voiceListening = false;
  let voiceSuppressSubmit = false;
  let voiceInterimBase = '';
  /** @type {{ mode: 'steer'|'configure', input: HTMLInputElement, submit: () => void, beforeStart?: () => void } | null} */
  let voiceCtx = null;
  const PAGE_CHAT_COLLAPSED_W = '104px';
  const PAGE_CHAT_QUEUED_W = '212px';
  const PAGE_CHAT_PLACEHOLDER_COLLAPSED = 'Steer…';
  const PAGE_CHAT_PLACEHOLDER_EXPANDED = 'Steer the page…';
  const STEER_AWAIT_TIMEOUT_MS = 120000;
  const AGENT_STATUS_POLL_MS = 5000;
  const AGENT_DISCONNECTED_MARK = 'oklch(62% 0 0 / 0.78)';
  const AGENT_DISCONNECTED_TIP = 'Agent disconnected - run live-poll.mjs to connect';
  // The indicator tracks whether a poll is parked, which is what decides if
  // steering can reach the agent right now. That goes quiet two ways, and they
  // need different copy: nobody is polling at all, or the agent took the work
  // and is busy with it. Under one-shot foreground polling the second case is
  // every normal generation, and telling the user to start a poll loop then is
  // wrong advice about a healthy session.
  const AGENT_BUSY_TIP = 'Agent is working - steering resumes when it finishes';
  // Same distinction, said where the steer request is waiting. A submitted
  // steer that lands while a generate holds the poll lease is not stuck, it is
  // second in line, and the pulsing dots alone read as "nothing is happening".
  const STEER_QUEUED_HINT = 'Queued behind current generation';
  const GLOBAL_BAR_SECTION_GAP = 8;
  const GLOBAL_BAR_INNER_GAP = 2;
  const GLOBAL_BAR_INNER_PAD_LEFT = 2;
  const PAGE_CHAT_EXPANDED_MAX_W = 280;
  const ICON_PAGE_CHAT =
    '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>';
  const ICON_PAGE_VOICE =
    '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/></svg>';

  // Theme-aware color palette for the global bar. We detect the page's
  // ambient background and invert - dark bar on light pages, light bar on
  // dark pages. This keeps the bar from fighting with the host design.
  function detectPageTheme() {
    try {
      // Dev override: set localStorage 'impeccable-dev-theme' to 'light' or
      // 'dark' to preview the opposite palette without actually changing the
      // page bg. Used for screenshots and theme QA.
      const override = localStorage.getItem('impeccable-dev-theme');
      if (override === 'light' || override === 'dark') return override;

      // Walk body → html, taking the first opaque background. The browser's
      // default body / html background is `rgba(0, 0, 0, 0)`, which a naive
      // regex would read as black and mislabel a perfectly white page as
      // dark. Honoring alpha avoids that - and falling through to <html>
      // catches the common pattern of a bg only on <html> (or only on body).
      function readOpaque(el) {
        if (!el) return null;
        const bg = getComputedStyle(el).backgroundColor;
        const m = bg.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d.]+))?\s*\)/);
        if (!m) return null;
        const alpha = m[4] == null ? 1 : parseFloat(m[4]);
        if (alpha < 0.5) return null; // transparent / nearly transparent → skip
        return [+m[1], +m[2], +m[3]];
      }

      const rgb = readOpaque(document.body) || readOpaque(document.documentElement);
      // Both transparent → fall back to the browser's effective canvas color.
      // White is the universal default; only one in a thousand sites swaps it
      // via `color-scheme: dark` on <html>, and `prefers-color-scheme` lets
      // us catch that case.
      if (!rgb) {
        return matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
      }
      const [r, g, b] = rgb;
      // Perceptual luminance (Rec. 709)
      const L = (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;
      return L > 0.55 ? 'light' : 'dark';
    } catch { return 'light'; }
  }

  function barPaletteForTheme(_theme) {
    // Picker chrome always uses neo-kinpaku styling (homepage /live-mode demo
    // bars in kinpaku-kit.css), regardless of host page light/dark theme.
    return {
      surface: C.ink,
      surfaceDeep: C.ink,
      // Quiet neutral hairline (was the loud kinpaku gold border). Gold lives on
      // the brand mark and the active control instead.
      border: 'oklch(92% 0 0 / 0.13)',
      // Crisp graphite pill behind the active toggle (was a murky kinpaku-dim
      // wash); the gold text/icon carries the "selected" signal.
      toggleActive: 'oklch(27% 0 0)',
      // Neutral hairline for internal control borders / dividers (was a warm
      // gold rule that read as muddy champagne edges on the pill / input / count).
      hairline: 'oklch(92% 0 0 / 0.12)',
      text: 'oklch(91% 0 0)',
      textDim: 'oklch(72% 0 0)',
      accent: C.brand,
      accentSoft: C.brandSoft,
      exitHover: 'oklch(58% 0.15 35 / 0.18)',
      shadow: PICKER_SHADOW,
      chatSurface: 'oklch(22% 0.012 82)',
      // Verdigris patina - secondary state (see site/styles/kinpaku-tokens.css)
      patina: 'oklch(70% 0.12 188)',
      patinaPale: 'oklch(82% 0.07 188)',
      patinaSoft: 'oklch(70% 0.12 188 / 0.28)',
    };
  }

  function pageChatPalette() {
    return barPaletteForTheme(globalBarEl?.dataset.theme || detectPageTheme());
  }

  function globalBarModeToggles() {
    return [
      uiGetById(PREFIX + '-pick-toggle'),
      uiGetById(PREFIX + '-insert-toggle'),
      uiGetById(PREFIX + '-detect-toggle'),
      uiGetById(PREFIX + '-design-toggle'),
    ].filter(Boolean);
  }

  function applyGlobalBarLabelState(expandInactive, forceCollapse = false) {
    globalBarModeToggles().forEach((toggle) => {
      if (forceCollapse) toggle._collapseLabel?.(true);
      else if (expandInactive || toggle.dataset.active === 'true') toggle._expandLabel?.();
      else toggle._collapseLabel?.();
    });
  }

  function syncGlobalBarExpandedLabels(expanded = globalBarEl?.matches(':hover')) {
    const expandInactive = !!(expanded && !pageChatExpanded);
    applyGlobalBarLabelState(expandInactive, pageChatExpanded);

    if (expandInactive && globalBarEl && globalBarEl.scrollWidth > window.innerWidth - 16) {
      applyGlobalBarLabelState(false);
    }
  }

  function pageChatCollapsedWidthPx() {
    const parsed = parseFloat(PAGE_CHAT_COLLAPSED_W);
    return Number.isFinite(parsed) ? parsed : 104;
  }

  function pageChatExpandedWidth() {
    if (!pageChatEl || !globalBarEl) return PAGE_CHAT_EXPANDED_MAX_W + 'px';
    const currentChatWidth = pageChatEl.getBoundingClientRect().width || pageChatCollapsedWidthPx();
    const barWidth = Math.max(globalBarEl.getBoundingClientRect().width || 0, globalBarEl.scrollWidth || 0);
    const nonChatWidth = Math.max(0, barWidth - currentChatWidth);
    const available = window.innerWidth - 16 - nonChatWidth;
    const next = Math.max(pageChatCollapsedWidthPx(), Math.min(PAGE_CHAT_EXPANDED_MAX_W, available));
    return Math.round(next) + 'px';
  }

  function syncPageChatExpandedWidth() {
    if (!pageChatEl || !pageChatExpanded) return;
    pageChatEl.style.width = pageChatExpandedWidth();
  }

  function syncPageChatChrome() {
    if (!pageChatEl) return;
    const P = pageChatPalette();
    const inputFocused = pageChatInput && activeElementDeep() === pageChatInput;
    pageChatEl.style.background = P.chatSurface;
    pageChatEl.style.borderColor = 'transparent';
    if (pageChatHint) pageChatHint.style.color = steerLocked ? P.patinaPale : P.textDim;
    const chatIcon = pageChatEl?.firstElementChild;
    if (chatIcon) {
      chatIcon.style.color = steerLocked
        ? P.patinaPale
        : (inputFocused || pageChatExpanded ? P.text : P.textDim);
    }
    if (pageChatInput) pageChatInput.style.color = P.text;
    if (pageChatVoiceBtn) {
      const listening = pageChatVoiceBtn.dataset.listening === 'true';
      pageChatVoiceBtn.style.color = listening || pageChatVoiceBtn.dataset.active === 'true'
        ? P.accent
        : P.textDim;
    }
  }

  function syncPageChatVisual() {
    if (!pageChatInput || steerLocked) {
      syncPageChatSendButton();
      return;
    }
    const hasText = pageChatInput.value.length > 0;
    if (hasText && !pageChatExpanded) expandPageChat({ focus: false });
    else if (!hasText && pageChatExpanded) collapsePageChat();
    syncPageChatSendButton();
  }

  /**
   * Send is visible once the pill is open for typing and enabled once there is
   * something to send. It disappears entirely while a steer is in flight, the
   * same way the mic does: a second submit during the lock has nowhere to go.
   */
  function syncPageChatSendButton() {
    if (!pageChatSendBtn) return;
    const P = pageChatPalette();
    const hasText = !!pageChatInput?.value.trim();
    const focused = pageChatInput && activeElementDeep() === pageChatInput;
    const visible = !steerLocked && (pageChatExpanded || hasText || focused);
    pageChatSendBtn.style.display = visible ? 'inline-flex' : 'none';
    pageChatSendBtn.disabled = !visible || !hasText;
    pageChatSendBtn.style.background = P.accent;
    pageChatSendBtn.style.color = C.ink;
    pageChatSendBtn.style.borderLeft = '1px solid ' + P.hairline;
    pageChatSendBtn.style.opacity = pageChatSendBtn.disabled ? '0.42' : '1';
    pageChatSendBtn.style.cursor = pageChatSendBtn.disabled ? 'not-allowed' : 'pointer';
    pageChatSendBtn.title = pageChatSendBtn.disabled ? 'Type what to change first' : 'Send (Enter)';
  }

  /**
   * A submitted steer is queued, not ignored, whenever no poll is parked and
   * the browser knows a generation is in flight: the agent holds the lease and
   * will not see the steer until it finishes. Saying so beats three dots that
   * look identical to a lost request.
   */
  function steerQueuedBehindGeneration() {
    return steerLocked && !agentPollingConnected && agentHasWorkInFlight();
  }

  function buildSteerQueueHint() {
    const P = pageChatPalette();
    const hint = el('span', {
      display: 'inline-flex', alignItems: 'center', justifyContent: 'flex-end',
      flex: '1', minWidth: '0', marginLeft: 'auto',
      padding: '0 10px 0 6px',
      fontFamily: FONT, fontSize: '10.5px', fontWeight: '500',
      color: P.patinaPale,
      whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
      pointerEvents: 'none',
    });
    hint.id = PREFIX + '-page-chat-queue';
    return hint;
  }

  function syncSteerQueueHint() {
    if (!pageChatEl) return;
    const queued = steerQueuedBehindGeneration();
    if (queued) {
      if (!pageChatQueueHintEl) {
        pageChatQueueHintEl = buildSteerQueueHint();
        pageChatEl.appendChild(pageChatQueueHintEl);
      }
      pageChatQueueHintEl.textContent = STEER_QUEUED_HINT;
      if (pageChatDotsEl) pageChatDotsEl.style.display = 'none';
      pageChatEl.style.width = PAGE_CHAT_QUEUED_W;
      pageChatEl.setAttribute('aria-label', STEER_QUEUED_HINT);
      return;
    }
    if (pageChatQueueHintEl?.parentNode) {
      pageChatQueueHintEl.remove();
      pageChatQueueHintEl = null;
      if (steerLocked) {
        pageChatEl.style.width = pageChatExpanded ? pageChatExpandedWidth() : PAGE_CHAT_COLLAPSED_W;
        pageChatEl.setAttribute('aria-label', 'Processing steer request');
      }
    }
    if (pageChatDotsEl) pageChatDotsEl.style.display = '';
  }

  function shouldFocusSteerChat() {
    return state !== 'CONFIGURING'
      && state !== 'EDITING'
      && !steerLocked;
  }

  function isPageEditableElement(el) {
    if (!el || own(el)) return false;
    if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName || '')) return true;
    return !!el.isContentEditable;
  }

  function isInlineEditActive(el) {
    return !!el && inlineEditRows.some((r) => r.el === el);
  }

  function isPageEditableActive() {
    const active = activeElementDeep();
    return isPageEditableElement(active) && !isInlineEditActive(active);
  }

  function pageHasHostTextSelection() {
    const sel = window.getSelection?.();
    if (!sel || sel.isCollapsed) return false;
    if (!(sel.toString() || '').trim()) return false;
    const node = sel.anchorNode;
    const el = node?.nodeType === 1 ? node : node?.parentElement;
    if (el && own(el)) return false;
    return true;
  }

  function shouldSteerAutoFocus() {
    return shouldFocusSteerChat()
      && !steerFocusSuspended
      && !isPageEditableActive()
      && performance.now() >= steerFocusPauseUntil;
  }

  function clearSteerFocusRecoverTimer() {
    if (steerFocusRecoverTimer) {
      clearTimeout(steerFocusRecoverTimer);
      steerFocusRecoverTimer = null;
    }
  }

  function scheduleSteerFocusRecover(reason) {
    clearSteerFocusRecoverTimer();
    const attempt = () => {
      steerFocusRecoverTimer = null;
      if (state === 'CONFIGURING' || steerLocked || voiceListening) return;
      if (pageChatEl?.contains(activeElementDeep())) return;
      if (pageHasHostTextSelection()) {
        steerFocusRecoverTimer = setTimeout(attempt, 120);
        return;
      }
      const pauseLeft = steerFocusPauseUntil - performance.now();
      if (pauseLeft > 0) {
        steerFocusRecoverTimer = setTimeout(attempt, pauseLeft);
        return;
      }
      if (!shouldFocusSteerChat()) return;
      syncPageChatFocus(reason);
    };
    steerFocusRecoverTimer = setTimeout(attempt, 0);
  }

  function notePagePointerDown(e) {
    if (!shouldFocusSteerChat() || own(e.target)) return;
    steerFocusSuspended = true;
    steerFocusPauseUntil = performance.now() + STEER_PAGE_FOCUS_PAUSE_MS;
    pagePointerGesture = { x: e.clientX, y: e.clientY, dragged: false };
    if (pageChatInput && activeElementDeep() === pageChatInput) {
      pageChatInput.blur();
    }
  }

  function attachSteerFocusGuard() {
    if (window.__IMPECCABLE_STEER_FOCUS_GUARD__) return;
    window.__IMPECCABLE_STEER_FOCUS_GUARD__ = true;

    document.addEventListener('mousedown', (e) => {
      notePagePointerDown(e);
    }, true);

    document.addEventListener('mousemove', (e) => {
      if (!pagePointerGesture || pagePointerGesture.dragged) return;
      const dx = e.clientX - pagePointerGesture.x;
      const dy = e.clientY - pagePointerGesture.y;
      if (Math.hypot(dx, dy) > 4) pagePointerGesture.dragged = true;
    }, true);

    document.addEventListener('mouseup', () => {
      if (!shouldFocusSteerChat()) return;
      pagePickSkipClick = !!(pagePointerGesture?.dragged || pageHasHostTextSelection());
      if (pageHasHostTextSelection()) {
        steerFocusSuspended = true;
      } else {
        steerFocusSuspended = false;
        scheduleSteerFocusRecover('page-mouseup-recover');
      }
      pagePointerGesture = null;
    }, true);

    document.addEventListener('selectionchange', () => {
      if (!shouldFocusSteerChat()) return;
      const wasSuspended = steerFocusSuspended;
      steerFocusSuspended = pageHasHostTextSelection();
      if (wasSuspended && !steerFocusSuspended) {
        scheduleSteerFocusRecover('selection-cleared');
      }
    });
  }

  function steerFocusTargetLabel(el) {
    if (!el || el === document.body) return 'body';
    if (el === document.documentElement) return 'html';
    if (el.id) return el.tagName.toLowerCase() + '#' + el.id;
    return el.tagName?.toLowerCase() || String(el);
  }

  function steerFocusDebugEnabled() {
    try { return localStorage.getItem('impeccable-steer-debug') === '1'; } catch { return false; }
  }

  function steerFocusLog(reason, extra) {
    if (!steerFocusDebugEnabled()) return;
    console.log('[impeccable.steer]', reason, {
      state,
      pickActive,
      pageChatReady: !!pageChatInput,
      pageChatExpanded,
      active: steerFocusTargetLabel(activeElementDeep()),
      shouldSteer: shouldFocusSteerChat(),
      ...(extra || {}),
    });
  }

  function attachSteerFocusDebug() {
    if (!steerFocusDebugEnabled()) return;
    if (window.__IMPECCABLE_STEER_FOCUS_DEBUG__) return;
    window.__IMPECCABLE_STEER_FOCUS_DEBUG__ = true;
    document.addEventListener('focusin', (e) => {
      if (!pageChatInput) return;
      steerFocusLog('focusin', { target: steerFocusTargetLabel(e.target) });
    }, true);
  }

  function focusConfigureInput(reason) {
    steerFocusLog('focusConfigureInput', { reason });
    const inputId = configureKind === 'insert' ? PREFIX + '-insert-input' : PREFIX + '-input';
    const input = uiGetById(inputId);
    if (!input) {
      steerFocusLog('focusConfigureInput missing', { reason });
      return;
    }
    setTimeout(() => {
      const before = activeElementDeep();
      input.focus();
      steerFocusLog('focusConfigureInput result', {
        reason,
        before: steerFocusTargetLabel(before),
        after: steerFocusTargetLabel(activeElementDeep()),
        stuck: activeElementDeep() !== input,
      });
    }, 60);
  }

  function syncPageChatFocusRing() {
    if (!pageChatEl || !pageChatInput) return;
    syncPageChatSendButton();
    const focused = activeElementDeep() === pageChatInput;
    const typingReady = focused && !steerLocked;
    pageChatEl.dataset.inputFocused = focused ? 'true' : 'false';
    pageChatEl.style.boxShadow = 'none';

    if (pageChatExpanded) {
      pageChatInput.placeholder = PAGE_CHAT_PLACEHOLDER_EXPANDED;
      pageChatInput.style.width = '';
      pageChatInput.style.padding = '0 6px';
      pageChatInput.style.opacity = steerLocked ? '0.72' : '1';
      pageChatInput.style.pointerEvents = steerLocked ? 'none' : 'auto';
      return;
    }

    if (typingReady) {
      // Collapsed type-to-steer: show the real input + caret instead of a
      // truncated patina "Steer" label with an invisible focused field.
      pageChatInput.placeholder = PAGE_CHAT_PLACEHOLDER_COLLAPSED;
      if (pageChatHint) {
        pageChatHint.style.display = 'none';
        pageChatHint.style.opacity = '0';
      }
      pageChatInput.style.width = '';
      pageChatInput.style.padding = '0 4px';
      pageChatInput.style.opacity = '1';
      pageChatInput.style.pointerEvents = 'auto';
      return;
    }

    pageChatInput.placeholder = PAGE_CHAT_PLACEHOLDER_COLLAPSED;
    if (pageChatHint) {
      pageChatHint.style.display = '';
      pageChatHint.style.opacity = '1';
      pageChatHint.style.visibility = '';
    }
    pageChatInput.style.width = '0';
    pageChatInput.style.padding = '0';
    pageChatInput.style.opacity = '0';
    pageChatInput.style.pointerEvents = 'none';
  }

  function focusSteerChat(reason) {
    steerFocusLog('focusSteerChat called', { reason });
    if (!pageChatInput || !shouldSteerAutoFocus()) {
      steerFocusLog('focusSteerChat skipped', {
        reason,
        hasInput: !!pageChatInput,
        shouldSteer: shouldFocusSteerChat(),
        suspended: steerFocusSuspended,
      });
      return;
    }
    syncPageChatVisual();
    pageChatInput.style.pointerEvents = 'auto';
    const before = activeElementDeep();
    try { window.focus(); } catch { /* embed may block */ }
    try { pageChatInput.focus({ preventScroll: true }); } catch { pageChatInput.focus(); }
    syncPageChatFocusRing();
    syncPageChatChrome();
    steerFocusLog('focusSteerChat result', {
      reason,
      before: steerFocusTargetLabel(before),
      after: steerFocusTargetLabel(activeElementDeep()),
      stuck: activeElementDeep() !== pageChatInput,
    });
  }

  function syncPageChatFocus(reason) {
    steerFocusLog('syncPageChatFocus', { reason });
    if (state === 'CONFIGURING') focusConfigureInput(reason);
    else if (shouldSteerAutoFocus()) focusSteerChat(reason);
  }

  function buildSteerProcessingDots() {
    const P = pageChatPalette();
    const wrap = el('span', {
      display: 'inline-flex', alignItems: 'center', justifyContent: 'flex-end',
      gap: '5px', flex: '0 0 auto', minWidth: '0', marginLeft: 'auto',
      padding: '0 12px 0 8px',
      pointerEvents: 'none',
    });
    wrap.setAttribute('aria-hidden', 'true');
    for (let i = 0; i < 3; i++) {
      wrap.appendChild(el('span', {
        display: 'inline-block',
        width: '4px', height: '4px', borderRadius: '50%',
        background: P.patinaPale,
        boxShadow: '0 0 6px ' + P.patinaSoft,
        animation: 'impeccable-steer-dot 1.05s ease-in-out ' + (i * 0.14) + 's infinite',
      }));
    }
    return wrap;
  }

  function keepSteerPointerInside(e, opts = {}) {
    e.stopPropagation();
    if (opts.preventDefault !== false) e.preventDefault();
  }

  function preparePageChatInputForTyping() {
    if (!pageChatEl || !pageChatInput) return false;
    pageChatExpanded = true;
    pageChatEl.dataset.expanded = 'true';
    syncGlobalBarExpandedLabels(false);
    pageChatEl.style.width = pageChatExpandedWidth();
    pageChatEl.style.cursor = steerLocked ? 'default' : 'text';
    pageChatInput.placeholder = PAGE_CHAT_PLACEHOLDER_EXPANDED;
    if (pageChatHint) {
      pageChatHint.style.display = 'none';
      pageChatHint.style.opacity = '0';
    }
    pageChatInput.style.width = '';
    pageChatInput.style.padding = '0 6px';
    pageChatInput.style.opacity = steerLocked ? '0.72' : '1';
    pageChatInput.style.pointerEvents = steerLocked ? 'none' : 'auto';
    return true;
  }

  function armPageChatForTyping(opts = {}) {
    if (!pageChatEl || !pageChatInput || steerLocked) return false;
    const expand = opts.expand !== false;
    const focus = opts.focus !== false;
    if (expand && !pageChatExpanded) {
      preparePageChatInputForTyping();
      syncPageChatChrome();
    }
    if (focus) return focusPageChatInput('arm-page-chat');
    syncPageChatFocusRing();
    syncPageChatChrome();
    return true;
  }

  function focusPageChatInput(reason) {
    if (!preparePageChatInputForTyping() || steerLocked) return false;
    try { pageChatInput.focus({ preventScroll: true }); } catch { pageChatInput.focus(); }
    const focused = activeElementDeep() === pageChatInput;
    if (focused) steerInputWasFocused = true;
    syncPageChatFocusRing();
    return focused;
  }

  function clearSteerAwaitTimer() {
    if (steerAwaitTimer) {
      clearTimeout(steerAwaitTimer);
      steerAwaitTimer = null;
    }
  }

  function scheduleSteerAwaitTimeout(id) {
    clearSteerAwaitTimer();
    steerAwaitTimer = setTimeout(() => {
      if (!steerLocked || steerRequestId !== id) return;
      unlockSteerChat({
        error: steerTimeoutMessage(),
        restoreMessage: steerPendingMessage,
      });
    }, STEER_AWAIT_TIMEOUT_MS);
  }

  /**
   * Two minutes of silence has three different causes and only one of them is
   * "live-poll is not running". Naming the wrong one sends the user to restart
   * a poll loop that was never the problem.
   */
  function steerTimeoutMessage() {
    const head = 'Steer timed out after 2 minutes. ';
    if (steerQueuedBehindGeneration()) {
      return head + 'The agent is still busy with the current generation - your message was not lost, but it never got picked up. Send it again once the variants land.';
    }
    if (!agentPollingConnected) {
      return head + 'No agent is polling right now. Run live-poll.mjs, then send it again.';
    }
    return head + 'The agent picked it up but never replied with steer_done. Check the agent session for a stalled or failed steer.';
  }

  function lockSteerChat() {
    if (!pageChatEl || !pageChatInput) return;
    stopVoice({ suppressSubmit: true });
    steerLocked = true;
    pageChatEl.dataset.processing = 'true';
    pageChatInput.disabled = true;
    preparePageChatInputForTyping();
    if (pageChatVoiceBtn) {
      pageChatVoiceBtn.disabled = true;
      pageChatVoiceBtn.style.display = 'none';
    }
    pageChatEl.style.cursor = 'default';
    pageChatInput.style.pointerEvents = 'none';
    if (pageChatHint) {
      pageChatHint.style.display = 'none';
      pageChatHint.style.visibility = 'hidden';
    }
    pageChatEl.setAttribute('aria-busy', 'true');
    pageChatEl.setAttribute('aria-label', 'Processing steer request');
    if (!pageChatDotsEl) {
      pageChatDotsEl = buildSteerProcessingDots();
      pageChatEl.appendChild(pageChatDotsEl);
    }
    syncSteerQueueHint();
    syncPageChatFocusRing();
    syncPageChatChrome();
  }

  function unlockSteerChat(opts) {
    clearSteerAwaitTimer();
    const restoreMessage = typeof opts?.restoreMessage === 'string' ? opts.restoreMessage : '';
    const keepExpanded = Boolean(opts?.error && restoreMessage);
    steerLocked = false;
    const completedId = steerRequestId;
    steerRequestId = null;
    if (!pageChatEl) return;
    pageChatEl.dataset.processing = 'false';
    pageChatEl.removeAttribute('aria-busy');
    pageChatEl.setAttribute('aria-label', 'Steer the page');
    pageChatExpanded = keepExpanded;
    pageChatEl.dataset.expanded = keepExpanded ? 'true' : 'false';
    pageChatEl.style.width = keepExpanded ? pageChatExpandedWidth() : PAGE_CHAT_COLLAPSED_W;
    pageChatEl.style.cursor = 'pointer';
    if (pageChatInput) {
      pageChatInput.disabled = false;
      pageChatInput.value = keepExpanded ? restoreMessage : '';
      pageChatInput.style.width = keepExpanded ? '' : '0';
      pageChatInput.style.padding = keepExpanded ? '0 6px' : '0';
      pageChatInput.style.opacity = keepExpanded ? '1' : '0';
      pageChatInput.style.pointerEvents = 'auto';
    }
    if (pageChatVoiceBtn) {
      pageChatVoiceBtn.disabled = false;
      pageChatVoiceBtn.style.display = '';
    }
    if (pageChatHint) {
      pageChatHint.textContent = 'Steer';
      pageChatHint.style.display = keepExpanded ? 'none' : '';
      pageChatHint.style.visibility = keepExpanded ? 'hidden' : '';
      pageChatHint.style.opacity = keepExpanded ? '0' : '1';
    }
    if (pageChatDotsEl?.parentNode) {
      pageChatDotsEl.remove();
      pageChatDotsEl = null;
    }
    if (pageChatQueueHintEl?.parentNode) {
      pageChatQueueHintEl.remove();
      pageChatQueueHintEl = null;
    }
    steerPendingMessage = keepExpanded ? restoreMessage : '';
    steerInputWasFocused = false;
    syncPageChatChrome();
    syncPageChatFocusRing();
    if (opts?.error) showToast(String(opts.error), 5000);
    else if (opts?.message) showToast(String(opts.message), 4000);
    if (completedId) {
      sendSteerCheckpoint(completedId, opts?.error ? 'steer_error' : 'steer_done', {
        message: opts?.message || opts?.error || '',
        file: opts?.file || '',
      });
    }
    if (keepExpanded) focusPageChatInput('steer-error-restore');
    else syncPageChatFocus('steer-unlock');
  }

  function steerSpeechRecognitionCtor() {
    return window.SpeechRecognition || window.webkitSpeechRecognition || null;
  }

  function isEmbeddedPreviewBrowser() {
    const ua = navigator.userAgent || '';
    if (/Electron/i.test(ua)) return true;
    if (/Cursor/i.test(ua)) return true;
    try {
      return !!(window.cursor || window.__CURSOR__ || window.__GLASS_BROWSER__);
    } catch { return false; }
  }

  function steerVoiceUnavailableMessage() {
    return 'Voice input works in Chrome or Safari. Cursor\'s preview browser cannot reach speech services.';
  }

  function steerVoiceErrorMessage(code) {
    switch (code) {
      case 'not-allowed':
        return 'Microphone access blocked';
      case 'audio-capture':
        return 'No microphone found';
      case 'network':
        return isEmbeddedPreviewBrowser()
          ? steerVoiceUnavailableMessage()
          : 'Voice input needs a network connection (browser speech uses a cloud service)';
      case 'service-not-allowed':
        return 'Voice input is not available in this browser tab';
      case 'language-not-supported':
        return 'Speech language not supported';
      case 'no-speech':
      case 'aborted':
        return null;
      default:
        return 'Voice input failed (' + code + ')';
    }
  }

  function syncVoiceUi(listening) {
    voiceListening = !!listening;
    if (voiceCtx?.mode === 'steer') {
      if (pageChatVoiceBtn) {
        pageChatVoiceBtn.dataset.active = listening ? 'true' : 'false';
        pageChatVoiceBtn.dataset.listening = listening ? 'true' : 'false';
        pageChatVoiceBtn.setAttribute('aria-label', listening ? 'Stop voice input' : 'Voice input');
        pageChatVoiceBtn.setAttribute('aria-pressed', listening ? 'true' : 'false');
      }
      if (pageChatEl) pageChatEl.dataset.voiceListening = listening ? 'true' : 'false';
      syncPageChatChrome();
    } else if (voiceCtx?.mode === 'configure') {
      // The bar shows either the replace row's voice button or the insert
      // row's - both run voice through the 'configure' mode.
      const voiceBtn = uiGetById(PREFIX + '-configure-voice') || uiGetById(PREFIX + '-insert-voice');
      if (voiceBtn) {
        voiceBtn.dataset.active = listening ? 'true' : 'false';
        voiceBtn.dataset.listening = listening ? 'true' : 'false';
        voiceBtn.setAttribute('aria-label', listening ? 'Stop voice input' : 'Voice input');
        voiceBtn.setAttribute('aria-pressed', listening ? 'true' : 'false');
      }
      syncConfigureInputChrome();
    }
  }

  function releaseVoiceEngine(opts) {
    if (opts && opts.suppressSubmit) voiceSuppressSubmit = true;
    const rec = voiceRecognition;
    voiceRecognition = null;
    if (!rec) return;
    rec.onstart = null;
    rec.onresult = null;
    rec.onerror = null;
    rec.onend = null;
    try {
      if (opts && opts.abort) rec.abort();
      else rec.stop();
    } catch { /* already ended */ }
  }

  function stopVoice(opts) {
    releaseVoiceEngine(opts);
    syncVoiceUi(false);
    voiceCtx = null;
    if (opts && opts.message) showToast(String(opts.message), opts.duration || 4000);
  }

  function finishVoiceSession() {
    voiceRecognition = null;
    const ctx = voiceCtx;
    syncVoiceUi(false);
    const suppress = voiceSuppressSubmit;
    voiceSuppressSubmit = false;
    voiceCtx = null;
    const input = ctx?.input;
    const text = input?.value.trim() || '';
    if (suppress || !text || !ctx) return;
    if (ctx.mode === 'steer' && !steerLocked) ctx.submit();
    else if (ctx.mode === 'configure' && state === 'CONFIGURING') ctx.submit();
  }

  function startVoice(ctx) {
    if (!ctx?.input || voiceListening) return;
    if (ctx.mode === 'steer' && (steerLocked || state === 'CONFIGURING')) return;
    if (ctx.mode === 'configure' && state !== 'CONFIGURING') return;
    const Ctor = steerSpeechRecognitionCtor();
    if (!Ctor) {
      showToast('Voice input needs Speech Recognition (Chrome, Safari, or Edge)', 4500);
      return;
    }
    if (!window.isSecureContext) {
      showToast('Voice input needs HTTPS or localhost', 4500);
      return;
    }
    if (isEmbeddedPreviewBrowser()) {
      showToast(steerVoiceUnavailableMessage(), 5200);
      return;
    }

    releaseVoiceEngine({ suppressSubmit: true, abort: true });
    voiceSuppressSubmit = false;
    voiceCtx = ctx;
    if (ctx.beforeStart) ctx.beforeStart();

    voiceInterimBase = ctx.input.value.trim()
      ? ctx.input.value.trim() + ' '
      : '';

    const rec = new Ctor();
    rec.continuous = false;
    rec.interimResults = true;
    rec.lang = document.documentElement.lang || navigator.language || 'en-US';
    rec.maxAlternatives = 1;

    rec.onstart = () => {
      syncVoiceUi(true);
    };

    rec.onresult = (event) => {
      if (!voiceCtx?.input) return;
      let transcript = '';
      for (let i = 0; i < event.results.length; i++) {
        transcript += event.results[i][0]?.transcript || '';
      }
      voiceCtx.input.value = (voiceInterimBase + transcript).trim();
      if (voiceCtx.mode === 'steer') syncPageChatVisual();
      else syncConfigureInputChrome();
    };

    rec.onerror = (event) => {
      const code = event.error || 'unknown';
      console.warn('[impeccable.voice] recognition error:', code);
      const message = steerVoiceErrorMessage(code);
      stopVoice({ suppressSubmit: true, message: message || undefined });
    };

    rec.onend = () => {
      if (voiceRecognition !== rec) return;
      finishVoiceSession();
    };

    voiceRecognition = rec;
    try {
      rec.start();
    } catch (err) {
      console.warn('[impeccable.voice] start failed:', err);
      stopVoice({
        suppressSubmit: true,
        message: err?.message?.includes('already started')
          ? 'Voice input already running'
          : 'Could not start voice input',
      });
    }
  }

  function steerVoiceContext() {
    return {
      mode: 'steer',
      input: pageChatInput,
      beforeStart: () => {
        if (!pageChatExpanded) expandPageChat({ focus: false });
      },
      submit: submitSteerMessage,
    };
  }

  function configureVoiceContext() {
    const input = uiGetById(
      configureKind === 'insert' ? PREFIX + '-insert-input' : PREFIX + '-input',
    );
    return {
      mode: 'configure',
      input,
      beforeStart: () => { input?.focus(); },
      submit: configureKind === 'insert' ? handleInsertCreate : handleGo,
    };
  }

  function toggleSteerVoice() {
    if (voiceListening && voiceCtx?.mode === 'steer') {
      voiceSuppressSubmit = true;
      stopVoice({ suppressSubmit: true, abort: true });
      return;
    }
    startVoice(steerVoiceContext());
  }

  function toggleConfigureVoice() {
    if (voiceListening && voiceCtx?.mode === 'configure') {
      voiceSuppressSubmit = true;
      stopVoice({ suppressSubmit: true, abort: true });
      return;
    }
    startVoice(configureVoiceContext());
  }

  function submitSteerMessage() {
    stopVoice({ suppressSubmit: true });
    const text = pageChatInput?.value.trim();
    if (!text || steerLocked) return;
    const id = id8();
    steerRequestId = id;
    steerPendingMessage = text;
    lockSteerChat();
    scheduleSteerAwaitTimeout(id);
    // Checkpoints follow the steer event, never precede it: the steer event
    // is what creates the session journal server-side, and a checkpoint for
    // a not-yet-created session is rejected as unknown_session.
    sendEvent({
      type: 'steer',
      id,
      message: text,
      pageUrl: location.href,
    }).then((res) => {
      if (!res) {
        unlockSteerChat({ error: 'Could not reach live server', restoreMessage: text });
        return;
      }
      if (steerInputWasFocused) sendSteerCheckpoint(id, 'steer_input_focused', { focused: true });
      sendSteerCheckpoint(id, 'steer_submitted', { message: text, pageUrl: location.href });
    });
  }

  function maybeCompleteSteer(msg) {
    if (!steerRequestId || msg.id !== steerRequestId) return false;
    if (msg.type === 'steer_done') {
      unlockSteerChat({ message: msg.message, file: msg.file });
      if (msg.file && /\.svelte(?:$|\?)/.test(String(msg.file))) {
        setTimeout(() => {
          if (!steerLocked) showToast('Steer applied. Reload if the page has not refreshed yet.', 5000);
        }, 4500);
      }
      return true;
    }
    if (msg.type === 'error') {
      unlockSteerChat({ error: msg.message || 'Steer failed', restoreMessage: steerPendingMessage });
      return true;
    }
    return false;
  }

  function expandPageChat(opts) {
    const focus = !opts || opts.focus !== false;
    if (!pageChatEl || !pageChatInput || steerLocked) return;
    preparePageChatInputForTyping();
    syncPageChatChrome();
    syncPageChatFocusRing();
    if (focus) focusPageChatInput('expand-page-chat');
  }

  function collapsePageChat(opts) {
    const blur = opts && opts.blur === true;
    if (voiceListening) return;
    if (!pageChatEl || !pageChatInput) return;
    pageChatExpanded = false;
    pageChatEl.dataset.expanded = 'false';
    pageChatEl.style.width = PAGE_CHAT_COLLAPSED_W;
    pageChatEl.style.cursor = 'pointer';
    syncGlobalBarExpandedLabels(globalBarEl?.matches(':hover'));
    if (blur) {
      pageChatInput.blur();
      pageChatInput.style.pointerEvents = 'none';
    } else {
      pageChatInput.style.pointerEvents = 'auto';
    }
    if (pageChatHint && activeElementDeep() !== pageChatInput) {
      pageChatHint.style.display = '';
      pageChatHint.style.opacity = '1';
    }
    if (pageChatVoiceBtn) pageChatVoiceBtn.dataset.active = 'false';
    syncPageChatChrome();
    syncPageChatFocusRing();
  }

  function initPageChat(parent, P) {
    pageChatEl = el('div', {
      display: 'inline-flex', alignItems: 'center',
      height: '28px', margin: '0 4px 0 ' + (GLOBAL_BAR_SECTION_GAP - GLOBAL_BAR_INNER_GAP) + 'px',
      borderRadius: '7px',
      background: P.chatSurface,
      border: '1px solid transparent',
      overflow: 'hidden',
      cursor: 'pointer',
      flexShrink: '0',
      width: PAGE_CHAT_COLLAPSED_W,
      transition: 'border-color 0.15s ease',
    });
    pageChatEl.id = PREFIX + '-page-chat';
    pageChatEl.dataset.expanded = 'false';
    pageChatEl.title = 'Steer the page';

    const chatIcon = el('span', {
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      width: '28px', height: '28px', flexShrink: '0',
      color: P.textDim, pointerEvents: 'none',
    });
    chatIcon.innerHTML = ICON_PAGE_CHAT;

    pageChatHint = el('span', {
      fontSize: '11.5px', fontWeight: '500',
      color: P.textDim,
      whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
      flex: '1', minWidth: '0',
      pointerEvents: 'none',
      transition: 'opacity 0.15s ease',
    });
    pageChatHint.textContent = 'Steer';

    pageChatInput = document.createElement('input');
    pageChatInput.id = PREFIX + '-page-chat-input';
    pageChatInput.type = 'text';
    pageChatInput.placeholder = PAGE_CHAT_PLACEHOLDER_COLLAPSED;
    pageChatInput.setAttribute('aria-label', 'Steer the page');
    Object.assign(pageChatInput.style, {
      flex: '1', minWidth: '0', width: '0',
      padding: '0', border: 'none', background: 'transparent',
      fontFamily: FONT, fontSize: '11.5px', color: P.text,
      outline: 'none', opacity: '0', pointerEvents: 'none',
      caretColor: P.accent,
      transition: 'opacity 0.15s ease',
    });

    pageChatVoiceBtn = el('button', {
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      padding: '0', boxSizing: 'border-box',
      width: '28px', height: '28px', flexShrink: '0',
      border: 'none', background: 'transparent',
      color: P.textDim, cursor: 'pointer',
      transition: 'color 0.12s ease, background 0.12s ease',
    });
    pageChatVoiceBtn.id = PREFIX + '-page-chat-voice';
    pageChatVoiceBtn.type = 'button';
    pageChatVoiceBtn.setAttribute('aria-label', 'Voice input');
    pageChatVoiceBtn.innerHTML = ICON_PAGE_VOICE;

    // Visible Send, same affordance the element-level Go bar gets from
    // buildConfigureSubmitButton. Enter still submits; the button exists so a
    // typed steer does not look like a dead-end text field.
    pageChatSendBtn = el('button', {
      display: 'none', alignItems: 'center', justifyContent: 'center',
      padding: '0', boxSizing: 'border-box',
      width: '28px', height: '28px', flexShrink: '0',
      border: 'none', borderLeft: '1px solid ' + P.hairline,
      borderRadius: '0',
      background: P.accent, color: C.ink,
      cursor: 'pointer',
      transition: 'filter 0.12s ease, opacity 0.12s ease',
    });
    pageChatSendBtn.id = PREFIX + '-page-chat-send';
    pageChatSendBtn.type = 'button';
    pageChatSendBtn.setAttribute('aria-label', 'Send steer message');
    pageChatSendBtn.innerHTML = ICON_CONFIGURE_SUBMIT;
    pageChatSendBtn.addEventListener('pointerdown', keepSteerPointerInside);
    pageChatSendBtn.addEventListener('mousedown', keepSteerPointerInside);
    pageChatSendBtn.addEventListener('mouseenter', () => {
      if (!pageChatSendBtn.disabled) pageChatSendBtn.style.filter = 'brightness(1.1)';
    });
    pageChatSendBtn.addEventListener('mouseleave', () => { pageChatSendBtn.style.filter = 'none'; });
    pageChatSendBtn.addEventListener('click', (e) => {
      e.stopPropagation();
      keepSteerPointerInside(e);
      if (steerLocked || pageChatSendBtn.disabled) return;
      submitSteerMessage();
    });

    pageChatEl.appendChild(chatIcon);
    pageChatEl.appendChild(pageChatHint);
    pageChatEl.appendChild(pageChatInput);
    pageChatEl.appendChild(pageChatVoiceBtn);
    pageChatEl.appendChild(pageChatSendBtn);

    if (!uiGetById(PREFIX + '-page-chat-style')) {
      const s = document.createElement('style');
      s.id = PREFIX + '-page-chat-style';
      s.textContent =
        '@keyframes impeccable-steer-dot { 0%, 70%, 100% { opacity: 0.28; transform: scale(0.82); } 35% { opacity: 1; transform: scale(1); } }' +
        '@keyframes impeccable-steer-processing { 0%, 100% { border-color: oklch(70% 0.12 188 / 0.28); box-shadow: 0 0 0 0 oklch(70% 0.12 188 / 0); } 50% { border-color: oklch(82% 0.07 188 / 0.55); box-shadow: 0 0 14px oklch(70% 0.12 188 / 0.18); } }' +
        '@keyframes impeccable-voice-pulse { 0%, 100% { opacity: 0.55; } 50% { opacity: 1; } }' +
        '#' + PREFIX + '-page-chat[data-processing="true"] { animation: impeccable-steer-processing 1.6s ease-in-out infinite; }' +
        '@media (prefers-reduced-motion: reduce) { #' + PREFIX + '-page-chat[data-processing="true"] { animation: none; border-color: oklch(70% 0.12 188 / 0.45); } #' + PREFIX + '-page-chat[data-processing="true"] [aria-hidden="true"] span { animation: none; opacity: 0.85; } }' +
        '#' + PREFIX + '-page-chat[data-voice-listening="true"] { border-color: oklch(70% 0.12 188 / 0.45); }' +
        '#' + PREFIX + '-page-chat-voice[data-listening="true"] svg { animation: impeccable-voice-pulse 1.1s ease-in-out infinite; }' +
        '@media (prefers-reduced-motion: reduce) { #' + PREFIX + '-page-chat-voice[data-listening="true"] svg { animation: none; opacity: 1; } }' +
        '#' + PREFIX + '-page-chat-input::placeholder { color: oklch(72% 0 0); opacity: 1; }' +
        '#' + PREFIX + '-page-chat-input { caret-color: oklch(84% 0.19 80.46); }' +
        '#' + PREFIX + '-page-chat[data-input-focused="true"]:not([data-expanded="true"]) #' + PREFIX + '-page-chat-input::placeholder { color: oklch(72% 0 0); }' +
        '#' + PREFIX + '-page-chat-voice:hover { background: oklch(78% 0.12 82 / 0.12); }';
      uiAppendStyle(s);
    }

    pageChatEl.addEventListener('pointerdown', (e) => {
      keepSteerPointerInside(e);
      if (steerLocked || pageChatVoiceBtn.contains(e.target) || pageChatSendBtn.contains(e.target)) return;
      armPageChatForTyping({ expand: true, focus: false });
    });
    pageChatEl.addEventListener('mousedown', keepSteerPointerInside);
    pageChatEl.addEventListener('click', (e) => {
      keepSteerPointerInside(e);
      if (steerLocked) return;
      if (pageChatVoiceBtn.contains(e.target) || pageChatSendBtn.contains(e.target)) return;
      armPageChatForTyping({ expand: true, focus: true });
    });

    pageChatVoiceBtn.addEventListener('pointerdown', keepSteerPointerInside);
    pageChatVoiceBtn.addEventListener('mousedown', keepSteerPointerInside);
    pageChatVoiceBtn.addEventListener('click', (e) => {
      keepSteerPointerInside(e);
      if (steerLocked) return;
      toggleSteerVoice();
    });

    pageChatInput.addEventListener('pointerdown', keepSteerPointerInside);
    pageChatInput.addEventListener('mousedown', keepSteerPointerInside);
    pageChatInput.addEventListener('click', (e) => {
      keepSteerPointerInside(e);
      if (!steerLocked) focusPageChatInput('page-chat-input-click');
    });

    pageChatInput.addEventListener('input', () => {
      syncPageChatVisual();
      syncPageChatSendButton();
    });

    pageChatInput.addEventListener('focus', () => {
      steerInputWasFocused = true;
      syncPageChatFocusRing();
      syncPageChatChrome();
    });

    pageChatInput.addEventListener('blur', () => {
      syncPageChatFocusRing();
      setTimeout(() => {
        if (state === 'CONFIGURING' || steerLocked || voiceListening) return;
        if (pageChatEl?.contains(activeElementDeep())) return;
        if (!pageChatInput.value.trim()) collapsePageChat();
        scheduleSteerFocusRecover('steer-blur-recover');
      }, 120);
    });

    pageChatInput.addEventListener('keydown', (e) => {
      if ((e.key === 'ArrowUp' || e.key === 'ArrowDown') && !pageChatInput.value) return;
      e.stopPropagation();
      if (e.key === 'Escape') {
        e.preventDefault();
        if (pageChatInput.value) {
          pageChatInput.value = '';
          syncPageChatVisual();
        } else {
          collapsePageChat();
        }
        return;
      }
      if (e.key === 'Enter') {
        e.preventDefault();
        submitSteerMessage();
      }
    });

    parent.appendChild(pageChatEl);
    steerFocusLog('page-chat-mounted', {});
  }

  // Impeccable mark - same paths as site/components/Header.astro + favicon.svg.
  function brandMarkSvg(color = C.brand, size = 18) {
    return `<svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="${color}" aria-hidden="true">
      <path d="M5 2.5 L13.5 2.5 L5.5 21.5 L5 21.5 Q2.5 21.5 2.5 19 L2.5 5 Q2.5 2.5 5 2.5 Z"/>
      <path d="M16.5 2.5 L19 2.5 Q21.5 2.5 21.5 5 L21.5 19 Q21.5 21.5 19 21.5 L8.5 21.5 Z"/>
    </svg>`;
  }

  /**
   * True while the browser is waiting on work it already handed to the agent.
   * In these states a quiet poll indicator means "busy", not "absent".
   */
  function agentHasWorkInFlight() {
    return state === 'GENERATING' || state === 'SAVING';
  }

  /**
   * Derived at read time, not cached: which of the two reasons applies depends on
   * the live state, which moves between the 5s status polls. The truthiness is
   * the same either way, so the indicator's visuals can stay driven by the
   * cached value while the wording stays current.
   */
  function agentStatusText() {
    if (agentPollingConnected) return null;
    return agentHasWorkInFlight() ? AGENT_BUSY_TIP : AGENT_DISCONNECTED_TIP;
  }

  function syncAgentPollingUi(connected) {
    agentPollingConnected = !!connected;
    syncSteerQueueHint();
    if (!globalBarBrandEl) return;
    const P = barPaletteForTheme(globalBarEl?.dataset.theme || detectPageTheme());
    agentStatusMessage = agentStatusText();
    globalBarBrandEl.dataset.agentConnected = connected ? 'true' : 'false';
    // The tooltip is mouse-only, so carry the same distinction in the label or
    // screen-reader users are left with the vaguer of the two readings.
    globalBarBrandEl.setAttribute('aria-label', agentStatusMessage
      ? 'Impeccable live mode - ' + (agentHasWorkInFlight() ? 'agent is working' : 'agent not polling')
      : 'Impeccable live mode');
    globalBarBrandEl.removeAttribute('title');
    globalBarBrandEl.style.cursor = agentStatusMessage ? 'help' : 'default';
    const mark = globalBarBrandEl.querySelector('[data-brand-mark]');
    if (mark) {
      mark.innerHTML = brandMarkSvg(connected ? P.accent : AGENT_DISCONNECTED_MARK, 18);
      mark.style.opacity = '1';
    }
    const dot = globalBarBrandEl.querySelector('[data-agent-dot]');
    if (dot) dot.style.display = agentStatusMessage ? 'block' : 'none';
    if (!agentStatusMessage) hideAgentPollTooltip();
  }

  function ensureAgentPollTooltip() {
    if (agentPollTooltipEl) return agentPollTooltipEl;
    const P = barPaletteForTheme(globalBarEl?.dataset.theme || detectPageTheme());
    agentPollTooltipEl = el('div', {
      position: 'fixed',
      display: 'none',
      opacity: '0',
      zIndex: String(Z.bar + 6),
      pointerEvents: 'none',
      maxWidth: '220px',
      padding: '6px 9px',
      borderRadius: '7px',
      background: P.chatSurface,
      border: '1px solid ' + P.hairline,
      boxShadow: P.shadow,
      color: P.text,
      fontFamily: FONT,
      fontSize: '11px',
      fontWeight: '500',
      lineHeight: '1.35',
      letterSpacing: '0.01em',
      whiteSpace: 'normal',
    });
    agentPollTooltipEl.id = PREFIX + '-agent-poll-tooltip';
    agentPollTooltipEl.textContent = agentStatusText() || AGENT_DISCONNECTED_TIP;
    uiAppend(agentPollTooltipEl);
    return agentPollTooltipEl;
  }

  function showAgentPollTooltip(anchor) {
    if (!agentStatusMessage || !anchor) return;
    const tip = ensureAgentPollTooltip();
    // Re-derive rather than reuse the cached copy: the live state may have moved
    // since the last status poll set it.
    tip.textContent = agentStatusText() || AGENT_DISCONNECTED_TIP;
    tip.style.transition = 'none';
    tip.style.display = 'block';
    tip.style.opacity = '1';
    const r = anchor.getBoundingClientRect();
    const tipW = tip.offsetWidth;
    const tipH = tip.offsetHeight;
    const left = Math.max(8, Math.min(window.innerWidth - tipW - 8, r.left + r.width / 2 - tipW / 2));
    const top = Math.max(8, r.top - tipH - 8);
    tip.style.left = left + 'px';
    tip.style.top = top + 'px';
  }

  function hideAgentPollTooltip() {
    if (!agentPollTooltipEl) return;
    agentPollTooltipEl.style.display = 'none';
    agentPollTooltipEl.style.opacity = '0';
  }

  function stopAgentStatusPoll() {
    if (agentStatusPollTimer) {
      clearInterval(agentStatusPollTimer);
      agentStatusPollTimer = null;
    }
  }

  function fetchAgentPollingStatus() {
    fetch('http://localhost:' + PORT + '/status?token=' + TOKEN, { cache: 'no-store' })
      .then((res) => (res.ok ? res.json() : null))
      .then((data) => {
        if (data && typeof data.agentPolling === 'boolean') {
          syncAgentPollingUi(data.agentPolling);
        }
      })
      .catch(() => { /* server loss handled elsewhere */ });
  }

  function startAgentStatusPoll() {
    stopAgentStatusPoll();
    fetchAgentPollingStatus();
    agentStatusPollTimer = setInterval(fetchAgentPollingStatus, AGENT_STATUS_POLL_MS);
  }

  function initGlobalBar() {
    const theme = detectPageTheme();
    const P = barPaletteForTheme(theme);

    // Custom focus-visible for bar buttons. Browser default is a heavy
    // blue ring that looks jarring on the dark capsule. Replace with a
    // soft accent-tinted inner ring that respects the bar's palette.
    if (!uiGetById(PREFIX + '-bar-focus-style')) {
      const s = document.createElement('style');
      s.id = PREFIX + '-bar-focus-style';
      s.textContent =
        '#' + PREFIX + '-global-bar button:focus { outline: none; }' +
        '#' + PREFIX + '-global-bar button:focus-visible {' +
        '  outline: none;' +
        '  box-shadow: 0 0 0 2px ' + P.accentSoft + ', 0 0 0 3px ' + P.accent + ';' +
        '}' +
        '@keyframes impeccable-agent-dot { 0%, 100% { opacity: 0.45; transform: scale(0.9); } 50% { opacity: 1; transform: scale(1); } }' +
        '#' + PREFIX + '-global-bar-brand[data-agent-connected="false"] [data-agent-dot] { animation: impeccable-agent-dot 1.4s ease-in-out infinite; }' +
        '@media (prefers-reduced-motion: reduce) { #' + PREFIX + '-global-bar-brand[data-agent-connected="false"] [data-agent-dot] { animation: none; opacity: 0.9; } }';
      uiAppendStyle(s);
    }

    globalBarEl = el('div', {
      position: 'fixed', bottom: '14px', left: '50%',
      transform: 'translateX(-50%) translateY(20px)',
      zIndex: Z.bar + 5,
      display: 'flex', alignItems: 'stretch',
      gap: '0',
      width: 'max-content',
      background: P.surface,
      border: '1px solid ' + P.border,
      borderRadius: '8px',
      boxShadow: P.shadow,
      fontFamily: FONT, fontSize: '12px', lineHeight: '1',
      opacity: '0',
      overflow: 'hidden',          // clip the full-bleed brand mark to the bar radius
      maxWidth: 'calc(100vw - 16px)',
      boxSizing: 'border-box',
      transition: 'opacity 0.3s ' + EASE + ', transform 0.3s ' + EASE,
    });
    globalBarEl.id = PREFIX + '-global-bar';
    globalBarEl.dataset.theme = theme;

    // Brand mark - kinpaku Impeccable icon (site header / favicon paths).
    const brand = el('span', {
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      alignSelf: 'stretch', position: 'relative',
      padding: '0 ' + (GLOBAL_BAR_SECTION_GAP - GLOBAL_BAR_INNER_PAD_LEFT) + 'px 0 14px',
      background: 'transparent',
      color: P.accent,
      flexShrink: '0',
    });
    brand.id = PREFIX + '-global-bar-brand';
    brand.dataset.agentConnected = 'false';
    brand.setAttribute('role', 'img');
    brand.setAttribute('aria-label', 'Impeccable live mode - agent not polling');

    const brandMark = el('span', {
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      position: 'relative',
    });
    brandMark.dataset.brandMark = 'true';
    brandMark.innerHTML = brandMarkSvg(P.accent, 18);

    const agentDot = el('span', {
      position: 'absolute', right: '-1px', bottom: '7px',
      width: '6px', height: '6px', borderRadius: '50%',
      background: 'oklch(77% 0.13 82)',
      boxShadow: '0 0 0 2px ' + P.surface,
      display: 'none', pointerEvents: 'none',
    });
    agentDot.dataset.agentDot = 'true';
    agentDot.setAttribute('aria-hidden', 'true');

    brandMark.appendChild(agentDot);
    brand.appendChild(brandMark);
    brand.addEventListener('mouseenter', () => showAgentPollTooltip(brand));
    brand.addEventListener('mouseleave', hideAgentPollTooltip);
    globalBarBrandEl = brand;
    globalBarEl.appendChild(brand);
    syncAgentPollingUi(false);

    // Inner wrapper: holds the toggles with normal bar padding.
    const inner = el('div', {
      display: 'flex', alignItems: 'center',
      padding: '4px 5px 4px ' + GLOBAL_BAR_INNER_PAD_LEFT + 'px', gap: GLOBAL_BAR_INNER_GAP + 'px',
      flex: '0 0 auto',
    });
    inner.id = PREFIX + '-global-bar-inner';
    globalBarEl.appendChild(inner);

    // Button factory: icon-only at rest, label slides in on hover/active.
    function makeIconBtn({ id, svg, label, ariaLabel, labelFont, onClick }) {
      const b = el('button', {
        position: 'relative',
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        boxSizing: 'border-box',
        flex: '0 0 auto',
        minWidth: '30px',
        padding: '6px 8px', borderRadius: '7px',
        border: 'none', background: 'transparent',
        color: P.textDim, fontFamily: FONT, fontSize: '11.5px', fontWeight: '500',
        cursor: 'pointer',
        transition: 'background 0.15s ease, color 0.15s ease',
        whiteSpace: 'nowrap', overflow: 'hidden',
      });
      b.id = id;
      b.title = ariaLabel || label || '';
      b.setAttribute('aria-label', ariaLabel || label || '');
      b.innerHTML = svg + (label
        ? `<span class="icon-btn-label" style="display:inline-block;max-width:0;opacity:0;margin-left:0;overflow:hidden;font-family:${labelFont || FONT};transform:translateX(-4px);transition:opacity 0.2s ease, transform 0.25s ${EASE};">${label}</span>`
        : '');
      const labelEl = b.querySelector('.icon-btn-label');
      const expand = () => {
        if (!labelEl) return;
        labelEl.style.maxWidth = '120px'; labelEl.style.opacity = '1'; labelEl.style.marginLeft = '6px'; labelEl.style.transform = 'translateX(0)';
      };
      const collapse = (force = false) => {
        if (!labelEl || (!force && b.dataset.active === 'true')) return;
        labelEl.style.maxWidth = '0'; labelEl.style.opacity = '0'; labelEl.style.marginLeft = '0'; labelEl.style.transform = 'translateX(-4px)';
      };
      // Per-button hover only changes color (no layout). The label expand/
      // collapse is driven by the bar-level mouseenter/mouseleave so moving
      // the mouse between adjacent buttons doesn't trigger per-button width
      // thrashing - the whole bar grows once and shrinks once.
      b.addEventListener('mouseenter', () => { if (b.dataset.active !== 'true') b.style.color = P.text; });
      b.addEventListener('mouseleave', () => { if (b.dataset.active !== 'true') b.style.color = P.textDim; });
      b.addEventListener('click', onClick);
      b._expandLabel = expand;
      b._collapseLabel = collapse;
      return b;
    }

    // Pick toggle - restored from localStorage; both pick and insert may be off.
    const pickBtn = makeIconBtn({
      id: PREFIX + '-pick-toggle',
      svg: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex-shrink:0"><circle cx="12" cy="12" r="10"/><line x1="22" y1="12" x2="18" y2="12"/><line x1="6" y1="12" x2="2" y2="12"/><line x1="12" y1="6" x2="12" y2="2"/><line x1="12" y1="22" x2="12" y2="18"/></svg>',
      label: 'Pick',
      ariaLabel: 'Pick element',
      onClick: () => togglePick(),
    });
    inner.appendChild(pickBtn);

    const insertBtn = makeIconBtn({
      id: PREFIX + '-insert-toggle',
      svg: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex-shrink:0"><path d="M12 5v14"/><path d="M5 12h14"/></svg>',
      label: 'Insert',
      ariaLabel: 'Insert new element',
      onClick: () => toggleInsert(),
    });
    inner.appendChild(insertBtn);

    // Detect toggle
    const detectBtn = makeIconBtn({
      id: PREFIX + '-detect-toggle',
      svg: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex-shrink:0"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>',
      label: 'Detect',
      ariaLabel: 'Detect anti-patterns',
      onClick: () => toggleDetect(),
    });
    const detectBadge = el('span', {
      fontSize: '10px', fontWeight: '600',
      padding: '0px 5px', borderRadius: '7px', lineHeight: '16px',
      background: P.accent, color: C.ink,
      display: 'none', fontFamily: MONO, marginLeft: '4px',
    });
    detectBadge.id = PREFIX + '-detect-badge';
    detectBtn.appendChild(detectBadge);
    inner.appendChild(detectBtn);

    // DESIGN.md panel toggle - quartet of color squares as the mark.
    const designBtn = makeIconBtn({
      id: PREFIX + '-design-toggle',
      svg: `<span style="display:inline-grid;grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr;width:14px;height:14px;border-radius:3px;overflow:hidden;box-shadow:inset 0 0 0 1px oklch(92% 0 0 / 0.13);flex-shrink:0">
        <span style="background:oklch(84% 0.19 80.46)"></span>
        <span style="background:oklch(70% 0.12 188)"></span>
        <span style="background:oklch(91% 0 0)"></span>
        <span style="background:oklch(34% 0 0)"></span>
      </span>`,
      label: 'DESIGN.md',
      ariaLabel: 'Toggle DESIGN.md panel',
      labelFont: MONO,
      onClick: () => toggleDesignPanel(),
    });
    inner.appendChild(designBtn);

    initPageChat(inner, P);

    // Pending manual edits live outside the bar so applying staged copy edits
    // reads as a distinct next step instead of another chrome toggle.
    pendingDockEl = el('div', {
      position: 'fixed',
      left: '0',
      bottom: '0',
      transform: 'translate(-100%, 50%)',
      zIndex: String(Z.bar + 6),
      display: 'none',
      alignItems: 'center',
      gap: '6px',
      fontFamily: FONT,
      pointerEvents: 'auto',
    });
    pendingDockEl.id = PREFIX + '-pending-dock';

    pendingPillEl = el('button', {
      display: 'none',
      alignItems: 'center',
      gap: '8px',
      fontFamily: FONT,
      fontSize: '12px',
      fontWeight: '600',
      letterSpacing: '0',
      color: C.ink,
      background: P.accent,
      padding: '7px 12px 7px 14px',
      border: 'none',
      borderRadius: '999px',
      whiteSpace: 'nowrap',
      cursor: 'pointer',
      boxShadow: '0 4px 16px oklch(0% 0 0 / 0.16), 0 1px 3px oklch(0% 0 0 / 0.1)',
      transition: 'filter 0.12s ease, transform 0.1s ease, box-shadow 0.18s ease',
    });
    pendingPillEl.title = 'Apply copy edits to source';
    pendingPillSpinnerEl = el('span', {
      display: 'none',
      width: '12px',
      height: '12px',
      borderRadius: '50%',
      border: '2px solid currentColor',
      borderTopColor: 'transparent',
      color: C.ink,
      opacity: '0.9',
      animation: 'impeccable-spin 0.6s linear infinite',
      flex: '0 0 auto',
      boxSizing: 'border-box',
    });
    pendingPillLabelEl = el('span', { lineHeight: '1', whiteSpace: 'nowrap' });
    pendingPillLabelEl.textContent = 'Apply copy edits';
    pendingPillCountEl = el('span', {
      display: 'inline-flex',
      alignItems: 'center',
      justifyContent: 'center',
      minWidth: '17px',
      height: '17px',
      padding: '0 5px',
      borderRadius: '999px',
      background: 'oklch(4% 0.004 95 / 0.18)',
      color: C.ink,
      fontFamily: MONO,
      fontSize: '10px',
      fontWeight: '700',
      lineHeight: '1',
    });
    ensureSpinKeyframes();
    pendingPillEl.appendChild(pendingPillSpinnerEl);
    pendingPillEl.appendChild(pendingPillLabelEl);
    pendingPillEl.appendChild(pendingPillCountEl);
    pendingPillEl.addEventListener('mouseenter', () => {
      if (pendingApplyInFlight) return;
      pendingPillEl.style.filter = 'brightness(1.1)';
      pendingPillEl.style.boxShadow = '0 7px 22px oklch(0% 0 0 / 0.18), 0 2px 5px oklch(0% 0 0 / 0.12)';
    });
    pendingPillEl.addEventListener('mouseleave', () => {
      if (pendingApplyInFlight) return;
      pendingPillEl.style.filter = 'none';
      pendingPillEl.style.transform = 'scale(1)';
      pendingPillEl.style.boxShadow = '0 4px 16px oklch(0% 0 0 / 0.16), 0 1px 3px oklch(0% 0 0 / 0.1)';
    });
    pendingPillEl.addEventListener('mousedown', () => { if (!pendingApplyInFlight) pendingPillEl.style.transform = 'scale(0.97)'; });
    pendingPillEl.addEventListener('mouseup', () => { pendingPillEl.style.transform = 'scale(1)'; });
    pendingPillEl.addEventListener('click', onPendingPillClick);

    pendingTrashBtn = el('button', {
      position: 'relative',
      display: 'none',
      alignItems: 'center',
      justifyContent: 'center',
      padding: '0', boxSizing: 'border-box',
      width: '30px', height: '30px', borderRadius: '999px',
      border: '1px solid ' + P.hairline,
      background: P.chatSurface,
      color: P.textDim,
      overflow: 'visible',
      boxShadow: '0 4px 16px oklch(0% 0 0 / 0.12), 0 1px 3px oklch(0% 0 0 / 0.08)',
      cursor: 'pointer',
      transition: 'color 0.12s ease, background 0.12s ease, box-shadow 0.18s ease',
    });
    pendingTrashBtn.innerHTML = '<svg width="12" height="12" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="flex:0 0 auto"><path d="M3 4h8"/><path d="M5 4V3a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v1"/><path d="M4 4l.5 7a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1L10 4"/></svg>';
    const pendingTrashTooltipEl = el('span', {
      position: 'absolute',
      bottom: 'calc(100% + 8px)',
      left: '50%',
      transform: 'translateX(-50%) translateY(4px)',
      opacity: '0',
      pointerEvents: 'none',
      padding: '8px 16px',
      borderRadius: '8px',
      background: C.ink,
      color: C.white,
      fontFamily: FONT,
      fontSize: '12px',
      fontWeight: '400',
      lineHeight: '1',
      whiteSpace: 'nowrap',
      textAlign: 'center',
      transition: 'opacity 0.16s ease, transform 0.18s ' + EASE,
    });
    pendingTrashTooltipEl.textContent = 'Discard copy edits';
    pendingTrashTooltipEl.setAttribute('role', 'tooltip');
    pendingTrashBtn.appendChild(pendingTrashTooltipEl);
    pendingTrashBtn.setAttribute('aria-label', 'Discard copy edits on this page');
    const showTrashTooltip = () => {
      pendingTrashBtn.style.color = P.accent;
      pendingTrashBtn.style.boxShadow = '0 7px 22px oklch(0% 0 0 / 0.16), 0 2px 5px oklch(0% 0 0 / 0.1)';
      pendingTrashTooltipEl.style.opacity = '1';
      pendingTrashTooltipEl.style.transform = 'translateX(-50%) translateY(0)';
    };
    const hideTrashTooltip = () => {
      pendingTrashBtn.style.color = P.textDim;
      pendingTrashBtn.style.background = P.chatSurface;
      pendingTrashBtn.style.boxShadow = '0 4px 16px oklch(0% 0 0 / 0.12), 0 1px 3px oklch(0% 0 0 / 0.08)';
      pendingTrashTooltipEl.style.opacity = '0';
      pendingTrashTooltipEl.style.transform = 'translateX(-50%) translateY(4px)';
    };
    pendingTrashBtn.addEventListener('mouseenter', showTrashTooltip);
    pendingTrashBtn.addEventListener('mouseleave', hideTrashTooltip);
    pendingTrashBtn.addEventListener('focus', showTrashTooltip);
    pendingTrashBtn.addEventListener('blur', hideTrashTooltip);
    pendingTrashBtn.addEventListener('click', onPendingTrashClick);

    const makePendingDecisionBtn = (label, accent) => {
      const btn = el('button', {
        display: 'none',
        alignItems: 'center',
        justifyContent: 'center',
        height: '30px',
        padding: '0 12px',
        borderRadius: '999px',
        border: '1px solid ' + (accent ? P.accent : P.hairline),
        background: accent ? P.accent : P.chatSurface,
        color: accent ? C.ink : P.textDim,
        fontFamily: FONT,
        fontSize: '12px',
        fontWeight: '600',
        letterSpacing: '0',
        cursor: 'pointer',
        whiteSpace: 'nowrap',
        boxShadow: '0 4px 16px oklch(0% 0 0 / 0.12), 0 1px 3px oklch(0% 0 0 / 0.08)',
      });
      btn.textContent = label;
      return btn;
    };
    pendingKeepFixingBtn = makePendingDecisionBtn('Keep fixing', true);
    pendingKeepFixingBtn.setAttribute('aria-label', 'Ask the agent to keep fixing Apply errors');
    pendingKeepFixingBtn.addEventListener('click', onPendingKeepFixingClick);
    pendingRollbackBtn = makePendingDecisionBtn('Rollback', false);
    pendingRollbackBtn.setAttribute('aria-label', 'Rollback source and keep copy edits staged');
    pendingRollbackBtn.addEventListener('click', onPendingRollbackClick);

    pendingDockEl.appendChild(pendingPillEl);
    pendingDockEl.appendChild(pendingTrashBtn);
    pendingDockEl.appendChild(pendingKeepFixingBtn);
    pendingDockEl.appendChild(pendingRollbackBtn);

    // Thin divider before the exit button
    const divider = el('span', {
      width: '1px', height: '18px',
      background: P.hairline,
      margin: '0 4px 0 2px',
      flexShrink: '0',
    });
    inner.appendChild(divider);

    // Exit × on the right - intentionally subtle (textDim at rest, text on
    // hover) so it sits behind the active toggles in visual hierarchy.
    //
    // Explicit padding + box-sizing here is load-bearing: a host page like
    // `button { padding: 0.5rem 1rem; }` (very common in resets) would
    // otherwise inflate this 24x24 button into 56x40 and push the SVG out
    // of the visible bar - the X stays invisible even though the styles in
    // DevTools look fine. Every other chrome button sets padding inline;
    // this one needed it too.
    const exitBtn = el('button', {
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      padding: '0', boxSizing: 'border-box',
      width: '24px', height: '24px', borderRadius: '6px',
      flexShrink: '0',
      border: 'none', background: 'transparent',
      color: P.textDim, fontFamily: FONT, fontSize: '0', lineHeight: '0',
      cursor: 'pointer', transition: 'color 0.12s ease, background 0.12s ease',
    });
    exitBtn.id = PREFIX + '-exit';
    exitBtn.innerHTML = '<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><line x1="3" y1="3" x2="11" y2="11"/><line x1="11" y1="3" x2="3" y2="11"/></svg>';
    exitBtn.title = 'Exit live mode';
    exitBtn.addEventListener('mouseenter', () => { exitBtn.style.color = 'oklch(58% 0.15 35)'; exitBtn.style.background = P.exitHover; });
    exitBtn.addEventListener('mouseleave', () => { exitBtn.style.color = P.textDim; exitBtn.style.background = 'transparent'; });
    exitBtn.addEventListener('click', () => { sendEvent({ type: 'exit' }); teardown(); });
    inner.appendChild(exitBtn);

    // Bar-level hover: expand mode labels unless Steer is using the space.
    // Buttons with dataset.active="true" ignore collapse (their label stays).
    globalBarEl.addEventListener('mouseenter', () => {
      syncGlobalBarExpandedLabels(true);
      syncPageChatExpandedWidth();
      schedulePendingDockPosition();
      setTimeout(schedulePendingDockPosition, 260);
    });
    globalBarEl.addEventListener('mouseleave', () => {
      syncGlobalBarExpandedLabels(false);
      schedulePendingDockPosition();
      setTimeout(schedulePendingDockPosition, 260);
    });
    globalBarEl.addEventListener('pointerdown', () => {
      try { window.focus(); } catch { /* in-app preview may block */ }
    }, true);

    uiAppend(pendingDockEl);
    uiAppend(globalBarEl);
    defangOutsideHandlers(pendingDockEl);
    defangOutsideHandlers(globalBarEl);

    if (window.ResizeObserver) {
      pendingDockResizeObserver = new ResizeObserver(schedulePendingDockPosition);
      pendingDockResizeObserver.observe(globalBarEl);
    }
    window.addEventListener('resize', positionPendingDock);
    window.addEventListener('resize', syncPageChatExpandedWidth);

    requestAnimationFrame(() => {
      globalBarEl.style.opacity = '1';
      globalBarEl.style.transform = 'translateX(-50%) translateY(0)';
      syncPageChatFocus('global-bar-visible');
    });

    // Listen for detection results AND ready signal
    window.addEventListener('message', onDetectMessage);
    updateGlobalBarState();
  }

  function updateGlobalBarState() {
    const detectToggle = uiGetById(PREFIX + '-detect-toggle');
    const detectBadge = uiGetById(PREFIX + '-detect-badge');
    const pickToggle = uiGetById(PREFIX + '-pick-toggle');
    const insertToggle = uiGetById(PREFIX + '-insert-toggle');
    const designToggle = uiGetById(PREFIX + '-design-toggle');
    const theme = globalBarEl?.dataset.theme || 'light';
    const P = barPaletteForTheme(theme);

    // Sync one toggle's active state, colors, and slide-label visibility.
    function sync(btn, active) {
      if (!btn) return;
      btn.style.background = active ? P.toggleActive : 'transparent';
      btn.style.color = active ? P.accent : P.textDim;
      btn.dataset.active = active ? 'true' : 'false';
      if (active && btn._expandLabel) btn._expandLabel();
      else if (!active && btn._collapseLabel) btn._collapseLabel();
    }
    sync(pickToggle, pickActive);
    sync(insertToggle, insertActive);
    sync(detectToggle, detectActive);
    sync(designToggle, designState.open);

    const controlsLocked = pendingApplyInFlight === true;
    [pickToggle, insertToggle, detectToggle, designToggle].forEach((btn) => {
      if (!btn) return;
      btn.disabled = controlsLocked;
      btn.style.cursor = controlsLocked ? 'not-allowed' : 'pointer';
      btn.style.opacity = controlsLocked ? '0.55' : '1';
    });

    // If the bar is currently under the cursor, keep all labels expanded -
    // otherwise clicking a toggle that deactivates (e.g. closing DESIGN.md)
    // would collapse its label while the user's mouse is still on the bar.
    syncGlobalBarExpandedLabels(globalBarEl && globalBarEl.matches(':hover'));

    if (detectBadge) {
      detectBadge.style.display = (detectActive && detectCount > 0) ? 'inline' : 'none';
      detectBadge.textContent = detectCount;
    }

    // When pick/insert is active, make detect overlays click-through
    document.querySelectorAll('.impeccable-overlay').forEach(o => {
      o.style.pointerEvents = (pickActive || insertActive) ? 'none' : '';
    });
    syncPageInteractionCursor();
  }

  let detectReady = false; // true once detect script posts 'impeccable-ready'
  let detectPendingScan = false; // scan requested before script was ready

  function requestDetectScan() {
    const scanId = String(++detectScanSeq);
    activeDetectScanId = scanId;
    pendingDetectScanId = scanId;
    window.postMessage({
      source: 'impeccable-command',
      action: 'scan',
      config: { scanId },
    }, '*');
  }

  function toggleDetect() {
    if (pendingApplyInFlight) { showManualApplyBusyToast(); return; }
    detectActive = !detectActive;
    updateGlobalBarState();

    if (detectActive) {
      if (!detectScriptLoaded) {
        detectPendingScan = true;
        loadDetectScript();
      } else if (detectReady) {
        requestDetectScan();
      } else {
        detectPendingScan = true;
      }
    } else {
      window.postMessage({ source: 'impeccable-command', action: 'remove' }, '*');
      activeDetectScanId = null;
      pendingDetectScanId = null;
      detectCount = 0;
      updateGlobalBarState();
    }
  }

  function togglePick() {
    if (pendingApplyInFlight) { showManualApplyBusyToast(); return; }
    pickActive = !pickActive;
    if (pickActive) {
      insertActive = false;
      clearInsertPicking();
    }
    saveInteractionPrefs();
    updateGlobalBarState();

    if (!pickActive) {
      if (configureKind === 'insert' && state === 'CONFIGURING') {
        cancelInsertConfigure();
        return;
      }
      teardownConfigureChrome();
      hideHighlight();
      hideActionPicker();
      selectedElement = null;
      hoveredElement = null;
      configureKind = 'replace';
      if (state === 'PICKING' || state === 'CONFIGURING') setLiveState('IDLE');
    } else {
      if (state === 'IDLE') setLiveState('PICKING');
    }
    syncPageChatFocus('toggle-pick');
  }

  function toggleInsert() {
    if (pendingApplyInFlight) { showManualApplyBusyToast(); return; }
    insertActive = !insertActive;
    if (insertActive) {
      pickActive = false;
      hideHighlight();
      hideBar();
      hideActionPicker();
      selectedElement = null;
      configureKind = 'replace';
      if (state === 'CONFIGURING') cancelInsertConfigure();
      else if (state === 'IDLE' || state === 'PICKING') setLiveState('PICKING');
    } else {
      clearInsertPicking();
      if (state === 'PICKING' && !pickActive) setLiveState('IDLE');
    }
    saveInteractionPrefs();
    updateGlobalBarState();
    syncPageChatFocus('toggle-insert');
  }

  function loadDetectScript() {
    if (detectScriptLoaded) return;
    detectScriptLoaded = true;
    const s = document.createElement('script');
    s.src = 'http://localhost:' + PORT + '/detect.js';
    s.dataset.impeccableExtension = 'true';
    document.head.appendChild(s);
  }

  function onDetectMessage(e) {
    if (!e.data || typeof e.data.source !== 'string') return;
    // Detection script is loaded and ready
    if (e.data.source === 'impeccable-ready') {
      detectReady = true;
      if (detectPendingScan && detectActive) {
        detectPendingScan = false;
        requestDetectScan();
      }
    }
    // Scan results arrived
    if (e.data.source === 'impeccable-results') {
      if (!detectActive) return;
      if (activeDetectScanId && e.data.scanId !== activeDetectScanId) return;
      detectCount = e.data.count || 0;
      if (detectActive && pendingDetectScanId && detectCount === 0) {
        showToast(DETECT_EMPTY_MESSAGE, 3200);
      }
      pendingDetectScanId = null;
      updateGlobalBarState();
    }
  }

  /** Full teardown: remove all UI, disconnect SSE, clean up. */
  function teardown() {
    stopAgentStatusPoll();
    hideAgentPollTooltip();
    if (agentPollTooltipEl) {
      agentPollTooltipEl.remove();
      agentPollTooltipEl = null;
    }
    stopVoice({ suppressSubmit: true });
    clearSteerFocusRecoverTimer();
    steerFocusSuspended = false;
    steerFocusPauseUntil = 0;
    pagePointerGesture = null;
    pagePickSkipClick = false;
    cleanup();
    hideBar();
    if (pendingDockResizeObserver) { pendingDockResizeObserver.disconnect(); pendingDockResizeObserver = null; }
    window.removeEventListener('resize', positionPendingDock);
    if (pendingIntroAnimation) { pendingIntroAnimation.cancel(); pendingIntroAnimation = null; }
    if (pendingDockEl) {
      pendingDockEl.remove();
      pendingDockEl = null;
      pendingPillEl = null;
      pendingPillSpinnerEl = null;
      pendingPillLabelEl = null;
      pendingPillCountEl = null;
      pendingTrashBtn = null;
      pendingKeepFixingBtn = null;
      pendingRollbackBtn = null;
      pendingApplyInFlight = false;
    }
    if (globalBarEl) {
      globalBarEl.style.transition = 'none';
      globalBarEl.remove();
      globalBarEl = null;
    }
    pageChatEl = null;
    pageChatInput = null;
    pageChatHint = null;
    pageChatVoiceBtn = null;
    pageChatExpanded = false;
    if (insertCreateTooltipEl) { insertCreateTooltipEl.remove(); insertCreateTooltipEl = null; }
    if (configureBarTooltipEl) { configureBarTooltipEl.remove(); configureBarTooltipEl = null; }
    if (highlightEl) { highlightEl.remove(); highlightEl = null; }
    if (tooltipEl) { tooltipEl.remove(); tooltipEl = null; }
    if (barEl) { barEl.remove(); barEl = null; }
    if (pickerEl) { pickerEl.remove(); pickerEl = null; }
    if (paramsPanelEl) { paramsPanelEl.remove(); paramsPanelEl = null; paramsPanelInner = null; paramsPanelBody = null; }
    if (editBadgeProxyRoot) { editBadgeProxyRoot.remove(); editBadgeProxyRoot = null; editBadgeProxyByTarget = new Map(); }
    if (evtSource) { evtSource.close(); evtSource = null; }
    document.removeEventListener('mousemove', handleMouseMove, true);
    document.removeEventListener('click', handleClick, true);
    document.removeEventListener('keydown', handleKeyDown, true);
    window.removeEventListener('message', onDetectMessage);
    // Remove detection overlays
    window.postMessage({ source: 'impeccable-command', action: 'remove' }, '*');
    setLiveState('IDLE');
    document.getElementById(PICK_CURSOR_STYLE_ID)?.remove();
    removeVariantStateStylesheet();
    window.__IMPECCABLE_LIVE_INIT__ = false;
    console.log('[impeccable] Live mode exited.');
  }

  //
  // Design System Panel - visualizes the project's .impeccable/design.json sidecar
  //

  const DESIGN_PREFS_KEY = 'impeccable-live-design-panel';
  const DESIGN_PANEL_WIDTH = 440;

  let designHost = null;
  let designShadow = null;
  let designState = {
    open: false,
    tab: 'visual',          // 'visual' | 'raw'
    parsed: null,           // parseDesignMd output (frontmatter + body sections)
    sidecar: null,          // .impeccable/design.json v2 payload (extensions + components + narrative)
    hasMd: false,
    hasSidecar: false,
    present: null,          // true/false once fetch resolves
    raw: null,              // raw DESIGN.md for the raw tab
    mdNewerThanJson: false, // stale-hint flag
    loading: false,
    error: null,
    collapsed: {            // narrative-section accordion state
      rules: true, dosdonts: true, overview: true,
    },
  };

  function loadDesignPrefs() {
    // `open` is intentionally NOT persisted - the panel always starts closed
    // so live mode doesn't auto-slide a big panel over the page on startup.
    try {
      const raw = localStorage.getItem(DESIGN_PREFS_KEY);
      if (!raw) return;
      const prefs = JSON.parse(raw);
      if (prefs.tab === 'visual' || prefs.tab === 'raw') designState.tab = prefs.tab;
      if (prefs.collapsed && typeof prefs.collapsed === 'object') {
        Object.assign(designState.collapsed, prefs.collapsed);
      }
    } catch { /* ignore */ }
  }

  function saveDesignPrefs() {
    try {
      localStorage.setItem(DESIGN_PREFS_KEY, JSON.stringify({
        tab: designState.tab,
        collapsed: designState.collapsed,
      }));
    } catch { /* ignore */ }
  }

  function initDesignPanel() {
    designHost = document.createElement('div');
    designHost.id = PREFIX + '-design-host';
    Object.assign(designHost.style, {
      position: 'fixed', top: '0', left: '0',
      width: '0', height: '0',
      zIndex: String(Z.bar + 10),
      pointerEvents: 'none',
    });
    designShadow = designHost.attachShadow({ mode: 'open' });

    const style = document.createElement('style');
    // Theme-match the bar: dark chrome on light pages, light chrome on dark pages.
    const theme = detectPageTheme();
    style.textContent = designPanelCss(barPaletteForTheme(theme));
    designShadow.appendChild(style);

    const root = document.createElement('div');
    root.className = 'root';
    designShadow.appendChild(root);

    uiAppend(designHost);
    // The host is pointer-events: none; the panel inside the shadow DOM
    // manages its own auto/none. Events bubble through the shadow boundary,
    // so attaching here silences host-page outside-interaction handlers
    // without touching the host's click-through behavior.
    defangOutsideHandlers(designHost, { setPointerEvents: false });

    loadDesignPrefs();
    renderDesignChrome();
    if (designState.open) {
      fetchDesignSystem();
    }
  }

  // Neutral panel palette - deliberately NOT Impeccable-branded. The panel is
  // a viewer of the project's design system, not an Impeccable surface.
  const DP = {
    canvas:   'oklch(94% 0 0)',            // panel background
    tile:     'oklch(98.5% 0 0)',          // card-on-canvas
    tileAlt:  'oklch(96% 0 0)',            // subtler tile for inner surfaces
    ink:      'oklch(15% 0 0)',
    ink2:     'oklch(35% 0 0)',
    meta:     'oklch(55% 0 0)',
    hairline: 'oklch(88% 0 0)',
    hairlineSoft: 'oklch(92% 0 0)',
    amber:    'oklch(77% 0.13 82)',         // stale-hint accent
    amberBg:  'oklch(89% 0.055 84)',
  };

  function designPanelCss(BP) {
    // BP = bar palette (theme-aware, matches the global bar).
    // DP = internal content palette (neutral, so tiles render colors true).
    return `
      :host, .root { all: initial; }
      .root {
        font-family: ${FONT};
        color: ${DP.ink};
        pointer-events: none;
      }
      .root * { box-sizing: border-box; }
      button { font: inherit; color: inherit; }

      /* Panel shell: chrome matches the bar; body canvas stays neutral */
      .panel {
        position: fixed; top: 12px; bottom: 72px; right: 12px;
        width: ${DESIGN_PANEL_WIDTH}px; max-width: calc(100vw - 24px);
        background: ${BP.surface};
        border: 1.5px solid ${BP.border};
        border-radius: 14px;
        box-shadow: ${BP.shadow};
        display: flex; flex-direction: column;
        transform: translateX(calc(100% + 24px));
        opacity: 0;
        transition: transform 0.35s ${EASE}, opacity 0.25s ${EASE};
        pointer-events: none;
        overflow: hidden;
      }
      .panel[data-open="true"] { transform: translateX(0); opacity: 1; pointer-events: auto; }

      .panel-header {
        display: flex; align-items: center; gap: 10px;
        padding: 10px 10px 10px 14px;
        background: transparent;
        border-bottom: 1px solid ${BP.hairline};
      }
      .panel-title {
        flex: 1; min-width: 0;
        font-family: ${MONO};
        font-size: 11.5px; font-weight: 600;
        letter-spacing: 0.02em;
        color: ${BP.text};
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
      }
      .panel-close {
        border: none; background: transparent; color: ${BP.textDim};
        width: 26px; height: 26px; border-radius: 7px;
        display: inline-flex; align-items: center; justify-content: center;
        cursor: pointer; transition: background 0.15s ease, color 0.15s ease;
      }
      .panel-close:hover { background: ${BP.hairline}; color: ${BP.text}; }

      .tabs {
        display: inline-flex; padding: 2px;
        background: ${BP.hairline};
        border-radius: 7px;
        gap: 2px;
      }
      .tab {
        border: none; background: transparent;
        padding: 4px 10px; border-radius: 5px;
        font-family: ${MONO};
        font-size: 10px; font-weight: 600; letter-spacing: 0.08em;
        text-transform: uppercase;
        color: ${BP.textDim}; cursor: pointer;
        transition: background 0.15s ease, color 0.15s ease;
      }
      .tab[data-active="true"] { background: ${BP.surface}; color: ${BP.text}; }

      .panel-body {
        flex: 1; overflow-y: auto;
        padding: 12px 12px 20px;
        background: ${DP.canvas};
        scrollbar-width: thin;
        scrollbar-color: ${DP.hairline} transparent;
      }
      .panel-body::-webkit-scrollbar { width: 8px; }
      .panel-body::-webkit-scrollbar-thumb { background: ${DP.hairline}; border-radius: 8px; border: 2px solid transparent; background-clip: padding-box; }

      /* States */
      .empty, .loading, .error {
        margin: 16px 4px;
        padding: 28px 20px; text-align: center;
        background: ${DP.tile}; border-radius: 14px;
        color: ${DP.ink2}; font-size: 13px; line-height: 1.55;
      }
      .empty strong { color: ${DP.ink}; display: block; margin-bottom: 6px; font-size: 14px; }
      .empty code { font-family: ${MONO}; background: ${DP.canvas}; padding: 1px 6px; border-radius: 4px; font-size: 12px; color: ${DP.ink}; }
      .error { color: oklch(58% 0.15 35); }

      /* Stale hint */
      .stale {
        display: flex; align-items: center; gap: 8px;
        margin: 8px 4px 12px;
        padding: 8px 12px;
        background: ${DP.amberBg};
        border-radius: 10px;
        font-size: 11.5px; color: ${DP.ink2};
      }
      .stale-dot { width: 8px; height: 8px; border-radius: 50%; background: ${DP.amber}; flex-shrink: 0; }
      .stale-text { flex: 1; min-width: 0; }
      .stale-text strong { color: ${DP.ink}; font-weight: 600; }

      /* Parsed-md fallback banner */
      .parsed-md-cta {
        margin: 8px 4px 14px;
        padding: 14px 16px;
        background: ${DP.tile};
        border: 1px dashed ${DP.hairline};
        border-radius: 12px;
        font-size: 12px; color: ${DP.ink2}; line-height: 1.55;
      }
      .parsed-md-cta strong { color: ${DP.ink}; display: block; margin-bottom: 4px; font-size: 13px; font-weight: 600; }
      .parsed-md-cta code { font-family: ${MONO}; background: ${DP.canvas}; padding: 1px 5px; border-radius: 4px; font-size: 11.5px; color: ${DP.ink}; }

      /* Tile primitives */
      .tile {
        position: relative;
        background: ${DP.tile};
        border-radius: 16px;
        padding: 16px;
        margin: 0 4px 10px;
      }
      .tile-row { margin: 0 4px 10px; display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
      .tile-row .tile { margin: 0; }
      .tile-meta {
        display: flex; align-items: baseline; justify-content: space-between;
        gap: 10px;
        font-family: ${MONO};
        font-size: 10px; font-weight: 500; letter-spacing: 0.1em; text-transform: uppercase;
        color: ${DP.meta};
      }
      .tile-meta .name { color: ${DP.ink}; font-weight: 600; letter-spacing: 0.05em; text-transform: none; font-family: ${FONT}; font-size: 12.5px; }

      /* Color tile */
      .c-tile { cursor: pointer; transition: transform 0.2s ${EASE}; }
      .c-tile:hover { transform: translateY(-1px); }
      .c-hero {
        height: 72px; border-radius: 10px; margin-top: 10px;
        box-shadow: inset 0 0 0 1px oklch(0% 0 0 / 0.05);
      }
      .c-ramp {
        display: flex; gap: 0; height: 14px; border-radius: 4px; overflow: hidden;
        margin-top: 8px;
        box-shadow: inset 0 0 0 1px oklch(0% 0 0 / 0.04);
      }
      .c-ramp > span { flex: 1; }
      .c-desc { margin-top: 8px; font-size: 11.5px; line-height: 1.45; color: ${DP.ink2}; }

      /* Type tile */
      .t-tile { }
      .t-specimen {
        margin: 4px 0 6px;
        color: ${DP.ink};
        line-height: 0.9;
      }
      .t-family { margin-top: 4px; font-size: 12px; font-weight: 600; color: ${DP.ink}; }
      .t-purpose { margin-top: 4px; font-size: 11px; line-height: 1.45; color: ${DP.ink2}; }

      /* Shadow tile */
      .s-tile { }
      .s-surface {
        height: 60px; margin: 8px 2px 10px;
        background: ${DP.tile};
        border-radius: 10px;
      }
      .s-value { font-family: ${MONO}; font-size: 10px; color: ${DP.meta}; word-break: break-all; line-height: 1.4; }
      .s-purpose { margin-top: 4px; font-size: 11px; color: ${DP.ink2}; line-height: 1.45; }

      /* Radii strip */
      .r-strip { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 10px; }
      .r-item { display: flex; flex-direction: column; align-items: center; gap: 4px; flex: 1; min-width: 60px; }
      .r-sample { width: 44px; height: 44px; background: ${DP.canvas}; box-shadow: inset 0 0 0 1px oklch(0% 0 0 / 0.08); }
      .r-label { font-family: ${MONO}; font-size: 10px; color: ${DP.meta}; letter-spacing: 0.05em; text-transform: uppercase; }
      .r-val { font-family: ${MONO}; font-size: 10px; color: ${DP.ink}; }

      /* Component tile (hosts live primitives) */
      .cmp-tile { }
      .cmp-stage {
        margin: 12px -4px 0;
        padding: 18px 16px 10px;
        border-top: 1px solid ${DP.hairlineSoft};
        display: flex; flex-direction: column; align-items: center; justify-content: center;
        gap: 14px;
        min-height: 68px;
      }
      .cmp-stage + .cmp-stage { border-top: 1px dashed ${DP.hairlineSoft}; }
      .cmp-sublabel { font-family: ${MONO}; font-size: 10px; color: ${DP.meta}; letter-spacing: 0.06em; }
      .cmp-kind { font-family: ${MONO}; font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: ${DP.meta}; }

      /* Collapsible */
      .coll {
        margin: 0 4px 8px;
        background: ${DP.tile};
        border-radius: 12px;
        overflow: hidden;
      }
      .coll-head {
        display: flex; align-items: center; gap: 10px;
        width: 100%;
        padding: 12px 14px;
        background: transparent; border: none;
        cursor: pointer; text-align: left;
        font-family: ${FONT}; font-size: 12.5px; font-weight: 600; color: ${DP.ink};
        transition: background 0.12s ease;
      }
      .coll-head:hover { background: ${DP.tileAlt}; }
      .coll-chev {
        width: 12px; height: 12px; flex-shrink: 0;
        color: ${DP.meta};
        transition: transform 0.2s ${EASE};
      }
      .coll[data-open="true"] .coll-chev { transform: rotate(90deg); }
      .coll-count { margin-left: auto; font-family: ${MONO}; font-size: 10px; color: ${DP.meta}; letter-spacing: 0.05em; }
      .coll-body { padding: 0 14px 14px; display: none; }
      .coll[data-open="true"] .coll-body { display: block; }

      .rule-card {
        padding: 10px 0;
        border-top: 1px solid ${DP.hairlineSoft};
      }
      .rule-card:first-child { border-top: none; padding-top: 2px; }
      .rule-card .name { font-size: 11.5px; font-weight: 700; color: ${DP.ink}; margin-bottom: 3px; }
      .rule-card .name .section { font-family: ${MONO}; font-size: 9px; font-weight: 500; letter-spacing: 0.1em; text-transform: uppercase; color: ${DP.meta}; margin-left: 8px; }
      .rule-card .body { font-size: 11.5px; color: ${DP.ink2}; line-height: 1.5; }

      .coll .dos { display: grid; gap: 0; margin-top: 2px; }
      .coll .do, .coll .dont {
        position: relative;
        padding: 8px 0 8px 22px;
        font-size: 11.5px; line-height: 1.5; color: ${DP.ink2};
        border-top: 1px solid ${DP.hairlineSoft};
      }
      .coll .do:first-child, .coll .dont:first-child,
      .coll .do:first-of-type { border-top: none; }
      .coll .do + .dont { border-top: 1px solid ${DP.hairlineSoft}; }
      .coll .do::before, .coll .dont::before {
        content: ''; position: absolute; left: 4px; top: 13px;
        width: 8px; height: 8px; border-radius: 50%;
      }
      .coll .do::before { background: oklch(45% 0.18 145); }
      .coll .dont::before { background: oklch(58% 0.15 35); }

      .coll .overview-body {
        font-size: 12px; line-height: 1.55; color: ${DP.ink2};
      }
      .coll .overview-body .north-star {
        display: block; font-family: ${FONT}; font-style: italic;
        font-size: 15px; line-height: 1.3; color: ${DP.ink};
        margin-bottom: 8px;
      }
      .coll .overview-body p { margin: 0 0 8px; }
      .coll .overview-body ul { margin: 6px 0 0; padding-left: 16px; font-size: 11.5px; }
      .coll .overview-body li { margin-bottom: 3px; }

      /* raw tab markdown (unchanged layout, neutralized palette) */
      .md { padding: 4px 10px 20px; font-size: 13px; line-height: 1.6; color: ${DP.ink}; }
      .md h1, .md h2, .md h3, .md h4 { margin: 20px 0 8px; color: ${DP.ink}; font-weight: 600; }
      .md h1 { font-size: 18px; }
      .md h2 { font-size: 15px; padding-bottom: 4px; border-bottom: 1px solid ${DP.hairlineSoft}; }
      .md h3 { font-size: 13px; }
      .md h4 { font-size: 12px; color: ${DP.meta}; }
      .md p { margin: 0 0 10px; }
      .md ul, .md ol { margin: 0 0 10px; padding-left: 20px; }
      .md li { margin-bottom: 4px; }
      .md code { font-family: ${MONO}; font-size: 12px; background: ${DP.canvas}; padding: 1px 5px; border-radius: 4px; }
      .md pre { font-family: ${MONO}; font-size: 12px; background: ${DP.canvas}; padding: 10px 12px; border-radius: 8px; overflow-x: auto; margin: 0 0 10px; }
      .md pre code { background: none; padding: 0; }
      .md strong { font-weight: 700; }
      .md em { font-style: italic; }
      .md a { color: ${DP.ink}; text-decoration: underline; }
      .md hr { border: none; border-top: 1px solid ${DP.hairlineSoft}; margin: 16px 0; }
    `;
  }

  function renderDesignChrome() {
    const root = designShadow.querySelector('.root');
    root.innerHTML = '';

    // (Panel toggle lives in the global bar - no floating FAB.)
    // Panel
    const panel = document.createElement('aside');
    panel.className = 'panel';
    panel.setAttribute('data-open', designState.open ? 'true' : 'false');
    panel.appendChild(buildDesignHeader());
    const body = document.createElement('div');
    body.className = 'panel-body';
    body.id = 'panel-body';
    panel.appendChild(body);
    root.appendChild(panel);

    renderDesignBody();
  }

  function buildDesignHeader() {
    const header = document.createElement('div');
    header.className = 'panel-header';

    const title = document.createElement('div');
    title.className = 'panel-title';
    title.textContent = 'DESIGN.md';
    header.appendChild(title);

    const tabs = document.createElement('div');
    tabs.className = 'tabs';
    for (const t of [['visual', 'Visual'], ['raw', 'Raw']]) {
      const btn = document.createElement('button');
      btn.className = 'tab';
      btn.textContent = t[1];
      btn.setAttribute('data-active', designState.tab === t[0] ? 'true' : 'false');
      btn.addEventListener('click', () => {
        if (designState.tab === t[0]) return;
        designState.tab = t[0];
        saveDesignPrefs();
        renderDesignChrome();
        if (t[0] === 'raw' && designState.raw === null && !designState.loading) {
          fetchDesignSystem(); // raw is part of the same fetch pair
        }
      });
      tabs.appendChild(btn);
    }
    header.appendChild(tabs);

    const close = document.createElement('button');
    close.className = 'panel-close';
    close.innerHTML = '&#x2715;';
    close.setAttribute('aria-label', 'Close panel');
    close.addEventListener('click', toggleDesignPanel);
    header.appendChild(close);

    return header;
  }

  function toggleDesignPanel() {
    if (pendingApplyInFlight) { showManualApplyBusyToast(); return; }
    designState.open = !designState.open;
    renderDesignChrome();
    updateGlobalBarState();
    if (designState.open && designState.present === null && !designState.loading) {
      fetchDesignSystem();
    }
  }

  async function fetchDesignSystem() {
    designState.loading = true;
    designState.error = null;
    renderDesignBody();
    try {
      const [jsonRes, rawRes] = await Promise.all([
        fetch(`http://localhost:${PORT}/design-system.json?token=${TOKEN}`, { cache: 'no-store' }),
        fetch(`http://localhost:${PORT}/design-system/raw?token=${TOKEN}`, { cache: 'no-store' }),
      ]);
      const jsonData = await jsonRes.json();
      designState.present = jsonData.present === true;
      designState.parsed = jsonData.parsed || null;
      designState.sidecar = jsonData.sidecar || null;
      designState.hasMd = !!jsonData.hasMd;
      designState.hasSidecar = !!jsonData.hasSidecar;
      designState.mdNewerThanJson = !!jsonData.mdNewerThanJson;
      designState.raw = designState.present && rawRes.ok ? await rawRes.text() : null;
      designState.error = jsonData.parseError || jsonData.sidecarError || null;
    } catch (err) {
      designState.error = err?.message || 'Failed to load design system.';
    } finally {
      designState.loading = false;
      renderDesignChrome(); // refresh title from data
    }
  }

  function renderDesignBody() {
    const body = designShadow.querySelector('#panel-body');
    if (!body) return;
    body.innerHTML = '';

    if (designState.loading) {
      body.appendChild(msgDiv('loading', 'Loading design system…'));
      return;
    }
    if (designState.error) {
      body.appendChild(msgDiv('error', designState.error));
      return;
    }
    if (designState.present === false) {
      const empty = document.createElement('div');
      empty.className = 'empty';
      empty.innerHTML = `<strong>No DESIGN.md yet</strong>Create one by running <code>${IMPECCABLE_COMMAND} document</code> in your terminal, then re-open this panel.`;
      body.appendChild(empty);
      return;
    }

    if (designState.tab === 'raw') {
      renderRawTab(body, designState.raw || '');
      return;
    }

    // Visual tab - single unified render path.
    if (designState.mdNewerThanJson) body.appendChild(renderStaleHint());
    if (designState.hasMd && !designState.hasSidecar) {
      body.appendChild(renderParsedMdCta());
    }
    renderDesignVisual(body, designState.parsed, designState.sidecar);
  }

  function msgDiv(cls, text) {
    const d = document.createElement('div');
    d.className = cls;
    d.textContent = text;
    return d;
  }

  function renderStaleHint() {
    const box = document.createElement('div');
    box.className = 'stale';
    box.innerHTML = `
      <span class="stale-dot"></span>
      <span class="stale-text"><strong>DESIGN.md is newer than .impeccable/design.json.</strong> Run <code>${IMPECCABLE_COMMAND} document</code> to refresh the sidecar.</span>
    `;
    return box;
  }

  function renderParsedMdCta() {
    const box = document.createElement('div');
    box.className = 'parsed-md-cta';
    box.innerHTML = `<strong>Basic view</strong>This panel reads the tokens in your <code>DESIGN.md</code> frontmatter. Running <code>${IMPECCABLE_COMMAND} document</code> also generates a <code>.impeccable/design.json</code> sidecar with your project's actual component snippets (button, input, nav) and tonal ramps, rendered live below the tokens.`;
    return box;
  }

  // Unified render: merge parsed DESIGN.md frontmatter with sidecar v2

  /**
   * The empty state has to say which emptiness it is. `present:false` (no
   * DESIGN.md at all) is handled upstream in renderDesignBody; everything here
   * means the helper found a design system and this panel found nothing in it
   * worth drawing. Telling that user "no design system data" reads as "your
   * DESIGN.md is missing" and sends them to write a file they already have.
   */
  function designEmptyMessage() {
    if (designState.hasMd && !designState.hasSidecar) {
      return 'DESIGN.md found, no structured tokens to display. Run ' + IMPECCABLE_COMMAND + ' document to generate the .impeccable/design.json sidecar.';
    }
    if (designState.hasMd) {
      return 'DESIGN.md and its sidecar were found, but neither carries colors, type, radii, or components to display.';
    }
    return 'No design system data available.';
  }

  function renderDesignVisual(body, parsed, sidecar) {
    // Count only what this function draws: renderDesignBody may already have
    // appended a stale-sidecar hint or the basic-view CTA, and those must not
    // pass for token content.
    const beforeCount = body.childElementCount;
    const frontmatter = parsed?.frontmatter || {};
    const extensions = sidecar?.extensions || {};
    const proseColors = parsed?.colors || null;

    const colors = buildColorModels(frontmatter.colors, extensions.colorMeta, proseColors);
    if (colors.length) renderColorTiles(body, colors);

    const types = buildTypographyModels(frontmatter.typography, extensions.typographyMeta);
    if (types.length) renderTypeTiles(body, types);

    const radii = buildRadiiModels(frontmatter.rounded);
    if (radii.length) renderRadiiTile(body, radii);

    if (extensions.shadows?.length) renderShadowTiles(body, extensions.shadows);

    const components = sidecar?.components || [];
    if (components.length) renderComponentTiles(body, components);

    // Narrative: sidecar wins if present (richer, agent-curated). Otherwise
    // synthesize from prose sections.
    const narrative = sidecar?.narrative || synthesizeNarrative(parsed);
    if (narrative.rules?.length) body.appendChild(renderRulesCollapsible(narrative.rules));
    if ((narrative.dos?.length || narrative.donts?.length)) body.appendChild(renderDosDontsCollapsible(narrative));
    if (narrative.overview || narrative.northStar || narrative.keyCharacteristics?.length) {
      body.appendChild(renderOverviewCollapsible(narrative));
    }

    if (body.childElementCount === beforeCount) {
      body.appendChild(msgDiv('empty', designEmptyMessage()));
    }
  }

  // Frontmatter primitives + sidecar colorMeta → tile-ready color models.
  // A matching prose bullet (when the slug sits in the bullet text) supplies
  // description as a last-resort fallback.
  function buildColorModels(fmColors, colorMeta, proseColors) {
    if (!fmColors) return [];
    const meta = colorMeta || {};
    return Object.entries(fmColors).map(([key, value]) => {
      const m = meta[key] || {};
      return {
        role: m.role || humanizeKey(key),
        name: m.displayName || humanizeKey(key),
        value: normalizeCssColor(m.canonical || value),
        canonical: m.canonical || null,
        description: m.description || findProseDescription(proseColors, key, m.displayName),
        tonalRamp: m.tonalRamp || null,
      };
    });
  }

  function buildTypographyModels(fmTypography, typographyMeta) {
    if (!fmTypography) return [];
    const meta = typographyMeta || {};
    return Object.entries(fmTypography).map(([key, spec]) => {
      const m = meta[key] || {};
      const { family, fallback } = splitFontFamily(spec?.fontFamily);
      return {
        role: key,
        name: m.displayName || humanizeKey(key),
        family,
        fallback,
        weight: spec?.fontWeight ?? 400,
        // fontStyle isn't in Stitch's frontmatter schema; the sidecar carries
        // it when a role is rendered in italic (e.g. display italic).
        style: m.style || 'normal',
        sampleSize: spec?.fontSize || '1rem',
        lineHeight: spec?.lineHeight != null ? String(spec.lineHeight) : '',
        letterSpacing: spec?.letterSpacing,
        purpose: m.purpose,
      };
    });
  }

  function buildRadiiModels(fmRounded) {
    if (!fmRounded) return [];
    return Object.entries(fmRounded).map(([name, value]) => ({ name, value }));
  }

  function splitFontFamily(stack) {
    if (!stack || typeof stack !== 'string') return { family: '', fallback: '' };
    const parts = stack.split(',').map((s) => s.trim().replace(/^['"]|['"]$/g, ''));
    return { family: parts[0] || '', fallback: parts.slice(1).join(', ') };
  }

  function humanizeKey(k) {
    return String(k || '').replace(/[-_]+/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
  }

  function findProseDescription(proseColors, key, displayName) {
    if (!proseColors || !proseColors.groups) return null;
    const needles = [key, displayName].filter(Boolean).map((s) => s.toLowerCase());
    for (const g of proseColors.groups) {
      for (const c of g.colors || []) {
        const hay = String(c.name || '').toLowerCase();
        if (hay && needles.some((n) => hay.includes(n) || n.includes(hay))) {
          return c.description || null;
        }
      }
    }
    return null;
  }

  function synthesizeNarrative(parsed) {
    if (!parsed) return {};
    const md = parsed;
    return {
      northStar: md.overview?.creativeNorthStar,
      overview: (md.overview?.philosophy || []).join(' '),
      keyCharacteristics: md.overview?.keyCharacteristics || [],
      rules: [
        ...(md.colors?.rules || []).map((r) => ({ ...r, section: 'colors' })),
        ...(md.typography?.rules || []).map((r) => ({ ...r, section: 'typography' })),
        ...(md.layout?.rules || []).map((r) => ({ ...r, section: 'layout' })),
        ...(md.elevation?.rules || []).map((r) => ({ ...r, section: 'elevation' })),
        ...(md.shapes?.rules || []).map((r) => ({ ...r, section: 'shapes' })),
      ],
      dos: md.dosDonts?.dos || [],
      donts: md.dosDonts?.donts || [],
    };
  }

  function renderColorTiles(body, colors) {
    for (const c of colors) {
      const tile = document.createElement('div');
      tile.className = 'tile c-tile';
      tile.title = 'Click to copy';
      tile.addEventListener('click', () => copyToClipboard(c.value));

      const meta = document.createElement('div');
      meta.className = 'tile-meta';
      meta.innerHTML = `<span class="name">${escapeHtml(c.name || c.role || 'Color')}</span><span>${escapeHtml(c.value || '')}</span>`;
      tile.appendChild(meta);

      const hero = document.createElement('div');
      hero.className = 'c-hero';
      hero.style.background = cssSafe(c.value || '');
      tile.appendChild(hero);

      const ramp = synthesizeRamp(c);
      if (ramp.length) {
        const r = document.createElement('div');
        r.className = 'c-ramp';
        r.innerHTML = ramp.map((v) => `<span style="background:${cssSafe(v)}"></span>`).join('');
        tile.appendChild(r);
      }

      if (c.description) {
        const d = document.createElement('div');
        d.className = 'c-desc';
        d.textContent = c.description;
        tile.appendChild(d);
      }
      body.appendChild(tile);
    }
  }

  function synthesizeRamp(c) {
    if (c.tonalRamp?.length) return c.tonalRamp;
    // If base value is OKLCH, synthesize an 8-step ramp across lightness.
    const m = typeof c.value === 'string' && c.value.match(/^oklch\(\s*([\d.]+)%\s+([\d.]+)\s+([\d.]+)\s*(?:\/\s*([\d.]+))?\s*\)$/i);
    if (!m) return [];
    const [, , chroma, hue] = m;
    const steps = [20, 32, 44, 56, 68, 80, 90, 96];
    return steps.map((l) => `oklch(${l}% ${chroma} ${hue})`);
  }

  function renderTypeTiles(body, types) {
    for (const t of types) {
      const tile = document.createElement('div');
      tile.className = 'tile t-tile';

      const meta = document.createElement('div');
      meta.className = 'tile-meta';
      meta.innerHTML = `<span>${escapeHtml(t.role || '')}</span><span>${escapeHtml(t.weight || '')} ${escapeHtml(t.style === 'italic' ? 'italic' : '')}</span>`;
      tile.appendChild(meta);

      const specimen = document.createElement('div');
      specimen.className = 't-specimen';
      specimen.textContent = 'Aa';
      specimen.style.fontFamily = fontStack(t);
      specimen.style.fontWeight = String(t.weight || 400);
      specimen.style.fontStyle = t.style || 'normal';
      specimen.style.fontSize = '56px';  // Fixed specimen size - compare faces, not scales.
      specimen.style.letterSpacing = 'normal';
      specimen.style.textTransform = 'none';
      tile.appendChild(specimen);

      // The system's actual sample size for this role, shown as small mono meta below.
      if (t.sampleSize) {
        const scale = document.createElement('div');
        scale.style.cssText = 'font-family:' + MONO + '; font-size: 10px; color:' + DP.meta + '; margin-top: 2px;';
        scale.textContent = t.sampleSize;
        tile.appendChild(scale);
      }

      const family = document.createElement('div');
      family.className = 't-family';
      family.textContent = t.family || t.name || '';
      tile.appendChild(family);

      if (t.purpose) {
        const p = document.createElement('div');
        p.className = 't-purpose';
        p.textContent = t.purpose;
        tile.appendChild(p);
      }
      body.appendChild(tile);
    }
  }

  function fontStack(t) {
    const fam = t.family || '';
    const fb = t.fallback || '';
    if (fam && /[,\s]/.test(fam) && !fam.includes("'") && !fam.includes('"')) {
      return `"${fam}", ${fb}`;
    }
    return fam && fb ? `"${fam}", ${fb}` : (fam || fb);
  }

  function renderRadiiTile(body, radii) {
    const tile = document.createElement('div');
    tile.className = 'tile';
    const meta = document.createElement('div');
    meta.className = 'tile-meta';
    meta.innerHTML = `<span class="name">Corner Radii</span><span>${radii.length}</span>`;
    tile.appendChild(meta);

    const strip = document.createElement('div');
    strip.className = 'r-strip';
    for (const r of radii) {
      const item = document.createElement('div');
      item.className = 'r-item';
      const s = document.createElement('div');
      s.className = 'r-sample';
      s.style.borderRadius = r.value || '0';
      item.appendChild(s);
      const lbl = document.createElement('div');
      lbl.className = 'r-label';
      lbl.textContent = r.name || '';
      item.appendChild(lbl);
      const val = document.createElement('div');
      val.className = 'r-val';
      val.textContent = r.value || '';
      item.appendChild(val);
      strip.appendChild(item);
    }
    tile.appendChild(strip);
    body.appendChild(tile);
  }

  function renderShadowTiles(body, shadows) {
    for (const sh of shadows) {
      const tile = document.createElement('div');
      tile.className = 'tile s-tile';

      const meta = document.createElement('div');
      meta.className = 'tile-meta';
      meta.innerHTML = `<span class="name">${escapeHtml(sh.name || 'Shadow')}</span><span>Elevation</span>`;
      tile.appendChild(meta);

      const surface = document.createElement('div');
      surface.className = 's-surface';
      surface.style.boxShadow = sh.value || 'none';
      tile.appendChild(surface);

      const val = document.createElement('div');
      val.className = 's-value';
      val.textContent = sh.value || '';
      tile.appendChild(val);

      if (sh.purpose) {
        const p = document.createElement('div');
        p.className = 's-purpose';
        p.textContent = sh.purpose;
        tile.appendChild(p);
      }
      body.appendChild(tile);
    }
  }

  function renderComponentTiles(body, components) {
    // Group consecutive components that share a kind into one tile. This avoids
    // a pile of one-component tiles (e.g., three button variants = three tiles)
    // and reads more like a proper category.
    const groups = groupByKind(components);

    for (const group of groups) {
      const tile = document.createElement('div');
      tile.className = 'tile cmp-tile';

      const meta = document.createElement('div');
      meta.className = 'tile-meta';
      const groupTitle = group.length === 1
        ? (group[0].name || group[0].kind || 'Component')
        : titleForKind(group[0].kind, group.length);
      meta.innerHTML = `<span class="name">${escapeHtml(groupTitle)}</span><span class="cmp-kind">${escapeHtml(group[0].kind || '')}</span>`;
      tile.appendChild(meta);

      for (const c of group) {
        const stage = document.createElement('div');
        stage.className = 'cmp-stage';

        // Render the component in its own shadow root so its CSS can't bleed.
        const host = document.createElement('div');
        const sub = host.attachShadow({ mode: 'open' });
        const style = document.createElement('style');
        style.textContent = c.css || '';
        sub.appendChild(style);
        const container = document.createElement('div');
        container.innerHTML = c.html || '';
        sub.appendChild(container);
        stage.appendChild(host);

        // Show component name as a sublabel only when the tile groups >1 item,
        // or when the component's display name differs from its kind.
        const showSublabel = group.length > 1;
        if (showSublabel) {
          const lbl = document.createElement('div');
          lbl.className = 'cmp-sublabel';
          lbl.textContent = c.name || '';
          stage.appendChild(lbl);
        }
        tile.appendChild(stage);
      }

      // Single shared description if all items carry the same one; otherwise
      // skip - per-item descriptions clutter a grouped tile.
      if (group.length === 1 && group[0].description) {
        const d = document.createElement('div');
        d.className = 'c-desc';
        d.textContent = group[0].description;
        tile.appendChild(d);
      }
      body.appendChild(tile);
    }
  }

  function groupByKind(components) {
    const groups = [];
    for (const c of components) {
      const last = groups[groups.length - 1];
      if (last && last[0].kind && c.kind === last[0].kind) {
        last.push(c);
      } else {
        groups.push([c]);
      }
    }
    return groups;
  }

  function titleForKind(kind, count) {
    const labels = {
      button: 'Buttons',
      input: 'Inputs',
      nav: 'Navigation',
      chip: 'Chips',
      card: 'Cards',
      custom: 'Components',
    };
    return labels[kind] || (kind ? kind.charAt(0).toUpperCase() + kind.slice(1) + 's' : 'Components');
  }

  // Collapsibles.

  function buildCollapsible(key, label, count) {
    const wrap = document.createElement('div');
    wrap.className = 'coll';
    wrap.setAttribute('data-open', designState.collapsed[key] ? 'false' : 'true');

    const head = document.createElement('button');
    head.className = 'coll-head';
    head.innerHTML = `
      <svg class="coll-chev" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M4 2.5L8 6 4 9.5"/></svg>
      <span>${escapeHtml(label)}</span>
      ${count != null ? `<span class="coll-count">${escapeHtml(String(count))}</span>` : ''}
    `;
    head.addEventListener('click', () => {
      designState.collapsed[key] = !designState.collapsed[key];
      saveDesignPrefs();
      renderDesignBody();
    });
    wrap.appendChild(head);

    const body = document.createElement('div');
    body.className = 'coll-body';
    wrap.appendChild(body);
    return { wrap, body };
  }

  function renderRulesCollapsible(rules) {
    const { wrap, body } = buildCollapsible('rules', 'Named Rules', rules.length);
    for (const r of rules) {
      const card = document.createElement('div');
      card.className = 'rule-card';
      const name = document.createElement('div');
      name.className = 'name';
      name.innerHTML = `${escapeHtml(r.name)}${r.section ? `<span class="section">${escapeHtml(r.section)}</span>` : ''}`;
      card.appendChild(name);
      const b = document.createElement('div');
      b.className = 'body';
      b.textContent = r.body || '';
      card.appendChild(b);
      body.appendChild(card);
    }
    return wrap;
  }

  function renderDosDontsCollapsible(n) {
    const total = (n.dos?.length || 0) + (n.donts?.length || 0);
    const { wrap, body } = buildCollapsible('dosdonts', "Do's and Don'ts", total);
    const grid = document.createElement('div');
    grid.className = 'dos';
    for (const d of n.dos || []) {
      const el = document.createElement('div');
      el.className = 'do';
      el.innerHTML = inlineMd(d);
      grid.appendChild(el);
    }
    for (const d of n.donts || []) {
      const el = document.createElement('div');
      el.className = 'dont';
      el.innerHTML = inlineMd(d);
      grid.appendChild(el);
    }
    body.appendChild(grid);
    return wrap;
  }

  function renderOverviewCollapsible(n) {
    const { wrap, body } = buildCollapsible('overview', 'Overview', null);
    const ov = document.createElement('div');
    ov.className = 'overview-body';
    if (n.northStar) {
      const star = document.createElement('span');
      star.className = 'north-star';
      star.textContent = '“' + n.northStar + '”';
      ov.appendChild(star);
    }
    if (n.overview) {
      const p = document.createElement('p');
      p.innerHTML = inlineMd(n.overview);
      ov.appendChild(p);
    }
    if (n.keyCharacteristics?.length) {
      const ul = document.createElement('ul');
      ul.innerHTML = n.keyCharacteristics.map((k) => `<li>${inlineMd(k)}</li>`).join('');
      ov.appendChild(ul);
    }
    body.appendChild(ov);
    return wrap;
  }

  function cssSafe(v) {
    // Strip anything outside valid CSS value chars to prevent injection via
    // .impeccable/design.json values rendered into inline style strings.
    return String(v).replace(/[<>"'`\n]/g, '');
  }

  function normalizeCssColor(v) {
    if (!v || typeof v !== 'string') return v;
    const s = v.trim();
    const oklch = s.match(/oklch\([^)]+\)/i);
    if (oklch) return oklch[0];
    const hex = s.match(/#[0-9a-fA-F]{3,8}\b/);
    if (hex) return hex[0];
    const rgb = s.match(/rgba?\([^)]+\)/i);
    if (rgb) return rgb[0];
    return s.replace(/\s+#.*$/, '').trim();
  }

  // Raw tab: minimal markdown renderer (subset)

  function renderRawTab(body, md) {
    const wrap = document.createElement('div');
    wrap.className = 'md';
    wrap.innerHTML = renderMarkdown(md);
    body.appendChild(wrap);
  }

  function renderMarkdown(md) {
    const lines = md.split(/\r?\n/);
    const out = [];
    let i = 0;
    let inCode = false;
    let codeBuf = [];
    let paraBuf = [];
    let listBuf = [];  // array of { indent, html }
    let listType = null; // 'ul' | 'ol'

    const flushPara = () => {
      if (paraBuf.length) {
        out.push(`<p>${inlineMd(paraBuf.join(' '))}</p>`);
        paraBuf = [];
      }
    };
    const flushList = () => {
      if (listBuf.length) {
        out.push(buildListHtml(listBuf, listType));
        listBuf = [];
        listType = null;
      }
    };
    const flushAll = () => { flushPara(); flushList(); };

    for (; i < lines.length; i++) {
      const line = lines[i];

      // Code fence
      const fence = line.match(/^```(\w*)\s*$/);
      if (fence) {
        if (!inCode) { flushAll(); inCode = true; codeBuf = []; }
        else {
          out.push(`<pre><code>${escapeHtml(codeBuf.join('\n'))}</code></pre>`);
          inCode = false;
        }
        continue;
      }
      if (inCode) { codeBuf.push(line); continue; }

      if (line.trim() === '') { flushAll(); continue; }

      const hr = line.match(/^\s*(?:---+|\*\*\*+)\s*$/);
      if (hr) { flushAll(); out.push('<hr />'); continue; }

      const heading = line.match(/^(#{1,4})\s+(.+)$/);
      if (heading) {
        flushAll();
        const lvl = heading[1].length;
        out.push(`<h${lvl}>${inlineMd(heading[2])}</h${lvl}>`);
        continue;
      }

      const bullet = line.match(/^(\s*)([-*])\s+(.+)$/);
      const ordered = line.match(/^(\s*)(\d+)\.\s+(.+)$/);
      if (bullet || ordered) {
        flushPara();
        const m = bullet || ordered;
        const indent = Math.floor(m[1].length / 2);
        const t = bullet ? 'ul' : 'ol';
        if (listType && listType !== t) flushList();
        listType = t;
        listBuf.push({ indent, html: inlineMd(m[3]) });
        continue;
      }

      paraBuf.push(line);
    }
    flushAll();
    if (inCode && codeBuf.length) {
      out.push(`<pre><code>${escapeHtml(codeBuf.join('\n'))}</code></pre>`);
    }
    return out.join('\n');
  }

  function buildListHtml(items, type) {
    // Nest by indent (one level deep is plenty for DESIGN.md).
    let html = `<${type}>`;
    let lastIndent = 0;
    for (const it of items) {
      if (it.indent > lastIndent) html += `<${type}>`;
      else if (it.indent < lastIndent) html += `</${type}>`.repeat(lastIndent - it.indent);
      html += `<li>${it.html}</li>`;
      lastIndent = it.indent;
    }
    html += `</${type}>`.repeat(lastIndent + 1);
    return html;
  }

  function inlineMd(text) {
    // Order matters: escape first, then re-inject tags.
    let s = escapeHtml(text);
    // Code spans
    s = s.replace(/`([^`]+)`/g, (_, code) => `<code>${code}</code>`);
    // Links [text](url)
    s = s.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, t, u) => `<a href="${u}" target="_blank" rel="noopener noreferrer">${t}</a>`);
    // Bold
    s = s.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
    // Italic (only single *…*, skip if inside bold already handled)
    s = s.replace(/(^|[^*])\*([^*\n]+)\*(?!\*)/g, '$1<em>$2</em>');
    return s;
  }

  function highlightBold(text) {
    return inlineMd(text);
  }

  function escapeHtml(s) {
    return String(s)
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#39;');
  }

  function copyToClipboard(text) {
    if (!text) return;
    try {
      navigator.clipboard.writeText(text);
      showToast('Copied: ' + text);
    } catch { /* ignore */ }
  }

  //
  // Init
  //

  function init() {
    try { history.scrollRestoration = 'manual'; } catch {}
    initHighlight();
    initEditBadge();
    initAnnotOverlay();
    initBar();
    initActionPicker();
    initParamsPanel();
    initGlobalBar();
    attachSteerFocusDebug();
    attachSteerFocusGuard();
    initDesignPanel();
    fetchPendingCount();
    document.addEventListener('mousemove', handleMouseMove, true);
    document.addEventListener('click', handleClick, true);
    document.addEventListener('keydown', handleKeyDown, true);
    connectSSE();

    // Check for an active session to resume (variant wrapper already in DOM after HMR)
    if (!resumeSession()) {
      console.log('[impeccable] Live variant mode ready. Hover over elements to pick one.');
      // SvelteKit (and any framework that hydrates after HTML parse) may add
      // the variant wrapper AFTER init runs. Watch for it and retry resume
      // once it appears. Disconnect on first hit.
      const scout = new MutationObserver(() => {
        const wrapper = document.querySelector('[data-impeccable-variants]');
        if (!wrapper) return;
        scout.disconnect();
        if (resumeSession()) {
          console.log('[impeccable] Resumed deferred session ' + currentSessionId + ' (post-hydration).');
        }
      });
      scout.observe(document.body, { childList: true, subtree: true });
    } else {
      console.log('[impeccable] Resumed active variant session ' + currentSessionId + ' (' + arrivedVariants + '/' + expectedVariants + ' variants).');
    }

    if (state === 'IDLE' && (pickActive || insertActive)) setLiveState('PICKING');
    syncPageInteractionCursor();
    syncPageChatFocus('init-complete');
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
})();
