'use strict';

function initSubmissionInboxUnifiedInspector(editor) {
	if (!editor || !editor.on) {
		return;
	}

	registerUnifiedInspectorCommand(editor);
	wrapNativeRightPanelCommand(editor, 'open-blocks');
	registerBlocksTabCommand(editor);
	window.setTimeout(function () {
		setupUnifiedInspectorPanel(editor);
	}, 0);
	editor.on('load', function () {
		setupUnifiedInspectorPanel(editor);
		window.setTimeout(function () {
			if (!editor.getSelected || !editor.getSelected()) {
				selectFormWrapperForInspector(editor);
			}
		}, 0);
	});
	editor.on('component:selected', function (component) {
		if (closestControlledStyleComponent(component)) {
			showUnifiedInspector(editor);
		}
	});
	editor.on('component:deselected', function () {
		window.setTimeout(function () {
			if (!editor.getSelected || !editor.getSelected()) {
				selectFormWrapperForInspector(editor);
			}
			updateUnifiedInspectorState(editor);
		}, 0);
	});
	[
		'component:styleUpdate',
		'component:update:style',
		'component:update',
	].forEach(function (eventName) {
		editor.on(eventName, function (component) {
			scheduleSelectedInspectorRefresh(editor, component);
		});
	});
}

function registerUnifiedInspectorCommand(editor) {
	if (!editor.Commands || !editor.Commands.add) {
		return;
	}

	editor.Commands.add('open-subin-inspector', {
		run: function (currentEditor) {
			showUnifiedInspector(currentEditor || editor);
		},
	});
}

function wrapNativeRightPanelCommand(editor, commandId) {
	var commands = editor && editor.Commands;
	var original;

	if (!commands || !commands.get || !commands.add || !commandId) {
		return;
	}

	original = commands.get(commandId);
	if (!original || original.__subinRightPanelWrapped) {
		return;
	}

	commands.add(commandId, {
		run: function (currentEditor, sender, options) {
			var activeEditor = currentEditor || editor;

			activeEditor.__subinActiveRightPanel = commandId;

			if (original.run) {
				var result = original.run.call(original, activeEditor, sender, options);
				scheduleApplyRightPanelMode(activeEditor, commandId === 'open-blocks' ? 'blocks' : 'layers');
				return result;
			}

			scheduleApplyRightPanelMode(activeEditor, commandId === 'open-blocks' ? 'blocks' : 'layers');
			return null;
		},
		stop: function (currentEditor, sender, options) {
			if (original.stop) {
				return original.stop.call(original, currentEditor || editor, sender, options);
			}

			return null;
		},
	});

	original.__subinRightPanelWrapped = true;
}

function setupUnifiedInspectorPanel(editor) {
	var viewsContainer = grapesjsViewsContainer(editor);

	if (!viewsContainer || viewsContainer.querySelector('.subin-gjs-unified-inspector')) {
		return;
	}

		var inspector = document.createElement('aside');
		inspector.className = 'subin-studio-inspector subin-gjs-unified-inspector subin-gjs-inspector';
		inspector.innerHTML = [
			'<div class="subin-inspector-head subin-gjs-unified-inspector__header">',
			'<span class="subin-studio-eyebrow">Selected element</span>',
			'<h3 class="subin-inspector-title">Form</h3>',
			'<div class="subin-inspector-selected subin-gjs-unified-inspector__selected">Form-wide content and appearance</div>',
			'<div class="subin-inspector-tabs" role="tablist" aria-label="Inspector sections">',
			'<button type="button" role="tab" data-subin-inspector-tab="content" aria-selected="true">Content</button>',
			'<button type="button" role="tab" data-subin-inspector-tab="validation" aria-selected="false">Validation</button>',
			'<button type="button" role="tab" data-subin-inspector-tab="design" aria-selected="false">Design</button>',
			'<button type="button" role="tab" data-subin-inspector-tab="advanced" aria-selected="false">Advanced</button>',
			'</div>',
			'</div>',
			'<div class="subin-inspector-scroll subin-gjs-inspector__body"></div>',
		].join('');
	viewsContainer.appendChild(inspector);
	bindCustomInspectorEvents(editor, inspector);
	installUnifiedInspectorPanelButton(editor);
	bindUnifiedInspectorViewSwitcher(editor);
	hideSeparateSettingsButtons(editor);
	markRightPanelButtons(editor);
	renderUnifiedInspector(editor);
	updateUnifiedInspectorState(editor);
	toggleUnifiedInspector(editor, true);
	updateRightPanelButtonState(editor, 'inspector');
}

function grapesjsViewsContainer(editor) {
	var container = editor && editor.getContainer ? editor.getContainer() : document.getElementById('subin-grapesjs-editor');
	var shell = container && container.closest ? container.closest('[data-subin-studio-shell]') : null;
	var externalHost = shell ? shell.querySelector('[data-subin-studio-inspector-host]') : null;

	return externalHost || (container ? container.querySelector('.gjs-pn-views-container') : null);
}

function installUnifiedInspectorPanelButton(editor) {
	var panels = editor && editor.Panels;
	var views = panels && panels.getPanel ? panels.getPanel('views') : null;
	var buttons = views && views.get ? views.get('buttons') : null;

	if (!buttons || !buttons.add) {
		return;
	}

	removePanelButton(buttons, 'open-sm');
	removePanelButton(buttons, 'open-tm');
	removePanelButton(buttons, 'open-layers');
	removePanelButton(buttons, 'open-blocks');

	if (!buttons.get || !buttons.get('open-subin-blocks')) {
		buttons.add({
			id: 'open-subin-blocks',
			command: 'open-subin-blocks',
			className: 'fa fa-th-large',
			attributes: {
				title: 'Form',
			},
		});
	}

	if (!buttons.get || !buttons.get('open-subin-inspector')) {
		buttons.add({
			id: 'open-subin-inspector',
			command: 'open-subin-inspector',
			className: 'fa fa-sliders',
			attributes: {
				title: 'Inspector',
			},
		});
	}

	markRightPanelButtons(editor);
}

function registerBlocksTabCommand(editor) {
	if (!editor.Commands || !editor.Commands.add) {
		return;
	}

	editor.Commands.add('open-subin-blocks', {
		run: function (currentEditor) {
			var activeEditor = currentEditor || editor;
			activeEditor.__subinActiveRightPanel = 'blocks';
			if (activeEditor.runCommand) {
				activeEditor.runCommand('open-blocks');
			}
			scheduleApplyRightPanelMode(activeEditor, 'blocks');
		},
	});
}

function markRightPanelButtons(editor) {
	var panels = editor && editor.Panels;
	var views = panels && panels.getPanel ? panels.getPanel('views') : null;
	var buttons = views && views.get ? views.get('buttons') : null;

	if (!buttons || !buttons.get) {
		return;
	}

	markPanelButton(buttons.get('open-subin-inspector'), 'inspector');
	markPanelButton(buttons.get('open-subin-blocks'), 'blocks');
}

function markPanelButton(button, mode) {
	var attributes;

	if (!button || !button.get || !button.set) {
		return;
	}

	attributes = Object.assign({}, button.get('attributes') || {});
	attributes['data-subin-right-panel'] = mode;
	button.set('attributes', attributes);
}

function hideSeparateSettingsButtons(editor) {
	var container = editor && editor.getContainer ? editor.getContainer() : document.getElementById('subin-grapesjs-editor');

	if (!container) {
		return;
	}

	container.querySelectorAll('.gjs-pn-btn').forEach(function (button) {
		var command = button.getAttribute('data-command') || button.getAttribute('data-id') || '';
		var title = String(button.getAttribute('title') || '').toLowerCase();
		if (command === 'open-sm' || command === 'open-tm' || title === 'style manager' || title === 'settings' || title === 'traits') {
			button.style.display = 'none';
		}
	});
}

function bindUnifiedInspectorViewSwitcher(editor) {
	var container = editor && editor.getContainer ? editor.getContainer() : document.getElementById('subin-grapesjs-editor');
	var viewsPanel = container ? container.querySelector('.gjs-pn-views') : null;

	if (!viewsPanel || viewsPanel.__subinUnifiedInspectorBound) {
		return;
	}

	viewsPanel.__subinUnifiedInspectorBound = true;
	viewsPanel.addEventListener('click', function (event) {
		var button = event.target && event.target.closest ? event.target.closest('.gjs-pn-btn') : null;

		if (!button) {
			return;
		}

		window.setTimeout(function () {
			var mode = rightPanelModeFromButton(button);
			if (mode === 'inspector') {
				showUnifiedInspector(editor);
				return;
			}
			if (mode) {
				editor.__subinActiveRightPanel = mode;
				scheduleApplyRightPanelMode(editor, mode);
			}
		}, 0);
	});
}

