<?php
/**
 * Style Helper Functions
 *
 * Centralized functions for generating inline styles from settings arrays.
 *
 * @package    Extra_Product_Options_For_WooCommerce
 * @subpackage Extra_Product_Options_For_WooCommerce/settings
 * @since      4.4.0
 */

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

/**
 * Convert settings array to CSS properties array.
 *
 * Helper function that converts style settings to CSS properties array
 * for use with the style collector.
 *
 * @since 4.4.0
 *
 * @param array $settings  Settings array with style properties.
 * @param array $style_map Optional. Mapping of setting keys to CSS properties.
 *                          Format: array( 'setting_key' => 'css-property' ).
 * @return array Array of CSS properties (e.g., array('background-color' => '#fff', 'margin' => '10px')).
 */
function epofw_settings_to_css_properties( $settings, $style_map = array() ) {
	if ( empty( $settings ) || ! is_array( $settings ) ) {
		return array();
	}

	$css_properties = array();

	// Default style mappings for common properties.
	$default_map = array(
		'background_color' => 'background-color',
		'text_color'       => 'color',
		'border_color'     => 'border-color',
		'border_width'     => 'border-width',
		'border_style'     => 'border-style',
		'border_radius'    => 'border-radius',
		'font_size'        => 'font-size',
		'font_weight'      => 'font-weight',
		'font_family'      => 'font-family',
		'text_align'       => 'text-align',
		'text_transform'   => 'text-transform',
		'letter_spacing'   => 'letter-spacing',
		'line_height'      => 'line-height',
		'text_shadow'      => 'text-shadow',
		'gap'              => 'gap',
		'width'            => 'width',
		'min_width'        => 'min-width',
		'max_width'        => 'max-width',
		'height'           => 'height',
		'min_height'       => 'min-height',
		'max_height'       => 'max-height',
		'box_shadow'       => 'box-shadow',
		'transition'       => 'transition',
		'display'          => 'display',
	);

	// Merge user-provided style map with defaults.
	$style_map = array_merge( $default_map, $style_map );

	// Handle spacing (margin/padding) - FREE feature.
	foreach ( array( 'margin', 'padding' ) as $spacing_type ) {
		if ( ! empty( $settings[ $spacing_type ] ) ) {
			if ( is_array( $settings[ $spacing_type ] ) ) {
				// Advanced spacing (PREMIUM feature - individual sides).
				$spacing = $settings[ $spacing_type ];
				$units   = ! empty( $spacing['units'] ) ? $spacing['units'] : 'px';
				$top     = ! empty( $spacing['top'] ) ? $spacing['top'] : '0';
				$right   = ! empty( $spacing['right'] ) ? $spacing['right'] : '0';
				$bottom  = ! empty( $spacing['bottom'] ) ? $spacing['bottom'] : '0';
				$left    = ! empty( $spacing['left'] ) ? $spacing['left'] : '0';

				// Build spacing value.
				$spacing_value                   = $top . $units . ' ' . $right . $units . ' ' . $bottom . $units . ' ' . $left . $units;
				$css_properties[ $spacing_type ] = $spacing_value;
			} elseif ( is_numeric( $settings[ $spacing_type ] ) ) {
				// Simple spacing (FREE feature - all sides same value).
				$css_properties[ $spacing_type ] = absint( $settings[ $spacing_type ] ) . 'px';
			} else {
				// String value.
				$css_properties[ $spacing_type ] = $settings[ $spacing_type ];
			}
		}
	}

	// Check if border properties exist (for border validation).
	$has_border = ! empty( $settings['border_width'] ) && absint( $settings['border_width'] ) > 0;

	// Handle mapped styles (colors, borders, typography, etc.).
	foreach ( $style_map as $setting_key => $css_property ) {
		if ( ! empty( $settings[ $setting_key ] ) ) {
			$value = $settings[ $setting_key ];

			// Skip array values - these need special handling in specific functions.
			// Properties like width, padding, margin can be arrays with value/units structure.
			if ( is_array( $value ) ) {
				continue;
			}

			// Skip border-style and border-color if border-width is 0 or empty.
			if ( ! $has_border && in_array( $css_property, array( 'border-style', 'border-color' ), true ) ) {
				continue;
			}

			// Determine if unit is needed.
			$needs_unit = false;
			$unit       = '';

			// Properties that typically need units (FREE: px only, PREMIUM: all units).
			$unit_properties = array(
				'font-size',
				'border-width',
				'border-radius',
				'gap',
				'width',
				'min-width',
				'max-width',
				'height',
				'min-height',
				'max-height',
				'letter-spacing',
				'line-height',
			);

			if ( in_array( $css_property, $unit_properties, true ) ) {
				$needs_unit = true;
				$unit       = 'px'; // Default unit for FREE version.
			}

			// Add unit if needed and not already present.
			if ( $needs_unit && is_numeric( $value ) ) {
				$value = $value . $unit;
			}

			$css_properties[ $css_property ] = $value;
		}
	}

	return $css_properties;
}

