Instruction: Create an AUTARCH web template for the 'Port Scanner' page. It should extend base.html, have a page header, and use AUTARCH's CSS variables and UI patterns (sections, tab bars, data tables, buttons).

Input:
Template: port_scanner.html
Sections: 0
Tabs: 0
Forms/API calls: 2
Has JavaScript: True

Output:
{% extends "base.html" %}
{% block title %}Port Scanner — AUTARCH{% endblock %}
{% block content %}

<div class="page-header">
    <h1>Port Scanner</h1>
    <p class="text-muted" style="font-size:0.85rem;color:var(--text-secondary)">
        Advanced TCP port scanner with nmap integration and real-time live output
    </p>
</div>

<div style="display:grid;grid-template-columns:380px 1fr;gap:1.25rem;align-items:start">

    <!-- ── Config Panel ── -->
    <div>
        <div class="card">
            <h3>Scan Configuration</h3>

            <div class="form-group">
                <label>Target Host / IP</label>
                <input type="text" id="ps-target" class="form-control"
                       placeholder="192.168.1.1 or hostname.local"
                       onkeypress="if(event.key==='Enter')startScan()">
            </div>

            <div class="form-group">
                <label>Scan Mode</label>
                <select id="ps-mode" class="form-control" onchange="onModeChange()">
                    <option value="quick">Quick — 22 common ports (~1s)</option>
                    <option value="common" selected>Common — 110 well-known ports (~5s)</option>
                    <option value="full">Full — All 65,535 ports (may take minutes)</option>
                    <option value="custom">Custom — Specify ports / ranges</option>
                </select>
            </div>

            <div class="form-group" id="custom-ports-group" style="display:none">
                <label>Ports / Ranges (e.g. 22,80,443,8000-9000)</label>
                <input type="text" id="ps-custom-ports" class="form-control"
                       placeholder="22,80,443,1024-2048">
            </div>

            <!-- Options -->
            <div style="padding:12px;background:var(--bg-primary);border:1px solid var(--border);border-radius:var(--radius);margin-bottom:14px">
                <div style="font-size:0.75rem;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:10px">Options</div>

                <div style="display:flex;flex-wrap:wrap;gap:10px;margin-bottom:10px">
                    <label style="display:flex;align-items:center;gap:6px;font-size:0.83rem;cursor:pointer">
                        <input type="checkbox" id="opt-nmap" style="width:auto"> Use nmap
                    </label>
                    <label style="display:flex;align-items:center;gap:6px;font-size:0.83rem;cursor:pointer">
                        <input type="checkbox" id="opt-svc" style="width:auto"> Service detection (-sV)
                    </label>
                    <label style="display:flex;align-items:center;gap:6px;font-size:0.83rem;cursor:pointer">
                        <input type="checkbox" id="opt-os" style="width:auto"> OS fingerprint (-O)
                    </label>
                    <label style="display:flex;align-items:center;gap:6px;font-size:0.83rem;cursor:pointer">
                        <input type="checkbox" id="opt-agg" style="width:auto"> Aggressive (-A)
                    </label>
                </div>

                <div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px">
                    <div>
                        <div style="font-size:0.75rem;color:var(--text-muted);margin-bottom:3px">Timeout (s)</div>
                        <input type="number" id="opt-timeout" class="form-control" value="1.0" min="0.1" max="10" step="0.1">
                    </div>
                    <div>
                        <div style="font-size:0.75rem;color:var(--text-muted);margin-bottom:3px">Concurrency</div>
                        <input type="number" id="opt-concurrency" class="form-control" value="200" min="1" max="500">
                    </div>
                    <div>
                        <div style="font-size:0.75rem;color:var(--text-muted);margin-bottom:3px">nmap Timing</div>
                        <select id="opt-timing" class="form-control">
                            <option value="2">T2 — Polite</option>
                            <option value="3">T3 — Normal</option>
                            <option value="4" selected>T4 — Aggressive</option>
                            <option value="5">T5 — Insane</option>
                        </select>
                    </div>
                </div>
            </div>

            <div style="display:flex;gap:8px">
                <button id="ps-start-btn" class="btn btn-primary" style="flex:1" onclick="startScan()">
                    &#x25B6; Start Scan
                </button>
                <button id="ps-cancel-btn" class="btn btn-danger btn-small" style="display:none"
                        onclick="cancelScan()">Cancel</button>
            </div>
        </div>

        <!-- Stats Card -->
        <div class="card" id="stats-card" style="display:none">
            <h3>Scan Stats</h3>
            <table style="width:100%;font-size:0.85rem">
                <tr><td style="color:var(--text-muted);padding:3px 0">Target</td>
                    <td id="st-target" style="text-align:right;color:var(--accent)"></td></tr>
                <tr><td style="color:var(--text-muted);padding:3px 0">Ports Scanned</td>
                    <td id="st-scanned" style="text-align:right"></td></tr>
                <tr><td style="color:var(--text-muted);padding:3px 0">Open Ports</td>
                    <td id="st-open" style="text-align:right;color:var(--success);font-weight:700"></td></tr>
                <tr><td style="color:var(--text-muted);padding:3px 0">Duration</td>
                    <td id="st-duration" style="text-align:right"></td></tr>
                <tr id="st-os-row" style="display:none">
                    <td style="color:var(--text-muted);padding:3px 0">OS Guess</td>
                    <td id="st-os" style="text-align:right;font-size:0.8rem"></td>
                </tr>
            </table>
        </div>
    </div>

    <!-- ── Right Panel — Output + Results ── -->
    <div>
        <!-- Progress bar -->
        <div id="ps-progress-wrap" style="display:none;margin-bottom:1rem">
            <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">
                <span id="ps-progress-label" style="font-size:0.82rem;color:var(--text-secondary)">Initializing...</span>
                <span id="ps-progress-pct" style="font-size:0.82rem;font-weight:600;color:var(--accent)">0%</span>
            </div>
            <div style="background:var(--bg-input);border-radius:4px;height:6px;overflow:hidden">
                <div id="ps-progress-bar" style="height:100%;background:var(--accent);
                     transition:width 0.3s;border-radius:4px;width:0%"></div>
            </div>
        </div>

        <!-- Live output box -->
        <div class="card" style="padding:0;overflow:hidden">
            <div style="display:flex;justify-content:space-between;align-items:center;
                        padding:10px 16px;border-bottom:1px solid var(--border)">
                <span style="font-size:0.8rem;font-weight:600;letter-spacing:0.05em">LIVE OUTPUT</span>
                <div style="display:flex;gap:6px;align-items:center">
                    <span id="ps-status-dot" style="width:8px;height:8px;border-radius:50%;
                          background:var(--text-muted);display:inline-block"></span>
                    <span id="ps-status-txt" style="font-size:0.75rem;color:var(--text-muted)">Idle</span>
                    <button class="btn btn-small" style="font-size:0.7rem;padding:3px 8px"
                            onclick="clearOutput()">Clear</button>
                </div>
            </div>
            <pre id="ps-output" style="background:var(--bg-primary);color:#c8d3f5;
                 font-family:'Cascadia Code','Fira Code','Consolas',monospace;
                 font-size:0.78rem;line-height:1.5;padding:14px;margin:0;
                 height:340px;overflow-y:auto;white-space:pre-wrap;word-break:break-all"></pre>
        </div>

        <!-- Results table -->
        <div id="ps-results-wrap" style="display:none;margin-top:1rem">
            <div class="card" style="padding:0;overflow:hidden">
                <div style="display:flex;justify-content:space-between;align-items:center;
                            padding:12px 16px;border-bottom:1px solid var(--border)">
                    <span style="font-weight:600;font-size:0.9rem">
                        Open Ports — <span id="res-count" style="color:var(--success)">0</span> found
                    </span>
                    <div style="display:flex;gap:6px">
                        <button class="btn btn-small" onclick="exportResults('txt')">Export TXT</button>
                        <button class="btn btn-small" onclick="exportResults('json')">Export JSON</button>
                    </div>
                </div>
                <table class="data-table">
                    <thead>
                        <tr>
                            <th style="width:80px">Port</th>
                            <th style="width:70px">Proto</th>
                            <th style="width:150px">Service</th>
                            <th>Banner / Version</th>
                        </tr>
                    </thead>
                    <tbody id="ps-results-body"></tbody>
                </table>
            </div>
        </div>
    </div>
</div>

<style>
#ps-output .ln-info    { color: #c8d3f5; }
#ps-output .ln-open    { color: #4ade80; font-weight: 700; }
#ps-output .ln-warn    { color: #fbbf24; }
#ps-output .ln-error   { color: #f87171; }
#ps-output .ln-nmap    { color: #94a3b8; font-size: 0.73rem; }
#ps-output .ln-prog    { color: #818cf8; }
#ps-output .ln-done    { color: #34d399; font-weight: 700; }
#ps-output .ln-muted   { color: #475569; }
.advanced-toggle { font-size: 0.82rem; color: var(--text-secondary); cursor: pointer;
                   user-select: none; display: inline-flex; align-items: center; gap: 4px; }
.advanced-toggle:hover { color: var(--text-primary); }
</style>

<script>
let _jobId = null;
let _es = null;
let _openPorts = [];
let _scanResult = null;

function onModeChange() {
    const mode = document.getElementById('ps-mode').value;
    document.getElementById('custom-ports-group').style.display =
        mode === 'custom' ? '' : 'none';
}

