Google Search Custom Sidebar

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Google Search Custom Sidebar
// @name:zh-TW   Google 搜尋自訂側邊欄
// @name:ja      Google検索カスタムサイドバー
// @namespace    https://greasyfork.org/en/users/1467948-stonedkhajiit
// @version      0.0.6
// @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/1589133/Google%20Search%20Custom%20Sidebar%20-%20i18n.js
// @require      https://update.greasyfork.org/scripts/535625/1589134/Google%20Search%20Custom%20Sidebar%20-%20Styles.js
// ==/UserScript==

(function() {
    'use strict';

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

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

    const defaultSettings = { // (Same as previous 0.0.5 attempt)
        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-country': true, 'sidebar-section-date-range': true, 'sidebar-section-site-search': true,
            'sidebar-section-tools': true
        },
        sectionDisplayMode: 'remember',
        accordionMode: false,
        resetButtonLocation: 'topBlock',
        verbatimButtonLocation: 'header',
        advancedSearchLinkLocation: 'header',
        personalizationButtonLocation: 'tools',
        countryDisplayMode: 'iconAndText',
        customLanguages: [],
        customTimeRanges: [],
        customFiletypes: [],
        customCountries: [],
        displayLanguages: [],
        displayCountries: [],
        favoriteSites: [
            { text: 'Wikipedia (EN)', url: 'en.wikipedia.org' }, { text: 'Stack Overflow', url: 'stackoverflow.com' },
            { text: 'GitHub', url: 'github.com' }, { text: 'Greasy Fork', url: 'greasyfork.org' },
            { text: 'Bluesky', url: 'bsky.app' }, { text: 'X.com', url: 'x.com' },
            { text: 'Reddit', url: 'reddit.com' }, { text: 'IMDb', url: 'imdb.com' },
            { text: 'Steam', url: 'store.steampowered.com' }, { text: 'Last.fm', url: 'last.fm' },
            { text: 'Metacritic', url: 'metacritic.com' }, { text: 'TMDb', url: 'themoviedb.org' },
            { text: 'Hacker News', url: 'news.ycombinator.com' }
        ],
        sidebarCollapsed: false,
        draggableHandleEnabled: true,
        enabledPredefinedOptions: {
            language: ['lang_en'],
            country: ['countryUS'],
            time: ['d', 'w', 'm', 'y', 'h'],
            filetype: ['pdf', 'docx', 'doc', 'xlsx', 'xls', 'pptx', 'ppt']
        },
        sidebarSectionOrder: [...DEFAULT_SECTION_ORDER]
    };

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

    const IDS = { /* ... (same as v0.0.5 attempt) ... */
        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',
        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_COUNTRY_DISPLAY_MODE: 'setting-country-display-mode', SETTING_THEME: 'setting-theme',
        SETTING_HOVER: 'setting-hover-mode', SETTING_OPACITY: 'setting-idle-opacity',
        TAB_PANE_GENERAL: 'tab-pane-general', TAB_PANE_APPEARANCE: 'tab-pane-appearance', TAB_PANE_FEATURES: 'tab-pane-features', TAB_PANE_CUSTOM: 'tab-pane-custom',
        SITES_LIST: 'custom-sites-list', LANG_LIST: 'custom-languages-list', TIME_LIST: 'custom-time-ranges-list',
        FT_LIST: 'custom-filetypes-list', COUNTRIES_LIST: 'custom-countries-list',
        NEW_SITE_NAME: 'new-site-name', NEW_SITE_URL: 'new-site-url', ADD_SITE_BTN: 'add-site-button',
        NEW_LANG_TEXT: 'new-lang-text', NEW_LANG_VALUE: 'new-lang-value', ADD_LANG_BTN: 'add-lang-button',
        NEW_TIME_TEXT: 'new-timerange-text', NEW_TIME_VALUE: 'new-timerange-value', ADD_TIME_BTN: 'add-timerange-button',
        NEW_FT_TEXT: 'new-ft-text', NEW_FT_VALUE: 'new-ft-value', ADD_FT_BTN: 'add-ft-button',
        NEW_COUNTRY_TEXT: 'new-country-text', NEW_COUNTRY_VALUE: 'new-country-value', ADD_COUNTRY_BTN: 'add-country-button',
        DATE_MIN: 'date-min', DATE_MAX: 'date-max', DATE_RANGE_ERROR_MSG: 'date-range-error-msg',
        SIDEBAR_SECTION_ORDER_LIST: 'sidebar-section-order-list',
        NOTIFICATION_CONTAINER: 'gscs-notification-container',
        MODAL_ADD_NEW_OPTION_BTN: 'gscs-modal-add-new-option-btn',
        MODAL_PREDEFINED_CHOOSER_CONTAINER: 'gscs-modal-predefined-chooser-container',
        MODAL_PREDEFINED_CHOOSER_LIST: 'gscs-modal-predefined-chooser-list',
        MODAL_PREDEFINED_CHOOSER_ADD_BTN: 'gscs-modal-predefined-chooser-add-btn',
        MODAL_PREDEFINED_CHOOSER_CANCEL_BTN: 'gscs-modal-predefined-chooser-cancel-btn'
    };
    const CSS = { /* ... (same as v0.0.5 attempt) ... */
        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',
        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'
    };
    const DATA_ATTR = { /* ... (same as v0.0.5 attempt) ... */
        FILTER_TYPE: 'filterType', FILTER_VALUE: 'filterValue', SITE_URL: 'siteUrl', SECTION_ID: 'sectionId',
        LIST_ID: 'listId', INDEX: 'index', LISTENER_ATTACHED: 'listenerAttached', TAB: 'tab', MANAGE_TYPE: 'managetype',
        ITEM_TYPE: 'itemType', ITEM_ID: 'itemId'
    };
    const STORAGE_KEY = 'googleSearchCustomSidebarSettings_v1';
    const SVG_ICONS = { /* ... (same as v0.0.5 attempt) ... */
        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 = { /* ... (same as v0.0.4) ... */
        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 = [ /* ... (same as v0.0.4) ... */ { 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' /* no displayItemsKey yet */ }, { id: 'sidebar-section-filetype', type: 'filter', titleKey: 'section_filetype', scriptDefined: [{ textKey: 'filter_any_format', v: '' }], param: 'filetype', predefinedOptionsKey: 'filetype', customItemsKey: 'customFiletypes' /* no displayItemsKey yet */ }, { id: 'sidebar-section-country', type: 'filter', titleKey: 'section_country', scriptDefined: [{textKey:'filter_any_country',v:''}], param: 'cr', predefinedOptionsKey: 'country', customItemsKey: 'customCountries', displayItemsKey: 'displayCountries' }, { id: 'sidebar-section-date-range', type: 'date', titleKey: 'section_date_range' }, { id: 'sidebar-section-site-search', type: 'site', titleKey: 'section_site_search' }, { id: 'sidebar-section-tools', type: 'tools', titleKey: 'section_tools' } ];

    const LocalizationService = (function() {
        const builtInTranslations = {
            'en': {
                scriptName: 'Google Search Custom Sidebar', settingsTitle: 'Google Search Custom Sidebar Settings', manageOptionsTitle: 'Manage Options', manageSitesTitle: 'Manage Favorite Sites', manageLanguagesTitle: 'Manage Language Options', manageCountriesTitle: 'Manage Country/Region Options', manageTimeRangesTitle: 'Manage Time Ranges', manageFileTypesTitle: 'Manage File Types', section_language: 'Language', section_time: 'Time', section_filetype: 'File Type', section_country: 'Country/Region', section_date_range: 'Date Range', section_site_search: 'Site Search', section_tools: 'Tools', filter_any_language: 'Any Language', filter_any_time: 'Any Time', filter_any_format: 'Any Format', filter_any_country: 'Any Country/Region', 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',
                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_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_location_tools: 'Tools Section', settings_location_top: 'Top Block', settings_location_header: 'Sidebar Header', settings_location_hide: 'Hide', settings_sidebar_width: 'Sidebar Width (px)', settings_width_range_hint: '(Range: 90-270, Step: 5)', settings_font_size: 'Base Font Size (px)', settings_font_size_range_hint: '(Range: 8-24, Step: 0.5)', settings_header_icon_size: 'Header Icon Size (px)', settings_header_icon_size_range_hint: '(Range: 8-32, Step: 0.5)', settings_vertical_spacing: 'Vertical Spacing', settings_vertical_spacing_range_hint: '(Multiplier Range: 0.05-1.5, Step: 0.05)', settings_theme: 'Theme:', settings_theme_system: 'Follow System', settings_theme_light: 'Light', settings_theme_dark: 'Dark', settings_theme_minimal_light: 'Minimal (Light)', settings_theme_minimal_dark: 'Minimal (Dark)', settings_hover_mode: 'Hover Mode', settings_idle_opacity: 'Idle Opacity:', settings_opacity_range_hint: '(Range: 0.1-1.0, Step: 0.05)', settings_country_display: 'Country/Region Display:', settings_country_display_icontext: 'Icon & Text', settings_country_display_text: 'Text Only', settings_country_display_icon: 'Icon Only', settings_visible_sections: 'Visible Sections:', settings_section_order: 'Adjust Sidebar Section Order (Drag & Drop):',
                settings_section_order_hint: '(Drag items to reorder. Only affects checked sections)',
                settings_no_orderable_sections: 'No visible sections to order.',
                settings_move_up_title: 'Move Up',
                settings_move_down_title: 'Move Down',
                settings_custom_intro: 'Manage filter options for each section:',
                settings_manage_sites_button: 'Manage Favorite Sites...', settings_manage_languages_button: 'Manage Language Options...', settings_manage_countries_button: 'Manage Country/Region Options...', settings_manage_time_ranges_button: 'Manage Time Ranges...', settings_manage_file_types_button: 'Manage File Types...', settings_save_button: 'Save Settings', settings_cancel_button: 'Cancel', settings_reset_all_button: 'Reset All',
                modal_label_enable_predefined: 'Enable Predefined {type}:',
                modal_label_my_custom: 'My Custom {type}:',
                modal_label_display_options_for: 'Display Options for {type} (Drag to Sort):',
                modal_button_add_new_option: 'Add New Option...',
                modal_button_add_predefined_option: 'Add Predefined...',
                modal_button_add_custom_option: 'Add Custom...',
                modal_placeholder_name: 'Name', modal_placeholder_domain: 'Domain', modal_placeholder_text: 'Text', modal_placeholder_value: 'Value', modal_hint_domain: 'Format: valid top-level domain, e.g., `wikipedia.org`', modal_hint_language: 'Format: starts with `lang_`, e.g., `lang_ja`, `lang_zh-TW`. Use `|` for multiple.', modal_hint_country: 'Format: `country` + 2-letter uppercase code, e.g., `countryDE`', modal_hint_time: 'Format: `h`, `d`, `w`, `m`, `y`, optionally followed by numbers, e.g., `h1`, `d7`, `w`', modal_hint_filetype: 'Format: file extension, e.g., `pdf`, `docx`', modal_tooltip_domain: 'Please enter a valid domain', modal_tooltip_language: 'Format: lang_xx or lang_xx-XX, separate multiple with |', modal_tooltip_country: 'Format: countryXX (XX = uppercase country code)', modal_tooltip_time: 'Format: h, d, w, m, y, optionally followed by numbers', modal_tooltip_filetype: 'File extension (without the dot)', modal_button_add_title: 'Add', modal_button_update_title: 'Update Item', modal_button_cancel_edit_title: 'Cancel Edit', modal_button_edit_title: 'Edit', modal_button_delete_title: 'Delete', modal_button_remove_from_list_title: 'Remove from list', modal_button_complete: 'Done', value_empty: '(empty)', date_range_from: 'From:', date_range_to: 'To:', sidebar_collapse_title: 'Collapse', sidebar_expand_title: 'Expand', sidebar_drag_title: 'Drag', sidebar_settings_title: 'Settings',
                alert_invalid_start_date: 'Invalid start date', alert_invalid_end_date: 'Invalid end date', alert_end_before_start: 'End date cannot be earlier than start date', alert_start_in_future: 'Start date cannot be in the future', alert_end_in_future: 'End date cannot be in the future', alert_select_date: 'Please select a date', alert_error_applying_date: 'Error applying date range', alert_error_applying_filter: 'Error applying filter {type}={value}', alert_error_applying_site_search: 'Error applying site search for {site}', alert_error_clearing_site_search: 'Error clearing site search', alert_error_resetting_filters: 'Error resetting filters', alert_error_toggling_verbatim: 'Error toggling Verbatim search', alert_error_toggling_personalization: 'Error toggling Personalization search', alert_enter_display_name: 'Please enter the display name for {type}.', alert_enter_value: 'Please enter the corresponding value for {type}.', alert_invalid_value_format: 'The value format for {type} is incorrect. {hint}', alert_duplicate_name: 'Custom item display name "{name}" already exists. Please use a different name.', alert_update_failed_invalid_index: 'Update failed: Invalid item index.', alert_edit_failed_missing_fields: 'Cannot edit: Input or button fields not found.',
                alert_no_more_predefined_to_add: 'No more predefined {type} options available to add.', // New string
                alert_generic_error: 'An unexpected error occurred. Please check the console or try again. Context: {context}', // Added 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] = {}; } Object.assign(effectiveTranslations[langCode], externalTranslations[langCode]); } } } else { console.warn(`${LOG_PREFIX} [i18n] External i18n pack (window.GSCS_Namespace.i18nPack) not found or invalid. Using built-in translations only.`); } }
        function _detectBrowserLocale() { let locale = 'en'; try { if (navigator.languages && navigator.languages.length) { locale = navigator.languages[0]; } else if (navigator.language) { locale = navigator.language; } } catch (e) { console.warn(`${LOG_PREFIX} [i18n] Error accessing navigator.language(s):`, e); } if (effectiveTranslations[locale]) return locale; if (locale.includes('-')) { const parts = locale.split('-'); if (parts.length > 0 && effectiveTranslations[parts[0]]) return parts[0]; if (parts.length > 2 && effectiveTranslations[`${parts[0]}-${parts[1]}`]) return `${parts[0]}-${parts[1]}`; } return 'en'; }
        function _updateActiveLocale(settingsToUse) { let newLocale = 'en'; const langSettingSource = (settingsToUse && Object.keys(settingsToUse).length > 0 && typeof settingsToUse.interfaceLanguage === 'string') ? settingsToUse : defaultSettings; const userSelectedLang = langSettingSource.interfaceLanguage; if (userSelectedLang && userSelectedLang !== 'auto') { if (effectiveTranslations[userSelectedLang]) { newLocale = userSelectedLang; } else if (userSelectedLang.includes('-')) { const genericLang = userSelectedLang.split('-')[0]; if (effectiveTranslations[genericLang]) { newLocale = genericLang; } else { newLocale = _detectBrowserLocale(); } } else { newLocale = _detectBrowserLocale(); } } else { newLocale = _detectBrowserLocale(); } if (_currentLocale !== newLocale) { _currentLocale = newLocale; } if (userSelectedLang && userSelectedLang !== 'auto' && _currentLocale !== userSelectedLang && !userSelectedLang.includes(_currentLocale)) { console.warn(`${LOG_PREFIX} [i18n] User selected language "${userSelectedLang}" was not fully available or matched. Using best match: "${_currentLocale}".`); } }
        _mergeExternalTranslations();
        function getString(key, replacements = {}) { let str = `[ERR: ${key} @ ${_currentLocale}]`; let found = false; if (effectiveTranslations[_currentLocale] && typeof effectiveTranslations[_currentLocale][key] !== 'undefined') { str = effectiveTranslations[_currentLocale][key]; found = true; } else if (_currentLocale.includes('-')) { const genericLang = _currentLocale.split('-')[0]; if (effectiveTranslations[genericLang] && typeof effectiveTranslations[genericLang][key] !== 'undefined') { str = effectiveTranslations[genericLang][key]; found = true; } } if (!found && _currentLocale !== 'en') { if (effectiveTranslations['en'] && typeof effectiveTranslations['en'][key] !== 'undefined') { str = effectiveTranslations['en'][key]; found = true; } } if (!found) { if (!(effectiveTranslations['en'] && typeof effectiveTranslations['en'][key] !== 'undefined')) { console.error(`${LOG_PREFIX} [i18n] CRITICAL: Missing translation for key: "${key}" in BOTH locale: "${_currentLocale}" AND default locale "en".`); } else { str = effectiveTranslations['en'][key]; found = true; } if(!found) str = `[ERR_NF: ${key}]`; } if (typeof str === 'string') { for (const placeholder in replacements) { if (Object.prototype.hasOwnProperty.call(replacements, placeholder)) { str = str.replace(new RegExp(`\\{${placeholder}\\}`, 'g'), replacements[placeholder]); } } } else { console.error(`${LOG_PREFIX} [i18n] CRITICAL: Translation for key "${key}" is not a string:`, str); return `[INVALID_TYPE_FOR_KEY: ${key}]`; } return str; }
        return { getString: getString, getCurrentLocale: function() { return _currentLocale; }, getTranslationsForLocale: function(locale = 'en') { return effectiveTranslations[locale] || effectiveTranslations['en']; }, initializeBaseLocale: function() { _updateActiveLocale(defaultSettings); }, updateActiveLocale: function(activeSettings) { _updateActiveLocale(activeSettings); }, getAvailableLocales: function() { const locales = new Set(['auto', 'en']); Object.keys(effectiveTranslations).forEach(lang => { if (Object.keys(effectiveTranslations[lang]).length > 0) { locales.add(lang); } }); return Array.from(locales).sort((a, b) => { if (a === 'auto') return -1; if (b === 'auto') return 1; if (a === 'en' && b !== 'auto') return -1; if (b === 'en' && a !== 'auto') return 1; let nameA = a, nameB = b; try { nameA = new Intl.DisplayNames([a],{type:'language'}).of(a); } catch(e){} try { nameB = new Intl.DisplayNames([b],{type:'language'}).of(b); } catch(e){} return nameA.localeCompare(nameB); }); } };
    })();
    const _ = LocalizationService.getString;
    const Utils = { /* ... (same as v0.0.4) ... */ debounce: function(func, wait) { let timeout; return function executedFunction(...args) { const context = this; const later = () => { timeout = null; func.apply(context, args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; }, mergeDeep: function(target, source) { if (!source) return target; target = target || {}; for (const key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { const targetValue = target[key]; const sourceValue = source[key]; if (sourceValue && typeof sourceValue === 'object' && !Array.isArray(sourceValue)) { target[key] = Utils.mergeDeep(targetValue, sourceValue); } else if (typeof sourceValue !== 'undefined') { target[key] = sourceValue; } } } return target; }, clamp: function(num, min, max) { return Math.min(Math.max(num, min), max); }, parseIconAndText: function(fullText) { const match = fullText.match(/^(\P{L}\P{N}\s*)+/u); let icon = ''; let text = fullText; if (match && match[0].trim() !== '') { icon = match[0].trim(); text = fullText.substring(icon.length).trim(); } return { icon, text }; }, getCurrentURL: function() { try { return new URL(window.location.href); } catch (e) { console.error(`${LOG_PREFIX} Error creating URL object:`, e); return null; } } };
    const NotificationManager = (function() { /* ... (same as v0.0.4) ... */ 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 }; })();

    // --- List Population and Item Creation (Consolidated) ---

    function createGenericListItem(index, item, listId, mapping) { /* ... (same as v0.0.4) ... */
        const listItem = document.createElement('li');
        listItem.dataset[DATA_ATTR.INDEX] = index;
        listItem.dataset[DATA_ATTR.LIST_ID] = listId;
        listItem.dataset[DATA_ATTR.ITEM_ID] = item.id || item.value || item.url;
        listItem.draggable = true;

        const dragIconSpan = document.createElement('span');
        dragIconSpan.classList.add(CSS.DRAG_ICON);
        dragIconSpan.innerHTML = SVG_ICONS.dragGrip;
        listItem.appendChild(dragIconSpan);

        const textSpan = document.createElement('span');
        let displayText = item.text;
        let paramName = '';

        if (item.type === 'predefined' && item.originalKey) {
            displayText = _(item.originalKey);
            if (listId === IDS.COUNTRIES_LIST) {
                const parsed = Utils.parseIconAndText(displayText);
                displayText = `${parsed.icon} ${parsed.text}`.trim();
            }
        }

        if (mapping) {
            if (listId === IDS.LANG_LIST) paramName = ALL_SECTION_DEFINITIONS.find(s=>s.id === 'sidebar-section-language').param;
            else if (listId === IDS.COUNTRIES_LIST) paramName = ALL_SECTION_DEFINITIONS.find(s=>s.id === 'sidebar-section-country').param;
            else if (listId === IDS.SITES_LIST) paramName = 'site';
            else if (listId === IDS.TIME_LIST) paramName = ALL_SECTION_DEFINITIONS.find(s=>s.id === 'sidebar-section-time').param;
            else if (listId === IDS.FT_LIST) paramName = ALL_SECTION_DEFINITIONS.find(s=>s.id === 'sidebar-section-filetype').param;
        }

        const valueForDisplay = item.value || item.url || _('value_empty');
        textSpan.textContent = `${displayText} (${paramName}=${valueForDisplay})`;
        textSpan.title = textSpan.textContent;
        listItem.appendChild(textSpan);

        const controlsSpan = document.createElement('span');
        controlsSpan.classList.add(CSS.ITEM_CONTROLS);
        if (item.type === 'custom' || listId === IDS.SITES_LIST || listId === IDS.TIME_LIST || listId === IDS.FT_LIST) {
            controlsSpan.innerHTML =
                `<button class="${CSS.EDIT_CUSTOM_ITEM}" title="${_('modal_button_edit_title')}">${SVG_ICONS.edit}</button> ` +
                `<button class="${CSS.DELETE_CUSTOM_ITEM}" title="${_('modal_button_delete_title')}">${SVG_ICONS.delete}</button>`;
            listItem.dataset[DATA_ATTR.ITEM_TYPE] = 'custom';
        } else if (item.type === 'predefined') {
            controlsSpan.innerHTML =
                `<button class="${CSS.REMOVE_FROM_LIST_BTN}" title="${_('modal_button_remove_from_list_title')}">${SVG_ICONS.removeFromList}</button>`;
            listItem.dataset[DATA_ATTR.ITEM_TYPE] = 'predefined';
        }
        listItem.appendChild(controlsSpan);
        return listItem;
    }

    function populateListInModal(listId, items, contextElement = document) { /* ... (same as v0.0.4) ... */
        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) { /* ... (same as v0.0.4) ... */
        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) { /* ... (same as v0.0.4) ... */ if (!inputElement) return false; const value = inputElement.value.trim(); const id = inputElement.id; let isValid = false; let isEmpty = value === ''; if (id === IDS.NEW_SITE_NAME || id === IDS.NEW_LANG_TEXT || id === IDS.NEW_TIME_TEXT || id === IDS.NEW_FT_TEXT || id === IDS.NEW_COUNTRY_TEXT) { isValid = !isEmpty; } else if (id === IDS.NEW_SITE_URL) { isValid = isEmpty || /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/.test(value); } else if (id === IDS.NEW_LANG_VALUE) { isValid = isEmpty || /^lang_[a-zA-Z]{2,3}(?:-[a-zA-Z0-9]{2,4})?(?:\|lang_[a-zA-Z]{2,3}(?:-[a-zA-Z0-9]{2,4})?)*$/.test(value); } else if (id === IDS.NEW_TIME_VALUE) { isValid = isEmpty || /^[hdwmy]\d*$/.test(value); } else if (id === IDS.NEW_FT_VALUE) { isValid = isEmpty || /^[a-zA-Z0-9]+$/.test(value); } else if (id === IDS.NEW_COUNTRY_VALUE) { isValid = isEmpty || /^country[A-Z]{2}$/.test(value); } inputElement.classList.remove('input-valid', 'input-invalid', CSS.INPUT_HAS_ERROR); _clearInputError(inputElement); if (!isEmpty) { inputElement.classList.add(isValid ? 'input-valid' : 'input-invalid'); if (!isValid) inputElement.classList.add(CSS.INPUT_HAS_ERROR); } return isValid || isEmpty; }
    function _getInputErrorElement(inputElement) { /* ... (same as v0.0.4) ... */ 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 = {}) { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.4) ... */ if (!textInput || !valueInput) { _showGlobalMessage('alert_edit_failed_missing_fields', {}, 'error', 0); return { isValid: false }; } _clearInputError(textInput); _clearInputError(valueInput); const text = textInput.value.trim(); const value = valueInput.value.trim(); let hint = ''; if (text === '') { _showInputError(textInput, 'alert_enter_display_name', { type: itemTypeName }); textInput.focus(); return { isValid: false, errorField: textInput }; } else { textInput.classList.remove(CSS.INPUT_HAS_ERROR); validateCustomInput(textInput); } if (value === '') { _showInputError(valueInput, 'alert_enter_value', { type: itemTypeName }); valueInput.focus(); return { isValid: false, errorField: valueInput }; } else { const isValueFormatValid = validateCustomInput(valueInput); if (!isValueFormatValid && !valueInput.classList.contains('input-invalid')) { if (listId === IDS.COUNTRIES_LIST) hint = _('modal_tooltip_country'); else if (listId === IDS.LANG_LIST) hint = _('modal_tooltip_language'); else if (listId === IDS.TIME_LIST) hint = _('modal_tooltip_time'); else if (listId === IDS.FT_LIST) hint = _('modal_tooltip_filetype'); else if (listId === IDS.SITES_LIST) hint = _('modal_tooltip_domain'); _showInputError(valueInput, 'alert_invalid_value_format', { type: itemTypeName, hint: hint }); valueInput.focus(); return { isValid: false, errorField: valueInput }; } else if (!isValueFormatValid) { valueInput.focus(); return { isValid: false, errorField: valueInput }; } else { valueInput.classList.remove(CSS.INPUT_HAS_ERROR); } } textInput.classList.remove(CSS.INPUT_HAS_ERROR); valueInput.classList.remove(CSS.INPUT_HAS_ERROR); return { isValid: true, text: text, value: value }; }
    function _isDuplicateCustomItem(text, itemsToCheck, listId, editingIndex, editingItemInfoRef) { /* ... (same as v0.0.4, with originalText check) ... */
        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 we are editing THIS item, it's not a duplicate of itself *if the text hasn't changed*.
                // If text *has* changed, then we need to check against others.
                if (editingItemInfoRef.originalText?.toLowerCase() === lowerText) {
                    return false; // Text hasn't changed for the item being edited, so it's not a duplicate OF ITSELF
                }
                // If text changed, proceed to check if it matches any OTHER custom item's text
            }
            // For any other item (or if not editing, or if text changed while editing), check if its text matches
            return item.text.toLowerCase() === lowerText;
        });
    }
    function applyThemeToElement(element, themeSetting) { /* ... (same as v0.0.4) ... */ if (!element) return; element.classList.remove( CSS.LIGHT_THEME, CSS.DARK_THEME, 'minimal-theme', 'minimal-light', 'minimal-dark' ); let effectiveTheme = themeSetting; const isSettingsOrModal = element.id === IDS.SETTINGS_WINDOW || element.id === IDS.SETTINGS_OVERLAY || element.classList.contains('settings-modal-content') || element.classList.contains('settings-modal-overlay'); if (isSettingsOrModal) { if (themeSetting === 'minimal-light') effectiveTheme = 'light'; else if (themeSetting === 'minimal-dark') effectiveTheme = 'dark'; } switch (effectiveTheme) { case 'dark': element.classList.add(CSS.DARK_THEME); break; case 'minimal-light': element.classList.add('minimal-theme', 'minimal-light'); break; case 'minimal-dark':  element.classList.add('minimal-theme', 'minimal-dark'); break; case 'system': const systemIsDark = systemThemeMediaQuery && systemThemeMediaQuery.matches; element.classList.add(systemIsDark ? CSS.DARK_THEME : CSS.LIGHT_THEME); break; case 'light': default: element.classList.add(CSS.LIGHT_THEME); break; } }

    // --- END OF PART 1 ---
	
// --- START OF PART 2 (Corrected) ---

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

        // Moved modalConfigsData inside the ModalManager IIFE
        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 },
            '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  },
            '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  },
            '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 },
            '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 },
        };


        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><div id="${IDS.MODAL_PREDEFINED_CHOOSER_CONTAINER}" class="${CSS.MODAL_PREDEFINED_CHOOSER_CLASS}" style="display:none;"></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) { /* ... (same as v0.0.5 attempt part 2) ... */ 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) { /* ... (same as v0.0.5 attempt part 2) ... */ 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) { /* ... (same as v0.0.5 attempt part 2) ... */ 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'); const itemType = listItem.dataset[DATA_ATTR.ITEM_TYPE]; 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) { /* ... (same as v0.0.5 attempt part 2) ... */ const mapping = getListMapping(listId); if (!mapping) return; const itemTypeName = _(mapping.nameKey); const textInput = contextElement.querySelector(mapping.textInput); const valueInput = contextElement.querySelector(mapping.valueInput); const inputGroup = textInput?.closest(`.${CSS.CUSTOM_LIST_INPUT_GROUP}`); if (inputGroup) _clearAllInputErrorsInGroup(inputGroup); const validationResult = _validateAndPrepareCustomItemData(textInput, valueInput, itemTypeName, listId); if (!validationResult.isValid) { if (validationResult.errorField) validationResult.errorField.focus(); return; } const { text, value } = validationResult; const editingIdx = (_editingItemInfo && _editingItemInfo.listId === listId) ? _editingItemInfo.index : -1; let isDuplicate; if (mapping.isSortableMixed) { isDuplicate = _isDuplicateCustomItem(text, itemsArrayRef, listId, editingIdx, _editingItemInfo); } else { isDuplicate = itemsArrayRef.some((item, idx) => { if (editingIdx === idx && (_editingItemInfo?.originalText?.toLowerCase() === text.toLowerCase())) return false; return item.text.toLowerCase() === text.toLowerCase(); }); } if (isDuplicate) { if (textInput) _showInputError(textInput, 'alert_duplicate_name', { name: text }); textInput?.focus(); return; } let newItemData; if (listId === IDS.SITES_LIST) { newItemData = { text: text, url: value }; } else if (mapping.isSortableMixed) { newItemData = { id: value, text: text, value: value, type: 'custom' }; } else { newItemData = { text: text, value: value }; } const itemBeingEdited = (editingIdx > -1) ? itemsArrayRef[editingIdx] : null; const itemBeingEditedIsCustom = itemBeingEdited && (itemBeingEdited.type === 'custom' || listId === IDS.SITES_LIST || listId === IDS.TIME_LIST || listId === IDS.FT_LIST); if (editingIdx > -1 && itemBeingEditedIsCustom) { itemsArrayRef[editingIdx] = {...itemsArrayRef[editingIdx], ...newItemData }; _resetEditStateInternal(contextElement); } else { itemsArrayRef.push(newItemData); } mapping.populateFn(listId, itemsArrayRef, contextElement); if (textInput) { textInput.value = ''; _clearInputError(textInput); textInput.focus(); } if (valueInput) { valueInput.value = ''; _clearInputError(valueInput); } }
        function _getDragAfterModalListItem(container, y) { /* ... (same as v0.0.5 attempt part 2) ... */ 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) { /* ... (same as v0.0.5 attempt part 2) ... */ 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) { /* ... (same as v0.0.5 attempt part 2) ... */ 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) { /* ... (same as v0.0.5 attempt part 2) ... */ 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) { /* ... (same as v0.0.5 attempt part 2) ... */
            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) { /* ... (same as v0.0.5 attempt part 2) ... */ 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 = ''); }

        // --- START: Add predefined options to display list ---
        function _closePredefinedChooser() {
            if (_predefinedChooserContainer) {
                _predefinedChooserContainer.remove();
                _predefinedChooserContainer = null;
            }
        }

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

        function _showPredefinedOptionSelector(manageType, listId, predefinedSourceKey, displayItemsArrayRef, contextElement) {
            _closePredefinedChooser();

            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) : manageType;
                 _showGlobalMessage('alert_no_more_predefined_to_add', { type: itemTypeName }, 'info', 3000, IDS.SETTINGS_MESSAGE_BAR);
                return;
            }

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

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

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

            const addNewBtn = contextElement.querySelector(`#${IDS.MODAL_ADD_NEW_OPTION_BTN}`);
            if (addNewBtn && addNewBtn.parentNode) {
                // Insert after the button, but before the main list if that's how layout is structured
                addNewBtn.insertAdjacentElement('afterend', _predefinedChooserContainer);
                 _predefinedChooserContainer.style.display = 'block';
            } else {
                const mainList = contextElement.querySelector(`#${listId}`);
                mainList?.insertAdjacentElement('beforebegin', _predefinedChooserContainer);
                _predefinedChooserContainer.style.display = 'block';
            }


            _predefinedChooserContainer.querySelector(`#${IDS.MODAL_PREDEFINED_CHOOSER_ADD_BTN}`).addEventListener('click', () => {
                const selectedValues = [];
                _predefinedChooserContainer.querySelectorAll(`#${IDS.MODAL_PREDEFINED_CHOOSER_LIST} input[type="checkbox"]:checked`).forEach(cb => {
                    selectedValues.push(cb.value);
                });
                if (selectedValues.length > 0) {
                    _addSelectedPredefinedItemsToDisplayList(selectedValues, predefinedSourceKey, displayItemsArrayRef, listId, contextElement);
                } else {
                    _closePredefinedChooser();
                }
            });
            _predefinedChooserContainer.querySelector(`#${IDS.MODAL_PREDEFINED_CHOOSER_CANCEL_BTN}`).addEventListener('click', _closePredefinedChooser);
        }
        // --- END: Add predefined options to display list ---


        function _bindModalContentEventsInternal(modalContent, itemsArrayRef, listIdForDragDrop = null) {
            if (!modalContent) return;
            // Simplified: always rebind if called, assuming old listeners are removed by modal recreation or content overwrite.
            // This is safer if modal content is dynamically generated frequently.
            modalContent.dataset.modalEventsBound = 'true'; // Mark as bound

            modalContent.addEventListener('click', (event) => {
                const target = event.target;
                // Determine listId based on what was clicked or context
                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) { // listIdForAction here should be the main list (e.g. LANG_LIST)
                    const mapping = getListMapping(listIdForAction);
                    const configForModal = modalConfigsData[Object.keys(modalConfigsData).find(key => modalConfigsData[key].listId === listIdForAction)];

                    if (mapping && configForModal && configForModal.predefinedSourceKey) {
                         _showPredefinedOptionSelector(configForModal.manageType, listIdForAction, configForModal.predefinedSourceKey, itemsArrayRef, modalContent);
                    } else if (mapping) { // Fallback for "Add new option" on non-predefined lists (e.g. if button was mistakenly shown)
                         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.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) {
                    // To avoid duplicate listeners if _bindModalContentEventsInternal is called multiple times on same modal instance
                    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) { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.4, includes _closePredefinedChooser) ... */
                _closePredefinedChooser();
                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) { /* ... (same as v0.0.4, using modalConfigsData) ... */
                const config = modalConfigsData[manageType];
                if (!config) { console.error("Error: Could not get config for manageType:", manageType); return; }
                const mapping = getListMapping(config.listId);
                if (!mapping) { console.error("Error: Could not get mapping for listId:", config.listId); return; }

                const tempItems = JSON.parse(JSON.stringify(currentSettingsRef[config.itemsArrayKey] || []));
                let contentHTML = '';
                const itemTypeNameForDisplay = _(mapping.nameKey);

                if (config.isSortableMixed) {
                    contentHTML += _createModalListAndInputHTML(config.listId, config.textPKey, config.valPKey, config.hintKey, config.fmtKey, itemTypeNameForDisplay, true);
                } else if (config.predefinedSourceKey && PREDEFINED_OPTIONS[config.predefinedSourceKey]) { // Ensure PREDEFINED_OPTIONS for the key exists
                    const enabledValues = new Set(currentSettingsRef.enabledPredefinedOptions[config.predefinedSourceKey] || []);
                    contentHTML += _createPredefinedOptionsSectionHTML(config.predefinedSourceKey, mapping.nameKey, PREDEFINED_OPTIONS_REF, enabledValues) + '<hr>';
                    contentHTML += _createModalListAndInputHTML(config.listId, config.textPKey, config.valPKey, config.hintKey, config.fmtKey, itemTypeNameForDisplay, false);
                } else { // For Favorite Sites or types without predefined options
                    contentHTML += _createModalListAndInputHTML(config.listId, config.textPKey, config.valPKey, config.hintKey, config.fmtKey, itemTypeNameForDisplay, false);
                }

                const modalContentElement = this.show(config.modalTitleKey, contentHTML, (modalContent) => {
                    let newEnabledPredefined = null;
                    if (config.predefinedSourceKey && !config.isSortableMixed) {
                        newEnabledPredefined = [];
                        modalContent.querySelectorAll(`.predefined-options-list input[data-option-type="${config.predefinedSourceKey}"]:checked`).forEach(cb => newEnabledPredefined.push(cb.value));
                    }
                    onModalCompleteCallback(tempItems, newEnabledPredefined, config.itemsArrayKey, config.predefinedSourceKey, config.customItemsMasterKey, config.isSortableMixed, manageType);
                }, currentSettingsRef.theme);

                if (modalContentElement) {
                    if (mapping && mapping.populateFn) {
                        mapping.populateFn(config.listId, tempItems, modalContentElement);
                    }
                    // Pass itemsArrayRef (tempItems) and listId for drag/drop and other actions
                    _bindModalContentEventsInternal(modalContentElement, tempItems, config.listId);
                }
            },
            resetEditStateGlobally: function() { _resetEditStateInternal(_currentModalContent || document); },
            isModalOpen: function() { return !!_currentModal; }
        };
    })();

    // modalConfigsData should be inside ModalManager IIFE or passed around explicitly
    // For simplicity of this diff, assuming it's defined as in previous (Part 1) in the global scope of this script.
    // const modalConfigsData = { ... }; // Defined in Part 1

    // --- END OF PART 2 ---
	
