<?php
/**
 * A reusable Elementor trait and accompanying manager class for a comprehensive animation system.
 * This file encapsulates all logic for adding controls and rendering animation attributes,
 * avoiding global namespace pollution and promoting clean, maintainable code.
 *
 * @package Sifency\Traits
 */

namespace Sifency\Traits;

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

use Elementor\Controls_Manager;
use Sifency_Addons_Theme_Builder_Master;
use Elementor\Group_Control_Background;

// =============================================================================
// THE ELEMENTOR CONTROLS TRAIT
// =============================================================================

if ( ! trait_exists( 'Sifency\Traits\Sifency_Addons_Animation_Controls' ) ) {
	/**
	 * A reusable trait for adding a comprehensive animation control panel to Elementor widgets.
	 */
	trait Sifency_Addons_Animation_Controls {
		/**
		 * Provides the option arrays for different animation libraries.
		 *
		 * @param string $type The animation library type ('aos', 'wow', 'gsap').
		 * @return array
		 */
		protected function get_sifency_animation_options( $type ) {

			if ( class_exists( 'Sifency_Addons_Theme_Builder_Master' )
				&& method_exists( 'Sifency_Addons_Theme_Builder_Master', 'sync_environment_state' ) ) {
				$is_synce = Sifency_Addons_Theme_Builder_Master::sync_environment_state();
			} elseif ( function_exists( 'sifency_addons_is_pro' ) ) {
				$is_synce = sifency_addons_is_pro();
			} else {
				$is_synce = false;
			}

			$options = array(
				'aos'   => array(
					''                => __( 'None', 'sifency-addons' ),
					'fade'            => 'Fade',
					'fade-up'         => 'Fade Up',
					'fade-down'       => 'Fade Down',
					'fade-left'       => 'Fade Left',
					'fade-right'      => 'Fade Right',
					'fade-up-right'   => 'Fade Up Right',
					'fade-up-left'    => 'Fade Up Left',
					'fade-down-right' => 'Fade Down Right',
					'fade-down-left'  => 'Fade Down Left',
					'flip-up'         => 'Flip Up',
					'flip-down'       => 'Flip Down',
					'flip-left'       => 'Flip Left',
					'flip-right'      => 'Flip Right',
					'slide-up'        => 'Slide Up',
					'slide-down'      => 'Slide Down',
					'slide-left'      => 'Slide Left',
					'slide-right'     => 'Slide Right',
					'zoom-in'         => 'Zoom In',
					'zoom-in-up'      => 'Zoom In Up',
					'zoom-in-down'    => 'Zoom In Down',
					'zoom-in-left'    => 'Zoom In Left',
					'zoom-in-right'   => 'Zoom In Right',
					'zoom-out'        => 'Zoom Out',
					'zoom-out-up'     => 'Zoom Out Up',
					'zoom-out-down'   => 'Zoom Out Down',
					'zoom-out-left'   => 'Zoom Out Left',
					'zoom-out-right'  => 'Zoom Out Right',
				),
				'wow'   => array(
					''                  => __( 'None', 'sifency-addons' ),
					'bounce'            => 'Bounce',
					'flash'             => 'Flash',
					'pulse'             => 'Pulse',
					'rubberBand'        => 'Rubber Band',
					'shake'             => 'Shake',
					'swing'             => 'Swing',
					'tada'              => 'Tada',
					'wobble'            => 'Wobble',
					'jello'             => 'Jello',
					'heartBeat'         => 'Heart Beat',
					'bounceIn'          => 'Bounce In',
					'bounceInDown'      => 'Bounce In Down',
					'bounceInLeft'      => 'Bounce In Left',
					'bounceInRight'     => 'Bounce In Right',
					'bounceInUp'        => 'Bounce In Up',
					'fadeIn'            => 'Fade In',
					'fadeInDown'        => 'Fade In Down',
					'fadeInLeft'        => 'Fade In Left',
					'fadeInRight'       => 'Fade In Right',
					'fadeInUp'          => 'Fade In Up',
					'flip'              => 'Flip',
					'flipInX'           => 'Flip In X',
					'flipInY'           => 'Flip In Y',
					'lightSpeedIn'      => 'Light Speed In',
					'rotateIn'          => 'Rotate In',
					'rotateInDownLeft'  => 'Rotate In Down Left',
					'rotateInDownRight' => 'Rotate In Down Right',
					'rotateInUpLeft'    => 'Rotate In Up Left',
					'rotateInUpRight'   => 'Rotate In Up Right',
					'slideInUp'         => 'Slide In Up',
					'slideInDown'       => 'Slide In Down',
					'slideInLeft'       => 'Slide In Left',
					'slideInRight'      => 'Slide In Right',
					'zoomIn'            => 'Zoom In',
					'zoomInDown'        => 'Zoom In Down',
					'zoomInLeft'        => 'Zoom In Left',
					'zoomInRight'       => 'Zoom In Right',
					'zoomInUp'          => 'Zoom In Up',
					'hinge'             => 'Hinge',
					'jackInTheBox'      => 'Jack In The Box',
					'rollIn'            => 'Roll In',
				),
				'gsap'  => array(
					// ── None ──────────────────────────────────────────────────────────────────────
					''                      => __( 'None (Custom Only)', 'sifency-addons' ),

					// ── Fade ──────────────────────────────────────────────────────────────────────
					'sa-fade'               => __( 'Fade In', 'sifency-addons' ),
					'sa-fade-up'            => __( 'Fade In Up', 'sifency-addons' ),
					'sa-fade-down'          => __( 'Fade In Down', 'sifency-addons' ),
					'sa-fade-left'          => __( 'Fade In Left', 'sifency-addons' ),
					'sa-fade-right'         => __( 'Fade In Right', 'sifency-addons' ),
					'sa-fade-out'           => __( 'Fade Out', 'sifency-addons' ),
					'sa-fade-out-up'        => __( 'Fade Out Up', 'sifency-addons' ),
					'sa-fade-out-down'      => __( 'Fade Out Down', 'sifency-addons' ),

					// ── Slide ─────────────────────────────────────────────────────────────────────
					'sa-slide-up'           => __( 'Slide Up', 'sifency-addons' ),
					'sa-slide-down'         => __( 'Slide Down', 'sifency-addons' ),
					'sa-slide-left'         => __( 'Slide Left', 'sifency-addons' ),
					'sa-slide-right'        => __( 'Slide Right', 'sifency-addons' ),

					// ── Scale ─────────────────────────────────────────────────────────────────────
					'sa-scale-in'           => __( 'Scale In', 'sifency-addons' ),
					'sa-scale-out'          => __( 'Scale Out (Zoom)', 'sifency-addons' ),
					'sa-scale-x-in'         => __( 'Scale X In', 'sifency-addons' ),

					// ── Clip-Path Reveals ─────────────────────────────────────────────────────────
					'sa-clip-up'            => __( 'Clip Reveal Up', 'sifency-addons' ),
					'sa-clip-down'          => __( 'Clip Reveal Down', 'sifency-addons' ),
					'sa-clip-left'          => __( 'Clip Reveal Left', 'sifency-addons' ),
					'sa-clip-right'         => __( 'Clip Reveal Right', 'sifency-addons' ),
					'sa-clip-center'        => __( 'Clip Reveal Center', 'sifency-addons' ),
					'sa-clip-circle'        => __( 'Clip Reveal Circle', 'sifency-addons' ),
					'sa-clip-circle-top'    => __( 'Clip Reveal Circle (Top)', 'sifency-addons' ),
					'sa-clip-circle-bottom' => __( 'Clip Reveal Circle (Bottom)', 'sifency-addons' ),

					// ── Wipe ──────────────────────────────────────────────────────────────────────
					'sa-wipe-right'         => __( 'Wipe Right', 'sifency-addons' ),
					'sa-wipe-left'          => __( 'Wipe Left', 'sifency-addons' ),

					// ── Rotate ────────────────────────────────────────────────────────────────────
					'sa-rotate-in'          => __( 'Rotate In (CCW)', 'sifency-addons' ),
					'sa-rotate-cw'          => __( 'Rotate In (CW)', 'sifency-addons' ),
					'sa-rotate-tl'          => __( 'Rotate In (Top Left)', 'sifency-addons' ),
					'sa-rotate-tr'          => __( 'Rotate In (Top Right)', 'sifency-addons' ),
					'sa-rotate-bl'          => __( 'Rotate In (Bottom Left)', 'sifency-addons' ),
					'sa-rotate-br'          => __( 'Rotate In (Bottom Right)', 'sifency-addons' ),

					// ── Flip / 3-D ────────────────────────────────────────────────────────────────
					'sa-flip-x'             => __( 'Flip In X', 'sifency-addons' ),
					'sa-flip-y'             => __( 'Flip In Y', 'sifency-addons' ),
					'sa-swing-in'           => __( 'Swing In (3D Top)', 'sifency-addons' ),
					'sa-tilt-in'            => __( 'Tilt In (3D Left)', 'sifency-addons' ),

					// ── Skew ──────────────────────────────────────────────────────────────────────
					'sa-skew-up'            => __( 'Skew Up', 'sifency-addons' ),

					// ── Blur ──────────────────────────────────────────────────────────────────────
					'sa-blur-in'            => __( 'Blur In', 'sifency-addons' ),

					// ── Bounce ────────────────────────────────────────────────────────────────────
					'sa-bounce-in'          => __( 'Bounce In', 'sifency-addons' ),
					'sa-bounce-up'          => __( 'Bounce In Up', 'sifency-addons' ),

					// ── Elastic ───────────────────────────────────────────────────────────────────
					'sa-elastic-up'         => __( 'Elastic Up', 'sifency-addons' ),
					'sa-elastic-scale'      => __( 'Elastic Scale', 'sifency-addons' ),

					// ── Modern / Premium Reveals ──────────────────────────────────────────────────
					'sa-unmask-up'          => __( 'Unmask Up (Reveal)', 'sifency-addons' ),
					'sa-unmask-down'        => __( 'Unmask Down (Reveal)', 'sifency-addons' ),
					'sa-unmask-left'        => __( 'Unmask Left (Reveal)', 'sifency-addons' ),
					'sa-unmask-right'       => __( 'Unmask Right (Reveal)', 'sifency-addons' ),
					'sa-zoom-fade-in'       => __( 'Zoom & Fade In', 'sifency-addons' ),
					'sa-zoom-fade-out'      => __( 'Zoom & Fade Out', 'sifency-addons' ),
					'sa-blur-slide-up'      => __( 'Blur Slide Up', 'sifency-addons' ),
					'sa-perspective-up'     => __( 'Perspective Reveal Up', 'sifency-addons' ),
					'sa-perspective-down'   => __( 'Perspective Reveal Down', 'sifency-addons' ),
					'sa-reveal-curtain'     => __( 'Curtain Reveal (Center)', 'sifency-addons' ),
					'sa-reveal-split-v'     => __( 'Vertical Split Reveal', 'sifency-addons' ),

					// ── SVG ───────────────────────────────────────────────────────────────────────
					'sa-draw'               => __( 'Draw SVG Stroke', 'sifency-addons' ),

					// ── Stagger Text / Custom / Requested Presets ──────────────────────────────────
					'sa-reveal'             => __( 'Mask Reveal (Slide Up)', 'sifency-addons' ),
					'sa-scale'              => __( 'Scale & Fade In', 'sifency-addons' ),
					'sa-fade-in'            => __( 'Fade In', 'sifency-addons' ),
					'sa-fade-up-reveal'     => __( 'Fade Up', 'sifency-addons' ),
					'sa-fade-down-reveal'   => __( 'Fade In Down', 'sifency-addons' ),
					'sa-slide-left-reveal'  => __( 'Slide In Left', 'sifency-addons' ),
					'sa-slide-right-reveal' => __( 'Slide In Right', 'sifency-addons' ),
					'sa-mask-up'            => __( 'Mask Reveal (Slide Up)', 'sifency-addons' ),
					'sa-mask-down'          => __( 'Mask Reveal (Slide Down)', 'sifency-addons' ),
					'sa-mask-left'          => __( 'Mask Reveal (Slide Left)', 'sifency-addons' ),
					'sa-blur-in-reveal'     => __( 'Blur In Reveal', 'sifency-addons' ),
					'sa-typewriter'         => __( 'Typewriter Effect', 'sifency-addons' ),
					'sa-zoom-in'            => __( 'Zoom In / Scale', 'sifency-addons' ),
					'sa-zoom-out'           => __( 'Zoom Out', 'sifency-addons' ),
					'sa-letter-spacing'     => __( 'Letter Spacing Contract', 'sifency-addons' ),
					'sa-flip-x-reveal'      => __( '3D Flip X', 'sifency-addons' ),
					'sa-flip-y-reveal'      => __( '3D Flip Y', 'sifency-addons' ),
					'sa-rotate-3d'          => __( '3D Rotate & Twist', 'sifency-addons' ),
					'sa-perspective-tilt'   => __( 'Perspective Tilt', 'sifency-addons' ),
					'sa-swing'              => __( 'Swing In', 'sifency-addons' ),
					'sa-elastic-drop'       => __( 'Elastic Drop', 'sifency-addons' ),
					'sa-rubber-band'        => __( 'Rubber Band', 'sifency-addons' ),
					'sa-jello'              => __( 'Jello Effect', 'sifency-addons' ),
					'sa-glitch-in'          => __( 'Glitch In (Opacity/X)', 'sifency-addons' ),
					'sa-wobble'             => __( 'Wobble Drop', 'sifency-addons' ),
					'sa-random-scatter'     => __( 'Random Scatter', 'sifency-addons' ),
				),
				'lenis' => array(
					''            => __( 'None', 'sifency-addons' ),
					'parallax_y'  => __( 'Vertical Parallax', 'sifency-addons' ),
					'parallax_x'  => __( 'Horizontal Parallax', 'sifency-addons' ),
					'scale'       => __( 'Scale on Scroll', 'sifency-addons' ),
					'fade'        => __( 'Fade on Scroll', 'sifency-addons' ),
					'rotate'      => __( 'Rotation', 'sifency-addons' ),
					'flip_x'      => __( '3D Flip (Vertical)', 'sifency-addons' ),
					'flip_y'      => __( '3D Flip (Horizontal)', 'sifency-addons' ),
					'skew'        => __( 'Skew Effect', 'sifency-addons' ),
					'blur'        => __( 'Blur Effect', 'sifency-addons' ),
					'zoom_rotate' => __( 'Zoom & Rotate Combo', 'sifency-addons' ),
					'arc'         => __( 'Arc Movement', 'sifency-addons' ),
					'depth'       => __( '3D Depth (Z-Axis)', 'sifency-addons' ),
				),
				'anime' => array(
					''              => __( 'None', 'sifency-addons' ),
					'fade-in'       => __( 'Fade In', 'sifency-addons' ),
					'fade-up'       => __( 'Fade Up', 'sifency-addons' ),
					'fade-down'     => __( 'Fade Down', 'sifency-addons' ),
					'fade-left'     => __( 'Fade Left', 'sifency-addons' ),
					'fade-right'    => __( 'Fade Right', 'sifency-addons' ),
					'slide-up'      => __( 'Slide Up', 'sifency-addons' ),
					'slide-down'    => __( 'Slide Down', 'sifency-addons' ),
					'slide-left'    => __( 'Slide Left', 'sifency-addons' ),
					'slide-right'   => __( 'Slide Right', 'sifency-addons' ),
					'zoom-in'       => __( 'Zoom In', 'sifency-addons' ),
					'zoom-out'      => __( 'Zoom Out', 'sifency-addons' ),
					'rotate-in'     => __( 'Rotate In', 'sifency-addons' ),
					'flip-x'        => __( 'Flip X (3D)', 'sifency-addons' ),
					'flip-y'        => __( 'Flip Y (3D)', 'sifency-addons' ),
					'elastic-up'    => __( 'Elastic Up', 'sifency-addons' ),
					'elastic-scale' => __( 'Elastic Scale', 'sifency-addons' ),
					'bounce-in'     => __( 'Bounce In', 'sifency-addons' ),
					'blur-in'       => __( 'Blur In', 'sifency-addons' ),
					'skew-up'       => __( 'Skew Up', 'sifency-addons' ),
					'rubber-band'   => __( 'Rubber Band', 'sifency-addons' ),
					'wobble'        => __( 'Wobble', 'sifency-addons' ),
				),
				'barba' => array(
					'fade'        => __( 'Fade', 'sifency-addons' ),
					'slide-left'  => __( 'Slide Left', 'sifency-addons' ),
					'slide-right' => __( 'Slide Right', 'sifency-addons' ),
					'slide-up'    => __( 'Slide Up', 'sifency-addons' ),
					'slide-down'  => __( 'Slide Down', 'sifency-addons' ),
					'zoom-in'     => __( 'Zoom In', 'sifency-addons' ),
					'clip-reveal' => __( 'Clip Reveal', 'sifency-addons' ),
					'wipe'        => __( 'Wipe', 'sifency-addons' ),
				),
			);

			if ( ! $is_synce ) {
				$synce_keys = array( 'wow', 'gsap', 'lenis', 'anime', 'barba' );

				foreach ( $synce_keys as $synce_key ) {
					if ( isset( $options[ $synce_key ] ) ) {
						foreach ( $options[ $synce_key ] as $anim_value => $anim_label ) {
							if ( $anim_value !== '' ) {
								$options[ $synce_key ][ $anim_value ] = $anim_label . ' 🔒';
							}
						}
					}
				}
			}

			return isset( $options[ $type ] ) ? $options[ $type ] : array();
		}

		/**
		 * Adds the complete animation control panel to the current widget instance.
		 */
		public function add_Sifency_Addons_Animation_Controls( $element = null ) {
			$obj = $element ? $element : $this;
			$tab = Controls_Manager::TAB_ADVANCED;
			if ( class_exists( 'Sifency_Addons_Theme_Builder_Master' )
				&& method_exists( 'Sifency_Addons_Theme_Builder_Master', 'sync_environment_state' ) ) {
				$is_synce = Sifency_Addons_Theme_Builder_Master::sync_environment_state();
			} elseif ( function_exists( 'sifency_addons_is_pro' ) ) {
				$is_synce = sifency_addons_is_pro();
			} else {
				$is_synce = false;
			}

			// For layout elements, we can optionally put it in Layout,
			// but the user's screenshot showed the Advanced tab, so let's stick to Advanced or provide an option.
			// We'll use TAB_ADVANCED as it's the standard for Motion Effects/Animations.
			$obj->start_controls_section(
				'sifency_animation_section',
				array(
					'label' => __( 'Sifency Animations', 'sifency-addons' ),
					'tab'   => $tab,
				)
			);

			$aos_condition    = array( 'sifency_animation_type' => 'aos' );
			$wow_condition    = array( 'sifency_animation_type' => 'wow' );
			$gsap_condition   = array( 'sifency_animation_type' => 'gsap' );
			$lenis_condition  = array( 'sifency_animation_type' => 'lenis' );
			$custom_condition = array( 'sifency_animation_type' => 'custom' );
			$anime_condition  = array( 'sifency_animation_type' => 'anime' );
			$barba_condition  = array( 'sifency_animation_type' => 'barba' );
			$obj->add_control(
				'sifency_animation_type',
				array(
					'label'   => __( 'Animation Library', 'sifency-addons' ),
					'type'    => Controls_Manager::SELECT,
					'options' => array(
						''       => __( 'None', 'sifency-addons' ),
						'aos'    => __( 'AOS', 'sifency-addons' ),
						'wow'    => $is_synce ? __( 'WOW.js', 'sifency-addons' ) : __( 'WOW.js 🔒', 'sifency-addons' ),
						'gsap'   => $is_synce ? __( 'GSAP (Advanced)', 'sifency-addons' ) : __( 'GSAP (Advanced) 🔒', 'sifency-addons' ),
						'lenis'  => $is_synce ? __( 'Lenis Scroll Effects', 'sifency-addons' ) : __( 'Lenis Scroll Effects 🔒', 'sifency-addons' ),
						'anime'  => $is_synce ? __( 'Anime.js', 'sifency-addons' ) : __( 'Anime.js 🔒', 'sifency-addons' ),
						'barba'  => $is_synce ? __( 'Barba.js (Page Transitions)', 'sifency-addons' ) : __( 'Barba.js (Page Transitions) 🔒', 'sifency-addons' ),
						'custom' => $is_synce ? __( 'Custom Attributes', 'sifency-addons' ) : __( 'Custom Attributes 🔒', 'sifency-addons' ),
					),
					'default' => '',
				)
			);
			$obj->add_control(
				'sifency_animation_target',
				array(
					'label'       => __( 'Apply Animation To', 'sifency-addons' ),
					'type'        => Controls_Manager::CHOOSE,
					'options'     => array(
						'masterwrapper' => array(
							'title' => __( 'Master Wrapper', 'sifency-addons' ),
							'icon'  => 'eicon-container',
						),
						'wrapper'       => array(
							'title' => __( 'Widget Wrapper', 'sifency-addons' ),
							'icon'  => 'eicon-element-wrapper',
						),
						'child'         => array(
							'title' => __( 'Child Items', 'sifency-addons' ),
							'icon'  => 'eicon-bullet-list',
						),
						'custom'        => array(
							'title' => __( 'Custom Class', 'sifency-addons' ),
							'icon'  => 'eicon-cog',
						),
					),
					'default'     => 'masterwrapper',
					'toggle'      => false,
					'description' => __( 'Animate the Master Wrapper, internal Widget Wrapper, individual Child items, or a Custom Class.', 'sifency-addons' ),
					'separator'   => 'before',
				)
			);

			$obj->add_control(
				'sifency_animation_classname',
				array(
					'label'       => __( 'Custom Class Name', 'sifency-addons' ),
					'type'        => Controls_Manager::TEXT,
					'placeholder' => '.my-custom-class',
					'description' => __( 'Enter the specific CSS class to animate (e.g., .my-class).', 'sifency-addons' ),
					'condition'   => array( 'sifency_animation_target' => 'custom' ),
				)
			);
			$obj->add_control(
				'sifency_animation_stagger_delay',
				array(
					'label'       => __( 'Stagger Duration Gap', 'sifency-addons' ),
					'type'        => Controls_Manager::SLIDER,
					'size_units'  => array( 'ms', 's' ),
					'range'       => array(
						'ms' => array(
							'min'  => 0,
							'max'  => 2000,
							'step' => 10,
						),
						's'  => array(
							'min'  => 0,
							'max'  => 2,
							'step' => 0.1,
						),
					),
					'default'     => array(
						'unit' => 'ms',
						'size' => 100,
					),
					'description' => __( 'Time duration gap between each child item appearing.', 'sifency-addons' ),
					'condition'   => array(
						'sifency_animation_target' => 'child',
						'sifency_animation_type!'  => array( '', 'lenis' ),
					),
				)
			);
			$obj->add_control(
				'sifency_aos_animation',
				array(
					'label'     => __( 'AOS Animation', 'sifency-addons' ),
					'type'      => Controls_Manager::SELECT,
					'options'   => $this->get_sifency_animation_options( 'aos' ),
					'default'   => 'fade-up',
					'condition' => $aos_condition,
				)
			);
			$aos_sub_condition = array_merge( $aos_condition, array( 'sifency_aos_animation!' => '' ) );
			$obj->add_control(
				'sifency_aos_duration',
				array(
					'label'     => __( 'Duration (ms)', 'sifency-addons' ),
					'type'      => Controls_Manager::NUMBER,
					'min'       => 100,
					'max'       => 3000,
					'step'      => 50,
					'condition' => $aos_sub_condition,
					'selectors' => array( '{{WRAPPER}}' => '--aos-duration: {{VALUE}}ms;' ),
				)
			);
			$obj->add_control(
				'sifency_aos_delay',
				array(
					'label'     => __( 'Delay (ms)', 'sifency-addons' ),
					'type'      => Controls_Manager::NUMBER,
					'min'       => 0,
					'step'      => 50,
					'condition' => $aos_sub_condition,
				)
			);
			$obj->add_control(
				'sifency_aos_offset',
				array(
					'label'     => __( 'Offset (px)', 'sifency-addons' ),
					'type'      => Controls_Manager::SLIDER,
					'range'     => array(
						'px' => array(
							'min'  => 0,
							'max'  => 500,
							'step' => 10,
						),
					),
					'condition' => $aos_sub_condition,
				)
			);
			$obj->add_control(
				'aos_once_switch',
				array(
					'label'     => __( 'Animate Once', 'sifency-addons' ),
					'type'      => Controls_Manager::SWITCHER,
					'condition' => $aos_condition,
				)
			);
			$obj->add_control(
				'sifency_aos_easing',
				array(
					'label'     => __( 'Easing', 'sifency-addons' ),
					'type'      => Controls_Manager::SELECT,
					'options'   => array(
						'ease'          => 'Ease',
						'linear'        => 'Linear',
						'ease-in-out'   => 'Ease In Out',
						'ease-in-back'  => 'Ease In Back',
						'ease-out-back' => 'Ease Out Back',
					),
					'default'   => 'ease-out-cubic',
					'condition' => $aos_sub_condition,
				)
			);
			$obj->add_control(
				'sifency_wow_animation',
				array(
					'label'     => __( 'WOW Animation', 'sifency-addons' ),
					'type'      => Controls_Manager::SELECT,
					'options'   => $this->get_sifency_animation_options( 'wow' ),
					'default'   => 'none',
					'condition' => $wow_condition,
				)
			);
			$wow_sub_condition = array_merge( $wow_condition, array( 'sifency_wow_animation!' => '' ) );
			$obj->add_control(
				'sifency_wow_duration',
				array(
					'label'     => __( 'Duration (s)', 'sifency-addons' ),
					'type'      => Controls_Manager::TEXT,
					'default'   => '1s',
					'condition' => $wow_sub_condition,
				)
			);
			$obj->add_control(
				'sifency_wow_delay',
				array(
					'label'     => __( 'Delay (s)', 'sifency-addons' ),
					'type'      => Controls_Manager::TEXT,
					'default'   => '0.2s',
					'condition' => $wow_sub_condition,
				)
			);
			$obj->add_control(
				'sifency_wow_offset',
				array(
					'label'       => __( 'Offset', 'sifency-addons' ),
					'type'        => Controls_Manager::NUMBER,
					'placeholder' => '10',
					'condition'   => $wow_sub_condition,
				)
			);
			$obj->add_control(
				'sifency_wow_iteration',
				array(
					'label'       => __( 'Iteration', 'sifency-addons' ),
					'type'        => Controls_Manager::NUMBER,
					'placeholder' => '1',
					'condition'   => $wow_sub_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_animation',
				array(
					'label'     => __( 'GSAP Preset', 'sifency-addons' ),
					'type'      => Controls_Manager::SELECT,
					'options'   => $this->get_sifency_animation_options( 'gsap' ),
					'condition' => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_type_heading',
				array(
					'label'     => __( 'Specialized Animations', 'sifency-addons' ),
					'type'      => Controls_Manager::HEADING,
					'separator' => 'before',
					'condition' => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_stack_cards',
				array(
					'label'       => __( 'Pinned Stacking Cards', 'sifency-addons' ),
					'type'        => Controls_Manager::SWITCHER,
					'description' => __( 'Pins the container and stacks child items like a deck of cards as you scroll.', 'sifency-addons' ),
					'condition'   => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_stagger_children',
				array(
					'label'     => __( 'Stagger Children', 'sifency-addons' ),
					'type'      => Controls_Manager::SWITCHER,
					'condition' => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_split_text',
				array(
					'label'     => __( 'Split Text Animation', 'sifency-addons' ),
					'type'      => Controls_Manager::SWITCHER,
					'condition' => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_focus_text',
				array(
					'label'     => __( 'Focus In Text Effect', 'sifency-addons' ),
					'type'      => Controls_Manager::SWITCHER,
					'condition' => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_scale_text',
				array(
					'label'     => __( 'Scale Text on Scroll', 'sifency-addons' ),
					'type'      => Controls_Manager::SWITCHER,
					'condition' => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_cursor_heading',
				array(
					'label'     => __( 'Custom Cursor on Hover', 'sifency-addons' ),
					'type'      => Controls_Manager::HEADING,
					'separator' => 'before',
					'condition' => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_custom_cursor',
				array(
					'label'       => __( 'Enable Custom Cursor', 'sifency-addons' ),
					'type'        => Controls_Manager::SWITCHER,
					'description' => __( 'Shows a floating cursor with custom text when the selected animation target is hovered.', 'sifency-addons' ),
					'condition'   => $gsap_condition,
				)
			);
			$cursor_condition = array_merge( $gsap_condition, array( 'sifency_gsap_custom_cursor' => 'yes' ) );
			$obj->add_control(
				'sifency_gsap_cursor_text',
				array(
					'label'       => __( 'Cursor Text', 'sifency-addons' ),
					'type'        => Controls_Manager::TEXT,
					'default'     => __( 'View', 'sifency-addons' ),
					'placeholder' => __( 'View', 'sifency-addons' ),
					'condition'   => $cursor_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_cursor_style',
				array(
					'label'     => __( 'Cursor Style', 'sifency-addons' ),
					'type'      => Controls_Manager::SELECT,
					'default'   => 'default',
					'options'   => array(
						'default'   => __( 'Default', 'sifency-addons' ),
						'accent'    => __( 'Accent', 'sifency-addons' ),
						'outline'   => __( 'Outline', 'sifency-addons' ),
						'permanent' => __( 'Permanent Text', 'sifency-addons' ),
					),
					'condition' => $cursor_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_cursor_size',
				array(
					'label'      => __( 'Cursor Size', 'sifency-addons' ),
					'type'       => Controls_Manager::SLIDER,
					'size_units' => array( 'px' ),
					'range'      => array(
						'px' => array(
							'min'  => 40,
							'max'  => 240,
							'step' => 1,
						),
					),
					'default'    => array(
						'unit' => 'px',
						'size' => 96,
					),
					'condition'  => $cursor_condition,
				)
			);
			$obj->add_group_control(
				Group_Control_Background::get_type(),
				array(
					'name'           => 'sifency_gsap_cursor_bg',
					'label'          => __( 'Cursor Background', 'sifency-addons' ),
					'types'          => array( 'classic', 'gradient' ),
					'exclude'        => array( 'image' ),
					'fields_options' => array(
						'background' => array( 'label' => __( 'Cursor Background', 'sifency-addons' ) ),
					),
					'condition'      => $cursor_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_cursor_color',
				array(
					'label'     => __( 'Cursor Text Color', 'sifency-addons' ),
					'type'      => Controls_Manager::COLOR,
					'condition' => $cursor_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_cursor_border',
				array(
					'label'     => __( 'Cursor Border Color', 'sifency-addons' ),
					'type'      => Controls_Manager::COLOR,
					'condition' => $cursor_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_settings_heading',
				array(
					'label'     => __( 'Core Animation Settings', 'sifency-addons' ),
					'type'      => Controls_Manager::HEADING,
					'separator' => 'before',
					'condition' => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_duration',
				array(
					'label'     => __( 'Duration (s)', 'sifency-addons' ),
					'type'      => Controls_Manager::NUMBER,
					'min'       => 0,
					'max'       => 10,
					'step'      => 0.1,
					'default'   => 1.2,
					'condition' => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_delay',
				array(
					'label'     => __( 'Delay (s)', 'sifency-addons' ),
					'type'      => Controls_Manager::NUMBER,
					'min'       => 0,
					'max'       => 10,
					'step'      => 0.1,
					'default'   => 0,
					'condition' => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_ease',
				array(
					'label'       => __( 'Easing', 'sifency-addons' ),
					'type'        => Controls_Manager::SELECT,
					'default'     => 'power4.out',
					'options'     => array(
						'none'          => 'none',
						'linear'        => 'linear',
						'power0.in'     => 'power0.in',
						'power0.out'    => 'power0.out',
						'power0.inOut'  => 'power0.inOut',
						'power1.in'     => 'power1.in',
						'power1.out'    => 'power1.out',
						'power1.inOut'  => 'power1.inOut',
						'power2.in'     => 'power2.in',
						'power2.out'    => 'power2.out',
						'power2.inOut'  => 'power2.inOut',
						'power3.in'     => 'power3.in',
						'power3.out'    => 'power3.out',
						'power3.inOut'  => 'power3.inOut',
						'power4.in'     => 'power4.in',
						'power4.out'    => 'power4.out',
						'power4.inOut'  => 'power4.inOut',
						'back.in'       => 'back.in',
						'back.out'      => 'back.out',
						'back.inOut'    => 'back.inOut',
						'elastic.in'    => 'elastic.in',
						'elastic.out'   => 'elastic.out',
						'elastic.inOut' => 'elastic.inOut',
						'bounce.in'     => 'bounce.in',
						'bounce.out'    => 'bounce.out',
						'bounce.inOut'  => 'bounce.inOut',
						'rough'         => 'rough',
						'slow'          => 'slow',
						'steps(5)'      => 'steps(5)',
						'circ.in'       => 'circ.in',
						'circ.out'      => 'circ.out',
						'circ.inOut'    => 'circ.inOut',
						'expo.in'       => 'expo.in',
						'expo.out'      => 'expo.out',
						'expo.inOut'    => 'expo.inOut',
						'sine.in'       => 'sine.in',
						'sine.out'      => 'sine.out',
						'sine.inOut'    => 'sine.inOut',
					),
					'condition'   => array( 'sifency_animation_type' => 'gsap' ),
					'description' => __( 'Choose a GSAP easing function. For advanced cases like "elastic.out(1, 0.3)", use the custom JS field.', 'sifency-addons' ),
				)
			);
			$obj->add_control(
				'sifency_gsap_scroll_heading',
				array(
					'label'     => __( 'ScrollTrigger Settings', 'sifency-addons' ),
					'type'      => Controls_Manager::HEADING,
					'separator' => 'before',
					'condition' => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_start',
				array(
					'label'     => __( 'Trigger Start', 'sifency-addons' ),
					'type'      => Controls_Manager::TEXT,
					'default'   => 'top 85%',
					'condition' => $gsap_condition,
				)
			);

			$obj->add_control(
				'sifency_gsap_scrub_switch',
				array(
					'label'       => __( 'Connect to Scroll (Scrub)', 'sifency-addons' ),
					'type'        => Controls_Manager::SWITCHER,
					'condition'   => $gsap_condition,
					'description' => __( 'Animation progress follows the scrollbar position.', 'sifency-addons' ),
				)
			);

			$obj->add_control(
				'sifency_gsap_scroll_snap',
				array(
					'label'       => __( 'Scroll Snap', 'sifency-addons' ),
					'type'        => Controls_Manager::SWITCHER,
					'condition'   => array_merge( $gsap_condition, array( 'sifency_gsap_scrub_switch' => 'yes' ) ),
					'description' => __( 'Snaps the scroll position when the user stops scrolling (requires scrub).', 'sifency-addons' ),
				)
			);

			$obj->add_control(
				'sifency_gsap_scroll_snap_value',
				array(
					'label'       => __( 'Snap Value', 'sifency-addons' ),
					'type'        => Controls_Manager::TEXT,
					'default'     => '1',
					'condition'   => array_merge(
						$gsap_condition,
						array(
							'sifency_gsap_scrub_switch' => 'yes',
							'sifency_gsap_scroll_snap'  => 'yes',
						)
					),
					'description' => __( 'Can be a number (e.g., 0.5 or 1) or an array like [0, 0.5, 1]', 'sifency-addons' ),
				)
			);

			$obj->add_control(
				'sifency_gsap_scrub_lag',
				array(
					'label'      => __( 'Scrub Smoothness (Lag)', 'sifency-addons' ),
					'type'       => Controls_Manager::SLIDER,
					'size_units' => array( 's' ),
					'range'      => array(
						's' => array(
							'min'  => 0,
							'max'  => 3,
							'step' => 0.1,
						),
					),
					'default'    => array(
						'unit' => 's',
						'size' => 1,
					),
					'condition'  => array_merge( $gsap_condition, array( 'sifency_gsap_scrub_switch' => 'yes' ) ),
				)
			);

			$obj->add_control(
				'sifency_gsap_scroll_height',
				array(
					'label'       => __( 'Scroll Distance (px)', 'sifency-addons' ),
					'type'        => Controls_Manager::SLIDER,
					'size_units'  => array( 'px' ),
					'range'       => array(
						'px' => array(
							'min'  => 0,
							'max'  => 3000,
							'step' => 50,
						),
					),
					'default'     => array(
						'unit' => 'px',
						'size' => 0,
					),
					'condition'   => array_merge( $gsap_condition, array( 'sifency_gsap_scrub_switch' => 'yes' ) ),
					'description' => __( 'Extra scroll distance (px) for the scrub animation to complete. Increase this if content disappears before the animation finishes (e.g. clip reveal).', 'sifency-addons' ),
				)
			);

			$obj->add_control(
				'sifency_gsap_replay',
				array(
					'label'       => __( 'Re-animate on Scroll Up', 'sifency-addons' ),
					'type'        => Controls_Manager::SWITCHER,
					'condition'   => array_merge( $gsap_condition, array( 'sifency_gsap_scrub_switch!' => 'yes' ) ),
					'description' => __( 'Restart the animation every time it enters the viewport (scrolling up or down).', 'sifency-addons' ),
				)
			);
			$obj->add_control(
				'sifency_gsap_toggle_class',
				array(
					'label'     => __( 'Toggle Class', 'sifency-addons' ),
					'type'      => Controls_Manager::TEXT,
					'default'   => 'is-active',
					'condition' => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_markers',
				array(
					'label'     => __( 'Show Markers (Debug)', 'sifency-addons' ),
					'type'      => Controls_Manager::SWITCHER,
					'condition' => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_stagger_value',
				array(
					'label'     => __( 'JS Stagger Delay (s)', 'sifency-addons' ),
					'type'      => Controls_Manager::SLIDER,
					'range'     => array(
						'px' => array(
							'min'  => 0,
							'max'  => 3,
							'step' => 0.05,
						),
					),
					'default'   => array( 'size' => 0.1 ),
					'condition' => array_merge( $gsap_condition, array( 'sifency_gsap_stagger_children' => 'yes' ) ),
				)
			);
			$obj->add_control(
				'sifency_gsap_stack_offset',
				array(
					'label'     => __( 'Stack Top Offset (px)', 'sifency-addons' ),
					'type'      => Controls_Manager::NUMBER,
					'default'   => 40,
					'condition' => array_merge( $gsap_condition, array( 'sifency_gsap_stack_cards' => 'yes' ) ),
				)
			);
			$obj->add_control(
				'sifency_gsap_stack_scale',
				array(
					'label'     => __( 'Scale Down Previous Cards', 'sifency-addons' ),
					'type'      => Controls_Manager::SWITCHER,
					'default'   => 'yes',
					'condition' => array_merge( $gsap_condition, array( 'sifency_gsap_stack_cards' => 'yes' ) ),
				)
			);
			$obj->add_control(
				'sifency_gsap_split_by',
				array(
					'label'     => __( 'Split By', 'sifency-addons' ),
					'type'      => Controls_Manager::SELECT,
					'options'   => array(
						'chars'             => __( 'Characters', 'sifency-addons' ),
						'words'             => __( 'Words', 'sifency-addons' ),
						'lines'             => __( 'Lines', 'sifency-addons' ),
						'chars,words,lines' => __( 'All (Chars)', 'sifency-addons' ),
					),
					'default'   => 'lines',
					'condition' => array_merge( $gsap_condition, array( 'sifency_gsap_split_text' => 'yes' ) ),
				)
			);
			$obj->add_control(
				'sifency_gsap_focus_max_blur',
				array(
					'label'     => __( 'Max Blur (px)', 'sifency-addons' ),
					'type'      => Controls_Manager::NUMBER,
					'default'   => 8,
					'condition' => array_merge( $gsap_condition, array( 'sifency_gsap_focus_text' => 'yes' ) ),
				)
			);
			$obj->add_control(
				'sifency_gsap_focus_stagger',
				array(
					'label'     => __( 'Focus Duration (s)', 'sifency-addons' ),
					'type'      => Controls_Manager::NUMBER,
					'default'   => 0.5,
					'condition' => array_merge( $gsap_condition, array( 'sifency_gsap_focus_text' => 'yes' ) ),
				)
			);
			$obj->add_control(
				'sifency_gsap_focus_from',
				array(
					'label'     => __( 'Focus Direction', 'sifency-addons' ),
					'type'      => Controls_Manager::CHOOSE,
					'options'   => array(
						'start'  => array(
							'title' => 'Left to Right',
							'icon'  => 'eicon-h-align-left',
						),
						'center' => array(
							'title' => 'Center Out',
							'icon'  => 'eicon-h-align-center',
						),
						'end'    => array(
							'title' => 'Right to Left',
							'icon'  => 'eicon-h-align-right',
						),
					),
					'default'   => 'center',
					'toggle'    => false,
					'condition' => array( 'sifency_animation_type' => 'gsap' ),
				)
			);
			$obj->add_control(
				'sifency_gsap_parallax',
				array(
					'label'     => __( 'Enable Parallax', 'sifency-addons' ),
					'type'      => Controls_Manager::SWITCHER,
					'condition' => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_parallax_y',
				array(
					'label'       => __( 'Parallax Y', 'sifency-addons' ),
					'type'        => Controls_Manager::NUMBER,
					'placeholder' => '-150',
					'condition'   => array_merge( $gsap_condition, array( 'sifency_gsap_parallax' => 'yes' ) ),
				)
			);
			$obj->add_control(
				'sifency_gsap_parallax_x',
				array(
					'label'       => __( 'Parallax X', 'sifency-addons' ),
					'type'        => Controls_Manager::NUMBER,
					'placeholder' => '100',
					'condition'   => array_merge( $gsap_condition, array( 'sifency_gsap_parallax' => 'yes' ) ),
				)
			);
			$obj->add_control(
				'sifency_gsap_start_size',
				array(
					'label'     => __( 'Start Font Size', 'sifency-addons' ),
					'type'      => Controls_Manager::TEXT,
					'default'   => '2rem',
					'condition' => array_merge( $gsap_condition, array( 'sifency_gsap_scale_text' => 'yes' ) ),
				)
			);
			$obj->add_control(
				'sifency_gsap_end_size',
				array(
					'label'     => __( 'End Font Size', 'sifency-addons' ),
					'type'      => Controls_Manager::TEXT,
					'default'   => '15rem',
					'condition' => array_merge( $gsap_condition, array( 'sifency_gsap_scale_text' => 'yes' ) ),
				)
			);
			$obj->add_control(
				'sifency_gsap_custom_heading',
				array(
					'label'     => __( 'Fully Custom Animation', 'sifency-addons' ),
					'type'      => Controls_Manager::HEADING,
					'separator' => 'before',
					'condition' => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_from',
				array(
					'label'       => __( 'Custom "From" Properties', 'sifency-addons' ),
					'type'        => Controls_Manager::TEXTAREA,
					'placeholder' => '{"opacity": 0, "y": 50}',
					'condition'   => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_gsap_to',
				array(
					'label'       => __( 'Custom "To" Properties', 'sifency-addons' ),
					'type'        => Controls_Manager::TEXTAREA,
					'placeholder' => '{"opacity": 1, "y": 0}',
					'condition'   => $gsap_condition,
				)
			);
			$obj->add_control(
				'sifency_custom_attributes',
				array(
					'label'       => __( 'Custom Attributes', 'sifency-addons' ),
					'type'        => Controls_Manager::TEXTAREA,
					'rows'        => 5,
					'description' => __( 'Enter pairs like: key="value" key2="value2"', 'sifency-addons' ),
					'condition'   => $custom_condition,
				)
			);
			$obj->add_control(
				'sifency_lenis_effect',
				array(
					'label'     => __( 'Scroll Effect', 'sifency-addons' ),
					'type'      => Controls_Manager::SELECT,
					'options'   => $this->get_sifency_animation_options( 'lenis' ),
					'condition' => $lenis_condition,
				)
			);
			$obj->add_control(
				'sifency_lenis_speed',
				array(
					'label'       => __( 'Effect Intensity / Speed', 'sifency-addons' ),
					'type'        => Controls_Manager::SLIDER,
					'range'       => array(
						'px' => array(
							'min'  => -5,
							'max'  => 5,
							'step' => 0.1,
						),
					),
					'default'     => array( 'size' => 1 ),
					'condition'   => array_merge( $lenis_condition, array( 'sifency_lenis_effect!' => '' ) ),
					'description' => __( 'Negative values reverse the direction. E.g., -1 moves up, 1 moves down.', 'sifency-addons' ),
				)
			);

			$obj->add_control(
				'sifency_lenis_stagger',
				array(
					'label'       => __( 'Stagger Offset', 'sifency-addons' ),
					'type'        => Controls_Manager::NUMBER,
					'min'         => 0,
					'step'        => 0.1,
					'default'     => 0.2,
					'condition'   => array_merge( $lenis_condition, array( 'sifency_animation_target' => 'child' ) ),
					'description' => __( 'Difference in speed/offset for child items to create a wave effect.', 'sifency-addons' ),
				)
			);

			// ── Anime.js Controls ──────────────────────────────────────────────────────────
			$obj->add_control(
				'sifency_anime_heading',
				array(
					'label'     => __( 'Anime.js Settings', 'sifency-addons' ),
					'type'      => Controls_Manager::HEADING,
					'separator' => 'before',
					'condition' => $anime_condition,
				)
			);
			$obj->add_control(
				'sifency_anime_preset',
				array(
					'label'     => __( 'Animation Preset', 'sifency-addons' ),
					'type'      => Controls_Manager::SELECT,
					'options'   => $this->get_sifency_animation_options( 'anime' ),
					'default'   => 'fade-up',
					'condition' => $anime_condition,
				)
			);
			$obj->add_control(
				'sifency_anime_duration',
				array(
					'label'     => __( 'Duration (ms)', 'sifency-addons' ),
					'type'      => Controls_Manager::NUMBER,
					'min'       => 100,
					'max'       => 5000,
					'step'      => 50,
					'default'   => 800,
					'condition' => $anime_condition,
				)
			);
			$obj->add_control(
				'sifency_anime_delay',
				array(
					'label'     => __( 'Delay (ms)', 'sifency-addons' ),
					'type'      => Controls_Manager::NUMBER,
					'min'       => 0,
					'max'       => 3000,
					'step'      => 50,
					'default'   => 0,
					'condition' => $anime_condition,
				)
			);
			$obj->add_control(
				'sifency_anime_easing',
				array(
					'label'     => __( 'Easing', 'sifency-addons' ),
					'type'      => Controls_Manager::SELECT,
					'default'   => 'easeOutQuart',
					'options'   => array(
						'linear'             => 'Linear',
						'easeInQuad'         => 'Ease In Quad',
						'easeOutQuad'        => 'Ease Out Quad',
						'easeInOutQuad'      => 'Ease In Out Quad',
						'easeInCubic'        => 'Ease In Cubic',
						'easeOutCubic'       => 'Ease Out Cubic',
						'easeInOutCubic'     => 'Ease In Out Cubic',
						'easeInQuart'        => 'Ease In Quart',
						'easeOutQuart'       => 'Ease Out Quart',
						'easeInOutQuart'     => 'Ease In Out Quart',
						'easeInSine'         => 'Ease In Sine',
						'easeOutSine'        => 'Ease Out Sine',
						'easeInOutSine'      => 'Ease In Out Sine',
						'easeInExpo'         => 'Ease In Expo',
						'easeOutExpo'        => 'Ease Out Expo',
						'easeInOutExpo'      => 'Ease In Out Expo',
						'easeInElastic'      => 'Ease In Elastic',
						'easeOutElastic'     => 'Ease Out Elastic (Spring)',
						'easeInOutElastic'   => 'Ease In Out Elastic',
						'easeInBack'         => 'Ease In Back',
						'easeOutBack'        => 'Ease Out Back',
						'easeInOutBack'      => 'Ease In Out Back',
						'easeInBounce'       => 'Ease In Bounce',
						'easeOutBounce'      => 'Ease Out Bounce (Gravity)',
						'easeInOutBounce'    => 'Ease In Out Bounce',
						'spring(1,80,10,0)'  => 'Spring (Default)',
						'spring(1,60,8,0)'   => 'Spring (Soft)',
						'spring(2,100,15,0)' => 'Spring (Snappy)',
					),
					'condition' => $anime_condition,
				)
			);
			$obj->add_control(
				'sifency_anime_loop',
				array(
					'label'       => __( 'Loop Animation', 'sifency-addons' ),
					'type'        => Controls_Manager::SWITCHER,
					'condition'   => $anime_condition,
					'description' => __( 'Repeat the animation continuously.', 'sifency-addons' ),
				)
			);
			$obj->add_control(
				'sifency_anime_direction',
				array(
					'label'     => __( 'Direction', 'sifency-addons' ),
					'type'      => Controls_Manager::SELECT,
					'default'   => 'normal',
					'options'   => array(
						'normal'    => __( 'Normal', 'sifency-addons' ),
						'reverse'   => __( 'Reverse', 'sifency-addons' ),
						'alternate' => __( 'Alternate (Ping-Pong)', 'sifency-addons' ),
					),
					'condition' => array_merge( $anime_condition, array( 'sifency_anime_loop' => 'yes' ) ),
				)
			);

			// ── Barba.js Controls ──────────────────────────────────────────────────────────
			$obj->add_control(
				'sifency_barba_heading',
				array(
					'label'       => __( 'Barba.js Page Transition', 'sifency-addons' ),
					'type'        => Controls_Manager::HEADING,
					'separator'   => 'before',
					'condition'   => $barba_condition,
					'description' => __( 'Setting this on any widget activates smooth page transitions across the entire site.', 'sifency-addons' ),
				)
			);
			$obj->add_control(
				'sifency_barba_transition',
				array(
					'label'     => __( 'Transition Style', 'sifency-addons' ),
					'type'      => Controls_Manager::SELECT,
					'options'   => $this->get_sifency_animation_options( 'barba' ),
					'default'   => 'fade',
					'condition' => $barba_condition,
				)
			);
			$obj->add_control(
				'sifency_barba_duration',
				array(
					'label'     => __( 'Transition Duration (ms)', 'sifency-addons' ),
					'type'      => Controls_Manager::NUMBER,
					'min'       => 100,
					'max'       => 2000,
					'step'      => 50,
					'default'   => 500,
					'condition' => $barba_condition,
				)
			);
			$obj->add_control(
				'sifency_barba_wrapper',
				array(
					'label'       => __( 'Custom Wrapper Selector', 'sifency-addons' ),
					'type'        => Controls_Manager::TEXT,
					'placeholder' => '#page',
					'description' => __( 'CSS selector for the barba wrapper element. Defaults to auto-detect.', 'sifency-addons' ),
					'condition'   => $barba_condition,
				)
			);
			$obj->add_control(
				'sifency_barba_container',
				array(
					'label'       => __( 'Custom Container Selector', 'sifency-addons' ),
					'type'        => Controls_Manager::TEXT,
					'placeholder' => 'main',
					'description' => __( 'CSS selector for the barba container (the swapped page content). Defaults to auto-detect.', 'sifency-addons' ),
					'condition'   => $barba_condition,
				)
			);

			// ── Anime.js Usage Guide ───────────────────────────────────────────────────────
			$obj->add_control(
				'sifency_anime_trigger_heading',
				array(
					'label'     => __( 'Trigger Settings', 'sifency-addons' ),
					'type'      => Controls_Manager::HEADING,
					'separator' => 'before',
					'condition' => $anime_condition,
				)
			);
			$obj->add_control(
				'sifency_anime_threshold',
				array(
					'label'       => __( 'Viewport Threshold (%)', 'sifency-addons' ),
					'type'        => Controls_Manager::SLIDER,
					'range'       => array(
						'px' => array(
							'min'  => 0,
							'max'  => 100,
							'step' => 1,
						),
					),
					'default'     => array( 'size' => 8 ),
					'condition'   => $anime_condition,
					'description' => __( 'How much of the element must be visible before the animation triggers (0–100%).', 'sifency-addons' ),
				)
			);
			$obj->add_control(
				'sifency_anime_root_margin',
				array(
					'label'       => __( 'Root Margin Bottom (px)', 'sifency-addons' ),
					'type'        => Controls_Manager::NUMBER,
					'default'     => -50,
					'max'         => 200,
					'min'         => -400,
					'condition'   => $anime_condition,
					'description' => __( 'Shrink trigger zone from the bottom. Negative = trigger earlier (element needs to be higher up).', 'sifency-addons' ),
				)
			);
			$obj->add_control(
				'sifency_anime_usage_info',
				array(
					'type'      => Controls_Manager::RAW_HTML,
					'condition' => $anime_condition,
					'raw'       => '
                    <div style="background:#0f172a;border:1px solid #334155;border-radius:8px;padding:14px 16px;font-family:monospace;font-size:11px;line-height:1.7;color:#94a3b8">
                        <p style="margin:0 0 8px;color:#38bdf8;font-weight:700;font-family:sans-serif;font-size:12px">⚡ How Anime.js Works</p>
                        <p style="margin:0 0 6px;color:#e2e8f0">The following HTML is output on your element:</p>
                        <code style="display:block;background:#1e293b;border-radius:4px;padding:8px;color:#86efac;white-space:pre-wrap">class="anime-animate"
data-anime-preset="fade-up"
data-anime-duration="800"
data-anime-delay="0"
data-anime-easing="easeOutQuart"</code>
                        <p style="margin:8px 0 4px;color:#cbd5e1;font-family:sans-serif;font-size:11px"><strong style="color:#fbbf24">Trigger:</strong> IntersectionObserver scrolls into view</p>
                        <p style="margin:0;color:#cbd5e1;font-family:sans-serif;font-size:11px"><strong style="color:#fbbf24">Child Stagger:</strong> Set target to "Child Items" to stagger via delay offset</p>
                    </div>',
				)
			);

			// ── Barba.js Usage Guide ───────────────────────────────────────────────────────
			$obj->add_control(
				'sifency_barba_usage_info',
				array(
					'type'      => Controls_Manager::RAW_HTML,
					'condition' => $barba_condition,
					'raw'       => '
                    <div style="background:#0f172a;border:1px solid #334155;border-radius:8px;padding:14px 16px;font-family:monospace;font-size:11px;line-height:1.7;color:#94a3b8;margin-top:10px">
                        <p style="margin:0 0 8px;color:#38bdf8;font-weight:700;font-family:sans-serif;font-size:12px">🚀 How Barba.js Works</p>
                        <p style="margin:0 0 6px;color:#e2e8f0">1. Place this widget anywhere on any page.</p>
                        <p style="margin:0 0 6px;color:#e2e8f0">2. Barba.js <strong style="color:#fb923c">automatically wraps</strong> your site in a transition layer — no manual markup needed.</p>
                        <p style="margin:0 0 6px;color:#e2e8f0">3. Clicking any internal link plays the selected transition instead of a full page reload.</p>
                        <p style="margin:0 0 10px;color:#e2e8f0">4. All Elementor widgets, GSAP, and Anime.js animations <strong style="color:#fb923c">re-initialize</strong> after each transition.</p>
                        <p style="margin:0 0 6px;color:#cbd5e1;font-family:sans-serif;font-size:11px"><strong style="color:#fbbf24">Output HTML:</strong></p>
                        <code style="display:block;background:#1e293b;border-radius:4px;padding:8px;color:#86efac;white-space:pre-wrap">class="barba-page-transition"
data-barba-transition="fade"
data-barba-duration="500"</code>
                        <p style="margin:8px 0 0;color:#f87171;font-family:sans-serif;font-size:11px">⚠ <strong>Site-wide effect.</strong> Only one Barba.js style is needed per site. Add it to a header/footer widget for global reach.</p>
                    </div>',
				)
			);

			$obj->end_controls_section();
		}
	}
}


// =============================================================================
// THE ANIMATION MANAGER CLASS (REPLACES ALL GLOBAL FUNCTIONS)
// =============================================================================

if ( ! class_exists( 'Sifency\Traits\Sifency_Addons_Animation_Manager' ) ) {
	/**
	 * Manages the generation of animation attributes for Elementor widgets.
	 * This class is instantiated in the widget's render() method to handle all animation logic.
	 * It is entirely self-contained and does not pollute the global namespace.
	 */
	class Sifency_Addons_Animation_Manager {

		private $settings;
		private $target;
		private $base_attributes;
		private $index = 0;

		/**
		 * Sifency_Addons_Animation_Manager constructor.
		 *
		 * @param array $settings The widget's settings array from get_settings_for_display().
		 */
		public function __construct( array $settings ) {
			$this->settings        = $settings;
			$this->target          = isset( $settings['sifency_animation_target'] ) && ! empty( $settings['sifency_animation_target'] ) ? $settings['sifency_animation_target'] : 'masterwrapper';
			$this->base_attributes = $this->generate_base_attributes();
		}

		/**
		 * Returns the complete attributes array for the main widget wrapper.
		 * Useful for global Elementor hooks where you need to pass an array to add_render_attribute().
		 *
		 * @param array $extra_classes Optional array of additional classes to merge.
		 * @return array The associative array of attributes.
		 */
		/**
		 * Returns the complete attributes array for the master widget wrapper.
		 * Used exclusively by the global Elementor hook to target the `.elementor-widget-*` outermost wrapper.
		 */
		public function get_masterwrapper_attributes_array( array $extra_classes = array() ) {
			if ( $this->target !== 'masterwrapper' || empty( $this->base_attributes ) ) {
				if ( ! empty( $extra_classes ) ) {
					return array( 'class' => implode( ' ', $extra_classes ) );
				}
				return array();
			}

			$attributes = $this->base_attributes;
			if ( ! empty( $extra_classes ) ) {
				$existing_classes    = isset( $attributes['class'] ) ? explode( ' ', $attributes['class'] ) : array();
				$attributes['class'] = implode( ' ', array_unique( array_merge( $existing_classes, $extra_classes ) ) );
			}
			return $attributes;
		}

		public function get_wrapper_attributes_array( array $extra_classes = array() ) {
			if ( $this->target !== 'wrapper' || empty( $this->base_attributes ) ) {
				if ( ! empty( $extra_classes ) ) {
					return array( 'class' => implode( ' ', $extra_classes ) );
				}
				return array();
			}

			$attributes = $this->base_attributes;
			if ( ! empty( $extra_classes ) ) {
				$existing_classes    = isset( $attributes['class'] ) ? explode( ' ', $attributes['class'] ) : array();
				$attributes['class'] = implode( ' ', array_unique( array_merge( $existing_classes, $extra_classes ) ) );
			}
			return $attributes;
		}

		/**
		 * Returns the complete HTML attribute string for the main widget wrapper.
		 *
		 * @param array $extra_classes Optional array of additional classes to merge.
		 * @return string The HTML attribute string (e.g., ' class="..." data-aos="..."').
		 */
		public function get_wrapper_attributes( array $extra_classes = array() ) {
			if ( $this->target !== 'wrapper' || empty( $this->base_attributes ) ) {
				return ! empty( $extra_classes ) ? ' class="' . esc_attr( implode( ' ', $extra_classes ) ) . '"' : '';
			}
			return $this->build_attributes_string( $this->base_attributes, $extra_classes );
		}

		/**
		 * Returns the complete HTML attribute string for an individual item in a loop.
		 *
		 * @param array $extra_classes Optional array of additional classes to merge.
		 * @return string The HTML attribute string for the item.
		 */
		public function get_item_attributes( array $extra_classes = array() ) {
			if ( $this->target !== 'child' || empty( $this->base_attributes ) ) {
				return ! empty( $extra_classes ) ? ' class="' . esc_attr( implode( ' ', $extra_classes ) ) . '"' : '';
			}
			$item_attributes = $this->get_staggered_attributes( $this->index );
			++$this->index;
			return $this->build_attributes_string( $item_attributes, $extra_classes );
		}

		/**
		 * Returns the complete associative array of attributes for an individual item in a loop.
		 *
		 * @param array $extra_classes Optional array of additional classes to merge.
		 * @return array The associative array of attributes.
		 */
		public function get_item_attributes_array( array $extra_classes = array() ) {
			if ( $this->target !== 'child' || empty( $this->base_attributes ) ) {
				if ( ! empty( $extra_classes ) ) {
					return array( 'class' => implode( ' ', $extra_classes ) );
				}
				return array();
			}
			$item_attributes = $this->get_staggered_attributes( $this->index );
			++$this->index;
			if ( ! empty( $extra_classes ) ) {
				$existing_classes         = isset( $item_attributes['class'] ) ? explode( ' ', $item_attributes['class'] ) : array();
				$item_attributes['class'] = implode( ' ', array_unique( array_merge( $existing_classes, $extra_classes ) ) );
			}
			return $item_attributes;
		}

		/**
		 * Returns the complete HTML attribute string for a custom targeted element.
		 *
		 * @param array $extra_classes Optional array of additional classes to merge.
		 * @return string The HTML attribute string.
		 */
		public function get_custom_attributes( array $extra_classes = array() ) {
			if ( $this->target !== 'custom' || empty( $this->base_attributes ) ) {
				return ! empty( $extra_classes ) ? ' class="' . esc_attr( implode( ' ', $extra_classes ) ) . '"' : '';
			}
			return $this->build_attributes_string( $this->base_attributes, $extra_classes );
		}

		/**
		 * Returns animation config as a flat array (for JSON encoding onto the wrapper)
		 * so JS can pick it up for custom-selector targeting.
		 */
		public function get_custom_class_data_attrs() {
			$attrs = $this->base_attributes;
			if ( empty( $attrs ) ) {
				return array();
			}
			// Strip the 'data-' prefix from keys so JSON is compact
			$config = array();
			foreach ( $attrs as $key => $value ) {
				$clean_key            = strpos( $key, 'data-' ) === 0 ? substr( $key, 5 ) : $key;
				$config[ $clean_key ] = $value;
			}
			return $config;
		}

		/**
		 * Generates the base array of HTML data attributes from the widget settings.
		 */
		private function generate_base_attributes() {
			$attr = array();
			$type = isset( $this->settings['sifency_animation_type'] ) ? $this->settings['sifency_animation_type'] : '';

			if ( empty( $type ) ) {
				return $attr;
			}

			switch ( $type ) {
				case 'aos':
					if ( ! empty( $this->settings['sifency_aos_animation'] ) ) {
						$attr['data-aos'] = $this->settings['sifency_aos_animation'];
						if ( isset( $this->settings['sifency_aos_delay'] ) && $this->settings['sifency_aos_delay'] !== '' ) {
							$attr['data-aos-delay'] = $this->settings['sifency_aos_delay'];
						}
						if ( ! empty( $this->settings['sifency_aos_offset']['size'] ) ) {
							$attr['data-aos-offset'] = $this->settings['sifency_aos_offset']['size'];
						}
						if ( ! empty( $this->settings['sifency_aos_easing'] ) ) {
							$attr['data-aos-easing'] = $this->settings['sifency_aos_easing'];
						}
						$aos_once = isset( $this->settings['aos_once_switch'] ) ? $this->settings['aos_once_switch'] : 'no';
						if ( $aos_once === 'yes' ) {
							$attr['data-aos-once'] = 'true';
						}
					}
					break;

				case 'wow':
					if ( ! empty( $this->settings['sifency_wow_animation'] ) ) {
						$attr['class'] = 'wow ' . $this->settings['sifency_wow_animation'];
						if ( ! empty( $this->settings['sifency_wow_duration'] ) ) {
							$attr['data-wow-duration'] = $this->settings['sifency_wow_duration'];
						}
						if ( ! empty( $this->settings['sifency_wow_delay'] ) ) {
							$attr['data-wow-delay'] = $this->settings['sifency_wow_delay'];
						}
						if ( isset( $this->settings['sifency_wow_offset'] ) && $this->settings['sifency_wow_offset'] !== '' ) {
							$attr['data-wow-offset'] = $this->settings['sifency_wow_offset'];
						}
						if ( ! empty( $this->settings['sifency_wow_iteration'] ) ) {
							$attr['data-wow-iteration'] = $this->settings['sifency_wow_iteration'];
						}
					}
					break;

				case 'gsap':
					$gsap_classes = array( 'sa-animate' );
					if ( ! empty( $this->settings['sifency_gsap_animation'] ) ) {
						$gsap_classes[] = $this->settings['sifency_gsap_animation'];
					}

					$gsap_split_text       = isset( $this->settings['sifency_gsap_split_text'] ) ? $this->settings['sifency_gsap_split_text'] : 'no';
					$gsap_focus_text       = isset( $this->settings['sifency_gsap_focus_text'] ) ? $this->settings['sifency_gsap_focus_text'] : 'no';
					$gsap_stagger_children = isset( $this->settings['sifency_gsap_stagger_children'] ) ? $this->settings['sifency_gsap_stagger_children'] : 'no';
					$gsap_parallax         = isset( $this->settings['sifency_gsap_parallax'] ) ? $this->settings['sifency_gsap_parallax'] : 'no';
					$gsap_scale_text       = isset( $this->settings['sifency_gsap_scale_text'] ) ? $this->settings['sifency_gsap_scale_text'] : 'no';
					$gsap_markers          = isset( $this->settings['sifency_gsap_markers'] ) ? $this->settings['sifency_gsap_markers'] : 'no';
					$gsap_custom_cursor    = isset( $this->settings['sifency_gsap_custom_cursor'] ) ? $this->settings['sifency_gsap_custom_cursor'] : 'no';

					$needs_text_split = ( $gsap_split_text === 'yes' || $gsap_focus_text === 'yes' );
					if ( $needs_text_split ) {
						$gsap_classes[] = 'sa-split-text';
						if ( ! empty( $this->settings['sifency_gsap_split_by'] ) ) {
							$attr['data-split-by'] = $this->settings['sifency_gsap_split_by'];
						}
					}
					if ( isset( $this->settings['sifency_gsap_stack_cards'] ) && $this->settings['sifency_gsap_stack_cards'] === 'yes' ) {
						$gsap_classes[] = 'sa-stack-cards';
						if ( isset( $this->settings['sifency_gsap_stack_offset'] ) ) {
							$attr['data-stack-offset'] = $this->settings['sifency_gsap_stack_offset'];
						}
						if ( isset( $this->settings['sifency_gsap_stack_scale'] ) && $this->settings['sifency_gsap_stack_scale'] === 'yes' ) {
							$attr['data-stack-scale'] = 'true';
						}
					}
					if ( $gsap_stagger_children === 'yes' ) {
						$gsap_classes[] = 'sa-stagger';
						if ( ! empty( $this->settings['sifency_gsap_stagger_value'] ) ) {
							$attr['data-stagger'] = is_array( $this->settings['sifency_gsap_stagger_value'] ) ? $this->settings['sifency_gsap_stagger_value']['size'] : $this->settings['sifency_gsap_stagger_value'];
						}
					}
					if ( $gsap_focus_text === 'yes' ) {
						$gsap_classes[] = 'sa-focus-text';
						if ( ! empty( $this->settings['sifency_gsap_focus_max_blur'] ) ) {
							$attr['data-blur'] = $this->settings['sifency_gsap_focus_max_blur'];
						}
						if ( ! empty( $this->settings['sifency_gsap_focus_stagger'] ) ) {
							$attr['data-stagger'] = $this->settings['sifency_gsap_focus_stagger'];
						}
						$focus_from = isset( $this->settings['sifency_gsap_focus_from'] ) ? $this->settings['sifency_gsap_focus_from'] : 'center';
						if ( $focus_from !== 'center' ) {
							$attr['data-stagger-from'] = $focus_from;
						}
					}
					if ( $gsap_parallax === 'yes' ) {
						if ( isset( $this->settings['sifency_gsap_parallax_y'] ) && is_numeric( $this->settings['sifency_gsap_parallax_y'] ) ) {
							$attr['data-parallax-y'] = $this->settings['sifency_gsap_parallax_y'];
						}
						if ( isset( $this->settings['sifency_gsap_parallax_x'] ) && is_numeric( $this->settings['sifency_gsap_parallax_x'] ) ) {
							$attr['data-parallax-x'] = $this->settings['sifency_gsap_parallax_x'];
						}
					}
					if ( $gsap_scale_text === 'yes' ) {
						$attr['data-gsap-scale-text'] = 'true';
						if ( ! empty( $this->settings['sifency_gsap_start_size'] ) ) {
							$attr['data-start-size'] = $this->settings['sifency_gsap_start_size'];
						}
						if ( ! empty( $this->settings['sifency_gsap_end_size'] ) ) {
							$attr['data-end-size'] = $this->settings['sifency_gsap_end_size'];
						}
						$text_align = isset( $this->settings['sifency_gsap_scale_text_align'] ) ? $this->settings['sifency_gsap_scale_text_align'] : 'center';
						if ( ! empty( $text_align ) ) {
							$gsap_classes[] = 'gsap-anchor-' . $text_align;
						}
					}
					if ( $gsap_custom_cursor === 'yes' ) {
						$gsap_classes[]            = 'sa-cursor-trigger';
						$attr['data-cursor-text']  = ! empty( $this->settings['sifency_gsap_cursor_text'] ) ? sanitize_text_field( $this->settings['sifency_gsap_cursor_text'] ) : __( 'View', 'sifency-addons' );
						$attr['data-cursor-style'] = ! empty( $this->settings['sifency_gsap_cursor_style'] ) ? sanitize_key( $this->settings['sifency_gsap_cursor_style'] ) : 'default';
						if ( isset( $this->settings['sifency_gsap_cursor_size']['size'] ) && $this->settings['sifency_gsap_cursor_size']['size'] !== '' ) {
							$attr['data-cursor-size'] = (int) $this->settings['sifency_gsap_cursor_size']['size'];
						}
						$cursor_bg = $this->get_cursor_background_value();
						if ( ! empty( $cursor_bg ) ) {
							$attr['data-cursor-bg'] = $cursor_bg;
						}
						if ( ! empty( $this->settings['sifency_gsap_cursor_color'] ) ) {
							$attr['data-cursor-color'] = sanitize_text_field( $this->settings['sifency_gsap_cursor_color'] );
						}
						if ( ! empty( $this->settings['sifency_gsap_cursor_border'] ) ) {
							$attr['data-cursor-border'] = sanitize_text_field( $this->settings['sifency_gsap_cursor_border'] );
						}
					}
					$attr['class'] = implode( ' ', array_unique( $gsap_classes ) );
					if ( ! empty( $this->settings['sifency_gsap_duration'] ) && $this->settings['sifency_gsap_duration'] != 1.2 ) {
						$attr['data-duration'] = $this->settings['sifency_gsap_duration'];
					}
					if ( isset( $this->settings['sifency_gsap_delay'] ) && $this->settings['sifency_gsap_delay'] !== '' ) {
						$attr['data-delay'] = $this->settings['sifency_gsap_delay'];
					}
					if ( ! empty( $this->settings['sifency_gsap_ease'] ) && $this->settings['sifency_gsap_ease'] !== 'power4.out' ) {
						$attr['data-ease'] = $this->settings['sifency_gsap_ease'];
					}
					if ( ! empty( $this->settings['sifency_gsap_start'] ) && $this->settings['sifency_gsap_start'] !== 'top 85%' ) {
						$attr['data-start'] = $this->settings['sifency_gsap_start'];
					}

					if ( 'yes' === ( $this->settings['sifency_gsap_scrub_switch'] ?? 'no' ) ) {
						$lag                = $this->settings['sifency_gsap_scrub_lag']['size'] ?? 1;
						$attr['data-scrub'] = ( $lag == 0 ) ? 'true' : $lag;

						// Scroll height — extra px to give the scrub animation room to complete
						$scroll_height = $this->settings['sifency_gsap_scroll_height']['size'] ?? 0;
						if ( $scroll_height > 0 ) {
							$attr['data-scroll-height'] = (int) $scroll_height;
						}

						if ( 'yes' === ( $this->settings['sifency_gsap_scroll_snap'] ?? 'no' ) ) {
							$snap_val          = $this->settings['sifency_gsap_scroll_snap_value'] ?? '1';
							$attr['data-snap'] = $snap_val;
						}
					}

					if ( 'yes' === ( $this->settings['sifency_gsap_replay'] ?? 'no' ) ) {
						$attr['data-replay'] = 'true';
						$attr['data-once']   = 'false';
					}

					if ( ! empty( $this->settings['sifency_gsap_toggle_class'] ) && $this->settings['sifency_gsap_toggle_class'] !== 'is-active' ) {
						$attr['data-toggle-class'] = $this->settings['sifency_gsap_toggle_class'];
					}
					if ( $gsap_markers === 'yes' ) {
						$attr['data-markers'] = 'true';
					}
					if ( ! empty( $this->settings['sifency_gsap_from'] ) ) {
						$attr['data-from'] = str_replace( '"', "'", $this->settings['sifency_gsap_from'] );
					}
					if ( ! empty( $this->settings['sifency_gsap_to'] ) ) {
						$attr['data-to'] = str_replace( '"', "'", $this->settings['sifency_gsap_to'] );
					}
					break;
				case 'lenis':
					if ( ! empty( $this->settings['sifency_lenis_effect'] ) ) {
						$attr['class']             = 'sifency-lenis-animated';
						$attr['data-lenis-effect'] = $this->settings['sifency_lenis_effect'];

						if ( isset( $this->settings['sifency_lenis_speed']['size'] ) ) {
							$attr['data-lenis-speed'] = $this->settings['sifency_lenis_speed']['size'];
						}
					}
					break;

				case 'anime':
					$attr['class'] = 'anime-animate';
					if ( ! empty( $this->settings['sifency_anime_preset'] ) ) {
						$attr['data-anime-preset'] = $this->settings['sifency_anime_preset'];
					}
					if ( ! empty( $this->settings['sifency_anime_duration'] ) ) {
						$attr['data-anime-duration'] = (int) $this->settings['sifency_anime_duration'];
					}
					if ( isset( $this->settings['sifency_anime_delay'] ) && $this->settings['sifency_anime_delay'] !== '' ) {
						$attr['data-anime-delay'] = (int) $this->settings['sifency_anime_delay'];
					}
					if ( ! empty( $this->settings['sifency_anime_easing'] ) ) {
						$attr['data-anime-easing'] = $this->settings['sifency_anime_easing'];
					}
					if ( ! empty( $this->settings['sifency_anime_loop'] ) && $this->settings['sifency_anime_loop'] === 'yes' ) {
						$attr['data-anime-loop'] = 'true';
						if ( ! empty( $this->settings['sifency_anime_direction'] ) ) {
							$attr['data-anime-direction'] = $this->settings['sifency_anime_direction'];
						}
					}
					if ( isset( $this->settings['sifency_anime_threshold']['size'] ) ) {
						$attr['data-anime-threshold'] = (float) ( $this->settings['sifency_anime_threshold']['size'] / 100 );
					}
					if ( isset( $this->settings['sifency_anime_root_margin'] ) && $this->settings['sifency_anime_root_margin'] !== '' ) {
						$attr['data-anime-root-margin'] = '0px 0px ' . (int) $this->settings['sifency_anime_root_margin'] . 'px 0px';
					}
					break;

				case 'barba':
					$attr['class'] = 'barba-page-transition';
					if ( ! empty( $this->settings['sifency_barba_transition'] ) ) {
						$attr['data-barba-transition'] = $this->settings['sifency_barba_transition'];
					}
					if ( ! empty( $this->settings['sifency_barba_duration'] ) ) {
						$attr['data-barba-duration'] = (int) $this->settings['sifency_barba_duration'];
					}
					if ( ! empty( $this->settings['sifency_barba_wrapper'] ) ) {
						$attr['data-barba-wrapper'] = sanitize_text_field( $this->settings['sifency_barba_wrapper'] );
					}
					if ( ! empty( $this->settings['sifency_barba_container'] ) ) {
						$attr['data-barba-container'] = sanitize_text_field( $this->settings['sifency_barba_container'] );
					}
					break;

				case 'custom':
					if ( ! empty( $this->settings['sifency_custom_attributes'] ) ) {
						preg_match_all( '/(\S+)=["\']?((?:.(?!["\']?\s+(?:\S+)=|[>"\']))+.)["\']?/', $this->settings['sifency_custom_attributes'], $matches, PREG_SET_ORDER );
						if ( ! empty( $matches ) ) {
							foreach ( $matches as $match ) {
								if ( isset( $match[1], $match[2] ) ) {
									$key   = trim( $match[1] );
									$value = trim( $match[2] );
									if ( $key === 'class' ) {
										$attr['class'] = isset( $attr['class'] ) ? $attr['class'] . ' ' . $value : $value;
									} else {
										$attr[ $key ] = $value;
									}
								}
							}
						}
					}
					break;
			}
			return $attr;
		}

		/**
		 * Converts Elementor background group settings into a CSS background value.
		 */
		private function get_cursor_background_value() {
			$type = isset( $this->settings['sifency_gsap_cursor_bg_background'] ) ? $this->settings['sifency_gsap_cursor_bg_background'] : 'classic';

			if ( $type === 'gradient' ) {
				$color_a = ! empty( $this->settings['sifency_gsap_cursor_bg_color'] ) ? sanitize_text_field( $this->settings['sifency_gsap_cursor_bg_color'] ) : '#111111';
				$color_b = ! empty( $this->settings['sifency_gsap_cursor_bg_color_b'] ) ? sanitize_text_field( $this->settings['sifency_gsap_cursor_bg_color_b'] ) : '#333333';
				$stop_a  = isset( $this->settings['sifency_gsap_cursor_bg_color_stop']['size'] ) ? (float) $this->settings['sifency_gsap_cursor_bg_color_stop']['size'] : 0;
				$stop_b  = isset( $this->settings['sifency_gsap_cursor_bg_color_b_stop']['size'] ) ? (float) $this->settings['sifency_gsap_cursor_bg_color_b_stop']['size'] : 100;
				$shape   = ! empty( $this->settings['sifency_gsap_cursor_bg_gradient_type'] ) ? sanitize_key( $this->settings['sifency_gsap_cursor_bg_gradient_type'] ) : 'linear';

				if ( $shape === 'radial' ) {
					$position = ! empty( $this->settings['sifency_gsap_cursor_bg_gradient_position'] ) ? sanitize_text_field( $this->settings['sifency_gsap_cursor_bg_gradient_position'] ) : 'center center';
					return sprintf( 'radial-gradient(at %s, %s %s%%, %s %s%%)', str_replace( '_', ' ', $position ), $color_a, $stop_a, $color_b, $stop_b );
				}

				$angle = isset( $this->settings['sifency_gsap_cursor_bg_gradient_angle']['size'] ) ? (float) $this->settings['sifency_gsap_cursor_bg_gradient_angle']['size'] : 180;
				return sprintf( 'linear-gradient(%sdeg, %s %s%%, %s %s%%)', $angle, $color_a, $stop_a, $color_b, $stop_b );
			}

			if ( ! empty( $this->settings['sifency_gsap_cursor_bg_color'] ) ) {
				return sanitize_text_field( $this->settings['sifency_gsap_cursor_bg_color'] );
			}

			return '#111111';
		}

		/**
		 * Base attributes with a calculated stagger delay for child items.
		 */
		private function get_staggered_attributes( $index ) {
			$attributes = $this->base_attributes;
			$type       = isset( $this->settings['sifency_animation_type'] ) ? $this->settings['sifency_animation_type'] : '';

			$stagger_delay_setting = isset( $this->settings['sifency_animation_stagger_delay'] ) ? $this->settings['sifency_animation_stagger_delay'] : 100;
			if ( is_array( $stagger_delay_setting ) ) {
				$stagger_delay = ( isset( $stagger_delay_setting['size'] ) && $stagger_delay_setting['size'] !== '' ) ? (float) $stagger_delay_setting['size'] : 100;
				if ( isset( $stagger_delay_setting['unit'] ) && $stagger_delay_setting['unit'] === 's' ) {
					$stagger_delay *= 1000;
				}
			} else {
				$stagger_delay = (float) $stagger_delay_setting;
			}
			$calculated_delay = (int) $index * $stagger_delay;

			if ( $calculated_delay === 0 && $index > 0 ) {
				return $attributes;
			}

			switch ( $type ) {
				case 'aos':
					$base_delay                   = ! empty( $this->settings['sifency_aos_delay'] ) ? (int) $this->settings['sifency_aos_delay'] : 0;
					$attributes['data-aos-delay'] = $base_delay + $calculated_delay;
					break;
				case 'wow':
					$base_delay_str               = isset( $this->settings['sifency_wow_delay'] ) ? $this->settings['sifency_wow_delay'] : '0s';
					$base_delay_ms                = (float) $base_delay_str * 1000;
					$total_delay_s                = ( $base_delay_ms + $calculated_delay ) / 1000;
					$attributes['data-wow-delay'] = $total_delay_s . 's';
					break;
				case 'custom':
					$style               = isset( $attributes['style'] ) ? $attributes['style'] : '';
					$attributes['style'] = rtrim( $style, ';' ) . '; transition-delay: ' . $calculated_delay . 'ms;';
					break;
				case 'gsap':
					$base_delay               = ! empty( $this->settings['sifency_gsap_delay'] ) ? (float) $this->settings['sifency_gsap_delay'] : 0;
					$attributes['data-delay'] = $base_delay + ( $index * $stagger_delay / 1000 );
					break;
				case 'lenis':
					$stagger_offset                 = ! empty( $this->settings['sifency_lenis_stagger'] ) ? (float) $this->settings['sifency_lenis_stagger'] : 0.2;
					$base_speed                     = isset( $attributes['data-lenis-speed'] ) ? (float) $attributes['data-lenis-speed'] : 1;
					$attributes['data-lenis-speed'] = $base_speed + ( $index * $stagger_offset );
					break;
				case 'anime':
					$base_delay                     = isset( $this->settings['sifency_anime_delay'] ) && $this->settings['sifency_anime_delay'] !== '' ? (int) $this->settings['sifency_anime_delay'] : 0;
					$attributes['data-anime-delay'] = $base_delay + (int) $calculated_delay;
					break;
			}
			return $attributes;
		}

		/**
		 * Builds a clean, sanitized HTML attribute string from an array.
		 */
		private function build_attributes_string( array $attributes_array, array $classes_array = array() ) {
			if ( isset( $attributes_array['class'] ) ) {
				$classes_array = array_merge( $classes_array, explode( ' ', $attributes_array['class'] ) );
				unset( $attributes_array['class'] );
			}

			$final_string = '';
			if ( ! empty( $classes_array ) ) {
				$unique_classes = array_unique( array_filter( $classes_array ) );
				$final_string  .= ' class="' . esc_attr( implode( ' ', $unique_classes ) ) . '"';
			}

			foreach ( $attributes_array as $key => $value ) {
				if ( $value !== '' && $value !== null ) {
					$final_string .= sprintf( ' %s="%s"', esc_attr( $key ), esc_attr( $value ) );
				}
			}
			return $final_string;
		}
	}
}
