<?php
/**
 * SiteOrigin Features widget — RSM Features chip cards.
 *
 * SiteOrigin requires widget id, folder name, and PHP basename to match
 * (id "features", path widgets/features/features.php).
 *
 * @package Rsmspark_Content_Widgets
 */

/*
Widget Name: RSM Features
Description: Display feature highlights as customizable chip cards with enable/disable, shape options, and theme-aware typography.
Author: RSMSpark
Author URI: https://rsmspark.com/
Widget URI: https://rsmspark.com/
*/

defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'SiteOrigin_Widget', false ) ) {
	return;
}

/**
 * RSM Features SiteOrigin widget.
 */
class Rsmspark_Content_Widgets_Features_Widget extends SiteOrigin_Widget {

	/**
	 * @var bool
	 */
	protected static $rendered_on_request = false;

	/**
	 * @var bool
	 */
	protected static $printed_shell_reset = false;

	/**
	 * Constructor.
	 */
	public function __construct() {
		parent::__construct(
			'features',
			__( 'RSM Features', 'rsm-content-widgets' ),
			array(
				'description' => __( 'Feature chip cards with per-item enable/disable, corner presets, and Customizer-aware fonts.', 'rsm-content-widgets' ),
				'help'        => 'https://rsmspark.com/',
				'panels_icon' => 'dashicons dashicons-star-filled',
				'has_preview' => true,
				'keywords'    => array( 'features', 'chips', 'cards', 'highlights', 'RSM', 'RSMSpark' ),
			),
			array(),
			array(),
			plugin_dir_path( __FILE__ )
		);

		$this->register_frontend_styles(
			array(
				array(
					'rsmspark-features-fontawesome',
					RSMSPARK_CONTENT_WIDGETS_URL . 'assets/vendor/fontawesome/css/all.min.css',
					array(),
					'6.5.2',
				),
				array(
					'rsmspark-rich-text',
					RSMSPARK_CONTENT_WIDGETS_URL . 'includes/rsm-editor/assets/css/rsm-editor.css',
					array(),
					RSMSPARK_RICH_TEXT_VERSION,
				),
				array(
					'rsmspark-content-widgets',
					RSMSPARK_CONTENT_WIDGETS_URL . 'assets/css/rsm-features.css',
					array( 'rsmspark-features-fontawesome', 'dashicons', 'rsmspark-rich-text' ),
					RSMSPARK_CONTENT_WIDGETS_VERSION,
				),
			)
		);

		$this->register_frontend_scripts(
			array(
				array(
					'rsmspark-cw-modal',
					RSMSPARK_CONTENT_WIDGETS_URL . 'assets/js/rsm-cw-modal.js',
					array(),
					RSMSPARK_CONTENT_WIDGETS_VERSION,
				),
				array(
					'rsmspark-content-widgets',
					RSMSPARK_CONTENT_WIDGETS_URL . 'assets/js/rsm-features.js',
					array( 'jquery', 'rsmspark-cw-modal' ),
					RSMSPARK_CONTENT_WIDGETS_VERSION,
				),
			)
		);
	}

	/**
	 * SiteOrigin integration hooks.
	 */
	public function initialize() {
		parent::initialize();

		$hook = 'siteorigin_widgets_wrapper_classes_' . $this->id_base;
		if ( ! has_filter( $hook, array( $this, 'filter_siteorigin_wrapper_classes' ) ) ) {
			add_filter( $hook, array( $this, 'filter_siteorigin_wrapper_classes' ), 10, 3 );
		}

		$after = 'siteorigin_widgets_after_widget_' . $this->id_base;
		if ( ! has_action( $after, array( __CLASS__, 'mark_rendered_for_shell_reset' ) ) ) {
			add_action( $after, array( __CLASS__, 'mark_rendered_for_shell_reset' ), 1, 2 );
		}
		if ( ! has_action( 'wp_footer', array( __CLASS__, 'print_so_shell_border_reset' ) ) ) {
			add_action( 'wp_footer', array( __CLASS__, 'print_so_shell_border_reset' ), 9999 );
			add_action( 'admin_print_footer_scripts', array( __CLASS__, 'print_so_shell_border_reset' ), 9999 );
		}

		$panels_classes = 'siteorigin_panels_widget_classes';
		if ( ! has_filter( $panels_classes, array( __CLASS__, 'filter_panels_so_panel_classes' ) ) ) {
			add_filter( $panels_classes, array( __CLASS__, 'filter_panels_so_panel_classes' ), 10, 4 );
		}
	}

	/**
	 * @param array              $instance Widget instance.
	 * @param SiteOrigin_Widget $widget    Widget object.
	 */
	public static function mark_rendered_for_shell_reset( $instance, $widget ) {
		self::$rendered_on_request = true;
	}