function rightPanelModeFromButton(button) {
	var mode = button && button.getAttribute ? button.getAttribute('data-subin-right-panel') : '';
	var command = button && button.getAttribute ? (button.getAttribute('data-command') || button.getAttribute('data-id') || '') : '';
	var title = String(button && button.getAttribute ? button.getAttribute('title') || '' : '').toLowerCase();

	if (mode) {
		return mode;
	}
	if (command === 'open-subin-inspector' || title === 'inspector' || (button && button.classList && button.classList.contains('fa-sliders'))) {
		return 'inspector';
	}
	if (command === 'open-blocks' || command === 'open-subin-blocks' || title.indexOf('block') !== -1) {
		return 'blocks';
	}

	return '';
}

function removePanelButton(buttons, id) {
	var button = buttons && buttons.get ? buttons.get(id) : null;
	if (button && buttons.remove) {
		buttons.remove(button);
	}
}

function showUnifiedInspector(editor) {
	editor.__subinActiveRightPanel = 'inspector';
	setupUnifiedInspectorPanel(editor);
	renderUnifiedInspector(editor);
	updateUnifiedInspectorState(editor);
	toggleUnifiedInspector(editor, true);
	updateRightPanelButtonState(editor, 'inspector');
}

function selectFormWrapperForInspector(editor) {
	var wrapper = editor && editor.getWrapper ? editor.getWrapper() : null;

	if (wrapper && editor.select) {
		editor.select(wrapper);
	}
}

function renderUnifiedInspector(editor) {
	var viewsContainer = grapesjsViewsContainer(editor);
	var inspector = viewsContainer ? viewsContainer.querySelector('.subin-gjs-unified-inspector') : null;
	var body = inspector ? inspector.querySelector('.subin-gjs-inspector__body') : null;

	if (!inspector || !body) {
		return;
	}

	if (!traitInputContainsFocus(inspector)) {
		body.innerHTML = customInspectorHtml(editor);
	}

	applySubmissionInboxInspectorTabs(inspector);
	hideSeparateSettingsButtons(editor);
}

function scheduleSelectedInspectorRefresh(editor, changedComponent) {
	if (!editor || !editor.getSelected) {
		return;
	}

	window.clearTimeout(editor.__subinInspectorRefreshTimer);
	editor.__subinInspectorRefreshTimer = window.setTimeout(function () {
		var selected = closestControlledStyleComponent(editor.getSelected ? editor.getSelected() : null);
		var changed = closestControlledStyleComponent(changedComponent);

		if (!selected || (changed && changed !== selected)) {
			return;
		}

		renderUnifiedInspector(editor);
		updateUnifiedInspectorState(editor);
	}, 80);
}

function bindCustomInspectorEvents(editor, inspector) {
	if (!inspector || inspector.__subinCustomInspectorBound) {
		return;
	}

	inspector.__subinCustomInspectorBound = true;
	inspector.addEventListener('input', function (event) {
		handleCustomInspectorInput(editor, inspector, event);
	});
	inspector.addEventListener('change', function (event) {
		handleCustomInspectorInput(editor, inspector, event);
	});
	inspector.addEventListener('click', function (event) {
		var tab = event.target && event.target.closest ? event.target.closest('[data-subin-inspector-tab]') : null;
		if (tab && inspector.contains(tab)) {
			inspector.setAttribute('data-subin-active-tab', tab.getAttribute('data-subin-inspector-tab') || 'content');
			applySubmissionInboxInspectorTabs(inspector);
			return;
		}
		handleCustomInspectorClick(editor, inspector, event);
	});
}

function customInspectorHtml(editor) {
	var selected = editor && editor.getSelected ? editor.getSelected() : null;
	var component = closestControlledStyleComponent(selected) || (editor && editor.getWrapper ? editor.getWrapper() : null);
	var subinType = controlledStyleComponentType(component);
	var fieldType = selectedFieldType(component, subinType);
	var attrs = component && component.getAttributes ? component.getAttributes() : {};
	var html = '';

	if (!component || !subinType) {
		return '<div class="subin-advanced-note">Select a form element to edit its settings.</div>';
	}

	if (subinType === 'form-wrapper') {
		html += inspectorSection('Form settings', [
			inspectorText('data-subin-form-title', 'Form title', attrs['data-subin-form-title']),
			inspectorTextarea('data-subin-form-description', 'Form description', attrs['data-subin-form-description'], 3),
		], 'Form');
		html += inspectorSection('Messages', [
			inspectorTextarea('data-subin-validation-error-message', 'Validation error message', attrs['data-subin-validation-error-message'], 3),
			inspectorText('data-subin-required-error-message', 'Default required message', attrs['data-subin-required-error-message']),
			inspectorTextarea('data-subin-spam-error-message', 'Spam protection message', attrs['data-subin-spam-error-message'], 3),
			inspectorTextarea('data-subin-success-message', 'Success message', attrs['data-subin-success-message'], 3),
		]);
		html += inspectorStyleSection('Layout', [
			styleControl('width', 'Form width', component, 'text'),
			styleControl('max-width', 'Max width', component, 'text'),
			styleControl('padding', 'Padding', component, 'text'),
			styleSelect('justify-content', 'Alignment', component, [
				['', 'Default'],
				['flex-start', 'Left'],
				['center', 'Center'],
				['flex-end', 'Right'],
			]),
		]);
		html += inspectorBoxStyleSections(component, true);
		html += inspectorBackgroundMediaSection(attrs);
		return html;
	}

	if (subinType === 'row') {
		html += inspectorStyleSection('Row layout', [
			styleControl('gap', 'Gap', component, 'text'),
			styleSelect('justify-content', 'Horizontal alignment', component, [
				['', 'Default'],
				['flex-start', 'Left'],
				['center', 'Center'],
				['flex-end', 'Right'],
				['space-between', 'Spread'],
			]),
			styleSelect('align-items', 'Vertical alignment', component, [
				['', 'Default'],
				['flex-start', 'Top'],
				['center', 'Middle'],
				['flex-end', 'Bottom'],
				['stretch', 'Stretch'],
			]),
			styleControl('padding', 'Padding', component, 'text'),
			styleControl('margin', 'Margin', component, 'text'),
		]);
		html += inspectorSection('Row actions', [rowActionButtons(component)]);
		html += inspectorBoxStyleSections(component, false);
		html += inspectorBackgroundMediaSection(attrs);
		return html;
	}

	if (subinType === 'field') {
		return fieldInspectorHtml(component, fieldType, attrs);
	}

	if (subinType === 'submit-button') {
		html += inspectorSection('Content', [
			inspectorText('data-subin-button-text', 'Button text', attrs['data-subin-button-text'] || componentPlainText(component) || 'Submit'),
		]);
		html += inspectorStyleSection('Layout', [
			styleControl('width', 'Width', component, 'text'),
			styleControl('margin', 'Margin', component, 'text'),
			styleControl('padding', 'Padding', component, 'text'),
			styleSelect('text-align', 'Alignment', component, [['', 'Default'], ['left', 'Left'], ['center', 'Center'], ['right', 'Right']]),
		]);
		html += inspectorStyleSection('Button style', buttonStyleControls(component));
		html += inspectorSection('States', ['<p class="subin-gjs-inspector__note">State preview is controlled from the top toolbar.</p>']);
		return html;
	}

	if (subinType === 'html-block') {
		html += inspectorSection('HTML content editor', [
			inspectorTextarea('data-subin-html-content', 'HTML content', attrs['data-subin-html-content'] || attrs['data-subin-content'], 12, 'subin-gjs-inspector__html'),
			'<button type="button" class="button subin-gjs-inspector__button" data-subin-open-wp-html-editor>Open WordPress editor</button>',
		]);
		html += inspectorStyleSection('Layout', layoutStyleControls(component));
		html += inspectorBoxStyleSections(component, true);
		html += inspectorBackgroundMediaSection(attrs);
		return html;
	}

	if (subinType === 'image-block') {
		html += inspectorImageMediaSection(attrs);
		html += inspectorSection('Content', [
			inspectorText('data-subin-media-alt', 'Alt text', attrs['data-subin-media-alt'], '', 'Describe the image for accessibility.'),
		]);
		html += inspectorStyleSection('Layout', layoutStyleControls(component));
		html += inspectorBoxStyleSections(component, true);
		return html;
	}

	if (['text-block', 'notice', 'privacy'].indexOf(subinType) !== -1) {
		html += inspectorSection('Content', [
			inspectorTextarea('data-subin-content', subinType === 'notice' ? 'Notice text' : (subinType === 'privacy' ? 'Privacy text' : 'Text content'), attrs['data-subin-content'], 5),
		]);
		html += inspectorStyleSection(subinType === 'notice' ? 'Notice style' : 'Typography', typographyStyleControls(component));
		html += inspectorStyleSection('Layout', layoutStyleControls(component));
		html += inspectorBoxStyleSections(component, true);
		html += inspectorBackgroundMediaSection(attrs);
		return html;
	}

	if (subinType === 'divider') {
		html += inspectorStyleSection('Divider settings', [
			styleControl('width', 'Width', component, 'text'),
			styleControl('border-width', 'Thickness', component, 'text'),
			styleSelect('border-style', 'Line style', component, [['', 'Default'], ['solid', 'Solid'], ['dashed', 'Dashed'], ['dotted', 'Dotted']]),
			styleControl('border-color', 'Color', component, 'color'),
			styleControl('margin', 'Margin', component, 'text'),
		]);
		return html;
	}

	html += inspectorStyleSection('Layout', layoutStyleControls(component));
	html += inspectorBoxStyleSections(component, true);
	return html;
}

