Max-Eee/NeoPass/main 128k tokens More Tools
```
├── README.md (1700 tokens)
├── contentScript.js (1300 tokens)
├── data/
   ├── inject/
      ├── anti-anti-debug.js (1100 tokens)
      ├── chatbot.js (28.7k tokens)
      ├── content.js (12.1k tokens)
      ├── copyOverride.js (1500 tokens)
      ├── customPaste.js (3.9k tokens)
      ├── exam.js (1300 tokens)
      ├── isolated.js (300 tokens)
      ├── main.js (900 tokens)
      ├── mock_code.js (700 tokens)
      ├── mock_code/
         ├── minifiedBackground.js (400 tokens)
         ├── minifiedContent-script.js
         ├── mock_manifest.json (400 tokens)
         ├── rules.json (3.9k tokens)
      ├── rightclickmenu.js
      ├── screenshare-bridge.js (200 tokens)
      ├── screenshare.js (3.8k tokens)
   ├── lib/
      ├── showdown.min.js (omitted)
   ├── nptel.json (21.5k tokens)
├── devtools.js (200 tokens)
├── images/
   ├── NeoExamShieldBanner.png
   ├── icon128.png
   ├── icon16.png
   ├── icon256.png
   ├── icon48.png
├── manifest.json (900 tokens)
├── metadata.json
├── nptel.txt (100 tokens)
├── popup.html (6.5k tokens)
├── popup.js (6.1k tokens)
├── worker.js (30.7k tokens)
```


## /README.md

<img width="1500" height="500" alt="NeoPass Banner" src="https://github.com/user-attachments/assets/7369dd86-838d-4fdc-abdd-6b41a9b14aed" />

# <i>**`Free`** NeoPass Extension</i>