function startScan() {
    const target = document.getElementById('ps-target').value.trim();
    if (!target) { alert('Enter a target host or IP address'); return; }
    const mode = document.getElementById('ps-mode').value;
    if (mode === 'custom' && !document.getElementById('ps-custom-ports').value.trim()) {
        alert('Enter ports or ranges for custom mode'); return;
    }

    _openPorts = [];
    _scanResult = null;
    clearOutput();
    document.getElementById('ps-results-wrap').style.display = 'none';
    document.getElementById('stats-card').style.display = 'none';
    document.getElementById('ps-progress-wrap').style.display = '';

    const payload = {
        target,
        mode,
        ports: document.getElementById('ps-custom-ports').value.trim(),
        use_nmap: document.getElementById('opt-nmap').checked,
        service_detection: document.getElementById('opt-svc').checked,
        os_detection: document.getElementById('opt-os').checked,
        aggressive: document.getElementById('opt-agg').checked,
        timing: document.getElementById('opt-timing').value,
        timeout: parseFloat(document.getElementById('opt-timeout').value) || 1.0,
        concurrency: parseInt(document.getElementById('opt-concurrency').value) || 200,
    };

    fetch('/port-scanner/start', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload),
    }).then(r => r.json()).then(d => {
        if (!d.ok) { appendLine('error', '✗ ' + d.error); return; }
        _jobId = d.job_id;
        setStatus('scanning', 'Scanning...');
        document.getElementById('ps-start-btn').disabled = true;
        document.getElementById('ps-cancel-btn').style.display = '';
        appendLine('info', `► Scan started | job=${d.job_id} | ${d.port_count} ports queued`);
        openStream(d.job_id);
    }).catch(e => appendLine('error', '✗ ' + e.message));
}

function openStream(jobId) {
    if (_es) { _es.close(); _es = null; }
    _es = new EventSource('/port-scanner/stream/' + jobId);
    _es.onmessage = e => handleEvent(JSON.parse(e.data));
    _es.onerror = () => { setStatus('idle', 'Connection lost'); };
}

function handleEvent(ev) {
    switch (ev.type) {
        case 'start':
            appendLine('info', `▶ Target: ${ev.target}  |  Ports: ${ev.total_ports}  |  Mode: ${ev.mode}`);
            setProgress(0, ev.total_ports, '0%', 'Starting...');
            document.getElementById('st-target').textContent = ev.target;
            document.getElementById('st-scanned').textContent = ev.total_ports;
            document.getElementById('stats-card').style.display = '';
            break;
        case 'info':
            appendLine('info', '  ' + ev.msg);
            break;
        case 'warning':
            appendLine('warn', '⚠ ' + ev.msg);
            break;
        case 'error':
            appendLine('error', '✗ ' + ev.msg);
            scanFinished();
            break;
        case 'progress':
            setProgress(ev.current, ev.total, ev.pct + '%', `Port ${ev.port} | ${ev.open_count} open | ETA ${ev.eta}`);
            break;
        case 'port_open':
            _openPorts.push(ev);
            const svc = ev.service || 'unknown';
            const banner = ev.banner ? ` — ${ev.banner.substring(0, 60)}` : '';
            appendLine('open', `  ✔ ${String(ev.port).padEnd(6)} ${svc.padEnd(18)}${banner}`);
            addResultRow(ev);
            document.getElementById('res-count').textContent = _openPorts.length;
            document.getElementById('st-open').textContent = _openPorts.length;
            document.getElementById('ps-results-wrap').style.display = '';
            break;
        case 'nmap_start':
            appendLine('info', `  nmap: ${ev.cmd}`);
            break;
        case 'nmap_line':
            if (ev.line.trim()) appendLine('nmap', '  ' + ev.line);
            break;
        case 'done':
            appendLine('done',
                `\n✔ SCAN COMPLETE — ${ev.open_count} open ports found in ${ev.duration}s ` +
                `(${ev.ports_scanned} ports scanned)`
            );
            if (ev.os_guess) {
                appendLine('info', `  OS: ${ev.os_guess}`);
                document.getElementById('st-os-row').style.display = '';
                document.getElementById('st-os').textContent = ev.os_guess;
            }
            document.getElementById('st-duration').textContent = ev.duration + 's';
            setProgress(100, 100, '100%', 'Complete');
            scanFinished();
            break;
    }
}

function addResultRow(port) {
    const tbody = document.getElementById('ps-results-body');
    const tr = document.createElement('tr');
    const banner = port.banner
        ? `<span style="font-family:monospace;font-size:0.75rem;color:var(--text-secondary)">${esc(port.banner.substring(0, 120))}</span>`
        : '<span style="color:var(--text-muted)">—</span>';
    tr.innerHTML = `
        <td><strong style="color:var(--success)">${port.port}</strong></td>
        <td style="color:var(--text-muted)">${port.protocol}</td>
        <td>${esc(port.service || '—')}</td>
        <td>${banner}</td>`;
    tbody.appendChild(tr);
}

function cancelScan() {
    if (!_jobId) return;
    fetch('/port-scanner/cancel/' + _jobId, { method: 'POST' });
    appendLine('warn', '⚠ Scan cancelled by user');
    scanFinished();
}

function scanFinished() {
    if (_es) { _es.close(); _es = null; }
    document.getElementById('ps-start-btn').disabled = false;
    document.getElementById('ps-cancel-btn').style.display = 'none';
    setStatus('idle', _openPorts.length + ' open ports');
    _jobId = null;
}

function setStatus(state, text) {
    const dot = document.getElementById('ps-status-dot');
    const txt = document.getElementById('ps-status-txt');
    txt.textContent = text;
    dot.style.background = state === 'scanning' ? 'var(--success)'
                         : state === 'error' ? 'var(--danger)'
                         : 'var(--text-muted)';
    if (state === 'scanning') {
        dot.style.animation = 'ps-pulse 1.2s ease infinite';
    } else {
        dot.style.animation = '';
    }
}

function setProgress(current, total, pct, label) {
    document.getElementById('ps-progress-bar').style.width = (typeof pct === 'string' ? pct : pct + '%');
    document.getElementById('ps-progress-pct').textContent = (typeof pct === 'string' ? pct : pct + '%');
    document.getElementById('ps-progress-label').textContent = label;
}

function appendLine(cls, text) {
    const out = document.getElementById('ps-output');
    const el = document.createElement('span');
    el.className = 'ln-' + cls;
    el.textContent = text + '\n';
    out.appendChild(el);
    out.scrollTop = out.scrollHeight;
}

function clearOutput() {
    document.getElementById('ps-output').innerHTML = '';
}

function exportResults(fmt) {
    if (!_openPorts.length) { alert('No results to export'); return; }
    let content, mime, ext;
    if (fmt === 'json') {
        content = JSON.stringify({ target: document.getElementById('ps-target').value,
                                   scan_time: new Date().toISOString(),
                                   open_ports: _openPorts }, null, 2);
        mime = 'application/json'; ext = 'json';
    } else {
        const target = document.getElementById('ps-target').value;
        const lines = [`# AUTARCH Port Scan Results`, `# Target: ${target}`,
                       `# Date: ${new Date().toISOString()}`, `# Open Ports: ${_openPorts.length}`, ''];
        _openPorts.forEach(p => {
            lines.push(`${p.port}/tcp\topen\t${p.service || 'unknown'}\t${p.banner || ''}`);
        });
        content = lines.join('\n'); mime = 'text/plain'; ext = 'txt';
    }
    const a = document.createElement('a');
    a.href = URL.createObjectURL(new Blob([content], { type: mime }));
    a.download = `scan_${document.getElementById('ps-target').value}_${Date.now()}.${ext}`;
    a.click();
}

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

<style>
@keyframes ps-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
}
</style>

{% endblock %}


Instruction: Create an AUTARCH web template for the 'Rcs Tools' page. It should extend base.html, have a page header, and use AUTARCH's CSS variables and UI patterns (sections, tab bars, data tables, buttons).

Input:
Template: rcs_tools.html
Sections: 29
Tabs: 6
Forms/API calls: 3
Has JavaScript: True

Output:
{% extends "base.html" %}
{% block title %}AUTARCH — RCS/SMS Exploit{% endblock %}

{% block content %}
<div class="page-header">
    <h1>RCS/SMS Exploitation</h1>
    <p style="margin:0;font-size:0.85rem;color:var(--text-secondary)">
        Extract, forge, modify, backup, and exploit SMS/RCS messages on connected Android devices.
        Uses content providers (no root), Archon relay, CVE-2024-0044, and bugle_db direct access.
    </p>
</div>

<!-- Device Status Banner -->
<div id="rcs-device-banner" class="section" style="padding:10px 16px;margin-bottom:16px;display:flex;align-items:center;gap:12px;flex-wrap:wrap">
    <span id="rcs-dev-indicator" style="width:10px;height:10px;border-radius:50%;background:#555;display:inline-block"></span>
    <span id="rcs-dev-label" style="font-size:0.85rem;color:var(--text-secondary)">Checking device...</span>
    <span id="rcs-shizuku-badge" style="font-size:0.75rem;padding:2px 8px;border-radius:4px;background:#333;color:#888">Shizuku: --</span>
    <span id="rcs-archon-badge" style="font-size:0.75rem;padding:2px 8px;border-radius:4px;background:#333;color:#888">Archon: --</span>
    <span id="rcs-cve-badge" style="font-size:0.75rem;padding:2px 8px;border-radius:4px;background:#333;color:#888">CVE: --</span>
    <span id="rcs-sms-app" style="font-size:0.75rem;color:var(--text-muted)">SMS App: --</span>
    <button class="btn btn-small" onclick="rcsRefreshStatus()" style="margin-left:auto">Refresh</button>