	/**
	 * Clear SiteOrigin outer wrapper chrome after our styles load.
	 */
	public static function print_so_shell_border_reset() {
		if ( ! self::$rendered_on_request || self::$printed_shell_reset ) {
			return;
		}
		self::$printed_shell_reset = true;

		$css  = 'div.so-widget-features.rsmspark-features-so-shell,div.so-widget-features.so-widget-features-base.rsmspark-features-so-shell,div.so-widget-features:has([data-rsmspark-features]){border-width:0!important;border-style:none!important;border-color:transparent!important;border-image:none!important;border-image-source:none!important;border-image-width:0!important;border-image-slice:0!important;box-shadow:none!important;outline:none!important;outline-width:0!important;filter:none!important;background:transparent!important;padding:0!important;margin:0!important;}';
		$css .= 'div.so-widget-features.rsmspark-features-so-shell::before,div.so-widget-features.rsmspark-features-so-shell::after,div.so-widget-features.so-widget-features-base.rsmspark-features-so-shell::before,div.so-widget-features.so-widget-features-base.rsmspark-features-so-shell::after,div.so-widget-features:has([data-rsmspark-features])::before,div.so-widget-features:has([data-rsmspark-features])::after{content:none!important;display:none!important;border-width:0!important;border-style:none!important;box-shadow:none!important;}';
		$css .= 'body.siteorigin-panels .so-panel.widget_features,body.siteorigin-panels .so-panel.widget.widget_features,body.siteorigin-panels .panel-grid-cell>.so-panel.widget_features,body.siteorigin-panels .panel-grid-cell>.so-panel.widget.widget_features,.panel-grid-cell>.so-panel.widget_features,.panel-grid-cell>.so-panel.widget.widget_features,.so-panel.widget_features:has([data-rsmspark-features]),.so-panel.rsmspark-features-so-panel:has([data-rsmspark-features]){border-width:0!important;border-style:none!important;border-color:transparent!important;border-image:none!important;box-shadow:none!important;outline:none!important;background:transparent!important;filter:none!important;}';
		$css .= '@supports selector(:has(*)){.panel-grid-cell:has(.so-widget-features.rsmspark-features-so-shell),.panel-grid-cell:has([data-rsmspark-features]){border-width:0!important;border-style:none!important;border-color:transparent!important;border-image:none!important;border-image-width:0!important;border-image-slice:0!important;box-shadow:none!important;outline:none!important;filter:none!important;}';
		$css .= '.panel-grid-cell:has(.so-widget-features.rsmspark-features-so-shell)>div[class*=panel-cell-style],.panel-grid-cell:has([data-rsmspark-features])>div[class*=panel-cell-style],.panel-grid-cell:has([data-rsmspark-features]) [class*=panel-cell-style],.panel-grid-cell:has([data-rsmspark-features]) [class*=panel-widget-style]{border-width:0!important;border-style:none!important;border-color:transparent!important;border-image:none!important;border-image-width:0!important;border-image-slice:0!important;box-shadow:none!important;outline:none!important;filter:none!important;}';
		$css .= '.panel-grid-cell:has(.so-widget-features.rsmspark-features-so-shell)::before,.panel-grid-cell:has(.so-widget-features.rsmspark-features-so-shell)::after,.panel-grid-cell:has([data-rsmspark-features])::before,.panel-grid-cell:has([data-rsmspark-features])::after{content:none!important;display:none!important;border-width:0!important;border-style:none!important;box-shadow:none!important;}}';
		$css .= '.so-panel.rsmspark-features-so-panel{border-width:0!important;border-style:none!important;border-color:transparent!important;border-image:none!important;border-image-width:0!important;border-image-slice:0!important;box-shadow:none!important;outline:none!important;filter:none!important;background:transparent!important;}';
		$css .= '.so-panel.rsmspark-features-so-panel::before,.so-panel.rsmspark-features-so-panel::after{content:none!important;display:none!important;border-width:0!important;border-style:none!important;box-shadow:none!important;}';

		$style_handle = 'rsmspark-features-so-shell-border-reset';
		if ( ! wp_style_is( $style_handle, 'registered' ) ) {
			wp_register_style( $style_handle, false, array(), RSMSPARK_CONTENT_WIDGETS_VERSION );
		}
		wp_enqueue_style( $style_handle );
		wp_add_inline_style( $style_handle, $css );
		wp_print_styles( $style_handle );
		$boot_js = '(function(){var f=window.rsmFeaturesStripShell||window.rsmFeaturesInit;if(!f){return;}f();setTimeout(f,0);setTimeout(f,150);setTimeout(f,500);setTimeout(f,1000);})();';
		$script_handle = 'rsmspark-features-so-shell-strip-boot';
		if ( ! wp_script_is( $script_handle, 'registered' ) ) {
			wp_register_script( $script_handle, false, array(), RSMSPARK_CONTENT_WIDGETS_VERSION, true );
		}
		wp_enqueue_script( $script_handle );
		wp_add_inline_script( $script_handle, $boot_js );
		wp_print_scripts( $script_handle );
	}

	/**
	 * @param string[] $classes      Panel classes.
	 * @param string   $widget_class Widget class key.
	 * @param array    $instance     Instance.
	 * @param array    $widget_info  Metadata.
	 * @return string[]
	 */
	public static function filter_panels_so_panel_classes( $classes, $widget_class, $instance, $widget_info ) {
		unset( $widget_class, $instance, $widget_info );
		if ( is_array( $classes ) && in_array( 'widget_features', $classes, true ) ) {
			$classes[] = 'rsmspark-features-so-panel';
		}
		return $classes;
	}

	/**
	 * @param string[]           $classes  Wrapper classes.
	 * @param array              $instance Instance.
	 * @param SiteOrigin_Widget $widget    Widget.
	 * @return string[]
	 */
	public function filter_siteorigin_wrapper_classes( $classes, $instance, $widget ) {
		unset( $instance, $widget );
		if ( ! is_array( $classes ) ) {
			$classes = array();
		}
		$classes[] = 'rsmspark-features-so-shell';
		return $classes;
	}

	/**
	 * Admin scripts and styles.
	 */
	public function enqueue_admin_scripts() {
		self::$rendered_on_request = true;
		if ( class_exists( 'Rsmspark_Rich_Text_Assets', false ) ) {
			Rsmspark_Rich_Text_Assets::enqueue_admin();
		}

		if ( class_exists( 'Rsmspark_Content_Widgets_Assets', false ) ) {
			Rsmspark_Content_Widgets_Assets::enqueue_export_json_ui_assets();
		}

		wp_enqueue_style( 'dashicons' );
		wp_enqueue_style(
			'rsmspark-features-fontawesome',
			RSMSPARK_CONTENT_WIDGETS_URL . 'assets/vendor/fontawesome/css/all.min.css',
			array(),
			'6.5.2'
		);
		wp_enqueue_style(
			'rsmspark-content-widgets',
			RSMSPARK_CONTENT_WIDGETS_URL . 'assets/css/rsm-features.css',
			array( 'rsmspark-features-fontawesome', 'dashicons' ),
			RSMSPARK_CONTENT_WIDGETS_VERSION
		);
		wp_enqueue_script(
			'rsmspark-cw-modal',
			RSMSPARK_CONTENT_WIDGETS_URL . 'assets/js/rsm-cw-modal.js',
			array(),
			RSMSPARK_CONTENT_WIDGETS_VERSION,
			true
		);
		wp_enqueue_script(
			'rsmspark-content-widgets',
			RSMSPARK_CONTENT_WIDGETS_URL . 'assets/js/rsm-features.js',
			array( 'jquery', 'rsmspark-cw-modal' ),
			RSMSPARK_CONTENT_WIDGETS_VERSION,
			true
		);

		wp_enqueue_script(
			'rsmspark-cw-features-admin',
			RSMSPARK_CONTENT_WIDGETS_URL . 'assets/js/rsm-cw-features-admin.js',
			array( 'jquery', 'rsmspark-cw-export-json-ui' ),
			RSMSPARK_CONTENT_WIDGETS_VERSION,
			true
		);

		wp_localize_script(
			'rsmspark-cw-features-admin',
			'rsmsparkCwFeaturesAdmin',
			array(
				'ajaxUrl' => admin_url( 'admin-ajax.php' ),
				'nonce'   => wp_create_nonce( 'rsmspark_cw_features_admin' ),
				'version' => RSMSPARK_CONTENT_WIDGETS_VERSION,
				'i18n'    => array(
					'exportLabel'      => __( 'Generated export (also copied to your clipboard):', 'rsm-content-widgets' ),
					'exportPanelTitle' => __( 'JSON export ready', 'rsm-content-widgets' ),
					'importError'      => __( 'Paste valid RSM Features JSON export data (widget or block export).', 'rsm-content-widgets' ),
					'importApplied'    => __( 'Features import applied. Review Feature chips and Popout rows if counts changed.', 'rsm-content-widgets' ),
					'confirm'          => __( 'Apply this features import? Current settings will be overwritten.', 'rsm-content-widgets' ),
					'requestError'     => __( 'Could not process features JSON. Try again.', 'rsm-content-widgets' ),
				),
			)
		);
	}

