(() => {
  if (window.__lsYelpScraperOverlay) return;
  window.__lsYelpScraperOverlay = true;

  const styles = `
    #ls-yelp-scrape-container{z-index:2147483647;font-family:"Inter","Segoe UI",sans-serif;display:flex;gap:8px;}
    #ls-yelp-scrape-container button{pointer-events:auto;background:linear-gradient(135deg,rgba(34,211,238,.92),rgba(56,189,248,.92));color:#021524;border:none;border-radius:999px;padding:10px 18px;font-weight:600;font-size:14px;cursor:pointer;box-shadow:0 14px 32px rgba(34,211,238,.28);display:inline-flex;align-items:center;gap:8px;transition:transform .18s ease,box-shadow .18s ease;}
    #ls-yelp-scrape-container button:hover{transform:translateY(-2px);box-shadow:0 18px 38px rgba(34,211,238,.34);}
    #ls-yelp-scrape-container button:disabled{opacity:.55;cursor:not-allowed;box-shadow:none;transform:none;}
    #ls-yelp-scrape-status{pointer-events:auto;padding:6px 10px;border-radius:8px;background:rgba(15,23,42,.85);color:rgba(226,232,240,.82);font-size:12px;box-shadow:0 10px 24px rgba(15,23,42,.4);}
    @media(max-width:640px){#ls-yelp-scrape-container{top:auto;bottom:18px;right:16px;}}
  `;

  const styleEl = document.createElement('style');
  styleEl.id = 'ls-yelp-scrape-styles';
  styleEl.textContent = styles;
  document.head.appendChild(styleEl);

  const container = document.createElement('div');
  container.id = 'ls-yelp-scrape-container';
  const button = document.createElement('button');
  button.type = 'button';
  button.textContent = 'Start Scraping';
  const status = document.createElement('div');
  status.id = 'ls-yelp-scrape-status';
  const defaultStatus = 'Ready – configure your Yelp search, then click the button.';
  status.textContent = defaultStatus;
  container.appendChild(button);
  container.appendChild(status);

  const setStatus = (msg) => { status.textContent = msg; };
  let verificationActive = false;

  const setBusy = (busy) => {
    if (busy) {
      button.disabled = true;
      button.textContent = 'Scraping…';
    } else {
      button.disabled = verificationActive;
      button.textContent = verificationActive ? 'Verification Required' : 'Start Scraping';
    }
  };

  const reportVerificationState = (active) => {
    if (!chrome?.runtime?.sendMessage) return;
    try {
      chrome.runtime.sendMessage({
        type: active ? 'yelp-verification-required' : 'yelp-verification-cleared',
        url: location.href
      });
    } catch (error) {
      console.warn('[LS][Yelp] Failed to report verification state', error);
    }
  };

  const isVerificationPage = () => {
    if (/\/(captcha|verify|verification|blocked)/i.test(location.pathname)) return true;
    const heading = document.querySelector('h1, h2');
    if (heading && /verification/i.test(heading.textContent || '')) return true;
    const text = document.body ? (document.body.innerText || '') : '';
    return /why is this verification required\?/i.test(text);
  };

  const refreshVerificationState = () => {
    const active = isVerificationPage();
    if (verificationActive === active) return active;
    verificationActive = active;
    if (verificationActive) {
      button.disabled = true;
      button.textContent = 'Verification Required';
      setStatus('Complete the Yelp verification challenge in this tab, then reload your search results.');
    } else {
      button.disabled = false;
      button.textContent = 'Start Scraping';
      const session = loadSession();
      if (!session || session.mode !== 'running') {
        setStatus(defaultStatus);
      }
    }
    reportVerificationState(active);
    return active;
  };

  const extensionOrigin = (() => {
    if (!chrome?.runtime?.getURL) return '';
    try {
      return chrome.runtime.getURL('').replace(/\/$/, '');
    } catch (error) {
      console.warn('[LS][Yelp] failed to derive extension origin', error);
      return '';
    }
  })();

  const isEmbedded = (() => {
    try {
      return window.top !== window;
    } catch (_) {
      return true;
    }
  })();

  const notifyParent = (payload) => {
    if (!isEmbedded || !payload || typeof payload !== 'object') return;
    try {
      window.parent.postMessage({ source: 'ls-yelp-overlay', ...payload }, '*');
    } catch (error) {
      console.warn('[LS][Yelp] postMessage to parent failed', error);
    }
  };

  let placement = null;

  const setPlacement = (mode) => {
    if (isEmbedded) {
      container.style.display = 'none';
      return;
    }
    if (placement === mode) return;
    placement = mode;
    if (mode === 'inline') {
      container.style.position = 'relative';
      container.style.top = 'auto';
      container.style.right = 'auto';
      container.style.pointerEvents = 'auto';
      container.style.width = '100%';
      container.style.justifyContent = 'flex-end';
      container.style.alignItems = 'center';
      container.style.flexDirection = 'row';
      container.style.margin = '12px 0';
      status.style.marginLeft = '8px';
    } else {
      container.style.position = 'fixed';
      container.style.top = '18px';
      container.style.right = '20px';
      container.style.pointerEvents = 'auto';
      container.style.width = 'auto';
      container.style.justifyContent = 'flex-end';
      container.style.alignItems = 'flex-end';
      container.style.flexDirection = 'column';
      container.style.margin = '0';
      status.style.marginLeft = '0';
    }
  };

  const findSiteInfo = () => {
    if (isEmbedded) return null;
    const selectors = [
      '[aria-label="Site view information"]',
      '[aria-label="Site View Information"]',
      '[data-testid="site-view-information"]',
      'section[aria-label="Site view information"]',
      'section[data-testid="site-view-information"]',
    ];
    for (const selector of selectors) {
      const el = document.querySelector(selector);
      if (el) return el;
    }
    if (!document.body) return null;
    try {
      const NF = window.NodeFilter;
      if (!NF || !document.createTreeWalker) return null;
      const walker = document.createTreeWalker(document.body, NF.SHOW_ELEMENT, {
        acceptNode(node) {
          if (!node || node === container || container.contains(node)) return NF.FILTER_SKIP;
          const text = node.textContent;
          if (typeof text === 'string' && /site\s*view\s*information/i.test(text)) {
            return NF.FILTER_ACCEPT;
          }
          return NF.FILTER_SKIP;
        }
      });
      return walker.nextNode();
    } catch (err) {
      console.warn('[LS][Yelp] site info search failed', err);
      return null;
    }
  };

  const isProfilePage = () => /\/biz\//i.test(location.pathname);
  const isSearchPage = () => !isProfilePage();

  const attachUi = () => {
    if (!document.body) return false;
    if (!document.body.contains(container)) {
      document.body.appendChild(container);
    }
    const onSearchPage = isSearchPage();
    if (isEmbedded || !onSearchPage) {
      container.style.display = 'none';
      return true;
    }
    const siteInfo = findSiteInfo();
    if (siteInfo && siteInfo.parentNode) {
      setPlacement('inline');
      if (container.parentNode !== siteInfo.parentNode || container.nextSibling !== siteInfo) {
        siteInfo.parentNode.insertBefore(container, siteInfo);
      }
    } else {
      setPlacement('corner');
      if (!document.body.contains(container)) {
        document.body.appendChild(container);
      }
    }
    if (!document.body.contains(container)) {
      document.body.appendChild(container);
    }
    container.style.display = 'flex';
    return true;
  };

  if (isEmbedded) {
    [0, 400, 1200].forEach((delay) => {
      setTimeout(() => notifyParent({ type: 'ls-yelp-overlay-ready' }), delay);
    });
  }

  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

  const TIMING = Object.freeze({
    scrollPauseMs: 220,
    profileReadyBaseMs: 10000,
    profileReadyExtraMs: 1800,
    profileReadyPollMs: 130,
    profileRetryPauseMs: 240,
    postCapturePauseMs: 260
  });

  const cleanText = (value) => (typeof value === 'string' ? value.replace(/\s+/g, ' ').trim() : '');

  const cssEscape = (value) => {
    try {
      if (window.CSS && typeof window.CSS.escape === 'function') {
        return window.CSS.escape(value);
      }
    } catch (_) {}
    return String(value || '').replace(/([\0-\x1f\x7f-\x9f"'`\\])/g, '\\$1');
  };

  const SESSION_KEY = '__lsYelpScrapeState';

  const loadSession = () => {
    try {
      const raw = sessionStorage.getItem(SESSION_KEY);
      return raw ? JSON.parse(raw) : null;
    } catch (error) {
      console.warn('[LS][Yelp] Failed to load session state', error);
      return null;
    }
  };

  const saveSession = (state) => {
    if (!state) return;
    try {
      sessionStorage.setItem(SESSION_KEY, JSON.stringify(state));
    } catch (error) {
      console.warn('[LS][Yelp] Failed to save session state', error);
    }
  };

  const clearSession = () => {
    try {
      sessionStorage.removeItem(SESSION_KEY);
    } catch (error) {
      console.warn('[LS][Yelp] Failed to clear session state', error);
    }
  };

  const toAbsoluteUrl = (href) => {
    if (!href) return '';
    try {
      return new URL(href, location.origin).toString();
    } catch (error) {
      console.warn('[LS][Yelp] Failed to resolve URL', href, error);
      return href;
    }
  };

  const decodeRedirectUrl = (href) => {
    const absolute = toAbsoluteUrl(href);
    try {
      const url = new URL(absolute);
      const internal = url.searchParams.get('url');
      if (internal) return decodeURIComponent(internal);
      return absolute;
    } catch (error) {
      return absolute;
    }
  };

  const normalizeProfileUrl = (url) => {
    if (!url) return '';
    try {
      const parsed = new URL(url, location.origin);
      parsed.hash = '';
      if (parsed.searchParams.has('osq')) parsed.searchParams.delete('osq');
      parsed.search = parsed.searchParams.toString() ? `?${parsed.searchParams.toString()}` : '';
      return parsed.toString();
    } catch (error) {
      return url;
    }
  };

  const gatherOrganicCards = () => {
    const selectors = [
      '[data-testid="serp-ia-card"]',
      '[data-testid="searchResult"]',
      'li[data-testid="serpListItem"]',
      '[data-yelp-component="SERPItem"]'
    ];
    const nodes = Array.from(document.querySelectorAll(selectors.join(',')));
    const items = [];
    const seen = new Set();
    nodes.forEach((node) => {
      const crawlId = (node.getAttribute('data-traffic-crawl-id') || '').toLowerCase();
      if (crawlId && /(ad|sponsored|promo)/.test(crawlId)) return;
      if (node.querySelector('[aria-label="Sponsored"], [data-testid="ad-label"], [data-testid="serp-ia-business-label"]')) return;
      if (/\bsponsored\b/i.test(node.textContent || '')) return;
      const anchor = node.querySelector('a[href^="/biz/"]') || node.querySelector('[data-testid="businessName"] a[href]');
      if (!anchor) return;
      const profileUrl = toAbsoluteUrl(anchor.getAttribute('href'));
      const canonical = normalizeProfileUrl(profileUrl);
      if (!profileUrl || seen.has(canonical)) return;
      seen.add(canonical);
      const titleLink = node.querySelector('[data-traffic-crawl-id="SearchResultBizName"] a') || node.querySelector('[data-testid="businessName"] a') || anchor;
      const name = cleanText(titleLink?.textContent || anchor.getAttribute('aria-label') || '');
      items.push({ element: node, name, profileUrl, canonical });
    });

    if (!items.length) {
      const fallbackContainer = document.querySelector('[data-testid="searchResults"]') || document.body;
      const anchors = Array.from(fallbackContainer.querySelectorAll('a[href^="/biz/"]'));
      anchors.forEach((anchor) => {
        const profileUrl = toAbsoluteUrl(anchor.getAttribute('href'));
        const canonical = normalizeProfileUrl(profileUrl);
        if (!profileUrl || seen.has(canonical)) return;
        seen.add(canonical);
        const name = cleanText(anchor.textContent || anchor.getAttribute('aria-label') || '');
        items.push({ element: anchor.closest('[data-testid]') || anchor.parentElement, name, profileUrl, canonical });
      });
    }
    return items;
  };

  const appendCardsToState = (state, cards) => {
    if (!state || !Array.isArray(cards)) return;
    if (!Array.isArray(state.items)) state.items = [];
    if (!state.order) state.order = [];
    if (!state.seen) state.seen = {};
    if (!state.lookup) state.lookup = {};
    ensureQueueState(state);
    cards.forEach((card) => {
      const key = card.canonical || card.profileUrl || card.name;
      if (!key) return;
      if (state.seen[key]) return;
      state.seen[key] = true;
      const entry = {
        name: card.name || '',
        profileUrl: card.profileUrl,
        canonical: card.canonical || key
      };
      state.items.push(entry);
      state.order.push(key);
      state.lookup[key] = entry;
      if (!state.processed || !state.processed[key]) {
        if (!state.queueSet[key]) {
          state.queue.push(key);
          state.queueSet[key] = true;
        }
      }
    });
  };

  const scrollResultsPane = async () => {
    const pane = document.querySelector('[data-testid="searchResults"]') ||
      document.querySelector('#main-content [role="presentation"]') ||
      document.querySelector('[data-component-prop="searchResultsList"]');
    if (pane && typeof pane.scrollBy === 'function') {
      pane.scrollBy({ top: pane.clientHeight * 0.85, behavior: 'instant' });
    } else {
      window.scrollBy(0, Math.max(600, Math.floor(window.innerHeight * 0.8)));
    }
    await sleep(TIMING.scrollPauseMs);
  };

  const refreshStateItems = async (state, { ensureNew = false, attempts = 6 } = {}) => {
    if (!state) return;
    let prevCount = Array.isArray(state.items) ? state.items.length : 0;
    appendCardsToState(state, gatherOrganicCards());
    if (state.items && state.items.length) {
      state.totalExpected = Math.max(state.totalExpected || 0, state.items.length);
    }
    if (Array.isArray(state.items) && state.items.length > prevCount) {
      saveSession(state);
    }
    if (!ensureNew) return;
    let tries = 0;
    const maxAttempts = Math.max(6, attempts);
    while (tries < maxAttempts && (state.items.length === prevCount)) {
      await scrollResultsPane();
      appendCardsToState(state, gatherOrganicCards());
      if (state.items && state.items.length) {
        state.totalExpected = Math.max(state.totalExpected || 0, state.items.length);
      }
      tries += 1;
      if (Array.isArray(state.items) && state.items.length > prevCount) {
        saveSession(state);
        break;
      }
    }
  };

  const dequeueNextListing = (state) => {
    if (!state) return null;
    ensureQueueState(state);
    while (state.queue.length) {
      const key = state.queue.shift();
      if (key && state.queueSet) delete state.queueSet[key];
      if (!key) continue;
      if (state.processed && state.processed[key] && state.processed[key].status === 'done') continue;
      const entry = state.lookup?.[key];
      if (!entry || !entry.profileUrl) continue;
      if (state.processed && state.processed[key] && state.processed[key].status === 'pending') continue;
      return entry;
    }
    return null;
  };

  const takeNextListing = async (state, { attempts = 18, delayMs = 420 } = {}) => {
    if (!state) return null;
    ensureQueueState(state);
    const max = Math.max(1, attempts);
    for (let i = 0; i < max; i += 1) {
      const entry = dequeueNextListing(state);
      if (entry) return entry;
      await sleep(delayMs);
      await refreshStateItems(state, { ensureNew: true, attempts: 4 });
    }
    return null;
  };

  const ensurePaginationState = (state) => {
    if (!state) return;
    if (!state.pagination || typeof state.pagination !== 'object') {
      state.pagination = {};
    }
    if (!Array.isArray(state.pagination.pagesVisited)) {
      state.pagination.pagesVisited = [];
    }
    if (!Array.isArray(state.pagination.pending)) {
      state.pagination.pending = [];
    }
    if (!state.pagination.pendingSet || typeof state.pagination.pendingSet !== 'object') {
      state.pagination.pendingSet = {};
    }
    if (!state.pagination.visitedSet || typeof state.pagination.visitedSet !== 'object') {
      state.pagination.visitedSet = {};
    }
    if (typeof state.pagination.discoveryCounter !== 'number') {
      state.pagination.discoveryCounter = 0;
    }
    if (typeof state.pagination.currentPage !== 'number' || Number.isNaN(state.pagination.currentPage)) {
      state.pagination.currentPage = null;
    }
    if (typeof state.pagination.advancing !== 'boolean') state.pagination.advancing = false;
    if (typeof state.pagination.from !== 'string') state.pagination.from = '';
    if (typeof state.pagination.target !== 'string') state.pagination.target = '';
    if (typeof state.pagination.startedAt !== 'number') state.pagination.startedAt = 0;
    if (typeof state.pagination.lastUrl !== 'string') state.pagination.lastUrl = '';
  };

  const ensureQueueState = (state) => {
    if (!state) return;
    if (!Array.isArray(state.queue)) state.queue = [];
    if (!state.queueSet || typeof state.queueSet !== 'object') state.queueSet = {};
  };

  const ESTIMATED_PAGE_SIZE = 10;

  const normalizeSearchListUrl = (url) => {
    if (!url) return '';
    try {
      const parsed = new URL(url, location.origin);
      parsed.hash = '';
      if (typeof parsed.searchParams.sort === 'function') {
        parsed.searchParams.sort();
      } else {
        const entries = Array.from(parsed.searchParams.entries()).sort(([aKey], [bKey]) => aKey.localeCompare(bKey));
        parsed.search = '';
        entries.forEach(([key, value]) => parsed.searchParams.append(key, value));
      }
      const serialized = parsed.searchParams.toString();
      parsed.search = serialized ? `?${serialized}` : '';
      return parsed.toString();
    } catch (_) {
      return url;
    }
  };

  const derivePageNumberFromUrl = (url) => {
    if (!url) return null;
    try {
      const parsed = new URL(url, location.origin);
      const startRaw = parsed.searchParams.get('start');
      if (startRaw === null) return 1;
      const start = Number(startRaw);
      if (Number.isNaN(start) || start < 0) return null;
      return Math.floor(start / ESTIMATED_PAGE_SIZE) + 1;
    } catch (_) {
      return null;
    }
  };

  const detectCurrentPageNumber = () => {
    const indicator = document.querySelector('.pagination-link-current__09f24__nwDm3[aria-label], [aria-current="true"] [aria-label*="Page"], [aria-current="true"]');
    const label = cleanText(indicator?.getAttribute('aria-label') || indicator?.textContent || '');
    if (label) {
      const match = label.match(/([0-9]+)/);
      if (match) {
        const value = Number(match[1]);
        if (!Number.isNaN(value)) return value;
      }
    }
    return derivePageNumberFromUrl(location.href);
  };

  const recordCurrentListPage = (state) => {
    if (!state) return;
    ensurePaginationState(state);
    const rawUrl = location.href;
    const normalized = normalizeSearchListUrl(rawUrl);
    state.listUrl = normalized;
    if (!state.pagination.pagesVisited.includes(normalized)) {
      state.pagination.pagesVisited.push(normalized);
    }
    state.pagination.visitedSet[normalized] = true;
    state.pagination.lastUrl = normalized;
    const pageNumber = detectCurrentPageNumber();
    if (pageNumber && (!state.pagination.currentPage || pageNumber >= state.pagination.currentPage)) {
      state.pagination.currentPage = pageNumber;
    }
    if (state.pagination.pending && state.pagination.pending.length) {
      state.pagination.pending = state.pagination.pending.filter((entry) => {
        if (!entry || typeof entry !== 'object') return false;
        const canonical = entry.canonical || normalizeSearchListUrl(entry.url || '');
        if (!canonical) return false;
        if (canonical === normalized) {
          if (state.pagination.pendingSet) delete state.pagination.pendingSet[canonical];
          return false;
        }
        return true;
      });
    }
  };

  const getElementLabel = (el) => {
    if (!el) return '';
    const text = cleanText(el.textContent || '');
    if (text) return text;
    const aria = cleanText(el.getAttribute('aria-label') || el.getAttribute('title') || '');
    if (aria) return aria;
    if (el.firstElementChild) {
      return getElementLabel(el.firstElementChild);
    }
    return '';
  };

  const matchesNextLabel = (label) => {
    if (!label) return false;
    const normalized = label.toLowerCase();
    if (!normalized) return false;
    if (/(prev|previous|back)\b/.test(normalized)) return false;
    return /\bnext\b/.test(normalized) || /»|›|→/.test(label);
  };

  const queuePaginationCandidate = (state, url, meta = {}) => {
    if (!state || !url) return false;
    ensurePaginationState(state);
    const normalized = normalizeSearchListUrl(url);
    if (!normalized) return false;
    if (state.pagination.visitedSet[normalized]) return false;
    if (state.pagination.pendingSet[normalized]) return false;

    const entry = {
      url: normalized,
      canonical: normalized,
      page: typeof meta.page === 'number' && !Number.isNaN(meta.page) ? meta.page : derivePageNumberFromUrl(normalized),
      order: typeof meta.order === 'number' ? meta.order : state.pagination.discoveryCounter
    };
    state.pagination.pendingSet[normalized] = true;
    state.pagination.pending.push(entry);
    state.pagination.pending.sort((a, b) => {
      const pageA = typeof a.page === 'number' ? a.page : Infinity;
      const pageB = typeof b.page === 'number' ? b.page : Infinity;
      if (pageA !== pageB) return pageA - pageB;
      const orderA = typeof a.order === 'number' ? a.order : 0;
      const orderB = typeof b.order === 'number' ? b.order : 0;
      return orderA - orderB;
    });
    return true;
  };

  const collectPaginationCandidates = (state) => {
    if (!state) return;
    ensurePaginationState(state);
    const containerSelectors = [
      '.pagination-links__09f24__Y1Vj7',
      '[data-testid="pagination-links"]',
      '[data-testid="paginationButtons"]',
      'nav[aria-label*="pagination"]',
    ];
    let container = null;
    for (const selector of containerSelectors) {
      container = document.querySelector(selector);
      if (container) break;
    }
    const anchors = container ? Array.from(container.querySelectorAll('a[href]')) : [];
    const globalAnchors = Array.from(document.querySelectorAll('a.next-link[aria-label], a[aria-label="Next"], a[aria-label*="Next"], a.navigation-button__09f24__D7E9g[aria-label]'));
    const nodes = [...anchors, ...globalAnchors];

    nodes.forEach((node) => {
      if (!node || !node.getAttribute) return;
      const href = node.getAttribute('href');
      if (!href) return;
      const absolute = toAbsoluteUrl(href);
      if (!absolute) return;
      state.pagination.discoveryCounter += 1;
      const label = cleanText(node.getAttribute('aria-label') || node.textContent || '');
      const match = label.match(/([0-9]+)/);
      const page = match ? Number(match[1]) : null;
      queuePaginationCandidate(state, absolute, { page, order: state.pagination.discoveryCounter });
    });

    const nextButton = document.querySelector('button.pagination-button__09f24__kbFYf, button[data-testid*="pagination-button-next"], button[aria-label*="Next"]');
    if (nextButton) {
      const dataHref = nextButton.getAttribute('data-href') || nextButton.getAttribute('href');
      if (dataHref) {
        const absolute = toAbsoluteUrl(dataHref);
        if (absolute) {
          state.pagination.discoveryCounter += 1;
          queuePaginationCandidate(state, absolute, { order: state.pagination.discoveryCounter });
        }
      }
    }
  };

  const takeNextPaginationCandidate = (state) => {
    if (!state) return null;
    ensurePaginationState(state);
    if (!Array.isArray(state.pagination.pending) || !state.pagination.pending.length) return null;

    const currentPage = typeof state.pagination.currentPage === 'number' ? state.pagination.currentPage : null;
    let fallback = null;
    let fallbackIndex = -1;
    let best = null;
    let bestIndex = -1;

    state.pagination.pending.forEach((entry, index) => {
      if (!entry) return;
      const canonical = entry.canonical || normalizeSearchListUrl(entry.url || '');
      if (!canonical) return;
      if (state.pagination.visitedSet[canonical]) {
        if (state.pagination.pendingSet) delete state.pagination.pendingSet[canonical];
        return;
      }
      const candidatePage = typeof entry.page === 'number' ? entry.page : derivePageNumberFromUrl(entry.url || '');
      if (currentPage && candidatePage && candidatePage > currentPage) {
        if (!best || !best.page || candidatePage < best.page) {
          best = { ...entry, canonical, page: candidatePage };
          bestIndex = index;
        }
        return;
      }
      if (fallback) return;
      fallback = { ...entry, canonical, page: candidatePage };
      fallbackIndex = index;
    });

    const chosen = best || fallback;
    const chosenIndex = best ? bestIndex : fallbackIndex;
    if (!chosen || chosenIndex < 0) return null;

    state.pagination.pending.splice(chosenIndex, 1);
    if (state.pagination.pendingSet && chosen.canonical) {
      delete state.pagination.pendingSet[chosen.canonical];
    }

    return chosen.url || chosen.canonical || null;
  };

  const isNextPaginationControl = (node) => {
    if (!node) return false;
    if (matchesNextLabel(getElementLabel(node))) return true;
    const aria = cleanText(node.getAttribute('aria-label') || '');
    if (matchesNextLabel(aria)) return true;
    const title = cleanText(node.getAttribute('title') || '');
    if (matchesNextLabel(title)) return true;
    const dataTestId = cleanText(node.getAttribute('data-testid') || '');
    if (matchesNextLabel(dataTestId)) return true;
    if (node.dataset) {
      for (const [key, value] of Object.entries(node.dataset)) {
        if (matchesNextLabel(key) || matchesNextLabel(cleanText(value || ''))) return true;
      }
    }
    return false;
  };

  const isPaginationControlDisabled = (el) => {
    if (!el) return true;
    if (el.disabled) return true;
    const aria = (el.getAttribute('aria-disabled') || '').toLowerCase();
    if (aria === 'true') return true;
    if (el.classList && el.classList.contains('disabled')) return true;
    if (el.hasAttribute && el.hasAttribute('disabled')) return true;
    const dataDisabledRaw = el.getAttribute('data-disabled') || el.getAttribute('aria-disabled') || (el.dataset ? el.dataset.disabled : '');
    const dataDisabled = cleanText(dataDisabledRaw || '').toLowerCase();
    if (dataDisabled && dataDisabled !== 'false' && dataDisabled !== '0' && dataDisabled !== 'no') return true;
    const dataState = (el.getAttribute('data-activated') || '').toLowerCase();
    if (dataState === 'false' && (!el.getAttribute('value') || el.tagName !== 'BUTTON')) {
      return false;
    }
    if (el.closest) {
      const disabledAncestor = el.closest('[aria-disabled="true"], [disabled]');
      if (disabledAncestor) return true;
    }
    return false;
  };

  const findNextPageControl = () => {
    const selectors = [
      'button[aria-label="Next"]',
      'button[aria-label*="Next"]',
      'button[aria-label*="next"]',
      'button[aria-label*="Next page"]',
      'button.pagination-button__09f24__kbFYf',
      'button[data-testid="pagination-button"]',
      'button[data-testid*="pagination-button-next"]',
      'button[data-testid*="pagination-next"]',
      'a[aria-label="Next"]',
      'a[aria-label*="Next"]',
      'a[aria-label*="next"]',
      'a[aria-label="Next page"]',
      'a[data-testid*="pagination-button-next"]',
      'a[data-testid*="pagination-next"]',
      '[role="button"][aria-label*="Next"]',
      '[role="link"][aria-label*="Next"]'
    ];
    for (const selector of selectors) {
      const nodes = document.querySelectorAll(selector);
      for (const node of nodes) {
        if (isNextPaginationControl(node)) return node;
      }
    }
    const buttons = document.querySelectorAll('button, a, [role="button"], [role="link"]');
    for (const node of buttons) {
      if (isNextPaginationControl(node)) return node;
    }
    return null;
  };

  const triggerPaginationControl = (el) => {
    if (!el) return false;
    try {
      if (el.tagName === 'A' && el.href) {
        const target = el.href;
        try {
          location.assign(target);
        } catch (_) {
          location.href = target;
        }
        return true;
      }
      if (typeof el.click === 'function') {
        el.click();
        return true;
      }
      const event = new MouseEvent('click', { bubbles: true, cancelable: true });
      if (el.dispatchEvent && el.dispatchEvent(event)) {
        return true;
      }
      const form = el.form || el.closest?.('form');
      if (form && typeof form.submit === 'function') {
        form.submit();
        return true;
      }
    } catch (error) {
      console.warn('[LS][Yelp] Failed to activate pagination control', error);
    }
    return false;
  };

  const advanceToNextPage = async (state) => {
    if (!state) return false;
    ensurePaginationState(state);
    if (state.activeNavigation) state.activeNavigation = null;
    collectPaginationCandidates(state);

    let targetUrl = takeNextPaginationCandidate(state);
    let control = null;

    if (!targetUrl) {
      control = findNextPageControl();
      if (!control) return false;
      if (isPaginationControlDisabled(control)) return false;

      if (control.tagName === 'A' && control.href) {
        targetUrl = control.href;
      } else {
        const dataHref = control.getAttribute('href') || control.getAttribute('data-href') || '';
        if (dataHref) {
          try {
            targetUrl = new URL(dataHref, location.origin).toString();
          } catch (_) {
            targetUrl = dataHref;
          }
        }
      }

      if (targetUrl) {
        try {
          const normalized = normalizeSearchListUrl(targetUrl);
          if (state.pagination.visitedSet[normalized]) {
            console.warn('[LS][Yelp] Skipping pagination to previously visited page');
            return false;
          }
          targetUrl = normalized;
        } catch (_) {}
      }
    }

    const currentUrl = normalizeSearchListUrl(location.href);
    recordCurrentListPage(state);
    ensurePaginationState(state);
    state.pagination.advancing = true;
    state.pagination.from = currentUrl;
    state.pagination.target = targetUrl || '';
    state.pagination.startedAt = Date.now();
    state.pagination.lastUrl = currentUrl;
    setStatus('Loading next results page…');
    saveSession(state);

    if (targetUrl) {
      try {
        location.assign(targetUrl);
      } catch (_) {
        location.href = targetUrl;
      }
      await sleep(400);
      return true;
    }

    if (!control) return false;

    try {
      control.scrollIntoView({ behavior: 'instant', block: 'center' });
    } catch (_) {}

    const triggered = triggerPaginationControl(control);
    if (!triggered) {
      state.pagination.advancing = false;
      state.pagination.target = '';
      saveSession(state);
      return false;
    }

    await sleep(400);
    return true;
  };

  const findLabeledDetail = (doc, label) => {
    const lowerLabel = label.toLowerCase();
    const sections = Array.from(doc.querySelectorAll('div.y-css-8x4us, section div.y-css-8x4us'));
    for (const section of sections) {
      const labelEl = section.querySelector('p');
      if (!labelEl) continue;
      const text = cleanText(labelEl.textContent);
      if (!text) continue;
      if (!text.toLowerCase().includes(lowerLabel)) continue;
      const link = section.querySelector('a[href]');
      const valueEl = link || section.querySelector('p[data-font-weight], span[data-font-weight]');
      const value = cleanText(valueEl?.textContent || '');
      const href = link ? decodeRedirectUrl(link.getAttribute('href')) : '';
      return { value, href };
    }
    return { value: '', href: '' };
  };

  const extractProfileDetails = (doc, profileUrl, fallbackName) => {
    if (!doc) return null;

    const selectText = (selector) => cleanText(doc.querySelector(selector)?.textContent || '');

    const name = (() => {
      const direct = selectText('.headingLight__09f24__N86u1 h1');
      if (direct) return direct;
      const alt = selectText('h1.y-css-olzveb');
      if (alt) return alt;
      const h1 = selectText('main h1');
      return h1 || cleanText(fallbackName || '');
    })();

    const rating = (() => {
      const aria = doc.querySelector('[aria-label*="star rating"]');
      if (aria) {
        const label = aria.getAttribute('aria-label') || aria.textContent || '';
        const match = label.match(/([0-9]+(?:\.[0-9]+)?)/);
        if (match) return cleanText(match[1]);
      }
      const numeric = [...doc.querySelectorAll('span[data-font-weight="semibold"]')]
        .map((el) => cleanText(el.textContent || ''))
        .find((text) => /^[0-9]+(?:\.[0-9]+)?$/.test(text));
      return numeric || '';
    })();

    const reviews = (() => {
      const el = doc.querySelector('a[href="#reviews"], [href="#reviews"]');
      return cleanText(el?.textContent || '');
    })();

    const hours = (() => {
      const el = doc.querySelector('.y-css-qavbuq span[data-font-weight="semibold"], [data-testid="currentHours"] span[data-font-weight="semibold"]');
      if (el) return cleanText(el.textContent || '');
      const alt = [...doc.querySelectorAll('span[data-font-weight="semibold"]')]
        .map((node) => cleanText(node.textContent || ''))
        .find((text) => /am|pm|closed|open/i.test(text));
      return alt || '';
    })();

    const websiteDetail = (() => {
      const detail = findLabeledDetail(doc, 'Business website');
      if (detail.href) return detail;
      const altLink = doc.querySelector('a[href*="biz_redir"], a[href^="http"]');
      if (altLink) {
        return { value: cleanText(altLink.textContent || altLink.href || ''), href: decodeRedirectUrl(altLink.getAttribute('href')) };
      }
      return detail;
    })();

    const phoneDetail = (() => {
      const detail = findLabeledDetail(doc, 'Phone number');
      if (detail.value) return detail;
      const phoneEl = [...doc.querySelectorAll('p[data-font-weight], span[data-font-weight]')]
        .map((el) => cleanText(el.textContent || ''))
        .find((text) => /\(\d{3}\)\s*\d{3}-\d{4}|\d{3}[-\s]?\d{3}[-\s]?\d{4}/.test(text));
      return { value: phoneEl || detail.value || '', href: detail.href || '' };
    })();

    const address = (() => {
      const exact = selectText('p.y-css-p0gpmm[data-font-weight="semibold"]');
      if (exact) return exact;
      return selectText('[data-testid="address"] p[data-font-weight]');
    })();

    if (!name) return null;

    return {
      name,
      rating,
      reviewsText: reviews,
      reviews,
      hours,
      phone: phoneDetail.value,
      websiteUrl: websiteDetail.href,
      website: websiteDetail.href,
      websiteLabel: websiteDetail.value || websiteDetail.href,
      address,
      profileUrl: profileUrl || location.href,
    };
  };

  const waitForProfileReady = async (timeoutMs = TIMING.profileReadyBaseMs) => {
    const start = Date.now();
    while (Date.now() - start < timeoutMs) {
      const heading = document.querySelector('.headingLight__09f24__N86u1 h1') || document.querySelector('h1');
      const addressBlock = document.querySelector('[data-testid="address"] p[data-font-weight], p.y-css-p0gpmm[data-font-weight="semibold"]');
      if (heading && cleanText(heading.textContent).length > 0) {
        if (addressBlock && cleanText(addressBlock.textContent).length > 0) return true;
        if (document.readyState === 'complete') return true;
      }
      if (/\b404\b|not found/i.test(document.body?.innerText || '')) return false;
      await sleep(TIMING.profileReadyPollMs);
    }
    return !!document.querySelector('.headingLight__09f24__N86u1 h1');
  };

  const notifyParentStatus = (payload) => {
    if (!isEmbedded) return;
    notifyParent(Object.assign({ type: 'ls-yelp-ack' }, payload || {}));
  };

  const ensureStartEvent = (state) => {
    if (!state || state.startNotified) return;
    if (!state.runId) {
      state.runId = `run-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
    }
    try {
      chrome.runtime.sendMessage({
        type: 'yelp-scrape-start',
        url: state.listUrl || location.href,
        runId: state.runId,
        expected: state.totalExpected || 0
      });
    } catch (error) {
      console.warn('[LS][Yelp] Failed to send start message', error);
    }
    notifyParentStatus({ status: 'starting' });
    state.startNotified = true;
    saveSession(state);
  };

  const reportProgress = (state, item, detail, index) => {
    if (!state) return;
    const total = state.totalExpected || state.items?.length || 0;
    const payload = detail && detail.name ? detail : Object.assign({
      name: item?.name || '',
      profileUrl: item?.profileUrl || location.href,
      error: 'detail_unavailable'
    });
    const snapshot = Array.isArray(state.results)
      ? state.results.map((entry) => ({ ...entry }))
      : [];
    try {
      chrome.runtime.sendMessage({
        type: 'yelp-scrape-progress',
        item: payload,
        index,
        total,
        url: payload.profileUrl || item?.profileUrl || location.href,
        items: snapshot,
        count: snapshot.length,
        runId: state.runId || null
      });
    } catch (error) {
      console.warn('[LS][Yelp] Failed to send progress update', error);
    }
    notifyParentStatus({ status: 'progress', index, total, name: payload.name || '', item: payload });
  };

  const reportError = (state, message) => {
    const text = message || 'Scrape failed.';
    try {
      chrome.runtime.sendMessage({
        type: 'yelp-scrape-error',
        error: text,
        url: state?.listUrl || location.href,
        runId: state?.runId || null
      });
    } catch (error) {
      console.warn('[LS][Yelp] Failed to send error message', error);
    }
    notifyParentStatus({ status: 'error', message: text });
    setStatus(text, { error: true });
    setBusy(false);
    clearSession();
    resumeTriggered = false;
  };

  const finalizeScrape = (state) => {
    if (!state || state.mode === 'done') return;
    state.mode = 'done';
    saveSession(state);
    const results = Array.isArray(state.results) ? state.results : [];
    const message = `Captured ${results.length} businesses.`;
    try {
      chrome.runtime.sendMessage({
        type: 'yelp-scrape-results',
        items: results,
        url: state.listUrl || location.href,
        count: results.length,
        runId: state.runId || null
      });
    } catch (error) {
      console.warn('[LS][Yelp] Failed to send final results', error);
    }
    notifyParentStatus({ status: 'done', count: results.length, message, items: results });
    setStatus(message);
    setBusy(false);
    clearSession();
    resumeTriggered = false;
    try {
      chrome.runtime.sendMessage({ type: 'yelp-close-tab' });
    } catch {}
    setTimeout(() => {
      try { window.close(); } catch {}
    }, 400);
  };

  const navigateToList = (state) => {
    const target = state?.listUrl || 'https://www.yelp.com/search';
    try {
      location.assign(target);
    } catch (_) {
      location.href = target;
    }
  };

  const processProfilePage = async (state) => {
    if (!state || state.mode !== 'running') return;
    ensureStartEvent(state);
    if (state.activeNavigation) {
      state.activeNavigation = null;
      saveSession(state);
    }
    const processed = state.processed || {};
    const key = state.currentKey || null;
    const items = state.items || [];
    let item = null;
    if (key && state.lookup && state.lookup[key]) {
      item = state.lookup[key];
    }
    if (!item && typeof state.currentIndex === 'number' && items[state.currentIndex]) {
      item = items[state.currentIndex];
    }
    if (!item && key) {
      item = items.find((entry) => (entry?.canonical || entry?.profileUrl || entry?.name) === key) || null;
    }
    if (!item) {
      const remaining = (state.items || []).filter((entry) => {
        const entryKey = entry?.canonical || entry?.profileUrl || entry?.name;
        return entryKey && !processed[entryKey];
      });
      if (!remaining.length) {
        finalizeScrape(state);
      } else {
        navigateToList(state);
      }
      return;
    }

    let detail = null;
    for (let attempt = 0; attempt < 3; attempt += 1) {
      await waitForProfileReady(TIMING.profileReadyBaseMs + attempt * TIMING.profileReadyExtraMs);
      try {
        detail = extractProfileDetails(document, location.href, item.name);
      } catch (error) {
        console.warn('[LS][Yelp] Failed to extract profile', error);
      }
      if (detail && detail.name) break;
      await sleep(TIMING.profileRetryPauseMs);
    }

    if (!Array.isArray(state.results)) state.results = [];

    const processedCountBefore = state.results.length;
    const displayIndex = processedCountBefore + 1;

    const record = detail || {
      name: cleanText(item.name || document.title || `Listing ${displayIndex}`) || `Listing ${displayIndex}`,
      rating: '',
      reviewsText: '',
      reviews: '',
      hours: '',
      phone: '',
      websiteUrl: '',
      website: '',
      websiteLabel: '',
      address: '',
      profileUrl: item.profileUrl || location.href,
      canonical: item.canonical || key || (item.profileUrl ? normalizeProfileUrl(item.profileUrl) : '')
    };

    if (!record.profileUrl) record.profileUrl = location.href;
    if (!record.canonical && item?.canonical) record.canonical = item.canonical;

    const label = record.name || `Listing ${displayIndex}`;

    state.results.push(record);
    state.totalExpected = Math.max(state.totalExpected || 0, state.results.length, state.items?.length || 0);
    reportProgress(state, item, record, displayIndex);
    if (detail && detail.name) {
      setStatus(`Captured ${label}. Returning to results…`);
    } else {
      console.warn('[LS][Yelp] Partial capture for', label);
      setStatus(`Captured limited data for ${label}. Returning…`);
    }

    const processedKey = record.canonical || record.profileUrl || label;
    if (!state.processed) state.processed = {};
    if (processedKey) {
      const previous = state.processed[processedKey];
      state.processed[processedKey] = {
        status: 'done',
        completedAt: Date.now(),
        startedAt: previous?.startedAt || null,
        pageUrl: previous?.pageUrl || state.listUrl || '',
        error: null
      };
      if (state.queueSet) delete state.queueSet[processedKey];
    }
    state.index = state.results.length;
    state.currentIndex = null;
    state.currentKey = null;
    saveSession(state);

    await sleep(TIMING.postCapturePauseMs);
    resumeTriggered = false;
    navigateToList(state);
  };

  const continueFromList = async (state) => {
    if (!state || state.mode !== 'running') return;
    ensureStartEvent(state);
    ensurePaginationState(state);
    ensureQueueState(state);
    if (!Array.isArray(state.order)) state.order = [];
    if (!state.lookup) state.lookup = {};
    if (!state.items) state.items = [];
    if (!state.processed) state.processed = {};

    const now = Date.now();
    if (state.activeNavigation && state.activeNavigation.startedAt) {
      const elapsedNav = now - state.activeNavigation.startedAt;
      if (elapsedNav < 20000) {
        resumeTriggered = false;
        return;
      }
      const stalledKey = state.activeNavigation.key || null;
      if (stalledKey) {
        const stalledItem = state.lookup?.[stalledKey] || null;
        const label = cleanText(stalledItem?.name || stalledItem?.profileUrl || stalledKey || 'listing');
        const processedMeta = state.processed[stalledKey] || {};
        const attempts = (processedMeta.navigationAttempts || 0) + 1;
        processedMeta.navigationAttempts = attempts;
        console.warn('[LS][Yelp] Navigation retry for', stalledKey, 'attempt', attempts);
        const maxAttempts = 3;
        if (attempts >= maxAttempts) {
          processedMeta.status = 'skipped';
          processedMeta.completedAt = Date.now();
          processedMeta.error = 'navigation_failed';
          state.processed[stalledKey] = processedMeta;

          const placeholder = {
            name: label || `Listing ${state.results?.length ? state.results.length + 1 : 1}`,
            rating: '',
            reviewsText: '',
            reviews: '',
            hours: '',
            phone: '',
            websiteUrl: '',
            website: '',
            websiteLabel: '',
            address: '',
            profileUrl: stalledItem?.profileUrl || '',
            canonical: stalledItem?.canonical || stalledKey,
            error: 'navigation_failed'
          };
          if (!Array.isArray(state.results)) state.results = [];
          state.results.push(placeholder);
          state.totalExpected = Math.max(state.totalExpected || 0, state.results.length, state.items?.length || 0);
          reportProgress(state, stalledItem, placeholder, state.results.length);
          setStatus(`Skipped ${label} after multiple navigation attempts.`);
          if (state.queueSet) delete state.queueSet[stalledKey];
          saveSession(state);
        } else {
          processedMeta.status = 'retrying';
          delete processedMeta.error;
          state.processed[stalledKey] = processedMeta;
          ensureQueueState(state);
          if (!state.queueSet[stalledKey]) {
            state.queue.unshift(stalledKey);
            state.queueSet[stalledKey] = true;
          }
          setStatus(`Retrying ${label}…`);
          saveSession(state);
        }
      }
      state.activeNavigation = null;
      saveSession(state);
    }

    const pagination = state.pagination;

    if (pagination.advancing) {
      const currentUrlNormalized = normalizeSearchListUrl(location.href);
      const fromNormalized = normalizeSearchListUrl(pagination.from || '');
      const targetNormalized = normalizeSearchListUrl(pagination.target || '');
      const changed = currentUrlNormalized !== fromNormalized || (pagination.target && currentUrlNormalized === targetNormalized);
      const elapsed = now - (pagination.startedAt || 0);
      if (changed) {
        pagination.advancing = false;
        pagination.from = currentUrlNormalized;
        pagination.target = '';
        pagination.startedAt = 0;
        pagination.lastUrl = currentUrlNormalized;
        saveSession(state);
      } else if (elapsed < 1400) {
        resumeTriggered = false;
        return;
      } else if (elapsed > 20000) {
        console.warn('[LS][Yelp] Pagination advance timed out; retrying');
        pagination.advancing = false;
        pagination.target = '';
        pagination.startedAt = 0;
        saveSession(state);
      } else {
        resumeTriggered = false;
        return;
      }
    }

    recordCurrentListPage(state);
    collectPaginationCandidates(state);
    saveSession(state);

    try {
      await refreshStateItems(state, { ensureNew: true, attempts: 10 });
    } catch (error) {
      console.warn('[LS][Yelp] refresh items failed', error);
    }

    collectPaginationCandidates(state);
    saveSession(state);

    let next = await takeNextListing(state, { attempts: 18, delayMs: 480 });
    if (next) {
      const key = next.canonical || next.profileUrl || next.name;
      const completedCount = Array.isArray(state.results) ? state.results.length : 0;
      const remaining = state.queue?.length || 0;
      const total = state.totalExpected || state.items.length || completedCount + remaining + 1;
      const label = next.name || `Listing ${completedCount + 1}`;
      setStatus(`Opening ${label} (${completedCount + 1}/${total})…`);

      state.processed[key] = { status: 'pending', startedAt: now, pageUrl: location.href };
      state.currentIndex = state.items.indexOf(next);
      state.currentKey = key;
      state.index = completedCount;
      state.activeNavigation = { key, startedAt: now, target: next.profileUrl, fallbackScheduled: false };
      saveSession(state);
      resumeTriggered = false;

      const fallbackDelayMs = 1800;
      const fallbackUrl = next.profileUrl;
      setTimeout(() => {
        try {
          const latest = loadSession();
          if (!latest || latest.mode !== 'running') return;
          const nav = latest.activeNavigation;
          if (!nav || nav.key !== key) return;
          if (nav.fallbackScheduled) return;
          if (isProfilePage()) return;
          nav.fallbackScheduled = true;
          latest.activeNavigation = nav;
          saveSession(latest);
          const candidate = nav.target || fallbackUrl;
          if (!candidate) return;

          const selectors = [];
          try {
            const parsed = new URL(candidate, location.origin);
            const path = parsed.pathname || '';
            const search = parsed.search || '';
            if (path) {
              const escapedPath = cssEscape(path);
              selectors.push(`a[href="${path}"]`, `a[href^="${escapedPath}"]`, `a[href*="${escapedPath}"]`);
              if (search) {
                const pathSearch = `${path}${search}`;
                const escapedPathSearch = cssEscape(pathSearch);
                selectors.unshift(`a[href="${pathSearch}"]`);
                selectors.push(`a[href*="${escapedPathSearch}"]`);
              }
            }
            const escapedAbsolute = cssEscape(parsed.href);
            selectors.push(`a[href="${parsed.href}"]`, `a[href*="${escapedAbsolute}"]`);
          } catch (_) {
            const escapedCandidate = cssEscape(candidate);
            selectors.push(`a[href="${candidate}"]`, `a[href*="${escapedCandidate}"]`);
          }

          let anchor = null;
          for (const selector of selectors) {
            if (!selector) continue;
            anchor = document.querySelector(selector);
            if (anchor) break;
          }
          if (!anchor) {
            location.assign(candidate);
            return;
          }
          try {
            anchor.removeAttribute('target');
          } catch (_) {}
          anchor.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
          if (typeof anchor.click === 'function') {
            anchor.click();
          }
        } catch (error) {
          console.warn('[LS][Yelp] Navigation fallback failed', error);
        }
      }, fallbackDelayMs);

      try {
        location.assign(next.profileUrl);
      } catch (_) {
        location.href = next.profileUrl;
      }
      return;
    }

    const advanced = await advanceToNextPage(state);
    if (advanced) {
      resumeTriggered = false;
      return;
    }

    finalizeScrape(state);
  };

  let resumeTriggered = false;
  function resumeScrapeFromSession() {
    if (resumeTriggered) return;
    const state = loadSession();
    if (!state || state.mode !== 'running') return;
    resumeTriggered = true;
    setBusy(true);
    if (isProfilePage()) {
      processProfilePage(state).catch((error) => {
        console.warn('[LS][Yelp] Profile processing failed', error);
        reportError(state, error?.message || 'Failed to scrape profile.');
      });
    } else {
      continueFromList(state).catch((error) => {
        console.warn('[LS][Yelp] Resume continue failed', error);
      });
    }
  }

  const runScrape = async () => {
    if (refreshVerificationState()) {
      const message = 'Yelp is verifying your browser. Complete the challenge, then reload the results and try again.';
      setStatus(message);
      return { ok: false, message };
    }

    const existing = loadSession();
    if (existing && existing.mode === 'running') {
      const message = 'Scrape already in progress. Finishing the current queue…';
      setStatus(message);
      return { ok: false, message };
    }

    attachUi();
    refreshVerificationState();

    const state = {
      mode: 'running',
      items: [],
      order: [],
      lookup: {},
      seen: {},
      processed: {},
      index: 0,
      currentIndex: null,
      currentKey: null,
      results: [],
      listUrl: location.href,
      startedAt: Date.now(),
      startNotified: false,
      pagination: {
        pagesVisited: [],
        pending: [],
        pendingSet: {},
        visitedSet: {},
        advancing: false,
        from: '',
        target: '',
        startedAt: 0,
        lastUrl: normalizeSearchListUrl(location.href),
        currentPage: derivePageNumberFromUrl(location.href) || null,
        discoveryCounter: 0
      },
      queue: [],
      queueSet: {},
      activeNavigation: null,
      runId: `run-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
    };

    ensureQueueState(state);
    ensurePaginationState(state);

    await refreshStateItems(state, { ensureNew: true });
    recordCurrentListPage(state);
    collectPaginationCandidates(state);

    if (!state.totalExpected) state.totalExpected = state.items.length;

    if (!state.items.length) {
      const message = 'No organic listings detected. Scroll the results into view and try again.';
      setStatus(message, { error: true });
      clearSession();
      setBusy(false);
      return { ok: false, message };
    }

    saveSession(state);
    resumeTriggered = false;
    setBusy(true);
    setStatus(`Preparing to scrape ${state.items.length} businesses…`);
    await continueFromList(state);

    const message = `Scrape started for ${state.items.length} businesses.`;
    return { ok: true, message, count: state.items.length };
  };

  button.addEventListener('click', () => {
    runScrape();
  });

  const runInitialSetup = () => {
    attachUi();
    refreshVerificationState();
    resumeScrapeFromSession();
  };

  const observer = new MutationObserver(() => {
    attachUi();
    refreshVerificationState();
    resumeScrapeFromSession();
  });

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', runInitialSetup, { once: true });
  } else {
    runInitialSetup();
  }

  observer.observe(document.documentElement, { childList: true, subtree: true });

  if (isEmbedded) {
    window.addEventListener('message', (event) => {
      if (!event || !event.data || typeof event.data !== 'object') return;
      if (event.source !== window.parent) return;
      if (extensionOrigin && event.origin && event.origin !== extensionOrigin) return;
      if (event.data.type !== 'ls-yelp-start') return;
      runScrape().then((result) => {
        if (!result) return;
        if (!result.ok) {
          notifyParentStatus({ status: 'error', message: result.message });
        }
      });
    });
  }

  if (chrome?.runtime?.onMessage) {
    chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
      if (!message || typeof message !== 'object') return;
      if (message.type === 'yelp-ensure-overlay') {
        attachUi();
        const verifying = refreshVerificationState();
        setBusy(false);
        if (!verifying) {
          setStatus(defaultStatus);
        }
        if (sendResponse) sendResponse({ ok: true });
        return;
      }
      if (message.type === 'yelp-trigger-scrape') {
        attachUi();
        runScrape().then((result) => {
          if (sendResponse) sendResponse(result || { ok: false });
        });
        return true;
      }
    });
  }

  window.addEventListener('beforeunload', () => {
    try { observer.disconnect(); } catch (_) {}
  });
})();
