Ultimate Glow Dashboard

A premium glowing userscript dashboard featuring persistent counters, a task manager, and a stopwatch/timer with drag-and-resize capabilities.

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Violentmonkey installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Violentmonkey installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Userscripts installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey installieren.

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

(Ich habe bereits einen Benutzerstil Verwaltung, ich möchte ihn installieren!)

// ==UserScript==
// @name         Ultimate Glow Dashboard
// @namespace    http://tampermonkey.net/
// @version      1.0.0
// @description  A premium glowing userscript dashboard featuring persistent counters, a task manager, and a stopwatch/timer with drag-and-resize capabilities.
// @author       ksmo
// @match        *://*/*
// @license      MIT
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const STORAGE_KEY = 'ksmo_glow_dashboard_state';
    let state = {
        visible: false,
        posX: window.innerWidth - 300,
        posY: 100,
        width: 260,
        height: 380,
        locked: false,
        activeTab: 'counters',
        counters: [
            { id: '1', name: 'User 1', value: 0, color: '#ff6bff' },
            { id: '2', name: 'User 2', value: 0, color: '#ffb834' }
        ],
        tasks: [
            { id: '1', text: 'Task 1', completed: false }
        ],
        pinY: window.innerHeight / 2 - 22,
        timer: { seconds: 0, running: false, startedAt: null }
    };

    try {
        const saved = localStorage.getItem(STORAGE_KEY);
        if (saved) {
            const parsed = JSON.parse(saved);
            if (parsed && typeof parsed === 'object') {
                if (Array.isArray(parsed.counters)) state.counters = parsed.counters;
                if (Array.isArray(parsed.tasks)) state.tasks = parsed.tasks;
                if (typeof parsed.visible === 'boolean') state.visible = parsed.visible;
                if (typeof parsed.locked === 'boolean') state.locked = parsed.locked;
                if (typeof parsed.activeTab === 'string') state.activeTab = parsed.activeTab;
                if (typeof parsed.posX === 'number') state.posX = parsed.posX;
                if (typeof parsed.posY === 'number') state.posY = parsed.posY;
                if (typeof parsed.width === 'number') state.width = parsed.width;
                if (typeof parsed.height === 'number') state.height = parsed.height;
                if (typeof parsed.pinY === 'number') state.pinY = parsed.pinY;
                if (parsed.timer && typeof parsed.timer === 'object') {
                    state.timer = parsed.timer;
                }
            }
        }
    } catch (e) {
        console.error('Failed to load state:', e);
    }

    const saveState = () => {
        try {
            localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
        } catch (e) {
            console.error('Failed to save state:', e);
        }
    };

    const generateId = () => Date.now().toString(36) + Math.random().toString(36).substr(2, 5);

    if (!state.timer) {
        state.timer = { seconds: 0, running: false, startedAt: null };
    }

    let timerInterval = null;
    let timerSeconds = state.timer.seconds || 0;
    let isTimerRunning = state.timer.running || false;
    let timerDisplayEl = null;

    const formatTime = (totalSeconds) => {
        const hrs = Math.floor(totalSeconds / 3600);
        const mins = Math.floor((totalSeconds % 3600) / 60);
        const secs = totalSeconds % 60;
        return [
            hrs > 0 ? String(hrs).padStart(2, '0') : null,
            String(mins).padStart(2, '0'),
            String(secs).padStart(2, '0')
        ].filter(Boolean).join(':');
    };

    const updateTimerGlobal = () => {
        timerSeconds++;
        if (timerDisplayEl) {
            timerDisplayEl.textContent = formatTime(timerSeconds);
        }
    };

    const startTimer = () => {
        clearInterval(timerInterval);
        clearTimeout(timerInterval);
        if (isTimerRunning && state.timer.startedAt) {
            const elapsedMs = Date.now() - state.timer.startedAt;
            timerSeconds = state.timer.seconds + Math.floor(elapsedMs / 1000);
            
            if (timerDisplayEl) {
                timerDisplayEl.textContent = formatTime(timerSeconds);
            }

            const msToNextSecond = 1000 - (elapsedMs % 1000);
            timerInterval = setTimeout(() => {
                updateTimerGlobal();
                timerInterval = setInterval(updateTimerGlobal, 1000);
            }, msToNextSecond);
        }
    };

    if (isTimerRunning) {
        startTimer();
    }

    const clampPos = (x, y, w, h) => {
        return {
            x: Math.max(0, Math.min(window.innerWidth - w, x)),
            y: Math.max(0, Math.min(window.innerHeight - h, y))
        };
    };

    const pos = clampPos(state.posX, state.posY, state.width, state.height);
    state.posX = pos.x;
    state.posY = pos.y;

    const host = document.createElement('div');
    host.id = 'ksmo-glow-dash-host';
    host.style.position = 'fixed';
    host.style.top = '0';
    host.style.left = '0';
    host.style.width = '0';
    host.style.height = '0';
    host.style.zIndex = '999999';

    const shadow = host.attachShadow({ mode: 'open' });

    const style = document.createElement('style');
    style.textContent = `
        ::-webkit-scrollbar {
            width: 6px;
            height: 6px;
        }
        ::-webkit-scrollbar-track {
            background: transparent;
        }
        ::-webkit-scrollbar-thumb {
            background: rgba(255, 255, 255, 0.1);
            border-radius: 3px;
        }
        ::-webkit-scrollbar-thumb:hover {
            background: rgba(255, 255, 255, 0.25);
        }
        .ksmo-panel {
            position: fixed;
            background: radial-gradient(circle at top left, rgba(25, 25, 40, 0.9), rgba(12, 12, 20, 0.96));
            backdrop-filter: blur(16px);
            -webkit-backdrop-filter: blur(16px);
            border: 1px solid rgba(255, 255, 255, 0.08);
            border-radius: 16px;
            box-shadow: 0 16px 48px rgba(0, 0, 0, 0.7);
            color: #ffffff;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
            display: flex;
            flex-direction: column;
            box-sizing: border-box;
            user-select: none;
            overflow: hidden;
            opacity: 0;
            transform: scale(0.92) translateY(10px);
            transition: opacity 0.3s cubic-bezier(0.16, 1, 0.3, 1), transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
            pointer-events: none;
        }
        .ksmo-panel.show {
            opacity: 1;
            transform: scale(1) translateY(0);
            pointer-events: auto;
        }
        .ksmo-header {
            padding: 0.8em 1.2em;
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-bottom: 1px solid rgba(255, 255, 255, 0.06);
            cursor: grab;
            flex-shrink: 0;
        }
        .ksmo-header.locked {
            cursor: default;
        }
        .ksmo-header:active:not(.locked) {
            cursor: grabbing;
        }
        .ksmo-title {
            font-size: 0.85em;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: 2px;
            color: rgba(255, 255, 255, 0.5);
        }
        .ksmo-header-actions {
            display: flex;
            gap: 0.5em;
        }
        .ksmo-icon-btn {
            background: none;
            border: none;
            color: #fff;
            cursor: pointer;
            font-size: 1.1em;
            padding: 0.2em 0.5em;
            border-radius: 6px;
            transition: all 0.2s ease;
            opacity: 0.5;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .ksmo-icon-btn:hover {
            background: rgba(255, 255, 255, 0.08);
            opacity: 1;
            transform: scale(1.05);
        }
        .ksmo-icon-btn:active {
            transform: scale(0.95);
        }
        .ksmo-tabs {
            display: flex;
            border-bottom: 1px solid rgba(255, 255, 255, 0.04);
            background: rgba(0, 0, 0, 0.15);
            flex-shrink: 0;
        }
        .ksmo-tab {
            flex: 1;
            padding: 0.8em 0;
            background: none;
            border: none;
            color: rgba(255, 255, 255, 0.4);
            font-size: 0.75em;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 1px;
            cursor: pointer;
            transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
            border-bottom: 2px solid transparent;
            text-align: center;
        }
        .ksmo-tab:hover {
            color: rgba(255, 255, 255, 0.8);
        }
        .ksmo-tab.active {
            color: #ffffff;
            border-bottom-color: #6c5ce7;
            background: rgba(255, 255, 255, 0.02);
            text-shadow: 0 0 12px rgba(108, 92, 231, 0.6);
        }
        .ksmo-content {
            flex-grow: 1;
            display: flex;
            flex-direction: column;
            padding: 1.2em;
            overflow-y: auto;
            position: relative;
            gap: 1em;
        }
        .ksmo-view {
            display: none;
            flex-direction: column;
            height: 100%;
        }
        .ksmo-view.active {
            display: flex;
        }
        .ksmo-counter-list {
            display: flex;
            flex-direction: column;
            gap: 0.8em;
            flex-grow: 1;
            overflow-y: auto;
        }
        .ksmo-counter-item {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 0.8em 1em;
            border-radius: 10px;
            background: rgba(255, 255, 255, 0.02);
            border: 1px solid rgba(255, 255, 255, 0.04);
            transition: all 0.2s ease;
        }
        .ksmo-counter-item:hover {
            background: rgba(255, 255, 255, 0.04);
            border-color: rgba(255, 255, 255, 0.06);
        }
        .ksmo-counter-info {
            display: flex;
            flex-direction: column;
            gap: 0.2em;
            cursor: pointer;
            max-width: 50%;
        }
        .ksmo-counter-name {
            font-size: 0.9em;
            font-weight: 600;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            transition: color 0.2s;
        }
        .ksmo-counter-val {
            font-size: 1.8em;
            font-weight: 700;
            line-height: 1.1;
            transition: text-shadow 0.3s ease;
        }
        .ksmo-counter-actions {
            display: flex;
            align-items: center;
            gap: 0.4em;
        }
        .ksmo-btn {
            background: rgba(255, 255, 255, 0.06);
            border: 1px solid rgba(255, 255, 255, 0.04);
            color: #fff;
            font-size: 1.1em;
            font-weight: 600;
            width: 2.2em;
            height: 2.2em;
            border-radius: 8px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
        }
        .ksmo-btn:hover {
            background: rgba(255, 255, 255, 0.12);
            border-color: rgba(255, 255, 255, 0.1);
            transform: translateY(-1px);
        }
        .ksmo-btn:active {
            transform: translateY(0) scale(0.95);
            background: rgba(255, 255, 255, 0.03);
        }
        .ksmo-btn.danger {
            background: rgba(255, 76, 76, 0.1);
            border-color: rgba(255, 76, 76, 0.15);
            color: #ff4c4c;
        }
        .ksmo-btn.danger:hover {
            background: rgba(255, 76, 76, 0.25);
            border-color: rgba(255, 76, 76, 0.3);
        }
        .ksmo-add-btn {
            margin-top: 0.8em;
            width: 100%;
            padding: 0.8em 0;
            background: rgba(108, 92, 231, 0.15);
            border: 1px solid rgba(108, 92, 231, 0.25);
            color: #a29bfe;
            border-radius: 10px;
            font-size: 0.85em;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.2s;
            flex-shrink: 0;
        }
        .ksmo-add-btn:hover {
            background: rgba(108, 92, 231, 0.3);
            color: #fff;
            box-shadow: 0 4px 15px rgba(108, 92, 231, 0.2);
        }
        .ksmo-task-input-row {
            display: flex;
            gap: 0.5em;
            margin-bottom: 0.8em;
            flex-shrink: 0;
        }
        .ksmo-input {
            flex: 1;
            background: rgba(255, 255, 255, 0.04);
            border: 1px solid rgba(255, 255, 255, 0.08);
            border-radius: 8px;
            padding: 0.6em 0.9em;
            color: #fff;
            font-size: 0.9em;
            outline: none;
            transition: border-color 0.2s, box-shadow 0.2s;
        }
        .ksmo-input:focus {
            border-color: rgba(108, 92, 231, 0.6);
            box-shadow: 0 0 10px rgba(108, 92, 231, 0.2);
        }
        .ksmo-task-list {
            display: flex;
            flex-direction: column;
            gap: 0.6em;
            flex-grow: 1;
            overflow-y: auto;
        }
        .ksmo-task-item {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 0.6em 0.8em;
            background: rgba(255, 255, 255, 0.01);
            border-radius: 8px;
            border: 1px solid rgba(255, 255, 255, 0.03);
            transition: all 0.2s;
        }
        .ksmo-task-item:hover {
            background: rgba(255, 255, 255, 0.03);
        }
        .ksmo-task-checkbox {
            cursor: pointer;
            margin-right: 0.8em;
            width: 1.1em;
            height: 1.1em;
            accent-color: #6c5ce7;
        }
        .ksmo-task-text {
            flex-grow: 1;
            font-size: 0.85em;
            word-break: break-word;
            transition: opacity 0.2s, text-decoration 0.2s;
        }
        .ksmo-task-text.completed {
            text-decoration: line-through;
            opacity: 0.35;
        }
        .ksmo-timer-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            flex-grow: 1;
            gap: 1.5em;
        }
        .ksmo-timer-display {
            font-size: 2.8em;
            font-weight: 700;
            font-family: monospace;
            color: #00ffcc;
            text-shadow: 0 0 15px rgba(0, 255, 204, 0.6), 0 0 30px rgba(0, 255, 204, 0.2);
        }
        .ksmo-timer-controls {
            display: flex;
            gap: 0.8em;
        }
        .ksmo-timer-btn {
            padding: 0.6em 1.4em;
            font-size: 0.85em;
            font-weight: 600;
            border-radius: 8px;
            border: none;
            cursor: pointer;
            transition: all 0.2s;
        }
        .ksmo-timer-btn.start {
            background: #00ffcc;
            color: #0c0c14;
            box-shadow: 0 0 12px rgba(0, 255, 204, 0.3);
        }
        .ksmo-timer-btn.pause {
            background: #ffcc00;
            color: #0c0c14;
            box-shadow: 0 0 12px rgba(255, 204, 0, 0.3);
        }
        .ksmo-timer-btn.reset {
            background: rgba(255, 255, 255, 0.08);
            color: #fff;
            border: 1px solid rgba(255, 255, 255, 0.12);
        }
        .ksmo-timer-btn:hover {
            transform: translateY(-1px);
            opacity: 0.9;
        }
        .ksmo-resize-e {
            position: absolute;
            top: 0;
            right: 0;
            width: 6px;
            height: 100%;
            cursor: e-resize;
            z-index: 1000;
        }
        .ksmo-resize-s {
            position: absolute;
            bottom: 0;
            left: 0;
            width: 100%;
            height: 6px;
            cursor: s-resize;
            z-index: 1000;
        }
        .ksmo-resize-se {
            position: absolute;
            bottom: 0;
            right: 0;
            width: 12px;
            height: 12px;
            cursor: se-resize;
            z-index: 1001;
        }
        .ksmo-modal-overlay {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(5, 5, 10, 0.85);
            z-index: 1000000;
            display: flex;
            justify-content: center;
            align-items: center;
            opacity: 0;
            transition: opacity 0.2s ease;
            pointer-events: none;
        }
        .ksmo-modal-overlay.show {
            opacity: 1;
            pointer-events: auto;
        }
        .ksmo-modal {
            background: rgba(20, 20, 32, 0.96);
            border: 1px solid rgba(255, 255, 255, 0.1);
            border-radius: 14px;
            padding: 1.2em;
            box-shadow: 0 16px 36px rgba(0, 0, 0, 0.6);
            width: 80%;
            max-width: 240px;
            display: flex;
            flex-direction: column;
            gap: 0.8em;
            transform: scale(0.92);
            transition: transform 0.2s ease;
        }
        .ksmo-modal-overlay.show .ksmo-modal {
            transform: scale(1);
        }
        .ksmo-modal-title {
            font-size: 0.95em;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: 1px;
            text-align: center;
        }
        .ksmo-modal-color-selectors {
            display: flex;
            justify-content: space-between;
            gap: 0.4em;
        }
        .ksmo-modal-color-opt {
            width: 1.5em;
            height: 1.5em;
            border-radius: 50%;
            cursor: pointer;
            border: 2px solid transparent;
            transition: all 0.2s;
        }
        .ksmo-modal-color-opt.selected {
            border-color: #fff;
            transform: scale(1.15);
        }
        .ksmo-modal-actions {
            display: flex;
            gap: 0.5em;
        }
        .ksmo-modal-btn {
            flex: 1;
            padding: 0.6em 0;
            border-radius: 8px;
            border: none;
            font-size: 0.85em;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.2s;
        }
        .ksmo-modal-btn.confirm {
            background: #6c5ce7;
            color: #fff;
        }
        .ksmo-modal-btn.cancel {
            background: rgba(255, 255, 255, 0.06);
            color: #ccc;
        }
    `;
    shadow.appendChild(style);

    const panel = document.createElement('div');
    panel.className = 'ksmo-panel';
    if (state.visible) {
        panel.classList.add('show');
    }
    panel.style.left = `${state.posX}px`;
    panel.style.top = `${state.posY}px`;
    panel.style.width = `${state.width}px`;
    panel.style.height = `${state.height}px`;

    const header = document.createElement('div');
    header.className = `ksmo-header${state.locked ? ' locked' : ''}`;

    const titleEl = document.createElement('span');
    titleEl.className = 'ksmo-title';
    titleEl.textContent = 'Dashboard';

    const headerActions = document.createElement('div');
    headerActions.className = 'ksmo-header-actions';

    const lockBtn = document.createElement('button');
    lockBtn.className = 'ksmo-icon-btn';
    lockBtn.textContent = state.locked ? '🔒' : '🔓';
    lockBtn.title = state.locked ? 'Unlock Position' : 'Lock Position';

    const closeBtn = document.createElement('button');
    closeBtn.className = 'ksmo-icon-btn';
    closeBtn.textContent = '✕';
    closeBtn.title = 'Close Panel';

    headerActions.appendChild(lockBtn);
    headerActions.appendChild(closeBtn);
    header.appendChild(titleEl);
    header.appendChild(headerActions);
    panel.appendChild(header);

    const tabsContainer = document.createElement('div');
    tabsContainer.className = 'ksmo-tabs';

    const tabConfigs = [
        { id: 'counters', label: 'Counters' },
        { id: 'tasks', label: 'Tasks' },
        { id: 'timer', label: 'Timer' }
    ];

    const tabElements = {};
    tabConfigs.forEach(config => {
        const tab = document.createElement('button');
        tab.className = `ksmo-tab${state.activeTab === config.id ? ' active' : ''}`;
        tab.textContent = config.label;
        tab.addEventListener('click', () => {
            switchTab(config.id);
        });
        tabsContainer.appendChild(tab);
        tabElements[config.id] = tab;
    });
    panel.appendChild(tabsContainer);

    const content = document.createElement('div');
    content.className = 'ksmo-content';
    panel.appendChild(content);

    const views = {};
    tabConfigs.forEach(config => {
        const view = document.createElement('div');
        view.className = `ksmo-view${state.activeTab === config.id ? ' active' : ''}`;
        content.appendChild(view);
        views[config.id] = view;
    });

    const updateFontSize = () => {
        const baseWidth = 260;
        const baseHeight = 380;
        const baseFontSize = 13;
        const scaleX = state.width / baseWidth;
        const scaleY = state.height / baseHeight;
        const scale = Math.min(scaleX, scaleY, 1.8);
        panel.style.fontSize = `${Math.max(10, baseFontSize * scale)}px`;
    };
    updateFontSize();

    const switchTab = (tabId) => {
        state.activeTab = tabId;
        saveState();
        Object.keys(tabElements).forEach(id => {
            tabElements[id].classList.toggle('active', id === tabId);
            views[id].classList.toggle('active', id === tabId);
        });
    };

    const showModal = (titleText, initValue, colors, onConfirm) => {
        const overlay = document.createElement('div');
        overlay.className = 'ksmo-modal-overlay';
        
        const modal = document.createElement('div');
        modal.className = 'ksmo-modal';

        const title = document.createElement('div');
        title.className = 'ksmo-modal-title';
        title.textContent = titleText;

        const input = document.createElement('input');
        input.className = 'ksmo-input';
        input.type = 'text';
        input.value = initValue;

        modal.appendChild(title);
        modal.appendChild(input);

        let selectedColor = colors ? colors[0] : null;
        if (colors) {
            const colorContainer = document.createElement('div');
            colorContainer.className = 'ksmo-modal-color-selectors';
            const optionEls = [];
            colors.forEach(col => {
                const opt = document.createElement('div');
                opt.className = 'ksmo-modal-color-opt';
                opt.style.backgroundColor = col;
                if (col === selectedColor) opt.classList.add('selected');
                opt.addEventListener('click', () => {
                    optionEls.forEach(el => el.classList.remove('selected'));
                    opt.classList.add('selected');
                    selectedColor = col;
                });
                colorContainer.appendChild(opt);
                optionEls.push(opt);
            });
            modal.appendChild(colorContainer);
        }

        const actions = document.createElement('div');
        actions.className = 'ksmo-modal-actions';

        const cancel = document.createElement('button');
        cancel.className = 'ksmo-modal-btn cancel';
        cancel.textContent = 'Cancel';
        cancel.addEventListener('click', () => close());

        const confirm = document.createElement('button');
        confirm.className = 'ksmo-modal-btn confirm';
        confirm.textContent = 'Save';
        confirm.addEventListener('click', () => {
            const val = input.value.trim();
            if (val) {
                onConfirm(val, selectedColor);
                close();
            }
        });

        actions.appendChild(cancel);
        actions.appendChild(confirm);
        modal.appendChild(actions);
        overlay.appendChild(modal);
        panel.appendChild(overlay);

        const close = () => {
            overlay.classList.remove('show');
            setTimeout(() => overlay.remove(), 200);
        };

        overlay.addEventListener('click', (e) => {
            if (e.target === overlay) close();
        });

        setTimeout(() => {
            overlay.classList.add('show');
            input.focus();
            input.select();
        }, 10);
    };

    const renderCounters = () => {
        const view = views.counters;
        view.innerHTML = '';

        const list = document.createElement('div');
        list.className = 'ksmo-counter-list';

        state.counters.forEach(counter => {
            const item = document.createElement('div');
            item.className = 'ksmo-counter-item';

            const info = document.createElement('div');
            info.className = 'ksmo-counter-info';
            info.addEventListener('click', () => {
                showModal('Edit Counter Name', counter.name, null, (newName) => {
                    counter.name = newName;
                    saveState();
                    renderCounters();
                });
            });

            const name = document.createElement('div');
            name.className = 'ksmo-counter-name';
            name.textContent = counter.name;
            name.style.color = counter.color;

            const val = document.createElement('div');
            val.className = 'ksmo-counter-val';
            val.textContent = counter.value;
            val.style.color = counter.color;
            val.style.textShadow = `0 0 10px ${counter.color}a0, 0 0 20px ${counter.color}50`;

            info.appendChild(name);
            info.appendChild(val);

            const actions = document.createElement('div');
            actions.className = 'ksmo-counter-actions';

            const minus = document.createElement('button');
            minus.className = 'ksmo-btn';
            minus.textContent = '-';
            minus.addEventListener('click', () => {
                counter.value--;
                val.textContent = counter.value;
                saveState();
            });

            const reset = document.createElement('button');
            reset.className = 'ksmo-btn';
            reset.textContent = '↺';
            reset.addEventListener('click', () => {
                counter.value = 0;
                val.textContent = counter.value;
                saveState();
            });

            const plus = document.createElement('button');
            plus.className = 'ksmo-btn';
            plus.textContent = '+';
            plus.addEventListener('click', () => {
                counter.value++;
                val.textContent = counter.value;
                saveState();
            });

            const del = document.createElement('button');
            del.className = 'ksmo-btn danger';
            del.textContent = '✕';
            del.addEventListener('click', () => {
                state.counters = state.counters.filter(c => c.id !== counter.id);
                saveState();
                renderCounters();
            });

            actions.appendChild(minus);
            actions.appendChild(reset);
            actions.appendChild(plus);
            if (state.counters.length > 1) {
                actions.appendChild(del);
            }

            item.appendChild(info);
            item.appendChild(actions);
            list.appendChild(item);
        });

        view.appendChild(list);

        const addBtn = document.createElement('button');
        addBtn.className = 'ksmo-add-btn';
        addBtn.textContent = '+ Add Counter';
        addBtn.addEventListener('click', () => {
            const availColors = ['#ff85ff', '#ffb834', '#00ffcc', '#3498db', '#e74c3c', '#2ecc71'];
            showModal('Add Counter', `User ${state.counters.length + 1}`, availColors, (newName, color) => {
                state.counters.push({
                    id: generateId(),
                    name: newName,
                    value: 0,
                    color: color
                });
                saveState();
                renderCounters();
            });
        });
        view.appendChild(addBtn);
    };

    const renderTasks = () => {
        const view = views.tasks;
        view.innerHTML = '';

        const inputRow = document.createElement('div');
        inputRow.className = 'ksmo-task-input-row';

        const input = document.createElement('input');
        input.className = 'ksmo-input';
        input.type = 'text';
        input.placeholder = 'New task...';
        input.addEventListener('keydown', (e) => {
            if (e.key === 'Enter') add();
        });

        const addBtn = document.createElement('button');
        addBtn.className = 'ksmo-btn';
        addBtn.textContent = '+';
        const add = () => {
            const text = input.value.trim();
            if (text) {
                state.tasks.push({
                    id: generateId(),
                    text: text,
                    completed: false
                });
                saveState();
                renderTasks();
            }
        };
        addBtn.addEventListener('click', add);

        inputRow.appendChild(input);
        inputRow.appendChild(addBtn);
        view.appendChild(inputRow);

        const list = document.createElement('div');
        list.className = 'ksmo-task-list';

        state.tasks.forEach(task => {
            const item = document.createElement('div');
            item.className = 'ksmo-task-item';

            const checkbox = document.createElement('input');
            checkbox.type = 'checkbox';
            checkbox.className = 'ksmo-task-checkbox';
            checkbox.checked = task.completed;
            checkbox.addEventListener('change', () => {
                task.completed = checkbox.checked;
                text.classList.toggle('completed', task.completed);
                saveState();
            });

            const text = document.createElement('span');
            text.className = `ksmo-task-text${task.completed ? ' completed' : ''}`;
            text.textContent = task.text;

            const del = document.createElement('button');
            del.className = 'ksmo-btn danger';
            del.textContent = '✕';
            del.addEventListener('click', () => {
                state.tasks = state.tasks.filter(t => t.id !== task.id);
                saveState();
                renderTasks();
            });

            item.appendChild(checkbox);
            item.appendChild(text);
            item.appendChild(del);
            list.appendChild(item);
        });

        view.appendChild(list);
    };

    const renderTimer = () => {
        const view = views.timer;
        view.innerHTML = '';

        const containerEl = document.createElement('div');
        containerEl.className = 'ksmo-timer-container';

        const display = document.createElement('div');
        display.className = 'ksmo-timer-display';
        display.textContent = formatTime(timerSeconds);
        timerDisplayEl = display;

        const controls = document.createElement('div');
        controls.className = 'ksmo-timer-controls';

        const startPause = document.createElement('button');
        startPause.className = `ksmo-timer-btn ${isTimerRunning ? 'pause' : 'start'}`;
        startPause.textContent = isTimerRunning ? 'Pause' : 'Start';

        const reset = document.createElement('button');
        reset.className = 'ksmo-timer-btn reset';
        reset.textContent = 'Reset';

        startPause.addEventListener('click', () => {
            if (isTimerRunning) {
                clearInterval(timerInterval);
                clearTimeout(timerInterval);
                isTimerRunning = false;
                startPause.textContent = 'Start';
                startPause.className = 'ksmo-timer-btn start';

                state.timer.running = false;
                state.timer.seconds = timerSeconds;
                state.timer.startedAt = null;
                saveState();
            } else {
                state.timer.running = true;
                state.timer.startedAt = Date.now();
                saveState();
                isTimerRunning = true;
                startTimer();
                startPause.textContent = 'Pause';
                startPause.className = 'ksmo-timer-btn pause';
            }
        });

        reset.addEventListener('click', () => {
            clearInterval(timerInterval);
            clearTimeout(timerInterval);
            isTimerRunning = false;
            timerSeconds = 0;
            display.textContent = formatTime(timerSeconds);
            startPause.textContent = 'Start';
            startPause.className = 'ksmo-timer-btn start';

            state.timer.running = false;
            state.timer.seconds = 0;
            state.timer.startedAt = null;
            saveState();
        });

        controls.appendChild(startPause);
        controls.appendChild(reset);
        containerEl.appendChild(display);
        containerEl.appendChild(controls);
        view.appendChild(containerEl);
    };

    renderCounters();
    renderTasks();
    renderTimer();

    const resizerE = document.createElement('div');
    resizerE.className = 'ksmo-resize-e';
    const resizerS = document.createElement('div');
    resizerS.className = 'ksmo-resize-s';
    const resizerSE = document.createElement('div');
    resizerSE.className = 'ksmo-resize-se';

    panel.appendChild(resizerE);
    panel.appendChild(resizerS);
    panel.appendChild(resizerSE);

    let isDragging = false;
    let dragStartX = 0;
    let dragStartY = 0;
    let initialLeft = 0;
    let initialTop = 0;

    const onHeaderMouseDown = (e) => {
        if (state.locked) return;
        if (e.target.closest('.ksmo-icon-btn')) return;
        isDragging = true;
        dragStartX = e.clientX;
        dragStartY = e.clientY;
        initialLeft = state.posX;
        initialTop = state.posY;
        document.addEventListener('mousemove', onMouseMove);
        document.addEventListener('mouseup', onMouseUp);
        e.preventDefault();
    };

    const onMouseMove = (e) => {
        if (!isDragging) return;
        const dx = e.clientX - dragStartX;
        const dy = e.clientY - dragStartY;
        const newPos = clampPos(initialLeft + dx, initialTop + dy, state.width, state.height);
        state.posX = newPos.x;
        state.posY = newPos.y;
        panel.style.left = `${state.posX}px`;
        panel.style.top = `${state.posY}px`;
    };

    const onMouseUp = () => {
        if (isDragging) {
            isDragging = false;
            document.removeEventListener('mousemove', onMouseMove);
            document.removeEventListener('mouseup', onMouseUp);
            saveState();
        }
    };

    header.addEventListener('mousedown', onHeaderMouseDown);

    let isResizing = false;
    let resizeType = '';
    let resizeStartX = 0;
    let resizeStartY = 0;
    let initialWidth = 0;
    let initialHeight = 0;

    const startResize = (e, type) => {
        isResizing = true;
        resizeType = type;
        resizeStartX = e.clientX;
        resizeStartY = e.clientY;
        initialWidth = state.width;
        initialHeight = state.height;
        document.addEventListener('mousemove', onResizeMove);
        document.addEventListener('mouseup', onResizeUp);
        e.preventDefault();
        e.stopPropagation();
    };

    const onResizeMove = (e) => {
        if (!isResizing) return;
        const dx = e.clientX - resizeStartX;
        const dy = e.clientY - resizeStartY;

        let newWidth = initialWidth;
        let newHeight = initialHeight;

        if (resizeType.includes('e')) {
            newWidth = Math.max(220, initialWidth + dx);
        }
        if (resizeType.includes('s')) {
            newHeight = Math.max(300, initialHeight + dy);
        }

        if (state.posX + newWidth > window.innerWidth) {
            newWidth = window.innerWidth - state.posX;
        }
        if (state.posY + newHeight > window.innerHeight) {
            newHeight = window.innerHeight - state.posY;
        }

        state.width = newWidth;
        state.height = newHeight;
        panel.style.width = `${newWidth}px`;
        panel.style.height = `${newHeight}px`;
        updateFontSize();
    };

    const onResizeUp = () => {
        if (isResizing) {
            isResizing = false;
            document.removeEventListener('mousemove', onResizeMove);
            document.removeEventListener('mouseup', onResizeUp);
            saveState();
        }
    };

    resizerE.addEventListener('mousedown', (e) => startResize(e, 'e'));
    resizerS.addEventListener('mousedown', (e) => startResize(e, 's'));
    resizerSE.addEventListener('mousedown', (e) => startResize(e, 'se'));

    lockBtn.addEventListener('mousedown', (e) => {
        e.stopPropagation();
    });

    lockBtn.addEventListener('click', () => {
        state.locked = !state.locked;
        lockBtn.textContent = state.locked ? '🔒' : '🔓';
        lockBtn.title = state.locked ? 'Unlock Position' : 'Lock Position';
        header.classList.toggle('locked', state.locked);
        saveState();
    });

    const closePanel = () => {
        state.visible = false;
        saveState();
        panel.classList.remove('show');
    };

    const openPanel = () => {
        state.visible = true;
        saveState();
        panel.classList.add('show');
    };

    closeBtn.addEventListener('click', closePanel);

    const pin = document.createElement('div');
    pin.className = 'ksmo-pin';
    pin.textContent = '📊';
    pin.style.top = `${state.pinY}px`;

    const pinStyle = document.createElement('style');
    pinStyle.textContent = `
        .ksmo-pin {
            position: fixed;
            right: 0;
            z-index: 2147483647;
            width: 44px;
            height: 44px;
            background: rgba(15, 15, 25, 0.88);
            border-radius: 12px 0 0 12px;
            box-shadow: -4px 4px 20px rgba(0,0,0,0.5);
            border: 1px solid rgba(255, 255, 255, 0.1);
            border-right: none;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 20px;
            cursor: grab;
            transition: transform 0.2s ease, opacity 0.3s ease;
            transform: translateX(34px);
            opacity: 0;
            pointer-events: none;
            user-select: none;
        }
        .ksmo-pin.visible {
            transform: translateX(0);
            opacity: 1;
            pointer-events: auto;
        }
        .ksmo-pin.active {
            cursor: grabbing;
        }
    `;
    document.head.appendChild(pinStyle);

    const BORDER_THRESHOLD = Math.min(50, window.innerWidth * 0.03);
    let hidePinTimeout = null;

    const showPin = () => {
        clearTimeout(hidePinTimeout);
        pin.classList.add('visible');
    };

    const hidePin = () => {
        clearTimeout(hidePinTimeout);
        hidePinTimeout = setTimeout(() => {
            if (!pin.classList.contains('active') && !pin._hovered) {
                pin.classList.remove('visible');
            }
        }, 1200);
    };

    document.addEventListener('mousemove', (e) => {
        const fromRight = window.innerWidth - e.clientX;
        if (fromRight <= BORDER_THRESHOLD) {
            showPin();
        } else {
            hidePin();
        }
    });

    pin.addEventListener('mouseenter', () => {
        pin._hovered = true;
        showPin();
    });

    pin.addEventListener('mouseleave', () => {
        pin._hovered = false;
        hidePin();
    });

    panel.addEventListener('mouseenter', () => {
        pin._hovered = true;
        showPin();
    });

    panel.addEventListener('mouseleave', () => {
        pin._hovered = false;
        hidePin();
    });

    let isPinDragging = false;
    let pinDragStartY = 0;
    let pinStartTop = 0;

    pin.addEventListener('mousedown', (e) => {
        if (e.button !== 0) return;
        isPinDragging = true;
        pin.classList.add('active');
        pinDragStartY = e.clientY;
        pinStartTop = parseInt(pin.style.top, 10);
        document.addEventListener('mousemove', onPinMouseMove);
        document.addEventListener('mouseup', onPinMouseUp);
        e.preventDefault();
        e.stopPropagation();
    });

    const onPinMouseMove = (e) => {
        if (!isPinDragging) return;
        const dy = e.clientY - pinDragStartY;
        const pinHeight = pin.offsetHeight || 44;
        let newTop = Math.max(0, Math.min(window.innerHeight - pinHeight, pinStartTop + dy));
        state.pinY = newTop;
        pin.style.top = `${newTop}px`;
    };

    const onPinMouseUp = () => {
        if (isPinDragging) {
            isPinDragging = false;
            pin.classList.remove('active');
            document.removeEventListener('mousemove', onPinMouseMove);
            document.removeEventListener('mouseup', onPinMouseUp);
            saveState();
            hidePin();
        }
    };

    pin.addEventListener('click', (e) => {
        if (isPinDragging) return;
        e.stopPropagation();
        if (state.visible) {
            closePanel();
        } else {
            openPanel();
        }
    });

    const onResizeWindow = () => {
        const newPos = clampPos(state.posX, state.posY, state.width, state.height);
        state.posX = newPos.x;
        state.posY = newPos.y;
        panel.style.left = `${state.posX}px`;
        panel.style.top = `${state.posY}px`;
        
        const pinHeight = pin.offsetHeight || 44;
        let newPinY = Math.max(0, Math.min(window.innerHeight - pinHeight, state.pinY));
        state.pinY = newPinY;
        pin.style.top = `${newPinY}px`;

        saveState();
    };

    window.addEventListener('resize', onResizeWindow);

    shadow.appendChild(panel);

    const initApp = () => {
        document.body.appendChild(host);
        document.body.appendChild(pin);
        if (state.visible) {
            openPanel();
        }
    };

    if (!document.body) {
        new MutationObserver((_, obs) => {
            if (document.body) {
                initApp();
                obs.disconnect();
            }
        }).observe(document.documentElement, { childList: true });
    } else {
        initApp();
    }

    showPin();
    hidePin();
})();