EMBEDDED_SCRIPT_JS

Constant EMBEDDED_SCRIPT_JS 

Source
pub const EMBEDDED_SCRIPT_JS: &str = r#"
// MemScope Dashboard JavaScript - Clean rendering for clean_dashboard.html
// This file contains comprehensive functions for memory analysis dashboard

// Global data store - will be populated by HTML template
window.analysisData = window.analysisData || {};

// FFI dashboard render style: 'svg' to mimic Rust SVG dashboard, 'cards' for card-based UI
const FFI_STYLE = 'svg';

// Initialize all dashboard components - Clean layout
function initCleanTemplate() {
    console.log('๐Ÿš€ Initializing MemScope Dashboard...');
    console.log('๐Ÿ“Š Available data:', Object.keys(window.analysisData||{}));
    const data = window.analysisData || {};

    // KPI
    updateKPICards(data);

    // Memory by type (Chart.js)
    const typeChartEl = document.getElementById('typeChart');
    if (typeChartEl) {
        const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
        const byType = {};
        for (const a of allocs) { const t=a.type_name||'Unknown'; byType[t]=(byType[t]||0)+(a.size||0); }
        const top = Object.entries(byType).sort((a,b)=>b[1]-a[1]).slice(0,10);
        if (top.length>0) {
            const ctx = typeChartEl.getContext('2d');
            if (window.chartInstances['clean-type']) window.chartInstances['clean-type'].destroy();
            window.chartInstances['clean-type'] = new Chart(ctx, {
                type:'bar',
                data:{ labels: top.map(x=>x[0]), datasets:[{ label:'Bytes', data: top.map(x=>x[1]), backgroundColor:'#3b82f6' }] },
                options:{ responsive:true, plugins:{legend:{display:false}}, scales:{y:{beginAtZero:true}} }
            });
            const legend = document.getElementById('typeLegend');
            if (legend) legend.innerHTML = top.map(([n,v])=>`<span class="pill">${n}: ${formatBytes(v)}</span>`).join(' ');
        }
    }

    // Timeline (Chart.js)
    const timelineEl = document.getElementById('timelineChart');
    if (timelineEl) {
        const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
        const rawTimeline = (data.memory_analysis && data.memory_analysis.memory_timeline) || [];
        let points = [];
        if (rawTimeline.length) {
            points = rawTimeline.map((p,i)=>({ x:i, y:(p.memory_usage||0) }));
        } else {
            const sorted = allocs.slice().sort((a,b)=>(a.timestamp_alloc||0)-(b.timestamp_alloc||0));
            let cum=0; const step=Math.max(1, Math.floor(sorted.length/50));
            for(let i=0;i<sorted.length;i+=step){ cum += sorted[i].size||0; points.push({x:i, y:cum}); }
        }
        if (points.length>1) {
            const ctx = timelineEl.getContext('2d');
            if (window.chartInstances['clean-timeline']) window.chartInstances['clean-timeline'].destroy();
            window.chartInstances['clean-timeline'] = new Chart(ctx, {
                type:'line',
                data:{ labels: points.map(p=>p.x), datasets:[{ label:'Cumulative', data: points.map(p=>p.y), borderColor:'#ef4444', backgroundColor:'rgba(239,68,68,0.1)', fill:true, tension:0.25 }] },
                options:{ responsive:true, plugins:{legend:{display:false}}, scales:{y:{beginAtZero:true}} }
            });
        }
    }

    // Treemap
    const treemapEl = document.getElementById('treemap');
    if (treemapEl) {
        const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
        treemapEl.innerHTML = createTreemapVisualization(allocs);
    }

    // Growth
    const growthEl = document.getElementById('growth');
    if (growthEl) {
        const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
        const total = allocs.reduce((s,a)=>s+(a.size||0),0);
        growthEl.innerHTML = createAdvancedGrowthTrendVisualization(allocs, Math.max(1,total));
    }

    // Lifetimes (top 10)
    const lifetimesEl = document.getElementById('lifetimes');
    if (lifetimesEl) {
        const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
        const top = allocs.filter(a=>a.var_name && a.var_name!=='unknown').sort((a,b)=>(b.size||0)-(a.size||0)).slice(0,10);
        lifetimesEl.innerHTML = top.map(a=>`<div class="flex items-center justify-between py-1 border-b">
            <div class="text-xs font-medium">${a.var_name}</div>
            <div class="text-xs text-gray-500">${formatBytes(a.size||0)}</div>
        </div>`).join('');
    }

    // Update memory allocation table
    updateAllocationsTable(data);
    
    // Update unsafe risk table
    updateUnsafeTable(data);

    // Initialize all charts and visualizations
    initCharts(data);
    
    // Initialize lifecycle visualization
    initLifetimeVisualization(data);

    // Complex types
    const complexSummary = document.getElementById('complexSummary');
    if (complexSummary) {
        const ct = data.complex_types || {};
        const s = ct.summary || {};
        const items = [
            {label:'Complex Types', val: s.total_complex_types||0},
            {label:'Smart Pointers', val: s.smart_pointers_count||0},
            {label:'Collections', val: s.collections_count||0},
            {label:'Generic Types', val: s.generic_types_count||s.generic_type_count||0},
        ];
        complexSummary.innerHTML = items.map(x=>`<div class="pill">${x.label}: ${x.val}</div>`).join('');
        document.getElementById('complexSmart')?.replaceChildren();
        document.getElementById('complexCollections')?.replaceChildren();
        document.getElementById('complexGenerics')?.replaceChildren();
    }

    // Variable relationships
    const graphEl = document.getElementById('graph');
    if (graphEl) {
        // reuse our D3 relationship graph init but mount into #graph
        const container = document.createElement('div');
        container.id = 'variable-graph-container';
        container.style.width = '100%';
        container.style.height = '260px';
        graphEl.appendChild(container);
        try { initVariableGraph(); } catch(e) { console.warn('variable graph init failed', e); }
    }

    // Security violations
    const secEl = document.getElementById('security');
    if (secEl) {
        const root = data.unsafe_ffi || {};
        const list = root.security_hotspots || root.unsafe_reports || [];
        secEl.innerHTML = (list||[]).slice(0,12).map(h=>{
            const score = h.risk_score || h.risk_assessment?.confidence_score || 0;
            const level = h.risk_level || h.risk_assessment?.risk_level || 'Unknown';
            const width = Math.min(100, Math.round((score||0)*10));
            return `<div class="card">
              <div class="text-sm font-semibold">${h.location||h.report_id||'Unknown'}</div>
              <div class="text-xs text-gray-500">${h.description||h.source?.type||''}</div>
              <div class="mt-2 bg-red-100 h-2 rounded"><div style="width:${width}%; background:#ef4444; height:100%" class="rounded"></div></div>
              <div class="text-xs text-gray-500 mt-1">Risk: ${level} (${score})</div>
            </div>`;
        }).join('') || '<div class="muted">No security violations</div>';
    }
}
function initializeDashboard() {
    console.log('๐Ÿš€ Initializing MemScope dashboard...');
    console.log('๐Ÿ“Š Available data:', Object.keys(window.analysisData || {}));

    // Initialize theme system first
    initThemeToggle();

    // Initialize enhanced dashboard with comprehensive data
    initEnhancedSummaryStats();
    
    // Initialize all components
    initSummaryStats();
    initCharts();
    initMemoryUsageAnalysis();
    initLifetimeVisualization();
    initFFIVisualization();
    initMemoryFragmentation();
    initMemoryGrowthTrends();
    initAllocationsTable();
    initVariableGraph();
}

// Initialize theme toggle functionality
function initThemeToggle() {
    const themeToggle = document.getElementById('theme-toggle');
    const html = document.documentElement;

    // Check for saved theme preference or default to light mode
    const savedTheme = localStorage.getItem('memscope-theme') || 'light';

    console.log('๐ŸŽจ Initializing theme system, saved theme:', savedTheme);

    // Apply initial theme
    applyTheme(savedTheme === 'dark');

    if (themeToggle) {
        themeToggle.addEventListener('click', () => {
            const isDark = html.classList.contains('dark');

            if (isDark) {
                applyTheme(false);
                localStorage.setItem('memscope-theme', 'light');
                console.log('๐ŸŽจ Theme switched to: light mode');
            } else {
                applyTheme(true);
                localStorage.setItem('memscope-theme', 'dark');
                console.log('๐ŸŽจ Theme switched to: dark mode');
            }
        });

        console.log('โœ… Theme toggle initialized successfully');
    } else {
        console.warn('โš ๏ธ Theme toggle button not found');
    }
}

// Apply theme to all modules
function applyTheme(isDark) {
    const html = document.documentElement;
    const body = document.body;

    if (isDark) {
        html.classList.remove('light');
        html.classList.add('dark');
        body.classList.add('dark');
    } else {
        html.classList.remove('dark');
        html.classList.add('light');
        body.classList.remove('dark');
    }

    // Force immediate repaint
    html.style.display = 'none';
    html.offsetHeight; // Trigger reflow
    html.style.display = '';

    // Apply theme to all modules that need explicit dark mode support
    applyThemeToAllModules(isDark);

    // Update theme toggle button icon
    updateThemeToggleIcon(isDark);

    // Destroy existing charts before reinitializing
    destroyAllCharts();

    // Reinitialize charts to apply theme changes
    setTimeout(() => {
        initCharts();
        initFFIRiskChart();
    }, 100);
}

// Update theme toggle button icon
function updateThemeToggleIcon(isDark) {
    const themeToggle = document.getElementById('theme-toggle');
    if (themeToggle) {
        const icon = themeToggle.querySelector('i');
        if (icon) {
            if (isDark) {
                icon.className = 'fa fa-sun';
            } else {
                icon.className = 'fa fa-moon';
            }
        }
    }
}

// Global chart instances storage
window.chartInstances = {};

// Destroy all existing charts
function destroyAllCharts() {
    Object.keys(window.chartInstances).forEach(chartId => {
        if (window.chartInstances[chartId]) {
            window.chartInstances[chartId].destroy();
            delete window.chartInstances[chartId];
        }
    });
}

// Apply theme to specific modules
function applyThemeToAllModules(isDark) {
    const modules = [
        'memory-usage-analysis',
        'generic-types-details',
        'variable-relationship-graph',
        'complex-type-analysis',
        'memory-optimization-recommendations',
        'unsafe-ffi-data'
    ];

    modules.forEach(moduleId => {
        const module = document.getElementById(moduleId);
        if (module) {
            module.classList.toggle('dark', isDark);
        }
    });

    // Also apply to any table elements that might need it
    const tables = document.querySelectorAll('table');
    tables.forEach(table => {
        table.classList.toggle('dark', isDark);
    });

    // Apply to any chart containers
    const chartContainers = document.querySelectorAll('canvas');
    chartContainers.forEach(container => {
        if (container.parentElement) {
            container.parentElement.classList.toggle('dark', isDark);
        }
    });
}

// Initialize summary statistics
function initSummaryStats() {
    console.log('๐Ÿ“Š Initializing summary stats...');

    const data = window.analysisData;

    // Update complex types count
    const complexTypesCount = data.complex_types?.summary?.total_complex_types || 0;
    updateElement('total-complex-types', complexTypesCount);

    // Update total allocations
    const totalAllocations = data.memory_analysis?.allocations?.length || 0;
    updateElement('total-allocations', totalAllocations);

    // Update generic types count
    const genericTypeCount = data.complex_types?.summary?.generic_type_count || 0;
    updateElement('generic-type-count', genericTypeCount);

    // Update unsafe FFI count
    const unsafeFFICount = data.unsafe_ffi?.enhanced_ffi_data?.length || 0;
    updateElement('unsafe-ffi-count', unsafeFFICount);

    // Update category counts
    const smartPointersCount = data.complex_types?.categorized_types?.smart_pointers?.length || 0;
    const collectionsCount = data.complex_types?.categorized_types?.collections?.length || 0;
    const primitivesCount = 0; // Calculate from data if available

    updateElement('smart-pointers-count', smartPointersCount);
    updateElement('collections-count', collectionsCount);
    updateElement('primitives-count', primitivesCount);
}

// Initialize charts - simplified
function initCharts() {
    console.log('๐Ÿ“Š Initializing charts...');

    // Initialize memory distribution chart
    initMemoryDistributionChart();

    // Initialize allocation size chart
    initAllocationSizeChart();
}



// Initialize memory distribution chart
function initMemoryDistributionChart() {
    const ctx = document.getElementById('memory-distribution-chart');
    if (!ctx) return;

    const allocations = window.analysisData.memory_analysis?.allocations || [];
    const typeDistribution = {};

    allocations.forEach(alloc => {
        const type = alloc.type_name || 'System Allocation';
        typeDistribution[type] = (typeDistribution[type] || 0) + alloc.size;
    });

    const sortedTypes = Object.entries(typeDistribution)
        .sort(([, a], [, b]) => b - a)
        .slice(0, 10);

    const isDark = document.documentElement.classList.contains('dark');

    // Destroy existing chart if it exists
    if (window.chartInstances['memory-distribution-chart']) {
        window.chartInstances['memory-distribution-chart'].destroy();
    }

    window.chartInstances['memory-distribution-chart'] = new Chart(ctx, {
        type: 'bar',
        data: {
            labels: sortedTypes.map(([type]) => formatTypeName(type)),
            datasets: [{
                label: 'Memory Usage (bytes)',
                data: sortedTypes.map(([, size]) => size),
                backgroundColor: '#3b82f6'
            }]
        },
        options: {
            responsive: true,
            maintainAspectRatio: false,
            plugins: {
                legend: {
                    labels: {
                        color: isDark ? '#ffffff' : '#374151'
                    }
                }
            },
            scales: {
                x: {
                    ticks: {
                        color: isDark ? '#d1d5db' : '#6b7280'
                    },
                    grid: {
                        color: isDark ? '#374151' : '#e5e7eb'
                    }
                },
                y: {
                    beginAtZero: true,
                    ticks: {
                        color: isDark ? '#d1d5db' : '#6b7280',
                        callback: function (value) {
                            return formatBytes(value);
                        }
                    },
                    grid: {
                        color: isDark ? '#374151' : '#e5e7eb'
                    }
                }
            }
        }
    });
}

// Initialize allocation size chart
function initAllocationSizeChart() {
    const ctx = document.getElementById('allocation-size-chart');
    if (!ctx) return;

    const allocations = window.analysisData.memory_analysis?.allocations || [];
    const sizeDistribution = {
        'Tiny (< 64B)': 0,
        'Small (64B - 1KB)': 0,
        'Medium (1KB - 64KB)': 0,
        'Large (64KB - 1MB)': 0,
        'Huge (> 1MB)': 0
    };

    allocations.forEach(alloc => {
        const size = alloc.size || 0;
        if (size < 64) sizeDistribution['Tiny (< 64B)']++;
        else if (size < 1024) sizeDistribution['Small (64B - 1KB)']++;
        else if (size < 65536) sizeDistribution['Medium (1KB - 64KB)']++;
        else if (size < 1048576) sizeDistribution['Large (64KB - 1MB)']++;
        else sizeDistribution['Huge (> 1MB)']++;
    });

    // Destroy existing chart if it exists
    if (window.chartInstances['allocation-size-chart']) {
        window.chartInstances['allocation-size-chart'].destroy();
    }

    window.chartInstances['allocation-size-chart'] = new Chart(ctx, {
        type: 'pie',
        data: {
            labels: Object.keys(sizeDistribution),
            datasets: [{
                data: Object.values(sizeDistribution),
                backgroundColor: ['#10b981', '#3b82f6', '#f59e0b', '#ef4444', '#7c2d12']
            }]
        },
        options: {
            responsive: true,
            maintainAspectRatio: false,
            plugins: {
                legend: {
                    labels: {
                        color: document.documentElement.classList.contains('dark') ? '#ffffff' : '#374151'
                    }
                }
            }
        }
    });
}



// Process memory analysis data with validation and fallback
function processMemoryAnalysisData(rawData) {
    if (!rawData || !rawData.memory_analysis) {
        console.warn('โš ๏ธ No memory analysis data found, generating fallback data');
        return generateFallbackMemoryData();
    }

    const memoryData = rawData.memory_analysis;
    const processedData = {
        stats: {
            total_allocations: memoryData.stats?.total_allocations || 0,
            active_allocations: memoryData.stats?.active_allocations || 0,
            total_memory: memoryData.stats?.total_memory || 0,
            active_memory: memoryData.stats?.active_memory || 0
        },
        allocations: memoryData.allocations || [],
        trends: {
            peak_memory: memoryData.peak_memory || 0,
            growth_rate: memoryData.growth_rate || 0,
            fragmentation_score: memoryData.fragmentation_score || 0
        }
    };

    // Calculate additional metrics if not present
    if (processedData.allocations.length > 0) {
        const totalSize = processedData.allocations.reduce((sum, alloc) => sum + (alloc.size || 0), 0);
        if (!processedData.stats.total_memory) {
            processedData.stats.total_memory = totalSize;
        }
        if (!processedData.stats.total_allocations) {
            processedData.stats.total_allocations = processedData.allocations.length;
        }
    }

    console.log('โœ… Processed memory analysis data:', processedData);
    return processedData;
}

// Generate fallback memory data when real data is unavailable
function generateFallbackMemoryData() {
    console.log('๐Ÿ”„ Generating fallback memory data');

    return {
        stats: {
            total_allocations: 0,
            active_allocations: 0,
            total_memory: 0,
            active_memory: 0
        },
        allocations: [],
        trends: {
            peak_memory: 0,
            growth_rate: 0,
            fragmentation_score: 0
        },
        isFallback: true
    };
}

// Validate memory data structure
function validateMemoryData(data) {
    if (!data) return false;

    const hasStats = data.stats && typeof data.stats === 'object';
    const hasAllocations = Array.isArray(data.allocations);

    return hasStats && hasAllocations;
}

// Calculate memory statistics from allocations
function calculateMemoryStatistics(allocations) {
    if (!Array.isArray(allocations) || allocations.length === 0) {
        return {
            totalSize: 0,
            averageSize: 0,
            largestAllocation: 0,
            userAllocations: 0,
            systemAllocations: 0
        };
    }

    const totalSize = allocations.reduce((sum, alloc) => sum + (alloc.size || 0), 0);
    const averageSize = totalSize / allocations.length;
    const largestAllocation = Math.max(...allocations.map(alloc => alloc.size || 0));

    const userAllocations = allocations.filter(alloc =>
        alloc.var_name && alloc.var_name !== 'unknown' &&
        alloc.type_name && alloc.type_name !== 'unknown'
    ).length;

    const systemAllocations = allocations.length - userAllocations;

    return {
        totalSize,
        averageSize,
        largestAllocation,
        userAllocations,
        systemAllocations
    };
}

// Initialize memory usage analysis with enhanced SVG-style visualization
function initMemoryUsageAnalysis() {
    const container = document.getElementById('memory-usage-analysis');
    if (!container) return;

    // Process memory data with validation
    const memoryData = processMemoryAnalysisData(window.analysisData);
    const allocations = memoryData.allocations;

    if (allocations.length === 0 || memoryData.isFallback) {
        container.innerHTML = createEnhancedEmptyState();
        return;
    }

    // Calculate comprehensive statistics
    const stats = calculateMemoryStatistics(allocations);
    const totalMemory = stats.totalSize;

    const userAllocations = allocations.filter(alloc =>
        alloc.var_name && alloc.var_name !== 'unknown' &&
        alloc.type_name && alloc.type_name !== 'unknown'
    );
    const systemAllocations = allocations.filter(alloc =>
        !alloc.var_name || alloc.var_name === 'unknown' ||
        !alloc.type_name || alloc.type_name === 'unknown'
    );

    const userMemory = userAllocations.reduce((sum, alloc) => sum + (alloc.size || 0), 0);
    const systemMemory = systemAllocations.reduce((sum, alloc) => sum + (alloc.size || 0), 0);

    // Create enhanced SVG-style visualization
    container.innerHTML = createMemoryAnalysisSVG(stats, allocations, userMemory, systemMemory, totalMemory);
}

// Create enhanced empty state with better styling
function createEnhancedEmptyState() {
    return `
        <div class="h-full flex items-center justify-center">
            <div class="text-center p-8 bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-800 dark:to-gray-700 rounded-xl border-2 border-dashed border-blue-200 dark:border-gray-600">
                <div class="mb-4">
                    <svg class="w-16 h-16 mx-auto text-blue-400 dark:text-blue-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
                    </svg>
                </div>
                <h4 class="text-lg font-semibold mb-2 text-gray-800 dark:text-gray-200">Memory Analysis Ready</h4>
                <p class="text-sm text-gray-600 dark:text-gray-400 mb-2">No memory allocation data found for analysis</p>
                <p class="text-xs text-gray-500 dark:text-gray-500">Run your application with memory tracking enabled to see detailed analysis</p>
            </div>
        </div>
    `;
}

// Create comprehensive SVG-style memory analysis visualization inspired by the memoryAnalysis.svg
function createMemoryAnalysisSVG(stats, allocations, userMemory, systemMemory, totalMemory) {
    const userPercentage = totalMemory > 0 ? (userMemory / totalMemory * 100) : 0;
    const systemPercentage = totalMemory > 0 ? (systemMemory / totalMemory * 100) : 0;

    // Calculate comprehensive efficiency metrics
    const efficiency = totalMemory > 0 ? Math.min(100, (userMemory / totalMemory * 100)) : 0;
    const reclamationRate = allocations.length > 0 ? Math.min(100, ((allocations.filter(a => a.timestamp_dealloc).length / allocations.length) * 100)) : 0;
    const fragmentation = Math.min(100, (allocations.length / Math.max(1, totalMemory / 1024)) * 10);

    // Advanced size distribution analysis
    const sizeDistribution = {
        tiny: allocations.filter(a => a.size < 64).length,
        small: allocations.filter(a => a.size >= 64 && a.size < 1024).length,
        medium: allocations.filter(a => a.size >= 1024 && a.size < 65536).length,
        large: allocations.filter(a => a.size >= 65536).length
    };

    // Calculate median and P95 sizes
    const sizes = allocations.map(a => a.size || 0).sort((a, b) => a - b);
    const medianSize = sizes.length > 0 ? sizes[Math.floor(sizes.length / 2)] : 0;
    const p95Size = sizes.length > 0 ? sizes[Math.floor(sizes.length * 0.95)] : 0;

    return `
        <div class="bg-white dark:bg-gray-800 rounded-xl shadow-lg overflow-hidden">
            <!-- Header with gradient background -->
            <div class="bg-gradient-to-r from-blue-600 to-purple-600 text-white p-6">
                <div class="text-center">
                    <h2 class="text-3xl font-bold mb-2">Rust Memory Usage Analysis</h2>
                    <p class="text-blue-100 uppercase tracking-wider text-sm">Key Performance Metrics</p>
                </div>
            </div>

            <div class="p-6">
                <!-- Key Performance Metrics Grid -->
                <div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-8 gap-4 mb-8">
                    ${createAdvancedMetricCard('Active Memory', formatBytes(userMemory), Math.round(userPercentage), '#3498db', 'MEDIUM')}
                    ${createAdvancedMetricCard('Peak Memory', formatBytes(totalMemory), 100, '#e74c3c', 'HIGH')}
                    ${createAdvancedMetricCard('Active Allocs', allocations.length, 100, '#2ecc71', 'HIGH')}
                    ${createAdvancedMetricCard('Reclamation', reclamationRate.toFixed(1) + '%', Math.round(reclamationRate), '#f39c12', reclamationRate > 70 ? 'OPTIMAL' : 'MEDIUM')}
                    ${createAdvancedMetricCard('Efficiency', efficiency.toFixed(1) + '%', Math.round(efficiency), '#9b59b6', efficiency > 70 ? 'OPTIMAL' : 'MEDIUM')}
                    ${createAdvancedMetricCard('Median Size', formatBytes(medianSize), Math.min(100, medianSize / 1024), '#1abc9c', medianSize < 100 ? 'OPTIMAL' : 'MEDIUM')}
                    ${createAdvancedMetricCard('P95 Size', formatBytes(p95Size), Math.min(100, p95Size / 1024), '#e67e22', p95Size < 1024 ? 'OPTIMAL' : 'MEDIUM')}
                    ${createAdvancedMetricCard('Fragmentation', fragmentation.toFixed(1) + '%', Math.round(fragmentation), '#95a5a6', fragmentation < 30 ? 'OPTIMAL' : 'MEDIUM')}
                </div>


                <!-- Memory Usage by Type - Enhanced Treemap -->
                <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6 mb-8 border border-gray-200 dark:border-gray-600">
                    <h3 class="text-xl font-semibold mb-4 text-gray-800 dark:text-white text-center">Memory Usage by Type - Treemap Visualization</h3>
                    <div class="bg-gray-100 dark:bg-gray-600 rounded-lg p-4 h-64 relative overflow-hidden">
                        ${createAdvancedTreemapVisualization(allocations, totalMemory)}
                    </div>
                    <div class="mt-4 grid grid-cols-3 gap-4 text-xs">
                        <div class="flex items-center">
                            <div class="w-3 h-3 bg-blue-500 rounded mr-2"></div>
                            <span class="text-gray-600 dark:text-gray-300">Collections</span>
                        </div>
                        <div class="flex items-center">
                            <div class="w-3 h-3 bg-green-500 rounded mr-2"></div>
                            <span class="text-gray-600 dark:text-gray-300">Basic Types</span>
                        </div>
                        <div class="flex items-center">
                            <div class="w-3 h-3 bg-gray-500 rounded mr-2"></div>
                            <span class="text-gray-600 dark:text-gray-300">System</span>
                        </div>
                    </div>
                </div>

                <!-- Advanced Analysis Grid -->
                <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
                    <!-- Memory Fragmentation Analysis -->
                    <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6 border border-gray-200 dark:border-gray-600">
                        <h3 class="text-xl font-semibold mb-4 text-gray-800 dark:text-white text-center">Memory Fragmentation Analysis</h3>
                        <div class="space-y-4">
                            ${createAdvancedFragmentationBar('Tiny (0-64B)', sizeDistribution.tiny, allocations.length, '#27ae60')}
                            ${createAdvancedFragmentationBar('Small (65B-1KB)', sizeDistribution.small, allocations.length, '#f39c12')}
                            ${createAdvancedFragmentationBar('Medium (1KB-64KB)', sizeDistribution.medium, allocations.length, '#e74c3c')}
                            ${createAdvancedFragmentationBar('Large (>64KB)', sizeDistribution.large, allocations.length, '#8e44ad')}
                        </div>
                    </div>

                    <!-- Call Stack Analysis -->
                    <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6 border border-gray-200 dark:border-gray-600">
                        <h3 class="text-xl font-semibold mb-4 text-gray-800 dark:text-white text-center">Call Stack Analysis</h3>
                        <div class="space-y-3 max-h-64 overflow-y-auto">
                            ${createCallStackAnalysis(allocations)}
                        </div>
                    </div>
                </div>

                <!-- Memory Statistics Summary -->
                <div class="mt-8 bg-gray-50 dark:bg-gray-700 rounded-lg p-6 border border-gray-200 dark:border-gray-600">
                    <h3 class="text-xl font-semibold mb-4 text-gray-800 dark:text-white text-center">Memory Statistics</h3>
                    <div class="grid grid-cols-3 gap-4 text-sm text-center">
                        <div>
                            <span class="text-gray-600 dark:text-gray-400">Peak Memory:</span>
                            <span class="font-semibold text-red-600 dark:text-red-400 ml-2">${formatBytes(totalMemory)}</span>
                        </div>
                        <div>
                            <span class="text-gray-600 dark:text-gray-400">Fragmentation:</span>
                            <span class="font-semibold text-orange-600 dark:text-orange-400 ml-2">${fragmentation.toFixed(1)}%</span>
                        </div>
                        <div>
                            <span class="text-gray-600 dark:text-gray-400">Efficiency:</span>
                            <span class="font-semibold text-purple-600 dark:text-purple-400 ml-2">${efficiency.toFixed(1)}%</span>
                        </div>
                    </div>
                </div>

                <!-- Variable Allocation Timeline -->
                <div class="mt-8 bg-gray-50 dark:bg-gray-700 rounded-lg p-6 border border-gray-200 dark:border-gray-600">
                    <h3 class="text-xl font-semibold mb-4 text-gray-800 dark:text-white text-center">Variable Allocation Timeline</h3>
                    <div class="space-y-3 max-h-64 overflow-y-auto">
                        ${createVariableAllocationTimeline(allocations)}
                    </div>
                </div>
            </div>
        </div>
    `;
}

// Create metric card with circular progress indicator
function createMetricCard(title, value, percentage, color, status) {
    const circumference = 2 * Math.PI * 25;
    const strokeDasharray = circumference;
    const strokeDashoffset = circumference - (percentage / 100) * circumference;

    const statusColors = {
        'OPTIMAL': '#27ae60',
        'MEDIUM': '#f39c12',
        'HIGH': '#e74c3c'
    };

    return `
        <div class="bg-white dark:bg-gray-700 rounded-lg p-4 shadow-sm hover:shadow-md transition-shadow">
            <div class="flex items-center justify-between">
                <div class="flex-1">
                    <p class="text-xs font-medium text-gray-600 dark:text-gray-400 uppercase">${title}</p>
                    <p class="text-lg font-bold text-gray-900 dark:text-white">${value}</p>
                    <div class="flex items-center mt-1">
                        <div class="w-2 h-2 rounded-full mr-2" style="background-color: ${statusColors[status]}"></div>
                        <span class="text-xs font-semibold" style="color: ${statusColors[status]}">${status}</span>
                    </div>
                </div>
                <div class="relative w-12 h-12">
                    <svg class="w-12 h-12 transform -rotate-90" viewBox="0 0 60 60">
                        <circle cx='30' cy='30' r='25' stroke='#e5e7eb' stroke-width='6' fill='none' class='dark:stroke-gray-600'/>
                        <circle cx='30' cy='30' r='25' stroke='${color}' stroke-width='6' fill='none' 
                                stroke-dasharray='${strokeDasharray}' stroke-dashoffset='${strokeDashoffset}'
                                stroke-linecap='round' class='transition-all duration-500'/>
                    </svg>
                    <div class="absolute inset-0 flex items-center justify-center">
                        <span class="text-xs font-bold" style="color: ${color}">${Math.round(percentage)}%</span>
                    </div>
                </div>
            </div>
        </div>
    `;
}

// Create timeline visualization
function createTimelineVisualization(allocations) {
    if (allocations.length === 0) return '<div class="flex items-center justify-center h-full text-gray-400">No timeline data</div>';

    const sortedAllocs = allocations.sort((a, b) => (a.timestamp_alloc || 0) - (b.timestamp_alloc || 0));
    const minTime = sortedAllocs[0]?.timestamp_alloc || 0;
    const maxTime = sortedAllocs[sortedAllocs.length - 1]?.timestamp_alloc || minTime + 1;
    const timeRange = maxTime - minTime || 1;

    return sortedAllocs.slice(0, 20).map((alloc, index) => {
        const position = ((alloc.timestamp_alloc - minTime) / timeRange) * 100;
        const height = Math.min(80, Math.max(4, (alloc.size / 1024) * 20));
        const color = alloc.var_name && alloc.var_name !== 'unknown' ? '#3498db' : '#95a5a6';

        return `
            <div class="absolute bottom-0 bg-opacity-80 rounded-t transition-all hover:bg-opacity-100" 
                 style="left: ${position}%; width: 4px; height: ${height}%; background-color: ${color};"
                 title="${alloc.var_name || 'System'}: ${formatBytes(alloc.size)}">
            </div>
        `;
    }).join('');
}

// Create treemap-style visualization
function createTreemapVisualization(allocations) {
    const typeGroups = {};
    allocations.forEach(alloc => {
        const type = alloc.type_name || 'System';
        if (!typeGroups[type]) {
            typeGroups[type] = { count: 0, size: 0 };
        }
        typeGroups[type].count++;
        typeGroups[type].size += alloc.size || 0;
    });

    const sortedTypes = Object.entries(typeGroups)
        .sort(([, a], [, b]) => b.size - a.size)
        .slice(0, 8);

    const totalSize = sortedTypes.reduce((sum, [, data]) => sum + data.size, 0);

    let currentX = 0;
    return sortedTypes.map(([type, data], index) => {
        const width = totalSize > 0 ? (data.size / totalSize) * 100 : 12.5;
        const color = getTypeColor(type, index);
        const result = `
            <div class="absolute h-full transition-all hover:brightness-110 cursor-pointer rounded" 
                 style="left: ${currentX}%; width: ${width}%; background-color: ${color};"
                 title="${type}: ${formatBytes(data.size)} (${data.count} allocs)">
                <div class="p-2 h-full flex flex-col justify-center text-white text-xs font-semibold text-center">
                    <div class="truncate">${type.length > 10 ? type.substring(0, 8) + '...' : type}</div>
                    <div class="text-xs opacity-90">${formatBytes(data.size)}</div>
                </div>
            </div>
        `;
        currentX += width;
        return result;
    }).join('');
}

// Create fragmentation bar
function createFragmentationBar(label, count, total, color) {
    const percentage = total > 0 ? (count / total) * 100 : 0;
    return `
        <div class="flex items-center justify-between">
            <span class="text-sm font-medium text-gray-700 dark:text-gray-300 w-24">${label}</span>
            <div class="flex-1 mx-3">
                <div class="w-full bg-gray-200 dark:bg-gray-600 rounded-full h-4">
                    <div class="h-4 rounded-full transition-all duration-500" 
                         style="width: ${percentage}%; background-color: ${color}"></div>
                </div>
            </div>
            <span class="text-sm font-bold text-gray-900 dark:text-white w-12 text-right">${count}</span>
        </div>
    `;
}

// Create growth trend visualization
function createGrowthTrendVisualization(allocations) {
    if (allocations.length < 2) return '<div class="flex items-center justify-center h-full text-gray-400">Insufficient data</div>';

    const sortedAllocs = allocations.sort((a, b) => (a.timestamp_alloc || 0) - (b.timestamp_alloc || 0));
    const points = [];
    let cumulativeSize = 0;

    sortedAllocs.forEach((alloc, index) => {
        cumulativeSize += alloc.size || 0;
        if (index % Math.max(1, Math.floor(sortedAllocs.length / 10)) === 0) {
            points.push(cumulativeSize);
        }
    });

    const maxSize = Math.max(...points);

    return points.map((size, index) => {
        const x = (index / (points.length - 1)) * 100;
        const y = 100 - (size / maxSize) * 80;

        return `
            <div class="absolute w-2 h-2 bg-green-500 rounded-full transform -translate-x-1 -translate-y-1" 
                 style="left: ${x}%; top: ${y}%"
                 title="Memory: ${formatBytes(size)}">
            </div>
            ${index > 0 ? `
                <div class="absolute h-0.5 bg-green-500" 
                     style="left: ${((index - 1) / (points.length - 1)) * 100}%; 
                            top: ${100 - (points[index - 1] / maxSize) * 80}%; 
                            width: ${(100 / (points.length - 1))}%;
                            transform: rotate(${Math.atan2(y - (100 - (points[index - 1] / maxSize) * 80), 100 / (points.length - 1)) * 180 / Math.PI}deg);
                            transform-origin: left center;">
                </div>
            ` : ''}
        `;
    }).join('');
}

// Get color for type visualization
function getTypeColor(type, index) {
    const colors = [
        '#3498db', '#e74c3c', '#2ecc71', '#f39c12',
        '#9b59b6', '#1abc9c', '#e67e22', '#95a5a6'
    ];

    if (type.toLowerCase().includes('vec')) return '#3498db';
    if (type.toLowerCase().includes('string')) return '#f39c12';
    if (type.toLowerCase().includes('hash')) return '#e74c3c';
    if (type.toLowerCase().includes('btree')) return '#2ecc71';

    return colors[index % colors.length];
}

// Create advanced metric card with enhanced styling
function createAdvancedMetricCard(title, value, percentage, color, status) {
    const circumference = 2 * Math.PI * 20;
    const strokeDasharray = circumference;
    const strokeDashoffset = circumference - (percentage / 100) * circumference;

    const statusColors = {
        'OPTIMAL': '#27ae60',
        'MEDIUM': '#f39c12',
        'HIGH': '#e74c3c'
    };

    return `
        <div class="bg-white dark:bg-gray-700 rounded-lg p-3 shadow-sm hover:shadow-md transition-all border border-gray-200 dark:border-gray-600">
            <div class="flex flex-col items-center">
                <div class="relative w-10 h-10 mb-2">
                    <svg class="w-10 h-10 transform -rotate-90" viewBox="0 0 50 50">
                        <circle cx='25' cy='25' r='20' stroke='#e5e7eb' stroke-width='4' fill='none' class='dark:stroke-gray-600'/>
                        <circle cx='25' cy='25' r='20' stroke='${color}' stroke-width='4' fill='none' 
                                stroke-dasharray='${strokeDasharray}' stroke-dashoffset='${strokeDashoffset}'
                                stroke-linecap='round' class='transition-all duration-500'/>
                    </svg>
                    <div class="absolute inset-0 flex items-center justify-center">
                        <span class="text-xs font-bold" style="color: ${color}">${Math.round(percentage)}%</span>
                    </div>
                </div>
                <p class="text-xs font-medium text-gray-600 dark:text-gray-400 uppercase text-center">${title}</p>
                <p class="text-sm font-bold text-gray-900 dark:text-white text-center">${value}</p>
                <div class="flex items-center mt-1">
                    <div class="w-1.5 h-1.5 rounded-full mr-1" style="background-color: ${statusColors[status]}"></div>
                    <span class="text-xs font-semibold" style="color: ${statusColors[status]}">${status}</span>
                </div>
            </div>
        </div>
    `;
}

// Create advanced timeline visualization
function createAdvancedTimelineVisualization(allocations, totalMemory) {
    if (allocations.length === 0) return '<div class="flex items-center justify-center h-full text-gray-400">No timeline data</div>';

    const sortedAllocs = allocations.sort((a, b) => (a.timestamp_alloc || 0) - (b.timestamp_alloc || 0));
    const minTime = sortedAllocs[0]?.timestamp_alloc || 0;
    const maxTime = sortedAllocs[sortedAllocs.length - 1]?.timestamp_alloc || minTime + 1;
    const timeRange = maxTime - minTime || 1;

    // Group allocations by scope/type for better visualization
    const scopeGroups = {};
    sortedAllocs.forEach(alloc => {
        const scope = alloc.scope_name || (alloc.var_name ? 'User Variables' : 'System');
        if (!scopeGroups[scope]) scopeGroups[scope] = [];
        scopeGroups[scope].push(alloc);
    });

    const scopeColors = ['#3498db', '#e74c3c', '#2ecc71', '#f39c12', '#9b59b6', '#1abc9c'];
    let scopeIndex = 0;

    return Object.entries(scopeGroups).map(([scope, allocs]) => {
        const color = scopeColors[scopeIndex % scopeColors.length];
        scopeIndex++;
        const yOffset = scopeIndex * 25;

        return `
            <div class="absolute" style="top: ${yOffset}px; left: 0; right: 0; height: 20px;">
                <div class="text-xs font-medium text-gray-700 dark:text-gray-300 mb-1" style="color: ${color}">
                    ${scope} (${allocs.length} allocs)
                </div>
                ${allocs.slice(0, 20).map(alloc => {
            const position = ((alloc.timestamp_alloc - minTime) / timeRange) * 100;
            const width = Math.max(2, (alloc.size / totalMemory) * 100);

            return `
                        <div class="absolute h-4 rounded opacity-80 hover:opacity-100 transition-opacity cursor-pointer" 
                             style="left: ${position}%; width: ${Math.max(4, width)}px; background-color: ${color};"
                             title="${alloc.var_name || 'System'}: ${formatBytes(alloc.size)}">
                        </div>
                    `;
        }).join('')}
            </div>
        `;
    }).join('');
}

// Create advanced treemap visualization inspired by SVG design
function createAdvancedTreemapVisualization(allocations, totalMemory) {
    if (allocations.length === 0) return '<div class="flex items-center justify-center h-full text-gray-400">No allocation data</div>';

    // Group allocations by type and category
    const typeGroups = {};
    const categoryGroups = {
        'Collections': { types: {}, totalSize: 0, color: '#3498db' },
        'Basic Types': { types: {}, totalSize: 0, color: '#27ae60' },
        'Smart Pointers': { types: {}, totalSize: 0, color: '#9b59b6' },
        'System': { types: {}, totalSize: 0, color: '#95a5a6' }
    };

    allocations.forEach(alloc => {
        const type = alloc.type_name || 'System';
        const category = getTypeCategory(type);
        const categoryName = getCategoryName(category);
        
        if (!typeGroups[type]) {
            typeGroups[type] = { count: 0, size: 0, category: categoryName };
        }
        typeGroups[type].count++;
        typeGroups[type].size += alloc.size || 0;
        
        // Add to category groups
        if (!categoryGroups[categoryName].types[type]) {
            categoryGroups[categoryName].types[type] = { count: 0, size: 0 };
        }
        categoryGroups[categoryName].types[type].count++;
        categoryGroups[categoryName].types[type].size += alloc.size || 0;
        categoryGroups[categoryName].totalSize += alloc.size || 0;
    });

    // Sort categories by size
    const sortedCategories = Object.entries(categoryGroups)
        .filter(([, data]) => data.totalSize > 0)
        .sort(([, a], [, b]) => b.totalSize - a.totalSize);

    let html = '';
    let currentY = 0;
    const containerHeight = 240;
    const padding = 8;

    sortedCategories.forEach(([categoryName, categoryData], categoryIndex) => {
        const categoryPercentage = (categoryData.totalSize / totalMemory) * 100;
        const categoryHeight = Math.max(40, (categoryPercentage / 100) * containerHeight * 0.8);
        
        // Category container with background
        html += `
            <div class="absolute w-full rounded-lg border-2 border-white shadow-sm transition-all hover:shadow-md" 
                 style="top: ${currentY}px; height: ${categoryHeight}px; background-color: ${categoryData.color}; opacity: 0.15;">
            </div>
        `;

        // Category label
        html += `
            <div class="absolute left-2 font-bold text-sm z-10" 
                 style="top: ${currentY + 8}px; color: ${categoryData.color};">
                ${categoryName} (${categoryPercentage.toFixed(1)}%)
            </div>
        `;

        // Sort types within category
        const sortedTypes = Object.entries(categoryData.types)
            .sort(([, a], [, b]) => b.size - a.size)
            .slice(0, 6); // Limit to top 6 types per category

        let currentX = 20;
        const typeY = currentY + 25;
        const availableWidth = 95; // Leave some margin

        sortedTypes.forEach(([type, typeData], typeIndex) => {
            const typePercentage = (typeData.size / categoryData.totalSize) * 100;
            const typeWidth = Math.max(60, (typePercentage / 100) * availableWidth);
            const typeHeight = Math.max(20, categoryHeight - 35);

            // Type rectangle with enhanced styling
            html += `
                <div class="absolute rounded-md border border-white shadow-sm cursor-pointer transition-all hover:brightness-110 hover:scale-105 hover:z-20" 
                     style="left: ${currentX}px; top: ${typeY}px; width: ${typeWidth}px; height: ${typeHeight}px; 
                            background-color: ${categoryData.color}; opacity: 0.9;"
                     title="${type}: ${formatBytes(typeData.size)} (${typeData.count} allocs, ${typePercentage.toFixed(1)}% of ${categoryName})">
                    <div class="p-1 h-full flex flex-col justify-center text-white text-xs font-bold text-center">
                        <div class="truncate text-shadow" style="text-shadow: 1px 1px 2px rgba(0,0,0,0.8);">
                            ${type.length > 12 ? type.substring(0, 10) + '..' : type}
                        </div>
                        <div class="text-xs opacity-90 font-semibold" style="text-shadow: 1px 1px 2px rgba(0,0,0,0.6);">
                            ${formatBytes(typeData.size)}
                        </div>
                        <div class="text-xs opacity-75" style="text-shadow: 1px 1px 2px rgba(0,0,0,0.6);">
                            (${typePercentage.toFixed(1)}%)
                        </div>
                    </div>
                </div>
            `;

            currentX += typeWidth + 4;
        });

        currentY += categoryHeight + padding;
    });

    return html;
}

// Helper function to get category name
function getCategoryName(category) {
    const categoryMap = {
        'collections': 'Collections',
        'basic': 'Basic Types',
        'smart_pointers': 'Smart Pointers',
        'system': 'System'
    };
    return categoryMap[category] || 'System';
}

// Create advanced fragmentation bar
function createAdvancedFragmentationBar(label, count, total, color) {
    const percentage = total > 0 ? (count / total) * 100 : 0;
    const barHeight = Math.max(8, (count / total) * 60);

    return `
        <div class="flex items-center justify-between ">
            <div class="flex items-center w-32">
                <div class="w-4 rounded mr-3 border border-gray-300 dark:border-gray-500" 
                     style="height: ${barHeight}px; background-color: ${color}"></div>
                <span class="text-sm font-medium text-gray-700 dark:text-gray-300">${label}</span>
            </div>
            <div class="flex-1 mx-3">
                <div class="w-full bg-gray-200 dark:bg-gray-600 rounded-full h-3">
                    <div class="h-3 rounded-full transition-all duration-500" 
                         style="width: ${percentage}%; background-color: ${color}"></div>
                </div>
            </div>
            <span class="text-sm font-bold text-gray-900 dark:text-white w-12 text-right ">${count}</span>
        </div>
    `;
}

// Create call stack analysis
function createCallStackAnalysis(allocations) {
    const userAllocs = allocations.filter(a => a.var_name && a.var_name !== 'unknown');
    const systemAllocs = allocations.filter(a => !a.var_name || a.var_name === 'unknown');

    const topAllocations = [...userAllocs, ...systemAllocs.slice(0, 3)]
        .sort((a, b) => (b.size || 0) - (a.size || 0))
        .slice(0, 10);

    return topAllocations.map(alloc => {
        const isSystem = !alloc.var_name || alloc.var_name === 'unknown';
        const color = isSystem ? '#e74c3c' : getTypeColor(alloc.type_name || '', 0);
        const radius = Math.min(8, Math.max(3, Math.sqrt((alloc.size || 0) / 100)));

        return `
            <div class="flex items-center space-x-3 p-2 bg-white dark:bg-gray-600 rounded border ">
                <div class="w-4 h-4 rounded-full border-2 border-gray-300 dark:border-gray-500" 
                     style="background-color: ${color}"></div>
                <div class="flex-1 min-w-0">
                    <div class="text-sm font-medium text-gray-900 dark:text-white truncate ">
                        ${alloc.var_name || 'System/Runtime allocations'}
                    </div>
                    <div class="text-xs text-gray-500 dark:text-gray-400 ">
                        ${alloc.type_name || 'no type info'} โ€ข ${formatBytes(alloc.size || 0)}
                    </div>
                </div>
            </div>
        `;
    }).join('');
}

// Create advanced growth trend visualization
function createAdvancedGrowthTrendVisualization(allocations, totalMemory) {
    if (allocations.length < 2) return '<div class="flex items-center justify-center h-full text-gray-400 ">Insufficient data</div>';

    const sortedAllocs = allocations.sort((a, b) => (a.timestamp_alloc || 0) - (b.timestamp_alloc || 0));
    const points = [];
    let cumulativeSize = 0;

    sortedAllocs.forEach((alloc, index) => {
        cumulativeSize += alloc.size || 0;
        if (index % Math.max(1, Math.floor(sortedAllocs.length / 15)) === 0) {
            points.push({
                x: (index / sortedAllocs.length) * 100,
                y: 100 - (cumulativeSize / totalMemory) * 80,
                size: cumulativeSize
            });
        }
    });

    return `
        <!-- Background Grid -->
        <div class="absolute inset-0">
            ${[20, 40, 60, 80].map(y => `
                <div class="absolute w-full border-t border-gray-200 dark:border-gray-500 opacity-30" 
                     style="top: ${y}%"></div>
            `).join('')}
        </div>
        
        <!-- Growth Line -->
        <svg class="absolute inset-0 w-full h-full ">
            <polyline
                fill="none"
                stroke='#27ae60'
                stroke-width="3"
                stroke-linecap="round"
                stroke-linejoin="round"
                points="${points.map(p => `${p.x},${p.y}`).join(' ')}"
                class="drop-shadow-sm "
            />
        </svg>
        
        <!-- Data Points -->
        ${points.map(point => `
            <div class="absolute w-2 h-2 bg-green-500 rounded-full border border-white dark:border-gray-600 transform -translate-x-1/2 -translate-y-1/2 hover:scale-150 transition-transform cursor-pointer " 
                 style="left: ${point.x}%; top: ${point.y}%"
                 title="Memory: ${formatBytes(point.size)}">
            </div>
        `).join('')}
        
        <!-- Peak Memory Line -->
        <div class="absolute w-full border-t-2 border-red-500 border-dashed opacity-60" style="top: 20%">
            <div class="absolute -top-1 right-0 text-xs text-red-500 bg-white dark:bg-gray-600 px-1 rounded ">
                Peak: ${formatBytes(totalMemory)}
            </div>
        </div>
    `;
}

// Create variable allocation timeline
function createVariableAllocationTimeline(allocations) {
    const userAllocs = allocations.filter(a => a.var_name && a.var_name !== 'unknown')
        .sort((a, b) => (a.timestamp_alloc || 0) - (b.timestamp_alloc || 0))
        .slice(0, 10);

    return userAllocs.map((alloc, index) => {
        const color = getTypeColor(alloc.type_name || '', index);

        return `
            <div class="flex items-center space-x-3 p-2 bg-white dark:bg-gray-600 rounded border ">
                <div class="w-3 h-3 rounded-full" style="background-color: ${color}"></div>
                <div class="flex-1 min-w-0">
                    <div class="text-sm font-medium text-gray-900 dark:text-white ">
                        ${alloc.var_name}
                    </div>
                    <div class="text-xs text-gray-500 dark:text-gray-400">
                        ${alloc.type_name || 'unknown'} โ€ข ${formatBytes(alloc.size || 0)}
                    </div>
                </div>
                <div class="text-xs text-gray-500 dark:text-gray-400">
                    ${new Date(alloc.timestamp_alloc / 1000000).toLocaleTimeString()}
                </div>
            </div>
        `;
    }).join('');
}

// Helper functions for type categorization
function getTypeCategory(type) {
    if (!type || type === 'System' || type === 'unknown') return 'system';
    
    const typeLower = type.toLowerCase();
    
    // Collections
    if (typeLower.includes('vec') || typeLower.includes('hash') || typeLower.includes('btree') || 
        typeLower.includes('deque') || typeLower.includes('set') || typeLower.includes('map')) {
        return 'collections';
    }
    
    // Smart Pointers
    if (typeLower.includes('box') || typeLower.includes('rc') || typeLower.includes('arc') || 
        typeLower.includes('refcell') || typeLower.includes('cell') || typeLower.includes('weak')) {
        return 'smart_pointers';
    }
    
    // Basic types (String, primitives, etc.)
    return 'basic';
}

function getCategoryColor(category) {
    const colors = {
        'collections': '#3498db',      // Bright blue
        'basic': '#27ae60',           // Bright green  
        'smart_pointers': '#9b59b6',  // Purple
        'system': '#95a5a6'           // Gray
    };
    return colors[category] || '#95a5a6';
}

// Initialize allocations table with improved collapsible functionality
function initAllocationsTable() {
    console.log('๐Ÿ“Š Initializing allocations table...');

    const tbody = document.getElementById('allocations-table');
    const toggleButton = document.getElementById('toggle-allocations');

    if (!tbody) {
        console.warn('โš ๏ธ Allocations table body not found');
        return;
    }

    const allocations = window.analysisData.memory_analysis?.allocations || [];

    if (allocations.length === 0) {
        tbody.innerHTML = '<tr><td colspan="5" class="px-4 py-8 text-center text-gray-500 dark:text-gray-400">No allocations found</td></tr>';
        if (toggleButton) {
            toggleButton.style.display = 'none';
        }
        return;
    }

    let isExpanded = false;
    const maxInitialRows = 5;

    function renderTable(showAll = false) {
        console.log(`๐Ÿ“Š Rendering table, showAll: ${showAll}, total allocations: ${allocations.length}`);

        const displayAllocations = showAll ? allocations : allocations.slice(0, maxInitialRows);

        tbody.innerHTML = displayAllocations.map(alloc => `
            <tr class="hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors ">
                <td class="px-4 py-2 text-gray-900 dark:text-gray-100 font-mono ">0x${(alloc.ptr ? parseInt(alloc.ptr.toString().replace('0x', ''), 16) : 0).toString(16).padStart(8, '0')}</td>
                <td class="px-4 py-2 text-gray-900 dark:text-gray-100">${alloc.var_name || 'System Allocation'}</td>
                <td class="px-4 py-2 text-gray-900 dark:text-gray-100">${formatTypeName(alloc.type_name || 'System Allocation')}</td>
                <td class="px-4 py-2 text-right text-gray-900 dark:text-gray-100">${formatBytes(alloc.size || 0)}</td>
                <td class="px-4 py-2 text-right text-gray-900 dark:text-gray-100">
                    <span class="px-2 py-1 text-xs rounded-full ${alloc.is_active ? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200' : 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200 '} ">
                        ${alloc.is_active ? 'Active' : 'Deallocated'}
                    </span>
                </td>
            </tr>
        `).join('');

        if (!showAll && allocations.length > maxInitialRows) {
            tbody.innerHTML += `
                <tr class="bg-gray-50 dark:bg-gray-700">
                    <td colspan="5" class="px-4 py-2 text-center text-gray-500 dark:text-gray-400 text-sm">
                        ... and ${allocations.length - maxInitialRows} more allocations
                    </td>
                </tr>
            `;
        }
    }

    // Initial render
    renderTable(false);

    // Toggle functionality - Fixed event binding
    if (toggleButton && allocations.length > maxInitialRows) {
        console.log('๐Ÿ“Š Setting up toggle button for', allocations.length, 'allocations');

        // Clear any existing event listeners and add new one
        toggleButton.replaceWith(toggleButton.cloneNode(true));
        const newToggleButton = document.getElementById('toggle-allocations');

        newToggleButton.addEventListener('click', function (e) {
            e.preventDefault();
            e.stopPropagation();
            console.log('๐Ÿ“Š Toggle button clicked, current state:', isExpanded);

            isExpanded = !isExpanded;
            renderTable(isExpanded);

            const icon = newToggleButton.querySelector('i');
            const text = newToggleButton.querySelector('span');

            if (isExpanded) {
                icon.className = 'fa fa-chevron-up mr-1';
                text.textContent = 'Show Less';
                console.log('๐Ÿ“Š Expanded table to show all allocations');
            } else {
                icon.className = 'fa fa-chevron-down mr-1';
                text.textContent = 'Show All';
                console.log('๐Ÿ“Š Collapsed table to show first', maxInitialRows, 'allocations');
            }
        });

        console.log('โœ… Toggle button initialized successfully');
    } else if (toggleButton) {
        // Hide button if not needed
        toggleButton.style.display = 'none';
        console.log('๐Ÿ“Š Toggle button hidden (not enough data)');
    }
}

// Initialize lifetime visualization from JSON data with collapsible functionality
function initLifetimeVisualization() {
    console.log('๐Ÿ”„ Initializing lifetime visualization...');

    // Get lifetime data from various sources (support extended data structure)
    let lifetimeData = null;
    let lifecycleEvents = [];
    
    // Smart data source selection: merge memory_analysis and complex_types data
    let memoryAllocations = window.analysisData.memory_analysis?.allocations || [];
    let complexAllocations = window.analysisData.complex_types?.allocations || [];
    
    console.log('๐Ÿ“Š Memory analysis allocations:', memoryAllocations.length);
    console.log('๐Ÿ“Š Complex types allocations:', complexAllocations.length);
    
    // ๅˆๅนถๆ•ฐๆฎ๏ผšไฝฟ็”จmemory_analysis็š„lifetime_ms + complex_types็š„ๆ‰ฉๅฑ•ๅญ—ๆฎต
    if (memoryAllocations.length > 0 && complexAllocations.length > 0) {
        // Create mapping from pointer to memory analysis data
        const memoryMap = new Map();
        memoryAllocations.forEach(alloc => {
            if (alloc.ptr) {
                memoryMap.set(alloc.ptr, alloc);
            }
        });
        
        // Merge data: complex_types + lifetime_ms from memory_analysis
        lifecycleEvents = complexAllocations.map(complexAlloc => {
            const memoryAlloc = memoryMap.get(complexAlloc.ptr);
            return {
                ...complexAlloc,
                lifetime_ms: memoryAlloc?.lifetime_ms || null,
                timestamp_dealloc: memoryAlloc?.timestamp_dealloc || null
            };
        });
        console.log('๐Ÿ“Š Merged allocation data:', lifecycleEvents.length);
    } else if (memoryAllocations.length > 0) {
        lifecycleEvents = memoryAllocations;
        console.log('๐Ÿ“Š Using memory analysis data:', lifecycleEvents.length);
    } else if (complexAllocations.length > 0) {
        lifecycleEvents = complexAllocations;
        console.log('๐Ÿ“Š Using complex types data:', lifecycleEvents.length);
    } else if (window.analysisData.lifetime?.lifecycle_events) {
        lifecycleEvents = window.analysisData.lifetime.lifecycle_events;
        console.log('๐Ÿ“Š Using lifetime events data:', lifecycleEvents.length);
    }
    
    if (!lifecycleEvents || lifecycleEvents.length === 0) {
        console.warn('โš ๏ธ No lifetime data found');
        console.log('Available data keys:', Object.keys(window.analysisData || {}));
        showEmptyLifetimeState();
        return;
    }

    console.log(`๐Ÿ“Š Total lifecycle events: ${lifecycleEvents.length}`);

    // Check if we have Rust-preprocessed data
    if (lifetimeData?.visualization_ready && lifetimeData?.variable_groups) {
        console.log(`๐Ÿ“Š Using Rust-preprocessed data with ${lifetimeData.variable_groups.length} variable groups`);
        renderLifetimeVisualizationFromRustWithCollapse(lifetimeData.variable_groups);
        return;
    }

    // Filter for user-defined variables (non-unknown var_name and type_name)
    const userVariables = lifecycleEvents.filter(event =>
        event.var_name && event.var_name !== 'unknown' &&
        event.type_name && event.type_name !== 'unknown'
    );

    console.log(`๐Ÿ“Š Found ${userVariables.length} user-defined variables in lifetime data`);

    // Debug: Show some examples of what we found
    if (userVariables.length > 0) {
        console.log('๐Ÿ“Š Sample user variables:', userVariables.slice(0, 3));
    } else {
        // Show some examples of unknown variables for debugging
        const unknownSamples = lifecycleEvents.slice(0, 3);
        console.log('๐Ÿ“Š Sample unknown variables:', unknownSamples);
    }

    if (userVariables.length === 0) {
        showEmptyLifetimeState();
        return;
    }

    // Group by variable name to get allocation/deallocation pairs
    const variableGroups = groupVariablesByName(userVariables);

    // Render the lifetime visualization with collapse functionality
    renderLifetimeVisualizationWithCollapse(variableGroups);
}

// Group variables by name to track their lifecycle (enhanced for multiple instances)
function groupVariablesByName(events) {
    const groups = {};

    events.forEach(event => {
        const varName = event.var_name;
        const instanceKey = `${varName}_${event.ptr || event.timestamp_alloc}`; // ไธบๆฏไธชๅฎžไพ‹ๅˆ›ๅปบๅ”ฏไธ€key
        
        if (!groups[instanceKey]) {
            groups[instanceKey] = {
                var_name: `${varName}#${Object.keys(groups).filter(k => k.startsWith(varName)).length + 1}`, // ๆทปๅŠ ๅฎžไพ‹็ผ–ๅท
                original_var_name: varName,
                type_name: event.type_name,
                events: [],
                instance_info: {
                    ptr: event.ptr,
                    timestamp: event.timestamp_alloc,
                    thread_id: event.thread_id
                }
            };
        }
        groups[instanceKey].events.push(event);
    });

    
    const groupValues = Object.values(groups);
    const varCounts = {};
    groupValues.forEach(group => {
        const originalName = group.original_var_name;
        varCounts[originalName] = (varCounts[originalName] || 0) + 1;
    });
    
    groupValues.forEach(group => {
        if (varCounts[group.original_var_name] === 1) {
            group.var_name = group.original_var_name; 
        }
    });

    return groupValues;
}

// Render lifetime visualization from Rust-preprocessed data with collapsible functionality
function renderLifetimeVisualizationFromRustWithCollapse(variableGroups) {
    console.log(`๐Ÿ“Š Rendering ${variableGroups.length} Rust-preprocessed variable groups with collapse functionality`);

    const container = document.getElementById('lifetimeVisualization');
    const toggleButton = document.getElementById('toggle-lifecycle');
    
    if (!container) return;

    // Clear loading state
    container.innerHTML = '';

    if (!variableGroups || variableGroups.length === 0) {
        showEmptyLifetimeState();
        if (toggleButton) {
            toggleButton.style.display = 'none';
        }
        return;
    }

    let isExpanded = false;
    const maxInitialRows = 5;

    // Calculate timeline bounds from preprocessed data
    const allTimestamps = variableGroups.flatMap(group =>
        group.events ? group.events.map(e => e.timestamp) : [group.start_time, group.end_time].filter(t => t !== undefined)
    );

    const minTime = Math.min(...allTimestamps);
    const maxTime = Math.max(...allTimestamps);
    const timeRange = maxTime - minTime || 1;

    console.log(`๐Ÿ“Š Rust data timeline: ${minTime} to ${maxTime} (range: ${timeRange})`);

    // Color palette for different data types and visualizations
    const COLOR_PALETTE = {
        progress: [
            '#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4', '#feca57',
            '#ff9ff3', '#54a0ff', '#5f27cd', '#00d2d3', '#ff9f43'
        ]
    };

    function renderLifetimeRows(showAll = false) {
        console.log(`๐Ÿ“Š Rendering lifecycle rows, showAll: ${showAll}, total groups: ${variableGroups.length}`);
        
        container.innerHTML = '';
        
        const displayGroups = showAll ? variableGroups : variableGroups.slice(0, maxInitialRows);

        // Render each variable with colorful progress bars
        displayGroups.forEach((group, index) => {
            const varDiv = document.createElement('div');
            varDiv.className = 'flex items-center py-4 border-b border-gray-100 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors';

            // Get color from palette (cycle through colors)
            const colorIndex = index % COLOR_PALETTE.progress.length;
            const progressColor = COLOR_PALETTE.progress[colorIndex];

            // Use preprocessed timing data or fallback to events
            const startTime = group.start_time || (group.events && group.events[0] ? group.events[0].timestamp : minTime);
            const firstEvent = group.events && group.events[0];
            
            const startPercent = timeRange > 0 ? ((startTime - minTime) / timeRange) * 100 : 0;
            
            
            let widthPercent;
            if (firstEvent && firstEvent.lifetime_ms && firstEvent.lifetime_ms > 0) {
                
                const lifetimeNs = firstEvent.lifetime_ms * 1000000; 
                widthPercent = timeRange > 0 ? Math.max(1, (lifetimeNs / timeRange) * 100) : 6.8;
            } else {
                //
                widthPercent = 6.8;
            }
            
            // ๅฎ‰ๅ…จ็š„ๅ˜้‡ๅฎšไน‰๏ผŒ้˜ฒๆญขNaN
            const finalStartPercent = isNaN(startPercent) ? 0 : Math.max(0, Math.min(95, startPercent));
            const finalWidthPercent = isNaN(widthPercent) ? 40 : Math.max(2, Math.min(100 - finalStartPercent, widthPercent));

            // Format type name for display
            const displayTypeName = formatTypeName(group.type_name);

            // Create gradient background for more visual appeal
            const gradientStyle = `background: linear-gradient(90deg, ${progressColor}, ${progressColor}dd);`;

            varDiv.innerHTML = `
                <div class="w-48 flex-shrink-0 pr-4">
                    <div class="text-sm font-semibold text-gray-800 dark:text-gray-200">${group.var_name}</div>
                    <div class="text-xs text-gray-500 dark:text-gray-400">${displayTypeName}</div>
                </div>
                <div class="flex-grow relative bg-gray-200 dark:bg-gray-600 rounded-full h-6 overflow-hidden">
                    <div class="absolute inset-0 rounded-full" 
                         style="${gradientStyle} width: ${finalWidthPercent}%; margin-left: ${finalStartPercent}%; 
                                box-shadow: 0 2px 4px rgba(0,0,0,0.1); 
                                transition: all 0.3s ease;"
                         title="Variable: ${group.var_name}, Type: ${displayTypeName}">
                        <div class="absolute inset-0 flex items-center justify-center">
                            <span class="text-xs font-bold text-white drop-shadow-sm">
                                ${Math.round(finalWidthPercent)}%
                            </span>
                        </div>
                    </div>
                    <div class="absolute -top-8 left-0 text-xs bg-gray-700 text-white px-2 py-1 rounded opacity-0 hover:opacity-100 transition-opacity whitespace-nowrap">
                        Duration: ${firstEvent && firstEvent.lifetime_ms ? firstEvent.lifetime_ms + 'ms' : 'Active'}
                    </div>
                </div>
                <div class="w-20 flex-shrink-0 pl-4 text-right">
                    <div class="text-xs text-gray-600 dark:text-gray-400">
                        ${formatBytes(group.size || (group.events && group.events[0] ? group.events[0].size : 0) || 0)}
                    </div>
                </div>
            `;

            container.appendChild(varDiv);
        });

        // Add "show more" indicator if collapsed
        if (!showAll && variableGroups.length > maxInitialRows) {
            const moreDiv = document.createElement('div');
            moreDiv.className = 'flex items-center py-4 bg-gray-50 dark:bg-gray-700 border-b border-gray-100 dark:border-gray-600';
            moreDiv.innerHTML = `
                <div class="w-full text-center text-gray-500 dark:text-gray-400 text-sm">
                    ... and ${variableGroups.length - maxInitialRows} more variables
                </div>
            `;
            container.appendChild(moreDiv);
        }
    }

    // Initial render
    renderLifetimeRows(false);

    // Toggle functionality
    if (toggleButton && variableGroups.length > maxInitialRows) {
        console.log('๐Ÿ“Š Setting up lifecycle toggle button for', variableGroups.length, 'variables');

        // Remove any existing event listeners
        const newToggleButton = toggleButton.cloneNode(true);
        toggleButton.parentNode.replaceChild(newToggleButton, toggleButton);

        newToggleButton.addEventListener('click', function (e) {
            e.preventDefault();
            console.log('๐Ÿ“Š Lifecycle toggle button clicked, current state:', isExpanded);

            isExpanded = !isExpanded;
            renderLifetimeRows(isExpanded);

            const icon = newToggleButton.querySelector('i');
            const text = newToggleButton.querySelector('span');

            if (isExpanded) {
                icon.className = 'fa fa-chevron-up mr-1';
                text.textContent = 'Show Less';
                console.log('๐Ÿ“Š Expanded lifecycle to show all variables');
            } else {
                icon.className = 'fa fa-chevron-down mr-1';
                text.textContent = 'Show All';
                console.log('๐Ÿ“Š Collapsed lifecycle to show first', maxInitialRows, 'variables');
            }
        });

        console.log('โœ… Lifecycle toggle button initialized successfully');
    } else if (toggleButton) {
        // Hide button if not needed
        toggleButton.style.display = 'none';
        console.log('๐Ÿ“Š Lifecycle toggle button hidden (not enough data)');
    }

    console.log(`โœ… Rendered ${variableGroups.length} Rust-preprocessed variables in lifetime visualization with collapse functionality`);
}

// Render the lifetime visualization with collapsible functionality
function renderLifetimeVisualizationWithCollapse(variableGroups) {
    const container = document.getElementById('lifetimeVisualization');
    const toggleButton = document.getElementById('toggle-lifecycle');
    
    if (!container) return;

    // Clear loading state
    container.innerHTML = '';

    if (!variableGroups || variableGroups.length === 0) {
        showEmptyLifetimeState();
        if (toggleButton) {
            toggleButton.style.display = 'none';
        }
        return;
    }

    let isExpanded = false;
    const maxInitialRows = 5;

    // Get color scheme for different types
    const typeColors = {
        'Vec': { bg: 'bg-blue-500', border: 'border-blue-500' },
        'Box': { bg: 'bg-purple-500', border: 'border-purple-500' },
        'Rc': { bg: 'bg-yellow-500', border: 'border-yellow-500' },
        'Arc': { bg: 'bg-green-500', border: 'border-green-500' },
        'String': { bg: 'bg-pink-500', border: 'border-pink-500' },
        'default': { bg: 'bg-gray-500', border: 'border-gray-500' }
    };

    // Calculate timeline bounds
    const allTimestamps = variableGroups.flatMap(group =>
        group.events.map(e => e.timestamp)
    );
    const minTime = Math.min(...allTimestamps);
    const maxTime = Math.max(...allTimestamps);
    const timeRange = maxTime - minTime;

    console.log(`๐Ÿ“Š Timeline: ${minTime} to ${maxTime} (range: ${timeRange})`);

    function renderLifetimeRows(showAll = false) {
        console.log(`๐Ÿ“Š Rendering lifecycle rows, showAll: ${showAll}, total groups: ${variableGroups.length}`);
        
        container.innerHTML = '';
        
        const displayGroups = showAll ? variableGroups : variableGroups.slice(0, maxInitialRows);

        // Render each variable
        displayGroups.forEach((group) => {
            const varDiv = document.createElement('div');
            varDiv.className = 'flex items-end py-3 border-b border-gray-100 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors';

            // Determine color based on type
            const typeKey = Object.keys(typeColors).find(key =>
                group.type_name.includes(key)
            ) || 'default';
            const colors = typeColors[typeKey];

            // Calculate position and width based on timestamps
            const firstEvent = group.events[0];
            const startTime = firstEvent.timestamp;
            const startPositionPercent = timeRange > 0 ? ((startTime - minTime) / timeRange) * 100 : 0;

            // real time correct time axis calculation: based on actual allocation and survival time
            const allocTime = firstEvent.timestamp;
            const deallocTime = firstEvent.timestamp_dealloc;
            const lifetimeMs = firstEvent.lifetime_ms || 1; // default 1ms lifetime
            
            // calculate survival time length (percentage)
            let durationPercent;
            if (deallocTime && deallocTime > allocTime) {
                // if there is a clear release time, use actual time span
                const actualDuration = deallocTime - allocTime;
                durationPercent = (actualDuration / timeRange) * 100;
            } else {
                // if there is no release time, use lifetime_ms calculation
                const lifetimeNs = lifetimeMs * 1000000; // convert to nanoseconds
                durationPercent = (lifetimeNs / timeRange) * 100;
            }
            
            // ensure value is within reasonable range
            const widthPercent = Math.max(0.5, Math.min(100 - startPositionPercent, durationPercent));
            
            // ๅฎ‰ๅ…จ็š„ๅ˜้‡ๅฎšไน‰๏ผŒ้˜ฒๆญขNaN
            const finalStartPercent = isNaN(startPositionPercent) ? 0 : Math.max(0, Math.min(95, startPositionPercent));
            const finalWidthPercent = isNaN(widthPercent) ? 30 : Math.max(2, Math.min(100 - finalStartPercent, widthPercent));

            // Format type name for display
            const displayTypeName = formatTypeName(group.type_name);

            varDiv.innerHTML = `
                <div class="w-40 flex-shrink-0 text-sm font-medium dark:text-gray-200">
                    ${group.var_name} (${displayTypeName})
                </div>
                <div class="flex-grow relative">
                    <div class="lifespan-indicator ${colors.bg}" 
                         style="width: ${finalWidthPercent}%; margin-left: ${finalStartPercent}%;" 
                         title="Variable: ${group.var_name}, Type: ${displayTypeName}">
                        <div class="absolute -top-6 left-0 text-xs ${colors.bg} text-white px-2 py-1 rounded whitespace-nowrap">
                            Allocated: ${formatTimestamp(startTime, minTime)}
                        </div>
                    </div>
                </div>
            `;

            container.appendChild(varDiv);
        });

        // Add "show more" indicator if collapsed
        if (!showAll && variableGroups.length > maxInitialRows) {
            const moreDiv = document.createElement('div');
            moreDiv.className = 'flex items-center py-3 bg-gray-50 dark:bg-gray-700 border-b border-gray-100 dark:border-gray-600';
            moreDiv.innerHTML = `
                <div class="w-full text-center text-gray-500 dark:text-gray-400 text-sm">
                    ... and ${variableGroups.length - maxInitialRows} more variables
                </div>
            `;
            container.appendChild(moreDiv);
        }
    }

    // Initial render
    renderLifetimeRows(false);

    // Toggle functionality
    if (toggleButton && variableGroups.length > maxInitialRows) {
        console.log('๐Ÿ“Š Setting up lifecycle toggle button for', variableGroups.length, 'variables');

        // Remove any existing event listeners
        const newToggleButton = toggleButton.cloneNode(true);
        toggleButton.parentNode.replaceChild(newToggleButton, toggleButton);

        newToggleButton.addEventListener('click', function (e) {
            e.preventDefault();
            console.log('๐Ÿ“Š Lifecycle toggle button clicked, current state:', isExpanded);

            isExpanded = !isExpanded;
            renderLifetimeRows(isExpanded);

            const icon = newToggleButton.querySelector('i');
            const text = newToggleButton.querySelector('span');

            if (isExpanded) {
                icon.className = 'fa fa-chevron-up mr-1';
                text.textContent = 'Show Less';
                console.log('๐Ÿ“Š Expanded lifecycle to show all variables');
            } else {
                icon.className = 'fa fa-chevron-down mr-1';
                text.textContent = 'Show All';
                console.log('๐Ÿ“Š Collapsed lifecycle to show first', maxInitialRows, 'variables');
            }
        });

        console.log('โœ… Lifecycle toggle button initialized successfully');
    } else if (toggleButton) {
        // Hide button if not needed
        toggleButton.style.display = 'none';
        console.log('๐Ÿ“Š Lifecycle toggle button hidden (not enough data)');
    }

    console.log(`โœ… Rendered ${variableGroups.length} variables in lifetime visualization with collapse functionality`);
}

// Initialize FFI visualization with enhanced support for improve.md fields
function initFFIVisualization() {
    console.log('๐Ÿ”„ Initializing FFI visualization...');

    const container = document.getElementById('ffiVisualization');
    if (!container) return;

    // Get FFI data from multiple sources with comprehensive field support
    let allocations = [];
    let unsafeReports = [];
    let memoryPassports = [];
    let ffiStatistics = {};
    
    console.log('๐Ÿ” Checking analysisData structure:', Object.keys(window.analysisData || {}));
    
    // Enhanced data extraction supporting improve.md structure
    if (window.analysisData) {
        // Debug: Show what data structure we actually have FIRST
        console.log('๐Ÿ” Available data keys:', Object.keys(window.analysisData));
        if (window.analysisData.unsafe_ffi) {
            console.log('๐Ÿ” unsafe_ffi keys:', Object.keys(window.analysisData.unsafe_ffi));
            console.log('๐Ÿ” unsafe_ffi.allocations exists:', !!window.analysisData.unsafe_ffi.allocations);
            
            // Data will be handled by initializeAnalysis function
            console.log('๐Ÿ” unsafe_ffi.allocations length:', window.analysisData.unsafe_ffi.allocations ? window.analysisData.unsafe_ffi.allocations.length : 'undefined');
        }
        
        // Try unsafe_ffi data first (improve.md structure)
        if (window.analysisData.unsafe_ffi) {
            allocations = window.analysisData.unsafe_ffi.allocations || [];
            unsafeReports = window.analysisData.unsafe_ffi.unsafe_reports || [];
            memoryPassports = window.analysisData.unsafe_ffi.memory_passports || [];
            ffiStatistics = window.analysisData.unsafe_ffi.ffi_statistics || {};
            console.log('๐Ÿ“Š Found unsafe_ffi data - allocations:', allocations.length, 'reports:', unsafeReports.length, 'passports:', memoryPassports.length);
        }
        // Try complex_types structure (for large_scale_user files)
        else if (window.analysisData.complex_types && window.analysisData.complex_types.allocations) {
            allocations = window.analysisData.complex_types.allocations;
            console.log('๐Ÿ“Š Found complex_types allocations:', allocations.length);
        }
        // Try direct allocations array (for files like large_scale_user_unsafe_ffi.json)
        else if (window.analysisData.allocations) {
            allocations = window.analysisData.allocations;
            console.log('๐Ÿ“Š Found direct allocations:', allocations.length);
        }
        // Fallback to memory_analysis
        else if (window.analysisData.memory_analysis && window.analysisData.memory_analysis.allocations) {
            allocations = window.analysisData.memory_analysis.allocations;
            console.log('๐Ÿ“Š Using memory_analysis allocations:', allocations.length);
        }
        
        // Debug: Show what data structure we actually have
        console.log('๐Ÿ” Available data keys:', Object.keys(window.analysisData));
        if (window.analysisData.unsafe_ffi) {
            console.log('๐Ÿ” unsafe_ffi keys:', Object.keys(window.analysisData.unsafe_ffi));
        }
        
        // Extract metadata if available
        const metadata = window.analysisData.metadata || {};
        console.log('๐Ÿ“Š Metadata:', metadata);
    }

    // Filter for FFI-tracked allocations with enhanced field support
    const ffiAllocations = allocations.filter(alloc => 
        alloc.ffi_tracked === true || 
        (alloc.safety_violations && alloc.safety_violations.length > 0) ||
        alloc.ownership_history_available === true ||
        (alloc.borrow_info && (alloc.borrow_info.immutable_borrows > 0 || alloc.borrow_info.mutable_borrows > 0)) ||
        (alloc.clone_info && alloc.clone_info.clone_count > 0)
    );
    console.log('๐Ÿ“Š Found FFI-tracked allocations:', ffiAllocations.length);
    
    // Debug: show first few allocations with improve.md fields
    if (allocations.length > 0) {
        console.log('๐Ÿ” Sample allocation with improve.md fields:', allocations[0]);
        console.log('๐Ÿ” FFI tracked allocations sample:', ffiAllocations.slice(0, 3));
        
        // Check for improve.md specific fields
        const sampleAlloc = allocations[0];
        console.log('๐Ÿ” Improve.md fields check:');
        console.log('  - borrow_info:', sampleAlloc.borrow_info);
        console.log('  - clone_info:', sampleAlloc.clone_info);
        console.log('  - ownership_history_available:', sampleAlloc.ownership_history_available);
        console.log('  - ffi_tracked:', sampleAlloc.ffi_tracked);
        console.log('  - safety_violations:', sampleAlloc.safety_violations);
    }

    // Debug: Show what we found before filtering
    console.log('๐Ÿ” Before filtering - Total allocations:', allocations.length);
    console.log('๐Ÿ” Sample allocation fields:', allocations[0] ? Object.keys(allocations[0]) : 'No allocations');
    console.log('๐Ÿ” FFI tracked count:', allocations.filter(a => a.ffi_tracked === true).length);
    console.log('๐Ÿ” Borrow info count:', allocations.filter(a => a.borrow_info).length);
    console.log('๐Ÿ” Clone info count:', allocations.filter(a => a.clone_info).length);
    
    // Enhanced rendering with improve.md support - ALWAYS show if we have any allocations
    if (allocations.length === 0) {
        container.innerHTML = createFFIEmptyState();
        return;
    }
    
    // If we have allocations but no FFI-specific ones, still show the dashboard with all data
    const displayAllocations = ffiAllocations.length > 0 ? ffiAllocations : allocations.slice(0, 20);
    console.log('๐ŸŽฏ Rendering FFI dashboard with:', displayAllocations.length, 'allocations,', unsafeReports.length, 'reports,', memoryPassports.length, 'passports');

    // Generate enhanced FFI analysis with improve.md fields
    try {
        if (FFI_STYLE === 'svg') {
            const boundaryEvents = window.analysisData.unsafe_ffi?.boundary_events || [];
            const unsafeAllocs = displayAllocations.filter(a => (a.safety_violations || []).length > 0).length;
            const ffiAllocs = displayAllocations.filter(a => a.ffi_tracked).length;
            const safetyViolations = displayAllocations.reduce((sum, a) => sum + ((a.safety_violations || []).length || 0), 0);
            const unsafeMemory = displayAllocations
                .filter(a => (a.safety_violations || []).length > 0)
                .reduce((sum, a) => sum + (a.size || 0), 0);

            container.innerHTML = createFFIDashboardSVG(
                unsafeAllocs,
                ffiAllocs,
                boundaryEvents.length,
                safetyViolations,
                unsafeMemory,
                displayAllocations,
                boundaryEvents,
                unsafeReports
            );
            console.log('โœ… FFI SVG-style dashboard rendered');
            return;
        }
        console.log('๐Ÿ”„ Generating FFI analysis...');
        const ffiAnalysis = generateEnhancedFFIAnalysisWithImproveFields(displayAllocations, unsafeReports, memoryPassports, ffiStatistics);
        console.log('โœ… FFI analysis generated:', ffiAnalysis);
        
        console.log('๐Ÿ”„ Creating FFI dashboard...');
        const dashboardHTML = createEnhancedFFIDashboardWithImproveFields(ffiAnalysis, displayAllocations, unsafeReports, memoryPassports);
        console.log('โœ… Dashboard HTML created, length:', dashboardHTML.length);
        
        container.innerHTML = dashboardHTML;
        console.log('โœ… Dashboard rendered successfully!');
    } catch (error) {
        console.error('โŒ Error in FFI rendering:', error);
        container.innerHTML = `<div class="bg-red-100 p-4 rounded text-red-800">Error rendering FFI data: ${error.message}</div>`;
    }
}

// Generate enhanced FFI analysis with improve.md fields support
function generateEnhancedFFIAnalysisWithImproveFields(ffiAllocations, unsafeReports, memoryPassports, ffiStatistics) {
    let totalFFI = ffiAllocations.length;
    let totalViolations = 0;
    let totalMemory = 0;
    let highRiskCount = 0;
    let mediumRiskCount = 0;
    let lowRiskCount = 0;
    let totalBorrows = 0;
    let totalClones = 0;
    let leakedAllocations = 0;

    const analysisData = ffiAllocations.map(alloc => {
        const violations = alloc.safety_violations?.length || 0;
        const size = alloc.size || 0;
        
        // Enhanced borrow analysis from improve.md fields
        const borrowConflicts = alloc.borrow_info ? 
            (alloc.borrow_info.mutable_borrows > 0 && alloc.borrow_info.immutable_borrows > 0) : false;
        const totalBorrowsForAlloc = alloc.borrow_info ? 
            (alloc.borrow_info.immutable_borrows || 0) + (alloc.borrow_info.mutable_borrows || 0) : 0;
        totalBorrows += totalBorrowsForAlloc;
        
        // Enhanced clone analysis from improve.md fields
        const cloneCount = alloc.clone_info?.clone_count || 0;
        const isClone = alloc.clone_info?.is_clone || false;
        totalClones += cloneCount;
        
        // Enhanced ownership and lifecycle analysis
        const ownershipHistoryAvailable = alloc.ownership_history_available || false;
        const isLeaked = alloc.is_leaked || false;
        if (isLeaked) leakedAllocations++;
        
        // Enhanced risk calculation with improve.md fields
        let riskScore = 0;
        if (violations > 0) riskScore += 50;
        if (borrowConflicts) riskScore += 30;
        if (size > 1024) riskScore += 20;
        if (isLeaked) riskScore += 40;
        if (cloneCount > 3) riskScore += 15;
        if (totalBorrowsForAlloc > 5) riskScore += 10;
        
        let riskLevel = 'Low';
        if (riskScore >= 70) {
            riskLevel = 'High';
            highRiskCount++;
        } else if (riskScore >= 35) {
            riskLevel = 'Medium';
            mediumRiskCount++;
        } else {
            lowRiskCount++;
        }

        totalViolations += violations;
        totalMemory += size;

        return {
            ...alloc,
            riskScore,
            riskLevel,
            violations,
            borrowConflicts,
            totalBorrowsForAlloc,
            cloneCount,
            isClone,
            ownershipHistoryAvailable,
            isLeaked
        };
    });

    // Enhanced statistics from improve.md structure
    const enhancedStats = {
        boundary_crossings: ffiStatistics.boundary_crossings || 0,
        memory_violations: ffiStatistics.memory_violations || 0,
        total_ffi_calls: ffiStatistics.total_ffi_calls || 0,
        unsafe_operations: ffiStatistics.unsafe_operations || 0
    };

    return {
        totalFFI,
        totalViolations,
        totalMemory,
        highRiskCount,
        mediumRiskCount,
        lowRiskCount,
        totalBorrows,
        totalClones,
        leakedAllocations,
        analysisData,
        unsafeReports,
        memoryPassports,
        ffiStatistics: enhancedStats
    };
}

// Legacy function for backward compatibility
function generateEnhancedFFIAnalysis(ffiAllocations) {
    return generateEnhancedFFIAnalysisWithImproveFields(ffiAllocations, [], [], {});
}

// Create enhanced FFI dashboard with improve.md fields support
function createEnhancedFFIDashboardWithImproveFields(analysis, ffiAllocations, unsafeReports, memoryPassports) {
    return `
        <div class="space-y-6">
            <!-- Enhanced FFI Overview Cards with improve.md metrics -->
            <div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-4">
                <div class="bg-blue-100 dark:bg-blue-900 rounded-lg p-4 text-center">
                    <div class="text-2xl font-bold text-blue-600 dark:text-blue-300">${analysis.totalFFI}</div>
                    <div class="text-sm text-blue-700 dark:text-blue-400">FFI Allocations</div>
                </div>
                <div class="bg-red-100 dark:bg-red-900 rounded-lg p-4 text-center">
                    <div class="text-2xl font-bold text-red-600 dark:text-red-300">${analysis.highRiskCount}</div>
                    <div class="text-sm text-red-700 dark:text-red-400">High Risk</div>
                </div>
                <div class="bg-orange-100 dark:bg-orange-900 rounded-lg p-4 text-center">
                    <div class="text-2xl font-bold text-orange-600 dark:text-orange-300">${analysis.mediumRiskCount}</div>
                    <div class="text-sm text-orange-700 dark:text-orange-400">Medium Risk</div>
                </div>
                <div class="bg-green-100 dark:bg-green-900 rounded-lg p-4 text-center">
                    <div class="text-2xl font-bold text-green-600 dark:text-green-300">${analysis.lowRiskCount}</div>
                    <div class="text-sm text-green-700 dark:text-green-400">Low Risk</div>
                </div>
                <div class="bg-purple-100 dark:bg-purple-900 rounded-lg p-4 text-center">
                    <div class="text-2xl font-bold text-purple-600 dark:text-purple-300">${analysis.totalBorrows}</div>
                    <div class="text-sm text-purple-700 dark:text-purple-400">Total Borrows</div>
                </div>
                <div class="bg-indigo-100 dark:bg-indigo-900 rounded-lg p-4 text-center">
                    <div class="text-2xl font-bold text-indigo-600 dark:text-indigo-300">${analysis.totalClones}</div>
                    <div class="text-sm text-indigo-700 dark:text-indigo-400">Total Clones</div>
                </div>
            </div>

            <!-- FFI Statistics from improve.md -->
            ${analysis.ffiStatistics && Object.keys(analysis.ffiStatistics).length > 0 ? `
                <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6">
                    <h3 class="text-lg font-semibold mb-4 text-gray-800 dark:text-white">FFI Statistics</h3>
                    <div class="grid grid-cols-2 md:grid-cols-4 gap-4">
                        <div class="text-center">
                            <div class="text-xl font-bold text-gray-900 dark:text-white">${analysis.ffiStatistics.boundary_crossings}</div>
                            <div class="text-sm text-gray-600 dark:text-gray-400">Boundary Crossings</div>
                        </div>
                        <div class="text-center">
                            <div class="text-xl font-bold text-gray-900 dark:text-white">${analysis.ffiStatistics.memory_violations}</div>
                            <div class="text-sm text-gray-600 dark:text-gray-400">Memory Violations</div>
                        </div>
                        <div class="text-center">
                            <div class="text-xl font-bold text-gray-900 dark:text-white">${analysis.ffiStatistics.total_ffi_calls}</div>
                            <div class="text-sm text-gray-600 dark:text-gray-400">Total FFI Calls</div>
                        </div>
                        <div class="text-center">
                            <div class="text-xl font-bold text-gray-900 dark:text-white">${analysis.ffiStatistics.unsafe_operations}</div>
                            <div class="text-sm text-gray-600 dark:text-gray-400">Unsafe Operations</div>
                        </div>
                    </div>
                </div>
            ` : ''}

            <!-- Unsafe Reports from improve.md structure -->
            ${analysis.unsafeReports && analysis.unsafeReports.length > 0 ? `
                <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6">
                    <h3 class="text-lg font-semibold mb-4 text-gray-800 dark:text-white">Unsafe Reports</h3>
                    <div class="space-y-4">
                        ${analysis.unsafeReports.map(report => createUnsafeReportCard(report)).join('')}
                    </div>
                </div>
            ` : ''}

            <!-- Memory Passports from improve.md structure -->
            ${analysis.memoryPassports && analysis.memoryPassports.length > 0 ? `
                <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6">
                    <h3 class="text-lg font-semibold mb-4 text-gray-800 dark:text-white">Memory Passports</h3>
                    <div class="space-y-3">
                        ${analysis.memoryPassports.map(passport => createMemoryPassportCard(passport)).join('')}
                    </div>
                </div>
            ` : ''}

            <!-- Enhanced FFI Risk Analysis with improve.md fields -->
            <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6">
                <h3 class="text-lg font-semibold mb-4 text-gray-800 dark:text-white">Enhanced FFI Risk Analysis</h3>
                <div class="space-y-4">
                    ${analysis.analysisData.map(alloc => createEnhancedFFIAllocationCard(alloc)).join('')}
                </div>
            </div>

            <!-- Enhanced Borrow Checker Analysis with improve.md fields -->
            <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6">
                <h3 class="text-lg font-semibold mb-4 text-gray-800 dark:text-white">Enhanced Borrow Checker Analysis</h3>
                <div class="space-y-3">
                    ${ffiAllocations.filter(alloc => alloc.borrow_info).map(alloc => createEnhancedBorrowAnalysisCard(alloc)).join('')}
                </div>
            </div>

            <!-- Clone Analysis from improve.md fields -->
            ${analysis.totalClones > 0 ? `
                <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6">
                    <h3 class="text-lg font-semibold mb-4 text-gray-800 dark:text-white">Clone Analysis</h3>
                    <div class="space-y-3">
                        ${ffiAllocations.filter(alloc => alloc.clone_info && alloc.clone_info.clone_count > 0).map(alloc => createCloneAnalysisCard(alloc)).join('')}
                    </div>
                </div>
            ` : ''}

            <!-- Ownership History Analysis -->
            ${ffiAllocations.some(alloc => alloc.ownership_history_available) ? `
                <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6">
                    <h3 class="text-lg font-semibold mb-4 text-gray-800 dark:text-white">Ownership History Analysis</h3>
                    <div class="space-y-3">
                        ${ffiAllocations.filter(alloc => alloc.ownership_history_available).map(alloc => createOwnershipHistoryCard(alloc)).join('')}
                    </div>
                </div>
            ` : ''}
        </div>
    `;
}

// Legacy function for backward compatibility
function createEnhancedFFIDashboard(analysis, ffiAllocations) {
    return createEnhancedFFIDashboardWithImproveFields(analysis, ffiAllocations, [], []);
}

// Create enhanced FFI allocation card with improve.md fields
function createEnhancedFFIAllocationCard(alloc) {
    const riskColor = alloc.riskLevel === 'High' ? 'red' : alloc.riskLevel === 'Medium' ? 'orange' : 'green';
    const hasViolations = alloc.violations > 0;
    const hasBorrowConflicts = alloc.borrowConflicts;
    const hasClones = alloc.cloneCount > 0;
    const isLeaked = alloc.isLeaked;
    const hasOwnershipHistory = alloc.ownershipHistoryAvailable;
    
    return `
        <div class="bg-white dark:bg-gray-600 rounded-lg p-4 border-l-4 border-${riskColor}-500">
            <div class="flex justify-between items-start mb-3">
                <div>
                    <h4 class="font-semibold text-gray-900 dark:text-white">${alloc.var_name || 'Unknown Variable'}</h4>
                    <p class="text-sm text-gray-600 dark:text-gray-300">${formatTypeName(alloc.type_name || 'Unknown Type')}</p>
                    ${alloc.isClone ? '<span class="inline-block px-2 py-1 text-xs bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 rounded-full mt-1">Clone</span>' : ''}
                </div>
                <div class="text-right">
                    <span class="px-2 py-1 text-xs font-bold rounded-full bg-${riskColor}-100 text-${riskColor}-800 dark:bg-${riskColor}-900 dark:text-${riskColor}-200">
                        ${alloc.riskLevel} Risk
                    </span>
                    ${isLeaked ? '<div class="mt-1"><span class="px-2 py-1 text-xs bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200 rounded-full">LEAKED</span></div>' : ''}
                </div>
            </div>
            
            <div class="grid grid-cols-2 gap-4 text-sm mb-3">
                <div>
                    <span class="text-gray-500 dark:text-gray-400">Size:</span>
                    <span class="ml-2 font-mono">${formatBytes(alloc.size || 0)}</span>
                </div>
                <div>
                    <span class="text-gray-500 dark:text-gray-400">Risk Score:</span>
                    <span class="ml-2 font-bold text-${riskColor}-600">${alloc.riskScore}/100</span>
                </div>
                <div>
                    <span class="text-gray-500 dark:text-gray-400">Pointer:</span>
                    <span class="ml-2 font-mono text-xs">${alloc.ptr}</span>
                </div>
                <div>
                    <span class="text-gray-500 dark:text-gray-400">Thread:</span>
                    <span class="ml-2">${alloc.thread_id || 'Unknown'}</span>
                </div>
            </div>

            <!-- Enhanced improve.md fields -->
            <div class="grid grid-cols-3 gap-4 text-sm mb-3">
                <div>
                    <span class="text-gray-500 dark:text-gray-400">Total Borrows:</span>
                    <span class="ml-2 font-bold">${alloc.totalBorrowsForAlloc || 0}</span>
                </div>
                <div>
                    <span class="text-gray-500 dark:text-gray-400">Clone Count:</span>
                    <span class="ml-2 font-bold">${alloc.cloneCount || 0}</span>
                </div>
                <div>
                    <span class="text-gray-500 dark:text-gray-400">FFI Tracked:</span>
                    <span class="ml-2">${alloc.ffi_tracked ? 'โœ…' : 'โŒ'}</span>
                </div>
            </div>
            
            ${hasViolations || hasBorrowConflicts || hasClones || hasOwnershipHistory ? `
                <div class="mt-3 pt-3 border-t border-gray-200 dark:border-gray-500">
                    <div class="text-sm space-y-1">
                        ${hasViolations ? `<div class="text-red-600 dark:text-red-400">โš ๏ธ ${alloc.violations} safety violations</div>` : ''}
                        ${hasBorrowConflicts ? `<div class="text-orange-600 dark:text-orange-400">โš ๏ธ Borrow conflicts detected</div>` : ''}
                        ${hasClones ? `<div class="text-blue-600 dark:text-blue-400">๐Ÿ”„ ${alloc.cloneCount} clones created</div>` : ''}
                        ${hasOwnershipHistory ? `<div class="text-green-600 dark:text-green-400">๐Ÿ“‹ Ownership history available</div>` : ''}
                    </div>
                </div>
            ` : ''}
        </div>
    `;
}

// Legacy function for backward compatibility
function createFFIAllocationCard(alloc) {
    return createEnhancedFFIAllocationCard(alloc);
}

// Create enhanced borrow analysis card with improve.md fields
function createEnhancedBorrowAnalysisCard(alloc) {
    const borrowInfo = alloc.borrow_info;
    const hasConflict = borrowInfo.mutable_borrows > 0 && borrowInfo.immutable_borrows > 0;
    const lastBorrowTime = borrowInfo.last_borrow_timestamp ? new Date(borrowInfo.last_borrow_timestamp / 1000000).toLocaleTimeString() : 'Unknown';
    
    return `
        <div class="bg-white dark:bg-gray-600 rounded-lg p-3 ${hasConflict ? 'border-l-4 border-red-500' : 'border border-gray-200 dark:border-gray-500'}">
            <div class="flex justify-between items-start">
                <div>
                    <h5 class="font-medium text-gray-900 dark:text-white">${alloc.var_name}</h5>
                    <p class="text-xs text-gray-500 dark:text-gray-400">${formatTypeName(alloc.type_name)}</p>
                    <p class="text-xs text-gray-500 dark:text-gray-400">Last borrow: ${lastBorrowTime}</p>
                </div>
                <div class="text-right text-sm">
                    <div class="text-blue-600 dark:text-blue-400">Immutable: ${borrowInfo.immutable_borrows}</div>
                    <div class="text-red-600 dark:text-red-400">Mutable: ${borrowInfo.mutable_borrows}</div>
                    <div class="text-purple-600 dark:text-purple-400">Max Concurrent: ${borrowInfo.max_concurrent_borrows}</div>
                    <div class="text-xs text-gray-500 dark:text-gray-400">Total: ${(borrowInfo.immutable_borrows || 0) + (borrowInfo.mutable_borrows || 0)}</div>
                </div>
            </div>
            ${hasConflict ? `
                <div class="mt-2 text-xs text-red-600 dark:text-red-400 font-bold">
                    โš ๏ธ BORROW CONFLICT: Simultaneous mutable and immutable borrows detected
                </div>
            ` : ''}
        </div>
    `;
}

// Legacy function for backward compatibility
function createBorrowAnalysisCard(alloc) {
    return createEnhancedBorrowAnalysisCard(alloc);
}

// Create clone analysis card for improve.md clone_info fields
function createCloneAnalysisCard(alloc) {
    const cloneInfo = alloc.clone_info;
    const isClone = cloneInfo.is_clone;
    const cloneCount = cloneInfo.clone_count;
    const originalPtr = cloneInfo.original_ptr;
    
    return `
        <div class="bg-white dark:bg-gray-600 rounded-lg p-3 border-l-4 border-blue-500">
            <div class="flex justify-between items-start">
                <div>
                    <h5 class="font-medium text-gray-900 dark:text-white">${alloc.var_name}</h5>
                    <p class="text-xs text-gray-500 dark:text-gray-400">${formatTypeName(alloc.type_name)}</p>
                    ${isClone ? `<p class="text-xs text-blue-600 dark:text-blue-400">Clone of: ${originalPtr}</p>` : ''}
                </div>
                <div class="text-right">
                    <div class="text-blue-600 dark:text-blue-400 font-bold text-lg">${cloneCount}</div>
                    <div class="text-xs text-gray-500 dark:text-gray-400">Clones Created</div>
                    ${isClone ? '<div class="text-xs bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 px-2 py-1 rounded mt-1">IS CLONE</div>' : ''}
                </div>
            </div>
            <div class="mt-2 text-sm text-gray-600 dark:text-gray-300">
                ${cloneCount > 0 ? `๐Ÿ”„ This allocation has been cloned ${cloneCount} times` : ''}
                ${isClone ? `<br>๐Ÿ“‹ This is a clone of allocation at ${originalPtr}` : ''}
            </div>
        </div>
    `;
}

// Create ownership history card for improve.md ownership_history_available field
function createOwnershipHistoryCard(alloc) {
    return `
        <div class="bg-white dark:bg-gray-600 rounded-lg p-3 border-l-4 border-green-500">
            <div class="flex justify-between items-center">
                <div>
                    <h5 class="font-medium text-gray-900 dark:text-white">${alloc.var_name}</h5>
                    <p class="text-xs text-gray-500 dark:text-gray-400">${formatTypeName(alloc.type_name)}</p>
                </div>
                <div class="text-right">
                    <div class="text-green-600 dark:text-green-400">๐Ÿ“‹ History Available</div>
                    <div class="text-xs text-gray-500 dark:text-gray-400">Detailed tracking enabled</div>
                </div>
            </div>
            <div class="mt-2 text-sm text-gray-600 dark:text-gray-300">
                โœ… Ownership history is available for this allocation in lifetime.json
            </div>
        </div>
    `;
}

// Create unsafe report card for improve.md UnsafeReport structure
function createUnsafeReportCard(report) {
    const riskLevel = report.risk_assessment?.risk_level || 'Unknown';
    const riskColor = riskLevel === 'High' ? 'red' : riskLevel === 'Medium' ? 'orange' : 'green';
    const confidenceScore = report.risk_assessment?.confidence_score || 0;
    const riskFactors = report.risk_assessment?.risk_factors || [];
    const dynamicViolations = report.dynamic_violations || [];
    
    return `
        <div class="bg-white dark:bg-gray-600 rounded-lg p-4 border-l-4 border-${riskColor}-500">
            <div class="flex justify-between items-start mb-3">
                <div>
                    <h4 class="font-semibold text-gray-900 dark:text-white">Unsafe Report: ${report.report_id || 'Unknown'}</h4>
                    <p class="text-sm text-gray-600 dark:text-gray-300">${report.source?.type || 'Unknown'} at ${report.source?.location || 'Unknown location'}</p>
                </div>
                <div class="text-right">
                    <span class="px-2 py-1 text-xs font-bold rounded-full bg-${riskColor}-100 text-${riskColor}-800 dark:bg-${riskColor}-900 dark:text-${riskColor}-200">
                        ${riskLevel} Risk
                    </span>
                    <div class="text-xs text-gray-500 dark:text-gray-400 mt-1">Confidence: ${(confidenceScore * 100).toFixed(1)}%</div>
                </div>
            </div>
            
            ${riskFactors.length > 0 ? `
                <div class="mb-3">
                    <h5 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Risk Factors:</h5>
                    <div class="space-y-1">
                        ${riskFactors.map(factor => `
                            <div class="text-sm">
                                <span class="font-medium text-${riskColor}-600 dark:text-${riskColor}-400">${factor.factor_type}</span>
                                <span class="text-gray-600 dark:text-gray-400"> (Severity: ${factor.severity}/10)</span>
                                <div class="text-xs text-gray-500 dark:text-gray-400">${factor.description}</div>
                            </div>
                        `).join('')}
                    </div>
                </div>
            ` : ''}
            
            ${dynamicViolations.length > 0 ? `
                <div class="mt-3 pt-3 border-t border-gray-200 dark:border-gray-500">
                    <h5 class="text-sm font-medium text-red-700 dark:text-red-300 mb-2">Dynamic Violations:</h5>
                    <div class="space-y-1">
                        ${dynamicViolations.map(violation => `
                            <div class="text-sm text-red-600 dark:text-red-400">
                                โš ๏ธ ${violation.violation_type}: ${violation.description}
                            </div>
                        `).join('')}
                    </div>
                </div>
            ` : ''}
        </div>
    `;
}

// Create memory passport card for improve.md MemoryPassport structure
function createMemoryPassportCard(passport) {
    const status = passport.status_at_shutdown || 'Unknown';
    const statusColor = status === 'Reclaimed' ? 'green' : status === 'InForeignCustody' ? 'red' : 'orange';
    const lifecycleEvents = passport.lifecycle_events || [];
    
    return `
        <div class="bg-white dark:bg-gray-600 rounded-lg p-3 border-l-4 border-${statusColor}-500">
            <div class="flex justify-between items-start">
                <div>
                    <h5 class="font-medium text-gray-900 dark:text-white">Passport: ${passport.passport_id || 'Unknown'}</h5>
                    <p class="text-xs text-gray-500 dark:text-gray-400">Allocation: ${passport.allocation_ptr} (${formatBytes(passport.size_bytes || 0)})</p>
                </div>
                <div class="text-right">
                    <span class="px-2 py-1 text-xs font-bold rounded-full bg-${statusColor}-100 text-${statusColor}-800 dark:bg-${statusColor}-900 dark:text-${statusColor}-200">
                        ${status}
                    </span>
                </div>
            </div>
            
            ${lifecycleEvents.length > 0 ? `
                <div class="mt-2">
                    <h6 class="text-xs font-medium text-gray-700 dark:text-gray-300 mb-1">Lifecycle Events:</h6>
                    <div class="space-y-1">
                        ${lifecycleEvents.slice(0, 3).map(event => `
                            <div class="text-xs text-gray-600 dark:text-gray-400">
                                ๐Ÿ“… ${event.event_type} ${event.how ? `(${event.how})` : ''}
                            </div>
                        `).join('')}
                        ${lifecycleEvents.length > 3 ? `<div class="text-xs text-gray-500 dark:text-gray-400">... and ${lifecycleEvents.length - 3} more events</div>` : ''}
                    </div>
                </div>
            ` : ''}
        </div>
    `;
}

// Create FFI empty state
function createFFIEmptyState() {
    return `
        <div class="text-center py-8">
            <div class="mb-4">
                <svg class="w-16 h-16 mx-auto text-green-400 dark:text-green-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path>
                </svg>
            </div>
            <h4 class="text-lg font-semibold mb-2 text-gray-800 dark:text-gray-200">Memory Safety Verified</h4>
            <p class="text-sm text-gray-600 dark:text-gray-400">No unsafe FFI operations detected in this analysis</p>
            <p class="text-xs mt-2 text-gray-500 dark:text-gray-500">Your code appears to be using safe Rust patterns</p>
        </div>
    `;
}

// Create comprehensive FFI dashboard with SVG-style visualization
function createFFIDashboardSVG(unsafeAllocs, ffiAllocs, boundaryCrossings, safetyViolations, unsafeMemory, enhancedData, boundaryEvents, violations) {
    return `
        <div class="bg-gradient-to-br from-gray-800 to-gray-900 rounded-xl p-6 text-white shadow-2xl">
            <!-- Header -->
            <div class="text-center mb-6">
                <h2 class="text-2xl font-bold mb-2 flex items-center justify-center">
                    <i class="fa fa-shield mr-3 text-red-400"></i>
                    Unsafe Rust & FFI Memory Analysis Dashboard
                </h2>
            </div>

            <!-- Key Metrics Row -->
            <div class="grid grid-cols-2 md:grid-cols-5 gap-4 mb-8">
                ${createFFIMetricCard('Unsafe Allocations', unsafeAllocs, '#e74c3c', 'fa-exclamation-triangle')}
                ${createFFIMetricCard('FFI Allocations', ffiAllocs, '#3498db', 'fa-exchange')}
                ${createFFIMetricCard('Boundary Crossings', boundaryCrossings, '#f39c12', 'fa-arrows-h')}
                ${createFFIMetricCard('Safety Violations', safetyViolations, '#e67e22', 'fa-warning')}
                ${createFFIMetricCard('Unsafe Memory', formatBytes(unsafeMemory), '#9b59b6', 'fa-memory')}
            </div>

            <!-- Main Dashboard Content -->
            <div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
                <!-- Memory Allocation Sources -->
                <div class="bg-gray-700/50 rounded-lg p-4 backdrop-blur-sm">
                    <h3 class="text-lg font-semibold mb-4 text-white">Memory Allocation Sources</h3>
                    <div class="space-y-4">
                        ${createAllocationSourceBar('Unsafe Rust', unsafeAllocs, Math.max(unsafeAllocs, ffiAllocs), '#e74c3c')}
                        ${createAllocationSourceBar('FFI', ffiAllocs, Math.max(unsafeAllocs, ffiAllocs), '#3498db')}
                    </div>
                </div>

                <!-- Memory Safety Status -->
                <div class="bg-gray-700/50 rounded-lg p-4 backdrop-blur-sm">
                    <h3 class="text-lg font-semibold mb-4 text-white">Memory Safety Status</h3>
                    ${safetyViolations > 0 ? `
                        <div class="bg-red-900/30 border border-red-500/50 rounded-lg p-4">
                            <h4 class="text-red-300 font-semibold mb-2 flex items-center">
                                <i class="fa fa-exclamation-triangle mr-2"></i>
                                ${safetyViolations} Safety Violations Detected
                            </h4>
                            ${enhancedData.filter(item => (item.safety_violations || 0) > 0).slice(0, 2).map(item => `
                                <div class="text-red-400 text-sm flex items-center mb-1">
                                    <i class="fa fa-dot-circle-o mr-2 text-xs"></i>
                                    Pointer ${item.ptr}: ${item.safety_violations} violations
                                </div>
                            `).join('')}
                        </div>
                    ` : `
                        <div class="bg-green-900/30 border border-green-500/50 rounded-lg p-4">
                            <h4 class="text-green-300 font-semibold flex items-center mb-2">
                                <i class="fa fa-check-circle mr-2"></i>
                                No Safety Violations Detected
                            </h4>
                            <p class="text-green-400 text-sm">All unsafe operations appear to be handled correctly</p>
                        </div>
                    `}
                </div>
            </div>

            <!-- Cross-Language Memory Flow -->
            <div class="bg-gray-700/50 rounded-lg p-6 mb-6 backdrop-blur-sm">
                <h3 class="text-lg font-semibold mb-6 text-white text-center">Cross-Language Memory Flow</h3>
                <div class="flex items-center justify-center space-x-8">
                    <!-- Rust Side -->
                    <div class="bg-green-800/30 border-2 border-green-400/50 rounded-lg p-6 text-center backdrop-blur-sm">
                        <div class="text-green-300 font-bold text-xl mb-2">RUST</div>
                        <div class="text-green-400 text-sm">${unsafeAllocs} allocations</div>
                        <div class="w-16 h-16 mx-auto mt-3 bg-green-500/20 rounded-full flex items-center justify-center">
                            <i class="fa fa-rust text-green-400 text-2xl"></i>
                        </div>
                    </div>
                    
                    <!-- Flow Arrows -->
                    <div class="flex flex-col items-center space-y-4">
                        <div class="flex items-center space-x-2">
                            <div class="flex items-center space-x-1">
                                <div class="w-8 h-0.5 bg-red-400"></div>
                                <div class="w-0 h-0 border-l-4 border-l-red-400 border-t-2 border-t-transparent border-b-2 border-b-transparent"></div>
                            </div>
                            <span class="text-red-400 text-sm font-bold bg-red-900/30 px-2 py-1 rounded">
                                ${boundaryEvents.filter(e => e.event_type === 'RustToFfi').length}
                            </span>
                        </div>
                        <div class="flex items-center space-x-2">
                            <span class="text-orange-400 text-sm font-bold bg-orange-900/30 px-2 py-1 rounded">
                                ${boundaryEvents.filter(e => e.event_type === 'FfiToRust').length}
                            </span>
                            <div class="flex items-center space-x-1">
                                <div class="w-0 h-0 border-r-4 border-r-orange-400 border-t-2 border-t-transparent border-b-2 border-b-transparent"></div>
                                <div class="w-8 h-0.5 bg-orange-400"></div>
                            </div>
                        </div>
                    </div>
                    
                    <!-- FFI/C Side -->
                    <div class="bg-blue-800/30 border-2 border-blue-400/50 rounded-lg p-6 text-center backdrop-blur-sm">
                        <div class="text-blue-300 font-bold text-xl mb-2">FFI / C</div>
                        <div class="text-blue-400 text-sm">${ffiAllocs} allocations</div>
                        <div class="w-16 h-16 mx-auto mt-3 bg-blue-500/20 rounded-full flex items-center justify-center">
                            <i class="fa fa-code text-blue-400 text-2xl"></i>
                        </div>
                    </div>
                </div>
            </div>

            <!-- Unsafe Memory Hotspots -->
            <div class="bg-gray-700/50 rounded-lg p-4 backdrop-blur-sm">
                <h3 class="text-lg font-semibold mb-4 text-white">Unsafe Memory Hotspots</h3>
                <div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-4">
                    ${enhancedData.slice(0, 12).map(item => createMemoryHotspot(item)).join('')}
                </div>
                ${enhancedData.length === 0 ? `
                    <div class="text-center py-8 text-gray-400">
                        <i class="fa fa-shield-alt text-4xl mb-2"></i>
                        <p>No unsafe memory hotspots detected</p>
                    </div>
                ` : ''}
            </div>
        </div>
    `;
}

// Create FFI metric card
function createFFIMetricCard(title, value, color, icon) {
    return `
        <div class="bg-gray-700/30 border border-gray-600/50 rounded-lg p-4 text-center backdrop-blur-sm hover:bg-gray-600/30 transition-all">
            <div class="flex items-center justify-center mb-2">
                <i class="fa ${icon} text-2xl" style="color: ${color}"></i>
            </div>
            <div class="text-2xl font-bold mb-1" style="color: ${color}">${value}</div>
            <div class="text-xs text-gray-300 uppercase tracking-wide">${title}</div>
        </div>
    `;
}

// Create allocation source bar
function createAllocationSourceBar(label, count, maxCount, color) {
    const percentage = maxCount > 0 ? (count / maxCount) * 100 : 0;
    const barHeight = Math.max(20, (count / maxCount) * 80);

    return `
        <div class="flex items-end space-x-4">
            <div class="flex-1">
                <div class="flex justify-between items-center mb-2">
                    <span class="text-sm font-medium text-gray-300">${label}</span>
                    <span class="text-lg font-bold text-white">${count}</span>
                </div>
                <div class="w-full bg-gray-600 rounded-full h-6 overflow-hidden">
                    <div class="h-full rounded-full transition-all duration-500 flex items-center justify-center text-white text-xs font-bold" 
                         style="width: ${percentage}%; background-color: ${color};">
                        ${count > 0 ? count : ''}
                    </div>
                </div>
            </div>
        </div>
    `;
}

// Create memory hotspot visualization
function createMemoryHotspot(item) {
    const size = item.size || 0;
    const isUnsafe = !item.ffi_tracked;
    const radius = Math.min(30, Math.max(12, Math.sqrt(size / 50)));
    const color = isUnsafe ? '#e74c3c' : '#3498db';
    const bgColor = isUnsafe ? 'bg-red-900/20' : 'bg-blue-900/20';
    const borderColor = isUnsafe ? 'border-red-500/50' : 'border-blue-500/50';

    // Interactive hotspot with data attributes for detail panel
    return `
        <div class="flex flex-col items-center p-3 ${bgColor} border ${borderColor} rounded-lg backdrop-blur-sm hover:scale-105 transition-transform cursor-pointer"
             data-ptr="${item.ptr || ''}"
             data-var="${(item.var_name || 'Unknown').toString().replace(/\"/g, '&quot;')}"
             data-type="${(item.type_name || 'Unknown').toString().replace(/\"/g, '&quot;')}"
             data-size="${size}"
             data-violations="${(item.safety_violations || 0)}"
             onclick="window.showFFIDetailFromDataset && window.showFFIDetailFromDataset(this)">
            <div class="relative mb-2">
                <div class="rounded-full border-2 flex items-center justify-center text-white text-xs font-bold shadow-lg"
                     style="width: ${radius * 2}px; height: ${radius * 2}px; background-color: ${color}; border-color: ${color};">
                    ${size > 1024 ? Math.round(size / 1024) + 'K' : size + 'B'}
                </div>
                ${(item.safety_violations || 0) > 0 ? `
                    <div class="absolute -top-1 -right-1 w-4 h-4 bg-red-500 rounded-full flex items-center justify-center">
                        <i class="fa fa-exclamation text-white text-xs"></i>
                    </div>
                ` : ''}
            </div>
            <div class="text-xs text-center">
                <div class="font-semibold" style="color: ${color}">
                    ${isUnsafe ? 'UNSAFE' : 'FFI'}
                </div>
                <div class="text-gray-400 text-xs">
                    ${formatBytes(size)}
                </div>
            </div>
        </div>
    `;
}

// Simple detail panel for FFI hotspot items
window.showFFIDetailFromDataset = function(el) {
    try {
        const container = document.getElementById('ffiVisualization');
        if (!container) return;

        // Remove existing panel
        const existing = container.querySelector('#ffi-detail-panel');
        if (existing) existing.remove();

        // Build panel
        const panel = document.createElement('div');
        panel.id = 'ffi-detail-panel';
        panel.style.position = 'absolute';
        panel.style.right = '16px';
        panel.style.top = '16px';
        panel.style.zIndex = '1000';
        panel.style.minWidth = '280px';
        panel.style.maxWidth = '360px';
        panel.style.background = 'var(--bg-primary)';
        panel.style.border = '1px solid var(--border-light)';
        panel.style.borderRadius = '10px';
        panel.style.boxShadow = '0 10px 25px rgba(0,0,0,0.2)';
        panel.style.padding = '12px';

        const name = el.getAttribute('data-var');
        const type = el.getAttribute('data-type');
        const size = parseInt(el.getAttribute('data-size') || '0', 10);
        const ptr = el.getAttribute('data-ptr');
        const violations = parseInt(el.getAttribute('data-violations') || '0', 10);

        panel.innerHTML = `
            <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:8px;">
                <div style="font-weight:700; font-size:14px; color: var(--text-primary);">FFI Allocation Detail</div>
                <button onclick="this.parentNode.parentNode.remove()" style="border:none; background:transparent; color: var(--text-secondary); font-size:18px; cursor:pointer">ร—</button>
            </div>
            <div style="font-size:12px; color: var(--text-primary);">
                <div style="margin-bottom:6px;"><strong>Name:</strong> ${name}</div>
                <div style="margin-bottom:6px;"><strong>Type:</strong> ${type}</div>
                <div style="margin-bottom:6px;"><strong>Size:</strong> ${formatBytes(size)}</div>
                ${ptr ? `<div style=\"margin-bottom:6px;\"><strong>Pointer:</strong> <code>${ptr}</code></div>` : ''}
                <div style="margin-bottom:6px;"><strong>Safety Violations:</strong> ${violations}</div>
            </div>
        `;

        container.appendChild(panel);
    } catch(e) {
        console.warn('Failed to show FFI detail panel', e);
    }
};

// Initialize memory fragmentation analysis with enhanced SVG-style visualization
function initMemoryFragmentation() {
    const container = document.getElementById('memoryFragmentation');
    if (!container) return;

    const allocations = window.analysisData.memory_analysis?.allocations || [];

    if (allocations.length === 0) {
        container.innerHTML = createFragmentationEmptyState();
        return;
    }

    // Fixed memory fragmentation analysis: based on allocation size distribution rather than address gaps
    const sortedAllocs = allocations
        .filter(alloc => alloc.size && alloc.size > 0)
        .map(alloc => ({
            size: alloc.size,
            type: alloc.type_name || 'System Allocation',
            var_name: alloc.var_name || 'unknown'
        }))
        .sort((a, b) => a.size - b.size);

    const totalMemory = sortedAllocs.reduce((sum, alloc) => sum + alloc.size, 0);
    
    // Calculate fragmentation based on allocation size distribution
    const sizeVariance = calculateSizeVariance(sortedAllocs);
    const smallAllocRatio = sortedAllocs.filter(a => a.size < 1024).length / sortedAllocs.length;
    
    // Fragmentation score: based on size distribution unevenness
    const fragmentationRatio = Math.min(100, (sizeVariance / 1000 + smallAllocRatio * 50));
    
    // Simplified gap analysis: only count quantity, not fake address gaps
    const gaps = Math.max(0, sortedAllocs.length - 1);
    const maxGap = 0; // No longer calculate address gaps
    let totalGapSize = 0; // Reset to 0 to avoid huge fake values

    // Size distribution analysis (inspired by SVG)
    const sizeDistribution = {
        tiny: sortedAllocs.filter(a => a.size < 64).length,
        small: sortedAllocs.filter(a => a.size >= 64 && a.size < 1024).length,
        medium: sortedAllocs.filter(a => a.size >= 1024 && a.size < 65536).length,
        large: sortedAllocs.filter(a => a.size >= 65536).length
    };

    container.innerHTML = createFragmentationAnalysisSVG(
        fragmentationRatio, gaps, maxGap, sortedAllocs.length,
        totalMemory, sizeDistribution, sortedAllocs
    );
}

// Create fragmentation empty state
function createFragmentationEmptyState() {
    return `
        <div class="bg-white dark:bg-gray-800 rounded-xl p-6 card-shadow transition-colors">
            <h2 class="text-xl font-semibold mb-4 flex items-center text-heading">
                <i class="fa fa-puzzle-piece text-orange-500 mr-2"></i>Memory Fragmentation Analysis
            </h2>
            <div class="text-center py-8">
                <div class="mb-4">
                    <svg class="w-16 h-16 mx-auto text-gray-400 dark:text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path>
                    </svg>
                </div>
                <h4 class="text-lg font-semibold mb-2 text-gray-800 dark:text-gray-200">No Memory Data for Analysis</h4>
                <p class="text-sm text-gray-600 dark:text-gray-400">Memory fragmentation analysis requires allocation data</p>
            </div>
        </div>
    `;
}

// Create comprehensive fragmentation analysis with SVG-style visualization
function createFragmentationAnalysisSVG(fragmentationRatio, gaps, maxGap, blockCount, totalMemory, sizeDistribution, sortedAllocs) {
    return `
        <div class="bg-white dark:bg-gray-800 rounded-xl p-6 card-shadow transition-colors">
            <h2 class="text-xl font-semibold mb-6 flex items-center text-heading">
                <i class="fa fa-puzzle-piece text-orange-500 mr-2"></i>Memory Fragmentation Analysis
            </h2>
            
            <!-- Key Metrics Grid -->
            <div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
                ${createFragmentationMetricCard('Fragmentation', fragmentationRatio.toFixed(1) + '%', fragmentationRatio, '#f39c12')}
                ${createFragmentationMetricCard('Memory Gaps', gaps, 100, '#3498db')}
                ${createFragmentationMetricCard('Largest Gap', formatBytes(maxGap), 100, '#27ae60')}
                ${createFragmentationMetricCard('Memory Blocks', blockCount, 100, '#9b59b6')}
            </div>

            <!-- Main Analysis Content -->
            <div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
                <!-- Fragmentation Assessment -->
                <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-4">
                    <h4 class="font-semibold mb-4 text-gray-800 dark:text-white">Fragmentation Assessment</h4>
                    <div class="space-y-4">
                        <div>
                            <div class="flex justify-between items-center mb-2">
                                <span class="text-sm font-medium text-gray-700 dark:text-gray-300">Overall Health</span>
                                <span class="text-sm font-bold ${getFragmentationColor(fragmentationRatio)}">${fragmentationRatio.toFixed(1)}%</span>
                            </div>
                            <div class="w-full bg-gray-200 dark:bg-gray-600 rounded-full h-4">
                                <div class="h-4 rounded-full transition-all duration-500 ${getFragmentationBgColor(fragmentationRatio)}" 
                                     style="width: ${Math.min(fragmentationRatio, 100)}%"></div>
                            </div>
                        </div>
                        <div class="text-sm text-gray-600 dark:text-gray-300">
                            ${getFragmentationAssessment(fragmentationRatio)}
                        </div>
                    </div>
                </div>

                <!-- Size Distribution (inspired by SVG bar chart) -->
                <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-4">
                    <h4 class="font-semibold mb-4 text-gray-800 dark:text-white">Size Distribution</h4>
                    <div class="space-y-3">
                        ${createSizeDistributionBar('Tiny (0-64B)', sizeDistribution.tiny, blockCount, '#27ae60')}
                        ${createSizeDistributionBar('Small (64B-1KB)', sizeDistribution.small, blockCount, '#f39c12')}
                        ${createSizeDistributionBar('Medium (1KB-64KB)', sizeDistribution.medium, blockCount, '#e74c3c')}
                        ${createSizeDistributionBar('Large (>64KB)', sizeDistribution.large, blockCount, '#8e44ad')}
                    </div>
                </div>
            </div>

            <!-- Memory Layout Visualization -->
            <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-4">
                <h4 class="font-semibold mb-4 text-gray-800 dark:text-white">Memory Layout Visualization</h4>
                <div class="relative">
                    <!-- Memory blocks visualization -->
                    <div class="h-16 bg-gray-200 dark:bg-gray-600 rounded relative overflow-hidden mb-4">
                        ${createMemoryLayoutVisualization(sortedAllocs, totalMemory)}
                    </div>
                    
                    <!-- Memory address timeline -->
                    <div class="flex justify-between text-xs text-gray-500 dark:text-gray-400 mb-2">
                        <span>Low Address</span>
                        <span>Memory Layout</span>
                        <span>High Address</span>
                    </div>
                    
                    <!-- Legend -->
                    <div class="flex flex-wrap gap-4 text-xs">
                        <div class="flex items-center">
                            <div class="w-3 h-3 bg-blue-500 rounded mr-2"></div>
                            <span class="text-gray-600 dark:text-gray-300">User Allocations</span>
                        </div>
                        <div class="flex items-center">
                            <div class="w-3 h-3 bg-gray-400 rounded mr-2"></div>
                            <span class="text-gray-600 dark:text-gray-300">System Allocations</span>
                        </div>
                        <div class="flex items-center">
                            <div class="w-3 h-3 bg-red-300 rounded mr-2"></div>
                            <span class="text-gray-600 dark:text-gray-300">Memory Gaps</span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    `;
}

// Create fragmentation metric card with circular progress
function createFragmentationMetricCard(title, value, percentage, color) {
    const normalizedPercentage = Math.min(100, Math.max(0, percentage));
    const circumference = 2 * Math.PI * 20;
    const strokeDashoffset = circumference - (normalizedPercentage / 100) * circumference;

    return `
        <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-4 text-center hover:shadow-md transition-shadow">
            <div class="flex items-center justify-between">
                <div class="flex-1">
                    <p class="text-xs font-medium text-gray-600 dark:text-gray-400 uppercase">${title}</p>
                    <p class="text-lg font-bold text-gray-900 dark:text-white">${value}</p>
                </div>
                <div class="relative w-10 h-10">
                    <svg class="w-10 h-10 transform -rotate-90" viewBox="0 0 50 50">
                        <circle cx="25" cy="25" r="20" stroke='#e5e7eb' stroke-width='4' fill='none' class='dark:stroke-gray-600'/>
                        <circle cx='25' cy='25' r='20' stroke='${color}' stroke-width='4' fill='none' 
                                stroke-dasharray='${circumference}' stroke-dashoffset='${strokeDashoffset}'
                                stroke-linecap='round' class='transition-all duration-500'/>
                    </svg>
                </div>
            </div>
        </div>
    `;
}

// Create size distribution bar
function createSizeDistributionBar(label, count, total, color) {
    const percentage = total > 0 ? (count / total) * 100 : 0;
    return `
        <div class="flex items-center justify-between">
            <span class="text-sm font-medium text-gray-700 dark:text-gray-300 w-28">${label}</span>
            <div class="flex-1 mx-3">
                <div class="w-full bg-gray-200 dark:bg-gray-600 rounded-full h-4">
                    <div class="h-4 rounded-full transition-all duration-500" 
                         style="width: ${percentage}%; background-color: ${color}"></div>
                </div>
            </div>
            <span class="text-sm font-bold text-gray-900 dark:text-white w-8 text-right">${count}</span>
        </div>
    `;
}

// Create memory layout visualization
function createMemoryLayoutVisualization(sortedAllocs, totalMemory) {
    if (sortedAllocs.length === 0) return '<div class="flex items-center justify-center h-full text-gray-400">No memory layout data</div>';

    return sortedAllocs.slice(0, 30).map((alloc, index) => {
        const width = Math.max(1, (alloc.size / totalMemory) * 100);
        const left = (index / 30) * 100;
        const isUserAlloc = alloc.type !== 'System Allocation';
        const color = isUserAlloc ? '#3498db' : '#95a5a6';

        return `
            <div class="absolute h-full transition-all hover:brightness-110 cursor-pointer" 
                 style="left: ${left}%; width: ${width}%; background-color: ${color}; opacity: 0.8;"
                 title="${alloc.type}: ${formatBytes(alloc.size)} at ${(alloc.address || 0).toString(16)}">
            </div>
        `;
    }).join('');
}

// Calculate variance of allocation sizes to assess fragmentation level
function calculateSizeVariance(allocations) {
    if (allocations.length === 0) return 0;
    
    const sizes = allocations.map(a => a.size);
    const mean = sizes.reduce((sum, size) => sum + size, 0) / sizes.length;
    const variance = sizes.reduce((sum, size) => sum + Math.pow(size - mean, 2), 0) / sizes.length;
    
    return Math.sqrt(variance); // ่ฟ”ๅ›žๆ ‡ๅ‡†ๅทฎ
}

// Helper functions for fragmentation analysis
function getFragmentationColor(ratio) {
    if (ratio < 10) return 'text-green-600 dark:text-green-400';
    if (ratio < 25) return 'text-yellow-600 dark:text-yellow-400';
    if (ratio < 50) return 'text-orange-600 dark:text-orange-400';
    return 'text-red-600 dark:text-red-400';
}

function getFragmentationBgColor(ratio) {
    if (ratio < 10) return 'bg-green-500';
    if (ratio < 25) return 'bg-yellow-500';
    if (ratio < 50) return 'bg-orange-500';
    return 'bg-red-500';
}

function getFragmentationAssessment(ratio) {
    if (ratio < 10) return 'Excellent memory layout with minimal fragmentation. Memory is well-organized.';
    if (ratio < 25) return 'Good memory layout with low fragmentation. No immediate concerns.';
    if (ratio < 50) return 'Moderate fragmentation detected. Consider memory pool allocation strategies.';
    return 'High fragmentation detected. Memory layout optimization strongly recommended.';
}

// Initialize memory growth trends with enhanced SVG-style visualization
function initMemoryGrowthTrends() {
    const container = document.getElementById('memoryGrowthTrends');
    if (!container) return;

    const allocations = window.analysisData.memory_analysis?.allocations || [];

    // Sort allocations by timestamp
    const sortedAllocs = allocations
        .filter(alloc => alloc.timestamp_alloc)
        .sort((a, b) => a.timestamp_alloc - b.timestamp_alloc);

    if (sortedAllocs.length === 0) {
        container.innerHTML = createGrowthTrendsEmptyState();
        return;
    }

    // Calculate cumulative memory usage over time
    let cumulativeMemory = 0;
    let peakMemory = 0;
    const timePoints = [];

    sortedAllocs.forEach((alloc, index) => {
        cumulativeMemory += alloc.size || 0;
        peakMemory = Math.max(peakMemory, cumulativeMemory);

        if (index % Math.max(1, Math.floor(sortedAllocs.length / 20)) === 0) {
            timePoints.push({
                timestamp: alloc.timestamp_alloc,
                memory: cumulativeMemory,
                index: index,
                allocCount: index + 1
            });
        }
    });

    const startMemory = timePoints[0]?.memory || 0;
    const endMemory = timePoints[timePoints.length - 1]?.memory || 0;
    const growthRate = startMemory > 0 ? ((endMemory - startMemory) / startMemory * 100) : 0;
    const averageMemory = timePoints.reduce((sum, point) => sum + point.memory, 0) / timePoints.length;

    container.innerHTML = createMemoryGrowthTrendsSVG(
        peakMemory, averageMemory, growthRate, timePoints, sortedAllocs.length
    );
}

// Create growth trends empty state
function createGrowthTrendsEmptyState() {
    return `
        <div class="bg-white dark:bg-gray-800 rounded-xl p-6 card-shadow transition-colors">
            <h2 class="text-xl font-semibold mb-4 flex items-center text-heading">
                <i class="fa fa-line-chart text-green-500 mr-2"></i>Memory Growth Trends
            </h2>
            <div class="text-center py-8">
                <div class="mb-4">
                    <svg class="w-16 h-16 mx-auto text-gray-400 dark:text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
                    </svg>
                </div>
                <h4 class="text-lg font-semibold mb-2 text-gray-800 dark:text-gray-200">No Timeline Data Available</h4>
                <p class="text-sm text-gray-600 dark:text-gray-400">Memory growth analysis requires timestamp data</p>
            </div>
        </div>
    `;
}

// Create comprehensive memory growth trends visualization
function createMemoryGrowthTrendsSVG(peakMemory, averageMemory, growthRate, timePoints, totalAllocs) {
    return `
        <div class="bg-white dark:bg-gray-800 rounded-xl p-6 card-shadow transition-colors">
            <h2 class="text-xl font-semibold mb-6 flex items-center text-heading">
                <i class="fa fa-line-chart text-green-500 mr-2"></i>Memory Growth Trends
            </h2>
            
            <!-- Key Metrics Grid -->
            <div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-8">
                ${createGrowthMetricCard('Peak Memory', formatBytes(peakMemory), 100, '#e74c3c')}
                ${createGrowthMetricCard('Average Memory', formatBytes(averageMemory), Math.round((averageMemory / peakMemory) * 100), '#3498db')}
                ${createGrowthMetricCard('Growth Rate', (growthRate > 0 ? '+' : '') + growthRate.toFixed(1) + '%', Math.abs(growthRate), getGrowthRateColor(growthRate))}
                ${createGrowthMetricCard('Total Allocations', totalAllocs, 100, '#9b59b6')}
            </div>

            <!-- Main Growth Chart -->
            <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-6 mb-6">
                <h4 class="font-semibold mb-4 text-gray-800 dark:text-white">Memory Usage Over Time</h4>
                <div class="relative">
                    <!-- Chart Container -->
                    <div class="h-48 relative bg-white dark:bg-gray-600 rounded border dark:border-gray-500 overflow-hidden">
                        ${createMemoryGrowthChart(timePoints, peakMemory)}
                    </div>
                    
                    <!-- Chart Labels -->
                    <div class="flex justify-between text-xs text-gray-500 dark:text-gray-400 mt-2">
                        <span>Start</span>
                        <span>Memory Usage Timeline</span>
                        <span>End</span>
                    </div>
                    
                    <!-- Peak Memory Line -->
                    <div class="absolute top-2 right-2 text-xs text-red-500 dark:text-red-400 bg-white dark:bg-gray-800 px-2 py-1 rounded shadow">
                        Peak: ${formatBytes(peakMemory)}
                    </div>
                </div>
            </div>

            <!-- Growth Analysis -->
            <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                <!-- Growth Assessment -->
                <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-4">
                    <h4 class="font-semibold mb-4 text-gray-800 dark:text-white">Growth Assessment</h4>
                    <div class="space-y-3">
                        <div class="flex items-center justify-between">
                            <span class="text-sm text-gray-600 dark:text-gray-300">Memory Efficiency</span>
                            <span class="text-sm font-bold ${getEfficiencyColor(averageMemory, peakMemory)}">${((averageMemory / peakMemory) * 100).toFixed(1)}%</span>
                        </div>
                        <div class="w-full bg-gray-200 dark:bg-gray-600 rounded-full h-2">
                            <div class="h-2 rounded-full transition-all duration-500 ${getEfficiencyBgColor(averageMemory, peakMemory)}" 
                                 style="width: ${(averageMemory / peakMemory) * 100}%"></div>
                        </div>
                        <div class="text-sm text-gray-600 dark:text-gray-300">
                            ${getGrowthAssessment(growthRate)}
                        </div>
                    </div>
                </div>

                <!-- Memory Allocation Timeline -->
                <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-4">
                    <h4 class="font-semibold mb-4 text-gray-800 dark:text-white">Recent Allocations</h4>
                    <div class="space-y-2 max-h-32 overflow-y-auto">
                        ${timePoints.slice(-6).map((point, index) => `
                            <div class="flex justify-between items-center text-sm">
                                <span class="text-gray-600 dark:text-gray-300">Alloc #${point.allocCount}</span>
                                <span class="font-mono text-xs font-bold text-gray-900 dark:text-white">${formatBytes(point.memory)}</span>
                            </div>
                        `).join('')}
                    </div>
                    <div class="text-xs text-gray-500 dark:text-gray-400 mt-2">
                        Showing latest allocation points
                    </div>
                </div>
            </div>
        </div>
    `;
}

// Create growth metric card
function createGrowthMetricCard(title, value, percentage, color) {
    const normalizedPercentage = Math.min(100, Math.max(0, percentage));

    return `
        <div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-4 text-center hover:shadow-md transition-shadow">
            <div class="mb-2">
                <div class="text-2xl font-bold" style="color: ${color}">${value}</div>
                <div class="text-xs text-gray-600 dark:text-gray-400 uppercase tracking-wide">${title}</div>
            </div>
            <div class="w-full bg-gray-200 dark:bg-gray-600 rounded-full h-2">
                <div class="h-2 rounded-full transition-all duration-500" 
                     style="width: ${normalizedPercentage}%; background-color: ${color}"></div>
            </div>
        </div>
    `;
}

// Create memory growth chart
function createMemoryGrowthChart(timePoints, peakMemory) {
    if (timePoints.length < 2) return '<div class="flex items-center justify-center h-full text-gray-400">Insufficient data points</div>';

    const chartHeight = 180;
    const chartWidth = 100; // percentage

    // Create SVG path for the growth line
    const pathPoints = timePoints.map((point, index) => {
        const x = (index / (timePoints.length - 1)) * chartWidth;
        const y = chartHeight - ((point.memory / peakMemory) * (chartHeight - 20));
        return `${x},${y}`;
    });

    return `
        <!-- Background Grid -->
        <div class="absolute inset-0">
            ${[0, 25, 50, 75, 100].map(y => `
                <div class="absolute w-full border-t border-gray-200 dark:border-gray-500 opacity-30" 
                     style="top: ${y}%"></div>
            `).join('')}
        </div>
        
        <!-- Growth Line -->
        <svg class="absolute inset-0 w-full h-full" preserveAspectRatio="none">
            <polyline
                fill="none"
                stroke='#27ae60'
                stroke-width="3"
                stroke-linecap='round'
                stroke-linejoin='round'
                points='${timePoints.map((point, index) => {
        const x = (index / (timePoints.length - 1)) * 100;
        const y = 100 - ((point.memory / peakMemory) * 90);
        return `${x},${y}`;
    }).join(' ')}'
                class='drop-shadow-sm'
            />
        </svg>
        
        <!-- Data Points -->
        ${timePoints.map((point, index) => {
        const x = (index / (timePoints.length - 1)) * 100;
        const y = 100 - ((point.memory / peakMemory) * 90);
        return `
                <div class="absolute w-3 h-3 bg-green-500 rounded-full border-2 border-white dark:border-gray-600 shadow-sm transform -translate-x-1/2 -translate-y-1/2 hover:scale-125 transition-transform cursor-pointer" 
                     style="left: ${x}%; top: ${y}%"
                     title="Memory: ${formatBytes(point.memory)} at allocation #${point.allocCount}">
                </div>
            `;
    }).join('')}
        
        <!-- Peak Memory Indicator -->
        <div class="absolute w-full border-t-2 border-red-500 border-dashed opacity-60" style="top: 10%">
            <div class="absolute -top-1 right-0 text-xs text-red-500 bg-white dark:bg-gray-600 px-1 rounded">
                Peak
            </div>
        </div>
    `;
}

// Helper functions for growth analysis
function getGrowthRateColor(rate) {
    if (rate < -10) return '#27ae60'; // Green for decreasing
    if (rate < 10) return '#3498db';  // Blue for stable
    if (rate < 50) return '#f39c12'; // Orange for moderate growth
    return '#e74c3c'; // Red for high growth
}

function getEfficiencyColor(avg, peak) {
    const efficiency = (avg / peak) * 100;
    if (efficiency > 80) return 'text-red-600 dark:text-red-400';
    if (efficiency > 60) return 'text-orange-600 dark:text-orange-400';
    if (efficiency > 40) return 'text-yellow-600 dark:text-yellow-400';
    return 'text-green-600 dark:text-green-400';
}

function getEfficiencyBgColor(avg, peak) {
    const efficiency = (avg / peak) * 100;
    if (efficiency > 80) return 'bg-red-500';
    if (efficiency > 60) return 'bg-orange-500';
    if (efficiency > 40) return 'bg-yellow-500';
    return 'bg-green-500';
}

function getGrowthAssessment(rate) {
    if (rate < -10) return 'Excellent: Memory usage is decreasing, indicating good cleanup.';
    if (rate < 10) return 'Good: Stable memory usage with minimal growth.';
    if (rate < 50) return 'Moderate: Some memory growth detected, monitor for trends.';
    return 'Concerning: High memory growth detected, investigate for potential leaks.';
}

// Node Detail Panel for Variable Relationship Graph
class NodeDetailPanel {
    constructor(containerId) {
        this.container = document.getElementById(containerId);
        this.panel = null;
        this.currentNode = null;
    }

    show(nodeData, position) {
        console.log('Showing panel for:', nodeData.id);
        this.hide(); // Close existing panel
        this.panel = this.createPanel(nodeData);
        console.log('Panel created:', this.panel);
        this.positionPanel(position);
        this.container.appendChild(this.panel);
        console.log('Panel added to container');
        this.currentNode = nodeData;
    }

    hide() {
        if (this.panel) {
            this.panel.remove();
            this.panel = null;
            this.currentNode = null;
        }
    }

    createPanel(nodeData) {
        const panel = document.createElement('div');
        panel.className = 'node-detail-panel';

        // Find related allocation data
        const allocations = window.analysisData.memory_analysis?.allocations || [];
        const allocation = allocations.find(alloc => alloc.var_name === nodeData.id);

        // Calculate relationships
        const sameTypeCount = allocations.filter(alloc =>
            alloc.type_name === nodeData.type_name && alloc.var_name !== nodeData.id
        ).length;

        const sameCategoryCount = allocations.filter(alloc =>
            getTypeCategory(alloc.type_name || '') === (nodeData.category || 'primitive') && alloc.var_name !== nodeData.id
        ).length;

        panel.innerHTML = `
            <div class="flex justify-between items-center mb-3">
                <h3>Variable Details</h3>
                <button class="close-button text-xl leading-none">&times;</button>
            </div>
            
            <div class="space-y-3">
                <div>
                    <label>Variable Name</label>
                    <p class="font-mono">${nodeData.id}</p>
                </div>
                
                <div>
                    <label>Type</label>
                    <p class="font-mono">${nodeData.type_name || 'Unknown'}</p>
                    <div class="flex items-center mt-1">
                        <div class="w-3 h-3 rounded-full mr-2" style="background-color: ${getEnhancedTypeColor(nodeData.type_name || 'unknown', nodeData.category || 'primitive')}"></div>
                        <span class="text-xs capitalize">${(nodeData.category || 'primitive').replace('_', ' ')}</span>
                    </div>
                </div>
                
                <div>
                    <label>Memory Size</label>
                    <p>${formatBytes(nodeData.size)}</p>
                </div>
                
                <div>
                    <label>Complexity Score</label>
                    <div class="flex items-center mb-2">
                        <div class="w-5 h-5 rounded-full mr-2 flex items-center justify-center text-white font-bold text-xs" style="background-color: ${getComplexityColor(nodeData.complexity || 2)}">${nodeData.complexity || 2}</div>
                        <span class="font-semibold">${nodeData.complexity || 2}/10 - ${getComplexityLevel(nodeData.complexity || 2)}</span>
                    </div>
                    <div class="text-xs text-gray-600 dark:text-gray-400">
                        ${getComplexityExplanation(nodeData.complexity || 2)}
                    </div>
                </div>
                
                ${allocation ? `
                    <div>
                        <label>Memory Address</label>
                        <p class="font-mono text-xs">${allocation.ptr}</p>
                    </div>
                    
                    <div>
                        <label>Allocated At</label>
                        <p class="text-sm">${new Date(allocation.timestamp_alloc / 1000000).toLocaleString()}</p>
                    </div>
                ` : ''}
                
                <div>
                    <label>Relationships</label>
                    <div class="text-sm space-y-1">
                        <div class="flex justify-between">
                            <span>Same type:</span>
                            <span class="font-semibold">${sameTypeCount}</span>
                        </div>
                        <div class="flex justify-between">
                            <span>Same category:</span>
                            <span class="font-semibold">${sameCategoryCount}</span>
                        </div>
                    </div>
                </div>
                
                <div>
                    <label>Type Analysis</label>
                    <div class="text-xs space-y-1">
                        ${getTypeAnalysis(nodeData.type_name || 'unknown', nodeData.size)}
                    </div>
                </div>
            </div>
        `;

        // Add close button functionality
        const closeButton = panel.querySelector('.close-button');
        closeButton.addEventListener('click', () => {
            this.hide();
        });

        return panel;
    }

    positionPanel(position) {
        if (!this.panel) return;

        // Simple positioning - place panel at a fixed position relative to container
        this.panel.style.position = 'absolute';
        this.panel.style.left = '20px';
        this.panel.style.top = '20px';
        this.panel.style.zIndex = '1000';

        console.log('Panel positioned at:', this.panel.style.left, this.panel.style.top);
    }
}

// Initialize variable relationship graph with enhanced D3.js force simulation
function initVariableGraph() {
    const container = document.getElementById('variable-graph-container');
    if (!container) return;

    const allocations = window.analysisData.memory_analysis?.allocations || [];
    const userAllocations = allocations.filter(alloc =>
        alloc.var_name && alloc.var_name !== 'unknown' &&
        alloc.type_name && alloc.type_name !== 'unknown'
    );

    if (userAllocations.length === 0) {
        container.innerHTML = `
            <div class="flex items-center justify-center h-full text-gray-500 dark:text-gray-400">
                <div class="text-center">
                    <i class="fa fa-sitemap text-4xl mb-4"></i>
                    <p class="text-lg font-semibold mb-2">No User Variables Found</p>
                    <p class="text-sm">Use track_var! macro to track variable relationships</p>
                </div>
            </div>
        `;
        return;
    }

    // Clear container
    container.innerHTML = '';

    // Set up dimensions
    const width = container.clientWidth;
    const height = container.clientHeight;

    // Create SVG
    const svg = d3.select(container)
        .append('svg')
        .attr('width', width)
        .attr('height', height)
        .style('background', 'transparent');

    // Create zoom behavior
    const zoom = d3.zoom()
        .scaleExtent([0.1, 4])
        .on('zoom', (event) => {
            g.attr('transform', event.transform);
        });

    svg.call(zoom);

    // Create main group for zooming/panning
    const g = svg.append('g');

    // Prepare nodes data
    const nodes = userAllocations.map((alloc, index) => ({
        id: alloc.var_name,
        type: alloc.type_name,
        size: alloc.size || 0,
        complexity: getComplexityFromType(alloc.type_name),
        category: getTypeCategory(alloc.type_name),
        allocation: alloc
    }));

    // Create more sophisticated relationships
    const links = [];

    // Type similarity relationships
    for (let i = 0; i < nodes.length; i++) {
        for (let j = i + 1; j < nodes.length; j++) {
            const node1 = nodes[i];
            const node2 = nodes[j];

            // Same type relationship
            if (node1.type === node2.type) {
                links.push({
                    source: node1.id,
                    target: node2.id,
                    type: 'same_type',
                    strength: 1.0
                });
            }
            // Similar category relationship
            else if (node1.category === node2.category && node1.category !== 'primitive') {
                links.push({
                    source: node1.id,
                    target: node2.id,
                    type: 'similar_category',
                    strength: 0.6
                });
            }
            // Generic type relationship (Vec<T>, Box<T>, etc.)
            else if (getGenericBase(node1.type) === getGenericBase(node2.type)) {
                links.push({
                    source: node1.id,
                    target: node2.id,
                    type: 'generic_family',
                    strength: 0.8
                });
            }
        }
    }

    // Create force simulation
    const simulation = d3.forceSimulation(nodes)
        .force('link', d3.forceLink(links)
            .id(d => d.id)
            .distance(d => 80 + (1 - d.strength) * 40)
            .strength(d => d.strength * 0.7)
        )
        .force('charge', d3.forceManyBody()
            .strength(d => -200 - (d.size / 100))
        )
        .force('center', d3.forceCenter(width / 2, height / 2))
        .force('collision', d3.forceCollide()
            .radius(d => {
                const minRadius = 15;
                const maxRadius = 50;
                const maxSize = Math.max(...nodes.map(n => n.size));
                const sizeRatio = maxSize > 0 ? d.size / maxSize : 0;
                const nodeRadius = minRadius + (sizeRatio * (maxRadius - minRadius));
                return nodeRadius + 5;
            })
        );

    // Create link elements
    const link = g.append('g')
        .attr('class', 'links')
        .selectAll('line')
        .data(links)
        .enter().append('line')
        .attr('stroke', d => getLinkColor(d.type))
        .attr('stroke-opacity', d => 0.3 + d.strength * 0.4)
        .attr('stroke-width', d => 1 + d.strength * 2)
        .attr('stroke-dasharray', d => d.type === 'similar_category' ? '5,5' : null);

    // Create node groups
    const node = g.append('g')
        .attr('class', 'nodes')
        .selectAll('g')
        .data(nodes)
        .enter().append('g')
        .attr('class', 'graph-node')
        .style('cursor', 'pointer')
        .call(d3.drag()
            .on('start', dragstarted)
            .on('drag', dragged)
            .on('end', dragended)
        );

    // Add circles to nodes - size based on memory usage
    node.append('circle')
        .attr('r', d => {
            // Scale node size based on memory usage (larger memory = larger node)
            const minRadius = 15;
            const maxRadius = 50;
            const maxSize = Math.max(...nodes.map(n => n.size));
            const sizeRatio = maxSize > 0 ? d.size / maxSize : 0;
            return minRadius + (sizeRatio * (maxRadius - minRadius));
        })
        .attr('fill', d => getEnhancedTypeColor(d.type, d.category))
        .attr('stroke', '#fff')
        .attr('stroke-width', 2)
        .style('filter', 'drop-shadow(0px 2px 4px rgba(0,0,0,0.2))')
        .on('mouseover', function (event, d) {
            const currentRadius = d3.select(this).attr('r');
            d3.select(this)
                .transition()
                .duration(200)
                .attr('r', parseFloat(currentRadius) * 1.2)
                .style('filter', 'drop-shadow(0px 4px 8px rgba(0,0,0,0.3))');

            // Highlight connected links
            link.style('stroke-opacity', l =>
                (l.source.id === d.id || l.target.id === d.id) ? 0.8 : 0.1
            );
        })
        .on('mouseout', function (event, d) {
            const minRadius = 15;
            const maxRadius = 50;
            const maxSize = Math.max(...nodes.map(n => n.size));
            const sizeRatio = maxSize > 0 ? d.size / maxSize : 0;
            const originalRadius = minRadius + (sizeRatio * (maxRadius - minRadius));
            
            d3.select(this)
                .transition()
                .duration(200)
                .attr('r', originalRadius)
                .style('filter', 'drop-shadow(0px 2px 4px rgba(0,0,0,0.2))');

            // Reset link opacity
            link.style('stroke-opacity', l => 0.3 + l.strength * 0.4);
        });

    // Add complexity indicators (small circles with numbers)
    const complexityGroup = node.append('g')
        .attr('class', 'complexity-indicator');

    complexityGroup.append('circle')
        .attr('r', 8)
        .attr('cx', d => {
            const minRadius = 15;
            const maxRadius = 50;
            const maxSize = Math.max(...nodes.map(n => n.size));
            const sizeRatio = maxSize > 0 ? d.size / maxSize : 0;
            const nodeRadius = minRadius + (sizeRatio * (maxRadius - minRadius));
            return nodeRadius + 8;
        })
        .attr('cy', d => {
            const minRadius = 15;
            const maxRadius = 50;
            const maxSize = Math.max(...nodes.map(n => n.size));
            const sizeRatio = maxSize > 0 ? d.size / maxSize : 0;
            const nodeRadius = minRadius + (sizeRatio * (maxRadius - minRadius));
            return -nodeRadius - 8;
        })
        .attr('fill', d => getComplexityColor(d.complexity))
        .attr('stroke', '#fff')
        .attr('stroke-width', 2);

    // Add complexity score text
    complexityGroup.append('text')
        .text(d => d.complexity || 2)
        .attr('x', d => {
            const minRadius = 15;
            const maxRadius = 50;
            const maxSize = Math.max(...nodes.map(n => n.size));
            const sizeRatio = maxSize > 0 ? d.size / maxSize : 0;
            const nodeRadius = minRadius + (sizeRatio * (maxRadius - minRadius));
            return nodeRadius + 8;
        })
        .attr('y', d => {
            const minRadius = 15;
            const maxRadius = 50;
            const maxSize = Math.max(...nodes.map(n => n.size));
            const sizeRatio = maxSize > 0 ? d.size / maxSize : 0;
            const nodeRadius = minRadius + (sizeRatio * (maxRadius - minRadius));
            return -nodeRadius - 8 + 3;
        })
        .attr('text-anchor', 'middle')
        .style('font-size', '10px')
        .style('font-weight', 'bold')
        .style('fill', '#fff')
        .style('pointer-events', 'none');

    // Add variable names
    node.append('text')
        .text(d => d.id)
        .attr('text-anchor', 'middle')
        .attr('dy', d => {
            const minRadius = 15;
            const maxRadius = 50;
            const maxSize = Math.max(...nodes.map(n => n.size));
            const sizeRatio = maxSize > 0 ? d.size / maxSize : 0;
            const nodeRadius = minRadius + (sizeRatio * (maxRadius - minRadius));
            return nodeRadius + 15;
        })
        .style('font-size', '11px')
        .style('font-weight', 'bold')
        .style('fill', 'var(--text-primary)')
        .style('pointer-events', 'none');

    // Add type labels
    node.append('text')
        .text(d => formatTypeName(d.type))
        .attr('text-anchor', 'middle')
        .attr('dy', d => {
            const minRadius = 15;
            const maxRadius = 50;
            const maxSize = Math.max(...nodes.map(n => n.size));
            const sizeRatio = maxSize > 0 ? d.size / maxSize : 0;
            const nodeRadius = minRadius + (sizeRatio * (maxRadius - minRadius));
            return nodeRadius + 28;
        })
        .style('font-size', '9px')
        .style('fill', 'var(--text-secondary)')
        .style('pointer-events', 'none');

    // Add click interaction
    const detailPanel = new NodeDetailPanel('variable-graph-container');

    node.on('click', function (event, d) {
        event.stopPropagation();
        console.log('Node clicked:', d.id, d);
        const position = {
            x: event.pageX,
            y: event.pageY
        };
        detailPanel.show(d, position);
    });

    // Click on empty space to hide panel
    svg.on('click', function (event) {
        if (event.target === this) {
            detailPanel.hide();
        }
    });

    // Update positions on simulation tick
    simulation.on('tick', () => {
        link
            .attr('x1', d => d.source.x)
            .attr('y1', d => d.source.y)
            .attr('x2', d => d.target.x)
            .attr('y2', d => d.target.y);

        node
            .attr('transform', d => `translate(${d.x},${d.y})`);
    });

    // Add control buttons
    const controls = d3.select(container)
        .append('div')
        .attr('class', 'absolute top-2 right-2 flex space-x-2');

    controls.append('button')
        .attr('class', 'px-3 py-1 bg-blue-500 hover:bg-blue-600 text-white text-xs rounded transition-colors')
        .text('Reset View')
        .on('click', () => {
            svg.transition().duration(750).call(
                zoom.transform,
                d3.zoomIdentity
            );
        });

    controls.append('button')
        .attr('class', 'px-3 py-1 bg-green-500 hover:bg-green-600 text-white text-xs rounded transition-colors')
        .text('Reheat')
        .on('click', () => {
            simulation.alpha(0.3).restart();
        });

    // Drag functions
    function dragstarted(event, d) {
        if (!event.active) simulation.alphaTarget(0.3).restart();
        d.fx = d.x;
        d.fy = d.y;
    }

    function dragged(event, d) {
        d.fx = event.x;
        d.fy = event.y;
    }

    function dragended(event, d) {
        if (!event.active) simulation.alphaTarget(0);
        d.fx = null;
        d.fy = null;
    }
}

// Get color for variable type
function getTypeColor(typeName) {
    if (typeName.includes('Vec')) return '#3b82f6';
    if (typeName.includes('Box')) return '#8b5cf6';
    if (typeName.includes('Rc') || typeName.includes('Arc')) return '#10b981';
    if (typeName.includes('String')) return '#f59e0b';
    return '#6b7280';
}

// Enhanced type color with comprehensive type mapping
function getEnhancedTypeColor(typeName, category) {
    // Comprehensive color mapping for specific types
    const typeColorMap = {
        // Smart Pointers - Purple/Violet family
        'Box': '#8b5cf6',           // Purple
        'Rc': '#a855f7',            // Purple-500
        'Arc': '#9333ea',           // Violet-600
        'RefCell': '#7c3aed',       // Violet-700
        'Cell': '#6d28d9',          // Violet-800
        'Weak': '#5b21b6',          // Violet-900

        // Collections - Blue family
        'Vec': '#3b82f6',           // Blue-500
        'VecDeque': '#2563eb',      // Blue-600
        'LinkedList': '#1d4ed8',    // Blue-700
        'HashMap': '#1e40af',       // Blue-800
        'BTreeMap': '#1e3a8a',      // Blue-900
        'HashSet': '#60a5fa',       // Blue-400
        'BTreeSet': '#93c5fd',      // Blue-300

        // String types - Orange/Amber family
        'String': '#f59e0b',        // Amber-500
        'str': '#d97706',           // Amber-600
        'OsString': '#b45309',      // Amber-700
        'OsStr': '#92400e',         // Amber-800
        'CString': '#78350f',       // Amber-900
        'CStr': '#fbbf24',          // Amber-400

        // Numeric types - Green family
        'i8': '#10b981',            // Emerald-500
        'i16': '#059669',           // Emerald-600
        'i32': '#047857',           // Emerald-700
        'i64': '#065f46',           // Emerald-800
        'i128': '#064e3b',          // Emerald-900
        'u8': '#34d399',            // Emerald-400
        'u16': '#6ee7b7',           // Emerald-300
        'u32': '#a7f3d0',           // Emerald-200
        'u64': '#d1fae5',           // Emerald-100
        'u128': '#ecfdf5',          // Emerald-50
        'f32': '#14b8a6',           // Teal-500
        'f64': '#0d9488',           // Teal-600
        'usize': '#0f766e',         // Teal-700
        'isize': '#115e59',         // Teal-800

        // Boolean and char - Pink family
        'bool': '#ec4899',          // Pink-500
        'char': '#db2777',          // Pink-600

        // Option and Result - Indigo family
        'Option': '#6366f1',        // Indigo-500
        'Result': '#4f46e5',        // Indigo-600
        'Some': '#4338ca',          // Indigo-700
        'None': '#3730a3',          // Indigo-800
        'Ok': '#312e81',            // Indigo-900
        'Err': '#6366f1',           // Indigo-500

        // Synchronization types - Red family
        'Mutex': '#ef4444',         // Red-500
        'RwLock': '#dc2626',        // Red-600
        'Condvar': '#b91c1c',       // Red-700
        'Barrier': '#991b1b',       // Red-800
        'Once': '#7f1d1d',          // Red-900

        // Channel types - Cyan family
        'Sender': '#06b6d4',        // Cyan-500
        'Receiver': '#0891b2',      // Cyan-600
        'mpsc': '#0e7490',          // Cyan-700

        // Path types - Lime family
        'Path': '#84cc16',          // Lime-500
        'PathBuf': '#65a30d',       // Lime-600

        // Time types - Yellow family
        'Duration': '#eab308',      // Yellow-500
        'Instant': '#ca8a04',       // Yellow-600
        'SystemTime': '#a16207',    // Yellow-700

        // IO types - Stone family
        'File': '#78716c',          // Stone-500
        'BufReader': '#57534e',     // Stone-600
        'BufWriter': '#44403c',     // Stone-700

        // Thread types - Rose family
        'Thread': '#f43f5e',        // Rose-500
        'JoinHandle': '#e11d48',    // Rose-600

        // Custom/Unknown types - Gray family
        'unknown': '#6b7280',       // Gray-500
        'custom': '#4b5563',        // Gray-600
    };

    // First, try exact type name match
    if (typeColorMap[typeName]) {
        return typeColorMap[typeName];
    }

    // Then try to match by type name contains
    for (const [type, color] of Object.entries(typeColorMap)) {
        if (typeName.includes(type)) {
            return color;
        }
    }

    // Extract generic base type and try to match
    const genericBase = getGenericBase(typeName);
    if (typeColorMap[genericBase]) {
        return typeColorMap[genericBase];
    }

    // Fall back to category-based colors
    switch (category) {
        case 'smart_pointer': return '#8b5cf6';  // Purple
        case 'collection': return '#3b82f6';     // Blue
        case 'string': return '#f59e0b';         // Amber
        case 'numeric': return '#10b981';        // Emerald
        case 'sync': return '#ef4444';           // Red
        case 'channel': return '#06b6d4';        // Cyan
        case 'path': return '#84cc16';           // Lime
        case 'time': return '#eab308';           // Yellow
        case 'io': return '#78716c';             // Stone
        case 'thread': return '#f43f5e';         // Rose
        default: return '#6b7280';               // Gray
    }
}

// Get type category for grouping with comprehensive type recognition
function getTypeCategory(typeName) {
    // Smart pointers
    if (typeName.includes('Box') || typeName.includes('Rc') || typeName.includes('Arc') ||
        typeName.includes('RefCell') || typeName.includes('Cell') || typeName.includes('Weak')) {
        return 'smart_pointer';
    }

    // Collections
    if (typeName.includes('Vec') || typeName.includes('HashMap') || typeName.includes('BTreeMap') ||
        typeName.includes('HashSet') || typeName.includes('BTreeSet') || typeName.includes('VecDeque') ||
        typeName.includes('LinkedList')) {
        return 'collection';
    }

    // String types
    if (typeName.includes('String') || typeName.includes('str') || typeName.includes('OsString') ||
        typeName.includes('OsStr') || typeName.includes('CString') || typeName.includes('CStr')) {
        return 'string';
    }

    // Numeric types
    if (typeName.match(/^[iuf]\d+$/) || typeName === 'usize' || typeName === 'isize' ||
        typeName === 'bool' || typeName === 'char') {
        return 'numeric';
    }

    // Synchronization types
    if (typeName.includes('Mutex') || typeName.includes('RwLock') || typeName.includes('Condvar') ||
        typeName.includes('Barrier') || typeName.includes('Once')) {
        return 'sync';
    }

    // Channel types
    if (typeName.includes('Sender') || typeName.includes('Receiver') || typeName.includes('mpsc')) {
        return 'channel';
    }

    // Path types
    if (typeName.includes('Path') || typeName.includes('PathBuf')) {
        return 'path';
    }

    // Time types
    if (typeName.includes('Duration') || typeName.includes('Instant') || typeName.includes('SystemTime')) {
        return 'time';
    }

    // IO types
    if (typeName.includes('File') || typeName.includes('BufReader') || typeName.includes('BufWriter')) {
        return 'io';
    }

    // Thread types
    if (typeName.includes('Thread') || typeName.includes('JoinHandle')) {
        return 'thread';
    }

    // Option and Result
    if (typeName.includes('Option') || typeName.includes('Result')) {
        return 'option_result';
    }

    return 'primitive';
}

// Get generic base type (Vec<T> -> Vec, Box<T> -> Box)
function getGenericBase(typeName) {
    const match = typeName.match(/^([^<]+)/);
    return match ? match[1] : typeName;
}

// Get complexity score from type with comprehensive scoring
function getComplexityFromType(typeName) {
    // Very high complexity (9-10)
    if (typeName.includes('HashMap') || typeName.includes('BTreeMap') ||
        typeName.includes('BTreeSet') || typeName.includes('LinkedList')) return 9;

    // High complexity (7-8)
    if (typeName.includes('Arc') || typeName.includes('Mutex') || typeName.includes('RwLock') ||
        typeName.includes('Condvar') || typeName.includes('Barrier')) return 8;
    if (typeName.includes('Rc') || typeName.includes('RefCell') || typeName.includes('HashSet') ||
        typeName.includes('VecDeque')) return 7;

    // Medium complexity (5-6)
    if (typeName.includes('Vec') || typeName.includes('Box') || typeName.includes('Option') ||
        typeName.includes('Result')) return 6;
    if (typeName.includes('String') || typeName.includes('PathBuf') || typeName.includes('OsString') ||
        typeName.includes('CString')) return 5;

    // Low complexity (3-4)
    if (typeName.includes('str') || typeName.includes('Path') || typeName.includes('OsStr') ||
        typeName.includes('CStr') || typeName.includes('Duration') || typeName.includes('Instant')) return 4;
    if (typeName.includes('Sender') || typeName.includes('Receiver') || typeName.includes('File') ||
        typeName.includes('Thread') || typeName.includes('JoinHandle')) return 3;

    // Very low complexity (1-2)
    if (typeName.match(/^[iuf]\d+$/) || typeName === 'usize' || typeName === 'isize' ||
        typeName === 'bool' || typeName === 'char') return 1;

    // Default for unknown types
    return 2;
}

// Get link color based on relationship type
function getLinkColor(linkType) {
    switch (linkType) {
        case 'same_type': return '#ef4444';
        case 'similar_category': return '#3b82f6';
        case 'generic_family': return '#10b981';
        default: return '#6b7280';
    }
}

// Get complexity level description
function getComplexityLevel(score) {
    if (score <= 2) return 'Simple';
    if (score <= 5) return 'Medium';
    if (score <= 8) return 'Complex';
    return 'Very Complex';
}

// Get complexity explanation
function getComplexityExplanation(score) {
    if (score <= 2) return 'Basic types with minimal performance overhead and simple memory usage';
    if (score <= 5) return 'Medium complexity with some memory management overhead';
    if (score <= 8) return 'Complex types involving heap allocation and smart pointers, performance considerations needed';
    return 'Very complex types with significant performance overhead, optimization recommended';
}

// Get type analysis information
function getTypeAnalysis(typeName, size) {
    const analysis = [];

    if (typeName.includes('Vec')) {
        analysis.push('โ€ข Dynamic array with heap allocation');
        analysis.push('โ€ข Grows automatically as needed');
        if (size > 1000) analysis.push('โ€ข Large allocation - consider capacity optimization');
    } else if (typeName.includes('Box')) {
        analysis.push('โ€ข Single heap allocation');
        analysis.push('โ€ข Unique ownership semantics');
    } else if (typeName.includes('Rc')) {
        analysis.push('โ€ข Reference counted smart pointer');
        analysis.push('โ€ข Shared ownership with runtime checks');
    } else if (typeName.includes('Arc')) {
        analysis.push('โ€ข Atomic reference counted pointer');
        analysis.push('โ€ข Thread-safe shared ownership');
    } else if (typeName.includes('String')) {
        analysis.push('โ€ข Growable UTF-8 string');
        analysis.push('โ€ข Heap allocated with capacity buffer');
    } else {
        analysis.push('โ€ข Basic type allocation');
    }

    if (size === 0) {
        analysis.push('โ€ข Zero-sized type (ZST)');
    } else if (size < 64) {
        analysis.push('โ€ข Small allocation - good for performance');
    } else if (size > 1024) {
        analysis.push('โ€ข Large allocation - monitor memory usage');
    }

    return analysis.join('<br>');
}

// Initialize generic types table
function initGenericTypesTable() {
    const tbody = document.getElementById('generic-types-table-body');
    if (!tbody) return;

    const genericTypes = window.analysisData.complex_types?.categorized_types?.generic_types || [];

    if (genericTypes.length === 0) {
        tbody.innerHTML = '<tr><td colspan="6" class="px-6 py-8 text-center text-gray-500 dark:text-gray-400">No generic types found</td></tr>';
        return;
    }

    tbody.innerHTML = genericTypes.map(type => `
        <tr class="hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
            <td class="px-6 py-4 text-gray-900 dark:text-gray-100">${type.var_name || 'System Allocation'}</td>
            <td class="px-6 py-4 text-gray-900 dark:text-gray-100">${formatTypeName(type.type_name || 'System Allocation')}</td>
            <td class="px-6 py-4 font-mono text-xs text-gray-900 dark:text-gray-100">${type.ptr}</td>
            <td class="px-6 py-4 text-gray-900 dark:text-gray-100">${formatBytes(type.size || 0)}</td>
            <td class="px-6 py-4 text-gray-900 dark:text-gray-100">N/A</td>
            <td class="px-6 py-4">
                <span class="px-2 py-1 rounded text-xs ${getComplexityColor(type.complexity_score)} text-white">
                    ${type.complexity_score || 0}
                </span>
            </td>
        </tr>
    `).join('');
}

// Initialize complex type analysis
function initComplexTypeAnalysis() {
    const tbody = document.getElementById('complex-type-analysis-table');
    if (!tbody) return;

    const complexTypeAnalysis = window.analysisData.complex_types?.complex_type_analysis || [];

    if (complexTypeAnalysis.length === 0) {
        tbody.innerHTML = '<tr><td colspan="6" class="px-6 py-8 text-center text-gray-500 dark:text-gray-400">No complex type analysis available</td></tr>';
        return;
    }

    tbody.innerHTML = complexTypeAnalysis.map(analysis => `
        <tr class="hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
            <td class="px-6 py-4 text-gray-900 dark:text-gray-100">${formatTypeName(analysis.type_name)}</td>
            <td class="px-6 py-4 text-center">
                <span class="px-2 py-1 rounded text-xs ${getComplexityColor(analysis.complexity_score)} text-white">
                    ${analysis.complexity_score}
                </span>
            </td>
            <td class="px-6 py-4 text-center">
                <span class="px-2 py-1 rounded text-xs ${getEfficiencyColor(analysis.memory_efficiency)} text-white">
                    ${analysis.memory_efficiency}%
                </span>
            </td>
            <td class="px-6 py-4 text-center text-gray-900 dark:text-gray-100">${analysis.allocation_count || 0}</td>
            <td class="px-6 py-4 text-center text-gray-900 dark:text-gray-100">${formatBytes(analysis.total_size || 0)}</td>
            <td class="px-6 py-4 text-gray-700 dark:text-gray-300">
                ${Array.isArray(analysis.optimization_suggestions) && analysis.optimization_suggestions.length > 0 
                    ? analysis.optimization_suggestions.join(', ') 
                    : '<span class="text-gray-400 italic">No optimization suggestions available</span>'}
            </td>
        </tr>
    `).join('');
}

// Initialize memory optimization recommendations
function initMemoryOptimizationRecommendations() {
    const container = document.getElementById('memory-optimization-recommendations');
    if (!container) return;

    const recommendations = window.analysisData.complex_types?.optimization_recommendations || [];

    if (recommendations.length === 0) {
        container.innerHTML = '<li class="text-gray-500 dark:text-gray-400">No specific recommendations available</li>';
        return;
    }

    container.innerHTML = recommendations.map(rec => `
        <li class="flex items-start">
            <i class="fa fa-lightbulb-o text-yellow-500 mr-2 mt-1"></i>
            <span class="dark:text-gray-200">${rec}</span>
        </li>
    `).join('');
}

// Initialize FFI risk chart
function initFFIRiskChart() {
    // Guard: ensure canvas isn't holding an existing chart instance
    try {
        if (window.chartInstances && window.chartInstances['ffi-risk-chart']) {
            window.chartInstances['ffi-risk-chart'].destroy();
            delete window.chartInstances['ffi-risk-chart'];
        }
    } catch (_) {}

    const ctx = document.getElementById('ffi-risk-chart');
    if (!ctx) return;

    const ffiData = window.analysisData.unsafe_ffi?.enhanced_ffi_data || [];

    const riskLevels = {
        'Low Risk': ffiData.filter(item => (item.safety_violations || 0) === 0).length,
        'Medium Risk': ffiData.filter(item => (item.safety_violations || 0) > 0 && (item.safety_violations || 0) <= 2).length,
        'High Risk': ffiData.filter(item => (item.safety_violations || 0) > 2).length
    };

    const isDark = document.documentElement.classList.contains('dark');

    // Destroy existing chart if it exists
    if (window.chartInstances['ffi-risk-chart']) {
        window.chartInstances['ffi-risk-chart'].destroy();
    }

    window.chartInstances['ffi-risk-chart'] = new Chart(ctx, {
        type: 'doughnut',
        data: {
            labels: Object.keys(riskLevels),
            datasets: [{
                data: Object.values(riskLevels),
                backgroundColor: ['#10b981', '#f59e0b', '#ef4444'],
                borderColor: isDark ? '#374151' : '#ffffff',
                borderWidth: 2
            }]
        },
        options: {
            responsive: true,
            maintainAspectRatio: false,
            plugins: {
                legend: {
                    labels: {
                        color: isDark ? '#f9fafb' : '#374151',
                        font: {
                            size: 12
                        }
                    }
                },
                tooltip: {
                    backgroundColor: isDark ? '#1f2937' : '#ffffff',
                    titleColor: isDark ? '#f9fafb' : '#374151',
                    bodyColor: isDark ? '#f9fafb' : '#374151',
                    borderColor: isDark ? '#374151' : '#e5e7eb',
                    borderWidth: 1
                }
            }
        }
    });
}

// Initialize complex type analysis chart
function initComplexTypeAnalysisChart() {
    const ctx = document.getElementById('complex-type-analysis-chart');
    if (!ctx) return;

    const complexTypeAnalysis = window.analysisData.complex_types?.complex_type_analysis || [];

    if (complexTypeAnalysis.length === 0) {
        // Show empty state
        const container = ctx.parentElement;
        container.innerHTML = `
            <div class="h-64 flex items-center justify-center text-gray-500 dark:text-gray-400">
                <div class="text-center">
                    <i class="fa fa-chart-bar text-4xl mb-4"></i>
                    <p class="text-lg font-semibold mb-2">No Complex Type Data</p>
                    <p class="text-sm">No complex type analysis data available</p>
                </div>
            </div>
        `;
        return;
    }

    const isDark = document.documentElement.classList.contains('dark');

    // Destroy existing chart if it exists
    if (window.chartInstances['complex-type-analysis-chart']) {
        window.chartInstances['complex-type-analysis-chart'].destroy();
    }

    window.chartInstances['complex-type-analysis-chart'] = new Chart(ctx, {
        type: 'scatter',
        data: {
            datasets: [{
                label: 'Type Complexity vs Memory Efficiency',
                data: complexTypeAnalysis.map(analysis => ({
                    x: analysis.complexity_score || 0,
                    y: analysis.memory_efficiency || 0,
                    typeName: analysis.type_name
                })),
                backgroundColor: 'rgba(59, 130, 246, 0.6)',
                borderColor: 'rgba(59, 130, 246, 1)',
                borderWidth: 2,
                pointRadius: 6,
                pointHoverRadius: 8
            }]
        },
        options: {
            responsive: true,
            maintainAspectRatio: false,
            scales: {
                x: {
                    title: {
                        display: true,
                        text: 'Complexity Score',
                        color: isDark ? '#f9fafb' : '#374151'
                    },
                    ticks: {
                        color: isDark ? '#d1d5db' : '#6b7280'
                    },
                    grid: {
                        color: isDark ? '#374151' : '#e5e7eb'
                    }
                },
                y: {
                    title: {
                        display: true,
                        text: 'Memory Efficiency (%)',
                        color: isDark ? '#f9fafb' : '#374151'
                    },
                    ticks: {
                        color: isDark ? '#d1d5db' : '#6b7280'
                    },
                    grid: {
                        color: isDark ? '#374151' : '#e5e7eb'
                    }
                }
            },
            plugins: {
                legend: {
                    labels: {
                        color: isDark ? '#f9fafb' : '#374151'
                    }
                },
                tooltip: {
                    backgroundColor: isDark ? '#1f2937' : '#ffffff',
                    titleColor: isDark ? '#f9fafb' : '#374151',
                    bodyColor: isDark ? '#f9fafb' : '#374151',
                    borderColor: isDark ? '#374151' : '#e5e7eb',
                    borderWidth: 1,
                    callbacks: {
                        title: function (context) {
                            return context[0].raw.typeName || 'Unknown Type';
                        },
                        label: function (context) {
                            return [
                                `Complexity: ${context.parsed.x}`,
                                `Efficiency: ${context.parsed.y}%`
                            ];
                        }
                    }
                }
            }
        }
    });
}

// Format type name for better display
function formatTypeName(typeName) {
    if (!typeName || typeName === 'unknown') return 'System Allocation';
    // Simplify complex type names
    return typeName
        .replace(/alloc::/g, '')
        .replace(/std::/g, '')
        .replace(/::Vec/g, 'Vec')
        .replace(/::Box/g, 'Box')
        .replace(/::Rc/g, 'Rc')
        .replace(/::Arc/g, 'Arc')
        .replace(/::String/g, 'String');
}

// Format timestamp relative to start time
function formatTimestamp(timestamp, minTime) {
    const relativeMs = Math.round((timestamp - minTime) / 1000000); // Convert nanoseconds to milliseconds
    return `${relativeMs}ms`;
}

// Enhanced summary statistics with comprehensive data analysis
function initEnhancedSummaryStats() {
    console.log('๐Ÿ“Š Initializing enhanced summary statistics...');
    
    try {
        // Get merged data from all sources
        const memoryAllocations = window.analysisData.memory_analysis?.allocations || [];
        const complexAllocations = window.analysisData.complex_types?.allocations || [];
        const unsafeAllocations = window.analysisData.unsafe_ffi?.allocations || [];
        
        // Merge all data sources for comprehensive analysis
        const allData = mergeAllDataSources(memoryAllocations, complexAllocations, unsafeAllocations);
        
        // Calculate comprehensive statistics
        const stats = calculateComprehensiveStats(allData);
        
        // Update enhanced dashboard
        updateElement('total-allocations', stats.totalAllocations);
        updateElement('allocation-rate', `${stats.allocationRate.toFixed(1)}/ms`);
        updateElement('active-variables', stats.activeVariables);
        updateElement('variable-types', `${stats.uniqueTypes} types`);
        updateElement('borrow-operations', stats.totalBorrows);
        updateElement('max-concurrent', `Max: ${stats.maxConcurrent}`);
        updateElement('safety-score', `${stats.safetyScore}%`);
        updateElement('ffi-tracked', `${stats.ffiTracked} FFI`);
        
        console.log('โœ… Enhanced dashboard updated successfully');
    } catch (error) {
        console.error('โŒ Error initializing enhanced stats:', error);
    }
}

// Merge data from all sources with comprehensive field mapping
function mergeAllDataSources(memory, complex, unsafe) {
    const dataMap = new Map();
    
    // Add memory analysis data (has lifetime_ms)
    memory.forEach(alloc => {
        if (alloc.ptr) {
            dataMap.set(alloc.ptr, { ...alloc, source: 'memory' });
        }
    });
    
    // Merge complex types data (has extended fields)
    complex.forEach(alloc => {
        if (alloc.ptr) {
            const existing = dataMap.get(alloc.ptr) || {};
            dataMap.set(alloc.ptr, { 
                ...existing, 
                ...alloc, 
                source: existing.source ? `${existing.source}+complex` : 'complex'
            });
        }
    });
    
    // Merge unsafe FFI data (has safety info)
    unsafe.forEach(alloc => {
        if (alloc.ptr) {
            const existing = dataMap.get(alloc.ptr) || {};
            dataMap.set(alloc.ptr, { 
                ...existing, 
                ...alloc, 
                source: existing.source ? `${existing.source}+unsafe` : 'unsafe'
            });
        }
    });
    
    return Array.from(dataMap.values());
}

// Calculate comprehensive statistics from merged data
function calculateComprehensiveStats(allData) {
    const validData = allData.filter(d => d.var_name && d.var_name !== 'unknown');
    
    // Basic counts
    const totalAllocations = validData.length;
    const uniqueVars = new Set(validData.map(d => d.var_name)).size;
    const uniqueTypes = new Set(validData.map(d => d.type_name)).size;
    
    // Time-based calculations
    const timestamps = validData.map(d => d.timestamp_alloc).filter(t => t);
    const timeRange = timestamps.length > 0 ? (Math.max(...timestamps) - Math.min(...timestamps)) / 1000000 : 1;
    const allocationRate = totalAllocations / Math.max(timeRange, 1);
    
    // Borrow analysis
    let totalBorrows = 0;
    let maxConcurrent = 0;
    validData.forEach(d => {
        if (d.borrow_info) {
            totalBorrows += (d.borrow_info.immutable_borrows || 0) + (d.borrow_info.mutable_borrows || 0);
            maxConcurrent = Math.max(maxConcurrent, d.borrow_info.max_concurrent_borrows || 0);
        }
    });
    
    // Safety analysis
    const ffiTracked = validData.filter(d => d.ffi_tracked).length;
    const leaked = validData.filter(d => d.is_leaked).length;
    const withSafetyViolations = validData.filter(d => d.safety_violations && d.safety_violations.length > 0).length;
    const safetyScore = Math.max(0, 100 - (leaked * 20) - (withSafetyViolations * 10));
    
    return {
        totalAllocations,
        activeVariables: uniqueVars,
        uniqueTypes,
        allocationRate,
        totalBorrows,
        maxConcurrent,
        ffiTracked,
        safetyScore: Math.round(safetyScore)
    };
}

// Helper function to safely update DOM elements
function updateElement(id, value) {
    const element = document.getElementById(id);
    if (element) {
        element.textContent = value;
    }
}

// Utility function to format bytes
function formatBytes(bytes) {
    if (bytes === 0) return '0 B';
    const k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}

// Show empty state when no user variables found
function showEmptyLifetimeState() {
    const container = document.getElementById('lifetimeVisualization');
    if (!container) return;

    container.innerHTML = `
        <div class="text-center py-8 text-gray-500 dark:text-gray-400">
            <i class="fa fa-info-circle text-2xl mb-2"></i>
            <p>No user-defined variables found in lifetime data</p>
            <p class="text-sm mt-1">Use track_var! macro to track variable lifetimes</p>
        </div>
    `;
}

// Utility functions
function updateElement(id, value) {
    const element = document.getElementById(id);
    if (element) {
        element.textContent = value;
    }
}

function getComplexityColor(score) {
    if (score <= 2) return '#10b981';  // Green - Low complexity
    if (score <= 5) return '#eab308';  // Yellow - Medium complexity  
    if (score <= 8) return '#f97316';  // Orange - High complexity
    return '#ef4444';                  // Red - Very high complexity
}

function getEfficiencyColor(efficiency) {
    if (efficiency >= 80) return 'bg-green-500';
    if (efficiency >= 60) return 'bg-yellow-500';
    if (efficiency >= 40) return 'bg-orange-500';
    return 'bg-red-500';
}

// Update KPI Cards
function updateKPICards(data) {
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    const total = allocs.reduce((s,a)=>s+(a.size||0),0);
    const active = allocs.filter(a=>!a.timestamp_dealloc).length;
    const safetyScore = calculateSafetyScore(allocs);
    
    updateElement('total-allocations', allocs.length.toLocaleString());
    updateElement('active-variables', active.toLocaleString());
    updateElement('total-memory', formatBytes(total));
    updateElement('safety-score', safetyScore + '%');
}

// Calculate Safety Score
function calculateSafetyScore(allocs) {
    if (!allocs.length) return 100;
    const leaked = allocs.filter(a => a.is_leaked).length;
    const violations = allocs.filter(a => a.safety_violations && a.safety_violations.length > 0).length;
    return Math.max(0, 100 - (leaked * 20) - (violations * 10));
}

// Theme Toggle Functionality
function initThemeToggle() {
    const toggleBtn = document.getElementById('theme-toggle');
    if (!toggleBtn) return;
    
    // Check local storage for theme
    const savedTheme = localStorage.getItem('memscope-theme') || 'light';
    applyTheme(savedTheme === 'dark');
    
    toggleBtn.addEventListener('click', () => {
        const isDark = document.documentElement.classList.contains('dark');
        const newTheme = isDark ? 'light' : 'dark';
        
        applyTheme(newTheme === 'dark');
        localStorage.setItem('memscope-theme', newTheme);
        
        // Update button text
        const icon = toggleBtn.querySelector('i');
        const text = toggleBtn.querySelector('span');
        if (newTheme === 'dark') {
            icon.className = 'fa fa-sun';
            text.textContent = 'Light Mode';
        } else {
            icon.className = 'fa fa-moon';
            text.textContent = 'Dark Mode';
        }
        
        console.log('๐ŸŽจ Theme switched to:', newTheme);
    });
}

// ๅบ”็”จไธป้ข˜
function applyTheme(isDark) {
    const html = document.documentElement;
    if (isDark) {
        html.classList.add('dark');
    } else {
        html.classList.remove('dark');
    }
}

// Update Memory Allocation Table
function updateAllocationsTable(data) {
    const allocTable = document.getElementById('allocTable');
    if (!allocTable) return;
    
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    const top = allocs.slice().sort((a,b)=>(b.size||0)-(a.size||0)).slice(0,50);
    
    allocTable.innerHTML = top.map(a => {
        const status = a.is_leaked ? 'Leaked' : (a.timestamp_dealloc ? 'Freed' : 'Active');
        const statusClass = a.is_leaked ? 'status-leaked' : (a.timestamp_dealloc ? 'status-freed' : 'status-active');
        
        return `<tr>
            <td>${a.var_name || 'Unknown'}</td>
            <td>${formatTypeName(a.type_name || 'Unknown')}</td>
            <td>${formatBytes(a.size || 0)}</td>
            <td><span class="status-badge ${statusClass}">${status}</span></td>
        </tr>`;
    }).join('');
}

// Update Unsafe Risk Table
function updateUnsafeTable(data) {
    const unsafeTable = document.getElementById('unsafeTable');
    if (!unsafeTable) return;
    
    const root = data.unsafe_ffi || {};
    const ops = root.enhanced_ffi_data || root.unsafe_operations || root.allocations || [];
    
    unsafeTable.innerHTML = (ops || []).slice(0, 50).map(op => {
        const riskLevel = op.risk_level || ((op.safety_violations||[]).length > 2 ? 'High' : 
                         ((op.safety_violations||[]).length > 0 ? 'Medium' : 'Low'));
        
        const riskText = riskLevel === 'High' ? 'High Risk' : (riskLevel === 'Medium' ? 'Medium Risk' : 'Low Risk');
        const riskClass = riskLevel === 'High' ? 'risk-high' : (riskLevel === 'Medium' ? 'risk-medium' : 'risk-low');
        
        return `<tr>
            <td>${op.location || op.var_name || 'Unknown'}</td>
            <td>${op.operation_type || op.type_name || 'Unknown'}</td>
            <td><span class="status-badge ${riskClass}">${riskText}</span></td>
        </tr>`;
    }).join('');
}

// Initialize Charts
function initCharts(data) {
    console.log('๐Ÿ“Š Initializing charts...');
    
    // Memory type distribution chart
    initTypeChart(data);
    
    // Memory timeline chart
    initTimelineChart(data);
    
    // Type treemap chart
    initTreemapChart(data);
    
    // FFI risk chart
    initFFIRiskChart(data);
    
    // Memory growth trends
    initGrowthTrends(data);
    
    // Memory fragmentation
    initMemoryFragmentation(data);
    
    // Variable relationship graph
    initVariableGraph(data);
}

// Memory Type Distribution Chart
function initTypeChart(data) {
    const ctx = document.getElementById('typeChart');
    if (!ctx) return;
    
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    const byType = {};
    
    allocs.forEach(a => {
        const type = a.type_name || 'Unknown';
        byType[type] = (byType[type] || 0) + (a.size || 0);
    });
    
    const top = Object.entries(byType).sort((a,b) => b[1] - a[1]).slice(0, 8);
    
    if (top.length > 0 && window.Chart) {
        const chart = new Chart(ctx, {
            type: 'bar',
            data: {
                labels: top.map(x => {
                    const formatted = formatTypeName(x[0]);
                    return formatted.length > 15 ? formatted.substring(0, 12) + '...' : formatted;
                }),
                datasets: [{
                    label: 'Memory Usage',
                    data: top.map(x => x[1]),
                    backgroundColor: '#2563eb',
                    borderRadius: 6
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: { display: false }
                },
                scales: {
                    x: {
                        ticks: {
                            maxRotation: 45,
                            minRotation: 0,
                            font: {
                                size: 10
                            }
                        }
                    },
                    y: { 
                        beginAtZero: true,
                        ticks: {
                            callback: function(value) {
                                return formatBytes(value);
                            }
                        }
                    }
                }
            }
        });
    }
}

// Memory Timeline Chart with optional Growth Rate (dual y-axes)
function initTimelineChart(data) {
    const ctx = document.getElementById('timelineChart');
    if (!ctx || !window.Chart) return;

    // Comprehensive cleanup for timeline chart
    try {
        if (ctx.chart) {
            ctx.chart.destroy();
            delete ctx.chart;
        }
        
        if (window.Chart.instances) {
            Object.values(window.Chart.instances).forEach(instance => {
                if (instance.canvas === ctx) {
                    instance.destroy();
                }
            });
        }
        
        if (window.chartInstances && window.chartInstances['timelineChart']) {
            window.chartInstances['timelineChart'].destroy();
            delete window.chartInstances['timelineChart'];
        }
        
        const context = ctx.getContext('2d');
        context.clearRect(0, 0, ctx.width, ctx.height);
        
    } catch(e) {
        console.warn('Timeline chart cleanup warning:', e);
    }
    
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    const sorted = allocs.slice().sort((a,b) => (a.timestamp_alloc||0) - (b.timestamp_alloc||0));
    
    // Bucketize by timestamp to ~200 buckets; compute bytes/sec
    if (sorted.length === 0) return;
    const minTs = sorted[0].timestamp_alloc || 0;
    const maxTs = sorted[sorted.length-1].timestamp_alloc || minTs;
    const rangeNs = Math.max(1, maxTs - minTs);
    const bucketCount = Math.min(200, Math.max(1, Math.floor(sorted.length / 2)));
    const bucketNs = Math.max(1, Math.floor(rangeNs / bucketCount));

    const cumSeries = [];
    const rateSeries = [];

    let cumulative = 0;
    let windowQueue = [];
    const windowBuckets = 3; // simple smoothing window

    for (let b = 0; b <= bucketCount; b++) {
        const start = minTs + b * bucketNs;
        const end = Math.min(maxTs, start + bucketNs);
        const slice = sorted.filter(a => (a.timestamp_alloc||0) >= start && (a.timestamp_alloc||0) < end);
        const sum = slice.reduce((s,a)=>s+(a.size||0),0);
        cumulative += sum;
        cumSeries.push({ x: start, y: cumulative });
        const dtSec = Math.max(1e-9, (end - start) / 1e9);
        const rate = sum / dtSec; // bytes/sec in this bucket
        windowQueue.push(rate);
        if (windowQueue.length > windowBuckets) windowQueue.shift();
        const smoothed = windowQueue.reduce((s,v)=>s+v,0) / windowQueue.length;
        rateSeries.push({ x: start, y: smoothed });
    }

    if (cumSeries.length > 1 && window.Chart) {
        // destroy previous chart if exists
        if (window.chartInstances && window.chartInstances['timelineChart']) {
            try { window.chartInstances['timelineChart'].destroy(); } catch(_) {}
            delete window.chartInstances['timelineChart'];
        }

        const labels = cumSeries.map(p=> new Date(p.x/1e6).toLocaleTimeString());
        const showGrowthCheckbox = document.getElementById('toggleGrowthRate');
        const datasets = [
            {
                type: 'line',
                label: 'Cumulative Memory',
                data: cumSeries.map(p=>p.y),
                borderColor: '#059669',
                backgroundColor: 'rgba(5, 150, 105, 0.1)',
                fill: true,
                tension: 0.3,
                yAxisID: 'y'
            }
        ];

        // add growth rate dataset (hidden by default; user toggles it)
        datasets.push({
            type: 'line',
            label: 'Growth Rate (bytes/sec)',
            data: rateSeries.map(p=>p.y),
            borderColor: '#eab308',
            backgroundColor: 'rgba(234, 179, 8, 0.15)',
            fill: true,
            tension: 0.2,
            hidden: showGrowthCheckbox ? !showGrowthCheckbox.checked : true,
            yAxisID: 'y1'
        });

        const chart = new Chart(ctx, {
            data: { labels, datasets },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: { position: 'bottom' }
                },
                scales: {
                    y: { 
                        beginAtZero: true,
                        title: { display: true, text: 'Cumulative Memory' },
                        ticks: { callback: v => formatBytes(v) }
                    },
                    y1: {
                        beginAtZero: true,
                        position: 'right',
                        grid: { drawOnChartArea: false },
                        title: { display: true, text: 'Growth Rate (bytes/step)' }
                    },
                    x: { title: { display: false } }
                }
            }
        });

        window.chartInstances = window.chartInstances || {};
        window.chartInstances['timelineChart'] = chart;

        if (showGrowthCheckbox) {
            showGrowthCheckbox.onchange = () => {
                const ds = chart.data.datasets.find(d => d.yAxisID === 'y1');
                if (!ds) return;
                ds.hidden = !showGrowthCheckbox.checked;
                chart.update();
            };
        }
    }
}

// Enhanced type chart with better label handling for complex Rust types
function initEnhancedTypeChart(data) {
    const ctx = document.getElementById('typeChart');
    if (!ctx || !window.Chart) return;

    // Comprehensive cleanup for this specific chart
    try {
        // Check if there's already a chart attached to this canvas
        if (ctx.chart) {
            ctx.chart.destroy();
            delete ctx.chart;
        }
        
        // Clear any Chart.js instance for this canvas
        if (window.Chart.instances) {
            Object.values(window.Chart.instances).forEach(instance => {
                if (instance.canvas === ctx) {
                    instance.destroy();
                }
            });
        }
        
        // Clear our tracked instance
        if (window.chartInstances && window.chartInstances['typeChart']) {
            window.chartInstances['typeChart'].destroy();
            delete window.chartInstances['typeChart'];
        }
        
        // Clear canvas context
        const context = ctx.getContext('2d');
        context.clearRect(0, 0, ctx.width, ctx.height);
        
    } catch(e) {
        console.warn('Chart cleanup warning:', e);
    }

    const typeData = {};
    const allocs = data.memory_analysis?.allocations || data.allocations || [];
    
    console.log('Type chart data extraction:', { totalAllocs: allocs.length });
    
    allocs.forEach(alloc => {
        let type = alloc.type_name || 'Unknown';
        const originalType = type;
        
        // Simplify complex Rust type names for better readability
        type = type.replace(/alloc::sync::Arc/g, 'Arc');
        type = type.replace(/alloc::rc::Rc/g, 'Rc');
        type = type.replace(/alloc::string::String/g, 'String');
        type = type.replace(/alloc::vec::Vec/g, 'Vec');
        type = type.replace(/std::collections::hash::map::HashMap/g, 'HashMap');
        type = type.replace(/std::collections::btree::map::BTreeMap/g, 'BTreeMap');
        type = type.replace(/alloc::collections::\w+::\w+::/g, '');
        
        // Remove generic parameters for cleaner display
        type = type.replace(/<[^>]+>/g, '<T>');
        
        // Truncate very long type names
        if (type.length > 25) {
            type = type.substring(0, 22) + '...';
        }
        
        const size = alloc.size || 0;
        typeData[type] = (typeData[type] || 0) + size;
        
        if (size > 0) {
            console.log(`Adding ${originalType} -> ${type}: ${size} bytes`);
        }
    });
    
    console.log('Type data aggregated:', typeData);

    const sortedEntries = Object.entries(typeData).sort((a, b) => b[1] - a[1]);
    const labels = sortedEntries.map(([k, v]) => k);
    const values = sortedEntries.map(([k, v]) => v);
    
    if (labels.length > 0 && window.Chart) {
        const chart = new Chart(ctx, {
            type: 'bar',
            data: {
                labels: labels,
                datasets: [{
                    label: 'Memory Usage',
                    data: values,
                    backgroundColor: labels.map((_, i) => {
                        const colors = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#06b6d4', '#84cc16'];
                        return colors[i % colors.length] + '80';
                    }),
                    borderColor: labels.map((_, i) => {
                        const colors = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#06b6d4', '#84cc16'];
                        return colors[i % colors.length];
                    }),
                    borderWidth: 2
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: { display: false },
                    tooltip: {
                        callbacks: {
                            label: (context) => {
                                const originalType = allocs.find(a => {
                                    let simplified = a.type_name || 'Unknown';
                                    simplified = simplified.replace(/alloc::(sync::Arc|rc::Rc|collections::\w+::\w+::|string::String|vec::Vec)/g, (match, p1) => {
                                        switch(p1) {
                                            case 'sync::Arc': return 'Arc';
                                            case 'rc::Rc': return 'Rc';
                                            case 'string::String': return 'String';
                                            case 'vec::Vec': return 'Vec';
                                            default: return p1.split('::').pop();
                                        }
                                    });
                                    simplified = simplified.replace(/std::collections::hash::map::HashMap/g, 'HashMap');
                                    simplified = simplified.replace(/std::collections::btree::map::BTreeMap/g, 'BTreeMap');
                                    if (simplified.length > 30) simplified = simplified.substring(0, 27) + '...';
                                    return simplified === context.label;
                                })?.type_name || context.label;
                                return [`Type: ${originalType}`, `Memory: ${formatBytes(context.parsed.y)}`];
                            }
                        }
                    }
                },
                scales: {
                    x: { 
                        ticks: {
                            maxRotation: 45,
                            minRotation: 0,
                            font: { 
                                size: 11, 
                                weight: '500',
                                family: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
                            },
                            color: function(context) {
                                return document.documentElement.classList.contains('dark-theme') ? '#e2e8f0' : '#475569';
                            },
                            padding: 8,
                            callback: function(value, index) {
                                const label = this.getLabelForValue(value);
                                // Ensure readability by adding spacing
                                return label.length > 15 ? label.substring(0, 13) + '...' : label;
                            }
                        },
                        grid: {
                            display: false
                        }
                    },
                    y: { 
                        beginAtZero: true,
                        ticks: {
                            callback: (value) => formatBytes(value),
                            color: function(context) {
                                return document.documentElement.classList.contains('dark-theme') ? '#cbd5e1' : '#64748b';
                            },
                            font: { size: 10, weight: '400' }
                        },
                        grid: {
                            color: function(context) {
                                return document.documentElement.classList.contains('dark-theme') ? '#374151' : '#e2e8f0';
                            },
                            lineWidth: 1
                        }
                    }
                }
            }
        });
        
        window.chartInstances = window.chartInstances || {};
        window.chartInstances['typeChart'] = chart;
    }
}

// Type Treemap Chart
function initTreemapChart(data) {
    const container = document.getElementById('treemap');
    if (!container) return;
    
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    const byType = {};
    
    allocs.forEach(a => {
        const type = a.type_name || 'Unknown';
        byType[type] = (byType[type] || 0) + (a.size || 0);
    });
    
    const top = Object.entries(byType).sort((a,b) => b[1] - a[1]).slice(0, 12);
    const totalSize = top.reduce((sum, [, size]) => sum + size, 0);
    
    if (totalSize > 0) {
        let html = '<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 8px; height: 100%; padding: 16px;">';
        
        top.forEach(([type, size], index) => {
            const percentage = (size / totalSize) * 100;
            const color = `hsl(${index * 30}, 70%, 55%)`;
            
            html += `
                <div style="
                    background: ${color};
                    color: white;
                    padding: 12px;
                    border-radius: 8px;
                    font-size: 11px;
                    font-weight: 600;
                    display: flex;
                    flex-direction: column;
                    justify-content: center;
                    text-align: center;
                    min-height: 80px;
                    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
                    transition: transform 0.2s ease;
                " title="${type}: ${formatBytes(size)}" onmouseover="this.style.transform='scale(1.05)'" onmouseout="this.style.transform='scale(1)'">
                    <div style="margin-bottom: 4px;">${formatTypeName(type)}</div>
                    <div style="font-size: 10px; opacity: 0.9;">${formatBytes(size)}</div>
                    <div style="font-size: 9px; opacity: 0.7;">${percentage.toFixed(1)}%</div>
                </div>
            `;
        });
        
        html += '</div>';
        container.innerHTML = html;
    } else {
        container.innerHTML = '<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-secondary);">No data available</div>';
    }
}

// FFI Risk Chart
function initFFIRiskChart(data) {
    // Guard destroy if exists
    try {
        if (window.chartInstances && window.chartInstances['ffi-risk-chart']) {
            window.chartInstances['ffi-risk-chart'].destroy();
            delete window.chartInstances['ffi-risk-chart'];
        }
    } catch (_) {}

    const ctx = document.getElementById('ffi-risk-chart');
    if (!ctx) return;
    
    const ffiData = data.unsafe_ffi?.enhanced_ffi_data || [];
    
    const riskLevels = {
        'Low Risk': ffiData.filter(item => (item.safety_violations || []).length === 0).length,
        'Medium Risk': ffiData.filter(item => (item.safety_violations || []).length > 0 && (item.safety_violations || []).length <= 2).length,
        'High Risk': ffiData.filter(item => (item.safety_violations || []).length > 2).length
    };
    
    if (window.Chart) {
        const chart = new Chart(ctx, {
            type: 'doughnut',
            data: {
                labels: Object.keys(riskLevels),
                datasets: [{
                    data: Object.values(riskLevels),
                    backgroundColor: ['#059669', '#ea580c', '#dc2626'],
                    borderWidth: 2,
                    borderColor: 'var(--bg-primary)'
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: {
                        position: 'bottom',
                        labels: {
                            padding: 20,
                            usePointStyle: true
                        }
                    }
                }
            }
        });
    }
}

// Add missing chart and graph functions
function initGrowthTrends(data) {
    const container = document.getElementById('growth');
    if (!container) return;
    
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    if (allocs.length === 0) {
        container.innerHTML = '<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-secondary);">No growth data available</div>';
        return;
    }
    
    // Simple growth visualization
    const sorted = allocs.slice().sort((a,b) => (a.timestamp_alloc||0) - (b.timestamp_alloc||0));
    let cumulative = 0;
    const points = [];
    
    for (let i = 0; i < Math.min(sorted.length, 20); i++) {
        cumulative += sorted[i].size || 0;
        points.push(cumulative);
    }
    
    const maxValue = Math.max(...points);
    let html = '<div style="display: flex; align-items: end; height: 200px; gap: 4px; padding: 20px;">';
    
    points.forEach((value, i) => {
        const height = (value / maxValue) * 160;
        html += `
            <div style="
                width: 12px;
                height: ${height}px;
                background: linear-gradient(to top, #2563eb, #3b82f6);
                border-radius: 2px;
                margin: 0 1px;
            " title="Step ${i + 1}: ${formatBytes(value)}"></div>
        `;
    });
    
    html += '</div>';
    container.innerHTML = html;
}

function initMemoryFragmentation(data) {
    const container = document.getElementById('memoryFragmentation');
    if (!container) return;
    
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    const totalMemory = allocs.reduce((sum, a) => sum + (a.size || 0), 0);
    const activeMemory = allocs.filter(a => !a.timestamp_dealloc).reduce((sum, a) => sum + (a.size || 0), 0);
    const fragmentationRate = totalMemory > 0 ? ((totalMemory - activeMemory) / totalMemory * 100) : 0;
    
    container.innerHTML = `
        <div style="padding: 20px;">
            <div style="display: flex; justify-content: space-between; margin-bottom: 16px;">
                <div>
                    <div style="color: var(--text-secondary); font-size: 0.9rem;">Fragmentation Rate</div>
                    <div style="font-size: 2rem; font-weight: 700; color: ${fragmentationRate > 30 ? '#dc2626' : fragmentationRate > 15 ? '#ea580c' : '#059669'};">
                        ${fragmentationRate.toFixed(1)}%
                    </div>
                </div>
                <div>
                    <div style="color: var(--text-secondary); font-size: 0.9rem;">Active Memory</div>
                    <div style="font-size: 1.2rem; font-weight: 600;">${formatBytes(activeMemory)}</div>
                </div>
            </div>
            <div style="background: var(--bg-secondary); height: 8px; border-radius: 4px; overflow: hidden;">
                <div style="
                    background: linear-gradient(to right, #059669, #ea580c);
                    width: ${Math.min(100, fragmentationRate)}%;
                    height: 100%;
                    border-radius: 4px;
                    transition: width 0.8s ease;
                "></div>
            </div>
            <div style="margin-top: 12px; font-size: 0.8rem; color: var(--text-secondary);">
                ${fragmentationRate > 30 ? 'High fragmentation detected' : fragmentationRate > 15 ? 'Moderate fragmentation' : 'Low fragmentation'}
            </div>
        </div>
    `;
}

function initVariableGraph(data) {
    const container = document.getElementById('graph');
    if (!container) return;
    
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    if (allocs.length === 0) {
        container.innerHTML = '<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-secondary);">No relationship data available</div>';
        return;
    }
    
    // Create a simple node-link visualization
    const nodes = allocs.slice(0, 20).map((a, i) => ({
        id: i,
        name: a.var_name || `var_${i}`,
        type: a.type_name || 'unknown',
        size: a.size || 0,
        x: 50 + (i % 4) * 80,
        y: 50 + Math.floor(i / 4) * 60
    }));
    
    let svg = `
        <svg width="100%" height="100%" style="background: transparent;">
            <defs>
                <filter id="glow">
                    <feGaussianBlur stdDeviation="3" result="coloredBlur"/>
                    <feMerge>
                        <feMergeNode in="coloredBlur"/>
                        <feMergeNode in="SourceGraphic"/>
                    </feMerge>
                </filter>
            </defs>
    `;
    
    // Add links between nearby nodes
    for (let i = 0; i < nodes.length - 1; i++) {
        if (i % 4 !== 3) { // Connect horizontally
            svg += `<line x1="${nodes[i].x}" y1="${nodes[i].y}" x2="${nodes[i+1].x}" y2="${nodes[i+1].y}" stroke="var(--border-light)" stroke-width="1" opacity="0.3"/>`;
        }
        if (i < nodes.length - 4) { // Connect vertically
            svg += `<line x1="${nodes[i].x}" y1="${nodes[i].y}" x2="${nodes[i+4].x}" y2="${nodes[i+4].y}" stroke="var(--border-light)" stroke-width="1" opacity="0.3"/>`;
        }
    }
    
    // Add nodes
    nodes.forEach(node => {
        const radius = Math.max(8, Math.min(20, Math.log(node.size + 1) * 2));
        const color = node.type.includes('String') ? '#fbbf24' : 
                     node.type.includes('Vec') ? '#3b82f6' : 
                     node.type.includes('Box') || node.type.includes('Rc') ? '#8b5cf6' : '#6b7280';
        
        svg += `
            <circle 
                cx="${node.x}" 
                cy="${node.y}" 
                r="${radius}" 
                fill="${color}" 
                stroke="white" 
                stroke-width="2" 
                filter="url(#glow)"
                style="cursor: pointer;"
                onmouseover="this.r.baseVal.value = ${radius + 3}"
                onmouseout="this.r.baseVal.value = ${radius}"
            >
                <title>${node.name} (${node.type})</title>
            </circle>
            <text 
                x="${node.x}" 
                y="${node.y + radius + 12}" 
                text-anchor="middle" 
                font-size="10" 
                fill="var(--text-primary)"
                style="font-weight: 500;"
            >${node.name.length > 8 ? node.name.substring(0, 8) + '...' : node.name}</text>
        `;
    });
    
    svg += '</svg>';
    container.innerHTML = svg;
}

// Initialize lifetime visualization
function initLifetimeVisualization(data) {
    const container = document.getElementById('lifetimes');
    if (!container) return;
    
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    if (allocs.length === 0) {
        container.innerHTML = '<div style="padding: 20px; text-align: center; color: var(--text-secondary);">No lifetime data available</div>';
        return;
    }
    
    // Show top allocations by lifetime
    const withLifetime = allocs.filter(a => a.lifetime_ms || (a.timestamp_alloc && a.timestamp_dealloc));
    const sorted = withLifetime.sort((a, b) => {
        const aLifetime = a.lifetime_ms || (a.timestamp_dealloc - a.timestamp_alloc);
        const bLifetime = b.lifetime_ms || (b.timestamp_dealloc - b.timestamp_alloc);
        return bLifetime - aLifetime;
    }).slice(0, 10);
    
    if (sorted.length === 0) {
        container.innerHTML = '<div style="padding: 20px; text-align: center; color: var(--text-secondary);">No lifetime data available</div>';
        return;
    }
    
    let html = '<div style="padding: 16px;">';
    
    sorted.forEach((alloc, index) => {
        const lifetime = alloc.lifetime_ms || (alloc.timestamp_dealloc - alloc.timestamp_alloc);
        const isActive = !alloc.timestamp_dealloc;
        const varName = alloc.var_name || `allocation_${index}`;
        const size = formatBytes(alloc.size || 0);
        
        html += `
            <div style="
                margin-bottom: 12px; 
                padding: 12px; 
                background: var(--bg-secondary); 
                border-radius: 8px;
                border-left: 4px solid ${isActive ? '#059669' : '#2563eb'};
            ">
                <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
                    <span style="font-weight: 600; color: var(--text-primary);">${varName}</span>
                    <span style="font-size: 0.9rem; color: var(--text-secondary);">${size}</span>
                </div>
                <div style="display: flex; justify-content: space-between; align-items: center;">
                    <span style="font-size: 0.8rem; color: var(--text-secondary);">
                        ${formatTypeName(alloc.type_name || 'Unknown')}
                    </span>
                    <span style="
                        font-size: 0.8rem; 
                        font-weight: 600; 
                        color: ${isActive ? '#059669' : '#2563eb'};
                    ">
                        ${isActive ? 'Active' : `${lifetime}ms`}
                    </span>
                </div>
            </div>
        `;
    });
    
    html += '</div>';
    container.innerHTML = html;
}

// Helper function to update elements
function updateElement(id, value) {
    const element = document.getElementById(id);
    if (element) {
        element.textContent = value;
    }
}

// Original dashboard functions from dashboard.html
function renderKpis() {
    const data = window.analysisData || {};
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    const total = allocs.reduce((s,a)=>s+(a.size||0),0);
    const active = allocs.filter(a=>!a.timestamp_dealloc).length;
    const leaks = allocs.filter(a=>a.is_leaked).length;
    const safety = Math.max(0, 100 - (leaks * 20));
    
    updateElement('total-allocations', allocs.length.toLocaleString());
    updateElement('active-variables', active.toLocaleString());
    updateElement('total-memory', formatBytes(total));
    updateElement('safety-score', safety + '%');
}

function populateAllocationsTable() {
    const data = window.analysisData || {};
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    const allocTable = document.getElementById('allocTable');
    if (!allocTable) return;
    
    const top = allocs.slice().sort((a,b)=>(b.size||0)-(a.size||0)).slice(0,50);
    allocTable.innerHTML = top.map(a => {
        const status = a.is_leaked ? 'Leaked' : (a.timestamp_dealloc ? 'Freed' : 'Active');
        const statusClass = a.is_leaked ? 'status-leaked' : (a.timestamp_dealloc ? 'status-freed' : 'status-active');
        
        return `<tr>
            <td>${a.var_name || 'Unknown'}</td>
            <td>${formatTypeName(a.type_name || 'Unknown')}</td>
            <td>${formatBytes(a.size || 0)}</td>
            <td><span class="status-badge ${statusClass}">${status}</span></td>
        </tr>`;
    }).join('');
}

function renderTypeChart() {
    const ctx = document.getElementById('typeChart');
    if (!ctx || !window.Chart) return;
    
    const data = window.analysisData || {};
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    const byType = {};
    
    allocs.forEach(a => {
        const type = a.type_name || 'Unknown';
        byType[type] = (byType[type] || 0) + (a.size || 0);
    });
    
    const top = Object.entries(byType).sort((a,b) => b[1] - a[1]).slice(0, 8);
    
    if (top.length > 0) {
        new Chart(ctx, {
            type: 'bar',
            data: {
                labels: top.map(x => formatTypeName(x[0])),
                datasets: [{
                    label: 'Memory Usage',
                    data: top.map(x => x[1]),
                    backgroundColor: '#2563eb',
                    borderRadius: 6
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: { legend: { display: false } },
                scales: {
                    y: { 
                        beginAtZero: true,
                        ticks: { callback: function(value) { return formatBytes(value); } }
                    }
                }
            }
        });
    }
}

function renderTimelineChart() {
    const ctx = document.getElementById('timelineChart');
    if (!ctx || !window.Chart) return;
    
    const data = window.analysisData || {};
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    const sorted = allocs.slice().sort((a,b) => (a.timestamp_alloc||0) - (b.timestamp_alloc||0));
    
    let cumulative = 0;
    const points = [];
    const step = Math.max(1, Math.floor(sorted.length / 30));
    
    for (let i = 0; i < sorted.length; i += step) {
        cumulative += sorted[i].size || 0;
        points.push({ x: i, y: cumulative });
    }
    
    if (points.length > 1) {
        new Chart(ctx, {
            type: 'line',
            data: {
                labels: points.map(p => p.x),
                datasets: [{
                    label: 'Cumulative Memory',
                    data: points.map(p => p.y),
                    borderColor: '#059669',
                    backgroundColor: 'rgba(5, 150, 105, 0.1)',
                    fill: true,
                    tension: 0.4
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: { legend: { display: false } },
                scales: {
                    y: { 
                        beginAtZero: true,
                        ticks: { callback: function(value) { return formatBytes(value); } }
                    }
                }
            }
        });
    }
}

function renderTreemap() {
    const container = document.getElementById('treemap');
    if (!container) return;
    
    const data = window.analysisData || {};
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    const byType = {};
    
    allocs.forEach(a => {
        const type = a.type_name || 'Unknown';
        byType[type] = (byType[type] || 0) + (a.size || 0);
    });
    
    const top = Object.entries(byType).sort((a,b) => b[1] - a[1]).slice(0, 12);
    const totalSize = top.reduce((sum, [, size]) => sum + size, 0);
    
    if (totalSize > 0) {
        let html = '<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 8px; height: 100%; padding: 16px;">';
        
        top.forEach(([type, size], index) => {
            const percentage = (size / totalSize) * 100;
            const color = `hsl(${index * 30}, 70%, 55%)`;
            
            html += `
                <div style="
                    background: ${color};
                    color: white;
                    padding: 12px;
                    border-radius: 8px;
                    font-size: 11px;
                    font-weight: 600;
                    display: flex;
                    flex-direction: column;
                    justify-content: center;
                    text-align: center;
                    min-height: 80px;
                    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
                    transition: transform 0.2s ease;
                " title="${type}: ${formatBytes(size)}" onmouseover="this.style.transform='scale(1.05)'" onmouseout="this.style.transform='scale(1)'">
                    <div style="margin-bottom: 4px;">${formatTypeName(type)}</div>
                    <div style="font-size: 10px; opacity: 0.9;">${formatBytes(size)}</div>
                    <div style="font-size: 9px; opacity: 0.7;">${percentage.toFixed(1)}%</div>
                </div>
            `;
        });
        
        html += '</div>';
        container.innerHTML = html;
    } else {
        container.innerHTML = '<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-secondary);">No data available</div>';
    }
}

function renderLifetimes() {
    const container = document.getElementById('lifetimes');
    if (!container) return;
    
    const data = window.analysisData || {};
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    const withLifetime = allocs.filter(a => a.lifetime_ms || (a.timestamp_alloc && a.timestamp_dealloc));
    const sorted = withLifetime.sort((a, b) => {
        const aLifetime = a.lifetime_ms || (a.timestamp_dealloc - a.timestamp_alloc);
        const bLifetime = b.lifetime_ms || (b.timestamp_dealloc - b.timestamp_alloc);
        return bLifetime - aLifetime;
    }).slice(0, 10);
    
    if (sorted.length === 0) {
        container.innerHTML = '<div style="padding: 20px; text-align: center; color: var(--text-secondary);">No lifetime data available</div>';
        return;
    }
    
    let html = '<div style="padding: 16px;">';
    
    sorted.forEach((alloc, index) => {
        const lifetime = alloc.lifetime_ms || (alloc.timestamp_dealloc - alloc.timestamp_alloc);
        const isActive = !alloc.timestamp_dealloc;
        const varName = alloc.var_name || `allocation_${index}`;
        const size = formatBytes(alloc.size || 0);
        
        html += `
            <div style="
                margin-bottom: 12px; 
                padding: 12px; 
                background: var(--bg-secondary); 
                border-radius: 8px;
                border-left: 4px solid ${isActive ? '#059669' : '#2563eb'};
            ">
                <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
                    <span style="font-weight: 600; color: var(--text-primary);">${varName}</span>
                    <span style="font-size: 0.9rem; color: var(--text-secondary);">${size}</span>
                </div>
                <div style="display: flex; justify-content: space-between; align-items: center;">
                    <span style="font-size: 0.8rem; color: var(--text-secondary);">
                        ${formatTypeName(alloc.type_name || 'Unknown')}
                    </span>
                    <span style="
                        font-size: 0.8rem; 
                        font-weight: 600; 
                        color: ${isActive ? '#059669' : '#2563eb'};
                    ">
                        ${isActive ? 'Active' : `${lifetime}ms`}
                    </span>
                </div>
            </div>
        `;
    });
    
    html += '</div>';
    container.innerHTML = html;
}

function renderFFI() {
    // First try the chart container for simple chart
    const chartContainer = document.getElementById('ffi-risk-chart');
    if (chartContainer && window.Chart) {
        const data = window.analysisData || {};
        const ffiData = data.unsafe_ffi || data.unsafeFFI || {};
        const operations = ffiData.enhanced_ffi_data || ffiData.allocations || ffiData.unsafe_operations || [];
        
        if (operations.length > 0) {
            // Guard: destroy existing chart instance if any
            try {
                if (window.chartInstances && window.chartInstances['ffi-risk-chart']) {
                    window.chartInstances['ffi-risk-chart'].destroy();
                    delete window.chartInstances['ffi-risk-chart'];
                }
            } catch (_) {}

            const highRisk = operations.filter(op => (op.safety_violations || []).length > 2).length;
            const mediumRisk = operations.filter(op => (op.safety_violations || []).length > 0 && (op.safety_violations || []).length <= 2).length;
            const lowRisk = operations.filter(op => (op.safety_violations || []).length === 0).length;
            
            window.chartInstances = window.chartInstances || {};
            window.chartInstances['ffi-risk-chart'] = new Chart(chartContainer, {
                type: 'doughnut',
                data: {
                    labels: ['Low Risk', 'Medium Risk', 'High Risk'],
                    datasets: [{
                        data: [lowRisk, mediumRisk, highRisk],
                        backgroundColor: ['#059669', '#ea580c', '#dc2626'],
                        borderWidth: 2,
                        borderColor: 'var(--bg-primary)'
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    plugins: {
                        legend: {
                            position: 'bottom',
                            labels: {
                                padding: 20,
                                usePointStyle: true,
                                generateLabels: function(chart) {
                                    const data = chart.data;
                                    return data.labels.map((label, i) => ({
                                        text: `${label}: ${data.datasets[0].data[i]}`,
                                        fillStyle: data.datasets[0].backgroundColor[i],
                                        strokeStyle: data.datasets[0].backgroundColor[i],
                                        pointStyle: 'circle'
                                    }));
                                }
                            }
                        }
                    }
                }
            });
            return;
        }
    }
    
    // Main comprehensive FFI visualization based on project's actual SVG code
    const container = document.getElementById('ffiVisualization');
    if (!container) return;
    
    const data = window.analysisData || {};
    const ffiData = data.unsafe_ffi || data.unsafeFFI || {};
    const allocations = ffiData.allocations || ffiData.enhanced_ffi_data || [];
    const violations = ffiData.violations || [];
    
    if (allocations.length === 0) {
        container.innerHTML = '<div style="padding: 20px; text-align: center; color: var(--text-secondary);">No FFI data available</div>';
        return;
    }
    
    // Create the ACTUAL project-based unsafe/FFI dashboard SVG
    createProjectBasedUnsafeFFIDashboard(container, allocations, violations);
}

// PROJECT-BASED Unsafe/FFI Dashboard - Direct implementation from visualization.rs
function createProjectBasedUnsafeFFIDashboard(container, allocations, violations) {
    const width = 1400;
    const height = 1000;
    
    // Calculate key metrics exactly like the Rust code
    const unsafeCount = allocations.filter(a => 
        (a.source && (a.source.UnsafeRust || a.source === 'UnsafeRust')) ||
        (a.allocation_source === 'UnsafeRust')
    ).length;
    
    const ffiCount = allocations.filter(a => 
        (a.source && (a.source.FfiC || a.source === 'FfiC')) ||
        (a.allocation_source === 'FfiC')
    ).length;
    
    const crossBoundaryEvents = allocations.reduce((sum, a) => 
        sum + ((a.cross_boundary_events && a.cross_boundary_events.length) || 0), 0
    );
    
    const totalUnsafeMemory = allocations
        .filter(a => a.source !== 'RustSafe' && a.allocation_source !== 'RustSafe')
        .reduce((sum, a) => sum + ((a.base && a.base.size) || a.size || 0), 0);
    
    // Create the full SVG dashboard exactly like the Rust implementation
    let html = `
        <div style="width: 100%; height: ${height}px; background: linear-gradient(135deg, #2c3e50 0%, #34495e 50%, #2c3e50 100%); border-radius: 12px; overflow: hidden; position: relative;">
            <svg width="100%" height="100%" viewBox="0 0 ${width} ${height}" style="font-family: 'Segoe UI', Arial, sans-serif;">
                <!-- SVG Definitions -->
                <defs>
                    <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
                        <polygon points="0 0, 10 3.5, 0 7" fill='#e74c3c'/>
                    </marker>
                    <filter id="glow">
                        <feGaussianBlur stdDeviation="3" result="coloredBlur"/>
                        <feMerge>
                            <feMergeNode in="coloredBlur"/>
                            <feMergeNode in="SourceGraphic"/>
                        </feMerge>
                    </filter>
                </defs>
                
                <!-- Main Title -->
                <text x="${width/2}" y="40" text-anchor="middle" font-size="24" font-weight="bold" fill='#ecf0f1'>
                    Unsafe Rust &amp; FFI Memory Analysis Dashboard
                </text>
                
                <!-- Key Metrics Cards -->
                <g id="metrics-cards">
                    ${createMetricsCards(unsafeCount, ffiCount, crossBoundaryEvents, violations.length, totalUnsafeMemory)}
                </g>
                
                <!-- Allocation Source Breakdown -->
                <g id="allocation-breakdown" transform="translate(50, 150)">
                    ${createAllocationSourceBreakdown(allocations)}
                </g>
                
                <!-- Memory Safety Status -->
                <g id="safety-status" transform="translate(750, 150)">
                    ${createMemorySafetyStatus(violations)}
                </g>
                
                <!-- Cross-Language Memory Flow -->
                <g id="boundary-flow" transform="translate(50, 500)">
                    ${createBoundaryFlow(allocations)}
                </g>
                
                <!-- Unsafe Memory Hotspots -->
                <g id="unsafe-hotspots" transform="translate(750, 500)">
                    ${createUnsafeHotspots(allocations)}
                </g>
            </svg>
        </div>
    `;
    
    container.innerHTML = html;
    
    // Add interactivity
    setTimeout(() => {
        addFFIInteractivity();
    }, 100);
}

// Create metrics cards exactly like Rust implementation
function createMetricsCards(unsafeCount, ffiCount, crossBoundaryEvents, violationCount, totalUnsafeMemory) {
    const metrics = [
        { label: 'Unsafe Allocations', value: unsafeCount, color: '#e74c3c', x: 100 },
        { label: 'FFI Allocations', value: ffiCount, color: '#3498db', x: 350 },
        { label: 'Boundary Crossings', value: crossBoundaryEvents, color: '#f39c12', x: 600 },
        { label: 'Safety Violations', value: violationCount, color: '#e67e22', x: 850 },
        { label: 'Unsafe Memory', value: formatBytes(totalUnsafeMemory), color: '#9b59b6', x: 1100 }
    ];
    
    return metrics.map(metric => `
        <!-- Card background -->
        <rect x="${metric.x - 60}" y="55" width="120" height="50" 
              fill="${metric.color}" fill-opacity="0.2" 
              stroke="${metric.color}" stroke-width="2" rx="8"/>
        
        <!-- Value -->
        <text x="${metric.x}" y="70" text-anchor="middle" font-size="16" font-weight="bold" fill="${metric.color}">
            ${metric.value}
        </text>
        
        <!-- Label -->
        <text x="${metric.x}" y="95" text-anchor="middle" font-size="10" fill='#bdc3c7'>
            ${metric.label}
        </text>
    `).join('');
}

// Create allocation source breakdown
function createAllocationSourceBreakdown(allocations) {
    let safeCount = 0, unsafeCount = 0, ffiCount = 0, crossBoundaryCount = 0;
    
    allocations.forEach(allocation => {
        const source = allocation.source || allocation.allocation_source || 'Unknown';
        if (source === 'RustSafe' || source.RustSafe) safeCount++;
        else if (source === 'UnsafeRust' || source.UnsafeRust) unsafeCount++;
        else if (source === 'FfiC' || source.FfiC) ffiCount++;
        else if (source === 'CrossBoundary' || source.CrossBoundary) crossBoundaryCount++;
    });
    
    const total = safeCount + unsafeCount + ffiCount + crossBoundaryCount;
    if (total === 0) {
        return `<text x="300" y="150" text-anchor="middle" font-size="14" fill='#95a5a6'>No allocation data available</text>`;
    }
    
    const sources = [
        { label: 'Safe Rust', count: safeCount, color: '#2ecc71', x: 50 },
        { label: 'Unsafe Rust', count: unsafeCount, color: '#e74c3c', x: 170 },
        { label: 'FFI', count: ffiCount, color: '#3498db', x: 290 },
        { label: 'Cross-boundary', count: crossBoundaryCount, color: '#9b59b6', x: 410 }
    ];
    
    let svg = `
        <!-- Section background -->
        <rect x="0" y="0" width="600" height="300" fill="rgba(52, 73, 94, 0.3)" 
              stroke='#34495e' stroke-width="2" rx="10"/>
        
        <!-- Section title -->
        <text x="300" y="-10" text-anchor="middle" font-size="18" font-weight="bold" fill='#ecf0f1'>
            Memory Allocation Sources
        </text>
    `;
    
    sources.forEach(source => {
        if (source.count > 0) {
            const barHeight = (source.count / total * 100);
            svg += `
                <!-- Bar -->
                <rect x="${source.x}" y="${200 - barHeight}" width="40" height="${barHeight}" fill="${source.color}"/>
                
                <!-- Count label -->
                <text x="${source.x + 20}" y="${200 - barHeight - 5}" text-anchor="middle" 
                      font-size="12" font-weight="bold" fill="${source.color}">
                    ${source.count}
                </text>
                
                <!-- Label -->
                <text x="${source.x + 20}" y="220" text-anchor="middle" font-size="10" fill='#ecf0f1'>
                    ${source.label}
                </text>
            `;
        }
    });
    
    return svg;
}

// Create memory safety status
function createMemorySafetyStatus(violations) {
    const bgColor = violations.length === 0 ? '#27ae60' : '#e74c3c';
    
    let svg = `
        <!-- Section background -->
        <rect x="0" y="0" width="600" height="300" fill="${bgColor}20" 
              stroke="${bgColor}" stroke-width="2" rx="10"/>
        
        <!-- Section title -->
        <text x="300" y="-10" text-anchor="middle" font-size="18" font-weight="bold" fill='#ecf0f1'>
            Memory Safety Status
        </text>
    `;
    
    if (violations.length === 0) {
        svg += `
            <text x="300" y="150" text-anchor="middle" font-size="16" font-weight="bold" fill='#27ae60'>
                No Safety Violations Detected
            </text>
            <text x="300" y="180" text-anchor="middle" font-size="12" fill='#2ecc71'>
                All unsafe operations and FFI calls appear to be memory-safe
            </text>
        `;
    } else {
        svg += `
            <text x="300" y="120" text-anchor="middle" font-size="16" font-weight="bold" fill='#e74c3c'>
                ${violations.length} Safety Violations Detected
            </text>
        `;
        
        violations.slice(0, 5).forEach((violation, i) => {
            const y = 160 + i * 20;
            const description = getViolationDescription(violation);
            svg += `
                <text x="30" y="${y}" font-size="12" fill='#e74c3c'>โ€ข ${description}</text>
            `;
        });
    }
    
    return svg;
}

// Create boundary flow diagram
function createBoundaryFlow(allocations) {
    let rustToFfi = 0, ffiToRust = 0;
    
    allocations.forEach(allocation => {
        if (allocation.cross_boundary_events) {
            allocation.cross_boundary_events.forEach(event => {
                const eventType = event.event_type || event.type;
                if (eventType === 'RustToFfi' || eventType === 'OwnershipTransfer') rustToFfi++;
                else if (eventType === 'FfiToRust') ffiToRust++;
                else if (eventType === 'SharedAccess') {
                    rustToFfi++;
                    ffiToRust++;
                }
            });
        }
    });
    
    return `
        <!-- Section background -->
        <rect x="0" y="0" width="600" height="200" fill="rgba(52, 73, 94, 0.3)" 
              stroke='#34495e' stroke-width="2" rx="10"/>
        
        <!-- Section title -->
        <text x="300" y="-10" text-anchor="middle" font-size="18" font-weight="bold" fill='#ecf0f1'>
            Cross-Language Memory Flow
        </text>
        
        <!-- Rust territory -->
        <rect x="50" y="50" width="200" height="100" fill='#2ecc71' fill-opacity="0.2" 
              stroke='#2ecc71' stroke-width="2" rx="8"/>
        <text x="150" y="110" text-anchor="middle" font-size="14" font-weight="bold" fill='#2ecc71'>
            RUST
        </text>
        
        <!-- FFI territory -->
        <rect x="350" y="50" width="200" height="100" fill='#3498db' fill-opacity="0.2" 
              stroke='#3498db' stroke-width="2" rx="8"/>
        <text x="450" y="110" text-anchor="middle" font-size="14" font-weight="bold" fill='#3498db'>
            FFI / C
        </text>
        
        ${rustToFfi > 0 ? `
            <!-- Rust to FFI arrow -->
            <line x1="250" y1="80" x2="350" y2="80" stroke='#e74c3c' stroke-width="3" marker-end="url(#arrowhead)"/>
            <text x="300" y="75" text-anchor="middle" font-size="12" font-weight="bold" fill='#e74c3c'>
                ${rustToFfi}
            </text>
        ` : ''}
        
        ${ffiToRust > 0 ? `
            <!-- FFI to Rust indicator -->
            <text x="300" y="135" text-anchor="middle" font-size="12" font-weight="bold" fill='#f39c12'>
                โ† ${ffiToRust}
            </text>
        ` : ''}
    `;
}

// Create unsafe hotspots
function createUnsafeHotspots(allocations) {
    const unsafeAllocations = allocations.filter(a => 
        a.source !== 'RustSafe' && a.allocation_source !== 'RustSafe'
    );
    
    if (unsafeAllocations.length === 0) {
        return `
            <rect x="0" y="0" width="600" height="200" fill="rgba(52, 73, 94, 0.3)" 
                  stroke='#34495e' stroke-width="2" rx="10"/>
            <text x="300" y="-10" text-anchor="middle" font-size="18" font-weight="bold" fill='#ecf0f1'>
                Unsafe Memory Hotspots
            </text>
            <text x="300" y="100" text-anchor="middle" font-size="14" fill='#2ecc71'>
                No unsafe memory allocations detected
            </text>
        `;
    }
    
    let svg = `
        <rect x="0" y="0" width="600" height="200" fill="rgba(52, 73, 94, 0.3)" 
              stroke='#34495e' stroke-width="2" rx="10"/>
        <text x="300" y="-10" text-anchor="middle" font-size="18" font-weight="bold" fill='#ecf0f1'>
            Unsafe Memory Hotspots
        </text>
    `;
    
    unsafeAllocations.slice(0, 6).forEach((allocation, i) => {
        const x = 80 + (i % 3) * 180;
        const y = 80 + Math.floor(i / 3) * 70;
        const size = (allocation.base && allocation.base.size) || allocation.size || 0;
        const sizeFactor = Math.max(5, Math.min(20, Math.log(size + 1) * 2));
        
        const source = allocation.source || allocation.allocation_source || 'Unknown';
        let color = '#95a5a6';
        let label = 'OTHER';
        
        if (source === 'UnsafeRust' || source.UnsafeRust) {
            color = '#e74c3c';
            label = 'UNSAFE';
        } else if (source === 'FfiC' || source.FfiC) {
            color = '#3498db';
            label = 'FFI';
        } else if (source === 'CrossBoundary' || source.CrossBoundary) {
            color = '#9b59b6';
            label = 'CROSS';
        }
        
        svg += `
            <!-- Hotspot circle -->
            <circle cx="${x}" cy="${y}" r="${sizeFactor}" fill="${color}" fill-opacity="0.7" 
                    stroke="${color}" stroke-width="2" filter="url(#glow)"/>
            
            <!-- Size label -->
            <text x="${x}" y="${y + 4}" text-anchor="middle" font-size="8" font-weight="bold" fill='#ffffff'>
                ${formatBytes(size)}
            </text>
            
            <!-- Type label -->
            <text x="${x}" y="${y + 35}" text-anchor="middle" font-size="10" fill="${color}">
                ${label}
            </text>
        `;
    });
    
    return svg;
}

// Helper functions
function getViolationDescription(violation) {
    if (violation.DoubleFree || violation.type === 'DoubleFree') return 'Double Free';
    if (violation.InvalidFree || violation.type === 'InvalidFree') return 'Invalid Free';
    if (violation.PotentialLeak || violation.type === 'PotentialLeak') return 'Memory Leak';
    if (violation.CrossBoundaryRisk || violation.type === 'CrossBoundaryRisk') return 'Cross-Boundary Risk';
    return 'Unknown Violation';
}

function addFFIInteractivity() {
    // Add hover effects to hotspots
    const hotspots = document.querySelectorAll('#unsafe-hotspots circle');
    hotspots.forEach(hotspot => {
        hotspot.addEventListener('mouseover', function() {
            this.setAttribute('r', parseInt(this.getAttribute('r')) * 1.2);
        });
        hotspot.addEventListener('mouseout', function() {
            this.setAttribute('r', parseInt(this.getAttribute('r')) / 1.2);
        });
    });
}

function renderAllocationSourceChart(allocations) {
    const container = document.getElementById('allocation-source-chart');
    if (!container) return;
    
    // Count allocations by source
    let safeCount = 0, unsafeCount = 0, ffiCount = 0, crossBoundaryCount = 0;
    
    allocations.forEach(allocation => {
        if (allocation.source) {
            if (allocation.source.includes && allocation.source.includes('Safe')) safeCount++;
            else if (allocation.source.includes && allocation.source.includes('Unsafe')) unsafeCount++;
            else if (allocation.source.includes && allocation.source.includes('Ffi')) ffiCount++;
            else if (allocation.source.includes && allocation.source.includes('Cross')) crossBoundaryCount++;
        }
    });
    
    const total = safeCount + unsafeCount + ffiCount + crossBoundaryCount;
    if (total === 0) {
        container.innerHTML = '<div style="text-align: center; color: #95a5a6;">No allocation data available</div>';
        return;
    }
    
    const sources = [
        { label: 'Safe Rust', count: safeCount, color: '#2ecc71' },
        { label: 'Unsafe Rust', count: unsafeCount, color: '#e74c3c' },
        { label: 'FFI', count: ffiCount, color: '#3498db' },
        { label: 'Cross-boundary', count: crossBoundaryCount, color: '#9b59b6' }
    ];
    
    let html = '<div style="display: flex; justify-content: space-around; align-items: end; height: 100px;">';
    
    sources.forEach(source => {
        if (source.count > 0) {
            const barHeight = (source.count / total * 80);
            html += `
                <div style="text-align: center;">
                    <div style="font-size: 12px; font-weight: bold; color: ${source.color}; margin-bottom: 5px;">${source.count}</div>
                    <div style="width: 30px; height: ${barHeight}px; background: ${source.color}; margin: 0 auto 5px;"></div>
                    <div style="font-size: 10px; color: #ecf0f1; writing-mode: vertical-rl; text-orientation: mixed;">${source.label}</div>
                </div>
            `;
        }
    });
    
    html += '</div>';
    container.innerHTML = html;
}

function renderSafetyStatusPanel(violations) {
    const container = document.getElementById('safety-status-panel');
    if (!container) return;
    
    if (violations.length === 0) {
        container.innerHTML = `
            <div style="text-align: center; color: #27ae60;">
                <div style="font-size: 16px; font-weight: bold; margin-bottom: 10px;">No Safety Violations Detected</div>
                <div style="font-size: 12px; color: #2ecc71;">All unsafe operations and FFI calls appear to be memory-safe</div>
            </div>
        `;
    } else {
        let html = `
            <div style="text-align: center; color: #e74c3c; margin-bottom: 15px;">
                <div style="font-size: 16px; font-weight: bold;">${violations.length} Safety Violations Detected</div>
            </div>
            <div style="max-height: 80px; overflow-y: auto;">
        `;
        
        violations.slice(0, 5).forEach(violation => {
            const description = violation.type || 'Unknown Violation';
            html += `<div style="font-size: 12px; color: #e74c3c; margin-bottom: 5px;">โ€ข ${description}</div>`;
        });
        
        html += '</div>';
        container.innerHTML = html;
    }
}

function renderBoundaryFlowDiagram(allocations) {
    const container = document.getElementById('boundary-flow-diagram');
    if (!container) return;
    
    // Count boundary events
    let rustToFfi = 0, ffiToRust = 0;
    
    allocations.forEach(allocation => {
        if (allocation.cross_boundary_events) {
            allocation.cross_boundary_events.forEach(event => {
                if (event.event_type === 'RustToFfi') rustToFfi++;
                else if (event.event_type === 'FfiToRust') ffiToRust++;
                else if (event.event_type === 'OwnershipTransfer') rustToFfi++;
                else if (event.event_type === 'SharedAccess') {
                    rustToFfi++;
                    ffiToRust++;
                }
            });
        }
    });
    
    container.innerHTML = `
        <div style="display: flex; justify-content: space-around; align-items: center; height: 80px;">
            <!-- Rust territory -->
            <div style="width: 150px; height: 60px; background: rgba(46, 204, 113, 0.2); border: 2px solid #2ecc71; border-radius: 8px; display: flex; align-items: center; justify-content: center;">
                <div style="text-align: center;">
                    <div style="font-size: 14px; font-weight: bold; color: #2ecc71;">RUST</div>
                </div>
            </div>
            
            <!-- Flow arrows -->
            <div style="text-align: center;">
                ${rustToFfi > 0 ? `
                    <div style="margin-bottom: 5px;">
                        <span style="color: #e74c3c; font-weight: bold;">${rustToFfi}</span>
                        <span style="color: #e74c3c;"> โ†’</span>
                    </div>
                ` : ''}
                ${ffiToRust > 0 ? `
                    <div>
                        <span style="color: #f39c12;"> โ†</span>
                        <span style="color: #f39c12; font-weight: bold;">${ffiToRust}</span>
                    </div>
                ` : ''}
            </div>
            
            <!-- FFI territory -->
            <div style="width: 150px; height: 60px; background: rgba(52, 152, 219, 0.2); border: 2px solid #3498db; border-radius: 8px; display: flex; align-items: center; justify-content: center;">
                <div style="text-align: center;">
                    <div style="font-size: 14px; font-weight: bold; color: #3498db;">FFI / C</div>
                </div>
            </div>
        </div>
    `;
}

function renderMemoryUsageAnalysis() {
    // Will be implemented if container exists
}

function renderMemoryFragmentation() {
    const container = document.getElementById('memoryFragmentation');
    if (!container) return;
    
    const data = window.analysisData || {};
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    
    if (allocs.length === 0) {
        container.innerHTML = '<div style="text-align: center; color: var(--text-secondary); padding: 40px;">No allocation data available</div>';
        return;
    }
    
    // Calculate fragmentation metrics
    const sizes = allocs.map(a => a.size || 0).filter(s => s > 0);
    const totalMemory = sizes.reduce((sum, size) => sum + size, 0);
    const avgSize = totalMemory / sizes.length;
    const variance = sizes.reduce((sum, size) => sum + Math.pow(size - avgSize, 2), 0) / sizes.length;
    const stdDev = Math.sqrt(variance);
    const fragmentation = Math.min(100, (stdDev / avgSize) * 100);
    
    // Sort allocations by size for visualization
    const sortedAllocs = allocs.slice().sort((a, b) => (a.size || 0) - (b.size || 0));
    
    // Create memory fragmentation visualization
    container.innerHTML = `
        <div style="height: 100%; display: flex; flex-direction: column; gap: 12px; padding: 12px;">
            <!-- Fragmentation Score -->
            <div style="display: flex; justify-content: space-between; align-items: center; padding: 12px; background: var(--bg-secondary); border-radius: 8px;">
                <div>
                    <div style="font-size: 14px; font-weight: 600; color: var(--text-primary);">Fragmentation Level</div>
                    <div style="font-size: 11px; color: var(--text-secondary);">Memory size variance indicator</div>
                </div>
                <div style="text-align: right;">
                    <div style="font-size: 24px; font-weight: 700; color: ${fragmentation > 50 ? 'var(--primary-red)' : fragmentation > 25 ? 'var(--primary-orange)' : 'var(--primary-green)'};">
                        ${fragmentation.toFixed(1)}%
                    </div>
                    <div style="font-size: 10px; color: var(--text-secondary);">
                        ${fragmentation > 50 ? 'High' : fragmentation > 25 ? 'Medium' : 'Low'}
                    </div>
                </div>
            </div>
            
            <!-- Memory Layout Visualization -->
            <div style="flex: 1; background: var(--bg-secondary); border-radius: 8px; padding: 12px;">
                <div style="font-size: 12px; font-weight: 600; color: var(--text-primary); margin-bottom: 8px;">Memory Layout (${allocs.length} allocations)</div>
                <div style="height: 80px; background: var(--bg-primary); border-radius: 6px; padding: 4px; position: relative; overflow: hidden;">
                    <!-- Memory blocks representing allocations -->
                    <div style="display: flex; height: 100%; align-items: end; gap: 1px;">
                        ${sortedAllocs.slice(0, 40).map((alloc, i) => {
                            const size = alloc.size || 0;
                            const maxSize = Math.max(...sizes);
                            const height = Math.max(8, (size / maxSize) * 70);
                            const width = Math.max(2, Math.min(8, 100 / Math.min(40, allocs.length)));
                            
                            let color = '#10b981'; // Green for small
                            if (size > 10240) color = '#ef4444'; // Red for large
                            else if (size > 1024) color = '#f59e0b'; // Orange for medium
                            else if (size > 100) color = '#3b82f6'; // Blue for small-medium
                            
                            return `
                                <div style="width: ${width}px; height: ${height}px; background: ${color}; 
                                           border-radius: 1px; cursor: pointer; transition: all 0.2s; opacity: 0.8;"
                                     title="${alloc.var_name}: ${formatBytes(size)}"
                                     onmouseover="this.style.transform='scaleY(1.2)'; this.style.opacity='1'"
                                     onmouseout="this.style.transform='scaleY(1)'; this.style.opacity='0.8'"
                                     onclick="showAllocationDetail('${alloc.ptr}')"></div>
                            `;
                        }).join('')}
                    </div>
                    
                    <!-- Size legend -->
                    <div style="position: absolute; bottom: 4px; right: 4px; display: flex; gap: 4px; font-size: 8px;">
                        <div style="display: flex; align-items: center; gap: 2px;">
                            <div style="width: 8px; height: 4px; background: #10b981;"></div>
                            <span style="color: var(--text-secondary);">Tiny</span>
                        </div>
                        <div style="display: flex; align-items: center; gap: 2px;">
                            <div style="width: 8px; height: 4px; background: #3b82f6;"></div>
                            <span style="color: var(--text-secondary);">Small</span>
                        </div>
                        <div style="display: flex; align-items: center; gap: 2px;">
                            <div style="width: 8px; height: 4px; background: #f59e0b;"></div>
                            <span style="color: var(--text-secondary);">Medium</span>
                        </div>
                        <div style="display: flex; align-items: center; gap: 2px;">
                            <div style="width: 8px; height: 4px; background: #ef4444;"></div>
                            <span style="color: var(--text-secondary);">Large</span>
                        </div>
                    </div>
                </div>
                
                <!-- Fragmentation Analysis -->
                <div style="margin-top: 8px; display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; font-size: 11px;">
                    <div style="text-align: center; padding: 6px; background: var(--bg-primary); border-radius: 4px;">
                        <div style="font-weight: 600; color: var(--text-primary);">${formatBytes(avgSize)}</div>
                        <div style="color: var(--text-secondary);">Avg Size</div>
                    </div>
                    <div style="text-align: center; padding: 6px; background: var(--bg-primary); border-radius: 4px;">
                        <div style="font-weight: 600; color: var(--text-primary);">${formatBytes(Math.max(...sizes))}</div>
                        <div style="color: var(--text-secondary);">Max Size</div>
                    </div>
                    <div style="text-align: center; padding: 6px; background: var(--bg-primary); border-radius: 4px;">
                        <div style="font-weight: 600; color: var(--text-primary);">${formatBytes(Math.min(...sizes))}</div>
                        <div style="color: var(--text-secondary);">Min Size</div>
                    </div>
                </div>
            </div>
        </div>
    `;
}

function renderMemoryGrowthTrends() {
    const container = document.getElementById('growth');
    if (!container) return;
    
    const data = window.analysisData || {};
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    if (allocs.length === 0) {
        container.innerHTML = '<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-secondary);">No growth data available</div>';
        return;
    }
    
    // Create a proper growth chart using Chart.js
    const canvas = document.createElement('canvas');
    canvas.style.width = '100%';
    canvas.style.height = '100%';
    container.innerHTML = '';
    container.appendChild(canvas);
    
    const sorted = allocs.slice().sort((a,b) => (a.timestamp_alloc||0) - (b.timestamp_alloc||0));
    let cumulative = 0;
    const points = [];
    
    for (let i = 0; i < Math.min(sorted.length, 30); i++) {
        cumulative += sorted[i].size || 0;
        points.push({ x: i, y: cumulative });
    }
    
    if (points.length > 1 && window.Chart) {
        new Chart(canvas, {
            type: 'line',
            data: {
                labels: points.map((_, i) => `T${i}`),
                datasets: [{
                    label: 'Memory Growth',
                    data: points.map(p => p.y),
                    borderColor: '#059669',
                    backgroundColor: 'rgba(5, 150, 105, 0.1)',
                    fill: true,
                    tension: 0.3,
                    pointRadius: 3,
                    pointHoverRadius: 5
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: { display: false }
                },
                scales: {
                    x: {
                        title: {
                            display: true,
                            text: 'Time Steps'
                        }
                    },
                    y: { 
                        beginAtZero: true,
                        title: {
                            display: true,
                            text: 'Cumulative Memory'
                        },
                        ticks: {
                            callback: function(value) {
                                return formatBytes(value);
                            }
                        }
                    }
                }
            }
        });
    }
}

function setupLifecycle() {
    // Lifecycle setup functionality
}

function populateUnsafeTable() {
    const data = window.analysisData || {};
    const root = data.unsafe_ffi || {};
    const ops = root.enhanced_ffi_data || root.unsafe_operations || root.allocations || [];
    const unsafeTable = document.getElementById('unsafeTable');
    if (!unsafeTable) return;
    
    unsafeTable.innerHTML = (ops || []).slice(0, 50).map(op => {
        const riskLevel = op.risk_level || ((op.safety_violations||[]).length > 2 ? 'High' : 
                         ((op.safety_violations||[]).length > 0 ? 'Medium' : 'Low'));
        
        const riskText = riskLevel === 'High' ? 'High Risk' : (riskLevel === 'Medium' ? 'Medium Risk' : 'Low Risk');
        const riskClass = riskLevel === 'High' ? 'risk-high' : (riskLevel === 'Medium' ? 'risk-medium' : 'risk-low');
        
        return `<tr>
            <td>${op.location || op.var_name || 'Unknown'}</td>
            <td>${op.operation_type || op.type_name || 'Unknown'}</td>
            <td><span class="status-badge ${riskClass}">${riskText}</span></td>
        </tr>`;
    }).join('');
}

function renderVariableGraph() {
    const container = document.getElementById('graph');
    if (!container) return;
    
    const data = window.analysisData || {};
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    if (allocs.length === 0) {
        container.innerHTML = '<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-secondary);">No relationship data available</div>';
        return;
    }
    
    // Enhanced variable relationship graph with pan/zoom and drag functionality
    const nodes = allocs.slice(0, 30).map((a, i) => ({
        id: i,
        name: a.var_name || `var_${i}`,
        type: a.type_name || 'unknown',
        size: a.size || 0,
        status: a.is_leaked ? 'leaked' : (a.timestamp_dealloc ? 'freed' : 'active'),
        ptr: a.ptr || 'unknown',
        timestamp_alloc: a.timestamp_alloc || 0,
        timestamp_dealloc: a.timestamp_dealloc || null,
        x: 200 + (i % 6) * 120 + Math.random() * 40,
        y: 200 + Math.floor(i / 6) * 120 + Math.random() * 40,
        isDragging: false
    }));
    
    // Create enhanced links with copy/clone/move relationships
    const links = [];
    for (let i = 0; i < nodes.length; i++) {
        for (let j = i + 1; j < nodes.length; j++) {
            const nodeA = nodes[i];
            const nodeB = nodes[j];
            const allocA = allocs[i];
            const allocB = allocs[j];
            
            // Clone relationship (based on clone_info)
            if (allocA.clone_info?.clone_count > 0 && allocB.clone_info?.is_clone) {
                links.push({ 
                    source: i, target: j, type: 'clone', 
                    color: '#f59e0b', strokeWidth: 3, dashArray: '5,5'
                });
            }
            // Copy relationship (same type, similar size)
            else if (nodeA.type === nodeB.type && 
                     Math.abs(nodeA.size - nodeB.size) < Math.max(nodeA.size, nodeB.size) * 0.1) {
                links.push({ 
                    source: i, target: j, type: 'copy', 
                    color: '#06b6d4', strokeWidth: 2, dashArray: 'none'
                });
            }
            // Move relationship (same type, different timestamps)
            else if (nodeA.type === nodeB.type && 
                     Math.abs(nodeA.timestamp_alloc - nodeB.timestamp_alloc) > 1000000) {
                links.push({ 
                    source: i, target: j, type: 'move', 
                    color: '#8b5cf6', strokeWidth: 2, dashArray: '10,5'
                });
            }
            // General relationship (same type prefix)
            else if (nodeA.type === nodeB.type || 
                     nodeA.name.startsWith(nodeB.name.substring(0, 3))) {
                links.push({ 
                    source: i, target: j, type: 'related', 
                    color: 'var(--border-light)', strokeWidth: 1, dashArray: 'none'
                });
            }
        }
    }
    
    const width = 1200;  // Larger virtual canvas
    const height = 800;
    const viewWidth = container.offsetWidth || 500;
    const viewHeight = 400;
    
    // Create SVG with pan/zoom capabilities and legend
    let html = `
        <div style="position: relative; width: 100%; height: ${viewHeight}px; overflow: hidden; border: 1px solid var(--border-light); border-radius: 8px;">
            <!-- Relationship Legend -->
            <div style="position: absolute; top: 10px; right: 10px; background: var(--bg-primary); padding: 12px; border-radius: 8px; font-size: 11px; z-index: 10; border: 1px solid var(--border-light); box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
                <div style="font-weight: bold; margin-bottom: 8px; color: var(--text-primary); font-size: 12px;">Variable Relationships</div>
                <div style="display: flex; align-items: center; margin-bottom: 4px;">
                    <svg width="20" height="3" style="margin-right: 8px;">
                        <line x1="0" y1="1.5" x2="20" y2="1.5" stroke='#06b6d4' stroke-width="2"/>
                    </svg>
                    <span style="color: var(--text-secondary);">Copy</span>
                </div>
                <div style="display: flex; align-items: center; margin-bottom: 4px;">
                    <svg width="20" height="3" style="margin-right: 8px;">
                        <line x1="0" y1="1.5" x2="20" y2="1.5" stroke='#f59e0b' stroke-width="3" stroke-dasharray="5,5"/>
                    </svg>
                    <span style="color: var(--text-secondary);">Clone</span>
                </div>
                <div style="display: flex; align-items: center; margin-bottom: 4px;">
                    <svg width="20" height="3" style="margin-right: 8px;">
                        <line x1="0" y1="1.5" x2="20" y2="1.5" stroke='#8b5cf6' stroke-width="2" stroke-dasharray="10,5"/>
                    </svg>
                    <span style="color: var(--text-secondary);">Move</span>
                </div>
                <div style="display: flex; align-items: center;">
                    <svg width="20" height="3" style="margin-right: 8px;">
                        <line x1="0" y1="1.5" x2="20" y2="1.5" stroke='#64748b' stroke-width="1"/>
                    </svg>
                    <span style="color: var(--text-secondary);">Related</span>
                </div>
            </div>
            
            <svg id="graph-svg" width="100%" height="100%" viewBox="0 0 ${viewWidth} ${viewHeight}" style="background: var(--bg-secondary); cursor: grab;">
                <defs>
                    <filter id="node-glow">
                        <feGaussianBlur stdDeviation="3" result="coloredBlur"/>
                        <feMerge>
                            <feMergeNode in="coloredBlur"/>
                            <feMergeNode in="SourceGraphic"/>
                        </feMerge>
                    </filter>
                    <marker id="arrow" viewBox="0 0 10 10" refX="8" refY="3"
                            markerWidth="6" markerHeight="6" orient="auto">
                        <path d="M0,0 L0,6 L9,3 z" fill="var(--border-light)" opacity="0.6"/>
                    </marker>
                </defs>
                <g id="graph-container" transform="translate(0,0) scale(1)">
                    <g id="links-group">`;
    
    // Draw enhanced links with relationship types
    links.forEach((link, linkIndex) => {
        const source = nodes[link.source];
        const target = nodes[link.target];
        const strokeDashArray = link.dashArray !== 'none' ? link.dashArray : '';
        
        html += `
            <line id="link-${linkIndex}" x1="${source.x}" y1="${source.y}" x2="${target.x}" y2="${target.y}" 
                  stroke="${link.color}" stroke-width="${link.strokeWidth}" opacity="0.8"
                  stroke-dasharray="${strokeDashArray}">
                <animate attributeName="opacity" values="0.8;1;0.8" dur="3s" repeatCount="indefinite"/>
            </line>`;
        
        // Add relationship label for special types
        const midX = (source.x + target.x) / 2;
        const midY = (source.y + target.y) / 2;
        if (link.type !== 'related') {
            html += `
            <text x="${midX}" y="${midY - 5}" text-anchor="middle" font-size="8" 
                  fill="${link.color}" font-weight="bold" opacity="0.9">
                ${link.type.toUpperCase()}
            </text>`;
        }
    });
    
    html += '</g><g id="nodes-group">';
    
    // Draw nodes
    nodes.forEach((node, nodeIndex) => {
        const radius = Math.max(12, Math.min(30, Math.log(node.size + 1) * 4));
        let color = '#6b7280'; // default
        
        if (node.type.includes('String')) color = '#fbbf24';
        else if (node.type.includes('Vec')) color = '#3b82f6';
        else if (node.type.includes('Box') || node.type.includes('Rc')) color = '#8b5cf6';
        else if (node.type.includes('HashMap')) color = '#10b981';
        else if (node.type.includes('Arc')) color = '#f59e0b';
        
        if (node.status === 'leaked') color = '#dc2626';
        else if (node.status === 'freed') color = '#9ca3af';
        
        html += `
            <circle 
                id="node-${nodeIndex}"
                cx="${node.x}" 
                cy="${node.y}" 
                r="${radius}" 
                fill="${color}" 
                stroke="white" 
                stroke-width="3" 
                filter="url(#node-glow)"
                style="cursor: grab;"
                class="graph-node"
                data-index="${nodeIndex}"
                data-name="${node.name}"
                data-type="${node.type}"
                data-size="${node.size}"
                data-status="${node.status}"
                data-ptr="${node.ptr}"
                data-alloc="${node.timestamp_alloc}"
                data-dealloc="${node.timestamp_dealloc || 'null'}"
            />
            <text 
                id="text-${nodeIndex}"
                x="${node.x}" 
                y="${node.y + radius + 20}" 
                text-anchor="middle" 
                font-size="12" 
                font-weight="600"
                fill="var(--text-primary)"
                style="pointer-events: none;"
            >${node.name.length > 12 ? node.name.substring(0, 10) + '...' : node.name}</text>
        `;
    });
    
    html += `
                </g>
            </g>
        </svg>
        
        <!-- Controls -->
        <div style="position: absolute; top: 10px; right: 10px; display: flex; gap: 8px;">
            <button id="zoom-in" style="background: var(--primary-blue); color: white; border: none; padding: 8px 12px; border-radius: 6px; cursor: pointer; font-size: 14px;">
                <i class="fa fa-plus"></i>
            </button>
            <button id="zoom-out" style="background: var(--primary-blue); color: white; border: none; padding: 8px 12px; border-radius: 6px; cursor: pointer; font-size: 14px;">
                <i class="fa fa-minus"></i>
            </button>
            <button id="reset-view" style="background: var(--primary-green); color: white; border: none; padding: 8px 12px; border-radius: 6px; cursor: pointer; font-size: 14px;">
                <i class="fa fa-home"></i>
            </button>
        </div>
        
        <!-- Node detail panel -->
        <div id="node-detail-panel" style="
            position: absolute;
            background: var(--bg-primary);
            border: 1px solid var(--border-light);
            border-radius: 8px;
            padding: 12px;
            width: 280px;
            box-shadow: 0 10px 25px rgba(0,0,0,0.1);
            z-index: 1000;
            font-size: 0.875rem;
            display: none;
            backdrop-filter: blur(10px);
        ">
            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
                <h4 id="detail-title" style="margin: 0; font-size: 1rem; font-weight: 600;"></h4>
                <button onclick="hideNodeDetails()" style="background: none; border: none; font-size: 16px; cursor: pointer; color: var(--text-secondary);">ร—</button>
            </div>
            <div id="detail-content"></div>
        </div>
        
        <!-- Legend -->
        <div style="display: flex; gap: 12px; margin-top: 12px; font-size: 0.75rem; flex-wrap: wrap;">
            <div style="display: flex; align-items: center; gap: 4px;">
                <div style="width: 10px; height: 10px; background: #fbbf24; border-radius: 50%;"></div>
                <span>String</span>
            </div>
            <div style="display: flex; align-items: center; gap: 4px;">
                <div style="width: 10px; height: 10px; background: #3b82f6; border-radius: 50%;"></div>
                <span>Vec</span>
            </div>
            <div style="display: flex; align-items: center; gap: 4px;">
                <div style="width: 10px; height: 10px; background: #8b5cf6; border-radius: 50%;"></div>
                <span>Smart Ptr</span>
            </div>
            <div style="display: flex; align-items: center; gap: 4px;">
                <div style="width: 10px; height: 10px; background: #dc2626; border-radius: 50%;"></div>
                <span>Leaked</span>
            </div>
            <div style="display: flex; align-items: center; gap: 4px;">
                <div style="width: 10px; height: 10px; background: #9ca3af; border-radius: 50%;"></div>
                <span>Freed</span>
            </div>
        </div>
    </div>
    `;
    
    container.innerHTML = html;
    
    // Store nodes and links data for interaction
    window.graphNodes = nodes;
    window.graphLinks = links;
    window.graphTransform = { x: 0, y: 0, scale: 1 };
    
    // Add pan/zoom and drag functionality
    setTimeout(() => {
        setupGraphInteractions();
        setupPanZoom();
    }, 100);
}

// Graph interaction functions
function setupGraphInteractions() {
    const svg = document.getElementById('graph-svg');
    const nodeElements = document.querySelectorAll('.graph-node');
    
    let draggedNode = null;
    let isDragging = false;
    let startX, startY;
    
    nodeElements.forEach(node => {
        // Mouse events for drag
        node.addEventListener('mousedown', function(e) {
            e.preventDefault();
            draggedNode = this;
            isDragging = false;
            startX = e.clientX;
            startY = e.clientY;
            this.style.cursor = 'grabbing';
            svg.style.cursor = 'grabbing';
        });
        
        // Click event for details
        node.addEventListener('click', function(e) {
            if (!isDragging) {
                showNodeDetails(this);
            }
        });
        
        // Hover effects
        node.addEventListener('mouseover', function() {
            if (!draggedNode) {
                const currentRadius = parseInt(this.getAttribute('r'));
                this.setAttribute('r', Math.round(currentRadius * 1.2));
            }
        });
        
        node.addEventListener('mouseout', function() {
            if (!draggedNode) {
                const currentRadius = parseInt(this.getAttribute('r'));
                this.setAttribute('r', Math.round(currentRadius / 1.2));
            }
        });
    });
    
    // Global mouse events for dragging
    document.addEventListener('mousemove', function(e) {
        if (draggedNode) {
            e.preventDefault();
            const deltaX = e.clientX - startX;
            const deltaY = e.clientY - startY;
            
            if (Math.abs(deltaX) > 3 || Math.abs(deltaY) > 3) {
                isDragging = true;
            }
            
            if (isDragging) {
                const rect = svg.getBoundingClientRect();
                const svgX = Math.max(20, Math.min(rect.width - 20, e.clientX - rect.left));
                const svgY = Math.max(20, Math.min(rect.height - 20, e.clientY - rect.top));
                
                // Update node position
                draggedNode.setAttribute('cx', svgX);
                draggedNode.setAttribute('cy', svgY);
                
                // Update text position
                const nodeIndex = draggedNode.getAttribute('data-index');
                const textElement = document.getElementById(`text-${nodeIndex}`);
                if (textElement) {
                    textElement.setAttribute('x', svgX);
                    textElement.setAttribute('y', svgY + parseInt(draggedNode.getAttribute('r')) + 15);
                }
                
                // Update connected links
                updateConnectedLinks(parseInt(nodeIndex), svgX, svgY);
                
                // Update stored node position
                if (window.graphNodes && window.graphNodes[nodeIndex]) {
                    window.graphNodes[nodeIndex].x = svgX;
                    window.graphNodes[nodeIndex].y = svgY;
                }
            }
        }
    });
    
    document.addEventListener('mouseup', function(e) {
        if (draggedNode) {
            draggedNode.style.cursor = 'grab';
            svg.style.cursor = 'grab';
            
            // Reset hover effect
            const originalRadius = parseInt(draggedNode.getAttribute('r'));
            draggedNode.setAttribute('r', originalRadius);
            
            draggedNode = null;
            setTimeout(() => { isDragging = false; }, 100);
        }
    });
}

function updateConnectedLinks(nodeIndex, newX, newY) {
    if (!window.graphLinks) return;
    
    window.graphLinks.forEach((link, linkIndex) => {
        const linkElement = document.getElementById(`link-${linkIndex}`);
        if (!linkElement) return;
        
        if (link.source === nodeIndex) {
            linkElement.setAttribute('x1', newX);
            linkElement.setAttribute('y1', newY);
        }
        if (link.target === nodeIndex) {
            linkElement.setAttribute('x2', newX);
            linkElement.setAttribute('y2', newY);
        }
    });
}

function showNodeDetails(nodeElement) {
    const panel = document.getElementById('node-detail-panel');
    const title = document.getElementById('detail-title');
    const content = document.getElementById('detail-content');
    
    if (!panel || !title || !content) return;
    
    const name = nodeElement.getAttribute('data-name');
    const type = nodeElement.getAttribute('data-type');
    const size = parseInt(nodeElement.getAttribute('data-size'));
    const status = nodeElement.getAttribute('data-status');
    const ptr = nodeElement.getAttribute('data-ptr');
    const alloc = nodeElement.getAttribute('data-alloc');
    const dealloc = nodeElement.getAttribute('data-dealloc');
    
    title.textContent = name;
    
    const lifetime = dealloc !== 'null' ? parseInt(dealloc) - parseInt(alloc) : 'Active';
    
    content.innerHTML = `
        <div style="margin-bottom: 8px;">
            <strong>Type:</strong> ${formatTypeName(type)}
        </div>
        <div style="margin-bottom: 8px;">
            <strong>Size:</strong> ${formatBytes(size)}
        </div>
        <div style="margin-bottom: 8px;">
            <strong>Status:</strong> <span style="color: ${status === 'leaked' ? '#dc2626' : status === 'freed' ? '#6b7280' : '#059669'};">${status.charAt(0).toUpperCase() + status.slice(1)}</span>
        </div>
        <div style="margin-bottom: 8px;">
            <strong>Pointer:</strong> <code style="font-size: 0.8rem; background: var(--bg-secondary); padding: 2px 4px; border-radius: 3px;">${ptr}</code>
        </div>
        <div style="margin-bottom: 8px;">
            <strong>Allocated:</strong> ${alloc}ms
        </div>
        <div style="margin-bottom: 8px;">
            <strong>Lifetime:</strong> ${typeof lifetime === 'number' ? lifetime + 'ms' : lifetime}
        </div>
    `;
    
    // Position panel near the node
    const rect = nodeElement.getBoundingClientRect();
    const containerRect = nodeElement.closest('#graph').getBoundingClientRect();
    
    panel.style.left = Math.min(rect.left - containerRect.left + 30, containerRect.width - 300) + 'px';
    panel.style.top = Math.max(rect.top - containerRect.top - 50, 10) + 'px';
    panel.style.display = 'block';
}

function hideNodeDetails() {
    const panel = document.getElementById('node-detail-panel');
    if (panel) {
        panel.style.display = 'none';
    }
}

// Pan and zoom functionality for the graph
function setupPanZoom() {
    const svg = document.getElementById('graph-svg');
    const container = document.getElementById('graph-container');
    const zoomInBtn = document.getElementById('zoom-in');
    const zoomOutBtn = document.getElementById('zoom-out');
    const resetBtn = document.getElementById('reset-view');
    
    if (!svg || !container) return;
    
    let isPanning = false;
    let startX, startY;
    let transform = window.graphTransform;
    
    // Zoom functions
    function updateTransform() {
        container.setAttribute('transform', `translate(${transform.x},${transform.y}) scale(${transform.scale})`);
    }
    
    function zoom(factor, centerX = 0, centerY = 0) {
        const newScale = Math.max(0.1, Math.min(3, transform.scale * factor));
        
        // Zoom towards center point
        const dx = centerX - transform.x;
        const dy = centerY - transform.y;
        
        transform.x = centerX - dx * (newScale / transform.scale);
        transform.y = centerY - dy * (newScale / transform.scale);
        transform.scale = newScale;
        
        updateTransform();
    }
    
    // Button controls
    if (zoomInBtn) {
        zoomInBtn.addEventListener('click', () => {
            const rect = svg.getBoundingClientRect();
            zoom(1.2, rect.width / 2, rect.height / 2);
        });
    }
    
    if (zoomOutBtn) {
        zoomOutBtn.addEventListener('click', () => {
            const rect = svg.getBoundingClientRect();
            zoom(0.8, rect.width / 2, rect.height / 2);
        });
    }
    
    if (resetBtn) {
        resetBtn.addEventListener('click', () => {
            transform.x = 0;
            transform.y = 0;
            transform.scale = 1;
            updateTransform();
        });
    }
    
    // Mouse wheel zoom
    svg.addEventListener('wheel', function(e) {
        e.preventDefault();
        const rect = svg.getBoundingClientRect();
        const mouseX = e.clientX - rect.left;
        const mouseY = e.clientY - rect.top;
        
        const zoomFactor = e.deltaY > 0 ? 0.9 : 1.1;
        zoom(zoomFactor, mouseX, mouseY);
    });
    
    // Pan functionality
    svg.addEventListener('mousedown', function(e) {
        if (e.target === svg || e.target === container) {
            isPanning = true;
            startX = e.clientX - transform.x;
            startY = e.clientY - transform.y;
            svg.style.cursor = 'grabbing';
        }
    });
    
    document.addEventListener('mousemove', function(e) {
        if (isPanning) {
            e.preventDefault();
            transform.x = e.clientX - startX;
            transform.y = e.clientY - startY;
            updateTransform();
        }
    });
    
    document.addEventListener('mouseup', function() {
        if (isPanning) {
            isPanning = false;
            svg.style.cursor = 'grab';
        }
    });
}

// Lifecycle toggle functionality
function setupLifecycleToggle() {
    // Hard reset any previous click bindings by cloning the button
    const oldBtn = document.getElementById('toggle-lifecycle');
    if (oldBtn) {
        const cloned = oldBtn.cloneNode(true);
        oldBtn.parentNode.replaceChild(cloned, oldBtn);
    }

    const toggleBtn = document.getElementById('toggle-lifecycle');
    if (!toggleBtn) return;
    
    const lifeContainer = document.getElementById('lifetimeVisualization');
    
    let isExpanded = false;
    
    toggleBtn.addEventListener('click', function() {
        const container = document.getElementById('lifetimeVisualization');
        if (!container) return;
        
        const data = window.analysisData || {};
        const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
        
        if (allocs.length === 0) {
            container.innerHTML = '<div style="padding: 20px; text-align: center; color: var(--text-secondary);">No lifecycle data available</div>';
            return;
        }
        
        const icon = toggleBtn.querySelector('i');
        const text = toggleBtn.querySelector('span');
        
        if (!isExpanded) {
            renderFullLifecycleTimeline(allocs);
            icon.className = 'fa fa-chevron-up';
            text.textContent = 'Show Less';
            isExpanded = true;
        } else {
            renderLimitedLifecycleTimeline(allocs);
            icon.className = 'fa fa-chevron-down';
            text.textContent = 'Show All';
            isExpanded = false;
        }
        // Ensure the container scrolls to top after toggle for visual confirmation
        if (lifeContainer) { lifeContainer.scrollTop = 0; }
    });
}

function renderLimitedLifecycleTimeline(allocs) {
    const container = document.getElementById('lifetimeVisualization');
    if (!container) return;
    
    // Create timeline visualization (limited to 20)
    const maxTime = Math.max(...allocs.map(a => a.timestamp_dealloc || a.timestamp_alloc || 0));
    const minTime = Math.min(...allocs.map(a => a.timestamp_alloc || 0));
    const timeRange = maxTime - minTime || 1;
    
    let html = '<div style="padding: 16px; max-height: 300px; overflow-y: auto;">';
    
    allocs.slice(0, 20).forEach((alloc, index) => {
        const startTime = alloc.timestamp_alloc || 0;
        const endTime = alloc.timestamp_dealloc || maxTime;
        const startPercent = ((startTime - minTime) / timeRange) * 100;
        const widthPercent = ((endTime - startTime) / timeRange) * 100;
        const isActive = !alloc.timestamp_dealloc;
        
        html += `
            <div style="margin-bottom: 8px;">
                <div style="display: flex; justify-content: space-between; margin-bottom: 4px; font-size: 0.8rem;">
                    <span style="font-weight: 600;">${alloc.var_name || `var_${index}`}</span>
                    <span style="color: var(--text-secondary);">${formatBytes(alloc.size || 0)}</span>
                </div>
                <div style="position: relative; background: var(--bg-secondary); height: 8px; border-radius: 4px;">
                    <div style="
                        position: absolute;
                        left: ${startPercent}%;
                        width: ${widthPercent}%;
                        height: 100%;
                        background: ${isActive ? 'linear-gradient(to right, #059669, #34d399)' : 'linear-gradient(to right, #2563eb, #60a5fa)'};
                        border-radius: 4px;
                        ${isActive ? 'animation: pulse 2s infinite;' : ''}
                    " title="Lifetime: ${endTime - startTime}ms"></div>
                </div>
            </div>
        `;
    });
    
    html += '</div>';
    
    // Add CSS for pulse animation
    html += `
        <style>
            @keyframes pulse {
                0%, 100% { opacity: 1; }
                50% { opacity: 0.7; }
            }
        </style>
    `;
    
    container.innerHTML = html;
}

function renderFullLifecycleTimeline(allocs) {
    const container = document.getElementById('lifetimeVisualization');
    if (!container) return;
    
    // Create full timeline visualization
    const maxTime = Math.max(...allocs.map(a => a.timestamp_dealloc || a.timestamp_alloc || 0));
    const minTime = Math.min(...allocs.map(a => a.timestamp_alloc || 0));
    const timeRange = maxTime - minTime || 1;
    
    let html = '<div style="padding: 16px; max-height: 600px; overflow-y: auto;">';
    
    // Add timeline header
    html += `
        <div style="margin-bottom: 16px; padding: 12px; background: var(--bg-secondary); border-radius: 8px;">
            <div style="font-weight: 600; margin-bottom: 8px;">Full Lifecycle Timeline</div>
            <div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; font-size: 0.8rem;">
                <div>
                    <div style="color: var(--text-secondary);">Total Variables</div>
                    <div style="font-weight: 600;">${allocs.length}</div>
                </div>
                <div>
                    <div style="color: var(--text-secondary);">Active</div>
                    <div style="font-weight: 600; color: #059669;">${allocs.filter(a => !a.timestamp_dealloc).length}</div>
                </div>
                <div>
                    <div style="color: var(--text-secondary);">Freed</div>
                    <div style="font-weight: 600; color: #2563eb;">${allocs.filter(a => a.timestamp_dealloc && !a.is_leaked).length}</div>
                </div>
                <div>
                    <div style="color: var(--text-secondary);">Leaked</div>
                    <div style="font-weight: 600; color: #dc2626;">${allocs.filter(a => a.is_leaked).length}</div>
                </div>
            </div>
        </div>
    `;
    
    allocs.forEach((alloc, index) => {
        const startTime = alloc.timestamp_alloc || 0;
        const endTime = alloc.timestamp_dealloc || maxTime;
        const startPercent = ((startTime - minTime) / timeRange) * 100;
        const widthPercent = ((endTime - startTime) / timeRange) * 100;
        const isActive = !alloc.timestamp_dealloc;
        const isLeaked = alloc.is_leaked;
        
        let barColor = 'linear-gradient(to right, #2563eb, #60a5fa)'; // freed
        if (isActive) barColor = 'linear-gradient(to right, #059669, #34d399)'; // active
        if (isLeaked) barColor = 'linear-gradient(to right, #dc2626, #f87171)'; // leaked
        
        html += `
            <div style="margin-bottom: 6px;">
                <div style="display: flex; justify-content: space-between; margin-bottom: 3px; font-size: 0.75rem;">
                    <span style="font-weight: 600;">${alloc.var_name || `var_${index}`}</span>
                    <div style="display: flex; gap: 8px;">
                        <span style="color: var(--text-secondary);">${formatTypeName(alloc.type_name || 'Unknown')}</span>
                        <span style="color: var(--text-secondary);">${formatBytes(alloc.size || 0)}</span>
                    </div>
                </div>
                <div style="position: relative; background: var(--bg-secondary); height: 6px; border-radius: 3px;">
                    <div style="
                        position: absolute;
                        left: ${startPercent}%;
                        width: ${widthPercent}%;
                        height: 100%;
                        background: ${barColor};
                        border-radius: 3px;
                        ${isActive ? 'animation: pulse 2s infinite;' : ''}
                    " title="Lifetime: ${endTime - startTime}ms | Status: ${isLeaked ? 'Leaked' : isActive ? 'Active' : 'Freed'}"></div>
                </div>
            </div>
        `;
    });
    
    html += '</div>';
    
    // Add CSS for pulse animation
    html += `
        <style>
            @keyframes pulse {
                0%, 100% { opacity: 1; }
                50% { opacity: 0.7; }
            }
        </style>
    `;
    
    container.innerHTML = html;
}

function setupLifecycleVisualization() {
    const container = document.getElementById('lifetimeVisualization');
    if (!container) return;
    
    const data = window.analysisData || {};
    const allocs = (data.memory_analysis && data.memory_analysis.allocations) || [];
    
    if (allocs.length === 0) {
        container.innerHTML = '<div style="padding: 20px; text-align: center; color: var(--text-secondary);">No lifecycle data available</div>';
        return;
    }
    
    // Create timeline visualization
    const maxTime = Math.max(...allocs.map(a => a.timestamp_dealloc || a.timestamp_alloc || 0));
    const minTime = Math.min(...allocs.map(a => a.timestamp_alloc || 0));
    const timeRange = maxTime - minTime || 1;
    
    let html = '<div style="padding: 16px; max-height: 300px; overflow-y: auto;">';
    
    allocs.slice(0, 20).forEach((alloc, index) => {
        const startTime = alloc.timestamp_alloc || 0;
        const endTime = alloc.timestamp_dealloc || maxTime;
        const startPercent = ((startTime - minTime) / timeRange) * 100;
        const widthPercent = ((endTime - startTime) / timeRange) * 100;
        const isActive = !alloc.timestamp_dealloc;
        
        html += `
            <div style="margin-bottom: 8px;">
                <div style="display: flex; justify-content: space-between; margin-bottom: 4px; font-size: 0.8rem;">
                    <span style="font-weight: 600;">${alloc.var_name || `var_${index}`}</span>
                    <span style="color: var(--text-secondary);">${formatBytes(alloc.size || 0)}</span>
                </div>
                <div style="position: relative; background: var(--bg-secondary); height: 8px; border-radius: 4px;">
                    <div style="
                        position: absolute;
                        left: ${startPercent}%;
                        width: ${widthPercent}%;
                        height: 100%;
                        background: ${isActive ? 'linear-gradient(to right, #059669, #34d399)' : 'linear-gradient(to right, #2563eb, #60a5fa)'};
                        border-radius: 4px;
                        ${isActive ? 'animation: pulse 2s infinite;' : ''}
                    " title="Lifetime: ${endTime - startTime}ms"></div>
                </div>
            </div>
        `;
    });
    
    html += '</div>';
    
    // Add CSS for pulse animation
    html += `
        <style>
            @keyframes pulse {
                0%, 100% { opacity: 1; }
                50% { opacity: 0.7; }
            }
        </style>
    `;
    
    container.innerHTML = html;
}

function initFFIVisualization() {
    // Additional FFI initialization if needed
    renderFFI();
}

// Complete JSON Data Explorer
function initCompleteJSONExplorer() {
    const container = document.getElementById('jsonDataExplorer');
    const expandBtn = document.getElementById('expand-all-json');
    const collapseBtn = document.getElementById('collapse-all-json');
    
    if (!container) return;
    
    const data = window.analysisData || {};
    
    if (Object.keys(data).length === 0) {
        container.innerHTML = '<div style="text-align: center; color: var(--text-secondary); padding: 40px;">No JSON data available</div>';
        return;
    }
    
    // Generate comprehensive JSON explorer
    let html = '<div class="json-explorer">';
    
    // Add data summary
    html += `
        <div style="background: var(--bg-primary); border: 1px solid var(--border-light); border-radius: 8px; padding: 16px; margin-bottom: 16px;">
            <h3 style="margin: 0 0 12px 0; color: var(--text-primary);">Data Summary</h3>
            <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px;">
                ${Object.keys(data).map(key => {
                    const value = data[key];
                    let itemCount = 'N/A';
                    let dataType = typeof value;
                    
                    if (Array.isArray(value)) {
                        itemCount = value.length + ' items';
                        dataType = 'Array';
                    } else if (value && typeof value === 'object') {
                        itemCount = Object.keys(value).length + ' properties';
                        dataType = 'Object';
                    }
                    
                    return `
                        <div style="background: var(--bg-secondary); padding: 12px; border-radius: 6px;">
                            <div style="font-weight: 600; color: var(--text-primary);">${key}</div>
                            <div style="font-size: 0.8rem; color: var(--text-secondary);">${dataType}</div>
                            <div style="font-size: 0.8rem; color: var(--text-secondary);">${itemCount}</div>
                        </div>
                    `;
                }).join('')}
            </div>
        </div>
    `;
    
    // Generate expandable JSON tree for each top-level key
    Object.keys(data).forEach((key, index) => {
        const value = data[key];
        html += createJSONSection(key, value, index);
    });
    
    html += '</div>';
    container.innerHTML = html;
    
    // Setup expand/collapse functionality
    if (expandBtn) {
        expandBtn.addEventListener('click', () => {
            const details = container.querySelectorAll('details');
            details.forEach(detail => detail.open = true);
        });
    }
    
    if (collapseBtn) {
        collapseBtn.addEventListener('click', () => {
            const details = container.querySelectorAll('details');
            details.forEach(detail => detail.open = false);
        });
    }
}

function createJSONSection(key, value, index) {
    const isOpen = index < 3; // Open first 3 sections by default
    
    let html = `
        <details class="json-section" ${isOpen ? 'open' : ''} style="
            border: 1px solid var(--border-light); 
            border-radius: 8px; 
            margin-bottom: 12px; 
            background: var(--bg-primary);
        ">
            <summary style="
                cursor: pointer; 
                padding: 12px 16px; 
                font-weight: 600; 
                color: var(--text-primary); 
                background: var(--bg-secondary);
                border-radius: 8px 8px 0 0;
                user-select: none;
            ">
                <i class="fa fa-chevron-right" style="margin-right: 8px; transition: transform 0.2s;"></i>
                ${key}
                <span style="font-weight: normal; color: var(--text-secondary); margin-left: 8px;">
                    ${getDataTypeInfo(value)}
                </span>
            </summary>
            <div style="padding: 16px;">
    `;
    
    if (Array.isArray(value)) {
        html += createArrayView(value, key);
    } else if (value && typeof value === 'object') {
        html += createObjectView(value, key);
    } else {
        html += `<pre style="margin: 0; color: var(--text-primary); font-size: 0.9rem;">${JSON.stringify(value, null, 2)}</pre>`;
    }
    
    html += '</div></details>';
    return html;
}

function createArrayView(array, parentKey) {
    if (array.length === 0) {
        return '<div style="color: var(--text-secondary); font-style: italic;">Empty array</div>';
    }
    
    let html = `
        <div style="margin-bottom: 12px;">
            <strong>Array with ${array.length} items</strong>
            ${array.length > 10 ? `<span style="color: var(--text-secondary);"> (showing first 10)</span>` : ''}
        </div>
    `;
    
    // Show first 10 items
    const itemsToShow = array.slice(0, 10);
    
    itemsToShow.forEach((item, index) => {
        html += `
            <details style="margin-bottom: 8px; border: 1px solid var(--border-light); border-radius: 6px;">
                <summary style="cursor: pointer; padding: 8px 12px; background: var(--bg-secondary); font-size: 0.9rem;">
                    [${index}] ${getDataTypeInfo(item)}
                </summary>
                <div style="padding: 12px;">
                    <pre style="margin: 0; font-size: 0.8rem; color: var(--text-primary); max-height: 300px; overflow: auto;">${JSON.stringify(item, null, 2)}</pre>
                </div>
            </details>
        `;
    });
    
    if (array.length > 10) {
        html += `<div style="color: var(--text-secondary); font-style: italic; margin-top: 12px;">... and ${array.length - 10} more items</div>`;
    }
    
    return html;
}

function createObjectView(obj, parentKey) {
    const keys = Object.keys(obj);
    
    if (keys.length === 0) {
        return '<div style="color: var(--text-secondary); font-style: italic;">Empty object</div>';
    }
    
    let html = `
        <div style="margin-bottom: 12px;">
            <strong>Object with ${keys.length} properties</strong>
        </div>
    `;
    
    keys.forEach(key => {
        const value = obj[key];
        html += `
            <details style="margin-bottom: 8px; border: 1px solid var(--border-light); border-radius: 6px;">
                <summary style="cursor: pointer; padding: 8px 12px; background: var(--bg-secondary); font-size: 0.9rem;">
                    <code style="background: var(--bg-primary); padding: 2px 6px; border-radius: 3px;">${key}</code>
                    <span style="margin-left: 8px; color: var(--text-secondary);">${getDataTypeInfo(value)}</span>
                </summary>
                <div style="padding: 12px;">
                    <pre style="margin: 0; font-size: 0.8rem; color: var(--text-primary); max-height: 300px; overflow: auto;">${JSON.stringify(value, null, 2)}</pre>
                </div>
            </details>
        `;
    });
    
    return html;
}

function getDataTypeInfo(value) {
    if (value === null) return 'null';
    if (value === undefined) return 'undefined';
    if (Array.isArray(value)) return `Array[${value.length}]`;
    if (typeof value === 'object') return `Object{${Object.keys(value).length}}`;
    if (typeof value === 'string') return `String(${value.length})`;
    if (typeof value === 'number') return `Number(${value})`;
    if (typeof value === 'boolean') return `Boolean(${value})`;
    return typeof value;
}

// Enhanced FFI Visualization with rich lifecycle data
function initEnhancedFFIVisualization() {
    const container = document.getElementById('ffiVisualization');
    if (!container) return;

    const data = window.analysisData || {};
    const allocs = data.unsafe_ffi?.allocations || data.memory_analysis?.allocations || data.allocations || [];
    
    if (allocs.length === 0) {
        container.innerHTML = `<div style="background: var(--bg-secondary); border-radius:8px; padding:16px; text-align:center; color: var(--text-secondary);"><i class="fa fa-exclamation-triangle" style="font-size:24px; margin-bottom:8px; color: var(--primary-red);"></i><div>Critical: No FFI allocation data found!</div></div>`;
        return;
    }

    // Rich data analysis
    const ffiTracked = allocs.filter(a => a.ffi_tracked).length;
    const withViolations = allocs.filter(a => a.safety_violations && a.safety_violations.length > 0).length;
    const withClones = allocs.filter(a => a.clone_info?.clone_count > 0).length;
    const leaked = allocs.filter(a => a.is_leaked).length;
    const totalBorrows = allocs.reduce((sum, a) => sum + (a.borrow_info?.immutable_borrows || 0) + (a.borrow_info?.mutable_borrows || 0), 0);
    const totalMemory = allocs.reduce((sum, a) => sum + (a.size || 0), 0);
    const avgLifetime = allocs.filter(a => a.lifetime_ms).reduce((sum, a) => sum + a.lifetime_ms, 0) / allocs.filter(a => a.lifetime_ms).length || 0;

    // Get time range for lifecycle visualization
    const timestamps = allocs.map(a => a.timestamp_alloc).filter(t => t).sort((a, b) => a - b);
    const minTime = timestamps[0] || 0;
    const maxTime = timestamps[timestamps.length - 1] || minTime;
    const timeRange = maxTime - minTime || 1;

    // Content that will be contained within the section's background
    container.innerHTML = `
        <!-- KPI Cards -->
        <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin-bottom: 20px;">
            <div style="background: var(--bg-primary); padding: 14px; border-radius: 8px; text-align: center; border-left: 4px solid var(--primary-blue);">
                <div style="font-size: 1.6rem; font-weight: 700; color: var(--primary-blue);">${allocs.length}</div>
                <div style="font-size: 0.75rem; color: var(--text-secondary);">FFI Allocations</div>
            </div>
            <div style="background: var(--bg-primary); padding: 14px; border-radius: 8px; text-align: center; border-left: 4px solid var(--primary-green);">
                <div style="font-size: 1.6rem; font-weight: 700; color: var(--primary-green);">${totalBorrows}</div>
                <div style="font-size: 0.75rem; color: var(--text-secondary);">Total Borrows</div>
            </div>
            <div style="background: var(--bg-primary); padding: 14px; border-radius: 8px; text-align: center; border-left: 4px solid var(--primary-orange);">
                <div style="font-size: 1.6rem; font-weight: 700; color: var(--primary-orange);">${withClones}</div>
                <div style="font-size: 0.75rem; color: var(--text-secondary);">With Clones</div>
            </div>
            <div style="background: var(--bg-primary); padding: 14px; border-radius: 8px; text-align: center; border-left: 4px solid ${leaked > 0 ? 'var(--primary-red)' : 'var(--primary-green)'};">
                <div style="font-size: 1.6rem; font-weight: 700; color: ${leaked > 0 ? 'var(--primary-red)' : 'var(--primary-green)'};">${leaked}</div>
                <div style="font-size: 0.75rem; color: var(--text-secondary);">Memory Leaks</div>
            </div>
            <div style="background: var(--bg-primary); padding: 14px; border-radius: 8px; text-align: center; border-left: 4px solid var(--primary-red);">
                <div style="font-size: 1.6rem; font-weight: 700; color: ${withViolations > 0 ? 'var(--primary-red)' : 'var(--primary-green)'};">${withViolations}</div>
                <div style="font-size: 0.75rem; color: var(--text-secondary);">Safety Violations</div>
            </div>
        </div>
        
        <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 20px;">
            <div style="background: var(--bg-secondary); padding: 16px; border-radius: 8px;">
                <h3 style="margin: 0 0 12px 0; color: var(--text-primary); display: flex; align-items: center;"><i class="fa fa-clock-o" style="margin-right: 8px;"></i>Lifecycle Metrics</h3>
                <div style="margin-bottom: 10px;">
                    <span style="color: var(--text-secondary); font-size: 0.9rem;">Avg Lifetime:</span>
                    <span style="color: var(--text-primary); font-weight: 600; margin-left: 8px;">${avgLifetime.toFixed(2)}ms</span>
                </div>
                <div style="margin-bottom: 10px;">
                    <span style="color: var(--text-secondary); font-size: 0.9rem;">Total Memory:</span>
                    <span style="color: var(--text-primary); font-weight: 600; margin-left: 8px;">${formatBytes(totalMemory)}</span>
                </div>
                <div style="margin-bottom: 10px;">
                    <span style="color: var(--text-secondary); font-size: 0.9rem;">Time Span:</span>
                    <span style="color: var(--text-primary); font-weight: 600; margin-left: 8px;">${(timeRange / 1e6).toFixed(2)}ms</span>
                </div>
            </div>
            
            <div style="background: var(--bg-secondary); padding: 16px; border-radius: 8px;">
                <h3 style="margin: 0 0 12px 0; color: var(--text-primary); display: flex; align-items: center;"><i class="fa fa-share-alt" style="margin-right: 8px;"></i>Borrow & Clone Activity</h3>
                <div style="margin-bottom: 8px;">
                    <span style="color: var(--text-secondary); font-size: 0.9rem;">Immutable Borrows:</span>
                    <span style="color: var(--primary-blue); font-weight: 600; margin-left: 8px;">${allocs.reduce((s, a) => s + (a.borrow_info?.immutable_borrows || 0), 0)}</span>
                </div>
                <div style="margin-bottom: 8px;">
                    <span style="color: var(--text-secondary); font-size: 0.9rem;">Mutable Borrows:</span>
                    <span style="color: var(--primary-orange); font-weight: 600; margin-left: 8px;">${allocs.reduce((s, a) => s + (a.borrow_info?.mutable_borrows || 0), 0)}</span>
                </div>
                <div>
                    <span style="color: var(--text-secondary); font-size: 0.9rem;">Clone Operations:</span>
                    <span style="color: var(--primary-green); font-weight: 600; margin-left: 8px;">${allocs.reduce((s, a) => s + (a.clone_info?.clone_count || 0), 0)}</span>
                </div>
            </div>
        </div>

        <!-- FFI Data Flow Visualization (data stream) -->
        <div style="margin-top: 20px; background: var(--bg-secondary); padding: 16px; border-radius: 8px;">
            <h3 style="margin: 0 0 12px 0; color: var(--text-primary); display: flex; align-items: center;">
                <i class="fa fa-exchange" style="margin-right: 8px;"></i>FFI Data Flow
                <button id="ffi-flow-toggle" style="margin-left: auto; background: var(--primary-green); color: white; border: none; padding: 4px 8px; border-radius: 4px; font-size: 11px; cursor: pointer;">
                    <i class="fa fa-play"></i> Animate
                </button>
            </h3>
            <div id="ffi-flow-container" style="height: 200px; position: relative; border: 1px solid var(--border-light); border-radius: 6px; overflow: hidden; background: linear-gradient(135deg, #1e293b 0%, #0f172a 50%, #1e293b 100%);">
                ${createFFIDataFlow(allocs)}
            </div>
            <div style="margin-top: 8px; font-size: 11px; color: var(--text-secondary); text-align: center;">
                ๐Ÿฆ€ Rust โ†” C Data Flow โ€ข ${ffiTracked} FFI-tracked allocations โ€ข Click nodes for details
            </div>
        </div>

        <!-- Interactive Allocation Analysis (Two Column Layout) -->
        <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 20px;">
            <!-- Timeline Column -->
            <div style="background: var(--bg-secondary); padding: 16px; border-radius: 8px;">
                <h3 style="margin: 0 0 12px 0; color: var(--text-primary); display: flex; align-items: center;">
                    <i class="fa fa-clock-o" style="margin-right: 8px;"></i>Allocation Timeline
                    <button id="ffi-timeline-toggle" style="margin-left: auto; background: var(--primary-blue); color: white; border: none; padding: 4px 8px; border-radius: 4px; font-size: 11px; cursor: pointer;">
                        <i class="fa fa-expand"></i> Details
                    </button>
                </h3>
                <div id="ffi-timeline-container" style="height: 160px; position: relative; border: 1px solid var(--border-light); border-radius: 6px; overflow: hidden; background: linear-gradient(45deg, var(--bg-primary) 0%, var(--bg-secondary) 100%);">
                    ${createAllocationTimeline(allocs, minTime, timeRange)}
                </div>
                <div style="margin-top: 8px; font-size: 11px; color: var(--text-secondary); text-align: center;">
                    Timeline spans ${(timeRange / 1e6).toFixed(1)}ms โ€ข Click dots for details
                </div>
            </div>
            
            <!-- Details Column -->
            <div style="background: var(--bg-secondary); padding: 16px; border-radius: 8px;">
                <h3 style="margin: 0 0 12px 0; color: var(--text-primary); display: flex; align-items: center;">
                    <i class="fa fa-list" style="margin-right: 8px;"></i>Allocation Details
                    <select id="ffi-filter" style="margin-left: auto; background: var(--bg-primary); border: 1px solid var(--border-light); border-radius: 4px; padding: 4px 8px; font-size: 11px; color: var(--text-primary);">
                        <option value="all">All (${allocs.length})</option>
                        <option value="leaked">Leaked (${allocs.filter(a => a.is_leaked).length})</option>
                        <option value="cloned">With Clones (${withClones})</option>
                        <option value="borrowed">With Borrows (${allocs.filter(a => ((a.borrow_info?.immutable_borrows || 0) + (a.borrow_info?.mutable_borrows || 0)) > 0).length})</option>
                    </select>
                </h3>
                <div id="ffi-allocation-table" style="max-height: 160px; overflow-y: auto; border: 1px solid var(--border-light); border-radius: 6px;">
                    ${createAllocationTable(allocs)}
                </div>
                <div style="margin-top: 8px; font-size: 11px; color: var(--text-secondary); text-align: center;">
                    Click rows for detailed view โ€ข Use filter to narrow results
                </div>
            </div>
        </div>
    `;

    // Add interactivity
    setupFFIInteractivity(allocs, minTime, timeRange);
    setupFFIFlowInteractivity(allocs);
}

// Create super cool FFI data flow visualization
function createFFIDataFlow(allocs) {
    const ffiAllocs = allocs.filter(a => a.ffi_tracked);
    const rustAllocs = allocs.filter(a => !a.ffi_tracked);
    
    // Create dynamic SVG-based flow visualization
    let html = `
        <svg width="100%" height="100%" viewBox="0 0 800 200" style="position: absolute; top: 0; left: 0;">
            <!-- Background grid pattern -->
            <defs>
                <pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse">
                    <path d="M 20 0 L 0 0 0 20" fill="none" stroke='#334155' stroke-width="0.5" opacity="0.3"/>
                </pattern>
                <filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
                    <feGaussianBlur stdDeviation="3" result="coloredBlur"/>
                    <feMerge>
                        <feMergeNode in="coloredBlur"/>
                        <feMergeNode in="SourceGraphic"/>
                    </feMerge>
                </filter>
                <linearGradient id="rustGradient" x1="0%" y1="0%" x2="100%" y2="0%">
                    <stop offset="0%" style="stop-color:#f97316;stop-opacity:1" />
                    <stop offset="100%" style="stop-color:#ea580c;stop-opacity:1" />
                </linearGradient>
                <linearGradient id="cGradient" x1="0%" y1="0%" x2="100%" y2="0%">
                    <stop offset="0%" style="stop-color:#3b82f6;stop-opacity:1" />
                    <stop offset="100%" style="stop-color:#1d4ed8;stop-opacity:1" />
                </linearGradient>
            </defs>
            
            <rect width="100%" height="100%" fill="url(#grid)"/>
            
            <!-- Rust Side (Left) -->
            <g id="rust-side">
                <rect x="50" y="40" width="200" height="120" rx="15" fill="url(#rustGradient)" opacity="0.2" stroke='#f97316' stroke-width="2"/>
                <text x="150" y="30" text-anchor="middle" font-size="16" font-weight="bold" fill='#f97316' filter="url(#glow)">
                    ๐Ÿฆ€ RUST
                </text>
                <text x="150" y="190" text-anchor="middle" font-size="12" fill='#f97316'>
                    ${rustAllocs.length} allocations
                </text>
                
                <!-- Rust memory nodes -->
                ${rustAllocs.slice(0, 8).map((alloc, i) => {
                    const x = 80 + (i % 4) * 35;
                    const y = 60 + Math.floor(i / 4) * 35;
                    const size = Math.max(8, Math.min(16, Math.sqrt((alloc.size || 0) / 1000)));
                    return `
                        <circle cx="${x}" cy="${y}" r="${size}" fill='#f97316' opacity="0.8" 
                                stroke='#fff' stroke-width="2" class='rust-node '
                                data-ptr="${alloc.ptr}" data-size="${alloc.size || 0}"
                                style="cursor: pointer; transition: all 0.3s;">
                            <animate attributeName="opacity" values="0.8;1;0.8" dur="2s" repeatCount="indefinite"/>
                        </circle>
                    `;
                }).join('')}
            </g>
            
            <!-- C/FFI Side (Right) -->
            <g id="c-side">
                <rect x="550" y="40" width="200" height="120" rx="15" fill="url(#cGradient)" opacity="0.2" stroke='#3b82f6' stroke-width="2"/>
                <text x="650" y="30" text-anchor="middle" font-size="16" font-weight="bold" fill='#3b82f6' filter="url(#glow)">
                    โš™๏ธ C/FFI
                </text>
                <text x="650" y="190" text-anchor="middle" font-size="12" fill='#3b82f6'>
                    ${ffiAllocs.length} FFI allocations
                </text>
                
                <!-- FFI memory nodes -->
                ${ffiAllocs.slice(0, 8).map((alloc, i) => {
                    const x = 580 + (i % 4) * 35;
                    const y = 60 + Math.floor(i / 4) * 35;
                    const size = Math.max(8, Math.min(16, Math.sqrt((alloc.size || 0) / 1000)));
                    return `
                        <circle cx="${x}" cy="${y}" r="${size}" fill='#3b82f6' opacity="0.9" 
                                stroke='#fff' stroke-width="2" class='ffi-node '
                                data-ptr="${alloc.ptr}" data-size="${alloc.size || 0}"
                                style="cursor: pointer;">
                        </circle>
                    `;
                }).join('')}
            </g>
            
            <!-- Data Flow Arrows -->
            <g id="data-flows">
                <!-- Rust to C flow -->
                <path d="M 250 80 Q 400 60 550 80" stroke='#10b981' stroke-width="3" fill="none" opacity="0.7">
                    <animate attributeName="stroke-dasharray " values="0,1000;1000,0" dur="3s" repeatCount="indefinite "/>
                </path>
                <text x="400" y="55" text-anchor="middle" font-size="10" fill='#10b981' font-weight="bold">
                    Rust โ†’ C
                </text>
                
                <!-- C to Rust flow -->
                <path d="M 550 120 Q 400 140 250 120" stroke='#ec4899' stroke-width="3" fill="none" opacity="0.7">
                    <animate attributeName="stroke-dasharray" values="0,1000;1000,0" dur="3.5s" repeatCount="indefinite"/>
                </path>
                <text x="400" y="155" text-anchor="middle" font-size="10" fill='#ec4899' font-weight="bold">
                    C โ†’ Rust
                </text>
                
                <!-- Central processing hub -->
                <circle cx="400" cy="100" r="20" fill='#8b5cf6' opacity="0.3" stroke='#8b5cf6' stroke-width="2">
                    <animate attributeName="r" values="20;25;20" dur="2s" repeatCount="indefinite"/>
                </circle>
                <text x="400" y="105" text-anchor="middle" font-size="10" fill='#8b5cf6' font-weight="bold">FFI</text>
            </g>
            
            <!-- Memory flow particles -->
            <g id="flow-particles">
                ${Array.from({length: 6}, (_, i) => `
                    <circle r="3" fill='#fbbf24' opacity="0.8">
                        <animateMotion dur="${3 + i * 0.5}s" repeatCount="indefinite">
                            <path d="M 250 80 Q 400 60 550 80"/>
                        </animateMotion>
                        <animate attributeName="opacity" values="0;1;0" dur="1s" repeatCount="indefinite"/>
                    </circle>
                `).join('')}
                
                ${Array.from({length: 4}, (_, i) => `
                    <circle r="3" fill='#06d6a0' opacity="0.8">
                        <animateMotion dur="${3.5 + i * 0.7}s" repeatCount="indefinite">
                            <path d="M 550 120 Q 400 140 250 120"/>
                        </animateMotion>
                        <animate attributeName="opacity" values="0;1;0" dur="1s" repeatCount="indefinite"/>
                    </circle>
                `).join('')}
            </g>
        </svg>
    `;
    
    return html;
}

// Create allocation timeline visualization
function createAllocationTimeline(allocs, minTime, timeRange) {
    const sorted = allocs.slice().sort((a, b) => (a.timestamp_alloc || 0) - (b.timestamp_alloc || 0));
    let html = '<div style="position: relative; height: 100%; background: linear-gradient(90deg, rgba(59,130,246,0.1) 0%, rgba(16,185,129,0.1) 50%, rgba(239,68,68,0.1) 100%);">';
    
    // Add time axis with better spacing
    html += '<div style="position: absolute; bottom: 25px; left: 0; right: 0; height: 1px; background: var(--border-light);"></div>';
    html += '<div style="position: absolute; bottom: 18px; left: 12px; font-size: 10px; color: var(--text-secondary); background: var(--bg-primary); padding: 2px 4px; border-radius: 3px;">0ms</div>';
    html += '<div style="position: absolute; bottom: 18px; right: 12px; font-size: 10px; color: var(--text-secondary); background: var(--bg-primary); padding: 2px 4px; border-radius: 3px;">' + (timeRange / 1e6).toFixed(1) + 'ms</div>';
    
    // Add middle time markers for better readability
    const midTime = (timeRange / 1e6) / 2;
    html += '<div style="position: absolute; bottom: 18px; left: 50%; transform: translateX(-50%); font-size: 10px; color: var(--text-secondary); background: var(--bg-primary); padding: 2px 4px; border-radius: 3px;">' + midTime.toFixed(1) + 'ms</div>';
    
    // Group nearby allocations to prevent overlap
    const groups = [];
    const threshold = timeRange * 0.05; // 5% of time range
    
    sorted.forEach(alloc => {
        const found = groups.find(g => Math.abs(g.avgTime - alloc.timestamp_alloc) < threshold);
        if (found) {
            found.allocs.push(alloc);
            found.avgTime = found.allocs.reduce((sum, a) => sum + a.timestamp_alloc, 0) / found.allocs.length;
        } else {
            groups.push({ allocs: [alloc], avgTime: alloc.timestamp_alloc });
        }
    });
    
    groups.forEach((group, groupIndex) => {
        const relativeTime = (group.avgTime - minTime) / timeRange;
        const left = Math.max(2, Math.min(93, relativeTime * 90 + 5));
        
        if (group.allocs.length === 1) {
            const alloc = group.allocs[0];
            const size = Math.max(10, Math.min(20, Math.sqrt((alloc.size || 0) / 50)));
            const isLeaked = alloc.is_leaked;
            const hasClones = alloc.clone_info?.clone_count > 0;
            const color = isLeaked ? '#dc2626' : hasClones ? '#ea580c' : '#2563eb';
            
            html += `<div style="position: absolute; left: ${left}%; top: 60%; transform: translateY(-50%); 
                     width: ${size}px; height: ${size}px; background: ${color}; border-radius: 50%; 
                     border: 2px solid white; cursor: pointer; z-index: 100; 
                     box-shadow: 0 2px 4px rgba(0,0,0,0.2); transition: transform 0.2s;"
                     onmouseover="this.style.transform='translateY(-50%) scale(1.2)'" 
                     onmouseout="this.style.transform='translateY(-50%) scale(1)'"
                     title="${alloc.var_name || 'unnamed'} | ${formatBytes(alloc.size || 0)} | ${new Date(alloc.timestamp_alloc / 1e6).toLocaleTimeString()}"
                     onclick="showAllocationDetail('${alloc.ptr}')"></div>`;
        } else {
            // Multiple allocations - create a cluster
            const totalSize = group.allocs.reduce((sum, a) => sum + (a.size || 0), 0);
            const hasLeaks = group.allocs.some(a => a.is_leaked);
            const hasClones = group.allocs.some(a => a.clone_info?.clone_count > 0);
            const clusterSize = Math.max(16, Math.min(28, Math.sqrt(totalSize / 100)));
            const color = hasLeaks ? '#dc2626' : hasClones ? '#ea580c' : '#2563eb';
            
            html += `<div style="position: absolute; left: ${left}%; top: 60%; transform: translateY(-50%); 
                     width: ${clusterSize}px; height: ${clusterSize}px; background: ${color}; border-radius: 50%; 
                     border: 3px solid white; cursor: pointer; z-index: 100;
                     box-shadow: 0 2px 8px rgba(0,0,0,0.3); display: flex; align-items: center; justify-content: center;
                     color: white; font-size: 9px; font-weight: bold; transition: transform 0.2s;"
                     onmouseover="this.style.transform='translateY(-50%) scale(1.2)'" 
                     onmouseout="this.style.transform='translateY(-50%) scale(1)'"
                     title="${group.allocs.length} allocations | Total: ${formatBytes(totalSize)} | Avg time: ${new Date(group.avgTime / 1e6).toLocaleTimeString()}"
                     onclick="showClusterDetail(${JSON.stringify(group.allocs.map(a => a.ptr)).replace(/"/g, '&quot;')})">${group.allocs.length}</div>`;
        }
    });
    
    html += '</div>';
    return html;
}

// Create allocation details table
function createAllocationTable(allocs) {
    const sorted = allocs.slice().sort((a, b) => (b.timestamp_alloc || 0) - (a.timestamp_alloc || 0));
    
    let html = `
        <div style="border: 1px solid var(--border-light); border-radius: 6px; overflow: hidden;">
            <table style="width: 100%; border-collapse: collapse; font-size: 12px;">
                <thead style="background: var(--bg-primary); border-bottom: 1px solid var(--border-light);">
                    <tr>
                        <th style="padding: 8px; text-align: left; color: var(--text-primary);">Variable</th>
                        <th style="padding: 8px; text-align: left; color: var(--text-primary);">Type</th>
                        <th style="padding: 8px; text-align: right; color: var(--text-primary);">Size</th>
                        <th style="padding: 8px; text-align: center; color: var(--text-primary);">Borrows</th>
                        <th style="padding: 8px; text-align: center; color: var(--text-primary);">Clones</th>
                        <th style="padding: 8px; text-align: center; color: var(--text-primary);">Status</th>
                        <th style="padding: 8px; text-align: right; color: var(--text-primary);">Lifetime</th>
                    </tr>
                </thead>
                <tbody>`;
    
    sorted.forEach((alloc, i) => {
        const typeName = (alloc.type_name || 'Unknown').replace(/alloc::|std::/g, '').replace(/collections::\w+::/g, '');
        const shortType = typeName.length > 20 ? typeName.substring(0, 17) + '...' : typeName;
        const totalBorrows = (alloc.borrow_info?.immutable_borrows || 0) + (alloc.borrow_info?.mutable_borrows || 0);
        const cloneCount = alloc.clone_info?.clone_count || 0;
        const isLeaked = alloc.is_leaked;
        const lifetime = alloc.lifetime_ms || 'Active';
        
        const statusColor = isLeaked ? 'var(--primary-red)' : 'var(--primary-green)';
        const statusText = isLeaked ? 'LEAKED' : 'OK';
        
        html += `
            <tr style="border-bottom: 1px solid var(--border-light); cursor: pointer;" 
                onclick="showAllocationDetail('${alloc.ptr}')" 
                onmouseover="this.style.background='var(--bg-secondary)'" 
                onmouseout="this.style.background='transparent'">
                <td style="padding: 8px; color: var(--text-primary); font-weight: 500;">${alloc.var_name || 'unnamed'}</td>
                <td style="padding: 8px; color: var(--text-secondary);" title="${alloc.type_name}">${shortType}</td>
                <td style="padding: 8px; text-align: right; color: var(--text-primary); font-weight: 600;">${formatBytes(alloc.size || 0)}</td>
                <td style="padding: 8px; text-align: center; color: var(--primary-blue);">${totalBorrows}</td>
                <td style="padding: 8px; text-align: center; color: var(--primary-orange);">${cloneCount}</td>
                <td style="padding: 8px; text-align: center;">
                    <span style="color: ${statusColor}; font-weight: 600; font-size: 11px;">${statusText}</span>
                </td>
                <td style="padding: 8px; text-align: right; color: var(--text-secondary); font-size: 11px;">
                    ${typeof lifetime === 'number' ? lifetime.toFixed(2) + 'ms' : lifetime}
                </td>
            </tr>`;
    });
    
    html += '</tbody></table></div>';
    return html;
}

// Setup FFI interactivity
function setupFFIInteractivity(allocs, minTime, timeRange) {
    // Timeline toggle
    const toggleBtn = document.getElementById('ffi-timeline-toggle');
    if (toggleBtn) {
        let expanded = false;
        toggleBtn.onclick = () => {
            const container = document.getElementById('ffi-timeline-container');
            if (!container) return;
            
            expanded = !expanded;
            container.style.height = expanded ? '200px' : '120px';
            toggleBtn.textContent = expanded ? 'Hide Details' : 'Show Details';
            
            if (expanded) {
                // Add detailed timeline with labels
                container.innerHTML = createAllocationTimeline(allocs, minTime, timeRange) + 
                    '<div style="position: absolute; bottom: 4px; left: 8px; font-size: 10px; color: var(--text-secondary);">Start</div>' +
                    '<div style="position: absolute; bottom: 4px; right: 8px; font-size: 10px; color: var(--text-secondary);">End</div>';
            } else {
                container.innerHTML = createAllocationTimeline(allocs, minTime, timeRange);
            }
        };
    }
    
    // Table filter
    const filterSelect = document.getElementById('ffi-filter');
    if (filterSelect) {
        filterSelect.onchange = () => {
            const filterValue = filterSelect.value;
            let filteredAllocs = allocs;
            
            switch(filterValue) {
                case 'leaked':
                    filteredAllocs = allocs.filter(a => a.is_leaked);
                    break;
                case 'cloned':
                    filteredAllocs = allocs.filter(a => a.clone_info?.clone_count > 0);
                    break;
                case 'borrowed':
                    filteredAllocs = allocs.filter(a => {
                        const borrows = (a.borrow_info?.immutable_borrows || 0) + (a.borrow_info?.mutable_borrows || 0);
                        return borrows > 0;
                    });
                    break;
                default:
                    filteredAllocs = allocs;
            }
            
            const tableContainer = document.getElementById('ffi-allocation-table');
            if (tableContainer) {
                tableContainer.innerHTML = createAllocationTable(filteredAllocs);
            }
        };
    }
}

// Show allocation detail modal
window.showAllocationDetail = function(ptr) {
    const data = window.analysisData || {};
    const allocs = data.unsafe_ffi?.allocations || data.memory_analysis?.allocations || data.allocations || [];
    const alloc = allocs.find(a => a.ptr === ptr);
    
    if (!alloc) return;
    
    const modal = document.createElement('div');
    modal.style.cssText = `
        position: fixed; top: 0; left: 0; right: 0; bottom: 0; 
        background: rgba(0,0,0,0.5); z-index: 1000; 
        display: flex; align-items: center; justify-content: center;
    `;
    
    modal.innerHTML = `
        <div style="background: var(--bg-primary); border-radius: 12px; padding: 24px; min-width: 400px; max-width: 600px; border: 1px solid var(--border-light);">
            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
                <h3 style="margin: 0; color: var(--text-primary);">Allocation Details</h3>
                <button onclick="this.closest('div').parentNode.remove()" style="background: none; border: none; font-size: 20px; color: var(--text-secondary); cursor: pointer;">ร—</button>
            </div>
            <div style="color: var(--text-primary); line-height: 1.6;">
                <div style="margin-bottom: 12px;"><strong>Variable:</strong> ${alloc.var_name || 'unnamed'}</div>
                <div style="margin-bottom: 12px;"><strong>Type:</strong> ${alloc.type_name || 'Unknown'}</div>
                <div style="margin-bottom: 12px;"><strong>Size:</strong> ${formatBytes(alloc.size || 0)}</div>
                <div style="margin-bottom: 12px;"><strong>Pointer:</strong> <code>${alloc.ptr}</code></div>
                <div style="margin-bottom: 12px;"><strong>Thread:</strong> ${alloc.thread_id}</div>
                <div style="margin-bottom: 12px;"><strong>Allocated:</strong> ${new Date(alloc.timestamp_alloc / 1e6).toLocaleString()}</div>
                <div style="margin-bottom: 12px;"><strong>Lifetime:</strong> ${alloc.lifetime_ms ? alloc.lifetime_ms.toFixed(2) + 'ms' : 'Active'}</div>
                <div style="margin-bottom: 12px;"><strong>Immutable Borrows:</strong> ${alloc.borrow_info?.immutable_borrows || 0}</div>
                <div style="margin-bottom: 12px;"><strong>Mutable Borrows:</strong> ${alloc.borrow_info?.mutable_borrows || 0}</div>
                <div style="margin-bottom: 12px;"><strong>Clone Count:</strong> ${alloc.clone_info?.clone_count || 0}</div>
                <div style="margin-bottom: 12px;"><strong>FFI Tracked:</strong> ${alloc.ffi_tracked ? 'Yes' : 'No'}</div>
                <div style="margin-bottom: 12px;"><strong>Status:</strong> 
                    <span style="color: ${alloc.is_leaked ? 'var(--primary-red)' : 'var(--primary-green)'}; font-weight: 600;">
                        ${alloc.is_leaked ? 'LEAKED' : 'OK'}
                    </span>
                </div>
                ${alloc.safety_violations && alloc.safety_violations.length > 0 ? 
                    `<div style="margin-bottom: 12px; color: var(--primary-red);"><strong>Safety Violations:</strong> ${alloc.safety_violations.join(', ')}</div>` 
                    : ''}
            </div>
        </div>
    `;
    
    document.body.appendChild(modal);
    modal.onclick = (e) => { if (e.target === modal) modal.remove(); };
};

// Show cluster detail for grouped allocations
window.showClusterDetail = function(ptrs) {
    const data = window.analysisData || {};
    const allocs = data.unsafe_ffi?.allocations || data.memory_analysis?.allocations || data.allocations || [];
    const clusterAllocs = allocs.filter(a => ptrs.includes(a.ptr));
    
    if (clusterAllocs.length === 0) return;
    
    const totalSize = clusterAllocs.reduce((sum, a) => sum + (a.size || 0), 0);
    const totalBorrows = clusterAllocs.reduce((sum, a) => sum + (a.borrow_info?.immutable_borrows || 0) + (a.borrow_info?.mutable_borrows || 0), 0);
    const totalClones = clusterAllocs.reduce((sum, a) => sum + (a.clone_info?.clone_count || 0), 0);
    const leakCount = clusterAllocs.filter(a => a.is_leaked).length;
    
    const modal = document.createElement('div');
    modal.style.cssText = `
        position: fixed; top: 0; left: 0; right: 0; bottom: 0; 
        background: rgba(0,0,0,0.5); z-index: 1000; 
        display: flex; align-items: center; justify-content: center;
    `;
    
    modal.innerHTML = `
        <div style="background: var(--bg-primary); border-radius: 12px; padding: 24px; min-width: 500px; max-width: 700px; max-height: 80vh; overflow-y: auto; border: 1px solid var(--border-light);">
            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
                <h3 style="margin: 0; color: var(--text-primary);">Allocation Cluster (${clusterAllocs.length} items)</h3>
                <button onclick="this.closest('div').parentNode.remove()" style="background: none; border: none; font-size: 20px; color: var(--text-secondary); cursor: pointer;">ร—</button>
            </div>
            <div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 16px;">
                <div style="text-align: center; padding: 12px; background: var(--bg-secondary); border-radius: 6px;">
                    <div style="font-size: 1.2rem; font-weight: 600; color: var(--primary-blue);">${formatBytes(totalSize)}</div>
                    <div style="font-size: 0.8rem; color: var(--text-secondary);">Total Size</div>
                </div>
                <div style="text-align: center; padding: 12px; background: var(--bg-secondary); border-radius: 6px;">
                    <div style="font-size: 1.2rem; font-weight: 600; color: var(--primary-green);">${totalBorrows}</div>
                    <div style="font-size: 0.8rem; color: var(--text-secondary);">Total Borrows</div>
                </div>
                <div style="text-align: center; padding: 12px; background: var(--bg-secondary); border-radius: 6px;">
                    <div style="font-size: 1.2rem; font-weight: 600; color: var(--primary-orange);">${totalClones}</div>
                    <div style="font-size: 0.8rem; color: var(--text-secondary);">Total Clones</div>
                </div>
                <div style="text-align: center; padding: 12px; background: var(--bg-secondary); border-radius: 6px;">
                    <div style="font-size: 1.2rem; font-weight: 600; color: ${leakCount > 0 ? 'var(--primary-red)' : 'var(--primary-green)'};">${leakCount}</div>
                    <div style="font-size: 0.8rem; color: var(--text-secondary);">Leaks</div>
                </div>
            </div>
            <div style="color: var(--text-primary);">
                <h4 style="margin: 0 0 12px 0; color: var(--text-primary);">Individual Allocations:</h4>
                <div style="max-height: 300px; overflow-y: auto; border: 1px solid var(--border-light); border-radius: 6px;">
                    <table style="width: 100%; border-collapse: collapse; font-size: 12px;">
                        <thead style="background: var(--bg-secondary); position: sticky; top: 0;">
                            <tr>
                                <th style="padding: 8px; text-align: left;">Variable</th>
                                <th style="padding: 8px; text-align: right;">Size</th>
                                <th style="padding: 8px; text-align: center;">Borrows</th>
                                <th style="padding: 8px; text-align: center;">Clones</th>
                                <th style="padding: 8px; text-align: center;">Status</th>
                            </tr>
                        </thead>
                        <tbody>
                            ${clusterAllocs.map(alloc => {
                                const totalBorrows = (alloc.borrow_info?.immutable_borrows || 0) + (alloc.borrow_info?.mutable_borrows || 0);
                                const cloneCount = alloc.clone_info?.clone_count || 0;
                                const isLeaked = alloc.is_leaked;
                                const statusColor = isLeaked ? 'var(--primary-red)' : 'var(--primary-green)';
                                const statusText = isLeaked ? 'LEAKED' : 'OK';
                                
                                return `
                                    <tr style="border-bottom: 1px solid var(--border-light); cursor: pointer;" onclick="showAllocationDetail('${alloc.ptr}')">
                                        <td style="padding: 8px; font-weight: 500;">${alloc.var_name || 'unnamed'}</td>
                                        <td style="padding: 8px; text-align: right; font-weight: 600;">${formatBytes(alloc.size || 0)}</td>
                                        <td style="padding: 8px; text-align: center; color: var(--primary-blue);">${totalBorrows}</td>
                                        <td style="padding: 8px; text-align: center; color: var(--primary-orange);">${cloneCount}</td>
                                        <td style="padding: 8px; text-align: center;"><span style="color: ${statusColor}; font-weight: 600; font-size: 11px;">${statusText}</span></td>
                                    </tr>
                                `;
                            }).join('')}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    `;
    
    document.body.appendChild(modal);
    modal.onclick = (e) => { if (e.target === modal) modal.remove(); };
};

// Render enhanced data insights with beautiful visualizations
function renderEnhancedDataInsights() {
    const data = window.analysisData || {};
    const allocs = data.memory_analysis?.allocations || data.allocations || [];
    
    if (allocs.length === 0) return;
    
    // Calculate timeline insights
    const timestamps = allocs.map(a => a.timestamp_alloc).filter(t => t).sort((a, b) => a - b);
    const timeSpanMs = timestamps.length > 1 ? (timestamps[timestamps.length - 1] - timestamps[0]) / 1e6 : 0;
    const allocationBurst = (allocs.length / Math.max(1, timeSpanMs / 1000)).toFixed(1);
    
    // Calculate borrow patterns
    const borrowPatterns = {};
    let totalBorrows = 0;
    let totalMutable = 0;
    let totalImmutable = 0;
    
    allocs.forEach(alloc => {
        const bi = alloc.borrow_info || {};
        const immut = bi.immutable_borrows || 0;
        const mut = bi.mutable_borrows || 0;
        const pattern = `${immut}i+${mut}m`;
        borrowPatterns[pattern] = (borrowPatterns[pattern] || 0) + 1;
        totalBorrows += immut + mut;
        totalImmutable += immut;
        totalMutable += mut;
    });
    
    // Calculate clone operations
    const totalClones = allocs.reduce((sum, a) => sum + (a.clone_info?.clone_count || 0), 0);
    
    // Update Timeline Insights
    document.getElementById('time-span').textContent = timeSpanMs.toFixed(2) + 'ms';
    document.getElementById('allocation-burst').textContent = allocationBurst + '/sec';
    document.getElementById('peak-concurrency').textContent = Math.max(...allocs.map(a => (a.borrow_info?.max_concurrent_borrows || 0)));
    document.getElementById('thread-activity').textContent = 'Single Thread';
    
    // Update Memory Operations
    document.getElementById('borrow-ops').textContent = totalBorrows;
    document.getElementById('clone-ops').textContent = totalClones;
    document.getElementById('mut-ratio').textContent = totalImmutable > 0 ? (totalMutable / totalImmutable).toFixed(1) : '0';
    document.getElementById('avg-borrows').textContent = (totalBorrows / allocs.length).toFixed(1);
    
    // Render charts with forced data refresh
    renderBorrowPatternChart(borrowPatterns);
    
    // Force Type Memory Distribution to render with debug info
    console.log('๐Ÿ” Forcing Type Memory Distribution render with data:', allocs.length, 'allocations');
    setTimeout(() => {
        renderMemoryDistributionChart(allocs);
    }, 100);
    
    console.log('โœ… Enhanced data insights rendered:', {
        timeSpan: timeSpanMs.toFixed(2) + 'ms',
        totalBorrows,
        totalClones,
        borrowPatterns,
        allocCount: allocs.length
    });
}

// Render borrow activity heatmap (ๆ–ฐๅฅ‡็›ด่ง‚็š„ๅฏ่ง†ๅŒ–)
function renderBorrowPatternChart(patterns) {
    const container = document.getElementById('borrowPatternChart');
    if (!container) return;
    
    const data = window.analysisData || {};
    const allocs = data.memory_analysis?.allocations || data.allocations || [];
    
    // Create interactive borrow activity heatmap
    container.innerHTML = '';
    container.style.cssText = 'height: 200px; overflow-y: auto; padding: 8px; background: var(--bg-primary); border-radius: 8px; border: 1px solid var(--border-light);';
    
    // Group variables by borrow intensity
    const borrowGroups = {
        'High Activity (4i+2m)': [],
        'Normal Activity (2i+1m)': [],
        'Low Activity (0-1 borrows)': []
    };
    
    allocs.forEach(alloc => {
        const bi = alloc.borrow_info || {};
        const immut = bi.immutable_borrows || 0;
        const mut = bi.mutable_borrows || 0;
        const total = immut + mut;
        
        if (total >= 5) {
            borrowGroups['High Activity (4i+2m)'].push(alloc);
        } else if (total >= 2) {
            borrowGroups['Normal Activity (2i+1m)'].push(alloc);
        } else {
            borrowGroups['Low Activity (0-1 borrows)'].push(alloc);
        }
    });
    
    // Create visual representation
    Object.entries(borrowGroups).forEach(([groupName, groupAllocs], groupIndex) => {
        if (groupAllocs.length === 0) return;
        
        const groupDiv = document.createElement('div');
        groupDiv.style.cssText = 'margin-bottom: 12px;';
        
        const groupHeader = document.createElement('div');
        groupHeader.style.cssText = `
            font-size: 11px; font-weight: 600; margin-bottom: 6px; 
            color: var(--text-primary); display: flex; align-items: center; gap: 8px;
        `;
        
        const colors = ['#ef4444', '#f59e0b', '#10b981'];
        const icons = ['๐Ÿ”ฅ', 'โšก', '๐Ÿ’ง'];
        
        groupHeader.innerHTML = `
            <span style="font-size: 14px;">${icons[groupIndex]}</span>
            <span>${groupName}</span>
            <span style="background: ${colors[groupIndex]}; color: white; padding: 2px 6px; border-radius: 10px; font-size: 9px;">
                ${groupAllocs.length}
            </span>
        `;
        
        const bubbleContainer = document.createElement('div');
        bubbleContainer.style.cssText = `
            display: flex; flex-wrap: wrap; gap: 4px; padding: 12px; 
            background: var(--bg-secondary); border-radius: 6px; min-height: 60px;
            align-items: center; justify-content: flex-start;
        `;
        
        // Create borrow activity bubbles
        groupAllocs.forEach((alloc, index) => {
            const bi = alloc.borrow_info || {};
            const immut = bi.immutable_borrows || 0;
            const mut = bi.mutable_borrows || 0;
            const maxConcurrent = bi.max_concurrent_borrows || 0;
            
            const bubble = document.createElement('div');
            const size = Math.max(16, Math.min(32, 12 + (immut + mut) * 2));
            
            bubble.style.cssText = `
                width: ${size}px; height: ${size}px; border-radius: 50%; 
                background: linear-gradient(45deg, ${colors[groupIndex]}80, ${colors[groupIndex]});
                border: 2px solid ${colors[groupIndex]}; cursor: pointer;
                display: flex; align-items: center; justify-content: center;
                font-size: 8px; font-weight: bold; color: white;
                transition: transform 0.2s, box-shadow 0.2s;
                position: relative;
            `;
            
            bubble.textContent = immut + mut;
            bubble.title = `${alloc.var_name}: ${immut}i + ${mut}m (max: ${maxConcurrent})`;
            
            // Add interactive effects
            bubble.onmouseover = () => {
                bubble.style.transform = 'scale(1.2)';
                bubble.style.boxShadow = `0 4px 12px ${colors[groupIndex]}40`;
            };
            bubble.onmouseout = () => {
                bubble.style.transform = 'scale(1)';
                bubble.style.boxShadow = 'none';
            };
            
            // Add click to show details
            bubble.onclick = () => {
                showBorrowDetail(alloc);
            };
            
            bubbleContainer.appendChild(bubble);
        });
        
        groupDiv.appendChild(groupHeader);
        groupDiv.appendChild(bubbleContainer);
        container.appendChild(groupDiv);
    });
    
    // Add summary stats at bottom
    const summaryDiv = document.createElement('div');
    summaryDiv.style.cssText = `
        margin-top: 8px; padding: 8px; background: var(--bg-secondary); 
        border-radius: 6px; font-size: 10px; color: var(--text-secondary);
        display: flex; justify-content: space-between;
    `;
    
    const totalBorrows = allocs.reduce((sum, a) => sum + (a.borrow_info?.immutable_borrows || 0) + (a.borrow_info?.mutable_borrows || 0), 0);
    const avgBorrows = (totalBorrows / allocs.length).toFixed(1);
    const maxConcurrent = Math.max(...allocs.map(a => a.borrow_info?.max_concurrent_borrows || 0));
    
    summaryDiv.innerHTML = `
        <span>Total Borrows: <strong>${totalBorrows}</strong></span>
        <span>Avg/Variable: <strong>${avgBorrows}</strong></span>
        <span>Peak Concurrent: <strong>${maxConcurrent}</strong></span>
    `;
    
    container.appendChild(summaryDiv);
}

// Show borrow detail modal
function showBorrowDetail(alloc) {
    const modal = document.createElement('div');
    modal.style.cssText = `
        position: fixed; top: 0; left: 0; right: 0; bottom: 0; 
        background: rgba(0,0,0,0.5); z-index: 1000; 
        display: flex; align-items: center; justify-content: center;
    `;
    
    const bi = alloc.borrow_info || {};
    
    modal.innerHTML = `
        <div style="background: var(--bg-primary); border-radius: 12px; padding: 20px; min-width: 350px; border: 1px solid var(--border-light);">
            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
                <h3 style="margin: 0; color: var(--text-primary);">๐Ÿ” Borrow Analysis</h3>
                <button onclick="this.closest('div').parentNode.remove()" style="background: none; border: none; font-size: 18px; color: var(--text-secondary); cursor: pointer;">ร—</button>
            </div>
            <div style="color: var(--text-primary); line-height: 1.6;">
                <div style="margin-bottom: 12px;"><strong>Variable:</strong> ${alloc.var_name}</div>
                <div style="margin-bottom: 12px;"><strong>Type:</strong> ${alloc.type_name}</div>
                <div style="margin-bottom: 12px;"><strong>Size:</strong> ${formatBytes(alloc.size || 0)}</div>
                <hr style="border: none; border-top: 1px solid var(--border-light); margin: 16px 0;">
                <div style="margin-bottom: 8px;"><strong>๐Ÿ“– Immutable Borrows:</strong> <span style="color: var(--primary-blue); font-weight: 600;">${bi.immutable_borrows || 0}</span></div>
                <div style="margin-bottom: 8px;"><strong>โœ๏ธ Mutable Borrows:</strong> <span style="color: var(--primary-orange); font-weight: 600;">${bi.mutable_borrows || 0}</span></div>
                <div style="margin-bottom: 8px;"><strong>๐Ÿ”ฅ Max Concurrent:</strong> <span style="color: var(--primary-red); font-weight: 600;">${bi.max_concurrent_borrows || 0}</span></div>
                <div style="margin-bottom: 8px;"><strong>โšก Total Activity:</strong> <span style="color: var(--primary-green); font-weight: 600;">${(bi.immutable_borrows || 0) + (bi.mutable_borrows || 0)}</span></div>
            </div>
        </div>
    `;
    
    document.body.appendChild(modal);
    modal.onclick = (e) => { if (e.target === modal) modal.remove(); };
}

// Render type memory distribution as interactive memory blocks
function renderMemoryDistributionChart(allocs) {
    const container = document.getElementById('memoryDistributionChart');
    if (!container) return;
    
    // Create unique memory blocks visualization (not pie chart)
    container.innerHTML = '';
    
    // Group by type and sum memory
    const typeMemory = {};
    console.log('๐Ÿ” Processing allocations for memory blocks:', allocs.length);
    
    allocs.forEach((alloc, index) => {
        let typeName = alloc.type_name || 'Unknown';
        const originalType = typeName;
        const size = alloc.size || 0;
        
        // Simplify type names
        if (typeName.includes('HashMap')) {
            typeName = 'HashMap';
        } else if (typeName.includes('BTreeMap')) {
            typeName = 'BTreeMap';
        } else if (typeName.includes('Arc')) {
            typeName = 'Arc';
        } else if (typeName.includes('Rc')) {
            typeName = 'Rc';
        } else if (typeName.includes('String')) {
            typeName = 'String';
        } else if (typeName.includes('Vec')) {
            typeName = 'Vec';
        } else {
            typeName = originalType.split('::').pop() || 'Unknown';
        }
        
        if (!typeMemory[typeName]) {
            typeMemory[typeName] = { size: 0, count: 0, allocations: [] };
        }
        typeMemory[typeName].size += size;
        typeMemory[typeName].count += 1;
        typeMemory[typeName].allocations.push(alloc);
        
        console.log(`[${index}] ${originalType} -> ${typeName}: ${size} bytes`);
    });
    
    // Sort by memory size
    const sortedTypes = Object.entries(typeMemory)
        .filter(([type, data]) => data.size > 0)
        .sort((a, b) => b[1].size - a[1].size);
    
    console.log('Memory blocks data:', sortedTypes);
    
    if (sortedTypes.length === 0) {
        container.innerHTML = '<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-secondary);">No type data available</div>';
        return;
    }
    
    const totalMemory = sortedTypes.reduce((sum, [_, data]) => sum + data.size, 0);
    const colors = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#06b6d4', '#84cc16', '#f97316'];
    
    // Create memory blocks visualization
    container.innerHTML = `
        <div style="height: 100%; display: flex; flex-direction: column; gap: 8px; padding: 8px;">
            ${sortedTypes.map(([typeName, data], index) => {
                const percentage = ((data.size / totalMemory) * 100);
                const color = colors[index % colors.length];
                const blockHeight = Math.max(20, Math.min(60, percentage * 2));
                
                return `
                    <div style="display: flex; align-items: center; gap: 12px; cursor: pointer; padding: 6px; border-radius: 6px; transition: all 0.2s;"
                         onmouseover="this.style.background='var(--bg-primary)'; this.style.transform='scale(1.02)'"
                         onmouseout="this.style.background='transparent'; this.style.transform='scale(1)'"
                         onclick="showTypeDetail('${typeName}', ${JSON.stringify(data).replace(/"/g, '&quot;')})">
                        
                        <!-- Memory Block -->
                        <div style="width: 40px; height: ${blockHeight}px; background: linear-gradient(135deg, ${color}, ${color}80); 
                                    border-radius: 4px; position: relative; border: 2px solid ${color};">
                            <div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); 
                                        color: white; font-size: 8px; font-weight: bold;">
                                ${data.count}
                            </div>
                        </div>
                        
                        <!-- Type Info -->
                        <div style="flex: 1; min-width: 0;">
                            <div style="font-size: 13px; font-weight: 600; color: var(--text-primary); margin-bottom: 2px;">
                                ${typeName}
                            </div>
                            <div style="font-size: 11px; color: var(--text-secondary);">
                                ${formatBytes(data.size)} โ€ข ${data.count} allocation${data.count > 1 ? 's' : ''}
                            </div>
                        </div>
                        
                        <!-- Percentage Bar -->
                        <div style="width: 60px; text-align: right;">
                            <div style="font-size: 12px; font-weight: 600; color: ${color}; margin-bottom: 2px;">
                                ${percentage.toFixed(1)}%
                            </div>
                            <div style="width: 100%; height: 4px; background: var(--border-light); border-radius: 2px; overflow: hidden;">
                                <div style="width: ${percentage}%; height: 100%; background: ${color}; border-radius: 2px;"></div>
                            </div>
                        </div>
                    </div>
                `;
            }).join('')}
        </div>
    `;
}

// Show type detail modal
window.showTypeDetail = function(typeName, data) {
    const modal = document.createElement('div');
    modal.style.cssText = `
        position: fixed; top: 0; left: 0; right: 0; bottom: 0; 
        background: rgba(0,0,0,0.6); z-index: 1000; 
        display: flex; align-items: center; justify-content: center;
    `;
    
    const typeColors = {
        'HashMap': '#3b82f6', 'BTreeMap': '#10b981', 'Arc': '#f59e0b', 
        'Rc': '#ef4444', 'String': '#8b5cf6', 'Vec': '#06b6d4'
    };
    const color = typeColors[typeName] || '#64748b';
    
    modal.innerHTML = `
        <div style="background: var(--bg-primary); border-radius: 16px; padding: 24px; min-width: 500px; max-width: 700px; max-height: 80vh; overflow-y: auto; border: 1px solid var(--border-light);">
            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
                <h3 style="margin: 0; color: var(--text-primary); display: flex; align-items: center; gap: 12px;">
                    <div style="width: 24px; height: 24px; background: ${color}; border-radius: 4px; display: flex; align-items: center; justify-content: center; color: white; font-size: 12px; font-weight: bold;">
                        ${data.count}
                    </div>
                    ${typeName} Memory Analysis
                </h3>
                <button onclick="this.closest('div').parentNode.remove()" style="background: none; border: none; font-size: 20px; color: var(--text-secondary); cursor: pointer;">ร—</button>
            </div>
            
            <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 20px;">
                <div style="text-align: center; padding: 16px; background: var(--bg-secondary); border-radius: 8px;">
                    <div style="font-size: 1.8rem; font-weight: 700; color: ${color};">${formatBytes(data.size)}</div>
                    <div style="font-size: 0.8rem; color: var(--text-secondary);">Total Memory</div>
                </div>
                <div style="text-align: center; padding: 16px; background: var(--bg-secondary); border-radius: 8px;">
                    <div style="font-size: 1.8rem; font-weight: 700; color: var(--text-primary);">${data.count}</div>
                    <div style="font-size: 0.8rem; color: var(--text-secondary);">Allocations</div>
                </div>
                <div style="text-align: center; padding: 16px; background: var(--bg-secondary); border-radius: 8px;">
                    <div style="font-size: 1.8rem; font-weight: 700; color: var(--text-primary);">${formatBytes(data.size / data.count)}</div>
                    <div style="font-size: 0.8rem; color: var(--text-secondary);">Avg Size</div>
                </div>
            </div>
            
            <h4 style="margin: 0 0 12px 0; color: var(--text-primary);">Individual Allocations:</h4>
            <div style="max-height: 300px; overflow-y: auto; border: 1px solid var(--border-light); border-radius: 8px;">
                <table style="width: 100%; border-collapse: collapse; font-size: 12px;">
                    <thead style="background: var(--bg-secondary); position: sticky; top: 0;">
                        <tr>
                            <th style="padding: 8px; text-align: left; color: var(--text-primary);">Variable</th>
                            <th style="padding: 8px; text-align: right; color: var(--text-primary);">Size</th>
                            <th style="padding: 8px; text-align: center; color: var(--text-primary);">Status</th>
                            <th style="padding: 8px; text-align: right; color: var(--text-primary);">Lifetime</th>
                        </tr>
                    </thead>
                    <tbody>
                        ${data.allocations.map(alloc => {
                            const isLeaked = alloc.is_leaked;
                            const statusColor = isLeaked ? 'var(--primary-red)' : 'var(--primary-green)';
                            const statusText = isLeaked ? 'LEAKED' : 'OK';
                            const lifetime = alloc.lifetime_ms || 'Active';
                            
                            return `
                                <tr style="border-bottom: 1px solid var(--border-light); cursor: pointer;" onclick="showAllocationDetail('${alloc.ptr}')">
                                    <td style="padding: 8px; color: var(--text-primary); font-weight: 500;">${alloc.var_name || 'unnamed'}</td>
                                    <td style="padding: 8px; text-align: right; color: var(--text-primary); font-weight: 600;">${formatBytes(alloc.size || 0)}</td>
                                    <td style="padding: 8px; text-align: center;">
                                        <span style="color: ${statusColor}; font-weight: 600; font-size: 11px;">${statusText}</span>
                                    </td>
                                    <td style="padding: 8px; text-align: right; color: var(--text-secondary); font-size: 11px;">
                                        ${typeof lifetime === 'number' ? lifetime.toFixed(2) + 'ms' : lifetime}
                                    </td>
                                </tr>
                            `;
                        }).join('')}
                    </tbody>
                </table>
            </div>
        </div>
    `;
    
    document.body.appendChild(modal);
    modal.onclick = (e) => { if (e.target === modal) modal.remove(); };
};

// Render detailed allocation timeline with heap/stack and timing info
function renderAllocationTimelineDetail() {
    const container = document.getElementById('allocationTimelineDetail');
    if (!container) return;
    
    const data = window.analysisData || {};
    const allocs = data.memory_analysis?.allocations || data.allocations || [];
    
    if (allocs.length === 0) {
        container.innerHTML = '<div style="text-align: center; color: var(--text-secondary); margin-top: 80px;">No allocation data available</div>';
        return;
    }
    
    // Sort by allocation time
    const sortedAllocs = allocs.slice().sort((a, b) => (a.timestamp_alloc || 0) - (b.timestamp_alloc || 0));
    const minTime = sortedAllocs[0].timestamp_alloc || 0;
    
    // Classify allocations as heap/stack
    const classifyAllocation = (typeName) => {
        const heapIndicators = ['Arc', 'Rc', 'Box', 'Vec', 'HashMap', 'BTreeMap', 'String'];
        const stackIndicators = ['&', 'i32', 'u32', 'i64', 'u64', 'f32', 'f64', 'bool', 'char'];
        
        if (heapIndicators.some(indicator => typeName.includes(indicator))) {
            return { type: 'heap', color: '#ef4444', icon: '๐Ÿ—๏ธ' };
        } else if (stackIndicators.some(indicator => typeName.includes(indicator))) {
            return { type: 'stack', color: '#10b981', icon: '๐Ÿ“š' };
        } else {
            return { type: 'unknown', color: '#64748b', icon: 'โ“' };
        }
    };
    
    container.innerHTML = `
        <div style="display: flex; flex-direction: column; gap: 4px; height: 100%;">
            ${sortedAllocs.slice(0, 15).map((alloc, index) => {
                const allocTime = alloc.timestamp_alloc || 0;
                const lifetime = alloc.lifetime_ms || 0;
                const dropTime = allocTime + (lifetime * 1_000_000); // Convert ms to ns
                const relativeTime = ((allocTime - minTime) / 1_000_000).toFixed(2); // Convert to ms
                
                const classification = classifyAllocation(alloc.type_name || '');
                const typeName = (alloc.type_name || 'Unknown').split('::').pop().split('<')[0];
                
                return `
                    <div style="display: flex; align-items: center; gap: 8px; padding: 6px; border-radius: 4px; cursor: pointer; transition: all 0.2s;"
                         onmouseover="this.style.background='var(--bg-primary)'"
                         onmouseout="this.style.background='transparent'"
                         onclick="showAllocationTimeDetail('${alloc.ptr}', ${allocTime}, ${dropTime}, '${classification.type}')">
                        
                        <!-- Allocation Type Icon -->
                        <div style="width: 24px; height: 24px; background: ${classification.color}20; border: 1px solid ${classification.color}; border-radius: 4px; display: flex; align-items: center; justify-content: center; font-size: 12px;">
                            ${classification.icon}
                        </div>
                        
                        <!-- Variable Info -->
                        <div style="flex: 1; min-width: 0;">
                            <div style="font-size: 11px; font-weight: 600; color: var(--text-primary); margin-bottom: 1px;">
                                ${alloc.var_name || 'unnamed'} (${typeName})
                            </div>
                            <div style="font-size: 9px; color: var(--text-secondary);">
                                ${formatBytes(alloc.size || 0)} โ€ข ${classification.type.toUpperCase()}
                            </div>
                        </div>
                        
                        <!-- Timing Info -->
                        <div style="text-align: right; font-size: 9px;">
                            <div style="color: var(--primary-blue); font-weight: 600;">+${relativeTime}ms</div>
                            <div style="color: var(--text-secondary);">โ†’ ${lifetime}ms</div>
                        </div>
                    </div>
                `;
            }).join('')}
            
            ${sortedAllocs.length > 15 ? `
                <div style="text-align: center; padding: 8px; color: var(--text-secondary); font-size: 10px; border-top: 1px solid var(--border-light);">
                    ... and ${sortedAllocs.length - 15} more allocations
                </div>
            ` : ''}
        </div>
    `;
}

// Show detailed allocation timing modal
window.showAllocationTimeDetail = function(ptr, allocTime, dropTime, allocationType) {
    const data = window.analysisData || {};
    const allocs = data.memory_analysis?.allocations || data.allocations || [];
    const alloc = allocs.find(a => a.ptr === ptr);
    
    if (!alloc) return;
    
    const modal = document.createElement('div');
    modal.style.cssText = `
        position: fixed; top: 0; left: 0; right: 0; bottom: 0; 
        background: rgba(0,0,0,0.6); z-index: 1000; 
        display: flex; align-items: center; justify-content: center;
    `;
    
    const allocDate = new Date(allocTime / 1_000_000);
    const dropDate = new Date(dropTime / 1_000_000);
    const typeColor = allocationType === 'heap' ? '#ef4444' : allocationType === 'stack' ? '#10b981' : '#64748b';
    const typeIcon = allocationType === 'heap' ? '๐Ÿ—๏ธ' : allocationType === 'stack' ? '๐Ÿ“š' : 'โ“';
    
    modal.innerHTML = `
        <div style="background: var(--bg-primary); border-radius: 16px; padding: 24px; min-width: 500px; color: var(--text-primary); border: 1px solid var(--border-light);">
            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
                <h3 style="margin: 0; display: flex; align-items: center; gap: 12px;">
                    <span style="font-size: 24px;">${typeIcon}</span>
                    ${allocationType.toUpperCase()} Allocation Timeline
                </h3>
                <button onclick="this.closest('div').parentNode.remove()" style="background: none; border: none; font-size: 20px; color: var(--text-secondary); cursor: pointer;">ร—</button>
            </div>
            
            <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 20px;">
                <div style="padding: 16px; background: var(--bg-secondary); border-radius: 8px;">
                    <div style="font-size: 12px; color: var(--text-secondary); margin-bottom: 4px;">Variable</div>
                    <div style="font-size: 16px; font-weight: 600;">${alloc.var_name || 'unnamed'}</div>
                </div>
                <div style="padding: 16px; background: var(--bg-secondary); border-radius: 8px;">
                    <div style="font-size: 12px; color: var(--text-secondary); margin-bottom: 4px;">Type</div>
                    <div style="font-size: 14px; font-weight: 600; word-break: break-all;">${alloc.type_name || 'Unknown'}</div>
                </div>
            </div>
            
            <div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; margin-bottom: 20px;">
                <div style="text-align: center; padding: 16px; background: var(--bg-secondary); border-radius: 8px;">
                    <div style="font-size: 18px; font-weight: 700; color: ${typeColor};">${formatBytes(alloc.size || 0)}</div>
                    <div style="font-size: 12px; color: var(--text-secondary);">Size</div>
                </div>
                <div style="text-align: center; padding: 16px; background: var(--bg-secondary); border-radius: 8px;">
                    <div style="font-size: 18px; font-weight: 700; color: var(--primary-blue);">${alloc.lifetime_ms || 0}ms</div>
                    <div style="font-size: 12px; color: var(--text-secondary);">Lifetime</div>
                </div>
                <div style="text-align: center; padding: 16px; background: var(--bg-secondary); border-radius: 8px;">
                    <div style="font-size: 18px; font-weight: 700; color: ${typeColor};">${allocationType.toUpperCase()}</div>
                    <div style="font-size: 12px; color: var(--text-secondary);">Location</div>
                </div>
            </div>
            
            <div style="background: var(--bg-secondary); padding: 16px; border-radius: 8px;">
                <h4 style="margin: 0 0 12px 0; color: var(--text-primary);">Timeline Details</h4>
                <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px;">
                    <div>
                        <div style="font-size: 12px; color: var(--text-secondary); margin-bottom: 4px;">๐ŸŸข Allocated At</div>
                        <div style="font-size: 14px; font-weight: 600; color: var(--primary-green);">${allocDate.toLocaleString()}</div>
                        <div style="font-size: 11px; color: var(--text-secondary); margin-top: 2px;">Timestamp: ${allocTime}</div>
                    </div>
                    <div>
                        <div style="font-size: 12px; color: var(--text-secondary); margin-bottom: 4px;">๐Ÿ”ด Dropped At</div>
                        <div style="font-size: 14px; font-weight: 600; color: var(--primary-red);">${dropDate.toLocaleString()}</div>
                        <div style="font-size: 11px; color: var(--text-secondary); margin-top: 2px;">Timestamp: ${dropTime}</div>
                    </div>
                </div>
            </div>
        </div>
    `;
    
    document.body.appendChild(modal);
    modal.onclick = (e) => { if (e.target === modal) modal.remove(); };
};

// Update lifecycle statistics and render distribution chart
function updateLifecycleStatistics() {
    const data = window.analysisData || {};
    const allocs = data.memory_analysis?.allocations || data.allocations || [];
    
    if (allocs.length === 0) return;
    
    // Calculate lifecycle statistics
    const activeVars = allocs.filter(a => !a.is_leaked && a.lifetime_ms === undefined).length;
    const freedVars = allocs.filter(a => !a.is_leaked && a.lifetime_ms !== undefined).length;
    const leakedVars = allocs.filter(a => a.is_leaked).length;
    const avgLifetime = allocs.filter(a => a.lifetime_ms).reduce((sum, a) => sum + a.lifetime_ms, 0) / Math.max(1, allocs.filter(a => a.lifetime_ms).length);
    
    // Update statistics display
    document.getElementById('active-vars').textContent = activeVars;
    document.getElementById('freed-vars').textContent = freedVars;
    document.getElementById('leaked-vars').textContent = leakedVars;
    document.getElementById('avg-lifetime-stat').textContent = avgLifetime.toFixed(2) + 'ms';
    
    // Render lifecycle distribution chart
    renderLifecycleDistributionChart(allocs);
}

// Render lifecycle distribution chart
function renderLifecycleDistributionChart(allocs) {
    const ctx = document.getElementById('lifecycleDistributionChart');
    if (!ctx || !window.Chart) return;
    
    // Cleanup existing chart
    if (window.chartInstances && window.chartInstances['lifecycleDistributionChart']) {
        try { window.chartInstances['lifecycleDistributionChart'].destroy(); } catch(_) {}
        delete window.chartInstances['lifecycleDistributionChart'];
    }
    
    // Group allocations by lifetime ranges
    const lifetimeRanges = {
        'Instant (0ms)': 0,
        'Quick (0-1ms)': 0,
        'Short (1-10ms)': 0,
        'Long (10ms+)': 0,
        'Active': 0
    };
    
    allocs.forEach(alloc => {
        const lifetime = alloc.lifetime_ms;
        if (lifetime === undefined) {
            lifetimeRanges['Active']++;
        } else if (lifetime === 0) {
            lifetimeRanges['Instant (0ms)']++;
        } else if (lifetime <= 1) {
            lifetimeRanges['Quick (0-1ms)']++;
        } else if (lifetime <= 10) {
            lifetimeRanges['Short (1-10ms)']++;
        } else {
            lifetimeRanges['Long (10ms+)']++;
        }
    });
    
    const labels = Object.keys(lifetimeRanges);
    const values = Object.values(lifetimeRanges);
    const colors = ['#ef4444', '#f59e0b', '#10b981', '#3b82f6', '#8b5cf6'];
    
    if (values.some(v => v > 0)) {
        const chart = new Chart(ctx, {
            type: 'bar',
            data: {
                labels: labels,
                datasets: [{
                    data: values,
                    backgroundColor: colors,
                    borderWidth: 1,
                    borderColor: colors.map(c => c + '80')
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: { display: false },
                    tooltip: {
                        callbacks: {
                            label: (context) => {
                                const range = context.label;
                                const count = context.parsed.y;
                                const total = context.dataset.data.reduce((a, b) => a + b, 0);
                                const percentage = ((count / total) * 100).toFixed(1);
                                return `${range}: ${count} vars (${percentage}%)`;
                            }
                        }
                    }
                },
                scales: {
                    x: {
                        ticks: {
                            font: { size: 9 },
                            color: function(context) {
                                return document.documentElement.classList.contains('dark-theme') ? '#cbd5e1' : '#64748b';
                            },
                            maxRotation: 45
                        },
                        grid: { display: false }
                    },
                    y: {
                        beginAtZero: true,
                        ticks: {
                            font: { size: 9 },
                            color: function(context) {
                                return document.documentElement.classList.contains('dark-theme') ? '#cbd5e1' : '#64748b';
                            }
                        },
                        grid: {
                            color: function(context) {
                                return document.documentElement.classList.contains('dark-theme') ? '#374151' : '#e2e8f0';
                            }
                        }
                    }
                }
            }
        });
        
        window.chartInstances = window.chartInstances || {};
        window.chartInstances['lifecycleDistributionChart'] = chart;
    }
}

// Render memory hotspots visualization
function renderMemoryHotspots() {
    const container = document.getElementById('memoryHotspots');
    if (!container) return;
    
    const data = window.analysisData || {};
    const allocs = data.memory_analysis?.allocations || data.allocations || [];
    
    if (allocs.length === 0) {
        container.innerHTML = '<div style="text-align: center; color: var(--text-secondary); margin-top: 100px;">No allocation data available</div>';
        return;
    }
    
    // Sort allocations by size to identify hotspots
    const sortedAllocs = allocs.slice().sort((a, b) => (b.size || 0) - (a.size || 0));
    const topHotspots = sortedAllocs.slice(0, 10); // Top 10 largest allocations
    
    container.innerHTML = '';
    
    // Create hotspot visualization
    topHotspots.forEach((alloc, index) => {
        const size = alloc.size || 0;
        const maxSize = sortedAllocs[0].size || 1;
        const intensity = (size / maxSize) * 100;
        
        const hotspotDiv = document.createElement('div');
        hotspotDiv.style.cssText = `
            display: flex; align-items: center; padding: 8px; margin-bottom: 6px;
            background: linear-gradient(90deg, var(--bg-primary) 0%, var(--primary-red)${Math.floor(intensity/4)} ${intensity}%, var(--bg-primary) 100%);
            border-radius: 6px; border: 1px solid var(--border-light);
            cursor: pointer; transition: transform 0.2s;
        `;
        
        const heatColor = intensity > 80 ? '#ef4444' : intensity > 60 ? '#f59e0b' : intensity > 40 ? '#10b981' : '#3b82f6';
        
        hotspotDiv.innerHTML = `
            <div style="width: 24px; height: 24px; border-radius: 50%; background: ${heatColor}; 
                        display: flex; align-items: center; justify-content: center; margin-right: 12px;
                        font-size: 10px; font-weight: bold; color: white;">
                ${index + 1}
            </div>
            <div style="flex: 1;">
                <div style="font-size: 12px; font-weight: 600; color: var(--text-primary);">
                    ${alloc.var_name || 'unnamed'}
                </div>
                <div style="font-size: 10px; color: var(--text-secondary);">
                    ${(alloc.type_name || 'Unknown').replace(/std::|alloc::/g, '').substring(0, 30)}...
                </div>
            </div>
            <div style="text-align: right;">
                <div style="font-size: 12px; font-weight: 700; color: ${heatColor};">
                    ${formatBytes(size)}
                </div>
                <div style="font-size: 9px; color: var(--text-secondary);">
                    ${intensity.toFixed(1)}% of max
                </div>
            </div>
        `;
        
        hotspotDiv.onmouseover = () => {
            hotspotDiv.style.transform = 'scale(1.02)';
            hotspotDiv.style.boxShadow = `0 4px 12px ${heatColor}40`;
        };
        hotspotDiv.onmouseout = () => {
            hotspotDiv.style.transform = 'scale(1)';
            hotspotDiv.style.boxShadow = 'none';
        };
        
        hotspotDiv.onclick = () => {
            showAllocationDetail(alloc.ptr);
        };
        
        container.appendChild(hotspotDiv);
    });
    
    // Add summary at bottom
    const summaryDiv = document.createElement('div');
    summaryDiv.style.cssText = `
        margin-top: 12px; padding: 8px; background: var(--bg-primary); 
        border-radius: 6px; font-size: 10px; color: var(--text-secondary);
        text-align: center; border: 1px solid var(--border-light);
    `;
    
    const totalHotspotMemory = topHotspots.reduce((sum, a) => sum + (a.size || 0), 0);
    const totalMemory = allocs.reduce((sum, a) => sum + (a.size || 0), 0);
    const hotspotPercentage = ((totalHotspotMemory / totalMemory) * 100).toFixed(1);
    
    summaryDiv.innerHTML = `
        Top ${topHotspots.length} hotspots: <strong>${formatBytes(totalHotspotMemory)}</strong> 
        (${hotspotPercentage}% of total memory)
    `;
    
    container.appendChild(summaryDiv);
}

// Render thread analysis
function renderThreadAnalysis() {
    const data = window.analysisData || {};
    const allocs = data.memory_analysis?.allocations || data.allocations || [];
    
    // Update thread timeline
    renderThreadTimeline(allocs);
    
    // Update contention analysis
    updateContentionAnalysis(allocs);
}

// Render thread timeline
function renderThreadTimeline(allocs) {
    const container = document.getElementById('threadTimeline');
    if (!container) return;
    
    container.innerHTML = '';
    
    // Get unique threads
    const threads = [...new Set(allocs.map(a => a.thread_id).filter(t => t))];
    
    if (threads.length <= 1) {
        // Single thread visualization
        container.innerHTML = `
            <div style="display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-secondary);">
                <div style="text-align: center;">
                    <div style="font-size: 14px; margin-bottom: 4px;">๐Ÿงต</div>
                    <div style="font-size: 10px;">Single Thread</div>
                    <div style="font-size: 9px;">ThreadId(${threads[0] || 1})</div>
                </div>
            </div>
        `;
        return;
    }
    
    // Multi-thread visualization (if applicable)
    threads.forEach((threadId, index) => {
        const threadAllocs = allocs.filter(a => a.thread_id === threadId);
        const threadDiv = document.createElement('div');
        threadDiv.style.cssText = `
            height: ${100/threads.length}%; display: flex; align-items: center; 
            padding: 0 8px; border-bottom: 1px solid var(--border-light);
        `;
        
        threadDiv.innerHTML = `
            <div style="width: 60px; font-size: 9px; color: var(--text-secondary);">
                Thread ${threadId}
            </div>
            <div style="flex: 1; height: 4px; background: var(--bg-secondary); border-radius: 2px; position: relative;">
                <div style="height: 100%; background: var(--primary-blue); border-radius: 2px; width: ${(threadAllocs.length / allocs.length) * 100}%;"></div>
            </div>
            <div style="width: 40px; text-align: right; font-size: 9px; color: var(--text-primary);">
                ${threadAllocs.length}
            </div>
        `;
        
        container.appendChild(threadDiv);
    });
}

// Update contention analysis
function updateContentionAnalysis(allocs) {
    const levelEl = document.getElementById('contention-level');
    const detailsEl = document.getElementById('contention-details');
    
    if (!levelEl || !detailsEl) return;
    
    // Calculate contention metrics
    const maxConcurrentBorrows = Math.max(...allocs.map(a => a.borrow_info?.max_concurrent_borrows || 0));
    const avgConcurrentBorrows = allocs.reduce((sum, a) => sum + (a.borrow_info?.max_concurrent_borrows || 0), 0) / allocs.length;
    
    let level = 'LOW';
    let color = 'var(--primary-green)';
    let details = 'Single-threaded';
    
    if (maxConcurrentBorrows > 5) {
        level = 'HIGH';
        color = 'var(--primary-red)';
        details = `Max ${maxConcurrentBorrows} concurrent`;
    } else if (maxConcurrentBorrows > 2) {
        level = 'MEDIUM';
        color = 'var(--primary-orange)';
        details = `Avg ${avgConcurrentBorrows.toFixed(1)} concurrent`;
    }
    
    levelEl.textContent = level;
    levelEl.style.color = color;
    detailsEl.textContent = details;
}

// Update Performance Metrics and Thread Safety Analysis
function updateEnhancedMetrics() {
    const data = window.analysisData || {};
    const allocs = data.memory_analysis?.allocations || data.allocations || [];
    
    if (allocs.length === 0) return;
    
    // Calculate Performance Metrics
    const totalMemory = allocs.reduce((sum, a) => sum + (a.size || 0), 0);
    const peakMemory = Math.max(...allocs.map(a => a.size || 0));
    const timestamps = allocs.map(a => a.timestamp_alloc).filter(t => t).sort((a, b) => a - b);
    const timeRangeNs = timestamps.length > 1 ? timestamps[timestamps.length - 1] - timestamps[0] : 1e9;
    const allocationRate = allocs.length / (timeRangeNs / 1e9); // allocations per second
    const avgLifetime = allocs.filter(a => a.lifetime_ms).reduce((sum, a) => sum + a.lifetime_ms, 0) / Math.max(1, allocs.filter(a => a.lifetime_ms).length);
    
    // Simple fragmentation calculation: variance in allocation sizes
    const avgSize = totalMemory / allocs.length;
    const variance = allocs.reduce((sum, a) => sum + Math.pow((a.size || 0) - avgSize, 2), 0) / allocs.length;
    const fragmentation = Math.min(100, (Math.sqrt(variance) / avgSize) * 100);

    // Update Performance Metrics
    const peakEl = document.getElementById('peak-memory');
    const rateEl = document.getElementById('allocation-rate');
    const lifetimeEl = document.getElementById('avg-lifetime');
    const fragEl = document.getElementById('fragmentation');
    
    if (peakEl) peakEl.textContent = formatBytes(peakMemory);
    if (rateEl) rateEl.textContent = allocationRate.toFixed(1) + '/sec';
    if (lifetimeEl) lifetimeEl.textContent = avgLifetime.toFixed(2) + 'ms';
    if (fragEl) fragEl.textContent = fragmentation.toFixed(1) + '%';

    // Calculate Thread Safety Analysis
    const arcCount = allocs.filter(a => (a.type_name || '').includes('Arc')).length;
    const rcCount = allocs.filter(a => (a.type_name || '').includes('Rc')).length;
    const collectionsCount = allocs.filter(a => {
        const type = a.type_name || '';
        return type.includes('HashMap') || type.includes('BTreeMap') || type.includes('Vec') || type.includes('HashSet');
    }).length;

    // Update Thread Safety Analysis
    const arcEl = document.getElementById('arc-count');
    const rcEl = document.getElementById('rc-count');
    const collEl = document.getElementById('collections-count');
    
    if (arcEl) arcEl.textContent = arcCount;
    if (rcEl) rcEl.textContent = rcCount;
    if (collEl) collEl.textContent = collectionsCount;
    
    console.log('โœ… Enhanced metrics updated:', {
        peakMemory: formatBytes(peakMemory),
        allocationRate: allocationRate.toFixed(1) + '/sec',
        avgLifetime: avgLifetime.toFixed(2) + 'ms',
        fragmentation: fragmentation.toFixed(1) + '%',
        arcCount, rcCount, collectionsCount
    });
}

// Enhanced chart rendering with comprehensive cleanup
function renderEnhancedCharts() {
    const data = window.analysisData || {};
    
    // Step 1: Destroy all Chart.js instances globally
    if (window.Chart && window.Chart.instances) {
        Object.keys(window.Chart.instances).forEach(id => {
            try {
                window.Chart.instances[id].destroy();
            } catch(e) {
                console.warn('Failed to destroy Chart.js instance:', id, e);
            }
        });
    }
    
    // Step 2: Destroy our tracked instances
    if (window.chartInstances) {
        Object.keys(window.chartInstances).forEach(chartId => {
            try {
                window.chartInstances[chartId].destroy();
                delete window.chartInstances[chartId];
            } catch(e) {
                console.warn('Failed to destroy tracked chart:', chartId, e);
            }
        });
    }
    window.chartInstances = {};
    
    // Step 3: Clear canvas contexts manually
    ['typeChart', 'timelineChart', 'ffi-risk-chart'].forEach(canvasId => {
        const canvas = document.getElementById(canvasId);
        if (canvas && canvas.getContext) {
            try {
                const ctx = canvas.getContext('2d');
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                // Remove Chart.js specific properties
                delete canvas.chart;
                canvas.removeAttribute('style');
            } catch(e) {
                console.warn('Failed to clear canvas:', canvasId, e);
            }
        }
    });
    
    // Step 4: Force garbage collection hint
    if (window.gc) { try { window.gc(); } catch(_) {} }
    
    // Step 5: Small delay to ensure cleanup, then create new charts
    setTimeout(() => {
        initEnhancedTypeChart(data);
        initTimelineChart(data);
    }, 10);
}

document.addEventListener("DOMContentLoaded", () => {
    console.log('๐Ÿš€ MemScope Dashboard Loaded');
    
    // Initialize theme toggle
    try { 
        initThemeToggle(); 
        console.log('โœ… Theme toggle initialized');
    } catch(e) { 
        console.warn('โš ๏ธ Theme toggle initialization failed:', e?.message); 
    }
    
    // Initialize main dashboard with all original functions
    try { 
        // Use original dashboard functions
        renderKpis();
        renderTypeChart();
        renderTimelineChart();
        renderTreemap();
        renderLifetimes();
        updateEnhancedMetrics();
        renderEnhancedCharts();
        renderMemoryFragmentation();
        renderEnhancedDataInsights();
        renderAllocationTimelineDetail();
        updateLifecycleStatistics();
        renderMemoryHotspots();
        renderThreadAnalysis();
        populateAllocationsTable();
        populateUnsafeTable();
        renderVariableGraph();
        initEnhancedFFIVisualization();
        setupLifecycleVisualization();
        setupLifecycleToggle();
        
        // Optional hooks (no-op if undefined)
        try { updateEmbeddedFFISVG && updateEmbeddedFFISVG(); } catch(_) {}
        try { updatePerformanceMetrics && updatePerformanceMetrics(); } catch(_) {}
        
        console.log('โœ… All dashboard components initialized');
    } catch(e) { 
        console.error('โŒ Dashboard initialization failed:', e); 
    }
});

// Setup FFI flow visualization interactivity
function setupFFIFlowInteractivity(allocs) {
    // Add click handlers to FFI flow nodes
    setTimeout(() => {
        const rustNodes = document.querySelectorAll('.rust-node');
        const ffiNodes = document.querySelectorAll('.ffi-node');
        
        [...rustNodes, ...ffiNodes].forEach(node => {
            node.addEventListener('click', (e) => {
                const ptr = e.target.getAttribute('data-ptr');
                const size = e.target.getAttribute('data-size');
                showFFIFlowNodeDetail(ptr, size, allocs);
            });
            
            node.addEventListener('mouseover', (e) => {
                e.target.style.transform = 'scale(1.3)';
                e.target.style.filter = 'drop-shadow(0 0 8px currentColor)';
            });
            
            node.addEventListener('mouseout', (e) => {
                e.target.style.transform = 'scale(1)';
                e.target.style.filter = 'none';
            });
        });
        
        // Setup flow animation toggle
        const flowToggle = document.getElementById('ffi-flow-toggle');
        if (flowToggle) {
            let isAnimating = true;
            flowToggle.onclick = () => {
                const particles = document.querySelectorAll('#flow-particles circle');
                const flows = document.querySelectorAll('#data-flows path');
                
                if (isAnimating) {
                    // Pause animations
                    [...particles, ...flows].forEach(el => {
                        el.style.animationPlayState = 'paused';
                    });
                    flowToggle.innerHTML = '<i class="fa fa-pause"></i> Paused';
                    flowToggle.style.background = 'var(--primary-red)';
                    isAnimating = false;
                } else {
                    // Resume animations
                    [...particles, ...flows].forEach(el => {
                        el.style.animationPlayState = 'running';
                    });
                    flowToggle.innerHTML = '<i class="fa fa-play"></i> Animate';
                    flowToggle.style.background = 'var(--primary-green)';
                    isAnimating = true;
                }
            };
        }
    }, 100);
}

// Show FFI flow node detail
function showFFIFlowNodeDetail(ptr, size, allocs) {
    const alloc = allocs.find(a => a.ptr === ptr);
    if (!alloc) return;
    
    const modal = document.createElement('div');
    modal.style.cssText = `
        position: fixed; top: 0; left: 0; right: 0; bottom: 0; 
        background: rgba(0,0,0,0.6); z-index: 1000; 
        display: flex; align-items: center; justify-content: center;
    `;
    
    const isFFI = alloc.ffi_tracked;
    const bgGradient = isFFI ? 'linear-gradient(135deg, #1e40af, #3b82f6)' : 'linear-gradient(135deg, #ea580c, #f97316)';
    const icon = isFFI ? 'โš™๏ธ' : '๐Ÿฆ€';
    const title = isFFI ? 'FFI Allocation' : 'Rust Allocation';
    
    modal.innerHTML = `
        <div style="background: ${bgGradient}; border-radius: 16px; padding: 24px; min-width: 400px; color: white; position: relative; overflow: hidden;">
            <div style="position: absolute; top: -50px; right: -50px; font-size: 120px; opacity: 0.1;">${icon}</div>
            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; position: relative; z-index: 1;">
                <h3 style="margin: 0; font-size: 18px;">${icon} ${title}</h3>
                <button onclick="this.closest('div').parentNode.remove()" style="background: rgba(255,255,255,0.2); border: none; border-radius: 50%; width: 32px; height: 32px; color: white; cursor: pointer; font-size: 16px;">ร—</button>
            </div>
            <div style="position: relative; z-index: 1; line-height: 1.8;">
                <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px;">
                    <div style="background: rgba(255,255,255,0.1); padding: 12px; border-radius: 8px;">
                        <div style="font-size: 12px; opacity: 0.8;">Variable</div>
                        <div style="font-weight: 600;">${alloc.var_name || 'unnamed'}</div>
                    </div>
                    <div style="background: rgba(255,255,255,0.1); padding: 12px; border-radius: 8px;">
                        <div style="font-size: 12px; opacity: 0.8;">Size</div>
                        <div style="font-weight: 600; font-size: 16px;">${formatBytes(alloc.size || 0)}</div>
                    </div>
                </div>
                <div style="background: rgba(255,255,255,0.1); padding: 12px; border-radius: 8px; margin-bottom: 16px;">
                    <div style="font-size: 12px; opacity: 0.8; margin-bottom: 4px;">Type</div>
                    <div style="font-weight: 600; font-size: 14px; word-break: break-all;">${alloc.type_name || 'Unknown'}</div>
                </div>
                <div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px;">
                    <div style="text-align: center; background: rgba(255,255,255,0.1); padding: 8px; border-radius: 6px;">
                        <div style="font-size: 16px; font-weight: 700;">${(alloc.borrow_info?.immutable_borrows || 0) + (alloc.borrow_info?.mutable_borrows || 0)}</div>
                        <div style="font-size: 10px; opacity: 0.8;">Borrows</div>
                    </div>
                    <div style="text-align: center; background: rgba(255,255,255,0.1); padding: 8px; border-radius: 6px;">
                        <div style="font-size: 16px; font-weight: 700;">${alloc.clone_info?.clone_count || 0}</div>
                        <div style="font-size: 10px; opacity: 0.8;">Clones</div>
                    </div>
                    <div style="text-align: center; background: rgba(255,255,255,0.1); padding: 8px; border-radius: 6px;">
                        <div style="font-size: 16px; font-weight: 700;">${alloc.thread_id || 1}</div>
                        <div style="font-size: 10px; opacity: 0.8;">Thread</div>
                    </div>
                </div>
            </div>
        </div>
    `;
    
    document.body.appendChild(modal);
    modal.onclick = (e) => { if (e.target === modal) modal.remove(); };
}

"#;