Google 搜尋自訂側邊欄

Google 搜尋自訂側邊欄:快速篩選(語言、時間、檔案類型、國家、日期)、站內搜尋、一字不差與個人化工具。

目前為 2025-05-21 提交的版本,檢視 最新版本

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

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

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

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

你需要先安裝一款使用者腳本管理器擴展,比如 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.1.0
// @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/1592845/Google%20Search%20Custom%20Sidebar%20-%20i18n.js
// @require      https://update.greasyfork.org/scripts/535625/1592847/Google%20Search%20Custom%20Sidebar%20-%20Styles.js
// ==/UserScript==

(function() {
    'use strict';

    // --- Constants and Configuration ---
    const SCRIPT_INTERNAL_NAME = 'GoogleSearchCustomSidebar';
    const SCRIPT_VERSION = '0.1.0';
    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: [
            { text: "📄Documents", value: "pdf OR docx OR doc OR odt OR rtf OR txt" },
            { text: "💹Spreadsheets", value: "xlsx OR xls OR ods OR csv" },
            { text: "📊Presentations", value: "pptx OR ppt OR odp OR key" },
        ],
        customCountries: [],
        displayLanguages: [],
        displayCountries: [],
        favoriteSites: [
            // == SINGLE SITES: GENERAL KNOWLEDGE & REFERENCE ==
            { text: 'Wikipedia (EN)', url: 'en.wikipedia.org' },
            { text: 'Wiktionary', url: 'wiktionary.org' },
            { text: 'Internet Archive', url: 'archive.org' },

            // == SINGLE SITES: DEVELOPER & TECH ==
            { text: 'GitHub', url: 'github.com' },
            { text: 'GitLab', url: 'gitlab.com' },
            { text: 'Stack Overflow', url: 'stackoverflow.com' },
            { text: 'Hacker News', url: 'news.ycombinator.com' },
            { text: 'Greasy Fork', url: 'greasyfork.org' },

            // == SINGLE SITES: SOCIAL, FORUMS & COMMUNITIES ==
            { text: 'Reddit', url: 'reddit.com' },
            { text: 'X', url: 'x.com' },
            { text: 'Mastodon', url: 'mastodon.social' },
            { text: 'Bluesky', url: 'bsky.app' },
            { text: 'Lemmy', url: 'lemmy.world' },

            // == SINGLE SITES: ENTERTAINMENT, ARTS & HOBBIES ==
            { text: 'IMDb', url: 'imdb.com' },
            { text: 'TMDb', url: 'themoviedb.org' },
            { text: 'Letterboxd', url: 'letterboxd.com' },
            { text: 'Metacritic', url: 'metacritic.com' },
            { text: 'OpenCritic', url: 'opencritic.com' },
            { text: 'Steam', url: 'store.steampowered.com' },
            { text: 'Bandcamp', url: 'bandcamp.com' },
            { text: 'Last.fm', url: 'last.fm' },

            // == COMBINED SITE GROUPS ==
            {
                text: '💬Social',
                url: 'x.com OR facebook.com OR instagram.com OR threads.net OR bluesky.social OR mastodon.social OR reddit.com OR tumblr.com OR linkedin.com OR lemmy.world'
            },
            {
                text: '📦Repositories',
                url: 'github.com OR gitlab.com OR bitbucket.org OR codeberg.org OR sourceforge.net'
            },
            {
                text: '🎓Academics',
                url: 'scholar.google.com OR arxiv.org OR researchgate.net OR jstor.org OR academia.edu OR pubmed.ncbi.nlm.nih.gov OR semanticscholar.org OR core.ac.uk'
            },
            {
                text: '📰News',
                url: 'bbc.com/news OR reuters.com OR apnews.com OR nytimes.com OR theguardian.com OR cnn.com OR wsj.com'
            },
            {
                text: '🎨Creative',
                url: 'behance.net OR dribbble.com OR artstation.com OR deviantart.com'
            }
        ],
        enableSiteSearchCheckboxMode: true,
        enableFiletypeCheckboxMode: true,
        sidebarCollapsed: false,
        draggableHandleEnabled: true,
        enabledPredefinedOptions: {
            language: ['lang_en'],
            country: ['countryUS'],
            time: ['d', 'w', 'm', 'y', 'h'],
            filetype: ['pdf', 'docx', 'doc', 'pptx', 'ppt', 'xlsx', 'xls', 'txt']
        },
        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',
        APPLY_SELECTED_FILETYPES_BUTTON: 'apply-selected-filetypes-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_FILETYPE_SEARCH_CHECKBOX_MODE: 'setting-filetype-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',
        CLEAR_SITE_SEARCH_OPTION: 'clear-site-search-option',
        CLEAR_FILETYPE_SEARCH_OPTION: 'clear-filetype-search-option'
    };
    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',
        FILETYPE_SEARCH_ITEM_CHECKBOX: 'filetype-search-item-checkbox',
        APPLY_SITES_BUTTON: 'apply-sites-button',
        APPLY_FILETYPES_BUTTON: 'apply-filetypes-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',
        FILETYPE_VALUE: 'filetypeValue',
        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: 'filetype', titleKey: 'section_filetype', scriptDefined: [{ textKey: 'filter_any_format', v: '' }], param: 'as_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', scriptDefined: [{ textKey: 'filter_any_site', v:''}] },
        { 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_any_site: 'Any Site',
                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',
                tool_apply_selected_filetypes: 'Apply Selected',
                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_enable_filetype_search_checkbox_mode: 'Enable Checkbox Mode for Filetype Search',
                settings_enable_filetype_search_checkbox_mode_hint: 'Allows selecting multiple filetypes 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 (e.g., site.com OR example.net)', modal_placeholder_text: 'Text', modal_placeholder_value: 'Value (e.g., pdf OR docx)',
                modal_hint_domain: 'Format: domain (e.g., `wikipedia.org`) or TLD/SLD (`.edu`). Use `OR` (case-insensitive, space separated) for multiple.',
                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: extension (e.g., `pdf`). Use `OR` (case-insensitive, space separated) for multiple (e.g., `docx OR xls`).',
                modal_tooltip_domain: 'Enter domain(s) or TLD/SLD(s). Use OR for multiple, e.g., site.com OR example.org',
                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(s). Use OR for multiple, e.g., pdf OR docx',
                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] = {};
                        }
                        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.`);
            }
            const ensureKeys = (lang, defaults) => {
                if (!effectiveTranslations[lang]) effectiveTranslations[lang] = {};
                for (const key in defaults) {
                    if (!effectiveTranslations[lang][key]) {
                        effectiveTranslations[lang][key] = defaults[key];
                    }
                }
            };
            ensureKeys('en', builtInTranslations.en);
            ensureKeys('zh-TW', builtInTranslations['zh-TW']);
        }

        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;
            }
        },
        parseCombinedValue: function(valueString) {
            if (typeof valueString !== 'string' || !valueString.trim()) {
                return [];
            }
            return valueString.split(/\s+OR\s+/i).map(s => s.trim()).filter(s => s.length > 0);
        }
    };
    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) {
                const ftSection = ALL_SECTION_DEFINITIONS.find(s => s.id === 'sidebar-section-filetype');
                if (ftSection) paramName = ftSection.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) {
            const singleDomainRegex = /^(?:(?:[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}$)/;
            const parts = Utils.parseCombinedValue(value);
            if (isEmpty) isValid = true; // Empty is fine, might not be required
            else if (parts.length > 0) isValid = parts.every(part => singleDomainRegex.test(part));
            else isValid = false; // e.g. "OR" alone, or just spaces
        } 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) {
            const singleFiletypeRegex = /^[a-zA-Z0-9]+$/;
            const parts = Utils.parseCombinedValue(value);
            if (isEmpty) isValid = true;
            else if (parts.length > 0) isValid = parts.every(part => singleFiletypeRegex.test(part));
            else isValid = false;
        } 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) { // Only add validation classes if not empty
            inputElement.classList.add(isValid ? 'input-valid' : 'input-invalid');
            if (!isValid) inputElement.classList.add(CSS.INPUT_HAS_ERROR);
        }
        return isValid || isEmpty; // Return true if format is valid OR if it's empty (emptiness check is separate)
    }

    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); // No need to re-validate text if non-empty for basic types
        }
        if (value === '') {
            _showInputError(valueInput, 'alert_enter_value', { type: itemTypeName });
            valueInput.focus();
            return { isValid: false, errorField: valueInput };
        } else {
            const isValueFormatValid = validateCustomInput(valueInput); // This also handles visual feedback
            if (!isValueFormatValid) { // validateCustomInput already showed error if !isValid and not empty
                if (valueInput.classList.contains('input-invalid')) { // Error was shown by validateCustomInput
                     valueInput.focus();
                     return { isValid: false, errorField: valueInput };
                }
                // If not marked invalid by validateCustomInput but still failed (e.g. more complex logic not in regex)
                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 };
            }
        }
        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;
        }
    }

    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();
                }
                const sanitizedValueForId = opt.value.replace(/[^a-zA-Z0-9-_]/g, '');
                listHTML += `<li class="${CSS.MODAL_PREDEFINED_CHOOSER_ITEM}"><input type="checkbox" value="${opt.value}" id="chooser-${sanitizedValueForId}"><label for="chooser-${sanitizedValueForId}">${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,       hasPredefinedToggles: false, 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,         hasPredefinedToggles: false, 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,         hasPredefinedToggles: false, 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,        hasPredefinedToggles: true, 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,        hasPredefinedToggles: true, 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 (!_editingItemInfo || _editingItemInfo.listId !== listId) {
                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.hasPredefinedToggles && config.predefinedSourceKey && PREDEFINED_OPTIONS_REF[config.predefinedSourceKey]) {
                    const enabledValues = new Set(currentSettingsRef.enabledPredefinedOptions[config.predefinedSourceKey] || []);
                    contentHTML += _createPredefinedOptionsSectionHTML(config.predefinedSourceKey, mapping.nameKey, PREDEFINED_OPTIONS_REF, enabledValues);
                    contentHTML += '<hr style="margin: 1em 0;">';
                    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.hasPredefinedToggles && config.predefinedSourceKey) {
                            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; }
        };
    })();

    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>`;
            const filetypeSearchCheckboxModeHTML =
                `<div class="${CSS.SETTING_ITEM}">` +
                `<input type="checkbox" id="${IDS.SETTING_FILETYPE_SEARCH_CHECKBOX_MODE}"><label for="${IDS.SETTING_FILETYPE_SEARCH_CHECKBOX_MODE}" class="${CSS.INLINE_LABEL}">${_('settings_enable_filetype_search_checkbox_mode')}</label>` +
                `<div class="${CSS.SETTING_VALUE_HINT}" style="margin-top:0.3em; margin-left:1.7em; font-weight:normal;">${_('settings_enable_filetype_search_checkbox_mode_hint')}</div>` +
                `</div>`;
            return `<p>${_('settings_visible_sections')}</p>${visItemsHTML}` +
                   `${siteSearchCheckboxModeHTML}${filetypeSearchCheckboxModeHTML}<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; const filetypeSearchCheckboxModeEl = win.querySelector(`#${IDS.SETTING_FILETYPE_SEARCH_CHECKBOX_MODE}`); if(filetypeSearchCheckboxModeEl) filetypeSearchCheckboxModeEl.checked = s.enableFiletypeCheckboxMode; 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; target.enableFiletypeCheckboxMode = typeof target.enableFiletypeCheckboxMode === 'boolean' ? target.enableFiletypeCheckboxMode : defaults.enableFiletypeCheckboxMode; 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){ target.enabledPredefinedOptions = target.enabledPredefinedOptions || {}; ['time', 'filetype'].forEach(type => { if (!target.enabledPredefinedOptions[type] || !Array.isArray(target.enabledPredefinedOptions[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)); } else if (!PREDEFINED_OPTIONS[type]) { target.enabledPredefinedOptions[type] = []; } }); 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_FILETYPE_SEARCH_CHECKBOX_MODE]: (target) => { _currentSettings.enableFiletypeCheckboxMode = 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) { 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 filetypeSearchCheckboxModeEl = featuresPane.querySelector(`#${IDS.SETTING_FILETYPE_SEARCH_CHECKBOX_MODE}`);
                if (filetypeSearchCheckboxModeEl && _sEH_internal[IDS.SETTING_FILETYPE_SEARCH_CHECKBOX_MODE]) {
                    filetypeSearchCheckboxModeEl.removeEventListener('change', _lUH_internal);
                    filetypeSearchCheckboxModeEl.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();
                    let cQ = q.replace(/\s*\(\s*(?:(?:site|filetype):[\w.:()-]+(?:\s+OR\s+|$))+[^)]*\)\s*/gi, ' ');
                    cQ = cQ.replace(/\s*(?:site|filetype):[\w.:()-]+\s*/gi, ' ');
                    cQ = cQ.replace(/\s\s+/g, ' ').trim();

                    if (cQ) { nP.set('q', cQ); }
                    u.search = nP.toString();
                    _deleteSearchParam(u, 'tbs'); _deleteSearchParam(u, 'lr'); _deleteSearchParam(u, 'cr');
                    _deleteSearchParam(u, 'as_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) { // Handles non-q-based filters and single 'as_filetype' which might contain OR
                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);

                    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}`);
                        _setTbsParam(u, pTP);
                    } else if (isStandaloneParam) {
                        _deleteSearchParam(u, type);
                        if (value !== '' && !(type === 'as_occt' && value === 'any')) {
                            _setSearchParam(u, type, value);
                        }
                        // pTP = tP; // No change to tbs for these params
                    } else if (type === 'as_filetype') {
                        const filetypesToApply = Utils.parseCombinedValue(value);
                        if (filetypesToApply.length > 1) {
                            this.applyCombinedFiletypeSearch(filetypesToApply); // Delegate to combined if OR is present
                            return; // applyCombinedFiletypeSearch handles navigation
                        }
                        // Single filetype or empty (clear)
                        let currentQuery = u.searchParams.get('q') || '';
                        currentQuery = currentQuery.replace(/\s*\(\s*(?:filetype:[\w.:()-]+(?:\s+OR\s+|$))+[^)]*\)\s*/gi, ' ');
                        currentQuery = currentQuery.replace(/\s*filetype:[\w.:()-]+\s*/gi, ' ');
                        currentQuery = currentQuery.replace(/\s\s+/g, ' ').trim();

                        if (value !== '') { // value here is a single type after parsing or if it was single initially
                            _setSearchParam(u, 'q', (currentQuery + ` filetype:${filetypesToApply[0]}`).trim());
                        } else {
                            if(currentQuery) _setSearchParam(u, 'q', currentQuery);
                            else _deleteSearchParam(u, 'q');
                        }
                        _deleteSearchParam(u, 'as_filetype');
                        // pTP = tP; // No change to tbs
                    }
                    // For standalone and time filters, tbs might be modified, so set it.
                    // For as_filetype handled via q, tbs is not modified here.
                    if (isTimeFilter || isStandaloneParam) {
                         _setTbsParam(u, tP); // tP was modified for time, or not for standalone
                    }
                    _navigateTo(u);
                } catch (e) {
                    NotificationManager.show('alert_error_applying_filter', { type: type, value: value }, 'error', 5000);
                }
            },
            // applySiteSearch and applyCombinedFiletypeSearch expect an array of individual terms
            applySiteSearch: function(siteCriteria) { // siteCriteria can be a string "siteA OR siteB" or an array ["siteA", "siteB"]
                const sitesToSearch = Array.isArray(siteCriteria)
                    ? siteCriteria.flatMap(sc => Utils.parseCombinedValue(sc)) // If array, parse each element
                    : Utils.parseCombinedValue(siteCriteria); // If string, parse it
                const uniqueSites = [...new Set(sitesToSearch.map(s => s.toLowerCase()))];


                if (uniqueSites.length === 0) {
                    this.clearSiteSearch(); return;
                }
                try {
                    const u = _getURLObject(); if (!u) return;
                    let q = u.searchParams.get('q') || '';

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

                    let siteQueryPart = '';
                    if (uniqueSites.length === 1) {
                        siteQueryPart = `site:${uniqueSites[0]}`;
                    } else {
                        siteQueryPart = `(${uniqueSites.map(s => `site:${s}`).join(' OR ')})`;
                    }

                    const nQ = `${q} ${siteQueryPart}`.trim();
                    _setSearchParam(u, 'q', nQ);
                    _deleteSearchParam(u, 'tbs'); _deleteSearchParam(u, 'lr'); _deleteSearchParam(u, 'cr');
                    _deleteSearchParam(u, 'as_filetype'); _deleteSearchParam(u, 'as_occt');
                    _navigateTo(u);
                } catch (e) {
                    const siteForError = uniqueSites.join(', ');
                    NotificationManager.show('alert_error_applying_site_search', { site: siteForError }, 'error', 5000);
                }
            },
            applyCombinedFiletypeSearch: function(filetypeCriteria) { // filetypeCriteria can be a string "typeA OR typeB" or an array ["typeA", "typeB"]
                const filetypesToSearch = Array.isArray(filetypeCriteria)
                    ? filetypeCriteria.flatMap(fc => Utils.parseCombinedValue(fc))
                    : Utils.parseCombinedValue(filetypeCriteria);
                const uniqueFiletypes = [...new Set(filetypesToSearch.map(f => f.toLowerCase()))];

                if (uniqueFiletypes.length === 0) {
                    this.clearFiletypeSearch();
                    return;
                }
                try {
                    const u = _getURLObject(); if (!u) return;
                    let q = u.searchParams.get('q') || '';

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

                    let filetypeQueryPart = '';
                    if (uniqueFiletypes.length === 1) {
                        filetypeQueryPart = `filetype:${uniqueFiletypes[0]}`;
                    } else {
                        filetypeQueryPart = `(${uniqueFiletypes.map(ft => `filetype:${ft}`).join(' OR ')})`;
                    }

                    const nQ = `${q} ${filetypeQueryPart}`.trim();
                    _setSearchParam(u, 'q', nQ);
                    _deleteSearchParam(u, 'as_filetype');
                    _navigateTo(u);
                } catch (e) {
                    const ftForError = uniqueFiletypes.join(', ');
                    NotificationManager.show('alert_error_applying_filter', { type: 'filetype (combined)', value: ftForError }, 'error', 5000);
                }
            },
            clearSiteSearch: function() {
                try {
                    const u = _getURLObject(); if (!u) return;
                    const q = u.searchParams.get('q') || '';
                    let nQ = q.replace(/\s*\(\s*(?:site:[\w.:()-]+(?:\s+OR\s+|$))+[^)]*\)\s*/gi, ' ');
                    nQ = nQ.replace(/\s*site:[\w.:()-]+\s*/gi, ' ');
                    nQ = nQ.replace(/\s\s+/g, ' ').trim();
                    if (nQ) { _setSearchParam(u, 'q', nQ); } else { _deleteSearchParam(u, 'q'); }
                    _navigateTo(u);
                } catch (e) {
                    NotificationManager.show('alert_error_clearing_site_search', {}, 'error', 5000);
                }
            },
            clearFiletypeSearch: function() {
                try {
                    const u = _getURLObject(); if (!u) return;
                    let q = u.searchParams.get('q') || '';
                    q = q.replace(/\s*\(\s*(?:filetype:[\w.:()-]+(?:\s+OR\s+|$))+[^)]*\)\s*/gi, ' ');
                    q = q.replace(/\s*filetype:[\w.:()-]+\s*/gi, ' ');
                    q = q.replace(/\s\s+/g, ' ').trim();
                    if (q) { _setSearchParam(u, 'q', q); } else { _deleteSearchParam(u, 'q'); }
                    _deleteSearchParam(u, 'as_filetype');
                    _navigateTo(u);
                } catch (e) {
                    NotificationManager.show('alert_error_applying_filter', { type: 'filetype', value: '(clear)' }, '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]);
        const isFiletypeCheckboxModeActive = sectionId === 'sidebar-section-filetype' && currentSettings.enableFiletypeCheckboxMode;
        const isSiteCheckboxModeActive = sectionId === 'sidebar-section-site-search' && currentSettings.enableSiteSearchCheckboxMode;

        // 1. Add "Any" type script-defined options (value === '') for sections where it's part of the sortable list
        if (scriptDefinedOptions) {
            scriptDefinedOptions.forEach(opt => {
                if (opt && typeof opt.textKey === 'string' && typeof opt.v === 'string' && opt.v === '') {
                    // Only add "Any" to finalOptions if it's NOT filetype/site in checkbox mode (those have dedicated clear divs)
                    if (!((isFiletypeCheckboxModeActive && sectionId === 'sidebar-section-filetype') ||
                          (isSiteCheckboxModeActive && sectionId === 'sidebar-section-site-search'))) {
                        const translatedText = (sectionId === 'sidebar-section-site-search') ? _('filter_any_site') : _(opt.textKey);
                        finalOptions.push({ text: translatedText, value: opt.v, originalText: translatedText, isCustom: false, isAnyOption: true });
                        tempAddedValues.add(opt.v);
                    }
                }
            });
        }


        if (isSortableMixedType) { // For Language, Country
            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 === 'sidebar-section-country') {
                            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 { // For Time, Filetype, Occurrence (and Site Search if not checkbox mode, though site search has its own populate)
            const predefinedKey = sectionDef.predefinedOptionsKey;
            const customKey = sectionDef.customItemsKey;
            const predefinedOptsFromSource = predefinedOptionsSource && predefinedKey ? (predefinedOptionsSource[predefinedKey] || []) : [];
            const customOptsFromSettings = customKey ? (currentSettings[customKey] || []) : [];
            let enabledPredefinedSystemVals;

            if (isFiletypeCheckboxModeActive && sectionId === 'sidebar-section-filetype') {
                enabledPredefinedSystemVals = currentSettings.enabledPredefinedOptions[predefinedKey] || [];
            } else {
                enabledPredefinedSystemVals = predefinedKey ? (currentSettings.enabledPredefinedOptions[predefinedKey] || []) : [];
            }

            const itemsForThisSection = [];
            const enabledSet = new Set(enabledPredefinedSystemVals);

            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);
                        itemsForThisSection.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 => {
                // For custom items, 'value' can now contain OR. The 'isCustom' flag helps differentiate.
                if (!tempAddedValues.has(opt.value)){ // Check against tempAddedValues to avoid re-adding scriptDefined "Any"
                    itemsForThisSection.push({ text: opt.text, value: opt.value, originalText: opt.text, isCustom: true });
                }
            });

            itemsForThisSection.forEach(opt => {
                 if (!tempAddedValues.has(opt.value)){
                    finalOptions.push(opt);
                    tempAddedValues.add(opt.value);
                }
            });
        }

        if (scriptDefinedOptions) {
            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, isCustom: false });
                    tempAddedValues.add(opt.v);
                }
            });
        }

        let anyOptionToSortSeparately = null;
        const anyOptionIdx = finalOptions.findIndex(opt => opt.isAnyOption === true);

        if (anyOptionIdx !== -1) {
            anyOptionToSortSeparately = finalOptions.splice(anyOptionIdx, 1)[0];
        }

        finalOptions.sort((a, b) => {
            const isTimeSection = (sectionId === 'sidebar-section-time');
            if (isTimeSection) {
                const timeA = _parseTimeValueToMinutes(a.value);
                const timeB = _parseTimeValueToMinutes(b.value);
                if (timeA !== Infinity || timeB !== Infinity) {
                    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' });
        });

        if (anyOptionToSortSeparately) {
            finalOptions.unshift(anyOptionToSortSeparately);
        }
        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 'filetype': sectionElement = _createFiletypeSectionElement(sectionIdForDisplay, sectionTitleKey, sectionData.scriptDefined, sectionData.param, currentSettings, PREDEFINED_OPTIONS_REF); 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);
        populateSiteSearchList(sectionContent, favoriteSites, checkboxModeEnabled);
        return section;
    }

    function populateSiteSearchList(sectionContentElement, favoriteSitesArray, checkboxModeEnabled) {
        if (!sectionContentElement) { console.error("Site search section content element missing"); return; }
        sectionContentElement.innerHTML = '';

        const sites = Array.isArray(favoriteSitesArray) ? favoriteSitesArray : [];
        const listFragment = document.createDocumentFragment();

        const clearOptDiv = document.createElement('div');
        clearOptDiv.classList.add(CSS.FILTER_OPTION);
        clearOptDiv.id = IDS.CLEAR_SITE_SEARCH_OPTION;
        clearOptDiv.title = _('tooltip_clear_site_search');
        clearOptDiv.textContent = _('filter_any_site');
        clearOptDiv.dataset[DATA_ATTR.FILTER_TYPE] = 'site_clear'; // Special type for click handler
        sectionContentElement.appendChild(clearOptDiv);

        const listElement = document.createElement('ul');
        listElement.classList.add(CSS.CUSTOM_LIST);
        if (checkboxModeEnabled) {
            listElement.classList.add('checkbox-mode-enabled');
        }

        sites.forEach((site, index) => {
            if (site?.text && site?.url) {
                const li = document.createElement('li');
                const siteValue = site.url;

                if (checkboxModeEnabled) {
                    const checkbox = document.createElement('input');
                    checkbox.type = 'checkbox';
                    checkbox.id = `site-cb-${index}-${Date.now()}`; // Ensure unique ID
                    checkbox.value = siteValue;
                    checkbox.classList.add(CSS.SITE_SEARCH_ITEM_CHECKBOX);
                    checkbox.dataset[DATA_ATTR.SITE_URL] = siteValue;
                    li.appendChild(checkbox);
                }

                const opt = document.createElement(checkboxModeEnabled ? 'label' : 'div');
                if (checkboxModeEnabled) {
                    opt.htmlFor = `site-cb-${index}-${Date.now()}`; // Ensure matches checkbox ID
                } else {
                    opt.classList.add(CSS.FILTER_OPTION);
                }
                opt.dataset[DATA_ATTR.SITE_URL] = siteValue;
                opt.title = _('tooltip_site_search', { siteUrl: siteValue.replace(/\s+OR\s+/gi, ', ') });
                opt.textContent = site.text;
                li.appendChild(opt);
                listFragment.appendChild(li);
            }
        });
        listElement.appendChild(listFragment);
        sectionContentElement.appendChild(listElement);

        if (checkboxModeEnabled) {
            let applyButton = sectionContentElement.querySelector(`#${IDS.APPLY_SELECTED_SITES_BUTTON}`);
            if (!applyButton) {
                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');
                sectionContentElement.appendChild(applyButton);
            }
            applyButton.disabled = true;
            applyButton.style.display = 'none';
        }

        if (!sectionContentElement.dataset.siteSearchClickListenerAttached) {
            sectionContentElement.dataset.siteSearchClickListenerAttached = 'true';
            sectionContentElement.addEventListener('click', (event) => {
                const target = event.target;
                const currentSettings = SettingsManager.getCurrentSettings();
                const isCheckboxMode = currentSettings.enableSiteSearchCheckboxMode;
                const clearSiteOpt = target.closest(`#${IDS.CLEAR_SITE_SEARCH_OPTION}`);

                if (clearSiteOpt) {
                    URLActionManager.clearSiteSearch();
                    sectionContentElement.querySelectorAll(`.${CSS.FILTER_OPTION}.${CSS.SELECTED}, label.${CSS.SELECTED}`).forEach(o => o.classList.remove(CSS.SELECTED));
                    clearSiteOpt.classList.add(CSS.SELECTED);
                    if (isCheckboxMode) {
                        sectionContentElement.querySelectorAll(`input[type="checkbox"].${CSS.SITE_SEARCH_ITEM_CHECKBOX}`).forEach(cb => cb.checked = false);
                        _updateApplySitesButtonState(sectionContentElement);
                    }
                } else if (isCheckboxMode) {
                    const labelElement = target.closest('label');
                    if (labelElement && labelElement.dataset[DATA_ATTR.SITE_URL]) {
                        event.preventDefault();
                        const siteUrlOrCombined = labelElement.dataset[DATA_ATTR.SITE_URL];
                        sectionContentElement.querySelectorAll(`input[type="checkbox"].${CSS.SITE_SEARCH_ITEM_CHECKBOX}`).forEach(cb => {
                            const correspondingLabel = sectionContentElement.querySelector(`label[for="${cb.id}"]`);
                            cb.checked = (cb.value === siteUrlOrCombined);
                            if(correspondingLabel) correspondingLabel.classList.toggle(CSS.SELECTED, cb.checked);
                        });
                        URLActionManager.applySiteSearch(siteUrlOrCombined);
                        _updateApplySitesButtonState(sectionContentElement);
                        sectionContentElement.querySelector(`#${IDS.CLEAR_SITE_SEARCH_OPTION}`)?.classList.remove(CSS.SELECTED);
                    }
                } else {
                    const siteOptionDiv = target.closest(`div.${CSS.FILTER_OPTION}:not(#${IDS.CLEAR_SITE_SEARCH_OPTION})`);
                    if (siteOptionDiv && siteOptionDiv.dataset[DATA_ATTR.SITE_URL]) {
                        const siteUrlOrCombined = siteOptionDiv.dataset[DATA_ATTR.SITE_URL];
                        sectionContentElement.querySelectorAll(`.${CSS.FILTER_OPTION}.${CSS.SELECTED}`).forEach(o => o.classList.remove(CSS.SELECTED));
                        URLActionManager.applySiteSearch(siteUrlOrCombined);
                        siteOptionDiv.classList.add(CSS.SELECTED);
                        sectionContentElement.querySelector(`#${IDS.CLEAR_SITE_SEARCH_OPTION}`)?.classList.remove(CSS.SELECTED);
                    }
                }
            });

            if (checkboxModeEnabled) {
                sectionContentElement.addEventListener('change', (event) => {
                    if (event.target.matches(`input[type="checkbox"].${CSS.SITE_SEARCH_ITEM_CHECKBOX}`)) {
                        _updateApplySitesButtonState(sectionContentElement);
                        const label = sectionContentElement.querySelector(`label[for="${event.target.id}"]`);
                        if (label) label.classList.toggle(CSS.SELECTED, event.target.checked);
                        if (event.target.checked) {
                            sectionContentElement.querySelector(`#${IDS.CLEAR_SITE_SEARCH_OPTION}`)?.classList.remove(CSS.SELECTED);
                        }
                    }
                });
                const applyBtn = sectionContentElement.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 selectedValuesFromCheckboxes = [];
                        sectionContentElement.querySelectorAll(`input[type="checkbox"].${CSS.SITE_SEARCH_ITEM_CHECKBOX}:checked`).forEach(cb => {
                            selectedValuesFromCheckboxes.push(cb.value);
                        });
                        if (selectedValuesFromCheckboxes.length > 0) {
                            URLActionManager.applySiteSearch(selectedValuesFromCheckboxes);
                            sectionContentElement.querySelector(`#${IDS.CLEAR_SITE_SEARCH_OPTION}`)?.classList.remove(CSS.SELECTED);
                        }
                    });
                }
            }
        }
    }

    function _createFiletypeSectionElement(sectionId, titleKey, scriptDefinedOptions, filterParam, currentSettings, predefinedOptionsSource) {
        const { section, sectionContent, sectionTitle } = _createSectionShell(sectionId, titleKey);
        sectionTitle.textContent = _(titleKey);
        populateFiletypeList(sectionContent, scriptDefinedOptions, currentSettings, predefinedOptionsSource, filterParam);
        return section;
    }

    function populateFiletypeList(sectionContentElement, scriptDefinedOpts, currentSettings, predefinedOptsSource, filterParam) {
        if (!sectionContentElement) { console.error("Filetype section content element missing"); return; }
        sectionContentElement.innerHTML = '';

        const checkboxModeEnabled = currentSettings.enableFiletypeCheckboxMode;
        const combinedOptions = _prepareFilterOptions('sidebar-section-filetype', scriptDefinedOpts, currentSettings, predefinedOptsSource);
        const listFragment = document.createDocumentFragment(); // For LIs

        const clearOptDiv = document.createElement('div');
        clearOptDiv.classList.add(CSS.FILTER_OPTION);
        clearOptDiv.id = IDS.CLEAR_FILETYPE_SEARCH_OPTION;
        clearOptDiv.title = _('filter_clear_tooltip_suffix');
        clearOptDiv.textContent = _('filter_any_format');
        clearOptDiv.dataset[DATA_ATTR.FILTER_TYPE] = 'filetype_clear'; // Special type
        sectionContentElement.appendChild(clearOptDiv);

        const listElement = document.createElement('ul');
        listElement.classList.add(CSS.CUSTOM_LIST);
        if (checkboxModeEnabled) {
            listElement.classList.add('checkbox-mode-enabled');
        }

        combinedOptions.forEach((option, index) => {
            if (option.isAnyOption) return; // "Any Format" is handled by the div above

            const li = document.createElement('li');
            const filetypeValue = option.value;

            if (checkboxModeEnabled) {
                const checkbox = document.createElement('input');
                checkbox.type = 'checkbox';
                checkbox.id = `ft-cb-${index}-${Date.now()}`; // Unique ID
                checkbox.value = filetypeValue;
                checkbox.classList.add(CSS.FILETYPE_SEARCH_ITEM_CHECKBOX);
                checkbox.dataset[DATA_ATTR.FILETYPE_VALUE] = filetypeValue;
                li.appendChild(checkbox);

                const label = document.createElement('label');
                label.htmlFor = checkbox.id; // Match checkbox ID
                label.dataset[DATA_ATTR.FILETYPE_VALUE] = filetypeValue;
                label.title = `${option.text} (${filterParam}=${filetypeValue.replace(/\s+OR\s+/gi, ', ')})`;
                label.textContent = option.text;
                li.appendChild(label);
            } else {
                const divOpt = document.createElement('div');
                divOpt.classList.add(CSS.FILTER_OPTION);
                divOpt.dataset[DATA_ATTR.FILTER_TYPE] = filterParam;
                divOpt.dataset[DATA_ATTR.FILTER_VALUE] = filetypeValue;
                divOpt.title = `${option.text} (${filterParam}=${filetypeValue.replace(/\s+OR\s+/gi, ', ')})`;
                divOpt.textContent = option.text;
                li.appendChild(divOpt);
            }
            listFragment.appendChild(li);
        });
        listElement.appendChild(listFragment);
        sectionContentElement.appendChild(listElement);

        if (checkboxModeEnabled) {
            let applyButton = sectionContentElement.querySelector(`#${IDS.APPLY_SELECTED_FILETYPES_BUTTON}`);
            if(!applyButton) {
                applyButton = document.createElement('button');
                applyButton.id = IDS.APPLY_SELECTED_FILETYPES_BUTTON;
                applyButton.classList.add(CSS.TOOL_BUTTON, CSS.APPLY_FILETYPES_BUTTON);
                applyButton.textContent = _('tool_apply_selected_filetypes');
                sectionContentElement.appendChild(applyButton);
            }
            applyButton.disabled = true;
            applyButton.style.display = 'none';
        }

        if (!sectionContentElement.dataset.filetypeClickListenerAttached) {
            sectionContentElement.dataset.filetypeClickListenerAttached = 'true';
            sectionContentElement.addEventListener('click', (event) => {
                const target = event.target;
                const isCheckboxMode = SettingsManager.getCurrentSettings().enableFiletypeCheckboxMode;
                const clearFiletypeOpt = target.closest(`#${IDS.CLEAR_FILETYPE_SEARCH_OPTION}`);

                if (clearFiletypeOpt) {
                    URLActionManager.clearFiletypeSearch();
                    sectionContentElement.querySelectorAll(`.${CSS.FILTER_OPTION}.${CSS.SELECTED}, label.${CSS.SELECTED}`).forEach(o => o.classList.remove(CSS.SELECTED));
                    clearFiletypeOpt.classList.add(CSS.SELECTED);
                    if (isCheckboxMode) {
                        sectionContentElement.querySelectorAll(`input[type="checkbox"].${CSS.FILETYPE_SEARCH_ITEM_CHECKBOX}`).forEach(cb => cb.checked = false);
                        _updateApplyFiletypesButtonState(sectionContentElement);
                    }
                } else if (isCheckboxMode) {
                    const labelElement = target.closest('label');
                    if (labelElement && labelElement.dataset[DATA_ATTR.FILETYPE_VALUE]) {
                        event.preventDefault();
                        const filetypeValueOrCombined = labelElement.dataset[DATA_ATTR.FILETYPE_VALUE];
                        sectionContentElement.querySelectorAll(`input[type="checkbox"].${CSS.FILETYPE_SEARCH_ITEM_CHECKBOX}`).forEach(cb => {
                            const correspondingLabel = sectionContentElement.querySelector(`label[for="${cb.id}"]`);
                            cb.checked = (cb.value === filetypeValueOrCombined);
                             if(correspondingLabel) correspondingLabel.classList.toggle(CSS.SELECTED, cb.checked);
                        });
                        URLActionManager.applyCombinedFiletypeSearch(filetypeValueOrCombined);
                        _updateApplyFiletypesButtonState(sectionContentElement);
                        sectionContentElement.querySelector(`#${IDS.CLEAR_FILETYPE_SEARCH_OPTION}`)?.classList.remove(CSS.SELECTED);
                    }
                } else {
                    const optionDiv = target.closest(`div.${CSS.FILTER_OPTION}:not(#${IDS.CLEAR_FILETYPE_SEARCH_OPTION})`);
                    if (optionDiv && optionDiv.dataset[DATA_ATTR.FILTER_VALUE]) {
                        const clickedFilterType = optionDiv.dataset[DATA_ATTR.FILTER_TYPE];
                        const clickedFilterValueOrCombined = optionDiv.dataset[DATA_ATTR.FILTER_VALUE];
                        sectionContentElement.querySelectorAll(`.${CSS.FILTER_OPTION}.${CSS.SELECTED}`).forEach(o => o.classList.remove(CSS.SELECTED));
                        optionDiv.classList.add(CSS.SELECTED);
                        URLActionManager.applyFilter(clickedFilterType, clickedFilterValueOrCombined);
                        sectionContentElement.querySelector(`#${IDS.CLEAR_FILETYPE_SEARCH_OPTION}`)?.classList.remove(CSS.SELECTED);
                    }
                }
            });

            if (checkboxModeEnabled) {
                sectionContentElement.addEventListener('change', (event) => {
                    if (event.target.matches(`input[type="checkbox"].${CSS.FILETYPE_SEARCH_ITEM_CHECKBOX}`)) {
                        _updateApplyFiletypesButtonState(sectionContentElement);
                        const label = sectionContentElement.querySelector(`label[for="${event.target.id}"]`);
                        if (label) label.classList.toggle(CSS.SELECTED, event.target.checked);
                        if (event.target.checked) {
                            sectionContentElement.querySelector(`#${IDS.CLEAR_FILETYPE_SEARCH_OPTION}`)?.classList.remove(CSS.SELECTED);
                        }
                    }
                });
                const applyBtn = sectionContentElement.querySelector(`#${IDS.APPLY_SELECTED_FILETYPES_BUTTON}`);
                if (applyBtn && !applyBtn.dataset[DATA_ATTR.LISTENER_ATTACHED]) {
                    applyBtn.dataset[DATA_ATTR.LISTENER_ATTACHED] = 'true';
                    applyBtn.addEventListener('click', () => {
                        const selectedValuesFromCheckboxes = [];
                        sectionContentElement.querySelectorAll(`input[type="checkbox"].${CSS.FILETYPE_SEARCH_ITEM_CHECKBOX}:checked`).forEach(cb => {
                            selectedValuesFromCheckboxes.push(cb.value);
                        });
                        if (selectedValuesFromCheckboxes.length > 0) {
                            URLActionManager.applyCombinedFiletypeSearch(selectedValuesFromCheckboxes);
                            sectionContentElement.querySelector(`#${IDS.CLEAR_FILETYPE_SEARCH_OPTION}`)?.classList.remove(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 _updateApplyFiletypesButtonState(sectionContentElement) {
        if (!sectionContentElement) return;
        const applyButton = sectionContentElement.querySelector(`#${IDS.APPLY_SELECTED_FILETYPES_BUTTON}`);
        if (!applyButton) return;
        const checkedCount = sectionContentElement.querySelectorAll(`input[type="checkbox"].${CSS.FILETYPE_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 && sectionDef.id !== 'sidebar-section-filetype' && sectionDef.id !== 'sidebar-section-site-search') {
                     _initializeStandaloneFilterState(params, sectionDef.id, sectionDef.param);
                }
            });
            _initializeTimeFilterState(currentTbs);
            _initializeVerbatimState();
            _initializePersonalizationState();
            _initializeDateRangeInputs(currentTbs);
            _initializeSiteSearchState(currentQuery);
            _initializeFiletypeSearchState(currentQuery, params.get('as_filetype'));
        } 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 siteSearchSectionContent = sidebar?.querySelector('#sidebar-section-site-search .'+CSS.SECTION_CONTENT);
        if (!siteSearchSectionContent) return;

        const clearSiteOptDiv = siteSearchSectionContent.querySelector(`#${IDS.CLEAR_SITE_SEARCH_OPTION}`);
        const listElement = siteSearchSectionContent.querySelector('ul.' + CSS.CUSTOM_LIST);
        const currentSettings = SettingsManager.getCurrentSettings();
        const checkboxModeEnabled = currentSettings.enableSiteSearchCheckboxMode;

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

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

        if (siteMatchOr && siteMatchOr[1]) {
            const innerQuery = siteMatchOr[1];
            const individualSiteMatches = [...innerQuery.matchAll(/site:([\w.:()-]+)/gi)];
            activeSiteUrlsFromQuery = individualSiteMatches.map(match => match[1].toLowerCase());
        } else {
            const siteMatchSimple = currentQuery.match(/(?<!\S)site:([\w.:()-]+)(?!\S)/i);
            if (siteMatchSimple && siteMatchSimple[1]) {
                activeSiteUrlsFromQuery.push(siteMatchSimple[1].toLowerCase());
            }
        }
        activeSiteUrlsFromQuery.sort(); // Sort for consistent comparison

        if (activeSiteUrlsFromQuery.length > 0) {
            if(clearSiteOptDiv) clearSiteOptDiv.classList.remove(CSS.SELECTED);
            let customOptionFullyMatched = false;

            if (listElement) {
                const customSiteOptions = Array.from(listElement.querySelectorAll(checkboxModeEnabled ? 'label' : `div.${CSS.FILTER_OPTION}`));
                for (const optElement of customSiteOptions) {
                    const customSiteValue = optElement.dataset[DATA_ATTR.SITE_URL];
                    if (!customSiteValue) continue;

                    const definedCustomSites = Utils.parseCombinedValue(customSiteValue).map(s => s.toLowerCase()).sort();
                    if (definedCustomSites.length === activeSiteUrlsFromQuery.length && definedCustomSites.every((val, index) => val === activeSiteUrlsFromQuery[index])) {
                        if (checkboxModeEnabled) {
                            const checkbox = listElement.querySelector(`input[type="checkbox"][value="${customSiteValue}"]`);
                            if (checkbox) checkbox.checked = true;
                        }
                        optElement.classList.add(CSS.SELECTED);
                        customOptionFullyMatched = true;
                        break; // Found a full match for the custom OR group
                    }
                }
            }

            // If no custom OR option fully matched, but URL has sites, select individual checkboxes/options if applicable
            if (!customOptionFullyMatched && listElement) {
                activeSiteUrlsFromQuery.forEach(url => {
                    if (checkboxModeEnabled) {
                        const checkbox = listElement.querySelector(`input[type="checkbox"].${CSS.SITE_SEARCH_ITEM_CHECKBOX}[value="${url}"]`);
                        if (checkbox) { checkbox.checked = true; const label = listElement.querySelector(`label[for="${checkbox.id}"]`); if(label) label.classList.add(CSS.SELECTED); }
                    } else {
                        // This case is less likely if a combined query was in URL, but handle for single site from URL
                        const option = listElement.querySelector(`.${CSS.FILTER_OPTION}[data-${DATA_ATTR.SITE_URL}="${url}"]`);
                        if (option) option.classList.add(CSS.SELECTED);
                    }
                });
            }
        } else {
            if (clearSiteOptDiv) clearSiteOptDiv.classList.add(CSS.SELECTED);
        }

        if (checkboxModeEnabled) {
            _updateApplySitesButtonState(siteSearchSectionContent);
        }
    }

    function _initializeFiletypeSearchState(currentQuery, asFiletypeParam) {
        const filetypeSectionContent = sidebar?.querySelector('#sidebar-section-filetype .'+CSS.SECTION_CONTENT);
        if (!filetypeSectionContent) return;

        const clearFiletypeOptDiv = filetypeSectionContent.querySelector(`#${IDS.CLEAR_FILETYPE_SEARCH_OPTION}`);
        const listElement = filetypeSectionContent.querySelector('ul.' + CSS.CUSTOM_LIST);
        const currentSettings = SettingsManager.getCurrentSettings();
        const checkboxModeEnabled = currentSettings.enableFiletypeCheckboxMode;

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

        let activeFiletypesFromQuery = [];
        const filetypeMatchOr = currentQuery.match(/\(\s*(filetype:[\w.:()-]+(?:\s+OR\s+filetype:[\w.:()-]+)*)\s*\)/i);

        if (filetypeMatchOr && filetypeMatchOr[1]) {
            const innerQuery = filetypeMatchOr[1];
            const individualFiletypeMatches = [...innerQuery.matchAll(/filetype:([\w.:()-]+)/gi)];
            activeFiletypesFromQuery = individualFiletypeMatches.map(match => match[1].toLowerCase());
        } else {
            const filetypeMatchSimpleSingle = currentQuery.match(/(?<!\S)filetype:([\w.:()-]+)(?!\S)/i);
            if (filetypeMatchSimpleSingle && filetypeMatchSimpleSingle[1]) {
                activeFiletypesFromQuery.push(filetypeMatchSimpleSingle[1].toLowerCase());
            } else if (asFiletypeParam && !currentQuery.includes('filetype:')) { // Only use as_filetype if q doesn't have filetype
                activeFiletypesFromQuery.push(asFiletypeParam.toLowerCase());
            }
        }
        activeFiletypesFromQuery.sort();

        if (activeFiletypesFromQuery.length > 0) {
            if(clearFiletypeOptDiv) clearFiletypeOptDiv.classList.remove(CSS.SELECTED);
            let customOptionFullyMatched = false;

            if (listElement) {
                const customFiletypeOptions = Array.from(listElement.querySelectorAll(checkboxModeEnabled ? 'label' : `div.${CSS.FILTER_OPTION}`));
                for (const optElement of customFiletypeOptions) {
                    const customFtValueAttr = checkboxModeEnabled ? optElement.dataset[DATA_ATTR.FILETYPE_VALUE] : optElement.dataset[DATA_ATTR.FILTER_VALUE];
                    if (!customFtValueAttr) continue;

                    const definedCustomFiletypes = Utils.parseCombinedValue(customFtValueAttr).map(s => s.toLowerCase()).sort();
                     if (definedCustomFiletypes.length > 0 && definedCustomFiletypes.length === activeFiletypesFromQuery.length && definedCustomFiletypes.every((val, index) => val === activeFiletypesFromQuery[index])) {
                        if (checkboxModeEnabled) {
                            const checkbox = listElement.querySelector(`input[type="checkbox"][value="${customFtValueAttr}"]`);
                            if (checkbox) checkbox.checked = true;
                        }
                        optElement.classList.add(CSS.SELECTED);
                        customOptionFullyMatched = true;
                        break;
                    }
                }
            }

            if (!customOptionFullyMatched && listElement) {
                activeFiletypesFromQuery.forEach(ft => {
                    if (checkboxModeEnabled) {
                        const checkbox = listElement.querySelector(`input[type="checkbox"].${CSS.FILETYPE_SEARCH_ITEM_CHECKBOX}[value="${ft}"]`);
                        if (checkbox) { checkbox.checked = true; const label = listElement.querySelector(`label[for="${checkbox.id}"]`); if(label) label.classList.add(CSS.SELECTED); }
                    } else {
                        const option = listElement.querySelector(`.${CSS.FILTER_OPTION}[data-${DATA_ATTR.FILTER_VALUE}="${ft}"]`);
                        if (option) option.classList.add(CSS.SELECTED);
                    }
                });
            }
        } else {
             if (clearFiletypeOptDiv) clearFiletypeOptDiv.classList.add(CSS.SELECTED);
        }
        if (checkboxModeEnabled) {
            _updateApplyFiletypesButtonState(filetypeSectionContent);
        }
    }

    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(); } }
})();