/**
 * Generate inline styles from settings array.
 *
 * This function converts a settings array into inline CSS styles.
 * Supports free features (basic colors, spacing) and can be extended
 * for premium features (advanced spacing, borders, typography, etc.).
 *
 * @since 4.4.0
 * @deprecated Use epofw_settings_to_css_properties() with style collector instead.
 *
 * @param array $settings  Settings array with style properties.
 * @param array $style_map Optional. Mapping of setting keys to CSS properties.
 *                          Format: array( 'setting_key' => 'css-property' ).
 * @return string Inline style string (e.g., ' style="background-color: #fff; margin: 10px;"').
 */
function epofw_generate_inline_styles( $settings, $style_map = array() ) {
	if ( empty( $settings ) || ! is_array( $settings ) ) {
		return '';
	}

	$styles = array();

	// Default style mappings for common properties.
	$default_map = array(
		'background_color' => 'background-color',
		'text_color'       => 'color',
		'border_color'     => 'border-color',
		'border_width'     => 'border-width',
		'border_style'     => 'border-style',
		'border_radius'    => 'border-radius',
		'font_size'        => 'font-size',
		'font_weight'      => 'font-weight',
		'text_align'       => 'text-align',
		'gap'              => 'gap',
		'width'            => 'width',
		'min_width'        => 'min-width',
		'max_width'        => 'max-width',
		'height'           => 'height',
		'min_height'       => 'min-height',
		'max_height'       => 'max-height',
	);

	// Merge user-provided style map with defaults.
	$style_map = array_merge( $default_map, $style_map );

	// Handle spacing (margin/padding) - FREE feature.
	foreach ( array( 'margin', 'padding' ) as $spacing_type ) {
		if ( ! empty( $settings[ $spacing_type ] ) && is_array( $settings[ $spacing_type ] ) ) {
			$spacing = $settings[ $spacing_type ];
			$units   = ! empty( $spacing['units'] ) ? $spacing['units'] : 'px';
			$top     = ! empty( $spacing['top'] ) ? $spacing['top'] : '0';
			$right   = ! empty( $spacing['right'] ) ? $spacing['right'] : '0';
			$bottom  = ! empty( $spacing['bottom'] ) ? $spacing['bottom'] : '0';
			$left    = ! empty( $spacing['left'] ) ? $spacing['left'] : '0';

			// Build spacing value.
			$spacing_value = $top . $units . ' ' . $right . $units . ' ' . $bottom . $units . ' ' . $left . $units;
			$styles[]      = $spacing_type . ': ' . esc_attr( $spacing_value );
		}
	}

	// Check if border properties exist (for border validation).
	$has_border = ! empty( $settings['border_width'] ) && absint( $settings['border_width'] ) > 0;

	// Handle mapped styles (colors, borders, typography, etc.).
	foreach ( $style_map as $setting_key => $css_property ) {
		if ( ! empty( $settings[ $setting_key ] ) ) {
			$value = $settings[ $setting_key ];

			// Skip array values - these need special handling in specific functions.
			// Properties like width, padding, margin can be arrays with value/units structure.
			if ( is_array( $value ) ) {
				continue;
			}

			// Skip border-style and border-color if border-width is 0 or empty.
			if ( ! $has_border && in_array( $css_property, array( 'border-style', 'border-color' ), true ) ) {
				continue;
			}

			// Determine if unit is needed.
			$needs_unit = false;
			$unit       = '';

			// Properties that typically need units (FREE: px only, PREMIUM: all units).
			$unit_properties = array(
				'font-size',
				'border-width',
				'border-radius',
				'gap',
				'width',
				'min-width',
				'max-width',
				'height',
				'min-height',
				'max-height',
			);

			if ( in_array( $css_property, $unit_properties, true ) ) {
				$needs_unit = true;
				$unit       = 'px'; // Default unit for FREE version.
			}

			// Add unit if needed and not already present.
			if ( $needs_unit && is_numeric( $value ) ) {
				$value = $value . $unit;
			}

			$styles[] = $css_property . ': ' . esc_attr( $value );
		}
	}

	// Return formatted style attribute.
	return ! empty( $styles ) ? ' style="' . esc_attr( implode( '; ', $styles ) ) . '"' : '';
}

