(function () {
  // Set up logging bridge to Objective-C with fallback to console FIRST
  const log = (message) => {
    // Try to send to Objective-C first (legacy WebView approach)
    if (window.styleStealer && window.styleStealer.log) {
      try {
        window.styleStealer.log(message);
      } catch (e) {
        console.log("[Style Stealer JS] " + message);
      }
    } else {
      console.log("[Style Stealer JS] " + message);
    }
  };

  // Test the bridge with a simple message first
  log("BRIDGE_TEST_MESSAGE");
  log("=== Style extraction started ===");

  // Block all media loading to prevent Security framework crashes
  log("Setting up comprehensive media blocking...");

  // Replace images with gray placeholders
  const images = document.querySelectorAll("img");
  images.forEach((img) => {
    const width = img.naturalWidth || img.width || 200;
    const height = img.naturalHeight || img.height || 150;
    const placeholder = document.createElement("div");
    placeholder.style.cssText = `
      width: ${width}px;
      height: ${height}px;
      background-color: #f0f0f0;
      border: 1px solid #ccc;
      display: flex;
      align-items: center;
      justify-content: center;
      color: #666;
      font-family: Arial, sans-serif;
      font-size: 12px;
      text-align: center;
    `;
    placeholder.textContent = `[IMAGE ${width}x${height}]`;
    img.parentNode.replaceChild(placeholder, img);
  });

  // Block video, audio, and other media elements
  const mediaElements = document.querySelectorAll(
    'video, audio, iframe[src*="youtube"], iframe[src*="vimeo"], iframe[src*="player"], embed, object, iframe[src*="embed"], iframe[src*="video"], iframe[src*="audio"]'
  );
  mediaElements.forEach((element) => {
    element.style.display = "none";
    element.remove();
  });

  // Also block any iframes that might contain media
  const allIframes = document.querySelectorAll("iframe");
  allIframes.forEach((iframe) => {
    const src = iframe.src || iframe.getAttribute("data-src") || "";
    if (
      src.includes("youtube") ||
      src.includes("vimeo") ||
      src.includes("player") ||
      src.includes("embed") ||
      src.includes("video") ||
      src.includes("audio") ||
      src.includes("streaming") ||
      src.includes("media")
    ) {
      log(`Blocking iframe with media-related src: ${src}`);
      iframe.style.display = "none";
      iframe.remove();
    }
  });

  // Prevent new media elements from loading
  const originalCreateElement = document.createElement;
  document.createElement = function (tagName) {
    const element = originalCreateElement.call(this, tagName);
    if (
      ["video", "audio", "iframe", "embed", "object"].includes(
        tagName.toLowerCase()
      )
    ) {
      element.style.display = "none";
      // Block src loading
      Object.defineProperty(element, "src", {
        set: function () {
          /* block setting src */
        },
        get: function () {
          return "";
        },
      });
    }
    return element;
  };

  // Block media-related network requests
  const originalFetch = window.fetch;
  window.fetch = function (url, options) {
    if (
      typeof url === "string" &&
      (url.includes(".mp4") ||
        url.includes(".webm") ||
        url.includes(".ogg") ||
        url.includes(".avi") ||
        url.includes(".mov") ||
        url.includes(".wmv") ||
        url.includes("youtube.com") ||
        url.includes("vimeo.com") ||
        url.includes("player") ||
        url.includes("embed"))
    ) {
      log(`Blocked media request: ${url}`);
      return Promise.reject(new Error("Media request blocked"));
    }
    return originalFetch.call(this, url, options);
  };

  // Try to prevent UsageTracking framework initialization
  try {
    // Override MediaToolbox and VideoToolbox related functions if they exist
    if (window.MediaToolbox) {
      window.MediaToolbox = undefined;
    }
    if (window.VideoToolbox) {
      window.VideoToolbox = undefined;
    }

    // Override any video/audio related APIs that might trigger UsageTracking
    if (window.HTMLVideoElement) {
      const originalVideoElement = window.HTMLVideoElement;
      window.HTMLVideoElement = function () {
        const element = new originalVideoElement();
        element.load = function () {
          /* block */
        };
        element.play = function () {
          /* block */
        };
        return element;
      };
    }

    if (window.HTMLAudioElement) {
      const originalAudioElement = window.HTMLAudioElement;
      window.HTMLAudioElement = function () {
        const element = new originalAudioElement();
        element.load = function () {
          /* block */
        };
        element.play = function () {
          /* block */
        };
        return element;
      };
    }

    log("UsageTracking prevention measures applied");
  } catch (e) {
    log("Could not apply UsageTracking prevention: " + e.message);
  }

  log("Media blocking setup complete");

  // Elements we want to capture styles for
  const targetElements = [
    "body",
    "h1",
    "h2",
    "h3",
    "h4",
    "h5",
    "h6",
    "p",
    "blockquote",
    "code",
    "pre",
    "ul",
    "ol",
    "li",
    "dl",
    "dt",
    "dd",
    "table",
    "th",
    "td",
    "a",
    "strong",
    "em",
    "u",
    "s",
    "ins",
    "del",
    "mark",
    "small",
    "sub",
    "sup",
    "abbr",
    "hr",
    "details",
    "summary",
  ];
  const testClasses = [
    "critic-comment",
    "critic-highlight",
    "critic-substitution",
    "task-list-item",
    "footnote",
    "footnote-ref",
    "highlight",
    "spoiler",
  ];
  const styles = {};
  const fonts = {
    imports: [],
    fontFaces: [],
  };

  // CSS properties we want to extract
  const relevantProperties = [
    "font-family",
    "font-size",
    "font-weight",
    "font-style",
    "color",
    "background",
    "background-color",
    "text-align",
    "text-decoration",
    "text-decoration-line",
    "text-decoration-style",
    "text-decoration-color",
    "text-transform",
    "line-height",
    "letter-spacing",
    "word-spacing",
    "margin",
    "margin-top",
    "margin-right",
    "margin-bottom",
    "margin-left",
    "padding",
    "padding-top",
    "padding-right",
    "padding-bottom",
    "padding-left",
    "border",
    "border-top",
    "border-right",
    "border-bottom",
    "border-left",
    "border-radius",
    "box-shadow",
    "text-shadow",
    "transition",
    "float",
    "content", // Important for ::before and ::after
    "z-index", // Important for pseudo-elements
    "max-width", // Important for responsive design
  ];

  // State variables for manual selection
  let contentContainer = null;
  let displayTimer = null;
  let display = null;
  let last = null;
  let isSelectionMode = true;
  let isCommandHeld = false;
  let originalEventListeners = new Map();
  let globalEventListeners = {
    keydown: null,
    keyup: null,
    mousedown: null,
    click: null,
  };

  // Inject highlight styles into the head
  function injectHighlightStyles() {
    // Check if styles already exist
    if (document.getElementById("style-stealer-highlight-styles")) {
      return;
    }

    const style = document.createElement("style");
    style.id = "style-stealer-highlight-styles";
    style.textContent = `
      .content-select-highlight {
        outline: 2px solid #b8860b !important;
        background-color: #fffacd !important;
      }
    `;
    document.head.appendChild(style);
    log("Highlight styles injected into head");
  }

  // Create the instruction display
  function createInstructionDisplay() {
    // If host app provides a shared status bar, bind to it and skip legacy bar
    if (
      typeof window.__mkExternalStatusBar !== "undefined" &&
      window.__mkExternalStatusBar
    ) {
      const shared = document.getElementById("mk-extractor-status");
      if (shared) {
        display = shared;
        display.style.display = "block";
      }
      return;
    }
    log("Creating instruction display");
    display = document.createElement("div");
    display.style.position = "fixed";
    display.style.top = "0";
    display.style.left = "0";
    display.style.right = "0";
    display.style.background = "hsla(196, 100%, 68%, 0.90)";
    display.style.color = "#333";
    display.style.display = "block";
    display.style.fontFamily = "helvetica, arial, sans-serif";
    display.style.fontSize = "14px";
    display.style.fontWeight = "600";
    display.style.height = "40px";
    display.style.margin = "0";
    display.style.overflow = "hidden";
    display.style.padding = "10px";
    display.style.textAlign = "center";
    display.style.zIndex = "10000";
    display.innerHTML =
      "Hover over content areas to highlight them, then click to select the main content area — ⌘-Click to Navigate";

    document.body.prepend(display);
    log(
      `Instruction display created and added to body. Background: ${display.style.background}`
    );
  }

  // Check if Command key is held down
  function isCommandKeyHeld(event) {
    return event.metaKey || event.ctrlKey; // metaKey for Mac, ctrlKey for Windows/Linux
  }

  // Temporarily disable selection interface for navigation
  function disableSelectionForNavigation() {
    if (isCommandHeld) return; // Already disabled

    isCommandHeld = true;
    log(
      "Command key detected - temporarily disabling selection interface for navigation"
    );

    // Clear any existing highlights
    const highlightedElements = document.querySelectorAll(
      ".content-select-highlight"
    );
    highlightedElements.forEach(function (el) {
      el.classList.remove("content-select-highlight");
    });

    // Update instruction display
    if (display) {
      display.innerHTML =
        "⌘-Click to Navigate — Release ⌘ to resume selection";
      display.style.backgroundColor = "#ff6b35"; // Orange to indicate navigation mode
    }

    // Remove mouseover/mouseout listeners from document body
    document.body.removeEventListener("mouseover", addHighlight, true);
    document.body.removeEventListener("mouseout", removeHighlight, true);

    // Keep document-level click interception in place. It already allows
    // Command-click navigation and blocks normal click navigation.
  }

  // Re-enable selection interface
  function enableSelectionForSelection() {
    if (!isCommandHeld) return; // Already enabled

    isCommandHeld = false;
    log("Command key released - re-enabling selection interface");

    // Update instruction display
    if (display) {
      display.innerHTML =
        "Hover over content areas to highlight them, then click to select the main content area — ⌘-Click to Navigate";
      display.style.backgroundColor = "hsla(196, 100%, 68%, 0.90)"; // Back to blue
    }

    // Restore mouseover/mouseout listeners to document body
    document.body.addEventListener("mouseover", addHighlight, true);
    document.body.addEventListener("mouseout", removeHighlight, true);

    // Clear stored listeners
    originalEventListeners.clear();
  }

  // Find the nearest container element (DIV, ARTICLE, SECTION, MAIN)
  function findNearestContainer(element) {
    if (
      window.__mkSelectionShared &&
      window.__mkSelectionShared.findNearestContainer
    ) {
      return window.__mkSelectionShared.findNearestContainer(element);
    }
    return null;
  }

  // Add yellow outline and background to element on hover
  function addHighlight(ev) {
    // Don't highlight if Command key is held (navigation mode)
    if (isCommandHeld) return;

    const element = ev.target;
    const container = findNearestContainer(element);

    log(
      `addHighlight called on ${element.tagName}, container: ${
        container ? container.tagName : "none"
      }, display exists: ${!!display}`
    );

    if (container) {
      // Remove highlight from any previously highlighted element
      const previousHighlighted = document.querySelector(
        ".content-select-highlight"
      );
      if (previousHighlighted && previousHighlighted !== container) {
        previousHighlighted.classList.remove("content-select-highlight");
      }

      // Add highlight to the container (not the child element)
      container.classList.add("content-select-highlight");
      clearTimeout(displayTimer);

      // Show element info (only if display exists)
      if (display) {
        const rect = container.getBoundingClientRect();
        const elementInfo = `${container.tagName.toLowerCase()}${
          container.className
            ? "." + container.className.split(" ").join(".")
            : ""
        } (${Math.round(rect.width)}x${Math.round(rect.height)})`;
        display.innerHTML = elementInfo;

        last = container;
        displayTimer = setTimeout(function () {
          if (display && !isCommandHeld) {
            display.innerHTML =
              "Hover over content areas to highlight them, then click to select the main content area — ⌘-Click to Navigate";
          }
        }, 1500);
      }
    }
  }

  // Remove outline and background on mouse out
  function removeHighlight(ev) {
    const element = ev.target;
    const container = findNearestContainer(element);
    const currentlyHighlighted = document.querySelector(
      ".content-select-highlight"
    );

    // Only remove highlight if we're moving to a different container or no container at all
    if (currentlyHighlighted && currentlyHighlighted !== container) {
      currentlyHighlighted.classList.remove("content-select-highlight");
      log(
        `Removed highlight from ${currentlyHighlighted.tagName} - moved to different container`
      );
    } else if (element === display) {
      log("Mouse out on instruction box - preserving background");
    } else if (!container && currentlyHighlighted) {
      // Moving outside all containers
      currentlyHighlighted.classList.remove("content-select-highlight");
      log(
        `Removed highlight from ${currentlyHighlighted.tagName} - moved outside all containers`
      );
    }
  }

  // Handle click to select content area
  function findContent(ev) {
    // If Command key is held, allow default link navigation
    if (isCommandKeyHeld(ev)) {
      log("Command+click detected - allowing default link navigation");
      return; // Don't prevent default, let the link navigate
    }

    ev.preventDefault();
    ev.stopPropagation();

    const element = ev.target;
    const container = findNearestContainer(element) || document.body;
    contentContainer = container;
    log(
      `Selected content container: ${container.tagName}${
        container.className ? "." + container.className : ""
      }`
    );

    // Clean up the selection interface
    cleanupSelectionInterface();

    // Start style extraction
    isSelectionMode = false;
    extractStyles();
  }

  // Extract @font-face rules from all stylesheets
  async function extractFonts() {
    log("Extracting custom fonts...");

    // Find Google Fonts imports via <link> tags
    const fontLinks = document.querySelectorAll(
      'link[href*="fonts.googleapis.com"]'
    );
    fontLinks.forEach((link) => {
      const href = link.href;
      log(`Found Google Fonts <link> import: ${href}`);
      fonts.imports.push(href);
    });

    // Find Google Fonts imports via @import statements in CSS
    const styleSheets = Array.from(document.styleSheets);
    log(`Found ${styleSheets.length} stylesheets to check for fonts`);

    for (let i = 0; i < styleSheets.length; i++) {
      const sheet = styleSheets[i];
      try {
        const rules = Array.from(sheet.cssRules || []);
        log(`Checking stylesheet ${i} with ${rules.length} rules`);

        rules.forEach((rule) => {
          // Check for @import rules with Google Fonts
          if (rule.type === CSSRule.IMPORT_RULE) {
            const importUrl = rule.href;
            if (importUrl && importUrl.includes("fonts.googleapis.com")) {
              log(`Found Google Fonts @import: ${importUrl}`);
              fonts.imports.push(importUrl);
            }
          }
          // Check for @font-face rules
          else if (rule.type === CSSRule.FONT_FACE_RULE) {
            const fontFace = rule.cssText;
            log(`Found @font-face rule: ${fontFace}`);
            fonts.fontFaces.push({
              fontFamily: "extracted",
              src: "extracted",
              fullRule: fontFace,
            });
          }
        });
      } catch (e) {
        // Cross-origin stylesheets will throw security errors
        log(`Could not access stylesheet ${i}: ${e.message}`);

        // Try to fetch external stylesheet
        if (sheet.href) {
          try {
            const response = await fetch(sheet.href);
            const cssText = await response.text();
            log(`Fetched external stylesheet: ${sheet.href}`);

            // Extract @import rules using regex
            const importMatches = cssText.match(
              /@import\s+url\(['"]?([^'"]+)['"]?\)/gi
            );
            if (importMatches) {
              importMatches.forEach((match) => {
                const urlMatch = match.match(/url\(['"]?([^'"]+)['"]?\)/i);
                if (
                  urlMatch &&
                  urlMatch[1] &&
                  urlMatch[1].includes("fonts.googleapis.com")
                ) {
                  log(
                    `Found Google Fonts @import in external CSS: ${urlMatch[1]}`
                  );
                  fonts.imports.push(urlMatch[1]);
                }
              });
            }

            // Extract @font-face rules using regex
            const fontFaceMatches = cssText.match(/@font-face\s*\{[^}]*\}/gi);
            if (fontFaceMatches) {
              log(
                `Found ${fontFaceMatches.length} @font-face rules in external stylesheet`
              );
              fontFaceMatches.forEach((match) => {
                // log(`External font-face: ${match}`); // Commented out to reduce log noise
                fonts.fontFaces.push({
                  fontFamily: "extracted",
                  src: "extracted",
                  fullRule: match,
                });
              });
            }
          } catch (fetchError) {
            log(
              `Could not fetch external stylesheet ${sheet.href}: ${fetchError.message}`
            );
          }
        }
      }
    }

    // Check for JavaScript-loaded Google Fonts
    // Look for dynamically added stylesheets that might contain Google Fonts
    const allStylesheets = Array.from(document.styleSheets);
    for (let i = 0; i < allStylesheets.length; i++) {
      const sheet = allStylesheets[i];
      if (sheet.href && sheet.href.includes("fonts.googleapis.com")) {
        log(`Found dynamically loaded Google Fonts stylesheet: ${sheet.href}`);
        if (!fonts.imports.includes(sheet.href)) {
          fonts.imports.push(sheet.href);
        }
      }
    }

    // Check for Google Fonts API calls in script tags
    const scriptTags = document.querySelectorAll("script");
    scriptTags.forEach((script, index) => {
      const scriptContent = script.textContent || script.innerHTML;
      if (scriptContent) {
        // Look for Google Fonts API patterns
        const googleFontsPatterns = [
          /fonts\.googleapis\.com\/css[^"'\s]*/gi,
          /WebFont\.load\s*\(\s*\{[^}]*families[^}]*\}/gi,
          /googleapis\.com\/webfonts/gi,
        ];

        googleFontsPatterns.forEach((pattern, patternIndex) => {
          const matches = scriptContent.match(pattern);
          if (matches) {
            matches.forEach((match) => {
              if (match.includes("fonts.googleapis.com")) {
                log(`Found Google Fonts API call in script ${index}: ${match}`);
                if (!fonts.imports.includes(match)) {
                  fonts.imports.push(match);
                }
              }
            });
          }
        });
      }
    });

    // Also check for @font-face rules in style tags
    const styleTags = document.querySelectorAll("style");
    styleTags.forEach((styleTag, index) => {
      const cssText = styleTag.textContent;
      const fontFaceMatches = cssText.match(/@font-face\s*\{[^}]*\}/gi);
      if (fontFaceMatches) {
        log(
          `Found ${fontFaceMatches.length} @font-face rules in style tag ${index}`
        );
        fontFaceMatches.forEach((match) => {
          log(`Style tag font-face: ${match}`);
          fonts.fontFaces.push(match);
        });
      }
    });
  }

  // Helper function to check if an element is inside a headline
  function isInsideHeadline(element) {
    let parent = element.parentElement;
    while (parent) {
      if (parent.tagName && parent.tagName.match(/^H[1-6]$/)) {
        return true;
      }
      parent = parent.parentElement;
    }
    return false;
  }

  // Helper function to check if an element is inside a paragraph
  function isInsideParagraph(element) {
    let parent = element.parentElement;
    while (parent) {
      if (parent.tagName && parent.tagName.toLowerCase() === "p") {
        return true;
      }
      parent = parent.parentElement;
    }
    return false;
  }

  // Helper function to extract styles from an element
  // Function to filter out inherited and default values
  function filterInheritedAndDefaultValues(
    elementStyles,
    tagName,
    bodyColor = null,
    bodyFontFamily = null
  ) {
    const filtered = {};

    // Define default values for common elements
    const defaultValues = {
      body: {
        margin: "0px",
        padding: "0px",
        "font-family": 'Times, "Times New Roman", serif',
        "font-size": "16px",
        "line-height": "normal",
        color: "rgb(0, 0, 0)",
        "background-color": "rgba(0, 0, 0, 0)",
        "text-align": "start",
      },
      h1: {
        "font-size": "2em",
        "font-weight": "bold",
        margin: "0.67em 0px",
        display: "block",
      },
      h2: {
        "font-size": "1.5em",
        "font-weight": "bold",
        margin: "0.83em 0px",
        display: "block",
      },
      h3: {
        "font-size": "1.17em",
        "font-weight": "bold",
        margin: "1em 0px",
        display: "block",
      },
      h4: {
        "font-size": "1em",
        "font-weight": "bold",
        margin: "1.33em 0px",
        display: "block",
      },
      h5: {
        "font-size": "0.83em",
        "font-weight": "bold",
        margin: "1.67em 0px",
        display: "block",
      },
      h6: {
        "font-size": "0.67em",
        "font-weight": "bold",
        margin: "2.33em 0px",
        display: "block",
      },
      p: {
        margin: "1em 0px",
        display: "block",
      },
      a: {
        color: "rgb(0, 0, 238)",
        "text-decoration": "underline",
        cursor: "pointer",
      },
      strong: {
        "font-weight": "bold",
      },
      em: {
        "font-style": "italic",
      },
      ul: {
        display: "block",
        "list-style-type": "disc",
        margin: "1em 0px",
        "padding-left": "40px",
      },
      ol: {
        display: "block",
        "list-style-type": "decimal",
        margin: "1em 0px",
        "padding-left": "40px",
      },
      li: {
        display: "list-item",
      },
      blockquote: {
        display: "block",
        margin: "1em 40px",
      },
      pre: {
        display: "block",
        "font-family": "monospace",
        "white-space": "pre",
        margin: "1em 0px",
      },
      code: {
        "font-family": "monospace",
      },
    };

    Object.keys(elementStyles).forEach((property) => {
      const value = elementStyles[property];

      // Skip if it's a pseudo-selector (starts with :)
      if (property.startsWith(":")) {
        filtered[property] = value;
        return;
      }

      // Check if this is a default value for this element type
      const elementDefaults = defaultValues[tagName];
      if (elementDefaults && elementDefaults[property] === value) {
        log(`Filtering out default value for ${tagName} ${property}: ${value}`);
        return;
      }

      // Check if this is a common inherited default
      if (isCommonInheritedDefault(property, value, tagName)) {
        log(
          `Filtering out inherited default for ${tagName} ${property}: ${value}`
        );
        return;
      }

      // Filter out color values that match the body color (inherited)
      if (bodyColor && property === "color" && value === bodyColor) {
        log(
          `Filtering out inherited color for ${tagName} ${property}: ${value} (matches body color)`
        );
        return;
      }

      // Filter out font-family values that match the body font-family (inherited)
      if (
        bodyFontFamily &&
        property === "font-family" &&
        value === bodyFontFamily
      ) {
        log(
          `Filtering out inherited font-family for ${tagName} ${property}: ${value} (matches body font-family)`
        );
        return;
      }

      // Keep the property
      filtered[property] = value;
    });

    return filtered;
  }

  // Helper function to identify common inherited defaults
  function isCommonInheritedDefault(property, value, tagName) {
    // Common inherited defaults that are usually not worth capturing
    const inheritedDefaults = {
      "font-family": ['Times, "Times New Roman", serif', "serif"],
      "font-size": ["16px", "medium"],
      "line-height": ["normal"],
      color: ["rgb(0, 0, 0)", "black"],
      "background-color": ["rgba(0, 0, 0, 0)", "transparent"],
      "text-align": ["start", "left"],
      direction: ["ltr"],
      "unicode-bidi": ["normal"],
      "white-space": ["normal"],
      "word-spacing": ["normal"],
      "letter-spacing": ["normal"],
      "text-indent": ["0px", "0"],
      "text-transform": ["none"],
      "text-decoration": ["none solid rgb(0, 0, 0)"],
      "text-shadow": ["none"],
      "border-collapse": ["separate"],
      "border-spacing": ["0px 0px"],
      "caption-side": ["top"],
      "empty-cells": ["show"],
      "table-layout": ["auto"],
      "vertical-align": ["baseline"],
      visibility: ["visible"],
      cursor: ["auto"],
      outline: ["none"],
      "outline-width": ["0px"],
      "outline-style": ["none"],
      "outline-color": ["rgb(0, 0, 0)"],
    };

    const defaults = inheritedDefaults[property];
    if (defaults && defaults.includes(value)) {
      return true;
    }

    // Filter out common "zero" or "none" values
    if (isZeroOrNoneValue(property, value)) {
      return true;
    }

    // Filter out common "normal" or "auto" values
    if (isNormalOrAutoValue(property, value)) {
      return true;
    }

    // Filter out complex default values (may consider tag-specific behavior)
    if (isComplexDefaultValue(property, value, tagName)) {
      return true;
    }

    // Special cases for specific elements
    if (tagName === "a" && property === "cursor" && value === "pointer") {
      return true; // Default for links
    }

    if (
      tagName.match(/^h[1-6]$/) &&
      property === "display" &&
      value === "block"
    ) {
      return true; // Default for headlines
    }

    if (tagName === "p" && property === "display" && value === "block") {
      return true; // Default for paragraphs
    }

    return false;
  }

  // Helper function to identify zero or none values
  function isZeroOrNoneValue(property, value) {
    // Properties that should be filtered when they have zero/none values
    const zeroNoneProperties = [
      "border",
      "border-top",
      "border-right",
      "border-bottom",
      "border-left",
      "border-width",
      "border-top-width",
      "border-right-width",
      "border-bottom-width",
      "border-left-width",
      "border-radius",
      "border-top-left-radius",
      "border-top-right-radius",
      "border-bottom-left-radius",
      "border-bottom-right-radius",
      "padding",
      "padding-top",
      "padding-right",
      "padding-bottom",
      "padding-left",
      "margin",
      "margin-top",
      "margin-right",
      "margin-bottom",
      "margin-left",
      "text-indent",
      "letter-spacing",
      "word-spacing",
      "box-shadow",
      "text-shadow",
      "outline",
      "outline-width",
      "z-index",
    ];

    if (zeroNoneProperties.includes(property)) {
      // Check for zero values
      if (
        value === "0" ||
        value === "0px" ||
        value === "0em" ||
        value === "0rem" ||
        value === "0%"
      ) {
        return true;
      }
      // Check for border properties with 0px width
      if (property.startsWith("border") && value.includes("0px")) {
        return true;
      }
      // Check for none values
      if (value === "none") {
        return true;
      }
      // Check for auto values (for z-index)
      if (property === "z-index" && value === "auto") {
        return true;
      }
    }

    return false;
  }

  // Helper function to identify normal or auto values
  function isNormalOrAutoValue(property, value) {
    // Never treat text-decoration properties as "normal/auto" when they are
    // set to "none" – this is often a deliberate choice (e.g. links with
    // text-decoration: none) that we want to preserve in the extracted styles.
    if (
      property === "text-decoration" ||
      property === "text-decoration-line" ||
      property === "text-decoration-style" ||
      property === "text-decoration-color"
    ) {
      return false;
    }
    // Properties that should be filtered when they have normal/auto values
    const normalAutoProperties = [
      "font-style",
      "font-weight",
      "text-transform",
      "text-decoration",
      "white-space",
      "word-spacing",
      "letter-spacing",
      "line-height",
      "vertical-align",
      "float",
      "clear",
      "overflow",
      "overflow-x",
      "overflow-y",
      "text-align",
      "direction",
      "unicode-bidi",
      "text-indent",
      "border-collapse",
      "border-spacing",
      "table-layout",
      "empty-cells",
      "caption-side",
      "visibility",
      "cursor",
      "outline-style",
      "outline-color",
      "content",
      "max-width",
      "min-width",
      "max-height",
      "min-height",
    ];

    if (normalAutoProperties.includes(property)) {
      if (value === "normal" || value === "auto" || value === "none") {
        return true;
      }
    }

    return false;
  }

  // Helper function to identify complex default values
  function isComplexDefaultValue(property, value, tagName) {
    // Filter out complex background values that are essentially transparent
    if (property === "background" || property === "background-color") {
      if (value.includes("rgba(0, 0, 0, 0)") || value === "transparent") {
        return true;
      }
      // Filter out complex background shorthand that's essentially transparent
      if (
        value.includes(
          "rgba(0, 0, 0, 0) none repeat scroll 0% 0% / auto padding-box border-box"
        )
      ) {
        return true;
      }
    }

    // Filter out complex text-decoration values that are essentially none
    // for non-link elements only. For links, explicit text-decoration values
    // (including "none") are significant and should be preserved so the Style
    // Stealer can detect when underlines are disabled.
    if (property === "text-decoration" || property === "text-decoration-line") {
      if (
        tagName !== "a" &&
        (value === "none" || value.includes("none solid"))
      ) {
        return true;
      }
    }

    // Filter out text-decoration-color that matches the text color (default behavior)
    if (property === "text-decoration-color") {
      // This is usually the same as the text color, so it's redundant
      return true;
    }

    // Filter out text-decoration-style when it's solid (default)
    if (property === "text-decoration-style" && value === "solid") {
      return true;
    }

    // Filter out transition: all (too broad)
    if (property === "transition" && value === "all") {
      return true;
    }

    // Filter out font-weight: 400 (normal)
    if (property === "font-weight" && (value === "400" || value === "normal")) {
      return true;
    }

    // Filter out font-style: normal
    if (property === "font-style" && value === "normal") {
      return true;
    }

    return false;
  }

  function extractStylesFromElement(element, tagName) {
    const computedStyle = window.getComputedStyle(element);
    const elementStyles = {};

    // Skip link, bold, and italic styles if they're inside headlines
    if (
      (tagName === "a" || tagName === "strong" || tagName === "em") &&
      isInsideHeadline(element)
    ) {
      log(`Skipping ${tagName} styles - element is inside a headline`);
      return false;
    }

    // Only extract link, bold, and italic styles if they're inside paragraphs
    if (
      (tagName === "a" || tagName === "strong" || tagName === "em") &&
      !isInsideParagraph(element)
    ) {
      log(`Skipping ${tagName} styles - element is not inside a paragraph`);
      return false;
    }

    relevantProperties.forEach((prop) => {
      const value = computedStyle.getPropertyValue(prop);
      if (
        value &&
        value !== "initial" &&
        value !== "inherit" &&
        // Only filter out transparent background colors, not all rgba(0,0,0,0)
        !(prop.includes("background") && value === "rgba(0, 0, 0, 0)") &&
        // Filter out line-height: 0 which would make text unreadable
        !(
          prop === "line-height" &&
          (value === "0" || value === "0px" || parseFloat(value) === 0)
        ) &&
        // Allow "none" for text-decoration properties
        !(value === "none" && !prop.includes("decoration"))
      ) {
        elementStyles[prop] = value;
      }
    });

    // Capture pseudo-classes and pseudo-elements for all elements
    const pseudoSelectors = [
      ":hover",
      ":active",
      ":focus",
      ":focus-within",
      ":link", // Only applies to links
      ":visited", // Only applies to links
    ];

    const pseudoElements = ["::before", "::after"];

    // Only check :link and :visited for anchor tags
    const applicablePseudoSelectors =
      tagName === "a"
        ? pseudoSelectors
        : pseudoSelectors.filter(
            (selector) =>
              !selector.includes("link") && !selector.includes("visited")
          );

    log(
      `Processing pseudo-classes and pseudo-elements for ${tagName} element with ${
        Object.keys(elementStyles).length
      } base styles`
    );

    // Capture pseudo-classes
    applicablePseudoSelectors.forEach((pseudoClass) => {
      const pseudoStyle = window.getComputedStyle(element, pseudoClass);
      const pseudoStyles = {};

      relevantProperties.forEach((prop) => {
        const value = pseudoStyle.getPropertyValue(prop);
        if (
          value &&
          value !== "initial" &&
          value !== "inherit" &&
          // Only filter out transparent background colors, not all rgba(0,0,0,0)
          !(prop.includes("background") && value === "rgba(0, 0, 0, 0)") &&
          value !== elementStyles[prop] && // Only include if different from base
          // Filter out line-height: 0 which would make text unreadable
          !(
            prop === "line-height" &&
            (value === "0" || value === "0px" || parseFloat(value) === 0)
          ) &&
          // Allow "none" for text-decoration properties
          !(value === "none" && !prop.includes("decoration"))
        ) {
          pseudoStyles[prop] = value;
          log(
            `Found ${pseudoClass} difference for ${prop}: ${elementStyles[prop]} -> ${value}`
          );
        }
      });

      if (Object.keys(pseudoStyles).length > 0) {
        elementStyles[pseudoClass] = pseudoStyles;
        log(
          `Found ${pseudoClass} styles for ${tagName}: ${Object.keys(
            pseudoStyles
          ).join(", ")}`
        );
      } else {
        log(`No ${pseudoClass} styles found for ${tagName}`);
      }
    });

    // Capture pseudo-elements with enhanced filtering
    pseudoElements.forEach((pseudoElement) => {
      const pseudoStyle = window.getComputedStyle(element, pseudoElement);
      const pseudoStyles = {};

      // Check if pseudo-element is actually defined (has meaningful content or display)
      const content = pseudoStyle.getPropertyValue("content");
      const display = pseudoStyle.getPropertyValue("display");

      // Skip pseudo-elements that are not actually defined
      if (content === "none" && display === "none") {
        log(
          `Skipping ${pseudoElement} - not defined (content: none, display: none)`
        );
        return;
      }

      // Skip pseudo-elements with only default/empty content
      if (content === "none" || content === '""' || content === "''") {
        log(`Skipping ${pseudoElement} - no meaningful content`);
        return;
      }

      relevantProperties.forEach((prop) => {
        const value = pseudoStyle.getPropertyValue(prop);
        if (
          value &&
          value !== "initial" &&
          value !== "inherit" &&
          // For pseudo-elements, be more selective about what we capture
          !(
            prop === "content" &&
            (value === "none" || value === '""' || value === "''")
          ) && // Skip empty content
          !(prop === "display" && value === "none") && // Skip hidden pseudo-elements
          // Only filter out transparent background colors, not all rgba(0,0,0,0)
          !(prop.includes("background") && value === "rgba(0, 0, 0, 0)") &&
          // Filter out line-height: 0 which would make text unreadable
          !(
            prop === "line-height" &&
            (value === "0" || value === "0px" || parseFloat(value) === 0)
          ) &&
          // Skip default values that are the same as the base element
          value !== elementStyles[prop]
        ) {
          pseudoStyles[prop] = value;
          log(`Found ${pseudoElement} style for ${prop}: ${value}`);
        }
      });

      // Only include pseudo-element if it has meaningful styles
      if (Object.keys(pseudoStyles).length > 0) {
        elementStyles[pseudoElement] = pseudoStyles;
        log(
          `Found ${pseudoElement} styles for ${tagName}: ${Object.keys(
            pseudoStyles
          ).join(", ")}`
        );
      } else {
        log(`No meaningful ${pseudoElement} styles found for ${tagName}`);
      }
    });

    if (Object.keys(elementStyles).length > 0) {
      styles[tagName] = elementStyles;
      log(
        `Extracted styles for ${tagName}: ${Object.keys(elementStyles).join(
          ", "
        )}`
      );

      // Special debugging for headlines and links
      if (tagName.match(/^h[1-6]$/)) {
        log(`HEADLINE DEBUG - ${tagName}:`);
        log(`  font-size: ${elementStyles["font-size"] || "NOT FOUND"}`);
        log(`  font-weight: ${elementStyles["font-weight"] || "NOT FOUND"}`);
        log(`  color: ${elementStyles["color"] || "NOT FOUND"}`);
        log(`  margin: ${elementStyles["margin"] || "NOT FOUND"}`);
        log(`  line-height: ${elementStyles["line-height"] || "NOT FOUND"}`);
      }

      if (tagName === "a") {
        log(`LINK DEBUG - a tag:`);
        log(`  color: ${elementStyles["color"] || "NOT FOUND"}`);
        log(
          `  text-decoration: ${
            elementStyles["text-decoration"] || "NOT FOUND"
          }`
        );
        log(`  font-weight: ${elementStyles["font-weight"] || "NOT FOUND"}`);
        log(`  border: ${elementStyles["border"] || "NOT FOUND"}`);
        log(`  Total base styles: ${Object.keys(elementStyles).length}`);
        log(`  All base styles: ${Object.keys(elementStyles).join(", ")}`);
      }

      // Filter out inherited and default values
      const bodyColor =
        styles.body && styles.body.color ? styles.body.color : null;
      const bodyFontFamily =
        styles.body && styles.body["font-family"]
          ? styles.body["font-family"]
          : null;
      const filteredStyles = filterInheritedAndDefaultValues(
        elementStyles,
        tagName,
        bodyColor,
        bodyFontFamily
      );

      if (Object.keys(filteredStyles).length > 0) {
        styles[tagName] = filteredStyles;
        log(
          `Filtered styles for ${tagName}: ${Object.keys(filteredStyles).join(
            ", "
          )}`
        );
        return true;
      } else {
        log(`No meaningful styles after filtering for ${tagName}`);
        return false;
      }
    }
    return false;
  }

  // Helper function to find the most common paragraph styles using majority voting
  function findMajorityParagraphStyles(paragraphStyles) {
    log(`Finding majority styles from ${paragraphStyles.length} paragraphs`);

    if (paragraphStyles.length === 0) {
      log(`No paragraph styles provided for majority voting`);
      return {};
    }

    // Count occurrences of each property-value combination
    const propertyCounts = {};

    paragraphStyles.forEach((style, index) => {
      Object.keys(style).forEach((prop) => {
        const value = style[prop];
        const key = `${prop}:${value}`;

        if (!propertyCounts[key]) {
          propertyCounts[key] = { count: 0, property: prop, value: value };
        }
        propertyCounts[key].count++;
      });
    });

    // Find the most common value for each property
    const majorityStyles = {};
    const propertyGroups = {};

    // Group by property
    Object.keys(propertyCounts).forEach((key) => {
      const { property, value, count } = propertyCounts[key];
      if (!propertyGroups[property]) {
        propertyGroups[property] = [];
      }
      propertyGroups[property].push({ value, count });
    });

    // For each property, find the value with the highest count
    Object.keys(propertyGroups).forEach((prop) => {
      const values = propertyGroups[prop];
      values.sort((a, b) => b.count - a.count); // Sort by count descending

      const mostCommon = values[0];
      const majorityThreshold = Math.ceil(paragraphStyles.length / 2); // More than half

      // Only include properties that appear in the majority of paragraphs
      if (mostCommon.count >= majorityThreshold) {
        majorityStyles[prop] = mostCommon.value;
        log(
          `Property ${prop}: majority value "${mostCommon.value}" (${mostCommon.count}/${paragraphStyles.length} paragraphs)`
        );
      } else {
        log(
          `Property ${prop}: no majority found, most common "${mostCommon.value}" (${mostCommon.count}/${paragraphStyles.length} paragraphs) - skipping`
        );
      }
    });

    log(
      `Majority voting complete: ${
        Object.keys(majorityStyles).length
      } properties identified with majority support`
    );
    return majorityStyles;
  }

  // Helper function to inject and test a missing element
  function injectAndTestElement(tagName) {
    if (tagName === "p") {
      // For paragraphs, inject 5 at the beginning to capture first-child styles and find majority normal styles
      log(
        `Injecting 5 paragraphs at beginning to capture first-child vs normal paragraph styles using majority voting`
      );

      // Check if there are existing paragraphs in the container
      const existingParagraphs = contentContainer.querySelectorAll("p");
      log(
        `Found ${existingParagraphs.length} existing paragraphs in content container`
      );

      // If we have at least 5 existing paragraphs, use them for majority voting
      if (existingParagraphs.length >= 5) {
        log(
          `Using existing paragraphs for majority voting style extraction (${existingParagraphs.length} found)`
        );

        // Extract styles from all existing paragraphs
        const paragraphStyles = [];
        for (let i = 0; i < Math.min(existingParagraphs.length, 10); i++) {
          const paragraph = existingParagraphs[i];
          const computedStyle = window.getComputedStyle(paragraph);
          const paragraphStyle = {};

          relevantProperties.forEach((prop) => {
            const value = computedStyle.getPropertyValue(prop);
            if (
              value &&
              value !== "initial" &&
              value !== "inherit" &&
              value !== "rgba(0, 0, 0, 0)"
            ) {
              paragraphStyle[prop] = value;
            }
          });

          paragraphStyles.push(paragraphStyle);
          log(
            `Extracted styles from existing paragraph ${i + 1}: ${
              Object.keys(paragraphStyle).length
            } properties`
          );
        }

        // Find the most common style pattern using majority voting
        const majorityStyles = findMajorityParagraphStyles(paragraphStyles);

        // Check for first-child specific styles by comparing first paragraph with majority
        const firstParagraphStyles = paragraphStyles[0];
        const firstChildStyles = {};
        Object.keys(firstParagraphStyles).forEach((prop) => {
          if (firstParagraphStyles[prop] !== majorityStyles[prop]) {
            firstChildStyles[prop] = firstParagraphStyles[prop];
            log(
              `First paragraph has different ${prop}: ${firstParagraphStyles[prop]} vs ${majorityStyles[prop]}`
            );
          }
        });

        // Also check for :first-letter styles on the first paragraph
        const firstLetterStyles = {};
        const firstLetterStyle = window.getComputedStyle(
          existingParagraphs[0],
          "::first-letter"
        );
        relevantProperties.forEach((prop) => {
          const value = firstLetterStyle.getPropertyValue(prop);
          if (
            value &&
            value !== "initial" &&
            value !== "inherit" &&
            value !== "rgba(0, 0, 0, 0)"
          ) {
            firstLetterStyles[prop] = value;
          }
        });

        // Add first-of-type styles if any differences found
        if (Object.keys(firstChildStyles).length > 0) {
          styles["#wrapper>p:first-of-type"] = firstChildStyles;
          log(
            `Added #wrapper>p:first-of-type styles from existing paragraphs: ${Object.keys(
              firstChildStyles
            ).join(", ")}`
          );
        }

        // Add first-letter styles if any found
        if (Object.keys(firstLetterStyles).length > 0) {
          styles["#wrapper>p:first-of-type::first-letter"] = firstLetterStyles;
          log(
            `Added #wrapper>p:first-of-type::first-letter styles from existing paragraphs: ${Object.keys(
              firstLetterStyles
            ).join(", ")}`
          );
        }

        // Use majority styles for normal paragraph styles
        log(
          `Using majority paragraph styles for normal paragraph styling (${
            Object.keys(majorityStyles).length
          } properties)`
        );

        // Add the majority styles directly to the styles object
        if (Object.keys(majorityStyles).length > 0) {
          styles["p"] = majorityStyles;
          log(`Successfully extracted majority paragraph styles`);
        } else {
          log(`No majority paragraph styles found`);
        }

        return; // Exit early since we used existing paragraphs
      }

      // Create 5 test paragraphs
      const testParagraphs = [];
      for (let i = 0; i < 5; i++) {
        const p = document.createElement("p");
        p.textContent = `Test paragraph ${i + 1}`;
        p.style.display = "block";
        p.style.visibility = "hidden";
        p.style.position = "absolute";
        p.style.left = "-9999px";
        testParagraphs.push(p);
      }

      // Insert all paragraphs at the beginning of the content container
      // Insert in reverse order so p1 becomes first-child
      for (let i = testParagraphs.length - 1; i >= 0; i--) {
        contentContainer.insertBefore(
          testParagraphs[i],
          contentContainer.firstChild
        );
      }

      // Verify the order is correct
      const firstChild = contentContainer.firstChild;
      log(
        `Inserted 5 paragraphs - first child: ${
          firstChild ? firstChild.tagName : "none"
        }`
      );

      // Extract styles from all 5 paragraphs
      const paragraphStyles = [];
      testParagraphs.forEach((paragraph, index) => {
        const computedStyle = window.getComputedStyle(paragraph);
        const paragraphStyle = {};

        relevantProperties.forEach((prop) => {
          const value = computedStyle.getPropertyValue(prop);
          if (
            value &&
            value !== "initial" &&
            value !== "inherit" &&
            value !== "rgba(0, 0, 0, 0)"
          ) {
            paragraphStyle[prop] = value;
          }
        });

        paragraphStyles.push(paragraphStyle);
        log(
          `Extracted styles from injected paragraph ${index + 1}: ${
            Object.keys(paragraphStyle).length
          } properties`
        );
      });

      // Find the most common style pattern using majority voting
      const majorityStyles = findMajorityParagraphStyles(paragraphStyles);

      // Check for first-child specific styles by comparing first paragraph with majority
      const firstParagraphStyles = paragraphStyles[0];
      const firstChildStyles = {};
      Object.keys(firstParagraphStyles).forEach((prop) => {
        if (firstParagraphStyles[prop] !== majorityStyles[prop]) {
          firstChildStyles[prop] = firstParagraphStyles[prop];
          log(
            `First paragraph has different ${prop}: ${firstParagraphStyles[prop]} vs ${majorityStyles[prop]}`
          );
        }
      });

      // Also check for :first-letter styles on the first paragraph
      const firstLetterStyles = {};
      const firstLetterStyle = window.getComputedStyle(
        testParagraphs[0],
        "::first-letter"
      );
      relevantProperties.forEach((prop) => {
        const value = firstLetterStyle.getPropertyValue(prop);
        if (
          value &&
          value !== "initial" &&
          value !== "inherit" &&
          value !== "rgba(0, 0, 0, 0)"
        ) {
          firstLetterStyles[prop] = value;
        }
      });

      // Add first-of-type styles if any differences found
      if (Object.keys(firstChildStyles).length > 0) {
        styles["#wrapper>p:first-of-type"] = firstChildStyles;
        log(
          `Added #wrapper>p:first-of-type styles: ${Object.keys(
            firstChildStyles
          ).join(", ")}`
        );
      }

      // Add first-letter styles if any found
      if (Object.keys(firstLetterStyles).length > 0) {
        styles["#wrapper>p:first-of-type::first-letter"] = firstLetterStyles;
        log(
          `Added #wrapper>p:first-of-type::first-letter styles: ${Object.keys(
            firstLetterStyles
          ).join(", ")}`
        );
      }

      // Use majority styles for normal paragraph styles
      log(
        `Using majority paragraph styles for normal paragraph styling (${
          Object.keys(majorityStyles).length
        } properties)`
      );

      // Add the majority styles directly to the styles object
      if (Object.keys(majorityStyles).length > 0) {
        styles["p"] = majorityStyles;
        log(
          `Successfully extracted majority paragraph styles from injected paragraphs`
        );
      } else {
        log(`No majority paragraph styles found from injected paragraphs`);
      }

      // Clean up - remove all test paragraphs
      testParagraphs.forEach((paragraph) => {
        contentContainer.removeChild(paragraph);
      });
    } else if (tagName === "a" || tagName === "strong" || tagName === "em") {
      // For links, bold, and italic, inject them inside a paragraph to get proper context
      log(`Injecting ${tagName} inside a paragraph for proper context`);

      // Create a test paragraph
      const testParagraph = document.createElement("p");
      testParagraph.textContent = "Test paragraph for context";
      testParagraph.style.display = "block";
      testParagraph.style.visibility = "hidden";
      testParagraph.style.position = "absolute";
      testParagraph.style.left = "-9999px";

      // Create the test element
      const testElement = document.createElement(tagName);
      testElement.textContent =
        tagName === "a" ? "Test Link" : `Test ${tagName}`;
      testElement.style.display = "inline";
      testElement.style.visibility = "hidden";
      testElement.style.position = "absolute";
      testElement.style.left = "-9999px";

      if (tagName === "a") {
        testElement.href = "#";
      }

      // Add the element to the paragraph
      testParagraph.appendChild(testElement);

      // Add the paragraph to the content container
      contentContainer.appendChild(testParagraph);

      const success = extractStylesFromElement(testElement, tagName);

      contentContainer.removeChild(testParagraph);

      if (success) {
        log(
          `Successfully extracted styles for injected ${tagName} inside paragraph`
        );
      } else {
        log(`No styles extracted for injected ${tagName} inside paragraph`);
      }
    } else {
      // For other elements, use the original logic
      // Inject two elements and capture the second one to avoid first-child rules
      const first = document.createElement(tagName);
      first.textContent = `Test ${tagName} 1`;
      first.style.display = "block";
      first.style.visibility = "hidden";
      first.style.position = "absolute";
      first.style.left = "-9999px";

      const second = document.createElement(tagName);
      second.textContent = `Test ${tagName} 2`;
      second.style.display = "block";
      second.style.visibility = "hidden";
      second.style.position = "absolute";
      second.style.left = "-9999px";

      contentContainer.appendChild(first);
      contentContainer.appendChild(second);

      const success = extractStylesFromElement(second, tagName);

      contentContainer.removeChild(first);
      contentContainer.removeChild(second);

      if (success) {
        log(
          `Successfully extracted styles for injected ${tagName} (second instance)`
        );
      } else {
        log(`No styles extracted for injected ${tagName} (second instance)`);
      }
    }
  }

  // Clean up fonts: remove duplicates and unused font-faces
  function cleanUpFonts(fonts, styles) {
    log("Cleaning up fonts: removing duplicates and unused declarations...");

    // Extract all font-family values from styles
    const usedFontFamilies = new Set();
    Object.values(styles).forEach((styleObj) => {
      if (styleObj["font-family"]) {
        // Parse font-family values (can be comma-separated)
        const fontFamilies = styleObj["font-family"]
          .split(",")
          .map((f) => f.trim().replace(/['"]/g, ""));
        fontFamilies.forEach((font) =>
          usedFontFamilies.add(font.toLowerCase())
        );
      }
    });

    log(
      `Found ${usedFontFamilies.size} unique font families in use: ${Array.from(
        usedFontFamilies
      ).join(", ")}`
    );

    // Remove duplicate font-face declarations
    const uniqueFontFaces = new Map();
    const cleanedFontFaces = [];

    fonts.fontFaces.forEach((fontFace) => {
      const fullRule = fontFace.fullRule || fontFace;
      if (typeof fullRule === "string") {
        // Extract font-family from the @font-face rule
        const fontFamilyMatch = fullRule.match(
          /font-family\s*:\s*['"]?([^'";,]+)['"]?/i
        );
        if (fontFamilyMatch) {
          const fontFamily = fontFamilyMatch[1].trim().toLowerCase();

          // Only keep if this font-family is actually used
          if (usedFontFamilies.has(fontFamily)) {
            // Check if we already have this exact rule
            if (!uniqueFontFaces.has(fullRule)) {
              uniqueFontFaces.set(fullRule, true);
              cleanedFontFaces.push(fontFace);
              log(`Keeping @font-face for used font: ${fontFamily}`);
            } else {
              log(`Removing duplicate @font-face for: ${fontFamily}`);
            }
          } else {
            log(`Removing unused @font-face for: ${fontFamily}`);
          }
        }
      }
    });

    log(
      `Font cleanup complete: ${fonts.fontFaces.length} -> ${cleanedFontFaces.length} font-face declarations`
    );

    return {
      imports: fonts.imports,
      fontFaces: cleanedFontFaces,
    };
  }

  // Main style extraction function
  async function extractStyles() {
    log("=== Starting style extraction ===");

    // Extract fonts first
    await extractFonts();

    // Phase 1: Scan for existing elements on the page
    log("=== PHASE 1: Scanning for existing elements ===");
    const foundElements = new Set();

    // Debug existing links on the page
    const existingLinks = contentContainer.querySelectorAll("a");
    if (existingLinks.length > 0) {
      log(`Found ${existingLinks.length} existing links in content container`);
      const firstLink = existingLinks[0];
      const linkComputedStyle = window.getComputedStyle(firstLink);
      log(`EXISTING LINK DEBUG - first link:`);
      log(`  Computed color: ${linkComputedStyle.color}`);
      log(`  Computed text-decoration: ${linkComputedStyle.textDecoration}`);
      log(`  Computed font-weight: ${linkComputedStyle.fontWeight}`);
      log(`  Computed border: ${linkComputedStyle.border}`);
      log(`  Computed background-color: ${linkComputedStyle.backgroundColor}`);
      log(`  Computed font-size: ${linkComputedStyle.fontSize}`);
      log(`  Link text: "${firstLink.textContent.substring(0, 30)}..."`);
      log(`  Link href: ${firstLink.href}`);
    } else {
      log(`No existing links found in content container`);
    }

    // Special handling for body element - extract from document.body
    if (targetElements.includes("body")) {
      if (document.body) {
        log("Extracting styles from document.body");
        log("BODY DEBUG:");
        const bodyStyle = window.getComputedStyle(document.body);
        log(`  Computed background-color: ${bodyStyle.backgroundColor}`);
        log(`  Computed background: ${bodyStyle.background}`);
        log(`  Computed color: ${bodyStyle.color}`);
        log(`  Computed font-family: ${bodyStyle.fontFamily}`);
        log(`  Computed font-size: ${bodyStyle.fontSize}`);

        if (extractStylesFromElement(document.body, "body", styles)) {
          log("Successfully extracted styles from body element");
          foundElements.add("body");
        }
      } else {
        log("No document.body found");
      }
    }

    // Special handling for links - use existing links to capture pseudo-selectors
    if (targetElements.includes("a")) {
      const existingLinks = contentContainer.querySelectorAll("a");
      if (existingLinks.length > 0) {
        log(
          `Found ${existingLinks.length} existing links in content container`
        );

        // Find the first link that's inside a paragraph (not a headline)
        let paragraphLink = null;
        for (let i = 0; i < existingLinks.length; i++) {
          const link = existingLinks[i];
          if (isInsideParagraph(link) && !isInsideHeadline(link)) {
            paragraphLink = link;
            break;
          }
        }

        if (paragraphLink) {
          log("EXISTING LINK DEBUG - paragraph link:");
          log(
            `  Computed color: ${window.getComputedStyle(paragraphLink).color}`
          );
          log(
            `  Computed text-decoration: ${
              window.getComputedStyle(paragraphLink).textDecoration
            }`
          );
          log(
            `  Computed font-weight: ${
              window.getComputedStyle(paragraphLink).fontWeight
            }`
          );
          log(
            `  Computed border: ${
              window.getComputedStyle(paragraphLink).border
            }`
          );
          log(
            `  Computed background-color: ${
              window.getComputedStyle(paragraphLink).backgroundColor
            }`
          );
          log(
            `  Computed font-size: ${
              window.getComputedStyle(paragraphLink).fontSize
            }`
          );
          log(
            `  Link text: "${paragraphLink.textContent.substring(0, 30)}..."`
          );
          log(`  Link href: ${paragraphLink.href}`);

          if (extractStylesFromElement(paragraphLink, "a")) {
            log("Successfully extracted styles from existing paragraph link");
            foundElements.add("a");
          }
        } else {
          log(
            "No existing links found inside paragraphs, will inject one later"
          );
        }
      } else {
        log("No existing links found, will inject one later");
      }
    }

    targetElements.forEach((tagName) => {
      // Skip links and body as they're handled above
      if (tagName === "a" || tagName === "body") {
        return;
      }

      // Look for existing headlines (h1-h6) anywhere in the content container
      if (tagName.match(/^h[1-6]$/)) {
        // First try direct descendants
        const directChildren = Array.from(contentContainer.children);
        const directHeadlines = directChildren.filter(
          (child) => child.tagName.toLowerCase() === tagName
        );

        let targetElement = null;
        if (directHeadlines.length > 0) {
          // Prefer the second element if present to avoid first-child-specific styles
          targetElement =
            directHeadlines.length > 1
              ? directHeadlines[1]
              : directHeadlines[0];
          log(
            `Found ${
              directHeadlines.length
            } direct descendant ${tagName} elements in content container (using ${
              directHeadlines.length > 1 ? "second" : "first"
            })`
          );
        } else {
          // If no direct descendants, look anywhere in the content container
          const allHeadlines = contentContainer.querySelectorAll(tagName);
          if (allHeadlines.length > 0) {
            // Prefer the second element if present
            targetElement =
              allHeadlines.length > 1 ? allHeadlines[1] : allHeadlines[0];
            log(
              `Found ${
                allHeadlines.length
              } ${tagName} elements anywhere in content container (using ${
                allHeadlines.length > 1 ? "second" : "first"
              })`
            );
          }
        }

        if (targetElement) {
          log(`Using ${tagName} element for style extraction`);

          // Add debugging for existing headlines
          const computedStyle = window.getComputedStyle(targetElement);
          log(`EXISTING HEADLINE DEBUG - ${tagName}:`);
          log(`  Computed font-size: ${computedStyle.fontSize}`);
          log(`  Computed font-weight: ${computedStyle.fontWeight}`);
          log(`  Computed color: ${computedStyle.color}`);
          log(`  Computed margin: ${computedStyle.margin}`);
          log(`  Computed line-height: ${computedStyle.lineHeight}`);
          log(
            `  Element text: "${targetElement.textContent.substring(0, 50)}..."`
          );

          const success = extractStylesFromElement(targetElement, tagName);

          if (success) {
            foundElements.add(tagName);
            log(`Successfully extracted styles from existing ${tagName}`);
          } else {
            log(`No styles extracted from existing ${tagName}`);
          }
        } else {
          log(`No ${tagName} elements found anywhere in content container`);
        }
      } else {
        // For all other elements (including paragraphs), always inject to get clean styling
        log(`Always injecting ${tagName} to get clean styling`);
        injectAndTestElement(tagName);
        foundElements.add(tagName);
      }
    });

    // Phase 2: Inject missing elements
    log("=== PHASE 2: Injecting missing elements ===");
    const missingElements = targetElements.filter(
      (tag) => !foundElements.has(tag)
    );

    if (missingElements.length > 0) {
      log(
        `Injecting ${
          missingElements.length
        } missing elements: ${missingElements.join(", ")}`
      );
      missingElements.forEach((tagName) => {
        if (tagName === "a") {
          log("Injecting fallback link since no existing links found");
        }
        injectAndTestElement(tagName);
      });
    } else {
      log("All target elements found on page - no injection needed!");
    }

    // Phase 3: Test CSS classes for CriticMarkup and other special elements
    log("=== PHASE 3: Testing special CSS classes ===");
    testClasses.forEach((className) => {
      const element = document.createElement("span");
      element.className = className;
      element.textContent = `Test ${className}`;
      element.style.display = "block";
      element.style.visibility = "hidden";
      element.style.position = "absolute";
      element.style.left = "-9999px";

      contentContainer.appendChild(element);

      const computedStyle = window.getComputedStyle(element);
      const elementStyles = {};
      relevantProperties.forEach((prop) => {
        const value = computedStyle.getPropertyValue(prop);
        if (
          value &&
          value !== "initial" &&
          value !== "inherit" &&
          value !== "rgba(0, 0, 0, 0)" &&
          // Filter out line-height: 0 which would make text unreadable
          !(
            prop === "line-height" &&
            (value === "0" || value === "0px" || parseFloat(value) === 0)
          ) &&
          // Allow "none" for text-decoration properties
          !(value === "none" && !prop.includes("decoration"))
        ) {
          elementStyles[prop] = value;
        }
      });

      if (Object.keys(elementStyles).length > 0) {
        styles["." + className] = elementStyles;
        log(
          `Extracted styles for .${className}: ${Object.keys(
            elementStyles
          ).join(", ")}`
        );
      } else {
        log(`No styles extracted for .${className}`);
      }

      contentContainer.removeChild(element);
    });

    // Clean up fonts: remove duplicates and unused font-faces
    const cleanedFonts = cleanUpFonts(fonts, styles);

    log(
      `Style extraction complete. Found ${
        Object.keys(styles).length
      } style rules and ${
        cleanedFonts.fontFaces.length
      } font-face declarations (after cleanup)`
    );

    // Send results back to Objective-C (legacy WebView approach)
    log("Attempting to send results to Objective-C...");
    log("window.styleStealer exists: " + (window.styleStealer ? "YES" : "NO"));
    if (window.styleStealer) {
      log(
        "window.styleStealer.styleExtracted exists: " +
          (window.styleStealer.styleExtracted ? "YES" : "NO")
      );
    }

    if (window.styleStealer && window.styleStealer.styleExtracted) {
      log("Calling window.styleStealer.styleExtracted...");
      try {
        // For legacy WebView, we need to stringify the data first
        const dataToSend = {
          styles: styles,
          fonts: cleanedFonts,
        };

        log(
          "Data to send - styles count: " +
            Object.keys(styles).length +
            ", fonts count: " +
            Object.keys(cleanedFonts).length
        );

        // Stringify the data for legacy WebView compatibility
        const jsonString = JSON.stringify(dataToSend);
        log("JSON string length: " + jsonString.length);

        // Send the stringified data
        window.styleStealer.styleExtracted(jsonString);
        log("Successfully called styleExtracted with stringified data");
      } catch (e) {
        log("Error calling styleExtracted: " + e.message);
      }
    } else {
      log("Cannot call styleExtracted - bridge not available");
    }
  }

  // Check if we're on the demo/preview page
  function isDemoPage() {
    return (
      window.location.href.includes("data:") ||
      document.title.includes("Style Preview") ||
      document.body.innerHTML.includes("Style Preview") ||
      document.body.innerHTML.includes("Extracted Styles Demo")
    );
  }

  // Disable all interactions on demo page
  function disableAllInteractions() {
    log("Disabling all interactions on demo page");

    // Remove all event listeners from containers
    const containers = document.querySelectorAll(
      "article, div, section, main, p, h1, h2, h3, h4, h5, h6"
    );
    containers.forEach(function (el) {
      // Clone the element to remove all event listeners
      const newEl = el.cloneNode(true);
      el.parentNode.replaceChild(newEl, el);
    });

    // Disable all links (prevent clicking but preserve styling)
    const links = document.querySelectorAll("a");
    links.forEach(function (link) {
      link.addEventListener(
        "click",
        function (e) {
          e.preventDefault();
          e.stopPropagation();
          return false;
        },
        true
      );

      // Keep href for styling purposes but prevent navigation
      // Change cursor to indicate it's not clickable
      link.style.cursor = "default";
    });

    // Disable any remaining interactive elements
    const interactiveElements = document.querySelectorAll(
      "button, input, select, textarea"
    );
    interactiveElements.forEach(function (el) {
      el.disabled = true;
      el.style.pointerEvents = "none";
    });

    log("All interactions disabled on demo page");
  }

  // Start the manual selection process
  function startSelection() {
    log("Starting manual content selection mode");
    log(`Document ready state: ${document.readyState}`);
    log(`Body exists: ${!!document.body}`);
    log(
      `Body children count: ${
        document.body ? document.body.children.length : "N/A"
      }`
    );

    // If DOM isn't ready, wait a bit and try again
    if (
      document.readyState !== "complete" ||
      !document.body ||
      document.body.children.length === 0
    ) {
      log("DOM not ready, waiting 100ms and retrying...");
      setTimeout(startSelection, 100);
      return;
    }

    // Check if we're on a demo page - if so, disable interactions instead
    if (isDemoPage()) {
      log("Detected demo page - disabling all interactions");
      const sharedBar = document.getElementById("mk-extractor-status");
      if (sharedBar) {
        sharedBar.style.display = "none";
      }
      disableAllInteractions();
      return;
    }

    // Only show the blue instruction box if we're on a remote page (not the Style Preview)
    // Check if we're on a remote page by looking for the presence of external content
    const isRemotePage =
      window.location.href.startsWith("http") &&
      !window.location.href.includes("data:") &&
      !document.title.includes("Style Preview") &&
      !document.body.innerHTML.includes("Style Preview");

    log(
      `Page detection - URL: ${window.location.href}, Title: ${document.title}, Is remote: ${isRemotePage}`
    );

    if (isRemotePage) {
      injectHighlightStyles();
      createInstructionDisplay();

      // Add global keyboard event listeners for Command key detection
      globalEventListeners.keydown = function (event) {
        if (isCommandKeyHeld(event)) {
          disableSelectionForNavigation();
        }
      };

      globalEventListeners.keyup = function (event) {
        if (!isCommandKeyHeld(event)) {
          enableSelectionForSelection();
        }
      };

      globalEventListeners.mousedown = function (event) {
        if (isCommandKeyHeld(event)) {
          disableSelectionForNavigation();
        }
      };

      document.addEventListener("keydown", globalEventListeners.keydown);
      document.addEventListener("keyup", globalEventListeners.keyup);
      document.addEventListener("mousedown", globalEventListeners.mousedown);
    } else {
      log("Skipping instruction display - appears to be Style Preview page");
    }

    const containers = document.querySelectorAll("article, div, section, main");
    log(`Found ${containers.length} potential content containers`);

    // Intercept clicks at document-level so first click always performs
    // extraction before page scripts can trigger a navigation.
    globalEventListeners.click = function (event) {
      if (!isSelectionMode) return;
      const container = findNearestContainer(event.target);
      if (!container) return;
      findContent(event);
    };
    document.addEventListener("click", globalEventListeners.click, true);

    // Add mouseover/mouseout listeners to document body for highlighting
    // This will catch all mouse events and bubble up to find containers
    document.body.addEventListener("mouseover", addHighlight, true);
    document.body.addEventListener("mouseout", removeHighlight, true);

    log(
      `Added document click interception and body hover handlers (${containers.length} containers detected)`
    );
  }

  // Clean up the selection interface
  function cleanupSelectionInterface() {
    log("Cleaning up selection interface");

    // Remove mouseover/mouseout listeners from document body
    document.body.removeEventListener("mouseover", addHighlight, true);
    document.body.removeEventListener("mouseout", removeHighlight, true);

    // Remove global keyboard event listeners
    if (globalEventListeners.keydown) {
      document.removeEventListener("keydown", globalEventListeners.keydown);
    }
    if (globalEventListeners.keyup) {
      document.removeEventListener("keyup", globalEventListeners.keyup);
    }
    if (globalEventListeners.mousedown) {
      document.removeEventListener("mousedown", globalEventListeners.mousedown);
    }
    if (globalEventListeners.click) {
      document.removeEventListener("click", globalEventListeners.click, true);
    }

    // Remove instruction display
    if (display) {
      // Shared status bar is managed by host app; hide it in preview mode.
      display.style.display = "none";
      if (!window.__mkExternalStatusBar) {
        display.remove();
      }
      display = null;
    }

    // Reset state
    isCommandHeld = false;
    originalEventListeners.clear();
  }

  // Expose functions to be called from Objective-C
  window.startContentSelection = startSelection;
  window.cleanupContentSelection = cleanupSelectionInterface;
  window.disableAllInteractions = disableAllInteractions;

  // Don't automatically start selection - wait for the page to be loaded
  // The selection will be started by the Objective-C code when needed
  return;
})();
