AI Floating Bubble

Adds a draggable floating AI bubble to all webpages with an updated list of AI sites appearing above it on hover, with a delay and fade-out on mouse leave.

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         AI Floating Bubble
// @version      1.1
// @description  Adds a draggable floating AI bubble to all webpages with an updated list of AI sites appearing above it on hover, with a delay and fade-out on mouse leave.
// @author       monit8280
// @match        *://*/*
// @grant        GM_addStyle
// @license      MIT
// @namespace    http://tampermonkey.net/
// ==/UserScript==

(function() {
    'use strict';

    // 현재 창이 AI 팝업 창인지 확인합니다.
    // URL에 'bubble_popup' 쿼리 파라미터가 있는지 검사하여 팝업 여부를 판단합니다.
    const urlParams = new URLSearchParams(window.location.search);
    const isAIPopup = urlParams.has('bubble_popup');

    // 현재 창이 AI 팝업 창으로 감지되면 버블을 초기화하지 않고 스크립트 실행을 종료합니다.
    if (isAIPopup) {
        console.log("AI 플로팅 버블: AI 팝업 창으로 감지되어 버블을 초기화하지 않습니다.");
        return;
    }

    /**
     * @class AIIcons
     * AI 사이트 아이콘 URL을 관리하는 클래스입니다.
     * 각 AI 서비스에 사용될 아이콘 이미지의 URL을 정의합니다.
     */
    class AIIcons {
        // 메인 버블 버튼에 사용될 아이콘 이미지 URL
        static get BUBBLE() { return "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPg0KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCjxwYXRoIGQ9Ik0xMC4yNzY4IDE2LjUxNDhDMTAuMjgxNSAxNi40MDUgMTAuNDYzNCAxNi4zNjEzIDEwLjUxNzQgMTYuNDU3MUMxMC43NzA3IDE2LjkwNjggMTEuMjAyOSAxNy41NjgyIDExLjY5MzIgMTcuODY4OUMxMi4xODM2IDE4LjE2OTYgMTIuOTY5IDE4LjI1NDkgMTMuNDg0NyAxOC4yNzY4QzEzLjU5NDUgMTguMjgxNSAxMy42MzgxIDE4LjQ2MzQgMTMuNTQyMyAxOC41MTc0QzEzLjA5MjYgMTguNzcwNyAxMi40MzEzIDE5LjIwMjkgMTIuMTMwNiAxOS42OTMyQzExLjgyOTkgMjAuMTgzNiAxMS43NDQ2IDIwLjk2OSAxMS43MjI3IDIxLjQ4NDdDMTEuNzE4IDIxLjU5NDUgMTEuNTM2IDIxLjYzODEgMTEuNDgyMSAyMS41NDIzQzExLjIyODcgMjEuMDkyNiAxMC43OTY2IDIwLjQzMTMgMTAuMzA2MiAyMC4xMzA2QzkuODE1ODggMTkuODI5OSA5LjAzMDQ4IDE5Ljc0NDYgOC41MTQ4MSAxOS43MjI3QzguNDA0OTUgMTkuNzE4IDguMzYxMzMgMTkuNTM2IDguNDU3MTMgMTkuNDgyMUM4LjkwNjgyIDE5LjIyODcgOS41NjgxOCAxOC43OTY2IDkuODY4ODkgMTguMzA2MkMxMC4xNjk2IDE3LjgxNTkgMTAuMjU0OSAxNy4wMzA1IDEwLjI3NjggMTYuNTE0OFoiIGZpbGw9IiMxQzI3NEMiLz4NCjxwYXRoIG9wYWNpdHk9IjAuNSIgZD0iTTE4LjQ5MTkgMTUuNTE0N0MxOC40ODM0IDE1LjQwNTEgMTguMjkxNiAxNS4zNTkxIDE4LjIzNDMgMTUuNDUzQzE4LjA2MiAxNS43MzU1IDE3LjgxMzUgMTYuMDc2NCAxNy41Mzc0IDE2LjI0NThDMTcuMjYxMiAxNi40MTUyIDE2Ljg0NDYgMTYuNDgyIDE2LjUxNDcgMTYuNTA3NUMxNi40MDUxIDE2LjUxNiAxNi4zNTkxIDE2LjcwNzggMTYuNDUzIDE2Ljc2NTFDMTYuNzM1NSAxNi45Mzc0IDE3LjA3NjQgMTcuMTg1OCAxNy4yNDU4IDE3LjQ2MkMxNy40MTUyIDE3LjczODIgMTcuNDgyIDE4LjE1NDggMTcuNTA3NSAxOC40ODQ3QzE3LjUxNiAxOC41OTQzIDE3LjcwNzggMTguNjQwMyAxNy43NjUxIDE4LjU0NjRDMTcuOTM3NCAxOC4yNjM5IDE4LjE4NTggMTcuOTIzIDE4LjQ2MiAxNy43NTM2QzE4LjczODIgMTcuNTg0MiAxOS4xNTQ4IDE3LjUxNzQgMTkuNDg0NyAxNy40OTE5QzE5LjU5NDMgMTcuNDgzNCAxOS42NDAzIDE3LjI5MTYgMTkuNTQ2NCAxNy4yMzQzQzE5LjI2MzkgMTcuMDYyIDE4LjkyMyAxNi44MTM1IDE4Ljc1MzYgMTYuNTM3NEMxOC41ODQyIDE2LjI2MTIgMTguNTE3NCAxNS44NDQ2IDE4LjQ5MTkgMTUuNTE0N1oiIGZpbGw9IiMxQzI3NEMiLz4NCjxwYXRoIGQ9Ik0xNC43MDM0IDQuMDAxODFMMTQuNDYxMSAzLjY5NTc0QzEzLjUyNDUgMi41MTI2NiAxMy4wNTYxIDEuOTIxMTIgMTIuNTExMyAyLjAwODQ1QzExLjk2NjUgMi4wOTU3NyAxMS43MDU5IDIuODA0MTIgMTEuMTg0OSA0LjIyMDgzTDExLjA1MDEgNC41ODczNUMxMC45MDIgNC45ODk5MyAxMC44MjggNS4xOTEyMiAxMC42ODYgNS4zMzg5N0MxMC41NDQgNS40ODY3MSAxMC4zNTAxIDUuNTY0MTcgOS45NjI0MiA1LjcxOTExTDkuNjA5NDIgNS44NjAxNkw5LjM2MTU2IDUuOTU5MzNDOC4xNjIwNCA2LjQ0MDYgNy41NTc2MSA2LjcxMzMxIDcuNDgwNDQgNy4yNDMyNEM3LjM5ODEzIDcuODA4NDkgNy45NzAyMyA4LjI5MjA1IDkuMTE0NDMgOS4yNTkxNUw5LjQxMDQ1IDkuNTA5MzVDOS43MzU2IDkuNzg0MTcgOS44OTgxNyA5LjkyMTU4IDkuOTkxMzcgMTAuMTA4OUMxMC4wODQ2IDEwLjI5NjIgMTAuMDk3OCAxMC41MTIxIDEwLjEyNDQgMTAuOTQ0MUwxMC4xNDg1IDExLjMzNzNDMTAuMjQxOSAxMi44NTc0IDEwLjI4ODYgMTMuNjE3NCAxMC43ODI2IDEzLjg3OTRDMTEuMjc2NSAxNC4xNDE0IDExLjg5MDYgMTMuNzMxOSAxMy4xMTg4IDEyLjkxMjlMMTMuMTE4OCAxMi45MTI5TDEzLjQzNjYgMTIuNzAxQzEzLjc4NTYgMTIuNDY4MyAxMy45NjAxIDEyLjM1MTkgMTQuMTU5NyAxMi4zMkMxNC4zNTkzIDEyLjI4OCAxNC41NjEzIDEyLjM0NCAxNC45NjU1IDEyLjQ1NkwxNS4zMzM0IDEyLjU1OEMxNi43NTU1IDEyLjk1MjIgMTcuNDY2NiAxMy4xNDkzIDE3Ljg1NDIgMTIuNzQ2QzE4LjI0MTggMTIuMzQyNyAxOC4wNDkzIDExLjYwNjEgMTcuNjY0MSAxMC4xMzI4TDE3LjU2NDUgOS43NTE2M0MxNy40NTUxIDkuMzMyOTcgMTcuNDAwMyA5LjEyMzY0IDE3LjQzMDUgOC45MTY1N0MxNy40NjA2IDguNzA5NTEgMTcuNTcyMyA4LjUyODE2IDE3Ljc5NTUgOC4xNjU0NkwxNy43OTU1IDguMTY1NDRMMTcuOTk4NyA3LjgzNTIyQzE4Ljc4NDMgNi41NTg4MyAxOS4xNzcxIDUuOTIwNjMgMTguOTIyNyA1LjQwOTM1QzE4LjY2ODIgNC44OTgwNiAxNy45MzUxIDQuODUyMjkgMTYuNDY4OSA0Ljc2MDc2TDE2LjA4OTYgNC43MzcwOEMxNS42NzI5IDQuNzExMDcgMTUuNDY0NiA0LjY5ODA3IDE1LjI4MzYgNC42MDIwOEMxNS4xMDI3IDQuNTA2MSAxNC45Njk2IDQuMzM4IDE0LjcwMzQgNC4wMDE4MUwxNC43MDM0IDQuMDAxODFaIiBmaWxsPSIjMUMyNzRDIi8+DQo8cGF0aCBvcGFjaXR5PSIwLjUiIGQ9Ik04LjgzNSAxMy4zMjZDNi42OTc3MiAxNC4zNzAyIDQuOTE5MzEgMTYuMDI0IDQuMjQ4NDQgMTguMDAwMkMzLjQ5NTg5IDEzLjI5MjYgNC41Mzk3NiAxMC4yNTI2IDYuMjEzMDggOC4zNjMyOEM2LjM1NzI4IDguNjU4IDYuNTQ0NjYgOC45MDIgNi43MTI5NyA5LjA5MjY5QzcuMDYyODYgOS40ODkxMSA3LjU2NTE4IDkuOTEzNDcgOC4wNzUyMyAxMC4zNDQ0TDguNDQyMjUgMTAuNjU0NUM4LjUxMTg0IDEwLjcxMzQgOC41NjU5NyAxMC43NTkyIDguNjExOTcgMTAuNzk4OUM4LjYxNjY1IDEwLjg2MzIgOC42MjEyOSAxMC45MzgzIDguNjI3MjcgMTEuMDM1N0w4LjY1NzA4IDExLjUyMTJDOC42OTcxNyAxMi4xNzYxIDguNzM2MyAxMi44MTU1IDguODM1IDEzLjMyNloiIGZpbGw9IiMxQzI3NEMiLz4NCjwvc3ZnPg=="; }
        // Gemini AI 서비스 아이콘 URL
        static get GEMINI() { return "data:image/png;base64,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"; }
        // ChatGPT AI 서비스 아이콘 URL
        static get CHATGPT() { return "https://chatgpt.com/favicon.ico"; }
        // Claude AI 서비스 아이콘 URL
        static get CLAUDE() { return "https://claude.ai/favicon.ico"; }
        // Copilot AI 서비스 아이콘 URL
        static get COPILOT() { return "https://copilot.microsoft.com/favicon.ico"; }
        // Grok AI 서비스 아이콘 URL
        static get GROK() { return "https://grok.com/favicon.ico"; }
        // Perplexity AI 서비스 아이콘 URL
        static get PERPLEXITY() { return "https://www.perplexity.ai/favicon.ico"; }
        // 아이콘 로드 실패 시 표시될 대체 이미지 (Placeholder)
        static get PLACEHOLDER() { return "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPgo8c3ZnIHdpZHRoPSI4MDBweCIgaGVpZ2h0PSI4MDBweCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTEyIDMuNTM4NDZDNy4zMjY4MiAzLjUzODQ2IDMuNTM4NDYgNy4zMjY4MiAzLjUzODQ2IDEyQzMuNTM4NDYgMTYuNjczMiA3LjMyNjgyIDIwLjQ2MTUgMTIgMjAuNDYxNUMxNi42NzMyIDIwLjQ2MTUgMjAuNDYxNSAxNi42NzMyIDIwLjQ2MTUgMTJDMjAuNDYxNSA3LjMyNjgyIDE2LjY3MzIgMy41Mzg0NiAxMiAzLjUzODQ2Wk0yIDEyQzIgNi40NzcxNSA2LjQ3NzE1IDIgMTIgMkMxNy41MjI4IDIgMjIgNi40NzcxNSAyMiAxMkMyMiAxNy41MjI4IDE3LjUyMjggMjIgMTIgMjJDNi40NzcxNSAyMiAyIDE3LjUyMjggMiAxMloiIGZpbGw9IiMwMzBENDUiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xMiA4LjE1Mzg1QzExLjI5MTkgOC4xNTM4NSAxMC43MTc5IDguNzI3ODQgMTAuNzE3OSA5LjQzNTlDMTAuNzE3OSA5Ljg2MDczIDEwLjM3MzYgMTAuMjA1MSA5Ljk0ODcyIDEwLjIwNTFDOS41MjM4OCAxMC4yMDUxIDkuMTc5NDkgOS44NjA3MyA5LjE3OTQ5IDkuNDM1OUM5LjE3OTQ5IDcuODc4MTcgMTAuNDQyMyA2LjYxNTM5IDEyIDYuNjE1MzlDMTMuNTU3NyA2LjYxNTM5IDE0LjgyMDUgNy44NzgxNyAxNC44MjA1IDkuNDM1OUMxNC44MjA1IDkuOTk2MjQgMTQuNjU2MyAxMC41MjA2IDE0LjM3MzEgMTAuOTYwNkMxNC4xOTU4IDExLjIzNjMgMTMuOTg4NCAxMS40OTk0IDEzLjc5NzIgMTEuNzM3MUMxMy43NjIyIDExLjc4MDUgMTMuNzI3OSAxMS44MjMxIDEzLjY5NDEgMTEuODY0OUMxMy41MzU1IDEyLjA2MTIgMTMuMzg5OCAxMi4yNDE1IDEzLjI1NTMgMTIuNDI2NEMxMi45MjM0IDEyLjg4MjYgMTIuNzY5MiAxMy4yMjUzIDEyLjc2OTIgMTMuNTM4NUMxMi43NjkyIDEzLjk2MzMgMTIuNDI0OCAxNC4zMDc3IDEyIDE0LjMwNzdDMTEuNTc1MiAxNC4zMDc3IDExLjIzMDggMTMuOTYzMyAxMS4yMzA4IDEzLjUzODVDMTEuMjMwOCAxMi43MTg3IDExLjYzMzIgMTIuMDQwOCAxMi4wMTEyIDExLjUyMTNDMTIuMTcxIDExLjMwMTggMTIuMzQ2IDExLjA4NTMgMTIuNTA1MSAxMC44ODg0QzEyLjUzNyAxMC44NDkgMTIuNTY4MyAxMC44MTAzIDEyLjU5ODYgMTAuNzcyNkMxMi43ODg1IDEwLjUzNjUgMTIuOTUwMiAxMC4zMjg5IDEzLjA3OTQgMTAuMTI4MkMxMy4yMDc2IDkuOTI4OTEgMTMuMjgyMSA5LjY5MjI3IDEzLjI4MjEgOS40MzU5QzEzLjI4MjEgOC43Mjc4NCAxMi43MDgxIDguMTUzODUgMTIgOC4xNTM4NVoiIGZpbGw9IiMwMzBENDUiLz4KPHBhdGggZD0iTTEzLjAyNTYgMTYuNjE1NEMxMy4wMjU2IDE3LjE4MTggMTIuNTY2NCAxNy42NDEgMTIgMTcuNjQxQzExLjQzMzYgMTcuNjQxIDEwLjk3NDQgMTcuMTgxOCAxMC45NzQ0IDE2LjYxNTRDMTAuOTc0NCAxNi4wNDg5IDExLjQzMzYgMTUuNTg5NyAxMiAxNS41ODk3QzEyLjU2NjQgMTUuNTg5NyAxMy4wMjU2IDE2LjA0ODkgMTMuMDI1NiAxNi42MTU0WiIgZmlsbD0iIzAzMEQ0NSIvPgo8L3N2Zz4="; }
    }

    /**
     * @class AISites
     * AI 사이트 이름과 URL 목록을 관리하는 클래스입니다.
     * 이 목록은 플로팅 버블 메뉴에 표시될 AI 서비스들의 정보를 담고 있습니다.
     * 목록 순서는 AI 목록 표시 순서와 동일하게 유지됩니다.
     */
    class AISites {
        static get LIST() {
            return [
                { name: "Perplexity", url: "https://www.perplexity.ai/", icon: AIIcons.PERPLEXITY },
                { name: "Grok", url: "https://grok.com/", icon: AIIcons.GROK },
                { name: "Gemini", url: "https://gemini.google.com/", icon: AIIcons.GEMINI },
                { name: "Copilot", url: "https://copilot.microsoft.com/", icon: AIIcons.COPILOT },
                { name: "Claude", url: "https://claude.ai/", icon: AIIcons.CLAUDE },
                { name: "ChatGPT", url: "https://chatgpt.com/", icon: AIIcons.CHATGPT }
            ];
        }
    }

    /**
     * @class BubbleConfig
     * 버블의 크기, 간격, 애니메이션 타이밍 등 모든 숫자형 설정 값을 관리하는 클래스입니다.
     * 모든 단위는 픽셀(px) 또는 밀리초(ms)입니다.
     * 이 값을 조정하여 버블의 외형과 동작을 커스터마이징할 수 있습니다.
     */
    class BubbleConfig {
        static get BUBBLE_SIZE() { return 50; } // 버블 버튼의 너비와 높이 (px)
        static get OPTION_ICON_SIZE() { return 16; } // AI 목록 각 항목의 아이콘 크기 (px)
        static get OPTION_MENU_GAP() { return 10; } // 버블 버튼과 AI 목록 메뉴 사이의 간격 (px)
        static get OPTION_ITEM_PADDING_VERTICAL() { return 10; } // 각 AI 목록 항목의 상하 패딩 (px)
        static get OPTION_ITEM_PADDING_HORIZONTAL() { return 15; } // 각 AI 목록 항목의 좌우 패딩 (px)
        static get OPTION_ITEM_ICON_MARGIN_RIGHT() { return 10; } // AI 목록 항목의 아이콘과 텍스트 사이 간격 (px)
        static get OPTION_MENU_WIDTH() { return 150; } // AI 목록 메뉴의 고정 너비 (px)
        static get MENU_TRANSITION_DURATION() { return 0.3; } // 메뉴가 나타나고 사라지는 애니메이션 시간 (초)
        static get MENU_HIDE_DELAY() { return 100; } // 마우스가 메뉴에서 벗어난 후 메뉴가 숨겨지기까지의 지연 시간 (밀리초)
        static get POPUP_WINDOW_WIDTH() { return 800; } // 새 창으로 열릴 AI 사이트 팝업의 기본 너비 (px)
        static get POPUP_WINDOW_HEIGHT() { return 600; } // 새 창으로 열릴 AI 사이트 팝업의 기본 높이 (px)
    }

    /**
     * @class AIFloatingBubble
     * AI 플로팅 버블을 관리하는 메인 클래스입니다.
     * 이 클래스는 버블의 생성, 드래그 기능, AI 목록 메뉴 표시/숨김,
     * AI 사이트 클릭 시 새 창 열기 등의 모든 기능을 담당합니다.
     */
    class AIFloatingBubble {
        constructor() {
            // DOM 요소 참조 변수 초기화
            this.bubbleContainer = null; // 전체 버블 컨테이너 (드래그 가능 영역)
            this.bubbleButton = null; // 버블 아이콘이 표시되는 버튼 영역
            this.siteOptions = null; // AI 사이트 목록 메뉴 영역
            this.hideTimeout = null; // 메뉴 숨김 지연을 위한 타이머 ID
            this.isDragging = false; // 버블 드래그 중인지 여부
            this.offsetX = 0; // 드래그 시작 시 마우스 X 오프셋
            this.offsetY = 0; // 드래그 시작 시 마우스 Y 오프셋

            this._init(); // 클래스 초기화 메서드 호출
        }

        /**
         * @private
         * 초기화 메서드: DOM 요소 생성, 스타일 적용, 이벤트 리스너 설정.
         * 스크립트가 로드될 때 가장 먼저 호출됩니다.
         */
        _init() {
            this._createElements(); // 필요한 HTML 요소들을 생성하고 문서에 추가합니다.
            this._applyStyles();        // 생성된 요소들에 CSS 스타일을 적용합니다.
            this._loadPosition(); // 저장된 위치를 로드하고 적용합니다.
            this._setupEventListeners(); // 드래그, 호버, 클릭 등의 이벤트 리스너를 설정합니다.
        }

        /**
         * @private
         * DOM 요소를 생성하고 문서에 추가합니다.
         * 플로팅 버블의 구조 (컨테이너, 버튼, 옵션 메뉴)를 만듭니다.
         */
        _createElements() {
            // AI 플로팅 버블 컨테이너 요소 생성
            this.bubbleContainer = document.createElement('div');
            this.bubbleContainer.id = 'aiFloatingBubbleContainer';
            // 초기 위치는 _loadPosition에서 설정되므로 여기서는 기본값 또는 빈 값으로 둡니다.
            document.body.appendChild(this.bubbleContainer);

            // 플로팅 버블 버튼 요소 (메인 아이콘) 생성
            this.bubbleButton = document.createElement('div');
            this.bubbleButton.id = 'aiFloatingBubbleButton';
            // 버블 아이콘 이미지를 설정합니다.
            this.bubbleButton.innerHTML = `
                <img src="${AIIcons.BUBBLE}" alt="AI 아이콘" style="width: ${BubbleConfig.BUBBLE_SIZE * (2/3)}px; height: ${BubbleConfig.BUBBLE_SIZE * (2/3)}px;">
            `;
            this.bubbleContainer.appendChild(this.bubbleButton);

            // AI 사이트 선택지 메뉴 요소 생성
            this.siteOptions = document.createElement('div');
            this.siteOptions.id = 'aiSiteOptions';

            // AISites 클래스에서 AI 목록을 가져와 메뉴 HTML을 동적으로 생성합니다.
            let optionsHtml = '';
            AISites.LIST.forEach(site => {
                optionsHtml += `
                    <div class="ai-option" data-url="${site.url}">
                        <img src="${site.icon}" alt="${site.name} 아이콘" class="option-icon" onerror="this.onerror=null;this.src='${AIIcons.PLACEHOLDER}';">
                        <span>${site.name}</span>
                    </div>
                `;
            });
            this.siteOptions.innerHTML = optionsHtml;
            this.bubbleContainer.appendChild(this.siteOptions);
        }

        /**
         * @private
         * 필요한 CSS 스타일을 문서에 동적으로 추가합니다.
         * Tampermonkey의 GM_addStyle 함수를 사용하여 전역 스타일을 적용합니다.
         * 모든 크기 관련 값은 BubbleConfig 클래스에서 가져옵니다.
         */
        _applyStyles() {
            GM_addStyle(`
                /* 플로팅 버블 전체 컨테이너 스타일 */
                #aiFloatingBubbleContainer {
                    position: fixed;
                    z-index: 9999;
                    width: ${BubbleConfig.BUBBLE_SIZE}px;
                    height: ${BubbleConfig.BUBBLE_SIZE}px;
                    cursor: grab;
                }

                /* 드래그 중일 때의 커서 스타일 */
                #aiFloatingBubbleContainer.grabbing {
                    cursor: grabbing;
                }

                /* 플로팅 버블 버튼 (원형 아이콘) 스타일 */
                #aiFloatingBubbleButton {
                    position: absolute;
                    bottom: 0;
                    right: 0;
                    background-color: #fff;
                    border: 1px solid #ccc;
                    border-radius: 50%;
                    width: ${BubbleConfig.BUBBLE_SIZE}px;
                    height: ${BubbleConfig.BUBBLE_SIZE}px;
                    display: flex;
                    justify-content: center;
                    align-items: center;
                    cursor: pointer;
                    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
                    transition: transform 0.2s;
                }

                /* 버블 버튼 내부 이미지 스타일 */
                #aiFloatingBubbleButton img {
                    user-select: none;
                    -webkit-user-drag: none;
                    pointer-events: none;
                }

                /* 버블 버튼 호버 시 확대 효과 */
                #aiFloatingBubbleButton:hover {
                    transform: scale(1.1);
                }

                /* AI 사이트 옵션 메뉴 스타일 */
                #aiSiteOptions {
                    position: absolute;
                    bottom: ${BubbleConfig.BUBBLE_SIZE + BubbleConfig.OPTION_MENU_GAP}px;
                    right: 0;
                    flex-direction: column;
                    background-color: #fff;
                    border: 1px solid #eee;
                    border-radius: 8px;
                    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);
                    overflow: hidden;
                    white-space: nowrap;

                    max-height: 0;
                    opacity: 0;
                    pointer-events: none;
                    transition: max-height ${BubbleConfig.MENU_TRANSITION_DURATION}s ease-out, opacity ${BubbleConfig.MENU_TRANSITION_DURATION}s ease-out;
                }

                /* AI 사이트 옵션 메뉴가 보일 때의 스타일 */
                #aiSiteOptions.visible {
                    max-height: 500px;
                    opacity: 1;
                    pointer-events: auto;
                    transition: max-height ${BubbleConfig.MENU_TRANSITION_DURATION}s ease-out, opacity ${BubbleConfig.MENU_TRANSITION_DURATION}s ease-out;
                }

                /* 각 AI 사이트 옵션 항목 스타일 */
                .ai-option {
                    display: flex;
                    align-items: center;
                    padding: ${BubbleConfig.OPTION_ITEM_PADDING_VERTICAL}px ${BubbleConfig.OPTION_ITEM_PADDING_HORIZONTAL}px;
                    cursor: pointer;
                    border-bottom: 1px solid #f0f0f0;
                    transition: background-color 0.2s;
                    width: ${BubbleConfig.OPTION_MENU_WIDTH}px;
                }

                /* 마지막 메뉴 항목의 하단 구분선 제거 */
                .ai-option:last-child {
                    border-bottom: none;
                }

                /* 메뉴 항목 호버 시 배경색 변경 */
                .ai-option:hover {
                    background-color: #f5f5f5;
                }

                /* 메뉴 항목 내부 아이콘 스타일 */
                .ai-option .option-icon {
                    width: ${BubbleConfig.OPTION_ICON_SIZE}px;
                    height: ${BubbleConfig.OPTION_ICON_SIZE}px;
                    margin-right: ${BubbleConfig.OPTION_ITEM_ICON_MARGIN_RIGHT}px;
                    border-radius: 2px;
                    vertical-align: middle;
                    user-select: none;
                    -webkit-user-drag: none;
                    pointer-events: none;
                }

                /* 메뉴 항목 내부 텍스트 (AI 이름) 스타일 */
                .ai-option span {
                    font-family: 'Inter', sans-serif;
                    font-size: 14px;
                    color: #333;
                    font-weight: normal;
                }
            `);
        }

        /**
         * @private
         * 모든 이벤트 리스너를 설정합니다.
         * 드래그, 호버, 클릭 관련 이벤트를 등록합니다.
         */
        _setupEventListeners() {
            this._setupDrag(); // 버블 드래그 기능 설정
            this._setupHover(); // AI 목록 표시/숨김 호버 기능 설정
            this._setupClick(); // AI 사이트 옵션 클릭 기능 설정
        }

        /**
         * @private
         * 버블 드래그 기능을 설정합니다.
         * 마우스 다운, 이동, 업 이벤트를 사용하여 버블을 드래그 가능하게 합니다.
         */
        _setupDrag() {
            this.bubbleContainer.addEventListener('mousedown', (e) => {
                // AI 옵션 메뉴 자체를 드래그하는 것은 방지합니다.
                // 만약 클릭된 요소가 '.ai-option' 클래스를 포함한다면 드래그를 시작하지 않습니다.
                if (e.target.closest('.ai-option')) {
                    return;
                }

                this.isDragging = true;
                this.bubbleContainer.classList.add('grabbing');

                this.offsetX = e.clientX - this.bubbleContainer.getBoundingClientRect().left;
                this.offsetY = e.clientY - this.bubbleContainer.getBoundingClientRect().top;
            });

            document.addEventListener('mousemove', (e) => {
                if (!this.isDragging) return;

                let newLeft = e.clientX - this.offsetX;
                let newTop = e.clientY - this.offsetY;

                const maxX = window.innerWidth - this.bubbleContainer.offsetWidth;
                const maxY = window.innerHeight - this.bubbleContainer.offsetHeight;

                newLeft = Math.max(0, Math.min(newLeft, maxX));
                newTop = Math.max(0, Math.min(newTop, maxY));

                this.bubbleContainer.style.left = `${newLeft}px`;
                this.bubbleContainer.style.top = `${newTop}px`;
                this.bubbleContainer.style.right = 'auto'; // left/top을 사용할 때는 기존 right/bottom 속성을 초기화
                this.bubbleContainer.style.bottom = 'auto'; // left/top을 사용할 때는 기존 right/bottom 속성을 초기화
            });

            document.addEventListener('mouseup', () => {
                this.isDragging = false;
                this.bubbleContainer.classList.remove('grabbing');
                this._savePosition(); // 드래그가 끝나면 위치를 저장합니다.
            });
        }

        /**
         * @private
         * AI 목록 표시/숨김 호버 기능을 설정합니다.
         * 마우스가 버블 위에 있을 때 메뉴를 표시하고, 벗어났을 때 지연 후 숨깁니다.
         */
        _setupHover() {
            this.bubbleContainer.addEventListener('mouseenter', () => {
                clearTimeout(this.hideTimeout);
                this.siteOptions.classList.add('visible');
            });

            this.bubbleContainer.addEventListener('mouseleave', () => {
                this.hideTimeout = setTimeout(() => {
                    this.siteOptions.classList.remove('visible');
                }, BubbleConfig.MENU_HIDE_DELAY);
            });
        }

        /**
         * @private
         * AI 사이트 옵션 클릭 기능을 설정합니다.
         * AI 목록에서 특정 AI 사이트를 클릭하면 새 팝업 창으로 해당 사이트를 엽니다.
         */
        _setupClick() {
            this.siteOptions.addEventListener('click', (event) => {
                const option = event.target.closest('.ai-option');
                if (option) {
                    let url = option.dataset.url;
                    if (url) {
                        url += (url.includes('?') ? '&' : '?') + 'bubble_popup=true';

                        const windowName = 'AIFloatingWindow';
                        const features = `width=${BubbleConfig.POPUP_WINDOW_WIDTH},height=${BubbleConfig.POPUP_WINDOW_HEIGHT},menubar=no,toolbar=no,location=no,status=no,resizable=yes,scrollbars=yes`;

                        window.open(url, windowName, features);
                    }
                }
            });
        }

        /**
         * @private
         * 버블의 현재 위치(left, top)를 localStorage에 저장합니다.
         */
        _savePosition() {
            const position = {
                left: this.bubbleContainer.offsetLeft,
                top: this.bubbleContainer.offsetTop
            };
            localStorage.setItem('aiFloatingBubblePosition', JSON.stringify(position));
        }

        /**
         * @private
         * localStorage에서 저장된 버블 위치를 불러와 적용합니다.
         * 저장된 위치가 없으면 기본 위치(우측 하단)를 설정합니다.
         */
        _loadPosition() {
            const savedPosition = localStorage.getItem('aiFloatingBubblePosition');
            if (savedPosition) {
                const position = JSON.parse(savedPosition);
                this.bubbleContainer.style.left = `${position.left}px`;
                this.bubbleContainer.style.top = `${position.top}px`;
                this.bubbleContainer.style.right = 'auto'; // 기존 right/bottom 초기화
                this.bubbleContainer.style.bottom = 'auto'; // 기존 right/bottom 초기화
            } else {
                // 저장된 위치가 없으면 기본 위치 설정
                this.bubbleContainer.style.bottom = `${BubbleConfig.OPTION_ITEM_PADDING_VERTICAL * 2}px`;
                this.bubbleContainer.style.right = `${BubbleConfig.OPTION_ITEM_PADDING_HORIZONTAL}px`;
            }
        }
    }

    // 스크립트 실행 시 AI 플로팅 버블 인스턴스를 생성하여 모든 기능을 시작합니다.
    new AIFloatingBubble();
})();