// Keep the old inline styles function for backward compatibility (used by title/description styles).

/**
 * Generate CSS class name for section container and collect styles.
 *
 * Helper function specifically for section styling.
 * Uses the style collector to generate a class name and collect CSS.
 *
 * @since 4.4.0
 *
 * @param array $section_settings Section settings array.
 * @param bool  $is_premium_user  Whether the user has premium access. Default true for backward compatibility.
 * @return string CSS class name (empty if disabled).
 */
function epofw_generate_section_styles( $section_settings, $is_premium_user = true ) {
	if ( empty( $section_settings ) || ! is_array( $section_settings ) ) {
		return '';
	}

	// Check if section styling is enabled.
	$enabled = isset( $section_settings['enabled'] ) ? $section_settings['enabled'] : '';
	if ( 'on' !== $enabled ) {
		return ''; // Return empty if disabled.
	}

	// Section style map - FREE features only.
	$style_map = array(
		'background_color' => 'background-color',
	);

	// Add border properties only for premium users (PREMIUM ONLY).
	if ( $is_premium_user ) {
		$style_map['border_color']  = 'border-color';
		$style_map['border_width']  = 'border-width';
		$style_map['border_style']  = 'border-style';
		$style_map['border_radius'] = 'border-radius';
	}

	// Convert settings to CSS properties.
	$css_properties = epofw_settings_to_css_properties( $section_settings, $style_map );

	if ( empty( $css_properties ) ) {
		return '';
	}

	// Generate unique class name and add to collector.
	$class_name = EPOFW_Style_Collector::generate_class_name( 'epofw-style-section' );
	return EPOFW_Style_Collector::add_style( $class_name, $css_properties );
}

/**
 * Generate inline styles for section title.
 *
 * Helper function specifically for section title styling.
 *
 * @since 4.4.0
 *
 * @param array $section_settings Section settings array.
 * @return string Inline style string.
 */
function epofw_generate_section_title_styles( $section_settings ) {
	if ( empty( $section_settings ) || ! is_array( $section_settings ) ) {
		return '';
	}

	// Create a clean settings array with ONLY title-specific properties.
	// Remove container properties that should not apply to the title.
	$title_settings = array();
	if ( ! empty( $section_settings['title_text_color'] ) ) {
		$title_settings['title_text_color'] = $section_settings['title_text_color'];
	}
	if ( ! empty( $section_settings['title_alignment'] ) ) {
		$title_settings['title_alignment'] = $section_settings['title_alignment'];
		// For text-align to work, element must be block-level (not inline).
		// Labels are inline by default, headings are block by default, but we ensure block for consistency.
		$title_settings['display'] = 'block';
		$title_settings['width']   = '100%';
	}

	// Title-specific style map.
	$style_map = array(
		'title_text_color' => 'color',
		'title_alignment'  => 'text-align',
		'display'          => 'display',
		'width'            => 'width',
	);

	return epofw_generate_inline_styles( $title_settings, $style_map );
}

/**
 * Generate inline styles for section description.
 *
 * Helper function specifically for section description styling.
 *
 * @since 4.4.0
 *
 * @param array $section_settings Section settings array.
 * @return string Inline style string.
 */
function epofw_generate_section_description_styles( $section_settings ) {
	if ( empty( $section_settings ) || ! is_array( $section_settings ) ) {
		return '';
	}

	// Create a clean settings array with ONLY description-specific properties.
	// Remove container properties that should not apply to the description.
	$description_settings = array();
	if ( ! empty( $section_settings['description_text_color'] ) ) {
		$description_settings['description_text_color'] = $section_settings['description_text_color'];
	}
	if ( ! empty( $section_settings['description_alignment'] ) ) {
		$description_settings['description_alignment'] = $section_settings['description_alignment'];
		// For text-align to work, element must be block-level (not inline).
		// Divs are block by default, but we ensure block for consistency.
		$description_settings['display'] = 'block';
		$description_settings['width']   = '100%';
	}

	// Description-specific style map.
	$style_map = array(
		'description_text_color' => 'color',
		'description_alignment'  => 'text-align',
		'display'                => 'display',
		'width'                  => 'width',
	);

	return epofw_generate_inline_styles( $description_settings, $style_map );
}

