(function () {
	'use strict';

	if (typeof epDebugData === 'undefined') return;

	var D = epDebugData;

	/* ── Helpers ──────────────────────────────────────────── */

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

	function perfClass(ms, ok, bad) {
		if (ms >= bad) return 'epd-perf-bad';
		if (ms >= ok) return 'epd-perf-ok';
		return 'epd-perf-good';
	}

	function esc(str) {
		var d = document.createElement('div');
		d.textContent = str;
		return d.innerHTML;
	}

	function getResourceDetails() {
		var entries = {};
		if (window.performance && performance.getEntriesByType) {
			var res = performance.getEntriesByType('resource');
			for (var i = 0; i < res.length; i++) {
				var r = res[i];
				var cached = r.transferSize === 0 && r.decodedBodySize > 0;
				entries[r.name] = {
					transferSize: r.transferSize || 0,
					decodedSize: r.decodedBodySize || 0,
					encodedSize: r.encodedBodySize || 0,
					duration: Math.round(r.duration),
					cached: cached,
					protocol: r.nextHopProtocol || '',
				};
			}
		}
		return entries;
	}

	function getPageTiming() {
		var t = {};
		if (window.performance && performance.timing) {
			var pt = performance.timing;
			t.domReady = pt.domContentLoadedEventEnd - pt.navigationStart;
			t.windowLoad = pt.loadEventEnd > 0 ? pt.loadEventEnd - pt.navigationStart : null;
			t.ttfb = pt.responseStart - pt.navigationStart;
			t.domInteractive = pt.domInteractive - pt.navigationStart;
		}
		if (window.performance && performance.getEntriesByType) {
			var paint = performance.getEntriesByType('paint');
			for (var i = 0; i < paint.length; i++) {
				if (paint[i].name === 'first-contentful-paint') {
					t.fcp = Math.round(paint[i].startTime);
				}
			}
		}
		t.domNodes = document.querySelectorAll('*').length;
		return t;
	}

	function scanDOMWidgets() {
		var widgets = [];
		var els = document.querySelectorAll('.elementor-widget[data-widget_type]');
		for (var i = 0; i < els.length; i++) {
			var el = els[i];
			var fullType = el.getAttribute('data-widget_type') || '';
			var elId = el.getAttribute('data-id') || '';
			if (!fullType) continue;
			var parts = fullType.split('.');
			var name = parts[0];
			var nodes = el.querySelectorAll('*').length;
			var htmlBytes = 0;
			try { htmlBytes = el.outerHTML.length * 2; } catch (e) {}
			widgets.push({
				name: name,
				skin: parts[1] || 'default',
				id: elId,
				isEP: name.indexOf('bdt-') === 0 || name.indexOf('ep-') === 0,
				nodes: nodes,
				htmlSize: htmlBytes
			});
		}
		return widgets;
	}

	function findJsEntryById(elementId) {
		var jsData = window.epDebugJS;
		if (!jsData || !jsData.widgets || !jsData.widgets.length) return null;
		for (var i = 0; i < jsData.widgets.length; i++) {
			if (jsData.widgets[i].elId === elementId) return jsData.widgets[i];
		}
		return null;
	}

	/* ── Widget Inspect ──────────────────────────────────── */

	function inspectWidget(elementId) {
		var el = document.querySelector('[data-id="' + elementId + '"]');
		if (!el) return;

		el.classList.remove('epd-inspect-highlight');
		if (el._epdTimer) clearTimeout(el._epdTimer);

		el.scrollIntoView({ behavior: 'smooth', block: 'center' });

		requestAnimationFrame(function () {
			requestAnimationFrame(function () {
				el.classList.add('epd-inspect-highlight');
				el._epdTimer = setTimeout(function () {
					el.classList.remove('epd-inspect-highlight');
				}, 2500);
			});
		});
	}

	/* ── Build Panel HTML ────────────────────────────────── */

	function buildPanel() {
		var timing = getPageTiming();
		var resDetails = getResourceDetails();
		var jsData = window.epDebugJS || { widgets: [], pageStart: 0 };

		var domWidgets = scanDOMWidgets();
		var isEditorPreview = D.widgets.count === 0 && domWidgets.length > 0;

		var phpLookup = {};
		for (var pi = 0; pi < D.widgets.items.length; pi++) {
			phpLookup[D.widgets.items[pi].id] = D.widgets.items[pi];
		}

		var effectiveWidgetCount = Math.max(domWidgets.length, D.widgets.count);

		var memPct = D.page.memory_limit > 0
			? Math.round((D.page.memory_usage / D.page.memory_limit) * 100) : 0;

		var html = '';

		html += '<div class="epd-resize"></div>';

		// Header
		html += '<div class="epd-header">';
		html += '<span class="epd-header-title">Element Pack Debug</span>';
		html += '<div class="epd-header-stats">';
		html += '<span class="epd-stat"><span class="epd-stat-label">PHP:</span> <span class="epd-stat-value ' + perfClass(D.page.total_time, 1000, 3000) + '">' + D.page.total_time + 'ms</span></span>';
		html += '<span class="epd-stat"><span class="epd-stat-label">Mem:</span> <span class="epd-stat-value">' + fmt(D.page.memory_usage) + '</span></span>';
		html += '<span class="epd-stat"><span class="epd-stat-label">Queries:</span> <span class="epd-stat-value">' + D.page.db_queries_total + '</span></span>';
		html += '<span class="epd-stat"><span class="epd-stat-label">Widgets:</span> <span class="epd-stat-value">' + effectiveWidgetCount + '</span></span>';
		if (timing.fcp) {
			html += '<span class="epd-stat"><span class="epd-stat-label">FCP:</span> <span class="epd-stat-value ' + perfClass(timing.fcp, 1800, 3000) + '">' + timing.fcp + 'ms</span></span>';
		}
		html += '</div>';
		html += '<button class="epd-close" title="Close">&times;</button>';
		html += '</div>';

		// Tabs
		html += '<div class="epd-tabs">';
		html += '<div class="epd-tab active" data-tab="overview">Overview</div>';
		html += '<div class="epd-tab" data-tab="widgets">Widgets <span class="epd-badge">' + effectiveWidgetCount + '</span></div>';
		html += '<div class="epd-tab" data-tab="js">JS Timing <span class="epd-badge">' + jsData.widgets.length + '</span></div>';
		html += '<div class="epd-tab" data-tab="assets">Assets <span class="epd-badge">' + (D.assets.scripts_total + D.assets.styles_total) + '</span></div>';
		html += '<div class="epd-tab" data-tab="env">Environment</div>';
		html += '</div>';

		html += '<div class="epd-content">';

		/* ── Overview Tab ───────────────────────────────────── */
		html += '<div class="epd-tab-pane active" data-pane="overview">';
		html += '<div class="epd-overview-grid">';

		html += '<div class="epd-card">';
		html += '<div class="epd-card-title">PHP Generation</div>';
		html += '<div class="epd-card-value ' + perfClass(D.page.total_time, 1000, 3000) + '">' + D.page.total_time + '<small>ms</small></div>';
		html += '<div class="epd-card-sub">Widget render: ' + (isEditorPreview ? 'client-side' : D.widgets.total_render_time + 'ms') + '</div>';
		html += '</div>';

		html += '<div class="epd-card">';
		html += '<div class="epd-card-title">Memory Usage</div>';
		html += '<div class="epd-card-value">' + fmt(D.page.memory_usage) + '</div>';
		html += '<div class="epd-card-sub">Peak: ' + fmt(D.page.memory_peak) + ' / Limit: ' + esc(D.page.memory_limit_raw) + '</div>';
		html += '<div class="epd-card-bar"><div class="epd-card-bar-fill" style="width:' + memPct + '%;background:' + (memPct > 80 ? 'var(--epd-red)' : memPct > 60 ? 'var(--epd-yellow)' : 'var(--epd-green)') + '"></div></div>';
		html += '</div>';

		html += '<div class="epd-card">';
		html += '<div class="epd-card-title">Database Queries</div>';
		html += '<div class="epd-card-value ' + perfClass(D.page.db_queries_total, 50, 100) + '">' + D.page.db_queries_total + '</div>';
		html += '<div class="epd-card-sub">EP widget queries: ' + D.widgets.total_queries + '</div>';
		html += '</div>';

		html += '<div class="epd-card">';
		html += '<div class="epd-card-title">Widgets on Page</div>';
		html += '<div class="epd-card-value">' + effectiveWidgetCount + '</div>';
		var epDomCount = 0;
		for (var ci = 0; ci < domWidgets.length; ci++) { if (domWidgets[ci].isEP) epDomCount++; }
		if (D.widgets.count > 0 && domWidgets.length > D.widgets.count) {
			html += '<div class="epd-card-sub">' + D.widgets.count + ' PHP-profiled / ' + (domWidgets.length - D.widgets.count) + ' cached &mdash; ' + epDomCount + ' EP</div>';
		} else if (isEditorPreview) {
			html += '<div class="epd-card-sub">' + epDomCount + ' Element Pack / ' + (domWidgets.length - epDomCount) + ' other (DOM scan)</div>';
		} else {
			html += '<div class="epd-card-sub">Total memory delta: ' + fmt(D.widgets.total_memory) + '</div>';
		}
		html += '</div>';

		html += '<div class="epd-card">';
		html += '<div class="epd-card-title">Browser Timing</div>';
		html += '<div class="epd-card-value">';
		if (timing.domReady) html += '<span class="' + perfClass(timing.domReady, 2000, 4000) + '">' + timing.domReady + '<small>ms</small></span>';
		html += '</div>';
		html += '<div class="epd-card-sub">';
		if (timing.ttfb) html += 'TTFB: ' + timing.ttfb + 'ms | ';
		if (timing.fcp) html += 'FCP: ' + timing.fcp + 'ms | ';
		html += 'DOM nodes: ' + timing.domNodes;
		html += '</div>';
		html += '</div>';

		html += '<div class="epd-card">';
		html += '<div class="epd-card-title">Loaded Assets</div>';
		html += '<div class="epd-card-value">' + D.assets.scripts_total + ' <small>JS</small> / ' + D.assets.styles_total + ' <small>CSS</small></div>';
		html += '<div class="epd-card-sub">EP: ' + D.assets.ep_scripts.length + ' scripts, ' + D.assets.ep_styles.length + ' styles</div>';
		html += '</div>';

		html += '</div>'; // grid
		html += '</div>'; // pane

		/* ── Widgets Tab ────────────────────────────────────── */
		html += '<div class="epd-tab-pane" data-pane="widgets">';

		if (domWidgets.length > 0) {
			var widgetRows = domWidgets.slice().sort(function (a, b) {
				var pa = phpLookup[a.id], pb = phpLookup[b.id];
				var ma = pa ? pa.memory_delta : -1, mb = pb ? pb.memory_delta : -1;
				return mb - ma;
			});

			var phpProfiled = 0;
			for (var pc = 0; pc < domWidgets.length; pc++) { if (phpLookup[domWidgets[pc].id]) phpProfiled++; }
			var unprofiled = domWidgets.length - phpProfiled;

			html += '<div style="background:var(--epd-surface1);padding:6px 10px;border-radius:4px;margin-bottom:10px;font-size:10px;color:var(--epd-lavender);">';
			if (isEditorPreview) {
				html += '&#9432; Editor preview &mdash; click a widget name to scroll &amp; highlight it on the page.';
			} else if (unprofiled > 0) {
				html += '&#9432; ' + phpProfiled + ' widgets PHP-profiled, ' + unprofiled + ' served from cache (no PHP metrics). Click a name to scroll &amp; highlight.';
			} else {
				html += '&#9432; Click a widget name to scroll &amp; highlight it on the page. Click a row to expand query details.';
			}
			html += '</div>';

			html += '<div class="epd-table-wrap">';
			html += '<table class="epd-table epd-sortable-table" id="epd-widgets-table">';
			html += '<thead><tr>';
			html += '<th data-sort="name">Widget <span class="epd-sort-arrow">&#9650;</span></th>';
			if (!isEditorPreview) {
				html += '<th data-sort="render_time" class="sorted">Render <span class="epd-sort-arrow">&#9660;</span></th>';
				html += '<th data-sort="memory_delta">Memory &Delta; <span class="epd-sort-arrow">&#9650;</span></th>';
				html += '<th data-sort="memory_peak">Peak <span class="epd-sort-arrow">&#9650;</span></th>';
				html += '<th data-sort="db_queries">Queries <span class="epd-sort-arrow">&#9650;</span></th>';
			} else {
				html += '<th data-sort="js">JS Init <span class="epd-sort-arrow">&#9650;</span></th>';
			}
			html += '<th data-sort="mem">DOM Mem <span class="epd-sort-arrow">&#9650;</span></th>';
			html += '<th data-sort="nodes">Nodes <span class="epd-sort-arrow">&#9650;</span></th>';
			html += '<th data-sort="source">Src <span class="epd-sort-arrow">&#9650;</span></th>';
			html += '</tr></thead><tbody>';

			var colSpan = isEditorPreview ? 6 : 8;

			for (var wi = 0; wi < widgetRows.length; wi++) {
				var dw = widgetRows[wi];
				var php = phpLookup[dw.id] || null;
				var jsEntry = findJsEntryById(dw.id);
				var nodeCount = dw.nodes || 0;
				var htmlSize = dw.htmlSize || 0;
				var renderT = php ? php.render_time : -1;
				var memD = php ? php.memory_delta : -1;
				var memP = php ? (php.memory_peak || 0) : -1;
				var dbQ = php ? php.db_queries : -1;

				html += '<tr data-sortable data-inspect-id="' + esc(dw.id) + '"';
				html += ' data-sort-name="' + esc(dw.name) + '"';
				if (!isEditorPreview) {
					html += ' data-sort-render_time="' + renderT + '"';
					html += ' data-sort-memory_delta="' + memD + '"';
					html += ' data-sort-memory_peak="' + memP + '"';
					html += ' data-sort-db_queries="' + dbQ + '"';
				} else {
					html += ' data-sort-js="' + (jsEntry ? jsEntry.ms : -1) + '"';
				}
				html += ' data-sort-mem="' + htmlSize + '"';
				html += ' data-sort-nodes="' + nodeCount + '"';
				html += ' data-sort-source="' + (dw.isEP ? '0' : '1') + '"';
				if (php) html += ' data-widget-idx="' + D.widgets.items.indexOf(php) + '"';
				html += '>';

				// Widget name
				html += '<td>';
				html += '<span class="epd-widget-name">' + esc(dw.name) + '</span>';
				html += '<span class="epd-inspect-btn" title="Scroll to widget">&#8982;</span>';
				html += '</td>';

				if (!isEditorPreview) {
					// Render time
					if (php) {
						html += '<td><span class="' + perfClass(php.render_time, 30, 100) + '">' + php.render_time + 'ms</span></td>';
					} else {
						html += '<td><span style="color:var(--epd-subtext);font-size:9px" title="Served from cache">cached</span></td>';
					}
					// Memory delta
					if (php) {
						html += '<td><span class="' + perfClass(php.memory_delta, 102400, 524288) + '">' + fmt(php.memory_delta) + '</span></td>';
					} else {
						html += '<td><span style="color:var(--epd-subtext)">&mdash;</span></td>';
					}
					// Peak
					if (php) {
						html += '<td><span class="' + perfClass(memP, 102400, 524288) + '">' + fmt(memP) + '</span></td>';
					} else {
						html += '<td><span style="color:var(--epd-subtext)">&mdash;</span></td>';
					}
					// Queries
					if (php) {
						html += '<td>' + (php.db_queries > 0 ? '<span class="' + perfClass(php.db_queries, 5, 15) + '">' + php.db_queries + '</span>' : '0') + '</td>';
					} else {
						html += '<td><span style="color:var(--epd-subtext)">&mdash;</span></td>';
					}
				} else {
					// JS Init (editor)
					if (jsEntry) {
						html += '<td><span class="' + perfClass(jsEntry.ms, 10, 50) + '">' + jsEntry.ms.toFixed(2) + 'ms</span></td>';
					} else {
						html += '<td><span style="color:var(--epd-subtext)">&mdash;</span></td>';
					}
				}

				// DOM Memory (always)
				html += '<td><span class="' + perfClass(htmlSize, 51200, 204800) + '">' + fmt(htmlSize) + '</span></td>';
				// Nodes (always)
				html += '<td><span class="' + perfClass(nodeCount, 100, 300) + '">' + nodeCount + '</span></td>';
				// Source
				html += '<td>' + (dw.isEP ? '<span style="color:var(--epd-blue);font-weight:600;font-size:9px;">EP</span>' : '<span style="color:var(--epd-subtext);font-size:9px;">Core</span>') + '</td>';
				html += '</tr>';

				// Query detail row (PHP frontend only)
				if (php && php.queries && php.queries.length > 0) {
					var phpIdx = D.widgets.items.indexOf(php);
					html += '<tr class="epd-query-detail-row" style="display:none" data-detail-for="' + phpIdx + '"><td colspan="' + colSpan + '">';
					for (var q = 0; q < php.queries.length; q++) {
						html += '<div class="epd-query-row">';
						html += '<div class="epd-query-sql">' + esc(php.queries[q].sql) + '</div>';
						html += '<div class="epd-query-time">' + php.queries[q].time + 'ms</div>';
						html += '</div>';
					}
					html += '</td></tr>';
				}
			}
			html += '</tbody></table></div>';

		} else {
			html += '<p style="color:var(--epd-subtext)">No widgets detected on this page.</p>';
		}
		html += '</div>';

		/* ── JS Timing Tab ──────────────────────────────────── */
		html += '<div class="epd-tab-pane" data-pane="js">';
		html += '<div class="epd-js-metrics">';
		if (timing.domReady) {
			html += '<div class="epd-js-metric"><div class="epd-js-metric-label">DOM Ready</div><div class="epd-js-metric-value ' + perfClass(timing.domReady, 2000, 4000) + '">' + timing.domReady + 'ms</div></div>';
		}
		if (timing.windowLoad) {
			html += '<div class="epd-js-metric"><div class="epd-js-metric-label">Window Load</div><div class="epd-js-metric-value ' + perfClass(timing.windowLoad, 3000, 6000) + '">' + timing.windowLoad + 'ms</div></div>';
		}
		if (timing.fcp) {
			html += '<div class="epd-js-metric"><div class="epd-js-metric-label">First Contentful Paint</div><div class="epd-js-metric-value ' + perfClass(timing.fcp, 1800, 3000) + '">' + timing.fcp + 'ms</div></div>';
		}
		if (timing.domInteractive) {
			html += '<div class="epd-js-metric"><div class="epd-js-metric-label">DOM Interactive</div><div class="epd-js-metric-value ' + perfClass(timing.domInteractive, 1500, 3000) + '">' + timing.domInteractive + 'ms</div></div>';
		}
		html += '<div class="epd-js-metric"><div class="epd-js-metric-label">DOM Nodes</div><div class="epd-js-metric-value">' + timing.domNodes + '</div></div>';
		if (performance.memory) {
			html += '<div class="epd-js-metric"><div class="epd-js-metric-label">JS Heap</div><div class="epd-js-metric-value">' + fmt(performance.memory.usedJSHeapSize) + ' / ' + fmt(performance.memory.jsHeapSizeLimit) + '</div></div>';
		}
		html += '</div>';

		if (jsData.widgets.length > 0) {
			var jsSorted = jsData.widgets.slice().sort(function (a, b) { return b.ms - a.ms; });
			html += '<h4 style="color:var(--epd-lavender);margin:12px 0 8px;font-size:11px;text-transform:uppercase;letter-spacing:.06em;">Widget JS Init Times</h4>';
			html += '<div class="epd-table-wrap"><table class="epd-table epd-sortable-table" id="epd-js-table"><thead><tr>';
			html += '<th data-sort="name">Widget <span class="epd-sort-arrow">&#9650;</span></th>';
			html += '<th data-sort="ms" class="sorted">Init Time <span class="epd-sort-arrow">&#9660;</span></th>';
			html += '<th data-sort="nodes">DOM Nodes <span class="epd-sort-arrow">&#9650;</span></th>';
			html += '<th>Element ID</th>';
			html += '</tr></thead><tbody>';
			for (var j = 0; j < jsSorted.length; j++) {
				var jw = jsSorted[j];
				var displayName = jw.widgetType || jw.tag.replace('frontend/element_ready/', '');
				var jwNodes = jw.nodes || 0;
				html += '<tr data-sortable data-sort-name="' + esc(displayName) + '" data-sort-ms="' + jw.ms + '" data-sort-nodes="' + jwNodes + '"' + (jw.elId ? ' data-inspect-id="' + esc(jw.elId) + '"' : '') + '>';
				html += '<td>';
				html += '<span class="epd-widget-name">' + esc(displayName) + '</span>';
				if (jw.elId) html += '<span class="epd-inspect-btn" title="Scroll to widget">&#8982;</span>';
				html += '</td>';
				html += '<td><span class="' + perfClass(jw.ms, 10, 50) + '">' + jw.ms.toFixed(2) + 'ms</span></td>';
				html += '<td><span class="' + perfClass(jwNodes, 100, 300) + '">' + jwNodes + '</span></td>';
				html += '<td><span class="epd-widget-id">' + esc(jw.elId || '—') + '</span></td>';
				html += '</tr>';
			}
			html += '</tbody></table></div>';
		} else {
			html += '<p style="color:var(--epd-subtext);margin-top:8px;">No widget JS init timing captured.</p>';
		}
		html += '</div>';

		/* ── Assets Tab ─────────────────────────────────────── */
		html += '<div class="epd-tab-pane" data-pane="assets">';

		var allAssets = [];
		var totalTransfer = 0, totalDecoded = 0, cacheHits = 0, networkLoads = 0;

		function pushAssets(list, type) {
			for (var ai = 0; ai < list.length; ai++) {
				var a = list[ai];
				var r = findResource(a.src, resDetails);
				var row = {
					handle: a.handle,
					src: a.src || '',
					ver: a.ver || '',
					deps: a.deps || 0,
					type: type,
					source: a.source || 'other',
					inFooter: a.in_footer || false,
					transfer: r ? r.transferSize : -1,
					decoded: r ? r.decodedSize : -1,
					encoded: r ? r.encodedSize : -1,
					duration: r ? r.duration : -1,
					cached: r ? r.cached : false,
					protocol: r ? r.protocol : '',
					hasPerf: !!r,
				};
				if (row.hasPerf) {
					totalTransfer += row.transfer;
					totalDecoded += row.decoded;
					if (row.cached) cacheHits++; else networkLoads++;
				}
				allAssets.push(row);
			}
		}
		pushAssets(D.assets.scripts_detail || [], 'JS');
		pushAssets(D.assets.styles_detail || [], 'CSS');

		var epAssets = 0, elAssets = 0;
		for (var ac = 0; ac < allAssets.length; ac++) {
			if (allAssets[ac].source === 'ep') epAssets++;
			else if (allAssets[ac].source === 'elementor') elAssets++;
		}

		// Summary cards
		html += '<div class="epd-overview-grid" style="margin-bottom:14px;">';
		html += '<div class="epd-card"><div class="epd-card-title">Total Assets</div>';
		html += '<div class="epd-card-value">' + D.assets.scripts_total + ' <small>JS</small> / ' + D.assets.styles_total + ' <small>CSS</small></div>';
		html += '<div class="epd-card-sub">EP: ' + epAssets + ' | Elementor: ' + elAssets + ' | Other: ' + (allAssets.length - epAssets - elAssets) + '</div></div>';

		html += '<div class="epd-card"><div class="epd-card-title">Network Transfer</div>';
		html += '<div class="epd-card-value">' + fmt(totalTransfer) + '</div>';
		html += '<div class="epd-card-sub">Decoded: ' + fmt(totalDecoded);
		if (totalDecoded > 0 && totalTransfer > 0 && totalTransfer < totalDecoded) {
			html += ' (saved ' + Math.round((1 - totalTransfer / totalDecoded) * 100) + '% via compression)';
		}
		html += '</div></div>';

		html += '<div class="epd-card"><div class="epd-card-title">Cache Performance</div>';
		var totalMeasured = cacheHits + networkLoads;
		html += '<div class="epd-card-value">' + cacheHits + ' <small>cached</small> / ' + networkLoads + ' <small>network</small></div>';
		if (totalMeasured > 0) {
			var cachePct = Math.round(cacheHits / totalMeasured * 100);
			html += '<div class="epd-card-bar"><div class="epd-card-bar-fill" style="width:' + cachePct + '%;background:var(--epd-green)"></div></div>';
		}
		html += '</div>';
		html += '</div>';

		// Assets table
		html += '<div class="epd-table-wrap">';
		html += '<table class="epd-table epd-sortable-table" id="epd-assets-table">';
		html += '<thead><tr>';
		html += '<th data-sort="handle">Handle <span class="epd-sort-arrow">&#9650;</span></th>';
		html += '<th data-sort="type">Type <span class="epd-sort-arrow">&#9650;</span></th>';
		html += '<th data-sort="transfer" class="sorted">Transfer <span class="epd-sort-arrow">&#9660;</span></th>';
		html += '<th data-sort="decoded">Original <span class="epd-sort-arrow">&#9650;</span></th>';
		html += '<th data-sort="duration">Load Time <span class="epd-sort-arrow">&#9650;</span></th>';
		html += '<th data-sort="status">Status <span class="epd-sort-arrow">&#9650;</span></th>';
		html += '<th data-sort="source">Source <span class="epd-sort-arrow">&#9650;</span></th>';
		html += '</tr></thead><tbody>';

		var assetsSorted = allAssets.slice().sort(function (a, b) { return b.transfer - a.transfer; });
		for (var at = 0; at < assetsSorted.length; at++) {
			var ar = assetsSorted[at];
			var statusVal = ar.cached ? 0 : (ar.hasPerf ? 1 : 2);
			var sourceVal = ar.source === 'ep' ? 0 : (ar.source === 'elementor' ? 1 : 2);
			html += '<tr data-sortable';
			html += ' data-sort-handle="' + esc(ar.handle) + '"';
			html += ' data-sort-type="' + ar.type + '"';
			html += ' data-sort-transfer="' + ar.transfer + '"';
			html += ' data-sort-decoded="' + ar.decoded + '"';
			html += ' data-sort-duration="' + ar.duration + '"';
			html += ' data-sort-status="' + statusVal + '"';
			html += ' data-sort-source="' + sourceVal + '"';
			html += '>';

			// Handle + path tooltip
			html += '<td>';
			html += '<span class="epd-asset-handle">' + esc(ar.handle) + '</span>';
			if (ar.src) html += '<div class="epd-asset-src" title="' + esc(ar.src) + '">' + shortenSrc(ar.src) + '</div>';
			if (ar.ver) html += '<span class="epd-asset-ver">v' + esc(ar.ver) + '</span>';
			html += '</td>';

			// Type
			html += '<td><span class="epd-type-badge epd-type-' + ar.type.toLowerCase() + '">' + ar.type + '</span></td>';

			// Transfer size
			if (ar.hasPerf) {
				var saved = ar.decoded > 0 && ar.transfer < ar.decoded ? Math.round((1 - ar.transfer / ar.decoded) * 100) : 0;
				html += '<td><span class="' + perfClass(ar.transfer, 50000, 150000) + '">' + fmt(ar.transfer) + '</span>';
				if (saved > 0) html += ' <span class="epd-compress-badge">-' + saved + '%</span>';
				html += '</td>';
			} else {
				html += '<td><span style="color:var(--epd-subtext)">&mdash;</span></td>';
			}

			// Original (decoded) size
			if (ar.hasPerf && ar.decoded > 0) {
				html += '<td>' + fmt(ar.decoded) + '</td>';
			} else {
				html += '<td><span style="color:var(--epd-subtext)">&mdash;</span></td>';
			}

			// Load time
			if (ar.hasPerf && ar.duration >= 0) {
				html += '<td><span class="' + perfClass(ar.duration, 100, 500) + '">' + ar.duration + 'ms</span></td>';
			} else {
				html += '<td><span style="color:var(--epd-subtext)">&mdash;</span></td>';
			}

			// Cache status
			if (ar.hasPerf) {
				if (ar.cached) {
					html += '<td><span class="epd-cache-badge epd-cached">Cached</span></td>';
				} else {
					html += '<td><span class="epd-cache-badge epd-network">Network</span>';
					if (ar.protocol) html += ' <span class="epd-asset-ver">' + esc(ar.protocol) + '</span>';
					html += '</td>';
				}
			} else {
				html += '<td><span style="color:var(--epd-subtext)">Inline</span></td>';
			}

			// Source
			if (ar.source === 'ep') {
				html += '<td><span class="epd-source-badge epd-src-ep">EP</span></td>';
			} else if (ar.source === 'elementor') {
				html += '<td><span class="epd-source-badge epd-src-el">Elementor</span></td>';
			} else {
				html += '<td><span class="epd-source-badge epd-src-other">Other</span></td>';
			}

			html += '</tr>';
		}
		html += '</tbody></table></div>';
		html += '</div>';

		/* ── Environment Tab ────────────────────────────────── */
		html += '<div class="epd-tab-pane" data-pane="env">';
		html += '<div class="epd-env-grid">';

		var envRows = [
			['PHP Version', D.page.php_version],
			['WordPress Version', D.page.wp_version],
			['Elementor Version', D.page.elementor_version],
			['Element Pack Version', D.page.ep_version],
			['PHP Memory Limit', D.page.memory_limit_raw],
			['Max Execution Time', D.server.max_execution_time + 's'],
			['PHP SAPI', D.server.php_sapi],
			['OPcache', D.server.opcache_enabled ? 'Enabled' : 'Disabled', D.server.opcache_enabled],
			['Object Cache', D.server.object_cache ? 'Enabled' : 'Disabled', D.server.object_cache],
			['Asset Optimization', D.page.asset_optimization ? 'Enabled' : 'Disabled', D.page.asset_optimization],
			['SAVEQUERIES', D.page.savequeries ? 'Enabled' : 'Disabled', D.page.savequeries],
			['User Agent', navigator.userAgent],
			['Screen', window.screen.width + 'x' + window.screen.height + ' @' + window.devicePixelRatio + 'x'],
			['Viewport', window.innerWidth + 'x' + window.innerHeight],
		];

		for (var e = 0; e < envRows.length; e++) {
			var cls = '';
			if (envRows[e].length === 3) cls = envRows[e][2] ? ' epd-on' : ' epd-off';
			html += '<div class="epd-env-label">' + esc(envRows[e][0]) + '</div>';
			html += '<div class="epd-env-value' + cls + '">' + esc(envRows[e][1]) + '</div>';
		}

		html += '</div></div>';

		html += '</div>'; // content

		return html;
	}

	function findResource(src, resMap) {
		if (!src) return null;
		var srcNorm = src.replace(/^https?:/, '');
		for (var url in resMap) {
			if (url.indexOf(srcNorm) !== -1 || srcNorm.indexOf(url.replace(/^https?:/, '')) !== -1) {
				return resMap[url];
			}
		}
		return null;
	}

	function shortenSrc(src) {
		if (!src) return '';
		var idx = src.indexOf('/wp-content/');
		if (idx > -1) return '...' + src.substring(idx);
		return src;
	}

	/* ── Initialize ──────────────────────────────────────── */

	function init() {
		var toggle = document.createElement('button');
		toggle.id = 'ep-debug-toggle';
		toggle.innerHTML = '&#128027;';
		toggle.title = 'Element Pack Debug Panel';
		document.body.appendChild(toggle);

		var panel = document.createElement('div');
		panel.id = 'ep-debug-panel';
		document.body.appendChild(panel);

		window.epDebugPanel = {
			toggle: function () {
				var isOpen = panel.classList.contains('open');
				if (isOpen) {
					panel.classList.remove('open');
					toggle.classList.remove('active');
				} else {
					panel.innerHTML = buildPanel();
					bindEvents(panel, toggle);
					panel.classList.add('open');
					toggle.classList.add('active');
				}
			},
		};

		toggle.addEventListener('click', function () {
			window.epDebugPanel.toggle();
		});
	}

	function bindTableSort(table, panel) {
		var headers = table.querySelectorAll('th[data-sort]');
		for (var h = 0; h < headers.length; h++) {
			headers[h].addEventListener('click', function () {
				var sortKey = this.getAttribute('data-sort');
				var tbody = table.querySelector('tbody');
				var rows = Array.prototype.slice.call(tbody.querySelectorAll('tr[data-sortable]'));
				var isDesc = this.classList.contains('sorted') &&
					this.querySelector('.epd-sort-arrow').innerHTML === '\u25BC';

				var allH = table.querySelectorAll('th[data-sort]');
				for (var x = 0; x < allH.length; x++) allH[x].classList.remove('sorted');
				this.classList.add('sorted');
				this.querySelector('.epd-sort-arrow').innerHTML = isDesc ? '\u25B2' : '\u25BC';

				rows.sort(function (a, b) {
					var va = a.getAttribute('data-sort-' + sortKey) || '';
					var vb = b.getAttribute('data-sort-' + sortKey) || '';
					var na = parseFloat(va);
					var nb = parseFloat(vb);
					if (!isNaN(na) && !isNaN(nb)) {
						return isDesc ? na - nb : nb - na;
					}
					return isDesc ? va.localeCompare(vb) : vb.localeCompare(va);
				});

				while (tbody.firstChild) tbody.removeChild(tbody.firstChild);
				for (var r = 0; r < rows.length; r++) {
					tbody.appendChild(rows[r]);
					var idx = rows[r].getAttribute('data-widget-idx');
					if (idx !== null) {
						var detailRow = panel.querySelector('[data-detail-for="' + idx + '"]');
						if (detailRow) tbody.appendChild(detailRow);
					}
				}
			});
		}
	}

	function bindEvents(panel, toggle) {
		// Close button
		panel.querySelector('.epd-close').addEventListener('click', function () {
			panel.classList.remove('open');
			toggle.classList.remove('active');
		});

		// Tab switching
		var tabs = panel.querySelectorAll('.epd-tab');
		var panes = panel.querySelectorAll('.epd-tab-pane');
		for (var t = 0; t < tabs.length; t++) {
			tabs[t].addEventListener('click', function () {
				var tabName = this.getAttribute('data-tab');
				for (var i = 0; i < tabs.length; i++) tabs[i].classList.remove('active');
				for (var j = 0; j < panes.length; j++) panes[j].classList.remove('active');
				this.classList.add('active');
				panel.querySelector('[data-pane="' + tabName + '"]').classList.add('active');
			});
		}

		// Inspect: click on widget name or inspect button → scroll to & highlight
		var inspectBtns = panel.querySelectorAll('.epd-inspect-btn');
		for (var ib = 0; ib < inspectBtns.length; ib++) {
			inspectBtns[ib].addEventListener('click', function (e) {
				e.stopPropagation();
				var row = this.closest('tr[data-inspect-id]');
				if (row) inspectWidget(row.getAttribute('data-inspect-id'));
			});
		}

		var inspectNames = panel.querySelectorAll('tr[data-inspect-id] .epd-widget-name');
		for (var wn = 0; wn < inspectNames.length; wn++) {
			inspectNames[wn].style.cursor = 'pointer';
			inspectNames[wn].addEventListener('click', function (e) {
				e.stopPropagation();
				var row = this.closest('tr[data-inspect-id]');
				if (row) inspectWidget(row.getAttribute('data-inspect-id'));
			});
		}

		// Sortable tables (Widgets tab + JS Timing tab)
		var sortTables = panel.querySelectorAll('.epd-sortable-table');
		for (var st = 0; st < sortTables.length; st++) {
			bindTableSort(sortTables[st], panel);
		}

		// Click row to expand query details (PHP frontend Widgets tab)
		var wTable = panel.querySelector('#epd-widgets-table');
		if (wTable) {
			wTable.addEventListener('click', function (e) {
				if (e.target.closest('.epd-inspect-btn') || e.target.closest('.epd-widget-name')) return;
				var row = e.target.closest('tr[data-widget-idx]');
				if (!row) return;
				var idx = row.getAttribute('data-widget-idx');
				var detail = panel.querySelector('[data-detail-for="' + idx + '"]');
				if (detail) {
					detail.style.display = detail.style.display === 'none' ? '' : 'none';
				}
			});
		}

		// Resize handle
		var resize = panel.querySelector('.epd-resize');
		if (resize) {
			var startY, startH;
			resize.addEventListener('mousedown', function (e) {
				startY = e.clientY;
				startH = panel.offsetHeight;
				document.addEventListener('mousemove', onResize);
				document.addEventListener('mouseup', stopResize);
				e.preventDefault();
			});
			function onResize(e) {
				var newH = startH + (startY - e.clientY);
				panel.style.height = Math.max(200, Math.min(window.innerHeight - 40, newH)) + 'px';
			}
			function stopResize() {
				document.removeEventListener('mousemove', onResize);
				document.removeEventListener('mouseup', stopResize);
			}
		}

		// Keyboard shortcut
		document.addEventListener('keydown', function (e) {
			if (e.ctrlKey && e.shiftKey && e.key === 'D') {
				e.preventDefault();
				window.epDebugPanel.toggle();
			}
		});
	}

	/* ── Boot ────────────────────────────────────────────── */

	if (document.readyState === 'complete' || document.readyState === 'interactive') {
		setTimeout(init, 0);
	} else {
		window.addEventListener('DOMContentLoaded', function () {
			setTimeout(init, 100);
		});
	}

})();