	/**
	 * @param array $instance Instance.
	 */
	public function enqueue_frontend_scripts( $instance ) {
		self::$rendered_on_request = true;
		wp_enqueue_style( 'dashicons' );
		parent::enqueue_frontend_scripts( $instance );
		if ( class_exists( 'Rsmspark_Rich_Text_Assets', false ) ) {
			Rsmspark_Rich_Text_Assets::enqueue_siteorigin_frontend();
		}
		wp_enqueue_style( 'rsmspark-content-widgets' );
		wp_enqueue_script( 'rsmspark-cw-modal' );
		wp_enqueue_script( 'rsmspark-content-widgets' );
		wp_add_inline_script(
			'rsmspark-content-widgets',
			'(function(){var f=window.rsmFeaturesStripShell||window.rsmFeaturesInit;if(!f){return;}f();setTimeout(f,0);setTimeout(f,150);setTimeout(f,500);setTimeout(f,1000);})();',
			'after'
		);
	}

	/**
	 * @param array $instance Instance.
	 * @return string
	 */
	public function get_style_name( $instance ) {
		return '';
	}

	/**
	 * @param array $instance Instance.
	 * @return string
	 */
	public function get_template_dir( $instance ) {
		return '';
	}

	/**
	 * @param array $instance Instance.
	 * @return string
	 */
	public function get_template_name( $instance ) {
		return 'features.tpl';
	}

