let data = [];
        function esc(s) { return s ? s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;') : ''; }
        function fmtTime(iso) { if(!iso)return''; const d=new Date(iso),now=new Date(),diff=(now-d)/1000; if(diff<60)return'v?a xong'; if(diff<3600)return Math.floor(diff/60)+' ph�t tru?c'; if(diff<86400)return Math.floor(diff/3600)+' gi? tru?c'; if(diff<604800)return Math.floor(diff/86400)+' ng�y tru?c'; return d.toLocaleDateString('vi-VN',{day:'2-digit',month:'2-digit',year:'numeric'}); }

        async function load() {
            try { const r=await fetch('/api/dashboard/changelog'); const j=await r.json(); data=j.entries||[]; render(); }
            catch(e) { console.error(e); }
        }

        function render() {
            const el = document.getElementById('list');
            if (!data.length) { el.innerHTML = `<div class="empty-state"><div class="empty-icon">??</div><p>Chua c� ghi ch� n�o. Th�m d�ng d?u ti�n!</p></div>`; return; }
            el.innerHTML = data.map((e,i) => `
                <div class="cl-entry">
                    <div class="cl-dot"></div>
                    ${i < data.length-1 ? '<div class="cl-line"></div>' : ''}
                    <div class="cl-body">
                        <div class="cl-meta">
                            <span class="cl-author">${esc(e.author)}</span>
                            <span class="cl-time">${fmtTime(e.created_at)}</span>
                        </div>
                        <div class="cl-content">${esc(e.content)}</div>
                    </div>
                    <button class="cl-delete" title="X�a" onclick="del('${e.id}')">???</button>
                </div>`).join('');
        }

        async function add() {
            const author=document.getElementById('clAuthor').value.trim(), content=document.getElementById('clContent').value.trim();
            if(!content){document.getElementById('clContent').focus();return;}
            try { await fetch('/api/dashboard/changelog',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({content,author:author||'Admin'})}); document.getElementById('clContent').value=''; await load(); }
            catch(e) { alert(e.message); }
        }

        async function del(id) {
            if(!confirm('X�a ghi ch� n�y?'))return;
            try { await fetch(`/api/dashboard/changelog/${id}`,{method:'DELETE'}); await load(); }
            catch(e) { alert(e.message); }
        }

        document.getElementById('clContent').addEventListener('keydown', e => { if(e.key==='Enter')add(); });
        load();