// --- START OF PART 3 (Corrected) ---

    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 = ()=>{};
        let _draggedSectionOrderItem = null;

        function _createPaneGeneralHTML_internal() { /* ... (same as v0.0.5 attempt part 1) ... */ 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(''); 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></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 _createPaneAppearanceHTML_internal() { /* ... (same as v0.0.5 attempt part 1) ... */ 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 _createPaneFeaturesHTML_internal() { /* ... (same as v0.0.5 attempt part 1) ... */ 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(''); return `<p>${_('settings_visible_sections')}</p>${visItemsHTML}<hr style="margin:1.2em 0;"><p style="font-weight:bold;margin-bottom:0.5em;">${_('settings_section_order')}</p><p 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 _createPaneCustomHTML_internal() { /* ... (same as v0.0.5 attempt part 1) ... */ 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>`;}
        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 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;}});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) { /* ... (same as v0.0.5 attempt part 1) ... */ 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){ /* ... (same as v0.0.5 attempt part 1) ... */ 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(t,s,d){if(typeof t.sidebarPosition!=='object'||t.sidebarPosition===null||Array.isArray(t.sidebarPosition)){t.sidebarPosition=JSON.parse(JSON.stringify(d.sidebarPosition));}t.sidebarPosition.left=parseInt(t.sidebarPosition.left,10)||d.sidebarPosition.left;t.sidebarPosition.top=parseInt(t.sidebarPosition.top,10)||d.sidebarPosition.top;if(typeof t.sectionStates!=='object'||t.sectionStates===null||Array.isArray(t.sectionStates)){t.sectionStates={};}t.sidebarCollapsed=!!t.sidebarCollapsed;t.draggableHandleEnabled=typeof t.draggableHandleEnabled==='boolean'?t.draggableHandleEnabled:d.draggableHandleEnabled;t.interfaceLanguage=typeof s.interfaceLanguage==='string'?s.interfaceLanguage:d.interfaceLanguage;}
        function _validateAndMergeAppearanceSettings_internal(t,s,d){t.sidebarWidth=Utils.clamp(parseInt(t.sidebarWidth,10)||d.sidebarWidth,90,270);t.fontSize=Utils.clamp(parseFloat(t.fontSize)||d.fontSize,8,24);t.headerIconSize=Utils.clamp(parseFloat(t.headerIconSize)||d.headerIconSize,8,32);t.verticalSpacingMultiplier=Utils.clamp(parseFloat(t.verticalSpacingMultiplier)||d.verticalSpacingMultiplier,0.05,1.5);t.idleOpacity=Utils.clamp(parseFloat(t.idleOpacity)||d.idleOpacity,0.1,1.0);t.hoverMode=!!t.hoverMode;const vT=['system','light','dark','minimal-light','minimal-dark'];if(t.theme==='minimal')t.theme='minimal-light';else if(!vT.includes(t.theme))t.theme=d.theme;}
        function _validateAndMergeFeatureSettings_internal(t,s,d){if(typeof t.visibleSections!=='object'||t.visibleSections===null||Array.isArray(t.visibleSections)){t.visibleSections=JSON.parse(JSON.stringify(d.visibleSections));}const vSI=new Set(ALL_SECTION_DEFINITIONS.map(def=>def.id));Object.keys(d.visibleSections).forEach(id=>{if(!vSI.has(id)){console.warn(`${LOG_PREFIX} Invalid section ID in defaultSettings.visibleSections: ${id}`);}else if(typeof t.visibleSections[id]!=='boolean'){t.visibleSections[id]=d.visibleSections[id]??true;}});const vSM=['remember','expandAll','collapseAll'];if(!vSM.includes(t.sectionDisplayMode))t.sectionDisplayMode=d.sectionDisplayMode;t.accordionMode=!!t.accordionMode;const validButtonLocations=['header','topBlock','tools','none'];if(!validButtonLocations.includes(t.resetButtonLocation))t.resetButtonLocation=d.resetButtonLocation;if(!validButtonLocations.includes(t.verbatimButtonLocation))t.verbatimButtonLocation=d.verbatimButtonLocation;if(!validButtonLocations.includes(t.advancedSearchLinkLocation))t.advancedSearchLinkLocation=d.advancedSearchLinkLocation; if (!validButtonLocations.includes(t.personalizationButtonLocation)) { t.personalizationButtonLocation = d.personalizationButtonLocation; } const vCDM=['iconAndText','textOnly','iconOnly'];if(!vCDM.includes(t.countryDisplayMode))t.countryDisplayMode=d.countryDisplayMode;}
        function _validateAndMergeCustomLists_internal(t,s,d){const lK=['favoriteSites','customLanguages','customTimeRanges','customFiletypes','customCountries'];lK.forEach(k=>{t[k]=Array.isArray(t[k])?t[k].filter(i=>i&&typeof i.text==='string'&&typeof i[k==='favoriteSites'?'url':'value']==='string'&&i.text.trim()!==''&&i[k==='favoriteSites'?'url':'value'].trim()!==''):JSON.parse(JSON.stringify(d[k]));});}
        function _validateAndMergePredefinedOptions_internal(t,s,d){ const nonDisplayManagedTypes = ['time', 'filetype']; t.enabledPredefinedOptions = t.enabledPredefinedOptions || {}; nonDisplayManagedTypes.forEach(type => { t.enabledPredefinedOptions[type] = JSON.parse(JSON.stringify(d.enabledPredefinedOptions[type] || [])); const savedTypeOptions = s.enabledPredefinedOptions?.[type]; if (PREDEFINED_OPTIONS[type] && Array.isArray(savedTypeOptions)) { const validValues = new Set(PREDEFINED_OPTIONS[type].map(opt => opt.value)); t.enabledPredefinedOptions[type] = savedTypeOptions.filter(val => typeof val === 'string' && validValues.has(val)); } }); if (t.displayLanguages && t.enabledPredefinedOptions) t.enabledPredefinedOptions.language = []; if (t.displayCountries && t.enabledPredefinedOptions) t.enabledPredefinedOptions.country = []; }
        function _finalizeSectionOrder_internal(t,s,d){const fO=[];const cVOS=new Set();const vSI=new Set(ALL_SECTION_DEFINITIONS.map(def=>def.id));const oS=(Array.isArray(s.sidebarSectionOrder)&&s.sidebarSectionOrder.length>0)?s.sidebarSectionOrder:d.sidebarSectionOrder;oS.forEach(id=>{if(typeof id==='string'&&vSI.has(id)&&t.visibleSections[id]===true&&!cVOS.has(id)){fO.push(id);cVOS.add(id);}});d.sidebarSectionOrder.forEach(id=>{if(typeof id==='string'&&vSI.has(id)&&t.visibleSections[id]===true&&!cVOS.has(id)){fO.push(id);}});t.sidebarSectionOrder=fO;}
        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(!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_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);}}
        function _getDragAfterElement(container, y) { /* ... (same as v0.0.4) ... */ 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 _handleSectionOrderDragStart(event) { /* ... (same as v0.0.4) ... */ _draggedSectionOrderItem = event.target; event.dataTransfer.effectAllowed = 'move'; event.dataTransfer.setData('text/plain', _draggedSectionOrderItem.dataset.sectionId); _draggedSectionOrderItem.classList.add(CSS.DRAGGING_ITEM); const list = _draggedSectionOrderItem.closest('ul'); if (list) { list.querySelectorAll('li:not(.gscs-dragging-item)').forEach(li => li.style.pointerEvents = 'none'); } }
        function _handleSectionOrderDragOver(event) { /* ... (same as v0.0.4) ... */ event.preventDefault(); const listElement = document.getElementById(IDS.SIDEBAR_SECTION_ORDER_LIST); 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 !== _draggedSectionOrderItem) { 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 _handleSectionOrderDragLeave(event) { /* ... (same as v0.0.4) ... */ const relatedTarget = event.relatedTarget; const listElement = document.getElementById(IDS.SIDEBAR_SECTION_ORDER_LIST); if (listElement && (!relatedTarget || !listElement.contains(relatedTarget))) { listElement.querySelectorAll(`li.${CSS.DRAG_OVER_HIGHLIGHT}`).forEach(li => { li.classList.remove(CSS.DRAG_OVER_HIGHLIGHT); }); } }
        function _handleSectionOrderDrop(event) { /* ... (same as v0.0.4) ... */ event.preventDefault(); if (!_draggedSectionOrderItem) return; const draggedSectionId = event.dataTransfer.getData('text/plain'); const listElement = document.getElementById(IDS.SIDEBAR_SECTION_ORDER_LIST); if (!listElement) return; let currentVisibleOrder = _currentSettings.sidebarSectionOrder.filter(id => _currentSettings.visibleSections[id]); const oldIndexInVisible = currentVisibleOrder.indexOf(draggedSectionId); if (oldIndexInVisible > -1) { currentVisibleOrder.splice(oldIndexInVisible, 1); } else { _handleSectionOrderDragEnd(); 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 = _currentSettings.sidebarSectionOrder.filter(id => !_currentSettings.visibleSections[id]); _currentSettings.sidebarSectionOrder = [...currentVisibleOrder, ...hiddenSectionOrder]; _handleSectionOrderDragEnd(); _renderSectionOrderList_ext_cb(_currentSettings); _buildSidebarUI_cb(); }
        function _handleSectionOrderDragEnd() { /* ... (same as v0.0.4) ... */ if (_draggedSectionOrderItem) { _draggedSectionOrderItem.classList.remove(CSS.DRAGGING_ITEM); } _draggedSectionOrderItem = null; const list = document.getElementById(IDS.SIDEBAR_SECTION_ORDER_LIST); if (list) { list.querySelectorAll('li').forEach(li => { li.classList.remove(CSS.DRAG_OVER_HIGHLIGHT); li.style.pointerEvents = ''; }); } }

        const publicApi = {
            initialize: function(dS, applyCb, buildCb, collapseCb, menuCb, renderOrderCb) { /* ... same ... */ if(_isInitialized) return; _defaultSettingsRef=dS; _applySettingsToSidebar_cb=applyCb; _buildSidebarUI_cb=buildCb; _applySectionCollapseStates_cb=collapseCb; _initMenuCommands_cb=menuCb; _renderSectionOrderList_ext_cb=renderOrderCb; this.load(); this.buildSkeleton(); _isInitialized=true; },
            load: function(){ /* ... same ... */ const s=_loadFromStorage();_currentSettings=_validateAndMergeSettings(s);LocalizationService.updateActiveLocale(_currentSettings);},
            save: function(lC='SaveBtn'){ // Corrected save function
                try {
                    // Sync master custom lists (customLanguages, customCountries) with display lists
                    ['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];
                            // Corrected: Use the variable name as intended.
                            const currentDisplayCustomItems = displayItems.filter(item => item.type === 'custom');
                            const currentDisplayCustomItemValues = new Set(currentDisplayCustomItems.map(item => item.value));

                            // Filter master list to only include custom items still present in display list
                            // And update text from display list if changed
                            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;
                                });

                            // Add any new custom items from display list that weren't in masterList previously
                            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${lC ? ` (${lC})` : ''}.`);
                    _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(){ /* ... (same as v0.0.5 attempt part 1, migration is key here) ... */ 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(){ /* ... (same as v0.0.4) ... */ 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(){ /* ... same ... */ return _currentSettings;},
            buildSkeleton: function(){ /* ... (same as v0.0.4) ... */ 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(){ /* ... (same as v0.0.4) ... */ 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 pG=_settingsWindow.querySelector(`#${IDS.TAB_PANE_GENERAL}`);if(pG)pG.innerHTML=_createPaneGeneralHTML_internal();const pA=_settingsWindow.querySelector(`#${IDS.TAB_PANE_APPEARANCE}`);if(pA)pA.innerHTML=_createPaneAppearanceHTML_internal();const pF=_settingsWindow.querySelector(`#${IDS.TAB_PANE_FEATURES}`);if(pF)pF.innerHTML=_createPaneFeaturesHTML_internal();const pC=_settingsWindow.querySelector(`#${IDS.TAB_PANE_CUSTOM}`);if(pC)pC.innerHTML=_createPaneCustomHTML_internal();_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(){ /* ... (same as v0.0.4) ... */ 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(isC=false){ /* ... (same as v0.0.4) ... */ if(!_settingsOverlay)return;ModalManager.resetEditStateGlobally();if(ModalManager.isModalOpen())ModalManager.hide(true);_settingsOverlay.style.display='none';const mB=document.getElementById(IDS.SETTINGS_MESSAGE_BAR);if(mB)mB.style.display='none';if(isC&&_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(isC){console.warn(`${LOG_PREFIX} SM: Cancelled, no backup.`);}},
            bindEvents: function(){ /* ... (same as v0.0.5 attempt part 2, onModalCompleteCallback updated) ... */
                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 tC=_settingsWindow.querySelector(`.${CSS.SETTINGS_TABS}`);
                if(tC){tC.addEventListener('click',e=>{const tg=e.target.closest(`.${CSS.TAB_BUTTON}`);if(tg&&!tg.classList.contains(CSS.ACTIVE)){ModalManager.resetEditStateGlobally();const tT=tg.dataset[DATA_ATTR.TAB];if(!tT)return;tC.querySelectorAll(`.${CSS.TAB_BUTTON}`).forEach(b=>b.classList.remove(CSS.ACTIVE));tg.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}="${tT}"]`)?.classList.add(CSS.ACTIVE);}});}_settingsWindow.dataset.eventsBound='true';
                const cTP=_settingsWindow.querySelector(`#${IDS.TAB_PANE_CUSTOM}`);
                if(cTP){
                    cTP.addEventListener('click',(e)=>{
                        const b=e.target.closest(`button.${CSS.MANAGE_CUSTOM_BUTTON}`);
                        if(b){
                            const mT=b.dataset[DATA_ATTR.MANAGE_TYPE];
                            if(mT){
                                ModalManager.openManageCustomOptions(
                                    mT, _currentSettings, PREDEFINED_OPTIONS,
                                    (updatedItemsArray, newEnabledPredefs, itemsArrayKey, predefinedOptKey, customItemsMasterKey, isSortableMixed, manageTypeFromCallback) => {
                                        if (itemsArrayKey) {
                                            _currentSettings[itemsArrayKey] = updatedItemsArray;
                                        }
                                        if (predefinedOptKey && newEnabledPredefs && !isSortableMixed) {
                                            if (!_currentSettings.enabledPredefinedOptions) _currentSettings.enabledPredefinedOptions = {};
                                            _currentSettings.enabledPredefinedOptions[predefinedOptKey] = newEnabledPredefs;
                                        }
                                        // Syncing of display* and custom* master lists now happens in SettingsManager.save()
                                        _buildSidebarUI_cb();
                                        this.populateWindow();
                                    }
                                );
                            }
                        }
                    });
                }
            },
            bindLiveUpdateEvents: function(){ /* ... (same as v0.0.4) ... */ 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() { /* ... (same as v0.0.4) ... */ 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 orderListElement = featuresPane.querySelector(`#${IDS.SIDEBAR_SECTION_ORDER_LIST}`); if (orderListElement) { if (orderListElement.dataset.dragEventsBound !== 'true') { orderListElement.addEventListener('dragstart', _handleSectionOrderDragStart); orderListElement.addEventListener('dragover', _handleSectionOrderDragOver); orderListElement.addEventListener('dragleave', _handleSectionOrderDragLeave); orderListElement.addEventListener('drop', _handleSectionOrderDrop); orderListElement.addEventListener('dragend', _handleSectionOrderDragEnd); orderListElement.dataset.dragEventsBound = 'true'; } } },
            _handleVisibleSectionChange: function(e){ /* ... (same as v0.0.4) ... */ 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() { /* ... (same as v0.0.4) ... */ 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() { /* ... (same as v0.0.4) ... */
        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(); const cQ = q.replace(/\s*site:[\w.-]+\s*/g, ' ').trim(); if (cQ) { nP.set('q', cQ); } u.search = nP.toString(); _navigateTo(u); } catch (e) { NotificationManager.show('alert_error_resetting_filters', {}, 'error', 5000); }},
            triggerToggleVerbatim: function() { try { const u = _getURLObject(); if (!u) return; let tP = _getTbsParts(u); const vP = 'li:1'; const iCA = tP.includes(vP); tP = tP.filter(p => p !== vP); if (!iCA) { tP.push(vP); } _setTbsParam(u, tP); _navigateTo(u); } catch (e) { NotificationManager.show('alert_error_toggling_verbatim', {}, 'error', 5000); }},
            isPersonalizationActive: function() { try { const currentUrl = _getURLObject(); if (!currentUrl) { return true; } return currentUrl.searchParams.get('pws') !== '0'; } catch (e) { console.warn(`${LOG_PREFIX} [URLActionManager.isPersonalizationActive] Error checking personalization status:`, e); return true; } },
            triggerTogglePersonalization: function() { try { const u = _getURLObject(); if (!u) { return; } const personalizationCurrentlyActive = URLActionManager.isPersonalizationActive(); if (personalizationCurrentlyActive) { _setSearchParam(u, 'pws', '0'); } else { _deleteSearchParam(u, 'pws'); } _navigateTo(u); } catch (e) { NotificationManager.show('alert_error_toggling_personalization', {}, 'error', 5000); console.error(`${LOG_PREFIX} [URLActionManager.triggerTogglePersonalization] Error:`, e); } },
            applyFilter: function(type, value) { try { const u = _getURLObject(); if (!u) return; let tP = _getTbsParts(u); let pTP; const isTimeFilter = ['qdr'].includes(type); const isStandaloneParam = ['lr', 'cr'].includes(type); const isFileType = type === 'filetype'; if (isTimeFilter) { pTP = tP.filter(p => !p.startsWith(`${type}:`) && !p.startsWith('cdr:') && !p.startsWith('cd_min:') && !p.startsWith('cd_max:')); if (value !== '') pTP.push(`${type}:${value}`); } else if (isFileType) { _deleteSearchParam(u, 'as_filetype'); _deleteSearchParam(u, 'filetype'); pTP = tP.filter(p => !p.startsWith('ft:') && !p.startsWith('aft:')); if (value !== '') _setSearchParam(u, 'as_filetype', value); } else if (isStandaloneParam) { _deleteSearchParam(u, type); if (value !== '') _setSearchParam(u, type, value); pTP = tP; } else { pTP = tP; } _setTbsParam(u, pTP); _navigateTo(u); } catch (e) { NotificationManager.show('alert_error_applying_filter', { type: type, value: value }, 'error', 5000); }},
            applySiteSearch: function(siteUrl) { if (!siteUrl) return; try { const u = _getURLObject(); if (!u) return; const q = u.searchParams.get('q') || ''; const qNS = q.replace(/\s*site:[\w.-]+\s*/g, ' ').trim(); const nQ = `${qNS} site:${siteUrl}`.trim(); _setSearchParam(u, 'q', nQ); _deleteSearchParam(u, 'tbs'); _deleteSearchParam(u, 'lr'); _deleteSearchParam(u, 'cr'); _deleteSearchParam(u, 'as_filetype'); _deleteSearchParam(u, 'filetype'); _navigateTo(u); } catch (e) { NotificationManager.show('alert_error_applying_site_search', { site: siteUrl }, 'error', 5000); }},
            clearSiteSearch: function() { try { const u = _getURLObject(); if (!u) return; const q = u.searchParams.get('q') || ''; const nQ = q.replace(/\s*site:[\w.-]+\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); }},
            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() { /* ... (same as v0.0.4) ... */ 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() { /* ... (same as v0.0.4) ... */ 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 = (event) => { const cs = SettingsManager.getCurrentSettings(); if (sidebar && cs.theme === 'system') { applyThemeToElement(sidebar, 'system'); } }; systemThemeMediaQuery.addEventListener('change', listener); systemThemeMediaQuery._sidebarThemeListener = listener; } }
    function buildSidebarSkeleton() { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.5 attempt part 1) ... */
        const finalOptions = [];
        const tempAddedValues = new Set();
        const sectionDef = ALL_SECTION_DEFINITIONS.find(s => s.id === sectionId);
        if (!sectionDef) return [];

        const isSortableMixedType = sectionDef.displayItemsKey && Array.isArray(currentSettings[sectionDef.displayItemsKey]);

        scriptDefinedOptions.forEach(opt => {
            if (opt && typeof opt.textKey === 'string' && typeof opt.v === 'string' && opt.v === '') {
                const translatedText = _(opt.textKey);
                finalOptions.push({ text: translatedText, value: opt.v, originalText: translatedText });
                tempAddedValues.add(opt.v);
            }
        });

        if (isSortableMixedType) {
            const displayItems = currentSettings[sectionDef.displayItemsKey] || [];
            displayItems.forEach(item => {
                if (!tempAddedValues.has(item.value)) {
                    let displayText = item.text;
                    if (item.type === 'predefined' && item.originalKey) {
                        displayText = _(item.originalKey);
                         if (sectionId === IDS.COUNTRIES_LIST) {
                            const parsed = Utils.parseIconAndText(displayText);
                            displayText = `${parsed.icon} ${parsed.text}`.trim();
                        }
                    }
                    finalOptions.push({ text: displayText, value: item.value, originalText: displayText, isCustom: item.type === 'custom' });
                    tempAddedValues.add(item.value);
                }
            });
        } else {
            const predefinedKey = sectionDef.predefinedOptionsKey;
            const customKey = sectionDef.customItemsKey;
            const predefinedOptsFromSource = predefinedOptionsSource[predefinedKey] || [];
            const customOptsFromSettings = currentSettings[customKey] || [];
            const enabledPredefinedVals = currentSettings.enabledPredefinedOptions[predefinedKey] || [];
            const combinedForSorting = [];
            const enabledSet = new Set(enabledPredefinedVals);

            if (Array.isArray(predefinedOptsFromSource)) {
                predefinedOptsFromSource.forEach(opt => {
                    if (opt && typeof opt.textKey === 'string' && typeof opt.value === 'string' && enabledSet.has(opt.value) && !tempAddedValues.has(opt.value)) {
                        const translatedText = _(opt.textKey);
                        combinedForSorting.push({ text: translatedText, value: opt.value, originalText: translatedText, isCustom: false });
                    }
                });
            }
            const validCustomOptions = Array.isArray(customOptsFromSettings) ? customOptsFromSettings.filter(cOpt => cOpt && typeof cOpt.text === 'string' && typeof cOpt.value === 'string') : [];
            validCustomOptions.forEach(opt => {
                if (!tempAddedValues.has(opt.value)) {
                     combinedForSorting.push({ text: opt.text, value: opt.value, originalText: opt.text, isCustom: true });
                }
            });

            const isTimeSection = (sectionId === 'sidebar-section-time');
            combinedForSorting.sort((a, b) => {
                if (isTimeSection) { const timeA = _parseTimeValueToMinutes(a.value); const timeB = _parseTimeValueToMinutes(b.value); if (timeA !== timeB) return timeA - timeB; }
                const sTA = a.originalText || a.text; const sTB = b.originalText || b.text;
                const sL = LocalizationService.getCurrentLocale() === 'en' ? undefined : LocalizationService.getCurrentLocale();
                return sTA.localeCompare(sTB, sL, { numeric: true, sensitivity: 'base' });
            });
            combinedForSorting.forEach(opt => { if (!tempAddedValues.has(opt.value)){ finalOptions.push(opt); tempAddedValues.add(opt.value); }});
        }
        scriptDefinedOptions.forEach(opt => { if (opt && typeof opt.textKey === 'string' && typeof opt.v === 'string' && opt.v !== '' && !tempAddedValues.has(opt.v)) { const translatedText = _(opt.textKey); finalOptions.push({ text: translatedText, value: opt.v, originalText: translatedText }); tempAddedValues.add(opt.v); } });
        return finalOptions;
    }
    function _createFilterOptionElement(optionData, filterParam, isCountrySection, countryDisplayMode) { /* ... (same as v0.0.4) ... */ 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() { /* ... (same as v0.0.4) ... */ 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 sBR = header.querySelector(`#${IDS.SETTINGS_BUTTON}`); _buildSidebarHeaderControls(header, sBR, rBL, vBL, aSL, pznBL, _createAdvancedSearchElementHTML, _createPersonalizationButtonHTML, currentSettings); const fTC = _buildSidebarFixedTopControls(rBL, vBL, aSL, pznBL, _createAdvancedSearchElementHTML, _createPersonalizationButtonHTML, currentSettings); if (fTC) header.after(fTC); const cW = document.createElement('div'); cW.classList.add(CSS.SIDEBAR_CONTENT_WRAPPER); const sDM = new Map(ALL_SECTION_DEFINITIONS.map(def => [def.id, def])); const sF = _buildSidebarSections(sDM, rBL, vBL, aSL, pznBL, _createAdvancedSearchElementHTML, _createPersonalizationButtonHTML, currentSettings, PREDEFINED_OPTIONS); cW.appendChild(sF); sidebar.appendChild(cW); _initializeSidebarEventListenersAndStates(); }
    function _buildSidebarSections(sectionDefinitionMap, rBL, vBL, aSL, pznBL, createAdvancedSearchElementFn, createPersonalizationButtonFn, currentSettings, PREDEFINED_OPTIONS_REF) { /* ... (same as v0.0.4) ... */ const contentFragment = document.createDocumentFragment(); currentSettings.sidebarSectionOrder.forEach(sectionId => { if (!currentSettings.visibleSections[sectionId]) return; const sectionData = sectionDefinitionMap.get(sectionId); if (!sectionData) { console.warn(`${LOG_PREFIX} No definition for section ID: ${sectionId}`); return; } let sectionElement = null; const sectionTitleKey = sectionData.titleKey; const sectionIdForDisplay = sectionData.id; switch (sectionData.type) { case 'filter': sectionElement = createFilterSection(sectionIdForDisplay, sectionTitleKey, sectionData.scriptDefined, sectionData.param, currentSettings, PREDEFINED_OPTIONS_REF, currentSettings.countryDisplayMode); break; case 'date': sectionElement = _createDateSectionElement(sectionIdForDisplay, sectionTitleKey); break; case 'site': sectionElement = _createSiteSearchSectionElement(sectionIdForDisplay, sectionTitleKey, currentSettings.favoriteSites); 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) { /* ... (same as v0.0.4) ... */ 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); const oldListener = sectionContent._filterClickListener; if (oldListener) sectionContent.removeEventListener('click', oldListener); const newListener = 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 === '') { const anyOpt = this.querySelector(`.${CSS.FILTER_OPTION}[data-${DATA_ATTR.FILTER_VALUE}=""]`); if (anyOpt) anyOpt.classList.add(CSS.SELECTED); } URLActionManager.applyFilter(clickedFilterType, clickedFilterValue); } } }; sectionContent.addEventListener('click', newListener); sectionContent._filterClickListener = newListener; return section; }
    function _createSiteSearchSectionElement(sectionId, titleKey, favoriteSites) { /* ... (same as v0.0.4) ... */ const { section, sectionContent, sectionTitle } = _createSectionShell(sectionId, titleKey); sectionTitle.textContent = _(titleKey); const list = document.createElement('ul'); list.classList.add(CSS.CUSTOM_LIST); sectionContent.appendChild(list); populateSiteSearchList(list, favoriteSites); return section; }
    function populateSiteSearchList(listElement, favoriteSitesArray) { /* ... (same as v0.0.4) ... */ if (!listElement) { console.error("Site search list element missing in populateSiteSearchList"); return; } listElement.innerHTML = ''; const sites = Array.isArray(favoriteSitesArray) ? favoriteSitesArray : []; const fragment = document.createDocumentFragment(); sites.forEach((site, index) => { if (site?.text && site?.url) { const li = document.createElement('li'); const opt = document.createElement('div'); opt.classList.add(CSS.FILTER_OPTION); opt.dataset[DATA_ATTR.SITE_URL] = site.url; opt.title = _('tooltip_site_search', { siteUrl: site.url }); opt.textContent = site.text; li.appendChild(opt); fragment.appendChild(li); }}); const clearLi = document.createElement('li'); const clearOpt = document.createElement('div'); clearOpt.classList.add(CSS.FILTER_OPTION); clearOpt.id = 'clear-site-search-option'; clearOpt.title = _('tooltip_clear_site_search'); clearOpt.textContent = _('filter_clear_site_search'); clearLi.appendChild(clearOpt); fragment.appendChild(clearLi); listElement.appendChild(fragment); if (!listElement.dataset[DATA_ATTR.LISTENER_ATTACHED]) { listElement.dataset[DATA_ATTR.LISTENER_ATTACHED] = 'true'; listElement.addEventListener('click', (event) => { const target = event.target.closest(`.${CSS.FILTER_OPTION}`); if (target) { listElement.querySelectorAll(`.${CSS.FILTER_OPTION}.${CSS.SELECTED}`).forEach(opt => opt.classList.remove(CSS.SELECTED)); if (target.id === 'clear-site-search-option') { URLActionManager.clearSiteSearch(); } else { const siteUrl = target.dataset[DATA_ATTR.SITE_URL]; if (siteUrl) { URLActionManager.applySiteSearch(siteUrl); target.classList.add(CSS.SELECTED); } } } }); } }
    function renderSectionOrderList(settingsRef) { /* ... (same as v0.0.4) ... */ 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() { /* ... (same as v0.0.4) ... */ 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); GM_unregisterMenuCommand(resetAllText); } catch (e) {} } GM_registerMenuCommand(openSettingsText, SettingsManager.show.bind(SettingsManager)); GM_registerMenuCommand(resetAllText, SettingsManager.resetAllFromMenu.bind(SettingsManager)); } }
    function _createSectionShell(id, titleKey) { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.4) ... */ 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 }) { /* ... (same as v0.0.4) ... */ 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]) { const wrappedClickHandler = function(event) { clickHandler(event); }; button.addEventListener('click', wrappedClickHandler); button.dataset[DATA_ATTR.LISTENER_ATTACHED] = 'true'; } } return button; }
    function _createPersonalizationButtonHTML(forLocation = 'tools') { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.4) ... */ 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) { const queryWithoutSite = currentQuery.replace(/\s*site:[\w.-]+\s*/gi, ' ').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) { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.4) ... */ _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() { /* ... (same as v0.0.4) ... */ 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() { /* ... (same as v0.0.4) ... */ addDateRangeListener(); addToolButtonListeners(); initializeSelectedFilters(); applySectionCollapseStates(); }
    function _clearElementMessage(element, visibleClass = CSS.ERROR_VISIBLE) { /* ... (same as v0.0.4) ... */ if(!element)return; element.textContent=''; element.classList.remove(visibleClass);}
    function _showElementMessage(element, messageKey, messageArgs = {}, visibleClass = CSS.ERROR_VISIBLE) { /* ... (same as v0.0.4) ... */ if(!element)return; element.textContent=_(messageKey,messageArgs); element.classList.add(visibleClass);}
    function addToolButtonListeners() { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.4) ... */ if(!sidebar)return;const cB=sidebar.querySelector(`#${IDS.COLLAPSE_BUTTON}`);if(isCollapsed){sidebar.classList.add(CSS.SIDEBAR_COLLAPSED);if(cB){cB.innerHTML=SVG_ICONS.chevronRight;cB.title=_('sidebar_expand_title');}}else{sidebar.classList.remove(CSS.SIDEBAR_COLLAPSED);if(cB){cB.innerHTML=SVG_ICONS.chevronLeft;cB.title=_('sidebar_collapse_title');}}}
    function applySectionCollapseStates() { /* ... (same as v0.0.4) ... */ 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() { /* ... (same as v0.0.4) ... */ if (!sidebar) return; try { const u = URLActionManager._getURLObject ? URLActionManager._getURLObject() : Utils.getCurrentURL(); if (!u) return; const p = u.searchParams; const cT = p.get('tbs') || ''; const cQ = p.get('q') || ''; _initializeStandaloneFilterState(p, 'language', 'lr'); _initializeStandaloneFilterState(p, 'country', 'cr'); _initializeStandaloneFilterState(p, 'filetype', 'as_filetype'); _initializeTimeFilterState(cT); _initializeVerbatimState(); _initializePersonalizationState(); _initializeDateRangeInputs(cT); _initializeSiteSearchState(cQ); } catch (e) { console.error(`${LOG_PREFIX} Error initializing filter highlights:`, e); } }
    function _initializeStandaloneFilterState(p,fT,pTC){ /* ... (same as v0.0.4) ... */ const sI=`sidebar-section-${fT}`;const s=sidebar?.querySelector(`#${sI}`);if(!s){return;}const uV=p.get(pTC);const o=s.querySelectorAll(`.${CSS.FILTER_OPTION}`);o.forEach(opt=>{const oV=opt.dataset[DATA_ATTR.FILTER_VALUE];opt.classList.toggle(CSS.SELECTED,(uV!==null&&uV===oV)||(uV===null&&oV===''));});}
    function _initializeTimeFilterState(cT){ /* ... (same as v0.0.4) ... */ const tS=sidebar?.querySelector('#sidebar-section-time');if(!tS)return;const qM=cT.match(/qdr:([^,]+)/);const aQV=qM?qM[1]:null;const hDR=/cdr:1/.test(cT);const tO=tS.querySelectorAll(`.${CSS.FILTER_OPTION}`);tO.forEach(o=>{const oV=o.dataset[DATA_ATTR.FILTER_VALUE];let sS=false;if(hDR){sS=(oV==='');}else if(aQV){sS=(oV===aQV);}else{sS=(oV==='');}o.classList.toggle(CSS.SELECTED,sS);});}
    function _initializeVerbatimState(){ /* ... (same as v0.0.4) ... */ const iVA = URLActionManager.isVerbatimActive(); sidebar?.querySelectorAll(`#${IDS.TOOL_VERBATIM}`).forEach(b=>b.classList.toggle(CSS.ACTIVE, iVA));}
    function _initializePersonalizationState() { /* ... (same as v0.0.4) ... */ 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(cT){ /* ... (same as v0.0.4) ... */ const dS = sidebar?.querySelector('#sidebar-section-date-range'); if (!dS) return; const dMI = dS.querySelector(`#${IDS.DATE_MIN}`); const dMXI = dS.querySelector(`#${IDS.DATE_MAX}`); const eME = dS.querySelector(`#${IDS.DATE_RANGE_ERROR_MSG}`); const applyButton = dS.querySelector('.apply-date-range'); if (eME) _clearElementMessage(eME, CSS.ERROR_VISIBLE); if (/cdr:1/.test(cT)) { const mIM = cT.match(/cd_min:(\d{1,2})\/(\d{1,2})\/(\d{4})/); const mAM = cT.match(/cd_max:(\d{1,2})\/(\d{1,2})\/(\d{4})/); if (dMI) dMI.value = mIM ? `${mIM[3]}-${mIM[1].padStart(2, '0')}-${mIM[2].padStart(2, '0')}` : ''; if (dMXI) dMXI.value = mAM ? `${mAM[3]}-${mAM[1].padStart(2, '0')}-${mAM[2].padStart(2, '0')}` : ''; } else { if (dMI) dMI.value = ''; if (dMXI) dMXI.value = ''; } if (dMI && dMXI && eME && applyButton) { const isValid = _validateDateInputs(dMI, dMXI, eME); applyButton.disabled = !isValid; } }
    function _initializeSiteSearchState(cQ){ /* ... (same as v0.0.4) ... */ const sS=sidebar?.querySelector('#sidebar-section-site-search');if(!sS)return;const sM=cQ.match(/site:([\w.-]+)/);const aSU=sM?sM[1]:null;const sO=sS.querySelectorAll(`.${CSS.FILTER_OPTION}[data-${DATA_ATTR.SITE_URL}]`);sO.forEach(o=>{o.classList.toggle(CSS.SELECTED,aSU&&o.dataset[DATA_ATTR.SITE_URL]===aSU);});const cO=sS.querySelector('#clear-site-search-option');if(cO){cO.classList.toggle(CSS.SELECTED,!aSU);}}
    function bindSidebarEvents() { /* ... (same as v0.0.4) ... */ 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() { /* ... (same as v0.0.4) ... */ const cs = SettingsManager.getCurrentSettings(); cs.sidebarCollapsed = !cs.sidebarCollapsed; applySettings(cs); SettingsManager.save('Sidebar Collapse');}
    function handleSectionCollapse(event) { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.4) ... */ 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) { /* ... (same as v0.0.4) ... */ 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; }

    // --- Main Initialization ---
    function initializeScript() { /* ... (same as v0.0.4) ... */ 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(); } }

    // --- Script Entry Point ---
    if (document.getElementById(IDS.SIDEBAR)) { console.warn(`${LOG_PREFIX} Sidebar with ID "${IDS.SIDEBAR}" already exists. Skipping initialization.`); return; }
    if (typeof window.GSCS_Namespace === 'undefined' || typeof window.GSCS_Namespace.stylesText !== 'string') { console.warn(`${LOG_PREFIX} Styles provider not yet available. Delaying initialization.`); let attempts = 0; const maxAttempts = 20; const interval = 100; const checkStylesInterval = setInterval(() => { attempts++; if (typeof window.GSCS_Namespace !== 'undefined' && typeof window.GSCS_Namespace.stylesText === 'string') { clearInterval(checkStylesInterval); if (document.readyState === 'complete' || document.readyState === 'interactive' || document.readyState === 'loaded') { initializeScript(); } else { window.addEventListener('DOMContentLoaded', initializeScript, { once: true }); } } else if (attempts >= maxAttempts) { clearInterval(checkStylesInterval); console.error(`${LOG_PREFIX} Styles provider failed to load. Initializing without external styles.`); if (document.readyState === 'complete' || document.readyState === 'interactive' || document.readyState === 'loaded') { initializeScript(); } else { window.addEventListener('DOMContentLoaded', initializeScript, { once: true }); } } }, interval);
    } else { if (document.readyState === 'complete' || document.readyState === 'interactive' || document.readyState === 'loaded') { initializeScript(); } else { window.addEventListener('DOMContentLoaded', initializeScript, { once: true }); } }

})();
    // --- END OF PART 3 ---