(function( $ ){

    const Body = $( 'body' ),
        openState = {
            search: false,
            offCanvas: false
        },
        { isRTL = false } = BlogBeeThemeConfig
    
    $.fn.isInViewport = function() {

        let _this = $( this )

        let elementTop = _this.offset().top;

        let elementBottom = elementTop + _this.outerHeight();

        let viewportTop = $( window ).scrollTop();

        let viewportBottom = viewportTop + $( window ).height();

        return ( elementBottom > viewportTop ) && ( elementTop < viewportBottom );
    }

    /**
     * MARK: Outside click handle
     * 
     * @since 1.0.0
     */
    const HandleOutsideClick = {
        /**
         * Init
         * 
         * @since 1.0.0
         */
        init: function() {
            this.bindEvent()
        },
        /**
         * Bind event
         * 
         * @since 1.0.0
         */
        bindEvent: function(){
            $( document ).on( 'click', ( event ) => {
                const _this = $( event.target )
                this.handleSearchOutsideclick( _this )
                this.handleOffCanvasOutsideclick( _this )
            } )
        },
        /**
         * Handle search outside click
         * 
         * @since 1.0.0
         */
        handleSearchOutsideclick: function( clickedElement ){
            const container = ! $( '.bbe-search-icon' ).is( clickedElement ) && ! $( '.bbe-search-icon' ).has( clickedElement ).length,
                searchForm = ! $( '#masthead .form-wrapper' ).is( clickedElement ) && ! $( '#masthead .form-wrapper' ).has( clickedElement ).length

            if( openState.search && container && searchForm ) {
                $( '.bbe-search-icon' ).removeClass( 'active' )
                $( '#masthead .form-wrapper' ).removeClass( 'active' )
                openState.search = false
            }
        },
        /**
         * Handle off canvas outside click
         * 
         * @since 1.0.0
         */
        handleOffCanvasOutsideclick: function( clickedElement ){
            const container = ! OffCanvas.container.is( clickedElement ) && ! OffCanvas.container.has( clickedElement ).length

            if( openState.offCanvas && ( container || OffCanvas.container.find( '.overlay' ).is( clickedElement ) ) ) {
                OffCanvas.container.toggleClass( 'active' )
                openState.offCanvas = false
                Body.removeClass( 'no-scroll' )
            }
        }
    }

    /**
     * MARK: Preloader Js
     * 
     * @since 1.0.0
     */
    const Preloader = {
        /**
         * Main banner container
         * 
         * @since 1.0.0
         */
        get container() {
            if( ! this._container ) {
                this._container = $( '.bbe-preloader' )
            }
            return this._container
        },
        /**
         * Initialization
         * 
         * @since 1.0.0
         */
        init() {
            if( this.container.length ) {
                let delay = this.container.data( 'delay' )

                let onlyFirstVisit = this.container.data( 'first-visit' )

                let delayMiliseconds = ( delay * 1000 )

                let timeout = null
                
                timeout = setTimeout( () => {
                    this.container.addClass( 'hidden' )
                }, delayMiliseconds )
            }
        }
    }

    /**
     * MARK: Main banner js
     * 
     * @since 1.0.0
     */
    const MainBanner = {
        /**
         * Main banner container
         * 
         * @since 1.0.0
         */
        get container() {
            if( ! this._container ) {
                this._container = $( '#bbe-main-banner' )
            }
            return this._container
        },
        /**
         * Main banner entry content
         * 
         * @since 1.0.0
         */
        get entryContent() {
            if( ! this._entryContent ) {
                this._entryContent = this.container.find( '.entry-content' )
            }
            return this._entryContent
        },
        /**
         * slick instance
         * 
         * @since 1.0.0
         */
        slickInstance: null,
        /**
         * Check if main banner layout three is active or not
         * 
         * @since 1.0.0
         */
        isLayoutThree: false,
        /**
         * Initialization function
         * 
         * @since 1.0.0
         */
        init() {
            if( this.container.length ) {
                this.isLayoutThree = this.container.hasClass( 'layout--three' )
                this.initSlick()
                if( this.isLayoutThree ) {
                    this.bindSidebarSlider()
                    this.setBackgroundImage( 0 )
                    this.bindSlideChange()
                }
            }    
        },
        /**
         * Initialize slick
         * 
         * @since 1.0.0
         */
        initSlick() {
            const { mainBanner } = BlogBeeThemeConfig

            const self = this

            const isCenterMode = self.container.hasClass( 'layout--four' )

            if( self.container.hasClass( 'layout--two' ) ) {
                mainBanner.vertical = false
            }

            const slickObject = {
                autoplay: mainBanner.autoplay ?? false,
                speed: mainBanner.speed ?? 300,
                arrows: mainBanner.arrows ?? true,
                infinite: true,
                vertical: mainBanner.vertical ?? false,
                dots: mainBanner.dots ?? true,
                prevArrow: this.container.find( '.prev-arrow' ),
                nextArrow: this.container.find( '.next-arrow' ),
                centerMode: isCenterMode,
                centerPadding: '100px',
                asNavFor: self.isLayoutThree ? '#bbe-main-banner .sidebar-content' : false,
                rtl: isRTL
            }
            if( mainBanner.vertical ) {
                slickObject.fade = false;
            } else {
                slickObject.fade = isCenterMode ? false : ( mainBanner.fade ?? true )
            }
            if( isCenterMode ) {
                slickObject.responsive = [
                    {
                        breakpoint: 768,
                        settings: {
                            centerMode: true,  // explicitly setting it here because it conflicts with mobile
                            centerPadding: '20px'
                        }
                    },
                ]
            }
            this.slickInstance = this.entryContent.slick( slickObject )
        },
        /**
         * Bind main banner sidebar slick slider
         * 
         * @since 1.0.0
         */
        bindSidebarSlider() {
            const slickObject = {
                autoplay: false,
                slidesToShow: 3,
                asNavFor: '#bbe-main-banner .entry-content',
                focusOnSelect: true,
                vertical: true,
                arrows: false,
                verticalSwiping: true,
                rtl: isRTL
            }
            this.container.find( '.sidebar-content' ).slick( slickObject )
        },
        /**
         * Set background image
         * 
         * @param { Int } index The slider index
         * @since 1.0.0
         */
        setBackgroundImage( index ) {
            // change background image
            let image = this.entryContent.find( '.bbe-article' ).eq( index ).find( '.bbe-article-thumb' )
            let src = image.attr( 'src' )
            this.container.find( '.slider-content-wrap' ).css( {
                backgroundImage: `url(${ src })`
            } )

            // change href
            let href = image.parent().attr( 'href' )
            this.container.find( '.banner-overlay' ).attr( 'href', href )
        },
        /**
         * Change background image after slide change
         * 
         * @since 1.0.0
         */
        bindSlideChange() {
            let self = this
            this.entryContent.on( 'beforeChange', function( event, slick, _currentSlide, nextSlide ){
                self.setBackgroundImage( nextSlide )
            } )
        }
    }

    /**
     * MARK: Dark mode js
     * 
     * @since 1.0.0
     */
    const DarkMode = {
        /**
         * Dark mode container
         * 
         * @since 1.0.0
         */
        get container() {
            if( ! this._container ) {
                this._container = $( '.bbe-dark-mode.header-widget' )
            }
            return this._container
        },
        /**
         * Initialization function
         * 
         * @since 1.0.0
         */
        init() {
            if( this.container.length ) {
                this.bindEvent()
                this.checkDark()
            }
        },
        /**
         * Bind click event
         * 
         * @since 1.0.0
         */
        bindEvent() {
            this.container.on( 'click', '.icon, .icon-wrapper', function() {
                Body.toggleClass( 'bbe-dark bbe-light' )
                const darkModeEnabled = localStorage.getItem( 'bbe-dark' )
                if( typeof darkModeEnabled === 'undefined' || darkModeEnabled === '0' ) {
                    localStorage.setItem( 'bbe-dark', '1' )
                } else {
                    localStorage.setItem( 'bbe-dark', '0' )
                }
            } )
        },
        /**
         * Check if dark or not
         * 
         * @since 1.0.0
         */
        checkDark() {
            const darkModeEnabled = localStorage.getItem( 'bbe-dark' )
            if( darkModeEnabled === '1' ) {
                Body.addClass( 'bbe-dark' ).removeClass( 'bbe-light' )
            } else {
                Body.addClass( 'bbe-light' ).removeClass( 'bbe-dark' )
            }
        }
    }

    /**
     * MARK: Search Js
     * 
     * @since 1.0.0
     */
    class Search {
        /**
         * Search container
         * 
         * @since 1.0.0
         */
        container = null
        /**
         * Search form
         * 
         * @since 1.0.0
         */
        searchForm = null
        /**
         * Initialization Function
         * 
         * @param { Object } container Container element
         * @param { Object } headerForm Header form element
         * @since 1.0.0
         */
        constructor( container, headerForm ) {
            this.container = container
            if( this.container.length ) {
                let searchForm = this.container.find( '.form-wrapper' )
                if( searchForm.length ) {
                    this.searchForm = searchForm
                } else {
                    this.searchForm = headerForm
                }
                this.init()
            }
        }
        /**
         * Initialization Function
         * 
         * @since 1.0.0
         */
        init() {
            this.bindClickEvent()
            this.bindCloseEvent()
        }
        /**
         * Toggle active class
         * 
         * @since 1.0.0
         */
        toggleActiveClass() {
            this.container.toggleClass( 'active' )
            this.searchForm.toggleClass( 'active' )
        }
        /**
         * Bind click event
         * 
         * @since 1.0.0
         */
        bindClickEvent() {
            let timeout
            this.container.on( 'click', '> .icon', () => {
                this.toggleActiveClass()
                clearTimeout( timeout )
                timeout = setTimeout( () => {
                    this.focusInput()
                }, 450 )    // the 450 should match the transition used in css if transition is used
                openState.search = true
            } )
        }
        /**
         * Move Search
         * 
         * @since 1.0.0
         */
        focusInput() {
            this.searchForm.find( '.search-field' )[ 0 ].focus( { preventScroll: true } )
        }
        /**
         * Close event
         * 
         * @since 1.0.0
         */
        bindCloseEvent() {
            let closeButton = this.searchForm.find( '.close-icon' )
            if( closeButton.length ) {
                closeButton.on( 'click', () => {
                    this.toggleActiveClass()
                    openState.search = false
                } )
            }
        }
    }

    /**
     * MARK: Scroll to top js
     * 
     * @since 1.0.0
     */
    const ScrollToTop = {
        /**
         * Container
         * 
         * @since 1.0.0
         */
        get container() {
            if( ! this._container ){
                this._container = $( '#bbe-scroll-to-top' )
            }
            return this._container
        },
        /**
         * Initialization function
         * 
         * @since 1.0.0
         */
        init() {
            if( this.container.length ){
                this.bindEvent()
                this.bindScrollEvent()
            }
        },
        /**
         * Bind event
         * 
         * @since 1.0.0
         */
        bindEvent(){
            this.container.on( 'click', () => {
                $( 'html, body' ).animate( {
                    scrollTop: '0'
                }, 300 );
            } )
        },
        /**
         * Bind scroll event
         * 
         * @since 1.0.0
         */
        bindScrollEvent(){
            let self = this
            this.toggleShowClass( $( document ).scrollTop() )   // initial rendering

            $( document ).on( 'scroll', function(){
                self.toggleShowClass( $( this ).scrollTop() )
            } )
        },
        /**
         * Toggle show class
         * 
         * @param { Int } topOffset value scrolled from the top of the document
         * @since 1.0.0
         */
        toggleShowClass( topOffset ) {
            if( topOffset > 500 ) {
                this.container.addClass( 'show' )
            } else {
                this.container.removeClass( 'show' )
            }
        }
    }

    /**
     * MARK: Time js
     * 
     * @since 1.0.0
     */
    const Time = {
        /**
         * Container
         * 
         * @since 1.0.0
         */
        get container() {
            if( ! this._container ){
                this._container = $( '.bbe-time, .bbe-date-time' )
            }
            return this._container
        },
        /**
         * Init
         * 
         * @since 1.0.0
         */
        init() {
            if( this.container.length ) {
                this.bindEvent()
            }
        },
        /**
         * Bind event
         * 
         * @since 1.0.0
         */
        bindEvent() {
            setInterval( () => {
                const now = new Date()
                this.container.find( '.time' ).html( now.toLocaleTimeString() )
            }, 1000 )
        }
    }

    /**
     * MARK: Carousel Js
     * 
     * @since 1.0.0
     */
    const Carousel = {
        /**
         * Container
         * 
         * @since 1.0.0
         */
        get container() {
            if( ! this._container ) {
                this._container = $( '.bbe-carousel:not(.is-widget)' )
            }
            return this._container
        },
        /**
         * Initialization
         * 
         * @since 1.0.0
         */
        init() {
            if( this.container.length ) {
                this.bindSlick()
            }
        },
        /**
         * Slick object
         * 
         * @since 1.0.0
         */
        getSlickObject() {
            const { carousel } = BlogBeeThemeConfig
            const slickObject = {
                autoplay: carousel.autoplay ?? true,
                speed: carousel.speed ?? 300,
                arrows: carousel.arrows ?? true,
                centerMode: carousel.centerMode ?? false,
                slidesToShow: carousel.slidesToShow ?? 4,
                dots: carousel.dots ?? false,
                appendDots: this.container.find( '.bbe-slick-dots' ),
                infinite: true,
                prevArrow: this.container.find( '.prev-arrow' ),
                nextArrow: this.container.find( '.next-arrow' ),
                rtl: isRTL,
                responsive: [
                    {
                        breakpoint: 1100,
                        settings: {
                        slidesToShow: 3,
                        },
                    },
                    {
                        breakpoint: 940,
                        settings: {
                        slidesToShow: 2,
                        },
                    },
                    {
                        breakpoint: 700,
                        settings: {
                        slidesToShow: 1,
                        },
                    }
                ]
            }
            return slickObject
        },
        /**
         * Bind slick slider
         * 
         * @since 1.0.0
         */
        bindSlick() {
            this.container.find( '.entry-content' ).slick( this.getSlickObject() )
        }
    }

    /**
     * MARK: Off canvas js
     * 
     * @since 1.0.0
     */
    const OffCanvas = {
        /**
         * Container
         * 
         * @since 1.0.0
         */
        get container() {
            if( ! this._container ) {
                this._container = $( '.bbe-off-canvas' )
            }
            return this._container
        },
        /**
         * Initialization
         * 
         * @since 1.0.0
         */
        init(){
            if( this.container.length ) {
                this.bindOpenEvent();
                this.bindCloseEvent();
            }
        },
        /**
         * Bind Open Event
         * 
         * @since 1.0.0
         */
        bindOpenEvent() {
            this.container.on( 'click', '.canvas-icon', () => {
                this.container.toggleClass( 'active' )
                openState.offCanvas = true
                Body.addClass( 'no-scroll' )
            } )
        },
        /**
         * Bind Close Event
         * 
         * @since 1.0.0
         */
        bindCloseEvent() {
            this.container.on( 'click', '.close-icon', () => {
                this.container.removeClass( 'active' )
                openState.offCanvas = false
                Body.removeClass( 'no-scroll' )
            } )
        }
    }

    /**
     * MARK: Mobile Canvas JS
     * 
     * @since 1.0.0
     */
    const MobileCanvas = {
        /**
         * Container
         * 
         * @since 1.0.0
         */
        get container() {
            if( ! this._container ) {
                this._container = $( '.column .bbe-mobile-canvas' )
            }
            return this._container
        },
        /**
         * Initialization
         * 
         * @since 1.0.0
         */
        init() {
            if( this.container.length ) {
                this.bindClickEvent()
                this.bindResizeEvent()
                this.bindCloseEvent()
            }
        },
        /**
         * Toggle active class
         * 
         * @since 1.0.0
         */
        toggleActiveClass() {
            Body.find( '.bbe--responsive > .bbe-mobile-canvas' ).toggleClass( 'active' )
        },
        /**
         * Bind click event
         * 
         * @since 1.0.0
         */
        bindClickEvent() {
            this.container.on( 'click', 'button.icon', () => {
                this.toggleActiveClass()
            } )
        },
        /**
         * Bind Resize
         * 
         * @since 1.0.0
         */
        bindResizeEvent() {
            let menu = $( '.bbe--responsive > .bbe-mobile-canvas .bbe-primary-menu' ),
                cutoff = menu.find( '.menu-item-more' ),
                submenu = cutoff.find( '> .sub-menu' ),
                target = cutoff.parent()

            submenu.children().appendTo( target )
            cutoff.remove()
        },
        /**
         * Close event
         * 
         * @since 1.0.0
         */
        bindCloseEvent() {
            $( '.bbe--responsive > .bbe-mobile-canvas' ).on( 'click', '.canvas-close-icon', () => {
                this.toggleActiveClass()
            } )
        }
    }

    /**
     * MARK: Menu JS
     * 
     * @since 1.0.0
     */
    const Menu = {
        /**
         * Container
         * 
         * @since 1.0.0
         */
        get container() {
            if( ! this._container ) {
                this._container = $( '.bbe-menu' )
            }
            return this._container
        },
        /**
         * Initialization
         */
        init(){
            if( this.container.length ) {
                this.bindClick()
                this.bindKeyDown()
            }
        },
        /**
         * Active to perform on click and keydown
         * 
         * @since 1.0.0
         */
        action( parent, parentSibling ) {
            if( parent.attr( 'aria-expanded' ) === 'true' ) {
                parent.attr( 'aria-expanded', 'false' )
            } else {
                parent.attr( 'aria-expanded', 'true' )
            }

            parentSibling.toggleClass( 'active' )
        },
        /**
         * Handle submenu icon keydown
         * 
         * @since 1.0.0
         */
        bindKeyDown() {
            let self = this
            this.container.on( 'keydown', '.submenu-icon.icon-button', function( event ){
                let key = event.key

                // Only intercept the keys this widget actually handles
                if ( key === 'Enter' || key === ' ' || key === 'Spacebar' ) {
                    event.preventDefault()
                    event.stopPropagation()

                    let _this = $( this ),
                        parent = _this.parent(),
                        parentSibling = parent.siblings()

                    self.action( parent, parentSibling )
                }
                // Tab, Shift+Tab, Escape, arrows, etc. fall through normally
            } )
        },
        /**
         * Handle submenu icon click
         * 
         * @since 1.0.0
         */
        bindClick() {
            let self = this
            this.container.on( 'touchstart', '.submenu-icon.icon-button', function( event ){
                event.preventDefault()
                event.stopPropagation()
                let _this = $( this ),
                    parent = _this.parent(),
                    parentSibling = parent.siblings()

                self.action( parent, parentSibling )
            } )
        }
    }

    /**
     * MARK: Masonry Js
     * 
     * @since 1.0.0
     */
    const Masonry = {
        /**
         * Container
         * 
         * @since 1.0.0
         */
        get container() {
            if( ! this._container ) {
                this._container = $( '.masonry--on' )
            }
            return this._container;
        },
        /**
         * Initialization
         * 
         * @since 1.0.0
         */
        init() {
            if( $.fn.masonry && this.container.length ) {
                this.bindMasonry()
            }
        },
        /**
         * Bind masonry
         * 
         * @since 1.0.0
         */
        bindMasonry() {
            let masonryObject = {
                itemSelector: '.bbe-article',
                columnWidth: '.bbe-masonry-sizer',
                percentPosition: true,
                gutter: 30
            }
            let $wrap = this.container.find( '.site-main .article-wrap' )
            $wrap.masonry( masonryObject )
        }
    }

    /**
     * MARK: Carousel Widget js
     * 
     * @since 1.0.0
     */
    class CarouselWidget {
        /**
         * Container
         * 
         * @since 1.0.0
         */
        container = null
        /**
         * Initialization Function
         * 
         * @param { Object } container Container element
         * @since 1.0.0
         */
        constructor( container ) {
            this.container = $( container )
            if( this.container.length ) {
                this.init()
            }
        }
        /**
         * Initialization
         * 
         * @since 1.0.0
         */
        init() {
            if( $.fn.slick ) {
                let self = this
                this.container.each(function(){
                    let _this = $( this )
                    self.bindSlick( _this )
                } )
            }
        }
        /**
         * Bind masonry
         * 
         * @param { Object } instance The current carousel posts widget instance
         * @since 1.0.0
         */
        bindSlick( instance ) {
            let autoplay = instance.data( 'autoplay' ) ?? 1

            let arrows = instance.data( 'arrows' ) ?? 1

            let vertical = instance.data( 'direction' ) ?? 'horizontal'

            let isVertical = vertical === 'vertical'

            let infinite = instance.data( 'infinite' ) ?? 1

            const slickObject = {
                autoplay: autoplay === 1,
                speed: 300,
                arrows: arrows === 1,
                infinite: infinite === 1,
                vertical: isVertical,
                prevArrow: instance.find( '.prev-arrow' ),
                nextArrow: instance.find( '.next-arrow' ),
                rtl: isRTL,
                adaptiveHeight: true
            }
            if( isVertical ) {
                slickObject.adaptiveHeight = true
            } else {
                slickObject.fade = true
            }
            if( instance.parents( '.frontpage-widget-area' ).length ) {
                let _slickObject = Carousel.getSlickObject()
                _slickObject.autoplay = ( autoplay === 1 )
                _slickObject.arrows = ( arrows === 1 )
                _slickObject.infinite = ( infinite === 1 )
                _slickObject.appendDots = instance.find( '.bbe-carousel.is-widget .bbe-slick-dots' )
                _slickObject.prevArrow = instance.find( '.prev-arrow' )
                _slickObject.nextArrow = instance.find( '.next-arrow' )
                instance.find( '.bbe-carousel.is-widget' ).find( '.entry-content' ).slick( _slickObject )
            } else {
                instance.find( '.article-wrap' ).slick( slickObject )
            }
        }
    }

    /**
     * MARK: Sticky Header js
     * 
     * @since 1.0.0
     */
    const StickyHeader = {
        /**
         * In viewport
         * 
         * @since 1.0.0
         */
        inViewport: false,
        /**
         * Container
         * 
         * @since 1.0.0
         */
        get container() {
            if( ! this._container ) {
                this._container = $( '.bbe-sticky-header' )
            }
            return this._container;
        },
        /**
         * Header
         * 
         * @since 1.0.0
         */
        get header() {
            if( ! this._header ) {
                this._header = $( '#masthead' )
            }
            return this._header;
        },
        /**
         * Initialization
         * 
         * @since 1.0.0
         */
        init() {
            if( this.container.length ) {
                this.bindScroll()
                this.bindIntersectionObserver()
                this.bindMenuClick()
            }
        },
        /**
         * Bind scroll
         * 
         * @since 1.0.0
         */
        bindScroll() {
            let lastY = 0;

            let self = this

            const { sticky } = BlogBeeThemeConfig

            const { down, up } = sticky

            $( window ).on( 'scroll', function() {
                if( self.inViewport ) return;
                let currentY = $( this ).scrollTop()

                if( currentY > lastY ) {
                    if( down ) {
                        self.header.addClass( 'sticky--on' ).removeClass( 'sticky--off' )
                    } else {
                        self.header.addClass( 'sticky--off' ).removeClass( 'sticky--on' )
                    }
                } else {
                    if( up ) {
                        self.header.addClass( 'sticky--on' ).removeClass( 'sticky--off' )
                    } else {
                        self.header.addClass( 'sticky--off' ).removeClass( 'sticky--on' )
                    }
                }
                lastY = currentY
            } )
        },
        /**
         * Bind Intersection Observer js API
         * 
         * @see https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
         * @since 1.0.0
         */
        bindIntersectionObserver() {
            const observer = new IntersectionObserver( ( entries ) => {
                entries.forEach( entry => {
                    if( entry.isIntersecting ) {
                        this.inViewport = true
                        this.header.addClass( 'sticky--off' ).removeClass( 'sticky--on' )
                    } else {
                        this.inViewport = false
                    }
                } )
            } )
            observer.observe( this.header[ 0 ] )
        },
        /**
         * Bind menu click
         * 
         * @since 1.0.0
         */
        bindMenuClick() {
            const primaryMenu = this.container.find( '.bbe-primary-menu' )
            if( primaryMenu.length < 1 ) return;    // guard

            primaryMenu.on( 'click', '.menu-toggle', function() {
                let _this = $( this )

                let sibling = _this.siblings( '.menu-container' )

                sibling.toggleClass( 'active' )
            } )
        }
    }

    /**
     * MARK: Lazy load sliders
     * 
     * @since 1.0.0
     */
    const LazySlider = {
        /**
         * Map each selector to its init function
         */
        sliders: [
            { selector: MainBanner.container, fn: () => MainBanner.init() },
            { selector: Carousel.container, fn: () => Carousel.init() },
            { selector: Masonry.container, fn: () => Masonry.init() },
            { selector: $( '.frontpage-widget-area .carousel-widget.bbe-sidebar-widget' ), fn: () => new CarouselWidget( $( '.frontpage-widget-area .carousel-widget.bbe-sidebar-widget' ) ) },
            { selector: $( '.carousel-widget.bbe-sidebar-widget.not-frontpage' ), fn: () => new CarouselWidget( $( '.carousel-widget.bbe-sidebar-widget.not-frontpage' ) ) },
        ],
        /**
         * Initialization
         * 
         * @since 1.0.0
         */
        init() {
            const observer = new IntersectionObserver( ( entries, obs ) => {
                entries.forEach( entry => {
                    if ( ! entry.isIntersecting ) return

                    const match = this.sliders.find( s => $( entry.target ).is( s.selector ) )

                    if ( match ) {
                        match.fn()
                        obs.unobserve( entry.target ) // never init twice
                    }
                })
            }, {
                rootMargin: '200px 0px', // look 200px ahead in scroll direction
            })

            this.sliders.forEach( ( { selector } ) => {
                // some selectors may match multiple elements (e.g. carousel widget)
                $( selector ).each(function() {
                    observer.observe( $( this )[0] )
                })
            } )
        }
    }

    /**
     * Cursor Animation
     * 
     * @since 1.0.0
     */
    const CursorAnimation = {
        /**
         * Container
         * 
         * @since 1.0.0
         */
        get container() {
            if( ! this._container ) {
                this._container = $( 'body .cursor-animation' )
            }
            return this._container
        },
        /**
         * Initialization
         * 
         * @since 1.0.0
         */
        init() {
            if( this.container.length ) {
                this.bindMouseMove()
                this.bindMouseInOut()
            }
        },
        /**
         * Bind on mouse move
         * 
         * @since 1.0.0
         */
        bindMouseMove() {
            $( document ).on( 'mousemove', ( event ) => {
                this.container.css({
                    'top': 'calc('+ event.clientY +'px - 15px)',
                    'left': 'calc('+ event.clientX +'px - 15px)'
                })
            })
        },
        /**
         * Bind mouse in and out of element
         * 
         * @sice 1.0.0
         */
        bindMouseInOut() {
            var selector = 'a, button, input[type="submit"]'
            $( selector ).on( 'mouseover', () => {
                this.container.addClass( 'isActive' )
            })
            $( selector ).on( 'mouseout', () => {
                this.container.removeClass( 'isActive' )
            })
        }
    }

    /**
     * Execute all when document is ready
     * MARK: Document Ready
     * 
     * @since 1.0.0
     */
    $( document ).ready( () => {
        /**
         * Check if is home or frontpage
         */
        const isHome = $( 'body.home.blog' ).length || $( 'body.blog' ).length
        let sliders = []
        /**
         * Preloader
         */
        Preloader.init()
        /**
         * Outside click
         */
        HandleOutsideClick.init()
        /**
         * Dark Mode
         */
        DarkMode.init()
        /**
         * Search
         */
        new Search( $( '.bbe--normal .bbe-search-icon' ), $( '#masthead .form-wrapper.normal' ) )
        new Search( $( '.bbe--responsive .bbe-search-icon' ), $( '#masthead .form-wrapper.responsive' ) )
        new Search( $( '.bbe-sticky-header .bbe-search-icon' ), $( '#masthead .form-wrapper.sticky' ) )
        /**
         * Scroll to Top
         */
        ScrollToTop.init()
        /**
         * Time
         */
        Time.init()
        /**
         * Off canvas
         */
        OffCanvas.init()
        /**
         * Mobile Canvas
         */
        MobileCanvas.init()
        /**
         * Menu
         */
        Menu.init()

        /**
         * Lazy Load Sliders
         */
        LazySlider.init()

        /**
         * Sticky Header
         */
        StickyHeader.init()

        /**
         * Cursor Animation
         */
        CursorAnimation.init()
    } )
})( jQuery )