	/**
	 * Widget form definition.
	 *
	 * @return array
	 */
	public function get_widget_form() {
		$demo_features = array(
			array(
				'enabled'      => true,
				'title'        => __( 'Fast setup', 'rsm-content-widgets' ),
				'description'  => '<p>' . __( 'Drop the widget into any SiteOrigin layout or widget area and start editing chip cards immediately.', 'rsm-content-widgets' ) . '</p>',
				'title_icon'   => 'dashicons dashicons-performance',
				'title_image'  => '',
				'accent_color' => '#2563eb',
				'chip_shape'   => 'inherit',
			),
			array(
				'enabled'      => true,
				'title'        => __( 'Theme fonts', 'rsm-content-widgets' ),
				'description'  => '<p>' . __( 'Inherits the RSMSpark theme body typography by default, with the same font families available in Customizer-powered forms.', 'rsm-content-widgets' ) . '</p>',
				'title_icon'   => 'dashicons dashicons-editor-textcolor',
				'title_image'  => '',
				'accent_color' => '#0f766e',
				'chip_shape'   => 'inherit',
			),
			array(
				'enabled'      => true,
				'title'        => __( 'Flexible shapes', 'rsm-content-widgets' ),
				'description'  => '<p>' . __( 'Choose global corner presets or override individual chips — square, rounded, or pill.', 'rsm-content-widgets' ) . '</p>',
				'title_icon'   => 'dashicons dashicons-art',
				'title_image'  => '',
				'accent_color' => '#c2410c',
				'chip_shape'   => 'inherit',
			),
		);

		return array(
			'import_export' => array(
				'type'   => 'section',
				'label'  => __( 'Import / export JSON', 'rsm-content-widgets' ),
				'fields' => array(
					'export_json' => array(
						'type'        => 'textarea',
						'label'       => __( 'Export JSON', 'rsm-content-widgets' ),
						'rows'        => 8,
						'description' => __( 'Generate JSON from the current features settings, then copy or save the text below.', 'rsm-content-widgets' )
							. '<p class="rsmspark-cw-features-json-actions"><button type="button" class="button rsmspark-cw-features-export-json">'
							. esc_html__( 'Export JSON', 'rsm-content-widgets' )
							. '</button></p>',
					),
					'import_json' => array(
						'type'        => 'textarea',
						'label'       => __( 'Import JSON', 'rsm-content-widgets' ),
						'rows'        => 8,
						'description' => __( 'Paste an RSM Features export (widget or block JSON), then click Apply import.', 'rsm-content-widgets' )
							. '<p class="rsmspark-cw-features-json-actions"><button type="button" class="button button-primary rsmspark-cw-features-import-json">'
							. esc_html__( 'Apply import', 'rsm-content-widgets' )
							. '</button></p>',
					),
				),
			),
			'general' => array(
				'type'        => 'section',
				'label'       => __( 'General', 'rsm-content-widgets' ),
				'description' => __( 'Widget heading and individual feature chip cards.', 'rsm-content-widgets' ),
				'hide'        => false,
				'fields'      => array(
					'title'    => array(
						'type'        => 'text',
						'label'       => __( 'Section title', 'rsm-content-widgets' ),
						'description' => __( 'Optional heading displayed above the chip grid.', 'rsm-content-widgets' ),
						'default'     => __( 'Features', 'rsm-content-widgets' ),
					),
					'features' => array(
						'type'       => 'repeater',
						'label'      => __( 'Feature chips', 'rsm-content-widgets' ),
						'item_name'  => __( 'Feature', 'rsm-content-widgets' ),
						'description' => __( 'Add, remove, and reorder feature chip cards. Disabled chips are hidden on the front end.', 'rsm-content-widgets' ),
						'item_label' => array(
							'selector'     => "[id*='title']",
							'update_event' => 'change',
							'value_method' => 'val',
						),
						'default'    => $demo_features,
						'fields'     => array(
							'enabled' => array(
								'type'        => 'checkbox',
								'label'       => __( 'Enabled', 'rsm-content-widgets' ),
								'description' => __( 'Uncheck to hide this chip on the front end.', 'rsm-content-widgets' ),
								'default'     => true,
							),
							'title'   => array_merge(
								Rsmspark_Rich_Text_Registry::siteorigin_tinymce_field( Rsmspark_Rich_Text_Registry::PROFILE_HEADLINE, 3 ),
								array(
									'label'          => __( 'Title', 'rsm-content-widgets' ),
									'default'        => __( 'Feature', 'rsm-content-widgets' ),
									'rsm_rt_profile' => Rsmspark_Rich_Text_Registry::PROFILE_HEADLINE,
									'description'    => __( 'Headline profile: size, color, and gradient tokens for chip titles.', 'rsm-content-widgets' ),
								)
							),
							'description' => array_merge(
								Rsmspark_Rich_Text_Registry::siteorigin_tinymce_field( Rsmspark_Rich_Text_Registry::PROFILE_BODY, 8 ),
								array(
									'label'          => __( 'Description', 'rsm-content-widgets' ),
									'default'        => '',
									'rsm_rt_profile' => Rsmspark_Rich_Text_Registry::PROFILE_BODY,
									'description'    => __( 'Body profile: paragraphs, lists, size/color tokens. Legacy shortcodes still render on the front end.', 'rsm-content-widgets' ),
								)
							),
							'title_icon' => array(
								'type'        => 'icon',
								'label'       => __( 'Icon', 'rsm-content-widgets' ),
								'description' => __( 'Optional for Number in circle. Pick an icon or enter a badge character below — either is enough.', 'rsm-content-widgets' ),
								'default'     => 'dashicons dashicons-star-filled',
							),
							'icon_style' => array(
								'type'        => 'select',
								'label'       => __( 'Icon style', 'rsm-content-widgets' ),
								'description' => __( 'Number in circle renders a Font Awesome stack (circle + number).', 'rsm-content-widgets' ),
								'default'     => 'glyph',
								'options'     => Rsmspark_Content_Widgets_Features_Styles::get_icon_style_options(),
							),
							'icon_color' => array(
								'type'        => 'color',
								'label'       => __( 'Icon color', 'rsm-content-widgets' ),
								'description' => __( 'Color for icon glyphs. Leave empty to use the accent color.', 'rsm-content-widgets' ),
								'default'     => '',
							),
							'icon_badge_circle_color' => array(
								'type'        => 'color',
								'label'       => __( 'Badge circle color', 'rsm-content-widgets' ),
								'description' => __( 'Background circle for Number in circle style. Defaults to accent color.', 'rsm-content-widgets' ),
								'default'     => '',
							),
							'icon_badge_text_color' => array(
								'type'        => 'color',
								'label'       => __( 'Badge number color', 'rsm-content-widgets' ),
								'description' => __( 'Foreground color for the number or glyph in the circle.', 'rsm-content-widgets' ),
								'default'     => '#ffffff',
							),
							'icon_badge_glyph' => array(
								'type'        => 'text',
								'label'       => __( 'Badge character', 'rsm-content-widgets' ),
								'description' => __( 'Required for Number in circle when no icon is selected. Enter 0–9 or a letter.', 'rsm-content-widgets' ),
								'default'     => '',
							),
							'title_image' => array(
								'type'    => 'media',
								'label'   => __( 'Icon image', 'rsm-content-widgets' ),
								'choose'  => __( 'Choose image', 'rsm-content-widgets' ),
								'update'  => __( 'Set image', 'rsm-content-widgets' ),
								'library' => 'image',
								'default' => '',
							),
							'accent_color' => array(
								'type'        => 'color',
								'label'       => __( 'Accent color', 'rsm-content-widgets' ),
								'description' => __( 'Left border tint and default icon/badge circle color when badge colors are empty.', 'rsm-content-widgets' ),
								'default'     => '',
							),
							'chip_shape' => array(
								'type'        => 'select',
								'label'       => __( 'Corner shape', 'rsm-content-widgets' ),
								'description' => __( 'Override the widget default corner preset for this chip only.', 'rsm-content-widgets' ),
								'default'     => 'inherit',
								'options'     => Rsmspark_Content_Widgets_Features_Styles::get_shape_options( true ),
							),
							'icon_size' => array(
								'type'        => 'select',
								'label'       => __( 'Icon size', 'rsm-content-widgets' ),
								'description' => __( 'Override the widget default icon size for this chip only.', 'rsm-content-widgets' ),
								'default'     => 'inherit',
								'options'     => Rsmspark_Content_Widgets_Features_Styles::get_icon_size_options( true ),
							),
							'icon_size_custom' => array(
								'type'        => 'slider',
								'label'       => __( 'Custom icon size', 'rsm-content-widgets' ),
								'description' => sprintf(
									/* translators: 1: minimum px, 2: maximum px */
									__( 'Used when this chip’s icon size is set to Custom (%1$d–%2$dpx).', 'rsm-content-widgets' ),
									Rsmspark_Content_Widgets_Features_Styles::get_icon_size_custom_bounds()['min'],
									Rsmspark_Content_Widgets_Features_Styles::get_icon_size_custom_bounds()['max']
								),
								'min'         => Rsmspark_Content_Widgets_Features_Styles::get_icon_size_custom_bounds()['min'],
								'max'         => Rsmspark_Content_Widgets_Features_Styles::get_icon_size_custom_bounds()['max'],
								'integer'     => true,
								'default'     => Rsmspark_Content_Widgets_Features_Styles::get_icon_size_custom_bounds()['default'],
							),
							'icon_align' => array(
								'type'        => 'select',
								'label'       => __( 'Icon alignment', 'rsm-content-widgets' ),
								'description' => __( 'Override the widget default icon alignment for this chip only.', 'rsm-content-widgets' ),
								'default'     => 'inherit',
								'options'     => Rsmspark_Content_Widgets_Features_Styles::get_icon_align_options( true ),
							),
							'popout_hot' => array(
								'type'        => 'checkbox',
								'label'       => __( 'Hot (opens popout)', 'rsm-content-widgets' ),
								'description' => __( 'Make this chip clickable when Feature Chip Popouts are enabled.', 'rsm-content-widgets' ),
								'default'     => false,
							),
						),
					),
				),
			),

			'layout' => array(
				'type'        => 'section',
				'label'       => __( 'Layout', 'rsm-content-widgets' ),
				'description' => __( 'Grid columns and spacing.', 'rsm-content-widgets' ),
				'hide'        => false,
				'fields'      => array(
					'columns' => array(
						'type'        => 'slider',
						'label'       => __( 'Columns', 'rsm-content-widgets' ),
						'description' => __( 'Number of chip cards per row on wide screens. Stacks on smaller viewports.', 'rsm-content-widgets' ),
						'min'         => 1,
						'max'         => 6,
						'integer'     => true,
						'default'     => 3,
					),
					'grid_gap' => array(
						'type'    => 'slider',
						'label'   => __( 'Gap between chips', 'rsm-content-widgets' ),
						'min'     => 0,
						'max'     => 48,
						'integer' => true,
						'default' => 16,
					),
					'chip_layout' => array(
						'type'        => 'select',
						'label'       => __( 'Chip layout', 'rsm-content-widgets' ),
						'description' => __( 'Stacked places the icon or number badge above the chip title. Icon left matches the RSMSpark plugin card style.', 'rsm-content-widgets' ),
						'default'     => 'stacked',
						'options'     => Rsmspark_Content_Widgets_Features_Styles::get_chip_layout_options(),
					),
					'media_gap' => array(
						'type'        => 'slider',
						'label'       => __( 'Icon-to-text gap', 'rsm-content-widgets' ),
						'description' => __( 'Space between the icon and text. Horizontal in icon-left layout; vertical in stacked layout.', 'rsm-content-widgets' ),
						'min'         => 0,
						'max'         => 48,
						'integer'     => true,
						'default'     => 16,
					),
					'align' => array(
						'type'    => 'select',
						'label'   => __( 'Text alignment', 'rsm-content-widgets' ),
						'default' => 'left',
						'options' => array(
							'left'   => __( 'Left', 'rsm-content-widgets' ),
							'center' => __( 'Center', 'rsm-content-widgets' ),
						),
					),
				),
			),

			'design' => array(
				'type'        => 'section',
				'label'       => __( 'Design', 'rsm-content-widgets' ),
				'description' => __( 'Chip appearance, typography, and colors. Values map to CSS custom properties.', 'rsm-content-widgets' ),
				'hide'        => false,
				'fields'      => array(
					'container_border' => array(
						'type'        => 'checkbox',
						'label'       => __( 'Show container border', 'rsm-content-widgets' ),
						'description' => __( 'Draw a border around the entire features widget area. Off by default.', 'rsm-content-widgets' ),
						'default'     => false,
					),
					'container_border_color' => array(
						'type'    => 'color',
						'label'   => __( 'Container border color', 'rsm-content-widgets' ),
						'default' => '#e2e8f0',
					),
					'container_border_width' => array(
						'type'    => 'slider',
						'label'   => __( 'Container border width', 'rsm-content-widgets' ),
						'min'     => 1,
						'max'     => 8,
						'integer' => true,
						'default' => 1,
					),
					'container_shape' => array(
						'type'    => 'select',
						'label'   => __( 'Container corner shape', 'rsm-content-widgets' ),
						'default' => 'medium',
						'options' => Rsmspark_Content_Widgets_Features_Styles::get_shape_options( false ),
					),
					'container_pad' => array(
						'type'        => 'slider',
						'label'       => __( 'Container padding', 'rsm-content-widgets' ),
						'description' => __( 'Inner spacing when the container border is enabled.', 'rsm-content-widgets' ),
						'min'         => 0,
						'max'         => 48,
						'integer'     => true,
						'default'     => 16,
					),
					'chip_style' => array(
						'type'    => 'select',
						'label'   => __( 'Chip style', 'rsm-content-widgets' ),
						'default' => 'soft',
						'options' => Rsmspark_Content_Widgets_Features_Styles::get_chip_style_options(),
					),
					'chip_shape' => array(
						'type'    => 'select',
						'label'   => __( 'Default corner shape', 'rsm-content-widgets' ),
						'default' => 'medium',
						'options' => Rsmspark_Content_Widgets_Features_Styles::get_shape_options( false ),
					),
					'chip_bg' => array(
						'type'    => 'color',
						'label'   => __( 'Chip background', 'rsm-content-widgets' ),
						'default' => '#ffffff',
					),
					'chip_border_color' => array(
						'type'    => 'color',
						'label'   => __( 'Chip border color', 'rsm-content-widgets' ),
						'default' => '#e2e8f0',
					),
					'chip_border_width' => array(
						'type'    => 'slider',
						'label'   => __( 'Chip border width', 'rsm-content-widgets' ),
						'min'     => 0,
						'max'     => 6,
						'integer' => true,
						'default' => 1,
					),
					'chip_accent_color' => array(
						'type'    => 'color',
						'label'   => __( 'Default accent color', 'rsm-content-widgets' ),
						'default' => '#2563eb',
					),
					'chip_title_color' => array(
						'type'    => 'color',
						'label'   => __( 'Title color', 'rsm-content-widgets' ),
						'default' => '#0f172a',
					),
					'chip_text_color' => array(
						'type'    => 'color',
						'label'   => __( 'Description color', 'rsm-content-widgets' ),
						'default' => '#475569',
					),
					'chip_pad_top' => array(
						'type'    => 'slider',
						'label'   => __( 'Chip padding: top', 'rsm-content-widgets' ),
						'min'     => 0,
						'max'     => 48,
						'integer' => true,
						'default' => 16,
					),
					'chip_pad_right' => array(
						'type'    => 'slider',
						'label'   => __( 'Chip padding: right', 'rsm-content-widgets' ),
						'min'     => 0,
						'max'     => 48,
						'integer' => true,
						'default' => 18,
					),
					'chip_pad_bottom' => array(
						'type'    => 'slider',
						'label'   => __( 'Chip padding: bottom', 'rsm-content-widgets' ),
						'min'     => 0,
						'max'     => 48,
						'integer' => true,
						'default' => 16,
					),
					'chip_pad_left' => array(
						'type'    => 'slider',
						'label'   => __( 'Chip padding: left', 'rsm-content-widgets' ),
						'min'     => 0,
						'max'     => 48,
						'integer' => true,
						'default' => 18,
					),
					'icon_size_preset' => array(
						'type'        => 'select',
						'label'       => __( 'Icon size', 'rsm-content-widgets' ),
						'description' => sprintf(
							/* translators: 1: minimum preset px, 2: maximum preset px */
							__( 'Preset sizes from %1$dpx to %2$dpx. Choose Custom for the slider.', 'rsm-content-widgets' ),
							Rsmspark_Content_Widgets_Features_Styles::get_icon_size_preset_bounds()['min'],
							Rsmspark_Content_Widgets_Features_Styles::get_icon_size_preset_bounds()['max']
						),
						'default'     => 'medium',
						'options'     => Rsmspark_Content_Widgets_Features_Styles::get_icon_size_options( false ),
					),
					'icon_size_custom' => array(
						'type'        => 'slider',
						'label'       => __( 'Custom icon size', 'rsm-content-widgets' ),
						'description' => sprintf(
							/* translators: 1: minimum px, 2: maximum px */
							__( 'Fine-tune icon size when Icon size is Custom (%1$d–%2$dpx).', 'rsm-content-widgets' ),
							Rsmspark_Content_Widgets_Features_Styles::get_icon_size_custom_bounds()['min'],
							Rsmspark_Content_Widgets_Features_Styles::get_icon_size_custom_bounds()['max']
						),
						'min'         => Rsmspark_Content_Widgets_Features_Styles::get_icon_size_custom_bounds()['min'],
						'max'         => Rsmspark_Content_Widgets_Features_Styles::get_icon_size_custom_bounds()['max'],
						'integer'     => true,
						'default'     => Rsmspark_Content_Widgets_Features_Styles::get_icon_size_custom_bounds()['default'],
					),
					'icon_align' => array(
						'type'        => 'select',
						'label'       => __( 'Icon alignment', 'rsm-content-widgets' ),
						'description' => __( 'Horizontal alignment of icons within each chip when using stacked layout.', 'rsm-content-widgets' ),
						'default'     => 'center',
						'options'     => Rsmspark_Content_Widgets_Features_Styles::get_icon_align_options( false ),
					),
					'title_font' => array(
						'type'        => 'select',
						'label'       => __( 'Title font', 'rsm-content-widgets' ),
						'description' => __( 'Theme default inherits the RSMSpark Customizer body font stack.', 'rsm-content-widgets' ),
						'default'     => 'inherit',
						'options'     => Rsmspark_Content_Widgets_Features_Fonts::get_select_options(),
					),
					'title_font_size' => array(
						'type'        => 'slider',
						'label'       => __( 'Title font size', 'rsm-content-widgets' ),
						'description' => __( 'Set to 0 to inherit the theme Customizer body font size.', 'rsm-content-widgets' ),
						'min'         => 0,
						'max'         => 36,
						'integer'     => true,
						'default'     => 0,
					),
					'title_font_weight' => array(
						'type'    => 'slider',
						'label'   => __( 'Title font weight', 'rsm-content-widgets' ),
						'min'     => 400,
						'max'     => 900,
						'integer' => true,
						'default' => 700,
					),
					'body_font' => array(
						'type'        => 'select',
						'label'       => __( 'Description font', 'rsm-content-widgets' ),
						'description' => __( 'Theme default inherits the RSMSpark Customizer body font stack.', 'rsm-content-widgets' ),
						'default'     => 'inherit',
						'options'     => Rsmspark_Content_Widgets_Features_Fonts::get_select_options(),
					),
					'body_font_size' => array(
						'type'        => 'slider',
						'label'       => __( 'Description font size', 'rsm-content-widgets' ),
						'description' => __( 'Set to 0 to inherit the theme Customizer body font size.', 'rsm-content-widgets' ),
						'min'         => 0,
						'max'         => 24,
						'integer'     => true,
						'default'     => 0,
					),
				),
			),

			'popouts' => array(
				'type'        => 'section',
				'label'       => __( 'Feature Chip Popouts', 'rsm-content-widgets' ),
				'description' => __( 'Clickable “hot” chips open a modal with extended content. Mark chips as Hot under Feature chips, then add matching popout rows below.', 'rsm-content-widgets' ),
				'hide'        => false,
				'fields'      => array(
					'enable_popouts' => array(
						'type'        => 'checkbox',
						'label'       => __( 'Enable chip popouts', 'rsm-content-widgets' ),
						'description' => __( 'When enabled, chips marked Hot become clickable and open a detail modal.', 'rsm-content-widgets' ),
						'default'     => false,
					),
					'popout_overlay_color' => array(
						'type'    => 'color',
						'label'   => __( 'Overlay color', 'rsm-content-widgets' ),
						'default' => '#0f172a',
					),
					'popout_overlay_opacity' => array(
						'type'        => 'slider',
						'label'       => __( 'Overlay opacity', 'rsm-content-widgets' ),
						'description' => __( 'Backdrop darkness behind the modal (0–100%).', 'rsm-content-widgets' ),
						'min'         => 0,
						'max'         => 100,
						'integer'     => true,
						'default'     => 70,
					),
					'popout_bg' => array(
						'type'    => 'color',
						'label'   => __( 'Popout background', 'rsm-content-widgets' ),
						'default' => '#ffffff',
					),
					'popout_border_color' => array(
						'type'    => 'color',
						'label'   => __( 'Popout border color', 'rsm-content-widgets' ),
						'default' => '#e2e8f0',
					),
					'popout_border_width' => array(
						'type'    => 'slider',
						'label'   => __( 'Popout border width', 'rsm-content-widgets' ),
						'min'     => 0,
						'max'     => 6,
						'integer' => true,
						'default' => 1,
					),
					'popout_shape' => array(
						'type'    => 'select',
						'label'   => __( 'Popout corner shape', 'rsm-content-widgets' ),
						'default' => 'large',
						'options' => Rsmspark_Content_Widgets_Features_Styles::get_shape_options( false ),
					),
					'popout_title_color' => array(
						'type'    => 'color',
						'label'   => __( 'Popout title color', 'rsm-content-widgets' ),
						'default' => '#0f172a',
					),
					'popout_text_color' => array(
						'type'    => 'color',
						'label'   => __( 'Popout text color', 'rsm-content-widgets' ),
						'default' => '#475569',
					),
					'popout_pad' => array(
						'type'    => 'slider',
						'label'   => __( 'Popout padding', 'rsm-content-widgets' ),
						'min'     => 0,
						'max'     => 48,
						'integer' => true,
						'default' => 28,
					),
					'popout_max_width' => array(
						'type'        => 'slider',
						'label'       => __( 'Popout max width', 'rsm-content-widgets' ),
						'description' => __( 'Maximum modal width in pixels. Use 960+ for month calendars.', 'rsm-content-widgets' ),
						'min'         => 320,
						'max'         => 1280,
						'integer'     => true,
						'default'     => 640,
					),
					'popout_max_height' => array(
						'type'        => 'slider',
						'label'       => __( 'Popout max height', 'rsm-content-widgets' ),
						'description' => __( 'Maximum modal height in pixels (capped at 90% of the viewport).', 'rsm-content-widgets' ),
						'min'         => 400,
						'max'         => 960,
						'integer'     => true,
						'default'     => 720,
					),
					'popout_title_font' => array(
						'type'    => 'select',
						'label'   => __( 'Popout title font', 'rsm-content-widgets' ),
						'default' => 'inherit',
						'options' => Rsmspark_Content_Widgets_Features_Fonts::get_select_options(),
					),
					'popout_title_font_size' => array(
						'type'        => 'slider',
						'label'       => __( 'Popout title font size', 'rsm-content-widgets' ),
						'description' => __( '0 = auto: ~24px max, sized to pair with the header icon at 125% scale. Set a pixel value to override.', 'rsm-content-widgets' ),
						'min'         => 0,
						'max'         => 48,
						'integer'     => true,
						'default'     => 0,
					),
					'popout_header_icon_scale' => array(
						'type'        => 'slider',
						'label'       => __( 'Popout header icon scale', 'rsm-content-widgets' ),
						'description' => __( 'Scales the modal header icon/image relative to the chip or custom popout icon size (100–200%).', 'rsm-content-widgets' ),
						'min'         => 100,
						'max'         => 200,
						'integer'     => true,
						'default'     => 125,
					),
					'popout_header_gap' => array(
						'type'        => 'slider',
						'label'       => __( 'Popout header icon-to-text gap', 'rsm-content-widgets' ),
						'description' => __( 'Horizontal spacing between the header icon/image and the title block.', 'rsm-content-widgets' ),
						'min'         => 0,
						'max'         => 48,
						'integer'     => true,
						'default'     => 12,
					),
					'popout_subtitle_color' => array(
						'type'    => 'color',
						'label'   => __( 'Popout sub-headline color', 'rsm-content-widgets' ),
						'default' => '#64748b',
					),
					'popout_subtitle_font_size' => array(
						'type'        => 'slider',
						'label'       => __( 'Popout sub-headline font size', 'rsm-content-widgets' ),
						'description' => __( '0 = auto: ~14px max tagline below the popout title. Set a pixel value to override.', 'rsm-content-widgets' ),
						'min'         => 0,
						'max'         => 32,
						'integer'     => true,
						'default'     => 0,
					),
					'popout_header_divider' => array(
						'type'        => 'checkbox',
						'label'       => __( 'Show header divider line', 'rsm-content-widgets' ),
						'description' => __( 'Draw a line below the icon/title header and above the popout body.', 'rsm-content-widgets' ),
						'default'     => false,
					),
					'popout_header_divider_color' => array(
						'type'    => 'color',
						'label'   => __( 'Header divider color', 'rsm-content-widgets' ),
						'default' => '#e2e8f0',
					),
					'popout_header_divider_width' => array(
						'type'    => 'slider',
						'label'   => __( 'Header divider thickness', 'rsm-content-widgets' ),
						'min'     => 1,
						'max'     => 8,
						'integer' => true,
						'default' => 1,
					),
					'popout_body_font' => array(
						'type'    => 'select',
						'label'   => __( 'Popout body font', 'rsm-content-widgets' ),
						'default' => 'inherit',
						'options' => Rsmspark_Content_Widgets_Features_Fonts::get_select_options(),
					),
					'popout_body_font_size' => array(
						'type'    => 'slider',
						'label'   => __( 'Popout body font size', 'rsm-content-widgets' ),
						'min'     => 0,
						'max'     => 24,
						'integer' => true,
						'default' => 0,
					),
					'popout_items' => array(
						'type'       => 'repeater',
						'label'      => __( 'Popout content', 'rsm-content-widgets' ),
						'item_name'  => __( 'Popout', 'rsm-content-widgets' ),
						'description' => __( 'One row per hot chip. Rows match chips by order, or set Chip label to the feature title.', 'rsm-content-widgets' ),
						'item_label' => array(
							'selector'     => "[id*='chip_label']",
							'update_event' => 'change',
							'value_method' => 'val',
						),
						'default'    => array(),
						'fields'     => array(
							'chip_label' => array(
								'type'        => 'text',
								'label'       => __( 'Chip label', 'rsm-content-widgets' ),
								'description' => __( 'Optional. Match the feature title when chip order differs.', 'rsm-content-widgets' ),
								'default'     => '',
							),
							'popout_title' => array_merge(
								Rsmspark_Rich_Text_Registry::siteorigin_tinymce_field( Rsmspark_Rich_Text_Registry::PROFILE_HEADLINE, 3 ),
								array(
									'label'       => __( 'Popout title', 'rsm-content-widgets' ),
									'description' => __( 'Optional. Headline profile: size/color tokens. Defaults to the chip title when empty.', 'rsm-content-widgets' ),
									'default'     => '',
								)
							),
							'popout_subtitle' => array_merge(
								Rsmspark_Rich_Text_Registry::siteorigin_tinymce_field( Rsmspark_Rich_Text_Registry::PROFILE_HEADLINE, 2 ),
								array(
									'label'       => __( 'Popout sub-headline', 'rsm-content-widgets' ),
									'description' => __( 'Optional tagline below the popout title in the modal header.', 'rsm-content-widgets' ),
									'default'     => '',
								)
							),
							'popout_media' => array(
								'type'        => 'select',
								'label'       => __( 'Popout icon / image', 'rsm-content-widgets' ),
								'description' => __( 'Inherit uses the feature chip icon or image; choose Custom to override.', 'rsm-content-widgets' ),
								'default'     => 'inherit',
								'options'     => Rsmspark_Content_Widgets_Features_Popouts::get_media_source_options(),
							),
							'popout_icon' => array(
								'type'        => 'icon',
								'label'       => __( 'Popout icon', 'rsm-content-widgets' ),
								'description' => __( 'Used when Popout icon / image is set to Custom.', 'rsm-content-widgets' ),
								'default'     => '',
							),
							'popout_icon_style' => array(
								'type'        => 'select',
								'label'       => __( 'Popout icon style', 'rsm-content-widgets' ),
								'default'     => 'glyph',
								'options'     => Rsmspark_Content_Widgets_Features_Styles::get_icon_style_options(),
							),
							'popout_icon_color' => array(
								'type'    => 'color',
								'label'   => __( 'Popout icon color', 'rsm-content-widgets' ),
								'default' => '',
							),
							'popout_icon_badge_circle_color' => array(
								'type'    => 'color',
								'label'   => __( 'Popout badge circle color', 'rsm-content-widgets' ),
								'default' => '',
							),
							'popout_icon_badge_text_color' => array(
								'type'    => 'color',
								'label'   => __( 'Popout badge number color', 'rsm-content-widgets' ),
								'default' => '#ffffff',
							),
							'popout_icon_badge_glyph' => array(
								'type'        => 'text',
								'label'       => __( 'Popout badge character', 'rsm-content-widgets' ),
								'description' => __( 'Optional number or letter for Number in circle style.', 'rsm-content-widgets' ),
								'default'     => '',
							),
							'popout_image' => array(
								'type'    => 'media',
								'label'   => __( 'Popout icon image', 'rsm-content-widgets' ),
								'choose'  => __( 'Choose image', 'rsm-content-widgets' ),
								'update'  => __( 'Set image', 'rsm-content-widgets' ),
								'library' => 'image',
								'default' => '',
							),
							'popout_icon_size' => array(
								'type'        => 'select',
								'label'       => __( 'Popout icon size', 'rsm-content-widgets' ),
								'description' => __( 'Inherit uses the feature chip icon size unless overridden here.', 'rsm-content-widgets' ),
								'default'     => 'inherit',
								'options'     => Rsmspark_Content_Widgets_Features_Styles::get_icon_size_options( true ),
							),
							'popout_icon_size_custom' => array(
								'type'        => 'slider',
								'label'       => __( 'Popout custom icon size', 'rsm-content-widgets' ),
								'description' => sprintf(
									/* translators: 1: minimum px, 2: maximum px */
									__( 'Used when Popout icon size is Custom (%1$d–%2$dpx).', 'rsm-content-widgets' ),
									Rsmspark_Content_Widgets_Features_Styles::get_icon_size_custom_bounds()['min'],
									Rsmspark_Content_Widgets_Features_Styles::get_icon_size_custom_bounds()['max']
								),
								'min'         => Rsmspark_Content_Widgets_Features_Styles::get_icon_size_custom_bounds()['min'],
								'max'         => Rsmspark_Content_Widgets_Features_Styles::get_icon_size_custom_bounds()['max'],
								'integer'     => true,
								'default'     => Rsmspark_Content_Widgets_Features_Styles::get_icon_size_custom_bounds()['default'],
							),
							'popout_content' => array_merge(
								Rsmspark_Rich_Text_Registry::siteorigin_tinymce_field( Rsmspark_Rich_Text_Registry::PROFILE_BODY, 12 ),
								array(
									'label'          => __( 'Popout content', 'rsm-content-widgets' ),
									'default'        => '',
									'rsm_rt_profile' => Rsmspark_Rich_Text_Registry::PROFILE_BODY,
									'description'    => __( 'Use List, Section title, and size/color tools. Legacy [rf_col] / [rf_list] shortcodes still work for existing content.', 'rsm-content-widgets' ),
								)
							),
						),
					),
				),
			),
		);
	}