/**
 * Generate inline styles for row group container (layout-only: gap, alignment).
 *
 * Row groups are now layout-only (no styling). This function only handles
 * layout properties like gap and alignment.
 *
 * @since 4.4.0
 *
 * @param array $row_group_settings Row group settings array.
 * @return string Inline style string for layout properties only.
 */
function epofw_generate_row_group_styles( $row_group_settings ) {
	if ( empty( $row_group_settings ) || ! is_array( $row_group_settings ) ) {
		return '';
	}

	$styles = array();

	// Handle gap (layout property - simple numeric value in px).
	if ( ! empty( $row_group_settings['gap'] ) && is_numeric( $row_group_settings['gap'] ) ) {
		$gap_value = absint( $row_group_settings['gap'] );
		$styles[]  = 'gap: ' . $gap_value . 'px';
	}

	// Handle alignment (CSS Grid property - layout, not styling).
	if ( ! empty( $row_group_settings['alignment'] ) ) {
		$alignment = $row_group_settings['alignment'];
		// Map alignment values to CSS Grid properties.
		$align_map = array(
			'start'   => 'start',
			'center'  => 'center',
			'end'     => 'end',
			'stretch' => 'stretch',
		);
		if ( isset( $align_map[ $alignment ] ) ) {
			$styles[] = 'align-items: ' . esc_attr( $align_map[ $alignment ] );
		}
	}

	// Return formatted style attribute (only layout properties).
	return ! empty( $styles ) ? ' style="' . esc_attr( implode( '; ', $styles ) ) . '"' : '';
}

/**
 * Generate inline styles for row container (column).
 *
 * Columns are now layout-only (no styling). This function returns empty
 * as columns no longer support styling.
 *
 * @since 4.4.0
 *
 * @param array $column_settings Column settings array.
 * @return string Empty string (columns are layout-only).
 */
function epofw_generate_row_container_styles( $column_settings ) {
	// Columns are layout-only, no styling supported.
	return '';
}

/**
 * Generate CSS class name for field container and collect styles.
 *
 * Helper function specifically for field container styling.
 * Uses the style collector to generate a class name and collect CSS.
 *
 * @since 4.4.0
 *
 * @param array $field_container_settings Field container settings array.
 * @return string CSS class name (empty if disabled).
 */
function epofw_generate_field_container_styles( $field_container_settings ) {
	if ( empty( $field_container_settings ) || ! is_array( $field_container_settings ) ) {
		return '';
	}

	// Check if field container styling is enabled.
	$enabled = isset( $field_container_settings['enabled'] ) ? $field_container_settings['enabled'] : '';
	if ( 'on' !== $enabled ) {
		return '';
	}

	// Field container style map.
	$style_map = array(
		'background_color' => 'background-color',
		'border_color'     => 'border-color',
		'border_width'     => 'border-width',
		'border_style'     => 'border-style',
		'border_radius'    => 'border-radius',
		'width'            => 'width',
		'max_width'        => 'max-width',
		'min_width'        => 'min-width',
		'gap'              => 'gap',
		'box_shadow'       => 'box-shadow',
	);

	// Convert settings to CSS properties.
	$css_properties = epofw_settings_to_css_properties( $field_container_settings, $style_map );

	if ( empty( $css_properties ) ) {
		return '';
	}

	// Generate unique class name and add to collector.
	$class_name = EPOFW_Style_Collector::generate_class_name( 'epofw-style-field-container' );
	return EPOFW_Style_Collector::add_style( $class_name, $css_properties );
}

/**
 * Input Container Styling has been removed.
 * Use Field Container Styling instead for all field wrapper styling needs.
 *
 * @deprecated 4.4.0 This function is no longer used. Input container styling has been removed.
 * @since 4.4.0
 *
 * @param array $input_container_settings Settings array (ignored).
 * @return string Always returns empty string.
 */
function epofw_generate_input_container_styles( $input_container_settings ) {
	// Input Container styling has been removed - use Field Container styling instead.
	return '';
}

/**
 * Generate inline styles for label container.
 *
 * Label containers no longer support styling (simplified approach).
 * This function returns empty string.
 *
 * @since 4.4.0
 *
 * @param array $label_styling_settings Label styling settings array.
 * @return string Empty string (label containers no longer styled).
 */
function epofw_generate_label_container_styles( $label_styling_settings ) {
	// Label containers no longer support styling (simplified approach).
	return '';
}

