TorrentBD Shoutbox Manager

Complete shoutbox overhaul

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         TorrentBD Shoutbox Manager
// @namespace    TBD-Shoutbox-Manager
// @version      1.3.8.1
// @description  Complete shoutbox overhaul
// @author       notPULS3
// @license      MIT
// @match        https://www.torrentbd.com/
// @match        https://www.torrentbd.net/
// @match        https://www.torrentbd.org/
// @match        https://www.torrentbd.me/
// @match        https://www.torrentbd.net/?spotlight
// @match        https://www.torrentbd.com/?spotlight
// @match        https://www.torrentbd.org/?spotlight
// @icon         https://www.google.com/s2/favicons?sz=64&domain=torrentbd.net
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @grant        GM_registerMenuCommand
// @run-at       document-idle
// ==/UserScript==

(function () {
    'use strict';

    // Prevent multiple instances
    if (window.TBDMLoaded) return;
    window.TBDMLoaded = true;

    // ============================================================================
    // GLOBAL CONFIGURATION & STORAGE
    // ============================================================================

    const CONFIG = {
        // Cleaner Module
        cleaner_enabled: GM_getValue('tbdm_cleaner_enabled', false),
        cleaner_filters: GM_getValue('tbdm_cleaner_filters', {
            torrent: true,
            forumPost: true,
            forumTopic: true,
            request: true
        }),
        cleaner_hide_all_users: GM_getValue('tbdm_cleaner_hide_all_users', false),
        cleaner_block_users_enabled: GM_getValue('tbdm_cleaner_block_users_enabled', false),
        cleaner_blocked_user_ids: GM_getValue('tbdm_cleaner_blocked_user_ids', []),
        cleaner_block_keywords_enabled: GM_getValue('tbdm_cleaner_block_keywords_enabled', false),
        cleaner_blocked_keywords: GM_getValue('tbdm_cleaner_blocked_keywords', []),

        // Notifier Module
        notifier_enabled: GM_getValue('tbdm_notifier_enabled', false),
        notifier_username: GM_getValue('tbdm_notifier_username', ''),
        notifier_keywords: GM_getValue('tbdm_notifier_keywords', []),
        notifier_sound_volume: GM_getValue('tbdm_notifier_sound_volume', 0.5),
        notifier_highlight_color: GM_getValue('tbdm_notifier_highlight_color', '#2E4636'),
        notifier_processed_messages: GM_getValue('tbdm_notifier_processed_messages', []),

        // Image Upload Module
        image_upload_enabled: GM_getValue('tbdm_image_upload_enabled', true),

        // Easy Mention Module
        easy_mention_enabled: GM_getValue('tbdm_easy_mention_enabled', true),

        // URL Sender Module
        url_sender_enabled: GM_getValue('tbdm_url_sender_enabled', false),

        // GIF Picker Module
        gif_picker_enabled: GM_getValue('tbdm_gif_picker_enabled', true),
        gif_picker_tenor_key: GM_getValue('tbdm_gif_picker_tenor_key', 'AIzaSyCGj4Qj1j0MBns1v2rWhlvJWRBkCNgIFyo'),
        gif_picker_giphy_key: GM_getValue('tbdm_gif_picker_giphy_key', ''),

        meme_creator_enabled: GM_getValue('tbdm_meme_creator_enabled', false),

        // Unicode Emoji Module
        unicode_emoji_enabled: GM_getValue('tbdm_unicode_emoji_enabled', false),

        // Image Viewer Module
        image_viewer_enabled: GM_getValue('tbdm_image_viewer_enabled', true),

        // Autocomplete Module
        autocomplete_username_enabled: GM_getValue('tbdm_autocomplete_username_enabled', false),
        autocomplete_sticker_enabled: GM_getValue('tbdm_autocomplete_sticker_enabled', false),
        autocomplete_mappings: GM_getValue('tbdm_autocomplete_mappings', {
            'hi': ':hello',
            'hello': ':hello',
            'no': ':negative',
            'nahi': ':sticker-mb-no',
            'sad': ':sticker-pepe-face',
            'lmao': ':lmao',
            'wow': ':sticker-omg-wow',
            'lol': ':sticker-jjj-laugh',
            'why': ':sticker-cat-why',
            'ty': ':thankyou',
            'wont': ':sticker-sr-no',
            'bruh': ':sticker-facepalm',
            'yay': ':yepdance',
            'aww': ':sticker-pepe-aw',
            'laugh': ':sticker-pepe-laugh',
            'salute': ':sticker-pepe-salute',
            'ohh': ':sticker-cp-ohh',
            'doge': ':sticker-doge',
            'dance': ':sticker-dancing-doge',
            'pepeog': ':sticker-pepe-og',
            'ekb': ':sticker-ekb',
            'police': ':sticker-pepe-police',
            'yes': ':sticker-yes',
            'wut': ':sticker-pepe-wut',
            'exp': ':sticker-pepe-exp',
            'knock': ':sticker-death-knock',
            'rules': 'https://www.torrentbd.net/rules.php',
            'faq': 'https://www.torrentbd.net/faq.php'
        }),

        // Focus Lock Module
        focus_lock_enabled: GM_getValue('tbdm_focus_lock_enabled', true),

        // Idle Prevention Module
        idle_prevention_enabled: GM_getValue('tbdm_idle_prevention_enabled', true)
    };

    // ============================================================================
    // UTILITY FUNCTIONS
    // ============================================================================

    function saveConfig(key, value) {
        CONFIG[key] = value;
        GM_setValue(`tbdm_${key}`, value);
    }

    function detectUsername() {
        const allRankElements = document.querySelectorAll('.tbdrank');
        for (const rankElement of allRankElements) {
            if (!rankElement.closest('#shoutbox-container')) {
                if (rankElement && rankElement.firstChild && rankElement.firstChild.nodeType === Node.TEXT_NODE) {
                    return rankElement.firstChild.nodeValue.trim();
                }
            }
        }
        return 'Not Found';
    }

    // ============================================================================
    // MODULE 1: SHOUTBOX CLEANER
    // ============================================================================

    const CleanerModule = {
        systemFilters: {
            torrent: { phrase: "New Torrent :", label: "New Torrents" },
            forumPost: { phrase: "New Forum Post", label: "New Forum Posts" },
            forumTopic: { phrase: "New Forum Topic", label: "New Forum Topics" },
            request: { phrase: "New Request :", label: "New Requests" }
        },

        check() {
            if (!CONFIG.cleaner_enabled) return;

            const shoutItems = document.querySelectorAll(".shout-item");
            const blockedUserIDs = CONFIG.cleaner_blocked_user_ids.filter(Boolean);
            const blockedKeywords = CONFIG.cleaner_blocked_keywords.filter(Boolean);

            shoutItems.forEach((item) => {
                item.style.display = "";

                const textField = item.querySelector(".shout-text");
                if (!textField) return;

                const lowerCaseText = textField.textContent.toLowerCase();
                let shouldHide = false;

                let isSystemMessage = false;
                let systemMessageType = null;

                for (const key in this.systemFilters) {
                    if (lowerCaseText.includes(this.systemFilters[key].phrase.toLowerCase())) {
                        isSystemMessage = true;
                        systemMessageType = key;
                        break;
                    }
                }

                if (isSystemMessage) {
                    if (CONFIG.cleaner_filters[systemMessageType]) {
                        shouldHide = true;
                    }
                } else {
                    if (CONFIG.cleaner_hide_all_users) {
                        shouldHide = true;
                    } else if (CONFIG.cleaner_block_users_enabled && blockedUserIDs.length > 0) {
                        const idElement = item.querySelector('.shout-user [data-tid]');
                        const userID = idElement ? idElement.getAttribute('data-tid') : null;
                        if (userID && blockedUserIDs.includes(userID)) {
                            shouldHide = true;
                        }
                    }

                    // Check for blocked keywords
                    if (!shouldHide && CONFIG.cleaner_block_keywords_enabled && blockedKeywords.length > 0) {
                        for (const keyword of blockedKeywords) {
                            if (keyword && lowerCaseText.includes(keyword.toLowerCase())) {
                                shouldHide = true;
                                break;
                            }
                        }
                    }
                }

                if (shouldHide) {
                    item.style.display = "none";
                }
            });
        },

        init() {
            const shoutContainer = document.querySelector("#shouts-container");
            if (shoutContainer) {
                const observer = new MutationObserver(() => this.check());
                observer.observe(shoutContainer, { childList: true, subtree: true });
                this.check();
            }
        }
    };

   //============================================================================
    // MODULE 2: SHOUTBOX NOTIFIER
    // ============================================================================

    const NotifierModule = {
        MAX_PROCESSED_MESSAGES: 200,

        playSound() {
            if (CONFIG.notifier_sound_volume < 0.01) return;
            try {
                const audio = new Audio("https://raw.githubusercontent.com/5ifty6ix/custom-sounds/refs/heads/main/new-notification-010-352755.mp3");
                audio.volume = CONFIG.notifier_sound_volume;
                audio.play();
            } catch (e) {
                console.error('Notifier: Could not play sound.', e);
            }
        },

        notifyUser() {
            if (!document.title.startsWith('(1)')) {
                document.title = '(1) ' + document.title;
            }
            this.playSound();
        },

        highlightShout(shoutElement) {
            shoutElement.style.backgroundColor = CONFIG.notifier_highlight_color;
            shoutElement.style.borderLeft = '3px solid #14a76c';
            shoutElement.style.paddingLeft = '5px';
        },

        checkShout(shoutElement) {
            if (!CONFIG.notifier_enabled || !shoutElement || !shoutElement.id) return;

            const messageBody = shoutElement.querySelector('.shout-text');
            if (!messageBody) return;

            // Skip system messages (New Forum Post, New Torrent, etc.)
            const messageText = messageBody.textContent.toLowerCase();
            const systemPhrases = ['new forum post', 'new forum topic', 'new torrent', 'new request'];
            for (const phrase of systemPhrases) {
                if (messageText.includes(phrase)) {
                    return; // Skip this message
                }
            }

            const activeUsername = (CONFIG.notifier_username && CONFIG.notifier_username !== 'Not Found')
                ? [CONFIG.notifier_username] : [];
            const allKeywords = [...activeUsername, ...CONFIG.notifier_keywords]
                .filter(k => k && k.trim() !== '')
                .map(k => k.toLowerCase());

            if (allKeywords.length === 0) return;

            let keywordFound = false;
            for (const keyword of allKeywords) {
                const escapeRegExp = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
                const normalizedKeyword = keyword.replace(/^@/, '').replace(/[.\-_]+$/, '');
                const escapedKeyword = escapeRegExp(normalizedKeyword);
                const keywordRegex = new RegExp(
                    `(?<![\\w\\u0080-\\uFFFF])@?${escapedKeyword}[.\\-_]*(?![\\w\\u0080-\\uFFFF])`,
                    'i'
                );
                if (keywordRegex.test(messageText)) {
                    this.highlightShout(shoutElement);
                    keywordFound = true;
                    break;
                }
            }
            if (keywordFound) {
                const processedMessages = CONFIG.notifier_processed_messages;
                if (!processedMessages.includes(shoutElement.id)) {
                    this.notifyUser();
                    processedMessages.push(shoutElement.id);
                    if (processedMessages.length > this.MAX_PROCESSED_MESSAGES) {
                        processedMessages.shift();
                    }
                    saveConfig('notifier_processed_messages', processedMessages);
                }
            }
        },

        init() {
            const observer = new MutationObserver((mutationsList) => {
                for (const mutation of mutationsList) {
                    if (mutation.addedNodes.length) {
                        mutation.addedNodes.forEach(node => {
                            if (node.nodeType === 1 && node.classList.contains('shout-item')) {
                                this.checkShout(node);
                            }
                        });
                    }
                }
            });

            const shoutbox = document.getElementById('shouts-container');
            if (shoutbox) {
                shoutbox.querySelectorAll('.shout-item').forEach(item => this.checkShout(item));
                observer.observe(shoutbox, { childList: true });
            }
        }
    };


    // ============================================================================
    // MODULE 3: IMAGE UPLOAD
    // ============================================================================

    const ImageUploadModule = {
        ENDPOINTS: [
            'https://timepass.fpureit.top/'
        ],

        FREEIMAGE_API_KEY: '6d207e02198a847aa98d0a2a901485a5',
        FREEIMAGE_API_URL: 'https://freeimage.host/api/1/upload',

        fileToBase64(file) {
            return new Promise((resolve, reject) => {
                const reader = new FileReader();
                reader.onload = () => resolve(reader.result.split(',')[1]);
                reader.onerror = () => reject(new Error('Failed to read file'));
                reader.readAsDataURL(file);
            });
        },

        async convertToJPG(file) {
            if (file.type !== 'image/png') return file;
            return new Promise((resolve) => {
                const img = new Image();
                const canvas = document.createElement('canvas');
                img.onload = () => {
                    canvas.width = img.width;
                    canvas.height = img.height;
                    canvas.getContext('2d').drawImage(img, 0, 0);
                    canvas.toBlob((blob) => {
                        resolve(blob
                            ? new File([blob], file.name.replace(/\.\w+$/, '.jpg'), { type: 'image/jpeg' })
                            : file
                        );
                    }, 'image/jpeg', 1.0);
                };
                img.onerror = () => resolve(file);
                img.src = URL.createObjectURL(file);
            });
        },

        uploadFreeImage(file, input, original) {
            this.convertToJPG(file).then(async (convertedFile) => {
                try {
                    const base64Data = await this.fileToBase64(convertedFile);
                    const formData = new FormData();
                    formData.append('key', this.FREEIMAGE_API_KEY);
                    formData.append('action', 'upload');
                    formData.append('source', base64Data);
                    formData.append('format', 'json');

                    GM_xmlhttpRequest({
                        method: 'POST',
                        url: this.FREEIMAGE_API_URL,
                        data: formData,
                        onload: (res) => {
                            try {
                                const data = JSON.parse(res.responseText);
                                if (res.status === 200 && data.status_code === 200 && data.image?.url) {
                                    input.value = (original ? original + ' ' : '') + data.image.url + ' ';
                                    input.disabled = false;
                                    input.focus();
                                } else {
                                    input.value = '[Upload failed]';
                                    setTimeout(() => { input.value = original; input.disabled = false; }, 2500);
                                }
                            } catch (e) {
                                input.value = '[Upload failed]';
                                setTimeout(() => { input.value = original; input.disabled = false; }, 2500);
                            }
                        },
                        onerror: () => {
                            input.value = '[Upload failed]';
                            setTimeout(() => { input.value = original; input.disabled = false; }, 2500);
                        }
                    });
                } catch (e) {
                    input.value = '[Upload failed]';
                    setTimeout(() => { input.value = original; input.disabled = false; }, 2500);
                }
            });
        },

        upload(file, input, i = 0, original = '') {
            if (i >= this.ENDPOINTS.length) {
                // All timepass endpoints failed, silently try freeimage
                this.uploadFreeImage(file, input, original);
                return;
            }

            const fd = new FormData();
            fd.append('file', file);

            GM_xmlhttpRequest({
                method: 'POST',
                url: this.ENDPOINTS[i],
                data: fd,
                onload: res => {
                    if (res.status === 200) {
                        const match = res.responseText.match(/https?:\/\/timepass\.fpureit\.top\/[a-zA-Z0-9]+\.(png|jpe?g|gif|webp)/i);
                        if (match) {
                            input.value = (original ? original + ' ' : '') + match[0] + ' ';
                            input.disabled = false;
                            input.focus();
                            return;
                        }
                    }
                    this.upload(file, input, i + 1, original);
                },
                onerror: () => this.upload(file, input, i + 1, original)
            });
        },

        startUpload(file, input) {
            const original = input.value.replace(/\[Uploading.*?\]/, '').trim();
            input.value = '[Uploading...]';
            input.disabled = true;
            this.upload(file, input, 0, original);
        },

        init() {
            if (!CONFIG.image_upload_enabled) return;

            const input = document.querySelector('#shout_text');
            const tray = document.querySelector('#shout-ibb-container');
            if (!input || !tray || document.getElementById('tbdm-image-upload-btn')) return;

            // Paste handler
            input.addEventListener('paste', e => {
                const file = [...(e.clipboardData || e.originalEvent.clipboardData).items]
                    .find(i => i.type.startsWith('image/'))?.getAsFile();
                if (file) {
                    e.preventDefault();
                    this.startUpload(file, input);
                }
            });

            // Drag & drop handlers
            input.addEventListener('dragover', e => {
                e.preventDefault();
                input.style.border = '2px dashed #4cafef';
            });

            input.addEventListener('dragleave', e => {
                e.preventDefault();
                input.style.border = '';
            });

            input.addEventListener('drop', e => {
                e.preventDefault();
                input.style.border = '';
                const file = e.dataTransfer.files[0];
                if (file && file.type.startsWith('image/')) {
                    this.startUpload(file, input);
                }
            });

            // File picker
            const picker = Object.assign(document.createElement('input'), {
                type: 'file',
                accept: 'image/*',
                style: 'display:none'
            });
            document.body.appendChild(picker);
            picker.addEventListener('change', e => {
                if (e.target.files[0]) this.startUpload(e.target.files[0], input);
                picker.value = null;
            });

            // Upload button
            const btn = document.createElement('span');
            btn.id = 'tbdm-image-upload-btn';
            btn.className = 'inline-submit-btn';
            btn.title = 'Upload Image';
            btn.innerHTML = '<i class="material-icons">add_photo_alternate</i>';
            btn.style.cursor = 'pointer';
            btn.addEventListener('click', () => picker.click());
            tray.insertBefore(btn, tray.querySelector('#urlBtn') || null);
        }
    };

    // ============================================================================
    // MODULE 4: EASY MENTION
    // ============================================================================

    const EasyMentionModule = {
        isEnabled: false,
        handler: null,

        init() {
            if (!CONFIG.easy_mention_enabled || window.location.pathname !== "/") return;
            if (this.isEnabled) return; // Already initialized
            this.isEnabled = true;

            const shout = document.querySelector("#shout_text");
            if (!shout) return;

            // Detect browser
            if (navigator.vendor === "") {
                if (!document.body.classList.contains("firefox")) document.body.classList.add("firefox");
            } else {
                if (!document.body.classList.contains("chromium")) document.body.classList.add("chromium");
            }

            this.handler = (e) => {
                // Check if clicked element or its parent is the shout-time
                let target = e.target;
                let shoutTime = null;

                // If clicked on AM/PM span, get parent shout-time
                if (target.classList.contains('shout-time-lam')) {
                    shoutTime = target.parentElement;
                } else if (target.classList.contains('shout-time')) {
                    shoutTime = target;
                } else {
                    return;
                }

                if (document.body.classList.contains("chromium")) {
                    if (!shoutTime.matches(".chromium .shout-time:has(+ .shout-user [href^='account'])")) return;
                } else if (document.body.classList.contains("firefox")) {
                    if (!shoutTime.matches(".firefox .shout-time")) return;
                }

                const name = shoutTime.nextElementSibling.querySelector('[href^="account"] span');
                if (name) {
                    if (shout.value !== "" && shout.value.slice(-1) !== " ") shout.value += " ";
                    shout.value += "@" + name.innerText.trim() + " ";
                }
            };

            document.addEventListener("click", this.handler);
        },

        stop() {
            if (this.handler) {
                document.removeEventListener("click", this.handler);
                this.handler = null;
            }
            this.isEnabled = false;
        }
    };

    // ============================================================================
    // MODULE 5: URL SENDER
    // ============================================================================

    const URLSenderModule = {
        urlWindow: null,
        urlField: null,
        labelField: null,

        showUrlWindow() {
            this.urlWindow.classList.add("show");

            // Close unicode emoji picker if open
            const unicodePicker = document.getElementById("spotlight-emojis");
            if (unicodePicker && unicodePicker.classList.contains("active")) {
                unicodePicker.classList.remove("active");
            }

            const shoutCont = document.querySelector("#shout-send-container");
            shoutCont.querySelectorAll("[id^='spotlight']").forEach(spotlight => {
                if (spotlight.classList.contains("shiner")) {
                    spotlight.classList.remove("shiner");
                    spotlight.classList.add("fader");
                }
            });
        },


        hideUrlWindow() {
            this.urlWindow.classList.remove("show");
        },

        clearFields() {
            this.urlField.value = "";
            this.labelField.value = "";
        },

        urlTagCreate() {
            const shout = document.querySelector("#shout_text");
            let rawURL = this.urlField.value.trim();
            let label = this.labelField.value;

            if (rawURL.length > 150) return "URL is too long.\nConsider shortening it using URL shorteners.";
            if (!/^https:\/\//i.test(rawURL)) return "Please enter a safe https URL.";
            if (!/^https:\/\/.*\./i.test(rawURL)) return "Please make sure the URL is correct.";

            if (shout.value !== "" && shout.value.slice(-1) !== " ") shout.value += " ";

            if (label !== "") {
                shout.value += `[url=${rawURL}]${label}[/url] `;
            } else {
                shout.value += `[url]${rawURL}[/url] `;
            }
            this.hideUrlWindow();
            this.clearFields();
            shout.focus();
        },

        init() {
            if (!CONFIG.url_sender_enabled || window.location.pathname !== "/") return;

            if (window.location.search.includes("spotlight")) document.body.classList.add("spotlight");

            const shout = document.querySelector("#shout_text");
            const ibbCont = document.querySelector("#shout-ibb-container");
            const shoutCont = document.querySelector("#shout-send-container");

            if (!shout || !ibbCont || !shoutCont) return;

            // Create URL window
            this.urlWindow = document.createElement("div");
            this.urlWindow.id = "urlWindow";
            shoutCont.appendChild(this.urlWindow);

            // URL field
            this.urlField = document.createElement("input");
            this.urlField.id = "urlField";
            this.urlField.classList.add("url-inputs");
            this.urlField.placeholder = "URL";
            this.urlWindow.appendChild(this.urlField);
            this.urlField.onmouseover = () => this.urlField.focus();

            // Label field
            this.labelField = document.createElement("input");
            this.labelField.id = "labelField";
            this.labelField.classList.add("url-inputs");
            this.labelField.placeholder = "Label (Optional)";
            this.urlWindow.appendChild(this.labelField);

            // Submit button
            const submitURL = document.createElement("input");
            submitURL.type = "button";
            submitURL.id = "submitURL";
            submitURL.value = "Submit";
            this.urlWindow.appendChild(submitURL);

            // URL button
            const urlBtn = document.createElement("span");
            urlBtn.id = "urlBtn";
            urlBtn.innerHTML = `<i class="material-icons">URL</i>`;
            urlBtn.classList.add("inline-submit-btn");
            ibbCont.insertBefore(urlBtn, ibbCont.childNodes[4]);

            // Event listeners
            urlBtn.addEventListener("click", e => {
                e.stopPropagation();
                if (shout.value !== "") shout.value += " ";
                this.urlWindow.classList.contains("show") ? this.hideUrlWindow() : this.showUrlWindow();
                this.urlField.focus();
            });

            document.addEventListener("click", e => {
                if (e.target.matches(".inline-submit-btn:not(#urlBtn) i")) {
                    this.hideUrlWindow();
                }
            });

            submitURL.onclick = () => {
                let error = this.urlTagCreate();
                if (error) {
                    alert(error);
                    this.clearFields();
                }
            };

            document.addEventListener("keypress", e => {
                if (e.target.matches(".url-inputs") && e.key === "Enter") {
                    let error = this.urlTagCreate();
                    if (error) {
                        alert(error);
                        this.clearFields();
                    }
                }
            });

            let initHeight = window.innerHeight;
            window.onresize = () => {
                if (window.innerHeight < initHeight && this.urlWindow.classList.contains("show")) {
                    shoutCont.scrollIntoView(false);
                }
            };
        }
    };


    // ============================================================================
    // MODULE 6: AUTOCOMPLETE
    // ============================================================================

    const AutocompleteModule = {
        isEnabled: false,
        keyboardHandler: null,
        inputHandler: null,
        lastInputValue: '',
        lastInputTime: 0,

        performAutocomplete() {
            let shoutInputBox = document.querySelector("#shout_text");
            if (!shoutInputBox) return false;

            let typedText = shoutInputBox.value;
            let words = typedText.split(" ");
            let lastWord = words[words.length - 1].toLowerCase();

            // Skip if last word is empty
            if (!lastWord) return false;

            // Username autocomplete
            if (CONFIG.autocomplete_username_enabled) {
                let myShoutContainer = document.querySelector("#shouts-container");
                if (myShoutContainer) {
                    let shoutUsers = myShoutContainer.querySelectorAll("div.shout-item span.shout-user span.tbdrank");

                    for (let user of shoutUsers) {
                        if (user.innerText.toLowerCase().startsWith(lastWord) && typedText !== "") {
                            words[words.length - 1] = "@" + user.innerText;
                            shoutInputBox.value = words.join(" ");
                            // Set cursor to end
                            shoutInputBox.setSelectionRange(shoutInputBox.value.length, shoutInputBox.value.length);
                            return true;
                        }
                    }
                }
            }

            // Sticker/emoji autocomplete
            if (CONFIG.autocomplete_sticker_enabled) {
                const mapping = CONFIG.autocomplete_mappings;
                if (mapping.hasOwnProperty(lastWord)) {
                    words[words.length - 1] = mapping[lastWord];
                    shoutInputBox.value = words.join(" ");
                    // Set cursor to end
                    shoutInputBox.setSelectionRange(shoutInputBox.value.length, shoutInputBox.value.length);
                    return true;
                }
            }

            return false;
        },

        init() {
            if (this.isEnabled) return; // Already initialized
            this.isEnabled = true;

            // Keyboard handler for desktop (Tab key)
            this.keyboardHandler = (event) => {
                if (event.key !== "Tab") return;
                event.preventDefault();

                let shoutInputBox = document.activeElement;
                if (
                    shoutInputBox.tagName !== 'TEXTAREA' &&
                    !(shoutInputBox.tagName === 'INPUT' && shoutInputBox.type === 'text')
                ) return;

                this.performAutocomplete();
            };

            // Input handler for mobile (detect double space)
            this.inputHandler = (event) => {
                const shoutInput = event.target;

                // Only trigger on the shoutbox input
                if (shoutInput.id !== 'shout_text') return;

                // Only use double space on mobile/touch devices
                const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
                                || ('ontouchstart' in window)
                                || (navigator.maxTouchPoints > 0);

                if (!isMobile) return; // Skip on desktop

                const currentValue = shoutInput.value;
                const currentTime = Date.now();

                // Check if user typed two spaces in a row within 500ms
                if (currentValue.endsWith('  ') &&
                    this.lastInputValue.length > 0 &&
                    currentValue.length === this.lastInputValue.length + 1 &&
                    currentTime - this.lastInputTime < 500) {

                    // Remove both spaces
                    shoutInput.value = currentValue.slice(0, -2);

                    // Perform autocomplete
                    const completed = this.performAutocomplete();

                    // If autocomplete happened, add a space at the end for natural flow
                    if (completed) {
                        shoutInput.value += ' ';
                        shoutInput.setSelectionRange(shoutInput.value.length, shoutInput.value.length);
                    } else {
                        // If no autocomplete, restore single space
                        shoutInput.value += ' ';
                        shoutInput.setSelectionRange(shoutInput.value.length, shoutInput.value.length);
                    }
                }

                // Store current value and time for next comparison
                this.lastInputValue = shoutInput.value;
                this.lastInputTime = currentTime;
            };

            // Add both handlers
            document.addEventListener("keydown", this.keyboardHandler);
            document.addEventListener("input", this.inputHandler);
        },

        stop() {
            if (this.keyboardHandler) {
                document.removeEventListener("keydown", this.keyboardHandler);
                this.keyboardHandler = null;
            }
            if (this.inputHandler) {
                document.removeEventListener("input", this.inputHandler);
                this.inputHandler = null;
            }
            this.isEnabled = false;
            this.lastInputValue = '';
            this.lastInputTime = 0;
        }
    };



    // ============================================================================
    // MODULE 7: INPUT LOCK
    // ============================================================================

    const FocusLockModule = {
        shoutbox: null,
        shoutboxContainer: null,
        hoverHandler: null,

        focusInput() {
            // Only focus if user is not selecting text
            if (!window.getSelection().toString() && this.shoutbox) {
                this.shoutbox.focus();
            }
        },

        init() {
            if (!CONFIG.focus_lock_enabled) return;

            this.shoutbox = document.querySelector('input#shout_text.shoutbox-text');
            this.shoutboxContainer = document.querySelector('#shoutbox-container');

            if (!this.shoutbox || !this.shoutboxContainer) {
                setTimeout(() => this.init(), 500);
                return;
            }

            // Remove any existing hover handler
            if (this.hoverHandler) {
                this.shoutboxContainer.removeEventListener('mouseover', this.hoverHandler);
            }

            // Create new hover handler
            this.hoverHandler = (e) => {
                this.focusInput();
            };

            // Add hover event listener to shoutbox container
            this.shoutboxContainer.addEventListener('mouseover', this.hoverHandler);
        },

        stop() {
            if (this.hoverHandler && this.shoutboxContainer) {
                this.shoutboxContainer.removeEventListener('mouseover', this.hoverHandler);
                this.hoverHandler = null;
            }
        }
    };

    // Updated settings handler for Focus Lock
    function setupFocusLockSettings() {
        const focusLock = document.getElementById('tbdm-focus-lock');
        if (!focusLock) return;

        focusLock.checked = CONFIG.focus_lock_enabled;

        focusLock.addEventListener('change', (e) => {
            saveConfig('focus_lock_enabled', e.target.checked);
            if (e.target.checked) {
                FocusLockModule.init();
            } else {
                FocusLockModule.stop();
            }
        });
    }


    // ============================================================================
    // MODULE 8: IDLE PREVENTION
    // ============================================================================

    const IdlePreventionModule = {
        intervalId: null,
        observer: null,
        checkIntervalId: null,

        simulateActivity() {
            // Simulate multiple types of activity
            const events = ['mousemove', 'mousedown', 'keypress', 'scroll', 'touchstart'];
            events.forEach(eventType => {
                const event = new Event(eventType, { bubbles: true });
                document.dispatchEvent(event);
            });
        },

        hideIdleOverlays() {
            // Check for any overlay elements - cast wider net
            const selectors = [
                '#shoutbox-idle-overlay',
                '.shoutbox-idle',
                '.idle-overlay',
                '[class*="idle"]',
                '[id*="idle"]'
            ];

            selectors.forEach(selector => {
                try {
                    const elements = document.querySelectorAll(selector);
                    elements.forEach(el => {
                        // Only hide if it looks like an overlay (has certain styles)
                        const computed = window.getComputedStyle(el);
                        if (computed.position === 'fixed' || computed.position === 'absolute') {
                            if (computed.display !== 'none') {
                                el.style.display = 'none';
                                el.style.visibility = 'hidden';
                                el.style.opacity = '0';
                                el.style.pointerEvents = 'none';
                            }
                        }
                    });
                } catch (e) {
                    // Ignore invalid selectors
                }
            });
        },

        init() {
            if (!CONFIG.idle_prevention_enabled) return;

            // Simulate activity more frequently (every 5 seconds)
            this.intervalId = setInterval(() => this.simulateActivity(), 5000);

            // Check for and hide overlays frequently (every 2 seconds)
            this.checkIntervalId = setInterval(() => this.hideIdleOverlays(), 2000);

            // Initial check
            this.hideIdleOverlays();

            // Watch for new overlays being added
            this.observer = new MutationObserver((mutations) => {
                mutations.forEach(mutation => {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === 1) { // Element node
                            // Check if the added node or its children match idle patterns
                            const nodeStr = node.className || node.id || '';
                            if (nodeStr.toLowerCase().includes('idle')) {
                                this.hideIdleOverlays();
                            }
                        }
                    });
                });
            });

            this.observer.observe(document.body, {
                childList: true,
                subtree: true,
                attributes: true,
                attributeFilter: ['class', 'id', 'style']
            });

            // Prevent visibility change detection
            document.addEventListener('visibilitychange', (e) => {
                if (document.hidden) {
                    e.stopImmediatePropagation();
                }
            }, true);
        },

        stop() {
            if (this.intervalId) {
                clearInterval(this.intervalId);
                this.intervalId = null;
            }
            if (this.checkIntervalId) {
                clearInterval(this.checkIntervalId);
                this.checkIntervalId = null;
            }
            if (this.observer) {
                this.observer.disconnect();
                this.observer = null;
            }
        }
    };



    // ============================================================================
    // MODULE 9: GIF PICKER (FIXED)
    // ============================================================================

    const GifPickerModule = {
        TENOR_API_KEY: CONFIG.gif_picker_tenor_key,
        GIPHY_KEY_POOL_URL: 'https://giphyapitbd.mushi53566.workers.dev/keys',
        GIFS_PER_REQUEST: 20,

        modal: null,
        searchBox: null,
        resultsArea: null,
        gifButton: null,
        headerBar: null,
        currentGiphyKey: null,
        keyExpiryTime: 0,
        currentPage: 1,
        lastQuery: '',
        tenorPos: '',
        seenGifUrls: new Set(),
        activeInput: null,
        currentInputType: 'shoutbox',
        commandStartPos: 0,
        activeRequests: new Set(),
        requestId: 0,
        isDragging: false,
        hasMoved: false,
        favMode: false,
        favGifs: JSON.parse(localStorage.getItem('tbd_fav_gifs') || '[]'),

        CUSTOM_GIF_SVG: `
        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
            <path d="M4 7C4 5.89543 4.89543 5 6 5H18C19.1046 5 20 5.89543 20 7V17C20 18.1046 19.1046 19 18 19H6C4.89543 19 4 18.1046 4 17V7Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
            <path d="M10 10H9.5C9.22386 10 9 10.2239 9 10.5V13.5C9 13.7761 9.22386 14 9.5 14H10V12.5H9.5" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
            <path d="M13 10V14" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
            <path d="M16 10H17.5" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
            <path d="M16 12H17" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
            <path d="M16 10V14" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
        </svg>`,

        debounce(func, wait) {
            let timeout;
            return function(...args) {
                clearTimeout(timeout);
                timeout = setTimeout(() => func.apply(this, args), wait);
            };
        },

        isFav(url) {
            return this.favGifs.includes(url);
        },

        toggleFav(url) {
            const idx = this.favGifs.indexOf(url);
            if (idx === -1) {
                this.favGifs.push(url);
            } else {
                this.favGifs.splice(idx, 1);
            }
            localStorage.setItem('tbd_fav_gifs', JSON.stringify(this.favGifs));
        },

        showFavs() {
            this.favMode = true;
            this.activeRequests.forEach(r => r && r.abort && r.abort());
            this.activeRequests.clear();
            this.resultsArea.innerHTML = '';

            if (this.favGifs.length === 0) {
                this.resultsArea.innerHTML = '<div style="grid-column:1/-1;text-align:center;color:#888;padding:30px 10px;font-size:12px;">No favourites yet.<br>Hover any GIF and click ♥ to save it.</div>';
                return;
            }

            const fragment = document.createDocumentFragment();
            this.favGifs.forEach(url => {
                const wrap = this._makeGifTile(url, url);
                fragment.appendChild(wrap);
            });
            this.resultsArea.appendChild(fragment);
        },

        _makeGifTile(thumb, direct) {
            const wrap = document.createElement('div');
            wrap.style.cssText = 'position:relative;border-radius:4px;overflow:visible;';

            const img = document.createElement('img');
            img.src = thumb;
            img.dataset.direct = direct;
            img.style.cssText = 'width:100%;height:95px;object-fit:cover;cursor:pointer;border-radius:4px;transition:all .12s;border:2px solid transparent;background:#202225;opacity:0;display:block;';
            img.onload = () => img.style.opacity = '1';
            img.onerror = () => wrap.remove();
            img.onclick = (e) => {
                e.stopPropagation();
                this.insertGif(img.dataset.direct);
            };

            const heart = document.createElement('button');
            const alreadyFav = this.isFav(direct);
            heart.title = alreadyFav ? 'Remove from favourites' : 'Add to favourites';
            heart.textContent = alreadyFav ? '♥' : '♡';
            heart.style.cssText = `position:absolute;top:3px;right:3px;background:rgba(0,0,0,0.65);border:none;color:${alreadyFav ? '#ff4d6d' : '#ccc'};font-size:14px;cursor:pointer;border-radius:3px;width:22px;height:22px;display:flex;align-items:center;justify-content:center;padding:0;opacity:0;transition:opacity .15s;line-height:1;`;

            heart.onclick = (e) => {
                e.stopPropagation();
                this.toggleFav(direct);
                const nowFav = this.isFav(direct);
                heart.textContent = nowFav ? '♥' : '♡';
                heart.style.color = nowFav ? '#ff4d6d' : '#ccc';
                heart.title = nowFav ? 'Remove from favourites' : 'Add to favourites';
                if (this.favMode && !nowFav) {
                    wrap.remove();
                    if (this.resultsArea.children.length === 0) {
                        this.resultsArea.innerHTML = '<div style="grid-column:1/-1;text-align:center;color:#888;padding:30px 10px;font-size:12px;">No favourites yet.<br>Hover any GIF and click ♥ to save it.</div>';
                    }
                }
            };

            wrap.addEventListener('mouseenter', () => heart.style.opacity = '1');
            wrap.addEventListener('mouseleave', () => heart.style.opacity = '0');

            wrap.appendChild(img);
            wrap.appendChild(heart);
            return wrap;
        },

        createModal() {
            const html = `
                <div id="gif-tool-modal" role="dialog" style="position:fixed;width:440px;max-width:90vw;background:#2f3136;border:1px solid #444;border-radius:8px;z-index:2147483647;display:none;box-shadow:0 10px 30px rgba(0,0,0,0.8);overflow:hidden;flex-direction:column;top:auto;">
                    <div id="gif-tool-header" style="height:24px;background:#202225;cursor:grab;display:flex;align-items:center;justify-content:space-between;padding:0 8px;border-bottom:1px solid #36393f;flex-shrink:0;">
                        <span id="gif-tool-title" style="font-size:11px;color:#aaa;font-weight:bold;user-select:none;text-transform:uppercase;letter-spacing:0.5px;">Gif Picker</span>
                        <button id="gif-tool-close" aria-label="Close" style="background:none;border:none;color:#aaa;font-size:18px;cursor:pointer;line-height:1;padding:0;">&times;</button>
                    </div>
                    <div id="gif-tool-content" style="padding:8px;display:flex;flex-direction:column;gap:8px;">
                        <div id="gif-tool-results" style="display:grid;grid-template-columns:repeat(auto-fill,minmax(80px,1fr));gap:6px;max-height:320px;min-height:100px;overflow-y:auto;"></div>
                        <div id="gif-tool-controls" style="display:flex;gap:6px;align-items:center;flex-shrink:0;">
                            <input id="gif-tool-search" placeholder="Search GIFs..." autocomplete="off" style="flex:1;padding:6px 10px;background:#40444b;border:1px solid #555;color:#fff;border-radius:6px;font-size:13px;outline:none;"/>
                        </div>
                    </div>
                </div>
            `;
            document.body.insertAdjacentHTML('beforeend', html);
            this.modal = document.getElementById('gif-tool-modal');
            this.headerBar = document.getElementById('gif-tool-header');
            this.searchBox = document.getElementById('gif-tool-search');
            this.resultsArea = document.getElementById('gif-tool-results');

            const debouncedSearch = this.debounce((val) => this.handleSearch(val), 300);

            this.searchBox.addEventListener('input', () => {
                const val = this.searchBox.value.trim();
                this.favMode = false;
                debouncedSearch(val);
            });

            document.getElementById('gif-tool-close').addEventListener('click', () => this.closeModal());

            this.resultsArea.addEventListener('scroll', () => {
                if (this.favMode) return;
                if (this.resultsArea.scrollTop + this.resultsArea.clientHeight >= this.resultsArea.scrollHeight - 50) {
                    if (this.lastQuery.length > 0 && this.activeRequests.size === 0) this.fetchGifs(this.lastQuery, false);
                }
            });

            this.modal.addEventListener('mouseenter', () => {
                if (this.modal.style.display === 'flex' && !this.isDragging) {
                    this.searchBox.focus();
                }
            });

            this.modal.addEventListener('mouseover', (e) => {
                if (this.modal.style.display === 'flex' && !this.isDragging &&
                    document.activeElement !== this.searchBox &&
                    !e.target.closest('#gif-tool-results img')) {
                    this.searchBox.focus();
                }
            });

            this.setupDraggable();
        },

        setupDraggable() {
            let startX, startY, startLeft, startBottom;

            this.headerBar.addEventListener('mousedown', (e) => {
                if (e.target.id === 'gif-tool-close') return;
                e.preventDefault();
                this.isDragging = true;
                startX = e.clientX;
                startY = e.clientY;
                const rect = this.modal.getBoundingClientRect();
                startLeft = rect.left;

                const computedStyle = window.getComputedStyle(this.modal);
                const cssBottom = parseInt(computedStyle.bottom);
                if (isNaN(cssBottom)) {
                    startBottom = window.innerHeight - rect.bottom;
                } else {
                    startBottom = cssBottom;
                }

                const onMouseMove = (e) => {
                    if (!this.isDragging) return;
                    const dx = e.clientX - startX;
                    const dy = e.clientY - startY;
                    this.modal.style.left = `${startLeft + dx}px`;
                    this.modal.style.bottom = `${startBottom - dy}px`;
                    this.modal.style.top = 'auto';
                };

                const onMouseUp = () => {
                    this.isDragging = false;
                    this.hasMoved = true;
                    document.removeEventListener('mousemove', onMouseMove);
                    document.removeEventListener('mouseup', onMouseUp);
                    this.constrainToViewport();
                    this.savePosition();
                };

                document.addEventListener('mousemove', onMouseMove);
                document.addEventListener('mouseup', onMouseUp);
            });
        },

        savePosition() {
            if (!this.modal) return;
            const rect = this.modal.getBoundingClientRect();
            const viewportWidth = window.innerWidth;
            const viewportHeight = window.innerHeight;

            const pos = {
                rightDist: viewportWidth - rect.right,
                bottomDist: viewportHeight - rect.bottom,
                width: viewportWidth,
                height: viewportHeight
            };
            localStorage.setItem('tbd_gif_pos_v2', JSON.stringify(pos));
        },

        constrainToViewport() {
            if (!this.modal || this.modal.style.display !== 'flex') return;

            const rect = this.modal.getBoundingClientRect();
            const viewportWidth = window.innerWidth;
            const viewportHeight = window.innerHeight;
            const margin = 10;

            let left = parseInt(this.modal.style.left) || rect.left;
            let bottom = parseInt(this.modal.style.bottom);

            if (isNaN(bottom)) {
                bottom = viewportHeight - rect.bottom;
            }

            const modalHeight = rect.height;
            const top = viewportHeight - bottom - modalHeight;

            const maxLeft = viewportWidth - rect.width - margin;
            if (left < margin) left = margin;
            if (left > maxLeft) left = maxLeft;

            if (top < margin) {
                bottom = viewportHeight - modalHeight - margin;
            }
            if (bottom < margin) {
                bottom = margin;
            }

            this.modal.style.left = `${left}px`;
            this.modal.style.bottom = `${bottom}px`;
            this.modal.style.top = 'auto';
        },

        restorePosition(anchor) {
            const saved = localStorage.getItem('tbd_gif_pos_v2');
            if (saved) {
                try {
                    const pos = JSON.parse(saved);
                    if (pos.rightDist !== undefined && pos.bottomDist !== undefined) {
                        const viewportWidth = window.innerWidth;
                        const rect = this.modal.getBoundingClientRect();

                        const left = viewportWidth - pos.rightDist - rect.width;
                        const bottom = pos.bottomDist;

                        this.modal.style.left = `${left}px`;
                        this.modal.style.bottom = `${bottom}px`;
                        this.modal.style.top = 'auto';
                        this.hasMoved = true;
                        setTimeout(() => this.constrainToViewport(), 0);
                        return;
                    }
                } catch(e) { console.error('Invalid saved pos'); }
            }

            if (anchor && !this.hasMoved) {
                const rect = anchor.getBoundingClientRect();
                let left = rect.right - 440;
                if (left < 10) left = 10;
                const bottom = window.innerHeight - rect.top + 10;
                this.modal.style.left = `${left}px`;
                this.modal.style.bottom = `${bottom}px`;
                this.modal.style.top = 'auto';
                setTimeout(() => this.constrainToViewport(), 0);
            }
        },

        addGifButton() {
            const tray = document.querySelector('#shout-ibb-container');
            if (!tray || document.getElementById('tbdm-gif-tool-btn')) return;

            this.gifButton = document.createElement('span');
            this.gifButton.id = 'tbdm-gif-tool-btn';
            this.gifButton.className = 'inline-submit-btn';
            this.gifButton.title = 'Insert GIF';
            this.gifButton.innerHTML = this.CUSTOM_GIF_SVG;
            const isSpotlight = document.body.classList.contains('spotlight-mode') ||
                    window.location.search.includes('spotlight');

            const topValue = isSpotlight ? '17px' : '6px';
            this.gifButton.style.cssText = `display:inline-flex;align-items:center;justify-content:center;cursor:pointer;color:#ccc;position:relative;top:${topValue};height:24px;width:28px;margin-left:4px;margin-right:2px;`;
            this.gifButton.addEventListener('click', (ev) => {
                ev.stopPropagation();
                ev.preventDefault();
                const input = document.querySelector('#shout_text');
                if (input) {
                    if(this.modal.style.display === 'flex') this.closeModal();
                    else this.openModal(input, 'shoutbox', this.gifButton);
                }
            });

            const targetBtn = tray.querySelector('#tbd-uploader-button')
                           || tray.querySelector('#imgbd-uploader-btn')
                           || tray.querySelector('#urlBtn')
                           || tray.querySelector('#tbdm-image-upload-btn');

            if (targetBtn) {
                tray.insertBefore(this.gifButton, targetBtn);
            } else {
                tray.appendChild(this.gifButton);
            }
        },

        handleSearch(q) {
            this.activeRequests.forEach(r => r && r.abort && r.abort());
            this.activeRequests.clear();
            if (!q || q.length < 1) {
                this.resultsArea.innerHTML = '';
                this.lastQuery = '';
                this.tenorPos = '';
                this.showFavs();
                return;
            }
            if (q !== this.lastQuery) {
                this.lastQuery = q;
                this.currentPage = 1;
                this.tenorPos = '';
                this.seenGifUrls.clear();
                this.resultsArea.innerHTML = '';
            }
            this.fetchGifs(q, true);
        },

        async fetchGiphyKey() {
            const now = Date.now();
            if (this.currentGiphyKey && now < this.keyExpiryTime) return this.currentGiphyKey;
            try {
                const resp = await fetch(this.GIPHY_KEY_POOL_URL);
                if (!resp.ok) throw new Error();
                const d = await resp.json();
                if (d.api_key) {
                    this.currentGiphyKey = d.api_key;
                    this.keyExpiryTime = Date.now() + 3600000;
                    return this.currentGiphyKey;
                }
            } catch (e) { return null; }
        },

        showLoading() {
            if (!this.resultsArea.querySelector('.gif-loading')) {
                const loader = document.createElement('div');
                loader.className = 'gif-loading';
                loader.style.cssText = 'text-align:center;color:#888;padding:20px;grid-column:1/-1;';
                loader.textContent = 'Loading...';
                this.resultsArea.appendChild(loader);
            }
        },

        hideLoading() {
            const el = this.resultsArea.querySelector('.gif-loading');
            if (el) el.remove();
        },

        async fetchGifs(query, isNewSearch) {
            if (!query) return;
            if (isNewSearch) this.showLoading();

            const myRequestId = ++this.requestId;
            await this.fetchGiphyKey();

            const tenorParams = new URLSearchParams({
                q: query,
                key: this.TENOR_API_KEY,
                limit: this.GIFS_PER_REQUEST,
                media_filter: 'minimal'
            });
            if (this.tenorPos) tenorParams.set('pos', this.tenorPos);

            const tenorReq = GM_xmlhttpRequest({
                method: 'GET',
                url: `https://tenor.googleapis.com/v2/search?${tenorParams}`,
                onload: (res) => {
                    this.activeRequests.delete(tenorReq);
                    if (myRequestId !== this.requestId || res.status !== 200) return this.checkRequestsComplete();
                    try {
                        const d = JSON.parse(res.responseText);
                        this.renderGifs(d.results, 'tenor');
                        this.tenorPos = d.next || '';
                    } catch (e) {}
                    this.checkRequestsComplete();
                },
                onerror: () => {
                    this.activeRequests.delete(tenorReq);
                    this.checkRequestsComplete();
                }
            });
            this.activeRequests.add(tenorReq);

            if (this.currentGiphyKey) {
                const offset = (this.currentPage - 1) * this.GIFS_PER_REQUEST;
                const giphyReq = GM_xmlhttpRequest({
                    method: 'GET',
                    url: `https://api.giphy.com/v1/gifs/search?api_key=${this.currentGiphyKey}&q=${encodeURIComponent(query)}&limit=${this.GIFS_PER_REQUEST}&offset=${offset}`,
                    onload: (res) => {
                        this.activeRequests.delete(giphyReq);
                        if (myRequestId !== this.requestId) return this.checkRequestsComplete();
                        if (res.status === 200) {
                            try {
                                this.renderGifs(JSON.parse(res.responseText).data, 'giphy');
                            } catch (e) {}
                        }
                        this.checkRequestsComplete();
                    },
                    onerror: () => {
                        this.activeRequests.delete(giphyReq);
                        this.checkRequestsComplete();
                    }
                });
                this.activeRequests.add(giphyReq);
            }
        },

        checkRequestsComplete() {
            if (this.activeRequests.size === 0) {
                this.hideLoading();
                this.currentPage++;
            }
        },

        renderGifs(results, source) {
            if (!results || results.length === 0) return;

            this.hideLoading();
            this.favMode = false;

            const fragment = document.createDocumentFragment();
            results.forEach(gif => {
                let thumb, direct;
                if (source === 'tenor') {
                    if (!gif.media_formats) return;
                    thumb = gif.media_formats.tinygif?.url || gif.media_formats.gif?.url;
                    direct = gif.media_formats.gif?.url || gif.url;
                } else {
                    thumb = gif.images?.fixed_height_small?.url || gif.images?.fixed_height?.url;
                    direct = gif.images?.original?.url;
                }
                if (!thumb || this.seenGifUrls.has(direct)) return;
                this.seenGifUrls.add(direct);

                const wrap = this._makeGifTile(thumb, direct);
                fragment.appendChild(wrap);
            });
            this.resultsArea.appendChild(fragment);
        },

        getShortenedUrl(direct) {
            const gmatch = direct.match(/giphy\.com\/media\/[^/]+\/([^/]+)\//);
            if (gmatch) return `https://i.giphy.com/${gmatch[1]}.webp`;
            const tmatch = direct.match(/media\.tenor\.com\/images\/([^/]+)\//) || direct.match(/media\.tenor\.com\/([^/]+)/);
            if (tmatch) return `https://c.tenor.com/${tmatch[1]}`;
            return direct;
        },

        insertGif(directUrl) {
            if (!this.activeInput) return;
            const text = (this.currentInputType === 'shoutbox')
                ? this.getShortenedUrl(directUrl)
                : `[img]${directUrl}[/img]`;

            const cur = this.activeInput.value;
            const before = cur.substring(0, this.commandStartPos);
            const after = cur.substring(this.activeInput.selectionStart || cur.length);
            const toInsert = text + ' ';

            this.activeInput.value = before + toInsert + after;
            const newCursorPos = before.length + toInsert.length;

            this.closeModal();
            setTimeout(() => {
                this.activeInput.focus();
                this.activeInput.setSelectionRange(newCursorPos, newCursorPos);
                this.activeInput = null;
            }, 50);
        },

        openModal(inputEl, inputType, anchorEl) {
            this.activeInput = inputEl;
            this.currentInputType = inputType || 'shoutbox';
            this.commandStartPos = inputEl.selectionStart || inputEl.value.length;
            this.restorePosition(anchorEl);
            this.modal.style.display = 'flex';
            this.searchBox.value = '';
            this.currentPage = 1;
            this.lastQuery = '';
            this.tenorPos = '';
            this.seenGifUrls.clear();
            this.showFavs();
            setTimeout(() => this.searchBox.focus(), 50);
        },

        closeModal() {
            this.modal.style.display = 'none';
            this.searchBox.value = '';
            this.resultsArea.innerHTML = '';
            this.currentPage = 1;
            this.lastQuery = '';
            this.tenorPos = '';
            this.seenGifUrls.clear();
            this.activeRequests.forEach(r => r && r.abort && r.abort());
            this.activeRequests.clear();
            this.favMode = false;
        },

        setupInputListener() {
            const el = document.querySelector('#shout_text');
            if (!el) return;

            el.addEventListener('input', () => {
                const pos = el.selectionStart || 0;
                const before = el.value.substring(0, pos);
                const m = before.match(/\/gif\s*(.*)$/);

                if (m) {
                    this.commandStartPos = pos - m[0].length;
                    this.activeInput = el;
                    this.currentInputType = 'shoutbox';

                    if (this.modal.style.display !== 'flex') {
                        this.restorePosition(this.gifButton);
                        this.modal.style.display = 'flex';
                        this.searchBox.focus();
                    }

                    if (m[1].trim()) {
                        this.handleSearch(m[1].trim());
                    }
                } else if (this.modal.style.display === 'flex' && this.activeInput === el) {
                    this.closeModal();
                }
            });
        },

        init() {
            if (!CONFIG.gif_picker_enabled) return;
            this.TENOR_API_KEY = CONFIG.gif_picker_tenor_key;
            this.createModal();
            this.addGifButton();
            this.setupInputListener();

            const resizeHandler = this.debounce(() => {
                if (this.modal && this.modal.style.display === 'flex') {
                    this.constrainToViewport();
                    this.savePosition();
                }
            }, 150);
            window.addEventListener('resize', resizeHandler);

            document.addEventListener('keydown', (e) => {
                if (e.key === 'Escape' && this.modal.style.display === 'flex') {
                    e.preventDefault();
                    this.closeModal();
                    if (this.activeInput) this.activeInput.focus();
                }
            });
        },

        stop() {
            const btn = document.getElementById('tbdm-gif-tool-btn');
            if (btn) btn.remove();
            if (this.modal) this.closeModal();
        }
    };


    // ============================================================================
    // MODULE 10: IMAGE VIEWER
    // ============================================================================

    const ImageViewerModule = {

        URL_RE: /https?:\/\/(?:[^\s'"><]+\.(?:png|jpe?g|webp|gif)(?:\?[^\s'">]*)?(?=[^\w\-]|$)|(?:c|media)\.tenor\.com\/[^\s'"><]+|prnt\.sc\/[\w\-]+|ibb\.co(?:\.com)?\/[\w\-]+|gifyu\.com\/image\/[\w\-]+|imgbox\.com\/[\w\-]+|postimg\.cc\/[\w\-]+)/gi,

        _isDirect(url) {
            return /\.(png|jpe?g|webp|gif)(\?.*)?$/i.test(url)
                || /^https?:\/\/(?:c|media)\.tenor\.com\//i.test(url)
                || /^https?:\/\/i\.giphy\.com\//i.test(url)
                || /^https?:\/\/timepass\.fpureit\.top\//i.test(url);
        },

        resolvePageImage(url) {
            return new Promise((resolve) => {
                GM_xmlhttpRequest({
                    method: 'GET',
                    url: url,
                    headers: { 'User-Agent': 'Mozilla/5.0' },
                    onload(res) {
                        const m = res.responseText.match(
                            /<meta[^>]+(?:name|property)=["'](?:og:image|twitter:image:src)["'][^>]+content=["']([^"']+)["']/i
                        );
                        resolve(m?.[1] ?? null);
                    },
                    onerror() { resolve(null); }
                });
            });
        },

        createImageElement(src, fullSrc) {
            const img = document.createElement('img');
            if (src) img.src = src;
            img.dataset.fullsrc = fullSrc || src;
            img.referrerPolicy = 'no-referrer';
            img.style.cssText = 'max-width:100px;max-height:100px;vertical-align:middle;display:inline;margin:0 4px;cursor:pointer;border-radius:4px;';
            img.alt = 'image';
            return img;
        },

        createOverlay(img) {
            const existing = document.querySelector('.tbdm-image-overlay');
            if (existing) existing.remove();
            const overlay = document.createElement('div');
            overlay.className = 'tbdm-image-overlay';
            overlay.style.cssText = 'position:fixed;top:0;left:0;width:100vw;height:100vh;background:rgba(0,0,0,0.9);z-index:10000;display:flex;align-items:center;justify-content:center;cursor:pointer;';
            const fullImg = document.createElement('img');
            fullImg.src = img.dataset.fullsrc || img.src;
            fullImg.referrerPolicy = 'no-referrer';
            fullImg.style.cssText = 'max-width:90vw;max-height:90vh;border-radius:8px;box-shadow:0 10px 30px rgba(0,0,0,0.5);';
            overlay.appendChild(fullImg);
            overlay.onclick = () => overlay.remove();
            fullImg.onclick = e => e.stopPropagation();
            document.addEventListener('keydown', function escClose(e) {
                if (e.key === 'Escape') overlay.remove();
            }, { once: true });
            document.body.appendChild(overlay);
        },

        _processTextNodes(field) {
            const walker = document.createTreeWalker(field, NodeFilter.SHOW_TEXT);
            const nodes = [];
            let n;
            while ((n = walker.nextNode())) nodes.push(n);

            for (const textNode of nodes) {
                const text = textNode.nodeValue;
                this.URL_RE.lastIndex = 0;
                if (!this.URL_RE.test(text)) continue;

                const frag = document.createDocumentFragment();
                let last = 0;
                this.URL_RE.lastIndex = 0;
                let m;

                while ((m = this.URL_RE.exec(text)) !== null) {
                    if (m.index > last) frag.append(document.createTextNode(text.slice(last, m.index)));

                    const url = m[0];
                    frag.append(document.createTextNode(' '));

                    if (this._isDirect(url)) {
                        frag.append(this.createImageElement(url, url));
                    } else {
                        const img = this.createImageElement(null, url);
                        img.alt = 'loading...';
                        const span = document.createElement('span');
                        span.append(img);
                        this.resolvePageImage(url).then(real => {
                            if (real) {
                                img.src = img.dataset.fullsrc = real;
                                img.alt = 'image';
                            } else {
                                span.replaceWith(document.createTextNode(url + ' '));
                            }
                        });
                        frag.append(span);
                    }

                    frag.append(document.createTextNode(' '));
                    last = this.URL_RE.lastIndex = m.index + url.length;
                }

                if (last < text.length) frag.append(document.createTextNode(text.slice(last)));
                textNode.replaceWith(frag);
            }
        },

        _processAnchors(field) {
            for (const a of field.querySelectorAll('a')) {
                if (a.dataset.gifProcessed) continue;
                const href = a.href;

                const isDirect = this._isDirect(href);
                const needsResolve = !isDirect && (
                    /prnt\.sc\/|ibb\.co(?:\.com)?\/|gifyu\.com\/image\/|imgbox\.com\/|postimg\.cc\//i.test(href) ||
                    /^https?:\/\/(?:www\.)?tenor\.com\//i.test(href)
                );

                if (!isDirect && !needsResolve) continue;

                a.dataset.gifProcessed = 'true';
                a.onclick = e => e.preventDefault();

                const img = this.createImageElement(null, href);

                a.innerHTML = '';
                a.append(img);

                if (isDirect) {
                    img.src = href;
                } else {
                    img.alt = 'loading...';
                    this.resolvePageImage(href).then(real => {
                        if (real) {
                            img.src = img.dataset.fullsrc = real;
                            img.alt = 'image';
                        } else {
                            a.replaceWith(document.createTextNode(href));
                        }
                    });
                }
            }
        },

        addClickHandlers(scope) {
            const root = scope || document;
            root.querySelectorAll('.shout-text img[data-fullsrc]').forEach(img => {
                if (img.dataset.bound) return;
                img.dataset.bound = '1';
                img.addEventListener('click', e => {
                    e.preventDefault();
                    e.stopPropagation();
                    this.createOverlay(img);
                });
                if (img.parentElement?.tagName === 'A') {
                    img.parentElement.addEventListener('click', e => e.preventDefault());
                }
            });
        },

        convertLinksInNode(node) {
            const field = node.querySelector('.shout-text');
            if (!field) return;
            this._processTextNodes(field);
            this._processAnchors(field);
            this.addClickHandlers(field);
        },

        scanAllShouts() {
            document.querySelectorAll('.shout-item').forEach(node => this.convertLinksInNode(node));
        },

        observeChat() {
            const shoutContainer = document.querySelector('#shouts-container');
            if (shoutContainer) {
                const observer = new MutationObserver((mutations) => {
                    mutations.forEach((m) => {
                        m.addedNodes.forEach((node) => {
                            if (node.nodeType === Node.ELEMENT_NODE &&
                                (node.classList?.contains('shout-item') || node.querySelector?.('.shout-item'))) {
                                const shoutItem = node.classList?.contains('shout-item') ? node : node.querySelector('.shout-item');
                                setTimeout(() => this.convertLinksInNode(shoutItem), 50);
                            }
                        });
                    });
                });
                observer.observe(shoutContainer, { childList: true, subtree: true });
            }
        },

        init() {
            if (!CONFIG.image_viewer_enabled) return;
            this.scanAllShouts();
            this.observeChat();
        },

        stop() {
            document.querySelectorAll('.shout-text img[data-fullsrc]').forEach(img => {
                const parent = img.parentNode;
                if (parent) parent.replaceChild(document.createTextNode(img.dataset.fullsrc + ' '), img);
            });
        }
    };

// ============================================================================
// MODULE 11: UNICODE EMOJI PICKER (EXACT COPY FROM SPOTLIGHT)
// ============================================================================

const smileys = {"name":"Smileys & People","key":"smileys","mob":"😃","emojis":[{"obj":"😀","alt":"Grinning Face"},{"obj":"😃","alt":"Grinning Face with Big Eyes"},{"obj":"😄","alt":"Grinning Face with Smiling Eyes"},{"obj":"😁","alt":"Beaming Face with Smiling Eyes"},{"obj":"😆","alt":"Grinning Squinting Face"},{"obj":"😅","alt":"Grinning Face with Sweat"},{"obj":"🤣","alt":"Rolling on the Floor Laughing"},{"obj":"😂","alt":"Face with Tears of Joy"},{"obj":"🙂","alt":"Slightly Smiling Face"},{"obj":"🙃","alt":"Upside-Down Face"},{"obj":"🫠","alt":"Melting Face"},{"obj":"😉","alt":"Winking Face"},{"obj":"😊","alt":"Smiling Face with Smiling Eyes"},{"obj":"😇","alt":"Smiling Face with Halo"},{"obj":"🥰","alt":"Smiling Face with Hearts"},{"obj":"😍","alt":"Smiling Face with Heart-Eyes"},{"obj":"🤩","alt":"Star-Struck"},{"obj":"😘","alt":"Face Blowing a Kiss"},{"obj":"😗","alt":"Kissing Face"},{"obj":"☺️","alt":"Smiling Face"},{"obj":"😚","alt":"Kissing Face with Closed Eyes"},{"obj":"😙","alt":"Kissing Face with Smiling Eyes"},{"obj":"🥲","alt":"Smiling Face with Tear"},{"obj":"😋","alt":"Face Savoring Food"},{"obj":"😛","alt":"Face with Tongue"},{"obj":"😜","alt":"Winking Face with Tongue"},{"obj":"🤪","alt":"Zany Face"},{"obj":"😝","alt":"Squinting Face with Tongue"},{"obj":"🤑","alt":"Money-Mouth Face"},{"obj":"🤗","alt":"Smiling Face with Open Hands"},{"obj":"🤭","alt":"Face with Hand Over Mouth"},{"obj":"🫢","alt":"Face with Open Eyes and Hand Over Mouth"},{"obj":"🫣","alt":"Face with Peeking Eye"},{"obj":"🤫","alt":"Shushing Face"},{"obj":"🤔","alt":"Thinking Face"},{"obj":"🫡","alt":"Saluting Face"},{"obj":"🤐","alt":"Zipper-Mouth Face"},{"obj":"🤨","alt":"Face with Raised Eyebrow"},{"obj":"😐","alt":"Neutral Face"},{"obj":"😑","alt":"Expressionless Face"},{"obj":"😶","alt":"Face Without Mouth"},{"obj":"🫥","alt":"Dotted Line Face"},{"obj":"😶‍🌫️","alt":"Face in Clouds"},{"obj":"😏","alt":"Smirking Face"},{"obj":"😒","alt":"Unamused Face"},{"obj":"🙄","alt":"Face with Rolling Eyes"},{"obj":"😬","alt":"Grimacing Face"},{"obj":"😮‍💨","alt":"Face Exhaling"},{"obj":"🤥","alt":"Lying Face"},{"obj":"😌","alt":"Relieved Face"},{"obj":"😔","alt":"Pensive Face"},{"obj":"😪","alt":"Sleepy Face"},{"obj":"🤤","alt":"Drooling Face"},{"obj":"😴","alt":"Sleeping Face"},{"obj":"😷","alt":"Face with Medical Mask"},{"obj":"🤒","alt":"Face with Thermometer"},{"obj":"🤕","alt":"Face with Head-Bandage"},{"obj":"🤢","alt":"Nauseated Face"},{"obj":"🤮","alt":"Face Vomiting"},{"obj":"🤧","alt":"Sneezing Face"},{"obj":"🥵","alt":"Hot Face"},{"obj":"🥶","alt":"Cold Face"},{"obj":"🥴","alt":"Woozy Face"},{"obj":"😵","alt":"Face with Crossed-Out Eyes"},{"obj":"😵‍💫","alt":"Face with Spiral Eyes"},{"obj":"🤯","alt":"Exploding Head"},{"obj":"🤠","alt":"Cowboy Hat Face"},{"obj":"🥳","alt":"Partying Face"},{"obj":"🥸","alt":"Disguised Face"},{"obj":"😎","alt":"Smiling Face with Sunglasses"},{"obj":"🤓","alt":"Nerd Face"},{"obj":"🧐","alt":"Face with Monocle"},{"obj":"😕","alt":"Confused Face"},{"obj":"🫤","alt":"Face with Diagonal Mouth"},{"obj":"😟","alt":"Worried Face"},{"obj":"🙁","alt":"Slightly Frowning Face"},{"obj":"☹️","alt":"Frowning Face"},{"obj":"😮","alt":"Face with Open Mouth"},{"obj":"😯","alt":"Hushed Face"},{"obj":"😲","alt":"Astonished Face"},{"obj":"😳","alt":"Flushed Face"},{"obj":"🥺","alt":"Pleading Face"},{"obj":"🥹","alt":"Face Holding Back Tears"},{"obj":"😦","alt":"Frowning Face with Open Mouth"},{"obj":"😧","alt":"Anguished Face"},{"obj":"😨","alt":"Fearful Face"},{"obj":"😰","alt":"Anxious Face with Sweat"},{"obj":"😥","alt":"Sad but Relieved Face"},{"obj":"😢","alt":"Crying Face"},{"obj":"😭","alt":"Loudly Crying Face"},{"obj":"😱","alt":"Face Screaming in Fear"},{"obj":"😖","alt":"Confounded Face"},{"obj":"😣","alt":"Persevering Face"},{"obj":"😞","alt":"Disappointed Face"},{"obj":"😓","alt":"Downcast Face with Sweat"},{"obj":"😩","alt":"Weary Face"},{"obj":"😫","alt":"Tired Face"},{"obj":"🥱","alt":"Yawning Face"},{"obj":"😤","alt":"Face with Steam From Nose"},{"obj":"😡","alt":"Enraged Face"},{"obj":"😠","alt":"Angry Face"},{"obj":"🤬","alt":"Face with Symbols on Mouth"},{"obj":"😈","alt":"Smiling Face with Horns"},{"obj":"👿","alt":"Angry Face with Horns"},{"obj":"💀","alt":"Skull"},{"obj":"☠️","alt":"Skull and Crossbones"},{"obj":"💩","alt":"Pile of Poo"},{"obj":"🤡","alt":"Clown Face"},{"obj":"👹","alt":"Ogre"},{"obj":"👺","alt":"Goblin"},{"obj":"👻","alt":"Ghost"},{"obj":"👽","alt":"Alien"},{"obj":"👾","alt":"Alien Monster"},{"obj":"🤖","alt":"Robot"},{"obj":"😺","alt":"Grinning Cat"},{"obj":"😸","alt":"Grinning Cat with Smiling Eyes"},{"obj":"😹","alt":"Cat with Tears of Joy"},{"obj":"😻","alt":"Smiling Cat with Heart-Eyes"},{"obj":"😼","alt":"Cat with Wry Smile"},{"obj":"😽","alt":"Kissing Cat"},{"obj":"🙀","alt":"Weary Cat"},{"obj":"😿","alt":"Crying Cat"},{"obj":"😾","alt":"Pouting Cat"},{"obj":"💋","alt":"Kiss Mark"},{"obj":"👋","alt":"Waving Hand"},{"obj":"🤚","alt":"Raised Back of Hand"},{"obj":"🖐️","alt":"Hand with Fingers Splayed"},{"obj":"✋","alt":"Raised Hand"},{"obj":"🖖","alt":"Vulcan Salute"},{"obj":"🫱","alt":"Rightwards Hand"},{"obj":"🫲","alt":"Leftwards Hand"},{"obj":"🫳","alt":"Palm Down Hand"},{"obj":"🫴","alt":"Palm Up Hand"},{"obj":"👌","alt":"OK Hand"},{"obj":"🤌","alt":"Pinched Fingers"},{"obj":"🤏","alt":"Pinching Hand"},{"obj":"✌️","alt":"Victory Hand"},{"obj":"🤞","alt":"Crossed Fingers"},{"obj":"🫰","alt":"Hand with Index Finger and Thumb Crossed"},{"obj":"🤟","alt":"Love-You Gesture"},{"obj":"🤘","alt":"Sign of the Horns"},{"obj":"🤙","alt":"Call Me Hand"},{"obj":"👈","alt":"Backhand Index Pointing Left"},{"obj":"👉","alt":"Backhand Index Pointing Right"},{"obj":"👆","alt":"Backhand Index Pointing Up"},{"obj":"🖕","alt":"Middle Finger"},{"obj":"👇","alt":"Backhand Index Pointing Down"},{"obj":"☝️","alt":"Index Pointing Up"},{"obj":"🫵","alt":"Index Pointing at the Viewer"},{"obj":"👍","alt":"Thumbs Up"},{"obj":"👎","alt":"Thumbs Down"},{"obj":"✊","alt":"Raised Fist"},{"obj":"👊","alt":"Oncoming Fist"},{"obj":"🤛","alt":"Left-Facing Fist"},{"obj":"🤜","alt":"Right-Facing Fist"},{"obj":"👏","alt":"Clapping Hands"},{"obj":"🙌","alt":"Raising Hands"},{"obj":"🫶","alt":"Heart Hands"},{"obj":"👐","alt":"Open Hands"},{"obj":"🤲","alt":"Palms Up Together"},{"obj":"🤝","alt":"Handshake"},{"obj":"🙏","alt":"Folded Hands"},{"obj":"✍️","alt":"Writing Hand"},{"obj":"💅","alt":"Nail Polish"},{"obj":"🤳","alt":"Selfie"},{"obj":"💪","alt":"Flexed Biceps"},{"obj":"🦾","alt":"Mechanical Arm"},{"obj":"🦿","alt":"Mechanical Leg"},{"obj":"🦵","alt":"Leg"},{"obj":"🦶","alt":"Foot"},{"obj":"👂","alt":"Ear"},{"obj":"🦻","alt":"Ear with Hearing Aid"},{"obj":"👃","alt":"Nose"},{"obj":"🧠","alt":"Brain"},{"obj":"🫀","alt":"Anatomical Heart"},{"obj":"🫁","alt":"Lungs"},{"obj":"🦷","alt":"Tooth"},{"obj":"🦴","alt":"Bone"},{"obj":"👀","alt":"Eyes"},{"obj":"👁️","alt":"Eye"},{"obj":"👅","alt":"Tongue"},{"obj":"👄","alt":"Mouth"},{"obj":"🫦","alt":"Biting Lip"},{"obj":"👶","alt":"Baby"},{"obj":"🧒","alt":"Child"},{"obj":"👦","alt":"Boy"},{"obj":"👧","alt":"Girl"},{"obj":"🧑","alt":"Person"},{"obj":"👱","alt":"Person: Blond Hair"},{"obj":"👨","alt":"Man"},{"obj":"🧔","alt":"Person: Beard"},{"obj":"👨‍🦰","alt":"Man: Red Hair"},{"obj":"👨‍🦱","alt":"Man: Curly Hair"},{"obj":"👨‍🦳","alt":"Man: White Hair"},{"obj":"👨‍🦲","alt":"Man: Bald"},{"obj":"👩","alt":"Woman"},{"obj":"👩‍🦰","alt":"Woman: Red Hair"},{"obj":"🧑‍🦰","alt":"Person: Red Hair"},{"obj":"👩‍🦱","alt":"Woman: Curly Hair"},{"obj":"🧑‍🦱","alt":"Person: Curly Hair"},{"obj":"👩‍🦳","alt":"Woman: White Hair"},{"obj":"🧑‍🦳","alt":"Person: White Hair"},{"obj":"👩‍🦲","alt":"Woman: Bald"},{"obj":"🧑‍🦲","alt":"Person: Bald"},{"obj":"👱‍♀️","alt":"Woman: Blond Hair"},{"obj":"👱‍♂️","alt":"Man: Blond Hair"},{"obj":"🧓","alt":"Older Person"},{"obj":"👴","alt":"Old Man"},{"obj":"👵","alt":"Old Woman"},{"obj":"🙍","alt":"Person Frowning"},{"obj":"🙍‍♂️","alt":"Man Frowning"},{"obj":"🙍‍♀️","alt":"Woman Frowning"},{"obj":"🙎","alt":"Person Pouting"},{"obj":"🙎‍♂️","alt":"Man Pouting"},{"obj":"🙎‍♀️","alt":"Woman Pouting"},{"obj":"🙅","alt":"Person Gesturing No"},{"obj":"🙅‍♂️","alt":"Man Gesturing No"},{"obj":"🙅‍♀️","alt":"Woman Gesturing No"},{"obj":"🙆","alt":"Person Gesturing OK"},{"obj":"🙆‍♂️","alt":"Man Gesturing OK"},{"obj":"🙆‍♀️","alt":"Woman Gesturing OK"},{"obj":"💁","alt":"Person Tipping Hand"},{"obj":"💁‍♂️","alt":"Man Tipping Hand"},{"obj":"💁‍♀️","alt":"Woman Tipping Hand"},{"obj":"🙋","alt":"Person Raising Hand"},{"obj":"🙋‍♂️","alt":"Man Raising Hand"},{"obj":"🙋‍♀️","alt":"Woman Raising Hand"},{"obj":"🧏","alt":"Deaf Person"},{"obj":"🧏‍♂️","alt":"Deaf Man"},{"obj":"🧏‍♀️","alt":"Deaf Woman"},{"obj":"🙇","alt":"Person Bowing"},{"obj":"🙇‍♂️","alt":"Man Bowing"},{"obj":"🙇‍♀️","alt":"Woman Bowing"},{"obj":"🤦","alt":"Person Facepalming"},{"obj":"🤦‍♂️","alt":"Man Facepalming"},{"obj":"🤦‍♀️","alt":"Woman Facepalming"},{"obj":"🤷","alt":"Person Shrugging"},{"obj":"🤷‍♂️","alt":"Man Shrugging"},{"obj":"🤷‍♀️","alt":"Woman Shrugging"},{"obj":"🧑‍⚕️","alt":"Health Worker"},{"obj":"👨‍⚕️","alt":"Man Health Worker"},{"obj":"👩‍⚕️","alt":"Woman Health Worker"},{"obj":"🧑‍🎓","alt":"Student"},{"obj":"👨‍🎓","alt":"Man Student"},{"obj":"👩‍🎓","alt":"Woman Student"},{"obj":"🧑‍🏫","alt":"Teacher"},{"obj":"👨‍🏫","alt":"Man Teacher"},{"obj":"👩‍🏫","alt":"Woman Teacher"},{"obj":"🧑‍⚖️","alt":"Judge"},{"obj":"👨‍⚖️","alt":"Man Judge"},{"obj":"👩‍⚖️","alt":"Woman Judge"},{"obj":"🧑‍🌾","alt":"Farmer"},{"obj":"👨‍🌾","alt":"Man Farmer"},{"obj":"👩‍🌾","alt":"Woman Farmer"},{"obj":"🧑‍🍳","alt":"Cook"},{"obj":"👨‍🍳","alt":"Man Cook"},{"obj":"👩‍🍳","alt":"Woman Cook"},{"obj":"🧑‍🔧","alt":"Mechanic"},{"obj":"👨‍🔧","alt":"Man Mechanic"},{"obj":"👩‍🔧","alt":"Woman Mechanic"},{"obj":"🧑‍🏭","alt":"Factory Worker"},{"obj":"👨‍🏭","alt":"Man Factory Worker"},{"obj":"👩‍🏭","alt":"Woman Factory Worker"},{"obj":"🧑‍💼","alt":"Office Worker"},{"obj":"👨‍💼","alt":"Man Office Worker"},{"obj":"👩‍💼","alt":"Woman Office Worker"},{"obj":"🧑‍🔬","alt":"Scientist"},{"obj":"👨‍🔬","alt":"Man Scientist"},{"obj":"👩‍🔬","alt":"Woman Scientist"},{"obj":"🧑‍💻","alt":"Technologist"},{"obj":"👨‍💻","alt":"Man Technologist"},{"obj":"👩‍💻","alt":"Woman Technologist"},{"obj":"🧑‍🎤","alt":"Singer"},{"obj":"👨‍🎤","alt":"Man Singer"},{"obj":"👩‍🎤","alt":"Woman Singer"},{"obj":"🧑‍🎨","alt":"Artist"},{"obj":"👨‍🎨","alt":"Man Artist"},{"obj":"👩‍🎨","alt":"Woman Artist"},{"obj":"🧑‍✈️","alt":"Pilot"},{"obj":"👨‍✈️","alt":"Man Pilot"},{"obj":"👩‍✈️","alt":"Woman Pilot"},{"obj":"🧑‍🚀","alt":"Astronaut"},{"obj":"👨‍🚀","alt":"Man Astronaut"},{"obj":"👩‍🚀","alt":"Woman Astronaut"},{"obj":"🧑‍🚒","alt":"Firefighter"},{"obj":"👨‍🚒","alt":"Man Firefighter"},{"obj":"👩‍🚒","alt":"Woman Firefighter"},{"obj":"👮","alt":"Police Officer"},{"obj":"👮‍♂️","alt":"Man Police Officer"},{"obj":"👮‍♀️","alt":"Woman Police Officer"},{"obj":"🕵️","alt":"Detective"},{"obj":"🕵️‍♂️","alt":"Man Detective"},{"obj":"🕵️‍♀️","alt":"Woman Detective"},{"obj":"💂","alt":"Guard"},{"obj":"💂‍♂️","alt":"Man Guard"},{"obj":"💂‍♀️","alt":"Woman Guard"},{"obj":"🥷","alt":"Ninja"},{"obj":"👷","alt":"Construction Worker"},{"obj":"👷‍♂️","alt":"Man Construction Worker"},{"obj":"👷‍♀️","alt":"Woman Construction Worker"},{"obj":"🫅","alt":"Person with Crown"},{"obj":"🤴","alt":"Prince"},{"obj":"👸","alt":"Princess"},{"obj":"👳","alt":"Person Wearing Turban"},{"obj":"👳‍♂️","alt":"Man Wearing Turban"},{"obj":"👳‍♀️","alt":"Woman Wearing Turban"},{"obj":"👲","alt":"Person with Skullcap"},{"obj":"🧕","alt":"Woman with Headscarf"},{"obj":"🤵","alt":"Person in Tuxedo"},{"obj":"🤵‍♂️","alt":"Man in Tuxedo"},{"obj":"🤵‍♀️","alt":"Woman in Tuxedo"},{"obj":"👰","alt":"Person with Veil"},{"obj":"👰‍♂️","alt":"Man with Veil"},{"obj":"👰‍♀️","alt":"Woman with Veil"},{"obj":"🤰","alt":"Pregnant Woman"},{"obj":"🫃","alt":"Pregnant Man"},{"obj":"🫄","alt":"Pregnant Person"},{"obj":"🤱","alt":"Breast-Feeding"},{"obj":"👩‍🍼","alt":"Woman Feeding Baby"},{"obj":"👨‍🍼","alt":"Man Feeding Baby"},{"obj":"🧑‍🍼","alt":"Person Feeding Baby"},{"obj":"👼","alt":"Baby Angel"},{"obj":"🎅","alt":"Santa Claus"},{"obj":"🤶","alt":"Mrs. Claus"},{"obj":"🧑‍🎄","alt":"Mx Claus"},{"obj":"🦸","alt":"Superhero"},{"obj":"🦸‍♂️","alt":"Man Superhero"},{"obj":"🦸‍♀️","alt":"Woman Superhero"},{"obj":"🦹","alt":"Supervillain"},{"obj":"🦹‍♂️","alt":"Man Supervillain"},{"obj":"🦹‍♀️","alt":"Woman Supervillain"},{"obj":"🧙","alt":"Mage"},{"obj":"🧙‍♂️","alt":"Man Mage"},{"obj":"🧙‍♀️","alt":"Woman Mage"},{"obj":"🧚","alt":"Fairy"},{"obj":"🧚‍♂️","alt":"Man Fairy"},{"obj":"🧚‍♀️","alt":"Woman Fairy"},{"obj":"🧛","alt":"Vampire"},{"obj":"🧛‍♂️","alt":"Man Vampire"},{"obj":"🧛‍♀️","alt":"Woman Vampire"},{"obj":"🧜","alt":"Merperson"},{"obj":"🧜‍♂️","alt":"Merman"},{"obj":"🧜‍♀️","alt":"Mermaid"},{"obj":"🧝","alt":"Elf"},{"obj":"🧝‍♂️","alt":"Man Elf"},{"obj":"🧝‍♀️","alt":"Woman Elf"},{"obj":"🧞","alt":"Genie"},{"obj":"🧞‍♂️","alt":"Man Genie"},{"obj":"🧞‍♀️","alt":"Woman Genie"},{"obj":"🧟","alt":"Zombie"},{"obj":"🧟‍♂️","alt":"Man Zombie"},{"obj":"🧟‍♀️","alt":"Woman Zombie"},{"obj":"🧌","alt":"Troll"},{"obj":"💆","alt":"Person Getting Massage"},{"obj":"💆‍♂️","alt":"Man Getting Massage"},{"obj":"💆‍♀️","alt":"Woman Getting Massage"},{"obj":"💇","alt":"Person Getting Haircut"},{"obj":"💇‍♂️","alt":"Man Getting Haircut"},{"obj":"💇‍♀️","alt":"Woman Getting Haircut"},{"obj":"🚶","alt":"Person Walking"},{"obj":"🚶‍♂️","alt":"Man Walking"},{"obj":"🚶‍♀️","alt":"Woman Walking"},{"obj":"🧍","alt":"Person Standing"},{"obj":"🧍‍♂️","alt":"Man Standing"},{"obj":"🧍‍♀️","alt":"Woman Standing"},{"obj":"🧎","alt":"Person Kneeling"},{"obj":"🧎‍♂️","alt":"Man Kneeling"},{"obj":"🧎‍♀️","alt":"Woman Kneeling"},{"obj":"🧑‍🦯","alt":"Person with White Cane"},{"obj":"👨‍🦯","alt":"Man with White Cane"},{"obj":"👩‍🦯","alt":"Woman with White Cane"},{"obj":"🧑‍🦼","alt":"Person in Motorized Wheelchair"},{"obj":"👨‍🦼","alt":"Man in Motorized Wheelchair"},{"obj":"👩‍🦼","alt":"Woman in Motorized Wheelchair"},{"obj":"🧑‍🦽","alt":"Person in Manual Wheelchair"},{"obj":"👨‍🦽","alt":"Man in Manual Wheelchair"},{"obj":"👩‍🦽","alt":"Woman in Manual Wheelchair"},{"obj":"🏃","alt":"Person Running"},{"obj":"🏃‍♂️","alt":"Man Running"},{"obj":"🏃‍♀️","alt":"Woman Running"},{"obj":"💃","alt":"Woman Dancing"},{"obj":"🕺","alt":"Man Dancing"},{"obj":"🕴️","alt":"Person in Suit Levitating"},{"obj":"👯","alt":"People with Bunny Ears"},{"obj":"👯‍♂️","alt":"Men with Bunny Ears"},{"obj":"👯‍♀️","alt":"Women with Bunny Ears"},{"obj":"🧖","alt":"Person in Steamy Room"},{"obj":"🧖‍♂️","alt":"Man in Steamy Room"},{"obj":"🧖‍♀️","alt":"Woman in Steamy Room"},{"obj":"🧘","alt":"Person in Lotus Position"},{"obj":"🧑‍🤝‍🧑","alt":"People Holding Hands"},{"obj":"👭","alt":"Women Holding Hands"},{"obj":"👫","alt":"Woman and Man Holding Hands"},{"obj":"👬","alt":"Men Holding Hands"},{"obj":"💏","alt":"Kiss"},{"obj":"👩‍❤️‍💋‍👨","alt":"Kiss: Woman, Man"},{"obj":"👨‍❤️‍💋‍👨","alt":"Kiss: Man, Man"},{"obj":"👩‍❤️‍💋‍👩","alt":"Kiss: Woman, Woman"},{"obj":"💑","alt":"Couple with Heart"},{"obj":"👩‍❤️‍👨","alt":"Couple with Heart: Woman, Man"},{"obj":"👨‍❤️‍👨","alt":"Couple with Heart: Man, Man"},{"obj":"👩‍❤️‍👩","alt":"Couple with Heart: Woman, Woman"},{"obj":"👪","alt":"Family"},{"obj":"👨‍👩‍👦","alt":"Family: Man, Woman, Boy"},{"obj":"👨‍👩‍👧","alt":"Family: Man, Woman, Girl"},{"obj":"👨‍👩‍👧‍👦","alt":"Family: Man, Woman, Girl, Boy"},{"obj":"👨‍👩‍👦‍👦","alt":"Family: Man, Woman, Boy, Boy"},{"obj":"👨‍👩‍👧‍👧","alt":"Family: Man, Woman, Girl, Girl"},{"obj":"👨‍👨‍👦","alt":"Family: Man, Man, Boy"},{"obj":"👨‍👨‍👧","alt":"Family: Man, Man, Girl"},{"obj":"👨‍👨‍👧‍👦","alt":"Family: Man, Man, Girl, Boy"},{"obj":"👨‍👨‍👦‍👦","alt":"Family: Man, Man, Boy, Boy"},{"obj":"👨‍👨‍👧‍👧","alt":"Family: Man, Man, Girl, Girl"},{"obj":"👩‍👩‍👦","alt":"Family: Woman, Woman, Boy"},{"obj":"👩‍👩‍👧","alt":"Family: Woman, Woman, Girl"},{"obj":"👩‍👩‍👧‍👦","alt":"Family: Woman, Woman, Girl, Boy"},{"obj":"👩‍👩‍👦‍👦","alt":"Family: Woman, Woman, Boy, Boy"},{"obj":"👩‍👩‍👧‍👧","alt":"Family: Woman, Woman, Girl, Girl"},{"obj":"👨‍👦","alt":"Family: Man, Boy"},{"obj":"👨‍👦‍👦","alt":"Family: Man, Boy, Boy"},{"obj":"👨‍👧","alt":"Family: Man, Girl"},{"obj":"👨‍👧‍👦","alt":"Family: Man, Girl, Boy"},{"obj":"👨‍👧‍👧","alt":"Family: Man, Girl, Girl"},{"obj":"👩‍👦","alt":"Family: Woman, Boy"},{"obj":"👩‍👦‍👦","alt":"Family: Woman, Boy, Boy"},{"obj":"👩‍👧","alt":"Family: Woman, Girl"},{"obj":"👩‍👧‍👦","alt":"Family: Woman, Girl, Boy"},{"obj":"👩‍👧‍👧","alt":"Family: Woman, Girl, Girl"},{"obj":"🗣️","alt":"Speaking Head"},{"obj":"👤","alt":"Bust in Silhouette"},{"obj":"👥","alt":"Busts in Silhouette"},{"obj":"🫂","alt":"People Hugging"},{"obj":"👣","alt":"Footprints"},{"obj":"🧳","alt":"Luggage"},{"obj":"🌂","alt":"Closed Umbrella"},{"obj":"☂️","alt":"Umbrella"},{"obj":"🎃","alt":"Jack-O-Lantern"},{"obj":"🧵","alt":"Thread"},{"obj":"🧶","alt":"Yarn"},{"obj":"👓","alt":"Glasses"},{"obj":"🕶️","alt":"Sunglasses"},{"obj":"🥽","alt":"Goggles"},{"obj":"🥼","alt":"Lab Coat"},{"obj":"🦺","alt":"Safety Vest"},{"obj":"👔","alt":"Necktie"},{"obj":"👕","alt":"T-Shirt"},{"obj":"👖","alt":"Jeans"},{"obj":"🧣","alt":"Scarf"},{"obj":"🧤","alt":"Gloves"},{"obj":"🧥","alt":"Coat"},{"obj":"🧦","alt":"Socks"},{"obj":"👗","alt":"Dress"},{"obj":"👘","alt":"Kimono"},{"obj":"🥻","alt":"Sari"},{"obj":"🩱","alt":"One-Piece Swimsuit"},{"obj":"🩲","alt":"Briefs"},{"obj":"🩳","alt":"Shorts"},{"obj":"👙","alt":"Bikini"},{"obj":"👚","alt":"Woman’s Clothes"},{"obj":"👛","alt":"Purse"},{"obj":"👜","alt":"Handbag"},{"obj":"👝","alt":"Clutch Bag"},{"obj":"🎒","alt":"Backpack"},{"obj":"🩴","alt":"Thong Sandal"},{"obj":"👞","alt":"Man’s Shoe"},{"obj":"👟","alt":"Running Shoe"},{"obj":"🥾","alt":"Hiking Boot"},{"obj":"🥿","alt":"Flat Shoe"},{"obj":"👠","alt":"High-Heeled Shoe"},{"obj":"👡","alt":"Woman’s Sandal"},{"obj":"🩰","alt":"Ballet Shoes"},{"obj":"👢","alt":"Woman’s Boot"},{"obj":"👑","alt":"Crown"},{"obj":"👒","alt":"Woman’s Hat"},{"obj":"🎩","alt":"Top Hat"},{"obj":"🎓","alt":"Graduation Cap"},{"obj":"🧢","alt":"Billed Cap"},{"obj":"🪖","alt":"Military Helmet"},{"obj":"⛑️","alt":"Rescue Worker’s Helmet"},{"obj":"💄","alt":"Lipstick"},{"obj":"💍","alt":"Ring"},{"obj":"💼","alt":"Briefcase"},{"obj":"🩸","alt":"Drop of Blood"}]},
      nature = {"name":"Animals & Nature","key":"nature","mob":"🐻","emojis":[{"obj":"🙈","alt":"See-No-Evil Monkey"},{"obj":"🙉","alt":"Hear-No-Evil Monkey"},{"obj":"🙊","alt":"Speak-No-Evil Monkey"},{"obj":"💥","alt":"Collision"},{"obj":"💫","alt":"Dizzy"},{"obj":"💦","alt":"Sweat Droplets"},{"obj":"💨","alt":"Dashing Away"},{"obj":"🐵","alt":"Monkey Face"},{"obj":"🐒","alt":"Monkey"},{"obj":"🦍","alt":"Gorilla"},{"obj":"🦧","alt":"Orangutan"},{"obj":"🐶","alt":"Dog Face"},{"obj":"🐕","alt":"Dog"},{"obj":"🦮","alt":"Guide Dog"},{"obj":"🐕‍🦺","alt":"Service Dog"},{"obj":"🐩","alt":"Poodle"},{"obj":"🐺","alt":"Wolf"},{"obj":"🦊","alt":"Fox"},{"obj":"🦝","alt":"Raccoon"},{"obj":"🐱","alt":"Cat Face"},{"obj":"🐈","alt":"Cat"},{"obj":"🐈‍⬛","alt":"Black Cat"},{"obj":"🦁","alt":"Lion"},{"obj":"🐯","alt":"Tiger Face"},{"obj":"🐅","alt":"Tiger"},{"obj":"🐆","alt":"Leopard"},{"obj":"🐴","alt":"Horse Face"},{"obj":"🐎","alt":"Horse"},{"obj":"🦄","alt":"Unicorn"},{"obj":"🦓","alt":"Zebra"},{"obj":"🦌","alt":"Deer"},{"obj":"🦬","alt":"Bison"},{"obj":"🐮","alt":"Cow Face"},{"obj":"🐂","alt":"Ox"},{"obj":"🐃","alt":"Water Buffalo"},{"obj":"🐄","alt":"Cow"},{"obj":"🐷","alt":"Pig Face"},{"obj":"🐖","alt":"Pig"},{"obj":"🐗","alt":"Boar"},{"obj":"🐽","alt":"Pig Nose"},{"obj":"🐏","alt":"Ram"},{"obj":"🐑","alt":"Ewe"},{"obj":"🐐","alt":"Goat"},{"obj":"🐪","alt":"Camel"},{"obj":"🐫","alt":"Two-Hump Camel"},{"obj":"🦙","alt":"Llama"},{"obj":"🦒","alt":"Giraffe"},{"obj":"🐘","alt":"Elephant"},{"obj":"🦣","alt":"Mammoth"},{"obj":"🦏","alt":"Rhinoceros"},{"obj":"🦛","alt":"Hippopotamus"},{"obj":"🐭","alt":"Mouse Face"},{"obj":"🐁","alt":"Mouse"},{"obj":"🐀","alt":"Rat"},{"obj":"🐹","alt":"Hamster"},{"obj":"🐰","alt":"Rabbit Face"},{"obj":"🐇","alt":"Rabbit"},{"obj":"🐿️","alt":"Chipmunk"},{"obj":"🦫","alt":"Beaver"},{"obj":"🦔","alt":"Hedgehog"},{"obj":"🦇","alt":"Bat"},{"obj":"🐻","alt":"Bear"},{"obj":"🐻‍❄️","alt":"Polar Bear"},{"obj":"🐨","alt":"Koala"},{"obj":"🐼","alt":"Panda"},{"obj":"🦥","alt":"Sloth"},{"obj":"🦦","alt":"Otter"},{"obj":"🦨","alt":"Skunk"},{"obj":"🦘","alt":"Kangaroo"},{"obj":"🦡","alt":"Badger"},{"obj":"🐾","alt":"Paw Prints"},{"obj":"🦃","alt":"Turkey"},{"obj":"🐔","alt":"Chicken"},{"obj":"🐓","alt":"Rooster"},{"obj":"🐣","alt":"Hatching Chick"},{"obj":"🐤","alt":"Baby Chick"},{"obj":"🐥","alt":"Front-Facing Baby Chick"},{"obj":"🐦","alt":"Bird"},{"obj":"🐧","alt":"Penguin"},{"obj":"🕊️","alt":"Dove"},{"obj":"🦅","alt":"Eagle"},{"obj":"🦆","alt":"Duck"},{"obj":"🦢","alt":"Swan"},{"obj":"🦉","alt":"Owl"},{"obj":"🦤","alt":"Dodo"},{"obj":"🪶","alt":"Feather"},{"obj":"🦩","alt":"Flamingo"},{"obj":"🦚","alt":"Peacock"},{"obj":"🦜","alt":"Parrot"},{"obj":"🐸","alt":"Frog"},{"obj":"🐊","alt":"Crocodile"},{"obj":"🐢","alt":"Turtle"},{"obj":"🦎","alt":"Lizard"},{"obj":"🐍","alt":"Snake"},{"obj":"🐲","alt":"Dragon Face"},{"obj":"🐉","alt":"Dragon"},{"obj":"🦕","alt":"Sauropod"},{"obj":"🦖","alt":"T-Rex"},{"obj":"🐳","alt":"Spouting Whale"},{"obj":"🐋","alt":"Whale"},{"obj":"🐬","alt":"Dolphin"},{"obj":"🦭","alt":"Seal"},{"obj":"🐟","alt":"Fish"},{"obj":"🐠","alt":"Tropical Fish"},{"obj":"🐡","alt":"Blowfish"},{"obj":"🦈","alt":"Shark"},{"obj":"🐙","alt":"Octopus"},{"obj":"🐚","alt":"Spiral Shell"},{"obj":"🪸","alt":"Coral"},{"obj":"🐌","alt":"Snail"},{"obj":"🦋","alt":"Butterfly"},{"obj":"🐛","alt":"Bug"},{"obj":"🐜","alt":"Ant"},{"obj":"🐝","alt":"Honeybee"},{"obj":"🪲","alt":"Beetle"},{"obj":"🐞","alt":"Lady Beetle"},{"obj":"🦗","alt":"Cricket"},{"obj":"🪳","alt":"Cockroach"},{"obj":"🕷️","alt":"Spider"},{"obj":"🕸️","alt":"Spider Web"},{"obj":"🦂","alt":"Scorpion"},{"obj":"🦟","alt":"Mosquito"},{"obj":"🪰","alt":"Fly"},{"obj":"🪱","alt":"Worm"},{"obj":"🦠","alt":"Microbe"},{"obj":"💐","alt":"Bouquet"},{"obj":"🌸","alt":"Cherry Blossom"},{"obj":"💮","alt":"White Flower"},{"obj":"🪷","alt":"Lotus"},{"obj":"🏵️","alt":"Rosette"},{"obj":"🌹","alt":"Rose"},{"obj":"🥀","alt":"Wilted Flower"},{"obj":"🌺","alt":"Hibiscus"},{"obj":"🌻","alt":"Sunflower"},{"obj":"🌼","alt":"Blossom"},{"obj":"🌷","alt":"Tulip"},{"obj":"🌱","alt":"Seedling"},{"obj":"🪴","alt":"Potted Plant"},{"obj":"🌲","alt":"Evergreen Tree"},{"obj":"🌳","alt":"Deciduous Tree"},{"obj":"🌴","alt":"Palm Tree"},{"obj":"🌵","alt":"Cactus"},{"obj":"🌾","alt":"Sheaf of Rice"},{"obj":"🌿","alt":"Herb"},{"obj":"☘️","alt":"Shamrock"},{"obj":"🍀","alt":"Four Leaf Clover"},{"obj":"🍁","alt":"Maple Leaf"},{"obj":"🍂","alt":"Fallen Leaf"},{"obj":"🍃","alt":"Leaf Fluttering in Wind"},{"obj":"🪹","alt":"Empty Nest"},{"obj":"🪺","alt":"Nest with Eggs"},{"obj":"🍄","alt":"Mushroom"},{"obj":"🌰","alt":"Chestnut"},{"obj":"🦀","alt":"Crab"},{"obj":"🦞","alt":"Lobster"},{"obj":"🦐","alt":"Shrimp"},{"obj":"🦑","alt":"Squid"},{"obj":"🌍","alt":"Globe Showing Europe-Africa"},{"obj":"🌎","alt":"Globe Showing Americas"},{"obj":"🌏","alt":"Globe Showing Asia-Australia"},{"obj":"🌐","alt":"Globe with Meridians"},{"obj":"🪨","alt":"Rock"},{"obj":"🌑","alt":"New Moon"},{"obj":"🌒","alt":"Waxing Crescent Moon"},{"obj":"🌓","alt":"First Quarter Moon"},{"obj":"🌔","alt":"Waxing Gibbous Moon"},{"obj":"🌕","alt":"Full Moon"},{"obj":"🌖","alt":"Waning Gibbous Moon"},{"obj":"🌗","alt":"Last Quarter Moon"},{"obj":"🌘","alt":"Waning Crescent Moon"},{"obj":"🌙","alt":"Crescent Moon"},{"obj":"🌚","alt":"New Moon Face"},{"obj":"🌛","alt":"First Quarter Moon Face"},{"obj":"🌜","alt":"Last Quarter Moon Face"},{"obj":"☀️","alt":"Sun"},{"obj":"🌝","alt":"Full Moon Face"},{"obj":"🌞","alt":"Sun with Face"},{"obj":"⭐","alt":"Star"},{"obj":"🌟","alt":"Glowing Star"},{"obj":"🌠","alt":"Shooting Star"},{"obj":"☁️","alt":"Cloud"},{"obj":"⛅","alt":"Sun Behind Cloud"},{"obj":"⛈️","alt":"Cloud with Lightning and Rain"},{"obj":"🌤️","alt":"Sun Behind Small Cloud"},{"obj":"🌥️","alt":"Sun Behind Large Cloud"},{"obj":"🌦️","alt":"Sun Behind Rain Cloud"},{"obj":"🌧️","alt":"Cloud with Rain"},{"obj":"🌨️","alt":"Cloud with Snow"},{"obj":"🌩️","alt":"Cloud with Lightning"},{"obj":"🌪️","alt":"Tornado"},{"obj":"🌫️","alt":"Fog"},{"obj":"🌬️","alt":"Wind Face"},{"obj":"🌈","alt":"Rainbow"},{"obj":"☂️","alt":"Umbrella"},{"obj":"☔","alt":"Umbrella with Rain Drops"},{"obj":"⚡","alt":"High Voltage"},{"obj":"❄️","alt":"Snowflake"},{"obj":"☃️","alt":"Snowman"},{"obj":"⛄","alt":"Snowman Without Snow"},{"obj":"☄️","alt":"Comet"},{"obj":"🔥","alt":"Fire"},{"obj":"💧","alt":"Droplet"},{"obj":"🌊","alt":"Water Wave"},{"obj":"🎄","alt":"Christmas Tree"},{"obj":"✨","alt":"Sparkles"},{"obj":"🎋","alt":"Tanabata Tree"},{"obj":"🎍","alt":"Pine Decoration"},{"obj":"🫧","alt":"Bubbles"}]},
      food = {"name":"Food & Drink","key":"food","mob":"🍔","emojis":[{"obj":"🍇","alt":"Grapes"},{"obj":"🍈","alt":"Melon"},{"obj":"🍉","alt":"Watermelon"},{"obj":"🍊","alt":"Tangerine"},{"obj":"🍋","alt":"Lemon"},{"obj":"🍌","alt":"Banana"},{"obj":"🍍","alt":"Pineapple"},{"obj":"🥭","alt":"Mango"},{"obj":"🍎","alt":"Red Apple"},{"obj":"🍏","alt":"Green Apple"},{"obj":"🍐","alt":"Pear"},{"obj":"🍑","alt":"Peach"},{"obj":"🍒","alt":"Cherries"},{"obj":"🍓","alt":"Strawberry"},{"obj":"🫐","alt":"Blueberries"},{"obj":"🥝","alt":"Kiwi Fruit"},{"obj":"🍅","alt":"Tomato"},{"obj":"🫒","alt":"Olive"},{"obj":"🥥","alt":"Coconut"},{"obj":"🥑","alt":"Avocado"},{"obj":"🍆","alt":"Eggplant"},{"obj":"🥔","alt":"Potato"},{"obj":"🥕","alt":"Carrot"},{"obj":"🌽","alt":"Ear of Corn"},{"obj":"🌶️","alt":"Hot Pepper"},{"obj":"🫑","alt":"Bell Pepper"},{"obj":"🥒","alt":"Cucumber"},{"obj":"🥬","alt":"Leafy Green"},{"obj":"🥦","alt":"Broccoli"},{"obj":"🧄","alt":"Garlic"},{"obj":"🧅","alt":"Onion"},{"obj":"🍄","alt":"Mushroom"},{"obj":"🥜","alt":"Peanuts"},{"obj":"🫘","alt":"Beans"},{"obj":"🌰","alt":"Chestnut"},{"obj":"🍞","alt":"Bread"},{"obj":"🥐","alt":"Croissant"},{"obj":"🥖","alt":"Baguette Bread"},{"obj":"🫓","alt":"Flatbread"},{"obj":"🥨","alt":"Pretzel"},{"obj":"🥯","alt":"Bagel"},{"obj":"🥞","alt":"Pancakes"},{"obj":"🧇","alt":"Waffle"},{"obj":"🧀","alt":"Cheese Wedge"},{"obj":"🍖","alt":"Meat on Bone"},{"obj":"🍗","alt":"Poultry Leg"},{"obj":"🥩","alt":"Cut of Meat"},{"obj":"🥓","alt":"Bacon"},{"obj":"🍔","alt":"Hamburger"},{"obj":"🍟","alt":"French Fries"},{"obj":"🍕","alt":"Pizza"},{"obj":"🌭","alt":"Hot Dog"},{"obj":"🥪","alt":"Sandwich"},{"obj":"🌮","alt":"Taco"},{"obj":"🌯","alt":"Burrito"},{"obj":"🫔","alt":"Tamale"},{"obj":"🥙","alt":"Stuffed Flatbread"},{"obj":"🧆","alt":"Falafel"},{"obj":"🥚","alt":"Egg"},{"obj":"🍳","alt":"Cooking"},{"obj":"🥘","alt":"Shallow Pan of Food"},{"obj":"🍲","alt":"Pot of Food"},{"obj":"🫕","alt":"Fondue"},{"obj":"🥣","alt":"Bowl with Spoon"},{"obj":"🥗","alt":"Green Salad"},{"obj":"🍿","alt":"Popcorn"},{"obj":"🧈","alt":"Butter"},{"obj":"🧂","alt":"Salt"},{"obj":"🥫","alt":"Canned Food"},{"obj":"🍱","alt":"Bento Box"},{"obj":"🍘","alt":"Rice Cracker"},{"obj":"🍙","alt":"Rice Ball"},{"obj":"🍚","alt":"Cooked Rice"},{"obj":"🍛","alt":"Curry Rice"},{"obj":"🍜","alt":"Steaming Bowl"},{"obj":"🍝","alt":"Spaghetti"},{"obj":"🍠","alt":"Roasted Sweet Potato"},{"obj":"🍢","alt":"Oden"},{"obj":"🍣","alt":"Sushi"},{"obj":"🍤","alt":"Fried Shrimp"},{"obj":"🍥","alt":"Fish Cake with Swirl"},{"obj":"🥮","alt":"Moon Cake"},{"obj":"🍡","alt":"Dango"},{"obj":"🥟","alt":"Dumpling"},{"obj":"🥠","alt":"Fortune Cookie"},{"obj":"🥡","alt":"Takeout Box"},{"obj":"🦪","alt":"Oyster"},{"obj":"🍦","alt":"Soft Ice Cream"},{"obj":"🍧","alt":"Shaved Ice"},{"obj":"🍨","alt":"Ice Cream"},{"obj":"🍩","alt":"Doughnut"},{"obj":"🍪","alt":"Cookie"},{"obj":"🎂","alt":"Birthday Cake"},{"obj":"🍰","alt":"Shortcake"},{"obj":"🧁","alt":"Cupcake"},{"obj":"🥧","alt":"Pie"},{"obj":"🍫","alt":"Chocolate Bar"},{"obj":"🍬","alt":"Candy"},{"obj":"🍭","alt":"Lollipop"},{"obj":"🍮","alt":"Custard"},{"obj":"🍯","alt":"Honey Pot"},{"obj":"🍼","alt":"Baby Bottle"},{"obj":"🥛","alt":"Glass of Milk"},{"obj":"☕","alt":"Hot Beverage"},{"obj":"🫖","alt":"Teapot"},{"obj":"🍵","alt":"Teacup Without Handle"},{"obj":"🍶","alt":"Sake"},{"obj":"🍾","alt":"Bottle with Popping Cork"},{"obj":"🍷","alt":"Wine Glass"},{"obj":"🍸","alt":"Cocktail Glass"},{"obj":"🍹","alt":"Tropical Drink"},{"obj":"🍺","alt":"Beer Mug"},{"obj":"🍻","alt":"Clinking Beer Mugs"},{"obj":"🥂","alt":"Clinking Glasses"},{"obj":"🥃","alt":"Tumbler Glass"},{"obj":"🫗","alt":"Pouring Liquid"},{"obj":"🥤","alt":"Cup with Straw"},{"obj":"🧋","alt":"Bubble Tea"},{"obj":"🧃","alt":"Beverage Box"},{"obj":"🧉","alt":"Mate"},{"obj":"🧊","alt":"Ice"},{"obj":"🥢","alt":"Chopsticks"},{"obj":"🍽️","alt":"Fork and Knife with Plate"},{"obj":"🍴","alt":"Fork and Knife"},{"obj":"🥄","alt":"Spoon"},{"obj":"🫙","alt":"Jar"}]},
      activity = {"name":"Activity","key":"activity","mob":"⚽","emojis":[{"obj":"🕴️","alt":"Person in Suit Levitating"},{"obj":"🧗","alt":"Person Climbing"},{"obj":"🧗‍♂️","alt":"Man Climbing"},{"obj":"🧗‍♀️","alt":"Woman Climbing"},{"obj":"🤺","alt":"Person Fencing"},{"obj":"🏇","alt":"Horse Racing"},{"obj":"⛷️","alt":"Skier"},{"obj":"🏂","alt":"Snowboarder"},{"obj":"🏌️","alt":"Person Golfing"},{"obj":"🏌️‍♂️","alt":"Man Golfing"},{"obj":"🏌️‍♀️","alt":"Woman Golfing"},{"obj":"🏄","alt":"Person Surfing"},{"obj":"🏄‍♂️","alt":"Man Surfing"},{"obj":"🏄‍♀️","alt":"Woman Surfing"},{"obj":"🚣","alt":"Person Rowing Boat"},{"obj":"🚣‍♂️","alt":"Man Rowing Boat"},{"obj":"🚣‍♀️","alt":"Woman Rowing Boat"},{"obj":"🏊","alt":"Person Swimming"},{"obj":"🏊‍♂️","alt":"Man Swimming"},{"obj":"🏊‍♀️","alt":"Woman Swimming"},{"obj":"⛹️","alt":"Person Bouncing Ball"},{"obj":"⛹️‍♂️","alt":"Man Bouncing Ball"},{"obj":"⛹️‍♀️","alt":"Woman Bouncing Ball"},{"obj":"🏋️","alt":"Person Lifting Weights"},{"obj":"🏋️‍♂️","alt":"Man Lifting Weights"},{"obj":"🏋️‍♀️","alt":"Woman Lifting Weights"},{"obj":"🚴","alt":"Person Biking"},{"obj":"🚴‍♂️","alt":"Man Biking"},{"obj":"🚴‍♀️","alt":"Woman Biking"},{"obj":"🚵","alt":"Person Mountain Biking"},{"obj":"🚵‍♂️","alt":"Man Mountain Biking"},{"obj":"🚵‍♀️","alt":"Woman Mountain Biking"},{"obj":"🤸","alt":"Person Cartwheeling"},{"obj":"🤸‍♂️","alt":"Man Cartwheeling"},{"obj":"🤸‍♀️","alt":"Woman Cartwheeling"},{"obj":"🤼","alt":"People Wrestling"},{"obj":"🤼‍♂️","alt":"Men Wrestling"},{"obj":"🤼‍♀️","alt":"Women Wrestling"},{"obj":"🤽","alt":"Person Playing Water Polo"},{"obj":"🤽‍♂️","alt":"Man Playing Water Polo"},{"obj":"🤽‍♀️","alt":"Woman Playing Water Polo"},{"obj":"🤾","alt":"Person Playing Handball"},{"obj":"🤾‍♂️","alt":"Man Playing Handball"},{"obj":"🤾‍♀️","alt":"Woman Playing Handball"},{"obj":"🤹","alt":"Person Juggling"},{"obj":"🤹‍♂️","alt":"Man Juggling"},{"obj":"🤹‍♀️","alt":"Woman Juggling"},{"obj":"🧘","alt":"Person in Lotus Position"},{"obj":"🧘‍♂️","alt":"Man in Lotus Position"},{"obj":"🧘‍♀️","alt":"Woman in Lotus Position"},{"obj":"🎪","alt":"Circus Tent"},{"obj":"🛹","alt":"Skateboard"},{"obj":"🛼","alt":"Roller Skate"},{"obj":"🛶","alt":"Canoe"},{"obj":"🎗️","alt":"Reminder Ribbon"},{"obj":"🎟️","alt":"Admission Tickets"},{"obj":"🎫","alt":"Ticket"},{"obj":"🎖️","alt":"Military Medal"},{"obj":"🏆","alt":"Trophy"},{"obj":"🏅","alt":"Sports Medal"},{"obj":"🥇","alt":"1st Place Medal"},{"obj":"🥈","alt":"2nd Place Medal"},{"obj":"🥉","alt":"3rd Place Medal"},{"obj":"⚽","alt":"Soccer Ball"},{"obj":"⚾","alt":"Baseball"},{"obj":"🥎","alt":"Softball"},{"obj":"🏀","alt":"Basketball"},{"obj":"🏐","alt":"Volleyball"},{"obj":"🏈","alt":"American Football"},{"obj":"🏉","alt":"Rugby Football"},{"obj":"🎾","alt":"Tennis"},{"obj":"🥏","alt":"Flying Disc"},{"obj":"🎳","alt":"Bowling"},{"obj":"🏏","alt":"Cricket Game"},{"obj":"🏑","alt":"Field Hockey"},{"obj":"🏒","alt":"Ice Hockey"},{"obj":"🥍","alt":"Lacrosse"},{"obj":"🏓","alt":"Ping Pong"},{"obj":"🏸","alt":"Badminton"},{"obj":"🥊","alt":"Boxing Glove"},{"obj":"🥋","alt":"Martial Arts Uniform"},{"obj":"🥅","alt":"Goal Net"},{"obj":"⛳","alt":"Flag in Hole"},{"obj":"⛸️","alt":"Ice Skate"},{"obj":"🎣","alt":"Fishing Pole"},{"obj":"🎽","alt":"Running Shirt"},{"obj":"🎿","alt":"Skis"},{"obj":"🛷","alt":"Sled"},{"obj":"🥌","alt":"Curling Stone"},{"obj":"🎯","alt":"Bullseye"},{"obj":"🎱","alt":"Pool 8 Ball"},{"obj":"🎮","alt":"Video Game"},{"obj":"🎰","alt":"Slot Machine"},{"obj":"🎲","alt":"Game Die"},{"obj":"🧩","alt":"Puzzle Piece"},{"obj":"🪩","alt":"Mirror Ball"},{"obj":"♟️","alt":"Chess Pawn"},{"obj":"🎭","alt":"Performing Arts"},{"obj":"🎨","alt":"Artist Palette"},{"obj":"🧵","alt":"Thread"},{"obj":"🧶","alt":"Yarn"},{"obj":"🎼","alt":"Musical Score"},{"obj":"🎤","alt":"Microphone"},{"obj":"🎧","alt":"Headphone"},{"obj":"🎷","alt":"Saxophone"},{"obj":"🪗","alt":"Accordion"},{"obj":"🎸","alt":"Guitar"},{"obj":"🎹","alt":"Musical Keyboard"},{"obj":"🎺","alt":"Trumpet"},{"obj":"🎻","alt":"Violin"},{"obj":"🥁","alt":"Drum"},{"obj":"🪘","alt":"Long Drum"},{"obj":"🎬","alt":"Clapper Board"},{"obj":"🏹","alt":"Bow and Arrow"}]},
      places = {"name":"Travel & Places","key":"places","mob":"🚀","emojis":[{"obj":"🚣","alt":"Person Rowing Boat"},{"obj":"🗾","alt":"Map of Japan"},{"obj":"🏔️","alt":"Snow-Capped Mountain"},{"obj":"⛰️","alt":"Mountain"},{"obj":"🌋","alt":"Volcano"},{"obj":"🗻","alt":"Mount Fuji"},{"obj":"🏕️","alt":"Camping"},{"obj":"🏖️","alt":"Beach with Umbrella"},{"obj":"🏜️","alt":"Desert"},{"obj":"🏝️","alt":"Desert Island"},{"obj":"🏞️","alt":"National Park"},{"obj":"🏟️","alt":"Stadium"},{"obj":"🏛️","alt":"Classical Building"},{"obj":"🏗️","alt":"Building Construction"},{"obj":"🛖","alt":"Hut"},{"obj":"🏘️","alt":"Houses"},{"obj":"🏚️","alt":"Derelict House"},{"obj":"🏠","alt":"House"},{"obj":"🏡","alt":"House with Garden"},{"obj":"🏢","alt":"Office Building"},{"obj":"🏣","alt":"Japanese Post Office"},{"obj":"🏤","alt":"Post Office"},{"obj":"🏥","alt":"Hospital"},{"obj":"🏦","alt":"Bank"},{"obj":"🏨","alt":"Hotel"},{"obj":"🏩","alt":"Love Hotel"},{"obj":"🏪","alt":"Convenience Store"},{"obj":"🏫","alt":"School"},{"obj":"🏬","alt":"Department Store"},{"obj":"🏭","alt":"Factory"},{"obj":"🏯","alt":"Japanese Castle"},{"obj":"🏰","alt":"Castle"},{"obj":"💒","alt":"Wedding"},{"obj":"🗼","alt":"Tokyo Tower"},{"obj":"🗽","alt":"Statue of Liberty"},{"obj":"⛪","alt":"Church"},{"obj":"🕌","alt":"Mosque"},{"obj":"🛕","alt":"Hindu Temple"},{"obj":"🕍","alt":"Synagogue"},{"obj":"⛩️","alt":"Shinto Shrine"},{"obj":"🕋","alt":"Kaaba"},{"obj":"⛲","alt":"Fountain"},{"obj":"⛺","alt":"Tent"},{"obj":"🌁","alt":"Foggy"},{"obj":"🌃","alt":"Night with Stars"},{"obj":"🏙️","alt":"Cityscape"},{"obj":"🌄","alt":"Sunrise Over Mountains"},{"obj":"🌅","alt":"Sunrise"},{"obj":"🌆","alt":"Cityscape at Dusk"},{"obj":"🌇","alt":"Sunset"},{"obj":"🌉","alt":"Bridge at Night"},{"obj":"🎠","alt":"Carousel Horse"},{"obj":"🛝","alt":"Playground Slide"},{"obj":"🎡","alt":"Ferris Wheel"},{"obj":"🎢","alt":"Roller Coaster"},{"obj":"🚂","alt":"Locomotive"},{"obj":"🚃","alt":"Railway Car"},{"obj":"🚄","alt":"High-Speed Train"},{"obj":"🚅","alt":"Bullet Train"},{"obj":"🚆","alt":"Train"},{"obj":"🚇","alt":"Metro"},{"obj":"🚈","alt":"Light Rail"},{"obj":"🚉","alt":"Station"},{"obj":"🚊","alt":"Tram"},{"obj":"🚝","alt":"Monorail"},{"obj":"🚞","alt":"Mountain Railway"},{"obj":"🚋","alt":"Tram Car"},{"obj":"🚌","alt":"Bus"},{"obj":"🚍","alt":"Oncoming Bus"},{"obj":"🚎","alt":"Trolleybus"},{"obj":"🚐","alt":"Minibus"},{"obj":"🚑","alt":"Ambulance"},{"obj":"🚒","alt":"Fire Engine"},{"obj":"🚓","alt":"Police Car"},{"obj":"🚔","alt":"Oncoming Police Car"},{"obj":"🚕","alt":"Taxi"},{"obj":"🚖","alt":"Oncoming Taxi"},{"obj":"🚗","alt":"Automobile"},{"obj":"🚘","alt":"Oncoming Automobile"},{"obj":"🚙","alt":"Sport Utility Vehicle"},{"obj":"🛻","alt":"Pickup Truck"},{"obj":"🚚","alt":"Delivery Truck"},{"obj":"🚛","alt":"Articulated Lorry"},{"obj":"🚜","alt":"Tractor"},{"obj":"🏎️","alt":"Racing Car"},{"obj":"🏍️","alt":"Motorcycle"},{"obj":"🛵","alt":"Motor Scooter"},{"obj":"🛺","alt":"Auto Rickshaw"},{"obj":"🚲","alt":"Bicycle"},{"obj":"🛴","alt":"Kick Scooter"},{"obj":"🚏","alt":"Bus Stop"},{"obj":"🛣️","alt":"Motorway"},{"obj":"🛤️","alt":"Railway Track"},{"obj":"⛽","alt":"Fuel Pump"},{"obj":"🛞","alt":"Wheel"},{"obj":"🚨","alt":"Police Car Light"},{"obj":"🚥","alt":"Horizontal Traffic Light"},{"obj":"🚦","alt":"Vertical Traffic Light"},{"obj":"🚧","alt":"Construction"},{"obj":"⚓","alt":"Anchor"},{"obj":"🛟","alt":"Ring Buoy"},{"obj":"⛵","alt":"Sailboat"},{"obj":"🚤","alt":"Speedboat"},{"obj":"🛳️","alt":"Passenger Ship"},{"obj":"⛴️","alt":"Ferry"},{"obj":"🛥️","alt":"Motor Boat"},{"obj":"🚢","alt":"Ship"},{"obj":"✈️","alt":"Airplane"},{"obj":"🛩️","alt":"Small Airplane"},{"obj":"🛫","alt":"Airplane Departure"},{"obj":"🛬","alt":"Airplane Arrival"},{"obj":"🪂","alt":"Parachute"},{"obj":"💺","alt":"Seat"},{"obj":"🚁","alt":"Helicopter"},{"obj":"🚟","alt":"Suspension Railway"},{"obj":"🚠","alt":"Mountain Cableway"},{"obj":"🚡","alt":"Aerial Tramway"},{"obj":"🛰️","alt":"Satellite"},{"obj":"🚀","alt":"Rocket"},{"obj":"🛸","alt":"Flying Saucer"},{"obj":"🪐","alt":"Ringed Planet"},{"obj":"🌠","alt":"Shooting Star"},{"obj":"🌌","alt":"Milky Way"},{"obj":"⛱️","alt":"Umbrella on Ground"},{"obj":"🎆","alt":"Fireworks"},{"obj":"🎇","alt":"Sparkler"},{"obj":"🎑","alt":"Moon Viewing Ceremony"},{"obj":"💴","alt":"Yen Banknote"},{"obj":"💵","alt":"Dollar Banknote"},{"obj":"💶","alt":"Euro Banknote"},{"obj":"💷","alt":"Pound Banknote"},{"obj":"🗿","alt":"Moai"},{"obj":"🛂","alt":"Passport Control"},{"obj":"🛃","alt":"Customs"},{"obj":"🛄","alt":"Baggage Claim"},{"obj":"🛅","alt":"Left Luggage"}]},
      objects = {"name":"Objects","key":"objects","mob":"💿","emojis":[{"obj":"💌","alt":"Love Letter"},{"obj":"🕳️","alt":"Hole"},{"obj":"💣","alt":"Bomb"},{"obj":"🛀","alt":"Person Taking Bath"},{"obj":"🛌","alt":"Person in Bed"},{"obj":"🔪","alt":"Kitchen Knife"},{"obj":"🏺","alt":"Amphora"},{"obj":"🗺️","alt":"World Map"},{"obj":"🧭","alt":"Compass"},{"obj":"🧱","alt":"Brick"},{"obj":"💈","alt":"Barber Pole"},{"obj":"🦽","alt":"Manual Wheelchair"},{"obj":"🦼","alt":"Motorized Wheelchair"},{"obj":"🛢️","alt":"Oil Drum"},{"obj":"🛎️","alt":"Bellhop Bell"},{"obj":"🧳","alt":"Luggage"},{"obj":"⌛","alt":"Hourglass Done"},{"obj":"⏳","alt":"Hourglass Not Done"},{"obj":"⌚","alt":"Watch"},{"obj":"⏰","alt":"Alarm Clock"},{"obj":"⏱️","alt":"Stopwatch"},{"obj":"⏲️","alt":"Timer Clock"},{"obj":"🕰️","alt":"Mantelpiece Clock"},{"obj":"🌡️","alt":"Thermometer"},{"obj":"⛱️","alt":"Umbrella on Ground"},{"obj":"🧨","alt":"Firecracker"},{"obj":"🎈","alt":"Balloon"},{"obj":"🎉","alt":"Party Popper"},{"obj":"🎊","alt":"Confetti Ball"},{"obj":"🎎","alt":"Japanese Dolls"},{"obj":"🎏","alt":"Carp Streamer"},{"obj":"🎐","alt":"Wind Chime"},{"obj":"🧧","alt":"Red Envelope"},{"obj":"🎀","alt":"Ribbon"},{"obj":"🎁","alt":"Wrapped Gift"},{"obj":"🤿","alt":"Diving Mask"},{"obj":"🪀","alt":"Yo-Yo"},{"obj":"🪁","alt":"Kite"},{"obj":"🔮","alt":"Crystal Ball"},{"obj":"🪄","alt":"Magic Wand"},{"obj":"🧿","alt":"Nazar Amulet"},{"obj":"🪬","alt":"Hamsa"},{"obj":"🕹️","alt":"Joystick"},{"obj":"🧸","alt":"Teddy Bear"},{"obj":"🪅","alt":"Piñata"},{"obj":"🪆","alt":"Nesting Dolls"},{"obj":"🖼️","alt":"Framed Picture"},{"obj":"🧵","alt":"Thread"},{"obj":"🪡","alt":"Sewing Needle"},{"obj":"🧶","alt":"Yarn"},{"obj":"🪢","alt":"Knot"},{"obj":"🛍️","alt":"Shopping Bags"},{"obj":"📿","alt":"Prayer Beads"},{"obj":"💎","alt":"Gem Stone"},{"obj":"📯","alt":"Postal Horn"},{"obj":"🎙️","alt":"Studio Microphone"},{"obj":"🎚️","alt":"Level Slider"},{"obj":"🎛️","alt":"Control Knobs"},{"obj":"📻","alt":"Radio"},{"obj":"🪕","alt":"Banjo"},{"obj":"📱","alt":"Mobile Phone"},{"obj":"📲","alt":"Mobile Phone with Arrow"},{"obj":"☎️","alt":"Telephone"},{"obj":"📞","alt":"Telephone Receiver"},{"obj":"📟","alt":"Pager"},{"obj":"📠","alt":"Fax Machine"},{"obj":"🔋","alt":"Battery"},{"obj":"🔌","alt":"Electric Plug"},{"obj":"💻","alt":"Laptop"},{"obj":"🖥️","alt":"Desktop Computer"},{"obj":"🖨️","alt":"Printer"},{"obj":"⌨️","alt":"Keyboard"},{"obj":"🖱️","alt":"Computer Mouse"},{"obj":"🖲️","alt":"Trackball"},{"obj":"💽","alt":"Computer Disk"},{"obj":"💾","alt":"Floppy Disk"},{"obj":"💿","alt":"Optical Disk"},{"obj":"📀","alt":"DVD"},{"obj":"🧮","alt":"Abacus"},{"obj":"🎥","alt":"Movie Camera"},{"obj":"🎞️","alt":"Film Frames"},{"obj":"📽️","alt":"Film Projector"},{"obj":"📺","alt":"Television"},{"obj":"📷","alt":"Camera"},{"obj":"📸","alt":"Camera with Flash"},{"obj":"📹","alt":"Video Camera"},{"obj":"📼","alt":"Videocassette"},{"obj":"🔍","alt":"Magnifying Glass Tilted Left"},{"obj":"🔎","alt":"Magnifying Glass Tilted Right"},{"obj":"🕯️","alt":"Candle"},{"obj":"💡","alt":"Light Bulb"},{"obj":"🔦","alt":"Flashlight"},{"obj":"🏮","alt":"Red Paper Lantern"},{"obj":"🪔","alt":"Diya Lamp"},{"obj":"📔","alt":"Notebook with Decorative Cover"},{"obj":"📕","alt":"Closed Book"},{"obj":"📖","alt":"Open Book"},{"obj":"📗","alt":"Green Book"},{"obj":"📘","alt":"Blue Book"},{"obj":"📙","alt":"Orange Book"},{"obj":"📚","alt":"Books"},{"obj":"📓","alt":"Notebook"},{"obj":"📒","alt":"Ledger"},{"obj":"📃","alt":"Page with Curl"},{"obj":"📜","alt":"Scroll"},{"obj":"📄","alt":"Page Facing Up"},{"obj":"📰","alt":"Newspaper"},{"obj":"🗞️","alt":"Rolled-Up Newspaper"},{"obj":"📑","alt":"Bookmark Tabs"},{"obj":"🔖","alt":"Bookmark"},{"obj":"🏷️","alt":"Label"},{"obj":"💰","alt":"Money Bag"},{"obj":"🪙","alt":"Coin"},{"obj":"💴","alt":"Yen Banknote"},{"obj":"💵","alt":"Dollar Banknote"},{"obj":"💶","alt":"Euro Banknote"},{"obj":"💷","alt":"Pound Banknote"},{"obj":"💸","alt":"Money with Wings"},{"obj":"💳","alt":"Credit Card"},{"obj":"🧾","alt":"Receipt"},{"obj":"✉️","alt":"Envelope"},{"obj":"📧","alt":"E-Mail"},{"obj":"📨","alt":"Incoming Envelope"},{"obj":"📩","alt":"Envelope with Arrow"},{"obj":"📤","alt":"Outbox Tray"},{"obj":"📥","alt":"Inbox Tray"},{"obj":"📦","alt":"Package"},{"obj":"📫","alt":"Closed Mailbox with Raised Flag"},{"obj":"📪","alt":"Closed Mailbox with Lowered Flag"},{"obj":"📬","alt":"Open Mailbox with Raised Flag"},{"obj":"📭","alt":"Open Mailbox with Lowered Flag"},{"obj":"📮","alt":"Postbox"},{"obj":"🗳️","alt":"Ballot Box with Ballot"},{"obj":"✏️","alt":"Pencil"},{"obj":"✒️","alt":"Black Nib"},{"obj":"🖋️","alt":"Fountain Pen"},{"obj":"🖊️","alt":"Pen"},{"obj":"🖌️","alt":"Paintbrush"},{"obj":"🖍️","alt":"Crayon"},{"obj":"📝","alt":"Memo"},{"obj":"📁","alt":"File Folder"},{"obj":"📂","alt":"Open File Folder"},{"obj":"🗂️","alt":"Card Index Dividers"},{"obj":"📅","alt":"Calendar"},{"obj":"📆","alt":"Tear-Off Calendar"},{"obj":"🗒️","alt":"Spiral Notepad"},{"obj":"🗓️","alt":"Spiral Calendar"},{"obj":"📇","alt":"Card Index"},{"obj":"📈","alt":"Chart Increasing"},{"obj":"📉","alt":"Chart Decreasing"},{"obj":"📊","alt":"Bar Chart"},{"obj":"📋","alt":"Clipboard"},{"obj":"📌","alt":"Pushpin"},{"obj":"📍","alt":"Round Pushpin"},{"obj":"📎","alt":"Paperclip"},{"obj":"🖇️","alt":"Linked Paperclips"},{"obj":"📏","alt":"Straight Ruler"},{"obj":"📐","alt":"Triangular Ruler"},{"obj":"✂️","alt":"Scissors"},{"obj":"🗃️","alt":"Card File Box"},{"obj":"🗄️","alt":"File Cabinet"},{"obj":"🗑️","alt":"Wastebasket"},{"obj":"🔒","alt":"Locked"},{"obj":"🔓","alt":"Unlocked"},{"obj":"🔏","alt":"Locked with Pen"},{"obj":"🔐","alt":"Locked with Key"},{"obj":"🔑","alt":"Key"},{"obj":"🗝️","alt":"Old Key"},{"obj":"🔨","alt":"Hammer"},{"obj":"🪓","alt":"Axe"},{"obj":"⛏️","alt":"Pick"},{"obj":"⚒️","alt":"Hammer and Pick"},{"obj":"🛠️","alt":"Hammer and Wrench"},{"obj":"🗡️","alt":"Dagger"},{"obj":"⚔️","alt":"Crossed Swords"},{"obj":"🔫","alt":"Water Pistol"},{"obj":"🪃","alt":"Boomerang"},{"obj":"🛡️","alt":"Shield"},{"obj":"🪚","alt":"Carpentry Saw"},{"obj":"🔧","alt":"Wrench"},{"obj":"🪛","alt":"Screwdriver"},{"obj":"🔩","alt":"Nut and Bolt"},{"obj":"⚙️","alt":"Gear"},{"obj":"🗜️","alt":"Clamp"},{"obj":"⚖️","alt":"Balance Scale"},{"obj":"🦯","alt":"White Cane"},{"obj":"🔗","alt":"Link"},{"obj":"⛓️","alt":"Chains"},{"obj":"🪝","alt":"Hook"},{"obj":"🧰","alt":"Toolbox"},{"obj":"🧲","alt":"Magnet"},{"obj":"🪜","alt":"Ladder"},{"obj":"⚗️","alt":"Alembic"},{"obj":"🧪","alt":"Test Tube"},{"obj":"🧫","alt":"Petri Dish"},{"obj":"🧬","alt":"DNA"},{"obj":"🔬","alt":"Microscope"},{"obj":"🔭","alt":"Telescope"},{"obj":"📡","alt":"Satellite Antenna"},{"obj":"💉","alt":"Syringe"},{"obj":"🩸","alt":"Drop of Blood"},{"obj":"💊","alt":"Pill"},{"obj":"🩹","alt":"Adhesive Bandage"},{"obj":"🩼","alt":"Crutch"},{"obj":"🩺","alt":"Stethoscope"},{"obj":"🚪","alt":"Door"},{"obj":"🪞","alt":"Mirror"},{"obj":"🪟","alt":"Window"},{"obj":"🛏️","alt":"Bed"},{"obj":"🛋️","alt":"Couch and Lamp"},{"obj":"🪑","alt":"Chair"},{"obj":"🚽","alt":"Toilet"},{"obj":"🪠","alt":"Plunger"},{"obj":"🚿","alt":"Shower"},{"obj":"🛁","alt":"Bathtub"},{"obj":"🪤","alt":"Mouse Trap"},{"obj":"🪒","alt":"Razor"},{"obj":"🧴","alt":"Lotion Bottle"},{"obj":"🧷","alt":"Safety Pin"},{"obj":"🧹","alt":"Broom"},{"obj":"🧺","alt":"Basket"},{"obj":"🧻","alt":"Roll of Paper"},{"obj":"🪣","alt":"Bucket"},{"obj":"🧼","alt":"Soap"},{"obj":"🪥","alt":"Toothbrush"},{"obj":"🧽","alt":"Sponge"},{"obj":"🧯","alt":"Fire Extinguisher"},{"obj":"🛒","alt":"Shopping Cart"},{"obj":"🚬","alt":"Cigarette"},{"obj":"⚰️","alt":"Coffin"},{"obj":"🪦","alt":"Headstone"},{"obj":"⚱️","alt":"Funeral Urn"},{"obj":"🗿","alt":"Moai"},{"obj":"🪧","alt":"Placard"},{"obj":"🪪","alt":"Identification Card"},{"obj":"🚰","alt":"Potable Water"}]},
      symbols = {"name":"Symbols","key":"symbols","mob":"💗","emojis":[{"obj":"💘","alt":"Heart with Arrow"},{"obj":"💝","alt":"Heart with Ribbon"},{"obj":"💖","alt":"Sparkling Heart"},{"obj":"💗","alt":"Growing Heart"},{"obj":"💓","alt":"Beating Heart"},{"obj":"💞","alt":"Revolving Hearts"},{"obj":"💕","alt":"Two Hearts"},{"obj":"💟","alt":"Heart Decoration"},{"obj":"❣️","alt":"Heart Exclamation"},{"obj":"💔","alt":"Broken Heart"},{"obj":"❤️‍🔥","alt":"Heart on Fire"},{"obj":"❤️‍🩹","alt":"Mending Heart"},{"obj":"❤️","alt":"Red Heart"},{"obj":"🧡","alt":"Orange Heart"},{"obj":"💛","alt":"Yellow Heart"},{"obj":"💚","alt":"Green Heart"},{"obj":"💙","alt":"Blue Heart"},{"obj":"💜","alt":"Purple Heart"},{"obj":"🤎","alt":"Brown Heart"},{"obj":"🖤","alt":"Black Heart"},{"obj":"🤍","alt":"White Heart"},{"obj":"💯","alt":"Hundred Points"},{"obj":"💢","alt":"Anger Symbol"},{"obj":"💬","alt":"Speech Balloon"},{"obj":"👁️‍🗨️","alt":"Eye in Speech Bubble"},{"obj":"🗨️","alt":"Left Speech Bubble"},{"obj":"🗯️","alt":"Right Anger Bubble"},{"obj":"💭","alt":"Thought Balloon"},{"obj":"💤","alt":"Zzz"},{"obj":"💮","alt":"White Flower"},{"obj":"♨️","alt":"Hot Springs"},{"obj":"💈","alt":"Barber Pole"},{"obj":"🛑","alt":"Stop Sign"},{"obj":"🕛","alt":"Twelve O’Clock"},{"obj":"🕧","alt":"Twelve-Thirty"},{"obj":"🕐","alt":"One O’Clock"},{"obj":"🕜","alt":"One-Thirty"},{"obj":"🕑","alt":"Two O’Clock"},{"obj":"🕝","alt":"Two-Thirty"},{"obj":"🕒","alt":"Three O’Clock"},{"obj":"🕞","alt":"Three-Thirty"},{"obj":"🕓","alt":"Four O’Clock"},{"obj":"🕟","alt":"Four-Thirty"},{"obj":"🕔","alt":"Five O’Clock"},{"obj":"🕠","alt":"Five-Thirty"},{"obj":"🕕","alt":"Six O’Clock"},{"obj":"🕡","alt":"Six-Thirty"},{"obj":"🕖","alt":"Seven O’Clock"},{"obj":"🕢","alt":"Seven-Thirty"},{"obj":"🕗","alt":"Eight O’Clock"},{"obj":"🕣","alt":"Eight-Thirty"},{"obj":"🕘","alt":"Nine O’Clock"},{"obj":"🕤","alt":"Nine-Thirty"},{"obj":"🕙","alt":"Ten O’Clock"},{"obj":"🕥","alt":"Ten-Thirty"},{"obj":"🕚","alt":"Eleven O’Clock"},{"obj":"🕦","alt":"Eleven-Thirty"},{"obj":"🌀","alt":"Cyclone"},{"obj":"♠️","alt":"Spade Suit"},{"obj":"♥️","alt":"Heart Suit"},{"obj":"♦️","alt":"Diamond Suit"},{"obj":"♣️","alt":"Club Suit"},{"obj":"🃏","alt":"Joker"},{"obj":"🀄","alt":"Mahjong Red Dragon"},{"obj":"🎴","alt":"Flower Playing Cards"},{"obj":"🔇","alt":"Muted Speaker"},{"obj":"🔈","alt":"Speaker Low Volume"},{"obj":"🔉","alt":"Speaker Medium Volume"},{"obj":"🔊","alt":"Speaker High Volume"},{"obj":"📢","alt":"Loudspeaker"},{"obj":"📣","alt":"Megaphone"},{"obj":"📯","alt":"Postal Horn"},{"obj":"🔔","alt":"Bell"},{"obj":"🔕","alt":"Bell with Slash"},{"obj":"🎵","alt":"Musical Note"},{"obj":"🎶","alt":"Musical Notes"},{"obj":"💹","alt":"Chart Increasing with Yen"},{"obj":"🛗","alt":"Elevator"},{"obj":"🏧","alt":"ATM Sign"},{"obj":"🚮","alt":"Litter in Bin Sign"},{"obj":"🚰","alt":"Potable Water"},{"obj":"♿","alt":"Wheelchair Symbol"},{"obj":"🚹","alt":"Men’s Room"},{"obj":"🚺","alt":"Women’s Room"},{"obj":"🚻","alt":"Restroom"},{"obj":"🚼","alt":"Baby Symbol"},{"obj":"🚾","alt":"Water Closet"},{"obj":"⚠️","alt":"Warning"},{"obj":"🚸","alt":"Children Crossing"},{"obj":"⛔","alt":"No Entry"},{"obj":"🚫","alt":"Prohibited"},{"obj":"🚳","alt":"No Bicycles"},{"obj":"🚭","alt":"No Smoking"},{"obj":"🚯","alt":"No Littering"},{"obj":"🚱","alt":"Non-Potable Water"},{"obj":"🚷","alt":"No Pedestrians"},{"obj":"📵","alt":"No Mobile Phones"},{"obj":"🔞","alt":"No One Under Eighteen"},{"obj":"☢️","alt":"Radioactive"},{"obj":"☣️","alt":"Biohazard"},{"obj":"⬆️","alt":"Up Arrow"},{"obj":"↗️","alt":"Up-Right Arrow"},{"obj":"➡️","alt":"Right Arrow"},{"obj":"↘️","alt":"Down-Right Arrow"},{"obj":"⬇️","alt":"Down Arrow"},{"obj":"↙️","alt":"Down-Left Arrow"},{"obj":"⬅️","alt":"Left Arrow"},{"obj":"↖️","alt":"Up-Left Arrow"},{"obj":"↕️","alt":"Up-Down Arrow"},{"obj":"↔️","alt":"Left-Right Arrow"},{"obj":"↩️","alt":"Right Arrow Curving Left"},{"obj":"↪️","alt":"Left Arrow Curving Right"},{"obj":"⤴️","alt":"Right Arrow Curving Up"},{"obj":"⤵️","alt":"Right Arrow Curving Down"},{"obj":"🔃","alt":"Clockwise Vertical Arrows"},{"obj":"🔄","alt":"Counterclockwise Arrows Button"},{"obj":"🔙","alt":"Back Arrow"},{"obj":"🔚","alt":"End Arrow"},{"obj":"🔛","alt":"On! Arrow"},{"obj":"🔜","alt":"Soon Arrow"},{"obj":"🔝","alt":"Top Arrow"},{"obj":"🛐","alt":"Place of Worship"},{"obj":"⚛️","alt":"Atom Symbol"},{"obj":"🕉️","alt":"Om"},{"obj":"✡️","alt":"Star of David"},{"obj":"☸️","alt":"Wheel of Dharma"},{"obj":"☯️","alt":"Yin Yang"},{"obj":"✝️","alt":"Latin Cross"},{"obj":"☦️","alt":"Orthodox Cross"},{"obj":"☪️","alt":"Star and Crescent"},{"obj":"☮️","alt":"Peace Symbol"},{"obj":"🕎","alt":"Menorah"},{"obj":"🔯","alt":"Dotted Six-Pointed Star"},{"obj":"♈","alt":"Aries"},{"obj":"♉","alt":"Taurus"},{"obj":"♊","alt":"Gemini"},{"obj":"♋","alt":"Cancer"},{"obj":"♌","alt":"Leo"},{"obj":"♍","alt":"Virgo"},{"obj":"♎","alt":"Libra"},{"obj":"♏","alt":"Scorpio"},{"obj":"♐","alt":"Sagittarius"},{"obj":"♑","alt":"Capricorn"},{"obj":"♒","alt":"Aquarius"},{"obj":"♓","alt":"Pisces"},{"obj":"⛎","alt":"Ophiuchus"},{"obj":"🔀","alt":"Shuffle Tracks Button"},{"obj":"🔁","alt":"Repeat Button"},{"obj":"🔂","alt":"Repeat Single Button"},{"obj":"▶️","alt":"Play Button"},{"obj":"⏩","alt":"Fast-Forward Button"},{"obj":"⏭️","alt":"Next Track Button"},{"obj":"⏯️","alt":"Play or Pause Button"},{"obj":"◀️","alt":"Reverse Button"},{"obj":"⏪","alt":"Fast Reverse Button"},{"obj":"⏮️","alt":"Last Track Button"},{"obj":"🔼","alt":"Upwards Button"},{"obj":"⏫","alt":"Fast Up Button"},{"obj":"🔽","alt":"Downwards Button"},{"obj":"⏬","alt":"Fast Down Button"},{"obj":"⏸️","alt":"Pause Button"},{"obj":"⏹️","alt":"Stop Button"},{"obj":"⏺️","alt":"Record Button"},{"obj":"⏏️","alt":"Eject Button"},{"obj":"🎦","alt":"Cinema"},{"obj":"🔅","alt":"Dim Button"},{"obj":"🔆","alt":"Bright Button"},{"obj":"📶","alt":"Antenna Bars"},{"obj":"📳","alt":"Vibration Mode"},{"obj":"📴","alt":"Mobile Phone Off"},{"obj":"♀️","alt":"Female Sign"},{"obj":"♂️","alt":"Male Sign"},{"obj":"✖️","alt":"Multiply"},{"obj":"➕","alt":"Plus"},{"obj":"➖","alt":"Minus"},{"obj":"➗","alt":"Divide"},{"obj":"🟰","alt":"Heavy Equals Sign"},{"obj":"♾️","alt":"Infinity"},{"obj":"‼️","alt":"Double Exclamation Mark"},{"obj":"⁉️","alt":"Exclamation Question Mark"},{"obj":"❓","alt":"Red Question Mark"},{"obj":"❔","alt":"White Question Mark"},{"obj":"❕","alt":"White Exclamation Mark"},{"obj":"❗","alt":"Red Exclamation Mark"},{"obj":"〰️","alt":"Wavy Dash"},{"obj":"💱","alt":"Currency Exchange"},{"obj":"💲","alt":"Heavy Dollar Sign"},{"obj":"⚕️","alt":"Medical Symbol"},{"obj":"♻️","alt":"Recycling Symbol"},{"obj":"⚜️","alt":"Fleur-de-lis"},{"obj":"🔱","alt":"Trident Emblem"},{"obj":"📛","alt":"Name Badge"},{"obj":"🔰","alt":"Japanese Symbol for Beginner"},{"obj":"⭕","alt":"Hollow Red Circle"},{"obj":"✅","alt":"Check Mark Button"},{"obj":"☑️","alt":"Check Box with Check"},{"obj":"✔️","alt":"Check Mark"},{"obj":"❌","alt":"Cross Mark"},{"obj":"❎","alt":"Cross Mark Button"},{"obj":"➰","alt":"Curly Loop"},{"obj":"➿","alt":"Double Curly Loop"},{"obj":"〽️","alt":"Part Alternation Mark"},{"obj":"✳️","alt":"Eight-Spoked Asterisk"},{"obj":"✴️","alt":"Eight-Pointed Star"},{"obj":"❇️","alt":"Sparkle"},{"obj":"©️","alt":"Copyright"},{"obj":"®️","alt":"Registered"},{"obj":"™️","alt":"Trade Mark"},{"obj":"#️⃣","alt":"Keycap Number Sign"},{"obj":"*️⃣","alt":"Keycap Asterisk"},{"obj":"0️⃣","alt":"Keycap Digit Zero"},{"obj":"1️⃣","alt":"Keycap Digit One"},{"obj":"2️⃣","alt":"Keycap Digit Two"},{"obj":"3️⃣","alt":"Keycap Digit Three"},{"obj":"4️⃣","alt":"Keycap Digit Four"},{"obj":"5️⃣","alt":"Keycap Digit Five"},{"obj":"6️⃣","alt":"Keycap Digit Six"},{"obj":"7️⃣","alt":"Keycap Digit Seven"},{"obj":"8️⃣","alt":"Keycap Digit Eight"},{"obj":"9️⃣","alt":"Keycap Digit Nine"},{"obj":"🔟","alt":"Keycap: 10"},{"obj":"🔠","alt":"Input Latin Uppercase"},{"obj":"🔡","alt":"Input Latin Lowercase"},{"obj":"🔢","alt":"Input Numbers"},{"obj":"🔣","alt":"Input Symbols"},{"obj":"🔤","alt":"Input Latin Letters"},{"obj":"🅰️","alt":"A Button (Blood Type)"},{"obj":"🆎","alt":"AB Button (Blood Type)"},{"obj":"🅱️","alt":"B Button (Blood Type)"},{"obj":"🆑","alt":"CL Button"},{"obj":"🆒","alt":"Cool Button"},{"obj":"🆓","alt":"Free Button"},{"obj":"ℹ️","alt":"Information"},{"obj":"🆔","alt":"ID Button"},{"obj":"Ⓜ️","alt":"Circled M"},{"obj":"🆕","alt":"New Button"},{"obj":"🆖","alt":"NG Button"},{"obj":"🅾️","alt":"O Button (Blood Type)"},{"obj":"🆗","alt":"OK Button"},{"obj":"🅿️","alt":"P Button"},{"obj":"🆘","alt":"SOS Button"},{"obj":"🆙","alt":"Up! Button"},{"obj":"🆚","alt":"Vs Button"},{"obj":"🈁","alt":"Japanese “Here” Button"},{"obj":"🈂️","alt":"Japanese “Service Charge” Button"},{"obj":"🈷️","alt":"Japanese “Monthly Amount” Button"},{"obj":"🈶","alt":"Japanese “Not Free of Charge” Button"},{"obj":"🈯","alt":"Japanese “Reserved” Button"},{"obj":"🉐","alt":"Japanese “Bargain” Button"},{"obj":"🈹","alt":"Japanese “Discount” Button"},{"obj":"🈚","alt":"Japanese “Free of Charge” Button"},{"obj":"🈲","alt":"Japanese “Prohibited” Button"},{"obj":"🉑","alt":"Japanese “Acceptable” Button"},{"obj":"🈸","alt":"Japanese “Application” Button"},{"obj":"🈴","alt":"Japanese “Passing Grade” Button"},{"obj":"🈳","alt":"Japanese “Vacancy” Button"},{"obj":"㊗️","alt":"Japanese “Congratulations” Button"},{"obj":"㊙️","alt":"Japanese “Secret” Button"},{"obj":"🈺","alt":"Japanese “Open for Business” Button"},{"obj":"🈵","alt":"Japanese “No Vacancy” Button"},{"obj":"🔴","alt":"Red Circle"},{"obj":"🟠","alt":"Orange Circle"},{"obj":"🟡","alt":"Yellow Circle"},{"obj":"🟢","alt":"Green Circle"},{"obj":"🔵","alt":"Blue Circle"},{"obj":"🟣","alt":"Purple Circle"},{"obj":"🟤","alt":"Brown Circle"},{"obj":"⚫","alt":"Black Circle"},{"obj":"⚪","alt":"White Circle"},{"obj":"🟥","alt":"Red Square"},{"obj":"🟧","alt":"Orange Square"},{"obj":"🟨","alt":"Yellow Square"},{"obj":"🟩","alt":"Green Square"},{"obj":"🟦","alt":"Blue Square"},{"obj":"🟪","alt":"Purple Square"},{"obj":"🟫","alt":"Brown Square"},{"obj":"⬛","alt":"Black Large Square"},{"obj":"⬜","alt":"White Large Square"},{"obj":"◼️","alt":"Black Medium Square"},{"obj":"◻️","alt":"White Medium Square"},{"obj":"◾","alt":"Black Medium-Small Square"},{"obj":"◽","alt":"White Medium-Small Square"},{"obj":"▪️","alt":"Black Small Square"},{"obj":"▫️","alt":"White Small Square"},{"obj":"🔶","alt":"Large Orange Diamond"},{"obj":"🔷","alt":"Large Blue Diamond"},{"obj":"🔸","alt":"Small Orange Diamond"},{"obj":"🔹","alt":"Small Blue Diamond"},{"obj":"🔺","alt":"Red Triangle Pointed Up"},{"obj":"🔻","alt":"Red Triangle Pointed Down"},{"obj":"💠","alt":"Diamond with a Dot"},{"obj":"🔘","alt":"Radio Button"},{"obj":"🔳","alt":"White Square Button"},{"obj":"🔲","alt":"Black Square Button"},]},
      flags = {"name":"Flags","key":"flags","mob":"🎌","emojis":[{"obj":"🏁","alt":"Chequered Flag"},{"obj":"🚩","alt":"Triangular Flag"},{"obj":"🎌","alt":"Crossed Flags"},{"obj":"🏴","alt":"Black Flag"},{"obj":"🏳️","alt":"White Flag"},{"obj":"🏳️‍🌈","alt":"Rainbow Flag"},{"obj":"🏳️‍⚧️","alt":"Transgender Flag"},{"obj":"🏴‍☠️","alt":"Pirate Flag"},{"obj":"🇦🇨","alt":"Flag: Ascension Island"},{"obj":"🇦🇩","alt":"Flag: Andorra"},{"obj":"🇦🇪","alt":"Flag: United Arab Emirates"},{"obj":"🇦🇫","alt":"Flag: Afghanistan"},{"obj":"🇦🇬","alt":"Flag: Antigua & Barbuda"},{"obj":"🇦🇮","alt":"Flag: Anguilla"},{"obj":"🇦🇱","alt":"Flag: Albania"},{"obj":"🇦🇲","alt":"Flag: Armenia"},{"obj":"🇦🇴","alt":"Flag: Angola"},{"obj":"🇦🇶","alt":"Flag: Antarctica"},{"obj":"🇦🇷","alt":"Flag: Argentina"},{"obj":"🇦🇸","alt":"Flag: American Samoa"},{"obj":"🇦🇹","alt":"Flag: Austria"},{"obj":"🇦🇺","alt":"Flag: Australia"},{"obj":"🇦🇼","alt":"Flag: Aruba"},{"obj":"🇦🇽","alt":"Flag: Åland Islands"},{"obj":"🇦🇿","alt":"Flag: Azerbaijan"},{"obj":"🇧🇦","alt":"Flag: Bosnia & Herzegovina"},{"obj":"🇧🇧","alt":"Flag: Barbados"},{"obj":"🇧🇩","alt":"Flag: Bangladesh"},{"obj":"🇧🇪","alt":"Flag: Belgium"},{"obj":"🇧🇫","alt":"Flag: Burkina Faso"},{"obj":"🇧🇬","alt":"Flag: Bulgaria"},{"obj":"🇧🇭","alt":"Flag: Bahrain"},{"obj":"🇧🇮","alt":"Flag: Burundi"},{"obj":"🇧🇯","alt":"Flag: Benin"},{"obj":"🇧🇱","alt":"Flag: St. Barthélemy"},{"obj":"🇧🇲","alt":"Flag: Bermuda"},{"obj":"🇧🇳","alt":"Flag: Brunei"},{"obj":"🇧🇴","alt":"Flag: Bolivia"},{"obj":"🇧🇶","alt":"Flag: Caribbean Netherlands"},{"obj":"🇧🇷","alt":"Flag: Brazil"},{"obj":"🇧🇸","alt":"Flag: Bahamas"},{"obj":"🇧🇹","alt":"Flag: Bhutan"},{"obj":"🇧🇻","alt":"Flag: Bouvet Island"},{"obj":"🇧🇼","alt":"Flag: Botswana"},{"obj":"🇧🇾","alt":"Flag: Belarus"},{"obj":"🇧🇿","alt":"Flag: Belize"},{"obj":"🇨🇦","alt":"Flag: Canada"},{"obj":"🇨🇨","alt":"Flag: Cocos (Keeling) Islands"},{"obj":"🇨🇩","alt":"Flag: Congo - Kinshasa"},{"obj":"🇨🇫","alt":"Flag: Central African Republic"},{"obj":"🇨🇬","alt":"Flag: Congo - Brazzaville"},{"obj":"🇨🇭","alt":"Flag: Switzerland"},{"obj":"🇨🇮","alt":"Flag: Côte d’Ivoire"},{"obj":"🇨🇰","alt":"Flag: Cook Islands"},{"obj":"🇨🇱","alt":"Flag: Chile"},{"obj":"🇨🇲","alt":"Flag: Cameroon"},{"obj":"🇨🇳","alt":"Flag: China"},{"obj":"🇨🇴","alt":"Flag: Colombia"},{"obj":"🇨🇵","alt":"Flag: Clipperton Island"},{"obj":"🇨🇷","alt":"Flag: Costa Rica"},{"obj":"🇨🇺","alt":"Flag: Cuba"},{"obj":"🇨🇻","alt":"Flag: Cape Verde"},{"obj":"🇨🇼","alt":"Flag: Curaçao"},{"obj":"🇨🇽","alt":"Flag: Christmas Island"},{"obj":"🇨🇾","alt":"Flag: Cyprus"},{"obj":"🇨🇿","alt":"Flag: Czechia"},{"obj":"🇩🇪","alt":"Flag: Germany"},{"obj":"🇩🇬","alt":"Flag: Diego Garcia"},{"obj":"🇩🇯","alt":"Flag: Djibouti"},{"obj":"🇩🇰","alt":"Flag: Denmark"},{"obj":"🇩🇲","alt":"Flag: Dominica"},{"obj":"🇩🇴","alt":"Flag: Dominican Republic"},{"obj":"🇩🇿","alt":"Flag: Algeria"},{"obj":"🇪🇦","alt":"Flag: Ceuta & Melilla"},{"obj":"🇪🇨","alt":"Flag: Ecuador"},{"obj":"🇪🇪","alt":"Flag: Estonia"},{"obj":"🇪🇬","alt":"Flag: Egypt"},{"obj":"🇪🇭","alt":"Flag: Western Sahara"},{"obj":"🇪🇷","alt":"Flag: Eritrea"},{"obj":"🇪🇸","alt":"Flag: Spain"},{"obj":"🇪🇹","alt":"Flag: Ethiopia"},{"obj":"🇪🇺","alt":"Flag: European Union"},{"obj":"🇫🇮","alt":"Flag: Finland"},{"obj":"🇫🇯","alt":"Flag: Fiji"},{"obj":"🇫🇰","alt":"Flag: Falkland Islands"},{"obj":"🇫🇲","alt":"Flag: Micronesia"},{"obj":"🇫🇴","alt":"Flag: Faroe Islands"},{"obj":"🇫🇷","alt":"Flag: France"},{"obj":"🇬🇦","alt":"Flag: Gabon"},{"obj":"🇬🇧","alt":"Flag: United Kingdom"},{"obj":"🇬🇩","alt":"Flag: Grenada"},{"obj":"🇬🇪","alt":"Flag: Georgia"},{"obj":"🇬🇫","alt":"Flag: French Guiana"},{"obj":"🇬🇬","alt":"Flag: Guernsey"},{"obj":"🇬🇭","alt":"Flag: Ghana"},{"obj":"🇬🇮","alt":"Flag: Gibraltar"},{"obj":"🇬🇱","alt":"Flag: Greenland"},{"obj":"🇬🇲","alt":"Flag: Gambia"},{"obj":"🇬🇳","alt":"Flag: Guinea"},{"obj":"🇬🇵","alt":"Flag: Guadeloupe"},{"obj":"🇬🇶","alt":"Flag: Equatorial Guinea"},{"obj":"🇬🇷","alt":"Flag: Greece"},{"obj":"🇬🇸","alt":"Flag: South Georgia & South Sandwich Islands"},{"obj":"🇬🇹","alt":"Flag: Guatemala"},{"obj":"🇬🇺","alt":"Flag: Guam"},{"obj":"🇬🇼","alt":"Flag: Guinea-Bissau"},{"obj":"🇬🇾","alt":"Flag: Guyana"},{"obj":"🇭🇰","alt":"Flag: Hong Kong SAR China"},{"obj":"🇭🇲","alt":"Flag: Heard & McDonald Islands"},{"obj":"🇭🇳","alt":"Flag: Honduras"},{"obj":"🇭🇷","alt":"Flag: Croatia"},{"obj":"🇭🇹","alt":"Flag: Haiti"},{"obj":"🇭🇺","alt":"Flag: Hungary"},{"obj":"🇮🇨","alt":"Flag: Canary Islands"},{"obj":"🇮🇩","alt":"Flag: Indonesia"},{"obj":"🇮🇪","alt":"Flag: Ireland"},{"obj":"🇮🇱","alt":"Flag: Israel"},{"obj":"🇮🇲","alt":"Flag: Isle of Man"},{"obj":"🇮🇳","alt":"Flag: India"},{"obj":"🇮🇴","alt":"Flag: British Indian Ocean Territory"},{"obj":"🇮🇶","alt":"Flag: Iraq"},{"obj":"🇮🇷","alt":"Flag: Iran"},{"obj":"🇮🇸","alt":"Flag: Iceland"},{"obj":"🇮🇹","alt":"Flag: Italy"},{"obj":"🇯🇪","alt":"Flag: Jersey"},{"obj":"🇯🇲","alt":"Flag: Jamaica"},{"obj":"🇯🇴","alt":"Flag: Jordan"},{"obj":"🇯🇵","alt":"Flag: Japan"},{"obj":"🇰🇪","alt":"Flag: Kenya"},{"obj":"🇰🇬","alt":"Flag: Kyrgyzstan"},{"obj":"🇰🇭","alt":"Flag: Cambodia"},{"obj":"🇰🇮","alt":"Flag: Kiribati"},{"obj":"🇰🇲","alt":"Flag: Comoros"},{"obj":"🇰🇳","alt":"Flag: St. Kitts & Nevis"},{"obj":"🇰🇵","alt":"Flag: North Korea"},{"obj":"🇰🇷","alt":"Flag: South Korea"},{"obj":"🇰🇼","alt":"Flag: Kuwait"},{"obj":"🇰🇾","alt":"Flag: Cayman Islands"},{"obj":"🇰🇿","alt":"Flag: Kazakhstan"},{"obj":"🇱🇦","alt":"Flag: Laos"},{"obj":"🇱🇧","alt":"Flag: Lebanon"},{"obj":"🇱🇨","alt":"Flag: St. Lucia"},{"obj":"🇱🇮","alt":"Flag: Liechtenstein"},{"obj":"🇱🇰","alt":"Flag: Sri Lanka"},{"obj":"🇱🇷","alt":"Flag: Liberia"},{"obj":"🇱🇸","alt":"Flag: Lesotho"},{"obj":"🇱🇹","alt":"Flag: Lithuania"},{"obj":"🇱🇺","alt":"Flag: Luxembourg"},{"obj":"🇱🇻","alt":"Flag: Latvia"},{"obj":"🇱🇾","alt":"Flag: Libya"},{"obj":"🇲🇦","alt":"Flag: Morocco"},{"obj":"🇲🇨","alt":"Flag: Monaco"},{"obj":"🇲🇩","alt":"Flag: Moldova"},{"obj":"🇲🇪","alt":"Flag: Montenegro"},{"obj":"🇲🇫","alt":"Flag: St. Martin"},{"obj":"🇲🇬","alt":"Flag: Madagascar"},{"obj":"🇲🇭","alt":"Flag: Marshall Islands"},{"obj":"🇲🇰","alt":"Flag: North Macedonia"},{"obj":"🇲🇱","alt":"Flag: Mali"},{"obj":"🇲🇲","alt":"Flag: Myanmar (Burma)"},{"obj":"🇲🇳","alt":"Flag: Mongolia"},{"obj":"🇲🇴","alt":"Flag: Macao Sar China"},{"obj":"🇲🇵","alt":"Flag: Northern Mariana Islands"},{"obj":"🇲🇶","alt":"Flag: Martinique"},{"obj":"🇲🇷","alt":"Flag: Mauritania"},{"obj":"🇲🇸","alt":"Flag: Montserrat"},{"obj":"🇲🇹","alt":"Flag: Malta"},{"obj":"🇲🇺","alt":"Flag: Mauritius"},{"obj":"🇲🇻","alt":"Flag: Maldives"},{"obj":"🇲🇼","alt":"Flag: Malawi"},{"obj":"🇲🇽","alt":"Flag: Mexico"},{"obj":"🇲🇾","alt":"Flag: Malaysia"},{"obj":"🇲🇿","alt":"Flag: Mozambique"},{"obj":"🇳🇦","alt":"Flag: Namibia"},{"obj":"🇳🇨","alt":"Flag: New Caledonia"},{"obj":"🇳🇪","alt":"Flag: Niger"},{"obj":"🇳🇫","alt":"Flag: Norfolk Island"},{"obj":"🇳🇬","alt":"Flag: Nigeria"},{"obj":"🇳🇮","alt":"Flag: Nicaragua"},{"obj":"🇳🇱","alt":"Flag: Netherlands"},{"obj":"🇳🇴","alt":"Flag: Norway"},{"obj":"🇳🇵","alt":"Flag: Nepal"},{"obj":"🇳🇷","alt":"Flag: Nauru"},{"obj":"🇳🇺","alt":"Flag: Niue"},{"obj":"🇳🇿","alt":"Flag: New Zealand"},{"obj":"🇴🇲","alt":"Flag: Oman"},{"obj":"🇵🇦","alt":"Flag: Panama"},{"obj":"🇵🇪","alt":"Flag: Peru"},{"obj":"🇵🇫","alt":"Flag: French Polynesia"},{"obj":"🇵🇬","alt":"Flag: Papua New Guinea"},{"obj":"🇵🇭","alt":"Flag: Philippines"},{"obj":"🇵🇰","alt":"Flag: Pakistan"},{"obj":"🇵🇱","alt":"Flag: Poland"},{"obj":"🇵🇲","alt":"Flag: St. Pierre & Miquelon"},{"obj":"🇵🇳","alt":"Flag: Pitcairn Islands"},{"obj":"🇵🇷","alt":"Flag: Puerto Rico"},{"obj":"🇵🇸","alt":"Flag: Palestinian Territories"},{"obj":"🇵🇹","alt":"Flag: Portugal"},{"obj":"🇵🇼","alt":"Flag: Palau"},{"obj":"🇵🇾","alt":"Flag: Paraguay"},{"obj":"🇶🇦","alt":"Flag: Qatar"},{"obj":"🇷🇪","alt":"Flag: Réunion"},{"obj":"🇷🇴","alt":"Flag: Romania"},{"obj":"🇷🇸","alt":"Flag: Serbia"},{"obj":"🇷🇺","alt":"Flag: Russia"},{"obj":"🇷🇼","alt":"Flag: Rwanda"},{"obj":"🇸🇦","alt":"Flag: Saudi Arabia"},{"obj":"🇸🇧","alt":"Flag: Solomon Islands"},{"obj":"🇸🇨","alt":"Flag: Seychelles"},{"obj":"🇸🇩","alt":"Flag: Sudan"},{"obj":"🇸🇪","alt":"Flag: Sweden"},{"obj":"🇸🇬","alt":"Flag: Singapore"},{"obj":"🇸🇭","alt":"Flag: St. Helena"},{"obj":"🇸🇮","alt":"Flag: Slovenia"},{"obj":"🇸🇯","alt":"Flag: Svalbard & Jan Mayen"},{"obj":"🇸🇰","alt":"Flag: Slovakia"},{"obj":"🇸🇱","alt":"Flag: Sierra Leone"},{"obj":"🇸🇲","alt":"Flag: San Marino"},{"obj":"🇸🇳","alt":"Flag: Senegal"},{"obj":"🇸🇴","alt":"Flag: Somalia"},{"obj":"🇸🇷","alt":"Flag: Suriname"},{"obj":"🇸🇸","alt":"Flag: South Sudan"},{"obj":"🇸🇹","alt":"Flag: São Tomé & Príncipe"},{"obj":"🇸🇻","alt":"Flag: El Salvador"},{"obj":"🇸🇽","alt":"Flag: Sint Maarten"},{"obj":"🇸🇾","alt":"Flag: Syria"},{"obj":"🇸🇿","alt":"Flag: Eswatini"},{"obj":"🇹🇦","alt":"Flag: Tristan Da Cunha"},{"obj":"🇹🇨","alt":"Flag: Turks & Caicos Islands"},{"obj":"🇹🇩","alt":"Flag: Chad"},{"obj":"🇹🇫","alt":"Flag: French Southern Territories"},{"obj":"🇹🇬","alt":"Flag: Togo"},{"obj":"🇹🇭","alt":"Flag: Thailand"},{"obj":"🇹🇯","alt":"Flag: Tajikistan"},{"obj":"🇹🇰","alt":"Flag: Tokelau"},{"obj":"🇹🇱","alt":"Flag: Timor-Leste"},{"obj":"🇹🇲","alt":"Flag: Turkmenistan"},{"obj":"🇹🇳","alt":"Flag: Tunisia"},{"obj":"🇹🇴","alt":"Flag: Tonga"},{"obj":"🇹🇷","alt":"Flag: Turkey"},{"obj":"🇹🇹","alt":"Flag: Trinidad & Tobago"},{"obj":"🇹🇻","alt":"Flag: Tuvalu"},{"obj":"🇹🇼","alt":"Flag: Taiwan"},{"obj":"🇹🇿","alt":"Flag: Tanzania"},{"obj":"🇺🇦","alt":"Flag: Ukraine"},{"obj":"🇺🇬","alt":"Flag: Uganda"},{"obj":"🇺🇲","alt":"Flag: U.S. Outlying Islands"},{"obj":"🇺🇳","alt":"Flag: United Nations"},{"obj":"🇺🇸","alt":"Flag: United States"},{"obj":"🇺🇾","alt":"Flag: Uruguay"},{"obj":"🇺🇿","alt":"Flag: Uzbekistan"},{"obj":"🇻🇦","alt":"Flag: Vatican City"},{"obj":"🇻🇨","alt":"Flag: St. Vincent & Grenadines"},{"obj":"🇻🇪","alt":"Flag: Venezuela"},{"obj":"🇻🇬","alt":"Flag: British Virgin Islands"},{"obj":"🇻🇮","alt":"Flag: U.S. Virgin Islands"},{"obj":"🇻🇳","alt":"Flag: Vietnam"},{"obj":"🇻🇺","alt":"Flag: Vanuatu"},{"obj":"🇼🇫","alt":"Flag: Wallis & Futuna"},{"obj":"🇼🇸","alt":"Flag: Samoa"},{"obj":"🇽🇰","alt":"Flag: Kosovo"},{"obj":"🇾🇪","alt":"Flag: Yemen"},{"obj":"🇾🇹","alt":"Flag: Mayotte"},{"obj":"🇿🇦","alt":"Flag: South Africa"},{"obj":"🇿🇲","alt":"Flag: Zambia"},{"obj":"🇿🇼","alt":"Flag: Zimbabwe"},{"obj":"🏴󠁧󠁢󠁥󠁮󠁧󠁿","alt":"Flag: England"},{"obj":"🏴󠁧󠁢󠁳󠁣󠁴󠁿","alt":"Flag: Scotland"},{"obj":"🏴󠁧󠁢󠁷󠁬󠁳󠁿","alt":"Flag: Wales"},{"obj":"🏴󠁵󠁳󠁴󠁸󠁿","alt":"Flag for Texas (US-TX)"}]};



const UnicodeEmojiModule = {
    // Determine active theme to set button color
    color: (() => {
        if (localStorage.themeDark && localStorage.themeLight) {
            return "var(--engine-content-title)";
        }
        return "ghostwhite";
    })(),

  // CSS for emoji picker
    emojiCSS: `
#spotlight-emojis {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    background: var(--main-bg);
    width: 100%;
    height: 0;
    opacity: 0;
    overflow: hidden;
    padding: 0 1rem;
    border-top: 1px solid var(--border-color);
    border-bottom: 1px solid var(--border-color);
    transition: height 0.2s linear, opacity 0.1s linear, padding 0.2s linear;
    -webkit-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
body.spotlight-mode #spotlight-emojis {
    position: absolute;
    bottom: 0;
    left: 0.7%;
    right: 0.7%;
    width: auto;
    margin-bottom: calc(4rem + 8px);
    overflow-y: auto;
}
#spotlight-emojis.active {
    opacity: 1;
    height: 20rem;
    max-height: 20rem;
    padding: 1rem;
}
body.spotlight-mode #spotlight-emojis.active {
    height: 30vh;
}
#spotlight-emojis spotfilter {
    display: flex;
    gap: 1rem;
    flex-flow: row wrap;
    padding: 0 4px;
}
#spotlight-emojis spotfilter key {
    cursor: pointer;
    padding: 0.6rem 0.8rem 0.8rem 0.8rem;
    word-break: keep-all;
    color: #00838f;
    background: transparent;
    border-radius: 4px;
    border: 1px solid teal;
    transition: transform 0.1s linear;
}
#spotlight-emojis spotfilter key:active {
    transform: scale(0.9);
}
#spotlight-emojis spotfilter key.active {
    cursor: default;
    transform: scale(1) !important;
    background: teal;
    color: ghostwhite;
}
#spotlight-emojis spotfilter key:hover,
#spotlight-emojis spotfilter key:focus {
    background: teal;
    color: ghostwhite;
}
#spotlight-emojis spotfilter key span:last-of-type {
    margin-left: 0.25rem;
    margin-right: 3px;
}
@media screen and (max-width: 1274px) {
    #spotlight-emojis spotfilter key {
        padding: 0.4rem 0.6rem 0.6rem 0.6rem;
    }
    #spotlight-emojis spotfilter key span {
        font-size: 1.2rem;
    }
    #spotlight-emojis spotfilter key span:last-of-type {
        display: none;
    }
}
@media screen and (max-width: 509px) {
    #spotlight-emojis spotfilter key {
        padding: 0.3rem 0.5rem 0.5rem 0.5rem;
    }
}
@media screen and (max-width: 485px) {
    #spotlight-emojis spotfilter {
        gap: 0.75rem;
    }
    #spotlight-emojis spotfilter key {
        padding: 0.3rem 0.4rem 0.4rem 0.4rem;
    }
}
@media screen and (max-width: 435px) {
    #spotlight-emojis spotfilter {
        gap: 0.65rem;
    }
    #spotlight-emojis spotfilter key {
        padding: 0.2rem 0.3rem 0.3rem 0.3rem;
    }
}
@media screen and (max-width: 400px) {
    #spotlight-emojis spotfilter key span {
        font-size: 1rem;
    }
}
#spotlight-emojis spotmoji {
    display: flex;
    flex-flow: row wrap;
    gap: 0 0.75rem;
    font-size: 1.4rem;
    overflow-y: auto;
    overflow-x: hidden;
}
#spotlight-emojis spotmoji x.emoji {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 2.4rem;
    width: 2.4rem;
    margin-bottom: 0.5rem;
    cursor: pointer;
    transition: transform 0.1s linear;
}
#spotlight-emojis spotmoji x.emoji:hover,
#spotlight-emojis spotmoji x.emoji:focus {
    transform: scale(1.4);
}
#spotlight-emojis spotmoji x.emoji:active {
    transform: scale(1.1);
}
#emoji-toggle-btn {
    cursor: pointer;
    color: ${(() => {
        if (localStorage.themeDark && localStorage.themeLight) {
            return "var(--engine-content-title)";
        }
        return "ghostwhite";
    })()};
}
#emoji-toggle-btn:hover {
    color: var(--link-color);
}
    `,

    // JavaScript for emoji functionality
    emojiJS: `
// Replace custom css to filter visible emojis
function emojistyle(key) {
    let style = "#spotlight-emojis spotmoji x.emoji:not(." + key + ") {display: none;}";
    return style;
}

// Show activity and emojis when a filter key is clicked
function filterKey(type, num) {
    let emojiCSS = document.getElementById("emoji-filter");

    document.querySelector("#spotlight-emojis spotfilter key.active").removeAttribute("class");
    document.querySelectorAll("#spotlight-emojis spotfilter key")[num].classList.add("active");

    emojiCSS.innerHTML = emojistyle(type);
    document.querySelector("#spotlight-emojis spotmoji").scrollTo({ top: 0, behavior: 'smooth' });
}

// Toggle emoji picker
function toggleEmojiPicker() {
    let picker = document.getElementById("spotlight-emojis");

    // Close spotlight smileys if open
    let spotlightSmileys = document.getElementById("spotlight-smileys");
    if (spotlightSmileys && spotlightSmileys.classList.contains("shiner")) {
        spotlightSmileys.classList.remove("shiner");
        setTimeout(function() {
            spotlightSmileys.classList.add("fader");
        }, 200);
    }

    // Close smilies-outline if open (for homepage)
    let sOutline = document.getElementById("smilies-outline");
    if (sOutline && sOutline.style.display !== "none") {
        $('#smilies-outline').slideToggle(200);
        setTimeout(function() {
            sOutline.classList.remove("smileys");
            sOutline.classList.remove("emojis");
        }, 200);
    }

    if (picker.classList.contains("active")) {
        picker.classList.remove("active");
    } else {
        picker.classList.add("active");
        document.querySelector("#spotlight-emojis spotmoji").scrollTo({ top: 0, behavior: 'smooth' });
    }
}
    `,

    // Style base for filtering emojis
    emojistyle(key) {
        let style = "#spotlight-emojis spotmoji x.emoji:not(." + key + ") {display: none;}";
        return style;
    },

    // Function for printing the Emojiboard
    print: '',

    echo(key) {
        this.print = this.print + key;
    },

    // Function for Pushing Filter Keys
    setKey(input, num, keyclass) {
        this.echo(`<key `);
        if (keyclass) {
            this.echo(`class="${keyclass}" `);
        }
        this.echo(`onclick="filterKey('${input.key}',${num})">`);
        this.echo(`<span>${input.mob}</span><span>${input.name}</span>`);
        this.echo(`</key>`);
    },

    // Function for Pushing Emojis
    setEmoji(input) {
        for (let x = 0; x < input.emojis.length; x++) {
            this.echo(`<x class="emoji ${input.key}" `);
            this.echo(`title="${input.emojis[x].alt}">`);
            this.echo(input.emojis[x].obj);
            this.echo(`</x>`);
        }
    },

    // Build emoji picker HTML
    buildEmojiHTML() {
        this.print = '';
        this.echo(`<spotfilter>`);
        this.setKey(smileys, 0, "active");
        this.setKey(nature, 1);
        this.setKey(food, 2);
        this.setKey(activity, 3);
        this.setKey(places, 4);
        this.setKey(objects, 5);
        this.setKey(symbols, 6);
        this.setKey(flags, 7);
        this.echo(`</spotfilter>`);
        this.echo(`<spotmoji>`);
        this.setEmoji(smileys);
        this.setEmoji(nature);
        this.setEmoji(food);
        this.setEmoji(activity);
        this.setEmoji(places);
        this.setEmoji(objects);
        this.setEmoji(symbols);
        this.setEmoji(flags);
        this.echo(`</spotmoji>`);
        return this.print;
    },

    // Function for adding styles
    addStyle(css, id) {
        let head = document.getElementsByTagName("head")[0];
        if (!head) {window.location.reload();}
        let style = document.createElement("style");
        if (id) {style.id = id;}
        style.setAttribute("type", "text/css");
        style.innerHTML = css;
        head.appendChild(style);
    },

    // Function for adding scripts
    addScript(js) {
        let body = document.getElementsByTagName("body")[0];
        if (!body) {window.location.reload();}
        let script = document.createElement("script");
        script.setAttribute("type", "text/javascript");
        script.innerHTML = js;
        body.appendChild(script);
    },

    // Add emoji button to shoutbox
    addEmojiButton() {
        let ibbc = document.getElementById("shout-ibb-container");
        let befr = document.getElementById("shoutHistoryBtn");
        if (!ibbc || !befr) return;

        let face = document.createElement("span");
        face.id = "emoji-toggle-btn";
        face.classList.add("inline-submit-btn");
        face.title = "Unicode Emojis";
        face.setAttribute("onclick", "toggleEmojiPicker()");
        face.innerHTML = "<i class='material-icons'>face</i>";
        ibbc.insertBefore(face, befr);
    },

    // Add emoji picker container
    addEmojiPicker() {
        let container = document.getElementById("smilies-outline");
        if (!container) return;

        let div = document.createElement("div");
        div.id = "spotlight-emojis";
        div.innerHTML = this.buildEmojiHTML();
        container.parentNode.insertBefore(div, container.nextSibling);
    },

init() {
    if (!CONFIG.unicode_emoji_enabled) return;

    // Detect if in spotlight mode and add class to body
    if (location.href.includes("?spotlight")) {
        document.body.classList.add("spotlight-mode");
    }

    // Add CSS
    this.addStyle(this.emojiCSS);
    this.addStyle(this.emojistyle("smileys"), "emoji-filter");

    // Add JS
    this.addScript(this.emojiJS);

    // Add UI elements
    this.addEmojiButton();
    this.addEmojiPicker();

    // Fix the smilies-outline container for homepage
    if (location.href === location.origin + "/") {
        const smiliesOutline = document.getElementById('smilies-outline');
        if (smiliesOutline && !smiliesOutline.querySelector('#spotlight-smileys')) {
            const smileyDiv = document.createElement('div');
            smileyDiv.id = 'spotlight-smileys';
            smiliesOutline.insertBefore(smileyDiv, smiliesOutline.firstChild);
        }
    }

    // Add click handler for emojis
    document.addEventListener("click", function(event) {
        if (!event.target.tagName.match(/x/i)) return;
        if (!event.target.className.match(/emoji/i)) return;
        if (!event.target.parentNode.tagName.match(/spotmoji/i)) return;

        let shoutText = document.getElementById("shout_text");
        if (!shoutText) return;

        let thisEmoji = event.target.innerHTML;
        shoutText.value = shoutText.value + thisEmoji;
        shoutText.focus();
    });

    // Close picker when sending message
    let sendBtn = document.getElementById("sendShoutBtn");
    if (sendBtn) {
        sendBtn.addEventListener("click", function() {
            let picker = document.getElementById("spotlight-emojis");
            if (picker && picker.classList.contains("active")) {
                picker.classList.remove("active");
            }
        });
    }

    // Close picker on Enter key
    let shoutText = document.getElementById("shout_text");
    if (shoutText) {
        shoutText.addEventListener("keydown", function(e) {
            if (e.key !== "Enter") return;
            let picker = document.getElementById("spotlight-emojis");
            if (picker && picker.classList.contains("active")) {
                picker.classList.remove("active");
            }
        });
    }
},
    stop() {
        const btn = document.getElementById('emoji-toggle-btn');
        if (btn) btn.remove();

        const picker = document.getElementById('spotlight-emojis');
        if (picker) picker.remove();

        const filterStyle = document.getElementById('emoji-filter');
        if (filterStyle) filterStyle.remove();

        document.body.classList.remove("spotlight-mode");
    }
};



// ============================================================================
// MODULE 12: SPOTLIGHT MODE
// ============================================================================

const UIImprovementsModule = {
    // Determine active theme to set button color
    color: (() => {
        if (localStorage.themeDark && localStorage.themeLight) {
            return "var(--engine-content-title)";
        }
        return "ghostwhite";
    })(),

    // CSS for shoutbox
    shoutboxCSS: `
#shout-expander {
    display: none;
}
.shoutbox-container .content-title {
    position: relative;
}
.shoutbox-container span.toggle-indicator,
.shoutbox-container .content-title > div.right {
    position: absolute;
    right: 16px;
}
.shoutbox-container h6 {
    padding: 0.5rem 0 0.4rem 0;
    margin: 0;
    width: 100%;
}
#spotbtns {
    display: flex;
    position: absolute;
    right: 48px;
    gap: 12px;
    margin-top: 1.475px;
}
#spotlight, #greasylight, #forumlight {
    cursor: pointer;
    padding-top: 4px;
    color: ${(() => {
        if (localStorage.themeDark && localStorage.themeLight) {
            return "var(--engine-content-title)";
        }
        return "ghostwhite";
    })()};
    transition: transform 0.1s;
}
#spotlight:hover, #spotlight:focus,
#greasylight:hover, #greasylight:focus,
#forumlight:hover, #forumlight:focus {
    color: var(--link-color);
    transform: scale(1);
}
#spotlight:active,
#greasylight:active,
#forumlight:active {
    transform: scale(0.8);
}
#spotlight {
    order: 3;
}
#shout-ibb-container {
    display: flex;
    gap: 0 0.5rem;
}
#shouts-container {
    display: flex;
    flex-direction: column;
}
    `,

    // Spotlight mode CSS
    spotlightCSS: `
header, #kuddus-trigger-container, footer, .drag-target, #left-block, #middle-block .row.card-panel:not(.shoutbox-container), br, .shoutbox-container .toggle-indicator, #smilies-outline {
    display: none !important;
}
html, body, main, #parent-block, #middle-block, #middle-block div.shoutbox-container {
    min-width: 100%;
    min-height: 100%;
    max-width: 100%;
    max-height: 100%;
    width: 100%;
    height: 100%;
    overflow: hidden;
    font-size: 16px !important;
}
.shouts, .shouts i {
    font-size: 1rem !important;
}
@media screen and (max-width: 743px) {
    html, body {
        font-size: 15px !important;
    }
}
main {
    margin-top: 0;
    padding-top: 0 !important;
}
#middle-block {
    margin: 0;
    padding: 0.5rem;
}
#spotbtns {
    right: 1rem;
}
#greasylight {
    order: 4;
}
#forumlight {
    order: 5;
}
.shoutbox-container {
    margin: auto;
}
.shoutbox-container .content-title {
    padding: 0 1rem;
    height: 4.375rem;
    display: flex;
    align-items: center;
}
.shoutbox-container .toggle-indicator {
    cursor: pointer;
}
#shoutbox-outline {
    width: 100%;
    height: 100%;
    display: flex !important;
    flex-direction: column;
}
#shouts-container {
    min-height: 100px;
    height: calc(calc(100% - 8.375rem) - 15px);
    padding: 0 0.7%;
}
#shout-send-container {
    height: 4rem;
    padding: 0;
    position: relative;
}
#shout_text {
    height: 100%;
    padding-left: 1.5rem;
    padding-right: calc(140px + 2.5rem);
}
#shout-ibb-container {
    margin-right: 0;
    padding-right: 1.5rem;
    position: absolute;
    right: 0;
    bottom: 0;
}
#shout-ibb-container .inline-submit-btn i {
    line-height: calc(4rem - 2px);
}
#spotlight-smileys {
    display: flex;
    flex-flow: row wrap;
    gap: 1rem;
    position: absolute;
    bottom: 1%;
    padding: 1rem;
    margin-bottom: calc(4rem - 2px);
    background: var(--main-bg);
    width: 100%;
    height: 0;
    opacity: 0;
    transition: height 0.2s linear, opacity 0.1s linear;
    border-top: 1px solid;
    border-bottom: 1px solid;
    border-color: var(--border-color);
    -webkit-user-select: none;
    -ms-user-select: none;
    user-select: none;
    overflow-y: auto;
}
#spotlight-smileys.shiner {
    opacity: 1;
    height: 30vh;
}
#spotlight-smileys.fader {
    display: none;
}
#spotlight-smileys a {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 2.4rem;
    width: 2.4rem;
    margin-bottom: 0.5rem;
    cursor: pointer;
    transition: transform 0.1s linear;
}
#spotlight-smileys a:hover,
#spotlight-smileys a:focus {
    transform: scale(1.4);
}
#spotlight-smileys a:active {
    transform: scale(1.1);
}
    `,

    // Homepage CSS
    shouthomeCSS: `
.shoutbox-container > .content-title {
    padding: 2px;
}
.shoutbox-container h6 {
    padding-left: 14px;
    padding-right: 14px;
}
#spotlight-smileys, #spotlight-emojis {
    display: none;
}
#smilies-outline.smileys #spotlight-smileys {
    display: flex;
}
#smilies-outline.emojis #spotlight-emojis {
    display: flex;
}
#smilies-outline {
    padding: 0 !important;
    margin: 0 !important;
}
#smilies-outline.smileys {
    padding: 1rem !important;
}
#smilies-outline.emojis {
    padding: 1rem !important;
}
#smilies-outline.emojis #spotlight-smileys {
    display: none !important;
    height: 0 !important;
    padding: 0 !important;
    margin: 0 !important;
    min-height: 0 !important;
}
#smilies-outline.smileys #spotlight-emojis {
    display: none !important;
    height: 0 !important;
    padding: 0 !important;
    margin: 0 !important;
    min-height: 0 !important;
}
#spotlight-smileys:empty {
    display: none !important;
    height: 0 !important;
    padding: 0 !important;
    margin: 0 !important;
}
#spotlight-smileys, #spotlight-emojis {
    flex-direction: column;
    gap: 1.5rem;
    background: var(--main-bg);
    width: 103%;
    height: 100%;
    max-height: 20rem;
    transition: height 0.2s linear, opacity 0.1s linear;
    -webkit-user-select: none;
    -ms-user-select: none;
    user-select: none;
    padding: 0;
    margin: 0;
}
#smilies-outline.emojis {
    padding: 1rem;
}
#smilies-outline.emojis #spotlight-smileys {
    display: none !important;
}
#smilies-outline.smileys #spotlight-emojis {
    display: none !important;
}
#smilies-outline {
    max-width: 98%;
    margin: 0 auto;
}
#spotlight-smileys {
    flex-flow: row wrap;
    gap: 1rem 0.75rem;
    overflow-y: auto;
}
#spotlight-smileys a {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 2.4rem;
    width: 2.4rem;
    margin-bottom: 0.5rem;
    cursor: pointer;
    transition: transform 0.1s linear;
}
#spotlight-smileys a:hover,
#spotlight-smileys a:focus {
    transform: scale(1.4);
}
#spotlight-smileys a:active {
    transform: scale(1.1);
}
#shout-send-container {
    padding: 0;
    position: relative;
}
#shout_text {
    padding-left: 0.5rem;
    padding-right: 140px;
}
#shout-ibb-container {
    margin-right: 0;
    padding-right: 0.5rem;
    position: absolute;
    right: 0;
}
    `,
    // Spotlight mode JS for emojis
    spotlightJS_emojis: `
// Toggle Smileys
function toggleSmilemoji(id, alt) {
    let emojibox = document.getElementById(id);

    // Close unicode emoji picker if open
    let unicodePicker = document.getElementById("spotlight-emojis");
    if (unicodePicker && unicodePicker.classList.contains("active")) {
        unicodePicker.classList.remove("active");
    }

    if (emojibox.className.match(/shiner/i)) {
        emojibox.classList.remove("shiner");
        setTimeout(function() {
            emojibox.classList.add("fader");
        }, 200);
    } else {
        emojibox.classList.remove("fader");
        setTimeout(function() {
            emojibox.classList.add("shiner");
        }, 100);
    }
}
// Toggle button for smileys
function toggleSmileys() {
    toggleSmilemoji("spotlight-smileys");
}
// Load the smileys ahead of time in new container
(function() {
    if (!smiliesLoaded) {
        $.post(
            siteUrl + "ajscripts.php", {
                task: 'getSmilies'
            },
            function(data) {
                $('#spotlight-smileys').html(data);
                smiliesLoaded = true;
            }
        );
    }
})();
    `,

// Homepage JS for emojis
homepageJS_emojis: `
// Quick Toggle for Smileys
function toggleQuickES(main, sub) {
    let sOutline = document.getElementById("smilies-outline");

    sOutline.classList.add(main);
    sOutline.classList.remove(sub);

    // If outline is hidden, show it
    if (sOutline.style.display === "none" || !sOutline.style.display) {
        $('#smilies-outline').slideDown(150);
    } else {
        // If outline is visible, hide it with easeOutQuad for smoother closing
        $('#smilies-outline').slideUp(150, 'linear', function() {
            sOutline.classList.remove(main);
            sOutline.classList.remove(sub);
        });
    }
}

// Handle Opposite Clicks on Smileys
function toggleSmilemoji(one, alt) {
    let sOutline = document.getElementById("smilies-outline"),
        oneRE = new RegExp(one, "i"),
        altRE = new RegExp(alt, "i");

    // Close unicode emoji picker if open
    let unicodePicker = document.getElementById("spotlight-emojis");
    if (unicodePicker && unicodePicker.classList.contains("active")) {
        unicodePicker.classList.remove("active");
        // Force open the smiley outline after closing unicode picker
        setTimeout(function() {
            sOutline.classList.add(one);
            sOutline.classList.remove(alt);
            if (sOutline.style.display === "none" || !sOutline.style.display) {
                $('#smilies-outline').slideDown(150);
            }
        }, 150);
        return;
    }

    // Normal toggle logic when unicode picker is not open
    if (altRE.test(sOutline.className)) {
        // If switching from emoji to smiley or vice versa, close then open
        $('#smilies-outline').slideUp(150, 'linear', function() {
            sOutline.classList.remove(alt);
            sOutline.classList.add(one);
            $('#smilies-outline').slideDown(150);
        });
    } else {
        toggleQuickES(one, alt);
    }
}

// Make room for Smileys in the same container
(function() {
    let sOutline = document.getElementById("smilies-outline");
    sOutline.innerHTML = "<div id='spotlight-smileys'></div>";
})();

// Load the smileys ahead of time in new container
(function() {
    if (!smiliesLoaded) {
        $.post(
            siteUrl + "ajscripts.php", {
                task: 'getSmilies'
            },
            function(data) {
                $('#spotlight-smileys').html(data);
                smiliesLoaded = true;
            }
        );
    }
})();
`,
    addStyle(css, id) {
        let head = document.getElementsByTagName("head")[0];
        if (!head) {window.location.reload();}
        let style = document.createElement("style");
        if (id) {style.id = id;}
        style.setAttribute("type", "text/css");
        style.innerHTML = css;
        head.appendChild(style);
    },

    addScript(js) {
        let body = document.getElementsByTagName("body")[0];
        if (!body) {window.location.reload();}
        let script = document.createElement("script");
        script.setAttribute("type", "text/javascript");
        script.innerHTML = js;
        body.appendChild(script);
    },

    spotlightJS(key, link, icon) {
        let spotHead = document.querySelector(".shoutbox-container .content-title.toggle");
        if (!spotHead) return;

        spotHead.removeAttribute("onclick");

        if (key.match(/enter/i)) {
            spotHead.children[0].setAttribute("onclick","toggleShoutbox()");
            spotHead.children[1].setAttribute("onclick","toggleShoutbox()");
        } else {
            if (spotHead.children[1]) spotHead.children[1].remove();
            spotHead.classList.remove("toggle");
        }

        let newCon = document.createElement("div");
        newCon.id = "spotbtns";
        spotHead.appendChild(newCon);

        newCon = document.getElementById("spotbtns");

        let anchor = document.createElement("a");
        anchor.id = "spotlight";
        anchor.title = key + " Spotlight";
        anchor.href = link;
        anchor.innerHTML = `<i class="material-icons">${icon}</i>`;
        newCon.appendChild(anchor);

    },

    whiteNull() {
        const shoutsContainer = document.getElementById("shouts-container");
        if (shoutsContainer) {
            shoutsContainer.innerHTML = shoutsContainer.innerHTML.replace(/>\s+</g,'><');
        }
    },

    smileyJS() {
        let container = document.getElementById("shout-send-container");
        let bottom = document.getElementById("shout_text");
        let toggle = document.querySelector("#shout-ibb-container span[onclick*='toggleSmilies']");

        if (!container || !bottom) return;

        let div = document.createElement("div");
        div.id = "spotlight-smileys";
        div.classList.add("fader");
        container.insertBefore(div, bottom);

        if (toggle) {
            toggle.setAttribute("onclick","toggleSmileys()");
        }
    },

    initSpotlightMode() {
        // Update material icons
        try {
            const iconLink = document.querySelector("link[href*='material-icons.css']");
            if (iconLink) {
                iconLink.href = "https://fonts.googleapis.com/icon?family=Material+Icons";
            }
        } catch(e) {}

        // Set new document title
        document.title = "Shoutbox - TorrentBD";

        // Set cookie for expanded Shoutbox
        document.cookie = "hideShoutbox=0";

        // Push the styles in head
        this.addStyle(this.shoutboxCSS + this.spotlightCSS, "spotlight");

        // Change stuff when page loads
        const initSpotlight = () => {
            this.addScript(this.spotlightJS_emojis);
            this.spotlightJS("Exit", location.origin, "fullscreen_exit");
            this.whiteNull();
            this.smileyJS();

            // Auto-close smileys after picking one
            document.addEventListener("click", function(event) {
                if (!event.target.closest("#spotlight-smileys a")) {return;}

                let emojibox = document.getElementById("spotlight-smileys");
                if (emojibox && emojibox.className.match(/shiner/i)) {
                    emojibox.classList.remove("shiner");
                    setTimeout(function() {
                        emojibox.classList.add("fader");
                    }, 200);
                }
            });

            // Add ESC key handler to exit spotlight mode
            document.addEventListener("keydown", function(event) {
                if (event.key === "Escape") {
                    window.location.href = location.origin;
                }
            });

            // Observe shoutbox
            let observer = new MutationObserver(function() {
                const shoutsContainer = document.getElementById("shouts-container");
                if (!shoutsContainer || !shoutsContainer.children[0]) {return;}

                let shoutID = parseInt(shoutsContainer.children[0].id.replace(/.*-/,''));

                if (!window.lastShoutID) {
                    window.lastShoutID = shoutID;
                    return;
                }

                if (window.lastShoutID >= shoutID) {return;}

                window.lastShoutID = shoutID;
            });

            const shoutsContainer = document.getElementById("shouts-container");
            if (shoutsContainer) {
                observer.observe(shoutsContainer, {childList: true});
            }
        };

        if (document.readyState === 'loading') {
            window.addEventListener('load', initSpotlight);
        } else {
            initSpotlight();
        }
    },

    initHomepage() {
        // Update material icons
        try {
            const iconLink = document.querySelector("link[href*='material-icons.css']");
            if (iconLink) {
                iconLink.href = "https://fonts.googleapis.com/icon?family=Material+Icons";
            }
        } catch(e) {}

        // Push the styles in head
        this.addStyle(this.shoutboxCSS + this.shouthomeCSS, "shouthome");


        // Change stuff when page loads
        const initHome = () => {
            this.addScript(this.homepageJS_emojis);
            this.spotlightJS("Enter", "?spotlight", "fullscreen");
            this.whiteNull();

            // Change button to use new toggle function
            let emojiOrigin = document.querySelector("#shout-ibb-container span[onclick='toggleSmilies()']");
            if (emojiOrigin) {
                emojiOrigin.setAttribute("onclick","toggleSmilemoji('smileys','emojis')");
            }
        };

        if (document.readyState === 'loading') {
            window.addEventListener('load', initHome);
        } else {
            initHome();
        }
    },

    init() {
        // Check if spotlight URL matches
        if (location.href === location.origin + "/?spotlight") {
            this.initSpotlightMode();
        }
        // Check if user is on the homepage
        else if (location.href === location.origin + "/") {
            this.initHomepage();
        }
    }
};



// ============================================================================
// MODULE 13: MEME CREATOR
// ============================================================================

const MemeCreatorModule = {
    IMGFLIP_CONFIG: {
        username: 'puls33',
        password: '12345678@',
        apiUrl: 'https://api.imgflip.com'
    },

    modal: null,
    templatesArea: null,
    editorArea: null,
    memeButton: null,
    allTemplates: [],
    currentTemplate: null,
    activeInput: null,
    isDragging: false,
    hasMoved: false,

    debounce(func, wait) {
        let timeout;
        return function(...args) {
            clearTimeout(timeout);
            timeout = setTimeout(() => func.apply(this, args), wait);
        };
    },

    addStyles() {
        const css = `
            #meme-tool-modal {
                position: fixed;
                width: 520px;
                max-width: 90vw;
                max-height: 90vh;
                background: #2f3136;
                border: 1px solid #444;
                border-radius: 8px;
                z-index: 2147483647;
                display: none;
                box-shadow: 0 10px 30px rgba(0,0,0,0.8);
                overflow: hidden;
                flex-direction: column;
                top: auto;
            }
            #meme-tool-header {
                height: 24px;
                background: #202225;
                cursor: grab;
                display: flex;
                align-items: center;
                justify-content: space-between;
                padding: 0 8px;
                border-bottom: 1px solid #36393f;
                flex-shrink: 0;
            }
            #meme-tool-header:active { cursor: grabbing; background: #18191c; }
            #meme-tool-title { font-size: 11px; color: #aaa; font-weight: bold; user-select: none; text-transform: uppercase; letter-spacing: 0.5px; }
            #meme-tool-content { padding: 10px; display: flex; flex-direction: column; gap: 10px; overflow-y: auto; flex: 1; }
            #meme-tool-templates {
                display: grid;
                grid-template-columns: repeat(auto-fill, minmax(100px,1fr));
                gap: 8px;
                max-height: 400px;
                min-height: 200px;
                overflow-y: auto;
                scrollbar-width: thin;
                scrollbar-color: #202225 #2f3136;
            }
            #meme-tool-templates::-webkit-scrollbar { width: 8px; }
            #meme-tool-templates::-webkit-scrollbar-track { background: #2f3136; }
            #meme-tool-templates::-webkit-scrollbar-thumb { background-color: #202225; border-radius: 4px; }
            .meme-template {
                cursor: pointer;
                border: 2px solid transparent;
                border-radius: 6px;
                overflow: hidden;
                transition: all 0.15s;
                position: relative;
                background: #202225;
                min-height: 115px;
                display: flex;
                flex-direction: column;
            }
            .meme-template:hover { border-color: #00bfff; transform: scale(1.03); }
            .meme-template.selected { border-color: #00ff00; box-shadow: 0 0 0 2px #00ff00; }
            .meme-template img { width: 100%; height: 100px; object-fit: contain; display: block; background: #18191c; }
            .meme-template-name {
                position: absolute;
                bottom: 0;
                left: 0;
                right: 0;
                background: rgba(0,0,0,0.85);
                color: white;
                padding: 4px 3px;
                font-size: 10px;
                text-align: center;
                line-height: 1.1;
            }
            #meme-tool-editor { display: none; }
            #meme-tool-editor.active { display: flex; flex-direction: column; overflow-y: auto; flex: 1; }
            .meme-preview {
                text-align: center;
                margin-bottom: 10px;
                background: #202225;
                padding: 12px;
                border-radius: 6px;
                flex-shrink: 0;
            }
            .meme-preview img {
                max-width: 100%;
                max-height: 200px;
                border-radius: 6px;
                object-fit: contain;
            }
            .meme-template-info {
                text-align: center;
                color: #aaa;
                font-size: 11px;
                margin-top: 6px;
            }
            .meme-input {
                margin-bottom: 8px;
            }
            .meme-input label {
                display: block;
                margin-bottom: 3px;
                font-weight: 600;
                color: #ccc;
                font-size: 12px;
            }
            .meme-input input {
                width: 100%;
                padding: 8px;
                background: #40444b;
                border: 1px solid #555;
                border-radius: 4px;
                font-size: 13px;
                box-sizing: border-box;
                color: #fff;
            }
            .meme-input input:focus {
                outline: none;
                border-color: #00bfff;
            }
            #meme-generation-controls {
                flex-shrink: 0;
            }
            .meme-btn {
                width: 100%;
                padding: 10px;
                background: #5865f2;
                color: white;
                border: none;
                border-radius: 4px;
                font-size: 14px;
                font-weight: 600;
                cursor: pointer;
                transition: background 0.15s;
                margin-bottom: 6px;
            }
            .meme-btn:hover { background: #4752c4; }
            .meme-btn:disabled {
                opacity: 0.5;
                cursor: not-allowed;
            }
            .meme-btn-secondary {
                background: #4f545c;
            }
            .meme-btn-secondary:hover {
                background: #686d73;
            }
            .meme-status {
                text-align: center;
                padding: 8px;
                border-radius: 4px;
                margin-bottom: 10px;
                font-size: 12px;
                display: none;
            }
            .meme-status.info {
                background: #2c3e50;
                color: #3498db;
            }
            .meme-status.success {
                background: #1e4620;
                color: #4caf50;
            }
            .meme-status.error {
                background: #4a1c1c;
                color: #f44336;
            }
            .meme-result {
                margin-top: 10px;
                text-align: center;
                flex-shrink: 0;
            }
            .meme-result img {
                max-width: 100%;
                max-height: 50vh;
                border-radius: 6px;
                margin-bottom: 8px;
                object-fit: contain;
            }
            .meme-loading {
                text-align: center;
                padding: 15px;
                color: #aaa;
                font-size: 12px;
            }
            #meme-tool-close { background:none; border:none; color:#aaa; font-size: 18px; cursor:pointer; line-height: 1; padding: 0; }
            #meme-tool-close:hover { color:#fff; }
        `;
        GM_addStyle(css);
    },

    createModal() {
        const html = `
            <div id="meme-tool-modal" role="dialog">
                <div id="meme-tool-header">
                    <span id="meme-tool-title">Meme Generator</span>
                    <button id="meme-tool-close" aria-label="Close">&times;</button>
                </div>
                <div id="meme-tool-content">
                    <div id="meme-tool-templates"></div>
                    <div id="meme-tool-editor">
                        <div class="meme-preview" id="meme-preview"></div>
                        <div id="meme-inputs-container"></div>
                        <div class="meme-status info" id="meme-status"></div>
                        <div id="meme-generation-controls">
                            <button class="meme-btn" id="meme-generate">Create Meme</button>
                            <button class="meme-btn meme-btn-secondary" id="meme-back">← Back to Templates</button>
                        </div>
                        <div class="meme-result" id="meme-result"></div>
                    </div>
                </div>
            </div>
        `;
        document.body.insertAdjacentHTML('beforeend', html);

        this.modal = document.getElementById('meme-tool-modal');
        const headerBar = document.getElementById('meme-tool-header');
        this.templatesArea = document.getElementById('meme-tool-templates');
        this.editorArea = document.getElementById('meme-tool-editor');

        document.getElementById('meme-tool-close').addEventListener('click', () => this.closeModal());
        document.getElementById('meme-back').addEventListener('click', () => {
            this.editorArea.classList.remove('active');
            this.templatesArea.style.display = 'grid';
            document.getElementById('meme-preview').style.display = 'block';
            document.getElementById('meme-inputs-container').style.display = 'block';
            document.getElementById('meme-generation-controls').style.display = 'block';
            document.getElementById('meme-status').style.display = 'none';
            document.getElementById('meme-result').innerHTML = '';
        });

        this.setupDraggable(headerBar);
    },

    setupDraggable(handle) {
        let startX, startY, startLeft, startBottom;

        handle.addEventListener('mousedown', (e) => {
            if (e.target.id === 'meme-tool-close') return;
            e.preventDefault();
            this.isDragging = true;
            startX = e.clientX;
            startY = e.clientY;
            const rect = this.modal.getBoundingClientRect();
            startLeft = rect.left;

            const computedStyle = window.getComputedStyle(this.modal);
            const cssBottom = parseInt(computedStyle.bottom);
            if (isNaN(cssBottom)) {
                startBottom = window.innerHeight - rect.bottom;
            } else {
                startBottom = cssBottom;
            }

            const onMouseMove = (e) => {
                if (!this.isDragging) return;
                const dx = e.clientX - startX;
                const dy = e.clientY - startY;
                this.modal.style.left = `${startLeft + dx}px`;
                this.modal.style.bottom = `${startBottom - dy}px`;
                this.modal.style.top = 'auto';
            };

            const onMouseUp = () => {
                this.isDragging = false;
                this.hasMoved = true;
                document.removeEventListener('mousemove', onMouseMove);
                document.removeEventListener('mouseup', onMouseUp);
                this.constrainToViewport();
                this.savePosition();
            };

            document.addEventListener('mousemove', onMouseMove);
            document.addEventListener('mouseup', onMouseUp);
        });
    },

    savePosition() {
        if (!this.modal) return;
        const rect = this.modal.getBoundingClientRect();
        const viewportWidth = window.innerWidth;
        const viewportHeight = window.innerHeight;

        const pos = {
            rightDist: viewportWidth - rect.right,
            bottomDist: viewportHeight - rect.bottom,
            width: viewportWidth,
            height: viewportHeight
        };
        localStorage.setItem('tbd_meme_pos_v1', JSON.stringify(pos));
    },

    constrainToViewport() {
        if (!this.modal || this.modal.style.display !== 'flex') return;

        const rect = this.modal.getBoundingClientRect();
        const viewportWidth = window.innerWidth;
        const viewportHeight = window.innerHeight;
        const margin = 10;

        let left = parseInt(this.modal.style.left) || rect.left;
        let bottom = parseInt(this.modal.style.bottom);

        if (isNaN(bottom)) {
            bottom = viewportHeight - rect.bottom;
        }

        const modalHeight = rect.height;
        const top = viewportHeight - bottom - modalHeight;

        const maxLeft = viewportWidth - rect.width - margin;
        if (left < margin) left = margin;
        if (left > maxLeft) left = maxLeft;

        if (top < margin) {
            bottom = viewportHeight - modalHeight - margin;
        }
        if (bottom < margin) {
            bottom = margin;
        }

        this.modal.style.left = `${left}px`;
        this.modal.style.bottom = `${bottom}px`;
        this.modal.style.top = 'auto';
    },

    restorePosition(anchor) {
        const saved = localStorage.getItem('tbd_meme_pos_v1');
        if (saved) {
            try {
                const pos = JSON.parse(saved);
                if (pos.rightDist !== undefined && pos.bottomDist !== undefined) {
                    const viewportWidth = window.innerWidth;
                    const rect = this.modal.getBoundingClientRect();

                    const left = viewportWidth - pos.rightDist - rect.width;
                    const bottom = pos.bottomDist;

                    this.modal.style.left = `${left}px`;
                    this.modal.style.bottom = `${bottom}px`;
                    this.modal.style.top = 'auto';
                    this.hasMoved = true;
                    setTimeout(() => this.constrainToViewport(), 0);
                    return;
                }
            } catch(e) { console.error('Invalid saved pos'); }
        }

        if (anchor && !this.hasMoved) {
            const rect = anchor.getBoundingClientRect();
            let left = rect.right - 520;
            if (left < 10) left = 10;
            const bottom = window.innerHeight - rect.top + 10;
            this.modal.style.left = `${left}px`;
            this.modal.style.bottom = `${bottom}px`;
            this.modal.style.top = 'auto';
            setTimeout(() => this.constrainToViewport(), 0);
        }
    },

    addMemeButton() {
        const tray = document.querySelector('#shout-ibb-container');
        if (!tray || document.getElementById('meme-tool-btn')) return;

        this.memeButton = document.createElement('span');
        this.memeButton.id = 'meme-tool-btn';
        this.memeButton.className = 'inline-submit-btn';
        this.memeButton.title = 'Create Meme';
        this.memeButton.innerHTML = '<i class="material-icons">theater_comedy</i>';

        const isSpotlight = document.body.classList.contains('spotlight-mode') ||
                window.location.search.includes('spotlight');
        const topValue = isSpotlight ? '17px' : '6px';
        this.memeButton.style.cssText = `display:inline-flex;align-items:center;justify-content:center;cursor:pointer;color:#ccc;position:relative;top:${topValue};height:24px;width:28px;margin-left:4px;margin-right:2px;`;

        this.memeButton.addEventListener('click', (ev) => {
            ev.stopPropagation();
            ev.preventDefault();
            const input = document.querySelector('#shout_text');
            if (input) {
                if(this.modal.style.display === 'flex') this.closeModal();
                else this.openModal(input, this.memeButton);
            }
        });

        const targetBtn = tray.querySelector('#tbd-uploader-button')
                       || tray.querySelector('#imgbd-uploader-btn')
                       || tray.querySelector('#urlBtn')
                       || tray.querySelector('#tbdm-image-upload-btn')
                       || tray.querySelector('#tbdm-gif-tool-btn');

        if (targetBtn) {
            tray.insertBefore(this.memeButton, targetBtn);
        } else {
            tray.appendChild(this.memeButton);
        }
    },

    loadTemplates() {
        const CUSTOM_TEMPLATES_URL = 'https://imgflip.mushi53566.workers.dev/';

        // Fetch Imgflip templates
        GM_xmlhttpRequest({
            method: 'GET',
            url: this.IMGFLIP_CONFIG.apiUrl + '/get_memes',
            onload: (res) => {
                try {
                    const data = JSON.parse(res.responseText);
                    if (data.success) {
                        const apiTemplates = data.data.memes;

                        // Fetch custom templates
                        GM_xmlhttpRequest({
                            method: 'GET',
                            url: CUSTOM_TEMPLATES_URL,
                            onload: (customRes) => {
                                try {
                                    const customData = JSON.parse(customRes.responseText);
                                    if (customData.success) {
                                        const customTemplates = customData.data.memes;
                                        const merged = [];
                                        const interval = Math.floor(apiTemplates.length / customTemplates.length);

                                        let customIndex = 0;
                                        for (let i = 0; i < apiTemplates.length; i++) {
                                            merged.push(apiTemplates[i]);
                                            if ((i + 1) % interval === 0 && customIndex < customTemplates.length) {
                                                merged.push(customTemplates[customIndex]);
                                                customIndex++;
                                            }
                                        }

                                        while (customIndex < customTemplates.length) {
                                            merged.push(customTemplates[customIndex]);
                                            customIndex++;
                                        }

                                        this.allTemplates = merged;
                                        this.renderTemplates();
                                    }
                                } catch (e) {
                                    // If custom templates fail, just use API templates
                                    this.allTemplates = apiTemplates;
                                    this.renderTemplates();
                                }
                            },
                            onerror: () => {
                                // Fallback to API templates only
                                this.allTemplates = apiTemplates;
                                this.renderTemplates();
                            }
                        });
                    }
                } catch (e) {
                    console.error('Error loading templates');
                }
            },
            onerror: () => console.error('Network error')
        });
    },

    renderTemplates() {
        this.templatesArea.innerHTML = this.allTemplates.map(t => `
            <div class="meme-template" data-id="${t.id}" data-url="${t.url}" data-boxes="${t.box_count}" data-name="${t.name}">
                <img src="${t.url}" alt="${t.name}" loading="lazy">
                <div class="meme-template-name">${t.name}</div>
            </div>
        `).join('');

        this.templatesArea.querySelectorAll('.meme-template').forEach(el => {
            el.onclick = () => this.selectTemplate(el);
        });
    },

    selectTemplate(el) {
        document.querySelectorAll('.meme-template').forEach(t => t.classList.remove('selected'));
        el.classList.add('selected');

        const id = el.dataset.id;
        const url = el.dataset.url;
        const boxes = parseInt(el.dataset.boxes) || 2;
        const name = el.dataset.name;

        this.currentTemplate = { id, url, boxes, name };

        document.getElementById('meme-preview').innerHTML = `
            <img src="${url}">
            <div class="meme-template-info">
                ${name} - ${boxes} text ${boxes === 1 ? 'box' : 'boxes'}
            </div>
        `;

        this.createTextInputs(boxes);

        this.templatesArea.style.display = 'none';
        this.editorArea.classList.add('active');
        document.getElementById('meme-result').innerHTML = '';

        setTimeout(() => {
            this.constrainToViewport();
        }, 0);

        document.getElementById('meme-generate').onclick = () => this.generateMeme();

    },

    createTextInputs(count) {
        const container = document.getElementById('meme-inputs-container');
        container.innerHTML = '';

        for (let i = 0; i < count; i++) {
            container.innerHTML += `
                <div class="meme-input">
                    <label>Text Box ${i + 1}</label>
                    <input type="text" id="meme-text${i}" placeholder="Enter text for box ${i + 1}">
                </div>
            `;
        }
    },

    generateMeme() {
        if (!this.currentTemplate) return;

        const boxes = [];
        for (let i = 0; i < this.currentTemplate.boxes; i++) {
            const text = document.getElementById(`meme-text${i}`)?.value || '';
            boxes.push({ text });
        }

        const hasText = boxes.some(box => box.text.trim() !== '');
        if (!hasText) {
            this.showStatus('Enter at least one text', 'error');
            return;
        }

        const btn = document.getElementById('meme-generate');
        btn.disabled = true;
        this.showStatus('Creating meme...', 'info');

        let formData = `template_id=${this.currentTemplate.id}&username=${this.IMGFLIP_CONFIG.username}&password=${this.IMGFLIP_CONFIG.password}`;

        boxes.forEach((box, index) => {
            formData += `&boxes[${index}][text]=${encodeURIComponent(box.text)}`;
        });

        GM_xmlhttpRequest({
            method: 'POST',
            url: this.IMGFLIP_CONFIG.apiUrl + '/caption_image',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            data: formData,
            onload: (res) => {
                btn.disabled = false;
                btn.textContent = 'Create Meme';
                try {
                    const result = JSON.parse(res.responseText);
                    if (result.success) {
                        this.showStatus('Meme created! Click to insert.', 'success');
                        const memeUrl = result.data.url;

                        document.getElementById('meme-preview').style.display = 'none';
                        document.getElementById('meme-inputs-container').style.display = 'none';
                        document.getElementById('meme-generation-controls').style.display = 'none';
                        document.getElementById('meme-status').style.display = 'none';

                        document.getElementById('meme-result').innerHTML = `
                            <img src="${memeUrl}">
                            <button class="meme-btn" id="meme-insert-action">Insert Meme</button>
                        `;
                        document.getElementById('meme-insert-action').onclick = () => {
                            this.insertMeme(memeUrl);
                        };
                    } else {
                        this.showStatus('Error: ' + result.error_message, 'error');
                    }
                } catch (e) {
                    this.showStatus('Failed to create meme', 'error');
                }
            },
            onerror: () => {
                btn.disabled = false;
                btn.textContent = 'Create Meme';
                this.showStatus('Network error', 'error');
            }
        });
    },

    insertMeme(url) {
        if (!this.activeInput) return;

        const cur = this.activeInput.value;
        const cursorPos = this.activeInput.selectionStart || cur.length;
        const before = cur.substring(0, cursorPos);
        const after = cur.substring(cursorPos);
        const toInsert = url + ' ';

        this.activeInput.value = before + toInsert + after;
        const newCursorPos = before.length + toInsert.length;

        this.closeModal();
        setTimeout(() => {
            this.activeInput.focus();
            this.activeInput.setSelectionRange(newCursorPos, newCursorPos);
        }, 50);
    },

    showStatus(msg, type) {
        const status = document.getElementById('meme-status');
        if (status) {
            status.textContent = msg;
            status.className = 'meme-status ' + type;
            status.style.display = 'block';
        }
    },

    openModal(inputEl, anchorEl) {
        this.activeInput = inputEl;
        this.restorePosition(anchorEl);
        this.modal.style.display = 'flex';

        if (this.allTemplates.length === 0) {
            this.loadTemplates();
        }
    },

    closeModal() {
        this.modal.style.display = 'none';
        this.editorArea.classList.remove('active');
        this.templatesArea.style.display = 'grid';

        document.getElementById('meme-preview').style.display = 'block';
        document.getElementById('meme-inputs-container').style.display = 'block';
        document.getElementById('meme-generation-controls').style.display = 'block';
        document.getElementById('meme-status').style.display = 'none';
        document.getElementById('meme-result').innerHTML = '';
    },

    init() {
        if (!CONFIG.meme_creator_enabled) return;
        this.addStyles();
        this.createModal();
        this.addMemeButton();

        const resizeHandler = this.debounce(() => {
            if (this.modal && this.modal.style.display === 'flex') {
                this.constrainToViewport();
                this.savePosition();
            }
        }, 150);
        window.addEventListener('resize', resizeHandler);

        document.addEventListener('keydown', (e) => {
            if (e.key === 'Escape' && this.modal.style.display === 'flex') {
                e.preventDefault();
                this.closeModal();
                if (this.activeInput) this.activeInput.focus();
            }
        });
    },

    stop() {
        const btn = document.getElementById('meme-tool-btn');
        if (btn) btn.remove();
        if (this.modal) this.closeModal();
    }
};



// ============================================================================
// MODULE 14: BBCODE VALIDATOR (Built-in - Always Active)
// ============================================================================

const BBCodeValidatorModule = {
    warningElement: null,
    checkTimeout: null,

    DISALLOWED_BBCODES: [
        'img', 'color', 'size', 'font', 'b', 'i', 'u', 's',
        'spoiler', 'center', 'quote', 'df', 'imgw'
    ],

createWarningElement() {
    if (this.warningElement) return;
    this.warningElement = document.createElement('div');
    this.warningElement.id = 'bbcode-warning';
    this.warningElement.style.cssText = `
        display: none;
        position: absolute;
        top: 45px;
        right: 12px;
        background: rgba(220, 38, 38, 0.15);
        backdrop-filter: blur(12px);
        -webkit-backdrop-filter: blur(12px);
        border: 1.5px solid rgba(239, 68, 68, 0.4);
        color: #ef4444;
        padding: 10px 16px;
        border-radius: 10px;
        font-size: 13px;
        font-weight: 600;
        box-shadow: 0 4px 16px rgba(220, 38, 38, 0.2), 0 0 0 1px rgba(255, 255, 255, 0.05);
        animation: slideInRight 0.3s cubic-bezier(0.4, 0, 0.2, 1);
        z-index: 10000;
        pointer-events: none;
        letter-spacing: 0.3px;
    `;
    this.warningElement.innerHTML = `
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="display: inline-block; vertical-align: middle; margin-right: 8px;">
            <circle cx="12" cy="12" r="10"/>
            <line x1="12" y1="8" x2="12" y2="12"/>
            <line x1="12" y1="16" x2="12.01" y2="16"/>
        </svg>
        <span style="vertical-align: middle;">BBCode is not allowed. Read rules.</span>
        <img src="https://www.torrentbd.net/images/smilies/an_slap.gif"
             alt="slap"
             style="display: inline-block; vertical-align: middle; margin-left: 8px; height: 24px; width: auto;">
    `;
    const container = document.getElementById('shoutbox-container');
    if (container) {
        container.style.position = 'relative';
        container.appendChild(this.warningElement);
    }
},

    checkForBBCode(text) {
        // Check for disallowed BBCode patterns
        const pattern = new RegExp(`\\[(${this.DISALLOWED_BBCODES.join('|')})(=.*?)?\\]`, 'i');
        return pattern.test(text);
    },

    showWarning() {
        if (this.warningElement) {
            this.warningElement.style.display = 'flex';
            this.warningElement.style.alignItems = 'center';
        }
    },

    hideWarning() {
        if (this.warningElement) {
            this.warningElement.style.display = 'none';
        }
    },

    handleInput(e) {
        clearTimeout(this.checkTimeout);

        this.checkTimeout = setTimeout(() => {
            const text = e.target.value;

            if (this.checkForBBCode(text)) {
                this.showWarning();
            } else {
                this.hideWarning();
            }
        }, 300);
    },

    init() {
        const shoutInput = document.querySelector('#shout_text');
        if (!shoutInput) return;

        this.createWarningElement();

        shoutInput.addEventListener('input', (e) => this.handleInput(e));

        // Hide warning when sending message
        const sendBtn = document.getElementById('sendShoutBtn');
        if (sendBtn) {
            sendBtn.addEventListener('click', () => this.hideWarning());
        }
    }
};


    // ============================================================================
    // MODULE 15: INFINITE SCROLL
    // ============================================================================
    const InfiniteScrollModule = {
        isLoading: false,

        init() {
            const container = document.querySelector('#shouts-container');
            if (!container) return;

            container.addEventListener('scroll', () => {
                if (this.isLoading) return;

                const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight;
                if (distanceFromBottom > 80) return;

                this.isLoading = true;

                if (typeof getShoutHistory === 'function') {
                    getShoutHistory();
                }

                // Watch for new shouts being added, then unlock
                const before = container.children.length;
                let checks = 0;
                const poll = setInterval(() => {
                    checks++;
                    const after = container.children.length;
                    if (after > before || checks > 20) {
                        clearInterval(poll);
                        this.isLoading = false;
                    }
                }, 200);
            });
        }
    };


    // ============================================================================
    // SETTINGS UI
    // ============================================================================

    function createSettingsUI() {
        if (document.querySelector("#tbdm-modal-wrapper")) return;

        const uiWrapper = document.createElement("div");
        uiWrapper.id = "tbdm-modal-wrapper";
        uiWrapper.style.display = "none";
        uiWrapper.innerHTML = `
            <div id="tbdm-container">
                <div id="tbdm-header">
                    <h1>🛠️ Shoutbox Manager</h1>
                    <p>Complete control over your TorrentBD shoutbox experience</p>
                    <button id="tbdm-close-btn" title="Close">×</button>
                </div>
                <div id="tbdm-tabs">
                    <button class="tbdm-tab active" data-tab="features">⚡ Features</button>
                    <button class="tbdm-tab" data-tab="cleaner">🧹 Cleaner</button>
                    <button class="tbdm-tab" data-tab="notifier">🔔 Notifier</button>
                    <button class="tbdm-tab" data-tab="autocomplete">⌨️ Autocomplete</button>
                </div>
                <div id="tbdm-content">
                    <!-- Features Tab -->
                    <div class="tbdm-tab-content active" data-tab="features">
                        <div class="tbdm-section">
                            <h2 class="tbdm-section-header">🎨 Available Features</h2>
                            <div class="tbdm-feature-card">
                                <div class="tbdm-feature-header">
                                    <div class="tbdm-feature-icon">📸</div>
                                    <div class="tbdm-feature-info">
                                        <div class="tbdm-feature-title">Image Upload</div>
                                        <div class="tbdm-feature-desc">Paste, drag & drop, or click to upload</div>
                                    </div>
                                </div>
                                <label class="tbdm-switch"><input type="checkbox" id="tbdm-image-upload"><span class="tbdm-slider"></span></label>
                            </div>
                            <div class="tbdm-feature-card">
                                <div class="tbdm-feature-header">
                                    <div class="tbdm-feature-icon">@</div>
                                    <div class="tbdm-feature-info">
                                        <div class="tbdm-feature-title">Easy Mention</div>
                                        <div class="tbdm-feature-desc">Click timestamp to mention users</div>
                                    </div>
                                </div>
                                <label class="tbdm-switch"><input type="checkbox" id="tbdm-easy-mention"><span class="tbdm-slider"></span></label>
                            </div>
                            <div class="tbdm-feature-card">
                                <div class="tbdm-feature-header">
                                    <div class="tbdm-feature-icon">🔗</div>
                                    <div class="tbdm-feature-info">
                                        <div class="tbdm-feature-title">URL Sender</div>
                                        <div class="tbdm-feature-desc">Easy URL formatting with labels</div>
                                    </div>
                                </div>
                                <label class="tbdm-switch"><input type="checkbox" id="tbdm-url-sender"><span class="tbdm-slider"></span></label>
                            </div>
                            <div class="tbdm-feature-card">
                                <div class="tbdm-feature-header">
                                    <div class="tbdm-feature-icon">🎯</div>
                                    <div class="tbdm-feature-info">
                                        <div class="tbdm-feature-title">Shoutbox Input Lock</div>
                                        <div class="tbdm-feature-desc">Put mouse anywhere on the shoutbox</div>
                                    </div>
                                </div>
                                <label class="tbdm-switch"><input type="checkbox" id="tbdm-focus-lock"><span class="tbdm-slider"></span></label>
                            </div>
                            <div class="tbdm-feature-card">
                                <div class="tbdm-feature-header">
                                    <div class="tbdm-feature-icon">⏰</div>
                                    <div class="tbdm-feature-info">
                                        <div class="tbdm-feature-title">Idle Prevention</div>
                                        <div class="tbdm-feature-desc">Prevent auto-pause on idle</div>
                                    </div>
                                </div>
                                <label class="tbdm-switch"><input type="checkbox" id="tbdm-idle-prevention"><span class="tbdm-slider"></span></label>
                            </div>
                            <div class="tbdm-feature-card">
                                <div class="tbdm-feature-header">
                                    <div class="tbdm-feature-icon">🎬</div>
                                    <div class="tbdm-feature-info">
                                        <div class="tbdm-feature-title">GIF Picker</div>
                                        <div class="tbdm-feature-desc">Search and insert GIFs (Tenor/Giphy)</div>
                                    </div>
                                </div>
                                <label class="tbdm-switch">
                                    <input type="checkbox" id="tbdm-gif-picker">
                                    <span class="tbdm-slider"></span>
                                </label>
                            </div>
                            <div class="tbdm-feature-card">
                                <div class="tbdm-feature-header">
                                    <div class="tbdm-feature-icon">🖼️</div>
                                    <div class="tbdm-feature-info">
                                        <div class="tbdm-feature-title">Image Viewer</div>
                                        <div class="tbdm-feature-desc">Display image links as thumbnails</div>
                                    </div>
                                </div>
                                <label class="tbdm-switch">
                                    <input type="checkbox" id="tbdm-image-viewer">
                                    <span class="tbdm-slider"></span>
                                </label>
                           </div>
                            <div class="tbdm-feature-card">
                                <div class="tbdm-feature-header">
                                    <div class="tbdm-feature-icon">😊</div>
                                    <div class="tbdm-feature-info">
                                        <div class="tbdm-feature-title">Unicode Emoji</div>
                                        <div class="tbdm-feature-desc">Pick and insert unicode emojis</div>
                                    </div>
                                </div>
                                <label class="tbdm-switch">
                                    <input type="checkbox" id="tbdm-unicode-emoji">
                                    <span class="tbdm-slider"></span>
                                </label>
                            </div>
                            <div class="tbdm-feature-card">
                                <div class="tbdm-feature-header">
                                    <div class="tbdm-feature-icon">🎭</div>
                                    <div class="tbdm-feature-info">
                                        <div class="tbdm-feature-title">Meme Creator</div>
                                        <div class="tbdm-feature-desc">Create and insert memes</div>
                                    </div>
                                </div>
                                <label class="tbdm-switch">
                                    <input type="checkbox" id="tbdm-meme-creator">
                                    <span class="tbdm-slider"></span>
                                </label>
                            </div>
                      </div>
                    </div>

                    <!-- Cleaner Tab -->
                    <div class="tbdm-tab-content" data-tab="cleaner">
                        <div class="tbdm-setting-row tbdm-master-switch">
                            <label for="tbdm-cleaner-enabled">Enable Cleaner</label>
                            <label class="tbdm-switch"><input type="checkbox" id="tbdm-cleaner-enabled"><span class="tbdm-slider"></span></label>
                        </div>
                        <hr class="tbdm-divider">
                        <div class="tbdm-section">
                            <h2 class="tbdm-section-header">Hide System Messages</h2>
                            <div class="tbdm-setting-row">
                                <label for="tbdm-hide-all-users">Hide All User Messages</label>
                                <label class="tbdm-switch"><input type="checkbox" id="tbdm-hide-all-users"><span class="tbdm-slider"></span></label>
                            </div>
                            <div class="tbdm-setting-row">
                                <label for="tbdm-filter-torrent">New Torrents</label>
                                <label class="tbdm-switch"><input type="checkbox" id="tbdm-filter-torrent"><span class="tbdm-slider"></span></label>
                            </div>
                            <div class="tbdm-setting-row">
                                <label for="tbdm-filter-forumPost">New Forum Posts</label>
                                <label class="tbdm-switch"><input type="checkbox" id="tbdm-filter-forumPost"><span class="tbdm-slider"></span></label>
                            </div>
                            <div class="tbdm-setting-row">
                                <label for="tbdm-filter-forumTopic">New Forum Topics</label>
                                <label class="tbdm-switch"><input type="checkbox" id="tbdm-filter-forumTopic"><span class="tbdm-slider"></span></label>
                            </div>
                            <div class="tbdm-setting-row">
                                <label for="tbdm-filter-request">New Requests</label>
                                <label class="tbdm-switch"><input type="checkbox" id="tbdm-filter-request"><span class="tbdm-slider"></span></label>
                            </div>
                        </div>
                        <hr class="tbdm-divider">
                        <div class="tbdm-section">
                            <h2 class="tbdm-section-header">Block Users</h2>
                            <div class="tbdm-setting-row">
                                <label for="tbdm-block-users">Block by User ID</label>
                                <label class="tbdm-switch"><input type="checkbox" id="tbdm-block-users"><span class="tbdm-slider"></span></label>
                            </div>
                            <textarea id="tbdm-blocked-user-ids" placeholder="Enter User IDs (one per line)"></textarea>
                        </div>
                        <hr class="tbdm-divider">
                        <div class="tbdm-section">
                            <h2 class="tbdm-section-header">Block Keywords</h2>
                            <div class="tbdm-setting-row">
                                <label for="tbdm-block-keywords">Block by Keyword</label>
                                <label class="tbdm-switch"><input type="checkbox" id="tbdm-block-keywords"><span class="tbdm-slider"></span></label>
                            </div>
                            <textarea id="tbdm-blocked-keywords" placeholder="Enter keywords to block (one per line)"></textarea>
                        </div>
                    </div>

                    <!-- Notifier Tab -->
                    <div class="tbdm-tab-content" data-tab="notifier">
                        <div class="tbdm-setting-row tbdm-master-switch">
                            <label for="tbdm-notifier-enabled">Enable Notifier</label>
                            <label class="tbdm-switch"><input type="checkbox" id="tbdm-notifier-enabled"><span class="tbdm-slider"></span></label>
                        </div>
                        <hr class="tbdm-divider">
                        <div class="tbdm-section">
                            <div class="tbdm-form-group">
                                <label>Your Username</label>
                                <div id="tbdm-username-display">Detecting...</div>
                            </div>
                            <div class="tbdm-form-group">
                                <div class="tbdm-label-row">
                                    <label for="tbdm-keywords">Additional Keywords (One per line)</label>
                                    <button id="tbdm-reset-keywords">Reset</button>
                                </div>
                                <textarea id="tbdm-keywords" placeholder="Add keywords to be notified about..."></textarea>
                            </div>
                            <div class="tbdm-controls-row">
                                <div class="tbdm-form-group">
                                    <label>Highlight Color</label>
                                    <div id="tbdm-color-picker-wrapper">
                                        <input type="color" id="tbdm-highlight-color">
                                    </div>
                                </div>
                                <div class="tbdm-form-group">
                                    <label for="tbdm-volume">Notification Volume</label>
                                    <div class="tbdm-volume-control">
                                        <div id="tbdm-volume-icon"></div>
                                        <input type="range" id="tbdm-volume" min="0" max="100" step="1">
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>

                    <!-- Autocomplete Tab -->
                    <div class="tbdm-tab-content" data-tab="autocomplete">
                        <div class="tbdm-section">
                            <h2 class="tbdm-section-header">Autocomplete Options (Press Tab)</h2>
                            <div class="tbdm-setting-row">
                                <label for="tbdm-autocomplete-username">Username Autocomplete</label>
                                <label class="tbdm-switch"><input type="checkbox" id="tbdm-autocomplete-username"><span class="tbdm-slider"></span></label>
                            </div>
                            <div class="tbdm-setting-row">
                                <label for="tbdm-autocomplete-sticker">Sticker/Emoji Autocomplete</label>
                                <label class="tbdm-switch"><input type="checkbox" id="tbdm-autocomplete-sticker"><span class="tbdm-slider"></span></label>
                            </div>
                        </div>
                        <hr class="tbdm-divider">
                        <div class="tbdm-section">
                            <h2 class="tbdm-section-header">Custom Mappings</h2>
                            <div class="tbdm-mapping-header">
                                <p class="tbdm-help-text">Format: keyword = emoji/sticker (one per line)</p>
                                <button id="tbdm-reset-mappings" class="tbdm-secondary-btn">Reset to Defaults</button>
                            </div>
                            <div id="tbdm-mappings-container"></div>
                            <button id="tbdm-add-mapping" class="tbdm-primary-btn">+ Add New Mapping</button>
                        </div>
                    </div>
                </div>
            </div>
        `;
        document.body.appendChild(uiWrapper);

        // Tab switching
        const tabs = uiWrapper.querySelectorAll('.tbdm-tab');
        const tabContents = uiWrapper.querySelectorAll('.tbdm-tab-content');
        tabs.forEach(tab => {
            tab.addEventListener('click', () => {
                const tabName = tab.dataset.tab;
                tabs.forEach(t => t.classList.remove('active'));
                tabContents.forEach(tc => tc.classList.remove('active'));
                tab.classList.add('active');
                uiWrapper.querySelector(`.tbdm-tab-content[data-tab="${tabName}"]`).classList.add('active');
            });
        });

        // Close button
        document.getElementById('tbdm-close-btn').addEventListener('click', () => {
            uiWrapper.style.display = 'none';
        });

        uiWrapper.addEventListener('click', (e) => {
            if (e.target.id === 'tbdm-modal-wrapper') {
                uiWrapper.style.display = 'none';
            }
        });

        // Load and setup all settings
        setupCleanerSettings();
        setupNotifierSettings();
        setupFeaturesSettings();
        setupAutocompleteSettings();

        return uiWrapper;
    }

    function setupCleanerSettings() {
        const enabledSwitch = document.getElementById('tbdm-cleaner-enabled');
        const hideAllUsers = document.getElementById('tbdm-hide-all-users');
        const blockUsers = document.getElementById('tbdm-block-users');
        const blockedUserIds = document.getElementById('tbdm-blocked-user-ids');
        const blockKeywords = document.getElementById('tbdm-block-keywords');
        const blockedKeywords = document.getElementById('tbdm-blocked-keywords');

        // Load settings
        enabledSwitch.checked = CONFIG.cleaner_enabled;
        hideAllUsers.checked = CONFIG.cleaner_hide_all_users;
        blockUsers.checked = CONFIG.cleaner_block_users_enabled;
        blockedUserIds.value = CONFIG.cleaner_blocked_user_ids.join('\n');
        blockedUserIds.disabled = !CONFIG.cleaner_block_users_enabled;
        blockKeywords.checked = CONFIG.cleaner_block_keywords_enabled;
        blockedKeywords.value = CONFIG.cleaner_blocked_keywords.join('\n');
        blockedKeywords.disabled = !CONFIG.cleaner_block_keywords_enabled;

        for (const key in CleanerModule.systemFilters) {
            const checkbox = document.getElementById(`tbdm-filter-${key}`);
            checkbox.checked = CONFIG.cleaner_filters[key];
            checkbox.addEventListener('change', (e) => {
                CONFIG.cleaner_filters[key] = e.target.checked;
                saveConfig('cleaner_filters', CONFIG.cleaner_filters);
                CleanerModule.check();
            });
        }

        // Event listeners
        enabledSwitch.addEventListener('change', (e) => {
            saveConfig('cleaner_enabled', e.target.checked);
            if (!e.target.checked) {
                // When disabling, show all hidden messages immediately
                const shoutItems = document.querySelectorAll(".shout-item");
                shoutItems.forEach((item) => {
                    item.style.display = "";
                });
            } else {
                // When enabling, apply filters immediately
                CleanerModule.check();
            }
        });

        hideAllUsers.addEventListener('change', (e) => {
            saveConfig('cleaner_hide_all_users', e.target.checked);
            CleanerModule.check();
        });

        blockUsers.addEventListener('change', (e) => {
            saveConfig('cleaner_block_users_enabled', e.target.checked);
            blockedUserIds.disabled = !e.target.checked;
            CleanerModule.check();
        });

        blockedUserIds.addEventListener('input', () => {
            const ids = blockedUserIds.value.split('\n').map(u => u.trim()).filter(Boolean);
            saveConfig('cleaner_blocked_user_ids', ids);
            CleanerModule.check();
        });

        blockKeywords.addEventListener('change', (e) => {
            saveConfig('cleaner_block_keywords_enabled', e.target.checked);
            blockedKeywords.disabled = !e.target.checked;
            CleanerModule.check();
        });

        blockedKeywords.addEventListener('input', () => {
            const keywords = blockedKeywords.value.split('\n').map(k => k.trim()).filter(Boolean);
            saveConfig('cleaner_blocked_keywords', keywords);
            CleanerModule.check();
        });

        // Make setting rows clickable
        document.querySelectorAll('.tbdm-tab-content[data-tab="cleaner"] .tbdm-setting-row').forEach(row => {
            row.style.cursor = 'pointer';

            // Remove the for attribute from labels so they don't interfere
            const label = row.querySelector('label:first-child');
            if (label) label.removeAttribute('for');

            row.addEventListener('click', (e) => {
                if (e.target.closest('.tbdm-switch')) return;
                const checkbox = row.querySelector('input[type="checkbox"]');
                if (checkbox) checkbox.click();
            });
        });
    }

    function setupNotifierSettings() {
        const enabledSwitch = document.getElementById('tbdm-notifier-enabled');
        const usernameDisplay = document.getElementById('tbdm-username-display');
        const keywords = document.getElementById('tbdm-keywords');
        const resetKeywords = document.getElementById('tbdm-reset-keywords');
        const highlightColor = document.getElementById('tbdm-highlight-color');
        const colorWrapper = document.getElementById('tbdm-color-picker-wrapper');
        const volumeSlider = document.getElementById('tbdm-volume');
        const volumeIcon = document.getElementById('tbdm-volume-icon');

        // Detect and load username
        const detectedUsername = detectUsername();
        if (!CONFIG.notifier_username || CONFIG.notifier_username === 'Not Found') {
            saveConfig('notifier_username', detectedUsername);
        }
        usernameDisplay.textContent = CONFIG.notifier_username;

        // Load settings
        enabledSwitch.checked = CONFIG.notifier_enabled;
        keywords.value = CONFIG.notifier_keywords.join('\n');
        highlightColor.value = CONFIG.notifier_highlight_color;
        colorWrapper.style.backgroundColor = CONFIG.notifier_highlight_color;
        volumeSlider.value = CONFIG.notifier_sound_volume * 100;

        const volumeIcons = {
            mute: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M13.5 4.06c0-1.336-1.616-2.005-2.56-1.06l-4.5 4.5H4.508c-1.141 0-2.318.664-2.66 1.905A9.76 9.76 0 0 0 1.5 12c0 .898.121 1.768.35 2.595.341 1.24 1.518 1.905 2.659 1.905h1.93l4.5 4.5c.945.945 2.561.276 2.561-1.06V4.06ZM17.78 9.22a.75.75 0 1 0-1.06 1.06L18.44 12l-1.72 1.72a.75.75 0 1 0 1.06 1.06l1.72-1.72 1.72 1.72a.75.75 0 1 0 1.06-1.06L20.56 12l1.72-1.72a.75.75 0 1 0-1.06-1.06l-1.72 1.72-1.72-1.72Z" /></svg>`,
            on: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M13.5 4.06c0-1.336-1.616-2.005-2.56-1.06l-4.5 4.5H4.508c-1.141 0-2.318.664-2.66 1.905A9.76 9.76 0 0 0 1.5 12c0 .898.121 1.768.35 2.595.341 1.24 1.518 1.905 2.659 1.905h1.93l4.5 4.5c.945.945 2.561.276 2.561-1.06V4.06ZM18.584 5.106a.75.75 0 0 1 1.06 0c3.808 3.807 3.808 9.98 0 13.788a.75.75 0 0 1-1.06-1.06 8.25 8.25 0 0 0 0-11.668.75.75 0 0 1 0-1.06Z" /><path d="M15.932 7.757a.75.75 0 0 1 1.061 0 6 6 0 0 1 0 8.486.75.75 0 0 1-1.06-1.061 4.5 4.5 0 0 0 0-6.364.75.75 0 0 1 0-1.06Z" /></svg>`
        };

        function updateVolumeIcon() {
            volumeIcon.innerHTML = volumeSlider.value == 0 ? volumeIcons.mute : volumeIcons.on;
        }
        updateVolumeIcon();

        // Event listeners
        enabledSwitch.addEventListener('change', (e) => {
            saveConfig('notifier_enabled', e.target.checked);
            if (e.target.checked) NotifierModule.init();
        });

        keywords.addEventListener('input', () => {
            const keywordList = keywords.value.split('\n').map(k => k.trim()).filter(k => k);
            saveConfig('notifier_keywords', keywordList);
        });

        resetKeywords.addEventListener('click', () => {
            keywords.value = '';
            saveConfig('notifier_keywords', []);
        });

        highlightColor.addEventListener('input', () => {
            saveConfig('notifier_highlight_color', highlightColor.value);
            colorWrapper.style.backgroundColor = highlightColor.value;
        });

        volumeSlider.addEventListener('input', () => {
            saveConfig('notifier_sound_volume', parseFloat(volumeSlider.value) / 100);
            updateVolumeIcon();
        });

        // Make notifier setting rows clickable
        document.querySelectorAll('.tbdm-tab-content[data-tab="notifier"] .tbdm-setting-row').forEach(row => {
            row.style.cursor = 'pointer';

            // Remove the for attribute from labels so they don't interfere
            const label = row.querySelector('label:first-child');
            if (label) label.removeAttribute('for');

            row.addEventListener('click', (e) => {
                if (e.target.closest('.tbdm-switch')) return;
                const checkbox = row.querySelector('input[type="checkbox"]');
                if (checkbox) checkbox.click();
            });
        });
    }

    function setupFeaturesSettings() {
        const imageUpload = document.getElementById('tbdm-image-upload');
        const easyMention = document.getElementById('tbdm-easy-mention');
        const urlSender = document.getElementById('tbdm-url-sender');
        const focusLock = document.getElementById('tbdm-focus-lock');
        const idlePrevention = document.getElementById('tbdm-idle-prevention');
        const gifPicker = document.getElementById('tbdm-gif-picker');
        const imageViewer = document.getElementById('tbdm-image-viewer');
        const unicodeEmoji = document.getElementById('tbdm-unicode-emoji');

        // Load settings
        unicodeEmoji.checked = CONFIG.unicode_emoji_enabled;

        // Event listener
        unicodeEmoji.addEventListener('change', (e) => {
            saveConfig('unicode_emoji_enabled', e.target.checked);
            if (e.target.checked) {
                UnicodeEmojiModule.init();
            } else {
                UnicodeEmojiModule.stop();
            }
        });

        //
        const memeCreator = document.getElementById('tbdm-meme-creator');

        // Load settings
        memeCreator.checked = CONFIG.meme_creator_enabled;

        // Event listener
        memeCreator.addEventListener('change', (e) => {
            saveConfig('meme_creator_enabled', e.target.checked);
            if (e.target.checked) {
                MemeCreatorModule.init();
            } else {
                MemeCreatorModule.stop();
            }
        });

        // Load settings
        gifPicker.checked = CONFIG.gif_picker_enabled;
        imageViewer.checked = CONFIG.image_viewer_enabled;

        // Event listeners
        gifPicker.addEventListener('change', (e) => {
            saveConfig('gif_picker_enabled', e.target.checked);
            if (e.target.checked) {
                GifPickerModule.init();
            } else {
                GifPickerModule.stop();
            }
        });

        imageViewer.addEventListener('change', (e) => {
            saveConfig('image_viewer_enabled', e.target.checked);
            if (e.target.checked) {
                ImageViewerModule.init();
            } else {
                ImageViewerModule.stop();
            }
        });

        // Load settings
        imageUpload.checked = CONFIG.image_upload_enabled;
        easyMention.checked = CONFIG.easy_mention_enabled;
        urlSender.checked = CONFIG.url_sender_enabled;
        focusLock.checked = CONFIG.focus_lock_enabled;
        idlePrevention.checked = CONFIG.idle_prevention_enabled;

        // Make feature cards clickable
        document.querySelectorAll('.tbdm-feature-card').forEach(card => {
            card.style.cursor = 'pointer';
            card.addEventListener('click', (e) => {
                if (e.target.closest('.tbdm-switch')) return;
                const checkbox = card.querySelector('input[type="checkbox"]');
                if (checkbox) checkbox.click();
            });
        });


        // Event listeners
        imageUpload.addEventListener('change', (e) => {
            saveConfig('image_upload_enabled', e.target.checked);
            if (e.target.checked) {
                ImageUploadModule.init();
            } else {
                // Remove upload button if exists
                const uploadBtn = document.getElementById('tbdm-image-upload-btn');
                if (uploadBtn) uploadBtn.remove();
            }
        });

        easyMention.addEventListener('change', (e) => {
            saveConfig('easy_mention_enabled', e.target.checked);
            if (e.target.checked) {
                EasyMentionModule.init();
            } else {
                EasyMentionModule.stop();
            }
        });

        urlSender.addEventListener('change', (e) => {
            saveConfig('url_sender_enabled', e.target.checked);
            if (e.target.checked) {
                URLSenderModule.init();
            } else {
                // Remove URL button and window if exists
                const urlBtn = document.getElementById('urlBtn');
                const urlWindow = document.getElementById('urlWindow');
                if (urlBtn) urlBtn.remove();
                if (urlWindow) urlWindow.remove();
            }
        });

        focusLock.addEventListener('change', (e) => {
            saveConfig('focus_lock_enabled', e.target.checked);
            if (e.target.checked) {
                FocusLockModule.init();
            } else {
                FocusLockModule.deactivateFocusLock();
            }
        });

        idlePrevention.addEventListener('change', (e) => {
            saveConfig('idle_prevention_enabled', e.target.checked);
            if (e.target.checked) {
                IdlePreventionModule.init();
            } else {
                IdlePreventionModule.stop();
            }
        });
    }

    function setupAutocompleteSettings() {
        const usernameAutocomplete = document.getElementById('tbdm-autocomplete-username');
        const stickerAutocomplete = document.getElementById('tbdm-autocomplete-sticker');
        const mappingsContainer = document.getElementById('tbdm-mappings-container');
        const addMappingBtn = document.getElementById('tbdm-add-mapping');
        const resetMappingsBtn = document.getElementById('tbdm-reset-mappings');

        // Load settings
        usernameAutocomplete.checked = CONFIG.autocomplete_username_enabled;
        stickerAutocomplete.checked = CONFIG.autocomplete_sticker_enabled;

        // Event listeners
        usernameAutocomplete.addEventListener('change', (e) => {
            saveConfig('autocomplete_username_enabled', e.target.checked);
            if (e.target.checked || CONFIG.autocomplete_sticker_enabled) {
                AutocompleteModule.init();
            } else if (!e.target.checked && !CONFIG.autocomplete_sticker_enabled) {
                AutocompleteModule.stop();
            }
        });

        stickerAutocomplete.addEventListener('change', (e) => {
            saveConfig('autocomplete_sticker_enabled', e.target.checked);
            if (e.target.checked || CONFIG.autocomplete_username_enabled) {
                AutocompleteModule.init();
            } else if (!e.target.checked && !CONFIG.autocomplete_username_enabled) {
                AutocompleteModule.stop();
            }
        });

        // Render mappings
        function renderMappings() {
            mappingsContainer.innerHTML = '';
            const mappings = CONFIG.autocomplete_mappings;

            Object.keys(mappings).forEach(key => {
                const row = document.createElement('div');
                row.className = 'tbdm-mapping-row';
                row.innerHTML = `
                    <input type="text" class="tbdm-mapping-key" value="${key}" placeholder="keyword" data-original-key="${key}">
                    <span>=</span>
                    <input type="text" class="tbdm-mapping-value" value="${mappings[key]}" placeholder=":emoji" data-original-key="${key}">
                    <button class="tbdm-delete-mapping" title="Delete" data-key="${key}">×</button>
                `;
                mappingsContainer.appendChild(row);

                const keyInput = row.querySelector('.tbdm-mapping-key');
                const valueInput = row.querySelector('.tbdm-mapping-value');
                const deleteBtn = row.querySelector('.tbdm-delete-mapping');

                keyInput.addEventListener('blur', () => {
                    const originalKey = keyInput.getAttribute('data-original-key');
                    const newKey = keyInput.value.trim();
                    if (newKey && newKey !== originalKey) {
                        updateMappingKey(originalKey, newKey);
                        keyInput.setAttribute('data-original-key', newKey);
                        // Update the data attribute for valueInput as well
                        valueInput.setAttribute('data-original-key', newKey);
                        // Update the delete button's data-key
                        deleteBtn.setAttribute('data-key', newKey);
                    }
                });

                valueInput.addEventListener('blur', () => {
                    const currentKey = keyInput.getAttribute('data-original-key');
                    const newValue = valueInput.value.trim();
                    const mappings = CONFIG.autocomplete_mappings;
                    if (newValue && newValue !== mappings[currentKey]) {
                        updateMappingValue(currentKey, newValue);
                    }
                });

                deleteBtn.addEventListener('click', () => {
                    const keyToDelete = deleteBtn.getAttribute('data-key');
                    deleteMapping(keyToDelete);
                });
            });
        }

        function updateMappingKey(oldKey, newKey) {
            const mappings = CONFIG.autocomplete_mappings;
            if (mappings.hasOwnProperty(oldKey)) {
                const value = mappings[oldKey];
                delete mappings[oldKey];
                mappings[newKey] = value;
                saveConfig('autocomplete_mappings', mappings);
            }
        }

        function updateMappingValue(key, newValue) {
            const mappings = CONFIG.autocomplete_mappings;
            if (mappings.hasOwnProperty(key)) {
                mappings[key] = newValue;
                saveConfig('autocomplete_mappings', mappings);
            }
        }

        function deleteMapping(key) {
            const mappings = CONFIG.autocomplete_mappings;
            delete mappings[key];
            saveConfig('autocomplete_mappings', mappings);
            renderMappings();
        }

        addMappingBtn.addEventListener('click', () => {
            const mappings = CONFIG.autocomplete_mappings;
            let newKey = 'new';
            let counter = 1;
            while (mappings.hasOwnProperty(newKey)) {
                newKey = `new${counter++}`;
            }
            mappings[newKey] = ':emoji';
            saveConfig('autocomplete_mappings', mappings);
            renderMappings();
        });

        resetMappingsBtn.addEventListener('click', () => {
            if (confirm('Reset all mappings to defaults?')) {
                const defaultMappings = {
                    'hi': ':hello',
                    'hello': ':hello',
                    'no': ':negative',
                    'nahi': ':sticker-mb-no',
                    'sad': ':sticker-pepe-face',
                    'lmao': ':lmao',
                    'justsaid': ':justsaid',
                    'wow': ':sticker-omg-wow',
                    'lol': ':sticker-jjj-laugh',
                    'why': ':sticker-cat-why',
                    'ty': ':thankyou',
                    'slap': ':slap',
                    'wont': ':sticker-sr-no',
                    'bruh': ':sticker-facepalm',
                    'yay': ':yepdance',
                    'aww': ':sticker-pepe-aw'
                };
                saveConfig('autocomplete_mappings', defaultMappings);
                renderMappings();
            }
        });

        renderMappings();

        // Make autocomplete setting rows clickable
        document.querySelectorAll('.tbdm-tab-content[data-tab="autocomplete"] .tbdm-setting-row').forEach(row => {
            row.style.cursor = 'pointer';

            // Remove the for attribute from labels so they don't interfere
            const label = row.querySelector('label:first-child');
            if (label) label.removeAttribute('for');

            row.addEventListener('click', (e) => {
                if (e.target.closest('.tbdm-switch')) return;
                const checkbox = row.querySelector('input[type="checkbox"]');
                if (checkbox) checkbox.click();
            });
        });
    }

    function addSettingsButton() {
        const titleElement = document.querySelector('#shoutbox-container .content-title h6.left');
        if (titleElement && !document.querySelector("#tbdm-settings-btn")) {
            const btn = document.createElement("span");
            btn.id = "tbdm-settings-btn";
            btn.title = "Shoutbox Manager Settings";
            btn.textContent = "⚙️";
            btn.addEventListener("click", (e) => {
                e.stopPropagation();
                const modal = document.getElementById('tbdm-modal-wrapper');
                modal.style.display = "flex";
            });
            titleElement.style.display = 'flex';
            titleElement.style.alignItems = 'center';
            titleElement.appendChild(btn);
        }
    }

    // ============================================================================
    // STYLES
    // ============================================================================

    GM_addStyle(`
        /* Modal Wrapper with Glass Effect */
        #tbdm-modal-wrapper {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
            position: fixed;
            z-index: 99999;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.75);
            display: none;
            justify-content: center;
            align-items: center;
            backdrop-filter: blur(8px);
            animation: fadeIn 0.3s ease;
        }
        @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

        #tbdm-container {
            background: linear-gradient(145deg, #1a1a2e 0%, #16213e 100%);
            color: #e0e0e0;
            border: 1px solid rgba(255,255,255,0.1);
            border-radius: 16px;
            width: 90%;
            max-width: 450px;
            box-shadow: 0 20px 60px rgba(0,0,0,0.6), 0 0 100px rgba(20,167,108,0.15);
            display: flex;
            flex-direction: column;
            max-height: 80vh;
            overflow: hidden;
            animation: slideUp 0.4s cubic-bezier(0.16, 1, 0.3, 1);
        }
        @keyframes slideUp {
            from { opacity: 0; transform: translateY(40px); }
            to { opacity: 1; transform: translateY(0); }
        }

        /* Header with Gradient */
        #tbdm-header {
            padding: 20px 20px 16px;
            text-align: center;
            position: relative;
            background: linear-gradient(135deg, rgba(20,167,108,0.15) 0%, rgba(59,130,246,0.1) 100%);
            border-bottom: 1px solid rgba(255,255,255,0.1);
        }
        #tbdm-header h1 {
            font-size: 22px;
            font-weight: 800;
            background: linear-gradient(135deg, #14a76c 0%, #3b82f6 100%);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
            margin: 0 0 4px 0;
            letter-spacing: -0.5px;
        }
        #tbdm-header p {
            font-size: 12px;
            color: #9ca3af;
            margin: 0;
            font-weight: 400;
        }
        #tbdm-close-btn {
            position: absolute;
            top: 10px;
            right: 10px;
            border: none;
            background: transparent;
            color: #6b7280;
            cursor: pointer;
            font-size: 24px;
            font-weight: 400;
            transition: color .2s;
            padding: 0;
            margin: 0;
            line-height: 24px;
            width: 24px;
            height: 24px;
            display: inline-block;
            text-align: center;
        }
        #tbdm-close-btn:hover {
            color: #ef4444;
        }

        /* Modern Tabs */
        #tbdm-tabs {
            display: flex;
            padding: 0 14px;
            gap: 4px;
            background: rgba(0,0,0,0.2);
            border-bottom: 1px solid rgba(255,255,255,0.05);
            overflow-x: auto;
            flex-shrink: 0;
        }
        #tbdm-tabs::-webkit-scrollbar { height: 3px; }
        #tbdm-tabs::-webkit-scrollbar-track { background: transparent; }
        #tbdm-tabs::-webkit-scrollbar-thumb { background: rgba(20,167,108,0.3); border-radius: 10px; }
        .tbdm-tab {
            background: none;
            border: none;
            color: #6b7280;
            padding: 10px 14px;
            cursor: pointer;
            font-size: 12px;
            font-weight: 600;
            border-bottom: 3px solid transparent;
            transition: all .3s cubic-bezier(0.4, 0, 0.2, 1);
            white-space: nowrap;
            position: relative;
        }
        .tbdm-tab:hover {
            color: #d1d5db;
            background: rgba(255,255,255,0.03);
        }
        .tbdm-tab.active {
            color: #14a76c;
            border-bottom-color: #14a76c;
            background: rgba(20,167,108,0.08);
        }
        .tbdm-tab.active::after {
            content: '';
            position: absolute;
            bottom: -3px;
            left: 0;
            right: 0;
            height: 3px;
            background: linear-gradient(90deg, #14a76c, #3b82f6);
            box-shadow: 0 0 10px rgba(20,167,108,0.5);
        }

        /* Content Area */
        #tbdm-content {
            padding: 16px;
            overflow-y: auto;
            flex: 1;
            background: linear-gradient(to bottom, rgba(0,0,0,0.1) 0%, transparent 100%);
            min-height: 0;
        }
        #tbdm-content::-webkit-scrollbar { width: 6px; }
        #tbdm-content::-webkit-scrollbar-track { background: rgba(0,0,0,0.2); border-radius: 10px; }
        #tbdm-content::-webkit-scrollbar-thumb { background: rgba(20,167,108,0.3); border-radius: 10px; }
        #tbdm-content::-webkit-scrollbar-thumb:hover { background: rgba(20,167,108,0.5); }

        .tbdm-tab-content { display: none; animation: fadeInContent 0.3s ease; }
        .tbdm-tab-content.active { display: block; }
        @keyframes fadeInContent { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }

        /* Feature Cards - New Modern Style */
        .tbdm-feature-card {
            background: linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%);
            border: 1px solid rgba(255,255,255,0.08);
            border-radius: 10px;
            padding: 12px 14px;
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin-bottom: 8px;
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            position: relative;
            overflow: hidden;
        }
        .tbdm-feature-card::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: linear-gradient(135deg, rgba(20,167,108,0.1) 0%, rgba(59,130,246,0.1) 100%);
            opacity: 0;
            transition: opacity 0.3s;
        }
        .tbdm-feature-card:hover {
            background: linear-gradient(135deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0.04) 100%);
            border-color: rgba(20,167,108,0.3);
            transform: translateY(-1px);
            box-shadow: 0 6px 16px rgba(0,0,0,0.3), 0 0 25px rgba(20,167,108,0.12);
        }
        .tbdm-feature-card:hover::before { opacity: 1; }

        .tbdm-feature-header {
            display: flex;
            align-items: center;
            gap: 10px;
            flex: 1;
            position: relative;
            z-index: 1;
        }
        .tbdm-feature-icon {
            width: 36px;
            height: 36px;
            border-radius: 8px;
            background: linear-gradient(135deg, rgba(20,167,108,0.2) 0%, rgba(59,130,246,0.2) 100%);
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 16px;
            flex-shrink: 0;
            box-shadow: 0 3px 10px rgba(0,0,0,0.2);
        }
        .tbdm-feature-info {
            flex: 1;
        }
        .tbdm-feature-title {
            font-size: 13px;
            font-weight: 600;
            color: #f3f4f6;
            margin-bottom: 2px;
        }
        .tbdm-feature-desc {
            font-size: 11px;
            color: #9ca3af;
            font-weight: 400;
        }

        /* Sections */
        .tbdm-section {
            margin-bottom: 16px;
        }
        .tbdm-section-header {
            font-size: 11px;
            text-transform: uppercase;
            color: #14a76c;
            margin: 0 0 10px 0;
            letter-spacing: 0.8px;
            font-weight: 700;
            display: flex;
            align-items: center;
            gap: 6px;
        }
        .tbdm-divider {
            border: none;
            border-top: 1px solid rgba(255,255,255,0.08);
            margin: 14px 0;
            box-shadow: 0 1px 0 rgba(0,0,0,0.2);
        }

        /* Settings Row - Cleaner Style */
        .tbdm-setting-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 8px 12px;
            background: rgba(255,255,255,0.03);
            border-radius: 8px;
            margin-bottom: 6px;
            border: 1px solid rgba(255,255,255,0.05);
            transition: all 0.2s;
        }
        .tbdm-setting-row:hover {
            background: rgba(255,255,255,0.05);
            border-color: rgba(20,167,108,0.2);
        }
        .tbdm-setting-row label {
            font-size: 13px !important;
            margin-bottom: 0 !important;
        }
        .tbdm-master-switch {
            padding: 12px 16px;
            background: linear-gradient(135deg, rgba(20,167,108,0.12) 0%, rgba(59,130,246,0.08) 100%);
            border: 1px solid rgba(20,167,108,0.3);
            margin-bottom: 10px;
        }
        .tbdm-master-switch label:first-child {
            font-size: 15px !important;
            font-weight: 700;
            color: #fff;
        }

        /* Compact Switch for Settings Rows */
        .tbdm-setting-row .tbdm-switch {
            position: relative;
            display: inline-block;
            width: 42px;
            height: 24px;
            flex-shrink: 0;
            cursor: pointer;
        }
        .tbdm-setting-row .tbdm-switch input { opacity: 0; width: 0; height: 0; }
        .tbdm-setting-row .tbdm-slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: linear-gradient(135deg, #374151 0%, #1f2937 100%);
            transition: .4s cubic-bezier(0.4, 0, 0.2, 1);
            border-radius: 24px;
            box-shadow: inset 0 2px 4px rgba(0,0,0,0.3);
        }
        .tbdm-setting-row .tbdm-slider:before {
            position: absolute;
            content: "";
            height: 18px;
            width: 18px;
            left: 3px;
            bottom: 3px;
            background: linear-gradient(135deg, #f3f4f6 0%, #d1d5db 100%);
            transition: .4s cubic-bezier(0.4, 0, 0.2, 1);
            border-radius: 50%;
            box-shadow: 0 2px 6px rgba(0,0,0,0.3);
        }
        .tbdm-setting-row input:checked + .tbdm-slider {
            background: linear-gradient(135deg, #14a76c 0%, #10b981 100%);
            box-shadow: 0 0 15px rgba(20,167,108,0.4), inset 0 1px 3px rgba(255,255,255,0.2);
        }
        .tbdm-setting-row input:checked + .tbdm-slider:before {
            transform: translateX(18px);
            background: linear-gradient(135deg, #ffffff 0%, #f3f4f6 100%);
        }

        /* Modern Switch for Master and Feature Cards */
        .tbdm-master-switch .tbdm-switch,
        .tbdm-feature-card .tbdm-switch {
            position: relative;
            display: inline-block;
            width: 50px;
            height: 28px;
            flex-shrink: 0;
            cursor: pointer;
        }
        .tbdm-master-switch .tbdm-switch input,
        .tbdm-feature-card .tbdm-switch input { opacity: 0; width: 0; height: 0; }
        .tbdm-master-switch .tbdm-slider,
        .tbdm-feature-card .tbdm-slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: linear-gradient(135deg, #374151 0%, #1f2937 100%);
            transition: .4s cubic-bezier(0.4, 0, 0.2, 1);
            border-radius: 28px;
            box-shadow: inset 0 2px 4px rgba(0,0,0,0.3);
        }
        .tbdm-master-switch .tbdm-slider:before,
        .tbdm-feature-card .tbdm-slider:before {
            position: absolute;
            content: "";
            height: 22px;
            width: 22px;
            left: 3px;
            bottom: 3px;
            background: linear-gradient(135deg, #f3f4f6 0%, #d1d5db 100%);
            transition: .4s cubic-bezier(0.4, 0, 0.2, 1);
            border-radius: 50%;
            box-shadow: 0 2px 6px rgba(0,0,0,0.3);
        }
        .tbdm-master-switch input:checked + .tbdm-slider,
        .tbdm-feature-card input:checked + .tbdm-slider {
            background: linear-gradient(135deg, #14a76c 0%, #10b981 100%);
            box-shadow: 0 0 20px rgba(20,167,108,0.4), inset 0 1px 3px rgba(255,255,255,0.2);
        }
        .tbdm-master-switch input:checked + .tbdm-slider:before,
        .tbdm-feature-card input:checked + .tbdm-slider:before {
            transform: translateX(22px);
            background: linear-gradient(135deg, #ffffff 0%, #f3f4f6 100%);
        }

        /* Form Elements with Glow */
        .tbdm-form-group { margin-bottom: 16px; }
        #tbdm-content label {
            font-weight: 600;
            color: #d1d5db;
            font-size: 12px;
            display: block;
            margin-bottom: 6px;
            letter-spacing: 0.3px;
        }
        .tbdm-label-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 6px;
        }
        textarea {
            width: 100%;
            height: 80px;
            resize: vertical;
            background: rgba(0,0,0,0.3);
            border: 1px solid rgba(255,255,255,0.1);
            border-radius: 10px;
            padding: 10px 12px;
            font-size: 13px;
            box-sizing: border-box;
            color: #f3f4f6;
            font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
            transition: all 0.3s;
        }
        textarea:focus {
            outline: none;
            border-color: #14a76c;
            background: rgba(0,0,0,0.4);
            box-shadow: 0 0 0 3px rgba(20,167,108,0.15), 0 0 20px rgba(20,167,108,0.1);
        }
        textarea:disabled { opacity: 0.4; cursor: not-allowed; }

        #tbdm-username-display {
            background: rgba(20,167,108,0.12);
            border: 1px solid rgba(20,167,108,0.3);
            border-radius: 10px;
            color: #14a76c;
            padding: 12px 14px;
            font-size: 14px;
            font-weight: 600;
            box-sizing: border-box;
            font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
        }
        #tbdm-keywords { height: 100px; }
        #tbdm-blocked-user-ids { height: 80px; }
        #tbdm-blocked-keywords { height: 80px; }

        /* Color Picker with Preview */
        .tbdm-controls-row { display: grid; grid-template-columns: 1fr 1.5fr; gap: 12px; }
        #tbdm-color-picker-wrapper {
            position: relative;
            width: 100%;
            height: 44px;
            border: 2px solid rgba(255,255,255,0.1);
            border-radius: 10px;
            overflow: hidden;
            box-shadow: inset 0 2px 8px rgba(0,0,0,0.3), 0 4px 12px rgba(0,0,0,0.2);
            transition: all 0.3s;
        }
        #tbdm-color-picker-wrapper:hover {
            border-color: rgba(20,167,108,0.4);
            box-shadow: inset 0 2px 8px rgba(0,0,0,0.3), 0 0 20px rgba(20,167,108,0.2);
        }
        #tbdm-highlight-color {
            position: absolute;
            top: -5px;
            left: -5px;
            width: calc(100% + 10px);
            height: calc(100% + 10px);
            border: none;
            padding: 0;
            cursor: pointer;
        }

        /* Volume Control */
        .tbdm-volume-control {
            display: flex;
            align-items: center;
            gap: 10px;
            height: 44px;
            background: rgba(0,0,0,0.3);
            border: 1px solid rgba(255,255,255,0.1);
            border-radius: 10px;
            padding: 0 14px;
            box-sizing: border-box;
            transition: all 0.3s;
        }
        .tbdm-volume-control:hover {
            border-color: rgba(20,167,108,0.3);
            background: rgba(0,0,0,0.4);
        }
        #tbdm-volume-icon { color: #14a76c; width: 20px; height: 20px; flex-shrink: 0; }
        #tbdm-volume {
            -webkit-appearance: none;
            appearance: none;
            width: 100%;
            height: 5px;
            background: linear-gradient(to right, #14a76c 0%, #374151 0%);
            border-radius: 5px;
            outline: none;
            transition: all 0.3s;
        }
        #tbdm-volume::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 16px;
            height: 16px;
            background: linear-gradient(135deg, #14a76c 0%, #10b981 100%);
            border-radius: 50%;
            cursor: pointer;
            box-shadow: 0 2px 6px rgba(20,167,108,0.4), 0 0 0 3px rgba(20,167,108,0.15);
            transition: all 0.2s;
            margin-top: -5.5px;
        }
        #tbdm-volume::-webkit-slider-thumb:hover {
            transform: scale(1.2);
            box-shadow: 0 3px 10px rgba(20,167,108,0.6), 0 0 0 5px rgba(20,167,108,0.2);
        }
        #tbdm-volume::-moz-range-thumb {
            width: 16px;
            height: 16px;
            background: linear-gradient(135deg, #14a76c 0%, #10b981 100%);
            border-radius: 50%;
            cursor: pointer;
            border: none;
            box-shadow: 0 2px 6px rgba(20,167,108,0.4);
        }
        #tbdm-volume::-webkit-slider-runnable-track {
            height: 5px;
            border-radius: 5px;
        }
        #tbdm-volume::-moz-range-track {
            height: 5px;
            border-radius: 5px;
        }

        /* Buttons with Gradients */
        button { font-family: inherit; }
        #tbdm-reset-keywords, .tbdm-secondary-btn {
            background: linear-gradient(135deg, rgba(239,68,68,0.15) 0%, rgba(220,38,38,0.1) 100%);
            border: 1px solid rgba(239,68,68,0.3);
            color: #f87171;
            font-size: 11px;
            font-weight: 600;
            cursor: pointer;
            padding: 6px 10px;
            border-radius: 6px;
            transition: all 0.3s;
            white-space: nowrap;
        }
        #tbdm-reset-keywords:hover, .tbdm-secondary-btn:hover {
            background: linear-gradient(135deg, rgba(239,68,68,0.25) 0%, rgba(220,38,38,0.15) 100%);
            border-color: rgba(239,68,68,0.5);
            transform: translateY(-1px);
            box-shadow: 0 4px 12px rgba(239,68,68,0.2);
        }
        .tbdm-primary-btn {
            background: linear-gradient(135deg, #14a76c 0%, #10b981 100%);
            border: none;
            color: #fff;
            padding: 10px 16px;
            border-radius: 8px;
            font-size: 13px;
            font-weight: 600;
            cursor: pointer;
            width: 100%;
            margin-top: 10px;
            transition: all 0.3s;
            box-shadow: 0 4px 12px rgba(20,167,108,0.3);
        }
        .tbdm-primary-btn:hover {
            background: linear-gradient(135deg, #10b981 0%, #059669 100%);
            transform: translateY(-2px);
            box-shadow: 0 6px 20px rgba(20,167,108,0.4);
        }
        .tbdm-primary-btn:active {
            transform: translateY(0);
        }

/* BBCode Warning Animation */
        @keyframes slideInRight {
            from {
                opacity: 0;
                transform: translateX(20px);
            }
            to {
                opacity: 1;
                transform: translateX(0);
            }
        }
        /* Mappings */
        .tbdm-mapping-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 10px;
            gap: 10px;
        }
        .tbdm-help-text {
            font-size: 12px;
            color: #9ca3af;
            margin: 0;
            padding: 8px 12px;
            background: rgba(59,130,246,0.08);
            border-left: 3px solid #3b82f6;
            border-radius: 6px;
            flex: 1;
        }
        #tbdm-mappings-container {
            display: flex;
            flex-direction: column;
            gap: 6px;
            margin-bottom: 10px;
            max-height: 250px;
            overflow-y: auto;
            padding: 2px;
        }
        #tbdm-mappings-container::-webkit-scrollbar { width: 5px; }
        #tbdm-mappings-container::-webkit-scrollbar-track { background: rgba(0,0,0,0.2); border-radius: 10px; }
        #tbdm-mappings-container::-webkit-scrollbar-thumb { background: rgba(20,167,108,0.3); border-radius: 10px; }

        .tbdm-mapping-row {
            display: flex;
            align-items: center;
            gap: 6px;
            background: rgba(255,255,255,0.03);
            padding: 4px 6px;
            border-radius: 6px;
            border: 1px solid rgba(255,255,255,0.05);
            transition: all 0.2s;
        }
        .tbdm-mapping-row:hover {
            background: rgba(255,255,255,0.05);
            border-color: rgba(20,167,108,0.2);
        }
        .tbdm-mapping-key, .tbdm-mapping-value {
            flex: 1;
            background: rgba(0,0,0,0.3);
            border: 1px solid rgba(255,255,255,0.1);
            border-radius: 5px;
            padding: 6px 8px;
            font-size: 12px;
            color: #f3f4f6;
            font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
            transition: all 0.2s;
        }
        .tbdm-mapping-key:focus, .tbdm-mapping-value:focus {
            outline: none;
            border-color: #14a76c;
            background: rgba(0,0,0,0.4);
            box-shadow: 0 0 0 2px rgba(20,167,108,0.1);
        }
        .tbdm-mapping-row span {
            color: #6b7280;
            font-weight: bold;
            font-size: 12px;
        }
        .tbdm-delete-mapping {
            background: rgba(239,68,68,0.1);
            border: 1px solid rgba(239,68,68,0.2);
            color: #f87171;
            font-size: 16px;
            font-weight: bold;
            cursor: pointer;
            width: 26px;
            height: 26px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 5px;
            transition: all 0.3s;
            flex-shrink: 0;
        }
        .tbdm-delete-mapping:hover {
            background: rgba(239,68,68,0.2);
            border-color: rgba(239,68,68,0.4);
            transform: scale(1.1) rotate(90deg);
        }

        /* GIF Tool Modal Styles */
        #gif-tool-modal {
            position: fixed;
            width: 440px;
            max-width: 90vw;
            background: #2f3136;
            border: 1px solid #444;
            border-radius: 8px;
            z-index: 2147483647;
            display: none;
            box-shadow: 0 10px 30px rgba(0,0,0,0.8);
            overflow: hidden;
            flex-direction: column;
            top: auto;
        }
        #gif-tool-header {
            height: 24px;
            background: #202225;
            cursor: grab;
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 0 8px;
            border-bottom: 1px solid #36393f;
            flex-shrink: 0;
        }
        #gif-tool-header:active { cursor: grabbing; background: #18191c; }
        #gif-tool-title {
            font-size: 11px;
            color: #aaa;
            font-weight: bold;
            user-select: none;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }
        #gif-tool-content {
            padding: 8px;
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        #gif-tool-results {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(80px,1fr));
            gap: 6px;
            max-height: 320px;
            min-height: 100px;
            overflow-y: auto;
            scrollbar-width: thin;
            scrollbar-color: #202225 #2f3136;
        }
        #gif-tool-results::-webkit-scrollbar { width: 8px; }
        #gif-tool-results::-webkit-scrollbar-track { background: #2f3136; }
        #gif-tool-results::-webkit-scrollbar-thumb { background-color: #202225; border-radius: 4px; }
        #gif-tool-results img {
            width:100%;
            height:80px;
            object-fit:cover;
            cursor:pointer;
            border-radius:4px;
            transition:all .12s;
            border:2px solid transparent;
            background: #202225;
        }
        #gif-tool-results img:hover {
            transform:scale(1.04);
            border-color:#00bfff;
            z-index: 1;
        }
        #gif-tool-controls {
            display:flex;
            gap:8px;
            align-items:center;
            flex-shrink: 0;
        }
        #gif-tool-search {
            flex:1;
            padding:6px 10px;
            background:#40444b;
            border:1px solid #555;
            color:#fff;
            border-radius:6px;
            font-size:13px;
            outline:none;
        }
        #gif-tool-search:focus { border-color: #00bfff; }
        #gif-tool-close {
            background:none;
            border:none;
            color:#aaa;
            font-size: 18px;
            cursor:pointer;
            line-height: 1;
            padding: 0;
        }
        #gif-tool-close:hover { color:#fff; }

#tbdm-gif-tool-btn {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    height: 28px;
    width: 28px;
    margin-left: 4px;
    margin-right: 2px;
    cursor: pointer;
    color: #ccc;
    transition: color 0.1s, transform 0.1s;
}
#tbdm-gif-tool-btn svg {
    position: relative;
    top: 1px;
}

        #tbdm-gif-tool-btn svg { display: block; }
        #tbdm-gif-tool-btn:hover { color: #fff; transform: translateY(-1px); }


        /* Settings Button */
        #tbdm-settings-btn {
            cursor: pointer;
            margin-left: 10px;
            font-size: 18px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            transition: all .3s ease;
            opacity: 0.7;
        }
        #tbdm-settings-btn:hover {
            opacity: 1;
            transform: rotate(90deg) scale(1.1);
        }

        /* Easy Mention Styles */
        .shout-user { user-select: none; }
        .chromium span.shout-time:has(+ .shout-user [href^="account"]) { cursor: pointer; position: relative; }
        .chromium span.shout-time:has(+ .shout-user [href^="account"]):hover { margin-left: -1.5em; }
        .chromium span.shout-time:has(+ .shout-user [href^="account"])::after { content: ""; margin-left: .5em; height: 1em; rotate: 180deg; display: none; width: 1em; }
        .chromium span.shout-time:has(+ .shout-user [href^="account"]):hover::after { display: inline-block; }
        .firefox span.shout-time { cursor: pointer; position: relative; }
        .firefox span.shout-time:hover { margin-left: -1.5em; }
        .firefox span.shout-time::after { content: ""; margin-left: .5em; height: 1em; rotate: 180deg; display: none; width: 1em; }
        .firefox span.shout-time:hover::after { display: inline-block; }
        .dark-scheme.chromium span.shout-time:has(+ .shout-user [href^="account"])::after { background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M205 34.8c11.5 5.1 19 16.6 19 29.2v64H336c97.2 0 176 78.8 176 176c0 113.3-81.5 163.9-100.2 174.1c-2.5 1.4-5.3 1.9-8.1 1.9c-10.9 0-19.7-8.9-19.7-19.7c0-7.5 4.3-14.4 9.8-19.5c9.4-8.8 22.2-26.4 22.2-56.7c0-53-43-96-96-96H224v64c0 12.6-7.4 24.1-19 29.2s-25 3-34.4-5.4l-160-144C3.9 225.7 0 217.1 0 208s3.9-17.7 10.6-23.8l160-144c9.4-8.5 22.9-10.6 34.4-5.4z" style="fill: rgb(238, 238, 238);"/></svg>'); }
        .light-scheme.chromium span.shout-time:has(+ .shout-user [href^="account"])::after { background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M205 34.8c11.5 5.1 19 16.6 19 29.2v64H336c97.2 0 176 78.8 176 176c0 113.3-81.5 163.9-100.2 174.1c-2.5 1.4-5.3 1.9-8.1 1.9c-10.9 0-19.7-8.9-19.7-19.7c0-7.5 4.3-14.4 9.8-19.5c9.4-8.8 22.2-26.4 22.2-56.7c0-53-43-96-96-96H224v64c0 12.6-7.4 24.1-19 29.2s-25 3-34.4-5.4l-160-144C3.9 225.7 0 217.1 0 208s3.9-17.7 10.6-23.8l160-144c9.4-8.5 22.9-10.6 34.4-5.4z" style="fill: rgb(68 ,68, 68);"/></svg>'); }
        .dark-scheme.firefox span.shout-time::after { background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M205 34.8c11.5 5.1 19 16.6 19 29.2v64H336c97.2 0 176 78.8 176 176c0 113.3-81.5 163.9-100.2 174.1c-2.5 1.4-5.3 1.9-8.1 1.9c-10.9 0-19.7-8.9-19.7-19.7c0-7.5 4.3-14.4 9.8-19.5c9.4-8.8 22.2-26.4 22.2-56.7c0-53-43-96-96-96H224v64c0 12.6-7.4 24.1-19 29.2s-25 3-34.4-5.4l-160-144C3.9 225.7 0 217.1 0 208s3.9-17.7 10.6-23.8l160-144c9.4-8.5 22.9-10.6 34.4-5.4z" style="fill: rgb(238, 238, 238);"/></svg>'); }
        .light-scheme.firefox span.shout-time::after { background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M205 34.8c11.5 5.1 19 16.6 19 29.2v64H336c97.2 0 176 78.8 176 176c0 113.3-81.5 163.9-100.2 174.1c-2.5 1.4-5.3 1.9-8.1 1.9c-10.9 0-19.7-8.9-19.7-19.7c0-7.5 4.3-14.4 9.8-19.5c9.4-8.8 22.2-26.4 22.2-56.7c0-53-43-96-96-96H224v64c0 12.6-7.4 24.1-19 29.2s-25 3-34.4-5.4l-160-144C3.9 225.7 0 217.1 0 208s3.9-17.7 10.6-23.8l160-144c9.4-8.5 22.9-10.6 34.4-5.4z" style="fill: rgb(68 ,68, 68);"/></svg>'); }

        /* URL Sender Styles */
            #shout-ibb-container {
            display: flex;
            gap: 0 .5rem;
            margin-right: 0;
            padding-right: .5rem;
            right: 0;
            position: absolute;
        }

        /* Keep history button always on the right */
        #shoutHistoryBtn {
            margin-left: auto !important;
            order: 999 !important;
        }
        #shout-send-container { position: relative; }
        #urlWindow { position: absolute; width: 100%; left: 0; flex-flow: wrap; bottom: 7px; gap: 0.5rem; display: flex; transition: visibility 0s linear .2s, opacity .1s linear .1s, translate .2s linear; visibility: hidden; background: var(--main-bg); border-top: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color); padding-top: 0.5rem; padding-bottom: 0.5rem; opacity: 0; }
        .spotlight #urlWindow { bottom: 28px; }
        #urlWindow.show { visibility: visible; translate: 0 -30px; transition-delay: 0s; opacity: 1; }
        .url-inputs { height: 37px; color: var(--text-color) !important; background: var(--main-bg); padding: 0px .5rem; border-top:1px solid var(--border-color); border-bottom:1px solid var(--border-color); border-left: none; border-right: none; outline: 0; }
        .spotlight .url-inputs { height: 60px; }
        #urlField { flex: 1 1 100%; }
        #labelField { flex: 4 1 auto; border-right: 1px solid var(--border-color); }
        #submitURL { flex: 1 1 auto; background: transparent; border: 1px solid var(--border-color); border-right: none; color: var(--text-color); font-weight: 600; font-size: 0.9rem; cursor: pointer; }
        #urlBtn i { line-height: 37px; font-size: 0.9rem; font-weight: 600; font-family: inherit; user-select: none; }
        input.shoutbox-text { width: auto !important; }
        .spotlight input#shout_text { padding-left: .5rem; padding-right: calc(220px - .5rem); }
        @media(max-width: 767px) {
            .spotlight input#shout_text { padding-right: calc(200px - .5rem); }
            .spotlight #shout-ibb-container { padding-right: .5rem; }
            #tbdm-container { width: 95%; max-width: 95%; border-radius: 16px; }
            #tbdm-tabs { padding: 0 12px; gap: 4px; }
            .tbdm-tab { padding: 12px 14px; font-size: 13px; }
            .tbdm-controls-row { grid-template-columns: 1fr; }
        }

        /* Mobile Improvements */
        input#shout_text.shoutbox-text { -webkit-text-size-adjust: 100%; }
        input#shout_text { autocapitalize: on; }
    `);

    // ============================================================================
    // INITIALIZATION
    // ============================================================================

    let scriptInitialized = false;

    function updateShoutInputPadding() {
        const input = document.querySelector('#shout_text');
        const tray = document.querySelector('#shout-ibb-container');
        if (!input || !tray) return;

        const buttonIds = [
            'tbdm-image-upload-btn',
            'tbdm-gif-tool-btn',
            'meme-tool-btn',
            'emoji-toggle-btn',
            'urlBtn'
        ];

        const paddingMap = { 1: 125, 2: 160, 3: 195, 4: 230, 5: 260 };
        const count = buttonIds.filter(id => document.getElementById(id)).length;
        const padding = paddingMap[count] || 125;

        input.style.paddingRight = padding + 'px';
    }

    function watchTrayForPaddingUpdates() {
        const tray = document.querySelector('#shout-ibb-container');
        if (!tray) return;

        const observer = new MutationObserver(() => updateShoutInputPadding());
        observer.observe(tray, { childList: true, subtree: true });
    }

    function waitForElement(selector, callback, maxRetries = 100) {
        let retries = 0;
        const checkInterval = setInterval(() => {
            const element = document.querySelector(selector);
            if (element) {
                clearInterval(checkInterval);
                callback(element);
            }
            retries++;
            if (retries > maxRetries) clearInterval(checkInterval);
        }, 100);
    }

    function initializeScript() {
        if (scriptInitialized) return;

        const shoutboxContainer = document.querySelector('#shoutbox-container');
        if (!shoutboxContainer) {
            setTimeout(initializeScript, 500);
            return;
        }

        scriptInitialized = true;

        if (CONFIG.cleaner_enabled) CleanerModule.init();
        if (CONFIG.notifier_enabled) NotifierModule.init();
        if (CONFIG.image_upload_enabled) ImageUploadModule.init();
        if (CONFIG.easy_mention_enabled) EasyMentionModule.init();
        if (CONFIG.url_sender_enabled) URLSenderModule.init();
        if (CONFIG.autocomplete_username_enabled || CONFIG.autocomplete_sticker_enabled) AutocompleteModule.init();
        if (CONFIG.focus_lock_enabled) FocusLockModule.init();
        if (CONFIG.idle_prevention_enabled) IdlePreventionModule.init();
        if (CONFIG.gif_picker_enabled) GifPickerModule.init();
        if (CONFIG.image_viewer_enabled) ImageViewerModule.init();
        if (CONFIG.meme_creator_enabled) MemeCreatorModule.init();
        BBCodeValidatorModule.init();
        InfiniteScrollModule.init();
        setTimeout(() => {
            updateShoutInputPadding();
            watchTrayForPaddingUpdates();
        }, 200);

        UIImprovementsModule.init();
        if (CONFIG.unicode_emoji_enabled) UnicodeEmojiModule.init();
        createSettingsUI();

        waitForElement('#shoutbox-container .content-title h6.left', addSettingsButton);

        const shoutInput = document.querySelector("#shout_text");
        if (shoutInput) shoutInput.setAttribute("autocapitalize", "on");

        const viewport = document.querySelector("meta[name='viewport']");
        if (viewport) {
            viewport.setAttribute("content", "width=device-width, height=device-height, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no");
        }
    }

    setTimeout(initializeScript, 1000);
    setTimeout(initializeScript, 3000);
    if (document.readyState !== 'loading') {
        initializeScript();
    } else {
        document.addEventListener('DOMContentLoaded', initializeScript);
    }

})();