PageSourceSearch

https://theunstuckgroup.com/wp-content/uploads/bb-plugin/cache/438…37195204d2f-layout-bundle.js?ver=2.11.1-1.6

js theunstuckgroup.com collected 2026-09-24 19:50:04 UTC 123,101 bytes, 4,341 lines download raw bytes

1var wpAjaxUrl = 'https://theunstuckgroup.com/wp-admin/admin-ajax.php';var flBuilderUrl = 'https://theunstuckgroup.com/wp-content/plugins/bb-plugin/';var FLBuilderLayoutConfig = {
2	anchorLinkAnimations : {
3		duration 	: 1000,
4		easing		: 'swing',
5		offset 		: 100
6	},
7	paths : {
8		pluginUrl : 'https://theunstuckgroup.com/wp-content/plugins/bb-plugin/',
9		wpAjaxUrl : 'https://theunstuckgroup.com/wp-admin/admin-ajax.php'
10	},
11	breakpoints : {
12		small  : 768,
13		medium : 992,
14		large : 1200	},
15	waypoint: {
16		offset: 80
17	},
18	emptyColWidth: '0%',
19	i18n : {
20		opensInNewTab : '(opens in new tab)'
21	}
22};
23(function($){
24
25	if(typeof FLBuilderLayout != 'undefined') {
26		return;
27	}
28
29	/**
30	 * Helper class with generic logic for a builder layout.
31	 *
32	 * @class FLBuilderLayout
33	 * @since 1.0
34	 */
35	FLBuilderLayout = {
36
37		/**
38		 * Initializes a builder layout.
39		 *
40		 * @since 1.0
41		 * @method init
42		 */
43		init: function()
44		{
45			// Destroy existing layout events.
46			FLBuilderLayout._destroy();
47
48			// Init CSS classes.
49			FLBuilderLayout._initClasses();
50
51			// Init backgrounds.
52			FLBuilderLayout._initBackgrounds();
53
54			// Init buttons.
55			FLBuilderLayout._initButtons();
56
57			// Init row shape layer height.
58			FLBuilderLayout._initRowShapeLayerHeight();
59
60			// Init the new tab notice on links opening in a new tab.
61			FLBuilderLayout._initLinkNotices();
62
63			// Only init if the builder isn't active.
64			if ( 0 === $('.fl-builder-edit').length ) {
65
66				// Init anchor links.
67				FLBuilderLayout._initAnchorLinks();
68
69				// Init the browser hash.
70				FLBuilderLayout._initHash();
71
72				// Init forms.
73				FLBuilderLayout._initForms();
74
75				FLBuilderLayout._reorderMenu();
76			}
77			else {
78				FLBuilderLayout._initNestedColsWidth();
79			}
80			$('body').removeClass( 'fl-no-js' );
81		},
82
83		/**
84		 * Public method for refreshing Wookmark or MosaicFlow galleries
85		 * within an element.
86		 *
87		 * @since 1.7.4
88		 * @method refreshGalleries
89		 */
90		refreshGalleries: function( element )
91		{
92			var $element  = 'undefined' == typeof element ? $( 'body' ) : $( element ),
93				mfContent = $element.find( '.fl-mosaicflow-content' ),
94				wmContent = $element.find( '.fl-gallery' ),
95				mfObject  = null;
96
97			if ( mfContent ) {
98
99				mfObject = mfContent.data( 'mosaicflow' );
100
101				if ( mfObject ) {
102					mfObject.columns = $( [] );
103					mfObject.columnsHeights = [];
104					mfContent.data( 'mosaicflow', mfObject );
105					mfContent.mosaicflow( 'refill' );
106				}
107			}
108			if ( wmContent ) {
109				wmContent.trigger( 'refreshWookmark' );
110			}
111		},
112
113		/**
114		 * Public method for refreshing Masonry within an element
115		 *
116		 * @since 1.8.1
117		 * @method refreshGridLayout
118		 */
119		refreshGridLayout: function( element )
120		{
121			var $element 		= 'undefined' == typeof element ? $( 'body' ) : $( element ),
122				msnryContent	= $element.find('.masonry');
123
124			if ( msnryContent.length )	{
125				msnryContent.masonry('layout');
126			}
127		},
128
129		/**
130		 * Public method for reloading BxSlider within an element
131		 *
132		 * @since 1.8.1
133		 * @method reloadSlider
134		 */
135		reloadSlider: function( content )
136		{
137			var $content = 'undefined' == typeof content ? $('body') : $(content);
138
139			// reload sliders.
140			if ($content.find('.bx-viewport > div').length > 0) {
141				$.each($content.find('.bx-viewport > div'), function (key, slider) {
142					setTimeout(function () {
143						$(slider).data('bxSlider').reloadSlider();
144					}, 100);
145				});
146			}
147		},
148
149		/**
150		 * Public method for resizing WP audio player
151		 *
152		 * @since 1.8.2
153		 * @method resizeAudio
154		 */
155		resizeAudio: function( element )
156		{
157			var $element 	 	= 'undefined' == typeof element ? $( 'body' ) : $( element ),
158				audioPlayers 	= $element.find('.wp-audio-shortcode.mejs-audio'),
159				player 		 	= null,
160				mejsPlayer 	 	= null,
161				rail 			= null,
162				railWidth 		= 400;
163
164			if ( audioPlayers.length && typeof mejs !== 'undefined' ) {
165            	audioPlayers.each(function(){
166	            	player 		= $(this);
167	            	mejsPlayer 	= mejs.players[player.attr('id')];
168	            	rail 		= player.find('.mejs-controls .mejs-time-rail');
169	            	var innerMejs = player.find('.mejs-inner'),
170	            		total 	  = player.find('.mejs-controls .mejs-time-total');
171
172	            	if ( typeof mejsPlayer !== 'undefined' ) {
173	            		railWidth = Math.ceil(player.width() * 0.8);
174
175	            		if ( innerMejs.length ) {
176
177		            		rail.css('width', railWidth +'px!important');
178		            		//total.width(rail.width() - 10);
179
180		            		mejsPlayer.options.autosizeProgress = true;
181
182		            		// webkit has trouble doing this without a delay
183							setTimeout(function () {
184								mejsPlayer.setControlsSize();
185							}, 50);
186
187			            	player.find('.mejs-inner').css({
188			            		visibility: 'visible',
189			            		height: 'inherit'
190			            	});
191		            	}
192		           	}
193	            });
194	        }
195		},
196
197		/**
198		 * Public method for preloading WP audio player when it's inside the hidden element
199		 *
200		 * @since 1.8.2
201		 * @method preloadAudio
202		 */
203		preloadAudio: function(element)
204		{
205			var $element 	 = 'undefined' == typeof element ? $( 'body' ) : $( element ),
206				contentWrap  = $element.closest('.fl-accordion-item'),
207				audioPlayers = $element.find('.wp-audio-shortcode.mejs-audio');
208
209			if ( ! contentWrap.hasClass('fl-accordion-item-active') && audioPlayers.find('.mejs-inner').length ) {
210				audioPlayers.find('.mejs-inner').css({
211					visibility : 'hidden',
212					height: 0
213				});
214			}
215		},
216
217		/**
218		 * Public method for resizing slideshow momdule within the tab
219		 *
220		 * @since 1.10.5
221		 * @method resizeSlideshow
222		 */
223		resizeSlideshow: function(){
224			if(typeof YUI !== 'undefined') {
225				YUI().use('node-event-simulate', function(Y) {
226					Y.one(window).simulate("resize");
227				});
228			}
229		},
230
231		/**
232		 * Public method for reloading an embedded Google Map within the tabs or hidden element.
233		 *
234		 * @since 2.2
235		 * @method reloadGoogleMap
236		 */
237		reloadGoogleMap: function(element){
238			var $element  = 'undefined' == typeof element ? $( 'body' ) : $( element ),
239			    googleMap = $element.find( 'iframe[src*="google.com/maps"]' );
240
241			if ( googleMap.length ) {
242			    googleMap.attr( 'src', function(i, val) {
243			        return val;
244			    });
245			}
246		},
247
248		/**
249		 * Unbinds builder layout events.
250		 *
251		 * @since 1.0
252		 * @access private
253		 * @method _destroy
254		 */
255		_destroy: function()
256		{
257			var win = $(window);
258
259			win.off('scroll.fl-bg-parallax');
260			win.off('resize.fl-bg-video');
261		},
262
263		/**
264		 * Checks to see if the current device has touch enabled.
265		 *
266		 * @since 1.0
267		 * @access private
268		 * @method _isTouch
269		 * @return {Boolean}
270		 */
271		_isTouch: function()
272		{
273			if(('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch)) {
274				return true;
275			}
276
277			return false;
278		},
279
280		/**
281		 * Checks to see if the current device is mobile.
282		 *
283		 * @since 1.7
284		 * @access private
285		 * @method _isMobile
286		 * @return {Boolean}
287		 */
288		_isMobile: function()
289		{
290			return /Mobile|Android|Silk\/|Kindle|BlackBerry|Opera Mini|Opera Mobi|webOS/i.test( navigator.userAgent );
291		},
292
293		/**
294		 * Initializes builder body classes.
295		 *
296		 * @since 1.0
297		 * @access private
298		 * @method _initClasses
299		 */
300		_initClasses: function()
301		{
302			var body = $( 'body' ),
303				ua   = navigator.userAgent;
304
305			// Add the builder body class (skip on block-only frontend to avoid layout break).
306			if ( ! body.hasClass( 'fl-builder-blocks-only' ) && ! body.hasClass( 'archive' ) && $( '.fl-builder-content-primary' ).length > 0 ) {
307				body.addClass('fl-builder');
308			}
309
310			// Add the builder touch body class.
311			if(FLBuilderLayout._isTouch()) {
312				body.addClass('fl-builder-touch');
313			}
314
315			// Add the builder mobile body class.
316			if(FLBuilderLayout._isMobile()) {
317				body.addClass('fl-builder-mobile');
318			}
319
320			if ( $(window).width() < FLBuilderLayoutConfig.breakpoints.small ) {
321				body.addClass( 'fl-builder-breakpoint-small' );
322			}
323
324			if ( $(window).width() > FLBuilderLayoutConfig.breakpoints.small && $(window).width() < FLBuilderLayoutConfig.breakpoints.medium ) {
325				body.addClass( 'fl-builder-breakpoint-medium' );
326			}
327
328			if ( $(window).width() > FLBuilderLayoutConfig.breakpoints.medium && $(window).width() < FLBuilderLayoutConfig.breakpoints.large ) {
329				body.addClass( 'fl-builder-breakpoint-large' );
330			}
331
332			if ( $(window).width() > FLBuilderLayoutConfig.breakpoints.large ) {
333				body.addClass( 'fl-builder-breakpoint-default' );
334			}
335
336			// IE11 body class.
337			if ( ua.indexOf( 'Trident/7.0' ) > -1 && ua.indexOf( 'rv:11.0' ) > -1 ) {
338				body.addClass( 'fl-builder-ie-11' );
339			}
340		},
341
342		/**
343		 * Initializes builder node backgrounds that require
344		 * additional JavaScript logic such as parallax.
345		 *
346		 * @since 1.1.4
347		 * @access private
348		 * @method _initBackgrounds
349		 */
350		_initBackgrounds: function()
351		{
352			var win = $(window);
353
354			// Init parallax backgrounds.
355			if($('.fl-row-bg-parallax').length > 0 && !FLBuilderLayout._isMobile()) {
356				FLBuilderLayout._scrollParallaxBackgrounds();
357				FLBuilderLayout._initParallaxBackgrounds();
358				win.on('resize.fl-bg-parallax', FLBuilderLayout._initParallaxBackgrounds);
359				win.on('scroll.fl-bg-parallax', FLBuilderLayout._scrollParallaxBackgrounds);
360			}
361
362			// Init video backgrounds.
363			if($('.fl-bg-video').length > 0) {
364				FLBuilderLayout._initBgVideos();
365				FLBuilderLayout._resizeBgVideos();
366
367				// Ensure FLBuilderLayout._resizeBgVideos() is only called once on window resize.
368				var resizeBGTimer = null;
369				win.on('resize.fl-bg-video', function(e){
370					clearTimeout( resizeBGTimer );
371					resizeBGTimer = setTimeout(function() {
372						FLBuilderLayout._resizeBgVideos(e);
373					}, 100 );
374				});
375			}
376		},
377
378		/**
379		 * Initializes all buttons in a layout.
380		 *
381		 * @since 2.10
382		 * @access private
383		 * @method _initButtons
384		 */
385		_initButtons: function()
386		{
387			// Trigger click event on Enter or Space key press for deprecated button markup.
388			$('a.fl-button[role="button"]').on('keydown', function(event) {
389				if (event.key === 'Enter' || event.key === ' ') {
390					// Necessary to prevent the default behavior of the space key from scrolling the page
391					event.preventDefault();
392					$(this).trigger('click');
393				}
394			});
395		},
396
397		/**
398		 * Initializes all parallax backgrounds in a layout.
399		 *
400		 * @since 1.1.4
401		 * @access private
402		 * @method _initParallaxBackgrounds
403		 */
404		_initParallaxBackgrounds: function()
405		{
406			$('.fl-row-bg-parallax').each(FLBuilderLayout._initParallaxBackground);
407		},
408
409		/**
410		 * Initializes a single parallax background.
411		 *
412		 * @since 1.1.4
413		 * @access private
414		 * @method _initParallaxBackgrounds
415		 */
416		_initParallaxBackground: function()
417		{
418			var row     = $(this),
419				content = row.find('> .fl-row-content-wrap'),
420				winWidth = $(window).width(),
421				screenSize = '',
422				imageSrc = {
423					default: '',
424					medium: '',
425					responsive: '',
426				};
427
428			imageSrc.default = row.data('parallax-image') || '';
429			imageSrc.medium = row.data('parallax-image-medium') || imageSrc.default;
430			imageSrc.responsive = row.data('parallax-image-responsive') || imageSrc.medium;
431
432			if (winWidth > FLBuilderLayoutConfig.breakpoints.medium) {
433				screenSize = 'default';
434			} else if (winWidth > FLBuilderLayoutConfig.breakpoints.small && winWidth <= FLBuilderLayoutConfig.breakpoints.medium ) {
435				screenSize = 'medium';
436			} else if (winWidth <= FLBuilderLayoutConfig.breakpoints.small) {
437				screenSize = 'responsive';
438			}
439
440			content.css('background-image', 'url(' + imageSrc[screenSize] + ')');
441			row.data('current-image-loaded', screenSize );
442
443		},
444
445		/**
446		 * Fires when the window is scrolled to adjust
447		 * parallax backgrounds.
448		 *
449		 * @since 1.1.4
450		 * @access private
451		 * @method _scrollParallaxBackgrounds
452		 */
453		_scrollParallaxBackgrounds: function()
454		{
455			$('.fl-row-bg-parallax').each(FLBuilderLayout._scrollParallaxBackground);
456		},
457
458		/**
459		 * Fires when the window is scrolled to adjust
460		 * a single parallax background.
461		 *
462		 * @since 1.1.4
463		 * @access private
464		 * @method _scrollParallaxBackground
465		 */
466		_scrollParallaxBackground: function()
467		{
468			var win     	  = $(window),
469				row     	  = $(this),
470				content 	  = row.find('> .fl-row-content-wrap'),
471				speed   	  = row.data('parallax-speed'),
472				offset  	  = content.offset(),
473				yPos		  = -((win.scrollTop() - offset.top) / speed),
474				initialOffset = ( row.data('parallax-offset') != null ) ? row.data('parallax-offset') : 0,
475				totalOffset   = yPos - initialOffset;
476
477			content.css('background-position', 'center ' + totalOffset + 'px');
478		},
479
480		/**
481		 * Initializes all video backgrounds.
482		 *
483		 * @since 1.6.3.3
484		 * @access private
485		 * @method _initBgVideos
486		 */
487		_initBgVideos: function()
488		{
489			$('.fl-bg-video').each(FLBuilderLayout._initBgVideo);
490		},
491
492		/**
493		 * Initializes a video background.
494		 *
495		 * @since 1.6.3.3
496		 * @access private
497		 * @method _initBgVideo
498		 */
499		_initBgVideo: function()
500		{
501			var wrap   = $( this ),
502				width       = wrap.data( 'width' ),
503				height      = wrap.data( 'height' ),
504				mp4         = wrap.data( 'mp4' ),
505				youtube     = wrap.data( 'youtube'),
506				vimeo       = wrap.data( 'vimeo'),
507				mp4Type     = wrap.data( 'mp4-type' ),
508				webm        = wrap.data( 'webm' ),
509				webmType    = wrap.data( 'webm-type' ),
510				fallback    = wrap.data( 'fallback' ),
511				loaded      = wrap.data( 'loaded' ),
512				videoMobile = wrap.data( 'video-mobile' ),
513				playPauseButton = wrap.find('.fl-bg-video-play-pause-control'),
514				fallbackTag = '',
515				videoTag    = null,
516				mp4Tag      = null,
517				webmTag     = null;
518
519			// Return if the video has been loaded for this row.
520			if ( loaded ) {
521				return;
522			}
523
524			videoTag  = $( '<video autoplay loop muted playsinline></video>' );
525
526			/**
527			 * Add poster image (fallback image)
528			 */
529			if( 'undefined' != typeof fallback && '' != fallback ) {
530				videoTag.attr( 'poster', 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' )
531				videoTag.css({
532					backgroundImage: 'url("' + fallback + '")',
533					backgroundColor: 'transparent',
534					backgroundRepeat: 'no-repeat',
535					backgroundSize: 'cover',
536					backgroundPosition: 'center center',
537				})
538			}
539
540			// MP4 Source Tag
541			if ( 'undefined' != typeof mp4 && '' != mp4 ) {
542
543				mp4Tag = $( '<source />' );
544				mp4Tag.attr( 'src', mp4 );
545				mp4Tag.attr( 'type', mp4Type );
546
547				videoTag.append( mp4Tag );
548			}
549			// WebM Source Tag
550			if ( 'undefined' != typeof webm && '' != webm ) {
551
552				webmTag = $( '<source />' );
553				webmTag.attr( 'src', webm );
554				webmTag.attr( 'type', webmType );
555
556				videoTag.append( webmTag );
557			}
558
559			// This is either desktop, or mobile is enabled.
560			if ( ! FLBuilderLayout._isMobile() || ( FLBuilderLayout._isMobile() && "yes" == videoMobile ) ) {
561				if ( 'undefined' != typeof youtube ) {
562					FLBuilderLayout._initYoutubeBgVideo.apply( this );
563				}
564				else if ( 'undefined' != typeof vimeo ) {
565					FLBuilderLayout._initVimeoBgVideo.apply( this );
566				}
567				else {
568					wrap.append( videoTag );
569
570					if ( playPauseButton.length > 0 ) {
571						var video = videoTag[0];
572
573						playPauseButton.on( 'click', { video: video }, function(e) {
574							var video = e.data.video;
575
576							if ( video.paused ) {
577								video.play();
578							} else {
579								video.pause();
580							}
581						} );
582
583						$( video ).on( 'play playing', function () {
584							playPauseButton.removeClass( 'fa-play' ).addClass( 'fa-pause' );
585						} );
586						
587						$( video ).on( 'pause ended waiting', function () {
588							playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
589						} );
590					}
591				}
592			}
593			else {
594				// if we are here, it means we are on mobile and NO is set so remove video src and use fallback
595				videoTag.attr('src', '')
596				wrap.append( videoTag );
597			}
598
599			// Mark this video as loaded.
600			wrap.data('loaded', true);
601		},
602
603		/**
604		 * Initializes Youtube video background
605		 *
606		 * @since 1.9
607		 * @access private
608		 * @method _initYoutubeBgVideo
609		 */
610		_initYoutubeBgVideo: function()
611		{
612			var playerWrap  = $(this),
613				videoId     = playerWrap.data('video-id'),
614				videoPlayer = playerWrap.find('.fl-bg-video-player'),
615				enableAudio = playerWrap.data('enable-audio'),
616				audioButton = playerWrap.find('.fl-bg-video-audio'),
617				playPauseButton = playerWrap.find('.fl-bg-video-play-pause-control'),
618				startTime   = 'undefined' !== typeof playerWrap.data('start') ? playerWrap.data('start') : 0,
619				startTime   = 'undefined' !== typeof playerWrap.data('t') && startTime === 0 ? playerWrap.data('t') : startTime,
620				endTime     = 'undefined' !== typeof playerWrap.data('end') ? playerWrap.data('end') : 0,
621				loop        = 'undefined' !== typeof playerWrap.data('loop') ? playerWrap.data('loop') : 1,
622				stateCount  = 0,
623				player,fallback_showing;
624
625			if ( videoId ) {
626				fallback = playerWrap.data('fallback') || false
627				if( fallback ) {
628					playerWrap.find('iframe').remove()
629					fallbackTag = $( '<div></div>' );
630					fallbackTag.addClass( 'fl-bg-video-fallback' );
631					fallbackTag.css( 'background-image', 'url(' + playerWrap.data('fallback') + ')' );
632					fallbackTag.css( 'background-size', 'cover' );
633					fallbackTag.css( 'transition', 'background-image 1s')
634					playerWrap.append( fallbackTag );
635					fallback_showing = true;
636				}
637				FLBuilderLayout._onYoutubeApiReady( function( YT ) {
638					setTimeout( function() {
639
640						player = new YT.Player( videoPlayer[0], {
641							videoId: videoId,
642							events: {
643								onReady: function(event) {
644									if ( "no" === enableAudio || FLBuilderLayout._isMobile() ) {
645										event.target.mute();
646									}
647									else if ( "yes" === enableAudio && event.target.isMuted ) {
648										event.target.unMute();
649									}
650
651									// Store an instance to a parent
652									playerWrap.data('YTPlayer', player);
653									FLBuilderLayout._resizeYoutubeBgVideo.apply(playerWrap);
654
655									// Queue the video.
656									event.target.playVideo();
657
658									if ( audioButton.length > 0 && ! FLBuilderLayout._isMobile() ) {
659										audioButton.on( 'click', {button: audioButton, player: player}, FLBuilderLayout._toggleBgVideoAudio );
660									}
661
662									if ( playPauseButton.length > 0 ) {
663										playPauseButton.on( 'click', {player: player}, function(e) {
664											var player = e.data.player;
665			
666											if ( 1 === player.getPlayerState() ) {
667												player.pauseVideo();
668											} else {
669												player.playVideo();
670											}
671										});
672									}
673								},
674								onStateChange: function( event ) {
675
676									if ( event.data === 1 ) {
677										if ( fallback_showing ) {
678											$( '.fl-bg-video-fallback' ).css( 'background-image', 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)' )
679										}
680									}
681									// Manual check if video is not playable in some browsers.
682									// StateChange order: [-1, 3, -1]
683									if ( stateCount < 4 ) {
684										stateCount++;
685									}
686
687									// Comply with the audio policy in some browsers like Chrome and Safari.
688									if ( stateCount > 1 && -1 === event.data && "yes" === enableAudio ) {
689										player.mute();
690										player.playVideo();
691										audioButton.show();
692									}
693
694									if ( event.data === YT.PlayerState.ENDED && 1 === loop ) {
695										if ( startTime > 0 ) {
696											player.seekTo( startTime );
697										}
698										else {
699											player.playVideo();
700										}
701									}
702
703									if ( event.data === YT.PlayerState.PLAYING ) {
704										playPauseButton.removeClass( 'fa-play' ).addClass( 'fa-pause' );
705									} else if ( event.data === YT.PlayerState.PAUSED ) {
706										playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
707									} else if ( event.data === YT.PlayerState.BUFFERING ) {
708										playPauseButton.removeClass( 'fa-play' ).addClass( 'fa-pause' );
709									} else if ( event.data === YT.PlayerState.CUED ) {
710										playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
711									} else if ( event.data === YT.PlayerState.ENDED ) {
712										playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
713									}
714								},
715								onError: function(event) {
716									console.info('YT Error: ' + event.data)
717									FLBuilderLayout._onErrorYoutubeVimeo(playerWrap)
718								}
719							},
720							playerVars: {
721								playsinline: FLBuilderLayout._isMobile() ? 1 : 0,
722								controls: 0,
723								showinfo: 0,
724								rel : 0,
725								start: startTime,
726								end: endTime,
727							}
728						} );
729					}, 1 );
730				} );
731			}
732		},
733
734		/**
735		 * On youtube or vimeo error show the fallback image if available.
736		 * @since 2.0.7
737		 */
738		_onErrorYoutubeVimeo: function(playerWrap) {
739
740			fallback = playerWrap.data('fallback') || false
741			if( ! fallback ) {
742				return false;
743			}
744			playerWrap.find('iframe').remove()
745			fallbackTag = $( '<div></div>' );
746			fallbackTag.addClass( 'fl-bg-video-fallback' );
747			fallbackTag.css( 'background-image', 'url(' + playerWrap.data('fallback') + ')' );
748			playerWrap.append( fallbackTag );
749		},
750
751		/**
752		 * Check if Youtube API has been downloaded
753		 *
754		 * @since 1.9
755		 * @access private
756		 * @method _onYoutubeApiReady
757		 * @param  {Function} callback Method to call when YT API has been loaded
758		 */
759		_onYoutubeApiReady: function( callback ) {
760			if ( window.YT && YT.loaded ) {
761				callback( YT );
762			} else {
763				// If not ready check again by timeout..
764				setTimeout( function() {
765					FLBuilderLayout._onYoutubeApiReady( callback );
766				}, 350 );
767			}
768		},
769
770		/**
771		 * Initializes Vimeo video background
772		 *
773		 * @since 1.9
774		 * @access private
775		 * @method _initVimeoBgVideo
776		 */
777		_initVimeoBgVideo: function()
778		{
779			var playerWrap	= $(this),
780				videoId 	= playerWrap.data('video-id'),
781				videoHash 	= playerWrap.data('video-hash'),
782				videoPlayer = playerWrap.find('.fl-bg-video-player'),
783				enableAudio = playerWrap.data('enable-audio'),
784				audioButton = playerWrap.find('.fl-bg-video-audio'),
785				playPauseButton = playerWrap.find('.fl-bg-video-play-pause-control'),
786				playerState = '',
787				player,
788				width = playerWrap.outerWidth(),
789				ua    = navigator.userAgent;
790
791			if ( typeof Vimeo !== 'undefined' && videoId )	{
792				
793				const vimOptions = {
794					loop       : true,
795					title      : false,
796					portrait   : false,
797					background : true,
798					autopause  : false,
799					muted      : true,
800				};
801
802				if ( videoHash.length ) {
803					vimOptions.url = `https://player.vimeo.com/video/${ videoId }?h=${ videoHash }`;
804				} else {
805					vimOptions.id = videoId;
806				}
807
808				player = new Vimeo.Player(videoPlayer[0], vimOptions );
809				playerWrap.data('VMPlayer', player);
810				if ( "no" === enableAudio ) {
811					player.setVolume(0);
812				}
813				else if ("yes" === enableAudio ) {
814					// Chrome, Safari, Firefox have audio policy restrictions for autoplay videos.
815					if ( ua.indexOf("Safari") > -1 || ua.indexOf("Chrome") > -1 || ua.indexOf("Firefox") > -1 ) {
816						player.setVolume(0);
817						audioButton.show();
818					}
819					else {
820						player.setVolume(1);
821					}
822				}
823
824				player.play().catch(function(error) {
825					FLBuilderLayout._onErrorYoutubeVimeo(playerWrap)
826				});
827
828				if ( audioButton.length > 0 ) {
829					audioButton.on( 'click', {button: audioButton, player: player}, FLBuilderLayout._toggleBgVideoAudio );
830				}
831
832				player.on( 'play', function() {
833					playerState = 'play';
834					playPauseButton.removeClass( 'fa-play' ).addClass( 'fa-pause' );
835				} );
836				player.on( 'pause', function() {
837					playerState = 'pause';
838					playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
839				} );
840				player.on( 'ended', function() {
841					playerState = 'ended';
842					playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
843				} );
844				player.on( 'bufferstart', function() {
845					playerState = 'bufferstart';
846					playPauseButton.removeClass( 'fa-play' ).addClass( 'fa-pause' );
847				} );
848
849				if ( playPauseButton.length > 0 ) {
850					playPauseButton.on( 'click', { player: player }, function( e ) {
851						var player = e.data.player;
852
853						if ( playerState === 'play' ) {
854							player.pause();
855						} else {
856							player.play();
857						}
858					} );
859				}
860			}
861		},
862
863		/**
864		 * Mute / unmute audio on row's video background.
865		 * It works for both Youtube and Vimeo.
866		 *
867		 * @since 2.1.3
868		 * @access private
869		 * @method _toggleBgVideoAudio
870		 * @param {Object} e Method arguments
871		 */
872		_toggleBgVideoAudio: function( e ) {
873			var player  = e.data.player,
874			    control = e.data.button.find('.fl-audio-control');
875
876			if ( control.hasClass( 'fa-volume-off' ) ) {
877				// Unmute
878				control
879					.removeClass( 'fa-volume-off' )
880					.addClass( 'fa-volume-up' );
881				e.data.button.find( '.fa-times' ).hide();
882
883				if ( 'function' === typeof player.unMute ) {
884					player.unMute();
885				}
886				else {
887					player.setVolume( 1 );
888				}
889			}
890			else {
891				// Mute
892				control
893					.removeClass( 'fa-volume-up' )
894					.addClass( 'fa-volume-off' );
895				e.data.button.find( '.fa-times' ).show();
896
897				if ( 'function' === typeof player.unMute ) {
898					player.mute();
899				}
900				else {
901					player.setVolume( 0 );
902				}
903			}
904		},
905
906		/**
907		 * Fires when there is an error loading a video
908		 * background source and shows the fallback.
909		 *
910		 * @since 1.6.3.3
911		 * @access private
912		 * @method _videoBgSourceError
913		 * @param {Object} e An event object
914		 * @deprecated 2.0.3
915		 */
916		_videoBgSourceError: function( e )
917		{
918			var source 		= $( e.target ),
919				wrap   		= source.closest( '.fl-bg-video' ),
920				vid		    = wrap.find( 'video' ),
921				fallback  	= wrap.data( 'fallback' ),
922				fallbackTag = '';
923			source.remove();
924
925			if ( vid.find( 'source' ).length ) {
926				// Don't show the fallback if we still have other sources to check.
927				return;
928			} else if ( '' !== fallback ) {
929				fallbackTag = $( '<div></div>' );
930				fallbackTag.addClass( 'fl-bg-video-fallback' );
931				fallbackTag.css( 'background-image', 'url(' + fallback + ')' );
932				wrap.append( fallbackTag );
933				vid.remove();
934			}
935		},
936
937		/**
938		 * Fires when the window is resized to resize
939		 * all video backgrounds.
940		 *
941		 * @since 1.1.4
942		 * @access private
943		 * @method _resizeBgVideos
944		 */
945		_resizeBgVideos: function()
946		{
947			$('.fl-bg-video').each( function() {
948
949				FLBuilderLayout._resizeBgVideo.apply( this );
950
951				if ( $( this ).parent().find( 'img' ).length > 0 ) {
952					$( this ).parent().imagesLoaded( $.proxy( FLBuilderLayout._resizeBgVideo, this ) );
953				}
954			} );
955		},
956
957		/**
958		 * Fires when the window is resized to resize
959		 * a single video background.
960		 *
961		 * @since 1.1.4
962		 * @access private
963		 * @method _resizeBgVideo
964		 */
965		_resizeBgVideo: function()
966		{
967			if ( 0 === $( this ).find( 'video' ).length && 0 === $( this ).find( 'iframe' ).length ) {
968				return;
969			}
970
971			var wrap        = $(this),
972				wrapHeight  = wrap.outerHeight(),
973				wrapWidth   = wrap.outerWidth(),
974				vid         = wrap.find('video'),
975				vidHeight   = wrap.data('height'),
976				vidWidth    = wrap.data('width'),
977				newWidth    = wrapWidth,
978				newHeight   = Math.round(vidHeight * wrapWidth/vidWidth),
979				newLeft     = 0,
980				newTop      = 0,
981				iframe 		= wrap.find('iframe'),
982				isRowFullHeight = $(this).closest('.fl-row-bg-video').hasClass('fl-row-full-height'),
983				vidCSS          = {
984					top:       '50%',
985					left:      '50%',
986					transform: 'translate(-50%,-50%)',
987				};
988
989			if ( vid.length ) {
990				if(vidHeight === '' || typeof vidHeight === 'undefined' || vidWidth === '' || typeof vidWidth === 'undefined') {
991					vid.css({
992						'left'      : '0px',
993						'top'       : '0px',
994						'width'     : newWidth + 'px'
995					});
996
997					// Try to set the actual video dimension on 'loadedmetadata' when using URL as video source
998					vid.on('loadedmetadata', FLBuilderLayout._resizeOnLoadedMeta);
999
1000					return;
1001				}
1002
1003				if ( ! isRowFullHeight ) {
1004					if ( newHeight < wrapHeight ) {
1005						newHeight = wrapHeight;
1006						newWidth  = vidHeight ? Math.round(vidWidth * wrapHeight/vidHeight) : newWidth;
1007						newLeft   = -((newWidth - wrapWidth) / 2);
1008					}
1009					else {
1010						newTop = -((newHeight - wrapHeight)/2);
1011					}
1012					vidCSS = {
1013						left   : newLeft + 'px',
1014						top    : newTop + 'px',
1015						height : newHeight + 'px',
1016						width  : newWidth + 'px',
1017					}
1018				}
1019
1020				vid.css( vidCSS );
1021
1022			}
1023			else if ( iframe.length ) {
1024
1025				// Resize Youtube video player within iframe tag
1026				if ( typeof wrap.data('youtube') !== 'undefined' ) {
1027					FLBuilderLayout._resizeYoutubeBgVideo.apply(this);
1028				}
1029			}
1030		},
1031
1032		/**
1033		 * Fires when video meta has been loaded.
1034		 * This will be Triggered when width/height attributes were not specified during video background resizing.
1035		 *
1036		 * @since 1.8.5
1037		 * @access private
1038		 * @method _resizeOnLoadedMeta
1039		 */
1040		_resizeOnLoadedMeta: function(){
1041			var video 		= $(this),
1042				wrapHeight 	= video.parent().outerHeight(),
1043				wrapWidth 	= video.parent().outerWidth(),
1044				vidWidth 	= video[0].videoWidth,
1045				vidHeight 	= video[0].videoHeight,
1046				newHeight   = Math.round(vidHeight * wrapWidth/vidWidth),
1047				newWidth    = wrapWidth,
1048				newLeft     = 0,
1049				newTop 		= 0;
1050
1051			if(newHeight < wrapHeight) {
1052				newHeight   = wrapHeight;
1053				newWidth    = Math.round(vidWidth * wrapHeight/vidHeight);
1054				newLeft     = -((newWidth - wrapWidth)/2);
1055			}
1056			else {
1057				newTop      = -((newHeight - wrapHeight)/2);
1058			}
1059
1060			video.parent().data('width', vidWidth);
1061			video.parent().data('height', vidHeight);
1062
1063			video.css({
1064				'left'      : newLeft + 'px',
1065				'top'       : newTop + 'px',
1066				'width'     : newWidth + 'px',
1067				'height' 	: newHeight + 'px'
1068			});
1069		},
1070
1071		/**
1072		 * Fires when the window is resized to resize
1073		 * a single Youtube video background.
1074		 *
1075		 * @since 1.9
1076		 * @access private
1077		 * @method _resizeYoutubeBgVideo
1078		 */
1079		_resizeYoutubeBgVideo: function()
1080		{
1081			var wrap				= $(this),
1082				wrapWidth 			= wrap.outerWidth(),
1083				wrapHeight 			= wrap.outerHeight(),
1084				player 				= wrap.data('YTPlayer'),
1085				video 				= player ? player.getIframe() : null,
1086				aspectRatioSetting 	= '16:9', // Medium
1087				aspectRatioArray 	= aspectRatioSetting.split( ':' ),
1088				aspectRatio 		= aspectRatioArray[0] / aspectRatioArray[1],
1089				ratioWidth 			= wrapWidth / aspectRatio,
1090				ratioHeight 		= wrapHeight * aspectRatio,
1091				isWidthFixed 		= wrapWidth / wrapHeight > aspectRatio,
1092				width 				= isWidthFixed ? wrapWidth : ratioHeight,
1093				height 				= isWidthFixed ? ratioWidth : wrapHeight;
1094
1095			if ( video ) {
1096				$(video).width( width ).height( height );
1097			}
1098		},
1099
1100		/**
1101		 * Opens a tab or accordion item if the browser hash is set
1102		 * to the ID of one on the page.
1103		 *
1104		 * @since 1.6.0
1105		 * @access private
1106		 * @method _initHash
1107		 */
1108		_initHash: function()
1109		{
1110			var hash 			= window.location.hash.replace( '#', '' ).split( '/' ).shift(),
1111				element 		= null,
1112				tabs			= null,
1113				responsiveLabel	= null,
1114				tabIndex		= null,
1115				label			= null;
1116
1117			if ( '' !== hash ) {
1118
1119				try {
1120
1121					element = $( '#' + hash );
1122
1123					if ( element.length > 0 ) {
1124
1125						if ( element.hasClass( 'fl-accordion-item' ) ) {
1126							setTimeout( function() {
1127								element.find( '.fl-accordion-button' ).trigger( 'click' );
1128							}, 100 );
1129						}
1130						if ( element.hasClass( 'fl-tabs-panel' ) ) {
1131							setTimeout( function() {
1132								tabs 			= element.closest( '.fl-tabs' );
1133								responsiveLabel = element.find( '.fl-tabs-panel-label' );
1134								tabIndex 		= responsiveLabel.data( 'index' );
1135								label 			= tabs.find( '.fl-tabs-labels .fl-tabs-label[data-index=' + tabIndex + ']' );
1136
1137								label[0].click();
1138								FLBuilderLayout._scrollToElement(element);
1139							}, 100 );
1140						}
1141					}
1142				}
1143				catch( e ) {}
1144			}
1145		},
1146
1147		/**
1148		 * Adds a visually-hidden "(opens in new tab)" notice to links
1149		 * inside a builder layout that target a new tab, and removes it
1150		 * from ones that don't. Runs on the live DOM only, across every
1151		 * module, so the notice is never part of any saved content. Covers
1152		 * both real anchors (`target` attribute) and non-anchor elements
1153		 * like the Box module's `role="link"` div, which carries the same
1154		 * intent via a `data-link-target` attribute instead.
1155		 *
1156		 * @since 2.12
1157		 * @access private
1158		 * @method _initLinkNotices
1159		 */
1160		_initLinkNotices: function()
1161		{
1162			$( '.fl-builder-content a[target], .fl-builder-content [role="link"][data-link-target]' ).each( function() {
1163				var link   = $( this ),
1164					notice = link.children( 'span.fl-new-tab-notice' ),
1165					target = link.attr( 'target' ) || link.attr( 'data-link-target' );
1166
1167				if ( '_blank' === target ) {
1168					if ( 0 === notice.length ) {
1169						link.append( '<span class="fl-new-tab-notice sr-only">' + FLBuilderLayoutConfig.i18n.opensInNewTab + '</span>' );
1170					}
1171				} else if ( notice.length > 0 ) {
1172					notice.remove();
1173				}
1174			});
1175		},
1176
1177		/**
1178		 * Initializes all anchor links on the page for smooth scrolling.
1179		 *
1180		 * @since 1.4.9
1181		 * @access private
1182		 * @method _initAnchorLinks
1183		 */
1184		_initAnchorLinks: function()
1185		{
1186			$( 'a, [role="link"]' ).each( FLBuilderLayout._initAnchorLink );
1187		},
1188
1189		/**
1190		 * Initializes a single anchor link for smooth scrolling.
1191		 *
1192		 * @since 1.4.9
1193		 * @access private
1194		 * @method _initAnchorLink
1195		 */
1196		_initAnchorLink: function()
1197		{
1198			var link    = $( this ),
1199				href    = link.data( 'url' ) ? link.data( 'url' ) : link.attr( 'href' ),
1200				target  = link.data( 'url' ) ? new URL( href, window.location.href ) : this,
1201				loc     = window.location,
1202				id      = null,
1203				element = null,
1204				flNode  = false;
1205
1206			if ( 'undefined' != typeof href && href.indexOf( '#' ) > -1 && link.closest('svg').length < 1 ) {
1207
1208				if ( loc.pathname.replace( /^\//, '' ) == target.pathname.replace( /^\//, '' ) && loc.hostname == target.hostname ) {
1209
1210					try {
1211
1212						id      = href.split( '#' ).pop();
1213						// If there is no ID then we have nowhere to look
1214						// Fixes a quirk in jQuery and FireFox
1215						if( ! id ) {
1216							return;
1217						}
1218						element = $( '#' + id );
1219
1220						if ( element.length > 0 ) {
1221							flNode = element.hasClass( 'fl-row' ) || element.hasClass( 'fl-col' ) || element.hasClass( 'fl-module' );
1222							if ( !element.hasClass( 'fl-no-scroll' ) && ( link.hasClass( 'fl-scroll-link' ) || flNode ) ) {
1223								$( link ).on( 'click', FLBuilderLayout._scrollToElementOnLinkClick );
1224							}
1225							if ( element.hasClass( 'fl-accordion-item' ) ) {
1226								$( link ).on( 'click', FLBuilderLayout._scrollToAccordionOnLinkClick );
1227							}
1228							if ( element.hasClass( 'fl-tabs-panel' ) ) {
1229								$( link ).on( 'click', FLBuilderLayout._scrollToTabOnLinkClick );
1230							}
1231						}
1232					}
1233					catch( e ) {}
1234				}
1235			}
1236		},
1237
1238		/**
1239		 * Scrolls to an element when an anchor link is clicked.
1240		 *
1241		 * @since 1.4.9
1242		 * @access private
1243		 * @method _scrollToElementOnLinkClick
1244		 * @param {Object} e An event object.
1245		 * @param {Function} callback A function to call when the scroll is complete.
1246		 */
1247		_scrollToElementOnLinkClick: function( e, callback )
1248		{
1249			var attribute = $( this ).data( 'url' ) ? $( this ).data( 'url' ) : $( this ).attr( 'href' );
1250			var element = $( '#' + attribute.split( '#' ).pop() );
1251
1252			FLBuilderLayout._scrollToElement( element, callback );
1253
1254			e.preventDefault();
1255		},
1256
1257		/**
1258		 * Scrolls to an element.
1259		 *
1260		 * @since 1.6.4.5
1261		 * @access private
1262		 * @method _scrollToElement
1263		 * @param {Object} element The element to scroll to.
1264		 * @param {Function} callback A function to call when the scroll is complete.
1265		 */
1266		_scrollToElement: function( element, callback )
1267		{
1268			var config  = FLBuilderLayoutConfig.anchorLinkAnimations,
1269				dest    = 0,
1270				win     = $( window ),
1271				doc     = $( document );
1272
1273			if ( element.length > 0 ) {
1274
1275				if ( 'fixed' === element.css('position') || 'fixed' === element.parent().css('position') ) {
1276					dest = element.position().top;
1277				}
1278				else if ( element.offset().top > doc.height() - win.height() ) {
1279					dest = doc.height() - win.height();
1280				}
1281				else {
1282					dest = element.offset().top - config.offset;
1283				}
1284
1285				$( 'html, body' ).stop( true ).animate( { scrollTop: dest }, config.duration, config.easing, function() {
1286
1287					if ( 'undefined' != typeof callback ) {
1288						callback();
1289					}
1290
1291					if ( undefined != element.attr( 'id' ) && window.location.hash !== '#' + element.attr( 'id' ) ) {
1292
1293						var firefox_version = window.navigator.userAgent.match( /Firefox\/(\d+)\./ ),
1294							firefox_version = firefox_version ? parseInt( firefox_version[1], 10 ) : null;
1295
1296						if ( firefox_version !== null && firefox_version < 135 ) {
1297							window.location.hash = element.attr( 'id' );
1298						} else {
1299							if ( history.pushState ) {
1300								history.pushState( null, null, '#' + element.attr( 'id' ) );
1301							} else {
1302								window.location.hash = element.attr( 'id' );
1303							}
1304						}
1305					}
1306				} );
1307			}
1308		},
1309
1310		/**
1311		 * Scrolls to an accordion item when a link is clicked.
1312		 *
1313		 * @since 1.5.9
1314		 * @access private
1315		 * @method _scrollToAccordionOnLinkClick
1316		 * @param {Object} e An event object.
1317		 */
1318		_scrollToAccordionOnLinkClick: function( e )
1319		{
1320			var element = $( '#' + $( this ).attr( 'href' ).split( '#' ).pop() );
1321
1322			if ( element.length > 0 ) {
1323
1324				var callback = function() {
1325					if ( element ) {
1326						element.find( '.fl-accordion-button' ).trigger( 'click' );
1327						element = false;
1328					}
1329				};
1330
1331				FLBuilderLayout._scrollToElementOnLinkClick.call( this, e, callback );
1332			}
1333		},
1334
1335		/**
1336		 * Scrolls to a tab panel when a link is clicked.
1337		 *
1338		 * @since 1.5.9
1339		 * @access private
1340		 * @method _scrollToTabOnLinkClick
1341		 * @param {Object} e An event object.
1342		 */
1343		_scrollToTabOnLinkClick: function( e )
1344		{
1345			var element 		= $( '#' + $( this ).attr( 'href' ).split( '#' ).pop() ),
1346				tabs			= null,
1347				label   		= null,
1348				responsiveLabel = null;
1349
1350			if ( element.length > 0 ) {
1351
1352				tabs 			= element.closest( '.fl-tabs' );
1353				responsiveLabel = element.find( '.fl-tabs-panel-label' );
1354				tabIndex 		= responsiveLabel.data( 'index' );
1355				label 			= tabs.find( '.fl-tabs-labels .fl-tabs-label[data-index=' + tabIndex + ']' );
1356
1357				if ( responsiveLabel.is( ':visible' ) ) {
1358
1359					var callback = function() {
1360						if ( element ) {
1361							responsiveLabel.trigger( $.Event( 'click', { which: 1 } ) );
1362						}
1363					};
1364
1365					FLBuilderLayout._scrollToElementOnLinkClick.call( this, e, callback );
1366				}
1367				else {
1368					label[0].click();
1369					FLBuilderLayout._scrollToElement( element );
1370				}
1371
1372				e.preventDefault();
1373			}
1374		},
1375
1376		/**
1377		 * Initializes all builder forms on a page.
1378		 *
1379		 * @since 1.5.4
1380		 * @access private
1381		 * @method _initForms
1382		 */
1383		_initForms: function()
1384		{
1385			if ( ! FLBuilderLayout._hasPlaceholderSupport ) {
1386				$( '.fl-form-field input' ).each( FLBuilderLayout._initFormFieldPlaceholderFallback );
1387			}
1388
1389			$( '.fl-form-field input' ).on( 'focus', FLBuilderLayout._clearFormFieldError );
1390		},
1391
1392		/**
1393		 * Checks to see if the current device has HTML5
1394		 * placeholder support.
1395		 *
1396		 * @since 1.5.4
1397		 * @access private
1398		 * @method _hasPlaceholderSupport
1399		 * @return {Boolean}
1400		 */
1401		_hasPlaceholderSupport: function()
1402		{
1403			var input = document.createElement( 'input' );
1404
1405			return 'undefined' != input.placeholder;
1406		},
1407
1408		/**
1409		 * Initializes the fallback for when placeholders aren't supported.
1410		 *
1411		 * @since 1.5.4
1412		 * @access private
1413		 * @method _initFormFieldPlaceholderFallback
1414		 */
1415		_initFormFieldPlaceholderFallback: function()
1416		{
1417			var field       = $( this ),
1418				val         = field.val(),
1419				placeholder = field.attr( 'placeholder' );
1420
1421			if ( 'undefined' != placeholder && '' === val ) {
1422				field.val( placeholder );
1423				field.on( 'focus', FLBuilderLayout._hideFormFieldPlaceholderFallback );
1424				field.on( 'blur', FLBuilderLayout._showFormFieldPlaceholderFallback );
1425			}
1426		},
1427
1428		/**
1429		 * Hides a fallback placeholder on focus.
1430		 *
1431		 * @since 1.5.4
1432		 * @access private
1433		 * @method _hideFormFieldPlaceholderFallback
1434		 */
1435		_hideFormFieldPlaceholderFallback: function()
1436		{
1437			var field       = $( this ),
1438				val         = field.val(),
1439				placeholder = field.attr( 'placeholder' );
1440
1441			if ( val == placeholder ) {
1442				field.val( '' );
1443			}
1444		},
1445
1446		/**
1447		 * Shows a fallback placeholder on blur.
1448		 *
1449		 * @since 1.5.4
1450		 * @access private
1451		 * @method _showFormFieldPlaceholderFallback
1452		 */
1453		_showFormFieldPlaceholderFallback: function()
1454		{
1455			var field       = $( this ),
1456				val         = field.val(),
1457				placeholder = field.attr( 'placeholder' );
1458
1459			if ( '' === val ) {
1460				field.val( placeholder );
1461			}
1462		},
1463
1464		/**
1465		 * Clears a form field error message.
1466		 *
1467		 * @since 1.5.4
1468		 * @access private
1469		 * @method _clearFormFieldError
1470		 */
1471		_clearFormFieldError: function()
1472		{
1473			var field = $( this );
1474
1475			field.removeAttr( 'aria-invalid' );
1476			field.removeClass( 'fl-form-error' );
1477			const message = field.attr('aria-describedby');
1478			message ? $( '#' + message ).hide() : field.siblings( '.fl-form-error-message' ).hide();
1479		},
1480
1481		/**
1482		 * Init Row Shape Layer's height.
1483		 *
1484		 * @since 2.5.3
1485		 * @access private
1486		 * @method _initRowShapeLayerHeight
1487		 */
1488		_initRowShapeLayerHeight: function () {
1489			FLBuilderLayout._adjustRowShapeLayerHeight();
1490			$( window ).on( 'resize', FLBuilderLayout._adjustRowShapeLayerHeight );
1491		},
1492
1493		/**
1494		 * Set parent column width of nested columns when it's zero or blank.
1495		 *
1496		 * @since 2.7.4
1497		 * @access private
1498		 * @method _initNestedColsWidth
1499		 */
1500		_initNestedColsWidth: function()
1501		{
1502			var nestedCols = $( '.fl-col-has-cols' );
1503
1504			if ( nestedCols.length <= 0 ) {
1505				return;
1506			}
1507
1508			$( nestedCols ).each( function(index, col ){
1509				if ( $( col ).width() <= 0 ) {
1510					$( col ).css( 'width', FLBuilderLayoutConfig.emptyColWidth );
1511				}
1512			});
1513		},
1514
1515		/**
1516		 * Adjust Row Shape Layer's height to fix to remove the fine line that appears on certain screen sizes.
1517		 *
1518		 * @since 2.5.3
1519		 * @access private
1520		 * @method _adjustRowShapeLayerHeight
1521		 */
1522		_adjustRowShapeLayerHeight: function() {
1523			var rowShapeLayers = $('.fl-builder-shape-layer');
1524
1525			$( rowShapeLayers ).each(function (index) {
1526				var rowShapeLayer = $(this),
1527					shape = $(rowShapeLayer).find('svg'),
1528					height = shape.height(),
1529					excludeShapes = '.fl-builder-shape-circle, .fl-builder-shape-dot-cluster, .fl-builder-shape-topography, .fl-builder-shape-rect';
1530
1531				if ( ! rowShapeLayer.is( excludeShapes ) ) {
1532					$(shape).css('height', Math.ceil( height ) );
1533				}
1534			});
1535		},
1536		_string_to_slug: function( str ) {
1537			str = str.replace(/^\s+|\s+$/g, ''); // trim
1538			if ( 'undefined' == typeof window._fl_string_to_slug_regex ) {
1539				regex = new RegExp('[^a-zA-Z0-9\'":() !.,-_|]', 'g');
1540			} else {
1541				regex = new RegExp('[^' + window._fl_string_to_slug_regex + '\'":\(\) !.,-_|\\\p{Letter}]', 'ug');
1542			}
1543			str = str.replace(regex, '') // remove invalid chars
1544				.replace(/\s+/g, ' '); // collapse whitespace and replace by a space
1545			return str;
1546		},
1547		_reorderMenu: function() {
1548			if ( $('#wp-admin-bar-fl-builder-frontend-edit-link-default li').length > 1 ) {
1549					$( '#wp-admin-bar-fl-builder-frontend-duplicate-link' )
1550					.appendTo('#wp-admin-bar-fl-builder-frontend-edit-link-default')
1551					.css( 'padding-top', '5px' )
1552					.css( 'border-top', '2px solid #1D2125' )
1553					.css( 'margin-top', '5px' )
1554				}
1555		}
1556	};
1557
1558	/* Initializes the builder layout. */
1559	$(function(){
1560		FLBuilderLayout.init();
1561	});
1562
1563})(jQuery);
1564(function($){
1565
1566	if(typeof FLBuilderLayoutModules !== 'undefined') {
1567		return;
1568	}
1569
1570	/**
1571	 * Helper class with generic logic for builder modules.
1572	 * If generic module code needs to work in both the block
1573	 * editor and builder, it should go here. Otherwise, it
1574	 * should go on FLBuilderLayout.
1575	 *
1576	 * @since 2.9
1577	 */
1578	FLBuilderLayoutModules = {
1579
1580		/**
1581		 * Initializes builder module logic.
1582		 *
1583		 * @since 2.9
1584		 * @method init
1585		 */
1586		init: function()
1587		{
1588			// Only init if the builder isn't active.
1589			if ( 0 === $('.fl-builder-edit').length ) {
1590
1591				// Init module animations.
1592				FLBuilderLayoutModules._initModuleAnimations();
1593			}
1594		},
1595
1596		/**
1597		 * Initializes module animations.
1598		 *
1599		 * @since 1.1.9
1600		 * @access private
1601		 * @method _initModuleAnimations
1602		 */
1603		_initModuleAnimations: function()
1604		{
1605			if(typeof jQuery.fn.waypoint !== 'undefined') {
1606				$('.fl-animation').each( function() {
1607					var node = $( this ),
1608						nodeTop = node.offset().top,
1609						winHeight = $( window ).height(),
1610						bodyHeight = $( 'body' ).height(),
1611						waypoint = FLBuilderLayoutConfig.waypoint,
1612						offset = '80%';
1613
1614					if ( typeof waypoint.offset !== undefined ) {
1615						offset = FLBuilderLayoutConfig.waypoint.offset + '%';
1616					}
1617
1618					if ( bodyHeight - nodeTop < winHeight * 0.2 ) {
1619						offset = '100%';
1620					}
1621
1622					node.waypoint({
1623						offset: offset,
1624						handler: FLBuilderLayoutModules._doModuleAnimation
1625					});
1626				} );
1627			}
1628		},
1629
1630		/**
1631		 * Runs a module animation.
1632		 *
1633		 * @since 1.1.9
1634		 * @access private
1635		 * @method _doModuleAnimation
1636		 */
1637		_doModuleAnimation: function()
1638		{
1639			var module = 'undefined' == typeof this.element ? $(this) : $(this.element),
1640				delay = parseFloat(module.data('animation-delay')),
1641				duration = parseFloat(module.data('animation-duration'));
1642
1643			if ( ! isNaN( duration ) ) {
1644				module.css( 'animation-duration', duration + 's' );
1645			}
1646
1647			if(!isNaN(delay) && delay > 0) {
1648				setTimeout(function(){
1649					module.addClass('fl-animated');
1650				}, delay * 1000);
1651			} else {
1652				setTimeout(function(){
1653					module.addClass('fl-animated');
1654				}, 1);
1655			}
1656		}
1657	};
1658
1659	/* Initializes builder module logic. */
1660	$(function(){
1661		FLBuilderLayoutModules.init();
1662	});
1663
1664})(jQuery);
1665
1666/* Start Global JS */
1667document.addEventListener("DOMContentLoaded", function () {
1668    const menuToggle  = document.getElementById("unstuckMenuToggle");
1669    const menuOverlay = document.querySelector(".unstuck-menu-overlay-inner");
1670    const logoImg     = document.querySelector("#mobile-menu-logo img");
1671    const overlayLinks = document.querySelectorAll(".unstuck-menu-overlay-inner a");
1672
1673    if (!menuToggle || !menuOverlay) {
1674        return;
1675    }
1676
1677    let scrollPosition = 0;
1678
1679    // Logo sources
1680    const closedSrc = logoImg ? logoImg.getAttribute("src") : null;
1681    const openSrc   = "/wp-content/uploads/2025/11/The-Unstuck-Group-Inline-FullColor-Inverse.svg";
1682
1683    function lockBodyScroll() {
1684        scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
1685        document.body.style.position = "fixed";
1686        document.body.style.top = `-${scrollPosition}px`;
1687        document.body.style.left = "0";
1688        document.body.style.right = "0";
1689        document.body.style.width = "100%";
1690    }
1691
1692    function unlockBodyScroll() {
1693        document.body.style.position = "";
1694        document.body.style.top = "";
1695        document.body.style.left = "";
1696        document.body.style.right = "";
1697        document.body.style.width = "";
1698        window.scrollTo(0, scrollPosition);
1699    }
1700
1701    function openMenu() {
1702        if (menuOverlay.classList.contains("active")) return;
1703
1704        menuToggle.classList.add("open");
1705        menuOverlay.classList.add("active");
1706        document.body.classList.add("menu-open");
1707        lockBodyScroll();
1708
1709        if (logoImg && closedSrc && openSrc) {
1710            fadeSwapLogo(openSrc);
1711        }
1712    }
1713
1714    function closeMenu() {
1715        if (!menuOverlay.classList.contains("active")) return;
1716
1717        menuToggle.classList.remove("open");
1718        menuOverlay.classList.remove("active");
1719        document.body.classList.remove("menu-open");
1720        unlockBodyScroll();
1721
1722        if (logoImg && closedSrc) {
1723            fadeSwapLogo(closedSrc);
1724        }
1725    }
1726
1727    // Toggle menu open/close
1728    menuToggle.addEventListener("click", function (e) {
1729        e.stopPropagation();
1730
1731        if (menuOverlay.classList.contains("active")) {
1732            closeMenu();
1733        } else {
1734            openMenu();
1735        }
1736    });
1737
1738    // Close menu on link click inside overlay
1739    overlayLinks.forEach(link => {
1740        link.addEventListener("click", function () {
1741            closeMenu();
1742        });
1743    });
1744
1745    // Close on ESC
1746    document.addEventListener("keydown", function (e) {
1747        if (e.key === "Escape" && document.body.classList.contains("menu-open")) {
1748            closeMenu();
1749        }
1750    });
1751
1752    // Optional: close if you click outside overlay & toggle
1753    document.addEventListener("click", function (e) {
1754        if (!document.body.classList.contains("menu-open")) return;
1755
1756        const clickedOverlay = menuOverlay.contains(e.target);
1757        const clickedToggle  = e.target.closest("#unstuckMenuToggle");
1758
1759        if (!clickedOverlay && !clickedToggle) {
1760            closeMenu();
1761        }
1762    });
1763
1764    function fadeSwapLogo(newSrc) {
1765        if (!logoImg) return;
1766
1767        // Save current transition (if any)
1768        const previousTransition = logoImg.style.transition;
1769
1770        // Disable transitions for instant swap
1771        logoImg.style.transition = "none";
1772
1773        // Swap image immediately
1774        logoImg.setAttribute("src", newSrc);
1775
1776        // Force a reflow so browser applies change instantly
1777        void logoImg.offsetHeight;
1778
1779        // Restore old transition after the frame
1780        requestAnimationFrame(() => {
1781            logoImg.style.transition = previousTransition;
1782        });
1783    }
1784});
1785
1786document.addEventListener('DOMContentLoaded', function () {
1787  document.querySelectorAll('.back-button').forEach(function (btn) {
1788    btn.addEventListener('click', function (e) {
1789      const hasHistory = window.history.length > 1 && document.referrer;
1790
1791      if (hasHistory) {
1792        e.preventDefault();
1793        window.history.back();
1794      }
1795      // else: do nothing → browser follows the normal href set in Beaver Builder
1796    });
1797  });
1798});
1799
1800
1801/* End Global JS */
1802
1803
1804;/* eslint-disable no-undef */
1805(function($) {
1806
1807	FLBuilderSearchForm = function(settings) {
1808		this.settings   = settings;
1809		this.nodeClass  = '.fl-node-' + settings.id;
1810		this.searchForm = $(this.nodeClass + ' .fl-search-form');
1811		this.form       = this.searchForm.find('form');
1812		this.input      = this.form.find('input[type=search]');
1813		this.button     = this.searchForm.find('.fl-button:is(a, button:not([type="submit"]), .fl-button:is(a, button:not([type="submit"]) *');
1814		this.resultsEl  = $(this.nodeClass + ' .fl-search-results-content');
1815
1816		this._init();
1817	};
1818
1819	FLBuilderSearchForm.prototype = {
1820
1821		settings: {},
1822		nodeClass: '',
1823		searchForm: '',
1824		form: null,
1825		input: null,
1826		button: null,
1827		resultsEl: '',
1828		searching: false,
1829		prevSearchData: {},
1830		request: null,
1831
1832		_init: function() {
1833			this._bindEvents();
1834			this._popupSearch();
1835		},
1836
1837		_bindEvents: function(){
1838			var $this        = this,
1839				keyCode      = null,
1840				keyType      = null,
1841			    enterPressed = false,
1842				t, et;
1843
1844			this.button.on('click', $.proxy(this._buttonClick, this));
1845			this.input.on('input', (event) => {
1846				const input = event.target;
1847				if ( input.checkValidity() ) {
1848					input.removeAttribute('aria-invalid');
1849				} else {
1850					input.setAttribute('aria-invalid', true);
1851				}
1852			});
1853
1854			if ( this.searchForm.hasClass('fl-search-button-expand') ) {
1855				this.input.attr({'id':  'input-' + this.settings.id, 'tabindex': -1});
1856				this.button.closest('.fl-button').attr({'aria-controls': 'input-' + this.settings.id, 'aria-expanded': false});
1857			}
1858			else if ( this.searchForm.hasClass('fl-search-button-reveal') ) {
1859				const form = this.searchForm.find('.fl-search-form-input-wrap');
1860				form.attr('id',  'form-' + this.settings.id);
1861				this.button.closest('.fl-button').attr({'aria-controls': 'form-' + this.settings.id, 'aria-expanded': false, 'aria-haspopup': true});
1862				form.on('focusout', (event) => {
1863					if (form.is(':visible') && form.has($(event.relatedTarget)).length === 0) {
1864						this._buttonClick(event);
1865					}
1866				});
1867				this.searchForm.on('keydown', (event) => {
1868					if (event.key === 'Escape' && form.is(':visible')) {
1869						this.button.focus();
1870					}
1871				});
1872			}
1873
1874			if ( 'ajax' == this.settings.result ) {
1875				$(document).on('click touchend', function(e){
1876					if( $(e.target).is('input') ) return;
1877
1878					$this._hideResults();
1879				} );
1880
1881				$this.resultsEl.bind("click touchend", function (e) {
1882	                e.stopImmediatePropagation();
1883	            });
1884
1885				// Disable form submit.
1886				$this.form.on( 'submit', function (e) {
1887                    e.preventDefault();
1888	            });
1889
1890				// Prevent auto-clearing errors in the FLBuilderLayout helper class.
1891				this.input.off('focus');
1892
1893				this.input.on('keyup', function(e) {
1894                    if (window.event) {
1895						keyCode = window.event.keyCode;
1896                        keyType = window.event.type;
1897                    } else if (e) {
1898						keyCode = e.which;
1899                        keyType = e.type;
1900                    }
1901
1902					// Prevent rapid enter
1903	                if ( 13 == keyCode ) {
1904	                    clearTimeout(et);
1905	                    et = setTimeout(function(){
1906	                        enterPressed = false;
1907	                    }, 300);
1908	                    if ( enterPressed ) {
1909					        return false;
1910	                    } else {
1911	                        enterPressed = true;
1912	                    }
1913	                }
1914
1915					if ( $this.input.val().length >= 3 && 'keyup' == keyType && 13 == keyCode ) {
1916						$this._search(e);
1917						return false;
1918					}
1919                });
1920
1921				this.input.on('click input', function(e) {
1922					if (window.event) {
1923						keyCode = window.event.keyCode;
1924                        keyType = window.event.type;
1925                    } else if (e) {
1926                        keyCode = e.which;
1927                        keyType = e.type;
1928                    }
1929
1930					// F1 to F12
1931					if ( (keyCode >= 37 && keyCode <= 40) || (keyCode >= 112 && keyCode <= 123) ) {
1932						return;
1933					}
1934
1935					if ($this.input.val().length < 3) {
1936	                    $this._hideLoader();
1937	                    $this._hideResults();
1938	                    $this.input.attr('aria-invalid', true);
1939	                    if ($this.post != null) $this.post.abort();
1940	                    clearTimeout(t);
1941	                    return;
1942	                }
1943
1944	                if ( 'click' == keyType || keyCode == 32 ) {
1945						if ( $this.resultsEl.html().length != 0 ) {
1946							clearTimeout(t);
1947							if( $this.resultsEl.hasClass('fl-search-open') ) return;
1948							$this._showResults();
1949						}
1950						else {
1951							$this._hideResults();
1952						}
1953						return;
1954	                }
1955
1956	                if ($this.request != null) $this.request.abort();
1957	                $this._hideLoader();
1958
1959					clearTimeout(t);
1960					t = setTimeout(function() {
1961						$this._search(e);
1962					}, 100);
1963				});
1964			}
1965		},
1966
1967		_search: function(e) {
1968			if ($.trim(this.input.val()).length < 1 || ('ajax' == this.settings.result && this.input.val().length < 3)) {
1969				this.input.attr('aria-invalid', true);
1970				return;
1971			}
1972			e.preventDefault();
1973
1974			if ( 'ajax' == this.settings.result ) {
1975				this._doAjaxSearch();
1976			}
1977			else {
1978				this.form.submit();
1979				// TODO: _doRedirectResults()
1980			}
1981
1982			return false;
1983		},
1984
1985		_doAjaxSearch: function() {
1986			var searchText     = this.input.val(),
1987				postId         = this.searchForm.closest( '.fl-builder-content' ).data( 'post-id' ),
1988				templateId     = this.searchForm.data( 'template-id' ),
1989				templateNodeId = this.searchForm.data( 'template-node-id' ),
1990				ajaxData       = {},
1991				self           = this;
1992
1993			if ( searchText.length < 1 ) return;
1994
1995			this.searching = true;
1996
1997			// Show loader
1998			this._showLoader();
1999
2000			ajaxData = {
2001				action           : 'fl_search_query',
2002				keyword          : searchText,
2003				post_id          : postId,
2004				template_id      : templateId,
2005				template_node_id : templateNodeId,
2006				node_id          : this.settings.id,
2007				nonce            : this.settings.nonce,
2008			}
2009
2010			// Check to see if searching the same keywords.
2011			if ( JSON.stringify(ajaxData) === JSON.stringify(this.prevSearchData) ) {
2012				if ( ! this.resultsEl.hasClass('fl-search-open') ) {
2013					this._showResults();
2014				}
2015                this._hideLoader();
2016                return false;
2017            }
2018
2019			// Send server request.
2020			this.request = $.post( FLBuilderLayoutConfig.paths.wpAjaxUrl, ajaxData, function(response){
2021				self._hideLoader();
2022
2023				self.resultsEl.html("");
2024				self.resultsEl.html(response);
2025				self._showResults();
2026
2027				self.prevSearchData = ajaxData;
2028			});
2029		},
2030
2031		_popupSearch: function() {
2032			var inputWrap = this.searchForm.find('.fl-search-form-input-wrap'),
2033				$this     = this;
2034
2035			if ('button' !== this.settings.layout || ( 'fullscreen' !== this.settings.btnAction && 'reveal' !== this.settings.btnAction )) {
2036				return;
2037			}
2038
2039			this.button.off('click');
2040			this.button.magnificPopup({
2041				type: 'inline',
2042				mainClass: 'fl-node-' + this.settings.id,
2043				items: {
2044					src: inputWrap[0],
2045				},
2046				alignTop: true,
2047				showCloseBtn: $this.settings.showCloseBtn,
2048				closeBtnInside: false,
2049				enableEscapeKey: true,
2050				closeOnBgClick: false,
2051				focus: 'input[type=search]',
2052				tLoading: '<i class="fas fa-spinner fa-spin fa-3x fa-fw"></i>',
2053				callbacks: {
2054					open: function(){
2055						$this.input.trigger('click');
2056					}
2057				}
2058			});
2059			this.resultsEl.appendTo( inputWrap );
2060		},
2061
2062		_buttonClick: function(e) {
2063			e.stopImmediatePropagation();
2064			if (this.searchForm.hasClass('fl-search-button-expand')) {
2065				this.searchForm.find('.fl-search-form-wrap').toggleClass('fl-search-expanded');
2066
2067				if (this.searchForm.find('.fl-search-form-wrap').hasClass('fl-search-expanded')) {
2068					this.button.closest('.fl-button').attr('aria-expanded', true);
2069					this.input.attr('tabindex', 0);
2070					this.input.focus();
2071				}
2072				else {
2073					this._hideResults();
2074					this.input.attr('tabindex', -1);
2075					this.button.closest('.fl-button').attr('aria-expanded', false);
2076				}
2077
2078				return false;
2079			} else if (this.searchForm.hasClass('fl-search-button-reveal') && $(e.target).closest('.fl-button:not([type="submit"])')) {
2080				const form = this.searchForm.find('.fl-search-form-input-wrap');
2081				if (e.detail && e.type === 'click' && form.is(':visible')) return false;
2082				form.fadeToggle('fast', () => {
2083					this.button.attr('aria-expanded', form.is(':visible'));
2084					if (form.is(':visible')) {
2085						this.input.focus();
2086					}
2087				});
2088
2089				return false;
2090			} else {
2091				this._search(e);
2092			}
2093		},
2094
2095		_showResults: function(){
2096			// Close any search results in a page.
2097			this._hideResults();
2098			this.resultsEl.addClass('fl-search-open');
2099
2100			if ('button' == this.settings.layout && 'expand' == this.settings.btnAction) {
2101				this.searchForm.find('.fl-search-form-input-wrap').css('overflow', 'visible');
2102			}
2103		},
2104
2105		_hideResults: function(){
2106			$('.fl-search-results-content').removeClass('fl-search-open');
2107
2108			if ('button' == this.settings.layout && 'expand' == this.settings.btnAction) {
2109				this.searchForm.find('.fl-search-form-input-wrap').removeAttr('style');
2110			}
2111		},
2112
2113		_doRedirectResults: function(){
2114			// TODO
2115		},
2116
2117		_showLoader: function(){
2118			$(this.nodeClass + ' .fl-search-loader-wrap').show();
2119		},
2120
2121		_hideLoader: function(){
2122			this.searching = false;
2123			$(this.nodeClass + ' .fl-search-loader-wrap').hide();
2124		},
2125
2126		_cleanInput: function(s) {
2127	        return encodeURIComponent(s).replace(/%20/g, '+');
2128	    }
2129
2130	}
2131
2132})(jQuery);
2133(function($) {
2134
2135	$(function() {
2136		new FLBuilderSearchForm({
2137			id: '613a41840bafb',
2138			layout: 'input',
2139			btnAction: 'expand',
2140			result: 'ajax',
2141			showCloseBtn: true,
2142			nonce: '3bd9264a44',
2143		});
2144	});
2145
2146})(jQuery);
2147
2148;/* eslint-disable no-undef */
2149(function($) {
2150
2151	FLBuilderPostGrid = function(settings)
2152	{
2153		this.settings    = settings;
2154		this.nodeClass   = '.fl-node-' + settings.id;
2155		this.matchHeight = settings.matchHeight;
2156
2157		if ( 'columns' == this.settings.layout ) {
2158			this.wrapperClass = this.nodeClass + ' .fl-post-grid';
2159			this.postClass    = this.nodeClass + ' .fl-post-column';
2160		}
2161		else {
2162			this.wrapperClass = this.nodeClass + ' .fl-post-' + this.settings.layout;
2163			this.postClass    = this.wrapperClass + '-post';
2164		}
2165
2166		if(this._hasPosts()) {
2167			this._initLayout();
2168			this._initInfiniteScroll();
2169		}
2170	};
2171
2172	FLBuilderPostGrid.prototype = {
2173
2174		settings        : {},
2175		nodeClass       : '',
2176		wrapperClass    : '',
2177		postClass       : '',
2178		gallery         : null,
2179		currPage		: 1,
2180		totalPages		: 1,
2181
2182		_hasPosts: function()
2183		{
2184			return $(this.postClass).length > 0;
2185		},
2186
2187		_initLayout: function()
2188		{
2189			switch(this.settings.layout) {
2190
2191				case 'columns':
2192				this._columnsLayout();
2193				break;
2194
2195				case 'grid':
2196				this._gridLayout();
2197				break;
2198
2199				case 'gallery':
2200				this._galleryLayout();
2201				break;
2202			}
2203
2204			$(this.postClass).css('visibility', 'visible');
2205
2206			FLBuilderLayout._scrollToElement( $( this.nodeClass + ' .fl-paged-scroll-to' ) );
2207		},
2208
2209		_columnsLayout: function()
2210		{
2211			$(this.wrapperClass).imagesLoaded( $.proxy( function() {
2212				this._gridLayoutMatchHeight();
2213			}, this ) );
2214
2215			$( window ).on( 'resize', $.proxy( function(){
2216				$(this.wrapperClass).imagesLoaded( $.proxy( function() {
2217					this._gridLayoutMatchHeight();
2218				}, this ) );
2219			}, this ) );
2220		},
2221
2222		_gridLayout: function()
2223		{
2224			var wrap = $(this.wrapperClass);
2225
2226			wrap.masonry({
2227				columnWidth         : this.nodeClass + ' .fl-post-grid-sizer',
2228				gutter              : parseInt(this.settings.postSpacing),
2229				isFitWidth          : true,
2230				itemSelector        : this.postClass,
2231				transitionDuration  : 0,
2232				isRTL               : this.settings.isRTL
2233			});
2234
2235			wrap.imagesLoaded( $.proxy( function() {
2236				this._gridLayoutMatchHeight();
2237				wrap.masonry();
2238			}, this ) );
2239
2240			$(window).scroll($.debounce( 25, function(){
2241				wrap.masonry()
2242			}));
2243
2244		},
2245
2246		_gridLayoutMatchHeight: function()
2247		{
2248			var highestBox = 0;
2249
2250			if ( ! this._isMatchHeight() ) {
2251				$(this.nodeClass + ' .fl-post-grid-post').css('height', '');
2252				return;
2253			}
2254
2255            $(this.nodeClass + ' .fl-post-grid-post').css('height', '').each(function(){
2256
2257                if($(this).height() > highestBox) {
2258                	highestBox = $(this).height();
2259                }
2260            });
2261
2262            $(this.nodeClass + ' .fl-post-grid-post').height(highestBox);
2263		},
2264
2265		_isMatchHeight: function(){
2266			var width 		= $( window ).width(),
2267				breakpoints = FLBuilderLayoutConfig.breakpoints,
2268				matchLarge = '' != this.matchHeight.large ? this.matchHeight.large : this.matchHeight.default,
2269				matchMedium = '' != this.matchHeight.medium ? this.matchHeight.medium : this.matchHeight.default,
2270				matchSmall  = '' != this.matchHeight.responsive ? this.matchHeight.responsive : this.matchHeight.default;
2271
2272			return (width > breakpoints.medium && 1 == this.matchHeight.default) // Must check medium here for backwards compat
2273				   || (width > breakpoints.medium && width <= breakpoints.large && 1 == matchLarge)
2274				   || (width > breakpoints.small && width <= breakpoints.medium && 1 == matchMedium)
2275				   || (width <= breakpoints.small && 1 == matchSmall);
2276		},
2277
2278		_galleryLayout: function()
2279		{
2280			this.gallery = new FLBuilderGalleryGrid({
2281				'wrapSelector' : this.wrapperClass,
2282				'itemSelector' : '.fl-post-gallery-post',
2283				'isRTL'        : this.settings.isRTL
2284			});
2285		},
2286
2287		_initInfiniteScroll: function()
2288		{
2289			var isScroll = 'scroll' == this.settings.pagination || 'load_more' == this.settings.pagination,
2290				pages	 = $( this.nodeClass + ' .fl-builder-pagination' ).find( 'li .page-numbers:not(.next)' );
2291
2292			if( pages.length > 1) {
2293				total = pages.last().text().replace( /\D/g, '' )
2294				this.totalPages = parseInt( total );
2295			}
2296
2297			if( isScroll && this.totalPages > 1 && 'undefined' === typeof FLBuilder ) {
2298				this._infiniteScroll();
2299
2300				if( 'load_more' == this.settings.pagination ) {
2301					this._infiniteScrollLoadMore();
2302				}
2303			}
2304		},
2305
2306		_infiniteScroll: function()
2307		{
2308			var path 		= $(this.nodeClass + ' .fl-builder-pagination a.next').attr('href'),
2309				pagePattern = /(.*?(\/|&|\?)paged-[0-9]{1,}(\/|=))([0-9]{1,})+(.*)/,
2310				wpPattern   = /^(.*?\/?page\/?)(?:\d+)(.*?$)/,
2311				pageMatched = null,
2312				scrollData	= {
2313					navSelector     : this.nodeClass + ' .fl-builder-pagination',
2314					nextSelector    : this.nodeClass + ' .fl-builder-pagination a.next',
2315					itemSelector    : this.postClass,
2316					prefill         : true,
2317					bufferPx        : 200,
2318					loading         : {
2319						msgText         : this.settings.loadingText,
2320						finishedMsg     : '',
2321						img             : FLBuilderLayoutConfig.paths.pluginUrl + 'img/ajax-loader-grey.gif',
2322						speed           : 1
2323					}
2324				};
2325			// Define path since Infinitescroll incremented our custom pagination '/paged-2/2/' to '/paged-3/2/'.
2326			if ( pagePattern.test( path ) ) {
2327				scrollData.path = function( currPage ){
2328					pageMatched = path.match( pagePattern );
2329					path = pageMatched[1] + currPage + pageMatched[5];
2330					return path;
2331				}
2332			}
2333			else if ( wpPattern.test( path ) ) {
2334				scrollData.path = path.match( wpPattern ).slice( 1 );
2335			}
2336
2337			$(this.postClass).first().parent().infinitescroll( scrollData, $.proxy(this._infiniteScrollComplete, this) );
2338
2339			setTimeout(function(){
2340				$(window).trigger('resize');
2341			}, 100);
2342		},
2343
2344		_infiniteScrollComplete: function(elements)
2345		{
2346			var wrap = $(this.wrapperClass);
2347
2348			elements = $(elements);
2349
2350			if(this.settings.layout == 'columns') {
2351				wrap.imagesLoaded( $.proxy( function() {
2352					$( '#infscr-loading' ).remove();
2353					this._gridLayoutMatchHeight();
2354					elements.css('visibility', 'visible');
2355				}, this ) );
2356			}
2357			else if(this.settings.layout == 'grid') {
2358				wrap.imagesLoaded( $.proxy( function() {
2359					this._gridLayoutMatchHeight();
2360					wrap.masonry('appended', elements);
2361					wrap.masonry();
2362					elements.css('visibility', 'visible');
2363				}, this ) );
2364			}
2365			else if(this.settings.layout == 'gallery') {
2366				this.gallery.resize();
2367				elements.css('visibility', 'visible');
2368			}
2369
2370			if( 'load_more' == this.settings.pagination ) {
2371				$( this.wrapperClass + ' .fl-post-grid-sizer.masonry-brick' ).appendTo( this.wrapperClass );
2372				$( '#infscr-loading' ).appendTo( this.wrapperClass );
2373			}
2374
2375			this.currPage++;
2376
2377			this._removeLoadMoreButton();
2378
2379			// trigger an event
2380			node = $(wrap).closest('.fl-module-post-grid').data('node')
2381			$('.fl-node-' + node).trigger( 'gridScrollComplete', this );
2382		},
2383
2384		_infiniteScrollLoadMore: function()
2385		{
2386			var wrap = $( this.postClass ).first().parent();
2387
2388			$( window ).unbind( '.infscr' );
2389
2390			$(this.nodeClass + ' .fl-builder-pagination-load-more .fl-button').on( 'click', function(){
2391				if( $( '#infscr-loading' ).length ) {
2392					$( '#infscr-loading' ).remove();
2393				}
2394
2395				wrap.infinitescroll( 'retrieve' );
2396				return false;
2397			});
2398		},
2399
2400		_removeLoadMoreButton: function()
2401		{
2402			if ( 'load_more' == this.settings.pagination && this.totalPages == this.currPage ) {
2403				$( this.nodeClass + ' .fl-builder-pagination-load-more' ).remove();
2404			}
2405		}
2406	};
2407
2408})(jQuery);
2409(function($) {
2410
2411	$(function() {
2412
2413		new FLBuilderPostGrid({
2414			id: '613a41840bb03',
2415			layout: 'columns',
2416			pagination: 'none',
2417			postSpacing: '30',
2418			postWidth: '300',
2419			matchHeight: {
2420				default	   : '0',
2421				large 	   : '',
2422				medium 	   : '',
2423				responsive : ''
2424			},
2425			isRTL: false,
2426			loadingText: 'Loading...'
2427		});
2428
2429			});
2430
2431})(jQuery);
2432(function($) {
2433
2434	$(function() {
2435
2436		new FLBuilderPostGrid({
2437			id: '613a41840bb0f',
2438			layout: 'columns',
2439			pagination: 'none',
2440			postSpacing: '30',
2441			postWidth: '300',
2442			matchHeight: {
2443				default	   : '0',
2444				large 	   : '',
2445				medium 	   : '',
2446				responsive : ''
2447			},
2448			isRTL: false,
2449			loadingText: 'Loading...'
2450		});
2451
2452			});
2453
2454})(jQuery);
2455(function($) {
2456
2457	$(function() {
2458
2459		new FLBuilderPostGrid({
2460			id: '613a41840bb16',
2461			layout: 'columns',
2462			pagination: 'none',
2463			postSpacing: '30',
2464			postWidth: '300',
2465			matchHeight: {
2466				default	   : '0',
2467				large 	   : '',
2468				medium 	   : '',
2469				responsive : ''
2470			},
2471			isRTL: false,
2472			loadingText: 'Loading...'
2473		});
2474
2475			});
2476
2477})(jQuery);
2478(function($){
2479	})(jQuery);
2480(function($){
2481	})(jQuery);
2482(function($){
2483	})(jQuery);
2484(function($){
2485		$('.fl-node-613a41840baf3').each(function(){
2486		var $this = $(this);
2487		$this.find('.fl-button-lightbox').magnificPopup({
2488			
2489						type: 'inline',
2490			items: {
2491				src: $this.find('.fl-button-lightbox-content')[0]
2492			},
2493			callbacks: {
2494				open: function() {
2495					var content = $(this.content),
2496						divWrap = $(content[0]).find('> div');
2497
2498					divWrap.css('display', 'block');
2499
2500					// Triggers select change in we have multiple forms in a page
2501					if ( divWrap.find('form select').length > 0 ) {
2502						divWrap.find('form select').trigger('change');
2503					}
2504
2505					// reload sliders.
2506					FLBuilderLayout.reloadSlider(content);
2507					FLBuilderLayout.resizeSlideshow();
2508				},
2509			},
2510						closeBtnInside: true,
2511			fixedContentPos: true,
2512			tLoading: '<i class="fas fa-spinner fa-spin fa-3x fa-fw"></i>',
2513		});
2514	});
2515	})(jQuery);
2516
2517/* Start Global Node Custom JS */
2518
2519/* End Global Node Custom JS */
2520
2521
2522/* Start Layout Custom JS */
2523document.addEventListener('DOMContentLoaded', function () {
2524
2525  // Blog post slider (single slide, dots)
2526  const blogPostSwiperEl = document.querySelector('.blog-post-swiper');
2527  if (blogPostSwiperEl) {
2528    new Swiper('.blog-post-swiper', {
2529      loop: true,
2530      slidesPerView: 1,
2531      spaceBetween: 0,
2532      pagination: {
2533        el: '.blog-post-swiper .swiper-pagination',
2534        clickable: true,
2535      },
2536    });
2537  }
2538
2539  // Blog category grid slider (2-row grid, custom nav icons)
2540  const categorySwiperEl = document.querySelector('.unstuck-blog-category-swiper');
2541  if (categorySwiperEl) {
2542    new Swiper('.unstuck-blog-category-swiper', {
2543      slidesPerView: 1,
2544      loop: true,
2545      grid: {
2546        rows: 2,
2547        fill: 'row',
2548      },
2549      spaceBetween: 30,
2550      navigation: {
2551        // Beaver Builder icon modules with these extra classes
2552        nextEl: '.unstuck-blog-category-next',
2553        prevEl: '.unstuck-blog-category-prev',
2554      },
2555     
2556      breakpoints: {
2557        640: {
2558          slidesPerView: 2,
2559          grid: {
2560            rows: 2,
2561            fill: 'row',
2562          },
2563        },
2564        1024: {
2565          slidesPerView: 2,
2566          grid: {
2567            rows: 2,
2568            fill: 'row',
2569          },
2570        },
2571      },
2572    });
2573  }
2574
2575});
2576
2577/* End Layout Custom JS */
2578
2579
2580		(function($){
2581			$('.fl-node-6166f998914b5').each(function(){
2582				var $this = $(this);
2583								$this.find('#fl-node-6166f998914b5-1 .fl-button-lightbox').magnificPopup({
2584					
2585										type: 'inline',
2586					callbacks: {
2587						elementParse: function(item) {
2588							item.src = $( item.el ).closest('.fl-button-wrap').find('.fl-button-lightbox-content');
2589						},
2590						open: function() {
2591							var divWrap = $( $(this.content)[0] ).find('> div');
2592							divWrap.css('display', 'block');
2593
2594							// Triggers select change in we have multiple forms in a page
2595							if ( divWrap.find('form select').length > 0 ) {
2596								divWrap.find('form select').trigger('change');
2597							}
2598						}
2599					},
2600										closeBtnInside: true,
2601					fixedContentPos: true,
2602					tLoading: '<i class="fas fa-spinner fa-spin fa-3x fa-fw"></i>'
2603				});
2604							});
2605		})(jQuery);
2606		jQuery(function($) {
2607	
2608		$(function() {
2609		$( '.fl-node-xnztwfgjbr49 .fl-photo-img' )
2610			.on( 'mouseenter', function( e ) {
2611				$( this ).data( 'title', $( this ).attr( 'title' ) ).removeAttr( 'title' );
2612			} )
2613			.on( 'mouseleave', function( e ){
2614				$( this ).attr( 'title', $( this ).data( 'title' ) ).data( 'title', null );
2615			} );
2616	});
2617		window._fl_string_to_slug_regex = 'a-zA-Z0-9';
2618});
2619
2620;/* eslint-disable no-undef */
2621(function($) {
2622
2623	/**
2624	 * Class for Menu Module
2625	 *
2626	 * @since 1.6.1
2627	 */
2628	FLBuilderMenu = function( settings ){
2629
2630		// set params
2631		this.nodeId              = settings.id;
2632		this.nodeClass           = '.fl-node-' + settings.id;
2633		this.wrapperClass        = this.nodeClass + ' .fl-menu';
2634		this.type				 				 = settings.type;
2635		this.mobileToggle		     = settings.mobile;
2636		this.mobileBelowRow		   = settings.mobileBelowRow;
2637		this.mobileFlyout		     = settings.mobileFlyout;
2638		this.breakPoints         = settings.breakPoints;
2639		this.mobileBreakpoint	 	 = settings.mobileBreakpoint;
2640		this.currentBrowserWidth = $( window ).width();
2641		this.postId              = settings.postId;
2642		this.mobileStacked       = settings.mobileStacked;
2643		this.submenuIcon         = settings.submenuIcon;
2644		this.flyoutWidth         = settings.flyoutWidth;
2645
2646		// initialize the menu
2647		this._initMenu();
2648
2649		// check if viewport is resizing
2650		$( window ).on( 'resize', $.proxy( function() {
2651
2652			var width = $( window ).width();
2653
2654			// if screen width is resized, reload the menu
2655		    if( width != this.currentBrowserWidth ){
2656
2657				this.currentBrowserWidth = width;
2658				this._initMenu( true );
2659 				this._clickOrHover( true );
2660			}
2661
2662			this._resizeFlyoutMenuPanel();
2663		}, this ) );
2664
2665		$( window ).on( 'scroll', $.proxy( function() {
2666			this._resizeFlyoutMenuPanel();
2667		}, this ) );
2668
2669		// Move focus to the first menu item if the layout is set to BelowRow
2670		$( this.wrapperClass ).on( 'keydown', '.fl-menu-mobile-toggle, .menu-item:first a:first', $.proxy( function ( event ) {
2671			// Make sure it is a tab key with both the menu toggle enabled & below row layout set
2672			if ( event.key !== 'Tab' || ! this._isMenuToggle() || ! this._isMobileBelowRowEnabled() ) {
2673				return;
2674			}
2675			// Trigger focus on the mobile toggle button if the user is shift tabbing from the first menu item
2676			if ( event.shiftKey && $( event.currentTarget ).is( 'a' ) ) {
2677				event.preventDefault();
2678				$( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).trigger( 'focus' );
2679			}
2680			// Trigger focus on the first menu item if the user is tabbing from the mobile toggle button
2681			else if ( ! event.shiftKey && $( event.currentTarget ).hasClass( 'fl-menu-mobile-toggle' ) && $( event.currentTarget ).hasClass( 'fl-active' )  ) {
2682				event.preventDefault();
2683				$( this.wrapperClass ).find( '.menu-item' ).first().find( 'a' ).first().trigger( 'focus' );
2684			}
2685		}, this ) );
2686
2687		// Close mobile menu or accordion when tabbing out from the first or last menu item
2688		$( this.wrapperClass ).on( 'focusout', $.proxy( function ( event ) {
2689			if ( $( this.wrapperClass + ' nav' ).has( $( event.relatedTarget ) ).length === 0 ) {
2690				if ( this.type === 'accordion' ) {
2691					this._toggleSubmenu( $( event.target ).parents( '.fl-has-submenu' ).last(), false );
2692				}
2693				else {
2694					this._clickOrHover( true );
2695				}
2696				const mobileToggle = $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' );
2697				if ( this._isMenuToggle() && mobileToggle.hasClass( 'fl-active' ) && ! $( event.relatedTarget ).is( mobileToggle ) && 'expanded' !== this.mobileToggle ) {
2698					mobileToggle.trigger( 'click' );
2699				}
2700			}
2701		}, this ) );
2702
2703	};
2704
2705	FLBuilderMenu.prototype = {
2706		nodeClass		: '',
2707		wrapperClass: '',
2708		type				: '',
2709		breakPoints	: {},
2710		$submenus		: null,
2711
2712		/**
2713		 * Check if the screen size fits a mobile viewport.
2714		 *
2715		 * @since  1.6.1
2716		 * @return bool
2717		 */
2718		_isMobile: function(){
2719			return this.currentBrowserWidth <= this.breakPoints.small ? true : false;
2720		},
2721
2722		/**
2723		 * Check if the device is connected to a mouse.
2724		 * 
2725		 * @since  2.9.0
2726		 * @return bool
2727		 */
2728		_isMouseAvailable: function(){
2729			return window.matchMedia("(pointer: fine) and (hover: hover)").matches;
2730		},
2731
2732		/**
2733		 * Check if the screen size fits a medium viewport.
2734		 *
2735		 * @since  1.10.5
2736		 * @return bool
2737		 */
2738		_isMedium: function(){
2739			return this.currentBrowserWidth <= this.breakPoints.medium ? true : false;
2740		},
2741
2742		/**
2743		 * Check if the screen size fits a large viewport.
2744		 *
2745		 * @since  1.10.5
2746		 * @return bool
2747		 */
2748		_isLarge: function(){
2749			return this.currentBrowserWidth <= this.breakPoints.large ? true : false;
2750		},
2751
2752		/**
2753		 * Check if the menu should toggle for the current viewport base on the selected breakpoint.
2754		 *
2755		 * @see 	 this._isMobile()
2756		 * @see 	 this._isMedium()
2757		 * @since  1.10.5
2758		 * @return bool
2759		 */
2760		_isMenuToggle: function(){
2761			if ( ( 'always' == this.mobileBreakpoint
2762				|| ( this._isMobile() && 'mobile' == this.mobileBreakpoint )
2763				|| ( this._isMedium() && 'medium-mobile' == this.mobileBreakpoint )
2764				|| ( this._isLarge() && 'large-mobile' == this.mobileBreakpoint )
2765			) && ( $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).is(':visible') || 'expanded' == this.mobileToggle ) ) {
2766				return true;
2767			}
2768
2769			return false;
2770		},
2771
2772		/**
2773		 * Initialize the toggle logic for the menu.
2774		 *
2775		 * @see    this._isMenuToggle()
2776		 * @see    this._menuOnCLick()
2777		 * @see    this._clickOrHover()
2778		 * @see    this._submenuOnRight()
2779		 * @see    this._submenuRowZindexFix()
2780		 * @see    this._toggleForMobile()
2781		 * @since  1.6.1
2782		 * @return void
2783		 */
2784		_initMenu: function( resized = false ){
2785			this._setupSubmenu();
2786			if ( ! resized ) {
2787				this._menuOnFocus();
2788				this._menuOnClick();
2789				this._menuOnEscape();
2790			}
2791			if ( $( this.nodeClass ).length && this.type == 'horizontal' ) {
2792				this._initMegaMenus();
2793			}
2794
2795			if( this._isMenuToggle() || this.type == 'accordion' ){
2796
2797				$( this.wrapperClass ).off( 'mouseenter mouseleave' );
2798				this._clickOrHover();
2799
2800			} else {
2801				this._submenuOnRight();
2802				this._submenuRowZindexFix();
2803			}
2804
2805			if( this.mobileToggle != 'expanded' ){
2806				this._toggleForMobile();
2807			}
2808
2809			if( $( this.wrapperClass ).find( '.fl-menu-search-item' ).length ){
2810				this._toggleMenuSearch();
2811			}
2812
2813			if( $( this.wrapperClass ).find( '.fl-menu-cart-item').length ){
2814				this._wooUpdateParams();
2815			}
2816		},
2817
2818		/**
2819		 * Whether the toggle behavior for submenus is through hovering or not.
2820		 *
2821		 * @since  2.5
2822		 * @return void
2823		 */
2824		_setupSubmenu: function() {
2825			if ( ! this._isMouseAvailable() || this._isMenuToggle() || this.type === 'accordion' ) {
2826				$( this.wrapperClass ).addClass( 'no-hover' );
2827			}
2828			else {
2829				$( this.wrapperClass ).removeClass( 'no-hover' );
2830			}
2831		},
2832
2833		/**
2834		 * Logic for menu items when focused.
2835		 *
2836		 * @since  1.9.0
2837		 * @return void
2838		 */
2839		_menuOnFocus: function(){
2840			$( this.wrapperClass ).on( 'focus', 'a:not(.fl-button), .fl-menu-toggle', $.proxy( function( event ) {
2841				const focusedMenuItem = $( event.currentTarget ).closest( '.menu-item' );
2842				const blurredMenuItem = $( event.relatedTarget ).closest( '.menu-item' );
2843				// In case the blurred & focused items are siblings
2844				if ( focusedMenuItem.closest( 'ul' ).is( blurredMenuItem.closest( 'ul' ) ) )	{
2845					// Check if the focus event is not between the link & submenu icon of the same menu item
2846					if ( ! focusedMenuItem.is( blurredMenuItem ) ) {
2847						this._toggleSubmenu( blurredMenuItem, false );
2848					}
2849				}
2850				// In case neither items are child & parent nor vice versa
2851				else if ( focusedMenuItem.has( blurredMenuItem ).length === blurredMenuItem.has( focusedMenuItem ).length ) {
2852					// Get the blurred item parent & is the sibling of the focused item
2853					blurredMenuItem.parents( '.fl-has-submenu' ).each( ( _, parent ) => {
2854						if ( focusedMenuItem.closest( 'ul' ).is( $( parent ).closest( 'ul' ) ) ) {
2855							this._toggleSubmenu( $( parent ), false );
2856							return false;
2857						}
2858					} );
2859				}
2860				// In case the blurred item is a child of the focused item
2861				else if ( focusedMenuItem.has( blurredMenuItem ).length ) {
2862					if ( this.type !== 'accordion' && this.submenuIcon === 'none' ) {
2863						this._toggleSubmenu( blurredMenuItem, false );
2864					}
2865				}
2866			}, this ) );
2867		},
2868
2869		/**
2870		 * Logic for menu items when Escape key is pressed.
2871		 *
2872		 * @since  2.7.1
2873		 * @return void
2874		 */
2875		_menuOnEscape: function(){
2876			$( this.wrapperClass ).on( 'keydown', $.proxy( function( event ){
2877				if ( event.key !== 'Escape' ) return;
2878				const menuItem = $( event.target ).closest( '.menu-item' );
2879				const mobileToggle = $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' );
2880				// In case there is a focused menu item
2881				if ( menuItem.length || $( event.target ).hasClass( 'fl-menu-mobile-close' ) ) {
2882					// Close the search form if it is open
2883					if ( menuItem.hasClass( 'fl-menu-search-item' ) && $( this.wrapperClass ).find('.fl-search-form-input-wrap').is( ':visible' ) ) {
2884						$( this.wrapperClass ).find('.fl-menu-search-item .fl-button:is(a, button:not([type="submit"]))').trigger( 'focus' );
2885					}
2886					// Close all the submenus of the focused menu item
2887					else if ( menuItem.hasClass( 'fl-has-submenu' ) && menuItem.find( '.sub-menu' ).first().is( ':visible' ) ) {
2888						this._toggleSubmenu( menuItem, false );
2889					}
2890					else {
2891						// Shift focus to the parent while closing all its submenus
2892						const parentMenuItem = menuItem.parents( '.fl-has-submenu' ).not( '.mega-menu.hide-heading, .mega-menu-disabled.hide-heading' ).first();
2893						// Close the mobile menu if there is no parent menu item and the mobile toggle is active
2894						if ( parentMenuItem.length === 0 && this._isMenuToggle() && mobileToggle.hasClass( 'fl-active' ) ) {
2895							// Blur to trigger the focus-out event for closing the menu
2896							mobileToggle.trigger( 'blur' ).trigger( 'focus' );
2897						}
2898						// Close the parent submenu and shift focus to its link
2899						else if ( parentMenuItem.length !== 0 ) {
2900							this._toggleSubmenu( parentMenuItem, false );
2901							parentMenuItem.find( 'a' ).first().trigger( 'focus' );
2902						}
2903					}
2904				}
2905				// Close the mobile menu if the mobile toggle is active
2906				else if ( $( event.target ).hasClass( 'fl-menu-mobile-toggle' ) && mobileToggle.hasClass( 'fl-active' ) ) {
2907					// Blur to trigger the focus-out event for closing the menu
2908					mobileToggle.trigger( 'blur' ).trigger( 'focus' );
2909				}
2910			}, this ) );
2911		},
2912
2913		/**
2914		 * Logic for menu items when clicked.
2915		 *
2916		 * @since  1.6.1
2917		 * @return void
2918		 */
2919		_menuOnClick: function(){
2920			// Fallback for span elements and fake links to interact with the keyboard
2921			$( this.wrapperClass ).on( 'keydown', 'a:not(.fl-button, [href]), span.fl-menu-toggle', $.proxy( function( event ) {
2922				if ( event.key === 'Enter' || event.key === ' ' ) {
2923					event.preventDefault();
2924					$( event.currentTarget ).trigger( 'click' );
2925				}
2926			}, this ) );
2927			$( this.wrapperClass ).on( 'click', 'a, .fl-menu-toggle', $.proxy( function( event ) {
2928				// Only allow mouse clicks with accordion & mobile menus
2929				if ( this._isMouseAvailable() && ! this._isMenuToggle() && event.detail && this.type !== 'accordion' ) return;
2930				// Links only open & do not toggle submenus if there is either a submenu icon or an accordion layout
2931				if ( $( event.currentTarget ).is( 'a' ) && ( this.submenuIcon !== 'none' || this.type === 'accordion' ) ) return;
2932				const menuItem = $( event.currentTarget ).closest( '.menu-item, .fl-menu-logo' );
2933				const menuLink = menuItem.find( 'a' ).first().attr( 'href' );
2934				const submenuHidden = menuItem.find( '.sub-menu' ).first().is( ':hidden' );
2935				if ( typeof menuLink === 'undefined' || menuLink === '#' || submenuHidden ) {
2936					event.preventDefault();
2937				}
2938				if ( $( event.currentTarget ).hasClass( 'fl-menu-toggle' ) || submenuHidden ) {
2939					this._toggleSubmenu( menuItem, submenuHidden );
2940				}
2941			}, this ) );
2942		},
2943
2944		/**
2945		 * Controls toggling the visibility of all submenu items for desktop & mobile.
2946		 *
2947		 * @since  2.10
2948		 * @return void
2949		 */
2950		_toggleSubmenu: function ( menuItem, opened ) {
2951			const togglingClass = this._isMenuToggle() || this.type === 'accordion' ? 'fl-active' : 'focus';
2952			const toggleElement = this.submenuIcon === 'none' ? 'a' : '.fl-menu-toggle';
2953			const hiddenMenu = '.mega-menu.hide-heading, .mega-menu-disabled.hide-heading';
2954			if ( opened && menuItem.hasClass( 'fl-has-submenu' ) && ! menuItem.is( hiddenMenu ) ) {
2955				menuItem.addClass( togglingClass );
2956				menuItem.find( toggleElement ).first().attr( 'aria-expanded', true );
2957				if ( this._isMenuToggle() || this.type === 'accordion' ) {
2958					menuItem.find( '.sub-menu' ).first().filter( ':hidden' ).slideDown();
2959				}
2960			}
2961			else {
2962				menuItem.parent().find( '.menu-item' ).removeClass( togglingClass );
2963				menuItem.parent().find( '.fl-has-submenu' ).not( hiddenMenu ).find( toggleElement ).attr( 'aria-expanded', false );
2964				if ( this._isMenuToggle() || this.type === 'accordion' ) {
2965					menuItem.find( '.sub-menu' ).filter( ':visible' ).slideUp();
2966				}
2967			}
2968		},
2969
2970		/**
2971		 * Changes general styling and behavior of menus based on mobile / desktop viewport.
2972		 *
2973		 * @see    this._isMenuToggle()
2974		 * @since  1.6.1
2975		 * @return void
2976		 */
2977		_clickOrHover: function( clear = false ){
2978			const selector = this._isMobileBelowRowEnabled() ? this.nodeClass + '-clone' : this.nodeClass;
2979			this.$submenus = this.$submenus || $( selector ).find( '.sub-menu' );
2980
2981			const className = this._isMenuToggle() || this.type === 'accordion' ? 'fl-active' : 'focus';
2982			const toggleElement = this.submenuIcon === 'none' ? 'a' : '.fl-menu-toggle';
2983			const hiddenMenu = '.mega-menu.hide-heading, .mega-menu-disabled.hide-heading';
2984			$( selector ).find( '.fl-has-submenu' ).not( hiddenMenu ).each( function() {
2985				if( clear || ! $ ( this ).hasClass( className ) ){
2986					if ( clear ) $( this ).removeClass( className );
2987					$( this ).find( toggleElement ).first().attr( 'aria-expanded', false );
2988					if ( className === 'fl-active' ) {
2989						$( this ).find( '.sub-menu' ).fadeOut();
2990					} else if ( className === 'focus' ) {
2991						$( this ).find( '.sub-menu' ).css( {
2992							'display' : '',
2993							'opacity' : ''
2994						} );
2995					}
2996				}
2997			} );
2998		},
2999
3000		/**
3001		 * Logic to prevent submenus to go outside viewport boundaries.
3002		 *
3003		 * @since  1.6.1
3004		 * @return void
3005		 */
3006		_submenuOnRight: function(){
3007
3008			$( this.wrapperClass )
3009				.on( 'mouseenter focus', '.fl-has-submenu', $.proxy( function( e ){
3010
3011					if( $ ( e.currentTarget ).find('.sub-menu').length === 0 ) {
3012						return;
3013					}
3014
3015					var $link           = $( e.currentTarget ),
3016						$parent         = $link.parent(),
3017						$subMenu        = $link.find( '.sub-menu' ),
3018						subMenuWidth    = $subMenu.width(),
3019						subMenuPos      = 0,
3020						bodyWidth       = $( 'body' ).width();
3021
3022					if( $link.closest( '.fl-menu-submenu-right' ).length !== 0) {
3023
3024						$link.addClass( 'fl-menu-submenu-right' );
3025
3026					} else if( $( 'body' ).hasClass( 'rtl' ) ) {
3027
3028						subMenuPos = $parent.is( '.sub-menu' ) ?
3029									 $parent.offset().left - subMenuWidth:
3030									 $link.offset().left - $link.width() - subMenuWidth;
3031
3032						if( subMenuPos <= 0 ) {
3033							$link.addClass( 'fl-menu-submenu-right' );
3034						}
3035
3036					} else {
3037
3038						subMenuPos = $parent.is( '.sub-menu' ) ?
3039									 $parent.offset().left + $parent.width() + subMenuWidth :
3040									 $link.offset().left + $link.width() + subMenuWidth;
3041
3042						if( subMenuPos > bodyWidth ) {
3043							$link.addClass('fl-menu-submenu-right');
3044						}
3045					}
3046				}, this ) )
3047				.on( 'mouseleave', '.fl-has-submenu', $.proxy( function( e ){
3048					$( e.currentTarget ).removeClass( 'fl-menu-submenu-right' );
3049				}, this ) );
3050
3051		},
3052
3053		/**
3054		 * Logic to prevent submenus to go behind the next overlay row.
3055		 *
3056		 * @since  1.10.9
3057		 * @return void
3058		 */
3059		_submenuRowZindexFix: function(){
3060
3061			$( this.wrapperClass )
3062				.on( 'mouseenter', 'ul.menu > .fl-has-submenu', $.proxy( function( e ){
3063
3064					if( $ ( e.currentTarget ).find('.sub-menu').length === 0 ) {
3065						return;
3066					}
3067
3068					$( this.nodeClass )
3069						.closest( '.fl-row' )
3070						.find( '.fl-row-content' )
3071						.css( 'z-index', '10' );
3072
3073				}, this ) )
3074				.on( 'mouseleave', 'ul.menu > .fl-has-submenu', $.proxy( function(){
3075
3076					$( this.nodeClass )
3077						.closest( '.fl-row' )
3078						.find( '.fl-row-content' )
3079						.css( 'z-index', '' );
3080
3081				}, this ) );
3082		},
3083
3084		/**
3085		 * Logic for the mobile menu button.
3086		 *
3087		 * @since  1.6.1
3088		 * @return void
3089		 */
3090		_toggleForMobile: function(){
3091
3092			var $wrapper = null,
3093				$menu    = null,
3094				self     = this;
3095
3096			$( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).attr('aria-controls', $( this.wrapperClass ).find( 'ul.menu' ).attr('id'));
3097
3098			if( this._isMenuToggle() ){
3099
3100				if ( this._isMobileBelowRowEnabled() ) {
3101					this._placeMobileMenuBelowRow();
3102					$wrapper = $( this.wrapperClass );
3103					$menu    = $( this.nodeClass + '-clone' );
3104					$menu.find( 'ul.menu' ).show();
3105				}
3106				else {
3107					$wrapper = $( this.wrapperClass );
3108					$menu    = $wrapper.find( '.menu' );
3109				}
3110
3111				if( !$wrapper.find( '.fl-menu-mobile-toggle' ).hasClass( 'fl-active' ) && ! self.mobileFlyout ){
3112					$menu.css({ display: 'none' });
3113				}
3114
3115				// Flayout Menu
3116				if ( self.mobileFlyout ) {
3117					this._initFlyoutMenu();
3118				}
3119
3120				$wrapper.on( 'click', '.fl-menu-mobile-toggle', function( e ){
3121					e.stopImmediatePropagation();
3122
3123					$( this ).toggleClass( 'fl-active' );
3124
3125					if ( self.mobileFlyout ) {
3126						self._toggleFlyoutMenu();
3127						const flyoutWrapper = $( '.fl-menu-mobile-flyout' );
3128						if ( $( this ).hasClass( 'fl-active' ) ) {
3129							flyoutWrapper.attr( 'aria-hidden', false );
3130							flyoutWrapper.find( 'a[href], button, input, select, textarea, span.fl-menu-toggle, [tabindex="-1"]' ).attr( 'tabindex', 0 );
3131						}
3132						else {
3133							flyoutWrapper.attr( 'aria-hidden', true );
3134							flyoutWrapper.find( 'a[href], button, input, select, textarea, span.fl-menu-toggle, [tabindex]:not
3134([tabindex="-1"])' ).attr( 'tabindex', -1 );
3135						}
3136					}
3137					else {
3138						var targetMenu = null;
3139
3140						if ( self.mobileBelowRow ) {
3141							var $closestCol = $( this ).parents( '.fl-col, .fl-module-box' ),
3142								$closestColGroup = $closestCol.length ? $closestCol.parent( '.fl-col-group' ) : null;
3143								targetMenu  = $closestCol.length ? $closestCol.last().next( '.fl-menu-mobile-clone' ) : null;
3144
3145							if ( $closestColGroup.length ) {
3146								if ( $closestColGroup.hasClass( 'fl-col-group-responsive-reversed' ) ) {
3147									$closestColGroup.find( '.fl-menu-mobile-clone' ).css( 'order', -1 );
3148								} else if ( $closestColGroup ) {
3149									$closestColGroup.find( '.fl-menu-mobile-clone' ).css( 'order', 2 );
3150								}
3151							}
3152						} else {
3153							targetMenu = $( this ).closest( '.fl-menu' ).find( 'ul.menu' );
3154						}
3155						
3156						if ( targetMenu.length ) {
3157							$menu = $( targetMenu );
3158						}
3159
3160						$menu.slideToggle();
3161					}
3162
3163					e.stopPropagation();
3164				} );
3165
3166				// Hide active menu when click on anchor link ID that exists on a page
3167				$menu.off().on( 'click', '.menu-item > a[href*="#"]:not([href="#"])', function(){
3168					var $href = $(this).attr('href'),
3169						$targetID = $href.split('#')[1],
3170						element = $('#' + $targetID);
3171					if ( $('body').find(element).length > 0 ) {
3172						$( this ).toggleClass( 'fl-active' );
3173						FLBuilderLayout._scrollToElement( element );
3174						if ( ! self._isMenuToggle() ) {
3175							$menu.slideToggle();
3176						}
3177					}
3178				});
3179			}
3180			else {
3181
3182				if ( this._isMobileBelowRowEnabled() ) {
3183					this._removeMenuFromBelowRow();
3184				}
3185
3186				$wrapper = $( this.wrapperClass ),
3187				$menu    = $wrapper.find( 'ul.menu' );
3188				$wrapper.find( '.fl-menu-mobile-toggle' ).removeClass( 'fl-active' );
3189				$menu.css({ display: '' });
3190
3191				if ( ! this._isMobileBelowRowEnabled() ) {
3192					$menu.off( 'click', '.menu-item > a[href*="#"]:not([href="#"])' );
3193				}
3194
3195				if ( this.mobileFlyout && $wrapper.find( '.fl-menu-mobile-flyout' ).length > 0 ) {
3196					$( 'body' ).css( 'margin', '' );
3197					$( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', '' );
3198					$menu.unwrap();
3199					$wrapper.find( '.fl-menu-mobile-close' ).remove();
3200					$wrapper.find( '.fl-menu-mobile-opacity' ).remove();
3201				}
3202			}
3203		},
3204
3205		/**
3206		 * Init any mega menus that exist.
3207		 *
3208		 * @see 	 this._isMenuToggle()
3209		 * @since  1.10.4
3210		 * @return void
3211		 */
3212		_initMegaMenus: function(){
3213
3214			var module     = $( this.nodeClass ),
3215				rowContent = module.closest( '.fl-row-content' ),
3216				rowWidth   = rowContent.width(),
3217				megas      = module.find( '.mega-menu' ),
3218				disabled   = module.find( '.mega-menu-disabled' ),
3219				isToggle   = this._isMenuToggle();
3220
3221			if ( isToggle ) {
3222				megas.removeClass( 'mega-menu' ).addClass( 'mega-menu-disabled' );
3223				module.find( 'li.mega-menu-disabled > ul.sub-menu' ).css( 'width', '' );
3224				rowContent.css( 'position', '' );
3225			} else {
3226				disabled.removeClass( 'mega-menu-disabled' ).addClass( 'mega-menu' );
3227				module.find( 'li.mega-menu > ul.sub-menu' ).css( 'width', rowWidth + 'px' );
3228				rowContent.css( 'position', 'relative' );
3229			}
3230		},
3231
3232		/**
3233		 * Check to see if Below Row should be enabled.
3234		 *
3235		 * @since  1.11
3236		 * @return boolean
3237		 */
3238		_isMobileBelowRowEnabled: function() {
3239			return this.mobileBelowRow && ( $( this.nodeClass ).parents( '.fl-col, .fl-module-box' ).length );
3240		},
3241
3242		/**
3243		 * Logic for putting the mobile menu below the menu's
3244		 * column so it spans the full width of the page.
3245		 *
3246		 * @since  1.10
3247		 * @return void
3248		 */
3249		_placeMobileMenuBelowRow: function(){
3250
3251			if ( $( this.nodeClass + '-clone' ).length ) {
3252				return;
3253			}
3254
3255			var module = $( this.nodeClass ),
3256				clone  = null,
3257				col    = module.parents( '.fl-col, .fl-module-box' ).last();
3258
3259			if ( module.length < 1 ) {
3260				return;
3261			}
3262
3263			clone = ( module.length > 1 ) ? $( module[0] ).clone() : module.clone();
3264			module.find( 'ul.menu' ).remove();
3265			clone.addClass( ( this.nodeClass + '-clone' ).replace( '.', '' ) );
3266			clone.addClass( 'fl-menu-mobile-clone' );
3267			clone.find( '.fl-menu-mobile-toggle' ).remove();
3268			col.after( clone );
3269
3270			// Removes animation when enabled
3271			if ( module.hasClass( 'fl-animation' ) ) {
3272				clone.removeClass( 'fl-animation' );
3273			}
3274
3275			this._menuOnFocus();
3276			this._menuOnClick();
3277			this._menuOnEscape();
3278		},
3279
3280		/**
3281		 * Logic for removing the mobile menu from below the menu's
3282		 * column and putting it back in the main wrapper.
3283		 *
3284		 * @since  1.10
3285		 * @return void
3286		 */
3287		_removeMenuFromBelowRow: function(){
3288
3289			if ( ! $( this.nodeClass + '-clone' ).length ) {
3290				return;
3291			}
3292
3293			var module = $( this.nodeClass ),
3294				clone  = $( this.nodeClass + '-clone' ),
3295				menu   = clone.find( 'ul.menu' ),
3296				nav    = module.find( 'nav' );
3297
3298			if ( nav.length ) {
3299				nav.append( menu );
3300			} else {
3301				module.find( '.fl-menu-mobile-toggle' ).after( menu );
3302			}
3303			clone.remove();
3304			menu.find( 'a' ).each( FLBuilderLayout._initAnchorLink );
3305		},
3306
3307		/**
3308		 * Logic for Flyout responsive menu.
3309		 *
3310		 * @since  2.2
3311		 * @return void
3312		 */
3313		_initFlyoutMenu: function(){
3314			var wrapper = $( this.wrapperClass ),
3315				menu  	= wrapper.find( 'ul.menu' ),
3316				button	= wrapper.find( '.fl-menu-mobile-toggle' );
3317
3318			if ( 0 === wrapper.find( '.fl-menu-mobile-flyout' ).length ) {
3319				menu.wrap( '<div class="fl-menu-mobile-flyout" aria-hidden="true"></div>' );
3320			}
3321
3322			if ( 0 === wrapper.find( '.fl-menu-mobile-close' ).length ) {
3323				var close = window.fl_responsive_close || 'Close'
3324				wrapper.find( '.fl-menu-mobile-flyout' ).prepend( '<button class="fl-menu-mobile-close fl-content-ui-button" aria-label="' + close + '"><i class="fas fa-times"></i></button>' );
3325			}
3326
3327			// Push with opacity
3328			if ( wrapper.hasClass( 'fl-menu-responsive-flyout-push-opacity' ) && 0 === wrapper.find( '.fl-menu-mobile-opacity' ).length ) {
3329				wrapper.append( '<div class="fl-menu-mobile-opacity"></div>' );
3330			}
3331
3332			wrapper.off( 'click', '.fl-menu-mobile-opacity, .fl-menu-mobile-close' ).on( 'click', '.fl-menu-mobile-opacity, .fl-menu-mobile-close', function(e){
3333				button.trigger('focus').trigger( 'click' );
3334				e.stopPropagation();
3335			});
3336
3337			if ( 'undefined' !== typeof FLBuilder ) {
3338				FLBuilder.addHook('restartEditingSession', function(){
3339					$( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', '' );
3340
3341					// Toggle active menu
3342					if ( button.hasClass( 'fl-active' ) ) {
3343						button.trigger( 'click' );
3344					}
3345				});
3346			}
3347			$( '.fl-menu-mobile-flyout' ).find( 'a[href], button, input, select, textarea, span.fl-menu-toggle, [tabindex]:not([tabindex="-1"])' ).attr( 'tabindex', -1 );
3348		},
3349
3350		/**
3351		 * Logic to enable/disable the Flyout menu on button click.
3352		 *
3353		 * @since  2.2
3354		 * @return void
3355		 */
3356		_toggleFlyoutMenu: function(){
3357			var wrapper		= $( this.wrapperClass ),
3358				button		= wrapper.find( '.fl-menu-mobile-toggle' ),
3359				position 	= wrapper.hasClass( 'fl-flyout-right' ) ? 'right' : 'left',
3360				pushMenu 	= wrapper.hasClass( 'fl-menu-responsive-flyout-push' ) || wrapper.hasClass( 'fl-menu-responsive-flyout-push-opacity' ),
3361				opacity		= wrapper.find( '.fl-menu-mobile-opacity' ),
3362				marginPos	= {},
3363				fixedPos 	= {},
3364				fixedHeader	= $('header, header > div');
3365
3366			this._resizeFlyoutMenuPanel();
3367
3368			// Fix the push menu when builder ui panel is pinned
3369			if ( $( '.fl-builder-ui-pinned-content-transform' ).length > 0 && ! $( 'body' ).hasClass( 'fl-builder-edit' ) ) {
3370				$( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', 'none' );
3371			}
3372
3373			if ( pushMenu ) {
3374				marginPos[ 'margin-' + position ] = button.hasClass( 'fl-active' ) ? this.flyoutWidth + 'px' : '0px';
3375				$( 'body' ).animate( marginPos, 200);
3376
3377				// Fixed header
3378				if ( fixedHeader.length > 0 ) {
3379					fixedPos[ position] = button.hasClass( 'fl-active' ) ? this.flyoutWidth + 'px' : '0px';
3380					fixedHeader.each(function(){
3381						if ( 'fixed' == $( this ).css( 'position' ) ) {
3382							$( this ).css({ 'transition' : 'none' });
3383							$( this ).animate( fixedPos, 200 );
3384						}
3385					});
3386				}
3387			}
3388
3389			if ( opacity.length > 0 && button.hasClass( 'fl-active' ) ) {
3390				opacity.show();
3391			}
3392			else {
3393				opacity.hide();
3394			}
3395		},
3396
3397		/**
3398		 * Resize or reposition the Flyout Menu Panel.
3399		 * 
3400		 * @since  2.8.1
3401		 * @return void
3402		 */
3403		_resizeFlyoutMenuPanel: function(){
3404			const wrapper    = $( this.wrapperClass );
3405			const wrapFlyout = wrapper.find( '.fl-menu-mobile-flyout' );
3406				
3407			if ( wrapFlyout.length > 0 ) {
3408				wrapFlyout.css( this._getFlyoutMenuPanelPosition() );
3409			}
3410		},
3411
3412		/**
3413		 * Compute the Flyout Menu Panel's position on the screen.
3414		 * 
3415		 * @since  2.8.1
3416		 * @return object
3417		 */
3418		_getFlyoutMenuPanelPosition: function() {
3419			var wrapper        = $( this.wrapperClass ),
3420				button         = wrapper.find( '.fl-menu-mobile-toggle' ),
3421				side           = wrapper.hasClass( 'fl-flyout-right' ) ? 'right' : 'left',
3422				winHeight      = $(window).outerHeight(),
3423				winTop         = $(window).scrollTop(),
3424				adminBarHeight = $( '#wpadminbar' ).length ? $( '#wpadminbar' ).height() : 0,
3425				flyoutPosition = {};
3426
3427			flyoutPosition[ side ]  = '-' + ( parseInt( this.flyoutWidth ) + 15 ) + 'px';
3428			if ( ! button.hasClass( 'fl-active' ) ) {
3429				return flyoutPosition;
3430			}
3431
3432			flyoutPosition[ side ]  = '0px';
3433			flyoutPosition[ 'height' ]  = winHeight + 'px';
3434			flyoutPosition[ 'top' ] = '0px';
3435			
3436			if ( adminBarHeight > 0 ) {
3437				const diff = adminBarHeight - winTop;
3438				flyoutPosition[ 'top' ] = diff <= 0 ? '0px' : (diff) + 'px';
3439			}
3440
3441			return flyoutPosition;
3442		},
3443
3444		/**
3445		 * Shows or hides the nav search form.
3446		 *
3447		 * @since  2.5
3448		 * @method _toggleMenuSearch
3449		 */
3450		_toggleMenuSearch: function(){
3451			const form   = $( this.wrapperClass ).find('.fl-menu-search-item .fl-search-form-input-wrap'); 
3452			const button = $( this.wrapperClass ).find('.fl-menu-search-item .fl-button:is(a, button:not([type="submit"]))');
3453			form.on('submit', () => form.stop().fadeToggle('fast'));
3454			// Close the search form when focus is lost
3455			form.on('focusout', (event) => {
3456				if (form.is(':visible') && form.has($(event.relatedTarget)).length === 0) {
3457					button.trigger('click');
3458				}
3459			});
3460			button.attr('aria-expanded', false);
3461			// Close other open submenus when focusing on the search button
3462			button.on('focus', (event) => {
3463				const parentMenus = $(event.relatedTarget).parents('.menu-item.fl-has-submenu');
3464				if (event.relatedTarget && parentMenus.length) {
3465					this._toggleSubmenu(parentMenus, false);
3466				}
3467			});
3468			button.on('click', (event) => {
3469				// Prevent toggling when clicking with mouse while the form is already open
3470				if (event.detail && event.type === 'click' && form.is(':visible')) return;
3471				form.stop().fadeToggle('fast', () => {
3472					button.attr('aria-expanded', form.is(':visible'));
3473					if(form.is(':visible')) {
3474						form.find('.fl-search-text').focus();
3475					}
3476				});
3477			});
3478		},
3479
3480		/**
3481		 * Adds menu node and post ID to WooCommerce ajax URL requests.
3482		 *
3483		 * @since  2.5
3484		 * @return void
3485		 */
3486		_wooUpdateParams: function() {
3487			if ( 'undefined' !== typeof wc_cart_fragments_params ) {
3488				wc_cart_fragments_params.wc_ajax_url += '&fl-menu-node='+ this.nodeId +'&post-id='+ this.postId;
3489			}
3490			if ( 'undefined' !== typeof wc_add_to_cart_params ) {
3491				wc_add_to_cart_params.wc_ajax_url += '&fl-menu-node='+ this.nodeId +'&post-id='+ this.postId;
3492			}
3493		},
3494	};
3495
3496})(jQuery);
3497
3498(function($) {
3499
3500	$(function() {
3501
3502		new FLBuilderMenu({
3503			id: '6166f42df0bd2',
3504			type: 'vertical',
3505			mobile: 'expanded',
3506			mobileBelowRow: false,
3507			mobileFlyout: false,
3508			breakPoints: {
3509				large: 1200,
3510				medium: 992,
3511				small: 768			},
3512			mobileBreakpoint: 'mobile',
3513			postId : '27335',
3514			mobileStacked: true,
3515			submenuIcon: 'none',
3516			flyoutWidth: '250',
3517		});
3518
3519	});
3520
3521})(jQuery);
3522
3523(function($) {
3524
3525	$(function() {
3526
3527		new FLBuilderMenu({
3528			id: '6166f49fcad45',
3529			type: 'vertical',
3530			mobile: 'expanded',
3531			mobileBelowRow: false,
3532			mobileFlyout: false,
3533			breakPoints: {
3534				large: 1200,
3535				medium: 992,
3536				small: 768			},
3537			mobileBreakpoint: 'mobile',
3538			postId : '27335',
3539			mobileStacked: true,
3540			submenuIcon: 'none',
3541			flyoutWidth: '250',
3542		});
3543
3544	});
3545
3546})(jQuery);
3547
3548(function($) {
3549
3550	$(function() {
3551
3552		new FLBuilderMenu({
3553			id: '6166f4b81fcaf',
3554			type: 'vertical',
3555			mobile: 'expanded',
3556			mobileBelowRow: false,
3557			mobileFlyout: false,
3558			breakPoints: {
3559				large: 1200,
3560				medium: 992,
3561				small: 768			},
3562			mobileBreakpoint: 'mobile',
3563			postId : '27335',
3564			mobileStacked: true,
3565			submenuIcon: 'none',
3566			flyoutWidth: '250',
3567		});
3568
3569	});
3570
3571})(jQuery);
3572
3573(function($) {
3574
3575	$(function() {
3576
3577		new FLBuilderMenu({
3578			id: '6166f60bec55f',
3579			type: 'vertical',
3580			mobile: 'expanded',
3581			mobileBelowRow: false,
3582			mobileFlyout: false,
3583			breakPoints: {
3584				large: 1200,
3585				medium: 992,
3586				small: 768			},
3587			mobileBreakpoint: 'mobile',
3588			postId : '27335',
3589			mobileStacked: true,
3590			submenuIcon: 'none',
3591			flyoutWidth: '250',
3592		});
3593
3594	});
3595
3596})(jQuery);
3597
3598/* Start Layout Custom JS */
3599
3600/* End Layout Custom JS */
3601
3602
3603jQuery(function($) {
3604	
3605		$(function() {
3606		$( '.fl-node-izhljdrm4vo8 .fl-photo-img' )
3607			.on( 'mouseenter', function( e ) {
3608				$( this ).data( 'title', $( this ).attr( 'title' ) ).removeAttr( 'title' );
3609			} )
3610			.on( 'mouseleave', function( e ){
3611				$( this ).attr( 'title', $( this ).data( 'title' ) ).data( 'title', null );
3612			} );
3613	});
3614		window._fl_string_to_slug_regex = 'a-zA-Z0-9';
3615});
3616(function($){
3617	})(jQuery);
3618jQuery(function($) {
3619	
3620		$(function() {
3621		$( '.fl-node-6jio1mt2wnkz .fl-photo-img' )
3622			.on( 'mouseenter', function( e ) {
3623				$( this ).data( 'title', $( this ).attr( 'title' ) ).removeAttr( 'title' );
3624			} )
3625			.on( 'mouseleave', function( e ){
3626				$( this ).attr( 'title', $( this ).data( 'title' ) ).data( 'title', null );
3627			} );
3628	});
3629		window._fl_string_to_slug_regex = 'a-zA-Z0-9';
3630});
3631
3632(function($) {
3633
3634	$(function() {
3635
3636		new FLBuilderMenu({
3637			id: 'u8pveyc47g30',
3638			type: 'horizontal',
3639			mobile: 'expanded',
3640			mobileBelowRow: true,
3641			mobileFlyout: false,
3642			breakPoints: {
3643				large: 1200,
3644				medium: 992,
3645				small: 768			},
3646			mobileBreakpoint: 'mobile',
3647			postId : '230550',
3648			mobileStacked: true,
3649			submenuIcon: 'arrows',
3650			flyoutWidth: '250',
3651		});
3652
3653	});
3654
3655})(jQuery);
3656
3657/* Start Layout Custom JS */
3658
3659/* End Layout Custom JS */
3660
3661(function($){
3662
3663	/**
3664	 * Helper class for header layout logic.
3665	 *
3666	 * @since 1.0
3667	 * @class FLThemeBuilderHeaderLayout
3668	 */
3669	FLThemeBuilderHeaderLayout = {
3670
3671		/**
3672		 * A reference to the window object for this page.
3673		 *
3674		 * @since 1.0
3675		 * @property {Object} win
3676		 */
3677		win : null,
3678
3679		/**
3680		 * A reference to the body object for this page.
3681		 *
3682		 * @since 1.0
3683		 * @property {Object} body
3684		 */
3685		body : null,
3686
3687		/**
3688		 * A reference to the header object for this page.
3689		 *
3690		 * @since 1.0
3691		 * @property {Object} header
3692		 */
3693		header : null,
3694
3695		/**
3696		 * Whether this header overlays the content or not.
3697		 *
3698		 * @since 1.0
3699		 * @property {Boolean} overlay
3700		 */
3701		overlay : false,
3702
3703		/**
3704		 * Whether the page has the WP admin bar or not.
3705		 *
3706		 * @since 1.0
3707		 * @property {Boolean} hasAdminBar
3708		 */
3709		hasAdminBar : false,
3710
3711		/**
3712		 * Breakpoint for when the sticky header should apply.
3713		 *
3714		 * @since 1.4
3715		 * @property {String} stickyOn
3716		 */
3717		stickyOn: '',
3718
3719		/**
3720		 * A reference of the sticky and shrink header breakpoint.
3721		 *
3722		 * @since 1.2.5
3723		 * @property {Number} breakpointWidth
3724		 */
3725		breakpointWidth: 0,
3726
3727		/**
3728		 * Initializes header layout logic.
3729		 *
3730		 * @since 1.0
3731		 * @method init
3732		 */
3733		init: function()
3734		{
3735			var editing          = $( 'html.fl-builder-edit' ).length,
3736				header           = $( '.fl-builder-content[data-type=header]' ),
3737				menuModule       = header.find( '.fl-module-menu' ),
3738				breakpoint       = null;
3739
3740			if ( ! editing && header.length ) {
3741
3742				header.imagesLoaded( $.proxy( function() {
3743
3744					this.win         = $( window );
3745					this.body        = $( 'body' );
3746					this.header      = header.eq( 0 );
3747					this.overlay     = !! Number( header.attr( 'data-overlay' ) );
3748					this.hasAdminBar = !! $( 'body.admin-bar' ).length;
3749					this.stickyOn    = this.header.data( 'sticky-on' );
3750					breakpoint       = this.header.data( 'sticky-breakpoint' );
3751
3752					if ( '' == this.stickyOn ) {
3753						if ( typeof FLBuilderLayoutConfig.breakpoints[ breakpoint ] !== undefined ) {
3754							this.breakpointWidth = FLBuilderLayoutConfig.breakpoints[ breakpoint ];
3755						}
3756						else {
3757							this.breakpointWidth = FLBuilderLayoutConfig.breakpoints.medium;
3758						}
3759					}
3760
3761					if ( Number( header.attr( 'data-sticky' ) ) ) {
3762
3763						this.header.data( 'original-top', this.header.offset().top );
3764						this.win.on( 'resize', $.throttle( 500, $.proxy( this._initSticky, this ) ) );
3765						this._initSticky();
3766
3767					}
3768
3769				}, this ) );
3770			}
3771		},
3772
3773		/**
3774		 * Initializes sticky logic for a header.
3775		 *
3776		 * @since 1.0
3777		 * @access private
3778		 * @method _initSticky
3779		 */
3780		_initSticky: function( e )
3781		{
3782			var header     = $('.fl-builder-content[data-type=header]'),
3783				windowSize = this.win.width(),
3784				makeSticky = false;
3785
3786			makeSticky = this._makeWindowSticky( windowSize );
3787			if ( makeSticky || ( this.breakpointWidth > 0 && windowSize >= this.breakpointWidth ) ) {
3788				this.win.on( 'scroll.fl-theme-builder-header-sticky', $.proxy( this._doSticky, this ) );
3789				//
3790				// Check if Event Type is 'resize' then invoke this._doSticky()
3791				// only if the 'fl-theme-builder-header-sticky' class is already present.
3792				//
3793				if ( e && 'resize' === e.type ) {
3794					if ( this.header.hasClass( 'fl-theme-builder-header-sticky' ) ) {
3795						this._doSticky( e );
3796					}
3797					this._adjustStickyHeaderWidth();
3798				}
3799
3800				if ( Number( header.attr( 'data-shrink' ) ) ) {
3801					this.header.data( 'original-height', this.header.outerHeight() );
3802					this.win.on( 'resize', $.throttle( 500, $.proxy( this._initShrink, this ) ) );
3803					this._initShrink();
3804				}
3805
3806				this._initFlyoutMenuFix( e );
3807			} else {
3808				this.win.off( 'scroll.fl-theme-builder-header-sticky' );
3809				this.win.off( 'resize.fl-theme-builder-header-sticky' );
3810
3811				this.header.removeClass( 'fl-theme-builder-header-sticky' );
3812				this.header.removeAttr( 'style' );
3813				this.header.parent().css( 'padding-top', '0' );
3814			}
3815		},
3816
3817		/**
3818		 * Check if Header should be sticky at a particular Window size.
3819		 *
3820		 * @since 1.4
3821		 * @access private
3822		 * @param  widowSize
3823		 * @method _makeWindowSticky
3824		 */
3825		_makeWindowSticky: function ( windowSize )
3826		{
3827			var makeSticky = false;
3828
3829			switch (this.stickyOn) {
3830				case 'xl':
3831					makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['large'];
3832					break;
3833				case '': // Default
3834				case 'desktop':
3835					makeSticky = windowSize >= FLBuilderLayoutConfig.breakpoints['medium'];
3836					break;
3837				case 'desktop-medium':
3838					makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['small'];
3839					break;
3840				case 'large':
3841					makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['medium'] && windowSize <= FLBuilderLayoutConfig.breakpoints['large'];
3842					break;
3843				case 'large-medium':
3844					makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['small'] && windowSize <= FLBuilderLayoutConfig.breakpoints['large'];
3845					break;
3846				case 'medium':
3847					makeSticky = ( windowSize <= FLBuilderLayoutConfig.breakpoints['medium'] && windowSize > FLBuilderLayoutConfig.breakpoints['small'] );
3848					break;
3849				case 'medium-mobile':
3850					makeSticky = (windowSize <= FLBuilderLayoutConfig.breakpoints['medium']);
3851					break;
3852				case 'mobile':
3853					makeSticky = (windowSize <= FLBuilderLayoutConfig.breakpoints['small']);
3854					break;
3855				case 'all':
3856					makeSticky = true;
3857					break;
3858			}
3859
3860			return makeSticky;
3861		},
3862
3863		/**
3864		 * Sticks the header when the page is scrolled.
3865		 *
3866		 * @since 1.0
3867		 * @access private
3868		 * @method _doSticky
3869		 */
3870		_doSticky: function( e )
3871		{
3872			var winTop    		  = Math.floor( this.win.scrollTop() ),
3873				headerTop 		  = Math.floor( this.header.data( 'original-top' ) ),
3874				hasStickyClass    = this.header.hasClass( 'fl-theme-builder-header-sticky' ),
3875				hasScrolledClass  = this.header.hasClass( 'fl-theme-builder-header-scrolled' ),
3876				beforeHeader      = this.header.prevAll( '.fl-builder-content' ),
3877				bodyTopPadding    = parseInt( jQuery('body').css('padding-top') ),
3878				winBarHeight      = $('#wpadminbar').length ? $('#wpadminbar').outerHeight() : 0,
3879				headerHeight      = 0;
3880
3881			if ( isNaN( bodyTopPadding ) ) {
3882				bodyTopPadding = 0;
3883			}
3884
3885			if ( this.hasAdminBar && this.win.width() > 600 ) {
3886				winTop += Math.floor( winBarHeight );
3887			}
3888
3889			if ( winTop > headerTop ) {
3890				if ( ! hasStickyClass ) {
3891					if ( e && ( 'scroll' === e.type || 'smartscroll' === e.type ) ) {
3892					 	this.header.addClass( 'fl-theme-builder-header-sticky' );
3893						if ( this.overlay && beforeHeader.length ) {
3894							this.header.css( 'top', winBarHeight);
3895						}
3896					}
3897
3898					if ( ! this.overlay ) {
3899						this._adjustHeaderHeight();
3900					}
3901				}
3902			}
3903			else if ( hasStickyClass ) {
3904				this.header.removeClass( 'fl-theme-builder-header-sticky' );
3905				this.header.removeAttr( 'style' );
3906				this.header.parent().css( 'padding-top', '0' );
3907			}
3908
3909			this._adjustStickyHeaderWidth();
3910
3911			if ( winTop > headerTop ) {
3912				if ( ! hasScrolledClass ) {
3913					this.header.addClass( 'fl-theme-builder-header-scrolled' );
3914				}
3915			} else if ( hasScrolledClass ) {
3916				this.header.removeClass( 'fl-theme-builder-header-scrolled' );
3917			}
3918
3919			this._flyoutMenuFix( e );
3920		},
3921
3922		/**
3923		 * Initializes flyout menu fixes on sticky header.
3924		 *
3925		 * @since 1.4.1
3926		 * @method _initFlyoutMenuFix
3927		 */
3928		_initFlyoutMenuFix: function( e ) {
3929			var header       = this.header,
3930				menuModule   = header.closest( '.fl-menu' ),
3931				flyoutMenu   = menuModule.find( '.fl-menu-mobile-flyout' ),
3932				isPushMenu   = menuModule.hasClass( 'fl-menu-responsive-flyout-push' ) || menuModule.hasClass( 'fl-menu-responsive-flyout-push-opacity' ),
3933				isOverlay    = menuModule.hasClass( 'fl-menu-responsive-flyout-overlay' ),
3934				flyoutPos    = menuModule.hasClass( 'fl-flyout-right' ) ? 'right' : 'left',
3935				flyoutParent = header.parent().is( 'header' ) ? header.parent().parent() : header.parent();
3936				isFullWidth  = this.win.width() === header.width(),
3937				flyoutLayout = '',
3938				activePos    = 250,
3939				headerPos    = 0;
3940
3941			if ( ! flyoutMenu.length ) {
3942				return;
3943			}
3944
3945			if ( this.win.width() > header.parent().width() ) {
3946				headerPos = ( this.win.width() - header.width() ) / 2;
3947			}
3948
3949			if ( isOverlay ) {
3950				activePos = headerPos;
3951			}
3952			else if ( isPushMenu ) {
3953				activePos = activePos + headerPos;
3954			}
3955			flyoutMenu.data( 'activePos', activePos );
3956
3957			if ( isPushMenu ) {
3958				flyoutLayout = 'push-' + flyoutPos;
3959			}
3960			else if ( isOverlay ) {
3961				flyoutLayout = 'overlay-' + flyoutPos;
3962			}
3963
3964			if ( isPushMenu && ! $( 'html' ).hasClass( 'fl-theme-builder-has-flyout-menu' ) ) {
3965				$( 'html' ).addClass( 'fl-theme-builder-has-flyout-menu' );
3966			}
3967
3968			if ( ! flyoutParent.hasClass( 'fl-theme-builder-flyout-menu-' + flyoutLayout ) ) {
3969				flyoutParent.addClass( 'fl-theme-builder-flyout-menu-' + flyoutLayout );
3970			}
3971
3972			if ( ! header.hasClass( 'fl-theme-builder-flyout-menu-overlay' ) && isOverlay ) {
3973				header.addClass( 'fl-theme-builder-flyout-menu-overlay' );
3974			}
3975
3976			if ( ! header.hasClass( 'fl-theme-builder-header-full-width' ) && isFullWidth ) {
3977			   header.addClass( 'fl-theme-builder-header-full-width' );
3978		    }
3979			else if ( ! isFullWidth ) {
3980				header.removeClass( 'fl-theme-builder-header-full-width' );
3981			}
3982
3983			menuModule.on( 'click', '.fl-menu-mobile-toggle', $.proxy( function( event ){
3984				if ( menuModule.find( '.fl-menu-mobile-toggle.fl-active' ).length ) {
3985					$( 'html' ).addClass( 'fl-theme-builder-flyout-menu-active' );
3986					event.stopImmediatePropagation();
3987				}
3988				else {
3989					$( 'html' ).removeClass( 'fl-theme-builder-flyout-menu-active' );
3990				}
3991
3992				this._flyoutMenuFix( event );
3993			}, this ) );
3994		},
3995
3996		/**
3997		 * Fix flyout menu inside the sticky header.
3998		 *
3999		 * @since 1.4.1
4000		 * @method _flyoutMenuFix
4001		 */
4002		_flyoutMenuFix: function( e ){
4003			var header      = this.header,
4004			    menuModule  = $( e.target ).closest( '.fl-menu' ),
4005				flyoutMenu  = menuModule.find( '.fl-menu-mobile-flyout' ),
4006				flyoutPos   = menuModule.hasClass( 'fl-flyout-right' ) ? 'right' : 'left',
4007				menuOpacity = menuModule.find( '.fl-menu-mobile-opacity' ),
4008				isScroll    = 'undefined' !== typeof e && 'scroll' === e.handleObj.type,
4009				activePos   = 'undefined' !== typeof flyoutMenu.data( 'activePos' ) ? flyoutMenu.data( 'activePos' ) : 0,
4010				headerPos   = ( this.win.width() - header.width() ) / 2,
4011				inactivePos = headerPos > 0 ? activePos + 4 : 254;
4012
4013			if ( ! flyoutMenu.length ) {
4014				return;
4015			}
4016
4017			if ( this.overlay ) {
4018				return;
4019			}
4020
4021			if( $( '.fl-theme-builder-flyout-menu-active' ).length ) {
4022
4023				if ( isScroll && ! flyoutMenu.hasClass( 'fl-menu-disable-transition' ) ) {
4024					flyoutMenu.addClass( 'fl-menu-disable-transition' );
4025				}
4026
4027				if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) {
4028					if ( ! isScroll ) {
4029						setTimeout( $.proxy( function(){
4030							flyoutMenu.css( flyoutPos, '-' + activePos + 'px' );
4031						}, this ), 1 );
4032					}
4033					else {
4034						flyoutMenu.css( flyoutPos, '-' + activePos + 'px' );
4035					}
4036				}
4037				else {
4038					flyoutMenu.css( flyoutPos, '0px' );
4039				}
4040			}
4041			else {
4042				if ( flyoutMenu.hasClass( 'fl-menu-disable-transition' ) ) {
4043					flyoutMenu.removeClass( 'fl-menu-disable-transition' );
4044				}
4045
4046				if ( header.hasClass( 'fl-theme-builder-flyout-menu-overlay' ) && headerPos > 0 && headerPos < 250 ) {
4047					if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) {
4048						inactivePos = headerPos + 254;
4049					}
4050					else {
4051						inactivePos = 254;
4052					}
4053				}
4054
4055				if ( e && e.type === 'resize' ) {
4056					inactivePos = headerPos + 254;
4057				}
4058
4059				flyoutMenu.css( flyoutPos, '-' + inactivePos + 'px' );
4060			}
4061
4062			if ( e && menuModule.is('.fl-menu-responsive-flyout-overlay') && $.infinitescroll ) {
4063				e.stopImmediatePropagation();
4064			}
4065
4066			if( menuOpacity.length ) {
4067				if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) {
4068					if ( '0px' === menuOpacity.css( 'left' ) ) {
4069						menuOpacity.css( 'left', '-' + headerPos + 'px' );
4070					}
4071				}
4072				else {
4073					menuOpacity.css( 'left', '' );
4074				}
4075			}
4076		},
4077
4078		/**
4079		 * Adjust sticky header width if BB Theme Boxed Layout is used.
4080		 *
4081		 * @since 1.4
4082		 * @access private
4083		 * @method _adjustStickyHeaderWidth
4084		 */
4085		_adjustStickyHeaderWidth: function () {
4086			if ( $('body').hasClass( 'fl-fixed-width' ) ) {
4087				var parentWidth = this.header.parent().width();
4088
4089				// Better if this is set in the stylesheet file.
4090				if ( this.win.width() >= 992 ) {
4091					this.header.css({
4092						'margin': '0 auto',
4093						'max-width': parentWidth,
4094					});
4095				}
4096				else {
4097					this.header.css({
4098						'margin': '',
4099						'max-width': '',
4100					});
4101				}
4102			}
4103		},
4104
4105		/**
4106		 * Adjust Sticky Header Height
4107		 *
4108		 * @since 1.4
4109		 * @access private
4110		 * @method _adjustHeaderHeight
4111		 */
4112		_adjustHeaderHeight: function () {
4113			var beforeHeader = this.header.prevAll('.fl-builder-content'),
4114				beforeHeaderHeight = 0,
4115				beforeHeaderFix = 0,
4116				headerHeight = Math.floor( this.header.outerHeight() ),
4117				bodyTopPadding = parseInt( $( 'body' ).css( 'padding-top' ) ),
4118				wpAdminBarHeight = 0,
4119				totalHeaderHeight = 0;
4120
4121			if ( isNaN( bodyTopPadding ) ) {
4122				bodyTopPadding = 0;
4123			}
4124
4125			if ( beforeHeader.length ) {
4126				$.each( beforeHeader, function() {
4127					beforeHeaderHeight += Math.floor( $(this).outerHeight() );
4128				});
4129				// Subtract this value from the header parent's top padding.
4130				beforeHeaderFix = 2;
4131			}
4132
4133			if ( this.hasAdminBar && this.win.width() <= 600 ) {
4134				wpAdminBarHeight = Math.floor( $('#wpadminbar').outerHeight() );
4135			}
4136
4137			totalHeaderHeight = Math.floor( beforeHeaderHeight + headerHeight);
4138
4139			if ( headerHeight > 0 ) {
4140				var headerParent = this.header.parent(),
4141					headerParentTopPadding = 0;
4142
4143				// If the header's parent container is the BODY tag ignore its top padding.
4144				if ( $( headerParent ).is('body') ) {
4145					headerParentTopPadding = Math.floor( headerHeight - wpAdminBarHeight );
4146				} else {
4147					headerParentTopPadding = Math.floor( headerHeight - bodyTopPadding - wpAdminBarHeight );
4148				}
4149
4150				$( headerParent ).css( 'padding-top',  ( headerParentTopPadding - beforeHeaderFix ) + 'px' );
4151
4152				this.header.css({
4153					'-webkit-transform': 'translate(0px, -' + totalHeaderHeight + 'px)',
4154					'-ms-transform': 'translate(0px, -' + totalHeaderHeight + 'px)',
4155					'transform': 'translate(0px, -' + totalHeaderHeight + 'px)'
4156				});
4157
4158			}
4159
4160		},
4161
4162		/**
4163		 * Initializes shrink logic for a header.
4164		 *
4165		 * @since 1.0
4166		 * @access private
4167		 * @method _initShrink
4168		 */
4169		_initShrink: function( e )
4170		{
4171			if ( this.win.width() >= this.breakpointWidth ) {
4172				this.win.on( 'scroll.fl-theme-builder-header-shrink', $.proxy( this._doShrink, this ) );
4173				this._setImageMaxHeight();
4174
4175				if ( this.win.scrollTop() > 0 ){
4176					this._doShrink();
4177				}
4178
4179			} else {
4180				this.header.parent().css( 'padding-top', '0' );
4181				this.win.off( 'scroll.fl-theme-builder-header-shrink' );
4182				this._removeShrink();
4183				this._removeImageMaxHeight();
4184			}
4185		},
4186
4187		/**
4188		 * Shrinks the header when the page is scrolled.
4189		 *
4190		 * @since 1.0
4191		 * @access private
4192		 * @method _doShrink
4193		 */
4194		_doShrink: function( e )
4195		{
4196			var winTop 			  = this.win.scrollTop(),
4197				headerTop 		  = this.header.data('original-top'),
4198				headerHeight 	  = this.header.data('original-height'),
4199				shrinkImageHeight = this.header.data('shrink-image-height'),
4200				windowSize   	  = this.win.width(),
4201				makeSticky   	  = this._makeWindowSticky( windowSize ),
4202				hasClass     	  = this.header.hasClass( 'fl-theme-builder-header-shrink' );
4203
4204
4205			if ( this.hasAdminBar ) {
4206				winTop += 32;
4207			}
4208
4209			if ( makeSticky && ( winTop > headerTop + headerHeight ) ) {
4210				if ( ! hasClass ) {
4211
4212					this.header.addClass( 'fl-theme-builder-header-shrink' );
4213
4214					// Shrink images but don't include lightbox and menu images.
4215					this.header.find('img').each( function( i ) {
4216						var image           = $( this ),
4217							maxMegaMenu     = image.closest( '.max-mega-menu' ).length,
4218							imageInLightbox = image.closest( '.fl-button-lightbox-content' ).length,
4219							imageInNavMenu  = image.closest( 'li.menu-item' ).length;
4220
4221						if ( ! ( imageInLightbox || imageInNavMenu || maxMegaMenu ) ) {
4222							image.css( 'max-height', shrinkImageHeight );
4223						}
4224
4225					});
4226
4227					this.header.find( '.fl-row-content-wrap' ).each( function() {
4228
4229						var row = $( this );
4230
4231						if ( parseInt( row.css( 'padding-bottom' ) ) > 5 ) {
4232							row.addClass( 'fl-theme-builder-header-shrink-row-bottom' );
4233						}
4234
4235						if ( parseInt( row.css( 'padding-top' ) ) > 5 ) {
4236							row.addClass( 'fl-theme-builder-header-shrink-row-top' );
4237						}
4238					} );
4239
4240					this.header.find( '.fl-module' ).each( function() {
4241
4242						var module = $( this ).find( '.fl-module-content' ).length ? $( this ).find( '.fl-module-content' ) : $( this );
4243
4244						if ( parseInt( module.css( 'margin-bottom' ) ) > 5 ) {
4245							module.addClass( 'fl-theme-builder-header-shrink-module-bottom' );
4246						}
4247
4248						if ( parseInt( module.css( 'margin-top' ) ) > 5 ) {
4249							module.addClass( 'fl-theme-builder-header-shrink-module-top' );
4250						}
4251					} );
4252				}
4253			} else if (hasClass) {
4254				this.header.find( 'img' ).css( 'max-height', '' );
4255				this._removeShrink();
4256			}
4257
4258			// Fixes Shrink header issue with BB Theme when window is scrolled then resized and back.
4259			if ( 'undefined' === typeof( e ) && $('body').hasClass( 'fl-fixed-width' ) ) {
4260				if ( ! this.overlay ) {
4261					this._adjustHeaderHeight();
4262				}
4263			}
4264
4265		},
4266
4267		/**
4268		 * Removes the header shrink effect.
4269		 *
4270		 * @since 1.0
4271		 * @access private
4272		 * @method _removeShrink
4273		 */
4274		_removeShrink: function()
4275		{
4276			var rows    = this.header.find( '.fl-row-content-wrap' ),
4277				modules = this.header.find('.fl-module, .fl-module-content');
4278
4279			rows.removeClass( 'fl-theme-builder-header-shrink-row-bottom' );
4280			rows.removeClass( 'fl-theme-builder-header-shrink-row-top' );
4281			modules.removeClass( 'fl-theme-builder-header-shrink-module-bottom' );
4282			modules.removeClass( 'fl-theme-builder-header-shrink-module-top' );
4283			this.header.removeClass( 'fl-theme-builder-header-shrink' );
4284		},
4285
4286		/**
4287		 * Adds max height to images in modules for smooth scrolling.
4288		 *
4289		 * @since 1.1.1
4290		 * @access private
4291		 * @method _setImageMaxHeight
4292		 */
4293		_setImageMaxHeight: function()
4294		{
4295			var head = $( 'head' ),
4296				stylesId = 'fl-header-styles-' + this.header.data( 'post-id' ),
4297				styles = '',
4298				images = this.header.find( '.fl-module img' );
4299
4300			if ( $( '#' + stylesId ).length ) {
4301				return;
4302			}
4303
4304			images.each( function( i ) {
4305				var image           = $( this ),
4306					height          = image.height(),
4307					node            = image.closest( '.fl-module' ).data( 'node' ),
4308					className       = 'fl-node-' + node + '-img-' + i,
4309					maxMegaMenu     = image.closest( '.max-mega-menu' ).length,
4310					imageInLightbox = image.closest( '.fl-button-lightbox-content' ).length,
4311					imageInNavMenu  = image.closest( 'li.menu-item' ).length;
4312
4313				if ( ! ( imageInLightbox || imageInNavMenu || maxMegaMenu  ) ) {
4314					image.addClass( className );
4315					styles += '.' + className + ' { max-height: ' + ( height ? height : image[0].height )  + 'px }';
4316				}
4317
4318			} );
4319
4320			if ( '' !== styles ) {
4321				head.append( '<style id="' + stylesId + '">' + styles + '</style>' );
4322			}
4323		},
4324
4325		/**
4326		 * Removes max height on images in modules for smooth scrolling.
4327		 *
4328		 * @since 1.1.1
4329		 * @access private
4330		 * @method _removeImageMaxHeight
4331		 */
4332		_removeImageMaxHeight: function()
4333		{
4334			$( '#fl-header-styles-' + this.header.data( 'post-id' ) ).remove();
4335		},
4336	};
4337
4338	$( function() { FLThemeBuilderHeaderLayout.init(); } );
4339
4340})(jQuery);
4341

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.