Focus Shield

On page load intercepts focus stealing and redirects to a custom search bar.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Focus Shield
// @namespace    http://tampermonkey.net/
// @version      175
// @description  On page load intercepts focus stealing and redirects to a custom search bar.
// @description  To use, update the @match line in the script header with your specific SSO domain.
// @author       Rick Zabel
// @license      CC-BY-NC-SA-4.0
// @match        *://sso.yourdomain.com/*
// @icon         data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTEyIDFMMyA1djZjMCA1LjU1IDMuODQgMTAuNzQgOSAxMiA1LjE2LTEuMjYgOS02LjQ1IDktMTJWNWwtOS00eiIgZmlsbD0iIzVmNjM2OCIvPjx0ZXh0IHg9IjEyIiB5PSIxNS41IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjZmZmZmZmIiBzdHlsZT0iZm9udC1zaXplOjEycHg7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LWZhbWlseTpBcmlhbCI+RjwvdGV4dD48L3N2Zz4=
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    const SCRIPT_VERSION = "v175";

    const initializeFocusShield = () => {
        // AI-generated with assistance from Gemini 3 Flash based on concepts by Rick Zabel.
        let blockCount = parseInt(localStorage.getItem('focusBlockCount') || '0', 10);
        let historyData = JSON.parse(localStorage.getItem('shieldHistory') || '[]');
        let sortPreference = localStorage.getItem('shieldSortPref') || 'recent';

        const labelText = "Blocked: ";
        const greasyForkUrl = "https://greasyfork.org/en/users/5920-rickzabel?sort=updated";
        const standardGrey = '#5f6368';
        const ghostGrey = '#9aa0a6';
        const textDarkGrey = '#3c4043';
        const metricGrey = '#70757a';
        const glowStyle = 'drop-shadow(0 0 4px rgba(217, 48, 37, 0.6))';

        const urlShortcuts = {
            "drive": "drive.google.com", "mail": "mail.google.com", "gmail": "mail.google.com",
            "cal": "calendar.google.com", "maps": "maps.google.com",
            "news": "news.google.com", "docs": "docs.google.com", "sheets": "sheets.google.com",
            "slides": "slides.google.com", "keep": "keep.google.com",
            "photos": "photos.google.com"
        };

        let isLocked = true;
        let searchWrapper, searchInput, counterDisplay, shieldLink, hoverCard;
        let historyDropdown, historyListContainer, sortLabel, clearHistoryBtn;
        let ghostMirror, typedSpan, suggestSpan, clearIcon;
        let currentSuggestion = "";
        let hideTimer, confirmTimer;
        let dropdownManuallyOpened = false;

        const saveHistory = (term) => {
            if (!term) { return; }
            const existing = historyData.find((i) => { return i.term.toLowerCase() === term.toLowerCase(); });
            if (existing) {
                existing.count++;
                existing.time = Date.now();
            } else {
                historyData.push({ term, count: 1, time: Date.now() });
            }
            localStorage.setItem('shieldHistory', JSON.stringify(historyData));
        };

        const deleteHistoryItem = (term) => {
            historyData = historyData.filter((i) => { return i.term !== term; });
            localStorage.setItem('shieldHistory', JSON.stringify(historyData));
            renderHistory(searchInput.value);
        };

        const renderHistory = (filter = "") => {
            if (!historyListContainer) { return; }
            historyListContainer.textContent = '';
            let displayList = historyData.filter((item) => { return item.term.toLowerCase().includes(filter.toLowerCase()); });

            if (displayList.length === 0) {
                const empty = document.createElement('div');
                empty.style.cssText = 'font-size:12px; color:#9aa0a6; text-align:center; padding:10px; font-family:Arial;';
                empty.textContent = filter ? 'No matches' : 'No history';
                historyListContainer.appendChild(empty);
                if (dropdownFooter) { dropdownFooter.style.display = 'none'; }
                return;
            }
            if (dropdownFooter) { dropdownFooter.style.display = 'flex'; }

            if (sortPreference === 'recent') {
                displayList.sort((a, b) => { return b.time - a.time; });
                if (sortLabel) { sortLabel.textContent = 'Sort: Recent'; }
            } else {
                displayList.sort((a, b) => { return b.count - a.count; });
                if (sortLabel) { sortLabel.textContent = 'Sort: Popular'; }
            }

            displayList.slice(0, 8).forEach((item) => {
                const row = document.createElement('div');
                row.style.cssText = `display:flex; justify-content:space-between; align-items:center; padding:0 15px 0 0; cursor:pointer; font-size:14px; color:${textDarkGrey}; transition:background 0.1s; font-family:Arial; position:relative; min-height:38px;`;

                const textWrapper = document.createElement('div');
                textWrapper.style.cssText = 'flex:1; display:flex; align-items:center; padding:8px 0 8px 52px; overflow:hidden;';

                row.addEventListener('mouseenter', () => { row.style.background = '#f1f3f4'; });
                row.addEventListener('mouseleave', () => { row.style.background = 'transparent'; });

                const textPart = document.createElement('span');
                textPart.textContent = item.term;
                textPart.style.cssText = 'white-space:nowrap; overflow:hidden; text-overflow:ellipsis;';

                textWrapper.appendChild(textPart);

                const metaGroup = document.createElement('div');
                metaGroup.style.cssText = 'display:flex; align-items:center; gap:10px; flex-shrink:0; padding-left:10px;';

                const badge = document.createElement('span');
                badge.textContent = `${item.count}x`;
                badge.style.cssText = `color:${metricGrey}; font-size:11px; font-weight:500;`;

                const deleteBtn = document.createElement('span');
                deleteBtn.textContent = '✕';
                deleteBtn.style.cssText = `color:${metricGrey}; font-size:10px; width:22px; height:22px; display:flex; align-items:center; justify-content:center; border-radius:50%; transition: all 0.15s ease; background: rgba(0, 0, 0, 0.03);`;

                deleteBtn.addEventListener('mouseenter', (e) => {
                    e.stopPropagation();
                    deleteBtn.style.background = 'rgba(217, 48, 37, 0.15)';
                    deleteBtn.style.color = '#d93025';
                });
                deleteBtn.addEventListener('mouseleave', () => {
                    deleteBtn.style.background = 'rgba(0, 0, 0, 0.03)';
                    deleteBtn.style.color = metricGrey;
                });
                deleteBtn.addEventListener('mousedown', (e) => {
                    e.preventDefault(); e.stopPropagation();
                    deleteHistoryItem(item.term);
                });

                metaGroup.appendChild(badge);
                metaGroup.appendChild(deleteBtn);
                row.appendChild(textWrapper);
                row.appendChild(metaGroup);

                row.addEventListener('mousedown', (e) => {
                    if (e.target !== deleteBtn) {
                        e.preventDefault();
                        searchInput.value = item.term;
                        performSearch(item.term, false);
                    }
                });
                historyListContainer.appendChild(row);
            });
        };

        const performSearch = (term, isCtrl) => {
            let finalTerm = term.trim();
            if (!finalTerm) { return; }

            const hasProtocol = /^(http|https):\/\//i.test(finalTerm);
            const hasWWW = /^www\./i.test(finalTerm);
            const hasTLD = /\.(com|net|org|edu|gov|io|co|info)$/i.test(finalTerm);

            if (isCtrl) {
                let cleanUrl = finalTerm.replace(/\s+/g, '');
                if (!hasWWW && !hasProtocol) { cleanUrl = "www." + cleanUrl; }
                if (!hasTLD) { cleanUrl = cleanUrl + ".com"; }
                finalTerm = cleanUrl;
                saveHistory(finalTerm);
                window.location.href = hasProtocol ? finalTerm : `http://${finalTerm}`;
            } else {
                saveHistory(finalTerm);
                if (hasProtocol) {
                    window.location.href = finalTerm;
                } else if ((hasWWW || hasTLD) && !finalTerm.includes(' ')) {
                    window.location.href = `https://${finalTerm}`;
                } else {
                    window.location.href = `https://www.google.com/search?q=${encodeURIComponent(finalTerm)}`;
                }
            }
            renderHistory("");
        };

        const updateGhostPosition = (fullText) => {
            const val = searchInput.value;
            if (fullText && fullText.toLowerCase().startsWith(val.toLowerCase()) && val.length > 0) {
                currentSuggestion = fullText;
                typedSpan.textContent = val;
                suggestSpan.textContent = fullText.substring(val.length);
            } else {
                currentSuggestion = "";
                typedSpan.textContent = "";
                suggestSpan.textContent = "";
            }
        };

        window.shieldSuggest = (data) => {
            if (currentSuggestion && Object.values(urlShortcuts).includes(currentSuggestion)) { return; }
            if (!data || !data[1] || data[1].length === 0) { updateGhostPosition(""); return; }
            updateGhostPosition(data[1][0]);
        };

        const fetchPredictive = (term) => {
            const lowTerm = term.toLowerCase();
            if (urlShortcuts[lowTerm]) { updateGhostPosition(urlShortcuts[lowTerm]); return; }
            const oldScript = document.getElementById('shield-jsonp');
            if (oldScript) { oldScript.remove(); }
            if (!term) { updateGhostPosition(""); return; }
            const script = document.createElement('script');
            script.id = 'shield-jsonp';
            script.src = `https://suggestqueries.google.com/complete/search?client=chrome&q=${encodeURIComponent(term)}&callback=shieldSuggest`;
            document.head.appendChild(script);
        };

        let dropdownFooter;
        const drawSearchBar = () => {
            if (document.getElementById('gemini-search-wrapper')) { return; }

            searchWrapper = document.createElement('div');
            searchWrapper.id = 'gemini-search-wrapper';
            searchWrapper.style.cssText = 'position:fixed; top:10px; left:850px; width:900px; height:48px; background:#fff; border:1px solid #dadce0; border-radius:24px; display:flex; align-items:center; padding:0 16px; box-sizing:border-box; z-index:2147483647; box-shadow:0 1px 6px rgba(32,33,36,0.28); transition: border-radius 0.2s;';

            const inputContainer = document.createElement('div');
            inputContainer.style.cssText = 'position:relative; flex:1; display:flex; align-items:center; height:100%; font-family:Arial,sans-serif; font-size:16px;';

            ghostMirror = document.createElement('div');
            ghostMirror.style.cssText = 'position:absolute; top:0; left:0; width:100%; height:100%; display:flex; align-items:center; pointer-events:none; white-space:pre; z-index:0; padding-left:2px;';
            typedSpan = document.createElement('span'); typedSpan.style.color = 'transparent';
            suggestSpan = document.createElement('span'); suggestSpan.style.cssText = `color:${ghostGrey}; text-shadow: 0 0 0.1px rgba(0,0,0,0.1);`;
            ghostMirror.appendChild(typedSpan); ghostMirror.appendChild(suggestSpan);

            searchInput = document.createElement('input');
            searchInput.type = 'text';
            searchInput.placeholder = isLocked ? 'Search Google' : 'Search Google (Unlocked)';
            searchInput.style.cssText = `width:100%; border:none; outline:none; font-size:16px; color:${textDarkGrey}; font-family:Arial,sans-serif; background:transparent; z-index:1; padding-right:35px; padding-left:2px;`;

            clearIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            clearIcon.setAttribute('viewBox', '0 0 24 24'); clearIcon.setAttribute('width', '20px'); clearIcon.setAttribute('height', '20px');
            clearIcon.style.cssText = 'position:absolute; right:5px; cursor:pointer; fill:#d93025; display:none; z-index:2; transition: transform 0.1s ease, background 0.2s ease; border-radius: 50%; padding: 2px; background: rgba(217, 48, 37, 0.1);';
            const clearPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            clearPath.setAttribute('d', 'M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z');
            clearIcon.appendChild(clearPath);
            clearIcon.addEventListener('mouseenter', () => { clearIcon.style.transform = 'scale(1.15)'; clearIcon.style.background = 'rgba(217, 48, 37, 0.25)'; });
            clearIcon.addEventListener('mouseleave', () => { clearIcon.style.transform = 'scale(1)'; clearIcon.style.background = 'rgba(217, 48, 37, 0.1)'; });
            clearIcon.addEventListener('click', () => { searchInput.value = ""; clearIcon.style.display = 'none'; updateGhostPosition(""); renderHistory(""); searchInput.focus(); });

            inputContainer.appendChild(ghostMirror); inputContainer.appendChild(searchInput); inputContainer.appendChild(clearIcon);

            const searchIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            searchIcon.setAttribute('viewBox', '0 0 24 24'); searchIcon.setAttribute('width', '20px'); searchIcon.setAttribute('height', '20px');
            searchIcon.style.cssText = 'fill:#5f6368; margin-right:12px; cursor:pointer; flex-shrink:0; transition: transform 0.1s ease;';
            const searchPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            searchPath.setAttribute('d', 'M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z');
            searchIcon.appendChild(searchPath);
            searchIcon.addEventListener('mouseenter', () => { searchIcon.style.transform = 'scale(1.15)'; });
            searchIcon.addEventListener('mouseleave', () => { searchIcon.style.transform = 'scale(1)'; });
            searchIcon.addEventListener('click', () => { performSearch(searchInput.value, false); });

            const logoGroup = document.createElement('div');
            logoGroup.style.cssText = 'display:flex; align-items:center; margin-left:10px; padding-left:10px; border-left:1px solid #dadce0; flex-shrink:0;';
            shieldLink = document.createElement('div');
            shieldLink.style.cssText = 'display:flex; cursor:pointer; transition:filter 0.2s ease;';

            const shieldSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            shieldSvg.setAttribute('viewBox', '0 0 24 24'); shieldSvg.setAttribute('width', '22px'); shieldSvg.setAttribute('height', '22px'); shieldSvg.style.marginRight = '6px';
            const shieldPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            shieldPath.setAttribute('d', 'M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4z'); shieldPath.setAttribute('fill', standardGrey);
            const logoText = document.createElementNS('http://www.w3.org/2000/svg', 'text');
            logoText.setAttribute('x', '12'); logoText.setAttribute('y', '15.5'); logoText.setAttribute('text-anchor', 'middle'); logoText.setAttribute('fill', '#fff');
            logoText.style.cssText = 'font-size:12px; font-weight:bold; font-family:Arial,sans-serif; pointer-events:none;'; logoText.textContent = 'F';
            shieldSvg.appendChild(shieldPath); shieldSvg.appendChild(logoText); shieldLink.appendChild(shieldSvg);

            historyDropdown = document.createElement('div');
            // 898px + 2px borders = 900px total width. Left -1px aligns borders perfectly.
            historyDropdown.style.cssText = 'position:absolute; top:47px; left:-1px; width:898px; background:#fff; border:1px solid #dadce0; border-top:none; border-radius:0 0 24px 24px; box-shadow:0 4px 6px rgba(32,33,36,0.28); display:none; flex-direction:column; padding:0; z-index:2147483646; overflow:hidden;';

            historyListContainer = document.createElement('div');
            historyListContainer.style.cssText = 'padding:4px 0;';

            dropdownFooter = document.createElement('div');
            dropdownFooter.style.cssText = 'display:flex; justify-content:space-between; align-items:center; padding:8px 15px; border-top:1px solid #eee; background:#fafafa; font-family:Arial;';

            const sortControl = document.createElement('div');
            sortControl.style.cssText = 'display:flex; align-items:center; cursor:pointer; gap:4px; padding:4px 8px; border-radius:4px; background:#f8f9fa; transition: background 0.2s;';
            sortControl.addEventListener('mouseenter', () => { sortControl.style.background = '#f1f3f4'; });
            sortControl.addEventListener('mouseleave', () => { sortControl.style.background = '#f8f9fa'; });

            const sortIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            sortIcon.setAttribute('viewBox', '0 0 24 24'); sortIcon.setAttribute('width', '14px'); sortIcon.setAttribute('height', '14px');
            sortIcon.style.fill = '#5f6368';
            const sortPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            sortPath.setAttribute('d', 'M3 18h6v-2H3v2zM3 6v2h18V6H3zm0 7h12v-2H3v2z');
            sortIcon.appendChild(sortPath);

            sortLabel = document.createElement('span');
            sortLabel.style.cssText = 'font-size:11px; color:#5f6368; font-weight:500;';
            sortLabel.textContent = sortPreference === 'recent' ? 'Sort: Recent' : 'Sort: Popular';

            sortControl.appendChild(sortIcon); sortControl.appendChild(sortLabel);
            sortControl.addEventListener('mousedown', (e) => {
                e.preventDefault();
                sortPreference = sortPreference === 'recent' ? 'popular' : 'recent';
                localStorage.setItem('shieldSortPref', sortPreference);
                renderHistory(searchInput.value);
            });

            clearHistoryBtn = document.createElement('div');
            clearHistoryBtn.style.cssText = 'font-size:11px; color:#d93025; cursor:pointer; font-weight:500; transition: color 0.1s;';
            clearHistoryBtn.textContent = 'Clear History';
            clearHistoryBtn.addEventListener('mouseenter', () => {
                clearHistoryBtn.style.color = '#a50e0e';
                clearHistoryBtn.style.textDecoration = 'underline';
            });
            clearHistoryBtn.addEventListener('mouseleave', () => {
                clearHistoryBtn.style.color = '#d93025';
                clearHistoryBtn.style.textDecoration = 'none';
            });
            clearHistoryBtn.addEventListener('mousedown', (e) => {
                e.preventDefault();
                if (clearHistoryBtn.textContent === 'Clear History') {
                    clearHistoryBtn.textContent = 'Confirm?';
                    confirmTimer = setTimeout(() => { clearHistoryBtn.textContent = 'Clear History'; }, 3000);
                } else {
                    historyData = [];
                    localStorage.setItem('shieldHistory', '[]');
                    renderHistory("");
                    clearHistoryBtn.textContent = 'Cleared';
                    setTimeout(() => { clearHistoryBtn.textContent = 'Clear History'; }, 1000);
                }
            });

            dropdownFooter.appendChild(sortControl); dropdownFooter.appendChild(clearHistoryBtn);
            historyDropdown.appendChild(historyListContainer); historyDropdown.appendChild(dropdownFooter);

            counterDisplay = document.createElement('span');
            counterDisplay.style.cssText = `color:${metricGrey}; font-size:12px; white-space:nowrap; font-family:monospace;`;
            counterDisplay.textContent = `${labelText}${blockCount}`;

            logoGroup.appendChild(shieldLink); logoGroup.appendChild(counterDisplay);
            searchWrapper.appendChild(searchIcon); searchWrapper.appendChild(inputContainer); searchWrapper.appendChild(logoGroup);
            searchWrapper.appendChild(historyDropdown);
            document.body.appendChild(searchWrapper);

            hoverCard = document.createElement('div');
            hoverCard.style.cssText = 'position:fixed; top:65px; left:1410px; width:320px; background:#fff; border:1px solid #dadce0; border-radius:12px; box-shadow:0 8px 24px rgba(0,0,0,0.18); padding:16px; display:none; z-index:2147483647; font-family:Arial,sans-serif;';
            const cardIcon = shieldSvg.cloneNode(true); cardIcon.setAttribute('width', '66px'); cardIcon.setAttribute('height', '66px'); cardIcon.style.marginRight = '20px';
            const cardText = document.createElement('div');
            const titleRow = document.createElement('div'); titleRow.style.cssText = 'font-weight:bold; font-size:18px; color:#202124;'; titleRow.textContent = 'Focus Shield';
            const creditRow = document.createElement('div'); creditRow.style.cssText = 'font-size:13px; color:#5f6368; margin-top:2px;'; creditRow.textContent = 'by Rick Zabel via Gemini';
            const versionRow = document.createElement('div'); versionRow.style.cssText = 'font-size:11px; color:#9aa0a6; margin-top:4px; margin-bottom:10px; font-family:monospace;'; versionRow.textContent = `Version: ${SCRIPT_VERSION}`;
            const gfLink = document.createElement('a'); gfLink.href = greasyForkUrl; gfLink.target = '_blank'; gfLink.style.cssText = 'font-size:13px; color:#1a73e8; font-weight:500; text-decoration:none;'; gfLink.textContent = 'Visit Greasy Fork Profile';
            cardText.appendChild(titleRow); cardText.appendChild(creditRow); cardText.appendChild(versionRow); cardText.appendChild(gfLink);
            const cardFlex = document.createElement('div'); cardFlex.style.display = 'flex'; cardFlex.style.alignItems = 'center';
            cardFlex.appendChild(cardIcon); cardFlex.appendChild(cardText); hoverCard.appendChild(cardFlex);
            document.body.appendChild(hoverCard);

            const syncUI = () => {
                if (searchInput && clearIcon) {
                    clearIcon.style.display = searchInput.value.length > 0 ? 'block' : 'none';
                }
            };
            syncUI();
            setInterval(syncUI, 500);

            window.addEventListener('pageshow', () => {
                syncUI();
                if (searchInput && searchInput.value.length > 0 && dropdownManuallyOpened) {
                    renderHistory(searchInput.value);
                }
            });

            shieldLink.addEventListener('mouseenter', () => { clearTimeout(hideTimer); hoverCard.style.display = 'block'; });
            shieldLink.addEventListener('mouseleave', () => { hideTimer = setTimeout(() => { hoverCard.style.display = 'none'; }, 350); });
            hoverCard.addEventListener('mouseenter', () => { clearTimeout(hideTimer); });
            hoverCard.addEventListener('mouseleave', () => { hideTimer = setTimeout(() => { hoverCard.style.display = 'none'; }, 350); });

            searchInput.addEventListener('mousedown', () => {
                dropdownManuallyOpened = true;
                historyDropdown.style.display = 'flex';
                searchWrapper.style.borderRadius = '24px 24px 0 0';
                renderHistory(searchInput.value);
            });
            searchInput.addEventListener('blur', () => {
                setTimeout(() => {
                    dropdownManuallyOpened = false;
                    historyDropdown.style.display = 'none';
                    searchWrapper.style.borderRadius = '24px';
                }, 200);
            });
            searchInput.addEventListener('input', () => {
                syncUI();
                if (dropdownManuallyOpened) { renderHistory(searchInput.value); }
                fetchPredictive(searchInput.value);
            });
            searchInput.addEventListener('keydown', (e) => {
                if (e.key === 'Tab' && currentSuggestion !== "") {
                    e.preventDefault(); searchInput.value = currentSuggestion; updateGhostPosition("");
                }
                if (e.key === 'Enter') {
                    performSearch(searchInput.value, e.ctrlKey);
                }
            });
        };

        const enforceFocus = () => {
            if (isLocked && searchInput && document.activeElement !== searchInput) {
                searchInput.focus(); searchInput.select();
            }
            requestAnimationFrame(enforceFocus);
        };
        const updateCounter = () => {
            blockCount++; localStorage.setItem('focusBlockCount', blockCount.toString());
            if (counterDisplay) { counterDisplay.textContent = `${labelText}${blockCount}`; }
            if (shieldLink) { shieldLink.style.filter = glowStyle; setTimeout(() => { shieldLink.style.filter = 'none'; }, 200); }
        };
        const unlock = () => {
            isLocked = false;
            if (searchWrapper) { searchWrapper.style.backgroundColor = '#f8f9fa'; }
            if (searchInput) { searchInput.placeholder = 'Search Google (Unlocked)'; }
        };

        window.addEventListener('mousedown', (e) => { if (searchWrapper && !searchWrapper.contains(e.target) && !hoverCard.contains(e.target)) { unlock(); } }, true);
        window.addEventListener('keydown', (e) => { if (e.key === 'Escape') { unlock(); } });

        const domObserver = new MutationObserver(() => {
            if (document.body && !document.getElementById('gemini-search-wrapper')) {
                drawSearchBar();
            }
        });
        domObserver.observe(document.documentElement, { childList: true, subtree: true });

        HTMLElement.prototype.focus = function() {
            if (isLocked && this !== searchInput) {
                updateCounter();
            }
        };

        if (document.body) { drawSearchBar(); enforceFocus(); }
        else { window.addEventListener('DOMContentLoaded', () => { drawSearchBar(); enforceFocus(); }); }
    };

    initializeFocusShield();
})();