> **NeoPass Pro** - [Click here to see Pro features and benefits](https://neopass.tech/pro)

This chrome extension is for students taking tests on the **`Iamneo portal`**, **`HackerRank`**, **`Wildlife Ecology NPTEL`**, **`conservation-geography NPTEL`**, **`forest management NPTEL`** and `other exam portals in chrome browser` that restrict your abilities

### [**Make sure to visit our website for the best experience!**](https://freeneopass.vercel.app) 🌐

<samp>
  
> [!IMPORTANT]
> **Free Users**: No sign-up needed! Configure your own AI API key by clicking the extension icon and going to the **Settings** tab.  
> Supported providers: OpenAI, Google Gemini, Anthropic Claude, and custom endpoints.
> 
>
> **Want a hassle-free experience?** Upgrade to Pro by visiting **neopass.tech/pro** for AI managed by NeoPass (GPT-5.1), increased rate limits, and NeoBrowser with built in Exam Helper access!  

> [!WARNING]
> **Educational Purposes Only**: This extension is intended for educational purposes. Please use it responsibly and ethically.  
> We am not responsible for any actions taken, and we do not encourage or promote cheating in any way.  
> Be cautious when using the extension to maintain academic integrity.

## ✨ Features

### Free Version (Bring Your Own API Key)
- **`NPTEL Integration`** : Solve NPTEL Wildlife ecology answers
- **`NeoExamShield Bypass`** : Break free from Examly's limitations. NeoPass mimics the NeoExamShield extension
- **`Chatbot With Stealth Mode`** : Leverage AI Chatbot to enhance your search capabilities
- **`AI Search Answers/Code`** : Perform AI-powered searches, helping you find answers without switching tabs
- **`Solve MCQ`** : Quickly Search MCQ Answers by simply selecting
- **`Tab Switching Bypass`** : Prevents unwanted tab switch restrictions
- **`Pasting When Restricted`** : Quickly paste answers with ease, reducing the time spent on manual entry
- **`Multiple AI Providers`** : Support for OpenAI, Google Gemini, Anthropic Claude, and custom endpoints

### Pro Version Features
- **`Everything in free`** : All free features are included
- **`Managed AI by NeoPass`** : Powered by GPT-5.1 - no API key needed!
- **`Screenshare Bypass`** : Bypass fullscreen screenshare requirements with three modes:
  - **Share Tab/Window** — share only the current tab or window instead of the entire screen
  - **Share Blank Screen** — share a black screen without capturing anything real
  - **Share Frozen Screen** — capture a single frame of your screen and freeze it
- **`NeoBrowser Access`** : Exclusive access to the NeoBrowser with built in Exam Helper
- **`No Network Restrictions`** : Works even if AI providers are blocked on your network
- **`Increased Rate Limits`** : Higher usage limits for intensive exam sessions
- **`Priority Support`** : Get help when you need it most
- **`Hassle-Free Experience`** : No configuration needed, just login and go!

## ⬇️ Installation

1. [Download](https://github.com/Max-Eee/NeoPass/archive/refs/heads/main.zip) the extension.
2. Open Chrome and go to the Extensions page by typing `chrome://extensions/`.
3. Enable **Developer mode** in the top right corner.
4. Click on **Load unpacked** and select the folder where the extension is located.
5. Your NeoPass extension is now installed!

### Installation Guide Video



https://github.com/user-attachments/assets/89fb986c-2edb-4252-8232-dbd10beec0cf


## 💻 Usage

### For Free Users:
1. Click the NeoPass extension icon in your browser toolbar
2. Navigate to the **Settings** tab
3. Enter your AI API key (OpenAI, Google Gemini, Anthropic, or custom endpoint)
4. Select your AI provider from the dropdown menu
5. Click "Test Connection" to verify your setup
6. Start using all NeoPass features with your own API!

> [!NOTE]
> **Network Restrictions**: If your school/organization blocks AI service providers (OpenAI, Google, etc.), the extension will not work even with a valid API key. In this case, consider using a VPN or upgrade to Pro by visiting **neopass.tech/pro**.

### For Pro Users:
1. Visit [neopass.tech/pro](https://freeneopass.vercel.app/pro) to subscribe
2. Click the extension icon and go to the **Pro** tab
3. Login with your Pro credentials you have created from the webstie
4. Enjoy hassle-free AI-powered assistance with no configuration needed!

## ⌨️ Shortcuts

### Windows/Linux Users:
- <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>Q</kbd> : Solve Iam Neo MCQs/Coding Questions with 100% ACCURACY
- <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>A</kbd> : Solve Iam Neo MCQs/Coding Questions with using AI [Backup]
- <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>T</kbd> : Autotypes Iam Neo Coding Question Solution letter by letter
- <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>H</kbd> : Solve HackerRank Questions [BETA]
> [!NOTE]
> The following shortcuts **require text to be selected** before activation:  
> - <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>N</kbd> : Solve NPTEL MCQs from selected text
> - <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>S</kbd> : Search answers and code from selected text  
> - <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>M</kbd> : Search MCQs from selected text
- <kbd>Ctrl</kbd> + <kbd>V</kbd> : Paste content when blocked
- <kbd>Alt</kbd> + <kbd>C</kbd> : Open/Close Chatbot

<details>
<summary><strong>Mac Users (Click to expand)</strong></summary>

- <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>Q</kbd> : Solve Iam Neo MCQs/Coding Questions with 100% ACCURACY
- <kbd>Option</kbd> + <kbd>Shift</kbd> + <kbd>A</kbd> : Solve Iam Neo MCQs/Coding Questions with using AI [Backup]
- <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>T</kbd> : Autotypes Iam Neo Coding Question Solution letter by letter
- <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>H</kbd> : Solve HackerRank Questions [BETA]

> [!NOTE]
> The following shortcuts **require text to be selected** before activation:  
> - <kbd>Option</kbd> + <kbd>Shift</kbd> + <kbd>N</kbd> : Solve NPTEL MCQs from selected text
> - <kbd>Option</kbd> + <kbd>Shift</kbd> + <kbd>S</kbd> : Search answers and code from selected text  
> - <kbd>Option</kbd> + <kbd>Shift</kbd> + <kbd>M</kbd> : Search MCQs from selected text

- <kbd>Cmd</kbd> + <kbd>V</kbd> : Paste content when blocked
- <kbd>Option</kbd> + <kbd>C</kbd> : Open/Close Chatbot

</details>

## 🤝 Contribute or Add NPTEL Dataset

If you want to contribute to the NPTEL question database, follow these steps:

1. Fork this repository
2. Open your NPTEL assignment page in the browser
3. Open browser developer tools (F12 or right-click > Inspect)
4. Go to the Console tab
5. Copy and paste the script from `nptel.txt` in the repository
6. Run the script by pressing Enter
7. The script will extract all questions and correct answers from the page
8. Copy the output JSON data
9. Update the `data/nptel.json` file with the new questions and answers
10. Create a pull request to contribute your additions back to the main repository

This helps expand our database and improves the accuracy of the NPTEL question solving feature!

## 💬 Feedback

We'd love to hear your thoughts! If you encounter any issues or have suggestions for improvement, please reach out. Your feedback is invaluable! 💌

📧 **Contact us at:** [freeneopass@gmail.com](mailto:freeneopass@gmail.com?subject=Issue%20Title%3A%20%5BBrief%20description%20of%20your%20issue%5D&body=Hello%20NeoPass%20Support%20Team%2C%0A%0AIssue%20Description%3A%0A%5BPlease%20describe%20your%20issue%20in%20detail%5D%0A%0AWhen%20does%20this%20occur%3A%0A%5BSpecify%20when%20the%20issue%20happens%20-%20e.g.%2C%20during%20login%2C%20while%20using%20a%20specific%20feature%2C%20etc.%5D%0A%0ASteps%20to%20Reproduce%3A%0A1.%20%5BFirst%20step%5D%0A2.%20%5BSecond%20step%5D%0A3.%20%5BThird%20step%5D%0A%0AScreenshots%2FError%20Messages%20if%20possible%3A%0A%5BPlease%20attach%20any%20relevant%20screenshots%20or%20paste%20error%20messages%20here%5D%0A%0AAdditional%20Information%3A%0A%5BAny%20other%20relevant%20details%5D%0A%0AThank%20you!)

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

</samp>


## /contentScript.js

```js path="/contentScript.js" 
// Check if the chrome object is available (for compatibility)
if (typeof chrome === "undefined") {
  // Handle the case where chrome is not defined (like in Firefox)
}

// Always inject mock_code.js interceptor to handle extension detection (even when not logged in)
(function injectMockCode() {
  const mockScript = document.createElement('script');
  mockScript.src = chrome.runtime.getURL('data/inject/mock_code.js');
  mockScript.onload = function () {
      console.log('✅ Mock code interceptor loaded');
      this.remove(); // Clean up after execution
  };
  mockScript.onerror = function() {
      console.error('❌ Failed to load mock code interceptor');
  };
  // Inject as early as possible
  (document.head || document.documentElement).prepend(mockScript);
})();

// Inject exam.js (no login required)
const script = document.createElement('script');
script.src = chrome.runtime.getURL('data/inject/exam.js');
(document.head || document.documentElement).appendChild(script);

// Login prompt and status sync removed - extension features now available to all users

// Function removed - login check no longer required for extension features

// Neo Browser Download Link - Updated
const neoBrowserDownloadLink = "https://freeneopass.vercel.app";

// Function to add our NeoPass button left of the existing Neo Browser button
function replaceNeoBrowserButton() {
  const neoButton = document.querySelector('button#neobrowser');

  if (neoButton && !neoButton.dataset.replaced) {
    // Create custom styled button/link
    const ourBtn = document.createElement('a');
    ourBtn.innerHTML = `
      <div class="container jcc btn-align">
        <div class="t-whitespace-nowrap ng-star-inserted">
          <span>Download NeoPass Launcher</span>
        </div>
      </div>
    `;
    ourBtn.href = neoBrowserDownloadLink;
    ourBtn.target = "_blank";
    ourBtn.className = neoButton.className;
    ourBtn.id = "neopass-browser-btn";
    ourBtn.tabIndex = 0;

    // Apply gradient styling
    ourBtn.style.cssText = `
      position: relative !important;
      display: inline-flex !important;
      padding: 8px 16px !important;
      font-size: 14px !important;
      font-weight: 500 !important;
      color: white !important;
      background-color: black !important;
      border-radius: 8px !important;
      text-align: center !important;
      text-decoration: none !important;
      cursor: pointer !important;
      z-index: 1 !important;
      border: 2px solid transparent !important;
      transition: all 0.3s ease !important;
    `;

    // Create gradient border effect
    const beforeStyle = document.createElement('style');
    beforeStyle.textContent = `
      a#neopass-browser-btn {
        position: relative !important;
        background: linear-gradient(black, black) padding-box,
                    linear-gradient(45deg, #3b82f6, #8b5cf6, #ec4899) border-box !important;
        border: 2px solid transparent !important;
      }
      a#neopass-browser-btn:hover {
        transform: scale(1.05) !important;
        box-shadow: 0 0 20px rgba(139, 92, 246, 0.6) !important;
      }
    `;
    if (!document.querySelector('style[data-neobrowser-style]')) {
      beforeStyle.setAttribute('data-neobrowser-style', 'true');
      document.head.appendChild(beforeStyle);
    }

    // Insert our button to the left of the existing button
    neoButton.parentNode.insertBefore(ourBtn, neoButton);

    // Make the parent (app-button) a flex row so both buttons sit side by side
    neoButton.parentNode.style.cssText += `
      display: flex !important;
      flex-direction: row !important;
      align-items: center !important;
      gap: 8px !important;
    `;

    neoButton.dataset.replaced = "true";

    console.log('✅ NeoPass NeoBrowser button added left of existing Neo Browser button');
  }
}

// Observer to detect Neo Browser button and add our button
const buttonObserver = new MutationObserver((mutations) => {
  replaceNeoBrowserButton();
});

// Start observing for button changes
buttonObserver.observe(document.body, { 
  childList: true, 
  subtree: true 
});

// Initial check for Neo Browser button (in case already loaded)
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', replaceNeoBrowserButton);
} else {
  replaceNeoBrowserButton();
}

// Listen for window messages
window.addEventListener("message", function(event) {
  // Only process messages that:
  // 1. Come from the same window
  // 2. Are targeted for the extension
  if (event.data.target === "extension") {
      // Forward the message to the extension's background script
      chrome.runtime.sendMessage(event.data.message, response => {
          // Send the response back to the window
          window.postMessage({
              source: "extension",
              response: response
          }, "*");
      });
  }
});

window.addEventListener("message", function (event) {

  if (event.source === window && event.data.target === "extension") {

    browser.runtime.sendMessage(event.data.message, (response) => {

      window.postMessage({ source: "extension", response: response }, "*");
    });
  }
});

// Listen for the 'beforeunload' event to remove any injected elements
window.addEventListener("beforeunload", removeInjectedElement);

// Function to send a message to the website
function sendMessageToWebsite(messageData) {
  removeInjectedElement(); // Clean up any previous injected elements

  // Create a new span element with a unique ID
  const injectedElement = document.createElement("span");
  injectedElement.id = "x-template-base-" + messageData.currentKey; // Set a unique ID based on currentKey

  // Append the new element to the document body
  document.body.appendChild(injectedElement);
  console.log("message", messageData); // Log the message data

  // Send the message to the website
  window.postMessage(0, messageData.url); // 0 is the targetOrigin, meaning the same origin
}

// Function to remove injected elements from the DOM
function removeInjectedElement() {
  const injectedElement = document.querySelector("[id^='x-template-base-']"); // Select elements with ID starting with "x-template-base-"
  if (injectedElement) {
      injectedElement.remove(); // Remove the element if it exists
  }
}


```

## /data/inject/anti-anti-debug.js

```js path="/data/inject/anti-anti-debug.js" 
!(() => {
    const Proxy = window.Proxy;
    const Object = window.Object;
    const Array = window.Array;
    /**
     * Save original methods before we override them
     */
    const Originals = {
        createElement: document.createElement,
        log: console.log,
        table: console.table,
        clear: console.clear,
        functionConstructor: window.Function.prototype.constructor,
        setInterval: window.setInterval,
        createElement: document.createElement,
        toString: Function.prototype.toString,
        addEventListener: window.addEventListener
    }

    /**
     * Cutoffs for logging. After cutoff is reached, will no longer log anti debug warnings.
     */
    const cutoffs = {
        table: {
            amount: 5,
            within: 5000
        },
        clear: {
            amount: 5,
            within: 5000
        },
        redactedLog: {
            amount: 5,
            within: 5000
        },
        debugger: {
            amount: 10,
            within: 10000
        },
        debuggerThrow: {
            amount: 10,
            within: 10000
        }
    }

    /**
     * Decides if anti debug warnings should be logged
     */
    function shouldLog(type) {

            return false;
    }

    window.console.log = wrapFn((...args) => {
        // Keep track of redacted arguments
        let redactedCount = 0;

        // Filter arguments for detectors
        const newArgs = args.map((a) => {

            // Don't print functions.
            if (typeof a === 'function') {
                redactedCount++;
                return "Redacted Function";
            }

            // Passthrough if primitive
            if (typeof a !== 'object' || a === null) return a;

            // For objects, scan properties
            var props = Object.getOwnPropertyDescriptors(a)
            for (var name in props) {

                // Redact custom getters
                if (props[name].get !== undefined) {
                    redactedCount++;
                    return "Redacted Getter";
                }

                // Also block toString overrides
                if (name === 'toString') {
                    redactedCount++;
                    return "Redacted Str";
                }
            }

            // Defeat Performance Detector
            // https://github.com/theajack/disable-devtool/blob/master/src/detector/sub-detector/performance.ts
            if (Array.isArray(a) && a.length === 50 && typeof a[0] === "object") {
                redactedCount++;
                return "Redacted LargeObjArray";
            }

            return a;
        });

        // If most arguments are redacted, its probably spam
        if (redactedCount >= Math.max(args.length - 1, 1)) {
            if (!shouldLog("redactedLog")) {
                return;
            }
        }

    }, Originals.log);

    window.console.table = wrapFn((obj) => {
        if (shouldLog("table")) {
        }
    }, Originals.table);

    window.console.clear = wrapFn(() => {
        if (shouldLog("table")) {
        }
    }, Originals.clear);

    let debugCount = 0;
    window.Function.prototype.constructor = wrapFn((...args) => {
        const originalFn = Originals.functionConstructor.apply(this, args);
        var fnContent = args[0];
        if (fnContent) {
            if (fnContent.includes('debugger')) { // An anti-debugger is attempting to stop debugging
                if (shouldLog("debugger")) {
                }
                debugCount++;
                if (debugCount > 100) {
                    if (shouldLog("debuggerThrow")) {
                    }
                    throw new Error("You bad!");
                } else {
                    setTimeout(() => {
                        debugCount--;
                    }, 1);
                }
                const newArgs = args.slice(0);
                newArgs[0] = args[0].replaceAll("debugger", ""); // remove debugger statements
                return new Proxy(Originals.functionConstructor.apply(this, newArgs),{
                    get: function (target, prop) {
                        if (prop === "toString") {
                            return originalFn.toString;
                        }
                        return target[prop];
                    }
                });
            }
        }
        return originalFn;
    }, Originals.functionConstructor);

    document.createElement = wrapFn((el, o) => {
        var string = el.toString();
        var element = Originals.createElement.apply(document, [string, o]);
        if (string.toLowerCase() === "iframe") {
            element.addEventListener("load", () => {
                try {
                    element.contentWindow.window.console = window.console;
                } catch (e) {

                }
            });
        }
        return element;
    }, Originals.createElement);

    function wrapFn(newFn, old) {
        return new Proxy(newFn, {
            get: function (target, prop) {
                const callMethods = ['apply', 'bind', 'call'];
                if (callMethods.includes(prop)) {
                    return target[prop];
                }
                return old[prop];
            }
        });
    }
})()

```

## /data/inject/chatbot.js

```js path="/data/inject/chatbot.js" 
if (typeof chrome === "undefined") {}

if (typeof window.isMac === 'undefined') {
    window.isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0 || 
                   navigator.userAgent.toUpperCase().indexOf('MAC') >= 0;
}

(function() {
    chrome.storage.local.get(['stealth'], function(result) {
        if (window.chatOverlayInjected) {
            console.log("Chat overlay script already injected.");
            return;
        }
        window.chatOverlayInjected = true;
        
        const isStealthModeEnabled = result.stealth === true;
        console.log("Initial stealth mode state:", isStealthModeEnabled);


        function loadShowdown() {
            return new Promise((resolve, reject) => {
                if (typeof showdown !== 'undefined') {
                    resolve();
                    return;
                }

                const script = document.createElement('script');
                script.src = chrome.runtime.getURL('data/lib/showdown.min.js'); // Local path
                script.onload = resolve;
                script.onerror = reject;
                document.head.appendChild(script);
            });
        }

        function loadPrism() {
            return new Promise((resolve) => {
                // Create a lightweight inline syntax highlighter to bypass CSP
                window.SimplePrism = {
                    highlightElement: function(codeElement) {
                        const code = codeElement.textContent;
                        const language = codeElement.className.replace('language-', '');
                        
                        // Use a simpler approach to avoid overlapping replacements
                        let highlightedCode = this.simpleHighlight(code, language);
                        codeElement.innerHTML = highlightedCode;
                    },
                    
                    simpleHighlight: function(code, language) {
                        // Escape HTML first
                        let highlighted = code.replace(/&/g, '&amp;')
                                             .replace(/</g, '&lt;')
                                             .replace(/>/g, '&gt;');
                        
                        // Apply basic highlighting based on language
                        if (language === 'python') {
                            highlighted = this.highlightPython(highlighted);
                        } else if (language === 'javascript' || language === 'js') {
                            highlighted = this.highlightJavaScript(highlighted);
                        } else if (language === 'java') {
                            highlighted = this.highlightJava(highlighted);
                        } else if (language === 'css') {
                            highlighted = this.highlightCSS(highlighted);
                        } else if (language === 'html') {
                            highlighted = this.highlightHTML(highlighted);
                        } else if (language === 'sql') {
                            highlighted = this.highlightSQL(highlighted);
                        } else if (language === 'json') {
                            highlighted = this.highlightJSON(highlighted);
                        } else {
                            // Default to javascript-like highlighting
                            highlighted = this.highlightJavaScript(highlighted);
                        }
                        
                        return highlighted;
                    },
                    
                    highlightPython: function(code) {
                        // Use a token-based approach to avoid overlapping
                        let tokens = [];
                        let currentIndex = 0;
                        
                        // First, find all comments
                        let match;
                        const commentRegex = /#.*$/gm;
                        while ((match = commentRegex.exec(code)) !== null) {
                            tokens.push({
                                start: match.index,
                                end: match.index + match[0].length,
                                type: 'comment',
                                content: match[0]
                            });
                        }
                        
                        // Find strings (avoiding those inside comments)
                        const stringRegex = /(['"])((?:\\.|(?!\1)[^\\])*?)\1/g;
                        while ((match = stringRegex.exec(code)) !== null) {
                            if (!this.isInsideToken(match.index, tokens)) {
                                tokens.push({
                                    start: match.index,
                                    end: match.index + match[0].length,
                                    type: 'string',
                                    content: match[0]
                                });
                            }
                        }
                        
                        // Find keywords (avoiding those inside comments and strings)
                        const keywordRegex = /\b(def|class|if|elif|else|for|while|return|import|from|try|except|finally|with|as|and|or|not|in|is)\b/g;
                        while ((match = keywordRegex.exec(code)) !== null) {
                            if (!this.isInsideToken(match.index, tokens)) {
                                tokens.push({
                                    start: match.index,
                                    end: match.index + match[0].length,
                                    type: 'keyword',
                                    content: match[0]
                                });
                            }
                        }
                        
                        // Find booleans and None
                        const booleanRegex = /\b(True|False|None)\b/g;
                        while ((match = booleanRegex.exec(code)) !== null) {
                            if (!this.isInsideToken(match.index, tokens)) {
                                tokens.push({
                                    start: match.index,
                                    end: match.index + match[0].length,
                                    type: 'boolean',
                                    content: match[0]
                                });
                            }
                        }
                        
                        // Find numbers
                        const numberRegex = /\b\d+(\.\d+)?\b/g;
                        while ((match = numberRegex.exec(code)) !== null) {
                            if (!this.isInsideToken(match.index, tokens)) {
                                tokens.push({
                                    start: match.index,
                                    end: match.index + match[0].length,
                                    type: 'number',
                                    content: match[0]
                                });
                            }
                        }
                        
                        // Sort tokens by position
                        tokens.sort((a, b) => a.start - b.start);
                        
                        // Build highlighted code
                        let result = '';
                        let lastIndex = 0;
                        
                        tokens.forEach(token => {
                            // Add unhighlighted text before this token
                            result += code.slice(lastIndex, token.start);
                            // Add highlighted token
                            result += `<span class="${token.type}">${token.content}</span>`;
                            lastIndex = token.end;
                        });
                        
                        // Add remaining text
                        result += code.slice(lastIndex);
                        
                        return result;
                    },
                    
                    buildHighlightedCode: function(code, tokens) {
                        // Sort tokens by their start position
                        tokens.sort((a, b) => a.start - b.start);
                        
                        let result = '';
                        let lastIndex = 0;
                        
                        for (let token of tokens) {
                            // Add text before this token
                            result += code.slice(lastIndex, token.start);
                            
                            // Add the highlighted token
                            result += `<span class="${token.type}">${token.content}</span>`;
                            
                            lastIndex = token.end;
                        }
                        
                        // Add remaining text
                        result += code.slice(lastIndex);
                        
                        return result;
                    },
                    
                    isInsideToken: function(position, tokens) {
                        return tokens.some(token => position >= token.start && position < token.end);
                    },
                    
                    highlightJavaScript: function(code) {
                        let tokens = [];
                        let match;
                        
                        // Find comments first
                        const singleLineCommentRegex = /\/\/.*$/gm;
                        while ((match = singleLineCommentRegex.exec(code)) !== null) {
                            tokens.push({
                                start: match.index,
                                end: match.index + match[0].length,
                                type: 'comment',
                                content: match[0]
                            });
                        }
                        
                        const multiLineCommentRegex = /\/\*[\s\S]*?\*\//g;
                        while ((match = multiLineCommentRegex.exec(code)) !== null) {
                            tokens.push({
                                start: match.index,
                                end: match.index + match[0].length,
                                type: 'comment',
                                content: match[0]
                            });
                        }
                        
                        // Find strings
                        const stringRegex = /(['"`])((?:\\.|(?!\1)[^\\])*?)\1/g;
                        while ((match = stringRegex.exec(code)) !== null) {
                            if (!this.isInsideToken(match.index, tokens)) {
                                tokens.push({
                                    start: match.index,
                                    end: match.index + match[0].length,
                                    type: 'string',
                                    content: match[0]
                                });
                            }
                        }
                        
                        // Find keywords
                        const keywordRegex = /\b(function|const|let|var|if|else|for|while|return|import|export|class|extends|new|this|typeof|instanceof)\b/g;
                        while ((match = keywordRegex.exec(code)) !== null) {
                            if (!this.isInsideToken(match.index, tokens)) {
                                tokens.push({
                                    start: match.index,
                                    end: match.index + match[0].length,
                                    type: 'keyword',
                                    content: match[0]
                                });
                            }
                        }
                        
                        // Find booleans
                        const booleanRegex = /\b(true|false|null|undefined)\b/g;
                        while ((match = booleanRegex.exec(code)) !== null) {
                            if (!this.isInsideToken(match.index, tokens)) {
                                tokens.push({
                                    start: match.index,
                                    end: match.index + match[0].length,
                                    type: 'boolean',
                                    content: match[0]
                                });
                            }
                        }
                        
                        // Find numbers
                        const numberRegex = /\b\d+(\.\d+)?\b/g;
                        while ((match = numberRegex.exec(code)) !== null) {
                            if (!this.isInsideToken(match.index, tokens)) {
                                tokens.push({
                                    start: match.index,
                                    end: match.index + match[0].length,
                                    type: 'number',
                                    content: match[0]
                                });
                            }
                        }
                        
                        return this.buildHighlightedCode(code, tokens);
                    },
                    
                    highlightJava: function(code) {
                        let tokens = [];
                        let match;
                        
                        // Find comments first
                        const singleLineCommentRegex = /\/\/.*$/gm;
                        while ((match = singleLineCommentRegex.exec(code)) !== null) {
                            tokens.push({
                                start: match.index,
                                end: match.index + match[0].length,
                                type: 'comment',
                                content: match[0]
                            });
                        }
                        
                        const multiLineCommentRegex = /\/\*[\s\S]*?\*\//g;
                        while ((match = multiLineCommentRegex.exec(code)) !== null) {
                            tokens.push({
                                start: match.index,
                                end: match.index + match[0].length,
                                type: 'comment',
                                content: match[0]
                            });
                        }
                        
                        // Find strings
                        const stringRegex = /(['"])((?:\\.|(?!\1)[^\\])*?)\1/g;
                        while ((match = stringRegex.exec(code)) !== null) {
                            if (!this.isInsideToken(match.index, tokens)) {
                                tokens.push({
                                    start: match.index,
                                    end: match.index + match[0].length,
                                    type: 'string',
                                    content: match[0]
                                });
                            }
                        }
                        
                        // Find keywords
                        const keywordRegex = /\b(public|private|protected|static|final|class|interface|extends|implements|if|else|for|while|return|import|package|new|this)\b/g;
                        while ((match = keywordRegex.exec(code)) !== null) {
                            if (!this.isInsideToken(match.index, tokens)) {
                                tokens.push({
                                    start: match.index,
                                    end: match.index + match[0].length,
                                    type: 'keyword',
                                    content: match[0]
                                });
                            }
                        }
                        
                        // Find booleans
                        const booleanRegex = /\b(true|false|null)\b/g;
                        while ((match = booleanRegex.exec(code)) !== null) {
                            if (!this.isInsideToken(match.index, tokens)) {
                                tokens.push({
                                    start: match.index,
                                    end: match.index + match[0].length,
                                    type: 'boolean',
                                    content: match[0]
                                });
                            }
                        }
                        
                        // Find numbers
                        const numberRegex = /\b\d+(\.\d+)?[fFdDlL]?\b/g;
                        while ((match = numberRegex.exec(code)) !== null) {
                            if (!this.isInsideToken(match.index, tokens)) {
                                tokens.push({
                                    start: match.index,
                                    end: match.index + match[0].length,
                                    type: 'number',
                                    content: match[0]
                                });
                            }
                        }
                        
                        return this.buildHighlightedCode(code, tokens);
                    },
                    
                    highlightCSS: function(code) {
                        // Comments first
                        code = code.replace(/\/\*[\s\S]*?\*\//g, '<span class="comment">{{contextString}}amp;</span>');
                        // Selectors
                        code = code.replace(/([.#][a-zA-Z][a-zA-Z0-9_-]*)/g, '<span class="selector">$1</span>');
                        // Properties
                        code = code.replace(/([a-zA-Z-]+)(\s*:)/g, '<span class="property">$1</span>$2');
                        // Values
                        code = code.replace(/(#[0-9a-fA-F]+)/g, '<span class="value">$1</span>');
                        return code;
                    },
                    
                    highlightHTML: function(code) {
                        // Comments first
                        code = code.replace(/(&lt;!--[\s\S]*?--&gt;)/g, '<span class="comment">$1</span>');
                        // Tags
                        code = code.replace(/(&lt;\/?[^&gt;]+&gt;)/g, '<span class="tag">$1</span>');
                        return code;
                    },
                    
                    highlightSQL: function(code) {
                        // Comments first
                        code = code.replace(/--.*$/gm, '<span class="comment">{{contextString}}amp;</span>');
                        // Strings
                        code = code.replace(/'[^']*'/g, '<span class="string">{{contextString}}amp;</span>');
                        // Keywords
                        code = code.replace(/\b(SELECT|FROM|WHERE|INSERT|UPDATE|DELETE|CREATE|DROP|ALTER|TABLE|INDEX|PRIMARY|KEY|FOREIGN|NOT|NULL|DEFAULT|AND|OR|ORDER|BY|GROUP|HAVING|LIMIT)\b/gi, '<span class="keyword">$1</span>');
                        // Numbers
                        code = code.replace(/\b\d+(\.\d+)?\b/g, '<span class="number">{{contextString}}amp;</span>');
                        return code;
                    },
                    
                    highlightJSON: function(code) {
                        // Property keys first (before general strings)
                        code = code.replace(/"([^"]*)"(\s*:)/g, '<span class="property">"$1"</span>$2');
                        // Remaining strings
                        code = code.replace(/"([^"]*)"/g, '<span class="string">"$1"</span>');
                        // Booleans and null
                        code = code.replace(/\b(true|false|null)\b/g, '<span class="boolean">$1</span>');
                        // Numbers
                        code = code.replace(/\b\d+(\.\d+)?\b/g, '<span class="number">{{contextString}}amp;</span>');
                        return code;
                    }
                };
                
                // Add CSS for syntax highlighting with clean default theme
                // Styles will be added to shadow DOM later, not to document.head
                window._chatSyntaxHighlightCSS = `
                    .keyword { color: #0066CC; font-weight: bold; }
                    .string { color: #008000; }
                    .comment { color: #808080; font-style: italic; }
                    .number { color: #FF6600; }
                    .boolean { color: #0066CC; font-weight: bold; }
                    .property { color: #9932CC; }
                    .selector { color: #008000; font-weight: bold; }
                    .value { color: #FF6600; }
                    .tag { color: #0066CC; }
                `;
                
                resolve();
            });
        }

        // Chat icon SVG data URL (matching Crisp style)
        const CHAT_ICON_SVG_URL = 'url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2235%22%20height%3D%2230%22%20viewBox%3D%220%200%2035%2030%22%3E%3Cdefs%3E%3Cfilter%20id%3D%22c%22%20width%3D%22123.1%25%22%20height%3D%22127.9%25%22%20x%3D%22-11.5%25%22%3E%3CfeOffset%20dy%3D%221%22%20in%3D%22SourceAlpha%22%20result%3D%22shadowOffsetOuter1%22%2F%3E%3CfeGaussianBlur%20in%3D%22shadowOffsetOuter1%22%20result%3D%22shadowBlurOuter1%22%20stdDeviation%3D%221%22%2F%3E%3CfeColorMatrix%20in%3D%22shadowBlurOuter1%22%20values%3D%220%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200.07%200%22%2F%3E%3C%2Ffilter%3E%3Cfilter%20id%3D%22e%22%20width%3D%22129.7%25%22%20height%3D%22135.9%25%22%20x%3D%22-14.8%25%22%20y%3D%22-14%25%22%3E%3CfeMorphology%20in%3D%22SourceAlpha%22%20radius%3D%221%22%20result%3D%22shadowSpreadInner1%22%2F%3E%3CfeGaussianBlur%20in%3D%22shadowSpreadInner1%22%20result%3D%22shadowBlurInner1%22%20stdDeviation%3D%222%22%2F%3E%3CfeOffset%20in%3D%22shadowBlurInner1%22%20result%3D%22shadowOffsetInner1%22%2F%3E%3CfeComposite%20in%3D%22shadowOffsetInner1%22%20in2%3D%22SourceAlpha%22%20k2%3D%22-1%22%20k3%3D%221%22%20operator%3D%22arithmetic%22%20result%3D%22shadowInnerInner1%22%2F%3E%3CfeColorMatrix%20in%3D%22shadowInnerInner1%22%20values%3D%220%200%200%200%201%200%200%200%200%201%200%200%200%200%201%200%200%200%200.750191215%200%22%2F%3E%3C%2Ffilter%3E%3ClinearGradient%20id%3D%22d%22%20x1%3D%2246.514%25%22%20x2%3D%2256.692%25%22%20y1%3D%2215.835%25%22%20y2%3D%2275.847%25%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23fff%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23fff%22%20stop-opacity%3D%22.601%22%2F%3E%3C%2FlinearGradient%3E%3Cpath%20id%3D%22a%22%20d%3D%22m40.34%2016.878.005.052%201.327%2014.35a2%202%200%200%201-1.754%202.17l-7.814.934-3.293%205.326a1%201%200%200%201-1.574.165l-4.207-4.407-8.113.969a2%202%200%200%201-2.228-1.802l-1.328-14.35a2%202%200%200%201%201.755-2.17l25-2.986a2%202%200%200%201%202.223%201.749%22%2F%3E%3C%2Fdefs%3E%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%20transform%3D%22translate%28-9%20-14%29%22%3E%3Cuse%20xlink%3Ahref%3D%22%23a%22%20fill%3D%22%23000%22%20filter%3D%22url%28%23c%29%22%2F%3E%3Cuse%20xlink%3Ahref%3D%22%23a%22%20fill%3D%22url%28%23d%29%22%2F%3E%3Cuse%20xlink%3Ahref%3D%22%23a%22%20fill%3D%22%23000%22%20filter%3D%22url%28%23e%29%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")';

        // State variables
        let isOverlayVisible = false;
        let chatHistory = [];
        let isDragging = false;
        let isResizing = false;
        let markdownConverter = null; // Will be initialized when showdown loads
        let currentStreamingDiv = null; // Tracks the current assistant message being streamed
        let chatAboutQuestionEnabled = false; // Toggle for chat about question feature
        let extractedQuestion = null; // Store extracted question

        // Helper function to access elements in shadow DOM
        function getShadowElement(id) {
            const shadowHost = document.getElementById('chat-overlay-shadow-host');
            if (!shadowHost || !shadowHost.shadowRoot) return null;
            return shadowHost.shadowRoot.getElementById(id);
        }
        
        function getShadowRoot() {
            const shadowHost = document.getElementById('chat-overlay-shadow-host');
            return shadowHost ? shadowHost.shadowRoot : null;
        }
        
        function getChatButton() {
            const buttonShadowHost = document.getElementById('chat-button-shadow-host');
            if (!buttonShadowHost || !buttonShadowHost.shadowRoot) return null;
            return buttonShadowHost.shadowRoot.getElementById('chat-button');
        }

        // Drag and resize state
        let dragOffsetX;
        let dragOffsetY;
        let initialWidth;
        let initialHeight;
        let resizeStartX;
        let resizeStartY;

        const fontLink = document.createElement('link');
        fontLink.href = 'https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap';
        fontLink.rel = 'stylesheet';
        document.head.appendChild(fontLink);

        // Question extraction functions
        function detectPlatform() {
            // Check for Examly/IamNeo
            if (document.querySelector('div[aria-labelledby="question-data"]')) {
                return 'examly';
            }
            // Check for HackerRank
            if (document.querySelector('.QuestionDetails_container__AIu0X') || 
                document.querySelector('.monaco-editor') ||
                document.querySelector('.grouped-mcq__question')) {
                return 'hackerrank';
            }
            return null;
        }

        function extractExamlyQuestion() {
            const questionElement = document.querySelector('div[aria-labelledby="question-data"]');
            if (!questionElement) return null;

            const questionText = questionElement.innerText.trim();

            // Check if it's a coding question
            const codingQuestionElement = document.querySelector('div[aria-labelledby="input-format"]');
            
            if (codingQuestionElement) {
                // Coding question
                const programmingLanguageElement = document.querySelector('span.inner-text');
                const programmingLanguage = programmingLanguageElement ? programmingLanguageElement.innerText.trim() : 'Programming language not found.';

                const inputFormatElement = document.querySelector('div[aria-labelledby="input-format"]');
                const inputFormatText = inputFormatElement ? inputFormatElement.innerText.trim() : '';

                const outputFormatElement = document.querySelector('div[aria-labelledby="output-format"]');
                const outputFormatText = outputFormatElement ? outputFormatElement.innerText.trim() : '';

                const sampleTestCaseElements = document.querySelectorAll('div[aria-labelledby="each-tc-card"]');
                let testCasesText = '';
                sampleTestCaseElements.forEach((testCase, index) => {
                    const inputElement = testCase.querySelector('div[aria-labelledby="each-tc-input-container"] pre');
                    const outputElement = testCase.querySelector('div[aria-labelledby="each-tc-output-container"] pre');

                    const inputText = inputElement ? inputElement.innerText.trim() : 'Input not found';
                    const outputText = outputElement ? outputElement.innerText.trim() : 'Output not found';

                    testCasesText += `Sample Test Case ${index + 1}:\nInput:\n${inputText}\nOutput:\n${outputText}\n\n`;
                });

                return {
                    type: 'coding',
                    language: programmingLanguage,
                    question: questionText,
                    inputFormat: inputFormatText,
                    outputFormat: outputFormatText,
                    testCases: testCasesText
                };
            } else {
                // MCQ question
                const codeLines = [];
                const codeElements = document.querySelectorAll('.ace_layer.ace_text-layer .ace_line');
                codeElements.forEach(line => {
                    codeLines.push(line.innerText.trim());
                });
                const codeText = codeLines.length > 0 ? codeLines.join('\n') : null;

                const optionsElements = document.querySelectorAll('div[aria-labelledby="each-option"]');
                const optionsText = [];
                optionsElements.forEach((option, index) => {
                    optionsText.push(`Option ${index + 1}: ${option.innerText.trim()}`);
                });

                return {
                    type: 'mcq',
                    question: questionText,
                    code: codeText,
                    options: optionsText.join('\n')
                };
            }
        }

        function extractHackerRankQuestion() {
            const getCleanText = el => el?.innerText?.trim() || "";

            // Check if it's a coding question (has Monaco editor)
            const monacoEditor = document.querySelector('.monaco-editor, .hr-monaco-editor');
            
            if (monacoEditor) {
                // Coding question
                let language = "Unknown";
                let title = "No Title Found";
                let instruction = "No Instructions Found";
                let details = "";

                const newLanguageSelector = document.querySelector('.select-language .css-3d4y2u-singleValue, .select-language .css-x7738g');
                if (newLanguageSelector) {
                    language = getCleanText(newLanguageSelector);
                } else {
                    language = getCleanText(document.querySelector('.select-language .css-x7738g')) || "Unknown";
                }

                let container = document.querySelector('.QuestionDetails_container__AIu0X');
                if (container) {
                    const titleElement = container.querySelector('.qaas-block-question-title, h2');
                    if (titleElement) {
                        const titleText = titleElement.textContent || titleElement.innerText;
                        title = titleText.replace(/Bookmark question \d+/g, '').trim();
                    }
                    
                    const instructionElement = container.querySelector('.qaas-block-question-instruction, .RichTextPreview_richText__1vKu5');
                    if (instructionElement) {
                        instruction = getCleanText(instructionElement);
                    }
                    
                    const detailsElements = container.querySelectorAll('details');
                    if (detailsElements.length > 0) {
                        details = Array.from(detailsElements).map(detail => {
                            const summary = getCleanText(detail.querySelector('summary'));
                            const content = getCleanText(detail.querySelector('.collapsable-details'));
                            return `\n${summary}\n${'-'.repeat(summary.length)}\n${content}`;
                        }).join('\n');
                    }
                } else {
                    container = document.querySelector('#main-splitpane-left');
                    if (container) {
                        title = getCleanText(container.querySelector('.question-view__title')) || "No Title Found";
                        instruction = getCleanText(container.querySelector('.question-view__instruction')) || "No Instructions Found";
                        
                        details = Array.from(container.querySelectorAll('details') || []).map(detail => {
                            const summary = getCleanText(detail.querySelector('summary'));
                            const content = getCleanText(detail.querySelector('.collapsable-details'));
                            return `\n${summary}\n${'-'.repeat(summary.length)}\n${content}`;
                        }).join('\n');
                    }
                }

                return {
                    type: 'coding',
                    language: language,
                    title: title,
                    instruction: instruction,
                    details: details
                };
            } else {
                // MCQ question
                const newLayoutQuestions = document.querySelectorAll('.QuestionDetails_container__AIu0X');
                
                if (newLayoutQuestions.length > 0) {
                    // New layout
                    const container = newLayoutQuestions[0]; // Get first question
                    let title = '';
                    let instruction = '';
                    let options = [];

                    const titleElement = container.querySelector('.qaas-block-question-title, h2');
                    if (titleElement) {
                        const titleText = titleElement.textContent || titleElement.innerText;
                        title = titleText.replace(/Bookmark question \d+/g, '').trim();
                    }

                    const instructionElement = container.querySelector('.qaas-block-question-instruction, .RichTextPreview_richText__1vKu5');
                    if (instructionElement) {
                        instruction = getCleanText(instructionElement);
                    }

                    let optionsContainer = container.nextElementSibling;
                    let attempts = 0;
                    while (optionsContainer && attempts < 5) {
                        const hasOptions = optionsContainer.querySelector('[role="checkbox"], [role="radio"]');
                        if (hasOptions) break;
                        optionsContainer = optionsContainer.nextElementSibling;
                        attempts++;
                    }

                    if (optionsContainer) {
                        let optionElements = optionsContainer.querySelectorAll('[role="radio"]');
                        if (optionElements.length === 0) {
                            optionElements = optionsContainer.querySelectorAll('[role="checkbox"]');
                        }

                        optionElements.forEach((option, index) => {
                            const labelId = option.getAttribute('aria-labelledby');
                            const labelElement = labelId ? document.getElementById(labelId) : 
                                              option.closest('.Control_optionList__vIubt, li')?.querySelector('label');
                            
                            if (labelElement) {
                                options.push(`Option ${index + 1}: ${labelElement.textContent.trim()}`);
                            }
                        });
                    }

                    return {
                        type: 'mcq',
                        title: title,
                        instruction: instruction,
                        options: options.join('\n')
                    };
                } else {
                    // Old layout
                    const oldLayoutQuestion = document.querySelector('.grouped-mcq__question');
                    if (oldLayoutQuestion) {
                        let title = '';
                        let instruction = '';
                        let options = [];

                        const titleElement = oldLayoutQuestion.querySelector('.question-view__title');
                        if (titleElement) {
                            title = titleElement.textContent.trim();
                        }

                        const instructionElement = oldLayoutQuestion.querySelector('.question-view__instruction');
                        if (instructionElement) {
                            instruction = instructionElement.textContent.trim();
                        }

                        const optionElements = oldLayoutQuestion.querySelectorAll('.ui-radio');
                        optionElements.forEach((option, index) => {
                            const labelElement = option.querySelector('.label');
                            if (labelElement) {
                                options.push(`Option ${index + 1}: ${labelElement.textContent.trim()}`);
                            }
                        });

                        return {
                            type: 'mcq',
                            title: title,
                            instruction: instruction,
                            options: options.join('\n')
                        };
                    }
                }
            }

            return null;
        }

        function extractCurrentQuestion() {
            const platform = detectPlatform();
            
            if (platform === 'examly') {
                return extractExamlyQuestion();
            } else if (platform === 'hackerrank') {
                return extractHackerRankQuestion();
            }
            
            return null;
        }

        function formatQuestionForChat(questionData) {
            if (!questionData) return null;

            let formattedQuestion = '';

            if (questionData.type === 'coding') {
                if (questionData.language) {
                    // Examly or HackerRank coding
                    formattedQuestion += `[Coding Question - ${questionData.language}]\n\n`;
                    
                    if (questionData.title) {
                        formattedQuestion += `Title: ${questionData.title}\n\n`;
                    }
                    
                    if (questionData.question) {
                        formattedQuestion += `Question:\n${questionData.question}\n\n`;
                    }
                    
                    if (questionData.instruction) {
                        formattedQuestion += `Instruction:\n${questionData.instruction}\n\n`;
                    }
                    
                    if (questionData.inputFormat) {
                        formattedQuestion += `Input Format:\n${questionData.inputFormat}\n\n`;
                    }
                    
                    if (questionData.outputFormat) {
                        formattedQuestion += `Output Format:\n${questionData.outputFormat}\n\n`;
                    }
                    
                    if (questionData.testCases) {
                        formattedQuestion += `Test Cases:\n${questionData.testCases}\n\n`;
                    }
                    
                    if (questionData.details) {
                        formattedQuestion += `Additional Details:${questionData.details}\n\n`;
                    }
                }
            } else if (questionData.type === 'mcq') {
                formattedQuestion += `[MCQ Question]\n\n`;
                
                if (questionData.title) {
                    formattedQuestion += `Title: ${questionData.title}\n\n`;
                }
                
                if (questionData.question) {
                    formattedQuestion += `Question:\n${questionData.question}\n\n`;
                }
                
                if (questionData.instruction) {
                    formattedQuestion += `${questionData.instruction}\n\n`;
                }
                
                if (questionData.code) {
                    formattedQuestion += `Code:\n${questionData.code}\n\n`;
                }
                
                if (questionData.options) {
                    formattedQuestion += `Options:\n${questionData.options}\n`;
                }
            }

            return formattedQuestion.trim();
        }

        // Create the main chat overlay UI
        function createChatOverlay() {
            // Check if shadow host already exists
            let shadowHost = document.getElementById("chat-overlay-shadow-host");
            if (shadowHost) {
                return shadowHost.shadowRoot.querySelector("#chat-overlay");
            }

            // Create shadow host element
            shadowHost = document.createElement("div");
            shadowHost.id = "chat-overlay-shadow-host";
            shadowHost.style.cssText = `
                position: fixed;
                bottom: 0;
                right: 0;
                z-index: 2147483647;
                pointer-events: none;
            `;

            // Attach shadow root
            const shadowRoot = shadowHost.attachShadow({ mode: 'open' });

            const overlay = document.createElement("div");
            overlay.id = "chat-overlay";
            overlay.style.cssText = `
                display: ${isOverlayVisible ? "flex" : "none"};
                position: fixed;
                bottom: 20px;
                right: 20px;
                width: 380px;
                height: 500px;
                background-color: #fff;
                border: none;
                border-radius: 16px;
                box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
                z-index: 2147483647;
                flex-direction: column;
                font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
                overflow: hidden;
                transition: opacity 0.3s ease;
                pointer-events: auto;
            `;

            // Create header
            const header = document.createElement("div");
            header.style.cssText = `
            padding: 16px 20px !important;
            font-weight: 500 !important;
            display: flex !important;
            justify-content: space-between !important;
            align-items: center !important;
            background-color: #fff !important;
            color: #333 !important;
            cursor: move !important;
        `;

            header.innerHTML = `
        <div style="display: flex !important; flex-direction: column !important; align-items: flex-start !important; gap: 2px !important;">
            <span style="display: flex !important; align-items: center !important; gap: 8px !important; font-size: 18px !important; font-weight: 700 !important; color: rgb(60, 84, 114) !important; opacity: 0.85 !important;">
                <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
                </svg>
                Chat
            </span>
            <span style="font-size: 12px !important; font-weight: 500 !important; color: #777 !important; margin-left: 30px !important;">
                ${window.isMac ? 'Option+C' : 'Alt+C'} to toggle
            </span>
        </div>
        <div style="display: flex !important; gap: 14px !important; align-items: center !important;">
            <span id="clear-chat" style="cursor: pointer !important; font-size: 14px !important; font-weight: 600 !important; color: rgb(220, 53, 69) !important; padding: 4px 8px !important; transition: all 0.2s ease !important;" onmouseover="this.style.opacity='0.7'" onmouseout="this.style.opacity='1'">Clear</span>
            <span id="close-chat" style="cursor: pointer !important; font-size: 22px !important; line-height: 1 !important; color: #888 !important; transition: color 0.2s ease !important; font-weight: 500 !important;" onmouseover="this.style.color='#333'" onmouseout="this.style.color='#888'">×</span>
        </div>
        `;

            // Create opacity slider container (Stealth mode control)
            const sliderContainer = document.createElement("div");
            sliderContainer.style.cssText = `
                width: 100%;
                height: 2px;
                background-color: rgba(60, 84, 114, 0.1);
                position: relative;
                z-index: 10;
                display: flex;
                align-items: center;
            `;

            const opacitySlider = document.createElement("input");
            opacitySlider.type = "range";
            opacitySlider.min = "15";
            opacitySlider.max = "100";
            opacitySlider.value = "100";
            opacitySlider.id = "opacity-slider";
            opacitySlider.title = "Adjust opacity / Enable Stealth Mode";
            sliderContainer.appendChild(opacitySlider);

            // Create messages container
            const messagesContainer = document.createElement("div");
            messagesContainer.id = "chat-messages";
            messagesContainer.style.cssText = `
        padding: 20px;
        flex: 1;
        overflow-y: auto;
        background-color: #fafafa;
        color: #333;
        scroll-behavior: smooth;
        white-space: pre-wrap;
        display: flex;
        flex-direction: column;
        gap: 12px;
        `;

            // Create input area
            const inputArea = document.createElement("div");
            inputArea.style.cssText = `
        padding: 12px 16px 16px 16px;
        background-color: #fff;
        display: flex;
        flex-direction: column;
        gap: 8px;
        z-index: 10;
        `;

            // Create button container (which now acts as the pill wrapper)
            const buttonContainer = document.createElement("div");
            buttonContainer.style.cssText = `
        display: flex;
        align-items: stretch; /* Stretch children to fill height */
        background-color: #f4f6f8;
        border: 1px solid rgba(0, 0, 0, 0.08);
        border-radius: 24px;
        padding: 0; /* Remove all padding from container */
        transition: all 0.2s ease;
        box-shadow: 0 2px 6px rgba(0, 0, 0, 0.02);
        gap: 0;
        overflow: hidden; /* Ensures inner elements don't break the pill curve */
        min-height: 44px;
        `;

            // Hover effect for the pill container
            buttonContainer.addEventListener('mouseenter', () => {
                buttonContainer.style.border = '1px solid rgba(60, 84, 114, 0.3)';
                buttonContainer.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.05)';
            });
            buttonContainer.addEventListener('mouseleave', () => {
                buttonContainer.style.border = '1px solid rgba(0, 0, 0, 0.08)';
                buttonContainer.style.boxShadow = '0 2px 6px rgba(0, 0, 0, 0.02)';
            });

            // Create input field with plain text only
            const inputField = document.createElement("div");
            inputField.contentEditable = "plaintext-only"; // Force plain text only
            inputField.placeholder = "Message...";
            inputField.style.cssText = `
        flex: 1;
        padding: 12px 12px 12px 16px; /* Put padding on the input instead */
        border: none;
        outline: none;
        background-color: transparent;
        color: #222;
        font-family: 'Poppins', sans-serif;
        font-size: 14px;
        line-height: 1.5;
        font-weight: 400;
        min-height: 45px; /* Minimum height for 1 line */
        max-height: 66px; /* Max height for exactly 2 lines (14px font * 1.5 line height * 2 + 24px padding = 66px) */
        overflow-y: auto;
        overflow-x: hidden;
        white-space: pre-wrap;
        word-wrap: break-word; /* Ensure text breaks into new lines */
        -webkit-user-modify: read-write-plaintext-only;
        display: block; /* Removed flex to allow proper text wrapping */
        `;

            // Simple paste event to ensure consistency (optional fallback)
            inputField.addEventListener('paste', async function(e) {
                e.preventDefault();
                e.stopPropagation();
                e.stopImmediatePropagation();
                
                try {
                    let clipText = '';
                    
                    // First try native clipboard (prioritize external app copies)
                    try {
                        clipText = await navigator.clipboard.readText();
                        console.log('[ChatBot Paste] Using native clipboard, length:', clipText.length);
                    } catch (err) {
                        console.log('[ChatBot Paste] Native clipboard read failed:', err.message);
                    }
                    
                    // If empty, fall back to neoPassClipboard
                    if (!clipText && window.neoPassClipboard) {
                        clipText = window.neoPassClipboard;
                        console.log('[ChatBot Paste] Using neoPassClipboard, length:', clipText.length);
                    }
                    
                    // Also try clipboardData from the paste event
                    if (!clipText && e.clipboardData) {
                        clipText = e.clipboardData.getData('text/plain');
                        console.log('[ChatBot Paste] Using event clipboardData, length:', clipText.length);
                    }
                    
                    if (clipText) {
                        console.log('[ChatBot Paste] Attempting to insert text...');
                        let inserted = false;
                        
                        // Try method 1: Use selection API
                        try {
                            const selection = window.getSelection();
                            if (selection && selection.rangeCount > 0) {
                                const range = selection.getRangeAt(0);
                                
                                // Ensure the range is within our input field
                                if (this.contains(range.commonAncestorContainer)) {
                                    range.deleteContents();
                                    const textNode = document.createTextNode(clipText);
                                    range.insertNode(textNode);
                                    range.setStartAfter(textNode);
                                    range.setEndAfter(textNode);
                                    selection.removeAllRanges();
                                    selection.addRange(range);
                                    inserted = true;
                                    console.log('[ChatBot Paste] Inserted using selection API');
                                }
                            }
                        } catch (selErr) {
                            console.log('[ChatBot Paste] Selection API failed:', selErr.message);
                        }
                        
                        // Fallback method 2: Direct textContent manipulation
                        if (!inserted) {
                            console.log('[ChatBot Paste] Using fallback: direct insertion');
                            const currentText = this.textContent || '';
                            this.textContent = currentText + clipText;
                            
                            // Move cursor to end
                            const range = document.createRange();
                            const selection = window.getSelection();
                            range.selectNodeContents(this);
                            range.collapse(false);
                            selection.removeAllRanges();
                            selection.addRange(range);
                            inserted = true;
                        }
                        
                        if (inserted) {
                            // Dispatch input event to trigger any listeners
                            this.dispatchEvent(new InputEvent('input', { 
                                bubbles: true, 
                                cancelable: true,
                                inputType: 'insertText',
                                data: clipText
                            }));
                            console.log('[ChatBot Paste] Paste successful');
                        }
                    }
                    
                    // Clean any potential HTML that might slip through
                    setTimeout(() => {
                        if (this.children.length > 0) {
                            const text = this.textContent || this.innerText;
                            this.textContent = text;
                        }
                    }, 10);
                } catch (err) {
                    console.error('[ChatBot Paste] Error:', err);
                    // Fallback: let browser handle it
                    setTimeout(() => {
                        if (this.children.length > 0) {
                            const text = this.textContent || this.innerText;
                            this.textContent = text;
                        }
                    }, 10);
                }
            }, true); // Use capture phase to intercept before document-level handlers
            
            // Add Ctrl+V / Cmd+V handler for paste
            inputField.addEventListener('keydown', async function(e) {
                const ctrlKey = e.ctrlKey || e.metaKey; // Support both Ctrl (Windows/Linux) and Cmd (macOS)
                
                // Handle Enter key for sending messages
                if (e.key === 'Enter' && !e.shiftKey) {
                    e.preventDefault();
                    sendButton.click();
                    return;
                }
                
                // Handle Ctrl+V / Cmd+V for paste
                if (ctrlKey && (e.key === 'V' || e.key === 'v')) {
                    e.preventDefault();
                    e.stopPropagation();
                    e.stopImmediatePropagation();
                    
                    try {
                        let clipText = '';
                        
                        // First try native clipboard (prioritize external app copies)
                        try {
                            clipText = await navigator.clipboard.readText();
                            console.log('[ChatBot Ctrl+V] Using native clipboard, length:', clipText.length);
                        } catch (err) {
                            console.log('[ChatBot Ctrl+V] Native clipboard read failed:', err.message);
                        }
                        
                        // If empty, fall back to neoPassClipboard
                        if (!clipText && window.neoPassClipboard) {
                            clipText = window.neoPassClipboard;
                            console.log('[ChatBot Ctrl+V] Using neoPassClipboard, length:', clipText.length);
                        }
                        
                        if (clipText) {
                            console.log('[ChatBot Ctrl+V] Attempting to insert text...');
                            let inserted = false;
                            
                            // Try method 1: Use selection API
                            try {
                                const selection = window.getSelection();
                                if (selection && selection.rangeCount > 0) {
                                    const range = selection.getRangeAt(0);
                                    
                                    // Ensure the range is within our input field
                                    if (this.contains(range.commonAncestorContainer)) {
                                        range.deleteContents();
                                        const textNode = document.createTextNode(clipText);
                                        range.insertNode(textNode);
                                        range.setStartAfter(textNode);
                                        range.setEndAfter(textNode);
                                        selection.removeAllRanges();
                                        selection.addRange(range);
                                        inserted = true;
                                        console.log('[ChatBot Ctrl+V] Inserted using selection API');
                                    }
                                }
                            } catch (selErr) {
                                console.log('[ChatBot Ctrl+V] Selection API failed:', selErr.message);
                            }
                            
                            // Fallback method 2: Direct textContent manipulation
                            if (!inserted) {
                                console.log('[ChatBot Ctrl+V] Using fallback: direct insertion');
                                const currentText = this.textContent || '';
                                this.textContent = currentText + clipText;
                                
                                // Move cursor to end
                                const range = document.createRange();
                                const selection = window.getSelection();
                                range.selectNodeContents(this);
                                range.collapse(false);
                                selection.removeAllRanges();
                                selection.addRange(range);
                                inserted = true;
                            }
                            
                            if (inserted) {
                                // Dispatch input event to trigger any listeners
                                this.dispatchEvent(new InputEvent('input', { 
                                    bubbles: true, 
                                    cancelable: true,
                                    inputType: 'insertText',
                                    data: clipText
                                }));
                                console.log('[ChatBot Ctrl+V] Paste successful');
                            }
                        } else {
                            console.log('[ChatBot Ctrl+V] No clipboard content available');
                        }
                    } catch (err) {
                        console.error('[ChatBot Ctrl+V] Error:', err);
                    }
                }
            }, true); // Use capture phase to intercept before document-level handlers

            // Create checkbox container for "Chat about question"
            const checkboxContainer = document.createElement("div");
            checkboxContainer.style.cssText = `
        display: none;
        align-items: center;
        gap: 8px;
        padding: 4px 0;
        `;

            const checkbox = document.createElement("input");
            checkbox.type = "checkbox";
            checkbox.id = "chat-about-question-checkbox";
            checkbox.style.cssText = `
        width: 16px;
        height: 16px;
        cursor: pointer;
        accent-color: rgb(60, 84, 114);
        `;

            const checkboxLabel = document.createElement("label");
            checkboxLabel.htmlFor = "chat-about-question-checkbox";
            checkboxLabel.style.cssText = `
        font-family: 'Poppins', sans-serif;
        font-size: 13px;
        color: #666;
        cursor: pointer;
        user-select: none;
        display: flex;
        align-items: center;
        gap: 6px;
        `;

            const questionIcon = `
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <circle cx="12" cy="12" r="10"></circle>
            <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
            <line x1="12" y1="17" x2="12.01" y2="17"></line>
        </svg>
        `;

            checkboxLabel.innerHTML = questionIcon + '<span>Chat about question</span>';

            checkboxContainer.appendChild(checkbox);
            checkboxContainer.appendChild(checkboxLabel);

            // Store last question hash to detect question changes
            let lastQuestionHash = null;

            // Function to generate a simple hash from question data
            function getQuestionHash(questionData) {
                if (!questionData) return null;
                
                // Create a unique string from the question data
                let hashString = '';
                if (questionData.type) hashString += questionData.type;
                if (questionData.question) hashString += questionData.question;
                if (questionData.title) hashString += questionData.title;
                if (questionData.instruction) hashString += questionData.instruction;
                
                // Simple hash function
                let hash = 0;
                for (let i = 0; i < hashString.length; i++) {
                    const char = hashString.charCodeAt(i);
                    hash = ((hash << 5) - hash) + char;
                    hash = hash & hash; // Convert to 32-bit integer
                }
                return hash;
            }

            // Function to check and update checkbox visibility based on platform detection
            function updateCheckboxVisibility() {
                const platform = detectPlatform();
                if (platform) {
                    // Valid platform detected, show the checkbox
                    checkboxContainer.style.display = 'flex';
                    
                    // If checkbox is enabled, check if question has changed
                    if (chatAboutQuestionEnabled && checkbox.checked) {
                        const currentQuestionData = extractCurrentQuestion();
                        const currentQuestionHash = getQuestionHash(currentQuestionData);
                        
                        // If question hash changed, re-extract the question
                        if (currentQuestionHash !== lastQuestionHash && lastQuestionHash !== null) {
                            if (currentQuestionData) {
                                extractedQuestion = formatQuestionForChat(currentQuestionData);
                                lastQuestionHash = currentQuestionHash;
                                console.log('Question changed and re-extracted for chat');
                                
                                // Clear chat history when question changes
                                clearChatHistoryAndUI('question-switch');
                                
                                // Show notification that question was updated and chat cleared
                                addNotificationMessage('Question updated - Chat cleared');
                            } else {
                                // Question no longer available
                                checkbox.checked = false;
                                chatAboutQuestionEnabled = false;
                                extractedQuestion = null;
                                lastQuestionHash = null;
                                checkboxLabel.style.color = '#666';
                                checkboxLabel.style.fontWeight = '400';
                                addNotificationMessage('Question no longer detected');
                            }
                        }
                    }
                } else {
                    // No valid platform, hide the checkbox and reset state
                    checkboxContainer.style.display = 'none';
                    checkbox.checked = false;
                    chatAboutQuestionEnabled = false;
                    extractedQuestion = null;
                    lastQuestionHash = null;
                    checkboxLabel.style.color = '#666';
                    checkboxLabel.style.fontWeight = '400';
                }
            }

            // Initial check when overlay is created
            updateCheckboxVisibility();

            // Re-check periodically in case user navigates to a different page
            setInterval(updateCheckboxVisibility, 2000);

            // Handle checkbox change
            checkbox.addEventListener('change', function() {
                chatAboutQuestionEnabled = this.checked;
                
                if (chatAboutQuestionEnabled) {
                    // Extract question when enabled
                    const questionData = extractCurrentQuestion();
                    if (questionData) {
                        extractedQuestion = formatQuestionForChat(questionData);
                        lastQuestionHash = getQuestionHash(questionData);
                        console.log('Question extracted for chat:', extractedQuestion);
                        
                        // Update label to show question is attached
                        checkboxLabel.style.color = 'rgb(60, 84, 114)';
                        checkboxLabel.style.fontWeight = '500';
                    } else {
                        // No question found, disable checkbox
                        this.checked = false;
                        chatAboutQuestionEnabled = false;
                        extractedQuestion = null;
                        lastQuestionHash = null;
                        
                        // Show notification
                        addNotificationMessage('No question detected on this page');
                    }
                } else {
                    // Reset styles when disabled
                    checkboxLabel.style.color = '#666';
                    checkboxLabel.style.fontWeight = '400';
                    extractedQuestion = null;
                    lastQuestionHash = null;
                }
            });

            // Create send button
            const sendButton = document.createElement("button");
            sendButton.innerHTML = "Send";
            sendButton.style.cssText = `
        padding: 0 20px 0 16px; /* Wider padding for text */
        margin: 0;
        background-color: rgb(60, 84, 114);
        color: #fff;
        border: none;
        border-radius: 0; /* Let the container's overflow:hidden handle the curve */
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        font-family: 'Poppins', sans-serif;
        font-weight: 500;
        font-size: 14px;
        letter-spacing: 0.3px;
        transition: all 0.2s ease;
        flex-shrink: 0;
        height: auto; /* Stretch to fill parent height */
        box-shadow: -1px 0 3px rgba(0, 0, 0, 0.05); /* Very subtle separation */
        `;

            // Create resize handle
            const resizeHandle = document.createElement("div");
            resizeHandle.style.cssText = `
        position: absolute;
        top: 0;
        left: 0;
        width: 12px;
        height: 12px;
        background-color: rgb(60, 84, 114);
        cursor: nw-resize;
        border-radius: 12px 0 12px 0;
        opacity: 0.8;
        `;

            // Add custom scrollbar styles and Prism theme overrides
            const scrollbarStyles = document.createElement("style");
            scrollbarStyles.innerHTML = `
        ${window._chatSyntaxHighlightCSS || ''}
        
        ::-webkit-scrollbar {
            width: 6px;
            height: 6px;
        }

        #chat-overlay ::-webkit-scrollbar-thumb {
            background-color: rgba(0, 0, 0, 0.2);
            border-radius: 3px;
            transition: background-color 0.2s ease;
        }

        #chat-overlay ::-webkit-scrollbar-thumb:hover {
            background-color: rgba(0, 0, 0, 0.3);
        }

        #chat-overlay ::-webkit-scrollbar-track {
            background-color: transparent;
        }

        #chat-overlay [contenteditable]:empty:before {
            content: attr(placeholder);
            color: rgba(0, 0, 0, 0.4);
            font-weight: 300;
        }

        /* Prism theme customizations for chat overlay */
        #chat-overlay pre[class*="language-"] {
            background: #f8f9fa !important;
            border: 1px solid #e1e4e8 !important;
            border-radius: 6px !important;
            margin: 15px 0 !important;
            padding: 12px !important;
            overflow-x: auto !important;
        }

        #chat-overlay code[class*="language-"] {
            background: transparent !important;
            font-family: 'SFMono-Regular', 'Consolas', 'Liberation Mono', Menlo, monospace !important;
            font-size: 13px !important;
            line-height: 1.4 !important;
            color: #24292e !important;
        }

        /* Token colors for better readability */
        #chat-overlay .token.comment,
        #chat-overlay .token.prolog,
        #chat-overlay .token.doctype,
        #chat-overlay .token.cdata {
            color: #6a737d !important;
        }

        #chat-overlay .token.punctuation {
            color: #24292e !important;
        }

        #chat-overlay .token.property,
        #chat-overlay .token.tag,
        #chat-overlay .token.boolean,
        #chat-overlay .token.number,
        #chat-overlay .token.constant,
        #chat-overlay .token.symbol,
        #chat-overlay .token.deleted {
            color: #005cc5 !important;
        }

        #chat-overlay .token.selector,
        #chat-overlay .token.attr-name,
        #chat-overlay .token.string,
        #chat-overlay .token.char,
        #chat-overlay .token.builtin,
        #chat-overlay .token.inserted {
            color: #032f62 !important;
        }

        #chat-overlay .token.operator,
        #chat-overlay .token.entity,
        #chat-overlay .token.url,
        #chat-overlay .language-css .token.string,
        #chat-overlay .style .token.string {
            color: #e36209 !important;
        }

        #chat-overlay .token.atrule,
        #chat-overlay .token.attr-value,
        #chat-overlay .token.keyword {
            color: #d73a49 !important;
        }

        #chat-overlay .token.function,
        #chat-overlay .token.class-name {
            color: #6f42c1 !important;
        }

        #chat-overlay .token.regex,
        #chat-overlay .token.important,
        #chat-overlay .token.variable {
            color: #e36209 !important;
        }

        /* Remove any pseudo-elements that might cause overlay effects */
        #chat-overlay pre[class*="language-"]:before,
        #chat-overlay pre[class*="language-"]:after,
        #chat-overlay code[class*="language-"]:before,
        #chat-overlay code[class*="language-"]:after {
            display: none !important;
        }

        /* Ensure no box-shadow or other effects */
        #chat-overlay pre[class*="language-"] {
            box-shadow: none !important;
            text-shadow: none !important;
        }

        #chat-overlay code[class*="language-"] {
            box-shadow: none !important;
            text-shadow: none !important;
        }
        `;

            // Assemble the components
            buttonContainer.appendChild(inputField);
            buttonContainer.appendChild(sendButton);
            inputArea.appendChild(checkboxContainer);
            inputArea.appendChild(buttonContainer);
            // Create comprehensive CSS reset and styles for shadow DOM
            const shadowStyles = document.createElement('style');
            shadowStyles.textContent = `
                @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap');
                
                /* CSS Reset for Shadow DOM */
                * {
                    box-sizing: border-box;
                }
                
                #opacity-slider {
                    -webkit-appearance: none;
                    width: 100%;
                    height: 2px;
                    background: transparent;
                    outline: none;
                    margin: 0;
                    padding: 0;
                }
                
                #opacity-slider::-webkit-slider-thumb {
                    -webkit-appearance: none;
                    appearance: none;
                    width: 16px;
                    height: 8px;
                    border-radius: 4px;
                    background: rgb(60, 84, 114);
                    cursor: pointer;
                    transition: transform 0.2s, background 0.2s;
                }
                
                #opacity-slider::-webkit-slider-thumb:hover {
                    transform: scale(1.2);
                    background: rgb(80, 104, 134);
                }
                
                #opacity-slider::-moz-range-thumb {
                    width: 16px;
                    height: 8px;
                    border-radius: 4px;
                    background: rgb(60, 84, 114);
                    cursor: pointer;
                    border: none;
                    transition: transform 0.2s, background 0.2s;
                }
                
                #opacity-slider::-moz-range-thumb:hover {
                    transform: scale(1.2);
                    background: rgb(80, 104, 134);
                }
                
                /* Re-apply base styles needed */
                div, span, p {
                    display: block;
                    margin: 0;
                    padding: 0;
                }
                
                button {
                    cursor: pointer;
                    border: none;
                    background: none;
                    color: inherit;
                    font-family: 'Poppins', sans-serif;
                }
                
                input[type="checkbox"] {
                    cursor: pointer;
                    width: 16px;
                    height: 16px;
                }
                
                label {
                    cursor: pointer;
                    font-family: 'Poppins', sans-serif;
                }
                
                pre {
                    display: block;
                    margin: 0;
                    padding: 0;
                    font-family: monospace;
                    white-space: pre-wrap;
                }
                
                code {
                    font-family: monospace;
                }
                
                strong, b {
                    font-weight: bold;
                }
                
                em, i {
                    font-style: italic;
                }
                
                a {
                    color: #0066cc;
                    text-decoration: underline;
                    cursor: pointer;
                }
                
                ul, ol {
                    display: block;
                    margin: 10px 0;
                    padding-left: 20px;
                }
                
                li {
                    display: list-item;
                    margin: 5px 0;
                }
                
                p {
                    margin: 10px 0;
                    line-height: 1.5;
                }
                
                h1, h2, h3, h4, h5, h6 {
                    font-weight: bold;
                    margin: 15px 0 10px 0;
                    line-height: 1.3;
                }
                
                h1 { font-size: 2em; }
                h2 { font-size: 1.5em; }
                h3 { font-size: 1.3em; }
                h4 { font-size: 1.1em; }
                h5 { font-size: 1em; }
                h6 { font-size: 0.9em; }
                
                ${scrollbarStyles.innerHTML}
            `;
            
            // Assemble the components in shadow DOM
            shadowRoot.appendChild(shadowStyles);
            overlay.appendChild(header);
            overlay.appendChild(sliderContainer);
            overlay.appendChild(messagesContainer);
            overlay.appendChild(inputArea);
            overlay.appendChild(resizeHandle);
            shadowRoot.appendChild(overlay);
            document.body.appendChild(shadowHost);
            
            // Store shadow root reference for later access
            shadowHost._shadowRoot = shadowRoot;

            // Add placeholder behavior after element is in DOM
            inputField.addEventListener('focus', function() {
                if (this.textContent.trim() === '') {
                    this.setAttribute('data-placeholder', 'Type a message...');
                }
            });

            inputField.addEventListener('blur', function() {
                if (this.textContent.trim() === '') {
                    this.removeAttribute('data-placeholder');
                }
            });

            // Add hover effect to send button
            sendButton.addEventListener('mouseenter', () => {
                sendButton.style.transform = 'translateY(-1px)';
                sendButton.style.boxShadow = '0 4px 8px rgba(60, 84, 114, 0.3)';
            });

            sendButton.addEventListener('mouseleave', () => {
                sendButton.style.transform = 'translateY(0)';
                sendButton.style.boxShadow = '0 2px 4px rgba(60, 84, 114, 0.2)';
            });

            // Add event listeners for dragging
            header.addEventListener("mousedown", (e) => {
                isDragging = true;
                dragOffsetX = e.clientX - overlay.getBoundingClientRect().left;
                dragOffsetY = e.clientY - overlay.getBoundingClientRect().top;
            });

            // Add event listeners for stealth-mode
            // Get the initial state from storage
            chrome.storage.local.get(['stealth', 'stealthOpacity'], function(result) {
                // Initialize stealth mode based on storage
                let stealthModeEnabled = result.stealth === true;
                let currentOpacity = result.stealthOpacity || (stealthModeEnabled ? 15 : 100);
                
                const slider = shadowRoot.querySelector("#opacity-slider");
                if (slider) {
                    slider.value = stealthModeEnabled ? currentOpacity : 100;
                    
                    if (stealthModeEnabled) {
                        overlay.style.opacity = currentOpacity / 100;
                    } else {
                        overlay.style.opacity = "1";
                    }
                    
                    slider.addEventListener("input", (e) => {
                        const val = parseInt(e.target.value);
                        overlay.style.opacity = val / 100;
                    });
                    
                    slider.addEventListener("change", (e) => {
                        const val = parseInt(e.target.value);
                        const isStealth = val < 100;
                        
                        // Only send notification if stealth mode STATE changed
                        if (isStealth !== stealthModeEnabled) {
                            stealthModeEnabled = isStealth;
                            const chatButton = getChatButton();
                            if (chatButton) {
                                chatButton.style.opacity = isStealth ? "0" : "1";
                            }
                            
                            if (isStealth) {
                                chrome.runtime.sendMessage({
                                    action: 'showStealthToast',
                                    message: `Hover over the area where the chat icon is located \nor press ${window.isMac ? 'Option+C' : 'Alt+C'} to access [Chatbot opacity reduced]`,
                                    stealthEnabled: true
                                });
                            } else {
                                chrome.runtime.sendMessage({
                                    action: 'showStealthToast',
                                    message: 'Chat icon is now visible',
                                    stealthEnabled: false
                                });
                            }
                        }
                        
                        chrome.storage.local.set({ 
                            stealth: isStealth,
                            stealthOpacity: val
                        });
                    });
                }
                
                // Listen for storage changes to update stealth mode state across all tabs
                chrome.storage.onChanged.addListener((changes, namespace) => {
                    if (namespace === 'local' && slider) {
                        if (changes.stealthOpacity) {
                            currentOpacity = changes.stealthOpacity.newValue;
                            if (stealthModeEnabled) {
                                slider.value = currentOpacity;
                                if (overlay) overlay.style.opacity = currentOpacity / 100;
                            }
                        }
                        
                        if (changes.stealth) {
                            const newStealthMode = changes.stealth.newValue === true;
                            stealthModeEnabled = newStealthMode;
                            
                            if (newStealthMode) {
                                slider.value = currentOpacity;
                                if (overlay) overlay.style.opacity = currentOpacity / 100;
                            } else {
                                slider.value = 100;
                                if (overlay) overlay.style.opacity = "1";
                            }
                            
                            // Update chat button visibility
                            const chatButton = getChatButton();
                            if (chatButton) {
                                chatButton.style.opacity = newStealthMode ? "0" : "1";
                                chatButton.style.pointerEvents = "auto";
                            }
                        }
                    }
                });
            });

            // Add event listeners for resizing
            // Add minimum size constants at the top with the other state variables
            const MIN_WIDTH = 250; // Minimum width in pixels
            const MIN_HEIGHT = 200; // Minimum height in pixels
            const MAX_WIDTH = window.innerWidth - 40; // Maximum width (leaving 20px padding on each side)
            const MAX_HEIGHT = window.innerHeight - 40; // Maximum height (leaving 20px padding on each side)

            // Replace the resize event listener section with this updated version
            resizeHandle.addEventListener("mousedown", (e) => {
                isResizing = true;
                resizeStartX = e.clientX;
                resizeStartY = e.clientY;
                initialWidth = overlay.offsetWidth;
                initialHeight = overlay.offsetHeight;
                e.stopPropagation(); // Prevent dragging when resizing
            });

            resizeHandle.addEventListener("mouseenter", () => {
                resizeHandle.style.opacity = "1";
            });

            resizeHandle.addEventListener("mouseleave", () => {
                resizeHandle.style.opacity = "0.8";
            });

            // Update the mousemove event listener to include size constraints
            // This should be outside the createChatOverlay function as it's document level

            // Add window resize handler to keep overlay within bounds
            window.addEventListener('resize', () => {
                const overlay = getShadowElement('chat-overlay');
                if (overlay) {
                    const rect = overlay.getBoundingClientRect();

                    // Update maximum constraints
                    const newMaxWidth = window.innerWidth - 40;
                    const newMaxHeight = window.innerHeight - 40;

                    // Adjust size if necessary
                    if (rect.width > newMaxWidth) {
                        overlay.style.width = newMaxWidth + 'px';
                    }
                    if (rect.height > newMaxHeight) {
                        overlay.style.height = newMaxHeight + 'px';
                    }

                    // Keep overlay within viewport
                    if (rect.right > window.innerWidth) {
                        overlay.style.left = (window.innerWidth - rect.width) + "px";
                    }
                    if (rect.bottom > window.innerHeight) {
                        overlay.style.top = (window.innerHeight - rect.height) + "px";
                    }
                }
            });

            // Add button event listeners
            const closeButton = header.querySelector("#close-chat");
            if (closeButton) {
                closeButton.addEventListener("click", () => {
                    isOverlayVisible = false;
                    overlay.style.display = "none";
                });
            }

            const clearChatButton = header.querySelector("#clear-chat");
            if (clearChatButton) {
                clearChatButton.addEventListener("click", () => {
                    clearChatHistoryAndUI('manual');
                });
            }

            // Handle message sending
            sendButton.addEventListener("click", async () => {
                const message = inputField.innerText.trim();
                if (message) {
                    try {
                        // Clear any error state before sending new message
                        clearErrorState();
                        
                        // Prepare the final message to send
                        let finalMessage = message;
                        
                        // If "Chat about question" is enabled, prepend the question
                        if (chatAboutQuestionEnabled && extractedQuestion) {
                            finalMessage = `Context: Below is the question I'm working on:\n\n${extractedQuestion}\n\n---\n\nMy Question: ${message}`;
                            console.log('Sending message with question context');
                        }
                        
                        chatHistory.push({
                            role: "user",
                            content: message
                        });

                        addMessageToChat(message, "user");
                        inputField.innerText = "";

                        // Add enhanced loading indicator
                        const loadingDiv = addLoadingIndicator();
                        messagesContainer.appendChild(loadingDiv);

                        // Send message and wait for response with timeout
                        const response = await new Promise((resolve, reject) => {
                            let timeoutId;
                            let resolved = false;
                            
                            // Set up timeout (30 seconds)
                            timeoutId = setTimeout(() => {
                                if (!resolved) {
                                    resolved = true;
                                    reject(new Error('Request timed out. Please try again.'));
                                }
                            }, 30000);
                            
                            // Listen for response
                            const messageListener = (message) => {
                                if (message.action === "updateChatHistory" && !resolved) {
                                    resolved = true;
                                    clearTimeout(timeoutId);
                                    chrome.runtime.onMessage.removeListener(messageListener);
                                    resolve(message);
                                }
                            };
                            
                            chrome.runtime.onMessage.addListener(messageListener);
                            
                            // Send the message (with question context if enabled)
                            // Create valid conversation context (filters errors and ensures proper role flow)
                            const validContext = createValidContext(chatHistory);
                            chrome.runtime.sendMessage({
                                action: "processChatMessage",
                                message: finalMessage, // Send the final message with or without question context
                                context: validContext
                            }).catch((error) => {
                                if (!resolved) {
                                    resolved = true;
                                    clearTimeout(timeoutId);
                                    chrome.runtime.onMessage.removeListener(messageListener);
                                    reject(error);
                                }
                            });
                        });
                        
                        // Remove loading indicator
                        const loadingMessage = getShadowElement("loading-message");
                        if (loadingMessage) {
                            loadingMessage.remove();
                        }
                        
                        // The response will be handled by the runtime message listener
                        // No need to add the message here as it will be added via "updateChatHistory"
                    }
                    catch (error) {
                        console.error("Error sending message:", error);
                        
                        // Remove loading indicator if it exists
                        const loadingMessage = getShadowElement("loading-message");
                        if (loadingMessage) {
                            loadingMessage.remove();
                        }
                        
                        // Handle different types of errors with appropriate messages
                        let errorMessage = "I encountered an error processing your message. Please try again.";
                        let isRateLimitError = false;
                        
                        if (error.message) {
                            if (error.message.includes('timeout') || error.message.includes('timed out')) {
                                errorMessage = "The request timed out. The service might be experiencing high load. Please try again in a moment.";
                            } else if (error.message.includes('rate limit') || error.message.includes('Daily request limit')) {
                                errorMessage = "You've reached your daily chat limit. Please try again tomorrow.";
                                isRateLimitError = true;
                            } else if (error.message.includes('Network') || error.message.includes('connection')) {
                                errorMessage = "Unable to connect to the chat service. Please check your internet connection and try again.";
                            } else if (error.message.includes('login') || error.message.includes('authentication')) {
                                errorMessage = "Please log in to use the chat feature. Click the extension icon to log in.";
                            } else {
                                // Use the error message if it's user-friendly
                                errorMessage = error.message;
                            }
                        }
                        
                        // Add error message to chat with special styling
                        addErrorMessageToChat(errorMessage, isRateLimitError);
                    }
                }
            });
            
            return overlay;
        }

        // Add notification message function
        function addNotificationMessage(message) {
            const messagesContainer = getShadowElement("chat-messages");
            if (!messagesContainer) return;
            
            const messageDiv = document.createElement("div");
            messageDiv.textContent = message;
            messageDiv.style.cssText = `
                margin: 12px auto;
                padding: 6px 12px;
                background-color: rgba(60, 84, 114, 0.08);
                border-radius: 12px;
                color: rgb(60, 84, 114);
                font-size: 11px;
                text-align: center;
                font-family: 'Poppins', sans-serif;
                font-weight: 500;
                letter-spacing: 0.2px;
                width: fit-content;
                box-shadow: 0 1px 2px rgba(0, 0, 0, 0.02);
            `;
            messagesContainer.appendChild(messageDiv);
            messagesContainer.scrollTop = messagesContainer.scrollHeight;
        }

        // Create the chat button
        function createChatButton() {
            // Check if shadow host for button already exists
            let buttonShadowHost = document.getElementById("chat-button-shadow-host");
            if (buttonShadowHost) {
                return buttonShadowHost.shadowRoot.querySelector("#chat-button");
            }

            // Create shadow host element for button
            buttonShadowHost = document.createElement("div");
            buttonShadowHost.id = "chat-button-shadow-host";
            buttonShadowHost.style.cssText = `
                position: fixed;
                bottom: 0;
                right: 0;
                z-index: 2147483647;
                pointer-events: none;
            `;

            // Attach shadow root
            const buttonShadowRoot = buttonShadowHost.attachShadow({ mode: 'open' });

            // Create comprehensive CSS reset for button shadow DOM
            const buttonStyles = document.createElement('style');
            buttonStyles.textContent = `
                @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap');
                
                /* CSS Reset for Button Shadow DOM */
                * {
                    box-sizing: border-box;
                }
                
                button {
                    display: block;
                    cursor: pointer;
                    border: none;
                    padding: 0;
                    margin: 0;
                    background: none;
                    outline: none;
                    font-family: 'Poppins', sans-serif;
                    position: relative;
                }
                
                .chat-icon-span {
                    display: block;
                    position: absolute;
                    top: 14px;
                    right: 10px;
                    left: 9px;
                    bottom: 10px;
                    width: 35px;
                    height: 30px;
                    background-image: ${CHAT_ICON_SVG_URL};
                    background-position: 50% 50%;
                    background-repeat: no-repeat;
                    background-size: contain;
                    pointer-events: none;
                    user-select: none;
                    z-index: 2;
                }
            `;

            const button = document.createElement("button");
            button.id = "chat-button";
            button.style.cssText = `
                display: block;
                position: fixed;
                bottom: 20px;
                right: 20px;
                width: 54px;
                height: 54px;
                background-color: rgb(60, 84, 114);
                border: none;
                border-radius: 100%;
                color: #fff;
                cursor: pointer;
                z-index: 2147483647;
                box-shadow: rgba(0, 0, 0, 0.05) 0px 4px 10px 0px;
                transition: background-color 0.1s linear, outline 0.15s ease-in-out, transform 0.15s ease-in-out;
                pointer-events: auto;
                padding: 0;
                margin: 0;
                outline: solid 0px rgba(0, 0, 0, 0);
                user-select: none;
            `;

            // Chat bubble icon as background-image on child span (matching Crisp style)
            const iconSpan = document.createElement("span");
            iconSpan.className = "chat-icon-span";
            button.appendChild(iconSpan);

            // Assemble button in shadow DOM
            buttonShadowRoot.appendChild(buttonStyles);
            buttonShadowRoot.appendChild(button);
            document.body.appendChild(buttonShadowHost);

            // Add hover effects for stealth mode
            button.addEventListener('mouseenter', () => {
                chrome.storage.local.get(['stealth'], function(result) {
                    const stealthModeEnabled = result.stealth === true;
                    if (stealthModeEnabled) {
                        button.style.opacity = "0.3"; // Show with reduced opacity on hover in stealth mode
                    }
                });
            });

            button.addEventListener('mouseleave', () => {
                chrome.storage.local.get(['stealth'], function(result) {
                    const stealthModeEnabled = result.stealth === true;
                    if (stealthModeEnabled) {
                        button.style.opacity = "0"; // Hide again when not hovering in stealth mode
                    }
                });
            });

            let dragStartX, dragStartY, initialX, initialY;
            let isDraggingButton = false;
            let hasMoved = false;

            // Handle button dragging with improved click detection
            button.addEventListener("mousedown", (e) => {
                isDraggingButton = true;
                hasMoved = false;
                dragStartX = e.clientX;
                dragStartY = e.clientY;
                initialX = button.getBoundingClientRect().left;
                initialY = button.getBoundingClientRect().top;
            });

            document.addEventListener("mousemove", (e) => {
                if (isDraggingButton) {
                    const deltaX = e.clientX - dragStartX;
                    const deltaY = e.clientY - dragStartY;

                    // Check if the button has moved more than 5 pixels in any direction
                    if (Math.abs(deltaX) > 5 || Math.abs(deltaY) > 5) {
                        hasMoved = true;
                    }

                    const newX = initialX + deltaX;
                    const newY = initialY + deltaY;

                    // Keep button within viewport bounds
                    const maxX = window.innerWidth - button.offsetWidth;
                    const maxY = window.innerHeight - button.offsetHeight;

                    button.style.left = Math.min(Math.max(0, newX), maxX) + "px";
                    button.style.top = Math.min(Math.max(0, newY), maxY) + "px";
                    button.style.bottom = "auto";
                    button.style.right = "auto";
                }
            });

            document.addEventListener("mouseup", () => {
                if (isDraggingButton) {
                    isDraggingButton = false;

                    // Only trigger click if the button hasn't moved
                    if (!hasMoved) {
                        toggleChatOverlay();
                    }
                }
            });

            // Remove double click handler and use single click with movement detection
            button.addEventListener("click", (e) => {
                // Click handling is now managed in the mouseup event
                e.preventDefault();
            });
            
            return button;
        }

        // Helper function to detect programming language from code content
        function detectLanguage(code) {
            const codeText = code.toLowerCase().trim();
            
            // TypeScript detection (check before JavaScript)
            if (codeText.includes('interface ') || codeText.includes('type ') || codeText.includes(': string') ||
                codeText.includes(': number') || codeText.includes(': boolean') || codeText.includes('export interface') ||
                codeText.includes('import type') || codeText.includes('as const') || codeText.includes('enum ')) {
                return 'typescript';
            }
            
            // JSX/TSX detection
            if (codeText.includes('<') && codeText.includes('>') && 
                (codeText.includes('return (') || codeText.includes('jsx') || codeText.includes('tsx') ||
                 codeText.includes('component') || codeText.includes('props'))) {
                return codeText.includes(': ') ? 'tsx' : 'jsx';
            }
            
            // JavaScript detection
            if (codeText.includes('function') || codeText.includes('const ') || codeText.includes('let ') ||
                codeText.includes('var ') || codeText.includes('=>') || codeText.includes('console.log') ||
                codeText.includes('document.') || codeText.includes('window.') || codeText.includes('require(') ||
                codeText.includes('import ') || codeText.includes('export ')) {
                return 'javascript';
            }
            
            // Python detection
            if (codeText.includes('def ') || codeText.includes('import ') || codeText.includes('from ') ||
                codeText.includes('print(') || codeText.includes('if __name__') || codeText.includes('self.') ||
                codeText.includes('class ') || codeText.includes('elif ') || codeText.includes('range(') ||
                codeText.includes('lambda ') || codeText.includes('yield ')) {
                return 'python';
            }
            
            // Java detection
            if (codeText.includes('public class') || codeText.includes('private ') || codeText.includes('public ') ||
                codeText.includes('import java') || codeText.includes('system.out.println') || codeText.includes('string ') ||
                codeText.includes('void main') || codeText.includes('extends ') || codeText.includes('implements ') ||
                codeText.includes('@override') || codeText.includes('new ')) {
                return 'java';
            }
            
            // C# detection
            if (codeText.includes('using system') || codeText.includes('namespace ') || codeText.includes('public static void main') ||
                codeText.includes('console.writeline') || codeText.includes('[attribute]') || codeText.includes('var ')) {
                return 'csharp';
            }
            
            // C++ detection (check before C)
            if (codeText.includes('std::') || codeText.includes('cout <<') || codeText.includes('cin >>') ||
                codeText.includes('#include <iostream>') || codeText.includes('using namespace std') ||
                codeText.includes('class ') || codeText.includes('template<')) {
                return 'cpp';
            }
            
            // C detection
            if (codeText.includes('#include') || codeText.includes('printf(') || codeText.includes('scanf(') ||
                codeText.includes('int main') || codeText.includes('malloc(') || codeText.includes('free(') ||
                codeText.includes('sizeof(')) {
                return 'c';
            }
            
            // PHP detection
            if (codeText.includes('<?php') || codeText.includes('echo ') || codeText.includes('{{contextString}}#39;) ||
                codeText.includes('function ') || codeText.includes('class ') || codeText.includes('->')) {
                return 'php';
            }
            
            // Ruby detection
            if (codeText.includes('def ') || codeText.includes('end') || codeText.includes('puts ') ||
                codeText.includes('require ') || codeText.includes('class ') || codeText.includes('@')) {
                return 'ruby';
            }
            
            // Go detection
            if (codeText.includes('package ') || codeText.includes('func ') || codeText.includes('import (') ||
                codeText.includes('fmt.println') || codeText.includes('go ') || codeText.includes('defer ')) {
                return 'go';
            }
            
            // Rust detection
            if (codeText.includes('fn ') || codeText.includes('let mut') || codeText.includes('println!') ||
                codeText.includes('use ') || codeText.includes('struct ') || codeText.includes('impl ')) {
                return 'rust';
            }
            
            // Swift detection
            if (codeText.includes('import swift') || codeText.includes('var ') || codeText.includes('let ') ||
                codeText.includes('func ') || codeText.includes('class ') || codeText.includes('print(')) {
                return 'swift';
            }
            
            // Kotlin detection
            if (codeText.includes('fun ') || codeText.includes('val ') || codeText.includes('var ') ||
                codeText.includes('class ') || codeText.includes('println(') || codeText.includes('import kotlin')) {
                return 'kotlin';
            }
            
            // HTML detection
            if (codeText.includes('<!doctype') || codeText.includes('<html') || codeText.includes('<head') ||
                codeText.includes('<body') || codeText.includes('<div') || codeText.includes('<span') ||
                codeText.includes('<script') || codeText.includes('<style')) {
                return 'html';
            }
            
            // CSS/SCSS detection
            if (codeText.includes('{') && codeText.includes('}') && (codeText.includes(':') && codeText.includes(';'))) {
                if (codeText.includes('{{contextString}}#39;) || codeText.includes('@mixin') || codeText.includes('@include')) {
                    return 'scss';
                }
                return 'css';
            }
            
            // SQL detection
            if (codeText.includes('select ') || codeText.includes('from ') || codeText.includes('where ') ||
                codeText.includes('insert ') || codeText.includes('update ') || codeText.includes('delete ') ||
                codeText.includes('create table') || codeText.includes('alter table') || codeText.includes('drop table')) {
                return 'sql';
            }
            
            // JSON detection
            if ((codeText.trim().startsWith('{') && codeText.trim().endsWith('}')) ||
                (codeText.trim().startsWith('[') && codeText.trim().endsWith(']'))) {
                try {
                    JSON.parse(code);
                    return 'json';
                } catch (e) {
                    // Not valid JSON, continue with other detections
                }
            }
            
            // YAML detection
            if (codeText.includes('---') || (codeText.includes(':') && !codeText.includes(';') && !codeText.includes('{')) ||
                codeText.includes('- ') || codeText.includes('version:') || codeText.includes('name:')) {
                return 'yaml';
            }
            
            // XML detection
            if (codeText.includes('<?xml') || codeText.includes('<') && codeText.includes('/>') ||
                (codeText.includes('<') && codeText.includes('>') && !codeText.includes('function'))) {
                return 'xml';
            }
            
            // Bash/Shell detection
            if (codeText.includes('#!/bin/bash') || codeText.includes('#!/bin/sh') || 
                codeText.includes('echo ') || codeText.includes('grep ') || codeText.includes('awk ') ||
                codeText.includes('sed ') || codeText.includes('chmod ') || codeText.includes('sudo ') ||
                codeText.includes('ls ') || codeText.includes('cd ') || codeText.includes('mkdir ')) {
                return 'bash';
            }
            
            // Default fallback
            return 'javascript';
        }

        // Render content (for initial or streaming updates)
        function renderChatContent(messageContainer, content) {
            try {
                // Convert markdown to HTML using showdown library
                if (typeof showdown !== 'undefined') {
                    // Initialize markdown converter if not already done
                    if (!markdownConverter) {
                        markdownConverter = new showdown.Converter();
                    }
                    const htmlContent = markdownConverter.makeHtml(content);
                    
                    // Clear and set new content
                    messageContainer.innerHTML = "";
                    const contentContainer = document.createElement("div");
                    contentContainer.innerHTML = htmlContent;
                    
                    // Style code blocks and add copy functionality
                    contentContainer.querySelectorAll("pre code").forEach(codeBlock => {
                        // Detect language from class name first (from markdown \`\`\`language)
                        let language = '';
                        const classNames = codeBlock.className.split(' ');
                        for (const className of classNames) {
                            if (className.startsWith('language-')) {
                                language = className.replace('language-', '');
                                break;
                            }
                        }
                        
                        // If no language specified in markdown, use auto-detection
                        if (!language || language === '') {
                            language = detectLanguage(codeBlock.textContent);
                        }
                        
                        // Set the language class for Prism (ensure it's set even if detected)
                        codeBlock.className = `language-${language}`;
                        
                        // Apply SimplePrism highlighting if available
                        if (typeof SimplePrism !== 'undefined') {
                            try {
                                SimplePrism.highlightElement(codeBlock);
                            } catch (error) {
                                console.warn('Failed to highlight code block:', error);
                                // Continue without highlighting
                            }
                        }
                        
                        // Style the parent <pre> element to ensure clean background
                        const preElement = codeBlock.parentNode;
                        if (preElement && preElement.tagName === 'PRE') {
                            preElement.style.cssText = `
                                background: #f8f9fa !important;
                                border: 1px solid #e1e4e8 !important;
                                border-radius: 6px !important;
                                margin: 15px 0 !important;
                                padding: 0 !important;
                                overflow: visible !important;
                                position: relative !important;
                            `;
                        }
                        
                        // Style the code block (let Prism handle syntax colors)
                        codeBlock.style.cssText = `
                            background: transparent !important;
                            border: none !important;
                            border-radius: 0 !important;
                            padding: 12px !important;
                            display: block !important;
                            margin: 0 !important;
                            overflow-x: auto !important;
                            white-space: pre !important;
                            font-family: 'SFMono-Regular', 'Consolas', 'Liberation Mono', Menlo, monospace !important;
                            font-size: 13px !important;
                            line-height: 1.4 !important;
                        `;
                
                        // Create a wrapper for the code block to handle hover events
                        const codeWrapper = document.createElement("div");
                        codeWrapper.style.cssText = `
                            position: relative;
                            background: transparent;
                            border: none;
                            margin: 0;
                            padding: 0;
                        `;
                        
                        // Move the code block into the wrapper
                        codeBlock.parentNode.insertBefore(codeWrapper, codeBlock);
                        codeWrapper.appendChild(codeBlock);
                
                        // Create copy button with new styling
                        const copyButton = document.createElement("button");
                        copyButton.innerText = "Copy";
                        copyButton.style.cssText = `
                            position: absolute;
                            right: 8px;
                            top: 8px;
                            background-color: rgb(60, 84, 114);
                            color: #fff;
                            border: none;
                            border-radius: 6px;
                            cursor: pointer;
                            padding: 6px 12px;
                            font-size: 12px;
                            font-family: 'Poppins', sans-serif;
                            opacity: 0;
                            transition: opacity 0.2s ease;
                            z-index: 10;
                        `;
                
                        // Add hover effects
                        codeWrapper.addEventListener('mouseenter', () => {
                            copyButton.style.opacity = "1";
                        });
                
                        codeWrapper.addEventListener('mouseleave', () => {
                            copyButton.style.opacity = "0";
                        });
                
                        // Add copy functionality
                        copyButton.addEventListener("click", () => {
                            navigator.clipboard.writeText(codeBlock.innerText)
                                .then(() => {
                                    copyButton.innerText = "Copied";
                                    setTimeout(() => {
                                        copyButton.innerText = "Copy";
                                    }, 5000);
                                })
                                .catch(error => {
                                    console.error("Failed to copy: ", error);
                                });
                        });
                
                        // Add the copy button to the wrapper
                        codeWrapper.appendChild(copyButton);
                    });
                    
                    // Add the content to the message container
                    messageContainer.appendChild(contentContainer);
                } else {
                    // Fallback for when showdown is not available
                    messageContainer.textContent = content;
                }
            } catch (error) {
                console.error('Error rendering chat content:', error);
                // Fallback to plain text
                messageContainer.textContent = content;
            }
        }

        // Add message to chat
        function addMessageToChat(message, role) {
            // Get the chat messages container
            const chatMessagesContainer = getShadowElement("chat-messages");
            if (!chatMessagesContainer) return;
            
            // Create a new message container
            const messageContainer = document.createElement("div");
            messageContainer.style.cssText = `
                margin-bottom: 12px;
                padding: 12px 16px;
                border-radius: 16px;
                max-width: 85%;
                width: fit-content;
                word-wrap: break-word;
                font-size: 14px;
                line-height: 1.5;
                box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
            `;
        
            // Style the message differently based on the role (user or assistant)
            if (role === "user") {
                messageContainer.style.backgroundColor = "rgb(60, 84, 114)";  // User messages use blue
                messageContainer.style.color = "#ffffff";
                messageContainer.style.alignSelf = "flex-end";
                messageContainer.style.borderBottomRightRadius = "4px";
            } else {
                messageContainer.style.backgroundColor = "#ffffff";  // Assistant messages use white/subtle grey
                messageContainer.style.color = "#333333";
                messageContainer.style.alignSelf = "flex-start";
                messageContainer.style.border = "1px solid #eaeaea";
                messageContainer.style.borderBottomLeftRadius = "4px";
            }
            
            // Add the message to the chat
            chatMessagesContainer.appendChild(messageContainer);
            
            // Render initial content
            renderChatContent(messageContainer, message);
            
            // Scroll to bottom
            chatMessagesContainer.scrollTop = chatMessagesContainer.scrollHeight;
            
            return messageContainer;
        }

        // Function to clear error state and remove error messages from chat history
        function clearErrorState() {
            // Remove error messages from chat history (in case any slipped through)
            chatHistory = chatHistory.filter(msg => msg.role !== "error");
            
            // Optionally clear error messages from UI after successful response
            // This helps provide a cleaner experience when the user resolves their issue
            // We keep them for now to maintain transparency, but you could uncomment below to remove them:
            /*
            const chatMessagesContainer = document.getElementById("chat-messages");
            if (chatMessagesContainer) {
                const errorMessages = chatMessagesContainer.querySelectorAll('[style*="f8d7da"], [style*="fff3cd"]');
                errorMessages.forEach(errorMsg => errorMsg.remove());
            }
            */
        }

        // Function to create valid conversation context for the API
        function createValidContext(chatHistory) {
            // First filter out error messages
            let filteredHistory = chatHistory.filter(msg => msg.role !== "error");
            
            // Ensure valid conversation flow (alternating user/assistant roles)
            let validContext = [];
            let lastRole = null;
            
            for (const message of filteredHistory) {
                // Skip consecutive messages with the same role (except the first)
                if (lastRole === message.role) {
                    // If we have consecutive user messages, skip the earlier one
                    // If we have consecutive assistant messages, skip the earlier one
                    if (validContext.length > 0) {
                        validContext.pop(); // Remove the previous message of the same role
                    }
                }
                
                validContext.push(message);
                lastRole = message.role;
            }
            
            // Ensure the conversation doesn't end with an assistant message if we're about to add a user message
            // The API expects user -> assistant -> user flow
            if (validContext.length > 0 && validContext[validContext.length - 1].role === "assistant") {
                // This is fine, we can add a user message next
            } else if (validContext.length > 0 && validContext[validContext.length - 1].role === "user") {
                // We have a trailing user message, which is fine since we're about to send another user message
                // But we should remove the trailing user message to avoid consecutive user messages
                validContext.pop();
            }
            
            return validContext;
        }

        // Add error message to chat with special styling
        function addErrorMessageToChat(errorMessage, isRateLimitError = false) {
            const chatMessagesContainer = getShadowElement("chat-messages");
            if (!chatMessagesContainer) return;
            
            // Create error message container
            const errorContainer = document.createElement("div");
            errorContainer.style.cssText = `
                margin-bottom: 12px;
                padding: 12px 16px;
                border-radius: 8px;
                max-width: 95%;
                word-wrap: break-word;
                background-color: ${isRateLimitError ? '#fff3cd' : '#f8d7da'};
                border: 1px solid ${isRateLimitError ? '#ffeaa7' : '#f5c6cb'};
                color: ${isRateLimitError ? '#856404' : '#721c24'};
                align-self: flex-start;
                font-family: 'Poppins', sans-serif;
                position: relative;
            `;
            
            // Add error icon and message
            const errorContent = document.createElement("div");
            errorContent.style.cssText = `
                display: flex;
                align-items: flex-start;
                gap: 10px;
            `;
            
            // Error icon
            const errorIcon = document.createElement("div");
            errorIcon.innerHTML = isRateLimitError ? 
                `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>` :
                `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg>`;
            errorIcon.style.cssText = `
                flex-shrink: 0;
                margin-top: 2px;
                opacity: 0.8;
            `;
            
            // Error text
            const errorText = document.createElement("div");
            errorText.style.cssText = `
                flex-grow: 1;
                font-size: 14px;
                line-height: 1.4;
            `;
            errorText.textContent = errorMessage;
            
            // Add retry suggestion for certain errors
            if (!isRateLimitError && !errorMessage.includes('log in')) {
                const retryText = document.createElement("div");
                retryText.style.cssText = `
                    margin-top: 8px;
                    font-size: 12px;
                    opacity: 0.8;
                    font-style: italic;
                `;
                retryText.textContent = "You can try sending your message again.";
                errorText.appendChild(retryText);
            }
            
            errorContent.appendChild(errorIcon);
            errorContent.appendChild(errorText);
            errorContainer.appendChild(errorContent);
            
            // Note: Don't add error messages to chatHistory to prevent them from being sent as context
            // This prevents error states from persisting across requests
            
            // Add to chat and scroll
            chatMessagesContainer.appendChild(errorContainer);
            chatMessagesContainer.scrollTop = chatMessagesContainer.scrollHeight;
        }

        // Add this new loading indicator function
        function addLoadingIndicator() {
            const loadingDiv = document.createElement("div");
            loadingDiv.id = "loading-message";
            loadingDiv.style.cssText = `
        margin-bottom: 16px;
        padding: 14px 16px;
        border-radius: 14px;
        background-color: #fff;
        align-self: flex-start;
        border: 1px solid rgba(0, 0, 0, 0.08);
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
        display: flex;
        align-items: center;
        gap: 8px;
        font-family: 'Poppins', sans-serif;
        font-size: 14px;
        color: rgba(0, 0, 0, 0.6);
        `;

            // Add typing animation dots
            const dotsContainer = document.createElement("div");
            dotsContainer.style.cssText = `
        display: flex;
        gap: 4px;
        margin-left: 4px;
        `;

            for (let i = 0; i < 3; i++) {
                const dot = document.createElement("div");
                dot.style.cssText = `
            width: 6px;
            height: 6px;
            background-color: rgba(0, 0, 0, 0.4);
            border-radius: 50%;
            animation: typingAnimation 1.4s infinite;
            animation-delay: ${i * 0.2}s;
        `;
                dotsContainer.appendChild(dot);
            }

            loadingDiv.textContent = "Thinking";
            loadingDiv.appendChild(dotsContainer);

            // No need to add keyframes - they're already in shadow DOM styles

            return loadingDiv;
        }

        // Function to toggle chat overlay visibility
        function toggleChatOverlay() {
            isOverlayVisible = !isOverlayVisible;
            const shadowHost = document.getElementById("chat-overlay-shadow-host");
            let chatOverlay = shadowHost ? shadowHost.shadowRoot.querySelector("#chat-overlay") : null;

            if (!chatOverlay) {
                chatOverlay = createChatOverlay(); // Creates shadow host and returns overlay
            }

            if (chatOverlay) {
                chatOverlay.style.display = isOverlayVisible ? "flex" : "none";
                
                // Focus on input field when showing overlay
                if (isOverlayVisible) {
                    setTimeout(() => {
                        const inputField = getShadowRoot()?.querySelector('[contenteditable]');
                        if (inputField) {
                            inputField.focus();
                            
                            // Place cursor at the end of existing text
                            const range = document.createRange();
                            const sel = window.getSelection();
                            
                            // If there's content, move cursor to the end
                            if (inputField.childNodes.length > 0) {
                                range.setStart(inputField.childNodes[inputField.childNodes.length - 1], 
                                    inputField.childNodes[inputField.childNodes.length - 1].length || 0);
                            } else {
                                range.setStart(inputField, 0);
                            }
                            
                            range.collapse(true);
                            sel.removeAllRanges();
                            sel.addRange(range);
                        }
                    }, 100);
                }
            }
        }

        // Function to clear chat history and UI (reusable)
        function clearChatHistoryAndUI(reason = 'manual') {
            try {
                const messagesContainer = getShadowElement("chat-messages");
                if (messagesContainer) {
                    // Clear the chat history array
                    chatHistory = [];
                    
                    // Clear the UI
                    messagesContainer.innerHTML = "";
                    
                    // Clear any error state
                    clearErrorState();
                    
                    // Send message to background script to reset context
                    chrome.runtime.sendMessage({
                        action: "resetContext"
                    });
                    
                    // Add a notification message based on the reason
                    let notificationMessage = "Chat history cleared.";
                    if (reason === 'providerChange') {
                        notificationMessage = "Chat history cleared - switched to new AI provider.";
                    }
                    
                    addNotificationMessage(notificationMessage);
                    console.log(`Chat history cleared (${reason})`);
                }
            } catch (error) {
                console.error('Error clearing chat history:', error);
            }
        }

        // Function to detect and block clashing chat elements
        function blockClashingChatElements() {
            // List of class patterns to block (updated class names)
            const blockedClassPatterns = [
                'cc-1m2mf',     // Old class
                'cc-1qbp0',     // New duplicate chatbot icon
                'cc-1o31k',     // New duplicate chatbot icon child
                'cc-otlyh',     // New duplicate chatbot icon child
                'cc-11f3x',     // New duplicate chatbot icon child
                'cc-1v4wj'      // New duplicate chatbot icon child
            ];
            
            // Function to hide elements matching any of the blocked patterns
            function hideBlockedElements() {
                blockedClassPatterns.forEach(className => {
                    // Match elements with the exact class or classes containing this pattern
                    const selector = `[class*="${className}"]`;
                    const elements = document.querySelectorAll(selector);
                    elements.forEach(element => {
                        // Only hide if it's not part of our chat overlay
                        if (!element.closest('#chat-overlay')) {
                            element.style.display = 'none';
                        }
                    });
                });
            }
            
            // Add observer to continuously check for and block the element
            const observer = new MutationObserver((mutations) => {
                hideBlockedElements();
            });
            
            // Start observing document body for changes
            observer.observe(document.body, {
                childList: true,
                subtree: true
            });
            
            // Also try to block any existing elements immediately
            hideBlockedElements();
            
            // Add CSS to ensure elements with these classes are always hidden
            const styleElement = document.createElement('style');
            const cssRules = blockedClassPatterns.map(className => `
                [class*="${className}"]:not(#chat-overlay):not(#chat-overlay *) {
                    display: none !important;
                    visibility: hidden !important;
                    opacity: 0 !important;
                    pointer-events: none !important;
                }
            `).join('\n');
            
            styleElement.textContent = cssRules;
            document.head.appendChild(styleElement);
        }

        // Set up document-level event handlers
        document.addEventListener("mousemove", (e) => {
            const shadowHost = document.getElementById("chat-overlay-shadow-host");
            if (!shadowHost) return;
            const overlay = shadowHost.shadowRoot?.querySelector("#chat-overlay");
            if (!overlay) return;
            
            if (isDragging) {
                const newLeft = e.clientX - dragOffsetX;
                const newTop = e.clientY - dragOffsetY;

                // Prevent dragging outside viewport
                const maxX = window.innerWidth - overlay.offsetWidth;
                const maxY = window.innerHeight - overlay.offsetHeight;

                overlay.style.left = Math.min(Math.max(0, newLeft), maxX) + "px";
                overlay.style.top = Math.min(Math.max(0, newTop), maxY) + "px";
                overlay.style.bottom = "auto";
                overlay.style.right = "auto";
            }

            if (isResizing) {
                const resizeHandle = overlay.querySelector("div[style*='nw-resize']");
                if (!resizeHandle) return;
                
                const MIN_WIDTH = 250;
                const MIN_HEIGHT = 200;
                const MAX_WIDTH = window.innerWidth - 40;
                const MAX_HEIGHT = window.innerHeight - 40;
                
                const dx = resizeStartX - e.clientX;
                const dy = resizeStartY - e.clientY;

                const newWidth = Math.min(Math.max(MIN_WIDTH, initialWidth + dx), MAX_WIDTH);
                const newHeight = Math.min(Math.max(MIN_HEIGHT, initialHeight + dy), MAX_HEIGHT);

                const rect = overlay.getBoundingClientRect();
                const newLeft = rect.right - newWidth;
                const newTop = rect.bottom - newHeight;

                // Ensure the overlay stays within viewport bounds
                if (newLeft >= 0 && newTop >= 0) {
                    overlay.style.width = newWidth + "px";
                    overlay.style.height = newHeight + "px";
                    overlay.style.left = newLeft + "px";
                    overlay.style.top = newTop + "px";
                }
            }
        });

        // Handle mouse up for drag and resize
        document.addEventListener("mouseup", () => {
            isDragging = false;
            isResizing = false;
        });

        // Add global keyboard event listeners
        document.addEventListener("keydown", (e) => {
            // Use Alt (Option) on all platforms including Mac
            const modifierKey = e.altKey;

            // Toggle chat with Alt/Option + C
            // Use e.code to be layout-independent (Option modifies e.key on macOS)
            if (modifierKey && e.code === "KeyC") {
                e.preventDefault(); // Prevent default browser behavior
                toggleChatOverlay();
            }

            // Close chat with Escape
            if (e.key === "Escape" && isOverlayVisible) {
                isOverlayVisible = false;
                const overlay = getShadowElement("chat-overlay");
                if (overlay) {
                    overlay.style.display = "none";
                }
            }


        });

        // Initialize everything
        async function init() {
            try {
                // Try to load showdown and our inline prism highlighter
                await Promise.all([loadShowdown(), loadPrism()]);
                console.log("Showdown and SimplePrism libraries loaded successfully");
            } catch (error) {
                console.error('Failed to load libraries:', error);
                // Continue even if libraries fail to load
            }
            
            // Block clashing chat elements
            blockClashingChatElements();
            
            // Create the chat button
            const chatButton = createChatButton();

            // Get current stealth mode state
            chrome.storage.local.get(['stealth'], function(result) {
                const stealthModeEnabled = result.stealth === true;
                
                // Hide chat button if stealth mode is enabled
                if (stealthModeEnabled && chatButton) {
                    chatButton.style.opacity = "0"; // Use opacity instead of display none
                    chatButton.style.pointerEvents = "auto"; // Keep pointer events active
                }
                
                // Create the chat overlay initially but keep it hidden
                // This ensures Alt+C (Option+C on Mac) will work right from the start
                try {
                    const overlay = createChatOverlay();
                    
                    // Set overlay opacity based on stealth mode
                    if (stealthModeEnabled && overlay) {
                        overlay.style.opacity = "0.15";
                    }
                } catch (error) {
                    console.error('Error creating chat overlay:', error);
                }
            });
        }
        
        // Start the initialization
        init();

        // Add global storage change listener for stealth mode updates across tabs
        chrome.storage.onChanged.addListener((changes, namespace) => {
            if (namespace === 'local') {
                // Clear error state when database or authentication changes occur
                if (changes.accessToken || changes.refreshToken) {
                    clearErrorState();
                    console.log("Auth state changed, cleared chat error state");
                }
                
                if (changes.stealth) {
                    const newStealthMode = changes.stealth.newValue === true;
                
                    // Update chat button visibility globally
                    const chatButton = getChatButton();
                    if (chatButton) {
                        chatButton.style.opacity = newStealthMode ? "0" : "1";
                        chatButton.style.pointerEvents = "auto"; // Keep pointer events active in both states
                        
                        // Icon is set via backgroundImage on child span, no innerHTML reset needed
                    }
                    
                    // Update overlay opacity if it exists
                    const overlay = document.getElementById("chat-overlay");
                    if (overlay) {
                        overlay.style.opacity = newStealthMode ? "0.15" : "1";
                    }
                }
            }
        });

        // Listen for messages from Chrome runtime
        chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
            if (message.action === "updateChatHistory") {
                const {
                    role,
                    content,
                    isStreaming
                } = message;
                
                // First remove loading indicator if it exists
                const loadingMessage = getShadowElement("loading-message");
                if (loadingMessage) {
                    loadingMessage.remove();
                }
                
                // Handle error responses from the background script
                if (role === "error" || content.includes("error") || content.includes("failed")) {
                    // Determine if this is a rate limit error
                    const isRateLimitError = content.includes("limit") || content.includes("exceeded") || content.includes("tomorrow");
                    addErrorMessageToChat(content, isRateLimitError);
                } else if (role === "assistant") {
                    // Clear any existing error state on successful response
                    clearErrorState();
                    
                    if (isStreaming) {
                        if (!currentStreamingDiv) {
                            // Create a new assistant message container for streaming
                            currentStreamingDiv = addMessageToChat("", "assistant");
                        }
                        // Update the content incrementally
                        renderChatContent(currentStreamingDiv, content);
                        
                        // Scroll to bottom during streaming
                        const chatMessagesContainer = getShadowElement("chat-messages");
                        if (chatMessagesContainer) {
                            chatMessagesContainer.scrollTop = chatMessagesContainer.scrollHeight;
                        }
                    } else {
                        // Stream finished or single response
                        if (currentStreamingDiv) {
                            // Final update for existing stream
                            renderChatContent(currentStreamingDiv, content);
                            currentStreamingDiv = null;
                        } else {
                            // Non-streaming assistant response
                            addMessageToChat(content, "assistant");
                        }
                        
                        // Add to local chat history for conversation context
                        chatHistory.push({
                            role: "assistant",
                            content: content
                        });
                    }
                } else {
                    // Handle other roles (like 'user' echo from server, though usually local)
                    addMessageToChat(content, role);
                }
            }
            
            // Handle clear chat history action
            if (message.action === "clearChatHistory") {
                const reason = message.reason || 'external';
                clearChatHistoryAndUI(reason);
                if (sendResponse) {
                    sendResponse({ success: true });
                }
            }
            
            // Handle direct error messages from background script
            if (message.action === "chatError") {
                // Remove loading indicator if it exists
                const loadingMessage = getShadowElement("loading-message");
                if (loadingMessage) {
                    loadingMessage.remove();
                }
                
                const { error, errorType, detailedInfo } = message;
                let errorMessage = error || "An error occurred processing your message.";
                let isRateLimitError = false;
                
                // Enhance error message based on type
                if (errorType === 'rateLimit') {
                    isRateLimitError = true;
                    if (!errorMessage.includes("tomorrow") && !errorMessage.includes("wait")) {
                        errorMessage += " Please try again later.";
                    }
                } else if (errorType === 'auth') {
                    errorMessage = "Please log in to use the chat feature. Click the extension icon to log in.";
                } else if (errorType === 'network') {
                    errorMessage += " Please check your internet connection and try again.";
                } else if (errorType === 'server') {
                    errorMessage += " The service is temporarily unavailable.";
                }
                
                addErrorMessageToChat(errorMessage, isRateLimitError);
            }
        });
    });
})();
```

## /data/inject/content.js

```js path="/data/inject/content.js" 
window.addEventListener('blur', function() {
    window.focus();
});

