/**
 * Theme Name: errigal
 * Theme URI: https://projecterrigal.com/themes/errigal/
 * Author: Project errigal
 * Author URI: https://projecterrigal.com/
 * Version: 1.2.1
 */
( function() {
	'use strict';

	const EVENT_PREVIEW_READY = 'preview-ready';
	const OBJECT_NAME_WP = 'wp';
	const EMPTY_ARRAY = [];
	const NULL_OBJECT = null;
	const INDEX_FIRST = 0;

	function isFunction( value ) {
		return value instanceof Function;
	}

	function isHTMLCollection( elements ) {
		return elements instanceof HTMLCollection;
	}

	function isObjectType( value, expectedType ) {
		return Object.prototype.toString.call( value ) ===
			`[object ${ expectedType }]`;
	}

	function isNumber( value ) {
		return (
			! isNaN( value ) &&
			isObjectType( value, 'Number' ) &&
			isFinite( value )
		);
	}

	function isPositiveNumber( value ) {
		return isNumber( value ) && value > 0;
	}

	function isIterable( items ) {
		return !! items && isPositiveNumber( items.length );
	}

	function isTrue( value ) {
		return value === true;
	}

	function forEach( items, callback ) {
		if ( ! isIterable( items ) || ! isFunction( callback ) ) {
			return false;
		}

		if ( isHTMLCollection( items ) ) {
			items = Array.prototype.slice.call( items );
		}

		for ( let i = INDEX_FIRST; i < items.length; i++ ) {
			if ( isTrue( callback( items[ i ], i, items ) ) ) {
				return true;
			}
		}

		return false;
	}

	const NULL_VALUE = null;

	function isObject( value ) {
		return value instanceof Object;
	}

	function getObjectValue( obj, key ) {
		return isObject( obj ) && ( key in obj )
			? obj[ key ]
			: NULL_VALUE;
	}

	function hasObjectKey( value, index ) {
		return (
			!! value &&
			!! index &&
			isTrue( Object.prototype.hasOwnProperty.call( value, index ) )
		);
	}

	const EMPTY_STRING = '';

	function isString( value ) {
		return isObjectType( value, 'String' );
	}

	function isNonEmptyString( value ) {
		return (
			isString( value ) &&
			isFunction( value.trim ) &&
			value.trim() !== EMPTY_STRING
		);
	}

	function isStringArray( items ) {
		return Array.isArray( items ) && isIterable( items )
			? ! forEach( items, ( item ) => ! isNonEmptyString( item ) )
			: false;
	}

	function getGlobalObject(
		objectName,
		expectedKeys = EMPTY_ARRAY
	) {
		if ( ! ( expectedKeys === EMPTY_ARRAY || isStringArray( expectedKeys ) ) ) {
			return NULL_OBJECT;
		}

		const GLOBAL_OBJECT = getObjectValue( window, objectName );

		if ( ! isObject( GLOBAL_OBJECT ) ) {
			return NULL_OBJECT;
		}

		if ( ! isPositiveNumber( expectedKeys.length ) ) {
			return GLOBAL_OBJECT;
		}

		const HAS_EXPECTED_KEYS =
			! forEach(
				expectedKeys,
				( key ) => ! hasObjectKey( GLOBAL_OBJECT, key )
			);

		return isTrue( HAS_EXPECTED_KEYS )
			? GLOBAL_OBJECT
			: NULL_OBJECT;
	}

	function getWp() {
		return getGlobalObject( OBJECT_NAME_WP );
	}

	function isWpCustomise( wpObj ) {
		return (
			!! wpObj &&
			isFunction( wpObj.customize ) &&
			isFunction( wpObj.customize.bind )
		);
	}

	function bindCustomEvent( eventType, callback ) {
		if ( ! isNonEmptyString( eventType ) || ! isFunction( callback ) ) {
			return;
		}

		const WP = getWp();

		if ( ! isWpCustomise( WP ) ) {
			return;
		}

		WP.customize.bind( eventType, callback );
	}

	function onCustomisePreviewReady( callback ) {
		bindCustomEvent( EVENT_PREVIEW_READY, callback );
	}

	const CLASS_CUSTOM_SUFFIX_HEADING_STYLE = '-headings';
	const CUSTOM_ID_HEADING_STYLE = 'heading_style';
	const CLASS_SECTION_ENTRY_CONTENT = 'entry-content';

	function getFirstItem( items ) {
		return isIterable( items )
			? items[ INDEX_FIRST ]
			: NULL_VALUE;
	}

	const NULL_ELEMENT = null;

	function hasClassList( element ) {
		return (
			!! element &&
			element.classList instanceof DOMTokenList &&
			isFunction( element.classList.contains )
		);
	}

	function isHTMLElement( element, ...classNames ) {
		if ( ! ( element instanceof HTMLElement ) ) {
			return false;
		}

		return (
			hasClassList( element ) &&
			! forEach(
				classNames,
				( className ) => ! element.classList.contains( className )
			)
		);
	}

	function isDocument( element ) {
		return element instanceof Document;
	}

	function isisHTMLElementOrDocument( element ) {
		return isHTMLElement( element ) || isDocument( element );
	}

	function callElementMethod(
		methodName,
		nameOrSelectors,
		rootElement
	) {
		return (
			isNonEmptyString( methodName ) &&
			isNonEmptyString( nameOrSelectors ) &&
			isisHTMLElementOrDocument( rootElement ) &&
			isFunction( rootElement[ methodName ] )
		)
			? rootElement[ methodName ]( nameOrSelectors )
			: NULL_ELEMENT;
	}

	function getElementsByClassName(
		className,
		rootElement = document
	) {
		const ELEMENTS =
			callElementMethod(
				'getElementsByClassName',
				className,
				rootElement
			);

		return isHTMLCollection( ELEMENTS )
			? ELEMENTS
			: NULL_ELEMENT;
	}

	function getElementByClassName(
		className,
		rootElement = document
	) {
		return getFirstItem( getElementsByClassName( className, rootElement ) );
	}

	function getEntryContent() {
		return getElementByClassName( CLASS_SECTION_ENTRY_CONTENT );
	}

	function isWpCustomisePreview( wpObj ) {
		return (
			!! wpObj &&
			isFunction( wpObj.customize ) &&
			isObject( wpObj.customize.preview ) &&
			isFunction( wpObj.customize.preview.bind ) &&
			isObject( wpObj.customize.selectiveRefresh ) &&
			isFunction( wpObj.customize.selectiveRefresh.bind ) &&
			isFunction( wpObj.customize.selectiveRefresh.partial ) &&
			isFunction( wpObj.customize.selectiveRefresh.requestFullRefresh )
		);
	}

	function isCustomPartial( partial ) {
		return (
			!! partial &&
			isObject( partial.params ) &&
			isString( partial.params.selector ) &&
			isFunction( partial.ready )
		);
	}

	function getCustomPartial( id ) {
		if ( ! isNonEmptyString( id ) ) {
			return NULL_OBJECT;
		}

		const WP = getWp();

		if ( ! isWpCustomisePreview( WP ) ) {
			return NULL_OBJECT;
		}

		const PARTIAL = WP.customize.selectiveRefresh.partial( id );

		return isCustomPartial( PARTIAL )
			? PARTIAL
			: NULL_OBJECT;
	}

	function getCustomSelectiveRefreshSelector( id ) {
		const PARTIAL = getCustomPartial( id );

		return !! PARTIAL
			? PARTIAL.params.selector
			: EMPTY_STRING;
	}

	function requestFullRefresh() {
		const WP = getWp();

		if ( ! isWpCustomisePreview( WP ) ) {
			return;
		}

		WP.customize.selectiveRefresh.requestFullRefresh();
	}

	function resetCustomSelectiveRefreshSelector( id ) {
		const PARTIAL = getCustomPartial( id );

		if ( ! PARTIAL ) {
			requestFullRefresh();

			return false;
		}

		PARTIAL.params.selector = EMPTY_STRING;

		return true;
	}

	const CLASS_CUSTOM_PARTIAL_REFRESHING = 'customize-partial-refreshing';
	const DELAY_PARTIAL_REFRESHING = 250;

	function addClass( element, className ) {
		if (
			! isHTMLElement( element ) ||
			! hasClassList( element ) ||
			! isFunction( element.classList.add ) ||
			! isNonEmptyString( className )
		) {
			return;
		}

		element.classList.add( className );
	}

	function removeClass( element, className ) {
		if (
			! isHTMLElement( element ) ||
			! hasClassList( element ) ||
			! isFunction( element.classList.remove ) ||
			! isNonEmptyString( className )
		) {
			return;
		}

		element.classList.remove( className );
	}

	function callIfFunction( callback ) {
		if ( ! isFunction( callback ) ) {
			return;
		}

		callback();
	}

	function isBoolean( value ) {
		return isObjectType( value, 'Boolean' );
	}

	function simulateCustomPartialRefresh(
		element,
		callback,
		shouldExecuteCallbackAfterRefresh = false
	) {
		if (
			! isHTMLElement( element ) ||
			! isFunction( callback ) ||
			! isBoolean( shouldExecuteCallbackAfterRefresh )
		) {
			return;
		}

		const REMOVE_CLASS =
			removeClass.bind(
				null,
				element,
				CLASS_CUSTOM_PARTIAL_REFRESHING
			);
		const CALLBACKS = isTrue( shouldExecuteCallbackAfterRefresh )
			? [ REMOVE_CLASS, callback ]
			: [ callback, REMOVE_CLASS ];

		addClass( element, CLASS_CUSTOM_PARTIAL_REFRESHING );
		setTimeout(
			() => forEach( CALLBACKS, callIfFunction ),
			DELAY_PARTIAL_REFRESHING
		);
	}

	function updateCustomSelectiveRefreshSelector( id, selector ) {
		if ( ! isNonEmptyString( selector ) ) {
			return;
		}

		const PARTIAL = getCustomPartial( id );

		if ( ! PARTIAL ) {
			return;
		}

		PARTIAL.params.selector = selector;
	}

	function isCustomSetting( setting ) {
		return (
			isFunction( setting ) &&
			isNonEmptyString( setting.id ) &&
			isFunction( setting.bind )
		);
	}

	function bindCustomSetting( id, callback ) {
		if ( ! isNonEmptyString( id ) || ! isFunction( callback ) ) {
			return;
		}

		const WP = getWp();

		if ( ! isWpCustomise( WP ) ) {
			return;
		}

		WP.customize(
			id,
			( setting ) => {
				if ( ! isCustomSetting( setting ) ) {
					return;
				}

				setting.bind( ( value ) => callback( value, id ) );
			}
		);
	}

	function onCustomisePreviewOptionChange( id, callback ) {
		bindCustomSetting( id, callback );
	}

	function stringEndsWith( fullString, partialString ) {
		return (
			isNonEmptyString( fullString ) &&
			isNonEmptyString( partialString ) &&
			fullString.substr(
				fullString.length - partialString.length,
				partialString.length
			) === partialString
		);
	}

	function isHeadingStyle( id ) {
		return id === CUSTOM_ID_HEADING_STYLE;
	}

	function updateContentHeadingStyle( headingStyle, id ) {
		if ( ! isString( headingStyle ) || ! isHeadingStyle( id ) ) {
			return;
		}

		const SELECTOR = getCustomSelectiveRefreshSelector( id );

		if (
			! isNonEmptyString( SELECTOR ) ||
			! resetCustomSelectiveRefreshSelector( id )
		) {
			return;
		}

		const ENTRY_CONTENT = getEntryContent();

		if ( ! ENTRY_CONTENT ) {
			return;
		}

		let headingsClassName = EMPTY_STRING;

		forEach(
			ENTRY_CONTENT.classList,
			( className ) => {
				if ( stringEndsWith( className, CLASS_CUSTOM_SUFFIX_HEADING_STYLE ) ) {
					headingsClassName = className;

					return true;
				}

				return false;
			}
		);

		if ( ! isNonEmptyString( headingStyle ) ) {
			return;
		}

		simulateCustomPartialRefresh(
			ENTRY_CONTENT,
			() => {
				if ( isNonEmptyString( headingsClassName ) ) {
					removeClass( ENTRY_CONTENT, headingsClassName );
				}

				if ( isNonEmptyString( headingStyle ) ) {
					addClass(
						ENTRY_CONTENT,
						headingStyle + CLASS_CUSTOM_SUFFIX_HEADING_STYLE
					);
				}

				updateCustomSelectiveRefreshSelector( id, SELECTOR );
			}
		);
	}

	function addHeadingStyleChangeEvent() {
		onCustomisePreviewOptionChange(
			CUSTOM_ID_HEADING_STYLE,
			updateContentHeadingStyle
		);
	}

	function addHeadingStyleEvents() {
		addHeadingStyleChangeEvent();
	}

	const CLASS_CUSTOM_PREFIX_SITE_HEADER = 'site-header-';
	const CUSTOM_ID_SITE_HEADER_COLOUR = 'site_header_colour';
	const CLASS_SECTION_SITE_HEADER = 'site-header';

	function getSiteHeader() {
		return getElementByClassName( CLASS_SECTION_SITE_HEADER );
	}

	function stringStartsWith( fullString, partialString ) {
		return (
			isNonEmptyString( fullString ) &&
			isNonEmptyString( partialString ) &&
			fullString.indexOf( partialString ) === INDEX_FIRST
		);
	}

	function isSiteHeaderColour( id ) {
		return id === CUSTOM_ID_SITE_HEADER_COLOUR;
	}

	function updateSiteHeaderColour( siteHeaderColour, id ) {
		if ( ! isNonEmptyString( siteHeaderColour ) || ! isSiteHeaderColour( id ) ) {
			return;
		}

		const SELECTOR = getCustomSelectiveRefreshSelector( id );

		if (
			! isNonEmptyString( SELECTOR ) ||
			! resetCustomSelectiveRefreshSelector( id )
		) {
			return;
		}

		const SITE_HEADER = getSiteHeader();

		if ( ! SITE_HEADER ) {
			return;
		}

		let siteHeaderColourClassName = EMPTY_STRING;

		forEach(
			SITE_HEADER.classList,
			( className ) => {
				if ( stringStartsWith( className, CLASS_CUSTOM_PREFIX_SITE_HEADER ) ) {
					siteHeaderColourClassName = className;

					return true;
				}

				return false;
			}
		);

		if ( ! isNonEmptyString( siteHeaderColourClassName ) ) {
			return;
		}

		simulateCustomPartialRefresh(
			SITE_HEADER,
			() => {
				removeClass( SITE_HEADER, siteHeaderColourClassName );
				addClass(
					SITE_HEADER,
					CLASS_CUSTOM_PREFIX_SITE_HEADER + siteHeaderColour
				);
				updateCustomSelectiveRefreshSelector( id, SELECTOR );
			}
		);
	}

	function addSiteHeaderColourChangeEvent() {
		onCustomisePreviewOptionChange(
			CUSTOM_ID_SITE_HEADER_COLOUR,
			updateSiteHeaderColour
		);
	}

	function addSiteHeaderColourEvents() {
		addSiteHeaderColourChangeEvent();
	}

	const ATTRIBUTE_HREF = 'href';
	const CUSTOM_ID_WEBSITE_COLOUR_SCHEME = 'colour_scheme';
	const ID_ERRIGAL_CSS_STYLE = 'errigal-style-css';
	const TAG_LINK = 'link';
	const SELECTOR_CUSTOMISER_ERRIGAL_CSS_STYLE = `${ TAG_LINK }#${ ID_ERRIGAL_CSS_STYLE }`;

	function querySelector( selectors, rootElement = document ) {
		return callElementMethod( 'querySelector', selectors, rootElement );
	}

	function getErrigalCssStyle() {
		return querySelector( SELECTOR_CUSTOMISER_ERRIGAL_CSS_STYLE );
	}

	function getAttribute( element, name ) {
		return isHTMLElement( element ) && isFunction( element.getAttribute )
			? element.getAttribute( name )
			: NULL_VALUE;
	}

	function setAttribute( element, name, value ) {
		if (
			! isHTMLElement( element ) ||
			! isFunction( element.setAttribute ) ||
			! isNonEmptyString( name )
		) {
			return;
		}

		element.setAttribute( name, value );
	}

	function updateWebsiteColourScheme( websiteColourScheme ) {
		const CSS_STYLE = getErrigalCssStyle();

		if ( ! CSS_STYLE ) {
			return;
		}

		const CSS_STYLE_HREF = getAttribute( CSS_STYLE, ATTRIBUTE_HREF );

		if ( ! isNonEmptyString( CSS_STYLE_HREF ) ) {
			return;
		}

		const CSS_FILE_NAME = isNonEmptyString( websiteColourScheme )
			? `style-${ websiteColourScheme }.min.css`
			: 'style.min.css';

		setAttribute(
			CSS_STYLE,
			ATTRIBUTE_HREF,
			CSS_STYLE_HREF.replace( /style.*.min.css/, CSS_FILE_NAME )
		);
	}

	function addWebsiteColourSchemeChangeEvent() {
		onCustomisePreviewOptionChange(
			CUSTOM_ID_WEBSITE_COLOUR_SCHEME,
			updateWebsiteColourScheme
		);
	}

	function addWebsiteColourSchemeEvents() {
		addWebsiteColourSchemeChangeEvent();
	}

	function addAppearanceEvents() {
		addWebsiteColourSchemeEvents();
		addSiteHeaderColourEvents();
		addHeadingStyleEvents();
	}

	const CUSTOM_ID_BREADCRUMB = 'breadcrumb';
	const EVENT_PARTIAL_CONTENT_RENDERED = 'partial-content-rendered';

	function isCustomPlacement( placement ) {
		return (
			!! placement &&
			isObject( placement.container ) &&
			isObject( placement.partial ) &&
			isNonEmptyString( placement.partial.id ) &&
			isObject( placement.partial.params ) &&
			isString( placement.partial.params.selector )
		);
	}

	function onCustomPartialContentRendered( callback ) {
		if ( ! isFunction( callback ) ) {
			return;
		}

		const WP = getWp();

		if ( ! isWpCustomisePreview( WP ) ) {
			return;
		}

		WP.customize.selectiveRefresh.bind(
			EVENT_PARTIAL_CONTENT_RENDERED,
			( placement ) => {
				if ( ! isCustomPlacement( placement ) ) {
					return;
				}

				callback( placement.partial.id, placement );
			}
		);
	}

	const CLASS_SHARED_COLLAPSED = 'collapsed';
	const CLASS_NAV_BREADCRUMB_LIST = 'errigal-breadcrumb__list';

	function getBreadcrumbList() {
		return getElementByClassName( CLASS_NAV_BREADCRUMB_LIST );
	}

	const CLASS_NAV_BREADCRUMB_LIST_ITEM = 'errigal-breadcrumb__list-item';

	function getBreadcrumbListItems() {
		return getElementsByClassName( CLASS_NAV_BREADCRUMB_LIST_ITEM );
	}

	const RECT_WIDTH = 'width';
	const PIXEL_ZERO = 0;

	function getRectProp( element, property ) {
		if (
			! isHTMLElement( element ) ||
			! isFunction( element.getBoundingClientRect )
		) {
			return PIXEL_ZERO;
		}

		const RECT_PROP =
			getObjectValue(
				element.getBoundingClientRect(),
				property
			);

		return isNumber( RECT_PROP )
			? RECT_PROP
			: PIXEL_ZERO;
	}

	function getWidth( element ) {
		return getRectProp( element, RECT_WIDTH );
	}

	function toggleClass( add, element, className ) {
		if ( ! isBoolean( add ) ) {
			return;
		}

		const TOGGLE_CLASS = isTrue( add ) ? addClass : removeClass;

		TOGGLE_CLASS( element, className );
	}

	const CLASS_NAV_BREADCRUMB_LIST_ITEM_ANCESTOR = 'errigal-breadcrumb__ancestor';

	function getBreadcrumbAncestorListItems() {
		return getElementsByClassName( CLASS_NAV_BREADCRUMB_LIST_ITEM_ANCESTOR );
	}

	const CLASS_NAV_BREADCRUMB_REVEAL_BUTTON = 'errigal-breadcrumb__reveal-button';

	function getBreadcrumbRevealButton() {
		return getElementByClassName( CLASS_NAV_BREADCRUMB_REVEAL_BUTTON );
	}

	const CLASS_NAV_BREADCRUMB_LIST_ITEM_REVEAL = 'errigal-breadcrumb__reveal';

	function getBreadcrumbRevealListItem() {
		return getElementByClassName( CLASS_NAV_BREADCRUMB_LIST_ITEM_REVEAL );
	}

	const ATTRIBUTE_ARIA_EXPANDED = 'aria-expanded';

	function toggleAriaExpanded( expanded, ...elements ) {
		if ( ! isBoolean( expanded ) ) {
			return;
		}

		forEach(
			elements,
			( element ) => setAttribute(
				element,
				ATTRIBUTE_ARIA_EXPANDED,
				isTrue( expanded )
			)
		);
	}

	const ATTRIBUTE_ARIA_HIDDEN = 'aria-hidden';

	function toggleAriaHidden( hidden, ...elements ) {
		if ( ! isBoolean( hidden ) ) {
			return;
		}

		forEach(
			elements,
			( element ) => setAttribute(
				element,
				ATTRIBUTE_ARIA_HIDDEN,
				isTrue( hidden )
			)
		);
	}

	function toggleBreadcrumbRevealAndAncestorAriaAttributes( isAncestorHidden ) {
		toggleAriaExpanded(
			! isAncestorHidden,
			getBreadcrumbRevealButton()
		);
		toggleAriaHidden(
			! isAncestorHidden,
			getBreadcrumbRevealListItem()
		);
		toggleAriaHidden(
			isAncestorHidden,
			...getBreadcrumbAncestorListItems()
		);
	}

	function isBreadcrumbListWrapped() {
		let totalWidth = 0;
		const BREADCRUMB_LIST_WIDTH = getWidth( getBreadcrumbList() );

		return forEach(
			getBreadcrumbListItems(),
			( item ) => ( totalWidth += getWidth( item ) ) >= BREADCRUMB_LIST_WIDTH
		);
	}

	function toggleBreadcrumbAncestor() {
		const IS_BREADCRUMB_LIST_WRAPPED = isBreadcrumbListWrapped();

		toggleClass(
			IS_BREADCRUMB_LIST_WRAPPED,
			getBreadcrumbList(),
			CLASS_SHARED_COLLAPSED
		);
		toggleBreadcrumbRevealAndAncestorAriaAttributes( IS_BREADCRUMB_LIST_WRAPPED );
	}

	function isBreadcrumb( id ) {
		return id === CUSTOM_ID_BREADCRUMB;
	}

	function updateBreadcrumbAncestorVisibility( id ) {
		if ( ! isBreadcrumb( id ) ) {
			return;
		}

		toggleBreadcrumbAncestor();
	}

	function addBreadcrumbChangeEvent() {
		onCustomPartialContentRendered( updateBreadcrumbAncestorVisibility );
	}

	function addBreadcrumbEvents() {
		addBreadcrumbChangeEvent();
	}

	const CUSTOM_ID_BASE_FONT = 'base_font';
	const ID_ERRIGAL_CSS_BASE_FONT_STYLE = 'errigal-base-google-font-style-css';
	const SELECTOR_CUSTOMISER_ERRIGAL_CSS_BASE_FONT_STYLE = `${ TAG_LINK }#${ ID_ERRIGAL_CSS_BASE_FONT_STYLE }`;

	function getErrigalCssBaseFontStyle() {
		return querySelector( SELECTOR_CUSTOMISER_ERRIGAL_CSS_BASE_FONT_STYLE );
	}

	const CSS_FONT_FAMILY = 'font-family';
	const CUSTOM_TYPOGRAPHY_GOOGLE_FONT_FAMILY_URL = '//fonts.googleapis.com/css?family=';
	const FONT_FALLBACK = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif';
	const ID_ERRIGAL_CSS_INLINE_STYLE = 'errigal-style-inline-css';
	const TAG_STYLE = 'style';
	const SELECTOR_CUSTOMISER_ERRIGAL_CSS_INLINE_STYLE = `${ TAG_STYLE }#${ ID_ERRIGAL_CSS_INLINE_STYLE }`;

	function toLowerCase( value ) {
		return isNonEmptyString( value ) && isFunction( value.toLowerCase )
			? value.toLowerCase()
			: EMPTY_STRING;
	}

	function areStringsEqualIgnoreCase( str1, str2 ) {
		return toLowerCase( str1 ) === toLowerCase( str2 );
	}

	function hasTagName( element ) {
		return !! element && isNonEmptyString( element.tagName );
	}

	function isElementOfType( element, tagName ) {
		return (
			hasTagName( element ) &&
			isNonEmptyString( tagName ) &&
			areStringsEqualIgnoreCase( element.tagName, tagName )
		);
	}

	function isHTMLElementOfType(
		tagName,
		element,
		...classNames
	) {
		return (
			isHTMLElement( element, ...classNames ) &&
			isElementOfType( element, tagName )
		);
	}

	function isStyleElement( element ) {
		return isHTMLElementOfType( TAG_STYLE, element );
	}

	function isCssRuleList( element ) {
		return element instanceof CSSRuleList;
	}

	function isCssStyleSheet( element ) {
		return element instanceof CSSStyleSheet;
	}

	function isCssInlineStyle( element ) {
		return (
			isStyleElement( element ) &&
			isCssStyleSheet( element.sheet ) &&
			isCssRuleList( element.sheet.cssRules ) &&
			isIterable( element.sheet.cssRules )
		);
	}

	function getErrigalCssInlineStyle() {
		const CSS_INLINE_STYLE =
			querySelector( SELECTOR_CUSTOMISER_ERRIGAL_CSS_INLINE_STYLE );

		return isCssInlineStyle( CSS_INLINE_STYLE )
			? CSS_INLINE_STYLE
			: NULL_ELEMENT;
	}

	const OBJECT_NAME_FONT_FAMILIES = 'ERRIGAL_FONT_FAMILIES';

	function getFontFamiliesObject() {
		return getGlobalObject( OBJECT_NAME_FONT_FAMILIES );
	}

	const OBJECT_NAME_FONT_NAMES = 'ERRIGAL_FONT_NAMES';

	function getFontNamesObject() {
		return getGlobalObject( OBJECT_NAME_FONT_NAMES );
	}

	function isCssStyleRule( element ) {
		return element instanceof CSSStyleRule;
	}

	function getCssStyleRule( cssInlineStyle, cssRuleId ) {
		if ( ! isCssInlineStyle( cssInlineStyle ) ) {
			return NULL_OBJECT;
		}

		const CSS_STYLE_RULE =
			getObjectValue(
				cssInlineStyle.sheet.cssRules,
				cssRuleId
			);

		return isCssStyleRule( CSS_STYLE_RULE )
			? CSS_STYLE_RULE
			: NULL_OBJECT;
	}

	function hasStyle( element ) {
		return (
			!! element &&
			element.style instanceof CSSStyleDeclaration &&
			isFunction( element.style.setProperty )
		);
	}

	function isStyleProperty( property ) {
		return (
			isString( property ) &&
			hasStyle( document.documentElement ) &&
			property in document.documentElement.style
		);
	}

	function updateInlineStyle(
		element,
		property,
		value,
		isPriority
	) {
		if (
			! element ||
			! hasStyle( element ) ||
			! isStyleProperty( property ) ||
			! ( isString( value ) || isNumber( value ) ) ||
			! isBoolean( isPriority )
		) {
			return;
		}

		if ( isTrue( isPriority ) ) {
			element.style.setProperty( property, value, 'important' );

			return;
		}

		element.style.setProperty( property, value );
	}

	function updateCssInlineStyle(
		cssInlineStyle,
		cssRuleId,
		property,
		value,
		isPriority = false
	) {
		updateInlineStyle(
			getCssStyleRule( cssInlineStyle, cssRuleId ),
			property,
			value,
			isPriority
		);
	}

	function getFontName( fontName ) {
		const FONT_NAME = getObjectValue( getFontNamesObject(), fontName );

		return isNonEmptyString( FONT_NAME )
			? FONT_NAME
			: EMPTY_STRING;
	}

	function getFontFamily( fontName ) {
		const FONT_FAMILY = getObjectValue( getFontFamiliesObject(), fontName );

		return isNonEmptyString( FONT_FAMILY )
			? FONT_FAMILY
			: EMPTY_STRING;
	}

	function updateInlineFontStyle(
		fontName,
		cssFontStyleElement,
		cssRuleId
	) {
		if ( ! isHTMLElement( cssFontStyleElement ) || ! isNumber( cssRuleId ) ) {
			return;
		}

		const FONT_FAMILY = getFontFamily( fontName );

		if ( ! isNonEmptyString( FONT_FAMILY ) ) {
			return;
		}

		const FONT_NAME = getFontName( fontName );

		if ( ! isNonEmptyString( FONT_NAME ) ) {
			return;
		}

		const CSS_INLINE_STYLE = getErrigalCssInlineStyle();

		if ( ! CSS_INLINE_STYLE ) {
			return;
		}

		setAttribute(
			cssFontStyleElement,
			ATTRIBUTE_HREF,
			CUSTOM_TYPOGRAPHY_GOOGLE_FONT_FAMILY_URL + FONT_FAMILY
		);
		updateCssInlineStyle(
			CSS_INLINE_STYLE,
			cssRuleId,
			CSS_FONT_FAMILY,
			`"${ FONT_NAME }", ${ FONT_FALLBACK }`
		);
	}

	function updateBaseFont( fontName ) {
		updateInlineFontStyle( fontName, getErrigalCssBaseFontStyle(), INDEX_FIRST );
	}

	function addBaseFontChangeEvent() {
		onCustomisePreviewOptionChange( CUSTOM_ID_BASE_FONT, updateBaseFont );
	}

	function addBaseFontEvents() {
		addBaseFontChangeEvent();
	}

	const CUSTOM_ID_FONT_SIZE = 'font_size';
	const OBJECT_NAME_FONT_SIZES = 'ERRIGAL_FONT_SIZES';

	function getFontSizesObject() {
		const FONT_SIZES = getGlobalObject( OBJECT_NAME_FONT_SIZES );

		return isStringArray( FONT_SIZES )
			? FONT_SIZES
			: NULL_OBJECT;
	}

	function updateFontSize( fontSize ) {
		if ( ! isNonEmptyString( fontSize ) ) {
			return;
		}

		const FONT_SIZES = getFontSizesObject();

		if ( ! FONT_SIZES || ! FONT_SIZES.includes( fontSize ) ) {
			return;
		}

		forEach(
			FONT_SIZES,
			( fontSize ) => removeClass( document.documentElement, fontSize )
		);
		addClass( document.documentElement, fontSize );
	}

	function addFontSizeChangeEvent() {
		onCustomisePreviewOptionChange( CUSTOM_ID_FONT_SIZE, updateFontSize );
	}

	function addFontSizeEvents() {
		addFontSizeChangeEvent();
	}

	const CUSTOM_ID_HEADING_FONT = 'heading_font';
	const INDEX_SECOND = 1;
	const ID_ERRIGAL_CSS_HEADING_FONT_STYLE = 'errigal-heading-google-font-style-css';
	const SELECTOR_CUSTOMISER_ERRIGAL_CSS_HEADING_FONT_STYLE = `${ TAG_LINK }#${ ID_ERRIGAL_CSS_HEADING_FONT_STYLE }`;

	function getErrigalCssHeadingFontStyle() {
		return querySelector( SELECTOR_CUSTOMISER_ERRIGAL_CSS_HEADING_FONT_STYLE );
	}

	function updateHeadingFont( fontName ) {
		updateInlineFontStyle(
			fontName,
			getErrigalCssHeadingFontStyle(),
			INDEX_SECOND
		);
	}

	function addHeadingFontChangeEvent() {
		onCustomisePreviewOptionChange( CUSTOM_ID_HEADING_FONT, updateHeadingFont );
	}

	function addHeadingFontEvents() {
		addHeadingFontChangeEvent();
	}

	function addFontSettingsEvents() {
		addBaseFontEvents();
		addHeadingFontEvents();
		addFontSizeEvents();
	}

	const CUSTOMISER_SECTION_ID_FOOTER = 'footer';
	const CLASS_SECTION_SITE_FOOTER = 'site-footer';

	function getSiteFooter() {
		return getElementByClassName( CLASS_SECTION_SITE_FOOTER );
	}

	const EVENT_SECTION_TOGGLE = 'section-toggle';

	function isCustomiseSectionToggleMessage( message, sectionId ) {
		return (
			!! message &&
			isNonEmptyString( sectionId ) &&
			message.sectionId === sectionId &&
			isBoolean( message.isExpanded )
		);
	}

	function onCustomisePreviewSectionToggle(
		sectionId,
		callback
	) {
		if ( ! isNonEmptyString( sectionId ) || ! isFunction( callback ) ) {
			return;
		}

		const WP = getWp();

		if ( ! isWpCustomisePreview( WP ) ) {
			return;
		}

		WP.customize.preview.bind(
			EVENT_SECTION_TOGGLE,
			( message ) => {
				if ( ! isCustomiseSectionToggleMessage( message, sectionId ) ) {
					return;
				}

				callback( message.isExpanded );
			}
		);
	}

	const POSITION_ZERO = 0;
	const SCROLL_DISTANCE_LONG = 2000;
	const SCROLL_DISTANCE_MODERATE = 1000;
	const SCROLL_DISTANCE_SHORT = 200;
	const SCROLL_DURATION_MODERATE = 200;
	const SCROLL_DURATION_NORMAL = 300;
	const SCROLL_DURATION_SLOW = 400;
	const SCROLL_DURATION_SWIFT = 50;
	const CLASS_ACCESSIBILITY_SKIP_LINK = 'skip-link';

	function getSkipLink() {
		return getElementByClassName( CLASS_ACCESSIBILITY_SKIP_LINK );
	}

	const TAG_A = 'a';

	function isAnchorElement( element, ...classNames ) {
		return isHTMLElementOfType( TAG_A, element, ...classNames );
	}

	const ATTRIBUTE_TABINDEX = 'tabIndex';
	const ATTRIBUTE_VALUE_MINUS_ONE = '-1';

	function setTabIndex( element ) {
		setAttribute( element, ATTRIBUTE_TABINDEX, ATTRIBUTE_VALUE_MINUS_ONE );
	}

	function getPageHeight() {
		return Math.max(
			document.body.scrollHeight,
			document.body.offsetHeight,
			document.documentElement.clientHeight,
			document.documentElement.scrollHeight,
			document.documentElement.offsetHeight
		);
	}

	function isIe() {
		return !! window.MSInputMethodContext && !! document.documentMode;
	}

	function getScrollLeft() {
		return isIe()
			? window.pageXOffset
			: window.scrollX || document.documentElement.scrollLeft;
	}

	function getScrollTop() {
		return isIe()
			? window.pageYOffset
			: window.scrollY || document.documentElement.scrollTop;
	}

	function getViewportHeight() {
		return (
			window.innerHeight ||
			document.documentElement.clientHeight ||
			document.body.clientHeight
		);
	}

	const NUMBER_ZERO = 0;
	const RADIX_DECIMAL = 10;

	function parseDecimalInt( value ) {
		const PARSED_INT = parseInt( value, RADIX_DECIMAL );

		return isNumber( PARSED_INT )
			? PARSED_INT
			: NUMBER_ZERO;
	}

	const TAG_BUTTON = 'button';
	const TAG_INPUT = 'input';
	const TAG_SELECT = 'select';
	const TAG_TEXTAREA = 'textarea';
	const TAGS_FOCUSABLE_ELEMENTS = [
		TAG_A,
		TAG_BUTTON,
		TAG_INPUT,
		TAG_SELECT,
		TAG_TEXTAREA,
	];

	function isFocusableElement( element ) {
		if ( ! isHTMLElement( element ) || ! hasTagName( element ) ) {
			return false;
		}

		const TAG_NAME = element.tagName;

		return forEach(
			TAGS_FOCUSABLE_ELEMENTS,
			( tagName ) => areStringsEqualIgnoreCase( tagName, TAG_NAME )
		);
	}

	function isNullOrEmpty( value ) {
		return ! value || value === EMPTY_STRING;
	}

	const CALLBACK_INITIAL_ATTEMPT_COUNT = 0;
	const CALLBACK_INITIAL_INTERVAL = 0;
	const CALLBACK_INTERVAL = 50;
	const CALLBACK_MAX_ATTEMPT_COUNT = 20;

	function focusElement(
		element,
		attemptCount = CALLBACK_INITIAL_ATTEMPT_COUNT,
		interval = CALLBACK_INITIAL_INTERVAL
	) {
		if (
			! isHTMLElement( element ) ||
			! isFunction( element.focus ) ||
			! isNumber( attemptCount ) ||
			! isNumber( interval ) ||
			attemptCount === CALLBACK_MAX_ATTEMPT_COUNT
		) {
			return;
		}

		element.focus();
		setTimeout(
			() => {
				if ( element === document.activeElement ) {
					return;
				}

				focusElement( element, ++attemptCount, CALLBACK_INTERVAL );
			},
			interval
		);
	}

	const DISTANCE_REM_LG = 2;
	const RECT_TOP = 'top';

	function getViewportTop( element ) {
		return getRectProp( element, RECT_TOP );
	}

	function getPageTop( element ) {
		return getViewportTop( element ) + getScrollTop();
	}

	const CSS_FONT_SIZE = 'font-size';

	function getStyleProp( element, property ) {
		if ( ! isHTMLElement( element ) ) {
			return NULL_VALUE;
		}

		const STYLE_PROP =
			getObjectValue(
				window.getComputedStyle( element ),
				property
			);

		return isString( STYLE_PROP )
			? STYLE_PROP
			: NULL_VALUE;
	}

	function getStylePropFloat( element, property ) {
		const STYLE_PROP = parseFloat( getStyleProp( element, property ) );

		return isNumber( STYLE_PROP )
			? STYLE_PROP
			: PIXEL_ZERO;
	}

	function convertRemToPx( rem ) {
		return isNumber( rem )
			? getStylePropFloat( document.documentElement, CSS_FONT_SIZE ) * rem
			: PIXEL_ZERO;
	}

	const CLASS_SHARED_STICKY = 'sticky';

	function isSiteHeader( element ) {
		return isHTMLElement( element, CLASS_SECTION_SITE_HEADER );
	}

	const RECT_HEIGHT = 'height';

	function getHeight( element ) {
		return getRectProp( element, RECT_HEIGHT );
	}

	const RECT_BOTTOM = 'bottom';

	function getViewportBottom( element ) {
		return getRectProp( element, RECT_BOTTOM );
	}

	function getLastItem( items ) {
		return isIterable( items )
			? items[ items.length - 1 ]
			: NULL_VALUE;
	}

	const CSS_POSITION = 'position';
	const CSS_VALUE_FIXED = 'fixed';

	function isFixedElement( element ) {
		return areStringsEqualIgnoreCase(
			getStyleProp( element, CSS_POSITION ),
			CSS_VALUE_FIXED
		);
	}

	function getSiteHeaderStickyElements( siteHeader ) {
		return isSiteHeader( siteHeader )
			? getElementsByClassName( CLASS_SHARED_STICKY, siteHeader )
			: NULL_ELEMENT;
	}

	function getFixedElementHeight() {
		const SITE_HEADER = getSiteHeader();

		if ( ! SITE_HEADER ) {
			return PIXEL_ZERO;
		}

		return isFixedElement( SITE_HEADER )
			? getHeight( SITE_HEADER )
			: getViewportBottom(
				getLastItem( getSiteHeaderStickyElements( SITE_HEADER ) )
			);
	}

	function getClearTopOffset() {
		return convertRemToPx( DISTANCE_REM_LG );
	}

	function getAdjustedElementPageTop( element ) {
		const TARGET_ELEMENT_PAGE_TOP = getPageTop( element );

		return TARGET_ELEMENT_PAGE_TOP === POSITION_ZERO
			? TARGET_ELEMENT_PAGE_TOP
			: TARGET_ELEMENT_PAGE_TOP - getFixedElementHeight() - getClearTopOffset();
	}

	function getStartTime() {
		return performance.now();
	}

	function focusScrollTargetElement( element ) {
		if ( ! isHTMLElement( element ) ) {
			return;
		}

		if ( ! isFocusableElement( element ) ) {
			setTabIndex( element );
		}

		const SCROLL_LEFT = getScrollLeft();
		const SCROLL_TOP = getScrollTop();

		focusElement( element );
		window.scrollTo( SCROLL_LEFT, SCROLL_TOP );
	}

	function isBackToTopDestinationElement( element ) {
		return isHTMLElement( element ) || isAnchorElement( element )
			? element === document.documentElement || element === getSkipLink()
			: false;
	}

	function isPageScrolledToBottom() {
		return getViewportHeight() + getScrollTop() >= getPageHeight();
	}

	function isAtDestination( element ) {
		return parseDecimalInt( getScrollTop() ) ===
			parseDecimalInt( getAdjustedElementPageTop( element ) );
	}

	function shouldScroll( element ) {
		return isHTMLElement( element )
			? ! ( isAtDestination( element ) || isPageScrolledToBottom() ) ||
			isBackToTopDestinationElement( element )
			: false;
	}

	function scrollTo( element, duration ) {
		if ( ! isHTMLElement( element ) ) {
			return;
		}

		if ( ! shouldScroll( element ) ) {
			focusScrollTargetElement( element );

			return;
		}

		if ( ! isNumber( duration ) ) {
			const DISTANCE =
				Math.abs( getScrollTop() - getAdjustedElementPageTop( element ) );

			switch ( true ) {
				case DISTANCE < SCROLL_DISTANCE_SHORT:
					duration = SCROLL_DURATION_SWIFT;
					break;
				case DISTANCE < SCROLL_DISTANCE_MODERATE:
					duration = SCROLL_DURATION_MODERATE;
					break;
				case DISTANCE < SCROLL_DISTANCE_LONG:
					duration = SCROLL_DURATION_NORMAL;
					break;
				default:
					duration = SCROLL_DURATION_SLOW;
			}
		}

		const START_TIME = getStartTime();

		step( START_TIME, element, START_TIME, parseDecimalInt( duration ) );

		function step( timeStamp, element, startTime, duration ) {
			if ( isNullOrEmpty( timeStamp ) ) {
				timeStamp = startTime;
			}

			if (
				! isNumber( timeStamp ) ||
				! isHTMLElement( element ) ||
				! isNumber( startTime ) ||
				! isNumber( duration )
			) {
				return;
			}

			const DESTINATION_ELEMENT_PAGE_TOP = getAdjustedElementPageTop( element );
			const PROGRESSED_TIME = timeStamp - startTime;

			if ( PROGRESSED_TIME < duration && duration !== PIXEL_ZERO ) {
				const SCROLL_TOP = getScrollTop();
				const TIME = Math.min( 1, PROGRESSED_TIME / duration );
				const DISTANCE = ( DESTINATION_ELEMENT_PAGE_TOP - SCROLL_TOP ) * TIME;

				window.scrollTo( POSITION_ZERO, SCROLL_TOP + DISTANCE );
				requestAnimationFrame( ( currentTime ) =>
					step( currentTime, element, startTime, duration )
				);

				return;
			}

			window.scrollTo( POSITION_ZERO, DESTINATION_ELEMENT_PAGE_TOP );
			focusScrollTargetElement( element );

			if ( ! isNonEmptyString( element.id ) ) {
				return;
			}

			history.pushState( null, '', `#${ element.id }` );
		}
	}

	function scrollToSiteFooter( isExpanded ) {
		if ( isTrue( isExpanded ) ) {
			scrollTo( getSiteFooter() );
		}
	}

	function addFooterSectionToggleEvent() {
		onCustomisePreviewSectionToggle(
			CUSTOMISER_SECTION_ID_FOOTER,
			scrollToSiteFooter
		);
	}

	function addFooterEvents() {
		addFooterSectionToggleEvent();
	}

	const CUSTOM_ID_TAGLINE = 'blogdescription';
	const CUSTOM_ID_SITE_TITLE = 'blogname';
	const CUSTOM_IDS_SITE_IDENTITY_TEXTS = [
		CUSTOM_ID_SITE_TITLE,
		CUSTOM_ID_TAGLINE,
	];
	const CUSTOM_ID_LOGO = 'custom_logo';

	function isLogo( id ) {
		return id === CUSTOM_ID_LOGO;
	}

	function filter( items, callback ) {
		return (
			!! items &&
			isFunction( items.filter ) &&
			isFunction( callback )
		)
			? items.filter( callback )
			: NULL_VALUE;
	}

	function addCustomPartialEditShortcut( id ) {
		const PARTIAL = getCustomPartial( id );

		if ( ! PARTIAL ) {
			return;
		}

		PARTIAL.ready();
	}

	function addCustomPartialEditShortcuts(
		ids,
		excludeId = null
	) {
		forEach(
			filter( ids, ( id ) => isNonEmptyString( id ) && id !== excludeId ),
			addCustomPartialEditShortcut
		);
	}

	function addSiteIdentityTextEditShortcuts( id ) {
		if ( ! isLogo( id ) ) {
			return;
		}

		addCustomPartialEditShortcuts( CUSTOM_IDS_SITE_IDENTITY_TEXTS, id );
	}

	function addLogoChangeEvent() {
		onCustomPartialContentRendered( addSiteIdentityTextEditShortcuts );
	}

	function addLogoEvents() {
		addLogoChangeEvent();
	}

	const CSS_MARGIN_TOP = 'margin-top';
	const CSS_VALUE_ZERO = 0;
	const CLASS_CUSTOM_SITE_IDENTITY_TAGLINE = 'brand-tagline';

	function getSiteIdentityTagline() {
		return getElementByClassName( CLASS_CUSTOM_SITE_IDENTITY_TAGLINE );
	}

	const ATTRIBUTE_STYLE = 'style';

	function removeAttribute( element, ...names ) {
		if (
			! isHTMLElement( element ) ||
			! isFunction( element.removeAttribute )
		) {
			return;
		}

		forEach( names, ( name ) => element.removeAttribute( name ) );
	}

	function resetElementInlineStyle( element, ...properties ) {
		if ( ! isHTMLElement( element ) || ! hasStyle( element ) ) {
			return;
		}

		forEach(
			filter( properties, ( property ) => property in element.style ),
			( property ) => element.style[ property ] = EMPTY_STRING
		);

		if ( ! isNonEmptyString( element.style.cssText ) ) {
			removeAttribute( element, ATTRIBUTE_STYLE );
		}
	}

	function updateElementInlineStyle(
		element,
		property,
		value,
		isPriority = false
	) {
		if ( ! isHTMLElement( element ) ) {
			return;
		}

		updateInlineStyle( element, property, value, isPriority );
	}

	const EVENT_LOAD = 'load';

	function isUndefined( value ) {
		return isObjectType( value, 'Undefined' );
	}

	function onWindowEvent( eventType, callback, options ) {
		if (
			! isNonEmptyString( eventType ) ||
			! isFunction( callback ) ||
			! ( isUndefined( options ) || isObject( options ) || isBoolean( options ) )
		) {
			return;
		}

		window.addEventListener( eventType, callback, options || false );
	}

	function onWindowLoad( callback, options ) {
		onWindowEvent( EVENT_LOAD, callback, options );
	}

	function hasTextContent( element ) {
		return !! element && isNonEmptyString( element.textContent );
	}

	function toggleTaglineMarginTop() {
		const SITE_IDENTITY_TAGLINE = getSiteIdentityTagline();

		if ( ! SITE_IDENTITY_TAGLINE ) {
			return;
		}

		if ( ! hasTextContent( SITE_IDENTITY_TAGLINE ) ) {
			updateElementInlineStyle(
				SITE_IDENTITY_TAGLINE,
				CSS_MARGIN_TOP,
				CSS_VALUE_ZERO
			);

			return;
		}

		resetElementInlineStyle( SITE_IDENTITY_TAGLINE, CSS_MARGIN_TOP );
	}

	function isTagline( id ) {
		return id === CUSTOM_ID_TAGLINE;
	}

	function updateTaglineMarginTop( id ) {
		if ( ! ( isTagline( id ) || isLogo( id ) ) ) {
			return;
		}

		toggleTaglineMarginTop();
	}

	function addTaglineChangeEvent() {
		onCustomPartialContentRendered( updateTaglineMarginTop );
	}

	function addTaglineEvents() {
		addTaglineChangeEvent();
		onWindowLoad( toggleTaglineMarginTop );
	}

	function addSiteIdentityEvents() {
		addLogoEvents();
		addTaglineEvents();
	}

	function addCustomisePreviewEvents() {
		onCustomisePreviewReady( () => {
			addSiteIdentityEvents();
			addAppearanceEvents();
			addFontSettingsEvents();
			addBreadcrumbEvents();
			addFooterEvents();
		} );
	}

	addCustomisePreviewEvents();
}() );