</div>

<!-- Tab Bar -->
<div class="tab-bar">
    <button class="tab active" data-tab-group="rcs" data-tab="extract" onclick="showTab('rcs','extract')">Extract</button>
    <button class="tab" data-tab-group="rcs" data-tab="database" onclick="showTab('rcs','database')">Database</button>
    <button class="tab" data-tab-group="rcs" data-tab="forge" onclick="showTab('rcs','forge')">Forge</button>
    <button class="tab" data-tab-group="rcs" data-tab="modify" onclick="showTab('rcs','modify')">Modify</button>
    <button class="tab" data-tab-group="rcs" data-tab="exploit" onclick="showTab('rcs','exploit')">Exploit</button>
    <button class="tab" data-tab-group="rcs" data-tab="backup" onclick="showTab('rcs','backup')">Backup</button>
    <button class="tab" data-tab-group="rcs" data-tab="monitor" onclick="showTab('rcs','monitor')">Monitor</button>
</div>

<!-- ========================== EXTRACT TAB ========================== -->
<div class="tab-content active" data-tab-group="rcs" data-tab="extract">

<div class="section">
    <h3>SMS Messages</h3>
    <div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px">
        <input id="rcs-search-addr" type="text" placeholder="Filter by address" style="flex:1;min-width:150px">
        <input id="rcs-search-kw" type="text" placeholder="Search keyword" style="flex:1;min-width:150px">
        <input id="rcs-search-thread" type="text" placeholder="Thread ID" style="width:90px">
        <select id="rcs-msg-filter" style="width:120px">
            <option value="all">All</option>
            <option value="inbox">Inbox</option>
            <option value="sent">Sent</option>
            <option value="drafts">Drafts</option>
            <option value="undelivered">Undelivered</option>
        </select>
        <button class="btn" onclick="rcsExtractMessages()">Extract</button>
        <button class="btn btn-secondary" onclick="rcsExportMessages('json')">Export JSON</button>
        <button class="btn btn-secondary" onclick="rcsExportMessages('csv')">Export CSV</button>
        <button class="btn btn-secondary" onclick="rcsExportMessages('xml')">Export XML</button>
    </div>
    <div id="rcs-msg-count" style="font-size:0.8rem;color:var(--text-muted);margin-bottom:8px"></div>
    <div id="rcs-messages-list" style="max-height:500px;overflow-y:auto"></div>
</div>

<div class="section">
    <h3>MMS Messages</h3>
    <button class="btn" onclick="rcsExtractMMS()">Extract MMS</button>
    <div id="rcs-mms-list" style="max-height:300px;overflow-y:auto;margin-top:8px"></div>
</div>

