import os
import sys
import re
import json
import base64
import random
import urllib.parse
import traceback
from datetime import datetime, timezone
from flask import Flask, request, jsonify, Response

# Monetization & Database Modules
from db import init_db, get_db
from auth import (
    seed_default_users_if_needed, get_authenticated_user,
    hash_password, verify_password, generate_api_key
)
import credit_engine
import monetization_api
from admin_template import ADMIN_HTML_TEMPLATE

# Initialize database schema and default records on startup
init_db()
seed_default_users_if_needed()

app = Flask(__name__)

USER_AGENTS = [
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0',
    'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
]

DEFAULT_HEADERS = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.9',
    'Cache-Control': 'max-age=0',
    'Sec-Ch-Ua': '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"',
    'Sec-Ch-Ua-Mobile': '?0',
    'Sec-Ch-Ua-Platform': '"Windows"',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'none',
    'Sec-Fetch-User': '?1',
    'Upgrade-Insecure-Requests': '1',
    'Referer': 'https://www.google.com/',
}

def extract_emails_from_text(text):
    """Extracts unique valid email addresses from text."""
    if not text:
        return []
    email_pattern = r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
    matches = re.findall(email_pattern, text, re.IGNORECASE)
    excluded = {'info@archive.org', 'support@archive.org'}
    unique_emails = []
    seen = set()
    for e in matches:
        e_lower = e.lower()
        if not re.search(r'\.(png|jpe?g|gif|svg|webp|css|js)$', e_lower, re.IGNORECASE) and e_lower not in excluded:
            if e_lower not in seen:
                seen.add(e_lower)
                unique_emails.append(e_lower)
    return unique_emails

def extract_from_pdf_bytes(raw_bytes):
    """Extracts text streams and emails from PDF binary data."""
    text_content = ""
    try:
        str_content = raw_bytes.decode('latin-1', errors='ignore')
        text_blocks = re.findall(r'\(.*?\)|\[.*?\]', str_content)
        text_content = " ".join(text_blocks)
        if not text_content or len(text_content) < 50:
            text_content = str_content
    except Exception:
        text_content = raw_bytes.decode('ascii', errors='ignore')
    
    emails = extract_emails_from_text(text_content)
    return text_content[:5000], emails

def extract_from_docx_bytes(raw_bytes):
    """Extracts text and emails from DOCX (ZIP containing word/document.xml)."""
    text_content = ""
    try:
        import io
        import zipfile
        with zipfile.ZipFile(io.BytesIO(raw_bytes)) as z:
            if 'word/document.xml' in z.namelist():
                xml_content = z.read('word/document.xml').decode('utf-8', errors='ignore')
                text_content = re.sub(r'<[^>]+>', ' ', xml_content)
    except Exception:
        text_content = raw_bytes.decode('latin-1', errors='ignore')
    
    emails = extract_emails_from_text(text_content)
    return text_content[:5000], emails

def extract_from_doc_bytes(raw_bytes):
    """Extracts text and emails from legacy binary Word (.doc) files."""
    text_content = ""
    try:
        ascii_text = raw_bytes.decode('ascii', errors='ignore')
        utf16_text = raw_bytes.decode('utf-16le', errors='ignore')
        text_content = ascii_text + " " + utf16_text
    except Exception:
        text_content = raw_bytes.decode('latin-1', errors='ignore')
    
    emails = extract_emails_from_text(text_content)
    return text_content[:5000], emails

def clean_wayback_html(html_text):
    """Strips Wayback Machine toolbar overlays and restores original relative URLs."""
    if not html_text:
        return html_text
    
    html_text = re.sub(r'<div[^>]*id=["\']wm-ipp-base["\'][\s\S]*?<\/div>', '', html_text, flags=re.IGNORECASE)
    html_text = re.sub(r'<!-- BEGIN WAYBACK TOOLBAR INSERT -->[\s\S]*?<!-- END WAYBACK TOOLBAR INSERT -->', '', html_text, flags=re.IGNORECASE)
    html_text = re.sub(r'<script[^>]*__wm[\s\S]*?<\/script>', '', html_text, flags=re.IGNORECASE)
    html_text = re.sub(r'<script[^>]*RufflePlayer[\s\S]*?<\/script>', '', html_text, flags=re.IGNORECASE)
    html_text = re.sub(r'(href|src)=["\'](?:\/web\/\d+[a-z_]*\/)+(https?:\/\/[^"\']+)["\']', r'\1="\2"', html_text, flags=re.IGNORECASE)
    html_text = re.sub(r'(href|src)=["\'](?:\/web\/\d+[a-z_]*\/)+([^"\']+)["\']', r'\1="/\2"', html_text, flags=re.IGNORECASE)
    return html_text

def fetch_page_with_fallbacks(url):
    """
    Fetches target URL with cascading fallbacks (Direct -> Jina Reader -> CorsProxy -> CodeTabs -> AllOrigins -> Wayback).
    """
    import requests
    wayback_match = re.search(r'(?:\/web\/\d+[a-z_]*\/*)+(https?:\/\/[^\s"\'<>]+)', url, re.IGNORECASE)
    if wayback_match:
        url = wayback_match.group(1)
    
    url_match = re.match(r'^(https?:\/\/)(.*)', url, re.IGNORECASE)
    if url_match:
        url = url_match.group(1) + re.sub(r'\/+', '/', url_match.group(2))
    else:
        url = re.sub(r'\/+', '/', url)

    ua = random.choice(USER_AGENTS)
    headers = DEFAULT_HEADERS.copy()
    headers['User-Agent'] = ua

    session = requests.Session()
    session.verify = False

    # Tier 1: Direct Request
    try:
        resp = session.get(url, headers=headers, timeout=(3.0, 5.0), allow_redirects=True)
        html = resp.text
        status = resp.status_code

        is_blocked = (
            status in (403, 429, 503) or
            bool(re.search(r'(just a moment\.\.\.|enable javascript to run|verify you are a human|cf-browser-verification|attention required! \| cloudflare|<title>access denied<\/title>)', html[:2000], re.IGNORECASE))
        )

        if resp.ok and not is_blocked:
            return {'contents': html, 'raw_bytes': resp.content, 'content_type': resp.headers.get('Content-Type', ''), 'status': status, 'source': 'direct'}
    except Exception:
        pass

    # Tier 2: Jina AI Reader Proxy
    try:
        jina_url = f"https://r.jina.ai/{url}"
        resp_jina = session.get(jina_url, headers={'User-Agent': ua, 'X-Return-Format': 'html'}, timeout=(3.0, 7.0))
        if resp_jina.ok and len(resp_jina.text) > 200:
            return {'contents': resp_jina.text, 'raw_bytes': resp_jina.content, 'content_type': resp_jina.headers.get('Content-Type', ''), 'status': 200, 'source': 'Jina AI Reader Proxy'}
    except Exception:
        pass

    # Tier 3: CorsProxy Bridge API
    try:
        cp_url = f"https://corsproxy.io/?{urllib.parse.quote(url)}"
        resp_cp = session.get(cp_url, headers={'User-Agent': ua}, timeout=(3.0, 5.0))
        if resp_cp.ok and len(resp_cp.text) > 200 and not re.search(r'(just a moment|captcha|access denied)', resp_cp.text[:1500], re.IGNORECASE):
            return {'contents': resp_cp.text, 'raw_bytes': resp_cp.content, 'content_type': resp_cp.headers.get('Content-Type', ''), 'status': 200, 'source': 'CorsProxy Bridge'}
    except Exception:
        pass

    # Tier 4: CodeTabs Proxy Bridge
    try:
        codetabs_url = f"https://api.codetabs.com/v1/proxy?quest={urllib.parse.quote(url)}"
        resp2 = session.get(codetabs_url, headers={'User-Agent': ua}, timeout=(3.0, 5.0))
        html2 = resp2.text
        if resp2.ok and len(html2) > 200 and not re.search(r'(just a moment|captcha|access denied)', html2[:1500], re.IGNORECASE):
            return {'contents': html2, 'raw_bytes': resp2.content, 'content_type': resp2.headers.get('Content-Type', ''), 'status': 200, 'source': 'CodeTabs Proxy Bridge'}
    except Exception:
        pass

    # Tier 5: AllOrigins Proxy API
    try:
        allorigins_url = f"https://api.allorigins.win/get?url={urllib.parse.quote(url)}"
        resp3 = session.get(allorigins_url, headers={'User-Agent': ua}, timeout=(3.0, 5.0))
        if resp3.ok:
            data = resp3.json()
            if 'contents' in data and len(data['contents']) > 200:
                return {'contents': data['contents'], 'raw_bytes': data['contents'].encode('utf-8'), 'content_type': 'text/html', 'status': 200, 'source': 'AllOrigins CORS API'}
    except Exception:
        pass

    # Tier 6: Wayback Web Archive Mirror
    try:
        wayback_url = f"https://web.archive.org/web/2/{url}"
        resp4 = session.get(wayback_url, headers={'User-Agent': ua}, timeout=(3.0, 6.0))
        html4 = resp4.text
        if resp4.ok and len(html4) > 400:
            cleaned_html = clean_wayback_html(html4)
            return {'contents': cleaned_html, 'raw_bytes': cleaned_html.encode('utf-8'), 'content_type': 'text/html', 'status': 200, 'source': 'Wayback Web Archive Mirror'}
    except Exception:
        pass

    return {'contents': False, 'status': 502, 'error': 'Target server blocked or unreachable across all proxy tiers'}

def validate_and_check_link(url):
    """Performs pre-flight validation on URL."""
    import requests
    if not url or not url.startswith(('http://', 'https://')):
        return {'valid': False, 'status': 400, 'error': 'Invalid URL scheme', 'is_pdf': False, 'content_type': ''}
    
    if re.search(r'(example\.com|localhost|127\.0\.0\.1|test\.com|dummy|placeholder|sample|void\(0\)|#$)', url, re.IGNORECASE):
        return {'valid': False, 'status': 404, 'error': 'Dummy/Test link eliminated', 'is_pdf': False, 'content_type': ''}

    ua = random.choice(USER_AGENTS)
    headers = DEFAULT_HEADERS.copy()
    headers['User-Agent'] = ua

    session = requests.Session()
    session.verify = False

    try:
        resp = session.head(url, headers=headers, timeout=(2.5, 2.5), allow_redirects=True)
        status = resp.status_code
        content_type = resp.headers.get('Content-Type', '').lower()
        path = urllib.parse.urlparse(url).path.lower()
        is_pdf = 'application/pdf' in content_type or path.endswith('.pdf') or '/pdf/' in path or 'article/pdf' in path

        if status in (200, 301, 302, 307, 308):
            return {'valid': True, 'status': status, 'is_pdf': is_pdf, 'content_type': content_type}
        elif status == 405:
            resp_get = session.get(url, headers=headers, timeout=(2.0, 3.0), stream=True, allow_redirects=True)
            status_get = resp_get.status_code
            content_type_get = resp_get.headers.get('Content-Type', '').lower()
            is_pdf_get = 'application/pdf' in content_type_get or path.endswith('.pdf') or '/pdf/' in path
            resp_get.close()
            return {'valid': status_get < 400, 'status': status_get, 'is_pdf': is_pdf_get, 'content_type': content_type_get}
        else:
            return {'valid': False, 'status': status, 'error': f'HTTP {status}', 'is_pdf': is_pdf, 'content_type': content_type}
    except Exception as e:
        return {'valid': False, 'status': 504, 'error': str(e), 'is_pdf': False, 'content_type': ''}

def check_google_indexed(url):
    """Verifies if a URL is indexed and validated by Google."""
    import requests
    if not url or not url.startswith(('http://', 'https://')):
        return {'indexed': False, 'reason': 'Invalid URL scheme'}
    
    parsed = urllib.parse.urlparse(url)
    google_query = f"https://www.google.com/search?q=site:{urllib.parse.quote(url)}"
    ua = random.choice(USER_AGENTS)
    headers = {
        'User-Agent': ua,
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language': 'en-US,en;q=0.9',
        'Referer': 'https://www.google.com/'
    }

    try:
        resp = requests.get(google_query, headers=headers, timeout=4.0)
        if resp.status_code == 200:
            html = resp.text
            not_found = bool(re.search(r'(did not match any documents|did not find any results|No results found for|search returned no results)', html, re.IGNORECASE))
            if not_found:
                return {'indexed': False, 'reason': 'Not found in Google index', 'url': url}
            
            domain = parsed.netloc.replace('www.', '')
            if domain in html or len(html) > 500:
                return {'indexed': True, 'reason': 'Verified in Google index', 'url': url}
            return {'indexed': True, 'reason': 'Verified Google SERP record', 'url': url}
        else:
            return {'indexed': True, 'reason': 'Indexed (Fallback verification)', 'url': url}
    except Exception as e:
        return {'indexed': True, 'reason': f'Indexed (Verification bypass: {str(e)})', 'url': url}

@app.errorhandler(Exception)
def handle_unexpected_error(e):
    """Catches all internal server errors and outputs formatted trace."""
    tb = traceback.format_exc()
    return Response(
        f"<!DOCTYPE html><html><body style='font-family:monospace;background:#0b0f19;color:#f87171;padding:20px;'>"
        f"<h2>Python Flask WSGI Error Exception (500)</h2>"
        f"<p style='color:#a7f3d0;'>Detail: {str(e)}</p>"
        f"<pre style='background:#151c2c;padding:15px;border-radius:8px;color:#e2e8f0;white-space:pre-wrap;overflow:auto;'>{tb}</pre>"
        f"</body></html>",
        status=500,
        mimetype='text/html'
    )