// Declare shared isMac variable (this will be the first to run)
window.isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0 || 
               navigator.userAgent.toUpperCase().indexOf('MAC') >= 0;

// Automatically enable text selection on all websites
(function() {
    // Function to enable text selection globally
    function enableTextSelectionGlobally() {
        // Remove CSS rules that disable text selection
        const style = document.createElement('style');
        style.id = 'force-text-selection-style';
        style.innerHTML = `
            * {
                -webkit-user-select: text !important;
                -moz-user-select: text !important;
                -ms-user-select: text !important;
                user-select: text !important;
                -webkit-touch-callout: default !important;
            }
            /* Override common classes that disable text selection */
            .no-select, .noselect, .unselectable,
            .qaas-disable-text-selection,
            .qaas-disable-text-selection *,
            [data-disable-text-selection],
            [data-disable-text-selection] *,
            [unselectable="on"],
            [onselectstart],
            [ondragstart] {
                -webkit-user-select: text !important;
                -moz-user-select: text !important;
                -ms-user-select: text !important;
                user-select: text !important;
                -webkit-touch-callout: default !important;
            }
        `;
        
        // Only add if not already present
        if (!document.getElementById('force-text-selection-style')) {
            document.head.appendChild(style);
        }
        
        // Remove specific attributes and classes that disable text selection
        const disabledElements = document.querySelectorAll(`
            .no-select, .noselect, .unselectable,
            .qaas-disable-text-selection, 
            [data-disable-text-selection],
            [unselectable="on"],
            [onselectstart],
            [ondragstart]
        `);
        
        disabledElements.forEach(element => {
            // Remove classes
            element.classList.remove('no-select', 'noselect', 'unselectable', 'qaas-disable-text-selection');
            
            // Remove attributes
            element.removeAttribute('data-disable-text-selection');
            element.removeAttribute('unselectable');
            element.removeAttribute('onselectstart');
            element.removeAttribute('ondragstart');
            
            // Force styles
            element.style.userSelect = 'text';
            element.style.webkitUserSelect = 'text';
            element.style.mozUserSelect = 'text';
            element.style.msUserSelect = 'text';
            element.style.webkitTouchCallout = 'default';
        });
        
        // Override common event handlers that prevent text selection
        document.onselectstart = null;
        document.ondragstart = null;
        document.oncontextmenu = null;
        
        // Remove event listeners that might interfere with text selection
        const body = document.body;
        if (body) {
            body.onselectstart = null;
            body.ondragstart = null;
        }
    }
    
    // Apply immediately
    enableTextSelectionGlobally();
    
    // Apply when DOM is fully loaded
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', enableTextSelectionGlobally);
    }
    
    // Re-apply when new content is added (for dynamic websites)
    const observer = new MutationObserver(function(mutations) {
        let shouldReapply = false;
        mutations.forEach(function(mutation) {
            if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                // Check if any added nodes have text selection disabled
                mutation.addedNodes.forEach(function(node) {
                    if (node.nodeType === Node.ELEMENT_NODE) {
                        const hasDisabledSelection = node.matches && node.matches(`
                            .no-select, .noselect, .unselectable,
                            .qaas-disable-text-selection,
                            [data-disable-text-selection],
                            [unselectable="on"],
                            [onselectstart],
                            [ondragstart]
                        `);
                        if (hasDisabledSelection || node.querySelector) {
                            shouldReapply = true;
                        }
                    }
                });
            }
        });
        
        if (shouldReapply) {
            enableTextSelectionGlobally();
        }
    });
    
    // Start observing
    observer.observe(document.body || document.documentElement, {
        childList: true,
        subtree: true
    });
})();

