(function() {
    if (window.MeshFooter) return;

    const WIDGET_CONFIG = {
        fontAwesome: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css",
        repoUrl: "https://github.com/yourusername/Mesh_Dash_2_0/releases",
        api: {
            version: '/api/system/version-status',
            triggerCheck: '/api/system/check-update',
            performUpdate: '/api/system/start-update',
            status: '/api/status',
            localNode: '/api/local_node/full',
            sse: '/sse',
            command: '/api/console'
        },
        ui: {
            defaultHeight: 350,
            minHeight: 180,
            maxHeightVh: 90,
            maxLogItems: 100
        }
    };

    // ==================== C2 THEMED STYLES ====================
    const STYLES = `
        /* ===== C2 THEME VARIABLES (fallback) ===== */
        :root {
            --bg: #020912;
            --bg1: #060e1c;
            --bg2: #0a1628;
            --bg3: #0d1c34;
            --bg4: #12243f;
            --bd: #152030;
            --bd2: #1c3050;
            --bd3: #263d5e;
            --txt: #bdd4f0;
            --txt2: #5a80a8;
            --txt3: #2e4a68;
            --acc: #00c8f5;
            --acc2: #0090c0;
            --acc-glow: rgba(0,200,245,.13);
            --acc-dim: rgba(0,200,245,.05);
            --ok: #00f090;
            --ok-dim: rgba(0,240,144,.1);
            --warn: #ffa800;
            --warn-dim: rgba(255,168,0,.1);
            --err: #ff3050;
            --err-dim: rgba(255,48,80,.1);
            --pur: #b060ff;
            --pur-dim: rgba(176,96,255,.1);
            --ora: #ff7030;
            --ora-dim: rgba(255,112,48,.1);
            --mono: 'Share Tech Mono', monospace;
            --sans: 'Exo 2', sans-serif;
            --r: 5px;
        }

        #md-ft-root {
            position: fixed;
            bottom: 0;
            left: 0;
            width: 100%;
            z-index: 99999;
            font-family: var(--sans);
            font-size: 13px;
            line-height: 1.5;
            color: var(--txt);
            pointer-events: none;
        }
        #md-ft-root * { box-sizing: border-box; }

        /* ----- Main Bar ----- */
        .md-ft-bar {
            background: var(--bg1);
            border-top: 1px solid var(--bd2);
            height: 36px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 0 12px;
            pointer-events: auto;
            box-shadow: 0 -2px 24px rgba(0,0,0,0.6);
            position: relative;
            color: var(--txt);
        }
        .md-ft-bar::after {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 1px;
            background: linear-gradient(90deg, transparent, var(--acc), transparent);
            opacity: .35;
            pointer-events: none;
        }
        .md-ft-section {
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .md-ft-item {
            display: flex;
            align-items: center;
            gap: 6px;
            font-size: 0.8rem;
        }
        .md-ft-divider {
            color: var(--bd2);
            margin: 0 4px;
        }
        .md-ft-btn {
            background: none;
            border: 1px solid transparent;
            color: var(--txt2);
            cursor: pointer;
            padding: 4px 6px;
            border-radius: var(--r);
            font-size: 0.8rem;
            display: flex;
            align-items: center;
            gap: 4px;
            transition: all .15s;
        }
        .md-ft-btn:hover {
            color: var(--txt);
            background: var(--bg2);
            border-color: var(--bd3);
        }

        /* ----- Drawer ----- */
        .md-ft-drawer {
            background: var(--bg1);
            border-top: 1px solid var(--bd2);
            position: absolute;
            bottom: 36px;
            left: 0;
            width: 100%;
            display: flex;
            flex-direction: column;
            transform: translateY(110%);
            transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
            pointer-events: auto;
            box-shadow: 0 -8px 28px rgba(0,0,0,0.7);
        }
        .md-ft-drawer.md-ft-open {
            transform: translateY(0);
        }
        .md-ft-resize-handle {
            height: 6px;
            width: 100%;
            cursor: ns-resize;
            background: transparent;
            position: relative;
            flex-shrink: 0;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        .md-ft-resize-handle::after {
            content: '';
            width: 30px;
            height: 3px;
            border-radius: 2px;
            background: var(--bd3);
        }
        .md-ft-resize-handle:hover::after {
            background: var(--acc);
        }

        /* ----- Drawer Header & Tabs ----- */
        .md-ft-drawer-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 4px 12px;
            background: var(--bg);
            border-bottom: 1px solid var(--bd2);
            flex-shrink: 0;
        }
        .md-ft-tabs {
            display: flex;
            gap: 2px;
        }
        .md-ft-tab {
            background: none;
            border: 1px solid transparent;
            color: var(--txt2);
            padding: 6px 10px;
            cursor: pointer;
            font-size: 0.8rem;
            border-radius: var(--r);
            display: flex;
            align-items: center;
            gap: 6px;
            position: relative;
            transition: all .15s;
        }
        .md-ft-tab:hover {
            color: var(--txt);
            background: var(--acc-dim);
            border-color: var(--bd3);
        }
        .md-ft-tab.md-ft-active {
            color: var(--acc);
            background: var(--acc-glow);
            border-color: var(--bd3);
            font-weight: 600;
        }
        .md-ft-tab.unread::after {
            content: '';
            position: absolute;
            top: 6px;
            right: 4px;
            width: 6px;
            height: 6px;
            background: var(--acc);
            border-radius: 50%;
            box-shadow: 0 0 5px var(--acc);
        }
        .md-ft-tab.update-avail {
            color: var(--warn);
            animation: md-ft-pulse-text 2s infinite;
        }
        .md-ft-tab-hidden {
            display: none !important;
        }

        /* ----- Tab Content ----- */
        .md-ft-content {
            display: none;
            flex: 1;
            overflow-y: auto;
            padding: 12px;
            font-family: var(--mono);
            font-size: 0.85rem;
            min-height: 0;
            background: var(--bg2);
            color: var(--txt2);
        }
        .md-ft-content.md-ft-active {
            display: block;
        }

        /* ----- Console ----- */
        .md-ft-console-wrapper {
            display: flex;
            flex-direction: column;
            height: 100%;
        }
        .md-ft-console-out {
            flex: 1;
            overflow-y: auto;
            color: var(--txt);
            padding-bottom: 8px;
            white-space: pre-wrap;
            line-height: 1.4;
        }
        .md-ft-console-in-row {
            display: flex;
            gap: 8px;
            border-top: 1px solid var(--bd2);
            padding-top: 8px;
            align-items: center;
        }
        .md-ft-console-prompt {
            color: var(--acc);
            font-weight: bold;
        }
        .md-ft-console-input {
            flex: 1;
            background: transparent;
            border: 1px solid var(--bd2);
            border-radius: var(--r);
            padding: 4px 8px;
            color: var(--txt);
            font-family: var(--mono);
            font-size: inherit;
            outline: none;
        }
        .md-ft-console-input:focus {
            border-color: var(--acc);
            box-shadow: 0 0 0 2px rgba(0,200,245,.08);
        }
        .md-ft-console-input::placeholder {
            color: var(--txt3);
        }
        .md-ft-cmd-echo {
            color: var(--txt3);
            margin: 4px 0;
            font-style: italic;
        }
        .md-ft-cmd-resp {
            color: var(--txt);
            margin-bottom: 12px;
            border-left: 2px solid var(--acc);
            padding-left: 8px;
        }

        /* ----- Vitals Cards ----- */
        .md-ft-vitals-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
            gap: 10px;
        }
        .md-ft-card {
            background: var(--bg3);
            border: 1px solid var(--bd2);
            border-radius: var(--r);
            padding: 10px;
        }
        .md-ft-card-title {
            color: var(--txt3);
            font-size: 0.7rem;
            text-transform: uppercase;
            font-weight: 700;
            margin-bottom: 6px;
            display: flex;
            align-items: center;
            gap: 5px;
            font-family: var(--mono);
        }
        .md-ft-card-title i {
            color: var(--txt3);
        }
        .md-ft-data-row {
            display: flex;
            justify-content: space-between;
            margin-bottom: 2px;
            font-size: 0.75rem;
        }
        .md-ft-data-val {
            color: var(--txt);
            font-weight: 500;
            font-family: var(--mono);
        }
        .md-ft-accent-text {
            color: var(--acc);
        }

        /* ----- Log Rows ----- */
        .md-ft-log-row {
            border-bottom: 1px solid var(--bd);
            padding: 2px 0;
        }
        .md-ft-ts {
            color: var(--txt3);
            font-size: 0.8em;
            margin-right: 6px;
        }
        .md-ft-dot {
            width: 8px;
            height: 8px;
            border-radius: 50%;
            background: var(--txt3);
            display: inline-block;
        }
        .md-ft-dot.connected {
            background: var(--ok);
            box-shadow: 0 0 6px var(--ok);
        }
        .md-ft-dot.connecting {
            background: var(--warn);
            box-shadow: 0 0 6px var(--warn);
        }

        /* ----- SSE Indicator ----- */
        .md-ft-sse-dot {
            color: var(--txt3);
        }
        .md-ft-sse-dot.active {
            color: var(--ok);
            text-shadow: 0 0 5px var(--ok);
        }

        /* ----- Version Badge ----- */
        .md-ft-badge {
            background: var(--bg3);
            color: var(--txt2);
            padding: 2px 8px;
            border-radius: 12px;
            font-size: 0.75rem;
            text-decoration: none;
            display: flex;
            align-items: center;
            gap: 5px;
            transition: all 0.2s;
            border: 1px solid var(--bd2);
            cursor: default;
        }
        .md-ft-badge i {
            color: var(--txt3);
        }
        .md-ft-badge.update-needed {
            background: var(--warn-dim);
            color: var(--warn);
            border-color: rgba(255,168,0,.3);
            animation: md-ft-pulse 2s infinite;
            cursor: pointer;
        }
        .md-ft-badge.update-needed:hover {
            background: rgba(255,168,0,.2);
        }
        .md-ft-badge.beta {
            background: var(--pur-dim);
            color: var(--pur);
            border-color: rgba(176,96,255,.3);
            cursor: help;
        }
        .md-ft-badge.current {
            background: var(--ok-dim);
            color: var(--ok);
            border-color: rgba(0,240,144,0.3);
            cursor: default;
        }

        /* ----- System Buttons ----- */
        .md-ft-sys-btn {
            margin-top: 15px;
            width: 100%;
            padding: 8px;
            border: 1px solid var(--bd2);
            background: var(--bg2);
            color: var(--txt);
            border-radius: var(--r);
            cursor: pointer;
            font-size: 0.75rem;
            text-align: left;
            font-family: var(--sans);
        }
        .md-ft-sys-btn:hover {
            background: var(--bg3);
            border-color: var(--bd3);
            color: var(--acc);
        }
        .md-ft-sys-btn i {
            margin-right: 8px;
            color: var(--acc);
        }

        /* ----- Animations ----- */
        @keyframes md-ft-pulse {
            0% { box-shadow: 0 0 0 0 rgba(255,168,0,0.4); }
            70% { box-shadow: 0 0 0 4px rgba(255,168,0,0); }
            100% { box-shadow: 0 0 0 0 rgba(255,168,0,0); }
        }
        @keyframes md-ft-pulse-text {
            0% { opacity: 1; }
            50% { opacity: 0.6; }
            100% { opacity: 1; }
        }
    `;

    const TEMPLATE = `
        <div id="md-ft-drawer" class="md-ft-drawer" style="height: ${WIDGET_CONFIG.ui.defaultHeight}px;">
            <div id="md-ft-handle" class="md-ft-resize-handle"></div>
            <div class="md-ft-drawer-header">
                <div class="md-ft-tabs">
                    <button class="md-ft-tab md-ft-active" data-tab="md-ft-tab-vitals"><i class="fas fa-microchip"></i> Vitals</button>
                    <button class="md-ft-tab" data-tab="md-ft-tab-console"><i class="fas fa-terminal"></i> Console</button>
                    <button class="md-ft-tab" data-tab="md-ft-tab-stream"><i class="fas fa-rss"></i> Stream</button>
                    <button class="md-ft-tab" data-tab="md-ft-tab-chat"><i class="fas fa-comments"></i> Chat</button>
                    <button class="md-ft-tab" data-tab="md-ft-tab-sensors"><i class="fas fa-gauge"></i> Sensors</button>
                    <button class="md-ft-tab" data-tab="md-ft-tab-system"><i class="fas fa-gears"></i> System</button>
                    <button class="md-ft-tab md-ft-tab-hidden" id="md-ft-tab-btn-update" data-tab="md-ft-tab-update"><i class="fas fa-cloud-download-alt"></i> Update</button>
                </div>
                <div class="md-ft-section">
                    <span id="md-ft-sse-ind" class="md-ft-sse-dot" title="Live Stream">●</span>
                    <button class="md-ft-btn" id="md-ft-clear-btn" title="Clear Persistence"><i class="fas fa-eraser"></i></button>
                    <button class="md-ft-btn" id="md-ft-close-btn" title="Close"><i class="fas fa-chevron-down"></i></button>
                </div>
            </div>
            <div id="md-ft-tab-vitals" class="md-ft-content md-ft-active">
                <div style="padding: 8px; text-align: center;">
                    <button class="md-ft-sys-btn" id="md-ft-force-update-btn">
                        <i class="fas fa-sync-alt"></i> Force Reinstall MeshDash
                    </button>
                </div>
                <div id="md-ft-vitals-container" class="md-ft-vitals-grid">Initialising Vitals...</div>
            </div>
            <div id="md-ft-tab-console" class="md-ft-content">
                <div class="md-ft-console-wrapper">
                    <div id="md-ft-console-out" class="md-ft-console-out"></div>
                    <div class="md-ft-console-in-row">
                        <span class="md-ft-console-prompt">meshtastic &gt;</span>
                        <input type="text" id="md-ft-console-in" class="md-ft-console-input" placeholder="..." autocomplete="off" spellcheck="false">
                    </div>
                </div>
            </div>
            <div id="md-ft-tab-stream" class="md-ft-content"></div>
            <div id="md-ft-tab-chat" class="md-ft-content"></div>
            <div id="md-ft-tab-sensors" class="md-ft-content"></div>
            <div id="md-ft-tab-system" class="md-ft-content">
                <div style="max-width: 400px;">
                    <p style="color: var(--txt3); margin-bottom: 10px;">System messages appear here.</p>
                </div>
            </div>
            <div id="md-ft-tab-update" class="md-ft-content">
                <div class="md-ft-console-wrapper">
                    <div id="md-ft-update-log" class="md-ft-console-out"></div>
                    <div class="md-ft-console-in-row" id="md-ft-update-input-row" style="display:none;">
                        <span class="md-ft-console-prompt" style="color:var(--warn)">CONFIRM (Y/N) &gt;</span>
                        <input type="text" id="md-ft-update-in" class="md-ft-console-input" placeholder="Type Y to update, N to cancel..." autocomplete="off">
                    </div>
                </div>
            </div>
        </div>
        <div class="md-ft-bar">
            <div class="md-ft-section">
                <div class="md-ft-item">
                    <i class="fas fa-cubes md-ft-accent-text"></i>
                    <strong>MeshDash</strong>
                </div>
                <div id="md-ft-update-wrapper">
                    <button id="md-ft-ver-badge" class="md-ft-badge current" title="Checking version...">
                        <i class="fas fa-circle-notch fa-spin" id="md-ft-ver-icon"></i>
                        <span id="md-ft-ver-text">Init...</span>
                    </button>
                </div>
            </div>
            <div class="md-ft-section">
                <div class="md-ft-item"><span id="md-ft-status-dot" class="md-ft-dot"></span> <span id="md-ft-status-text">Disconnected</span></div>
                <span class="md-ft-divider">|</span>
                <button class="md-ft-btn" id="md-ft-trigger-console"><i class="fas fa-terminal"></i> Console</button>
            </div>
        </div>
    `;

    // ── Human-readable status map ──────────────────────────────────────────
    const STATUS_LABELS = {
        'current':      'up to date ✓',
        'beta':         'running beta',
        'update_needed':'update available'
    };

    class MeshFooterController {
        constructor() {
            this.history     = JSON.parse(localStorage.getItem('md-ft-history') || '[]');
            this.historyIdx  = -1;
            this.isDragging  = false;
            this.versionData = null;
            this.updatePending = false;
            
            // Guard against multiple overlapping checks
            this._versionCheckInProgress = false;

            // ── FIX 1: Debounced savePersistence ──────────────────────────
            this._saveTimer = null;
            this.savePersistence = () => {
                if (this._saveTimer) return;
                this._saveTimer = setTimeout(() => {
                    this._saveTimer = null;
                    this._doSavePersistence();
                }, 1000);
            };

            // ── FIX 2: system_update dedup ────────────────────────────────
            this._lastSystemMsg = '';
            this._systemMsgCount = 0;
        }

        init() {
            this.injectStyles();
            this.injectHTML();
            this.bindEvents();
            this.loadPersistence();
            this.setupSSE();
            this.startRefreshLoops();
            setTimeout(() => this.checkVersion(true), 3000);
        }

        injectStyles() {
            const s = document.createElement('style');
            s.textContent = STYLES;
            document.head.appendChild(s);
            const fa = document.createElement('link');
            fa.rel = 'stylesheet';
            fa.href = WIDGET_CONFIG.fontAwesome;
            document.head.appendChild(fa);
        }

        injectHTML() {
            const root = document.createElement('div');
            root.id = 'md-ft-root';
            root.innerHTML = TEMPLATE;
            document.body.appendChild(root);
        }

        bindEvents() {
            const get = id => document.getElementById(id);

            document.querySelectorAll('.md-ft-tab').forEach(t => t.onclick = () => {
                this.switchTab(t.dataset.tab);
                this.savePersistence();
            });

            get('md-ft-console-in').onkeydown = e => {
                if (e.key === 'Enter')     this.runConsoleCmd();
                if (e.key === 'ArrowUp')   this.browseHistory(-1);
                if (e.key === 'ArrowDown') this.browseHistory(1);
            };

            get('md-ft-update-in').onkeydown = e => {
                if (e.key !== 'Enter') return;
                const val = e.target.value.trim().toUpperCase();
                if (val === 'Y' || val === 'YES') {
                    this.executeUpdate();
                } else if (val === 'N' || val === 'NO') {
                    this.logUpdate('❌ Update cancelled by user.');
                    get('md-ft-update-input-row').style.display = 'none';
                    this.updatePending = false;
                } else {
                    this.logUpdate("⚠️ Invalid input. Type 'Y' to update or 'N' to cancel.");
                    e.target.value = '';
                }
            };

            get('md-ft-trigger-console').onclick = () => {
                this.toggleDrawer(true);
                this.switchTab('md-ft-tab-console');
            };
            get('md-ft-close-btn').onclick    = () => this.toggleDrawer(false);
            get('md-ft-clear-btn').onclick    = () => this.wipeEverything();
            get('md-ft-ver-badge').onclick    = () => this.handleVersionClick();
            get('md-ft-force-update-btn').onclick = () => this.triggerForceUpdate();

            // Resize handle
            const handle = get('md-ft-handle');
            const drawer = get('md-ft-drawer');
            handle.onmousedown = () => {
                this.isDragging = true;
                document.onmousemove = me => {
                    if (!this.isDragging) return;
                    let h = window.innerHeight - me.clientY - 36;
                    h = Math.max(WIDGET_CONFIG.ui.minHeight, Math.min(h, window.innerHeight * 0.9));
                    drawer.style.height = h + 'px';
                };
                document.onmouseup = () => {
                    this.isDragging = false;
                    localStorage.setItem('md-ft-height', drawer.style.height);
                };
            };
        }

        // ── FIX 3: checkVersion is now fully async & guarded ─────────────────
        async checkVersion(initialLoad = false) {
            if (this._versionCheckInProgress) return;
            this._versionCheckInProgress = true;

            console.log("🔍 MeshFooter: Fetching version data from:", WIDGET_CONFIG.api.version); 
            
            try {
                const r = await fetch(WIDGET_CONFIG.api.version);
                
                if (!r.ok) {
                    console.error(`❌ MeshFooter: Server responded with HTTP ${r.status}`);
                    throw new Error(`HTTP ${r.status}`);
                }
                
                const d = await r.json();
                
                console.log("✅ MeshFooter: Version check successful! Received:", d); 
                
                this.versionData = d;
                this.renderVersionBadge();
                if (d.status === 'update_needed') {
                    this.activateUpdateMode(d);
                }
                this._versionCheckInProgress = false;
                return d;
            } catch (err) {
                console.error('❌ MeshFooter: Version check completely failed!', err); 
                const text = document.getElementById('md-ft-ver-text');
                if (text) text.textContent = 'Offline';
                this._versionCheckInProgress = false;
                return null;
            }
        }

        async triggerForceUpdate() {
            if (!confirm('FORCE UPDATE: This will overwrite system files even if you are up to date. Continue?')) return;
            const d = await this.checkVersion();
            const forceData = { ...(d || {}), status: 'update_needed', isForced: true };
            this.updatePending = false;
            this.activateUpdateMode(forceData);
        }

        activateUpdateMode(data) {
            const updateTabBtn = document.getElementById('md-ft-tab-btn-update');
            updateTabBtn.classList.remove('md-ft-tab-hidden');
            updateTabBtn.classList.add('update-avail');

            if (!this.updatePending) {
                this.updatePending = true;
                this.toggleDrawer(true);
                this.switchTab('md-ft-tab-update');

                const logDiv = document.getElementById('md-ft-update-log');
                logDiv.innerHTML = '';

                if (data.isForced) {
                    this.logUpdate(`🛠️ <b>FORCE INSTALL TRIGGERED</b>`);
                    this.logUpdate(`Current: v${data.local || '?'} | Target: v${data.remote || data.local || '?'}`);
                } else {
                    this.logUpdate(`🚀 <b>UPDATE AVAILABLE:</b> v${data.local} → v${data.remote}`);
                }
                this.logUpdate('------------------------------------------------');
                this.logUpdate('⚠️  <b>IMPORTANT NOTICE:</b> This process replaces core files.');
                this.logUpdate('   - <b>Database &amp; Config:</b> PRESERVED (Safe)');
                this.logUpdate('   - <b>Service Mode:</b> Will AUTO-RESTART (Recommended)');
                this.logUpdate('------------------------------------------------');
                this.logUpdate('Do you want to download and install now?');

                const inputRow = document.getElementById('md-ft-update-input-row');
                inputRow.style.display = 'flex';
                const inp = document.getElementById('md-ft-update-in');
                inp.value = '';
                inp.focus();
            }
        }

        logUpdate(msg) {
            const container = document.getElementById('md-ft-update-log');
            if (!container) return;
            const div = document.createElement('div');
            const ts = new Date().toLocaleTimeString([], { hour12: false });
            div.innerHTML = `<span class="md-ft-ts">${ts}</span> ${msg}`;
            
            requestAnimationFrame(() => {
                container.appendChild(div);
                container.scrollTop = container.scrollHeight;
            });
        }

        async executeUpdate() {
            const input    = document.getElementById('md-ft-update-in');
            const inputRow = document.getElementById('md-ft-update-input-row');
            input.disabled = true;
            inputRow.style.display = 'none';
            this.logUpdate('<span style="color:var(--warn)">Initiating Update Sequence...</span>');

            try {
                const response = await fetch(WIDGET_CONFIG.api.performUpdate, { method: 'POST' });
                const result   = await response.json();
                if (response.ok) {
                    this.logUpdate('⬇️  Downloading update package...');
                    this.logUpdate('✅  Download Complete.');
                    this.logUpdate('🔄  <b>RESTARTING SERVER...</b>');
                    this.pollForLife();
                } else {
                    throw new Error(result.detail || 'Unknown Error');
                }
            } catch (err) {
                this.logUpdate(`<span style="color:var(--err)">❌ Error: ${err.message}</span>`);
                input.disabled = false;
                inputRow.style.display = 'flex';
            }
        }

        pollForLife() {
            let spinIdx = 0;
            const spinnerChars = ['|', '/', '-', '\\'];
            const flavorText   = ['Restarting...', 'Loading...', 'Connecting...', 'Initializing...'];

            const statusLine = document.createElement('div');
            statusLine.className = 'md-ft-log-row';
            statusLine.style.color = 'var(--warn)';
            statusLine.innerHTML = `<span class="md-ft-ts">SYSTEM</span> <span id="md-ft-reboot-msg">Initializing reboot...</span> <span id="md-ft-reboot-spinner">|</span>`;
            document.getElementById('md-ft-update-log').appendChild(statusLine);

            let cycles = 0;
            const interval = setInterval(async () => {
                const spinner = document.getElementById('md-ft-reboot-spinner');
                const msgEl   = document.getElementById('md-ft-reboot-msg');
                if (spinner) {
                    spinIdx = (spinIdx + 1) % 4;
                    spinner.innerText = spinnerChars[spinIdx];
                    if (cycles % 5 === 0 && msgEl) {
                        msgEl.innerText = flavorText[Math.floor((cycles / 5) % flavorText.length)];
                    }
                }
                cycles++;
                try {
                    const resp = await fetch(WIDGET_CONFIG.api.status, { cache: 'no-store' });
                    if (resp.ok) {
                        clearInterval(interval);
                        if (msgEl)   msgEl.innerText   = 'System Online!';
                        if (spinner) spinner.innerText = '✅';
                        this.logUpdate('✅  <b>SUCCESS!</b> Reloading...');
                        setTimeout(() => location.reload(), 1500);
                    }
                } catch (e) { /* server still restarting */ }
            }, 2000);
        }

        renderVersionBadge() {
            if (!this.versionData) return;
            const badge = document.getElementById('md-ft-ver-badge');
            const icon  = document.getElementById('md-ft-ver-icon');
            const text  = document.getElementById('md-ft-ver-text');
            const d     = this.versionData;

            badge.className = 'md-ft-badge';
            icon.className  = '';

            if (d.status === 'update_needed') {
                badge.classList.add('update-needed');
                icon.className = 'fas fa-cloud-download-alt';
                text.innerHTML = `v${d.local} &rarr; v${d.remote}`;
            } else if (d.status === 'beta') {
                badge.classList.add('beta');
                icon.className = 'fas fa-flask';
                text.textContent = `v${d.local} (Beta)`;
            } else {
                badge.classList.add('current');
                icon.className = 'fas fa-check';
                text.textContent = `v${d.local}`;
            }
        }

        async handleVersionClick() {
            if (!this.versionData) return;
            const icon = document.getElementById('md-ft-ver-icon');
            icon.className = 'fas fa-circle-notch fa-spin';

            if (this.versionData.status === 'update_needed') {
                this.updatePending = false;
                this.activateUpdateMode(this.versionData);
                this.renderVersionBadge();
                return;
            }

            const data = await this.checkVersion();
            if (data) {
                const label = STATUS_LABELS[data.status] || data.status || 'unknown';
                this.log('system', `Version check: <b>v${data.local}</b> — ${label}`);
            } else {
                this.log('system', 'Version check failed — server unreachable.');
            }
        }

        switchTab(tabId) {
            const tabBtn = document.querySelector(`[data-tab="${tabId}"]`);
            if (!tabBtn) return;
            document.querySelectorAll('.md-ft-tab').forEach(t => t.classList.remove('md-ft-active'));
            document.querySelectorAll('.md-ft-content').forEach(c => c.classList.remove('md-ft-active'));
            tabBtn.classList.add('md-ft-active');
            tabBtn.classList.remove('unread');
            const target = document.getElementById(tabId);
            if (target) {
                target.classList.add('md-ft-active');
                target.scrollTop = target.scrollHeight;
            }
            if (tabId === 'md-ft-tab-console') setTimeout(() => document.getElementById('md-ft-console-in')?.focus(), 50);
            if (tabId === 'md-ft-tab-update')  setTimeout(() => document.getElementById('md-ft-update-in')?.focus(), 50);
            localStorage.setItem('md-ft-active-tab', tabId);
        }

        toggleDrawer(state) {
            const d = document.getElementById('md-ft-drawer');
            const isOpen = state === undefined ? !d.classList.contains('md-ft-open') : state;
            isOpen ? d.classList.add('md-ft-open') : d.classList.remove('md-ft-open');
            localStorage.setItem('md-ft-is-open', isOpen);
        }

        _doSavePersistence() {
            try {
                const state = {
                    stream:  document.getElementById('md-ft-tab-stream').innerHTML,
                    chat:    document.getElementById('md-ft-tab-chat').innerHTML,
                    sensors: document.getElementById('md-ft-tab-sensors').innerHTML,
                    system:  document.getElementById('md-ft-tab-system').innerHTML,
                    console: document.getElementById('md-ft-console-out').innerHTML
                };
                localStorage.setItem('md-ft-state', JSON.stringify(state));
            } catch(e) { /* localStorage full or unavailable */ }
        }

        loadPersistence() {
            try {
                const savedState = localStorage.getItem('md-ft-state');
                if (savedState) {
                    const state = JSON.parse(savedState);
                    document.getElementById('md-ft-tab-stream').innerHTML  = state.stream  || '';
                    document.getElementById('md-ft-tab-chat').innerHTML    = state.chat    || '';
                    document.getElementById('md-ft-tab-sensors').innerHTML = state.sensors || '';
                    document.getElementById('md-ft-tab-system').innerHTML  = state.system  || document.getElementById('md-ft-tab-system').innerHTML;
                    document.getElementById('md-ft-console-out').innerHTML = state.console || 'CLI Bridge Ready.';
                }
                const savedHeight = localStorage.getItem('md-ft-height');
                if (savedHeight) document.getElementById('md-ft-drawer').style.height = savedHeight;
                // Default closed on load. Only opens if checkVersion triggers activateUpdateMode.
                const activeTab = localStorage.getItem('md-ft-active-tab');;
                if (activeTab) this.switchTab(activeTab);
            } catch(e) { /* corrupt storage — ignore */ }
        }

        wipeEverything() {
            if (confirm('Clear all log history and persistence?')) {
                localStorage.clear();
                location.reload();
            }
        }

        async runConsoleCmd() {
            const input  = document.getElementById('md-ft-console-in');
            const output = document.getElementById('md-ft-console-out');
            const cmd    = input.value.trim();
            if (!cmd) return;

            this.history.unshift(cmd);
            if (this.history.length > 50) this.history.pop();
            localStorage.setItem('md-ft-history', JSON.stringify(this.history));
            this.historyIdx = -1;

            const echo = document.createElement('div');
            echo.className   = 'md-ft-cmd-echo';
            echo.textContent = `> meshtastic ${cmd}`;
            output.appendChild(echo);
            input.value = '';

            try {
                const res  = await fetch(WIDGET_CONFIG.api.command, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ command: cmd })
                });
                const text = await res.text();
                const resp = document.createElement('div');
                resp.className   = 'md-ft-cmd-resp';
                resp.textContent = text;
                output.appendChild(resp);
                this.savePersistence();
            } catch (err) {
                this.log('system', `Console Error: ${err.message}`);
            }
            output.scrollTop = output.scrollHeight;
        }

        browseHistory(dir) {
            const input = document.getElementById('md-ft-console-in');
            this.historyIdx += dir;
            if (this.historyIdx < -1)                       this.historyIdx = -1;
            if (this.historyIdx >= this.history.length)     this.historyIdx = this.history.length - 1;
            input.value = this.historyIdx === -1 ? '' : this.history[this.historyIdx];
        }

        setupSSE() {
            const source = new EventSource(WIDGET_CONFIG.api.sse);

            source.onopen = () => {
                document.getElementById('md-ft-sse-ind').classList.add('active');
                document.getElementById('md-ft-status-dot').className = 'md-ft-dot connected';
                document.getElementById('md-ft-status-text').textContent = 'Connected';
            };
            source.onerror = (e) => {
                if (e.target.readyState === EventSource.CLOSED) return;
                
                document.getElementById('md-ft-sse-ind').classList.remove('active');
                document.getElementById('md-ft-status-dot').className = 'md-ft-dot connecting';
                document.getElementById('md-ft-status-text').textContent = 'Reconnecting...';
            };

            source.addEventListener('system_update', e => {
                try {
                    const data = JSON.parse(e.data);
                    const msg  = (data.message || String(e.data) || '').trim();
                    if (!msg) return;

                    if (msg === this._lastSystemMsg) {
                        this._systemMsgCount++;
                        const lastRow = document.getElementById('md-ft-tab-system')?.lastElementChild;
                        if (lastRow) {
                            const counter = lastRow.querySelector('.md-ft-dup-count');
                            if (counter) {
                                counter.textContent = ` (×${this._systemMsgCount})`;
                            } else {
                                const span = document.createElement('span');
                                span.className = 'md-ft-dup-count';
                                span.style.cssText = 'color:var(--txt3);font-size:0.75em;';
                                span.textContent = ` (×${this._systemMsgCount})`;
                                lastRow.appendChild(span);
                            }
                        }
                    } else {
                        this._lastSystemMsg  = msg;
                        this._systemMsgCount = 1;
                        this.log('system', `<span class="md-ft-accent-text">[SYS]</span> ${msg}`);
                    }

                    if (msg.toLowerCase().includes('update available')) {
                        this.checkVersion();
                    }

                    this.savePersistence();
                } catch(err) { /* malformed SSE data */ }
            });

            source.addEventListener('packet', e => {
                try {
                    const pkt  = JSON.parse(e.data);
                    const type = pkt.app_packet_type || 'Data';
                    const from = pkt.fromId || 'Unknown';
                    this.log('stream', `[${type}] From ${from}`);
                    if (type === 'Message') {
                        this.log('chat', `<b class="md-ft-accent-text">${from}:</b> ${pkt.decoded?.payload || ''}`);
                    }
                    if (type === 'Telemetry') {
                        const met = pkt.decoded?.telemetry?.deviceMetrics || {};
                        if (met.batteryLevel !== undefined) {
                            this.log('sensors', `<b>${from}:</b> Bat ${met.batteryLevel}% | ${met.voltage?.toFixed(2)}V`);
                        }
                    }
                    this.savePersistence();
                } catch(err) { /* malformed packet */ }
            });
        }

        log(target, html) {
            const container = document.getElementById(`md-ft-tab-${target}`);
            if (!container) return;
            const div = document.createElement('div');
            div.className = 'md-ft-log-row';
            const ts = new Date().toLocaleTimeString([], { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
            div.innerHTML = `<span class="md-ft-ts">${ts}</span> ${html}`;
            
            requestAnimationFrame(() => {
                container.appendChild(div);
                
                const tabBtn = document.querySelector(`[data-tab="md-ft-tab-${target}"]`);
                if (tabBtn && !tabBtn.classList.contains('md-ft-active')) tabBtn.classList.add('unread');

                while (container.childElementCount > WIDGET_CONFIG.ui.maxLogItems) container.removeChild(container.firstChild);
                if (container.classList.contains('md-ft-active')) container.scrollTop = container.scrollHeight;
            });
        }

        renderVitals(data) {
            const container = document.getElementById('md-ft-vitals-container');
            if (!container) return;
            const g = (path, fallback = '-') =>
                path.split('.').reduce((obj, key) => (obj != null && obj[key] !== undefined) ? obj[key] : fallback, data);

            requestAnimationFrame(() => {
                container.innerHTML = `
                    <div class="md-ft-card">
                        <div class="md-ft-card-title"><i class="fas fa-id-card"></i> Node Identity</div>
                        <div class="md-ft-data-row"><span>Name</span><span class="md-ft-data-val md-ft-accent-text">${g('long_name', 'Unnamed')}</span></div>
                        <div class="md-ft-data-row"><span>ID</span><span class="md-ft-data-val">${g('node_id_hex', '00000000').replace('!','')}</span></div>
                        <div class="md-ft-data-row"><span>Role</span><span class="md-ft-data-val">${g('role')}</span></div>
                    </div>
                    <div class="md-ft-card">
                        <div class="md-ft-card-title"><i class="fas fa-bolt"></i> System Vitals</div>
                        <div class="md-ft-data-row"><span>Battery</span><span class="md-ft-data-val">${g('battery_level')}%</span></div>
                        <div class="md-ft-data-row"><span>Uptime</span><span class="md-ft-data-val">${this.formatUptime(g('uptime_seconds', 0))}</span></div>
                    </div>
                    <div class="md-ft-card">
                        <div class="md-ft-card-title"><i class="fas fa-microchip"></i> Hardware</div>
                        <div class="md-ft-data-row"><span>Model</span><span class="md-ft-data-val">${g('hardware_model_string', 'Unknown')}</span></div>
                        <div class="md-ft-data-row"><span>Firmware</span><span class="md-ft-data-val">${g('firmware_version')}</span></div>
                    </div>
                    <div class="md-ft-card">
                        <div class="md-ft-card-title"><i class="fas fa-broadcast-tower"></i> LoRa Status</div>
                        <div class="md-ft-data-row"><span>Air Util</span><span class="md-ft-data-val">${Number(g('channel_utilization', 0)).toFixed(1)}%</span></div>
                        <div class="md-ft-data-row"><span>TX Power</span><span class="md-ft-data-val">${g('lora_tx_power', '-')} dBm</span></div>
                    </div>`;
            });
        }

        formatUptime(s) {
            s = Number(s) || 0;
            const d = Math.floor(s / 86400);
            const h = Math.floor((s % 86400) / 3600);
            const m = Math.floor((s % 3600) / 60);
            return d > 0 ? `${d}d ${h}h` : `${h}h ${m}m`;
        }

        startRefreshLoops() {
            const refreshVitals = () =>
                fetch(WIDGET_CONFIG.api.localNode)
                    .then(r => r.json())
                    .then(d => this.renderVitals(d))
                    .catch(() => {});
            refreshVitals();
            setInterval(refreshVitals, 20000);

            setInterval(() => this.checkVersion(false), 600000);
        }
    }

    window.MeshFooter = new MeshFooterController();
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => window.MeshFooter.init());
    } else {
        window.MeshFooter.init();
    }
})();