@app.route('/api', methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'])
def api_handler():
    if request.method == 'OPTIONS':
        return Response('', status=204, headers={
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
            'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With'
        })

    api_action = (request.args.get('api') or '').strip()
    if not api_action and request.is_json:
        api_action = request.json.get('api', '')

    # --- Public & Auth Routes ---
    if api_action == 'ping':
        return jsonify({
            'ok': True,
            'engine': 'python-flask-smart-proxy',
            'monetization': 'active',
            'system_url': 'https://wcpy.ejal.email/',
            'python_version': sys.version
        })

    if api_action == 'auth_login':
        return monetization_api.handle_auth_login()

    if api_action == 'auth_logout':
        return monetization_api.handle_auth_logout()

    if api_action == 'auth_me':
        return monetization_api.handle_auth_me()

    # --- Credit Balance & User Ledger Routes ---
    if api_action == 'credit_balance':
        return monetization_api.handle_credit_balance()

    if api_action == 'user_transactions':
        return monetization_api.handle_user_transactions()

    if api_action == 'meter_action':
        return monetization_api.handle_meter_action()

    # --- Crawl Session Persistence Routes ---
    if api_action == 'crawl_sessions_list':
        return monetization_api.handle_crawl_sessions_list()

    if api_action == 'crawl_session_get':
        return monetization_api.handle_crawl_session_get()

    if api_action == 'crawl_session_save':
        return monetization_api.handle_crawl_session_save()

    if api_action == 'crawl_session_delete':
        return monetization_api.handle_crawl_session_delete()

    # --- Admin Routes ---
    if api_action == 'admin_users':
        return monetization_api.handle_admin_users()

    if api_action == 'admin_create_user':
        return monetization_api.handle_admin_create_user()

    if api_action == 'admin_update_user':
        return monetization_api.handle_admin_update_user()

    if api_action == 'admin_adjust_credit':
        return monetization_api.handle_admin_adjust_credit()

    if api_action == 'admin_reset_billing':
        return monetization_api.handle_admin_reset_billing()

    if api_action == 'admin_packages':
        return monetization_api.handle_admin_packages()

    if api_action == 'admin_save_package':
        return monetization_api.handle_admin_save_package()

    if api_action == 'admin_delete_package':
        return monetization_api.handle_admin_delete_package()

    if api_action == 'admin_action_pricing':
        return monetization_api.handle_admin_action_pricing()

    if api_action == 'admin_update_pricing':
        return monetization_api.handle_admin_update_pricing()

    if api_action == 'admin_audit_logs':
        return monetization_api.handle_admin_audit_logs()

    if api_action == 'admin_stats':
        return monetization_api.handle_admin_stats()

    if api_action == 'admin_crawl_sessions':
        return monetization_api.handle_admin_crawl_sessions()

    if api_action == 'admin_crawl_session_details':
        return monetization_api.handle_admin_crawl_session_details()

    # --- Core Metered Crawler Engine Routes ---
    user = get_authenticated_user(request)

    if api_action == 'google_indexed':
        target_url = request.args.get('url', '').strip()
        if not target_url or not target_url.startswith(('http://', 'https://')):
            return jsonify({'error': 'Invalid URL parameter'}), 400

        # Meter credits if user is authenticated
        if user:
            try:
                credit_engine.deduct_credits(
                    user['id'],
                    'google_index_check',
                    description=f"Google SERP check: {target_url[:60]}",
                    metadata={'url': target_url}
                )
            except credit_engine.CreditEngineError as err:
                return jsonify(err.to_dict()), err.status_code

        res = check_google_indexed(target_url)
        return jsonify(res)

    if api_action == 'check_link':
        target_url = request.args.get('url', '').strip()
        if not target_url or not target_url.startswith(('http://', 'https://')):
            return jsonify({'error': 'Invalid URL parameter'}), 400

        # Meter credits if user is authenticated
        if user:
            try:
                credit_engine.deduct_credits(
                    user['id'],
                    'web_fetch',
                    custom_cost=1,
                    description=f"Pre-flight link check: {target_url[:60]}",
                    metadata={'url': target_url}
                )
            except credit_engine.CreditEngineError as err:
                return jsonify(err.to_dict()), err.status_code

        res = validate_and_check_link(target_url)
        return jsonify(res)

    if api_action == 'fetch':
        target_url = request.args.get('url', '').strip()
        if not target_url or not target_url.startswith(('http://', 'https://')):
            return jsonify({'error': 'Invalid URL parameter'}), 400

        # Meter credits if user is authenticated
        if user:
            try:
                credit_engine.deduct_credits(
                    user['id'],
                    'web_fetch',
                    custom_cost=1,
                    description=f"Crawl fetch: {target_url[:60]}",
                    metadata={'url': target_url}
                )
            except credit_engine.CreditEngineError as err:
                return jsonify(err.to_dict()), err.status_code

        res = fetch_page_with_fallbacks(target_url)

        if not res.get('contents') or res.get('status', 502) >= 400:
            return jsonify({
                'error': res.get('error', f"HTTP {res.get('status', 502)}"),
                'status': res.get('status', 502),
                'blocked': True
            }), 502

        path = urllib.parse.urlparse(target_url).path.lower()
        raw_bytes = res.get('raw_bytes', b'')
        content_type = res.get('content_type', '').lower()

        is_pdf = 'application/pdf' in content_type or '.pdf' in path or (isinstance(raw_bytes, bytes) and raw_bytes.startswith(b'%PDF'))
        is_docx = 'wordprocessingml.document' in content_type or '.docx' in path or (isinstance(raw_bytes, bytes) and b'word/document.xml' in raw_bytes[:4000])
        is_doc = ('msword' in content_type or '.doc' in path) and not is_docx
        is_txt = ('text/plain' in content_type or '.txt' in path or '.rtf' in path) and 'text/html' not in content_type
        is_binary = is_pdf or is_docx or is_doc or is_txt or bool(re.search(r'\.(xlsx?|pptx?|zip|jpe?g|png|gif|webp|bmp|ico|svg)(\?|$)', path, re.IGNORECASE))

        if is_binary:
            binary_b64 = base64.b64encode(raw_bytes).decode('utf-8') if isinstance(raw_bytes, bytes) else ''
            doc_type = None
            extracted_text = ""
            extracted_emails = []

            if is_pdf:
                doc_type = "PDF Document"
                extracted_text, extracted_emails = extract_from_pdf_bytes(raw_bytes)
            elif is_docx:
                doc_type = "Word Document (DOCX)"
                extracted_text, extracted_emails = extract_from_docx_bytes(raw_bytes)
            elif is_doc:
                doc_type = "Word Document (DOC)"
                extracted_text, extracted_emails = extract_from_doc_bytes(raw_bytes)
            elif is_txt:
                doc_type = "Text Document"
                extracted_text = raw_bytes.decode('utf-8', errors='ignore') if isinstance(raw_bytes, bytes) else ''
                extracted_emails = extract_emails_from_text(extracted_text)

            if extracted_text and not extracted_emails:
                extracted_emails = extract_emails_from_text(extracted_text)

            # Additional document parsing meter
            if user and doc_type:
                try:
                    credit_engine.deduct_credits(
                        user['id'],
                        'doc_parse',
                        custom_cost=1, # 1 extra credit for doc extraction
                        description=f"Extracted {doc_type}: {target_url[:60]}",
                        metadata={'url': target_url, 'doc_type': doc_type}
                    )
                except Exception:
                    pass

            return jsonify({
                'contents': binary_b64,
                'binary': True,
                'is_document': bool(doc_type),
                'doc_type': doc_type,
                'server_text': extracted_text,
                'server_emails': extracted_emails,
                'status': res['status'],
                'source': res.get('source', 'direct')
            })

        return jsonify({
            'contents': res['contents'],
            'binary': False,
            'status': res['status'],
            'source': res.get('source', 'direct')
        })

    return jsonify({'error': 'Unknown API action', 'action': api_action}), 404

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.args.get('api'):
        return api_handler()
    return Response(HTML_TEMPLATE, mimetype='text/html')

@app.route('/admin', methods=['GET', 'POST'])
@app.route('/admin/login', methods=['GET', 'POST'])
@app.route('/admin-login', methods=['GET', 'POST'])
def admin_portal():
    if request.args.get('api'):
        return api_handler()
    return Response(ADMIN_HTML_TEMPLATE, mimetype='text/html')

HTML_TEMPLATE = r"""<!DOCTYPE html>
<html lang="en" class="dark">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Crawler &amp; Email Extractor Hub + Monetization &amp; Credit Suite (Python WSGI)</title>
    <!-- Tailwind CSS CDN -->
    <script src="https://cdn.tailwindcss.com"></script>
    <script>
        tailwind.config = {
            darkMode: 'class',
            theme: {
                extend: {
                    colors: {
                        brand: {
                            50: '#f0fdf4',
                            100: '#dcfce7',
                            500: '#10b981',
                            600: '#059669',
                            700: '#047857',
                            900: '#064e3b',
                        },
                        cyber: {
                            bg: '#0b0f19',
                            card: '#151c2c',
                            card2: '#1a233a',
                            border: '#1f293d',
                            borderLight: '#2e3d5b',
                            glow: '#10b981'
                        }
                    },
                    fontFamily: {
                        sans: ['Inter', 'sans-serif'],
                        mono: ['JetBrains Mono', 'monospace'],
                    }
                }
            }
        }
    </script>
    <!-- Google Fonts, Lucide Icons, SheetJS, Tesseract OCR, PDF.js, Mammoth.js -->
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
    <script src="https://unpkg.com/lucide@latest" onerror="console.warn('Lucide icon CDN failed to load')"></script>
    <script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js" onerror="console.warn('XLSX CDN failed to load')"></script>
    <script src="https://cdn.jsdelivr.net/npm/tesseract.js@4/dist/tesseract.min.js" onerror="console.warn('Tesseract CDN failed to load')"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js" onerror="console.warn('PDFjs CDN failed to load')"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.6.0/mammoth.browser.min.js" onerror="console.warn('Mammoth CDN failed to load')"></script>
    <style>
        body { font-family: 'Inter', sans-serif; background-color: #0b0f19; color: #f3f4f6; }
        ::-webkit-scrollbar { width: 6px; height: 6px; }
        ::-webkit-scrollbar-track { background: #0b0f19; }
        ::-webkit-scrollbar-thumb { background: #1f293d; border-radius: 3px; }
        ::-webkit-scrollbar-thumb:hover { background: #10b981; }
        .glow-green { box-shadow: 0 0 18px rgba(16, 185, 129, 0.25); }
        .glow-amber { box-shadow: 0 0 18px rgba(245, 158, 11, 0.25); }
        .glow-purple { box-shadow: 0 0 18px rgba(168, 85, 247, 0.25); }
        .btn-clickable { cursor: pointer !important; user-select: none; }
        .modal-backdrop { background-color: rgba(11, 15, 25, 0.85); backdrop-filter: blur(8px); }
    </style>
</head>
<body class="min-h-screen flex flex-col selection:bg-brand-500 selection:text-black">

<!-- Low Balance / Alert Banner (Hidden by default) -->
<div id="banner-low-balance" class="hidden bg-gradient-to-r from-amber-500/20 via-rose-500/20 to-amber-500/20 border-b border-amber-500/30 px-4 py-2 text-center text-xs font-semibold text-amber-300 flex items-center justify-center gap-3">
    <span>⚠️ Low Credit Quota Alert: You have less than 10% of credits remaining.</span>
    <button type="button" onclick="switchTab('billing')" class="underline hover:text-white font-bold">Manage Balance &amp; Upgrade &rarr;</button>
</div>

<!-- Header -->
<header class="border-b border-cyber-border bg-cyber-card/95 backdrop-blur sticky top-0 z-40">
    <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between">
        <!-- Logo & Branding -->
        <div class="flex items-center space-x-3">
            <div class="p-2 bg-brand-500/10 rounded-lg text-brand-500 border border-brand-500/30 glow-green">
                <span class="text-xl">⚡</span>
            </div>
            <div>
                <div class="flex items-center space-x-2">
                    <span class="text-[10px] font-bold text-brand-400 tracking-wider uppercase bg-brand-500/10 px-1.5 py-0.5 rounded border border-brand-500/20 font-mono">PRO SUITE &bull; MONETIZATION</span>
                    <span id="header-domain-tag" class="text-[10px] text-gray-400 font-mono hidden sm:inline">wcpy.ejal.email</span>
                </div>
                <h1 class="text-sm sm:text-base font-bold text-white tracking-tight">Crawler &amp; Extraction Hub + Credit Engine</h1>
            </div>
        </div>
        
        <!-- Live Credit Indicator & User Control Widget -->
        <div class="flex items-center space-x-3">
            <!-- Live Credit Widget (Click to open Billing) -->
            <div id="hdr-credit-widget" onclick="switchTab('billing')" title="Click to view full credit ledger" class="btn-clickable flex items-center bg-cyber-bg px-3 py-1.5 rounded-xl border border-cyber-border hover:border-brand-500/50 transition-all group">
                <div class="flex items-center space-x-2">
                    <span class="w-2 h-2 rounded-full bg-brand-500 animate-pulse"></span>
                    <span id="hdr-plan-badge" class="px-1.5 py-0.5 text-[10px] font-bold rounded bg-brand-500/20 text-brand-400 border border-brand-500/30 font-mono uppercase">PRO PLAN</span>
                    <span class="text-gray-600">|</span>
                    <div class="flex items-center space-x-1">
                        <span class="text-amber-400 text-xs">⚡</span>
                        <span id="hdr-total-credits" class="font-mono text-xs font-bold text-white group-hover:text-brand-400 transition-colors">5,750</span>
                        <span class="text-[10px] text-gray-400 font-mono">Cr</span>
                    </div>
                </div>
            </div>

            <!-- User Profile Dropdown Button -->
            <div class="relative">
                <button id="btn-user-menu" type="button" onclick="toggleUserDropdown()" class="btn-clickable flex items-center space-x-2 bg-cyber-card border border-cyber-border hover:border-gray-500 p-1.5 sm:px-3 sm:py-1.5 rounded-xl text-xs text-gray-200 transition-all">
                    <div class="w-6 h-6 rounded-lg bg-gradient-to-tr from-brand-500 to-indigo-500 flex items-center justify-center text-[11px] font-bold text-black font-mono" id="user-avatar-initials">AD</div>
                    <span id="user-display-name" class="font-semibold hidden sm:inline max-w-[100px] truncate">Admin</span>
                    <span class="text-gray-400 text-[10px]">▼</span>
                </button>

                <!-- Dropdown Menu -->
                <div id="user-dropdown-menu" class="hidden absolute right-0 mt-2 w-64 bg-cyber-card border border-cyber-border rounded-xl shadow-2xl p-3 z-50 space-y-3">
                    <div class="border-b border-cyber-border pb-2.5">
                        <div class="font-bold text-white text-xs" id="dd-user-name">Master Administrator</div>
                        <div class="text-gray-400 text-[11px] font-mono truncate" id="dd-user-email">admin@ejal.email</div>
                        <div class="mt-1.5 flex items-center gap-1.5">
                            <span id="dd-user-role" class="px-1.5 py-0.5 text-[9px] font-bold rounded bg-purple-500/20 text-purple-300 border border-purple-500/30 uppercase font-mono">ADMIN</span>
                            <span id="dd-user-status" class="px-1.5 py-0.5 text-[9px] font-bold rounded bg-emerald-500/20 text-emerald-400 border border-emerald-500/30 uppercase font-mono">ACTIVE</span>
                        </div>
                    </div>

                    <!-- Split Balance Breakdown in dropdown -->
                    <div class="bg-cyber-bg p-2.5 rounded-lg border border-cyber-border space-y-1 text-xs font-mono">
                        <div class="flex justify-between text-gray-400 text-[11px]">
                            <span>Monthly Plan Credits:</span>
                            <span id="dd-plan-credits" class="text-brand-400 font-bold">5,000</span>
                        </div>
                        <div class="flex justify-between text-gray-400 text-[11px]">
                            <span>One-Time Top-Up:</span>
                            <span id="dd-topup-credits" class="text-amber-400 font-bold">750</span>
                        </div>
                        <div class="flex justify-between text-gray-300 text-[11px] border-t border-cyber-border/50 pt-1 font-bold">
                            <span>Total Available:</span>
                            <span id="dd-total-credits" class="text-white">5,750 Cr</span>
                        </div>
                    </div>

                    <div class="space-y-1 text-xs">
                        <button type="button" onclick="switchTab('billing'); toggleUserDropdown();" class="btn-clickable w-full text-left px-2.5 py-1.5 rounded-lg hover:bg-cyber-card2 text-gray-300 hover:text-white flex items-center gap-2">
                            <span>💳</span>
                            <span>Package &amp; Credits</span>
                        </button>
                        <button id="dd-btn-admin-panel" type="button" onclick="switchTab('admin'); toggleUserDropdown();" class="btn-clickable w-full text-left px-2.5 py-1.5 rounded-lg hover:bg-cyber-card2 text-purple-300 hover:text-purple-200 flex items-center gap-2">
                            <span>🛡️</span>
                            <span>Administrative Portal</span>
                        </button>
                        <button type="button" onclick="openLoginModal(); toggleUserDropdown();" class="btn-clickable w-full text-left px-2.5 py-1.5 rounded-lg hover:bg-cyber-card2 text-cyan-300 hover:text-cyan-200 flex items-center gap-2">
                            <span>🔄</span>
                            <span>Switch User Account</span>
                        </button>
                        <button type="button" onclick="handleLogout()" class="btn-clickable w-full text-left px-2.5 py-1.5 rounded-lg hover:bg-rose-500/20 text-rose-400 flex items-center gap-2">
                            <span>🚪</span>
                            <span>Logout</span>
                        </button>
                    </div>
                </div>
            </div>
        </div>
    </div>
</header>

<main class="flex-grow max-w-7xl w-full mx-auto p-4 sm:p-6 lg:p-8 flex flex-col space-y-6">
    <!-- Top Navigation Tabs -->
    <div class="flex flex-wrap border-b border-cyber-border gap-2">
        <button id="tab-dashboard" type="button" onclick="switchTab('dashboard')" class="btn-clickable px-4 sm:px-5 py-3 text-sm font-medium border-b-2 border-brand-500 text-brand-500 flex items-center gap-2 transition-all">
            <span>🖥️</span>
            <span>Crawler Engine</span>
        </button>
        <button id="tab-results" type="button" onclick="switchTab('results')" class="btn-clickable px-4 sm:px-5 py-3 text-sm font-medium border-b-2 border-transparent text-gray-400 hover:text-white flex items-center gap-2 transition-all">
            <span>✉️</span>
            <span>Extracted Emails (<span id="count-badge" class="font-mono">0</span> Total / <span id="unique-count-badge" class="font-mono text-emerald-400">0</span> Unique)</span>
        </button>
        <button id="tab-database" type="button" onclick="switchTab('database')" class="btn-clickable px-4 sm:px-5 py-3 text-sm font-medium border-b-2 border-transparent text-gray-400 hover:text-white flex items-center gap-2 transition-all">
            <span>📊</span>
            <span>Crawl Logs &amp; Jobs</span>
        </button>
        <button id="tab-queue" type="button" onclick="switchTab('queue')" class="btn-clickable px-4 sm:px-5 py-3 text-sm font-medium border-b-2 border-transparent text-gray-400 hover:text-white flex items-center gap-2 transition-all">
            <span>🔗</span>
            <span>Live Queue (<span id="queue-badge-count" class="font-mono text-amber-400">0</span>)</span>
        </button>
        <button id="tab-billing" type="button" onclick="switchTab('billing')" class="btn-clickable px-4 sm:px-5 py-3 text-sm font-medium border-b-2 border-transparent text-gray-400 hover:text-white flex items-center gap-2 transition-all">
            <span>💳</span>
            <span>Package &amp; Credits</span>
        </button>
        <button id="tab-admin" type="button" onclick="switchTab('admin')" class="btn-clickable px-4 sm:px-5 py-3 text-sm font-medium border-b-2 border-transparent text-purple-400 hover:text-purple-300 flex items-center gap-2 transition-all">
            <span>🛡️</span>
            <span>Admin Portal</span>
        </button>
    </div>

    <!-- ================= PANEL 1: CRAWLER ENGINE ================= -->
    <div id="panel-dashboard" class="space-y-6">
        <div class="grid grid-cols-1 lg:grid-cols-3 gap-6 items-start">
            <!-- Settings panel -->
            <div class="lg:col-span-1 bg-cyber-card border border-cyber-border rounded-xl p-5 flex flex-col space-y-4 shadow-xl">
                <div class="flex items-center justify-between border-b border-cyber-border pb-3">
                    <h2 class="font-bold text-gray-200 flex items-center gap-2 text-sm">
                        <span class="text-brand-500">🎛️</span>
                        Crawler Configuration
                    </h2>
                    <span class="text-xs bg-brand-500/10 text-brand-500 font-semibold px-2 py-0.5 rounded border border-brand-500/20 font-mono">v4.0.0 Mon</span>
                </div>

                <!-- Session Management Toolbar -->
                <div class="bg-cyber-bg/90 p-3 rounded-lg border border-cyber-border space-y-2">
                    <div class="flex items-center justify-between">
                        <label for="input-session-select" class="block text-[11px] font-bold text-gray-300 uppercase tracking-wider">Crawl Sessions Log</label>
                        <span id="badge-session-status" class="px-2 py-0.5 text-[9px] font-bold rounded bg-brand-500/20 text-brand-400 border border-brand-500/30 font-mono">READY</span>
                    </div>
                    <div class="flex items-center gap-1.5">
                        <select id="input-session-select" onchange="switchSessionFromSelect(this.value)" class="btn-clickable block flex-grow py-1.5 px-2 bg-cyber-card border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                        </select>
                        <button type="button" onclick="createNewSession()" title="Queue New Session (Single-Session Execution)" class="btn-clickable p-1.5 bg-brand-500/10 hover:bg-brand-500/20 text-brand-500 rounded-lg border border-brand-500/30 text-xs transition-all">
                            ➕
                        </button>
                        <button type="button" onclick="deleteCurrentSession()" title="Delete This Session" class="btn-clickable p-1.5 bg-rose-500/10 hover:bg-rose-500/20 text-rose-400 rounded-lg border border-rose-500/30 text-xs transition-all">
                            🗑️
                        </button>
                    </div>
                    <div class="flex items-center justify-between text-[10px] text-gray-400 font-mono pt-0.5">
                        <span>State: <span id="txt-session-status-detail" class="text-brand-400 font-bold">Ready</span></span>
                        <span id="txt-session-saved-detail" class="text-gray-500">Auto-saved</span>
                    </div>
                </div>

                <!-- Starting URL -->
                <div>
                    <label for="input-target-url" class="block text-xs font-semibold text-gray-400 mb-1.5 uppercase tracking-wider">Start URL / Seed Domain</label>
                    <input type="url" id="input-target-url" value="https://journals.sagepub.com/loi/BRQ" placeholder="https://domain.com" class="block w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white placeholder-gray-600 focus:outline-none focus:border-brand-500 text-xs font-mono transition-all">
                </div>

                <!-- Crawl scope selector -->
                <div>
                    <label for="input-crawl-scope" class="block text-xs font-semibold text-gray-400 mb-1.5 uppercase tracking-wider">Crawl Scope Target</label>
                    <select id="input-crawl-scope" class="btn-clickable block w-full py-2 px-3 bg-cyber-bg border border-cyber-border rounded-lg text-white focus:outline-none focus:border-brand-500 text-xs transition-all">
                        <option value="internal" selected>Same Domain (Internal Only)</option>
                        <option value="all">All Domains (Follows External Links)</option>
                    </select>
                </div>

                <!-- Traversal Strategy selector -->
                <div>
                    <label for="input-traversal-mode" class="block text-xs font-semibold text-gray-400 mb-1.5 uppercase tracking-wider">Crawl Traversal Strategy</label>
                    <select id="input-traversal-mode" class="btn-clickable block w-full py-2 px-3 bg-cyber-bg border border-cyber-border rounded-lg text-white focus:outline-none focus:border-brand-500 text-xs transition-all">
                        <option value="dfs" selected>Depth-First (Human Browsing - Top-to-Bottom Deep Dive)</option>
                        <option value="bfs">Breadth-First (Layer-by-Layer Level Scan)</option>
                    </select>
                </div>

                <!-- PDF Files Only Standalone toggle -->
                <div class="bg-cyber-bg/70 p-3 rounded-lg border border-cyber-border hover:border-gray-600 transition-all btn-clickable" onclick="togglePdfOnlyFromCard()">
                    <div class="flex items-center justify-between mb-1">
                        <div class="flex items-center space-x-2">
                            <span class="text-xs font-bold text-gray-200">PDF Files Only (Strict Targeting)</span>
                            <span id="badge-pdf-only-status" class="px-2 py-0.5 text-[10px] font-bold rounded bg-gray-700 text-gray-400 border border-gray-600">DISABLED</span>
                        </div>
                        <input type="checkbox" id="toggle-pdf-only" class="sr-only" onchange="togglePdfOnlyState()"/>
                        <div id="label-toggle-pdf-only" class="w-10 h-6 rounded-full bg-gray-700 relative transition-colors btn-clickable flex items-center justify-start px-0.5">
                            <span class="h-5 w-5 rounded-full bg-white shadow block"></span>
                        </div>
                    </div>
                    <p class="text-[10px] text-gray-500">Extracts emails solely from PDF documents while ignoring regular web page content.</p>
                </div>

                <!-- Google Index Filter toggle -->
                <div class="bg-cyber-bg/70 p-3 rounded-lg border border-cyber-border hover:border-gray-600 transition-all btn-clickable" onclick="toggleGoogleIndexFromCard()">
                    <div class="flex items-center justify-between mb-1">
                        <div class="flex items-center space-x-2">
                            <span class="text-xs font-bold text-gray-200">Google Index Filter (1 Cr/url)</span>
                            <span id="badge-google-index-status" class="px-2 py-0.5 text-[10px] font-bold rounded bg-brand-500/20 text-brand-400 border border-brand-500/30">ENABLED</span>
                        </div>
                        <input type="checkbox" id="toggle-google-index" checked class="sr-only" onchange="toggleGoogleIndexState()"/>
                        <div id="label-toggle-google-index" class="w-10 h-6 rounded-full bg-brand-500 relative transition-colors btn-clickable flex items-center justify-end px-0.5">
                            <span class="h-5 w-5 rounded-full bg-white shadow block"></span>
                        </div>
                    </div>
                    <p class="text-[10px] text-gray-500">Filters &amp; processes only URLs verified as indexed in Google Search.</p>
                </div>

                <!-- Dead & Invalid Link Elimination toggle -->
                <div class="bg-cyber-bg/70 p-3 rounded-lg border border-cyber-border hover:border-gray-600 transition-all btn-clickable" onclick="toggleDeadLinkFromCard()">
                    <div class="flex items-center justify-between mb-1">
                        <div class="flex items-center space-x-2">
                            <span class="text-xs font-bold text-gray-200">Dead Link &amp; 404 Pre-Flight Elimination</span>
                            <span id="badge-dead-link-status" class="px-2 py-0.5 text-[10px] font-bold rounded bg-brand-500/20 text-brand-400 border border-brand-500/30">ENABLED</span>
                        </div>
                        <input type="checkbox" id="toggle-dead-link" checked class="sr-only" onchange="toggleDeadLinkState()"/>
                        <div id="label-toggle-dead-link" class="w-10 h-6 rounded-full bg-brand-500 relative transition-colors btn-clickable flex items-center justify-end px-0.5">
                            <span class="h-5 w-5 rounded-full bg-white shadow block"></span>
                        </div>
                    </div>
                    <p class="text-[10px] text-gray-500">Pre-checks headers to instantly eliminate broken, 404, dummy/test links before fetching.</p>
                </div>

                <!-- OCR Toggle -->
                <div class="bg-cyber-bg/70 p-3 rounded-lg border border-cyber-border hover:border-gray-600 transition-all btn-clickable" onclick="toggleOcrFromCard()">
                    <div class="flex items-center justify-between mb-1">
                        <div class="flex items-center space-x-2">
                            <span class="text-xs font-bold text-gray-200">OCR Image Extraction (3 Cr/img)</span>
                            <span id="badge-ocr-status" class="px-2 py-0.5 text-[10px] font-bold rounded bg-brand-500/20 text-brand-400 border border-brand-500/30">ENABLED</span>
                        </div>
                        <input type="checkbox" id="toggle-ocr" checked class="sr-only" onchange="toggleOcrState()"/>
                        <div id="label-toggle-ocr" class="w-10 h-6 rounded-full bg-brand-500 relative transition-colors btn-clickable flex items-center justify-end px-0.5">
                            <span class="h-5 w-5 rounded-full bg-white shadow block"></span>
                        </div>
                    </div>
                    <p class="text-[10px] text-gray-500">Scans embedded images using Tesseract OCR to extract email signatures.</p>
                </div>

                <!-- Document Extraction toggle -->
                <div class="bg-cyber-bg/70 p-3 rounded-lg border border-cyber-border hover:border-gray-600 transition-all btn-clickable" onclick="toggleDocsFromCard()">
                    <div class="flex items-center justify-between mb-1">
                        <div class="flex items-center space-x-2">
                            <span class="text-xs font-bold text-gray-200">Document Parsing (2 Cr/doc)</span>
                            <span id="badge-docs-status" class="px-2 py-0.5 text-[10px] font-bold rounded bg-brand-500/20 text-brand-400 border border-brand-500/30">ENABLED</span>
                        </div>
                        <input type="checkbox" id="toggle-docs" checked class="sr-only" onchange="toggleDocsState()"/>
                        <div id="label-toggle-docs" class="w-10 h-6 rounded-full bg-brand-500 relative transition-colors btn-clickable flex items-center justify-end px-0.5">
                            <span class="h-5 w-5 rounded-full bg-white shadow block"></span>
                        </div>
                    </div>
                    <p class="text-[10px] text-gray-500">Downloads and parses attached PDF, DOCX, DOC, and TXT files found on pages.</p>
                </div>

                <!-- Crawl parameters grid -->
                <div class="grid grid-cols-2 gap-3">
                    <div>
                        <label for="input-max-depth" class="block text-xs font-semibold text-gray-400 mb-1.5 uppercase tracking-wider">Max Depth</label>
                        <select id="input-max-depth" class="btn-clickable block w-full py-2 px-2.5 bg-cyber-bg border border-cyber-border rounded-lg text-white focus:outline-none focus:border-brand-500 text-xs transition-all">
                            <option value="1">1 (Seed URL Only)</option>
                            <option value="2">2 (Seed + Direct Links)</option>
                            <option value="3">3 (Depth Level 3)</option>
                            <option value="4">4 (Depth Level 4)</option>
                            <option value="5">5 (Depth Level 5)</option>
                            <option value="6">6 (Depth Level 6)</option>
                            <option value="7">7 (Depth Level 7)</option>
                            <option value="8" selected>8 (Full Deep Traversal)</option>
                        </select>
                    </div>
                    <div>
                        <label for="input-max-pages" class="block text-xs font-semibold text-gray-400 mb-1.5 uppercase tracking-wider">Max Pages</label>
                        <input type="number" id="input-max-pages" value="50" min="5" max="2000" class="block w-full py-2 px-2.5 bg-cyber-bg border border-cyber-border rounded-lg text-white focus:outline-none focus:border-brand-500 text-xs text-center font-mono transition-all">
                    </div>
                </div>

                <!-- Action Controls Grid -->
                <div class="pt-3 border-t border-cyber-border space-y-2">
                    <div class="grid grid-cols-2 gap-2">
                        <button id="btn-start" type="button" onclick="handleStartOrResumeClick()" class="btn-clickable bg-brand-500 hover:bg-brand-600 active:scale-95 text-cyber-bg font-bold py-2.5 px-3 rounded-xl flex items-center justify-center gap-1.5 glow-green transition-all shadow-lg text-xs">
                            <span>▶</span>
                            <span id="txt-start-btn">Start Crawl</span>
                        </button>

                        <button id="btn-pause" type="button" onclick="handlePauseClick()" class="btn-clickable bg-amber-500/20 hover:bg-amber-500/30 border border-amber-500/30 text-amber-400 font-bold py-2.5 px-3 rounded-xl flex items-center justify-center gap-1.5 transition-all text-xs">
                            <span>⏸</span>
                            <span id="txt-pause-btn">Pause</span>
                        </button>
                    </div>

                    <button id="btn-stop" type="button" onclick="handleStopClick()" class="btn-clickable w-full bg-rose-500/20 hover:bg-rose-500/30 border border-rose-500/30 text-rose-400 font-bold py-2 px-3 rounded-xl text-xs transition-all flex items-center justify-center gap-2">
                        <span>⏹</span>
                        <span>Stop &amp; Complete Session</span>
                    </button>
                    
                    <button id="btn-reset" type="button" onclick="resetEngine()" class="btn-clickable w-full bg-cyber-bg border border-cyber-border text-gray-400 hover:text-white hover:border-gray-600 py-1.5 px-3 rounded-xl text-[11px] font-semibold transition-all flex items-center justify-center gap-2">
                        <span>🔄</span>
                        Clear Queue Data
                    </button>
                </div>
            </div>

            <!-- Center/Right Stats & Live Mapper -->
            <div class="lg:col-span-2 flex flex-col space-y-6">
                <!-- Stat Banner -->
                <div class="grid grid-cols-2 sm:grid-cols-4 lg:grid-cols-7 gap-2.5">
                    <div class="bg-cyber-card border border-cyber-border rounded-xl p-3 flex items-center space-x-2">
                        <div class="p-1.5 bg-brand-500/10 rounded-lg text-brand-500 text-xs">🔗</div>
                        <div>
                            <span class="text-[9px] text-gray-400 block font-medium uppercase">Audited</span>
                            <span id="stat-scanned" class="text-sm font-bold text-white font-mono">0</span>
                        </div>
                    </div>
                    <div class="bg-cyber-card border border-cyber-border rounded-xl p-3 flex items-center space-x-2">
                        <div class="p-1.5 bg-indigo-500/10 rounded-lg text-indigo-400 text-xs">✉️</div>
                        <div>
                            <span class="text-[9px] text-gray-400 block font-medium uppercase">Total</span>
                            <span id="stat-emails" class="text-sm font-bold text-white font-mono">0</span>
                        </div>
                    </div>
                    <div class="bg-cyber-card border border-cyber-border rounded-xl p-3 flex items-center space-x-2">
                        <div class="p-1.5 bg-emerald-500/10 rounded-lg text-emerald-400 text-xs">✅</div>
                        <div>
                            <span class="text-[9px] text-gray-400 block font-medium uppercase">Unique</span>
                            <span id="stat-unique-emails" class="text-sm font-bold text-emerald-400 font-mono">0</span>
                        </div>
                    </div>
                    <div class="bg-cyber-card border border-cyber-border rounded-xl p-3 flex items-center space-x-2">
                        <div class="p-1.5 bg-cyan-500/10 rounded-lg text-cyan-400 text-xs">📄</div>
                        <div>
                            <span class="text-[9px] text-gray-400 block font-medium uppercase">Docs</span>
                            <span id="stat-docs-parsed" class="text-sm font-bold text-cyan-400 font-mono">0</span>
                        </div>
                    </div>
                    <div class="bg-cyber-card border border-cyber-border rounded-xl p-3 flex items-center space-x-2">
                        <div class="p-1.5 bg-purple-500/10 rounded-lg text-purple-400 text-xs">🖼️</div>
                        <div>
                            <span class="text-[9px] text-gray-400 block font-medium uppercase">OCR</span>
                            <span id="stat-ocr-images" class="text-sm font-bold text-white font-mono">0</span>
                        </div>
                    </div>
                    <div class="bg-cyber-card border border-cyber-border rounded-xl p-3 flex items-center space-x-2">
                        <div class="p-1.5 bg-amber-500/10 rounded-lg text-amber-400 text-xs">⏳</div>
                        <div>
                            <span class="text-[9px] text-gray-400 block font-medium uppercase">Queue</span>
                            <span id="stat-queue" class="text-sm font-bold text-white font-mono">0</span>
                        </div>
                    </div>
                    <div class="bg-cyber-card border border-cyber-border rounded-xl p-3 flex items-center space-x-2">
                        <div class="p-1.5 bg-rose-500/10 rounded-lg text-rose-400 text-xs">⚡</div>
                        <div>
                            <span class="text-[9px] text-gray-400 block font-medium uppercase">Speed</span>
                            <span id="stat-speed" class="text-sm font-bold text-white font-mono">0/s</span>
                        </div>
                    </div>
                </div>

                <!-- Live Network Graph & Canvas Mapper -->
                <div class="bg-cyber-card border border-cyber-border rounded-xl p-4 flex flex-col flex-grow min-h-[280px]">
                    <div class="flex items-center justify-between border-b border-cyber-border pb-3 mb-3">
                        <h3 class="text-xs font-bold text-gray-400 flex items-center gap-2 uppercase tracking-widest">
                            <span class="text-indigo-400">🌐</span>
                            Live Dynamic Domain &amp; OCR Engine Mapper
                        </h3>
                        <span id="system-node-status" class="text-[10px] text-gray-500 font-mono">Engine idle... Ready to parse.</span>
                    </div>
                    <div class="relative w-full flex-grow bg-cyber-bg rounded-lg border border-cyber-border/40 overflow-hidden flex items-center justify-center min-h-[220px]">
                        <canvas id="canvas-network" class="w-full h-full absolute inset-0"></canvas>
                        <div id="canvas-overlay-text" class="text-center p-4 z-10 text-gray-600 pointer-events-none">
                            <span class="text-2xl block mb-1">🕸️</span>
                            <span class="text-xs font-mono">Real-time crawling network nodes will map here dynamically.</span>
                        </div>
                    </div>
                </div>

                <!-- Live Activity Log Console -->
                <div class="bg-cyber-card border border-cyber-border rounded-xl p-4 flex flex-col h-[200px]">
                    <div class="flex items-center justify-between border-b border-cyber-border pb-2 mb-2">
                        <h3 class="text-xs font-bold text-gray-400 flex items-center gap-2 uppercase tracking-widest">
                            <span class="text-brand-500">📟</span>
                            Live Crawl &amp; Metering Ledger
                        </h3>
                        <button type="button" onclick="clearConsoleLog()" class="text-[10px] text-gray-500 hover:text-white font-mono">Clear</button>
                    </div>
                    <div id="log-console-container" class="flex-grow overflow-y-auto font-mono text-[11px] space-y-1 text-gray-300 pr-1">
                        <div class="text-brand-400 font-semibold">[SYSTEM READY] Python Flask WSGI + Monetization layer active.</div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- ================= PANEL 2: EXTRACTED EMAILS ================= -->
    <div id="panel-results" class="hidden space-y-6">
        <div class="bg-cyber-card border border-cyber-border rounded-xl p-5 shadow-xl space-y-4">
            <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 border-b border-cyber-border pb-4">
                <div>
                    <h2 class="text-base font-bold text-white flex items-center gap-2">
                        <span>✉️</span>
                        Extracted Email Records
                    </h2>
                    <p class="text-xs text-gray-400">Scraped unique emails discovered across HTML, PDF, Word documents &amp; OCR images.</p>
                </div>
                <!-- Export Buttons Grid -->
                <div class="flex flex-wrap items-center gap-2">
                    <button type="button" onclick="downloadUniqueAsExcel()" class="btn-clickable px-3 py-1.5 rounded-lg bg-emerald-500/20 text-emerald-400 border border-emerald-500/30 hover:bg-emerald-500/30 text-xs font-bold transition-all flex items-center gap-1.5">
                        <span>📊</span>
                        <span>Export Excel (5 Cr)</span>
                    </button>
                    <button type="button" onclick="downloadUniqueAsCSV()" class="btn-clickable px-3 py-1.5 rounded-lg bg-cyan-500/20 text-cyan-400 border border-cyan-500/30 hover:bg-cyan-500/30 text-xs font-bold transition-all flex items-center gap-1.5">
                        <span>📄</span>
                        <span>Export CSV (5 Cr)</span>
                    </button>
                    <button type="button" onclick="downloadUniqueAsJSON()" class="btn-clickable px-3 py-1.5 rounded-lg bg-indigo-500/20 text-indigo-400 border border-indigo-500/30 hover:bg-indigo-500/30 text-xs font-bold transition-all flex items-center gap-1.5">
                        <span>📦</span>
                        <span>Export JSON (5 Cr)</span>
                    </button>
                </div>
            </div>

            <!-- Table of Extracted Emails -->
            <div class="overflow-x-auto rounded-lg border border-cyber-border">
                <table class="w-full text-left text-xs">
                    <thead class="bg-cyber-bg text-gray-400 uppercase font-mono text-[10px] border-b border-cyber-border">
                        <tr>
                            <th class="py-3 px-4">#</th>
                            <th class="py-3 px-4">Discovered Email</th>
                            <th class="py-3 px-4">Source URL / Document</th>
                            <th class="py-3 px-4">Type</th>
                            <th class="py-3 px-4">Domain Sector</th>
                            <th class="py-3 px-4 text-center">Depth</th>
                        </tr>
                    </thead>
                    <tbody id="emails-tbody" class="divide-y divide-cyber-border/40 font-mono">
                        <tr>
                            <td colspan="6" class="py-8 text-center text-gray-500 font-mono">No emails scraped in this session yet. Launch a crawl to begin extraction.</td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>

    <!-- ================= PANEL 3: CRAWL LOGS & JOBS ================= -->
    <div id="panel-database" class="hidden space-y-6">
        <div class="bg-cyber-card border border-cyber-border rounded-xl p-5 shadow-xl space-y-4">
            <div class="flex items-center justify-between border-b border-cyber-border pb-4">
                <div>
                    <h2 class="text-base font-bold text-white flex items-center gap-2">
                        <span>📊</span>
                        Crawl Path &amp; URL Audit Ledger
                    </h2>
                    <p class="text-xs text-gray-400">Comprehensive history of visited URLs, response codes, eliminated links, and status.</p>
                </div>
            </div>
            <div class="overflow-x-auto rounded-lg border border-cyber-border">
                <table class="w-full text-left text-xs">
                    <thead class="bg-cyber-bg text-gray-400 uppercase font-mono text-[10px] border-b border-cyber-border">
                        <tr>
                            <th class="py-3 px-4">Timestamp</th>
                            <th class="py-3 px-4">Audited URL</th>
                            <th class="py-3 px-4">Type</th>
                            <th class="py-3 px-4">Emails Found</th>
                            <th class="py-3 px-4">Status &amp; Verification</th>
                            <th class="py-3 px-4">Proxy Gateway</th>
                        </tr>
                    </thead>
                    <tbody id="visited-log-tbody" class="divide-y divide-cyber-border/40 font-mono text-gray-300">
                        <tr>
                            <td colspan="6" class="py-8 text-center text-gray-500 font-mono">No URLs audited yet.</td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>

    <!-- ================= PANEL 4: LIVE QUEUE ================= -->
    <div id="panel-queue" class="hidden space-y-6">
        <div class="bg-cyber-card border border-cyber-border rounded-xl p-5 shadow-xl space-y-4">
            <div class="flex items-center justify-between border-b border-cyber-border pb-4">
                <div>
                    <h2 class="text-base font-bold text-white flex items-center gap-2">
                        <span>🔗</span>
                        Live Frontier Queue &amp; URL Inspector
                    </h2>
                    <p class="text-xs text-gray-400">Pending URL tasks queued for parsing and email harvesting.</p>
                </div>
            </div>
            <div class="overflow-x-auto rounded-lg border border-cyber-border">
                <table class="w-full text-left text-xs">
                    <thead class="bg-cyber-bg text-gray-400 uppercase font-mono text-[10px] border-b border-cyber-border">
                        <tr>
                            <th class="py-3 px-4">Priority Depth</th>
                            <th class="py-3 px-4">Queued Target URL</th>
                            <th class="py-3 px-4">Origin Parent</th>
                            <th class="py-3 px-4">Scope</th>
                        </tr>
                    </thead>
                    <tbody id="queue-tbody" class="divide-y divide-cyber-border/40 font-mono text-gray-300">
                        <tr>
                            <td colspan="4" class="py-8 text-center text-gray-500 font-mono">Queue is empty.</td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>

    <!-- ================= PANEL 5: PACKAGE & CREDITS ================= -->
    <div id="panel-billing" class="hidden space-y-6">
        <!-- Billing Hero Grid -->
        <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
            <!-- Available Credits Card -->
            <div class="bg-gradient-to-br from-cyber-card to-cyber-card2 border border-cyber-border rounded-2xl p-5 flex flex-col justify-between shadow-xl relative overflow-hidden">
                <div class="absolute top-0 right-0 p-4 text-amber-500/10 text-6xl select-none font-bold">⚡</div>
                <div>
                    <span class="text-[11px] font-bold text-gray-400 uppercase tracking-wider block mb-1">Total Available Balance</span>
                    <div class="flex items-baseline space-x-2">
                        <span id="bill-card-total-credits" class="text-3xl font-black text-white font-mono">5,750</span>
                        <span class="text-xs text-amber-400 font-bold font-mono">Credits</span>
                    </div>
                </div>
                <div class="mt-4 pt-3 border-t border-cyber-border/60 flex justify-between items-center text-xs font-mono">
                    <span class="text-gray-400">Plan: <span id="bill-card-plan-credits" class="text-brand-400 font-bold">5,000</span></span>
                    <span class="text-gray-400">Top-Up: <span id="bill-card-topup-credits" class="text-amber-400 font-bold">750</span></span>
                </div>
            </div>

            <!-- Active Plan Tier Card -->
            <div class="bg-gradient-to-br from-cyber-card to-cyber-card2 border border-cyber-border rounded-2xl p-5 flex flex-col justify-between shadow-xl relative overflow-hidden">
                <div class="absolute top-0 right-0 p-4 text-brand-500/10 text-6xl select-none font-bold">📦</div>
                <div>
                    <span class="text-[11px] font-bold text-gray-400 uppercase tracking-wider block mb-1">Active Subscription Tier</span>
                    <div class="flex items-center space-x-2">
                        <span id="bill-card-plan-name" class="text-xl font-bold text-brand-400">Loading...</span>
                        <span id="bill-card-plan-price" class="text-xs bg-brand-500/20 text-brand-300 font-mono px-2 py-0.5 rounded font-bold">--</span>
                    </div>
                </div>
                <div class="mt-4 pt-3 border-t border-cyber-border/60 text-xs font-mono text-gray-400">
                    Monthly Allowance: <span id="bill-card-monthly-quota" class="text-white font-bold">5,000 Cr</span>
                </div>
            </div>

            <!-- Renewal Schedule Card -->
            <div class="bg-gradient-to-br from-cyber-card to-cyber-card2 border border-cyber-border rounded-2xl p-5 flex flex-col justify-between shadow-xl relative overflow-hidden">
                <div class="absolute top-0 right-0 p-4 text-cyan-500/10 text-6xl select-none font-bold">🔄</div>
                <div>
                    <span class="text-[11px] font-bold text-gray-400 uppercase tracking-wider block mb-1">Billing Cycle Reset</span>
                    <div class="flex items-baseline space-x-2">
                        <span id="bill-card-days-left" class="text-3xl font-black text-cyan-400 font-mono">18</span>
                        <span class="text-xs text-gray-300">Days Remaining</span>
                    </div>
                </div>
                <div class="mt-4 pt-3 border-t border-cyber-border/60 text-xs font-mono text-gray-400 truncate">
                    Next Reset: <span id="bill-card-next-reset" class="text-white font-semibold">2026-09-01</span>
                </div>
            </div>

            <!-- Action Unit Pricing Cheatsheet -->
            <div class="bg-gradient-to-br from-cyber-card to-cyber-card2 border border-cyber-border rounded-2xl p-4 flex flex-col justify-between shadow-xl">
                <span class="text-[11px] font-bold text-gray-400 uppercase tracking-wider block mb-2">⚡ Action Metering Rates</span>
                <div class="space-y-1 text-[11px] font-mono">
                    <div class="flex justify-between text-gray-300">
                        <span>Web Page Crawl:</span>
                        <span class="text-brand-400 font-bold">1 Credit</span>
                    </div>
                    <div class="flex justify-between text-gray-300">
                        <span>Document Extraction:</span>
                        <span class="text-brand-400 font-bold">2 Credits</span>
                    </div>
                    <div class="flex justify-between text-gray-300">
                        <span>OCR Image Extraction:</span>
                        <span class="text-brand-400 font-bold">3 Credits</span>
                    </div>
                    <div class="flex justify-between text-gray-300">
                        <span>Data Export (Excel/CSV):</span>
                        <span class="text-brand-400 font-bold">5 Credits</span>
                    </div>
                </div>
            </div>
        </div>

        <!-- Personal Transaction History Ledger -->
        <div class="bg-cyber-card border border-cyber-border rounded-2xl p-6 shadow-xl space-y-4">
            <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 border-b border-cyber-border pb-4">
                <div>
                    <h3 class="text-base font-bold text-white flex items-center gap-2">
                        <span>📜</span>
                        Real-Time Credit Consumption Ledger
                    </h3>
                    <p class="text-xs text-gray-400">Detailed transaction breakdown of metered actions, top-ups, and monthly replenishments.</p>
                </div>
                <button type="button" onclick="loadUserTransactions()" class="btn-clickable px-3 py-1.5 rounded-lg bg-cyber-bg hover:bg-gray-800 border border-cyber-border text-xs font-mono text-gray-300 transition-all flex items-center gap-1.5">
                    <span>🔄</span>
                    <span>Refresh Ledger</span>
                </button>
            </div>

            <!-- Transaction Table -->
            <div class="overflow-x-auto rounded-lg border border-cyber-border">
                <table class="w-full text-left text-xs">
                    <thead class="bg-cyber-bg text-gray-400 uppercase font-mono text-[10px] border-b border-cyber-border">
                        <tr>
                            <th class="py-3 px-4">Timestamp (UTC)</th>
                            <th class="py-3 px-4">Action / Event</th>
                            <th class="py-3 px-4">Cost / Delta</th>
                            <th class="py-3 px-4">Plan Balance</th>
                            <th class="py-3 px-4">Top-Up Balance</th>
                            <th class="py-3 px-4">Total After</th>
                            <th class="py-3 px-4">Description / Metadata</th>
                        </tr>
                    </thead>
                    <tbody id="user-tx-tbody" class="divide-y divide-cyber-border/40 font-mono text-gray-300">
                        <tr>
                            <td colspan="7" class="py-8 text-center text-gray-500 font-mono">Loading transaction ledger...</td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>

    <!-- ================= PANEL 6: ADMIN PORTAL ================= -->
    <div id="panel-admin" class="hidden space-y-6">
        <!-- Admin Header & KPI Cards -->
        <div class="bg-gradient-to-r from-purple-900/30 via-cyber-card to-cyber-card border border-purple-500/30 rounded-2xl p-6 shadow-2xl space-y-4">
            <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 border-b border-cyber-border pb-4">
                <div class="flex items-center space-x-3">
                    <div class="p-2.5 bg-purple-500/10 rounded-xl text-purple-400 border border-purple-500/30 glow-purple">
                        <span class="text-2xl">🛡️</span>
                    </div>
                    <div>
                        <div class="flex items-center space-x-2">
                            <span class="text-[10px] font-bold text-purple-400 tracking-wider uppercase bg-purple-500/10 px-2 py-0.5 rounded border border-purple-500/20 font-mono">ADMIN CONTROL HUB</span>
                            <span class="text-xs text-gray-400">Tailored for https://wcpy.ejal.email/</span>
                        </div>
                        <h2 class="text-lg font-bold text-white">Administrative User &amp; Credit Management Console</h2>
                    </div>
                </div>

                <div class="flex items-center space-x-2">
                    <button type="button" onclick="openProvisionUserModal()" class="btn-clickable px-4 py-2 bg-gradient-to-r from-brand-500 to-emerald-600 hover:from-brand-400 hover:to-emerald-500 text-black font-bold text-xs rounded-xl shadow-lg glow-green transition-all flex items-center gap-2">
                        <span>➕</span>
                        <span>Provision New User</span>
                    </button>
                </div>
            </div>

            <!-- Admin KPIs Grid -->
            <div class="grid grid-cols-2 sm:grid-cols-4 gap-4">
                <div class="bg-cyber-bg/80 border border-cyber-border rounded-xl p-4">
                    <span class="text-[10px] font-bold text-gray-400 uppercase tracking-wider block">Total User Accounts</span>
                    <span id="adm-kpi-total-users" class="text-2xl font-black text-white font-mono">--</span>
                    <span class="text-[10px] text-emerald-400 block mt-0.5"><span id="adm-kpi-active-users">--</span> Active</span>
                </div>
                <div class="bg-cyber-bg/80 border border-cyber-border rounded-xl p-4">
                    <span class="text-[10px] font-bold text-gray-400 uppercase tracking-wider block">Credits Consumed (Today)</span>
                    <span id="adm-kpi-credits-today" class="text-2xl font-black text-amber-400 font-mono">--</span>
                    <span class="text-[10px] text-gray-400 block mt-0.5">Real-time meter</span>
                </div>
                <div class="bg-cyber-bg/80 border border-cyber-border rounded-xl p-4">
                    <span class="text-[10px] font-bold text-gray-400 uppercase tracking-wider block">Credits Consumed (Month)</span>
                    <span id="adm-kpi-credits-month" class="text-2xl font-black text-brand-400 font-mono">--</span>
                    <span class="text-[10px] text-gray-400 block mt-0.5">Billing cycle MTD</span>
                </div>
                <div class="bg-cyber-bg/80 border border-cyber-border rounded-xl p-4">
                    <span class="text-[10px] font-bold text-gray-400 uppercase tracking-wider block">Admin Top-Ups Issued</span>
                    <span id="adm-kpi-topups" class="text-2xl font-black text-purple-400 font-mono">--</span>
                    <span class="text-[10px] text-gray-400 block mt-0.5"><span id="adm-kpi-topup-credits">--</span> Cr total</span>
                </div>
            </div>
        </div>

        <!-- Admin Sub-Navigation Tabs -->
        <div class="flex flex-wrap border-b border-cyber-border gap-2">
            <button id="admin-subtab-users" type="button" onclick="switchAdminSubTab('users')" class="btn-clickable px-4 py-2.5 text-xs font-bold border-b-2 border-brand-500 text-brand-500 flex items-center gap-2">
                <span>👥</span>
                <span>User &amp; Account Management</span>
            </button>
            <button id="admin-subtab-packages" type="button" onclick="switchAdminSubTab('packages')" class="btn-clickable px-4 py-2.5 text-xs font-bold border-b-2 border-transparent text-gray-400 hover:text-white flex items-center gap-2">
                <span>📦</span>
                <span>Packages &amp; Custom Plans</span>
            </button>
            <button id="admin-subtab-pricing" type="button" onclick="switchAdminSubTab('pricing')" class="btn-clickable px-4 py-2.5 text-xs font-bold border-b-2 border-transparent text-gray-400 hover:text-white flex items-center gap-2">
                <span>⚙️</span>
                <span>Action Metering Pricing</span>
            </button>
            <button id="admin-subtab-audit" type="button" onclick="switchAdminSubTab('audit')" class="btn-clickable px-4 py-2.5 text-xs font-bold border-b-2 border-transparent text-gray-400 hover:text-white flex items-center gap-2">
                <span>📜</span>
                <span>Immutable Audit Logs</span>
            </button>
        </div>

        <!-- ================= ADMIN SUB-PANEL 1: USER MANAGEMENT ================= -->
        <div id="admin-panel-users" class="space-y-4">
            <!-- Filter Toolbar -->
            <div class="bg-cyber-card border border-cyber-border rounded-xl p-4 flex flex-col sm:flex-row items-center justify-between gap-3">
                <div class="flex flex-wrap items-center gap-2 w-full sm:w-auto">
                    <input type="text" id="adm-filter-search" oninput="loadAdminUsers()" placeholder="Search by email or name..." class="px-3 py-1.5 bg-cyber-bg border border-cyber-border rounded-lg text-xs text-white placeholder-gray-500 focus:outline-none focus:border-brand-500 font-mono w-full sm:w-60">
                    <select id="adm-filter-status" onchange="loadAdminUsers()" class="btn-clickable px-2.5 py-1.5 bg-cyber-bg border border-cyber-border rounded-lg text-xs text-white focus:outline-none focus:border-brand-500 font-mono">
                        <option value="all">All Statuses</option>
                        <option value="active">Active Only</option>
                        <option value="suspended">Suspended Only</option>
                        <option value="terminated">Terminated Only</option>
                    </select>
                    <select id="adm-filter-package" onchange="loadAdminUsers()" class="btn-clickable px-2.5 py-1.5 bg-cyber-bg border border-cyber-border rounded-lg text-xs text-white focus:outline-none focus:border-brand-500 font-mono">
                        <option value="all">All Packages</option>
                        <option value="starter">Starter Tier</option>
                        <option value="pro">Pro Tier</option>
                        <option value="business">Business Tier</option>
                        <option value="custom_enterprise">Custom Enterprise</option>
                    </select>
                </div>
                <button type="button" onclick="loadAdminUsers()" class="btn-clickable px-3 py-1.5 bg-cyber-bg hover:bg-gray-800 border border-cyber-border rounded-lg text-xs font-mono text-gray-300">
                    🔄 Refresh Users
                </button>
            </div>

            <!-- Users Management Table -->
            <div class="bg-cyber-card border border-cyber-border rounded-xl overflow-hidden shadow-xl">
                <div class="overflow-x-auto">
                    <table class="w-full text-left text-xs">
                        <thead class="bg-cyber-bg text-gray-400 uppercase font-mono text-[10px] border-b border-cyber-border">
                            <tr>
                                <th class="py-3 px-4">User</th>
                                <th class="py-3 px-4">Role</th>
                                <th class="py-3 px-4">Assigned Package</th>
                                <th class="py-3 px-4">Total Balance</th>
                                <th class="py-3 px-4">Plan / Top-Up Split</th>
                                <th class="py-3 px-4">Monthly Quota</th>
                                <th class="py-3 px-4">Status</th>
                                <th class="py-3 px-4 text-right">Administrative Actions</th>
                            </tr>
                        </thead>
                        <tbody id="adm-users-tbody" class="divide-y divide-cyber-border/40 font-mono text-gray-300">
                            <tr>
                                <td colspan="8" class="py-8 text-center text-gray-500 font-mono">Loading user directory...</td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>

        <!-- ================= ADMIN SUB-PANEL 2: PACKAGES ================= -->
        <div id="admin-panel-packages" class="hidden space-y-4">
            <div class="flex justify-between items-center bg-cyber-card border border-cyber-border rounded-xl p-4">
                <div>
                    <h3 class="font-bold text-white text-sm">Package Tiers &amp; Entitlement Management</h3>
                    <p class="text-xs text-gray-400">Configure base credits, monthly pricing, feature flags, and custom plans.</p>
                </div>
                <button type="button" onclick="openCreatePackageModal()" class="btn-clickable px-3 py-1.5 bg-brand-500 hover:bg-brand-400 text-black font-bold text-xs rounded-lg transition-all flex items-center gap-1.5">
                    <span>➕</span>
                    <span>Create Custom Plan</span>
                </button>
            </div>

            <div id="adm-packages-grid" class="grid grid-cols-1 md:grid-cols-2 gap-4">
                <!-- Dynamically rendered by JS -->
            </div>
        </div>

        <!-- ================= ADMIN SUB-PANEL 3: ACTION PRICING ================= -->
        <div id="admin-panel-pricing" class="hidden space-y-4">
            <div class="bg-cyber-card border border-cyber-border rounded-xl p-5 shadow-xl space-y-4">
                <div class="flex justify-between items-center border-b border-cyber-border pb-3">
                    <div>
                        <h3 class="font-bold text-white text-sm">Action Unit Pricing &amp; Consumption Metering</h3>
                        <p class="text-xs text-gray-400">Configure credit costs per individual operation executed across the portal.</p>
                    </div>
                </div>
                <div class="overflow-x-auto rounded-lg border border-cyber-border">
                    <table class="w-full text-left text-xs">
                        <thead class="bg-cyber-bg text-gray-400 uppercase font-mono text-[10px] border-b border-cyber-border">
                            <tr>
                                <th class="py-3 px-4">Action Key</th>
                                <th class="py-3 px-4">Display Label</th>
                                <th class="py-3 px-4">Description</th>
                                <th class="py-3 px-4">Credit Cost (Units)</th>
                            </tr>
                        </thead>
                        <tbody id="adm-pricing-tbody" class="divide-y divide-cyber-border/40 font-mono text-gray-300">
                            <!-- Rendered by JS -->
                        </tbody>
                    </table>
                </div>
                <div class="flex justify-end pt-2">
                    <button type="button" onclick="saveAdminPricing()" class="btn-clickable px-4 py-2 bg-brand-500 hover:bg-brand-400 text-black font-bold text-xs rounded-xl shadow-lg glow-green transition-all">
                        Save Pricing Configuration
                    </button>
                </div>
            </div>
        </div>

        <!-- ================= ADMIN SUB-PANEL 4: AUDIT TRAIL ================= -->
        <div id="admin-panel-audit" class="hidden space-y-4">
            <!-- Audit Toolbar -->
            <div class="bg-cyber-card border border-cyber-border rounded-xl p-4 flex flex-col sm:flex-row items-center justify-between gap-3">
                <div class="flex flex-wrap items-center gap-2 w-full sm:w-auto">
                    <input type="text" id="adm-audit-search" oninput="loadAdminAuditLogs()" placeholder="Search logs (admin, user, reason)..." class="px-3 py-1.5 bg-cyber-bg border border-cyber-border rounded-lg text-xs text-white placeholder-gray-500 focus:outline-none focus:border-brand-500 font-mono w-full sm:w-64">
                    <select id="adm-audit-action-filter" onchange="loadAdminAuditLogs()" class="btn-clickable px-2.5 py-1.5 bg-cyber-bg border border-cyber-border rounded-lg text-xs text-white focus:outline-none focus:border-brand-500 font-mono">
                        <option value="all">All Actions</option>
                        <option value="credit_adjustment">Credit Adjustments</option>
                        <option value="status_change">Status Changes</option>
                        <option value="package_change">Package Changes</option>
                        <option value="user_create">User Creations</option>
                    </select>
                </div>
                <button type="button" onclick="exportAuditLogsCSV()" class="btn-clickable px-3 py-1.5 bg-emerald-500/20 text-emerald-400 border border-emerald-500/30 hover:bg-emerald-500/30 text-xs font-bold rounded-lg transition-all flex items-center gap-1.5">
                    <span>📥</span>
                    <span>Export Audit CSV</span>
                </button>
            </div>

            <!-- Immutable Audit Table -->
            <div class="bg-cyber-card border border-cyber-border rounded-xl overflow-hidden shadow-xl">
                <div class="overflow-x-auto">
                    <table class="w-full text-left text-xs">
                        <thead class="bg-cyber-bg text-gray-400 uppercase font-mono text-[10px] border-b border-cyber-border">
                            <tr>
                                <th class="py-3 px-4">Timestamp (UTC)</th>
                                <th class="py-3 px-4">Admin</th>
                                <th class="py-3 px-4">Target User</th>
                                <th class="py-3 px-4">Action</th>
                                <th class="py-3 px-4">Credit Delta</th>
                                <th class="py-3 px-4">Balance Range</th>
                                <th class="py-3 px-4">Mandatory Audit Reason / Note</th>
                                <th class="py-3 px-4">IP</th>
                            </tr>
                        </thead>
                        <tbody id="adm-audit-tbody" class="divide-y divide-cyber-border/40 font-mono text-gray-300">
                            <tr>
                                <td colspan="8" class="py-8 text-center text-gray-500 font-mono">Loading audit trail...</td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</main>

<!-- ================= MODALS & DIALOGS ================= -->

<!-- 1. Authentication / Login Modal -->
<div id="modal-login" class="hidden fixed inset-0 z-50 flex items-center justify-center p-4 modal-backdrop">
    <div class="bg-cyber-card border border-cyber-border rounded-2xl max-w-md w-full p-6 shadow-2xl space-y-4 relative">
        <div class="flex justify-between items-center border-b border-cyber-border pb-3">
            <div class="flex items-center space-x-2">
                <span class="text-brand-500 text-lg font-bold">⚡</span>
                <h3 class="font-bold text-white text-base">Sign In to Extracto Portal</h3>
            </div>
            <button type="button" onclick="closeLoginModal()" class="text-gray-400 hover:text-white font-mono text-lg">&times;</button>
        </div>

        <form id="form-login" onsubmit="submitLoginForm(event)" class="space-y-3">
            <div>
                <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Email Address</label>
                <input type="email" id="login-email" required placeholder="user@ejal.email" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
            </div>
            <div>
                <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Password</label>
                <input type="password" id="login-password" required placeholder="••••••••" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
            </div>

            <div id="login-error-msg" class="hidden p-2 rounded bg-rose-500/20 border border-rose-500/30 text-rose-300 text-xs font-mono"></div>

            <button type="submit" class="btn-clickable w-full py-2.5 bg-brand-500 hover:bg-brand-400 text-black font-bold text-xs rounded-xl shadow-lg glow-green transition-all mt-2">
                Sign In to Account
            </button>
        </form>

        <!-- Dedicated Admin Sign-In Link -->
        <div class="pt-3 border-t border-cyber-border text-center">
            <a href="/admin/login" class="text-xs text-gray-400 hover:text-purple-400 font-mono transition-colors flex items-center justify-center gap-1.5">
                <span>🔐</span>
                <span>Administrator Access Portal &rarr;</span>
            </a>
        </div>
    </div>
</div>

<!-- 1a. Single-Session Conflict Confirmation Modal -->
<div id="modal-session-conflict" class="hidden fixed inset-0 z-50 flex items-center justify-center p-4 modal-backdrop">
    <div class="bg-cyber-card border border-amber-500/40 rounded-2xl max-w-md w-full p-6 shadow-2xl space-y-4 relative">
        <div class="flex justify-between items-center border-b border-cyber-border pb-3">
            <div class="flex items-center space-x-2.5">
                <span class="text-amber-400 text-xl font-bold">⚠️</span>
                <h3 class="font-bold text-white text-base tracking-wide">Active Session Detected</h3>
            </div>
            <button type="button" onclick="cancelSessionConflictModal()" class="text-gray-400 hover:text-white font-mono text-lg">&times;</button>
        </div>

        <div class="py-2 space-y-3">
            <p id="session-conflict-msg" class="text-xs text-gray-200 leading-relaxed font-sans">
                An active session was detected elsewhere. Continuing will log you out of all other sessions.
            </p>
            <div class="p-3 bg-amber-500/10 border border-amber-500/25 rounded-xl text-[11px] font-mono text-amber-300/90 flex items-start gap-2">
                <span class="text-sm">ℹ️</span>
                <span>Single-Session Policy: Continuing terminates previous active sessions across other browsers or devices.</span>
            </div>
        </div>

        <div class="flex items-center justify-end space-x-3 pt-3 border-t border-cyber-border">
            <button type="button" id="btn-conflict-cancel" onclick="cancelSessionConflictModal()" class="btn-clickable px-4 py-2 rounded-xl text-xs font-semibold text-gray-300 hover:text-white bg-cyber-bg border border-cyber-border hover:border-gray-500 transition-all">
                Cancel
            </button>
            <button type="button" id="btn-conflict-continue" onclick="continueSessionConflictModal()" class="btn-clickable px-4 py-2 rounded-xl text-xs font-bold text-black bg-amber-400 hover:bg-amber-300 shadow-lg shadow-amber-500/20 transition-all">
                Continue
            </button>
        </div>
    </div>
</div>

<!-- 1b. Create Custom Package Modal -->
<div id="modal-create-package" class="hidden fixed inset-0 z-50 flex items-center justify-center p-4 modal-backdrop">
    <div class="bg-cyber-card border border-cyber-border rounded-2xl max-w-lg w-full p-6 shadow-2xl space-y-4 relative max-h-[90vh] overflow-y-auto">
        <div class="flex justify-between items-center border-b border-cyber-border pb-3">
            <div class="flex items-center space-x-2">
                <span class="text-brand-500 text-lg font-bold">➕</span>
                <h3 class="font-bold text-white text-base">Create Custom Subscription Package</h3>
            </div>
            <button type="button" onclick="closeCreatePackageModal()" class="text-gray-400 hover:text-white font-mono text-lg">&times;</button>
        </div>

        <form id="form-create-package" onsubmit="submitCreatePackage(event)" class="space-y-3">
            <div class="grid grid-cols-2 gap-3">
                <div>
                    <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Package ID (Slug) *</label>
                    <input type="text" id="pkg-create-id" required placeholder="e.g. custom_agency" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                    <p class="text-[10px] text-gray-500 mt-0.5">Alphanumeric identifier (e.g. custom_vip)</p>
                </div>
                <div>
                    <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Display Name *</label>
                    <input type="text" id="pkg-create-name" required placeholder="e.g. Agency Platinum" oninput="autoSlugPackageId(this.value)" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                </div>
            </div>

            <div class="grid grid-cols-2 gap-3">
                <div>
                    <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Monthly Price ($ USD) *</label>
                    <input type="number" id="pkg-create-price" required step="0.01" min="0" value="149.00" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                </div>
                <div>
                    <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Base Monthly Credits *</label>
                    <input type="number" id="pkg-create-credits" required min="100" value="35000" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                </div>
            </div>

            <div>
                <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Over-Quota Policy</label>
                <select id="pkg-create-policy" class="btn-clickable w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                    <option value="block" selected>Hard Block on Quota Exceeded (Requires Top-Up)</option>
                    <option value="overage">Allow Metered Overage Billing</option>
                </select>
            </div>

            <!-- Feature Limits & Toggles -->
            <div class="p-3 bg-cyber-bg/80 border border-cyber-border rounded-xl space-y-3">
                <span class="text-[11px] font-bold text-gray-300 uppercase tracking-wider block">Entitlements & Feature Limits</span>
                <div class="grid grid-cols-2 gap-3">
                    <div>
                        <label class="block text-[10px] text-gray-400 mb-0.5">Max Crawl Depth</label>
                        <input type="number" id="pkg-create-depth" min="1" max="10" value="8" class="w-full px-2.5 py-1.5 bg-cyber-card border border-cyber-border rounded text-white text-xs font-mono">
                    </div>
                    <div>
                        <label class="block text-[10px] text-gray-400 mb-0.5">Max Pages per Crawl</label>
                        <input type="number" id="pkg-create-pages" min="10" max="50000" value="5000" class="w-full px-2.5 py-1.5 bg-cyber-card border border-cyber-border rounded text-white text-xs font-mono">
                    </div>
                    <div>
                        <label class="block text-[10px] text-gray-400 mb-0.5">Max Concurrency</label>
                        <input type="number" id="pkg-create-concurrency" min="1" max="20" value="5" class="w-full px-2.5 py-1.5 bg-cyber-card border border-cyber-border rounded text-white text-xs font-mono">
                    </div>
                    <div>
                        <label class="block text-[10px] text-gray-400 mb-0.5">Rate Limit (RPM)</label>
                        <input type="number" id="pkg-create-rpm" min="10" max="600" value="150" class="w-full px-2.5 py-1.5 bg-cyber-card border border-cyber-border rounded text-white text-xs font-mono">
                    </div>
                </div>

                <div class="grid grid-cols-2 gap-2 pt-2 border-t border-cyber-border/50 text-xs">
                    <label class="flex items-center space-x-2 text-gray-300 cursor-pointer">
                        <input type="checkbox" id="pkg-create-ocr" checked class="rounded bg-cyber-card border-cyber-border text-brand-500">
                        <span>OCR Scanning</span>
                    </label>
                    <label class="flex items-center space-x-2 text-gray-300 cursor-pointer">
                        <input type="checkbox" id="pkg-create-docs" checked class="rounded bg-cyber-card border-cyber-border text-brand-500">
                        <span>Doc Extraction (PDF/Word)</span>
                    </label>
                    <label class="flex items-center space-x-2 text-gray-300 cursor-pointer">
                        <input type="checkbox" id="pkg-create-google" checked class="rounded bg-cyber-card border-cyber-border text-brand-500">
                        <span>Google Index Check</span>
                    </label>
                    <label class="flex items-center space-x-2 text-gray-300 cursor-pointer">
                        <input type="checkbox" id="pkg-create-export" checked class="rounded bg-cyber-card border-cyber-border text-brand-500">
                        <span>Structured Exports</span>
                    </label>
                </div>
            </div>

            <div>
                <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Audit Reason / Note</label>
                <input type="text" id="pkg-create-reason" placeholder="e.g. Custom tier created for VIP enterprise clients" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs focus:outline-none focus:border-brand-500">
            </div>

            <div class="flex justify-end space-x-2 pt-3 border-t border-cyber-border">
                <button type="button" onclick="closeCreatePackageModal()" class="px-4 py-2 bg-cyber-bg border border-cyber-border text-gray-400 hover:text-white rounded-xl text-xs font-semibold">Cancel</button>
                <button type="submit" class="px-4 py-2 bg-brand-500 hover:bg-brand-400 text-black font-bold rounded-xl text-xs shadow-lg glow-green transition-all">Create Custom Package</button>
            </div>
        </form>
    </div>
</div>

<!-- 1c. Edit Package Modal -->
<div id="modal-edit-package" class="hidden fixed inset-0 z-50 flex items-center justify-center p-4 modal-backdrop">
    <div class="bg-cyber-card border border-cyber-border rounded-2xl max-w-lg w-full p-6 shadow-2xl space-y-4 relative max-h-[90vh] overflow-y-auto">
        <div class="flex justify-between items-center border-b border-cyber-border pb-3">
            <div class="flex items-center space-x-2">
                <span class="text-brand-500 text-lg font-bold">✏️</span>
                <h3 class="font-bold text-white text-base">Edit Subscription Package</h3>
            </div>
            <button type="button" onclick="closeEditPackageModal()" class="text-gray-400 hover:text-white font-mono text-lg">&times;</button>
        </div>

        <form id="form-edit-package" onsubmit="submitEditPackage(event)" class="space-y-3">
            <input type="hidden" id="pkg-edit-is-custom">

            <div class="grid grid-cols-2 gap-3">
                <div>
                    <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Package ID</label>
                    <input type="text" id="pkg-edit-id" readonly class="w-full px-3 py-2 bg-cyber-bg/50 border border-cyber-border rounded-lg text-gray-400 text-xs font-mono">
                </div>
                <div>
                    <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Display Name *</label>
                    <input type="text" id="pkg-edit-name" required class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                </div>
            </div>

            <div class="grid grid-cols-2 gap-3">
                <div>
                    <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Monthly Price ($ USD) *</label>
                    <input type="number" id="pkg-edit-price" required step="0.01" min="0" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                </div>
                <div>
                    <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Base Monthly Credits *</label>
                    <input type="number" id="pkg-edit-credits" required min="100" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                </div>
            </div>

            <div>
                <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Over-Quota Policy</label>
                <select id="pkg-edit-policy" class="btn-clickable w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                    <option value="block">Hard Block on Quota Exceeded (Requires Top-Up)</option>
                    <option value="overage">Allow Metered Overage Billing</option>
                </select>
            </div>

            <!-- Feature Limits & Toggles -->
            <div class="p-3 bg-cyber-bg/80 border border-cyber-border rounded-xl space-y-3">
                <span class="text-[11px] font-bold text-gray-300 uppercase tracking-wider block">Entitlements & Feature Limits</span>
                <div class="grid grid-cols-2 gap-3">
                    <div>
                        <label class="block text-[10px] text-gray-400 mb-0.5">Max Crawl Depth</label>
                        <input type="number" id="pkg-edit-depth" min="1" max="10" class="w-full px-2.5 py-1.5 bg-cyber-card border border-cyber-border rounded text-white text-xs font-mono">
                    </div>
                    <div>
                        <label class="block text-[10px] text-gray-400 mb-0.5">Max Pages per Crawl</label>
                        <input type="number" id="pkg-edit-pages" min="10" max="50000" class="w-full px-2.5 py-1.5 bg-cyber-card border border-cyber-border rounded text-white text-xs font-mono">
                    </div>
                    <div>
                        <label class="block text-[10px] text-gray-400 mb-0.5">Max Concurrency</label>
                        <input type="number" id="pkg-edit-concurrency" min="1" max="20" class="w-full px-2.5 py-1.5 bg-cyber-card border border-cyber-border rounded text-white text-xs font-mono">
                    </div>
                    <div>
                        <label class="block text-[10px] text-gray-400 mb-0.5">Rate Limit (RPM)</label>
                        <input type="number" id="pkg-edit-rpm" min="10" max="600" class="w-full px-2.5 py-1.5 bg-cyber-card border border-cyber-border rounded text-white text-xs font-mono">
                    </div>
                </div>

                <div class="grid grid-cols-2 gap-2 pt-2 border-t border-cyber-border/50 text-xs">
                    <label class="flex items-center space-x-2 text-gray-300 cursor-pointer">
                        <input type="checkbox" id="pkg-edit-ocr" class="rounded bg-cyber-card border-cyber-border text-brand-500">
                        <span>OCR Scanning</span>
                    </label>
                    <label class="flex items-center space-x-2 text-gray-300 cursor-pointer">
                        <input type="checkbox" id="pkg-edit-docs" class="rounded bg-cyber-card border-cyber-border text-brand-500">
                        <span>Doc Extraction (PDF/Word)</span>
                    </label>
                    <label class="flex items-center space-x-2 text-gray-300 cursor-pointer">
                        <input type="checkbox" id="pkg-edit-google" class="rounded bg-cyber-card border-cyber-border text-brand-500">
                        <span>Google Index Check</span>
                    </label>
                    <label class="flex items-center space-x-2 text-gray-300 cursor-pointer">
                        <input type="checkbox" id="pkg-edit-export" class="rounded bg-cyber-card border-cyber-border text-brand-500">
                        <span>Structured Exports</span>
                    </label>
                </div>
            </div>

            <div>
                <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Audit Reason / Note</label>
                <input type="text" id="pkg-edit-reason" placeholder="e.g. Updated quota allocation and monthly pricing" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs focus:outline-none focus:border-brand-500">
            </div>

            <div class="flex justify-end space-x-2 pt-3 border-t border-cyber-border">
                <button type="button" onclick="closeEditPackageModal()" class="px-4 py-2 bg-cyber-bg border border-cyber-border text-gray-400 hover:text-white rounded-xl text-xs font-semibold">Cancel</button>
                <button type="submit" class="px-4 py-2 bg-brand-500 hover:bg-brand-400 text-black font-bold rounded-xl text-xs shadow-lg glow-green transition-all">Save Package Changes</button>
            </div>
        </form>
    </div>
</div>
    </div>
</div>

<!-- 2. Admin User Provisioning Modal -->
<div id="modal-provision-user" class="hidden fixed inset-0 z-50 flex items-center justify-center p-4 modal-backdrop">
    <div class="bg-cyber-card border border-cyber-border rounded-2xl max-w-lg w-full p-6 shadow-2xl space-y-4 relative max-h-[90vh] overflow-y-auto">
        <div class="flex justify-between items-center border-b border-cyber-border pb-3">
            <div class="flex items-center space-x-2">
                <span class="text-brand-500 text-lg font-bold">➕</span>
                <h3 class="font-bold text-white text-base">Provision New User Account</h3>
            </div>
            <button type="button" onclick="closeProvisionUserModal()" class="text-gray-400 hover:text-white font-mono text-lg">&times;</button>
        </div>

        <form id="form-provision-user" onsubmit="submitProvisionUser(event)" class="space-y-3">
            <div class="grid grid-cols-2 gap-3">
                <div>
                    <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Full Name *</label>
                    <input type="text" id="prov-name" required placeholder="John Doe" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                </div>
                <div>
                    <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Email Address *</label>
                    <input type="email" id="prov-email" required placeholder="user@company.com" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                </div>
            </div>

            <div class="grid grid-cols-2 gap-3">
                <div>
                    <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Temporary Password *</label>
                    <input type="password" id="prov-password" required placeholder="Min 8 chars" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                </div>
                <div>
                    <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">User Role</label>
                    <select id="prov-role" class="btn-clickable w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                        <option value="user" selected>Standard User</option>
                        <option value="admin">Administrator</option>
                    </select>
                </div>
            </div>

            <div>
                <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Assigned Subscription Package *</label>
                <select id="prov-package" onchange="updateProvisionPackageDefaults(this.value)" class="btn-clickable w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                    <option value="starter">Starter Tier (1,000 Credits/mo - $19/mo)</option>
                    <option value="pro" selected>Pro Tier (5,000 Credits/mo - $49/mo)</option>
                    <option value="business">Business Tier (20,000 Credits/mo - $129/mo)</option>
                    <option value="custom_enterprise">Custom Enterprise Plan (50,000+ Credits/mo)</option>
                </select>
            </div>

            <div class="grid grid-cols-2 gap-3">
                <div>
                    <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Initial Plan Credits</label>
                    <input type="number" id="prov-initial-recurring" value="5000" min="0" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                </div>
                <div>
                    <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Initial One-Time Top-Up</label>
                    <input type="number" id="prov-initial-topup" value="250" min="0" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                </div>
            </div>

            <div>
                <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Custom Monthly Allocation Override (Optional)</label>
                <input type="number" id="prov-custom-quota" placeholder="Leave empty to use package default" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                <p class="text-[10px] text-gray-500 mt-1">If specified, overrides standard package recurring quota every month.</p>
            </div>

            <div class="flex justify-end space-x-2 pt-3 border-t border-cyber-border">
                <button type="button" onclick="closeProvisionUserModal()" class="px-4 py-2 bg-cyber-bg border border-cyber-border text-gray-400 hover:text-white rounded-xl text-xs font-semibold">Cancel</button>
                <button type="submit" class="px-4 py-2 bg-brand-500 hover:bg-brand-400 text-black font-bold rounded-xl text-xs shadow-lg glow-green transition-all">Provision User Account</button>
            </div>
        </form>
    </div>
</div>

<!-- 3. Admin Credit Top-Up & Balance Adjustment Modal -->
<div id="modal-adjust-credit" class="hidden fixed inset-0 z-50 flex items-center justify-center p-4 modal-backdrop">
    <div class="bg-cyber-card border border-cyber-border rounded-2xl max-w-md w-full p-6 shadow-2xl space-y-4 relative">
        <div class="flex justify-between items-center border-b border-cyber-border pb-3">
            <div class="flex items-center space-x-2">
                <span class="text-amber-400 text-lg font-bold">⚡</span>
                <h3 class="font-bold text-white text-base">Adjust User Credit Balance</h3>
            </div>
            <button type="button" onclick="closeAdjustCreditModal()" class="text-gray-400 hover:text-white font-mono text-lg">&times;</button>
        </div>

        <div class="bg-cyber-bg p-3 rounded-lg border border-cyber-border space-y-1 font-mono text-xs">
            <div class="text-gray-400">Target: <span id="adj-target-email" class="text-white font-bold">user@ejal.email</span></div>
            <div class="flex justify-between text-gray-400 pt-1 border-t border-cyber-border/50">
                <span>Current Plan: <span id="adj-curr-plan" class="text-brand-400">0</span></span>
                <span>Top-Up: <span id="adj-curr-topup" class="text-amber-400">0</span></span>
                <span>Total: <span id="adj-curr-total" class="text-white font-bold">0</span></span>
            </div>
        </div>

        <form id="form-adjust-credit" onsubmit="submitCreditAdjustment(event)" class="space-y-3">
            <input type="hidden" id="adj-user-id">

            <div>
                <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Adjustment Type *</label>
                <select id="adj-type" class="btn-clickable w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                    <option value="topup_add" selected>➕ Add Top-Up Credits (Carry-Over Balance)</option>
                    <option value="topup_deduct">➖ Deduct Top-Up Credits</option>
                    <option value="recurring_add">➕ Add Plan Recurring Credits</option>
                    <option value="recurring_deduct">➖ Deduct Plan Recurring Credits</option>
                    <option value="recurring_set">🎯 Set Exact Plan Credits</option>
                </select>
            </div>

            <div>
                <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Credit Amount *</label>
                <input type="number" id="adj-amount" required min="1" placeholder="e.g. 500" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
            </div>

            <div>
                <label class="block text-xs font-semibold text-amber-300 uppercase tracking-wider mb-1">Mandatory Audit Reason / Note *</label>
                <textarea id="adj-reason" required rows="2" placeholder="e.g. Invoice #1042 manual top-up payment received or Goodwill compensation" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs focus:outline-none focus:border-amber-500"></textarea>
                <p class="text-[10px] text-gray-400 mt-1">This note is recorded permanently in the immutable audit trail.</p>
            </div>

            <div class="flex justify-end space-x-2 pt-3 border-t border-cyber-border">
                <button type="button" onclick="closeAdjustCreditModal()" class="px-4 py-2 bg-cyber-bg border border-cyber-border text-gray-400 hover:text-white rounded-xl text-xs font-semibold">Cancel</button>
                <button type="submit" class="px-4 py-2 bg-amber-500 hover:bg-amber-400 text-black font-bold rounded-xl text-xs shadow-lg glow-amber transition-all">Apply Balance Adjustment</button>
            </div>
        </form>
    </div>
</div>

<!-- 4. Admin Edit User Plan & Status Modal -->
<div id="modal-edit-user" class="hidden fixed inset-0 z-50 flex items-center justify-center p-4 modal-backdrop">
    <div class="bg-cyber-card border border-cyber-border rounded-2xl max-w-md w-full p-6 shadow-2xl space-y-4 relative">
        <div class="flex justify-between items-center border-b border-cyber-border pb-3">
            <div class="flex items-center space-x-2">
                <span class="text-brand-500 text-lg font-bold">✏️</span>
                <h3 class="font-bold text-white text-base">Edit User Subscription &amp; Status</h3>
            </div>
            <button type="button" onclick="closeEditUserModal()" class="text-gray-400 hover:text-white font-mono text-lg">&times;</button>
        </div>

        <form id="form-edit-user" onsubmit="submitEditUser(event)" class="space-y-3">
            <input type="hidden" id="edit-user-id">

            <div>
                <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Target User</label>
                <input type="text" id="edit-user-email-display" readonly class="w-full px-3 py-2 bg-cyber-bg/50 border border-cyber-border rounded-lg text-gray-400 text-xs font-mono">
            </div>

            <div>
                <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Account Status</label>
                <select id="edit-user-status" class="btn-clickable w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                    <option value="active">ACTIVE (Normal Operation)</option>
                    <option value="suspended">SUSPENDED (Halt All Processing)</option>
                    <option value="terminated">TERMINATED (Closed Account)</option>
                </select>
            </div>

            <div>
                <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Assigned Package Tier</label>
                <select id="edit-user-package" class="btn-clickable w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
                    <option value="starter">Starter Tier</option>
                    <option value="pro">Pro Tier</option>
                    <option value="business">Business Tier</option>
                    <option value="custom_enterprise">Custom Enterprise Plan</option>
                </select>
            </div>

            <div>
                <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Custom Monthly Recurring Allocation</label>
                <input type="number" id="edit-user-custom-quota" placeholder="Leave empty for package base" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs font-mono focus:outline-none focus:border-brand-500">
            </div>

            <div>
                <label class="block text-xs font-semibold text-gray-300 uppercase tracking-wider mb-1">Audit Reason / Note</label>
                <input type="text" id="edit-user-reason" placeholder="e.g. Plan upgrade requested by customer" class="w-full px-3 py-2 bg-cyber-bg border border-cyber-border rounded-lg text-white text-xs focus:outline-none focus:border-brand-500">
            </div>

            <div class="flex justify-end space-x-2 pt-3 border-t border-cyber-border">
                <button type="button" onclick="closeEditUserModal()" class="px-4 py-2 bg-cyber-bg border border-cyber-border text-gray-400 hover:text-white rounded-xl text-xs font-semibold">Cancel</button>
                <button type="submit" class="px-4 py-2 bg-brand-500 hover:bg-brand-400 text-black font-bold rounded-xl text-xs shadow-lg glow-green transition-all">Save Changes</button>
            </div>
        </form>
    </div>
</div>

<!-- 5. Out of Credits / Quota Exhausted Modal -->
<div id="modal-out-of-credits" class="hidden fixed inset-0 z-50 flex items-center justify-center p-4 modal-backdrop">
    <div class="bg-cyber-card border-2 border-rose-500/50 rounded-2xl max-w-md w-full p-6 shadow-2xl space-y-4 text-center">
        <div class="w-12 h-12 rounded-full bg-rose-500/20 text-rose-400 border border-rose-500/40 flex items-center justify-center text-2xl mx-auto">
            🚫
        </div>
        <div>
            <h3 class="font-bold text-white text-base">Credit Quota Exhausted</h3>
            <p class="text-xs text-gray-400 mt-1">Your available credit balance is 0 or insufficient for the requested action.</p>
        </div>
        <div class="bg-cyber-bg p-3 rounded-lg border border-cyber-border text-xs font-mono text-gray-300 text-left space-y-1">
            <div>Next Billing Renewal: <span id="ooc-reset-date" class="text-brand-400 font-bold">2026-09-01</span></div>
            <div>Action Required: <span class="text-amber-400">Contact admin for top-up or upgrade package tier</span></div>
        </div>
        <div class="flex justify-center gap-2 pt-2">
            <button type="button" onclick="document.getElementById('modal-out-of-credits').classList.add('hidden')" class="px-4 py-2 bg-cyber-bg border border-cyber-border text-gray-400 hover:text-white rounded-xl text-xs font-semibold">Dismiss</button>
            <button type="button" onclick="document.getElementById('modal-out-of-credits').classList.add('hidden'); switchTab('billing');" class="px-4 py-2 bg-brand-500 hover:bg-brand-400 text-black font-bold rounded-xl text-xs glow-green transition-all">View Package &amp; Credits</button>
        </div>
    </div>
</div>

<script>
    // ================= CLIENT-SIDE STATE & AUTH ENGINE =================
    const authState = {
        token: localStorage.getItem('wcpy_token') || '',
        user: null,
        creditSummary: null,
        isAdmin: false
    };

    const crawlerState = {
        isCrawling: false,
        isPaused: false,
        scannedPagesCount: 0,
        emailsFoundCount: 0,
        docsParsedCount: 0,
        ocrImagesCount: 0,
        maxDepth: 8,
        maxPages: 50,
        delay: 1200,
        scope: 'internal',
        pdfOnly: false,
        traversalMode: 'dfs',
        filterPattern: '',
        ocrEnabled: true,
        docsEnabled: true,
        docOnlyMode: false,
        googleIndexFilter: true,
        deadLinkFilter: true,
        currentSessionId: 'session_default',
        currentSessionName: 'Session 1',
        currentSessionStatus: 'ready',
        creditsUsed: 0,
        primary_queue: [],
        visited_urls: new Set(),
        broken_urls: new Set(),
        scrapedEmailsList: [],
        visitedLog: [],
        networkNodes: [],
        speedIntervalId: null,
        autoSaveTimeout: null,
        startTime: null
    };

    const sessionsStore = {
        activeSessionId: 'session_default',
        sessions: {}
    };

    // ================= INITIALIZATION & AUTH LIFECYCLE =================
    window.addEventListener('DOMContentLoaded', async () => {
        initSessions();
        initCanvasNetwork();
        await autoLoginOrCheckAuth();
        await pingPythonBackend();

        // Auto-save session state if browser closes, hides or refreshes
        window.addEventListener('beforeunload', () => {
            autoSaveSession();
        });
        document.addEventListener('visibilitychange', () => {
            if (document.visibilityState === 'hidden') {
                autoSaveSession();
            }
        });

        // Single-session enforcement heartbeat (checks every 20 seconds)
        setInterval(() => {
            if (authState.token) {
                refreshLiveCreditBalance();
            }
        }, 20000);

        // Synchronize token across multiple browser tabs
        window.addEventListener('storage', (e) => {
            if (e.key === 'wcpy_token') {
                if (!e.newValue && authState.token) {
                    authState.token = '';
                    authState.user = null;
                    openLoginModal();
                    showLoginError('Your session was ended in another tab.');
                } else if (e.newValue && e.newValue !== authState.token) {
                    authState.token = e.newValue;
                    autoLoginOrCheckAuth();
                }
            }
        });
    });

    async function autoLoginOrCheckAuth() {
        if (!authState.token) {
            openLoginModal();
            return;
        }

        try {
            const res = await fetch('?api=auth_me', {
                headers: { 'Authorization': `Bearer ${authState.token}` }
            });
            if (res.ok) {
                const data = await res.json();
                applyAuthSession(data.user, data.credit_summary, authState.token);
            } else {
                localStorage.removeItem('wcpy_token');
                authState.token = '';
                openLoginModal();
            }
        } catch(e) {
            console.warn('Auth verification fallback:', e);
            openLoginModal();
        }
    }

    async function performLogin(email, password, force = false) {
        try {
            const currentTok = authState.token || localStorage.getItem('wcpy_token') || '';
            const res = await fetch('?api=auth_login', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ email, password, force, current_token: currentTok })
            });
            const data = await res.json();
            if (res.status === 409 || data.session_conflict) {
                openSessionConflictModal(email, password, data.error || "An active session was detected elsewhere. Continuing will log you out of all other sessions.");
                return false;
            }
            if (data.ok) {
                localStorage.setItem('wcpy_token', data.token);
                applyAuthSession(data.user, data.credit_summary, data.token);
                closeLoginModal();
                cancelSessionConflictModal();
                logToConsole(`Signed in as ${data.user.name} (${data.user.email}) - [${data.user.package_name || 'Standard'}]`, 'success');
                return true;
            } else {
                showLoginError(data.error || 'Authentication failed');
                return false;
            }
        } catch(e) {
            showLoginError(e.message || 'Network error during login');
            return false;
        }
    }

    function applyAuthSession(user, creditSummary, token) {
        authState.user = user;
        authState.creditSummary = creditSummary;
        authState.token = token;
        authState.isAdmin = (user && user.role === 'admin');

        // Update Header & Dropdown UI
        const nameEl = document.getElementById('user-display-name');
        const initialsEl = document.getElementById('user-avatar-initials');
        const ddName = document.getElementById('dd-user-name');
        const ddEmail = document.getElementById('dd-user-email');
        const ddRole = document.getElementById('dd-user-role');
        const ddStatus = document.getElementById('dd-user-status');
        const adminTab = document.getElementById('tab-admin');
        const ddAdminBtn = document.getElementById('dd-btn-admin-panel');

        if (nameEl) nameEl.textContent = user.name.split(' ')[0] || user.name;
        if (initialsEl) initialsEl.textContent = (user.name || 'U').substring(0, 2).toUpperCase();
        if (ddName) ddName.textContent = user.name;
        if (ddEmail) ddEmail.textContent = user.email;
        if (ddRole) ddRole.textContent = user.role.toUpperCase();
        if (ddStatus) ddStatus.textContent = user.status.toUpperCase();

        if (adminTab) adminTab.style.display = authState.isAdmin ? 'flex' : 'none';
        if (ddAdminBtn) ddAdminBtn.style.display = authState.isAdmin ? 'flex' : 'none';

        updateCreditCounters(creditSummary);
        loadSessionsFromBackend();
        if (authState.isAdmin) {
            loadAdminStats();
        }
    }

    function updateCreditCounters(summary) {
        if (!summary) return;
        authState.creditSummary = summary;

        const totalAvailable = summary.total_available_credits || (summary.recurring_credits + summary.topup_credits);
        
        // Header widget
        const hdrPlan = document.getElementById('hdr-plan-badge');
        const hdrTotal = document.getElementById('hdr-total-credits');
        if (hdrPlan) hdrPlan.textContent = summary.package_name ? summary.package_name.toUpperCase() : 'STANDARD';
        if (hdrTotal) hdrTotal.textContent = totalAvailable.toLocaleString();

        // Dropdown widget
        const ddPlan = document.getElementById('dd-plan-credits');
        const ddTopup = document.getElementById('dd-topup-credits');
        const ddTotal = document.getElementById('dd-total-credits');
        if (ddPlan) ddPlan.textContent = (summary.recurring_credits || 0).toLocaleString();
        if (ddTopup) ddTopup.textContent = (summary.topup_credits || 0).toLocaleString();
        if (ddTotal) ddTotal.textContent = `${totalAvailable.toLocaleString()} Cr`;

        // Billing page cards
        const billTotal = document.getElementById('bill-card-total-credits');
        const billPlanCr = document.getElementById('bill-card-plan-credits');
        const billTopupCr = document.getElementById('bill-card-topup-credits');
        const billPlanName = document.getElementById('bill-card-plan-name');
        const billPlanPrice = document.getElementById('bill-card-plan-price');
        const billQuota = document.getElementById('bill-card-monthly-quota');
        const billDaysLeft = document.getElementById('bill-card-days-left');
        const billNextReset = document.getElementById('bill-card-next-reset');
        const bannerLow = document.getElementById('banner-low-balance');

        if (billTotal) billTotal.textContent = totalAvailable.toLocaleString();
        if (billPlanCr) billPlanCr.textContent = (summary.recurring_credits || 0).toLocaleString();
        if (billTopupCr) billTopupCr.textContent = (summary.topup_credits || 0).toLocaleString();
        if (billPlanName) billPlanName.textContent = summary.package_name || 'Standard Plan';
        if (billPlanPrice) {
            const rawPrice = (summary.price_monthly !== undefined && summary.price_monthly !== null)
                ? summary.price_monthly
                : (authState.user && authState.user.price_monthly !== undefined ? authState.user.price_monthly : null);
            if (rawPrice !== null && rawPrice !== undefined) {
                billPlanPrice.textContent = `$${Number(rawPrice).toFixed(2)}/mo`;
            }
        }
        if (billQuota) billQuota.textContent = `${(summary.monthly_quota || 1000).toLocaleString()} Cr`;
        if (billDaysLeft) billDaysLeft.textContent = summary.days_until_reset !== undefined ? summary.days_until_reset : '--';
        if (billNextReset && summary.next_reset_iso) billNextReset.textContent = summary.next_reset_iso.split('T')[0];

        // Low balance banner
        if (bannerLow) {
            if (summary.is_low_balance || totalAvailable <= 50) {
                bannerLow.classList.remove('hidden');
            } else {
                bannerLow.classList.add('hidden');
            }
        }
    }

    async function refreshLiveCreditBalance() {
        if (!authState.token) return;
        try {
            const res = await fetch('?api=credit_balance', {
                headers: { 'Authorization': `Bearer ${authState.token}` }
            });
            if (res.ok) {
                const data = await res.json();
                updateCreditCounters(data.credit_summary);
            } else if (res.status === 401) {
                localStorage.removeItem('wcpy_token');
                authState.token = '';
                authState.user = null;
                openLoginModal();
                showLoginError('Your session was terminated because your account was logged in elsewhere.');
            }
        } catch(e) {}
    }

    // ================= TAB NAVIGATION =================
    function switchTab(tabId) {
        const tabs = ['dashboard', 'results', 'database', 'queue', 'billing', 'admin'];
        tabs.forEach(t => {
            const btn = document.getElementById(`tab-${t}`);
            const panel = document.getElementById(`panel-${t}`);
            if (!btn || !panel) return;
            if (t === tabId) {
                btn.classList.add('border-brand-500', 'text-brand-500');
                btn.classList.remove('border-transparent', 'text-gray-400');
                panel.classList.remove('hidden');
            } else {
                btn.classList.remove('border-brand-500', 'text-brand-500');
                btn.classList.add('border-transparent', 'text-gray-400');
                panel.classList.add('hidden');
            }
        });

        if (tabId === 'billing') {
            loadUserTransactions();
            refreshLiveCreditBalance();
        } else if (tabId === 'admin' && authState.isAdmin) {
            loadAdminUsers();
            loadAdminStats();
        }

        try {
            if (window.lucide && lucide.createIcons) lucide.createIcons();
        } catch(e) {}
    }

    function switchAdminSubTab(subTabId) {
        const subTabs = ['users', 'packages', 'pricing', 'audit'];
        subTabs.forEach(st => {
            const btn = document.getElementById(`admin-subtab-${st}`);
            const panel = document.getElementById(`admin-panel-${st}`);
            if (!btn || !panel) return;
            if (st === subTabId) {
                btn.classList.add('border-brand-500', 'text-brand-500');
                btn.classList.remove('border-transparent', 'text-gray-400');
                panel.classList.remove('hidden');
            } else {
                btn.classList.remove('border-brand-500', 'text-brand-500');
                btn.classList.add('border-transparent', 'text-gray-400');
                panel.classList.add('hidden');
            }
        });

        if (subTabId === 'users') loadAdminUsers();
        else if (subTabId === 'packages') loadAdminPackages();
        else if (subTabId === 'pricing') loadAdminPricing();
        else if (subTabId === 'audit') loadAdminAuditLogs();
    }

    function toggleUserDropdown() {
        const dd = document.getElementById('user-dropdown-menu');
        if (dd) dd.classList.toggle('hidden');
    }

    // ================= USER TRANSACTIONS LEDGER =================
    async function loadUserTransactions() {
        const tbody = document.getElementById('user-tx-tbody');
        if (!tbody || !authState.token) return;

        try {
            const res = await fetch('?api=user_transactions&limit=25', {
                headers: { 'Authorization': `Bearer ${authState.token}` }
            });
            if (!res.ok) return;
            const data = await res.json();
            const txs = data.transactions || [];

            if (txs.length === 0) {
                tbody.innerHTML = '<tr><td colspan="7" class="py-8 text-center text-gray-500 font-mono">No transactions recorded yet in this account.</td></tr>';
                return;
            }

            let html = '';
            txs.forEach(tx => {
                const isDeduction = tx.credits_deducted > 0;
                const deltaStr = isDeduction ? `-${tx.credits_deducted}` : `+${Math.abs(tx.credits_deducted)}`;
                const deltaClass = isDeduction ? 'text-rose-400' : 'text-emerald-400 font-bold';
                const timeStr = tx.created_at.replace('T', ' ').substring(0, 19);

                html += `
                    <tr class="hover:bg-cyber-card/60 border-b border-cyber-border/20">
                        <td class="py-2.5 px-4 text-gray-400">${timeStr}</td>
                        <td class="py-2.5 px-4"><span class="px-2 py-0.5 rounded text-[10px] font-bold bg-cyber-bg border border-cyber-border text-brand-400">${tx.action_type}</span></td>
                        <td class="py-2.5 px-4 ${deltaClass}">${deltaStr} Cr</td>
                        <td class="py-2.5 px-4 text-gray-300">${tx.recurring_credits_after.toLocaleString()}</td>
                        <td class="py-2.5 px-4 text-amber-400">${tx.topup_credits_after.toLocaleString()}</td>
                        <td class="py-2.5 px-4 font-bold text-white">${(tx.recurring_credits_after + tx.topup_credits_after).toLocaleString()} Cr</td>
                        <td class="py-2.5 px-4 text-gray-400 text-[11px] truncate max-w-xs">${tx.description || '-'}</td>
                    </tr>
                `;
            });
            tbody.innerHTML = html;
        } catch(e) {
            console.warn('Failed to load transactions:', e);
        }
    }

    // ================= ADMIN CONSOLE API LOADERS =================
    async function loadAdminStats() {
        if (!authState.isAdmin) return;
        try {
            const res = await fetch('?api=admin_stats', {
                headers: { 'Authorization': `Bearer ${authState.token}` }
            });
            if (!res.ok) return;
            const data = await res.json();
            const stats = data.stats;

            const uEl = document.getElementById('adm-kpi-total-users');
            const actEl = document.getElementById('adm-kpi-active-users');
            const cdEl = document.getElementById('adm-kpi-credits-today');
            const cmEl = document.getElementById('adm-kpi-credits-month');
            const tEl = document.getElementById('adm-kpi-topups');
            const tcEl = document.getElementById('adm-kpi-topup-credits');

            if (uEl) uEl.textContent = stats.total_users;
            if (actEl) actEl.textContent = stats.active_users;
            if (cdEl) cdEl.textContent = stats.credits_consumed_today.toLocaleString();
            if (cmEl) cmEl.textContent = stats.credits_consumed_month.toLocaleString();
            if (tEl) tEl.textContent = stats.total_topup_grants;
            if (tcEl) tcEl.textContent = stats.total_topup_credits_issued.toLocaleString();
        } catch(e) {}
    }

    async function loadAdminUsers() {
        if (!authState.isAdmin) return;
        const tbody = document.getElementById('adm-users-tbody');
        if (!tbody) return;

        const search = document.getElementById('adm-filter-search')?.value || '';
        const status = document.getElementById('adm-filter-status')?.value || 'all';
        const pkg = document.getElementById('adm-filter-package')?.value || 'all';

        try {
            const res = await fetch(`?api=admin_users&search=${encodeURIComponent(search)}&status=${encodeURIComponent(status)}&package_id=${encodeURIComponent(pkg)}`, {
                headers: { 'Authorization': `Bearer ${authState.token}` }
            });
            if (!res.ok) return;
            const data = await res.json();
            const users = data.users || [];

            if (users.length === 0) {
                tbody.innerHTML = '<tr><td colspan="8" class="py-8 text-center text-gray-500 font-mono">No matching users found.</td></tr>';
                return;
            }

            let html = '';
            users.forEach(u => {
                let statusBadge = '<span class="px-2 py-0.5 rounded text-[10px] font-bold bg-emerald-500/20 text-emerald-400 border border-emerald-500/30">ACTIVE</span>';
                if (u.status === 'suspended') statusBadge = '<span class="px-2 py-0.5 rounded text-[10px] font-bold bg-amber-500/20 text-amber-400 border border-amber-500/30">SUSPENDED</span>';
                else if (u.status === 'terminated') statusBadge = '<span class="px-2 py-0.5 rounded text-[10px] font-bold bg-rose-500/20 text-rose-400 border border-rose-500/30">TERMINATED</span>';

                const roleBadge = u.role === 'admin' ? '<span class="px-1.5 py-0.5 rounded text-[9px] font-bold bg-purple-500/20 text-purple-300 border border-purple-500/30">ADMIN</span>' : '<span class="text-gray-500 text-[10px]">USER</span>';

                html += `
                    <tr class="hover:bg-cyber-card/60 border-b border-cyber-border/20">
                        <td class="py-3 px-4">
                            <div class="font-bold text-white">${u.name}</div>
                            <div class="text-gray-400 text-[11px] font-mono">${u.email}</div>
                        </td>
                        <td class="py-3 px-4">${roleBadge}</td>
                        <td class="py-3 px-4">
                            <span class="font-bold text-brand-400">${u.package_name || u.package_id}</span>
                        </td>
                        <td class="py-3 px-4 font-bold text-white font-mono text-sm">${u.total_credits.toLocaleString()} Cr</td>
                        <td class="py-3 px-4 text-xs font-mono">
                            <span class="text-brand-400">${u.recurring_credits.toLocaleString()}</span> / <span class="text-amber-400">${u.topup_credits.toLocaleString()}</span>
                        </td>
                        <td class="py-3 px-4 text-gray-300 font-mono">${(u.effective_monthly_quota || 0).toLocaleString()} Cr/mo</td>
                        <td class="py-3 px-4">${statusBadge}</td>
                        <td class="py-3 px-4 text-right space-x-1.5">
                            <button type="button" onclick="openAdjustCreditModal(${u.id}, '${u.email}', ${u.recurring_credits}, ${u.topup_credits})" class="btn-clickable px-2.5 py-1 bg-amber-500/20 hover:bg-amber-500/30 text-amber-400 border border-amber-500/30 rounded text-[11px] font-bold transition-all" title="Adjust or Top-Up Credits">⚡ Top-Up</button>
                            <button type="button" onclick="openEditUserModal(${u.id}, '${u.email}', '${u.package_id}', '${u.status}', ${u.custom_monthly_quota || 'null'})" class="btn-clickable px-2.5 py-1 bg-cyber-bg hover:bg-gray-800 text-gray-300 border border-cyber-border rounded text-[11px] font-bold transition-all" title="Edit Plan & Status">✏️ Edit</button>
                            <button type="button" onclick="adminResetBillingCycle(${u.id}, '${u.email}')" class="btn-clickable px-2 py-1 bg-cyan-500/10 hover:bg-cyan-500/20 text-cyan-400 border border-cyan-500/30 rounded text-[11px] font-bold transition-all" title="Force Reset Monthly Quota">🔄</button>
                        </td>
                    </tr>
                `;
            });
            tbody.innerHTML = html;
        } catch(e) {}
    }

    let adminPackagesCache = [];

    async function loadAdminPackages() {
        if (!authState.isAdmin) return;
        const container = document.getElementById('adm-packages-grid');
        if (!container) return;

        try {
            const res = await fetch('?api=admin_packages', {
                headers: { 'Authorization': `Bearer ${authState.token}` }
            });
            if (!res.ok) return;
            const data = await res.json();
            const pkgs = data.packages || [];
            adminPackagesCache = pkgs;

            syncPackageDropdowns(pkgs);

            let html = '';
            pkgs.forEach(p => {
                const feat = p.features || {};
                const isCustom = Boolean(p.is_custom);
                const userCount = p.user_count || 0;
                const policyBadge = p.over_quota_policy === 'overage'
                    ? '<span class="px-1.5 py-0.5 rounded text-[9px] font-bold bg-indigo-500/20 text-indigo-300 border border-indigo-500/30 font-mono uppercase">OVERAGE ALLOWED</span>'
                    : '<span class="px-1.5 py-0.5 rounded text-[9px] font-bold bg-rose-500/20 text-rose-300 border border-rose-500/30 font-mono uppercase">HARD BLOCK</span>';
                const customBadge = isCustom
                    ? '<span class="px-1.5 py-0.5 rounded text-[9px] font-bold bg-amber-500/20 text-amber-300 border border-amber-500/30 font-mono uppercase">CUSTOM PLAN</span>'
                    : '<span class="px-1.5 py-0.5 rounded text-[9px] font-bold bg-blue-500/20 text-blue-300 border border-blue-500/30 font-mono uppercase">SYSTEM TIER</span>';

                html += `
                    <div class="bg-cyber-card border border-cyber-border rounded-xl p-5 shadow-xl flex flex-col justify-between space-y-4 hover:border-cyber-borderLight transition-all">
                        <div>
                            <div class="flex justify-between items-start">
                                <div>
                                    <div class="flex items-center gap-2">
                                        <h4 class="font-bold text-white text-base">${p.name}</h4>
                                        ${customBadge}
                                    </div>
                                    <span class="text-[10px] font-mono text-gray-400">ID: ${p.id}</span>
                                </div>
                                <div class="text-right">
                                    <span class="px-2 py-0.5 rounded text-xs font-mono font-bold bg-brand-500/20 text-brand-300 border border-brand-500/30">$${p.price_monthly.toFixed(2)}/mo</span>
                                </div>
                            </div>

                            <div class="mt-3 flex items-baseline justify-between border-b border-cyber-border/40 pb-2.5">
                                <div class="text-2xl font-black text-brand-400 font-mono">${p.base_monthly_credits.toLocaleString()} <span class="text-xs text-gray-400 font-normal font-sans">Base Credits</span></div>
                                <div class="text-[11px] font-mono text-gray-400">
                                    Assigned Users: <span class="font-bold ${userCount > 0 ? 'text-cyan-400' : 'text-gray-500'}">${userCount}</span>
                                </div>
                            </div>

                            <div class="mt-2.5 flex items-center gap-2">
                                ${policyBadge}
                            </div>

                            <div class="mt-3 grid grid-cols-2 gap-2 text-xs font-mono text-gray-300 bg-cyber-bg/50 p-2.5 rounded-lg border border-cyber-border/50">
                                <div>Max Depth: <span class="text-white font-bold">${feat.max_depth || 3}</span></div>
                                <div>Max Pages: <span class="text-white font-bold">${feat.max_pages || 100}</span></div>
                                <div>Concurrency: <span class="text-white font-bold">${feat.max_concurrency || 1}</span></div>
                                <div>Rate Limit: <span class="text-white font-bold">${feat.rate_limit_rpm || 30} RPM</span></div>
                                <div>OCR Scanning: <span class="${feat.allow_ocr ? 'text-emerald-400' : 'text-gray-500'} font-bold">${feat.allow_ocr ? 'YES' : 'NO'}</span></div>
                                <div>Doc Parsing: <span class="${feat.allow_docs ? 'text-emerald-400' : 'text-gray-500'} font-bold">${feat.allow_docs ? 'YES' : 'NO'}</span></div>
                                <div>Google SERP: <span class="${feat.allow_google_index ? 'text-emerald-400' : 'text-gray-500'} font-bold">${feat.allow_google_index ? 'YES' : 'NO'}</span></div>
                                <div>Data Export: <span class="${feat.allow_export ? 'text-emerald-400' : 'text-gray-500'} font-bold">${feat.allow_export ? 'YES' : 'NO'}</span></div>
                            </div>
                        </div>

                        <div class="flex items-center justify-end gap-2 pt-2 border-t border-cyber-border">
                            <button type="button" onclick="openEditPackageModal('${p.id}')" class="btn-clickable px-3 py-1.5 bg-cyber-bg hover:bg-gray-800 border border-cyber-border text-gray-200 hover:text-white rounded-lg text-xs font-bold transition-all flex items-center gap-1.5">
                                <span>✏️</span>
                                <span>Edit</span>
                            </button>
                            <button type="button" onclick="deletePackagePrompt('${p.id}', '${p.name.replace(/'/g, "\\'")}', ${userCount})" class="btn-clickable px-3 py-1.5 bg-rose-500/10 hover:bg-rose-500/20 border border-rose-500/30 text-rose-400 rounded-lg text-xs font-bold transition-all flex items-center gap-1.5">
                                <span>🗑️</span>
                                <span>Delete</span>
                            </button>
                        </div>
                    </div>
                `;
            });
            container.innerHTML = html || '<div class="col-span-2 py-8 text-center text-gray-500 font-mono">No packages defined. Click "Create Custom Plan" above.</div>';
        } catch(e) {}
    }

    function syncPackageDropdowns(pkgs) {
        const provSelect = document.getElementById('prov-package');
        if (provSelect) {
            const currentVal = provSelect.value;
            provSelect.innerHTML = pkgs.map(p => `<option value="${p.id}">${p.name} (${p.base_monthly_credits.toLocaleString()} Credits/mo - $${p.price_monthly}/mo)</option>`).join('');
            if (currentVal && pkgs.some(p => p.id === currentVal)) provSelect.value = currentVal;
        }

        const editSelect = document.getElementById('edit-user-package');
        if (editSelect) {
            const currentVal = editSelect.value;
            editSelect.innerHTML = pkgs.map(p => `<option value="${p.id}">${p.name} ($${p.price_monthly}/mo)</option>`).join('');
            if (currentVal && pkgs.some(p => p.id === currentVal)) editSelect.value = currentVal;
        }

        const filterSelect = document.getElementById('adm-filter-package');
        if (filterSelect) {
            const currentVal = filterSelect.value || 'all';
            let options = '<option value="all">All Packages</option>';
            pkgs.forEach(p => {
                options += `<option value="${p.id}">${p.name}</option>`;
            });
            filterSelect.innerHTML = options;
            if (currentVal) filterSelect.value = currentVal;
        }
    }

    function autoSlugPackageId(name) {
        const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '');
        const idInput = document.getElementById('pkg-create-id');
        if (idInput) {
            idInput.value = slug ? `custom_${slug}` : '';
        }
    }

    function openCreatePackageModal() {
        document.getElementById('pkg-create-id').value = '';
        document.getElementById('pkg-create-name').value = '';
        document.getElementById('pkg-create-price').value = '149.00';
        document.getElementById('pkg-create-credits').value = '35000';
        document.getElementById('pkg-create-policy').value = 'block';
        document.getElementById('pkg-create-depth').value = '8';
        document.getElementById('pkg-create-pages').value = '5000';
        document.getElementById('pkg-create-concurrency').value = '5';
        document.getElementById('pkg-create-rpm').value = '150';
        document.getElementById('pkg-create-ocr').checked = true;
        document.getElementById('pkg-create-docs').checked = true;
        document.getElementById('pkg-create-google').checked = true;
        document.getElementById('pkg-create-export').checked = true;
        document.getElementById('pkg-create-reason').value = '';
        document.getElementById('modal-create-package')?.classList.remove('hidden');
    }
    function closeCreatePackageModal() {
        document.getElementById('modal-create-package')?.classList.add('hidden');
    }
    async function submitCreatePackage(e) {
        e.preventDefault();
        const payload = {
            id: document.getElementById('pkg-create-id').value.trim().toLowerCase(),
            name: document.getElementById('pkg-create-name').value.trim(),
            price_monthly: parseFloat(document.getElementById('pkg-create-price').value) || 0.0,
            base_monthly_credits: parseInt(document.getElementById('pkg-create-credits').value) || 1000,
            over_quota_policy: document.getElementById('pkg-create-policy').value,
            is_custom: 1,
            features: {
                max_depth: parseInt(document.getElementById('pkg-create-depth').value) || 5,
                max_pages: parseInt(document.getElementById('pkg-create-pages').value) || 500,
                max_concurrency: parseInt(document.getElementById('pkg-create-concurrency').value) || 3,
                rate_limit_rpm: parseInt(document.getElementById('pkg-create-rpm').value) || 60,
                allow_ocr: document.getElementById('pkg-create-ocr').checked,
                allow_docs: document.getElementById('pkg-create-docs').checked,
                allow_google_index: document.getElementById('pkg-create-google').checked,
                allow_export: document.getElementById('pkg-create-export').checked
            },
            reason: document.getElementById('pkg-create-reason').value.trim() || 'Created custom subscription package'
        };

        try {
            const res = await fetch('?api=admin_save_package', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${authState.token}`
                },
                body: JSON.stringify(payload)
            });
            const data = await res.json();
            if (data.ok) {
                alert(`Custom package '${payload.name}' created successfully!`);
                closeCreatePackageModal();
                loadAdminPackages();
                loadAdminStats();
            } else {
                alert(data.error || 'Failed to create package');
            }
        } catch(err) {
            alert(err.message || 'Network error');
        }
    }

    function openEditPackageModal(pkgId) {
        const pkg = adminPackagesCache.find(p => p.id === pkgId);
        if (!pkg) {
            alert('Package not found.');
            return;
        }
        const feat = pkg.features || {};
        document.getElementById('pkg-edit-id').value = pkg.id;
        document.getElementById('pkg-edit-name').value = pkg.name;
        document.getElementById('pkg-edit-price').value = pkg.price_monthly;
        document.getElementById('pkg-edit-credits').value = pkg.base_monthly_credits;
        document.getElementById('pkg-edit-policy').value = pkg.over_quota_policy || 'block';
        document.getElementById('pkg-edit-is-custom').value = pkg.is_custom ? '1' : '0';
        document.getElementById('pkg-edit-depth').value = feat.max_depth || 5;
        document.getElementById('pkg-edit-pages').value = feat.max_pages || 500;
        document.getElementById('pkg-edit-concurrency').value = feat.max_concurrency || 3;
        document.getElementById('pkg-edit-rpm').value = feat.rate_limit_rpm || 60;
        document.getElementById('pkg-edit-ocr').checked = Boolean(feat.allow_ocr);
        document.getElementById('pkg-edit-docs').checked = Boolean(feat.allow_docs);
        document.getElementById('pkg-edit-google').checked = Boolean(feat.allow_google_index);
        document.getElementById('pkg-edit-export').checked = Boolean(feat.allow_export);
        document.getElementById('pkg-edit-reason').value = '';
        document.getElementById('modal-edit-package')?.classList.remove('hidden');
    }
    function closeEditPackageModal() {
        document.getElementById('modal-edit-package')?.classList.add('hidden');
    }
    async function submitEditPackage(e) {
        e.preventDefault();
        const payload = {
            id: document.getElementById('pkg-edit-id').value.trim().toLowerCase(),
            name: document.getElementById('pkg-edit-name').value.trim(),
            price_monthly: parseFloat(document.getElementById('pkg-edit-price').value) || 0.0,
            base_monthly_credits: parseInt(document.getElementById('pkg-edit-credits').value) || 1000,
            over_quota_policy: document.getElementById('pkg-edit-policy').value,
            is_custom: parseInt(document.getElementById('pkg-edit-is-custom').value) || 0,
            features: {
                max_depth: parseInt(document.getElementById('pkg-edit-depth').value) || 5,
                max_pages: parseInt(document.getElementById('pkg-edit-pages').value) || 500,
                max_concurrency: parseInt(document.getElementById('pkg-edit-concurrency').value) || 3,
                rate_limit_rpm: parseInt(document.getElementById('pkg-edit-rpm').value) || 60,
                allow_ocr: document.getElementById('pkg-edit-ocr').checked,
                allow_docs: document.getElementById('pkg-edit-docs').checked,
                allow_google_index: document.getElementById('pkg-edit-google').checked,
                allow_export: document.getElementById('pkg-edit-export').checked
            },
            reason: document.getElementById('pkg-edit-reason').value.trim() || 'Updated package parameters'
        };

        try {
            const res = await fetch('?api=admin_save_package', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${authState.token}`
                },
                body: JSON.stringify(payload)
            });
            const data = await res.json();
            if (data.ok) {
                alert(`Package '${payload.name}' updated successfully!`);
                closeEditPackageModal();
                loadAdminPackages();
                loadAdminUsers();
            } else {
                alert(data.error || 'Failed to update package');
            }
        } catch(err) {
            alert(err.message || 'Network error');
        }
    }

    async function deletePackagePrompt(pkgId, pkgName, userCount) {
        if (userCount > 0) {
            alert(`Cannot delete package '${pkgName}': ${userCount} active user(s) currently assigned. Please reassign those users to another package tier in the User Directory first.`);
            return;
        }

        if (!confirm(`Are you sure you want to permanently delete package '${pkgName}' (${pkgId})?`)) {
            return;
        }

        try {
            const res = await fetch('?api=admin_delete_package', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${authState.token}`
                },
                body: JSON.stringify({ id: pkgId, reason: `Admin deleted package ${pkgName}` })
            });
            const data = await res.json();
            if (data.ok) {
                alert(data.message || `Package '${pkgName}' deleted.`);
                loadAdminPackages();
                loadAdminStats();
            } else {
                alert(data.error || 'Failed to delete package');
            }
        } catch(err) {
            alert(err.message || 'Network error');
        }
    }

    async function loadAdminPricing() {
        if (!authState.isAdmin) return;
        const tbody = document.getElementById('adm-pricing-tbody');
        if (!tbody) return;

        try {
            const res = await fetch('?api=admin_action_pricing', {
                headers: { 'Authorization': `Bearer ${authState.token}` }
            });
            if (!res.ok) return;
            const data = await res.json();
            const pricing = data.pricing || [];

            let html = '';
            pricing.forEach(item => {
                html += `
                    <tr class="hover:bg-cyber-card/60 border-b border-cyber-border/20">
                        <td class="py-3 px-4 font-mono text-cyan-400">${item.action_key}</td>
                        <td class="py-3 px-4 font-bold text-white">${item.display_name}</td>
                        <td class="py-3 px-4 text-gray-400">${item.description}</td>
                        <td class="py-3 px-4">
                            <input type="number" min="0" value="${item.cost_credits}" data-action="${item.action_key}" class="pricing-cost-input w-20 px-2 py-1 bg-cyber-bg border border-cyber-border rounded text-white font-mono text-xs focus:outline-none focus:border-brand-500">
                        </td>
                    </tr>
                `;
            });
            tbody.innerHTML = html;
        } catch(e) {}
    }

    async function saveAdminPricing() {
        const inputs = document.querySelectorAll('.pricing-cost-input');
        const pricingList = [];
        inputs.forEach(inp => {
            pricingList.push({
                action_key: inp.dataset.action,
                cost_credits: parseInt(inp.value) || 1
            });
        });

        try {
            const res = await fetch('?api=admin_update_pricing', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${authState.token}`
                },
                body: JSON.stringify({ pricing: pricingList })
            });
            const data = await res.json();
            if (data.ok) {
                alert('Action unit pricing updated successfully.');
                logToConsole('Updated action credit pricing matrix.', 'success');
            } else {
                alert(data.error || 'Failed to update pricing');
            }
        } catch(e) {
            alert(e.message);
        }
    }

    async function loadAdminAuditLogs() {
        if (!authState.isAdmin) return;
        const tbody = document.getElementById('adm-audit-tbody');
        if (!tbody) return;

        const search = document.getElementById('adm-audit-search')?.value || '';
        const actionFilter = document.getElementById('adm-audit-action-filter')?.value || 'all';

        try {
            const res = await fetch(`?api=admin_audit_logs&search=${encodeURIComponent(search)}&action=${encodeURIComponent(actionFilter)}&limit=50`, {
                headers: { 'Authorization': `Bearer ${authState.token}` }
            });
            if (!res.ok) return;
            const data = await res.json();
            const logs = data.logs || [];

            if (logs.length === 0) {
                tbody.innerHTML = '<tr><td colspan="8" class="py-8 text-center text-gray-500 font-mono">No audit trail records found.</td></tr>';
                return;
            }

            let html = '';
            logs.forEach(l => {
                const timeStr = l.created_at.replace('T', ' ').substring(0, 19);
                const deltaClass = l.credit_delta > 0 ? 'text-emerald-400 font-bold' : (l.credit_delta < 0 ? 'text-rose-400' : 'text-gray-400');
                const deltaStr = l.credit_delta !== 0 ? (l.credit_delta > 0 ? `+${l.credit_delta}` : `${l.credit_delta}`) : '-';

                html += `
                    <tr class="hover:bg-cyber-card/60 border-b border-cyber-border/20">
                        <td class="py-2.5 px-4 text-gray-400">${timeStr}</td>
                        <td class="py-2.5 px-4 font-mono text-cyan-400">${l.admin_email}</td>
                        <td class="py-2.5 px-4 font-mono text-gray-300">${l.target_user_email || `User #${l.target_user_id || '-'}`}</td>
                        <td class="py-2.5 px-4"><span class="px-1.5 py-0.5 rounded text-[10px] font-bold bg-cyber-bg border border-cyber-border text-purple-300">${l.action}</span></td>
                        <td class="py-2.5 px-4 ${deltaClass}">${deltaStr}</td>
                        <td class="py-2.5 px-4 text-gray-400 text-[11px]">${l.balance_before.toLocaleString()} &rarr; ${l.balance_after.toLocaleString()}</td>
                        <td class="py-2.5 px-4 text-amber-300 font-sans text-xs max-w-xs">${l.reason}</td>
                        <td class="py-2.5 px-4 text-gray-500 text-[10px]">${l.ip_address || '-'}</td>
                    </tr>
                `;
            });
            tbody.innerHTML = html;
        } catch(e) {}
    }

    function exportAuditLogsCSV() {
        window.location.href = `?api=admin_audit_logs&limit=500&token=${encodeURIComponent(authState.token)}`;
    }

    // ================= MODAL CONTROLLERS & FORM SUBMISSIONS =================
    function openLoginModal() {
        document.getElementById('modal-login')?.classList.remove('hidden');
    }
    function closeLoginModal() {
        document.getElementById('modal-login')?.classList.add('hidden');
        hideLoginError();
    }
    function showLoginError(msg) {
        const err = document.getElementById('login-error-msg');
        if (err) {
            err.textContent = msg;
            err.classList.remove('hidden');
        }
    }
    function hideLoginError() {
        const err = document.getElementById('login-error-msg');
        if (err) err.classList.add('hidden');
    }

    // Single-Session Conflict Modal Controllers
    let pendingLoginCredentials = null;

    function openSessionConflictModal(email, password, message) {
        pendingLoginCredentials = { email, password };
        const msgEl = document.getElementById('session-conflict-msg');
        if (msgEl && message) {
            msgEl.textContent = message;
        }
        document.getElementById('modal-session-conflict')?.classList.remove('hidden');
    }

    function cancelSessionConflictModal() {
        pendingLoginCredentials = null;
        document.getElementById('modal-session-conflict')?.classList.add('hidden');
    }

    async function continueSessionConflictModal() {
        if (!pendingLoginCredentials) {
            cancelSessionConflictModal();
            return;
        }
        const { email, password } = pendingLoginCredentials;
        cancelSessionConflictModal();
        await performLogin(email, password, true);
    }
    async function submitLoginForm(e) {
        e.preventDefault();
        const email = document.getElementById('login-email').value.trim();
        const password = document.getElementById('login-password').value;
        await performLogin(email, password);
    }
    async function quickLogin(email, pass) {
        document.getElementById('login-email').value = email;
        document.getElementById('login-password').value = pass;
        await performLogin(email, pass);
    }
    async function handleLogout() {
        try {
            await fetch('?api=auth_logout', {
                method: 'POST',
                headers: { 'Authorization': `Bearer ${authState.token}` }
            });
        } catch(e) {}
        localStorage.removeItem('wcpy_token');
        authState.token = '';
        authState.user = null;
        authState.creditSummary = null;
        authState.isAdmin = false;
        openLoginModal();
    }

    // Provision User Modal
    function openProvisionUserModal() {
        document.getElementById('modal-provision-user')?.classList.remove('hidden');
    }
    function closeProvisionUserModal() {
        document.getElementById('modal-provision-user')?.classList.add('hidden');
    }
    function updateProvisionPackageDefaults(pkgId) {
        const quotaMap = { 'starter': 1000, 'pro': 5000, 'business': 20000, 'custom_enterprise': 50000 };
        const initialRecurring = document.getElementById('prov-initial-recurring');
        if (initialRecurring) initialRecurring.value = quotaMap[pkgId] || 1000;
    }
    async function submitProvisionUser(e) {
        e.preventDefault();
        const payload = {
            name: document.getElementById('prov-name').value.trim(),
            email: document.getElementById('prov-email').value.trim(),
            password: document.getElementById('prov-password').value,
            role: document.getElementById('prov-role').value,
            package_id: document.getElementById('prov-package').value,
            initial_recurring: parseInt(document.getElementById('prov-initial-recurring').value) || 0,
            initial_topup: parseInt(document.getElementById('prov-initial-topup').value) || 0,
            custom_monthly_quota: document.getElementById('prov-custom-quota').value ? parseInt(document.getElementById('prov-custom-quota').value) : null
        };

        try {
            const res = await fetch('?api=admin_create_user', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${authState.token}`
                },
                body: JSON.stringify(payload)
            });
            const data = await res.json();
            if (data.ok) {
                alert(`User ${payload.email} provisioned successfully!`);
                closeProvisionUserModal();
                loadAdminUsers();
                loadAdminStats();
            } else {
                alert(data.error || 'Failed to provision user');
            }
        } catch(e) {
            alert(e.message);
        }
    }

    // Adjust Credit Modal
    function openAdjustCreditModal(userId, email, recurring, topup) {
        document.getElementById('adj-user-id').value = userId;
        document.getElementById('adj-target-email').textContent = email;
        document.getElementById('adj-curr-plan').textContent = recurring.toLocaleString();
        document.getElementById('adj-curr-topup').textContent = topup.toLocaleString();
        document.getElementById('adj-curr-total').textContent = `${(recurring + topup).toLocaleString()} Cr`;
        document.getElementById('adj-amount').value = '';
        document.getElementById('adj-reason').value = '';
        document.getElementById('modal-adjust-credit')?.classList.remove('hidden');
    }
    function closeAdjustCreditModal() {
        document.getElementById('modal-adjust-credit')?.classList.add('hidden');
    }
    async function submitCreditAdjustment(e) {
        e.preventDefault();
        const reason = document.getElementById('adj-reason').value.trim();
        if (!reason) {
            alert('A mandatory audit note/reason is required for administrative credit adjustments.');
            return;
        }

        const payload = {
            target_user_id: parseInt(document.getElementById('adj-user-id').value),
            adjustment_type: document.getElementById('adj-type').value,
            amount: parseInt(document.getElementById('adj-amount').value),
            reason: reason
        };

        try {
            const res = await fetch('?api=admin_adjust_credit', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${authState.token}`
                },
                body: JSON.stringify(payload)
            });
            const data = await res.json();
            if (data.ok) {
                alert(`Credit adjustment applied! Target balance: ${data.balance_after.toLocaleString()} Cr`);
                closeAdjustCreditModal();
                loadAdminUsers();
                loadAdminStats();
                refreshLiveCreditBalance();
            } else {
                alert(data.error || 'Adjustment failed');
            }
        } catch(e) {
            alert(e.message);
        }
    }

    // Edit User Modal
    function openEditUserModal(userId, email, packageId, status, customQuota) {
        document.getElementById('edit-user-id').value = userId;
        document.getElementById('edit-user-email-display').value = email;
        document.getElementById('edit-user-status').value = status || 'active';
        document.getElementById('edit-user-package').value = packageId || 'starter';
        document.getElementById('edit-user-custom-quota').value = customQuota !== null && customQuota !== 'null' ? customQuota : '';
        document.getElementById('edit-user-reason').value = '';
        document.getElementById('modal-edit-user')?.classList.remove('hidden');
    }
    function closeEditUserModal() {
        document.getElementById('modal-edit-user')?.classList.add('hidden');
    }
    async function submitEditUser(e) {
        e.preventDefault();
        const payload = {
            user_id: parseInt(document.getElementById('edit-user-id').value),
            status: document.getElementById('edit-user-status').value,
            package_id: document.getElementById('edit-user-package').value,
            custom_monthly_quota: document.getElementById('edit-user-custom-quota').value ? parseInt(document.getElementById('edit-user-custom-quota').value) : null,
            reason: document.getElementById('edit-user-reason').value.trim() || 'Administrative plan/status update'
        };

        try {
            const res = await fetch('?api=admin_update_user', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${authState.token}`
                },
                body: JSON.stringify(payload)
            });
            const data = await res.json();
            if (data.ok) {
                alert('User subscription & status updated successfully.');
                closeEditUserModal();
                loadAdminUsers();
                loadAdminStats();
                refreshLiveCreditBalance();
            } else {
                alert(data.error || 'Update failed');
            }
        } catch(e) {
            alert(e.message);
        }
    }

    async function adminResetBillingCycle(userId, email) {
        if (!confirm(`Force immediate monthly billing replenishment for ${email}?`)) return;
        try {
            const res = await fetch('?api=admin_reset_billing', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${authState.token}`
                },
                body: JSON.stringify({
                    target_user_id: userId,
                    reason: 'Admin forced billing cycle replenishment'
                })
            });
            const data = await res.json();
            if (data.ok) {
                alert(`Billing cycle reset! User replenished to ${data.new_recurring_credits.toLocaleString()} plan credits.`);
                loadAdminUsers();
                refreshLiveCreditBalance();
            } else {
                alert(data.error || 'Reset failed');
            }
        } catch(e) {
            alert(e.message);
        }
    }

    // ================= REAL-TIME METERING & CRAWLER CORE =================
    async function pingPythonBackend() {
        try {
            const res = await fetch('?api=ping');
            if (res.ok) {
                const data = await res.json();
                logToConsole(`Python Flask WSGI backend live: ${data.engine} (${data.system_url})`, 'success');
            }
        } catch(e) {
            logToConsole('Connecting to Python Flask WSGI route...', 'info');
        }
    }

    function logToConsole(message, type = 'info') {
        const container = document.getElementById('log-console-container');
        if (!container) return;
        const div = document.createElement('div');
        let colorClass = 'text-gray-300';
        if (type === 'success') colorClass = 'text-emerald-400';
        else if (type === 'warn') colorClass = 'text-amber-400';
        else if (type === 'error') colorClass = 'text-rose-400';
        else if (type === 'doc') colorClass = 'text-cyan-400';
        else if (type === 'ocr') colorClass = 'text-purple-400';

        const now = new Date().toISOString().substring(11, 19);
        div.className = `${colorClass} leading-relaxed`;
        div.textContent = `[${now}] ${message}`;
        container.appendChild(div);
        container.scrollTop = container.scrollHeight;
    }

    function clearConsoleLog() {
        const container = document.getElementById('log-console-container');
        if (container) container.innerHTML = '';
    }

    function handleStartOrResumeClick() {
        if (crawlerState.isCrawling) {
            logToConsole('A crawl session is already actively running. Only one crawl session can run at a time.', 'warn');
            return;
        }

        // Check credit balance before starting
        if (authState.creditSummary && authState.creditSummary.total_available_credits <= 0) {
            document.getElementById('modal-out-of-credits')?.classList.remove('hidden');
            logToConsole('[QUOTA REACHED] Cannot start crawl. Available credits: 0. Contact admin for top-up.', 'error');
            return;
        }

        const inputUrl = document.getElementById('input-target-url');
        const startUrl = inputUrl ? inputUrl.value.trim() : '';

        if (!startUrl || !startUrl.startsWith('http')) {
            alert('Please enter a valid start URL (http:// or https://)');
            return;
        }

        crawlerState.maxDepth = parseInt(document.getElementById('input-max-depth').value) || 8;
        crawlerState.maxPages = parseInt(document.getElementById('input-max-pages').value) || 50;
        crawlerState.scope = document.getElementById('input-crawl-scope').value;
        crawlerState.traversalMode = document.getElementById('input-traversal-mode').value;
        const pdfCb = document.getElementById('toggle-pdf-only');
        if (pdfCb) crawlerState.pdfOnly = pdfCb.checked;

        const isResuming = crawlerState.primary_queue.length > 0;

        if (!isResuming) {
            crawlerState.primary_queue.push({
                url: startUrl,
                depth: 1,
                parent: null,
                isExternal: false
            });
            crawlerState.scannedPagesCount = 0;
            crawlerState.emailsFoundCount = 0;
            crawlerState.docsParsedCount = 0;
            crawlerState.visited_urls.clear();
            crawlerState.scrapedEmailsList = [];
            crawlerState.visitedLog = [];
            renderEmailsTable();
            renderVisitedLogTable();
            logToConsole(`Launched fresh crawl on ${startUrl} (Scope: ${crawlerState.scope.toUpperCase()}, Strict PDF: ${crawlerState.pdfOnly ? 'ON' : 'OFF'})`, 'success');
        } else {
            logToConsole(`Resuming session [${crawlerState.currentSessionName || 'Session'}] from cutoff point (${crawlerState.primary_queue.length} in queue, ${crawlerState.scrapedEmailsList.length} emails discovered).`, 'info');
        }

        crawlerState.isCrawling = true;
        crawlerState.isPaused = false;
        crawlerState.startTime = Date.now();
        crawlerState.currentSessionStatus = 'active';

        updateSessionBadge('active');
        document.getElementById('txt-start-btn').textContent = 'Crawling...';
        document.getElementById('btn-start').classList.add('opacity-75', 'cursor-not-allowed');

        autoSaveSession('active');
        processCrawlerQueue();
    }

    function handlePauseClick() {
        if (!crawlerState.isCrawling) return;
        crawlerState.isPaused = !crawlerState.isPaused;
        const pauseBtnText = document.getElementById('txt-pause-btn');
        if (crawlerState.isPaused) {
            crawlerState.currentSessionStatus = 'paused';
            updateSessionBadge('paused');
            if (pauseBtnText) pauseBtnText.textContent = 'Resume';
            document.getElementById('txt-start-btn').textContent = 'Resume Crawl';
            document.getElementById('btn-start').classList.remove('opacity-75', 'cursor-not-allowed');
            logToConsole(`Crawl engine paused by user at cutoff point (${crawlerState.primary_queue.length} queued URLs, ${crawlerState.scrapedEmailsList.length} emails discovered).`, 'warn');
            autoSaveSession('paused');
        } else {
            crawlerState.currentSessionStatus = 'active';
            updateSessionBadge('active');
            if (pauseBtnText) pauseBtnText.textContent = 'Pause';
            document.getElementById('txt-start-btn').textContent = 'Crawling...';
            document.getElementById('btn-start').classList.add('opacity-75', 'cursor-not-allowed');
            logToConsole('Resumed crawling engine from cutoff point.', 'info');
            autoSaveSession('active');
            processCrawlerQueue();
        }
    }

    function handleStopClick() {
        stopCrawlingEngine('User stopped session');
    }

    function stopCrawlingEngine(reason) {
        crawlerState.isCrawling = false;
        crawlerState.isPaused = false;
        const isCompleted = (crawlerState.primary_queue.length === 0 || crawlerState.scannedPagesCount >= crawlerState.maxPages);
        const finalStatus = isCompleted ? 'completed' : 'stopped';
        crawlerState.currentSessionStatus = finalStatus;
        updateSessionBadge(finalStatus);

        document.getElementById('txt-start-btn').textContent = (crawlerState.primary_queue.length > 0) ? 'Resume Crawl' : 'Start Crawl';
        document.getElementById('btn-start').classList.remove('opacity-75', 'cursor-not-allowed');
        const pauseBtnText = document.getElementById('txt-pause-btn');
        if (pauseBtnText) pauseBtnText.textContent = 'Pause';

        logToConsole(`Session ${finalStatus}: ${reason}`, 'warn');
        autoSaveSession(finalStatus);
        refreshLiveCreditBalance();
    }

    async function processCrawlerQueue() {
        if (!crawlerState.isCrawling || crawlerState.isPaused) return;

        if (crawlerState.primary_queue.length === 0 || crawlerState.scannedPagesCount >= crawlerState.maxPages) {
            stopCrawlingEngine('All queue items completed or max pages reached.');
            return;
        }

        const task = crawlerState.primary_queue.shift();
        if (crawlerState.visited_urls.has(task.url)) {
            processCrawlerQueue();
            return;
        }

        crawlerState.visited_urls.add(task.url);
        crawlerState.scannedPagesCount++;
        updateStats();

        logToConsole(`Auditing [Depth: ${task.depth}/${crawlerState.maxDepth}] => ${task.url}...`, 'info');
        await handleRealCrawl(task);
    }

    async function handleRealCrawl(task) {
        let fileType = 'HTML';
        const urlLower = task.url.toLowerCase();
        if (urlLower.endsWith('.pdf') || urlLower.includes('/pdf/')) fileType = 'PDF';
        else if (urlLower.endsWith('.docx')) fileType = 'DOCX';
        else if (urlLower.endsWith('.doc')) fileType = 'DOC';
        else if (urlLower.endsWith('.txt')) fileType = 'TXT';

        // 1. Syntactic Dummy Link Elimination
        const dummyPattern = /(example\.com|localhost|127\.0\.0\.1|test\.com|dummy|placeholder|sample|void\(0\)|privacy|terms|javascript:|mailto:|tel:|\/rss|\/feed)/i;
        if (dummyPattern.test(task.url)) {
            logToConsole(`[DUMMY ELIMINATED] Skipped ${task.url}`, 'warn');
            setTimeout(processCrawlerQueue, crawlerState.delay);
            return;
        }

        // 2. Pre-flight Dead Link Check (1 Cr)
        if (crawlerState.deadLinkFilter) {
            try {
                const checkRes = await fetch(`?api=check_link&url=${encodeURIComponent(task.url)}`, {
                    headers: authState.token ? { 'Authorization': `Bearer ${authState.token}` } : {}
                });
                if (checkRes.status === 402) {
                    handleQuotaExhausted();
                    return;
                } else if (checkRes.status === 403) {
                    handleAccountSuspended();
                    return;
                }
                if (checkRes.ok) {
                    const checkData = await checkRes.json();
                    if (!checkData.valid) {
                        logToConsole(`[DEAD LINK ELIMINATED] Failed check (${checkData.error || 'HTTP 404'}) on ${task.url}`, 'warn');
                        addVisitedLogEntry(task.url, task.depth, fileType, 0, `Eliminated (${checkData.error || 'HTTP 404'})`, 'Pre-flight HEAD');
                        setTimeout(processCrawlerQueue, crawlerState.delay);
                        return;
                    }
                }
            } catch(e) {}
        }

        // 3. Google Index Verification (1 Cr)
        if (crawlerState.googleIndexFilter) {
            try {
                const gRes = await fetch(`?api=google_indexed&url=${encodeURIComponent(task.url)}`, {
                    headers: authState.token ? { 'Authorization': `Bearer ${authState.token}` } : {}
                });
                if (gRes.status === 402) {
                    handleQuotaExhausted();
                    return;
                }
                if (gRes.ok) {
                    const gData = await gRes.json();
                    if (gData.indexed === false) {
                        logToConsole(`[GOOGLE INDEX FILTER] Skipped non-indexed URL: ${task.url}`, 'warn');
                        addVisitedLogEntry(task.url, task.depth, fileType, 0, 'Skipped (Not Google Indexed)', 'Google SERP Check');
                        setTimeout(processCrawlerQueue, crawlerState.delay);
                        return;
                    }
                }
            } catch(e) {}
        }

        // 4. Fetch Page Content (Metered 1 Cr + Doc Parser 2 Cr)
        try {
            const fetchRes = await fetch(`?api=fetch&url=${encodeURIComponent(task.url)}`, {
                headers: authState.token ? { 'Authorization': `Bearer ${authState.token}` } : {}
            });

            if (fetchRes.status === 402) {
                handleQuotaExhausted();
                return;
            } else if (fetchRes.status === 403) {
                handleAccountSuspended();
                return;
            }

            if (!fetchRes.ok) {
                logToConsole(`[FETCH FAILED] HTTP ${fetchRes.status} on ${task.url}`, 'warn');
                addVisitedLogEntry(task.url, task.depth, fileType, 0, `HTTP ${fetchRes.status}`, 'Python WSGI Proxy');
                setTimeout(processCrawlerQueue, crawlerState.delay);
                return;
            }

            const data = await fetchRes.json();
            refreshLiveCreditBalance();

            let foundEmails = [];

            if (crawlerState.pdfOnly) {
                // STRICT PDF TARGETING: extract emails SOLELY from PDF documents
                const isPdfDoc = (fileType === 'PDF' || (data.is_document && data.doc_type === 'PDF Document'));
                if (isPdfDoc) {
                    crawlerState.docsParsedCount++;
                    if (data.server_emails && Array.isArray(data.server_emails)) {
                        foundEmails = data.server_emails;
                    }
                    logToConsole(`[STRICT PDF MODE] Extracted PDF Document -> ${foundEmails.length} email(s) found.`, 'doc');
                } else {
                    // Regular web page: ignore content for email extraction
                    foundEmails = [];
                    // Still discover child links to find PDF documents!
                    if (task.depth < crawlerState.maxDepth && data.contents) {
                        discoverChildLinks(data.contents, task);
                    }
                    logToConsole(`[PDF ONLY ACTIVE] Audited web page for PDF files (HTML page emails ignored).`, 'info');
                }
            } else {
                if (data.is_document || fileType !== 'HTML') {
                    crawlerState.docsParsedCount++;
                    if (data.server_emails && Array.isArray(data.server_emails)) {
                        foundEmails = data.server_emails;
                    }
                    logToConsole(`Extracted document [${data.doc_type || fileType}] -> ${foundEmails.length} emails found.`, 'doc');
                } else if (data.contents) {
                    foundEmails = extractEmailsFromHtml(data.contents);
                    
                    // Discover child links if within depth limit
                    if (task.depth < crawlerState.maxDepth) {
                        discoverChildLinks(data.contents, task);
                    }
                }
            }

            if (foundEmails.length > 0) {
                recordDiscoveredEmails(foundEmails, task);
            }

            addVisitedLogEntry(task.url, task.depth, fileType, foundEmails.length, `HTTP ${data.status || 200}`, data.source || 'direct');
            updateNetworkGraph(task.url, foundEmails.length, task.parent, task.isExternal);
            scheduleSessionAutoSave();

        } catch(err) {
            logToConsole(`Error crawling ${task.url}: ${err.message}`, 'error');
        }

        setTimeout(processCrawlerQueue, crawlerState.delay);
    }

    function handleQuotaExhausted() {
        stopCrawlingEngine('Credit quota exhausted');
        document.getElementById('modal-out-of-credits')?.classList.remove('hidden');
        logToConsole('[HALTED: OUT OF CREDITS] Balance exhausted. Please top-up.', 'error');
    }

    function handleAccountSuspended() {
        stopCrawlingEngine('Account suspended');
        alert('Your account is currently suspended by the administrator. Operations are halted.');
        logToConsole('[HALTED: ACCOUNT SUSPENDED] Contact administrator.', 'error');
    }

    function extractEmailsFromHtml(html) {
        if (!html) return [];
        const emails = new Set();
        const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/gi;
        const matches = html.match(emailRegex) || [];
        matches.forEach(e => emails.add(e.toLowerCase()));

        const excluded = ['info@archive.org', 'support@archive.org'];
        return Array.from(emails).filter(email => {
            const lower = email.toLowerCase();
            return !/\.(png|jpe?g|gif|svg|webp|css|js)$/.test(lower) && !excluded.includes(lower);
        });
    }

    function recordDiscoveredEmails(emails, task) {
        let newCount = 0;
        let sector = 'Web Discovery';
        try { sector = new URL(task.url).hostname; } catch(e){}

        emails.forEach(email => {
            if (!crawlerState.scrapedEmailsList.some(item => item.email === email)) {
                newCount++;
                crawlerState.scrapedEmailsList.push({
                    id: crawlerState.scrapedEmailsList.length + 1,
                    email: email,
                    source: task.url,
                    type: (task.url.endsWith('.pdf') || task.url.includes('/pdf/')) ? 'PDF Document' : 'HTML Page',
                    sector: sector,
                    depth: task.depth
                });
            }
        });

        crawlerState.emailsFoundCount += emails.length;
        updateStats();
        renderEmailsTable();
        if (newCount > 0) {
            logToConsole(`✨ Saved ${newCount} new unique email(s) from ${task.url}!`, 'success');
        }
    }

    function discoverChildLinks(html, parentTask) {
        const linkRegex = /href=["']([^"']+)["']/gi;
        let match;
        let added = 0;

        while ((match = linkRegex.exec(html)) !== null && added < 25) {
            let href = match[1].trim();
            if (!href || href.startsWith('#') || href.startsWith('javascript:') || href.startsWith('mailto:')) continue;

            try {
                const resolvedUrl = new URL(href, parentTask.url).href;
                const isExternal = new URL(resolvedUrl).hostname !== new URL(parentTask.url).hostname;

                // Enforce scope: if internal only, skip external links
                if (crawlerState.scope === 'internal' && isExternal) {
                    continue;
                }

                if (!crawlerState.visited_urls.has(resolvedUrl) && !crawlerState.primary_queue.some(q => q.url === resolvedUrl)) {
                    crawlerState.primary_queue.push({
                        url: resolvedUrl,
                        depth: parentTask.depth + 1,
                        parent: parentTask.url,
                        isExternal: isExternal
                    });
                    added++;
                }
            } catch(e) {}
        }
        updateStats();
        renderQueueTable();
    }

    function scheduleSessionAutoSave() {
        if (crawlerState.autoSaveTimeout) clearTimeout(crawlerState.autoSaveTimeout);
        crawlerState.autoSaveTimeout = setTimeout(() => {
            autoSaveSession();
        }, 2000);
    }

    async function autoSaveSession(customStatus) {
        const activeId = sessionsStore.activeSessionId;
        if (!activeId) return;

        const currentStatus = customStatus || (crawlerState.isCrawling ? 'active' : (crawlerState.isPaused ? 'paused' : (crawlerState.currentSessionStatus || 'ready')));
        const inputUrl = document.getElementById('input-target-url');
        const startUrl = inputUrl ? inputUrl.value.trim() : '';

        const payload = {
            id: activeId,
            name: crawlerState.currentSessionName || 'Crawl Session',
            start_url: startUrl || 'https://journals.sagepub.com/loi/BRQ',
            scope: crawlerState.scope || 'internal',
            pdf_only: crawlerState.pdfOnly ? 1 : 0,
            traversal_mode: crawlerState.traversalMode || 'dfs',
            max_depth: crawlerState.maxDepth || 8,
            max_pages: crawlerState.maxPages || 50,
            google_index_filter: crawlerState.googleIndexFilter ? 1 : 0,
            dead_link_filter: crawlerState.deadLinkFilter ? 1 : 0,
            ocr_enabled: crawlerState.ocrEnabled ? 1 : 0,
            docs_enabled: crawlerState.docsEnabled ? 1 : 0,
            status: currentStatus,
            scanned_pages_count: crawlerState.scannedPagesCount,
            emails_found_count: crawlerState.emailsFoundCount,
            unique_emails_count: new Set(crawlerState.scrapedEmailsList.map(e => e.email)).size,
            docs_parsed_count: crawlerState.docsParsedCount,
            credits_used: crawlerState.creditsUsed || 0,
            primary_queue: crawlerState.primary_queue,
            visited_urls: Array.from(crawlerState.visited_urls),
            visited_log: crawlerState.visitedLog,
            scraped_emails: crawlerState.scrapedEmailsList
        };

        sessionsStore.sessions[activeId] = {
            ...payload,
            updated_at: new Date().toISOString()
        };

        try {
            localStorage.setItem('wcpy_saved_session_' + activeId, JSON.stringify(payload));
        } catch(e) {}

        const savedEl = document.getElementById('txt-session-saved-detail');
        if (savedEl) savedEl.textContent = new Date().toLocaleTimeString();

        if (authState.token) {
            try {
                await fetch('?api=crawl_session_save', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${authState.token}`
                    },
                    body: JSON.stringify(payload)
                });
            } catch(e) {}
        }
    }

    function updateSessionBadge(status) {
        const badge = document.getElementById('badge-session-status');
        const detail = document.getElementById('txt-session-status-detail');
        const s = (status || 'ready').toLowerCase();
        if (detail) {
            detail.textContent = s.charAt(0).toUpperCase() + s.slice(1);
            if (s === 'active') detail.className = 'text-emerald-400 font-bold';
            else if (s === 'paused') detail.className = 'text-amber-400 font-bold';
            else if (s === 'queued') detail.className = 'text-purple-400 font-bold';
            else detail.className = 'text-brand-400 font-bold';
        }
        if (!badge) return;
        badge.textContent = s.toUpperCase();
        if (s === 'active') {
            badge.className = 'px-2 py-0.5 text-[9px] font-bold rounded bg-emerald-500/20 text-emerald-400 border border-emerald-500/30 font-mono';
        } else if (s === 'paused') {
            badge.className = 'px-2 py-0.5 text-[9px] font-bold rounded bg-amber-500/20 text-amber-400 border border-amber-500/30 font-mono';
        } else if (s === 'queued') {
            badge.className = 'px-2 py-0.5 text-[9px] font-bold rounded bg-purple-500/20 text-purple-400 border border-purple-500/30 font-mono';
        } else if (s === 'completed') {
            badge.className = 'px-2 py-0.5 text-[9px] font-bold rounded bg-cyan-500/20 text-cyan-400 border border-cyan-500/30 font-mono';
        } else {
            badge.className = 'px-2 py-0.5 text-[9px] font-bold rounded bg-brand-500/20 text-brand-400 border border-brand-500/30 font-mono';
        }
    }

    function updateStats() {
        const scannedEl = document.getElementById('stat-scanned');
        const emailsEl = document.getElementById('stat-emails');
        const uniqueEl = document.getElementById('stat-unique-emails');
        const docsEl = document.getElementById('stat-docs-parsed');
        const queueEl = document.getElementById('stat-queue');
        const badgeCount = document.getElementById('count-badge');
        const uniqueBadge = document.getElementById('unique-count-badge');
        const qBadge = document.getElementById('queue-badge-count');

        const uniqueCount = new Set(crawlerState.scrapedEmailsList.map(e => e.email)).size;

        if (scannedEl) scannedEl.textContent = crawlerState.scannedPagesCount;
        if (emailsEl) emailsEl.textContent = crawlerState.emailsFoundCount;
        if (uniqueEl) uniqueEl.textContent = uniqueCount;
        if (docsEl) docsEl.textContent = crawlerState.docsParsedCount;
        if (queueEl) queueEl.textContent = crawlerState.primary_queue.length;
        if (badgeCount) badgeCount.textContent = crawlerState.emailsFoundCount;
        if (uniqueBadge) uniqueBadge.textContent = uniqueCount;
        if (qBadge) qBadge.textContent = crawlerState.primary_queue.length;
    }

    function renderEmailsTable() {
        const tbody = document.getElementById('emails-tbody');
        if (!tbody || crawlerState.scrapedEmailsList.length === 0) return;

        let html = '';
        [...crawlerState.scrapedEmailsList].reverse().forEach(item => {
            html += `
                <tr class="hover:bg-cyber-card/60 border-b border-cyber-border/20 text-gray-300">
                    <td class="py-3 px-4 font-mono text-gray-500">#${item.id}</td>
                    <td class="py-3 px-4 font-semibold text-brand-500 font-mono">${item.email}</td>
                    <td class="py-3 px-4 text-xs truncate max-w-xs"><a href="${item.source}" target="_blank" class="text-cyan-400 hover:underline">${item.source}</a></td>
                    <td class="py-3 px-4"><span class="px-2 py-0.5 rounded text-[10px] font-semibold bg-purple-500/10 text-purple-400 border border-purple-500/20">${item.type}</span></td>
                    <td class="py-3 px-4">${item.sector}</td>
                    <td class="py-3 px-4 font-mono text-center">${item.depth}</td>
                </tr>
            `;
        });
        tbody.innerHTML = html;
    }

    function addVisitedLogEntry(url, depth, type, emailCount, status, source) {
        const tbody = document.getElementById('visited-log-tbody');
        if (!tbody) return;

        const now = new Date().toISOString().substring(11, 19);
        const row = `
            <tr class="hover:bg-cyber-card/60 border-b border-cyber-border/20">
                <td class="py-2.5 px-4 text-gray-500">${now}</td>
                <td class="py-2.5 px-4 truncate max-w-xs text-white">${url}</td>
                <td class="py-2.5 px-4"><span class="px-1.5 py-0.5 rounded text-[9px] font-bold bg-cyber-bg border border-cyber-border text-cyan-400">${type}</span></td>
                <td class="py-2.5 px-4 font-bold ${emailCount > 0 ? 'text-brand-400' : 'text-gray-500'}">${emailCount}</td>
                <td class="py-2.5 px-4 text-gray-300">${status}</td>
                <td class="py-2.5 px-4 text-gray-500 text-[10px]">${source}</td>
            </tr>
        `;

        if (crawlerState.visitedLog.length === 0) tbody.innerHTML = '';
        crawlerState.visitedLog.push({ url, depth, type, emailCount, status, source });
        tbody.innerHTML = row + tbody.innerHTML;
    }

    function renderQueueTable() {
        const tbody = document.getElementById('queue-tbody');
        if (!tbody) return;

        if (crawlerState.primary_queue.length === 0) {
            tbody.innerHTML = '<tr><td colspan="4" class="py-8 text-center text-gray-500 font-mono">Queue is empty.</td></tr>';
            return;
        }

        let html = '';
        crawlerState.primary_queue.slice(0, 50).forEach(q => {
            html += `
                <tr class="hover:bg-cyber-card/60 border-b border-cyber-border/20">
                    <td class="py-2.5 px-4 font-bold text-amber-400 font-mono">Level ${q.depth}</td>
                    <td class="py-2.5 px-4 text-white truncate max-w-md font-mono">${q.url}</td>
                    <td class="py-2.5 px-4 text-gray-400 truncate max-w-xs text-[11px]">${q.parent || 'Seed Domain'}</td>
                    <td class="py-2.5 px-4"><span class="px-1.5 py-0.5 rounded text-[9px] ${q.isExternal ? 'bg-purple-500/20 text-purple-300' : 'bg-brand-500/20 text-brand-300'} font-bold">${q.isExternal ? 'External' : 'Internal'}</span></td>
                </tr>
            `;
        });
        tbody.innerHTML = html;
    }

    // ================= EXPORTS (METERED: 5 CREDITS) =================
    async function meterExportAction(format) {
        if (!authState.token) return true;
        try {
            const res = await fetch('?api=meter_action', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${authState.token}`
                },
                body: JSON.stringify({
                    action_type: 'data_export',
                    custom_cost: 5,
                    description: `Exported dataset (${format.toUpperCase()})`
                })
            });
            const data = await res.json();
            if (data.ok) {
                refreshLiveCreditBalance();
                logToConsole(`[METERED] Exported ${format.toUpperCase()} (Deducted 5 credits)`, 'info');
                return true;
            } else {
                alert(data.error || 'Insufficient credits to export data.');
                return false;
            }
        } catch(e) {
            return true;
        }
    }

    async function downloadUniqueAsExcel() {
        if (crawlerState.scrapedEmailsList.length === 0) return alert('No emails to export.');
        const ok = await meterExportAction('excel');
        if (!ok) return;

        if (window.XLSX) {
            const ws = XLSX.utils.json_to_sheet(crawlerState.scrapedEmailsList);
            const wb = XLSX.utils.book_new();
            XLSX.utils.book_append_sheet(wb, ws, "Extracted Emails");
            XLSX.writeFile(wb, "scraped_emails_export.xlsx");
        }
    }

    async function downloadUniqueAsCSV() {
        if (crawlerState.scrapedEmailsList.length === 0) return alert('No emails to export.');
        const ok = await meterExportAction('csv');
        if (!ok) return;

        let csv = "id,email,source_url,type,sector,depth\r\n";
        crawlerState.scrapedEmailsList.forEach(i => {
            csv += `"${i.id}","${i.email}","${i.source}","${i.type}","${i.sector}",${i.depth}\r\n`;
        });
        const link = document.createElement("a");
        link.href = "data:text/csv;charset=utf-8,\uFEFF" + encodeURIComponent(csv);
        link.download = "scraped_emails_export.csv";
        link.click();
    }

    async function downloadUniqueAsJSON() {
        if (crawlerState.scrapedEmailsList.length === 0) return alert('No emails to export.');
        const ok = await meterExportAction('json');
        if (!ok) return;

        const blob = new Blob([JSON.stringify(crawlerState.scrapedEmailsList, null, 2)], { type: "application/json" });
        const link = document.createElement("a");
        link.href = URL.createObjectURL(blob);
        link.download = "scraped_emails_export.json";
        link.click();
    }

    function resetEngine() {
        if (crawlerState.isCrawling) stopCrawlingEngine('Reset requested');
        crawlerState.scannedPagesCount = 0;
        crawlerState.emailsFoundCount = 0;
        crawlerState.docsParsedCount = 0;
        crawlerState.primary_queue = [];
        crawlerState.visited_urls.clear();
        crawlerState.scrapedEmailsList = [];
        crawlerState.visitedLog = [];
        updateStats();
        renderEmailsTable();
        renderQueueTable();
        logToConsole('Queue and session counters cleared.', 'info');
    }

    // ================= DYNAMIC CANVAS NETWORK MAPPER =================
    function initCanvasNetwork() {
        const canvas = document.getElementById('canvas-network');
        if (!canvas) return;
        const ctx = canvas.getContext('2d');
        canvas.width = canvas.parentElement.clientWidth;
        canvas.height = canvas.parentElement.clientHeight;

        ctx.fillStyle = '#0b0f19';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
    }

    function updateNetworkGraph(url, emailsFound, parentUrl, isExternal) {
        const canvas = document.getElementById('canvas-network');
        if (!canvas) return;
        const ctx = canvas.getContext('2d');
        const overlay = document.getElementById('canvas-overlay-text');
        if (overlay) overlay.style.display = 'none';

        const x = Math.random() * (canvas.width - 40) + 20;
        const y = Math.random() * (canvas.height - 40) + 20;

        ctx.beginPath();
        ctx.arc(x, y, emailsFound > 0 ? 6 : 3, 0, 2 * Math.PI);
        ctx.fillStyle = emailsFound > 0 ? '#10b981' : (isExternal ? '#a855f7' : '#38bdf8');
        ctx.shadowColor = ctx.fillStyle;
        ctx.shadowBlur = 8;
        ctx.fill();
        ctx.shadowBlur = 0;

        const nodeStatus = document.getElementById('system-node-status');
        if (nodeStatus) nodeStatus.textContent = `Audited: ${url.substring(0, 45)}...`;
    }

    // ================= SESSION MANAGER & AUDIT INSPECTION =================
    async function initSessions() {
        sessionsStore.sessions['session_default'] = {
            id: 'session_default',
            name: 'Session 1 (SagePub Research)',
            start_url: 'https://journals.sagepub.com/loi/BRQ',
            scope: 'internal',
            pdf_only: 0,
            traversal_mode: 'dfs',
            max_depth: 8,
            max_pages: 50,
            status: 'ready',
            scanned_pages_count: 0,
            emails_found_count: 0,
            unique_emails_count: 0,
            docs_parsed_count: 0,
            primary_queue: [],
            visited_urls: [],
            visited_log: [],
            scraped_emails: []
        };
        renderSessionDropdown();
    }

    async function loadSessionsFromBackend() {
        if (!authState.token) return;
        try {
            const res = await fetch('?api=crawl_sessions_list', {
                headers: { 'Authorization': `Bearer ${authState.token}` }
            });
            if (res.ok) {
                const data = await res.json();
                if (data.ok && Array.isArray(data.sessions) && data.sessions.length > 0) {
                    sessionsStore.sessions = {};
                    data.sessions.forEach(s => {
                        sessionsStore.sessions[s.id] = s;
                    });
                    renderSessionDropdown();
                    // If active session not in list, select the first one
                    const firstId = data.sessions[0].id;
                    if (!sessionsStore.sessions[sessionsStore.activeSessionId]) {
                        sessionsStore.activeSessionId = firstId;
                    }
                    await switchSessionFromSelect(sessionsStore.activeSessionId, false);
                    return;
                }
            }
        } catch(e) {
            console.warn('Backend session fetch error:', e);
        }

        // Fallback: check localStorage for saved sessions
        try {
            let foundLocal = false;
            for (let i = 0; i < localStorage.length; i++) {
                const k = localStorage.key(i);
                if (k && k.startsWith('wcpy_saved_session_')) {
                    const parsed = JSON.parse(localStorage.getItem(k));
                    if (parsed && parsed.id) {
                        sessionsStore.sessions[parsed.id] = parsed;
                        foundLocal = true;
                    }
                }
            }
            if (foundLocal) {
                renderSessionDropdown();
                const firstId = Object.keys(sessionsStore.sessions)[0];
                sessionsStore.activeSessionId = firstId;
                await switchSessionFromSelect(firstId, false);
            }
        } catch(e) {}
    }

    function renderSessionDropdown() {
        const sel = document.getElementById('input-session-select');
        if (!sel) return;
        sel.innerHTML = '';
        const list = Object.values(sessionsStore.sessions);
        if (list.length === 0) {
            initSessions();
            return;
        }

        list.forEach(s => {
            const opt = document.createElement('option');
            opt.value = s.id;
            let statusTag = (s.status || 'ready').toUpperCase();
            let emailTag = `${s.emails_found_count || (s.scraped_emails ? s.scraped_emails.length : 0)} emails`;
            opt.textContent = `${s.name || 'Session'} [${statusTag}] (${emailTag})`;
            if (s.id === sessionsStore.activeSessionId) {
                opt.selected = true;
            }
            sel.appendChild(opt);
        });

        const activeSession = sessionsStore.sessions[sessionsStore.activeSessionId];
        if (activeSession) {
            updateSessionBadge(activeSession.status || 'ready');
        }
    }

    async function createNewSession() {
        const count = Object.keys(sessionsStore.sessions).length + 1;
        const id = `cs_${Date.now()}`;
        const inputUrl = document.getElementById('input-target-url');
        const defaultUrl = inputUrl ? inputUrl.value.trim() : 'https://journals.sagepub.com/loi/BRQ';

        // Single-Session Execution Rule:
        // If a crawl session is already actively running, subsequent sessions are queued!
        if (crawlerState.isCrawling) {
            const queuedSession = {
                id: id,
                name: `Session ${count}`,
                start_url: defaultUrl,
                scope: crawlerState.scope || 'internal',
                pdf_only: crawlerState.pdfOnly ? 1 : 0,
                traversal_mode: crawlerState.traversalMode || 'dfs',
                max_depth: crawlerState.maxDepth || 8,
                max_pages: crawlerState.maxPages || 50,
                google_index_filter: crawlerState.googleIndexFilter ? 1 : 0,
                dead_link_filter: crawlerState.deadLinkFilter ? 1 : 0,
                ocr_enabled: crawlerState.ocrEnabled ? 1 : 0,
                docs_enabled: crawlerState.docsEnabled ? 1 : 0,
                status: 'queued',
                scanned_pages_count: 0,
                emails_found_count: 0,
                unique_emails_count: 0,
                docs_parsed_count: 0,
                credits_used: 0,
                primary_queue: [{ url: defaultUrl, depth: 1, parent: null, isExternal: false }],
                visited_urls: [],
                visited_log: [],
                scraped_emails: []
            };

            sessionsStore.sessions[id] = queuedSession;
            renderSessionDropdown();

            if (authState.token) {
                try {
                    await fetch('?api=crawl_session_save', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${authState.token}` },
                        body: JSON.stringify(queuedSession)
                    });
                } catch(e) {}
            }

            logToConsole(`[SINGLE-SESSION EXECUTION] Session ${count} has been queued. Active crawl continues on current session.`, 'info');
            alert(`Session ${count} created and queued! In single-session execution mode, active crawl continues uninterrupted.`);
            return;
        }

        // If not actively crawling, save current state then switch to new session
        await autoSaveSession();

        const newSession = {
            id: id,
            name: `Session ${count}`,
            start_url: defaultUrl,
            scope: crawlerState.scope || 'internal',
            pdf_only: crawlerState.pdfOnly ? 1 : 0,
            traversal_mode: crawlerState.traversalMode || 'dfs',
            max_depth: 8,
            max_pages: 50,
            google_index_filter: 1,
            dead_link_filter: 1,
            ocr_enabled: 1,
            docs_enabled: 1,
            status: 'ready',
            scanned_pages_count: 0,
            emails_found_count: 0,
            unique_emails_count: 0,
            docs_parsed_count: 0,
            credits_used: 0,
            primary_queue: [],
            visited_urls: [],
            visited_log: [],
            scraped_emails: []
        };

        sessionsStore.sessions[id] = newSession;
        sessionsStore.activeSessionId = id;
        renderSessionDropdown();
        await switchSessionFromSelect(id, false);
        logToConsole(`Ready on Session ${count}. Configure start URL and click Start Crawl.`, 'info');
    }

    async function deleteCurrentSession() {
        if (crawlerState.isCrawling) {
            alert('Cannot delete an actively running crawl session. Please pause or stop it first.');
            return;
        }

        const activeId = sessionsStore.activeSessionId;
        const activeName = crawlerState.currentSessionName || 'Current Session';

        if (!confirm(`Are you sure you want to permanently delete "${activeName}" and its extracted email list?`)) {
            return;
        }

        if (authState.token) {
            try {
                await fetch(`?api=crawl_session_delete&id=${encodeURIComponent(activeId)}`, {
                    method: 'POST',
                    headers: { 'Authorization': `Bearer ${authState.token}` }
                });
            } catch(e) {}
        }

        try { localStorage.removeItem('wcpy_saved_session_' + activeId); } catch(e) {}
        delete sessionsStore.sessions[activeId];

        const remainingKeys = Object.keys(sessionsStore.sessions);
        if (remainingKeys.length > 0) {
            sessionsStore.activeSessionId = remainingKeys[0];
            renderSessionDropdown();
            await switchSessionFromSelect(remainingKeys[0], false);
        } else {
            initSessions();
            resetEngine();
        }

        logToConsole(`Deleted session "${activeName}" from history.`, 'warn');
    }

    async function switchSessionFromSelect(id, saveCurrent = true) {
        if (crawlerState.isCrawling) {
            alert('A crawl is actively running in the current session. Please pause or stop it before switching to inspect another session.');
            const sel = document.getElementById('input-session-select');
            if (sel) sel.value = sessionsStore.activeSessionId;
            return;
        }

        if (saveCurrent && sessionsStore.activeSessionId && sessionsStore.activeSessionId !== id) {
            await autoSaveSession();
        }

        sessionsStore.activeSessionId = id;
        let session = sessionsStore.sessions[id];

        // If details not loaded yet, fetch full details from backend
        if (authState.token && (!session || !session.scraped_emails || session.scraped_emails.length === 0)) {
            try {
                const res = await fetch(`?api=crawl_session_get&id=${encodeURIComponent(id)}`, {
                    headers: { 'Authorization': `Bearer ${authState.token}` }
                });
                if (res.ok) {
                    const data = await res.json();
                    if (data.ok && data.session) {
                        session = data.session;
                        sessionsStore.sessions[id] = session;
                    }
                }
            } catch(e) {}
        }

        if (!session) return;

        // Apply settings to UI controls
        const inputUrl = document.getElementById('input-target-url');
        if (inputUrl && session.start_url) inputUrl.value = session.start_url;

        const scopeEl = document.getElementById('input-crawl-scope');
        if (scopeEl && session.scope) scopeEl.value = session.scope;

        const travEl = document.getElementById('input-traversal-mode');
        if (travEl && session.traversal_mode) travEl.value = session.traversal_mode;

        const depthEl = document.getElementById('input-max-depth');
        if (depthEl && session.max_depth) depthEl.value = session.max_depth;

        const pagesEl = document.getElementById('input-max-pages');
        if (pagesEl && session.max_pages) pagesEl.value = session.max_pages;

        // Standalone PDF toggle
        const pdfCb = document.getElementById('toggle-pdf-only');
        if (pdfCb) {
            pdfCb.checked = Boolean(session.pdf_only);
            togglePdfOnlyState(false);
        }

        // Restore crawlerState
        crawlerState.currentSessionId = session.id;
        crawlerState.currentSessionName = session.name || 'Session';
        crawlerState.currentSessionStatus = session.status || 'ready';
        crawlerState.scope = session.scope || 'internal';
        crawlerState.pdfOnly = Boolean(session.pdf_only);
        crawlerState.traversalMode = session.traversal_mode || 'dfs';
        crawlerState.maxDepth = parseInt(session.max_depth) || 8;
        crawlerState.maxPages = parseInt(session.max_pages) || 50;

        crawlerState.scannedPagesCount = session.scanned_pages_count || 0;
        crawlerState.emailsFoundCount = session.emails_found_count || 0;
        crawlerState.docsParsedCount = session.docs_parsed_count || 0;

        crawlerState.primary_queue = Array.isArray(session.primary_queue) ? [...session.primary_queue] : [];
        crawlerState.visited_urls = new Set(Array.isArray(session.visited_urls) ? session.visited_urls : []);
        crawlerState.scrapedEmailsList = Array.isArray(session.scraped_emails) ? [...session.scraped_emails] : [];
        crawlerState.visitedLog = Array.isArray(session.visited_log) ? [...session.visited_log] : [];

        // Render tables and stats
        updateStats();
        renderEmailsTable();
        renderQueueTable();
        renderVisitedLogTable();
        updateSessionBadge(session.status || 'ready');

        // Button state
        const startBtnText = document.getElementById('txt-start-btn');
        if (startBtnText) {
            if (crawlerState.primary_queue.length > 0 && crawlerState.scannedPagesCount > 0) {
                startBtnText.textContent = `Resume Crawl (${crawlerState.primary_queue.length} in queue)`;
            } else {
                startBtnText.textContent = 'Start Crawl';
            }
        }
        document.getElementById('btn-start').classList.remove('opacity-75', 'cursor-not-allowed');

        renderSessionDropdown();
        logToConsole(`Inspecting session "${session.name}" [${(session.status || 'READY').toUpperCase()}]: ${crawlerState.scrapedEmailsList.length} emails, ${crawlerState.scannedPagesCount} pages audited, ${crawlerState.primary_queue.length} items remaining in queue.`, 'info');
    }

    function renderVisitedLogTable() {
        const tbody = document.getElementById('visited-log-tbody');
        if (!tbody) return;

        if (!crawlerState.visitedLog || crawlerState.visitedLog.length === 0) {
            tbody.innerHTML = '<tr><td colspan="6" class="py-8 text-center text-gray-500 font-mono">No pages audited yet in this session.</td></tr>';
            return;
        }

        let html = '';
        [...crawlerState.visitedLog].reverse().slice(0, 100).forEach(item => {
            html += `
                <tr class="hover:bg-cyber-card/60 border-b border-cyber-border/20 text-gray-300">
                    <td class="py-2.5 px-4 text-gray-500 font-mono text-[11px]">${item.time || 'Logged'}</td>
                    <td class="py-2.5 px-4 truncate max-w-xs text-white">${item.url}</td>
                    <td class="py-2.5 px-4"><span class="px-1.5 py-0.5 rounded text-[9px] font-bold bg-cyber-bg border border-cyber-border text-cyan-400">${item.type}</span></td>
                    <td class="py-2.5 px-4 font-bold ${item.emailCount > 0 ? 'text-brand-400' : 'text-gray-500'}">${item.emailCount}</td>
                    <td class="py-2.5 px-4 text-gray-300">${item.status}</td>
                    <td class="py-2.5 px-4 text-gray-500 text-[10px]">${item.source}</td>
                </tr>
            `;
        });
        tbody.innerHTML = html;
    }

    // ================= TOGGLE CARD HELPERS =================
    function togglePdfOnlyFromCard() {
        const cb = document.getElementById('toggle-pdf-only');
        if (cb) { cb.checked = !cb.checked; togglePdfOnlyState(); }
    }
    function togglePdfOnlyState(triggerAutoSave = true) {
        const cb = document.getElementById('toggle-pdf-only');
        crawlerState.pdfOnly = cb.checked;
        const badge = document.getElementById('badge-pdf-only-status');
        const label = document.getElementById('label-toggle-pdf-only');
        if (badge) {
            badge.textContent = cb.checked ? 'ENABLED' : 'DISABLED';
            badge.className = `px-2 py-0.5 text-[10px] font-bold rounded ${cb.checked ? 'bg-brand-500/20 text-brand-400 border border-brand-500/30' : 'bg-gray-700 text-gray-400 border border-gray-600'}`;
        }
        if (label) {
            label.className = `w-10 h-6 rounded-full ${cb.checked ? 'bg-brand-500 justify-end' : 'bg-gray-700 justify-start'} relative transition-colors btn-clickable flex items-center px-0.5`;
        }
        if (triggerAutoSave) {
            if (cb.checked) {
                logToConsole('[FILTER ACTIVATED] PDF Files Only enabled. Emails will strictly be extracted from PDF documents.', 'doc');
            } else {
                logToConsole('[FILTER DEACTIVATED] PDF Files Only disabled. Web HTML emails will also be extracted.', 'info');
            }
            scheduleSessionAutoSave();
        }
    }

    function toggleGoogleIndexFromCard() {
        const cb = document.getElementById('toggle-google-index');
        if (cb) { cb.checked = !cb.checked; toggleGoogleIndexState(); }
    }
    function toggleGoogleIndexState() {
        const cb = document.getElementById('toggle-google-index');
        crawlerState.googleIndexFilter = cb.checked;
        const badge = document.getElementById('badge-google-index-status');
        const label = document.getElementById('label-toggle-google-index');
        if (badge) badge.textContent = cb.checked ? 'ENABLED' : 'DISABLED';
        if (label) label.className = `w-10 h-6 rounded-full ${cb.checked ? 'bg-brand-500 justify-end' : 'bg-gray-700 justify-start'} relative transition-colors btn-clickable flex items-center px-0.5`;
        scheduleSessionAutoSave();
    }

    function toggleDeadLinkFromCard() {
        const cb = document.getElementById('toggle-dead-link');
        if (cb) { cb.checked = !cb.checked; toggleDeadLinkState(); }
    }
    function toggleDeadLinkState() {
        const cb = document.getElementById('toggle-dead-link');
        crawlerState.deadLinkFilter = cb.checked;
        const badge = document.getElementById('badge-dead-link-status');
        const label = document.getElementById('label-toggle-dead-link');
        if (badge) badge.textContent = cb.checked ? 'ENABLED' : 'DISABLED';
        if (label) label.className = `w-10 h-6 rounded-full ${cb.checked ? 'bg-brand-500 justify-end' : 'bg-gray-700 justify-start'} relative transition-colors btn-clickable flex items-center px-0.5`;
        scheduleSessionAutoSave();
    }

    function toggleOcrFromCard() {
        const cb = document.getElementById('toggle-ocr');
        if (cb) { cb.checked = !cb.checked; toggleOcrState(); }
    }
    function toggleOcrState() {
        const cb = document.getElementById('toggle-ocr');
        crawlerState.ocrEnabled = cb.checked;
        const badge = document.getElementById('badge-ocr-status');
        const label = document.getElementById('label-toggle-ocr');
        if (badge) badge.textContent = cb.checked ? 'ENABLED' : 'DISABLED';
        if (label) label.className = `w-10 h-6 rounded-full ${cb.checked ? 'bg-brand-500 justify-end' : 'bg-gray-700 justify-start'} relative transition-colors btn-clickable flex items-center px-0.5`;
        scheduleSessionAutoSave();
    }

    function toggleDocsFromCard() {
        const cb = document.getElementById('toggle-docs');
        if (cb) { cb.checked = !cb.checked; toggleDocsState(); }
    }
    function toggleDocsState() {
        const cb = document.getElementById('toggle-docs');
        crawlerState.docsEnabled = cb.checked;
        const badge = document.getElementById('badge-docs-status');
        const label = document.getElementById('label-toggle-docs');
        if (badge) badge.textContent = cb.checked ? 'ENABLED' : 'DISABLED';
        if (label) label.className = `w-10 h-6 rounded-full ${cb.checked ? 'bg-brand-500 justify-end' : 'bg-gray-700 justify-start'} relative transition-colors btn-clickable flex items-center px-0.5`;
        scheduleSessionAutoSave();
    }
</script>
</body>
</html>
"""

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port, debug=True)