function fieldInspectorHtml(component, fieldType, attrs) {
	var html = '';

	if (fieldType === 'hidden') {
		return inspectorSection('Hidden field settings', [
			inspectorText('data-subin-field-key', 'Field key', attrs['data-subin-field-key']),
			inspectorText('data-subin-default-value', 'Default value', attrs['data-subin-default-value']),
		]) + inspectorSection('Advanced', [
			'<p class="subin-gjs-inspector__note">Hidden fields are submitted without visible frontend controls.</p>',
		]);
	}

	if (fieldType === 'consent') {
		html += inspectorSection('Consent settings', [
			inspectorReadonly('Field type', fieldTypeLabel(fieldType)),
			inspectorTextarea('data-subin-consent-text', 'Consent text', attrs['data-subin-consent-text'] || attrs['data-subin-label'], 4),
			inspectorTextarea('data-subin-help-text', 'Help/privacy text', attrs['data-subin-help-text'], 3),
		], 'Field');
	} else {
		html += inspectorSection('Content', [
			inspectorReadonly('Field type', fieldTypeLabel(fieldType)),
			inspectorText('data-subin-label', 'Label', attrs['data-subin-label'] || attrs['data-subin-field-label']),
			supportsPlaceholderTrait(fieldType) ? inspectorText('data-subin-placeholder', fieldType === 'select' ? 'Empty option text' : 'Placeholder', attrs['data-subin-placeholder']) : '',
			supportsHelpTextTrait(fieldType) ? inspectorTextarea('data-subin-help-text', 'Help text', attrs['data-subin-help-text'], 3) : '',
		], 'Field');
	}

	if (isChoiceField(fieldType)) {
		html += inspectorSection('Options', [optionsEditorHtml(attrs['data-subin-options'])]);
	}

	html += inspectorSection('Validation', [
		inspectorCheckbox('data-subin-required', 'Required', attrs['data-subin-required']),
		inspectorText('data-subin-required-message', 'Required error message', attrs['data-subin-required-message'], '', 'Shown when this required field is empty.'),
	]);

	html += inspectorStyleSection('Layout', [
		styleUnitControl('width', 'Width', component, '%'),
		styleUnitControl('margin-top', 'Margin top', component, 'px'),
		styleUnitControl('margin-right', 'Margin right', component, 'px'),
		styleUnitControl('margin-bottom', 'Margin bottom', component, 'px'),
		styleUnitControl('margin-left', 'Margin left', component, 'px'),
	]);

	if (fieldType === 'radio' || fieldType === 'checkbox') {
		html += inspectorStyleSection('Style', choiceFieldStyleControls(component, attrs), 'Field parts');
	} else {
		html += inspectorStyleSection('Style', fieldStyleControls(component, attrs, fieldType), 'Inner parts');
	}

	html += inspectorSection('States', ['<p class="subin-gjs-inspector__note">Use Normal, Error, and Success preview buttons to review state styling.</p>']);
	html += inspectorSection('Advanced', [
		inspectorText('data-subin-field-key', 'Field key', attrs['data-subin-field-key']),
	]);

	return html;
}

function inspectorSection(title, controls, meta) {
	var body = (controls || []).filter(Boolean).join('');
	if (!body) {
		return '';
	}
	return '<section class="subin-inspector-section subin-gjs-inspector__section"><header class="subin-section-header"><div class="subin-section-title">' + escapeHtml(title) + '</div>' + (meta ? '<div class="subin-section-meta">' + escapeHtml(meta) + '</div>' : '') + '</header><div class="subin-section-body subin-gjs-inspector__controls">' + body + '</div></section>';
}

function inspectorStyleSection(title, controls, meta) {
	return inspectorSection(title, controls, meta);
}

function applySubmissionInboxInspectorTabs(inspector) {
	var sections = inspector ? inspector.querySelectorAll('.subin-inspector-section') : [];
	var tabs = inspector ? inspector.querySelectorAll('[data-subin-inspector-tab]') : [];
	var counts = {content: 0, validation: 0, design: 0, advanced: 0};
	var active = inspector ? (inspector.getAttribute('data-subin-active-tab') || 'content') : 'content';

	sections.forEach(function (section) {
		var title = String((section.querySelector('.subin-section-title') || {}).textContent || '').toLowerCase();
		var group = inspectorSectionGroup(title);
		section.setAttribute('data-subin-inspector-group', group);
		counts[group]++;
	});

	if (!counts[active]) {
		active = ['content', 'validation', 'design', 'advanced'].filter(function (group) {
			return counts[group] > 0;
		})[0] || 'content';
		if (inspector) {
			inspector.setAttribute('data-subin-active-tab', active);
		}
	}

	tabs.forEach(function (tab) {
		var group = tab.getAttribute('data-subin-inspector-tab') || 'content';
		var selected = group === active;
		tab.hidden = counts[group] === 0;
		tab.classList.toggle('is-active', selected);
		tab.setAttribute('aria-selected', selected ? 'true' : 'false');
		tab.tabIndex = selected ? 0 : -1;
	});
	sections.forEach(function (section) {
		section.hidden = section.getAttribute('data-subin-inspector-group') !== active;
	});
}

function inspectorSectionGroup(title) {
	if (/validation|messages|states/.test(title)) {
		return 'validation';
	}
	if (/layout|style|typography|background|border|shadow|divider/.test(title)) {
		return 'design';
	}
	if (/advanced|actions|hidden|html|media/.test(title)) {
		return 'advanced';
	}
	return 'content';
}

function inspectorText(name, label, value, className, hint) {
	return '<div class="subin-control' + (hint ? ' subin-control-spaced' : '') + ' subin-gjs-inspector__control"><label class="subin-control-label">' + escapeHtml(label) + '</label><input class="subin-input ' + escapeHtml(className || '') + '" type="text" data-subin-inspector-attr="' + escapeHtml(name) + '" data-subin-setting="' + escapeHtml(settingAlias(name)) + '" value="' + escapeHtml(value || '') + '" />' + (hint ? '<div class="subin-control-hint">' + escapeHtml(hint) + '</div>' : '') + '</div>';
}

function inspectorTextarea(name, label, value, rows, className) {
	return '<div class="subin-control subin-gjs-inspector__control"><label class="subin-control-label">' + escapeHtml(label) + '</label><textarea class="subin-textarea ' + escapeHtml(className || '') + '" rows="' + escapeHtml(String(rows || 4)) + '" data-subin-inspector-attr="' + escapeHtml(name) + '" data-subin-setting="' + escapeHtml(settingAlias(name)) + '">' + escapeHtml(value || '') + '</textarea></div>';
}

function inspectorCheckbox(name, label, value) {
	var checked = value === '1' || value === true ? ' checked' : '';
	return '<div class="subin-toggle-row subin-gjs-inspector__control subin-gjs-inspector__control--toggle"><span class="subin-toggle-label">' + escapeHtml(label) + '</span><label class="subin-switch"><input type="checkbox" data-subin-inspector-attr="' + escapeHtml(name) + '" data-subin-setting="' + escapeHtml(settingAlias(name)) + '" value="1"' + checked + ' /><span></span></label></div>';
}

function inspectorReadonly(label, value) {
	return '<div class="subin-control subin-gjs-inspector__control"><label class="subin-control-label">' + escapeHtml(label) + '</label><input class="subin-input" type="text" value="' + escapeHtml(value || '') + '" disabled /></div>';
}

function styleControl(property, label, component, type) {
	var value = componentStyleValue(component, property);
	if (type === 'color') {
		return colorControl(label, 'data-subin-inspector-style', property, value, styleAlias(property));
	}
	return '<div class="subin-control subin-gjs-inspector__control"><label class="subin-control-label">' + escapeHtml(label) + '</label><input class="subin-input" type="' + escapeHtml(type || 'text') + '" data-subin-inspector-style="' + escapeHtml(property) + '" data-subin-style="' + escapeHtml(styleAlias(property)) + '" value="' + escapeHtml(value) + '" /></div>';
}