<div class="section">
    <h3>RCS Provider (AOSP content://rcs/)</h3>
    <div style="display:flex;gap:8px;margin-bottom:8px">
        <button class="btn" onclick="rcsExtractRCSProvider()">Query RCS Provider</button>
        <button class="btn btn-secondary" onclick="rcsExtractRCSMessages()">RCS Messages</button>
        <button class="btn btn-secondary" onclick="rcsExtractRCSParticipants()">RCS Participants</button>
    </div>
    <div id="rcs-provider-result" style="max-height:400px;overflow-y:auto"></div>
</div>

<div class="section">
    <h3>Content Provider Enumeration</h3>
    <p style="font-size:0.8rem;color:var(--text-muted)">Scan all known messaging content providers to see which are accessible at UID 2000.</p>
    <button class="btn" onclick="rcsEnumerateProviders()">Enumerate All Providers</button>
    <div id="rcs-providers-result" style="margin-top:8px"></div>
</div>

</div>

<!-- ========================== DATABASE TAB ========================== -->
<div class="tab-content" data-tab-group="rcs" data-tab="database">

<div class="section">
    <h3>bugle_db Extraction</h3>
    <p style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:12px">
        Extract the Google Messages RCS database. The database is <strong>encrypted at rest</strong> &mdash;
        raw file extraction also requires the encryption key. Best method: Archon relay (queries from
        decrypted app context). Fallback: CVE-2024-0044 (app-UID access) &rarr; root (DB + keys) &rarr; ADB backup.
    </p>
    <div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px">
        <button class="btn btn-danger" onclick="rcsExtractBugle()">Extract bugle_db</button>
        <button class="btn" onclick="rcsExtractRCSFromBugle()">Extract RCS Only</button>
        <button class="btn" onclick="rcsExtractConvosFromBugle()">Extract Conversations</button>
        <button class="btn" onclick="rcsExtractEdits()">Extract Message Edits</button>
        <button class="btn btn-secondary" onclick="rcsExtractAllBugle()">Full Export (all tables)</button>
    </div>
    <div id="rcs-bugle-result" style="max-height:400px;overflow-y:auto"></div>
</div>

<div class="section">
    <h3>SQL Query (extracted bugle_db)</h3>
    <p style="font-size:0.8rem;color:var(--text-muted)">Run arbitrary SQL against a previously extracted bugle_db.</p>
    <textarea id="rcs-sql-query" rows="4" style="width:100%;font-family:monospace;font-size:0.85rem"
        placeholder="SELECT m.*, p.text FROM messages m JOIN parts p ON m._id=p.message_id WHERE m.message_protocol>=2 ORDER BY m.sent_timestamp DESC LIMIT 50"></textarea>
    <div style="display:flex;gap:8px;margin-top:8px">
        <button class="btn" onclick="rcsQueryBugle()">Run Query</button>
        <select id="rcs-sql-preset" onchange="rcsSQLPreset(this.value)" style="font-size:0.85rem">
            <option value="">-- Preset Queries --</option>
            <option value="rcs">RCS Messages Only</option>
            <option value="all_msgs">All Messages with Contacts</option>
            <option value="edits">Message Edit History</option>
            <option value="conversations">Conversations with Participants</option>
            <option value="attachments">Attachments</option>
            <option value="stats">Message Statistics</option>
        </select>
    </div>
    <div id="rcs-sql-result" style="max-height:400px;overflow-y:auto;margin-top:8px"></div>
</div>

<div class="section">
    <h3>Extracted Database Snapshots</h3>
    <button class="btn btn-secondary" onclick="rcsListExtracted()">List Snapshots</button>
    <div id="rcs-extracted-list" style="margin-top:8px"></div>
</div>

</div>

<!-- ========================== FORGE TAB ========================== -->
<div class="tab-content" data-tab-group="rcs" data-tab="forge">

<div class="section">
    <h3>Forge SMS Message</h3>
    <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:8px">
        <input id="forge-address" type="text" placeholder="Phone number (+1234567890)">
        <input id="forge-contact" type="text" placeholder="Contact name (optional)">
    </div>
    <textarea id="forge-body" rows="3" style="width:100%" placeholder="Message body"></textarea>
    <div style="display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center">
        <select id="forge-type">
            <option value="1">Incoming (Inbox)</option>
            <option value="2">Outgoing (Sent)</option>
            <option value="3">Draft</option>
        </select>
        <input id="forge-timestamp" type="datetime-local" style="width:200px">
        <label style="font-size:0.85rem"><input type="checkbox" id="forge-read" checked> Mark as read</label>
        <button class="btn" onclick="rcsForgeSMS()">Forge SMS</button>
    </div>
</div>

<div class="section">
    <h3>Forge RCS Message (via Archon)</h3>
    <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:8px">
        <input id="forge-rcs-address" type="text" placeholder="Phone number">
        <select id="forge-rcs-direction">
            <option value="incoming">Incoming</option>
            <option value="outgoing">Outgoing</option>
        </select>
    </div>
    <textarea id="forge-rcs-body" rows="3" style="width:100%" placeholder="RCS message body"></textarea>
    <button class="btn" onclick="rcsForgeRCS()" style="margin-top:8px">Forge RCS</button>
</div>

<div class="section">
    <h3>Forge Conversation</h3>
    <input id="forge-conv-address" type="text" placeholder="Phone number" style="width:100%;margin-bottom:8px">
    <textarea id="forge-conv-msgs" rows="6" style="width:100%;font-family:monospace;font-size:0.85rem"
        placeholder='[{"body":"Hey!","type":1},{"body":"Hi there","type":2},{"body":"How are you?","type":1}]'></textarea>
    <button class="btn" onclick="rcsForgeConversation()" style="margin-top:8px">Forge Conversation</button>
</div>

<div class="section">
    <h3>Import SMS Backup XML</h3>
    <p style="font-size:0.8rem;color:var(--text-muted)">Import from SMS Backup & Restore XML format.</p>
    <textarea id="forge-import-xml" rows="4" style="width:100%;font-family:monospace;font-size:0.85rem"
        placeholder='Paste XML content here or load from file'></textarea>
    <div style="display:flex;gap:8px;margin-top:8px">
        <button class="btn" onclick="rcsImportXML()">Import XML</button>
        <input type="file" id="forge-xml-file" accept=".xml" onchange="rcsLoadXMLFile(this)" style="font-size:0.85rem">
    </div>
    <div id="forge-import-result" style="margin-top:8px"></div>
</div>

<div class="section">
    <h3>Forge Log</h3>
    <div style="display:flex;gap:8px;margin-bottom:8px">
        <button class="btn btn-secondary" onclick="rcsRefreshForgeLog()">Refresh</button>
        <button class="btn btn-secondary" onclick="rcsClearForgeLog()">Clear Log</button>
    </div>
    <div id="forge-log-list" style="max-height:300px;overflow-y:auto"></div>
</div>

</div>

<!-- ========================== MODIFY TAB ========================== -->
<div class="tab-content" data-tab-group="rcs" data-tab="modify">

<div class="section">
    <h3>Modify Message</h3>
    <div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-bottom:8px">
        <input id="mod-msg-id" type="number" placeholder="Message ID">
        <select id="mod-type">
            <option value="">-- Change type --</option>
            <option value="1">Incoming</option>
            <option value="2">Outgoing</option>
            <option value="3">Draft</option>
        </select>
        <input id="mod-timestamp" type="datetime-local">
    </div>
    <textarea id="mod-body" rows="2" style="width:100%" placeholder="New body (leave empty to keep)"></textarea>
    <button class="btn" onclick="rcsModifyMessage()" style="margin-top:8px">Modify</button>
</div>

<div class="section">
    <h3>Change Sender</h3>
    <div style="display:flex;gap:8px;align-items:center">
        <input id="mod-sender-id" type="number" placeholder="Message ID" style="width:120px">
        <input id="mod-new-address" type="text" placeholder="New sender address" style="flex:1">
        <button class="btn" onclick="rcsChangeSender()">Change</button>
    </div>
</div>

<div class="section">
    <h3>Shift Timestamps</h3>
    <div style="display:flex;gap:8px;align-items:center">
        <input id="mod-shift-addr" type="text" placeholder="Address" style="flex:1">
        <input id="mod-shift-mins" type="number" placeholder="Offset (minutes)" style="width:140px">
        <button class="btn" onclick="rcsShiftTimestamps()">Shift</button>
    </div>
</div>

<div class="section">
    <h3>Bulk Actions</h3>
    <div style="display:flex;gap:8px;flex-wrap:wrap">
        <input id="mod-thread-id" type="number" placeholder="Thread ID" style="width:120px">
        <button class="btn" onclick="rcsMarkAllRead()">Mark All Read</button>
        <button class="btn btn-danger" onclick="rcsWipeThread()">Wipe Thread</button>
        <button class="btn btn-danger" onclick="rcsDeleteConversation()">Delete Conversation</button>
    </div>
</div>

<div class="section">
    <h3>Delete Single Message</h3>
    <div style="display:flex;gap:8px;align-items:center">
        <input id="mod-del-id" type="number" placeholder="Message ID" style="width:150px">
        <button class="btn btn-danger" onclick="rcsDeleteMessage()">Delete</button>
    </div>
</div>

</div>

<!-- ========================== EXPLOIT TAB ========================== -->
<div class="tab-content" data-tab-group="rcs" data-tab="exploit">

<div class="section">
    <h3>CVE-2024-0044 — run-as Privilege Escalation</h3>
    <p style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:8px">
        Newline injection in PackageInstallerService allows run-as access to any app's private data.
        Works on Android 12-13 with security patch before October 2024.
    </p>
    <div id="rcs-cve-status" style="margin-bottom:8px;padding:8px;border-radius:4px;background:var(--bg-secondary)"></div>
    <div style="display:flex;gap:8px;flex-wrap:wrap">
        <button class="btn" onclick="rcsCVECheck()">Check Vulnerability</button>
        <button class="btn btn-danger" onclick="rcsCVEExploit()">Execute Exploit</button>
        <button class="btn btn-secondary" onclick="rcsCVECleanup()">Cleanup Traces</button>
    </div>
    <div id="rcs-cve-result" style="margin-top:8px"></div>
</div>

<div class="section">
    <h3>RCS Spoofing</h3>
    <div style="display:grid;grid-template-columns:1fr auto;gap:8px;margin-bottom:8px">
        <input id="exploit-spoof-addr" type="text" placeholder="Target phone number">
        <button class="btn" onclick="rcsSpoofTyping()">Spoof Typing</button>
    </div>
    <div style="display:grid;grid-template-columns:1fr auto;gap:8px">
        <input id="exploit-spoof-msgid" type="text" placeholder="Message ID for read receipt">
        <button class="btn" onclick="rcsSpoofReadReceipt()">Spoof Read Receipt</button>
    </div>
</div>

<div class="section">
    <h3>RCS Identity & Signal Protocol</h3>
    <div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:8px">
        <button class="btn" onclick="rcsCloneIdentity()">Clone RCS Identity</button>
        <button class="btn" onclick="rcsExtractSignalState()">Extract Signal Protocol State</button>
        <button class="btn btn-secondary" onclick="rcsInterceptArchival()">Register Archival Listener</button>
    </div>
    <div id="rcs-identity-result" style="max-height:300px;overflow-y:auto"></div>
</div>

<div class="section">
    <h3>Known RCS CVEs</h3>
    <button class="btn btn-secondary" onclick="rcsShowCVEs()">Show CVE Database</button>
    <div id="rcs-cves-list" style="margin-top:8px"></div>
</div>

<div class="section">
    <h3>IMS/RCS Diagnostics</h3>
    <div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:8px">
        <button class="btn" onclick="rcsGetIMSStatus()">IMS Status</button>
        <button class="btn" onclick="rcsGetCarrierConfig()">Carrier RCS Config</button>
        <button class="btn" onclick="rcsGetRCSState()">RCS State</button>
        <button class="btn btn-secondary" onclick="rcsEnableLogging()">Enable Verbose Logging</button>
        <button class="btn btn-secondary" onclick="rcsCaptureLogs()">Capture RCS Logs</button>
        <button class="btn btn-secondary" onclick="rcsPixelDiag()">Pixel Diagnostics</button>
    </div>
    <div id="rcs-diag-result" style="max-height:400px;overflow-y:auto;font-family:monospace;font-size:0.8rem;white-space:pre-wrap"></div>
</div>

</div>

<!-- ========================== BACKUP TAB ========================== -->
<div class="tab-content" data-tab-group="rcs" data-tab="backup">

<div class="section">
    <h3>Full Backup</h3>
    <p style="font-size:0.85rem;color:var(--text-secondary)">
        Back up all SMS/MMS/RCS messages from the device. Content providers capture SMS/MMS;
        Archon relay or bugle_db extraction captures RCS.
    </p>
    <div style="display:flex;gap:8px;margin-top:8px">
        <button class="btn" onclick="rcsFullBackup('json')">Backup (JSON)</button>
        <button class="btn" onclick="rcsFullBackup('xml')">Backup (XML — SMS Backup & Restore format)</button>
        <button class="btn btn-secondary" onclick="rcsArchonBackup()">Archon Full Backup (incl. RCS)</button>
    </div>
    <div id="rcs-backup-result" style="margin-top:8px"></div>
</div>

<div class="section">
    <h3>Restore / Clone</h3>
    <div style="display:flex;gap:8px;align-items:center;margin-bottom:8px">
        <input id="backup-restore-path" type="text" placeholder="Backup filename or full path" style="flex:1">
        <button class="btn" onclick="rcsRestore()">Restore</button>
    </div>
    <button class="btn btn-secondary" onclick="rcsCloneDevice()">Clone to Another Device</button>
    <div id="rcs-restore-result" style="margin-top:8px"></div>
</div>

<div class="section">
    <h3>Set Default SMS App</h3>
    <div style="display:flex;gap:8px;align-items:center">
        <select id="backup-sms-app" style="flex:1">
            <option value="com.darkhal.archon">Archon (enables full RCS access)</option>
            <option value="com.google.android.apps.messaging">Google Messages</option>
            <option value="com.android.messaging">AOSP Messages</option>
            <option value="com.samsung.android.messaging">Samsung Messages</option>
        </select>
        <button class="btn" onclick="rcsSetDefaultApp()">Set Default</button>
    </div>
</div>

<div class="section">
    <h3>Saved Backups</h3>
    <button class="btn btn-secondary" onclick="rcsListBackups()">Refresh</button>
    <div id="rcs-backups-list" style="margin-top:8px"></div>
</div>

<div class="section">
    <h3>Exported Files</h3>
    <button class="btn btn-secondary" onclick="rcsListExports()">Refresh</button>
    <div id="rcs-exports-list" style="margin-top:8px"></div>
</div>

</div>

<!-- ========================== MONITOR TAB ========================== -->
<div class="tab-content" data-tab-group="rcs" data-tab="monitor">

<div class="section">
    <h3>SMS/RCS Monitor</h3>
    <p style="font-size:0.85rem;color:var(--text-secondary)">
        Monitor incoming SMS/RCS messages in real-time via logcat interception.
    </p>
    <div style="display:flex;gap:8px;margin-bottom:8px">
        <button class="btn" id="rcs-monitor-btn" onclick="rcsToggleMonitor()">Start Monitor</button>
        <button class="btn btn-secondary" onclick="rcsRefreshMonitor()">Refresh</button>
        <button class="btn btn-secondary" onclick="rcsClearMonitor()">Clear</button>
        <span id="rcs-monitor-count" style="font-size:0.85rem;color:var(--text-muted);align-self:center"></span>
    </div>
    <div id="rcs-monitor-feed" style="max-height:500px;overflow-y:auto;font-family:monospace;font-size:0.8rem"></div>
</div>

</div>

<!-- ========================== INLINE JS ========================== -->
<script>
const RCS_BASE = '/rcs-tools';
let rcsMonitorRunning = false;
let rcsMonitorInterval = null;

// ── Helpers ─────────────────────────────────────────────────────────
function rcsPost(path, data) {
    return postJSON(RCS_BASE + path, data || {});
}
function rcsGet(path) {
    return fetchJSON(RCS_BASE + path);
}

function renderTable(rows, columns) {
    if (!rows || !rows.length) return '<p style="color:var(--text-muted)">No data</p>';
    let cols = columns || Object.keys(rows[0]);
    let h = '<table class="data-table" style="width:100%;font-size:0.8rem"><thead><tr>';
    cols.forEach(c => h += '<th>' + esc(c) + '</th>');
    h += '</tr></thead><tbody>';
    rows.forEach(r => {
        h += '<tr>';
        cols.forEach(c => {
            let v = r[c];
            if (v === null || v === undefined) v = '';
            let s = String(v);
            if (s.length > 120) s = s.substring(0, 120) + '...';
            h += '<td>' + esc(s) + '</td>';
        });
        h += '</tr>';
    });
    h += '</tbody></table>';
    return h;
}

function renderJSON(obj) {
    return '<pre style="max-height:300px;overflow:auto;font-size:0.8rem;padding:8px;background:var(--bg-secondary);border-radius:4px">'
        + esc(JSON.stringify(obj, null, 2)) + '</pre>';
}

function renderMsgRow(m) {
    let dir = parseInt(m.type) === 2 ? 'outgoing' : 'incoming';
    let color = dir === 'outgoing' ? '#2196f3' : '#4caf50';
    let arrow = dir === 'outgoing' ? '&#x2192;' : '&#x2190;';
    return '<div style="padding:6px 10px;border-bottom:1px solid var(--border);display:flex;gap:8px;align-items:flex-start">'
        + '<span style="color:' + color + ';font-weight:bold;min-width:20px">' + arrow + '</span>'
        + '<div style="flex:1;min-width:0">'
        + '<div style="font-size:0.8rem;color:var(--text-muted)">'
        + '<strong>' + esc(m.address || '') + '</strong>'
        + ' &middot; ID:' + esc(m._id || '')
        + ' &middot; Thread:' + esc(m.thread_id || '')
        + (m.date_formatted ? ' &middot; ' + esc(m.date_formatted) : '')
        + '</div>'
        + '<div style="font-size:0.85rem;margin-top:2px;word-break:break-word">' + esc(m.body || '') + '</div>'
        + '</div></div>';
}

// ── Status ──────────────────────────────────────────────────────────
async function rcsRefreshStatus() {
    try {
        const r = await rcsGet('/status');
        const ind = document.getElementById('rcs-dev-indicator');
        const lbl = document.getElementById('rcs-dev-label');
        const shBadge = document.getElementById('rcs-shizuku-badge');
        const arBadge = document.getElementById('rcs-archon-badge');
        const cvBadge = document.getElementById('rcs-cve-badge');
        const smsApp = document.getElementById('rcs-sms-app');
        if (r.connected) {
            const d = r.device || {};
            ind.style.background = '#4caf50';
            lbl.textContent = (d.model || 'Device') + ' (' + (d.serial || '?') + ') — Android ' + (d.android_version || '?');
            smsApp.textContent = 'SMS App: ' + (d.default_sms_app || '?');
        } else {
            ind.style.background = '#f44336';
            lbl.textContent = r.error || 'Not connected';
        }
        // Shizuku
        const sh = r.shizuku || {};
        if (sh.running) { shBadge.textContent = 'Shizuku: Running'; shBadge.style.background = '#1b5e20'; shBadge.style.color = '#4caf50'; }
        else if (sh.installed) { shBadge.textContent = 'Shizuku: Installed'; shBadge.style.background = '#33691e'; shBadge.style.color = '#8bc34a'; }
        else { shBadge.textContent = 'Shizuku: N/A'; shBadge.style.background = '#333'; shBadge.style.color = '#888'; }
        // Archon
        const ar = r.archon || {};
        if (ar.installed) { arBadge.textContent = 'Archon: ' + (ar.version || 'OK'); arBadge.style.background = '#0d47a1'; arBadge.style.color = '#42a5f5'; }
        else { arBadge.textContent = 'Archon: N/A'; arBadge.style.background = '#333'; arBadge.style.color = '#888'; }
        // CVE
        const cv = r.cve_2024_0044 || {};
        if (cv.vulnerable) { cvBadge.textContent = 'CVE-0044: VULN'; cvBadge.style.background = '#b71c1c'; cvBadge.style.color = '#ef5350'; }
        else { cvBadge.textContent = 'CVE-0044: Patched'; cvBadge.style.background = '#1b5e20'; cvBadge.style.color = '#4caf50'; }
    } catch(e) {
        document.getElementById('rcs-dev-label').textContent = 'Error: ' + e.message;
    }
}

// ── Extract ─────────────────────────────────────────────────────────
async function rcsExtractMessages() {
    const addr = document.getElementById('rcs-search-addr').value;
    const kw = document.getElementById('rcs-search-kw').value;
    const tid = document.getElementById('rcs-search-thread').value;
    const filter = document.getElementById('rcs-msg-filter').value;
    let url = '/messages?limit=200';
    if (tid) url += '&thread_id=' + tid;
    else if (addr) url += '&address=' + encodeURIComponent(addr);
    else if (kw) url += '&keyword=' + encodeURIComponent(kw);

    if (filter === 'inbox') url = '/sms-inbox';
    else if (filter === 'sent') url = '/sms-sent';
    else if (filter === 'drafts') url = '/drafts';
    else if (filter === 'undelivered') url = '/undelivered';

    const r = await rcsGet(url);
    const list = document.getElementById('rcs-messages-list');
    const count = document.getElementById('rcs-msg-count');
    const msgs = r.messages || [];
    count.textContent = msgs.length + ' messages';
    list.innerHTML = msgs.map(renderMsgRow).join('');
}

async function rcsExtractMMS() {
    const r = await rcsGet('/mms');
    const list = document.getElementById('rcs-mms-list');
    const msgs = r.messages || [];
    list.innerHTML = msgs.length ? renderTable(msgs, ['_id','thread_id','date_formatted','msg_box','body','sub']) : '<p style="color:var(--text-muted)">No MMS messages</p>';
}

async function rcsExtractRCSProvider() {
    const r = await rcsGet('/rcs-provider');
    document.getElementById('rcs-provider-result').innerHTML = renderJSON(r);
}

async function rcsExtractRCSMessages() {
    const r = await rcsGet('/rcs-messages');
    document.getElementById('rcs-provider-result').innerHTML = renderJSON(r);
}

async function rcsExtractRCSParticipants() {
    const r = await rcsGet('/rcs-participants');
    document.getElementById('rcs-provider-result').innerHTML = renderJSON(r);
}

async function rcsEnumerateProviders() {
    const r = await rcsPost('/enumerate-providers');
    let h = '';
    if (r.accessible && r.accessible.length) {
        h += '<h4 style="color:#4caf50">Accessible (' + r.total_accessible + ')</h4>';
        h += renderTable(r.accessible, ['uri','status','rows','name']);
    }
    if (r.blocked && r.blocked.length) {
        h += '<h4 style="color:#f44336">Blocked (' + r.total_blocked + ')</h4>';
        h += renderTable(r.blocked, ['uri','error']);
    }
    document.getElementById('rcs-providers-result').innerHTML = h;
}

async function rcsExportMessages(fmt) {
    const addr = document.getElementById('rcs-search-addr').value;
    const r = await rcsPost('/export', {address: addr || null, format: fmt});
    if (r.ok) alert('Exported ' + r.count + ' messages to ' + r.path);
    else alert('Export failed: ' + (r.error || 'unknown'));
}

// ── Database ────────────────────────────────────────────────────────
async function rcsExtractBugle() {
    document.getElementById('rcs-bugle-result').innerHTML = '<p>Extracting bugle_db...</p>';
    const r = await rcsPost('/extract-bugle');
    document.getElementById('rcs-bugle-result').innerHTML = renderJSON(r);
}

async function rcsExtractRCSFromBugle() {
    const r = await rcsPost('/extract-rcs-bugle');
    document.getElementById('rcs-bugle-result').innerHTML = renderJSON(r);
}

async function rcsExtractConvosFromBugle() {
    const r = await rcsPost('/extract-conversations-bugle');
    document.getElementById('rcs-bugle-result').innerHTML = r.ok && r.rows
        ? renderTable(r.rows) : renderJSON(r);
}

async function rcsExtractEdits() {
    const r = await rcsPost('/extract-edits');
    document.getElementById('rcs-bugle-result').innerHTML = renderJSON(r);
}

async function rcsExtractAllBugle() {
    document.getElementById('rcs-bugle-result').innerHTML = '<p>Exporting all tables...</p>';
    const r = await rcsPost('/extract-all-bugle');
    document.getElementById('rcs-bugle-result').innerHTML = renderJSON(r);
}

async function rcsQueryBugle() {
    const sql = document.getElementById('rcs-sql-query').value;
    if (!sql) return;
    const r = await rcsPost('/query-bugle', {sql});
    const el = document.getElementById('rcs-sql-result');
    if (r.ok && r.rows && r.rows.length) {
        el.innerHTML = '<p style="color:var(--text-muted)">' + r.count + ' rows</p>' + renderTable(r.rows);
    } else {
        el.innerHTML = renderJSON(r);
    }
}

function rcsSQLPreset(val) {
    const presets = {
        rcs: "SELECT m.*, p.text, p.content_type FROM messages m LEFT JOIN parts p ON m._id=p.message_id WHERE m.message_protocol>=2 ORDER BY m.sent_timestamp DESC LIMIT 100",
        all_msgs: "SELECT m._id, m.conversation_id, m.message_protocol, m.sent_timestamp, p.text, ppl.normalized_destination, ppl.full_name, CASE WHEN ppl.sub_id=-2 THEN 'IN' ELSE 'OUT' END AS dir FROM messages m LEFT JOIN parts p ON m._id=p.message_id LEFT JOIN conversation_participants cp ON m.conversation_id=cp.conversation_id LEFT JOIN participants ppl ON cp.participant_id=ppl._id ORDER BY m.sent_timestamp DESC LIMIT 100",
        edits: "SELECT me.*, p.text AS current_text FROM message_edits me LEFT JOIN messages m ON me.latest_message_id=m._id LEFT JOIN parts p ON m._id=p.message_id ORDER BY me.edited_at_timestamp_ms DESC",
        conversations: "SELECT c._id, c.name, c.snippet_text, c.sort_timestamp, c.participant_count, GROUP_CONCAT(ppl.normalized_destination,'; ') AS numbers FROM conversations c LEFT JOIN conversation_participants cp ON c._id=cp.conversation_id LEFT JOIN participants ppl ON cp.participant_id=ppl._id GROUP BY c._id ORDER BY c.sort_timestamp DESC",
        attachments: "SELECT p._id, p.message_id, p.content_type, p.uri, p.text, m.message_protocol FROM parts p JOIN messages m ON p.message_id=m._id WHERE p.content_type!='text/plain' AND p.uri IS NOT NULL ORDER BY p._id DESC LIMIT 50",
        stats: "SELECT message_protocol, COUNT(*) as count, MIN(sent_timestamp) as earliest, MAX(sent_timestamp) as latest FROM messages GROUP BY message_protocol",
    };
    if (presets[val]) document.getElementById('rcs-sql-query').value = presets[val];
}

async function rcsListExtracted() {
    const r = await rcsGet('/extracted-dbs');
    const el = document.getElementById('rcs-extracted-list');
    if (r.extractions && r.extractions.length) {
        el.innerHTML = renderTable(r.extractions, ['name','files','total_size']);
    } else {
        el.innerHTML = '<p style="color:var(--text-muted)">No extracted databases yet</p>';
    }
}

// ── Forge ────────────────────────────────────────────────────────────
async function rcsForgeSMS() {
    const tsInput = document.getElementById('forge-timestamp').value;
    let ts = null;
    if (tsInput) ts = new Date(tsInput).getTime();
    const r = await rcsPost('/forge', {
        address: document.getElementById('forge-address').value,
        body: document.getElementById('forge-body').value,
        type: document.getElementById('forge-type').value,
        timestamp: ts,
        contact_name: document.getElementById('forge-contact').value || null,
        read: document.getElementById('forge-read').checked ? 1 : 0,
    });
    alert(r.ok ? 'SMS forged!' : 'Failed: ' + (r.error || ''));
}

async function rcsForgeRCS() {
    const r = await rcsPost('/archon/forge-rcs', {
        address: document.getElementById('forge-rcs-address').value,
        body: document.getElementById('forge-rcs-body').value,
        direction: document.getElementById('forge-rcs-direction').value,
    });
    alert(r.ok ? 'RCS message forged via Archon!' : 'Failed: ' + (r.error || r.result || ''));
}

async function rcsForgeConversation() {
    let msgs;
    try { msgs = JSON.parse(document.getElementById('forge-conv-msgs').value); }
    catch(e) { alert('Invalid JSON'); return; }
    const r = await rcsPost('/forge-conversation', {
        address: document.getElementById('forge-conv-address').value,
        messages: msgs,
    });
    alert(r.ok ? r.message : 'Failed: ' + (r.error || ''));
}

async function rcsImportXML() {
    const xml = document.getElementById('forge-import-xml').value;
    if (!xml) { alert('Paste XML first'); return; }
    const r = await rcsPost('/import-xml', {xml});
    document.getElementById('forge-import-result').innerHTML = renderJSON(r);
}

function rcsLoadXMLFile(input) {
    if (!input.files.length) return;
    const reader = new FileReader();
    reader.onload = e => document.getElementById('forge-import-xml').value = e.target.result;
    reader.readAsText(input.files[0]);
}

async function rcsRefreshForgeLog() {
    const r = await rcsGet('/forged-log');
    const list = document.getElementById('forge-log-list');
    const log = r.log || [];
    if (log.length) {
        list.innerHTML = renderTable(log, ['time','action','address','body']);
    } else {
        list.innerHTML = '<p style="color:var(--text-muted)">No forged messages yet</p>';
    }
}

async function rcsClearForgeLog() {
    await rcsPost('/forged-log/clear');
    rcsRefreshForgeLog();
}

// ── Modify ──────────────────────────────────────────────────────────
async function rcsModifyMessage() {
    const id = parseInt(document.getElementById('mod-msg-id').value);
    if (!id) { alert('Enter message ID'); return; }
    const tsInput = document.getElementById('mod-timestamp').value;
    const data = {};
    const body = document.getElementById('mod-body').value;
    if (body) data.body = body;
    const type = document.getElementById('mod-type').value;
    if (type) data.type = type;
    if (tsInput) data.timestamp = new Date(tsInput).getTime();
    const r = await fetch(RCS_BASE + '/message/' + id, {
        method: 'PUT', headers: {'Content-Type':'application/json'}, body: JSON.stringify(data)
    }).then(r => r.json());
    alert(r.ok ? 'Modified!' : 'Failed: ' + (r.error || ''));
}

async function rcsChangeSender() {
    const r = await rcsPost('/change-sender', {
        msg_id: document.getElementById('mod-sender-id').value,
        new_address: document.getElementById('mod-new-address').value,
    });
    alert(r.ok ? 'Sender changed!' : 'Failed: ' + (r.error || ''));
}

async function rcsShiftTimestamps() {
    const r = await rcsPost('/shift-timestamps', {
        address: document.getElementById('mod-shift-addr').value,
        offset_minutes: parseInt(document.getElementById('mod-shift-mins').value) || 0,
    });
    alert(r.ok ? 'Modified ' + r.modified + ' messages' : 'Failed: ' + (r.error || ''));
}

async function rcsMarkAllRead() {
    const tid = document.getElementById('mod-thread-id').value;
    const r = await rcsPost('/mark-read', {thread_id: tid || null});
    alert(r.ok ? r.message : 'Failed: ' + (r.error || ''));
}

async function rcsWipeThread() {
    const tid = parseInt(document.getElementById('mod-thread-id').value);
    if (!tid) { alert('Enter thread ID'); return; }
    if (!confirm('Wipe all messages in thread ' + tid + '?')) return;
    const r = await rcsPost('/wipe-thread', {thread_id: tid});
    alert(r.ok ? r.message : 'Failed: ' + (r.error || ''));
}

async function rcsDeleteConversation() {
    const tid = parseInt(document.getElementById('mod-thread-id').value);
    if (!tid) { alert('Enter thread ID'); return; }
    if (!confirm('Delete conversation ' + tid + '?')) return;
    const r = await fetch(RCS_BASE + '/conversation/' + tid, {method:'DELETE'}).then(r => r.json());
    alert(r.ok ? r.message : 'Failed: ' + (r.error || ''));
}

async function rcsDeleteMessage() {
    const id = parseInt(document.getElementById('mod-del-id').value);
    if (!id) { alert('Enter message ID'); return; }
    if (!confirm('Delete message ' + id + '?')) return;
    const r = await fetch(RCS_BASE + '/message/' + id, {method:'DELETE'}).then(r => r.json());
    alert(r.ok ? r.message : 'Failed: ' + (r.error || ''));
}

// ── Exploit ─────────────────────────────────────────────────────────
async function rcsCVECheck() {
    const r = await rcsGet('/cve-check');
    const el = document.getElementById('rcs-cve-status');
    if (r.vulnerable) {
        el.style.border = '1px solid #f44336';
        el.innerHTML = '<strong style="color:#f44336">VULNERABLE</strong> — ' + esc(r.message);
    } else {
        el.style.border = '1px solid #4caf50';
        el.innerHTML = '<strong style="color:#4caf50">NOT VULNERABLE</strong> — ' + esc(r.message);
    }
}

async function rcsCVEExploit() {
    if (!confirm('Execute CVE-2024-0044 exploit? This will forge a package entry to gain app-level access.')) return;
    document.getElementById('rcs-cve-result').innerHTML = '<p>Exploiting...</p>';
    const r = await rcsPost('/cve-exploit', {target_package: 'com.google.android.apps.messaging'});
    document.getElementById('rcs-cve-result').innerHTML = renderJSON(r);
    rcsRefreshStatus();
}

async function rcsCVECleanup() {
    const r = await rcsPost('/cve-cleanup');
    document.getElementById('rcs-cve-result').innerHTML = renderJSON(r);
    rcsRefreshStatus();
}

async function rcsSpoofTyping() {
    const addr = document.getElementById('exploit-spoof-addr').value;
    if (!addr) return;
    const r = await rcsPost('/rcs-spoof-typing', {address: addr});
    alert(r.ok ? r.message : 'Failed');
}

async function rcsSpoofReadReceipt() {
    const mid = document.getElementById('exploit-spoof-msgid').value;
    if (!mid) return;
    const r = await rcsPost('/rcs-spoof-read', {msg_id: mid});
    alert(r.ok ? r.message : 'Failed');
}

async function rcsCloneIdentity() {
    const r = await rcsPost('/clone-identity');
    document.getElementById('rcs-identity-result').innerHTML = renderJSON(r);
}

async function rcsExtractSignalState() {
    const r = await rcsPost('/signal-state');
    document.getElementById('rcs-identity-result').innerHTML = renderJSON(r);
}

async function rcsInterceptArchival() {
    const r = await rcsPost('/intercept-archival');
    document.getElementById('rcs-identity-result').innerHTML = renderJSON(r);
}

async function rcsShowCVEs() {
    const r = await rcsGet('/cve-database');
    const el = document.getElementById('rcs-cves-list');
    if (r.cves) {
        let h = '';
        for (const [id, cve] of Object.entries(r.cves)) {
            let sColor = cve.severity === 'critical' ? '#f44336' : cve.severity === 'high' ? '#ff9800' : '#ffeb3b';
            h += '<div style="padding:8px;margin-bottom:6px;border:1px solid var(--border);border-radius:4px;border-left:3px solid ' + sColor + '">'
                + '<div style="display:flex;justify-content:space-between;align-items:center">'
                + '<strong>' + esc(id) + '</strong>'
                + '<span style="font-size:0.75rem;padding:2px 6px;border-radius:3px;background:' + sColor + ';color:#000">'
                + esc(cve.severity.toUpperCase()) + ' ' + cve.cvss + '</span></div>'
                + '<div style="font-size:0.85rem;margin-top:4px">' + esc(cve.desc) + '</div>'
                + '<div style="font-size:0.8rem;color:var(--text-muted);margin-top:2px">Affected: ' + esc(cve.affected) + ' | Type: ' + esc(cve.type) + '</div>'
                + '</div>';
        }
        el.innerHTML = h;
    }
}

async function rcsGetIMSStatus() {
    const r = await rcsGet('/ims-status');
    document.getElementById('rcs-diag-result').textContent = r.raw || JSON.stringify(r, null, 2);
}

async function rcsGetCarrierConfig() {
    const r = await rcsGet('/carrier-config');
    document.getElementById('rcs-diag-result').textContent = JSON.stringify(r.rcs_config || r, null, 2);
}

async function rcsGetRCSState() {
    const r = await rcsGet('/rcs-state');
    document.getElementById('rcs-diag-result').textContent = JSON.stringify(r, null, 2);
}

async function rcsEnableLogging() {
    const r = await rcsPost('/enable-logging');
    document.getElementById('rcs-diag-result').textContent = JSON.stringify(r, null, 2);
}

async function rcsCaptureLogs() {
    document.getElementById('rcs-diag-result').textContent = 'Capturing logs (10s)...';
    const r = await rcsPost('/capture-logs', {duration: 10});
    document.getElementById('rcs-diag-result').textContent = (r.lines || []).join('\n');
}

async function rcsPixelDiag() {
    const r = await rcsGet('/pixel-diagnostics');
    document.getElementById('rcs-diag-result').textContent = JSON.stringify(r, null, 2);
}

// ── Backup ──────────────────────────────────────────────────────────
async function rcsFullBackup(fmt) {
    document.getElementById('rcs-backup-result').innerHTML = '<p>Creating backup...</p>';
    const r = await rcsPost('/backup', {format: fmt});
    document.getElementById('rcs-backup-result').innerHTML = renderJSON(r);
}

async function rcsArchonBackup() {
    document.getElementById('rcs-backup-result').innerHTML = '<p>Archon backup in progress...</p>';
    const r = await rcsPost('/archon/backup');
    document.getElementById('rcs-backup-result').innerHTML = renderJSON(r);
}

async function rcsRestore() {
    const path = document.getElementById('backup-restore-path').value;
    if (!path) { alert('Enter backup path'); return; }
    const r = await rcsPost('/restore', {path});
    document.getElementById('rcs-restore-result').innerHTML = renderJSON(r);
}

async function rcsCloneDevice() {
    if (!confirm('This will create a full backup for cloning. Continue?')) return;
    const r = await rcsPost('/clone');
    document.getElementById('rcs-restore-result').innerHTML = renderJSON(r);
}

async function rcsSetDefaultApp() {
    const pkg = document.getElementById('backup-sms-app').value;
    const r = await rcsPost('/set-default', {package: pkg});
    alert(r.ok ? r.message : 'Failed: ' + (r.error || ''));
    rcsRefreshStatus();
}

async function rcsListBackups() {
    const r = await rcsGet('/backups');
    const el = document.getElementById('rcs-backups-list');
    if (r.backups && r.backups.length) {
        el.innerHTML = renderTable(r.backups, ['name','size','modified']);
    } else {
        el.innerHTML = '<p style="color:var(--text-muted)">No backups yet</p>';
    }
}

async function rcsListExports() {
    const r = await rcsGet('/exports');
    const el = document.getElementById('rcs-exports-list');
    if (r.exports && r.exports.length) {
        el.innerHTML = renderTable(r.exports, ['name','size','modified']);
    } else {
        el.innerHTML = '<p style="color:var(--text-muted)">No exports yet</p>';
    }
}

// ── Monitor ─────────────────────────────────────────────────────────
async function rcsToggleMonitor() {
    if (rcsMonitorRunning) {
        await rcsPost('/monitor/stop');
        rcsMonitorRunning = false;
        document.getElementById('rcs-monitor-btn').textContent = 'Start Monitor';
        if (rcsMonitorInterval) { clearInterval(rcsMonitorInterval); rcsMonitorInterval = null; }
    } else {
        await rcsPost('/monitor/start');
        rcsMonitorRunning = true;
        document.getElementById('rcs-monitor-btn').textContent = 'Stop Monitor';
        rcsMonitorInterval = setInterval(rcsRefreshMonitor, 3000);
    }
}

async function rcsRefreshMonitor() {
    const r = await rcsGet('/monitor/messages');
    const feed = document.getElementById('rcs-monitor-feed');
    const msgs = r.messages || [];
    document.getElementById('rcs-monitor-count').textContent = msgs.length + ' intercepted';
    feed.innerHTML = msgs.map(m =>
        '<div style="padding:4px 8px;border-bottom:1px solid var(--border)">'
        + '<span style="color:var(--text-muted);font-size:0.75rem">' + esc(m.time || '') + '</span> '
        + '<span style="color:#ff9800">[' + esc(m.type || '') + ']</span> '
        + esc(m.raw || '')
        + '</div>'
    ).join('');
}

async function rcsClearMonitor() {
    await rcsPost('/monitor/clear');
    document.getElementById('rcs-monitor-feed').innerHTML = '';
    document.getElementById('rcs-monitor-count').textContent = '';
}

// ── Init ────────────────────────────────────────────────────────────
rcsRefreshStatus();
</script>
{% endblock %}


Instruction: Create an AUTARCH web template for the 'Report Engine' page. It should extend base.html, have a page header, and use AUTARCH's CSS variables and UI patterns (sections, tab bars, data tables, buttons).

Input:
Template: report_engine.html
Sections: 0
Tabs: 2
Forms/API calls: 10
Has JavaScript: True

Output:
{% extends "base.html" %}
{% block title %}Reports — AUTARCH{% endblock %}
{% block content %}
<div class="page-header">
    <h1>Reporting Engine</h1>
    <p class="text-muted">Pentest report builder with findings, CVSS scoring, and export</p>
</div>

<div class="tabs">
    <button class="tab active" onclick="switchTab('reports')">Reports</button>
    <button class="tab" onclick="switchTab('editor')">Editor</button>
    <button class="tab" onclick="switchTab('templates')">Finding Templates</button>
</div>

<!-- Reports List -->
<div id="tab-reports" class="tab-content active">
    <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem">
        <h3>Reports</h3>
        <button class="btn btn-primary" onclick="showCreateReport()">New Report</button>
    </div>
    <div id="create-form" class="card" style="display:none;margin-bottom:1rem;max-width:600px">
        <h4>Create Report</h4>
        <div class="form-group"><label>Title</label><input type="text" id="cr-title" class="form-control" placeholder="Penetration Test Report"></div>
        <div class="form-group"><label>Client</label><input type="text" id="cr-client" class="form-control" placeholder="Client name"></div>
        <div class="form-group"><label>Scope</label><textarea id="cr-scope" class="form-control" rows="2" placeholder="Target systems and IP ranges"></textarea></div>
        <button class="btn btn-primary" onclick="createReport()">Create</button>
    </div>
    <div id="reports-list"></div>
</div>

<!-- Editor -->
<div id="tab-editor" class="tab-content" style="display:none">
    <div id="editor-empty" class="card" style="text-align:center;color:var(--text-muted)">Select a report from the Reports tab</div>
    <div id="editor" style="display:none">
        <div class="card">
            <div style="display:flex;justify-content:space-between;align-items:center">
                <h3 id="ed-title" style="margin:0"></h3>
                <div style="display:flex;gap:0.5rem">
                    <select id="ed-status" class="form-control" style="width:auto" onchange="updateReportField('status',this.value)">
                        <option value="draft">Draft</option>
                        <option value="review">Review</option>
                        <option value="final">Final</option>
                    </select>
                    <button class="btn btn-sm" onclick="exportReport('html')">Export HTML</button>
                    <button class="btn btn-sm" onclick="exportReport('markdown')">Export MD</button>
                    <button class="btn btn-sm" onclick="exportReport('json')">Export JSON</button>
                </div>
            </div>
            <div class="form-group" style="margin-top:1rem"><label>Executive Summary</label>
                <textarea id="ed-summary" class="form-control" rows="3" onblur="updateReportField('executive_summary',this.value)"></textarea></div>
        </div>

        <!-- Severity Summary -->
        <div id="sev-summary" style="display:flex;gap:0.75rem;margin:1rem 0"></div>

        <!-- Findings -->
        <div style="display:flex;justify-content:space-between;align-items:center;margin:1rem 0">
            <h3>Findings</h3>
            <div style="display:flex;gap:0.5rem">
                <button class="btn btn-primary btn-sm" onclick="showAddFinding()">Add Finding</button>
                <button class="btn btn-sm" onclick="showTemplateSelector()">From Template</button>
            </div>
        </div>
        <div id="findings-list"></div>

        <!-- Add finding form -->
        <div id="add-finding-form" class="card" style="display:none;margin-top:1rem">
            <h4>Add Finding</h4>
            <div class="form-group"><label>Title</label><input type="text" id="af-title" class="form-control"></div>
            <div style="display:grid;grid-template-columns:1fr 1fr;gap:0.5rem">
                <div class="form-group"><label>Severity</label>
                    <select id="af-severity" class="form-control">
                        <option value="critical">Critical</option><option value="high">High</option>
                        <option value="medium" selected>Medium</option><option value="low">Low</option><option value="info">Info</option>
                    </select></div>
                <div class="form-group"><label>CVSS Score</label><input type="number" id="af-cvss" class="form-control" value="5.0" min="0" max="10" step="0.1"></div>
            </div>
            <div class="form-group"><label>Description</label><textarea id="af-desc" class="form-control" rows="2"></textarea></div>
            <div class="form-group"><label>Impact</label><textarea id="af-impact" class="form-control" rows="2"></textarea></div>
            <div class="form-group"><label>Remediation</label><textarea id="af-remediation" class="form-control" rows="2"></textarea></div>
            <button class="btn btn-primary" onclick="addFinding()">Add</button>
            <button class="btn" onclick="document.getElementById('add-finding-form').style.display='none'">Cancel</button>
        </div>
    </div>
</div>

<!-- Templates -->
<div id="tab-templates" class="tab-content" style="display:none">
    <h3>Finding Templates</h3>
    <div id="templates-list"></div>
</div>

<style>
.sev-badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:0.75rem;font-weight:700;color:#fff}
.sev-critical{background:#dc2626}.sev-high{background:#ef4444}.sev-medium{background:#f59e0b}.sev-low{background:#22c55e}.sev-info{background:#6366f1}
.sev-box{border:2px solid;border-radius:8px;padding:0.5rem 1rem;text-align:center;min-width:70px}
.finding-card{border:1px solid var(--border);border-radius:var(--radius);padding:1rem;margin-bottom:0.75rem}
.finding-card h4{margin:0 0 0.5rem}
</style>

<script>
let currentReportId=null;

function switchTab(name){
    document.querySelectorAll('.tab').forEach((t,i)=>t.classList.toggle('active',['reports','editor','templates'][i]===name));
    document.querySelectorAll('.tab-content').forEach(c=>c.style.display='none');
    document.getElementById('tab-'+name).style.display='block';
    if(name==='reports') loadReports();
    if(name==='templates') loadTemplates();
}

function loadReports(){
    fetch('/reports/list').then(r=>r.json()).then(d=>{
        const div=document.getElementById('reports-list');
        const reps=d.reports||[];
        if(!reps.length){div.innerHTML='<div class="card" style="text-align:center;color:var(--text-muted)">No reports yet</div>';return}
        div.innerHTML=reps.map(r=>`<div class="card" style="margin-bottom:0.5rem;cursor:pointer" onclick="openReport('${r.id}')">
            <div style="display:flex;justify-content:space-between;align-items:center">
                <div><strong>${esc(r.title)}</strong> <span style="color:var(--text-muted);font-size:0.8rem">${esc(r.client)}</span></div>
                <div style="display:flex;align-items:center;gap:0.75rem">
                    <span style="font-size:0.8rem">${r.findings_count} findings</span>
                    <span class="sev-badge sev-${r.status==='final'?'info':r.status==='review'?'medium':'low'}">${r.status}</span>
                    <button class="btn btn-sm" style="color:var(--danger)" onclick="event.stopPropagation();deleteReport('${r.id}')">Delete</button>
                </div>
            </div></div>`).join('');
    });
}

function showCreateReport(){document.getElementById('create-form').style.display=document.getElementById('create-form').style.display==='none'?'':'none'}

function createReport(){
    const payload={title:document.getElementById('cr-title').value||'Untitled',
        client:document.getElementById('cr-client').value,scope:document.getElementById('cr-scope').value};
    fetch('/reports/create',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)})
    .then(r=>r.json()).then(d=>{
        if(d.ok){document.getElementById('create-form').style.display='none';loadReports();openReport(d.report.id)}
    });
}