/**
 * Generate CSS class name for label text and collect styles.
 *
 * Simplified label text styling - only typography and basic colors.
 * Uses the style collector to generate a class name and collect CSS.
 *
 * @since 4.4.0
 *
 * @param array $label_styling_settings Label styling settings array.
 * @return string CSS class name (empty if disabled).
 */
function epofw_generate_label_text_styles( $label_styling_settings ) {
	if ( empty( $label_styling_settings ) || ! is_array( $label_styling_settings ) ) {
		return '';
	}

	// Check if label styling is enabled.
	$enabled = isset( $label_styling_settings['enabled'] ) ? $label_styling_settings['enabled'] : '';
	if ( 'on' !== $enabled ) {
		return ''; // Return empty if disabled.
	}

	// Label text style map (simplified - only typography and text shadow, text color is handled by title_color).
	$style_map = array(
		'font_size'      => 'font-size',
		'font_weight'    => 'font-weight',
		'font_family'    => 'font-family',
		'text_align'     => 'text-align',
		'text_transform' => 'text-transform',
		'letter_spacing' => 'letter-spacing',
		'line_height'    => 'line-height',
		'text_shadow'    => 'text-shadow',
	);

	// Convert settings to CSS properties.
	$css_properties = epofw_settings_to_css_properties( $label_styling_settings, $style_map );

	if ( empty( $css_properties ) ) {
		return '';
	}

	// Generate unique class name and add to collector.
	$class_name = EPOFW_Style_Collector::generate_class_name( 'epofw-style-label-text' );
	return EPOFW_Style_Collector::add_style( $class_name, $css_properties );
}

/**
 * Output custom CSS as a scoped style tag.
 *
 * @since 4.4.0
 *
 * @param string $custom_css The custom CSS content.
 * @param string $scope_selector The CSS selector to scope the styles (e.g., '#epofw-section-123').
 * @return string HTML style tag or empty string.
 */
function epofw_output_custom_css( $custom_css, $scope_selector = '' ) {
	if ( empty( $custom_css ) ) {
		return '';
	}

	// Sanitize CSS content.
	$custom_css = wp_strip_all_tags( $custom_css );
	$custom_css = trim( $custom_css );

	if ( empty( $custom_css ) ) {
		return '';
	}

	// If scope selector is provided, scope the CSS to the specific element.
	if ( ! empty( $scope_selector ) ) {
		// Check if the CSS already contains a selector (has opening brace).
		$has_selector = ( strpos( $custom_css, '{' ) !== false );

		if ( ! $has_selector ) {
			// No selector in user's CSS - wrap with scope selector.
			// The CSS properties apply directly to the scoped element.
			$custom_css = trim( $custom_css );
			$custom_css = $scope_selector . ' { ' . $custom_css . ' }';
		} else {
			// User has provided their own selector.
			// Process each CSS rule separately to handle multiple rules.
			$custom_css      = trim( $custom_css );
			$processed_rules = array();

			// Match all CSS rules: selector { properties }.
			// This regex handles multiple rules in the CSS.
			if ( preg_match_all( '/([^{]+)\{([^}]+)\}/s', $custom_css, $matches, PREG_SET_ORDER ) ) {
				foreach ( $matches as $match ) {
					$user_selector   = trim( $match[1] );
					$user_properties = trim( $match[2] );

					// Determine the final selector based on the user's input.
					$final_selector = epofw_scope_css_selector( $user_selector, $scope_selector );

					$processed_rules[] = $final_selector . ' { ' . $user_properties . ' }';
				}
				$custom_css = implode( "\n", $processed_rules );
			} else {
				// If regex doesn't match, apply CSS directly to scope selector.
				$custom_css = $scope_selector . ' { ' . $custom_css . ' }';
			}
		}
	}

	/**
	 * Filter whether to add !important to custom CSS declarations.
	 *
	 * By default, !important is added to ensure custom CSS overrides inline styles.
	 * Developers can disable this behavior by returning false.
	 *
	 * @since 4.4.0
	 *
	 * @param bool   $add_important  Whether to add !important. Default true.
	 * @param string $custom_css     The custom CSS content.
	 * @param string $scope_selector The scope selector being used.
	 */
	$add_important = apply_filters( 'epofw_custom_css_add_important', true, $custom_css, $scope_selector );

	if ( $add_important ) {
		// Add !important to all CSS declarations to override inline styles.
		// This ensures custom CSS always takes precedence over inline styles set via UI settings.
		// We add !important only if it's not already present.
		$custom_css = preg_replace_callback(
			'/([^:]+):([^;!}]+)(;|})/',
			function( $matches ) {
				$property = $matches[1];
				$value    = trim( $matches[2] );
				$ending   = $matches[3];

				// Skip if already has !important.
				if ( strpos( $value, '!important' ) !== false ) {
					return $matches[0];
				}

				return $property . ': ' . $value . ' !important' . $ending;
			},
			$custom_css
		);
	}

	/**
	 * Filter the final custom CSS before output.
	 *
	 * Allows developers to modify the CSS content after all processing is done.
	 * Can be used to remove !important, add prefixes, or make other modifications.
	 *
	 * @since 4.4.0
	 *
	 * @param string $custom_css     The processed custom CSS content.
	 * @param string $scope_selector The scope selector being used.
	 */
	$custom_css = apply_filters( 'epofw_custom_css_output', $custom_css, $scope_selector );

	// Output the CSS directly without escaping.
	$style_output = '<style type="text/css">' . "\n" . $custom_css . "\n" . '</style>' . "\n";

	return $style_output;
}