function styleSelect(property, label, component, options) {
	var value = explicitComponentStyleValue(component, property);
	var html = '<div class="subin-control subin-gjs-inspector__control"><label class="subin-control-label">' + escapeHtml(label) + '</label><select class="subin-select" data-subin-inspector-style="' + escapeHtml(property) + '" data-subin-style="' + escapeHtml(styleAlias(property)) + '">';
	(options || []).forEach(function (option) {
		html += '<option value="' + escapeHtml(option[0]) + '"' + (String(option[0]) === String(value) ? ' selected' : '') + '>' + escapeHtml(option[1]) + '</option>';
	});
	return html + '</select></div>';
}

function fieldInnerStyleControl(name, label, attrs, type, suffix) {
	if (type === 'color') {
		return colorControl(label, 'data-subin-field-style', name, attrs[name] || '', styleAlias(name));
	}
	if (suffix) {
		return '<div class="subin-control subin-gjs-inspector__control"><label class="subin-control-label">' + escapeHtml(label) + '</label><div class="subin-unit"><input class="subin-input" type="' + escapeHtml(type || 'text') + '" data-subin-field-style="' + escapeHtml(name) + '" data-subin-style="' + escapeHtml(styleAlias(name)) + '" value="' + escapeHtml(attrs[name] || '') + '" ' + (type === 'number' ? 'min="0" step="1" ' : '') + '/><span>' + escapeHtml(suffix) + '</span></div></div>';
	}
	return '<div class="subin-control subin-gjs-inspector__control"><label class="subin-control-label">' + escapeHtml(label) + '</label><input class="subin-input" type="' + escapeHtml(type || 'text') + '" data-subin-field-style="' + escapeHtml(name) + '" data-subin-style="' + escapeHtml(styleAlias(name)) + '" value="' + escapeHtml(attrs[name] || '') + '" ' + (type === 'number' ? 'min="0" step="1" ' : '') + '/></div>';
}

function fieldInnerStyleSelect(name, label, attrs, options) {
	var html = '<div class="subin-control subin-gjs-inspector__control"><label class="subin-control-label">' + escapeHtml(label) + '</label><select class="subin-select" data-subin-field-style="' + escapeHtml(name) + '" data-subin-style="' + escapeHtml(styleAlias(name)) + '">';
	(options || []).forEach(function (option) {
		html += '<option value="' + escapeHtml(option[0]) + '"' + (String(option[0]) === String(attrs[name] || '') ? ' selected' : '') + '>' + escapeHtml(option[1]) + '</option>';
	});
	return html + '</select></div>';
}

function labelStyleControls(attrs) {
	return [
		fieldInnerStyleControl('data-subin-label-color', 'Text color', attrs, 'color'),
		fieldInnerStyleControl('data-subin-label-font-size', 'Font size', attrs, 'number', 'px'),
		fieldInnerStyleSelect('data-subin-label-font-weight', 'Font weight', attrs, [['', 'Default'], ['400', 'Regular'], ['500', 'Medium'], ['600', 'Semibold'], ['700', 'Bold']]),
		fieldInnerStyleControl('data-subin-label-line-height', 'Line height', attrs, 'number'),
		fieldInnerStyleControl('data-subin-label-margin-bottom', 'Margin bottom', attrs, 'number', 'px'),
	];
}

function inputStyleControls(attrs) {
	return [
		fieldInnerStyleControl('data-subin-input-bg-color', 'Background color', attrs, 'color'),
		fieldInnerStyleControl('data-subin-input-text-color', 'Text color', attrs, 'color'),
		fieldInnerStyleControl('data-subin-placeholder-color', 'Placeholder color', attrs, 'color'),
		fieldInnerStyleControl('data-subin-input-border-color', 'Border color', attrs, 'color'),
		fieldInnerStyleControl('data-subin-input-border-width', 'Border width', attrs, 'number', 'px'),
		fieldInnerStyleControl('data-subin-input-border-radius', 'Border radius', attrs, 'number', 'px'),
		fieldInnerStyleControl('data-subin-input-padding', 'Padding', attrs, 'text', 'px'),
		fieldInnerStyleControl('data-subin-input-min-height', 'Height / min-height', attrs, 'number', 'px'),
		fieldInnerStyleSelect('data-subin-input-box-shadow', 'Shadow', attrs, [['', 'Default'], ['none', 'None'], ['0 4px 12px rgba(15, 23, 42, 0.12)', 'Subtle'], ['0 10px 24px rgba(15, 23, 42, 0.16)', 'Raised'], ['0 18px 36px rgba(15, 23, 42, 0.22)', 'Strong']]),
	];
}

function fieldStyleControls(component, attrs, fieldType) {
	var helpControls = helpStyleControls(attrs);
	var helpText = attrs['data-subin-help-text'] || '';
	var label = fieldType === 'consent' ? 'Consent text' : 'Label';

	return [
		stylePartTabs([
			['container', 'Container'],
			['label', label],
			['input', fieldType === 'consent' ? 'Checkbox' : 'Input'],
			['help', 'Help text'],
		], 'input'),
		stylePartPane('container', 'input', containerStyleControls(component)),
		stylePartPane('label', 'input', labelStyleControls(attrs)),
		stylePartPane('input', 'input', inputStyleControls(attrs)),
		stylePartPane('help', 'input', helpControls, helpText ? '' : 'Add help text in Content settings first.'),
	];
}

function choiceFieldStyleControls(component, attrs) {
	var helpText = attrs['data-subin-help-text'] || '';

	return [
		stylePartTabs([
			['container', 'Container'],
			['label', 'Label'],
			['input', 'Choice control'],
			['help', 'Help text'],
		], 'input'),
		stylePartPane('container', 'input', containerStyleControls(component)),
		stylePartPane('label', 'input', labelStyleControls(attrs)),
		stylePartPane('input', 'input', [
			fieldInnerStyleControl('data-subin-input-min-height', 'Checkbox/radio size', attrs, 'number', 'px'),
			fieldInnerStyleControl('data-subin-input-border-color', 'Checkbox/radio color', attrs, 'color'),
			fieldInnerStyleSelect('data-subin-input-box-shadow', 'Shadow', attrs, [['', 'Default'], ['none', 'None'], ['0 4px 12px rgba(15, 23, 42, 0.12)', 'Subtle'], ['0 10px 24px rgba(15, 23, 42, 0.16)', 'Raised'], ['0 18px 36px rgba(15, 23, 42, 0.22)', 'Strong']]),
		]),
		stylePartPane('help', 'input', helpStyleControls(attrs), helpText ? '' : 'Add help text in Content settings first.'),
	];
}

function containerStyleControls(component) {
	return [
		styleControl('background-color', 'Background color', component, 'color'),
		styleControl('padding', 'Padding', component, 'text'),
		styleControl('margin', 'Margin', component, 'text'),
		styleControl('border-color', 'Border color', component, 'color'),
		styleControl('border-width', 'Border width', component, 'text'),
		styleControl('border-radius', 'Border radius', component, 'text'),
		styleSelect('box-shadow', 'Shadow', component, [['', 'Default'], ['none', 'None'], ['0 4px 12px rgba(15, 23, 42, 0.12)', 'Subtle'], ['0 10px 24px rgba(15, 23, 42, 0.16)', 'Raised'], ['0 18px 36px rgba(15, 23, 42, 0.22)', 'Strong']]),
	];
}

function stylePartTabs(parts, activePart) {
	var html = '<div class="subin-control subin-gjs-inspector__control"><label class="subin-control-label">Edit part</label><div class="subin-part-tabs">';
	(parts || []).forEach(function (part) {
		html += '<button type="button" class="subin-part-tab' + (part[0] === activePart ? ' is-active' : '') + '" data-subin-inspector-static="' + escapeHtml(part[0]) + '">' + escapeHtml(part[1]) + '</button>';
	});
	return html + '</div></div>';
}

function stylePartPane(part, activePart, controls, hint) {
	var body = (controls || []).filter(Boolean).join('');
	if (hint) {
		body = '<div class="subin-control-hint subin-style-part-hint">' + escapeHtml(hint) + '</div>' + body;
	}

	return '<div class="subin-style-part-pane' + (part === activePart ? ' is-active' : '') + '" data-subin-style-part-pane="' + escapeHtml(part) + '">' + body + '</div>';
}

function styleUnitControl(property, label, component, unit) {
	var value = componentStyleValue(component, property);
	var number = styleUnitNumberValue(value, unit);
	return '<div class="subin-control subin-gjs-inspector__control"><label class="subin-control-label">' + escapeHtml(label) + '</label><div class="subin-unit"><input class="subin-input" type="text" data-subin-inspector-style="' + escapeHtml(property) + '" data-subin-style-unit="' + escapeHtml(unit) + '" data-subin-style="' + escapeHtml(styleAlias(property)) + '" value="' + escapeHtml(number || '') + '" /><span>' + escapeHtml(unit) + '</span></div></div>';
}