function deleteReport(id){
    if(!confirm('Delete this report?')) return;
    fetch('/reports/'+id,{method:'DELETE'}).then(r=>r.json()).then(()=>loadReports());
}

function openReport(id){
    currentReportId=id;
    fetch('/reports/'+id).then(r=>r.json()).then(d=>{
        if(!d.ok) return;
        const r=d.report;
        document.getElementById('editor-empty').style.display='none';
        document.getElementById('editor').style.display='';
        document.getElementById('ed-title').textContent=r.title;
        document.getElementById('ed-summary').value=r.executive_summary||'';
        document.getElementById('ed-status').value=r.status||'draft';
        renderFindings(r.findings||[]);
        switchTab('editor');
    });
}

function updateReportField(field,value){
    if(!currentReportId) return;
    const data={};data[field]=value;
    fetch('/reports/'+currentReportId,{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(data)});
}

function renderFindings(findings){
    const sevOrder={critical:0,high:1,medium:2,low:3,info:4};
    findings.sort((a,b)=>(sevOrder[a.severity]||5)-(sevOrder[b.severity]||5));
    // Summary
    const counts={};findings.forEach(f=>{counts[f.severity]=(counts[f.severity]||0)+1});
    const colors={critical:'#dc2626',high:'#ef4444',medium:'#f59e0b',low:'#22c55e',info:'#6366f1'};
    document.getElementById('sev-summary').innerHTML=['critical','high','medium','low','info'].map(s=>
        `<div class="sev-box" style="border-color:${colors[s]}"><strong style="color:${colors[s]};font-size:1.2rem">${counts[s]||0}</strong><br><span style="font-size:0.7rem">${s.toUpperCase()}</span></div>`).join('');
    // List
    document.getElementById('findings-list').innerHTML=findings.map((f,i)=>
        `<div class="finding-card"><div style="display:flex;justify-content:space-between;align-items:start">
            <div><h4>${i+1}. ${esc(f.title)}</h4>
                <span class="sev-badge sev-${f.severity}">${f.severity.toUpperCase()}</span>
                <span style="font-size:0.8rem;margin-left:0.5rem">CVSS: ${f.cvss||'N/A'}</span></div>
            <button class="btn btn-sm" style="color:var(--danger)" onclick="deleteFinding('${f.id}')">Remove</button>
        </div>
        <p style="font-size:0.85rem;margin:0.5rem 0">${esc(f.description||'')}</p>
        ${f.impact?'<div style="font-size:0.8rem"><strong>Impact:</strong> '+esc(f.impact)+'</div>':''}
        ${f.remediation?'<div style="font-size:0.8rem"><strong>Remediation:</strong> '+esc(f.remediation)+'</div>':''}
        </div>`).join('');
}