/**
 * Scope a CSS selector intelligently.
 *
 * This function determines how to combine a user's CSS selector with a scope selector.
 * - If user selector targets the same element class as the scope, use scope selector directly.
 * - If user selector is a descendant (starts with a child combinator or different class), prepend scope.
 * - Handles pseudo-classes and pseudo-elements properly.
 *
 * @since 4.4.0
 *
 * @param string $user_selector  The user's CSS selector.
 * @param string $scope_selector The scope selector (e.g., '.epofw-row-group[data-group-id="123"]').
 * @return string The final scoped selector.
 */
function epofw_scope_css_selector( $user_selector, $scope_selector ) {
	$user_selector = trim( $user_selector );

	// If user selector is empty or just whitespace, use scope selector.
	if ( empty( $user_selector ) ) {
		return $scope_selector;
	}

	// Extract the base class from scope selector (e.g., '.epofw-row-group' from '.epofw-row-group[data-group-id="123"]').
	$scope_base_class = '';
	if ( preg_match( '/^([.#]?[a-zA-Z_-][a-zA-Z0-9_-]*)/', $scope_selector, $base_match ) ) {
		$scope_base_class = $base_match[1];
	}

	// Get the first part of user selector (before any space, pseudo-class, or attribute).
	$user_first_selector = $user_selector;
	if ( preg_match( '/^([.#]?[a-zA-Z_-][a-zA-Z0-9_-]*)/', $user_selector, $user_match ) ) {
		$user_first_selector = $user_match[1];
	}

	// Check if user selector starts with the same base class as the scope selector.
	// This handles cases like:
	// - User: ".epofw-row-group" vs Scope: ".epofw-row-group[data-group-id='123']".
	if ( ! empty( $scope_base_class ) && $user_first_selector === $scope_base_class ) {
		// User is targeting the same element type - replace their selector with scope selector.
		// Handle pseudo-classes/elements that may follow (e.g., ".epofw-row-group:hover").
		$remainder = substr( $user_selector, strlen( $user_first_selector ) );
		return $scope_selector . $remainder;
	}

	// For ID-based scope selectors (like #epofw-section-123), check if user is targeting.
	// A class that's on the SAME element (not a child).
	// The section wrapper has both ID and class on the same element.
	// Example: <div class="epofw-section-wrapper" id="epofw-section-1765283050363">.
	if ( strpos( $scope_selector, '#' ) === 0 ) {
		// Known classes that are on the same element as the ID (not children).
		// These are classes that exist on the section wrapper element itself.
		$same_element_classes = array(
			'.epofw-section-wrapper',
		);

		// Check if user selector starts with a known same-element class.
		if ( in_array( $user_first_selector, $same_element_classes, true ) ) {
			// User is targeting the same element - combine ID and class directly (no space).
			// This creates: #epofw-section-123.epofw-section-wrapper.
			$remainder = substr( $user_selector, strlen( $user_first_selector ) );
			return $scope_selector . $user_first_selector . $remainder;
		}

		// For other classes, treat as descendant selector.
		return $scope_selector . ' ' . $user_selector;
	}

	// For class-based scope selectors with attributes (like .epofw-row-group[data-group-id="123"]).
	// If user selector is different from the base class, treat it as targeting a descendant.
	return $scope_selector . ' ' . $user_selector;
}
