(function () {
    let latestSections = {};
    let latestContextActions = { global: [], context: [] };
    let activeKey = 'timer';
    let overviewFilter = null;
    let ws = null;
    let pollTimer = null;
    let wsReconnectTimer = null;
    let latestNotificationCount = 0;
    let latestNotifications = [];
    let switchCaseModalInstance = null;
    let quickNoteDraft = '';
    let quickNoteHintState = {
        message: 'Tip: gemmer som kommentar på aktiv/åben sag.',
        level: 'muted'
    };
    let switchCaseState = {
        activeTimer: null,
        decision: 'unchanged',
        timers: { active: [], paused: [] },
        recentCases: [],
        unassignedCases: []
    };
    let noteEditorState = {
        editingId: 0,
        title: '',
        content: ''
    };
    let noteTargetModalInstance = null;
    let noteTargetState = {
        target: 'case',
        noteId: 0
    };
    const LOCAL_NOTES_KEY = 'bmc_bottom_bar_notes_v1';
    let notesApiUnavailable = false;

    function byId(id) {
        return document.getElementById(id);
    }

    function escapeHtml(value) {
        return String(value)
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;');
    }

    function loadLocalNotes() {
        try {
            const raw = window.localStorage.getItem(LOCAL_NOTES_KEY);
            const parsed = raw ? JSON.parse(raw) : [];
            return Array.isArray(parsed) ? parsed : [];
        } catch (e) {
            return [];
        }
    }

    function saveLocalNotes(notes) {
        try {
            window.localStorage.setItem(LOCAL_NOTES_KEY, JSON.stringify(Array.isArray(notes) ? notes : []));
        } catch (e) {
            // Ignore storage failures (private mode/quota)
        }
    }

    function hydrateNotesFromLocalIfNeeded(sections) {
        const target = sections || {};
        const notes = target.notes || { list: [], count: 0 };
        const localNotes = loadLocalNotes();
        const remoteList = Array.isArray(notes.list) ? notes.list : [];

        if (!notesApiUnavailable && remoteList.length > 0) {
            return target;
        }

        target.notes = {
            count: localNotes.length,
            list: localNotes
                .slice()
                .sort(function (a, b) {
                    return Number(b.is_pinned || 0) - Number(a.is_pinned || 0)
                        || String(b.updated_at || '').localeCompare(String(a.updated_at || ''));
                })
        };
        return target;
    }

    async function fetchBottomBarState() {
        const contextPath = encodeURIComponent(window.location.pathname || '/');
        const response = await fetch('/api/v1/bottom-bar/state?context=' + contextPath, {
            credentials: 'same-origin',
            headers: {
                'Accept': 'application/json'
            }
        });

        if (!response.ok) {
            const error = new Error('Could not load bottom bar state');
            error.status = response.status;
            throw error;
        }

        return response.json();
    }

    function disableBottomBarAuthRetry(reason) {
        stopPolling();
        if (wsReconnectTimer) {
            window.clearTimeout(wsReconnectTimer);
            wsReconnectTimer = null;
        }
        if (ws && ws.readyState === WebSocket.OPEN) {
            try {
                ws.close(1000, 'auth-failed');
            } catch (_) {
                // Ignore close failures
            }
        }
        setVisibility(false);
        console.info('Bottom bar disabled due to auth state:', reason || 'unauthorized');
    }

    function applyState(data) {
        if (data && data.enabled) {
            latestSections = data.sections || {};
            latestSections = hydrateNotesFromLocalIfNeeded(latestSections);
            latestContextActions = (latestSections.context_actions || { global: [], context: [] });
            latestNotificationCount = Number((((data || {}).notifications || {}).count) || 0);
            latestNotifications = (((data || {}).notifications || {}).items || []);
            syncBossTabVisibility();
            updateBar(latestSections);
            updateActivityZone();
            const focusedId = document.activeElement && document.activeElement.id;
            const keepCurrentRender = activeKey === 'notes' && (focusedId === 'bbNoteTitleInput' || focusedId === 'bbNoteContentInput');
            if (!keepCurrentRender) {
                renderTabPanel();
            }
            setVisibility(true);
            return;
        }
        setVisibility(false);
    }

    function setVisibility(enabled) {
        const shell = byId('globalBottomBar');
        if (!shell) {
            return;
        }

        if (enabled) {
            shell.hidden = false;
            window.requestAnimationFrame(function () {
                shell.classList.add('is-visible');
            });
        } else {
            shell.classList.remove('is-visible');
            window.setTimeout(function () {
                if (!shell.classList.contains('is-visible')) {
                    shell.hidden = true;
                }
            }, 320);
        }

        document.body.classList.toggle('bottom-bar-visible', !!enabled);
        if (!enabled) {
            document.body.classList.remove('bottom-bar-expanded');
        }
    }

    function setExpanded(expanded) {
        const shell = byId('globalBottomBar');
        const toggle = byId('bbSheetToggle');
        const panel = byId('bbSheetPanel');
        if (!shell || !toggle || !panel) {
            return;
        }

        shell.classList.toggle('is-expanded', !!expanded);
        document.body.classList.toggle('bottom-bar-expanded', !!expanded);
        toggle.setAttribute('aria-expanded', expanded ? 'true' : 'false');
        panel.setAttribute('aria-hidden', expanded ? 'false' : 'true');
    }

    function syncBossTabVisibility() {
        const bossBtn = document.querySelector('.bb-tab-btn[data-bb-tab="boss"]');
        if (!bossBtn) {
            return;
        }

        bossBtn.classList.remove('d-none');
    }

    function getCounts(sections) {
        const mail = sections.mail || {};
        const cases = sections.cases || {};
        const urgent = sections.urgent || {};
        const timer = sections.timer || {};
        const kuma = sections.kuma || {};
        const eset = sections.eset || {};
        const unassigned = sections.unassigned || {};

        return {
            mail: Number(mail.unread || 0),
            cases: Number(cases.open || 0),
            urgent: Number(urgent.count || 0),
            unassigned: Number(unassigned.count || 0),
            timer: Number(timer.active_count || 0),
            kuma: Number(kuma.down || 0),
            eset: Number(eset.incidents || 0)
        };
    }

    function detailTextFor(key, sections) {
        const counts = getCounts(sections);
        const nameMap = {
            mail: 'Ubesvarede mails',
            cases: 'Åbne sager',
            urgent: 'Hastesager',
            unassigned: 'Sager uden ansvarlig',
            timer: 'Aktive timere',
            kuma: 'Kuma alerts',
            eset: 'ESET incidents'
        };
        const val = counts[key] || 0;
        return nameMap[key] + ': ' + val;
    }

    function severityClassFor(key, value) {
        const val = Number(value || 0);
        if (key === 'urgent') {
            return val > 0 ? 'sev-critical' : 'sev-ok';
        }
        if (key === 'unassigned') {
            if (val >= 3) return 'sev-critical';
            if (val > 0) return 'sev-warn';
            return 'sev-ok';
        }
        if (key === 'mail') {
            if (val >= 10) return 'sev-critical';
            if (val > 0) return 'sev-warn';
            return 'sev-ok';
        }
        return val > 0 ? 'sev-warn' : 'sev-ok';
    }

    function listFor(key, sections) {
        const mail = sections.mail || {};
        const cases = sections.cases || {};
        const urgent = sections.urgent || {};
        const unassigned = sections.unassigned || {};
        const timer = sections.timer || {};
        const kuma = sections.kuma || {};
        const eset = sections.eset || {};
        const messages = sections.messages || {};
        const tasks = sections.tasks || {};
        const notes = sections.notes || {};
        const boss = sections.boss || {};

        function esc(str) { 
            return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;'); 
        }

        const quickNoteValue = esc(quickNoteDraft || '');
        
        if (key === 'overview') {
            if (overviewFilter === 'urgent') return urgent.list ? urgent.list.map(u => '<div><strong class="text-danger"><i class="bi bi-exclamation-octagon"></i> Hastesag:</strong> ' + esc(u.title) + ' <br><button class="btn btn-sm btn-outline-danger mt-2" data-bb-open-case="' + Number(u.id || 0) + '">Vis sag</button></div>') : ['Ingen hastesager.'];
            if (overviewFilter === 'kuma') return kuma.list ? kuma.list.map(k => '<div class="d-flex justify-content-between align-items-center"><span>📉 ' + esc(k) + '</span> <div><button class="btn btn-sm btn-outline-primary me-1">Opret Sag</button> <button class="btn btn-sm btn-outline-secondary">Ignorer</button></div></div>') : ['Alle systemer oppe.'];
            if (overviewFilter === 'eset') return eset.list ? eset.list.map(e => '<div class="d-flex justify-content-between align-items-center"><span>🔐 ' + esc(e) + '</span> <button class="btn btn-sm btn-outline-primary">Håndter</button></div>') : ['Ingen ESET incidents.'];
            if (overviewFilter === 'cases') return cases.list ? cases.list.map(c => '<div><i class="bi bi-folder2-open text-primary"></i> ' + esc(c.title) + ' <button class="btn btn-sm btn-outline-primary mt-2" data-bb-open-case="' + Number(c.id || 0) + '">Vis sag</button></div>') : ['Ingen åbne sager.'];
            if (overviewFilter === 'mail') return ['<div>📧 <strong>' + mail.unread + '</strong> ulæste mails. <br>💬 <strong>' + mail.customer_reply_needed + '</strong> kræver kundesvar. <button class="btn btn-sm btn-outline-primary mt-2">Åbn indbakke</button></div>'];
            if (overviewFilter === 'unassigned') return unassigned.list ? unassigned.list.map(u => '<div><i class="bi bi-person-x text-warning"></i> ' + esc(u.title || ('Sag #' + (u.id || ''))) + ' <button class="btn btn-sm btn-outline-primary mt-2" data-bb-open-case="' + Number(u.id || 0) + '">Åbn sag</button></div>') : ['Ingen åbne sager uden ansvarlig.'];

            let out = [];
            if (urgent.count > 0) out.push('<div><i class="bi bi-exclamation-octagon text-danger"></i> Hastesager: <strong>' + urgent.count + '</strong> aktive</div>');
            if (mail.unread > 0) out.push('<div><i class="bi bi-envelope text-primary"></i> Ubesvarede mails: <strong>' + mail.unread + '</strong></div>');
            if (cases.open > 0) out.push('<div><i class="bi bi-folder2-open text-primary"></i> Åbne sager i alt: <strong>' + cases.open + '</strong></div>');
            if (kuma.down > 0) out.push('<div><i class="bi bi-activity text-warning"></i> Uptime Kuma nedetid: <strong>' + kuma.down + '</strong> enheder</div>');
            if (eset.incidents > 0) out.push('<div><i class="bi bi-shield-lock text-danger"></i> ESET incidents: <strong>' + eset.incidents + '</strong></div>');
            
            if (out.length === 0) {
                out.push('<div>🎉 Alt ser grønt ud! Intet kritisk lige nu.</div>');
            }
            
            // Add quick note button on overview
            out.push('<div class="mt-3 pt-3 border-top"><div class="input-group"><input type="text" id="bbQuickNoteInput" class="form-control form-control-sm" placeholder="Skriv en quick note..." value="' + quickNoteValue + '"><button class="btn btn-outline-secondary btn-sm" id="bbQuickNoteSaveBtn"><i class="bi bi-pencil"></i> Gem note</button></div><div id="bbQuickNoteHint" class="small text-muted mt-2">' + esc(quickNoteHintState.message || 'Tip: gemmer som kommentar på aktiv/åben sag.') + '</div></div>');
            
            return out;
        }

        if (key === 'timer') {
            if (timer.active_count > 0) {
                return (timer.list || []).map(t => {
                    const elapsedText = t.elapsed_hhmmss || (String(t.elapsed || 0) + 's');
                    return '<div class="d-flex justify-content-between align-items-center"><span><i class="bi bi-stopwatch text-success"></i> ' + esc(t.desc) + ' (' + esc(elapsedText) + ')</span> <button class="btn btn-sm btn-danger" data-bb-stop-time="' + Number(t.id || t.time_entry_id || 0) + '"><i class="bi bi-stop-fill"></i> Stop</button></div>';
                });
            }
            return ['Ingen aktive timere lige nu.'];
        }

        if (key === 'messages') {
            if (messages.count > 0) {
                return (messages.list || []).map(m => '<div><strong class="' + (m.from === 'System' ? 'text-primary' : 'text-accent') + '">' + esc(m.from) + ':</strong> ' + esc(m.text) + '</div>');
            }
            return ['Ingen nye beskeder.'];
        }

        if (key === 'tasks') {
            if (tasks.count > 0) {
                return (tasks.list || []).map(t => '<div><i class="bi bi-calendar-check text-success"></i> <strong>' + esc(t.title) + '</strong> <span class="badge bg-secondary ms-2">' + esc(t.deadline) + '</span></div>');
            }
            return ['Ingen aktuelle opgaver.'];
        }

        if (key === 'notes') {
            const noteItems = Array.isArray(notes.list) ? notes.list : [];
            const editorTitle = esc(noteEditorState.title || '');
            const editorContent = esc(noteEditorState.content || '');
            const editingId = Number(noteEditorState.editingId || 0);
            const out = [
                '<div class="border rounded p-2 mb-3 bg-body-tertiary">' +
                    '<div class="small text-muted mb-2">Egne noter (vises i bundbar)</div>' +
                    '<input type="text" id="bbNoteTitleInput" class="form-control form-control-sm mb-2" placeholder="Titel (valgfri)" value="' + editorTitle + '">' +
                    '<textarea id="bbNoteContentInput" class="form-control form-control-sm" rows="4" placeholder="Skriv note...">' + editorContent + '</textarea>' +
                    '<div class="d-flex gap-2 mt-2">' +
                        '<button class="btn btn-sm btn-primary" id="bbNoteSaveBtn" data-note-edit-id="' + editingId + '"><i class="bi bi-save me-1"></i>' + (editingId > 0 ? 'Gem ændringer' : 'Opret note') + '</button>' +
                        '<button class="btn btn-sm btn-outline-secondary" id="bbNoteClearBtn"><i class="bi bi-x-circle me-1"></i>Ryd</button>' +
                    '</div>' +
                '</div>'
            ];

            if (!noteItems.length) {
                out.push('<div class="text-muted">Ingen noter endnu.</div>');
                return out;
            }

            noteItems.forEach(function (note) {
                const noteId = Number(note.id || 0);
                const noteTitle = esc((note.title || '').trim() || ('Note #' + noteId));
                const content = String(note.content || '');
                const preview = esc(content.length > 220 ? (content.slice(0, 220) + '...') : content);
                const pinned = !!note.is_pinned;

                out.push(
                    '<div class="border rounded p-2 mb-2">' +
                        '<div class="d-flex justify-content-between align-items-start gap-2">' +
                            '<div><strong>' + noteTitle + '</strong>' + (pinned ? ' <span class="badge text-bg-warning">Pinned</span>' : '') + '</div>' +
                            '<div class="btn-group btn-group-sm">' +
                                '<button class="btn btn-outline-secondary" data-note-edit="' + noteId + '"><i class="bi bi-pencil"></i></button>' +
                                '<button class="btn btn-outline-secondary" data-note-pin="' + noteId + '"><i class="bi bi-pin-angle' + (pinned ? '-fill' : '') + '"></i></button>' +
                                '<button class="btn btn-outline-danger" data-note-delete="' + noteId + '"><i class="bi bi-trash"></i></button>' +
                            '</div>' +
                        '</div>' +
                        '<div class="small text-muted mt-2" style="white-space: pre-wrap;">' + preview + '</div>' +
                        '<div class="d-flex flex-wrap gap-2 mt-2">' +
                            '<button class="btn btn-sm btn-outline-primary" data-note-to-case="' + noteId + '"><i class="bi bi-chat-left-text me-1"></i>Til sag-kommentar</button>' +
                            '<button class="btn btn-sm btn-outline-primary" data-note-to-contact="' + noteId + '"><i class="bi bi-person-lines-fill me-1"></i>Til kontakt</button>' +
                            '<button class="btn btn-sm btn-outline-primary" data-note-to-customer="' + noteId + '"><i class="bi bi-building me-1"></i>Til firma</button>' +
                        '</div>' +
                    '</div>'
                );
            });
            return out;
        }
        
        if (key === 'boss') {
            const stats = boss.stats || {};
            const workload = Array.isArray(boss.team_workload) ? boss.team_workload : [];
            const techniciansToday = Array.isArray(boss.technicians_today) ? boss.technicians_today : [];
            const escalations = Array.isArray(boss.escalations) ? boss.escalations : [];
            const unassigned = Array.isArray(boss.unassigned_cases) ? boss.unassigned_cases : [];

            const out = [
                '<div class="row g-2">' +
                    '<div class="col-6"><div class="border rounded p-2 bg-body-tertiary"><div class="small text-muted">Åbne sager</div><div class="fw-bold">' + Number(stats.open_cases || 0) + '</div></div></div>' +
                    '<div class="col-6"><div class="border rounded p-2 bg-body-tertiary"><div class="small text-muted">Hastesager</div><div class="fw-bold text-danger">' + Number(stats.urgent_cases || 0) + '</div></div></div>' +
                    '<div class="col-6"><div class="border rounded p-2 bg-body-tertiary"><div class="small text-muted">Uden ansvarlig</div><div class="fw-bold text-warning">' + Number(stats.unassigned || 0) + '</div></div></div>' +
                    '<div class="col-6"><div class="border rounded p-2 bg-body-tertiary"><div class="small text-muted">Stale >24t</div><div class="fw-bold text-danger">' + Number(stats.stale_urgent_cases || 0) + '</div></div></div>' +
                '</div>',
                '<div class="d-flex gap-2 flex-wrap mt-2">' +
                    '<button class="btn btn-sm btn-primary" data-boss-action="auto_assign_next"><i class="bi bi-magic me-1"></i>Auto-fordel næste</button>' +
                    '<button class="btn btn-sm btn-outline-primary" data-boss-action="open_unassigned"><i class="bi bi-person-x me-1"></i>Fordel ufordelte</button>' +
                    '<button class="btn btn-sm btn-outline-danger" data-boss-action="open_escalations"><i class="bi bi-exclamation-octagon me-1"></i>Se eskaleringer</button>' +
                    '<button class="btn btn-sm btn-outline-secondary" data-boss-action="open_team"><i class="bi bi-people me-1"></i>Team-overblik</button>' +
                '</div>'
            ];

            if (workload.length > 0) {
                out.push('<div class="small text-muted mt-3 mb-1">Team-belastning</div>');
                workload.slice(0, 5).forEach(function (w) {
                    out.push(
                        '<div class="d-flex justify-content-between align-items-center border rounded p-2">' +
                            '<div><strong>' + esc(w.owner_name || 'Ukendt') + '</strong><div class="small text-muted">Åbne: ' + Number(w.open_cases || 0) + ' • Haste: ' + Number(w.urgent_cases || 0) + '</div></div>' +
                            '<button class="btn btn-sm btn-outline-primary" data-boss-action="open_owner" data-owner-id="' + Number(w.user_id || 0) + '">Åbn</button>' +
                        '</div>'
                    );
                });
            }

            if (techniciansToday.length > 0) {
                out.push('<div class="small text-muted mt-3 mb-1">Teknikernes opgaver i dag</div>');
                techniciansToday.slice(0, 6).forEach(function (tech) {
                    const todayTasks = Array.isArray(tech.today_tasks) ? tech.today_tasks : [];
                    let tasksHtml = '<div class="small text-muted mt-1">Ingen opgaver i dag.</div>';
                    if (todayTasks.length > 0) {
                        tasksHtml = '<div class="small mt-1">' + todayTasks.slice(0, 3).map(function (task) {
                            return '<div><i class="bi bi-dot"></i> ' + esc(task.title || ('Sag #' + task.id)) + '</div>';
                        }).join('') + '</div>';
                    }

                    out.push(
                        '<div class="border rounded p-2">' +
                            '<div class="d-flex justify-content-between align-items-center">' +
                                '<div><strong>' + esc(tech.owner_name || 'Tekniker') + '</strong><div class="small text-muted">I dag: ' + Number(tech.due_today_cases || 0) + ' • Åbne: ' + Number(tech.open_cases || 0) + '</div></div>' +
                                '<div class="d-flex gap-1">' +
                                    '<button class="btn btn-sm btn-outline-primary" data-boss-action="open_owner" data-owner-id="' + Number(tech.user_id || 0) + '">Vis</button>' +
                                    '<button class="btn btn-sm btn-primary" data-boss-action="assign_next_to_owner" data-owner-id="' + Number(tech.user_id || 0) + '">Tildel næste</button>' +
                                '</div>' +
                            '</div>' +
                            tasksHtml +
                        '</div>'
                    );
                });
            }

            if (escalations.length > 0) {
                out.push('<div class="small text-muted mt-3 mb-1">Eskaleringer</div>');
                escalations.slice(0, 4).forEach(function (c) {
                    const ageHours = Math.floor(Number(c.age_seconds || 0) / 3600);
                    out.push(
                        '<div class="d-flex justify-content-between align-items-center border rounded p-2">' +
                            '<div><strong>' + esc(c.title || 'Sag') + '</strong><div class="small text-muted">' + esc(c.owner_name || 'Ikke tildelt') + ' • ' + ageHours + 't siden opdatering</div></div>' +
                            '<button class="btn btn-sm btn-outline-danger" data-boss-action="open_case" data-case-id="' + Number(c.id || 0) + '">Åbn</button>' +
                        '</div>'
                    );
                });
            }

            if (unassigned.length > 0) {
                out.push('<div class="small text-muted mt-3 mb-1">Ufordelte sager</div>');
                unassigned.slice(0, 4).forEach(function (c) {
                    out.push(
                        '<div class="d-flex justify-content-between align-items-center border rounded p-2">' +
                            '<div><strong>' + esc(c.title || 'Sag') + '</strong><div class="small text-muted">Prioritet: ' + esc(c.priority || 'normal') + '</div></div>' +
                            '<button class="btn btn-sm btn-outline-warning" data-boss-action="open_case" data-case-id="' + Number(c.id || 0) + '">Åbn</button>' +
                        '</div>'
                    );
                });
            }

            return out;
        }

        return ['Klik rundt i menuen for at se data.'];
    }

    function updateBar(sections) {
        const counts = getCounts(sections);
        const keys = Object.keys(counts);

        for (let i = 0; i < keys.length; i++) {
            const key = keys[i];
            const chipText = document.querySelector('.bb-chip[data-bb-key="' + key + '"] .bb-chip-text');
            const chipLabel = document.querySelector('.bb-chip[data-bb-key="' + key + '"] .bb-chip-label');
            const chipBubble = document.querySelector('.bb-chip[data-bb-key="' + key + '"] .bb-chip-bubble');
            const chip = document.querySelector('.bb-chip[data-bb-key="' + key + '"]');
            if (chipText && chip) {
                const val = counts[key];
                
                const labels = {
                    mail: 'Ulæste mails',
                    cases: 'Sager',
                    urgent: 'Hastesager',
                    unassigned: 'Uden ansvarlig',
                    timer: 'Timere',
                    kuma: 'Kuma',
                    eset: 'ESET'
                };

                if (chipLabel) {
                    chipLabel.textContent = labels[key];
                }
                if (chipBubble) {
                    chipBubble.textContent = String(val);
                }
                chipText.textContent = labels[key] + ': ' + val;
                chip.classList.toggle('has-items', val > 0);
                chip.classList.remove('sev-ok', 'sev-warn', 'sev-critical');
                chip.classList.add(severityClassFor(key, val));
                chip.setAttribute('title', detailTextFor(key, sections));
                chip.setAttribute('aria-label', detailTextFor(key, sections));
            }
        }
    }

    function bindChipHoverPreview() {
        const chips = document.querySelectorAll('.bb-chip');
        const detail = byId('bbCountDetail');
        if (!detail || !chips.length) {
            return;
        }

        chips.forEach(function (chip) {
            chip.addEventListener('mouseenter', function () {
                const key = chip.getAttribute('data-bb-key');
                if (!key) return;
                detail.innerHTML = '<i class="bi bi-eye me-1 text-accent"></i> ' + detailTextFor(key, latestSections);
            });

            chip.addEventListener('mouseleave', function () {
                detail.innerHTML = '<i class="bi bi-info-circle me-1 opacity-75"></i> Klik på en kategori for at se detaljer';
            });
        });
    }

    function updateActivityZone() {
        const timerChip = byId('bbActiveTimerChip');
        const timerText = byId('bbActiveTimerText');
        const notifCount = byId('bbNotificationsCount');

        const timer = ((latestSections || {}).timer || {}).active || {};
        const hasActiveTimer = !!timer.active;
        if (timerChip && timerText) {
            timerChip.classList.toggle('is-hidden', !hasActiveTimer);
            if (hasActiveTimer) {
                const elapsed = timer.elapsed_hhmmss || '00:00:00';
                const name = timer.sag_navn || ('Sag #' + (timer.sag_id || ''));
                timerText.textContent = name + ' - ' + elapsed;
            }
        }

        if (notifCount) {
            const computed = Number(latestNotificationCount || ((latestSections.messages || {}).count || 0));
            notifCount.textContent = String(computed);
        }
    }

    function renderTabPanel() {
        const titleContainer = byId('bbTabTitle');
        const innerContent = byId('bbTabInnerContent');
        if (!titleContainer || !innerContent) {
            return;
        }
        
        const titleText = titleContainer.querySelector('.bb-tab-title-text');

        const titleByKey = {
            overview: 'Overblik',
            timer: 'Timere',
            messages: 'Beskeder',
            tasks: 'Opgaver',
            notes: 'Noter',
            boss: 'Chef Dashboard'
        };
        
        const iconByKey = {
            overview: 'bi-bell',
            timer: 'bi-stopwatch',
            messages: 'bi-chat-dots',
            tasks: 'bi-calendar-check',
            notes: 'bi-journal-text',
            boss: 'bi-person-workspace'
        };

        const activeTitle = titleByKey[activeKey] || 'Info';
        if (titleText) {
            titleText.textContent = activeTitle;
        } else {
            titleContainer.textContent = activeTitle;
        }
        
        const iconSpan = titleContainer.querySelector('.bi');
        if (iconSpan) {
            iconSpan.className = 'bi ' + (iconByKey[activeKey] || 'bi-info-circle') + ' me-2 text-accent';
        }

        // Render rich UI lists
        const lines = listFor(activeKey, latestSections);
        const ul = document.createElement('ul');
        ul.className = 'bb-tab-list';
        
        lines.forEach(function (line) {
            const li = document.createElement('li');
            // Allow rich HTML (buttons, inputs) - assuming listFor provides sanitized data wrapped in markup
            li.innerHTML = line;
            ul.appendChild(li);
        });
        
        innerContent.innerHTML = '';
        
        // Add specific headers/controls based on active tab
        if (activeKey === 'tasks') {
            const topBar = document.createElement('div');
            topBar.className = 'bb-task-actions mb-3';
            topBar.innerHTML = '<button class="btn btn-primary btn-sm w-100 fw-bold shadow-sm" id="btnNextTask"><i class="bi bi-box-arrow-in-down-right"></i> Giv mig næste opgave</button>';
            innerContent.appendChild(topBar);
        }
        if (activeKey === 'messages') {
            const chatContainer = document.createElement('div');
            chatContainer.className = 'd-flex flex-column h-100';
            ul.classList.add('flex-grow-1', 'mb-3');
            


            const replyBox = document.createElement('div');
            replyBox.className = 'mt-2 border-top pt-2 border-primary-subtle';
            replyBox.innerHTML = `
                <div class="input-group input-group-sm mb-1">
                    <span class="input-group-text bg-light text-muted border-0"><i class="bi bi-person"></i></span>
                    <select id="chatRecipient" class="form-select border-0 bg-light">
                        <option value="all">Indlæser brugere...</option>
                    </select>
                </div>
                <div class="input-group">
                    <input type="text" id="chatInputQuick" class="form-control form-control-sm" placeholder="Skriv en besked...">
                    <button class="btn btn-outline-primary btn-sm" id="btnSendMsg"><i class="bi bi-send"></i></button>
                </div>
            `;
            
            chatContainer.appendChild(ul);
            chatContainer.appendChild(replyBox);
            innerContent.appendChild(chatContainer);
            
            // Fetch users dynamically
            fetch('/api/v1/users?is_active=true', { credentials: 'include' })
            .then(r => r.json())
            .then(payload => {
                const users = Array.isArray(payload) ? payload : ((payload && payload.data && Array.isArray(payload.data)) ? payload.data : []);
                const sel = document.getElementById('chatRecipient');
                if (sel) {
                    sel.innerHTML = '<option value="all">Alle på vagt</option><option value="system">System (Bot)</option>';
                    users.forEach(u => {
                        sel.innerHTML += `<option value="${u.id}">${u.full_name || u.username || u.email || ('Bruger #' + u.id)}</option>`;
                    });
                }
            })
            .catch(e => console.error("Error fetching users for chat:", e));
        } else {
            innerContent.appendChild(ul);
        }

    }

    function bindSideTabs() {
        const buttons = document.querySelectorAll('.bb-tab-btn');
        for (let i = 0; i < buttons.length; i++) {
            buttons[i].addEventListener('click', function (e) {
                // Clear filter on direct human click of the button, unless we programmatically called click()
                if (e.isTrusted) overviewFilter = null; 

                for (let j = 0; j < buttons.length; j++) {
                    buttons[j].classList.remove('is-active');
                    buttons[j].setAttribute('aria-selected', 'false');
                }
                this.classList.add('is-active');
                this.setAttribute('aria-selected', 'true');

                activeKey = this.getAttribute('data-bb-tab');
                renderTabPanel();
                
                const detail = byId('bbCountDetail');
                if (detail) {
                    detail.innerHTML = '<i class="bi bi-info-circle me-1 opacity-75"></i> Viser: ' + (activeKey.charAt(0).toUpperCase() + activeKey.slice(1));
                }
            });
        }
    }

    function bindChipClicks() {
        const chips = document.querySelectorAll('.bb-chip');
        for (let i = 0; i < chips.length; i++) {
            chips[i].addEventListener('click', function () {
                const key = this.getAttribute('data-bb-key');
                if (!key) return;

                const detail = byId('bbCountDetail');
                if (detail) {
                    detail.innerHTML = '<i class="bi bi-check-circle me-1 text-accent"></i> ' + detailTextFor(key, latestSections);
                }

                const routes = {
                    mail: '/emails',
                    urgent: '/sag?priority=urgent',
                    timer: '/timetracking',
                    cases: '/sag'
                };

                if (key === 'unassigned') {
                    openUnassignedCasesPanel();
                    return;
                }

                const route = routes[key] || '/dashboard';
                window.location.href = route;
            });
        }
    }

    function bindSheetToggle() {
        const toggle = byId('bbSheetToggle');
        if (!toggle) return;
        toggle.addEventListener('click', function () {
            const shell = byId('globalBottomBar');
            if (!shell) return;
            const isExp = shell.classList.contains('is-expanded');
            setExpanded(!isExp);
        });
    }

    function stopPolling() {
        if (pollTimer) {
            window.clearTimeout(pollTimer);
            pollTimer = null;
        }
    }

    function pollOnce() {
        let shouldScheduleNextPoll = true;
        fetchBottomBarState().then(function (data) {
            applyState(data);
        }).catch(function (err) {
            console.warn('Bottom bar poll failed', err);
            if (err && (err.status === 401 || err.status === 403)) {
                shouldScheduleNextPoll = false;
                disableBottomBarAuthRetry('poll-' + err.status);
            }
        }).finally(function () {
            if (shouldScheduleNextPoll) {
                pollTimer = window.setTimeout(pollOnce, 15000);
            }
        });
    }

    function startPollingFallback() {
        stopPolling();
        pollOnce();
    }

    function updateFromRealtimeEvent(payload) {
        if (!payload || !payload.event) {
            return;
        }

        if (payload.event === 'timer_tick') {
            const timer = payload.data || {};
            latestSections.timer = latestSections.timer || {};
            latestSections.timer.active = timer;
            latestSections.timer.active_count = timer.active ? 1 : 0;
            latestSections.timer.list = timer.active ? [{
                id: timer.time_entry_id,
                sag_id: timer.sag_id,
                desc: timer.sag_navn || ('Sag #' + (timer.sag_id || '')),
                elapsed: timer.elapsed,
                elapsed_hhmmss: timer.elapsed_hhmmss
            }] : [];
        }

        if (payload.event === 'status_delta') {
            const status = payload.data || {};
            latestSections.mail = latestSections.mail || {};
            latestSections.cases = latestSections.cases || {};
            latestSections.urgent = latestSections.urgent || {};
            latestSections.unassigned = latestSections.unassigned || {};
            latestSections.boss = latestSections.boss || { stats: {} };

            latestSections.mail.unread = Number(status.mails_unread || 0);
            latestSections.mail.customer_reply_needed = Number(status.mails_unread || 0);
            latestSections.cases.open = Number(status.sager_open || 0);
            latestSections.urgent.count = Number(status.sager_urgent || 0);
            latestSections.unassigned.count = Number(status.sager_unassigned || 0);
            latestSections.boss.stats = latestSections.boss.stats || {};
            latestSections.boss.stats.unassigned = Number(status.sager_unassigned || 0);
        }

        if (payload.event === 'notification_delta') {
            const notifications = payload.data || {};
            const items = Array.isArray(notifications.items) ? notifications.items : [];
            latestSections.messages = latestSections.messages || {};
            latestSections.tasks = latestSections.tasks || {};

            latestSections.messages.count = items.length;
            latestSections.messages.list = items.slice(0, 5).map(function (item) {
                return {
                    from: (item.type || 'System').toString(),
                    text: (item.title || item.message || 'Notifikation').toString()
                };
            });

            latestSections.tasks.count = items.length;
            latestSections.tasks.list = items.slice(0, 5).map(function (item) {
                return {
                    title: item.title || 'Notifikation',
                    deadline: item.severity || 'info'
                };
            });
            latestNotificationCount = Number(notifications.count || items.length || 0);
            latestNotifications = items;
        }

        syncBossTabVisibility();
        updateBar(latestSections);
        updateActivityZone();
        const focusedId = document.activeElement && document.activeElement.id;
        const quickNoteFocused = activeKey === 'overview' && focusedId === 'bbQuickNoteInput';
        const noteEditorFocused = activeKey === 'notes' && (focusedId === 'bbNoteTitleInput' || focusedId === 'bbNoteContentInput');
        if (!quickNoteFocused && !noteEditorFocused) {
            renderTabPanel();
        }
    }

    function scheduleWsReconnect() {
        if (wsReconnectTimer) {
            window.clearTimeout(wsReconnectTimer);
        }
        wsReconnectTimer = window.setTimeout(connectRealtime, 3000);
    }

    function connectRealtime() {
        if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) {
            return;
        }

        const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
        const wsUrl = protocol + '//' + window.location.host + '/api/v1/bottom-bar/ws';

        try {
            ws = new WebSocket(wsUrl);
        } catch (err) {
            console.warn('Bottom bar websocket init failed', err);
            startPollingFallback();
            scheduleWsReconnect();
            return;
        }

        ws.addEventListener('open', function () {
            stopPolling();
        });

        ws.addEventListener('message', function (event) {
            try {
                const payload = JSON.parse(event.data || '{}');
                updateFromRealtimeEvent(payload);
            } catch (err) {
                console.warn('Bottom bar websocket parse error', err);
            }
        });

        ws.addEventListener('close', function (event) {
            // 1008 = policy violation (used server-side for auth failure).
            if (event && event.code === 1008) {
                disableBottomBarAuthRetry('ws-1008');
                return;
            }
            startPollingFallback();
            scheduleWsReconnect();
        });

        ws.addEventListener('error', function (err) {
            console.warn('Bottom bar websocket error', err);
            startPollingFallback();
        });
    }


    function stopActiveTimer() {
        const active = ((latestSections || {}).timer || {}).active || {};
        if (!active.time_entry_id) {
            return Promise.resolve();
        }

        return fetch('/api/v1/timetracking/time/stop', {
            method: 'POST',
            credentials: 'include',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ time_id: active.time_entry_id })
        }).catch(function (err) {
            console.warn('Failed stopping active timer', err);
        });
    }

    function pauseActiveTimer() {
        return fetch('/api/v1/timetracking/time/pause', {
            method: 'POST',
            credentials: 'include',
            headers: { 'Content-Type': 'application/json' },
            body: '{}'
        }).then(function (res) {
            if (!res.ok) {
                throw new Error('Kunne ikke pause timer');
            }
            return res.json().catch(function () { return {}; });
        });
    }

    function resumeTimer(timeId) {
        const payload = {};
        if (Number(timeId || 0) > 0) {
            payload.time_id = Number(timeId);
        }

        return fetch('/api/v1/timetracking/time/resume', {
            method: 'POST',
            credentials: 'include',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload)
        }).then(function (res) {
            if (!res.ok) {
                throw new Error('Kunne ikke genoptage timer');
            }
            return res.json().catch(function () { return {}; });
        });
    }

    function normalizeSwitchableTimerPayload(payload) {
        const out = { active: [], paused: [] };
        if (!payload || typeof payload !== 'object') {
            return out;
        }

        if (Array.isArray(payload.active) || Array.isArray(payload.paused)) {
            out.active = Array.isArray(payload.active) ? payload.active : [];
            out.paused = Array.isArray(payload.paused) ? payload.paused : [];
            return out;
        }

        const active = payload.active || {};
        const paused = Array.isArray(payload.paused) ? payload.paused : [];
        out.active = active && active.active ? [active] : [];
        out.paused = paused;
        return out;
    }

    async function fetchSwitchableTimers() {
        const primary = await fetch('/api/v1/timetracking/time/my-switchable', {
            credentials: 'include',
            headers: { 'Accept': 'application/json' }
        });

        if (primary.ok) {
            const payload = await primary.json();
            return normalizeSwitchableTimerPayload(payload);
        }

        const fallback = await fetch('/api/v1/bottom-bar/timers/own?paused_limit=10', {
            credentials: 'include',
            headers: { 'Accept': 'application/json' }
        });

        if (!fallback.ok) {
            throw new Error('Kunne ikke hente timeroversigt');
        }

        const payload = await fallback.json();
        return normalizeSwitchableTimerPayload(payload);
    }

    async function fetchRecentCases() {
        const response = await fetch('/api/v1/sag/recent?limit=10', {
            credentials: 'include',
            headers: { 'Accept': 'application/json' }
        });
        if (!response.ok) {
            throw new Error('Kunne ikke hente seneste sager');
        }
        const payload = await response.json();
        return Array.isArray(payload) ? payload : [];
    }

    function getSwitchCaseModal() {
        const modalEl = byId('bbSwitchCaseModal');
        if (!modalEl || !window.bootstrap || !window.bootstrap.Modal) {
            return null;
        }

        if (!switchCaseModalInstance) {
            switchCaseModalInstance = window.bootstrap.Modal.getOrCreateInstance(modalEl);
        }
        return switchCaseModalInstance;
    }

    function switchCaseStatusMessage(html) {
        const statusEl = byId('bbSwitchCaseStatus');
        if (statusEl) {
            statusEl.innerHTML = html;
        }
    }

    function timerDisplayName(timer) {
        const sagId = Number((timer && timer.sag_id) || 0);
        const title = (timer && (timer.sag_navn || timer.title || timer.beskrivelse || timer.desc)) || '';
        if (title) {
            return escapeHtml(title);
        }
        return sagId > 0 ? ('Sag #' + sagId) : 'Ukendt sag';
    }

    function renderSwitchCaseLists() {
        const timersEl = byId('bbSwitchTimersList');
        const recentEl = byId('bbSwitchRecentCasesList');
        const actionsEl = byId('bbSwitchTimerActions');
        if (!timersEl || !recentEl) {
            return;
        }

        const active = Array.isArray(switchCaseState.timers.active) ? switchCaseState.timers.active : [];
        const paused = Array.isArray(switchCaseState.timers.paused) ? switchCaseState.timers.paused : [];
        const recentCases = Array.isArray(switchCaseState.recentCases) ? switchCaseState.recentCases : [];
        const unassignedCases = Array.isArray(switchCaseState.unassignedCases) ? switchCaseState.unassignedCases : [];
        const showUnassigned = unassignedCases.length > 0;

        if (actionsEl) {
            actionsEl.classList.toggle('d-none', !switchCaseState.activeTimer);
        }

        if (!active.length && !paused.length) {
            timersEl.innerHTML = '<div class="list-group-item text-muted">Ingen aktive eller pausede timere.</div>';
        } else {
            let timerItems = '';
            active.forEach(function (t) {
                const timeId = Number((t && (t.id || t.time_entry_id)) || 0);
                timerItems +=
                    '<div class="list-group-item d-flex justify-content-between align-items-start">' +
                        '<div><span class="badge text-bg-success me-2">Aktiv</span>' + timerDisplayName(t) + '</div>' +
                        '<button class="btn btn-sm btn-outline-primary" data-bb-open-case="' + Number((t && t.sag_id) || 0) + '">Åbn sag</button>' +
                    '</div>';
                if (timeId > 0) {
                    timerItems +=
                        '<div class="list-group-item small text-muted border-top-0 pt-0">Timer ID: ' + timeId + '</div>';
                }
            });

            paused.forEach(function (t) {
                timerItems +=
                    '<div class="list-group-item d-flex justify-content-between align-items-start">' +
                        '<div><span class="badge text-bg-warning me-2">Pauset</span>' + timerDisplayName(t) + '</div>' +
                        '<button class="btn btn-sm btn-outline-primary" data-bb-open-case="' + Number((t && t.sag_id) || 0) + '">Åbn sag</button>' +
                    '</div>';
            });

            timersEl.innerHTML = timerItems;
        }

        const sourceCases = showUnassigned ? unassignedCases : recentCases;
        const titleEl = byId('bbSwitchCaseModalLabel');
        if (titleEl) {
            titleEl.innerHTML = showUnassigned
                ? '<i class="bi bi-person-x me-2"></i>Uden ansvarlig (åbne sager)'
                : '<i class="bi bi-arrow-left-right me-2"></i>Skift sag';
        }

        if (!sourceCases.length) {
            recentEl.innerHTML = '<div class="list-group-item text-muted">Ingen sager at vise.</div>';
            return;
        }

        recentEl.innerHTML = sourceCases.map(function (row) {
            const caseId = Number((row && (row.sag_id || row.id)) || 0);
            const title = escapeHtml((row && (row.titel || row.title)) || (caseId > 0 ? ('Sag #' + caseId) : 'Ukendt sag'));
            const prefix = showUnassigned ? '<span class="badge text-bg-warning me-2">Uden ansvarlig</span>' : '<span class="badge text-bg-light border me-2">Senest</span>';
            return (
                '<div class="list-group-item d-flex justify-content-between align-items-start gap-2">' +
                    '<div class="me-2">' + prefix + title + '</div>' +
                    '<div class="d-flex gap-1">' +
                        '<button class="btn btn-sm btn-outline-primary" data-bb-open-case="' + caseId + '">Åbn</button>' +
                        '<button class="btn btn-sm btn-primary" data-bb-start-case="' + caseId + '">Start timer</button>' +
                    '</div>' +
                '</div>'
            );
        }).join('');
    }

    async function loadSwitchCaseData(options) {
        const opts = options || {};
        switchCaseState.decision = 'unchanged';
        switchCaseState.activeTimer = (((latestSections || {}).timer || {}).active || {}).active
            ? ((latestSections || {}).timer || {}).active
            : null;
        switchCaseState.unassignedCases = [];
        switchCaseState.recentCases = [];
        switchCaseState.timers = { active: [], paused: [] };

        if (opts.onlyUnassigned) {
            const unassigned = (((latestSections || {}).unassigned || {}).list || []);
            switchCaseState.unassignedCases = Array.isArray(unassigned) ? unassigned.slice(0, 25) : [];
            switchCaseStatusMessage('<i class="bi bi-info-circle me-1"></i>Viser kun åbne sager uden ansvarlig.');
            renderSwitchCaseLists();
            return;
        }

        switchCaseStatusMessage('<span class="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>Henter timer og seneste sager...');

        const results = await Promise.allSettled([fetchSwitchableTimers(), fetchRecentCases()]);

        const timersResult = results[0];
        const casesResult = results[1];

        if (timersResult.status === 'fulfilled') {
            switchCaseState.timers = timersResult.value;
        }

        if (casesResult.status === 'fulfilled') {
            switchCaseState.recentCases = casesResult.value;
        }

        const failedParts = [];
        if (timersResult.status === 'rejected') failedParts.push('timere');
        if (casesResult.status === 'rejected') failedParts.push('seneste sager');

        if (failedParts.length) {
            switchCaseStatusMessage('<i class="bi bi-exclamation-triangle me-1 text-warning"></i>Kunne ikke hente ' + escapeHtml(failedParts.join(' + ')) + '. Viser det vi har.');
        } else if (switchCaseState.activeTimer) {
            const name = timerDisplayName(switchCaseState.activeTimer);
            switchCaseStatusMessage('<i class="bi bi-stopwatch me-1"></i>Aktiv timer: ' + name + '. Vælg handling før du starter en ny timer.');
        } else {
            switchCaseStatusMessage('<i class="bi bi-check-circle me-1 text-success"></i>Klar til skift af sag.');
        }

        renderSwitchCaseLists();
    }

    async function openSwitchCaseModal(options) {
        const modal = getSwitchCaseModal();
        if (!modal) {
            window.location.href = '/sag';
            return;
        }

        modal.show();
        try {
            await loadSwitchCaseData(options);
        } catch (err) {
            console.warn('Switch case modal load failed', err);
            switchCaseStatusMessage('<i class="bi bi-exclamation-triangle me-1 text-danger"></i>Kunne ikke hente data til skift af sag.');
            renderSwitchCaseLists();
        }
    }

    function openUnassignedCasesPanel() {
        window.location.href = '/sag?unassigned=1';
    }

    async function startTimerForCase(caseId) {
        const validCaseId = Number(caseId || 0);
        if (validCaseId <= 0) {
            return;
        }

        const hasActiveTimer = !!(switchCaseState.activeTimer && switchCaseState.activeTimer.active);
        if (hasActiveTimer && switchCaseState.decision === 'unchanged') {
            switchCaseStatusMessage('<i class="bi bi-info-circle me-1 text-warning"></i>Du har en aktiv timer. Vælg Pause nu, Stop nu eller Fortsæt uændret først.');
            return;
        }

        try {
            const response = await fetch('/api/v1/timetracking/time/start', {
                method: 'POST',
                credentials: 'include',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ sag_id: validCaseId })
            });

            if (!response.ok) {
                const payload = await response.json().catch(function () { return {}; });
                const detail = (payload && payload.detail) ? payload.detail : ('HTTP ' + response.status);
                throw new Error(typeof detail === 'string' ? detail : 'Kunne ikke starte timer');
            }

            const modal = getSwitchCaseModal();
            if (modal) {
                modal.hide();
            }
            window.location.href = '/sag/' + validCaseId;
        } catch (err) {
            switchCaseStatusMessage('<i class="bi bi-exclamation-triangle me-1 text-danger"></i>' + escapeHtml(err.message || 'Kunne ikke starte timer for sag.'));
        }
    }

    function openCaseDetail(caseId) {
        const validCaseId = Number(caseId || 0);
        if (validCaseId <= 0) {
            return;
        }
        const modal = getSwitchCaseModal();
        if (modal) {
            modal.hide();
        }
        window.location.href = '/sag/' + validCaseId;
    }

    function resolveQuickNoteCaseId() {
        const match = (window.location.pathname || '').match(/^\/sag\/(\d+)$/);
        if (match && match[1]) {
            return Number(match[1]);
        }

        const active = (((latestSections || {}).timer || {}).active || {});
        const activeSagId = Number(active.sag_id || 0);
        if (activeSagId > 0) {
            return activeSagId;
        }

        const recent = (((latestSections || {}).recent_cases || {}).items || []);
        const recentFirst = Number((((recent[0] || {}).id) || ((recent[0] || {}).sag_id) || 0));
        return recentFirst > 0 ? recentFirst : 0;
    }

    function saveQuickNote(noteText, caseId) {
        return fetch('/api/v1/sag/' + Number(caseId) + '/kommentarer', {
            method: 'POST',
            credentials: 'include',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ indhold: noteText })
        }).then(function (res) {
            if (!res.ok) {
                throw new Error('Kunne ikke gemme note');
            }
            return res.json().catch(function () { return {}; });
        });
    }

    function noteById(noteId) {
        const notes = (((latestSections || {}).notes || {}).list || []);
        return notes.find(function (row) { return Number((row || {}).id || 0) === Number(noteId || 0); }) || null;
    }

    async function readApiError(response, fallbackMessage) {
        let payload = {};
        try {
            payload = await response.json();
        } catch (e) {
            payload = {};
        }
        const detail = payload && payload.detail ? payload.detail : null;
        if (typeof detail === 'string' && detail.trim()) {
            return detail;
        }
        return fallbackMessage;
    }

    async function fetchWithNotesFallback(url, options) {
        const response = await fetch(url, options);
        if (response.status !== 404 || !/\/api\/v1\/bottom-bar\/notes(\/|$)/.test(url)) {
            return response;
        }

        const altUrl = url.endsWith('/') ? url.slice(0, -1) : (url + '/');
        return fetch(altUrl, options);
    }

    async function createUserNote(title, content) {
        const endpoint = '/api/v1/bottom-bar/notes';
        const res = await fetchWithNotesFallback(endpoint, {
            method: 'POST',
            credentials: 'include',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ title: title || '', content: content || '' })
        });
        if (res.status === 404) {
            notesApiUnavailable = true;
            const now = new Date().toISOString();
            const local = loadLocalNotes();
            const created = {
                id: Date.now(),
                title: String(title || '').trim(),
                content: String(content || '').trim(),
                is_pinned: false,
                is_archived: false,
                created_at: now,
                updated_at: now,
                _local_only: true
            };
            local.unshift(created);
            saveLocalNotes(local);
            return created;
        }
        if (!res.ok) {
            throw new Error(await readApiError(res, 'Kunne ikke oprette note (' + endpoint + ')'));
        }
        notesApiUnavailable = false;
        return res.json().catch(function () { return {}; });
    }

    async function updateUserNote(noteId, payload) {
        const endpoint = '/api/v1/bottom-bar/notes/' + Number(noteId || 0);
        const res = await fetchWithNotesFallback(endpoint, {
            method: 'PATCH',
            credentials: 'include',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload || {})
        });
        if (res.status === 404) {
            notesApiUnavailable = true;
            const local = loadLocalNotes();
            const idNum = Number(noteId || 0);
            const updated = local.map(function (row) {
                if (Number((row || {}).id || 0) !== idNum) return row;
                return {
                    ...row,
                    ...payload,
                    updated_at: new Date().toISOString(),
                    _local_only: true
                };
            });
            saveLocalNotes(updated);
            return updated.find(function (row) { return Number((row || {}).id || 0) === idNum; }) || {};
        }
        if (!res.ok) {
            throw new Error(await readApiError(res, 'Kunne ikke opdatere note (' + endpoint + ')'));
        }
        notesApiUnavailable = false;
        return res.json().catch(function () { return {}; });
    }

    async function deleteUserNote(noteId) {
        const endpoint = '/api/v1/bottom-bar/notes/' + Number(noteId || 0);
        const res = await fetchWithNotesFallback(endpoint, {
            method: 'DELETE',
            credentials: 'include'
        });
        if (res.status === 404) {
            notesApiUnavailable = true;
            const idNum = Number(noteId || 0);
            const local = loadLocalNotes().filter(function (row) {
                return Number((row || {}).id || 0) !== idNum;
            });
            saveLocalNotes(local);
            return { status: 'deleted', note_id: idNum, _local_only: true };
        }
        if (!res.ok) {
            throw new Error(await readApiError(res, 'Kunne ikke slette note (' + endpoint + ')'));
        }
        notesApiUnavailable = false;
        return res.json().catch(function () { return {}; });
    }

    async function noteToCaseComment(noteId, caseId, excerpt) {
        const endpoint = '/api/v1/bottom-bar/notes/' + Number(noteId || 0) + '/actions/sag-comment';
        const res = await fetchWithNotesFallback(endpoint, {
            method: 'POST',
            credentials: 'include',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ sag_id: Number(caseId || 0), excerpt: excerpt || null })
        });
        if (!res.ok) {
            throw new Error(await readApiError(res, 'Kunne ikke indsætte i sag-kommentar (' + endpoint + ')'));
        }
        return res.json().catch(function () { return {}; });
    }

    async function noteToContact(noteId, contactId, field, value, mode) {
        const endpoint = '/api/v1/bottom-bar/notes/' + Number(noteId || 0) + '/actions/contact-update';
        const res = await fetchWithNotesFallback(endpoint, {
            method: 'POST',
            credentials: 'include',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                contact_id: Number(contactId || 0),
                field: String(field || ''),
                value: value || '',
                mode: mode || 'append'
            })
        });
        if (!res.ok) {
            throw new Error(await readApiError(res, 'Kunne ikke opdatere kontakt fra note (' + endpoint + ')'));
        }
        return res.json().catch(function () { return {}; });
    }

    async function noteToCustomer(noteId, customerId, field, value, mode) {
        const endpoint = '/api/v1/bottom-bar/notes/' + Number(noteId || 0) + '/actions/customer-update';
        const res = await fetchWithNotesFallback(endpoint, {
            method: 'POST',
            credentials: 'include',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                customer_id: Number(customerId || 0),
                field: String(field || ''),
                value: value || '',
                mode: mode || 'append'
            })
        });
        if (!res.ok) {
            throw new Error(await readApiError(res, 'Kunne ikke opdatere firma fra note (' + endpoint + ')'));
        }
        return res.json().catch(function () { return {}; });
    }

    function getNoteTargetModal() {
        const modalEl = byId('bbNoteTargetModal');
        if (!modalEl || !window.bootstrap || !window.bootstrap.Modal) {
            return null;
        }
        if (!noteTargetModalInstance) {
            noteTargetModalInstance = window.bootstrap.Modal.getOrCreateInstance(modalEl);
        }
        return noteTargetModalInstance;
    }

    function updateNoteTargetStatus(message, isError) {
        const statusEl = byId('bbNoteTargetStatus');
        if (!statusEl) {
            return;
        }
        statusEl.textContent = String(message || '');
        statusEl.classList.remove('text-muted', 'text-success', 'text-danger');
        if (isError === true) {
            statusEl.classList.add('text-danger');
            return;
        }
        if (isError === false) {
            statusEl.classList.add('text-success');
            return;
        }
        statusEl.classList.add('text-muted');
    }

    function renderNoteTargetFieldOptions(target) {
        const wrap = byId('bbNoteTargetFieldWrap');
        const label = byId('bbNoteTargetFieldLabel');
        const select = byId('bbNoteTargetFieldSelect');
        if (!wrap || !label || !select) {
            return;
        }

        if (target === 'case') {
            wrap.classList.add('d-none');
            select.innerHTML = '';
            return;
        }

        const options = target === 'contact'
            ? [
                { value: 'mobile', label: 'Mobile' },
                { value: 'phone', label: 'Telefon' },
                { value: 'email', label: 'Email' },
                { value: 'title', label: 'Titel' },
                { value: 'department', label: 'Afdeling' }
            ]
            : [
                { value: 'note', label: 'Firma note' },
                { value: 'mobile_phone', label: 'Mobil' },
                { value: 'phone', label: 'Telefon' },
                { value: 'email', label: 'Email' },
                { value: 'address', label: 'Adresse' },
                { value: 'invoice_email', label: 'Faktura-email' }
            ];

        wrap.classList.remove('d-none');
        label.textContent = target === 'contact' ? 'Kontaktfelt' : 'Firmafelt';
        select.innerHTML = options.map(function (item) {
            return '<option value="' + escapeHtml(item.value) + '">' + escapeHtml(item.label) + '</option>';
        }).join('');
    }

    function openNoteTargetModal(target, noteId) {
        const modal = getNoteTargetModal();
        if (!modal) {
            return;
        }

        const note = noteById(noteId);
        noteTargetState = {
            target: String(target || 'case'),
            noteId: Number(noteId || 0)
        };

        const titleEl = byId('bbNoteTargetModalLabel');
        const idLabel = byId('bbNoteTargetIdLabel');
        const idInput = byId('bbNoteTargetIdInput');
        const textInput = byId('bbNoteTargetTextInput');
        const submitBtn = byId('bbNoteTargetSubmitBtn');

        if (titleEl) {
            const targetTitle = noteTargetState.target === 'contact'
                ? 'kontakt'
                : (noteTargetState.target === 'customer' ? 'firma' : 'sag-kommentar');
            titleEl.innerHTML = '<i class="bi bi-journal-plus me-2"></i>Indsæt note i ' + escapeHtml(targetTitle);
        }

        if (idLabel) {
            if (noteTargetState.target === 'contact') {
                idLabel.textContent = 'Kontakt ID';
            } else if (noteTargetState.target === 'customer') {
                idLabel.textContent = 'Firma ID';
            } else {
                idLabel.textContent = 'Sag ID';
            }
        }

        if (idInput) {
            const defaultCaseId = resolveQuickNoteCaseId();
            const defaultId = noteTargetState.target === 'case' && defaultCaseId > 0 ? defaultCaseId : 0;
            idInput.value = defaultId > 0 ? String(defaultId) : '';
        }

        if (textInput) {
            textInput.value = String((note && note.content) || '');
        }

        if (submitBtn) {
            submitBtn.disabled = false;
            submitBtn.dataset.target = noteTargetState.target;
            submitBtn.dataset.noteId = String(noteTargetState.noteId);
        }

        renderNoteTargetFieldOptions(noteTargetState.target);
        updateNoteTargetStatus('Vælg mål og indsæt tekst.', null);
        modal.show();
    }

    function updateQuickNoteHint(message, isError) {
        const hint = byId('bbQuickNoteHint');
        quickNoteHintState.message = message;
        quickNoteHintState.level = isError ? 'danger' : 'success';
        if (!hint) {
            return;
        }
        hint.textContent = message;
        hint.classList.remove('text-muted');
        hint.classList.toggle('text-danger', !!isError);
        hint.classList.toggle('text-success', !isError);
    }

    function bindHeaderActions() {
        const backBtn = byId('bbBackBtn');
        const searchBtn = byId('bbSearchBtn');
        const notificationsBtn = byId('bbNotificationsBtn');
        const pauseBtn = byId('bbTimerPauseBtn');
        const stopBtn = byId('bbTimerStopBtn');
        const switchBtn = byId('bbTimerSwitchBtn');
        const timerChip = byId('bbActiveTimerChip');

        if (backBtn) {
            backBtn.addEventListener('click', function () {
                if (window.history.length > 1) {
                    window.history.back();
                } else {
                    window.location.href = '/sag';
                }
            });
        }

        if (searchBtn) {
            searchBtn.addEventListener('click', function () {
                const trigger = byId('globalSearchBtn');
                if (trigger) {
                    trigger.click();
                }
            });
        }

        if (notificationsBtn) {
            notificationsBtn.addEventListener('click', function () {
                if (latestNotifications.length > 0) {
                    const first = latestNotifications[0] || {};
                    if (first.action) {
                        window.location.href = first.action;
                        return;
                    }
                }
                const trigger = byId('globalRemindersBtn');
                if (trigger) {
                    trigger.click();
                }
            });
        }

        if (pauseBtn) {
            pauseBtn.addEventListener('click', function () {
                const activeTimer = (((latestSections || {}).timer || {}).active || {});
                const own = (((latestSections || {}).timer || {}).own || {});
                const paused = Array.isArray(own.paused) ? own.paused : [];

                if (activeTimer.active) {
                    pauseActiveTimer()
                        .then(fetchBottomBarState)
                        .then(applyState)
                        .catch(function (err) {
                            console.warn('Failed pausing timer', err);
                        });
                    return;
                }

                const pausedTimeId = Number((((paused[0] || {}).time_entry_id) || ((paused[0] || {}).id) || 0));
                resumeTimer(pausedTimeId || null)
                    .then(fetchBottomBarState)
                    .then(applyState)
                    .catch(function (err) {
                        console.warn('Failed resuming timer', err);
                    });
            });
        }

        if (stopBtn) {
            stopBtn.addEventListener('click', function () {
                stopActiveTimer()
                    .then(fetchBottomBarState)
                    .then(applyState)
                    .catch(function (err) {
                        console.warn('Failed stopping timer', err);
                    });
            });
        }

        if (switchBtn) {
            switchBtn.addEventListener('click', function () {
                openSwitchCaseModal();
            });
        }

        if (timerChip) {
            timerChip.addEventListener('click', function () {
                window.location.href = '/timetracking';
            });
        }

        document.addEventListener('click', function (e) {
            const actionBtn = e.target && e.target.closest('[data-bb-create]');
            if (!actionBtn) return;

            const actionKey = actionBtn.getAttribute('data-bb-create');
            const actions = (latestContextActions.context || []).concat(latestContextActions.global || []);
            const matched = actions.find(function (item) { return item.id === actionKey; });

            if (actionKey === 'new_case') {
                const quickBtn = byId('quickCreateBtn');
                if (quickBtn) {
                    quickBtn.click();
                    return;
                }
            }
            if (matched && matched.action) {
                window.location.href = matched.action;
            }
        });
    }

    function bindDynamicActions() {
        document.addEventListener('click', function (e) {
            const target = e.target;
            const btn = target && target.closest('button');
            if (!btn) return;

            if (btn.id === 'bbNoteClearBtn') {
                noteEditorState = { editingId: 0, title: '', content: '' };
                renderTabPanel();
                return;
            }

            if (btn.id === 'bbNoteSaveBtn') {
                const titleInput = byId('bbNoteTitleInput');
                const contentInput = byId('bbNoteContentInput');
                const title = titleInput ? String(titleInput.value || '').trim() : '';
                const content = contentInput ? String(contentInput.value || '').trim() : '';
                if (!content) {
                    const detail = byId('bbCountDetail');
                    if (detail) {
                        detail.innerHTML = '<i class="bi bi-exclamation-triangle me-1 text-warning"></i> Noten er tom.';
                    }
                    return;
                }

                const editId = Number(btn.getAttribute('data-note-edit-id') || 0);
                const action = editId > 0
                    ? updateUserNote(editId, { title: title, content: content })
                    : createUserNote(title, content);

                action
                    .then(fetchBottomBarState)
                    .then(function (data) {
                        noteEditorState = { editingId: 0, title: '', content: '' };
                        applyState(data);
                        const detail = byId('bbCountDetail');
                        if (detail) {
                            detail.innerHTML = '<i class="bi bi-check-circle me-1 text-success"></i> Note gemt.';
                        }
                    })
                    .catch(function (err) {
                        console.warn('Failed saving note', err);
                        const detail = byId('bbCountDetail');
                        if (detail) {
                            detail.innerHTML = '<i class="bi bi-exclamation-triangle me-1 text-danger"></i> ' + escapeHtml((err && err.message) ? err.message : 'Kunne ikke gemme note.');
                        }
                    });
                return;
            }

            const noteEditId = Number(btn.getAttribute('data-note-edit') || 0);
            if (noteEditId > 0) {
                const note = noteById(noteEditId);
                noteEditorState = {
                    editingId: noteEditId,
                    title: String((note && note.title) || ''),
                    content: String((note && note.content) || '')
                };
                renderTabPanel();
                return;
            }

            const notePinId = Number(btn.getAttribute('data-note-pin') || 0);
            if (notePinId > 0) {
                const note = noteById(notePinId);
                const pinned = !!(note && note.is_pinned);
                updateUserNote(notePinId, { is_pinned: !pinned })
                    .then(fetchBottomBarState)
                    .then(applyState)
                    .catch(function (err) {
                        console.warn('Failed pin toggle', err);
                    });
                return;
            }

            const noteDeleteId = Number(btn.getAttribute('data-note-delete') || 0);
            if (noteDeleteId > 0) {
                if (!window.confirm('Slet note permanent fra din liste?')) {
                    return;
                }
                deleteUserNote(noteDeleteId)
                    .then(fetchBottomBarState)
                    .then(function (data) {
                        if (Number(noteEditorState.editingId || 0) === noteDeleteId) {
                            noteEditorState = { editingId: 0, title: '', content: '' };
                        }
                        applyState(data);
                    })
                    .catch(function (err) {
                        console.warn('Failed deleting note', err);
                    });
                return;
            }

            const noteToCaseId = Number(btn.getAttribute('data-note-to-case') || 0);
            if (noteToCaseId > 0) {
                openNoteTargetModal('case', noteToCaseId);
                return;
            }

            const noteToContactId = Number(btn.getAttribute('data-note-to-contact') || 0);
            if (noteToContactId > 0) {
                openNoteTargetModal('contact', noteToContactId);
                return;
            }

            const noteToCustomerId = Number(btn.getAttribute('data-note-to-customer') || 0);
            if (noteToCustomerId > 0) {
                openNoteTargetModal('customer', noteToCustomerId);
                return;
            }

            if (btn.id === 'bbNoteTargetSubmitBtn') {
                const target = String(btn.dataset.target || 'case');
                const noteId = Number(btn.dataset.noteId || 0);
                const targetId = Number((byId('bbNoteTargetIdInput') || {}).value || 0);
                const field = String(((byId('bbNoteTargetFieldSelect') || {}).value) || '').trim();
                const text = String(((byId('bbNoteTargetTextInput') || {}).value) || '').trim();
                if (!(noteId > 0)) {
                    updateNoteTargetStatus('Mangler note-id.', true);
                    return;
                }
                if (!(targetId > 0)) {
                    updateNoteTargetStatus('Mål-ID skal være et tal større end 0.', true);
                    return;
                }
                if (!text) {
                    updateNoteTargetStatus('Tekstfeltet er tomt.', true);
                    return;
                }

                btn.disabled = true;
                updateNoteTargetStatus('Gemmer...', null);

                let action;
                if (target === 'contact') {
                    action = noteToContact(noteId, targetId, field || 'mobile', text, 'append');
                } else if (target === 'customer') {
                    action = noteToCustomer(noteId, targetId, field || 'note', text, 'append');
                } else {
                    action = noteToCaseComment(noteId, targetId, text);
                }

                action
                    .then(function () {
                        const detail = byId('bbCountDetail');
                        if (detail) {
                            const targetLabel = target === 'contact' ? 'kontakt' : (target === 'customer' ? 'firma' : 'sag');
                            detail.innerHTML = '<i class="bi bi-check-circle me-1 text-success"></i> Note-data gemt på ' + targetLabel + ' #' + targetId;
                        }
                        updateNoteTargetStatus('Gemt.', false);
                        const modal = getNoteTargetModal();
                        if (modal) {
                            modal.hide();
                        }
                    })
                    .catch(function (err) {
                        console.warn('Failed note target insert', err);
                        updateNoteTargetStatus((err && err.message) ? err.message : 'Kunne ikke gemme note-data.', true);
                    })
                    .finally(function () {
                        btn.disabled = false;
                    });
                return;
            }

            const switchAction = btn.getAttribute('data-bb-switch-action');
            if (switchAction) {
                if (switchAction === 'continue-unchanged') {
                    switchCaseState.decision = 'unchanged';
                    switchCaseStatusMessage('<i class="bi bi-info-circle me-1"></i>Timer fortsætter uændret. Du kan åbne en sag uden at starte ny timer.');
                    return;
                }

                if (switchAction === 'pause-now') {
                    pauseActiveTimer().then(function () {
                        switchCaseState.decision = 'pause';
                        switchCaseState.activeTimer = null;
                        switchCaseStatusMessage('<i class="bi bi-check-circle me-1 text-success"></i>Timer sat på pause. Du kan nu starte ny timer.');
                        return loadSwitchCaseData();
                    }).catch(function (err) {
                        switchCaseStatusMessage('<i class="bi bi-exclamation-triangle me-1 text-danger"></i>' + escapeHtml(err.message || 'Kunne ikke pause timer.'));
                    });
                    return;
                }

                if (switchAction === 'stop-now') {
                    stopActiveTimer().then(function () {
                        switchCaseState.decision = 'stop';
                        switchCaseState.activeTimer = null;
                        switchCaseStatusMessage('<i class="bi bi-check-circle me-1 text-success"></i>Aktiv timer stoppet. Du kan nu starte ny timer.');
                        return loadSwitchCaseData();
                    }).catch(function () {
                        switchCaseStatusMessage('<i class="bi bi-exclamation-triangle me-1 text-danger"></i>Kunne ikke stoppe timer.');
                    });
                    return;
                }
            }

            const openCaseId = Number(btn.getAttribute('data-bb-open-case') || 0);
            if (openCaseId > 0) {
                openCaseDetail(openCaseId);
                return;
            }

            const startCaseId = Number(btn.getAttribute('data-bb-start-case') || 0);
            if (startCaseId > 0) {
                startTimerForCase(startCaseId);
                return;
            }

            const stopTimeId = Number(btn.getAttribute('data-bb-stop-time') || 0);
            if (stopTimeId > 0) {
                fetch('/api/v1/timetracking/time/stop', {
                    method: 'POST',
                    credentials: 'include',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ time_id: stopTimeId })
                })
                .then(fetchBottomBarState)
                .then(applyState)
                .catch(function (err) {
                    console.warn('Failed stopping timer from list', err);
                });
                return;
            }

            if (btn.id === 'bbQuickNoteSaveBtn') {
                const input = byId('bbQuickNoteInput');
                const value = input ? String(input.value || '').trim() : '';
                quickNoteDraft = value;
                if (!value) {
                    updateQuickNoteHint('Skriv en note først.', true);
                    return;
                }

                const caseId = resolveQuickNoteCaseId();
                if (!(caseId > 0)) {
                    updateQuickNoteHint('Åbn en sag (eller start timer på en sag) før du gemmer quick note.', true);
                    return;
                }

                const originalHtml = btn.innerHTML;
                btn.disabled = true;
                btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>Gemmer...';

                saveQuickNote(value, caseId)
                    .then(function () {
                        if (input) {
                            input.value = '';
                        }
                        quickNoteDraft = '';
                        updateQuickNoteHint('Gemte note på sag #' + caseId + '.', false);
                        const detail = byId('bbCountDetail');
                        if (detail) {
                            detail.innerHTML = '<i class="bi bi-check-circle me-1 text-success"></i> Quick note gemt på sag #' + caseId;
                        }
                    })
                    .catch(function (err) {
                        updateQuickNoteHint((err && err.message) ? err.message : 'Kunne ikke gemme note.', true);
                    })
                    .finally(function () {
                        btn.disabled = false;
                        btn.innerHTML = originalHtml;
                    });
                return;
            }

            const bossAction = btn.getAttribute('data-boss-action');
            if (bossAction) {
                if (bossAction === 'assign_next_to_owner') {
                    const ownerId = Number(btn.getAttribute('data-owner-id') || 0);
                    if (ownerId <= 0) {
                        return;
                    }

                    const originalHtml = btn.innerHTML;
                    btn.disabled = true;
                    btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>Tildeler...';

                    fetch('/api/v1/bottom-bar/boss/assign-next-to-user', {
                        method: 'POST',
                        credentials: 'include',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ assignee_user_id: ownerId })
                    })
                    .then(async r => {
                        const body = await r.json().catch(() => ({}));
                        if (!r.ok) {
                            const detail = body && body.detail ? body.detail : 'Kunne ikke tildele næste sag';
                            throw new Error(typeof detail === 'string' ? detail : 'Kunne ikke tildele næste sag');
                        }
                        return body;
                    })
                    .then(data => {
                        const detail = byId('bbCountDetail');
                        if (detail) {
                            if (data.status === 'assigned' && data.case) {
                                detail.innerHTML = '<i class="bi bi-check-circle me-1 text-success"></i> Tildelt: ' + escapeHtml(data.case.title || 'Sag') + ' til tekniker.';
                            } else {
                                detail.innerHTML = '<i class="bi bi-info-circle me-1 text-accent"></i> ' + escapeHtml(data.message || 'Ingen sager at tildele');
                            }
                        }
                        return fetchBottomBarState();
                    })
                    .then(applyState)
                    .catch(err => {
                        console.error('Assign next to owner failed', err);
                        const detail = byId('bbCountDetail');
                        if (detail) {
                            detail.innerHTML = '<i class="bi bi-exclamation-triangle me-1 text-danger"></i> ' + escapeHtml(err.message || 'Fejl ved tildeling');
                        }
                    })
                    .finally(() => {
                        btn.disabled = false;
                        btn.innerHTML = originalHtml;
                    });
                    return;
                }
                if (bossAction === 'auto_assign_next') {
                    const originalHtml = btn.innerHTML;
                    btn.disabled = true;
                    btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>Fordeler...';

                    fetch('/api/v1/bottom-bar/boss/auto-assign-next', {
                        method: 'POST',
                        credentials: 'include'
                    })
                    .then(async r => {
                        const body = await r.json().catch(() => ({}));
                        if (!r.ok) {
                            const detail = body && body.detail ? body.detail : 'Kunne ikke auto-fordele sag';
                            throw new Error(typeof detail === 'string' ? detail : 'Kunne ikke auto-fordele sag');
                        }
                        return body;
                    })
                    .then(data => {
                        const detail = byId('bbCountDetail');
                        if (detail) {
                            if (data.status === 'assigned' && data.case && data.assignee) {
                                detail.innerHTML = '<i class="bi bi-check-circle me-1 text-success"></i> Auto-fordelt: ' + escapeHtml(data.case.title || 'Sag') + ' → ' + escapeHtml(data.assignee.name || 'medarbejder');
                            } else {
                                detail.innerHTML = '<i class="bi bi-info-circle me-1 text-accent"></i> ' + escapeHtml(data.message || 'Ingen sager at fordele');
                            }
                        }
                        return fetchBottomBarState();
                    })
                    .then(applyState)
                    .catch(err => {
                        console.error('Boss auto-assign failed', err);
                        const detail = byId('bbCountDetail');
                        if (detail) {
                            detail.innerHTML = '<i class="bi bi-exclamation-triangle me-1 text-danger"></i> ' + escapeHtml(err.message || 'Fejl ved auto-fordeling');
                        }
                    })
                    .finally(() => {
                        btn.disabled = false;
                        btn.innerHTML = originalHtml;
                    });
                    return;
                }
                if (bossAction === 'open_unassigned') {
                    openUnassignedCasesPanel();
                    return;
                }
                if (bossAction === 'open_escalations') {
                    window.location.href = '/sag?priority=urgent';
                    return;
                }
                if (bossAction === 'open_team') {
                    window.location.href = '/timetracking';
                    return;
                }
                if (bossAction === 'open_owner') {
                    const ownerId = Number(btn.getAttribute('data-owner-id') || 0);
                    window.location.href = ownerId > 0 ? ('/sag?ansvarlig=' + ownerId) : '/sag';
                    return;
                }
                if (bossAction === 'open_case') {
                    const caseId = Number(btn.getAttribute('data-case-id') || 0);
                    window.location.href = caseId > 0 ? ('/sag/' + caseId) : '/sag';
                    return;
                }
            }

            if (btn.id === 'btnNextTask') {
                console.log("-> Beder backend om næste opgave...");
                btn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Omsætter kalender og SLA...';
                btn.disabled = true;
                
                fetch('/api/v1/bottom-bar/next_task', { method: 'POST', credentials: 'include' })
                .then(r => {
                    if (!r.ok) {
                        throw new Error('Kunne ikke hente næste opgave');
                    }
                    return r.json();
                })
                .then(data => {
                    const task = data && data.task ? data.task : {};
                    const taskTitle = task.title || 'Ingen opgave fundet';
                    const caseId = task.case_id || '-';
                    const freeMins = data && data.free_time_calculated ? data.free_time_calculated : 0;
                    btn.innerHTML = '<i class="bi bi-magic me-2"></i>Du fik tildelt: ' + taskTitle + ' (Sag #' + caseId + ') <span class="badge bg-light text-dark ms-2">' + freeMins + 'm fri</span>';
                    btn.classList.add('btn-success');
                    btn.classList.remove('btn-primary');
                })
                .catch(err => {
                    console.error("Fejl:", err);
                    btn.innerHTML = "Fejl - prøv igen";
                    btn.disabled = false;
                });
            }

            if (btn.id === 'btnSendMsg') {
                const input = document.getElementById('chatInputQuick');
                const recipientObj = document.getElementById('chatRecipient');
                
                if (input && input.value.trim() !== '') {
                    const recipient = recipientObj ? recipientObj.options[recipientObj.selectedIndex].text : 'Alle';
                    
                    console.log("-> Sender besked til", recipient, ":", input.value);
                    
                    const msgVal = input.value;
                    input.value = '';
                    
                    const msgContainer = document.createElement('div');
                    msgContainer.className = 'mb-2 text-end';
                    msgContainer.innerHTML = '<div class="small text-muted mb-1 me-1" style="font-size:0.7rem;">Til: ' + escapeHtml(recipient) + '</div><div class="d-inline-block bg-primary text-white p-2 rounded-3 text-start shadow-sm" style="max-width: 85%;"><strong>Mig:</strong> ' + escapeHtml(msgVal) + '</div>';

                    const chatContainer = document.querySelector('#bbTabInnerContent .d-flex.flex-column.h-100');
                    if (!chatContainer) {
                        return;
                    }
                    const listUl = chatContainer.querySelector('ul.bb-tab-list');
                    if (!listUl) {
                        return;
                    }
                    listUl.appendChild(msgContainer);
                    
                    // Simple hacky scroll down
                    const tabInner = document.getElementById('bbTabInnerContent');
                    if(tabInner) {
                        tabInner.scrollTop = tabInner.scrollHeight + 500;
                    }
                }
            }
        });

        document.addEventListener('keydown', function (e) {
            if (e.key !== 'Enter') {
                return;
            }
            const input = byId('bbQuickNoteInput');
            if (!input || document.activeElement !== input) {
                return;
            }
            e.preventDefault();
            const saveBtn = byId('bbQuickNoteSaveBtn');
            if (saveBtn) {
                saveBtn.click();
            }
        });

        document.addEventListener('input', function (e) {
            const target = e.target;
            if (!target || target.id !== 'bbQuickNoteInput') {
                if (target && target.id === 'bbNoteTitleInput') {
                    noteEditorState.title = String(target.value || '');
                }
                if (target && target.id === 'bbNoteContentInput') {
                    noteEditorState.content = String(target.value || '');
                }
                return;
            }
            quickNoteDraft = String(target.value || '');
            if (quickNoteHintState.level !== 'muted') {
                quickNoteHintState = {
                    message: 'Tip: gemmer som kommentar på aktiv/åben sag.',
                    level: 'muted'
                };
                const hint = byId('bbQuickNoteHint');
                if (hint) {
                    hint.textContent = quickNoteHintState.message;
                    hint.classList.remove('text-danger', 'text-success');
                    hint.classList.add('text-muted');
                }
            }
        });
    }

    document.addEventListener('DOMContentLoaded', function () {
        activeKey = 'overview'; // Default overview state
        bindChipClicks();
        bindChipHoverPreview();
        bindSheetToggle();
        bindHeaderActions();
        bindDynamicActions();

        bindSideTabs();

        startPollingFallback();
        connectRealtime();
    });

})();