function showAddFinding(){document.getElementById('add-finding-form').style.display=''}
function showTemplateSelector(){
    fetch('/reports/templates').then(r=>r.json()).then(d=>{
        const templates=d.templates||[];
        const sel=prompt('Enter template #:\n'+templates.map((t,i)=>`${i+1}. [${t.severity.toUpperCase()}] ${t.title}`).join('\n'));
        if(!sel) return;
        const idx=parseInt(sel)-1;
        if(idx>=0&&idx<templates.length){
            const t={...templates[idx]};delete t.id;
            fetch('/reports/'+currentReportId+'/findings',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(t)})
            .then(r=>r.json()).then(()=>openReport(currentReportId));
        }
    });
}

function addFinding(){
    const data={title:document.getElementById('af-title').value,
        severity:document.getElementById('af-severity').value,
        cvss:+document.getElementById('af-cvss').value,
        description:document.getElementById('af-desc').value,
        impact:document.getElementById('af-impact').value,
        remediation:document.getElementById('af-remediation').value};
    fetch('/reports/'+currentReportId+'/findings',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(data)})
    .then(r=>r.json()).then(d=>{
        if(d.ok){document.getElementById('add-finding-form').style.display='none';openReport(currentReportId)}
    });
}

function deleteFinding(fid){
    if(!confirm('Remove this finding?')) return;
    fetch('/reports/'+currentReportId+'/findings/'+fid,{method:'DELETE'})
    .then(r=>r.json()).then(()=>openReport(currentReportId));
}

function exportReport(fmt){
    if(!currentReportId) return;
    window.open('/reports/'+currentReportId+'/export/'+fmt,'_blank');
}

function loadTemplates(){
    fetch('/reports/templates').then(r=>r.json()).then(d=>{
        document.getElementById('templates-list').innerHTML=(d.templates||[]).map(t=>
            `<div class="card" style="margin-bottom:0.5rem">
                <div style="display:flex;justify-content:space-between;align-items:center">
                    <div><span class="sev-badge sev-${t.severity}">${t.severity.toUpperCase()}</span>
                        <strong style="margin-left:0.5rem">${esc(t.title)}</strong>
                        <span style="color:var(--text-muted);font-size:0.8rem;margin-left:0.5rem">CVSS ${t.cvss}</span></div>
                </div>
                <p style="font-size:0.8rem;margin:0.3rem 0;color:var(--text-secondary)">${esc(t.description)}</p>
                <div style="font-size:0.75rem;color:var(--text-muted)">${(t.references||[]).join(', ')}</div>
            </div>`).join('');
    });
}

loadReports();

function esc(s){return s?String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;'):''}
</script>
{% endblock %}