Ultimate Glow Dashboard

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

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(Tôi đã có Trình quản lý tập lệnh người dùng, hãy cài đặt nó!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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();
})();