// Function to convert HTML to readable text with proper formatting
function htmlToText(element) {
    if (!element) return '';
    
    // Clone the element to avoid modifying the original
    const clone = element.cloneNode(true);
    
    // Handle superscripts - convert <sup>text</sup> to ^text
    clone.querySelectorAll('sup').forEach(sup => {
        sup.textContent = '^' + sup.textContent;
    });
    
    // Handle subscripts - convert <sub>text</sub> to _text
    clone.querySelectorAll('sub').forEach(sub => {
        sub.textContent = '_' + sub.textContent;
    });
    
    // Handle line breaks
    clone.querySelectorAll('br').forEach(br => {
        br.replaceWith('\n');
    });
    
    // Get the text content
    return clone.innerText.trim();
}

// Function to extract the question, code, and options
function extractQuestionCodeAndOptions() {
    // Extracting the question text
    const questionElement = document.querySelector('div[aria-labelledby="question-data"]');
    const questionText = questionElement ? htmlToText(questionElement) : '';

    // Extracting the code
    const codeLines = [];
    const codeElements = document.querySelectorAll('.ace_layer.ace_text-layer .ace_line');

    codeElements.forEach(line => {
        codeLines.push(line.innerText.trim());
    });

    const codeText = codeLines.length > 0 ? codeLines.join('\n') : null; // Set to null if no code is found

    // Extracting options
    const optionsElements = document.querySelectorAll('div[aria-labelledby="each-option"]'); // Update this selector as necessary
    const optionsText = [];
    optionsElements.forEach((option, index) => {
        optionsText.push(`Option ${index + 1}: ${htmlToText(option)}`);
    });

    return {
        question: questionText,
        code: codeText, // This can be null if no code is present
        options: optionsText.join('\n') // Join options with new line characters
    };
}

