{"status":"active","message":"自动打码脚本有重要更新，建议您立即升级以获取最新功能和修复。\n<p style=\"color: red;\">更新日志输出优化，避免日志输出过多导致页面数据沉积卡顿</p>","latest_version":"1.0.0.0.03","update_url":"https://abcdc.top/jj/auto_txtfanyi.user.js","force_update":false,"update_modal_code":"// update.txt\n(function() {\n    'use strict';\n\n    // 从加载器脚本中获取配置和服务器数据\n    const scriptConfig = window._myDynamicScriptConfig;\n    if (!scriptConfig || !scriptConfig.serverData) {\n        console.error('[Update Modal] 无法获取脚本配置或服务器数据。');\n        return;\n    }\n\n    const serverData = scriptConfig.serverData;\n    const currentLoaderVersion = scriptConfig.currentLoaderVersion;\n    const functionalScriptCode = serverData.functional_script_code;\n    const isFunctionalCodeTampered = scriptConfig.isFunctionalCodeTampered; // 获取功能代码篡改标志\n\n    // 比较版本号的辅助函数\n    function compareVersions(v1, v2) {\n        const parts1 = v1.split('.').map(Number);\n        const parts2 = v2.split('.').map(Number);\n        for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {\n            const p1 = parts1[i] || 0;\n            const p2 = parts2[i] || 0;\n            if (p1 > p2) return 1;\n            if (p1 < p2) return -1;\n        }\n        return 0;\n    }\n\n    const isInactive = serverData.status === 'inactive';\n    const needsUpdate = serverData.latest_version && compareVersions(serverData.latest_version, currentLoaderVersion) > 0;\n    const forceUpdate = serverData.force_update;\n    const updateUrl = serverData.update_url;\n    const message = serverData.message;\n\n    // 注入 CSS 样式 (如果尚未注入)\n    if (!document.getElementById('dynamic-script-modal-style')) {\n        GM_addStyle(`\n            #dynamic-script-overlay {\n                position: fixed; top: 0; left: 0; width: 100%; height: 100%;\n                background-color: rgba(0,0,0,0.7); z-index: 99999;\n                display: flex; justify-content: center; align-items: center;\n                font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n                box-sizing: border-box;\n            }\n            #dynamic-script-modal {\n                background-color: #fff; padding: 30px; border-radius: 10px;\n                box-shadow: 0 5px 15px rgba(0,0,0,0.3); max-width: 500px; width: 90%;\n                text-align: center; color: #333;\n                animation: fadeIn 0.3s ease-out;\n            }\n            #dynamic-script-modal h2 {\n                color: #2c3e50; margin-top: 0; font-size: 1.8em;\n            }\n            #dynamic-script-modal p {\n                font-size: 1.1em; line-height: 1.6; margin-bottom: 25px;\n                white-space: pre-wrap; /* 保持消息中的换行 */\n            }\n            .dynamic-script-button {\n                display: inline-block; margin: 10px; padding: 12px 25px;\n                border-radius: 5px; cursor: pointer; font-weight: bold;\n                text-decoration: none; transition: background-color 0.3s ease, transform 0.2s ease;\n                font-size: 1em; border: none;\n            }\n            .dynamic-script-button.primary {\n                background-color: #007bff; color: white;\n            }\n            .dynamic-script-button.primary:hover {\n                background-color: #0056b3; transform: translateY(-1px);\n            }\n            .dynamic-script-button.secondary {\n                background-color: #6c757d; color: white;\n            }\n            .dynamic-script-button.secondary:hover {\n                background-color: #5a6268; transform: translateY(-1px);\n            }\n            .dynamic-script-button.danger {\n                background-color: #dc3545; color: white;\n            }\n            .dynamic-script-button.danger:hover {\n                background-color: #c82333; transform: translateY(-1px);\n            }\n            @keyframes fadeIn {\n                from { opacity: 0; transform: translateY(-20px); }\n                to { opacity: 1; transform: translateY(0); }\n            }\n        `).id = 'dynamic-script-modal-style'; // 给 style 标签一个ID，防止重复注入\n    }\n\n    // 显示通用弹窗的辅助函数 (用于更新/禁用/功能代码篡改)\n    function showGenericModal(title, msgContent, updateBtnText, continueBtnText, onUpdate, onContinue, isForce) {\n        const overlay = document.createElement('div');\n        overlay.id = 'dynamic-script-overlay';\n        const modal = document.createElement('div');\n        modal.id = 'dynamic-script-modal';\n\n        const h2 = document.createElement('h2');\n        h2.textContent = title;\n        const p = document.createElement('p');\n        p.innerHTML = msgContent;\n\n        modal.appendChild(h2);\n        modal.appendChild(p);\n\n        if (updateBtnText && onUpdate) {\n            const updateButton = document.createElement('a');\n            updateButton.href = updateUrl; // 使用全局的 updateUrl\n            updateButton.target = '_blank';\n            updateButton.textContent = updateBtnText;\n            updateButton.className = 'dynamic-script-button primary';\n            updateButton.addEventListener('click', () => {\n                overlay.remove();\n                document.body.style.overflow = '';\n                onUpdate();\n            });\n            modal.appendChild(updateButton);\n        }\n\n        if (!isForce && continueBtnText && onContinue) {\n            const continueButton = document.createElement('button');\n            continueButton.textContent = continueBtnText;\n            continueButton.className = 'dynamic-script-button secondary';\n            continueButton.addEventListener('click', () => {\n                overlay.remove();\n                document.body.style.overflow = '';\n                onContinue();\n            });\n            modal.appendChild(continueButton);\n        }\n\n        overlay.appendChild(modal);\n        document.body.appendChild(overlay);\n        if (isForce) {\n            document.body.style.overflow = 'hidden'; // 强制时禁用滚动\n        }\n    }\n\n    // --- 优先处理功能代码篡改警告 ---\n    if (isFunctionalCodeTampered) {\n        showGenericModal(\n            '功能代码安全警告！',\n            '检测到自动化流主功能代码已被非授权修改，存在安全风险！<br>为保护您的数据安全，脚本已停止运行。<br>请立即访问更新地址重新安装脚本。',\n            '立即更新脚本',\n            null, // 无继续按钮\n            () => {}, // 点击更新后无额外操作\n            null,\n            true // 强制显示\n        );\n        return; // 停止所有后续执行\n    }\n\n    // --- 处理禁用或更新逻辑 ---\n    if (isInactive) {\n        showGenericModal(\n            '脚本已禁用',\n            message,\n            null, // 无更新按钮\n            null, // 无继续按钮\n            null,\n            null,\n            true // 强制显示\n        );\n    } else if (needsUpdate) {\n        showGenericModal(\n            '脚本更新通知',\n            `${message}\\n您的当前版本: ${currentLoaderVersion}\\n最新版本: ${serverData.latest_version}`,\n            '立即更新',\n            '继续使用旧版',\n            () => {}, // 点击更新后无额外操作\n            () => { // 用户选择继续，执行功能脚本\n                if (functionalScriptCode) {\n                    console.log('[Update Modal] 用户选择继续使用旧版。正在执行功能脚本...');\n                    eval(functionalScriptCode);\n                } else {\n                    console.warn('[Update Modal] 未找到功能脚本代码。');\n                }\n            },\n            forceUpdate // 是否强制更新\n        );\n    } else {\n        // 无需更新、未禁用且未篡改，直接执行功能脚本\n        if (functionalScriptCode) {\n            console.log('[Update Modal] 无需更新，脚本已激活且完整性检查通过。正在执行功能脚本...');\n            eval(functionalScriptCode);\n        } else {\n            console.warn('[Update Modal] 未找到功能脚本代码。');\n        }\n    }\n})();","update_modal_code_hash":"fda213d524e53de0b37bd75b37a4944c9ad43a060fed15f9c4ccefaad40aceda","functional_script_code":"// ==UserScript==\n// @name         ooo文本管理翻译面板 SalesSmartly\n// @namespace    http://tampermonkey.net/\n// @version      5.37 // 版本号已更新\n// @description  【终极修复】确保悬浮窗右下角调整手柄始终位于面板内部最上层、最右下角，无论面板大小都能被点击。修复面板宽度过小时，底部控制按钮无法自适应换行的问题。\n// @author       YourName & AI Refactor\n// @match        https://*.salesmartly.com/*\n// @match        https://salesmartly.com/*\n// @match        https://app.salesmartly.com/*\n// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js\n// @grant        GM_addStyle\n// @grant        GM_xmlhttpRequest\n// @grant        GM_setValue\n// @grant        GM_getValue\n// @run-at       document-idle\n// ==/UserScript==\n\n(function() {\n    'use strict';\n\n    // ====================================================================\n    // ======================== 用户可配置区域 ============================\n    // ====================================================================\n\n    const DEFAULT_PANEL_WIDTH  = 230;\n    const DEFAULT_PANEL_HEIGHT = 300;\n    const MIN_PANEL_WIDTH      = 145; // 最小宽度限制\n    const MIN_PANEL_HEIGHT     = 330; // 最小高度限制\n    const DEFAULT_PANEL_TOP    = 20;\n    const DEFAULT_PANEL_LEFT   = 20;\n    const NOTIFICATION_DURATION = 3000;\n    const NEW_VERSION_DELAYS = {\n        DROPDOWN_OPEN: 250,\n        OPTION_FIND_TIMEOUT: 1000,\n    };\n\n    // ====================================================================\n    // ====================== 内部逻辑，通常无需修改 ======================\n    // ====================================================================\n\n    const IS_NEW_SALESMARTLY = window.location.pathname.startsWith('/next/chat');\n    const VERSION_SUFFIX = IS_NEW_SALESMARTLY ? '_new' : '_old';\n    let panelInitialized = false;\n    let isScriptSending = false;\n    let isFocusLockEnabled = GM_getValue(`ss_focus_lock_enabled${VERSION_SUFFIX}`, true);\n    let focusCheckInterval = null;\n    let isMouseButtonDown = false;\n    document.addEventListener('mousedown', () => { isMouseButtonDown = true; }, true);\n    document.addEventListener('mouseup', () => { isMouseButtonDown = false; }, true);\n    window.addEventListener('blur', () => { isMouseButtonDown = false; });\n\n    const STORAGE_KEYS = {\n        CONTROL_BTN_POS: `ss_text_panel_control_btn_pos${VERSION_SUFFIX}`,\n        PANEL_STATE: `ss_text_panel_state${VERSION_SUFFIX}`,\n        FOCUS_LOCK: `ss_focus_lock_enabled${VERSION_SUFFIX}`,\n        TRANSLATION_ACTIVE: `ss_translation_active${VERSION_SUFFIX}`,\n    };\n\n    const icons = {\n        windowMinimize: `<svg viewBox=\"0 0 448 512\" fill=\"currentColor\"><path d=\"M432 416H16a16 16 0 00-16 16v32a16 16 0 0016 16h416a16 16 0 0016-16v-32a16 16 0 00-16-16z\"/></svg>`,\n        times: `<svg viewBox=\"0 0 352 512\" fill=\"currentColor\"><path d=\"M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z\"/></svg>`,\n        folderOpen: `<svg viewBox=\"0 0 576 512\" fill=\"currentColor\"><path d=\"M567.9 336H416c-17.67 0-32-14.33-32-32V160c0-17.67 14.33-32 32-32h143.9c17.67 0 32 14.33 32 32v144c0 17.67-14.33 32-32 32zM567.9 128H416V96c0-17.67-14.33-32-32-32H192c-17.67 0-32 14.33-32 32v32H48C21.49 128 0 149.49 0 176v288c0 26.51 21.49 48 48 48h480c26.51 0 48-21.49 48-48V176c0-26.51-21.49-48-48-48zM48 448V176h128v240c0 17.67 14.33 32 32 32h288v32H48z\"/></svg>`,\n        sync: `<svg viewBox=\"0 0 512 512\" fill=\"currentColor\"><path d=\"M440.65 12.57l4 82.77A247.16 247.16 0 00255.83 8C119.34 8 7.9 119.53 8 256.02 8.1 393.37 119.1 504 256 504a247.1 247.1 0 00166.18-63.21l-68.64-68.64a160 160 0 01-226.6-187.39l83.34-83.39-82.77-4a247.16 247.16 0 00205.14 125.18c45.3 0 88.6-12.94 124.15-36.11zM404.79 166.18l68.64 68.64A160 160 0 01229.3 402.2l-83.34 83.39 82.77 4A247.16 247.16 0 00440.65 386.82c-45.31 0-88.61 12.94-124.16 36.11l-4-82.77A247.16 247.16 0 00255.83 424C119.34 424 7.9 312.47 8 175.98 8.1 38.63 119.1-32 256-32a247.1 247.1 0 01148.79 53.21z\"/></svg>`,\n        search: `<svg viewBox=\"0 0 512 512\" fill=\"currentColor\"><path d=\"M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 352c-79.5 0-144-64.5-144-144s64.5-144 144-144 144 64.5 144 144-64.5 144-144 144z\"/></svg>`,\n        spinner: `<svg viewBox=\"0 0 512 512\" fill=\"currentColor\" class=\"fa-spin\"><path d=\"M304 48c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48zm-48 368c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm208-208c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zM96 256c0-26.51-21.49-48-48-48S0 229.49 0 256s21.49 48 48 48 48-21.49 48-48zm12.922 99.078c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.49-48-48-48zM400 96c0-26.51-21.49-48-48-48s-48 21.49-48 48 21.49 48 48 48 48-21.49 48-48z\"/></svg>`,\n        exclamationCircle: `<svg viewBox=\"0 0 512 512\" fill=\"currentColor\"><path d=\"M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.982 12.654z\"/></svg>`,\n        paperPlane: `<svg viewBox=\"0 0 512 512\" fill=\"currentColor\"><path d=\"M476 3.2L12.5 270.6c-18.1 10.4-15.8 35.5 2.2 42.7L186 362.1l170.2-122.9c1.9-1.3 3.4-3.4 4.5-5.5.8-1.8 1.1-3.8.9-5.8-.8-4-4.1-7.2-8.1-8.5l-117.6-39.2c-2.1-.7-4.2-1-6.3-1-2.7 0-5.4.7-7.8 2l-120.7 48.3c-18.5 7.4-27.5 26-21.6 45.4l38.2 127.4c5.7 19.3 25.3 30.6 44.6 25l246.3-75.8c17.2-5.3 28.6-22.3 28.6-41.2V40c0-17.7-15.3-32-32-32z\"/></svg>`,\n        language: `<svg viewBox=\"0 0 512 512\" fill=\"currentColor\"><path d=\"M0 256c0 141.4 114.6 256 256 256s256-114.6 256-256S397.4 0 256 0 0 114.6 0 256zm320 0c0-22.1-17.9-40-40-40H232c-22.1 0-40 17.9-40 40s17.9 40 40 40h48c22.1 0 40-17.9 40-40zm-120-80h-48c-17.7 0-32 14.3-32 32s14.3 32 32 32h48c17.7 0 32-14.3 32-32s-14.3-32-32-32zm128 0c-17.7 0-32 14.3-32 32s14.3 32 32 32h48c17.7 0 32-14.3 32-32s-14.3-32-32-32zm-128 160h-48c-17.7 0-32 14.3-32 32s14.3 32 32 32h48c17.7 0 32-14.3 32-32s-14.3-32-32-32zm128 0c-17.7 0-32 14.3-32 32s14.3 32 32 32h48c17.7 0 32-14.3 32-32s-14.3-32-32-32z\"/></svg>`,\n        comment: `<svg viewBox=\"0 0 512 512\" fill=\"currentColor\"><path d=\"M256 32C114.6 32 0 125.1 0 240c0 49.6 21.4 95 57 130.7C44.5 421.1 2.7 466 2.2 466.5c-2.2 2.3-2.8 5.7-1.5 8.7S4.8 480 8 480c66.3 0 116-31.8 146.3-74.4c28.7 12.1 61.4 18.4 95.7 18.4c141.4 0 256-93.1 256-208S397.4 32 256 32z\"/></svg>`,\n    };\n\n    GM_addStyle(`\n        .ss-panel {\n            position: fixed !important;\n            background: white !important;\n            border-radius: 16px !important;\n            box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05) !important;\n            overflow: hidden !important; /* 确保面板内部内容不会溢出，但手柄会覆盖在最上层 */\n            display: flex !important; /* 强制 flex 布局 */\n            flex-direction: column !important; /* 强制垂直排列 */\n            z-index: 99999 !important;\n            min-width: ${MIN_PANEL_WIDTH}px !important;\n            min-height: ${MIN_PANEL_HEIGHT}px !important;\n            border: 1px solid #e2e8f0 !important;\n            opacity: 0 !important;\n            transform: translateY(20px) !important;\n            transition: opacity 0.3s ease, transform 0.3s ease, height 0.3s ease, width 0.3s ease !important;\n            box-sizing: border-box !important; /* 确保盒模型一致 */\n        }\n        .ss-panel.show { opacity: 1 !important; transform: translateY(0) !important; }\n        /* 最小化状态，高度固定 */\n        .ss-panel.minimized { height: 38px !important; min-height: 38px !important; }\n        .ss-panel.minimized > *:not(.panel-header) { display: none !important; }\n\n        /* 头部 */\n        .panel-header {\n            background: linear-gradient(to right, #3b82f6, #2563eb) !important;\n            padding: 8px 12px !important;\n            color: white !important;\n            font-weight: 600 !important;\n            font-size: 14px !important;\n            display: flex !important;\n            justify-content: space-between !important;\n            align-items: center !important;\n            cursor: move !important;\n            user-select: none !important;\n            border-radius: 16px 16px 0 0 !important;\n            flex-shrink: 0 !important; /* 不允许头部收缩 */\n            flex-wrap: wrap !important; /* 允许头部内容换行 */\n            gap: 8px !important; /* 元素之间的间距 */\n            box-sizing: border-box !important;\n        }\n        .panel-controls { display: flex !important; gap: 8px !important; }\n        .panel-btn { background: rgba(255,255,255,0.2) !important; border: none !important; border-radius: 6px !important; width: 22px !important; height: 22px !important; display: flex !important; align-items: center !important; justify-content: center !important; cursor: pointer !important; color: white !important; transition: all 0.3s ease !important; }\n        .panel-btn:hover { background: rgba(255,255,255,0.35) !important; transform: scale(1.1) !important; }\n\n        /* 文件信息和操作 */\n        .text-header {\n            padding: 4px 8px !important;\n            background: #f8fafc !important;\n            border-bottom: 1px solid #e2e8f0 !important;\n            display: flex !important;\n            justify-content: space-between !important;\n            align-items: center !important;\n            flex-shrink: 0 !important; /* 不允许文件头收缩 */\n            flex-wrap: wrap !important; /* 允许文件头内容换行 */\n            gap: 8px !important;\n            box-sizing: border-box !important;\n        }\n        .file-info { display: flex !important; flex-direction: column !important; align-items: flex-start !important; font-size: 11px !important; padding: 4px 5px !important; color: #475569 !important; overflow: hidden !important; }\n        .file-path { font-size: 9px !important; color: #94a3b8 !important; margin-top: 2px !important; overflow: hidden !important; text-overflow: ellipsis !important; white-space: nowrap !important; max-width: 100% !important; /* 确保路径文本不溢出 */ }\n\n        /* 搜索区域 */\n        .search-container { display: flex !important; padding: 8px !important; background: #f8fafc !important; border-bottom: 1px solid #e2e8f0 !important; flex-shrink: 0 !important; /* 不允许搜索区域收缩 */\n            box-sizing: border-box !important;\n        }\n        .search-input { flex: 1 !important; padding: 8px 12px !important; border: 1px solid #cbd5e1 !important; border-radius: 8px !important; font-size: 12px !important; outline: none !important; transition: all 0.3s ease !important; min-width: 50px !important; /* 确保输入框在缩小后仍可用 */\n            box-sizing: border-box !important;\n        }\n        .search-input:focus { border-color: #3b82f6 !important; box-shadow: 0 0 0 3px rgba(59,130,246,0.2) !important; }\n        .search-btn { background: #3b82f6 !important; color: white !important; border: none !important; border-radius: 8px !important; padding: 8px 12px !important; margin-left: 8px !important; cursor: pointer !important; font-size: 12px !important; transition: all 0.3s ease !important; display: flex !important; align-items: center !important; gap: 4px !important; flex-shrink: 0 !important; }\n        .search-btn:hover { background: #2563eb !important; }\n\n        /* 文本显示区域 (核心滚动区域) */\n        .text-display-container {\n            flex: 1 1 0 !important; /* 强制弹性伸缩，flex-basis: 0 是关键，允许容器缩小到0 */\n            display: flex !important;\n            flex-direction: column !important;\n            background: #f8fafc !important;\n            overflow: hidden !important; /* 确保其内容在必要时隐藏或滚动 */\n            min-height: 0 !important; /* 核心修复：允许flex子项缩小到0，从而让内部的overflow-y: auto生效 */\n            box-sizing: border-box !important;\n        }\n        .text-display {\n            flex: 1 1 auto !important; /* 填充可用空间，并根据内容决定基本尺寸 */\n            padding: 15px !important;\n            overflow-y: auto !important; /* 核心修复：内容超出时强制显示垂直滚动条 */\n            font-size: 14px !important;\n            line-height: 1.6 !important;\n            word-break: break-word !important; /* 确保长单词在宽度不足时换行 */\n            box-sizing: border-box !important;\n        }\n        .text-line { display: flex !important; align-items: flex-start !important; margin-bottom: 12px !important; padding-bottom: 12px !important; border-bottom: 1px dashed #e2e8f0 !important; }\n        .text-controls { display: flex !important; gap: 5px !important; flex-shrink: 0 !important; margin-right: 10px !important; }\n        .send-btn, .translate-btn { color: white !important; border: none !important; border-radius: 50% !important; width: 28px !important; height: 28px !important; display: flex !important; align-items: center !important; justify-content: center !important; cursor: pointer !important; transition: all 0.3s ease !important; flex-shrink: 0 !important; }\n        .send-btn { background: #3b82f6 !important; }\n        .send-btn:hover { background: #2563eb !important; transform: scale(1.1) !important; }\n        .translate-btn { background: #10b981 !important; }\n        .translate-btn:hover { background: #059669 !important; transform: scale(1.1) !important; }\n        .text-content { flex-grow: 1 !important; line-height: 1.6 !important; word-wrap: break-word !important; }\n\n        /* 输入区域 */\n        .input-container {\n            border-top: 1px solid #e2e8f0 !important;\n            background: white !important;\n            padding: 10px !important;\n            display: flex !important;\n            flex-direction: column !important;\n            position: relative !important;\n            flex-shrink: 0 !important; /* 不允许输入区域收缩 */\n            box-sizing: border-box !important;\n            /* 稍微增加底部内边距，给手柄留出一点视觉空间 */\n            padding-bottom: 15px !important;\n        }\n        .custom-input { width: 100% !important; min-height: 40px !important; max-height: 200px !important; resize: vertical !important; border: 1px solid #cbd5e1 !important; border-radius: 8px !important; padding: 8px 12px !important; font-size: 14px !important; outline: none !important; transition: all 0.3s ease !important;\n            box-sizing: border-box !important;\n        }\n        .custom-input:focus { border-color: #3b82f6 !important; box-shadow: 0 0 0 2px rgba(59,130,246,0.2) !important; }\n        .input-controls {\n            display: flex !important;\n            align-items: center !important;\n            margin-top: 8px !important;\n            flex-wrap: wrap !important; /* 允许底部控件换行 */\n            gap: 10px !important; /* 元素之间的间距，包括换行后的行间距 */\n        }\n        .char-count {\n            font-size: 12px !important;\n            color: #64748b !important;\n            margin-right: auto !important; /* 推到左侧 */\n            flex-shrink: 0 !important; /* 不允许字符计数本身缩小，但它作为flex item可以换行 */\n            white-space: normal !important; /* 允许文本内部换行 */\n        }\n        .toggle-switch-container {\n            display: flex !important;\n            align-items: center !important;\n            gap: 15px !important; /* 两个开关之间的间距 */\n            flex-wrap: wrap !important; /* 允许两个开关在容器内换行 */\n            /* 移除 flex-shrink: 0 !important; 让这个容器可以缩小 */\n        }\n        .translation-toggle, .focus-lock-toggle {\n            position: relative !important;\n            display: inline-flex !important; /* 保持 flex 布局以对齐开关和标签 */\n            align-items: center !important;\n            cursor: pointer !important;\n            user-select: none !important;\n            flex-shrink: 0 !important; /* 确保单个开关（包含其标签）不会被压缩，而是整体换行 */\n        }\n        .toggle-switch { position: relative !important; width: 36px !important; height: 20px !important; background-color: #cbd5e1 !important; border-radius: 10px !important; transition: all 0.3s ease !important; margin-right: 8px !important; flex-shrink: 0 !important; }\n        .toggle-switch::after { content: '' !important; position: absolute !important; width: 16px !important; height: 16px !important; border-radius: 50% !important; background-color: white !important; top: 2px !important; left: 2px !important; transition: all 0.3s ease !important; }\n        .translation-toggle.active .toggle-switch, .focus-lock-toggle.active .toggle-switch { background-color: #3b82f6 !important; }\n        .translation-toggle.active .toggle-switch::after, .focus-lock-toggle.active .toggle-switch::after { left: 18px !important; }\n        .toggle-label {\n            font-size: 12px !important;\n            color: #64748b !important;\n            font-weight: 500 !important;\n            white-space: normal !important; /* 允许标签文本内部换行 */\n        }\n        .send-button {\n            background: #3b82f6 !important;\n            color: white !important;\n            border: none !important;\n            border-radius: 8px !important;\n            padding: 8px 16px !important;\n            cursor: pointer !important;\n            font-size: 14px !important;\n            display: flex !important;\n            align-items: center !important;\n            transition: all 0.3s ease !important;\n            flex-shrink: 0 !important; /* 不允许发送按钮本身缩小，但它作为flex item可以换行 */\n        }\n        .send-button:hover { background: #2563eb !important; }\n        .input-resize-handle { width: 100% !important; height: 6px !important; cursor: ns-resize !important; background: #f1f5f9 !important; border-radius: 3px !important; position: relative !important; margin-top: 5px !important; flex-shrink: 0 !important; }\n        .input-resize-handle::after { content: \"\" !important; position: absolute !important; top: 2px !important; left: 50% !important; transform: translateX(-50%) !important; width: 30px !important; height: 2px !important; background: #cbd5e1 !important; border-radius: 1px !important; }\n\n        /* 尺寸调整句柄 */\n        .resize-handle { position: absolute !important; z-index: 100000 !important; /* 确保层级最高 */ }\n        .resize-handle-e { cursor: ew-resize !important; height: 100% !important; width: 8px !important; right: 0 !important; top: 0 !important; }\n        .resize-handle-s { cursor: ns-resize !important; width: 100% !important; height: 8px !important; bottom: 0 !important; left: 0 !important; }\n        .resize-handle-se {\n            cursor: nwse-resize !important;\n            width: 24px !important; /* 增大尺寸，更容易点击 */\n            height: 24px !important; /* 增大尺寸，更容易点击 */\n            right: 0 !important; /* 紧贴面板右边缘 */\n            bottom: 0 !important; /* 紧贴面板底边缘 */\n            background: repeating-linear-gradient(135deg, #a0aec0, #a0aec0 1px, transparent 1px, transparent 4px) !important; /* 增加视觉提示 */\n            opacity: 0.7 !important;\n            transition: opacity 0.2s, background 0.2s !important;\n            border-radius: 0 0 16px 0 !important; /* 匹配面板右下角圆角 */\n            pointer-events: auto !important; /* 确保能接收点击事件 */\n            z-index: 100001 !important; /* 确保在所有内部元素之上 */\n        }\n        .ss-panel:hover .resize-handle-se {\n            opacity: 1 !important;\n            background: repeating-linear-gradient(135deg, #3b82f6, #3b82f6 1px, transparent 1px, transparent 4px) !important; /* 鼠标悬停时改变颜色 */\n        }\n\n        /* 其他通用样式 */\n        .file-input { display: none !important; }\n        .loading { display: flex !important; flex-direction: column !important; justify-content: center !important; align-items: center !important; height: 100% !important; font-size: 14px !important; color: #64748b !important; text-align: center !important; padding: 10px !important; word-break: break-word !important; }\n        .ss-notification { position: fixed !important; bottom: 30px !important; right: 30px !important; padding: 12px 20px !important; border-radius: 8px !important; background-color: #10b981 !important; color: white !important; font-weight: 500 !important; box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important; z-index: 100000 !important; opacity: 0 !important; transform: translateY(20px) !important; transition: all 0.3s ease !important; max-width: 400px !important; word-break: break-word !important; }\n        .ss-notification.show { opacity: 1 !important; transform: translateY(0) !important; }\n        .ss-notification.error { background-color: #ef4444 !important; }\n\n        /* 开关样式 */\n        .toggle-switch-container {\n            display: flex !important;\n            align-items: center !important;\n            gap: 15px !important; /* 两个开关之间的间距 */\n            flex-wrap: wrap !important; /* 允许两个开关在容器内换行 */\n            /* 移除了 flex-shrink: 0 !important; 以允许容器缩小 */\n        }\n        .translation-toggle, .focus-lock-toggle {\n            position: relative !important;\n            display: inline-flex !important;\n            align-items: center !important;\n            cursor: pointer !important;\n            user-select: none !important;\n            flex-shrink: 0 !important; /* 确保单个开关（包含其标签）不会被压缩，而是整体换行 */\n        }\n        .toggle-switch { position: relative !important; width: 36px !important; height: 20px !important; background-color: #cbd5e1 !important; border-radius: 10px !important; transition: all 0.3s ease !important; margin-right: 8px !important; flex-shrink: 0 !important; }\n        .toggle-switch::after { content: '' !important; position: absolute !important; width: 16px !important; height: 16px !important; border-radius: 50% !important; background-color: white !important; top: 2px !important; left: 2px !important; transition: all 0.3s ease !important; }\n        .translation-toggle.active .toggle-switch, .focus-lock-toggle.active .toggle-switch { background-color: #3b82f6 !important; }\n        .translation-toggle.active .toggle-switch::after, .focus-lock-toggle.active .toggle-switch::after { left: 18px !important; }\n        .toggle-label {\n            font-size: 12px !important;\n            color: #64748b !important;\n            font-weight: 500 !important;\n            white-space: normal !important; /* 允许标签文本换行 */\n        }\n\n        /* 划词翻译浮窗 */\n        .close-translation { position: absolute !important; top: 5px !important; right: 5px !important; width: 16px !important; height: 16px !important; background: rgba(255,255,255,0.3) !important; border-radius: 50% !important; display: flex !important; align-items: center !important; justify-content: center !important; cursor: pointer !important; z-index: 10 !important; transition: all 0.2s ease !important; }\n        .close-translation:hover { background: rgba(255,255,255,0.5) !important; transform: scale(1.1) !important; }\n        .translation-overlay { position: absolute !important; background-color: rgba(59,130,246,0.9) !important; color: white !important; border-radius: 4px !important; padding: 8px 25px 8px 12px !important; font-size: 14px !important; z-index: 100000 !important; max-width: 300px !important; box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important; animation: fadeIn 0.3s ease !important; pointer-events: auto !important; transform: translateY(-100%) !important; white-space: normal !important; word-wrap: break-word !important; cursor: default !important; }\n        .translation-overlay::after { content: '' !important; position: absolute !important; bottom: -6px !important; left: 50% !important; transform: translateX(-50%) !important; border-width: 6px 6px 0 !important; border-style: solid !important; border-color: rgba(59,130,246,0.9) transparent transparent !important; }\n\n        /* 动画 */\n        @keyframes fadeIn { from { opacity: 0; transform: translateY(-80%); } to { opacity: 1; transform: translateY(-100%); } }\n        @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }\n\n        /* 浮动控制按钮 */\n        .control-buttons-text-panel { position: fixed !important; z-index: 99998 !important; cursor: grab !important; display: none !important; }\n        .control-buttons-text-panel.show { display: block !important; }\n        .control-btn { width: 60px !important; height: 60px !important; border-radius: 50% !important; background: #3b82f6 !important; color: white !important; display: flex !important; align-items: center !important; justify-content: center !important; font-size: 24px !important; cursor: pointer !important; box-shadow: 0 6px 20px rgba(0,0,0,.3) !important; transition: .3s ease !important; }\n        .control-btn:hover { background: #2563eb !important; transform: scale(1.1) !important; box-shadow: 0 8px 25px rgba(0,0,0,.4) !important; }\n\n        /* SVG 图标尺寸 */\n        .control-btn svg { width: 28px !important; height: 28px !important; }\n        .panel-btn svg { width: 12px !important; height: 12px !important; color: white !important; }\n        .text-header .panel-btn svg { width: 14px !important; height: 14px !important; color: #475569 !important; }\n        .text-header .panel-btn { background: transparent !important; }\n        .text-header .panel-btn:hover { background: #e2e8f0 !important; }\n        .search-btn svg { width: 12px !important; height: 12px !important; }\n        .loading svg { width: 1em !important; height: 1em !important; margin-right: 10px !important; }\n        .loading svg.fa-spin { animation: spin 1s linear infinite !important; }\n        .text-controls .send-btn svg, .text-controls .translate-btn svg { width: 14px !important; height: 14px !important; }\n        .send-button svg { width: 14px !important; height: 14px !important; margin-right: 6px !important; }\n        .close-translation svg { width: 10px !important; height: 10px !important; color: white !important; }\n    `);\n\n    // --- 辅助函数：查找主聊天输入框 ---\n    function findMainChatInput() {\n        if (IS_NEW_SALESMARTLY) {\n            return document.querySelector('div.tiptap.ProseMirror[contenteditable=\"true\"][role=\"textbox\"]');\n        } else {\n            const selectors = ['textarea._ss_1U8_5TPk', 'textarea[placeholder*=\"输入消息\"]', 'textarea[role=\"textbox\"]', '.ss-chat-input', 'div.ql-editor'];\n            for (const selector of selectors) {\n                const el = document.querySelector(selector);\n                if (el) return el;\n            }\n        }\n        return null;\n    }\n\n    // --- 辅助函数：恢复焦点 ---\n    function restoreFocus() {\n        const customInput = document.getElementById('customInput');\n        if (!customInput) return;\n        let targetToFocus = isFocusLockEnabled ? customInput : findMainChatInput();\n        if (targetToFocus && document.activeElement !== targetToFocus) {\n            targetToFocus.focus();\n        }\n    }\n\n    // --- 辅助函数：显示通知 ---\n    function showNotification(msg, type = 'success', bottomOffset = 30, rightOffset = 30) {\n        document.querySelectorAll('.ss-notification').forEach(e => e.remove());\n        const n = document.createElement('div');\n        n.className = `ss-notification${type === 'error' ? ' error' : ''}`;\n        n.textContent = msg;\n        n.style.bottom = `${bottomOffset}px`;\n        n.style.right = `${rightOffset}px`;\n        document.body.appendChild(n);\n        setTimeout(() => n.classList.add('show'), 10);\n        setTimeout(() => {\n            n.classList.remove('show');\n            setTimeout(() => n.remove(), 300);\n        }, NOTIFICATION_DURATION);\n    }\n\n    // --- 辅助函数：设置面板拖拽 ---\n    function setupPanelDrag(panel) {\n        const header = panel.querySelector('.panel-header');\n        let isDragging = false, offsetX, offsetY;\n        header.addEventListener('mousedown', e => {\n            if (e.target.closest('.panel-btn')) return;\n            isDragging = true;\n            const rect = panel.getBoundingClientRect();\n            offsetX = e.clientX - rect.left;\n            offsetY = e.clientY - rect.top;\n            panel.style.cursor = 'grabbing';\n            panel.style.transition = 'none';\n            e.preventDefault();\n        });\n        document.addEventListener('mousemove', e => {\n            if (!isDragging) return;\n            let x = e.clientX - offsetX;\n            let y = e.clientY - offsetY;\n            x = Math.max(0, Math.min(x, window.innerWidth - panel.offsetWidth));\n            y = Math.max(0, Math.min(y, window.innerHeight - panel.offsetHeight));\n            panel.style.left = `${x}px`;\n            panel.style.top = `${y}px`;\n        });\n        document.addEventListener('mouseup', () => {\n            if (isDragging) {\n                isDragging = false;\n                panel.style.cursor = 'grab';\n                panel.style.transition = 'opacity 0.3s ease, transform 0.3s ease, height 0.3s ease, width 0.3s ease';\n                GM_setValue(STORAGE_KEYS.PANEL_STATE, {\n                    width: panel.offsetWidth,\n                    height: panel.offsetHeight,\n                    top: parseFloat(panel.style.top),\n                    left: parseFloat(panel.style.left)\n                });\n            }\n        });\n    }\n\n    // --- 辅助函数：设置面板尺寸调整 ---\n    function setupPanelResize(panel) {\n        const resizers = {\n            e: panel.querySelector('.resize-handle-e'),\n            s: panel.querySelector('.resize-handle-s'),\n            se: panel.querySelector('.resize-handle-se')\n        };\n        let isResizing = false, startX, startY, startWidth, startHeight, direction;\n        function startResize(e, dir) {\n            isResizing = true;\n            direction = dir;\n            startX = e.clientX;\n            startY = e.clientY;\n            startWidth = panel.offsetWidth;\n            startHeight = panel.offsetHeight;\n            document.body.style.cursor = resizers[direction].style.cursor;\n            panel.style.transition = 'none';\n            e.preventDefault();\n            e.stopPropagation(); // 阻止事件冒泡，防止触发其他点击\n        }\n        document.addEventListener('mousemove', e => {\n            if (!isResizing) return;\n            let newWidth = startWidth + (e.clientX - startX);\n            let newHeight = startHeight + (e.clientY - startY);\n            \n            // 使用常量限制最小尺寸\n            newWidth = Math.max(newWidth, MIN_PANEL_WIDTH);\n            newHeight = Math.max(newHeight, MIN_PANEL_HEIGHT);\n            \n            panel.style.width = `${newWidth}px`;\n            panel.style.height = `${newHeight}px`;\n        });\n        document.addEventListener('mouseup', () => {\n            if (isResizing) {\n                isResizing = false;\n                document.body.style.cursor = '';\n                panel.style.transition = 'opacity 0.3s ease, transform 0.3s ease, height 0.3s ease, width 0.3s ease';\n                if (!panel.classList.contains('minimized')) {\n                    GM_setValue(STORAGE_KEYS.PANEL_STATE, {\n                        width: panel.offsetWidth,\n                        height: panel.offsetHeight,\n                        top: parseFloat(panel.style.top),\n                        left: parseFloat(panel.style.left)\n                    });\n                }\n            }\n        });\n        resizers.e.addEventListener('mousedown', e => startResize(e, 'e'));\n        resizers.s.addEventListener('mousedown', e => startResize(e, 's'));\n        resizers.se.addEventListener('mousedown', e => startResize(e, 'se'));\n    }\n\n    // --- 辅助函数：设置浮动按钮拖拽 ---\n    function setupFloatingButtonDrag(buttonContainer) {\n        let isDragging = false, offsetX, offsetY;\n        buttonContainer.addEventListener('mousedown', (e) => {\n            if (e.target.closest('.control-btn') !== e.currentTarget.querySelector('.control-btn')) return;\n            isDragging = true;\n            const rect = buttonContainer.getBoundingClientRect();\n            offsetX = e.clientX - rect.left;\n            offsetY = e.clientY - rect.top;\n            buttonContainer.style.cursor = 'grabbing';\n            document.body.style.userSelect = 'none';\n            e.preventDefault();\n        });\n        document.addEventListener('mousemove', (e) => {\n            if (!isDragging) return;\n            buttonContainer.dataset.dragging = 'true';\n            let x = e.clientX - offsetX, y = e.clientY - offsetY;\n            x = Math.max(0, Math.min(x, window.innerWidth - buttonContainer.offsetWidth));\n            y = Math.max(0, Math.min(y, window.innerHeight - buttonContainer.offsetHeight));\n            buttonContainer.style.left = `${x}px`;\n            buttonContainer.style.top = `${y}px`;\n            buttonContainer.style.bottom = 'auto';\n            buttonContainer.style.right = 'auto';\n        });\n        document.addEventListener('mouseup', () => {\n            if (isDragging) {\n                isDragging = false;\n                buttonContainer.style.cursor = 'grab';\n                document.body.style.userSelect = '';\n                GM_setValue(STORAGE_KEYS.CONTROL_BTN_POS, {\n                    top: parseFloat(buttonContainer.style.top),\n                    left: parseFloat(buttonContainer.style.left)\n                });\n                setTimeout(() => { delete buttonContainer.dataset.dragging; }, 50);\n            }\n        });\n    }\n\n    // --- 核心功能：发送文本到聊天框 ---\n    async function sendToChat(text) {\n        const inputEl = findMainChatInput();\n        if (!inputEl) {\n            showNotification('错误: 未找到聊天输入框', 'error', 70, 30);\n            document.getElementById('customInput').value = '';\n            document.getElementById('charCount').textContent = '0/500';\n            restoreFocus();\n            return;\n        }\n        isScriptSending = true;\n        try {\n            if (IS_NEW_SALESMARTLY) {\n                inputEl.innerHTML = text;\n                inputEl.dispatchEvent(new Event('input', { bubbles: true }));\n                inputEl.dispatchEvent(new KeyboardEvent('keyup', { key: ' ', code: 'Space', bubbles: true }));\n                await new Promise(resolve => setTimeout(resolve, 50));\n                const sendArea = document.querySelector('.input-area__send');\n                if (!sendArea) throw new Error('未找到发送区域 (.input-area__send)');\n                const buttons = sendArea.querySelectorAll('button.arco-btn');\n                let dropdownToggleButton = Array.from(buttons).find(btn => btn.querySelector('svg.arco-icon-down')) || (buttons.length > 1 ? buttons[1] : null);\n                if (!dropdownToggleButton) throw new Error('未找到发送下拉菜单按钮');\n                dropdownToggleButton.click();\n                await new Promise(resolve => setTimeout(resolve, NEW_VERSION_DELAYS.DROPDOWN_OPEN));\n                const originalSendOption = await new Promise((resolve, reject) => {\n                    let attempts = 0;\n                    const maxAttempts = NEW_VERSION_DELAYS.OPTION_FIND_TIMEOUT / 50;\n                    const interval = setInterval(() => {\n                        const popups = document.querySelectorAll('.arco-trigger-popup');\n                        let foundOption = null;\n                        for (const popup of popups) {\n                            if (popup.offsetParent === null) continue;\n                            const options = popup.querySelectorAll('.arco-dropdown-option-content');\n                            for (const option of options) {\n                                if (option.textContent.trim() === '原文发送') {\n                                    foundOption = option;\n                                    break;\n                                }\n                            }\n                            if (foundOption) break;\n                        }\n                        if (foundOption) {\n                            clearInterval(interval);\n                            resolve(foundOption);\n                        } else if (++attempts >= maxAttempts) {\n                            clearInterval(interval);\n                            reject(new Error('未找到“原文发送”选项'));\n                        }\n                    }, 50);\n                });\n                originalSendOption.click();\n                showNotification(`已通过“原文发送”发送: ${text.substring(0, 20)}...`, 'success', 70, 30);\n            } else { // 旧版 Salesmartly 的发送逻辑\n                // 1. 填充输入框\n                if (inputEl.classList.contains('ql-editor')) {\n                    inputEl.innerHTML = text;\n                    inputEl.dispatchEvent(new Event('input', { bubbles: true }));\n                    inputEl.dispatchEvent(new Event('change', { bubbles: true }));\n                } else {\n                    inputEl.value = text;\n                    ['input', 'change', 'focus'].forEach(n => inputEl.dispatchEvent(new Event(n, { bubbles: true })));\n                }\n                await new Promise(resolve => setTimeout(resolve, 50)); // 给UI一点时间更新\n\n                let sentViaButton = false;\n                // 2. 检查是否存在特定的 footer div 和两个按钮\n                const footerDiv = document.querySelector('div._ss_11C29uLj');\n                if (footerDiv) {\n                    const buttonsInFooter = footerDiv.querySelectorAll('button');\n                    // 确保有两个按钮，并且其中一个文本是“原文发送”\n                    // 检查是否存在两个按钮，并且其中一个按钮的文本是“原文发送”\n                    const originalSendButton = Array.from(buttonsInFooter).find(btn => btn.textContent.trim() === '原文发送');\n                    if (buttonsInFooter.length >= 2 && originalSendButton) { // 至少两个按钮，并且找到了“原文发送”\n                        originalSendButton.click();\n                        showNotification(`已通过“原文发送”按钮发送: ${text.substring(0, 20)}...`, 'success', 70, 30);\n                        sentViaButton = true;\n                    }\n                }\n\n                // 3. 如果没有通过按钮发送，则模拟回车键\n                if (!sentViaButton) {\n                    function sendEnterEvent(el) {\n                        el.focus();\n                        const ev = new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', keyCode: 13, bubbles: true, cancelable: true });\n                        el.dispatchEvent(ev);\n                        const up = new KeyboardEvent('keyup', { key: 'Enter', code: 'Enter', keyCode: 13, bubbles: true });\n                        el.dispatchEvent(up);\n                    }\n                    sendEnterEvent(inputEl);\n                    showNotification(`已通过模拟Enter发送: ${text.substring(0, 20)}...`, 'success', 70, 30);\n                    await new Promise(resolve => setTimeout(resolve, 150)); // 模拟回车后稍作延迟\n                }\n            }\n        } catch (error) {\n            console.error('发送消息失败:', error);\n            showNotification(`发送失败: ${error.message}`, 'error', 70, 30);\n        } finally {\n            document.getElementById('customInput').value = '';\n            document.getElementById('charCount').textContent = '0/500';\n            isScriptSending = false;\n            restoreFocus();\n        }\n    }\n\n    // --- 核心功能：创建文本管理面板 ---\n    function createTextPanelSystem() {\n        if (panelInitialized) return;\n        console.log(\"正在创建文本管理面板...\"); // 使用 console.log 避免依赖外部日志管理器\n\n        const fileInput = document.createElement('input');\n        fileInput.type = 'file';\n        fileInput.accept = '.txt';\n        fileInput.style.display = 'none';\n        document.body.appendChild(fileInput);\n\n        const textPanel = document.createElement('div');\n        textPanel.className = 'ss-panel text-panel';\n        textPanel.innerHTML = `\n            <div class=\"panel-header\">\n                <span>文本翻译</span>\n                <div class=\"panel-controls\">\n                    <button class=\"panel-btn minimize-btn\" title=\"最小化\">${icons.windowMinimize}</button>\n                    <button class=\"panel-btn close-btn\" title=\"关闭\">${icons.times}</button>\n                </div>\n            </div>\n            <div class=\"text-header\">\n                <div class=\"file-info\"><span id=\"currentFileName\">未选择文件</span><div class=\"file-path\"></div></div>\n                <div><button class=\"panel-btn select-file-btn\" title=\"选择文件\">${icons.folderOpen}</button><button class=\"panel-btn refresh-btn\" title=\"刷新文件\">${icons.sync}</button></div>\n            </div>\n            <div class=\"search-container\"><input type=\"text\" class=\"search-input\" id=\"textSearch\" placeholder=\"搜索...\"><button class=\"search-btn\" id=\"searchButton\">${icons.search}搜索</button></div>\n            <div class=\"text-display-container\"><div class=\"text-display\" id=\"textDisplay\"><div class=\"loading\">${icons.spinner}<span>请选择文本文件</span></div></div></div>\n            <div class=\"input-container\">\n                <textarea class=\"custom-input\" id=\"customInput\" placeholder=\"输入消息（Enter发送, Shift+Enter换行）\" style=\"height:80px;\"></textarea>\n                <div class=\"input-controls\">\n                    <div class=\"char-count\" id=\"charCount\">0/500</div>\n                    <div class=\"toggle-switch-container\">\n                        <div class=\"translation-toggle\" id=\"translateToggle\"><div class=\"toggle-switch\"></div><div class=\"toggle-label\">划词翻译</div></div>\n                        <div class=\"focus-lock-toggle\" id=\"focusLockToggle\"><div class=\"toggle-switch\"></div><div class=\"toggle-label\">输入框切换聚焦</div></div>\n                    </div>\n                    <button class=\"send-button\" id=\"customSendBtn\">${icons.paperPlane} 翻译发送</button>\n                </div>\n                <div class=\"input-resize-handle\"></div>\n            </div>\n            <div class=\"resize-handle resize-handle-e\"></div><div class=\"resize-handle resize-handle-s\"></div><div class=\"resize-handle resize-handle-se\"></div>\n        `;\n        document.body.appendChild(textPanel);\n\n        const controlButtonContainer = document.createElement('div');\n        controlButtonContainer.className = 'control-buttons-text-panel';\n        controlButtonContainer.innerHTML = `<div class=\"control-btn\" title=\"打开文本面板\">${icons.comment}</div>`;\n        document.body.appendChild(controlButtonContainer);\n\n        const savedBtnPos = GM_getValue(STORAGE_KEYS.CONTROL_BTN_POS, { top: window.innerHeight - 100, left: window.innerWidth - 100 });\n        controlButtonContainer.style.top = `${savedBtnPos.top}px`;\n        controlButtonContainer.style.left = `${savedBtnPos.left}px`;\n\n        let savedPanelState = GM_getValue(STORAGE_KEYS.PANEL_STATE, { width: DEFAULT_PANEL_WIDTH, height: DEFAULT_PANEL_HEIGHT, top: DEFAULT_PANEL_TOP, left: DEFAULT_PANEL_LEFT });\n        savedPanelState.left = Math.max(0, Math.min(savedPanelState.left, window.innerWidth - savedPanelState.width));\n        savedPanelState.top = Math.max(0, Math.min(savedPanelState.top, window.innerHeight - savedPanelState.height));\n        \n        // 确保加载的尺寸不小于最小尺寸\n        savedPanelState.width = Math.max(savedPanelState.width, MIN_PANEL_WIDTH);\n        savedPanelState.height = Math.max(savedPanelState.height, MIN_PANEL_HEIGHT);\n\n        textPanel.style.width = savedPanelState.width + 'px';\n        textPanel.style.height = savedPanelState.height + 'px';\n        textPanel.style.top = savedPanelState.top + 'px';\n        textPanel.style.left = savedPanelState.left + 'px';\n        setTimeout(() => textPanel.classList.add('show'), 500);\n\n        let resizeTimeout;\n        window.addEventListener('resize', () => {\n            clearTimeout(resizeTimeout);\n            resizeTimeout = setTimeout(() => {\n                const rect = textPanel.getBoundingClientRect();\n                let newLeft = rect.left, newTop = rect.top, changed = false;\n                // 确保面板主体在窗口内\n                if (rect.right > window.innerWidth) { newLeft = window.innerWidth - rect.width; changed = true; }\n                if (rect.bottom > window.innerHeight) { newTop = window.innerHeight - rect.height; changed = true; }\n                \n                if (changed) { \n                    textPanel.style.left = `${Math.max(0, newLeft)}px`; \n                    textPanel.style.top = `${Math.max(0, newTop)}px`; \n                }\n            }, 100);\n        });\n\n        const customInput = textPanel.querySelector('#customInput');\n        const focusLockToggle = textPanel.querySelector('#focusLockToggle');\n        if (isFocusLockEnabled) focusLockToggle.classList.add('active');\n        focusLockToggle.addEventListener('click', () => {\n            isFocusLockEnabled = !isFocusLockEnabled;\n            focusLockToggle.classList.toggle('active', isFocusLockEnabled);\n            GM_setValue(STORAGE_KEYS.FOCUS_LOCK, isFocusLockEnabled);\n            showNotification(isFocusLockEnabled ? '焦点已锁定至【脚本面板】输入框。' : '焦点已锁定至【主聊天】输入框。', 'success', 70, 30);\n            restoreFocus();\n        });\n\n        if (focusCheckInterval) clearInterval(focusCheckInterval);\n        focusCheckInterval = setInterval(() => {\n            if (isMouseButtonDown || !textPanel.classList.contains('show') || isScriptSending) return;\n            const activeEl = document.activeElement;\n            if (isFocusLockEnabled) { if (activeEl !== customInput) restoreFocus(); }\n            else { if (!activeEl || activeEl === document.body) restoreFocus(); }\n        }, 300);\n\n        let isTranslationActive = GM_getValue(STORAGE_KEYS.TRANSLATION_ACTIVE, false);\n        let translationBox = null;\n        const translationCache = {};\n        const translateToggle = textPanel.querySelector('#translateToggle');\n        if (isTranslationActive) translateToggle.classList.add('active');\n        function shouldTranslate(text) {\n            if (!text || text.length < 2) return false;\n            // 检查是否全为数字、空格、标点符号，或全为中文 (不翻译)\n            if (/^[\\d\\s\\p{P}]+$/u.test(text) || /^[\\u4e00-\\u9fa5]+$/.test(text)) return false;\n            // 检查是否只包含表情符号 (不翻译)\n            const emojiRegex = /(\\p{Emoji_Presentation}|\\p{Extended_Pictographic})/gu;\n            return text.replace(emojiRegex, '').trim() !== '';\n        }\n        function createTranslationOverlay(txt, pos) {\n            if (translationBox) translationBox.remove();\n            translationBox = document.createElement('div');\n            translationBox.className = 'translation-overlay';\n            translationBox.textContent = txt;\n            translationBox.style.left = pos.x + 'px';\n            translationBox.style.top = pos.y + 'px';\n            const closeBtn = document.createElement('div');\n            closeBtn.className = 'close-translation';\n            closeBtn.innerHTML = icons.times;\n            closeBtn.onclick = e => { e.stopPropagation(); translationBox.remove(); translationBox = null; };\n            translationBox.appendChild(closeBtn);\n            translationBox.onclick = function() { this.remove(); translationBox = null; };\n            document.body.appendChild(translationBox);\n            return translationBox;\n        }\n        function translateText(text, targetLang, cb) {\n            if (!text) return cb('');\n            if (translationCache[text]) return cb(translationCache[text]);\n            const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}`;\n            GM_xmlhttpRequest({\n                method: 'GET', url,\n                onload(resp) {\n                    try {\n                        const d = JSON.parse(resp.responseText);\n                        const translated = d[0][0][0] || null;\n                        if (translated) translationCache[text] = translated;\n                        cb(translated);\n                    } catch (e) { cb(null); }\n                },\n                onerror(err) { cb(null); }\n            });\n        }\n        function handleMouseUp(e) {\n            if (e.target.closest('.translation-overlay')) return;\n            setTimeout(() => {\n                const sel = window.getSelection().toString().trim();\n                if (!sel || sel === handleMouseUp.lastSelectedText || !isTranslationActive) return;\n                handleMouseUp.lastSelectedText = sel;\n                if (!shouldTranslate(sel)) return;\n                const pos = { x: e.clientX, y: e.clientY - 30 };\n                createTranslationOverlay('翻译中...', pos);\n                if (translationCache[sel]) { createTranslationOverlay(translationCache[sel], pos); return; }\n                translateText(sel, 'zh-CN', res => {\n                    createTranslationOverlay(res || '翻译失败', pos);\n                    if (res) translationCache[sel] = res;\n                });\n            }, 100);\n        }\n        translateToggle.addEventListener('click', () => {\n            isTranslationActive = !isTranslationActive;\n            translateToggle.classList.toggle('active', isTranslationActive);\n            GM_setValue(STORAGE_KEYS.TRANSLATION_ACTIVE, isTranslationActive);\n            if (isTranslationActive) { document.addEventListener('mouseup', handleMouseUp); showNotification('划词翻译已启用', 'success', 70, 30); }\n            else { document.removeEventListener('mouseup', handleMouseUp); if (translationBox) translationBox.remove(), translationBox = null; showNotification('划词翻译已禁用', 'success', 70, 30); }\n        });\n        if (isTranslationActive) document.addEventListener('mouseup', handleMouseUp);\n\n        const textDisplay = textPanel.querySelector('#textDisplay'), currentFileName = textPanel.querySelector('#currentFileName'), selectFileBtn = textPanel.querySelector('.select-file-btn'), refreshBtn = textPanel.querySelector('.refresh-btn'), textSearchInput = textPanel.querySelector('#textSearch'), searchButton = textPanel.querySelector('#searchButton'), customSendBtn = textPanel.querySelector('#customSendBtn'), charCount = textPanel.querySelector('#charCount'), inputResizeHandle = textPanel.querySelector('.input-resize-handle');\n        let currentFile = null, currentMessages = [], originalMessages = [];\n        selectFileBtn.addEventListener('click', () => fileInput.click());\n        fileInput.addEventListener('change', e => { if (e.target.files.length > 0) loadFileContent(e.target.files[0]); });\n        refreshBtn.addEventListener('click', () => { if (currentFile) loadFileContent(currentFile); else fileInput.click(); });\n        function loadFileContent(file) {\n            currentFile = file;\n            currentFileName.textContent = file.name;\n            textPanel.querySelector('.file-path').textContent = file.path || '';\n            textDisplay.innerHTML = `<div class=\"loading\">${icons.spinner}<span>正在加载...</span></div>`;\n            const reader = new FileReader();\n            reader.onload = e => {\n                const content = e.target.result;\n                currentMessages = content.split(/\\r?\\n\\s*\\r?\\n/).filter(m => m.trim());\n                originalMessages = [...currentMessages];\n                displayMessages(currentMessages);\n            };\n            reader.onerror = () => { textDisplay.innerHTML = `<div class=\"loading\">${icons.exclamationCircle}<span>读取失败</span></div>`; };\n            reader.readAsText(file);\n        }\n        function extractAfterEqual(txt) { const idx = txt.lastIndexOf('='); return idx !== -1 ? txt.slice(idx + 1).trim() : txt; }\n        function displayMessages(msgs) {\n            if (!msgs.length) { textDisplay.innerHTML = '<div class=\"loading\"><span>无匹配内容</span></div>'; return; }\n            textDisplay.innerHTML = msgs.map(m => {\n                const contentToSend = encodeURIComponent(extractAfterEqual(m));\n                return `<div class=\"text-line\"><div class=\"text-controls\"><button class=\"send-btn\" data-content=\"${contentToSend}\" title=\"发送\">${icons.paperPlane}</button><button class=\"translate-btn\" data-content=\"${contentToSend}\" title=\"翻译并发送\">${icons.language}</button></div><div class=\"text-content\">${m.replace(/\\n/g,'<br>')}</div></div>`;\n            }).join('');\n            textDisplay.querySelectorAll('.send-btn').forEach(btn => btn.onclick = () => { sendToChat(decodeURIComponent(btn.dataset.content)); });\n            textDisplay.querySelectorAll('.translate-btn').forEach(btn => btn.onclick = () => {\n                const content = decodeURIComponent(btn.dataset.content);\n                // 如果内容包含中文字符，则尝试翻译成葡萄牙语（pt），否则直接发送\n                if (/[\\u4e00-\\u9fa5]/.test(content)) { translateText(content, 'pt', translatedText => sendToChat(translatedText || content)); }\n                else { sendToChat(content); }\n            });\n        }\n        function filterMessages(term) {\n            if (!term.trim()) { displayMessages(originalMessages); return; }\n            const filtered = originalMessages.filter(m => m.toLowerCase().includes(term.toLowerCase()));\n            displayMessages(filtered);\n        }\n        textSearchInput.addEventListener('input', () => filterMessages(textSearchInput.value));\n        searchButton.addEventListener('click', () => filterMessages(textSearchInput.value));\n        customInput.addEventListener('input', function() {\n            const len = this.value.length;\n            charCount.textContent = `${len}/500`;\n            charCount.style.color = len > 500 ? '#ef4444' : '#64748b';\n        });\n        function handlePanelInputSend() {\n            const txt = customInput.value.trim();\n            if (!txt) return;\n            // 如果内容包含中文字符，则尝试翻译成葡萄牙语（pt），否则直接发送\n            if (/[\\u4e00-\\u9fa5]/.test(txt)) { translateText(txt, 'pt', translatedText => sendToChat(translatedText || txt)); }\n            else { sendToChat(txt); }\n        }\n        customSendBtn.addEventListener('click', handlePanelInputSend);\n        customInput.addEventListener('keydown', e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handlePanelInputSend(); } });\n        let resizingInput = false, startH = 0, startY = 0;\n        inputResizeHandle.addEventListener('mousedown', e => {\n            resizingInput = true;\n            startH = customInput.offsetHeight;\n            startY = e.clientY;\n            document.body.style.cursor = 'ns-resize';\n            e.preventDefault();\n        });\n        document.addEventListener('mousemove', e => { if (resizingInput) { const nh = startH + (startY - e.clientY); if (nh >= 40 && nh <= 200) customInput.style.height = nh + 'px'; } });\n        document.addEventListener('mouseup', () => { if (resizingInput) { resizingInput = false; document.body.style.cursor = ''; } });\n        textPanel.querySelector('.close-btn').addEventListener('click', () => { textPanel.classList.remove('show'); controlButtonContainer.classList.add('show'); });\n        controlButtonContainer.addEventListener('click', (e) => {\n            if (e.currentTarget.dataset.dragging === 'true') { delete e.currentTarget.dataset.dragging; return; }\n            textPanel.classList.add('show');\n            controlButtonContainer.classList.remove('show');\n        });\n        textPanel.querySelector('.minimize-btn').addEventListener('click', () => {\n            if (textPanel.classList.contains('minimized')) {\n                const preMinimizeHeight = textPanel.dataset.preMinimizeHeight;\n                if (preMinimizeHeight) textPanel.style.height = preMinimizeHeight + 'px';\n                textPanel.classList.remove('minimized');\n            } else {\n                textPanel.dataset.preMinimizeHeight = textPanel.offsetHeight;\n                textPanel.classList.add('minimized');\n            }\n        });\n        setupPanelDrag(textPanel);\n        setupPanelResize(textPanel);\n        setupFloatingButtonDrag(controlButtonContainer);\n        panelInitialized = true;\n        console.log(\"文本管理面板创建完成。\"); // 使用 console.log 避免依赖外部日志管理器\n    }\n\n    function init() {\n        const observer = new MutationObserver((mutationsList, observer) => {\n            const chatContainerSelectors = IS_NEW_SALESMARTLY ? '.editor-container__content, .input-area__send' : '.ss-chat-container, .chat-window, .conversation-panel';\n            if (document.querySelector(chatContainerSelectors)) {\n                observer.disconnect();\n                createTextPanelSystem();\n            }\n        });\n        observer.observe(document.body, { childList: true, subtree: true });\n        setTimeout(() => {\n            if (!panelInitialized) {\n                console.log('MutationObserver 未触发，通过 setTimeout 备用方案创建面板。'); // 使用 console.log\n                createTextPanelSystem();\n            }\n        }, 5000);\n    }\n\n    if (document.readyState === 'complete') {\n        setTimeout(init, 500);\n    } else {\n        window.addEventListener('load', () => setTimeout(init, 500));\n    }\n\n})();","functional_script_code_hash":"cd9e4e606a6d270a36184602654ce72f274a4bfa9e56574b9b69127c7a88bd96","loader_script_hash":"fe71b0516c22faf1d0abfed9460fb144e0d7cd3c6c78119d4ead5031980f3d2b","config":{"feature_x_enabled":true,"keyword_list":["example","test"],"salesmartly_api_key":"YOUR_SALESMARTLY_API_KEY_IF_NEEDED"}}