Google Search Custom Sidebar

Customizable Google Search sidebar: quick filters (lang, time, filetype, country, date), site search, Verbatim & Personalization tools.

当前为 2025-05-17 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Google Search Custom Sidebar
// @name:zh-TW   Google 搜尋自訂側邊欄
// @name:ja      Google検索カスタムサイドバー
// @namespace    https://greasyfork.org/en/users/1467948-stonedkhajiit
// @version      0.0.8
// @description  Customizable Google Search sidebar: quick filters (lang, time, filetype, country, date), site search, Verbatim & Personalization tools.
// @description:zh-TW Google 搜尋自訂側邊欄:快速篩選(語言、時間、檔案類型、國家、日期)、站內搜尋、一字不差與個人化工具。
// @description:ja Google検索カスタムサイドバー:高速フィルター(言語,期間,ファイル形式,国,日付)、サイト検索、完全一致検索とパーソナライズツール。
// @match        https://www.google.com/search*
// @include      /^https:\/\/(?:ipv4|ipv6|www)\.google\.(?:[a-z\.]+)\/search\?(?:.+&)?q=[^&]+(?:&.+)?$/
// @exclude      /^https:\/\/(?:ipv4|ipv6|www)\.google\.(?:[a-z\.]+)\/search\?(?:.+&)?(?:tbm=(?:isch|shop|bks|flm|fin|lcl)|udm=(?:2|28))(?:&.+)?$/
// @icon         https://www.google.com/favicon.ico
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @grant        GM_deleteValue
// @run-at       document-idle
// @author       StonedKhajiit
// @license      MIT
// @require      https://update.greasyfork.org/scripts/535624/1590843/Google%20Search%20Custom%20Sidebar%20-%20i18n.js
// @require      https://update.greasyfork.org/scripts/535625/1590839/Google%20Search%20Custom%20Sidebar%20-%20Styles.js
// ==/UserScript==