// Async function to handle question, code, and options extraction
async function handleQuestionExtraction() {
    const { question, code, options } = extractQuestionCodeAndOptions();

    if (!question) {
        return;
    }

    console.log('Question:', question);
    console.log('Code:\n', code ? code : 'No code available');
    console.log('Options:\n', options);

    // Send the extracted data to background.js
    // The clicking will be handled by the clickMCQOption message handler
    chrome.runtime.sendMessage({
        action: 'extractData',
        question: question,
        code: code,
        options: options,
        isMCQ: true
    });
}

// Function to extract coding question details
function extractCodingQuestion(isTyped = false) {
    // Extract programming language
    const programmingLanguageElement = document.querySelector('span.inner-text');
    const programmingLanguage = programmingLanguageElement ? programmingLanguageElement.innerText.trim() : 'Programming language not found.';

    // Extract question components
    const questionElement = document.querySelector('div[aria-labelledby="question-data"]');
    const questionText = questionElement ? htmlToText(questionElement) : 'Question not found.';

    const inputFormatElement = document.querySelector('div[aria-labelledby="input-format"]');
    const inputFormatText = inputFormatElement ? htmlToText(inputFormatElement) : '';

    const outputFormatElement = document.querySelector('div[aria-labelledby="output-format"]');
    const outputFormatText = outputFormatElement ? htmlToText(outputFormatElement) : '';

    // Extract sample test cases with robust fallback method
    const testCases = [];
    
    // Try Method 1: Find test case containers with aria-labelledby="each-tc-card"
    let containers = document.querySelectorAll('div[aria-labelledby="each-tc-card"]');
    
    if (containers.length > 0) {
        console.log('[Test Cases] Method 1: Found', containers.length, 'test case containers');
        containers.forEach((container) => {
            const inputPre = container.querySelector('div[aria-labelledby="each-tc-input-container"] pre');
            const outputPre = container.querySelector('div[aria-labelledby="each-tc-output-container"] pre');
            
            if (inputPre && outputPre) {
                testCases.push({
                    input: inputPre.textContent.trim(),
                    output: outputPre.textContent.trim()
                });
            }
        });
    }
    
    // Try Method 2: Find by aria-labelledby="each-tc-container"
    if (testCases.length === 0) {
        console.log('[Test Cases] Method 1 failed. Trying Method 2...');
        containers = document.querySelectorAll('[aria-labelledby="each-tc-container"]');
        
        if (containers.length > 0) {
            console.log('[Test Cases] Method 2: Found', containers.length, 'test case containers');
            containers.forEach((container) => {
                const inputPre = container.querySelector('[aria-labelledby="each-tc-input"]');
                const outputPre = container.querySelector('[aria-labelledby="each-tc-output"]');
                
                if (inputPre && outputPre) {
                    testCases.push({
                        input: inputPre.textContent.trim(),
                        output: outputPre.textContent.trim()
                    });
                }
            });
        }
    }
    
    // Try Method 3: Find pre elements with Input/Output labels
    if (testCases.length === 0) {
        console.log('[Test Cases] Method 2 failed. Trying Method 3...');
        const allPres = document.querySelectorAll('pre');
        const inputs = [];
        const outputs = [];
        
        allPres.forEach(pre => {
            const text = pre.textContent.trim();
            const prevElement = pre.previousElementSibling;
            
            if (prevElement) {
                const labelText = prevElement.textContent.toLowerCase();
                if (labelText.includes('input') && !labelText.includes('output')) {
                    inputs.push(text);
                } else if (labelText.includes('output')) {
                    outputs.push(text);
                }
            }
        });
        
        console.log('[Test Cases] Method 3: Found', inputs.length, 'inputs and', outputs.length, 'outputs');
        
        // Pair inputs and outputs
        for (let i = 0; i < Math.min(inputs.length, outputs.length); i++) {
            testCases.push({
                input: inputs[i],
                output: outputs[i]
            });
        }
    }
    
    let testCasesText = '';
    if (testCases.length > 0) {
        testCases.forEach((testCase, index) => {
            testCasesText += `Sample Test Case ${index + 1}:\nInput:\n${testCase.input}\nOutput:\n${testCase.output}\n\n`;
        });
        console.log('[Test Cases] Successfully extracted', testCases.length, 'test cases');
    } else {
        console.warn('[Test Cases] All methods failed. No test cases extracted.');
        testCasesText = 'No test cases found. Please check the page structure.';
    }

    // Extract whitelist keywords from instruction cards
    let whitelistText = '';
    const instructionCards = document.querySelectorAll('div[aria-labelledby="instruction-card"]');
    instructionCards.forEach(card => {
        const header = card.querySelector('[aria-labelledby="instruction-header"]');
        if (header && header.textContent.trim().toLowerCase().includes('whitelist')) {
            const sets = card.querySelectorAll('[aria-labelledby="list"]');
            sets.forEach(set => {
                const setHeader = set.querySelector('[aria-labelledby="set-header"]');
                const values = set.querySelectorAll('[aria-labelledby="list-value-card"]');
                const keywords = Array.from(values).map(v => v.textContent.trim()).filter(Boolean);
                if (keywords.length > 0) {
                    const setName = setHeader ? setHeader.textContent.trim() : '';
                    whitelistText += (setName ? setName + ' ' : '') + keywords.join(', ') + '\n';
                }
            });
        }
    });
    whitelistText = whitelistText.trim();

    // Extract header and footer snippet code from readonly editors
    let headerSnippet = '';
    let footerSnippet = '';
    const headerEditorEl = document.querySelector('[aria-labelledby="editor-question"][id*="ttHeaderEditor"]');
    const footerEditorEl = document.querySelector('[aria-labelledby="editor-question"][id*="ttFooterEditor"]');
    if (headerEditorEl) {
        const headerLines = headerEditorEl.querySelectorAll('.ace_line');
        headerSnippet = Array.from(headerLines).map(line => line.textContent).join('\n').trim();
    }
    if (footerEditorEl) {
        const footerLines = footerEditorEl.querySelectorAll('.ace_line');
        footerSnippet = Array.from(footerLines).map(line => line.textContent).join('\n').trim();
    }

    // Send data to background.js for querying
    chrome.runtime.sendMessage({
        action: 'extractData',
        programmingLanguage: programmingLanguage,
        question: questionText,
        inputFormat: inputFormatText,
        outputFormat: outputFormatText,
        testCases: testCasesText,
        headerSnippet: headerSnippet,
        footerSnippet: footerSnippet,
        whitelist: whitelistText,
        isCoding: true,
        isTyped: isTyped
    }, (response) => {
        // Injection is handled directly by worker.js via chrome.scripting.executeScript.
        // This callback may receive null due to multiple onMessage listeners — that's expected.
        if (response && response.error) {
            console.error('[AI Answer] Error from background:', response.error);
        }
    });
}    

