/**
 * Password Protect Master — Template Builder (Drag & Drop)
 *
 * Zone-aware canvas with card selection, media uploads, and full block customisation.
 *
 * @package PasswordProtectMaster
 */
(function () {
	'use strict';

	/* ================================================================
	 * State
	 * ================================================================ */
	var blockStore = { before_card: [], card: [], after_card: [] };
	var selectedId = null;
	var editId     = '';
	var isFreeMode = false;
	var defaults   = {};
	var globalStyles = {
		bgColor: '#F0F2F8', bgImage: '',
		bgGradient: false, bgGradFrom: '#F0F2F8', bgGradTo: '#FFFFFF', bgGradAngle: 135,
		bgOverlay: false, bgOverlayColor: '#000000', bgOverlayOpacity: 50,
		cardBg: '#FFFFFF', cardRadius: 16,
		cardShadow: true, cardPadding: 40, maxWidth: 420
	};

	var iconSVGs = {
		lock:        '<rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/><circle cx="12" cy="16" r="1.5"/>',
		shield:      '<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>',
		key:         '<path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 0-7.778 7.778 5.5 5.5 0 0 0 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"/>',
		eye:         '<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>',
		lockopen:    '<rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 9.9-1"/>',
		fingerprint: '<path d="M2 12C2 6.5 6.5 2 12 2a10 10 0 0 1 8 4"/><path d="M5 19.5C5.5 18 6 15 6 12c0-3.3 2.7-6 6-6 1 0 2 .3 2.8.7"/><path d="M12 12c0 4-1 8-3 10"/><path d="M12 12c0 5 1.5 8.5 3 10"/><path d="M18 12a6 6 0 0 0-6-6"/>',
		userlock:    '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><rect x="16" y="13" width="6" height="8" rx="1"/><path d="M18 13v-1.5a1.5 1.5 0 1 1 3 0V13"/>'
	};

	var fontFamilies = [
		{ v: 'inherit', l: 'Default' },
		{ v: 'Arial, Helvetica, sans-serif', l: 'Arial' },
		{ v: 'Georgia, serif', l: 'Georgia' },
		{ v: 'Verdana, sans-serif', l: 'Verdana' },
		{ v: '"Trebuchet MS", sans-serif', l: 'Trebuchet' },
		{ v: '"Times New Roman", serif', l: 'Times New Roman' },
		{ v: '"Courier New", monospace', l: 'Courier New' },
		{ v: 'Impact, sans-serif', l: 'Impact' },
		{ v: '"Segoe UI", sans-serif', l: 'Segoe UI' },
		{ v: 'Tahoma, sans-serif', l: 'Tahoma' },
		{ v: 'system-ui, sans-serif', l: 'System UI' }
	];

	var blockDefs = {
		logo:           { label: 'Logo',            defaults: { content: '', settings: { maxheight: 48, alignment: 'center', borderradius: 0, opacity: 100, margintop: 0, marginbottom: 16, bgcolor: 'transparent', blockpadding: 0, blockradius: 0 } } },
		icon:           { label: 'Lock Icon',       defaults: { content: '', settings: { icontype: 'lock', size: 48, color: '#6C5CE7', alignment: 'center', margintop: 0, marginbottom: 16, bgcolor: 'transparent', blockpadding: 0, blockradius: 0 } } },
		heading:        { label: 'Heading',          defaults: { content: '', settings: { fontfamily: 'inherit', fontsize: 24, fontweight: 700, color: '#1A1A2E', texttransform: 'none', letterspacing: 0, lineheight: 120, alignment: 'center', margintop: 0, marginbottom: 12, bgcolor: 'transparent', blockpadding: 0, blockradius: 0 } } },
		description:    { label: 'Description',      defaults: { content: '', settings: { fontfamily: 'inherit', fontsize: 14, fontweight: 400, color: '#6C7293', texttransform: 'none', letterspacing: 0, lineheight: 150, alignment: 'center', margintop: 0, marginbottom: 20, bgcolor: 'transparent', blockpadding: 0, blockradius: 0 } } },
		error_message:  { label: 'Error Message',    defaults: { content: '', settings: { fontsize: 13, textcolor: '#C0392B', errbg: 'rgba(225,112,85,0.1)', borderradius: 8, margintop: 0, marginbottom: 16 } } },
		password_input: { label: 'Password Field',   defaults: { content: '', settings: { fontsize: 14, borderradius: 10, bordercolor: '#E4E6EF', borderwidth: 2, inputbg: '#F9F9FC', textcolor: '#1A1A2E', focusbordercolor: '#6C5CE7', inputpadding: 12, fullwidth: true, margintop: 0, marginbottom: 14, bgcolor: 'transparent', blockpadding: 0, blockradius: 0 } } },
		submit_button:  { label: 'Submit Button',    defaults: { content: '', settings: { bgcolor: '#6C5CE7', hovercolor: '#5A4BD1', textcolor: '#FFFFFF', borderradius: 10, fontsize: 15, fontweight: 600, fullwidth: true, paddingv: 13, paddingh: 24, borderstyle: 'none', borderwidth: 0, bordercolor: '#6C5CE7', margintop: 0, marginbottom: 0 } } },
		spacer:         { label: 'Spacer',            defaults: { content: '', settings: { height: 20 } } },
		divider:        { label: 'Divider',           defaults: { content: '', settings: { color: '#E4E6EF', width: 1, margintop: 8, marginbottom: 8 } } },
		custom_text:    { label: 'Custom Text',       defaults: { content: 'Your text here', settings: { fontfamily: 'inherit', fontsize: 13, fontweight: 400, color: '#6C7293', texttransform: 'none', letterspacing: 0, lineheight: 150, alignment: 'center', margintop: 0, marginbottom: 12, bgcolor: 'transparent', blockpadding: 0, blockradius: 0 } } }
	};

	/* ================================================================
	 * Init
	 * ================================================================ */
	document.addEventListener('DOMContentLoaded', function () {
		if (typeof ppmstrBuilderData === 'undefined' || typeof ppmstrAdmin === 'undefined') return;

		defaults   = ppmstrBuilderData.defaults || {};
		editId     = ppmstrBuilderData.editId || '';
		isFreeMode = !!(ppmstrBuilderData.isFreeMode);

		if (ppmstrBuilderData.editTpl) {
			loadBlocks(ppmstrBuilderData.editTpl.blocks || []);
			var tplGlobal = ppmstrBuilderData.editTpl.global;
			if (tplGlobal) {
				for (var k in tplGlobal) { globalStyles[k] = tplGlobal[k]; }
			}
			syncGlobalInputs();
		} else {
			addBlock('icon', 'card');
			addBlock('heading', 'card');
			addBlock('description', 'card');
			addBlock('password_input', 'card');
			addBlock('submit_button', 'card');
		}

		// Inject animation CSS from PHP-generated styles so canvas reflects real design.
		if (ppmstrBuilderData.animationCSS) {
			var animStyleEl = document.getElementById('ppmstr-builder-anim-css');
			if (!animStyleEl) {
				animStyleEl = document.createElement('style');
				animStyleEl.id = 'ppmstr-builder-anim-css';
				document.head.appendChild(animStyleEl);
			}
			animStyleEl.textContent = ppmstrBuilderData.animationCSS;
		}

		renderCanvas();
		applyGlobalStyles();
		bindPalette();
		bindGlobalStyles();
		bindTopBar();
		bindCanvasDrop();
		bindCanvasClicks();

		// Apply free-mode visual restrictions after everything is rendered.
		if (isFreeMode) {
			applyFreeModeRestrictions();
		}
	});

	/* ================================================================
	 * Block Store (zone-based)
	 * ================================================================ */
	function loadBlocks(blocksArray) {
		blockStore = { before_card: [], card: [], after_card: [] };
		(blocksArray || []).forEach(function (b) {
			var zone = b.zone || 'card';
			if (!blockStore[zone]) zone = 'card';
			blockStore[zone].push(b);
		});
	}

	function getAllBlocks() {
		var all = [];
		blockStore.before_card.forEach(function (b) { b.zone = 'before_card'; all.push(b); });
		blockStore.card.forEach(function (b) { b.zone = 'card'; all.push(b); });
		blockStore.after_card.forEach(function (b) { b.zone = 'after_card'; all.push(b); });
		return all;
	}

	function getBlock(id) {
		for (var zone in blockStore) {
			var found = blockStore[zone].find(function (b) { return b.id === id; });
			if (found) return found;
		}
		return null;
	}

	function getBlockZone(id) {
		for (var zone in blockStore) {
			if (blockStore[zone].some(function (b) { return b.id === id; })) return zone;
		}
		return null;
	}

	/* ================================================================
	 * Block CRUD
	 * ================================================================ */
	function uid() { return 'b' + Math.random().toString(36).substr(2, 8); }

	function addBlock(type, zone, index) {
		var def = blockDefs[type];
		if (!def) return null;
		zone = zone || 'card';

		var block = {
			id: uid(), type: type, zone: zone,
			content: def.defaults.content,
			settings: JSON.parse(JSON.stringify(def.defaults.settings))
		};

		if (type === 'heading')        block.content = defaults.headline || 'Protected Content';
		if (type === 'description')    block.content = defaults.description || 'Enter password to continue.';
		if (type === 'password_input') block.content = defaults.placeholder || 'Enter password\u2026';
		if (type === 'submit_button')  block.content = defaults.buttonText || 'Unlock';

		if (typeof index === 'number') {
			blockStore[zone].splice(index, 0, block);
		} else {
			blockStore[zone].push(block);
		}
		return block;
	}

	function removeBlock(id) {
		var zone = getBlockZone(id);
		if (!zone) return;
		blockStore[zone] = blockStore[zone].filter(function (b) { return b.id !== id; });
		if (selectedId === id) { selectedId = null; renderInspector(); }
		renderCanvas();
	}

	function moveBlock(id, dir) {
		var zone = getBlockZone(id);
		if (!zone) return;
		var arr = blockStore[zone];
		var idx = arr.findIndex(function (b) { return b.id === id; });
		if (idx < 0) return;
		var newIdx = idx + dir;
		if (newIdx < 0 || newIdx >= arr.length) return;
		var tmp = arr[idx]; arr[idx] = arr[newIdx]; arr[newIdx] = tmp;
		renderCanvas();
	}

	/* ================================================================
	 * Canvas Rendering
	 * ================================================================ */
	function renderCanvas() {
		var beforeZone = document.getElementById('ppmstr-zone-before');
		var cardZone   = document.getElementById('ppmstr-canvas-card');
		var afterZone  = document.getElementById('ppmstr-zone-after');

		[beforeZone, cardZone, afterZone].forEach(function (z) {
			z.querySelectorAll('.ppmstr-cb').forEach(function (el) { el.remove(); });
		});

		document.getElementById('ppmstr-before-empty').style.display = blockStore.before_card.length ? 'none' : '';
		document.getElementById('ppmstr-canvas-empty').style.display = blockStore.card.length ? 'none' : '';
		document.getElementById('ppmstr-after-empty').style.display  = blockStore.after_card.length ? 'none' : '';

		renderZoneBlocks(beforeZone, blockStore.before_card);
		renderZoneBlocks(cardZone, blockStore.card);
		renderZoneBlocks(afterZone, blockStore.after_card);

		cardZone.classList.toggle('ppmstr-card--selected', selectedId === '__card__');
	}

	function renderZoneBlocks(container, zoneBlocks) {
		zoneBlocks.forEach(function (block) {
			container.appendChild(createBlockElement(block));
		});
	}

	function createBlockElement(block) {
		var el = document.createElement('div');
		el.className = 'ppmstr-cb' + (selectedId === block.id ? ' ppmstr-cb--selected' : '');
		el.setAttribute('data-block-id', block.id);
		el.draggable = !isFreeMode; // Disable drag in free mode.

		// In free mode: hide move and delete toolbar, only allow clicking to select/edit.
		if (isFreeMode) {
			el.innerHTML = '<div class="ppmstr-cb-content">' + renderBlockPreview(block) + '</div>';
		} else {
			el.innerHTML = '<div class="ppmstr-cb-toolbar">' +
				'<button type="button" class="ppmstr-cb-tool ppmstr-cb-up" title="Move up">\u2191</button>' +
				'<button type="button" class="ppmstr-cb-tool ppmstr-cb-down" title="Move down">\u2193</button>' +
				'<button type="button" class="ppmstr-cb-tool ppmstr-cb-tool--delete ppmstr-cb-del" title="Delete">\u2715</button>' +
				'</div>' +
				'<div class="ppmstr-cb-content">' + renderBlockPreview(block) + '</div>';
		}

		el.addEventListener('click', function (e) {
			e.stopPropagation();
			if (e.target.closest('.ppmstr-cb-tool')) return;
			selectBlock(block.id);
		});

		if (!isFreeMode) {
			el.querySelector('.ppmstr-cb-up').addEventListener('click', function (e) { e.stopPropagation(); moveBlock(block.id, -1); });
			el.querySelector('.ppmstr-cb-down').addEventListener('click', function (e) { e.stopPropagation(); moveBlock(block.id, 1); });
			el.querySelector('.ppmstr-cb-del').addEventListener('click', function (e) { e.stopPropagation(); removeBlock(block.id); });

			el.addEventListener('dragstart', function (e) {
				e.dataTransfer.setData('text/plain', 'canvas:' + block.id);
				el.style.opacity = '0.4';
			});
			el.addEventListener('dragend', function () { el.style.opacity = '1'; });
		}

		return el;
	}

	function renderBlockPreview(block) {
		var s    = block.settings || {};
		var type = block.type;
		var align = 'text-align:' + (s.alignment || 'center') + ';';

		var wrapStyle = '';
		if (s.bgcolor && s.bgcolor !== 'transparent') {
			wrapStyle += 'background:' + s.bgcolor + ';';
		}
		if (s.blockpadding) { wrapStyle += 'padding:' + s.blockpadding + 'px;'; }
		if (s.blockradius)  { wrapStyle += 'border-radius:' + s.blockradius + 'px;'; }

		switch (type) {
			case 'logo':
				var logoStyle = 'max-height:' + (s.maxheight || 48) + 'px;';
				if (s.borderradius) logoStyle += 'border-radius:' + s.borderradius + 'px;';
				if (s.opacity !== undefined && s.opacity < 100) logoStyle += 'opacity:' + (s.opacity / 100) + ';';
				if (block.content) {
					return '<div style="' + align + wrapStyle + '"><img src="' + escHtml(block.content) + '" style="' + logoStyle + '" /></div>';
				}
				return '<div style="' + align + 'color:#A0A5B8;font-size:12px;padding:8px;border:1px dashed #CCC;border-radius:6px;' + wrapStyle + '">\uD83D\uDCF7 Logo (upload or set URL)</div>';

			case 'icon':
				var svgInner = iconSVGs[s.icontype || 'lock'] || iconSVGs.lock;
				return '<div style="' + align + 'color:' + (s.color || '#6C5CE7') + ';' + wrapStyle + '"><svg width="' + (s.size || 48) + '" height="' + (s.size || 48) + '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">' + svgInner + '</svg></div>';

			case 'heading':
				var hStyle = 'font-size:' + (s.fontsize || 24) + 'px;font-weight:' + (s.fontweight || 700) + ';color:' + (s.color || '#1A1A2E') + ';';
				if (s.fontfamily && s.fontfamily !== 'inherit') hStyle += 'font-family:' + s.fontfamily + ';';
				if (s.texttransform && s.texttransform !== 'none') hStyle += 'text-transform:' + s.texttransform + ';';
				if (s.letterspacing) hStyle += 'letter-spacing:' + s.letterspacing + 'px;';
				if (s.lineheight) hStyle += 'line-height:' + s.lineheight + '%;';
				return '<div style="' + hStyle + align + wrapStyle + '">' + escHtml(block.content) + '</div>';

			case 'description':
				var dStyle = 'font-size:' + (s.fontsize || 14) + 'px;font-weight:' + (s.fontweight || 400) + ';color:' + (s.color || '#6C7293') + ';';
				if (s.fontfamily && s.fontfamily !== 'inherit') dStyle += 'font-family:' + s.fontfamily + ';';
				if (s.texttransform && s.texttransform !== 'none') dStyle += 'text-transform:' + s.texttransform + ';';
				if (s.letterspacing) dStyle += 'letter-spacing:' + s.letterspacing + 'px;';
				if (s.lineheight) dStyle += 'line-height:' + s.lineheight + '%;';
				return '<div style="' + dStyle + align + wrapStyle + '">' + escHtml(block.content) + '</div>';

			case 'error_message':
				return '<div style="background:' + (s.errbg || 'rgba(225,112,85,0.1)') + ';color:' + (s.textcolor || '#C0392B') + ';padding:10px 14px;border-radius:' + (s.borderradius || 8) + 'px;font-size:' + (s.fontsize || 13) + 'px;">\u26A0 Error message appears here</div>';

			case 'password_input':
				var ipPad = (s.inputpadding || 12);
				var ipBw = (s.borderwidth || 2);
				var ipW = s.fullwidth !== false ? 'width:100%;' : 'width:auto;min-width:200px;';
				return '<div style="position:relative;' + wrapStyle + '"><input type="text" disabled placeholder="' + escHtml(block.content || 'Enter password\u2026') + '" style="' + ipW + 'padding:' + ipPad + 'px ' + (ipPad + 2) + 'px;border:' + ipBw + 'px solid ' + (s.bordercolor || '#E4E6EF') + ';border-radius:' + (s.borderradius || 10) + 'px;font-size:' + (s.fontsize || 14) + 'px;box-sizing:border-box;background:' + (s.inputbg || '#F9F9FC') + ';color:' + (s.textcolor || '#999') + ';" /></div>';

			case 'submit_button':
				var btnW = s.fullwidth !== false ? 'width:100%;' : 'width:auto;';
				var btnPad = 'padding:' + (s.paddingv || 13) + 'px ' + (s.paddingh || 24) + 'px;';
				var btnBorder = 'border:none;';
				if (s.borderstyle && s.borderstyle !== 'none') {
					btnBorder = 'border:' + (s.borderwidth || 1) + 'px ' + s.borderstyle + ' ' + (s.bordercolor || '#6C5CE7') + ';';
				}
				return '<div><button type="button" disabled style="' + btnW + btnPad + btnBorder + 'border-radius:' + (s.borderradius || 10) + 'px;font-size:' + (s.fontsize || 15) + 'px;font-weight:' + (s.fontweight || 600) + ';background:' + (s.bgcolor || '#6C5CE7') + ';color:' + (s.textcolor || '#FFF') + ';cursor:default;">' + escHtml(block.content || 'Unlock') + '</button></div>';

			case 'spacer':
				return '<div style="height:' + (s.height || 20) + 'px;background:repeating-linear-gradient(45deg,transparent,transparent 4px,rgba(108,92,231,0.05) 4px,rgba(108,92,231,0.05) 8px);border-radius:4px;"></div>';

			case 'divider':
				return '<hr style="border:none;border-top:' + (s.width || 1) + 'px solid ' + (s.color || '#E4E6EF') + ';margin:0;" />';

			case 'custom_text':
				var ctStyle = 'font-size:' + (s.fontsize || 13) + 'px;font-weight:' + (s.fontweight || 400) + ';color:' + (s.color || '#6C7293') + ';';
				if (s.fontfamily && s.fontfamily !== 'inherit') ctStyle += 'font-family:' + s.fontfamily + ';';
				if (s.texttransform && s.texttransform !== 'none') ctStyle += 'text-transform:' + s.texttransform + ';';
				if (s.letterspacing) ctStyle += 'letter-spacing:' + s.letterspacing + 'px;';
				if (s.lineheight) ctStyle += 'line-height:' + s.lineheight + '%;';
				return '<div style="' + ctStyle + align + wrapStyle + '">' + escHtml(block.content) + '</div>';

			default:
				return '<div style="color:#999;font-size:12px;">Unknown block</div>';
		}
	}

	/* ================================================================
	 * Inspector
	 * ================================================================ */
	function selectBlock(id) {
		selectedId = id;
		renderCanvas();
		renderInspector();
	}

	function selectCard() {
		selectedId = '__card__';
		renderCanvas();
		renderInspector();
	}

	function renderInspector() {
		var container = document.getElementById('ppmstr-inspector-content');
		var title     = document.querySelector('.ppmstr-builder-inspector .ppmstr-builder-sidebar-title');

		if (selectedId === '__card__') {
			if (title) title.textContent = 'Card Settings';
			container.innerHTML = renderCardInspector();
			bindCardInspector(container);
			return;
		}

		var block = getBlock(selectedId);
		if (!block) {
			if (title) title.textContent = 'Settings';
			container.innerHTML = '<p class="ppmstr-text-muted" style="font-size:13px;padding:8px 0;">Click the card or a block to edit.</p>';
			return;
		}

		var def = blockDefs[block.type];
		if (title) title.textContent = (def ? def.label : block.type) + ' Settings';
		container.innerHTML = renderBlockInspector(block);
		bindBlockInspector(container, block);
	}

	/* ----- Card Inspector ----- */
	function renderCardInspector() {
		var gs   = globalStyles;
		var html = '';

		/* Background */
		html += '<div class="ppmstr-insp-section-title">BACKGROUND</div>';
		html += makeColorField('cardBg', 'Color', gs.cardBg || '#FFFFFF');

		html += '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">Gradient</span>';
		html += '<label style="display:flex;align-items:center;gap:6px;font-size:12px;cursor:pointer;margin-bottom:6px;"><input type="checkbox" data-card="cardGradient" ' + (gs.cardGradient ? 'checked' : '') + ' /> Enable gradient</label>';
		if (gs.cardGradient) {
			html += '<div style="display:flex;gap:6px;align-items:center;margin-bottom:4px;"><span style="font-size:11px;color:#6C7293;">From</span><input type="color" class="ppmstr-insp-color" data-card="cardGradFrom" value="' + (gs.cardGradFrom || '#FFFFFF') + '" />';
			html += '<span style="font-size:11px;color:#6C7293;">To</span><input type="color" class="ppmstr-insp-color" data-card="cardGradTo" value="' + (gs.cardGradTo || '#F0F2F8') + '" /></div>';
			html += '<div style="display:flex;gap:6px;align-items:center;"><span style="font-size:11px;color:#6C7293;">Angle</span><input type="range" class="ppmstr-insp-range" data-card="cardGradAngle" min="0" max="360" step="1" value="' + (gs.cardGradAngle || 135) + '" style="flex:1;" /><span class="ppmstr-insp-range-val">' + (gs.cardGradAngle || 135) + '°</span></div>';
		}
		html += '</div>';

		/* Size & Shape */
		html += '<div class="ppmstr-insp-section-title">SIZE & SHAPE</div>';
		html += makeRangeField('maxWidth', 'Max Width', gs.maxWidth, 200, 900, 10);
		html += makeRangeField('cardRadius', 'Border Radius', gs.cardRadius, 0, 50, 1);
		html += makeRangeField('cardPadding', 'Padding', gs.cardPadding, 0, 80, 1);
		html += makeRangeField('cardMinHeight', 'Min Height', gs.cardMinHeight || 0, 0, 600, 10);

		/* Border */
		html += '<div class="ppmstr-insp-section-title">BORDER</div>';
		html += makeRangeField('cardBorderWidth', 'Width', gs.cardBorderWidth || 0, 0, 8, 1);
		html += makeColorField('cardBorderColor', 'Color', gs.cardBorderColor || '#E4E6EF');

		/* Effects */
		html += '<div class="ppmstr-insp-section-title">EFFECTS</div>';
		html += '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">Shadow</span>';
		html += '<label style="display:flex;align-items:center;gap:6px;font-size:12px;cursor:pointer;"><input type="checkbox" data-card="cardShadow" ' + (gs.cardShadow ? 'checked' : '') + ' /> Enable shadow</label>';
		html += '</div>';

		/* Visibility */
		html += '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">Card Visible</span>';
		html += '<label style="display:flex;align-items:center;gap:6px;font-size:12px;cursor:pointer;"><input type="checkbox" data-card="cardVisible" ' + (gs.cardVisible !== false ? 'checked' : '') + ' /> Show card container</label>';
		html += '<p style="font-size:10px;color:#A0A5B8;margin:4px 0 0;">Uncheck to make blocks float without a card.</p>';
		html += '</div>';

		/* Alignment */
		html += '<div class="ppmstr-insp-section-title">POSITION</div>';
		html += '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">Alignment</span>';
		html += '<div style="display:flex;gap:4px;">';
		['left', 'center', 'right'].forEach(function (a) {
			var active = ((gs.cardAlign || 'center') === a) ? 'background:#6C5CE7;color:#FFF;' : '';
			html += '<button type="button" class="ppmstr-cb-tool ppmstr-card-align-btn" data-card="cardAlign" data-value="' + a + '" style="width:32px;' + active + '">' + a.charAt(0).toUpperCase() + '</button>';
		});
		html += '</div></div>';

		return html;
	}

	function bindCardInspector(container) {
		container.querySelectorAll('[data-card]').forEach(function (el) {
			var event = (el.type === 'checkbox') ? 'change' : 'input';

			/* Card alignment buttons */
			if (el.classList.contains('ppmstr-card-align-btn')) {
				el.addEventListener('click', function () {
					globalStyles[el.getAttribute('data-card')] = el.getAttribute('data-value');
					applyGlobalStyles();
					renderInspector();
				});
				return;
			}

			el.addEventListener(event, function () {
				var key = el.getAttribute('data-card');
				if (el.type === 'checkbox') {
					globalStyles[key] = el.checked;
					if (key === 'cardGradient' || key === 'cardVisible') renderInspector();
				} else if (el.type === 'range') {
					globalStyles[key] = parseInt(el.value, 10);
					var valEl = el.parentElement.querySelector('.ppmstr-insp-range-val');
					if (valEl) valEl.textContent = el.value + (key === 'cardGradAngle' ? '\u00b0' : '');
				} else if (el.type === 'color') {
					globalStyles[key] = el.value;
				}
				applyGlobalStyles();
			});
		});
	}

	/* ----- Block Inspector ----- */
	function renderBlockInspector(block) {
		var s    = block.settings;
		var html = '';

		/* -- Content / Upload -- */
		if (block.type === 'logo') {
			html += '<div class="ppmstr-insp-section-title">IMAGE</div>';
			html += '<div class="ppmstr-insp-group">';
			if (block.content) {
				html += '<div style="margin-bottom:8px;text-align:center;"><img src="' + escHtml(block.content) + '" style="max-height:60px;max-width:100%;border-radius:4px;" /></div>';
			}
			html += '<button type="button" class="ppmstr-btn ppmstr-btn--secondary ppmstr-btn--sm ppmstr-upload-logo" style="width:100%;margin-bottom:6px;">Upload Image</button>';
			html += '<input type="text" class="ppmstr-insp-input" data-field="content" value="' + escHtml(block.content) + '" placeholder="Or paste image URL\u2026" />';
			html += '</div>';
		} else if (['heading', 'description', 'custom_text'].indexOf(block.type) >= 0) {
			html += '<div class="ppmstr-insp-section-title">CONTENT</div>';
			html += '<div class="ppmstr-insp-group">';
			html += '<textarea class="ppmstr-insp-input" data-field="content" rows="3">' + escHtml(block.content) + '</textarea>';
			html += '</div>';
		} else if (block.type === 'password_input') {
			html += '<div class="ppmstr-insp-section-title">PLACEHOLDER</div>';
			html += '<div class="ppmstr-insp-group">';
			html += '<input type="text" class="ppmstr-insp-input" data-field="content" value="' + escHtml(block.content) + '" />';
			html += '</div>';
		} else if (block.type === 'submit_button') {
			html += '<div class="ppmstr-insp-section-title">BUTTON TEXT</div>';
			html += '<div class="ppmstr-insp-group">';
			html += '<input type="text" class="ppmstr-insp-input" data-field="content" value="' + escHtml(block.content) + '" />';
			html += '</div>';
		}

		/* -- Icon Type -- */
		if (block.type === 'icon') {
			html += '<div class="ppmstr-insp-section-title">ICON</div>';
			html += '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">Type</span>';
			html += '<div class="ppmstr-icon-select" style="flex-wrap:wrap;">';
			['lock', 'shield', 'key', 'eye', 'lockopen', 'fingerprint', 'userlock'].forEach(function (itype) {
				var labels = {lock:'Lock',shield:'Shield',key:'Key',eye:'Eye',lockopen:'Unlock',fingerprint:'Fingerprint',userlock:'User Lock'};
				var active = ((s.icontype || 'lock') === itype) ? 'background:#6C5CE7;color:#FFF;' : 'background:#F0F2F5;color:#6C7293;';
				html += '<button type="button" class="ppmstr-icon-btn" data-icon="' + itype + '" style="' + active + '" title="' + (labels[itype] || itype) + '">';
				html += '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">' + iconSVGs[itype] + '</svg>';
				html += '</button>';
			});
			html += '</div></div>';
		}

		/* -- Placement / Zone -- */
		html += '<div class="ppmstr-insp-section-title">PLACEMENT</div>';
		html += '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">Zone</span>';
		html += '<select class="ppmstr-insp-input ppmstr-zone-select" style="padding:6px 8px;">';
		var curZone = block.zone || 'card';
		[{ v: 'before_card', l: 'Above Card' }, { v: 'card', l: 'Inside Card' }, { v: 'after_card', l: 'Below Card' }].forEach(function (opt) {
			html += '<option value="' + opt.v + '"' + (curZone === opt.v ? ' selected' : '') + '>' + opt.l + '</option>';
		});
		html += '</select></div>';

		/* -- Style fields -- */
		var styleFields = [];

		/* Font family for text blocks */
		if (typeof s.fontfamily !== 'undefined') {
			html += '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">Font Family</span>';
			html += '<select class="ppmstr-insp-input ppmstr-fontfamily-select" data-setting="fontfamily" style="padding:6px 8px;">';
			fontFamilies.forEach(function (ff) {
				html += '<option value="' + escHtml(ff.v) + '"' + ((s.fontfamily || 'inherit') === ff.v ? ' selected' : '') + ' style="font-family:' + ff.v + '">' + ff.l + '</option>';
			});
			html += '</select></div>';
		}

		if (typeof s.fontsize     !== 'undefined') styleFields.push({ key: 'fontsize',     label: 'Font Size',     type: 'range', min: 8, max: 60 });
		if (typeof s.fontweight   !== 'undefined') styleFields.push({ key: 'fontweight',   label: 'Font Weight',   type: 'range', min: 100, max: 900, step: 100 });
		if (typeof s.color        !== 'undefined') styleFields.push({ key: 'color',        label: 'Color',         type: 'color' });
		if (typeof s.textcolor    !== 'undefined') styleFields.push({ key: 'textcolor',    label: 'Text Color',    type: 'color' });
		if (typeof s.size         !== 'undefined') styleFields.push({ key: 'size',         label: 'Size',          type: 'range', min: 16, max: 120 });
		if (typeof s.maxheight    !== 'undefined') styleFields.push({ key: 'maxheight',    label: 'Max Height',    type: 'range', min: 16, max: 200 });
		if (typeof s.opacity      !== 'undefined') styleFields.push({ key: 'opacity',      label: 'Opacity',       type: 'range', min: 0, max: 100 });
		if (typeof s.bgcolor      !== 'undefined' && block.type !== 'submit_button') styleFields.push({ key: 'bgcolor', label: 'Block BG', type: 'bgcolor' });
		if (typeof s.bgcolor      !== 'undefined' && block.type === 'submit_button') styleFields.push({ key: 'bgcolor', label: 'BG Color', type: 'color' });
		if (typeof s.hovercolor   !== 'undefined') styleFields.push({ key: 'hovercolor',   label: 'Hover Color',   type: 'color' });
		if (typeof s.errbg        !== 'undefined') styleFields.push({ key: 'errbg',        label: 'Error BG',      type: 'text' });
		if (typeof s.inputbg      !== 'undefined') styleFields.push({ key: 'inputbg',      label: 'Input BG',      type: 'color' });
		if (typeof s.bordercolor  !== 'undefined') styleFields.push({ key: 'bordercolor',  label: 'Border Color',  type: 'color' });
		if (typeof s.borderwidth  !== 'undefined') styleFields.push({ key: 'borderwidth',  label: 'Border Width',  type: 'range', min: 0, max: 6 });
		if (typeof s.borderradius !== 'undefined') styleFields.push({ key: 'borderradius', label: 'Border Radius', type: 'range', min: 0, max: 30 });
		if (typeof s.focusbordercolor !== 'undefined') styleFields.push({ key: 'focusbordercolor', label: 'Focus Border', type: 'color' });
		if (typeof s.alignment    !== 'undefined') styleFields.push({ key: 'alignment',    label: 'Alignment',     type: 'align' });
		if (typeof s.height       !== 'undefined') styleFields.push({ key: 'height',       label: 'Height',        type: 'range', min: 4, max: 100 });
		if (typeof s.width        !== 'undefined') styleFields.push({ key: 'width',        label: 'Thickness',     type: 'range', min: 1, max: 6 });
		if (typeof s.inputpadding !== 'undefined') styleFields.push({ key: 'inputpadding', label: 'Input Padding', type: 'range', min: 4, max: 30 });
		if (typeof s.paddingv     !== 'undefined') styleFields.push({ key: 'paddingv',     label: 'Vertical Pad',  type: 'range', min: 4, max: 30 });
		if (typeof s.paddingh     !== 'undefined') styleFields.push({ key: 'paddingh',     label: 'Horizontal Pad', type: 'range', min: 8, max: 60 });

		/* Text Transform */
		if (typeof s.texttransform !== 'undefined') {
			html += '<div class="ppmstr-insp-section-title">TYPOGRAPHY</div>';
			html += '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">Transform</span>';
			html += '<div style="display:flex;gap:4px;">';
			[{v:'none',l:'Aa'},{v:'uppercase',l:'AB'},{v:'lowercase',l:'ab'},{v:'capitalize',l:'Ab'}].forEach(function (tt) {
				var active = ((s.texttransform || 'none') === tt.v) ? 'background:#6C5CE7;color:#FFF;' : '';
				html += '<button type="button" class="ppmstr-cb-tool ppmstr-align-btn" data-setting="texttransform" data-value="' + tt.v + '" style="width:32px;font-size:11px;' + active + '">' + tt.l + '</button>';
			});
			html += '</div></div>';
			if (typeof s.letterspacing !== 'undefined') styleFields.push({ key: 'letterspacing', label: 'Letter Spacing', type: 'range', min: -2, max: 10 });
			if (typeof s.lineheight !== 'undefined') styleFields.push({ key: 'lineheight', label: 'Line Height %', type: 'range', min: 80, max: 250, step: 5 });
		}

		/* Full width toggle for button/input */
		if (typeof s.fullwidth !== 'undefined') {
			html += '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">Full Width</span>';
			html += '<label style="display:flex;align-items:center;gap:6px;font-size:12px;cursor:pointer;"><input type="checkbox" class="ppmstr-fullwidth-toggle" data-setting="fullwidth" ' + (s.fullwidth ? 'checked' : '') + ' /> Stretch to full width</label>';
			html += '</div>';
		}

		if (styleFields.length) {
			html += '<div class="ppmstr-insp-section-title">STYLE</div>';
			styleFields.forEach(function (f) { html += renderSettingField(f, s); });
		}

		/* -- Spacing fields -- */
		var spacingFields = [];
		if (typeof s.margintop    !== 'undefined') spacingFields.push({ key: 'margintop',    label: 'Top Margin',    type: 'range', min: 0, max: 80 });
		if (typeof s.marginbottom !== 'undefined') spacingFields.push({ key: 'marginbottom', label: 'Bottom Margin', type: 'range', min: 0, max: 80 });
		if (typeof s.blockpadding !== 'undefined') spacingFields.push({ key: 'blockpadding', label: 'Block Padding', type: 'range', min: 0, max: 60 });
		if (typeof s.blockradius  !== 'undefined') spacingFields.push({ key: 'blockradius',  label: 'Block Radius',  type: 'range', min: 0, max: 30 });

		if (spacingFields.length) {
			html += '<div class="ppmstr-insp-section-title">SPACING</div>';
			spacingFields.forEach(function (f) { html += renderSettingField(f, s); });
		}

		return html;
	}

	function renderSettingField(field, s) {
		var val  = s[field.key];
		var html = '';

		if (field.type === 'color') {
			html += '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">' + field.label + '</span>';
			html += '<input type="color" class="ppmstr-insp-color" data-setting="' + field.key + '" value="' + (val || '#000000') + '" /></div>';
		} else if (field.type === 'bgcolor') {
			var isTrans = (!val || val === 'transparent');
			html += '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">' + field.label + '</span>';
			html += '<div style="display:flex;gap:6px;align-items:center;">';
			html += '<input type="color" class="ppmstr-insp-color" data-setting="' + field.key + '" value="' + (isTrans ? '#FFFFFF' : val) + '" />';
			html += '<label style="font-size:11px;display:flex;align-items:center;gap:4px;"><input type="checkbox" class="ppmstr-insp-transparent" data-setting="' + field.key + '"' + (isTrans ? ' checked' : '') + ' /> None</label>';
			html += '</div></div>';
		} else if (field.type === 'range') {
			html += '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">' + field.label + '</span>';
			html += '<div class="ppmstr-insp-range-row"><input type="range" class="ppmstr-insp-range" data-setting="' + field.key + '" min="' + (field.min || 0) + '" max="' + (field.max || 100) + '" step="' + (field.step || 1) + '" value="' + (val || 0) + '" /><span class="ppmstr-insp-range-val">' + (val || 0) + '</span></div></div>';
		} else if (field.type === 'align') {
			html += '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">' + field.label + '</span>';
			html += '<div style="display:flex;gap:4px;">';
			['left', 'center', 'right'].forEach(function (a) {
				var active = (val === a) ? 'background:#6C5CE7;color:#FFF;' : '';
				html += '<button type="button" class="ppmstr-cb-tool ppmstr-align-btn" data-setting="' + field.key + '" data-value="' + a + '" style="width:32px;' + active + '">' + a.charAt(0).toUpperCase() + '</button>';
			});
			html += '</div></div>';
		} else if (field.type === 'text') {
			html += '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">' + field.label + '</span>';
			html += '<input type="text" class="ppmstr-insp-input" data-setting="' + field.key + '" value="' + escHtml(val || '') + '" /></div>';
		}

		return html;
	}

	function bindBlockInspector(container, block) {
		/* Content fields */
		container.querySelectorAll('[data-field="content"]').forEach(function (el) {
			el.addEventListener('input', function () { block.content = el.value; renderCanvas(); });
		});

		/* Logo upload via WP Media */
		var uploadBtn = container.querySelector('.ppmstr-upload-logo');
		if (uploadBtn) {
			uploadBtn.addEventListener('click', function () {
				if (typeof wp === 'undefined' || !wp.media) { alert('Media uploader not available.'); return; }
				var frame = wp.media({
					title: 'Select Logo Image',
					button: { text: 'Use this image' },
					multiple: false,
					library: { type: 'image' }
				});
				frame.on('select', function () {
					var attachment = frame.state().get('selection').first().toJSON();
					block.content = attachment.url;
					renderCanvas();
					renderInspector();
				});
				frame.open();
			});
		}

		/* Icon type buttons */
		container.querySelectorAll('.ppmstr-icon-btn').forEach(function (btn) {
			btn.addEventListener('click', function () {
				block.settings.icontype = btn.getAttribute('data-icon');
				renderCanvas();
				renderInspector();
			});
		});

		/* Zone select */
		var zoneSelect = container.querySelector('.ppmstr-zone-select');
		if (zoneSelect) {
			zoneSelect.addEventListener('change', function () {
				var newZone = zoneSelect.value;
				var oldZone = getBlockZone(block.id);
				if (oldZone && newZone !== oldZone) {
					blockStore[oldZone] = blockStore[oldZone].filter(function (b) { return b.id !== block.id; });
					block.zone = newZone;
					blockStore[newZone].push(block);
					renderCanvas();
				}
			});
		}

		/* Font family select */
		var ffSelect = container.querySelector('.ppmstr-fontfamily-select');
		if (ffSelect) {
			ffSelect.addEventListener('change', function () {
				block.settings.fontfamily = ffSelect.value;
				renderCanvas();
			});
		}

		/* Fullwidth toggle */
		var fwToggle = container.querySelector('.ppmstr-fullwidth-toggle');
		if (fwToggle) {
			fwToggle.addEventListener('change', function () {
				block.settings.fullwidth = fwToggle.checked;
				renderCanvas();
			});
		}

		/* Transparent checkboxes */
		container.querySelectorAll('.ppmstr-insp-transparent').forEach(function (cb) {
			cb.addEventListener('change', function () {
				var key = cb.getAttribute('data-setting');
				if (cb.checked) {
					block.settings[key] = 'transparent';
				} else {
					var colorInput = container.querySelector('input[type="color"][data-setting="' + key + '"]');
					block.settings[key] = colorInput ? colorInput.value : '#FFFFFF';
				}
				renderCanvas();
			});
		});

		/* Setting fields */
		container.querySelectorAll('[data-setting]').forEach(function (el) {
			if (el.classList.contains('ppmstr-insp-transparent')) return;
			if (el.classList.contains('ppmstr-fontfamily-select')) return;
			if (el.classList.contains('ppmstr-fullwidth-toggle')) return;
			var event = el.type === 'range' ? 'input' : (el.type === 'color' ? 'input' : 'click');

			el.addEventListener(event, function () {
				var key = el.getAttribute('data-setting');
				if (el.classList.contains('ppmstr-align-btn')) {
					block.settings[key] = el.getAttribute('data-value');
				} else if (el.type === 'range') {
					block.settings[key] = parseFloat(el.value);
					var valEl = el.parentElement.querySelector('.ppmstr-insp-range-val');
					if (valEl) valEl.textContent = el.value;
				} else if (el.type === 'color') {
					var transCb = container.querySelector('.ppmstr-insp-transparent[data-setting="' + key + '"]');
					if (transCb && transCb.checked) transCb.checked = false;
					block.settings[key] = el.value;
				} else if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') {
					block.settings[key] = el.value;
				}
				renderCanvas();
				if (el.classList.contains('ppmstr-align-btn')) renderInspector();
			});

			if (el.tagName === 'INPUT' && el.type === 'text') {
				el.addEventListener('input', function () {
					block.settings[el.getAttribute('data-setting')] = el.value;
					renderCanvas();
				});
			}
		});
	}

	/* ================================================================
	 * Canvas Clicks (card selection + deselect)
	 * ================================================================ */
	function bindCanvasClicks() {
		document.getElementById('ppmstr-canvas-card').addEventListener('click', function (e) {
			if (e.target.closest('.ppmstr-cb')) return;
			selectCard();
		});
		document.getElementById('ppmstr-canvas-bg').addEventListener('click', function (e) {
			if (e.target.id === 'ppmstr-canvas-bg' || e.target.classList.contains('ppmstr-canvas-zone') || e.target.classList.contains('ppmstr-zone-placeholder')) {
				selectedId = null;
				renderCanvas();
				renderInspector();
			}
		});
	}

	/* ================================================================
	 * Palette
	 * ================================================================ */
	function bindPalette() {
		document.querySelectorAll('.ppmstr-block-item').forEach(function (item) {
			if (isFreeMode) {
				// Free mode: disable all palette interactions.
				item.style.opacity = '0.38';
				item.style.cursor  = 'not-allowed';
				item.setAttribute('draggable', 'false');
				return;
			}
			item.addEventListener('click', function () {
				addBlock(item.getAttribute('data-block-type'), 'card');
				renderCanvas();
			});
			item.addEventListener('dragstart', function (e) {
				e.dataTransfer.setData('text/plain', 'palette:' + item.getAttribute('data-block-type'));
			});
		});
	}

	/* ================================================================
	 * Canvas Drop (multi-zone)
	 * ================================================================ */
	function bindCanvasDrop() {
		bindZoneDrop('ppmstr-zone-before', 'before_card');
		bindZoneDrop('ppmstr-canvas-card', 'card');
		bindZoneDrop('ppmstr-zone-after', 'after_card');
	}

	function bindZoneDrop(elementId, zone) {
		var el = document.getElementById(elementId);

		if (isFreeMode) return; // Free mode: no dropping allowed.

		el.addEventListener('dragover', function (e) {
			e.preventDefault();
			e.stopPropagation();
			e.dataTransfer.dropEffect = 'move';
			showDropIndicator(el, e);
		});

		el.addEventListener('dragleave', function (e) {
			if (!el.contains(e.relatedTarget)) removeDropIndicator();
		});

		el.addEventListener('drop', function (e) {
			e.preventDefault();
			e.stopPropagation();
			removeDropIndicator();

			var data     = e.dataTransfer.getData('text/plain');
			var dropIdx  = getDropIndex(el, zone, e);

			if (data.startsWith('palette:')) {
				addBlock(data.replace('palette:', ''), zone, dropIdx);
			} else if (data.startsWith('canvas:')) {
				var blockId = data.replace('canvas:', '');
				var oldZone = getBlockZone(blockId);
				if (oldZone) {
					var blk    = getBlock(blockId);
					var oldIdx = blockStore[oldZone].indexOf(blk);
					blockStore[oldZone].splice(oldIdx, 1);
					blk.zone = zone;
					if (oldZone === zone && dropIdx > oldIdx) dropIdx--;
					blockStore[zone].splice(dropIdx, 0, blk);
				}
			}
			renderCanvas();
		});
	}

	function getDropIndex(container, zone, e) {
		var els = container.querySelectorAll('.ppmstr-cb');
		for (var i = 0; i < els.length; i++) {
			var rect = els[i].getBoundingClientRect();
			if (e.clientY < rect.top + rect.height / 2) return i;
		}
		return blockStore[zone].length;
	}

	function showDropIndicator(container, e) {
		removeDropIndicator();
		var els       = container.querySelectorAll('.ppmstr-cb');
		var indicator = document.createElement('div');
		indicator.className = 'ppmstr-drop-indicator';
		indicator.id        = 'ppmstr-drop-ind';

		for (var i = 0; i < els.length; i++) {
			var rect = els[i].getBoundingClientRect();
			if (e.clientY < rect.top + rect.height / 2) {
				els[i].insertAdjacentElement('beforebegin', indicator);
				return;
			}
		}
		if (els.length > 0) {
			els[els.length - 1].insertAdjacentElement('afterend', indicator);
		} else {
			container.appendChild(indicator);
		}
	}

	function removeDropIndicator() {
		var ind = document.getElementById('ppmstr-drop-ind');
		if (ind) ind.remove();
	}

	/* ================================================================
	 * Global Styles (left sidebar — page bg + gradient + overlay)
	 * ================================================================ */
	function bindGlobalStyles() {
		var bgEl    = document.getElementById('ppmstr-gs-bg');
		var bgImgEl = document.getElementById('ppmstr-gs-bg-image');

		if (bgEl) {
			bgEl.addEventListener('input', function () {
				globalStyles.bgColor = bgEl.value;
				applyGlobalStyles();
			});
		}
		if (bgImgEl) {
			bgImgEl.addEventListener('input', function () {
				globalStyles.bgImage = bgImgEl.value;
				applyGlobalStyles();
			});
		}

		var bgUploadBtn = document.getElementById('ppmstr-gs-bg-upload');
		if (bgUploadBtn) {
			bgUploadBtn.addEventListener('click', function () {
				if (typeof wp === 'undefined' || !wp.media) return;
				var frame = wp.media({
					title: 'Select Background Image',
					button: { text: 'Use this image' },
					multiple: false,
					library: { type: 'image' }
				});
				frame.on('select', function () {
					var attachment = frame.state().get('selection').first().toJSON();
					globalStyles.bgImage = attachment.url;
					if (bgImgEl) bgImgEl.value = attachment.url;
					applyGlobalStyles();
				});
				frame.open();
			});
		}

		/* --- Page Gradient --- */
		var gradEnable = document.getElementById('ppmstr-gs-bg-grad-enable');
		var gradCtrls  = document.getElementById('ppmstr-gs-bg-grad-controls');
		var gradFrom   = document.getElementById('ppmstr-gs-bg-grad-from');
		var gradTo     = document.getElementById('ppmstr-gs-bg-grad-to');
		var gradAngle  = document.getElementById('ppmstr-gs-bg-grad-angle');

		if (gradEnable) {
			gradEnable.addEventListener('change', function () {
				globalStyles.bgGradient = gradEnable.checked;
				if (gradCtrls) gradCtrls.style.display = gradEnable.checked ? 'flex' : 'none';
				applyGlobalStyles();
			});
		}
		if (gradFrom) {
			gradFrom.addEventListener('input', function () {
				globalStyles.bgGradFrom = gradFrom.value;
				applyGlobalStyles();
			});
		}
		if (gradTo) {
			gradTo.addEventListener('input', function () {
				globalStyles.bgGradTo = gradTo.value;
				applyGlobalStyles();
			});
		}
		if (gradAngle) {
			gradAngle.addEventListener('input', function () {
				globalStyles.bgGradAngle = parseInt(gradAngle.value, 10);
				applyGlobalStyles();
			});
		}

		/* --- Page Overlay --- */
		var ovEnable  = document.getElementById('ppmstr-gs-bg-overlay-enable');
		var ovCtrls   = document.getElementById('ppmstr-gs-bg-overlay-controls');
		var ovColor   = document.getElementById('ppmstr-gs-bg-overlay-color');
		var ovOpacity = document.getElementById('ppmstr-gs-bg-overlay-opacity');

		if (ovEnable) {
			ovEnable.addEventListener('change', function () {
				globalStyles.bgOverlay = ovEnable.checked;
				if (ovCtrls) ovCtrls.style.display = ovEnable.checked ? 'flex' : 'none';
				applyGlobalStyles();
			});
		}
		if (ovColor) {
			ovColor.addEventListener('input', function () {
				globalStyles.bgOverlayColor = ovColor.value;
				applyGlobalStyles();
			});
		}
		if (ovOpacity) {
			ovOpacity.addEventListener('input', function () {
				globalStyles.bgOverlayOpacity = parseInt(ovOpacity.value, 10);
				applyGlobalStyles();
			});
		}
	}

	function applyGlobalStyles() {
		var bg   = document.getElementById('ppmstr-canvas-bg');
		var card = document.getElementById('ppmstr-canvas-card');
		var anim = globalStyles.animation || 'none';

		if (bg) {
			bg.style.position = 'relative';
			bg.style.overflow = 'hidden';

			/* Animation-specific background overrides */
			if (anim === 'orbs') {
				bg.style.background = '#07071A';
			} else if (anim === 'cyber') {
				bg.style.background = '#040812';
			} else {
				/* Normal: image > gradient > solid */
				if (globalStyles.bgImage) {
					bg.style.background = 'url(' + globalStyles.bgImage + ') center/cover no-repeat';
				} else if (globalStyles.bgGradient) {
					var pAngle = globalStyles.bgGradAngle || 135;
					var pFrom  = globalStyles.bgGradFrom || '#F0F2F8';
					var pTo    = globalStyles.bgGradTo || '#FFFFFF';
					bg.style.background = 'linear-gradient(' + pAngle + 'deg, ' + pFrom + ', ' + pTo + ')';
				} else {
					bg.style.background = globalStyles.bgColor;
				}
			}

			/* Overlay pseudo-element via a child div */
			var overlayEl = bg.querySelector('.ppmstr-canvas-overlay');
			if (globalStyles.bgOverlay && anim === 'none') {
				if (!overlayEl) {
					overlayEl = document.createElement('div');
					overlayEl.className = 'ppmstr-canvas-overlay';
					overlayEl.style.cssText = 'position:absolute;top:0;left:0;right:0;bottom:0;pointer-events:none;z-index:0;';
					bg.insertBefore(overlayEl, bg.firstChild);
				}
				var oColor = globalStyles.bgOverlayColor || '#000000';
				var oAlpha = (globalStyles.bgOverlayOpacity || 50) / 100;
				var r = parseInt(oColor.substr(1, 2), 16);
				var g = parseInt(oColor.substr(3, 2), 16);
				var b = parseInt(oColor.substr(5, 2), 16);
				overlayEl.style.background = 'rgba(' + r + ',' + g + ',' + b + ',' + oAlpha + ')';
				overlayEl.style.display = '';
			} else if (overlayEl) {
				overlayEl.style.display = 'none';
			}

			/* Inject / refresh animated decorative elements */
			updateAnimElements(bg, anim);
		}

		if (card) {
			/* Reset backdrop-filter first so switching animations clears it */
			card.style.backdropFilter       = '';
			card.style.webkitBackdropFilter = '';

			/* Animation-specific card styles */
			if (anim === 'glass' || anim === 'orbs') {
				card.style.background           = 'rgba(255,255,255,0.07)';
				card.style.backdropFilter       = 'blur(40px)';
				card.style.webkitBackdropFilter = 'blur(40px)';
				card.style.border               = '1px solid rgba(255,255,255,0.12)';
				card.style.boxShadow            = '0 8px 32px rgba(0,0,0,0.4)';
			} else if (anim === 'pulse' || anim === 'cyber') {
				card.style.background           = 'rgba(255,255,255,0.05)';
				card.style.backdropFilter       = 'blur(20px)';
				card.style.webkitBackdropFilter = 'blur(20px)';
				card.style.border               = '1px solid rgba(255,255,255,0.08)';
				card.style.boxShadow            = '0 8px 32px rgba(0,0,0,0.5)';
			} else {
				/* Normal card */
				if (globalStyles.cardGradient) {
					var angle = globalStyles.cardGradAngle || 135;
					var from  = globalStyles.cardGradFrom || '#FFFFFF';
					var to    = globalStyles.cardGradTo || '#F0F2F8';
					card.style.background = 'linear-gradient(' + angle + 'deg, ' + from + ', ' + to + ')';
				} else {
					card.style.background = globalStyles.cardBg;
				}
				var bw = globalStyles.cardBorderWidth || 0;
				card.style.border     = bw > 0 ? bw + 'px solid ' + (globalStyles.cardBorderColor || '#E4E6EF') : 'none';
				card.style.boxShadow  = globalStyles.cardShadow ? '0 8px 40px rgba(0,0,0,0.08)' : 'none';

				if (globalStyles.cardVisible === false) {
					card.style.background = 'transparent';
					card.style.boxShadow  = 'none';
					card.style.border     = '1px dashed #C8CBDA';
				}
			}

			/* Always apply these */
			card.style.borderRadius = (globalStyles.cardRadius || 16) + 'px';
			card.style.padding      = (globalStyles.cardPadding || 40) + 'px';
			card.style.maxWidth     = (globalStyles.maxWidth || 420) + 'px';
			card.style.minHeight    = (globalStyles.cardMinHeight || 0) + 'px';

			/* Card alignment */
			var align = globalStyles.cardAlign || 'center';
			card.style.margin = align === 'center' ? '0 auto' : (align === 'right' ? '0 0 0 auto' : '0 auto 0 0');
		}
	}

	/**
	 * Inject / refresh animated decorative elements inside the canvas background.
	 * Clears any previous anim elements before injecting new ones.
	 */
	function updateAnimElements(bg, anim) {
		if (!bg) return;

		/* Remove old anim elements */
		bg.querySelectorAll('.ppmstr-orb, .ppmstr-pulse-glow, .ppmstr-radar-rings, .ppmstr-cyber-scan').forEach(function (el) {
			el.remove();
		});

		/* Helper: insert before first child so anim elements paint BEHIND the card/zones */
		var firstChild = bg.firstChild;
		function prepend(el) {
			if (firstChild) {
				bg.insertBefore(el, firstChild);
			} else {
				bg.appendChild(el);
			}
		}

		if (anim === 'orbs') {
			var orbColors = [
				globalStyles.bgGradFrom || '#6C5CE7',
				globalStyles.bgGradTo   || '#00CEC9',
				globalStyles.bgGradFrom || '#A29BFE'
			];
			var orbPos = [
				{ top: '-10%', left: '-10%', w: '520px', h: '520px' },
				{ top: '55%',  left: '50%',  w: '420px', h: '420px' },
				{ top: '25%',  left: '-8%',  w: '300px', h: '300px' }
			];
			orbColors.forEach(function (c, i) {
				var orb = document.createElement('div');
				orb.className = 'ppmstr-orb';
				orb.style.cssText = [
					'position:absolute',
					'border-radius:50%',
					'filter:blur(90px)',
					'opacity:0.55',
					'pointer-events:none',
					'width:'  + orbPos[i].w,
					'height:' + orbPos[i].h,
					'top:'    + orbPos[i].top,
					'left:'   + orbPos[i].left,
					'background:' + c
				].join(';') + ';';
				prepend(orb);
			});

		} else if (anim === 'pulse') {
			var accent = (function () {
				var all = getAllBlocks();
				for (var i = 0; i < all.length; i++) {
					if (all[i].type === 'submit_button') return all[i].settings.bgcolor || '#6C5CE7';
				}
				return '#6C5CE7';
			}());

			var rings = document.createElement('div');
			rings.className = 'ppmstr-radar-rings';
			rings.style.cssText = 'position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);pointer-events:none;';
			for (var ri = 1; ri <= 4; ri++) {
				var sz  = ri * 110;
				var ring = document.createElement('div');
				ring.className = 'ppmstr-ring';
				ring.style.cssText = [
					'position:absolute',
					'border-radius:50%',
					'border:1px solid ' + accent + '44',
					'width:'  + sz + 'px',
					'height:' + sz + 'px',
					'top:'    + (-sz / 2) + 'px',
					'left:'   + (-sz / 2) + 'px'
				].join(';') + ';';
				rings.appendChild(ring);
			}
			prepend(rings);

			var glow = document.createElement('div');
			glow.className = 'ppmstr-pulse-glow';
			glow.style.cssText = [
				'position:absolute',
				'top:50%', 'left:50%',
				'transform:translate(-50%,-50%)',
				'width:500px', 'height:500px',
				'border-radius:50%',
				'background:radial-gradient(circle,' + accent + '33 0%,transparent 70%)',
				'pointer-events:none'
			].join(';') + ';';
			prepend(glow);

		} else if (anim === 'cyber') {
			var scan = document.createElement('div');
			scan.className = 'ppmstr-cyber-scan';
			scan.style.cssText = [
				'position:absolute',
				'left:0', 'right:0',
				'height:160px',
				'pointer-events:none',
				'top:15%',
				'background:linear-gradient(to bottom,transparent,rgba(108,92,231,0.07),transparent)'
			].join(';') + ';';
			prepend(scan);
		}
	}

	function syncGlobalInputs() {
		/* Basic fields */
		var map = { 'ppmstr-gs-bg': 'bgColor', 'ppmstr-gs-bg-image': 'bgImage' };
		for (var id in map) {
			var el = document.getElementById(id);
			if (el) el.value = globalStyles[map[id]] || '';
		}

		/* Gradient */
		var gradEnable = document.getElementById('ppmstr-gs-bg-grad-enable');
		var gradCtrls  = document.getElementById('ppmstr-gs-bg-grad-controls');
		var gradFrom   = document.getElementById('ppmstr-gs-bg-grad-from');
		var gradTo     = document.getElementById('ppmstr-gs-bg-grad-to');
		var gradAngle  = document.getElementById('ppmstr-gs-bg-grad-angle');
		if (gradEnable) gradEnable.checked = !!globalStyles.bgGradient;
		if (gradCtrls)  gradCtrls.style.display = globalStyles.bgGradient ? 'flex' : 'none';
		if (gradFrom)   gradFrom.value = globalStyles.bgGradFrom || '#F0F2F8';
		if (gradTo)     gradTo.value = globalStyles.bgGradTo || '#FFFFFF';
		if (gradAngle)  gradAngle.value = globalStyles.bgGradAngle || 135;

		/* Overlay */
		var ovEnable  = document.getElementById('ppmstr-gs-bg-overlay-enable');
		var ovCtrls   = document.getElementById('ppmstr-gs-bg-overlay-controls');
		var ovColor   = document.getElementById('ppmstr-gs-bg-overlay-color');
		var ovOpacity = document.getElementById('ppmstr-gs-bg-overlay-opacity');
		if (ovEnable)  ovEnable.checked = !!globalStyles.bgOverlay;
		if (ovCtrls)   ovCtrls.style.display = globalStyles.bgOverlay ? 'flex' : 'none';
		if (ovColor)   ovColor.value = globalStyles.bgOverlayColor || '#000000';
		if (ovOpacity) ovOpacity.value = globalStyles.bgOverlayOpacity || 50;
	}

	/* ================================================================
	 * Save / Publish / Top Bar
	 * ================================================================ */
	function bindTopBar() {
		document.getElementById('ppmstr-builder-save').addEventListener('click', function () { saveTemplate(false); });
		document.getElementById('ppmstr-builder-publish').addEventListener('click', function () { saveTemplate(true); });
	}

	function saveTemplate(activate) {
		var name   = document.getElementById('ppmstr-builder-name').value.trim();
		var status = document.getElementById('ppmstr-builder-status');

		if (!name) {
			status.textContent = 'Please enter a template name.';
			status.style.color = '#E17055';
			return;
		}

		var allBlocks = getAllBlocks();
		var hasInput  = allBlocks.some(function (b) { return b.type === 'password_input'; });
		var hasButton = allBlocks.some(function (b) { return b.type === 'submit_button'; });
		if (!hasInput || !hasButton) {
			status.textContent = 'Template must include Password Field and Submit Button.';
			status.style.color = '#E17055';
			return;
		}

		status.textContent = 'Saving\u2026';
		status.style.color = '#6C7293';

		var body = new URLSearchParams();
		body.append('action', 'ppmstr_save_template');
		body.append('nonce', ppmstrAdmin.nonce);
		body.append('template_id', editId);
		body.append('name', name);
		body.append('blocks', JSON.stringify(allBlocks));
		body.append('global_styles', JSON.stringify(globalStyles));

		fetch(ppmstrAdmin.ajaxUrl, {
			method: 'POST', credentials: 'same-origin',
			headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
			body: body.toString()
		})
		.then(function (r) { return r.json(); })
		.then(function (resp) {
			if (resp.success) {
				editId = resp.data.template_id;
				status.textContent = activate ? 'Saved! Activating\u2026' : 'Saved \u2714';
				status.style.color = '#00B894';

				if (activate) {
					activateTemplate(editId, function (activateResp) {
						if (activateResp && activateResp.success) {
							status.textContent = 'Published & Activated! Redirecting\u2026';
							// Redirect back to templates page so user sees the active template.
							setTimeout(function () {
								var url = (typeof ppmstrAdmin !== 'undefined' && ppmstrAdmin.templatesUrl)
									? ppmstrAdmin.templatesUrl
									: 'admin.php?page=ppmstr-templates';
								window.location.href = url;
							}, 900);
						} else {
							status.textContent = 'Saved but activation failed. Try activating from the Templates page.';
							status.style.color = '#E17055';
							setTimeout(function () { status.textContent = ''; }, 5000);
						}
					});
				} else {
					setTimeout(function () { status.textContent = ''; }, 3000);
				}
			} else {
				status.textContent = resp.data || 'Error saving.';
				status.style.color = '#E17055';
			}
		});
	}

	function activateTemplate(tplId, callback) {
		var body = new URLSearchParams();
		body.append('action', 'ppmstr_activate_template');
		body.append('nonce', ppmstrAdmin.nonce);
		body.append('template_id', tplId);

		fetch(ppmstrAdmin.ajaxUrl, {
			method: 'POST', credentials: 'same-origin',
			headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
			body: body.toString()
		})
		.then(function (r) { return r.json(); })
		.then(function (resp) {
			if (callback) callback(resp);
		});
	}

	/* ================================================================
	 * Free Mode: Apply Visual Restrictions
	 * ================================================================ */
	

	/* ================================================================
	 * Helpers
	 * ================================================================ */
	function escHtml(str) {
		var div = document.createElement('div');
		div.textContent = str || '';
		return div.innerHTML;
	}

	function makeColorField(key, label, value) {
		return '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">' + label + '</span>' +
			'<input type="color" class="ppmstr-insp-color" data-card="' + key + '" value="' + (value || '#FFFFFF') + '" /></div>';
	}

	function makeRangeField(key, label, value, min, max, step) {
		return '<div class="ppmstr-insp-group"><span class="ppmstr-insp-label">' + label + '</span>' +
			'<div class="ppmstr-insp-range-row"><input type="range" class="ppmstr-insp-range" data-card="' + key + '" min="' + min + '" max="' + max + '" step="' + (step || 1) + '" value="' + (value || 0) + '" /><span class="ppmstr-insp-range-val">' + (value || 0) + '</span></div></div>';
	}

})();
