Black Russia Helper

[v6.2] UI Оптимизация. Глобальные стили (Шрифт, B/I/U). Больше BBCode. Авто-ник/дата, Категории, сортировка, счетчик, выбор формата даты. Опция авто-отправки. Темный UI. Кнопка помощи.

// ==UserScript==
// @name         Black Russia  Helper
// @namespace    http://tampermonkey.net/
// @version      6.2
// @description  [v6.2] UI Оптимизация. Глобальные стили (Шрифт, B/I/U). Больше BBCode. Авто-ник/дата, Категории, сортировка, счетчик, выбор формата даты. Опция авто-отправки. Темный UI. Кнопка помощи.
// @author       Maras Rofls
// @match        *://forum.blackrussia.online/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @run-at       document-idle
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const CURRENT_VERSION = '6.2';
    const DATA_KEY = `blackrussia_signatures_helper_v${CURRENT_VERSION}`;
    const PREVIOUS_DATA_KEY = 'blackrussia_signatures_helper_v6.1';
    const DEFAULT_SEPARATOR = '\n\n---\n';
    const DEFAULT_DATETIME_PRESET = 'DD.MM.YYYY HH:mm';
    const MAX_EDITOR_FIND_ATTEMPTS = 20;
    const EDITOR_FIND_INTERVAL = 500; // ms
    const AUTO_SEND_DELAY = 350; // ms

    const DATETIME_PRESETS = {
        'DD.MM.YYYY HH:mm': { dateStyle: 'short', timeStyle: 'short', hour12: false },
        'DD.MM.YY HH:mm': { year: '2-digit', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hour12: false },
        'D MMMMற்றுப்ரம் г., HH:mm': { dateStyle: 'long', timeStyle: 'short', hour12: false },
        'YYYY-MM-DD HH:mm': { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hour12: false, hourCycle: 'h23' },
        'HH:mm DD.MM.YYYY': { timeStyle: 'short', dateStyle: 'short', hour12: false },
    };

     const FONT_LIST = ['По умолчанию', 'Arial', 'Verdana', 'Tahoma', 'Trebuchet MS', 'Times New Roman', 'Georgia', 'Courier New', 'Comic Sans MS', 'Impact'];

    const defaultData = {
        signatures: [],
        settings: {
            separator: DEFAULT_SEPARATOR,
            dateTimePreset: DEFAULT_DATETIME_PRESET,
            autoSendAfterInsert: false,
            lastSelectedSignatureIndex: -1,
        }
    };

    let appData = JSON.parse(JSON.stringify(defaultData));
    let editorElement = null;
    let mainUiContainer = null;
    let selectSignatureElement = null;
    let insertSignatureButton = null;
    let randomSignatureButton = null;
    let currentUsername = null;

    let modalElement = null;
    let modalListElement = null;
    let modalCategoryFilter = null;
    let modalSortSelect = null;
    let modalFormElement = null;
    let modalNameInput = null;
    let modalContentInput = null;
    let modalCategoryInput = null;
    let modalSaveButton = null;
    let modalSaveAndNewButton = null;
    let modalCancelButton = null;
    let modalSettingsSeparatorInput = null;
    let modalSettingsDateTimeSelect = null;
    let modalSettingsAutoSendCheckbox = null;
    let editingIndex = null;

    let currentSortType = 'name_asc';
    let currentFilterCategory = 'all';

    function loadData() {
        const storedData = GM_getValue(DATA_KEY, null);
        if (storedData) {
            try {
                const parsedData = JSON.parse(storedData);
                const mergedSettings = { ...defaultData.settings, ...(parsedData.settings || {}) };
                appData.signatures = Array.isArray(parsedData.signatures) ? parsedData.signatures : defaultData.signatures;
                appData.settings = mergedSettings;
                 appData.signatures = appData.signatures.filter(isValidSignature).map(migrateSignatureData);
                 if (!DATETIME_PRESETS[appData.settings.dateTimePreset]) {
                     appData.settings.dateTimePreset = DEFAULT_DATETIME_PRESET;
                 }
            } catch (e) {
                console.error(`Signature Helper: Ошибка парсинга данных v${CURRENT_VERSION}. Используются стандартные.`, e);
                appData = JSON.parse(JSON.stringify(defaultData));
                alert(`Не удалось загрузить сохраненные данные Помощника Подписей v${CURRENT_VERSION}. Используются настройки по умолчанию.`);
            }
        } else {
            const previousData = GM_getValue(PREVIOUS_DATA_KEY, null);
            if (previousData) {
                console.log(`Signature Helper: Миграция данных из ${PREVIOUS_DATA_KEY}...`);
                try {
                    const parsedPreviousData = JSON.parse(previousData);
                     const migratedSettings = { ...defaultData.settings, ...(parsedPreviousData.settings || {}) };
                     appData.signatures = Array.isArray(parsedPreviousData.signatures) ? parsedPreviousData.signatures : defaultData.signatures;
                     appData.settings = migratedSettings;
                     appData.signatures = appData.signatures.filter(isValidSignature).map(migrateSignatureData);
                     if (!DATETIME_PRESETS[appData.settings.dateTimePreset]) {
                         appData.settings.dateTimePreset = DEFAULT_DATETIME_PRESET;
                     }
                    console.log(`Signature Helper: Данные ${PREVIOUS_DATA_KEY} успешно перенесены в v${CURRENT_VERSION}.`);
                    saveData();
                } catch (e) {
                    console.error(`Signature Helper: Ошибка миграции данных из ${PREVIOUS_DATA_KEY}. Используются стандартные.`, e);
                    appData = JSON.parse(JSON.stringify(defaultData));
                }
            } else {
                console.log('Signature Helper: Сохраненные данные не найдены, используются стандартные.');
                appData = JSON.parse(JSON.stringify(defaultData));
            }
        }
         appData.signatures = appData.signatures.filter(isValidSignature).map(migrateSignatureData);
    }

    function migrateSignatureData(signature) {
        return {
            name: signature.name || 'Без имени',
            content: signature.content || '',
            usageCount: signature.usageCount || 0,
            category: signature.category || '',
            dateAdded: signature.dateAdded || Date.now(),
            lastUsed: signature.lastUsed || null,
        };
    }

    function saveData() {
        try {
            const dataToSave = {
                signatures: appData.signatures,
                settings: appData.settings
            };
            GM_setValue(DATA_KEY, JSON.stringify(dataToSave));
        } catch (e) {
            console.error('Signature Helper: Ошибка сохранения данных.', e);
            alert('Ошибка сохранения данных Помощника Подписей!');
        }
        updateMainUIState();
        populateSignatureSelect();
    }

    function isValidSignature(item) {
        return typeof item === 'object' && item !== null && typeof item.name === 'string' && typeof item.content === 'string';
    }

    function getUsername() {
        if (currentUsername === null) {
            const userLink = document.querySelector('.p-navgroup-link--user .p-navgroup-linkText');
            if (userLink) currentUsername = userLink.textContent.trim();
            else {
                const avatar = document.querySelector('.p-navgroup-link--user .avatar');
                if (avatar) currentUsername = avatar.getAttribute('alt')?.trim() || '';
            }
            if (!currentUsername) currentUsername = 'Пользователь';
        }
        return currentUsername;
    }

    function getCurrentDateTime(formatPreset = null) {
        const presetKey = formatPreset || appData.settings.dateTimePreset;
        const options = DATETIME_PRESETS[presetKey] || DATETIME_PRESETS[DEFAULT_DATETIME_PRESET];
        const now = new Date();
        let formattedString = '';
        try {
            // Try formatting using Intl first (more reliable for different presets)
            if (presetKey === 'YYYY-MM-DD HH:mm') {
                 // Intl doesn't easily support this exact format with space separator AND 24h cycle consistently
                 const year = now.getFullYear();
                 const month = (now.getMonth() + 1).toString().padStart(2, '0');
                 const day = now.getDate().toString().padStart(2, '0');
                 const hours = now.getHours().toString().padStart(2, '0');
                 const minutes = now.getMinutes().toString().padStart(2, '0');
                 formattedString = `${year}-${month}-${day} ${hours}:${minutes}`;
            } else if (presetKey === 'HH:mm DD.MM.YYYY') {
                 const timeFormatter = new Intl.DateTimeFormat('ru-RU', { hour: '2-digit', minute: '2-digit', hour12: false });
                 const dateFormatter = new Intl.DateTimeFormat('ru-RU', { day: '2-digit', month: '2-digit', year: 'numeric' });
                 formattedString = `${timeFormatter.format(now)} ${dateFormatter.format(now)}`;
            } else {
                // Use Intl for other standard formats
                const formatter = new Intl.DateTimeFormat('ru-RU', options);
                formattedString = formatter.format(now);
            }
        } catch (e) {
            console.error(`Signature Helper: Ошибка форматирования даты для пресета ${presetKey}`, e);
            // Fallback to manual formatting if Intl fails
            const d = now;
            formattedString = `${d.getDate().toString().padStart(2, '0')}.${(d.getMonth() + 1).toString().padStart(2, '0')}.${d.getFullYear()} ${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}`;
        }
        return formattedString;
    }


     function addSignature(name, content, category) {
        if (!name?.trim() || !content) {
            alert('Название и содержание подписи не могут быть пустыми.');
            return false;
        }
        const newSignature = migrateSignatureData({
             name: name.trim(),
             content: content,
             category: category?.trim() || '',
         });
        appData.signatures.push(newSignature);
        return true;
    }

    function updateSignature(index, name, content, category) {
        if (index < 0 || index >= appData.signatures.length) return false;
        if (!name?.trim() || !content) {
            alert('Название и содержание подписи не могут быть пустыми.');
            return false;
        }
        const oldSignature = appData.signatures[index];
        appData.signatures[index] = {
            ...oldSignature,
            name: name.trim(),
            content: content,
            category: category?.trim() || '',
        };
        return true;
    }

    function deleteSignature(index) {
        if (index < 0 || index >= appData.signatures.length) return;
        setTimeout(() => {
            const sigName = appData.signatures[index]?.name || 'Без имени';
            if (confirm(`Вы уверены, что хотите удалить подпись "${sigName}"?`)) {
                appData.signatures.splice(index, 1);
                saveData();
                renderModalList();
                populateSignatureSelect();
            }
        }, 0);
    }

     function duplicateSignature(index) {
        if (index < 0 || index >= appData.signatures.length) return;
        const originalSig = appData.signatures[index];
        const newName = `${originalSig.name} (Копия)`;
        modalNameInput.value = newName;
        modalContentInput.value = originalSig.content;
        modalCategoryInput.value = originalSig.category;
        showModalForm(null);
        modalNameInput.focus();
        modalNameInput.select();
     }

    function findEditorElement() {
        let editor = document.querySelector('.fr-element.fr-view');
        if (editor && editor.isContentEditable) return editor;
        editor = document.querySelector('textarea[name="message"], textarea.input--labelled-textArea, textarea#message');
        return editor;
    }

    function handleInsertion(signatureIndex) {
        if (signatureIndex < 0 || signatureIndex >= appData.signatures.length) return false;

        const signature = appData.signatures[signatureIndex];
        if (!editorElement) {
            editorElement = findEditorElement();
            if (!editorElement) {
                console.warn('Helper: Редактор не найден.');
                alert('Не удалось найти поле редактора для вставки.');
                return false;
            }
        }

        const username = getUsername();
        const dateTime = getCurrentDateTime();
        const userInfoText = `${username} | ${dateTime}`;
        const userSeparatorText = appData.settings.separator.replace(/<br\s*\/?>/gi, '\n'); // Allow <br> or <br/>
        const userSeparatorHtml = appData.settings.separator.replace(/\n/g, '<br>');
        const finalContentText = `${signature.content}${userSeparatorText}${userInfoText}`;
        // Ensure BBCode line breaks are converted for HTML view, but keep existing <br>
        const finalContentHtml = signature.content.replace(/(?<!<br\s*\/?>)\n/g, '<br>') + userSeparatorHtml + userInfoText;


        const previewText = `--- Предпросмотр Подписи ---\n\n${finalContentText}\n\n---------------------------\n\nВставить?`;

        if (!confirm(previewText)) return false;

        let insertSuccess = false;
        try {
            const isTextArea = editorElement.tagName === 'TEXTAREA';
            const isContentEditable = editorElement.isContentEditable;

            if (isTextArea) {
                insertIntoTextarea(finalContentText);
            } else if (isContentEditable) {
                insertIntoContentEditable(finalContentHtml);
            } else {
                throw new Error('Найденный редактор не поддерживается.');
            }
            insertSuccess = true;
        } catch (e) {
            console.error("Signature Helper: Ошибка вставки подписи:", e);
            alert(`Ошибка вставки подписи: ${e.message}`);
            return false;
        }

        signature.usageCount = (signature.usageCount || 0) + 1;
        signature.lastUsed = Date.now();
        appData.settings.lastSelectedSignatureIndex = signatureIndex;
        saveData();

        if (modalElement && modalElement.style.display !== 'none') {
            renderModalList();
        }

        return true;
    }

    function insertIntoTextarea(textToInsert) {
        const currentEditorText = editorElement.value.trim();
        const initialSeparator = currentEditorText.length > 0 ? '\n\n' : '';
        const start = editorElement.selectionStart;
        const end = editorElement.selectionEnd;
        const before = editorElement.value.substring(0, start);
        const after = editorElement.value.substring(end);

        editorElement.value = before + initialSeparator + textToInsert + after;
        editorElement.focus();
        const newCursorPos = start + initialSeparator.length + textToInsert.length;
        editorElement.setSelectionRange(newCursorPos, newCursorPos);
        editorElement.scrollTop = editorElement.scrollHeight; // Scroll to bottom after insert
        // Trigger input event for frameworks that might listen for it
        editorElement.dispatchEvent(new Event('input', { bubbles: true }));
    }


    function insertIntoContentEditable(htmlToInsert) {
         editorElement.focus();
         setTimeout(() => {
             try {
                 // Check if editor already ends with paragraphs/breaks and avoid adding extra ones
                 const currentEditorHTML = editorElement.innerHTML.trim();
                 const endsWithBreak = /<(p|div|br)[\s>]/i.test(currentEditorHTML.slice(-20)); // Simple check if it ends likely with a block/break
                 const initialSeparator = currentEditorHTML.length > 0 && !endsWithBreak ? '<br><br>' : '';

                 document.execCommand('insertHTML', false, initialSeparator + htmlToInsert);
             } catch (e) {
                 console.error("Helper: Ошибка execCommand('insertHTML'):", e);
                 // Fallback attempt (less reliable with cursor position)
                 try {
                     const currentEditorHTML = editorElement.innerHTML.trim();
                      const endsWithBreak = /<(p|div|br)[\s>]/i.test(currentEditorHTML.slice(-20));
                      const initialSeparator = currentEditorHTML.length > 0 && !endsWithBreak ? '<br><br>' : '';
                     // Append at the end as a last resort
                     editorElement.innerHTML += initialSeparator + htmlToInsert;
                 } catch (fallbackError) {
                      console.error("Helper: Резервная вставка не удалась:", fallbackError);
                      throw new Error('Не удалось вставить контент.');
                 }
             }
             // Ensure visibility after insertion
             editorElement.scrollTop = editorElement.scrollHeight;
         }, 50); // Timeout helps ensure focus is set before execCommand
    }


     function triggerAutoSend() {
        if (!appData.settings.autoSendAfterInsert || !editorElement) return;
        setTimeout(() => {
            const form = editorElement.closest('form');
            if (!form) {
                console.warn('Signature Helper: Auto-send failed, could not find parent form.');
                return;
            }
            let submitButton = form.querySelector('button[type="submit"].button--primary, button.button--cta[type="submit"]'); // More specific selectors first
            if (!submitButton) submitButton = form.querySelector('button[type="submit"]');
            if (!submitButton) submitButton = form.querySelector('input[type="submit"]');
             if (!submitButton) {
                 // Try common button texts in Russian and English
                 const possibleTexts = ['Отправить', 'Ответить', 'Создать тему', 'Сохранить', 'Save', 'Reply', 'Submit', 'Post reply'];
                 const buttons = form.querySelectorAll('button, input[type="button"], input[type="submit"]');
                 for(const btn of buttons) {
                     const btnText = (btn.textContent || btn.value || '').trim();
                     if (possibleTexts.some(text => btnText.toLowerCase().includes(text.toLowerCase()))) {
                         submitButton = btn;
                         break;
                     }
                 }
             }

            if (submitButton) {
                console.log('Signature Helper: Auto-sending form...');
                submitButton.click();
            } else {
                console.warn('Signature Helper: Auto-send failed, could not find submit button.');
                 // alert('Не удалось найти кнопку отправки для авто-отправки.'); // Optional user feedback
            }
        }, AUTO_SEND_DELAY);
    }


     function updateMainUIState() {
        const hasSignatures = appData.signatures.length > 0;
        if (selectSignatureElement) selectSignatureElement.disabled = !hasSignatures;
        if (insertSignatureButton) insertSignatureButton.disabled = !hasSignatures;
        if (randomSignatureButton) randomSignatureButton.disabled = !hasSignatures;
    }

     function populateSignatureSelect() {
        if (!selectSignatureElement) return;
        const currentSelectedIndex = selectSignatureElement.value; // Remember currently selected value if any
        selectSignatureElement.innerHTML = ''; // Clear existing options

        if (appData.signatures.length === 0) {
            const option = document.createElement('option');
            option.textContent = 'Нет подписей';
            option.disabled = true;
            selectSignatureElement.appendChild(option);
        } else {
            // Group signatures by category
            const categories = {};
            appData.signatures.forEach((sig, index) => {
                const categoryName = sig.category?.trim() || 'Без категории'; // Ensure category is a string
                if (!categories[categoryName]) categories[categoryName] = [];
                categories[categoryName].push({ ...sig, originalIndex: index });
            });

            // Sort category names, placing "Без категории" first
            const sortedCategoryNames = Object.keys(categories).sort((a, b) => {
                 if (a === 'Без категории') return -1;
                 if (b === 'Без категории') return 1;
                 return a.localeCompare(b, 'ru'); // Locale-specific sorting for category names
            });

            // Create optgroups and options
            sortedCategoryNames.forEach(categoryName => {
                const group = document.createElement('optgroup');
                group.label = categoryName;

                // Sort signatures within each category by name
                const signaturesInCategory = categories[categoryName].sort((a, b) => a.name.localeCompare(b.name, 'ru'));

                signaturesInCategory.forEach(sigData => {
                    const option = document.createElement('option');
                    option.value = sigData.originalIndex.toString();
                    option.textContent = sigData.name;
                    // Add tooltip with category and preview (limited length)
                    const preview = sigData.content.substring(0, 100) + (sigData.content.length > 100 ? '...' : '');
                    option.title = `Категория: ${categoryName}\n---\n${preview}`;
                    group.appendChild(option);
                });
                selectSignatureElement.appendChild(group);
            });

            // Restore selection if possible
            const lastIndex = appData.settings.lastSelectedSignatureIndex;
            if (lastIndex !== -1 && selectSignatureElement.querySelector(`option[value="${lastIndex}"]`)) {
                 selectSignatureElement.value = lastIndex.toString();
             } else if (selectSignatureElement.querySelector(`option[value="${currentSelectedIndex}"]`)) {
                 // If last index is invalid, try restoring the previous selection
                selectSignatureElement.value = currentSelectedIndex;
            } else if (selectSignatureElement.options.length > 0) {
                 // Otherwise, select the first available option
                 selectSignatureElement.value = selectSignatureElement.options[0].value;
                 // Update lastSelectedSignatureIndex setting if we selected the first one
                 appData.settings.lastSelectedSignatureIndex = parseInt(selectSignatureElement.value, 10);
            }
        }
        updateMainUIState(); // Update button disabled states
    }


    function showHelpInfo() {
        const helpText = `--- Помощник Подписей Black Russia v${CURRENT_VERSION} ---

Этот скрипт добавляет панель под редактором сообщений для быстрой вставки заранее созданных подписей.

Основные элементы:
- Выпадающий список: Выбор сохраненной подписи (сгруппированы по категориям).
- [Вставить]: Вставка выбранной подписи с предпросмотром. Ваш ник и текущая дата/время будут добавлены в конце согласно настройкам.
- [🎲]: Вставка случайной подписи из списка (также с предпросмотром).
- [⚙️]: Открытие окна управления подписями и настройками.
- [?]: Отображение этой справки.

Окно управления (⚙️):
- Фильтр по категориям и Сортировка: Навигация по списку подписей.
- [+ Добавить подпись]: Открывает форму для создания новой подписи.
- Список подписей: Показывает имя, категорию, количество использований ([N]), дату добавления и последнего использования. При наведении виден текст подписи.
  - [✏️]: Редактировать подпись.
  - [📋]: Дублировать подпись (создать копию).
  - [❌]: Удалить подпись (с подтверждением).
- Настройки:
  - Разделитель: Текст (можно использовать <br> или <br/> для переноса), который вставляется между подписью и блоком "Ник | Дата".
  - Формат даты и времени: Выбор вида отображения даты и времени.
  - Авто-отправка: Опция автоматического нажатия кнопки отправки формы после вставки подписи (используйте с осторожностью!).

Форма добавления/редактирования:
- Название: Обязательное поле для идентификации подписи.
- Категория: Необязательное поле для группировки.
- Глобальные стили: Применение шрифта, жирности (B), курсива (I) или подчеркивания (U) ко ВСЕЙ подписи. Выбор шрифта или нажатие B/I/U обернет весь текст в соответствующие BBCode теги ([font=...], [b], [i], [u]). Повторное нажатие B/I/U уберет тег.
- Содержание подписи: Основной текст вашей подписи. Можно использовать BBCode.
- Панель BBCode: Кнопки для быстрой вставки тегов [b], [i], [u], [strike], [center], [quote], [color], [size], [img], [url].
  - Для [color] и [size] используются выбранные рядом цвет и размер.
  - [🌈]: Применяет случайный цвет ([color=...]) к каждой непустой строке текста.
  - [🕒]: Вставляет текущую дату и время (согласно настройкам) в место курсора.
- Кнопки: "Добавить/Сохранить", "Сохранить и Добавить еще" (только при добавлении), "Отмена" (закрывает форму без сохранения).

При вставке подписи ваш Ник и Дата/Время добавляются автоматически в конец, согласно выбранному формату и разделителю.

Приятного пользования!`;
        alert(helpText);
    }

    function createMainUI(targetEditor) {
         if (document.getElementById('sig-helper-main-ui')) return;

        mainUiContainer = document.createElement('div');
        mainUiContainer.id = 'sig-helper-main-ui';
        mainUiContainer.className = 'sig-helper-main-ui sig-helper-dark';

        selectSignatureElement = document.createElement('select');
        selectSignatureElement.title = 'Выберите подпись (авто-ник/дата)';
        selectSignatureElement.onchange = () => {
             const selectedIndex = parseInt(selectSignatureElement.value, 10);
             if (!isNaN(selectedIndex)) {
                 appData.settings.lastSelectedSignatureIndex = selectedIndex;
                 // No save needed on select change, only on insert
             }
        };
        populateSignatureSelect();

        insertSignatureButton = document.createElement('button');
        insertSignatureButton.type = 'button';
        insertSignatureButton.textContent = 'Вставить';
        insertSignatureButton.className = 'button button--cta';
        insertSignatureButton.title = 'Вставить выбранную подпись (с предпросмотром)';
        insertSignatureButton.onclick = () => {
            const selectedIndex = parseInt(selectSignatureElement.value, 10);
            if (!isNaN(selectedIndex)) {
                if (handleInsertion(selectedIndex)) {
                    triggerAutoSend();
                }
            } else {
                 alert('Пожалуйста, выберите подпись из списка.');
            }
        };

        randomSignatureButton = document.createElement('button');
        randomSignatureButton.type = 'button';
        randomSignatureButton.innerHTML = '🎲';
        randomSignatureButton.className = 'button';
        randomSignatureButton.title = 'Вставить случайную подпись (с предпросмотром)';
        randomSignatureButton.onclick = () => {
            if (appData.signatures.length > 0) {
                const randomIndex = Math.floor(Math.random() * appData.signatures.length);
                 // Select the random signature in the dropdown for visual feedback
                selectSignatureElement.value = randomIndex.toString();
                 // Update setting as if user selected it
                 appData.settings.lastSelectedSignatureIndex = randomIndex;

                if (handleInsertion(randomIndex)) {
                     triggerAutoSend();
                }
            } else {
                alert('Нет сохраненных подписей.');
            }
        };

        const manageButton = document.createElement('button');
        manageButton.type = 'button';
        manageButton.innerHTML = '⚙️';
        manageButton.className = 'button';
        manageButton.title = 'Управление подписями и настройками';
        manageButton.onclick = openManageModal;

        const helpButton = document.createElement('button');
        helpButton.type = 'button';
        helpButton.innerHTML = '?';
        helpButton.className = 'button';
        helpButton.title = 'Помощь и информация о скрипте';
        helpButton.onclick = showHelpInfo;

        mainUiContainer.append(selectSignatureElement, insertSignatureButton, randomSignatureButton, manageButton, helpButton);

        updateMainUIState();

        let insertBeforeElement = targetEditor.closest('.fr-box') || targetEditor.closest('.editorHtml') || targetEditor.parentNode;
        if (insertBeforeElement?.parentNode) {
            insertBeforeElement.parentNode.insertBefore(mainUiContainer, insertBeforeElement);
        } else if(targetEditor?.parentNode) {
             // Fallback: insert directly before the editor itself if no better container found
            targetEditor.parentNode.insertBefore(mainUiContainer, targetEditor);
        } else {
             console.error("Signature Helper: Не удалось найти место для вставки UI.");
        }
    }


    function createManageModal() {
        if (modalElement) return;

        modalElement = document.createElement('div');
        modalElement.id = 'sig-helper-modal';
        modalElement.className = 'sig-helper-modal sig-helper-dark';
        modalElement.style.display = 'none';
        // Close modal if backdrop is clicked
        modalElement.addEventListener('click', (event) => {
            if (event.target === modalElement) {
                closeManageModal();
            }
        });


        const modalContent = document.createElement('div');
        modalContent.className = 'sig-helper-modal-content';
        // Prevent backdrop click from closing when clicking inside content
        modalContent.addEventListener('click', (event) => event.stopPropagation());


        const closeButton = document.createElement('button');
        closeButton.innerHTML = '&times;';
        closeButton.className = 'sig-helper-modal-close';
        closeButton.title = 'Закрыть';
        closeButton.onclick = closeManageModal;

        const title = document.createElement('h2');
        title.textContent = 'Управление подписями и настройками';

        // --- Main Area Wrapper (for scrolling list/settings) ---
        const mainArea = document.createElement('div');
        mainArea.className = 'sig-helper-modal-main-area';

        const controlsContainer = document.createElement('div');
        controlsContainer.className = 'sig-helper-modal-controls';

        modalCategoryFilter = document.createElement('select');
        modalCategoryFilter.title = 'Фильтр по категории';
        modalCategoryFilter.onchange = () => { currentFilterCategory = modalCategoryFilter.value; renderModalList(); };
        controlsContainer.appendChild(modalCategoryFilter);

        modalSortSelect = document.createElement('select');
        modalSortSelect.title = 'Сортировка списка';
        const sortOptions = {
             'name_asc': 'Имя (А-Я)', 'name_desc': 'Имя (Я-А)', 'usage_desc': 'Чаще используемые', 'usage_asc': 'Реже используемые',
             'date_desc': 'Новые', 'date_asc': 'Старые', 'lastused_desc': 'Недавно использованные', 'lastused_asc': 'Давно использованные' };
        Object.entries(sortOptions).forEach(([value, text]) => {
             const option = document.createElement('option'); option.value = value; option.textContent = text; modalSortSelect.appendChild(option); });
        modalSortSelect.value = currentSortType;
        modalSortSelect.onchange = () => { currentSortType = modalSortSelect.value; renderModalList(); };
        controlsContainer.appendChild(modalSortSelect);

        modalListElement = document.createElement('ul');
        modalListElement.className = 'sig-helper-modal-list';
        modalListElement.addEventListener('click', handleModalListClick);

        const addButton = document.createElement('button');
        addButton.textContent = '+ Добавить подпись';
        addButton.className = 'button button--primary sig-helper-add-button';
        addButton.onclick = () => showModalForm(null);

        const settingsContainer = document.createElement('div');
        settingsContainer.className = 'sig-helper-modal-settings';
        const settingsTitle = document.createElement('h3'); settingsTitle.textContent = 'Настройки';
        settingsContainer.appendChild(settingsTitle);
        createSettingsPane(settingsContainer);

        // Append controls, list, add button, settings to the main scrollable area
        mainArea.append(controlsContainer, modalListElement, addButton, settingsContainer);
        // --- End Main Area Wrapper ---

        createModalForm(); // Create form element (initially hidden)

        // Append title, main scrollable area, and the form (conditionally displayed) to modal content
        modalContent.append(closeButton, title, mainArea, modalFormElement);
        modalElement.appendChild(modalContent);
        document.body.appendChild(modalElement);
    }

     function createSettingsPane(container) {
         const sepLabel = document.createElement('label');
         sepLabel.textContent = 'Разделитель перед Ник/Дата:'; sepLabel.htmlFor = 'sig-helper-settings-separator';
         modalSettingsSeparatorInput = document.createElement('textarea');
         modalSettingsSeparatorInput.id = 'sig-helper-settings-separator'; modalSettingsSeparatorInput.rows = 2;
         modalSettingsSeparatorInput.value = appData.settings.separator; modalSettingsSeparatorInput.placeholder = DEFAULT_SEPARATOR.replace(/\\n/g, '\n'); // Show default line breaks correctly
         modalSettingsSeparatorInput.className = 'sig-helper-settings-input';
         modalSettingsSeparatorInput.addEventListener('change', saveSettings); // Save on change


         const dtLabel = document.createElement('label');
         dtLabel.textContent = 'Формат даты и времени:'; dtLabel.htmlFor = 'sig-helper-settings-datetime';
         modalSettingsDateTimeSelect = document.createElement('select');
         modalSettingsDateTimeSelect.id = 'sig-helper-settings-datetime'; modalSettingsDateTimeSelect.className = 'sig-helper-settings-input';
         Object.keys(DATETIME_PRESETS).forEach(presetKey => {
             const option = document.createElement('option'); option.value = presetKey;
             // Get a formatted example for each preset
             option.textContent = `${presetKey} (Пример: ${getCurrentDateTime(presetKey)})`;
              modalSettingsDateTimeSelect.appendChild(option); });
         modalSettingsDateTimeSelect.value = appData.settings.dateTimePreset;
         modalSettingsDateTimeSelect.addEventListener('change', saveSettings);

         const autoSendLabel = document.createElement('label'); autoSendLabel.className = 'sig-helper-settings-label-checkbox';
         modalSettingsAutoSendCheckbox = document.createElement('input');
         modalSettingsAutoSendCheckbox.type = 'checkbox'; modalSettingsAutoSendCheckbox.id = 'sig-helper-settings-autosend';
         modalSettingsAutoSendCheckbox.checked = appData.settings.autoSendAfterInsert;
          modalSettingsAutoSendCheckbox.addEventListener('change', saveSettings);
         autoSendLabel.appendChild(modalSettingsAutoSendCheckbox);
         autoSendLabel.appendChild(document.createTextNode(' Автоматически отправлять форму после вставки (Рискованно!)'));
         autoSendLabel.title = 'Если включено, скрипт попытается нажать кнопку отправки формы после успешной вставки подписи.';

         container.append(sepLabel, modalSettingsSeparatorInput, dtLabel, modalSettingsDateTimeSelect, autoSendLabel);
     }

     function saveSettings() {
         // Read values from inputs
         let separatorValue = modalSettingsSeparatorInput.value;
         // Ensure default separator if input is empty or only whitespace
         appData.settings.separator = separatorValue.trim() === '' ? DEFAULT_SEPARATOR : separatorValue;
         appData.settings.dateTimePreset = DATETIME_PRESETS[modalSettingsDateTimeSelect.value] ? modalSettingsDateTimeSelect.value : DEFAULT_DATETIME_PRESET;
         appData.settings.autoSendAfterInsert = modalSettingsAutoSendCheckbox.checked;

         // Update UI in case validation changed the value (e.g., empty separator)
         modalSettingsSeparatorInput.value = appData.settings.separator; // Reflect potentially corrected value
         modalSettingsDateTimeSelect.value = appData.settings.dateTimePreset;
         modalSettingsAutoSendCheckbox.checked = appData.settings.autoSendAfterInsert;

         saveData(); // Save the updated appData
     }


    function createModalForm() {
        modalFormElement = document.createElement('div');
        modalFormElement.className = 'sig-helper-modal-form';
        modalFormElement.style.display = 'none'; // Initially hidden

        const formTitle = document.createElement('h3');
        formTitle.id = 'sig-helper-form-title';

        const nameLabel = document.createElement('label'); nameLabel.textContent = 'Название:'; nameLabel.htmlFor = 'sig-helper-name-input';
        modalNameInput = document.createElement('input'); modalNameInput.type = 'text'; modalNameInput.id = 'sig-helper-name-input'; modalNameInput.required = true;

        const categoryLabel = document.createElement('label'); categoryLabel.textContent = 'Категория (необязательно):'; categoryLabel.htmlFor = 'sig-helper-category-input';
        modalCategoryInput = document.createElement('input'); modalCategoryInput.type = 'text'; modalCategoryInput.id = 'sig-helper-category-input'; modalCategoryInput.placeholder = 'Например: RP, Гос. Орг., Жалобы';
        const categoryDatalist = document.createElement('datalist'); categoryDatalist.id = 'sig-helper-categories';
        modalCategoryInput.setAttribute('list', categoryDatalist.id); // Link input to datalist

        // --- Global Styles ---
        const globalStyleContainer = document.createElement('div');
        globalStyleContainer.className = 'sig-helper-global-style-controls';

        const fontLabel = document.createElement('label'); fontLabel.textContent = 'Шрифт:'; fontLabel.htmlFor = 'sig-helper-global-font';
        const fontSelect = document.createElement('select'); fontSelect.id = 'sig-helper-global-font'; fontSelect.title = 'Применить шрифт ко всей подписи';
        FONT_LIST.forEach(fontName => {
            const option = document.createElement('option');
            option.value = fontName === 'По умолчанию' ? '' : fontName; option.textContent = fontName;
            if (fontName !== 'По умолчанию') option.style.fontFamily = fontName; // Show font preview in dropdown
            fontSelect.appendChild(option);
        });
        fontSelect.onchange = () => applyGlobalStyle('font', fontSelect.value);
        fontLabel.appendChild(fontSelect);

        const styleButtonContainer = document.createElement('div'); styleButtonContainer.className = 'sig-helper-global-style-buttons';
        [{ tag: 'b', text: 'B' }, { tag: 'i', text: 'I' }, { tag: 'u', text: 'U' }].forEach(style => {
            const button = document.createElement('button'); button.type = 'button'; button.textContent = style.text; button.id = `sig-helper-global-${style.tag}`;
            button.className = 'button button--small sig-helper-global-style-button'; button.title = `Применить/убрать ${style.tag}-стиль ко всей подписи`;
            button.onclick = () => applyGlobalStyle(style.tag);
            styleButtonContainer.appendChild(button);
        });
        globalStyleContainer.append(fontLabel, styleButtonContainer);
        // --- End Global Styles ---


        const contentLabel = document.createElement('label'); contentLabel.innerHTML = 'Содержание подписи <small>(BBCode)</small>:'; contentLabel.htmlFor = 'sig-helper-content-input';
        modalContentInput = document.createElement('textarea'); modalContentInput.id = 'sig-helper-content-input';
        modalContentInput.rows = 7; modalContentInput.required = true;
        // Update global style UI based on content changes/focus
        modalContentInput.addEventListener('input', debounce(updateGlobalStyleUI, 300));
        modalContentInput.addEventListener('focus', updateGlobalStyleUI);
        modalContentInput.addEventListener('blur', updateGlobalStyleUI); // Also check on blur

        // --- Toolbar ---
        const toolbarContainer = document.createElement('div'); toolbarContainer.className = 'sig-helper-toolbar-container';
        const bbCodeToolbar = document.createElement('div'); bbCodeToolbar.className = 'sig-helper-bbcode-toolbar';

        // Basic tags
        ['b', 'i', 'u'].forEach(tag => bbCodeToolbar.appendChild(createToolbarButton(tag, `[${tag}]`)));
        // Additional tags
        bbCodeToolbar.appendChild(createToolbarButton('strike', 'Зачеркнутый'));
        bbCodeToolbar.appendChild(createToolbarButton('center', 'Центрировать'));
        bbCodeToolbar.appendChild(createToolbarButton('quote', 'Цитата'));

        // Color picker + button
        const colorPicker = document.createElement('input'); colorPicker.type = 'color'; colorPicker.id = 'sig-helper-bbcode-color'; colorPicker.value = '#E0E0E0'; // Default dark theme text color
        colorPicker.title = 'Выбрать цвет для [color]'; colorPicker.className = 'sig-helper-bbcode-control sig-helper-bbcode-colorpicker';
        bbCodeToolbar.appendChild(colorPicker);
        bbCodeToolbar.appendChild(createToolbarButton('color', 'Цвет текста'));

        // Size select + button
        const sizeSelect = document.createElement('select'); sizeSelect.id = 'sig-helper-bbcode-size'; sizeSelect.title = 'Выбрать размер для [size]'; sizeSelect.className = 'sig-helper-bbcode-control';
        for (let i = 1; i <= 7; i++) { const opt = document.createElement('option'); opt.value = i; opt.textContent = ` ${i} `; if (i === 4) opt.selected = true; sizeSelect.appendChild(opt); } // Size 4 is often default
        bbCodeToolbar.appendChild(sizeSelect);
        bbCodeToolbar.appendChild(createToolbarButton('size', 'Размер текста'));

        // Image and Link buttons
        bbCodeToolbar.appendChild(createToolbarButton('img', 'Изображение'));
        bbCodeToolbar.appendChild(createToolbarButton('url', 'Ссылка'));

        // Action buttons (Random color, Insert Date/Time)
        const actionButtonsContainer = document.createElement('div');
        actionButtonsContainer.className = 'sig-helper-toolbar-actions';

        const randomColorButton = document.createElement('button'); randomColorButton.type = 'button'; randomColorButton.innerHTML = '🌈';
        randomColorButton.title = 'Применить случайный цвет к каждой строке'; randomColorButton.className = 'button button--small'; randomColorButton.onclick = applyRandomLineColors;
        actionButtonsContainer.appendChild(randomColorButton);

        const insertDateTimeButton = document.createElement('button'); insertDateTimeButton.type = 'button'; insertDateTimeButton.innerHTML = '🕒';
        insertDateTimeButton.title = 'Вставить текущую дату/время в текст'; insertDateTimeButton.className = 'button button--small'; insertDateTimeButton.onclick = insertDateTimeIntoContent;
        actionButtonsContainer.appendChild(insertDateTimeButton);

        toolbarContainer.append(bbCodeToolbar, actionButtonsContainer);
        // --- End Toolbar ---

        // --- Form Buttons ---
        const buttonGroup = document.createElement('div'); buttonGroup.className = 'sig-helper-form-buttons';

        modalSaveButton = document.createElement('button'); modalSaveButton.type = 'button'; // Ensure type=button
        modalSaveButton.className = 'button button--cta';
        modalSaveButton.onclick = () => handleModalSave(false);

        modalSaveAndNewButton = document.createElement('button'); modalSaveAndNewButton.type = 'button';
        modalSaveAndNewButton.textContent = 'Сохранить и Добавить еще';
        modalSaveAndNewButton.className = 'button button--primary';
        modalSaveAndNewButton.title = 'Сохранить текущую и очистить форму для добавления следующей';
        modalSaveAndNewButton.onclick = () => handleModalSave(true);

        modalCancelButton = document.createElement('button'); modalCancelButton.type = 'button';
        modalCancelButton.textContent = 'Отмена';
        modalCancelButton.className = 'button';
        modalCancelButton.onclick = hideModalForm; // Use the function to hide the form

        buttonGroup.append(modalSaveButton, modalSaveAndNewButton, modalCancelButton);
        // --- End Form Buttons ---

        // Assemble the form
        modalFormElement.append(
            formTitle,
            nameLabel, modalNameInput,
            categoryLabel, modalCategoryInput, categoryDatalist,
            globalStyleContainer,
            contentLabel, modalContentInput,
            toolbarContainer,
            buttonGroup
        );
    }


     function createToolbarButton(tag, title) {
         const button = document.createElement('button'); button.type = 'button';
         button.textContent = `[${tag}]`; button.className = 'button button--small sig-helper-bbcode-button';
         button.title = title; button.onclick = () => insertBbCode(tag);
         return button;
     }

     function insertDateTimeIntoContent() {
         const currentDateTime = getCurrentDateTime(); const textarea = modalContentInput;
         const start = textarea.selectionStart; const end = textarea.selectionEnd;
         const before = textarea.value.substring(0, start);
         const after = textarea.value.substring(end);

         textarea.value = before + currentDateTime + after;
         textarea.focus();
         // Place cursor after inserted text
         textarea.selectionStart = textarea.selectionEnd = start + currentDateTime.length;
         textarea.dispatchEvent(new Event('input', { bubbles: true })); // Trigger updates
     }


     function insertBbCode(tag) {
        const textarea = modalContentInput;
        const start = textarea.selectionStart;
        const end = textarea.selectionEnd;
        const selectedText = textarea.value.substring(start, end);
        const beforeText = textarea.value.substring(0, start);
        const afterText = textarea.value.substring(end);

        let replacement = '';
        let cursorPosition = start; // Default cursor position if no text selected

        switch (tag) {
            case 'url':
                const url = prompt('Введите URL адрес:', selectedText.startsWith('http') ? selectedText : 'https://');
                if (url === null || url.trim() === '') return;
                const urlText = selectedText || url; // Use selected text or URL itself as text
                replacement = `[url=${url}]${urlText}[/url]`;
                cursorPosition = start + `[url=${url}]`.length + urlText.length + `[/url]`.length; // End of tag
                break;
            case 'img':
                 const imgUrl = prompt('Введите URL изображения:', selectedText.startsWith('http') ? selectedText : 'https://');
                 if (imgUrl === null || imgUrl.trim() === '') return;
                 replacement = `[img]${imgUrl}[/img]`;
                 cursorPosition = start + replacement.length; // End of tag
                 break;
            case 'color':
                 const colorInput = document.getElementById('sig-helper-bbcode-color');
                 const color = colorInput ? colorInput.value : '#E0E0E0';
                 replacement = `[color=${color}]${selectedText || 'текст'}[/color]`;
                 if (selectedText) {
                     cursorPosition = start + replacement.length; // End if text was selected
                 } else {
                     cursorPosition = start + `[color=${color}]`.length; // Inside tag if no text selected
                 }
                 break;
            case 'size':
                 const sizeInput = document.getElementById('sig-helper-bbcode-size');
                 const size = sizeInput ? sizeInput.value : '4';
                 replacement = `[size=${size}]${selectedText || 'текст'}[/size]`;
                  if (selectedText) {
                     cursorPosition = start + replacement.length;
                 } else {
                     cursorPosition = start + `[size=${size}]`.length;
                 }
                 break;
            case 'center':
            case 'strike':
            case 'quote':
            case 'b':
            case 'i':
            case 'u':
            default: // Standard tags like [b]...[/b]
                 replacement = `[${tag}]${selectedText}[/${tag}]`;
                 if (selectedText) {
                      cursorPosition = start + replacement.length;
                 } else {
                      cursorPosition = start + `[${tag}]`.length; // Position inside the tags
                 }
                 break;
        }

        textarea.value = beforeText + replacement + afterText;
        textarea.focus();
        textarea.setSelectionRange(cursorPosition, cursorPosition); // Set cursor position intelligently
        textarea.dispatchEvent(new Event('input', { bubbles: true })); // Trigger updates
     }


     function getRandomHexColor() {
         // Generate a bright, saturated color usable on a dark background
         const h = Math.floor(Math.random() * 360); // Hue (0-359)
         const s = Math.floor(Math.random() * 30) + 70; // Saturation (70-100%) - high saturation
         const l = Math.floor(Math.random() * 20) + 60; // Lightness (60-80%) - bright but not white

         // Convert HSL to RGB (standard algorithm)
         const c = (1 - Math.abs(2 * l/100 - 1)) * (s/100);
         const x = c * (1 - Math.abs((h / 60) % 2 - 1));
         const m = (l/100) - c/2;
         let r = 0, g = 0, b = 0;
         if (0 <= h && h < 60) { r = c; g = x; b = 0; }
         else if (60 <= h && h < 120) { r = x; g = c; b = 0; }
         else if (120 <= h && h < 180) { r = 0; g = c; b = x; }
         else if (180 <= h && h < 240) { r = 0; g = x; b = c; }
         else if (240 <= h && h < 300) { r = x; g = 0; b = c; }
         else if (300 <= h && h < 360) { r = c; g = 0; b = x; }
         r = Math.round((r + m) * 255);
         g = Math.round((g + m) * 255);
         b = Math.round((b + m) * 255);

         // Convert RGB to Hex
         const toHex = n => n.toString(16).padStart(2, '0');
         return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
     }

     function applyRandomLineColors() {
         const textarea = modalContentInput;
         const lines = textarea.value.split('\n');
         const coloredLines = lines.map(line => {
             const trimmedLine = line.trim();
             if (trimmedLine === '') return line; // Keep empty lines as is
             // Avoid re-coloring lines that already seem to have a color tag
             if (/^\[color=#[0-9a-f]{6}\].*\[\/color\]$/i.test(trimmedLine)) return line;
             // Remove existing color tags if they aren't wrapping the whole line
             const lineWithoutColor = trimmedLine.replace(/\[color=#[0-9a-f]{6}\](.*?)\[\/color\]/gi, '$1');
             return `[color=${getRandomHexColor()}]${lineWithoutColor}[/color]`;
         });
         textarea.value = coloredLines.join('\n');
         textarea.focus();
         updateGlobalStyleUI(); // Update UI in case global styles were affected
         textarea.dispatchEvent(new Event('input', { bubbles: true }));
     }


    function applyGlobalStyle(styleType, value = null) {
        const textarea = modalContentInput;
        if (!textarea) return;

        let currentContent = textarea.value;
        let needsUpdate = false;

        // Trim BOM if present
        if (currentContent.charCodeAt(0) === 0xFEFF) {
            currentContent = currentContent.substring(1);
        }

        let cleanedContent = currentContent.trim(); // Work with trimmed content initially
        let prefix = currentContent.match(/^\s*/)?.[0] || ''; // Preserve leading whitespace
        let suffix = currentContent.match(/\s*$/)?.[0] || ''; // Preserve trailing whitespace

        let regex, tag;
        let wasWrapped = false;

        if (styleType === 'font') {
            regex = /^\[font=([^\]]+)\]([\s\S]*)\[\/font\]$/i;
            const match = cleanedContent.match(regex);
            if (match) {
                cleanedContent = match[2] || ''; // Content inside
                wasWrapped = true; // Was wrapped
            }
            // Apply new font if selected, otherwise leave cleaned content
            if (value && value !== '') {
                cleanedContent = `[font=${value}]${cleanedContent}[/font]`;
                needsUpdate = true;
            } else if (wasWrapped) { // Font is removed (value='') and it was previously applied
                needsUpdate = true;
            }
        } else if (['b', 'i', 'u'].includes(styleType)) {
            tag = styleType;
            regex = new RegExp(`^\\[${tag}\\]([\\s\\S]*)\\[\\/${tag}\\]$`, 'i');
            const match = cleanedContent.match(regex);
            if (match) { // Is wrapped, so unwrap
                cleanedContent = match[1] || '';
                wasWrapped = true;
                needsUpdate = true;
            } else { // Not wrapped, so apply wrap
                cleanedContent = `[${tag}]${cleanedContent}[/${tag}]`;
                needsUpdate = true;
            }
        }

        if (needsUpdate) {
             // Re-apply prefix/suffix
            textarea.value = prefix + cleanedContent + suffix;
            updateGlobalStyleUI(); // Update UI controls
             textarea.focus();
             // Move cursor to end after applying style
             textarea.selectionStart = textarea.selectionEnd = textarea.value.length;
             textarea.dispatchEvent(new Event('input', { bubbles: true }));
        }
    }

    function updateGlobalStyleUI() {
        const content = modalContentInput?.value.trim() || ''; // Check trimmed content for styles

        // Font
        const fontSelect = document.getElementById('sig-helper-global-font');
        if (fontSelect) {
            const fontMatch = content.match(/^\[font=([^\]]+)\]/i);
            let currentFont = fontMatch ? fontMatch[1].trim() : '';
            // Find the option matching the current font (case-insensitive)
            const option = Array.from(fontSelect.options).find(opt => opt.value.toLowerCase() === currentFont.toLowerCase());
            fontSelect.value = option ? option.value : ''; // Set to found or "По умолчанию"
        }

        // B/I/U buttons
        ['b', 'i', 'u'].forEach(tag => {
            const button = document.getElementById(`sig-helper-global-${tag}`);
            if (button) {
                // Check if the content starts with [tag] and ends with [/tag] (case-insensitive)
                const styleRegex = new RegExp(`^\\[${tag}\\][\\s\\S]*\\[\\/${tag}\\]$`, 'i');
                button.classList.toggle('active', styleRegex.test(content));
            }
        });
    }

    function debounce(func, wait) {
        let timeout;
        return function executedFunction(...args) {
            const context = this; // Capture context
            const later = () => {
                timeout = null; // Clear timeout ID
                func.apply(context, args); // Execute function with original context and args
            };
            clearTimeout(timeout); // Clear the previous timeout
            timeout = setTimeout(later, wait); // Set a new timeout
        };
    }


    function handleModalListClick(event) {
        const target = event.target;
        const actionButton = target.closest('button[data-action]');
        const listItem = target.closest('li[data-index]');

        if (!listItem) return; // Click wasn't on a list item or its contents

        const indexStr = listItem.dataset.index;
        if (!indexStr) return; // No index found

        const index = parseInt(indexStr, 10);
        if (isNaN(index) || index < 0 || index >= appData.signatures.length) {
            console.warn('Invalid index clicked:', indexStr);
            return; // Invalid index
        }

        if (actionButton) {
            // Handle button clicks (Edit, Delete, Duplicate)
            const action = actionButton.dataset.action;
            event.stopPropagation(); // Prevent triggering other actions if nested
            if (action === 'edit') showModalForm(index);
            else if (action === 'delete') deleteSignature(index);
            else if (action === 'duplicate') duplicateSignature(index);
        } else {
            // Optional: Handle click on the list item itself (e.g., select for editing?)
            // Currently, only buttons have actions.
        }
    }


     function populateCategoryFilter() {
         if (!modalCategoryFilter) return;
         const currentFilterValue = modalCategoryFilter.value; // Remember current selection
         modalCategoryFilter.innerHTML = ''; // Clear old options

         // Add default options
         const allOption = document.createElement('option'); allOption.value = 'all'; allOption.textContent = 'Все категории'; modalCategoryFilter.appendChild(allOption);
         const noCategoryOption = document.createElement('option'); noCategoryOption.value = ''; noCategoryOption.textContent = 'Без категории'; modalCategoryFilter.appendChild(noCategoryOption);

         // Get unique, sorted categories from signatures
         const categories = [...new Set(appData.signatures.map(sig => sig.category?.trim()).filter(Boolean))] // Filter out empty/null, trim
                           .sort((a, b) => a.localeCompare(b, 'ru'));

         // Add options for each category
         categories.forEach(cat => {
              const option = document.createElement('option');
              option.value = cat;
              option.textContent = cat;
              modalCategoryFilter.appendChild(option); });

         // Restore previous selection if possible, otherwise default to 'all'
         modalCategoryFilter.value = currentFilterValue && modalCategoryFilter.querySelector(`option[value="${CSS.escape(currentFilterValue)}"]`) ? currentFilterValue : 'all';
         currentFilterCategory = modalCategoryFilter.value; // Update state variable
     }


     function updateCategoryDatalist() {
         const datalist = document.getElementById('sig-helper-categories'); if (!datalist) return;
         datalist.innerHTML = ''; // Clear old suggestions
         // Get unique, non-empty, sorted categories
         const categories = [...new Set(appData.signatures.map(sig => sig.category?.trim()).filter(Boolean))]
                           .sort((a, b) => a.localeCompare(b, 'ru'));
         categories.forEach(cat => { const option = document.createElement('option'); option.value = cat; datalist.appendChild(option); });
     }

    function renderModalList() {
        if (!modalListElement) return;
        modalListElement.innerHTML = ''; // Clear previous list

        // Filter signatures based on the selected category
        let filteredSignatures = appData.signatures.filter(sig => {
            const sigCategory = sig.category?.trim() || '';
            return currentFilterCategory === 'all' || sigCategory === currentFilterCategory;
        });

        // Sort the filtered signatures
        filteredSignatures.sort((a, b) => {
            // Helper for safe number comparison (treat null/undefined as 0)
            const safeNum = (n) => n || 0;
            // Helper for safe string comparison
            const safeStr = (s) => s || '';

            switch (currentSortType) {
                case 'name_asc': return safeStr(a.name).localeCompare(safeStr(b.name), 'ru');
                case 'name_desc': return safeStr(b.name).localeCompare(safeStr(a.name), 'ru');
                case 'usage_desc': return safeNum(b.usageCount) - safeNum(a.usageCount);
                case 'usage_asc': return safeNum(a.usageCount) - safeNum(b.usageCount);
                case 'date_desc': return safeNum(b.dateAdded) - safeNum(a.dateAdded);
                case 'date_asc': return safeNum(a.dateAdded) - safeNum(b.dateAdded);
                case 'lastused_desc': return safeNum(b.lastUsed) - safeNum(a.lastUsed); // Nulls (never used) will be last
                case 'lastused_asc': return safeNum(a.lastUsed) - safeNum(b.lastUsed); // Nulls (never used) will be first
                default: return 0;
            }
        });

        if (filteredSignatures.length === 0) {
            modalListElement.innerHTML = '<li class="sig-helper-list-empty">Нет подписей, соответствующих фильтру.</li>';
            return;
        }

        // Create list items for filtered and sorted signatures
        filteredSignatures.forEach(sig => {
            // Find the original index in the main appData array
            const originalIndex = appData.signatures.findIndex(original => original === sig);
             if (originalIndex === -1) return; // Should not happen, but safety check

            const li = document.createElement('li');
            li.dataset.index = originalIndex; // Store the original index

            const mainInfoDiv = document.createElement('div');
            mainInfoDiv.className = 'sig-helper-list-main';

            const nameSpan = document.createElement('span');
            nameSpan.className = 'sig-helper-list-name';
            nameSpan.textContent = sig.name || 'Без имени';
            mainInfoDiv.appendChild(nameSpan);

            const categorySpan = document.createElement('span');
            categorySpan.className = 'sig-helper-list-category';
            categorySpan.textContent = sig.category?.trim() || 'Без категории';
            mainInfoDiv.appendChild(categorySpan);

            const usageSpan = document.createElement('span');
            usageSpan.className = 'sig-helper-list-usage';
            usageSpan.textContent = `[${sig.usageCount || 0}]`;
            usageSpan.title = `Использовано: ${sig.usageCount || 0} раз`;
            mainInfoDiv.appendChild(usageSpan);


            const extraInfoDiv = document.createElement('div');
            extraInfoDiv.className = 'sig-helper-list-extra';
            const dateAdded = sig.dateAdded ? new Date(sig.dateAdded).toLocaleDateString('ru-RU', { day:'2-digit', month:'2-digit', year:'2-digit' }) : 'N/A';
            const lastUsed = sig.lastUsed ? new Date(sig.lastUsed).toLocaleString('ru-RU', { day:'2-digit', month:'2-digit', year:'2-digit', hour:'2-digit', minute:'2-digit' }) : 'Никогда';
            extraInfoDiv.textContent = `Добавлено: ${dateAdded} | Последний раз: ${lastUsed}`;
            // Tooltip for the extra info could show full content or be removed if redundant
            const preview = sig.content.substring(0, 150) + (sig.content.length > 150 ? '...' : '');
            extraInfoDiv.title = `Содержание:\n${preview}`;


            const buttonDiv = document.createElement('div');
            buttonDiv.className = 'sig-helper-list-actions';
            buttonDiv.append(
                createModalButton('✏️', 'Редактировать', 'edit'),
                createModalButton('📋', 'Дублировать', 'duplicate'),
                createModalButton('❌', 'Удалить', 'delete', true) // isDanger = true
            );

            li.append(mainInfoDiv, extraInfoDiv, buttonDiv);
            modalListElement.appendChild(li);
        });
    }


    function createModalButton(text, title, action, isDanger = false) {
        const button = document.createElement('button');
        button.type = 'button';
        button.innerHTML = text; // Use innerHTML for emoji icons
        button.title = title;
        button.className = `button button--small ${isDanger ? 'button--danger' : ''}`;
        button.dataset.action = action; // Store action in data attribute
        return button;
    }

    function showModalForm(index) {
        editingIndex = index; // Store index being edited (null for new)
        modalFormElement.style.display = 'flex'; // Show the form section
        updateCategoryDatalist(); // Update category suggestions

        const formTitle = modalFormElement.querySelector('#sig-helper-form-title');
        const isEditing = index !== null && index >= 0 && index < appData.signatures.length;

        if (isEditing) {
            const sig = appData.signatures[index];
            formTitle.textContent = 'Редактировать подпись';
            modalNameInput.value = sig.name;
            modalContentInput.value = sig.content;
            modalCategoryInput.value = sig.category || '';
            modalSaveButton.textContent = 'Сохранить изменения';
            modalSaveAndNewButton.style.display = 'none'; // Hide "Save & New" when editing
            // Focus last element or content area for editing flow
            modalContentInput.focus();
            // Optionally move cursor to end of content
            modalContentInput.setSelectionRange(modalContentInput.value.length, modalContentInput.value.length);
        } else {
            // Adding a new signature
            formTitle.textContent = 'Добавить подпись';
            modalSaveButton.textContent = 'Добавить подпись';
            modalSaveAndNewButton.style.display = 'inline-block'; // Show "Save & New"
             // Clear form only if it wasn't just populated by 'duplicate'
             if (modalNameInput.value.endsWith(' (Копия)') === false) {
                 modalNameInput.value = '';
                 modalContentInput.value = '';
                 modalCategoryInput.value = '';
             }
            modalNameInput.focus(); // Focus name field for new signature
        }

        updateGlobalStyleUI(); // Update B/I/U/Font buttons based on content
        // Scroll the form into view if it's outside the viewport
        modalFormElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
    }


    function hideModalForm() {
        modalFormElement.style.display = 'none'; // Hide the form section
        editingIndex = null; // Reset editing state

        // Optionally clear fields on cancel, or leave them if user might reopen
        // modalNameInput.value = '';
        // modalContentInput.value = '';
        // modalCategoryInput.value = '';

        // Reset global style UI state visually
        const fontSelect = document.getElementById('sig-helper-global-font'); if (fontSelect) fontSelect.value = '';
        ['b', 'i', 'u'].forEach(tag => { const btn = document.getElementById(`sig-helper-global-${tag}`); if (btn) btn.classList.remove('active'); });
    }


    function handleModalSave(keepFormOpen = false) {
        const name = modalNameInput.value;
        const content = modalContentInput.value;
        const category = modalCategoryInput.value;

        // Basic validation
        if (!name?.trim()) {
             alert('Название подписи не может быть пустым.');
             modalNameInput.focus();
             return;
        }
         if (!content) { // Allow empty content? For now, require something.
             alert('Содержание подписи не может быть пустым.');
             modalContentInput.focus();
             return;
        }


        let success = false;
        const isEditing = editingIndex !== null && editingIndex >= 0;

        if (isEditing) {
            success = updateSignature(editingIndex, name, content, category);
        } else {
            success = addSignature(name, content, category);
        }

        if (success) {
            saveData(); // Persist changes
            populateCategoryFilter(); // Update filter dropdown
            renderModalList(); // Refresh the list view
            populateSignatureSelect(); // Update main UI dropdown

            if (!isEditing && keepFormOpen) {
                // Clear form for next entry
                modalNameInput.value = '';
                modalContentInput.value = '';
                modalCategoryInput.value = ''; // Keep category maybe? No, clear all.
                editingIndex = null; // Ensure we are adding next time
                const formTitle = modalFormElement.querySelector('#sig-helper-form-title');
                if (formTitle) formTitle.textContent = 'Добавить подпись';
                updateGlobalStyleUI(); // Reset style buttons for empty form
                modalNameInput.focus(); // Focus name for next entry
            } else {
                hideModalForm(); // Close form on successful save/edit unless "Save & New"
            }
        }
        // No 'else' needed, validation alerts handle failure cases
    }


    function openManageModal() {
        if (!modalElement) createManageModal(); // Create modal if it doesn't exist

        // Ensure UI elements reflect current state *before* showing
        populateCategoryFilter();
        renderModalList(); // Render list based on current filter/sort
        modalSettingsSeparatorInput.value = appData.settings.separator;
        modalSettingsDateTimeSelect.value = appData.settings.dateTimePreset;
        modalSettingsAutoSendCheckbox.checked = appData.settings.autoSendAfterInsert;

        // Ensure form is hidden when modal opens initially
        hideModalForm();

        modalElement.style.display = 'flex'; // Show the modal
        // Focus filter or sort as a starting point
        modalCategoryFilter.focus();
         // Add class to body to prevent background scroll when modal is open
        document.body.classList.add('sig-helper-modal-open');
    }

    function closeManageModal() {
        if (modalElement) {
            hideModalForm(); // Ensure form is hidden if user closes modal while form is open
            modalElement.style.display = 'none'; // Hide the modal
            // Remove class from body to allow background scroll again
             document.body.classList.remove('sig-helper-modal-open');
        }
    }


    function addStyles() {
        GM_addStyle(`
            /* Prevent background scroll when modal is open */
            body.sig-helper-modal-open { overflow: hidden; }

            /* Переменные */
            .sig-helper-dark {
                --bg-color: #2d2d2d; --text-color: #e0e0e0; --border-color: #555;
                --input-bg: #3a3a3a; --input-text: #e0e0e0; --button-bg: #4a4a4a;
                --button-text: #e0e0e0; --button-hover-bg: #5a5a5a;
                --button-primary-bg: #007bff; --button-primary-hover-bg: #0056b3;
                --button-danger-bg: #dc3545; --button-danger-hover-bg: #c82333;
                --button-cta-bg: #28a745; --button-cta-hover-bg: #218838;
                --modal-list-hover-bg: #3f3f3f; --modal-list-extra-color: #aaa;
                --scrollbar-track-bg: #333; --scrollbar-thumb-bg: #666; --scrollbar-thumb-hover-bg: #888;
                --global-style-active-bg: var(--button-primary-bg);
                --global-style-active-text: white;
            }
            /* Основной UI */
            .sig-helper-main-ui { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 10px 0; padding: 8px 10px; background-color: var(--bg-color); border: 1px solid var(--border-color); border-radius: 4px; color: var(--text-color); }
            .sig-helper-main-ui select { padding: 5px 8px; border: 1px solid var(--border-color); border-radius: 3px; min-width: 150px; max-width: 250px; background-color: var(--input-bg); color: var(--input-text); cursor: pointer; flex-grow: 1; }
            .sig-helper-main-ui button { padding: 5px 10px; font-size: 1em; line-height: 1.2; background-color: var(--button-bg); color: var(--button-text); border: 1px solid var(--border-color); border-radius: 3px; cursor: pointer; white-space: nowrap; transition: background-color 0.2s ease; }
            .sig-helper-main-ui button:hover:not(:disabled) { background-color: var(--button-hover-bg); }
            .sig-helper-main-ui select:disabled, .sig-helper-main-ui button:disabled { opacity: 0.6; cursor: not-allowed; }
            .sig-helper-main-ui .button--cta { background-color: var(--button-cta-bg); border-color: var(--button-cta-bg); color: white; }
            .sig-helper-main-ui .button--cta:hover:not(:disabled) { background-color: var(--button-cta-hover-bg); border-color: var(--button-cta-hover-bg); }
            .sig-helper-main-ui select optgroup { font-style: italic; font-weight: bold; color: #ccc; background-color: var(--input-bg); }
            .sig-helper-main-ui select option { color: var(--input-text); background-color: var(--input-bg); padding-left: 10px; }

            /* Модальное окно */
            .sig-helper-modal { display: none; position: fixed; z-index: 10001; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.75); justify-content: center; align-items: center; backdrop-filter: blur(2px); }
            .sig-helper-modal-content { background-color: var(--bg-color); color: var(--text-color); padding: 0; border-radius: 6px; border: 1px solid var(--border-color); max-width: 850px; width: 95%; max-height: 90vh; box-shadow: 0 10px 30px rgba(0,0,0,0.5); display: flex; flex-direction: column; /* overflow: hidden; */ position: relative; } /* Removed overflow hidden from main content */
            .sig-helper-modal-close { position: absolute; top: 10px; right: 12px; font-size: 28px; font-weight: bold; z-index: 10; border: none; background: none; cursor: pointer; padding: 0; line-height: 1; color: #aaa; transition: color 0.2s ease; }
            .sig-helper-modal-close:hover { color: #fff; }
            .sig-helper-modal-content h2 { color: var(--text-color); margin: 0; padding: 15px 25px; text-align: center; font-size: 1.3em; border-bottom: 1px solid var(--border-color); flex-shrink: 0; } /* Title fixed top */

            /* Main scrollable area for list/settings */
            .sig-helper-modal-main-area { display: flex; flex-direction: column; flex-grow: 1; overflow-y: auto; /* Primary scroll here */ overflow-x: hidden; /* Prevent horizontal scroll */ scrollbar-color: var(--scrollbar-thumb-bg) transparent; scrollbar-width: thin; }
            .sig-helper-modal-main-area::-webkit-scrollbar { width: 8px; }
            .sig-helper-modal-main-area::-webkit-scrollbar-track { background: transparent; }
            .sig-helper-modal-main-area::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb-bg); border-radius: 4px;}
            .sig-helper-modal-main-area::-webkit-scrollbar-thumb:hover { background: var(--scrollbar-thumb-hover-bg); }

            /* Controls, List, Add Button, Settings inside the main area */
            .sig-helper-modal-controls { display: flex; gap: 10px; padding: 10px 20px; border-bottom: 1px solid var(--border-color); flex-shrink: 0; background-color: var(--input-bg); }
            .sig-helper-modal-controls select { padding: 5px 8px; border: 1px solid var(--border-color); border-radius: 3px; background-color: var(--bg-color); color: var(--input-text); cursor: pointer; }
            .sig-helper-modal-list { list-style: none; padding: 0; margin: 10px 20px; flex-shrink: 1; /* Allow list to shrink if needed, but main area grows */ border: 1px solid var(--border-color); border-radius: 4px; min-height: 150px; } /* Removed flex-grow from list itself */
            .sig-helper-add-button { margin: 0 20px 15px 20px; align-self: flex-start; flex-shrink: 0; }
            .sig-helper-modal-settings { padding: 10px 20px 15px 20px; border-top: 1px solid var(--border-color); background-color: var(--input-bg); flex-shrink: 0; margin-top: auto; /* Push settings towards bottom of main area */ }

            /* List Item Styling */
            .sig-helper-modal-list li { padding: 8px 12px; border-bottom: 1px solid var(--border-color); display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; transition: background-color 0.2s ease; gap: 10px; }
            .sig-helper-modal-list li:last-child { border-bottom: none; }
            .sig-helper-modal-list li:hover { background-color: var(--modal-list-hover-bg); }
            .sig-helper-list-main { display: flex; align-items: baseline; gap: 8px; flex-grow: 1; min-width: 200px; flex-wrap: nowrap; overflow: hidden; }
            .sig-helper-list-name { font-weight: bold; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex-shrink: 1; }
            .sig-helper-list-category { font-size: 0.85em; color: #ccc; background-color: #444; padding: 1px 5px; border-radius: 3px; white-space: nowrap; margin-left: 4px; flex-shrink: 0; }
            .sig-helper-list-usage { font-size: 0.85em; color: var(--button-primary-bg); font-weight: bold; margin-left: auto; padding-left: 10px; flex-shrink: 0; }
            .sig-helper-list-extra { font-size: 0.8em; color: var(--modal-list-extra-color); width: 100%; margin-top: 3px; cursor: default; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
            .sig-helper-list-actions { display: flex; gap: 6px; flex-shrink: 0; }
            .sig-helper-modal-list li.sig-helper-list-empty { padding: 15px; text-align: center; color: #aaa; font-style: italic; border: none; justify-content: center; }

             /* Settings Content */
             .sig-helper-modal-settings h3 { margin: 0 0 10px 0; font-size: 1.1em; color: #ccc; }
             .sig-helper-modal-settings label:not(.sig-helper-settings-label-checkbox) { display: block; margin-bottom: 3px; font-size: 0.9em; color: #ccc; }
             .sig-helper-settings-input { width: 100%; padding: 6px 8px; margin-bottom: 8px; border: 1px solid var(--border-color); border-radius: 3px; background-color: var(--bg-color); color: var(--input-text); font-size: 1em; font-family: inherit; box-sizing: border-box; }
             .sig-helper-modal-settings textarea.sig-helper-settings-input { resize: vertical; min-height: 40px; }
             .sig-helper-settings-label-checkbox { display: flex; align-items: center; margin-top: 5px; font-size: 0.95em; cursor: pointer; }
             .sig-helper-settings-label-checkbox input[type="checkbox"] { margin-right: 8px; cursor: pointer; }

             /* Form Styling (Appears below main area) */
             .sig-helper-modal-form {
                display: none; /* Initially hidden */
                flex-direction: column;
                gap: 10px;
                padding: 15px 20px;
                border-top: 1px solid var(--border-color);
                background-color: var(--bg-color); /* Same as modal content */
                /* max-height: 60%; /* Limit form height */
                overflow-y: auto; /* Scroll form content if needed */
                flex-shrink: 0; /* Prevent form from shrinking */
                box-shadow: 0 -5px 15px rgba(0,0,0,0.3); /* Visual separation */
                z-index: 5; /* Ensure form is above main area if overlap occurs (shouldn't) */
                scrollbar-color: var(--scrollbar-thumb-bg) var(--scrollbar-track-bg);
                scrollbar-width: thin;
             }
             .sig-helper-modal-form::-webkit-scrollbar { width: 8px; }
             .sig-helper-modal-form::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb-bg); border-radius: 4px;}
             .sig-helper-modal-form h3 { margin-top: 0; margin-bottom: 10px; }
             .sig-helper-modal-form label { display: block; margin-bottom: 3px; font-weight: bold; color: #ccc; font-size: 0.9em; }
             .sig-helper-modal-form input[type="text"],
             .sig-helper-modal-form input[list], /* Style datalist input */
             .sig-helper-modal-form textarea { width: 100%; padding: 8px; border: 1px solid var(--border-color); border-radius: 3px; background-color: var(--input-bg); color: var(--input-text); font-size: 1em; font-family: inherit; box-sizing: border-box; }
             .sig-helper-modal-form textarea { resize: vertical; min-height: 100px; }

             /* Global Styles Controls */
             .sig-helper-global-style-controls { display: flex; align-items: center; gap: 15px; margin-bottom: 10px; flex-wrap: wrap; background-color: var(--input-bg); padding: 8px; border-radius: 3px; }
             .sig-helper-global-style-controls label { margin-bottom: 0; display: flex; align-items: center; gap: 5px; font-size: 0.85em; }
             .sig-helper-global-style-controls select { padding: 3px 6px; border: 1px solid var(--border-color); border-radius: 3px; background-color: var(--bg-color); color: var(--input-text); cursor: pointer; font-size: 0.9em; max-width: 180px; }
             .sig-helper-global-style-buttons { display: flex; gap: 5px; }
             .sig-helper-global-style-button { font-weight: bold; }
             .sig-helper-global-style-button.active { background-color: var(--global-style-active-bg); color: var(--global-style-active-text); border-color: var(--global-style-active-bg); }

             /* BBCode Toolbar */
             .sig-helper-toolbar-container { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-bottom: 5px; flex-wrap: wrap; }
             .sig-helper-bbcode-toolbar { display: flex; gap: 5px; flex-wrap: wrap; align-items: center; flex-grow: 1; }
             .sig-helper-bbcode-control { padding: 2px 4px; border: 1px solid var(--border-color); background-color: var(--input-bg); color: var(--input-text); border-radius: 3px; height: 26px; vertical-align: middle; }
             .sig-helper-bbcode-colorpicker { padding: 1px; width: 30px; cursor: pointer; border: none; background: none; height: 24px; width: 24px; }
              .sig-helper-toolbar-actions { display: flex; gap: 5px; flex-shrink: 0; /* Prevent action buttons wrapping unnecessarily */ }
             .sig-helper-bbcode-toolbar button, .sig-helper-toolbar-actions button { background-color: var(--button-bg); color: var(--button-text); border: 1px solid var(--border-color); }
             .sig-helper-bbcode-toolbar button:hover, .sig-helper-toolbar-actions button:hover { background-color: var(--button-hover-bg); }

             /* Form Buttons */
             .sig-helper-form-buttons { display: flex; gap: 10px; margin-top: 15px; flex-wrap: wrap; padding-top: 10px; border-top: 1px solid var(--border-color);} /* Add separator */
             .sig-helper-modal-form .sig-helper-form-buttons > button { padding: 8px 15px; }

            /* Common Button Styles (Small, Danger, Primary, CTA) */
            .button--small { padding: 2px 6px !important; font-size: 0.9em !important; line-height: 1.4 !important; vertical-align: middle; } /* Adjusted line-height */
            .button--danger { background-color: var(--button-danger-bg) !important; color: white !important; border-color: var(--button-danger-bg) !important; }
            .button--danger:hover { background-color: var(--button-danger-hover-bg) !important; border-color: var(--button-danger-hover-bg) !important; }
            .sig-helper-modal .button--primary { background-color: var(--button-primary-bg); border-color: var(--button-primary-bg); color: white; }
            .sig-helper-modal .button--primary:hover { background-color: var(--button-primary-hover-bg); border-color: var(--button-primary-hover-bg); }
            .sig-helper-modal .button--cta { background-color: var(--button-cta-bg); border-color: var(--button-cta-bg); color: white; }
            .sig-helper-modal .button--cta:hover { background-color: var(--button-cta-hover-bg); border-color: var(--button-cta-hover-bg); }
        `);
    }

    function initialize() {
        loadData();
        getUsername(); // Get username early if possible
        addStyles(); // Inject CSS

        let attempts = 0;
        const checkInterval = setInterval(() => {
            const currentEditor = findEditorElement();
            if (currentEditor) {
                clearInterval(checkInterval);
                editorElement = currentEditor;
                createMainUI(editorElement); // Create main UI below editor
                console.log(`Signature Helper v${CURRENT_VERSION}: Инициализация завершена.`);
            } else {
                attempts++;
                if (attempts >= MAX_EDITOR_FIND_ATTEMPTS) {
                    clearInterval(checkInterval);
                    console.warn(`Signature Helper v${CURRENT_VERSION}: Редактор не найден после ${MAX_EDITOR_FIND_ATTEMPTS} попыток.`);
                }
            }
        }, EDITOR_FIND_INTERVAL);
    }

    // Wait for the page to be fully loaded or interactive before initializing
    if (document.readyState === 'complete' || document.readyState === 'interactive') {
        setTimeout(initialize, 350); // Small delay to ensure dynamic elements load
    } else {
        document.addEventListener('DOMContentLoaded', () => setTimeout(initialize, 350));
    }

})();