function solveIamneoExamly(){
        // Check if this is a coding question or MCQ
        const codingQuestionElement = document.querySelector('div[aria-labelledby="input-format"]');
        if (codingQuestionElement) {
            extractCodingQuestion();
        } else {
            handleQuestionExtraction();
        }
}
document.addEventListener('keydown', (event) => {
    // Use Option (Alt) key on all platforms
    const modifierKey = event.altKey;

    if (modifierKey && event.shiftKey && event.code === 'KeyA') {
        solveIamneoExamly();
    }
});

// Alt+Shift+T (Ctrl+Shift+T on Mac): Typed code insertion — only handles initial AI fetch.
// Resume/stop/continue typing is handled by exam.js locally.
let _typedFetchQuestion = null; // track which question we already fetched for
document.addEventListener('keydown', (event) => {
    const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
    const modifierKey = isMac ? event.ctrlKey : event.altKey;

    if (modifierKey && event.shiftKey && event.code === 'KeyT') {
        console.log('[Alt+Shift+T] Key detected in content.js');

        // Only fetch if this is a coding question
        const codingQuestionElement = document.querySelector('div[aria-labelledby="input-format"]');
        console.log('[Alt+Shift+T] codingQuestionElement found:', !!codingQuestionElement);
        if (!codingQuestionElement) return;

        // Get current question number to avoid re-fetching
        const qEl = document.querySelector('div[class*="t-bg-primary"]');
        const qMatch = qEl && qEl.textContent.match(/Question No : (\d+)/);
        const qNum = qMatch ? qMatch[1] : null;
        console.log('[Alt+Shift+T] question number:', qNum, 'already fetched for:', _typedFetchQuestion);

        if (qNum && _typedFetchQuestion === qNum) {
            console.log('[Alt+Shift+T] Already fetched for this question, skipping');
            return;
        }
        _typedFetchQuestion = qNum;

        console.log('[Alt+Shift+T] Calling extractCodingQuestion(true)');
        extractCodingQuestion(true); // isTyped = true
    }
});

// Add event listener for Option+O to toggle toast opacity
document.addEventListener('keydown', (event) => {
    // Use Option (Alt) key on all platforms
    const modifierKey = event.altKey;
    
    if (modifierKey && event.code === 'KeyO') {
        chrome.runtime.sendMessage({
            action: 'toggleToastOpacity'
        });
    }
});

// Function to extract code from snippets
function extractSnippets() {
    const headerContainer = Array.from(document.querySelectorAll('div[aria-labelledby="tt-header"]'))
        .find(container => container.innerText.includes('Header Snippet'));
    const footerContainer = Array.from(document.querySelectorAll('div[aria-labelledby="footer"]'))
        .find(container => container.innerText.includes('Footer Snippet'));

    const extractCode = container => {
        if (!container) return '';
        const codeLines = container.querySelectorAll('.ace_line');
        return Array.from(codeLines).map(line => line.textContent).join('\n');
    };

    const snippets = {
        header: extractCode(headerContainer),
        footer: extractCode(footerContainer)
    };

    // Send snippets directly to background.js
    chrome.runtime.sendMessage({
        action: 'processSnippets',
        snippets: snippets
    });
}