(function() {
    'use strict';

    // --- Constants and Configuration ---
    const SCRIPT_INTERNAL_NAME = 'GoogleSearchCustomSidebar';
    const SCRIPT_VERSION = '0.0.8';
    const LOG_PREFIX = `[${SCRIPT_INTERNAL_NAME} v${SCRIPT_VERSION}]`;

    const DEFAULT_SECTION_ORDER = [
        'sidebar-section-language', 'sidebar-section-time', 'sidebar-section-filetype',
        'sidebar-section-occurrence',
        'sidebar-section-country', 'sidebar-section-date-range', 'sidebar-section-site-search', 'sidebar-section-tools'
    ];

    const defaultSettings = {
        sidebarPosition: { left: 0, top: 80 },
        sectionStates: {},
        theme: 'system',
        hoverMode: false,
        idleOpacity: 0.8,
        sidebarWidth: 135,
        fontSize: 12.5,
        headerIconSize: 16,
        verticalSpacingMultiplier: 0.5,
        interfaceLanguage: 'auto',
        visibleSections: {
            'sidebar-section-language': true, 'sidebar-section-time': true, 'sidebar-section-filetype': true,
            'sidebar-section-occurrence': true,
            'sidebar-section-country': true, 'sidebar-section-date-range': true,
            'sidebar-section-site-search': true, 'sidebar-section-tools': true
        },
        sectionDisplayMode: 'remember',
        accordionMode: false,
        resetButtonLocation: 'topBlock',
        verbatimButtonLocation: 'header',
        advancedSearchLinkLocation: 'header',
        personalizationButtonLocation: 'tools',
        countryDisplayMode: 'iconAndText',
        customLanguages: [],
        customTimeRanges: [],
        customFiletypes: [],
        customCountries: [],
        displayLanguages: [],
        displayCountries: [],
        favoriteSites: [
            { text: 'Wikipedia (EN)', url: 'en.wikipedia.org' }, { text: 'Stack Overflow', url: 'stackoverflow.com' },
            { text: 'GitHub', url: 'github.com' }, { text: 'Greasy Fork', url: 'greasyfork.org' },
            { text: 'Bluesky', url: 'bsky.app' }, { text: 'X.com', url: 'x.com' },
            { text: 'Reddit', url: 'reddit.com' }, { text: 'IMDb', url: 'imdb.com' },
            { text: 'Steam', url: 'store.steampowered.com' }, { text: 'Last.fm', url: 'last.fm' },
            { text: 'Metacritic', url: 'metacritic.com' }, { text: 'TMDb', url: 'themoviedb.org' },
            { text: 'Hacker News', url: 'news.ycombinator.com' }
        ],
        enableSiteSearchCheckboxMode: true,
        sidebarCollapsed: false,
        draggableHandleEnabled: true,
        enabledPredefinedOptions: {
            language: ['lang_en'],
            country: ['countryUS'],
            time: ['d', 'w', 'm', 'y', 'h'],
            filetype: ['pdf', 'docx', 'doc', 'xlsx', 'xls', 'pptx', 'ppt']
            // No predefined options for 'occurrence' as they are scriptDefined
        },
        sidebarSectionOrder: [...DEFAULT_SECTION_ORDER]
    };

    let sidebar = null, systemThemeMediaQuery = null;
    const MIN_SIDEBAR_TOP_POSITION = 5;
    let debouncedSaveSettings;
    let globalMessageTimeout = null;

    const IDS = {
        SIDEBAR: 'customizable-search-sidebar', SETTINGS_OVERLAY: 'settings-overlay', SETTINGS_WINDOW: 'settings-window',
        COLLAPSE_BUTTON: 'sidebar-collapse-button', SETTINGS_BUTTON: 'open-settings-button',
        TOOL_RESET_BUTTON: 'tool-reset-button', TOOL_VERBATIM: 'tool-verbatim', TOOL_PERSONALIZE: 'tool-personalize-search',
        APPLY_SELECTED_SITES_BUTTON: 'apply-selected-sites-button',
        FIXED_TOP_BUTTONS: 'sidebar-fixed-top-buttons',
        SETTINGS_MESSAGE_BAR: 'gscs-settings-message-bar',
        SETTING_WIDTH: 'setting-sidebar-width', SETTING_FONT_SIZE: 'setting-font-size', SETTING_HEADER_ICON_SIZE: 'setting-header-icon-size',
        SETTING_VERTICAL_SPACING: 'setting-vertical-spacing', SETTING_INTERFACE_LANGUAGE: 'setting-interface-language',
        SETTING_SECTION_MODE: 'setting-section-display-mode', SETTING_ACCORDION: 'setting-accordion-mode',
        SETTING_DRAGGABLE: 'setting-draggable-handle', SETTING_RESET_LOCATION: 'setting-reset-button-location',
        SETTING_VERBATIM_LOCATION: 'setting-verbatim-button-location', SETTING_ADV_SEARCH_LOCATION: 'setting-adv-search-link-location',
        SETTING_PERSONALIZE_LOCATION: 'setting-personalize-button-location',
        SETTING_SITE_SEARCH_CHECKBOX_MODE: 'setting-site-search-checkbox-mode',
        SETTING_COUNTRY_DISPLAY_MODE: 'setting-country-display-mode', SETTING_THEME: 'setting-theme',
        SETTING_HOVER: 'setting-hover-mode', SETTING_OPACITY: 'setting-idle-opacity',
        TAB_PANE_GENERAL: 'tab-pane-general', TAB_PANE_APPEARANCE: 'tab-pane-appearance', TAB_PANE_FEATURES: 'tab-pane-features', TAB_PANE_CUSTOM: 'tab-pane-custom',
        SITES_LIST: 'custom-sites-list', LANG_LIST: 'custom-languages-list', TIME_LIST: 'custom-time-ranges-list',
        FT_LIST: 'custom-filetypes-list', COUNTRIES_LIST: 'custom-countries-list',
        NEW_SITE_NAME: 'new-site-name', NEW_SITE_URL: 'new-site-url', ADD_SITE_BTN: 'add-site-button',
        NEW_LANG_TEXT: 'new-lang-text', NEW_LANG_VALUE: 'new-lang-value', ADD_LANG_BTN: 'add-lang-button',
        NEW_TIME_TEXT: 'new-timerange-text', NEW_TIME_VALUE: 'new-timerange-value', ADD_TIME_BTN: 'add-timerange-button',
        NEW_FT_TEXT: 'new-ft-text', NEW_FT_VALUE: 'new-ft-value', ADD_FT_BTN: 'add-ft-button',
        NEW_COUNTRY_TEXT: 'new-country-text', NEW_COUNTRY_VALUE: 'new-country-value', ADD_COUNTRY_BTN: 'add-country-button',
        DATE_MIN: 'date-min', DATE_MAX: 'date-max', DATE_RANGE_ERROR_MSG: 'date-range-error-msg',
        SIDEBAR_SECTION_ORDER_LIST: 'sidebar-section-order-list',
        NOTIFICATION_CONTAINER: 'gscs-notification-container',
        MODAL_ADD_NEW_OPTION_BTN: 'gscs-modal-add-new-option-btn',
        MODAL_PREDEFINED_CHOOSER_CONTAINER: 'gscs-modal-predefined-chooser-container',
        MODAL_PREDEFINED_CHOOSER_LIST: 'gscs-modal-predefined-chooser-list',
        MODAL_PREDEFINED_CHOOSER_ADD_BTN: 'gscs-modal-predefined-chooser-add-btn',
        MODAL_PREDEFINED_CHOOSER_CANCEL_BTN: 'gscs-modal-predefined-chooser-cancel-btn'
    };
    const CSS = {
        SIDEBAR_COLLAPSED: 'sidebar-collapsed', SIDEBAR_HEADER: 'sidebar-header', SIDEBAR_CONTENT_WRAPPER: 'sidebar-content-wrapper',
        DRAG_HANDLE: 'sidebar-drag-handle', SETTINGS_BUTTON: 'sidebar-settings-button', HEADER_BUTTON: 'sidebar-header-button',
        SIDEBAR_SECTION: 'sidebar-section', FIXED_TOP_BUTTON_ITEM: 'fixed-top-button-item', SECTION_TITLE: 'section-title',
        SECTION_CONTENT: 'section-content', COLLAPSED: 'collapsed', FILTER_OPTION: 'filter-option', SELECTED: 'selected',
        SITE_SEARCH_ITEM_CHECKBOX: 'site-search-item-checkbox',
        APPLY_SITES_BUTTON: 'apply-sites-button',
        DATE_INPUT_LABEL: 'date-input-label', DATE_INPUT: 'date-input', TOOL_BUTTON: 'tool-button', ACTIVE: 'active',
        CUSTOM_LIST: 'custom-list', ITEM_CONTROLS: 'item-controls', EDIT_CUSTOM_ITEM: 'edit-custom-item',
        DELETE_CUSTOM_ITEM: 'delete-custom-item', CUSTOM_LIST_INPUT_GROUP: 'custom-list-input-group',
        ADD_CUSTOM_BUTTON: 'add-custom-button', SETTINGS_HEADER: 'settings-header', SETTINGS_CLOSE_BTN: 'settings-close-button',
        SETTINGS_TABS: 'settings-tabs', TAB_BUTTON: 'tab-button', SETTINGS_TAB_CONTENT: 'settings-tab-content',
        TAB_PANE: 'tab-pane', SETTING_ITEM: 'setting-item', INLINE_LABEL: 'inline', SETTINGS_FOOTER: 'settings-footer',
        SAVE_BUTTON: 'save-button', CANCEL_BUTTON: 'cancel-button', RESET_BUTTON: 'reset-button',
        LIGHT_THEME: 'light-theme', DARK_THEME: 'dark-theme',
        SIMPLE_ITEM: 'simple', RANGE_VALUE: 'range-value', RANGE_HINT: 'setting-range-hint', SECTION_ORDER_LIST: 'section-order-list',
        INPUT_ERROR_MESSAGE: 'input-error-message', ERROR_VISIBLE: 'error-visible', INPUT_HAS_ERROR: 'input-has-error',
        DATE_RANGE_ERROR_MSG: 'date-range-error-message',
        MESSAGE_BAR: 'gscs-message-bar', MSG_INFO: 'gscs-msg-info', MSG_SUCCESS: 'gscs-msg-success',
        MSG_WARNING: 'gscs-msg-warning', MSG_ERROR: 'gscs-msg-error', MANAGE_CUSTOM_BUTTON: 'manage-custom-button',
        NOTIFICATION: 'gscs-notification',
        NTF_INFO: 'gscs-ntf-info', NTF_SUCCESS: 'gscs-ntf-success',
        NTF_WARNING: 'gscs-ntf-warning', NTF_ERROR: 'gscs-ntf-error',
        DRAGGING_ITEM: 'gscs-dragging-item',
        DRAG_OVER_HIGHLIGHT: 'gscs-drag-over-highlight',
        DRAG_ICON: 'gscs-drag-icon',
        REMOVE_FROM_LIST_BTN: 'gscs-remove-from-list-btn',
        MODAL_ADD_NEW_OPTION_BTN_CLASS: 'gscs-modal-add-new-option-button-class',
        MODAL_PREDEFINED_CHOOSER_CLASS: 'gscs-modal-predefined-chooser',
        MODAL_PREDEFINED_CHOOSER_ITEM: 'gscs-modal-predefined-chooser-item',
        SETTING_VALUE_HINT: 'setting-value-hint'
    };
    const DATA_ATTR = {
        FILTER_TYPE: 'filterType', FILTER_VALUE: 'filterValue', SITE_URL: 'siteUrl', SECTION_ID: 'sectionId',
        LIST_ID: 'listId', INDEX: 'index', LISTENER_ATTACHED: 'listenerAttached', TAB: 'tab', MANAGE_TYPE: 'managetype',
        ITEM_TYPE: 'itemType', ITEM_ID: 'itemId'
    };
    const STORAGE_KEY = 'googleSearchCustomSidebarSettings_v1';
    const SVG_ICONS = {
        chevronLeft: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"></polyline></svg>`,
        chevronRight: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>`,
        settings: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06-.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>`,
        reset: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"></polyline><polyline points="1 20 1 14 7 14"></polyline><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path></svg>`,
        verbatim: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><g transform="translate(-4.3875 -3.2375) scale(1.15)"><path d="M6 17.5c0 1.5 1.5 2.5 3 2.5h1.5c1.5 0 3-1 3-2.5V9c0-1.5-1.5-2.5-3-2.5H9C7.5 6.5 6 7.5 6 9v8.5z"/><path d="M15 17.5c0 1.5 1.5 2.5 3 2.5h1.5c1.5 0 3-1 3-2.5V9c0-1.5-1.5-2.5-3-2.5H18c-1.5 0-3 1-3 2.5v8.5z"/></g></svg>`,
        magnifyingGlass: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>`,
        close: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>`,
        edit: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>`,
        delete: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>`,
        add: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>`,
        update: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>`,
        personalization: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>`,
        dragGrip: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="1em" height="1em" fill="currentColor"><circle cx="9" cy="6" r="1.5"/><circle cx="15" cy="6" r="1.5"/><circle cx="9" cy="12" r="1.5"/><circle cx="15" cy="12" r="1.5"/><circle cx="9" cy="18" r="1.5"/><circle cx="15" cy="18" r="1.5"/></svg>`,
        removeFromList: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>`
    };
    const PREDEFINED_OPTIONS = {
        language: [ { textKey: 'predefined_lang_en', value: 'lang_en' }, { textKey: 'predefined_lang_ja', value: 'lang_ja' }, { textKey: 'predefined_lang_ko', value: 'lang_ko' }, { textKey: 'predefined_lang_fr', value: 'lang_fr' }, { textKey: 'predefined_lang_de', value: 'lang_de' }, { textKey: 'predefined_lang_es', value: 'lang_es' }, { textKey: 'predefined_lang_it', value: 'lang_it' }, { textKey: 'predefined_lang_pt', value: 'lang_pt' }, { textKey: 'predefined_lang_ru', value: 'lang_ru' }, { textKey: 'predefined_lang_ar', value: 'lang_ar' }, { textKey: 'predefined_lang_hi', value: 'lang_hi' }, { textKey: 'predefined_lang_nl', value: 'lang_nl' }, { textKey: 'predefined_lang_tr', value: 'lang_tr' }, { textKey: 'predefined_lang_vi', value: 'lang_vi' }, { textKey: 'predefined_lang_th', value: 'lang_th' }, { textKey: 'predefined_lang_id', value: 'lang_id' }, { textKey: 'predefined_lang_zh_tw', value: 'lang_zh-TW' }, { textKey: 'predefined_lang_zh_cn', value: 'lang_zh-CN' }, { textKey: 'predefined_lang_zh_all', value: 'lang_zh-TW|lang_zh-CN' }, ],
        country: [ { textKey: 'predefined_country_us', value: 'countryUS' }, { textKey: 'predefined_country_gb', value: 'countryGB' }, { textKey: 'predefined_country_ca', value: 'countryCA' }, { textKey: 'predefined_country_au', value: 'countryAU' }, { textKey: 'predefined_country_de', value: 'countryDE' }, { textKey: 'predefined_country_fr', value: 'countryFR' }, { textKey: 'predefined_country_jp', value: 'countryJP' }, { textKey: 'predefined_country_kr', value: 'countryKR' }, { textKey: 'predefined_country_cn', value: 'countryCN' }, { textKey: 'predefined_country_in', value: 'countryIN' }, { textKey: 'predefined_country_br', value: 'countryBR' }, { textKey: 'predefined_country_mx', value: 'countryMX' }, { textKey: 'predefined_country_es', value: 'countryES' }, { textKey: 'predefined_country_it', value: 'countryIT' }, { textKey: 'predefined_country_ru', value: 'countryRU' }, { textKey: 'predefined_country_nl', value: 'countryNL' }, { textKey: 'predefined_country_sg', value: 'countrySG' }, { textKey: 'predefined_country_hk', value: 'countryHK' }, { textKey: 'predefined_country_tw', value: 'countryTW' }, { textKey: 'predefined_country_my', value: 'countryMY' }, { textKey: 'predefined_country_vn', value: 'countryVN' }, { textKey: 'predefined_country_ph', value: 'countryPH' }, { textKey: 'predefined_country_th', value: 'countryTH' }, { textKey: 'predefined_country_za', value: 'countryZA' }, { textKey: 'predefined_country_tr', value: 'countryTR' }, ],
        time: [ { textKey: 'predefined_time_h', value: 'h' }, { textKey: 'predefined_time_h2', value: 'h2' }, { textKey: 'predefined_time_h6', value: 'h6' }, { textKey: 'predefined_time_h12', value: 'h12' }, { textKey: 'predefined_time_d', value: 'd' }, { textKey: 'predefined_time_d2', value: 'd2' }, { textKey: 'predefined_time_d3', value: 'd3' }, { textKey: 'predefined_time_w', value: 'w' }, { textKey: 'predefined_time_m', value: 'm' }, { textKey: 'predefined_time_y', value: 'y' }, ],
        filetype: [ { textKey: 'predefined_filetype_pdf', value: 'pdf' }, { textKey: 'predefined_filetype_docx', value: 'docx' }, { textKey: 'predefined_filetype_doc', value: 'doc' }, { textKey: 'predefined_filetype_xlsx', value: 'xlsx' }, { textKey: 'predefined_filetype_xls', value: 'xls' }, { textKey: 'predefined_filetype_pptx', value: 'pptx' }, { textKey: 'predefined_filetype_ppt', value: 'ppt' }, { textKey: 'predefined_filetype_txt', value: 'txt' }, { textKey: 'predefined_filetype_rtf', value: 'rtf' }, { textKey: 'predefined_filetype_html', value: 'html' }, { textKey: 'predefined_filetype_htm', value: 'htm' }, { textKey: 'predefined_filetype_xml', value: 'xml' }, { textKey: 'predefined_filetype_jpg', value: 'jpg' }, { textKey: 'predefined_filetype_png', value: 'png' }, { textKey: 'predefined_filetype_gif', value: 'gif' }, { textKey: 'predefined_filetype_svg', value: 'svg' }, { textKey: 'predefined_filetype_bmp', value: 'bmp' }, { textKey: 'predefined_filetype_js', value: 'js' }, { textKey: 'predefined_filetype_css', value: 'css' }, { textKey: 'predefined_filetype_py', value: 'py' }, { textKey: 'predefined_filetype_java', value: 'java' }, { textKey: 'predefined_filetype_cpp', value: 'cpp' }, { textKey: 'predefined_filetype_cs', value: 'cs' }, { textKey: 'predefined_filetype_kml', value: 'kml'}, { textKey: 'predefined_filetype_kmz', value: 'kmz'}, ]
    };
    const ALL_SECTION_DEFINITIONS = [
        { id: 'sidebar-section-language', type: 'filter', titleKey: 'section_language', scriptDefined: [{textKey:'filter_any_language',v:''}], param: 'lr', predefinedOptionsKey: 'language', customItemsKey: 'customLanguages', displayItemsKey: 'displayLanguages' },
        { id: 'sidebar-section-time', type: 'filter', titleKey: 'section_time', scriptDefined: [{textKey:'filter_any_time',v:''}], param: 'qdr', predefinedOptionsKey: 'time', customItemsKey: 'customTimeRanges' },
        { id: 'sidebar-section-filetype', type: 'filter', titleKey: 'section_filetype', scriptDefined: [{ textKey: 'filter_any_format', v: '' }], param: 'filetype', predefinedOptionsKey: 'filetype', customItemsKey: 'customFiletypes' },
        {
            id: 'sidebar-section-occurrence',
            type: 'filter',
            titleKey: 'section_occurrence',
            scriptDefined: [
                { textKey: 'filter_occurrence_any', v: 'any' },
                { textKey: 'filter_occurrence_title', v: 'title' },
                { textKey: 'filter_occurrence_text', v: 'text' },
                { textKey: 'filter_occurrence_url', v: 'url' },
            ],
            param: 'as_occt'
        },
        { id: 'sidebar-section-country', type: 'filter', titleKey: 'section_country', scriptDefined: [{textKey:'filter_any_country',v:''}], param: 'cr', predefinedOptionsKey: 'country', customItemsKey: 'customCountries', displayItemsKey: 'displayCountries' },
        { id: 'sidebar-section-date-range', type: 'date', titleKey: 'section_date_range' },
        { id: 'sidebar-section-site-search', type: 'site', titleKey: 'section_site_search' },
        { id: 'sidebar-section-tools', type: 'tools', titleKey: 'section_tools' }
    ];

    const LocalizationService = (function() {
        const builtInTranslations = {
            'en': {
                scriptName: 'Google Search Custom Sidebar', settingsTitle: 'Google Search Custom Sidebar Settings', manageOptionsTitle: 'Manage Options', manageSitesTitle: 'Manage Favorite Sites', manageLanguagesTitle: 'Manage Language Options', manageCountriesTitle: 'Manage Country/Region Options', manageTimeRangesTitle: 'Manage Time Ranges', manageFileTypesTitle: 'Manage File Types', section_language: 'Language', section_time: 'Time', section_filetype: 'File Type', section_country: 'Country/Region', section_date_range: 'Date Range', section_site_search: 'Site Search', section_tools: 'Tools',
                section_occurrence: 'Keyword Location',
                filter_any_language: 'Any Language', filter_any_time: 'Any Time', filter_any_format: 'Any Format', filter_any_country: 'Any Country/Region',
                filter_occurrence_any: 'Anywhere in the page', filter_occurrence_title: 'In the title of the page', filter_occurrence_text: 'In the text of the page', filter_occurrence_url: 'In the URL of the page',
                filter_clear_site_search: 'Clear Site Search', filter_clear_tooltip_suffix: '(Clear)', predefined_lang_zh_tw: 'Traditional Chinese', predefined_lang_zh_cn: 'Simplified Chinese', predefined_lang_zh_all: 'All Chinese', predefined_lang_en: 'English', predefined_lang_ja: 'Japanese', predefined_lang_ko: 'Korean', predefined_lang_fr: 'French', predefined_lang_de: 'German', predefined_lang_es: 'Spanish', predefined_lang_it: 'Italian', predefined_lang_pt: 'Portuguese', predefined_lang_ru: 'Russian', predefined_lang_ar: 'Arabic', predefined_lang_hi: 'Hindi', predefined_lang_nl: 'Dutch', predefined_lang_tr: 'Turkish', predefined_lang_vi: 'Vietnamese', predefined_lang_th: 'Thai', predefined_lang_id: 'Indonesian', predefined_country_tw: '🇹🇼 Taiwan', predefined_country_jp: '🇯🇵 Japan', predefined_country_kr: '🇰🇷 South Korea', predefined_country_cn: '🇨🇳 China', predefined_country_hk: '🇭🇰 Hong Kong', predefined_country_sg: '🇸🇬 Singapore', predefined_country_my: '🇲🇾 Malaysia', predefined_country_vn: '🇻🇳 Vietnam', predefined_country_ph: '🇵🇭 Philippines', predefined_country_th: '🇹🇭 Thailand', predefined_country_us: '🇺🇸 United States', predefined_country_ca: '🇨🇦 Canada', predefined_country_br: '🇧🇷 Brazil', predefined_country_mx: '🇲🇽 Mexico', predefined_country_gb: '🇬🇧 United Kingdom', predefined_country_de: '🇩🇪 Germany', predefined_country_fr: '🇫🇷 France', predefined_country_it: '🇮🇹 Italy', predefined_country_es: '🇪🇸 Spain', predefined_country_ru: '🇷🇺 Russia', predefined_country_nl: '🇳🇱 Netherlands', predefined_country_au: '🇦🇺 Australia', predefined_country_in: '🇮🇳 India', predefined_country_za: '🇿🇦 South Africa', predefined_country_tr: '🇹🇷 Turkey', predefined_time_h: 'Past hour', predefined_time_h2: 'Past 2 hours', predefined_time_h6: 'Past 6 hours', predefined_time_h12: 'Past 12 hours', predefined_time_d: 'Past 24 hours', predefined_time_d2: 'Past 2 days', predefined_time_d3: 'Past 3 days', predefined_time_w: 'Past week', predefined_time_m: 'Past month', predefined_time_y: 'Past year', predefined_filetype_pdf: 'PDF', predefined_filetype_docx: 'Word (docx)', predefined_filetype_doc: 'Word (doc)', predefined_filetype_xlsx: 'Excel (xlsx)', predefined_filetype_xls: 'Excel (xls)', predefined_filetype_pptx: 'PowerPoint (pptx)', predefined_filetype_ppt: 'PowerPoint (ppt)', predefined_filetype_txt: 'Plain Text', predefined_filetype_rtf: 'Rich Text Format', predefined_filetype_html: 'Web Page (html)', predefined_filetype_htm: 'Web Page (htm)', predefined_filetype_xml: 'XML', predefined_filetype_jpg: 'JPEG Image', predefined_filetype_png: 'PNG Image', predefined_filetype_gif: 'GIF Image', predefined_filetype_svg: 'SVG Image', predefined_filetype_bmp: 'BMP Image', predefined_filetype_js: 'JavaScript', predefined_filetype_css: 'CSS', predefined_filetype_py: 'Python', predefined_filetype_java: 'Java', predefined_filetype_cpp: 'C++', predefined_filetype_cs: 'C#', predefined_filetype_kml: 'Google Earth (kml)', predefined_filetype_kmz: 'Google Earth (kmz)',
                tool_reset_filters: 'Reset Filters', tool_verbatim_search: 'Verbatim Search', tool_advanced_search: 'Advanced Search', tool_apply_date: 'Apply Dates',
                tool_personalization_toggle: 'Personalization', tool_apply_selected_sites: 'Apply Selected Sites',
                link_advanced_search_title: 'Open Google Advanced Search page', tooltip_site_search: 'Search within {siteUrl}', tooltip_clear_site_search: 'Remove site: restriction', tooltip_toggle_personalization_on: 'Click to turn Personalization ON (Results tailored to you)', tooltip_toggle_personalization_off: 'Click to turn Personalization OFF (More generic results)', settings_tab_general: 'General', settings_tab_appearance: 'Appearance', settings_tab_features: 'Features', settings_tab_custom: 'Custom', settings_close_button_title: 'Close', settings_interface_language: 'Interface Language:', settings_language_auto: 'Auto (Browser Default)', settings_section_mode: 'Section Collapse Mode:', settings_section_mode_remember: 'Remember State', settings_section_mode_expand: 'Expand All', settings_section_mode_collapse: 'Collapse All',
                settings_accordion_mode: 'Accordion Mode (only when "Remember State" is active)',
                settings_accordion_mode_hint_desc: 'When enabled, expanding one section will automatically collapse other open sections.',
                settings_enable_drag: 'Enable Dragging', settings_reset_button_location: 'Reset Button Location:', settings_verbatim_button_location: 'Verbatim Button Location:', settings_adv_search_location: '"Advanced Search" Link Location:', settings_personalize_button_location: 'Personalization Button Location:',
                settings_enable_site_search_checkbox_mode: 'Enable Checkbox Mode for Site Search',
                settings_enable_site_search_checkbox_mode_hint: 'Allows selecting multiple favorite sites for a combined (OR) search.',
                settings_location_tools: 'Tools Section', settings_location_top: 'Top Block', settings_location_header: 'Sidebar Header', settings_location_hide: 'Hide', settings_sidebar_width: 'Sidebar Width (px)', settings_width_range_hint: '(Range: 90-270, Step: 5)', settings_font_size: 'Base Font Size (px)', settings_font_size_range_hint: '(Range: 8-24, Step: 0.5)', settings_header_icon_size: 'Header Icon Size (px)', settings_header_icon_size_range_hint: '(Range: 8-32, Step: 0.5)', settings_vertical_spacing: 'Vertical Spacing', settings_vertical_spacing_range_hint: '(Multiplier Range: 0.05-1.5, Step: 0.05)', settings_theme: 'Theme:', settings_theme_system: 'Follow System', settings_theme_light: 'Light', settings_theme_dark: 'Dark', settings_theme_minimal_light: 'Minimal (Light)', settings_theme_minimal_dark: 'Minimal (Dark)', settings_hover_mode: 'Hover Mode', settings_idle_opacity: 'Idle Opacity:', settings_opacity_range_hint: '(Range: 0.1-1.0, Step: 0.05)', settings_country_display: 'Country/Region Display:', settings_country_display_icontext: 'Icon & Text', settings_country_display_text: 'Text Only', settings_country_display_icon: 'Icon Only', settings_visible_sections: 'Visible Sections:', settings_section_order: 'Adjust Sidebar Section Order (Drag & Drop):',
                settings_section_order_hint: '(Drag items to reorder. Only affects checked sections)',
                settings_no_orderable_sections: 'No visible sections to order.',
                settings_move_up_title: 'Move Up',
                settings_move_down_title: 'Move Down',
                settings_custom_intro: 'Manage filter options for each section:',
                settings_manage_sites_button: 'Manage Favorite Sites...', settings_manage_languages_button: 'Manage Language Options...', settings_manage_countries_button: 'Manage Country/Region Options...', settings_manage_time_ranges_button: 'Manage Time Ranges...', settings_manage_file_types_button: 'Manage File Types...', settings_save_button: 'Save Settings', settings_cancel_button: 'Cancel', settings_reset_all_button: 'Reset All',
                modal_label_enable_predefined: 'Enable Predefined {type}:',
                modal_label_my_custom: 'My Custom {type}:',
                modal_label_display_options_for: 'Display Options for {type} (Drag to Sort):',
                modal_button_add_new_option: 'Add New Option...',
                modal_button_add_predefined_option: 'Add Predefined...',
                modal_button_add_custom_option: 'Add Custom...',
                modal_placeholder_name: 'Name', modal_placeholder_domain: 'Domain', modal_placeholder_text: 'Text', modal_placeholder_value: 'Value',
                modal_hint_domain: 'Format: valid domain (e.g., `wikipedia.org`) or TLD/SLD starting with `.` (e.g., `.edu`, `.gov.uk`)',
                modal_hint_language: 'Format: starts with `lang_`, e.g., `lang_ja`, `lang_zh-TW`. Use `|` for multiple.', modal_hint_country: 'Format: `country` + 2-letter uppercase code, e.g., `countryDE`', modal_hint_time: 'Format: `h`, `d`, `w`, `m`, `y`, optionally followed by numbers, e.g., `h1`, `d7`, `w`', modal_hint_filetype: 'Format: file extension, e.g., `pdf`, `docx`',
                modal_tooltip_domain: 'Enter a valid domain or a TLD/SLD like .edu, .gov.uk',
                modal_tooltip_language: 'Format: lang_xx or lang_xx-XX, separate multiple with |', modal_tooltip_country: 'Format: countryXX (XX = uppercase country code)', modal_tooltip_time: 'Format: h, d, w, m, y, optionally followed by numbers', modal_tooltip_filetype: 'File extension (without the dot)', modal_button_add_title: 'Add', modal_button_update_title: 'Update Item', modal_button_cancel_edit_title: 'Cancel Edit', modal_button_edit_title: 'Edit', modal_button_delete_title: 'Delete', modal_button_remove_from_list_title: 'Remove from list', modal_button_complete: 'Done', value_empty: '(empty)', date_range_from: 'From:', date_range_to: 'To:', sidebar_collapse_title: 'Collapse', sidebar_expand_title: 'Expand', sidebar_drag_title: 'Drag', sidebar_settings_title: 'Settings',
                alert_invalid_start_date: 'Invalid start date', alert_invalid_end_date: 'Invalid end date', alert_end_before_start: 'End date cannot be earlier than start date', alert_start_in_future: 'Start date cannot be in the future', alert_end_in_future: 'End date cannot be in the future', alert_select_date: 'Please select a date', alert_error_applying_date: 'Error applying date range', alert_error_applying_filter: 'Error applying filter {type}={value}', alert_error_applying_site_search: 'Error applying site search for {site}', alert_error_clearing_site_search: 'Error clearing site search', alert_error_resetting_filters: 'Error resetting filters', alert_error_toggling_verbatim: 'Error toggling Verbatim search', alert_error_toggling_personalization: 'Error toggling Personalization search', alert_enter_display_name: 'Please enter the display name for {type}.', alert_enter_value: 'Please enter the corresponding value for {type}.', alert_invalid_value_format: 'The value format for {type} is incorrect. {hint}', alert_duplicate_name: 'Custom item display name "{name}" already exists. Please use a different name.', alert_update_failed_invalid_index: 'Update failed: Invalid item index.', alert_edit_failed_missing_fields: 'Cannot edit: Input or button fields not found.',
                alert_no_more_predefined_to_add: 'No more predefined {type} options available to add.',
                alert_generic_error: 'An unexpected error occurred. Please check the console or try again. Context: {context}',
                confirm_delete_item: 'Are you sure you want to delete the custom item "{name}"?', confirm_remove_item_from_list: 'Are you sure you want to remove "{name}" from this display list?', confirm_reset_settings: 'Are you sure you want to reset all settings to their default values?', alert_settings_reset_success: 'Settings have been reset to default. You can continue editing or click "Save Settings" to confirm.', confirm_reset_all_menu: 'Are you sure you want to reset all settings to their default values?\nThis cannot be undone and requires a page refresh to take effect.', alert_reset_all_menu_success: 'All settings have been reset to defaults.\nPlease refresh the page to apply the changes.', alert_reset_all_menu_fail: 'Failed to reset settings via menu command! Please check the console.', alert_init_fail: '{scriptName} initialization failed. Some features may not work. Please check the console for technical details.\nTechnical Error: {error}', menu_open_settings: '⚙️ Open Settings', menu_reset_all_settings: '🚨 Reset All Settings',
            }
        };
        let effectiveTranslations = JSON.parse(JSON.stringify(builtInTranslations));
        let _currentLocale = 'en';

        function _mergeExternalTranslations() {
            if (typeof window.GSCS_Namespace !== 'undefined' && typeof window.GSCS_Namespace.i18nPack === 'object' && typeof window.GSCS_Namespace.i18nPack.translations === 'object') {
                const externalTranslations = window.GSCS_Namespace.i18nPack.translations;
                for (const langCode in externalTranslations) {
                    if (Object.prototype.hasOwnProperty.call(externalTranslations, langCode)) {
                        if (!effectiveTranslations[langCode]) {
                            effectiveTranslations[langCode] = {};
                        }
                        // Merge, allowing external to overwrite built-in for that specific key
                        for (const key in externalTranslations[langCode]) {
                            if (Object.prototype.hasOwnProperty.call(externalTranslations[langCode], key)) {
                                effectiveTranslations[langCode][key] = externalTranslations[langCode][key];
                            }
                        }
                    }
                }
            } else {
                console.warn(`${LOG_PREFIX} [i18n] External i18n pack (window.GSCS_Namespace.i18nPack) not found or invalid. Using built-in translations only.`);
            }
        }

        function _detectBrowserLocale() {
            let locale = 'en';
            try {
                if (navigator.languages && navigator.languages.length) {
                    locale = navigator.languages[0];
                } else if (navigator.language) {
                    locale = navigator.language;
                }
            } catch (e) {
                console.warn(`${LOG_PREFIX} [i18n] Error accessing navigator.language(s):`, e);
            }
            if (effectiveTranslations[locale]) return locale;
            if (locale.includes('-')) {
                const parts = locale.split('-');
                if (parts.length > 0 && effectiveTranslations[parts[0]]) return parts[0];
                if (parts.length > 2 && effectiveTranslations[`${parts[0]}-${parts[1]}`]) return `${parts[0]}-${parts[1]}`;
            }
            return 'en';
        }

        function _updateActiveLocale(settingsToUse) {
            let newLocale = 'en';
            const langSettingSource = (settingsToUse && Object.keys(settingsToUse).length > 0 && typeof settingsToUse.interfaceLanguage === 'string')
                ? settingsToUse
                : defaultSettings;
            const userSelectedLang = langSettingSource.interfaceLanguage;
            if (userSelectedLang && userSelectedLang !== 'auto') {
                if (effectiveTranslations[userSelectedLang]) {
                    newLocale = userSelectedLang;
                } else if (userSelectedLang.includes('-')) {
                    const genericLang = userSelectedLang.split('-')[0];
                    if (effectiveTranslations[genericLang]) {
                        newLocale = genericLang;
                    } else {
                        newLocale = _detectBrowserLocale();
                    }
                } else {
                    newLocale = _detectBrowserLocale();
                }
            } else {
                newLocale = _detectBrowserLocale();
            }
            if (_currentLocale !== newLocale) {
                _currentLocale = newLocale;
            }
            if (userSelectedLang && userSelectedLang !== 'auto' && _currentLocale !== userSelectedLang && !userSelectedLang.includes(_currentLocale)) {
                console.warn(`${LOG_PREFIX} [i18n] User selected language "${userSelectedLang}" was not fully available or matched. Using best match: "${_currentLocale}".`);
            }
        }

        _mergeExternalTranslations();

        function getString(key, replacements = {}) {
            let str = `[ERR: ${key} @ ${_currentLocale}]`;
            let found = false;
            if (effectiveTranslations[_currentLocale] && typeof effectiveTranslations[_currentLocale][key] !== 'undefined') {
                str = effectiveTranslations[_currentLocale][key];
                found = true;
            }
            else if (_currentLocale.includes('-')) {
                const genericLang = _currentLocale.split('-')[0];
                if (effectiveTranslations[genericLang] && typeof effectiveTranslations[genericLang][key] !== 'undefined') {
                    str = effectiveTranslations[genericLang][key];
                    found = true;
                }
            }
            if (!found && _currentLocale !== 'en') {
                if (effectiveTranslations['en'] && typeof effectiveTranslations['en'][key] !== 'undefined') {
                    str = effectiveTranslations['en'][key];
                    found = true;
                }
            }
            if (!found) {
                if (!(effectiveTranslations['en'] && typeof effectiveTranslations['en'][key] !== 'undefined')) {
                    console.error(`${LOG_PREFIX} [i18n] CRITICAL: Missing translation for key: "${key}" in BOTH locale: "${_currentLocale}" AND default locale "en".`);
                } else {
                    str = effectiveTranslations['en'][key];
                    found = true;
                }
                if(!found) str = `[ERR_NF: ${key}]`;
            }
            if (typeof str === 'string') {
                for (const placeholder in replacements) {
                    if (Object.prototype.hasOwnProperty.call(replacements, placeholder)) {
                        str = str.replace(new RegExp(`\\{${placeholder}\\}`, 'g'), replacements[placeholder]);
                    }
                }
            } else {
                console.error(`${LOG_PREFIX} [i18n] CRITICAL: Translation for key "${key}" is not a string:`, str);
                return `[INVALID_TYPE_FOR_KEY: ${key}]`;
            }
            return str;
        }

        return {
            getString: getString,
            getCurrentLocale: function() { return _currentLocale; },
            getTranslationsForLocale: function(locale = 'en') { return effectiveTranslations[locale] || effectiveTranslations['en']; },
            initializeBaseLocale: function() { _updateActiveLocale(defaultSettings); },
            updateActiveLocale: function(activeSettings) { _updateActiveLocale(activeSettings); },
            getAvailableLocales: function() {
                const locales = new Set(['auto', 'en']);
                Object.keys(effectiveTranslations).forEach(lang => {
                    if (Object.keys(effectiveTranslations[lang]).length > 0) {
                        locales.add(lang);
                    }
                });
                return Array.from(locales).sort((a, b) => {
                    if (a === 'auto') return -1;
                    if (b === 'auto') return 1;
                    if (a === 'en' && b !== 'auto') return -1;
                    if (b === 'en' && a !== 'auto') return 1;
                    let nameA = a, nameB = b;
                    try { nameA = new Intl.DisplayNames([a],{type:'language'}).of(a); } catch(e){}
                    try { nameB = new Intl.DisplayNames([b],{type:'language'}).of(b); } catch(e){}
                    return nameA.localeCompare(nameB);
                });
            }
        };
    })();
    const _ = LocalizationService.getString;

    const Utils = {
        debounce: function(func, wait) {
            let timeout;
            return function executedFunction(...args) {
                const context = this;
                const later = () => {
                    timeout = null;
                    func.apply(context, args);
                };
                clearTimeout(timeout);
                timeout = setTimeout(later, wait);
            };
        },
        mergeDeep: function(target, source) {
            if (!source) return target;
            target = target || {};
            for (const key in source) {
                if (Object.prototype.hasOwnProperty.call(source, key)) {
                    const targetValue = target[key];
                    const sourceValue = source[key];
                    if (sourceValue && typeof sourceValue === 'object' && !Array.isArray(sourceValue)) {
                        target[key] = Utils.mergeDeep(targetValue, sourceValue);
                    } else if (typeof sourceValue !== 'undefined') {
                        target[key] = sourceValue;
                    }
                }
            }
            return target;
        },
        clamp: function(num, min, max) {
            return Math.min(Math.max(num, min), max);
        },
        parseIconAndText: function(fullText) {
            const match = fullText.match(/^(\P{L}\P{N}\s*)+/u);
            let icon = '';
            let text = fullText;
            if (match && match[0].trim() !== '') {
                icon = match[0].trim();
                text = fullText.substring(icon.length).trim();
            }
            return { icon, text };
        },
        getCurrentURL: function() {
            try {
                return new URL(window.location.href);
            } catch (e) {
                console.error(`${LOG_PREFIX} Error creating URL object:`, e);
                return null;
            }
        }
    };
    const NotificationManager = (function() {
        let container = null;
        function init() {
            if (document.getElementById(IDS.NOTIFICATION_CONTAINER)) {
                container = document.getElementById(IDS.NOTIFICATION_CONTAINER);
                return;
            }
            container = document.createElement('div');
            container.id = IDS.NOTIFICATION_CONTAINER;
            if (document.body) {
                document.body.appendChild(container);
            } else {
                console.error(LOG_PREFIX + " NotificationManager.init(): document.body is not available!");
                container = null;
            }
        }
        function show(messageKey, messageArgs = {}, type = 'info', duration = 3000) {
            if (!container) {
                const alertMsg = (typeof _ === 'function' && _(messageKey, messageArgs) && !(_(messageKey, messageArgs).startsWith('[ERR:')))
                    ? _(messageKey, messageArgs)
                    : `${messageKey} (args: ${JSON.stringify(messageArgs)})`;
                alert(alertMsg);
                return null;
            }
            const notificationElement = document.createElement('div');
            notificationElement.classList.add(CSS.NOTIFICATION);
            const typeClass = CSS[`NTF_${type.toUpperCase()}`] || CSS.NTF_INFO;
            notificationElement.classList.add(typeClass);
            notificationElement.textContent = _(messageKey, messageArgs);
            if (duration <= 0) {
                const closeButton = document.createElement('span');
                closeButton.innerHTML = '×';
                closeButton.style.cursor = 'pointer';
                closeButton.style.marginLeft = '10px';
                closeButton.style.float = 'right';
                closeButton.onclick = () => notificationElement.remove();
                notificationElement.appendChild(closeButton);
            }
            container.appendChild(notificationElement);
            if (duration > 0) {
                setTimeout(() => {
                    notificationElement.style.opacity = '0';
                    setTimeout(() => notificationElement.remove(), 500);
                }, duration);
            }
            return notificationElement;
        }
        return { init: init, show: show };
    })();

    function createGenericListItem(index, item, listId, mapping) {
        const listItem = document.createElement('li');
        listItem.dataset[DATA_ATTR.INDEX] = index;
        listItem.dataset[DATA_ATTR.LIST_ID] = listId;
        listItem.dataset[DATA_ATTR.ITEM_ID] = item.id || item.value || item.url;
        listItem.draggable = true;
        const dragIconSpan = document.createElement('span');
        dragIconSpan.classList.add(CSS.DRAG_ICON);
        dragIconSpan.innerHTML = SVG_ICONS.dragGrip;
        listItem.appendChild(dragIconSpan);
        const textSpan = document.createElement('span');
        let displayText = item.text;
        let paramName = '';
        if (item.type === 'predefined' && item.originalKey) {
            displayText = _(item.originalKey);
            if (listId === IDS.COUNTRIES_LIST) {
                const parsed = Utils.parseIconAndText(displayText);
                displayText = `${parsed.icon} ${parsed.text}`.trim();
            }
        }
        if (mapping) {
            if (listId === IDS.LANG_LIST) paramName = ALL_SECTION_DEFINITIONS.find(s=>s.id === 'sidebar-section-language').param;
            else if (listId === IDS.COUNTRIES_LIST) paramName = ALL_SECTION_DEFINITIONS.find(s=>s.id === 'sidebar-section-country').param;
            else if (listId === IDS.SITES_LIST) paramName = 'site';
            else if (listId === IDS.TIME_LIST) paramName = ALL_SECTION_DEFINITIONS.find(s=>s.id === 'sidebar-section-time').param;
            else if (listId === IDS.FT_LIST) paramName = ALL_SECTION_DEFINITIONS.find(s=>s.id === 'sidebar-section-filetype').param;
        }
        const valueForDisplay = item.value || item.url || _('value_empty');
        textSpan.textContent = `${displayText} (${paramName}=${valueForDisplay})`;
        textSpan.title = textSpan.textContent;
        listItem.appendChild(textSpan);
        const controlsSpan = document.createElement('span');
        controlsSpan.classList.add(CSS.ITEM_CONTROLS);
        if (item.type === 'custom' || listId === IDS.SITES_LIST || listId === IDS.TIME_LIST || listId === IDS.FT_LIST) {
            controlsSpan.innerHTML =
                `<button class="${CSS.EDIT_CUSTOM_ITEM}" title="${_('modal_button_edit_title')}">${SVG_ICONS.edit}</button> ` +
                `<button class="${CSS.DELETE_CUSTOM_ITEM}" title="${_('modal_button_delete_title')}">${SVG_ICONS.delete}</button>`;
            listItem.dataset[DATA_ATTR.ITEM_TYPE] = 'custom';
        } else if (item.type === 'predefined') {
            controlsSpan.innerHTML =
                `<button class="${CSS.REMOVE_FROM_LIST_BTN}" title="${_('modal_button_remove_from_list_title')}">${SVG_ICONS.removeFromList}</button>`;
            listItem.dataset[DATA_ATTR.ITEM_TYPE] = 'predefined';
        }
        listItem.appendChild(controlsSpan);
        return listItem;
    }

    function populateListInModal(listId, items, contextElement = document) {
        const listElement = contextElement.querySelector(`#${listId}`);
        if (!listElement) {
            console.warn(`${LOG_PREFIX} List element not found: #${listId} in context`, contextElement);
            return;
        }
        listElement.innerHTML = '';
        const fragment = document.createDocumentFragment();
        const mapping = getListMapping(listId);
        if (!Array.isArray(items)) items = [];
        items.forEach((item, index) => {
            fragment.appendChild(createGenericListItem(index, item, listId, mapping));
        });
        listElement.appendChild(fragment);
    }

    function getListMapping(listId) {
        const listMappings = {
            [IDS.SITES_LIST]:     { itemsArrayKey: 'favoriteSites',           customItemsMasterKey: null,                 valueKey: 'url',   populateFn: populateListInModal, textInput: `#${IDS.NEW_SITE_NAME}`,    valueInput: `#${IDS.NEW_SITE_URL}`,    addButton: `#${IDS.ADD_SITE_BTN}`,    nameKey: 'section_site_search', isSortableMixed: false, predefinedSourceKey: null },
            [IDS.LANG_LIST]:      { itemsArrayKey: 'displayLanguages',        customItemsMasterKey: 'customLanguages',    valueKey: 'value', populateFn: populateListInModal, textInput: `#${IDS.NEW_LANG_TEXT}`,    valueInput: `#${IDS.NEW_LANG_VALUE}`,    addButton: `#${IDS.ADD_LANG_BTN}`,    nameKey: 'section_language',    isSortableMixed: true,  predefinedSourceKey: 'language' },
            [IDS.COUNTRIES_LIST]: { itemsArrayKey: 'displayCountries',      customItemsMasterKey: 'customCountries',  valueKey: 'value', populateFn: populateListInModal, textInput: `#${IDS.NEW_COUNTRY_TEXT}`, valueInput: `#${IDS.NEW_COUNTRY_VALUE}`, addButton: `#${IDS.ADD_COUNTRY_BTN}`, nameKey: 'section_country',   isSortableMixed: true,  predefinedSourceKey: 'country' },
            [IDS.TIME_LIST]:      { itemsArrayKey: 'customTimeRanges',        customItemsMasterKey: null,                 valueKey: 'value', populateFn: populateListInModal, textInput: `#${IDS.NEW_TIME_TEXT}`,    valueInput: `#${IDS.NEW_TIME_VALUE}`,    addButton: `#${IDS.ADD_TIME_BTN}`,    nameKey: 'section_time',        isSortableMixed: false, predefinedSourceKey: 'time' },
            [IDS.FT_LIST]:        { itemsArrayKey: 'customFiletypes',         customItemsMasterKey: null,                 valueKey: 'value', populateFn: populateListInModal, textInput: `#${IDS.NEW_FT_TEXT}`,      valueInput: `#${IDS.NEW_FT_VALUE}`,      addButton: `#${IDS.ADD_FT_BTN}`,      nameKey: 'section_filetype',    isSortableMixed: false, predefinedSourceKey: 'filetype' },
        };
        return listMappings[listId] || null;
    }

    function validateCustomInput(inputElement) {
        if (!inputElement) return false;
        const value = inputElement.value.trim();
        const id = inputElement.id;
        let isValid = false;
        let isEmpty = value === '';
        if (id === IDS.NEW_SITE_NAME || id === IDS.NEW_LANG_TEXT || id === IDS.NEW_TIME_TEXT || id === IDS.NEW_FT_TEXT || id === IDS.NEW_COUNTRY_TEXT) {
            isValid = !isEmpty;
        } else if (id === IDS.NEW_SITE_URL) {
            isValid = isEmpty || /^(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,})$|(?:^\.(?:[a-zA-Z0-9-]{1,63}\.)*[a-zA-Z]{2,63}$)/.test(value);
        } else if (id === IDS.NEW_LANG_VALUE) {
            isValid = isEmpty || /^lang_[a-zA-Z]{2,3}(?:-[a-zA-Z0-9]{2,4})?(?:\|lang_[a-zA-Z]{2,3}(?:-[a-zA-Z0-9]{2,4})?)*$/.test(value);
        } else if (id === IDS.NEW_TIME_VALUE) {
            isValid = isEmpty || /^[hdwmy]\d*$/.test(value);
        } else if (id === IDS.NEW_FT_VALUE) {
            isValid = isEmpty || /^[a-zA-Z0-9]+$/.test(value);
        } else if (id === IDS.NEW_COUNTRY_VALUE) {
            isValid = isEmpty || /^country[A-Z]{2}$/.test(value);
        }
        inputElement.classList.remove('input-valid', 'input-invalid', CSS.INPUT_HAS_ERROR);
        _clearInputError(inputElement);
        if (!isEmpty) {
            inputElement.classList.add(isValid ? 'input-valid' : 'input-invalid');
            if (!isValid) inputElement.classList.add(CSS.INPUT_HAS_ERROR);
        }
        return isValid || isEmpty;
    }
    function _getInputErrorElement(inputElement) {
        if (!inputElement || !inputElement.id) return null;
        let errorEl = inputElement.nextElementSibling;
        if (errorEl && errorEl.classList.contains(CSS.INPUT_ERROR_MESSAGE) && errorEl.id === `${inputElement.id}-error-msg`) {
            return errorEl;
        }
        const parentDiv = inputElement.parentElement;
        if (parentDiv) {
            return parentDiv.querySelector(`#${inputElement.id}-error-msg`);
        }
        return null;
    }
    function _showInputError(inputElement, messageKey, messageArgs = {}) {
        if (!inputElement) return;
        const errorElement = _getInputErrorElement(inputElement);
        if (errorElement) {
            errorElement.textContent = _(messageKey, messageArgs);
            errorElement.classList.add(CSS.ERROR_VISIBLE);
        }
        inputElement.classList.add(CSS.INPUT_HAS_ERROR);
        inputElement.classList.remove('input-valid');
    }
    function _clearInputError(inputElement) {
        if (!inputElement) return;
        const errorElement = _getInputErrorElement(inputElement);
        if (errorElement) {
            errorElement.textContent = '';
            errorElement.classList.remove(CSS.ERROR_VISIBLE);
        }
        inputElement.classList.remove(CSS.INPUT_HAS_ERROR, 'input-invalid');
    }
    function _clearAllInputErrorsInGroup(inputGroupElement) {
        if (!inputGroupElement) return;
        inputGroupElement.querySelectorAll(`input[type="text"]`).forEach(input => {
            _clearInputError(input);
            input.classList.remove('input-valid', 'input-invalid');
        });
    }
    function _showGlobalMessage(messageKey, messageArgs = {}, type = 'info', duration = 3000, targetElementId = IDS.SETTINGS_MESSAGE_BAR) {
        const messageBar = document.getElementById(targetElementId);
        if (!messageBar) {
            if (targetElementId !== IDS.SETTINGS_MESSAGE_BAR && NotificationManager && typeof NotificationManager.show === 'function') {
                NotificationManager.show(messageKey, messageArgs, type, duration > 0 ? duration : 5000);
            } else {
                const alertMsg = (typeof _ === 'function' && _(messageKey, messageArgs) && !(_(messageKey, messageArgs).startsWith('[ERR:')))
                    ? _(messageKey, messageArgs)
                    : `${messageKey} (args: ${JSON.stringify(messageArgs)})`;
                alert(alertMsg);
            }
            return;
        }
        if (globalMessageTimeout && targetElementId === IDS.SETTINGS_MESSAGE_BAR) {
            clearTimeout(globalMessageTimeout);
            globalMessageTimeout = null;
        }
        messageBar.textContent = _(messageKey, messageArgs);
        messageBar.className = `${CSS.MESSAGE_BAR}`;
        messageBar.classList.add(CSS[`MSG_${type.toUpperCase()}`] || CSS.MSG_INFO);
        messageBar.style.display = 'block';
        if (duration > 0 && targetElementId === IDS.SETTINGS_MESSAGE_BAR) {
            globalMessageTimeout = setTimeout(() => {
                messageBar.style.display = 'none';
                messageBar.textContent = '';
                messageBar.className = CSS.MESSAGE_BAR;
            }, duration);
        }
    }
    function _validateAndPrepareCustomItemData(textInput, valueInput, itemTypeName, listId) {
        if (!textInput || !valueInput) {
            _showGlobalMessage('alert_edit_failed_missing_fields', {}, 'error', 0);
            return { isValid: false };
        }
        _clearInputError(textInput);
        _clearInputError(valueInput);
        const text = textInput.value.trim();
        const value = valueInput.value.trim();
        let hint = '';
        if (text === '') {
            _showInputError(textInput, 'alert_enter_display_name', { type: itemTypeName });
            textInput.focus();
            return { isValid: false, errorField: textInput };
        } else {
            textInput.classList.remove(CSS.INPUT_HAS_ERROR);
            validateCustomInput(textInput);
        }
        if (value === '') {
            _showInputError(valueInput, 'alert_enter_value', { type: itemTypeName });
            valueInput.focus();
            return { isValid: false, errorField: valueInput };
        } else {
            const isValueFormatValid = validateCustomInput(valueInput);
            if (!isValueFormatValid && !valueInput.classList.contains('input-invalid')) {
                if (listId === IDS.COUNTRIES_LIST) hint = _('modal_tooltip_country');
                else if (listId === IDS.LANG_LIST) hint = _('modal_tooltip_language');
                else if (listId === IDS.TIME_LIST) hint = _('modal_tooltip_time');
                else if (listId === IDS.FT_LIST) hint = _('modal_tooltip_filetype');
                else if (listId === IDS.SITES_LIST) hint = _('modal_tooltip_domain');
                _showInputError(valueInput, 'alert_invalid_value_format', { type: itemTypeName, hint: hint });
                valueInput.focus();
                return { isValid: false, errorField: valueInput };
            } else if (!isValueFormatValid) {
                valueInput.focus();
                return { isValid: false, errorField: valueInput };
            } else {
                 valueInput.classList.remove(CSS.INPUT_HAS_ERROR);
            }
        }
        textInput.classList.remove(CSS.INPUT_HAS_ERROR);
        valueInput.classList.remove(CSS.INPUT_HAS_ERROR);
        return { isValid: true, text: text, value: value };
    }
    function _isDuplicateCustomItem(text, itemsToCheck, listId, editingIndex, editingItemInfoRef) {
        const lowerText = text.toLowerCase();
        return itemsToCheck.some((item, idx) => {
            const itemIsCustom = item.type === 'custom' || listId === IDS.SITES_LIST || listId === IDS.TIME_LIST || listId === IDS.FT_LIST;
            if (!itemIsCustom) return false;
            if (editingItemInfoRef && editingItemInfoRef.listId === listId && editingIndex === idx) {
                if (editingItemInfoRef.originalText?.toLowerCase() === lowerText) {
                    return false;
                }
            }
            return item.text.toLowerCase() === lowerText;
        });
    }
    function applyThemeToElement(element, themeSetting) {
        if (!element) return;
        element.classList.remove( CSS.LIGHT_THEME, CSS.DARK_THEME, 'minimal-theme', 'minimal-light', 'minimal-dark' );
        let effectiveTheme = themeSetting;
        const isSettingsOrModal = element.id === IDS.SETTINGS_WINDOW || element.id === IDS.SETTINGS_OVERLAY || element.classList.contains('settings-modal-content') || element.classList.contains('settings-modal-overlay');
        if (isSettingsOrModal) {
            if (themeSetting === 'minimal-light') effectiveTheme = 'light';
            else if (themeSetting === 'minimal-dark') effectiveTheme = 'dark';
        }
        switch (effectiveTheme) {
            case 'dark': element.classList.add(CSS.DARK_THEME); break;
            case 'minimal-light': element.classList.add('minimal-theme', 'minimal-light'); break;
            case 'minimal-dark':  element.classList.add('minimal-theme', 'minimal-dark'); break;
            case 'system': const systemIsDark = systemThemeMediaQuery && systemThemeMediaQuery.matches; element.classList.add(systemIsDark ? CSS.DARK_THEME : CSS.LIGHT_THEME); break;
            case 'light': default: element.classList.add(CSS.LIGHT_THEME); break;
        }
    }

    // --- End of Part 1 (gscs-base.user.js) ---

	// --- START OF PART 2 (gscs-base.user.js) ---

    const PredefinedOptionChooser = (function() {
        let _chooserContainer = null;
        let _currentListId = null;
        let _currentPredefinedSourceKey = null;
        let _currentDisplayItemsArrayRef = null;
        let _currentModalContentContext = null;
        let _onAddCallback = null;

        function _buildChooserHTML(listId, predefinedSourceKey, displayItemsArrayRef) {
            const allPredefinedSystemOptions = PREDEFINED_OPTIONS[predefinedSourceKey] || [];
            const currentDisplayedValues = new Set(displayItemsArrayRef.filter(item => item.type === 'predefined').map(item => item.value));
            const availablePredefinedToAdd = allPredefinedSystemOptions.filter(opt => !currentDisplayedValues.has(opt.value));

            if (availablePredefinedToAdd.length === 0) {
                const itemTypeName = getListMapping(listId)?.nameKey ? _(getListMapping(listId).nameKey) : predefinedSourceKey;
                _showGlobalMessage('alert_no_more_predefined_to_add', { type: itemTypeName }, 'info', 3000, IDS.SETTINGS_MESSAGE_BAR);
                return null;
            }

            let listHTML = `<ul id="${IDS.MODAL_PREDEFINED_CHOOSER_LIST}">`;
            availablePredefinedToAdd.forEach(opt => {
                let displayText = _(opt.textKey);
                 if (listId === IDS.COUNTRIES_LIST) {
                    const parsed = Utils.parseIconAndText(displayText);
                    displayText = `${parsed.icon} ${parsed.text}`.trim();
                }
                listHTML += `<li class="${CSS.MODAL_PREDEFINED_CHOOSER_ITEM}"><input type="checkbox" value="${opt.value}" id="chooser-${opt.value.replace(/[^a-zA-Z0-9]/g, '')}"><label for="chooser-${opt.value.replace(/[^a-zA-Z0-9]/g, '')}">${displayText}</label></li>`;
            });
            listHTML += `</ul>`;

            const buttonsHTML = `
                <div class="chooser-buttons" style="text-align: right; margin-top: 10px;">
                    <button id="${IDS.MODAL_PREDEFINED_CHOOSER_ADD_BTN}" class="${CSS.TOOL_BUTTON}" style="margin-right: 5px;">${_('modal_button_add_title')}</button>
                    <button id="${IDS.MODAL_PREDEFINED_CHOOSER_CANCEL_BTN}" class="${CSS.TOOL_BUTTON}">${_('settings_cancel_button')}</button>
                </div>`;
            return listHTML + buttonsHTML;
        }

        function _handleAdd() {
            if (!_chooserContainer) return;
            const selectedValues = [];
            _chooserContainer.querySelectorAll(`#${IDS.MODAL_PREDEFINED_CHOOSER_LIST} input[type="checkbox"]:checked`).forEach(cb => {
                selectedValues.push(cb.value);
            });

            if (selectedValues.length > 0 && typeof _onAddCallback === 'function') {
                _onAddCallback(selectedValues, _currentPredefinedSourceKey, _currentDisplayItemsArrayRef, _currentListId, _currentModalContentContext);
            }
            hide();
        }

        function show(manageType, listId, predefinedSourceKey, displayItemsArrayRef, contextElement, onAddCb) {
            hide();
            _currentListId = listId;
            _currentPredefinedSourceKey = predefinedSourceKey;
            _currentDisplayItemsArrayRef = displayItemsArrayRef;
            _currentModalContentContext = contextElement;
            _onAddCallback = onAddCb;

            const chooserHTML = _buildChooserHTML(listId, predefinedSourceKey, displayItemsArrayRef);
            if (!chooserHTML) return;

            _chooserContainer = document.createElement('div');
            _chooserContainer.id = IDS.MODAL_PREDEFINED_CHOOSER_CONTAINER;
            _chooserContainer.classList.add(CSS.MODAL_PREDEFINED_CHOOSER_CLASS);
            _chooserContainer.innerHTML = chooserHTML;

            const addNewBtn = contextElement.querySelector(`#${IDS.MODAL_ADD_NEW_OPTION_BTN}`);
            if (addNewBtn && addNewBtn.parentNode) {
                addNewBtn.insertAdjacentElement('afterend', _chooserContainer);
            } else {
                const mainListElement = contextElement.querySelector(`#${listId}`);
                mainListElement?.insertAdjacentElement('beforebegin', _chooserContainer);
            }
            _chooserContainer.style.display = 'block';

            _chooserContainer.querySelector(`#${IDS.MODAL_PREDEFINED_CHOOSER_ADD_BTN}`).addEventListener('click', _handleAdd);
            _chooserContainer.querySelector(`#${IDS.MODAL_PREDEFINED_CHOOSER_CANCEL_BTN}`).addEventListener('click', hide);
        }

        function hide() {
            if (_chooserContainer) {
                _chooserContainer.remove();
                _chooserContainer = null;
            }
            _currentListId = null;
            _currentPredefinedSourceKey = null;
            _currentDisplayItemsArrayRef = null;
            _currentModalContentContext = null;
            _onAddCallback = null;
        }

        return {
            show: show,
            hide: hide,
            isOpen: function() { return !!_chooserContainer; }
        };
    })();


    const ModalManager = (function() {
        let _currentModal = null;
        let _currentModalContent = null;
        let _editingItemInfo = null;
        let _draggedListItem = null;

        const modalConfigsData = {
            'site':     { modalTitleKey: 'manageSitesTitle',     listId: IDS.SITES_LIST,     itemsArrayKey: 'favoriteSites',           customItemsMasterKey: null,                 textPKey: 'modal_placeholder_name',   valPKey: 'modal_placeholder_domain', hintKey: 'modal_hint_domain',   fmtKey: 'modal_tooltip_domain',   isSortableMixed: false, predefinedSourceKey: null,       manageType: 'site' },
            'language': { modalTitleKey: 'manageLanguagesTitle', listId: IDS.LANG_LIST,      itemsArrayKey: 'displayLanguages',        customItemsMasterKey: 'customLanguages',    textPKey: 'modal_placeholder_text',   valPKey: 'modal_placeholder_value',  hintKey: 'modal_hint_language', fmtKey: 'modal_tooltip_language', predefinedSourceKey: 'language', isSortableMixed: true,         manageType: 'language' },
            'country':  { modalTitleKey: 'manageCountriesTitle', listId: IDS.COUNTRIES_LIST, itemsArrayKey: 'displayCountries',      customItemsMasterKey: 'customCountries',  textPKey: 'modal_placeholder_text',   valPKey: 'modal_placeholder_value',  hintKey: 'modal_hint_country',  fmtKey: 'modal_tooltip_country',  predefinedSourceKey: 'country',  isSortableMixed: true,         manageType: 'country' },
            'time':     { modalTitleKey: 'manageTimeRangesTitle',listId: IDS.TIME_LIST,      itemsArrayKey: 'customTimeRanges',        customItemsMasterKey: null,                 textPKey: 'modal_placeholder_text',   valPKey: 'modal_placeholder_value',  hintKey: 'modal_hint_time',     fmtKey: 'modal_tooltip_time',     predefinedSourceKey: 'time',     isSortableMixed: false,        manageType: 'time' },
            'filetype': { modalTitleKey: 'manageFileTypesTitle', listId: IDS.FT_LIST,        itemsArrayKey: 'customFiletypes',         customItemsMasterKey: null,                 textPKey: 'modal_placeholder_text',   valPKey: 'modal_placeholder_value',  hintKey: 'modal_hint_filetype', fmtKey: 'modal_tooltip_filetype', predefinedSourceKey: 'filetype', isSortableMixed: false,        manageType: 'filetype' },
        };

        function _createPredefinedOptionsSectionHTML(currentOptionType, typeNameKey, predefinedOptionsSource, enabledPredefinedValues) {
            const label = _(typeNameKey);
            const optionsHTML = (predefinedOptionsSource[currentOptionType] || []).map(option => {
                const checkboxId = `predefined-${currentOptionType}-${option.value.replace(/[^a-zA-Z0-9-_]/g, '')}`;
                const translatedOptionText = _(option.textKey);
                const isChecked = enabledPredefinedValues.has(option.value);
                return `<li><input type="checkbox" id="${checkboxId}" value="${option.value}" data-option-type="${currentOptionType}" ${isChecked ? 'checked' : ''}><label for="${checkboxId}">${translatedOptionText}</label></li>`;
            }).join('');
            return `<label style="font-weight: bold;">${_('modal_label_enable_predefined', { type: label })}</label><ul class="predefined-options-list" data-option-type="${currentOptionType}">${optionsHTML}</ul>`;
        }

        function _createModalListAndInputHTML(currentListId, textPlaceholderKey, valuePlaceholderKey, hintKey, formatTooltipKey, itemTypeName, isSortableMixed = false) {
            const mapping = getListMapping(currentListId);
            const typeNameToDisplay = itemTypeName || (mapping ? _(mapping.nameKey) : 'Items');
            let headerHTML = '';
            let addNewOptionButtonHTML = '';
            if (isSortableMixed) {
                headerHTML = `<label style="font-weight: bold; margin-top: 0.5em; display: block;">${_('modal_label_display_options_for', {type: typeNameToDisplay})}</label>`;
                addNewOptionButtonHTML = `<div style="margin-bottom: 0.5em;"><button id="${IDS.MODAL_ADD_NEW_OPTION_BTN}" class="${CSS.MODAL_ADD_NEW_OPTION_BTN_CLASS} ${CSS.TOOL_BUTTON}">${_('modal_button_add_new_option')}</button></div>`;
            } else {
                 headerHTML = `<label style="font-weight: bold; margin-top: 0.5em; display: block;">${_('modal_label_my_custom', { type: typeNameToDisplay })}</label>`;
            }
            const textInputId = mapping ? mapping.textInput.substring(1) : `new-custom-${currentListId}-text`;
            const valueInputId = mapping ? mapping.valueInput.substring(1) : `new-custom-${currentListId}-value`;
            const addButtonId = mapping ? mapping.addButton.substring(1) : `add-custom-${currentListId}-button`;
            const inputGroupHTML = `<div class="${CSS.CUSTOM_LIST_INPUT_GROUP}"><div><input type="text" id="${textInputId}" placeholder="${_(textPlaceholderKey)}"><span id="${textInputId}-error-msg" class="${CSS.INPUT_ERROR_MESSAGE}"></span></div><div><input type="text" id="${valueInputId}" placeholder="${_(valuePlaceholderKey)}" title="${_(formatTooltipKey)}"><span id="${valueInputId}-error-msg" class="${CSS.INPUT_ERROR_MESSAGE}"></span></div><button id="${addButtonId}" class="${CSS.ADD_CUSTOM_BUTTON} custom-list-action-button" data-list-id="${currentListId}" title="${_('modal_button_add_title')}">${SVG_ICONS.add}</button><button class="cancel-edit-button" style="display: none;" title="${_('modal_button_cancel_edit_title')}">${SVG_ICONS.close}</button></div>`;
            const hintHTML = `<span class="setting-value-hint">${_(hintKey)}</span>`;
            return `${addNewOptionButtonHTML}${headerHTML}<ul id="${currentListId}" class="${CSS.CUSTOM_LIST}"></ul>${inputGroupHTML}${hintHTML}`;
        }

        function _resetEditStateInternal(contextElement = _currentModalContent) {
            if (_editingItemInfo) {
                const mapping = getListMapping(_editingItemInfo.listId);
                if (_editingItemInfo.addButton) {
                    _editingItemInfo.addButton.innerHTML = SVG_ICONS.add;
                    _editingItemInfo.addButton.title = _('modal_button_add_title');
                    _editingItemInfo.addButton.classList.remove('update-mode');
                }
                if (_editingItemInfo.cancelButton) {
                    _editingItemInfo.cancelButton.style.display = 'none';
                }
                if (mapping && contextElement) {
                    const textInput = contextElement.querySelector(mapping.textInput);
                    const valueInput = contextElement.querySelector(mapping.valueInput);
                    const inputGroup = textInput?.closest(`.${CSS.CUSTOM_LIST_INPUT_GROUP}`);
                    if(inputGroup) _clearAllInputErrorsInGroup(inputGroup);
                    if (textInput) { textInput.value = ''; textInput.classList.remove('input-valid', 'input-invalid', CSS.INPUT_HAS_ERROR); _clearInputError(textInput); }
                    if (valueInput) { valueInput.value = ''; valueInput.classList.remove('input-valid', 'input-invalid', CSS.INPUT_HAS_ERROR); _clearInputError(valueInput); }
                }
            }
            _editingItemInfo = null;
        }
        function _prepareEditItemActionInternal(item, index, listId, mapping, contextElement) {
            const textInput = contextElement.querySelector(mapping.textInput);
            const valueInput = contextElement.querySelector(mapping.valueInput);
            const addButton = contextElement.querySelector(mapping.addButton);
            const cancelButton = addButton?.parentElement?.querySelector('.cancel-edit-button');
            if (textInput && valueInput && addButton && cancelButton) {
                if (_editingItemInfo && (_editingItemInfo.listId !== listId || _editingItemInfo.index !== index)) {
                    _resetEditStateInternal(contextElement);
                }
                textInput.value = item.text;
                valueInput.value = item[mapping.valueKey] || item.value;
                _editingItemInfo = { listId, index, originalValue: item[mapping.valueKey] || item.value, originalText: item.text, addButton, cancelButton, arrayKey: mapping.itemsArrayKey || mapping.displayArrayKey };
                addButton.innerHTML = SVG_ICONS.update; addButton.title = _('modal_button_update_title'); addButton.classList.add('update-mode');
                cancelButton.style.display = 'inline-block';
                validateCustomInput(valueInput); validateCustomInput(textInput);
                textInput.focus();
            } else {
                const errorSourceInput = textInput || valueInput || addButton?.closest(`.${CSS.CUSTOM_LIST_INPUT_GROUP}`)?.querySelector('input[type="text"]');
                if (errorSourceInput) _showInputError(errorSourceInput, 'alert_edit_failed_missing_fields');
                else _showGlobalMessage('alert_edit_failed_missing_fields', {}, 'error', 0, _currentModalContent?.querySelector(`#${IDS.SETTINGS_MESSAGE_BAR}`) ? IDS.SETTINGS_MESSAGE_BAR : null);
            }
        }
        function _handleCustomListActionsInternal(event, contextElement, itemsArrayRef) {
            const button = event.target.closest(`button.${CSS.EDIT_CUSTOM_ITEM}, button.${CSS.DELETE_CUSTOM_ITEM}, button.${CSS.REMOVE_FROM_LIST_BTN}`);
            if (!button) return;
            const listItem = button.closest(`li[data-${DATA_ATTR.INDEX}][data-list-id]`);
            if (!listItem) return;
            const index = parseInt(listItem.dataset[DATA_ATTR.INDEX], 10);
            const listId = listItem.getAttribute('data-list-id');
            if (isNaN(index) || !listId || index < 0 || index >= itemsArrayRef.length) return;
            const mapping = getListMapping(listId);
            if (!mapping) return;
            const item = itemsArrayRef[index];
            if (!item) return;
            const itemIsTrulyCustom = item.type === 'custom' || (!item.type && (listId === IDS.SITES_LIST || listId === IDS.TIME_LIST || listId === IDS.FT_LIST));
            if (button.classList.contains(CSS.DELETE_CUSTOM_ITEM) && itemIsTrulyCustom) {
                if (confirm(_('confirm_delete_item', { name: item.text }))) {
                    if (_editingItemInfo && _editingItemInfo.listId === listId && _editingItemInfo.index === index) {
                        _resetEditStateInternal(contextElement);
                    }
                    itemsArrayRef.splice(index, 1);
                    mapping.populateFn(listId, itemsArrayRef, contextElement);
                }
            } else if (button.classList.contains(CSS.REMOVE_FROM_LIST_BTN) && item.type === 'predefined') {
                if (confirm(_('confirm_remove_item_from_list', { name: (item.originalKey ? _(item.originalKey) : item.text) }))) {
                    itemsArrayRef.splice(index, 1);
                    mapping.populateFn(listId, itemsArrayRef, contextElement);
                }
            } else if (button.classList.contains(CSS.EDIT_CUSTOM_ITEM) && itemIsTrulyCustom) {
                _prepareEditItemActionInternal(item, index, listId, mapping, contextElement);
            }
        }
        function _handleCustomItemSubmitInternal(listId, contextElement, itemsArrayRef) {
            const mapping = getListMapping(listId);
            if (!mapping) return;
            const itemTypeName = _(mapping.nameKey);
            const textInput = contextElement.querySelector(mapping.textInput);
            const valueInput = contextElement.querySelector(mapping.valueInput);
            const inputGroup = textInput?.closest(`.${CSS.CUSTOM_LIST_INPUT_GROUP}`);
            if (inputGroup) _clearAllInputErrorsInGroup(inputGroup);
            const validationResult = _validateAndPrepareCustomItemData(textInput, valueInput, itemTypeName, listId);
            if (!validationResult.isValid) {
                if (validationResult.errorField) validationResult.errorField.focus();
                return;
            }
            const { text, value } = validationResult;
            const editingIdx = (_editingItemInfo && _editingItemInfo.listId === listId) ? _editingItemInfo.index : -1;
            let isDuplicate;
            if (mapping.isSortableMixed) {
                isDuplicate = _isDuplicateCustomItem(text, itemsArrayRef, listId, editingIdx, _editingItemInfo);
            } else {
                isDuplicate = itemsArrayRef.some((item, idx) => {
                    if (editingIdx === idx && (_editingItemInfo?.originalText?.toLowerCase() === text.toLowerCase())) return false;
                    return item.text.toLowerCase() === text.toLowerCase();
                });
            }
            if (isDuplicate) {
                if (textInput) _showInputError(textInput, 'alert_duplicate_name', { name: text });
                textInput?.focus(); return;
            }
            let newItemData;
            if (listId === IDS.SITES_LIST) {
                newItemData = { text: text, url: value };
            } else if (mapping.isSortableMixed) {
                newItemData = { id: value, text: text, value: value, type: 'custom' };
            } else {
                newItemData = { text: text, value: value };
            }
            const itemBeingEdited = (editingIdx > -1) ? itemsArrayRef[editingIdx] : null;
            const itemBeingEditedIsCustom = itemBeingEdited && (itemBeingEdited.type === 'custom' || listId === IDS.SITES_LIST || listId === IDS.TIME_LIST || listId === IDS.FT_LIST);
            if (editingIdx > -1 && itemBeingEditedIsCustom) {
                itemsArrayRef[editingIdx] = {...itemsArrayRef[editingIdx], ...newItemData };
                _resetEditStateInternal(contextElement);
            } else {
                itemsArrayRef.push(newItemData);
            }
            mapping.populateFn(listId, itemsArrayRef, contextElement);
            if (textInput) { textInput.value = ''; _clearInputError(textInput); textInput.focus(); }
            if (valueInput) { valueInput.value = ''; _clearInputError(valueInput); }
        }
        function _getDragAfterModalListItem(container, y) {
            const draggableElements = [...container.querySelectorAll(`li[draggable="true"]:not(.${CSS.DRAGGING_ITEM})`)];
            return draggableElements.reduce((closest, child) => {
                const box = child.getBoundingClientRect();
                const offset = y - box.top - box.height / 2;
                if (offset < 0 && offset > closest.offset) { return { offset: offset, element: child }; }
                else { return closest; }
            }, { offset: Number.NEGATIVE_INFINITY }).element;
        }
        function _handleModalListDragStart(event) {
            if (!event.target.matches('li[draggable="true"]')) return;
            _draggedListItem = event.target;
            event.dataTransfer.effectAllowed = 'move';
            event.dataTransfer.setData('text/plain', _draggedListItem.dataset.index);
            _draggedListItem.classList.add(CSS.DRAGGING_ITEM);
            const list = _draggedListItem.closest('ul');
            if (list) { list.querySelectorAll('li:not(.gscs-dragging-item)').forEach(li => li.style.pointerEvents = 'none'); }
        }
        function _handleModalListDragOver(event) {
            event.preventDefault();
            const listElement = event.currentTarget;
            listElement.querySelectorAll(`li.${CSS.DRAG_OVER_HIGHLIGHT}`).forEach(li => li.classList.remove(CSS.DRAG_OVER_HIGHLIGHT));
            const targetItem = event.target.closest('li[draggable="true"]');
            if (targetItem && targetItem !== _draggedListItem) {
                targetItem.classList.add(CSS.DRAG_OVER_HIGHLIGHT);
            } else {
                const afterElement = _getDragAfterModalListItem(listElement, event.clientY);
                if (afterElement) { afterElement.classList.add(CSS.DRAG_OVER_HIGHLIGHT); }
            }
        }
        function _handleModalListDragLeave(event) {
            const listElement = event.currentTarget;
            if (event.relatedTarget && listElement.contains(event.relatedTarget)) return;
            listElement.querySelectorAll(`li.${CSS.DRAG_OVER_HIGHLIGHT}`).forEach(li => li.classList.remove(CSS.DRAG_OVER_HIGHLIGHT));
        }
        function _handleModalListDrop(event, listId, itemsArrayRef) {
            event.preventDefault();
            if (!_draggedListItem) return;
            const draggedIndexOriginal = parseInt(event.dataTransfer.getData('text/plain'), 10);
            if (isNaN(draggedIndexOriginal) || draggedIndexOriginal < 0 || draggedIndexOriginal >= itemsArrayRef.length) {
                _handleModalListDragEnd(event.currentTarget); return;
            }
            const listElement = event.currentTarget;
            const mapping = getListMapping(listId);
            if (!mapping) { _handleModalListDragEnd(listElement); return; }
            const draggedItemData = itemsArrayRef[draggedIndexOriginal];
            if (!draggedItemData) { _handleModalListDragEnd(listElement); return; }
            const itemsWithoutDragged = itemsArrayRef.filter((item, index) => index !== draggedIndexOriginal);
            const afterElement = _getDragAfterModalListItem(listElement, event.clientY);
            let newIndexInSplicedArray;
            if (afterElement) {
                const originalIndexOfAfterElement = parseInt(afterElement.dataset.index, 10);
                let countSkipped = 0; newIndexInSplicedArray = -1;
                for(let i=0; i < itemsArrayRef.length; i++) {
                    if (i === draggedIndexOriginal) continue;
                    if (i === originalIndexOfAfterElement) { newIndexInSplicedArray = countSkipped; break; }
                    countSkipped++;
                }
                if (newIndexInSplicedArray === -1 && originalIndexOfAfterElement === itemsArrayRef.length -1 && draggedIndexOriginal < originalIndexOfAfterElement) {
                    newIndexInSplicedArray = itemsWithoutDragged.length;
                } else if (newIndexInSplicedArray === -1) {
                    newIndexInSplicedArray = itemsWithoutDragged.length;
                }
            } else {
                newIndexInSplicedArray = itemsWithoutDragged.length;
            }
            itemsWithoutDragged.splice(newIndexInSplicedArray, 0, draggedItemData);
            itemsArrayRef.length = 0;
            itemsWithoutDragged.forEach(item => itemsArrayRef.push(item));
            _handleModalListDragEnd(listElement);
            mapping.populateFn(listId, itemsArrayRef, _currentModalContent);
            const newLiElements = listElement.querySelectorAll('li');
            newLiElements.forEach((li, idx) => { li.dataset.index = idx; });
        }
        function _handleModalListDragEnd(listElement) {
            if (_draggedListItem) {
                _draggedListItem.classList.remove(CSS.DRAGGING_ITEM);
            }
            _draggedListItem = null;
            (listElement || _currentModalContent)?.querySelectorAll(`li.${CSS.DRAG_OVER_HIGHLIGHT}`).forEach(li => li.classList.remove(CSS.DRAG_OVER_HIGHLIGHT));
            _currentModalContent?.querySelectorAll('ul.custom-list li[draggable="true"]').forEach(li => li.style.pointerEvents = '');
        }

        function _addPredefinedItemsToModalList(selectedValues, predefinedSourceKey, displayItemsArrayRef, listIdToUpdate, modalContentContext) {
            const mapping = getListMapping(listIdToUpdate);
            if (!mapping) return;

            selectedValues.forEach(value => {
                const predefinedOpt = PREDEFINED_OPTIONS[predefinedSourceKey]?.find(p => p.value === value);
                if (predefinedOpt && !displayItemsArrayRef.some(item => item.value === value && item.type === 'predefined')) {
                    displayItemsArrayRef.push({
                        id: predefinedOpt.value, text: _(predefinedOpt.textKey),
                        value: predefinedOpt.value, type: 'predefined', originalKey: predefinedOpt.textKey
                    });
                }
            });
            mapping.populateFn(listIdToUpdate, displayItemsArrayRef, modalContentContext);
        }

        function _bindModalContentEventsInternal(modalContent, itemsArrayRef, listIdForDragDrop = null) {
            if (!modalContent) return;
            if (modalContent.dataset.modalEventsBound === 'true' && listIdForDragDrop === modalContent.dataset.boundListId) return;

            modalContent.addEventListener('click', (event) => {
                const target = event.target;
                let listIdForAction = listIdForDragDrop || target.closest('[data-list-id]')?.dataset.listId || target.closest(`.${CSS.ADD_CUSTOM_BUTTON}`)?.dataset.listId;

                const addNewOptionButton = target.closest(`#${IDS.MODAL_ADD_NEW_OPTION_BTN}`);
                if (addNewOptionButton && listIdForAction) {
                    const mapping = getListMapping(listIdForAction);
                    const configForModal = modalConfigsData[Object.keys(modalConfigsData).find(key => modalConfigsData[key].listId === listIdForAction)];

                    if (mapping && configForModal && configForModal.predefinedSourceKey && configForModal.isSortableMixed) {
                         PredefinedOptionChooser.show(
                            configForModal.manageType, listIdForAction, configForModal.predefinedSourceKey,
                            itemsArrayRef, modalContent, _addPredefinedItemsToModalList
                        );
                    } else if (mapping) {
                         const textInput = modalContent.querySelector(mapping.textInput);
                         textInput?.focus();
                    }
                    return;
                }

                const addButton = target.closest(`.${CSS.ADD_CUSTOM_BUTTON}.custom-list-action-button`);
                const itemControlButton = target.closest(`button.${CSS.EDIT_CUSTOM_ITEM}, button.${CSS.DELETE_CUSTOM_ITEM}, button.${CSS.REMOVE_FROM_LIST_BTN}`);
                const cancelEditButton = target.closest('.cancel-edit-button');

                if (itemControlButton && listIdForAction) { _handleCustomListActionsInternal(event, modalContent, itemsArrayRef); return; }
                if (addButton && listIdForAction) { _handleCustomItemSubmitInternal(listIdForAction, modalContent, itemsArrayRef); return; }
                if (cancelEditButton) { _resetEditStateInternal(modalContent); return; }
            });
            modalContent.dataset.modalEventsBound = 'true';
            modalContent.dataset.boundListId = listIdForDragDrop;


            modalContent.addEventListener('input', (event) => {
                const target = event.target;
                if (target.matches(`#${IDS.NEW_SITE_NAME}, #${IDS.NEW_SITE_URL}, #${IDS.NEW_LANG_TEXT}, #${IDS.NEW_LANG_VALUE}, #${IDS.NEW_TIME_TEXT}, #${IDS.NEW_TIME_VALUE}, #${IDS.NEW_FT_TEXT}, #${IDS.NEW_FT_VALUE}, #${IDS.NEW_COUNTRY_TEXT}, #${IDS.NEW_COUNTRY_VALUE}`)) {
                    _clearInputError(target); validateCustomInput(target);
                }
            });

            if (listIdForDragDrop) {
                const draggableListElement = modalContent.querySelector(`#${listIdForDragDrop}`);
                if (draggableListElement) {
                    if (draggableListElement.dataset.dragEventsBound !== 'true') {
                        draggableListElement.dataset.dragEventsBound = 'true';
                        draggableListElement.addEventListener('dragstart', _handleModalListDragStart);
                        draggableListElement.addEventListener('dragover', _handleModalListDragOver);
                        draggableListElement.addEventListener('dragleave', _handleModalListDragLeave);
                        draggableListElement.addEventListener('drop', (event) => _handleModalListDrop(event, listIdForDragDrop, itemsArrayRef));
                        draggableListElement.addEventListener('dragend', (event) => _handleModalListDragEnd(draggableListElement));
                    }
                }
            }
        }

        return {
            show: function(titleKey, contentHTML, onCompleteCallback, currentTheme) {
                this.hide();
                _currentModal = document.createElement('div'); _currentModal.className = 'settings-modal-overlay'; applyThemeToElement(_currentModal, currentTheme);
                _currentModalContent = document.createElement('div'); _currentModalContent.className = 'settings-modal-content'; applyThemeToElement(_currentModalContent, currentTheme);
                const header = document.createElement('div'); header.className = 'settings-modal-header'; header.innerHTML = `<h4>${_(titleKey)}</h4><button class="settings-modal-close-btn" title="${_('settings_close_button_title')}">${SVG_ICONS.close}</button>`;
                const body = document.createElement('div'); body.className = 'settings-modal-body'; body.innerHTML = contentHTML;
                const footer = document.createElement('div'); footer.className = 'settings-modal-footer'; footer.innerHTML = `<button class="modal-complete-btn">${_('modal_button_complete')}</button>`;
                _currentModalContent.appendChild(header); _currentModalContent.appendChild(body); _currentModalContent.appendChild(footer);
                _currentModal.appendChild(_currentModalContent);
                let closeModalHandlerInstance = null; let completeModalHandlerInstance = null; const self = this;
                closeModalHandlerInstance = (event) => { if (event.target === _currentModal || event.target.closest('.settings-modal-close-btn')) { self.hide(true); _currentModal?.removeEventListener('click', closeModalHandlerInstance, true); header.querySelector('.settings-modal-close-btn')?.removeEventListener('click', closeModalHandlerInstance); footer.querySelector('.modal-complete-btn')?.removeEventListener('click', completeModalHandlerInstance); } };
                completeModalHandlerInstance = () => { if (onCompleteCallback && typeof onCompleteCallback === 'function') { onCompleteCallback(_currentModalContent); } _currentModal?.removeEventListener('click', closeModalHandlerInstance, true); header.querySelector('.settings-modal-close-btn')?.removeEventListener('click', closeModalHandlerInstance); footer.querySelector('.modal-complete-btn')?.removeEventListener('click', completeModalHandlerInstance); self.hide(false); };
                _currentModal.addEventListener('click', closeModalHandlerInstance, true);
                header.querySelector('.settings-modal-close-btn').addEventListener('click', closeModalHandlerInstance);
                footer.querySelector('.modal-complete-btn').addEventListener('click', completeModalHandlerInstance);
                _currentModalContent.addEventListener('click', (event) => event.stopPropagation());
                document.body.appendChild(_currentModal);
                return _currentModalContent;
            },
            hide: function(isCancel = false) {
                PredefinedOptionChooser.hide();
                if (_currentModal) {
                    const inputGroup = _currentModalContent?.querySelector(`.${CSS.CUSTOM_LIST_INPUT_GROUP}`);
                    if (inputGroup) _clearAllInputErrorsInGroup(inputGroup);
                    _resetEditStateInternal();
                    _currentModal.remove();
                }
                _currentModal = null; _currentModalContent = null; _handleModalListDragEnd();
            },
            openManageCustomOptions: function(manageType, currentSettingsRef, PREDEFINED_OPTIONS_REF, onModalCompleteCallback) {
                const config = modalConfigsData[manageType];
                if (!config) { console.error("Error: Could not get config for manageType:", manageType); return; }
                const mapping = getListMapping(config.listId);
                if (!mapping) { console.error("Error: Could not get mapping for listId:", config.listId); return; }
                const tempItems = JSON.parse(JSON.stringify(currentSettingsRef[config.itemsArrayKey] || []));
                let contentHTML = '';
                const itemTypeNameForDisplay = _(mapping.nameKey);
                if (config.isSortableMixed) {
                    contentHTML += _createModalListAndInputHTML(config.listId, config.textPKey, config.valPKey, config.hintKey, config.fmtKey, itemTypeNameForDisplay, true);
                } else if (config.predefinedSourceKey && PREDEFINED_OPTIONS[config.predefinedSourceKey]) {
                    const enabledValues = new Set(currentSettingsRef.enabledPredefinedOptions[config.predefinedSourceKey] || []);
                    contentHTML += _createPredefinedOptionsSectionHTML(config.predefinedSourceKey, mapping.nameKey, PREDEFINED_OPTIONS_REF, enabledValues) + '<hr>';
                    contentHTML += _createModalListAndInputHTML(config.listId, config.textPKey, config.valPKey, config.hintKey, config.fmtKey, itemTypeNameForDisplay, false);
                } else {
                    contentHTML += _createModalListAndInputHTML(config.listId, config.textPKey, config.valPKey, config.hintKey, config.fmtKey, itemTypeNameForDisplay, false);
                }
                const modalContentElement = this.show(config.modalTitleKey, contentHTML, (modalContent) => {
                    let newEnabledPredefs = null;
                    if (config.predefinedSourceKey && !config.isSortableMixed) {
                        newEnabledPredefs = [];
                        modalContent.querySelectorAll(`.predefined-options-list input[data-option-type="${config.predefinedSourceKey}"]:checked`).forEach(cb => newEnabledPredefs.push(cb.value));
                    }
                    onModalCompleteCallback(tempItems, newEnabledPredefs, config.itemsArrayKey, config.predefinedSourceKey, config.customItemsMasterKey, config.isSortableMixed, manageType);
                }, currentSettingsRef.theme);
                if (modalContentElement) {
                    if (mapping && mapping.populateFn) {
                        mapping.populateFn(config.listId, tempItems, modalContentElement);
                    }
                    _bindModalContentEventsInternal(modalContentElement, tempItems, config.listId);
                }
            },
            resetEditStateGlobally: function() { _resetEditStateInternal(_currentModalContent || document); },
            isModalOpen: function() { return !!_currentModal; }
        };
    })();

    // --- END OF PART 2 (gscs-base.user.js) ---

    // --- START OF PART 3 (gscs-base.user.js) ---

    const SettingsUIPaneGenerator = (function() {
        function createGeneralPaneHTML() {
            let langOpts = LocalizationService.getAvailableLocales().map(lc => {
                let dn;
                if (lc === 'auto') dn = _('settings_language_auto');
                else { try { dn = new Intl.DisplayNames([lc],{type:'language'}).of(lc); dn = dn.charAt(0).toUpperCase() + dn.slice(1); } catch(e){ dn = lc; } dn = `${dn} (${lc})`; }
                return `<option value="${lc}">${dn}</option>`;
            }).join('');
            const accordionHintHTML = `<div class="${CSS.SETTING_VALUE_HINT}" style="margin-top:0.3em; margin-left:1.7em; font-weight:normal;">${_('settings_accordion_mode_hint_desc')}</div>`;
            return `<div class="${CSS.SETTING_ITEM}"><label for="${IDS.SETTING_INTERFACE_LANGUAGE}">${_('settings_interface_language')}</label><select id="${IDS.SETTING_INTERFACE_LANGUAGE}">${langOpts}</select></div>` +
                   `<div class="${CSS.SETTING_ITEM}"><label for="${IDS.SETTING_SECTION_MODE}">${_('settings_section_mode')}</label><select id="${IDS.SETTING_SECTION_MODE}"><option value="remember">${_('settings_section_mode_remember')}</option><option value="expandAll">${_('settings_section_mode_expand')}</option><option value="collapseAll">${_('settings_section_mode_collapse')}</option></select><div style="margin-top:0.6em;"><input type="checkbox" id="${IDS.SETTING_ACCORDION}"><label for="${IDS.SETTING_ACCORDION}" class="${CSS.INLINE_LABEL}">${_('settings_accordion_mode')}</label>${accordionHintHTML}</div></div>` +
                   `<div class="${CSS.SETTING_ITEM}"><input type="checkbox" id="${IDS.SETTING_DRAGGABLE}"><label for="${IDS.SETTING_DRAGGABLE}" class="${CSS.INLINE_LABEL}">${_('settings_enable_drag')}</label></div>` +
                   `<div class="${CSS.SETTING_ITEM}"><label for="${IDS.SETTING_RESET_LOCATION}">${_('settings_reset_button_location')}</label><select id="${IDS.SETTING_RESET_LOCATION}"><option value="tools">${_('settings_location_tools')}</option><option value="topBlock">${_('settings_location_top')}</option><option value="header">${_('settings_location_header')}</option><option value="none">${_('settings_location_hide')}</option></select></div>` +
                   `<div class="${CSS.SETTING_ITEM}"><label for="${IDS.SETTING_VERBATIM_LOCATION}">${_('settings_verbatim_button_location')}</label><select id="${IDS.SETTING_VERBATIM_LOCATION}"><option value="tools">${_('settings_location_tools')}</option><option value="topBlock">${_('settings_location_top')}</option><option value="header">${_('settings_location_header')}</option><option value="none">${_('settings_location_hide')}</option></select></div>` +
                   `<div class="${CSS.SETTING_ITEM}"><label for="${IDS.SETTING_ADV_SEARCH_LOCATION}">${_('settings_adv_search_location')}</label><select id="${IDS.SETTING_ADV_SEARCH_LOCATION}"><option value="tools">${_('settings_location_tools')}</option><option value="topBlock">${_('settings_location_top')}</option><option value="header">${_('settings_location_header')}</option><option value="none">${_('settings_location_hide')}</option></select></div>`+
                   `<div class="${CSS.SETTING_ITEM}"><label for="${IDS.SETTING_PERSONALIZE_LOCATION}">${_('settings_personalize_button_location')}</label><select id="${IDS.SETTING_PERSONALIZE_LOCATION}"><option value="tools">${_('settings_location_tools')}</option><option value="topBlock">${_('settings_location_top')}</option><option value="header">${_('settings_location_header')}</option><option value="none">${_('settings_location_hide')}</option></select></div>`;
        }
        function createAppearancePaneHTML() {
            return `<div class="${CSS.SETTING_ITEM}"><label for="${IDS.SETTING_WIDTH}">${_('settings_sidebar_width')}</label><span class="${CSS.RANGE_HINT}">${_('settings_width_range_hint')}</span><input type="range" id="${IDS.SETTING_WIDTH}" min="90" max="270" step="5"><span class="${CSS.RANGE_VALUE}"></span></div>` +
                   `<div class="${CSS.SETTING_ITEM}"><label for="${IDS.SETTING_FONT_SIZE}">${_('settings_font_size')}</label><span class="${CSS.RANGE_HINT}">${_('settings_font_size_range_hint')}</span><input type="range" id="${IDS.SETTING_FONT_SIZE}" min="8" max="24" step="0.5"><span class="${CSS.RANGE_VALUE}"></span></div>` +
                   `<div class="${CSS.SETTING_ITEM}"><label for="${IDS.SETTING_HEADER_ICON_SIZE}">${_('settings_header_icon_size')}</label><span class="${CSS.RANGE_HINT}">${_('settings_header_icon_size_range_hint')}</span><input type="range" id="${IDS.SETTING_HEADER_ICON_SIZE}" min="8" max="32" step="0.5"><span class="${CSS.RANGE_VALUE}"></span></div>` +
                   `<div class="${CSS.SETTING_ITEM}"><label for="${IDS.SETTING_VERTICAL_SPACING}">${_('settings_vertical_spacing')}</label><span class="${CSS.RANGE_HINT}">${_('settings_vertical_spacing_range_hint')}</span><input type="range" id="${IDS.SETTING_VERTICAL_SPACING}" min="0.05" max="1.5" step="0.05"><span class="${CSS.RANGE_VALUE}"></span></div>` +
                   `<div class="${CSS.SETTING_ITEM}"><label for="${IDS.SETTING_THEME}">${_('settings_theme')}</label><select id="${IDS.SETTING_THEME}"><option value="system">${_('settings_theme_system')}</option><option value="light">${_('settings_theme_light')}</option><option value="dark">${_('settings_theme_dark')}</option><option value="minimal-light">${_('settings_theme_minimal_light')}</option><option value="minimal-dark">${_('settings_theme_minimal_dark')}</option></select></div><div class="${CSS.SETTING_ITEM}"><input type="checkbox" id="${IDS.SETTING_HOVER}"><label for="${IDS.SETTING_HOVER}" class="${CSS.INLINE_LABEL}">${_('settings_hover_mode')}</label><div style="margin-top:0.8em;padding-left:1.5em;"><label for="${IDS.SETTING_OPACITY}" style="display:block;margin-bottom:0.4em;font-weight:normal;">${_('settings_idle_opacity')}</label><span class="${CSS.RANGE_HINT}" style="width:auto;display:inline-block;margin-right:1em;">${_('settings_opacity_range_hint')}</span><input type="range" id="${IDS.SETTING_OPACITY}" min="0.1" max="1.0" step="0.05" style="width:calc(100% - 18em);vertical-align:middle;display:inline-block;"><span class="${CSS.RANGE_VALUE}" style="display:inline-block;min-width:3em;text-align:right;vertical-align:middle;"></span></div></div><div class="${CSS.SETTING_ITEM}"><label for="${IDS.SETTING_COUNTRY_DISPLAY_MODE}">${_('settings_country_display')}</label><select id="${IDS.SETTING_COUNTRY_DISPLAY_MODE}"><option value="iconAndText">${_('settings_country_display_icontext')}</option><option value="textOnly">${_('settings_country_display_text')}</option><option value="iconOnly">${_('settings_country_display_icon')}</option></select></div>`;
        }
        function createFeaturesPaneHTML() {
            const visItemsHTML = ALL_SECTION_DEFINITIONS.map(def=>{ const dn=_(def.titleKey)||def.id; return `<div class="${CSS.SETTING_ITEM} ${CSS.SIMPLE_ITEM}"><input type="checkbox" id="setting-visible-${def.id}" data-${DATA_ATTR.SECTION_ID}="${def.id}"><label for="setting-visible-${def.id}" class="${CSS.INLINE_LABEL}">${dn}</label></div>`; }).join('');
            const siteSearchCheckboxModeHTML =
                `<div class="${CSS.SETTING_ITEM}">` +
                `<input type="checkbox" id="${IDS.SETTING_SITE_SEARCH_CHECKBOX_MODE}"><label for="${IDS.SETTING_SITE_SEARCH_CHECKBOX_MODE}" class="${CSS.INLINE_LABEL}">${_('settings_enable_site_search_checkbox_mode')}</label>` +
                `<div class="${CSS.SETTING_VALUE_HINT}" style="margin-top:0.3em; margin-left:1.7em; font-weight:normal;">${_('settings_enable_site_search_checkbox_mode_hint')}</div>` +
                `</div>`;
            return `<p>${_('settings_visible_sections')}</p>${visItemsHTML}` +
                   `${siteSearchCheckboxModeHTML}<hr style="margin:1.2em 0;">` +
                   `<p style="font-weight:bold;margin-bottom:0.5em;">${_('settings_section_order')}</p><p class="${CSS.SETTING_VALUE_HINT}" style="font-size:0.9em;margin-top:-0.3em;margin-bottom:0.7em;">${_('settings_section_order_hint')}</p><ul id="${IDS.SIDEBAR_SECTION_ORDER_LIST}" class="${CSS.SECTION_ORDER_LIST}"></ul>`;
        }
        function createCustomPaneHTML() {
            return `<div class="${CSS.SETTING_ITEM}"><p>${_('settings_custom_intro')}</p><button class="${CSS.MANAGE_CUSTOM_BUTTON}" data-${DATA_ATTR.MANAGE_TYPE}="site">${_('settings_manage_sites_button')}</button></div><div class="${CSS.SETTING_ITEM}"><button class="${CSS.MANAGE_CUSTOM_BUTTON}" data-${DATA_ATTR.MANAGE_TYPE}="language">${_('settings_manage_languages_button')}</button></div><div class="${CSS.SETTING_ITEM}"><button class="${CSS.MANAGE_CUSTOM_BUTTON}" data-${DATA_ATTR.MANAGE_TYPE}="country">${_('settings_manage_countries_button')}</button></div><div class="${CSS.SETTING_ITEM}"><button class="${CSS.MANAGE_CUSTOM_BUTTON}" data-${DATA_ATTR.MANAGE_TYPE}="time">${_('settings_manage_time_ranges_button')}</button></div><div class="${CSS.SETTING_ITEM}"><button class="${CSS.MANAGE_CUSTOM_BUTTON}" data-${DATA_ATTR.MANAGE_TYPE}="filetype">${_('settings_manage_file_types_button')}</button></div>`;
        }
        return { createGeneralPaneHTML, createAppearancePaneHTML, createFeaturesPaneHTML, createCustomPaneHTML };
    })();

    const SectionOrderDragHandler = (function() {
        let _draggedItem = null; let _listElement = null; let _settingsRef = null; let _onOrderUpdateCallback = null;
        function getDragAfterElement(container, y) { const draggableElements = [...container.querySelectorAll(`li[draggable="true"]:not(.${CSS.DRAGGING_ITEM})`)]; return draggableElements.reduce((closest, child) => { const box = child.getBoundingClientRect(); const offset = y - box.top - box.height / 2; if (offset < 0 && offset > closest.offset) { return { offset: offset, element: child }; } else { return closest; } }, { offset: Number.NEGATIVE_INFINITY }).element; }
        function handleDragStart(event) { _draggedItem = event.target; event.dataTransfer.effectAllowed = 'move'; event.dataTransfer.setData('text/plain', _draggedItem.dataset.sectionId); _draggedItem.classList.add(CSS.DRAGGING_ITEM); if (_listElement) { _listElement.querySelectorAll('li:not(.gscs-dragging-item)').forEach(li => li.style.pointerEvents = 'none'); } }
        function handleDragOver(event) { event.preventDefault(); if (!_listElement) return; _listElement.querySelectorAll(`li.${CSS.DRAG_OVER_HIGHLIGHT}`).forEach(li => { li.classList.remove(CSS.DRAG_OVER_HIGHLIGHT); }); const targetItem = event.target.closest('li[draggable="true"]'); if (targetItem && targetItem !== _draggedItem) { targetItem.classList.add(CSS.DRAG_OVER_HIGHLIGHT); } else if (!targetItem && _listElement.contains(event.target)) { const afterElement = getDragAfterElement(_listElement, event.clientY); if (afterElement) { afterElement.classList.add(CSS.DRAG_OVER_HIGHLIGHT); } } }
        function handleDragLeave(event) { const relatedTarget = event.relatedTarget; if (_listElement && (!relatedTarget || !_listElement.contains(relatedTarget))) { _listElement.querySelectorAll(`li.${CSS.DRAG_OVER_HIGHLIGHT}`).forEach(li => { li.classList.remove(CSS.DRAG_OVER_HIGHLIGHT); }); } }
        function handleDrop(event) {
            event.preventDefault(); if (!_draggedItem || !_listElement || !_settingsRef || !_onOrderUpdateCallback) return;
            const draggedSectionId = event.dataTransfer.getData('text/plain');
            let currentVisibleOrder = _settingsRef.sidebarSectionOrder.filter(id => _settingsRef.visibleSections[id]);
            const oldIndexInVisible = currentVisibleOrder.indexOf(draggedSectionId);
            if (oldIndexInVisible > -1) { currentVisibleOrder.splice(oldIndexInVisible, 1); } else { handleDragEnd(); return; }
            const afterElement = getDragAfterElement(_listElement, event.clientY);
            if (afterElement) { const targetId = afterElement.dataset.sectionId; const newIndexInVisible = currentVisibleOrder.indexOf(targetId); if (newIndexInVisible > -1) { currentVisibleOrder.splice(newIndexInVisible, 0, draggedSectionId); } else { currentVisibleOrder.push(draggedSectionId); }
            } else { currentVisibleOrder.push(draggedSectionId); }
            const hiddenSectionOrder = _settingsRef.sidebarSectionOrder.filter(id => !_settingsRef.visibleSections[id]);
            _settingsRef.sidebarSectionOrder = [...currentVisibleOrder, ...hiddenSectionOrder];
            handleDragEnd(); _onOrderUpdateCallback();
        }
        function handleDragEnd() { if (_draggedItem) { _draggedItem.classList.remove(CSS.DRAGGING_ITEM); } _draggedItem = null; if (_listElement) { _listElement.querySelectorAll('li').forEach(li => { li.classList.remove(CSS.DRAG_OVER_HIGHLIGHT); li.style.pointerEvents = ''; }); } }
        function initialize(listEl, currentSettings, orderUpdateCallback) { _listElement = listEl; _settingsRef = currentSettings; _onOrderUpdateCallback = orderUpdateCallback; if (_listElement && _listElement.dataset.sectionOrderDragBound !== 'true') { _listElement.addEventListener('dragstart', handleDragStart); _listElement.addEventListener('dragover', handleDragOver); _listElement.addEventListener('dragleave', handleDragLeave); _listElement.addEventListener('drop', handleDrop); _listElement.addEventListener('dragend', handleDragEnd); _listElement.dataset.sectionOrderDragBound = 'true'; } }
        function destroy() { if (_listElement && _listElement.dataset.sectionOrderDragBound === 'true') { _listElement.removeEventListener('dragstart', handleDragStart); _listElement.removeEventListener('dragover', handleDragOver); _listElement.removeEventListener('dragleave', handleDragLeave); _listElement.removeEventListener('drop', handleDrop); _listElement.removeEventListener('dragend', handleDragEnd); delete _listElement.dataset.sectionOrderDragBound; } _listElement = null; _settingsRef = null; _onOrderUpdateCallback = null; }
        return { initialize, destroy };
    })();

    const SettingsManager = (function() {
        let _settingsWindow = null; let _settingsOverlay = null; let _currentSettings = {};
        let _settingsBackup = {}; let _defaultSettingsRef = null; let _isInitialized = false;
        let _applySettingsToSidebar_cb = ()=>{}; let _buildSidebarUI_cb = ()=>{};
        let _applySectionCollapseStates_cb = ()=>{}; let _initMenuCommands_cb = ()=>{};
        let _renderSectionOrderList_ext_cb = ()=>{};

        function _populateSliderSetting_internal(win,id,value,formatFn=(val)=>val){const i=win.querySelector(`#${id}`);if(i){i.value=value;let vs=i.parentNode.querySelector(`.${CSS.RANGE_VALUE}`);if(vs&&vs.classList.contains(CSS.RANGE_VALUE)){vs.textContent=formatFn(value);}}}
        function _populateGeneralSettings_internal(win,s){ const lS=win.querySelector(`#${IDS.SETTING_INTERFACE_LANGUAGE}`);if(lS)lS.value=s.interfaceLanguage;const sMS=win.querySelector(`#${IDS.SETTING_SECTION_MODE}`),acC=win.querySelector(`#${IDS.SETTING_ACCORDION}`);if(sMS&&acC){sMS.value=s.sectionDisplayMode;const iRM=s.sectionDisplayMode==='remember';acC.disabled=!iRM;acC.checked=iRM?s.accordionMode:false; const accordionHint = acC.parentElement.querySelector(`.${CSS.SETTING_VALUE_HINT}`); if(accordionHint) accordionHint.style.color = iRM ? '' : 'grey';} const dC=win.querySelector(`#${IDS.SETTING_DRAGGABLE}`);if(dC)dC.checked=s.draggableHandleEnabled;const rLS=win.querySelector(`#${IDS.SETTING_RESET_LOCATION}`);if(rLS)rLS.value=s.resetButtonLocation;const vLS=win.querySelector(`#${IDS.SETTING_VERBATIM_LOCATION}`);if(vLS)vLS.value=s.verbatimButtonLocation;const aSLS=win.querySelector(`#${IDS.SETTING_ADV_SEARCH_LOCATION}`);if(aSLS)aSLS.value=s.advancedSearchLinkLocation; const pznLS = win.querySelector(`#${IDS.SETTING_PERSONALIZE_LOCATION}`); if (pznLS) pznLS.value = s.personalizationButtonLocation;}
        function _populateAppearanceSettings_internal(win,s){_populateSliderSetting_internal(win,IDS.SETTING_WIDTH,s.sidebarWidth);_populateSliderSetting_internal(win,IDS.SETTING_FONT_SIZE,s.fontSize,v=>parseFloat(v).toFixed(1));_populateSliderSetting_internal(win,IDS.SETTING_HEADER_ICON_SIZE,s.headerIconSize,v=>parseFloat(v).toFixed(1));_populateSliderSetting_internal(win,IDS.SETTING_VERTICAL_SPACING,s.verticalSpacingMultiplier,v=>`x ${parseFloat(v).toFixed(2)}`);_populateSliderSetting_internal(win,IDS.SETTING_OPACITY,s.idleOpacity,v=>parseFloat(v).toFixed(2));const tS=win.querySelector(`#${IDS.SETTING_THEME}`);if(tS)tS.value=s.theme;const cDS=win.querySelector(`#${IDS.SETTING_COUNTRY_DISPLAY_MODE}`);if(cDS)cDS.value=s.countryDisplayMode;const hC=win.querySelector(`#${IDS.SETTING_HOVER}`),oI=win.querySelector(`#${IDS.SETTING_OPACITY}`);if(hC&&oI){hC.checked=s.hoverMode;const iHE=s.hoverMode;oI.disabled=!iHE;const oC=oI.closest('div');if(oC){oC.style.opacity=iHE?'1':'0.6';oC.style.pointerEvents=iHE?'auto':'none';}}}
        function _populateFeatureSettings_internal(win,s,renderFn){win.querySelectorAll(`#${IDS.TAB_PANE_FEATURES} input[type="checkbox"][data-${DATA_ATTR.SECTION_ID}]`)?.forEach(cb=>{const sId=cb.getAttribute(`data-${DATA_ATTR.SECTION_ID}`);if(sId&&s.visibleSections.hasOwnProperty(sId)){cb.checked=s.visibleSections[sId];}else if(sId&&_defaultSettingsRef.visibleSections.hasOwnProperty(sId)){cb.checked=_defaultSettingsRef.visibleSections[sId]??false;}}); const siteSearchCheckboxModeEl = win.querySelector(`#${IDS.SETTING_SITE_SEARCH_CHECKBOX_MODE}`); if(siteSearchCheckboxModeEl) siteSearchCheckboxModeEl.checked = s.enableSiteSearchCheckboxMode; renderFn(s);}
        function _initializeActiveSettingsTab_internal(){if(!_settingsWindow)return;const tC=_settingsWindow.querySelector(`.${CSS.SETTINGS_TABS}`),cC=_settingsWindow.querySelector(`.${CSS.SETTINGS_TAB_CONTENT}`);if(!tC||!cC)return;const aTB=tC.querySelector(`.${CSS.TAB_BUTTON}.${CSS.ACTIVE}`);const tT=(aTB&&aTB.dataset[DATA_ATTR.TAB])?aTB.dataset[DATA_ATTR.TAB]:'general';tC.querySelectorAll(`.${CSS.TAB_BUTTON}`).forEach(b=>b.classList.toggle(CSS.ACTIVE,b.dataset[DATA_ATTR.TAB]===tT));cC.querySelectorAll(`.${CSS.TAB_PANE}`).forEach(p=>p.classList.toggle(CSS.ACTIVE,p.dataset[DATA_ATTR.TAB]===tT));}
        function _loadFromStorage(){try{const s=GM_getValue(STORAGE_KEY,'{}');return JSON.parse(s||'{}');}catch(e){console.error(`${LOG_PREFIX} Error loading/parsing settings:`,e);return{};}}
        function _migrateToDisplayArraysIfNecessary(settings) {
            const displayTypes = [ { displayKey: 'displayLanguages', predefinedKey: 'language', customKey: 'customLanguages', defaultEnabled: defaultSettings.enabledPredefinedOptions.language }, { displayKey: 'displayCountries', predefinedKey: 'country', customKey: 'customCountries', defaultEnabled: defaultSettings.enabledPredefinedOptions.country } ]; let migrationPerformed = false;
            displayTypes.forEach(typeInfo => { if ((!settings[typeInfo.displayKey] || settings[typeInfo.displayKey].length === 0) && ( (settings.enabledPredefinedOptions && settings.enabledPredefinedOptions[typeInfo.predefinedKey]?.length > 0) || (settings[typeInfo.customKey] && settings[typeInfo.customKey]?.length > 0) ) ) { console.log(`${LOG_PREFIX} Migrating settings for ${typeInfo.displayKey}`); migrationPerformed = true; const newDisplayArray = []; const addedValues = new Set(); const enabledPredefined = settings.enabledPredefinedOptions?.[typeInfo.predefinedKey] || typeInfo.defaultEnabled || []; enabledPredefined.forEach(val => { const predefinedOpt = PREDEFINED_OPTIONS[typeInfo.predefinedKey]?.find(p => p.value === val); if (predefinedOpt && !addedValues.has(predefinedOpt.value)) { newDisplayArray.push({ id: predefinedOpt.value, text: _(predefinedOpt.textKey), value: predefinedOpt.value, type: 'predefined', originalKey: predefinedOpt.textKey }); addedValues.add(predefinedOpt.value); } }); newDisplayArray.sort((a,b) => { const textA = a.originalKey ? _(a.originalKey) : a.text; const textB = b.originalKey ? _(b.originalKey) : b.text; return textA.localeCompare(textB, LocalizationService.getCurrentLocale(), {sensitivity: 'base'}) }); const customItems = settings[typeInfo.customKey] || []; customItems.forEach(customOpt => { if (customOpt.value && !addedValues.has(customOpt.value)) { newDisplayArray.push({ id: customOpt.value, text: customOpt.text, value: customOpt.value, type: 'custom' }); addedValues.add(customOpt.value); } }); settings[typeInfo.displayKey] = newDisplayArray; if (settings.enabledPredefinedOptions) { settings.enabledPredefinedOptions[typeInfo.predefinedKey] = []; } } else if (!settings[typeInfo.displayKey]) { settings[typeInfo.displayKey] = JSON.parse(JSON.stringify(defaultSettings[typeInfo.displayKey] || [])); } });
            if (migrationPerformed) console.log(`${LOG_PREFIX} Migration to display arrays complete.`);
        }
        function _validateAndMergeSettings(saved){
            let newSettings = JSON.parse(JSON.stringify(_defaultSettingsRef)); newSettings = Utils.mergeDeep(newSettings, saved);
            _validateAndMergeCoreSettings_internal(newSettings, saved, _defaultSettingsRef); _validateAndMergeAppearanceSettings_internal(newSettings, saved, _defaultSettingsRef); _validateAndMergeFeatureSettings_internal(newSettings, saved, _defaultSettingsRef); _validateAndMergeCustomLists_internal(newSettings, saved, _defaultSettingsRef);
            _migrateToDisplayArraysIfNecessary(newSettings);
            ['displayLanguages', 'displayCountries'].forEach(displayKey => { if (!Array.isArray(newSettings[displayKey])) { newSettings[displayKey] = JSON.parse(JSON.stringify(_defaultSettingsRef[displayKey])) || []; } newSettings[displayKey] = newSettings[displayKey].filter(item => item && typeof item.id === 'string' && (item.type === 'predefined' ? (typeof item.text === 'string' && typeof item.originalKey === 'string') : typeof item.text === 'string') && typeof item.value === 'string' && (item.type === 'predefined' || item.type === 'custom') ); });
            _validateAndMergePredefinedOptions_internal(newSettings, saved, _defaultSettingsRef); _finalizeSectionOrder_internal(newSettings, saved, _defaultSettingsRef);
            return newSettings;
        }
        function _validateAndMergeCoreSettings_internal(target,source,defaults){if(typeof target.sidebarPosition!=='object'||target.sidebarPosition===null||Array.isArray(target.sidebarPosition)){target.sidebarPosition=JSON.parse(JSON.stringify(defaults.sidebarPosition));}target.sidebarPosition.left=parseInt(target.sidebarPosition.left,10)||defaults.sidebarPosition.left;target.sidebarPosition.top=parseInt(target.sidebarPosition.top,10)||defaults.sidebarPosition.top;if(typeof target.sectionStates!=='object'||target.sectionStates===null||Array.isArray(target.sectionStates)){target.sectionStates={};}target.sidebarCollapsed=!!target.sidebarCollapsed;target.draggableHandleEnabled=typeof target.draggableHandleEnabled==='boolean'?target.draggableHandleEnabled:defaults.draggableHandleEnabled;target.interfaceLanguage=typeof source.interfaceLanguage==='string'?source.interfaceLanguage:defaults.interfaceLanguage;}
        function _validateAndMergeAppearanceSettings_internal(target,source,defaults){target.sidebarWidth=Utils.clamp(parseInt(target.sidebarWidth,10)||defaults.sidebarWidth,90,270);target.fontSize=Utils.clamp(parseFloat(target.fontSize)||defaults.fontSize,8,24);target.headerIconSize=Utils.clamp(parseFloat(target.headerIconSize)||defaults.headerIconSize,8,32);target.verticalSpacingMultiplier=Utils.clamp(parseFloat(target.verticalSpacingMultiplier)||defaults.verticalSpacingMultiplier,0.05,1.5);target.idleOpacity=Utils.clamp(parseFloat(target.idleOpacity)||defaults.idleOpacity,0.1,1.0);target.hoverMode=!!target.hoverMode;const validThemes=['system','light','dark','minimal-light','minimal-dark'];if(target.theme==='minimal')target.theme='minimal-light';else if(!validThemes.includes(target.theme))target.theme=defaults.theme;}
        function _validateAndMergeFeatureSettings_internal(target,source,defaults){if(typeof target.visibleSections!=='object'||target.visibleSections===null||Array.isArray(target.visibleSections)){target.visibleSections=JSON.parse(JSON.stringify(defaults.visibleSections));}const validSectionIDs=new Set(ALL_SECTION_DEFINITIONS.map(def=>def.id));Object.keys(defaults.visibleSections).forEach(id=>{if(!validSectionIDs.has(id)){console.warn(`${LOG_PREFIX} Invalid section ID in defaultSettings.visibleSections: ${id}`);}else if(typeof target.visibleSections[id]!=='boolean'){target.visibleSections[id]=defaults.visibleSections[id]??true;}});const validSectionModes=['remember','expandAll','collapseAll'];if(!validSectionModes.includes(target.sectionDisplayMode))target.sectionDisplayMode=defaults.sectionDisplayMode;target.accordionMode=!!target.accordionMode; target.enableSiteSearchCheckboxMode = typeof target.enableSiteSearchCheckboxMode === 'boolean' ? target.enableSiteSearchCheckboxMode : defaults.enableSiteSearchCheckboxMode; const validButtonLocations=['header','topBlock','tools','none'];if(!validButtonLocations.includes(target.resetButtonLocation))target.resetButtonLocation=defaults.resetButtonLocation;if(!validButtonLocations.includes(target.verbatimButtonLocation))target.verbatimButtonLocation=defaults.verbatimButtonLocation;if(!validButtonLocations.includes(target.advancedSearchLinkLocation))target.advancedSearchLinkLocation=defaults.advancedSearchLinkLocation; if (!validButtonLocations.includes(target.personalizationButtonLocation)) { target.personalizationButtonLocation = defaults.personalizationButtonLocation; } const validCountryDisplayModes=['iconAndText','textOnly','iconOnly'];if(!validCountryDisplayModes.includes(target.countryDisplayMode))target.countryDisplayMode=defaults.countryDisplayMode;}
        function _validateAndMergeCustomLists_internal(target,source,defaults){const listKeys=['favoriteSites','customLanguages','customTimeRanges','customFiletypes','customCountries'];listKeys.forEach(key=>{target[key]=Array.isArray(target[key])?target[key].filter(item=>item&&typeof item.text==='string'&&typeof item[key==='favoriteSites'?'url':'value']==='string'&&item.text.trim()!==''&&item[key==='favoriteSites'?'url':'value'].trim()!==''):JSON.parse(JSON.stringify(defaults[key]));});}
        function _validateAndMergePredefinedOptions_internal(target,source,defaults){ const nonDisplayManagedTypes = ['time', 'filetype']; target.enabledPredefinedOptions = target.enabledPredefinedOptions || {}; nonDisplayManagedTypes.forEach(type => { target.enabledPredefinedOptions[type] = JSON.parse(JSON.stringify(defaults.enabledPredefinedOptions[type] || [])); const savedTypeOptions = source.enabledPredefinedOptions?.[type]; if (PREDEFINED_OPTIONS[type] && Array.isArray(savedTypeOptions)) { const validValues = new Set(PREDEFINED_OPTIONS[type].map(opt => opt.value)); target.enabledPredefinedOptions[type] = savedTypeOptions.filter(val => typeof val === 'string' && validValues.has(val)); } }); if (target.displayLanguages && target.enabledPredefinedOptions) target.enabledPredefinedOptions.language = []; if (target.displayCountries && target.enabledPredefinedOptions) target.enabledPredefinedOptions.country = []; }
        function _finalizeSectionOrder_internal(target,source,defaults){const finalOrder=[];const currentVisibleOrderSet=new Set();const validSectionIDs=new Set(ALL_SECTION_DEFINITIONS.map(def=>def.id));const orderSource=(Array.isArray(source.sidebarSectionOrder)&&source.sidebarSectionOrder.length>0)?source.sidebarSectionOrder:defaults.sidebarSectionOrder;orderSource.forEach(id=>{if(typeof id==='string'&&validSectionIDs.has(id)&&target.visibleSections[id]===true&&!currentVisibleOrderSet.has(id)){finalOrder.push(id);currentVisibleOrderSet.add(id);}});defaults.sidebarSectionOrder.forEach(id=>{if(typeof id==='string'&&validSectionIDs.has(id)&&target.visibleSections[id]===true&&!currentVisibleOrderSet.has(id)){finalOrder.push(id);}});target.sidebarSectionOrder=finalOrder;}
        const _sEH_internal = { [IDS.SETTING_WIDTH]:(t,vS)=>_hSLI(t,'sidebarWidth',vS,90,270,5), [IDS.SETTING_FONT_SIZE]:(t,vS)=>_hSLI(t,'fontSize',vS,8,24,0.5,v=>parseFloat(v).toFixed(1)), [IDS.SETTING_HEADER_ICON_SIZE]:(t,vS)=>_hSLI(t,'headerIconSize',vS,8,32,0.5,v=>parseFloat(v).toFixed(1)), [IDS.SETTING_VERTICAL_SPACING]:(t,vS)=>_hSLI(t,'verticalSpacingMultiplier',vS,0.05,1.5,0.05,v=>`x ${parseFloat(v).toFixed(2)}`), [IDS.SETTING_OPACITY]:(t,vS)=>_hSLI(t,'idleOpacity',vS,0.1,1.0,0.05,v=>parseFloat(v).toFixed(2)), [IDS.SETTING_INTERFACE_LANGUAGE]:(t)=>{const nL=t.value;if(_currentSettings.interfaceLanguage!==nL){_currentSettings.interfaceLanguage=nL;LocalizationService.updateActiveLocale(_currentSettings);_initMenuCommands_cb();publicApi.populateWindow();_buildSidebarUI_cb();}}, [IDS.SETTING_THEME]:(t)=>{_currentSettings.theme=t.value;_applySettingsToSidebar_cb(_currentSettings);}, [IDS.SETTING_HOVER]:(t)=>{_currentSettings.hoverMode=t.checked;const oI=_settingsWindow.querySelector(`#${IDS.SETTING_OPACITY}`);if(oI){const iHE=_currentSettings.hoverMode;oI.disabled=!iHE;const oC=oI.closest('div');if(oC){oC.style.opacity=iHE?'1':'0.6';oC.style.pointerEvents=iHE?'auto':'none';}}_applySettingsToSidebar_cb(_currentSettings);}, [IDS.SETTING_DRAGGABLE]:(t)=>{_currentSettings.draggableHandleEnabled=t.checked;_applySettingsToSidebar_cb(_currentSettings);DragManager.setDraggable(t.checked, sidebar, sidebar?.querySelector(`.${CSS.DRAG_HANDLE}`), _currentSettings, debouncedSaveSettings);}, [IDS.SETTING_ACCORDION]:(t)=>{const sMS=_settingsWindow.querySelector(`#${IDS.SETTING_SECTION_MODE}`);if(sMS?.value==='remember')_currentSettings.accordionMode=t.checked;else{t.checked=false;_currentSettings.accordionMode=false;}_applySettingsToSidebar_cb(_currentSettings);_applySectionCollapseStates_cb();}, [IDS.SETTING_SECTION_MODE]:(t)=>{_currentSettings.sectionDisplayMode=t.value;const aC=_settingsWindow.querySelector(`#${IDS.SETTING_ACCORDION}`);if(aC){const iRM=t.value==='remember';aC.disabled=!iRM; if(aC.parentElement.querySelector(`.${CSS.SETTING_VALUE_HINT}`)) aC.parentElement.querySelector(`.${CSS.SETTING_VALUE_HINT}`).style.color = iRM ? '' : 'grey'; if(!iRM){aC.checked=false;_currentSettings.accordionMode=false;}else{aC.checked=_settingsBackup?.accordionMode??_currentSettings.accordionMode??_defaultSettingsRef.accordionMode;_currentSettings.accordionMode=aC.checked;}}_applySettingsToSidebar_cb(_currentSettings);_applySectionCollapseStates_cb();}, [IDS.SETTING_RESET_LOCATION]:(t)=>{_currentSettings.resetButtonLocation=t.value;_buildSidebarUI_cb();}, [IDS.SETTING_VERBATIM_LOCATION]:(t)=>{_currentSettings.verbatimButtonLocation=t.value;_buildSidebarUI_cb();}, [IDS.SETTING_ADV_SEARCH_LOCATION]:(t)=>{_currentSettings.advancedSearchLinkLocation=t.value;_buildSidebarUI_cb();}, [IDS.SETTING_PERSONALIZE_LOCATION]: (target) => { _currentSettings.personalizationButtonLocation = target.value; _buildSidebarUI_cb(); }, [IDS.SETTING_SITE_SEARCH_CHECKBOX_MODE]: (target) => { _currentSettings.enableSiteSearchCheckboxMode = target.checked; _buildSidebarUI_cb(); }, [IDS.SETTING_COUNTRY_DISPLAY_MODE]:(t)=>{_currentSettings.countryDisplayMode=t.value;_buildSidebarUI_cb();}, };
        function _hSLI(t,sK,vS,min,max,step,fFn=v=>v){const v=Utils.clamp((step===1||step===5)?parseInt(t.value,10):parseFloat(t.value),min,max);if(isNaN(v))_currentSettings[sK]=_defaultSettingsRef[sK];else _currentSettings[sK]=v;if(vS)vS.textContent=fFn(_currentSettings[sK]);_applySettingsToSidebar_cb(_currentSettings);}
        function _lUH_internal(e){const t=e.target;if(!t)return;const sI=t.id;const vS=(t.type==='range')?t.parentNode.querySelector(`.${CSS.RANGE_VALUE}`):null;if(_sEH_internal[sI]){if(t.type==='range')_sEH_internal[sI](t,vS);else _sEH_internal[sI](t);}}

        const publicApi = {
            initialize: function(defaultSettingsObj, applyCb, buildCb, collapseCb, menuCb, renderOrderCb) { if(_isInitialized) return; _defaultSettingsRef = defaultSettingsObj; _applySettingsToSidebar_cb = applyCb; _buildSidebarUI_cb = buildCb; _applySectionCollapseStates_cb = collapseCb; _initMenuCommands_cb = menuCb; _renderSectionOrderList_ext_cb = renderOrderCb; this.load(); this.buildSkeleton(); _isInitialized = true; },
            load: function(){ const s=_loadFromStorage(); _currentSettings=_validateAndMergeSettings(s); LocalizationService.updateActiveLocale(_currentSettings);},
            save: function(logContext='SaveBtn'){ try { ['displayLanguages', 'displayCountries'].forEach(displayKey => { const mapping = getListMapping(displayKey === 'displayLanguages' ? IDS.LANG_LIST : IDS.COUNTRIES_LIST); if (mapping && mapping.customItemsMasterKey && _currentSettings[displayKey] && Array.isArray(_currentSettings[mapping.customItemsMasterKey])) { const displayItems = _currentSettings[displayKey]; const currentDisplayCustomItems = displayItems.filter(item => item.type === 'custom'); const currentDisplayCustomItemValues = new Set(currentDisplayCustomItems.map(item => item.value)); const newMasterList = (_currentSettings[mapping.customItemsMasterKey] || []).filter(masterItem => currentDisplayCustomItemValues.has(masterItem.value)).map(oldMasterItem => { const correspondingDisplayItem = currentDisplayCustomItems.find(d => d.value === oldMasterItem.value); return correspondingDisplayItem ? { text: correspondingDisplayItem.text, value: oldMasterItem.value } : oldMasterItem; }); currentDisplayCustomItems.forEach(dispItem => { if (!newMasterList.find(mi => mi.value === dispItem.value)) { newMasterList.push({ text: dispItem.text, value: dispItem.value }); } }); _currentSettings[mapping.customItemsMasterKey] = newMasterList; } }); GM_setValue(STORAGE_KEY, JSON.stringify(_currentSettings)); console.log(`${LOG_PREFIX} Settings saved by SM${logContext ? ` (${logContext})` : ''}.`); _settingsBackup = JSON.parse(JSON.stringify(_currentSettings)); } catch (e) { console.error(`${LOG_PREFIX} SM save error:`, e); NotificationManager.show('alert_generic_error', { context: 'saving settings' }, 'error', 5000); } },
            reset: function(){ if(confirm(_('confirm_reset_settings'))){ _currentSettings = JSON.parse(JSON.stringify(_defaultSettingsRef)); _migrateToDisplayArraysIfNecessary(_currentSettings); if(!_currentSettings.sidebarSectionOrder||_currentSettings.sidebarSectionOrder.length===0){ _currentSettings.sidebarSectionOrder = [..._defaultSettingsRef.sidebarSectionOrder]; } LocalizationService.updateActiveLocale(_currentSettings); this.populateWindow(); _applySettingsToSidebar_cb(_currentSettings); _buildSidebarUI_cb(); _initMenuCommands_cb(); _showGlobalMessage('alert_settings_reset_success',{},'success',4000);}},
            resetAllFromMenu: function(){ if(confirm(_('confirm_reset_all_menu'))){ try{ GM_setValue(STORAGE_KEY,JSON.stringify(_defaultSettingsRef)); alert(_('alert_reset_all_menu_success')); }catch(e){ _showGlobalMessage('alert_reset_all_menu_fail',{},'error',0); }}},
            getCurrentSettings: function(){ return _currentSettings;},
            buildSkeleton: function(){ if(_settingsWindow)return; _settingsOverlay=document.createElement('div');_settingsOverlay.id=IDS.SETTINGS_OVERLAY;_settingsWindow=document.createElement('div');_settingsWindow.id=IDS.SETTINGS_WINDOW;const h=document.createElement('div');h.classList.add(CSS.SETTINGS_HEADER);h.innerHTML=`<h3>${_('settingsTitle')}</h3><button class="${CSS.SETTINGS_CLOSE_BTN}" title="${_('settings_close_button_title')}">${SVG_ICONS.close}</button>`;const mB=document.createElement('div');mB.id=IDS.SETTINGS_MESSAGE_BAR;mB.classList.add(CSS.MESSAGE_BAR);mB.style.display='none';const ts=document.createElement('div');ts.classList.add(CSS.SETTINGS_TABS);ts.innerHTML=`<button class="${CSS.TAB_BUTTON} ${CSS.ACTIVE}" data-${DATA_ATTR.TAB}="general">${_('settings_tab_general')}</button> <button class="${CSS.TAB_BUTTON}" data-${DATA_ATTR.TAB}="appearance">${_('settings_tab_appearance')}</button> <button class="${CSS.TAB_BUTTON}" data-${DATA_ATTR.TAB}="features">${_('settings_tab_features')}</button> <button class="${CSS.TAB_BUTTON}" data-${DATA_ATTR.TAB}="custom">${_('settings_tab_custom')}</button>`;const c=document.createElement('div');c.classList.add(CSS.SETTINGS_TAB_CONTENT);c.innerHTML=`<div class="${CSS.TAB_PANE} ${CSS.ACTIVE}" data-${DATA_ATTR.TAB}="general" id="${IDS.TAB_PANE_GENERAL}"></div><div class="${CSS.TAB_PANE}" data-${DATA_ATTR.TAB}="appearance" id="${IDS.TAB_PANE_APPEARANCE}"></div><div class="${CSS.TAB_PANE}" data-${DATA_ATTR.TAB}="features" id="${IDS.TAB_PANE_FEATURES}"></div><div class="${CSS.TAB_PANE}" data-${DATA_ATTR.TAB}="custom" id="${IDS.TAB_PANE_CUSTOM}"></div>`;const f=document.createElement('div');f.classList.add(CSS.SETTINGS_FOOTER);f.innerHTML=`<button class="${CSS.RESET_BUTTON}">${_('settings_reset_all_button')}</button><button class="${CSS.CANCEL_BUTTON}">${_('settings_cancel_button')}</button><button class="${CSS.SAVE_BUTTON}">${_('settings_save_button')}</button>`;_settingsWindow.appendChild(h);_settingsWindow.appendChild(mB);_settingsWindow.appendChild(ts);_settingsWindow.appendChild(c);_settingsWindow.appendChild(f);_settingsOverlay.appendChild(_settingsWindow);document.body.appendChild(_settingsOverlay);this.bindEvents();},
            populateWindow: function(){
                if(!_settingsWindow)return;
                try {
                    _settingsWindow.querySelector(`.${CSS.SETTINGS_HEADER} h3`).textContent=_( 'settingsTitle');
                    _settingsWindow.querySelector(`.${CSS.SETTINGS_CLOSE_BTN}`).title=_( 'settings_close_button_title');
                    _settingsWindow.querySelector(`button[data-${DATA_ATTR.TAB}="general"]`).textContent=_( 'settings_tab_general');
                    _settingsWindow.querySelector(`button[data-${DATA_ATTR.TAB}="appearance"]`).textContent=_( 'settings_tab_appearance');
                    _settingsWindow.querySelector(`button[data-${DATA_ATTR.TAB}="features"]`).textContent=_( 'settings_tab_features');
                    _settingsWindow.querySelector(`button[data-${DATA_ATTR.TAB}="custom"]`).textContent=_( 'settings_tab_custom');
                    _settingsWindow.querySelector(`.${CSS.RESET_BUTTON}`).textContent=_( 'settings_reset_all_button');
                    _settingsWindow.querySelector(`.${CSS.CANCEL_BUTTON}`).textContent=_( 'settings_cancel_button');
                    _settingsWindow.querySelector(`.${CSS.SAVE_BUTTON}`).textContent=_( 'settings_save_button');

                    const paneGeneral = _settingsWindow.querySelector(`#${IDS.TAB_PANE_GENERAL}`); if(paneGeneral) paneGeneral.innerHTML = SettingsUIPaneGenerator.createGeneralPaneHTML();
                    const paneAppearance = _settingsWindow.querySelector(`#${IDS.TAB_PANE_APPEARANCE}`); if(paneAppearance) paneAppearance.innerHTML = SettingsUIPaneGenerator.createAppearancePaneHTML();
                    const paneFeatures = _settingsWindow.querySelector(`#${IDS.TAB_PANE_FEATURES}`); if(paneFeatures) paneFeatures.innerHTML = SettingsUIPaneGenerator.createFeaturesPaneHTML();
                    const paneCustom = _settingsWindow.querySelector(`#${IDS.TAB_PANE_CUSTOM}`); if(paneCustom) paneCustom.innerHTML = SettingsUIPaneGenerator.createCustomPaneHTML();

                    _populateGeneralSettings_internal(_settingsWindow, _currentSettings);
                    _populateAppearanceSettings_internal(_settingsWindow, _currentSettings);
                    _populateFeatureSettings_internal(_settingsWindow, _currentSettings, _renderSectionOrderList_ext_cb);
                    ModalManager.resetEditStateGlobally(); _initializeActiveSettingsTab_internal();
                    this.bindLiveUpdateEvents(); this.bindFeaturesTabEvents();
                }catch(e){ _showGlobalMessage('alert_init_fail',{scriptName:SCRIPT_INTERNAL_NAME,error:"Settings UI pop err"},'error',0); }
            },
            show: function(){ if(!_settingsOverlay||!_settingsWindow)return;_settingsBackup = JSON.parse(JSON.stringify(_currentSettings));LocalizationService.updateActiveLocale(_currentSettings);this.populateWindow();applyThemeToElement(_settingsWindow, _currentSettings.theme);applyThemeToElement(_settingsOverlay, _currentSettings.theme);_settingsOverlay.style.display = 'flex';},
            hide: function(isCancel = false){ if(!_settingsOverlay)return;ModalManager.resetEditStateGlobally();if(ModalManager.isModalOpen()) ModalManager.hide(true);_settingsOverlay.style.display = 'none';const messageBar = document.getElementById(IDS.SETTINGS_MESSAGE_BAR);if(messageBar) messageBar.style.display = 'none';if(isCancel && _settingsBackup && Object.keys(_settingsBackup).length > 0){ _currentSettings = JSON.parse(JSON.stringify(_settingsBackup));LocalizationService.updateActiveLocale(_currentSettings);this.populateWindow();_applySettingsToSidebar_cb(_currentSettings);_buildSidebarUI_cb();_initMenuCommands_cb();} else if(isCancel) { console.warn(`${LOG_PREFIX} SM: Cancelled, no backup to restore or backup was identical.`); }},
            bindEvents: function(){
                if(!_settingsWindow || _settingsWindow.dataset.eventsBound === 'true') return;
                _settingsWindow.querySelector(`.${CSS.SETTINGS_CLOSE_BTN}`)?.addEventListener('click', () => this.hide(true));
                _settingsWindow.querySelector(`.${CSS.CANCEL_BUTTON}`)?.addEventListener('click', () => this.hide(true));
                _settingsWindow.querySelector(`.${CSS.SAVE_BUTTON}`)?.addEventListener('click', () => { this.save(); LocalizationService.updateActiveLocale(_currentSettings); _initMenuCommands_cb(); _buildSidebarUI_cb(); this.hide(false); });
                _settingsWindow.querySelector(`.${CSS.RESET_BUTTON}`)?.addEventListener('click', () => this.reset());
                const tabsContainer = _settingsWindow.querySelector(`.${CSS.SETTINGS_TABS}`);
                if(tabsContainer){ tabsContainer.addEventListener('click', e => { const targetButton = e.target.closest(`.${CSS.TAB_BUTTON}`); if(targetButton && !targetButton.classList.contains(CSS.ACTIVE)){ ModalManager.resetEditStateGlobally(); const tabToActivate = targetButton.dataset[DATA_ATTR.TAB]; if(!tabToActivate) return; tabsContainer.querySelectorAll(`.${CSS.TAB_BUTTON}`).forEach(b => b.classList.remove(CSS.ACTIVE)); targetButton.classList.add(CSS.ACTIVE); _settingsWindow.querySelector(`.${CSS.SETTINGS_TAB_CONTENT}`)?.querySelectorAll(`.${CSS.TAB_PANE}`)?.forEach(p => p.classList.remove(CSS.ACTIVE)); _settingsWindow.querySelector(`.${CSS.SETTINGS_TAB_CONTENT} .${CSS.TAB_PANE}[data-${DATA_ATTR.TAB}="${tabToActivate}"]`)?.classList.add(CSS.ACTIVE); } }); }
                _settingsWindow.dataset.eventsBound = 'true';
                const customTabPane = _settingsWindow.querySelector(`#${IDS.TAB_PANE_CUSTOM}`);
                if(customTabPane){ customTabPane.addEventListener('click', (e) => { const manageButton = e.target.closest(`button.${CSS.MANAGE_CUSTOM_BUTTON}`); if(manageButton){ const manageType = manageButton.dataset[DATA_ATTR.MANAGE_TYPE]; if(manageType){ ModalManager.openManageCustomOptions( manageType, _currentSettings, PREDEFINED_OPTIONS, (updatedItemsArray, newEnabledPredefs, itemsArrayKey, predefinedOptKey, customItemsMasterKey, isSortableMixed, manageTypeFromCallback) => { if (itemsArrayKey) { _currentSettings[itemsArrayKey] = updatedItemsArray; } if (predefinedOptKey && newEnabledPredefs && !isSortableMixed) { if (!_currentSettings.enabledPredefinedOptions) _currentSettings.enabledPredefinedOptions = {}; _currentSettings.enabledPredefinedOptions[predefinedOptKey] = newEnabledPredefs; } _buildSidebarUI_cb(); } ); } } }); }
            },
            bindLiveUpdateEvents: function(){ if(!_settingsWindow)return; _settingsWindow.querySelectorAll('input[type="range"]').forEach(el=>{ el.removeEventListener('input',_lUH_internal); el.addEventListener('input',_lUH_internal); }); _settingsWindow.querySelectorAll('select, input[type="checkbox"]:not([data-section-id])').forEach(el=>{ if(_sEH_internal[el.id]){ el.removeEventListener('change',_lUH_internal); el.addEventListener('change',_lUH_internal); } }); },
            bindFeaturesTabEvents: function() {
                const featuresPane = _settingsWindow?.querySelector(`#${IDS.TAB_PANE_FEATURES}`); if (!featuresPane) return;
                featuresPane.querySelectorAll(`input[type="checkbox"][data-${DATA_ATTR.SECTION_ID}]`).forEach(checkbox => { checkbox.removeEventListener('change', this._handleVisibleSectionChange); checkbox.addEventListener('change', this._handleVisibleSectionChange.bind(this)); });
                const siteSearchCheckboxModeEl = featuresPane.querySelector(`#${IDS.SETTING_SITE_SEARCH_CHECKBOX_MODE}`);
                if (siteSearchCheckboxModeEl && _sEH_internal[IDS.SETTING_SITE_SEARCH_CHECKBOX_MODE]) {
                    siteSearchCheckboxModeEl.removeEventListener('change', _lUH_internal);
                    siteSearchCheckboxModeEl.addEventListener('change', _lUH_internal);
                }
                const orderListElement = featuresPane.querySelector(`#${IDS.SIDEBAR_SECTION_ORDER_LIST}`);
                if (orderListElement) { SectionOrderDragHandler.initialize(orderListElement, _currentSettings, () => { _renderSectionOrderList_ext_cb(_currentSettings); _buildSidebarUI_cb(); }); }
            },
            _handleVisibleSectionChange: function(e){ const target = e.target; const sectionId = target.getAttribute(`data-${DATA_ATTR.SECTION_ID}`); if (sectionId && _currentSettings.visibleSections.hasOwnProperty(sectionId)) { _currentSettings.visibleSections[sectionId] = target.checked; _finalizeSectionOrder_internal(_currentSettings, _currentSettings, _defaultSettingsRef); _renderSectionOrderList_ext_cb(_currentSettings); _buildSidebarUI_cb(); } },
        };
        return publicApi;
    })();
    const DragManager = (function() {
        let _isDragging = false; let _dragStartX, _dragStartY, _sidebarStartX, _sidebarStartY;
        let _sidebarElement, _handleElement; let _settingsManagerRef, _saveCallbackRef;
        function _getEventCoordinates(e) { return (e.touches && e.touches.length > 0) ? { x: e.touches[0].clientX, y: e.touches[0].clientY } : { x: e.clientX, y: e.clientY }; }
        function _startDrag(e) { const currentSettings = _settingsManagerRef.getCurrentSettings(); if (!currentSettings.draggableHandleEnabled || currentSettings.sidebarCollapsed || (e.type === 'mousedown' && e.button !== 0)) { return; } e.preventDefault(); _isDragging = true; const coords = _getEventCoordinates(e); _dragStartX = coords.x; _dragStartY = coords.y; _sidebarStartX = _sidebarElement.offsetLeft; _sidebarStartY = _sidebarElement.offsetTop; _sidebarElement.style.cursor = 'grabbing'; _sidebarElement.style.userSelect = 'none'; document.body.style.cursor = 'grabbing'; }
        function _drag(e) { if (!_isDragging) return; e.preventDefault(); const coords = _getEventCoordinates(e); const dx = coords.x - _dragStartX; const dy = coords.y - _dragStartY; let newLeft = _sidebarStartX + dx; let newTop = _sidebarStartY + dy; const maxLeft = window.innerWidth - (_sidebarElement?.offsetWidth ?? 0); const maxTop = window.innerHeight - (_sidebarElement?.offsetHeight ?? 0); newLeft = Utils.clamp(newLeft, 0, maxLeft); newTop = Utils.clamp(newTop, MIN_SIDEBAR_TOP_POSITION, maxTop); if (_sidebarElement) { _sidebarElement.style.left = `${newLeft}px`; _sidebarElement.style.top = `${newTop}px`; } }
        function _stopDrag() { if (_isDragging) { _isDragging = false; if (_sidebarElement) { _sidebarElement.style.cursor = 'default'; _sidebarElement.style.userSelect = ''; } document.body.style.cursor = ''; const currentSettings = _settingsManagerRef.getCurrentSettings(); if (!currentSettings.sidebarPosition) currentSettings.sidebarPosition = {}; currentSettings.sidebarPosition.left = _sidebarElement.offsetLeft; currentSettings.sidebarPosition.top = _sidebarElement.offsetTop; if (typeof _saveCallbackRef === 'function') { _saveCallbackRef('Drag Stop'); } } }
        return { init: function(sidebarEl, handleEl, settingsMgr, saveCb) { _sidebarElement = sidebarEl; _handleElement = handleEl; _settingsManagerRef = settingsMgr; _saveCallbackRef = saveCb; if (_handleElement) { _handleElement.addEventListener('mousedown', _startDrag); _handleElement.addEventListener('touchstart', _startDrag, { passive: false }); } document.addEventListener('mousemove', _drag); document.addEventListener('touchmove', _drag, { passive: false }); document.addEventListener('mouseup', _stopDrag); document.addEventListener('touchend', _stopDrag); document.addEventListener('touchcancel', _stopDrag); }, setDraggable: function(isEnabled, sidebarEl, handleEl) { _sidebarElement = sidebarEl; _handleElement = handleEl; if (_handleElement) { _handleElement.style.display = isEnabled ? 'block' : 'none'; } } };
    })();
    const URLActionManager = (function() {
        function _getURLObject() { try { return new URL(window.location.href); } catch (e) { console.error(`${LOG_PREFIX} Error creating URL object: `, e); return null; }}
        function _navigateTo(url) { const urlString = url.toString(); window.location.href = urlString; }
        function _setSearchParam(urlObj, paramName, value) { urlObj.searchParams.set(paramName, value); }
        function _deleteSearchParam(urlObj, paramName) { urlObj.searchParams.delete(paramName); }
        function _getTbsParts(urlObj) { const tbs = urlObj.searchParams.get('tbs'); return tbs ? tbs.split(',').filter(p => p.trim() !== '') : []; }
        function _setTbsParam(urlObj, tbsPartsArray) { const newTbsValue = tbsPartsArray.join(','); if (newTbsValue) { _setSearchParam(urlObj, 'tbs', newTbsValue); } else { _deleteSearchParam(urlObj, 'tbs'); }}
        return {
            triggerResetFilters: function() {
                try {
                    const u = _getURLObject(); if (!u) return;
                    const q = u.searchParams.get('q') || '';
                    const nP = new URLSearchParams();
                    // Regex to remove (site:A OR site:B) and individual site:C, then clean up spaces
                    let cQ = q.replace(/\s*\(\s*(?:site:[\w.:()-]+(?:\s+OR\s+|$))+[^)]*\)\s*/gi, ' '); // Remove OR groups
                    cQ = cQ.replace(/\s*site:[\w.:()-]+\s*/gi, ' '); // Remove individual sites
                    cQ = cQ.replace(/\s\s+/g, ' ').trim(); // Clean spaces

                    if (cQ) { nP.set('q', cQ); }
                    // Remove other specific filter params
                    u.search = nP.toString(); // Set the cleaned query
                    _deleteSearchParam(u, 'tbs'); _deleteSearchParam(u, 'lr'); _deleteSearchParam(u, 'cr');
                    _deleteSearchParam(u, 'as_filetype'); _deleteSearchParam(u, 'filetype'); _deleteSearchParam(u, 'as_occt');
                    _navigateTo(u);
                } catch (e) {
                    NotificationManager.show('alert_error_resetting_filters', {}, 'error', 5000);
                }
            },
            triggerToggleVerbatim: function() { try { const u = _getURLObject(); if (!u) return; let tP = _getTbsParts(u); const vP = 'li:1'; const iCA = tP.includes(vP); tP = tP.filter(p => p !== vP); if (!iCA) { tP.push(vP); } _setTbsParam(u, tP); _navigateTo(u); } catch (e) { NotificationManager.show('alert_error_toggling_verbatim', {}, 'error', 5000); }},
            isPersonalizationActive: function() { try { const currentUrl = _getURLObject(); if (!currentUrl) { return true; } return currentUrl.searchParams.get('pws') !== '0'; } catch (e) { console.warn(`${LOG_PREFIX} [URLActionManager.isPersonalizationActive] Error checking personalization status:`, e); return true; } },
            triggerTogglePersonalization: function() { try { const u = _getURLObject(); if (!u) { return; } const personalizationCurrentlyActive = URLActionManager.isPersonalizationActive(); if (personalizationCurrentlyActive) { _setSearchParam(u, 'pws', '0'); } else { _deleteSearchParam(u, 'pws'); } _navigateTo(u); } catch (e) { NotificationManager.show('alert_error_toggling_personalization', {}, 'error', 5000); console.error(`${LOG_PREFIX} [URLActionManager.triggerTogglePersonalization] Error:`, e); } },
            applyFilter: function(type, value) {
                try {
                    const u = _getURLObject(); if (!u) return;
                    let tP = _getTbsParts(u);
                    let pTP;

                    const isTimeFilter = type === 'qdr';
                    const isStandaloneParam = ['lr', 'cr', 'as_occt'].includes(type);
                    const isFileType = type === 'filetype';

                    if (isTimeFilter) {
                        pTP = tP.filter(p => !p.startsWith(`qdr:`) && !p.startsWith('cdr:') && !p.startsWith('cd_min:') && !p.startsWith('cd_max:'));
                        if (value !== '') pTP.push(`qdr:${value}`);
                    } else if (isFileType) {
                        _deleteSearchParam(u, 'as_filetype');
                        pTP = tP.filter(p => !p.startsWith('ft:') && !p.startsWith('aft:'));
                        if (value !== '') _setSearchParam(u, 'as_filetype', value);
                    } else if (isStandaloneParam) {
                        _deleteSearchParam(u, type);
                        if (value !== '' && !(type === 'as_occt' && value === 'any')) {
                            _setSearchParam(u, type, value);
                        }
                        pTP = tP;
                    } else {
                        pTP = tP;
                    }
                    _setTbsParam(u, pTP);
                    _navigateTo(u);
                } catch (e) {
                    NotificationManager.show('alert_error_applying_filter', { type: type, value: value }, 'error', 5000);
                }
            },
            applySiteSearch: function(siteCriteria) {
                if (!siteCriteria) return;
                try {
                    const u = _getURLObject(); if (!u) return;
                    const q = u.searchParams.get('q') || '';

                    let qNS = q.replace(/\s*\(\s*(?:site:[\w.:()-]+(?:\s+OR\s+|$))+[^)]*\)\s*/gi, ' ');
                    qNS = qNS.replace(/\s*site:[\w.:()-]+\s*/gi, ' ');
                    qNS = qNS.replace(/\s\s+/g, ' ').trim();

                    let siteQueryPart = '';
                    if (Array.isArray(siteCriteria) && siteCriteria.length > 0) {
                        if (siteCriteria.length === 1) {
                            siteQueryPart = `site:${siteCriteria[0]}`;
                        } else {
                            siteQueryPart = `(${siteCriteria.map(s => `site:${s}`).join(' OR ')})`;
                        }
                    } else if (typeof siteCriteria === 'string' && siteCriteria.trim() !== '') {
                        siteQueryPart = `site:${siteCriteria}`;
                    }

                    const nQ = `${qNS} ${siteQueryPart}`.trim();
                    _setSearchParam(u, 'q', nQ);

                    _deleteSearchParam(u, 'tbs'); _deleteSearchParam(u, 'lr'); _deleteSearchParam(u, 'cr');
                    _deleteSearchParam(u, 'as_filetype'); _deleteSearchParam(u, 'filetype'); _deleteSearchParam(u, 'as_occt');
                    _navigateTo(u);
                } catch (e) {
                    const siteForError = Array.isArray(siteCriteria) ? siteCriteria.join(', ') : siteCriteria;
                    NotificationManager.show('alert_error_applying_site_search', { site: siteForError }, 'error', 5000);
                }
            },
            clearSiteSearch: function() {
                try {
                    const u = _getURLObject(); if (!u) return;
                    const q = u.searchParams.get('q') || '';
                    // Regex to remove (site:A OR site:B) and individual site:C, then clean up spaces
                    let nQ = q.replace(/\s*\(\s*(?:site:[\w.:()-]+(?:\s+OR\s+|$))+[^)]*\)\s*/gi, ' '); // Remove OR groups
                    nQ = nQ.replace(/\s*site:[\w.:()-]+\s*/gi, ' '); // Remove individual sites
                    nQ = nQ.replace(/\s\s+/g, ' ').trim(); // Clean spaces

                    if (nQ) { _setSearchParam(u, 'q', nQ); }
                    else { _deleteSearchParam(u, 'q'); } // If query becomes empty, remove q param
                    _navigateTo(u);
                } catch (e) {
                    NotificationManager.show('alert_error_clearing_site_search', {}, 'error', 5000);
                }
            },
            isVerbatimActive: function() { try { const currentUrl = _getURLObject(); if (!currentUrl) return false; return /li:1/.test(currentUrl.searchParams.get('tbs') || ''); } catch (e) { console.warn(`${LOG_PREFIX} Error checking verbatim status:`, e); return false; }},
            applyDateRange: function(dateMinStr, dateMaxStr) { try { const url = _getURLObject(); if (!url) return; let dateTbsPart = 'cdr:1'; if (dateMinStr) { const [y, m, d] = dateMinStr.split('-'); dateTbsPart += `,cd_min:${m}/${d}/${y}`; } if (dateMaxStr) { const [y, m, d] = dateMaxStr.split('-'); dateTbsPart += `,cd_max:${m}/${d}/${y}`; } let tbsParts = _getTbsParts(url); let preservedTbsParts = tbsParts.filter(p => !p.startsWith('qdr:') && !p.startsWith('cdr:') && !p.startsWith('cd_min:') && !p.startsWith('cd_max:')); let newTbsParts = [...preservedTbsParts, dateTbsPart]; _setTbsParam(url, newTbsParts); _navigateTo(url); } catch (e) { NotificationManager.show('alert_error_applying_date', {}, 'error', 5000); }}
        };
    })();

    function addGlobalStyles() { if (typeof window.GSCS_Namespace !== 'undefined' && typeof window.GSCS_Namespace.stylesText === 'string') { const cleanedCSS = window.GSCS_Namespace.stylesText.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '$1').replace(/\n\s*\n/g, '\n'); GM_addStyle(cleanedCSS); } else { console.error(`${LOG_PREFIX} CRITICAL: CSS styles provider not found.`); if (typeof IDS !== 'undefined' && IDS.SIDEBAR) { GM_addStyle(`#${IDS.SIDEBAR} { border: 3px dashed red !important; padding: 15px !important; background: white !important; color: red !important; } #${IDS.SIDEBAR}::before { content: "Error: CSS Missing!"; }`);} } }
    function setupSystemThemeListener() { if (systemThemeMediaQuery && systemThemeMediaQuery._sidebarThemeListener) { try { systemThemeMediaQuery.removeEventListener('change', systemThemeMediaQuery._sidebarThemeListener); } catch (e) {} systemThemeMediaQuery._sidebarThemeListener = null; } if (window.matchMedia) { systemThemeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); const listener = () => { const cs = SettingsManager.getCurrentSettings(); if (sidebar && cs.theme === 'system') { applyThemeToElement(sidebar, 'system'); } }; systemThemeMediaQuery.addEventListener('change', listener); systemThemeMediaQuery._sidebarThemeListener = listener; } }
    function buildSidebarSkeleton() { sidebar = document.createElement('div'); sidebar.id = IDS.SIDEBAR; const header = document.createElement('div'); header.classList.add(CSS.SIDEBAR_HEADER); const collapseBtn = document.createElement('button'); collapseBtn.id = IDS.COLLAPSE_BUTTON; collapseBtn.innerHTML = SVG_ICONS.chevronLeft; collapseBtn.title = _('sidebar_collapse_title'); const dragHandle = document.createElement('div'); dragHandle.classList.add(CSS.DRAG_HANDLE); dragHandle.title = _('sidebar_drag_title'); const settingsBtn = document.createElement('button'); settingsBtn.id = IDS.SETTINGS_BUTTON; settingsBtn.classList.add(CSS.SETTINGS_BUTTON); settingsBtn.innerHTML = SVG_ICONS.settings; settingsBtn.title = _('sidebar_settings_title'); header.appendChild(collapseBtn); header.appendChild(dragHandle); header.appendChild(settingsBtn); sidebar.appendChild(header); document.body.appendChild(sidebar); }
    function applySettings(settingsToApply) { if (!sidebar) return; const currentSettings = settingsToApply || SettingsManager.getCurrentSettings(); let targetTop = currentSettings.sidebarPosition.top; targetTop = Math.max(MIN_SIDEBAR_TOP_POSITION, targetTop); sidebar.style.left = `${currentSettings.sidebarPosition.left}px`; sidebar.style.top = `${targetTop}px`; sidebar.style.setProperty('--sidebar-font-base-size', `${currentSettings.fontSize}px`); sidebar.style.setProperty('--sidebar-header-icon-base-size', `${currentSettings.headerIconSize}px`); sidebar.style.setProperty('--sidebar-spacing-multiplier', currentSettings.verticalSpacingMultiplier); if (!currentSettings.sidebarCollapsed) { sidebar.style.width = `${currentSettings.sidebarWidth}px`; } else { sidebar.style.width = '40px';} applyThemeToElement(sidebar, currentSettings.theme); if (sidebar._hoverListeners) { sidebar.removeEventListener('mouseenter', sidebar._hoverListeners.enter); sidebar.removeEventListener('mouseleave', sidebar._hoverListeners.leave); sidebar._hoverListeners = null; sidebar.style.opacity = '1';} if (currentSettings.hoverMode && !currentSettings.sidebarCollapsed) { const idleOpacityValue = currentSettings.idleOpacity; sidebar.style.opacity = idleOpacityValue.toString(); const enterL = () => { if (!currentSettings.sidebarCollapsed) sidebar.style.opacity = '1'; }; const leaveL = () => { if (!currentSettings.sidebarCollapsed) sidebar.style.opacity = idleOpacityValue.toString(); }; sidebar.addEventListener('mouseenter', enterL); sidebar.addEventListener('mouseleave', leaveL); sidebar._hoverListeners = { enter: enterL, leave: leaveL }; } else { sidebar.style.opacity = '1'; } applySidebarCollapseVisuals(currentSettings.sidebarCollapsed); }
    function _parseTimeValueToMinutes(timeValue) { if (!timeValue || typeof timeValue !== 'string') return Infinity; const match = timeValue.match(/^([hdwmy])(\d*)$/i); if (!match) return Infinity; const unit = match[1].toLowerCase(); const number = parseInt(match[2] || '1', 10); if (isNaN(number)) return Infinity; switch (unit) { case 'h': return number * 60; case 'd': return number * 24 * 60; case 'w': return number * 7 * 24 * 60; case 'm': return number * 30 * 24 * 60; case 'y': return number * 365 * 24 * 60; default: return Infinity; } }
    function _prepareFilterOptions(sectionId, scriptDefinedOptions, currentSettings, predefinedOptionsSource) {
        const finalOptions = []; const tempAddedValues = new Set(); const sectionDef = ALL_SECTION_DEFINITIONS.find(s => s.id === sectionId); if (!sectionDef) return [];
        const isSortableMixedType = sectionDef.displayItemsKey && Array.isArray(currentSettings[sectionDef.displayItemsKey]);
        scriptDefinedOptions.forEach(opt => { if (opt && typeof opt.textKey === 'string' && typeof opt.v === 'string' && opt.v === '') { const translatedText = _(opt.textKey); finalOptions.push({ text: translatedText, value: opt.v, originalText: translatedText }); tempAddedValues.add(opt.v); } });
        if (isSortableMixedType) { const displayItems = currentSettings[sectionDef.displayItemsKey] || []; displayItems.forEach(item => { if (!tempAddedValues.has(item.value)) { let displayText = item.text; if (item.type === 'predefined' && item.originalKey) { displayText = _(item.originalKey); if (sectionId === IDS.COUNTRIES_LIST) { const parsed = Utils.parseIconAndText(displayText); displayText = `${parsed.icon} ${parsed.text}`.trim(); } } finalOptions.push({ text: displayText, value: item.value, originalText: displayText, isCustom: item.type === 'custom' }); tempAddedValues.add(item.value); } });
        } else {
            const predefinedKey = sectionDef.predefinedOptionsKey; const customKey = sectionDef.customItemsKey;
            const predefinedOptsFromSource = predefinedOptionsSource[predefinedKey] || [];
            const customOptsFromSettings = currentSettings[customKey] || [];
            const enabledPredefinedVals = currentSettings.enabledPredefinedOptions && currentSettings.enabledPredefinedOptions[predefinedKey] ? currentSettings.enabledPredefinedOptions[predefinedKey] : [];
            const combinedForSorting = []; const enabledSet = new Set(enabledPredefinedVals);
            if (Array.isArray(predefinedOptsFromSource)) { predefinedOptsFromSource.forEach(opt => { if (opt && typeof opt.textKey === 'string' && typeof opt.value === 'string' && enabledSet.has(opt.value) && !tempAddedValues.has(opt.value)) { const translatedText = _(opt.textKey); combinedForSorting.push({ text: translatedText, value: opt.value, originalText: translatedText, isCustom: false }); } }); }
            const validCustomOptions = Array.isArray(customOptsFromSettings) ? customOptsFromSettings.filter(cOpt => cOpt && typeof cOpt.text === 'string' && typeof cOpt.value === 'string') : [];
            validCustomOptions.forEach(opt => { if (!tempAddedValues.has(opt.value)){ combinedForSorting.push({ text: opt.text, value: opt.value, originalText: opt.text, isCustom: true }); } });
            const isTimeSection = (sectionId === 'sidebar-section-time');
            combinedForSorting.sort((a, b) => { if (isTimeSection) { const timeA = _parseTimeValueToMinutes(a.value); const timeB = _parseTimeValueToMinutes(b.value); if (timeA !== timeB) return timeA - timeB; } const sTA = a.originalText || a.text; const sTB = b.originalText || b.text; const sL = LocalizationService.getCurrentLocale() === 'en' ? undefined : LocalizationService.getCurrentLocale(); return sTA.localeCompare(sTB, sL, { numeric: true, sensitivity: 'base' }); });
            combinedForSorting.forEach(opt => { if (!tempAddedValues.has(opt.value)){ finalOptions.push(opt); tempAddedValues.add(opt.value); }});
        }
        scriptDefinedOptions.forEach(opt => { if (opt && typeof opt.textKey === 'string' && typeof opt.v === 'string' && opt.v !== '' && !tempAddedValues.has(opt.v)) { const translatedText = _(opt.textKey); finalOptions.push({ text: translatedText, value: opt.v, originalText: translatedText }); tempAddedValues.add(opt.v); } });
        return finalOptions;
    }
    function _createFilterOptionElement(optionData, filterParam, isCountrySection, countryDisplayMode) { const optionElement = document.createElement('div'); optionElement.classList.add(CSS.FILTER_OPTION); const displayText = optionData.text; if (isCountrySection) { const { icon, text: countryTextOnly } = Utils.parseIconAndText(displayText); switch (countryDisplayMode) { case 'textOnly': optionElement.textContent = countryTextOnly || displayText; break; case 'iconOnly': if (icon) { optionElement.innerHTML = `<span class="country-icon-container">${icon}</span>`; } else { optionElement.textContent = countryTextOnly || displayText; } break; case 'iconAndText': default: if (icon) { const textPart = countryTextOnly || displayText.substring(icon.length).trim(); optionElement.innerHTML = `<span class="country-icon-container">${icon}</span>${textPart}`; } else { optionElement.textContent = displayText; } break; } } else { optionElement.textContent = displayText; } optionElement.title = `${displayText} (${filterParam}=${optionData.value || _('filter_clear_tooltip_suffix')})`; optionElement.dataset[DATA_ATTR.FILTER_TYPE] = filterParam; optionElement.dataset[DATA_ATTR.FILTER_VALUE] = optionData.value; return optionElement; }
    function buildSidebarUI() { if (!sidebar) { console.error("Sidebar element not ready for buildSidebarUI"); return; } const currentSettings = SettingsManager.getCurrentSettings(); const header = sidebar.querySelector(`.${CSS.SIDEBAR_HEADER}`); if (!header) { console.error("Sidebar header not found in buildSidebarUI"); return; } sidebar.querySelectorAll(`#${IDS.FIXED_TOP_BUTTONS}, .${CSS.SIDEBAR_CONTENT_WRAPPER}`).forEach(el => el.remove()); header.querySelectorAll(`.${CSS.HEADER_BUTTON}:not(#${IDS.SETTINGS_BUTTON}):not(#${IDS.COLLAPSE_BUTTON}), a.${CSS.HEADER_BUTTON}`).forEach(el => el.remove()); const rBL = currentSettings.resetButtonLocation; const vBL = currentSettings.verbatimButtonLocation; const aSL = currentSettings.advancedSearchLinkLocation; const pznBL = currentSettings.personalizationButtonLocation; const settingsButtonRef = header.querySelector(`#${IDS.SETTINGS_BUTTON}`); _buildSidebarHeaderControls(header, settingsButtonRef, rBL, vBL, aSL, pznBL, _createAdvancedSearchElementHTML, _createPersonalizationButtonHTML, currentSettings); const fixedTopControlsContainer = _buildSidebarFixedTopControls(rBL, vBL, aSL, pznBL, _createAdvancedSearchElementHTML, _createPersonalizationButtonHTML, currentSettings); if (fixedTopControlsContainer) { header.after(fixedTopControlsContainer); } const contentWrapper = document.createElement('div'); contentWrapper.classList.add(CSS.SIDEBAR_CONTENT_WRAPPER); const sectionDefinitionsMap = new Map(ALL_SECTION_DEFINITIONS.map(def => [def.id, def])); const sectionsFragment = _buildSidebarSections(sectionDefinitionsMap, rBL, vBL, aSL, pznBL, _createAdvancedSearchElementHTML, _createPersonalizationButtonHTML, currentSettings, PREDEFINED_OPTIONS); contentWrapper.appendChild(sectionsFragment); sidebar.appendChild(contentWrapper); _initializeSidebarEventListenersAndStates(); }
    function _buildSidebarSections(sectionDefinitionMap, rBL, vBL, aSL, pznBL, createAdvancedSearchElementFn, createPersonalizationButtonFn, currentSettings, PREDEFINED_OPTIONS_REF) { const contentFragment = document.createDocumentFragment(); currentSettings.sidebarSectionOrder.forEach(sectionId => { if (!currentSettings.visibleSections[sectionId]) return; const sectionData = sectionDefinitionMap.get(sectionId); if (!sectionData) { console.warn(`${LOG_PREFIX} No definition for section ID: ${sectionId}`); return; } let sectionElement = null; const sectionTitleKey = sectionData.titleKey; const sectionIdForDisplay = sectionData.id; switch (sectionData.type) { case 'filter': sectionElement = createFilterSection(sectionIdForDisplay, sectionTitleKey, sectionData.scriptDefined, sectionData.param, currentSettings, PREDEFINED_OPTIONS_REF, currentSettings.countryDisplayMode); break; case 'date': sectionElement = _createDateSectionElement(sectionIdForDisplay, sectionTitleKey); break; case 'site': sectionElement = _createSiteSearchSectionElement(sectionIdForDisplay, sectionTitleKey, currentSettings.favoriteSites, currentSettings.enableSiteSearchCheckboxMode); break; case 'tools': sectionElement = _createToolsSectionElement( sectionIdForDisplay, sectionTitleKey, rBL, vBL, aSL, pznBL, createAdvancedSearchElementFn, createPersonalizationButtonFn ); break; default: console.warn(`${LOG_PREFIX} Unknown section type: ${sectionData.type} for ID: ${sectionIdForDisplay}`); break; } if (sectionElement) contentFragment.appendChild(sectionElement); }); return contentFragment; }
    function createFilterSection(id, titleKey, scriptDefinedOptions, filterParam, currentSettings, predefinedOptionsSource, countryDisplayMode) { if (!sidebar) return null; const { section, sectionContent, sectionTitle } = _createSectionShell(id, titleKey); sectionTitle.textContent = _(titleKey); const fragment = document.createDocumentFragment(); const isCountrySection = (id === 'sidebar-section-country'); const combinedOptions = _prepareFilterOptions(id, scriptDefinedOptions, currentSettings, predefinedOptionsSource); combinedOptions.forEach(option => { fragment.appendChild(_createFilterOptionElement(option, filterParam, isCountrySection, countryDisplayMode)); }); sectionContent.innerHTML = ''; sectionContent.appendChild(fragment); if (!sectionContent.dataset.filterClickListenerAttached) { sectionContent.addEventListener('click', function(event) { const target = event.target.closest(`.${CSS.FILTER_OPTION}`); if (target && target.classList.contains(CSS.FILTER_OPTION)) { event.preventDefault(); const clickedFilterType = target.dataset[DATA_ATTR.FILTER_TYPE]; const clickedFilterValue = target.dataset[DATA_ATTR.FILTER_VALUE]; if (typeof clickedFilterType !== 'undefined' && typeof clickedFilterValue !== 'undefined') { this.querySelectorAll(`.${CSS.FILTER_OPTION}`).forEach(opt => opt.classList.remove(CSS.SELECTED)); target.classList.add(CSS.SELECTED); if (clickedFilterValue === '' || (clickedFilterType === 'as_occt' && clickedFilterValue === 'any') ) { const defaultVal = (clickedFilterType === 'as_occt') ? 'any' : ''; const anyOpt = this.querySelector(`.${CSS.FILTER_OPTION}[data-${DATA_ATTR.FILTER_VALUE}="${defaultVal}"]`); if (anyOpt) anyOpt.classList.add(CSS.SELECTED); } URLActionManager.applyFilter(clickedFilterType, clickedFilterValue); } } }); sectionContent.dataset.filterClickListenerAttached = 'true'; } return section; }
    function _createSiteSearchSectionElement(sectionId, titleKey, favoriteSites, checkboxModeEnabled) { const { section, sectionContent, sectionTitle } = _createSectionShell(sectionId, titleKey); sectionTitle.textContent = _(titleKey); const list = document.createElement('ul'); list.classList.add(CSS.CUSTOM_LIST); if (checkboxModeEnabled) list.classList.add('checkbox-mode-enabled'); sectionContent.appendChild(list); populateSiteSearchList(list, favoriteSites, checkboxModeEnabled); return section; }
    function populateSiteSearchList(listElement, favoriteSitesArray, checkboxModeEnabled) {
        if (!listElement) { console.error("Site search list element missing"); return; }
        listElement.innerHTML = '';
        const sites = Array.isArray(favoriteSitesArray) ? favoriteSitesArray : [];
        const fragment = document.createDocumentFragment();

        sites.forEach((site, index) => {
            if (site?.text && site?.url) {
                const li = document.createElement('li');
                if (checkboxModeEnabled) {
                    const checkbox = document.createElement('input');
                    checkbox.type = 'checkbox';
                    checkbox.id = `site-cb-${index}`;
                    checkbox.value = site.url;
                    checkbox.classList.add(CSS.SITE_SEARCH_ITEM_CHECKBOX);
                    checkbox.dataset[DATA_ATTR.SITE_URL] = site.url;
                    li.appendChild(checkbox);
                }

                const opt = document.createElement(checkboxModeEnabled ? 'label' : 'div');
                if (checkboxModeEnabled) {
                    opt.htmlFor = `site-cb-${index}`;
                } else {
                    opt.classList.add(CSS.FILTER_OPTION);
                }
                opt.dataset[DATA_ATTR.SITE_URL] = site.url;
                opt.title = _('tooltip_site_search', { siteUrl: site.url });
                opt.textContent = site.text;

                li.appendChild(opt);
                fragment.appendChild(li);
            }
        });

        const clearLi = document.createElement('li');
        const clearOpt = document.createElement('div');
        clearOpt.classList.add(CSS.FILTER_OPTION);
        clearOpt.id = 'clear-site-search-option';
        clearOpt.title = _('tooltip_clear_site_search');
        clearOpt.textContent = _('filter_clear_site_search');
        clearLi.appendChild(clearOpt);
        fragment.appendChild(clearLi);

        listElement.appendChild(fragment);

        if (checkboxModeEnabled) {
            const applyButton = document.createElement('button');
            applyButton.id = IDS.APPLY_SELECTED_SITES_BUTTON;
            applyButton.classList.add(CSS.TOOL_BUTTON, CSS.APPLY_SITES_BUTTON);
            applyButton.textContent = _('tool_apply_selected_sites');
            applyButton.disabled = true;
            applyButton.style.display = 'none';
            listElement.parentElement.appendChild(applyButton);
        }

        if (!listElement.dataset.siteSearchClickListenerAttached) {
            listElement.dataset.siteSearchClickListenerAttached = 'true';
            listElement.addEventListener('click', (event) => {
                const target = event.target;
                const currentSettings = SettingsManager.getCurrentSettings(); // Get current settings
                const isCheckboxMode = currentSettings.enableSiteSearchCheckboxMode;

                if (target.id === 'clear-site-search-option') {
                    URLActionManager.clearSiteSearch();
                    listElement.querySelectorAll(`.${CSS.FILTER_OPTION}.${CSS.SELECTED}`).forEach(o => o.classList.remove(CSS.SELECTED));
                    target.classList.add(CSS.SELECTED);
                    if (isCheckboxMode) {
                        listElement.querySelectorAll(`input[type="checkbox"].${CSS.SITE_SEARCH_ITEM_CHECKBOX}`).forEach(cb => cb.checked = false);
                        _updateApplySitesButtonState(listElement.parentElement);
                    }
                } else if (isCheckboxMode) {
                    if (target.tagName === 'LABEL' || (target.classList.contains(CSS.FILTER_OPTION) && target.tagName === 'DIV')) { // Click on text/label or DIV wrapper if any
                        const siteUrl = target.dataset[DATA_ATTR.SITE_URL];
                        if (siteUrl) {
                            // Single site search: uncheck others, check this one
                            listElement.querySelectorAll(`input[type="checkbox"].${CSS.SITE_SEARCH_ITEM_CHECKBOX}`).forEach(cb => {
                                cb.checked = (cb.value === siteUrl);
                            });
                             URLActionManager.applySiteSearch(siteUrl); // Apply single site search immediately
                            _updateApplySitesButtonState(listElement.parentElement);
                             // Update visual selection for labels
                            listElement.querySelectorAll(`label[data-${DATA_ATTR.SITE_URL}], div.${CSS.FILTER_OPTION}[data-${DATA_ATTR.SITE_URL}]`).forEach(lbl => lbl.classList.remove(CSS.SELECTED));
                            if(target.tagName === 'LABEL') target.classList.add(CSS.SELECTED);
                            else if (target.classList.contains(CSS.FILTER_OPTION)) target.classList.add(CSS.SELECTED);

                        }
                    }
                } else { // Traditional mode
                    const siteUrl = target.closest(`.${CSS.FILTER_OPTION}`)?.dataset[DATA_ATTR.SITE_URL];
                    if (siteUrl) {
                        listElement.querySelectorAll(`.${CSS.FILTER_OPTION}.${CSS.SELECTED}`).forEach(o => o.classList.remove(CSS.SELECTED));
                        URLActionManager.applySiteSearch(siteUrl);
                        target.closest(`.${CSS.FILTER_OPTION}`).classList.add(CSS.SELECTED);
                    }
                }
            });

            if (checkboxModeEnabled) {
                listElement.addEventListener('change', (event) => {
                    if (event.target.matches(`input[type="checkbox"].${CSS.SITE_SEARCH_ITEM_CHECKBOX}`)) {
                        _updateApplySitesButtonState(listElement.parentElement);
                    }
                });

                const sectionContent = listElement.parentElement;
                const applyBtn = sectionContent.querySelector(`#${IDS.APPLY_SELECTED_SITES_BUTTON}`);
                if(applyBtn && !applyBtn.dataset[DATA_ATTR.LISTENER_ATTACHED]){
                    applyBtn.dataset[DATA_ATTR.LISTENER_ATTACHED] = 'true';
                    applyBtn.addEventListener('click', () => {
                        const selectedSiteUrls = [];
                        sectionContent.querySelectorAll(`input[type="checkbox"].${CSS.SITE_SEARCH_ITEM_CHECKBOX}:checked`).forEach(cb => {
                            selectedSiteUrls.push(cb.value);
                        });
                        if (selectedSiteUrls.length > 0) {
                            URLActionManager.applySiteSearch(selectedSiteUrls);
                            // Update visual selection for labels/divs to match checkboxes
                            sectionContent.querySelectorAll(`label[data-${DATA_ATTR.SITE_URL}], div.${CSS.FILTER_OPTION}[data-${DATA_ATTR.SITE_URL}]`).forEach(lbl => lbl.classList.remove(CSS.SELECTED));
                            selectedSiteUrls.forEach(url => {
                                const item = sectionContent.querySelector(`[data-${DATA_ATTR.SITE_URL}="${url}"]`); // This could be checkbox or label/div
                                if(item){
                                    if(item.tagName === 'INPUT' && item.nextElementSibling) item.nextElementSibling.classList.add(CSS.SELECTED);
                                    else if (item.tagName === 'LABEL' || item.tagName === 'DIV') item.classList.add(CSS.SELECTED);
                                }
                            });
                        }
                    });
                }
            }
        }
    }

    function _updateApplySitesButtonState(sectionContentElement) {
        if (!sectionContentElement) return;
        const applyButton = sectionContentElement.querySelector(`#${IDS.APPLY_SELECTED_SITES_BUTTON}`);
        if (!applyButton) return;
        const checkedCount = sectionContentElement.querySelectorAll(`input[type="checkbox"].${CSS.SITE_SEARCH_ITEM_CHECKBOX}:checked`).length;
        applyButton.disabled = checkedCount === 0;
        applyButton.style.display = checkedCount > 0 ? 'inline-flex' : 'none';
    }


    function renderSectionOrderList(settingsRef) { const settingsWindowEl = document.getElementById(IDS.SETTINGS_WINDOW); const orderListElement = settingsWindowEl?.querySelector(`#${IDS.SIDEBAR_SECTION_ORDER_LIST}`); if (!orderListElement) return; orderListElement.innerHTML = ''; const currentSettings = settingsRef || SettingsManager.getCurrentSettings(); const visibleOrderedSections = currentSettings.sidebarSectionOrder.filter(id => currentSettings.visibleSections[id]); if (visibleOrderedSections.length === 0) { orderListElement.innerHTML = `<li><span style="font-style:italic;color:var(--settings-tab-color);">${_('settings_no_orderable_sections')}</span></li>`; return; } const fragment = document.createDocumentFragment(); visibleOrderedSections.forEach((sectionId) => { const definition = ALL_SECTION_DEFINITIONS.find(def => def.id === sectionId); const displayName = definition ? _(definition.titleKey) : sectionId; const listItem = document.createElement('li'); listItem.dataset.sectionId = sectionId; listItem.draggable = true; const dragIconSpan = document.createElement('span'); dragIconSpan.classList.add(CSS.DRAG_ICON); dragIconSpan.innerHTML = SVG_ICONS.dragGrip; listItem.appendChild(dragIconSpan); const nameSpan = document.createElement('span'); nameSpan.textContent = displayName; listItem.appendChild(nameSpan); fragment.appendChild(listItem); }); orderListElement.appendChild(fragment); }
    function _initMenuCommands() { if (typeof GM_registerMenuCommand === 'function') { const openSettingsText = _('menu_open_settings'); const resetAllText = _('menu_reset_all_settings'); if (typeof GM_unregisterMenuCommand === 'function') { try { GM_unregisterMenuCommand(openSettingsText); } catch (e) {} try { GM_unregisterMenuCommand(resetAllText);   } catch (e) {} } GM_registerMenuCommand(openSettingsText, SettingsManager.show.bind(SettingsManager)); GM_registerMenuCommand(resetAllText, SettingsManager.resetAllFromMenu.bind(SettingsManager)); } }
    function _createSectionShell(id, titleKey) { const section = document.createElement('div'); section.id = id; section.classList.add(CSS.SIDEBAR_SECTION); const sectionTitle = document.createElement('div'); sectionTitle.classList.add(CSS.SECTION_TITLE); sectionTitle.textContent = _(titleKey); section.appendChild(sectionTitle); const sectionContent = document.createElement('div'); sectionContent.classList.add(CSS.SECTION_CONTENT); section.appendChild(sectionContent); return { section, sectionContent, sectionTitle }; }
    function _createDateSectionElement(sectionId, titleKey) { const { section, sectionContent, sectionTitle } = _createSectionShell(sectionId, titleKey); sectionTitle.textContent = _(titleKey); const today = new Date(); const yyyy = today.getFullYear(); const mm = String(today.getMonth() + 1).padStart(2, '0'); const dd = String(today.getDate()).padStart(2, '0'); const todayString = `${yyyy}-${mm}-${dd}`; sectionContent.innerHTML = `<label class="${CSS.DATE_INPUT_LABEL}" for="${IDS.DATE_MIN}">${_('date_range_from')}</label>` + `<input type="date" class="${CSS.DATE_INPUT}" id="${IDS.DATE_MIN}" max="${todayString}">` + `<label class="${CSS.DATE_INPUT_LABEL}" for="${IDS.DATE_MAX}">${_('date_range_to')}</label>` + `<input type="date" class="${CSS.DATE_INPUT}" id="${IDS.DATE_MAX}" max="${todayString}">` + `<span id="${IDS.DATE_RANGE_ERROR_MSG}" class="${CSS.DATE_RANGE_ERROR_MSG} ${CSS.INPUT_ERROR_MESSAGE}"></span>` + `<button class="${CSS.TOOL_BUTTON} apply-date-range">${_('tool_apply_date')}</button>`; return section; }
    function _createStandardButton({ id = null, className, svgIcon, textContent = null, title, clickHandler, isActive = false }) { const button = document.createElement('button'); if (id) button.id = id; button.classList.add(className); if (isActive) button.classList.add(CSS.ACTIVE); button.title = title; let content = svgIcon || ''; if (textContent) { content = svgIcon ? `${svgIcon} ${textContent}` : textContent; } button.innerHTML = content.trim(); if (clickHandler) { if (!button.dataset[DATA_ATTR.LISTENER_ATTACHED]) { button.addEventListener('click', clickHandler); button.dataset[DATA_ATTR.LISTENER_ATTACHED] = 'true'; } } return button; }
    function _createPersonalizationButtonHTML(forLocation = 'tools') { const personalizationActive = URLActionManager.isPersonalizationActive(); const isIconOnlyLocation = (forLocation === 'header'); const svgIcon = SVG_ICONS.personalization || ''; const displayText = !isIconOnlyLocation ? _('tool_personalization_toggle') : ''; const titleKey = personalizationActive ? 'tooltip_toggle_personalization_off' : 'tooltip_toggle_personalization_on'; return _createStandardButton({ id: IDS.TOOL_PERSONALIZE, className: (forLocation === 'header') ? CSS.HEADER_BUTTON : CSS.TOOL_BUTTON, svgIcon: svgIcon, textContent: displayText, title: _(titleKey), clickHandler: () => URLActionManager.triggerTogglePersonalization(), isActive: personalizationActive }); }
    function _createAdvancedSearchElementHTML(isButtonLike = false) { const el = document.createElement('a'); let iconHTML = SVG_ICONS.magnifyingGlass || ''; if (isButtonLike) { el.classList.add(CSS.TOOL_BUTTON); el.innerHTML = `${iconHTML} ${_('tool_advanced_search')}`; } else { el.classList.add(CSS.HEADER_BUTTON); el.innerHTML = iconHTML; } const baseUrl = "https://www.google.com/advanced_search"; let finalUrl = baseUrl; try { const currentFullUrl = Utils.getCurrentURL(); if (currentFullUrl) { const currentQuery = currentFullUrl.searchParams.get('q'); if (currentQuery) { let queryWithoutSite = currentQuery.replace(/\s*\(\s*(?:site:[\w.:()-]+(?:\s+OR\s+|$))+[^)]*\)\s*/gi, ' '); queryWithoutSite = queryWithoutSite.replace(/\s*site:[\w.:()-]+\s*/gi, ' '); queryWithoutSite = queryWithoutSite.replace(/\s\s+/g, ' ').trim(); if (queryWithoutSite) { finalUrl = `${baseUrl}?as_q=${encodeURIComponent(queryWithoutSite)}`; } } } } catch (e) { console.warn(`${LOG_PREFIX} Error constructing advanced search URL with query:`, e); } el.href = finalUrl; el.target = "_blank"; el.rel = "noopener noreferrer"; el.title = _('link_advanced_search_title'); return el; }
    function _buildSidebarHeaderControls(headerEl, settingsBtnRef, rBL, vBL, aSL, pznBL, advSearchFn, personalizeBtnFn, settings) { const verbatimActive = URLActionManager.isVerbatimActive(); const buttonsInOrder = []; if (aSL === 'header' && advSearchFn && settings.advancedSearchLinkLocation !== 'none') { buttonsInOrder.push(advSearchFn(false)); } if (vBL === 'header' && settings.verbatimButtonLocation !== 'none') { buttonsInOrder.push(_createStandardButton({ id: IDS.TOOL_VERBATIM, className: CSS.HEADER_BUTTON, svgIcon: SVG_ICONS.verbatim, title: _('tool_verbatim_search'), clickHandler: URLActionManager.triggerToggleVerbatim, isActive: verbatimActive })); } if (pznBL === 'header' && personalizeBtnFn && settings.personalizationButtonLocation !== 'none') { buttonsInOrder.push(personalizeBtnFn('header')); } if (rBL === 'header' && settings.resetButtonLocation !== 'none') { buttonsInOrder.push(_createStandardButton({ id: IDS.TOOL_RESET_BUTTON, className: CSS.HEADER_BUTTON, svgIcon: SVG_ICONS.reset, title: _('tool_reset_filters'), clickHandler: URLActionManager.triggerResetFilters })); } buttonsInOrder.forEach(btn => { if (settingsBtnRef) { headerEl.insertBefore(btn, settingsBtnRef); } else { headerEl.appendChild(btn); } }); }
    function _buildSidebarFixedTopControls(rBL, vBL, aSL, pznBL, advSearchFn, personalizeBtnFn, settings) { const fTBC = document.createElement('div'); fTBC.id = IDS.FIXED_TOP_BUTTONS; const fTF = document.createDocumentFragment(); const verbatimActive = URLActionManager.isVerbatimActive(); if (rBL === 'topBlock' && settings.resetButtonLocation !== 'none') { const btn = _createStandardButton({ id: IDS.TOOL_RESET_BUTTON, className: CSS.TOOL_BUTTON, svgIcon: SVG_ICONS.reset, textContent: _('tool_reset_filters'), title: _('tool_reset_filters'), clickHandler: URLActionManager.triggerResetFilters }); const bD = document.createElement('div'); bD.classList.add(CSS.FIXED_TOP_BUTTON_ITEM); bD.appendChild(btn); fTF.appendChild(bD); } if (pznBL === 'topBlock' && personalizeBtnFn && settings.personalizationButtonLocation !== 'none') { const btnPzn = personalizeBtnFn('topBlock'); const bDPzn = document.createElement('div'); bDPzn.classList.add(CSS.FIXED_TOP_BUTTON_ITEM); bDPzn.appendChild(btnPzn); fTF.appendChild(bDPzn); } if (vBL === 'topBlock' && settings.verbatimButtonLocation !== 'none') { const btnVerbatim = _createStandardButton({ id: IDS.TOOL_VERBATIM, className: CSS.TOOL_BUTTON, svgIcon: SVG_ICONS.verbatim, textContent: _('tool_verbatim_search'), title: _('tool_verbatim_search'), clickHandler: URLActionManager.triggerToggleVerbatim, isActive: verbatimActive }); const bDVerbatim = document.createElement('div'); bDVerbatim.classList.add(CSS.FIXED_TOP_BUTTON_ITEM); bDVerbatim.appendChild(btnVerbatim); fTF.appendChild(bDVerbatim); } if (aSL === 'topBlock' && advSearchFn && settings.advancedSearchLinkLocation !== 'none') { const linkEl = advSearchFn(true); const bDAdv = document.createElement('div'); bDAdv.classList.add(CSS.FIXED_TOP_BUTTON_ITEM); bDAdv.appendChild(linkEl); fTF.appendChild(bDAdv); } if (fTF.childElementCount > 0) { fTBC.appendChild(fTF); return fTBC; } return null; }
    function _createToolsSectionElement(sectionId, titleKey, rBL, vBL, aSL, pznBL, advSearchFn, personalizeBtnFn) { const { section, sectionContent, sectionTitle } = _createSectionShell(sectionId, titleKey); sectionTitle.textContent = _(titleKey); const frag = document.createDocumentFragment(); const verbatimActive = URLActionManager.isVerbatimActive(); const currentSettings = SettingsManager.getCurrentSettings(); if (rBL === 'tools' && currentSettings.resetButtonLocation !== 'none') { const btn = _createStandardButton({ id: IDS.TOOL_RESET_BUTTON, className: CSS.TOOL_BUTTON, svgIcon: SVG_ICONS.reset, textContent: _('tool_reset_filters'), title: _('tool_reset_filters'), clickHandler: URLActionManager.triggerResetFilters }); frag.appendChild(btn); } if (pznBL === 'tools' && personalizeBtnFn && currentSettings.personalizationButtonLocation !== 'none') { const btnPzn = personalizeBtnFn('tools'); frag.appendChild(btnPzn); } if (vBL === 'tools' && currentSettings.verbatimButtonLocation !== 'none') { const btnVerbatim = _createStandardButton({ id: IDS.TOOL_VERBATIM, className: CSS.TOOL_BUTTON, svgIcon: SVG_ICONS.verbatim, textContent: _('tool_verbatim_search'), title: _('tool_verbatim_search'), clickHandler: URLActionManager.triggerToggleVerbatim, isActive: verbatimActive }); frag.appendChild(btnVerbatim); } if (aSL === 'tools' && advSearchFn && currentSettings.advancedSearchLinkLocation !== 'none') { frag.appendChild(advSearchFn(true)); } if (frag.childElementCount > 0) { sectionContent.appendChild(frag); return section; } return null; }
    function _validateDateInputs(minInput, maxInput, errorMsgElement) { _clearElementMessage(errorMsgElement, CSS.ERROR_VISIBLE); minInput.classList.remove(CSS.INPUT_HAS_ERROR); maxInput.classList.remove(CSS.INPUT_HAS_ERROR); let isValid = true; const today = new Date(); today.setHours(0, 0, 0, 0); const startDateStr = minInput.value; const endDateStr = maxInput.value; let startDate = null; let endDate = null; if (startDateStr) { startDate = new Date(startDateStr); startDate.setHours(0,0,0,0); if (startDate > today) { _showElementMessage(errorMsgElement, 'alert_start_in_future', {}, CSS.ERROR_VISIBLE); minInput.classList.add(CSS.INPUT_HAS_ERROR); isValid = false; } } if (endDateStr) { endDate = new Date(endDateStr); endDate.setHours(0,0,0,0); if (endDate > today && !maxInput.getAttribute('max')) { if (isValid) _showElementMessage(errorMsgElement, 'alert_end_in_future', {}, CSS.ERROR_VISIBLE); else errorMsgElement.textContent += " " + _('alert_end_in_future'); maxInput.classList.add(CSS.INPUT_HAS_ERROR); isValid = false; } } if (startDate && endDate && startDate > endDate) { if (isValid) _showElementMessage(errorMsgElement, 'alert_end_before_start', {}, CSS.ERROR_VISIBLE); else errorMsgElement.textContent += " " + _('alert_end_before_start'); minInput.classList.add(CSS.INPUT_HAS_ERROR); maxInput.classList.add(CSS.INPUT_HAS_ERROR); isValid = false; } return isValid; }
    function addDateRangeListener() { const dateRangeSection = sidebar?.querySelector('#sidebar-section-date-range'); if (!dateRangeSection) return; const applyButton = dateRangeSection.querySelector('.apply-date-range'); const errorMsgElement = dateRangeSection.querySelector(`#${IDS.DATE_RANGE_ERROR_MSG}`); const dateMinInput = dateRangeSection.querySelector(`#${IDS.DATE_MIN}`); const dateMaxInput = dateRangeSection.querySelector(`#${IDS.DATE_MAX}`); if (!applyButton || !errorMsgElement || !dateMinInput || !dateMaxInput) { console.warn(`${LOG_PREFIX} Date range elements not found for listener setup.`); return; } const handleDateValidation = () => { const isValid = _validateDateInputs(dateMinInput, dateMaxInput, errorMsgElement); applyButton.disabled = !isValid; }; if (!dateMinInput.dataset[DATA_ATTR.LISTENER_ATTACHED]) { dateMinInput.addEventListener('input', handleDateValidation); dateMinInput.addEventListener('change', handleDateValidation); dateMinInput.dataset[DATA_ATTR.LISTENER_ATTACHED] = 'true'; } if (!dateMaxInput.dataset[DATA_ATTR.LISTENER_ATTACHED]) { dateMaxInput.addEventListener('input', handleDateValidation); dateMaxInput.addEventListener('change', handleDateValidation); dateMaxInput.dataset[DATA_ATTR.LISTENER_ATTACHED] = 'true'; } if (!applyButton.dataset[DATA_ATTR.LISTENER_ATTACHED]) { applyButton.dataset[DATA_ATTR.LISTENER_ATTACHED] = 'true'; applyButton.addEventListener('click', () => { if (!_validateDateInputs(dateMinInput, dateMaxInput, errorMsgElement)) return; URLActionManager.applyDateRange(dateMinInput.value, dateMaxInput.value); }); } handleDateValidation(); }
    function _initializeSidebarEventListenersAndStates() { addDateRangeListener(); addToolButtonListeners(); initializeSelectedFilters(); applySectionCollapseStates(); }
    function _clearElementMessage(element, visibleClass = CSS.ERROR_VISIBLE) { if(!element)return; element.textContent=''; element.classList.remove(visibleClass);}
    function _showElementMessage(element, messageKey, messageArgs = {}, visibleClass = CSS.ERROR_VISIBLE) { if(!element)return; element.textContent=_(messageKey,messageArgs); element.classList.add(visibleClass);}
    function addToolButtonListeners() { const queryAreas = [ sidebar?.querySelector(`.${CSS.SIDEBAR_HEADER}`), sidebar?.querySelector(`#${IDS.FIXED_TOP_BUTTONS}`), sidebar?.querySelector(`#sidebar-section-tools .${CSS.SECTION_CONTENT}`) ].filter(Boolean); queryAreas.forEach(area => { area.querySelectorAll(`#${IDS.TOOL_VERBATIM}:not([data-${DATA_ATTR.LISTENER_ATTACHED}])`).forEach(b => { b.addEventListener('click', URLActionManager.triggerToggleVerbatim); b.dataset[DATA_ATTR.LISTENER_ATTACHED] = 'true'; }); area.querySelectorAll(`#${IDS.TOOL_RESET_BUTTON}:not([data-${DATA_ATTR.LISTENER_ATTACHED}])`).forEach(b => { b.addEventListener('click', URLActionManager.triggerResetFilters); b.dataset[DATA_ATTR.LISTENER_ATTACHED] = 'true'; }); }); }
    function applySidebarCollapseVisuals(isCollapsed) { if(!sidebar)return; const collapseButton = sidebar.querySelector(`#${IDS.COLLAPSE_BUTTON}`); if(isCollapsed){ sidebar.classList.add(CSS.SIDEBAR_COLLAPSED); if(collapseButton){ collapseButton.innerHTML = SVG_ICONS.chevronRight; collapseButton.title = _('sidebar_expand_title');}} else{ sidebar.classList.remove(CSS.SIDEBAR_COLLAPSED); if(collapseButton){ collapseButton.innerHTML = SVG_ICONS.chevronLeft; collapseButton.title = _('sidebar_collapse_title');}} }
    function applySectionCollapseStates() { if(!sidebar)return; const currentSettings = SettingsManager.getCurrentSettings(); const sections = sidebar.querySelectorAll(`.${CSS.SIDEBAR_CONTENT_WRAPPER} .${CSS.SIDEBAR_SECTION}`); sections.forEach(section => { const content = section.querySelector(`.${CSS.SECTION_CONTENT}`); const title = section.querySelector(`.${CSS.SECTION_TITLE}`); const sectionId = section.id; if (content && title && sectionId) { let shouldBeCollapsed = false; if (currentSettings.sectionDisplayMode === 'collapseAll') { shouldBeCollapsed = true; } else if (currentSettings.sectionDisplayMode === 'expandAll') { shouldBeCollapsed = false; } else { shouldBeCollapsed = currentSettings.sectionStates?.[sectionId] === true; } content.classList.toggle(CSS.COLLAPSED, shouldBeCollapsed); title.classList.toggle(CSS.COLLAPSED, shouldBeCollapsed); if (currentSettings.sectionDisplayMode === 'remember') { if (!currentSettings.sectionStates) currentSettings.sectionStates = {}; currentSettings.sectionStates[sectionId] = shouldBeCollapsed; } } }); }

    function initializeSelectedFilters() {
        if (!sidebar) return;
        try {
            const currentUrl = URLActionManager._getURLObject ? URLActionManager._getURLObject() : Utils.getCurrentURL();
            if (!currentUrl) return;
            const params = currentUrl.searchParams;
            const currentTbs = params.get('tbs') || '';
            const currentQuery = params.get('q') || '';

            ALL_SECTION_DEFINITIONS.forEach(sectionDef => {
                if (sectionDef.type === 'filter' && sectionDef.param) {
                    const paramNameToFetchFromURL = (sectionDef.param === 'filetype') ? 'as_filetype' : sectionDef.param;
                     _initializeStandaloneFilterState(params, sectionDef.id, paramNameToFetchFromURL);
                }
            });
            _initializeTimeFilterState(currentTbs);
            _initializeVerbatimState();
            _initializePersonalizationState();
            _initializeDateRangeInputs(currentTbs);
            _initializeSiteSearchState(currentQuery);
        } catch (e) {
            console.error(`${LOG_PREFIX} Error initializing filter highlights:`, e);
        }
    }

    function _initializeStandaloneFilterState(params, sectionId, paramToGetFromURL) {
        const sectionElement = sidebar?.querySelector(`#${sectionId}`);
        if (!sectionElement) return;
        const urlValue = params.get(paramToGetFromURL);
        const options = sectionElement.querySelectorAll(`.${CSS.FILTER_OPTION}`);
        let anOptionWasSelectedBasedOnUrl = false;

        options.forEach(opt => {
            const optionValue = opt.dataset[DATA_ATTR.FILTER_VALUE];
            const isSelected = (urlValue !== null && urlValue === optionValue);
            opt.classList.toggle(CSS.SELECTED, isSelected);
            if (isSelected) anOptionWasSelectedBasedOnUrl = true;
        });

        if (!anOptionWasSelectedBasedOnUrl) {
            const defaultOptionQuery = (paramToGetFromURL === 'as_occt')
                ? `.${CSS.FILTER_OPTION}[data-${DATA_ATTR.FILTER_VALUE}="any"]`
                : `.${CSS.FILTER_OPTION}[data-${DATA_ATTR.FILTER_VALUE}=""]`;
            const defaultOpt = sectionElement.querySelector(defaultOptionQuery);
            if (defaultOpt) {
                defaultOpt.classList.add(CSS.SELECTED);
            }
        }
    }

    function _initializeTimeFilterState(currentTbs){ const timeSection = sidebar?.querySelector('#sidebar-section-time'); if(!timeSection) return; const qdrMatch = currentTbs.match(/qdr:([^,]+)/); const activeQdrValue = qdrMatch ? qdrMatch[1] : null; const hasDateRange = /cdr:1/.test(currentTbs); const timeOptions = timeSection.querySelectorAll(`.${CSS.FILTER_OPTION}`); timeOptions.forEach(opt => { const optionValue = opt.dataset[DATA_ATTR.FILTER_VALUE]; let shouldBeSelected = false; if(hasDateRange){ shouldBeSelected = (optionValue === '');} else if(activeQdrValue){ shouldBeSelected = (optionValue === activeQdrValue); } else { shouldBeSelected = (optionValue === '');} opt.classList.toggle(CSS.SELECTED, shouldBeSelected); }); }
    function _initializeVerbatimState(){ const isVerbatimActiveNow = URLActionManager.isVerbatimActive(); sidebar?.querySelectorAll(`#${IDS.TOOL_VERBATIM}`).forEach(b=>b.classList.toggle(CSS.ACTIVE, isVerbatimActiveNow)); }
    function _initializePersonalizationState() { const isActive = URLActionManager.isPersonalizationActive(); sidebar?.querySelectorAll(`#${IDS.TOOL_PERSONALIZE}`).forEach(button => { button.classList.toggle(CSS.ACTIVE, isActive); const titleKey = isActive ? 'tooltip_toggle_personalization_off' : 'tooltip_toggle_personalization_on'; button.title = _(titleKey); const svgIcon = SVG_ICONS.personalization || ''; const isIconOnly = button.classList.contains(CSS.HEADER_BUTTON) && !button.classList.contains(CSS.TOOL_BUTTON); const currentText = !isIconOnly ? _('tool_personalization_toggle') : ''; let newHTML = ''; if(svgIcon) newHTML += svgIcon; if(currentText) newHTML += (svgIcon && currentText ? ' ' : '') + currentText; button.innerHTML = newHTML.trim(); }); }
    function _initializeDateRangeInputs(currentTbs){ const dateSection = sidebar?.querySelector('#sidebar-section-date-range'); if (!dateSection) return; const dateMinInput = dateSection.querySelector(`#${IDS.DATE_MIN}`); const dateMaxInput = dateSection.querySelector(`#${IDS.DATE_MAX}`); const errorMsgElement = dateSection.querySelector(`#${IDS.DATE_RANGE_ERROR_MSG}`); const applyButton = dateSection.querySelector('.apply-date-range'); if (errorMsgElement) _clearElementMessage(errorMsgElement, CSS.ERROR_VISIBLE); if (/cdr:1/.test(currentTbs)) { const minMatch = currentTbs.match(/cd_min:(\d{1,2})\/(\d{1,2})\/(\d{4})/); const maxMatch = currentTbs.match(/cd_max:(\d{1,2})\/(\d{1,2})\/(\d{4})/); if (dateMinInput) dateMinInput.value = minMatch ? `${minMatch[3]}-${minMatch[1].padStart(2, '0')}-${minMatch[2].padStart(2, '0')}` : ''; if (dateMaxInput) dateMaxInput.value = maxMatch ? `${maxMatch[3]}-${maxMatch[1].padStart(2, '0')}-${maxMatch[2].padStart(2, '0')}` : ''; } else { if (dateMinInput) dateMinInput.value = ''; if (dateMaxInput) dateMaxInput.value = ''; } if (dateMinInput && dateMaxInput && errorMsgElement && applyButton) { const isValid = _validateDateInputs(dateMinInput, dateMaxInput, errorMsgElement); applyButton.disabled = !isValid; } }
    function _initializeSiteSearchState(currentQuery){
        const siteSearchSection = sidebar?.querySelector('#sidebar-section-site-search');
        if (!siteSearchSection) return;
        const sectionContent = siteSearchSection.querySelector(`.${CSS.SECTION_CONTENT}`);
        if (!sectionContent || !sectionContent.firstElementChild) return; // Ensure ul exists

        const listElement = sectionContent.firstElementChild; // Assuming ul is the first child
        const currentSettings = SettingsManager.getCurrentSettings();
        const checkboxModeEnabled = currentSettings.enableSiteSearchCheckboxMode;

        listElement.querySelectorAll(`.${CSS.FILTER_OPTION}.${CSS.SELECTED}, label.${CSS.SELECTED}`).forEach(opt => opt.classList.remove(CSS.SELECTED));
        if (checkboxModeEnabled) {
            listElement.querySelectorAll(`input[type="checkbox"].${CSS.SITE_SEARCH_ITEM_CHECKBOX}`).forEach(cb => cb.checked = false);
        }

        const siteMatchSimple = currentQuery.match(/site:([\w.:()-]+)/i);
        const siteMatchOr = currentQuery.match(/\(\s*(site:[\w.:()-]+(?:\s+OR\s+site:[\w.:()-]+)*)\s*\)/i);

        let activeSiteUrls = [];
        if (siteMatchOr && siteMatchOr[1]) {
            const innerQuery = siteMatchOr[1];
            const individualSiteMatches = [...innerQuery.matchAll(/site:([\w.:()-]+)/gi)];
            activeSiteUrls = individualSiteMatches.map(match => match[1].toLowerCase()); // Compare lowercase
        } else if (siteMatchSimple && siteMatchSimple[1]) {
            activeSiteUrls.push(siteMatchSimple[1].toLowerCase()); // Compare lowercase
        }

        if (activeSiteUrls.length > 0) {
            activeSiteUrls.forEach(url => {
                if (checkboxModeEnabled) {
                    const checkbox = listElement.querySelector(`input[type="checkbox"].${CSS.SITE_SEARCH_ITEM_CHECKBOX}[value="${url}"]`);
                    if (checkbox) {
                        checkbox.checked = true;
                        if(checkbox.nextElementSibling) checkbox.nextElementSibling.classList.add(CSS.SELECTED);
                    }
                } else {
                    const option = listElement.querySelector(`.${CSS.FILTER_OPTION}[data-${DATA_ATTR.SITE_URL}="${url}"]`);
                    if (option) option.classList.add(CSS.SELECTED);
                }
            });
        } else {
            const clearOption = listElement.querySelector('#clear-site-search-option');
            if (clearOption) clearOption.classList.add(CSS.SELECTED);
        }

        if (checkboxModeEnabled) {
            _updateApplySitesButtonState(sectionContent);
        }
    }
    function bindSidebarEvents() { if (!sidebar) return; const collapseButton = sidebar.querySelector(`#${IDS.COLLAPSE_BUTTON}`); const settingsButton = sidebar.querySelector(`#${IDS.SETTINGS_BUTTON}`); if (collapseButton) collapseButton.title = _('sidebar_collapse_title'); if (settingsButton) settingsButton.title = _('sidebar_settings_title'); sidebar.addEventListener('click', (e) => { const settingsBtnTarget = e.target.closest(`#${IDS.SETTINGS_BUTTON}`); if (settingsBtnTarget) { SettingsManager.show(); return; } const collapseBtnTarget = e.target.closest(`#${IDS.COLLAPSE_BUTTON}`); if (collapseBtnTarget) { toggleSidebarCollapse(); return; } const sectionTitleTarget = e.target.closest(`.${CSS.SIDEBAR_CONTENT_WRAPPER} .${CSS.SECTION_TITLE}`); if (sectionTitleTarget && !sidebar.classList.contains(CSS.SIDEBAR_COLLAPSED)) { handleSectionCollapse(e); return; } }); }
    function toggleSidebarCollapse() { const cs = SettingsManager.getCurrentSettings(); cs.sidebarCollapsed = !cs.sidebarCollapsed; applySettings(cs); SettingsManager.save('Sidebar Collapse');}
    function handleSectionCollapse(event) { const title = event.target.closest(`.${CSS.SECTION_TITLE}`); if (!title || sidebar?.classList.contains(CSS.SIDEBAR_COLLAPSED) || title.closest(`#${IDS.FIXED_TOP_BUTTONS}`)) return; const section = title.closest(`.${CSS.SIDEBAR_SECTION}`); if (!section) return; const content = section.querySelector(`.${CSS.SECTION_CONTENT}`); const sectionId = section.id; if (!content || !sectionId) return; const currentSettings = SettingsManager.getCurrentSettings(); const isCurrentlyCollapsed = content.classList.contains(CSS.COLLAPSED); const shouldBeCollapsedAfterClick = !isCurrentlyCollapsed; let overallStateChanged = false; if (currentSettings.accordionMode && !shouldBeCollapsedAfterClick) { const sectionsContainer = section.parentElement; if (_applyAccordionEffectToSections(sectionId, sectionsContainer, currentSettings)) overallStateChanged = true; } if (_toggleSectionVisualState(section, title, content, sectionId, shouldBeCollapsedAfterClick, currentSettings)) overallStateChanged = true; if (overallStateChanged && currentSettings.sectionDisplayMode === 'remember') { debouncedSaveSettings('Section Collapse/Accordion'); } }
    function _applyAccordionEffectToSections(clickedSectionId, allSectionsContainer, currentSettings) { let stateChangedForAccordion = false; allSectionsContainer?.querySelectorAll(`.${CSS.SIDEBAR_SECTION}`)?.forEach(otherSection => { if (otherSection.id !== clickedSectionId) { const otherContent = otherSection.querySelector(`.${CSS.SECTION_CONTENT}`); const otherTitle = otherSection.querySelector(`.${CSS.SECTION_TITLE}`); if (otherContent && !otherContent.classList.contains(CSS.COLLAPSED)) { otherContent.classList.add(CSS.COLLAPSED); otherTitle?.classList.add(CSS.COLLAPSED); if (currentSettings.sectionDisplayMode === 'remember') { if (!currentSettings.sectionStates) currentSettings.sectionStates = {}; if (currentSettings.sectionStates[otherSection.id] !== true) { currentSettings.sectionStates[otherSection.id] = true; stateChangedForAccordion = true; } } } } }); return stateChangedForAccordion; }
    function _toggleSectionVisualState(sectionEl, titleEl, contentEl, sectionId, newCollapsedState, currentSettings) { let sectionStateActuallyChanged = false; const isCurrentlyCollapsed = contentEl.classList.contains(CSS.COLLAPSED); if (isCurrentlyCollapsed !== newCollapsedState) { contentEl.classList.toggle(CSS.COLLAPSED, newCollapsedState); titleEl.classList.toggle(CSS.COLLAPSED, newCollapsedState); sectionStateActuallyChanged = true; } if (currentSettings.sectionDisplayMode === 'remember') { if (!currentSettings.sectionStates) currentSettings.sectionStates = {}; if (currentSettings.sectionStates[sectionId] !== newCollapsedState) { currentSettings.sectionStates[sectionId] = newCollapsedState; if (!sectionStateActuallyChanged) sectionStateActuallyChanged = true; } } return sectionStateActuallyChanged; }

    function initializeScript() {
        console.log(LOG_PREFIX + " Initializing script...");
        debouncedSaveSettings = Utils.debounce(() => SettingsManager.save('Debounced Save'), 800);
        try {
            addGlobalStyles(); NotificationManager.init(); LocalizationService.initializeBaseLocale();
            SettingsManager.initialize( defaultSettings, applySettings, buildSidebarUI, applySectionCollapseStates, _initMenuCommands, renderSectionOrderList );
            setupSystemThemeListener(); buildSidebarSkeleton();
            DragManager.init( sidebar, sidebar.querySelector(`.${CSS.DRAG_HANDLE}`), SettingsManager, debouncedSaveSettings );
            const initialSettings = SettingsManager.getCurrentSettings();
            DragManager.setDraggable(initialSettings.draggableHandleEnabled, sidebar, sidebar.querySelector(`.${CSS.DRAG_HANDLE}`));
            applySettings(initialSettings); buildSidebarUI(); bindSidebarEvents(); _initMenuCommands();
            console.log(`${LOG_PREFIX} Script initialization complete. Final effective locale: ${LocalizationService.getCurrentLocale()}`);
        } catch (error) {
            console.error(`${LOG_PREFIX} [initializeScript] CRITICAL ERROR DURING INITIALIZATION:`, error, error.stack);
            const scriptNameForAlert = (typeof _ === 'function' && _('scriptName') && !(_('scriptName').startsWith('[ERR:'))) ? _('scriptName') : SCRIPT_INTERNAL_NAME;
            if (typeof NotificationManager !== 'undefined' && NotificationManager.show) { NotificationManager.show('alert_init_fail', { scriptName: scriptNameForAlert, error: error.message }, 'error', 0); }
            else { _showGlobalMessage('alert_init_fail', { scriptName: scriptNameForAlert, error: error.message }, 'error', 0); }
            if(sidebar && sidebar.remove) sidebar.remove(); const settingsOverlayEl = document.getElementById(IDS.SETTINGS_OVERLAY); if(settingsOverlayEl) settingsOverlayEl.remove(); ModalManager.hide();
        }
    }

    if (document.getElementById(IDS.SIDEBAR)) { console.warn(`${LOG_PREFIX} Sidebar with ID "${IDS.SIDEBAR}" already exists. Skipping initialization.`); return; }
    const dependenciesReady = { styles: false, i18n: false }; let initializationAttempted = false; let timeoutFallback;
    function checkDependenciesAndInitialize() { if (initializationAttempted) return; if (dependenciesReady.styles && dependenciesReady.i18n) { console.log(`${LOG_PREFIX} All dependencies ready. Initializing script.`); clearTimeout(timeoutFallback); initializationAttempted = true; if (document.readyState === 'complete' || document.readyState === 'interactive' || document.readyState === 'loaded') { initializeScript(); } else { window.addEventListener('DOMContentLoaded', initializeScript, { once: true }); } } }
    document.addEventListener('gscsStylesLoaded', function stylesLoadedHandler() { console.log(`${LOG_PREFIX} Event "gscsStylesLoaded" received.`); dependenciesReady.styles = true; checkDependenciesAndInitialize(); }, { once: true });
    document.addEventListener('gscsi18nLoaded', function i18nLoadedHandler() { console.log(`${LOG_PREFIX} Event "gscsi18nLoaded" received.`); dependenciesReady.i18n = true; checkDependenciesAndInitialize(); }, { once: true });
    timeoutFallback = setTimeout(() => { if (initializationAttempted) return; console.log(`${LOG_PREFIX} Fallback: Checking dependencies after timeout.`); if (typeof window.GSCS_Namespace !== 'undefined') { if (typeof window.GSCS_Namespace.stylesText === 'string' && window.GSCS_Namespace.stylesText.trim() !== '' && !dependenciesReady.styles) { console.log(`${LOG_PREFIX} Fallback: Styles found via namespace.`); dependenciesReady.styles = true; } if (typeof window.GSCS_Namespace.i18nPack === 'object' && Object.keys(window.GSCS_Namespace.i18nPack.translations || {}).length > 0 && !dependenciesReady.i18n) { console.log(`${LOG_PREFIX} Fallback: i18n pack found via namespace.`); dependenciesReady.i18n = true; } } if (dependenciesReady.styles && dependenciesReady.i18n) { checkDependenciesAndInitialize(); } else { console.error(`${LOG_PREFIX} Fallback: Dependencies still not fully loaded after timeout. Styles: ${dependenciesReady.styles}, i18n: ${dependenciesReady.i18n}.`); if (!initializationAttempted) { console.warn(`${LOG_PREFIX} Attempting to initialize with potentially incomplete dependencies due to fallback timeout.`); if (!dependenciesReady.styles) { console.warn(`${LOG_PREFIX} Styles dependency forced true in fallback.`); dependenciesReady.styles = true; } if (!dependenciesReady.i18n) { console.warn(`${LOG_PREFIX} i18n dependency forced true in fallback.`); dependenciesReady.i18n = true; } checkDependenciesAndInitialize(); } } }, 2000);
    if (document.readyState === 'complete' || document.readyState === 'interactive' || document.readyState === 'loaded') { if (typeof window.GSCS_Namespace !== 'undefined') { if (typeof window.GSCS_Namespace.stylesText === 'string' && window.GSCS_Namespace.stylesText.trim() !== '' && !dependenciesReady.styles) { dependenciesReady.styles = true; } if (typeof window.GSCS_Namespace.i18nPack === 'object' && Object.keys(window.GSCS_Namespace.i18nPack.translations || {}).length > 0 && !dependenciesReady.i18n) { dependenciesReady.i18n = true; } } if (dependenciesReady.styles && dependenciesReady.i18n && !initializationAttempted) { checkDependenciesAndInitialize(); } }
})();
    // --- END OF PART 3 (gscs-base.user.js) ---