<?php
/**
 * Storzen Modules — Registry & Manager
 *
 * Defines all available FREE and PRO modules.
 * Handles toggle-based enable/disable from admin panel.
 * Loads each module's class file only when enabled.
 *
 * @package storzen
 * @since   1.1.0
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! class_exists( 'Storzen_Modules' ) ) {

	class Storzen_Modules {

		/** @var static */
		private static $instance = null;

		/** @var string Option key for module states */
		const OPTION_KEY = 'storzen_modules_settings';

		/**
		 * All available modules definition.
		 * 
		 * Structure:
		 *   'module_key' => [
		 *       'label'       => string  — Display name in admin
		 *       'description' => string  — Tooltip / info text
		 *       'pro'         => bool    — PRO only?
		 *       'default'     => bool    — Enabled by default?
		 *       'class_file'  => string  — Relative path from STORZEN_INC
		 *       'class_name'  => string  — PHP class to instantiate after load
		 *       'has_settings'=> bool    — Shows gear icon with sub-settings?
		 *       'settings'    => array   — Sub-settings fields (key => [type, label, default, options])
		 *   ]
		 *
		 * @return array
		 */
		public static function get_module_definitions() {
			return array(

				// ── FREE MODULES ────────────────────────────────────────────

				'variation_swatches' => array(
					'label'        => __( 'Variation Swatches', 'storzen' ),
					'description'  => __( 'Show color, image, or button swatches for product variations instead of plain dropdowns — proven to lift conversion on variable products.', 'storzen' ),
					'pro'          => false,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-variation-swatches.php',
					'class_name'   => 'Storzen_Module_Variation_Swatches',
					'has_settings' => true,
					'tabs'         => array(
						'general'  => __( 'General', 'storzen' ),
						'display'  => __( 'Display', 'storzen' ),
						'behavior' => __( 'Behavior', 'storzen' ),
						'pro'      => array(
							'label' => __( 'Pro ✦', 'storzen' ),
							'pro'   => true,
						),
					),
					'settings'     => array(

						// ── General ────────────────────────────────────────
						'swatch_type' => array(
							'type'        => 'select',
							'tab'         => 'general',
							'label'       => __( 'Default Swatch Type', 'storzen' ),
							'description' => __( 'Used for attributes that don\'t have a swatch defined at the attribute level.', 'storzen' ),
							'default'     => 'color',
							'options'     => array(
								'auto'   => __( 'Auto (use attribute setting)', 'storzen' ),
								'color'  => __( 'Color Swatch', 'storzen' ),
								'image'  => __( 'Image Swatch', 'storzen' ),
								'button' => __( 'Button / Label', 'storzen' ),
							),
						),
						'show_on' => array(
							'type'        => 'multi_select',
							'tab'         => 'general',
							'label'       => __( 'Show Swatches On', 'storzen' ),
							'description' => __( 'Pick the locations where swatches should replace dropdowns.', 'storzen' ),
							'default'     => array( 'single', 'shop' ),
							'options'     => array(
								'single'     => __( 'Single Product Page', 'storzen' ),
								'shop'       => __( 'Shop / Category Pages', 'storzen' ),
								'quick_view' => __( 'Quick View Modal', 'storzen' ),
								'cart'       => __( 'Cart / Mini Cart', 'storzen' ),
							),
						),
						'show_label' => array(
							'type'        => 'toggle',
							'tab'         => 'general',
							'label'       => __( 'Show Selected Value Label', 'storzen' ),
							'description' => __( 'Displays text like "Color: Red" next to the swatches.', 'storzen' ),
							'default'     => true,
						),
						'attribute_image_size' => array(
							'type'    => 'select',
							'tab'     => 'general',
							'label'   => __( 'Variation Image Size', 'storzen' ),
							'default' => 'thumbnail',
							'options' => array(
								'thumbnail'    => __( 'Thumbnail (150×150)', 'storzen' ),
								'medium'       => __( 'Medium (300×300)', 'storzen' ),
								'woocommerce_thumbnail' => __( 'WooCommerce Thumbnail', 'storzen' ),
							),
						),

						// ── Display ────────────────────────────────────────
						'swatch_size' => array(
							'type'        => 'number',
							'tab'         => 'display',
							'label'       => __( 'Swatch Size (px)', 'storzen' ),
							'description' => __( 'Width and height of color/image swatches.', 'storzen' ),
							'default'     => 28,
							'min'         => 16,
							'max'         => 80,
						),
						'shape' => array(
							'type'    => 'select',
							'tab'     => 'display',
							'label'   => __( 'Swatch Shape', 'storzen' ),
							'default' => 'rounded',
							'options' => array(
								'square'  => __( 'Square', 'storzen' ),
								'rounded' => __( 'Rounded Square', 'storzen' ),
								'circle'  => __( 'Circle', 'storzen' ),
							),
						),
						'spacing' => array(
							'type'        => 'number',
							'tab'         => 'display',
							'label'       => __( 'Spacing Between Swatches (px)', 'storzen' ),
							'default'     => 6,
							'min'         => 0,
							'max'         => 30,
						),
						'selected_style' => array(
							'type'    => 'select',
							'tab'     => 'display',
							'label'   => __( 'Selected Indicator Style', 'storzen' ),
							'default' => 'border',
							'options' => array(
								'border'    => __( 'Outline Border', 'storzen' ),
								'checkmark' => __( 'Checkmark Overlay', 'storzen' ),
								'shadow'    => __( 'Soft Shadow Glow', 'storzen' ),
								'border_check' => __( 'Border + Checkmark', 'storzen' ),
							),
						),
						'accent_color' => array(
							'type'        => 'color',
							'tab'         => 'display',
							'label'       => __( 'Selected / Hover Color', 'storzen' ),
							'description' => __( 'Used for the border, checkmark, and hover state.', 'storzen' ),
							'default'     => '#FF3636',
						),
						'show_tooltip' => array(
							'type'    => 'toggle',
							'tab'     => 'display',
							'label'   => __( 'Show Tooltip on Hover', 'storzen' ),
							'default' => true,
						),
						'tooltip_position' => array(
							'type'    => 'select',
							'tab'     => 'display',
							'label'   => __( 'Tooltip Position', 'storzen' ),
							'default' => 'top',
							'options' => array(
								'top'    => __( 'Above Swatch', 'storzen' ),
								'bottom' => __( 'Below Swatch', 'storzen' ),
							),
						),

						// ── Behavior ───────────────────────────────────────
						'out_of_stock_style' => array(
							'type'        => 'select',
							'tab'         => 'behavior',
							'label'       => __( 'Out-of-Stock Variations', 'storzen' ),
							'description' => __( 'How to handle swatches whose variation is sold out.', 'storzen' ),
							'default'     => 'crossed',
							'options'     => array(
								'crossed' => __( 'Show with Diagonal Strike-Through', 'storzen' ),
								'faded'   => __( 'Fade to 40% Opacity', 'storzen' ),
								'hide'    => __( 'Hide Completely', 'storzen' ),
								'none'    => __( 'No Visual Change', 'storzen' ),
							),
						),
						'auto_select_first' => array(
							'type'        => 'toggle',
							'tab'         => 'behavior',
							'label'       => __( 'Auto-Select First Available Variation', 'storzen' ),
							'description' => __( 'Customers see a price and add-to-cart immediately instead of having to click swatches first.', 'storzen' ),
							'default'     => true,
						),
						'update_main_image' => array(
							'type'        => 'toggle',
							'tab'         => 'behavior',
							'label'       => __( 'Update Main Product Image on Click', 'storzen' ),
							'description' => __( 'When a swatch is clicked on shop cards, the card image switches to that variation.', 'storzen' ),
							'default'     => true,
						),
						'show_price_change' => array(
							'type'        => 'toggle',
							'tab'         => 'behavior',
							'label'       => __( 'Animate Price on Variation Change', 'storzen' ),
							'description' => __( 'Fades the price when a different variation is selected.', 'storzen' ),
							'default'     => true,
						),

						// ── Pro ───────────────────────────────────────────
						'pro_variation_gallery' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Show Variation Gallery on Swatch Click', 'storzen' ),
							'description' => __( 'Cycles the entire product gallery to images tagged for the selected variation — not just the featured image.', 'storzen' ),
							'default'     => false,
						),
						'pro_animation' => array(
							'type'    => 'select',
							'tab'     => 'pro',
							'label'   => __( 'Variation Change Animation', 'storzen' ),
							'default' => 'fade',
							'options' => array(
								'none' => __( 'None (instant)', 'storzen' ),
								'fade' => __( 'Fade', 'storzen' ),
								'slide' => __( 'Slide', 'storzen' ),
								'zoom' => __( 'Zoom', 'storzen' ),
							),
						),
						'pro_bulk_manager' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Enable Bulk Attribute Manager', 'storzen' ),
							'description' => __( 'Adds a dedicated screen to set color codes / images for every attribute term at once.', 'storzen' ),
							'default'     => false,
						),
						'pro_custom_shapes' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Allow Custom SVG Shapes', 'storzen' ),
							'description' => __( 'Lets you set a custom shape per attribute term using inline SVG (great for fabric swatches, rings, etc).', 'storzen' ),
							'default'     => false,
						),
						'pro_custom_css' => array(
							'type'        => 'textarea',
							'tab'         => 'pro',
							'label'       => __( 'Custom Swatch CSS', 'storzen' ),
							'description' => __( 'Advanced styling overrides applied only to swatch elements.', 'storzen' ),
							'default'     => '',
						),
					),
				),

				'sale_notification' => array(
					'label'        => __( 'Sale Notification', 'storzen' ),
					'description'  => __( 'Show live purchase popups (social proof) using real WooCommerce orders or virtual data.', 'storzen' ),
					'pro'          => false,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-sale-notification.php',
					'class_name'   => 'Storzen_Module_Sale_Notification',
					'has_settings' => true,
					'tabs'         => array(
						'general' => __( 'General', 'storzen' ),
						'timing'  => __( 'Timing', 'storzen' ),
						'display' => __( 'Display', 'storzen' ),
						'pro'     => array(
							'label' => __( 'Pro ✦', 'storzen' ),
							'pro'   => true,
						),
					),
					'settings'     => array(

						'message' => array(
							'type'        => 'text',
							'tab'         => 'general',
							'label'       => __( 'Notification Message', 'storzen' ),
							'description' => __( 'Placeholders: {name}, {city}, {country}, {product}, {time}', 'storzen' ),
							'default'     => '{name} from {city} purchased {product}',
						),

						'position' => array(
							'type'    => 'select',
							'tab'     => 'general',
							'label'   => __( 'Notification Position', 'storzen' ),
							'default' => 'bottom-left',
							'options' => array(
								'bottom-left'  => __( 'Bottom Left', 'storzen' ),
								'bottom-right' => __( 'Bottom Right', 'storzen' ),
								'top-left'     => __( 'Top Left', 'storzen' ),
								'top-right'    => __( 'Top Right', 'storzen' ),
							),
						),

						'data_source' => array(
							'type'        => 'select',
							'tab'         => 'general',
							'label'       => __( 'Data Source', 'storzen' ),
							'description' => __( 'Virtual mode is GDPR-safe — no real customer data is shown.', 'storzen' ),
							'default'     => 'real',
							'options'     => array(
								'real'    => __( 'Real Orders Only', 'storzen' ),
								'virtual' => __( 'Virtual (Generated)', 'storzen' ),
								'mixed'   => __( 'Mixed (Real + Virtual)', 'storzen' ),
							),
						),

						'lookback_days' => array(
							'type'        => 'number',
							'tab'         => 'general',
							'label'       => __( 'Lookback Period (days)', 'storzen' ),
							'description' => __( 'How far back to pull real orders from.', 'storzen' ),
							'default'     => 30,
							'min'         => 1,
							'max'         => 365,
						),

						'max_notifications' => array(
							'type'    => 'number',
							'tab'     => 'general',
							'label'   => __( 'Max Notifications per Visit', 'storzen' ),
							'default' => 10,
							'min'     => 1,
							'max'     => 50,
						),

						'first_delay' => array(
							'type'    => 'number',
							'tab'     => 'timing',
							'label'   => __( 'First Show Delay (seconds)', 'storzen' ),
							'default' => 5,
							'min'     => 0,
							'max'     => 120,
						),

						'display_duration' => array(
							'type'    => 'number',
							'tab'     => 'timing',
							'label'   => __( 'Display Duration (seconds)', 'storzen' ),
							'default' => 6,
							'min'     => 2,
							'max'     => 60,
						),

						'between_delay' => array(
							'type'    => 'number',
							'tab'     => 'timing',
							'label'   => __( 'Gap Between Notifications (seconds)', 'storzen' ),
							'default' => 8,
							'min'     => 2,
							'max'     => 120,
						),

						'animation' => array(
							'type'    => 'select',
							'tab'     => 'display',
							'label'   => __( 'Animation Style', 'storzen' ),
							'default' => 'slide-up',
							'options' => array(
								'slide-up'   => __( 'Slide Up', 'storzen' ),
								'slide-side' => __( 'Slide From Side', 'storzen' ),
								'fade'       => __( 'Fade In', 'storzen' ),
							),
						),

						'show_avatar' => array(
							'type'    => 'toggle',
							'tab'     => 'display',
							'label'   => __( 'Show Product Image', 'storzen' ),
							'default' => true,
						),

						'show_time' => array(
							'type'    => 'toggle',
							'tab'     => 'display',
							'label'   => __( 'Show Relative Time', 'storzen' ),
							'default' => true,
						),

						'show_close' => array(
							'type'    => 'toggle',
							'tab'     => 'display',
							'label'   => __( 'Show Close Button', 'storzen' ),
							'default' => true,
						),

						// ── Pro ───────────────────────────────────────────
						'pro_ab_test_messages' => array(
							'type'        => 'textarea',
							'tab'         => 'pro',
							'label'       => __( 'A/B Test Messages', 'storzen' ),
							'description' => __( 'One message per line. Storzen rotates them randomly to find the highest-converting copy.', 'storzen' ),
							'default'     => '',
						),
						'pro_targeting' => array(
							'type'    => 'select',
							'tab'     => 'pro',
							'label'   => __( 'Display Targeting', 'storzen' ),
							'default' => 'all',
							'options' => array(
								'all'             => __( 'All pages', 'storzen' ),
								'shop_only'       => __( 'Shop &amp; category pages only', 'storzen' ),
								'single_product'  => __( 'Single product pages only', 'storzen' ),
								'cart_checkout'   => __( 'Cart &amp; checkout only', 'storzen' ),
								'home_only'       => __( 'Homepage only', 'storzen' ),
							),
						),
						'pro_device' => array(
							'type'    => 'select',
							'tab'     => 'pro',
							'label'   => __( 'Show on Devices', 'storzen' ),
							'default' => 'both',
							'options' => array(
								'both'    => __( 'Desktop &amp; Mobile', 'storzen' ),
								'desktop' => __( 'Desktop Only', 'storzen' ),
								'mobile'  => __( 'Mobile Only', 'storzen' ),
							),
						),
						'pro_schedule_hours' => array(
							'type'        => 'text',
							'tab'         => 'pro',
							'label'       => __( 'Active Hours (24h)', 'storzen' ),
							'description' => __( 'Only show during these hours. Format: 09-22 means 9am to 10pm. Leave empty for always-on.', 'storzen' ),
							'default'     => '',
						),
						'pro_exclude_categories' => array(
							'type'        => 'text',
							'tab'         => 'pro',
							'label'       => __( 'Excluded Product IDs', 'storzen' ),
							'description' => __( 'Comma-separated product IDs to never appear in popups (e.g. test products).', 'storzen' ),
							'default'     => '',
						),
						'pro_custom_css' => array(
							'type'        => 'textarea',
							'tab'         => 'pro',
							'label'       => __( 'Custom Popup CSS', 'storzen' ),
							'description' => __( 'Advanced styling overrides for the notification popup.', 'storzen' ),
							'default'     => '',
						),
					),
				),

				'quick_view' => array(
					'label'        => __( 'Quick View', 'storzen' ),
					'description'  => __( 'Open a product modal with gallery, variations, and AJAX add to cart — without leaving the shop page.', 'storzen' ),
					'pro'          => false,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-quick-view.php',
					'class_name'   => 'Storzen_Module_Quick_View',
					'has_settings' => true,
					'tabs'         => array(
						'general' => __( 'General', 'storzen' ),
						'content' => __( 'Modal Content', 'storzen' ),
						'pro'     => array(
							'label' => __( 'Pro ✦', 'storzen' ),
							'pro'   => true,
						),
					),
					'settings'     => array(

						'btn_text' => array(
							'type'    => 'text',
							'tab'     => 'general',
							'label'   => __( 'Button Label', 'storzen' ),
							'default' => 'Quick View',
						),

						'button_position' => array(
							'type'    => 'select',
							'tab'     => 'general',
							'label'   => __( 'Button Position', 'storzen' ),
							'default' => 'on-image',
							'options' => array(
								'on-image'    => __( 'Overlay on Product Image (Recommended)', 'storzen' ),
								'after-title' => __( 'Below Product Title', 'storzen' ),
								'after-item'  => __( 'After Add to Cart', 'storzen' ),
							),
						),

						'icon' => array(
							'type'    => 'select',
							'tab'     => 'general',
							'label'   => __( 'Button Icon', 'storzen' ),
							'default' => 'eye',
							'options' => array(
								'eye'    => __( 'Eye', 'storzen' ),
								'search' => __( 'Magnifier', 'storzen' ),
								'plus'   => __( 'Plus', 'storzen' ),
								'none'   => __( 'No Icon', 'storzen' ),
							),
						),

						'ajax_add_to_cart' => array(
							'type'        => 'toggle',
							'tab'         => 'general',
							'label'       => __( 'AJAX Add to Cart in Modal', 'storzen' ),
							'description' => __( 'Stay in modal after adding to cart.', 'storzen' ),
							'default'     => true,
						),

						'show_gallery' => array(
							'type'    => 'toggle',
							'tab'     => 'content',
							'label'   => __( 'Show Image Gallery', 'storzen' ),
							'default' => true,
						),

						'show_sku' => array(
							'type'    => 'toggle',
							'tab'     => 'content',
							'label'   => __( 'Show SKU', 'storzen' ),
							'default' => false,
						),

						'show_categories' => array(
							'type'    => 'toggle',
							'tab'     => 'content',
							'label'   => __( 'Show Categories', 'storzen' ),
							'default' => true,
						),

						'show_tags' => array(
							'type'    => 'toggle',
							'tab'     => 'content',
							'label'   => __( 'Show Tags', 'storzen' ),
							'default' => false,
						),

						// ── Pro ───────────────────────────────────────────
						'pro_modal_template' => array(
							'type'        => 'select',
							'tab'         => 'pro',
							'label'       => __( 'Modal Template', 'storzen' ),
							'description' => __( 'Pick a layout style for the Quick View modal.', 'storzen' ),
							'default'     => 'classic',
							'options'     => array(
								'classic'   => __( 'Classic (image left, info right)', 'storzen' ),
								'spotlight' => __( 'Spotlight (large image, info below)', 'storzen' ),
								'compact'   => __( 'Compact (small modal, key info only)', 'storzen' ),
								'story'     => __( 'Story (full-screen vertical, mobile-first)', 'storzen' ),
							),
						),
						'pro_image_zoom' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Enable Image Zoom on Hover', 'storzen' ),
							'description' => __( 'Magnifies the product image when the customer hovers over it inside the modal.', 'storzen' ),
							'default'     => true,
						),
						'pro_modal_width' => array(
							'type'        => 'number',
							'tab'         => 'pro',
							'label'       => __( 'Custom Modal Width (px)', 'storzen' ),
							'description' => __( 'Set to 0 to use the default template width.', 'storzen' ),
							'default'     => 0,
							'min'         => 0,
							'max'         => 1600,
						),
						'pro_show_related' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Show Related Products Inside Modal', 'storzen' ),
							'description' => __( 'Adds a "You might also like" carousel at the bottom of the modal — strong cross-sell driver.', 'storzen' ),
							'default'     => false,
						),
						'pro_show_stock_bar' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Show Stock Progress Bar', 'storzen' ),
							'description' => __( 'Displays "Only X left!" as a visual progress bar — creates urgency.', 'storzen' ),
							'default'     => false,
						),
						'pro_countdown_badge' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Show Sale Countdown Badge', 'storzen' ),
							'description' => __( 'Reuses the Flash Countdown timer for products on sale (requires Flash Countdown enabled).', 'storzen' ),
							'default'     => false,
						),
						'pro_custom_css' => array(
							'type'        => 'textarea',
							'tab'         => 'pro',
							'label'       => __( 'Custom Modal CSS', 'storzen' ),
							'description' => __( 'Advanced styling overrides for the Quick View modal.', 'storzen' ),
							'default'     => '',
						),
					),
				),

				'sale_badge' => array(
					'label'        => __( 'Sale Badge', 'storzen' ),
					'description'  => __( 'Automatically show Hot, New, and Sale % badges on product cards.', 'storzen' ),
					'pro'          => false,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-sale-badge.php',
					'class_name'   => 'Storzen_Module_Sale_Badge',
					'has_settings' => true,
					'tabs'         => array(
						'general' => __( 'General', 'storzen' ),
						'display' => __( 'Display', 'storzen' ),
						'pro'     => array(
							'label' => __( 'Pro ✦', 'storzen' ),
							'pro'   => true,
						),
					),
					'settings'     => array(
						'show_discount_pct' => array(
							'type'    => 'toggle',
							'tab'     => 'general',
							'label'   => __( 'Show Discount %', 'storzen' ),
							'default' => true,
						),
						'new_badge_days' => array(
							'type'    => 'number',
							'tab'     => 'general',
							'label'   => __( '"New" Badge Window (days)', 'storzen' ),
							'description' => __( 'Show "New" badge for products added within this many days.', 'storzen' ),
							'default' => 30,
							'min'     => 1,
							'max'     => 365,
						),
						'badge_style' => array(
							'type'    => 'select',
							'tab'     => 'display',
							'label'   => __( 'Badge Style', 'storzen' ),
							'default' => 'rounded',
							'options' => array(
								'rounded' => __( 'Rounded', 'storzen' ),
								'square'  => __( 'Square', 'storzen' ),
								'ribbon'  => __( 'Ribbon', 'storzen' ),
							),
						),

						// ── Pro ───────────────────────────────────────────
						'pro_custom_text' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Per-Product Custom Badge Text', 'storzen' ),
							'description' => __( 'Adds a "Custom badge" field to every product so you can set unique labels like "Editor\'s Pick" or "Bestseller".', 'storzen' ),
							'default'     => false,
						),
						'pro_multiple_badges' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Allow Multiple Badges Per Product', 'storzen' ),
							'description' => __( 'Stacks Sale + New + Hot on the same product instead of showing only the highest-priority one.', 'storzen' ),
							'default'     => false,
						),
						'pro_animation' => array(
							'type'    => 'select',
							'tab'     => 'pro',
							'label'   => __( 'Badge Animation', 'storzen' ),
							'default' => 'none',
							'options' => array(
								'none'  => __( 'No animation', 'storzen' ),
								'pulse' => __( 'Pulse (subtle)', 'storzen' ),
								'flash' => __( 'Flash (attention-grab)', 'storzen' ),
								'shake' => __( 'Shake (urgency)', 'storzen' ),
							),
						),
						'pro_bg_color' => array(
							'type'    => 'color',
							'tab'     => 'pro',
							'label'   => __( 'Sale Badge Background', 'storzen' ),
							'default' => '#ef4444',
						),
						'pro_text_color' => array(
							'type'    => 'color',
							'tab'     => 'pro',
							'label'   => __( 'Sale Badge Text Color', 'storzen' ),
							'default' => '#ffffff',
						),
						'pro_country_targeting' => array(
							'type'        => 'text',
							'tab'         => 'pro',
							'label'       => __( 'Show Only in Countries', 'storzen' ),
							'description' => __( 'Comma-separated ISO codes (e.g. US,GB,CA). Empty = show everywhere. Uses WooCommerce GeoIP.', 'storzen' ),
							'default'     => '',
						),
					),
				),

				'wishlist' => array(
					'label'        => __( 'Wishlist', 'storzen' ),
					'description'  => __( 'Let customers save products to a wishlist without registration.', 'storzen' ),
					'pro'          => false,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-wishlist.php',
					'class_name'   => 'Storzen_Module_Wishlist',
					'has_settings' => true,
					'tabs'         => array(
						'general' => __( 'General', 'storzen' ),
						'pro'     => array(
							'label' => __( 'Pro ✦', 'storzen' ),
							'pro'   => true,
						),
					),
					'settings'     => array(
						'guest_storage' => array(
							'type'    => 'select',
							'tab'     => 'general',
							'label'   => __( 'Guest User Storage', 'storzen' ),
							'default' => 'cookie',
							'options' => array(
								'cookie'  => __( 'Cookie', 'storzen' ),
								'session' => __( 'Session', 'storzen' ),
							),
						),
						'wishlist_page' => array(
							'type'    => 'page_select',
							'tab'     => 'general',
							'label'   => __( 'Wishlist Page', 'storzen' ),
							'default' => 0,
						),

						// ── Pro ───────────────────────────────────────────
						'pro_price_drop_email' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Send Price Drop Email Alerts', 'storzen' ),
							'description' => __( 'Notify customers when a wishlisted product goes on sale — strong re-engagement trigger.', 'storzen' ),
							'default'     => false,
						),
						'pro_back_in_stock' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Send Back-In-Stock Alerts', 'storzen' ),
							'description' => __( 'Notify customers when an out-of-stock wishlisted product is restocked.', 'storzen' ),
							'default'     => false,
						),
						'pro_shareable_link' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Generate Shareable Wishlist Link', 'storzen' ),
							'description' => __( 'Adds a unique URL customers can share. Great for gift wishlists and social referrals.', 'storzen' ),
							'default'     => false,
						),
						'pro_multiple_lists' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Allow Multiple Wishlists Per User', 'storzen' ),
							'description' => __( 'Logged-in customers can create named lists ("Birthday", "Office"). Guests still get one.', 'storzen' ),
							'default'     => false,
						),
						'pro_analytics' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Track Wishlist Analytics', 'storzen' ),
							'description' => __( 'Adds a dashboard widget showing the most-wishlisted products — invaluable for buying decisions.', 'storzen' ),
							'default'     => false,
						),
						'pro_reminder_days' => array(
							'type'        => 'number',
							'tab'         => 'pro',
							'label'       => __( 'Idle Reminder Email (days)', 'storzen' ),
							'description' => __( 'Email customers about wishlisted items they haven\'t bought yet after this many days. 0 = disabled.', 'storzen' ),
							'default'     => 0,
							'min'         => 0,
							'max'         => 90,
						),
					),
				),

				'compare' => array(
					'label'        => __( 'Compare Products', 'storzen' ),
					'description'  => __( 'Let customers add products to a side-by-side comparison table — perfect for stores with technical specs or feature-rich products.', 'storzen' ),
					'pro'          => false,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-compare.php',
					'class_name'   => 'Storzen_Module_Compare',
					'has_settings' => true,
					'tabs'         => array(
						'general'    => __( 'General', 'storzen' ),
						'fields'     => __( 'Fields', 'storzen' ),
						'display'    => __( 'Display', 'storzen' ),
						'pro'        => array(
							'label' => __( 'Pro ✦', 'storzen' ),
							'pro'   => true,
						),
					),
					'settings'     => array(

						// ── General ────────────────────────────────────────
						'max_products' => array(
							'type'        => 'number',
							'tab'         => 'general',
							'label'       => __( 'Max Products to Compare', 'storzen' ),
							'description' => __( 'How many products can be added before the oldest is bumped out. 3–4 works best on mobile.', 'storzen' ),
							'default'     => 4,
							'min'         => 2,
							'max'         => 6,
						),
						'button_label' => array(
							'type'    => 'text',
							'tab'     => 'general',
							'label'   => __( 'Add Button Label', 'storzen' ),
							'default' => 'Compare',
						),
						'added_label' => array(
							'type'        => 'text',
							'tab'         => 'general',
							'label'       => __( 'Already-Added Label', 'storzen' ),
							'description' => __( 'Shown when a product is already in the compare list.', 'storzen' ),
							'default'     => '✓ Added',
						),
						'button_position' => array(
							'type'        => 'select',
							'tab'         => 'general',
							'label'       => __( 'Button Placement', 'storzen' ),
							'description' => __( 'Where the Compare button appears on product cards and single pages.', 'storzen' ),
							'default'     => 'after_add_to_cart',
							'options'     => array(
								'after_add_to_cart' => __( 'After Add to Cart', 'storzen' ),
								'after_title'       => __( 'After Product Title', 'storzen' ),
								'on_image'          => __( 'Overlay on Product Image', 'storzen' ),
								'shortcode_only'    => __( 'Shortcode Only (manual placement)', 'storzen' ),
							),
						),
						'icon_style' => array(
							'type'    => 'select',
							'tab'     => 'general',
							'label'   => __( 'Button Icon', 'storzen' ),
							'default' => 'arrows',
							'options' => array(
								'arrows'  => __( 'Arrows ⇄', 'storzen' ),
								'balance' => __( 'Balance Scale ⚖', 'storzen' ),
								'list'    => __( 'List Icon', 'storzen' ),
								'none'    => __( 'No Icon', 'storzen' ),
							),
						),
						'compare_page' => array(
							'type'        => 'page_select',
							'tab'         => 'general',
							'label'       => __( 'Compare Page', 'storzen' ),
							'description' => __( 'Page containing the [storzen_compare] shortcode. Leave empty to use a modal popup only.', 'storzen' ),
							'default'     => 0,
						),

						// ── Fields ─────────────────────────────────────────
						'fields_to_compare' => array(
							'type'        => 'multi_select',
							'tab'         => 'fields',
							'label'       => __( 'Rows to Show in Comparison Table', 'storzen' ),
							'description' => __( 'Pick the data points customers will compare across products.', 'storzen' ),
							'default'     => array( 'image', 'price', 'rating', 'short_desc', 'add_to_cart' ),
							'options'     => array(
								'image'       => __( 'Product Image', 'storzen' ),
								'price'       => __( 'Price', 'storzen' ),
								'rating'      => __( 'Star Rating', 'storzen' ),
								'sku'         => __( 'SKU', 'storzen' ),
								'stock'       => __( 'Stock Status', 'storzen' ),
								'short_desc'  => __( 'Short Description', 'storzen' ),
								'categories'  => __( 'Categories', 'storzen' ),
								'tags'        => __( 'Tags', 'storzen' ),
								'attributes'  => __( 'Product Attributes', 'storzen' ),
								'weight'      => __( 'Weight', 'storzen' ),
								'dimensions'  => __( 'Dimensions', 'storzen' ),
								'add_to_cart' => __( 'Add to Cart Button', 'storzen' ),
							),
						),
						'highlight_diffs' => array(
							'type'        => 'toggle',
							'tab'         => 'fields',
							'label'       => __( 'Highlight Differences', 'storzen' ),
							'description' => __( 'Subtly tints rows where products differ — makes it obvious at a glance.', 'storzen' ),
							'default'     => true,
						),
						'hide_identical_rows' => array(
							'type'        => 'toggle',
							'tab'         => 'fields',
							'label'       => __( 'Hide Rows Where All Values Match', 'storzen' ),
							'description' => __( 'Keeps the table focused on the differences only.', 'storzen' ),
							'default'     => false,
						),

						// ── Display ────────────────────────────────────────
						'layout' => array(
							'type'    => 'select',
							'tab'     => 'display',
							'label'   => __( 'Comparison Layout', 'storzen' ),
							'default' => 'table',
							'options' => array(
								'table' => __( 'Classic Table (rows = fields)', 'storzen' ),
								'cards' => __( 'Side-by-Side Cards', 'storzen' ),
							),
						),
						'sticky_bar' => array(
							'type'        => 'toggle',
							'tab'         => 'display',
							'label'       => __( 'Show Sticky Compare Bar', 'storzen' ),
							'description' => __( 'A floating bar at the bottom showing added products with a "Compare Now" button.', 'storzen' ),
							'default'     => true,
						),
						'sticky_bar_position' => array(
							'type'    => 'select',
							'tab'     => 'display',
							'label'   => __( 'Sticky Bar Position', 'storzen' ),
							'default' => 'bottom',
							'options' => array(
								'bottom' => __( 'Bottom of Page', 'storzen' ),
								'top'    => __( 'Top of Page', 'storzen' ),
							),
						),
						'open_in' => array(
							'type'    => 'select',
							'tab'     => 'display',
							'label'   => __( 'Open Comparison In', 'storzen' ),
							'default' => 'modal',
							'options' => array(
								'modal' => __( 'Modal Popup', 'storzen' ),
								'page'  => __( 'Dedicated Compare Page', 'storzen' ),
							),
						),
						'accent_color' => array(
							'type'        => 'color',
							'tab'         => 'display',
							'label'       => __( 'Accent Color', 'storzen' ),
							'description' => __( 'Used for the button, sticky bar, and row highlights.', 'storzen' ),
							'default'     => '#FF3636',
						),

						// ── Pro ───────────────────────────────────────────
						'pro_shareable_url' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Generate Shareable Compare URLs', 'storzen' ),
							'description' => __( 'Each comparison gets a unique URL customers can bookmark or share — drives back-traffic from buyers researching options.', 'storzen' ),
							'default'     => false,
						),
						'pro_pdf_export' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Export Comparison as PDF', 'storzen' ),
							'description' => __( 'Adds a download button to save the comparison table as a branded PDF.', 'storzen' ),
							'default'     => false,
						),
						'pro_print_view' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Print-Optimized View', 'storzen' ),
							'description' => __( 'Adds a print-friendly stylesheet so the table prints cleanly without page furniture.', 'storzen' ),
							'default'     => false,
						),
						'pro_show_competitors' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Allow Competitor Comparison Rows', 'storzen' ),
							'description' => __( 'Adds custom columns where you can hand-fill competitor product data (great for "Us vs Them" pages).', 'storzen' ),
							'default'     => false,
						),
						'pro_pre_filled_compare' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Pre-Filled Comparison Pages', 'storzen' ),
							'description' => __( 'Create custom URLs like /compare/iphone-vs-pixel/ for SEO landing pages.', 'storzen' ),
							'default'     => false,
						),
					),
				),

				'sticky_atc' => array(
					'label'        => __( 'Sticky Add to Cart', 'storzen' ),
					'description'  => __( 'Floating product bar with Add to Cart + Buy Now that follows the customer as they scroll the product page.', 'storzen' ),
					'pro'          => false,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-sticky-atc.php',
					'class_name'   => 'Storzen_Module_Sticky_Atc',
					'has_settings' => true,
					'tabs'         => array(
						'general'  => __( 'General', 'storzen' ),
						'elements' => __( 'Bar Elements', 'storzen' ),
						'devices'  => __( 'Devices', 'storzen' ),
						'pro'      => array(
							'label' => __( 'Pro ✦', 'storzen' ),
							'pro'   => true,
						),
					),
					'settings'     => array(

						'position' => array(
							'type'        => 'select',
							'tab'         => 'general',
							'label'       => __( 'Bar Position', 'storzen' ),
							'description' => __( 'Bottom converts best on mobile; top works well on desktop.', 'storzen' ),
							'default'     => 'bottom',
							'options'     => array(
								'bottom' => __( 'Bottom of Screen', 'storzen' ),
								'top'    => __( 'Top of Screen', 'storzen' ),
							),
						),

						'animation' => array(
							'type'    => 'select',
							'tab'     => 'general',
							'label'   => __( 'Reveal Animation', 'storzen' ),
							'default' => 'slide',
							'options' => array(
								'slide' => __( 'Slide', 'storzen' ),
								'fade'  => __( 'Fade', 'storzen' ),
							),
						),

						'trigger_offset' => array(
							'type'        => 'number',
							'tab'         => 'general',
							'label'       => __( 'Show After Scrolling (px)', 'storzen' ),
							'description' => __( 'Bar appears once the customer scrolls past this many pixels.', 'storzen' ),
							'default'     => 500,
							'min'         => 100,
							'max'         => 3000,
						),

						'button_text' => array(
							'type'    => 'text',
							'tab'     => 'general',
							'label'   => __( 'Add to Cart Button Label', 'storzen' ),
							'default' => 'Add to Cart',
						),

						'buy_now_text' => array(
							'type'    => 'text',
							'tab'     => 'general',
							'label'   => __( 'Buy Now Button Label', 'storzen' ),
							'default' => 'Buy Now',
						),

						'show_buy_now' => array(
							'type'    => 'toggle',
							'tab'     => 'elements',
							'label'   => __( 'Show Buy Now Button', 'storzen' ),
							'default' => true,
						),

						'show_thumbnail' => array(
							'type'    => 'toggle',
							'tab'     => 'elements',
							'label'   => __( 'Show Product Thumbnail', 'storzen' ),
							'default' => true,
						),

						'show_title' => array(
							'type'    => 'toggle',
							'tab'     => 'elements',
							'label'   => __( 'Show Product Title', 'storzen' ),
							'default' => true,
						),

						'show_price' => array(
							'type'    => 'toggle',
							'tab'     => 'elements',
							'label'   => __( 'Show Product Price', 'storzen' ),
							'default' => true,
						),

						'show_quantity' => array(
							'type'    => 'toggle',
							'tab'     => 'elements',
							'label'   => __( 'Show Quantity Selector', 'storzen' ),
							'default' => true,
						),

						'shadow' => array(
							'type'    => 'toggle',
							'tab'     => 'elements',
							'label'   => __( 'Drop Shadow', 'storzen' ),
							'default' => true,
						),

						'border_top' => array(
							'type'    => 'toggle',
							'tab'     => 'elements',
							'label'   => __( 'Divider Line', 'storzen' ),
							'default' => true,
						),

						'show_on_mobile' => array(
							'type'    => 'toggle',
							'tab'     => 'devices',
							'label'   => __( 'Show on Mobile', 'storzen' ),
							'default' => true,
						),

						'show_on_desktop' => array(
							'type'    => 'toggle',
							'tab'     => 'devices',
							'label'   => __( 'Show on Desktop / Tablet', 'storzen' ),
							'default' => true,
						),

						// ── Pro ───────────────────────────────────────────
						'pro_show_savings' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Show Savings Badge', 'storzen' ),
							'description' => __( 'Displays "Save $X (Y%)" next to the price when the product is on sale — strong conversion nudge.', 'storzen' ),
							'default'     => false,
						),
						'pro_recently_viewed' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Show Recently Viewed Carousel', 'storzen' ),
							'description' => __( 'Expandable strip above the bar showing products the customer recently looked at.', 'storzen' ),
							'default'     => false,
						),
						'pro_countdown_in_bar' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Show Sale Countdown In Bar', 'storzen' ),
							'description' => __( 'When the product is on sale, shows time-remaining inline in the bar to drive urgency.', 'storzen' ),
							'default'     => false,
						),
						'pro_progress_to_goal' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Show Free Shipping Progress', 'storzen' ),
							'description' => __( 'Mini progress bar showing "$X more for free shipping". Pairs with the Shipping Bar module\'s threshold.', 'storzen' ),
							'default'     => false,
						),
						'pro_ab_test_label' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'A/B Test Button Labels', 'storzen' ),
							'description' => __( 'Randomly alternates between two button labels and tracks which converts better.', 'storzen' ),
							'default'     => false,
						),
						'pro_ab_test_alt_label' => array(
							'type'        => 'text',
							'tab'         => 'pro',
							'label'       => __( 'Alternative Button Label', 'storzen' ),
							'description' => __( 'The second label tested against the main button label above. Only used when A/B testing is on.', 'storzen' ),
							'default'     => 'Add to Bag',
						),
						'pro_custom_css' => array(
							'type'        => 'textarea',
							'tab'         => 'pro',
							'label'       => __( 'Custom Bar CSS', 'storzen' ),
							'description' => __( 'Advanced styling overrides for the sticky bar.', 'storzen' ),
							'default'     => '',
						),
					),
				),

				'flash_countdown' => array(
					'label'        => __( 'Flash Sale Countdown', 'storzen' ),
					'description'  => __( 'Countdown timer based on WooCommerce sale end date.', 'storzen' ),
					'pro'          => false,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-flash-countdown.php',
					'class_name'   => 'Storzen_Module_Flash_Countdown',
					'has_settings' => true,
					'tabs'         => array(
						'general'  => __( 'General', 'storzen' ),
						'display'  => __( 'Display', 'storzen' ),
						'pro'      => array(
							'label' => __( 'Pro ✦', 'storzen' ),
							'pro'   => true,
						),
					),
					'settings'     => array(
						'label_text' => array(
							'type'    => 'text',
							'tab'     => 'general',
							'label'   => __( 'Timer Label Text', 'storzen' ),
							'default' => __( 'Offer ends in:', 'storzen' ),
						),
						'show_on_cards' => array(
							'type'    => 'toggle',
							'tab'     => 'display',
							'label'   => __( 'Show on Shop Cards', 'storzen' ),
							'default' => true,
						),
						'show_on_single' => array(
							'type'    => 'toggle',
							'tab'     => 'display',
							'label'   => __( 'Show on Single Product Page', 'storzen' ),
							'default' => true,
						),

						// ── Pro ───────────────────────────────────────────
						'pro_custom_end_date' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Custom Per-Product Timer Override', 'storzen' ),
							'description' => __( 'Adds a "Countdown end" date field to every product, independent of the WooCommerce sale end date.', 'storzen' ),
							'default'     => false,
						),
						'pro_recurring_timers' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Recurring Weekly Sales', 'storzen' ),
							'description' => __( 'Set timers that reset every Monday (or chosen day) — great for "Flash Sale Friday" promos.', 'storzen' ),
							'default'     => false,
						),
						'pro_post_expiry_action' => array(
							'type'    => 'select',
							'tab'     => 'pro',
							'label'   => __( 'When Timer Reaches Zero', 'storzen' ),
							'default' => 'hide',
							'options' => array(
								'hide'             => __( 'Hide the timer (default)', 'storzen' ),
								'show_ended'       => __( 'Show "Sale Ended" message', 'storzen' ),
								'hide_product'     => __( 'Mark product as sold out', 'storzen' ),
								'continue_message' => __( 'Show custom continue message', 'storzen' ),
							),
						),
						'pro_timer_style' => array(
							'type'    => 'select',
							'tab'     => 'pro',
							'label'   => __( 'Timer Visual Style', 'storzen' ),
							'default' => 'boxed',
							'options' => array(
								'boxed'    => __( 'Boxed digits', 'storzen' ),
								'circular' => __( 'Circular progress rings', 'storzen' ),
								'flip'     => __( 'Flip-clock animation', 'storzen' ),
								'minimal'  => __( 'Minimal inline text', 'storzen' ),
							),
						),
						'pro_accent_color' => array(
							'type'    => 'color',
							'tab'     => 'pro',
							'label'   => __( 'Timer Accent Color', 'storzen' ),
							'default' => '#ef4444',
						),
						'pro_urgency_threshold' => array(
							'type'        => 'number',
							'tab'         => 'pro',
							'label'       => __( 'Urgency Mode (minutes left)', 'storzen' ),
							'description' => __( 'When less than this many minutes remain, the timer pulses red. 0 = disabled.', 'storzen' ),
							'default'     => 60,
							'min'         => 0,
							'max'         => 1440,
						),
					),
				),

				'shipping_bar' => array(
					'label'        => __( 'Free Shipping Progress Bar', 'storzen' ),
					'description'  => __( 'Show a progress bar with how much more the customer needs to spend for free shipping. Industry-standard for boosting average order value.', 'storzen' ),
					'pro'          => false,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-shipping-bar.php',
					'class_name'   => 'Storzen_Module_Shipping_Bar',
					'has_settings' => true,
					'tabs'         => array(
						'general'   => __( 'General', 'storzen' ),
						'locations' => __( 'Where to Show', 'storzen' ),
						'display'   => __( 'Display', 'storzen' ),
						'pro'       => array(
							'label' => __( 'Pro ✦', 'storzen' ),
							'pro'   => true,
						),
					),
					'settings'     => array(

						'threshold' => array(
							'type'        => 'number',
							'float'       => true,
							'tab'         => 'general',
							'label'       => __( 'Free Shipping Threshold', 'storzen' ),
							'description' => __( 'The cart subtotal needed to qualify for free shipping (in your store currency).', 'storzen' ),
							'default'     => 50,
							'min'         => 0,
							'max'         => 100000,
						),

						'initial_msg' => array(
							'type'        => 'text',
							'tab'         => 'general',
							'label'       => __( 'Progress Message', 'storzen' ),
							'description' => __( 'Shown while customer is below threshold. Placeholders: {remaining}, {threshold}, {subtotal}', 'storzen' ),
							'default'     => 'Spend {remaining} more to get FREE shipping!',
						),

						'achieved_msg' => array(
							'type'        => 'text',
							'tab'         => 'general',
							'label'       => __( 'Goal Achieved Message', 'storzen' ),
							'description' => __( 'Shown when the cart subtotal reaches the threshold.', 'storzen' ),
							'default'     => 'You\'ve unlocked FREE shipping!',
						),

						'show_on_cart' => array(
							'type'    => 'toggle',
							'tab'     => 'locations',
							'label'   => __( 'Cart Page', 'storzen' ),
							'default' => true,
						),

						'show_on_mini_cart' => array(
							'type'    => 'toggle',
							'tab'     => 'locations',
							'label'   => __( 'Mini Cart / Cart Widget', 'storzen' ),
							'default' => true,
						),

						'show_on_checkout' => array(
							'type'    => 'toggle',
							'tab'     => 'locations',
							'label'   => __( 'Checkout Page', 'storzen' ),
							'default' => false,
						),

						'show_on_sticky' => array(
							'type'        => 'toggle',
							'tab'         => 'locations',
							'label'       => __( 'Sticky Banner (every page)', 'storzen' ),
							'description' => __( 'Show a full-width announcement bar at the top or bottom of every page.', 'storzen' ),
							'default'     => false,
						),

						'sticky_position' => array(
							'type'    => 'select',
							'tab'     => 'locations',
							'label'   => __( 'Sticky Banner Position', 'storzen' ),
							'default' => 'top',
							'options' => array(
								'top'    => __( 'Top of Page', 'storzen' ),
								'bottom' => __( 'Bottom of Page', 'storzen' ),
							),
						),

						'icon' => array(
							'type'    => 'select',
							'tab'     => 'display',
							'label'   => __( 'Icon', 'storzen' ),
							'default' => 'truck',
							'options' => array(
								'truck' => __( 'Truck 🚚', 'storzen' ),
								'gift'  => __( 'Gift 🎁', 'storzen' ),
								'cart'  => __( 'Cart 🛒', 'storzen' ),
								'none'  => __( 'No Icon', 'storzen' ),
							),
						),

						'show_progress' => array(
							'type'        => 'toggle',
							'tab'         => 'display',
							'label'       => __( 'Show Progress Bar', 'storzen' ),
							'description' => __( 'Uncheck to show only the text message without the visual bar.', 'storzen' ),
							'default'     => true,
						),

						'animate' => array(
							'type'        => 'toggle',
							'tab'         => 'display',
							'label'       => __( 'Animate Progress Fill', 'storzen' ),
							'description' => __( 'Smoothly animate the bar fill when the cart updates.', 'storzen' ),
							'default'     => true,
						),

						// ── Pro ───────────────────────────────────────────
						'pro_multi_step' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Multi-Step Goals', 'storzen' ),
							'description' => __( 'Stack incentives: free shipping at $50, free gift at $100, premium gift at $200. Drives bigger basket sizes than single thresholds.', 'storzen' ),
							'default'     => false,
						),
						'pro_gift_product_id' => array(
							'type'        => 'number',
							'tab'         => 'pro',
							'label'       => __( 'Free Gift Product ID', 'storzen' ),
							'description' => __( 'When customers cross the gift threshold, this product is auto-added to their cart at zero price.', 'storzen' ),
							'default'     => 0,
							'min'         => 0,
							'max'         => 999999,
						),
						'pro_per_country' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Per-Country Thresholds', 'storzen' ),
							'description' => __( 'Set different free shipping thresholds for different customer countries (e.g. $50 US, €75 EU).', 'storzen' ),
							'default'     => false,
						),
						'pro_celebration' => array(
							'type'    => 'select',
							'tab'     => 'pro',
							'label'   => __( 'Goal-Reached Celebration', 'storzen' ),
							'default' => 'none',
							'options' => array(
								'none'      => __( 'None', 'storzen' ),
								'confetti'  => __( 'Confetti burst', 'storzen' ),
								'pulse'     => __( 'Bar pulses green', 'storzen' ),
								'message'   => __( 'Pop a "Congrats" message', 'storzen' ),
							),
						),
						'pro_category_targeting' => array(
							'type'        => 'text',
							'tab'         => 'pro',
							'label'       => __( 'Only Count These Category IDs', 'storzen' ),
							'description' => __( 'Comma-separated category IDs. Bar progress only counts products from these categories. Empty = count everything.', 'storzen' ),
							'default'     => '',
						),
						'pro_custom_css' => array(
							'type'        => 'textarea',
							'tab'         => 'pro',
							'label'       => __( 'Custom Bar CSS', 'storzen' ),
							'description' => __( 'Advanced styling overrides for the shipping bar.', 'storzen' ),
							'default'     => '',
						),
					),
				),

				'stock_scarcity' => array(
					'label'        => __( 'Stock Scarcity Messages', 'storzen' ),
					'description'  => __( 'Show "Only X left in stock!" urgency messages on product pages when inventory runs low. Pairs powerfully with Sale Notification for a complete urgency stack.', 'storzen' ),
					'pro'          => false,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-stock-scarcity.php',
					'class_name'   => 'Storzen_Module_Stock_Scarcity',
					'has_settings' => true,
					'tabs'         => array(
						'general'  => __( 'General', 'storzen' ),
						'critical' => __( 'Critical Stock', 'storzen' ),
						'display'  => __( 'Display', 'storzen' ),
						'pro'      => array(
							'label' => __( 'Pro ✦', 'storzen' ),
							'pro'   => true,
						),
					),
					'settings'     => array(

						'threshold' => array(
							'type'        => 'number',
							'tab'         => 'general',
							'label'       => __( 'Low Stock Threshold', 'storzen' ),
							'description' => __( 'Show the message when remaining stock is at or below this number. Recommended: 10.', 'storzen' ),
							'default'     => 10,
							'min'         => 1,
							'max'         => 1000,
						),

						'message' => array(
							'type'        => 'text',
							'tab'         => 'general',
							'label'       => __( 'Low Stock Message', 'storzen' ),
							'description' => __( 'Use {stock} as a placeholder for the remaining quantity.', 'storzen' ),
							'default'     => 'Hurry! Only {stock} left in stock',
						),

						'critical_threshold' => array(
							'type'        => 'number',
							'tab'         => 'critical',
							'label'       => __( 'Critical Stock Threshold', 'storzen' ),
							'description' => __( 'At this stock level or below, switch to a more urgent style and message.', 'storzen' ),
							'default'     => 3,
							'min'         => 1,
							'max'         => 1000,
						),

						'critical_message' => array(
							'type'        => 'text',
							'tab'         => 'critical',
							'label'       => __( 'Critical Stock Message', 'storzen' ),
							'description' => __( 'Use {stock} as a placeholder for the remaining quantity.', 'storzen' ),
							'default'     => 'Almost gone! Only {stock} left',
						),

						'icon' => array(
							'type'    => 'select',
							'tab'     => 'display',
							'label'   => __( 'Icon', 'storzen' ),
							'default' => 'fire',
							'options' => array(
								'fire'  => __( 'Fire 🔥 (urgency)', 'storzen' ),
								'clock' => __( 'Clock ⏰', 'storzen' ),
								'alert' => __( 'Alert ⚠️', 'storzen' ),
								'none'  => __( 'No Icon', 'storzen' ),
							),
						),

						'show_progress' => array(
							'type'        => 'toggle',
							'tab'         => 'display',
							'label'       => __( 'Show Progress Bar', 'storzen' ),
							'description' => __( 'Visual stock-level indicator under the message.', 'storzen' ),
							'default'     => true,
						),

						'show_on_variable' => array(
							'type'        => 'toggle',
							'tab'         => 'display',
							'label'       => __( 'Show on Variable Products', 'storzen' ),
							'description' => __( 'Display message when a low-stock variation is selected.', 'storzen' ),
							'default'     => true,
						),

						'show_on_shop' => array(
							'type'        => 'toggle',
							'tab'         => 'display',
							'label'       => __( 'Show on Shop / Category Pages', 'storzen' ),
							'description' => __( 'Compact version appears on product cards.', 'storzen' ),
							'default'     => false,
						),

						// ── Pro ───────────────────────────────────────────
						'pro_viewers_counter' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Show "X people viewing now" Counter', 'storzen' ),
							'description' => __( 'Adds a live (or simulated) viewer count to the scarcity message — drives intense FOMO.', 'storzen' ),
							'default'     => false,
						),
						'pro_viewers_mode' => array(
							'type'    => 'select',
							'tab'     => 'pro',
							'label'   => __( 'Viewer Count Source', 'storzen' ),
							'default' => 'simulated',
							'options' => array(
								'simulated' => __( 'Simulated (random in range)', 'storzen' ),
								'real_time' => __( 'Real-time (via WebSocket)', 'storzen' ),
								'session'   => __( 'Active sessions in last hour', 'storzen' ),
							),
						),
						'pro_recent_sales' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Show "X sold in last Y hours"', 'storzen' ),
							'description' => __( 'Adds recent purchase activity from real WooCommerce orders.', 'storzen' ),
							'default'     => false,
						),
						'pro_per_category_threshold' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Per-Category Low-Stock Thresholds', 'storzen' ),
							'description' => __( 'Set different "low stock" thresholds per category (e.g. show urgency at 5 for shirts, 2 for furniture).', 'storzen' ),
							'default'     => false,
						),
						'pro_tab_flash' => array(
							'type'        => 'toggle',
							'tab'         => 'pro',
							'label'       => __( 'Browser Tab Flash on Critical Stock', 'storzen' ),
							'description' => __( 'Animates the browser tab title ("⚠ Only 1 left!") when the customer switches tabs — pulls them back.', 'storzen' ),
							'default'     => false,
						),
						'pro_accent_color' => array(
							'type'    => 'color',
							'tab'     => 'pro',
							'label'   => __( 'Urgency Accent Color', 'storzen' ),
							'default' => '#dc2626',
						),
					),
				),


				'back_in_stock' => array(
					'label'        => __( 'Back in Stock Notifier', 'storzen' ),
					'description'  => __( 'Shows an email opt-in form on out-of-stock product pages. Automatically emails subscribers the moment a product is back in stock. Supports simple + variable products, double opt-in, GDPR consent, and WooCommerce HPOS.', 'storzen' ),
					'pro'          => false,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-back-in-stock.php',
					'class_name'   => 'Storzen_Module_Back_In_Stock',
					'has_settings' => true,
					'tabs'         => array(
						'general'  => __( 'General', 'storzen' ),
						'messages' => __( 'Messages', 'storzen' ),
						'email'    => __( 'Email', 'storzen' ),
						'style'    => __( 'Style', 'storzen' ),
					),
					'settings'     => array(

						// ── General ──────────────────────────────────────────────
						'show_oos_only' => array(
							'type'        => 'toggle',
							'tab'         => 'general',
							'label'       => __( 'Show Only When Out of Stock', 'storzen' ),
							'description' => __( 'Hide the opt-in form when the product is in stock. Recommended: ON.', 'storzen' ),
							'default'     => true,
						),
						'show_for_variable' => array(
							'type'        => 'toggle',
							'tab'         => 'general',
							'label'       => __( 'Support Variable Products', 'storzen' ),
							'description' => __( 'Show the opt-in form when the selected variation is out of stock. The form is hidden until a variation is chosen.', 'storzen' ),
							'default'     => true,
						),
						'double_optin' => array(
							'type'        => 'toggle',
							'tab'         => 'general',
							'label'       => __( 'Double Opt-In', 'storzen' ),
							'description' => __( 'Send a confirmation email before adding the subscriber. Recommended for GDPR compliance.', 'storzen' ),
							'default'     => false,
						),
						'show_consent' => array(
							'type'        => 'toggle',
							'tab'         => 'general',
							'label'       => __( 'Show GDPR Consent Checkbox', 'storzen' ),
							'description' => __( 'Adds a mandatory consent checkbox to the opt-in form.', 'storzen' ),
							'default'     => false,
						),
						'consent_text' => array(
							'type'        => 'text',
							'tab'         => 'general',
							'label'       => __( 'Consent Label', 'storzen' ),
							'description' => __( 'Text shown next to the GDPR checkbox.', 'storzen' ),
							'default'     => __( 'I agree to be emailed when this product is back in stock.', 'storzen' ),
						),
						'emails_per_batch' => array(
							'type'        => 'number',
							'tab'         => 'general',
							'label'       => __( 'Emails Per Batch', 'storzen' ),
							'description' => __( 'Maximum emails sent per WP Cron run. Lower this if your host has email-per-hour limits.', 'storzen' ),
							'default'     => 50,
						),
						'notify_delay_hours' => array(
							'type'        => 'number',
							'tab'         => 'general',
							'label'       => __( 'Notification Delay (hours)', 'storzen' ),
							'description' => __( 'Wait this many hours after stock restores before sending notifications. Set to 0 for immediate.', 'storzen' ),
							'default'     => 0,
						),

						// ── Messages ─────────────────────────────────────────────
						'placeholder' => array(
							'type'    => 'text',
							'tab'     => 'messages',
							'label'   => __( 'Email Field Placeholder', 'storzen' ),
							'default' => __( 'Enter your email address', 'storzen' ),
						),
						'btn_text' => array(
							'type'    => 'text',
							'tab'     => 'messages',
							'label'   => __( 'Button Text', 'storzen' ),
							'default' => __( 'Notify Me When Available', 'storzen' ),
						),
						'success_msg' => array(
							'type'    => 'textarea',
							'tab'     => 'messages',
							'label'   => __( 'Success Message', 'storzen' ),
							'default' => __( "You\'re on the list! We\'ll email you when this product is back in stock.", 'storzen' ),
						),

						// ── Email ────────────────────────────────────────────────
						'notify_subject' => array(
							'type'        => 'text',
							'tab'         => 'email',
							'label'       => __( 'Notification Email Subject', 'storzen' ),
							'description' => __( 'Subject line for the back-in-stock notification email sent to subscribers.', 'storzen' ),
							'default'     => '',
						),
						'confirm_subject' => array(
							'type'        => 'text',
							'tab'         => 'email',
							'label'       => __( 'Confirmation Email Subject', 'storzen' ),
							'description' => __( 'Subject for the double-opt-in confirmation email. Only used when Double Opt-In is enabled.', 'storzen' ),
							'default'     => __( 'Confirm your back-in-stock notification', 'storzen' ),
						),

						// ── Style ────────────────────────────────────────────────
						'bg_color' => array(
							'type'    => 'color',
							'tab'     => 'style',
							'label'   => __( 'Form Background', 'storzen' ),
							'default' => '#f9fafb',
						),
						'btn_color' => array(
							'type'    => 'color',
							'tab'     => 'style',
							'label'   => __( 'Button Background', 'storzen' ),
							'default' => '#111827',
						),
						'btn_text_color' => array(
							'type'    => 'color',
							'tab'     => 'style',
							'label'   => __( 'Button Text Color', 'storzen' ),
							'default' => '#ffffff',
						),
					),
				),

				// ── PRO MODULES ─────────────────────────────────────────────

				'cart' => array(
					'label'        => __( 'Cart', 'storzen' ),
					'description'  => __( 'Cart behaviour: Ajax add to cart, mini-cart drawer, and a cross-sell popup that lifts average order value.', 'storzen' ),
					'pro'          => true,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-cart-cross-sell.php',
					'class_name'   => 'Storzen_Module_Cart_Cross_Sell',
					'has_settings' => true,
					'tabs'         => array(
						'cart'       => __( 'Cart', 'storzen' ),
						'cross_sell' => __( 'Cross Sell', 'storzen' ),
						'content'    => __( 'Content', 'storzen' ),
						'display'    => __( 'Display', 'storzen' ),
					),
					'settings'     => array(
						// ── Cart behaviour ──────────────────────────────────
						'ajax_cart' => array(
							'type'        => 'toggle',
							'tab'         => 'cart',
							'label'       => __( 'Ajax Add to Cart', 'storzen' ),
							'description' => __( 'Add to cart without full page reload.', 'storzen' ),
							'default'     => true,
						),
						'cart_redirect' => array(
							'type'    => 'toggle',
							'tab'     => 'cart',
							'label'   => __( 'Redirect to Cart After Add', 'storzen' ),
							'default' => false,
						),
						'mini_cart_drw' => array(
							'type'    => 'toggle',
							'tab'     => 'cart',
							'label'   => __( 'Mini Cart Drawer', 'storzen' ),
							'default' => false,
						),

						// ── Cross Sell Popup ────────────────────────────────
						'xs_enable' => array(
							'type'        => 'toggle',
							'tab'         => 'cross_sell',
							'label'       => __( 'Enable Cross Sell Popup', 'storzen' ),
							'description' => __( 'Show related product offers after add to cart.', 'storzen' ),
							'default'     => false,
						),
						'xs_trigger' => array(
							'type'        => 'select',
							'tab'         => 'cross_sell',
							'label'       => __( 'Show Popup When', 'storzen' ),
							'description' => __( 'Choose the moment customers see cross-sell suggestions.', 'storzen' ),
							'default'     => 'after_add_to_cart',
							'options'     => array(
								'after_add_to_cart' => __( 'After Add to Cart (Recommended)', 'storzen' ),
								'before_checkout'   => __( 'Before Checkout', 'storzen' ),
								'cart_page_view'    => __( 'On Cart Page View', 'storzen' ),
							),
						),
						'xs_source' => array(
							'type'        => 'select',
							'tab'         => 'cross_sell',
							'label'       => __( 'Product Source', 'storzen' ),
							'description' => __( 'Where to pull suggested products from. Falls back automatically if empty.', 'storzen' ),
							'default'     => 'upsells',
							'options'     => array(
								'upsells'       => __( 'WooCommerce Upsells (set per product)', 'storzen' ),
								'cross_sells'   => __( 'WooCommerce Cross-Sells', 'storzen' ),
								'same_category' => __( 'Same Category', 'storzen' ),
								'best_sellers'  => __( 'Best Sellers', 'storzen' ),
								'recent'        => __( 'Recent Products', 'storzen' ),
							),
						),
						'xs_max_products' => array(
							'type'        => 'number',
							'tab'         => 'cross_sell',
							'label'       => __( 'Products to Show', 'storzen' ),
							'description' => __( 'Maximum number of cross-sell items in the popup.', 'storzen' ),
							'default'     => 3,
							'min'         => 1,
							'max'         => 8,
						),

						// ── Content ─────────────────────────────────────────
						'xs_heading' => array(
							'type'        => 'text',
							'tab'         => 'content',
							'label'       => __( 'Popup Heading', 'storzen' ),
							'description' => __( 'Title shown above the suggestions.', 'storzen' ),
							'default'     => 'You might also like…',
						),
						'xs_button_text' => array(
							'type'    => 'text',
							'tab'     => 'content',
							'label'   => __( 'Add Button Label', 'storzen' ),
							'default' => 'Add to cart',
						),
						'xs_skip_text' => array(
							'type'    => 'text',
							'tab'     => 'content',
							'label'   => __( 'Skip Button Label', 'storzen' ),
							'default' => 'No thanks, continue',
						),

						// ── Display ─────────────────────────────────────────
						'xs_layout' => array(
							'type'    => 'select',
							'tab'     => 'display',
							'label'   => __( 'Layout', 'storzen' ),
							'default' => 'grid',
							'options' => array(
								'grid'     => __( 'Grid', 'storzen' ),
								'list'     => __( 'List (stacked)', 'storzen' ),
								'carousel' => __( 'Carousel (swipeable)', 'storzen' ),
							),
						),
						'xs_show_price' => array(
							'type'    => 'toggle',
							'tab'     => 'display',
							'label'   => __( 'Show Product Price', 'storzen' ),
							'default' => true,
						),
						'xs_show_rating' => array(
							'type'    => 'toggle',
							'tab'     => 'display',
							'label'   => __( 'Show Star Rating', 'storzen' ),
							'default' => false,
						),
						'xs_show_discount_badge' => array(
							'type'        => 'toggle',
							'tab'         => 'display',
							'label'       => __( 'Highlight On-Sale Items', 'storzen' ),
							'description' => __( 'Adds a small badge to discounted suggestions.', 'storzen' ),
							'default'     => true,
						),
					),
				),

				'preorder' => array(
					'label'        => __( 'Pre-Order', 'storzen' ),
					'description'  => __( 'Let customers order out-of-stock products with an expected ship date.', 'storzen' ),
					'pro'          => true,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-preorder.php',
					'class_name'   => 'Storzen_Module_Preorder',
					'has_settings' => true,
					'tabs'         => array(
						'general'  => __( 'General', 'storzen' ),
						'display'  => __( 'Display', 'storzen' ),
						'advanced' => __( 'Advanced', 'storzen' ),
					),
					'settings'     => array(
						'button_label' => array(
							'type'    => 'text',
							'tab'     => 'general',
							'label'   => __( 'Pre-Order Button Label', 'storzen' ),
							'default' => 'Pre-Order Now',
						),
						'badge_text' => array(
							'type'        => 'text',
							'tab'         => 'general',
							'label'       => __( 'Pre-Order Badge Text', 'storzen' ),
							'description' => __( 'Replaces the "Out of stock" label.', 'storzen' ),
							'default'     => 'Pre-Order',
						),
						'availability_message' => array(
							'type'        => 'text',
							'tab'         => 'general',
							'label'       => __( 'Availability Message', 'storzen' ),
							'description' => __( 'Shown under the price. Use {date} for the expected ship date.', 'storzen' ),
							'default'     => 'Ships on or around {date}',
						),
						'date_format' => array(
							'type'    => 'select',
							'tab'     => 'display',
							'label'   => __( 'Date Format', 'storzen' ),
							'default' => 'wp',
							'options' => array(
								'wp'         => __( 'WordPress default', 'storzen' ),
								'short'      => __( 'Short (Dec 15, 2025)', 'storzen' ),
								'long'       => __( 'Long (December 15, 2025)', 'storzen' ),
								'numeric'    => __( 'Numeric (12/15/2025)', 'storzen' ),
								'relative'   => __( 'Relative (in 3 weeks)', 'storzen' ),
							),
						),
						'show_on_cards' => array(
							'type'        => 'toggle',
							'tab'         => 'display',
							'label'       => __( 'Show Badge on Shop Cards', 'storzen' ),
							'default'     => true,
						),
						'show_on_single' => array(
							'type'    => 'toggle',
							'tab'     => 'display',
							'label'   => __( 'Show Badge on Single Product Page', 'storzen' ),
							'default' => true,
						),
						'allow_backorder' => array(
							'type'        => 'toggle',
							'tab'         => 'advanced',
							'label'       => __( 'Automatically Enable Backorders', 'storzen' ),
							'description' => __( 'Forces backorder support on pre-order products so the cart accepts them.', 'storzen' ),
							'default'     => true,
						),
						'partial_deposit_pct' => array(
							'type'        => 'number',
							'tab'         => 'advanced',
							'label'       => __( 'Partial Deposit (%)', 'storzen' ),
							'description' => __( 'Charge only this percentage upfront. Set to 100 to charge in full.', 'storzen' ),
							'default'     => 100,
							'min'         => 10,
							'max'         => 100,
						),
						'email_confirmation' => array(
							'type'        => 'toggle',
							'tab'         => 'advanced',
							'label'       => __( 'Send Pre-Order Confirmation Email', 'storzen' ),
							'description' => __( 'Adds a custom note to the order confirmation.', 'storzen' ),
							'default'     => true,
						),
					),
				),

				'quick_checkout' => array(
					'label'        => __( 'Quick Checkout', 'storzen' ),
					'description'  => __( 'One-click checkout modal that reduces cart abandonment with a streamlined form.', 'storzen' ),
					'pro'          => true,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-quick-checkout.php',
					'class_name'   => 'Storzen_Module_Quick_Checkout',
					'has_settings' => true,
					'tabs'         => array(
						'general'  => __( 'General', 'storzen' ),
						'fields'   => __( 'Form Fields', 'storzen' ),
						'behavior' => __( 'Behavior', 'storzen' ),
					),
					'settings'     => array(
						'button_label' => array(
							'type'    => 'text',
							'tab'     => 'general',
							'label'   => __( 'Quick Checkout Button Label', 'storzen' ),
							'default' => 'Buy Now',
						),
						'button_position' => array(
							'type'    => 'select',
							'tab'     => 'general',
							'label'   => __( 'Button Position', 'storzen' ),
							'default' => 'after_add_to_cart',
							'options' => array(
								'after_add_to_cart' => __( 'Next to Add to Cart', 'storzen' ),
								'replace_add_to_cart' => __( 'Replace Add to Cart', 'storzen' ),
								'shop_cards'        => __( 'On Shop Product Cards', 'storzen' ),
								'both'              => __( 'Both Single + Shop Cards', 'storzen' ),
							),
						),
						'modal_title' => array(
							'type'    => 'text',
							'tab'     => 'general',
							'label'   => __( 'Modal Title', 'storzen' ),
							'default' => 'Express Checkout',
						),
						'require_phone' => array(
							'type'    => 'toggle',
							'tab'     => 'fields',
							'label'   => __( 'Require Phone Number', 'storzen' ),
							'default' => true,
						),
						'require_address' => array(
							'type'        => 'toggle',
							'tab'         => 'fields',
							'label'       => __( 'Require Shipping Address', 'storzen' ),
							'description' => __( 'Disable for digital-only stores.', 'storzen' ),
							'default'     => true,
						),
						'require_account' => array(
							'type'        => 'toggle',
							'tab'         => 'fields',
							'label'       => __( 'Require Account Creation', 'storzen' ),
							'description' => __( 'Off allows guest checkout — recommended for conversion.', 'storzen' ),
							'default'     => false,
						),
						'show_order_notes' => array(
							'type'    => 'toggle',
							'tab'     => 'fields',
							'label'   => __( 'Show Order Notes Field', 'storzen' ),
							'default' => false,
						),
						'show_coupon_field' => array(
							'type'    => 'toggle',
							'tab'     => 'fields',
							'label'   => __( 'Show Coupon Field', 'storzen' ),
							'default' => true,
						),
						'success_action' => array(
							'type'    => 'select',
							'tab'     => 'behavior',
							'label'   => __( 'After Successful Order', 'storzen' ),
							'default' => 'thank_you',
							'options' => array(
								'thank_you' => __( 'Redirect to WooCommerce Thank You Page', 'storzen' ),
								'stay'      => __( 'Stay on Page (show inline success)', 'storzen' ),
								'custom'    => __( 'Custom Redirect URL', 'storzen' ),
							),
						),
						'custom_redirect' => array(
							'type'        => 'text',
							'tab'         => 'behavior',
							'label'       => __( 'Custom Redirect URL', 'storzen' ),
							'description' => __( 'Only used when "Custom Redirect URL" is selected above.', 'storzen' ),
							'default'     => '',
						),
						'clear_cart' => array(
							'type'        => 'toggle',
							'tab'         => 'behavior',
							'label'       => __( 'Clear Cart Before Quick Checkout', 'storzen' ),
							'description' => __( 'Treats Quick Checkout as a single-product flow.', 'storzen' ),
							'default'     => true,
						),
					),
				),

				'floating_cart' => array(
					'label'        => __( 'Floating Cart', 'storzen' ),
					'description'  => __( 'A floating cart icon with live item count, total, and optional mini-preview on hover.', 'storzen' ),
					'pro'          => true,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-floating-cart.php',
					'class_name'   => 'Storzen_Module_Floating_Cart',
					'has_settings' => true,
					'tabs'         => array(
						'general' => __( 'General', 'storzen' ),
						'display' => __( 'Display', 'storzen' ),
						'devices' => __( 'Devices', 'storzen' ),
					),
					'settings'     => array(
						'position' => array(
							'type'    => 'select',
							'tab'     => 'general',
							'label'   => __( 'Icon Position', 'storzen' ),
							'default' => 'bottom-right',
							'options' => array(
								'bottom-right' => __( 'Bottom Right', 'storzen' ),
								'bottom-left'  => __( 'Bottom Left', 'storzen' ),
								'middle-right' => __( 'Middle Right', 'storzen' ),
								'middle-left'  => __( 'Middle Left', 'storzen' ),
							),
						),
						'icon_style' => array(
							'type'    => 'select',
							'tab'     => 'general',
							'label'   => __( 'Icon Style', 'storzen' ),
							'default' => 'cart',
							'options' => array(
								'cart'   => __( 'Shopping Cart 🛒', 'storzen' ),
								'bag'    => __( 'Shopping Bag 🛍️', 'storzen' ),
								'basket' => __( 'Basket', 'storzen' ),
							),
						),
						'reveal_action' => array(
							'type'        => 'select',
							'tab'         => 'general',
							'label'       => __( 'Hover Action', 'storzen' ),
							'description' => __( 'What happens when the customer hovers (desktop) or taps (mobile) the icon.', 'storzen' ),
							'default'     => 'mini_cart',
							'options'     => array(
								'mini_cart' => __( 'Open Mini Cart Drawer', 'storzen' ),
								'go_to_cart' => __( 'Go to Cart Page', 'storzen' ),
								'preview'   => __( 'Show Quick Preview', 'storzen' ),
							),
						),
						'hide_when_empty' => array(
							'type'    => 'toggle',
							'tab'     => 'general',
							'label'   => __( 'Hide When Cart Is Empty', 'storzen' ),
							'default' => true,
						),
						'show_count_badge' => array(
							'type'    => 'toggle',
							'tab'     => 'display',
							'label'   => __( 'Show Item Count Badge', 'storzen' ),
							'default' => true,
						),
						'show_total' => array(
							'type'        => 'toggle',
							'tab'         => 'display',
							'label'       => __( 'Show Cart Total Amount', 'storzen' ),
							'description' => __( 'Displays the running total under the icon.', 'storzen' ),
							'default'     => false,
						),
						'animation' => array(
							'type'    => 'select',
							'tab'     => 'display',
							'label'   => __( 'On-Add Animation', 'storzen' ),
							'default' => 'bounce',
							'options' => array(
								'bounce' => __( 'Bounce', 'storzen' ),
								'shake'  => __( 'Shake', 'storzen' ),
								'pulse'  => __( 'Pulse', 'storzen' ),
								'none'   => __( 'No Animation', 'storzen' ),
							),
						),
						'bg_color' => array(
							'type'    => 'color',
							'tab'     => 'display',
							'label'   => __( 'Background Color', 'storzen' ),
							'default' => '#FF3636',
						),
						'icon_color' => array(
							'type'    => 'color',
							'tab'     => 'display',
							'label'   => __( 'Icon Color', 'storzen' ),
							'default' => '#ffffff',
						),
						'show_on_mobile' => array(
							'type'    => 'toggle',
							'tab'     => 'devices',
							'label'   => __( 'Show on Mobile', 'storzen' ),
							'default' => true,
						),
						'show_on_desktop' => array(
							'type'    => 'toggle',
							'tab'     => 'devices',
							'label'   => __( 'Show on Desktop / Tablet', 'storzen' ),
							'default' => true,
						),
						'hide_on_pages' => array(
							'type'        => 'text',
							'tab'         => 'devices',
							'label'       => __( 'Hide on These Page IDs', 'storzen' ),
							'description' => __( 'Comma-separated page IDs where the icon should be hidden (e.g. checkout). Leave empty to show everywhere.', 'storzen' ),
							'default'     => '',
						),
					),
				),

				'currency_switcher' => array(
					'label'        => __( 'Currency Switcher', 'storzen' ),
					'description'  => __( 'Let international customers switch currencies — boosts conversion and trust.', 'storzen' ),
					'pro'          => true,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-currency-switcher.php',
					'class_name'   => 'Storzen_Module_Currency_Switcher',
					'has_settings' => true,
					'tabs'         => array(
						'general'    => __( 'General', 'storzen' ),
						'currencies' => __( 'Currencies', 'storzen' ),
						'display'    => __( 'Display', 'storzen' ),
					),
					'settings'     => array(
						'enabled_currencies' => array(
							'type'        => 'multi_select',
							'tab'         => 'currencies',
							'label'       => __( 'Enabled Currencies', 'storzen' ),
							'description' => __( 'Select all currencies the switcher should offer. Store base currency is always included.', 'storzen' ),
							'default'     => array( 'USD', 'EUR', 'GBP' ),
							'options'     => array(
								'USD' => __( 'US Dollar (USD)', 'storzen' ),
								'EUR' => __( 'Euro (EUR)', 'storzen' ),
								'GBP' => __( 'British Pound (GBP)', 'storzen' ),
								'CAD' => __( 'Canadian Dollar (CAD)', 'storzen' ),
								'AUD' => __( 'Australian Dollar (AUD)', 'storzen' ),
								'JPY' => __( 'Japanese Yen (JPY)', 'storzen' ),
								'CNY' => __( 'Chinese Yuan (CNY)', 'storzen' ),
								'INR' => __( 'Indian Rupee (INR)', 'storzen' ),
								'BRL' => __( 'Brazilian Real (BRL)', 'storzen' ),
								'MXN' => __( 'Mexican Peso (MXN)', 'storzen' ),
								'SGD' => __( 'Singapore Dollar (SGD)', 'storzen' ),
								'AED' => __( 'UAE Dirham (AED)', 'storzen' ),
								'BDT' => __( 'Bangladeshi Taka (BDT)', 'storzen' ),
							),
						),
						'rate_source' => array(
							'type'        => 'select',
							'tab'         => 'general',
							'label'       => __( 'Exchange Rate Source', 'storzen' ),
							'description' => __( 'Auto pulls live rates from a free public API daily; Manual lets you set fixed rates per currency.', 'storzen' ),
							'default'     => 'auto',
							'options'     => array(
								'auto'   => __( 'Automatic (live rates)', 'storzen' ),
								'manual' => __( 'Manual (fixed rates)', 'storzen' ),
							),
						),
						'refresh_hours' => array(
							'type'        => 'number',
							'tab'         => 'general',
							'label'       => __( 'Refresh Interval (hours)', 'storzen' ),
							'description' => __( 'How often to fetch fresh rates when in Automatic mode.', 'storzen' ),
							'default'     => 24,
							'min'         => 1,
							'max'         => 168,
						),
						'auto_detect' => array(
							'type'        => 'toggle',
							'tab'         => 'general',
							'label'       => __( 'Auto-Detect Visitor Currency', 'storzen' ),
							'description' => __( 'Use GeoIP to preselect a currency on first visit.', 'storzen' ),
							'default'     => true,
						),
						'switcher_style' => array(
							'type'    => 'select',
							'tab'     => 'display',
							'label'   => __( 'Switcher Style', 'storzen' ),
							'default' => 'dropdown',
							'options' => array(
								'dropdown' => __( 'Dropdown', 'storzen' ),
								'list'     => __( 'Vertical List', 'storzen' ),
								'buttons'  => __( 'Pill Buttons', 'storzen' ),
								'flags'    => __( 'Flag Grid', 'storzen' ),
							),
						),
						'display_format' => array(
							'type'    => 'select',
							'tab'     => 'display',
							'label'   => __( 'Currency Label Format', 'storzen' ),
							'default' => 'code_symbol',
							'options' => array(
								'code'        => __( 'Code only (USD)', 'storzen' ),
								'symbol'      => __( 'Symbol only ($)', 'storzen' ),
								'code_symbol' => __( 'Code + Symbol ($ USD)', 'storzen' ),
								'name'        => __( 'Full Name (US Dollar)', 'storzen' ),
							),
						),
						'show_flags' => array(
							'type'    => 'toggle',
							'tab'     => 'display',
							'label'   => __( 'Show Country Flags', 'storzen' ),
							'default' => true,
						),
						'sticky_widget' => array(
							'type'        => 'toggle',
							'tab'         => 'display',
							'label'       => __( 'Show as Floating Widget', 'storzen' ),
							'description' => __( 'Adds a small floating switcher in the corner of every page.', 'storzen' ),
							'default'     => false,
						),
					),
				),

				'invoice' => array(
					'label'        => __( 'Invoice / PDF', 'storzen' ),
					'description'  => __( 'Auto-generate branded PDF invoices for WooCommerce orders and attach them to customer emails.', 'storzen' ),
					'pro'          => true,
					'default'      => false,
					'class_file'   => '/modules/class-storzen-module-invoice.php',
					'class_name'   => 'Storzen_Module_Invoice',
					'has_settings' => true,
					'tabs'         => array(
						'general'  => __( 'General', 'storzen' ),
						'branding' => __( 'Branding', 'storzen' ),
						'behavior' => __( 'Behavior', 'storzen' ),
					),
					'settings'     => array(
						'generate_on' => array(
							'type'        => 'select',
							'tab'         => 'general',
							'label'       => __( 'Generate Invoice On', 'storzen' ),
							'description' => __( 'Which order status triggers invoice generation.', 'storzen' ),
							'default'     => 'completed',
							'options'     => array(
								'processing' => __( 'Processing', 'storzen' ),
								'completed'  => __( 'Completed (Recommended)', 'storzen' ),
								'paid'       => __( 'Any Paid Status', 'storzen' ),
								'manual'     => __( 'Manual Only', 'storzen' ),
							),
						),
						'paper_size' => array(
							'type'    => 'select',
							'tab'     => 'general',
							'label'   => __( 'Paper Size', 'storzen' ),
							'default' => 'A4',
							'options' => array(
								'A4'     => __( 'A4', 'storzen' ),
								'Letter' => __( 'US Letter', 'storzen' ),
								'Legal'  => __( 'US Legal', 'storzen' ),
							),
						),
						'invoice_number_prefix' => array(
							'type'        => 'text',
							'tab'         => 'general',
							'label'       => __( 'Invoice Number Prefix', 'storzen' ),
							'description' => __( 'No trailing dash needed. Example: INV → INV-2026-00001', 'storzen' ),
							'default'     => 'INV',
						),
						'company_name' => array(
							'type'    => 'text',
							'tab'     => 'branding',
							'label'   => __( 'Company Name', 'storzen' ),
							'default' => '',
						),
						'company_details' => array(
							'type'        => 'textarea',
							'tab'         => 'branding',
							'label'       => __( 'Company Address / Details', 'storzen' ),
							'description' => __( 'Address, VAT/Tax ID, phone — appears at the top of every invoice.', 'storzen' ),
							'default'     => '',
						),
						'logo_url' => array(
							'type'        => 'text',
							'tab'         => 'branding',
							'label'       => __( 'Logo URL', 'storzen' ),
							'description' => __( 'Paste a URL to your logo (PNG/JPG, ideally under 300×100px).', 'storzen' ),
							'default'     => '',
						),
						'accent_color' => array(
							'type'    => 'color',
							'tab'     => 'branding',
							'label'   => __( 'Accent Color', 'storzen' ),
							'default' => '#FF3636',
						),
						'footer_text' => array(
							'type'        => 'textarea',
							'tab'         => 'branding',
							'label'       => __( 'Footer Text', 'storzen' ),
							'description' => __( 'Shown at the bottom of every invoice (return policy, thank-you note, etc).', 'storzen' ),
							'default'     => 'Thank you for your business!',
						),
						'include_tax_breakdown' => array(
							'type'    => 'toggle',
							'tab'     => 'behavior',
							'label'   => __( 'Include Per-Line Tax Breakdown', 'storzen' ),
							'default' => true,
						),
						'attach_to_email' => array(
							'type'        => 'toggle',
							'tab'         => 'behavior',
							'label'       => __( 'Attach PDF to Customer Order Email', 'storzen' ),
							'description' => __( 'Automatically attaches the generated invoice to WooCommerce order emails.', 'storzen' ),
							'default'     => true,
						),
						'allow_download' => array(
							'type'        => 'toggle',
							'tab'         => 'behavior',
							'label'       => __( 'Customer Can Download from My Account', 'storzen' ),
							'default'     => true,
						),
					),
				),

			);
		}

		/**
		 * Singleton accessor.
		 *
		 * @return static
		 */
		public static function instance() {
			if ( is_null( self::$instance ) ) {
				self::$instance = new self();
			}
			return self::$instance;
		}

		public function __construct() {
			add_action( 'wp_ajax_storzen_save_modules', array( $this, 'ajax_save' ) );
			add_action( 'init', array( $this, 'load_active_modules' ), 15 );
		}

		/**
		 * Get saved module states from DB.
		 *
		 * @return array
		 */
		public function get_saved_states() {
			$saved = get_option( self::OPTION_KEY, array() );
			return is_array( $saved ) ? $saved : array();
		}

		/**
		 * Check if a specific module is enabled.
		 *
		 * @param string $module_key
		 * @return bool
		 */
		public function is_enabled( $module_key ) {
			$defs   = self::get_module_definitions();
			$saved  = $this->get_saved_states();
			$is_pro = ( isset( $defs[ $module_key ]['pro'] ) && $defs[ $module_key ]['pro'] );

			// PRO modules disabled unless license active
			if ( $is_pro && ! $this->is_pro_active() ) {
				return false;
			}

			if ( isset( $saved['modules'][ $module_key ] ) ) {
				return (bool) $saved['modules'][ $module_key ];
			}

			// Fall back to default
			return ! empty( $defs[ $module_key ]['default'] );
		}

		/**
		 * Get a specific module setting value.
		 *
		 * @param string $module_key
		 * @param string $setting_key
		 * @return mixed
		 */
		public function get_module_setting( $module_key, $setting_key ) {
			$saved   = $this->get_saved_states();
			$defs    = self::get_module_definitions();
			$default = isset( $defs[ $module_key ]['settings'][ $setting_key ]['default'] )
				? $defs[ $module_key ]['settings'][ $setting_key ]['default']
				: null;

			return isset( $saved['settings'][ $module_key ][ $setting_key ] )
				? $saved['settings'][ $module_key ][ $setting_key ]
				: $default;
		}

		/**
		 * Load all enabled module class files.
		 */
		public function load_active_modules() {
			if ( ! class_exists( 'WooCommerce' ) ) {
				return;
			}

			foreach ( self::get_module_definitions() as $key => $def ) {
				if ( ! $this->is_enabled( $key ) ) {
					continue;
				}
				$file = STORZEN_INC . $def['class_file'];
				if ( file_exists( $file ) ) {
					require_once $file;
					if ( ! empty( $def['class_name'] ) && class_exists( $def['class_name'] ) ) {
						new $def['class_name']();
					}
				}
			}
		}

		/**
		 * AJAX handler — save module toggles + settings.
		 */
		public function ajax_save() {
			check_ajax_referer( 'storzen_modules_nonce', 'nonce' );

			if ( ! current_user_can( 'manage_options' ) ) {
				wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'storzen' ) ) );
			}

			$raw_modules  = isset( $_POST['modules'] )  ? wp_unslash( $_POST['modules'] )  : array();  // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitized below
			$raw_settings = isset( $_POST['settings'] ) ? wp_unslash( $_POST['settings'] ) : array(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitized below

			$defs           = self::get_module_definitions();
			$clean_modules  = array();
			$clean_settings = array();

			// Sanitize module toggles
			foreach ( $defs as $key => $def ) {
				if ( $def['pro'] && ! $this->is_pro_active() ) {
					$clean_modules[ $key ] = false;
					continue;
				}
				$clean_modules[ $key ] = ! empty( $raw_modules[ $key ] );
			}

			// Sanitize module settings
			$is_pro_active = $this->is_pro_active();
			foreach ( $defs as $key => $def ) {
				if ( empty( $def['settings'] ) ) {
					continue;
				}

				// Pre-compute which tab keys are Pro-only for this module.
				// Tabs can be either 'tab_key' => 'Label' (free) or
				// 'tab_key' => array( 'label' => '...', 'pro' => true ).
				$pro_tab_keys = array();
				if ( ! empty( $def['tabs'] ) && is_array( $def['tabs'] ) ) {
					foreach ( $def['tabs'] as $tab_key => $tab_val ) {
						if ( is_array( $tab_val ) && ! empty( $tab_val['pro'] ) ) {
							$pro_tab_keys[ $tab_key ] = true;
						}
					}
				}

				foreach ( $def['settings'] as $setting_key => $field ) {
					// Drop fields that belong to a locked Pro tab when the user
					// has no active license. The UI already disables the inputs
					// via <fieldset disabled>; this is defense-in-depth against
					// crafted POST requests.
					if ( ! $is_pro_active && isset( $field['tab'] ) && isset( $pro_tab_keys[ $field['tab'] ] ) ) {
						continue;
					}

					$raw_val = isset( $raw_settings[ $key ][ $setting_key ] )
						? $raw_settings[ $key ][ $setting_key ]
						: null;

					switch ( $field['type'] ) {
						case 'number':
							// Some fields (currency thresholds, percentages) need decimals.
							// Opt-in via 'float' => true on the field definition.
							if ( ! empty( $field['float'] ) ) {
								$val = (float) $raw_val;
								if ( isset( $field['min'] ) ) $val = max( (float) $field['min'], $val );
								if ( isset( $field['max'] ) ) $val = min( (float) $field['max'], $val );
								$clean_settings[ $key ][ $setting_key ] = $val;
							} else {
								$val = (int) $raw_val;
								if ( isset( $field['min'] ) ) $val = max( $field['min'], $val );
								if ( isset( $field['max'] ) ) $val = min( $field['max'], $val );
								$clean_settings[ $key ][ $setting_key ] = $val;
							}
							break;
						case 'toggle':
							$clean_settings[ $key ][ $setting_key ] = (bool) $raw_val;
							break;
						case 'select':
							$options = array_keys( $field['options'] );
							$clean_settings[ $key ][ $setting_key ] = in_array( $raw_val, $options, true )
								? $raw_val
								: $field['default'];
							break;
						case 'multi_select':
							// Whitelist each value against the allowed options; preserve order.
							$allowed   = array_keys( $field['options'] );
							$incoming  = is_array( $raw_val ) ? $raw_val : array();
							$filtered  = array();
							foreach ( $incoming as $v ) {
								$v = (string) $v;
								if ( in_array( $v, $allowed, true ) && ! in_array( $v, $filtered, true ) ) {
									$filtered[] = $v;
								}
							}
							$clean_settings[ $key ][ $setting_key ] = $filtered;
							break;
						case 'color':
							// Accept #rgb, #rrggbb (sanitize_hex_color), or empty string for "no color".
							$hex = sanitize_hex_color( (string) $raw_val );
							$clean_settings[ $key ][ $setting_key ] = $hex
								? $hex
								: (string) ( $field['default'] ?? '' );
							break;
						case 'textarea':
							// Multi-line text — strip tags by default; opt-in HTML via 'allow_html' => true.
							if ( ! empty( $field['allow_html'] ) ) {
								$clean_settings[ $key ][ $setting_key ] = wp_kses_post( (string) $raw_val );
							} else {
								$clean_settings[ $key ][ $setting_key ] = sanitize_textarea_field( (string) $raw_val );
							}
							break;
						case 'page_select':
							$clean_settings[ $key ][ $setting_key ] = absint( $raw_val );
							break;
						case 'text':
						default:
							$clean_settings[ $key ][ $setting_key ] = sanitize_text_field( (string) $raw_val );
							break;
					}
				}
			}

			update_option(
				self::OPTION_KEY,
				array(
					'modules'  => $clean_modules,
					'settings' => $clean_settings,
				),
				false
			);

			wp_send_json_success( array( 'message' => __( 'Modules saved!', 'storzen' ) ) );
		}

		/**
		 * Whether PRO license is active.
		 *
		 * @return bool
		 */
		public function is_pro_active() {
			return defined( 'STORZEN_IS_PRO' ) && STORZEN_IS_PRO === 'yes';
		}

	} // end class

	// Boot on plugins_loaded
	add_action( 'plugins_loaded', array( 'Storzen_Modules', 'instance' ), 6 );

} // end class_exists

/**
 * Global helper — check if a Storzen module is enabled.
 *
 * Usage: if ( storzen_module_enabled( 'quick_view' ) ) { ... }
 *
 * @param string $module_key
 * @return bool
 */
function storzen_module_enabled( $module_key ) {
	return Storzen_Modules::instance()->is_enabled( $module_key );
}

/**
 * Global helper — get a module setting value.
 *
 * Usage: $size = storzen_module_setting( 'variation_swatches', 'swatch_size' );
 *
 * @param string $module_key
 * @param string $setting_key
 * @return mixed
 */
function storzen_module_setting( $module_key, $setting_key ) {
	return Storzen_Modules::instance()->get_module_setting( $module_key, $setting_key );
}