// Remove old listener and add new one
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
    if (message.action === 'extractSnippets') {
        extractSnippets();
    }
    if (message.action === 'solveIamneoExamly') {
        solveIamneoExamly();
    }
});

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
    if (message.action === "updateChatHistory") {
        const { role, content } = message;
        
        // Remove loading indicator if it exists
        const loadingMessage = document.getElementById("loading-message");
        if (loadingMessage) {
            loadingMessage.remove();
        }
        
        // Add the actual message
        chatHistory.push({
            role: role,
            content: content
        });
        addMessageToChat(content, role);
    }
});

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.action === 'clickMCQOption') {
        (async () => {
            try {
                // Check if this is HackerRank
                if (request.isHackerRank) {
                    let clicked = false;
                    
                    // Handle multiple choice questions (checkboxes) differently
                    if (request.isMultipleChoice) {
                    console.log('Multiple choice question detected, response:', request.response);
                    
                    // Enhanced parsing for multiple options
                    // Look for patterns like: "1. text, 3. text" or "A. text, C. text" or "1, 3" or "A, C"
                    const optionNumbers = [];
                    
                    // Pattern 1: "1. text, 3. text" or "A. text, C. text"
                    let matches = request.response.match(/([A-Z]|\d+)\.\s*[^,]+/gi);
                    if (matches) {
                        matches.forEach(match => {
                            const num = match.match(/^([A-Z]|\d+)\./);
                            if (num) {
                                let optionIndex;
                                if (isNaN(num[1])) {
                                    // Convert A,B,C to 0,1,2
                                    optionIndex = num[1].charCodeAt(0) - 'A'.charCodeAt(0);
                                } else {
                                    // Convert 1,2,3 to 0,1,2
                                    optionIndex = parseInt(num[1]) - 1;
                                }
                                if (optionIndex >= 0) {
                                    optionNumbers.push(optionIndex);
                                }
                            }
                        });
                    }
                    
                    // Pattern 2: Simple comma-separated numbers or letters: "1, 3, 5" or "A, C, E"
                    if (optionNumbers.length === 0) {
                        const simpleMatches = request.response.match(/(?:^|[,\s])([A-Z]|\d+)(?=[,\s]|$)/gi);
                        if (simpleMatches) {
                            simpleMatches.forEach(match => {
                                const cleaned = match.trim().replace(/^[,\s]+|[,\s]+$/g, '');
                                let optionIndex;
                                if (isNaN(cleaned)) {
                                    // Convert A,B,C to 0,1,2
                                    optionIndex = cleaned.charCodeAt(0) - 'A'.charCodeAt(0);
                                } else {
                                    // Convert 1,2,3 to 0,1,2
                                    optionIndex = parseInt(cleaned) - 1;
                                }
                                if (optionIndex >= 0) {
                                    optionNumbers.push(optionIndex);
                                }
                            });
                        }
                    }
                    
                    // Remove duplicates
                    const uniqueOptionNumbers = [...new Set(optionNumbers)];
                    
                    console.log('Parsed multiple choice options:', uniqueOptionNumbers.map(n => n + 1));
                    
                    // Click all the selected options for multiple choice
                    const checkboxes = document.querySelectorAll('[role="checkbox"]');
                    if (checkboxes.length > 0) {
                        console.log(`Found ${checkboxes.length} checkboxes, will click options:`, uniqueOptionNumbers.map(n => n + 1));
                        
                        // Click options with delay to ensure UI state is properly updated
                        for (let i = 0; i < uniqueOptionNumbers.length; i++) {
                            const optionNumber = uniqueOptionNumbers[i];
                            
                            if (optionNumber >= 0 && optionNumber < checkboxes.length) {
                                const checkbox = checkboxes[optionNumber];
                                
                                // Wait a bit before checking and clicking each option
                                await new Promise(resolve => setTimeout(resolve, 300));
                                
                                // Re-check the current state after delay
                                const isCurrentlyChecked = checkbox.getAttribute('aria-checked') === 'true' || 
                                                         checkbox.getAttribute('data-state') === 'checked' ||
                                                         checkbox.checked === true;
                                
                                console.log(`Option ${optionNumber + 1} current state: ${isCurrentlyChecked ? 'checked' : 'unchecked'}`);
                                
                                // Only click if not already checked
                                if (!isCurrentlyChecked) {
                                    console.log(`Clicking checkbox option ${optionNumber + 1}...`);
                                    
                                    // Try multiple click methods to ensure it works
                                    checkbox.click();
                                    
                                    // Alternative click method - dispatch events directly
                                    checkbox.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
                                    checkbox.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
                                    checkbox.dispatchEvent(new MouseEvent('click', { bubbles: true }));
                                    
                                    // Wait a bit more to let the UI update
                                    await new Promise(resolve => setTimeout(resolve, 200));
                                    
                                    // Verify the click worked
                                    const newState = checkbox.getAttribute('aria-checked') === 'true' || 
                                                   checkbox.getAttribute('data-state') === 'checked' ||
                                                   checkbox.checked === true;
                                    
                                    if (newState) {
                                        console.log(`✅ HackerRank checkbox option ${optionNumber + 1} clicked successfully`);
                                        clicked = true;
                                    } else {
                                        console.log(`⚠️ HackerRank checkbox option ${optionNumber + 1} click may have failed - retrying...`);
                                        
                                        // Retry once more
                                        checkbox.click();
                                        await new Promise(resolve => setTimeout(resolve, 100));
                                        
                                        const retryState = checkbox.getAttribute('aria-checked') === 'true' || 
                                                         checkbox.getAttribute('data-state') === 'checked' ||
                                                         checkbox.checked === true;
                                        
                                        if (retryState) {
                                            console.log(`✅ HackerRank checkbox option ${optionNumber + 1} clicked successfully on retry`);
                                            clicked = true;
                                        } else {
                                            console.log(`❌ HackerRank checkbox option ${optionNumber + 1} failed to click`);
                                        }
                                    }
                                } else {
                                    console.log(`✅ HackerRank checkbox option ${optionNumber + 1} already selected`);
                                    clicked = true; // Still count as successful
                                }
                            }
                        }
                        
                        // If no options were found, fall back to single option logic
                        if (uniqueOptionNumbers.length === 0) {
                            console.log('No multiple options found, falling back to single option logic');
                            const optionMatch = request.response.match(/(?:options?\s*)?([A-Z]|\d+)\.?/i);
                            if (optionMatch) {
                                let optionNumber;
                                if (isNaN(optionMatch[1])) {
                                    optionNumber = optionMatch[1].charCodeAt(0) - 'A'.charCodeAt(0);
                                } else {
                                    optionNumber = parseInt(optionMatch[1]) - 1;
                                }
                                
                                if (optionNumber >= 0 && optionNumber < checkboxes.length) {
                                    await new Promise(resolve => setTimeout(resolve, 200));
                                    
                                    const checkbox = checkboxes[optionNumber];
                                    const isCurrentlyChecked = checkbox.getAttribute('aria-checked') === 'true' || 
                                                             checkbox.getAttribute('data-state') === 'checked' ||
                                                             checkbox.checked === true;
                                    
                                    if (!isCurrentlyChecked) {
                                        checkbox.click();
                                        console.log(`HackerRank single checkbox option ${optionNumber + 1} clicked as fallback`);
                                        clicked = true;
                                    } else {
                                        console.log(`HackerRank single checkbox option ${optionNumber + 1} already selected`);
                                        clicked = true;
                                    }
                                }
                            }
                        }
                    }
                } else {
                    // Single choice question - use enhanced logic
                    const optionMatch = request.response.match(/(?:options?\s*)?([A-Z]|\d+)\.?/i);
                    if (optionMatch) {
                        let optionNumber;
                        if (isNaN(optionMatch[1])) {
                            // Handle letter options (A, B, C, etc.)
                            optionNumber = optionMatch[1].toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0);
                        } else {
                            // Handle number options (1, 2, 3, etc.)
                            optionNumber = parseInt(optionMatch[1]) - 1;
                        }
                        
                        console.log(`Single choice detected, clicking option: ${optionNumber + 1}`);
                        
                        // Add a small delay before clicking
                        await new Promise(resolve => setTimeout(resolve, 200));
                        
                        // Try new layout first - check for radio buttons
                        const newLayoutRadios = document.querySelectorAll('[role="radio"]');
                        if (newLayoutRadios.length > optionNumber && optionNumber >= 0) {
                            const radio = newLayoutRadios[optionNumber];
                            
                            // Check if already selected
                            const isCurrentlySelected = radio.getAttribute('aria-checked') === 'true' || 
                                                      radio.getAttribute('data-state') === 'checked' ||
                                                      radio.checked === true;
                            
                            if (!isCurrentlySelected) {
                                radio.click();
                                console.log(`HackerRank new layout radio option ${optionNumber + 1} clicked successfully`);
                                clicked = true;
                            } else {
                                console.log(`HackerRank new layout radio option ${optionNumber + 1} already selected`);
                                clicked = true;
                            }
                        } else {
                            // Try checkboxes if no radio buttons found (fallback for single checkbox)
                            const newLayoutCheckboxes = document.querySelectorAll('[role="checkbox"]');
                            if (newLayoutCheckboxes.length > optionNumber && optionNumber >= 0) {
                                const checkbox = newLayoutCheckboxes[optionNumber];
                                
                                const isCurrentlyChecked = checkbox.getAttribute('aria-checked') === 'true' || 
                                                         checkbox.getAttribute('data-state') === 'checked' ||
                                                         checkbox.checked === true;
                                
                                if (!isCurrentlyChecked) {
                                    checkbox.click();
                                    console.log(`HackerRank new layout checkbox option ${optionNumber + 1} clicked successfully`);
                                    clicked = true;
                                } else {
                                    console.log(`HackerRank new layout checkbox option ${optionNumber + 1} already selected`);
                                    clicked = true;
                                }
                            } else {
                                // Fallback to old layout (radio buttons)
                                const questionContainer = document.querySelector('.grouped-mcq__question');
                                if (questionContainer) {
                                    const radios = questionContainer.querySelectorAll('input[type="radio"]');
                                    if (radios.length > optionNumber && optionNumber >= 0) {
                                        const radio = radios[optionNumber];
                                        
                                        if (!radio.checked) {
                                            radio.click();
                                            console.log(`HackerRank old layout option ${optionNumber + 1} clicked successfully`);
                                            clicked = true;
                                        } else {
                                            console.log(`HackerRank old layout option ${optionNumber + 1} already selected`);
                                            clicked = true;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                
                if (!clicked) {
                    chrome.runtime.sendMessage({
                        action: 'showMCQToast',
                        message: request.response,
                    });
                }
            } else {
                // Original logic for other platforms (Examly)
                const optionMatch = request.response.match(/(?:options?\s*)?(\d+)\.?/i);
                if (optionMatch) {
                    const optionNumber = parseInt(optionMatch[1])-1;
                    // Use exact same selector as Alt+Shift+Q
                    const answerElement = document.querySelector(`#tt-option-${optionNumber} > label > span.checkmark1`);
                    
                    if (answerElement) {
                        answerElement.dispatchEvent(new Event("click", { bubbles: true }));
                        console.log(`Option element ${optionNumber + 1} clicked successfully`);
                    } else {
                        chrome.runtime.sendMessage({
                            action: 'showMCQToast',
                            message: request.response,
                        });
                    }
                } else {
                    chrome.runtime.sendMessage({
                        action: 'showMCQToast',
                        message: request.response,
                    });
                }
            }
        } catch (error) {
            chrome.runtime.sendMessage({
                action: 'showMCQToast',
                message: request.response,
            });
        }
        })();
    }
});

// Function to extract HackerRank MCQ data (updated for new layout)
function extractHackerRankMCQ() {
    const questions = [];
    
    // Try new layout first (2024+ layout)
    const newLayoutQuestions = document.querySelectorAll('.QuestionDetails_container__AIu0X');
    
    if (newLayoutQuestions.length > 0) {
        // New layout processing
        newLayoutQuestions.forEach((container, index) => {
            const questionData = {
                questionNumber: index + 1,
                title: '',
                instruction: '',
                options: [],
                selectedAnswer: null
            };
            
            // Extract question title from new layout
            const titleElement = container.querySelector('.qaas-block-question-title, h2');
            if (titleElement) {
                // Remove bookmark icon and get clean title
                const titleText = titleElement.textContent || titleElement.innerText;
                questionData.title = titleText.replace(/Bookmark question \d+/g, '').trim();
            }
            
            // Extract question instruction/content from new layout
            const instructionElement = container.querySelector('.qaas-block-question-instruction, .RichTextPreview_richText__1vKu5');
            if (instructionElement) {
                let instructionText = instructionElement.textContent || instructionElement.innerText;
                instructionText = instructionText.replace(/\s+/g, ' ').trim();
                questionData.instruction = instructionText;
            }
            
            // Look for options in multiple possible containers
            let optionsContainer = container.nextElementSibling;
            let attempts = 0;
            while (optionsContainer && attempts < 5) {
                // Check for both radio buttons and checkboxes
                const hasOptions = optionsContainer.querySelector('[role="checkbox"], [role="radio"], .ui-radio');
                if (hasOptions) {
                    break;
                }
                optionsContainer = optionsContainer.nextElementSibling;
                attempts++;
            }
            
            // Also check for options within the same container or nearby
            if (!optionsContainer || !optionsContainer.querySelector('[role="checkbox"], [role="radio"]')) {
                optionsContainer = container.parentElement?.querySelector('.Control_container__F35yA') ||
                                document.querySelector('.Control_container__F35yA');
            }
            
            if (optionsContainer) {
                // Try radio buttons first (new layout)
                let optionElements = optionsContainer.querySelectorAll('[role="radio"]');
                
                // If no radio buttons, try checkboxes
                if (optionElements.length === 0) {
                    optionElements = optionsContainer.querySelectorAll('[role="checkbox"]');
                }
                
                optionElements.forEach((option, optionIndex) => {
                    const labelId = option.getAttribute('aria-labelledby');
                    const labelElement = labelId ? document.getElementById(labelId) : 
                                      option.closest('.Control_optionList__vIubt, li')?.querySelector('label');
                    
                    if (labelElement) {
                        const optionText = labelElement.textContent.trim();
                        const isChecked = option.getAttribute('aria-checked') === 'true' || 
                                        option.getAttribute('data-state') === 'checked';
                        
                        questionData.options.push({
                            value: option.value || optionIndex.toString(),
                            text: optionText,
                            isSelected: isChecked
                        });
                        
                        if (isChecked) {
                            questionData.selectedAnswer = option.value || optionIndex.toString();
                        }
                    }
                });
            }
            
            // Only add question if it has options (to distinguish from coding questions)
            if (questionData.options.length > 0) {
                questions.push(questionData);
            }
        });
    } else {
        // Fallback to old layout
        const oldLayoutQuestions = document.querySelectorAll('.grouped-mcq__question');
        
        oldLayoutQuestions.forEach((container, index) => {
            const questionData = {
                questionNumber: index + 1,
                title: '',
                instruction: '',
                options: [],
                selectedAnswer: null
            };
            
            // Extract question title from old layout
            const titleElement = container.querySelector('.question-view__title');
            if (titleElement) {
                questionData.title = titleElement.textContent.trim();
            }
            
            // Extract question instruction/content from old layout
            const instructionElement = container.querySelector('.question-view__instruction');
            if (instructionElement) {
                let instructionText = instructionElement.textContent.trim();
                instructionText = instructionText.replace(/\s+/g, ' ').trim();
                questionData.instruction = instructionText;
            }
            
            // Extract options from old layout
            const optionElements = container.querySelectorAll('.ui-radio');
            optionElements.forEach((option, optionIndex) => {
                const labelElement = option.querySelector('.label');
                const inputElement = option.querySelector('input[type="radio"]');
                
                if (labelElement && inputElement) {
                    const optionText = labelElement.textContent.trim();
                    const optionValue = inputElement.value;
                    const isChecked = inputElement.checked;
                    
                    questionData.options.push({
                        value: optionValue,
                        text: optionText,
                        isSelected: isChecked
                    });
                    
                    if (isChecked) {
                        questionData.selectedAnswer = optionValue;
                    }
                }
            });
            
            questions.push(questionData);
        });
    }
    
    return questions;
}

// Function to extract HackerRank coding question (updated for new layout)
function extractHackerRankCoding() {
    const getCleanText = el => el?.innerText?.trim() || "";

    // Try new layout first (2024+ layout)
    let language = "Unknown";
    let title = "No Title Found";
    let instruction = "No Instructions Found";
    let details = "";
    let starterCode = "";

    // Check for new layout language selector
    const newLanguageSelector = document.querySelector('.select-language .css-3d4y2u-singleValue, .select-language .css-x7738g');
    if (newLanguageSelector) {
        language = getCleanText(newLanguageSelector);
    } else {
        // Fallback to old layout
        language = getCleanText(document.querySelector('.select-language .css-x7738g')) || "Unknown";
    }

    // Try new layout question container
    let container = document.querySelector('.QuestionDetails_container__AIu0X');
    if (container) {
        // New layout
        const titleElement = container.querySelector('.qaas-block-question-title, h2');
        if (titleElement) {
            const titleText = titleElement.textContent || titleElement.innerText;
            title = titleText.replace(/Bookmark question \d+/g, '').trim();
        }
        
        const instructionElement = container.querySelector('.qaas-block-question-instruction, .RichTextPreview_richText__1vKu5');
        if (instructionElement) {
            instruction = getCleanText(instructionElement);
        }
        
        // Look for details sections in new layout
        const detailsElements = container.querySelectorAll('details');
        if (detailsElements.length > 0) {
            details = Array.from(detailsElements).map(detail => {
                const summary = getCleanText(detail.querySelector('summary'));
                const content = getCleanText(detail.querySelector('.collapsable-details'));
                return `\n${summary}\n${'-'.repeat(summary.length)}\n${content}`;
            }).join('\n');
        }
    } else {
        // Fallback to old layout
        container = document.querySelector('#main-splitpane-left');
        if (container) {
            title = getCleanText(container.querySelector('.question-view__title')) || "No Title Found";
            instruction = getCleanText(container.querySelector('.question-view__instruction')) || "No Instructions Found";
            
            details = Array.from(container.querySelectorAll('details') || []).map(detail => {
                const summary = getCleanText(detail.querySelector('summary'));
                const content = getCleanText(detail.querySelector('.collapsable-details'));
                return `\n${summary}\n${'-'.repeat(summary.length)}\n${content}`;
            }).join('\n');
        }
    }

    // Get starter code from Monaco editor (works for both layouts)
    const codeLines = Array.from(document.querySelectorAll('.view-lines .view-line')).map(line =>
        line.innerText
    ).join('\n').trim();
    
    starterCode = codeLines;

    return {
        language,
        title,
        instruction,
        details,
        starterCode: starterCode
    };
}

// Function to normalize code indentation
function normalizeCodeIndentation(code) {
    if (!code) return code;
    
    const lines = code.split('\n');
    
    // Remove empty lines at the beginning and end
    while (lines.length > 0 && lines[0].trim() === '') {
        lines.shift();
    }
    while (lines.length > 0 && lines[lines.length - 1].trim() === '') {
        lines.pop();
    }
    
    if (lines.length === 0) return '';
    
    // Find the minimum indentation (excluding empty lines)
    let minIndent = Infinity;
    for (const line of lines) {
        if (line.trim() !== '') {
            const indent = line.match(/^\s*/)[0].length;
            minIndent = Math.min(minIndent, indent);
        }
    }
    
    // Remove the common indentation from all lines
    if (minIndent > 0 && minIndent !== Infinity) {
        for (let i = 0; i < lines.length; i++) {
            if (lines[i].trim() !== '') {
                lines[i] = lines[i].substring(minIndent);
            }
        }
    }
    
    return lines.join('\n');
}

// Function to insert code into Monaco editor with proper formatting
async function insertCodeIntoMonacoEditor(text) {
    console.log('insertCodeIntoMonacoEditor called with text length:', text.length);
    
    // Normalize the code indentation first
    const normalizedText = normalizeCodeIndentation(text);
    console.log('Text after normalization:', normalizedText);
    
    // 1. Try to find Monaco editor instance through the global scope
    if (typeof monaco !== 'undefined' && window.monaco) {
        try {
            const editor = window.monaco.editor.getEditors()[0];
            if (editor) {
                console.log('Found Monaco editor instance, setting value directly...');
                editor.setValue(normalizedText);
                editor.focus();
                return true;
            }
        } catch (error) {
            console.log('Monaco API method failed, trying alternative approaches...');
        }
    }
    
    // 2. Try to access Monaco editor through DOM manipulation
    const monacoEditor = document.querySelector('.monaco-editor');
    console.log('Monaco editor DOM element found:', !!monacoEditor);
    
    if (!monacoEditor) {
        console.error("❌ Monaco editor not found.");
        return false;
    }

    try {
        // 3. Focus the editor properly
        const editorTextArea = monacoEditor.querySelector('textarea.inputarea') || 
                              monacoEditor.querySelector('textarea') ||
                              monacoEditor.querySelector('.monaco-editor-background');
        
        if (editorTextArea) {
            console.log('Found Monaco textarea, focusing...');
            editorTextArea.focus();
            editorTextArea.click();
        } else {
            console.log('Monaco textarea not found, clicking editor container...');
            monacoEditor.focus();
            monacoEditor.click();
        }
        
        // 4. Wait a bit for focus to settle
        await new Promise(resolve => setTimeout(resolve, 200));
        
        // 5. Clear existing content using keyboard shortcuts
        console.log('Clearing existing content...');
        
        // Use Select All (Cmd+A on macOS, Ctrl+A elsewhere)
        document.dispatchEvent(new KeyboardEvent('keydown', {
            key: 'a',
            code: 'KeyA',
            ctrlKey: !window.isMac,
            metaKey: window.isMac,
            bubbles: true
        }));
        
        await new Promise(resolve => setTimeout(resolve, 100));
        
        // Use Delete or Backspace to clear
        document.dispatchEvent(new KeyboardEvent('keydown', {
            key: 'Delete',
            code: 'Delete',
            bubbles: true
        }));
        
        await new Promise(resolve => setTimeout(resolve, 100));
        
        // 6. Copy normalized text to clipboard
        await navigator.clipboard.writeText(normalizedText);
        console.log('Text copied to clipboard');
        
        // 7. Paste (Cmd+V on macOS, Ctrl+V elsewhere)
        console.log('Pasting content...');
        document.dispatchEvent(new KeyboardEvent('keydown', {
            key: 'v',
            code: 'KeyV',
            ctrlKey: !window.isMac,
            metaKey: window.isMac,
            bubbles: true
        }));
        
        await new Promise(resolve => setTimeout(resolve, 300));
        
        // 8. Try input event as fallback
        if (editorTextArea) {
            console.log('Trying input event fallback...');
            
            // Set the value directly on the textarea
            editorTextArea.value = normalizedText;
            
            // Trigger input events
            editorTextArea.dispatchEvent(new Event('input', { bubbles: true }));
            editorTextArea.dispatchEvent(new Event('change', { bubbles: true }));
            
            // Try to trigger Monaco's internal update
            editorTextArea.dispatchEvent(new KeyboardEvent('keydown', {
                key: 'End',
                code: 'End',
                bubbles: true
            }));
        }
        
        console.log('✅ Successfully inserted code into Monaco editor');
        return true;
        
    } catch (error) {
        console.error("❌ Error inserting code into Monaco editor:", error);
        
        // Final fallback: copy to clipboard
        try {
            await navigator.clipboard.writeText(normalizedText);
            console.log('Fallback: copied normalized text to clipboard');
        } catch (clipboardError) {
            console.error('Clipboard fallback also failed:', clipboardError);
        }
        
        return false;
    }
}

// Function to handle HackerRank extraction (both MCQ and coding, updated for new layout)
function handleHackerRankMCQ() {
    // Check if it's a coding question first (Monaco editor present)
    const monacoEditor = document.querySelector('.monaco-editor, .hr-monaco-editor');
    
    // Check for MCQ options specifically (more precise detection)
    const hasRadioOptions = document.querySelector('[role="radio"], [role="radiogroup"]');
    const hasCheckboxOptions = document.querySelector('[role="checkbox"]');
    const hasOldMcqOptions = document.querySelector('.grouped-mcq__question .ui-radio');
    const hasOptionsControl = document.querySelector('.Control_container__F35yA');
    
    // More precise MCQ detection
    const isMCQ = hasRadioOptions || hasCheckboxOptions || hasOldMcqOptions || 
                  (hasOptionsControl && !monacoEditor);
    
    if (monacoEditor && !isMCQ) {
        // This is definitely a coding question
        const codingData = extractHackerRankCoding();
        
        if (!codingData.instruction || codingData.instruction === "No Instructions Found") {
            chrome.runtime.sendMessage({
                action: 'showToast',
                message: 'No HackerRank coding question found.',
                isError: true
            });
            return;
        }

        // Format the question for AI
        const questionText = `
Language: ${codingData.language}

Title: ${codingData.title}

Instructions:
${codingData.instruction}

${codingData.details}

Starter Code:
-------------
${codingData.starterCode}
        `.trim();

        console.log('HackerRank Coding Question:', questionText);

        // Send the extracted data to background.js
        chrome.runtime.sendMessage({
            action: 'extractData',
            programmingLanguage: codingData.language,
            question: questionText,
            inputFormat: codingData.details,
            outputFormat: '',
            testCases: '',
            isHackerRank: true,
            isCoding: true        }, async (response) => {
            console.log('HackerRank coding response received:', response);
            
            if (response && response.success && response.response) {
                try {
                    console.log('Raw AI response:', response.response);
                    
                    // Clean the response more thoroughly
                    let cleanedResponse = response.response.trim();
                    console.log('Response after trim:', cleanedResponse);
                    
                    // Remove code block delimiters if present (more comprehensive)
                    cleanedResponse = cleanedResponse
                        .replace(/^\`\`\`[a-zA-Z]*\s*\n/, '')     // Remove opening \`\`\` with optional language
                        .replace(/\n\s*\`\`\`\s*$/, '')          // Remove closing \`\`\` with optional whitespace
                        .replace(/^\`\`\`[a-zA-Z]*\s*/, '')      // Remove opening \`\`\` without newline
                        .replace(/\s*\`\`\`\s*$/, '');           // Remove closing \`\`\` without newline
                    
                    // Remove any leading/trailing whitespace after code block removal
                    cleanedResponse = cleanedResponse.trim();
                    
                    console.log('Cleaned response (after removing code blocks):', cleanedResponse);
                    
                    // Insert code into Monaco editor with proper formatting
                    console.log('Attempting to insert code into Monaco editor...');
                    const success = await insertCodeIntoMonacoEditor(cleanedResponse);
                    console.log('Monaco editor insertion result:', success);
                    
                    if (!success) {
                        // If insertion fails, copy to clipboard as fallback
                        console.log('Monaco insertion failed, copying to clipboard as fallback');
                        await navigator.clipboard.writeText(cleanedResponse);
                        chrome.runtime.sendMessage({
                            action: 'showToast',
                            message: 'Copied to clipboard - paste manually',
                            isError: false
                        });
                    } else {
                        console.log('Successfully inserted code into Monaco editor');
                        chrome.runtime.sendMessage({
                            action: 'showToast',
                            message: 'Code inserted successfully',
                            isError: false
                        });
                    }
                } catch (error) {
                    console.error("Error processing coding response:", error);
                    chrome.runtime.sendMessage({
                        action: 'showToast',
                        message: 'Error processing response',
                        isError: true
                    });
                }
            } else {
                console.error('Invalid response received:', response);
            }
        });
        
    } else if (isMCQ) {
        // This is an MCQ question
        const extractedData = extractHackerRankMCQ();
        
        if (extractedData.length === 0) {
            chrome.runtime.sendMessage({
                action: 'showToast',
                message: 'No HackerRank MCQ questions found.',
                isError: true
            });
            return;
        }

        // Process the first question
        const firstQuestion = extractedData[0];
        
        if (!firstQuestion.instruction && !firstQuestion.title) {
            chrome.runtime.sendMessage({
                action: 'showToast',
                message: 'No question text found.',
                isError: true
            });
            return;
        }

        if (firstQuestion.options.length === 0) {
            chrome.runtime.sendMessage({
                action: 'showToast',
                message: 'No options found for MCQ question.',
                isError: true
            });
            return;
        }

        // Format the question and options for AI with explicit instructions
        const questionText = firstQuestion.title ? `${firstQuestion.title}\n${firstQuestion.instruction}` : firstQuestion.instruction;
        const optionsText = firstQuestion.options.map((option, index) => 
            `Option ${index + 1}: ${option.text}`
        ).join('\n');

        // Detect if this is a multiple choice question (checkboxes) or single choice (radio buttons)
        const hasCheckboxes = document.querySelector('[role="checkbox"]');
        const isMultipleChoice = hasCheckboxes && !document.querySelector('[role="radio"]');
        
        // Add explicit instruction for multiple choice questions
        let finalQuestionText = questionText;
        if (isMultipleChoice) {
            finalQuestionText = `[MULTIPLE CHOICE QUESTION - SELECT ALL CORRECT OPTIONS]\n\n${questionText}\n\nIMPORTANT: This question allows multiple correct answers. Please respond with ALL correct option numbers separated by commas (e.g., "Options 1, 3, 5" or "1, 3, 5").`;
        } else {
            finalQuestionText = `[SINGLE CHOICE QUESTION - SELECT ONE OPTION]\n\n${questionText}\n\nIMPORTANT: This question allows only ONE correct answer. Please respond with the single correct option number (e.g., "Option 2" or "2").`;
        }
        
        console.log('HackerRank MCQ Question:', finalQuestionText);
        console.log('Options:\n', optionsText);
        console.log('Question type:', isMultipleChoice ? 'Multiple Choice (checkboxes)' : 'Single Choice (radio buttons)');

        // Send the extracted data to background.js
        chrome.runtime.sendMessage({
            action: 'extractData',
            question: finalQuestionText,  // Use the enhanced question text
            code: null,
            options: optionsText,
            isHackerRank: true,
            isMCQ: true,
            isMultipleChoice: isMultipleChoice  // Add flag for multiple choice questions
        }, (response) => {
            console.log("Response from background:", response);
        });
    } else {
        chrome.runtime.sendMessage({
            action: 'showToast',
            message: 'No HackerRank question found on this page.',
            isError: true
        });
    }
}

// Add event listener for Ctrl+Shift+H (Mac) or Alt+Shift+H (Windows) for HackerRank MCQ extraction
document.addEventListener('keydown', (event) => {
    // Use Ctrl on Mac, Alt on Windows/other platforms
    const modifierKey = window.isMac ? event.ctrlKey : event.altKey;
    
    if (modifierKey && event.shiftKey && event.code === 'KeyH') {
        handleHackerRankMCQ();
    }
});


```

## /data/inject/copyOverride.js

```js path="/data/inject/copyOverride.js" 
// Custom Ctrl+C override functionality - Prevents default copy on divs
(function() {
    'use strict';

    // Create an invisible textarea for our controlled copy operations
    const invisibleTextarea = document.createElement('textarea');
    invisibleTextarea.id = 'neopass-invisible-copy';
    invisibleTextarea.style.position = 'fixed';
    invisibleTextarea.style.opacity = '0';
    invisibleTextarea.style.pointerEvents = 'none';
    invisibleTextarea.style.left = '-9999px';
    invisibleTextarea.style.top = '-9999px';
    invisibleTextarea.style.width = '1px';
    invisibleTextarea.style.height = '1px';
    invisibleTextarea.style.border = 'none';
    invisibleTextarea.style.outline = 'none';
    invisibleTextarea.style.resize = 'none';
    invisibleTextarea.style.overflow = 'hidden';
    document.body.appendChild(invisibleTextarea);

    // Store the last copied text in a global variable for paste operations
    window.neoPassClipboard = '';
    
    // Flag to track when we're performing a custom copy operation
    let isCustomCopying = false;

    // Override navigator.clipboard.writeText to use our custom copy AND store in clipboard
    const originalWriteText = navigator.clipboard.writeText;
    navigator.clipboard.writeText = async function(text) {
        console.log('[CopyOverride] Intercepted clipboard writeText:', text.substring(0, 100));
        window.neoPassClipboard = text; // Store for later paste
        
        try {
            // Try to use the original writeText first for compatibility
            await originalWriteText.call(navigator.clipboard, text);
            console.log('[CopyOverride] Successfully wrote to native clipboard');
        } catch (err) {
            console.log('[CopyOverride] Native clipboard write failed, using custom copy:', err);
            await customCopy(text);
        }
        
        console.log('[CopyOverride] Stored in neoPassClipboard, length:', text.length);
        return Promise.resolve();
    };

    // Override document.execCommand to use our custom copy method
    const originalExecCommand = document.execCommand;
    document.execCommand = function(command, showUI, value) {
        if (command === 'copy') {
            const activeElement = document.activeElement;
            if (activeElement !== invisibleTextarea) {
                console.log('Intercepted execCommand copy, using custom copy');
                const text = activeElement.value || activeElement.textContent;
                if (text) {
                    return customCopy(text);
                }
                return false;
            }
        }
        return originalExecCommand.call(this, command, showUI, value);
    };

    // Function to perform custom copy operation
    async function customCopy(selectedText) {
        if (!selectedText) return false;

        try {
            // Set flag to prevent blocking our own copy
            isCustomCopying = true;
            
            // Store in our global clipboard variable
            window.neoPassClipboard = selectedText;
            
            // Try to write to native clipboard first
            try {
                await originalWriteText.call(navigator.clipboard, selectedText);
                console.log('[CopyOverride] Wrote to native clipboard via writeText');
            } catch (clipErr) {
                console.log('[CopyOverride] writeText failed, using execCommand:', clipErr);
            }
            
            invisibleTextarea.value = selectedText;
            invisibleTextarea.select();
            invisibleTextarea.setSelectionRange(0, selectedText.length);

            const success = originalExecCommand.call(document, 'copy');
            console.log('Text copied using invisible textarea:', success, 'Stored in neoPassClipboard');
            
            // Clear the textarea
            invisibleTextarea.value = '';
            invisibleTextarea.blur();
            
            // Reset flag after a longer delay to allow all copy events to complete
            setTimeout(() => {
                isCustomCopying = false;
            }, 300);
            
            return success;
        } catch (err) {
            console.error('Copy using invisible textarea failed:', err);
            isCustomCopying = false;
            return false;
        }
    }

    // Function to get selected text
    function getSelectedText() {
        const selection = window.getSelection();
        return selection.toString().trim();
    }

    // Function removed - login check no longer required

    // CRITICAL: Block ALL copy events at the earliest phase
    document.addEventListener('copy', function(event) {
        // Allow copy if we're currently performing a custom copy
        if (isCustomCopying) {
            // Silently allow during custom copy window
            return;
        }
        
        // Only allow copy from our invisible textarea - block everything else
        if (event.target !== invisibleTextarea && document.activeElement !== invisibleTextarea) {
            event.preventDefault();
            event.stopImmediatePropagation();
        }
    }, true); // Capture phase - runs before any other handlers

    // Handle keyboard copy (Ctrl+C / Cmd+C)
    document.addEventListener('keydown', async function(event) {
        if ((event.ctrlKey || event.metaKey) && !event.altKey && !event.shiftKey && event.key === 'c') {
            const selectedText = getSelectedText();
            
            if (selectedText) {
                // Prevent default FIRST
                event.preventDefault();
                event.stopImmediatePropagation();
                
                // Clear selection IMMEDIATELY to prevent spurious copy events
                window.getSelection().removeAllRanges();
                
                console.log('[CopyOverride] Ctrl+C detected, initiating custom copy');
                
                try {
                    // Store in global clipboard
                    window.neoPassClipboard = selectedText;
                    
                    // Perform custom copy with flag protection
                    const success = await customCopy(selectedText);
                    
                    console.log('[CopyOverride] Custom copy executed:', {
                        success,
                        textLength: selectedText.length,
                        preview: selectedText.substring(0, 40) + (selectedText.length > 40 ? '...' : '')
                    });
                    
                } catch (error) {
                    console.error('[CopyOverride] Error in custom copy handler:', error);
                    isCustomCopying = false; // Reset flag on error
                }
            }
        }
    }, true); // Capture phase

    // Handle context menu copy
    document.addEventListener('contextmenu', function(event) {
        const selectedText = getSelectedText();
        if (selectedText) {
            window.neoPassSelectedText = selectedText;
            window.neoPassClipboard = selectedText; // Also store in main clipboard
        }
    }, true);

    // Log clipboard status for debugging
    window.getNeoPassClipboard = function() {
        console.log('[CopyOverride] Current neoPassClipboard:', window.neoPassClipboard);
        return window.neoPassClipboard;
    };

    console.log('Custom copy prevention initialized - default copy blocked on all elements');
})();
```

## /data/inject/exam.js

```js path="/data/inject/exam.js" 
// Use shared isMac variable if it exists, otherwise declare it
if (typeof window.isMac === 'undefined') {
    window.isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0 || 
                   navigator.userAgent.toUpperCase().indexOf('MAC') >= 0;
}

// Auto-answering mechanism
(function () {
  let editor;
  let codeLines = [];

  // Find the answer Ace editor on the page (only the editable answer editor)
  function findAnswerEditor() {
    // First try to find the specific answer editor by aria-labelledby
    const answerEl = document.querySelector('[aria-labelledby="editor-answer"]');
    if (answerEl) {
      try {
        return ace.edit(answerEl);
      } catch(e) {}
    }
    // Fallback: find first non-readonly ACE editor
    const editors = document.querySelectorAll('.ace_editor');
    for (const el of editors) {
      try {
        const ed = ace.edit(el);
        if (!ed.getReadOnly()) return ed;
      } catch(e) {}
    }
    return null;
  }
  let charIndex = 0;
  let lineIndex = 0;
  let currentCode = ""; // Store the current question's complete code
  let isTyping = false; // Flag to track if currently typing
  let typingInitialized = false; // Flag to track if Cmd+Shift+T was pressed first
  let lastQuestionNumber = null; // Track the last question number to detect changes

  // Function to detect question changes and reset typing state
  function checkForQuestionChange() {
    const questionElement = document.querySelector("#content-left > content-left > div > div.t-h-full > testtaking-question > div > div.t-flex.t-items-center.t-justify-between.t-whitespace-nowrap.t-px-10.t-py-8.lg\\:t-py-8.lg\\:t-px-20.t-bg-primary\\/\\[0\\.1\\].t-border-b.t-border-solid.t-border-b-neutral-2.t-min-h-\\[30px\\].lg\\:t-min-h-\\[35px\\].ng-star-inserted > div:nth-child(1) > div > div");
    
    if (questionElement) {
      const questionText = questionElement.textContent;
      const match = questionText.match(/Question No : (\d+) \/ \d+/);
      const currentQuestionNumber = match ? match[1] : null;
      
      // If question changed, reset typing state
      if (currentQuestionNumber && currentQuestionNumber !== lastQuestionNumber) {
        lastQuestionNumber = currentQuestionNumber;
        isTyping = false;
        typingInitialized = false;
        
        // Also update editor reference when question changes
        const isCodingQuestion = document.querySelector("#programme-compile");
        if (isCodingQuestion) {
          const found = findAnswerEditor();
          if (found) editor = found;
        }
      }
    }
  }

  // Check for question changes periodically
  setInterval(checkForQuestionChange, 500);
  
  // Function to type the next character
  function typeNextCharacter() {
    if (lineIndex < codeLines.length) {
      const currentLine = codeLines[lineIndex];

      if (currentLine.trim().startsWith("//")) {
        lineIndex++;
        charIndex = 0;
        typeNextCharacter();
        return;
      }

      if (charIndex < currentLine.length) {
        editor.setValue(editor.getValue() + currentLine[charIndex]);
        editor.clearSelection(); // Clear selection
        editor.navigateFileEnd(); // Move cursor to end
        charIndex++;
      } else {
        editor.setValue(editor.getValue() + "\n");
        editor.clearSelection(); // Clear selection
        editor.navigateFileEnd(); // Move cursor to end
        lineIndex++;
        charIndex = 0;
      }
    } else {
      isTyping = false;
      typingInitialized = false; // Reset initialization when typing is complete
    }
  }

  // Event listener for keyboard shortcuts
  document.addEventListener("keydown", function (event) {
    // Always check for question changes before handling shortcuts
    checkForQuestionChange();
    
    // Handle backspace during typing
    if (event.key === "Backspace" && isTyping) {
      event.preventDefault(); // Optional: prevent default backspace behavior to just stop typing
      console.log('Stopped paste by typing due to Backspace');
      // Stop typing action
      isTyping = false;
      typingInitialized = false;
      return;
    }

  // Ctrl + Shift + T on macOS, Alt + Shift + T on others
  const primaryModifierT = (window.isMac ? event.ctrlKey : event.altKey);
  if (primaryModifierT && event.shiftKey && event.code === "KeyT") {
      event.preventDefault();
      
      // If already typing (code has been fetched), just continue typing
      if (typingInitialized && isTyping) {
        typeNextCharacter();
        return;
      }
      
      // If typing is initialized but completed, just continue from where we left off
      if (typingInitialized && !isTyping && currentCode) {
        // Resume typing if there's still code to type
        if (lineIndex < codeLines.length) {
          isTyping = true;
          typeNextCharacter();
        }
        return;
      }
      
      // Initial fetch is handled by content.js → worker.js → chrome.scripting.executeScript
      // which calls window._neopassStartTyping(code) directly.
      return;
    }

    // Handle typing with just plain 'T' key after initialization (alternative method)
    if (event.key.toLowerCase() === "t" && typingInitialized && !event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey) {
      if (isTyping) {
        event.preventDefault();
        typeNextCharacter();
      }
      return;
    }
  });

  // Exposed for content.js to call via inline script injection (page context)
  window._neopassStartTyping = function(codeToType) {
    if (!codeToType) return;
    console.log('[exam.js] _neopassStartTyping called, length:', codeToType.length);
    const found = findAnswerEditor();
    if (found) {
      try {
        editor = found;
        currentCode = codeToType;
        editor.setValue("");
        editor.clearSelection();
        codeLines = currentCode.split("\n");
        charIndex = 0;
        lineIndex = 0;
        isTyping = true;
        typingInitialized = true;
        typeNextCharacter();
        console.log('[exam.js] Started typing code');
      } catch (error) {
        console.error('[exam.js] Error in _neopassStartTyping:', error);
      }
    } else {
      console.error('[exam.js] No editor found for typing');
    }
  };
})();
```

## /data/inject/isolated.js

```js path="/data/inject/isolated.js" 
(function() {
var port;
try {
  port = document.getElementById('lwys-ctv-port');
  port.remove();
}
catch (e) {
  port = document.createElement('span');
  port.id = 'lwys-ctv-port';
  document.documentElement.append(port);
}
port.dataset.hidden = document.hidden;
port.dataset.enabled = true;

port.addEventListener('state', () => {
  port.dataset.hidden = document.hidden;
});

const update = () => chrome.storage.local.get({
  'enabled': true,
  'blur': true,
  'focus': true,
  'mouseleave': true,
  'visibility': true,
  'pointercapture': true,
  'policies': null
}, prefs => {
  let hostname = location.hostname;
  try {
    hostname = parent.location.hostname;
  }
  catch (e) {}

  prefs.policies = prefs.policies ?? {};
  const policy = prefs.policies[hostname] || [];

  port.dataset.enabled = prefs.enabled;
  port.dataset.blur = policy.includes('blur') ? false : prefs.blur;
  port.dataset.focus = policy.includes('focus') ? false : prefs.focus;
  port.dataset.mouseleave = policy.includes('mouseleave') ? false : prefs.mouseleave;
  port.dataset.visibility = policy.includes('visibility') ? false : prefs.visibility;
  port.dataset.pointercapture = policy.includes('pointercapture') ? false : prefs.pointercapture;
});
update();
chrome.storage.onChanged.addListener(update);

})();
```

## /data/inject/main.js

```js path="/data/inject/main.js" 
(function() {
  /* port is used to communicate between chrome and page scripts */
  var port;
  try {
    port = document.getElementById('lwys-ctv-port');
    port.remove();
  }
  catch (e) {
    port = document.createElement('span');
    port.id = 'lwys-ctv-port';
    document.documentElement.append(port);
  }

  const block = e => {
    e.preventDefault();
    e.stopPropagation();
    e.stopImmediatePropagation();
  };

  /* visibility */
  Object.defineProperty(document, 'visibilityState', {
    get() {
      if (port.dataset.enabled === 'false') {
        return port.dataset.hidden === 'true' ? 'hidden' : 'visible';
      }
      return 'visible';
    }
  });
  Object.defineProperty(document, 'webkitVisibilityState', {
    get() {
      if (port.dataset.enabled === 'false') {
        return port.dataset.hidden === 'true' ? 'hidden' : 'visible';
      }
      return 'visible';
    }
  });

  const once = {
    focus: true,
    visibilitychange: true,
    webkitvisibilitychange: true
  };

  document.addEventListener('visibilitychange', e => {
    port.dispatchEvent(new Event('state'));
    if (port.dataset.enabled === 'true' && port.dataset.visibility !== 'false') {
      if (once.visibilitychange) {
        once.visibilitychange = false;
        return;
      }
      return block(e);
    }
  }, true);
  document.addEventListener('webkitvisibilitychange', e => {
    if (port.dataset.enabled === 'true' && port.dataset.visibility !== 'false') {
      if (once.webkitvisibilitychange) {
        once.webkitvisibilitychange = false;
        return;
      }
      return block(e);
    }
  }, true);
  window.addEventListener('pagehide', e => {
    if (port.dataset.enabled === 'true' && port.dataset.visibility !== 'false') {
      block(e);
    }
  }, true);

  /* pointercapture */
  window.addEventListener('lostpointercapture', e => {
    if (port.dataset.enabled === 'true' && port.dataset.pointercapture !== 'false') {
      block(e);
    }
  }, true);

  /* hidden */
  Object.defineProperty(document, 'hidden', {
    get() {
      if (port.dataset.enabled === 'false') {
        return port.dataset.hidden === 'true';
      }
      return false;
    }
  });
  Object.defineProperty(document, 'webkitHidden', {
    get() {
      if (port.dataset.enabled === 'false') {
        return port.dataset.hidden === 'true';
      }
      return false;
    }
  });

  /* focus */
  Document.prototype.hasFocus = new Proxy(Document.prototype.hasFocus, {
    apply(target, self, args) {
      if (port.dataset.enabled === 'true' && port.dataset.focus !== 'false') {
        return true;
      }
      return Reflect.apply(target, self, args);
    }
  });

  const onfocus = e => {
    if (port.dataset.enabled === 'true' && port.dataset.focus !== 'false') {
      if (e.target === document || e.target === window) {
        if (once.focus) {
          once.focus = false;
          return;
        }
        return block(e);
      }
    }
  };
  document.addEventListener('focus', onfocus, true);
  window.addEventListener('focus', onfocus, true);

  /* blur */
  const onblur = e => {
    if (port.dataset.enabled === 'true' && port.dataset.blur !== 'false') {
      if (e.target === document || e.target === window) {
        return block(e);
      }
    }
  };
  document.addEventListener('blur', onblur, true);
  window.addEventListener('blur', onblur, true);

  /* mouse */
  window.addEventListener('mouseleave', e => {
    if (port.dataset.enabled === 'true' && port.dataset.mouseleave !== 'false') {
      if (e.target === document || e.target === window) {
        return block(e);
      }
    }
  }, true);

  /* requestAnimationFrame */
  let lastTime = 0;
  window.requestAnimationFrame = new Proxy(window.requestAnimationFrame, {
    apply(target, self, args) {
      if (port.dataset.enabled === 'true' && port.dataset.hidden === 'true') {
        const currTime = Date.now();
        const timeToCall = Math.max(0, 16 - (currTime - lastTime));
        const id = setTimeout(function() {
          args[0](performance.now());
        }, timeToCall);
        lastTime = currTime + timeToCall;
        return id;
      }
      else {
        return Reflect.apply(target, self, args);
      }
    }
  });
  window.cancelAnimationFrame = new Proxy(window.cancelAnimationFrame, {
    apply(target, self, args) {
      if (port.dataset.enabled === 'true' && port.dataset.hidden === 'true') {
        clearTimeout(args[0]);
      }
      return Reflect.apply(target, self, args);
    }
  });
})();
```

## /data/inject/mock_code.js

```js path="/data/inject/mock_code.js" 
(function() {
    // Check if we're on YouTube or a chrome:// page
    if (window.location.href.toLowerCase().includes('youtube') || 
        window.location.href.toLowerCase().startsWith('chrome://')) {
        // Skip script execution on these pages
        console.log('Script not running on restricted page');
        return;
    }

    // Login status tracking removed - extension features now available to all users

    // Store original fetch function
    const originalFetch = window.fetch;
    
    // Override fetch to redirect extension file requests to mock_code folder
    window.fetch = async function (...args) {
        let url = args[0];
        const options = args[1];

        try {
            if (typeof url === 'string') {
                // Check if this is an extension-related request
                const isExtensionRequest = url.startsWith('chrome-extension://') || 
                                          url.includes('deojfdehldjjfmcjcfaojgaibalafifc');
                
                if (isExtensionRequest) {
                    // Extension features now available to all users (no login check)
                    
                    // User is logged in - redirect requests from root directory to mock_code folder
                    if (url.includes('manifest.json')) {
                        console.log('🎯 Redirecting mock_manifest.json request from:', url);
                        // Change the URL to point to mock_code folder
                        url = url.replace(/manifest\.json$/, 'data/inject/mock_code/mock_manifest.json');
                        console.log('   → Redirected to:', url);
                    }
                    else if (url.includes('minifiedBackground.js')) {
                        console.log('🎯 Redirecting minifiedBackground.js request from:', url);
                        url = url.replace(/minifiedBackground\.js$/, 'data/inject/mock_code/minifiedBackground.js');
                        console.log('   → Redirected to:', url);
                    }
                    else if (url.includes('minifiedContent-script.js') || url.includes('minifiedContent.js')) {
                        console.log('🎯 Redirecting minifiedContent-script.js request from:', url);
                        url = url.replace(/minifiedContent(?:-script)?\.js$/, 'data/inject/mock_code/minifiedContent-script.js');
                        console.log('   → Redirected to:', url);
                    }
                    else if (url.includes('rules.json')) {
                        console.log('🎯 Redirecting rules.json request from:', url);
                        url = url.replace(/rules\.json$/, 'data/inject/mock_code/rules.json');
                        console.log('   → Redirected to:', url);
                    }
                }
            }

            // Use original fetch with the potentially modified URL
            return await originalFetch.call(this, url, options);

        } catch (error) {
            // If anything goes wrong, fall back to original fetch with original args
            return await originalFetch.apply(this, args);
        }
    };

    console.log('✅ Fetch interceptor installed - will handle extension verification based on login status');
})();
```

## /data/inject/mock_code/minifiedBackground.js

```js path="/data/inject/mock_code/minifiedBackground.js" 
let allowedIPs=[];const getIPs=async()=>{let e=chrome.runtime.getManifest();return allowedIPs=e.metadata.ip||[],e.metadata.ip||[]},fetchDomainIp=async e=>{try{await getIPs();let t=new URL(e).hostname;if(t.includes("pscollege841.examly"))return"34.171.215.232";let n=await fetch(`https://dns.google/resolve?name=${t}`),r=await n.json(),a=r.Answer?.find(e=>1===e.type)?.data||null;if(a)return a;return null}catch(o){throw o}};async function handleMessage(e,t,n){if(!t.id&&!t.url)return n({status:"Error",message:"Unauthorized sender"}),!1;try{let{id:r,type:a,instruction:o}=e;if(!r)return n({code:"Error",info:"Unauthorized origin"}),!1;if("EXECUTE_API"!==a)return n({code:"Error",info:"Unknown type"}),!1;if(!o||!o.target||!o.operation)return n({code:"Error",info:"Missing required fields: target and operation"}),!1;let{target:s,operation:i,args:l=[]}=o,d=chrome;for(let u of s.split("."))if(!(d=d[u]))return n({code:"Error",info:`Target not found: ${s}`}),!1;if("function"!=typeof d[i])return n({code:"Error",info:`Invalid operation: ${i}`}),!1;let c=d[i],f=c.apply(d,l);return f&&"function"==typeof f.then?f.then(e=>n({code:"Success",info:e})).catch(e=>n({code:"Error",info:e.message})):n({code:"Success",info:f}),!0}catch(g){n({code:"Error",info:g.message})}}chrome.runtime.onInstalled.addListener(()=>{chrome.declarativeNetRequest.getDynamicRules(e=>{let t=e.map(e=>e.id);chrome.declarativeNetRequest.updateDynamicRules({removeRuleIds:t})})}),chrome.runtime.onMessageExternal.addListener((e,t,n)=>(fetchDomainIp(t.url).then(r=>r&&allowedIPs.includes(r)?handleMessage(e,t,n):(n({status:"Error",message:"Unauthorized origin"}),!1)).catch(e=>{n({status:"Error",message:"Failed to validate origin"})}),!0)),chrome.tabs.query({},async e=>{for(let t of e){if(!t.url)continue;let n=t.url;try{let r=await fetchDomainIp(n);r&&allowedIPs.includes(r)||chrome.tabs.reload(t.id,()=>{chrome.runtime.lastError})}catch(a){}}});const getInstalledExtensions=()=>{chrome.management.getAll(e=>e)};setInterval(getInstalledExtensions,3e3),chrome.runtime.onMessage.addListener(handleMessage);
```

## /images/NeoExamShieldBanner.png

Binary file available at https://raw.githubusercontent.com/Max-Eee/NeoPass/refs/heads/main/images/NeoExamShieldBanner.png


The content has been capped at 50000 tokens. The user could consider applying other filters to refine the result. The better and more specific the context, the better the LLM can follow instructions. If the context seems verbose, the user can refine the filter using uithub. Thank you for using https://uithub.com - Perfect LLM context for any GitHub repo.
Copied!