// ==========================================
// Mermaid Diagram Renderer — Browser Extension
// ==========================================
// Renders ```mermaid code blocks as interactive SVG diagrams.
// Features: viewBox-based zoom/pan, context-aware expand (fullscreen
// or side-panel pop-out), SVG/PNG export, source copy.
// Loads mermaid.js dynamically on first use.
//
// Uses ctx.ui primitives from the host app for toast notifications,
// side-panel preview, theme detection, and mobile awareness.
// ==========================================

Extensions.register({
    id: 'mermaid-renderer',

    _mermaidReady: false,
    _mermaidLoading: null,
    _ctx: null,

    async init(ctx) {
        const self = this;
        this._ctx = ctx;

        this._injectStyles();

        // ── Block renderer: match ```mermaid ──
        ctx.renderers.register('mermaid', {
            type: 'block',
            pattern: 'mermaid',
            priority: 10,
            render(lang, code, container) {
                const id = 'mmd-' + Math.random().toString(36).slice(2, 9);
                container.innerHTML = `
                    <div class="mermaid-block" data-mermaid-id="${id}">
                        <div class="mermaid-toolbar">
                            <span class="mermaid-title">\u{1f4ca} Diagram</span>
                            <span class="mermaid-zoom-label" data-zoom-label="${id}">100%</span>
                            <div class="mermaid-toolbar-btns">
                                <button class="mmd-btn" data-action="zoom-in" data-target="${id}" title="Zoom in">+</button>
                                <button class="mmd-btn" data-action="zoom-out" data-target="${id}" title="Zoom out">\u2212</button>
                                <button class="mmd-btn" data-action="zoom-fit" data-target="${id}" title="Fit to view">\u22a1</button>
                                <button class="mmd-btn" data-action="zoom-reset" data-target="${id}" title="Reset zoom">1:1</button>
                                <span class="mmd-sep"></span>
                                <button class="mmd-btn" data-action="expand" data-target="${id}" title="Expand">\u26f6</button>
                                <span class="mmd-sep"></span>
                                <button class="mmd-btn" data-action="export-svg" data-target="${id}" title="Download SVG">SVG</button>
                                <button class="mmd-btn" data-action="export-png" data-target="${id}" title="Download PNG">PNG</button>
                            </div>
                        </div>
                        <div class="mermaid-viewport" data-viewport="${id}">
                            <div class="mermaid-diagram" data-mermaid-src="${encodeURIComponent(code.trim())}" data-diagram="${id}">
                                <div class="mermaid-loading">
                                    <span class="mermaid-spinner"></span> Rendering diagram\u2026
                                </div>
                            </div>
                        </div>
                        <details class="mermaid-source">
                            <summary>
                                <span>\u{1f4cb} View source</span>
                                <button class="mmd-btn mmd-copy-src" data-action="copy-src" data-target="${id}" title="Copy source" onclick="event.stopPropagation()">Copy</button>
                            </summary>
                            <pre><code class="language-mermaid" data-source="${id}">${self._escapeHtml(code.trim())}</code></pre>
                        </details>
                    </div>
                `;
            }
        });

        // ── Post renderer: render diagrams + wire interactivity ──
        ctx.renderers.register('mermaid-post', {
            type: 'post',
            priority: 10,
            render(container) {
                const diagrams = container.querySelectorAll('.mermaid-diagram[data-mermaid-src]');
                if (diagrams.length === 0) return;

                diagrams.forEach(el => {
                    if (el.dataset.rendered) return;
                    el.dataset.rendered = 'pending';
                    self._renderDiagram(el);
                });

                self._wireToolbar(container);
            }
        });

        this._loadMermaid();
    },

    // ── ViewBox Zoom/Pan State ──────────────

    _getState(id) {
        const vp = document.querySelector(`[data-viewport="${id}"]`);
        if (!vp) return null;
        if (!vp._mmdState) {
            vp._mmdState = {
                natX: 0, natY: 0, natW: 0, natH: 0,
                vbX: 0, vbY: 0, vbW: 0, vbH: 0,
                dragging: false, startX: 0, startY: 0,
                startVbX: 0, startVbY: 0,
                ready: false,
            };
        }
        return vp._mmdState;
    },

    _initState(id) {
        const state = this._getState(id);
        if (!state) return;
        const svg = document.querySelector(`[data-diagram="${id}"] svg`);
        if (!svg) return;

        const vb = svg.getAttribute('viewBox');
        if (!vb) {
            const bbox = svg.getBBox();
            state.natX = bbox.x;
            state.natY = bbox.y;
            state.natW = bbox.width;
            state.natH = bbox.height;
        } else {
            const parts = vb.trim().split(/[\s,]+/).map(Number);
            state.natX = parts[0] || 0;
            state.natY = parts[1] || 0;
            state.natW = parts[2] || 0;
            state.natH = parts[3] || 0;
        }

        state.vbX = state.natX;
        state.vbY = state.natY;
        state.vbW = state.natW;
        state.vbH = state.natH;
        state.ready = true;

        this._applyViewBox(id);
    },

    _applyViewBox(id) {
        const state = this._getState(id);
        if (!state || !state.ready) return;
        const svg = document.querySelector(`[data-diagram="${id}"] svg`);
        if (!svg) return;

        svg.setAttribute('viewBox', `${state.vbX} ${state.vbY} ${state.vbW} ${state.vbH}`);

        const zoomPct = Math.round((state.natW / state.vbW) * 100);
        const label = document.querySelector(`[data-zoom-label="${id}"]`);
        if (label) label.textContent = zoomPct + '%';
    },

    _zoom(id, factor) {
        const state = this._getState(id);
        if (!state || !state.ready) return;

        const scale = 1 / (1 + factor);
        const newW = state.vbW * scale;
        const newH = state.vbH * scale;

        const minW = state.natW / 20;
        const maxW = state.natW * 2;
        if (newW < minW || newW > maxW) return;

        const cx = state.vbX + state.vbW / 2;
        const cy = state.vbY + state.vbH / 2;

        state.vbW = newW;
        state.vbH = newH;
        state.vbX = cx - newW / 2;
        state.vbY = cy - newH / 2;

        this._applyViewBox(id);
    },

    _zoomAt(id, factor, clientX, clientY) {
        const state = this._getState(id);
        if (!state || !state.ready) return;
        const svg = document.querySelector(`[data-diagram="${id}"] svg`);
        if (!svg) return;

        const svgRect = svg.getBoundingClientRect();
        if (svgRect.width === 0 || svgRect.height === 0) return;

        const fx = (clientX - svgRect.left) / svgRect.width;
        const fy = (clientY - svgRect.top) / svgRect.height;
        const pointX = state.vbX + fx * state.vbW;
        const pointY = state.vbY + fy * state.vbH;

        const scale = 1 / (1 + factor);
        const newW = state.vbW * scale;
        const newH = state.vbH * scale;

        const minW = state.natW / 20;
        const maxW = state.natW * 2;
        if (newW < minW || newW > maxW) return;

        state.vbW = newW;
        state.vbH = newH;
        state.vbX = pointX - fx * newW;
        state.vbY = pointY - fy * newH;

        this._applyViewBox(id);
    },

    _zoomReset(id) {
        const state = this._getState(id);
        if (!state || !state.ready) return;
        state.vbX = state.natX;
        state.vbY = state.natY;
        state.vbW = state.natW;
        state.vbH = state.natH;
        this._applyViewBox(id);
    },

    _zoomFit(id) {
        const state = this._getState(id);
        if (!state || !state.ready) return;
        const vp = document.querySelector(`[data-viewport="${id}"]`);
        if (!vp) return;

        const vpRect = vp.getBoundingClientRect();
        if (vpRect.width === 0 || vpRect.height === 0) return;

        const vpAspect = vpRect.width / vpRect.height;
        const natAspect = state.natW / state.natH;

        if (vpAspect > natAspect) {
            const newW = state.natH * vpAspect;
            state.vbX = state.natX - (newW - state.natW) / 2;
            state.vbY = state.natY;
            state.vbW = newW;
            state.vbH = state.natH;
        } else {
            const newH = state.natW / vpAspect;
            state.vbX = state.natX;
            state.vbY = state.natY - (newH - state.natH) / 2;
            state.vbW = state.natW;
            state.vbH = newH;
        }

        this._applyViewBox(id);
    },

    // ── Expand (context-aware) ──────────────
    // Side panel open → pop out into it (replaces current content).
    // Side panel closed → fullscreen overlay.

    _expand(id) {
        if (this._ctx.ui.isPanelOpen()) {
            this._popOutToPanel(id);
        } else {
            this._toggleFullscreen(id);
        }
    },

    // ── Fullscreen ──────────────────────────

    _toggleFullscreen(id) {
        const block = document.querySelector(`[data-mermaid-id="${id}"]`);
        if (!block) return;

        const isFS = block.classList.toggle('mermaid-fullscreen');

        if (isFS) {
            document.body.style.overflow = 'hidden';

            // Close button overlay (always visible — critical for mobile)
            const closeBtn = document.createElement('button');
            closeBtn.className = 'mmd-fullscreen-close';
            closeBtn.innerHTML = '\u2715';
            closeBtn.title = 'Close fullscreen';
            closeBtn.addEventListener('click', () => this._toggleFullscreen(id));
            block.appendChild(closeBtn);

            // Escape listener (desktop convenience, not sole exit)
            block._mmdEscHandler = (e) => {
                if (e.key === 'Escape') this._toggleFullscreen(id);
            };
            document.addEventListener('keydown', block._mmdEscHandler);

            requestAnimationFrame(() => this._zoomFit(id));
        } else {
            document.body.style.overflow = '';

            const closeBtn = block.querySelector('.mmd-fullscreen-close');
            if (closeBtn) closeBtn.remove();

            if (block._mmdEscHandler) {
                document.removeEventListener('keydown', block._mmdEscHandler);
                delete block._mmdEscHandler;
            }
        }
    },

    // ── Side Panel Pop-out ──────────────────

    _popOutToPanel(id) {
        const diagram = document.querySelector(`[data-diagram="${id}"]`);
        const svg = diagram?.querySelector('svg');
        if (!svg) return;

        const state = this._getState(id);
        const clone = svg.cloneNode(true);
        if (state?.ready) {
            clone.setAttribute('viewBox',
                `${state.natX} ${state.natY} ${state.natW} ${state.natH}`);
        }
        clone.setAttribute('width', '100%');
        clone.removeAttribute('height');
        clone.setAttribute('preserveAspectRatio', 'xMidYMid meet');

        const isDark = this._ctx.ui.isDark();
        const html = `<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<style>
  body { margin: 0; padding: 16px; display: flex; justify-content: center;
         align-items: flex-start; min-height: 100vh;
         background: ${isDark ? '#1a1a2e' : '#fff'};
         font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }
  svg { max-width: 100%; height: auto; }
</style>
</head><body>${clone.outerHTML}</body></html>`;

        this._ctx.ui.openPreview(html);
    },

    // ── Toolbar Wiring ──────────────────────

    _wireToolbar(container) {
        const self = this;

        if (container._mmdWired) return;
        container._mmdWired = true;

        container.addEventListener('click', (e) => {
            const btn = e.target.closest('[data-action]');
            if (!btn) return;
            const action = btn.dataset.action;
            const id = btn.dataset.target;
            if (!id) return;

            switch (action) {
                case 'zoom-in':    self._zoom(id, 0.25); break;
                case 'zoom-out':   self._zoom(id, -0.2); break;
                case 'zoom-reset': self._zoomReset(id); break;
                case 'zoom-fit':   self._zoomFit(id); break;
                case 'expand':     self._expand(id); break;
                case 'export-svg': self._exportSVG(id); break;
                case 'export-png': self._exportPNG(id); break;
                case 'copy-src':   self._copySource(id); break;
            }
        });

        // Wire each viewport for mouse/touch interaction
        container.querySelectorAll('.mermaid-viewport').forEach(vp => {
            if (vp._mmdWired) return;
            vp._mmdWired = true;
            const id = vp.dataset.viewport;

            vp.addEventListener('wheel', (e) => {
                e.preventDefault();
                const delta = e.deltaY > 0 ? -0.1 : 0.1;
                self._zoomAt(id, delta, e.clientX, e.clientY);
            }, { passive: false });

            vp.addEventListener('mousedown', (e) => {
                if (e.button !== 0) return;
                const state = self._getState(id);
                if (!state || !state.ready) return;
                state.dragging = true;
                state.startX = e.clientX;
                state.startY = e.clientY;
                state.startVbX = state.vbX;
                state.startVbY = state.vbY;
                vp.classList.add('mmd-grabbing');
                e.preventDefault();
            });

            vp.addEventListener('mousemove', (e) => {
                const state = self._getState(id);
                if (!state?.dragging) return;
                const svg = document.querySelector(`[data-diagram="${id}"] svg`);
                if (!svg) return;

                const svgRect = svg.getBoundingClientRect();
                if (svgRect.width === 0) return;

                const pxToVb = state.vbW / svgRect.width;
                const dx = (e.clientX - state.startX) * pxToVb;
                const dy = (e.clientY - state.startY) * pxToVb;

                state.vbX = state.startVbX - dx;
                state.vbY = state.startVbY - dy;
                self._applyViewBox(id);
            });

            const endDrag = () => {
                const state = self._getState(id);
                if (!state) return;
                state.dragging = false;
                vp.classList.remove('mmd-grabbing');
            };
            vp.addEventListener('mouseup', endDrag);
            vp.addEventListener('mouseleave', endDrag);

            let lastTouchDist = 0;
            let lastTouchCenter = null;
            vp.addEventListener('touchstart', (e) => {
                const state = self._getState(id);
                if (!state || !state.ready) return;
                if (e.touches.length === 1) {
                    state.dragging = true;
                    state.startX = e.touches[0].clientX;
                    state.startY = e.touches[0].clientY;
                    state.startVbX = state.vbX;
                    state.startVbY = state.vbY;
                } else if (e.touches.length === 2) {
                    lastTouchDist = Math.hypot(
                        e.touches[0].clientX - e.touches[1].clientX,
                        e.touches[0].clientY - e.touches[1].clientY
                    );
                    lastTouchCenter = {
                        x: (e.touches[0].clientX + e.touches[1].clientX) / 2,
                        y: (e.touches[0].clientY + e.touches[1].clientY) / 2,
                    };
                }
            }, { passive: true });

            vp.addEventListener('touchmove', (e) => {
                const state = self._getState(id);
                if (!state || !state.ready) return;
                if (e.touches.length === 1 && state.dragging) {
                    const svg = document.querySelector(`[data-diagram="${id}"] svg`);
                    if (!svg) return;
                    const svgRect = svg.getBoundingClientRect();
                    if (svgRect.width === 0) return;

                    const pxToVb = state.vbW / svgRect.width;
                    const dx = (e.touches[0].clientX - state.startX) * pxToVb;
                    const dy = (e.touches[0].clientY - state.startY) * pxToVb;
                    state.vbX = state.startVbX - dx;
                    state.vbY = state.startVbY - dy;
                    self._applyViewBox(id);
                    e.preventDefault();
                } else if (e.touches.length === 2) {
                    const dist = Math.hypot(
                        e.touches[0].clientX - e.touches[1].clientX,
                        e.touches[0].clientY - e.touches[1].clientY
                    );
                    const center = {
                        x: (e.touches[0].clientX + e.touches[1].clientX) / 2,
                        y: (e.touches[0].clientY + e.touches[1].clientY) / 2,
                    };
                    if (lastTouchDist > 0) {
                        const factor = (dist - lastTouchDist) / lastTouchDist;
                        self._zoomAt(id, factor, center.x, center.y);
                    }
                    lastTouchDist = dist;
                    lastTouchCenter = center;
                    e.preventDefault();
                }
            }, { passive: false });

            vp.addEventListener('touchend', () => {
                const state = self._getState(id);
                if (state) state.dragging = false;
                lastTouchDist = 0;
                lastTouchCenter = null;
            }, { passive: true });
        });
    },

    // ── Export ───────────────────────────────

    _exportSVG(id) {
        const diagram = document.querySelector(`[data-diagram="${id}"]`);
        const svg = diagram?.querySelector('svg');
        if (!svg) return;

        const state = this._getState(id);
        const clone = svg.cloneNode(true);
        clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
        if (state?.ready) {
            clone.setAttribute('viewBox', `${state.natX} ${state.natY} ${state.natW} ${state.natH}`);
        }
        const blob = new Blob([clone.outerHTML], { type: 'image/svg+xml' });
        this._download(blob, `diagram-${id}.svg`);
    },

    _exportPNG(id) {
        const diagram = document.querySelector(`[data-diagram="${id}"]`);
        const svg = diagram?.querySelector('svg');
        if (!svg) return;

        const state = this._getState(id);
        const clone = svg.cloneNode(true);
        clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
        if (state?.ready) {
            clone.setAttribute('viewBox', `${state.natX} ${state.natY} ${state.natW} ${state.natH}`);
            clone.setAttribute('width', state.natW);
            clone.setAttribute('height', state.natH);
        }

        const svgData = new XMLSerializer().serializeToString(clone);
        const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });
        const url = URL.createObjectURL(svgBlob);
        const self = this;

        const img = new Image();
        img.onload = () => {
            const scale = 2;
            const canvas = document.createElement('canvas');
            canvas.width = img.naturalWidth * scale;
            canvas.height = img.naturalHeight * scale;
            const ctx = canvas.getContext('2d');
            ctx.scale(scale, scale);
            ctx.drawImage(img, 0, 0);
            URL.revokeObjectURL(url);

            canvas.toBlob((blob) => {
                if (blob) self._download(blob, `diagram-${id}.png`);
            }, 'image/png');
        };
        img.onerror = () => {
            URL.revokeObjectURL(url);
            console.error('[Mermaid] PNG export failed');
        };
        img.src = url;
    },

    _download(blob, filename) {
        const a = document.createElement('a');
        a.href = URL.createObjectURL(blob);
        a.download = filename;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        setTimeout(() => URL.revokeObjectURL(a.href), 1000);
    },

    _copySource(id) {
        const code = document.querySelector(`[data-source="${id}"]`);
        if (!code) return;
        navigator.clipboard.writeText(code.textContent).then(() => {
            this._ctx.ui.toast('Source copied', 'success');
        });
    },

    // ── Diagram Rendering ───────────────────

    async _renderDiagram(el) {
        const code = decodeURIComponent(el.dataset.mermaidSrc);
        const id = el.dataset.diagram;

        try {
            await this._loadMermaid();

            const svgId = 'mmd-svg-' + Math.random().toString(36).slice(2, 9);
            const { svg } = await mermaid.render(svgId, code);
            el.innerHTML = svg;
            el.dataset.rendered = 'true';

            const svgEl = el.querySelector('svg');
            if (svgEl) {
                svgEl.removeAttribute('height');
                svgEl.setAttribute('width', '100%');
                svgEl.style.maxWidth = 'none';
                svgEl.setAttribute('preserveAspectRatio', 'xMidYMid meet');
            }

            this._initState(id);
        } catch (e) {
            el.innerHTML = `
                <div class="mermaid-error">
                    <strong>Diagram error:</strong> ${this._escapeHtml(e.message || String(e))}
                </div>
            `;
            el.dataset.rendered = 'error';
        }
    },

    // ── Mermaid Library Loading ──────────────

    _loadMermaid() {
        if (this._mermaidReady) return Promise.resolve();
        if (this._mermaidLoading) return this._mermaidLoading;

        this._mermaidLoading = new Promise((resolve, reject) => {
            if (typeof mermaid !== 'undefined') {
                this._initMermaid();
                this._mermaidReady = true;
                resolve();
                return;
            }

            const base = (window.__BASE__ || '');
            const localSrc = `${base}/vendor/mermaid/mermaid.min.js`;
            const cdnSrc = 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js';

            const script = document.createElement('script');
            script.src = localSrc;
            script.onload = () => {
                this._initMermaid();
                this._mermaidReady = true;
                resolve();
            };
            script.onerror = () => {
                console.warn('[Mermaid] Local vendor not found, trying CDN');
                const cdn = document.createElement('script');
                cdn.src = cdnSrc;
                cdn.onload = () => {
                    this._initMermaid();
                    this._mermaidReady = true;
                    resolve();
                };
                cdn.onerror = () => {
                    console.error('[Mermaid] Failed to load from both local and CDN');
                    reject(new Error('Failed to load mermaid.js'));
                };
                document.head.appendChild(cdn);
            };
            document.head.appendChild(script);
        });

        return this._mermaidLoading;
    },

    _initMermaid() {
        if (typeof mermaid === 'undefined') return;

        mermaid.initialize({
            startOnLoad: false,
            theme: this._ctx.ui.isDark() ? 'dark' : 'default',
            securityLevel: 'strict',
            fontFamily: 'inherit',
            logLevel: 'error',
        });
    },

    // ── Styles ──────────────────────────────

    _injectStyles() {
        if (document.getElementById('ext-style-mermaid-renderer')) return;
        const style = document.createElement('style');
        style.id = 'ext-style-mermaid-renderer';
        style.textContent = `
.mermaid-block {
    background: var(--bg-2); border: 1px solid var(--border);
    border-radius: 8px; overflow: hidden; margin: 12px 0;
}

/* ── Fullscreen mode ── */
.mermaid-block.mermaid-fullscreen {
    position: fixed; top: 0; left: 0; right: 0; bottom: 0;
    z-index: 10000; border-radius: 0; margin: 0;
    display: flex; flex-direction: column;
    background: var(--bg-1, var(--bg-2, #1a1a2e));
}
.mermaid-block.mermaid-fullscreen .mermaid-viewport {
    background: var(--bg-2, #1a1a2e);
    flex: 1; max-height: none;
}
.mermaid-block.mermaid-fullscreen .mermaid-toolbar {
    border-bottom: 1px solid var(--border);
    padding: 6px 14px;
}

/* Fullscreen close button — always visible, critical for mobile */
.mmd-fullscreen-close {
    position: absolute; top: 12px; right: 12px; z-index: 10001;
    width: 40px; height: 40px; border-radius: 50%;
    background: var(--bg-raised, rgba(0,0,0,0.6));
    border: 1px solid var(--border, rgba(255,255,255,0.2));
    color: var(--text, #fff); font-size: 20px; line-height: 1;
    cursor: pointer; display: flex; align-items: center; justify-content: center;
    transition: background 0.15s, transform 0.15s;
    box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
.mmd-fullscreen-close:hover {
    background: var(--bg-hover, rgba(255,255,255,0.15));
    transform: scale(1.1);
}

/* Toolbar */
.mermaid-toolbar {
    display: flex; align-items: center; gap: 6px;
    padding: 4px 10px; border-bottom: 1px solid var(--border);
    font-size: 12px; color: var(--text-3); flex-wrap: wrap;
}
.mermaid-title { font-weight: 600; color: var(--text-2); margin-right: auto; }
.mermaid-zoom-label {
    font-family: var(--mono); font-size: 11px; min-width: 36px;
    text-align: center; color: var(--text-3);
}
.mermaid-toolbar-btns { display: flex; gap: 2px; align-items: center; }
.mmd-btn {
    background: none; border: 1px solid var(--border); border-radius: 4px;
    padding: 1px 7px; font-size: 11px; cursor: pointer;
    color: var(--text-3); font-family: var(--mono); line-height: 1.6;
}
.mmd-btn:hover { color: var(--text-1); border-color: var(--text-3); background: var(--bg-3); }
.mmd-sep { width: 1px; height: 16px; background: var(--border); margin: 0 4px; }

/* Viewport */
.mermaid-viewport {
    overflow: hidden; position: relative;
    min-height: 80px; max-height: 600px;
    cursor: grab; user-select: none;
}
.mermaid-viewport.mmd-grabbing { cursor: grabbing; }

/* Diagram wrapper */
.mermaid-diagram {
    width: 100%; height: 100%; min-height: 60px;
}
.mermaid-diagram svg {
    display: block; width: 100%; height: 100%;
}

/* Loading / Error */
.mermaid-loading {
    color: var(--text-3); font-size: 13px; padding: 20px;
    display: flex; align-items: center; justify-content: center; gap: 8px;
}
.mermaid-spinner {
    display: inline-block; width: 14px; height: 14px;
    border: 2px solid var(--border); border-top-color: var(--accent);
    border-radius: 50%; animation: mmd-spin 0.8s linear infinite;
}
@keyframes mmd-spin { to { transform: rotate(360deg); } }
.mermaid-error {
    color: var(--error, #e74c3c); background: var(--bg-3, rgba(231,76,60,0.1));
    padding: 12px 16px; border-radius: 4px; font-size: 13px;
    font-family: var(--mono); white-space: pre-wrap;
}

/* Source panel */
.mermaid-source { border-top: 1px solid var(--border); font-size: 12px; }
.mermaid-source summary {
    padding: 6px 12px; cursor: pointer; color: var(--text-3);
    user-select: none; display: flex; align-items: center; gap: 8px;
}
.mermaid-source summary:hover { color: var(--text-2); }
.mermaid-source summary span { flex: 1; }
.mmd-copy-src { font-size: 11px; }
.mermaid-source pre {
    margin: 0; border-radius: 0; border: none;
    max-height: 200px; overflow: auto;
}

/* Hide source panel in fullscreen */
.mermaid-block.mermaid-fullscreen .mermaid-source { display: none; }

/* ── Mobile adjustments ── */
@media (max-width: 768px) {
    .mermaid-toolbar { padding: 6px 10px; gap: 4px; }
    .mmd-btn { padding: 4px 10px; font-size: 12px; }
    .mmd-sep { margin: 0 2px; }
    .mmd-fullscreen-close { width: 48px; height: 48px; font-size: 24px; top: 16px; right: 16px; }
}
`;
        document.head.appendChild(style);
    },

    _escapeHtml(str) {
        const div = document.createElement('div');
        div.textContent = str;
        return div.innerHTML;
    },

    destroy() {
        document.getElementById('ext-style-mermaid-renderer')?.remove();
        document.querySelectorAll('.mermaid-fullscreen').forEach(el => {
            el.classList.remove('mermaid-fullscreen');
            const closeBtn = el.querySelector('.mmd-fullscreen-close');
            if (closeBtn) closeBtn.remove();
        });
        document.body.style.overflow = '';
    }
});