	/**
	 * Sanitize rich-text chip fields when SiteOrigin saves the widget instance.
	 *
	 * @param array<string, mixed> $instance Widget instance.
	 * @return array<string, mixed>
	 */
	public function modify_instance( $instance ) {
		if ( ! is_array( $instance ) ) {
			return $instance;
		}

		if ( ! class_exists( 'Rsmspark_Rich_Text_Body', false ) ) {
			return $instance;
		}

		if ( ! empty( $instance['general']['features'] ) && is_array( $instance['general']['features'] ) ) {
			foreach ( $instance['general']['features'] as $index => $feature ) {
				if ( ! is_array( $feature ) ) {
					continue;
				}

				if ( array_key_exists( 'description', $feature ) ) {
					$instance['general']['features'][ $index ]['description'] = Rsmspark_Rich_Text_Body::sanitize( $feature['description'] ?? '' );
				}
			}
		}

		if ( ! empty( $instance['popouts']['popout_items'] ) && is_array( $instance['popouts']['popout_items'] ) ) {
			foreach ( $instance['popouts']['popout_items'] as $index => $item ) {
				if ( ! is_array( $item ) ) {
					continue;
				}

				if ( array_key_exists( 'popout_content', $item ) ) {
					$instance['popouts']['popout_items'][ $index ]['popout_content'] = Rsmspark_Rich_Text_Body::sanitize( $item['popout_content'] ?? '' );
				}

				if ( array_key_exists( 'popout_title', $item ) && class_exists( 'Rsmspark_Content_Widgets_Headline_Styles', false ) ) {
					$instance['popouts']['popout_items'][ $index ]['popout_title'] = Rsmspark_Content_Widgets_Headline_Styles::sanitize_line_html( $item['popout_title'] ?? '' );
				}

				if ( array_key_exists( 'popout_subtitle', $item ) && class_exists( 'Rsmspark_Content_Widgets_Headline_Styles', false ) ) {
					$instance['popouts']['popout_items'][ $index ]['popout_subtitle'] = Rsmspark_Content_Widgets_Headline_Styles::sanitize_line_html( $item['popout_subtitle'] ?? '' );
				}
			}
		}

		return $instance;
	}

	/**
	 * Template variables — delegates to the compat render layer.
	 *
	 * @param array $instance Instance.
	 * @param array $args     Sidebar args.
	 * @return array
	 */
	public function get_template_variables( $instance, $args ) {
		return Rsmspark_Content_Widgets_Widget_Features::prepare_template_vars( $instance, is_array( $args ) ? $args : array() );
	}
}

if ( function_exists( 'siteorigin_widget_register' ) ) {
	siteorigin_widget_register( 'features', __FILE__, 'Rsmspark_Content_Widgets_Features_Widget' );
}