function styleUnitNumberValue(value, unit) {
	var safe = String(value || '').trim();
	var calcMatch;

	if (!safe) {
		return '';
	}

	if (unit === '%') {
		calcMatch = safe.match(/calc\(\s*([0-9.]+)%/i);
		if (calcMatch) {
			return calcMatch[1];
		}
		if (/%$/.test(safe)) {
			return String(parseFloat(safe) || '');
		}
	}

	if (unit === 'px' && /px$/i.test(safe)) {
		return String(parseFloat(safe) || '');
	}

	if (/^\d+(?:\.\d+)?$/.test(safe)) {
		return safe;
	}

	return '';
}

function colorControl(label, dataName, name, value, alias) {
	var color = /^#[0-9a-f]{6}$/i.test(String(value || '')) ? value : '';
	return '<div class="subin-control subin-gjs-inspector__control"><label class="subin-control-label">' + escapeHtml(label) + '</label><div class="subin-color-control"><input class="subin-input" type="text" ' + escapeHtml(dataName) + '="' + escapeHtml(name) + '" data-subin-style="' + escapeHtml(alias || styleAlias(name)) + '" value="' + escapeHtml(color) + '" /><button type="button" class="subin-swatch" style="background:' + escapeHtml(color || '#ffffff') + ';" aria-label="Select color"></button><input class="subin-color-native" type="color" value="' + escapeHtml(color || '#ffffff') + '" tabindex="-1" aria-hidden="true" /></div></div>';
}

function settingAlias(name) {
	return String(name || '').replace(/^data-subin-/, '').replace(/-/g, '_');
}

function styleAlias(name) {
	return String(name || '').replace(/^data-subin-/, '').replace(/-/g, '_');
}

function helpStyleControls(attrs) {
	return [
		fieldInnerStyleControl('data-subin-help-color', 'Text color', attrs, 'color'),
		fieldInnerStyleControl('data-subin-help-font-size', 'Font size', attrs, 'number', 'px'),
		fieldInnerStyleControl('data-subin-help-line-height', 'Line height', attrs, 'number'),
		fieldInnerStyleControl('data-subin-help-margin-top', 'Margin top', attrs, 'number', 'px'),
	];
}

function layoutStyleControls(component) {
	return [
		styleControl('width', 'Width', component, 'text'),
		styleControl('max-width', 'Max width', component, 'text'),
		styleControl('margin', 'Margin', component, 'text'),
		styleControl('padding', 'Padding', component, 'text'),
	];
}

function typographyStyleControls(component) {
	return [
		styleControl('font-size', 'Font size', component, 'text'),
		styleSelect('font-weight', 'Font weight', component, [['', 'Default'], ['400', 'Regular'], ['500', 'Medium'], ['600', 'Semibold'], ['700', 'Bold']]),
		styleControl('line-height', 'Line height', component, 'text'),
		styleSelect('text-align', 'Text align', component, [['', 'Default'], ['left', 'Left'], ['center', 'Center'], ['right', 'Right']]),
		styleControl('color', 'Text color', component, 'color'),
	];
}

function buttonStyleControls(component) {
	return [
		styleControl('background-color', 'Background color', component, 'color'),
		styleControl('color', 'Text color', component, 'color'),
		styleControl('font-size', 'Font size', component, 'text'),
		styleSelect('font-weight', 'Font weight', component, [['', 'Default'], ['400', 'Regular'], ['500', 'Medium'], ['600', 'Semibold'], ['700', 'Bold']]),
		styleControl('border-color', 'Border color', component, 'color'),
		styleControl('border-width', 'Border width', component, 'text'),
		styleSelect('border-style', 'Border style', component, [['', 'Default'], ['none', 'None'], ['solid', 'Solid'], ['dashed', 'Dashed'], ['dotted', 'Dotted']]),
		styleControl('border-radius', 'Radius', component, 'text'),
		styleSelect('box-shadow', 'Shadow', component, [['', 'Default'], ['none', 'None'], ['0 4px 12px rgba(15, 23, 42, 0.12)', 'Subtle'], ['0 10px 24px rgba(15, 23, 42, 0.16)', 'Raised'], ['0 18px 36px rgba(15, 23, 42, 0.22)', 'Strong']]),
	];
}

function inspectorBoxStyleSections(component, includeTypography) {
	var html = '';
	if (includeTypography) {
		html += inspectorStyleSection('Typography', typographyStyleControls(component));
	}
	html += inspectorStyleSection('Style', [
		styleControl('background-color', 'Background color', component, 'color'),
		styleControl('border-color', 'Border color', component, 'color'),
		styleControl('border-width', 'Border width', component, 'text'),
		styleSelect('border-style', 'Border style', component, [['', 'Default'], ['none', 'None'], ['solid', 'Solid'], ['dashed', 'Dashed'], ['dotted', 'Dotted']]),
		styleControl('border-radius', 'Radius', component, 'text'),
		styleSelect('box-shadow', 'Shadow', component, [['', 'Default'], ['none', 'None'], ['0 4px 12px rgba(15, 23, 42, 0.12)', 'Subtle'], ['0 10px 24px rgba(15, 23, 42, 0.16)', 'Raised'], ['0 18px 36px rgba(15, 23, 42, 0.22)', 'Strong']]),
	]);
	return html;
}

function componentStyleValue(component, property) {
	var value = explicitComponentStyleValue(component, property);
	if (value) {
		return value;
	}

	return defaultInspectorStyleValue(component, property);
}

function explicitComponentStyleValue(component, property) {
	var styles = component && component.getStyle ? component.getStyle() : {};
	if (styles && styles[property]) {
		return styles[property];
	}

	return '';
}

function defaultInspectorStyleValue(component, property) {
	var subinType = controlledStyleComponentType(component);
	var defaults = {
		'text-block': {
			'color': '#1f2933',
			'font-size': '16px',
			'font-weight': '400',
			'line-height': '1.55',
			'text-align': 'left',
		},
		'privacy': {
			'color': '#52606d',
			'font-size': '14px',
			'font-weight': '400',
			'line-height': '1.5',
			'text-align': 'left',
		},
		'notice': {
			'background-color': '#f0f6fc',
			'border-color': '#c5d9ed',
			'border-radius': '6px',
			'border-style': 'solid',
			'border-width': '1px',
			'color': '#17324d',
			'font-size': '14px',
			'font-weight': '400',
			'line-height': '1.45',
			'padding': '12px 14px',
			'text-align': 'left',
		},
		'submit-button': {
			'background-color': '#1d4ed8',
			'border-style': 'none',
			'border-radius': '6px',
			'border-width': '0',
			'color': '#ffffff',
			'font-size': '16px',
			'font-weight': '600',
			'line-height': '1.3',
			'padding': '10px 18px',
			'text-align': 'center',
		},
		'form-wrapper': {
			'background-color': '#ffffff',
			'border-color': '#d8e2ee',
			'border-radius': '20px',
			'border-style': 'solid',
			'border-width': '1px',
			'color': '#172033',
			'font-size': '16px',
			'gap': '18px',
			'padding': '30px',
		},
		'field': {
			'width': '100%',
		},
		'row': {
			'align-items': 'flex-start',
			'gap': '0 16px',
			'justify-content': 'flex-start',
			'padding': '6px',
		},
		'divider': {
			'border-style': 'solid',
			'border-width': '1px',
			'width': '100%',
		},
	};

	return defaults[subinType] && defaults[subinType][property] ? defaults[subinType][property] : '';
}

function optionsEditorHtml(optionsJson) {
	var options = parseChoiceOptions(optionsJson);
	var html = '<div class="subin-gjs-inspector-options" data-subin-custom-options>';
	options.forEach(function (option) {
		html += '<div class="subin-option-card subin-gjs-options-trait__row" data-subin-option-row>';
		html += '<div class="subin-control"><label class="subin-control-label">Label</label><input class="subin-input" type="text" data-subin-option-label value="' + escapeHtml(option.label) + '" /></div>';
		html += '<div class="subin-control"><label class="subin-control-label">Value</label><input class="subin-input" type="text" data-subin-option-value value="' + escapeHtml(option.value) + '" /></div>';
		html += '<div class="subin-option-actions subin-gjs-options-trait__actions">';
		html += '<button type="button" class="subin-mini-btn" data-subin-option-move="up">Up</button>';
		html += '<button type="button" class="subin-mini-btn" data-subin-option-move="down">Down</button>';
		html += '<button type="button" class="subin-mini-btn is-danger" data-subin-option-remove>Remove</button>';
		html += '</div></div>';
	});
	return html + '<button type="button" class="subin-mini-btn subin-gjs-inspector__button" data-subin-option-add>Add option</button></div>';
}

function rowActionButtons(component) {
	var row = selectedRow(component);
	var children = row && row.components ? row.components() : null;
	var deleteDisabled = children && children.length ? ' disabled aria-disabled="true" title="Remove the fields before deleting this row"' : '';

	return [
		'<div class="subin-gjs-row-actions-trait">',
		'<button type="button" class="subin-mini-btn" data-subin-row-action="above">Add row above</button>',
		'<button type="button" class="subin-mini-btn" data-subin-row-action="below">Add row below</button>',
		'<button type="button" class="subin-mini-btn is-danger" data-subin-row-action="delete-empty"' + deleteDisabled + '>Delete empty row</button>',
		'</div>',
	].join('');
}

function inspectorBackgroundMediaSection(attrs) {
	var wrapper = document.createElement('div');
	wrapper.className = 'subin-gjs-media-trait';
	renderBackgroundMediaTrait(wrapper, attrs || {});
	return inspectorSection('Background image', [wrapper.outerHTML]);
}

function inspectorImageMediaSection(attrs) {
	var wrapper = document.createElement('div');
	wrapper.className = 'subin-gjs-media-trait subin-gjs-image-trait';
	renderImageMediaTrait(wrapper, attrs || {});
	return inspectorSection('Image', [wrapper.outerHTML]);
}

function handleCustomInspectorInput(editor, inspector, event) {
	var component = currentInspectorComponent(editor);
	var target = event && event.target;
	var attrName = target && target.getAttribute ? target.getAttribute('data-subin-inspector-attr') : '';
	var styleName = target && target.getAttribute ? target.getAttribute('data-subin-inspector-style') : '';
	var fieldStyleName = target && target.getAttribute ? target.getAttribute('data-subin-field-style') : '';
	var bgSetting = target && target.getAttribute ? target.getAttribute('data-subin-bg-setting') : '';
	var styleUnit = target && target.getAttribute ? target.getAttribute('data-subin-style-unit') : '';

	if (!component || !target) {
		return;
	}

	if (target.matches && target.matches('.subin-color-native')) {
		applyInspectorNativeColor(component, target);
		return;
	}

	if (attrName) {
		addComponentAttribute(component, attrName, sanitizeInspectorAttributeValue(attrName, target));
		return;
	}

	if (styleName) {
		setInspectorComponentStyle(component, styleName, sanitizeInspectorStyleValue(styleName, styleUnit ? target.value + styleUnit : target.value));
		syncInspectorSwatch(target);
		return;
	}

	if (fieldStyleName) {
		addComponentAttribute(component, fieldStyleName, sanitizeFieldStyleTraitValue(target));
		applyFieldInnerStyles(component);
		syncInspectorSwatch(target);
		return;
	}

	if (bgSetting) {
		setBackgroundMediaSetting(component, bgSetting, target.value);
		return;
	}

	if (target.matches && target.matches('[data-subin-option-label], [data-subin-option-value]')) {
		scheduleChoiceOptionsFlush(customOptionsRoot(target), component);
	}
}

function handleCustomInspectorClick(editor, inspector, event) {
	var component = currentInspectorComponent(editor);
	var target = event && event.target;
	var optionsRoot;
	var row;
	var moveButton;

	if (!component || !target) {
		return;
	}

	if (target.closest && target.closest('[data-subin-inspector-static]')) {
		var tabs = target.closest('.subin-part-tabs');
		var activeTab = target.closest('[data-subin-inspector-static]');
		var section = target.closest('.subin-inspector-section');
		var activePart = activeTab ? activeTab.getAttribute('data-subin-inspector-static') : '';
		event.preventDefault();
		if (tabs) {
			tabs.querySelectorAll('.subin-part-tab').forEach(function (button) {
				button.classList.toggle('is-active', button === activeTab);
			});
		}
		if (section) {
			section.querySelectorAll('[data-subin-style-part-pane]').forEach(function (pane) {
				pane.classList.toggle('is-active', pane.getAttribute('data-subin-style-part-pane') === activePart);
			});
		}
		return;
	}

	if (target.closest && target.closest('.subin-swatch')) {
		event.preventDefault();
		openInspectorNativeColor(target.closest('.subin-color-control'));
		return;
	}

	if (target.closest && target.closest('[data-subin-option-add]')) {
		event.preventDefault();
		optionsRoot = customOptionsRoot(target);
		renderOptionsTraitInput(optionsRoot, readOptionsTraitInput(optionsRoot).concat([nextChoiceOption(optionsRoot)]));
		setChoiceOptionsAttribute(component, readOptionsTraitInput(optionsRoot));
		return;
	}

	if (target.closest && target.closest('[data-subin-option-remove]')) {
		event.preventDefault();
		optionsRoot = customOptionsRoot(target);
		row = target.closest('[data-subin-option-row]');
		if (row && row.parentNode) {
			row.parentNode.removeChild(row);
		}
		setChoiceOptionsAttribute(component, readOptionsTraitInput(optionsRoot));
		return;
	}

	moveButton = target.closest && target.closest('[data-subin-option-move]');
	if (moveButton) {
		event.preventDefault();
		optionsRoot = customOptionsRoot(target);
		moveOptionRow(target.closest('[data-subin-option-row]'), moveButton.getAttribute('data-subin-option-move'));
		setChoiceOptionsAttribute(component, readOptionsTraitInput(optionsRoot));
		return;
	}

	if (target.closest && target.closest('[data-subin-row-action]')) {
		event.preventDefault();
		handleInspectorRowAction(component, target.closest('[data-subin-row-action]').getAttribute('data-subin-row-action'));
		renderUnifiedInspector(editor);
		return;
	}

	if (target.closest && target.closest('[data-subin-bg-select]')) {
		event.preventDefault();
		openBackgroundMediaFrame(component, target.closest('.subin-gjs-media-trait') || inspector);
		return;
	}

	if (target.closest && target.closest('[data-subin-bg-remove]')) {
		event.preventDefault();
		removeBackgroundMedia(component);
		renderUnifiedInspector(editor);
		return;
	}

	if (target.closest && target.closest('[data-subin-image-select]')) {
		event.preventDefault();
		openImageMediaFrame(component, target.closest('.subin-gjs-media-trait') || inspector);
		return;
	}

	if (target.closest && target.closest('[data-subin-image-remove]')) {
		event.preventDefault();
		removeImageMedia(component);
		renderUnifiedInspector(editor);
		return;
	}

	if (target.closest && target.closest('[data-subin-open-wp-html-editor]')) {
		event.preventDefault();
		openSubmissionInboxHtmlEditorModal(component, inspector.querySelector('[data-subin-inspector-attr="data-subin-html-content"]'), 'data-subin-html-content');
	}
}

function syncInspectorSwatch(control) {
	var wrapper = control && control.closest ? control.closest('.subin-color-control') : null;
	var swatch = wrapper ? wrapper.querySelector('.subin-swatch') : null;
	var nativeColor = wrapper ? wrapper.querySelector('.subin-color-native') : null;
	var value = control ? control.value : '';

	if (swatch && /^#[0-9a-f]{6}$/i.test(value)) {
		swatch.style.background = value;
	}
	if (nativeColor && /^#[0-9a-f]{6}$/i.test(value)) {
		nativeColor.value = value;
	}
}

function openInspectorNativeColor(wrapper) {
	var nativeColor = wrapper ? wrapper.querySelector('.subin-color-native') : null;

	if (!nativeColor) {
		return;
	}

	if (nativeColor.showPicker) {
		nativeColor.showPicker();
	} else {
		nativeColor.click();
	}
}

function applyInspectorNativeColor(component, nativeColor) {
	var wrapper = nativeColor && nativeColor.closest ? nativeColor.closest('.subin-color-control') : null;
	var textInput = wrapper ? wrapper.querySelector('.subin-input') : null;
	var value = nativeColor ? nativeColor.value : '';
	var styleName = textInput && textInput.getAttribute ? textInput.getAttribute('data-subin-inspector-style') : '';
	var fieldStyleName = textInput && textInput.getAttribute ? textInput.getAttribute('data-subin-field-style') : '';

	if (!textInput || !/^#[0-9a-f]{6}$/i.test(value)) {
		return;
	}

	textInput.value = value;
	syncInspectorSwatch(textInput);

	if (styleName) {
		setInspectorComponentStyle(component, styleName, sanitizeInspectorStyleValue(styleName, value));
		return;
	}

	if (fieldStyleName) {
		addComponentAttribute(component, fieldStyleName, sanitizeFieldStyleTraitValue(textInput));
		applyFieldInnerStyles(component);
	}
}

function currentInspectorComponent(editor) {
	var selected = editor && editor.getSelected ? editor.getSelected() : null;
	return closestControlledStyleComponent(selected) || (editor && editor.getWrapper ? editor.getWrapper() : null);
}

function sanitizeInspectorAttributeValue(name, control) {
	var value = control && control.type === 'checkbox' ? (control.checked ? '1' : '0') : String(control ? control.value : '');

	if (name === 'data-subin-options') {
		return stringifyChoiceOptions(parseChoiceOptions(value));
	}

	if (name === 'data-subin-field-key') {
		return sanitizeOptionValue(value, 0).replace(/^option_1$/, 'field');
	}

	if (name === 'data-subin-html-content') {
		return sanitizeSafeHtml(value);
	}

	if (name === 'data-subin-content') {
		return sanitizeContentAttribute(value, '');
	}

	if (name === 'data-subin-media-url') {
		return sanitizeMediaUrl(value);
	}

	if (name === 'data-subin-media-id') {
		return String(Math.max(0, parseInt(value, 10) || 0));
	}

	return String(value || '').replace(/<\s*(script|iframe|object|embed)\b[\s\S]*?>/gi, '').replace(/on\w+\s*=/gi, '').replace(/(?:javascript|data)\s*:/gi, '').trim();
}

function sanitizeInspectorStyleValue(property, value) {
	var safe = String(value || '').trim();

	if (!safe) {
		return '';
	}

	if (/color/i.test(property)) {
		return /^#[0-9a-f]{6}$/i.test(safe) ? safe : '';
	}

	if (property === 'box-shadow') {
		return ['none', '0 4px 12px rgba(15, 23, 42, 0.12)', '0 10px 24px rgba(15, 23, 42, 0.16)', '0 18px 36px rgba(15, 23, 42, 0.22)'].indexOf(safe) !== -1 ? safe : '';
	}

	if (property === 'border-style') {
		return ['none', 'solid', 'dashed', 'dotted'].indexOf(safe) !== -1 ? safe : '';
	}

	if (property === 'font-weight') {
		return ['300', '400', '500', '600', '700', '800'].indexOf(safe) !== -1 ? safe : '';
	}

	if (property === 'text-align') {
		return ['left', 'center', 'right'].indexOf(safe) !== -1 ? safe : '';
	}

	if (property === 'align-items') {
		return ['flex-start', 'center', 'flex-end', 'stretch'].indexOf(safe) !== -1 ? safe : '';
	}

	if (property === 'justify-content') {
		return ['flex-start', 'center', 'flex-end', 'space-between'].indexOf(safe) !== -1 ? safe : '';
	}

	if (property === 'line-height') {
		return /^\d+(?:\.\d{1,2})?$/.test(safe) || /^\d+(?:\.\d+)?(?:px|rem|em|%)$/.test(safe) ? safe : '';
	}

	if (/(width|height|margin|padding|gap|radius|size|line-height)/i.test(property)) {
		return sanitizeCssBoxValue(safe) || (/^\d+(?:\.\d+)?$/.test(safe) ? safe + 'px' : '');
	}

	return safe.replace(/@import/gi, '').replace(/(?:javascript|data)\s*:/gi, '').replace(/expression\s*\(/gi, '');
}

function setInspectorComponentStyle(component, property, value) {
	var styles = component && component.getStyle ? component.getStyle() : {};
	var next = Object.assign({}, styles);

	if (!component || !component.setStyle) {
		return;
	}

	if (value) {
		next[property] = value;
	} else {
		delete next[property];
	}

	component.setStyle(next);
}

function customOptionsRoot(target) {
	return target && target.closest ? target.closest('[data-subin-custom-options]') : null;
}

function handleInspectorRowAction(component, action) {
	if (action === 'above' || action === 'below') {
		addRowNear(component, action);
	} else if (action === 'delete-empty') {
		deleteRowIfEmpty(component);
	}
}


function updateUnifiedInspectorState(editor) {
	var viewsContainer = grapesjsViewsContainer(editor);
	var inspector = viewsContainer ? viewsContainer.querySelector('.subin-gjs-unified-inspector') : null;
	var selected = editor && editor.getSelected ? editor.getSelected() : null;
	var selectedComponent = closestControlledStyleComponent(selected);
	var subinType = controlledStyleComponentType(selectedComponent);
	var fieldType = selectedFieldType(selectedComponent, subinType);

	if (!inspector) {
		return;
	}

	inspector.setAttribute('data-subin-inspector-type', subinType || '');
	inspector.setAttribute('data-subin-field-type', fieldType || '');
	inspector.classList.toggle('subin-gjs-unified-inspector--empty', !subinType);
	updateInspectorSectionLabels(inspector, subinType, selectedComponent, fieldType);
	applySubmissionInboxInspectorTabs(inspector);
	organizeUnifiedInspector(editor);
}

function updateInspectorSectionLabels(inspector, subinType, selectedComponent, fieldType) {
	var contentTitle = inspector.querySelector('.subin-gjs-unified-inspector__section--traits h3');
	var styleTitle = inspector.querySelector('.subin-gjs-unified-inspector__section--styles h3');
	var selectedLabel = inspector.querySelector('.subin-gjs-unified-inspector__selected');
	var title = inspector.querySelector('.subin-inspector-title');
	var componentLabel = humanReadableComponentLabel(selectedComponent, subinType);

	if (contentTitle) {
		contentTitle.textContent = subinType === 'row' ? 'Layout' : (subinType === 'form-wrapper' ? 'Settings' : 'Content');
	}

	if (styleTitle) {
		styleTitle.textContent = 'Style';
	}

	if (title) {
		title.textContent = componentLabel;
	}

	if (selectedLabel) {
		selectedLabel.textContent = subinType === 'form-wrapper'
			? 'Form-wide content and appearance'
			: (subinType === 'field' ? fieldTypeLabel(fieldType) + ' field' : 'Content and appearance');
	}
}

function selectedFieldType(component, subinType) {
	var attributes = component && component.getAttributes ? component.getAttributes() : {};

	if (subinType !== 'field') {
		return '';
	}

	return String(attributes['data-subin-field-type'] || 'text');
}

function organizeUnifiedInspector(editor) {
	var viewsContainer = grapesjsViewsContainer(editor);
	var inspector = viewsContainer ? viewsContainer.querySelector('.subin-gjs-unified-inspector') : null;
	var selected = editor && editor.getSelected ? editor.getSelected() : null;
	var selectedComponent = closestControlledStyleComponent(selected);
	var subinType = controlledStyleComponentType(selectedComponent);
	var fieldType = selectedFieldType(selectedComponent, subinType);

	if (!inspector) {
		return;
	}

	insertInspectorTraitGroupTitles(inspector, subinType, fieldType);
	normalizeInspectorStyleSectors(inspector, subinType, fieldType);
}

function insertInspectorTraitGroupTitles(inspector, subinType, fieldType) {
	var traits = inspector.querySelectorAll('.subin-gjs-unified-inspector__traits .gjs-trt-trait');
	var lastGroup = '';

	inspector.querySelectorAll('.subin-gjs-trait-group-title').forEach(function (title) {
		title.parentNode.removeChild(title);
	});

	traits.forEach(function (trait) {
		var label = inspectorTraitLabel(trait);
		var group = inspectorTraitGroup(label, subinType, fieldType);

		trait.setAttribute('data-subin-trait-label', label.toLowerCase());

		if (!group || group === lastGroup) {
			return;
		}

		lastGroup = group;
		trait.parentNode.insertBefore(inspectorGroupTitle(group), trait);
	});
}

function inspectorTraitLabel(trait) {
	var label = trait.querySelector('.gjs-label, .gjs-trt-trait__label, label');

	return String(label ? label.textContent : '').replace(/\s+/g, ' ').trim();
}

function inspectorTraitGroup(label, subinType, fieldType) {
	var normalized = String(label || '').toLowerCase();

	if (subinType === 'form-wrapper') {
		if (/(validation|required|spam|success|generic)/.test(normalized)) {
			return 'Messages';
		}
		if (/background image/.test(normalized)) {
			return 'Style';
		}
		return 'Form settings';
	}

	if (subinType === 'row') {
		if (/row actions/.test(normalized)) {
			return 'Row actions';
		}
		if (/background image/.test(normalized)) {
			return 'Style';
		}
		return '';
	}

	if (subinType === 'field') {
		if (fieldType === 'hidden') {
			return 'Hidden field settings';
		}
		if (/options/.test(normalized)) {
			return 'Options';
		}
		if (/required/.test(normalized)) {
			return 'Validation';
		}
		if (/field part styles/.test(normalized)) {
			return '';
		}
		if (fieldType === 'consent') {
			return 'Consent settings';
		}
		return 'Content';
	}

	if (subinType === 'submit-button') {
		return '';
	}

	if (subinType === 'html-block') {
		return '';
	}

	if (['text-block', 'notice', 'privacy'].indexOf(subinType) !== -1) {
		return '';
	}

	return '';
}

function inspectorGroupTitle(label) {
	var element = document.createElement('div');

	element.className = 'subin-gjs-trait-group-title';
	element.textContent = label;
	return element;
}

function normalizeInspectorStyleSectors(inspector, subinType, fieldType) {
	var styleSection = inspector.querySelector('.subin-gjs-unified-inspector__section--styles');
	var sectors = styleSection ? styleSection.querySelectorAll('.gjs-sm-sector') : [];
	var hiddenField = subinType === 'field' && fieldType === 'hidden';

	if (styleSection) {
		styleSection.hidden = hiddenField || subinType === '';
	}

	sectors.forEach(function (sector) {
		var title = sector.querySelector('.gjs-sm-sector-title');
		var label = sector.getAttribute('data-subin-original-sector-label') || (title ? String(title.textContent || '').replace(/\s+/g, ' ').trim() : '');
		var nextLabel = inspectorStyleSectorLabel(label, subinType);

		if (label) {
			sector.setAttribute('data-subin-original-sector-label', label);
		}

		if (title && nextLabel) {
			title.textContent = nextLabel;
		}

		sector.hidden = shouldHideInspectorStyleSector(label, subinType, fieldType);
	});
}

function inspectorStyleSectorLabel(label, subinType) {
	if (label === 'Size') {
		return subinType === 'row' ? 'Row layout' : 'Layout';
	}
	if (label === 'Spacing') {
		return subinType === 'row' ? 'Row layout' : 'Spacing';
	}
	if (label === 'Typography') {
		if (subinType === 'submit-button') {
			return 'Button typography';
		}
		if (['text-block', 'html-block', 'notice', 'privacy'].indexOf(subinType) !== -1) {
			return 'Typography';
		}
		return 'Container text';
	}
	if (label === 'Background') {
		return subinType === 'submit-button' ? 'Button background' : 'Background';
	}
	if (label === 'Border & Radius') {
		return 'Border & Radius';
	}
	if (label === 'Shadow') {
		return 'Shadow';
	}

	return label;
}

function shouldHideInspectorStyleSector(label, subinType, fieldType) {
	if (subinType === 'field' && fieldType === 'hidden') {
		return true;
	}

	if (subinType === 'row') {
		return label === 'Typography' || label === 'Shadow';
	}

	if (subinType === 'form-wrapper') {
		return label === 'Typography';
	}

	if (subinType === 'divider') {
		return label === 'Typography' || label === 'Background' || label === 'Shadow';
	}

	if (subinType === 'spacer') {
		return label === 'Typography' || label === 'Background' || label === 'Border & Radius' || label === 'Shadow';
	}

	return false;
}

function toggleUnifiedInspector(editor, active) {
	var viewsContainer = grapesjsViewsContainer(editor);
	var inspector = viewsContainer ? viewsContainer.querySelector('.subin-gjs-unified-inspector') : null;

	if (!viewsContainer || !inspector) {
		return;
	}

	Array.prototype.forEach.call(viewsContainer.children, function (child) {
		if (child === inspector) {
			child.style.display = active ? 'flex' : 'none';
			return;
		}

		child.style.display = active ? 'none' : '';
	});
}

function scheduleApplyRightPanelMode(editor, mode) {
	applyRightPanelMode(editor, mode);
	window.setTimeout(function () {
		applyRightPanelMode(editor, mode);
	}, 0);
	window.setTimeout(function () {
		applyRightPanelMode(editor, mode);
	}, 80);
}

function applyRightPanelMode(editor, mode) {
	var viewsContainer = grapesjsViewsContainer(editor);
	var inspector = viewsContainer ? viewsContainer.querySelector('.subin-gjs-unified-inspector') : null;

	updateRightPanelButtonState(editor, mode);

	if (!viewsContainer || !inspector) {
		return;
	}

	if (mode === 'inspector') {
		toggleUnifiedInspector(editor, true);
		return;
	}

	Array.prototype.forEach.call(viewsContainer.children, function (child) {
		if (child === inspector) {
			child.style.display = 'none';
			return;
		}

		if (mode === 'blocks') {
			child.style.display = childContainsPanel(child, 'blocks') ? '' : 'none';
			return;
		}

		child.style.display = '';
	});
}

function updateRightPanelButtonState(editor, activeMode) {
	var container = editor && editor.getContainer ? editor.getContainer() : document.getElementById('subin-grapesjs-editor');
	var viewsPanel = container ? container.querySelector('.gjs-pn-views') : null;

	if (!viewsPanel) {
		return;
	}

	viewsPanel.querySelectorAll('.gjs-pn-btn[data-subin-right-panel]').forEach(function (button) {
		var isActive = button.getAttribute('data-subin-right-panel') === activeMode;

		button.classList.toggle('subin-right-panel-tab--active', isActive);
		button.classList.toggle('gjs-pn-active', isActive);
		button.setAttribute('aria-pressed', isActive ? 'true' : 'false');
	});
}

function childContainsPanel(child, mode) {
	if (!child || !child.querySelector) {
		return false;
	}

	if (mode === 'blocks') {
		return !!((child.matches && child.matches('.gjs-blocks-c,.gjs-block-category,.gjs-block')) || child.querySelector('.gjs-blocks-c,.gjs-block-category,.gjs-block'));
	}

	if (mode === 'layers') {
		return !!((child.matches && child.matches('.gjs-layer-manager,.gjs-layers,.gjs-layer,.gjs-layer-title')) || child.querySelector('.gjs-layer-manager,.gjs-layers,.gjs-layer,.gjs-layer-title'));
	}

	return false;
}

function initSubmissionInboxStyleManagerSelection(editor) {
	if (!editor || !editor.on) {
		return;
	}

	editor.on('component:selected', function (component) {
		var selectedComponent = closestControlledStyleComponent(component);

		if (!selectedComponent) {
			return;
		}

		ensureControlledStyleComponent(selectedComponent);

		if (selectedComponent !== component && editor.select) {
			editor.select(selectedComponent);
			return;
		}

		refreshStyleManager(editor);
		updateUnifiedInspectorState(editor);
	});
}

function closestControlledStyleComponent(component) {
	var current = component;

	while (current) {
		if (controlledStyleComponentType(current)) {
			return current;
		}

		current = current.parent ? current.parent() : null;
	}

	return null;
}

function controlledStyleComponentType(component) {
	if (!component || !component.getAttributes) {
		return '';
	}

	var attributes = component.getAttributes();
	var type = component.get ? component.get('type') : '';
	var subinType = attributes['data-subin-component'] || subinComponentNameFromType(type);

	return controlledStyleProps(subinType).length ? subinType : '';
}

function ensureControlledStyleComponent(component) {
	var subinType = controlledStyleComponentType(component);
	var styleProps = controlledStyleProps(subinType);

	if (!styleProps.length || !component.set) {
		return;
	}

	if (subinType === 'form-wrapper') {
		addClasses(component, ['subin-gjs-form-preview', 'subin-gjs-form-flow']);
		component.set('name', 'Form');
	} else if (subinType === 'row') {
		addClasses(component, ['subin-gjs-row']);
		ensureRowId(component);
		ensureUniqueStyleTarget(component, 'row');
		component.set('name', 'Row');
	} else if (subinType === 'field') {
		addClasses(component, ['subin-form-field', 'subin-field-group']);
		ensureUniqueStyleTarget(component, 'field');
		configureFieldComponentTraits(component);
		updateFieldLayerName(component);
	} else if (subinType === 'submit-button') {
		addClasses(component, ['subin-submit-button']);
		ensureUniqueStyleTarget(component, 'submit-button');
		component.set('name', 'Submit button');
	} else {
		addClasses(component, contentBlockClasses(subinComponentTypeFromName(subinType), subinType));
		ensureUniqueStyleTarget(component, subinType);
		component.set('name', humanReadableComponentLabel(component, subinType));
	}

	component.set('stylable', styleProps);
}

function controlledStyleProps(subinType) {
	if (subinType === 'form-wrapper') {
		return subinWrapperStyleProps();
	}

	if (subinType === 'row') {
		return subinRowStyleProps();
	}

	if (subinType === 'field') {
		return subinFieldStyleProps();
	}

	if (subinType === 'submit-button') {
		return subinButtonStyleProps();
	}

	if ([
		'text-block',
		'html-block',
		'notice',
		'divider',
		'privacy',
		'section',
		'spacer',
		'image-block',
	].indexOf(subinType) !== -1) {
		return subinContentStyleProps(subinType);
	}

	return [];
}
