JanitorAI Context Maker

Adds a Location and Character System to JanitorAI with nested grouping functionality

Ajankohdalta 1.11.2024. Katso uusin versio.

// ==UserScript==
// @name         JanitorAI Context Maker
// @namespace    http://tampermonkey.net/
// @version      5
// @license MIT
// @description  Adds a Location and Character System to JanitorAI with nested grouping functionality
// @match        https://janitorai.com/chats/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=https://janitorai.com/
// @grant        GM.setValue
// @grant        GM.getValue
// @grant        GM.xmlHttpRequest
// @connect      cdnjs.cloudflare.com
// ==/UserScript==

(async function() {
    'use strict';

    let customContextMenu;
    let initialMouseX;
    let initialMouseY;
    const hideDistance = 100; // Distance in pixels to hide the menu
    let ItemTransferTarget = null;

    //.addEventListener('contextmenu', showMenu);
    function CreateContextMenu(mainColor, textColor, optionNames, optionFunctions) {
        // Destroy existing menu if present
        DestroyContextMenu();

        // Create a new custom menu
        customContextMenu = document.createElement('div');
        customContextMenu.style.position = 'absolute';
        customContextMenu.style.background = mainColor;
        customContextMenu.style.color = textColor;
        customContextMenu.style.border = '1px solid #ccc';
        customContextMenu.style.padding = '5px 10px';
        customContextMenu.style.display = 'none';
        customContextMenu.style.zIndex = '1000';
        customContextMenu.style.zIndex = '99999999'; // High z-index

        // Add menu items with dividers
        optionNames.forEach((name, index) => {
            const menuItem = document.createElement('div');
            menuItem.style.padding = '5px 0';
            menuItem.style.cursor = 'pointer';
            menuItem.textContent = name;
            menuItem.addEventListener('click', () => {
                optionFunctions[index]();
                hideMenu();
            });

            // Append menu item
            customContextMenu.appendChild(menuItem);

            // Add a divider except after the last item
            if (index < optionNames.length - 1) {
                const divider = document.createElement('div');
                divider.style.borderTop = '1px solid #ccc';
                customContextMenu.appendChild(divider);
            }
        });

        // Append the menu to the body
        document.body.appendChild(customContextMenu);

        // Check mouse distance
        document.addEventListener('mousemove', trackMouseDistance);
    }

    function DestroyContextMenu() {
        if (customContextMenu) {
            customContextMenu.remove();
            document.removeEventListener('contextmenu', showMenu);
            document.removeEventListener('click', hideMenu);
            document.removeEventListener('mousemove', trackMouseDistance);
            customContextMenu = null;
        }
    }

    function showMenu(event) {
        event.preventDefault();
        initialMouseX = event.clientX;
        initialMouseY = event.clientY;
        if (customContextMenu) {
            customContextMenu.style.top = `${event.clientY}px`;
            customContextMenu.style.left = `${event.clientX}px`;
            customContextMenu.style.display = 'block';
        }
    }

    function hideMenu() {
        if (customContextMenu) {
            customContextMenu.style.display = 'none';
        }
    }

    function trackMouseDistance(event) {
        if (customContextMenu && customContextMenu.style.display === 'block') {
            const distance = Math.sqrt(
                Math.pow(event.clientX - initialMouseX, 2) +
                Math.pow(event.clientY - initialMouseY, 2)
            );
            if (distance > hideDistance && !customContextMenu.contains(event.target)) {
                hideMenu();
            }
        }
    }

    // Define Themes
    const themes = {
        dark: {
            '--bg-color': 'rgba(34, 34, 34, var(--ui-transparency))',
            '--bg-tool': 'rgba(34, 34, 34, 0.8)',
            '--text-color': '#ffffff',
            '--text-color-darker': '#cccccc',
            '--border-color': 'rgba(68, 68, 68, var(--ui-transparency))',
            '--button-bg-color': 'rgba(0, 123, 255, var(--ui-transparency))',
            '--active-char-color': 'rgba(173, 216, 230, var(--ui-transparency))',
            '--success-bg-color': 'rgba(40, 167, 69, var(--ui-transparency))',
            '--info-bg-color': 'rgba(23, 162, 184, var(--ui-transparency))',
            '--warning-bg-color': 'rgba(255, 193, 7, var(--ui-transparency))',
            '--muted-bg-color': 'rgba(108, 117, 125, var(--ui-transparency))',
            '--danger-bg-color': 'rgba(220, 53, 69, var(--ui-transparency))',
            '--shadow-color': 'rgba(0,0,0,0.5)',
            '--link-color': '#8cb3ff',
            '--code-bg-color': 'rgba(0, 0, 0, 0.3)',
            '--code-text-color': '#ff9d00'
        },
        light: {
            '--bg-color': 'rgba(255, 255, 255, var(--ui-transparency))',
            '--bg-tool': 'rgba(255, 255, 255, 0.8)',
            '--text-color': '#000000',
            '--text-color-darker': '#333333',
            '--border-color': 'rgba(204, 204, 204, var(--ui-transparency))',
            '--button-bg-color': 'rgba(0, 123, 255, var(--ui-transparency))',
            '--active-char-color': 'rgba(173, 216, 230, var(--ui-transparency))',
            '--success-bg-color': 'rgba(40, 167, 69, var(--ui-transparency))',
            '--info-bg-color': 'rgba(23, 162, 184, var(--ui-transparency))',
            '--warning-bg-color': 'rgba(255, 193, 7, var(--ui-transparency))',
            '--muted-bg-color': 'rgba(108, 117, 125, var(--ui-transparency))',
            '--danger-bg-color': 'rgba(220, 53, 69, var(--ui-transparency))',
            '--shadow-color': 'rgba(0,0,0,0.1)',
            '--link-color': '#007bff',
            '--code-bg-color': 'rgba(0, 0, 0, 0.05)',
            '--code-text-color': '#d63384'
        },
        sepia_light: {
            '--bg-color': 'rgba(244, 232, 208, var(--ui-transparency))',
            '--bg-tool': 'rgba(244, 232, 208, 0.8',
            '--text-color': '#2e241c',
            '--text-color-darker': '#1a140f',
            '--border-color': 'rgba(193, 154, 107, var(--ui-transparency))',
            '--button-bg-color': 'rgba(160, 82, 45, var(--ui-transparency))',
            '--active-char-color': 'rgba(210, 180, 140, var(--ui-transparency))',
            '--success-bg-color': 'rgba(107, 68, 35, var(--ui-transparency))',
            '--info-bg-color': 'rgba(194, 148, 110, var(--ui-transparency))',
            '--warning-bg-color': 'rgba(215, 172, 116, var(--ui-transparency))',
            '--muted-bg-color': 'rgba(160, 130, 94, var(--ui-transparency))',
            '--danger-bg-color': 'rgba(168, 96, 50, var(--ui-transparency))',
            '--shadow-color': 'rgba(0,0,0,0.3)',
            '--link-color': '#6c757d',
            '--code-bg-color': 'rgba(0, 0, 0, 0.1)',
            '--code-text-color': '#a0522d'
        },
        sepia_dark: {
            '--bg-color': 'rgba(60, 45, 31, var(--ui-transparency))',
            '--bg-tool': 'rgba(60, 45, 31, 0.8)',
            '--text-color': '#d8c6b2',
            '--text-color-darker': '#b8a493',
            '--border-color': 'rgba(102, 75, 50, var(--ui-transparency))',
            '--button-bg-color': 'rgba(139, 69, 19, var(--ui-transparency))',
            '--active-char-color': 'rgba(210, 180, 140, var(--ui-transparency))',
            '--success-bg-color': 'rgba(107, 68, 35, var(--ui-transparency))',
            '--info-bg-color': 'rgba(139, 101, 68, var(--ui-transparency))',
            '--warning-bg-color': 'rgba(205, 133, 63, var(--ui-transparency))',
            '--muted-bg-color': 'rgba(122, 91, 62, var(--ui-transparency))',
            '--danger-bg-color': 'rgba(165, 42, 42, var(--ui-transparency))',
            '--shadow-color': 'rgba(0,0,0,0.6)',
            '--link-color': '#d2b48c',
            '--code-bg-color': 'rgba(0, 0, 0, 0.3)',
            '--code-text-color': '#deb887'
        },
        solarized_light: {
            '--bg-color': 'rgba(253, 246, 227, var(--ui-transparency))',
            '--bg-tool': 'rgba(253, 246, 227, 0.8)',
            '--text-color': '#47565c',
            '--text-color-darker': '#2c3438',
            '--border-color': 'rgba(238, 232, 213, var(--ui-transparency))',
            '--button-bg-color': 'rgba(38, 139, 210, var(--ui-transparency))',
            '--active-char-color': 'rgba(133, 153, 0, var(--ui-transparency))',
            '--success-bg-color': 'rgba(133, 153, 0, var(--ui-transparency))',
            '--info-bg-color': 'rgba(38, 139, 210, var(--ui-transparency))',
            '--warning-bg-color': 'rgba(181, 137, 0, var(--ui-transparency))',
            '--muted-bg-color': 'rgba(147, 161, 161, var(--ui-transparency))',
            '--danger-bg-color': 'rgba(220, 50, 47, var(--ui-transparency))',
            '--shadow-color': 'rgba(0,0,0,0.2)',
            '--link-color': '#2aa198',
            '--code-bg-color': 'rgba(0, 43, 54, 0.7)',
            '--code-text-color': '#cb4b16'
        },
        solarized_dark: {
            '--bg-color': 'rgba(0, 43, 54, var(--ui-transparency))',
            '--bg-tool': 'rgba(0, 43, 54, 0.8)',
            '--text-color': '#eee8d5',
            '--text-color-darker': '#cdc5b0',
            '--border-color': 'rgba(7, 54, 66, var(--ui-transparency))',
            '--button-bg-color': 'rgba(38, 139, 210, var(--ui-transparency))',
            '--active-char-color': 'rgba(133, 153, 0, var(--ui-transparency))',
            '--success-bg-color': 'rgba(133, 153, 0, var(--ui-transparency))',
            '--info-bg-color': 'rgba(38, 139, 210, var(--ui-transparency))',
            '--warning-bg-color': 'rgba(181, 137, 0, var(--ui-transparency))',
            '--muted-bg-color': 'rgba(88, 110, 117, var(--ui-transparency))',
            '--danger-bg-color': 'rgba(220, 50, 47, var(--ui-transparency))',
            '--shadow-color': 'rgba(0, 0, 0, 0.4)',
            '--link-color': '#2aa198',
            '--code-bg-color': 'rgba(253, 246, 227, 0.1)',
            '--code-text-color': '#cb4b16'
        },
        forest_light: {
            '--bg-color': 'rgba(233, 245, 233, var(--ui-transparency))',
            '--bg-tool': 'rgba(233, 245, 233, 0.8)',
            '--text-color': '#2f4f2f',
            '--text-color-darker': '#1c2f1c',
            '--border-color': 'rgba(209, 230, 209, var(--ui-transparency))',
            '--button-bg-color': 'rgba(60, 179, 113, var(--ui-transparency))',
            '--active-char-color': 'rgba(34, 139, 34, var(--ui-transparency))',
            '--success-bg-color': 'rgba(144, 238, 144, var(--ui-transparency))',
            '--info-bg-color': 'rgba(60, 179, 113, var(--ui-transparency))',
            '--warning-bg-color': 'rgba(240, 230, 140, var(--ui-transparency))',
            '--muted-bg-color': 'rgba(152, 251, 152, var(--ui-transparency))',
            '--danger-bg-color': 'rgba(205, 92, 92, var(--ui-transparency))',
            '--shadow-color': 'rgba(0,0,0,0.2)',
            '--link-color': '#3cb371',
            '--code-bg-color': 'rgba(0, 0, 0, 0.1)',
            '--code-text-color': '#8b4513'
        },
        forest_dark: {
            '--bg-color': 'rgba(34, 49, 34, var(--ui-transparency))',
            '--bg-tool': 'rgba(34, 49, 34, 0.8)',
            '--text-color': '#e0f7e9',
            '--text-color-darker': '#b0c7b9',
            '--border-color': 'rgba(46, 61, 46, var(--ui-transparency))',
            '--button-bg-color': 'rgba(60, 179, 113, var(--ui-transparency))',
            '--active-char-color': 'rgba(144, 238, 144, var(--ui-transparency))',
            '--success-bg-color': 'rgba(34, 139, 34, var(--ui-transparency))',
            '--info-bg-color': 'rgba(144, 238, 144, var(--ui-transparency))',
            '--warning-bg-color': 'rgba(189, 183, 107, var(--ui-transparency))',
            '--muted-bg-color': 'rgba(85, 107, 47, var(--ui-transparency))',
            '--danger-bg-color': 'rgba(139, 69, 19, var(--ui-transparency))',
            '--shadow-color': 'rgba(0,0,0,0.4)',
            '--link-color': '#8fbc8f',
            '--code-bg-color': 'rgba(0, 0, 0, 0.3)',
            '--code-text-color': '#ffd700'
        },
        ocean_light: {
            '--bg-color': 'rgba(28, 107, 160, var(--ui-transparency))',
            '--bg-tool': 'rgba(28, 107, 160, 0.8)',
            '--text-color': '#ffffff',
            '--text-color-darker': '#cccccc',
            '--border-color': 'rgba(54, 144, 192, var(--ui-transparency))',
            '--button-bg-color': 'rgba(0, 123, 255, var(--ui-transparency))',
            '--active-char-color': 'rgba(173, 216, 230, var(--ui-transparency))',
            '--success-bg-color': 'rgba(60, 179, 113, var(--ui-transparency))',
            '--info-bg-color': 'rgba(23, 162, 184, var(--ui-transparency))',
            '--warning-bg-color': 'rgba(255, 193, 7, var(--ui-transparency))',
            '--muted-bg-color': 'rgba(108, 117, 125, var(--ui-transparency))',
            '--danger-bg-color': 'rgba(220, 53, 69, var(--ui-transparency))',
            '--shadow-color': 'rgba(0,0,0,0.3)',
            '--link-color': '#00ffff',
            '--code-bg-color': 'rgba(0, 0, 0, 0.2)',
            '--code-text-color': '#ff7f50'
        },
        ocean_dark: {
            '--bg-color': 'rgba(0, 30, 60, var(--ui-transparency))',
            '--bg-tool': 'rgba(0, 30, 60, 0.8)',
            '--text-color': '#ffffff',
            '--text-color-darker': '#cccccc',
            '--border-color': 'rgba(0, 53, 102, var(--ui-transparency))',
            '--button-bg-color': 'rgba(0, 123, 255, var(--ui-transparency))',
            '--active-char-color': 'rgba(135, 206, 235, var(--ui-transparency))',
            '--success-bg-color': 'rgba(46, 139, 87, var(--ui-transparency))',
            '--info-bg-color': 'rgba(0, 96, 100, var(--ui-transparency))',
            '--warning-bg-color': 'rgba(255, 140, 0, var(--ui-transparency))',
            '--muted-bg-color': 'rgba(47, 79, 79, var(--ui-transparency))',
            '--danger-bg-color': 'rgba(139, 0, 0, var(--ui-transparency))',
            '--shadow-color': 'rgba(0,0,0,0.5)',
            '--link-color': '#00ffff',
            '--code-bg-color': 'rgba(0, 0, 0, 0.4)',
            '--code-text-color': '#ff7f50'
        },
        terminal: {
            '--bg-color': 'rgba(0, 0, 0, var(--ui-transparency))',
            '--bg-tool': 'rgba(0, 0, 0, 0.8)',
            '--text-color': '#00ff00',
            '--text-color-darker': '#00cc00',
            '--border-color': 'rgba(0, 200, 0, var(--ui-transparency))',
            '--button-bg-color': 'rgba(0, 125, 0, var(--ui-transparency))',
            '--active-char-color': 'rgba(0, 75, 0, var(--ui-transparency))',
            '--success-bg-color': 'rgba(0, 128, 0, var(--ui-transparency))',
            '--info-bg-color': 'rgba(0, 125, 0, var(--ui-transparency))',
            '--warning-bg-color': 'rgba(100, 125, 0, var(--ui-transparency))',
            '--muted-bg-color': 'rgba(0, 128, 0, var(--ui-transparency))',
            '--danger-bg-color': 'rgba(100, 0, 0, var(--ui-transparency))',
            '--shadow-color': 'rgba(0, 50, 0, 0.5)',
            '--link-color': '#00ffff',
            '--code-bg-color': 'rgba(0, 0, 0, 0.8)',
            '--code-text-color': '#7fff00'
        },
        retro: {
            '--bg-color': 'rgba(196, 182, 187, var(--ui-transparency))',
            '--bg-tool': 'rgba(196, 182, 187, 0.8)',
            '--text-color': '#191919',
            '--text-color-darker': '#000000',
            '--border-color': 'rgba(128, 128, 128, var(--ui-transparency))',
            '--button-bg-color': 'rgba(255, 105, 180, var(--ui-transparency))',
            '--active-char-color': 'rgba(255, 255, 0, var(--ui-transparency))',
            '--success-bg-color': 'rgba(50, 205, 50, var(--ui-transparency))',
            '--info-bg-color': 'rgba(135, 206, 235, var(--ui-transparency))',
            '--warning-bg-color': 'rgba(255, 165, 0, var(--ui-transparency))',
            '--muted-bg-color': 'rgba(128, 128, 128, var(--ui-transparency))',
            '--danger-bg-color': 'rgba(255, 0, 0, var(--ui-transparency))',
            '--shadow-color': 'rgba(0,0,0,0.3)',
            '--link-color': '#1e90ff',
            '--code-bg-color': 'rgba(0, 0, 0, 0.1)',
            '--code-text-color': '#ff1493'
        },
        neon: {
            '--bg-color': 'rgba(0, 0, 0, var(--ui-transparency))',
            '--bg-tool': 'rgba(0, 0, 0, 0.8)',
            '--text-color': '#ffffff',
            '--text-color-darker': '#cccccc',
            '--border-color': 'rgba(0, 255, 255, var(--ui-transparency))',
            '--button-bg-color': 'rgba(255, 0, 255, var(--ui-transparency))',
            '--active-char-color': 'rgba(0, 255, 0, var(--ui-transparency))',
            '--success-bg-color': 'rgba(0, 255, 0, var(--ui-transparency))',
            '--info-bg-color': 'rgba(0, 255, 255, var(--ui-transparency))',
            '--warning-bg-color': 'rgba(255, 255, 0, var(--ui-transparency))',
            '--muted-bg-color': 'rgba(255, 0, 255, var(--ui-transparency))',
            '--danger-bg-color': 'rgba(255, 0, 0, var(--ui-transparency))',
            '--shadow-color': 'rgba(0, 255, 255, 0.5)',
            '--link-color': '#ff00ff',
            '--code-bg-color': 'rgba(0, 0, 0, 0.8)',
            '--code-text-color': '#00ffff'
        },
        vintage: {
            '--bg-color': 'rgba(240, 230, 140, var(--ui-transparency))',
            '--bg-tool': 'rgba(240, 230, 140, 0.8)',
            '--text-color': '#360505',
            '--text-color-darker': '#200303',
            '--border-color': 'rgba(139, 69, 19, var(--ui-transparency))',
            '--button-bg-color': 'rgba(128, 0, 0, var(--ui-transparency))',
            '--active-char-color': 'rgba(255, 215, 0, var(--ui-transparency))',
            '--success-bg-color': 'rgba(50, 205, 50, var(--ui-transparency))',
            '--info-bg-color': 'rgba(70, 130, 180, var(--ui-transparency))',
            '--warning-bg-color': 'rgba(218, 165, 32, var(--ui-transparency))',
            '--muted-bg-color': 'rgba(128, 128, 0, var(--ui-transparency))',
            '--danger-bg-color': 'rgba(178, 34, 34, var(--ui-transparency))',
            '--shadow-color': 'rgba(139, 69, 19, 0.5)',
            '--link-color': '#8b0000',
            '--code-bg-color': 'rgba(245, 222, 179, 0.5)',
            '--code-text-color': '#8b0000'
        },
        pastel: {
            '--bg-color': 'rgba(255, 228, 225, var(--ui-transparency))',
            '--bg-tool': 'rgba(255, 228, 225, 0.8)',
            '--text-color': '#4d4d4d',
            '--text-color-darker': '#333333',
            '--border-color': 'rgba(255, 192, 203, var(--ui-transparency))',
            '--button-bg-color': 'rgba(135, 206, 235, var(--ui-transparency))',
            '--active-char-color': 'rgba(175, 238, 238, var(--ui-transparency))',
            '--success-bg-color': 'rgba(152, 251, 152, var(--ui-transparency))',
            '--info-bg-color': 'rgba(135, 206, 235, var(--ui-transparency))',
            '--warning-bg-color': 'rgba(255, 228, 181, var(--ui-transparency))',
            '--muted-bg-color': 'rgba(238, 130, 238, var(--ui-transparency))',
            '--danger-bg-color': 'rgba(240, 128, 128, var(--ui-transparency))',
            '--shadow-color': 'rgba(0,0,0,0.1)',
            '--link-color': '#ff69b4',
            '--code-bg-color': 'rgba(255, 250, 205, 0.8)',
            '--code-text-color': '#dc143c'
        }
    };

    // Initialize CSS variables
    function setTheme(themeName) {
        const theme = themes[themeName];
        Object.keys(theme).forEach(key => {
            document.documentElement.style.setProperty(key, theme[key]);
        });
    }

    // Retrieve saved settings or set defaults
    const defaultTransparency = await GM.getValue('transparency', '0.9');
    const defaultTheme = await GM.getValue('theme', 'dark');

    // Initialize transparency and theme
    document.documentElement.style.setProperty('--ui-transparency', defaultTransparency);
    setTheme(defaultTheme);

    // Add placeholder styles
    const style = document.createElement('style');
    style.innerHTML = `
    input::placeholder, textarea::placeholder {
        color: var(--text-color);
    }
    input:-ms-input-placeholder, textarea:-ms-input-placeholder {
        color: var(--text-color);
    }
    input::-ms-input-placeholder, textarea::-ms-input-placeholder {
        color: var(--text-color);
    }
    input::-webkit-input-placeholder, textarea::-webkit-input-placeholder {
        color: var(--text-color);
    }
    `;
    document.head.appendChild(style);

    // --- Context Menu and Tool Buttons ---
    const menuButtonsContainer = document.createElement('div');
    menuButtonsContainer.style.cssText = `
        position: fixed;
        top: 10px;
        left: 50%;
        transform: translateX(-50%);
        display: flex;
        justify-content: center;
        z-index: 10000;
    `;
    document.body.appendChild(menuButtonsContainer);

    const contextMenuButton = document.createElement('button');
    contextMenuButton.textContent = '⚙️';
    contextMenuButton.title = 'Menu';
    contextMenuButton.style.cssText = `
        width: 40px;
        height: 40px;
        margin-right: 5px;
        padding: 0;
        border: none;
        background-color: var(--button-bg-color);
        color: var(--text-color);
        border-radius: 50%;
        font-size: 24px;
        cursor: pointer;
        z-index: 10000;
    `;
    menuButtonsContainer.appendChild(contextMenuButton);

    const toolButtonsData = [
        { emoji: '🧮', title: 'Calculator', iframeSrc: 'https://www.desmos.com/fourfunction', id: 'calculator' },
        { emoji: '🎲', title: 'Dice Roller', iframeSrc: '', id: 'dice' },
        { emoji: '🎮', title: 'Game', iframeSrc: 'https://freepacman.org/', id: 'game' },
    ];

    toolButtonsData.forEach(tool => {
        const button = document.createElement('button');
        button.textContent = tool.emoji;
        button.title = tool.title;
        button.style.cssText = `
            width: 40px;
            height: 40px;
            margin-right: 5px;
            padding: 0;
            border: none;
            background-color: var(--button-bg-color);
            color: var(--text-color);
            border-radius: 50%;
            font-size: 24px;
            cursor: pointer;
        `;
        button.addEventListener('click', () => {
            openToolWindow(tool);
        });
        menuButtonsContainer.appendChild(button);
    });

    const openWindows = new Set();

    function openToolWindow(tool) {
        if (openWindows.has(tool.id)) {
            return;
        }

        // Create the window container
        const windowContainer = document.createElement('div');
        windowContainer.style.cssText = `
        position: fixed;
        top: 100px;
        left: 100px;
        width: 500px;
        height: 400px;
        background-color: var(--bg-color);
        border: 1px solid var(--border-color);
        box-shadow: 0 0 10px var(--shadow-color);
        border-radius: 5px;
        z-index: 10002;
        display: flex;
        flex-direction: column;
    `;

        // Add a header with the title and close button
        const header = document.createElement('div');
        header.style.cssText = `
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 5px;
        background-color: var(--button-bg-color);
        color: var(--text-color);
        cursor: move;
    `;
        const title = document.createElement('span');
        title.textContent = tool.title;
        header.appendChild(title);
        const closeButton = document.createElement('button');
        closeButton.textContent = '✖️';
        closeButton.style.cssText = `
        background: none;
        border: none;
        color: var(--text-color);
        cursor: pointer;
    `;
        closeButton.addEventListener('click', () => {
            document.body.removeChild(windowContainer);
            openWindows.delete(tool.id);
        });
        header.appendChild(closeButton);

        windowContainer.appendChild(header);

        // Add iframe
        const iframe = document.createElement('iframe');
        iframe.style.cssText = `
    flex-grow: 1;
    width: 100%;
    border: none;
    background-color: var(--bg-color);
    color: var(--text-color);
`;
        let src = tool.iframeSrc;

        // Adjust dice URL based on theme
        if (tool.id === 'dice') {
            const dicehex = getComputedHexValue('--button-bg-color').slice(1);
            const chromahex = getComputedHexValue('--bg-color').slice(1);
            const labelhex = getComputedHexValue('--text-color').slice(1);
            src = `https://dice.bee.ac/?dicehex=${dicehex}&chromahex=${chromahex}&labelhex=${labelhex}`;
        }

        // Adjust calculator URL based on theme
        if (tool.id === 'calculator') {
            const bgColor = getComputedHexValue('--bg-color').slice(1);
            const textColor = getComputedHexValue('--text-color').slice(1);
            const buttonBgColor = getComputedHexValue('--button-bg-color').slice(1);
            src = `https://www.desmos.com/fourfunction?backgroundColor=${bgColor}&textColor=${textColor}&buttonBackgroundColor=${buttonBgColor}`;
        }

        iframe.src = src;
        windowContainer.appendChild(iframe);

        // Make window draggable
        makeElementDraggable(windowContainer, header);

        document.body.appendChild(windowContainer);
        openWindows.add(tool.id);

        document.body.appendChild(windowContainer);
        openWindows.add(tool.id);
    }

    function getComputedHexValue(variableName) {
        const computedStyle = getComputedStyle(document.documentElement);
        const colorValue = computedStyle.getPropertyValue(variableName).trim();

        // Create a temporary div to get the computed color
        const tempDiv = document.createElement('div');
        tempDiv.style.color = colorValue;
        document.body.appendChild(tempDiv);
        const computedColor = getComputedStyle(tempDiv).color;
        document.body.removeChild(tempDiv);

        // Now computedColor is in 'rgb(r, g, b)' or 'rgba(r, g, b, a)' format
        const rgba = computedColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);

        if (rgba) {
            const r = parseInt(rgba[1]).toString(16).padStart(2, '0');
            const g = parseInt(rgba[2]).toString(16).padStart(2, '0');
            const b = parseInt(rgba[3]).toString(16).padStart(2, '0');
            return `#${r}${g}${b}`;
        } else {
            // Fallback to default
            return '#FFFFFF';
        }
    }

    function makeElementDraggable(elmnt, handle) {
        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
        if (handle) {
            handle.onmousedown = dragMouseDown;
        } else {
            elmnt.onmousedown = dragMouseDown;
        }

        function dragMouseDown(e) {
            e = e || window.event;
            e.preventDefault();
            pos3 = e.clientX;
            pos4 = e.clientY;
            document.onmouseup = closeDragElement;
            document.onmousemove = elementDrag;
        }

        function elementDrag(e) {
            e = e || window.event;
            e.preventDefault();
            pos1 = pos3 - e.clientX;
            pos2 = pos4 - e.clientY;
            pos3 = e.clientX;
            pos4 = e.clientY;
            elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
            elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
        }

        function closeDragElement() {
            document.onmouseup = null;
            document.onmousemove = null;
        }
    }

    // Helper functions for tooltip
    let tooltipElement = null;

    function showTooltip(event, content, set) {
        hideTooltip(); // Remove existing tooltip if any

        // Create new tooltip element
        tooltipElement = document.createElement('div');
        tooltipElement.style.cssText = `
        position: absolute;
        z-index: 10000;
        background-color: var(--bg-tool);
        color: var(--text-color);
        border: 1px solid var(--border-color);
        padding: 5px;
        border-radius: 5px;
        font-size: 12px;
        max-width: 600px;
        white-space: pre-wrap;
        box-shadow: 0 0 10px var(--shadow-color);
    `;
        tooltipElement.innerHTML = content;

        // Append the tooltip to the body first to get its size
        document.body.appendChild(tooltipElement);

        // Get the parent node's bounding rectangle
        const parentRect = event.currentTarget.parentNode.parentNode.getBoundingClientRect();

        if (!set) {
            // Tooltip to the right of the parent element
            tooltipElement.style.left = `${parentRect.right + 4}px`;
            tooltipElement.style.top = `${parentRect.top}px`;
        } else {
            // Tooltip to the left of the parent element
            const tooltipWidth = tooltipElement.offsetWidth; // Get the tooltip width after it's appended
            tooltipElement.style.left = `${parentRect.left - tooltipWidth + 15}px`; // Adjust to the left
            tooltipElement.style.top = `${parentRect.top}px`;
        }

        // Adjust position if the tooltip goes off screen
        const tooltipRect = tooltipElement.getBoundingClientRect();
        if (tooltipRect.right > window.innerWidth) {
            tooltipElement.style.left = `${window.innerWidth - tooltipRect.width - 10}px`;
        }
        if (tooltipRect.left < 0) {
            tooltipElement.style.left = `10px`; // Move it a bit to the right if it goes off screen on the left
        }
        if (tooltipRect.bottom > window.innerHeight) {
            tooltipElement.style.top = `${window.innerHeight - tooltipRect.height - 10}px`;
        }
    }

    function hideTooltip() {
        if (tooltipElement && tooltipElement.parentNode) {
            tooltipElement.parentNode.removeChild(tooltipElement);
            tooltipElement = null; // Set to null after removing
        }
    }

    // --- Context Panel ---
    const contextPanel = document.createElement('div');
    contextPanel.id = 'context-panel';
    contextPanel.style.cssText = `
    position: fixed; /* Keep position fixed to center the panel */
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 400px;
    padding: 20px;
    background-color: var(--bg-color);
    border: 1px solid var(--border-color);
    box-shadow: 0 0 10px var(--shadow-color);
    border-radius: 5px;
    display: none;
    z-index: 10001;
    /* Remove position: relative; */
`;
    document.body.appendChild(contextPanel);

    // Add close button to contextPanel
    const contextCloseButton = document.createElement('button');
    contextCloseButton.textContent = '✖️';
    contextCloseButton.style.cssText = `
        position: absolute;
        top: 10px;
        right: 10px;
        background: none;
        border: none;
        font-size: 20px;
        cursor: pointer;
        color: var(--text-color);
    `;
    contextCloseButton.addEventListener('click', () => {
        contextPanel.style.display = 'none';
    });
    contextPanel.appendChild(contextCloseButton);

    const transparencyLabel = document.createElement('label');
    transparencyLabel.textContent = 'UI Transparency';
    transparencyLabel.style.cssText = `
        color: var(--text-color);
        display: block;
        margin-bottom: 5px;
    `;
    contextPanel.appendChild(transparencyLabel);

    const transparencySlider = document.createElement('input');
    transparencySlider.type = 'range';
    transparencySlider.min = '0.1';
    transparencySlider.max = '1';
    transparencySlider.step = '0.1';
    transparencySlider.value = defaultTransparency;
    transparencySlider.style.cssText = `
        width: 100%;
        margin-bottom: 10px;
    `;
    transparencySlider.addEventListener('input', () => {
        document.documentElement.style.setProperty('--ui-transparency', transparencySlider.value);
        // Re-apply current theme to update transparency
        setTheme(themeDropdown.value);
        GM.setValue('transparency', transparencySlider.value);
    });
    contextPanel.appendChild(transparencySlider);

    const dropperLabel = document.createElement('label');
    dropperLabel.textContent = 'UI Theme';
    dropperLabel.style.cssText = `
        color: var(--text-color);
        display: block;
        margin-bottom: 5px;
    `;
    contextPanel.appendChild(dropperLabel);

    const themeDropdown = document.createElement('select');
    themeDropdown.style.cssText = `
        width: 100%;
        padding: 5px;
        margin-bottom: 10px;
        border: 1px solid var(--border-color);
        border-radius: 5px;
        background-color: var(--bg-color);
        color: var(--text-color);
    `;
    Object.keys(themes).forEach(theme => {
        const option = document.createElement('option');
        option.value = theme;
        option.textContent = theme.charAt(0).toUpperCase() + theme.slice(1);
        themeDropdown.appendChild(option);
    });

    themeDropdown.value = defaultTheme;

    themeDropdown.addEventListener('change', () => {
        setTheme(themeDropdown.value);
        GM.setValue('theme', themeDropdown.value);
    });
    contextPanel.appendChild(themeDropdown);

    // Add divider
    const divider = document.createElement('hr');
    divider.style.cssText = `
        border: none;
        border-top: 1px solid var(--border-color);
        margin: 10px 0;
    `;
    contextPanel.appendChild(divider);

    const contextLabel = document.createElement('label');
    contextLabel.textContent = 'Primary Context';
    contextLabel.style.cssText = `
        color: var(--text-color);
        display: block;
        margin-bottom: 5px;
    `;
    contextPanel.appendChild(contextLabel);

    const primaryContextInput = document.createElement('textarea');
    primaryContextInput.placeholder = 'Primary context goes here...';
    primaryContextInput.style.cssText = `
        width: 100%;
        height: 100px;
        margin-bottom: 10px;
        padding: 10px;
        border: 1px solid var(--border-color);
        border-radius: 5px;
        box-sizing: border-box;
        background-color: var(--bg-color);
        color: var(--text-color);
    `;
    contextPanel.appendChild(primaryContextInput);

    // Define the sleep function
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    const updateContextButton = document.createElement('button');
    updateContextButton.textContent = 'Update Context';
    updateContextButton.style.cssText = `
        width: 100%;
        padding: 10px;
        border: none;
        background-color: var(--success-bg-color);
        color: var(--text-color);
        border-radius: 5px;
        cursor: pointer;
    `;

    updateContextButton.addEventListener('click', async () => {
        const primaryContext = primaryContextInput.value;
        var fullContext = `Context;\n"` + primaryContext + `"\n`;
        fullContext += `\n` + window.getContext();
        console.log("setting context; " + fullContext);

        window.manuClick('//*[@id="menu-button-:rb:"]');
        await sleep(250);

        window.manuClick('//*[@id="menu-list-:rb:-menuitem-:ru:"]');
        await sleep(250);

        window.manuWrite("/html/body/div[9]/div[3]/div/section/div/textarea", fullContext);
        await sleep(250);

        window.manuClick("/html/body/div[9]/div[3]/div/section/footer/button[2]");
    });

    window.manuWrite = function(xpath, text) {
        var result = document.evaluate(
            xpath,
            document,
            null,
            XPathResult.FIRST_ORDERED_NODE_TYPE,
            null
        );

        var node = result.singleNodeValue;

        if (node) {
            node.focus();

            // Since the node is an HTMLTextAreaElement, get the value setter from its prototype
            const nativeTextAreaValueSetter = Object.getOwnPropertyDescriptor(
                window.HTMLTextAreaElement.prototype,
                'value'
            ).set;

            nativeTextAreaValueSetter.call(node, text);

            // Dispatch the 'input' event to simulate user input
            var event = new Event('input', { bubbles: true });
            node.dispatchEvent(event);

        } else {
            console.error("Node not found for XPath:", xpath);
        }
    }

    window.manuClick = function(xpath) {
        var result = document.evaluate(
            xpath,
            document,
            null,
            XPathResult.FIRST_ORDERED_NODE_TYPE,
            null
        );

        var node = result.singleNodeValue;

        if (node) {
            node.click();
        }
    }

    contextPanel.appendChild(updateContextButton);

    contextMenuButton.addEventListener('click', () => {
        contextPanel.style.display = contextPanel.style.display === 'none' ? 'block' : 'none';
    });

    // Helper function to find the active location recursively
    function findActiveLocation(items) {
        for (const item of items) {
            if (item.active) {
                return item;
            }
            if (item.children && item.children.length > 0) {
                const activeChild = findActiveLocation(item.children);
                if (activeChild) {
                    return activeChild;
                }
            }
        }
        return null;
    }

    // Helper function to collect all active characters recursively
    function collectActiveCharacters(items, result = []) {
        for (const item of items) {
            if (item.active) {
                result.push(item);
            }
            if (item.children && item.children.length > 0) {
                collectActiveCharacters(item.children, result);
            }
        }
        return result;
    }

    // Modify the getContext function to utilize the helper functions
    window.getContext = function() {
        const activeLocation = findActiveLocation(locationGroups.flatMap(g => g.items));
        if (!activeLocation) return '';

        let context = ``;

        if (plotInput && plotInput.value.trim() !== '') {
            context += `Plot:\n"${plotInput.value}"\n`;
        } else {
            context += `Plot:\n"No specific plot."\n`;
        }

        context += `\nSetting;\n"${activeLocation.name}" (${timeInput.value}, ${weatherInput.value}):\n`
        context += `\u0009"${activeLocation.description}"\n`;

        context += `\n{{user}}'s characters;\n`;

        const activeUserCharacters = collectActiveCharacters(characterGroups.flatMap(g => g.items)).filter(char => char.characterType == 1);

        activeUserCharacters.forEach(char => {
            context += `"${char.name}" (${char.sex}, ${char.species}, ${char.age}, ${char.bodyType}, ${char.personality}):\n`;
            context += `\u0009"${char.bio}"\n`;
        });

        context += `\n{{char}}'s characters;\n`;

        const activeCharCharacters = collectActiveCharacters(characterGroups.flatMap(g => g.items)).filter(char => char.characterType == 0);

        activeCharCharacters.forEach(char => {
            context += `"${char.name}" (${char.sex}, ${char.species}, ${char.age}, ${char.bodyType}, ${char.personality}):\n`;
            context += `\u0009"${char.bio}"\n`;
        });

        return context;
    };

    // --- Character Sidebar with Groups and Nested Characters ---
    const characterSidebar = document.createElement('div');
    characterSidebar.id = 'character-sheet-sidebar';
    characterSidebar.style.cssText = `
        position: fixed;
        top: 0;
        right: -350px;
        width: 350px;
        height: 100%;
        display: flex;
        flex-direction: column;
        background-color: var(--bg-color);
        border-left: 2px solid var(--border-color);
        box-shadow: -2px 0 5px var(--shadow-color);
        box-sizing: border-box;
        transition: right 0.3s;
        z-index: 9999;
    `;
    document.body.appendChild(characterSidebar);

    const characterToggleButton = document.createElement('button');
    characterToggleButton.textContent = '☰';
    characterToggleButton.style.cssText = `
        position: fixed;
        top: 10px;
        right: 10px;
        padding: 5px 10px;
        border: none;
        background-color: var(--button-bg-color);
        color: var(--text-color);
        border-radius: 5px;
        cursor: pointer;
        transition: right 0.3s;
        z-index: 10000;
    `;
    characterToggleButton.addEventListener('click', () => {
        const isOpen = characterSidebar.style.right === '0px';
        characterSidebar.style.right = isOpen ? '-350px' : '0';
        characterToggleButton.style.right = isOpen ? '10px' : '360px';
    });
    document.body.appendChild(characterToggleButton);

    const characterHeader = document.createElement('div');
    characterHeader.style.cssText = `
        padding: 10px;
        background-color: var(--border-color);
        text-align: center;
        font-weight: bold;
        color: var(--text-color);
    `;
    characterHeader.textContent = 'Characters';
    characterSidebar.appendChild(characterHeader);

    const characterButtonBox = document.createElement('div');
    characterButtonBox.style.cssText = `
        display: flex;
        justify-content: space-between;
        padding: 10px;
        background-color: var(--bg-color);
        flex-shrink: 0;
    `;
    characterSidebar.appendChild(characterButtonBox);

    // New Character Button
    const newCharacterButton = document.createElement('button');
    newCharacterButton.textContent = 'New';
    newCharacterButton.title = 'Create New Character';
    newCharacterButton.style.cssText = `
        padding: 5px 10px;
        border: none;
        background-color: var(--success-bg-color);
        color: var(--text-color);
        border-radius: 5px;
        cursor: pointer;
    `;
    newCharacterButton.addEventListener('click', () => {
        createNewCharacter();
    });
    characterButtonBox.appendChild(newCharacterButton);

    // Load Character Button
    const loadCharacterButton = document.createElement('button');
    loadCharacterButton.textContent = 'Load';
    loadCharacterButton.title = 'Load a Character';
    loadCharacterButton.style.cssText = `
        padding: 5px 10px;
        border: none;
        background-color: var(--info-bg-color);
        color: var(--text-color);
        border-radius: 5px;
        cursor: pointer;
    `;
    loadCharacterButton.addEventListener('click', () => {
        loadCharacter();
    });
    characterButtonBox.appendChild(loadCharacterButton);

    // Group Character Button
    const groupCharacterButton = document.createElement('button');
    groupCharacterButton.textContent = 'Group';
    groupCharacterButton.title = 'Create New Group';
    groupCharacterButton.style.cssText = `
        padding: 5px 10px;
        border: none;
        background-color: var(--info-bg-color);
        color: var(--text-color);
        border-radius: 5px;
        cursor: pointer;
    `;
    groupCharacterButton.addEventListener('click', () => {
        createNewCharacterGroup();
    });
    characterButtonBox.appendChild(groupCharacterButton);

    // Import Character Button
    const importCharacterButton = document.createElement('button');
    importCharacterButton.textContent = 'Import';
    importCharacterButton.title = 'Import Characters';
    importCharacterButton.style.cssText = `
        padding: 5px 10px;
        border: none;
        background-color: var(--warning-bg-color);
        color: var(--text-color);
        border-radius: 5px;
        cursor: pointer;
    `;
    importCharacterButton.addEventListener('click', () => {
        importCharacters();
    });
    characterButtonBox.appendChild(importCharacterButton);

    // Export Character Button
    const exportCharacterButton = document.createElement('button');
    exportCharacterButton.textContent = 'Export';
    exportCharacterButton.title = 'Export Characters';
    exportCharacterButton.style.cssText = `
        padding: 5px 10px;
        border: none;
        background-color: var(--muted-bg-color);
        color: var(--text-color);
        border-radius: 5px;
        cursor: pointer;
    `;
    exportCharacterButton.addEventListener('click', () => {
        exportCharacters();
    });
    characterButtonBox.appendChild(exportCharacterButton);

    // Add fifth button: "Load" for Character
    function loadCharacter() {
        const fileInput = document.createElement('input');
        fileInput.type = 'file';
        fileInput.accept = '.json';
        fileInput.addEventListener('change', async (event) => {
            const file = event.target.files[0];
            const reader = new FileReader();
            reader.onload = (e) => {
                try {
                    const character = JSON.parse(e.target.result);
                    if (character && character.id) {
                        // Add to Ungrouped
                        const ungrouped = characterGroups.find(g => g.name === 'Ungrouped');
                        if (ungrouped) {
                            ungrouped.items.push(character);
                        } else {
                            characterGroups[0].items.push(character);
                        }
                        renderCharacterGroups();
                    } else {
                        alert('Invalid character format.');
                    }
                } catch (error) {
                    alert('Failed to load character: ' + error.message);
                }
            };
            reader.readAsText(file);
        });
        fileInput.click();
    }

    const characterGroupList = document.createElement('div');
    characterGroupList.id = 'character-group-list';
    characterGroupList.style.cssText = `
        flex-grow: 1;
        overflow-y: auto;
        padding: 10px;
    `;
    characterSidebar.appendChild(characterGroupList);

    // Initialize Character Groups
    let characterGroups = [
        { name: 'Ungrouped', items: [], collapsed: false }
    ];

    // Function to create a new Character
    function createNewCharacter() {
        const newCharacter = {
            id: generateId(),
            active: true,
            emoji: '😀',
            name: 'New Character',
            sex: '',
            species: '',
            age: '',
            bodyType: '',
            personality: '',
            bio: '',
            characterType: 0,
            children: [],
            collapsed: false
        };
        // Add to Ungrouped
        const ungrouped = characterGroups.find(g => g.name === 'Ungrouped');
        if (ungrouped) {
            ungrouped.items.push(newCharacter);
        } else {
            characterGroups[0].items.push(newCharacter);
        }
        renderCharacterGroups();
    }

    // Function to create a new Character Group
    function createNewCharacterGroup() {
        const groupName = prompt('Enter group name:', `Group ${characterGroups.length}`);
        if (groupName && groupName.trim() !== '') {
            characterGroups.push({ name: groupName.trim(), items: [], collapsed: false });
            renderCharacterGroups();
        }
    }

    // Function to render Character Groups and Items
    function renderCharacterGroups() {
        characterGroupList.innerHTML = '';

        characterGroups.forEach((group, groupIndex) => {
            // Sort items alphabetically by name
            group.items.sort((a, b) => a.name.localeCompare(b.name));

            const groupContainer = document.createElement('div');
            groupContainer.className = 'character-group';
            groupContainer.style.cssText = `
                margin-bottom: 10px;
                border: 1px solid var(--border-color);
                border-radius: 5px;
                background-color: var(--active-char-color);
            `;

            const groupHeader = document.createElement('div');
            groupHeader.style.cssText = `
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 5px 10px;
                background-color: var(--button-bg-color);
                color: var(--text-color);
                cursor: pointer;
                user-select: none;
                position: relative;
            `;
            groupHeader.textContent = group.name;
            groupHeader.addEventListener('click', () => {
                group.collapsed = !group.collapsed;
                renderCharacterGroups();
            });

            const groupActions = document.createElement('div');
            groupActions.style.cssText = `
                display: flex;
                align-items: center;
            `;

            // Activate/Deactivate All Button
            const toggleAllButton = document.createElement('button');
            toggleAllButton.title = 'Activate/Deactivate All';
            toggleAllButton.style.cssText = `
                background: none;
                border: none;
                color: var(--text-color);
                cursor: pointer;
                margin-right: 3px;
                font-size: 16px;
            `;
            updateToggleAllButton(toggleAllButton, group);
            toggleAllButton.addEventListener('click', (e) => {
                e.stopPropagation();
                toggleAllGroupCharacters(group);
                updateToggleAllButton(toggleAllButton, group);
                renderCharacterGroups();
            });
            groupActions.appendChild(toggleAllButton);

            // Rename Group Button
            const renameGroupButton = document.createElement('button');
            renameGroupButton.textContent = '✏️';
            renameGroupButton.title = 'Rename Group';
            renameGroupButton.style.cssText = `
                background: none;
                border: none;
                color: var(--text-color);
                cursor: pointer;
                margin-right: 2px;
            `;
            renameGroupButton.addEventListener('click', (e) => {
                e.stopPropagation();
                renameGroup(groupIndex);
            });
            groupActions.appendChild(renameGroupButton);

            // Delete Group Button
            const deleteGroupButton = document.createElement('button');
            deleteGroupButton.textContent = '🗑️';
            deleteGroupButton.title = 'Delete Group';
            deleteGroupButton.style.cssText = `
                background: none;
                border: none;
                color: var(--text-color);
                cursor: pointer;
            `;
            deleteGroupButton.addEventListener('click', (e) => {
                e.stopPropagation();
                deleteGroup(groupIndex);
            });
            groupActions.appendChild(deleteGroupButton);

            groupHeader.appendChild(groupActions);
            groupContainer.appendChild(groupHeader);

            if (!group.collapsed) {
                const itemsContainer = document.createElement('div');
                itemsContainer.style.cssText = `
                    padding: 5px 10px;
                    display: block;
                `;
                if (group.items.length === 0) {
                    const emptyInfo = document.createElement('div');
                    emptyInfo.className = 'character-slot';
                    emptyInfo.style.cssText = `
                        display: flex;
                        align-items: center;
                        padding: 10px;
                        border: 1px solid var(--border-color);
                        border-radius: 0px;
                        height: 20px;
                        margin-bottom: 5px;
                        background-color: var(--bg-color);
                        cursor: default;
                    `;

                    const infoText = document.createElement('span');
                    infoText.textContent = `Group is empty`;
                    infoText.style.cssText = `
                        color: var(--text-color);
                    `;

                    emptyInfo.appendChild(infoText);
                    itemsContainer.appendChild(emptyInfo);
                } else {
                    group.items.forEach((character, charIndex) => {
                        const characterSlot = createCharacterSlot(character, groupIndex);
                        itemsContainer.appendChild(characterSlot);
                    });
                }
                groupContainer.appendChild(itemsContainer);
            } else {
                const collapsedInfo = document.createElement('div');
                collapsedInfo.className = 'character-slot';
                collapsedInfo.style.cssText = `
                    display: flex;
                    align-items: center;
                    padding: 10px;
                    margin-bottom: 10px;
                    border: 1px solid var(--border-color);
                    border-radius: 5px;
                    height: 20px;
                    margin-top: 5px;
                    background-color: var(--bg-color);
                    cursor: default;
                    margin-left: 10px;
                    margin-right: 10px;
                `;
                const infoText = document.createElement('span');
                infoText.textContent = `${group.items.length} items hidden`;

                //lime
                const activeCount = countActiveCharacters(group.items);
                const totalCount = countTotalCharacters(group.items);
                if (activeCount === totalCount && totalCount > 0) {
                    // All active
                    infoText.style.cssText = `color: rgba(36, 242, 0, 0.75);`;
                } else if (activeCount === 0) {
                    // All inactive
                    infoText.style.cssText = `color: var(--text-color-darker);`;
                } else {
                    // Mixed
                    infoText.style.cssText = `color: rgba(242, 198, 0, 0.75);`;
                }

                collapsedInfo.appendChild(infoText);
                groupContainer.appendChild(collapsedInfo);
            }

            // Add dragover and drop events for grouping
            groupContainer.addEventListener('dragover', (e) => {
                e.preventDefault();
                groupContainer.style.border = `2px dashed var(--info-bg-color)`;
            });

            groupContainer.addEventListener('dragleave', (e) => {
                groupContainer.style.border = `1px solid var(--border-color)`;
            });

            groupContainer.addEventListener('drop', (e) => {
                e.preventDefault();
                groupContainer.style.border = `1px solid var(--border-color)`;
                const data = e.dataTransfer.getData('text/plain');
                const { type, id } = JSON.parse(data);
                if (type === 'character') {
                    moveCharacterToGroup(id, groupIndex);
                }
            });

            characterGroupList.appendChild(groupContainer);
        });

        // Ensure at least one group exists
        if (characterGroups.length === 0) {
            characterGroups.push({ name: 'Ungrouped', items: [], collapsed: false });
            renderCharacterGroups();
        }
    }

    // Function to update the Toggle All Button appearance
    function updateToggleAllButton(button, group) {
        const activeCount = countActiveCharacters(group.items);
        const totalCount = countTotalCharacters(group.items);
        if (activeCount === totalCount && totalCount > 0) {
            // All active
            button.textContent = '🟢';
        } else if (activeCount === 0) {
            // All inactive
            button.textContent = '🔴';
        } else {
            // Mixed
            button.textContent = '🟡';
        }
    }

    function countActiveCharacters(items) {
        let count = 0;
        items.forEach(item => {
            if (item.active) count++;
            if (item.children && item.children.length > 0) {
                count += countActiveCharacters(item.children);
            }
        });
        return count;
    }

    function countTotalCharacters(items) {
        let count = items.length;
        items.forEach(item => {
            if (item.children && item.children.length > 0) {
                count += countTotalCharacters(item.children);
            }
        });
        return count;
    }

    // Function to toggle all characters in a group
    function toggleAllGroupCharacters(group) {
        const allActive = countActiveCharacters(group.items) === countTotalCharacters(group.items);
        toggleCharacters(group.items, !allActive);
    }

    function toggleCharacters(items, state) {
        items.forEach(item => {
            item.active = state;
            if (item.children && item.children.length > 0) {
                toggleCharacters(item.children, state);
            }
        });
    }

    // Function to generate tooltip content for a character
    function getCharacterTooltipContent(character, isRadial = false) {
        if (isRadial && character.emoji === '📁') {
            // If it's a group node in the radial tree, only show the name
            return `<strong>"${character.name}"</strong>`;
        }
        var content = `<strong>"${character.name}"</strong>`;

        if(character.characterType != 2){
            content += ` <small>(${character.sex || 'Unknown'}, ${character.species || 'Unknown'}, ${character.age || 'Unknown'}, ${character.bodyType || 'Unknown'}, ${character.personality || 'Unknown'})</small>`;
        }

        content += `:<br><em>"${character.bio || 'No bio available.'}"</em>`;
        return content;
    }

    // Function to create a Character Slot DOM element (recursive)
    function createCharacterSlot(character, groupIndex, parent = null, level = 0) {
        const characterSlot = document.createElement('div');
        characterSlot.className = 'character-slot';
        characterSlot.draggable = true;
        characterSlot.dataset.id = character.id;
        characterSlot.style.cssText = `
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 5px;
            margin-bottom: 5px;
            border: 1px solid var(--border-color);
            border-radius: 5px;
            background-color: ${character.characterType == 1 ? 'var(--active-char-color)' : 'var(--bg-color)'};
            cursor: grab;
            margin-left: ${level * 20}px;
        `;

        // Drag events
        characterSlot.addEventListener('dragstart', (e) => {
            e.stopPropagation();
            e.dataTransfer.setData('text/plain', JSON.stringify({ type: 'character', id: character.id }));
            e.currentTarget.style.opacity = '0.5';
        });

        characterSlot.addEventListener('dragend', (e) => {
            e.currentTarget.style.opacity = '1';
        });

        // Click event for collapsing/expanding
        if (character.children && character.children.length > 0) {
            characterSlot.style.cursor = 'pointer';
            characterSlot.addEventListener('click', (e) => {
                e.stopPropagation();
                character.collapsed = !character.collapsed;
                renderCharacterGroups();
            });
        }

        // Left Div (Active Toggle, Emoji, Name)
        const leftDiv = document.createElement('div');
        leftDiv.style.cssText = `
            display: flex;
            align-items: center;
            flex-grow: 1;
            overflow: hidden;
        `;

        // Remove Collapse/Expand Button
        // (Not needed as per new requirement)
        const activeButton = document.createElement('button');
        activeButton.textContent = character.active ? '🟢' : '🔴';
        activeButton.title = 'Toggle Active';
        activeButton.style.cssText = `
            padding: 3px;
            border: none;
            background: none;
            cursor: pointer;
            color: var(--text-color);
            margin-right: 5px;
        `;
        activeButton.addEventListener('click', (e) => {
            e.stopPropagation();
            character.active = !character.active;
            updateAllToggleButtons();
            renderCharacterGroups();
        });
        leftDiv.appendChild(activeButton);

        if(character.characterType == 2) {
            activeButton.style.display = 'none';
        }

        const emojiSpan = document.createElement('span');
        emojiSpan.textContent = character.emoji;
        emojiSpan.style.marginRight = '5px';
        leftDiv.appendChild(emojiSpan);

        const nameSpan = document.createElement('span');
        nameSpan.textContent = character.name;
        nameSpan.style.cssText = `
            flex-grow: 1;
            min-width: 0;
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
            color: var(--text-color);
        `;

        // Add tooltip event listeners
        nameSpan.addEventListener('mouseenter', (e) => {
            showTooltip(e, getCharacterTooltipContent(character), true);
        });
        nameSpan.addEventListener('mouseleave', hideTooltip);
        nameSpan.addEventListener('dragover', hideTooltip);

        leftDiv.appendChild(nameSpan);

        characterSlot.appendChild(leftDiv);

        // Right Div (Edit, Delete, Export)
        const rightDiv = document.createElement('div');
        rightDiv.style.display = 'flex';
        rightDiv.style.alignItems = 'center';

        const editButton = document.createElement('button');
        editButton.textContent = '✏️';
        editButton.title = 'Edit Character';
        editButton.style.cssText = `
            padding: 0px;
            border: none;
            background: none;
            cursor: pointer;
            color: var(--text-color);
            margin-right: 2px;
        `;
        editButton.addEventListener('click', (e) => {
            e.stopPropagation();
            editCharacter(character);
        });
        rightDiv.appendChild(editButton);

        const deleteButton = document.createElement('button');
        deleteButton.textContent = '🗑️';
        deleteButton.title = 'Delete Character';
        deleteButton.style.cssText = `
            padding: 0px;
            border: none;
            background: none;
            cursor: pointer;
            color: var(--text-color);
            margin-right: 2px;
        `;
        deleteButton.addEventListener('click', (e) => {
            e.stopPropagation();
            deleteCharacter(character.id);
        });
        rightDiv.appendChild(deleteButton);

        const exportButton = document.createElement('button');
        exportButton.textContent = '⬇️';
        exportButton.title = 'Export Character';
        exportButton.style.cssText = `
            padding: 0px;
            border: none;
            background: none;
            cursor: pointer;
            color: var(--text-color);
        `;
        exportButton.addEventListener('click', (e) => {
            e.stopPropagation();
            exportCharacter(character);
        });
        rightDiv.appendChild(exportButton);

        characterSlot.appendChild(rightDiv);

        // Dragover and Drop events
        characterSlot.addEventListener('dragover', (e) => {
            e.preventDefault();
            e.stopPropagation();
            characterSlot.style.border = `2px dashed var(--info-bg-color)`;
        });

        characterSlot.addEventListener('dragleave', (e) => {
            characterSlot.style.border = `1px solid var(--border-color)`;
        });

        characterSlot.addEventListener('drop', (e) => {
            e.preventDefault();
            e.stopPropagation();
            characterSlot.style.border = `1px solid var(--border-color)`;
            const data = e.dataTransfer.getData('text/plain');
            const { type, id } = JSON.parse(data);
            if (type === 'character' && id !== character.id) {
                moveCharacterToParent(id, character);
            }
        });

        // Prevent click on buttons from triggering slot collapse/expand
        activeButton.addEventListener('click', (e) => e.stopPropagation());
        editButton.addEventListener('click', (e) => e.stopPropagation());
        deleteButton.addEventListener('click', (e) => e.stopPropagation());
        exportButton.addEventListener('click', (e) => e.stopPropagation());

        // Recursive rendering of children
        const container = document.createElement('div');
        container.appendChild(characterSlot);

        if (character.children && character.children.length > 0) {
            if (!character.collapsed) {
                character.children.forEach(child => {
                    const childSlot = createCharacterSlot(child, groupIndex, character, level + 1);
                    container.appendChild(childSlot);
                });
            } else {
                const collapsedInfo = document.createElement('div');
                collapsedInfo.className = 'character-slot';
                collapsedInfo.style.cssText = `
                    display: flex;
                    align-items: center;
                    padding: 10px;
                    margin-bottom: 5px;
                    border: 1px solid var(--border-color);
                    border-radius: 5px;
                    background-color: var(--bg-color);
                    height: 20px;
                    cursor: default;
                    margin-left: ${(level + 1) * 20}px;
                `;

                const infoText = document.createElement('span');
                infoText.textContent = `${character.children.length} items hidden`;

                //lime
                const activeCount = countActiveCharacters(character.children);
                const totalCount = countTotalCharacters(character.children);
                if (activeCount === totalCount && totalCount > 0) {
                    // All active
                    infoText.style.cssText = `color: rgba(36, 242, 0, 0.75);`;
                } else if (activeCount === 0) {
                    // All inactive
                    infoText.style.cssText = `color: var(--text-color-darker);`;
                } else {
                    // Mixed
                    infoText.style.cssText = `color: rgba(242, 198, 0, 0.75);`;
                }

                collapsedInfo.appendChild(infoText);
                container.appendChild(collapsedInfo);
            }
        }

        return container;
    }

    function updateAllToggleButtons() {
        characterGroups.forEach((group, groupIndex) => {
            const toggleAllButton = toggleAllButtonForGroup(groupIndex);
            if (toggleAllButton) {
                updateToggleAllButton(toggleAllButton, group);
            }
        });
    }

    // Function to get the toggle all button for a group
    function toggleAllButtonForGroup(groupIndex) {
        const groupContainer = characterGroupList.children[groupIndex];
        if (groupContainer) {
            const toggleAllButton = groupContainer.querySelector('button[title="Activate/Deactivate All"]');
            return toggleAllButton;
        }
        return null;
    }

    // Function to rename a group
    function renameGroup(groupIndex) {
        const newName = prompt('Enter new group name:', characterGroups[groupIndex].name);
        if (newName && newName.trim() !== '') {
            characterGroups[groupIndex].name = newName.trim();
            renderCharacterGroups();
        }
    }

    // Function to delete a group
    function deleteGroup(groupIndex) {
        if (characterGroups.length === 1) {
            alert('At least one group must exist.');
            return;
        }
        if (confirm(`Are you sure you want to delete the group "${characterGroups[groupIndex].name}"? All characters in this group will be moved to "Ungrouped".`)) {
            const group = characterGroups.splice(groupIndex, 1)[0];
            const ungrouped = characterGroups.find(g => g.name === 'Ungrouped');
            if (ungrouped) {
                ungrouped.items = ungrouped.items.concat(group.items);
            } else {
                characterGroups.unshift({ name: 'Ungrouped', items: group.items, collapsed: false });
            }
            renderCharacterGroups();
        }
    }

    // Function to edit a character
    function editCharacter(character) {
        const editForm = document.createElement('form');
        editForm.innerHTML = `
    <div style="width: 100%; min-width: 500px; margin: 0 auto;">
        <label style="color: var(--text-color); font-size: 12px;">Emoji: <input type="text" name="emoji" value="${character.emoji}" autocomplete="off" style="background-color: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color); border-radius: 5px; padding: 5px; width: 100%; box-sizing: border-box;"></label><br>
        <label style="color: var(--text-color); font-size: 12px;">Name: <input type="text" name="name" value="${character.name}" autocomplete="off" style="background-color: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color); border-radius: 5px; padding: 5px; width: 100%; box-sizing: border-box;"></label><br>
        <label style="color: var(--text-color); font-size: 12px;">Sex: <input type="text" name="sex" value="${character.sex}" autocomplete="off" style="background-color: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color); border-radius: 5px; padding: 5px; width: 100%; box-sizing: border-box;"></label><br>
        <label style="color: var(--text-color); font-size: 12px;">Species: <input type="text" name="species" value="${character.species}" autocomplete="off" style="background-color: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color); border-radius: 5px; padding: 5px; width: 100%; box-sizing: border-box;"></label><br>
        <label style="color: var(--text-color); font-size: 12px;">Age: <input type="text" name="age" value="${character.age}" autocomplete="off" style="background-color: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color); border-radius: 5px; padding: 5px; width: 100%; box-sizing: border-box;"></label><br>
        <label style="color: var(--text-color); font-size: 12px;">Body Type: <input type="text" name="bodyType" value="${character.bodyType}" autocomplete="off" style="background-color: var(--bg-color); color: var (--text-color); border: 1px solid var(--border-color); border-radius: 5px; padding: 5px; width: 100%; box-sizing: border-box;"></label><br>
        <label style="color: var(--text-color); font-size: 12px;">Personality: <input type="text" name="personality" value="${character.personality}" autocomplete="off" style="background-color: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color); border-radius: 5px; padding: 5px; width: 100%; box-sizing: border-box;"></label><br>
        <label style="color: var(--text-color); font-size: 12px;">Bio: <textarea name="bio" autocomplete="off" rows="4" style="background-color: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color); border-radius: 5px; padding: 5px; width: 100%; box-sizing: border-box;">${character.bio}</textarea></label><br>
        <label style="color: var(--text-color); font-size: 12px;">Character Type:
            <select name="characterType" style="background-color: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color); border-radius: 5px; padding: 5px; width: 100%; box-sizing: border-box;">
                <option value="0" ${character.characterType === 0 ? 'selected' : ''}>Non-User</option>
                <option value="1" ${character.characterType === 1 ? 'selected' : ''}>User</option>
                <option value="2" ${character.characterType === 2 ? 'selected' : ''}>Collection</option>
            </select>
        </label><br>
        <button type="submit" style="background-color: var(--button-bg-color); color: var(--text-color); border: none; padding: 5px; border-radius: 5px; width: 100%; text-align: center; margin-top: 10px;">Save</button>
    </div>
    `;

        // Copy Tooltip button
        const copyButton = document.createElement('button');
        copyButton.textContent = '📋';
        copyButton.title = 'Copy Tooltip';
        copyButton.style.cssText = `
        position: absolute;
        top: 15px;
        right: 50px;
        background: none;
        border: none;
        font-size: 20px;
        cursor: pointer;
        color: var(--text-color);
    `;
        copyButton.addEventListener('click', () => {
            const tooltipContent = getCharacterTooltipContent(character);
            const textWithNewlines = tooltipContent.replace(/<br\s*\/?>/gi, '\n').replace(/<[^>]*>/g, '');
            navigator.clipboard.writeText(textWithNewlines);
        });
        editForm.appendChild(copyButton);

        const modal = createModal('Edit Character', editForm);
        editForm.addEventListener('submit', (e) => {
            e.preventDefault();
            character.emoji = editForm.emoji.value;
            character.name = editForm.name.value;
            character.sex = editForm.sex.value;
            character.species = editForm.species.value;
            character.age = editForm.age.value;
            character.bodyType = editForm.bodyType.value;
            character.personality = editForm.personality.value;
            character.bio = editForm.bio.value;
            character.characterType = parseInt(editForm.characterType.value, 10);
            renderCharacterGroups();
            closeModal(modal);
        });
    }

    // Function to delete a character
    function deleteCharacter(characterId) {
        if (confirm('Are you sure you want to delete this character?')) {
            characterGroups.forEach(group => {
                group.items = deleteCharacterRecursive(group.items, characterId);
            });
            renderCharacterGroups();
        }
    }

    function deleteCharacterRecursive(items, characterId) {
        return items.filter(item => {
            if (item.id === characterId) {
                return false;
            }
            if (item.children && item.children.length > 0) {
                item.children = deleteCharacterRecursive(item.children, characterId);
            }
            return true;
        });
    }

    // Function to export all characters with groups
    function exportCharacters() {
        const data = {
            characterGroups: characterGroups,
            settings: { c_radius, c_labelFontSize } // Save current settings
        };
        const json = JSON.stringify(data, null, 2);
        const blob = new Blob([json], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = url;
        link.download = `all_characters_with_groups.json`;
        link.click();
    }

    // Function to import characters with settings
    function importCharacters() {
        const fileInput = document.createElement('input');
        fileInput.type = 'file';
        fileInput.accept = '.json';
        fileInput.addEventListener('change', async (event) => {
            const file = event.target.files[0];
            const reader = new FileReader();
            reader.onload = (e) => {
                try {
                    const importedData = JSON.parse(e.target.result);
                    if (Array.isArray(importedData)) {
                        // Old format
                        characterGroups = importedData;
                        renderCharacterGroups();
                    } else if (importedData.characterGroups) {
                        characterGroups = importedData.characterGroups;

                        // Load settings
                        if (importedData.settings) {
                            // Assign settings
                            c_radius = importedData.settings.c_radius || c_radius;
                            c_labelFontSize = importedData.settings.c_labelFontSize || c_labelFontSize;
                        }

                        renderCharacterGroups();
                    } else {
                        alert('Invalid format for characters import.');
                    }
                } catch (error) {
                    alert('Failed to import characters: ' + error.message);
                }
            };
            reader.readAsText(file);
        });
        fileInput.click();
    }

    // Function to export a single character
    function exportCharacter(character) {
        const json = JSON.stringify(character, null, 2);
        const blob = new Blob([json], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = url;
        link.download = `${character.name}.json`;
        link.click();
    }

    // Function to move character to a group (uncoupling from parent)
    function moveCharacterToGroup(characterId, targetGroupIndex) {
        let character = null;
        // Remove character from current group or parent
        characterGroups.forEach(group => {
            group.items = removeCharacterRecursive(group.items, characterId, (item) => {
                character = item;
            });
        });
        // Add to target group
        if (character) {
            characterGroups[targetGroupIndex].items.push(character);
            renderCharacterGroups();
        }
    }

    function removeCharacterRecursive(items, characterId, callback) {
        return items.filter(item => {
            if (item.id === characterId) {
                callback(item);
                return false;
            }
            if (item.children && item.children.length > 0) {
                item.children = removeCharacterRecursive(item.children, characterId, callback);
            }
            return true;
        });
    }

    // Function to move character under another character (nesting)
    function moveCharacterToParent(characterId, parentCharacter) {
        let character = null;
        // Remove character from current group or parent
        characterGroups.forEach(group => {
            group.items = removeCharacterRecursive(group.items, characterId, (item) => {
                character = item;
            });
        });
        if (character) {
            parentCharacter.children.push(character);
            renderCharacterGroups();
        }
    }

    // Utility function to generate unique IDs
    function generateId() {
        return '_' + Math.random().toString(36).substr(2, 9);
    }

    // --- Location Sidebar with Groups and Nested Locations ---
    const locationSidebar = document.createElement('div');
    locationSidebar.id = 'location-sheet-sidebar';
    locationSidebar.style.cssText = `
        position: fixed;
        top: 0;
        left: -350px;
        width: 350px;
        height: 100%;
        display: flex;
        flex-direction: column;
        background-color: var(--bg-color);
        border-right: 2px solid var(--border-color);
        box-shadow: 2px 0 5px var(--shadow-color);
        box-sizing: border-box;
        transition: left 0.3s;
        z-index: 9999;
    `;
    document.body.appendChild(locationSidebar);

    const locationToggleButton = document.createElement('button');
    locationToggleButton.textContent = '☰';
    locationToggleButton.style.cssText = `
        position: fixed;
        top: 10px;
        left: 10px;
        padding: 5px 10px;
        border: none;
        background-color: var(--button-bg-color);
        color: var(--text-color);
        border-radius: 5px;
        cursor: pointer;
        transition: left 0.3s;
        z-index: 10000;
    `;
    locationToggleButton.addEventListener('click', () => {
        const isOpen = locationSidebar.style.left === '0px';
        locationSidebar.style.left = isOpen ? '-350px' : '0';
        locationToggleButton.style.left = isOpen ? '10px' : '360px';
    });
    document.body.appendChild(locationToggleButton);

    const locationHeader = document.createElement('div');
    locationHeader.style.cssText = `
        padding: 10px;
        background-color: var(--border-color);
        text-align: center;
        font-weight: bold;
        color: var(--text-color);
    `;
    locationHeader.textContent = 'Locations';
    locationSidebar.appendChild(locationHeader);

    const locationButtonBox = document.createElement('div');
    locationButtonBox.style.cssText = `
        display: flex;
        justify-content: space-between;
        padding: 10px;
        background-color: var(--bg-color);
        flex-shrink: 0;
    `;
    locationSidebar.appendChild(locationButtonBox);

    // New Location Button
    const newLocationButton = document.createElement('button');
    newLocationButton.textContent = 'New';
    newLocationButton.title = 'Create New Location';
    newLocationButton.style.cssText = `
        padding: 5px 10px;
        border: none;
        background-color: var(--success-bg-color);
        color: var(--text-color);
        border-radius: 5px;
        cursor: pointer;
    `;
    newLocationButton.addEventListener('click', () => {
        createNewLocation();
    });
    locationButtonBox.appendChild(newLocationButton);

    // Load Location Button
    const loadLocationButton = document.createElement('button');
    loadLocationButton.textContent = 'Load';
    loadLocationButton.title = 'Load a Location';
    loadLocationButton.style.cssText = `
        padding: 5px 10px;
        border: none;
        background-color: var(--info-bg-color);
        color: var(--text-color);
        border-radius: 5px;
        cursor: pointer;
    `;
    loadLocationButton.addEventListener('click', () => {
        loadLocation();
    });
    locationButtonBox.appendChild(loadLocationButton);

    // Group Location Button
    const groupLocationButton = document.createElement('button');
    groupLocationButton.textContent = 'Group';
    groupLocationButton.title = 'Create New Group';
    groupLocationButton.style.cssText = `
        padding: 5px 10px;
        border: none;
        background-color: var(--info-bg-color);
        color: var(--text-color);
        border-radius: 5px;
        cursor: pointer;
    `;
    groupLocationButton.addEventListener('click', () => {
        createNewLocationGroup();
    });
    locationButtonBox.appendChild(groupLocationButton);

    // Import Location Button
    const importLocationButton = document.createElement('button');
    importLocationButton.textContent = 'Import';
    importLocationButton.title = 'Import Locations';
    importLocationButton.style.cssText = `
        padding: 5px 10px;
        border: none;
        background-color: var(--warning-bg-color);
        color: var(--text-color);
        border-radius: 5px;
        cursor: pointer;
    `;
    importLocationButton.addEventListener('click', () => {
        importLocations();
    });
    locationButtonBox.appendChild(importLocationButton);

    // Export Location Button
    const exportLocationButton = document.createElement('button');
    exportLocationButton.textContent = 'Export';
    exportLocationButton.title = 'Export Locations';
    exportLocationButton.style.cssText = `
        padding: 5px 10px;
        border: none;
        background-color: var(--muted-bg-color);
        color: var(--text-color);
        border-radius: 5px;
        cursor: pointer;
    `;
    exportLocationButton.addEventListener('click', () => {
        exportLocations();
    });
    locationButtonBox.appendChild(exportLocationButton);

    // Add fifth button: "Load" for Location
    function loadLocation() {
        const fileInput = document.createElement('input');
        fileInput.type = 'file';
        fileInput.accept = '.json';
        fileInput.addEventListener('change', async (event) => {
            const file = event.target.files[0];
            const reader = new FileReader();
            reader.onload = (e) => {
                try {
                    const location = JSON.parse(e.target.result);
                    if (location && location.id) {
                        // Add to Ungrouped
                        const ungrouped = locationGroups.find(g => g.name === 'Ungrouped');
                        if (ungrouped) {
                            ungrouped.items.push(location);
                        } else {
                            locationGroups[0].items.push(location);
                        }
                        renderLocationGroups();
                        ensureActiveLocation();
                    } else {
                        alert('Invalid location format.');
                    }
                } catch (error) {
                    alert('Failed to load location: ' + error.message);
                }
            };
            reader.readAsText(file);
        });
        fileInput.click();
    }

    const locationGroupList = document.createElement('div');
    locationGroupList.id = 'location-group-list';
    locationGroupList.style.cssText = `
        flex-grow: 1;
        overflow-y: auto;
        padding: 10px;
    `;
    locationSidebar.appendChild(locationGroupList);

    // Initialize Location Groups with a single default location
    let locationGroups = [
        {
            name: 'Ungrouped',
            items: [
                {
                    id: generateId(),
                    active: true,
                    emoji: '📍',
                    name: 'Default Location',
                    description: 'Description of the default location.',
                    children: [],
                    collapsed: false
                }
            ],
            collapsed: false
        }
    ];

    // Function to create a new Location
    function createNewLocation() {
        const newLocation = {
            id: generateId(),
            active: false,
            emoji: '📍',
            name: 'New Location',
            description: '',
            children: [],
            collapsed: false
        };
        // Add to Ungrouped
        const ungrouped = locationGroups.find(g => g.name === 'Ungrouped');
        if (ungrouped) {
            ungrouped.items.push(newLocation);
        } else {
            locationGroups[0].items.push(newLocation);
        }
        renderLocationGroups();
        ensureActiveLocation();
    }

    // Function to create a new Location Group
    function createNewLocationGroup() {
        const groupName = prompt('Enter group name:', `Group ${locationGroups.length}`);
        if (groupName && groupName.trim() !== '') {
            locationGroups.push({ name: groupName.trim(), items: [], collapsed: false });
            renderLocationGroups();
        }
    }

    // Function to render Location Groups and Items
    function renderLocationGroups() {
        locationGroupList.innerHTML = '';

        locationGroups.forEach((group, groupIndex) => {
            // Sort items alphabetically by name
            group.items.sort((a, b) => a.name.localeCompare(b.name));

            const groupContainer = document.createElement('div');
            groupContainer.className = 'location-group';
            groupContainer.style.cssText = `
                margin-bottom: 10px;
                border: 1px solid var(--border-color);
                border-radius: 5px;
                background-color: var(--active-char-color);
            `;

            const groupHeader = document.createElement('div');
            groupHeader.style.cssText = `
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 5px 10px;
                background-color: var(--button-bg-color);
                color: var(--text-color);
                cursor: pointer;
                user-select: none;
                position: relative;
            `;
            groupHeader.textContent = group.name;
            groupHeader.addEventListener('click', () => {
                group.collapsed = !group.collapsed;
                renderLocationGroups();
            });

            const groupActions = document.createElement('div');
            groupActions.style.cssText = `
                display: flex;
                align-items: center;
            `;

            // Rename Group Button
            const renameGroupButton = document.createElement('button');
            renameGroupButton.textContent = '✏️';
            renameGroupButton.title = 'Rename Group';
            renameGroupButton.style.cssText = `
                background: none;
                border: none;
                color: var(--text-color);
                cursor: pointer;
                margin-right: 2px;
            `;
            renameGroupButton.addEventListener('click', (e) => {
                e.stopPropagation();
                renameLocationGroup(groupIndex);
            });
            groupActions.appendChild(renameGroupButton);

            // Delete Group Button
            const deleteGroupButton = document.createElement('button');
            deleteGroupButton.textContent = '🗑️';
            deleteGroupButton.title = 'Delete Group';
            deleteGroupButton.style.cssText = `
                background: none;
                border: none;
                color: var(--text-color);
                cursor: pointer;
            `;
            deleteGroupButton.addEventListener('click', (e) => {
                e.stopPropagation();
                deleteLocationGroup(groupIndex);
            });
            groupActions.appendChild(deleteGroupButton);

            groupHeader.appendChild(groupActions);
            groupContainer.appendChild(groupHeader);

            if (!group.collapsed) {
                const itemsContainer = document.createElement('div');
                itemsContainer.style.cssText = `
                    padding: 5px 10px;
                    display: block;
                `;
                if (group.items.length === 0) {
                    const emptyInfo = document.createElement('div');
                    emptyInfo.className = 'location-slot';
                    emptyInfo.style.cssText = `
                        display: flex;
                        align-items: center;
                        padding: 10px;
                        margin-bottom: 5px;
                        border: 1px solid var(--border-color);
                        border-radius: 5px;
                        height: 20px;
                        background-color: var(--bg-color);
                        cursor: default;
                    `;

                    const infoText = document.createElement('span');
                    infoText.textContent = `Group is empty`;
                    infoText.style.cssText = `
                        color: var(--text-color);
                    `;

                    emptyInfo.appendChild(infoText);
                    itemsContainer.appendChild(emptyInfo);
                } else {
                    group.items.forEach((location) => {
                        const locationSlot = createLocationSlot(location, groupIndex);
                        itemsContainer.appendChild(locationSlot);
                    });
                }
                groupContainer.appendChild(itemsContainer);
            } else {
                const collapsedInfo = document.createElement('div');
                collapsedInfo.className = 'location-slot';
                collapsedInfo.style.cssText = `
                    display: flex;
                    align-items: center;
                    padding: 10px;
                    margin-bottom: 10px;
                    border: 1px solid var(--border-color);
                    border-radius: 5px;
                    height: 20px;
                    margin-top: 5px;
                    background-color: var(--bg-color);
                    cursor: default;
                    margin-left: 10px;
                    margin-right: 10px;
                `;
                const infoText = document.createElement('span');
                infoText.textContent = `${group.items.length} items hidden`;

                //lime
                if (findActiveLocation(group.items)) {
                    // All active
                    infoText.style.cssText = `color: rgba(36, 242, 0, 0.75);`;
                } else {
                    // All inactive
                    infoText.style.cssText = `color: var(--text-color-darker);`;
                }

                collapsedInfo.appendChild(infoText);
                groupContainer.appendChild(collapsedInfo);
            }

            // Add dragover and drop events for grouping
            groupContainer.addEventListener('dragover', (e) => {
                e.preventDefault();
                groupContainer.style.border = `2px dashed var(--info-bg-color)`;
            });

            groupContainer.addEventListener('dragleave', (e) => {
                groupContainer.style.border = `1px solid var(--border-color)`;
            });

            groupContainer.addEventListener('drop', (e) => {
                e.preventDefault();
                groupContainer.style.border = `1px solid var(--border-color)`;
                const data = e.dataTransfer.getData('text/plain');
                const { type, id } = JSON.parse(data);
                if (type === 'location') {
                    moveLocationToGroup(id, groupIndex);
                }
            });

            locationGroupList.appendChild(groupContainer);
        });

        // Ensure at least one group exists
        if (locationGroups.length === 0) {
            locationGroups.push({ name: 'Ungrouped', items: [], collapsed: false });
            renderLocationGroups();
        }

        // Ensure at least one location is active
        ensureActiveLocation();
    }

    // Function to generate tooltip content for a location
    function getLocationTooltipContent(location, isRadial = false) {
        if (isRadial && location.emoji === '📁') {
            // If it's a group node in the radial tree, only show the name
            return `<strong>"${location.name}"</strong>`;
        }
        let content = `<strong>"${location.name}"</strong>:<br><em>"${location.description || 'No description available.'}"</em>`;
        return content;
    }

    // Function to create a Location Slot DOM element (recursive)
    function createLocationSlot(location, groupIndex, parent = null, level = 0) {
        const locationSlot = document.createElement('div');
        locationSlot.className = 'location-slot';
        locationSlot.draggable = true;
        locationSlot.dataset.id = location.id;
        locationSlot.style.cssText = `
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 5px;
            margin-bottom: 5px;
            border: 1px solid var(--border-color);
            border-radius: 5px;
            background-color: var(--bg-color);
            cursor: grab;
            margin-left: ${level * 20}px;
        `;

        // Drag events
        locationSlot.addEventListener('dragstart', (e) => {
            e.stopPropagation();
            e.dataTransfer.setData('text/plain', JSON.stringify({ type: 'location', id: location.id }));
            e.currentTarget.style.opacity = '0.5';
        });

        locationSlot.addEventListener('dragend', (e) => {
            e.currentTarget.style.opacity = '1';
        });

        // Click event for collapsing/expanding
        if (location.children && location.children.length > 0) {
            locationSlot.style.cursor = 'pointer';
            locationSlot.addEventListener('click', (e) => {
                e.stopPropagation();
                location.collapsed = !location.collapsed;
                renderLocationGroups();
            });
        }

        // Left Div (Active Toggle, Emoji, Name)
        const leftDiv = document.createElement('div');
        leftDiv.style.cssText = `
            display: flex;
            align-items: center;
            flex-grow: 1;
            overflow: hidden;
        `;

        // Remove Collapse/Expand Button
        // (Not needed as per new requirement)

        const activeButton = document.createElement('button');
        activeButton.textContent = location.active ? '🟢' : '🔴';
        activeButton.title = 'Toggle Active';
        activeButton.style.cssText = `
            padding: 3px;
            border: none;
            background: none;
            cursor: pointer;
            color: var(--text-color);
            margin-right: 5px;
        `;
        activeButton.addEventListener('click', (e) => {
            e.stopPropagation();
            // Since only one active location is allowed, deactivate others
            locationGroups.forEach(group => {
                group.items.forEach(loc => {
                    deactivateLocationRecursive(loc);
                });
            });
            location.active = !location.active;
            renderLocationGroups();
        });
        leftDiv.appendChild(activeButton);

        const emojiSpan = document.createElement('span');
        emojiSpan.textContent = location.emoji;
        emojiSpan.style.marginRight = '5px';
        leftDiv.appendChild(emojiSpan);

        const nameSpan = document.createElement('span');
        nameSpan.textContent = location.name;
        nameSpan.style.cssText = `
            flex-grow: 1;
            min-width: 0;
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
            color: var(--text-color);
        `;

        // Add tooltip event listeners
        nameSpan.addEventListener('mouseenter', (e) => {
            showTooltip(e, getLocationTooltipContent(location));
        });
        nameSpan.addEventListener('mouseleave', hideTooltip);
        nameSpan.addEventListener('dragover', hideTooltip);

        leftDiv.appendChild(nameSpan);

        locationSlot.appendChild(leftDiv);

        // Right Div (Edit, Delete, Export)
        const rightDiv = document.createElement('div');
        rightDiv.style.display = 'flex';
        rightDiv.style.alignItems = 'center';

        const editButton = document.createElement('button');
        editButton.textContent = '✏️';
        editButton.title = 'Edit Location';
        editButton.style.cssText = `
            padding: 0px;
            border: none;
            background: none;
            cursor: pointer;
            color: var(--text-color);
            margin-right: 2px;
        `;
        editButton.addEventListener('click', (e) => {
            e.stopPropagation();
            editLocation(location);
        });
        rightDiv.appendChild(editButton);

        const deleteButton = document.createElement('button');
        deleteButton.textContent = '🗑️';
        deleteButton.title = 'Delete Location';
        deleteButton.style.cssText = `
            padding: 0px;
            border: none;
            background: none;
            cursor: pointer;
            color: var(--text-color);
            margin-right: 2px;
        `;
        deleteButton.addEventListener('click', (e) => {
            e.stopPropagation();
            deleteLocation(location.id);
        });
        rightDiv.appendChild(deleteButton);

        const exportButton = document.createElement('button');
        exportButton.textContent = '⬇️';
        exportButton.title = 'Export Location';
        exportButton.style.cssText = `
            padding: 0px;
            border: none;
            background: none;
            cursor: pointer;
            color: var(--text-color);
        `;
        exportButton.addEventListener('click', (e) => {
            e.stopPropagation();
            exportLocation(location);
        });
        rightDiv.appendChild(exportButton);

        locationSlot.appendChild(rightDiv);

        // Dragover and Drop events
        locationSlot.addEventListener('dragover', (e) => {
            e.preventDefault();
            e.stopPropagation();
            locationSlot.style.border = `2px dashed var(--info-bg-color)`;
        });

        locationSlot.addEventListener('dragleave', (e) => {
            locationSlot.style.border = `1px solid var(--border-color)`;
        });

        locationSlot.addEventListener('drop', (e) => {
            e.preventDefault();
            e.stopPropagation();
            locationSlot.style.border = `1px solid var(--border-color)`;
            const data = e.dataTransfer.getData('text/plain');
            const { type, id } = JSON.parse(data);
            if (type === 'location' && id !== location.id) {
                moveLocationToParent(id, location);
            }
        });

        // Prevent click on buttons from triggering slot collapse/expand
        activeButton.addEventListener('click', (e) => e.stopPropagation());
        editButton.addEventListener('click', (e) => e.stopPropagation());
        deleteButton.addEventListener('click', (e) => e.stopPropagation());
        exportButton.addEventListener('click', (e) => e.stopPropagation());

        // Recursive rendering of children
        const container = document.createElement('div');
        container.appendChild(locationSlot);

        if (location.children && location.children.length > 0) {
            if (!location.collapsed) {
                location.children.forEach(child => {
                    const childSlot = createLocationSlot(child, groupIndex, location, level + 1);
                    container.appendChild(childSlot);
                });
            } else {
                const collapsedInfo = document.createElement('div');
                collapsedInfo.className = 'location-slot';
                collapsedInfo.style.cssText = `
                    display: flex;
                    align-items: center;
                    padding: 10px;
                    margin-bottom: 5px;
                    border: 1px solid var(--border-color);
                    border-radius: 5px;
                    background-color: var(--bg-color);
                    height: 20px;
                    cursor: default;
                    margin-left: ${(level + 1) * 20}px;
                `;

                const infoText = document.createElement('span');
                infoText.textContent = `${location.children.length} items hidden`;

                //lime
                if (findActiveLocation(location.children)) {
                    // All active
                    infoText.style.cssText = `color: rgba(36, 242, 0, 0.75);`;
                } else {
                    // All inactive
                    infoText.style.cssText = `color: var(--text-color-darker);`;
                }

                collapsedInfo.appendChild(infoText);
                container.appendChild(collapsedInfo);
            }
        }

        return container;
    }

    function deactivateLocationRecursive(location) {
        location.active = false;
        if (location.children && location.children.length > 0) {
            location.children.forEach(child => {
                deactivateLocationRecursive(child);
            });
        }
    }

    // Function to rename a location group
    function renameLocationGroup(groupIndex) {
        const newName = prompt('Enter new group name:', locationGroups[groupIndex].name);
        if (newName && newName.trim() !== '') {
            locationGroups[groupIndex].name = newName.trim();
            renderLocationGroups();
        }
    }

    // Function to delete a location group
    function deleteLocationGroup(groupIndex) {
        if (locationGroups.length === 1) {
            alert('At least one group must exist.');
            return;
        }
        if (confirm(`Are you sure you want to delete the group "${locationGroups[groupIndex].name}"? All locations in this group will be moved to "Ungrouped".`)) {
            const group = locationGroups.splice(groupIndex, 1)[0];
            const ungrouped = locationGroups.find(g => g.name === 'Ungrouped');
            if (ungrouped) {
                ungrouped.items = ungrouped.items.concat(group.items);
            } else {
                locationGroups.unshift({ name: 'Ungrouped', items: group.items, collapsed: false });
            }
            renderLocationGroups();
        }
    }

    // Function to edit a location
    function editLocation(location) {
        const editForm = document.createElement('form');
        editForm.innerHTML = `
        <div style="width: 100%; min-width: 500px; margin: 0 auto;">
            <label style="color: var(--text-color); font-size: 12px;">Emoji: <input type="text" name="emoji" value="${location.emoji}" autocomplete="off" style="background-color: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color); border-radius: 5px; padding: 5px; width: 100%; box-sizing: border-box;"></label><br>
            <label style="color: var(--text-color); font-size: 12px;">Name: <input type="text" name="name" value="${location.name}" autocomplete="off" style="background-color: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color); border-radius: 5px; padding: 5px; width: 100%; box-sizing: border-box;"></label><br>
            <label style="color: var(--text-color); font-size: 12px;">Description: <textarea name="description" autocomplete="off" rows="4" style="background-color: var(--bg-color); color: var(--text-color); border: 1px solid var(--border-color); border-radius: 5px; padding: 5px; width: 100%; box-sizing: border-box;">${location.description}</textarea></label><br>
            <button type="submit" style="background-color: var(--button-bg-color); color: var(--text-color); border: none; padding: 5px; border-radius: 5px; width: 100%; text-align: center; margin-top: 10px;">Save</button>
        </div>
    `;

        // Copy Tooltip button
        const copyButton = document.createElement('button');
        copyButton.textContent = '📋';
        copyButton.title = 'Copy Tooltip';
        copyButton.style.cssText = `
        position: absolute;
        top: 15px;
        right: 50px;
        background: none;
        border: none;
        font-size: 20px;
        cursor: pointer;
        color: var(--text-color);
    `;
        copyButton.addEventListener('click', () => {
            const tooltipContent = getLocationTooltipContent(location);
            const textWithNewlines = tooltipContent.replace(/<br\s*\/?>/gi, '\n').replace(/<[^>]*>/g, '');
            navigator.clipboard.writeText(textWithNewlines);
        });
        editForm.appendChild(copyButton);

        const modal = createModal('Edit Location', editForm);
        editForm.addEventListener('submit', (e) => {
            e.preventDefault();
            location.emoji = editForm.emoji.value;
            location.name = editForm.name.value;
            location.description = editForm.description.value;
            renderLocationGroups();
            ensureActiveLocation();
            closeModal(modal);
        });
    }

    // Function to delete a location
    function deleteLocation(locationId) {
        if (confirm('Are you sure you want to delete this location?')) {
            locationGroups.forEach(group => {
                group.items = deleteLocationRecursive(group.items, locationId);
            });
            renderLocationGroups();
            ensureActiveLocation();
        }
    }

    function deleteLocationRecursive(items, locationId) {
        return items.filter(item => {
            if (item.id === locationId) {
                return false;
            }
            if (item.children && item.children.length > 0) {
                item.children = deleteLocationRecursive(item.children, locationId);
            }
            return true;
        });
    }

    // Function to export all locations with groups
    function exportLocations() {
        const data = {
            locationGroups: locationGroups,
            settings: { l_radius, l_labelFontSize } // Save current settings
        };
        const json = JSON.stringify(data, null, 2);
        const blob = new Blob([json], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = url;
        link.download = `all_locations_with_groups.json`;
        link.click();
    }

    // Function to import locations with groups
    function importLocations() {
        const fileInput = document.createElement('input');
        fileInput.type = 'file';
        fileInput.accept = '.json';
        fileInput.addEventListener('change', async (event) => {
            const file = event.target.files[0];
            const reader = new FileReader();
            reader.onload = (e) => {
            try {
                const importedData = JSON.parse(e.target.result);
                if (Array.isArray(importedData)) {
                    // Old format
                    locationGroups = importedData;
                    renderLocationGroups();
                } else if (importedData.locationGroups) {
                    locationGroups = importedData.locationGroups;

                    // Load settings
                    if (importedData.settings) {
                        // Assign settings
                        l_radius = importedData.settings.l_radius || l_radius;
                        l_labelFontSize = importedData.settings.l_labelFontSize || l_labelFontSize;
                    }

                    renderLocationGroups();
                } else {
                    alert('Invalid format for characters import.');
                }
            } catch (error) {
                alert('Failed to import characters: ' + error.message);
            }
        };
            reader.readAsText(file);
        });
        fileInput.click();
    }

    // Function to export a single location
    function exportLocation(location) {
        const json = JSON.stringify(location, null, 2);
        const blob = new Blob([json], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = url;
        link.download = `${location.name}.json`;
        link.click();
    }

    // Function to move location to a group (uncoupling from parent)
    function moveLocationToGroup(locationId, targetGroupIndex) {
        let location = null;
        // Remove location from current group or parent
        locationGroups.forEach(group => {
            group.items = removeLocationRecursive(group.items, locationId, (item) => {
                location = item;
            });
        });
        // Add to target group
        if (location) {
            locationGroups[targetGroupIndex].items.push(location);
            renderLocationGroups();
            ensureActiveLocation();
        }
    }

    function removeLocationRecursive(items, locationId, callback) {
        return items.filter(item => {
            if (item.id === locationId) {
                callback(item);
                return false;
            }
            if (item.children && item.children.length > 0) {
                item.children = removeLocationRecursive(item.children, locationId, callback);
            }
            return true;
        });
    }

    // Function to move location under another location (nesting)
    function moveLocationToParent(locationId, parentLocation) {
        let location = null;
        // Remove location from current group or parent
        locationGroups.forEach(group => {
            group.items = removeLocationRecursive(group.items, locationId, (item) => {
                location = item;
            });
        });
        if (location) {
            if(parentLocation.children == undefined){
               parentLocation.children = [];
            }
            parentLocation.children.push(location);
            renderLocationGroups();
            ensureActiveLocation();
        }
    }

    // Function to create a modal
    function createModal(title, content) {
        const modalOverlay = document.createElement('div');
        modalOverlay.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0,0,0,0.5);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 10002;
        `;

        const modalBox = document.createElement('div');
        modalBox.style.cssText = `
            background-color: var(--bg-color);
            padding: 20px;
            border: 1px solid var(--border-color);
            border-radius: 5px;
            width: fit-content;
            min-width: 500px;
            max-width: 90%;
            box-shadow: 0 0 10px var(--shadow-color);
            position: relative;
        `;

        const modalTitle = document.createElement('h2');
        modalTitle.textContent = title;
        modalTitle.style.cssText = `
            margin-top: 0;
            color: var(--text-color);
        `;
        modalBox.appendChild(modalTitle);

        const closeButton = document.createElement('button');
        closeButton.textContent = '✖️';
        closeButton.style.cssText = `
            position: absolute;
            top: 15px;
            right: 20px;
            background: none;
            border: none;
            font-size: 20px;
            cursor: pointer;
            color: var(--text-color);
        `;
        closeButton.addEventListener('click', () => {
            closeModal(modalOverlay);
        });
        modalBox.appendChild(closeButton);

        modalBox.appendChild(content);
        modalOverlay.appendChild(modalBox);
        document.body.appendChild(modalOverlay);

        return modalOverlay;
    }

    // Function to close a modal
    function closeModal(modal) {
        if (modal && modal.parentNode) {
            modal.parentNode.removeChild(modal);
        }
    }

    // Function to ensure at least one location is active
    function ensureActiveLocation() {
        const activeLocations = [];
        locationGroups.forEach(group => {
            group.items.forEach(loc => {
                collectActiveLocations(loc, activeLocations);
            });
        });
        if (activeLocations.length === 0 && locationGroups.flatMap(g => g.items).length > 0) {
            locationGroups[0].items[0].active = true;
        }
    }

    function collectActiveLocations(location, activeLocations) {
        if (location.active) {
            activeLocations.push(location);
        }
        if (location.children && location.children.length > 0) {
            location.children.forEach(child => {
                collectActiveLocations(child, activeLocations);
            });
        }
    }

    // Initial render of Character and Location Groups
    renderCharacterGroups();
    renderLocationGroups();

    // --- Plot Field ---
    const plotDiv = document.createElement('div');
    plotDiv.style.cssText = `
        display: flex;
        justify-content: space-between;
        padding: 10px;
        background-color: var(--bg-color);
        border-top: 1px solid var(--border-color);
        flex-shrink: 0;
    `;
    const plotInput = document.createElement('input');
    plotInput.type = 'text';
    plotInput.placeholder = 'Plot';
    plotInput.style.cssText = `
        width: 100%;
        padding: 5px;
        border: 1px solid var(--border-color);
        border-radius: 5px;
        background-color: var(--bg-color);
        color: var(--text-color);
        box-sizing: border-box;
    `;
    plotDiv.appendChild(plotInput);
    characterSidebar.appendChild(plotDiv);

    // --- Location Context Inputs ---
    const globalInputs = document.createElement('div');
    globalInputs.style.cssText = `
        display: flex;
        justify-content: space-between;
        padding: 10px;
        background-color: var(--bg-color);
        border-top: 1px solid var(--border-color);
        flex-shrink: 0;
    `;
    locationSidebar.appendChild(globalInputs);

    const timeInput = document.createElement('input');
    timeInput.type = 'text';
    timeInput.placeholder = 'Time';
    timeInput.style.cssText = `
        width: calc(50% - 5px);
        padding: 5px;
        border: 1px solid var(--border-color);
        border-radius: 5px;
        background-color: var(--bg-color);
        color: var(--text-color);
    `;
    globalInputs.appendChild(timeInput);

    const weatherInput = document.createElement('input');
    weatherInput.type = 'text';
    weatherInput.placeholder = 'Weather';
    weatherInput.style.cssText = `
        width: calc(50% - 5px);
        padding: 5px;
        border: 1px solid var(--border-color);
        border-radius: 5px;
        background-color: var(--bg-color);
        color: var(--text-color);
    `;
    globalInputs.appendChild(weatherInput);

    // Initial render of transparency and theme settings
    transparencySlider.value = defaultTransparency;
    themeDropdown.value = defaultTheme;

    // Load D3.js library
    await new Promise((resolve, reject) => {
        const d3Script = document.createElement('script');
        d3Script.src = 'https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.4/d3.min.js';
        d3Script.onload = resolve;
        d3Script.onerror = reject;
        document.head.appendChild(d3Script);
    });

    // --- Modifications Start Here ---

    // Variables to keep track of open windows
    let radialTreeOpen = false;
    let searchPanelOpen = { character: false, location: false };

    // Helper function to find an item by ID
    function findItemById(groups, id) {
        let result = null;
        for (let group of groups) {
            if (group.id === id) {
                return group;
            }
            if (group.items) {
                result = findItemInItems(group.items, id);
                if (result) {
                    return result;
                }
            }
        }
        return null;
    }

    function findItemInItems(items, id) {
        for (let item of items) {
            if (item.id === id) {
                return item;
            } else if (item.children && item.children.length > 0) {
                let found = findItemInItems(item.children, id);
                if (found) return found;
            }
        }
        return null;
    }

    function findGroupIndexByName(groups, name) {
        for (let i = 0; i < groups.length; i++) {
            if (groups[i].name === name) {
                return i;
            }
        }
        return null;
    }

    // Helper function to remove an item by ID
    function removeItemById(groups, id) {
        for (let group of groups) {
            if (group.items) {
                group.items = removeItemFromItems(group.items, id);
            }
        }
    }

    function removeItemFromItems(items, id) {
        return items.filter(item => {
            if (item.id === id) {
                return false;
            } else if (item.children && item.children.length > 0) {
                item.children = removeItemFromItems(item.children, id);
            }
            return true;
        });
    }

    // Helper function to check for circular references
    function isAncestor(itemId, possibleAncestorId, type) {
        let targetItem = null;
        if (type === 'character') {
            targetItem = findItemById(characterGroups, itemId);
        } else {
            targetItem = findItemById(locationGroups, itemId);
        }

        if (!targetItem) return false;

        function searchChildren(item) {
            if (item.id === possibleAncestorId) {
                return true;
            }
            if (item.children && item.children.length > 0) {
                for (let child of item.children) {
                    if (searchChildren(child)) {
                        return true;
                    }
                }
            }
            if (item.items && item.items.length > 0) {
                for (let child of item.items) {
                    if (searchChildren(child)) {
                        return true;
                    }
                }
            }
            return false;
        }

        return searchChildren(targetItem);
    }

    // Function to create a radial tree visualization
    function createRadialTree(data, type) {
        // Variables to store settings and use them globally
        let c_radius = type === 'character' ? (window.c_radius || 300) : 300;
        let c_labelFontSize = type === 'character' ? (window.c_labelFontSize || 12) : 12;
        let c_nodeSize = type === 'character' ? (window.c_nodeSize || 24) : 24;
        let l_radius = type === 'location' ? (window.l_radius || 300) : 300;
        let l_labelFontSize = type === 'location' ? (window.l_labelFontSize || 12) : 12;
        let l_nodeSize = type === 'location' ? (window.l_nodeSize || 24) : 24;

        ItemTransferTarget = null;

        // Close any existing radial tree window
        if (document.getElementById('radial-tree-window')) {
            document.body.removeChild(document.getElementById('radial-tree-window'));
        }

        // Create the movable window container
        const windowContainer = document.createElement('div');
        windowContainer.id = 'radial-tree-window';
        windowContainer.style.cssText = `
        position: fixed;
        top: 100px;
        left: 100px;
        width: 600px;
        height: 600px;
        background-color: var(--bg-color);
        border: 1px solid var(--border-color);
        box-shadow: 0 0 10px var(--shadow-color);
        border-radius: 5px;
        z-index: 10002;
        display: flex;
        flex-direction: column;
    `;

        // Add a header with the title and buttons
        const header = document.createElement('div');
        header.style.cssText = `
        display: flex;
        align-items: center;
        padding: 5px;
        background-color: var(--button-bg-color);
        color: var(--text-color);
        cursor: move;
    `;

        const title = document.createElement('span');
        title.textContent = `${type === 'character' ? 'Character' : 'Location'} Radial Tree`;
        title.style.flexGrow = '1';
        header.appendChild(title);

        const buttonContainer = document.createElement('div');
        buttonContainer.style.display = 'flex';
        buttonContainer.style.alignItems = 'center';

        // New Refresh Button
        const NItemButton = document.createElement('button');
        NItemButton.textContent = '📝';
        NItemButton.title = 'New Item';
        NItemButton.style.cssText = `
        background: none;
        border: none;
        color: var(--text-color);
        cursor: pointer;
        margin-right: 5px;
    `;
        buttonContainer.appendChild(NItemButton);

        NItemButton.addEventListener('click', () => {
            if(type === 'character'){createNewCharacter();}else{createNewLocation();}
            ItemTransferTarget = null;
            refreshTree(svgContainer, data, type);
        });

        // New Refresh Button
        const NGroupButton = document.createElement('button');
        NGroupButton.textContent = '🗄️';
        NGroupButton.title = 'New Group';
        NGroupButton.style.cssText = `
        background: none;
        border: none;
        color: var(--text-color);
        cursor: pointer;
        margin-right: 5px;
    `;
        buttonContainer.appendChild(NGroupButton);

        NGroupButton.addEventListener('click', () => {
            if(type === 'character'){createNewCharacterGroup();}else{createNewLocationGroup();}
            ItemTransferTarget = null;
            refreshTree(svgContainer, data, type);
        });

        // New Refresh Button
        const refreshButton = document.createElement('button');
        refreshButton.textContent = '🔄';
        refreshButton.title = 'Refresh Tree';
        refreshButton.style.cssText = `
        background: none;
        border: none;
        color: var(--text-color);
        cursor: pointer;
        margin-right: 5px;
    `;
        buttonContainer.appendChild(refreshButton);

        // Settings Button
        const settingsButton = document.createElement('button');
        settingsButton.textContent = '⚙️';
        settingsButton.title = 'Settings';
        settingsButton.style.cssText = `
        background: none;
        border: none;
        color: var(--text-color);
        cursor: pointer;
        margin-right: 5px;
    `;
        buttonContainer.appendChild(settingsButton);

        // Close Button
        const closeButton = document.createElement('button');
        closeButton.textContent = '✖️';
        closeButton.style.cssText = `
        background: none;
        border: none;
        color: var(--text-color);
        cursor: pointer;
    `;
        closeButton.addEventListener('click', () => {
            document.body.removeChild(windowContainer);
            radialTreeOpen = false;
            ItemTransferTarget = null;
        });
        buttonContainer.appendChild(closeButton);

        header.appendChild(buttonContainer);
        windowContainer.appendChild(header);

        // Create SVG container
        const svgContainer = document.createElement('div');
        svgContainer.style.cssText = `
        flex-grow: 1;
        width: 100%;
        background-color: var(--bg-color);
        overflow: hidden;
        position: relative;
    `;
        windowContainer.appendChild(svgContainer);

        // Append to body
        document.body.appendChild(windowContainer);
        radialTreeOpen = true;

        // Make window draggable
        makeElementDraggable(windowContainer, header);

        // Create settings panel
        const settingsPanel = document.createElement('div');
        settingsPanel.style.cssText = `
        position: absolute;
        top: 50px;
        right: 10px;
        width: 200px;
        background-color: var(--bg-color);
        border: 1px solid var(--border-color);
        box-shadow: 0 0 10px var(--shadow-color);
        border-radius: 5px;
        padding: 10px;
        z-index: 10003;
        display: none;
    `;
        settingsPanel.innerHTML = `
        <label style="color: var(--text-color);">Node Distance: <input type="range" min="100" max="1000" value="${type === 'character' ? c_radius : l_radius}" id="nodeDistanceSlider" style="width: 100%;"></label>
        <label style="color: var(--text-color);">Label Size: <input type="range" min="8" max="24" value="${type === 'character' ? c_labelFontSize : l_labelFontSize}" id="labelSizeSlider" style="width: 100%;"></label>
        <label style="color: var(--text-color);">Node Size: <input type="range" min="8" max="48" value="${type === 'character' ? c_nodeSize : l_nodeSize}" id="nodeSizeSlider" style="width: 100%;"></label>
        <button id="applySettingsButton" style="margin-top: 10px; width: 100%;">Apply</button>
    `;
        windowContainer.appendChild(settingsPanel);

        settingsButton.addEventListener('click', () => {
            settingsPanel.style.display = settingsPanel.style.display === 'none' ? 'block' : 'none';
            ItemTransferTarget = null;
            refreshTree(svgContainer, data, type);
        });

        const nodeDistanceSlider = settingsPanel.querySelector('#nodeDistanceSlider');
        const labelSizeSlider = settingsPanel.querySelector('#labelSizeSlider');
        const nodeSizeSlider = settingsPanel.querySelector('#nodeSizeSlider');
        const applySettingsButton = settingsPanel.querySelector('#applySettingsButton');

        applySettingsButton.addEventListener('click', () => {
            if (type === 'character') {
                window.c_radius = parseInt(nodeDistanceSlider.value, 10);
                window.c_labelFontSize = parseInt(labelSizeSlider.value, 10);
                window.c_nodeSize = parseInt(nodeSizeSlider.value, 10);
            } else {
                window.l_radius = parseInt(nodeDistanceSlider.value, 10);
                window.l_labelFontSize = parseInt(labelSizeSlider.value, 10);
                window.l_nodeSize = parseInt(nodeSizeSlider.value, 10);
            }

            settingsPanel.style.display = 'none';

            // Regenerate the tree with new settings
            generateRadialTreeVisualization(svgContainer, data, type, type === 'character' ? window.c_radius : window.l_radius, type === 'character' ? window.c_labelFontSize : window.l_labelFontSize, type === 'character' ? window.c_nodeSize : window.l_nodeSize);
        });

        // Add event listener to refresh button
        refreshButton.addEventListener('click', () => {
            ItemTransferTarget = null;
            refreshTree(svgContainer, data, type);
        });

        // Initial rendering of the tree
        generateRadialTreeVisualization(svgContainer, data, type, type === 'character' ? c_radius : l_radius, type === 'character' ? c_labelFontSize : l_labelFontSize, type === 'character' ? c_nodeSize : l_nodeSize);
    }

    function refreshTree(container, data, type) {
        // Clear the existing SVG container (to remove the old tree)
        container.innerHTML = '';

        // Re-use the same data, or if necessary, fetch new data here
        const structuredData = structureData(type === 'character' ? characterGroups : locationGroups);

        // Store the current zoom, pan, and rotation before refresh
        const currentTransform = window.currentTransform || { x: container.clientWidth / 2, y: container.clientHeight / 2, k: 1 };
        const currentRotation = window.currentRotation || 0;

        // Regenerate the tree visualization with the existing settings
        const radius = type === 'character' ? window.c_radius : window.l_radius;
        const labelFontSize = type === 'character' ? window.c_labelFontSize : window.l_labelFontSize;
        const nodeSize = type === 'character' ? window.c_nodeSize : window.l_nodeSize;

        // Regenerate the tree and apply the stored transformation
        generateRadialTreeVisualization(container, structuredData, type, radius, labelFontSize, nodeSize, currentTransform, currentRotation);
    }

    function generateRadialTreeVisualization(container, data, type, radius = 300, labelFontSize = 12, nodeSize = 24, initialTransform = null, initialRotation = 0) {
        // Clear the container
        container.innerHTML = '';

        // Set dimensions
        const width = container.clientWidth;
        const height = container.clientHeight;

        // Current zoom, pan, and rotation state
        let currentRotation = initialRotation;
        let currentTransform = initialTransform || { x: width / 2, y: height / 2, k: 1 };

        // Create a D3 zoom behavior
        const zoomBehavior = d3.zoom()
        .scaleExtent([0.5, 5])
        .on('zoom', zoomed);

        // Create SVG element with zoom and pan functionality
        const svg = d3.select(container)
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .call(zoomBehavior) // Apply the zoom behavior
        .append('g')
        .attr('transform', `translate(${currentTransform.x},${currentTransform.y}) scale(${currentTransform.k}) rotate(${currentRotation})`);

        // Apply the initial zoom, pan, and rotation
        d3.select(container).select('svg').call(zoomBehavior.transform, d3.zoomIdentity.translate(currentTransform.x, currentTransform.y).scale(currentTransform.k));

        function zoomed(event) {
            // Update the current pan and zoom values
            currentTransform = event.transform;
            // Apply the combined transformation (zoom, pan, and rotation)
            svg.attr('transform', `translate(${currentTransform.x},${currentTransform.y}) scale(${currentTransform.k}) rotate(${currentRotation})`);

            // Store the transformation globally so we can retain it after refresh
            window.currentTransform = currentTransform;
        }

        // Convert data to D3 hierarchy
        const root = d3.hierarchy({ name: type === 'character' ? 'Characters' : 'Locations', children: data })
        .sum(d => d.children ? 0 : 1);

        // Create the radial tree layout
        const tree = d3.tree()
        .size([2 * Math.PI, radius])
        .separation((a, b) => (a.parent == b.parent ? 1 : 2) / a.depth);

        tree(root);

        // Create links
        const link = svg.append('g')
        .selectAll('.link')
        .data(root.links())
        .join('path')
        .attr('class', 'link')
        .attr('d', d3.linkRadial()
              .angle(d => d.x)
              .radius(d => d.y))
        .attr('stroke', 'var(--border-color)')
        .attr('fill', 'none');

        // Create nodes
        const node = svg.append('g')
        .selectAll('.node')
        .data(root.descendants())
        .join('g')
        .attr('class', 'node')
        .attr('transform', d => `
            rotate(${d.x * 180 / Math.PI - 90})
            translate(${d.y},0)
        `);

        // Use emoji as node symbols
        node.append('text')
            .attr('dy', '0.31em')
            .attr('font-size', `${nodeSize}px`) // Use nodeSize for font size
            .attr('text-anchor', 'middle')
            .attr('transform', d => `rotate(0)`) // No flipping of text
            .text(d => d.data.emoji || '⭕') // Use emoji or a default symbol
            .style('font-size', `${nodeSize}px`)
            .style('fill', 'var(--text-color)')
            .on('mouseover', (event, d) => {
            const content = type === 'character' ? getCharacterTooltipContent(d.data, true) : getLocationTooltipContent(d.data, true);
            showTooltip_radial(event, content);
        })
            .on('mousemove', (event) => {
            moveTooltip_radial(event);
        })
            .on('mouseout', hideTooltip_radial)
            .on('contextmenu', (event, d) => {
            event.preventDefault();
            navigateToItem(d.data.id, type); // Navigate to the item in the sidebar
        });

        // Labels (without emoji)
        node.append('text')
            .attr('dy', '0.31em')
            .attr('x', +nodeSize / 2 + 5)
            .attr('text-anchor', 'center') // Always center the text
            .attr('transform', d => `rotate(0)`) // No flipping of text
            .text(d => d.data.name) // Do not include emoji in label
            .style('font-size', `${labelFontSize}px`)
            .style('fill', d => (ItemTransferTarget && d.data.id === ItemTransferTarget.id) ? 'var(--warning-bg-color)' : 'var(--text-color)')
            .on('mouseover', (event, d) => {
            const content = type === 'character' ? getCharacterTooltipContent(d.data, true) : getLocationTooltipContent(d.data, true);
            showTooltip_radial(event, content);
        })
            .on('mousemove', (event) => {
            moveTooltip_radial(event);
        })
            .on('mouseout', hideTooltip_radial)
            .on('contextmenu', (event, d) => {
            event.preventDefault();

            if (ItemTransferTarget == null) {
                // Check if it's an item (not a group)
                if (d.data.description != undefined) { // items undefined means it's not a group
                    CreateContextMenu(
                        'var(--button-bg-color)',
                        'var(--text-color)',
                        ['Locate', 'Edit', 'Move', 'Delete'],
                        [
                            // Locate
                            function() { navigateToItem(d.data.id, type); },
                            // Edit
                            function() {
                                const itemId = d.data.id;
                                if (type === 'character') {
                                    const character = findItemById(characterGroups, itemId);
                                    if (character) {
                                        editCharacter(character);
                                        renderCharacterGroups();
                                        refreshTree(container, data, type);
                                    }
                                } else {
                                    const location = findItemById(locationGroups, itemId);
                                    if (location) {
                                        editLocation(location);
                                        renderLocationGroups();
                                        refreshTree(container, data, type);
                                    }
                                }
                            },
                            // Move
                            function() {
                                ItemTransferTarget = d.data;
                                refreshTree(container, data, type);
                            },
                            // Delete
                            function() {
                                const itemId = d.data.id;
                                if (type === 'character') {
                                    deleteCharacter(itemId);
                                    renderCharacterGroups();
                                    refreshTree(container, data, type);
                                } else {
                                    deleteLocation(itemId);
                                    renderLocationGroups();
                                    refreshTree(container, data, type);
                                }
                            }
                        ]
                    );
                } else {
                    // It's a group
                    CreateContextMenu(
                        'var(--button-bg-color)',
                        'var(--text-color)',
                        ['Edit', 'Delete'],
                        [
                            // Edit Group
                            function() {
                                const groupName = d.data.name;
                                if (type === 'character') {
                                    const groupIndex = findGroupIndexByName(characterGroups, groupName);
                                    if (groupIndex !== null) {
                                        renameGroup(groupIndex);
                                        renderCharacterGroups();
                                        refreshTree(container, data, type);
                                    }
                                } else {
                                    const groupIndex = findGroupIndexByName(locationGroups, groupName);
                                    if (groupIndex !== null) {
                                        renameLocationGroup(groupIndex);
                                        renderLocationGroups();
                                        refreshTree(container, data, type);
                                    }
                                }
                            },
                            // Delete Group
                            function() {
                                const groupName = d.data.name;
                                if (type === 'character') {
                                    const groupIndex = findGroupIndexByName(characterGroups, groupName);
                                    if (groupIndex !== null) {
                                        deleteGroup(groupIndex);
                                        renderCharacterGroups();
                                        refreshTree(container, data, type);
                                    }
                                } else {
                                    const groupIndex = findGroupIndexByName(locationGroups, groupName);
                                    if (groupIndex !== null) {
                                        deleteLocationGroup(groupIndex);
                                        renderLocationGroups();
                                        refreshTree(container, data, type);
                                    }
                                }
                            }
                        ]
                    );
                }
            } else {
                // Moving an item
                if (ItemTransferTarget.id === d.data.id) {
                    // Stop moving
                    CreateContextMenu(
                        'var(--button-bg-color)',
                        'var(--text-color)',
                        ['Stop'],
                        [
                            function() {
                                ItemTransferTarget = null;
                                refreshTree(container, data, type);
                            }
                        ]
                    );
                } else {
                    // Place the item
                    CreateContextMenu(
                        'var(--button-bg-color)',
                        'var(--text-color)',
                        ['Place'],
                        [
                            function() {
                                // Check for circular reference
                                if (isAncestor(ItemTransferTarget.id, d.data.id, type)) {
                                    alert('Cannot move an item into its descendant.');
                                    return;
                                }
                                // Remove from current location
                                if (type === 'character') {
                                    removeItemById(characterGroups, ItemTransferTarget.id);
                                } else {
                                    removeItemById(locationGroups, ItemTransferTarget.id);
                                }
                                // Add to new parent
                                if (d.data.description == undefined) {
                                    // New parent is a group
                                    const groupName = d.data.name;
                                    if (type === 'character') {
                                        const groupIndex = findGroupIndexByName(characterGroups, groupName);
                                        if (groupIndex !== null) {
                                            characterGroups[groupIndex].items.push(ItemTransferTarget);
                                        } else {
                                            alert('Group not found.');
                                            return;
                                        }
                                    } else {
                                        const groupIndex = findGroupIndexByName(locationGroups, groupName);
                                        if (groupIndex !== null) {
                                            locationGroups[groupIndex].items.push(ItemTransferTarget);
                                        } else {
                                            alert('Group not found.');
                                            return;
                                        }
                                    }
                                } else {
                                    // New parent is an item
                                    let newParent = null;
                                    if (type === 'character') {
                                        newParent = findItemById(characterGroups, d.data.id);
                                    } else {
                                        newParent = findItemById(locationGroups, d.data.id);
                                    }
                                    if (!newParent) {
                                        alert('Could not find the new parent in data.');
                                        return;
                                    }
                                    if (!newParent.children) {
                                        newParent.children = [];
                                    }
                                    newParent.children.push(ItemTransferTarget);
                                }
                                // Clear transfer target
                                ItemTransferTarget = null;

                                // Refresh
                                if (type === 'character') {
                                    renderCharacterGroups();
                                } else {
                                    renderLocationGroups();
                                }
                                refreshTree(container, data, type);
                            }
                        ]
                    );
                }
            }
            showMenu(event);
        });

        // --- Rotation Knob UI ---
        const knobContainer = document.createElement('div');
        knobContainer.style.cssText = `
        position: absolute;
        bottom: 10px;
        right: 10px;
        width: 100px;
        height: 100px;
        z-index: 10003;
        background-color: var(--bg-color);
        border: 1px solid var(--border-color);
        border-radius: 50%;
        display: flex;
        justify-content: center;
        align-items: center;
        cursor: pointer;
    `;

        const knob = document.createElement('div');
        knob.style.cssText = `
        width: 60px;
        height: 60px;
        background-color: var(--button-bg-color);
        border-radius: 50%;
        position: relative;
        transform: rotate(${currentRotation}deg); /* Apply initial rotation */
    `;

        // Add a small indicator inside the knob to show the starting point
        const knobIndicator = document.createElement('div');
        knobIndicator.style.cssText = `
        position: absolute;
        top: 5px;
        left: 50%;
        transform: translateX(-50%);
        width: 10px;
        height: 10px;
        background-color: var(--text-color);
        border-radius: 50%;
    `;
        knob.appendChild(knobIndicator);

        knobContainer.appendChild(knob);
        container.appendChild(knobContainer);

        let isDragging = false;
        let previousAngle = 0;

        // Utility function to get the angle of the mouse relative to the center of the knob
        function getAngleFromEvent(event, element) {
            const rect = element.getBoundingClientRect();
            const centerX = rect.left + rect.width / 2;
            const centerY = rect.top + rect.height / 2;
            const deltaX = event.clientX - centerX;
            const deltaY = event.clientY - centerY;
            const angle = Math.atan2(deltaY, deltaX) * (180 / Math.PI);
            return angle;
        }

        // Function to start dragging the knob
        knob.addEventListener('mousedown', (event) => {
            isDragging = true;
            previousAngle = getAngleFromEvent(event, knob);
            event.preventDefault();
        });

        // Function to handle dragging
        document.addEventListener('mousemove', (event) => {
            if (isDragging) {
                const currentAngle = getAngleFromEvent(event, knob);
                const deltaAngle = currentAngle - previousAngle;

                // Update the current rotation
                currentRotation = (currentRotation + deltaAngle) % 360;
                if (currentRotation < 0) currentRotation += 360; // Ensure positive rotation

                // Apply the combined transformation (rotation, zoom, and pan)
                svg.attr('transform', `translate(${currentTransform.x},${currentTransform.y}) scale(${currentTransform.k}) rotate(${currentRotation})`);

                // Rotate the knob visually
                knob.style.transform = `rotate(${currentRotation}deg)`;

                // Store the updated rotation globally so we can retain it after refresh
                window.currentRotation = currentRotation;

                // Update previous angle for the next move
                previousAngle = currentAngle;
            }
        });

        // Stop dragging when mouse is released
        document.addEventListener('mouseup', () => {
            isDragging = false;
        });

        // Resize listener
        window.addEventListener('resize', () => {
            svg.attr('width', container.clientWidth).attr('height', container.clientHeight);
        });
    }

    function navigateToItem(id, type) {
        if (type === 'character') {
            // Expand groups and scroll to the character
            characterGroups.forEach(group => {
                expandItemAndFind(group, id, type);
            });
            renderCharacterGroups();

            const itemElement = document.querySelector(`#character-group-list [data-id="${id}"]`);
            if (itemElement) {
                // Ensure the character menu stays open
                if (characterSidebar.style.right === '-350px') {
                    characterToggleButton.click(); // Open the sidebar if it's closed
                }
                itemElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
            }
        } else {
            // Expand groups and scroll to the location
            locationGroups.forEach(group => {
                expandItemAndFind(group, id, type);
            });
            renderLocationGroups();
            const itemElement = document.querySelector(`#location-group-list [data-id="${id}"]`);
            if (itemElement) {
                // Ensure the location menu stays open
                if (locationSidebar.style.left === '-350px') {
                    locationToggleButton.click(); // Open the sidebar if it's closed
                }
                itemElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
            }
        }
    }

    // Function to expand groups and find item (recursive)
    function expandItemAndFind(item, id, type) {
        if (item.id === id) {
            return true;
        }

        let found = false;

        if (item.items && item.items.length > 0) {
            for (let i = 0; i < item.items.length; i++) {
                if (expandItemAndFind(item.items[i], id, type)) {
                    item.collapsed = false; // Expand parent
                    found = true;
                }
            }
        }

        if (item.children && item.children.length > 0) {
            for (let i = 0; i < item.children.length; i++) {
                if (expandItemAndFind(item.children[i], id, type)) {
                    item.collapsed = false; // Expand parent
                    found = true;
                }
            }
        }

        return found;
    }

    // Function to create structured data for D3.js
    function structureData(groups) {
        return groups.map(group => ({
            name: group.name,
            emoji: '📁', // Assign folder emoji to groups
            id: group.id || generateId(),
            children: group.items.map(item => mapItem(item))
        }));
    }

    function mapItem(item) {
        return {
            id: item.id,
            name: item.name,
            emoji: item.emoji || '', // Use item's emoji, empty string if none
            description: item.description || item.bio || '',
            children: item.children ? item.children.map(child => mapItem(child)) : []
        };
    }

    // Tooltips for Radial Tree
    let radialTooltipElement = null;

    function showTooltip_radial(event, content) {
        hideTooltip_radial(); // Remove existing tooltip if any

        // Create new tooltip element
        radialTooltipElement = document.createElement('div');
        radialTooltipElement.style.cssText = `
        position: absolute;
        z-index: 100003;
        background-color: var(--bg-tool);
        color: var(--text-color);
        border: 1px solid var(--border-color);
        padding: 5px;
        border-radius: 5px;
        font-size: 12px;
        max-width: 600px;
        white-space: pre-wrap;
        box-shadow: 0 0 10px var(--shadow-color);
        pointer-events: none;
    `;
        radialTooltipElement.innerHTML = content;

        radialTooltipElement.style.left = `${event.pageX + 10}px`;
        radialTooltipElement.style.top = `${event.pageY + 10}px`;

        document.body.appendChild(radialTooltipElement);
    }

    function moveTooltip_radial(event) {
        if (radialTooltipElement) {
            radialTooltipElement.style.left = `${event.pageX + 10}px`;
            radialTooltipElement.style.top = `${event.pageY + 10}px`;
        }
    }

    function hideTooltip_radial() {
        if (radialTooltipElement && radialTooltipElement.parentNode) {
            radialTooltipElement.parentNode.removeChild(radialTooltipElement);
            radialTooltipElement = null; // Set to null after removing
        }
    }
    // Adding buttons to headers

    // Character Header Modifications
    characterHeader.innerHTML = '';

    const characterHeaderContainer = document.createElement('div');
    characterHeaderContainer.style.cssText = `
        display: flex;
        align-items: center;
        justify-content: center;
    `;

    // Search Button for Characters (Left Side)
    const characterSearchButton = document.createElement('button');
    characterSearchButton.textContent = '🔍';
    characterSearchButton.title = 'Open Search Panel';
    characterSearchButton.style.cssText = `
        background: none;
        border: none;
        color: var(--text-color);
        cursor: pointer;
        font-size: 18px;
        margin-right: 10px;
    `;
    characterHeaderContainer.appendChild(characterSearchButton);

    // Character Title
    const characterTitle = document.createElement('span');
    characterTitle.textContent = 'Characters';
    characterTitle.style.cssText = `
        color: var(--text-color);
        flex-grow: 1;
        text-align: center;
    `;
    characterHeaderContainer.appendChild(characterTitle);

    // Radial Tree Button for Characters (Right Side)
    const characterRadialButton = document.createElement('button');
    characterRadialButton.textContent = '🌐';
    characterRadialButton.title = 'Open Radial Tree';
    characterRadialButton.style.cssText = `
        background: none;
        border: none;
        color: var(--text-color);
        cursor: pointer;
        font-size: 18px;
        margin-left: 10px;
    `;
    characterHeaderContainer.appendChild(characterRadialButton);

    characterHeader.appendChild(characterHeaderContainer);

    // Location Header Modifications
    locationHeader.innerHTML = '';

    const locationHeaderContainer = document.createElement('div');
    locationHeaderContainer.style.cssText = `
        display: flex;
        align-items: center;
        justify-content: center;
    `;

    // Radial Tree Button for Locations (Left Side)
    const locationRadialButton = document.createElement('button');
    locationRadialButton.textContent = '🌐';
    locationRadialButton.title = 'Open Radial Tree';
    locationRadialButton.style.cssText = `
        background: none;
        border: none;
        color: var(--text-color);
        cursor: pointer;
        font-size: 18px;
        margin-right: 10px;
    `;
    locationHeaderContainer.appendChild(locationRadialButton);

    // Location Title
    const locationTitle = document.createElement('span');
    locationTitle.textContent = 'Locations';
    locationTitle.style.cssText = `
        color: var(--text-color);
        flex-grow: 1;
        text-align: center;
    `;
    locationHeaderContainer.appendChild(locationTitle);

    // Search Button for Locations (Right Side)
    const locationSearchButton = document.createElement('button');
    locationSearchButton.textContent = '🔍';
    locationSearchButton.title = 'Open Search Panel';
    locationSearchButton.style.cssText = `
        background: none;
        border: none;
        color: var(--text-color);
        cursor: pointer;
        font-size: 18px;
        margin-left: 10px;
    `;
    locationHeaderContainer.appendChild(locationSearchButton);

    locationHeader.appendChild(locationHeaderContainer);

    // Function to open search panel (Integrated into Sidebar)
    function toggleSearchPanel(type) {
        if (type === 'character') {
            if (searchPanelOpen.character) {
                // Close search panel
                characterSearchContainer.style.display = 'none';
                searchPanelOpen.character = false;
            } else {
                // Open search panel
                characterSearchContainer.style.display = 'block';
                searchPanelOpen.character = true;
                characterSearchInput.focus();
            }
        } else {
            if (searchPanelOpen.location) {
                // Close search panel
                locationSearchContainer.style.display = 'none';
                searchPanelOpen.location = false;
            } else {
                // Open search panel
                locationSearchContainer.style.display = 'block';
                searchPanelOpen.location = true;
                locationSearchInput.focus();
            }
        }
    }

    // Character Search Panel
    const characterSearchContainer = document.createElement('div');
    characterSearchContainer.style.cssText = `
    position: relative;
    display: none;
    padding: 10px;
    background-color: var(--bg-color);
`;
    const characterSearchInput = document.createElement('input');
    characterSearchInput.type = 'text';
    characterSearchInput.placeholder = 'Search...';
    characterSearchInput.style.cssText = `
    width: 100%;
    margin-bottom: 0px;
    padding: 5px;
    border: 1px solid var(--border-color);
    border-radius: 5px;
    background-color: var(--bg-color);
    color: var(--text-color);
`;

    // Adjust the results container to match the search input width
    const characterResultsContainer = document.createElement('div');
    characterResultsContainer.style.cssText = `
    position: absolute;
    top: calc(100% + 5px); /* Position below the search input */
    left: 0;
    width: 100%;
    max-height: 200px;
    overflow-y: auto;
    background-color: var(--bg-color);
    border: 1px solid var(--border-color);
    box-shadow: 0 0 10px var(--shadow-color);
    z-index: 1000;
`;
    characterSearchContainer.appendChild(characterSearchInput);
    characterSearchContainer.appendChild(characterResultsContainer);
    characterSidebar.insertBefore(characterSearchContainer, characterGroupList);

    characterSearchInput.addEventListener('input', () => {
        const query = characterSearchInput.value.trim().toLowerCase();
        characterResultsContainer.innerHTML = '';
        if (query.length > 0) {
            const results = searchItems(query, 'character');
            if (results.length > 0) {
                results.forEach(result => {
                    const resultItem = document.createElement('div');
                    resultItem.style.cssText = `
                    padding: 5px;
                    border-bottom: 1px solid var(--border-color);
                    cursor: pointer;
                    color: var(--text-color);
                    overflow: hidden;
                    text-overflow: ellipsis;
                    white-space: nowrap;
                `;
                    resultItem.addEventListener('click', () => {
                        navigateToItem(result.id, 'character');
                        characterSearchInput.value = '';
                        characterResultsContainer.innerHTML = '';
                    });
                    resultItem.innerHTML = formatSearchResult(result);
                    characterResultsContainer.appendChild(resultItem);
                });
            } else {
                characterResultsContainer.textContent = 'No results found.';
            }
        }
    });

    // Location Search Panel
    const locationSearchContainer = document.createElement('div');
    locationSearchContainer.style.cssText = `
    position: relative;
    display: none;
    padding: 10px;
    background-color: var(--bg-color);
`;
    const locationSearchInput = document.createElement('input');
    locationSearchInput.type = 'text';
    locationSearchInput.placeholder = 'Search...';
    locationSearchInput.style.cssText = `
    width: 100%;
    margin-bottom: 0px;
    padding: 5px;
    border: 1px solid var(--border-color);
    border-radius: 5px;
    background-color: var(--bg-color);
    color: var(--text-color);
`;

    // Adjust the results container to match the search input width
    const locationResultsContainer = document.createElement('div');
    locationResultsContainer.style.cssText = `
    position: absolute;
    top: calc(100% + 5px); /* Position below the search input */
    left: 0;
    width: 100%;
    max-height: 200px;
    overflow-y: auto;
    background-color: var(--bg-color);
    border: 1px solid var(--border-color);
    box-shadow: 0 0 10px var(--shadow-color);
    z-index: 1000;
`;
    locationSearchContainer.appendChild(locationSearchInput);
    locationSearchContainer.appendChild(locationResultsContainer);
    locationSidebar.insertBefore(locationSearchContainer, locationGroupList);

    locationSearchInput.addEventListener('input', () => {
        const query = locationSearchInput.value.trim().toLowerCase();
        locationResultsContainer.innerHTML = '';
        if (query.length > 0) {
            const results = searchItems(query, 'location');
            if (results.length > 0) {
                results.forEach(result => {
                    const resultItem = document.createElement('div');
                    resultItem.style.cssText = `
                    padding: 5px;
                    border-bottom: 1px solid var(--border-color);
                    cursor: pointer;
                    color: var(--text-color);
                    overflow: hidden;
                    text-overflow: ellipsis;
                    white-space: nowrap;
                `;
                    resultItem.addEventListener('click', () => {
                        navigateToItem(result.id, 'location');
                        locationSearchInput.value = '';
                        locationResultsContainer.innerHTML = '';
                    });
                    resultItem.innerHTML = formatSearchResult(result);
                    locationResultsContainer.appendChild(resultItem);
                });
            } else {
                locationResultsContainer.textContent = 'No results found.';
            }
        }
    });

    locationSearchButton.addEventListener('click', () => {
        toggleSearchPanel('location');
    });

    // Radial Tree Button Event Listeners
    characterRadialButton.addEventListener('click', () => {
        if (radialTreeOpen) {
            document.getElementById('radial-tree-window').remove();
            radialTreeOpen = false;
        }
        const data = structureData(characterGroups);
        createRadialTree(data, 'character');
    });

    locationRadialButton.addEventListener('click', () => {
        if (radialTreeOpen) {
            document.getElementById('radial-tree-window').remove();
            radialTreeOpen = false;
        }
        const data = structureData(locationGroups);
        createRadialTree(data, 'location');
    });

    // Function to search items
    function searchItems(query, type) {
        const results = [];
        const groups = type === 'character' ? characterGroups : locationGroups;
        groups.forEach(group => {
            searchGroup(group, query, results, []);
        });
        return results;
    }

    function searchGroup(group, query, results, path) {
        const newPath = [...path, group.name];
        group.items.forEach(item => {
            searchItem(item, query, results, newPath);
        });
    }

    function searchItem(item, query, results, path) {
        const newPath = [...path, item.name];
        if (item.name.toLowerCase().includes(query)) {
            results.push({ id: item.id, path: newPath });
        }
        if (item.children && item.children.length > 0) {
            item.children.forEach(child => {
                searchItem(child, query, results, newPath);
            });
        }
    }

    function formatSearchResult(result) {
        let html = '';
        const maxCharacters = 42; // Adjust as needed
        let displayPath = result.path.join(' > ');

        if (displayPath.length > maxCharacters) {
            displayPath = '...' + displayPath.slice(-maxCharacters);
        }

        const pathSegments = displayPath.split(' > ');

        for (let i = 0; i < pathSegments.length - 1; i++) {
            html += `<span style="font-size: 12px; color: var(--text-color-darker); white-space: nowrap;">${pathSegments[i]} > </span>`;
        }
        html += `<strong style="white-space: nowrap;">${pathSegments[pathSegments.length - 1]}</strong>`;

        return `<div style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">${html}</div>`;
    }

})();